passagemath-modules 10.6.31rc3__cp314-cp314-musllinux_1_2_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 +807 -0
- passagemath_modules-10.6.31rc3.dist-info/WHEEL +5 -0
- passagemath_modules-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_modules.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_modules.libs/libgfortran-67378ab2.so.5.0.0 +0 -0
- passagemath_modules.libs/libgmp-28992bcb.so.10.5.0 +0 -0
- passagemath_modules.libs/libgsl-23768756.so.28.0.0 +0 -0
- passagemath_modules.libs/libmpc-7897025b.so.3.3.1 +0 -0
- passagemath_modules.libs/libmpfr-e34bb864.so.6.2.1 +0 -0
- passagemath_modules.libs/libopenblasp-r0-503f0c35.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.so +0 -0
- sage/calculus/integration.pyx +698 -0
- sage/calculus/interpolation.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/interpolation.pxd +13 -0
- sage/calculus/interpolation.pyx +387 -0
- sage/calculus/interpolators.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/interpolators.pyx +326 -0
- sage/calculus/ode.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/ode.pxd +5 -0
- sage/calculus/ode.pyx +610 -0
- sage/calculus/riemann.cpython-314-aarch64-linux-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.so +0 -0
- sage/libs/mpmath/utils.pxd +4 -0
- sage/libs/mpmath/utils.pyx +319 -0
- sage/matrix/action.cpython-314-aarch64-linux-musl.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-musl.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-musl.so +0 -0
- sage/matrix/constructor.pyx +750 -0
- sage/matrix/docs.py +430 -0
- sage/matrix/echelon_matrix.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/echelon_matrix.pyx +155 -0
- sage/matrix/matrix.pxd +2 -0
- sage/matrix/matrix0.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix0.pxd +68 -0
- sage/matrix/matrix0.pyx +6324 -0
- sage/matrix/matrix1.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix1.pxd +8 -0
- sage/matrix/matrix1.pyx +2851 -0
- sage/matrix/matrix2.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix2.pxd +25 -0
- sage/matrix/matrix2.pyx +20181 -0
- sage/matrix/matrix_cdv.cpython-314-aarch64-linux-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.so +0 -0
- sage/matroids/extension.pxd +34 -0
- sage/matroids/extension.pyx +519 -0
- sage/matroids/flats_matroid.cpython-314-aarch64-linux-musl.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-musl.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-musl.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-musl.so +0 -0
- sage/matroids/linear_matroid.pxd +180 -0
- sage/matroids/linear_matroid.pyx +6649 -0
- sage/matroids/matroid.cpython-314-aarch64-linux-musl.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-musl.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-musl.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-musl.so +0 -0
- sage/matroids/union_matroid.pxd +20 -0
- sage/matroids/union_matroid.pyx +331 -0
- sage/matroids/unpickling.cpython-314-aarch64-linux-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.so +0 -0
- sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
- sage/rings/function_field/khuri_makdisi.cpython-314-aarch64-linux-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.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-musl.so +0 -0
- sage/stats/hmm/chmm.pyx +1595 -0
- sage/stats/hmm/distributions.cpython-314-aarch64-linux-musl.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-musl.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-musl.so +0 -0
- sage/stats/hmm/util.pxd +7 -0
- sage/stats/hmm/util.pyx +165 -0
- sage/stats/intlist.cpython-314-aarch64-linux-musl.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-musl.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
|
@@ -0,0 +1,2091 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-modules
|
|
2
|
+
# sage.doctest: needs sage.libs.pari
|
|
3
|
+
r"""
|
|
4
|
+
Finitely generated modules over a PID
|
|
5
|
+
|
|
6
|
+
You can use Sage to compute with finitely generated modules (FGM's)
|
|
7
|
+
over a principal ideal domain `R` presented as a quotient `V / W`, where `V`
|
|
8
|
+
and `W` are free.
|
|
9
|
+
|
|
10
|
+
.. NOTE::
|
|
11
|
+
|
|
12
|
+
Currently this is only enabled over ``R=ZZ``, since it has not been
|
|
13
|
+
tested and debugged over more general PIDs. All algorithms make sense
|
|
14
|
+
whenever there is a Hermite form implementation. In theory the
|
|
15
|
+
obstruction to extending the implementation is only that one has to
|
|
16
|
+
decide how elements print.
|
|
17
|
+
|
|
18
|
+
We represent `M = V / W` as a pair `(V, W)` with `W` contained in
|
|
19
|
+
`V`, and we internally represent elements of `M` non-canonically as elements
|
|
20
|
+
`x` of `V`. We also fix independent generators ``g[i]`` for `M` in
|
|
21
|
+
`V`, and when we print out elements of `V` we print their coordinates
|
|
22
|
+
with respect to the ``g[i]``; over `\ZZ` this is canonical, since each
|
|
23
|
+
coefficient is reduced modulo the additive order of ``g[i]``. To obtain
|
|
24
|
+
the vector in `V` corresponding to `x` in `M`, use ``x.lift()``.
|
|
25
|
+
|
|
26
|
+
Morphisms between finitely generated `R`-modules are well supported.
|
|
27
|
+
You create a homomorphism by simply giving the images of generators of
|
|
28
|
+
`M_0` in `M_1`. Given a morphism `\phi: M_0 \to M_1`, you can compute the image of
|
|
29
|
+
`\phi`, the kernel of `\phi`, and using ``y = phi.lift(x)`` you can lift an
|
|
30
|
+
element `x` in `M_1` to an element `y` in `M_0`, if such a `y` exists.
|
|
31
|
+
|
|
32
|
+
TECHNICAL NOTE: For efficiency, we introduce a notion of optimized
|
|
33
|
+
representation for quotient modules. The optimized representation of
|
|
34
|
+
`M=V/W` is the quotient `V'/W'` where `V'` has as basis lifts of the
|
|
35
|
+
generators ``g[i]`` for `M`. We internally store a morphism from `M_0=V_0/W_0`
|
|
36
|
+
to `M_1=V_1/W_1` by giving a morphism from the optimized representation `V_0'`
|
|
37
|
+
of `M_0` to `V_1` that sends `W_0` into `W_1`.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
The following TUTORIAL illustrates several of the above points.
|
|
41
|
+
|
|
42
|
+
First we create free modules `V_0` and `W_0` and the quotient module `M_0`.
|
|
43
|
+
Notice that everything works fine even though `V_0` and `W_0` are not
|
|
44
|
+
contained inside `\ZZ^n`, which is extremely convenient. ::
|
|
45
|
+
|
|
46
|
+
sage: V0 = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ)
|
|
47
|
+
sage: W0 = V0.span([V0.0 + 2*V0.1, 9*V0.0 + 2*V0.1, 4*V0.2])
|
|
48
|
+
sage: M0 = V0/W0; M0
|
|
49
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 16)
|
|
50
|
+
|
|
51
|
+
The invariants are computed using the Smith normal form algorithm, and
|
|
52
|
+
determine the structure of this finitely generated module.
|
|
53
|
+
|
|
54
|
+
You can get the `V` and `W` used in constructing the quotient module using
|
|
55
|
+
the methods :meth:`V` and :meth:`W`::
|
|
56
|
+
|
|
57
|
+
sage: M0.V()
|
|
58
|
+
Free module of degree 3 and rank 3 over Integer Ring
|
|
59
|
+
Echelon basis matrix:
|
|
60
|
+
[1/2 0 0]
|
|
61
|
+
[ 0 2 0]
|
|
62
|
+
[ 0 0 1]
|
|
63
|
+
sage: M0.W()
|
|
64
|
+
Free module of degree 3 and rank 3 over Integer Ring
|
|
65
|
+
Echelon basis matrix:
|
|
66
|
+
[1/2 4 0]
|
|
67
|
+
[ 0 32 0]
|
|
68
|
+
[ 0 0 4]
|
|
69
|
+
|
|
70
|
+
We note that the optimized representation of `M_0`, mentioned above in
|
|
71
|
+
the technical note, has a `V` that need not be equal to `V_0`, in general. ::
|
|
72
|
+
|
|
73
|
+
sage: M0.optimized()[0].V()
|
|
74
|
+
Free module of degree 3 and rank 2 over Integer Ring
|
|
75
|
+
User basis matrix:
|
|
76
|
+
[ 0 8 1]
|
|
77
|
+
[ 0 -2 0]
|
|
78
|
+
|
|
79
|
+
Create elements of `M_0` either by coercing in elements of `V_0`, getting generators,
|
|
80
|
+
or coercing in a list or tuple or coercing in 0. Finally, one can express an
|
|
81
|
+
element as a linear combination of the Smith form generators ::
|
|
82
|
+
|
|
83
|
+
sage: M0(V0.0)
|
|
84
|
+
(0, 2)
|
|
85
|
+
sage: M0(V0.0 + W0.0) # no difference modulo W0
|
|
86
|
+
(0, 2)
|
|
87
|
+
sage: M0.linear_combination_of_smith_form_gens([3,20])
|
|
88
|
+
(3, 4)
|
|
89
|
+
sage: 3*M0.0 + 20*M0.1
|
|
90
|
+
(3, 4)
|
|
91
|
+
|
|
92
|
+
We make an element of `M_0` by taking a difference of two generators, and
|
|
93
|
+
lift it. We also illustrate making an element from a list, which
|
|
94
|
+
coerces to `V_0`, then take the equivalence class modulo `W_0`. ::
|
|
95
|
+
|
|
96
|
+
sage: x = M0.0 - M0.1; x
|
|
97
|
+
(1, 15)
|
|
98
|
+
sage: x.lift()
|
|
99
|
+
(0, 10, 1)
|
|
100
|
+
sage: M0(vector([1/2,0,0]))
|
|
101
|
+
(0, 2)
|
|
102
|
+
sage: x.additive_order()
|
|
103
|
+
16
|
|
104
|
+
|
|
105
|
+
Similarly, we construct `V_1` and `W_1`, and the quotient `M_1`,
|
|
106
|
+
in a completely different 2-dimensional ambient space. ::
|
|
107
|
+
|
|
108
|
+
sage: V1 = span([[1/2,0], [3/2,2]], ZZ); W1 = V1.span([2*V1.0, 3*V1.1])
|
|
109
|
+
sage: M1 = V1/W1; M1
|
|
110
|
+
Finitely generated module V/W over Integer Ring with invariants (6)
|
|
111
|
+
|
|
112
|
+
We create the homomorphism from `M_0` to `M_1` that sends both generators of
|
|
113
|
+
`M_0` to 3 times the generator of `M_1`. This is well-defined since 3 times
|
|
114
|
+
the generator has order 2. ::
|
|
115
|
+
|
|
116
|
+
sage: f = M0.hom([3*M1.0, 3*M1.0]); f
|
|
117
|
+
Morphism from module over Integer Ring with invariants (4, 16)
|
|
118
|
+
to module with invariants (6,) that sends the generators to [(3), (3)]
|
|
119
|
+
|
|
120
|
+
We evaluate the homomorphism on our element `x` of the domain, and on the
|
|
121
|
+
first generator of the domain. We also evaluate at an element of `V_0`,
|
|
122
|
+
which is coerced into `M_0`. ::
|
|
123
|
+
|
|
124
|
+
sage: f(x)
|
|
125
|
+
(0)
|
|
126
|
+
sage: f(M0.0)
|
|
127
|
+
(3)
|
|
128
|
+
sage: f(V0.1)
|
|
129
|
+
(3)
|
|
130
|
+
|
|
131
|
+
Here we illustrate lifting an element of the image of `f`, i.e., finding
|
|
132
|
+
an element of `M_0` that maps to a given element of `M_1`::
|
|
133
|
+
|
|
134
|
+
sage: y = f.lift(3*M1.0)
|
|
135
|
+
sage: y # random
|
|
136
|
+
(0, 13)
|
|
137
|
+
sage: f(y)
|
|
138
|
+
(3)
|
|
139
|
+
|
|
140
|
+
We compute the kernel of `f`, i.e., the submodule of elements of `M_0` that
|
|
141
|
+
map to 0. Note that the kernel is not explicitly represented as a
|
|
142
|
+
submodule, but as another quotient `V/W` where `V` is contained in `V_0`.
|
|
143
|
+
You can explicitly coerce elements of the kernel into `M_0` though. ::
|
|
144
|
+
|
|
145
|
+
sage: K = f.kernel(); K
|
|
146
|
+
Finitely generated module V/W over Integer Ring with invariants (2, 16)
|
|
147
|
+
|
|
148
|
+
sage: M0(K.0)
|
|
149
|
+
(2, 8)
|
|
150
|
+
sage: M0(K.1)
|
|
151
|
+
(1, 5)
|
|
152
|
+
sage: f(M0(K.0))
|
|
153
|
+
(0)
|
|
154
|
+
sage: f(M0(K.1))
|
|
155
|
+
(0)
|
|
156
|
+
|
|
157
|
+
We compute the image of `f`. ::
|
|
158
|
+
|
|
159
|
+
sage: f.image()
|
|
160
|
+
Finitely generated module V/W over Integer Ring with invariants (2)
|
|
161
|
+
|
|
162
|
+
Notice how the elements of the image are written as (0) and (1),
|
|
163
|
+
despite the image being naturally a submodule of `M_1`, which has
|
|
164
|
+
elements (0), (1), (2), (3), (4), (5). However, below we coerce the
|
|
165
|
+
element (1) of the image into the codomain, and get (3)::
|
|
166
|
+
|
|
167
|
+
sage: list(f.image())
|
|
168
|
+
[(0), (1)]
|
|
169
|
+
sage: list(M1)
|
|
170
|
+
[(0), (1), (2), (3), (4), (5)]
|
|
171
|
+
sage: x = f.image().0; x
|
|
172
|
+
(1)
|
|
173
|
+
sage: M1(x)
|
|
174
|
+
(3)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
TESTS::
|
|
178
|
+
|
|
179
|
+
sage: from sage.modules.fg_pid.fgp_module import FGP_Module
|
|
180
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
181
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
182
|
+
sage: Q = FGP_Module(V, W); Q
|
|
183
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
184
|
+
sage: Q.linear_combination_of_smith_form_gens([1,3])
|
|
185
|
+
(1, 3)
|
|
186
|
+
sage: Q(V([1,3,4]))
|
|
187
|
+
(0, 1)
|
|
188
|
+
sage: Q(W([1,16,0]))
|
|
189
|
+
(0, 0)
|
|
190
|
+
sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],QQ)
|
|
191
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1])
|
|
192
|
+
sage: Q = FGP_Module(V, W); Q
|
|
193
|
+
Finitely generated module V/W over Rational Field with invariants (0)
|
|
194
|
+
sage: q = Q.an_element(); q
|
|
195
|
+
(1)
|
|
196
|
+
sage: q*(1/2)
|
|
197
|
+
(1/2)
|
|
198
|
+
sage: (1/2)*q
|
|
199
|
+
(1/2)
|
|
200
|
+
|
|
201
|
+
AUTHOR:
|
|
202
|
+
|
|
203
|
+
- William Stein, 2009
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
# ****************************************************************************
|
|
207
|
+
# Copyright (C) 2009 William Stein <wstein@gmail.com>
|
|
208
|
+
#
|
|
209
|
+
# This program is free software: you can redistribute it and/or modify
|
|
210
|
+
# it under the terms of the GNU General Public License as published by
|
|
211
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
212
|
+
# (at your option) any later version.
|
|
213
|
+
# https://www.gnu.org/licenses/
|
|
214
|
+
# ****************************************************************************
|
|
215
|
+
from itertools import product
|
|
216
|
+
|
|
217
|
+
from sage.modules.module import Module
|
|
218
|
+
from sage.modules.free_module import FreeModule_generic
|
|
219
|
+
from sage.structure.all import parent
|
|
220
|
+
from sage.structure.sequence import Sequence
|
|
221
|
+
from .fgp_element import DEBUG, FGP_Element
|
|
222
|
+
from .fgp_morphism import FGP_Morphism, FGP_Homset
|
|
223
|
+
from sage.rings.integer_ring import ZZ
|
|
224
|
+
from sage.rings.integer import Integer
|
|
225
|
+
from sage.arith.functions import lcm, LCM_list
|
|
226
|
+
from sage.misc.cachefunc import cached_method
|
|
227
|
+
from sage.misc.superseded import deprecated_function_alias
|
|
228
|
+
from sage.matrix.constructor import matrix
|
|
229
|
+
|
|
230
|
+
import sage.misc.weak_dict
|
|
231
|
+
from functools import reduce
|
|
232
|
+
_fgp_module = sage.misc.weak_dict.WeakValueDictionary()
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def FGP_Module(V, W, check=True):
|
|
236
|
+
"""
|
|
237
|
+
INPUT:
|
|
238
|
+
|
|
239
|
+
- ``V`` -- a free `R`-module
|
|
240
|
+
|
|
241
|
+
- ``W`` -- a free `R`-submodule of `V`
|
|
242
|
+
|
|
243
|
+
- ``check`` -- boolean (default: ``True``); if ``True``, more checks
|
|
244
|
+
on correctness are performed. In particular, we check the data
|
|
245
|
+
types of ``V`` and ``W``, and that `W` is a submodule of `V`
|
|
246
|
+
with the same base ring.
|
|
247
|
+
|
|
248
|
+
OUTPUT: the quotient `V/W` as a finitely generated `R`-module
|
|
249
|
+
|
|
250
|
+
EXAMPLES::
|
|
251
|
+
|
|
252
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
253
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
254
|
+
sage: import sage.modules.fg_pid.fgp_module
|
|
255
|
+
sage: Q = sage.modules.fg_pid.fgp_module.FGP_Module(V, W)
|
|
256
|
+
sage: type(Q)
|
|
257
|
+
<class 'sage.modules.fg_pid.fgp_module.FGP_Module_class_with_category'>
|
|
258
|
+
sage: Q is sage.modules.fg_pid.fgp_module.FGP_Module(V, W, check=False)
|
|
259
|
+
True
|
|
260
|
+
"""
|
|
261
|
+
key = (V, V.basis_matrix(), W, W.basis_matrix())
|
|
262
|
+
try:
|
|
263
|
+
return _fgp_module[key]
|
|
264
|
+
except KeyError:
|
|
265
|
+
pass
|
|
266
|
+
M = FGP_Module_class(V, W, check=check)
|
|
267
|
+
_fgp_module[key] = M
|
|
268
|
+
return M
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def is_FGP_Module(x):
|
|
272
|
+
"""
|
|
273
|
+
Return ``True`` if x is an FGP module, i.e., a finitely generated
|
|
274
|
+
module over a PID represented as a quotient of finitely generated
|
|
275
|
+
free modules over a PID.
|
|
276
|
+
|
|
277
|
+
EXAMPLES::
|
|
278
|
+
|
|
279
|
+
sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ)
|
|
280
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]); Q = V/W
|
|
281
|
+
sage: sage.modules.fg_pid.fgp_module.is_FGP_Module(V)
|
|
282
|
+
doctest:warning...
|
|
283
|
+
DeprecationWarning: the function is_FGP_Module is deprecated;
|
|
284
|
+
use 'isinstance(..., FGP_Module_class)' instead
|
|
285
|
+
See https://github.com/sagemath/sage/issues/37924 for details.
|
|
286
|
+
False
|
|
287
|
+
sage: sage.modules.fg_pid.fgp_module.is_FGP_Module(Q)
|
|
288
|
+
True
|
|
289
|
+
"""
|
|
290
|
+
from sage.misc.superseded import deprecation
|
|
291
|
+
deprecation(37924, "the function is_FGP_Module is deprecated; use 'isinstance(..., FGP_Module_class)' instead")
|
|
292
|
+
return isinstance(x, FGP_Module_class)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
class FGP_Module_class(Module):
|
|
296
|
+
"""
|
|
297
|
+
A finitely generated module over a PID presented as a quotient `V/W`.
|
|
298
|
+
|
|
299
|
+
INPUT:
|
|
300
|
+
|
|
301
|
+
- ``V`` -- an `R`-module
|
|
302
|
+
|
|
303
|
+
- ``W`` -- an `R`-submodule of `V`
|
|
304
|
+
|
|
305
|
+
- ``check`` -- boolean (default: ``True``)
|
|
306
|
+
|
|
307
|
+
EXAMPLES::
|
|
308
|
+
|
|
309
|
+
sage: A = (ZZ^1)/span([[100]], ZZ); A
|
|
310
|
+
Finitely generated module V/W over Integer Ring with invariants (100)
|
|
311
|
+
sage: A.V()
|
|
312
|
+
Ambient free module of rank 1 over the principal ideal domain Integer Ring
|
|
313
|
+
sage: A.W()
|
|
314
|
+
Free module of degree 1 and rank 1 over Integer Ring
|
|
315
|
+
Echelon basis matrix:
|
|
316
|
+
[100]
|
|
317
|
+
|
|
318
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
319
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
320
|
+
sage: Q = V/W; Q
|
|
321
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
322
|
+
sage: type(Q)
|
|
323
|
+
<class 'sage.modules.fg_pid.fgp_module.FGP_Module_class_with_category'>
|
|
324
|
+
|
|
325
|
+
TESTS:
|
|
326
|
+
|
|
327
|
+
Make sure that the problems in :issue:`7516` are fixed::
|
|
328
|
+
|
|
329
|
+
sage: V = FreeModule(QQ, 2)
|
|
330
|
+
sage: W = V.submodule([V([1,1])])
|
|
331
|
+
sage: Z = W.submodule([])
|
|
332
|
+
sage: WmodZ = W / Z
|
|
333
|
+
sage: loads(dumps(WmodZ)) == WmodZ
|
|
334
|
+
True
|
|
335
|
+
"""
|
|
336
|
+
|
|
337
|
+
# The class to be used for creating elements of this
|
|
338
|
+
# module. Should be overridden in derived classes.
|
|
339
|
+
Element = FGP_Element
|
|
340
|
+
|
|
341
|
+
def __init__(self, V, W, check=True):
|
|
342
|
+
"""
|
|
343
|
+
INPUT:
|
|
344
|
+
|
|
345
|
+
- ``V`` -- an `R`-module
|
|
346
|
+
|
|
347
|
+
- ``W`` -- an `R`-submodule of `V`
|
|
348
|
+
|
|
349
|
+
- ``check`` -- boolean (default: ``True``); if ``True``, more checks on
|
|
350
|
+
correctness are performed. In particular, we check the data types of
|
|
351
|
+
``V`` and ``W``, and that `W` is a submodule of `V` with the same
|
|
352
|
+
base ring `R`.
|
|
353
|
+
|
|
354
|
+
EXAMPLES::
|
|
355
|
+
|
|
356
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
357
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
358
|
+
sage: Q = V/W; Q
|
|
359
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
360
|
+
sage: type(Q)
|
|
361
|
+
<class 'sage.modules.fg_pid.fgp_module.FGP_Module_class_with_category'>
|
|
362
|
+
"""
|
|
363
|
+
if check:
|
|
364
|
+
if not isinstance(V, FreeModule_generic):
|
|
365
|
+
raise TypeError("V must be a FreeModule")
|
|
366
|
+
if not isinstance(W, FreeModule_generic):
|
|
367
|
+
raise TypeError("W must be a FreeModule")
|
|
368
|
+
if not W.is_submodule(V):
|
|
369
|
+
raise ValueError("W must be a submodule of V")
|
|
370
|
+
if V.base_ring() != W.base_ring():
|
|
371
|
+
raise ValueError("W and V must have the same base ring")
|
|
372
|
+
self._W = W
|
|
373
|
+
self._V = V
|
|
374
|
+
Module.__init__(self, base=V.base_ring())
|
|
375
|
+
|
|
376
|
+
# Note: There once was a
|
|
377
|
+
# def _subquotient_class():
|
|
378
|
+
# method that returned a functionoid to construct new modules, so
|
|
379
|
+
# you would call module._subquotient_class()(V,W,check). This has
|
|
380
|
+
# been replaced with module._module_constructor(V,W,check).
|
|
381
|
+
|
|
382
|
+
def _module_constructor(self, V, W, check=True):
|
|
383
|
+
r"""
|
|
384
|
+
Construct a quotient module `V/W`.
|
|
385
|
+
|
|
386
|
+
This should be overridden in derived classes.
|
|
387
|
+
|
|
388
|
+
INPUT:
|
|
389
|
+
|
|
390
|
+
- ``V`` -- an `R`-module
|
|
391
|
+
|
|
392
|
+
- ``W`` -- an `R`-submodule of `V`
|
|
393
|
+
|
|
394
|
+
- ``check`` -- boolean (default: ``True``)
|
|
395
|
+
|
|
396
|
+
OUTPUT: the quotient `V/W`
|
|
397
|
+
|
|
398
|
+
EXAMPLES::
|
|
399
|
+
|
|
400
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
401
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
402
|
+
sage: Q = V/W; Q
|
|
403
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
404
|
+
sage: Q._module_constructor(V,W)
|
|
405
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
406
|
+
"""
|
|
407
|
+
return FGP_Module(V, W, check)
|
|
408
|
+
|
|
409
|
+
def _coerce_map_from_(self, S):
|
|
410
|
+
"""
|
|
411
|
+
Return whether ``S`` canonically coerces to ``self``.
|
|
412
|
+
|
|
413
|
+
INPUT:
|
|
414
|
+
|
|
415
|
+
- ``S`` -- anything
|
|
416
|
+
|
|
417
|
+
OUTPUT: boolean
|
|
418
|
+
|
|
419
|
+
EXAMPLES::
|
|
420
|
+
|
|
421
|
+
sage: V = span([[5, -1/2]], ZZ); W = span([[20,-2]], ZZ)
|
|
422
|
+
sage: Q = V/W; phi = Q.hom([2*Q.0])
|
|
423
|
+
sage: Q._coerce_map_from_(ZZ)
|
|
424
|
+
False
|
|
425
|
+
sage: Q._coerce_map_from_(phi.kernel())
|
|
426
|
+
True
|
|
427
|
+
sage: Q._coerce_map_from_(Q)
|
|
428
|
+
True
|
|
429
|
+
sage: Q._coerce_map_from_(phi.image())
|
|
430
|
+
True
|
|
431
|
+
sage: Q._coerce_map_from_(V/V.zero_submodule())
|
|
432
|
+
True
|
|
433
|
+
sage: Q._coerce_map_from_(V/V)
|
|
434
|
+
False
|
|
435
|
+
sage: Q._coerce_map_from_(ZZ^2)
|
|
436
|
+
False
|
|
437
|
+
|
|
438
|
+
Of course, `V` canonically coerces to `Q`, as does twice `V`::
|
|
439
|
+
|
|
440
|
+
sage: Q._coerce_map_from_(V)
|
|
441
|
+
True
|
|
442
|
+
sage: Q._coerce_map_from_(V.scale(2))
|
|
443
|
+
True
|
|
444
|
+
"""
|
|
445
|
+
if isinstance(S, FGP_Module_class):
|
|
446
|
+
return S.has_canonical_map_to(self)
|
|
447
|
+
return self._V.has_coerce_map_from(S)
|
|
448
|
+
|
|
449
|
+
def _mul_(self, other, switch_sides=False):
|
|
450
|
+
r"""
|
|
451
|
+
Return the image of this module under scalar multiplication by ``other``.
|
|
452
|
+
|
|
453
|
+
INPUT:
|
|
454
|
+
|
|
455
|
+
- ``other`` -- an element of the base ring
|
|
456
|
+
- ``switch_sides`` -- boolean (default: ``False``); left or right
|
|
457
|
+
multiplication
|
|
458
|
+
|
|
459
|
+
EXAMPLES::
|
|
460
|
+
|
|
461
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
462
|
+
sage: W = span([2*V.0, 4*V.1, 3*V.2])
|
|
463
|
+
sage: Q = V/W; Q
|
|
464
|
+
Finitely generated module V/W over Integer Ring with invariants (2, 12)
|
|
465
|
+
sage: 2*Q
|
|
466
|
+
Finitely generated module V/W over Integer Ring with invariants (6)
|
|
467
|
+
sage: Q*3
|
|
468
|
+
Finitely generated module V/W over Integer Ring with invariants (2, 4)
|
|
469
|
+
"""
|
|
470
|
+
if other in self.base_ring():
|
|
471
|
+
return self._module_constructor(other*self.V() + self.W(), self.W())
|
|
472
|
+
raise ValueError("Scalar multiplication of a module is only " +
|
|
473
|
+
"defined for an element of the base ring.")
|
|
474
|
+
|
|
475
|
+
def _repr_(self):
|
|
476
|
+
"""
|
|
477
|
+
Return string representation of this module.
|
|
478
|
+
|
|
479
|
+
EXAMPLES::
|
|
480
|
+
|
|
481
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
482
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
483
|
+
sage: (V/W)._repr_()
|
|
484
|
+
'Finitely generated module V/W over Integer Ring with invariants (4, 12)'
|
|
485
|
+
"""
|
|
486
|
+
I = str(self.invariants()).replace(',)', ')')
|
|
487
|
+
return "Finitely generated module V/W over %s with invariants %s" % (self.base_ring(), I)
|
|
488
|
+
|
|
489
|
+
def __truediv__(self, other):
|
|
490
|
+
"""
|
|
491
|
+
Return the quotient ``self`` / ``other``, where ``other`` must be a
|
|
492
|
+
submodule of ``self``.
|
|
493
|
+
|
|
494
|
+
EXAMPLES::
|
|
495
|
+
|
|
496
|
+
sage: V = span([[5, -1/2]], ZZ); W = span([[20,-2]] ,ZZ)
|
|
497
|
+
sage: Q = V/W; phi = Q.hom([2*Q.0])
|
|
498
|
+
sage: Q
|
|
499
|
+
Finitely generated module V/W over Integer Ring with invariants (4)
|
|
500
|
+
sage: Q/phi.kernel()
|
|
501
|
+
Finitely generated module V/W over Integer Ring with invariants (2)
|
|
502
|
+
sage: Q/Q
|
|
503
|
+
Finitely generated module V/W over Integer Ring with invariants ()
|
|
504
|
+
"""
|
|
505
|
+
if not isinstance(other, FGP_Module_class):
|
|
506
|
+
if isinstance(other, FreeModule_generic):
|
|
507
|
+
other = other / other.zero_submodule()
|
|
508
|
+
else:
|
|
509
|
+
raise TypeError("other must be an FGP module")
|
|
510
|
+
if not other.is_submodule(self):
|
|
511
|
+
raise ValueError("other must be a submodule of self")
|
|
512
|
+
return self._module_constructor(self._V, other._V+self._W)
|
|
513
|
+
|
|
514
|
+
def __eq__(self, other):
|
|
515
|
+
"""
|
|
516
|
+
EXAMPLES::
|
|
517
|
+
|
|
518
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
519
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
520
|
+
sage: Q = V/W
|
|
521
|
+
sage: Q == Q
|
|
522
|
+
True
|
|
523
|
+
sage: loads(dumps(Q)) == Q
|
|
524
|
+
True
|
|
525
|
+
sage: Q == V
|
|
526
|
+
False
|
|
527
|
+
sage: Q == V/V.zero_submodule()
|
|
528
|
+
False
|
|
529
|
+
"""
|
|
530
|
+
if not isinstance(other, FGP_Module_class):
|
|
531
|
+
return False
|
|
532
|
+
return self._V == other._V and self._W == other._W
|
|
533
|
+
|
|
534
|
+
def __ne__(self, other):
|
|
535
|
+
"""
|
|
536
|
+
Return ``True`` iff ``self`` is not equal to ``other``.
|
|
537
|
+
|
|
538
|
+
This may not be needed for modules created using the function
|
|
539
|
+
:func:`FGP_Module`, since those have uniqueness built into
|
|
540
|
+
them, but if the modules are created directly using the
|
|
541
|
+
``__init__`` method for this class, then this may fail; in
|
|
542
|
+
particular, for modules ``M`` and ``N`` with ``M == N`` returning
|
|
543
|
+
True, it may be the case that ``M != N`` may also return True.
|
|
544
|
+
In particular, for derived classes whose ``__init__`` methods just
|
|
545
|
+
call the ``__init__`` method for this class need this. See
|
|
546
|
+
:issue:`9940` for illustrations.
|
|
547
|
+
|
|
548
|
+
EXAMPLES:
|
|
549
|
+
|
|
550
|
+
Make sure that the problems in :issue:`9940` are fixed::
|
|
551
|
+
|
|
552
|
+
sage: G = AdditiveAbelianGroup([0,0])
|
|
553
|
+
sage: H = AdditiveAbelianGroup([0,0])
|
|
554
|
+
sage: G == H
|
|
555
|
+
True
|
|
556
|
+
sage: G != H # indirect doctest
|
|
557
|
+
False
|
|
558
|
+
|
|
559
|
+
sage: N1 = ToricLattice(3)
|
|
560
|
+
sage: sublattice1 = N1.submodule([(1,1,0), (3,2,1)])
|
|
561
|
+
sage: Q1 = N1/sublattice1
|
|
562
|
+
sage: N2 = ToricLattice(3)
|
|
563
|
+
sage: sublattice2 = N2.submodule([(1,1,0), (3,2,1)])
|
|
564
|
+
sage: Q2 = N2/sublattice2
|
|
565
|
+
sage: Q1 == Q2
|
|
566
|
+
True
|
|
567
|
+
sage: Q1 != Q2
|
|
568
|
+
False
|
|
569
|
+
"""
|
|
570
|
+
return not self == other
|
|
571
|
+
|
|
572
|
+
# __le__ is a synonym for `is_submodule`: see below
|
|
573
|
+
|
|
574
|
+
def __lt__(self, other):
|
|
575
|
+
"""
|
|
576
|
+
Return ``True`` iff ``self`` is a proper submodule of ``other``.
|
|
577
|
+
|
|
578
|
+
EXAMPLES::
|
|
579
|
+
|
|
580
|
+
sage: V = ZZ^2; W = V.span([[1,2]]); W2 = W.scale(2)
|
|
581
|
+
sage: A = V/W; B = W/W2
|
|
582
|
+
sage: B < A
|
|
583
|
+
False
|
|
584
|
+
sage: A = V/W2; B = W/W2
|
|
585
|
+
sage: B < A
|
|
586
|
+
True
|
|
587
|
+
sage: A < A
|
|
588
|
+
False
|
|
589
|
+
"""
|
|
590
|
+
return self <= other and not self == other
|
|
591
|
+
|
|
592
|
+
def __gt__(self, other):
|
|
593
|
+
"""
|
|
594
|
+
Return ``True`` iff ``other`` is a proper submodule of ``self``.
|
|
595
|
+
|
|
596
|
+
EXAMPLES::
|
|
597
|
+
|
|
598
|
+
sage: V = ZZ^2; W = V.span([[1,2]]); W2 = W.scale(2)
|
|
599
|
+
sage: A = V/W; B = W/W2
|
|
600
|
+
sage: A > B
|
|
601
|
+
False
|
|
602
|
+
sage: A = V/W2; B = W/W2
|
|
603
|
+
sage: A > B
|
|
604
|
+
True
|
|
605
|
+
sage: A > A
|
|
606
|
+
False
|
|
607
|
+
"""
|
|
608
|
+
return self >= other and not self == other
|
|
609
|
+
|
|
610
|
+
def __ge__(self, other):
|
|
611
|
+
"""
|
|
612
|
+
Return ``True`` iff ``other`` is a submodule of ``self``.
|
|
613
|
+
|
|
614
|
+
EXAMPLES::
|
|
615
|
+
|
|
616
|
+
sage: V = ZZ^2; W = V.span([[1,2]]); W2 = W.scale(2)
|
|
617
|
+
sage: A = V/W; B = W/W2
|
|
618
|
+
sage: A >= B
|
|
619
|
+
False
|
|
620
|
+
sage: A = V/W2; B = W/W2
|
|
621
|
+
sage: A >= B
|
|
622
|
+
True
|
|
623
|
+
sage: A >= A
|
|
624
|
+
True
|
|
625
|
+
"""
|
|
626
|
+
return other.is_submodule(self)
|
|
627
|
+
|
|
628
|
+
def _element_constructor_(self, x, check=True):
|
|
629
|
+
"""
|
|
630
|
+
INPUT:
|
|
631
|
+
|
|
632
|
+
- ``x`` -- a vector or an fgp module element:
|
|
633
|
+
|
|
634
|
+
- vector: coerce vector into `V` and define the
|
|
635
|
+
corresponding element of `V/W`
|
|
636
|
+
|
|
637
|
+
- fgp module element: lift to element of ambient vector
|
|
638
|
+
space and try to put into `V`. If ``x`` is in ``self`` already,
|
|
639
|
+
just return ``x``.
|
|
640
|
+
|
|
641
|
+
- ``check`` -- boolean (default: ``True``)
|
|
642
|
+
|
|
643
|
+
.. SEEALSO:: :meth:`linear_combination_of_smith_form_gens`
|
|
644
|
+
|
|
645
|
+
EXAMPLES::
|
|
646
|
+
|
|
647
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
648
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
649
|
+
sage: Q = V/W
|
|
650
|
+
sage: x = Q(V.0 - V.1); x # indirect doctest
|
|
651
|
+
(0, 9)
|
|
652
|
+
sage: type(x)
|
|
653
|
+
<class 'sage.modules.fg_pid.fgp_module.FGP_Module_class_with_category.element_class'>
|
|
654
|
+
sage: x is Q(x)
|
|
655
|
+
True
|
|
656
|
+
sage: x.parent() is Q
|
|
657
|
+
True
|
|
658
|
+
"""
|
|
659
|
+
if isinstance(x, FGP_Element):
|
|
660
|
+
x = x.lift()
|
|
661
|
+
return self.element_class(self, self._V(x))
|
|
662
|
+
|
|
663
|
+
def linear_combination_of_smith_form_gens(self, x):
|
|
664
|
+
r"""
|
|
665
|
+
Compute a linear combination of the optimised generators of this module
|
|
666
|
+
as returned by :meth:`smith_form_gens`.
|
|
667
|
+
|
|
668
|
+
EXAMPLES::
|
|
669
|
+
|
|
670
|
+
sage: X = ZZ**2 / span([[3,0], [0,2]], ZZ)
|
|
671
|
+
sage: X.linear_combination_of_smith_form_gens([1])
|
|
672
|
+
(1)
|
|
673
|
+
"""
|
|
674
|
+
try:
|
|
675
|
+
x = self.optimized()[0].V().linear_combination_of_basis(x)
|
|
676
|
+
except ValueError as msg:
|
|
677
|
+
raise TypeError(msg)
|
|
678
|
+
return self.element_class(self, self._V(x))
|
|
679
|
+
|
|
680
|
+
def __contains__(self, x):
|
|
681
|
+
"""
|
|
682
|
+
Return true if ``x`` is contained in ``self``.
|
|
683
|
+
|
|
684
|
+
EXAMPLES::
|
|
685
|
+
|
|
686
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
687
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
688
|
+
sage: Q = V/W; Q
|
|
689
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
690
|
+
sage: Q.0 in Q
|
|
691
|
+
True
|
|
692
|
+
sage: 0 in Q
|
|
693
|
+
True
|
|
694
|
+
sage: vector([1,2,3/7]) in Q
|
|
695
|
+
False
|
|
696
|
+
sage: vector([1,2,3]) in Q
|
|
697
|
+
True
|
|
698
|
+
sage: Q.0 - Q.1 in Q
|
|
699
|
+
True
|
|
700
|
+
"""
|
|
701
|
+
if parent(x) is self:
|
|
702
|
+
return True
|
|
703
|
+
try:
|
|
704
|
+
self(x)
|
|
705
|
+
return True
|
|
706
|
+
except (TypeError, ValueError):
|
|
707
|
+
return False
|
|
708
|
+
|
|
709
|
+
def submodule(self, x):
|
|
710
|
+
"""
|
|
711
|
+
Return the submodule defined by ``x``.
|
|
712
|
+
|
|
713
|
+
INPUT:
|
|
714
|
+
|
|
715
|
+
- ``x`` -- list, tuple, or FGP module
|
|
716
|
+
|
|
717
|
+
EXAMPLES::
|
|
718
|
+
|
|
719
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
720
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
721
|
+
sage: Q = V/W; Q
|
|
722
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
723
|
+
sage: Q.gens()
|
|
724
|
+
((1, 0), (0, 1))
|
|
725
|
+
|
|
726
|
+
We create submodules generated by a list or tuple of elements::
|
|
727
|
+
|
|
728
|
+
sage: Q.submodule([Q.0])
|
|
729
|
+
Finitely generated module V/W over Integer Ring with invariants (4)
|
|
730
|
+
sage: Q.submodule([Q.1])
|
|
731
|
+
Finitely generated module V/W over Integer Ring with invariants (12)
|
|
732
|
+
sage: Q.submodule((Q.0, Q.0 + 3*Q.1))
|
|
733
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 4)
|
|
734
|
+
|
|
735
|
+
A submodule defined by a submodule::
|
|
736
|
+
|
|
737
|
+
sage: A = Q.submodule((Q.0, Q.0 + 3*Q.1)); A
|
|
738
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 4)
|
|
739
|
+
sage: Q.submodule(A)
|
|
740
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 4)
|
|
741
|
+
|
|
742
|
+
Inclusion is checked::
|
|
743
|
+
|
|
744
|
+
sage: A.submodule(Q)
|
|
745
|
+
Traceback (most recent call last):
|
|
746
|
+
...
|
|
747
|
+
ValueError: x.V() must be contained in self's V.
|
|
748
|
+
"""
|
|
749
|
+
if isinstance(x, FGP_Module_class):
|
|
750
|
+
if not x._W.is_submodule(self._W):
|
|
751
|
+
raise ValueError("x.W() must be contained in self's W.")
|
|
752
|
+
|
|
753
|
+
V = x._V
|
|
754
|
+
if not V.is_submodule(self._V):
|
|
755
|
+
raise ValueError("x.V() must be contained in self's V.")
|
|
756
|
+
|
|
757
|
+
return x
|
|
758
|
+
|
|
759
|
+
if not isinstance(x, (list, tuple)):
|
|
760
|
+
raise TypeError("x must be a list, tuple, or FGP module")
|
|
761
|
+
|
|
762
|
+
x = Sequence(x)
|
|
763
|
+
if isinstance(x.universe(), FGP_Module_class):
|
|
764
|
+
# TODO: possibly inefficient in some cases
|
|
765
|
+
x = [self(v).lift() for v in x]
|
|
766
|
+
V = self._V.submodule(x) + self._W
|
|
767
|
+
return self._module_constructor(V, self._W)
|
|
768
|
+
|
|
769
|
+
def has_canonical_map_to(self, A) -> bool:
|
|
770
|
+
"""
|
|
771
|
+
Return ``True`` if ``self`` has a canonical map to ``A``, relative to the
|
|
772
|
+
given presentation of ``A``.
|
|
773
|
+
|
|
774
|
+
This means that ``A`` is a finitely
|
|
775
|
+
generated quotient module, ``self.V()`` is a submodule of ``A.V()``
|
|
776
|
+
and ``self.W()`` is a submodule of ``A.W()``, i.e., that there is a
|
|
777
|
+
natural map induced by inclusion of the V's. Note that we do
|
|
778
|
+
*not* require that this natural map be injective; for this use
|
|
779
|
+
:meth:`is_submodule`.
|
|
780
|
+
|
|
781
|
+
EXAMPLES::
|
|
782
|
+
|
|
783
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
784
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
785
|
+
sage: Q = V/W; Q
|
|
786
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
787
|
+
sage: A = Q.submodule((Q.0, Q.0 + 3*Q.1)); A
|
|
788
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 4)
|
|
789
|
+
sage: A.has_canonical_map_to(Q)
|
|
790
|
+
True
|
|
791
|
+
sage: Q.has_canonical_map_to(A)
|
|
792
|
+
False
|
|
793
|
+
"""
|
|
794
|
+
if not isinstance(A, FGP_Module_class):
|
|
795
|
+
return False
|
|
796
|
+
if self.cardinality() == 0 and self.base_ring() == A.base_ring():
|
|
797
|
+
return True
|
|
798
|
+
return self.V().is_submodule(A.V()) and self.W().is_submodule(A.W())
|
|
799
|
+
|
|
800
|
+
def is_submodule(self, A) -> bool:
|
|
801
|
+
"""
|
|
802
|
+
Return ``True`` if ``self`` is a submodule of ``A``.
|
|
803
|
+
|
|
804
|
+
More precisely, this returns ``True`` if ``self.V()`` is a
|
|
805
|
+
submodule of ``A.V()``, with ``self.W()`` equal to ``A.W()``.
|
|
806
|
+
|
|
807
|
+
Compare :meth:`has_canonical_map_to`.
|
|
808
|
+
|
|
809
|
+
EXAMPLES::
|
|
810
|
+
|
|
811
|
+
sage: V = ZZ^2; W = V.span([[1,2]]); W2 = W.scale(2)
|
|
812
|
+
sage: A = V/W; B = W/W2
|
|
813
|
+
sage: B.is_submodule(A)
|
|
814
|
+
False
|
|
815
|
+
sage: A = V/W2; B = W/W2
|
|
816
|
+
sage: B.is_submodule(A)
|
|
817
|
+
True
|
|
818
|
+
|
|
819
|
+
This example illustrates that this command works in a subtle cases.::
|
|
820
|
+
|
|
821
|
+
sage: A = ZZ^1
|
|
822
|
+
sage: Q3 = A / A.span([[3]])
|
|
823
|
+
sage: Q6 = A / A.span([[6]])
|
|
824
|
+
sage: Q6.is_submodule(Q3)
|
|
825
|
+
False
|
|
826
|
+
sage: Q6.has_canonical_map_to(Q3)
|
|
827
|
+
True
|
|
828
|
+
sage: Q = A.span([[2]]) / A.span([[6]])
|
|
829
|
+
sage: Q.is_submodule(Q6)
|
|
830
|
+
True
|
|
831
|
+
"""
|
|
832
|
+
if not self.has_canonical_map_to(A):
|
|
833
|
+
return False
|
|
834
|
+
|
|
835
|
+
return self.V().is_submodule(A.V()) and self.W() == A.W()
|
|
836
|
+
|
|
837
|
+
__le__ = is_submodule
|
|
838
|
+
|
|
839
|
+
def V(self):
|
|
840
|
+
"""
|
|
841
|
+
If this module was constructed as a quotient V/W, return V.
|
|
842
|
+
|
|
843
|
+
EXAMPLES::
|
|
844
|
+
|
|
845
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
846
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
847
|
+
sage: Q = V/W
|
|
848
|
+
sage: Q.V()
|
|
849
|
+
Free module of degree 3 and rank 3 over Integer Ring
|
|
850
|
+
Echelon basis matrix:
|
|
851
|
+
[1/2 0 0]
|
|
852
|
+
[ 0 1 0]
|
|
853
|
+
[ 0 0 1]
|
|
854
|
+
"""
|
|
855
|
+
return self._V
|
|
856
|
+
|
|
857
|
+
def cover(self):
|
|
858
|
+
"""
|
|
859
|
+
If this module was constructed as `V/W`, return the cover module `V`.
|
|
860
|
+
|
|
861
|
+
This is the same as ``self.V()``.
|
|
862
|
+
|
|
863
|
+
EXAMPLES::
|
|
864
|
+
|
|
865
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
866
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
867
|
+
sage: Q = V/W
|
|
868
|
+
sage: Q.V()
|
|
869
|
+
Free module of degree 3 and rank 3 over Integer Ring
|
|
870
|
+
Echelon basis matrix:
|
|
871
|
+
[1/2 0 0]
|
|
872
|
+
[ 0 1 0]
|
|
873
|
+
[ 0 0 1]
|
|
874
|
+
"""
|
|
875
|
+
return self.V()
|
|
876
|
+
|
|
877
|
+
def W(self):
|
|
878
|
+
"""
|
|
879
|
+
If this module was constructed as a quotient `V/W`, return `W`.
|
|
880
|
+
|
|
881
|
+
EXAMPLES::
|
|
882
|
+
|
|
883
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
884
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
885
|
+
sage: Q = V/W
|
|
886
|
+
sage: Q.W()
|
|
887
|
+
Free module of degree 3 and rank 3 over Integer Ring
|
|
888
|
+
Echelon basis matrix:
|
|
889
|
+
[1/2 8 0]
|
|
890
|
+
[ 0 12 0]
|
|
891
|
+
[ 0 0 4]
|
|
892
|
+
"""
|
|
893
|
+
return self._W
|
|
894
|
+
|
|
895
|
+
def relations(self):
|
|
896
|
+
"""
|
|
897
|
+
If ``self`` was constructed as `V / W`, return the
|
|
898
|
+
relations module `W`.
|
|
899
|
+
|
|
900
|
+
This is the same as ``self.W()``.
|
|
901
|
+
|
|
902
|
+
EXAMPLES::
|
|
903
|
+
|
|
904
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
905
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
906
|
+
sage: Q = V / W
|
|
907
|
+
sage: Q.relations()
|
|
908
|
+
Free module of degree 3 and rank 3 over Integer Ring
|
|
909
|
+
Echelon basis matrix:
|
|
910
|
+
[1/2 8 0]
|
|
911
|
+
[ 0 12 0]
|
|
912
|
+
[ 0 0 4]
|
|
913
|
+
"""
|
|
914
|
+
return self.W()
|
|
915
|
+
|
|
916
|
+
@cached_method
|
|
917
|
+
def _relative_matrix(self):
|
|
918
|
+
"""
|
|
919
|
+
`V` has a fixed choice of basis, and `W` has a fixed choice of
|
|
920
|
+
basis, and both `V` and `W` are free `R`-modules. Since `W` is
|
|
921
|
+
contained in `V`, we can write each basis element of `W` as an
|
|
922
|
+
`R`-linear combination of the basis for `V`. This function
|
|
923
|
+
returns that matrix over `R`, where each row corresponds to a
|
|
924
|
+
basis element of `W`.
|
|
925
|
+
|
|
926
|
+
EXAMPLES::
|
|
927
|
+
|
|
928
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
929
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
930
|
+
sage: Q = V/W
|
|
931
|
+
sage: Q._relative_matrix()
|
|
932
|
+
[ 1 8 0]
|
|
933
|
+
[ 0 12 0]
|
|
934
|
+
[ 0 0 4]
|
|
935
|
+
"""
|
|
936
|
+
V = self._V
|
|
937
|
+
W = self._W
|
|
938
|
+
A = V.coordinate_module(W).basis_matrix().change_ring(self.base_ring())
|
|
939
|
+
return A
|
|
940
|
+
|
|
941
|
+
@cached_method
|
|
942
|
+
def _smith_form(self):
|
|
943
|
+
"""
|
|
944
|
+
Return matrices `S`, `U`, and `V` such that `S = U*R*V`, and `S` is in
|
|
945
|
+
Smith normal form, and `R` is the relative matrix that defines
|
|
946
|
+
``self``.
|
|
947
|
+
|
|
948
|
+
See :meth:`_relative_matrix`.
|
|
949
|
+
|
|
950
|
+
EXAMPLES::
|
|
951
|
+
|
|
952
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
953
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
954
|
+
sage: Q = V/W
|
|
955
|
+
sage: Q._smith_form()
|
|
956
|
+
(
|
|
957
|
+
[ 1 0 0] [ 1 0 0] [ 1 0 8]
|
|
958
|
+
[ 0 4 0] [ 0 1 1] [ 0 0 -1]
|
|
959
|
+
[ 0 0 12], [ 0 -1 0], [ 0 1 3]
|
|
960
|
+
)
|
|
961
|
+
"""
|
|
962
|
+
return self._relative_matrix().smith_form()
|
|
963
|
+
|
|
964
|
+
def base_ring(self):
|
|
965
|
+
"""
|
|
966
|
+
Return the base ring of ``self``.
|
|
967
|
+
|
|
968
|
+
EXAMPLES::
|
|
969
|
+
|
|
970
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
971
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
972
|
+
sage: Q = V/W
|
|
973
|
+
sage: Q.base_ring()
|
|
974
|
+
Integer Ring
|
|
975
|
+
"""
|
|
976
|
+
return self._V.base_ring()
|
|
977
|
+
|
|
978
|
+
@cached_method
|
|
979
|
+
def invariants(self, include_ones=False):
|
|
980
|
+
r"""
|
|
981
|
+
Return the diagonal entries of the Smith form of the relative
|
|
982
|
+
matrix that defines ``self`` (see :meth:`._relative_matrix`)
|
|
983
|
+
padded with zeros, excluding 1s by default. Thus if ``v`` is the
|
|
984
|
+
list of integers returned, then ``self`` is abstractly isomorphic to
|
|
985
|
+
the product of cyclic groups `\ZZ/n\ZZ` where `n` is in ``v``.
|
|
986
|
+
|
|
987
|
+
INPUT:
|
|
988
|
+
|
|
989
|
+
- ``include_ones`` -- boolean (default: ``False``); if ``True``, also
|
|
990
|
+
include 1s in the output list
|
|
991
|
+
|
|
992
|
+
EXAMPLES::
|
|
993
|
+
|
|
994
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
995
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
996
|
+
sage: Q = V/W
|
|
997
|
+
sage: Q.invariants()
|
|
998
|
+
(4, 12)
|
|
999
|
+
|
|
1000
|
+
An example with 1 and 0 rows::
|
|
1001
|
+
|
|
1002
|
+
sage: V = ZZ^3; W = V.span([[1,2,0], [0,1,0], [0,2,0]]); Q = V/W; Q
|
|
1003
|
+
Finitely generated module V/W over Integer Ring with invariants (0)
|
|
1004
|
+
sage: Q.invariants()
|
|
1005
|
+
(0,)
|
|
1006
|
+
sage: Q.invariants(include_ones=True)
|
|
1007
|
+
(1, 1, 0)
|
|
1008
|
+
"""
|
|
1009
|
+
D, _, _ = self._smith_form()
|
|
1010
|
+
|
|
1011
|
+
v = [D[i, i] for i in range(D.nrows())] + [Integer(0)] * (D.ncols()-D.nrows())
|
|
1012
|
+
w = tuple([x for x in v if x != 1])
|
|
1013
|
+
v = tuple(v)
|
|
1014
|
+
self.invariants.set_cache(v, True)
|
|
1015
|
+
self.invariants.set_cache(w, False)
|
|
1016
|
+
return self.invariants(include_ones)
|
|
1017
|
+
|
|
1018
|
+
def gens(self) -> tuple:
|
|
1019
|
+
"""
|
|
1020
|
+
Return tuple of elements `g_0,...,g_n` of ``self`` such that the module generated by
|
|
1021
|
+
the `g_i` is isomorphic to the direct sum of `R/e_i R`, where `e_i` are the
|
|
1022
|
+
invariants of ``self`` and `R` is the base ring.
|
|
1023
|
+
|
|
1024
|
+
Note that these are not generally uniquely determined, and depending on
|
|
1025
|
+
how Smith normal form is implemented for the base ring, they may not
|
|
1026
|
+
even be deterministic.
|
|
1027
|
+
|
|
1028
|
+
This can safely be overridden in all derived classes.
|
|
1029
|
+
|
|
1030
|
+
EXAMPLES::
|
|
1031
|
+
|
|
1032
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
1033
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
1034
|
+
sage: Q = V/W
|
|
1035
|
+
sage: Q.gens()
|
|
1036
|
+
((1, 0), (0, 1))
|
|
1037
|
+
sage: Q.0
|
|
1038
|
+
(1, 0)
|
|
1039
|
+
"""
|
|
1040
|
+
return self.smith_form_gens()
|
|
1041
|
+
|
|
1042
|
+
@cached_method
|
|
1043
|
+
def smith_form_gens(self):
|
|
1044
|
+
"""
|
|
1045
|
+
Return a set of generators for ``self`` which are in Smith normal form.
|
|
1046
|
+
|
|
1047
|
+
EXAMPLES::
|
|
1048
|
+
|
|
1049
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
1050
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
1051
|
+
sage: Q = V/W
|
|
1052
|
+
sage: Q.smith_form_gens()
|
|
1053
|
+
((1, 0), (0, 1))
|
|
1054
|
+
sage: [x.lift() for x in Q.smith_form_gens()]
|
|
1055
|
+
[(0, 3, 1), (0, -1, 0)]
|
|
1056
|
+
"""
|
|
1057
|
+
# Get the rightmost transformation in the Smith form
|
|
1058
|
+
_, _, X = self._smith_form()
|
|
1059
|
+
# Invert it to get a matrix whose rows (in terms of the basis for V)
|
|
1060
|
+
# are the gi (including 1 invariants).
|
|
1061
|
+
Y = X**(-1)
|
|
1062
|
+
# Get the basis matrix for V
|
|
1063
|
+
B = self._V.basis_matrix()
|
|
1064
|
+
# Multiply to express the gi in terms of the ambient vector space.
|
|
1065
|
+
Z = Y*B
|
|
1066
|
+
# Make gens out of the rows of Z that correspond to non-1 invariants.
|
|
1067
|
+
v = self.invariants(include_ones=True)
|
|
1068
|
+
non1 = [i for i in range(Z.nrows()) if v[i] != 1]
|
|
1069
|
+
Z = Z.matrix_from_rows(non1)
|
|
1070
|
+
self._gens_smith = tuple([self(z, check=DEBUG) for z in Z.rows()])
|
|
1071
|
+
return self._gens_smith
|
|
1072
|
+
|
|
1073
|
+
def gens_to_smith(self):
|
|
1074
|
+
r"""
|
|
1075
|
+
Return the transformation matrix from the user to Smith form generators.
|
|
1076
|
+
|
|
1077
|
+
To go in the other direction, use :meth:`smith_to_gens`.
|
|
1078
|
+
|
|
1079
|
+
OUTPUT: a matrix over the base ring
|
|
1080
|
+
|
|
1081
|
+
EXAMPLES::
|
|
1082
|
+
|
|
1083
|
+
sage: L2 = IntegralLattice(3 * matrix([[-2,0,0], [0,1,0], [0,0,-4]]))
|
|
1084
|
+
sage: D = L2.discriminant_group().normal_form(); D # needs sage.libs.pari sage.rings.padics
|
|
1085
|
+
Finite quadratic module over Integer Ring with invariants (3, 6, 12)
|
|
1086
|
+
Gram matrix of the quadratic form with values in Q/Z:
|
|
1087
|
+
[1/2 0 0 0 0]
|
|
1088
|
+
[ 0 1/4 0 0 0]
|
|
1089
|
+
[ 0 0 1/3 0 0]
|
|
1090
|
+
[ 0 0 0 1/3 0]
|
|
1091
|
+
[ 0 0 0 0 2/3]
|
|
1092
|
+
sage: D.gens_to_smith() # needs sage.libs.pari sage.rings.padics
|
|
1093
|
+
[0 3 0]
|
|
1094
|
+
[0 0 3]
|
|
1095
|
+
[0 4 0]
|
|
1096
|
+
[1 2 0]
|
|
1097
|
+
[0 0 4]
|
|
1098
|
+
sage: T = D.gens_to_smith() * D.smith_to_gens(); T # needs sage.libs.pari sage.rings.padics
|
|
1099
|
+
[ 3 0 3 0 0]
|
|
1100
|
+
[ 0 33 0 0 3]
|
|
1101
|
+
[ 4 0 4 0 0]
|
|
1102
|
+
[ 2 0 3 1 0]
|
|
1103
|
+
[ 0 44 0 0 4]
|
|
1104
|
+
|
|
1105
|
+
The matrix `T` now satisfies a certain congruence::
|
|
1106
|
+
|
|
1107
|
+
sage: for i in range(T.nrows()): # needs sage.libs.pari sage.rings.padics
|
|
1108
|
+
....: T[:,i] = T[:,i] % D.gens()[i].order()
|
|
1109
|
+
sage: T # needs sage.libs.pari sage.rings.padics
|
|
1110
|
+
[1 0 0 0 0]
|
|
1111
|
+
[0 1 0 0 0]
|
|
1112
|
+
[0 0 1 0 0]
|
|
1113
|
+
[0 0 0 1 0]
|
|
1114
|
+
[0 0 0 0 1]
|
|
1115
|
+
"""
|
|
1116
|
+
gens_to_smith = matrix(self.base_ring(),
|
|
1117
|
+
[t.vector() for t in self.gens()])
|
|
1118
|
+
gens_to_smith.set_immutable()
|
|
1119
|
+
return gens_to_smith
|
|
1120
|
+
|
|
1121
|
+
@cached_method
|
|
1122
|
+
def smith_to_gens(self):
|
|
1123
|
+
r"""
|
|
1124
|
+
Return the transformation matrix from Smith form to user generators.
|
|
1125
|
+
|
|
1126
|
+
To go in the other direction, use :meth:`gens_to_smith`.
|
|
1127
|
+
|
|
1128
|
+
OUTPUT: a matrix over the base ring
|
|
1129
|
+
|
|
1130
|
+
EXAMPLES::
|
|
1131
|
+
|
|
1132
|
+
sage: L2 = IntegralLattice(3 * matrix([[-2,0,0], [0,1,0], [0,0,-4]]))
|
|
1133
|
+
sage: D = L2.discriminant_group().normal_form(); D # needs sage.libs.pari sage.rings.padics
|
|
1134
|
+
Finite quadratic module over Integer Ring with invariants (3, 6, 12)
|
|
1135
|
+
Gram matrix of the quadratic form with values in Q/Z:
|
|
1136
|
+
[1/2 0 0 0 0]
|
|
1137
|
+
[ 0 1/4 0 0 0]
|
|
1138
|
+
[ 0 0 1/3 0 0]
|
|
1139
|
+
[ 0 0 0 1/3 0]
|
|
1140
|
+
[ 0 0 0 0 2/3]
|
|
1141
|
+
sage: D.smith_to_gens() # needs sage.libs.pari sage.rings.padics
|
|
1142
|
+
[ 0 0 1 1 0]
|
|
1143
|
+
[ 1 0 1 0 0]
|
|
1144
|
+
[ 0 11 0 0 1]
|
|
1145
|
+
sage: T = D.smith_to_gens() * D.gens_to_smith(); T # needs sage.libs.pari sage.rings.padics
|
|
1146
|
+
[ 1 6 0]
|
|
1147
|
+
[ 0 7 0]
|
|
1148
|
+
[ 0 0 37]
|
|
1149
|
+
|
|
1150
|
+
This matrix satisfies the congruence::
|
|
1151
|
+
|
|
1152
|
+
sage: for i in range(T.ncols()): # needs sage.libs.pari sage.rings.padics
|
|
1153
|
+
....: T[:, i] = T[:, i] % D.smith_form_gens()[i].order()
|
|
1154
|
+
sage: T # needs sage.libs.pari sage.rings.padics
|
|
1155
|
+
[1 0 0]
|
|
1156
|
+
[0 1 0]
|
|
1157
|
+
[0 0 1]
|
|
1158
|
+
|
|
1159
|
+
We create some element of our FGP module::
|
|
1160
|
+
|
|
1161
|
+
sage: x = D.linear_combination_of_smith_form_gens((1,2,3)); x # needs sage.libs.pari sage.rings.padics
|
|
1162
|
+
(1, 2, 3)
|
|
1163
|
+
|
|
1164
|
+
and want to know some (it is not unique) linear combination
|
|
1165
|
+
of the user defined generators that is ``x``::
|
|
1166
|
+
|
|
1167
|
+
sage: x.vector() * D.smith_to_gens() # needs sage.libs.pari sage.rings.padics
|
|
1168
|
+
(2, 33, 3, 1, 3)
|
|
1169
|
+
"""
|
|
1170
|
+
if self.base_ring() != ZZ:
|
|
1171
|
+
# it is not
|
|
1172
|
+
raise NotImplementedError("the base ring must be ZZ")
|
|
1173
|
+
base = self.base_ring()
|
|
1174
|
+
invs = self.invariants()
|
|
1175
|
+
B = self.gens_to_smith()
|
|
1176
|
+
n = len(invs)
|
|
1177
|
+
smith_to_gens = []
|
|
1178
|
+
for k in range(n):
|
|
1179
|
+
R = base.quotient_ring(invs[k])
|
|
1180
|
+
e = (R**n).gen(k) # k-th standard basis vector
|
|
1181
|
+
v = B.change_ring(R).solve_left(e)
|
|
1182
|
+
smith_to_gens.append(v)
|
|
1183
|
+
smith_to_gens = matrix(base, smith_to_gens)
|
|
1184
|
+
smith_to_gens.set_immutable()
|
|
1185
|
+
return smith_to_gens
|
|
1186
|
+
|
|
1187
|
+
def gens_vector(self, x, reduce=False):
|
|
1188
|
+
r"""
|
|
1189
|
+
Return coordinates of ``x`` with respect to the generators.
|
|
1190
|
+
|
|
1191
|
+
INPUT:
|
|
1192
|
+
|
|
1193
|
+
- ``x`` -- element of ``self``
|
|
1194
|
+
|
|
1195
|
+
- ``reduce`` -- (default: ``False``) if ``True``,
|
|
1196
|
+
reduce coefficients modulo invariants; this is
|
|
1197
|
+
ignored if the base ring is not `\ZZ`
|
|
1198
|
+
|
|
1199
|
+
EXAMPLES:
|
|
1200
|
+
|
|
1201
|
+
We create a derived class and overwrite :meth:`gens`::
|
|
1202
|
+
|
|
1203
|
+
sage: from sage.modules.fg_pid.fgp_module import FGP_Module_class
|
|
1204
|
+
sage: W = ZZ^3
|
|
1205
|
+
sage: V = W.span(matrix.diagonal([1/6, 1/3, 1/12]))
|
|
1206
|
+
sage: class FGP_with_gens(FGP_Module_class):
|
|
1207
|
+
....: def __init__(self, V, W, gens):
|
|
1208
|
+
....: FGP_Module_class.__init__(self, V, W)
|
|
1209
|
+
....: self._gens = tuple([self(g) for g in gens])
|
|
1210
|
+
....: def gens(self):
|
|
1211
|
+
....: return self._gens
|
|
1212
|
+
sage: gens = [(1/2, 0, 0), (0, 0, 1/4), (1/3, 0, 0), (0, 1/3, 0), (0, 0, 2/3)]
|
|
1213
|
+
sage: gens = [V(g) for g in gens]
|
|
1214
|
+
sage: D = FGP_with_gens(V, W, gens)
|
|
1215
|
+
sage: D.gens()
|
|
1216
|
+
((0, 3, 0), (0, 0, 3), (0, 4, 0), (1, 2, 0), (0, 0, 8))
|
|
1217
|
+
|
|
1218
|
+
|
|
1219
|
+
We create some element of ``D``::
|
|
1220
|
+
|
|
1221
|
+
sage: x = D.linear_combination_of_smith_form_gens((1,2,3)); x
|
|
1222
|
+
(1, 2, 3)
|
|
1223
|
+
|
|
1224
|
+
In our generators::
|
|
1225
|
+
|
|
1226
|
+
sage: v = D.gens_vector(x); v # needs sage.libs.pari
|
|
1227
|
+
(2, 9, 3, 1, 33)
|
|
1228
|
+
|
|
1229
|
+
The output can be further reduced::
|
|
1230
|
+
|
|
1231
|
+
sage: D.gens_vector(x, reduce=True) # needs sage.libs.pari
|
|
1232
|
+
(0, 1, 0, 1, 0)
|
|
1233
|
+
|
|
1234
|
+
Let us check::
|
|
1235
|
+
|
|
1236
|
+
sage: x == sum(v[i]*D.gen(i) for i in range(len(D.gens()))) # needs sage.libs.pari
|
|
1237
|
+
True
|
|
1238
|
+
"""
|
|
1239
|
+
x = self(x)
|
|
1240
|
+
v = x.vector() * self.smith_to_gens()
|
|
1241
|
+
from sage.rings.infinity import infinity
|
|
1242
|
+
if reduce and self.base_ring() == ZZ:
|
|
1243
|
+
orders = [g.order() for g in self.gens()]
|
|
1244
|
+
v = v.parent()([v[i] if orders[i] == infinity
|
|
1245
|
+
else v[i] % orders[i]
|
|
1246
|
+
for i in range(len(self.gens()))])
|
|
1247
|
+
return v
|
|
1248
|
+
|
|
1249
|
+
def coordinate_vector(self, x, reduce=False):
|
|
1250
|
+
"""
|
|
1251
|
+
Return coordinates of ``x`` with respect to the optimized
|
|
1252
|
+
representation of ``self``.
|
|
1253
|
+
|
|
1254
|
+
INPUT:
|
|
1255
|
+
|
|
1256
|
+
- ``x`` -- element of ``self``
|
|
1257
|
+
|
|
1258
|
+
- ``reduce`` -- (default: ``False``) if ``True``, reduce
|
|
1259
|
+
coefficients modulo invariants; this is
|
|
1260
|
+
ignored if the base ring is not ``ZZ``
|
|
1261
|
+
|
|
1262
|
+
OUTPUT:
|
|
1263
|
+
|
|
1264
|
+
The coordinates as a vector. That is, the same type as
|
|
1265
|
+
``self.V()``, but in general with fewer entries.
|
|
1266
|
+
|
|
1267
|
+
EXAMPLES::
|
|
1268
|
+
|
|
1269
|
+
sage: V = span([[1/4,0,0], [3/4,4,2], [0,0,2]], ZZ)
|
|
1270
|
+
sage: W = V.span([4*V.0 + 12*V.1])
|
|
1271
|
+
sage: Q = V/W; Q
|
|
1272
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 0, 0)
|
|
1273
|
+
sage: Q.coordinate_vector(-Q.0)
|
|
1274
|
+
(-1, 0, 0)
|
|
1275
|
+
sage: Q.coordinate_vector(-Q.0, reduce=True)
|
|
1276
|
+
(3, 0, 0)
|
|
1277
|
+
|
|
1278
|
+
If x is not in self, it is coerced in::
|
|
1279
|
+
|
|
1280
|
+
sage: Q.coordinate_vector(V.0)
|
|
1281
|
+
(1, -3, 0)
|
|
1282
|
+
sage: Q.coordinate_vector(Q(V.0))
|
|
1283
|
+
(1, -3, 0)
|
|
1284
|
+
|
|
1285
|
+
TESTS::
|
|
1286
|
+
|
|
1287
|
+
sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ)
|
|
1288
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
1289
|
+
sage: Q = V/W; Q
|
|
1290
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
1291
|
+
sage: Q.coordinate_vector(Q.0 - Q.1, reduce=True)
|
|
1292
|
+
(1, 11)
|
|
1293
|
+
sage: a, b = Q.coordinate_vector(Q.0 - Q.1)
|
|
1294
|
+
sage: (a % 4, b % 12)
|
|
1295
|
+
(1, 11)
|
|
1296
|
+
|
|
1297
|
+
sage: O, X = Q.optimized()
|
|
1298
|
+
sage: O.V()
|
|
1299
|
+
Free module of degree 3 and rank 2 over Integer Ring
|
|
1300
|
+
User basis matrix:
|
|
1301
|
+
[ 0 6 1]
|
|
1302
|
+
[ 0 -2 0]
|
|
1303
|
+
sage: phi = Q.hom([Q.0, 4*Q.1])
|
|
1304
|
+
sage: x = Q(V.0); x
|
|
1305
|
+
(0, 8)
|
|
1306
|
+
sage: Q.coordinate_vector(x, reduce=True)
|
|
1307
|
+
(0, 8)
|
|
1308
|
+
sage: a, b = Q.coordinate_vector(-x, reduce=False)
|
|
1309
|
+
sage: (a % 4, b % 12)
|
|
1310
|
+
(0, 4)
|
|
1311
|
+
sage: x == 8*Q.1
|
|
1312
|
+
True
|
|
1313
|
+
sage: x = Q(V.1); x
|
|
1314
|
+
(0, 11)
|
|
1315
|
+
sage: a, b = Q.coordinate_vector(x)
|
|
1316
|
+
sage: (a % 4, b % 12)
|
|
1317
|
+
(0, 11)
|
|
1318
|
+
sage: x == -Q.1
|
|
1319
|
+
True
|
|
1320
|
+
sage: x = Q(V.2); x
|
|
1321
|
+
(1, 3)
|
|
1322
|
+
sage: Q.coordinate_vector(x)
|
|
1323
|
+
(1, 3)
|
|
1324
|
+
sage: x == Q.0 + 3*Q.1
|
|
1325
|
+
True
|
|
1326
|
+
"""
|
|
1327
|
+
try:
|
|
1328
|
+
T = self.__T
|
|
1329
|
+
except AttributeError:
|
|
1330
|
+
self.optimized() # computes T as side effect
|
|
1331
|
+
# see the "optimized" method.
|
|
1332
|
+
T = self.__T
|
|
1333
|
+
|
|
1334
|
+
x = self(x)
|
|
1335
|
+
|
|
1336
|
+
c = self._V.coordinate_vector(x.lift())
|
|
1337
|
+
b = (c * T).change_ring(self.base_ring())
|
|
1338
|
+
if reduce and self.base_ring() == ZZ:
|
|
1339
|
+
|
|
1340
|
+
I = self.invariants()
|
|
1341
|
+
return b.parent()([b[i] if I[i] == 0 else b[i] % I[i]
|
|
1342
|
+
for i in range(len(I))])
|
|
1343
|
+
|
|
1344
|
+
else:
|
|
1345
|
+
# Don't know (or not requested) canonical way to reduce
|
|
1346
|
+
# each entry yet, or how to compute invariants.
|
|
1347
|
+
return b
|
|
1348
|
+
|
|
1349
|
+
def gen(self, i):
|
|
1350
|
+
"""
|
|
1351
|
+
Return the ``i``-th generator of ``self``.
|
|
1352
|
+
|
|
1353
|
+
INPUT:
|
|
1354
|
+
|
|
1355
|
+
- ``i`` -- integer
|
|
1356
|
+
|
|
1357
|
+
EXAMPLES::
|
|
1358
|
+
|
|
1359
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
1360
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
1361
|
+
sage: Q = V/W; Q
|
|
1362
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
1363
|
+
sage: Q.gen(0)
|
|
1364
|
+
(1, 0)
|
|
1365
|
+
sage: Q.gen(1)
|
|
1366
|
+
(0, 1)
|
|
1367
|
+
sage: Q.gen(2)
|
|
1368
|
+
Traceback (most recent call last):
|
|
1369
|
+
...
|
|
1370
|
+
ValueError: Generator 2 not defined
|
|
1371
|
+
sage: Q.gen(-1)
|
|
1372
|
+
Traceback (most recent call last):
|
|
1373
|
+
...
|
|
1374
|
+
ValueError: Generator -1 not defined
|
|
1375
|
+
"""
|
|
1376
|
+
v = self.gens()
|
|
1377
|
+
if i < 0 or i >= len(v):
|
|
1378
|
+
raise ValueError("Generator %s not defined" % i)
|
|
1379
|
+
return v[i]
|
|
1380
|
+
|
|
1381
|
+
def smith_form_gen(self, i):
|
|
1382
|
+
"""
|
|
1383
|
+
Return the ``i``-th generator of ``self``.
|
|
1384
|
+
|
|
1385
|
+
This is a separate method so we can freely override :meth:`gen`
|
|
1386
|
+
in derived classes.
|
|
1387
|
+
|
|
1388
|
+
INPUT:
|
|
1389
|
+
|
|
1390
|
+
- ``i`` -- integer
|
|
1391
|
+
|
|
1392
|
+
EXAMPLES::
|
|
1393
|
+
|
|
1394
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
1395
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
1396
|
+
sage: Q = V/W; Q
|
|
1397
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
1398
|
+
sage: Q.smith_form_gen(0)
|
|
1399
|
+
(1, 0)
|
|
1400
|
+
sage: Q.smith_form_gen(1)
|
|
1401
|
+
(0, 1)
|
|
1402
|
+
"""
|
|
1403
|
+
v = self.smith_form_gens()
|
|
1404
|
+
if i < 0 or i >= len(v):
|
|
1405
|
+
raise ValueError("Smith form generator %s not defined" % i)
|
|
1406
|
+
return v[i]
|
|
1407
|
+
|
|
1408
|
+
def optimized(self):
|
|
1409
|
+
r"""
|
|
1410
|
+
Return a module isomorphic to this one, but with `V` replaced by
|
|
1411
|
+
a submodule of `V` such that the generators of ``self`` all lift
|
|
1412
|
+
trivially to generators of `V`. Replace `W` by the intersection
|
|
1413
|
+
of `V` and `W`. This has the advantage that `V` has small dimension
|
|
1414
|
+
and any homomorphism from ``self`` trivially extends to a
|
|
1415
|
+
homomorphism from `V`.
|
|
1416
|
+
|
|
1417
|
+
OUTPUT:
|
|
1418
|
+
|
|
1419
|
+
- ``Q`` -- an optimized quotient `V_0/W_0` with `V_0` a submodule of `V`
|
|
1420
|
+
such that `\phi: V_0/W_0 \to V/W` is an isomorphism
|
|
1421
|
+
|
|
1422
|
+
- ``Z`` -- matrix such that if `x` is in ``self.V()`` and
|
|
1423
|
+
``c`` gives the coordinates of `x` in terms of the
|
|
1424
|
+
basis for ``self.V()``, then ``c*Z`` is in `V_0`
|
|
1425
|
+
and ``c*Z`` maps to `x` via `\phi` above.
|
|
1426
|
+
|
|
1427
|
+
EXAMPLES::
|
|
1428
|
+
|
|
1429
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
1430
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
1431
|
+
sage: Q = V/W
|
|
1432
|
+
sage: O, X = Q.optimized(); O
|
|
1433
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 12)
|
|
1434
|
+
sage: O.V()
|
|
1435
|
+
Free module of degree 3 and rank 2 over Integer Ring
|
|
1436
|
+
User basis matrix:
|
|
1437
|
+
[ 0 3 1]
|
|
1438
|
+
[ 0 -1 0]
|
|
1439
|
+
sage: O.W()
|
|
1440
|
+
Free module of degree 3 and rank 2 over Integer Ring
|
|
1441
|
+
Echelon basis matrix:
|
|
1442
|
+
[ 0 12 0]
|
|
1443
|
+
[ 0 0 4]
|
|
1444
|
+
sage: X # random
|
|
1445
|
+
[0 4 0]
|
|
1446
|
+
[0 1 0]
|
|
1447
|
+
[0 0 1]
|
|
1448
|
+
sage: OV = O.V()
|
|
1449
|
+
sage: Q(OV([0,-8,0])) == V.0
|
|
1450
|
+
True
|
|
1451
|
+
sage: Q(OV([0,1,0])) == V.1
|
|
1452
|
+
True
|
|
1453
|
+
sage: Q(OV([0,0,1])) == V.2
|
|
1454
|
+
True
|
|
1455
|
+
"""
|
|
1456
|
+
try:
|
|
1457
|
+
if self.__optimized is True:
|
|
1458
|
+
return self, None
|
|
1459
|
+
return self.__optimized
|
|
1460
|
+
except AttributeError:
|
|
1461
|
+
pass
|
|
1462
|
+
V = self._V.span_of_basis([x.lift() for x in self.smith_form_gens()])
|
|
1463
|
+
M = self._module_constructor(V, self._W.intersection(V))
|
|
1464
|
+
# Compute matrix T of linear transformation from self._V to V.
|
|
1465
|
+
# This matrix T gives each basis element of self._V in terms
|
|
1466
|
+
# of our new optimized V, modulo the W's.
|
|
1467
|
+
A = V.basis_matrix().stack(self._W.basis_matrix())
|
|
1468
|
+
if A.base_ring() is ZZ:
|
|
1469
|
+
B, d = A, 1
|
|
1470
|
+
else:
|
|
1471
|
+
try:
|
|
1472
|
+
# Use fast routine specific to Matrix_rational_dense
|
|
1473
|
+
B, d = A._clear_denom()
|
|
1474
|
+
except AttributeError:
|
|
1475
|
+
d = LCM_list(coeff.denominator()
|
|
1476
|
+
for key, coeff in A.items())
|
|
1477
|
+
B = d * A
|
|
1478
|
+
H, U = B.hermite_form(transformation=True)
|
|
1479
|
+
Y = H.solve_left(d * self._V.basis_matrix())
|
|
1480
|
+
T = Y * U.matrix_from_columns(range(V.rank()))
|
|
1481
|
+
self.__T = T
|
|
1482
|
+
|
|
1483
|
+
# Finally we multiply by V.basis_matrix() so X gives vectors
|
|
1484
|
+
# in the ambient space instead of coefficients of linear
|
|
1485
|
+
# combinations of the basis for V.
|
|
1486
|
+
X = T * V.basis_matrix()
|
|
1487
|
+
|
|
1488
|
+
self.__optimized = M, X
|
|
1489
|
+
return M, X
|
|
1490
|
+
|
|
1491
|
+
def hom(self, im_gens, codomain=None, check=True):
|
|
1492
|
+
"""
|
|
1493
|
+
Homomorphism defined by giving the images of ``self.gens()`` in some
|
|
1494
|
+
fixed finitely generated `R`-module.
|
|
1495
|
+
|
|
1496
|
+
.. NOTE::
|
|
1497
|
+
|
|
1498
|
+
We do not assume that the generators given by ``self.gens()`` are
|
|
1499
|
+
the same as the Smith form generators, since this may not be true
|
|
1500
|
+
for a general derived class.
|
|
1501
|
+
|
|
1502
|
+
INPUT:
|
|
1503
|
+
|
|
1504
|
+
- ``im_gens`` -- list of the images of ``self.gens()`` in some
|
|
1505
|
+
`R`-module
|
|
1506
|
+
|
|
1507
|
+
EXAMPLES::
|
|
1508
|
+
|
|
1509
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
1510
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
1511
|
+
sage: Q = V/W
|
|
1512
|
+
sage: phi = Q.hom([3*Q.1, Q.0])
|
|
1513
|
+
sage: phi
|
|
1514
|
+
Morphism from module over Integer Ring with invariants (4, 12)
|
|
1515
|
+
to module with invariants (4, 12)
|
|
1516
|
+
that sends the generators to [(0, 3), (1, 0)]
|
|
1517
|
+
sage: phi(Q.0)
|
|
1518
|
+
(0, 3)
|
|
1519
|
+
sage: phi(Q.1)
|
|
1520
|
+
(1, 0)
|
|
1521
|
+
sage: Q.0 == phi(Q.1)
|
|
1522
|
+
True
|
|
1523
|
+
|
|
1524
|
+
This example illustrates creating a morphism to a free module.
|
|
1525
|
+
The free module is turned into an FGP module (i.e., quotient
|
|
1526
|
+
`V/W` with `W=0`), and the morphism is constructed::
|
|
1527
|
+
|
|
1528
|
+
sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ)
|
|
1529
|
+
sage: W = V.span([2*V.0 + 4*V.1])
|
|
1530
|
+
sage: Q = V/W; Q
|
|
1531
|
+
Finitely generated module V/W over Integer Ring with invariants (2, 0, 0)
|
|
1532
|
+
sage: phi = Q.hom([0, V.0, V.1]); phi
|
|
1533
|
+
Morphism from module over Integer Ring with invariants (2, 0, 0)
|
|
1534
|
+
to module with invariants (0, 0, 0)
|
|
1535
|
+
that sends the generators to [(0, 0, 0), (1, 0, 0), (0, 1, 0)]
|
|
1536
|
+
sage: phi.domain()
|
|
1537
|
+
Finitely generated module V/W over Integer Ring with invariants (2, 0, 0)
|
|
1538
|
+
sage: phi.codomain()
|
|
1539
|
+
Finitely generated module V/W over Integer Ring with invariants (0, 0, 0)
|
|
1540
|
+
sage: phi(Q.0)
|
|
1541
|
+
(0, 0, 0)
|
|
1542
|
+
sage: phi(Q.1)
|
|
1543
|
+
(1, 0, 0)
|
|
1544
|
+
sage: phi(Q.2) == V.1
|
|
1545
|
+
True
|
|
1546
|
+
|
|
1547
|
+
Constructing two zero maps from the zero module::
|
|
1548
|
+
|
|
1549
|
+
sage: A = (ZZ^2)/(ZZ^2); A
|
|
1550
|
+
Finitely generated module V/W over Integer Ring with invariants ()
|
|
1551
|
+
sage: A.hom([])
|
|
1552
|
+
Morphism from module over Integer Ring with invariants ()
|
|
1553
|
+
to module with invariants ()
|
|
1554
|
+
that sends the generators to []
|
|
1555
|
+
sage: A.hom([]).codomain() is A
|
|
1556
|
+
True
|
|
1557
|
+
sage: B = (ZZ^3)/(ZZ^3)
|
|
1558
|
+
sage: phi = A.hom([], codomain=B); phi
|
|
1559
|
+
Morphism from module over Integer Ring with invariants ()
|
|
1560
|
+
to module with invariants ()
|
|
1561
|
+
that sends the generators to []
|
|
1562
|
+
sage: phi(A(0))
|
|
1563
|
+
()
|
|
1564
|
+
sage: phi(A(0)) == B(0)
|
|
1565
|
+
True
|
|
1566
|
+
|
|
1567
|
+
A degenerate case::
|
|
1568
|
+
|
|
1569
|
+
sage: A = (ZZ^2)/(ZZ^2)
|
|
1570
|
+
sage: phi = A.hom([]); phi
|
|
1571
|
+
Morphism from module over Integer Ring with invariants ()
|
|
1572
|
+
to module with invariants ()
|
|
1573
|
+
that sends the generators to []
|
|
1574
|
+
sage: phi(A(0))
|
|
1575
|
+
()
|
|
1576
|
+
|
|
1577
|
+
The code checks that the morphism is valid. In the example
|
|
1578
|
+
below we try to send a generator of order 2 to an element of
|
|
1579
|
+
order 14::
|
|
1580
|
+
|
|
1581
|
+
sage: V = span([[1/14,3/14], [0,1/2]], ZZ); W = ZZ^2
|
|
1582
|
+
sage: Q = V/W; Q
|
|
1583
|
+
Finitely generated module V/W over Integer Ring with invariants (2, 14)
|
|
1584
|
+
sage: Q.linear_combination_of_smith_form_gens([1,11]).additive_order()
|
|
1585
|
+
14
|
|
1586
|
+
sage: f = Q.hom([Q.linear_combination_of_smith_form_gens([1,11]),
|
|
1587
|
+
....: Q.linear_combination_of_smith_form_gens([1,3])]); f
|
|
1588
|
+
Traceback (most recent call last):
|
|
1589
|
+
...
|
|
1590
|
+
ValueError: phi must send optimized submodule of M.W() into N.W()
|
|
1591
|
+
"""
|
|
1592
|
+
if len(im_gens) == 0:
|
|
1593
|
+
# 0 map
|
|
1594
|
+
N = self if codomain is None else codomain
|
|
1595
|
+
else:
|
|
1596
|
+
if codomain is None:
|
|
1597
|
+
im_gens = Sequence(im_gens)
|
|
1598
|
+
N = im_gens.universe()
|
|
1599
|
+
else:
|
|
1600
|
+
N = codomain
|
|
1601
|
+
im_gens = Sequence(im_gens, universe=N)
|
|
1602
|
+
|
|
1603
|
+
if isinstance(N, FreeModule_generic):
|
|
1604
|
+
# If im_smith_gens are not in an R-module, but are in a Free-module,
|
|
1605
|
+
# then we quotient out by the 0 submodule and get an R-module.
|
|
1606
|
+
N = FGP_Module(N, N.zero_submodule(), check=DEBUG)
|
|
1607
|
+
im_gens = Sequence(im_gens, universe=N)
|
|
1608
|
+
|
|
1609
|
+
if len(im_gens) == 0:
|
|
1610
|
+
VO = self.optimized()[0].V()
|
|
1611
|
+
H = VO.Hom(N.V())
|
|
1612
|
+
return FGP_Morphism(self.Hom(N), H(0), check=DEBUG)
|
|
1613
|
+
|
|
1614
|
+
if self.gens() == self.smith_form_gens():
|
|
1615
|
+
return self._hom_from_smith(im_gens, check)
|
|
1616
|
+
else:
|
|
1617
|
+
return self._hom_general(im_gens, check)
|
|
1618
|
+
|
|
1619
|
+
def _hom_general(self, im_gens, check=True):
|
|
1620
|
+
"""
|
|
1621
|
+
Homomorphism defined by giving the images of ``self.gens()`` in some
|
|
1622
|
+
fixed finitely generated `R`-module. We do not assume that the generators given by
|
|
1623
|
+
``self.gens()`` are the same as the Smith form generators, since this
|
|
1624
|
+
may not be true for a general derived class.
|
|
1625
|
+
|
|
1626
|
+
INPUT:
|
|
1627
|
+
|
|
1628
|
+
- ``im_gens`` -- a Sequence object giving the images of ``self.gens()``,
|
|
1629
|
+
whose universe is some fixed finitely generated `R`-module
|
|
1630
|
+
|
|
1631
|
+
EXAMPLES::
|
|
1632
|
+
|
|
1633
|
+
sage: class SillyModule(sage.modules.fg_pid.fgp_module.FGP_Module_class):
|
|
1634
|
+
....: def gens(self):
|
|
1635
|
+
....: return tuple(flatten([[x,x] for x in self.smith_form_gens()]))
|
|
1636
|
+
sage: A = SillyModule(ZZ**1, span([[3]], ZZ))
|
|
1637
|
+
sage: A.gen(0)
|
|
1638
|
+
(1)
|
|
1639
|
+
sage: A.gen(1)
|
|
1640
|
+
(1)
|
|
1641
|
+
sage: B = ZZ**1 / span([[3]], ZZ)
|
|
1642
|
+
sage: A.hom([B.0, 2*B.0], B)
|
|
1643
|
+
Traceback (most recent call last):
|
|
1644
|
+
...
|
|
1645
|
+
ValueError: Images do not determine a valid homomorphism
|
|
1646
|
+
sage: A.hom([B.0, B.0], B) # indirect doctest
|
|
1647
|
+
Morphism from module over Integer Ring with invariants (3,)
|
|
1648
|
+
to module with invariants (3,)
|
|
1649
|
+
that sends the generators to [(1), (1)]
|
|
1650
|
+
"""
|
|
1651
|
+
m = self.ngens()
|
|
1652
|
+
A = ZZ**m
|
|
1653
|
+
q = A.hom([x.lift() for x in self.gens()], self.V())
|
|
1654
|
+
B = q.inverse_image(self.W())
|
|
1655
|
+
N = im_gens.universe()
|
|
1656
|
+
r = A.hom([x.lift() for x in im_gens], N.V())
|
|
1657
|
+
if check:
|
|
1658
|
+
if not r(B).is_submodule(N.W()):
|
|
1659
|
+
raise ValueError("Images do not determine a valid homomorphism")
|
|
1660
|
+
smith_images = Sequence([N(r(q.lift(x.lift()))) for x in self.smith_form_gens()])
|
|
1661
|
+
return self._hom_from_smith(smith_images, check=DEBUG)
|
|
1662
|
+
|
|
1663
|
+
def _hom_from_smith(self, im_smith_gens, check=True):
|
|
1664
|
+
"""
|
|
1665
|
+
Homomorphism defined by giving the images of the Smith-form generators
|
|
1666
|
+
of ``self`` in some fixed finitely generated `R`-module.
|
|
1667
|
+
|
|
1668
|
+
INPUT:
|
|
1669
|
+
|
|
1670
|
+
- ``im_gens`` -- a Sequence object giving the images of the Smith-form
|
|
1671
|
+
generators of ``self``, whose universe is some fixed finitely generated `R`-module
|
|
1672
|
+
|
|
1673
|
+
EXAMPLES::
|
|
1674
|
+
|
|
1675
|
+
sage: class SillyModule(sage.modules.fg_pid.fgp_module.FGP_Module_class):
|
|
1676
|
+
....: def gens(self):
|
|
1677
|
+
....: return tuple(flatten([[x,x] for x in self.smith_form_gens()]))
|
|
1678
|
+
sage: A = SillyModule(ZZ**1, span([[3]], ZZ))
|
|
1679
|
+
sage: A.gen(0)
|
|
1680
|
+
(1)
|
|
1681
|
+
sage: A.gen(1)
|
|
1682
|
+
(1)
|
|
1683
|
+
sage: B = ZZ**1 / span([[3]], ZZ)
|
|
1684
|
+
sage: A._hom_from_smith(Sequence([B.0]))
|
|
1685
|
+
Morphism from module over Integer Ring with invariants (3,)
|
|
1686
|
+
to module with invariants (3,)
|
|
1687
|
+
that sends the generators to [(1), (1)]
|
|
1688
|
+
"""
|
|
1689
|
+
if len(im_smith_gens) != len(self.smith_form_gens()):
|
|
1690
|
+
raise ValueError("im_gens must have length the same as self.smith_form_gens()")
|
|
1691
|
+
|
|
1692
|
+
# replace self by representation in which smith-gens g_i are a basis for V.
|
|
1693
|
+
M, _ = self.optimized()
|
|
1694
|
+
# Define morphism from M to N
|
|
1695
|
+
f = M.V().hom([x.lift() for x in im_smith_gens])
|
|
1696
|
+
N = im_smith_gens.universe()
|
|
1697
|
+
homspace = self.Hom(N)
|
|
1698
|
+
phi = FGP_Morphism(homspace, f, check=DEBUG)
|
|
1699
|
+
return phi
|
|
1700
|
+
|
|
1701
|
+
def _Hom_(self, N, category=None):
|
|
1702
|
+
"""
|
|
1703
|
+
EXAMPLES::
|
|
1704
|
+
|
|
1705
|
+
sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ); W = V.span([V.0 + 2*V.1, 9*V.0 + 2*V.1, 4*V.2])
|
|
1706
|
+
sage: Q = V/W
|
|
1707
|
+
sage: Q.Hom(Q) # indirect doctest
|
|
1708
|
+
Set of Morphisms
|
|
1709
|
+
from Finitely generated module V/W over Integer Ring with invariants (4, 16)
|
|
1710
|
+
to Finitely generated module V/W over Integer Ring with invariants (4, 16)
|
|
1711
|
+
in Category of modules over Integer Ring
|
|
1712
|
+
sage: M = V/V.zero_submodule()
|
|
1713
|
+
sage: H = M.Hom(Q); H
|
|
1714
|
+
Set of Morphisms
|
|
1715
|
+
from Finitely generated module V/W over Integer Ring with invariants (0, 0, 0)
|
|
1716
|
+
to Finitely generated module V/W over Integer Ring with invariants (4, 16)
|
|
1717
|
+
in Category of modules over Integer Ring
|
|
1718
|
+
sage: Hom(M, Q) is H
|
|
1719
|
+
True
|
|
1720
|
+
sage: type(Hom(M, Q))
|
|
1721
|
+
<class 'sage.modules.fg_pid.fgp_morphism.FGP_Homset_class_with_category'>
|
|
1722
|
+
sage: H.category()
|
|
1723
|
+
Category of homsets of modules over Integer Ring
|
|
1724
|
+
sage: H.homset_category()
|
|
1725
|
+
Category of modules over Integer Ring
|
|
1726
|
+
|
|
1727
|
+
The category is correctly adjusted when constructing Hom sets
|
|
1728
|
+
with more general codomains (see :issue:`16402`)::
|
|
1729
|
+
|
|
1730
|
+
sage: V = ZZ^2
|
|
1731
|
+
sage: W = V.quotient(V.span([[1, 1]]))
|
|
1732
|
+
sage: H = W.Hom(QQ); H
|
|
1733
|
+
Set of Morphisms
|
|
1734
|
+
from Finitely generated module V/W over Integer Ring with invariants (0)
|
|
1735
|
+
to Rational Field
|
|
1736
|
+
in Category of commutative additive groups
|
|
1737
|
+
sage: type(H)
|
|
1738
|
+
<class 'sage.categories.homset.Homset_with_category'>
|
|
1739
|
+
"""
|
|
1740
|
+
if isinstance(N, FGP_Module_class):
|
|
1741
|
+
return FGP_Homset(self, N)
|
|
1742
|
+
return super()._Hom_(N, category=category)
|
|
1743
|
+
|
|
1744
|
+
def random_element(self, *args, **kwds):
|
|
1745
|
+
"""
|
|
1746
|
+
Create a random element of ``self`` = `V/W`, by creating a random element of `V` and
|
|
1747
|
+
reducing it modulo `W`.
|
|
1748
|
+
|
|
1749
|
+
All arguments are passed on to the method :meth:`random_element` of `V`.
|
|
1750
|
+
|
|
1751
|
+
EXAMPLES::
|
|
1752
|
+
|
|
1753
|
+
sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ)
|
|
1754
|
+
sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2])
|
|
1755
|
+
sage: Q = V/W
|
|
1756
|
+
sage: Q.random_element().parent() is Q
|
|
1757
|
+
True
|
|
1758
|
+
sage: Q.cardinality()
|
|
1759
|
+
48
|
|
1760
|
+
sage: S = set()
|
|
1761
|
+
sage: while len(S) < 48:
|
|
1762
|
+
....: S.add(Q.random_element())
|
|
1763
|
+
"""
|
|
1764
|
+
return self(self._V.random_element(*args, **kwds))
|
|
1765
|
+
|
|
1766
|
+
def cardinality(self):
|
|
1767
|
+
"""
|
|
1768
|
+
Return the cardinality of this module as a set.
|
|
1769
|
+
|
|
1770
|
+
EXAMPLES::
|
|
1771
|
+
|
|
1772
|
+
sage: V = ZZ^2; W = V.span([[1,2], [3,4]]); A = V/W; A
|
|
1773
|
+
Finitely generated module V/W over Integer Ring with invariants (2)
|
|
1774
|
+
sage: A.cardinality()
|
|
1775
|
+
2
|
|
1776
|
+
sage: V = ZZ^2; W = V.span([[1,2]]); A = V/W; A
|
|
1777
|
+
Finitely generated module V/W over Integer Ring with invariants (0)
|
|
1778
|
+
sage: A.cardinality()
|
|
1779
|
+
+Infinity
|
|
1780
|
+
sage: V = QQ^2; W = V.span([[1,2]]); A = V/W; A
|
|
1781
|
+
Vector space quotient V/W of dimension 1 over Rational Field where
|
|
1782
|
+
V: Vector space of dimension 2 over Rational Field
|
|
1783
|
+
W: Vector space of degree 2 and dimension 1 over Rational Field
|
|
1784
|
+
Basis matrix:
|
|
1785
|
+
[1 2]
|
|
1786
|
+
sage: A.cardinality()
|
|
1787
|
+
+Infinity
|
|
1788
|
+
"""
|
|
1789
|
+
try:
|
|
1790
|
+
return self.__cardinality
|
|
1791
|
+
except AttributeError:
|
|
1792
|
+
pass
|
|
1793
|
+
from sage.rings.infinity import infinity
|
|
1794
|
+
from sage.misc.misc_c import prod
|
|
1795
|
+
v = self.invariants()
|
|
1796
|
+
self.__cardinality = infinity if 0 in v else prod(v)
|
|
1797
|
+
return self.__cardinality
|
|
1798
|
+
|
|
1799
|
+
def list(self):
|
|
1800
|
+
"""
|
|
1801
|
+
Return a list of the elements of ``self``.
|
|
1802
|
+
|
|
1803
|
+
EXAMPLES::
|
|
1804
|
+
|
|
1805
|
+
sage: V = ZZ^2; W = V.span([[1,2],[3,4]])
|
|
1806
|
+
sage: list(V/W)
|
|
1807
|
+
[(0), (1)]
|
|
1808
|
+
"""
|
|
1809
|
+
return list(self)
|
|
1810
|
+
|
|
1811
|
+
def __iter__(self):
|
|
1812
|
+
"""
|
|
1813
|
+
Return iterator over all elements of ``self``.
|
|
1814
|
+
|
|
1815
|
+
EXAMPLES::
|
|
1816
|
+
|
|
1817
|
+
sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ); W = V.span([V.0 + 2*V.1, 4*V.0 + 2*V.1, 4*V.2])
|
|
1818
|
+
sage: Q = V/W; Q
|
|
1819
|
+
Finitely generated module V/W over Integer Ring with invariants (2, 12)
|
|
1820
|
+
sage: z = list(V/W)
|
|
1821
|
+
sage: z
|
|
1822
|
+
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (0, 10), (0, 11),
|
|
1823
|
+
(1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (1, 11)]
|
|
1824
|
+
sage: len(z)
|
|
1825
|
+
24
|
|
1826
|
+
|
|
1827
|
+
We test that the trivial module is handled correctly (:issue:`6561`)::
|
|
1828
|
+
|
|
1829
|
+
sage: A = (ZZ**1)/(ZZ**1); list(A) == [A(0)]
|
|
1830
|
+
True
|
|
1831
|
+
"""
|
|
1832
|
+
if self.base_ring() != ZZ:
|
|
1833
|
+
raise NotImplementedError("only implemented over ZZ")
|
|
1834
|
+
v = self.invariants()
|
|
1835
|
+
if 0 in v:
|
|
1836
|
+
raise NotImplementedError("currently self must be finite to iterate over")
|
|
1837
|
+
B = self.optimized()[0].V().basis_matrix()
|
|
1838
|
+
V = self.base_ring()**B.nrows()
|
|
1839
|
+
for a in product(*[range(k) for k in v]):
|
|
1840
|
+
b = V(a) * B
|
|
1841
|
+
yield self(b)
|
|
1842
|
+
|
|
1843
|
+
def construction(self):
|
|
1844
|
+
"""
|
|
1845
|
+
The construction functor and ambient module for ``self``.
|
|
1846
|
+
|
|
1847
|
+
EXAMPLES::
|
|
1848
|
+
|
|
1849
|
+
sage: W = ZZ^2
|
|
1850
|
+
sage: A1 = W.submodule([[1,0]])
|
|
1851
|
+
sage: B1 = W.submodule([[2,0]])
|
|
1852
|
+
sage: T1 = A1 / B1
|
|
1853
|
+
sage: T1.construction()
|
|
1854
|
+
(QuotientModuleFunctor,
|
|
1855
|
+
Free module of degree 2 and rank 1 over Integer Ring
|
|
1856
|
+
Echelon basis matrix:
|
|
1857
|
+
[1 0])
|
|
1858
|
+
|
|
1859
|
+
TESTS::
|
|
1860
|
+
|
|
1861
|
+
sage: W = ZZ^2
|
|
1862
|
+
sage: A1 = W.submodule([[1,0]])
|
|
1863
|
+
sage: A2 = W.submodule([[0,1]])
|
|
1864
|
+
sage: B1 = W.submodule([[2,0]])
|
|
1865
|
+
sage: B2 = W.submodule([[0,2]])
|
|
1866
|
+
sage: T1 = A1 / B1
|
|
1867
|
+
sage: T2 = A2 / B2
|
|
1868
|
+
sage: t1 = T1.an_element()
|
|
1869
|
+
sage: t2 = T2.an_element()
|
|
1870
|
+
|
|
1871
|
+
sage: # needs sage.libs.flint (o/w infinite recursion)
|
|
1872
|
+
sage: t1 + t2
|
|
1873
|
+
(1, 1)
|
|
1874
|
+
"""
|
|
1875
|
+
from sage.modules.module_functors import QuotientModuleFunctor
|
|
1876
|
+
return (QuotientModuleFunctor(self._W), self._V)
|
|
1877
|
+
|
|
1878
|
+
def is_finite(self) -> bool:
|
|
1879
|
+
"""
|
|
1880
|
+
Return ``True`` if ``self`` is finite and ``False`` otherwise.
|
|
1881
|
+
|
|
1882
|
+
EXAMPLES::
|
|
1883
|
+
|
|
1884
|
+
sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ)
|
|
1885
|
+
sage: W = V.span([V.0 + 2*V.1, 9*V.0 + 2*V.1, 4*V.2])
|
|
1886
|
+
sage: Q = V/W; Q
|
|
1887
|
+
Finitely generated module V/W over Integer Ring with invariants (4, 16)
|
|
1888
|
+
sage: Q.is_finite()
|
|
1889
|
+
True
|
|
1890
|
+
sage: Q = V / V.zero_submodule(); Q
|
|
1891
|
+
Finitely generated module V/W over Integer Ring with invariants (0, 0, 0)
|
|
1892
|
+
sage: Q.is_finite()
|
|
1893
|
+
False
|
|
1894
|
+
"""
|
|
1895
|
+
return 0 not in self.invariants()
|
|
1896
|
+
|
|
1897
|
+
def annihilator(self):
|
|
1898
|
+
"""
|
|
1899
|
+
Return the ideal of the base ring that annihilates ``self``. This
|
|
1900
|
+
is precisely the ideal generated by the LCM of the invariants
|
|
1901
|
+
of ``self`` if ``self`` is finite, and is 0 otherwise.
|
|
1902
|
+
|
|
1903
|
+
EXAMPLES::
|
|
1904
|
+
|
|
1905
|
+
sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ)
|
|
1906
|
+
sage: W = V.span([V.0 + 2*V.1, 9*V.0 + 2*V.1, 4*V.2])
|
|
1907
|
+
sage: Q = V/W; Q.annihilator()
|
|
1908
|
+
Principal ideal (16) of Integer Ring
|
|
1909
|
+
sage: Q.annihilator().gen()
|
|
1910
|
+
16
|
|
1911
|
+
|
|
1912
|
+
sage: Q = V / V.span([V.0]); Q
|
|
1913
|
+
Finitely generated module V/W over Integer Ring with invariants (0, 0)
|
|
1914
|
+
sage: Q.annihilator()
|
|
1915
|
+
Principal ideal (0) of Integer Ring
|
|
1916
|
+
|
|
1917
|
+
We check that :issue:`22720` is resolved::
|
|
1918
|
+
|
|
1919
|
+
sage: H = AdditiveAbelianGroup([])
|
|
1920
|
+
sage: H.annihilator()
|
|
1921
|
+
Principal ideal (1) of Integer Ring
|
|
1922
|
+
"""
|
|
1923
|
+
if not self.is_finite():
|
|
1924
|
+
g = 0
|
|
1925
|
+
elif self.cardinality() == 1:
|
|
1926
|
+
g = 1
|
|
1927
|
+
else:
|
|
1928
|
+
g = reduce(lcm, self.invariants())
|
|
1929
|
+
return self.base_ring().ideal(g)
|
|
1930
|
+
|
|
1931
|
+
def ngens(self):
|
|
1932
|
+
r"""
|
|
1933
|
+
Return the number of generators of ``self``.
|
|
1934
|
+
|
|
1935
|
+
(Note for developers: This is just the length of :meth:`gens`, rather
|
|
1936
|
+
than of the minimal set of generators as returned by
|
|
1937
|
+
:meth:`.smith_form_gens`; these are the same in the
|
|
1938
|
+
:class:`~sage.modules.fg_pid.fgp_module.FGP_Module_class`, but not
|
|
1939
|
+
necessarily in derived classes.)
|
|
1940
|
+
|
|
1941
|
+
EXAMPLES::
|
|
1942
|
+
|
|
1943
|
+
sage: A = (ZZ**2) / span([[4,0], [0,3]], ZZ)
|
|
1944
|
+
sage: A.ngens()
|
|
1945
|
+
1
|
|
1946
|
+
|
|
1947
|
+
This works (but please do not do it in production code!) ::
|
|
1948
|
+
|
|
1949
|
+
sage: A.gens = lambda: [1,2,"Barcelona!"]
|
|
1950
|
+
sage: A.ngens()
|
|
1951
|
+
3
|
|
1952
|
+
"""
|
|
1953
|
+
return len(self.gens())
|
|
1954
|
+
|
|
1955
|
+
def __hash__(self):
|
|
1956
|
+
r"""
|
|
1957
|
+
Calculate a hash for ``self``.
|
|
1958
|
+
|
|
1959
|
+
EXAMPLES::
|
|
1960
|
+
|
|
1961
|
+
sage: A = (ZZ**2) / span([[4,0], [0,3]], ZZ)
|
|
1962
|
+
sage: hash(A) == hash(((2, ZZ), ((4, 0), (0, 3))))
|
|
1963
|
+
True
|
|
1964
|
+
"""
|
|
1965
|
+
return hash((self.V(), self.W()))
|
|
1966
|
+
|
|
1967
|
+
@cached_method
|
|
1968
|
+
def quotient_map(self):
|
|
1969
|
+
"""
|
|
1970
|
+
Given this quotient space `Q = V / W`, return the natural quotient
|
|
1971
|
+
map from `V` to `Q`.
|
|
1972
|
+
|
|
1973
|
+
EXAMPLES::
|
|
1974
|
+
|
|
1975
|
+
sage: A = (ZZ**2) / span([[4,0],[0,3]], ZZ)
|
|
1976
|
+
sage: A.quotient_map()
|
|
1977
|
+
Coercion map:
|
|
1978
|
+
From: Ambient free module of rank 2 over the principal ideal domain Integer Ring
|
|
1979
|
+
To: Finitely generated module V/W over Integer Ring with invariants (12)
|
|
1980
|
+
"""
|
|
1981
|
+
return self.coerce_map_from(self._V)
|
|
1982
|
+
|
|
1983
|
+
##############################################################
|
|
1984
|
+
# Useful for testing
|
|
1985
|
+
##############################################################
|
|
1986
|
+
|
|
1987
|
+
|
|
1988
|
+
def random_fgp_module(n, R=ZZ, finite=False):
|
|
1989
|
+
"""
|
|
1990
|
+
Return a random FGP module inside a rank n free module over R.
|
|
1991
|
+
|
|
1992
|
+
INPUT:
|
|
1993
|
+
|
|
1994
|
+
- ``n`` -- nonnegative integer
|
|
1995
|
+
|
|
1996
|
+
- ``R`` -- base ring (default: ``ZZ``)
|
|
1997
|
+
|
|
1998
|
+
- ``finite`` -- boolean (default: ``True``); if ``True``, make the random
|
|
1999
|
+
module finite
|
|
2000
|
+
|
|
2001
|
+
EXAMPLES::
|
|
2002
|
+
|
|
2003
|
+
sage: import sage.modules.fg_pid.fgp_module as fgp
|
|
2004
|
+
sage: fgp.random_fgp_module(4)
|
|
2005
|
+
Finitely generated module V/W over Integer Ring with invariants (...)
|
|
2006
|
+
|
|
2007
|
+
In most cases the cardinality is small or infinite::
|
|
2008
|
+
|
|
2009
|
+
sage: for g in (1, 2, 3, +Infinity):
|
|
2010
|
+
....: while fgp.random_fgp_module(4).cardinality() != 1:
|
|
2011
|
+
....: pass
|
|
2012
|
+
|
|
2013
|
+
One can force a finite module::
|
|
2014
|
+
|
|
2015
|
+
sage: fgp.random_fgp_module(4, finite=True).is_finite()
|
|
2016
|
+
True
|
|
2017
|
+
|
|
2018
|
+
Larger finite modules appear::
|
|
2019
|
+
|
|
2020
|
+
sage: while fgp.random_fgp_module(4, finite=True).cardinality() < 100:
|
|
2021
|
+
....: pass
|
|
2022
|
+
"""
|
|
2023
|
+
K = R.fraction_field()
|
|
2024
|
+
V = K**n
|
|
2025
|
+
i = ZZ.random_element(max(n, 1))
|
|
2026
|
+
A = V.span([V.random_element() for _ in range(i)], R)
|
|
2027
|
+
if not finite:
|
|
2028
|
+
i = ZZ.random_element(i+1)
|
|
2029
|
+
while True:
|
|
2030
|
+
B = A.span([A.random_element() for _ in range(i)], R)
|
|
2031
|
+
# Q = A/B
|
|
2032
|
+
Q = FGP_Module_class(A, B, check=DEBUG)
|
|
2033
|
+
if not finite or Q.is_finite():
|
|
2034
|
+
return Q
|
|
2035
|
+
|
|
2036
|
+
|
|
2037
|
+
def random_fgp_morphism_0(*args, **kwds):
|
|
2038
|
+
"""
|
|
2039
|
+
Construct a random fgp module using :func:`random_fgp_module`,
|
|
2040
|
+
then construct a random morphism that sends each generator
|
|
2041
|
+
to a random multiple of itself.
|
|
2042
|
+
|
|
2043
|
+
Inputs are the same as to :func:`random_fgp_module`.
|
|
2044
|
+
|
|
2045
|
+
EXAMPLES::
|
|
2046
|
+
|
|
2047
|
+
sage: import sage.modules.fg_pid.fgp_module as fgp
|
|
2048
|
+
sage: mor = fgp.random_fgp_morphism_0(4)
|
|
2049
|
+
sage: mor.domain() == mor.codomain()
|
|
2050
|
+
True
|
|
2051
|
+
sage: isinstance(mor.domain(), fgp.FGP_Module_class)
|
|
2052
|
+
True
|
|
2053
|
+
|
|
2054
|
+
Each generator is sent to a random multiple of itself::
|
|
2055
|
+
|
|
2056
|
+
sage: gens = mor.domain().gens()
|
|
2057
|
+
sage: im_gens = mor.im_gens()
|
|
2058
|
+
sage: all(im_gens[i] == sum(im_gens[i])*gens[i] for i in range(len(gens)))
|
|
2059
|
+
True
|
|
2060
|
+
"""
|
|
2061
|
+
A = random_fgp_module(*args, **kwds)
|
|
2062
|
+
return A.hom([ZZ.random_element() * g for g in A.smith_form_gens()])
|
|
2063
|
+
|
|
2064
|
+
|
|
2065
|
+
def _test_morphism_0(*args, **kwds):
|
|
2066
|
+
"""
|
|
2067
|
+
EXAMPLES::
|
|
2068
|
+
|
|
2069
|
+
sage: import sage.modules.fg_pid.fgp_module as fgp
|
|
2070
|
+
sage: s = 0 # we set a seed so results clearly and easily reproducible across runs.
|
|
2071
|
+
sage: set_random_seed(s); v = [fgp._test_morphism_0(1) for _ in range(30)]
|
|
2072
|
+
sage: set_random_seed(s); v = [fgp._test_morphism_0(2) for _ in range(30)]
|
|
2073
|
+
sage: set_random_seed(s); v = [fgp._test_morphism_0(3) for _ in range(10)]
|
|
2074
|
+
|
|
2075
|
+
sage: # needs sage.libs.flint (o/w timeout)
|
|
2076
|
+
sage: set_random_seed(s); v = [fgp._test_morphism_0(i) for i in range(1,20)]
|
|
2077
|
+
sage: set_random_seed(s); v = [fgp._test_morphism_0(4) for _ in range(50)] # long time
|
|
2078
|
+
"""
|
|
2079
|
+
phi = random_fgp_morphism_0(*args, **kwds)
|
|
2080
|
+
K = phi.kernel()
|
|
2081
|
+
I = phi.image()
|
|
2082
|
+
from sage.misc.misc_c import prod
|
|
2083
|
+
if prod(K.invariants()):
|
|
2084
|
+
assert prod(phi.domain().invariants()) % prod(K.invariants()) == 0
|
|
2085
|
+
assert I.is_submodule(phi.codomain())
|
|
2086
|
+
if len(I.smith_form_gens()) > 0:
|
|
2087
|
+
x = phi.lift(I.smith_form_gen(0))
|
|
2088
|
+
assert phi(x) == I.smith_form_gen(0)
|
|
2089
|
+
|
|
2090
|
+
|
|
2091
|
+
test_morphism_0 = deprecated_function_alias(33617, _test_morphism_0)
|