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.

Files changed (807) hide show
  1. passagemath_modules-10.6.31rc3.dist-info/METADATA +281 -0
  2. passagemath_modules-10.6.31rc3.dist-info/RECORD +807 -0
  3. passagemath_modules-10.6.31rc3.dist-info/WHEEL +5 -0
  4. passagemath_modules-10.6.31rc3.dist-info/top_level.txt +2 -0
  5. passagemath_modules.libs/libgcc_s-2d945d6c.so.1 +0 -0
  6. passagemath_modules.libs/libgfortran-67378ab2.so.5.0.0 +0 -0
  7. passagemath_modules.libs/libgmp-28992bcb.so.10.5.0 +0 -0
  8. passagemath_modules.libs/libgsl-23768756.so.28.0.0 +0 -0
  9. passagemath_modules.libs/libmpc-7897025b.so.3.3.1 +0 -0
  10. passagemath_modules.libs/libmpfr-e34bb864.so.6.2.1 +0 -0
  11. passagemath_modules.libs/libopenblasp-r0-503f0c35.3.29.so +0 -0
  12. sage/algebras/all__sagemath_modules.py +20 -0
  13. sage/algebras/catalog.py +148 -0
  14. sage/algebras/clifford_algebra.py +3107 -0
  15. sage/algebras/clifford_algebra_element.cpython-314-aarch64-linux-musl.so +0 -0
  16. sage/algebras/clifford_algebra_element.pxd +16 -0
  17. sage/algebras/clifford_algebra_element.pyx +997 -0
  18. sage/algebras/commutative_dga.py +4252 -0
  19. sage/algebras/exterior_algebra_groebner.cpython-314-aarch64-linux-musl.so +0 -0
  20. sage/algebras/exterior_algebra_groebner.pxd +55 -0
  21. sage/algebras/exterior_algebra_groebner.pyx +727 -0
  22. sage/algebras/finite_dimensional_algebras/all.py +2 -0
  23. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +1029 -0
  24. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.cpython-314-aarch64-linux-musl.so +0 -0
  25. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd +12 -0
  26. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +706 -0
  27. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +196 -0
  28. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +255 -0
  29. sage/algebras/finite_gca.py +528 -0
  30. sage/algebras/group_algebra.py +232 -0
  31. sage/algebras/lie_algebras/abelian.py +197 -0
  32. sage/algebras/lie_algebras/affine_lie_algebra.py +1213 -0
  33. sage/algebras/lie_algebras/all.py +25 -0
  34. sage/algebras/lie_algebras/all__sagemath_modules.py +1 -0
  35. sage/algebras/lie_algebras/bch.py +177 -0
  36. sage/algebras/lie_algebras/bgg_dual_module.py +1184 -0
  37. sage/algebras/lie_algebras/bgg_resolution.py +232 -0
  38. sage/algebras/lie_algebras/center_uea.py +767 -0
  39. sage/algebras/lie_algebras/classical_lie_algebra.py +2516 -0
  40. sage/algebras/lie_algebras/examples.py +683 -0
  41. sage/algebras/lie_algebras/free_lie_algebra.py +973 -0
  42. sage/algebras/lie_algebras/heisenberg.py +820 -0
  43. sage/algebras/lie_algebras/lie_algebra.py +1562 -0
  44. sage/algebras/lie_algebras/lie_algebra_element.cpython-314-aarch64-linux-musl.so +0 -0
  45. sage/algebras/lie_algebras/lie_algebra_element.pxd +68 -0
  46. sage/algebras/lie_algebras/lie_algebra_element.pyx +2122 -0
  47. sage/algebras/lie_algebras/morphism.py +661 -0
  48. sage/algebras/lie_algebras/nilpotent_lie_algebra.py +457 -0
  49. sage/algebras/lie_algebras/onsager.py +1324 -0
  50. sage/algebras/lie_algebras/poincare_birkhoff_witt.py +816 -0
  51. sage/algebras/lie_algebras/quotient.py +462 -0
  52. sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +355 -0
  53. sage/algebras/lie_algebras/representation.py +1040 -0
  54. sage/algebras/lie_algebras/structure_coefficients.py +459 -0
  55. sage/algebras/lie_algebras/subalgebra.py +967 -0
  56. sage/algebras/lie_algebras/symplectic_derivation.py +289 -0
  57. sage/algebras/lie_algebras/verma_module.py +1630 -0
  58. sage/algebras/lie_algebras/virasoro.py +1186 -0
  59. sage/algebras/octonion_algebra.cpython-314-aarch64-linux-musl.so +0 -0
  60. sage/algebras/octonion_algebra.pxd +20 -0
  61. sage/algebras/octonion_algebra.pyx +987 -0
  62. sage/algebras/orlik_solomon.py +907 -0
  63. sage/algebras/orlik_terao.py +779 -0
  64. sage/algebras/steenrod/all.py +7 -0
  65. sage/algebras/steenrod/steenrod_algebra.py +4258 -0
  66. sage/algebras/steenrod/steenrod_algebra_bases.py +1179 -0
  67. sage/algebras/steenrod/steenrod_algebra_misc.py +1167 -0
  68. sage/algebras/steenrod/steenrod_algebra_mult.py +954 -0
  69. sage/algebras/weyl_algebra.py +1126 -0
  70. sage/all__sagemath_modules.py +62 -0
  71. sage/calculus/all__sagemath_modules.py +19 -0
  72. sage/calculus/expr.py +205 -0
  73. sage/calculus/integration.cpython-314-aarch64-linux-musl.so +0 -0
  74. sage/calculus/integration.pyx +698 -0
  75. sage/calculus/interpolation.cpython-314-aarch64-linux-musl.so +0 -0
  76. sage/calculus/interpolation.pxd +13 -0
  77. sage/calculus/interpolation.pyx +387 -0
  78. sage/calculus/interpolators.cpython-314-aarch64-linux-musl.so +0 -0
  79. sage/calculus/interpolators.pyx +326 -0
  80. sage/calculus/ode.cpython-314-aarch64-linux-musl.so +0 -0
  81. sage/calculus/ode.pxd +5 -0
  82. sage/calculus/ode.pyx +610 -0
  83. sage/calculus/riemann.cpython-314-aarch64-linux-musl.so +0 -0
  84. sage/calculus/riemann.pyx +1521 -0
  85. sage/calculus/test_sympy.py +201 -0
  86. sage/calculus/transforms/all.py +7 -0
  87. sage/calculus/transforms/dft.py +844 -0
  88. sage/calculus/transforms/dwt.cpython-314-aarch64-linux-musl.so +0 -0
  89. sage/calculus/transforms/dwt.pxd +7 -0
  90. sage/calculus/transforms/dwt.pyx +160 -0
  91. sage/calculus/transforms/fft.cpython-314-aarch64-linux-musl.so +0 -0
  92. sage/calculus/transforms/fft.pxd +12 -0
  93. sage/calculus/transforms/fft.pyx +487 -0
  94. sage/calculus/wester.py +662 -0
  95. sage/coding/abstract_code.py +1108 -0
  96. sage/coding/ag_code.py +868 -0
  97. sage/coding/ag_code_decoders.cpython-314-aarch64-linux-musl.so +0 -0
  98. sage/coding/ag_code_decoders.pyx +2639 -0
  99. sage/coding/all.py +15 -0
  100. sage/coding/bch_code.py +494 -0
  101. sage/coding/binary_code.cpython-314-aarch64-linux-musl.so +0 -0
  102. sage/coding/binary_code.pxd +124 -0
  103. sage/coding/binary_code.pyx +4139 -0
  104. sage/coding/bounds_catalog.py +43 -0
  105. sage/coding/channel.py +819 -0
  106. sage/coding/channels_catalog.py +29 -0
  107. sage/coding/code_bounds.py +755 -0
  108. sage/coding/code_constructions.py +804 -0
  109. sage/coding/codes_catalog.py +111 -0
  110. sage/coding/cyclic_code.py +1329 -0
  111. sage/coding/databases.py +316 -0
  112. sage/coding/decoder.py +373 -0
  113. sage/coding/decoders_catalog.py +88 -0
  114. sage/coding/delsarte_bounds.py +709 -0
  115. sage/coding/encoder.py +390 -0
  116. sage/coding/encoders_catalog.py +64 -0
  117. sage/coding/extended_code.py +468 -0
  118. sage/coding/gabidulin_code.py +1058 -0
  119. sage/coding/golay_code.py +404 -0
  120. sage/coding/goppa_code.py +441 -0
  121. sage/coding/grs_code.py +2371 -0
  122. sage/coding/guava.py +107 -0
  123. sage/coding/guruswami_sudan/all.py +1 -0
  124. sage/coding/guruswami_sudan/gs_decoder.py +897 -0
  125. sage/coding/guruswami_sudan/interpolation.py +409 -0
  126. sage/coding/guruswami_sudan/utils.py +176 -0
  127. sage/coding/hamming_code.py +176 -0
  128. sage/coding/information_set_decoder.py +1032 -0
  129. sage/coding/kasami_codes.cpython-314-aarch64-linux-musl.so +0 -0
  130. sage/coding/kasami_codes.pyx +351 -0
  131. sage/coding/linear_code.py +3067 -0
  132. sage/coding/linear_code_no_metric.py +1354 -0
  133. sage/coding/linear_rank_metric.py +961 -0
  134. sage/coding/parity_check_code.py +353 -0
  135. sage/coding/punctured_code.py +719 -0
  136. sage/coding/reed_muller_code.py +999 -0
  137. sage/coding/self_dual_codes.py +942 -0
  138. sage/coding/source_coding/all.py +2 -0
  139. sage/coding/source_coding/huffman.py +553 -0
  140. sage/coding/subfield_subcode.py +423 -0
  141. sage/coding/two_weight_db.py +399 -0
  142. sage/combinat/all__sagemath_modules.py +7 -0
  143. sage/combinat/cartesian_product.py +347 -0
  144. sage/combinat/family.py +11 -0
  145. sage/combinat/free_module.py +1977 -0
  146. sage/combinat/root_system/all.py +147 -0
  147. sage/combinat/root_system/ambient_space.py +527 -0
  148. sage/combinat/root_system/associahedron.py +471 -0
  149. sage/combinat/root_system/braid_move_calculator.py +143 -0
  150. sage/combinat/root_system/braid_orbit.cpython-314-aarch64-linux-musl.so +0 -0
  151. sage/combinat/root_system/braid_orbit.pyx +144 -0
  152. sage/combinat/root_system/branching_rules.py +2301 -0
  153. sage/combinat/root_system/cartan_matrix.py +1245 -0
  154. sage/combinat/root_system/cartan_type.py +3069 -0
  155. sage/combinat/root_system/coxeter_group.py +162 -0
  156. sage/combinat/root_system/coxeter_matrix.py +1261 -0
  157. sage/combinat/root_system/coxeter_type.py +681 -0
  158. sage/combinat/root_system/dynkin_diagram.py +900 -0
  159. sage/combinat/root_system/extended_affine_weyl_group.py +2993 -0
  160. sage/combinat/root_system/fundamental_group.py +795 -0
  161. sage/combinat/root_system/hecke_algebra_representation.py +1203 -0
  162. sage/combinat/root_system/integrable_representations.py +1227 -0
  163. sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +1965 -0
  164. sage/combinat/root_system/pieri_factors.py +1147 -0
  165. sage/combinat/root_system/plot.py +1615 -0
  166. sage/combinat/root_system/root_lattice_realization_algebras.py +1214 -0
  167. sage/combinat/root_system/root_lattice_realizations.py +4628 -0
  168. sage/combinat/root_system/root_space.py +487 -0
  169. sage/combinat/root_system/root_system.py +882 -0
  170. sage/combinat/root_system/type_A.py +348 -0
  171. sage/combinat/root_system/type_A_affine.py +227 -0
  172. sage/combinat/root_system/type_A_infinity.py +241 -0
  173. sage/combinat/root_system/type_B.py +347 -0
  174. sage/combinat/root_system/type_BC_affine.py +287 -0
  175. sage/combinat/root_system/type_B_affine.py +216 -0
  176. sage/combinat/root_system/type_C.py +317 -0
  177. sage/combinat/root_system/type_C_affine.py +188 -0
  178. sage/combinat/root_system/type_D.py +357 -0
  179. sage/combinat/root_system/type_D_affine.py +208 -0
  180. sage/combinat/root_system/type_E.py +641 -0
  181. sage/combinat/root_system/type_E_affine.py +231 -0
  182. sage/combinat/root_system/type_F.py +387 -0
  183. sage/combinat/root_system/type_F_affine.py +137 -0
  184. sage/combinat/root_system/type_G.py +293 -0
  185. sage/combinat/root_system/type_G_affine.py +132 -0
  186. sage/combinat/root_system/type_H.py +105 -0
  187. sage/combinat/root_system/type_I.py +110 -0
  188. sage/combinat/root_system/type_Q.py +150 -0
  189. sage/combinat/root_system/type_affine.py +509 -0
  190. sage/combinat/root_system/type_dual.py +704 -0
  191. sage/combinat/root_system/type_folded.py +301 -0
  192. sage/combinat/root_system/type_marked.py +748 -0
  193. sage/combinat/root_system/type_reducible.py +601 -0
  194. sage/combinat/root_system/type_relabel.py +730 -0
  195. sage/combinat/root_system/type_super_A.py +837 -0
  196. sage/combinat/root_system/weight_lattice_realizations.py +1188 -0
  197. sage/combinat/root_system/weight_space.py +639 -0
  198. sage/combinat/root_system/weyl_characters.py +2238 -0
  199. sage/crypto/__init__.py +4 -0
  200. sage/crypto/all.py +28 -0
  201. sage/crypto/block_cipher/all.py +7 -0
  202. sage/crypto/block_cipher/des.py +1065 -0
  203. sage/crypto/block_cipher/miniaes.py +2171 -0
  204. sage/crypto/block_cipher/present.py +909 -0
  205. sage/crypto/block_cipher/sdes.py +1527 -0
  206. sage/crypto/boolean_function.cpython-314-aarch64-linux-musl.so +0 -0
  207. sage/crypto/boolean_function.pxd +10 -0
  208. sage/crypto/boolean_function.pyx +1487 -0
  209. sage/crypto/cipher.py +78 -0
  210. sage/crypto/classical.py +3668 -0
  211. sage/crypto/classical_cipher.py +569 -0
  212. sage/crypto/cryptosystem.py +387 -0
  213. sage/crypto/key_exchange/all.py +7 -0
  214. sage/crypto/key_exchange/catalog.py +24 -0
  215. sage/crypto/key_exchange/diffie_hellman.py +323 -0
  216. sage/crypto/key_exchange/key_exchange_scheme.py +107 -0
  217. sage/crypto/lattice.py +312 -0
  218. sage/crypto/lfsr.py +295 -0
  219. sage/crypto/lwe.py +840 -0
  220. sage/crypto/mq/__init__.py +4 -0
  221. sage/crypto/mq/mpolynomialsystemgenerator.py +204 -0
  222. sage/crypto/mq/rijndael_gf.py +2345 -0
  223. sage/crypto/mq/sbox.py +7 -0
  224. sage/crypto/mq/sr.py +3344 -0
  225. sage/crypto/public_key/all.py +5 -0
  226. sage/crypto/public_key/blum_goldwasser.py +776 -0
  227. sage/crypto/sbox.cpython-314-aarch64-linux-musl.so +0 -0
  228. sage/crypto/sbox.pyx +2090 -0
  229. sage/crypto/sboxes.py +2090 -0
  230. sage/crypto/stream.py +390 -0
  231. sage/crypto/stream_cipher.py +297 -0
  232. sage/crypto/util.py +519 -0
  233. sage/ext/all__sagemath_modules.py +1 -0
  234. sage/ext/interpreters/__init__.py +1 -0
  235. sage/ext/interpreters/all__sagemath_modules.py +2 -0
  236. sage/ext/interpreters/wrapper_cc.cpython-314-aarch64-linux-musl.so +0 -0
  237. sage/ext/interpreters/wrapper_cc.pxd +30 -0
  238. sage/ext/interpreters/wrapper_cc.pyx +252 -0
  239. sage/ext/interpreters/wrapper_cdf.cpython-314-aarch64-linux-musl.so +0 -0
  240. sage/ext/interpreters/wrapper_cdf.pxd +26 -0
  241. sage/ext/interpreters/wrapper_cdf.pyx +245 -0
  242. sage/ext/interpreters/wrapper_rdf.cpython-314-aarch64-linux-musl.so +0 -0
  243. sage/ext/interpreters/wrapper_rdf.pxd +23 -0
  244. sage/ext/interpreters/wrapper_rdf.pyx +221 -0
  245. sage/ext/interpreters/wrapper_rr.cpython-314-aarch64-linux-musl.so +0 -0
  246. sage/ext/interpreters/wrapper_rr.pxd +28 -0
  247. sage/ext/interpreters/wrapper_rr.pyx +335 -0
  248. sage/geometry/all__sagemath_modules.py +5 -0
  249. sage/geometry/toric_lattice.py +1745 -0
  250. sage/geometry/toric_lattice_element.cpython-314-aarch64-linux-musl.so +0 -0
  251. sage/geometry/toric_lattice_element.pyx +432 -0
  252. sage/groups/abelian_gps/abelian_group.py +1925 -0
  253. sage/groups/abelian_gps/abelian_group_element.py +164 -0
  254. sage/groups/abelian_gps/all__sagemath_modules.py +5 -0
  255. sage/groups/abelian_gps/dual_abelian_group.py +421 -0
  256. sage/groups/abelian_gps/dual_abelian_group_element.py +179 -0
  257. sage/groups/abelian_gps/element_base.py +341 -0
  258. sage/groups/abelian_gps/values.py +488 -0
  259. sage/groups/additive_abelian/additive_abelian_group.py +476 -0
  260. sage/groups/additive_abelian/additive_abelian_wrapper.py +857 -0
  261. sage/groups/additive_abelian/all.py +4 -0
  262. sage/groups/additive_abelian/qmodnz.py +231 -0
  263. sage/groups/additive_abelian/qmodnz_element.py +349 -0
  264. sage/groups/affine_gps/affine_group.py +535 -0
  265. sage/groups/affine_gps/all.py +1 -0
  266. sage/groups/affine_gps/catalog.py +17 -0
  267. sage/groups/affine_gps/euclidean_group.py +246 -0
  268. sage/groups/affine_gps/group_element.py +562 -0
  269. sage/groups/all__sagemath_modules.py +12 -0
  270. sage/groups/galois_group.py +479 -0
  271. sage/groups/matrix_gps/all.py +4 -0
  272. sage/groups/matrix_gps/all__sagemath_modules.py +13 -0
  273. sage/groups/matrix_gps/catalog.py +26 -0
  274. sage/groups/matrix_gps/coxeter_group.py +927 -0
  275. sage/groups/matrix_gps/finitely_generated.py +487 -0
  276. sage/groups/matrix_gps/group_element.cpython-314-aarch64-linux-musl.so +0 -0
  277. sage/groups/matrix_gps/group_element.pxd +11 -0
  278. sage/groups/matrix_gps/group_element.pyx +431 -0
  279. sage/groups/matrix_gps/linear.py +440 -0
  280. sage/groups/matrix_gps/matrix_group.py +617 -0
  281. sage/groups/matrix_gps/named_group.py +296 -0
  282. sage/groups/matrix_gps/orthogonal.py +544 -0
  283. sage/groups/matrix_gps/symplectic.py +251 -0
  284. sage/groups/matrix_gps/unitary.py +436 -0
  285. sage/groups/misc_gps/all__sagemath_modules.py +1 -0
  286. sage/groups/misc_gps/argument_groups.py +1905 -0
  287. sage/groups/misc_gps/imaginary_groups.py +479 -0
  288. sage/groups/perm_gps/all__sagemath_modules.py +1 -0
  289. sage/groups/perm_gps/partn_ref/all__sagemath_modules.py +1 -0
  290. sage/groups/perm_gps/partn_ref/refinement_binary.cpython-314-aarch64-linux-musl.so +0 -0
  291. sage/groups/perm_gps/partn_ref/refinement_binary.pxd +41 -0
  292. sage/groups/perm_gps/partn_ref/refinement_binary.pyx +1167 -0
  293. sage/groups/perm_gps/partn_ref/refinement_matrices.cpython-314-aarch64-linux-musl.so +0 -0
  294. sage/groups/perm_gps/partn_ref/refinement_matrices.pxd +31 -0
  295. sage/groups/perm_gps/partn_ref/refinement_matrices.pyx +385 -0
  296. sage/homology/algebraic_topological_model.py +595 -0
  297. sage/homology/all.py +2 -0
  298. sage/homology/all__sagemath_modules.py +8 -0
  299. sage/homology/chain_complex.py +2148 -0
  300. sage/homology/chain_complex_homspace.py +165 -0
  301. sage/homology/chain_complex_morphism.py +629 -0
  302. sage/homology/chain_homotopy.py +604 -0
  303. sage/homology/chains.py +653 -0
  304. sage/homology/free_resolution.py +923 -0
  305. sage/homology/graded_resolution.py +567 -0
  306. sage/homology/hochschild_complex.py +756 -0
  307. sage/homology/homology_group.py +188 -0
  308. sage/homology/homology_morphism.py +422 -0
  309. sage/homology/homology_vector_space_with_basis.py +1454 -0
  310. sage/homology/koszul_complex.py +169 -0
  311. sage/homology/matrix_utils.py +205 -0
  312. sage/libs/all__sagemath_modules.py +1 -0
  313. sage/libs/gsl/__init__.py +1 -0
  314. sage/libs/gsl/airy.pxd +56 -0
  315. sage/libs/gsl/all.pxd +66 -0
  316. sage/libs/gsl/array.cpython-314-aarch64-linux-musl.so +0 -0
  317. sage/libs/gsl/array.pxd +5 -0
  318. sage/libs/gsl/array.pyx +102 -0
  319. sage/libs/gsl/bessel.pxd +208 -0
  320. sage/libs/gsl/blas.pxd +116 -0
  321. sage/libs/gsl/blas_types.pxd +34 -0
  322. sage/libs/gsl/block.pxd +52 -0
  323. sage/libs/gsl/chebyshev.pxd +37 -0
  324. sage/libs/gsl/clausen.pxd +12 -0
  325. sage/libs/gsl/combination.pxd +47 -0
  326. sage/libs/gsl/complex.pxd +151 -0
  327. sage/libs/gsl/coulomb.pxd +30 -0
  328. sage/libs/gsl/coupling.pxd +21 -0
  329. sage/libs/gsl/dawson.pxd +12 -0
  330. sage/libs/gsl/debye.pxd +24 -0
  331. sage/libs/gsl/dilog.pxd +14 -0
  332. sage/libs/gsl/eigen.pxd +46 -0
  333. sage/libs/gsl/elementary.pxd +12 -0
  334. sage/libs/gsl/ellint.pxd +48 -0
  335. sage/libs/gsl/elljac.pxd +8 -0
  336. sage/libs/gsl/erf.pxd +32 -0
  337. sage/libs/gsl/errno.pxd +26 -0
  338. sage/libs/gsl/exp.pxd +44 -0
  339. sage/libs/gsl/expint.pxd +44 -0
  340. sage/libs/gsl/fermi_dirac.pxd +44 -0
  341. sage/libs/gsl/fft.pxd +121 -0
  342. sage/libs/gsl/fit.pxd +50 -0
  343. sage/libs/gsl/gamma.pxd +94 -0
  344. sage/libs/gsl/gegenbauer.pxd +26 -0
  345. sage/libs/gsl/histogram.pxd +176 -0
  346. sage/libs/gsl/hyperg.pxd +52 -0
  347. sage/libs/gsl/integration.pxd +69 -0
  348. sage/libs/gsl/interp.pxd +109 -0
  349. sage/libs/gsl/laguerre.pxd +24 -0
  350. sage/libs/gsl/lambert.pxd +16 -0
  351. sage/libs/gsl/legendre.pxd +90 -0
  352. sage/libs/gsl/linalg.pxd +185 -0
  353. sage/libs/gsl/log.pxd +26 -0
  354. sage/libs/gsl/math.pxd +43 -0
  355. sage/libs/gsl/matrix.pxd +143 -0
  356. sage/libs/gsl/matrix_complex.pxd +130 -0
  357. sage/libs/gsl/min.pxd +67 -0
  358. sage/libs/gsl/monte.pxd +56 -0
  359. sage/libs/gsl/ntuple.pxd +32 -0
  360. sage/libs/gsl/odeiv.pxd +70 -0
  361. sage/libs/gsl/permutation.pxd +78 -0
  362. sage/libs/gsl/poly.pxd +40 -0
  363. sage/libs/gsl/pow_int.pxd +12 -0
  364. sage/libs/gsl/psi.pxd +28 -0
  365. sage/libs/gsl/qrng.pxd +29 -0
  366. sage/libs/gsl/random.pxd +257 -0
  367. sage/libs/gsl/rng.pxd +100 -0
  368. sage/libs/gsl/roots.pxd +72 -0
  369. sage/libs/gsl/sort.pxd +36 -0
  370. sage/libs/gsl/statistics.pxd +59 -0
  371. sage/libs/gsl/sum.pxd +55 -0
  372. sage/libs/gsl/synchrotron.pxd +16 -0
  373. sage/libs/gsl/transport.pxd +24 -0
  374. sage/libs/gsl/trig.pxd +58 -0
  375. sage/libs/gsl/types.pxd +137 -0
  376. sage/libs/gsl/vector.pxd +101 -0
  377. sage/libs/gsl/vector_complex.pxd +83 -0
  378. sage/libs/gsl/wavelet.pxd +49 -0
  379. sage/libs/gsl/zeta.pxd +28 -0
  380. sage/libs/mpc/__init__.pxd +114 -0
  381. sage/libs/mpc/types.pxd +28 -0
  382. sage/libs/mpfr/__init__.pxd +299 -0
  383. sage/libs/mpfr/types.pxd +26 -0
  384. sage/libs/mpmath/__init__.py +1 -0
  385. sage/libs/mpmath/all.py +27 -0
  386. sage/libs/mpmath/all__sagemath_modules.py +1 -0
  387. sage/libs/mpmath/utils.cpython-314-aarch64-linux-musl.so +0 -0
  388. sage/libs/mpmath/utils.pxd +4 -0
  389. sage/libs/mpmath/utils.pyx +319 -0
  390. sage/matrix/action.cpython-314-aarch64-linux-musl.so +0 -0
  391. sage/matrix/action.pxd +26 -0
  392. sage/matrix/action.pyx +596 -0
  393. sage/matrix/all.py +9 -0
  394. sage/matrix/args.cpython-314-aarch64-linux-musl.so +0 -0
  395. sage/matrix/args.pxd +144 -0
  396. sage/matrix/args.pyx +1668 -0
  397. sage/matrix/benchmark.py +1258 -0
  398. sage/matrix/berlekamp_massey.py +95 -0
  399. sage/matrix/compute_J_ideal.py +926 -0
  400. sage/matrix/constructor.cpython-314-aarch64-linux-musl.so +0 -0
  401. sage/matrix/constructor.pyx +750 -0
  402. sage/matrix/docs.py +430 -0
  403. sage/matrix/echelon_matrix.cpython-314-aarch64-linux-musl.so +0 -0
  404. sage/matrix/echelon_matrix.pyx +155 -0
  405. sage/matrix/matrix.pxd +2 -0
  406. sage/matrix/matrix0.cpython-314-aarch64-linux-musl.so +0 -0
  407. sage/matrix/matrix0.pxd +68 -0
  408. sage/matrix/matrix0.pyx +6324 -0
  409. sage/matrix/matrix1.cpython-314-aarch64-linux-musl.so +0 -0
  410. sage/matrix/matrix1.pxd +8 -0
  411. sage/matrix/matrix1.pyx +2851 -0
  412. sage/matrix/matrix2.cpython-314-aarch64-linux-musl.so +0 -0
  413. sage/matrix/matrix2.pxd +25 -0
  414. sage/matrix/matrix2.pyx +20181 -0
  415. sage/matrix/matrix_cdv.cpython-314-aarch64-linux-musl.so +0 -0
  416. sage/matrix/matrix_cdv.pxd +4 -0
  417. sage/matrix/matrix_cdv.pyx +93 -0
  418. sage/matrix/matrix_complex_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
  419. sage/matrix/matrix_complex_double_dense.pxd +5 -0
  420. sage/matrix/matrix_complex_double_dense.pyx +98 -0
  421. sage/matrix/matrix_dense.cpython-314-aarch64-linux-musl.so +0 -0
  422. sage/matrix/matrix_dense.pxd +5 -0
  423. sage/matrix/matrix_dense.pyx +343 -0
  424. sage/matrix/matrix_domain_dense.pxd +5 -0
  425. sage/matrix/matrix_domain_sparse.pxd +5 -0
  426. sage/matrix/matrix_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
  427. sage/matrix/matrix_double_dense.pxd +7 -0
  428. sage/matrix/matrix_double_dense.pyx +3906 -0
  429. sage/matrix/matrix_double_sparse.cpython-314-aarch64-linux-musl.so +0 -0
  430. sage/matrix/matrix_double_sparse.pxd +6 -0
  431. sage/matrix/matrix_double_sparse.pyx +248 -0
  432. sage/matrix/matrix_generic_dense.cpython-314-aarch64-linux-musl.so +0 -0
  433. sage/matrix/matrix_generic_dense.pxd +7 -0
  434. sage/matrix/matrix_generic_dense.pyx +354 -0
  435. sage/matrix/matrix_generic_sparse.cpython-314-aarch64-linux-musl.so +0 -0
  436. sage/matrix/matrix_generic_sparse.pxd +7 -0
  437. sage/matrix/matrix_generic_sparse.pyx +461 -0
  438. sage/matrix/matrix_laurent_mpolynomial_dense.cpython-314-aarch64-linux-musl.so +0 -0
  439. sage/matrix/matrix_laurent_mpolynomial_dense.pxd +5 -0
  440. sage/matrix/matrix_laurent_mpolynomial_dense.pyx +115 -0
  441. sage/matrix/matrix_misc.py +313 -0
  442. sage/matrix/matrix_numpy_dense.cpython-314-aarch64-linux-musl.so +0 -0
  443. sage/matrix/matrix_numpy_dense.pxd +14 -0
  444. sage/matrix/matrix_numpy_dense.pyx +450 -0
  445. sage/matrix/matrix_numpy_integer_dense.cpython-314-aarch64-linux-musl.so +0 -0
  446. sage/matrix/matrix_numpy_integer_dense.pxd +7 -0
  447. sage/matrix/matrix_numpy_integer_dense.pyx +59 -0
  448. sage/matrix/matrix_polynomial_dense.cpython-314-aarch64-linux-musl.so +0 -0
  449. sage/matrix/matrix_polynomial_dense.pxd +5 -0
  450. sage/matrix/matrix_polynomial_dense.pyx +5341 -0
  451. sage/matrix/matrix_real_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
  452. sage/matrix/matrix_real_double_dense.pxd +7 -0
  453. sage/matrix/matrix_real_double_dense.pyx +122 -0
  454. sage/matrix/matrix_space.py +2848 -0
  455. sage/matrix/matrix_sparse.cpython-314-aarch64-linux-musl.so +0 -0
  456. sage/matrix/matrix_sparse.pxd +5 -0
  457. sage/matrix/matrix_sparse.pyx +1222 -0
  458. sage/matrix/matrix_window.cpython-314-aarch64-linux-musl.so +0 -0
  459. sage/matrix/matrix_window.pxd +37 -0
  460. sage/matrix/matrix_window.pyx +242 -0
  461. sage/matrix/misc_mpfr.cpython-314-aarch64-linux-musl.so +0 -0
  462. sage/matrix/misc_mpfr.pyx +80 -0
  463. sage/matrix/operation_table.py +1182 -0
  464. sage/matrix/special.py +3666 -0
  465. sage/matrix/strassen.cpython-314-aarch64-linux-musl.so +0 -0
  466. sage/matrix/strassen.pyx +851 -0
  467. sage/matrix/symplectic_basis.py +541 -0
  468. sage/matrix/template.pxd +6 -0
  469. sage/matrix/tests.py +71 -0
  470. sage/matroids/advanced.py +77 -0
  471. sage/matroids/all.py +13 -0
  472. sage/matroids/basis_exchange_matroid.cpython-314-aarch64-linux-musl.so +0 -0
  473. sage/matroids/basis_exchange_matroid.pxd +96 -0
  474. sage/matroids/basis_exchange_matroid.pyx +2344 -0
  475. sage/matroids/basis_matroid.cpython-314-aarch64-linux-musl.so +0 -0
  476. sage/matroids/basis_matroid.pxd +45 -0
  477. sage/matroids/basis_matroid.pyx +1217 -0
  478. sage/matroids/catalog.py +44 -0
  479. sage/matroids/chow_ring.py +473 -0
  480. sage/matroids/chow_ring_ideal.py +849 -0
  481. sage/matroids/circuit_closures_matroid.cpython-314-aarch64-linux-musl.so +0 -0
  482. sage/matroids/circuit_closures_matroid.pxd +16 -0
  483. sage/matroids/circuit_closures_matroid.pyx +559 -0
  484. sage/matroids/circuits_matroid.cpython-314-aarch64-linux-musl.so +0 -0
  485. sage/matroids/circuits_matroid.pxd +38 -0
  486. sage/matroids/circuits_matroid.pyx +947 -0
  487. sage/matroids/constructor.py +1086 -0
  488. sage/matroids/database_collections.py +365 -0
  489. sage/matroids/database_matroids.py +5338 -0
  490. sage/matroids/dual_matroid.py +583 -0
  491. sage/matroids/extension.cpython-314-aarch64-linux-musl.so +0 -0
  492. sage/matroids/extension.pxd +34 -0
  493. sage/matroids/extension.pyx +519 -0
  494. sage/matroids/flats_matroid.cpython-314-aarch64-linux-musl.so +0 -0
  495. sage/matroids/flats_matroid.pxd +28 -0
  496. sage/matroids/flats_matroid.pyx +715 -0
  497. sage/matroids/gammoid.py +600 -0
  498. sage/matroids/graphic_matroid.cpython-314-aarch64-linux-musl.so +0 -0
  499. sage/matroids/graphic_matroid.pxd +39 -0
  500. sage/matroids/graphic_matroid.pyx +2024 -0
  501. sage/matroids/lean_matrix.cpython-314-aarch64-linux-musl.so +0 -0
  502. sage/matroids/lean_matrix.pxd +126 -0
  503. sage/matroids/lean_matrix.pyx +3667 -0
  504. sage/matroids/linear_matroid.cpython-314-aarch64-linux-musl.so +0 -0
  505. sage/matroids/linear_matroid.pxd +180 -0
  506. sage/matroids/linear_matroid.pyx +6649 -0
  507. sage/matroids/matroid.cpython-314-aarch64-linux-musl.so +0 -0
  508. sage/matroids/matroid.pxd +243 -0
  509. sage/matroids/matroid.pyx +8759 -0
  510. sage/matroids/matroids_catalog.py +190 -0
  511. sage/matroids/matroids_plot_helpers.py +890 -0
  512. sage/matroids/minor_matroid.py +480 -0
  513. sage/matroids/minorfix.h +9 -0
  514. sage/matroids/named_matroids.py +5 -0
  515. sage/matroids/rank_matroid.py +268 -0
  516. sage/matroids/set_system.cpython-314-aarch64-linux-musl.so +0 -0
  517. sage/matroids/set_system.pxd +38 -0
  518. sage/matroids/set_system.pyx +800 -0
  519. sage/matroids/transversal_matroid.cpython-314-aarch64-linux-musl.so +0 -0
  520. sage/matroids/transversal_matroid.pxd +14 -0
  521. sage/matroids/transversal_matroid.pyx +893 -0
  522. sage/matroids/union_matroid.cpython-314-aarch64-linux-musl.so +0 -0
  523. sage/matroids/union_matroid.pxd +20 -0
  524. sage/matroids/union_matroid.pyx +331 -0
  525. sage/matroids/unpickling.cpython-314-aarch64-linux-musl.so +0 -0
  526. sage/matroids/unpickling.pyx +843 -0
  527. sage/matroids/utilities.py +809 -0
  528. sage/misc/all__sagemath_modules.py +20 -0
  529. sage/misc/c3.cpython-314-aarch64-linux-musl.so +0 -0
  530. sage/misc/c3.pyx +238 -0
  531. sage/misc/compat.py +87 -0
  532. sage/misc/element_with_label.py +173 -0
  533. sage/misc/func_persist.py +79 -0
  534. sage/misc/pickle_old.cpython-314-aarch64-linux-musl.so +0 -0
  535. sage/misc/pickle_old.pyx +19 -0
  536. sage/misc/proof.py +7 -0
  537. sage/misc/replace_dot_all.py +472 -0
  538. sage/misc/sagedoc_conf.py +168 -0
  539. sage/misc/sphinxify.py +167 -0
  540. sage/misc/test_class_pickling.py +85 -0
  541. sage/modules/all.py +42 -0
  542. sage/modules/complex_double_vector.py +25 -0
  543. sage/modules/diamond_cutting.py +380 -0
  544. sage/modules/fg_pid/all.py +1 -0
  545. sage/modules/fg_pid/fgp_element.py +456 -0
  546. sage/modules/fg_pid/fgp_module.py +2091 -0
  547. sage/modules/fg_pid/fgp_morphism.py +550 -0
  548. sage/modules/filtered_vector_space.py +1271 -0
  549. sage/modules/finite_submodule_iter.cpython-314-aarch64-linux-musl.so +0 -0
  550. sage/modules/finite_submodule_iter.pxd +27 -0
  551. sage/modules/finite_submodule_iter.pyx +452 -0
  552. sage/modules/fp_graded/all.py +1 -0
  553. sage/modules/fp_graded/element.py +346 -0
  554. sage/modules/fp_graded/free_element.py +298 -0
  555. sage/modules/fp_graded/free_homspace.py +53 -0
  556. sage/modules/fp_graded/free_module.py +1060 -0
  557. sage/modules/fp_graded/free_morphism.py +217 -0
  558. sage/modules/fp_graded/homspace.py +563 -0
  559. sage/modules/fp_graded/module.py +1340 -0
  560. sage/modules/fp_graded/morphism.py +1990 -0
  561. sage/modules/fp_graded/steenrod/all.py +1 -0
  562. sage/modules/fp_graded/steenrod/homspace.py +65 -0
  563. sage/modules/fp_graded/steenrod/module.py +477 -0
  564. sage/modules/fp_graded/steenrod/morphism.py +404 -0
  565. sage/modules/fp_graded/steenrod/profile.py +241 -0
  566. sage/modules/free_module.py +8447 -0
  567. sage/modules/free_module_element.cpython-314-aarch64-linux-musl.so +0 -0
  568. sage/modules/free_module_element.pxd +22 -0
  569. sage/modules/free_module_element.pyx +5445 -0
  570. sage/modules/free_module_homspace.py +369 -0
  571. sage/modules/free_module_integer.py +896 -0
  572. sage/modules/free_module_morphism.py +823 -0
  573. sage/modules/free_module_pseudohomspace.py +352 -0
  574. sage/modules/free_module_pseudomorphism.py +578 -0
  575. sage/modules/free_quadratic_module.py +1706 -0
  576. sage/modules/free_quadratic_module_integer_symmetric.py +1790 -0
  577. sage/modules/matrix_morphism.py +1745 -0
  578. sage/modules/misc.py +103 -0
  579. sage/modules/module_functors.py +192 -0
  580. sage/modules/multi_filtered_vector_space.py +719 -0
  581. sage/modules/ore_module.py +2208 -0
  582. sage/modules/ore_module_element.py +178 -0
  583. sage/modules/ore_module_homspace.py +147 -0
  584. sage/modules/ore_module_morphism.py +968 -0
  585. sage/modules/quotient_module.py +699 -0
  586. sage/modules/real_double_vector.py +22 -0
  587. sage/modules/submodule.py +255 -0
  588. sage/modules/tensor_operations.py +567 -0
  589. sage/modules/torsion_quadratic_module.py +1352 -0
  590. sage/modules/tutorial_free_modules.py +248 -0
  591. sage/modules/vector_complex_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
  592. sage/modules/vector_complex_double_dense.pxd +6 -0
  593. sage/modules/vector_complex_double_dense.pyx +117 -0
  594. sage/modules/vector_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
  595. sage/modules/vector_double_dense.pxd +6 -0
  596. sage/modules/vector_double_dense.pyx +604 -0
  597. sage/modules/vector_integer_dense.cpython-314-aarch64-linux-musl.so +0 -0
  598. sage/modules/vector_integer_dense.pxd +15 -0
  599. sage/modules/vector_integer_dense.pyx +361 -0
  600. sage/modules/vector_integer_sparse.cpython-314-aarch64-linux-musl.so +0 -0
  601. sage/modules/vector_integer_sparse.pxd +29 -0
  602. sage/modules/vector_integer_sparse.pyx +406 -0
  603. sage/modules/vector_modn_dense.cpython-314-aarch64-linux-musl.so +0 -0
  604. sage/modules/vector_modn_dense.pxd +12 -0
  605. sage/modules/vector_modn_dense.pyx +394 -0
  606. sage/modules/vector_modn_sparse.cpython-314-aarch64-linux-musl.so +0 -0
  607. sage/modules/vector_modn_sparse.pxd +21 -0
  608. sage/modules/vector_modn_sparse.pyx +298 -0
  609. sage/modules/vector_numpy_dense.cpython-314-aarch64-linux-musl.so +0 -0
  610. sage/modules/vector_numpy_dense.pxd +15 -0
  611. sage/modules/vector_numpy_dense.pyx +304 -0
  612. sage/modules/vector_numpy_integer_dense.cpython-314-aarch64-linux-musl.so +0 -0
  613. sage/modules/vector_numpy_integer_dense.pxd +7 -0
  614. sage/modules/vector_numpy_integer_dense.pyx +54 -0
  615. sage/modules/vector_rational_dense.cpython-314-aarch64-linux-musl.so +0 -0
  616. sage/modules/vector_rational_dense.pxd +15 -0
  617. sage/modules/vector_rational_dense.pyx +387 -0
  618. sage/modules/vector_rational_sparse.cpython-314-aarch64-linux-musl.so +0 -0
  619. sage/modules/vector_rational_sparse.pxd +30 -0
  620. sage/modules/vector_rational_sparse.pyx +413 -0
  621. sage/modules/vector_real_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
  622. sage/modules/vector_real_double_dense.pxd +6 -0
  623. sage/modules/vector_real_double_dense.pyx +126 -0
  624. sage/modules/vector_space_homspace.py +430 -0
  625. sage/modules/vector_space_morphism.py +989 -0
  626. sage/modules/with_basis/all.py +15 -0
  627. sage/modules/with_basis/cell_module.py +494 -0
  628. sage/modules/with_basis/indexed_element.cpython-314-aarch64-linux-musl.so +0 -0
  629. sage/modules/with_basis/indexed_element.pxd +13 -0
  630. sage/modules/with_basis/indexed_element.pyx +1058 -0
  631. sage/modules/with_basis/invariant.py +1075 -0
  632. sage/modules/with_basis/morphism.py +1636 -0
  633. sage/modules/with_basis/representation.py +2939 -0
  634. sage/modules/with_basis/subquotient.py +685 -0
  635. sage/numerical/all__sagemath_modules.py +6 -0
  636. sage/numerical/gauss_legendre.cpython-314-aarch64-linux-musl.so +0 -0
  637. sage/numerical/gauss_legendre.pyx +381 -0
  638. sage/numerical/optimize.py +910 -0
  639. sage/probability/all.py +10 -0
  640. sage/probability/probability_distribution.cpython-314-aarch64-linux-musl.so +0 -0
  641. sage/probability/probability_distribution.pyx +1242 -0
  642. sage/probability/random_variable.py +411 -0
  643. sage/quadratic_forms/all.py +4 -0
  644. sage/quadratic_forms/all__sagemath_modules.py +15 -0
  645. sage/quadratic_forms/binary_qf.py +2042 -0
  646. sage/quadratic_forms/bqf_class_group.py +748 -0
  647. sage/quadratic_forms/constructions.py +93 -0
  648. sage/quadratic_forms/count_local_2.cpython-314-aarch64-linux-musl.so +0 -0
  649. sage/quadratic_forms/count_local_2.pyx +365 -0
  650. sage/quadratic_forms/extras.py +195 -0
  651. sage/quadratic_forms/quadratic_form.py +1753 -0
  652. sage/quadratic_forms/quadratic_form__count_local_2.py +221 -0
  653. sage/quadratic_forms/quadratic_form__equivalence_testing.py +708 -0
  654. sage/quadratic_forms/quadratic_form__evaluate.cpython-314-aarch64-linux-musl.so +0 -0
  655. sage/quadratic_forms/quadratic_form__evaluate.pyx +139 -0
  656. sage/quadratic_forms/quadratic_form__local_density_congruence.py +977 -0
  657. sage/quadratic_forms/quadratic_form__local_field_invariants.py +1072 -0
  658. sage/quadratic_forms/quadratic_form__neighbors.py +424 -0
  659. sage/quadratic_forms/quadratic_form__reduction_theory.py +488 -0
  660. sage/quadratic_forms/quadratic_form__split_local_covering.py +416 -0
  661. sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +657 -0
  662. sage/quadratic_forms/quadratic_form__theta.py +352 -0
  663. sage/quadratic_forms/quadratic_form__variable_substitutions.py +370 -0
  664. sage/quadratic_forms/random_quadraticform.py +209 -0
  665. sage/quadratic_forms/ternary.cpython-314-aarch64-linux-musl.so +0 -0
  666. sage/quadratic_forms/ternary.pyx +1154 -0
  667. sage/quadratic_forms/ternary_qf.py +2027 -0
  668. sage/rings/all__sagemath_modules.py +28 -0
  669. sage/rings/asymptotic/all__sagemath_modules.py +1 -0
  670. sage/rings/asymptotic/misc.py +1252 -0
  671. sage/rings/cc.py +4 -0
  672. sage/rings/cfinite_sequence.py +1306 -0
  673. sage/rings/complex_conversion.cpython-314-aarch64-linux-musl.so +0 -0
  674. sage/rings/complex_conversion.pxd +8 -0
  675. sage/rings/complex_conversion.pyx +23 -0
  676. sage/rings/complex_double.cpython-314-aarch64-linux-musl.so +0 -0
  677. sage/rings/complex_double.pxd +21 -0
  678. sage/rings/complex_double.pyx +2654 -0
  679. sage/rings/complex_mpc.cpython-314-aarch64-linux-musl.so +0 -0
  680. sage/rings/complex_mpc.pxd +21 -0
  681. sage/rings/complex_mpc.pyx +2576 -0
  682. sage/rings/complex_mpfr.cpython-314-aarch64-linux-musl.so +0 -0
  683. sage/rings/complex_mpfr.pxd +18 -0
  684. sage/rings/complex_mpfr.pyx +3602 -0
  685. sage/rings/derivation.py +2334 -0
  686. sage/rings/finite_rings/all__sagemath_modules.py +1 -0
  687. sage/rings/finite_rings/maps_finite_field.py +191 -0
  688. sage/rings/function_field/all__sagemath_modules.py +8 -0
  689. sage/rings/function_field/derivations.py +102 -0
  690. sage/rings/function_field/derivations_rational.py +132 -0
  691. sage/rings/function_field/differential.py +853 -0
  692. sage/rings/function_field/divisor.py +1107 -0
  693. sage/rings/function_field/drinfeld_modules/action.py +199 -0
  694. sage/rings/function_field/drinfeld_modules/all.py +1 -0
  695. sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +673 -0
  696. sage/rings/function_field/drinfeld_modules/drinfeld_module.py +2087 -0
  697. sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +1131 -0
  698. sage/rings/function_field/drinfeld_modules/homset.py +420 -0
  699. sage/rings/function_field/drinfeld_modules/morphism.py +820 -0
  700. sage/rings/function_field/hermite_form_polynomial.cpython-314-aarch64-linux-musl.so +0 -0
  701. sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
  702. sage/rings/function_field/khuri_makdisi.cpython-314-aarch64-linux-musl.so +0 -0
  703. sage/rings/function_field/khuri_makdisi.pyx +935 -0
  704. sage/rings/invariants/all.py +4 -0
  705. sage/rings/invariants/invariant_theory.py +4597 -0
  706. sage/rings/invariants/reconstruction.py +395 -0
  707. sage/rings/polynomial/all__sagemath_modules.py +17 -0
  708. sage/rings/polynomial/integer_valued_polynomials.py +1230 -0
  709. sage/rings/polynomial/laurent_polynomial_mpair.cpython-314-aarch64-linux-musl.so +0 -0
  710. sage/rings/polynomial/laurent_polynomial_mpair.pxd +15 -0
  711. sage/rings/polynomial/laurent_polynomial_mpair.pyx +2023 -0
  712. sage/rings/polynomial/ore_function_element.py +952 -0
  713. sage/rings/polynomial/ore_function_field.py +1028 -0
  714. sage/rings/polynomial/ore_polynomial_element.cpython-314-aarch64-linux-musl.so +0 -0
  715. sage/rings/polynomial/ore_polynomial_element.pxd +48 -0
  716. sage/rings/polynomial/ore_polynomial_element.pyx +3145 -0
  717. sage/rings/polynomial/ore_polynomial_ring.py +1334 -0
  718. sage/rings/polynomial/polynomial_real_mpfr_dense.cpython-314-aarch64-linux-musl.so +0 -0
  719. sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +788 -0
  720. sage/rings/polynomial/q_integer_valued_polynomials.py +1264 -0
  721. sage/rings/polynomial/skew_polynomial_element.cpython-314-aarch64-linux-musl.so +0 -0
  722. sage/rings/polynomial/skew_polynomial_element.pxd +9 -0
  723. sage/rings/polynomial/skew_polynomial_element.pyx +684 -0
  724. sage/rings/polynomial/skew_polynomial_finite_field.cpython-314-aarch64-linux-musl.so +0 -0
  725. sage/rings/polynomial/skew_polynomial_finite_field.pxd +19 -0
  726. sage/rings/polynomial/skew_polynomial_finite_field.pyx +1093 -0
  727. sage/rings/polynomial/skew_polynomial_finite_order.cpython-314-aarch64-linux-musl.so +0 -0
  728. sage/rings/polynomial/skew_polynomial_finite_order.pxd +10 -0
  729. sage/rings/polynomial/skew_polynomial_finite_order.pyx +567 -0
  730. sage/rings/polynomial/skew_polynomial_ring.py +908 -0
  731. sage/rings/real_double_element_gsl.cpython-314-aarch64-linux-musl.so +0 -0
  732. sage/rings/real_double_element_gsl.pxd +8 -0
  733. sage/rings/real_double_element_gsl.pyx +794 -0
  734. sage/rings/real_field.py +58 -0
  735. sage/rings/real_mpfr.cpython-314-aarch64-linux-musl.so +0 -0
  736. sage/rings/real_mpfr.pxd +29 -0
  737. sage/rings/real_mpfr.pyx +6122 -0
  738. sage/rings/ring_extension.cpython-314-aarch64-linux-musl.so +0 -0
  739. sage/rings/ring_extension.pxd +42 -0
  740. sage/rings/ring_extension.pyx +2779 -0
  741. sage/rings/ring_extension_conversion.cpython-314-aarch64-linux-musl.so +0 -0
  742. sage/rings/ring_extension_conversion.pxd +16 -0
  743. sage/rings/ring_extension_conversion.pyx +462 -0
  744. sage/rings/ring_extension_element.cpython-314-aarch64-linux-musl.so +0 -0
  745. sage/rings/ring_extension_element.pxd +21 -0
  746. sage/rings/ring_extension_element.pyx +1635 -0
  747. sage/rings/ring_extension_homset.py +64 -0
  748. sage/rings/ring_extension_morphism.cpython-314-aarch64-linux-musl.so +0 -0
  749. sage/rings/ring_extension_morphism.pxd +35 -0
  750. sage/rings/ring_extension_morphism.pyx +920 -0
  751. sage/schemes/all__sagemath_modules.py +1 -0
  752. sage/schemes/projective/all__sagemath_modules.py +1 -0
  753. sage/schemes/projective/coherent_sheaf.py +300 -0
  754. sage/schemes/projective/cohomology.py +510 -0
  755. sage/stats/all.py +15 -0
  756. sage/stats/basic_stats.py +489 -0
  757. sage/stats/distributions/all.py +7 -0
  758. sage/stats/distributions/catalog.py +34 -0
  759. sage/stats/distributions/dgs.h +50 -0
  760. sage/stats/distributions/dgs.pxd +111 -0
  761. sage/stats/distributions/dgs_bern.h +400 -0
  762. sage/stats/distributions/dgs_gauss.h +614 -0
  763. sage/stats/distributions/dgs_misc.h +104 -0
  764. sage/stats/distributions/discrete_gaussian_integer.cpython-314-aarch64-linux-musl.so +0 -0
  765. sage/stats/distributions/discrete_gaussian_integer.pxd +14 -0
  766. sage/stats/distributions/discrete_gaussian_integer.pyx +498 -0
  767. sage/stats/distributions/discrete_gaussian_lattice.py +908 -0
  768. sage/stats/distributions/discrete_gaussian_polynomial.py +141 -0
  769. sage/stats/hmm/all.py +15 -0
  770. sage/stats/hmm/chmm.cpython-314-aarch64-linux-musl.so +0 -0
  771. sage/stats/hmm/chmm.pyx +1595 -0
  772. sage/stats/hmm/distributions.cpython-314-aarch64-linux-musl.so +0 -0
  773. sage/stats/hmm/distributions.pxd +29 -0
  774. sage/stats/hmm/distributions.pyx +531 -0
  775. sage/stats/hmm/hmm.cpython-314-aarch64-linux-musl.so +0 -0
  776. sage/stats/hmm/hmm.pxd +17 -0
  777. sage/stats/hmm/hmm.pyx +1388 -0
  778. sage/stats/hmm/util.cpython-314-aarch64-linux-musl.so +0 -0
  779. sage/stats/hmm/util.pxd +7 -0
  780. sage/stats/hmm/util.pyx +165 -0
  781. sage/stats/intlist.cpython-314-aarch64-linux-musl.so +0 -0
  782. sage/stats/intlist.pxd +14 -0
  783. sage/stats/intlist.pyx +588 -0
  784. sage/stats/r.py +49 -0
  785. sage/stats/time_series.cpython-314-aarch64-linux-musl.so +0 -0
  786. sage/stats/time_series.pxd +6 -0
  787. sage/stats/time_series.pyx +2546 -0
  788. sage/tensor/all.py +2 -0
  789. sage/tensor/modules/all.py +8 -0
  790. sage/tensor/modules/alternating_contr_tensor.py +761 -0
  791. sage/tensor/modules/comp.py +5598 -0
  792. sage/tensor/modules/ext_pow_free_module.py +824 -0
  793. sage/tensor/modules/finite_rank_free_module.py +3589 -0
  794. sage/tensor/modules/format_utilities.py +333 -0
  795. sage/tensor/modules/free_module_alt_form.py +858 -0
  796. sage/tensor/modules/free_module_automorphism.py +1207 -0
  797. sage/tensor/modules/free_module_basis.py +1074 -0
  798. sage/tensor/modules/free_module_element.py +284 -0
  799. sage/tensor/modules/free_module_homset.py +652 -0
  800. sage/tensor/modules/free_module_linear_group.py +564 -0
  801. sage/tensor/modules/free_module_morphism.py +1581 -0
  802. sage/tensor/modules/free_module_tensor.py +3289 -0
  803. sage/tensor/modules/reflexive_module.py +386 -0
  804. sage/tensor/modules/tensor_free_module.py +780 -0
  805. sage/tensor/modules/tensor_free_submodule.py +538 -0
  806. sage/tensor/modules/tensor_free_submodule_basis.py +140 -0
  807. 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"}