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,3067 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-modules
|
|
2
|
+
# sage.doctest: needs sage.modules sage.rings.finite_rings
|
|
3
|
+
r"""
|
|
4
|
+
Generic structures for linear codes over the Hamming metric
|
|
5
|
+
|
|
6
|
+
Linear Codes
|
|
7
|
+
============
|
|
8
|
+
|
|
9
|
+
Let `F = \GF{q}` be a finite field. A rank `k` linear subspace of the vector
|
|
10
|
+
space `F^n` is called an `[n, k]`-linear code, `n` being the length of the code
|
|
11
|
+
and `k` its dimension. Elements of a code `C` are called codewords.
|
|
12
|
+
|
|
13
|
+
A linear map from `F^k` to an `[n,k]` code `C` is called an "encoding", and it
|
|
14
|
+
can be represented as a `k \times n` matrix, called a generator matrix.
|
|
15
|
+
Alternatively, `C` can be represented by its orthogonal complement in `F^n`,
|
|
16
|
+
i.e. the `(n-k)`-dimensional vector space `C^\perp` such that the inner product
|
|
17
|
+
of any element from `C` and any element from `C^\perp` is zero. `C^\perp` is
|
|
18
|
+
called the dual code of `C`, and any generator matrix for `C^\perp` is called a
|
|
19
|
+
parity check matrix for `C`.
|
|
20
|
+
|
|
21
|
+
We commonly endow `F^n` with the Hamming metric, i.e. the weight of a vector is
|
|
22
|
+
the number of nonzero elements in it. The central operation of a linear code
|
|
23
|
+
is then "decoding": given a linear code `C \subset F^n` and a "received word"
|
|
24
|
+
`r \in F^n` , retrieve the codeword `c \in C` such that the Hamming distance
|
|
25
|
+
between `r` and `c` is minimal.
|
|
26
|
+
|
|
27
|
+
Families or Generic codes
|
|
28
|
+
=========================
|
|
29
|
+
|
|
30
|
+
Linear codes are either studied as generic vector spaces without any known
|
|
31
|
+
structure, or as particular sub-families with special properties.
|
|
32
|
+
|
|
33
|
+
The class :class:`sage.coding.linear_code.LinearCode` is used to represent the
|
|
34
|
+
former.
|
|
35
|
+
|
|
36
|
+
For the latter, these will be represented by specialised classes; for instance,
|
|
37
|
+
the family of Hamming codes are represented by the class
|
|
38
|
+
:class:`sage.coding.hamming_code.HammingCode`. Type ``codes.<tab>`` for a list
|
|
39
|
+
of all code families known to Sage. Such code family classes should inherit from
|
|
40
|
+
the abstract base class :class:`sage.coding.linear_code.AbstractLinearCode`.
|
|
41
|
+
|
|
42
|
+
``AbstractLinearCode``
|
|
43
|
+
----------------------
|
|
44
|
+
|
|
45
|
+
This is a base class designed to contain methods, features and parameters
|
|
46
|
+
shared by every linear code. For instance, generic algorithms for computing the
|
|
47
|
+
minimum distance, the covering radius, etc. Many of these algorithms are slow,
|
|
48
|
+
e.g. exponential in the code length. For specific subfamilies, better algorithms
|
|
49
|
+
or even closed formulas might be known, in which case the respective method
|
|
50
|
+
should be overridden.
|
|
51
|
+
|
|
52
|
+
``AbstractLinearCode`` is an abstract class for linear codes, so any linear code
|
|
53
|
+
class should inherit from this class. Also ``AbstractLinearCode`` should never
|
|
54
|
+
itself be instantiated.
|
|
55
|
+
|
|
56
|
+
See :class:`sage.coding.linear_code.AbstractLinearCode` for details and
|
|
57
|
+
examples.
|
|
58
|
+
|
|
59
|
+
``LinearCode``
|
|
60
|
+
--------------
|
|
61
|
+
|
|
62
|
+
This class is used to represent arbitrary and unstructured linear codes. It
|
|
63
|
+
mostly rely directly on generic methods provided by ``AbstractLinearCode``,
|
|
64
|
+
which means that basic operations on the code (e.g. computation of the minimum
|
|
65
|
+
distance) will use slow algorithms.
|
|
66
|
+
|
|
67
|
+
A ``LinearCode`` is instantiated by providing a generator matrix::
|
|
68
|
+
|
|
69
|
+
sage: M = matrix(GF(2), [[1, 0, 0, 1, 0],\
|
|
70
|
+
....: [0, 1, 0, 1, 1],\
|
|
71
|
+
....: [0, 0, 1, 1, 1]])
|
|
72
|
+
sage: C = codes.LinearCode(M)
|
|
73
|
+
sage: C
|
|
74
|
+
[5, 3] linear code over GF(2)
|
|
75
|
+
sage: C.generator_matrix()
|
|
76
|
+
[1 0 0 1 0]
|
|
77
|
+
[0 1 0 1 1]
|
|
78
|
+
[0 0 1 1 1]
|
|
79
|
+
|
|
80
|
+
sage: MS = MatrixSpace(GF(2),4,7)
|
|
81
|
+
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
82
|
+
sage: C = LinearCode(G)
|
|
83
|
+
sage: C.basis()
|
|
84
|
+
[(1, 1, 1, 0, 0, 0, 0),
|
|
85
|
+
(1, 0, 0, 1, 1, 0, 0),
|
|
86
|
+
(0, 1, 0, 1, 0, 1, 0),
|
|
87
|
+
(1, 1, 0, 1, 0, 0, 1)]
|
|
88
|
+
sage: c = C.basis()[1]
|
|
89
|
+
sage: c in C
|
|
90
|
+
True
|
|
91
|
+
sage: c.nonzero_positions()
|
|
92
|
+
[0, 3, 4]
|
|
93
|
+
sage: c.support()
|
|
94
|
+
[0, 3, 4]
|
|
95
|
+
sage: c.parent()
|
|
96
|
+
Vector space of dimension 7 over Finite Field of size 2
|
|
97
|
+
|
|
98
|
+
Further references
|
|
99
|
+
------------------
|
|
100
|
+
|
|
101
|
+
If you want to get started on Sage's linear codes library, see
|
|
102
|
+
https://passagemath.org/docs/latest/html/en/thematic_tutorials/coding_theory.html
|
|
103
|
+
|
|
104
|
+
If you want to learn more on the design of this library, see
|
|
105
|
+
https://passagemath.org/docs/latest/html/en/thematic_tutorials/structures_in_coding_theory.html
|
|
106
|
+
|
|
107
|
+
REFERENCES:
|
|
108
|
+
|
|
109
|
+
- [HP2003]_
|
|
110
|
+
|
|
111
|
+
- [Gu]_
|
|
112
|
+
|
|
113
|
+
AUTHORS:
|
|
114
|
+
|
|
115
|
+
- David Joyner (2005-11-22, 2006-12-03): initial version
|
|
116
|
+
|
|
117
|
+
- William Stein (2006-01-23): Inclusion in Sage
|
|
118
|
+
|
|
119
|
+
- David Joyner (2006-01-30, 2006-04): small fixes
|
|
120
|
+
|
|
121
|
+
- David Joyner (2006-07): added documentation, group-theoretical methods,
|
|
122
|
+
ToricCode
|
|
123
|
+
|
|
124
|
+
- David Joyner (2006-08): hopeful latex fixes to documentation, added list and
|
|
125
|
+
__iter__ methods to LinearCode and examples, added hamming_weight function,
|
|
126
|
+
fixed random method to return a vector, TrivialCode, fixed subtle bug in
|
|
127
|
+
dual_code, added galois_closure method, fixed mysterious bug in
|
|
128
|
+
permutation_automorphism_group (GAP was over-using "G" somehow?)
|
|
129
|
+
|
|
130
|
+
- David Joyner (2006-08): hopeful latex fixes to documentation, added
|
|
131
|
+
CyclicCode, best_known_linear_code, bounds_minimum_distance,
|
|
132
|
+
assmus_mattson_designs (implementing Assmus-Mattson Theorem).
|
|
133
|
+
|
|
134
|
+
- David Joyner (2006-09): modified decode syntax, fixed bug in
|
|
135
|
+
is_galois_closed, added LinearCode_from_vectorspace, extended_code,
|
|
136
|
+
zeta_function
|
|
137
|
+
|
|
138
|
+
- Nick Alexander (2006-12-10): factor GUAVA code to guava.py
|
|
139
|
+
|
|
140
|
+
- David Joyner (2007-05): added methods punctured, shortened, divisor,
|
|
141
|
+
characteristic_polynomial, binomial_moment, support for
|
|
142
|
+
LinearCode. Completely rewritten zeta_function (old version is now
|
|
143
|
+
zeta_function2) and a new function, LinearCodeFromVectorSpace.
|
|
144
|
+
|
|
145
|
+
- David Joyner (2007-11): added zeta_polynomial, weight_enumerator,
|
|
146
|
+
chinen_polynomial; improved best_known_code; made some pythonic revisions;
|
|
147
|
+
added is_equivalent (for binary codes)
|
|
148
|
+
|
|
149
|
+
- David Joyner (2008-01): fixed bug in decode reported by Harald Schilly,
|
|
150
|
+
(with Mike Hansen) added some doctests.
|
|
151
|
+
|
|
152
|
+
- David Joyner (2008-02): translated standard_form, dual_code to Python.
|
|
153
|
+
|
|
154
|
+
- David Joyner (2008-03): translated punctured, shortened, extended_code,
|
|
155
|
+
random (and renamed random to random_element), deleted zeta_function2,
|
|
156
|
+
zeta_function3, added wrapper automorphism_group_binary_code to Robert
|
|
157
|
+
Miller's code), added direct_sum_code, is_subcode, is_self_dual,
|
|
158
|
+
is_self_orthogonal, redundancy_matrix, did some alphabetical reorganizing
|
|
159
|
+
to make the file more readable. Fixed a bug in permutation_automorphism_group
|
|
160
|
+
which caused it to crash.
|
|
161
|
+
|
|
162
|
+
- David Joyner (2008-03): fixed bugs in spectrum and zeta_polynomial, which
|
|
163
|
+
misbehaved over non-prime base rings.
|
|
164
|
+
|
|
165
|
+
- David Joyner (2008-10): use CJ Tjhal's MinimumWeight if char = 2 or 3 for
|
|
166
|
+
min_dist; add is_permutation_equivalent and improve
|
|
167
|
+
permutation_automorphism_group using an interface with Robert Miller's code;
|
|
168
|
+
added interface with Leon's code for the spectrum method.
|
|
169
|
+
|
|
170
|
+
- David Joyner (2009-02): added native decoding methods (see module_decoder.py)
|
|
171
|
+
|
|
172
|
+
- David Joyner (2009-05): removed dependence on Guava, allowing it to be an
|
|
173
|
+
option. Fixed errors in some docstrings.
|
|
174
|
+
|
|
175
|
+
- Kwankyu Lee (2010-01): added methods generator_matrix_systematic,
|
|
176
|
+
information_set, and magma interface for linear codes.
|
|
177
|
+
|
|
178
|
+
- Niles Johnson (2010-08): :issue:`3893`: ``random_element()`` should pass on
|
|
179
|
+
``*args`` and ``**kwds``.
|
|
180
|
+
|
|
181
|
+
- Thomas Feulner (2012-11): :issue:`13723`: deprecation of ``hamming_weight()``
|
|
182
|
+
|
|
183
|
+
- Thomas Feulner (2013-10): added methods to compute a canonical representative
|
|
184
|
+
and the automorphism group
|
|
185
|
+
|
|
186
|
+
TESTS::
|
|
187
|
+
|
|
188
|
+
sage: MS = MatrixSpace(GF(2),4,7)
|
|
189
|
+
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
190
|
+
sage: C = LinearCode(G)
|
|
191
|
+
sage: C == loads(dumps(C))
|
|
192
|
+
True
|
|
193
|
+
"""
|
|
194
|
+
# *****************************************************************************
|
|
195
|
+
# Copyright (C) 2005 David Joyner <wdjoyner@gmail.com>
|
|
196
|
+
# 2006 William Stein <wstein@gmail.com>
|
|
197
|
+
#
|
|
198
|
+
# Distributed under the terms of the GNU General Public License (GPL),
|
|
199
|
+
# version 2 or later (at your preference).
|
|
200
|
+
#
|
|
201
|
+
# https://www.gnu.org/licenses/
|
|
202
|
+
# *****************************************************************************
|
|
203
|
+
|
|
204
|
+
import os
|
|
205
|
+
import subprocess
|
|
206
|
+
|
|
207
|
+
from copy import copy
|
|
208
|
+
from io import StringIO
|
|
209
|
+
|
|
210
|
+
from sage.arith.misc import binomial, GCD
|
|
211
|
+
from sage.categories.cartesian_product import cartesian_product
|
|
212
|
+
from sage.categories.fields import Fields
|
|
213
|
+
from sage.coding.decoder import Decoder
|
|
214
|
+
from sage.coding.encoder import Encoder
|
|
215
|
+
from sage.coding.linear_code_no_metric import AbstractLinearCodeNoMetric
|
|
216
|
+
from sage.combinat.subset import Subsets
|
|
217
|
+
from sage.cpython.string import bytes_to_str
|
|
218
|
+
from sage.features.gap import GapPackage
|
|
219
|
+
from sage.matrix.matrix_space import MatrixSpace
|
|
220
|
+
from sage.misc.cachefunc import cached_method
|
|
221
|
+
from sage.misc.functional import is_even
|
|
222
|
+
from sage.misc.lazy_import import lazy_import
|
|
223
|
+
from sage.misc.misc_c import prod
|
|
224
|
+
from sage.misc.randstate import current_randstate
|
|
225
|
+
from sage.modules.free_module import VectorSpace
|
|
226
|
+
from sage.modules.free_module_element import vector
|
|
227
|
+
from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
|
|
228
|
+
from sage.rings.integer import Integer
|
|
229
|
+
from sage.rings.integer_ring import ZZ
|
|
230
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
231
|
+
from sage.rings.rational_field import QQ
|
|
232
|
+
|
|
233
|
+
lazy_import('sage.groups.perm_gps.permgroup_named', 'SymmetricGroup')
|
|
234
|
+
lazy_import('sage.groups.perm_gps.permgroup', 'PermutationGroup')
|
|
235
|
+
lazy_import('sage.interfaces.gap', 'gap')
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# *****************************************************************************
|
|
239
|
+
# coding theory functions
|
|
240
|
+
# *****************************************************************************
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _dump_code_in_leon_format(C):
|
|
244
|
+
r"""
|
|
245
|
+
Writes a file in Sage's temp directory representing the code C, returning
|
|
246
|
+
the absolute path to the file.
|
|
247
|
+
|
|
248
|
+
This is the Sage translation of the GuavaToLeon command in Guava's
|
|
249
|
+
codefun.gi file.
|
|
250
|
+
|
|
251
|
+
INPUT:
|
|
252
|
+
|
|
253
|
+
- ``C`` -- a linear code (over GF(p), p < 11)
|
|
254
|
+
|
|
255
|
+
OUTPUT: absolute path to the file written
|
|
256
|
+
|
|
257
|
+
EXAMPLES::
|
|
258
|
+
|
|
259
|
+
sage: C = codes.HammingCode(GF(2), 3); C
|
|
260
|
+
[7, 4] Hamming Code over GF(2)
|
|
261
|
+
sage: file_loc = sage.coding.linear_code._dump_code_in_leon_format(C)
|
|
262
|
+
sage: f = open(file_loc); print(f.read())
|
|
263
|
+
LIBRARY code;
|
|
264
|
+
code=seq(2,4,7,seq(
|
|
265
|
+
1,0,0,0,0,1,1,
|
|
266
|
+
0,1,0,0,1,0,1,
|
|
267
|
+
0,0,1,0,1,1,0,
|
|
268
|
+
0,0,0,1,1,1,1
|
|
269
|
+
));
|
|
270
|
+
FINISH;
|
|
271
|
+
sage: f.close()
|
|
272
|
+
"""
|
|
273
|
+
from sage.misc.temporary_file import tmp_filename
|
|
274
|
+
F = C.base_ring()
|
|
275
|
+
p = F.order() # must be prime and <11
|
|
276
|
+
s = "LIBRARY code;\n" + "code=seq(%s,%s,%s,seq(\n" % (p, C.dimension(), C.length())
|
|
277
|
+
Gr = [str(r)[1:-1].replace(" ", "") for r in C.generator_matrix().rows()]
|
|
278
|
+
s += ",\n".join(Gr) + "\n));\nFINISH;"
|
|
279
|
+
file_loc = tmp_filename()
|
|
280
|
+
f = open(file_loc, "w")
|
|
281
|
+
f.write(s)
|
|
282
|
+
f.close()
|
|
283
|
+
|
|
284
|
+
return file_loc
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class AbstractLinearCode(AbstractLinearCodeNoMetric):
|
|
288
|
+
"""
|
|
289
|
+
Abstract base class for linear codes.
|
|
290
|
+
|
|
291
|
+
This class contains all methods that can be used on Linear Codes and on
|
|
292
|
+
Linear Codes families. So, every Linear Code-related class should inherit
|
|
293
|
+
from this abstract class.
|
|
294
|
+
|
|
295
|
+
To implement a linear code, you need to:
|
|
296
|
+
|
|
297
|
+
- inherit from :class:`AbstractLinearCode`
|
|
298
|
+
|
|
299
|
+
- call :class:`AbstractLinearCode` ``__init__`` method in the subclass constructor. Example:
|
|
300
|
+
``super().__init__(base_field, length, "EncoderName", "DecoderName")``.
|
|
301
|
+
By doing that, your subclass will have its ``length`` parameter
|
|
302
|
+
initialized and will be properly set as a member of the category framework.
|
|
303
|
+
You need of course to complete the constructor by adding any additional parameter
|
|
304
|
+
needed to describe properly the code defined in the subclass.
|
|
305
|
+
|
|
306
|
+
- Add the following two lines on the class level::
|
|
307
|
+
|
|
308
|
+
_registered_encoders = {}
|
|
309
|
+
_registered_decoders = {}
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
- fill the dictionary of its encoders in ``sage.coding.__init__.py`` file. Example:
|
|
313
|
+
I want to link the encoder ``MyEncoderClass`` to ``MyNewCodeClass``
|
|
314
|
+
under the name ``MyEncoderName``.
|
|
315
|
+
All I need to do is to write this line in the ``__init__.py`` file:
|
|
316
|
+
``MyNewCodeClass._registered_encoders["NameOfMyEncoder"] = MyEncoderClass`` and all instances of
|
|
317
|
+
``MyNewCodeClass`` will be able to use instances of ``MyEncoderClass``.
|
|
318
|
+
|
|
319
|
+
- fill the dictionary of its decoders in ``sage.coding.__init__`` file. Example:
|
|
320
|
+
I want to link the encoder ``MyDecoderClass`` to ``MyNewCodeClass``
|
|
321
|
+
under the name ``MyDecoderName``.
|
|
322
|
+
All I need to do is to write this line in the ``__init__.py`` file:
|
|
323
|
+
``MyNewCodeClass._registered_decoders["NameOfMyDecoder"] = MyDecoderClass`` and all instances of
|
|
324
|
+
``MyNewCodeClass`` will be able to use instances of ``MyDecoderClass``.
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
As the class :class:`AbstractLinearCode` is not designed to be instantiated, it does not have any representation
|
|
328
|
+
methods. You should implement ``_repr_`` and ``_latex_`` methods in the subclass.
|
|
329
|
+
|
|
330
|
+
.. NOTE::
|
|
331
|
+
|
|
332
|
+
:class:`AbstractLinearCode` has a generic implementation of the
|
|
333
|
+
method ``__eq__`` which uses the generator matrix and is quite
|
|
334
|
+
slow. In subclasses you are encouraged to override ``__eq__``
|
|
335
|
+
and ``__hash__``.
|
|
336
|
+
|
|
337
|
+
.. WARNING::
|
|
338
|
+
|
|
339
|
+
The default encoder should always have `F^{k}` as message space, with `k` the dimension
|
|
340
|
+
of the code and `F` is the base ring of the code.
|
|
341
|
+
|
|
342
|
+
A lot of methods of the abstract class rely on the knowledge of a generator matrix.
|
|
343
|
+
It is thus strongly recommended to set an encoder with a generator matrix implemented
|
|
344
|
+
as a default encoder.
|
|
345
|
+
"""
|
|
346
|
+
_registered_encoders = {}
|
|
347
|
+
_registered_decoders = {}
|
|
348
|
+
|
|
349
|
+
def __init__(self, base_field, length, default_encoder_name, default_decoder_name):
|
|
350
|
+
"""
|
|
351
|
+
Initialize mandatory parameters that any linear code shares.
|
|
352
|
+
|
|
353
|
+
This method only exists for inheritance purposes as it initializes
|
|
354
|
+
parameters that need to be known by every linear code. The class
|
|
355
|
+
:class:`sage.coding.linear_code.AbstractLinearCode` should never be
|
|
356
|
+
directly instantiated.
|
|
357
|
+
|
|
358
|
+
INPUT:
|
|
359
|
+
|
|
360
|
+
- ``base_field`` -- the base field of ``self``
|
|
361
|
+
|
|
362
|
+
- ``length`` -- the length of ``self`` (a Python int or a Sage Integer, must be > 0)
|
|
363
|
+
|
|
364
|
+
- ``default_encoder_name`` -- the name of the default encoder of ``self``
|
|
365
|
+
|
|
366
|
+
- ``default_decoder_name`` -- the name of the default decoder of ``self``
|
|
367
|
+
|
|
368
|
+
EXAMPLES:
|
|
369
|
+
|
|
370
|
+
The following example demonstrates how to subclass `AbstractLinearCode`
|
|
371
|
+
for representing a new family of codes. The example family is non-sensical::
|
|
372
|
+
|
|
373
|
+
sage: class MyCodeFamily(sage.coding.linear_code.AbstractLinearCode):
|
|
374
|
+
....: def __init__(self, field, length, dimension, generator_matrix):
|
|
375
|
+
....: super().__init__(field, length,
|
|
376
|
+
....: "GeneratorMatrix", "Syndrome")
|
|
377
|
+
....: self._dimension = dimension
|
|
378
|
+
....: self._generator_matrix = generator_matrix
|
|
379
|
+
....: def generator_matrix(self):
|
|
380
|
+
....: return self._generator_matrix
|
|
381
|
+
....: def _repr_(self):
|
|
382
|
+
....: return "[%d, %d] dummy code over GF(%s)" % (self.length(), self.dimension(), self.base_field().cardinality())
|
|
383
|
+
|
|
384
|
+
We now instantiate a member of our newly made code family::
|
|
385
|
+
|
|
386
|
+
sage: generator_matrix = matrix(GF(17), 5, 10,
|
|
387
|
+
....: {(i,i):1 for i in range(5)})
|
|
388
|
+
sage: C = MyCodeFamily(GF(17), 10, 5, generator_matrix)
|
|
389
|
+
|
|
390
|
+
We can check its existence and parameters::
|
|
391
|
+
|
|
392
|
+
sage: C
|
|
393
|
+
[10, 5] dummy code over GF(17)
|
|
394
|
+
|
|
395
|
+
We can check that it is truly a part of the framework category::
|
|
396
|
+
|
|
397
|
+
sage: C.parent()
|
|
398
|
+
<class '__main__.MyCodeFamily_with_category'>
|
|
399
|
+
sage: C.category()
|
|
400
|
+
Category of facade finite dimensional vector spaces with basis over Finite Field of size 17
|
|
401
|
+
|
|
402
|
+
And any method that works on linear codes works for our new dummy code::
|
|
403
|
+
|
|
404
|
+
sage: C.minimum_distance() # needs sage.libs.gap
|
|
405
|
+
1
|
|
406
|
+
sage: C.is_self_orthogonal()
|
|
407
|
+
False
|
|
408
|
+
sage: print(C.divisor()) #long time
|
|
409
|
+
1
|
|
410
|
+
"""
|
|
411
|
+
from sage.coding.information_set_decoder import LinearCodeInformationSetDecoder
|
|
412
|
+
|
|
413
|
+
# Add here any generic encoder or decoder. This allows any class which
|
|
414
|
+
# inherits from AbstractLinearCode to use generic decoders/encoders
|
|
415
|
+
self._registered_decoders['Syndrome'] = LinearCodeSyndromeDecoder
|
|
416
|
+
self._registered_decoders['NearestNeighbor'] = LinearCodeNearestNeighborDecoder
|
|
417
|
+
self._registered_decoders['InformationSet'] = LinearCodeInformationSetDecoder
|
|
418
|
+
|
|
419
|
+
self._generic_constructor = LinearCode
|
|
420
|
+
super().__init__(base_field, length, default_encoder_name,
|
|
421
|
+
default_decoder_name)
|
|
422
|
+
|
|
423
|
+
def _an_element_(self):
|
|
424
|
+
r"""
|
|
425
|
+
Return an element of the linear code. Currently, it simply returns
|
|
426
|
+
the first row of the generator matrix.
|
|
427
|
+
|
|
428
|
+
EXAMPLES::
|
|
429
|
+
|
|
430
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
431
|
+
sage: C.an_element()
|
|
432
|
+
(1, 0, 0, 0, 0, 1, 1)
|
|
433
|
+
sage: C2 = C.cartesian_product(C)
|
|
434
|
+
sage: C2.an_element()
|
|
435
|
+
((1, 0, 0, 0, 0, 1, 1), (1, 0, 0, 0, 0, 1, 1))
|
|
436
|
+
"""
|
|
437
|
+
return self.gens()[0]
|
|
438
|
+
|
|
439
|
+
def automorphism_group_gens(self, equivalence='semilinear'):
|
|
440
|
+
r"""
|
|
441
|
+
Return generators of the automorphism group of ``self``.
|
|
442
|
+
|
|
443
|
+
INPUT:
|
|
444
|
+
|
|
445
|
+
- ``equivalence`` -- (optional) defines the acting group, either
|
|
446
|
+
|
|
447
|
+
* ``'permutational'``
|
|
448
|
+
|
|
449
|
+
* ``'linear'``
|
|
450
|
+
|
|
451
|
+
* ``'semilinear'``
|
|
452
|
+
|
|
453
|
+
OUTPUT:
|
|
454
|
+
|
|
455
|
+
- generators of the automorphism group of ``self``
|
|
456
|
+
- the order of the automorphism group of ``self``
|
|
457
|
+
|
|
458
|
+
EXAMPLES:
|
|
459
|
+
|
|
460
|
+
Note, this result can depend on the PRNG state in libgap in a way that
|
|
461
|
+
depends on which packages are loaded, so we must re-seed GAP to ensure
|
|
462
|
+
a consistent result for this example::
|
|
463
|
+
|
|
464
|
+
sage: # needs sage.libs.gap
|
|
465
|
+
sage: libgap.set_seed(0)
|
|
466
|
+
0
|
|
467
|
+
sage: C = codes.HammingCode(GF(4, 'z'), 3)
|
|
468
|
+
sage: C.automorphism_group_gens()
|
|
469
|
+
([((1, 1, 1, z, z + 1, 1, 1, 1, 1, z + 1, z, z, z + 1, z + 1,
|
|
470
|
+
z + 1, 1, z + 1, z, z, 1, z);
|
|
471
|
+
(1,13,14,20)(2,21,8,18,7,16,19,15)(3,10,5,12,17,9,6,4),
|
|
472
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
473
|
+
Defn: z |--> z + 1),
|
|
474
|
+
((z, 1, z, z, z, z + 1, z, z, z, z, z, z, z + 1, z, z, z,
|
|
475
|
+
z, z + 1, z, z, z);
|
|
476
|
+
(1,11,5,12,3,19)(2,8)(6,18,13)(7,17,15)(9,10,14,16,20,21),
|
|
477
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
478
|
+
Defn: z |--> z + 1),
|
|
479
|
+
((z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z);
|
|
480
|
+
(),
|
|
481
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
482
|
+
Defn: z |--> z)],
|
|
483
|
+
362880)
|
|
484
|
+
sage: C.automorphism_group_gens(equivalence='linear')
|
|
485
|
+
([((z, 1, z + 1, z + 1, 1, z + 1, z, 1, z + 1, z + 1, 1, z, 1, z + 1,
|
|
486
|
+
z, 1, z, 1, z + 1, 1, 1);
|
|
487
|
+
(1,12,11,10,6,8,9,20,13,21,5,14,3,16,17,19,7,4,2,15,18),
|
|
488
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
489
|
+
Defn: z |--> z),
|
|
490
|
+
((z + 1, z + 1, z + 1, z, 1, 1, z, z, 1, z + 1, z, 1, 1, z, 1, z + 1,
|
|
491
|
+
z, z + 1, z + 1, 1, z);
|
|
492
|
+
(1,3,18,2,17,6,19)(4,15,13,20,7,14,16)(5,11,8,21,12,9,10),
|
|
493
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
494
|
+
Defn: z |--> z),
|
|
495
|
+
((z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1,
|
|
496
|
+
z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1);
|
|
497
|
+
(),
|
|
498
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
499
|
+
Defn: z |--> z)],
|
|
500
|
+
181440)
|
|
501
|
+
sage: C.automorphism_group_gens(equivalence='permutational')
|
|
502
|
+
([((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
|
|
503
|
+
(1,11)(3,10)(4,9)(5,7)(12,21)(14,20)(15,19)(16,17),
|
|
504
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
505
|
+
Defn: z |--> z),
|
|
506
|
+
((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
|
|
507
|
+
(2,18)(3,19)(4,10)(5,16)(8,13)(9,14)(11,21)(15,20),
|
|
508
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
509
|
+
Defn: z |--> z),
|
|
510
|
+
((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
|
|
511
|
+
(1,19)(3,17)(4,21)(5,20)(7,14)(9,12)(10,16)(11,15),
|
|
512
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
513
|
+
Defn: z |--> z),
|
|
514
|
+
((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
|
|
515
|
+
(2,13)(3,14)(4,20)(5,11)(8,18)(9,19)(10,15)(16,21),
|
|
516
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
517
|
+
Defn: z |--> z)],
|
|
518
|
+
64)
|
|
519
|
+
"""
|
|
520
|
+
aut_group_can_label = self._canonize(equivalence)
|
|
521
|
+
return aut_group_can_label.get_autom_gens(), \
|
|
522
|
+
aut_group_can_label.get_autom_order()
|
|
523
|
+
|
|
524
|
+
def assmus_mattson_designs(self, t, mode=None):
|
|
525
|
+
r"""
|
|
526
|
+
Assmus and Mattson Theorem (section 8.4, page 303 of [HP2003]_): Let
|
|
527
|
+
`A_0, A_1, ..., A_n` be the weights of the codewords in a binary
|
|
528
|
+
linear `[n , k, d]` code `C`, and let `A_0^*, A_1^*, ..., A_n^*` be
|
|
529
|
+
the weights of the codewords in its dual `[n, n-k, d^*]` code `C^*`.
|
|
530
|
+
Fix a `t`, `0<t<d`, and let
|
|
531
|
+
|
|
532
|
+
.. MATH::
|
|
533
|
+
|
|
534
|
+
s = |\{ i\ |\ A_i^* \not= 0, 0< i \leq n-t\}|.
|
|
535
|
+
|
|
536
|
+
Assume `s\leq d-t`.
|
|
537
|
+
|
|
538
|
+
1. If `A_i\not= 0` and `d\leq i\leq n`
|
|
539
|
+
then `C_i = \{ c \in C\ |\ wt(c) = i\}` holds a simple t-design.
|
|
540
|
+
|
|
541
|
+
2. If `A_i^*\not= 0` and `d*\leq i\leq n-t` then
|
|
542
|
+
`C_i^* = \{ c \in C^*\ |\ wt(c) = i\}` holds a simple t-design.
|
|
543
|
+
|
|
544
|
+
A block design is a pair `(X,B)`, where `X` is a non-empty finite set
|
|
545
|
+
of `v>0` elements called points, and `B` is a non-empty finite
|
|
546
|
+
multiset of size b whose elements are called blocks, such that each
|
|
547
|
+
block is a non-empty finite multiset of `k` points. `A` design without
|
|
548
|
+
repeated blocks is called a simple block design. If every subset of
|
|
549
|
+
points of size `t` is contained in exactly `\lambda` blocks the block
|
|
550
|
+
design is called a `t-(v,k,\lambda)` design (or simply a `t`-design
|
|
551
|
+
when the parameters are not specified). When `\lambda=1` then the
|
|
552
|
+
block design is called a `S(t,k,v)` Steiner system.
|
|
553
|
+
|
|
554
|
+
In the Assmus and Mattson Theorem (1), `X` is the set `\{1,2,...,n\}`
|
|
555
|
+
of coordinate locations and `B = \{supp(c)\ |\ c \in C_i\}` is the set
|
|
556
|
+
of supports of the codewords of `C` of weight `i`. Therefore, the
|
|
557
|
+
parameters of the `t`-design for `C_i` are
|
|
558
|
+
|
|
559
|
+
::
|
|
560
|
+
|
|
561
|
+
t = given
|
|
562
|
+
v = n
|
|
563
|
+
k = i (k not to be confused with dim(C))
|
|
564
|
+
b = Ai
|
|
565
|
+
lambda = b*binomial(k,t)/binomial(v,t) (by Theorem 8.1.6,
|
|
566
|
+
p 294, in [HP2003]_)
|
|
567
|
+
|
|
568
|
+
Setting the ``mode="verbose"`` option prints out the values of the
|
|
569
|
+
parameters.
|
|
570
|
+
|
|
571
|
+
The first example below means that the binary [24,12,8]-code C has
|
|
572
|
+
the property that the (support of the) codewords of weight 8 (resp.,
|
|
573
|
+
12, 16) form a 5-design. Similarly for its dual code `C^*` (of course
|
|
574
|
+
`C=C^*` in this case, so this info is extraneous). The test fails to
|
|
575
|
+
produce 6-designs (ie, the hypotheses of the theorem fail to hold,
|
|
576
|
+
not that the 6-designs definitely don't exist). The command
|
|
577
|
+
``assmus_mattson_designs(C,5,mode='verbose')`` returns the same value
|
|
578
|
+
but prints out more detailed information.
|
|
579
|
+
|
|
580
|
+
The second example below illustrates the blocks of the 5-(24, 8, 1)
|
|
581
|
+
design (i.e., the S(5,8,24) Steiner system).
|
|
582
|
+
|
|
583
|
+
EXAMPLES::
|
|
584
|
+
|
|
585
|
+
sage: C = codes.GolayCode(GF(2)) # example 1
|
|
586
|
+
sage: C.assmus_mattson_designs(5)
|
|
587
|
+
['weights from C: ', [8, 12, 16, 24],
|
|
588
|
+
'designs from C: ', [[5, (24, 8, 1)], [5, (24, 12, 48)],
|
|
589
|
+
[5, (24, 16, 78)], [5, (24, 24, 1)]],
|
|
590
|
+
'weights from C*: ', [8, 12, 16],
|
|
591
|
+
'designs from C*: ', [[5, (24, 8, 1)], [5, (24, 12, 48)], [5, (24, 16, 78)]]]
|
|
592
|
+
sage: C.assmus_mattson_designs(6)
|
|
593
|
+
0
|
|
594
|
+
sage: X = range(24) # example 2
|
|
595
|
+
sage: blocks = [c.support() # long time
|
|
596
|
+
....: for c in C if c.hamming_weight()==8]; len(blocks)
|
|
597
|
+
759
|
|
598
|
+
"""
|
|
599
|
+
C = self
|
|
600
|
+
ans = []
|
|
601
|
+
G = C.generator_matrix()
|
|
602
|
+
n = len(G.columns())
|
|
603
|
+
Cp = C.dual_code()
|
|
604
|
+
wts = C.weight_distribution()
|
|
605
|
+
d = min([i for i in range(1, len(wts)) if wts[i] != 0])
|
|
606
|
+
if t >= d:
|
|
607
|
+
return 0
|
|
608
|
+
nonzerowts = [i for i in range(len(wts)) if wts[i] != 0 and d <= i <= n]
|
|
609
|
+
if mode == "verbose":
|
|
610
|
+
for w in nonzerowts:
|
|
611
|
+
print("The weight w={} codewords of C* form a t-(v,k,lambda) design, where\n \
|
|
612
|
+
t={}, v={}, k={}, lambda={}. \nThere are {} block of this design.".format(
|
|
613
|
+
w, t, n, w, wts[w] * binomial(w, t) // binomial(n, t), wts[w]))
|
|
614
|
+
wtsp = Cp.weight_distribution()
|
|
615
|
+
dp = min([i for i in range(1, len(wtsp)) if wtsp[i] != 0])
|
|
616
|
+
nonzerowtsp = [i for i in range(len(wtsp)) if wtsp[i] != 0 and i <= n-t and i >= dp]
|
|
617
|
+
s = len([i for i in range(1, n) if wtsp[i] != 0 and 0 < i <= n-t])
|
|
618
|
+
if mode == "verbose":
|
|
619
|
+
for w in nonzerowtsp:
|
|
620
|
+
print("The weight w={} codewords of C* form a t-(v,k,lambda) design, where\n \
|
|
621
|
+
t={}, v={}, k={}, lambda={}. \nThere are {} block of this design.".format(
|
|
622
|
+
w, t, n, w, wts[w] * binomial(w, t) // binomial(n, t), wts[w]))
|
|
623
|
+
if s <= d-t:
|
|
624
|
+
des = [[t, (n, w, wts[w] * binomial(w, t) // binomial(n, t))] for w in nonzerowts]
|
|
625
|
+
ans = ans + ["weights from C: ", nonzerowts, "designs from C: ", des]
|
|
626
|
+
desp = [[t, (n, w, wtsp[w] * binomial(w, t) // binomial(n, t))] for w in nonzerowtsp]
|
|
627
|
+
ans = ans + ["weights from C*: ", nonzerowtsp, "designs from C*: ", desp]
|
|
628
|
+
return ans
|
|
629
|
+
return 0
|
|
630
|
+
|
|
631
|
+
# S. Pancratz, 19 Jan 2010: In the doctests below, I removed the example
|
|
632
|
+
# ``C.binomial_moment(3)``, which was also marked as ``#long``. This way,
|
|
633
|
+
# we shorten the doctests time while still maintaining a zero and a
|
|
634
|
+
# nonzero example.
|
|
635
|
+
def binomial_moment(self, i):
|
|
636
|
+
r"""
|
|
637
|
+
Return the `i`-th binomial moment of the `[n,k,d]_q`-code `C`:
|
|
638
|
+
|
|
639
|
+
.. MATH::
|
|
640
|
+
|
|
641
|
+
B_i(C) = \sum_{S, |S|=i} \frac{q^{k_S}-1}{q-1}
|
|
642
|
+
|
|
643
|
+
where `k_S` is the dimension of the shortened code `C_{J-S}`,
|
|
644
|
+
`J=[1,2,...,n]`. (The normalized binomial moment is
|
|
645
|
+
`b_i(C) = \binom{n}{d+i})^{-1}B_{d+i}(C)`.) In other words, `C_{J-S}`
|
|
646
|
+
is isomorphic to the subcode of C of codewords supported on S.
|
|
647
|
+
|
|
648
|
+
EXAMPLES::
|
|
649
|
+
|
|
650
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
651
|
+
sage: C.binomial_moment(2) # needs sage.libs.gap
|
|
652
|
+
0
|
|
653
|
+
sage: C.binomial_moment(4) # long time # needs sage.libs.gap
|
|
654
|
+
35
|
|
655
|
+
|
|
656
|
+
.. warning::
|
|
657
|
+
|
|
658
|
+
This is slow.
|
|
659
|
+
|
|
660
|
+
REFERENCE:
|
|
661
|
+
|
|
662
|
+
- [Du2004]_
|
|
663
|
+
"""
|
|
664
|
+
n = self.length()
|
|
665
|
+
k = self.dimension()
|
|
666
|
+
d = self.minimum_distance()
|
|
667
|
+
F = self.base_ring()
|
|
668
|
+
q = F.order()
|
|
669
|
+
J = range(1, n+1)
|
|
670
|
+
Cp = self.dual_code()
|
|
671
|
+
dp = Cp.minimum_distance()
|
|
672
|
+
if i < d:
|
|
673
|
+
return 0
|
|
674
|
+
if n - dp < i <= n:
|
|
675
|
+
return binomial(n, i)*(q**(i+k-n) - 1)//(q-1)
|
|
676
|
+
from sage.combinat.set_partition import SetPartitions
|
|
677
|
+
P = SetPartitions(J, 2).list()
|
|
678
|
+
b = QQ(0)
|
|
679
|
+
for p in P:
|
|
680
|
+
p = list(p)
|
|
681
|
+
S = p[0]
|
|
682
|
+
if len(S) == n-i:
|
|
683
|
+
C_S = self.shortened(S)
|
|
684
|
+
k_S = C_S.dimension()
|
|
685
|
+
b = b + (q**(k_S) - 1)//(q-1)
|
|
686
|
+
return b
|
|
687
|
+
|
|
688
|
+
@cached_method
|
|
689
|
+
def _canonize(self, equivalence):
|
|
690
|
+
r"""
|
|
691
|
+
Compute a canonical representative and the automorphism group
|
|
692
|
+
under the action of the semimonomial transformation group.
|
|
693
|
+
|
|
694
|
+
INPUT:
|
|
695
|
+
|
|
696
|
+
- ``equivalence`` -- which defines the acting group, either
|
|
697
|
+
|
|
698
|
+
* ``permutational``
|
|
699
|
+
|
|
700
|
+
* ``linear``
|
|
701
|
+
|
|
702
|
+
* ``semilinear``
|
|
703
|
+
|
|
704
|
+
EXAMPLES:
|
|
705
|
+
|
|
706
|
+
Note, this result can depend on the PRNG state in libgap in a way that
|
|
707
|
+
depends on which packages are loaded, so we must re-seed GAP to ensure
|
|
708
|
+
a consistent result for this example::
|
|
709
|
+
|
|
710
|
+
sage: # needs sage.libs.gap
|
|
711
|
+
sage: libgap.set_seed(0)
|
|
712
|
+
0
|
|
713
|
+
sage: C = codes.HammingCode(GF(4, 'z'), 3)
|
|
714
|
+
sage: aut_group_can_label = C._canonize("semilinear")
|
|
715
|
+
sage: C_iso = LinearCode(aut_group_can_label.get_transporter()*C.generator_matrix())
|
|
716
|
+
sage: C_iso == aut_group_can_label.get_canonical_form()
|
|
717
|
+
True
|
|
718
|
+
sage: aut_group_can_label.get_autom_gens()
|
|
719
|
+
[((1, 1, 1, z, z + 1, 1, 1, 1, 1, z + 1, z, z, z + 1, z + 1, z + 1, 1, z + 1, z, z, 1, z); (1,13,14,20)(2,21,8,18,7,16,19,15)(3,10,5,12,17,9,6,4),
|
|
720
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
721
|
+
Defn: z |--> z + 1),
|
|
722
|
+
((z, 1, z, z, z, z + 1, z, z, z, z, z, z, z + 1, z, z, z, z, z + 1, z, z, z); (1,11,5,12,3,19)(2,8)(6,18,13)(7,17,15)(9,10,14,16,20,21),
|
|
723
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
724
|
+
Defn: z |--> z + 1),
|
|
725
|
+
((z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z); (),
|
|
726
|
+
Ring endomorphism of Finite Field in z of size 2^2
|
|
727
|
+
Defn: z |--> z)]
|
|
728
|
+
"""
|
|
729
|
+
from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
|
|
730
|
+
return LinearCodeAutGroupCanLabel(self, algorithm_type=equivalence)
|
|
731
|
+
|
|
732
|
+
def canonical_representative(self, equivalence='semilinear'):
|
|
733
|
+
r"""
|
|
734
|
+
Compute a canonical orbit representative under the action of the
|
|
735
|
+
semimonomial transformation group.
|
|
736
|
+
|
|
737
|
+
See :mod:`sage.coding.codecan.autgroup_can_label`
|
|
738
|
+
for more details, for example if you would like to compute
|
|
739
|
+
a canonical form under some more restrictive notion of equivalence,
|
|
740
|
+
i.e. if you would like to restrict the permutation group
|
|
741
|
+
to a Young subgroup.
|
|
742
|
+
|
|
743
|
+
INPUT:
|
|
744
|
+
|
|
745
|
+
- ``equivalence`` -- (optional) defines the acting group, either
|
|
746
|
+
|
|
747
|
+
* ``'permutational'``
|
|
748
|
+
|
|
749
|
+
* ``'linear'``
|
|
750
|
+
|
|
751
|
+
* ``'semilinear'``
|
|
752
|
+
|
|
753
|
+
OUTPUT:
|
|
754
|
+
|
|
755
|
+
- a canonical representative of ``self``
|
|
756
|
+
- a semimonomial transformation mapping ``self`` onto its representative
|
|
757
|
+
|
|
758
|
+
EXAMPLES::
|
|
759
|
+
|
|
760
|
+
sage: F.<z> = GF(4)
|
|
761
|
+
sage: C = codes.HammingCode(F, 3)
|
|
762
|
+
sage: CanRep, transp = C.canonical_representative() # needs sage.libs.gap
|
|
763
|
+
|
|
764
|
+
Check that the transporter element is correct::
|
|
765
|
+
|
|
766
|
+
sage: LinearCode(transp*C.generator_matrix()) == CanRep # needs sage.libs.gap
|
|
767
|
+
True
|
|
768
|
+
|
|
769
|
+
Check if an equivalent code has the same canonical representative::
|
|
770
|
+
|
|
771
|
+
sage: f = F.hom([z**2])
|
|
772
|
+
sage: C_iso = LinearCode(C.generator_matrix().apply_map(f))
|
|
773
|
+
sage: CanRep_iso, _ = C_iso.canonical_representative() # needs sage.libs.gap
|
|
774
|
+
sage: CanRep_iso == CanRep # needs sage.libs.gap
|
|
775
|
+
True
|
|
776
|
+
|
|
777
|
+
Since applying the Frobenius automorphism could be extended to an
|
|
778
|
+
automorphism of `C`, the following must also yield ``True``::
|
|
779
|
+
|
|
780
|
+
sage: CanRep1, _ = C.canonical_representative("linear") # needs sage.libs.gap
|
|
781
|
+
sage: CanRep2, _ = C_iso.canonical_representative("linear") # needs sage.libs.gap
|
|
782
|
+
sage: CanRep2 == CanRep1 # needs sage.libs.gap
|
|
783
|
+
True
|
|
784
|
+
|
|
785
|
+
TESTS:
|
|
786
|
+
|
|
787
|
+
Check that interrupting this does not segfault
|
|
788
|
+
(see :issue:`21651`)::
|
|
789
|
+
|
|
790
|
+
sage: C = LinearCode(random_matrix(GF(47), 25, 35))
|
|
791
|
+
sage: from sage.doctest.util import ensure_interruptible_after
|
|
792
|
+
sage: with ensure_interruptible_after(0.5): C.canonical_representative() # needs sage.libs.gap
|
|
793
|
+
"""
|
|
794
|
+
aut_group_can_label = self._canonize(equivalence)
|
|
795
|
+
return aut_group_can_label.get_canonical_form(), \
|
|
796
|
+
aut_group_can_label.get_transporter()
|
|
797
|
+
|
|
798
|
+
def characteristic(self):
|
|
799
|
+
r"""
|
|
800
|
+
Return the characteristic of the base ring of ``self``.
|
|
801
|
+
|
|
802
|
+
EXAMPLES::
|
|
803
|
+
|
|
804
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
805
|
+
sage: C.characteristic()
|
|
806
|
+
2
|
|
807
|
+
"""
|
|
808
|
+
return (self.base_ring()).characteristic()
|
|
809
|
+
|
|
810
|
+
def characteristic_polynomial(self):
|
|
811
|
+
r"""
|
|
812
|
+
Return the characteristic polynomial of a linear code, as defined in
|
|
813
|
+
[Lin1999]_.
|
|
814
|
+
|
|
815
|
+
EXAMPLES::
|
|
816
|
+
|
|
817
|
+
sage: C = codes.GolayCode(GF(2))
|
|
818
|
+
sage: C.characteristic_polynomial()
|
|
819
|
+
-4/3*x^3 + 64*x^2 - 2816/3*x + 4096
|
|
820
|
+
"""
|
|
821
|
+
R = PolynomialRing(QQ,"x")
|
|
822
|
+
x = R.gen()
|
|
823
|
+
C = self
|
|
824
|
+
Cd = C.dual_code()
|
|
825
|
+
Sd = Cd.support()
|
|
826
|
+
k = C.dimension()
|
|
827
|
+
n = C.length()
|
|
828
|
+
q = (C.base_ring()).order()
|
|
829
|
+
return q**(n-k)*prod([1-x/j for j in Sd if j > 0])
|
|
830
|
+
|
|
831
|
+
def chinen_polynomial(self):
|
|
832
|
+
"""
|
|
833
|
+
Return the Chinen zeta polynomial of the code.
|
|
834
|
+
|
|
835
|
+
EXAMPLES::
|
|
836
|
+
|
|
837
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
838
|
+
sage: C.chinen_polynomial() # long time
|
|
839
|
+
1/5*(2*sqrt(2)*t^3 + 2*sqrt(2)*t^2 + 2*t^2 + sqrt(2)*t + 2*t + 1)/(sqrt(2) + 1)
|
|
840
|
+
sage: C = codes.GolayCode(GF(3), False)
|
|
841
|
+
sage: C.chinen_polynomial() # long time
|
|
842
|
+
1/7*(3*sqrt(3)*t^3 + 3*sqrt(3)*t^2 + 3*t^2 + sqrt(3)*t + 3*t + 1)/(sqrt(3) + 1)
|
|
843
|
+
|
|
844
|
+
This last output agrees with the corresponding example given in
|
|
845
|
+
Chinen's paper below.
|
|
846
|
+
|
|
847
|
+
REFERENCES:
|
|
848
|
+
|
|
849
|
+
- Chinen, K. "An abundance of invariant polynomials satisfying the
|
|
850
|
+
Riemann hypothesis", April 2007 preprint.
|
|
851
|
+
"""
|
|
852
|
+
from sage.misc.functional import sqrt
|
|
853
|
+
C = self
|
|
854
|
+
n = C.length()
|
|
855
|
+
RT = PolynomialRing(QQ,2,"Ts")
|
|
856
|
+
T,s = RT.fraction_field().gens()
|
|
857
|
+
t = PolynomialRing(QQ,"t").gen()
|
|
858
|
+
Cd = C.dual_code()
|
|
859
|
+
k = C.dimension()
|
|
860
|
+
q = (C.base_ring()).characteristic()
|
|
861
|
+
d = C.minimum_distance()
|
|
862
|
+
dperp = Cd.minimum_distance()
|
|
863
|
+
if dperp > d:
|
|
864
|
+
P = RT(C.zeta_polynomial())
|
|
865
|
+
# Sage does not find dealing with sqrt(int) *as an algebraic object*
|
|
866
|
+
# an easy thing to do. Some tricky gymnastics are used to
|
|
867
|
+
# make Sage deal with objects over QQ(sqrt(q)) nicely.
|
|
868
|
+
if is_even(n):
|
|
869
|
+
Pd = q**(k-n//2) * RT(Cd.zeta_polynomial()) * T**(dperp - d)
|
|
870
|
+
else:
|
|
871
|
+
Pd = s * q**(k-(n+1)//2) * RT(Cd.zeta_polynomial()) * T**(dperp - d)
|
|
872
|
+
CP = P+Pd
|
|
873
|
+
f = CP/CP(1,s)
|
|
874
|
+
return f(t,sqrt(q))
|
|
875
|
+
if dperp < d:
|
|
876
|
+
P = RT(C.zeta_polynomial())*T**(d - dperp)
|
|
877
|
+
if is_even(n):
|
|
878
|
+
Pd = q**(k-n/2)*RT(Cd.zeta_polynomial())
|
|
879
|
+
if not is_even(n):
|
|
880
|
+
Pd = s*q**(k-(n+1)/2)*RT(Cd.zeta_polynomial())
|
|
881
|
+
CP = P+Pd
|
|
882
|
+
f = CP/CP(1,s)
|
|
883
|
+
return f(t,sqrt(q))
|
|
884
|
+
if dperp == d:
|
|
885
|
+
P = RT(C.zeta_polynomial())
|
|
886
|
+
if is_even(n):
|
|
887
|
+
Pd = q**(k-n/2)*RT(Cd.zeta_polynomial())
|
|
888
|
+
if not is_even(n):
|
|
889
|
+
Pd = s*q**(k-(n+1)/2)*RT(Cd.zeta_polynomial())
|
|
890
|
+
CP = P+Pd
|
|
891
|
+
f = CP/CP(1,s)
|
|
892
|
+
return f(t,sqrt(q))
|
|
893
|
+
|
|
894
|
+
@cached_method
|
|
895
|
+
def covering_radius(self):
|
|
896
|
+
r"""
|
|
897
|
+
Return the minimal integer `r` such that any element in the ambient space of ``self`` has distance at most `r` to a codeword of ``self``.
|
|
898
|
+
|
|
899
|
+
This method requires the optional GAP package Guava.
|
|
900
|
+
|
|
901
|
+
If the covering radius of a code equals its minimum distance, then the code is called perfect.
|
|
902
|
+
|
|
903
|
+
.. NOTE::
|
|
904
|
+
|
|
905
|
+
This method is currently not implemented on codes over base fields
|
|
906
|
+
of cardinality greater than 256 due to limitations in the underlying
|
|
907
|
+
algorithm of GAP.
|
|
908
|
+
|
|
909
|
+
EXAMPLES::
|
|
910
|
+
|
|
911
|
+
sage: C = codes.HammingCode(GF(2), 5)
|
|
912
|
+
sage: C.covering_radius() # optional - gap_package_guava
|
|
913
|
+
...1
|
|
914
|
+
|
|
915
|
+
sage: C = codes.random_linear_code(GF(263), 5, 1)
|
|
916
|
+
sage: C.covering_radius() # optional - gap_package_guava
|
|
917
|
+
Traceback (most recent call last):
|
|
918
|
+
...
|
|
919
|
+
NotImplementedError: the GAP algorithm that Sage is using
|
|
920
|
+
is limited to computing with fields of size at most 256
|
|
921
|
+
"""
|
|
922
|
+
from sage.libs.gap.libgap import libgap
|
|
923
|
+
GapPackage('guava', spkg='gap_packages').require()
|
|
924
|
+
libgap.LoadPackage('guava')
|
|
925
|
+
F = self.base_ring()
|
|
926
|
+
if F.cardinality() > 256:
|
|
927
|
+
raise NotImplementedError("the GAP algorithm that Sage is using "
|
|
928
|
+
"is limited to computing with fields "
|
|
929
|
+
"of size at most 256")
|
|
930
|
+
gapG = libgap(self.generator_matrix())
|
|
931
|
+
C = gapG.GeneratorMatCode(libgap(F))
|
|
932
|
+
r = C.CoveringRadius()
|
|
933
|
+
try:
|
|
934
|
+
return ZZ(r)
|
|
935
|
+
except TypeError:
|
|
936
|
+
raise RuntimeError("the covering radius of this code cannot be computed by Guava")
|
|
937
|
+
|
|
938
|
+
def divisor(self):
|
|
939
|
+
r"""
|
|
940
|
+
Return the greatest common divisor of the weights of the nonzero codewords.
|
|
941
|
+
|
|
942
|
+
EXAMPLES::
|
|
943
|
+
|
|
944
|
+
sage: C = codes.GolayCode(GF(2))
|
|
945
|
+
sage: C.divisor() # Type II self-dual
|
|
946
|
+
4
|
|
947
|
+
sage: C = codes.QuadraticResidueCodeEvenPair(17, GF(2))[0]
|
|
948
|
+
sage: C.divisor()
|
|
949
|
+
2
|
|
950
|
+
"""
|
|
951
|
+
C = self
|
|
952
|
+
A = C.weight_distribution()
|
|
953
|
+
n = C.length()
|
|
954
|
+
V = VectorSpace(QQ,n+1)
|
|
955
|
+
S = V(A).nonzero_positions()
|
|
956
|
+
S0 = [S[i] for i in range(1,len(S))]
|
|
957
|
+
if len(S) > 1:
|
|
958
|
+
return GCD(S0)
|
|
959
|
+
return 1
|
|
960
|
+
|
|
961
|
+
def is_projective(self):
|
|
962
|
+
r"""
|
|
963
|
+
Test whether the code is projective.
|
|
964
|
+
|
|
965
|
+
A linear code `C` over a field is called *projective* when its dual `Cd`
|
|
966
|
+
has minimum weight `\geq 3`, i.e. when no two coordinate positions of
|
|
967
|
+
`C` are linearly independent (cf. definition 3 from [BS2011]_ or 9.8.1 from
|
|
968
|
+
[BH2012]_).
|
|
969
|
+
|
|
970
|
+
EXAMPLES::
|
|
971
|
+
|
|
972
|
+
sage: C = codes.GolayCode(GF(2), False)
|
|
973
|
+
sage: C.is_projective()
|
|
974
|
+
True
|
|
975
|
+
sage: C.dual_code().minimum_distance() # needs sage.libs.gap
|
|
976
|
+
8
|
|
977
|
+
|
|
978
|
+
A non-projective code::
|
|
979
|
+
|
|
980
|
+
sage: C = codes.LinearCode(matrix(GF(2), [[1,0,1],[1,1,1]]))
|
|
981
|
+
sage: C.is_projective()
|
|
982
|
+
False
|
|
983
|
+
"""
|
|
984
|
+
M = self.generator_matrix().transpose()
|
|
985
|
+
|
|
986
|
+
def projectivize(row):
|
|
987
|
+
if not row.is_zero():
|
|
988
|
+
for i in range(len(row)):
|
|
989
|
+
if row[i]:
|
|
990
|
+
break
|
|
991
|
+
row = ~(row[i]) * row
|
|
992
|
+
row.set_immutable()
|
|
993
|
+
return row
|
|
994
|
+
|
|
995
|
+
rows = set()
|
|
996
|
+
for row in M.rows():
|
|
997
|
+
row = projectivize(row)
|
|
998
|
+
if row in rows:
|
|
999
|
+
return False
|
|
1000
|
+
rows.add(row)
|
|
1001
|
+
|
|
1002
|
+
return True
|
|
1003
|
+
|
|
1004
|
+
def direct_sum(self, other):
|
|
1005
|
+
"""
|
|
1006
|
+
Return the direct sum of the codes ``self`` and ``other``.
|
|
1007
|
+
|
|
1008
|
+
This returns the code given by the direct sum of the codes ``self`` and
|
|
1009
|
+
``other``, which must be linear codes defined over the same base ring.
|
|
1010
|
+
|
|
1011
|
+
EXAMPLES::
|
|
1012
|
+
|
|
1013
|
+
sage: C1 = codes.HammingCode(GF(2), 3)
|
|
1014
|
+
sage: C2 = C1.direct_sum(C1); C2
|
|
1015
|
+
[14, 8] linear code over GF(2)
|
|
1016
|
+
sage: C3 = C1.direct_sum(C2); C3
|
|
1017
|
+
[21, 12] linear code over GF(2)
|
|
1018
|
+
"""
|
|
1019
|
+
C1 = self
|
|
1020
|
+
C2 = other
|
|
1021
|
+
G1 = C1.generator_matrix()
|
|
1022
|
+
G2 = C2.generator_matrix()
|
|
1023
|
+
F = C1.base_ring()
|
|
1024
|
+
n1 = len(G1.columns())
|
|
1025
|
+
k1 = len(G1.rows())
|
|
1026
|
+
n2 = len(G2.columns())
|
|
1027
|
+
k2 = len(G2.rows())
|
|
1028
|
+
MS1 = MatrixSpace(F,k2,n1)
|
|
1029
|
+
MS2 = MatrixSpace(F,k1,n2)
|
|
1030
|
+
Z1 = MS1(0)
|
|
1031
|
+
Z2 = MS2(0)
|
|
1032
|
+
top = G1.augment(Z2)
|
|
1033
|
+
bottom = Z1.augment(G2)
|
|
1034
|
+
G = top.stack(bottom)
|
|
1035
|
+
return LinearCode(G)
|
|
1036
|
+
|
|
1037
|
+
def juxtapose(self, other):
|
|
1038
|
+
"""
|
|
1039
|
+
Juxtaposition of ``self`` and ``other``.
|
|
1040
|
+
|
|
1041
|
+
The two codes must have equal dimension.
|
|
1042
|
+
|
|
1043
|
+
EXAMPLES::
|
|
1044
|
+
|
|
1045
|
+
sage: C1 = codes.HammingCode(GF(2), 3)
|
|
1046
|
+
sage: C2 = C1.juxtapose(C1)
|
|
1047
|
+
sage: C2
|
|
1048
|
+
[14, 4] linear code over GF(2)
|
|
1049
|
+
"""
|
|
1050
|
+
G1 = self.generator_matrix()
|
|
1051
|
+
G2 = other.generator_matrix()
|
|
1052
|
+
G = G1.augment(G2)
|
|
1053
|
+
return LinearCode(G)
|
|
1054
|
+
|
|
1055
|
+
def u_u_plus_v_code(self, other):
|
|
1056
|
+
r"""
|
|
1057
|
+
Return the `(u|u+v)`-construction with ``self=u`` and ``other=v``.
|
|
1058
|
+
|
|
1059
|
+
This returns the code obtained through `(u|u+v)`-construction with ``self`` as `u`
|
|
1060
|
+
and ``other`` as `v`. Note that `u` and `v` must have equal lengths.
|
|
1061
|
+
For `u` a `[n, k_1, d_1]`-code and `v` a `[n, k_2, d_2]`-code this returns
|
|
1062
|
+
a `[2n, k_1+k_2, d]`-code, where `d=\min(2d_1,d_2)`.
|
|
1063
|
+
|
|
1064
|
+
EXAMPLES::
|
|
1065
|
+
|
|
1066
|
+
sage: C1 = codes.HammingCode(GF(2), 3)
|
|
1067
|
+
sage: C2 = codes.HammingCode(GF(2), 3)
|
|
1068
|
+
sage: D = C1.u_u_plus_v_code(C2)
|
|
1069
|
+
sage: D
|
|
1070
|
+
[14, 8] linear code over GF(2)
|
|
1071
|
+
"""
|
|
1072
|
+
F = self.base_ring()
|
|
1073
|
+
G1 = self.generator_matrix()
|
|
1074
|
+
G2 = other.generator_matrix()
|
|
1075
|
+
k2 = len(G2.rows())
|
|
1076
|
+
n2 = len(G2.columns())
|
|
1077
|
+
MS = MatrixSpace(F,k2,n2)
|
|
1078
|
+
Z = MS(0)
|
|
1079
|
+
top = G1.augment(G1)
|
|
1080
|
+
bot = Z.augment(G2)
|
|
1081
|
+
G = top.stack(bot)
|
|
1082
|
+
return LinearCode(G)
|
|
1083
|
+
|
|
1084
|
+
def product_code(self, other):
|
|
1085
|
+
"""
|
|
1086
|
+
Combines ``self`` with ``other`` to give the tensor product code.
|
|
1087
|
+
|
|
1088
|
+
If ``self`` is a `[n_1, k_1, d_1]`-code and ``other`` is
|
|
1089
|
+
a `[n_2, k_2, d_2]`-code, the product is a `[n_1n_2, k_1k_2, d_1d_2]`-code.
|
|
1090
|
+
|
|
1091
|
+
Note that the two codes have to be over the same field.
|
|
1092
|
+
|
|
1093
|
+
EXAMPLES::
|
|
1094
|
+
|
|
1095
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
1096
|
+
sage: C
|
|
1097
|
+
[7, 4] Hamming Code over GF(2)
|
|
1098
|
+
sage: D = codes.ReedMullerCode(GF(2), 2, 2)
|
|
1099
|
+
sage: D
|
|
1100
|
+
Binary Reed-Muller Code of order 2 and number of variables 2
|
|
1101
|
+
sage: A = C.product_code(D)
|
|
1102
|
+
sage: A
|
|
1103
|
+
[28, 16] linear code over GF(2)
|
|
1104
|
+
sage: A.length() == C.length()*D.length()
|
|
1105
|
+
True
|
|
1106
|
+
sage: A.dimension() == C.dimension()*D.dimension()
|
|
1107
|
+
True
|
|
1108
|
+
sage: A.minimum_distance() == C.minimum_distance()*D.minimum_distance() # needs sage.libs.gap
|
|
1109
|
+
True
|
|
1110
|
+
"""
|
|
1111
|
+
G1 = self.generator_matrix()
|
|
1112
|
+
G2 = other.generator_matrix()
|
|
1113
|
+
G = G1.tensor_product(G2)
|
|
1114
|
+
return LinearCode(G)
|
|
1115
|
+
|
|
1116
|
+
def construction_x(self, other, aux):
|
|
1117
|
+
r"""
|
|
1118
|
+
Construction X applied to ``self=C_1``, ``other=C_2`` and ``aux=C_a``.
|
|
1119
|
+
|
|
1120
|
+
``other`` must be a subcode of ``self``.
|
|
1121
|
+
|
|
1122
|
+
If `C_1` is a `[n, k_1, d_1]` linear code and `C_2` is
|
|
1123
|
+
a `[n, k_2, d_2]` linear code, then `k_1 > k_2` and `d_1 < d_2`. `C_a` must
|
|
1124
|
+
be a `[n_a, k_a, d_a]` linear code, such that `k_a + k_2 = k_1`
|
|
1125
|
+
and `d_a + d_1 \leq d_2`.
|
|
1126
|
+
|
|
1127
|
+
The method will then return a `[n+n_a, k_1, d_a+d_1]` linear code.
|
|
1128
|
+
|
|
1129
|
+
EXAMPLES::
|
|
1130
|
+
|
|
1131
|
+
sage: C = codes.BCHCode(GF(2),15,7)
|
|
1132
|
+
sage: C
|
|
1133
|
+
[15, 5] BCH Code over GF(2) with designed distance 7
|
|
1134
|
+
sage: D = codes.BCHCode(GF(2),15,5)
|
|
1135
|
+
sage: D
|
|
1136
|
+
[15, 7] BCH Code over GF(2) with designed distance 5
|
|
1137
|
+
sage: C.is_subcode(D)
|
|
1138
|
+
True
|
|
1139
|
+
|
|
1140
|
+
sage: # needs sage.libs.gap
|
|
1141
|
+
sage: C.minimum_distance()
|
|
1142
|
+
7
|
|
1143
|
+
sage: D.minimum_distance()
|
|
1144
|
+
5
|
|
1145
|
+
sage: aux = codes.HammingCode(GF(2),2)
|
|
1146
|
+
sage: aux = aux.dual_code()
|
|
1147
|
+
sage: aux.minimum_distance()
|
|
1148
|
+
2
|
|
1149
|
+
sage: Cx = D.construction_x(C,aux)
|
|
1150
|
+
sage: Cx
|
|
1151
|
+
[18, 7] linear code over GF(2)
|
|
1152
|
+
sage: Cx.minimum_distance()
|
|
1153
|
+
7
|
|
1154
|
+
"""
|
|
1155
|
+
if not other.is_subcode(self):
|
|
1156
|
+
raise ValueError("%s is not a subcode of %s" % (self, other))
|
|
1157
|
+
|
|
1158
|
+
G2 = self.generator_matrix()
|
|
1159
|
+
left = other.generator_matrix() # G1
|
|
1160
|
+
k = self.dimension()
|
|
1161
|
+
|
|
1162
|
+
for r in G2.rows():
|
|
1163
|
+
if r not in left.row_space():
|
|
1164
|
+
left = left.stack(r)
|
|
1165
|
+
|
|
1166
|
+
Ga = aux.generator_matrix()
|
|
1167
|
+
na = aux.length()
|
|
1168
|
+
ka = aux.dimension()
|
|
1169
|
+
|
|
1170
|
+
F = self.base_field()
|
|
1171
|
+
MS = MatrixSpace(F,k-ka,na)
|
|
1172
|
+
Z = MS(0)
|
|
1173
|
+
right = Z.stack(Ga)
|
|
1174
|
+
G = left.augment(right)
|
|
1175
|
+
return LinearCode(G)
|
|
1176
|
+
|
|
1177
|
+
def extended_code(self):
|
|
1178
|
+
r"""
|
|
1179
|
+
Return ``self`` as an extended code.
|
|
1180
|
+
|
|
1181
|
+
See documentation of :class:`sage.coding.extended_code.ExtendedCode`
|
|
1182
|
+
for details.
|
|
1183
|
+
|
|
1184
|
+
EXAMPLES::
|
|
1185
|
+
|
|
1186
|
+
sage: C = codes.HammingCode(GF(4,'a'), 3)
|
|
1187
|
+
sage: C
|
|
1188
|
+
[21, 18] Hamming Code over GF(4)
|
|
1189
|
+
sage: Cx = C.extended_code()
|
|
1190
|
+
sage: Cx
|
|
1191
|
+
Extension of [21, 18] Hamming Code over GF(4)
|
|
1192
|
+
"""
|
|
1193
|
+
from .extended_code import ExtendedCode
|
|
1194
|
+
return ExtendedCode(self)
|
|
1195
|
+
|
|
1196
|
+
def galois_closure(self, F0):
|
|
1197
|
+
r"""
|
|
1198
|
+
If ``self`` is a linear code defined over `F` and `F_0` is a subfield
|
|
1199
|
+
with Galois group `G = Gal(F/F_0)` then this returns the `G`-module
|
|
1200
|
+
`C^-` containing `C`.
|
|
1201
|
+
|
|
1202
|
+
EXAMPLES::
|
|
1203
|
+
|
|
1204
|
+
sage: C = codes.HammingCode(GF(4,'a'), 3)
|
|
1205
|
+
sage: Cc = C.galois_closure(GF(2))
|
|
1206
|
+
sage: C; Cc
|
|
1207
|
+
[21, 18] Hamming Code over GF(4)
|
|
1208
|
+
[21, 20] linear code over GF(4)
|
|
1209
|
+
sage: c = C.basis()[2]
|
|
1210
|
+
sage: V = VectorSpace(GF(4,'a'),21)
|
|
1211
|
+
sage: c2 = V([x^2 for x in c.list()])
|
|
1212
|
+
sage: c2 in C
|
|
1213
|
+
False
|
|
1214
|
+
sage: c2 in Cc
|
|
1215
|
+
True
|
|
1216
|
+
"""
|
|
1217
|
+
G = self.generator_matrix()
|
|
1218
|
+
F = self.base_ring()
|
|
1219
|
+
q = F.order()
|
|
1220
|
+
q0 = F0.order()
|
|
1221
|
+
a = q.log(q0) # test if F/F0 is a field extension
|
|
1222
|
+
if not isinstance(a, Integer):
|
|
1223
|
+
raise ValueError("Base field must be an extension of given field %s" % F0)
|
|
1224
|
+
n = len(G.columns())
|
|
1225
|
+
k = len(G.rows())
|
|
1226
|
+
G0 = [[x**q0 for x in g.list()] for g in G.rows()]
|
|
1227
|
+
G1 = [list(g.list()) for g in G.rows()]
|
|
1228
|
+
G2 = G0+G1
|
|
1229
|
+
MS = MatrixSpace(F,2*k,n)
|
|
1230
|
+
G3 = MS(G2)
|
|
1231
|
+
r = G3.rank()
|
|
1232
|
+
MS = MatrixSpace(F,r,n)
|
|
1233
|
+
Grref = G3.echelon_form()
|
|
1234
|
+
G = MS([Grref.row(i) for i in range(r)])
|
|
1235
|
+
return LinearCode(G)
|
|
1236
|
+
|
|
1237
|
+
def genus(self):
|
|
1238
|
+
r"""
|
|
1239
|
+
Return the "Duursma genus" of the code, `\gamma_C = n+1-k-d`.
|
|
1240
|
+
|
|
1241
|
+
EXAMPLES::
|
|
1242
|
+
|
|
1243
|
+
sage: C1 = codes.HammingCode(GF(2), 3); C1
|
|
1244
|
+
[7, 4] Hamming Code over GF(2)
|
|
1245
|
+
sage: C1.genus()
|
|
1246
|
+
1
|
|
1247
|
+
sage: C2 = codes.HammingCode(GF(4,"a"), 2); C2
|
|
1248
|
+
[5, 3] Hamming Code over GF(4)
|
|
1249
|
+
sage: C2.genus()
|
|
1250
|
+
0
|
|
1251
|
+
|
|
1252
|
+
Since all Hamming codes have minimum distance 3, these computations
|
|
1253
|
+
agree with the definition, `n+1-k-d`.
|
|
1254
|
+
"""
|
|
1255
|
+
d = self.minimum_distance()
|
|
1256
|
+
n = self.length()
|
|
1257
|
+
k = self.dimension()
|
|
1258
|
+
gammaC = n+1-k-d
|
|
1259
|
+
return gammaC
|
|
1260
|
+
|
|
1261
|
+
def is_permutation_equivalent(self, other, algorithm=None):
|
|
1262
|
+
"""
|
|
1263
|
+
Return ``True`` if ``self`` and ``other`` are permutation equivalent
|
|
1264
|
+
codes and ``False`` otherwise.
|
|
1265
|
+
|
|
1266
|
+
The ``algorithm="verbose"`` option also returns a permutation (if
|
|
1267
|
+
``True``) sending ``self`` to ``other``.
|
|
1268
|
+
|
|
1269
|
+
Uses Robert Miller's double coset partition refinement work.
|
|
1270
|
+
|
|
1271
|
+
EXAMPLES::
|
|
1272
|
+
|
|
1273
|
+
sage: P.<x> = PolynomialRing(GF(2),"x")
|
|
1274
|
+
sage: g = x^3 + x + 1
|
|
1275
|
+
sage: C1 = codes.CyclicCode(length=7, generator_pol=g); C1
|
|
1276
|
+
[7, 4] Cyclic Code over GF(2)
|
|
1277
|
+
sage: C2 = codes.HammingCode(GF(2), 3); C2
|
|
1278
|
+
[7, 4] Hamming Code over GF(2)
|
|
1279
|
+
sage: C1.is_permutation_equivalent(C2)
|
|
1280
|
+
True
|
|
1281
|
+
sage: C1.is_permutation_equivalent(C2, algorithm='verbose') # needs sage.groups
|
|
1282
|
+
(True, (3,4)(5,7,6))
|
|
1283
|
+
sage: C1 = codes.random_linear_code(GF(2), 10, 5)
|
|
1284
|
+
sage: C2 = codes.random_linear_code(GF(3), 10, 5)
|
|
1285
|
+
sage: C1.is_permutation_equivalent(C2)
|
|
1286
|
+
False
|
|
1287
|
+
"""
|
|
1288
|
+
from sage.groups.perm_gps.partn_ref.refinement_binary import NonlinearBinaryCodeStruct
|
|
1289
|
+
F = self.base_ring()
|
|
1290
|
+
F_o = other.base_ring()
|
|
1291
|
+
q = F.order()
|
|
1292
|
+
G = self.generator_matrix()
|
|
1293
|
+
n = self.length()
|
|
1294
|
+
n_o = other.length()
|
|
1295
|
+
if F != F_o or n != n_o:
|
|
1296
|
+
return False
|
|
1297
|
+
k = len(G.rows())
|
|
1298
|
+
MS = MatrixSpace(F,q**k,n)
|
|
1299
|
+
CW1 = MS(self.list())
|
|
1300
|
+
CW2 = MS(other.list())
|
|
1301
|
+
B1 = NonlinearBinaryCodeStruct(CW1)
|
|
1302
|
+
B2 = NonlinearBinaryCodeStruct(CW2)
|
|
1303
|
+
ans = B1.is_isomorphic(B2)
|
|
1304
|
+
if ans is not False:
|
|
1305
|
+
if algorithm == "verbose":
|
|
1306
|
+
Sn = SymmetricGroup(n)
|
|
1307
|
+
return True, Sn([i+1 for i in ans])**(-1)
|
|
1308
|
+
return True
|
|
1309
|
+
return False
|
|
1310
|
+
|
|
1311
|
+
def is_galois_closed(self):
|
|
1312
|
+
r"""
|
|
1313
|
+
Check if ``self`` is equal to its Galois closure.
|
|
1314
|
+
|
|
1315
|
+
EXAMPLES::
|
|
1316
|
+
|
|
1317
|
+
sage: C = codes.HammingCode(GF(4,"a"), 3)
|
|
1318
|
+
sage: C.is_galois_closed()
|
|
1319
|
+
False
|
|
1320
|
+
"""
|
|
1321
|
+
p = self.base_ring().characteristic()
|
|
1322
|
+
return self == self.galois_closure(GF(p))
|
|
1323
|
+
|
|
1324
|
+
def _magma_init_(self, magma):
|
|
1325
|
+
r"""
|
|
1326
|
+
Return a string representation in Magma of this linear code.
|
|
1327
|
+
|
|
1328
|
+
EXAMPLES::
|
|
1329
|
+
|
|
1330
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
1331
|
+
sage: Cm = magma(C) # optional - magma, indirect doctest
|
|
1332
|
+
sage: Cm.MinimumWeight() # optional - magma
|
|
1333
|
+
3
|
|
1334
|
+
"""
|
|
1335
|
+
G = magma(self.generator_matrix())._ref()
|
|
1336
|
+
return 'LinearCode(%s)' % G
|
|
1337
|
+
|
|
1338
|
+
@cached_method
|
|
1339
|
+
def minimum_distance(self, algorithm=None):
|
|
1340
|
+
r"""
|
|
1341
|
+
Return the minimum distance of ``self``.
|
|
1342
|
+
|
|
1343
|
+
.. NOTE::
|
|
1344
|
+
|
|
1345
|
+
When using GAP, this raises a :exc:`NotImplementedError` if
|
|
1346
|
+
the base field of the code has size greater than 256 due
|
|
1347
|
+
to limitations in GAP.
|
|
1348
|
+
|
|
1349
|
+
INPUT:
|
|
1350
|
+
|
|
1351
|
+
- ``algorithm`` -- (default: ``None``) the name of the algorithm to use
|
|
1352
|
+
to perform minimum distance computation. ``algorithm`` can be:
|
|
1353
|
+
|
|
1354
|
+
- ``None``, to use GAP methods (but not Guava)
|
|
1355
|
+
|
|
1356
|
+
- ``'guava'``, to use the optional GAP package Guava
|
|
1357
|
+
|
|
1358
|
+
OUTPUT: integer; minimum distance of this code
|
|
1359
|
+
|
|
1360
|
+
EXAMPLES::
|
|
1361
|
+
|
|
1362
|
+
sage: MS = MatrixSpace(GF(3),4,7)
|
|
1363
|
+
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
1364
|
+
sage: C = LinearCode(G)
|
|
1365
|
+
sage: C.minimum_distance() # needs sage.libs.gap
|
|
1366
|
+
3
|
|
1367
|
+
|
|
1368
|
+
If ``algorithm`` is provided, then the minimum distance will be
|
|
1369
|
+
recomputed even if there is a stored value from a previous run.::
|
|
1370
|
+
|
|
1371
|
+
sage: C.minimum_distance(algorithm='gap') # needs sage.libs.gap
|
|
1372
|
+
3
|
|
1373
|
+
sage: libgap.SetAllInfoLevels(0) # to suppress extra info messages # needs sage.libs.gap
|
|
1374
|
+
sage: C.minimum_distance(algorithm='guava') # optional - gap_package_guava
|
|
1375
|
+
...3
|
|
1376
|
+
|
|
1377
|
+
TESTS::
|
|
1378
|
+
|
|
1379
|
+
sage: C = codes.random_linear_code(GF(4,"a"), 5, 2)
|
|
1380
|
+
sage: C.minimum_distance(algorithm='something')
|
|
1381
|
+
Traceback (most recent call last):
|
|
1382
|
+
...
|
|
1383
|
+
ValueError: The algorithm argument must be one of None, 'gap' or 'guava'; got 'something'
|
|
1384
|
+
|
|
1385
|
+
The field must be size at most 256::
|
|
1386
|
+
|
|
1387
|
+
sage: C = codes.random_linear_code(GF(257,"a"), 5, 2)
|
|
1388
|
+
sage: C.minimum_distance()
|
|
1389
|
+
Traceback (most recent call last):
|
|
1390
|
+
...
|
|
1391
|
+
NotImplementedError: the GAP algorithm that Sage is using
|
|
1392
|
+
is limited to computing with fields of size at most 256
|
|
1393
|
+
"""
|
|
1394
|
+
if algorithm == 'guava':
|
|
1395
|
+
GapPackage('guava', spkg='gap_packages').require()
|
|
1396
|
+
|
|
1397
|
+
# If the minimum distance has already been computed or provided by
|
|
1398
|
+
# the user then simply return the stored value.
|
|
1399
|
+
# This is done only if algorithm is None.
|
|
1400
|
+
if algorithm not in (None, 'gap', 'guava'):
|
|
1401
|
+
raise ValueError("The algorithm argument must be one of None, "
|
|
1402
|
+
"'gap' or 'guava'; got '{0}'".format(algorithm))
|
|
1403
|
+
|
|
1404
|
+
F = self.base_ring()
|
|
1405
|
+
q = F.order()
|
|
1406
|
+
if q > 256:
|
|
1407
|
+
raise NotImplementedError("the GAP algorithm that Sage is using "
|
|
1408
|
+
"is limited to computing with fields "
|
|
1409
|
+
"of size at most 256")
|
|
1410
|
+
|
|
1411
|
+
G = self.generator_matrix()
|
|
1412
|
+
if (q == 2 or q == 3) and algorithm == 'guava':
|
|
1413
|
+
from sage.libs.gap.libgap import libgap
|
|
1414
|
+
libgap.LoadPackage('guava')
|
|
1415
|
+
C = libgap(G).GeneratorMatCode(libgap(F))
|
|
1416
|
+
d = C.MinimumWeight()
|
|
1417
|
+
return ZZ(d)
|
|
1418
|
+
return self._minimum_weight_codeword(algorithm).hamming_weight()
|
|
1419
|
+
|
|
1420
|
+
def _minimum_weight_codeword(self, algorithm=None):
|
|
1421
|
+
r"""
|
|
1422
|
+
Return a minimum weight codeword of ``self``.
|
|
1423
|
+
|
|
1424
|
+
INPUT:
|
|
1425
|
+
|
|
1426
|
+
- ``algorithm`` -- (default: ``None``) the name of the algorithm to use
|
|
1427
|
+
to perform minimum weight codeword search. If set to ``None``,
|
|
1428
|
+
a search using GAP methods will be done. ``algorithm`` can be
|
|
1429
|
+
``'guava'``, which will use the optional GAP package Guava.
|
|
1430
|
+
|
|
1431
|
+
REMARKS:
|
|
1432
|
+
|
|
1433
|
+
- The code in the default case allows one (for free) to also compute the
|
|
1434
|
+
message vector `m` such that `m\*G = v`, and the (minimum) distance, as
|
|
1435
|
+
a triple. however, this output is not implemented.
|
|
1436
|
+
- The binary case can presumably be done much faster using Robert Miller's
|
|
1437
|
+
code (see the docstring for the spectrum method). This is also not (yet)
|
|
1438
|
+
implemented.
|
|
1439
|
+
|
|
1440
|
+
EXAMPLES::
|
|
1441
|
+
|
|
1442
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
1443
|
+
sage: C = LinearCode(G)
|
|
1444
|
+
sage: C._minimum_weight_codeword() # needs sage.libs.gap
|
|
1445
|
+
(0, 1, 0, 1, 0, 1, 0)
|
|
1446
|
+
|
|
1447
|
+
TESTS:
|
|
1448
|
+
|
|
1449
|
+
We check that :issue:`18480` is fixed::
|
|
1450
|
+
|
|
1451
|
+
sage: codes.HammingCode(GF(2), 2).minimum_distance() # needs sage.libs.gap
|
|
1452
|
+
3
|
|
1453
|
+
|
|
1454
|
+
AUTHORS:
|
|
1455
|
+
|
|
1456
|
+
- David Joyner (11-2005)
|
|
1457
|
+
"""
|
|
1458
|
+
from sage.libs.gap.libgap import libgap
|
|
1459
|
+
n, k = self.length(), self.dimension()
|
|
1460
|
+
F = self.base_field()
|
|
1461
|
+
Gmat = libgap(self.generator_matrix())
|
|
1462
|
+
|
|
1463
|
+
current_randstate().set_seed_gap()
|
|
1464
|
+
|
|
1465
|
+
if algorithm == 'guava':
|
|
1466
|
+
GapPackage('guava', spkg='gap_packages').require()
|
|
1467
|
+
libgap.LoadPackage('guava')
|
|
1468
|
+
C = Gmat.GeneratorMatCode(F)
|
|
1469
|
+
cg = C.MinimumDistanceCodeword()
|
|
1470
|
+
c = [cg[j].sage(ring=F) for j in range(n)]
|
|
1471
|
+
return vector(F, c)
|
|
1472
|
+
|
|
1473
|
+
q = F.order()
|
|
1474
|
+
ans = None
|
|
1475
|
+
dist_min = libgap(n + 1)
|
|
1476
|
+
K = libgap.GF(q)
|
|
1477
|
+
v0 = (K**n).Zero()
|
|
1478
|
+
for i in range(1,k+1):
|
|
1479
|
+
v = Gmat.AClosestVectorCombinationsMatFFEVecFFECoords(K,v0,i,1)[0]
|
|
1480
|
+
dist = v.WeightVecFFE()
|
|
1481
|
+
if dist and dist < dist_min:
|
|
1482
|
+
dist_min = dist
|
|
1483
|
+
ans = list(v)
|
|
1484
|
+
|
|
1485
|
+
if ans is None:
|
|
1486
|
+
raise RuntimeError("Computation failed due to some GAP error")
|
|
1487
|
+
|
|
1488
|
+
# return the result as a vector (and not a 1xn matrix)
|
|
1489
|
+
return vector(F, ans)
|
|
1490
|
+
|
|
1491
|
+
def module_composition_factors(self, gp):
|
|
1492
|
+
r"""
|
|
1493
|
+
Print the GAP record of the Meataxe composition factors module.
|
|
1494
|
+
|
|
1495
|
+
This is displayed in Meataxe notation.
|
|
1496
|
+
|
|
1497
|
+
This uses GAP but not Guava.
|
|
1498
|
+
|
|
1499
|
+
EXAMPLES::
|
|
1500
|
+
|
|
1501
|
+
sage: MS = MatrixSpace(GF(2),4,8)
|
|
1502
|
+
sage: G = MS([[1,0,0,0,1,1,1,0], [0,1,1,1,0,0,0,0],
|
|
1503
|
+
....: [0,0,0,0,0,0,0,1], [0,0,0,0,0,1,0,0]])
|
|
1504
|
+
sage: C = LinearCode(G)
|
|
1505
|
+
sage: gp = C.permutation_automorphism_group() # needs sage.libs.gap
|
|
1506
|
+
sage: C.module_composition_factors(gp) # needs sage.libs.gap
|
|
1507
|
+
[ rec(
|
|
1508
|
+
IsIrreducible := true,
|
|
1509
|
+
IsOverFiniteField := true,
|
|
1510
|
+
...) ]
|
|
1511
|
+
"""
|
|
1512
|
+
from sage.libs.gap.libgap import libgap
|
|
1513
|
+
F = self.base_ring()
|
|
1514
|
+
gens = gp.gens()
|
|
1515
|
+
G = self.generator_matrix()
|
|
1516
|
+
n = G.ncols()
|
|
1517
|
+
MS = MatrixSpace(F, n, n)
|
|
1518
|
+
mats = [] # initializing list of mats by which the gens act on self
|
|
1519
|
+
Fn = VectorSpace(F, n)
|
|
1520
|
+
W = Fn.subspace_with_basis(G.rows()) # this is self
|
|
1521
|
+
for g in gens:
|
|
1522
|
+
p = MS(g.matrix())
|
|
1523
|
+
m = [W.coordinate_vector(r * p) for r in G.rows()]
|
|
1524
|
+
mats.append(m)
|
|
1525
|
+
mats_gap = libgap(mats)
|
|
1526
|
+
M_gap = mats_gap.GModuleByMats(F)
|
|
1527
|
+
# our parser does not grok "foo.MTX.Bar" yet;so we cannot do
|
|
1528
|
+
# M_gap.MTX.CompositionFactors() yet
|
|
1529
|
+
return libgap.eval('MTX.CompositionFactors('+str(M_gap)+')')
|
|
1530
|
+
|
|
1531
|
+
def permutation_automorphism_group(self, algorithm='partition'):
|
|
1532
|
+
r"""
|
|
1533
|
+
If `C` is an `[n,k,d]` code over `F`, this function computes the
|
|
1534
|
+
subgroup `Aut(C) \subset S_n` of all permutation automorphisms of `C`.
|
|
1535
|
+
The binary case always uses the (default) partition refinement
|
|
1536
|
+
algorithm of Robert Miller.
|
|
1537
|
+
|
|
1538
|
+
Note that if the base ring of `C` is `GF(2)` then this is the full
|
|
1539
|
+
automorphism group. Otherwise, you could use
|
|
1540
|
+
:meth:`~sage.coding.linear_code.LinearCode.automorphism_group_gens`
|
|
1541
|
+
to compute generators of the full automorphism group.
|
|
1542
|
+
|
|
1543
|
+
INPUT:
|
|
1544
|
+
|
|
1545
|
+
- ``algorithm`` -- if ``'gap'`` then GAP's MatrixAutomorphism function
|
|
1546
|
+
(written by Thomas Breuer) is used. The implementation combines an
|
|
1547
|
+
idea of mine with an improvement suggested by Cary Huffman. If
|
|
1548
|
+
``'gap+verbose'`` then code-theoretic data is printed out at
|
|
1549
|
+
several stages of the computation. If ``'partition'`` then the
|
|
1550
|
+
(default) partition refinement algorithm of Robert Miller is used.
|
|
1551
|
+
Finally, if ``'codecan'`` then the partition refinement algorithm
|
|
1552
|
+
of Thomas Feulner is used, which also computes a canonical
|
|
1553
|
+
representative of ``self`` (call
|
|
1554
|
+
:meth:`~sage.coding.linear_code.LinearCode.canonical_representative`
|
|
1555
|
+
to access it).
|
|
1556
|
+
|
|
1557
|
+
OUTPUT: permutation automorphism group
|
|
1558
|
+
|
|
1559
|
+
EXAMPLES::
|
|
1560
|
+
|
|
1561
|
+
sage: MS = MatrixSpace(GF(2),4,8)
|
|
1562
|
+
sage: G = MS([[1,0,0,0,1,1,1,0], [0,1,1,1,0,0,0,0],
|
|
1563
|
+
....: [0,0,0,0,0,0,0,1], [0,0,0,0,0,1,0,0]])
|
|
1564
|
+
sage: C = LinearCode(G); C
|
|
1565
|
+
[8, 4] linear code over GF(2)
|
|
1566
|
+
|
|
1567
|
+
sage: # needs sage.groups
|
|
1568
|
+
sage: G = C.permutation_automorphism_group()
|
|
1569
|
+
sage: G.order()
|
|
1570
|
+
144
|
|
1571
|
+
sage: GG = C.permutation_automorphism_group("codecan")
|
|
1572
|
+
sage: GG == G
|
|
1573
|
+
True
|
|
1574
|
+
|
|
1575
|
+
A less easy example involves showing that the permutation
|
|
1576
|
+
automorphism group of the extended ternary Golay code is the
|
|
1577
|
+
Mathieu group `M_{11}`.
|
|
1578
|
+
|
|
1579
|
+
::
|
|
1580
|
+
|
|
1581
|
+
sage: # needs sage.groups
|
|
1582
|
+
sage: C = codes.GolayCode(GF(3))
|
|
1583
|
+
sage: M11 = MathieuGroup(11)
|
|
1584
|
+
sage: M11.order()
|
|
1585
|
+
7920
|
|
1586
|
+
sage: G = C.permutation_automorphism_group() # long time (6s on sage.math, 2011)
|
|
1587
|
+
sage: G.is_isomorphic(M11) # long time
|
|
1588
|
+
True
|
|
1589
|
+
sage: GG = C.permutation_automorphism_group("codecan") # long time
|
|
1590
|
+
sage: GG == G # long time
|
|
1591
|
+
True
|
|
1592
|
+
|
|
1593
|
+
Other examples::
|
|
1594
|
+
|
|
1595
|
+
sage: # needs sage.groups
|
|
1596
|
+
sage: C = codes.GolayCode(GF(2))
|
|
1597
|
+
sage: G = C.permutation_automorphism_group()
|
|
1598
|
+
sage: G.order()
|
|
1599
|
+
244823040
|
|
1600
|
+
sage: C = codes.HammingCode(GF(2), 5)
|
|
1601
|
+
sage: G = C.permutation_automorphism_group()
|
|
1602
|
+
sage: G.order()
|
|
1603
|
+
9999360
|
|
1604
|
+
sage: C = codes.HammingCode(GF(3), 2); C
|
|
1605
|
+
[4, 2] Hamming Code over GF(3)
|
|
1606
|
+
sage: C.permutation_automorphism_group(algorithm='partition')
|
|
1607
|
+
Permutation Group with generators [(1,3,4)]
|
|
1608
|
+
sage: C = codes.HammingCode(GF(4,"z"), 2); C
|
|
1609
|
+
[5, 3] Hamming Code over GF(4)
|
|
1610
|
+
sage: G = C.permutation_automorphism_group(algorithm='partition'); G
|
|
1611
|
+
Permutation Group with generators [(1,3)(4,5), (1,4)(3,5)]
|
|
1612
|
+
sage: GG = C.permutation_automorphism_group(algorithm='codecan') # long time
|
|
1613
|
+
sage: GG == G # long time
|
|
1614
|
+
True
|
|
1615
|
+
sage: C.permutation_automorphism_group(algorithm='gap') # optional - gap_package_guava
|
|
1616
|
+
Permutation Group with generators [(1,3)(4,5), (1,4)(3,5)]
|
|
1617
|
+
sage: C = codes.GolayCode(GF(3), True)
|
|
1618
|
+
sage: C.permutation_automorphism_group(algorithm='gap') # optional - gap_package_guava
|
|
1619
|
+
Permutation Group with generators
|
|
1620
|
+
[(5,7)(6,11)(8,9)(10,12), (4,6,11)(5,8,12)(7,10,9), (3,4)(6,8)(9,11)(10,12),
|
|
1621
|
+
(2,3)(6,11)(8,12)(9,10), (1,2)(5,10)(7,12)(8,9)]
|
|
1622
|
+
|
|
1623
|
+
However, the option ``algorithm="gap+verbose"``, will print out::
|
|
1624
|
+
|
|
1625
|
+
Minimum distance: 5 Weight distribution: [1, 0, 0, 0, 0, 132, 132,
|
|
1626
|
+
0, 330, 110, 0, 24]
|
|
1627
|
+
|
|
1628
|
+
Using the 132 codewords of weight 5 Supergroup size: 39916800
|
|
1629
|
+
|
|
1630
|
+
in addition to the output of
|
|
1631
|
+
``C.permutation_automorphism_group(algorithm='gap')``.
|
|
1632
|
+
"""
|
|
1633
|
+
F = self.base_ring()
|
|
1634
|
+
q = F.order()
|
|
1635
|
+
G = self.generator_matrix() if 2*self.dimension() <= self.length() else self.dual_code().generator_matrix()
|
|
1636
|
+
n = len(G.columns())
|
|
1637
|
+
if "gap" in algorithm:
|
|
1638
|
+
from sage.libs.gap.libgap import libgap
|
|
1639
|
+
GapPackage('guava', spkg='gap_packages').require()
|
|
1640
|
+
libgap.LoadPackage('guava')
|
|
1641
|
+
wts = self.weight_distribution() # bottleneck 1
|
|
1642
|
+
nonzerowts = [i for i in range(len(wts)) if wts[i] != 0]
|
|
1643
|
+
Sn = libgap.SymmetricGroup(n)
|
|
1644
|
+
Sn_sage = SymmetricGroup(n)
|
|
1645
|
+
Gp = Sn # initializing G in gap
|
|
1646
|
+
C = libgap(G).GeneratorMatCode(libgap.GF(q))
|
|
1647
|
+
eltsC = C.Elements()
|
|
1648
|
+
if algorithm == "gap+verbose":
|
|
1649
|
+
print("\n Minimum distance: %s \n Weight distribution: \n %s" % (nonzerowts[1], wts))
|
|
1650
|
+
stop = 0 # only stop if all gens are autos
|
|
1651
|
+
for i in range(1,len(nonzerowts)):
|
|
1652
|
+
if stop == 1:
|
|
1653
|
+
break
|
|
1654
|
+
wt = nonzerowts[i]
|
|
1655
|
+
if algorithm == "gap+verbose":
|
|
1656
|
+
size = Gp.Size()
|
|
1657
|
+
print("\n Using the %s codewords of weight %s \n Supergroup size: \n %s\n " % (wts[wt], wt, size))
|
|
1658
|
+
Cwt = filter(lambda c: c.WeightCodeword() == wt, eltsC) # bottleneck 2 (repeated
|
|
1659
|
+
matCwt = [c.VectorCodeword() for c in Cwt] # for each i until stop = 1)
|
|
1660
|
+
if len(matCwt) > 0:
|
|
1661
|
+
A = libgap(matCwt).MatrixAutomorphisms()
|
|
1662
|
+
Gp = A.Intersection2(Gp) # bottleneck 3
|
|
1663
|
+
if Gp.Size() == 1:
|
|
1664
|
+
return PermutationGroup([()])
|
|
1665
|
+
gens = Gp.GeneratorsOfGroup()
|
|
1666
|
+
stop = 1 # get ready to stop
|
|
1667
|
+
for x in gens: # if one of these gens is not an auto then don't stop
|
|
1668
|
+
if not self.is_permutation_automorphism(Sn_sage(x)):
|
|
1669
|
+
stop = 0
|
|
1670
|
+
break
|
|
1671
|
+
G = PermutationGroup(list(map(Sn_sage, gens)))
|
|
1672
|
+
return G
|
|
1673
|
+
if algorithm == "partition":
|
|
1674
|
+
if q == 2:
|
|
1675
|
+
from sage.groups.perm_gps.partn_ref.refinement_binary import LinearBinaryCodeStruct
|
|
1676
|
+
B = LinearBinaryCodeStruct(G)
|
|
1677
|
+
autgp = B.automorphism_group()
|
|
1678
|
+
L = [[j+1 for j in gen] for gen in autgp[0]]
|
|
1679
|
+
AutGp = PermutationGroup(L)
|
|
1680
|
+
else:
|
|
1681
|
+
from sage.groups.perm_gps.partn_ref.refinement_matrices import MatrixStruct
|
|
1682
|
+
from sage.matrix.constructor import matrix
|
|
1683
|
+
weights = {}
|
|
1684
|
+
for c in self:
|
|
1685
|
+
wt = c.hamming_weight()
|
|
1686
|
+
if wt not in weights:
|
|
1687
|
+
weights[wt] = [c]
|
|
1688
|
+
else:
|
|
1689
|
+
weights[wt].append(c)
|
|
1690
|
+
weights.pop(0)
|
|
1691
|
+
AutGps = []
|
|
1692
|
+
for wt, words in weights.items():
|
|
1693
|
+
M = MatrixStruct(matrix(words))
|
|
1694
|
+
autgp = M.automorphism_group()
|
|
1695
|
+
L = [[j+1 for j in gen] for gen in autgp[0]]
|
|
1696
|
+
G = PermutationGroup(L)
|
|
1697
|
+
AutGps.append(G)
|
|
1698
|
+
if len(AutGps) > 0:
|
|
1699
|
+
AutGp = AutGps[0]
|
|
1700
|
+
for G in AutGps[1:]:
|
|
1701
|
+
AutGp = AutGp.intersection(G)
|
|
1702
|
+
else:
|
|
1703
|
+
return PermutationGroup([])
|
|
1704
|
+
return AutGp
|
|
1705
|
+
if algorithm == "codecan":
|
|
1706
|
+
gens, _ = self.automorphism_group_gens("permutational")
|
|
1707
|
+
return PermutationGroup([x.get_perm() for x in gens])
|
|
1708
|
+
raise NotImplementedError("The only algorithms implemented currently are 'gap', 'gap+verbose', and 'partition'.")
|
|
1709
|
+
|
|
1710
|
+
def punctured(self, L):
|
|
1711
|
+
r"""
|
|
1712
|
+
Return a :class:`sage.coding.punctured_code` object from ``L``.
|
|
1713
|
+
|
|
1714
|
+
INPUT:
|
|
1715
|
+
|
|
1716
|
+
- ``L`` -- list of positions to puncture
|
|
1717
|
+
|
|
1718
|
+
OUTPUT: an instance of :class:`sage.coding.punctured_code`
|
|
1719
|
+
|
|
1720
|
+
EXAMPLES::
|
|
1721
|
+
|
|
1722
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
1723
|
+
sage: C.punctured([1,2])
|
|
1724
|
+
Puncturing of [7, 4] Hamming Code over GF(2) on position(s) [1, 2]
|
|
1725
|
+
"""
|
|
1726
|
+
from .punctured_code import PuncturedCode
|
|
1727
|
+
return PuncturedCode(self, set(L))
|
|
1728
|
+
|
|
1729
|
+
def _punctured_form(self, points):
|
|
1730
|
+
r"""
|
|
1731
|
+
Return a representation of ``self`` as a :class:`LinearCode` punctured in ``points``.
|
|
1732
|
+
|
|
1733
|
+
INPUT:
|
|
1734
|
+
|
|
1735
|
+
- ``points`` -- set of positions where to puncture ``self``
|
|
1736
|
+
|
|
1737
|
+
EXAMPLES::
|
|
1738
|
+
|
|
1739
|
+
sage: C = codes.random_linear_code(GF(7), 11, 4)
|
|
1740
|
+
sage: C._punctured_form({3})
|
|
1741
|
+
[10, 4] linear code over GF(7)
|
|
1742
|
+
"""
|
|
1743
|
+
if not isinstance(points, (Integer, int, set)):
|
|
1744
|
+
raise TypeError("points must be either a Sage Integer, a Python int, or a set")
|
|
1745
|
+
M = self.generator_matrix()
|
|
1746
|
+
G = M.delete_columns(list(points))
|
|
1747
|
+
G = G.echelon_form()
|
|
1748
|
+
k = G.rank()
|
|
1749
|
+
return LinearCode(G[:k])
|
|
1750
|
+
|
|
1751
|
+
def relative_distance(self):
|
|
1752
|
+
r"""
|
|
1753
|
+
Return the ratio of the minimum distance to the code length.
|
|
1754
|
+
|
|
1755
|
+
EXAMPLES::
|
|
1756
|
+
|
|
1757
|
+
sage: C = codes.HammingCode(GF(2),3)
|
|
1758
|
+
sage: C.relative_distance()
|
|
1759
|
+
3/7
|
|
1760
|
+
"""
|
|
1761
|
+
return self.minimum_distance() / self.length()
|
|
1762
|
+
|
|
1763
|
+
def shortened(self, L):
|
|
1764
|
+
r"""
|
|
1765
|
+
Return the code shortened at the positions ``L``, where
|
|
1766
|
+
`L \subset \{1,2,...,n\}`.
|
|
1767
|
+
|
|
1768
|
+
Consider the subcode `C(L)` consisting of all codewords `c\in C` which
|
|
1769
|
+
satisfy `c_i=0` for all `i\in L`. The punctured code `C(L)^L` is
|
|
1770
|
+
called the shortened code on `L` and is denoted `C_L`. The code
|
|
1771
|
+
constructed is actually only isomorphic to the shortened code defined
|
|
1772
|
+
in this way.
|
|
1773
|
+
|
|
1774
|
+
By Theorem 1.5.7 in [HP2003]_, `C_L` is `((C^\perp)^L)^\perp`. This is used
|
|
1775
|
+
in the construction below.
|
|
1776
|
+
|
|
1777
|
+
INPUT:
|
|
1778
|
+
|
|
1779
|
+
- ``L`` -- subset of `\{1,...,n\}`, where `n` is the length of this code
|
|
1780
|
+
|
|
1781
|
+
OUTPUT: linear code, the shortened code described above
|
|
1782
|
+
|
|
1783
|
+
EXAMPLES::
|
|
1784
|
+
|
|
1785
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
1786
|
+
sage: C.shortened([1,2])
|
|
1787
|
+
[5, 2] linear code over GF(2)
|
|
1788
|
+
"""
|
|
1789
|
+
Cd = self.dual_code()
|
|
1790
|
+
Cdp = Cd.punctured(set(L))
|
|
1791
|
+
return Cdp.dual_code()
|
|
1792
|
+
|
|
1793
|
+
@cached_method
|
|
1794
|
+
def weight_distribution(self, algorithm=None):
|
|
1795
|
+
r"""
|
|
1796
|
+
Return the weight distribution, or spectrum, of ``self`` as a list.
|
|
1797
|
+
|
|
1798
|
+
The weight distribution a code of length `n` is the sequence `A_0,
|
|
1799
|
+
A_1,..., A_n` where `A_i` is the number of codewords of weight `i`.
|
|
1800
|
+
|
|
1801
|
+
INPUT:
|
|
1802
|
+
|
|
1803
|
+
- ``algorithm`` -- (default: ``None``) if set to ``'gap'``,
|
|
1804
|
+
call GAP. If set to ``'leon'``, call the option GAP package GUAVA and
|
|
1805
|
+
call a function therein by Jeffrey Leon (see warning below). If set to
|
|
1806
|
+
``'binary'``, use an algorithm optimized for binary codes. The default
|
|
1807
|
+
is to use ``'binary'`` for binary codes and ``'gap'`` otherwise.
|
|
1808
|
+
|
|
1809
|
+
OUTPUT: list of nonnegative integers; the weight distribution
|
|
1810
|
+
|
|
1811
|
+
.. WARNING::
|
|
1812
|
+
|
|
1813
|
+
Specifying ``algorithm="leon"`` sometimes prints a traceback
|
|
1814
|
+
related to a stack smashing error in the C library. The result
|
|
1815
|
+
appears to be computed correctly, however. It appears to run much
|
|
1816
|
+
faster than the GAP algorithm in small examples and much slower than
|
|
1817
|
+
the GAP algorithm in larger examples.
|
|
1818
|
+
|
|
1819
|
+
EXAMPLES::
|
|
1820
|
+
|
|
1821
|
+
sage: MS = MatrixSpace(GF(2),4,7)
|
|
1822
|
+
sage: G = MS([[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
|
|
1823
|
+
sage: C = LinearCode(G)
|
|
1824
|
+
sage: C.weight_distribution()
|
|
1825
|
+
[1, 0, 0, 7, 7, 0, 0, 1]
|
|
1826
|
+
sage: F.<z> = GF(2^2,"z")
|
|
1827
|
+
sage: C = codes.HammingCode(F, 2); C
|
|
1828
|
+
[5, 3] Hamming Code over GF(4)
|
|
1829
|
+
sage: C.weight_distribution() # needs sage.libs.gap
|
|
1830
|
+
[1, 0, 0, 30, 15, 18]
|
|
1831
|
+
sage: C = codes.HammingCode(GF(2), 3); C
|
|
1832
|
+
[7, 4] Hamming Code over GF(2)
|
|
1833
|
+
sage: C.weight_distribution(algorithm='leon') # optional - gap_package_guava
|
|
1834
|
+
[1, 0, 0, 7, 7, 0, 0, 1]
|
|
1835
|
+
sage: C.weight_distribution(algorithm='gap') # needs sage.libs.gap
|
|
1836
|
+
[1, 0, 0, 7, 7, 0, 0, 1]
|
|
1837
|
+
sage: C.weight_distribution(algorithm='binary')
|
|
1838
|
+
[1, 0, 0, 7, 7, 0, 0, 1]
|
|
1839
|
+
|
|
1840
|
+
sage: # optional - gap_package_guava
|
|
1841
|
+
sage: C = codes.HammingCode(GF(3), 3); C
|
|
1842
|
+
[13, 10] Hamming Code over GF(3)
|
|
1843
|
+
sage: C.weight_distribution() == C.weight_distribution(algorithm='leon')
|
|
1844
|
+
True
|
|
1845
|
+
sage: C = codes.HammingCode(GF(5), 2); C
|
|
1846
|
+
[6, 4] Hamming Code over GF(5)
|
|
1847
|
+
sage: C.weight_distribution() == C.weight_distribution(algorithm='leon')
|
|
1848
|
+
True
|
|
1849
|
+
sage: C = codes.HammingCode(GF(7), 2); C
|
|
1850
|
+
[8, 6] Hamming Code over GF(7)
|
|
1851
|
+
sage: C.weight_distribution() == C.weight_distribution(algorithm='leon')
|
|
1852
|
+
True
|
|
1853
|
+
"""
|
|
1854
|
+
if algorithm is None:
|
|
1855
|
+
if self.base_ring().order() == 2:
|
|
1856
|
+
algorithm = "binary"
|
|
1857
|
+
else:
|
|
1858
|
+
algorithm = "gap"
|
|
1859
|
+
F = self.base_ring()
|
|
1860
|
+
n = self.length()
|
|
1861
|
+
if algorithm == "gap":
|
|
1862
|
+
from sage.libs.gap.libgap import libgap
|
|
1863
|
+
Gmat = self.generator_matrix()
|
|
1864
|
+
q = self.base_ring().order()
|
|
1865
|
+
z = 0*libgap.Z(q)*([0]*self.length()) # GAP zero vector
|
|
1866
|
+
w = libgap(Gmat).DistancesDistributionMatFFEVecFFE(libgap.GF(q),z)
|
|
1867
|
+
return w.sage()
|
|
1868
|
+
elif algorithm == "binary":
|
|
1869
|
+
from sage.coding.binary_code import weight_dist
|
|
1870
|
+
return weight_dist(self.generator_matrix())
|
|
1871
|
+
elif algorithm == "leon":
|
|
1872
|
+
if F.order() not in [2, 3, 5, 7]:
|
|
1873
|
+
raise NotImplementedError("The algorithm 'leon' is only implemented for q = 2,3,5,7.")
|
|
1874
|
+
# The GAP command DirectoriesPackageLibrary tells the location of the latest
|
|
1875
|
+
# version of the Guava libraries, so gives us the location of the Guava binaries too.
|
|
1876
|
+
from sage.libs.gap.libgap import libgap
|
|
1877
|
+
guava_bin_dir = libgap.DirectoriesPackagePrograms('guava')[0].Filename("").sage()
|
|
1878
|
+
input = _dump_code_in_leon_format(self) + "::code"
|
|
1879
|
+
lines = subprocess.check_output([os.path.join(guava_bin_dir, 'wtdist'), input])
|
|
1880
|
+
# to use the already present output parser
|
|
1881
|
+
wts = [0] * (n + 1)
|
|
1882
|
+
for L in StringIO(bytes_to_str(lines)).readlines():
|
|
1883
|
+
L = L.strip()
|
|
1884
|
+
if L:
|
|
1885
|
+
o = ord(L[0])
|
|
1886
|
+
if o >= 48 and o <= 57:
|
|
1887
|
+
wt, num = L.split()
|
|
1888
|
+
wts[eval(wt)] = eval(num)
|
|
1889
|
+
return wts
|
|
1890
|
+
else:
|
|
1891
|
+
raise NotImplementedError("The only algorithms implemented currently are 'gap', 'leon' and 'binary'.")
|
|
1892
|
+
|
|
1893
|
+
spectrum = weight_distribution
|
|
1894
|
+
|
|
1895
|
+
def support(self):
|
|
1896
|
+
r"""
|
|
1897
|
+
Return the set of indices `j` where `A_j` is nonzero, where
|
|
1898
|
+
`A_j` is the number of codewords in ``self`` of Hamming weight `j`.
|
|
1899
|
+
|
|
1900
|
+
OUTPUT: list of integers
|
|
1901
|
+
|
|
1902
|
+
EXAMPLES::
|
|
1903
|
+
|
|
1904
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
1905
|
+
sage: C.weight_distribution()
|
|
1906
|
+
[1, 0, 0, 7, 7, 0, 0, 1]
|
|
1907
|
+
sage: C.support()
|
|
1908
|
+
[0, 3, 4, 7]
|
|
1909
|
+
"""
|
|
1910
|
+
n = self.length()
|
|
1911
|
+
F = self.base_ring()
|
|
1912
|
+
V = VectorSpace(F,n+1)
|
|
1913
|
+
return V(self.weight_distribution()).support()
|
|
1914
|
+
|
|
1915
|
+
def weight_enumerator(self, names=None, bivariate=True):
|
|
1916
|
+
r"""
|
|
1917
|
+
Return the weight enumerator polynomial of ``self``.
|
|
1918
|
+
|
|
1919
|
+
This is the bivariate, homogeneous polynomial in `x` and `y` whose
|
|
1920
|
+
coefficient to `x^i y^{n-i}` is the number of codewords of ``self`` of
|
|
1921
|
+
Hamming weight `i`. Here, `n` is the length of ``self``.
|
|
1922
|
+
|
|
1923
|
+
INPUT:
|
|
1924
|
+
|
|
1925
|
+
- ``names`` -- (default: ``'xy'``) the names of the variables in the
|
|
1926
|
+
homogeneous polynomial. Can be given as a single string of length 2,
|
|
1927
|
+
or a single string with a comma, or as a tuple or list of two strings.
|
|
1928
|
+
|
|
1929
|
+
- ``bivariate`` -- boolean (default: ``True``); whether to return a
|
|
1930
|
+
bivariate, homogeneous polynomial or just a univariate polynomial. If
|
|
1931
|
+
set to ``False``, then ``names`` will be interpreted as a single
|
|
1932
|
+
variable name and default to ``'x'``.
|
|
1933
|
+
|
|
1934
|
+
OUTPUT: the weight enumerator polynomial over `\ZZ`
|
|
1935
|
+
|
|
1936
|
+
EXAMPLES::
|
|
1937
|
+
|
|
1938
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
1939
|
+
sage: C.weight_enumerator()
|
|
1940
|
+
x^7 + 7*x^4*y^3 + 7*x^3*y^4 + y^7
|
|
1941
|
+
sage: C.weight_enumerator(names='st')
|
|
1942
|
+
s^7 + 7*s^4*t^3 + 7*s^3*t^4 + t^7
|
|
1943
|
+
sage: C.weight_enumerator(names="var1, var2")
|
|
1944
|
+
var1^7 + 7*var1^4*var2^3 + 7*var1^3*var2^4 + var2^7
|
|
1945
|
+
sage: C.weight_enumerator(names=('var1', 'var2'))
|
|
1946
|
+
var1^7 + 7*var1^4*var2^3 + 7*var1^3*var2^4 + var2^7
|
|
1947
|
+
sage: C.weight_enumerator(bivariate=False)
|
|
1948
|
+
x^7 + 7*x^4 + 7*x^3 + 1
|
|
1949
|
+
|
|
1950
|
+
An example of a code with a non-symmetrical weight enumerator::
|
|
1951
|
+
|
|
1952
|
+
sage: C = codes.GolayCode(GF(3), extended=False)
|
|
1953
|
+
sage: C.weight_enumerator()
|
|
1954
|
+
24*x^11 + 110*x^9*y^2 + 330*x^8*y^3 + 132*x^6*y^5 + 132*x^5*y^6 + y^11
|
|
1955
|
+
"""
|
|
1956
|
+
if names is None:
|
|
1957
|
+
if bivariate:
|
|
1958
|
+
names = "xy"
|
|
1959
|
+
else:
|
|
1960
|
+
names = "x"
|
|
1961
|
+
spec = self.weight_distribution()
|
|
1962
|
+
n = self.length()
|
|
1963
|
+
if bivariate:
|
|
1964
|
+
R = PolynomialRing(ZZ,2,names)
|
|
1965
|
+
x,y = R.gens()
|
|
1966
|
+
return sum(spec[i]*x**i*y**(n-i) for i in range(n+1))
|
|
1967
|
+
else:
|
|
1968
|
+
R = PolynomialRing(ZZ,names)
|
|
1969
|
+
x, = R.gens()
|
|
1970
|
+
return sum(spec[i]*x**i for i in range(n+1))
|
|
1971
|
+
|
|
1972
|
+
def zeta_polynomial(self, name='T'):
|
|
1973
|
+
r"""
|
|
1974
|
+
Return the Duursma zeta polynomial of this code.
|
|
1975
|
+
|
|
1976
|
+
Assumes that the minimum distances of this code and its dual are
|
|
1977
|
+
greater than 1. Prints a warning to ``stdout`` otherwise.
|
|
1978
|
+
|
|
1979
|
+
INPUT:
|
|
1980
|
+
|
|
1981
|
+
- ``name`` -- string (default: ``'T'``); variable name
|
|
1982
|
+
|
|
1983
|
+
OUTPUT: polynomial over `\QQ`
|
|
1984
|
+
|
|
1985
|
+
EXAMPLES::
|
|
1986
|
+
|
|
1987
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
1988
|
+
sage: C.zeta_polynomial() # needs sage.libs.gap
|
|
1989
|
+
2/5*T^2 + 2/5*T + 1/5
|
|
1990
|
+
|
|
1991
|
+
sage: C = codes.databases.best_linear_code_in_guava(6, 3, GF(2)) # optional - gap_package_guava
|
|
1992
|
+
sage: C.minimum_distance() # optional - gap_package_guava
|
|
1993
|
+
3
|
|
1994
|
+
sage: C.zeta_polynomial() # optional - gap_package_guava
|
|
1995
|
+
2/5*T^2 + 2/5*T + 1/5
|
|
1996
|
+
|
|
1997
|
+
sage: C = codes.HammingCode(GF(2), 4)
|
|
1998
|
+
sage: C.zeta_polynomial() # needs sage.libs.gap
|
|
1999
|
+
16/429*T^6 + 16/143*T^5 + 80/429*T^4 + 32/143*T^3 + 30/143*T^2 + 2/13*T + 1/13
|
|
2000
|
+
|
|
2001
|
+
sage: F.<z> = GF(4,"z")
|
|
2002
|
+
sage: MS = MatrixSpace(F, 3, 6)
|
|
2003
|
+
sage: G = MS([[1,0,0,1,z,z],[0,1,0,z,1,z],[0,0,1,z,z,1]])
|
|
2004
|
+
sage: C = LinearCode(G) # the "hexacode"
|
|
2005
|
+
sage: C.zeta_polynomial() # needs sage.libs.gap
|
|
2006
|
+
1
|
|
2007
|
+
|
|
2008
|
+
REFERENCES:
|
|
2009
|
+
|
|
2010
|
+
- [Du2001]_
|
|
2011
|
+
"""
|
|
2012
|
+
n = self.length()
|
|
2013
|
+
q = (self.base_ring()).order()
|
|
2014
|
+
d = self.minimum_distance()
|
|
2015
|
+
dperp = (self.dual_code()).minimum_distance()
|
|
2016
|
+
if d == 1 or dperp == 1:
|
|
2017
|
+
print("\n WARNING: There is no guarantee this function works when the minimum distance")
|
|
2018
|
+
print(" of the code or of the dual code equals 1.\n")
|
|
2019
|
+
RT = PolynomialRing(QQ, "%s" % name)
|
|
2020
|
+
R = PolynomialRing(QQ, 3, "xy%s" % name)
|
|
2021
|
+
x, y, T = R.gens()
|
|
2022
|
+
we = self.weight_enumerator()
|
|
2023
|
+
A = R(we)
|
|
2024
|
+
# B = A(x+y,y,T)-(x+y)**n
|
|
2025
|
+
B = A(x, x+y, T)-(x+y)**n
|
|
2026
|
+
Bs = B.coefficients()
|
|
2027
|
+
Bs.reverse()
|
|
2028
|
+
b = [Bs[i]/binomial(n, i+d) for i in range(len(Bs))]
|
|
2029
|
+
r = n-d-dperp+2
|
|
2030
|
+
P_coeffs = []
|
|
2031
|
+
for i in range(len(b)):
|
|
2032
|
+
if i == 0:
|
|
2033
|
+
P_coeffs.append(b[0])
|
|
2034
|
+
if i == 1:
|
|
2035
|
+
P_coeffs.append(b[1] - (q+1)*b[0])
|
|
2036
|
+
if i > 1:
|
|
2037
|
+
P_coeffs.append(b[i] - (q+1)*b[i-1] + q*b[i-2])
|
|
2038
|
+
P = sum([P_coeffs[i]*T**i for i in range(r+1)])
|
|
2039
|
+
return RT(P) / RT(P)(1)
|
|
2040
|
+
|
|
2041
|
+
def zeta_function(self, name='T'):
|
|
2042
|
+
r"""
|
|
2043
|
+
Return the Duursma zeta function of the code.
|
|
2044
|
+
|
|
2045
|
+
INPUT:
|
|
2046
|
+
|
|
2047
|
+
- ``name`` -- string (default: ``'T'``); variable name
|
|
2048
|
+
|
|
2049
|
+
OUTPUT:
|
|
2050
|
+
|
|
2051
|
+
Element of `\QQ(T)`
|
|
2052
|
+
|
|
2053
|
+
EXAMPLES::
|
|
2054
|
+
|
|
2055
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
2056
|
+
sage: C.zeta_function() # needs sage.libs.gap
|
|
2057
|
+
(1/5*T^2 + 1/5*T + 1/10)/(T^2 - 3/2*T + 1/2)
|
|
2058
|
+
"""
|
|
2059
|
+
P = self.zeta_polynomial()
|
|
2060
|
+
q = self.base_ring().characteristic()
|
|
2061
|
+
RT = PolynomialRing(QQ, name)
|
|
2062
|
+
T = RT.gen()
|
|
2063
|
+
return P/((1-T)*(1-q*T))
|
|
2064
|
+
|
|
2065
|
+
def cosetGraph(self):
|
|
2066
|
+
r"""
|
|
2067
|
+
Return the coset graph of this linear code.
|
|
2068
|
+
|
|
2069
|
+
The coset graph of a linear code `C` is the graph whose vertices
|
|
2070
|
+
are the cosets of `C`, considered as a subgroup of the additive
|
|
2071
|
+
group of the ambient vector space, and two cosets are adjacent
|
|
2072
|
+
if they have representatives that differ in exactly one coordinate.
|
|
2073
|
+
|
|
2074
|
+
EXAMPLES::
|
|
2075
|
+
|
|
2076
|
+
sage: # needs sage.graphs
|
|
2077
|
+
sage: C = codes.GolayCode(GF(3))
|
|
2078
|
+
sage: G = C.cosetGraph()
|
|
2079
|
+
sage: G.is_distance_regular()
|
|
2080
|
+
True
|
|
2081
|
+
sage: C = codes.KasamiCode(8,2)
|
|
2082
|
+
sage: G = C.cosetGraph()
|
|
2083
|
+
sage: G.is_distance_regular()
|
|
2084
|
+
True
|
|
2085
|
+
|
|
2086
|
+
ALGORITHM:
|
|
2087
|
+
|
|
2088
|
+
Instead of working with cosets we compute a (direct sum) complement
|
|
2089
|
+
of `C`. Let `P` be the projection of the cosets to the newly found
|
|
2090
|
+
subspace. Then two vectors are adjacent if they differ by
|
|
2091
|
+
`\lambda P(e_i)` for some `i`.
|
|
2092
|
+
|
|
2093
|
+
TESTS::
|
|
2094
|
+
|
|
2095
|
+
sage: # needs sage.graphs
|
|
2096
|
+
sage: C = codes.KasamiCode(4,2)
|
|
2097
|
+
sage: C.cosetGraph()
|
|
2098
|
+
Hamming Graph with parameters 4,2: Graph on 16 vertices
|
|
2099
|
+
sage: M = matrix.identity(GF(3), 7)
|
|
2100
|
+
sage: C = LinearCode(M)
|
|
2101
|
+
sage: G = C.cosetGraph()
|
|
2102
|
+
sage: G.vertices(sort=False)
|
|
2103
|
+
[0]
|
|
2104
|
+
sage: G.edges(sort=False)
|
|
2105
|
+
[]
|
|
2106
|
+
"""
|
|
2107
|
+
from sage.matrix.constructor import matrix
|
|
2108
|
+
from sage.graphs.graph import Graph
|
|
2109
|
+
|
|
2110
|
+
F = self.base_field()
|
|
2111
|
+
|
|
2112
|
+
def e(i):
|
|
2113
|
+
v = [0]*self.length()
|
|
2114
|
+
v[i-1] = 1
|
|
2115
|
+
return vector(F, v, immutable=True)
|
|
2116
|
+
|
|
2117
|
+
# Handle special cases
|
|
2118
|
+
if len(self.basis()) == self.length():
|
|
2119
|
+
G = Graph(1)
|
|
2120
|
+
G.name(f"coset graph of {self.__repr__()}")
|
|
2121
|
+
return G
|
|
2122
|
+
if len(self.basis()) == 0:
|
|
2123
|
+
from sage.graphs.graph_generators import GraphGenerators
|
|
2124
|
+
return GraphGenerators.HammingGraph(self.length(), F.order())
|
|
2125
|
+
|
|
2126
|
+
# we need to find a basis for the complement
|
|
2127
|
+
M = matrix(F, self.basis())
|
|
2128
|
+
M.echelonize()
|
|
2129
|
+
C_basis = M.rows()
|
|
2130
|
+
|
|
2131
|
+
# we use Steinitz exchange lemma on [e_1, ..., e_n]
|
|
2132
|
+
# to obtain a basis of V which includes C_basis
|
|
2133
|
+
U_basis = list(range(self.length())) # i represents e_{i+1}
|
|
2134
|
+
for v in C_basis:
|
|
2135
|
+
i = v.support()[0]
|
|
2136
|
+
U_basis.remove(i) # swap e_{i+1} with v
|
|
2137
|
+
U_basis = [e(i + 1) for i in U_basis]
|
|
2138
|
+
|
|
2139
|
+
V = VectorSpace(F, self.length())
|
|
2140
|
+
U = V.span(U_basis)
|
|
2141
|
+
vertices = list(U)
|
|
2142
|
+
|
|
2143
|
+
# build matrix whose columns are the basis of U and C
|
|
2144
|
+
A = matrix(F, U_basis)
|
|
2145
|
+
A = A.stack(matrix(F, C_basis))
|
|
2146
|
+
A = A.transpose()
|
|
2147
|
+
Ainv = A.inverse()
|
|
2148
|
+
|
|
2149
|
+
Pei = [] # projection of e_i on U
|
|
2150
|
+
for i in range(1, self.length() + 1):
|
|
2151
|
+
ei = e(i)
|
|
2152
|
+
if ei in U:
|
|
2153
|
+
Pei.append(ei)
|
|
2154
|
+
else:
|
|
2155
|
+
a = Ainv * ei
|
|
2156
|
+
# get zero vector and sum a[i]u_i to it
|
|
2157
|
+
v = vector(F, [0] * self.length())
|
|
2158
|
+
for ai, Ui in zip(a, U_basis):
|
|
2159
|
+
v += ai * Ui
|
|
2160
|
+
if not v.is_zero(): # don't care about 0 vectors
|
|
2161
|
+
v.set_immutable()
|
|
2162
|
+
Pei.append(v)
|
|
2163
|
+
|
|
2164
|
+
lPei = [l*u for l in F for u in Pei if not l.is_zero()]
|
|
2165
|
+
|
|
2166
|
+
edges = []
|
|
2167
|
+
for v in vertices:
|
|
2168
|
+
v.set_immutable()
|
|
2169
|
+
for u in lPei:
|
|
2170
|
+
w = v + u
|
|
2171
|
+
w.set_immutable()
|
|
2172
|
+
edges.append((v, w))
|
|
2173
|
+
|
|
2174
|
+
G = Graph(edges, format='list_of_edges')
|
|
2175
|
+
G.name(f"coset graph of {self.__repr__()}")
|
|
2176
|
+
return G
|
|
2177
|
+
|
|
2178
|
+
|
|
2179
|
+
# ########################### linear codes python class ########################
|
|
2180
|
+
|
|
2181
|
+
class LinearCode(AbstractLinearCode):
|
|
2182
|
+
r"""
|
|
2183
|
+
Linear codes over a finite field or finite ring, represented using a
|
|
2184
|
+
generator matrix.
|
|
2185
|
+
|
|
2186
|
+
This class should be used for arbitrary and unstructured linear codes. This
|
|
2187
|
+
means that basic operations on the code, such as the computation of the
|
|
2188
|
+
minimum distance, will use generic, slow algorithms.
|
|
2189
|
+
|
|
2190
|
+
If you are looking for constructing a code from a more specific family, see
|
|
2191
|
+
if the family has been implemented by investigating ``codes.<tab>``. These
|
|
2192
|
+
more specific classes use properties particular to that family to allow
|
|
2193
|
+
faster algorithms, and could also have family-specific methods.
|
|
2194
|
+
|
|
2195
|
+
See :wikipedia:`Linear_code` for more information on unstructured linear codes.
|
|
2196
|
+
|
|
2197
|
+
INPUT:
|
|
2198
|
+
|
|
2199
|
+
- ``generator`` -- a generator matrix over a finite field (``G`` can be
|
|
2200
|
+
defined over a finite ring but the matrices over that ring must have
|
|
2201
|
+
certain attributes, such as ``rank``) or a code over a finite field
|
|
2202
|
+
|
|
2203
|
+
- ``d`` -- (default: ``None``) the minimum distance of the code
|
|
2204
|
+
|
|
2205
|
+
.. NOTE::
|
|
2206
|
+
|
|
2207
|
+
The veracity of the minimum distance ``d``, if provided, is not
|
|
2208
|
+
checked.
|
|
2209
|
+
|
|
2210
|
+
EXAMPLES::
|
|
2211
|
+
|
|
2212
|
+
sage: MS = MatrixSpace(GF(2),4,7)
|
|
2213
|
+
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
2214
|
+
sage: C = LinearCode(G)
|
|
2215
|
+
sage: C
|
|
2216
|
+
[7, 4] linear code over GF(2)
|
|
2217
|
+
sage: C.base_ring()
|
|
2218
|
+
Finite Field of size 2
|
|
2219
|
+
sage: C.dimension()
|
|
2220
|
+
4
|
|
2221
|
+
sage: C.length()
|
|
2222
|
+
7
|
|
2223
|
+
sage: C.minimum_distance() # needs sage.libs.gap
|
|
2224
|
+
3
|
|
2225
|
+
sage: C.spectrum()
|
|
2226
|
+
[1, 0, 0, 7, 7, 0, 0, 1]
|
|
2227
|
+
sage: C.weight_distribution()
|
|
2228
|
+
[1, 0, 0, 7, 7, 0, 0, 1]
|
|
2229
|
+
|
|
2230
|
+
The minimum distance of the code, if known, can be provided as an
|
|
2231
|
+
optional parameter.::
|
|
2232
|
+
|
|
2233
|
+
sage: C = LinearCode(G, d=3)
|
|
2234
|
+
sage: C.minimum_distance() # needs sage.libs.gap
|
|
2235
|
+
3
|
|
2236
|
+
|
|
2237
|
+
Another example.::
|
|
2238
|
+
|
|
2239
|
+
sage: MS = MatrixSpace(GF(5),4,7)
|
|
2240
|
+
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
2241
|
+
sage: C = LinearCode(G); C
|
|
2242
|
+
[7, 4] linear code over GF(5)
|
|
2243
|
+
|
|
2244
|
+
Providing a code as the parameter in order to "forget" its structure (see
|
|
2245
|
+
:issue:`20198`)::
|
|
2246
|
+
|
|
2247
|
+
sage: C = codes.GeneralizedReedSolomonCode(GF(23).list(), 12)
|
|
2248
|
+
sage: LinearCode(C)
|
|
2249
|
+
[23, 12] linear code over GF(23)
|
|
2250
|
+
|
|
2251
|
+
Another example::
|
|
2252
|
+
|
|
2253
|
+
sage: C = codes.HammingCode(GF(7), 3)
|
|
2254
|
+
sage: C
|
|
2255
|
+
[57, 54] Hamming Code over GF(7)
|
|
2256
|
+
sage: LinearCode(C)
|
|
2257
|
+
[57, 54] linear code over GF(7)
|
|
2258
|
+
|
|
2259
|
+
AUTHORS:
|
|
2260
|
+
|
|
2261
|
+
- David Joyner (11-2005)
|
|
2262
|
+
- Charles Prior (03-2016): :issue:`20198`, LinearCode from a code
|
|
2263
|
+
"""
|
|
2264
|
+
def __init__(self, generator, d=None):
|
|
2265
|
+
r"""
|
|
2266
|
+
See the docstring for :meth:`LinearCode`.
|
|
2267
|
+
|
|
2268
|
+
EXAMPLES::
|
|
2269
|
+
|
|
2270
|
+
sage: MS = MatrixSpace(GF(2),4,7)
|
|
2271
|
+
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
2272
|
+
sage: C = LinearCode(G) # indirect doctest
|
|
2273
|
+
sage: C
|
|
2274
|
+
[7, 4] linear code over GF(2)
|
|
2275
|
+
|
|
2276
|
+
The minimum distance of the code, if known, can be provided as an
|
|
2277
|
+
optional parameter.::
|
|
2278
|
+
|
|
2279
|
+
sage: C = LinearCode(G, d=3)
|
|
2280
|
+
sage: C.minimum_distance() # needs sage.libs.gap
|
|
2281
|
+
3
|
|
2282
|
+
|
|
2283
|
+
TESTS::
|
|
2284
|
+
|
|
2285
|
+
sage: C = codes.HammingCode(GF(2), 3)
|
|
2286
|
+
sage: TestSuite(C).run()
|
|
2287
|
+
|
|
2288
|
+
Check that it works even with input matrix with non full rank (see
|
|
2289
|
+
:issue:`17452`)::
|
|
2290
|
+
|
|
2291
|
+
sage: K.<a> = GF(4)
|
|
2292
|
+
sage: G = matrix([[a, a + 1, 1, a + 1, 1, 0, 0],
|
|
2293
|
+
....: [0, a, a + 1, 1, a + 1, 1, 0],
|
|
2294
|
+
....: [0, 0, a, a + 1, 1, a + 1, 1],
|
|
2295
|
+
....: [a + 1, 0, 1, 0, a + 1, 1, a + 1],
|
|
2296
|
+
....: [a, a + 1, a + 1, 0, 0, a + 1, 1],
|
|
2297
|
+
....: [a + 1, a, a, 1, 0, 0, a + 1],
|
|
2298
|
+
....: [a, a + 1, 1, a + 1, 1, 0, 0]])
|
|
2299
|
+
sage: C = LinearCode(G)
|
|
2300
|
+
sage: C.basis()
|
|
2301
|
+
[(1, 0, 0, a + 1, 0, 1, 0),
|
|
2302
|
+
(0, 1, 0, 0, a + 1, 0, 1),
|
|
2303
|
+
(0, 0, 1, a, a + 1, a, a + 1)]
|
|
2304
|
+
sage: C.minimum_distance() # needs sage.libs.gap
|
|
2305
|
+
3
|
|
2306
|
+
|
|
2307
|
+
We can construct a linear code directly from a vector space::
|
|
2308
|
+
|
|
2309
|
+
sage: VS = matrix(GF(2), [[1,0,1],
|
|
2310
|
+
....: [1,0,1]]).row_space()
|
|
2311
|
+
sage: C = LinearCode(VS); C
|
|
2312
|
+
[3, 1] linear code over GF(2)
|
|
2313
|
+
|
|
2314
|
+
Forbid the zero vector space (see :issue:`17452` and :issue:`6486`)::
|
|
2315
|
+
|
|
2316
|
+
sage: G = matrix(GF(2), [[0,0,0]])
|
|
2317
|
+
sage: C = LinearCode(G)
|
|
2318
|
+
Traceback (most recent call last):
|
|
2319
|
+
...
|
|
2320
|
+
ValueError: this linear code contains no nonzero vector
|
|
2321
|
+
"""
|
|
2322
|
+
|
|
2323
|
+
base_ring = generator.base_ring()
|
|
2324
|
+
if not base_ring.is_field():
|
|
2325
|
+
raise ValueError("'generator' must be defined on a field (not a ring)")
|
|
2326
|
+
|
|
2327
|
+
try:
|
|
2328
|
+
basis = None
|
|
2329
|
+
if hasattr(generator, "nrows"): # generator matrix case
|
|
2330
|
+
if generator.rank() < generator.nrows():
|
|
2331
|
+
basis = generator.row_space().basis()
|
|
2332
|
+
else:
|
|
2333
|
+
basis = generator.basis() # vector space etc. case
|
|
2334
|
+
if basis is not None:
|
|
2335
|
+
from sage.matrix.constructor import matrix
|
|
2336
|
+
generator = matrix(base_ring, basis)
|
|
2337
|
+
if generator.nrows() == 0:
|
|
2338
|
+
raise ValueError("this linear code contains no nonzero vector")
|
|
2339
|
+
except AttributeError:
|
|
2340
|
+
# Assume input is an AbstractLinearCode, extract its generator matrix
|
|
2341
|
+
generator = generator.generator_matrix()
|
|
2342
|
+
|
|
2343
|
+
super().__init__(base_ring, generator.ncols(),
|
|
2344
|
+
"GeneratorMatrix", "Syndrome")
|
|
2345
|
+
self._generator_matrix = generator
|
|
2346
|
+
self._dimension = generator.rank()
|
|
2347
|
+
self._minimum_distance = d
|
|
2348
|
+
|
|
2349
|
+
def __hash__(self):
|
|
2350
|
+
Str = str(self)
|
|
2351
|
+
G = self.generator_matrix()
|
|
2352
|
+
return hash((Str, G))
|
|
2353
|
+
|
|
2354
|
+
def _repr_(self):
|
|
2355
|
+
r"""
|
|
2356
|
+
See the docstring for :meth:`LinearCode`.
|
|
2357
|
+
|
|
2358
|
+
EXAMPLES::
|
|
2359
|
+
|
|
2360
|
+
sage: MS = MatrixSpace(GF(2),4,7)
|
|
2361
|
+
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
2362
|
+
sage: C = LinearCode(G)
|
|
2363
|
+
sage: C # indirect doctest
|
|
2364
|
+
[7, 4] linear code over GF(2)
|
|
2365
|
+
"""
|
|
2366
|
+
R = self.base_ring()
|
|
2367
|
+
if R in Fields():
|
|
2368
|
+
return "[%s, %s] linear code over GF(%s)" % (self.length(), self.dimension(), R.cardinality())
|
|
2369
|
+
else:
|
|
2370
|
+
return "[%s, %s] linear code over %s" % (self.length(), self.dimension(), R)
|
|
2371
|
+
|
|
2372
|
+
def _latex_(self):
|
|
2373
|
+
r"""
|
|
2374
|
+
Return a latex representation of ``self``.
|
|
2375
|
+
|
|
2376
|
+
EXAMPLES::
|
|
2377
|
+
|
|
2378
|
+
sage: MS = MatrixSpace(GF(2),4,7)
|
|
2379
|
+
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
2380
|
+
sage: C = LinearCode(G)
|
|
2381
|
+
sage: latex(C)
|
|
2382
|
+
[7, 4]\textnormal{ Linear code over }\Bold{F}_{2}
|
|
2383
|
+
"""
|
|
2384
|
+
return "[%s, %s]\\textnormal{ Linear code over }%s"\
|
|
2385
|
+
% (self.length(), self.dimension(), self.base_ring()._latex_())
|
|
2386
|
+
|
|
2387
|
+
def generator_matrix(self, encoder_name=None, **kwargs):
|
|
2388
|
+
r"""
|
|
2389
|
+
Return a generator matrix of ``self``.
|
|
2390
|
+
|
|
2391
|
+
INPUT:
|
|
2392
|
+
|
|
2393
|
+
- ``encoder_name`` -- (default: ``None``) name of the encoder which will be
|
|
2394
|
+
used to compute the generator matrix. ``self._generator_matrix``
|
|
2395
|
+
will be returned if default value is kept.
|
|
2396
|
+
|
|
2397
|
+
- ``kwargs`` -- all additional arguments are forwarded to the construction of the
|
|
2398
|
+
encoder that is used
|
|
2399
|
+
|
|
2400
|
+
EXAMPLES::
|
|
2401
|
+
|
|
2402
|
+
sage: G = matrix(GF(3),2,[1,-1,1,-1,1,1])
|
|
2403
|
+
sage: code = LinearCode(G)
|
|
2404
|
+
sage: code.generator_matrix()
|
|
2405
|
+
[1 2 1]
|
|
2406
|
+
[2 1 1]
|
|
2407
|
+
"""
|
|
2408
|
+
if encoder_name is None or encoder_name == 'GeneratorMatrix':
|
|
2409
|
+
g = self._generator_matrix
|
|
2410
|
+
else:
|
|
2411
|
+
g = super().generator_matrix(encoder_name, **kwargs)
|
|
2412
|
+
g.set_immutable()
|
|
2413
|
+
return g
|
|
2414
|
+
|
|
2415
|
+
|
|
2416
|
+
# ###################### encoders ###############################
|
|
2417
|
+
|
|
2418
|
+
class LinearCodeGeneratorMatrixEncoder(Encoder):
|
|
2419
|
+
r"""
|
|
2420
|
+
Encoder based on generator_matrix for Linear codes.
|
|
2421
|
+
|
|
2422
|
+
This is the default encoder of a generic linear code, and should never be used for other codes than
|
|
2423
|
+
:class:`LinearCode`.
|
|
2424
|
+
|
|
2425
|
+
INPUT:
|
|
2426
|
+
|
|
2427
|
+
- ``code`` -- the associated :class:`LinearCode` of this encoder
|
|
2428
|
+
"""
|
|
2429
|
+
|
|
2430
|
+
def __init__(self, code):
|
|
2431
|
+
r"""
|
|
2432
|
+
EXAMPLES::
|
|
2433
|
+
|
|
2434
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
|
|
2435
|
+
sage: C = LinearCode(G)
|
|
2436
|
+
sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C)
|
|
2437
|
+
sage: E
|
|
2438
|
+
Generator matrix-based encoder for [7, 4] linear code over GF(2)
|
|
2439
|
+
"""
|
|
2440
|
+
super().__init__(code)
|
|
2441
|
+
|
|
2442
|
+
def __eq__(self, other):
|
|
2443
|
+
r"""
|
|
2444
|
+
Test equality between LinearCodeGeneratorMatrixEncoder objects.
|
|
2445
|
+
|
|
2446
|
+
EXAMPLES::
|
|
2447
|
+
|
|
2448
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
|
|
2449
|
+
sage: E1 = LinearCode(G).encoder()
|
|
2450
|
+
sage: E2 = LinearCode(G).encoder()
|
|
2451
|
+
sage: E1 == E2
|
|
2452
|
+
True
|
|
2453
|
+
"""
|
|
2454
|
+
return isinstance(other, LinearCodeGeneratorMatrixEncoder)\
|
|
2455
|
+
and self.code() == other.code()
|
|
2456
|
+
|
|
2457
|
+
def _repr_(self):
|
|
2458
|
+
r"""
|
|
2459
|
+
Return a string representation of ``self``.
|
|
2460
|
+
|
|
2461
|
+
EXAMPLES::
|
|
2462
|
+
|
|
2463
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
|
|
2464
|
+
sage: C = LinearCode(G)
|
|
2465
|
+
sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C)
|
|
2466
|
+
sage: E
|
|
2467
|
+
Generator matrix-based encoder for [7, 4] linear code over GF(2)
|
|
2468
|
+
"""
|
|
2469
|
+
return "Generator matrix-based encoder for %s" % self.code()
|
|
2470
|
+
|
|
2471
|
+
def _latex_(self):
|
|
2472
|
+
r"""
|
|
2473
|
+
Return a latex representation of ``self``.
|
|
2474
|
+
|
|
2475
|
+
EXAMPLES::
|
|
2476
|
+
|
|
2477
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
|
|
2478
|
+
sage: C = LinearCode(G)
|
|
2479
|
+
sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C)
|
|
2480
|
+
sage: latex(E)
|
|
2481
|
+
\textnormal{Generator matrix-based encoder for }[7, 4]\textnormal{ Linear code over }\Bold{F}_{2}
|
|
2482
|
+
"""
|
|
2483
|
+
return "\\textnormal{Generator matrix-based encoder for }%s" % self.code()._latex_()
|
|
2484
|
+
|
|
2485
|
+
@cached_method
|
|
2486
|
+
def generator_matrix(self):
|
|
2487
|
+
r"""
|
|
2488
|
+
Return a generator matrix of the associated code of ``self``.
|
|
2489
|
+
|
|
2490
|
+
EXAMPLES::
|
|
2491
|
+
|
|
2492
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0],
|
|
2493
|
+
....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
2494
|
+
sage: C = LinearCode(G)
|
|
2495
|
+
sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C)
|
|
2496
|
+
sage: E.generator_matrix()
|
|
2497
|
+
[1 1 1 0 0 0 0]
|
|
2498
|
+
[1 0 0 1 1 0 0]
|
|
2499
|
+
[0 1 0 1 0 1 0]
|
|
2500
|
+
[1 1 0 1 0 0 1]
|
|
2501
|
+
"""
|
|
2502
|
+
g = self.code().generator_matrix()
|
|
2503
|
+
g.set_immutable()
|
|
2504
|
+
return g
|
|
2505
|
+
|
|
2506
|
+
|
|
2507
|
+
# ###################### decoders ###############################
|
|
2508
|
+
|
|
2509
|
+
class LinearCodeSyndromeDecoder(Decoder):
|
|
2510
|
+
r"""
|
|
2511
|
+
Construct a decoder for Linear Codes based on syndrome lookup table.
|
|
2512
|
+
|
|
2513
|
+
The decoding algorithm works as follows:
|
|
2514
|
+
|
|
2515
|
+
- First, a lookup table is built by computing the syndrome of every error
|
|
2516
|
+
pattern of weight up to ``maximum_error_weight``.
|
|
2517
|
+
- Then, whenever one tries to decode a word ``r``, the syndrome of ``r`` is
|
|
2518
|
+
computed. The corresponding error pattern is recovered from the
|
|
2519
|
+
pre-computed lookup table.
|
|
2520
|
+
- Finally, the recovered error pattern is subtracted from ``r`` to recover
|
|
2521
|
+
the original word.
|
|
2522
|
+
|
|
2523
|
+
``maximum_error_weight`` need never exceed the covering radius of the code,
|
|
2524
|
+
since there are then always lower-weight errors with the same syndrome. If
|
|
2525
|
+
one sets ``maximum_error_weight`` to a value greater than the covering
|
|
2526
|
+
radius, then the covering radius will be determined while building the
|
|
2527
|
+
lookup-table. This lower value is then returned if you query
|
|
2528
|
+
``decoding_radius`` after construction.
|
|
2529
|
+
|
|
2530
|
+
If ``maximum_error_weight`` is left unspecified or set to a number at least
|
|
2531
|
+
the covering radius of the code, this decoder is complete, i.e. it decodes
|
|
2532
|
+
every vector in the ambient space.
|
|
2533
|
+
|
|
2534
|
+
.. NOTE::
|
|
2535
|
+
|
|
2536
|
+
Constructing the lookup table takes time exponential in the length of the
|
|
2537
|
+
code and the size of the code's base field. Afterwards, the individual
|
|
2538
|
+
decodings are fast.
|
|
2539
|
+
|
|
2540
|
+
INPUT:
|
|
2541
|
+
|
|
2542
|
+
- ``code`` -- a code associated to this decoder
|
|
2543
|
+
|
|
2544
|
+
- ``maximum_error_weight`` -- (default: ``None``) the maximum number of
|
|
2545
|
+
errors to look for when building the table. An error is raised if it is
|
|
2546
|
+
set greater than `n-k`, since this is an upper bound on the covering
|
|
2547
|
+
radius on any linear code. If ``maximum_error_weight`` is kept
|
|
2548
|
+
unspecified, it will be set to `n - k`, where `n` is the length of
|
|
2549
|
+
``code`` and `k` its dimension.
|
|
2550
|
+
|
|
2551
|
+
EXAMPLES::
|
|
2552
|
+
|
|
2553
|
+
sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2],
|
|
2554
|
+
....: [0,1,0,2,2,0,1,1,0],
|
|
2555
|
+
....: [0,0,1,0,2,2,2,1,2]])
|
|
2556
|
+
sage: C = LinearCode(G)
|
|
2557
|
+
sage: D = codes.decoders.LinearCodeSyndromeDecoder(C)
|
|
2558
|
+
sage: D
|
|
2559
|
+
Syndrome decoder for [9, 3] linear code over GF(3) handling errors of weight up to 4
|
|
2560
|
+
|
|
2561
|
+
If one wants to correct up to a lower number of errors, one can do as follows::
|
|
2562
|
+
|
|
2563
|
+
sage: D = codes.decoders.LinearCodeSyndromeDecoder(C, maximum_error_weight=2)
|
|
2564
|
+
sage: D
|
|
2565
|
+
Syndrome decoder for [9, 3] linear code over GF(3) handling errors of weight up to 2
|
|
2566
|
+
|
|
2567
|
+
If one checks the list of types of this decoder before constructing it,
|
|
2568
|
+
one will notice it contains the keyword ``dynamic``.
|
|
2569
|
+
Indeed, the behaviour of the syndrome decoder depends on the maximum
|
|
2570
|
+
error weight one wants to handle, and how it compares to the minimum
|
|
2571
|
+
distance and the covering radius of ``code``.
|
|
2572
|
+
In the following examples, we illustrate this property by computing
|
|
2573
|
+
different instances of syndrome decoder for the same code.
|
|
2574
|
+
|
|
2575
|
+
We choose the following linear code, whose covering radius equals to 4
|
|
2576
|
+
and minimum distance to 5 (half the minimum distance is 2)::
|
|
2577
|
+
|
|
2578
|
+
sage: G = matrix(GF(5), [[1, 0, 0, 0, 0, 4, 3, 0, 3, 1, 0],
|
|
2579
|
+
....: [0, 1, 0, 0, 0, 3, 2, 2, 3, 2, 1],
|
|
2580
|
+
....: [0, 0, 1, 0, 0, 1, 3, 0, 1, 4, 1],
|
|
2581
|
+
....: [0, 0, 0, 1, 0, 3, 4, 2, 2, 3, 3],
|
|
2582
|
+
....: [0, 0, 0, 0, 1, 4, 2, 3, 2, 2, 1]])
|
|
2583
|
+
sage: C = LinearCode(G)
|
|
2584
|
+
|
|
2585
|
+
In the following examples, we illustrate how the choice of
|
|
2586
|
+
``maximum_error_weight`` influences the types of the instance of
|
|
2587
|
+
syndrome decoder, alongside with its decoding radius.
|
|
2588
|
+
|
|
2589
|
+
We build a first syndrome decoder, and pick a ``maximum_error_weight``
|
|
2590
|
+
smaller than both the covering radius and half the minimum distance::
|
|
2591
|
+
|
|
2592
|
+
sage: D = C.decoder("Syndrome", maximum_error_weight=1)
|
|
2593
|
+
sage: D.decoder_type()
|
|
2594
|
+
{'always-succeed', 'bounded_distance', 'hard-decision'}
|
|
2595
|
+
sage: D.decoding_radius()
|
|
2596
|
+
1
|
|
2597
|
+
|
|
2598
|
+
In that case, we are sure the decoder will always succeed. It is also
|
|
2599
|
+
a bounded distance decoder.
|
|
2600
|
+
|
|
2601
|
+
We now build another syndrome decoder, and this time,
|
|
2602
|
+
``maximum_error_weight`` is chosen to be bigger than half the minimum distance,
|
|
2603
|
+
but lower than the covering radius::
|
|
2604
|
+
|
|
2605
|
+
sage: D = C.decoder("Syndrome", maximum_error_weight=3)
|
|
2606
|
+
sage: D.decoder_type()
|
|
2607
|
+
{'bounded_distance', 'hard-decision', 'might-error'}
|
|
2608
|
+
sage: D.decoding_radius()
|
|
2609
|
+
3
|
|
2610
|
+
|
|
2611
|
+
Here, we still get a bounded distance decoder.
|
|
2612
|
+
But because we have a maximum error weight bigger than half the
|
|
2613
|
+
minimum distance, we know it might return a codeword which was not
|
|
2614
|
+
the original codeword.
|
|
2615
|
+
|
|
2616
|
+
And now, we build a third syndrome decoder, whose ``maximum_error_weight``
|
|
2617
|
+
is bigger than both the covering radius and half the minimum distance::
|
|
2618
|
+
|
|
2619
|
+
sage: D = C.decoder("Syndrome", maximum_error_weight=5) # long time
|
|
2620
|
+
sage: D.decoder_type() # long time
|
|
2621
|
+
{'complete', 'hard-decision', 'might-error'}
|
|
2622
|
+
sage: D.decoding_radius() # long time
|
|
2623
|
+
4
|
|
2624
|
+
|
|
2625
|
+
In that case, the decoder might still return an unexpected codeword, but
|
|
2626
|
+
it is now complete. Note the decoding radius is equal to 4: it was
|
|
2627
|
+
determined while building the syndrome lookup table that any error with
|
|
2628
|
+
weight more than 4 will be decoded incorrectly. That is because the covering
|
|
2629
|
+
radius for the code is 4.
|
|
2630
|
+
|
|
2631
|
+
The minimum distance and the covering radius are both determined while
|
|
2632
|
+
computing the syndrome lookup table. They user did not explicitly ask to
|
|
2633
|
+
compute these on the code ``C``. The dynamic typing of the syndrome decoder
|
|
2634
|
+
might therefore seem slightly surprising, but in the end is quite
|
|
2635
|
+
informative.
|
|
2636
|
+
"""
|
|
2637
|
+
|
|
2638
|
+
def __init__(self, code, maximum_error_weight=None):
|
|
2639
|
+
r"""
|
|
2640
|
+
TESTS:
|
|
2641
|
+
|
|
2642
|
+
If ``maximum_error_weight`` is greater or equal than `n-k`, where `n`
|
|
2643
|
+
is ``code``'s length, and `k` is ``code``'s dimension,
|
|
2644
|
+
an error is raised::
|
|
2645
|
+
|
|
2646
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
|
|
2647
|
+
sage: C = LinearCode(G)
|
|
2648
|
+
sage: D = codes.decoders.LinearCodeSyndromeDecoder(C, 42)
|
|
2649
|
+
Traceback (most recent call last):
|
|
2650
|
+
...
|
|
2651
|
+
ValueError: maximum_error_weight has to be less than code's length minus its dimension
|
|
2652
|
+
|
|
2653
|
+
The Syndrome Decoder of a Hamming code should have types
|
|
2654
|
+
``minimum-distance`` and ``always-succeed`` (see :issue:`20898`)::
|
|
2655
|
+
|
|
2656
|
+
sage: C = codes.HammingCode(GF(5), 3)
|
|
2657
|
+
sage: D = C.decoder("Syndrome")
|
|
2658
|
+
sage: C.minimum_distance()
|
|
2659
|
+
3
|
|
2660
|
+
sage: D.maximum_error_weight()
|
|
2661
|
+
1
|
|
2662
|
+
sage: D.decoder_type()
|
|
2663
|
+
{'always-succeed', 'complete', 'hard-decision', 'minimum-distance'}
|
|
2664
|
+
"""
|
|
2665
|
+
n_minus_k = code.length() - code.dimension()
|
|
2666
|
+
if maximum_error_weight is None:
|
|
2667
|
+
self._maximum_error_weight = n_minus_k
|
|
2668
|
+
elif not isinstance(maximum_error_weight, (Integer, int)):
|
|
2669
|
+
raise ValueError("maximum_error_weight has to be a Sage integer or a Python int")
|
|
2670
|
+
elif maximum_error_weight > n_minus_k:
|
|
2671
|
+
raise ValueError("maximum_error_weight has to be less than code's length minus its dimension")
|
|
2672
|
+
else:
|
|
2673
|
+
self._maximum_error_weight = maximum_error_weight
|
|
2674
|
+
super().__init__(code, code.ambient_space(), code._default_encoder_name)
|
|
2675
|
+
self._lookup_table = self._build_lookup_table()
|
|
2676
|
+
|
|
2677
|
+
def __eq__(self, other):
|
|
2678
|
+
r"""
|
|
2679
|
+
Test equality between LinearCodeSyndromeDecoder objects.
|
|
2680
|
+
|
|
2681
|
+
EXAMPLES::
|
|
2682
|
+
|
|
2683
|
+
sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2],[0,1,0,2,2,0,1,1,0],[0,0,1,0,2,2,2,1,2]])
|
|
2684
|
+
sage: D1 = codes.decoders.LinearCodeSyndromeDecoder(LinearCode(G))
|
|
2685
|
+
sage: D2 = codes.decoders.LinearCodeSyndromeDecoder(LinearCode(G))
|
|
2686
|
+
sage: D1 == D2
|
|
2687
|
+
True
|
|
2688
|
+
"""
|
|
2689
|
+
return (isinstance(other, LinearCodeSyndromeDecoder) and
|
|
2690
|
+
self.code() == other.code() and
|
|
2691
|
+
self.maximum_error_weight() == other.maximum_error_weight())
|
|
2692
|
+
|
|
2693
|
+
def __hash__(self):
|
|
2694
|
+
"""
|
|
2695
|
+
Return the hash of ``self``.
|
|
2696
|
+
|
|
2697
|
+
EXAMPLES::
|
|
2698
|
+
|
|
2699
|
+
sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2],[0,1,0,2,2,0,1,1,0],[0,0,1,0,2,2,2,1,2]])
|
|
2700
|
+
sage: D1 = codes.decoders.LinearCodeSyndromeDecoder(LinearCode(G))
|
|
2701
|
+
sage: D2 = codes.decoders.LinearCodeSyndromeDecoder(LinearCode(G))
|
|
2702
|
+
sage: hash(D1) == hash(D2)
|
|
2703
|
+
True
|
|
2704
|
+
"""
|
|
2705
|
+
return hash((self.code(), self.maximum_error_weight()))
|
|
2706
|
+
|
|
2707
|
+
def _repr_(self):
|
|
2708
|
+
r"""
|
|
2709
|
+
Return a string representation of ``self``.
|
|
2710
|
+
|
|
2711
|
+
EXAMPLES::
|
|
2712
|
+
|
|
2713
|
+
sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2],[0,1,0,2,2,0,1,1,0],[0,0,1,0,2,2,2,1,2]])
|
|
2714
|
+
sage: C = LinearCode(G)
|
|
2715
|
+
sage: D = codes.decoders.LinearCodeSyndromeDecoder(C)
|
|
2716
|
+
sage: D
|
|
2717
|
+
Syndrome decoder for [9, 3] linear code over GF(3) handling errors of weight up to 4
|
|
2718
|
+
"""
|
|
2719
|
+
return "Syndrome decoder for %s handling errors of weight up to %s" % (self.code(), self.maximum_error_weight())
|
|
2720
|
+
|
|
2721
|
+
def _latex_(self):
|
|
2722
|
+
r"""
|
|
2723
|
+
Return a latex representation of ``self``.
|
|
2724
|
+
|
|
2725
|
+
EXAMPLES::
|
|
2726
|
+
|
|
2727
|
+
sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2],[0,1,0,2,2,0,1,1,0],[0,0,1,0,2,2,2,1,2]])
|
|
2728
|
+
sage: C = LinearCode(G)
|
|
2729
|
+
sage: D = codes.decoders.LinearCodeSyndromeDecoder(C)
|
|
2730
|
+
sage: latex(D)
|
|
2731
|
+
\textnormal{Syndrome decoder for [9, 3]\textnormal{ Linear code over }\Bold{F}_{3} handling errors of weight up to 4}
|
|
2732
|
+
"""
|
|
2733
|
+
return "\\textnormal{Syndrome decoder for %s handling errors of weight up to %s}" % (self.code()._latex_(), self.maximum_error_weight())
|
|
2734
|
+
|
|
2735
|
+
@cached_method
|
|
2736
|
+
def _build_lookup_table(self):
|
|
2737
|
+
r"""
|
|
2738
|
+
Build lookup table for all possible error patterns of weight up to :meth:`maximum_error_weight`.
|
|
2739
|
+
|
|
2740
|
+
EXAMPLES::
|
|
2741
|
+
|
|
2742
|
+
sage: G = Matrix(GF(3),[
|
|
2743
|
+
....: [1, 0, 0, 0, 2, 2, 1, 1],
|
|
2744
|
+
....: [0, 1, 0, 0, 0, 0, 1, 1],
|
|
2745
|
+
....: [0, 0, 1, 0, 2, 0, 0, 2],
|
|
2746
|
+
....: [0, 0, 0, 1, 0, 2, 0, 1]])
|
|
2747
|
+
sage: C = LinearCode(G)
|
|
2748
|
+
sage: D = codes.decoders.LinearCodeSyndromeDecoder(C, maximum_error_weight = 1)
|
|
2749
|
+
sage: D._build_lookup_table()
|
|
2750
|
+
{(0, 0, 0, 0): (0, 0, 0, 0, 0, 0, 0, 0),
|
|
2751
|
+
(0, 0, 0, 1): (0, 0, 0, 0, 1, 0, 0, 0),
|
|
2752
|
+
(0, 0, 0, 2): (0, 0, 0, 0, 2, 0, 0, 0),
|
|
2753
|
+
(0, 0, 1, 0): (0, 0, 1, 0, 0, 0, 0, 0),
|
|
2754
|
+
(0, 0, 1, 2): (0, 0, 0, 0, 0, 0, 0, 1),
|
|
2755
|
+
(0, 0, 2, 0): (0, 0, 2, 0, 0, 0, 0, 0),
|
|
2756
|
+
(0, 0, 2, 1): (0, 0, 0, 0, 0, 0, 0, 2),
|
|
2757
|
+
(0, 1, 0, 0): (0, 1, 0, 0, 0, 0, 0, 0),
|
|
2758
|
+
(0, 1, 1, 2): (0, 0, 0, 0, 0, 0, 2, 0),
|
|
2759
|
+
(0, 2, 0, 0): (0, 2, 0, 0, 0, 0, 0, 0),
|
|
2760
|
+
(0, 2, 2, 1): (0, 0, 0, 0, 0, 0, 1, 0),
|
|
2761
|
+
(1, 0, 0, 0): (1, 0, 0, 0, 0, 0, 0, 0),
|
|
2762
|
+
(1, 2, 0, 2): (0, 0, 0, 0, 0, 1, 0, 0),
|
|
2763
|
+
(1, 2, 2, 0): (0, 0, 0, 1, 0, 0, 0, 0),
|
|
2764
|
+
(2, 0, 0, 0): (2, 0, 0, 0, 0, 0, 0, 0),
|
|
2765
|
+
(2, 1, 0, 1): (0, 0, 0, 0, 0, 2, 0, 0),
|
|
2766
|
+
(2, 1, 1, 0): (0, 0, 0, 2, 0, 0, 0, 0)}
|
|
2767
|
+
|
|
2768
|
+
TESTS:
|
|
2769
|
+
|
|
2770
|
+
Check that :issue:`24114` is fixed::
|
|
2771
|
+
|
|
2772
|
+
sage: R.<x> = PolynomialRing(GF(3))
|
|
2773
|
+
sage: f = x^2 + x + 2
|
|
2774
|
+
sage: K.<a> = f.root_field()
|
|
2775
|
+
sage: H = Matrix(K,[[1,2,1],[2*a+1,a,1]])
|
|
2776
|
+
sage: C = codes.from_parity_check_matrix(H)
|
|
2777
|
+
sage: D = codes.decoders.LinearCodeSyndromeDecoder(C)
|
|
2778
|
+
sage: D.syndrome_table()
|
|
2779
|
+
{(0, 0): (0, 0, 0),
|
|
2780
|
+
(0, 1): (0, 1, 0),
|
|
2781
|
+
(0, 2): (0, 2, 0),
|
|
2782
|
+
(0, a): (0, a, 0),
|
|
2783
|
+
...
|
|
2784
|
+
(2*a + 2, 2*a): (0, 0, 2),
|
|
2785
|
+
(2*a + 2, 2*a + 1): (2*a + 2, 2*a + 1, 0),
|
|
2786
|
+
(2*a + 2, 2*a + 2): (2*a + 2, 2*a + 2, 0)}
|
|
2787
|
+
"""
|
|
2788
|
+
t = self._maximum_error_weight
|
|
2789
|
+
self._code_covering_radius = None
|
|
2790
|
+
self._code_minimum_distance = None
|
|
2791
|
+
self._decoder_type = copy(self._decoder_type)
|
|
2792
|
+
self._decoder_type.remove("dynamic")
|
|
2793
|
+
C = self.code()
|
|
2794
|
+
n = C.length()
|
|
2795
|
+
k = C.dimension()
|
|
2796
|
+
H = C.parity_check_matrix()
|
|
2797
|
+
F = C.base_ring()
|
|
2798
|
+
l = list(F)
|
|
2799
|
+
zero = F.zero()
|
|
2800
|
+
# Builds a list of generators of all error positions for all
|
|
2801
|
+
# possible error weights
|
|
2802
|
+
if zero in l:
|
|
2803
|
+
l.remove(zero)
|
|
2804
|
+
# Remember to include the no-error-vector to handle codes of minimum
|
|
2805
|
+
# distance 1 gracefully
|
|
2806
|
+
zero_syndrome = vector(F, [F.zero()]*(n-k))
|
|
2807
|
+
zero_syndrome.set_immutable()
|
|
2808
|
+
lookup = {zero_syndrome: vector(F, [F.zero()]*n)}
|
|
2809
|
+
error_position_tables = [cartesian_product([l]*i) for i in range(1, t+1)]
|
|
2810
|
+
first_collision = True
|
|
2811
|
+
# Filling the lookup table
|
|
2812
|
+
for i in range(1, t+1):
|
|
2813
|
+
stop = True
|
|
2814
|
+
patterns = Subsets(range(n), i)
|
|
2815
|
+
basic = vector(F, n)
|
|
2816
|
+
for p in patterns:
|
|
2817
|
+
for error in error_position_tables[i-1]:
|
|
2818
|
+
ind = 0
|
|
2819
|
+
e = copy(basic)
|
|
2820
|
+
for pos in p:
|
|
2821
|
+
e[pos] = error[ind]
|
|
2822
|
+
ind += 1
|
|
2823
|
+
s = H * e
|
|
2824
|
+
s.set_immutable()
|
|
2825
|
+
try:
|
|
2826
|
+
e_cur = lookup[s]
|
|
2827
|
+
# if this is the first time we see a collision
|
|
2828
|
+
# we learn the minimum distance of the code
|
|
2829
|
+
if first_collision:
|
|
2830
|
+
self._code_minimum_distance = e.hamming_weight() + e_cur.hamming_weight()
|
|
2831
|
+
first_collision = False
|
|
2832
|
+
except KeyError:
|
|
2833
|
+
stop = False
|
|
2834
|
+
lookup[s] = copy(e)
|
|
2835
|
+
# if we reached the early termination condition
|
|
2836
|
+
# we learn the covering radius of the code
|
|
2837
|
+
if stop:
|
|
2838
|
+
self._code_covering_radius = i - 1
|
|
2839
|
+
self._maximum_error_weight = self._code_covering_radius
|
|
2840
|
+
break
|
|
2841
|
+
# Update decoder types depending on whether we are decoding up to covering radius
|
|
2842
|
+
if self._code_covering_radius:
|
|
2843
|
+
self._decoder_type.add("complete")
|
|
2844
|
+
else:
|
|
2845
|
+
self._decoder_type.add("bounded_distance")
|
|
2846
|
+
# Update decoder types depending on whether we are decoding beyond d/2
|
|
2847
|
+
if self._code_minimum_distance:
|
|
2848
|
+
if self._maximum_error_weight == (self._code_minimum_distance-1)//2:
|
|
2849
|
+
self._decoder_type.update({"minimum-distance", "always-succeed"})
|
|
2850
|
+
else:
|
|
2851
|
+
# then t > (d-1)/2
|
|
2852
|
+
self._decoder_type.add("might-error")
|
|
2853
|
+
else:
|
|
2854
|
+
self._decoder_type.add("always-succeed")
|
|
2855
|
+
return lookup
|
|
2856
|
+
|
|
2857
|
+
def decode_to_code(self, r):
|
|
2858
|
+
r"""
|
|
2859
|
+
Correct the errors in ``word`` and return a codeword.
|
|
2860
|
+
|
|
2861
|
+
INPUT:
|
|
2862
|
+
|
|
2863
|
+
- ``r`` -- a codeword of ``self``
|
|
2864
|
+
|
|
2865
|
+
OUTPUT: a vector of ``self``'s message space
|
|
2866
|
+
|
|
2867
|
+
EXAMPLES::
|
|
2868
|
+
|
|
2869
|
+
sage: G = Matrix(GF(3), [[1, 0, 0, 0, 2, 2, 1, 1],
|
|
2870
|
+
....: [0, 1, 0, 0, 0, 0, 1, 1],
|
|
2871
|
+
....: [0, 0, 1, 0, 2, 0, 0, 2],
|
|
2872
|
+
....: [0, 0, 0, 1, 0, 2, 0, 1]])
|
|
2873
|
+
sage: C = LinearCode(G)
|
|
2874
|
+
sage: D = codes.decoders.LinearCodeSyndromeDecoder(C, maximum_error_weight = 1)
|
|
2875
|
+
sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), 1)
|
|
2876
|
+
sage: c = C.random_element()
|
|
2877
|
+
sage: r = Chan(c)
|
|
2878
|
+
sage: c == D.decode_to_code(r)
|
|
2879
|
+
True
|
|
2880
|
+
"""
|
|
2881
|
+
lookup_table = self.syndrome_table()
|
|
2882
|
+
s = self.code().parity_check_matrix() * r
|
|
2883
|
+
s.set_immutable()
|
|
2884
|
+
if s.is_zero():
|
|
2885
|
+
return r
|
|
2886
|
+
err = lookup_table[s]
|
|
2887
|
+
r_corr = copy(r)
|
|
2888
|
+
for i in range(self.code().length()):
|
|
2889
|
+
r_corr[i] = r[i] - err[i]
|
|
2890
|
+
return r_corr
|
|
2891
|
+
|
|
2892
|
+
def maximum_error_weight(self):
|
|
2893
|
+
r"""
|
|
2894
|
+
Return the maximal number of errors a received word can have
|
|
2895
|
+
and for which ``self`` is guaranteed to return a most likely codeword.
|
|
2896
|
+
|
|
2897
|
+
Same as :meth:`decoding_radius`.
|
|
2898
|
+
|
|
2899
|
+
EXAMPLES::
|
|
2900
|
+
|
|
2901
|
+
sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2],
|
|
2902
|
+
....: [0,1,0,2,2,0,1,1,0],
|
|
2903
|
+
....: [0,0,1,0,2,2,2,1,2]])
|
|
2904
|
+
sage: C = LinearCode(G)
|
|
2905
|
+
sage: D = codes.decoders.LinearCodeSyndromeDecoder(C)
|
|
2906
|
+
sage: D.maximum_error_weight()
|
|
2907
|
+
4
|
|
2908
|
+
"""
|
|
2909
|
+
return self._maximum_error_weight
|
|
2910
|
+
|
|
2911
|
+
def decoding_radius(self):
|
|
2912
|
+
r"""
|
|
2913
|
+
Return the maximal number of errors a received word can have
|
|
2914
|
+
and for which ``self`` is guaranteed to return a most likely codeword.
|
|
2915
|
+
|
|
2916
|
+
EXAMPLES::
|
|
2917
|
+
|
|
2918
|
+
sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2],
|
|
2919
|
+
....: [0,1,0,2,2,0,1,1,0],
|
|
2920
|
+
....: [0,0,1,0,2,2,2,1,2]])
|
|
2921
|
+
sage: C = LinearCode(G)
|
|
2922
|
+
sage: D = codes.decoders.LinearCodeSyndromeDecoder(C)
|
|
2923
|
+
sage: D.decoding_radius()
|
|
2924
|
+
4
|
|
2925
|
+
"""
|
|
2926
|
+
return self._maximum_error_weight
|
|
2927
|
+
|
|
2928
|
+
def syndrome_table(self):
|
|
2929
|
+
r"""
|
|
2930
|
+
Return the syndrome lookup table of ``self``.
|
|
2931
|
+
|
|
2932
|
+
EXAMPLES::
|
|
2933
|
+
|
|
2934
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0],
|
|
2935
|
+
....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
2936
|
+
sage: C = LinearCode(G)
|
|
2937
|
+
sage: D = codes.decoders.LinearCodeSyndromeDecoder(C)
|
|
2938
|
+
sage: D.syndrome_table()
|
|
2939
|
+
{(0, 0, 0): (0, 0, 0, 0, 0, 0, 0),
|
|
2940
|
+
(1, 0, 0): (1, 0, 0, 0, 0, 0, 0),
|
|
2941
|
+
(0, 1, 0): (0, 1, 0, 0, 0, 0, 0),
|
|
2942
|
+
(1, 1, 0): (0, 0, 1, 0, 0, 0, 0),
|
|
2943
|
+
(0, 0, 1): (0, 0, 0, 1, 0, 0, 0),
|
|
2944
|
+
(1, 0, 1): (0, 0, 0, 0, 1, 0, 0),
|
|
2945
|
+
(0, 1, 1): (0, 0, 0, 0, 0, 1, 0),
|
|
2946
|
+
(1, 1, 1): (0, 0, 0, 0, 0, 0, 1)}
|
|
2947
|
+
"""
|
|
2948
|
+
return self._lookup_table
|
|
2949
|
+
|
|
2950
|
+
|
|
2951
|
+
class LinearCodeNearestNeighborDecoder(Decoder):
|
|
2952
|
+
r"""
|
|
2953
|
+
Construct a decoder for Linear Codes. This decoder will decode to the
|
|
2954
|
+
nearest codeword found.
|
|
2955
|
+
|
|
2956
|
+
INPUT:
|
|
2957
|
+
|
|
2958
|
+
- ``code`` -- a code associated to this decoder
|
|
2959
|
+
"""
|
|
2960
|
+
|
|
2961
|
+
def __init__(self, code):
|
|
2962
|
+
r"""
|
|
2963
|
+
EXAMPLES::
|
|
2964
|
+
|
|
2965
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
|
|
2966
|
+
sage: C = LinearCode(G)
|
|
2967
|
+
sage: D = codes.decoders.LinearCodeNearestNeighborDecoder(C)
|
|
2968
|
+
sage: D
|
|
2969
|
+
Nearest neighbor decoder for [7, 4] linear code over GF(2)
|
|
2970
|
+
"""
|
|
2971
|
+
super().__init__(code, code.ambient_space(), code._default_encoder_name)
|
|
2972
|
+
|
|
2973
|
+
def __eq__(self, other):
|
|
2974
|
+
r"""
|
|
2975
|
+
Test equality between LinearCodeNearestNeighborDecoder objects.
|
|
2976
|
+
|
|
2977
|
+
EXAMPLES::
|
|
2978
|
+
|
|
2979
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
|
|
2980
|
+
sage: D1 = codes.decoders.LinearCodeNearestNeighborDecoder(LinearCode(G))
|
|
2981
|
+
sage: D2 = codes.decoders.LinearCodeNearestNeighborDecoder(LinearCode(G))
|
|
2982
|
+
sage: D1 == D2
|
|
2983
|
+
True
|
|
2984
|
+
"""
|
|
2985
|
+
return isinstance(other, LinearCodeNearestNeighborDecoder)\
|
|
2986
|
+
and self.code() == other.code()
|
|
2987
|
+
|
|
2988
|
+
def _repr_(self) -> str:
|
|
2989
|
+
r"""
|
|
2990
|
+
Return a string representation of ``self``.
|
|
2991
|
+
|
|
2992
|
+
EXAMPLES::
|
|
2993
|
+
|
|
2994
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
|
|
2995
|
+
sage: C = LinearCode(G)
|
|
2996
|
+
sage: D = codes.decoders.LinearCodeNearestNeighborDecoder(C)
|
|
2997
|
+
sage: D
|
|
2998
|
+
Nearest neighbor decoder for [7, 4] linear code over GF(2)
|
|
2999
|
+
"""
|
|
3000
|
+
return "Nearest neighbor decoder for %s" % self.code()
|
|
3001
|
+
|
|
3002
|
+
def _latex_(self):
|
|
3003
|
+
r"""
|
|
3004
|
+
Return a latex representation of ``self``.
|
|
3005
|
+
|
|
3006
|
+
EXAMPLES::
|
|
3007
|
+
|
|
3008
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
|
|
3009
|
+
sage: C = LinearCode(G)
|
|
3010
|
+
sage: D = codes.decoders.LinearCodeNearestNeighborDecoder(C)
|
|
3011
|
+
sage: latex(D)
|
|
3012
|
+
\textnormal{Nearest neighbor decoder for }[7, 4]\textnormal{ Linear code over }\Bold{F}_{2}
|
|
3013
|
+
"""
|
|
3014
|
+
return "\\textnormal{Nearest neighbor decoder for }%s" % self.code()._latex_()
|
|
3015
|
+
|
|
3016
|
+
def decode_to_code(self, r):
|
|
3017
|
+
r"""
|
|
3018
|
+
Corrects the errors in ``word`` and returns a codeword.
|
|
3019
|
+
|
|
3020
|
+
INPUT:
|
|
3021
|
+
|
|
3022
|
+
- ``r`` -- a codeword of ``self``
|
|
3023
|
+
|
|
3024
|
+
OUTPUT: a vector of ``self``'s message space
|
|
3025
|
+
|
|
3026
|
+
EXAMPLES::
|
|
3027
|
+
|
|
3028
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0],
|
|
3029
|
+
....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
3030
|
+
sage: C = LinearCode(G)
|
|
3031
|
+
sage: D = codes.decoders.LinearCodeNearestNeighborDecoder(C)
|
|
3032
|
+
sage: word = vector(GF(2), (1, 1, 0, 0, 1, 1, 0))
|
|
3033
|
+
sage: w_err = word + vector(GF(2), (1, 0, 0, 0, 0, 0, 0))
|
|
3034
|
+
sage: D.decode_to_code(w_err)
|
|
3035
|
+
(1, 1, 0, 0, 1, 1, 0)
|
|
3036
|
+
"""
|
|
3037
|
+
c_min = self.code().zero()
|
|
3038
|
+
h_min = r.hamming_weight()
|
|
3039
|
+
for c in self.code():
|
|
3040
|
+
if (c-r).hamming_weight() < h_min:
|
|
3041
|
+
h_min = (c-r).hamming_weight()
|
|
3042
|
+
c_min = c
|
|
3043
|
+
c_min.set_immutable()
|
|
3044
|
+
return c_min
|
|
3045
|
+
|
|
3046
|
+
def decoding_radius(self):
|
|
3047
|
+
r"""
|
|
3048
|
+
Return maximal number of errors ``self`` can decode.
|
|
3049
|
+
|
|
3050
|
+
EXAMPLES::
|
|
3051
|
+
|
|
3052
|
+
sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0],
|
|
3053
|
+
....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
|
|
3054
|
+
sage: C = LinearCode(G)
|
|
3055
|
+
sage: D = codes.decoders.LinearCodeNearestNeighborDecoder(C)
|
|
3056
|
+
sage: D.decoding_radius() # needs sage.libs.gap
|
|
3057
|
+
1
|
|
3058
|
+
"""
|
|
3059
|
+
return (self.code().minimum_distance()-1) // 2
|
|
3060
|
+
|
|
3061
|
+
|
|
3062
|
+
# ###################### registration ###############################
|
|
3063
|
+
|
|
3064
|
+
LinearCode._registered_encoders["GeneratorMatrix"] = LinearCodeGeneratorMatrixEncoder
|
|
3065
|
+
|
|
3066
|
+
LinearCodeSyndromeDecoder._decoder_type = {"hard-decision", "dynamic"}
|
|
3067
|
+
LinearCodeNearestNeighborDecoder._decoder_type = {"hard-decision", "always-succeed", "complete"}
|