passagemath-modules 10.6.31rc3__cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-modules might be problematic. Click here for more details.
- passagemath_modules-10.6.31rc3.dist-info/METADATA +281 -0
- passagemath_modules-10.6.31rc3.dist-info/RECORD +806 -0
- passagemath_modules-10.6.31rc3.dist-info/WHEEL +6 -0
- passagemath_modules-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_modules.libs/libgfortran-e1b7dfc8.so.5.0.0 +0 -0
- passagemath_modules.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
- passagemath_modules.libs/libgsl-e3525837.so.28.0.0 +0 -0
- passagemath_modules.libs/libmpc-c5c421e1.so.3.3.1 +0 -0
- passagemath_modules.libs/libmpfr-e0f11cf3.so.6.2.1 +0 -0
- passagemath_modules.libs/libopenblasp-r0-4c5b64b1.3.29.so +0 -0
- sage/algebras/all__sagemath_modules.py +20 -0
- sage/algebras/catalog.py +148 -0
- sage/algebras/clifford_algebra.py +3107 -0
- sage/algebras/clifford_algebra_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/clifford_algebra_element.pxd +16 -0
- sage/algebras/clifford_algebra_element.pyx +997 -0
- sage/algebras/commutative_dga.py +4252 -0
- sage/algebras/exterior_algebra_groebner.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/exterior_algebra_groebner.pxd +55 -0
- sage/algebras/exterior_algebra_groebner.pyx +727 -0
- sage/algebras/finite_dimensional_algebras/all.py +2 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +1029 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd +12 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +706 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +196 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +255 -0
- sage/algebras/finite_gca.py +528 -0
- sage/algebras/group_algebra.py +232 -0
- sage/algebras/lie_algebras/abelian.py +197 -0
- sage/algebras/lie_algebras/affine_lie_algebra.py +1213 -0
- sage/algebras/lie_algebras/all.py +25 -0
- sage/algebras/lie_algebras/all__sagemath_modules.py +1 -0
- sage/algebras/lie_algebras/bch.py +177 -0
- sage/algebras/lie_algebras/bgg_dual_module.py +1184 -0
- sage/algebras/lie_algebras/bgg_resolution.py +232 -0
- sage/algebras/lie_algebras/center_uea.py +767 -0
- sage/algebras/lie_algebras/classical_lie_algebra.py +2516 -0
- sage/algebras/lie_algebras/examples.py +683 -0
- sage/algebras/lie_algebras/free_lie_algebra.py +973 -0
- sage/algebras/lie_algebras/heisenberg.py +820 -0
- sage/algebras/lie_algebras/lie_algebra.py +1562 -0
- sage/algebras/lie_algebras/lie_algebra_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/lie_algebras/lie_algebra_element.pxd +68 -0
- sage/algebras/lie_algebras/lie_algebra_element.pyx +2122 -0
- sage/algebras/lie_algebras/morphism.py +661 -0
- sage/algebras/lie_algebras/nilpotent_lie_algebra.py +457 -0
- sage/algebras/lie_algebras/onsager.py +1324 -0
- sage/algebras/lie_algebras/poincare_birkhoff_witt.py +816 -0
- sage/algebras/lie_algebras/quotient.py +462 -0
- sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +355 -0
- sage/algebras/lie_algebras/representation.py +1040 -0
- sage/algebras/lie_algebras/structure_coefficients.py +459 -0
- sage/algebras/lie_algebras/subalgebra.py +967 -0
- sage/algebras/lie_algebras/symplectic_derivation.py +289 -0
- sage/algebras/lie_algebras/verma_module.py +1630 -0
- sage/algebras/lie_algebras/virasoro.py +1186 -0
- sage/algebras/octonion_algebra.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/octonion_algebra.pxd +20 -0
- sage/algebras/octonion_algebra.pyx +987 -0
- sage/algebras/orlik_solomon.py +907 -0
- sage/algebras/orlik_terao.py +779 -0
- sage/algebras/steenrod/all.py +7 -0
- sage/algebras/steenrod/steenrod_algebra.py +4258 -0
- sage/algebras/steenrod/steenrod_algebra_bases.py +1179 -0
- sage/algebras/steenrod/steenrod_algebra_misc.py +1167 -0
- sage/algebras/steenrod/steenrod_algebra_mult.py +954 -0
- sage/algebras/weyl_algebra.py +1126 -0
- sage/all__sagemath_modules.py +62 -0
- sage/calculus/all__sagemath_modules.py +19 -0
- sage/calculus/expr.py +205 -0
- sage/calculus/integration.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/integration.pyx +698 -0
- sage/calculus/interpolation.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/interpolation.pxd +13 -0
- sage/calculus/interpolation.pyx +387 -0
- sage/calculus/interpolators.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/interpolators.pyx +326 -0
- sage/calculus/ode.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/ode.pxd +5 -0
- sage/calculus/ode.pyx +610 -0
- sage/calculus/riemann.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/riemann.pyx +1521 -0
- sage/calculus/test_sympy.py +201 -0
- sage/calculus/transforms/all.py +7 -0
- sage/calculus/transforms/dft.py +844 -0
- sage/calculus/transforms/dwt.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/transforms/dwt.pxd +7 -0
- sage/calculus/transforms/dwt.pyx +160 -0
- sage/calculus/transforms/fft.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/transforms/fft.pxd +12 -0
- sage/calculus/transforms/fft.pyx +487 -0
- sage/calculus/wester.py +662 -0
- sage/coding/abstract_code.py +1108 -0
- sage/coding/ag_code.py +868 -0
- sage/coding/ag_code_decoders.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/coding/ag_code_decoders.pyx +2639 -0
- sage/coding/all.py +15 -0
- sage/coding/bch_code.py +494 -0
- sage/coding/binary_code.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/coding/binary_code.pxd +124 -0
- sage/coding/binary_code.pyx +4139 -0
- sage/coding/bounds_catalog.py +43 -0
- sage/coding/channel.py +819 -0
- sage/coding/channels_catalog.py +29 -0
- sage/coding/code_bounds.py +755 -0
- sage/coding/code_constructions.py +804 -0
- sage/coding/codes_catalog.py +111 -0
- sage/coding/cyclic_code.py +1329 -0
- sage/coding/databases.py +316 -0
- sage/coding/decoder.py +373 -0
- sage/coding/decoders_catalog.py +88 -0
- sage/coding/delsarte_bounds.py +709 -0
- sage/coding/encoder.py +390 -0
- sage/coding/encoders_catalog.py +64 -0
- sage/coding/extended_code.py +468 -0
- sage/coding/gabidulin_code.py +1058 -0
- sage/coding/golay_code.py +404 -0
- sage/coding/goppa_code.py +441 -0
- sage/coding/grs_code.py +2371 -0
- sage/coding/guava.py +107 -0
- sage/coding/guruswami_sudan/all.py +1 -0
- sage/coding/guruswami_sudan/gs_decoder.py +897 -0
- sage/coding/guruswami_sudan/interpolation.py +409 -0
- sage/coding/guruswami_sudan/utils.py +176 -0
- sage/coding/hamming_code.py +176 -0
- sage/coding/information_set_decoder.py +1032 -0
- sage/coding/kasami_codes.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/coding/kasami_codes.pyx +351 -0
- sage/coding/linear_code.py +3067 -0
- sage/coding/linear_code_no_metric.py +1354 -0
- sage/coding/linear_rank_metric.py +961 -0
- sage/coding/parity_check_code.py +353 -0
- sage/coding/punctured_code.py +719 -0
- sage/coding/reed_muller_code.py +999 -0
- sage/coding/self_dual_codes.py +942 -0
- sage/coding/source_coding/all.py +2 -0
- sage/coding/source_coding/huffman.py +553 -0
- sage/coding/subfield_subcode.py +423 -0
- sage/coding/two_weight_db.py +399 -0
- sage/combinat/all__sagemath_modules.py +7 -0
- sage/combinat/cartesian_product.py +347 -0
- sage/combinat/family.py +11 -0
- sage/combinat/free_module.py +1977 -0
- sage/combinat/root_system/all.py +147 -0
- sage/combinat/root_system/ambient_space.py +527 -0
- sage/combinat/root_system/associahedron.py +471 -0
- sage/combinat/root_system/braid_move_calculator.py +143 -0
- sage/combinat/root_system/braid_orbit.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/combinat/root_system/braid_orbit.pyx +144 -0
- sage/combinat/root_system/branching_rules.py +2301 -0
- sage/combinat/root_system/cartan_matrix.py +1245 -0
- sage/combinat/root_system/cartan_type.py +3069 -0
- sage/combinat/root_system/coxeter_group.py +162 -0
- sage/combinat/root_system/coxeter_matrix.py +1261 -0
- sage/combinat/root_system/coxeter_type.py +681 -0
- sage/combinat/root_system/dynkin_diagram.py +900 -0
- sage/combinat/root_system/extended_affine_weyl_group.py +2993 -0
- sage/combinat/root_system/fundamental_group.py +795 -0
- sage/combinat/root_system/hecke_algebra_representation.py +1203 -0
- sage/combinat/root_system/integrable_representations.py +1227 -0
- sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +1965 -0
- sage/combinat/root_system/pieri_factors.py +1147 -0
- sage/combinat/root_system/plot.py +1615 -0
- sage/combinat/root_system/root_lattice_realization_algebras.py +1214 -0
- sage/combinat/root_system/root_lattice_realizations.py +4628 -0
- sage/combinat/root_system/root_space.py +487 -0
- sage/combinat/root_system/root_system.py +882 -0
- sage/combinat/root_system/type_A.py +348 -0
- sage/combinat/root_system/type_A_affine.py +227 -0
- sage/combinat/root_system/type_A_infinity.py +241 -0
- sage/combinat/root_system/type_B.py +347 -0
- sage/combinat/root_system/type_BC_affine.py +287 -0
- sage/combinat/root_system/type_B_affine.py +216 -0
- sage/combinat/root_system/type_C.py +317 -0
- sage/combinat/root_system/type_C_affine.py +188 -0
- sage/combinat/root_system/type_D.py +357 -0
- sage/combinat/root_system/type_D_affine.py +208 -0
- sage/combinat/root_system/type_E.py +641 -0
- sage/combinat/root_system/type_E_affine.py +231 -0
- sage/combinat/root_system/type_F.py +387 -0
- sage/combinat/root_system/type_F_affine.py +137 -0
- sage/combinat/root_system/type_G.py +293 -0
- sage/combinat/root_system/type_G_affine.py +132 -0
- sage/combinat/root_system/type_H.py +105 -0
- sage/combinat/root_system/type_I.py +110 -0
- sage/combinat/root_system/type_Q.py +150 -0
- sage/combinat/root_system/type_affine.py +509 -0
- sage/combinat/root_system/type_dual.py +704 -0
- sage/combinat/root_system/type_folded.py +301 -0
- sage/combinat/root_system/type_marked.py +748 -0
- sage/combinat/root_system/type_reducible.py +601 -0
- sage/combinat/root_system/type_relabel.py +730 -0
- sage/combinat/root_system/type_super_A.py +837 -0
- sage/combinat/root_system/weight_lattice_realizations.py +1188 -0
- sage/combinat/root_system/weight_space.py +639 -0
- sage/combinat/root_system/weyl_characters.py +2238 -0
- sage/crypto/__init__.py +4 -0
- sage/crypto/all.py +28 -0
- sage/crypto/block_cipher/all.py +7 -0
- sage/crypto/block_cipher/des.py +1065 -0
- sage/crypto/block_cipher/miniaes.py +2171 -0
- sage/crypto/block_cipher/present.py +909 -0
- sage/crypto/block_cipher/sdes.py +1527 -0
- sage/crypto/boolean_function.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/crypto/boolean_function.pxd +10 -0
- sage/crypto/boolean_function.pyx +1487 -0
- sage/crypto/cipher.py +78 -0
- sage/crypto/classical.py +3668 -0
- sage/crypto/classical_cipher.py +569 -0
- sage/crypto/cryptosystem.py +387 -0
- sage/crypto/key_exchange/all.py +7 -0
- sage/crypto/key_exchange/catalog.py +24 -0
- sage/crypto/key_exchange/diffie_hellman.py +323 -0
- sage/crypto/key_exchange/key_exchange_scheme.py +107 -0
- sage/crypto/lattice.py +312 -0
- sage/crypto/lfsr.py +295 -0
- sage/crypto/lwe.py +840 -0
- sage/crypto/mq/__init__.py +4 -0
- sage/crypto/mq/mpolynomialsystemgenerator.py +204 -0
- sage/crypto/mq/rijndael_gf.py +2345 -0
- sage/crypto/mq/sbox.py +7 -0
- sage/crypto/mq/sr.py +3344 -0
- sage/crypto/public_key/all.py +5 -0
- sage/crypto/public_key/blum_goldwasser.py +776 -0
- sage/crypto/sbox.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/crypto/sbox.pyx +2090 -0
- sage/crypto/sboxes.py +2090 -0
- sage/crypto/stream.py +390 -0
- sage/crypto/stream_cipher.py +297 -0
- sage/crypto/util.py +519 -0
- sage/ext/all__sagemath_modules.py +1 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_modules.py +2 -0
- sage/ext/interpreters/wrapper_cc.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/ext/interpreters/wrapper_cc.pxd +30 -0
- sage/ext/interpreters/wrapper_cc.pyx +252 -0
- sage/ext/interpreters/wrapper_cdf.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/ext/interpreters/wrapper_cdf.pxd +26 -0
- sage/ext/interpreters/wrapper_cdf.pyx +245 -0
- sage/ext/interpreters/wrapper_rdf.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/ext/interpreters/wrapper_rdf.pxd +23 -0
- sage/ext/interpreters/wrapper_rdf.pyx +221 -0
- sage/ext/interpreters/wrapper_rr.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/ext/interpreters/wrapper_rr.pxd +28 -0
- sage/ext/interpreters/wrapper_rr.pyx +335 -0
- sage/geometry/all__sagemath_modules.py +5 -0
- sage/geometry/toric_lattice.py +1745 -0
- sage/geometry/toric_lattice_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/geometry/toric_lattice_element.pyx +432 -0
- sage/groups/abelian_gps/abelian_group.py +1925 -0
- sage/groups/abelian_gps/abelian_group_element.py +164 -0
- sage/groups/abelian_gps/all__sagemath_modules.py +5 -0
- sage/groups/abelian_gps/dual_abelian_group.py +421 -0
- sage/groups/abelian_gps/dual_abelian_group_element.py +179 -0
- sage/groups/abelian_gps/element_base.py +341 -0
- sage/groups/abelian_gps/values.py +488 -0
- sage/groups/additive_abelian/additive_abelian_group.py +476 -0
- sage/groups/additive_abelian/additive_abelian_wrapper.py +857 -0
- sage/groups/additive_abelian/all.py +4 -0
- sage/groups/additive_abelian/qmodnz.py +231 -0
- sage/groups/additive_abelian/qmodnz_element.py +349 -0
- sage/groups/affine_gps/affine_group.py +535 -0
- sage/groups/affine_gps/all.py +1 -0
- sage/groups/affine_gps/catalog.py +17 -0
- sage/groups/affine_gps/euclidean_group.py +246 -0
- sage/groups/affine_gps/group_element.py +562 -0
- sage/groups/all__sagemath_modules.py +12 -0
- sage/groups/galois_group.py +479 -0
- sage/groups/matrix_gps/all.py +4 -0
- sage/groups/matrix_gps/all__sagemath_modules.py +13 -0
- sage/groups/matrix_gps/catalog.py +26 -0
- sage/groups/matrix_gps/coxeter_group.py +927 -0
- sage/groups/matrix_gps/finitely_generated.py +487 -0
- sage/groups/matrix_gps/group_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/groups/matrix_gps/group_element.pxd +11 -0
- sage/groups/matrix_gps/group_element.pyx +431 -0
- sage/groups/matrix_gps/linear.py +440 -0
- sage/groups/matrix_gps/matrix_group.py +617 -0
- sage/groups/matrix_gps/named_group.py +296 -0
- sage/groups/matrix_gps/orthogonal.py +544 -0
- sage/groups/matrix_gps/symplectic.py +251 -0
- sage/groups/matrix_gps/unitary.py +436 -0
- sage/groups/misc_gps/all__sagemath_modules.py +1 -0
- sage/groups/misc_gps/argument_groups.py +1905 -0
- sage/groups/misc_gps/imaginary_groups.py +479 -0
- sage/groups/perm_gps/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pxd +41 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pyx +1167 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pxd +31 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pyx +385 -0
- sage/homology/algebraic_topological_model.py +595 -0
- sage/homology/all.py +2 -0
- sage/homology/all__sagemath_modules.py +8 -0
- sage/homology/chain_complex.py +2148 -0
- sage/homology/chain_complex_homspace.py +165 -0
- sage/homology/chain_complex_morphism.py +629 -0
- sage/homology/chain_homotopy.py +604 -0
- sage/homology/chains.py +653 -0
- sage/homology/free_resolution.py +923 -0
- sage/homology/graded_resolution.py +567 -0
- sage/homology/hochschild_complex.py +756 -0
- sage/homology/homology_group.py +188 -0
- sage/homology/homology_morphism.py +422 -0
- sage/homology/homology_vector_space_with_basis.py +1454 -0
- sage/homology/koszul_complex.py +169 -0
- sage/homology/matrix_utils.py +205 -0
- sage/libs/all__sagemath_modules.py +1 -0
- sage/libs/gsl/__init__.py +1 -0
- sage/libs/gsl/airy.pxd +56 -0
- sage/libs/gsl/all.pxd +66 -0
- sage/libs/gsl/array.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/gsl/array.pxd +5 -0
- sage/libs/gsl/array.pyx +102 -0
- sage/libs/gsl/bessel.pxd +208 -0
- sage/libs/gsl/blas.pxd +116 -0
- sage/libs/gsl/blas_types.pxd +34 -0
- sage/libs/gsl/block.pxd +52 -0
- sage/libs/gsl/chebyshev.pxd +37 -0
- sage/libs/gsl/clausen.pxd +12 -0
- sage/libs/gsl/combination.pxd +47 -0
- sage/libs/gsl/complex.pxd +151 -0
- sage/libs/gsl/coulomb.pxd +30 -0
- sage/libs/gsl/coupling.pxd +21 -0
- sage/libs/gsl/dawson.pxd +12 -0
- sage/libs/gsl/debye.pxd +24 -0
- sage/libs/gsl/dilog.pxd +14 -0
- sage/libs/gsl/eigen.pxd +46 -0
- sage/libs/gsl/elementary.pxd +12 -0
- sage/libs/gsl/ellint.pxd +48 -0
- sage/libs/gsl/elljac.pxd +8 -0
- sage/libs/gsl/erf.pxd +32 -0
- sage/libs/gsl/errno.pxd +26 -0
- sage/libs/gsl/exp.pxd +44 -0
- sage/libs/gsl/expint.pxd +44 -0
- sage/libs/gsl/fermi_dirac.pxd +44 -0
- sage/libs/gsl/fft.pxd +121 -0
- sage/libs/gsl/fit.pxd +50 -0
- sage/libs/gsl/gamma.pxd +94 -0
- sage/libs/gsl/gegenbauer.pxd +26 -0
- sage/libs/gsl/histogram.pxd +176 -0
- sage/libs/gsl/hyperg.pxd +52 -0
- sage/libs/gsl/integration.pxd +69 -0
- sage/libs/gsl/interp.pxd +109 -0
- sage/libs/gsl/laguerre.pxd +24 -0
- sage/libs/gsl/lambert.pxd +16 -0
- sage/libs/gsl/legendre.pxd +90 -0
- sage/libs/gsl/linalg.pxd +185 -0
- sage/libs/gsl/log.pxd +26 -0
- sage/libs/gsl/math.pxd +43 -0
- sage/libs/gsl/matrix.pxd +143 -0
- sage/libs/gsl/matrix_complex.pxd +130 -0
- sage/libs/gsl/min.pxd +67 -0
- sage/libs/gsl/monte.pxd +56 -0
- sage/libs/gsl/ntuple.pxd +32 -0
- sage/libs/gsl/odeiv.pxd +70 -0
- sage/libs/gsl/permutation.pxd +78 -0
- sage/libs/gsl/poly.pxd +40 -0
- sage/libs/gsl/pow_int.pxd +12 -0
- sage/libs/gsl/psi.pxd +28 -0
- sage/libs/gsl/qrng.pxd +29 -0
- sage/libs/gsl/random.pxd +257 -0
- sage/libs/gsl/rng.pxd +100 -0
- sage/libs/gsl/roots.pxd +72 -0
- sage/libs/gsl/sort.pxd +36 -0
- sage/libs/gsl/statistics.pxd +59 -0
- sage/libs/gsl/sum.pxd +55 -0
- sage/libs/gsl/synchrotron.pxd +16 -0
- sage/libs/gsl/transport.pxd +24 -0
- sage/libs/gsl/trig.pxd +58 -0
- sage/libs/gsl/types.pxd +137 -0
- sage/libs/gsl/vector.pxd +101 -0
- sage/libs/gsl/vector_complex.pxd +83 -0
- sage/libs/gsl/wavelet.pxd +49 -0
- sage/libs/gsl/zeta.pxd +28 -0
- sage/libs/mpc/__init__.pxd +114 -0
- sage/libs/mpc/types.pxd +28 -0
- sage/libs/mpfr/__init__.pxd +299 -0
- sage/libs/mpfr/types.pxd +26 -0
- sage/libs/mpmath/__init__.py +1 -0
- sage/libs/mpmath/all.py +27 -0
- sage/libs/mpmath/all__sagemath_modules.py +1 -0
- sage/libs/mpmath/utils.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/mpmath/utils.pxd +4 -0
- sage/libs/mpmath/utils.pyx +319 -0
- sage/matrix/action.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/action.pxd +26 -0
- sage/matrix/action.pyx +596 -0
- sage/matrix/all.py +9 -0
- sage/matrix/args.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/args.pxd +144 -0
- sage/matrix/args.pyx +1668 -0
- sage/matrix/benchmark.py +1258 -0
- sage/matrix/berlekamp_massey.py +95 -0
- sage/matrix/compute_J_ideal.py +926 -0
- sage/matrix/constructor.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/constructor.pyx +750 -0
- sage/matrix/docs.py +430 -0
- sage/matrix/echelon_matrix.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/echelon_matrix.pyx +155 -0
- sage/matrix/matrix.pxd +2 -0
- sage/matrix/matrix0.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix0.pxd +68 -0
- sage/matrix/matrix0.pyx +6324 -0
- sage/matrix/matrix1.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix1.pxd +8 -0
- sage/matrix/matrix1.pyx +2851 -0
- sage/matrix/matrix2.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix2.pxd +25 -0
- sage/matrix/matrix2.pyx +20181 -0
- sage/matrix/matrix_cdv.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_cdv.pxd +4 -0
- sage/matrix/matrix_cdv.pyx +93 -0
- sage/matrix/matrix_complex_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_complex_double_dense.pxd +5 -0
- sage/matrix/matrix_complex_double_dense.pyx +98 -0
- sage/matrix/matrix_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_dense.pxd +5 -0
- sage/matrix/matrix_dense.pyx +343 -0
- sage/matrix/matrix_domain_dense.pxd +5 -0
- sage/matrix/matrix_domain_sparse.pxd +5 -0
- sage/matrix/matrix_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_double_dense.pxd +7 -0
- sage/matrix/matrix_double_dense.pyx +3906 -0
- sage/matrix/matrix_double_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_double_sparse.pxd +6 -0
- sage/matrix/matrix_double_sparse.pyx +248 -0
- sage/matrix/matrix_generic_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_generic_dense.pxd +7 -0
- sage/matrix/matrix_generic_dense.pyx +354 -0
- sage/matrix/matrix_generic_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_generic_sparse.pxd +7 -0
- sage/matrix/matrix_generic_sparse.pyx +461 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pxd +5 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pyx +115 -0
- sage/matrix/matrix_misc.py +313 -0
- sage/matrix/matrix_numpy_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_numpy_dense.pxd +14 -0
- sage/matrix/matrix_numpy_dense.pyx +450 -0
- sage/matrix/matrix_numpy_integer_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_numpy_integer_dense.pxd +7 -0
- sage/matrix/matrix_numpy_integer_dense.pyx +59 -0
- sage/matrix/matrix_polynomial_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_polynomial_dense.pxd +5 -0
- sage/matrix/matrix_polynomial_dense.pyx +5341 -0
- sage/matrix/matrix_real_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_real_double_dense.pxd +7 -0
- sage/matrix/matrix_real_double_dense.pyx +122 -0
- sage/matrix/matrix_space.py +2848 -0
- sage/matrix/matrix_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_sparse.pxd +5 -0
- sage/matrix/matrix_sparse.pyx +1222 -0
- sage/matrix/matrix_window.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_window.pxd +37 -0
- sage/matrix/matrix_window.pyx +242 -0
- sage/matrix/misc_mpfr.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/misc_mpfr.pyx +80 -0
- sage/matrix/operation_table.py +1182 -0
- sage/matrix/special.py +3666 -0
- sage/matrix/strassen.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/strassen.pyx +851 -0
- sage/matrix/symplectic_basis.py +541 -0
- sage/matrix/template.pxd +6 -0
- sage/matrix/tests.py +71 -0
- sage/matroids/advanced.py +77 -0
- sage/matroids/all.py +13 -0
- sage/matroids/basis_exchange_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/basis_exchange_matroid.pxd +96 -0
- sage/matroids/basis_exchange_matroid.pyx +2344 -0
- sage/matroids/basis_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/basis_matroid.pxd +45 -0
- sage/matroids/basis_matroid.pyx +1217 -0
- sage/matroids/catalog.py +44 -0
- sage/matroids/chow_ring.py +473 -0
- sage/matroids/chow_ring_ideal.py +849 -0
- sage/matroids/circuit_closures_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/circuit_closures_matroid.pxd +16 -0
- sage/matroids/circuit_closures_matroid.pyx +559 -0
- sage/matroids/circuits_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/circuits_matroid.pxd +38 -0
- sage/matroids/circuits_matroid.pyx +947 -0
- sage/matroids/constructor.py +1086 -0
- sage/matroids/database_collections.py +365 -0
- sage/matroids/database_matroids.py +5338 -0
- sage/matroids/dual_matroid.py +583 -0
- sage/matroids/extension.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/extension.pxd +34 -0
- sage/matroids/extension.pyx +519 -0
- sage/matroids/flats_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/flats_matroid.pxd +28 -0
- sage/matroids/flats_matroid.pyx +715 -0
- sage/matroids/gammoid.py +600 -0
- sage/matroids/graphic_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/graphic_matroid.pxd +39 -0
- sage/matroids/graphic_matroid.pyx +2024 -0
- sage/matroids/lean_matrix.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/lean_matrix.pxd +126 -0
- sage/matroids/lean_matrix.pyx +3667 -0
- sage/matroids/linear_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/linear_matroid.pxd +180 -0
- sage/matroids/linear_matroid.pyx +6649 -0
- sage/matroids/matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/matroid.pxd +243 -0
- sage/matroids/matroid.pyx +8759 -0
- sage/matroids/matroids_catalog.py +190 -0
- sage/matroids/matroids_plot_helpers.py +890 -0
- sage/matroids/minor_matroid.py +480 -0
- sage/matroids/minorfix.h +9 -0
- sage/matroids/named_matroids.py +5 -0
- sage/matroids/rank_matroid.py +268 -0
- sage/matroids/set_system.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/set_system.pxd +38 -0
- sage/matroids/set_system.pyx +800 -0
- sage/matroids/transversal_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/transversal_matroid.pxd +14 -0
- sage/matroids/transversal_matroid.pyx +893 -0
- sage/matroids/union_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/union_matroid.pxd +20 -0
- sage/matroids/union_matroid.pyx +331 -0
- sage/matroids/unpickling.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/unpickling.pyx +843 -0
- sage/matroids/utilities.py +809 -0
- sage/misc/all__sagemath_modules.py +20 -0
- sage/misc/c3.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/misc/c3.pyx +238 -0
- sage/misc/compat.py +87 -0
- sage/misc/element_with_label.py +173 -0
- sage/misc/func_persist.py +79 -0
- sage/misc/pickle_old.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/misc/pickle_old.pyx +19 -0
- sage/misc/proof.py +7 -0
- sage/misc/replace_dot_all.py +472 -0
- sage/misc/sagedoc_conf.py +168 -0
- sage/misc/sphinxify.py +167 -0
- sage/misc/test_class_pickling.py +85 -0
- sage/modules/all.py +42 -0
- sage/modules/complex_double_vector.py +25 -0
- sage/modules/diamond_cutting.py +380 -0
- sage/modules/fg_pid/all.py +1 -0
- sage/modules/fg_pid/fgp_element.py +456 -0
- sage/modules/fg_pid/fgp_module.py +2091 -0
- sage/modules/fg_pid/fgp_morphism.py +550 -0
- sage/modules/filtered_vector_space.py +1271 -0
- sage/modules/finite_submodule_iter.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/finite_submodule_iter.pxd +27 -0
- sage/modules/finite_submodule_iter.pyx +452 -0
- sage/modules/fp_graded/all.py +1 -0
- sage/modules/fp_graded/element.py +346 -0
- sage/modules/fp_graded/free_element.py +298 -0
- sage/modules/fp_graded/free_homspace.py +53 -0
- sage/modules/fp_graded/free_module.py +1060 -0
- sage/modules/fp_graded/free_morphism.py +217 -0
- sage/modules/fp_graded/homspace.py +563 -0
- sage/modules/fp_graded/module.py +1340 -0
- sage/modules/fp_graded/morphism.py +1990 -0
- sage/modules/fp_graded/steenrod/all.py +1 -0
- sage/modules/fp_graded/steenrod/homspace.py +65 -0
- sage/modules/fp_graded/steenrod/module.py +477 -0
- sage/modules/fp_graded/steenrod/morphism.py +404 -0
- sage/modules/fp_graded/steenrod/profile.py +241 -0
- sage/modules/free_module.py +8447 -0
- sage/modules/free_module_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/free_module_element.pxd +22 -0
- sage/modules/free_module_element.pyx +5445 -0
- sage/modules/free_module_homspace.py +369 -0
- sage/modules/free_module_integer.py +896 -0
- sage/modules/free_module_morphism.py +823 -0
- sage/modules/free_module_pseudohomspace.py +352 -0
- sage/modules/free_module_pseudomorphism.py +578 -0
- sage/modules/free_quadratic_module.py +1706 -0
- sage/modules/free_quadratic_module_integer_symmetric.py +1790 -0
- sage/modules/matrix_morphism.py +1745 -0
- sage/modules/misc.py +103 -0
- sage/modules/module_functors.py +192 -0
- sage/modules/multi_filtered_vector_space.py +719 -0
- sage/modules/ore_module.py +2208 -0
- sage/modules/ore_module_element.py +178 -0
- sage/modules/ore_module_homspace.py +147 -0
- sage/modules/ore_module_morphism.py +968 -0
- sage/modules/quotient_module.py +699 -0
- sage/modules/real_double_vector.py +22 -0
- sage/modules/submodule.py +255 -0
- sage/modules/tensor_operations.py +567 -0
- sage/modules/torsion_quadratic_module.py +1352 -0
- sage/modules/tutorial_free_modules.py +248 -0
- sage/modules/vector_complex_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_complex_double_dense.pxd +6 -0
- sage/modules/vector_complex_double_dense.pyx +117 -0
- sage/modules/vector_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_double_dense.pxd +6 -0
- sage/modules/vector_double_dense.pyx +604 -0
- sage/modules/vector_integer_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_integer_dense.pxd +15 -0
- sage/modules/vector_integer_dense.pyx +361 -0
- sage/modules/vector_integer_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_integer_sparse.pxd +29 -0
- sage/modules/vector_integer_sparse.pyx +406 -0
- sage/modules/vector_modn_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_modn_dense.pxd +12 -0
- sage/modules/vector_modn_dense.pyx +394 -0
- sage/modules/vector_modn_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_modn_sparse.pxd +21 -0
- sage/modules/vector_modn_sparse.pyx +298 -0
- sage/modules/vector_numpy_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_numpy_dense.pxd +15 -0
- sage/modules/vector_numpy_dense.pyx +304 -0
- sage/modules/vector_numpy_integer_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_numpy_integer_dense.pxd +7 -0
- sage/modules/vector_numpy_integer_dense.pyx +54 -0
- sage/modules/vector_rational_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_rational_dense.pxd +15 -0
- sage/modules/vector_rational_dense.pyx +387 -0
- sage/modules/vector_rational_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_rational_sparse.pxd +30 -0
- sage/modules/vector_rational_sparse.pyx +413 -0
- sage/modules/vector_real_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_real_double_dense.pxd +6 -0
- sage/modules/vector_real_double_dense.pyx +126 -0
- sage/modules/vector_space_homspace.py +430 -0
- sage/modules/vector_space_morphism.py +989 -0
- sage/modules/with_basis/all.py +15 -0
- sage/modules/with_basis/cell_module.py +494 -0
- sage/modules/with_basis/indexed_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/with_basis/indexed_element.pxd +13 -0
- sage/modules/with_basis/indexed_element.pyx +1058 -0
- sage/modules/with_basis/invariant.py +1075 -0
- sage/modules/with_basis/morphism.py +1636 -0
- sage/modules/with_basis/representation.py +2939 -0
- sage/modules/with_basis/subquotient.py +685 -0
- sage/numerical/all__sagemath_modules.py +6 -0
- sage/numerical/gauss_legendre.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/numerical/gauss_legendre.pyx +381 -0
- sage/numerical/optimize.py +910 -0
- sage/probability/all.py +10 -0
- sage/probability/probability_distribution.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/probability/probability_distribution.pyx +1242 -0
- sage/probability/random_variable.py +411 -0
- sage/quadratic_forms/all.py +4 -0
- sage/quadratic_forms/all__sagemath_modules.py +15 -0
- sage/quadratic_forms/binary_qf.py +2042 -0
- sage/quadratic_forms/bqf_class_group.py +748 -0
- sage/quadratic_forms/constructions.py +93 -0
- sage/quadratic_forms/count_local_2.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/quadratic_forms/count_local_2.pyx +365 -0
- sage/quadratic_forms/extras.py +195 -0
- sage/quadratic_forms/quadratic_form.py +1753 -0
- sage/quadratic_forms/quadratic_form__count_local_2.py +221 -0
- sage/quadratic_forms/quadratic_form__equivalence_testing.py +708 -0
- sage/quadratic_forms/quadratic_form__evaluate.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/quadratic_forms/quadratic_form__evaluate.pyx +139 -0
- sage/quadratic_forms/quadratic_form__local_density_congruence.py +977 -0
- sage/quadratic_forms/quadratic_form__local_field_invariants.py +1072 -0
- sage/quadratic_forms/quadratic_form__neighbors.py +424 -0
- sage/quadratic_forms/quadratic_form__reduction_theory.py +488 -0
- sage/quadratic_forms/quadratic_form__split_local_covering.py +416 -0
- sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +657 -0
- sage/quadratic_forms/quadratic_form__theta.py +352 -0
- sage/quadratic_forms/quadratic_form__variable_substitutions.py +370 -0
- sage/quadratic_forms/random_quadraticform.py +209 -0
- sage/quadratic_forms/ternary.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/quadratic_forms/ternary.pyx +1154 -0
- sage/quadratic_forms/ternary_qf.py +2027 -0
- sage/rings/all__sagemath_modules.py +28 -0
- sage/rings/asymptotic/all__sagemath_modules.py +1 -0
- sage/rings/asymptotic/misc.py +1252 -0
- sage/rings/cc.py +4 -0
- sage/rings/cfinite_sequence.py +1306 -0
- sage/rings/complex_conversion.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_conversion.pxd +8 -0
- sage/rings/complex_conversion.pyx +23 -0
- sage/rings/complex_double.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_double.pxd +21 -0
- sage/rings/complex_double.pyx +2654 -0
- sage/rings/complex_mpc.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_mpc.pxd +21 -0
- sage/rings/complex_mpc.pyx +2576 -0
- sage/rings/complex_mpfr.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_mpfr.pxd +18 -0
- sage/rings/complex_mpfr.pyx +3602 -0
- sage/rings/derivation.py +2334 -0
- sage/rings/finite_rings/all__sagemath_modules.py +1 -0
- sage/rings/finite_rings/maps_finite_field.py +191 -0
- sage/rings/function_field/all__sagemath_modules.py +8 -0
- sage/rings/function_field/derivations.py +102 -0
- sage/rings/function_field/derivations_rational.py +132 -0
- sage/rings/function_field/differential.py +853 -0
- sage/rings/function_field/divisor.py +1107 -0
- sage/rings/function_field/drinfeld_modules/action.py +199 -0
- sage/rings/function_field/drinfeld_modules/all.py +1 -0
- sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +673 -0
- sage/rings/function_field/drinfeld_modules/drinfeld_module.py +2087 -0
- sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +1131 -0
- sage/rings/function_field/drinfeld_modules/homset.py +420 -0
- sage/rings/function_field/drinfeld_modules/morphism.py +820 -0
- sage/rings/function_field/hermite_form_polynomial.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
- sage/rings/function_field/khuri_makdisi.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/function_field/khuri_makdisi.pyx +935 -0
- sage/rings/invariants/all.py +4 -0
- sage/rings/invariants/invariant_theory.py +4597 -0
- sage/rings/invariants/reconstruction.py +395 -0
- sage/rings/polynomial/all__sagemath_modules.py +17 -0
- sage/rings/polynomial/integer_valued_polynomials.py +1230 -0
- sage/rings/polynomial/laurent_polynomial_mpair.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pxd +15 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pyx +2023 -0
- sage/rings/polynomial/ore_function_element.py +952 -0
- sage/rings/polynomial/ore_function_field.py +1028 -0
- sage/rings/polynomial/ore_polynomial_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/ore_polynomial_element.pxd +48 -0
- sage/rings/polynomial/ore_polynomial_element.pyx +3145 -0
- sage/rings/polynomial/ore_polynomial_ring.py +1334 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +788 -0
- sage/rings/polynomial/q_integer_valued_polynomials.py +1264 -0
- sage/rings/polynomial/skew_polynomial_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/skew_polynomial_element.pxd +9 -0
- sage/rings/polynomial/skew_polynomial_element.pyx +684 -0
- sage/rings/polynomial/skew_polynomial_finite_field.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pxd +19 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pyx +1093 -0
- sage/rings/polynomial/skew_polynomial_finite_order.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pxd +10 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pyx +567 -0
- sage/rings/polynomial/skew_polynomial_ring.py +908 -0
- sage/rings/real_double_element_gsl.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/real_double_element_gsl.pxd +8 -0
- sage/rings/real_double_element_gsl.pyx +794 -0
- sage/rings/real_field.py +58 -0
- sage/rings/real_mpfr.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/real_mpfr.pxd +29 -0
- sage/rings/real_mpfr.pyx +6122 -0
- sage/rings/ring_extension.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/ring_extension.pxd +42 -0
- sage/rings/ring_extension.pyx +2779 -0
- sage/rings/ring_extension_conversion.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/ring_extension_conversion.pxd +16 -0
- sage/rings/ring_extension_conversion.pyx +462 -0
- sage/rings/ring_extension_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/ring_extension_element.pxd +21 -0
- sage/rings/ring_extension_element.pyx +1635 -0
- sage/rings/ring_extension_homset.py +64 -0
- sage/rings/ring_extension_morphism.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/ring_extension_morphism.pxd +35 -0
- sage/rings/ring_extension_morphism.pyx +920 -0
- sage/schemes/all__sagemath_modules.py +1 -0
- sage/schemes/projective/all__sagemath_modules.py +1 -0
- sage/schemes/projective/coherent_sheaf.py +300 -0
- sage/schemes/projective/cohomology.py +510 -0
- sage/stats/all.py +15 -0
- sage/stats/basic_stats.py +489 -0
- sage/stats/distributions/all.py +7 -0
- sage/stats/distributions/catalog.py +34 -0
- sage/stats/distributions/dgs.h +50 -0
- sage/stats/distributions/dgs.pxd +111 -0
- sage/stats/distributions/dgs_bern.h +400 -0
- sage/stats/distributions/dgs_gauss.h +614 -0
- sage/stats/distributions/dgs_misc.h +104 -0
- sage/stats/distributions/discrete_gaussian_integer.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/distributions/discrete_gaussian_integer.pxd +14 -0
- sage/stats/distributions/discrete_gaussian_integer.pyx +498 -0
- sage/stats/distributions/discrete_gaussian_lattice.py +908 -0
- sage/stats/distributions/discrete_gaussian_polynomial.py +141 -0
- sage/stats/hmm/all.py +15 -0
- sage/stats/hmm/chmm.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/hmm/chmm.pyx +1595 -0
- sage/stats/hmm/distributions.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/hmm/distributions.pxd +29 -0
- sage/stats/hmm/distributions.pyx +531 -0
- sage/stats/hmm/hmm.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/hmm/hmm.pxd +17 -0
- sage/stats/hmm/hmm.pyx +1388 -0
- sage/stats/hmm/util.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/hmm/util.pxd +7 -0
- sage/stats/hmm/util.pyx +165 -0
- sage/stats/intlist.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/intlist.pxd +14 -0
- sage/stats/intlist.pyx +588 -0
- sage/stats/r.py +49 -0
- sage/stats/time_series.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/time_series.pxd +6 -0
- sage/stats/time_series.pyx +2546 -0
- sage/tensor/all.py +2 -0
- sage/tensor/modules/all.py +8 -0
- sage/tensor/modules/alternating_contr_tensor.py +761 -0
- sage/tensor/modules/comp.py +5598 -0
- sage/tensor/modules/ext_pow_free_module.py +824 -0
- sage/tensor/modules/finite_rank_free_module.py +3589 -0
- sage/tensor/modules/format_utilities.py +333 -0
- sage/tensor/modules/free_module_alt_form.py +858 -0
- sage/tensor/modules/free_module_automorphism.py +1207 -0
- sage/tensor/modules/free_module_basis.py +1074 -0
- sage/tensor/modules/free_module_element.py +284 -0
- sage/tensor/modules/free_module_homset.py +652 -0
- sage/tensor/modules/free_module_linear_group.py +564 -0
- sage/tensor/modules/free_module_morphism.py +1581 -0
- sage/tensor/modules/free_module_tensor.py +3289 -0
- sage/tensor/modules/reflexive_module.py +386 -0
- sage/tensor/modules/tensor_free_module.py +780 -0
- sage/tensor/modules/tensor_free_submodule.py +538 -0
- sage/tensor/modules/tensor_free_submodule_basis.py +140 -0
- sage/tensor/modules/tensor_with_indices.py +1043 -0
sage/stats/hmm/hmm.pyx
ADDED
|
@@ -0,0 +1,1388 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-modules
|
|
2
|
+
# sage.doctest: needs numpy sage.modules
|
|
3
|
+
r"""
|
|
4
|
+
Hidden Markov Models
|
|
5
|
+
|
|
6
|
+
This is a complete pure-Cython optimized implementation of Hidden
|
|
7
|
+
Markov Models. It fully supports Discrete, Gaussian, and Mixed
|
|
8
|
+
Gaussian emissions.
|
|
9
|
+
|
|
10
|
+
The best references for the basic HMM algorithms implemented here are:
|
|
11
|
+
|
|
12
|
+
- Tapas Kanungo's "Hidden Markov Models"
|
|
13
|
+
|
|
14
|
+
- Jackson's HMM tutorial:
|
|
15
|
+
http://personal.ee.surrey.ac.uk/Personal/P.Jackson/tutorial/
|
|
16
|
+
|
|
17
|
+
LICENSE: Some of the code in this file is based on reading Kanungo's
|
|
18
|
+
GPLv2+ implementation of discrete HMM's, hence the present code must
|
|
19
|
+
be licensed with a GPLv2+ compatible license.
|
|
20
|
+
|
|
21
|
+
AUTHOR:
|
|
22
|
+
|
|
23
|
+
- William Stein, 2010-03
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
# ****************************************************************************
|
|
27
|
+
# Copyright (C) 2010 William Stein <wstein@gmail.com>
|
|
28
|
+
#
|
|
29
|
+
# This program is free software: you can redistribute it and/or modify
|
|
30
|
+
# it under the terms of the GNU General Public License as published by
|
|
31
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
32
|
+
# (at your option) any later version.
|
|
33
|
+
# https://www.gnu.org/licenses/
|
|
34
|
+
# ****************************************************************************
|
|
35
|
+
|
|
36
|
+
from libc.math cimport log
|
|
37
|
+
from cysignals.signals cimport sig_on, sig_off
|
|
38
|
+
|
|
39
|
+
from sage.stats.time_series cimport TimeSeries
|
|
40
|
+
from sage.structure.element import Matrix
|
|
41
|
+
from sage.matrix.constructor import matrix
|
|
42
|
+
from sage.misc.randstate cimport current_randstate, randstate
|
|
43
|
+
from cpython.object cimport PyObject_RichCompare
|
|
44
|
+
|
|
45
|
+
from sage.stats.hmm.util cimport HMM_Util
|
|
46
|
+
|
|
47
|
+
cdef HMM_Util util = HMM_Util()
|
|
48
|
+
|
|
49
|
+
###########################################
|
|
50
|
+
|
|
51
|
+
cdef class HiddenMarkovModel:
|
|
52
|
+
r"""
|
|
53
|
+
Abstract base class for all Hidden Markov Models.
|
|
54
|
+
"""
|
|
55
|
+
def initial_probabilities(self):
|
|
56
|
+
r"""
|
|
57
|
+
Return the initial probabilities as a :class:`TimeSeries` of
|
|
58
|
+
length `N`, where `N` is the number of states of the Markov model.
|
|
59
|
+
|
|
60
|
+
EXAMPLES::
|
|
61
|
+
|
|
62
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]],
|
|
63
|
+
....: [[0.1,0.9],[0.5,0.5]],
|
|
64
|
+
....: [.2,.8])
|
|
65
|
+
sage: pi = m.initial_probabilities(); pi
|
|
66
|
+
[0.2000, 0.8000]
|
|
67
|
+
sage: type(pi)
|
|
68
|
+
<... 'sage.stats.time_series.TimeSeries'>
|
|
69
|
+
|
|
70
|
+
The returned time series is a copy, so changing it does not
|
|
71
|
+
change the model::
|
|
72
|
+
|
|
73
|
+
sage: pi[0] = .1; pi[1] = .9
|
|
74
|
+
sage: m.initial_probabilities()
|
|
75
|
+
[0.2000, 0.8000]
|
|
76
|
+
|
|
77
|
+
Some other models::
|
|
78
|
+
|
|
79
|
+
sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]],
|
|
80
|
+
....: [(1,1), (-1,1)],
|
|
81
|
+
....: [.1,.9])
|
|
82
|
+
sage: m.initial_probabilities()
|
|
83
|
+
[0.1000, 0.9000]
|
|
84
|
+
sage: m = hmm.GaussianMixtureHiddenMarkovModel(
|
|
85
|
+
....: [[.9,.1],[.4,.6]],
|
|
86
|
+
....: [[(.4,(0,1)), (.6,(1,0.1))], [(1,(0,1))]],
|
|
87
|
+
....: [.7,.3])
|
|
88
|
+
sage: m.initial_probabilities()
|
|
89
|
+
[0.7000, 0.3000]
|
|
90
|
+
"""
|
|
91
|
+
return TimeSeries(self.pi)
|
|
92
|
+
|
|
93
|
+
def transition_matrix(self):
|
|
94
|
+
r"""
|
|
95
|
+
Return the state transition matrix.
|
|
96
|
+
|
|
97
|
+
OUTPUT: a Sage matrix with real double precision (RDF) entries.
|
|
98
|
+
|
|
99
|
+
EXAMPLES::
|
|
100
|
+
|
|
101
|
+
sage: M = hmm.DiscreteHiddenMarkovModel([[0.7,0.3],[0.9,0.1]],
|
|
102
|
+
....: [[0.5,.5],[.1,.9]],
|
|
103
|
+
....: [0.3,0.7])
|
|
104
|
+
sage: T = M.transition_matrix(); T
|
|
105
|
+
[0.7 0.3]
|
|
106
|
+
[0.9 0.1]
|
|
107
|
+
|
|
108
|
+
The returned matrix is mutable, but changing it does not
|
|
109
|
+
change the transition matrix for the model::
|
|
110
|
+
|
|
111
|
+
sage: T[0,0] = .1; T[0,1] = .9
|
|
112
|
+
sage: M.transition_matrix()
|
|
113
|
+
[0.7 0.3]
|
|
114
|
+
[0.9 0.1]
|
|
115
|
+
|
|
116
|
+
Transition matrices for other types of models::
|
|
117
|
+
|
|
118
|
+
sage: M = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]],
|
|
119
|
+
....: [(1,1), (-1,1)],
|
|
120
|
+
....: [.5,.5])
|
|
121
|
+
sage: M.transition_matrix()
|
|
122
|
+
[0.1 0.9]
|
|
123
|
+
[0.5 0.5]
|
|
124
|
+
sage: M = hmm.GaussianMixtureHiddenMarkovModel(
|
|
125
|
+
....: [[.9,.1],[.4,.6]],
|
|
126
|
+
....: [[(.4,(0,1)), (.6,(1,0.1))],[(1,(0,1))]],
|
|
127
|
+
....: [.7,.3])
|
|
128
|
+
sage: M.transition_matrix()
|
|
129
|
+
[0.9 0.1]
|
|
130
|
+
[0.4 0.6]
|
|
131
|
+
"""
|
|
132
|
+
from sage.matrix.constructor import matrix
|
|
133
|
+
from sage.rings.real_double import RDF
|
|
134
|
+
return matrix(RDF, self.N, self.A.list())
|
|
135
|
+
|
|
136
|
+
def graph(self, eps=1e-3):
|
|
137
|
+
r"""
|
|
138
|
+
Create a weighted directed graph from the transition matrix,
|
|
139
|
+
not including any edge with a probability less than ``eps``.
|
|
140
|
+
|
|
141
|
+
INPUT:
|
|
142
|
+
|
|
143
|
+
- ``eps`` -- nonnegative real number
|
|
144
|
+
|
|
145
|
+
OUTPUT: a :class:`DiGraph`
|
|
146
|
+
|
|
147
|
+
EXAMPLES::
|
|
148
|
+
|
|
149
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[.3,0,.7],[0,0,1],[.5,.5,0]],
|
|
150
|
+
....: [[.5,.5,.2]]*3,
|
|
151
|
+
....: [1/3]*3)
|
|
152
|
+
sage: G = m.graph(); G # needs sage.graphs
|
|
153
|
+
Looped digraph on 3 vertices
|
|
154
|
+
sage: G.edges(sort=True) # needs sage.graphs
|
|
155
|
+
[(0, 0, 0.3), (0, 2, 0.7), (1, 2, 1.0), (2, 0, 0.5), (2, 1, 0.5)]
|
|
156
|
+
sage: G.plot() # needs sage.graphs sage.plot
|
|
157
|
+
Graphics object consisting of 11 graphics primitives
|
|
158
|
+
"""
|
|
159
|
+
cdef int i, j
|
|
160
|
+
m = self.transition_matrix()
|
|
161
|
+
for i in range(self.N):
|
|
162
|
+
for j in range(self.N):
|
|
163
|
+
if m[i,j] < eps:
|
|
164
|
+
m[i,j] = 0
|
|
165
|
+
from sage.graphs.digraph import DiGraph
|
|
166
|
+
return DiGraph(m, weighted=True)
|
|
167
|
+
|
|
168
|
+
def sample(self, Py_ssize_t length, number=None, starting_state=None):
|
|
169
|
+
r"""
|
|
170
|
+
Return number samples from this HMM of given length.
|
|
171
|
+
|
|
172
|
+
INPUT:
|
|
173
|
+
|
|
174
|
+
- ``length`` -- positive integer
|
|
175
|
+
- ``number`` -- (default: ``None``) if given, compute list of this many
|
|
176
|
+
sample sequences
|
|
177
|
+
- ``starting_state`` -- integer (or ``None``); if specified, generate a
|
|
178
|
+
sequence using this model starting with the given state instead of
|
|
179
|
+
the initial probabilities to determine the starting state
|
|
180
|
+
|
|
181
|
+
OUTPUT:
|
|
182
|
+
|
|
183
|
+
- if ``number`` is not given, return a single :class:`TimeSeries`.
|
|
184
|
+
- if ``number`` is given, return a list of :class:`TimeSeries`.
|
|
185
|
+
|
|
186
|
+
EXAMPLES::
|
|
187
|
+
|
|
188
|
+
sage: set_random_seed(0)
|
|
189
|
+
sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]],
|
|
190
|
+
....: [[1,0],[0,1]],
|
|
191
|
+
....: [0,1])
|
|
192
|
+
sage: print(a.sample(10, 3))
|
|
193
|
+
[[1, 0, 1, 1, 1, 1, 0, 1, 1, 1],
|
|
194
|
+
[1, 1, 0, 0, 1, 1, 1, 1, 1, 1],
|
|
195
|
+
[1, 1, 1, 1, 0, 1, 0, 1, 1, 1]]
|
|
196
|
+
sage: a.sample(15)
|
|
197
|
+
[1, 1, 1, 1, 0 ... 1, 1, 1, 1, 1]
|
|
198
|
+
sage: a.sample(3, 1)
|
|
199
|
+
[[1, 1, 1]]
|
|
200
|
+
sage: list(a.sample(1000)).count(0)
|
|
201
|
+
88
|
|
202
|
+
|
|
203
|
+
If the emission symbols are set::
|
|
204
|
+
|
|
205
|
+
sage: set_random_seed(0)
|
|
206
|
+
sage: a = hmm.DiscreteHiddenMarkovModel([[0.5,0.5],[0.1,0.9]],
|
|
207
|
+
....: [[1,0],[0,1]], [0,1],
|
|
208
|
+
....: ['up', 'down'])
|
|
209
|
+
sage: a.sample(10)
|
|
210
|
+
['down', 'up', 'down', 'down', 'down', 'down', 'up', 'up', 'up', 'up']
|
|
211
|
+
|
|
212
|
+
Force a starting state::
|
|
213
|
+
|
|
214
|
+
sage: set_random_seed(0); a.sample(10, starting_state=0)
|
|
215
|
+
['up', 'up', 'down', 'down', 'down', 'down', 'up', 'up', 'up', 'up']
|
|
216
|
+
"""
|
|
217
|
+
if number is None:
|
|
218
|
+
return self.generate_sequence(length, starting_state=starting_state)[0]
|
|
219
|
+
|
|
220
|
+
cdef Py_ssize_t i
|
|
221
|
+
return [self.generate_sequence(length, starting_state=starting_state)[0] for i in range(number)]
|
|
222
|
+
|
|
223
|
+
#########################################################
|
|
224
|
+
# Some internal functions used for various general
|
|
225
|
+
# HMM algorithms.
|
|
226
|
+
#########################################################
|
|
227
|
+
cdef TimeSeries _baum_welch_gamma(self, TimeSeries alpha, TimeSeries beta):
|
|
228
|
+
r"""
|
|
229
|
+
Used internally to compute the scaled quantity gamma_t(j)
|
|
230
|
+
appearing in the Baum-Welch reestimation algorithm.
|
|
231
|
+
|
|
232
|
+
The quantity gamma_t(j) is the (scaled!) probability of being
|
|
233
|
+
in state j at time t, given the observation sequence.
|
|
234
|
+
|
|
235
|
+
INPUT:
|
|
236
|
+
|
|
237
|
+
- ``alpha`` -- :class:`TimeSeries` as output by the scaled forward algorithm
|
|
238
|
+
- ``beta`` -- :class:`TimeSeries` as output by the scaled backward algorithm
|
|
239
|
+
|
|
240
|
+
OUTPUT: :class:`TimeSeries` gamma such that gamma[t*N+j] is gamma_t(j).
|
|
241
|
+
"""
|
|
242
|
+
cdef int j, N = self.N
|
|
243
|
+
cdef Py_ssize_t t, T = alpha._length//N
|
|
244
|
+
cdef TimeSeries gamma = TimeSeries(alpha._length, initialize=False)
|
|
245
|
+
cdef double denominator
|
|
246
|
+
sig_on()
|
|
247
|
+
for t in range(T):
|
|
248
|
+
denominator = 0
|
|
249
|
+
for j in range(N):
|
|
250
|
+
gamma._values[t*N + j] = alpha._values[t*N + j] * beta._values[t*N + j]
|
|
251
|
+
denominator += gamma._values[t*N + j]
|
|
252
|
+
for j in range(N):
|
|
253
|
+
gamma._values[t*N + j] /= denominator
|
|
254
|
+
sig_off()
|
|
255
|
+
return gamma
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel):
|
|
259
|
+
r"""
|
|
260
|
+
A discrete Hidden Markov model implemented using double precision
|
|
261
|
+
floating point arithmetic.
|
|
262
|
+
|
|
263
|
+
INPUT:
|
|
264
|
+
|
|
265
|
+
- ``A`` -- list of lists or a square `N \times N` matrix, whose
|
|
266
|
+
`(i,j)` entry gives the probability of transitioning from
|
|
267
|
+
state `i` to state `j`.
|
|
268
|
+
|
|
269
|
+
- ``B`` -- list of `N` lists or a matrix with `N` rows, such that
|
|
270
|
+
`B[i,k]` gives the probability of emitting symbol `k` while
|
|
271
|
+
in state `i`.
|
|
272
|
+
|
|
273
|
+
- ``pi`` -- the probabilities of starting in each initial
|
|
274
|
+
state, i.e., ``pi[i]`` is the probability of starting in
|
|
275
|
+
state `i`.
|
|
276
|
+
|
|
277
|
+
- ``emission_symbols`` -- ``None`` or list (default: ``None``); if
|
|
278
|
+
None, the emission_symbols are the ints ``[0..N-1]``, where `N`
|
|
279
|
+
is the number of states. Otherwise, they are the entries
|
|
280
|
+
of the list ``emissions_symbols``, which must all be hashable.
|
|
281
|
+
|
|
282
|
+
- ``normalize`` -- boolean (default: ``True``); if given, input is
|
|
283
|
+
normalized to define valid probability distributions,
|
|
284
|
+
e.g., the entries of `A` are made nonnegative and the rows
|
|
285
|
+
sum to 1, and the probabilities in ``pi`` are normalized.
|
|
286
|
+
|
|
287
|
+
EXAMPLES::
|
|
288
|
+
|
|
289
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]],
|
|
290
|
+
....: [[0.1,0.9],[0.5,0.5]],
|
|
291
|
+
....: [.5,.5]); m
|
|
292
|
+
Discrete Hidden Markov Model with 2 States and 2 Emissions
|
|
293
|
+
Transition matrix:
|
|
294
|
+
[0.4 0.6]
|
|
295
|
+
[0.1 0.9]
|
|
296
|
+
Emission matrix:
|
|
297
|
+
[0.1 0.9]
|
|
298
|
+
[0.5 0.5]
|
|
299
|
+
Initial probabilities: [0.5000, 0.5000]
|
|
300
|
+
sage: m.log_likelihood([0,1,0,1,0,1])
|
|
301
|
+
-4.66693474691329...
|
|
302
|
+
sage: m.viterbi([0,1,0,1,0,1])
|
|
303
|
+
([1, 1, 1, 1, 1, 1], -5.378832842208748)
|
|
304
|
+
sage: m.baum_welch([0,1,0,1,0,1])
|
|
305
|
+
(0.0, 22)
|
|
306
|
+
sage: m # rel tol 1e-10
|
|
307
|
+
Discrete Hidden Markov Model with 2 States and 2 Emissions
|
|
308
|
+
Transition matrix:
|
|
309
|
+
[1.0134345614745788e-70 1.0]
|
|
310
|
+
[ 1.0 3.9974352713558623e-19]
|
|
311
|
+
Emission matrix:
|
|
312
|
+
[ 7.380221566254936e-54 1.0]
|
|
313
|
+
[ 1.0 3.9974352626002193e-19]
|
|
314
|
+
Initial probabilities: [0.0000, 1.0000]
|
|
315
|
+
sage: m.sample(10)
|
|
316
|
+
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
|
|
317
|
+
sage: m.graph().plot() # needs sage.plot
|
|
318
|
+
Graphics object consisting of 6 graphics primitives
|
|
319
|
+
|
|
320
|
+
A 3-state model that happens to always outputs 'b'::
|
|
321
|
+
|
|
322
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[1/3]*3]*3, [[0,1,0]]*3, [1/3]*3, ['a','b','c'])
|
|
323
|
+
sage: m.sample(10)
|
|
324
|
+
['b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b']
|
|
325
|
+
"""
|
|
326
|
+
cdef TimeSeries B
|
|
327
|
+
cdef int n_out
|
|
328
|
+
cdef object _emission_symbols, _emission_symbols_dict
|
|
329
|
+
|
|
330
|
+
def __init__(self, A, B, pi, emission_symbols=None, bint normalize=True):
|
|
331
|
+
r"""
|
|
332
|
+
Create a discrete emissions HMM with transition probability
|
|
333
|
+
matrix A, emission probabilities given by B, initial state
|
|
334
|
+
probabilities pi, and given emission symbols (which default
|
|
335
|
+
to the first few nonnegative integers).
|
|
336
|
+
|
|
337
|
+
EXAMPLES::
|
|
338
|
+
|
|
339
|
+
sage: hmm.DiscreteHiddenMarkovModel([.5,0,-1,.5], [[1],[1]],[.5,.5]).transition_matrix()
|
|
340
|
+
[1.0 0.0]
|
|
341
|
+
[0.0 1.0]
|
|
342
|
+
sage: hmm.DiscreteHiddenMarkovModel([0,0,.1,.9], [[1],[1]],[.5,.5]).transition_matrix()
|
|
343
|
+
[0.5 0.5]
|
|
344
|
+
[0.1 0.9]
|
|
345
|
+
sage: hmm.DiscreteHiddenMarkovModel([-1,-2,.1,.9], [[1],[1]],[.5,.5]).transition_matrix()
|
|
346
|
+
[0.5 0.5]
|
|
347
|
+
[0.1 0.9]
|
|
348
|
+
sage: hmm.DiscreteHiddenMarkovModel([1,2,.1,1.2], [[1],[1]],[.5,.5]).transition_matrix()
|
|
349
|
+
[ 0.3333333333333333 0.6666666666666666]
|
|
350
|
+
[0.07692307692307693 0.923076923076923]
|
|
351
|
+
"""
|
|
352
|
+
self.pi = util.initial_probs_to_TimeSeries(pi, normalize)
|
|
353
|
+
self.N = len(self.pi)
|
|
354
|
+
self.A = util.state_matrix_to_TimeSeries(A, self.N, normalize)
|
|
355
|
+
self._emission_symbols = emission_symbols
|
|
356
|
+
if self._emission_symbols is not None:
|
|
357
|
+
self._emission_symbols_dict = dict([(y,x) for x,y in enumerate(emission_symbols)])
|
|
358
|
+
|
|
359
|
+
if not isinstance(B, Matrix):
|
|
360
|
+
B = matrix(B)
|
|
361
|
+
if B.nrows() != self.N:
|
|
362
|
+
raise ValueError("number of rows of B must equal number of states")
|
|
363
|
+
self.B = TimeSeries(B.list())
|
|
364
|
+
self.n_out = B.ncols()
|
|
365
|
+
if emission_symbols is not None and len(emission_symbols) != self.n_out:
|
|
366
|
+
raise ValueError("number of emission symbols must equal number of output states")
|
|
367
|
+
cdef Py_ssize_t i
|
|
368
|
+
if normalize:
|
|
369
|
+
for i in range(self.N):
|
|
370
|
+
util.normalize_probability_TimeSeries(self.B, i*self.n_out, (i+1)*self.n_out)
|
|
371
|
+
|
|
372
|
+
def __reduce__(self):
|
|
373
|
+
r"""
|
|
374
|
+
Used in pickling.
|
|
375
|
+
|
|
376
|
+
EXAMPLES::
|
|
377
|
+
|
|
378
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.0,1.0],[1,1]], [0,1], ['a','b'])
|
|
379
|
+
sage: loads(dumps(m)) == m
|
|
380
|
+
True
|
|
381
|
+
"""
|
|
382
|
+
return unpickle_discrete_hmm_v1, \
|
|
383
|
+
(self.A, self.B, self.pi, self.n_out, self._emission_symbols, self._emission_symbols_dict)
|
|
384
|
+
|
|
385
|
+
def __richcmp__(self, other, op):
|
|
386
|
+
r"""
|
|
387
|
+
EXAMPLES::
|
|
388
|
+
|
|
389
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.0,1.0],[0.5,0.5]], [.5,.5])
|
|
390
|
+
sage: n = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.0,1.0],[0.5,0.5]], [1,0])
|
|
391
|
+
sage: m == n
|
|
392
|
+
False
|
|
393
|
+
sage: m == m
|
|
394
|
+
True
|
|
395
|
+
sage: m < n
|
|
396
|
+
True
|
|
397
|
+
sage: n < m
|
|
398
|
+
False
|
|
399
|
+
"""
|
|
400
|
+
if not isinstance(other, DiscreteHiddenMarkovModel):
|
|
401
|
+
return NotImplemented
|
|
402
|
+
return PyObject_RichCompare(self.__reduce__()[1],
|
|
403
|
+
other.__reduce__()[1], op)
|
|
404
|
+
|
|
405
|
+
def emission_matrix(self):
|
|
406
|
+
r"""
|
|
407
|
+
Return the matrix whose `i`-th row specifies the emission
|
|
408
|
+
probability distribution for the `i`-th state.
|
|
409
|
+
|
|
410
|
+
More precisely,
|
|
411
|
+
the `i,j` entry of the matrix is the probability of the Markov
|
|
412
|
+
model outputting the `j`-th symbol when it is in the `i`-th state.
|
|
413
|
+
|
|
414
|
+
OUTPUT: a Sage matrix with real double precision (RDF) entries.
|
|
415
|
+
|
|
416
|
+
EXAMPLES::
|
|
417
|
+
|
|
418
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]],
|
|
419
|
+
....: [[0.1,0.9],[0.5,0.5]],
|
|
420
|
+
....: [.5,.5])
|
|
421
|
+
sage: E = m.emission_matrix(); E
|
|
422
|
+
[0.1 0.9]
|
|
423
|
+
[0.5 0.5]
|
|
424
|
+
|
|
425
|
+
The returned matrix is mutable, but changing it does not
|
|
426
|
+
change the transition matrix for the model::
|
|
427
|
+
|
|
428
|
+
sage: E[0,0] = 0; E[0,1] = 1
|
|
429
|
+
sage: m.emission_matrix()
|
|
430
|
+
[0.1 0.9]
|
|
431
|
+
[0.5 0.5]
|
|
432
|
+
"""
|
|
433
|
+
from sage.matrix.constructor import matrix
|
|
434
|
+
from sage.rings.real_double import RDF
|
|
435
|
+
return matrix(RDF, self.N, self.n_out, self.B.list())
|
|
436
|
+
|
|
437
|
+
def __repr__(self):
|
|
438
|
+
r"""
|
|
439
|
+
Return string representation of this discrete hidden Markov model.
|
|
440
|
+
|
|
441
|
+
EXAMPLES::
|
|
442
|
+
|
|
443
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.5,0.5]], [.2,.8])
|
|
444
|
+
sage: m.__repr__()
|
|
445
|
+
'Discrete Hidden Markov Model with 2 States and 2 Emissions\nTransition matrix:\n[0.4 0.6]\n[0.1 0.9]\nEmission matrix:\n[0.1 0.9]\n[0.5 0.5]\nInitial probabilities: [0.2000, 0.8000]'
|
|
446
|
+
"""
|
|
447
|
+
s = "Discrete Hidden Markov Model with %s States and %s Emissions" % (
|
|
448
|
+
self.N, self.n_out)
|
|
449
|
+
s += '\nTransition matrix:\n%s' % self.transition_matrix()
|
|
450
|
+
s += '\nEmission matrix:\n%s' % self.emission_matrix()
|
|
451
|
+
s += '\nInitial probabilities: %s' % self.initial_probabilities()
|
|
452
|
+
if self._emission_symbols is not None:
|
|
453
|
+
s += '\nEmission symbols: %s' % self._emission_symbols
|
|
454
|
+
return s
|
|
455
|
+
|
|
456
|
+
def _emission_symbols_to_IntList(self, obs):
|
|
457
|
+
r"""
|
|
458
|
+
Internal function used to convert a list of emission symbols to an :class:`IntList`.
|
|
459
|
+
|
|
460
|
+
INPUT:
|
|
461
|
+
|
|
462
|
+
- ``obs`` -- list of objects
|
|
463
|
+
|
|
464
|
+
OUTPUT: an IntList
|
|
465
|
+
|
|
466
|
+
EXAMPLES::
|
|
467
|
+
|
|
468
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.5,0.5]], [.2,.8], ['smile', 'frown'])
|
|
469
|
+
sage: m._emission_symbols_to_IntList(['frown','smile'])
|
|
470
|
+
[1, 0]
|
|
471
|
+
"""
|
|
472
|
+
d = self._emission_symbols_dict
|
|
473
|
+
return IntList([d[x] for x in obs])
|
|
474
|
+
|
|
475
|
+
def _IntList_to_emission_symbols(self, obs):
|
|
476
|
+
r"""
|
|
477
|
+
Internal function used to convert a list of emission symbols to an IntList.
|
|
478
|
+
|
|
479
|
+
INPUT:
|
|
480
|
+
|
|
481
|
+
- ``obs`` -- list of objects
|
|
482
|
+
|
|
483
|
+
OUTPUT: an IntList
|
|
484
|
+
|
|
485
|
+
EXAMPLES::
|
|
486
|
+
|
|
487
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.5,0.5]], [.2,.8], ['smile', 'frown'])
|
|
488
|
+
sage: m._IntList_to_emission_symbols(stats.IntList([0,0,1,0]))
|
|
489
|
+
['smile', 'smile', 'frown', 'smile']
|
|
490
|
+
"""
|
|
491
|
+
d = self._emission_symbols
|
|
492
|
+
return [d[x] for x in obs]
|
|
493
|
+
|
|
494
|
+
def log_likelihood(self, obs, bint scale=True):
|
|
495
|
+
r"""
|
|
496
|
+
Return the logarithm of the probability that this model produced the given
|
|
497
|
+
observation sequence. Thus the output is a nonpositive number.
|
|
498
|
+
|
|
499
|
+
INPUT:
|
|
500
|
+
|
|
501
|
+
- ``obs`` -- sequence of observations
|
|
502
|
+
|
|
503
|
+
- ``scale`` -- boolean (default: ``True``); if ``True``, use rescaling
|
|
504
|
+
to overoid loss of precision due to the very limited
|
|
505
|
+
dynamic range of floats. You should leave this as ``True``
|
|
506
|
+
unless the ``obs`` sequence is very small.
|
|
507
|
+
|
|
508
|
+
EXAMPLES::
|
|
509
|
+
|
|
510
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]],
|
|
511
|
+
....: [[0.1,0.9],[0.5,0.5]],
|
|
512
|
+
....: [.2,.8])
|
|
513
|
+
sage: m.log_likelihood([0, 1, 0, 1, 1, 0, 1, 0, 0, 0])
|
|
514
|
+
-7.3301308009370825
|
|
515
|
+
sage: m.log_likelihood([0, 1, 0, 1, 1, 0, 1, 0, 0, 0], scale=False)
|
|
516
|
+
-7.330130800937082
|
|
517
|
+
sage: m.log_likelihood([])
|
|
518
|
+
0.0
|
|
519
|
+
|
|
520
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]],
|
|
521
|
+
....: [[0.1,0.9],[0.5,0.5]],
|
|
522
|
+
....: [.2,.8], ['happy','sad'])
|
|
523
|
+
sage: m.log_likelihood(['happy','happy'])
|
|
524
|
+
-1.6565295199679506
|
|
525
|
+
sage: m.log_likelihood(['happy','sad'])
|
|
526
|
+
-1.4731602941415523
|
|
527
|
+
|
|
528
|
+
Overflow from not using the scale option::
|
|
529
|
+
|
|
530
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]],
|
|
531
|
+
....: [[0.1,0.9],[0.5,0.5]],
|
|
532
|
+
....: [.2,.8])
|
|
533
|
+
sage: m.log_likelihood([0,1]*1000, scale=True)
|
|
534
|
+
-1433.820666652728
|
|
535
|
+
sage: m.log_likelihood([0,1]*1000, scale=False)
|
|
536
|
+
-inf
|
|
537
|
+
"""
|
|
538
|
+
if len(obs) == 0:
|
|
539
|
+
return 0.0
|
|
540
|
+
if self._emission_symbols is not None:
|
|
541
|
+
obs = self._emission_symbols_to_IntList(obs)
|
|
542
|
+
if not isinstance(obs, IntList):
|
|
543
|
+
obs = IntList(obs)
|
|
544
|
+
if scale:
|
|
545
|
+
return self._forward_scale(obs)
|
|
546
|
+
else:
|
|
547
|
+
return self._forward(obs)
|
|
548
|
+
|
|
549
|
+
def _forward(self, IntList obs):
|
|
550
|
+
r"""
|
|
551
|
+
Memory-efficient implementation of the forward algorithm, without
|
|
552
|
+
scaling.
|
|
553
|
+
|
|
554
|
+
INPUT:
|
|
555
|
+
|
|
556
|
+
- ``obs`` -- integer list of observation states
|
|
557
|
+
|
|
558
|
+
OUTPUT: ``float`` -- the log of the probability that the model produced
|
|
559
|
+
this sequence
|
|
560
|
+
|
|
561
|
+
EXAMPLES::
|
|
562
|
+
|
|
563
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.5,0.5]], [.2,.8])
|
|
564
|
+
sage: m._forward(stats.IntList([0,1]*10))
|
|
565
|
+
-14.378663512219456
|
|
566
|
+
|
|
567
|
+
The forward algorithm computes the log likelihood::
|
|
568
|
+
|
|
569
|
+
sage: m.log_likelihood(stats.IntList([0,1]*10), scale=False)
|
|
570
|
+
-14.378663512219456
|
|
571
|
+
|
|
572
|
+
But numerical overflow will happen (without scaling) for long sequences::
|
|
573
|
+
|
|
574
|
+
sage: m._forward(stats.IntList([0,1]*1000))
|
|
575
|
+
-inf
|
|
576
|
+
"""
|
|
577
|
+
if obs.max() > self.N or obs.min() < 0:
|
|
578
|
+
raise ValueError("invalid observation sequence, since it includes unknown states")
|
|
579
|
+
|
|
580
|
+
cdef Py_ssize_t i, j, t, T = len(obs)
|
|
581
|
+
|
|
582
|
+
cdef TimeSeries alpha = TimeSeries(self.N), \
|
|
583
|
+
alpha2 = TimeSeries(self.N)
|
|
584
|
+
|
|
585
|
+
# Initialization
|
|
586
|
+
for i in range(self.N):
|
|
587
|
+
alpha[i] = self.pi[i] * self.B[i*self.n_out + obs._values[0]]
|
|
588
|
+
alpha[i] = self.pi[i] * self.B[i*self.n_out + obs._values[0]]
|
|
589
|
+
|
|
590
|
+
# Induction
|
|
591
|
+
cdef double s
|
|
592
|
+
for t in range(1, T):
|
|
593
|
+
for j in range(self.N):
|
|
594
|
+
s = 0
|
|
595
|
+
for i in range(self.N):
|
|
596
|
+
s += alpha._values[i] * self.A._values[i*self.N + j]
|
|
597
|
+
alpha2._values[j] = s * self.B._values[j*self.n_out+obs._values[t]]
|
|
598
|
+
for j in range(self.N):
|
|
599
|
+
alpha._values[j] = alpha2._values[j]
|
|
600
|
+
|
|
601
|
+
# Termination
|
|
602
|
+
return log(alpha.sum())
|
|
603
|
+
|
|
604
|
+
def _forward_scale(self, IntList obs):
|
|
605
|
+
r"""
|
|
606
|
+
Memory-efficient implementation of the forward algorithm, with scaling.
|
|
607
|
+
|
|
608
|
+
INPUT:
|
|
609
|
+
|
|
610
|
+
- ``obs`` -- integer list of observation states
|
|
611
|
+
|
|
612
|
+
OUTPUT: ``float`` -- the log of the probability that the model produced
|
|
613
|
+
this sequence
|
|
614
|
+
|
|
615
|
+
EXAMPLES::
|
|
616
|
+
|
|
617
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.5,0.5]], [.2,.8])
|
|
618
|
+
sage: m._forward_scale(stats.IntList([0,1]*10))
|
|
619
|
+
-14.378663512219454
|
|
620
|
+
|
|
621
|
+
The forward algorithm computes the log likelihood::
|
|
622
|
+
|
|
623
|
+
sage: m.log_likelihood(stats.IntList([0,1]*10))
|
|
624
|
+
-14.378663512219454
|
|
625
|
+
|
|
626
|
+
Note that the scale algorithm ensures that numerical overflow
|
|
627
|
+
won't happen for long sequences like it does with the forward
|
|
628
|
+
non-scaled algorithm::
|
|
629
|
+
|
|
630
|
+
sage: m._forward_scale(stats.IntList([0,1]*1000))
|
|
631
|
+
-1433.820666652728
|
|
632
|
+
sage: m._forward(stats.IntList([0,1]*1000))
|
|
633
|
+
-inf
|
|
634
|
+
|
|
635
|
+
A random sequence produced by the model is more likely::
|
|
636
|
+
|
|
637
|
+
sage: set_random_seed(0); v = m.sample(1000)
|
|
638
|
+
sage: m._forward_scale(v)
|
|
639
|
+
-686.8753189365056
|
|
640
|
+
"""
|
|
641
|
+
# This is just like self._forward(obs) above, except at every step of the
|
|
642
|
+
# algorithm, we rescale the vector alpha so that the sum of
|
|
643
|
+
# the entries in alpha is 1. Then, at the end of the
|
|
644
|
+
# algorithm, the sum of probabilities (alpha.sum()) is of
|
|
645
|
+
# course just 1. However, the true probability that we want
|
|
646
|
+
# is the product of the numbers that we divided by when
|
|
647
|
+
# rescaling, since at each step of the iteration the next term
|
|
648
|
+
# depends linearly on the previous one. Instead of returning
|
|
649
|
+
# the product, we return the sum of the logs, which avoid
|
|
650
|
+
# numerical error.
|
|
651
|
+
cdef Py_ssize_t i, j, t, T = len(obs)
|
|
652
|
+
|
|
653
|
+
# The running some of the log probabilities
|
|
654
|
+
cdef double log_probability = 0, sum, a
|
|
655
|
+
|
|
656
|
+
cdef TimeSeries alpha = TimeSeries(self.N), \
|
|
657
|
+
alpha2 = TimeSeries(self.N)
|
|
658
|
+
|
|
659
|
+
# Initialization
|
|
660
|
+
sum = 0
|
|
661
|
+
for i in range(self.N):
|
|
662
|
+
a = self.pi[i] * self.B[i*self.n_out + obs._values[0]]
|
|
663
|
+
alpha[i] = a
|
|
664
|
+
sum += a
|
|
665
|
+
|
|
666
|
+
log_probability = log(sum)
|
|
667
|
+
alpha.rescale(1/sum)
|
|
668
|
+
|
|
669
|
+
# Induction
|
|
670
|
+
# The code below is just an optimized version of:
|
|
671
|
+
# alpha = (alpha * A).pairwise_product(B[O[t+1]])
|
|
672
|
+
# alpha = alpha.scale(1/alpha.sum())
|
|
673
|
+
# along with keeping track of the log of the scaling factor.
|
|
674
|
+
cdef double s
|
|
675
|
+
for t in range(1, T):
|
|
676
|
+
sum = 0
|
|
677
|
+
for j in range(self.N):
|
|
678
|
+
s = 0
|
|
679
|
+
for i in range(self.N):
|
|
680
|
+
s += alpha._values[i] * self.A._values[i*self.N + j]
|
|
681
|
+
a = s * self.B._values[j*self.n_out+obs._values[t]]
|
|
682
|
+
alpha2._values[j] = a
|
|
683
|
+
sum += a
|
|
684
|
+
|
|
685
|
+
log_probability += log(sum)
|
|
686
|
+
for j in range(self.N):
|
|
687
|
+
alpha._values[j] = alpha2._values[j] / sum
|
|
688
|
+
|
|
689
|
+
# Termination
|
|
690
|
+
return log_probability
|
|
691
|
+
|
|
692
|
+
def generate_sequence(self, Py_ssize_t length, starting_state=None):
|
|
693
|
+
r"""
|
|
694
|
+
Return a sample of the given length from this HMM.
|
|
695
|
+
|
|
696
|
+
INPUT:
|
|
697
|
+
|
|
698
|
+
- ``length`` -- positive integer
|
|
699
|
+
- ``starting_state`` -- integer (or ``None``); if specified, generate a
|
|
700
|
+
sequence using this model starting with the given state instead of
|
|
701
|
+
the initial probabilities to determine the starting state
|
|
702
|
+
|
|
703
|
+
OUTPUT:
|
|
704
|
+
|
|
705
|
+
- an :class:`IntList` or list of emission symbols
|
|
706
|
+
- :class:`IntList` of the actual states the model was in when
|
|
707
|
+
emitting the corresponding symbols
|
|
708
|
+
|
|
709
|
+
EXAMPLES:
|
|
710
|
+
|
|
711
|
+
In this example, the emission symbols are not set::
|
|
712
|
+
|
|
713
|
+
sage: set_random_seed(0)
|
|
714
|
+
sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]],
|
|
715
|
+
....: [[1,0],[0,1]],
|
|
716
|
+
....: [0,1])
|
|
717
|
+
sage: a.generate_sequence(5)
|
|
718
|
+
([1, 0, 1, 1, 1], [1, 0, 1, 1, 1])
|
|
719
|
+
sage: list(a.generate_sequence(1000)[0]).count(0)
|
|
720
|
+
90
|
|
721
|
+
|
|
722
|
+
Here the emission symbols are set::
|
|
723
|
+
|
|
724
|
+
sage: set_random_seed(0)
|
|
725
|
+
sage: a = hmm.DiscreteHiddenMarkovModel([[0.5,0.5],[0.1,0.9]],
|
|
726
|
+
....: [[1,0],[0,1]],
|
|
727
|
+
....: [0,1], ['up', 'down'])
|
|
728
|
+
sage: a.generate_sequence(5)
|
|
729
|
+
(['down', 'up', 'down', 'down', 'down'], [1, 0, 1, 1, 1])
|
|
730
|
+
|
|
731
|
+
Specify the starting state::
|
|
732
|
+
|
|
733
|
+
sage: set_random_seed(0); a.generate_sequence(5, starting_state=0)
|
|
734
|
+
(['up', 'up', 'down', 'down', 'down'], [0, 0, 1, 1, 1])
|
|
735
|
+
"""
|
|
736
|
+
if length < 0:
|
|
737
|
+
raise ValueError("length must be nonnegative")
|
|
738
|
+
|
|
739
|
+
# Create Integer lists for states and observations
|
|
740
|
+
cdef IntList states = IntList(length)
|
|
741
|
+
cdef IntList obs = IntList(length)
|
|
742
|
+
if length == 0:
|
|
743
|
+
# A special case
|
|
744
|
+
if self._emission_symbols is None:
|
|
745
|
+
return states, obs
|
|
746
|
+
else:
|
|
747
|
+
return states, []
|
|
748
|
+
|
|
749
|
+
# Setup variables, including random state.
|
|
750
|
+
cdef Py_ssize_t i, j
|
|
751
|
+
cdef randstate rstate = current_randstate()
|
|
752
|
+
cdef int q = 0
|
|
753
|
+
cdef double r, accum
|
|
754
|
+
r = rstate.c_rand_double()
|
|
755
|
+
|
|
756
|
+
# Now choose random variables from our discrete distribution.
|
|
757
|
+
|
|
758
|
+
# This standard naive algorithm has complexity that is linear
|
|
759
|
+
# in the number of states. It might be possible to replace it
|
|
760
|
+
# by something that is more efficient. However, make sure to
|
|
761
|
+
# refactor this code into distribution.pyx before doing so.
|
|
762
|
+
# Note that state switching involves the same algorithm
|
|
763
|
+
# (below). Use GSL as described here to make this O(1):
|
|
764
|
+
# http://www.gnu.org/software/gsl/manual/html_node/General-Discrete-Distributions.html
|
|
765
|
+
|
|
766
|
+
# Choose initial state:
|
|
767
|
+
if starting_state is None:
|
|
768
|
+
accum = 0
|
|
769
|
+
for i in range(self.N):
|
|
770
|
+
if r < self.pi._values[i] + accum:
|
|
771
|
+
q = i
|
|
772
|
+
else:
|
|
773
|
+
accum += self.pi._values[i]
|
|
774
|
+
else:
|
|
775
|
+
q = starting_state
|
|
776
|
+
if q < 0 or q >= self.N:
|
|
777
|
+
raise ValueError("starting state must be between 0 and %s" % (self.N-1))
|
|
778
|
+
|
|
779
|
+
states._values[0] = q
|
|
780
|
+
# Generate a symbol from state q
|
|
781
|
+
obs._values[0] = self._gen_symbol(q, rstate.c_rand_double())
|
|
782
|
+
|
|
783
|
+
cdef double* row
|
|
784
|
+
cdef int O
|
|
785
|
+
sig_on()
|
|
786
|
+
for i in range(1, length):
|
|
787
|
+
# Choose next state
|
|
788
|
+
accum = 0
|
|
789
|
+
row = self.A._values + q*self.N
|
|
790
|
+
r = rstate.c_rand_double()
|
|
791
|
+
for j in range(self.N):
|
|
792
|
+
if r < row[j] + accum:
|
|
793
|
+
q = j
|
|
794
|
+
break
|
|
795
|
+
else:
|
|
796
|
+
accum += row[j]
|
|
797
|
+
states._values[i] = q
|
|
798
|
+
# Generate symbol from this new state q
|
|
799
|
+
obs._values[i] = self._gen_symbol(q, rstate.c_rand_double())
|
|
800
|
+
sig_off()
|
|
801
|
+
|
|
802
|
+
if self._emission_symbols is None:
|
|
803
|
+
# No emission symbol mapping
|
|
804
|
+
return obs, states
|
|
805
|
+
else:
|
|
806
|
+
# Emission symbol mapping, so change our intlist into a list of symbols
|
|
807
|
+
return self._IntList_to_emission_symbols(obs), states
|
|
808
|
+
|
|
809
|
+
cdef int _gen_symbol(self, int q, double r) noexcept:
|
|
810
|
+
r"""
|
|
811
|
+
Generate a symbol in state q using the randomly chosen
|
|
812
|
+
floating point number r, which should be between 0 and 1.
|
|
813
|
+
|
|
814
|
+
INPUT:
|
|
815
|
+
|
|
816
|
+
- ``q`` -- nonnegative integer, which specifies a state
|
|
817
|
+
- ``r`` -- a real number between 0 and 1
|
|
818
|
+
|
|
819
|
+
OUTPUT: a nonnegative int
|
|
820
|
+
|
|
821
|
+
EXAMPLES::
|
|
822
|
+
|
|
823
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.9,0.1]], [.2,.8])
|
|
824
|
+
sage: set_random_seed(0)
|
|
825
|
+
sage: m.generate_sequence(10) # indirect test
|
|
826
|
+
([0, 1, 0, 0, 0, 0, 1, 0, 1, 1], [1, 0, 1, 1, 1, 1, 0, 0, 0, 0])
|
|
827
|
+
"""
|
|
828
|
+
cdef Py_ssize_t j
|
|
829
|
+
cdef double a, accum = 0
|
|
830
|
+
# See the comments above about switching to GSL for this; also note
|
|
831
|
+
# that this should get factored out into a call to something
|
|
832
|
+
# defined in distributions.pyx.
|
|
833
|
+
for j in range(self.n_out):
|
|
834
|
+
a = self.B._values[q*self.n_out + j]
|
|
835
|
+
if r < a + accum:
|
|
836
|
+
return j
|
|
837
|
+
else:
|
|
838
|
+
accum += a
|
|
839
|
+
# None of the values was selected: shouldn't this only happen if the
|
|
840
|
+
# distribution is invalid? Anyway, this will get factored out.
|
|
841
|
+
return self.n_out - 1
|
|
842
|
+
|
|
843
|
+
def viterbi(self, obs, log_scale=True):
|
|
844
|
+
r"""
|
|
845
|
+
Determine "the" hidden sequence of states that is most likely
|
|
846
|
+
to produce the given sequence seq of observations, along with
|
|
847
|
+
the probability that this hidden sequence actually produced
|
|
848
|
+
the observation.
|
|
849
|
+
|
|
850
|
+
INPUT:
|
|
851
|
+
|
|
852
|
+
- ``seq`` -- sequence of emitted ints or symbols
|
|
853
|
+
|
|
854
|
+
- ``log_scale`` -- boolean (default: ``True``); whether to scale the
|
|
855
|
+
sequence in order to avoid numerical overflow
|
|
856
|
+
|
|
857
|
+
OUTPUT:
|
|
858
|
+
|
|
859
|
+
- ``list`` -- "the" most probable sequence of hidden states, i.e.,
|
|
860
|
+
the Viterbi path
|
|
861
|
+
|
|
862
|
+
- ``float`` -- log of probability that the observed sequence
|
|
863
|
+
was produced by the Viterbi sequence of states
|
|
864
|
+
|
|
865
|
+
EXAMPLES::
|
|
866
|
+
|
|
867
|
+
sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]],
|
|
868
|
+
....: [[0.9,0.1],[0.1,0.9]],
|
|
869
|
+
....: [0.5,0.5])
|
|
870
|
+
sage: a.viterbi([1,0,0,1,0,0,1,1])
|
|
871
|
+
([1, 0, 0, 1, ..., 0, 1, 1], -11.06245322477221...)
|
|
872
|
+
|
|
873
|
+
We predict the state sequence when the emissions are 3/4 and 'abc'.::
|
|
874
|
+
|
|
875
|
+
sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]],
|
|
876
|
+
....: [[0.9,0.1],[0.1,0.9]],
|
|
877
|
+
....: [0.5,0.5], [3/4, 'abc'])
|
|
878
|
+
|
|
879
|
+
Note that state 0 is common below, despite the model trying hard to
|
|
880
|
+
switch to state 1::
|
|
881
|
+
|
|
882
|
+
sage: a.viterbi([3/4, 'abc', 'abc'] + [3/4]*10)
|
|
883
|
+
([0, 1, 1, 0, 0 ... 0, 0, 0, 0, 0], -25.299405845367794)
|
|
884
|
+
"""
|
|
885
|
+
if self._emission_symbols is not None:
|
|
886
|
+
obs = self._emission_symbols_to_IntList(obs)
|
|
887
|
+
elif not isinstance(obs, IntList):
|
|
888
|
+
obs = IntList(obs)
|
|
889
|
+
if log_scale:
|
|
890
|
+
return self._viterbi_scale(obs)
|
|
891
|
+
else:
|
|
892
|
+
return self._viterbi(obs)
|
|
893
|
+
|
|
894
|
+
cpdef _viterbi(self, IntList obs):
|
|
895
|
+
r"""
|
|
896
|
+
Used internally to compute the viterbi path, without
|
|
897
|
+
rescaling. This can be useful for short sequences.
|
|
898
|
+
|
|
899
|
+
INPUT:
|
|
900
|
+
|
|
901
|
+
- ``obs`` -- IntList
|
|
902
|
+
|
|
903
|
+
OUTPUT:
|
|
904
|
+
|
|
905
|
+
- IntList (most likely state sequence)
|
|
906
|
+
|
|
907
|
+
- log of probability that the observed sequence was
|
|
908
|
+
produced by the Viterbi sequence of states.
|
|
909
|
+
|
|
910
|
+
EXAMPLES::
|
|
911
|
+
|
|
912
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.9,0.1]], [[1,0],[0,1]], [.2,.8])
|
|
913
|
+
sage: m._viterbi(stats.IntList([1]*5))
|
|
914
|
+
([1, 1, 1, 1, 1], -9.433483923290392)
|
|
915
|
+
sage: m._viterbi(stats.IntList([0]*5))
|
|
916
|
+
([0, 0, 0, 0, 0], -10.819778284410283)
|
|
917
|
+
|
|
918
|
+
Long sequences will overflow::
|
|
919
|
+
|
|
920
|
+
sage: m._viterbi(stats.IntList([0]*1000))
|
|
921
|
+
([0, 0, 0, 0, 0 ... 0, 0, 0, 0, 0], -inf)
|
|
922
|
+
"""
|
|
923
|
+
cdef Py_ssize_t t, T = obs._length
|
|
924
|
+
cdef IntList state_sequence = IntList(T)
|
|
925
|
+
if T == 0:
|
|
926
|
+
return state_sequence, 0.0
|
|
927
|
+
|
|
928
|
+
cdef int i, j, N = self.N
|
|
929
|
+
|
|
930
|
+
# delta[i] is the maximum of the probabilities over all
|
|
931
|
+
# paths ending in state i.
|
|
932
|
+
cdef TimeSeries delta = TimeSeries(N), delta_prev = TimeSeries(N)
|
|
933
|
+
|
|
934
|
+
# We view psi as an N x T matrix of ints. The quantity
|
|
935
|
+
# psi[N*t + j]
|
|
936
|
+
# is a most probable hidden state at time t-1, given
|
|
937
|
+
# that j is a most probable state at time j.
|
|
938
|
+
cdef IntList psi = IntList(N * T) # initialized to 0 by default
|
|
939
|
+
|
|
940
|
+
# Initialization:
|
|
941
|
+
for i in range(N):
|
|
942
|
+
delta._values[i] = self.pi._values[i] * self.B._values[self.n_out*i + obs._values[0]]
|
|
943
|
+
|
|
944
|
+
# Recursion:
|
|
945
|
+
cdef double mx, tmp
|
|
946
|
+
cdef int index
|
|
947
|
+
for t in range(1, T):
|
|
948
|
+
delta_prev, delta = delta, delta_prev
|
|
949
|
+
for j in range(N):
|
|
950
|
+
# delta_t[j] = max_i(delta_{t-1}(i) a_{i,j}) * b_j(obs[t])
|
|
951
|
+
mx = -1
|
|
952
|
+
index = -1
|
|
953
|
+
for i in range(N):
|
|
954
|
+
tmp = delta_prev._values[i]*self.A._values[i*N+j]
|
|
955
|
+
if tmp > mx:
|
|
956
|
+
mx = tmp
|
|
957
|
+
index = i
|
|
958
|
+
delta._values[j] = mx * self.B._values[self.n_out*j + obs._values[t]]
|
|
959
|
+
psi._values[N*t + j] = index
|
|
960
|
+
|
|
961
|
+
# Termination:
|
|
962
|
+
mx, index = delta.max(index=True)
|
|
963
|
+
|
|
964
|
+
# Path (state sequence) backtracking:
|
|
965
|
+
state_sequence._values[T-1] = index
|
|
966
|
+
t = T-2
|
|
967
|
+
while t >= 0:
|
|
968
|
+
state_sequence._values[t] = psi._values[N*(t+1) + state_sequence._values[t+1]]
|
|
969
|
+
t -= 1
|
|
970
|
+
|
|
971
|
+
return state_sequence, log(mx)
|
|
972
|
+
|
|
973
|
+
cpdef _viterbi_scale(self, IntList obs):
|
|
974
|
+
r"""
|
|
975
|
+
Used internally to compute the viterbi path with rescaling.
|
|
976
|
+
|
|
977
|
+
INPUT:
|
|
978
|
+
|
|
979
|
+
- ``obs`` -- IntList
|
|
980
|
+
|
|
981
|
+
OUTPUT:
|
|
982
|
+
|
|
983
|
+
- IntList (most likely state sequence)
|
|
984
|
+
|
|
985
|
+
- log of probability that the observed sequence was
|
|
986
|
+
produced by the Viterbi sequence of states.
|
|
987
|
+
|
|
988
|
+
EXAMPLES::
|
|
989
|
+
|
|
990
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.9,0.1]], [[.5,.5],[0,1]], [.2,.8])
|
|
991
|
+
sage: m._viterbi_scale(stats.IntList([1]*10))
|
|
992
|
+
([1, 0, 1, 0, 1, 0, 1, 0, 1, 0], -4.637124095034373)
|
|
993
|
+
|
|
994
|
+
Long sequences should not overflow::
|
|
995
|
+
|
|
996
|
+
sage: m._viterbi_scale(stats.IntList([1]*1000))
|
|
997
|
+
([1, 0, 1, 0, 1 ... 0, 1, 0, 1, 0], -452.05188897345...)
|
|
998
|
+
"""
|
|
999
|
+
# The algorithm is the same as _viterbi above, except
|
|
1000
|
+
# we take the logarithms of everything first, and add
|
|
1001
|
+
# instead of multiply.
|
|
1002
|
+
cdef Py_ssize_t t, T = obs._length
|
|
1003
|
+
cdef IntList state_sequence = IntList(T)
|
|
1004
|
+
if T == 0:
|
|
1005
|
+
return state_sequence, 0.0
|
|
1006
|
+
cdef int i, j, N = self.N
|
|
1007
|
+
|
|
1008
|
+
# delta[i] is the maximum of the probabilities over all
|
|
1009
|
+
# paths ending in state i.
|
|
1010
|
+
cdef TimeSeries delta = TimeSeries(N), delta_prev = TimeSeries(N)
|
|
1011
|
+
|
|
1012
|
+
# We view psi as an N x T matrix of ints. The quantity
|
|
1013
|
+
# psi[N*t + j]
|
|
1014
|
+
# is a most probable hidden state at time t-1, given
|
|
1015
|
+
# that j is a most probable state at time j.
|
|
1016
|
+
cdef IntList psi = IntList(N * T) # initialized to 0 by default
|
|
1017
|
+
|
|
1018
|
+
# Log Preprocessing
|
|
1019
|
+
cdef TimeSeries A = self.A.log()
|
|
1020
|
+
cdef TimeSeries B = self.B.log()
|
|
1021
|
+
cdef TimeSeries pi = self.pi.log()
|
|
1022
|
+
|
|
1023
|
+
# Initialization:
|
|
1024
|
+
for i in range(N):
|
|
1025
|
+
delta._values[i] = pi._values[i] + B._values[self.n_out*i + obs._values[0]]
|
|
1026
|
+
|
|
1027
|
+
# Recursion:
|
|
1028
|
+
cdef double mx, tmp, minus_inf = float('-inf')
|
|
1029
|
+
cdef int index
|
|
1030
|
+
|
|
1031
|
+
for t in range(1, T):
|
|
1032
|
+
delta_prev, delta = delta, delta_prev
|
|
1033
|
+
for j in range(N):
|
|
1034
|
+
# delta_t[j] = max_i(delta_{t-1}(i) a_{i,j}) * b_j(obs[t])
|
|
1035
|
+
mx = minus_inf
|
|
1036
|
+
index = -1
|
|
1037
|
+
for i in range(N):
|
|
1038
|
+
tmp = delta_prev._values[i] + A._values[i*N+j]
|
|
1039
|
+
if tmp > mx:
|
|
1040
|
+
mx = tmp
|
|
1041
|
+
index = i
|
|
1042
|
+
delta._values[j] = mx + B._values[self.n_out*j + obs._values[t]]
|
|
1043
|
+
psi._values[N*t + j] = index
|
|
1044
|
+
|
|
1045
|
+
# Termination:
|
|
1046
|
+
mx, index = delta.max(index=True)
|
|
1047
|
+
|
|
1048
|
+
# Path (state sequence) backtracking:
|
|
1049
|
+
state_sequence._values[T-1] = index
|
|
1050
|
+
t = T-2
|
|
1051
|
+
while t >= 0:
|
|
1052
|
+
state_sequence._values[t] = psi._values[N*(t+1) + state_sequence._values[t+1]]
|
|
1053
|
+
t -= 1
|
|
1054
|
+
|
|
1055
|
+
return state_sequence, mx
|
|
1056
|
+
|
|
1057
|
+
cdef TimeSeries _backward_scale_all(self, IntList obs, TimeSeries scale):
|
|
1058
|
+
r"""
|
|
1059
|
+
Return the scaled matrix of values `\beta_t(i)` that appear in
|
|
1060
|
+
the backtracking algorithm. This function is used internally
|
|
1061
|
+
by the Baum-Welch algorithm.
|
|
1062
|
+
|
|
1063
|
+
The matrix is stored as a TimeSeries T, such that
|
|
1064
|
+
`\beta_t(i) = T[t*N + i]` where N is the number of states of
|
|
1065
|
+
the Hidden Markov Model.
|
|
1066
|
+
|
|
1067
|
+
The quantity beta_t(i) is the probability of observing the
|
|
1068
|
+
sequence obs[t+1:] assuming that the model is in state i at
|
|
1069
|
+
time t.
|
|
1070
|
+
|
|
1071
|
+
INPUT:
|
|
1072
|
+
|
|
1073
|
+
- ``obs`` -- IntList
|
|
1074
|
+
- ``scale`` -- series that is *changed* in place, so that
|
|
1075
|
+
after calling this function, scale[t] is value that is
|
|
1076
|
+
used to scale each of the `\beta_t(i)`.
|
|
1077
|
+
|
|
1078
|
+
OUTPUT:
|
|
1079
|
+
|
|
1080
|
+
- a TimeSeries of values beta_t(i).
|
|
1081
|
+
- the input object scale is modified
|
|
1082
|
+
"""
|
|
1083
|
+
cdef Py_ssize_t t, T = obs._length
|
|
1084
|
+
cdef int N = self.N, i, j
|
|
1085
|
+
cdef double s
|
|
1086
|
+
cdef TimeSeries beta = TimeSeries(N*T, initialize=False)
|
|
1087
|
+
|
|
1088
|
+
# 1. Initialization
|
|
1089
|
+
for i in range(N):
|
|
1090
|
+
beta._values[(T-1)*N + i] = 1/scale._values[T-1]
|
|
1091
|
+
|
|
1092
|
+
# 2. Induction
|
|
1093
|
+
t = T-2
|
|
1094
|
+
while t >= 0:
|
|
1095
|
+
for i in range(N):
|
|
1096
|
+
s = 0
|
|
1097
|
+
for j in range(N):
|
|
1098
|
+
s += self.A._values[i*N+j] * \
|
|
1099
|
+
self.B._values[j*self.n_out+obs._values[t+1]] * beta._values[(t+1)*N+j]
|
|
1100
|
+
beta._values[t*N + i] = s/scale._values[t]
|
|
1101
|
+
t -= 1
|
|
1102
|
+
return beta
|
|
1103
|
+
|
|
1104
|
+
cdef _forward_scale_all(self, IntList obs):
|
|
1105
|
+
r"""
|
|
1106
|
+
Return scaled values alpha_t(i), the sequence of scalings, and
|
|
1107
|
+
the log probability.
|
|
1108
|
+
|
|
1109
|
+
INPUT:
|
|
1110
|
+
|
|
1111
|
+
- ``obs`` -- IntList
|
|
1112
|
+
|
|
1113
|
+
OUTPUT:
|
|
1114
|
+
|
|
1115
|
+
- TimeSeries alpha with alpha_t(i) = alpha[t*N + i]
|
|
1116
|
+
- TimeSeries scale with scale[t] the scaling at step t
|
|
1117
|
+
- ``float`` -- log_probability of the observation sequence
|
|
1118
|
+
being produced by the model
|
|
1119
|
+
"""
|
|
1120
|
+
cdef Py_ssize_t i, j, t, T = len(obs)
|
|
1121
|
+
cdef int N = self.N
|
|
1122
|
+
|
|
1123
|
+
# The running some of the log probabilities
|
|
1124
|
+
cdef double log_probability = 0, sum, a
|
|
1125
|
+
|
|
1126
|
+
cdef TimeSeries alpha = TimeSeries(N*T, initialize=False)
|
|
1127
|
+
cdef TimeSeries scale = TimeSeries(T, initialize=False)
|
|
1128
|
+
|
|
1129
|
+
# Initialization
|
|
1130
|
+
sum = 0
|
|
1131
|
+
for i in range(self.N):
|
|
1132
|
+
a = self.pi._values[i] * self.B._values[i*self.n_out + obs._values[0]]
|
|
1133
|
+
alpha._values[0*N + i] = a
|
|
1134
|
+
sum += a
|
|
1135
|
+
|
|
1136
|
+
scale._values[0] = sum
|
|
1137
|
+
log_probability = log(sum)
|
|
1138
|
+
for i in range(self.N):
|
|
1139
|
+
alpha._values[0*N + i] /= sum
|
|
1140
|
+
|
|
1141
|
+
# Induction
|
|
1142
|
+
# The code below is just an optimized version of:
|
|
1143
|
+
# alpha = (alpha * A).pairwise_product(B[O[t+1]])
|
|
1144
|
+
# alpha = alpha.scale(1/alpha.sum())
|
|
1145
|
+
# along with keeping track of the log of the scaling factor.
|
|
1146
|
+
cdef double s
|
|
1147
|
+
for t in range(1,T):
|
|
1148
|
+
sum = 0
|
|
1149
|
+
for j in range(N):
|
|
1150
|
+
s = 0
|
|
1151
|
+
for i in range(N):
|
|
1152
|
+
s += alpha._values[(t-1)*N + i] * self.A._values[i*N + j]
|
|
1153
|
+
a = s * self.B._values[j*self.n_out + obs._values[t]]
|
|
1154
|
+
alpha._values[t*N + j] = a
|
|
1155
|
+
sum += a
|
|
1156
|
+
|
|
1157
|
+
log_probability += log(sum)
|
|
1158
|
+
scale._values[t] = sum
|
|
1159
|
+
for j in range(self.N):
|
|
1160
|
+
alpha._values[t*N + j] /= sum
|
|
1161
|
+
|
|
1162
|
+
# Termination
|
|
1163
|
+
return alpha, scale, log_probability
|
|
1164
|
+
|
|
1165
|
+
cdef TimeSeries _baum_welch_xi(self, TimeSeries alpha, TimeSeries beta, IntList obs):
|
|
1166
|
+
r"""
|
|
1167
|
+
Used internally to compute the scaled quantity xi_t(i,j)
|
|
1168
|
+
appearing in the Baum-Welch reestimation algorithm.
|
|
1169
|
+
|
|
1170
|
+
INPUT:
|
|
1171
|
+
|
|
1172
|
+
- ``alpha`` -- TimeSeries as output by the scaled forward algorithm
|
|
1173
|
+
- ``beta`` -- TimeSeries as output by the scaled backward algorithm
|
|
1174
|
+
- ``obs `` -- IntList of observations
|
|
1175
|
+
|
|
1176
|
+
OUTPUT:
|
|
1177
|
+
|
|
1178
|
+
- TimeSeries xi such that xi[t*N*N + i*N + j] = xi_t(i,j).
|
|
1179
|
+
"""
|
|
1180
|
+
cdef int i, j, N = self.N
|
|
1181
|
+
cdef double sum
|
|
1182
|
+
cdef Py_ssize_t t, T = alpha._length//N
|
|
1183
|
+
cdef TimeSeries xi = TimeSeries(T*N*N, initialize=False)
|
|
1184
|
+
sig_on()
|
|
1185
|
+
for t in range(T-1):
|
|
1186
|
+
sum = 0.0
|
|
1187
|
+
for i in range(N):
|
|
1188
|
+
for j in range(N):
|
|
1189
|
+
xi._values[t*N*N + i*N + j] = alpha._values[t*N + i]*beta._values[(t+1)*N + j]*\
|
|
1190
|
+
self.A._values[i*N + j] * self.B._values[j*self.n_out + obs._values[t+1]]
|
|
1191
|
+
sum += xi._values[t*N*N + i*N + j]
|
|
1192
|
+
for i in range(N):
|
|
1193
|
+
for j in range(N):
|
|
1194
|
+
xi._values[t*N*N + i*N + j] /= sum
|
|
1195
|
+
sig_off()
|
|
1196
|
+
return xi
|
|
1197
|
+
|
|
1198
|
+
def baum_welch(self, obs, int max_iter=100, double log_likelihood_cutoff=1e-4, bint fix_emissions=False):
|
|
1199
|
+
r"""
|
|
1200
|
+
Given an observation sequence obs, improve this HMM using the
|
|
1201
|
+
Baum-Welch algorithm to increase the probability of observing obs.
|
|
1202
|
+
|
|
1203
|
+
INPUT:
|
|
1204
|
+
|
|
1205
|
+
- ``obs`` -- list of emissions
|
|
1206
|
+
|
|
1207
|
+
- ``max_iter`` -- integer (default: 100); maximum number
|
|
1208
|
+
of Baum-Welch steps to take
|
|
1209
|
+
|
|
1210
|
+
- ``log_likelihood_cutoff`` -- positive float (default: 1e-4);
|
|
1211
|
+
the minimal improvement in likelihood with respect to
|
|
1212
|
+
the last iteration required to continue. Relative value
|
|
1213
|
+
to log likelihood.
|
|
1214
|
+
|
|
1215
|
+
- ``fix_emissions`` -- boolean (default: ``False``); if ``True``, do
|
|
1216
|
+
not change emissions when updating
|
|
1217
|
+
|
|
1218
|
+
OUTPUT:
|
|
1219
|
+
|
|
1220
|
+
changes the model in place, and returns the log
|
|
1221
|
+
likelihood and number of iterations.
|
|
1222
|
+
|
|
1223
|
+
EXAMPLES::
|
|
1224
|
+
|
|
1225
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.9,0.1]],
|
|
1226
|
+
....: [[.5,.5],[0,1]],
|
|
1227
|
+
....: [.2,.8])
|
|
1228
|
+
sage: m.baum_welch([1,0]*20, log_likelihood_cutoff=0)
|
|
1229
|
+
(0.0, 4)
|
|
1230
|
+
sage: m # rel tol 1e-14
|
|
1231
|
+
Discrete Hidden Markov Model with 2 States and 2 Emissions
|
|
1232
|
+
Transition matrix:
|
|
1233
|
+
[1.3515269707707603e-51 1.0]
|
|
1234
|
+
[ 1.0 0.0]
|
|
1235
|
+
Emission matrix:
|
|
1236
|
+
[ 1.0 6.462537138850569e-52]
|
|
1237
|
+
[ 0.0 1.0]
|
|
1238
|
+
Initial probabilities: [0.0000, 1.0000]
|
|
1239
|
+
|
|
1240
|
+
The following illustrates how Baum-Welch is only a local
|
|
1241
|
+
optimizer, i.e., the above model is far more likely to produce
|
|
1242
|
+
the sequence [1,0]*20 than the one we get below::
|
|
1243
|
+
|
|
1244
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.5,0.5],[0.5,0.5]],
|
|
1245
|
+
....: [[.5,.5],[.5,.5]],
|
|
1246
|
+
....: [.5,.5])
|
|
1247
|
+
sage: m.baum_welch([1,0]*20, log_likelihood_cutoff=0)
|
|
1248
|
+
(-27.725887222397784, 1)
|
|
1249
|
+
sage: m
|
|
1250
|
+
Discrete Hidden Markov Model with 2 States and 2 Emissions
|
|
1251
|
+
Transition matrix:
|
|
1252
|
+
[0.5 0.5]
|
|
1253
|
+
[0.5 0.5]
|
|
1254
|
+
Emission matrix:
|
|
1255
|
+
[0.5 0.5]
|
|
1256
|
+
[0.5 0.5]
|
|
1257
|
+
Initial probabilities: [0.5000, 0.5000]
|
|
1258
|
+
|
|
1259
|
+
We illustrate fixing emissions::
|
|
1260
|
+
|
|
1261
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.9,0.1]],
|
|
1262
|
+
....: [[.5,.5],[.2,.8]],
|
|
1263
|
+
....: [.2,.8])
|
|
1264
|
+
sage: set_random_seed(0); v = m.sample(100)
|
|
1265
|
+
sage: m.baum_welch(v,fix_emissions=True)
|
|
1266
|
+
(-66.98630856918774, 100)
|
|
1267
|
+
sage: m.emission_matrix()
|
|
1268
|
+
[0.5 0.5]
|
|
1269
|
+
[0.2 0.8]
|
|
1270
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.9,0.1]],
|
|
1271
|
+
....: [[.5,.5],[.2,.8]],
|
|
1272
|
+
....: [.2,.8])
|
|
1273
|
+
sage: m.baum_welch(v)
|
|
1274
|
+
(-66.782360659293..., 100)
|
|
1275
|
+
sage: m.emission_matrix() # rel tol 1e-14
|
|
1276
|
+
[ 0.5303085748626447 0.46969142513735535]
|
|
1277
|
+
[ 0.2909775550173978 0.7090224449826023]
|
|
1278
|
+
"""
|
|
1279
|
+
if self._emission_symbols is not None:
|
|
1280
|
+
obs = self._emission_symbols_to_IntList(obs)
|
|
1281
|
+
elif not isinstance(obs, IntList):
|
|
1282
|
+
obs = IntList(obs)
|
|
1283
|
+
cdef IntList _obs = obs
|
|
1284
|
+
cdef TimeSeries alpha, beta, scale, gamma, xi
|
|
1285
|
+
cdef double log_probability, log_probability_prev, delta
|
|
1286
|
+
cdef int i, j, k, N, n_iterations
|
|
1287
|
+
cdef Py_ssize_t t, T
|
|
1288
|
+
cdef double denominator_A, numerator_A, denominator_B, numerator_B
|
|
1289
|
+
|
|
1290
|
+
# Initialization
|
|
1291
|
+
alpha, scale, log_probability = self._forward_scale_all(_obs)
|
|
1292
|
+
beta = self._backward_scale_all(_obs, scale)
|
|
1293
|
+
gamma = self._baum_welch_gamma(alpha, beta)
|
|
1294
|
+
xi = self._baum_welch_xi(alpha, beta, _obs)
|
|
1295
|
+
log_probability_prev = log_probability
|
|
1296
|
+
N = self.N
|
|
1297
|
+
n_iterations = 0
|
|
1298
|
+
T = len(_obs)
|
|
1299
|
+
|
|
1300
|
+
# Re-estimation
|
|
1301
|
+
while True:
|
|
1302
|
+
|
|
1303
|
+
# Reestimate frequency of state i in time t=0
|
|
1304
|
+
for i in range(N):
|
|
1305
|
+
self.pi._values[i] = gamma._values[0*N+i]
|
|
1306
|
+
|
|
1307
|
+
# Reestimate transition matrix and emissions probability in
|
|
1308
|
+
# each state.
|
|
1309
|
+
for i in range(N):
|
|
1310
|
+
denominator_A = 0.0
|
|
1311
|
+
for t in range(T-1):
|
|
1312
|
+
denominator_A += gamma._values[t*N+i]
|
|
1313
|
+
for j in range(N):
|
|
1314
|
+
numerator_A = 0.0
|
|
1315
|
+
for t in range(T-1):
|
|
1316
|
+
numerator_A += xi._values[t*N*N+i*N+j]
|
|
1317
|
+
self.A._values[i*N+j] = numerator_A / denominator_A
|
|
1318
|
+
|
|
1319
|
+
if not fix_emissions:
|
|
1320
|
+
denominator_B = denominator_A + gamma._values[(T-1)*N + i]
|
|
1321
|
+
for k in range(self.n_out):
|
|
1322
|
+
numerator_B = 0.0
|
|
1323
|
+
for t in range(T):
|
|
1324
|
+
if _obs._values[t] == k:
|
|
1325
|
+
numerator_B += gamma._values[t*N + i]
|
|
1326
|
+
self.B._values[i*self.n_out + k] = numerator_B / denominator_B
|
|
1327
|
+
|
|
1328
|
+
# Initialization
|
|
1329
|
+
alpha, scale, log_probability = self._forward_scale_all(_obs)
|
|
1330
|
+
beta = self._backward_scale_all(_obs, scale)
|
|
1331
|
+
gamma = self._baum_welch_gamma(alpha, beta)
|
|
1332
|
+
xi = self._baum_welch_xi(alpha, beta, _obs)
|
|
1333
|
+
|
|
1334
|
+
# Compute the difference between the log probability of
|
|
1335
|
+
# two iterations.
|
|
1336
|
+
delta = log_probability - log_probability_prev
|
|
1337
|
+
log_probability_prev = log_probability
|
|
1338
|
+
n_iterations += 1
|
|
1339
|
+
|
|
1340
|
+
# If the log probability does not change by more than
|
|
1341
|
+
# delta, then terminate
|
|
1342
|
+
if delta <= log_likelihood_cutoff or n_iterations >= max_iter:
|
|
1343
|
+
break
|
|
1344
|
+
|
|
1345
|
+
return log_probability, n_iterations
|
|
1346
|
+
|
|
1347
|
+
|
|
1348
|
+
# Keep this -- it's for backwards compatibility with the GHMM based implementation
|
|
1349
|
+
def unpickle_discrete_hmm_v0(A, B, pi, emission_symbols, name):
|
|
1350
|
+
r"""
|
|
1351
|
+
TESTS::
|
|
1352
|
+
|
|
1353
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.0,1.0],[0.5,0.5]], [1,0])
|
|
1354
|
+
sage: sage.stats.hmm.hmm.unpickle_discrete_hmm_v0(m.transition_matrix(), m.emission_matrix(), m.initial_probabilities(), ['a','b'], 'test model')
|
|
1355
|
+
Discrete Hidden Markov Model with 2 States and 2 Emissions...
|
|
1356
|
+
"""
|
|
1357
|
+
return DiscreteHiddenMarkovModel(A, B, pi, emission_symbols, normalize=False)
|
|
1358
|
+
|
|
1359
|
+
|
|
1360
|
+
def unpickle_discrete_hmm_v1(A, B, pi, n_out, emission_symbols, emission_symbols_dict):
|
|
1361
|
+
r"""
|
|
1362
|
+
Return a :class:`DiscreteHiddenMarkovModel`, restored from the arguments.
|
|
1363
|
+
|
|
1364
|
+
This function is used internally for unpickling.
|
|
1365
|
+
|
|
1366
|
+
TESTS::
|
|
1367
|
+
|
|
1368
|
+
sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.0,1.0],[0.5,0.5]], [1,0],['a','b'])
|
|
1369
|
+
sage: m2 = loads(dumps(m)) # indirect doctest
|
|
1370
|
+
sage: m2 == m
|
|
1371
|
+
True
|
|
1372
|
+
|
|
1373
|
+
Test that :issue:`15711` has been resolved::
|
|
1374
|
+
|
|
1375
|
+
sage: str(m2) == str(m)
|
|
1376
|
+
True
|
|
1377
|
+
sage: m2.log_likelihood('baa'*2) == m.log_likelihood('baa'*2)
|
|
1378
|
+
True
|
|
1379
|
+
"""
|
|
1380
|
+
cdef DiscreteHiddenMarkovModel m = DiscreteHiddenMarkovModel.__new__(DiscreteHiddenMarkovModel)
|
|
1381
|
+
m.A = A
|
|
1382
|
+
m.B = B
|
|
1383
|
+
m.pi = pi
|
|
1384
|
+
m.N = len(pi)
|
|
1385
|
+
m.n_out = n_out
|
|
1386
|
+
m._emission_symbols = emission_symbols
|
|
1387
|
+
m._emission_symbols_dict = emission_symbols_dict
|
|
1388
|
+
return m
|