passagemath-categories 10.6.32__cp314-cp314t-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.
- passagemath_categories-10.6.32.dist-info/METADATA +156 -0
- passagemath_categories-10.6.32.dist-info/RECORD +719 -0
- passagemath_categories-10.6.32.dist-info/WHEEL +5 -0
- passagemath_categories-10.6.32.dist-info/top_level.txt +2 -0
- passagemath_categories.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_categories.libs/libgmp-28992bcb.so.10.5.0 +0 -0
- passagemath_categories.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
- sage/all__sagemath_categories.py +28 -0
- sage/arith/all.py +38 -0
- sage/arith/constants.pxd +27 -0
- sage/arith/functions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/functions.pxd +4 -0
- sage/arith/functions.pyx +221 -0
- sage/arith/misc.py +6552 -0
- sage/arith/multi_modular.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/multi_modular.pxd +39 -0
- sage/arith/multi_modular.pyx +994 -0
- sage/arith/rational_reconstruction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/rational_reconstruction.pxd +4 -0
- sage/arith/rational_reconstruction.pyx +115 -0
- sage/arith/srange.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/srange.pyx +571 -0
- sage/calculus/all__sagemath_categories.py +2 -0
- sage/calculus/functional.py +481 -0
- sage/calculus/functions.py +151 -0
- sage/categories/additive_groups.py +73 -0
- sage/categories/additive_magmas.py +1044 -0
- sage/categories/additive_monoids.py +114 -0
- sage/categories/additive_semigroups.py +184 -0
- sage/categories/affine_weyl_groups.py +238 -0
- sage/categories/algebra_ideals.py +95 -0
- sage/categories/algebra_modules.py +96 -0
- sage/categories/algebras.py +349 -0
- sage/categories/algebras_with_basis.py +377 -0
- sage/categories/all.py +160 -0
- sage/categories/aperiodic_semigroups.py +29 -0
- sage/categories/associative_algebras.py +47 -0
- sage/categories/bialgebras.py +101 -0
- sage/categories/bialgebras_with_basis.py +414 -0
- sage/categories/bimodules.py +206 -0
- sage/categories/chain_complexes.py +268 -0
- sage/categories/classical_crystals.py +480 -0
- sage/categories/coalgebras.py +405 -0
- sage/categories/coalgebras_with_basis.py +232 -0
- sage/categories/coercion_methods.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/coercion_methods.pyx +52 -0
- sage/categories/commutative_additive_groups.py +104 -0
- sage/categories/commutative_additive_monoids.py +45 -0
- sage/categories/commutative_additive_semigroups.py +48 -0
- sage/categories/commutative_algebra_ideals.py +87 -0
- sage/categories/commutative_algebras.py +94 -0
- sage/categories/commutative_ring_ideals.py +58 -0
- sage/categories/commutative_rings.py +736 -0
- sage/categories/complete_discrete_valuation.py +293 -0
- sage/categories/complex_reflection_groups.py +145 -0
- sage/categories/complex_reflection_or_generalized_coxeter_groups.py +1249 -0
- sage/categories/coxeter_group_algebras.py +186 -0
- sage/categories/coxeter_groups.py +3402 -0
- sage/categories/crystals.py +2628 -0
- sage/categories/cw_complexes.py +216 -0
- sage/categories/dedekind_domains.py +137 -0
- sage/categories/discrete_valuation.py +325 -0
- sage/categories/distributive_magmas_and_additive_magmas.py +100 -0
- sage/categories/division_rings.py +114 -0
- sage/categories/domains.py +95 -0
- sage/categories/drinfeld_modules.py +789 -0
- sage/categories/dual.py +42 -0
- sage/categories/enumerated_sets.py +1146 -0
- sage/categories/euclidean_domains.py +271 -0
- sage/categories/examples/algebras_with_basis.py +102 -0
- sage/categories/examples/all.py +1 -0
- sage/categories/examples/commutative_additive_monoids.py +130 -0
- sage/categories/examples/commutative_additive_semigroups.py +199 -0
- sage/categories/examples/coxeter_groups.py +8 -0
- sage/categories/examples/crystals.py +236 -0
- sage/categories/examples/cw_complexes.py +163 -0
- sage/categories/examples/facade_sets.py +187 -0
- sage/categories/examples/filtered_algebras_with_basis.py +204 -0
- sage/categories/examples/filtered_modules_with_basis.py +154 -0
- sage/categories/examples/finite_coxeter_groups.py +252 -0
- sage/categories/examples/finite_dimensional_algebras_with_basis.py +148 -0
- sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +495 -0
- sage/categories/examples/finite_enumerated_sets.py +208 -0
- sage/categories/examples/finite_monoids.py +150 -0
- sage/categories/examples/finite_semigroups.py +190 -0
- sage/categories/examples/finite_weyl_groups.py +191 -0
- sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +152 -0
- sage/categories/examples/graded_modules_with_basis.py +168 -0
- sage/categories/examples/graphs.py +122 -0
- sage/categories/examples/hopf_algebras_with_basis.py +145 -0
- sage/categories/examples/infinite_enumerated_sets.py +190 -0
- sage/categories/examples/lie_algebras.py +352 -0
- sage/categories/examples/lie_algebras_with_basis.py +196 -0
- sage/categories/examples/magmas.py +162 -0
- sage/categories/examples/manifolds.py +94 -0
- sage/categories/examples/monoids.py +144 -0
- sage/categories/examples/posets.py +178 -0
- sage/categories/examples/semigroups.py +580 -0
- sage/categories/examples/semigroups_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/examples/semigroups_cython.pyx +221 -0
- sage/categories/examples/semirings.py +249 -0
- sage/categories/examples/sets_cat.py +706 -0
- sage/categories/examples/sets_with_grading.py +101 -0
- sage/categories/examples/with_realizations.py +542 -0
- sage/categories/fields.py +991 -0
- sage/categories/filtered_algebras.py +63 -0
- sage/categories/filtered_algebras_with_basis.py +548 -0
- sage/categories/filtered_hopf_algebras_with_basis.py +138 -0
- sage/categories/filtered_modules.py +210 -0
- sage/categories/filtered_modules_with_basis.py +1209 -0
- sage/categories/finite_complex_reflection_groups.py +1506 -0
- sage/categories/finite_coxeter_groups.py +1138 -0
- sage/categories/finite_crystals.py +103 -0
- sage/categories/finite_dimensional_algebras_with_basis.py +1860 -0
- sage/categories/finite_dimensional_bialgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_coalgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +231 -0
- sage/categories/finite_dimensional_hopf_algebras_with_basis.py +38 -0
- sage/categories/finite_dimensional_lie_algebras_with_basis.py +2774 -0
- sage/categories/finite_dimensional_modules_with_basis.py +1407 -0
- sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +167 -0
- sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +270 -0
- sage/categories/finite_enumerated_sets.py +769 -0
- sage/categories/finite_fields.py +252 -0
- sage/categories/finite_groups.py +256 -0
- sage/categories/finite_lattice_posets.py +242 -0
- sage/categories/finite_monoids.py +316 -0
- sage/categories/finite_permutation_groups.py +339 -0
- sage/categories/finite_posets.py +1994 -0
- sage/categories/finite_semigroups.py +136 -0
- sage/categories/finite_sets.py +93 -0
- sage/categories/finite_weyl_groups.py +39 -0
- sage/categories/finitely_generated_lambda_bracket_algebras.py +112 -0
- sage/categories/finitely_generated_lie_conformal_algebras.py +114 -0
- sage/categories/finitely_generated_magmas.py +57 -0
- sage/categories/finitely_generated_semigroups.py +214 -0
- sage/categories/function_fields.py +76 -0
- sage/categories/g_sets.py +77 -0
- sage/categories/gcd_domains.py +65 -0
- sage/categories/generalized_coxeter_groups.py +94 -0
- sage/categories/graded_algebras.py +85 -0
- sage/categories/graded_algebras_with_basis.py +258 -0
- sage/categories/graded_bialgebras.py +32 -0
- sage/categories/graded_bialgebras_with_basis.py +32 -0
- sage/categories/graded_coalgebras.py +65 -0
- sage/categories/graded_coalgebras_with_basis.py +51 -0
- sage/categories/graded_hopf_algebras.py +41 -0
- sage/categories/graded_hopf_algebras_with_basis.py +169 -0
- sage/categories/graded_lie_algebras.py +91 -0
- sage/categories/graded_lie_algebras_with_basis.py +44 -0
- sage/categories/graded_lie_conformal_algebras.py +74 -0
- sage/categories/graded_modules.py +133 -0
- sage/categories/graded_modules_with_basis.py +329 -0
- sage/categories/graphs.py +138 -0
- sage/categories/group_algebras.py +430 -0
- sage/categories/groupoid.py +94 -0
- sage/categories/groups.py +667 -0
- sage/categories/h_trivial_semigroups.py +64 -0
- sage/categories/hecke_modules.py +185 -0
- sage/categories/highest_weight_crystals.py +980 -0
- sage/categories/hopf_algebras.py +219 -0
- sage/categories/hopf_algebras_with_basis.py +309 -0
- sage/categories/infinite_enumerated_sets.py +115 -0
- sage/categories/integral_domains.py +203 -0
- sage/categories/j_trivial_semigroups.py +29 -0
- sage/categories/kac_moody_algebras.py +82 -0
- sage/categories/kahler_algebras.py +203 -0
- sage/categories/l_trivial_semigroups.py +63 -0
- sage/categories/lambda_bracket_algebras.py +280 -0
- sage/categories/lambda_bracket_algebras_with_basis.py +107 -0
- sage/categories/lattice_posets.py +89 -0
- sage/categories/left_modules.py +49 -0
- sage/categories/lie_algebras.py +1070 -0
- sage/categories/lie_algebras_with_basis.py +261 -0
- sage/categories/lie_conformal_algebras.py +350 -0
- sage/categories/lie_conformal_algebras_with_basis.py +147 -0
- sage/categories/lie_groups.py +73 -0
- sage/categories/loop_crystals.py +1290 -0
- sage/categories/magmas.py +1189 -0
- sage/categories/magmas_and_additive_magmas.py +149 -0
- sage/categories/magmatic_algebras.py +365 -0
- sage/categories/manifolds.py +352 -0
- sage/categories/matrix_algebras.py +40 -0
- sage/categories/metric_spaces.py +387 -0
- sage/categories/modular_abelian_varieties.py +78 -0
- sage/categories/modules.py +989 -0
- sage/categories/modules_with_basis.py +2794 -0
- sage/categories/monoid_algebras.py +38 -0
- sage/categories/monoids.py +739 -0
- sage/categories/noetherian_rings.py +87 -0
- sage/categories/number_fields.py +242 -0
- sage/categories/ore_modules.py +189 -0
- sage/categories/partially_ordered_monoids.py +49 -0
- sage/categories/permutation_groups.py +63 -0
- sage/categories/pointed_sets.py +42 -0
- sage/categories/polyhedra.py +74 -0
- sage/categories/poor_man_map.py +270 -0
- sage/categories/posets.py +722 -0
- sage/categories/principal_ideal_domains.py +270 -0
- sage/categories/quantum_group_representations.py +543 -0
- sage/categories/quotient_fields.py +728 -0
- sage/categories/r_trivial_semigroups.py +45 -0
- sage/categories/regular_crystals.py +898 -0
- sage/categories/regular_supercrystals.py +170 -0
- sage/categories/right_modules.py +49 -0
- sage/categories/ring_ideals.py +74 -0
- sage/categories/rings.py +1904 -0
- sage/categories/rngs.py +175 -0
- sage/categories/schemes.py +393 -0
- sage/categories/semigroups.py +1060 -0
- sage/categories/semirings.py +71 -0
- sage/categories/semisimple_algebras.py +114 -0
- sage/categories/sets_with_grading.py +235 -0
- sage/categories/shephard_groups.py +43 -0
- sage/categories/signed_tensor.py +120 -0
- sage/categories/simplicial_complexes.py +134 -0
- sage/categories/simplicial_sets.py +1206 -0
- sage/categories/super_algebras.py +149 -0
- sage/categories/super_algebras_with_basis.py +144 -0
- sage/categories/super_hopf_algebras_with_basis.py +126 -0
- sage/categories/super_lie_conformal_algebras.py +193 -0
- sage/categories/super_modules.py +229 -0
- sage/categories/super_modules_with_basis.py +193 -0
- sage/categories/supercommutative_algebras.py +99 -0
- sage/categories/supercrystals.py +406 -0
- sage/categories/tensor.py +110 -0
- sage/categories/topological_spaces.py +170 -0
- sage/categories/triangular_kac_moody_algebras.py +439 -0
- sage/categories/tutorial.py +58 -0
- sage/categories/unique_factorization_domains.py +318 -0
- sage/categories/unital_algebras.py +426 -0
- sage/categories/vector_bundles.py +159 -0
- sage/categories/vector_spaces.py +357 -0
- sage/categories/weyl_groups.py +853 -0
- sage/combinat/all__sagemath_categories.py +34 -0
- sage/combinat/backtrack.py +180 -0
- sage/combinat/combinat.py +2269 -0
- sage/combinat/combinat_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/combinat_cython.pxd +6 -0
- sage/combinat/combinat_cython.pyx +390 -0
- sage/combinat/combination.py +796 -0
- sage/combinat/combinatorial_map.py +416 -0
- sage/combinat/composition.py +2192 -0
- sage/combinat/dlx.py +510 -0
- sage/combinat/integer_lists/__init__.py +7 -0
- sage/combinat/integer_lists/base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/base.pxd +16 -0
- sage/combinat/integer_lists/base.pyx +713 -0
- sage/combinat/integer_lists/invlex.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/invlex.pxd +4 -0
- sage/combinat/integer_lists/invlex.pyx +1650 -0
- sage/combinat/integer_lists/lists.py +328 -0
- sage/combinat/integer_lists/nn.py +48 -0
- sage/combinat/integer_vector.py +1818 -0
- sage/combinat/integer_vector_weighted.py +413 -0
- sage/combinat/matrices/all__sagemath_categories.py +5 -0
- sage/combinat/matrices/dancing_links.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/matrices/dancing_links.pyx +1159 -0
- sage/combinat/matrices/dancing_links_c.h +380 -0
- sage/combinat/matrices/dlxcpp.py +136 -0
- sage/combinat/partition.py +10070 -0
- sage/combinat/partitions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/partitions.pyx +743 -0
- sage/combinat/permutation.py +10168 -0
- sage/combinat/permutation_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/permutation_cython.pxd +11 -0
- sage/combinat/permutation_cython.pyx +407 -0
- sage/combinat/q_analogues.py +1090 -0
- sage/combinat/ranker.py +268 -0
- sage/combinat/subset.py +1561 -0
- sage/combinat/subsets_hereditary.py +202 -0
- sage/combinat/subsets_pairwise.py +184 -0
- sage/combinat/tools.py +63 -0
- sage/combinat/tuple.py +348 -0
- sage/data_structures/all.py +2 -0
- sage/data_structures/all__sagemath_categories.py +2 -0
- sage/data_structures/binary_matrix.pxd +138 -0
- sage/data_structures/binary_search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/binary_search.pxd +3 -0
- sage/data_structures/binary_search.pyx +66 -0
- sage/data_structures/bitset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset.pxd +40 -0
- sage/data_structures/bitset.pyx +2385 -0
- sage/data_structures/bitset_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset_base.pxd +926 -0
- sage/data_structures/bitset_base.pyx +117 -0
- sage/data_structures/bitset_intrinsics.h +487 -0
- sage/data_structures/blas_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/blas_dict.pxd +12 -0
- sage/data_structures/blas_dict.pyx +469 -0
- sage/data_structures/list_of_pairs.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/list_of_pairs.pxd +16 -0
- sage/data_structures/list_of_pairs.pyx +122 -0
- sage/data_structures/mutable_poset.py +3312 -0
- sage/data_structures/pairing_heap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/pairing_heap.h +346 -0
- sage/data_structures/pairing_heap.pxd +88 -0
- sage/data_structures/pairing_heap.pyx +1464 -0
- sage/data_structures/sparse_bitset.pxd +62 -0
- sage/data_structures/stream.py +5070 -0
- sage/databases/all__sagemath_categories.py +7 -0
- sage/databases/sql_db.py +2236 -0
- sage/ext/all__sagemath_categories.py +3 -0
- sage/ext/fast_callable.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_callable.pxd +4 -0
- sage/ext/fast_callable.pyx +2746 -0
- sage/ext/fast_eval.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_eval.pxd +1 -0
- sage/ext/fast_eval.pyx +102 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_categories.py +2 -0
- sage/ext/interpreters/wrapper_el.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_el.pxd +18 -0
- sage/ext/interpreters/wrapper_el.pyx +148 -0
- sage/ext/interpreters/wrapper_py.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_py.pxd +17 -0
- sage/ext/interpreters/wrapper_py.pyx +133 -0
- sage/functions/airy.py +937 -0
- sage/functions/all.py +97 -0
- sage/functions/bessel.py +2102 -0
- sage/functions/error.py +784 -0
- sage/functions/exp_integral.py +1529 -0
- sage/functions/gamma.py +1087 -0
- sage/functions/generalized.py +672 -0
- sage/functions/hyperbolic.py +747 -0
- sage/functions/hypergeometric.py +1156 -0
- sage/functions/jacobi.py +1705 -0
- sage/functions/log.py +1402 -0
- sage/functions/min_max.py +338 -0
- sage/functions/orthogonal_polys.py +3106 -0
- sage/functions/other.py +2303 -0
- sage/functions/piecewise.py +1505 -0
- sage/functions/prime_pi.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/functions/prime_pi.pyx +262 -0
- sage/functions/special.py +1212 -0
- sage/functions/spike_function.py +278 -0
- sage/functions/transcendental.py +690 -0
- sage/functions/trig.py +1062 -0
- sage/functions/wigner.py +726 -0
- sage/geometry/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/geometry/abc.pyx +82 -0
- sage/geometry/all__sagemath_categories.py +1 -0
- sage/groups/all__sagemath_categories.py +11 -0
- sage/groups/generic.py +1733 -0
- sage/groups/groups_catalog.py +113 -0
- sage/groups/perm_gps/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/all.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pxd +52 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +906 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd +85 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx +534 -0
- sage/groups/perm_gps/partn_ref/data_structures.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/data_structures.pxd +576 -0
- sage/groups/perm_gps/partn_ref/data_structures.pyx +1792 -0
- sage/groups/perm_gps/partn_ref/double_coset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/double_coset.pxd +45 -0
- sage/groups/perm_gps/partn_ref/double_coset.pyx +739 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pxd +18 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pyx +82 -0
- sage/groups/perm_gps/partn_ref/refinement_python.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pxd +16 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pyx +564 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pxd +60 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pyx +858 -0
- sage/interfaces/abc.py +140 -0
- sage/interfaces/all.py +58 -0
- sage/interfaces/all__sagemath_categories.py +1 -0
- sage/interfaces/expect.py +1643 -0
- sage/interfaces/interface.py +1682 -0
- sage/interfaces/process.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/process.pxd +5 -0
- sage/interfaces/process.pyx +288 -0
- sage/interfaces/quit.py +167 -0
- sage/interfaces/sage0.py +604 -0
- sage/interfaces/sagespawn.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/sagespawn.pyx +308 -0
- sage/interfaces/tab_completion.py +101 -0
- sage/misc/all__sagemath_categories.py +78 -0
- sage/misc/allocator.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/allocator.pxd +6 -0
- sage/misc/allocator.pyx +47 -0
- sage/misc/binary_tree.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/binary_tree.pxd +29 -0
- sage/misc/binary_tree.pyx +537 -0
- sage/misc/callable_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/callable_dict.pyx +89 -0
- sage/misc/citation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/citation.pyx +159 -0
- sage/misc/converting_dict.py +293 -0
- sage/misc/defaults.py +129 -0
- sage/misc/derivative.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/derivative.pyx +223 -0
- sage/misc/functional.py +2005 -0
- sage/misc/html.py +589 -0
- sage/misc/latex.py +2673 -0
- sage/misc/latex_macros.py +236 -0
- sage/misc/latex_standalone.py +1833 -0
- sage/misc/map_threaded.py +38 -0
- sage/misc/mathml.py +76 -0
- sage/misc/method_decorator.py +88 -0
- sage/misc/mrange.py +755 -0
- sage/misc/multireplace.py +41 -0
- sage/misc/object_multiplexer.py +92 -0
- sage/misc/parser.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/parser.pyx +1107 -0
- sage/misc/random_testing.py +264 -0
- sage/misc/rest_index_of_methods.py +377 -0
- sage/misc/search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/search.pxd +2 -0
- sage/misc/search.pyx +68 -0
- sage/misc/stopgap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/stopgap.pyx +95 -0
- sage/misc/table.py +853 -0
- sage/monoids/all__sagemath_categories.py +1 -0
- sage/monoids/indexed_free_monoid.py +1071 -0
- sage/monoids/monoid.py +82 -0
- sage/numerical/all__sagemath_categories.py +1 -0
- sage/numerical/backends/all__sagemath_categories.py +1 -0
- sage/numerical/backends/generic_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_backend.pxd +61 -0
- sage/numerical/backends/generic_backend.pyx +1893 -0
- sage/numerical/backends/generic_sdp_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_sdp_backend.pxd +38 -0
- sage/numerical/backends/generic_sdp_backend.pyx +755 -0
- sage/parallel/all.py +6 -0
- sage/parallel/decorate.py +575 -0
- sage/parallel/map_reduce.py +1997 -0
- sage/parallel/multiprocessing_sage.py +76 -0
- sage/parallel/ncpus.py +35 -0
- sage/parallel/parallelism.py +364 -0
- sage/parallel/reference.py +47 -0
- sage/parallel/use_fork.py +333 -0
- sage/rings/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/abc.pxd +31 -0
- sage/rings/abc.pyx +526 -0
- sage/rings/algebraic_closure_finite_field.py +1154 -0
- sage/rings/all__sagemath_categories.py +91 -0
- sage/rings/big_oh.py +227 -0
- sage/rings/continued_fraction.py +2754 -0
- sage/rings/continued_fraction_gosper.py +220 -0
- sage/rings/factorint.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/factorint.pyx +295 -0
- sage/rings/fast_arith.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fast_arith.pxd +21 -0
- sage/rings/fast_arith.pyx +535 -0
- sage/rings/finite_rings/all__sagemath_categories.py +9 -0
- sage/rings/finite_rings/conway_polynomials.py +542 -0
- sage/rings/finite_rings/element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/element_base.pxd +12 -0
- sage/rings/finite_rings/element_base.pyx +1176 -0
- sage/rings/finite_rings/finite_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/finite_field_base.pxd +7 -0
- sage/rings/finite_rings/finite_field_base.pyx +2171 -0
- sage/rings/finite_rings/finite_field_constructor.py +827 -0
- sage/rings/finite_rings/finite_field_prime_modn.py +372 -0
- sage/rings/finite_rings/galois_group.py +154 -0
- sage/rings/finite_rings/hom_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_finite_field.pxd +23 -0
- sage/rings/finite_rings/hom_finite_field.pyx +856 -0
- sage/rings/finite_rings/hom_prime_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_prime_finite_field.pxd +15 -0
- sage/rings/finite_rings/hom_prime_finite_field.pyx +164 -0
- sage/rings/finite_rings/homset.py +357 -0
- sage/rings/finite_rings/integer_mod.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/integer_mod.pxd +56 -0
- sage/rings/finite_rings/integer_mod.pyx +4586 -0
- sage/rings/finite_rings/integer_mod_limits.h +11 -0
- sage/rings/finite_rings/integer_mod_ring.py +2044 -0
- sage/rings/finite_rings/residue_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/residue_field.pxd +30 -0
- sage/rings/finite_rings/residue_field.pyx +1811 -0
- sage/rings/finite_rings/stdint.pxd +19 -0
- sage/rings/fraction_field.py +1452 -0
- sage/rings/fraction_field_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fraction_field_element.pyx +1357 -0
- sage/rings/function_field/all.py +7 -0
- sage/rings/function_field/all__sagemath_categories.py +2 -0
- sage/rings/function_field/constructor.py +218 -0
- sage/rings/function_field/element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element.pxd +11 -0
- sage/rings/function_field/element.pyx +1008 -0
- sage/rings/function_field/element_rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element_rational.pyx +513 -0
- sage/rings/function_field/extensions.py +230 -0
- sage/rings/function_field/function_field.py +1468 -0
- sage/rings/function_field/function_field_rational.py +1005 -0
- sage/rings/function_field/ideal.py +1155 -0
- sage/rings/function_field/ideal_rational.py +629 -0
- sage/rings/function_field/jacobian_base.py +826 -0
- sage/rings/function_field/jacobian_hess.py +1053 -0
- sage/rings/function_field/jacobian_khuri_makdisi.py +1027 -0
- sage/rings/function_field/maps.py +1039 -0
- sage/rings/function_field/order.py +281 -0
- sage/rings/function_field/order_basis.py +586 -0
- sage/rings/function_field/order_rational.py +576 -0
- sage/rings/function_field/place.py +426 -0
- sage/rings/function_field/place_rational.py +181 -0
- sage/rings/generic.py +320 -0
- sage/rings/homset.py +332 -0
- sage/rings/ideal.py +1885 -0
- sage/rings/ideal_monoid.py +215 -0
- sage/rings/infinity.py +1890 -0
- sage/rings/integer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer.pxd +45 -0
- sage/rings/integer.pyx +7874 -0
- sage/rings/integer_ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer_ring.pxd +8 -0
- sage/rings/integer_ring.pyx +1693 -0
- sage/rings/laurent_series_ring.py +931 -0
- sage/rings/laurent_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/laurent_series_ring_element.pxd +11 -0
- sage/rings/laurent_series_ring_element.pyx +1927 -0
- sage/rings/lazy_series.py +7815 -0
- sage/rings/lazy_series_ring.py +4356 -0
- sage/rings/localization.py +1043 -0
- sage/rings/morphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/morphism.pxd +39 -0
- sage/rings/morphism.pyx +3299 -0
- sage/rings/multi_power_series_ring.py +1145 -0
- sage/rings/multi_power_series_ring_element.py +2184 -0
- sage/rings/noncommutative_ideals.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/noncommutative_ideals.pyx +423 -0
- sage/rings/number_field/all__sagemath_categories.py +1 -0
- sage/rings/number_field/number_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_base.pxd +8 -0
- sage/rings/number_field/number_field_base.pyx +507 -0
- sage/rings/number_field/number_field_element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_element_base.pxd +6 -0
- sage/rings/number_field/number_field_element_base.pyx +36 -0
- sage/rings/number_field/number_field_ideal.py +3550 -0
- sage/rings/padics/all__sagemath_categories.py +4 -0
- sage/rings/padics/local_generic.py +1670 -0
- sage/rings/padics/local_generic_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/local_generic_element.pxd +5 -0
- sage/rings/padics/local_generic_element.pyx +1017 -0
- sage/rings/padics/misc.py +256 -0
- sage/rings/padics/padic_generic.py +1911 -0
- sage/rings/padics/pow_computer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/pow_computer.pxd +38 -0
- sage/rings/padics/pow_computer.pyx +671 -0
- sage/rings/padics/precision_error.py +24 -0
- sage/rings/polynomial/all__sagemath_categories.py +25 -0
- sage/rings/polynomial/commutative_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/commutative_polynomial.pxd +6 -0
- sage/rings/polynomial/commutative_polynomial.pyx +24 -0
- sage/rings/polynomial/cyclotomic.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/cyclotomic.pyx +404 -0
- sage/rings/polynomial/flatten.py +711 -0
- sage/rings/polynomial/ideal.py +102 -0
- sage/rings/polynomial/infinite_polynomial_element.py +1768 -0
- sage/rings/polynomial/infinite_polynomial_ring.py +1653 -0
- sage/rings/polynomial/laurent_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial.pxd +18 -0
- sage/rings/polynomial/laurent_polynomial.pyx +2190 -0
- sage/rings/polynomial/laurent_polynomial_ideal.py +590 -0
- sage/rings/polynomial/laurent_polynomial_ring.py +832 -0
- sage/rings/polynomial/laurent_polynomial_ring_base.py +708 -0
- sage/rings/polynomial/multi_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial.pxd +12 -0
- sage/rings/polynomial/multi_polynomial.pyx +3082 -0
- sage/rings/polynomial/multi_polynomial_element.py +2570 -0
- sage/rings/polynomial/multi_polynomial_ideal.py +5771 -0
- sage/rings/polynomial/multi_polynomial_ring.py +947 -0
- sage/rings/polynomial/multi_polynomial_ring_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pxd +15 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pyx +1855 -0
- sage/rings/polynomial/multi_polynomial_sequence.py +2204 -0
- sage/rings/polynomial/polydict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polydict.pxd +45 -0
- sage/rings/polynomial/polydict.pyx +2701 -0
- sage/rings/polynomial/polynomial_compiled.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_compiled.pxd +59 -0
- sage/rings/polynomial/polynomial_compiled.pyx +509 -0
- sage/rings/polynomial/polynomial_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_element.pxd +64 -0
- sage/rings/polynomial/polynomial_element.pyx +13255 -0
- sage/rings/polynomial/polynomial_element_generic.py +1637 -0
- sage/rings/polynomial/polynomial_fateman.py +97 -0
- sage/rings/polynomial/polynomial_quotient_ring.py +2465 -0
- sage/rings/polynomial/polynomial_quotient_ring_element.py +779 -0
- sage/rings/polynomial/polynomial_ring.py +3784 -0
- sage/rings/polynomial/polynomial_ring_constructor.py +1051 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pxd +5 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pyx +121 -0
- sage/rings/polynomial/polynomial_singular_interface.py +549 -0
- sage/rings/polynomial/symmetric_ideal.py +989 -0
- sage/rings/polynomial/symmetric_reduction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/symmetric_reduction.pxd +8 -0
- sage/rings/polynomial/symmetric_reduction.pyx +669 -0
- sage/rings/polynomial/term_order.py +2279 -0
- sage/rings/polynomial/toy_buchberger.py +449 -0
- sage/rings/polynomial/toy_d_basis.py +387 -0
- sage/rings/polynomial/toy_variety.py +362 -0
- sage/rings/power_series_mpoly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_mpoly.pxd +9 -0
- sage/rings/power_series_mpoly.pyx +161 -0
- sage/rings/power_series_poly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_poly.pxd +10 -0
- sage/rings/power_series_poly.pyx +1317 -0
- sage/rings/power_series_ring.py +1441 -0
- sage/rings/power_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_ring_element.pxd +12 -0
- sage/rings/power_series_ring_element.pyx +3028 -0
- sage/rings/puiseux_series_ring.py +487 -0
- sage/rings/puiseux_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/puiseux_series_ring_element.pxd +7 -0
- sage/rings/puiseux_series_ring_element.pyx +1055 -0
- sage/rings/qqbar_decorators.py +167 -0
- sage/rings/quotient_ring.py +1598 -0
- sage/rings/quotient_ring_element.py +979 -0
- sage/rings/rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/rational.pxd +20 -0
- sage/rings/rational.pyx +4284 -0
- sage/rings/rational_field.py +1730 -0
- sage/rings/real_double.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_double.pxd +16 -0
- sage/rings/real_double.pyx +2218 -0
- sage/rings/real_lazy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_lazy.pxd +30 -0
- sage/rings/real_lazy.pyx +1773 -0
- sage/rings/ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/ring.pxd +30 -0
- sage/rings/ring.pyx +850 -0
- sage/rings/semirings/all.py +3 -0
- sage/rings/semirings/non_negative_integer_semiring.py +107 -0
- sage/rings/semirings/tropical_mpolynomial.py +972 -0
- sage/rings/semirings/tropical_polynomial.py +997 -0
- sage/rings/semirings/tropical_semiring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/semirings/tropical_semiring.pyx +676 -0
- sage/rings/semirings/tropical_variety.py +1701 -0
- sage/rings/sum_of_squares.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/sum_of_squares.pxd +3 -0
- sage/rings/sum_of_squares.pyx +336 -0
- sage/rings/tests.py +504 -0
- sage/schemes/affine/affine_homset.py +508 -0
- sage/schemes/affine/affine_morphism.py +1574 -0
- sage/schemes/affine/affine_point.py +460 -0
- sage/schemes/affine/affine_rational_point.py +308 -0
- sage/schemes/affine/affine_space.py +1264 -0
- sage/schemes/affine/affine_subscheme.py +592 -0
- sage/schemes/affine/all.py +25 -0
- sage/schemes/all__sagemath_categories.py +5 -0
- sage/schemes/generic/algebraic_scheme.py +2092 -0
- sage/schemes/generic/all.py +5 -0
- sage/schemes/generic/ambient_space.py +400 -0
- sage/schemes/generic/divisor.py +465 -0
- sage/schemes/generic/divisor_group.py +313 -0
- sage/schemes/generic/glue.py +84 -0
- sage/schemes/generic/homset.py +820 -0
- sage/schemes/generic/hypersurface.py +234 -0
- sage/schemes/generic/morphism.py +2107 -0
- sage/schemes/generic/point.py +237 -0
- sage/schemes/generic/scheme.py +1190 -0
- sage/schemes/generic/spec.py +199 -0
- sage/schemes/product_projective/all.py +6 -0
- sage/schemes/product_projective/homset.py +236 -0
- sage/schemes/product_projective/morphism.py +517 -0
- sage/schemes/product_projective/point.py +568 -0
- sage/schemes/product_projective/rational_point.py +550 -0
- sage/schemes/product_projective/space.py +1301 -0
- sage/schemes/product_projective/subscheme.py +466 -0
- sage/schemes/projective/all.py +24 -0
- sage/schemes/projective/proj_bdd_height.py +453 -0
- sage/schemes/projective/projective_homset.py +718 -0
- sage/schemes/projective/projective_morphism.py +2792 -0
- sage/schemes/projective/projective_point.py +1484 -0
- sage/schemes/projective/projective_rational_point.py +569 -0
- sage/schemes/projective/projective_space.py +2571 -0
- sage/schemes/projective/projective_subscheme.py +1574 -0
- sage/sets/all.py +17 -0
- sage/sets/cartesian_product.py +376 -0
- sage/sets/condition_set.py +525 -0
- sage/sets/disjoint_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/disjoint_set.pxd +36 -0
- sage/sets/disjoint_set.pyx +998 -0
- sage/sets/disjoint_union_enumerated_sets.py +625 -0
- sage/sets/family.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/family.pxd +12 -0
- sage/sets/family.pyx +1556 -0
- sage/sets/finite_enumerated_set.py +406 -0
- sage/sets/finite_set_map_cy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/finite_set_map_cy.pxd +34 -0
- sage/sets/finite_set_map_cy.pyx +708 -0
- sage/sets/finite_set_maps.py +591 -0
- sage/sets/image_set.py +448 -0
- sage/sets/integer_range.py +829 -0
- sage/sets/non_negative_integers.py +241 -0
- sage/sets/positive_integers.py +93 -0
- sage/sets/primes.py +188 -0
- sage/sets/real_set.py +2760 -0
- sage/sets/recursively_enumerated_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/recursively_enumerated_set.pxd +31 -0
- sage/sets/recursively_enumerated_set.pyx +2082 -0
- sage/sets/set.py +2083 -0
- sage/sets/set_from_iterator.py +1021 -0
- sage/sets/totally_ordered_finite_set.py +329 -0
- sage/symbolic/all__sagemath_categories.py +1 -0
- sage/symbolic/function.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/symbolic/function.pxd +29 -0
- sage/symbolic/function.pyx +1488 -0
- sage/symbolic/symbols.py +56 -0
- sage/tests/all__sagemath_categories.py +1 -0
- sage/tests/cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/cython.pyx +37 -0
- sage/tests/stl_vector.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/stl_vector.pyx +171 -0
- sage/typeset/all.py +6 -0
- sage/typeset/ascii_art.py +295 -0
- sage/typeset/character_art.py +789 -0
- sage/typeset/character_art_factory.py +572 -0
- sage/typeset/symbols.py +334 -0
- sage/typeset/unicode_art.py +183 -0
- sage/typeset/unicode_characters.py +101 -0
|
@@ -0,0 +1,2204 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
r"""
|
|
3
|
+
Polynomial Sequences
|
|
4
|
+
|
|
5
|
+
We call a finite list of polynomials a ``Polynomial Sequence``.
|
|
6
|
+
|
|
7
|
+
Polynomial sequences in Sage can optionally be viewed as consisting of
|
|
8
|
+
various parts or sub-sequences. These kind of polynomial sequences
|
|
9
|
+
which naturally split into parts arise naturally for example in
|
|
10
|
+
algebraic cryptanalysis of symmetric cryptographic primitives. The
|
|
11
|
+
most prominent examples of these systems are: the small scale variants
|
|
12
|
+
of the AES [CMR2005]_ (cf. :func:`sage.crypto.mq.sr.SR`) and Flurry/Curry [BPW2006]_. By
|
|
13
|
+
default, a polynomial sequence has exactly one part.
|
|
14
|
+
|
|
15
|
+
AUTHORS:
|
|
16
|
+
|
|
17
|
+
- Martin Albrecht (2007ff): initial version
|
|
18
|
+
- Martin Albrecht (2009): refactoring, clean-up, new functions
|
|
19
|
+
- Martin Albrecht (2011): refactoring, moved to sage.rings.polynomial
|
|
20
|
+
- Alex Raichev (2011-06): added algebraic_dependence()
|
|
21
|
+
- Charles Bouillaguet (2013-1): added solve()
|
|
22
|
+
|
|
23
|
+
EXAMPLES:
|
|
24
|
+
|
|
25
|
+
As an example consider a small scale variant of the AES::
|
|
26
|
+
|
|
27
|
+
sage: sr = mq.SR(2, 1, 2, 4, gf2=True, polybori=True) # needs sage.rings.polynomial.pbori
|
|
28
|
+
sage: sr # needs sage.rings.polynomial.pbori
|
|
29
|
+
SR(2,1,2,4)
|
|
30
|
+
|
|
31
|
+
We can construct a polynomial sequence for a random plaintext-ciphertext
|
|
32
|
+
pair and study it::
|
|
33
|
+
|
|
34
|
+
sage: set_random_seed(1)
|
|
35
|
+
sage: while True: # workaround (see :issue:`31891`) # needs sage.rings.polynomial.pbori
|
|
36
|
+
....: try:
|
|
37
|
+
....: F, s = sr.polynomial_system()
|
|
38
|
+
....: break
|
|
39
|
+
....: except ZeroDivisionError:
|
|
40
|
+
....: pass
|
|
41
|
+
sage: F # needs sage.rings.polynomial.pbori
|
|
42
|
+
Polynomial Sequence with 112 Polynomials in 64 Variables
|
|
43
|
+
|
|
44
|
+
sage: r2 = F.part(2); r2 # needs sage.rings.polynomial.pbori
|
|
45
|
+
(w200 + k100 + x100 + x102 + x103,
|
|
46
|
+
w201 + k101 + x100 + x101 + x103 + 1,
|
|
47
|
+
w202 + k102 + x100 + x101 + x102 + 1,
|
|
48
|
+
w203 + k103 + x101 + x102 + x103,
|
|
49
|
+
w210 + k110 + x110 + x112 + x113,
|
|
50
|
+
w211 + k111 + x110 + x111 + x113 + 1,
|
|
51
|
+
w212 + k112 + x110 + x111 + x112 + 1,
|
|
52
|
+
w213 + k113 + x111 + x112 + x113,
|
|
53
|
+
x100*w100 + x100*w103 + x101*w102 + x102*w101 + x103*w100,
|
|
54
|
+
x100*w100 + x100*w101 + x101*w100 + x101*w103 + x102*w102 + x103*w101,
|
|
55
|
+
x100*w101 + x100*w102 + x101*w100 + x101*w101 + x102*w100 + x102*w103 + x103*w102,
|
|
56
|
+
x100*w100 + x100*w102 + x100*w103 + x101*w100 + x101*w101 + x102*w102 + x103*w100 + x100,
|
|
57
|
+
x100*w101 + x100*w103 + x101*w101 + x101*w102 + x102*w100 + x102*w103 + x103*w101 + x101,
|
|
58
|
+
x100*w100 + x100*w102 + x101*w100 + x101*w102 + x101*w103 + x102*w100 + x102*w101 + x103*w102 + x102,
|
|
59
|
+
x100*w101 + x100*w102 + x101*w100 + x101*w103 + x102*w101 + x103*w103 + x103,
|
|
60
|
+
x100*w100 + x100*w101 + x100*w103 + x101*w101 + x102*w100 + x102*w102 + x103*w100 + w100,
|
|
61
|
+
x100*w102 + x101*w100 + x101*w101 + x101*w103 + x102*w101 + x103*w100 + x103*w102 + w101,
|
|
62
|
+
x100*w100 + x100*w101 + x100*w102 + x101*w102 + x102*w100 + x102*w101 + x102*w103 + x103*w101 + w102,
|
|
63
|
+
x100*w101 + x101*w100 + x101*w102 + x102*w100 + x103*w101 + x103*w103 + w103,
|
|
64
|
+
x100*w102 + x101*w101 + x102*w100 + x103*w103 + 1,
|
|
65
|
+
x110*w110 + x110*w113 + x111*w112 + x112*w111 + x113*w110,
|
|
66
|
+
x110*w110 + x110*w111 + x111*w110 + x111*w113 + x112*w112 + x113*w111,
|
|
67
|
+
x110*w111 + x110*w112 + x111*w110 + x111*w111 + x112*w110 + x112*w113 + x113*w112,
|
|
68
|
+
x110*w110 + x110*w112 + x110*w113 + x111*w110 + x111*w111 + x112*w112 + x113*w110 + x110,
|
|
69
|
+
x110*w111 + x110*w113 + x111*w111 + x111*w112 + x112*w110 + x112*w113 + x113*w111 + x111,
|
|
70
|
+
x110*w110 + x110*w112 + x111*w110 + x111*w112 + x111*w113 + x112*w110 + x112*w111 + x113*w112 + x112,
|
|
71
|
+
x110*w111 + x110*w112 + x111*w110 + x111*w113 + x112*w111 + x113*w113 + x113,
|
|
72
|
+
x110*w110 + x110*w111 + x110*w113 + x111*w111 + x112*w110 + x112*w112 + x113*w110 + w110,
|
|
73
|
+
x110*w112 + x111*w110 + x111*w111 + x111*w113 + x112*w111 + x113*w110 + x113*w112 + w111,
|
|
74
|
+
x110*w110 + x110*w111 + x110*w112 + x111*w112 + x112*w110 + x112*w111 + x112*w113 + x113*w111 + w112,
|
|
75
|
+
x110*w111 + x111*w110 + x111*w112 + x112*w110 + x113*w111 + x113*w113 + w113,
|
|
76
|
+
x110*w112 + x111*w111 + x112*w110 + x113*w113 + 1)
|
|
77
|
+
|
|
78
|
+
We separate the system in independent subsystems::
|
|
79
|
+
|
|
80
|
+
sage: C = Sequence(r2).connected_components(); C # needs sage.rings.polynomial.pbori
|
|
81
|
+
[[w200 + k100 + x100 + x102 + x103,
|
|
82
|
+
w201 + k101 + x100 + x101 + x103 + 1,
|
|
83
|
+
w202 + k102 + x100 + x101 + x102 + 1,
|
|
84
|
+
w203 + k103 + x101 + x102 + x103,
|
|
85
|
+
x100*w100 + x100*w103 + x101*w102 + x102*w101 + x103*w100,
|
|
86
|
+
x100*w100 + x100*w101 + x101*w100 + x101*w103 + x102*w102 + x103*w101,
|
|
87
|
+
x100*w101 + x100*w102 + x101*w100 + x101*w101 + x102*w100 + x102*w103 + x103*w102,
|
|
88
|
+
x100*w100 + x100*w102 + x100*w103 + x101*w100 + x101*w101 + x102*w102 + x103*w100 + x100,
|
|
89
|
+
x100*w101 + x100*w103 + x101*w101 + x101*w102 + x102*w100 + x102*w103 + x103*w101 + x101,
|
|
90
|
+
x100*w100 + x100*w102 + x101*w100 + x101*w102 + x101*w103 + x102*w100 + x102*w101 + x103*w102 + x102,
|
|
91
|
+
x100*w101 + x100*w102 + x101*w100 + x101*w103 + x102*w101 + x103*w103 + x103,
|
|
92
|
+
x100*w100 + x100*w101 + x100*w103 + x101*w101 + x102*w100 + x102*w102 + x103*w100 + w100,
|
|
93
|
+
x100*w102 + x101*w100 + x101*w101 + x101*w103 + x102*w101 + x103*w100 + x103*w102 + w101,
|
|
94
|
+
x100*w100 + x100*w101 + x100*w102 + x101*w102 + x102*w100 + x102*w101 + x102*w103 + x103*w101 + w102,
|
|
95
|
+
x100*w101 + x101*w100 + x101*w102 + x102*w100 + x103*w101 + x103*w103 + w103,
|
|
96
|
+
x100*w102 + x101*w101 + x102*w100 + x103*w103 + 1],
|
|
97
|
+
[w210 + k110 + x110 + x112 + x113,
|
|
98
|
+
w211 + k111 + x110 + x111 + x113 + 1,
|
|
99
|
+
w212 + k112 + x110 + x111 + x112 + 1,
|
|
100
|
+
w213 + k113 + x111 + x112 + x113,
|
|
101
|
+
x110*w110 + x110*w113 + x111*w112 + x112*w111 + x113*w110,
|
|
102
|
+
x110*w110 + x110*w111 + x111*w110 + x111*w113 + x112*w112 + x113*w111,
|
|
103
|
+
x110*w111 + x110*w112 + x111*w110 + x111*w111 + x112*w110 + x112*w113 + x113*w112,
|
|
104
|
+
x110*w110 + x110*w112 + x110*w113 + x111*w110 + x111*w111 + x112*w112 + x113*w110 + x110,
|
|
105
|
+
x110*w111 + x110*w113 + x111*w111 + x111*w112 + x112*w110 + x112*w113 + x113*w111 + x111,
|
|
106
|
+
x110*w110 + x110*w112 + x111*w110 + x111*w112 + x111*w113 + x112*w110 + x112*w111 + x113*w112 + x112,
|
|
107
|
+
x110*w111 + x110*w112 + x111*w110 + x111*w113 + x112*w111 + x113*w113 + x113,
|
|
108
|
+
x110*w110 + x110*w111 + x110*w113 + x111*w111 + x112*w110 + x112*w112 + x113*w110 + w110,
|
|
109
|
+
x110*w112 + x111*w110 + x111*w111 + x111*w113 + x112*w111 + x113*w110 + x113*w112 + w111,
|
|
110
|
+
x110*w110 + x110*w111 + x110*w112 + x111*w112 + x112*w110 + x112*w111 + x112*w113 + x113*w111 + w112,
|
|
111
|
+
x110*w111 + x111*w110 + x111*w112 + x112*w110 + x113*w111 + x113*w113 + w113,
|
|
112
|
+
x110*w112 + x111*w111 + x112*w110 + x113*w113 + 1]]
|
|
113
|
+
sage: C[0].groebner_basis() # needs sage.rings.polynomial.pbori
|
|
114
|
+
Polynomial Sequence with 30 Polynomials in 16 Variables
|
|
115
|
+
|
|
116
|
+
and compute the coefficient matrix::
|
|
117
|
+
|
|
118
|
+
sage: A,v = Sequence(r2).coefficients_monomials() # needs sage.rings.polynomial.pbori
|
|
119
|
+
sage: A.rank() # needs sage.rings.polynomial.pbori
|
|
120
|
+
32
|
|
121
|
+
|
|
122
|
+
Using these building blocks we can implement a simple XL algorithm
|
|
123
|
+
easily::
|
|
124
|
+
|
|
125
|
+
sage: sr = mq.SR(1,1,1,4, gf2=True, polybori=True, order='lex') # needs sage.rings.polynomial.pbori
|
|
126
|
+
sage: while True: # workaround (see :issue:`31891`) # needs sage.rings.polynomial.pbori
|
|
127
|
+
....: try:
|
|
128
|
+
....: F, s = sr.polynomial_system()
|
|
129
|
+
....: break
|
|
130
|
+
....: except ZeroDivisionError:
|
|
131
|
+
....: pass
|
|
132
|
+
|
|
133
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
134
|
+
sage: monomials = [a*b for a in F.variables() for b in F.variables() if a < b]
|
|
135
|
+
sage: len(monomials)
|
|
136
|
+
190
|
|
137
|
+
sage: F2 = Sequence(map(mul, cartesian_product_iterator((monomials, F))))
|
|
138
|
+
sage: A, v = F2.coefficients_monomials(sparse=False)
|
|
139
|
+
sage: A.echelonize()
|
|
140
|
+
sage: A
|
|
141
|
+
6840 x 4474 dense matrix over Finite Field of size 2...
|
|
142
|
+
sage: A.rank()
|
|
143
|
+
4056
|
|
144
|
+
sage: A[4055] * v
|
|
145
|
+
k001*k003
|
|
146
|
+
|
|
147
|
+
TESTS::
|
|
148
|
+
|
|
149
|
+
sage: P.<x,y> = PolynomialRing(QQ)
|
|
150
|
+
sage: I = [[x^2 + y^2], [x^2 - y^2]]
|
|
151
|
+
sage: F = Sequence(I, P)
|
|
152
|
+
sage: loads(dumps(F)) == F
|
|
153
|
+
True
|
|
154
|
+
|
|
155
|
+
.. NOTE::
|
|
156
|
+
|
|
157
|
+
In many other computer algebra systems (cf. Singular) this class
|
|
158
|
+
would be called ``Ideal`` but an ideal is a very distinct object
|
|
159
|
+
from its generators and thus this is not an ideal in Sage.
|
|
160
|
+
|
|
161
|
+
Classes
|
|
162
|
+
-------
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
from sage.misc.persist import register_unpickle_override
|
|
166
|
+
from sage.misc.cachefunc import cached_method
|
|
167
|
+
from sage.misc.converting_dict import KeyConvertingDict
|
|
168
|
+
from sage.rings.finite_rings.finite_field_base import FiniteField
|
|
169
|
+
from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
|
|
170
|
+
from sage.rings.infinity import Infinity
|
|
171
|
+
from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal
|
|
172
|
+
from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base
|
|
173
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
174
|
+
from sage.rings.polynomial.infinite_polynomial_ring import InfinitePolynomialRing_sparse
|
|
175
|
+
from sage.rings.quotient_ring import QuotientRing_nc
|
|
176
|
+
from sage.structure.sequence import Sequence_generic
|
|
177
|
+
|
|
178
|
+
try:
|
|
179
|
+
from sage.interfaces.singular import singular, singular_gb_standard_options
|
|
180
|
+
from sage.libs.singular.standard_options import \
|
|
181
|
+
libsingular_gb_standard_options
|
|
182
|
+
except ImportError:
|
|
183
|
+
singular = None
|
|
184
|
+
def singular_gb_standard_options(func):
|
|
185
|
+
return func
|
|
186
|
+
libsingular_gb_standard_options = singular_gb_standard_options
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def is_PolynomialSequence(F):
|
|
190
|
+
"""
|
|
191
|
+
Return ``True`` if ``F`` is a ``PolynomialSequence``.
|
|
192
|
+
|
|
193
|
+
INPUT:
|
|
194
|
+
|
|
195
|
+
- ``F`` -- anything
|
|
196
|
+
|
|
197
|
+
EXAMPLES::
|
|
198
|
+
|
|
199
|
+
sage: P.<x,y> = PolynomialRing(QQ)
|
|
200
|
+
sage: I = [[x^2 + y^2], [x^2 - y^2]]
|
|
201
|
+
sage: F = Sequence(I, P); F
|
|
202
|
+
[x^2 + y^2, x^2 - y^2]
|
|
203
|
+
|
|
204
|
+
sage: from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence_generic
|
|
205
|
+
sage: isinstance(F, PolynomialSequence_generic)
|
|
206
|
+
True
|
|
207
|
+
"""
|
|
208
|
+
from sage.misc.superseded import deprecation
|
|
209
|
+
deprecation(38266,
|
|
210
|
+
"The function is_PolynomialSequence is deprecated; "
|
|
211
|
+
"use 'isinstance(..., PolynomialSequence_generic)' instead.")
|
|
212
|
+
return isinstance(F, PolynomialSequence_generic)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None):
|
|
216
|
+
"""
|
|
217
|
+
Construct a new polynomial sequence object.
|
|
218
|
+
|
|
219
|
+
INPUT:
|
|
220
|
+
|
|
221
|
+
- ``arg1`` -- a multivariate polynomial ring, an ideal or a matrix
|
|
222
|
+
|
|
223
|
+
- ``arg2`` -- an iterable object of parts or polynomials
|
|
224
|
+
(default: ``None``)
|
|
225
|
+
|
|
226
|
+
- ``immutable`` -- if ``True`` the sequence is immutable (default: ``False``)
|
|
227
|
+
|
|
228
|
+
- ``cr``, ``cr_str`` -- see :func:`~sage.structure.sequence.Sequence`
|
|
229
|
+
|
|
230
|
+
EXAMPLES::
|
|
231
|
+
|
|
232
|
+
sage: P.<a,b,c,d> = PolynomialRing(GF(127), 4)
|
|
233
|
+
sage: I = sage.rings.ideal.Katsura(P) # needs sage.libs.singular
|
|
234
|
+
|
|
235
|
+
If a list of tuples is provided, those form the parts::
|
|
236
|
+
|
|
237
|
+
sage: F = Sequence([I.gens(),I.gens()], I.ring()); F # indirect doctest # needs sage.libs.singular
|
|
238
|
+
[a + 2*b + 2*c + 2*d - 1,
|
|
239
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
240
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
241
|
+
b^2 + 2*a*c + 2*b*d - c,
|
|
242
|
+
a + 2*b + 2*c + 2*d - 1,
|
|
243
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
244
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
245
|
+
b^2 + 2*a*c + 2*b*d - c]
|
|
246
|
+
sage: F.nparts() # needs sage.libs.singular
|
|
247
|
+
2
|
|
248
|
+
|
|
249
|
+
If an ideal is provided, the generators are used::
|
|
250
|
+
|
|
251
|
+
sage: Sequence(I) # needs sage.libs.singular
|
|
252
|
+
[a + 2*b + 2*c + 2*d - 1,
|
|
253
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
254
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
255
|
+
b^2 + 2*a*c + 2*b*d - c]
|
|
256
|
+
|
|
257
|
+
If a list of polynomials is provided, the system has only one part::
|
|
258
|
+
|
|
259
|
+
sage: F = Sequence(I.gens(), I.ring()); F # needs sage.libs.singular
|
|
260
|
+
[a + 2*b + 2*c + 2*d - 1,
|
|
261
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
262
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
263
|
+
b^2 + 2*a*c + 2*b*d - c]
|
|
264
|
+
sage: F.nparts() # needs sage.libs.singular
|
|
265
|
+
1
|
|
266
|
+
|
|
267
|
+
We test that the ring is inferred correctly::
|
|
268
|
+
|
|
269
|
+
sage: P.<x,y,z> = GF(2)[]
|
|
270
|
+
sage: from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence
|
|
271
|
+
sage: PolynomialSequence([1,x,y]).ring()
|
|
272
|
+
Multivariate Polynomial Ring in x, y, z over Finite Field of size 2
|
|
273
|
+
|
|
274
|
+
sage: PolynomialSequence([[1,x,y], [0]]).ring()
|
|
275
|
+
Multivariate Polynomial Ring in x, y, z over Finite Field of size 2
|
|
276
|
+
|
|
277
|
+
TESTS:
|
|
278
|
+
|
|
279
|
+
A ``PolynomialSequence`` can exist with elements in an infinite field of
|
|
280
|
+
characteristic 2 (see :issue:`19452`)::
|
|
281
|
+
|
|
282
|
+
sage: from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence
|
|
283
|
+
sage: F = GF(2)
|
|
284
|
+
sage: L.<t> = PowerSeriesRing(F,'t')
|
|
285
|
+
sage: R.<x,y> = PolynomialRing(L,'x,y')
|
|
286
|
+
sage: PolynomialSequence([0], R)
|
|
287
|
+
[0]
|
|
288
|
+
|
|
289
|
+
A ``PolynomialSequence`` can be created from an iterator (see :issue:`25989`)::
|
|
290
|
+
|
|
291
|
+
sage: R.<x,y,z> = QQ[]
|
|
292
|
+
sage: PolynomialSequence(iter(R.gens()))
|
|
293
|
+
[x, y, z]
|
|
294
|
+
sage: PolynomialSequence(iter(R.gens()), R)
|
|
295
|
+
[x, y, z]
|
|
296
|
+
sage: PolynomialSequence(iter([(x,y), (z,)]), R)
|
|
297
|
+
[x, y, z]
|
|
298
|
+
|
|
299
|
+
A ``PolynomialSequence`` can be created from elements of an
|
|
300
|
+
``InfinitePolynomialRing``::
|
|
301
|
+
|
|
302
|
+
sage: R.<a> = InfinitePolynomialRing(QQ)
|
|
303
|
+
sage: s = PolynomialSequence([a[i]-a[i+1] for i in range(3)])
|
|
304
|
+
sage: s
|
|
305
|
+
[-a_1 + a_0, -a_2 + a_1, -a_3 + a_2]
|
|
306
|
+
sage: s.coefficients_monomials() # needs sage.modules
|
|
307
|
+
(
|
|
308
|
+
[ 0 0 -1 1]
|
|
309
|
+
[ 0 -1 1 0]
|
|
310
|
+
[-1 1 0 0], (a_3, a_2, a_1, a_0)
|
|
311
|
+
)
|
|
312
|
+
"""
|
|
313
|
+
from sage.structure.element import Matrix
|
|
314
|
+
try:
|
|
315
|
+
from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid
|
|
316
|
+
except ImportError:
|
|
317
|
+
BooleanMonomialMonoid = ()
|
|
318
|
+
|
|
319
|
+
def is_ring(r):
|
|
320
|
+
return (isinstance(r, (MPolynomialRing_base,
|
|
321
|
+
BooleanMonomialMonoid,
|
|
322
|
+
InfinitePolynomialRing_sparse))
|
|
323
|
+
or (isinstance(r, QuotientRing_nc)
|
|
324
|
+
and isinstance(r.cover_ring(), MPolynomialRing_base)))
|
|
325
|
+
|
|
326
|
+
if is_ring(arg1):
|
|
327
|
+
ring, gens = arg1, arg2
|
|
328
|
+
|
|
329
|
+
elif is_ring(arg2):
|
|
330
|
+
ring, gens = arg2, arg1
|
|
331
|
+
|
|
332
|
+
elif isinstance(arg1, Matrix):
|
|
333
|
+
ring, gens = arg1.base_ring(), arg1.list()
|
|
334
|
+
|
|
335
|
+
elif isinstance(arg1, MPolynomialIdeal):
|
|
336
|
+
ring, gens = arg1.ring(), arg1.gens()
|
|
337
|
+
else:
|
|
338
|
+
gens = list(arg1)
|
|
339
|
+
|
|
340
|
+
if arg2:
|
|
341
|
+
ring = arg2
|
|
342
|
+
if not is_ring(ring):
|
|
343
|
+
raise TypeError("Ring '%s' not supported." % ring)
|
|
344
|
+
else:
|
|
345
|
+
try:
|
|
346
|
+
e = next(iter(gens))
|
|
347
|
+
except StopIteration:
|
|
348
|
+
raise ValueError("Cannot determine ring from provided information.")
|
|
349
|
+
|
|
350
|
+
import sage.structure.element as coerce
|
|
351
|
+
|
|
352
|
+
el = 0
|
|
353
|
+
|
|
354
|
+
for f in gens:
|
|
355
|
+
try:
|
|
356
|
+
el, _ = coerce.canonical_coercion(el, f)
|
|
357
|
+
except TypeError:
|
|
358
|
+
el = 0
|
|
359
|
+
for part in gens:
|
|
360
|
+
for f in part:
|
|
361
|
+
el, _ = coerce.canonical_coercion(el, f)
|
|
362
|
+
|
|
363
|
+
if is_ring(el.parent()):
|
|
364
|
+
ring = el.parent()
|
|
365
|
+
else:
|
|
366
|
+
raise TypeError("Cannot determine ring.")
|
|
367
|
+
|
|
368
|
+
try:
|
|
369
|
+
gens = iter(gens)
|
|
370
|
+
e = next(gens)
|
|
371
|
+
# fast path for known collection types
|
|
372
|
+
if isinstance(e, (tuple, list, Sequence_generic, PolynomialSequence_generic)):
|
|
373
|
+
nested = True
|
|
374
|
+
else:
|
|
375
|
+
nested = False
|
|
376
|
+
try:
|
|
377
|
+
e2 = ring(e)
|
|
378
|
+
except TypeError:
|
|
379
|
+
nested = True
|
|
380
|
+
from itertools import chain
|
|
381
|
+
if nested:
|
|
382
|
+
parts = tuple(tuple(ring(f) for f in part) for part in chain([e], gens))
|
|
383
|
+
else:
|
|
384
|
+
parts = tuple(chain([e2], map(ring, gens))),
|
|
385
|
+
except StopIteration:
|
|
386
|
+
parts = ((),)
|
|
387
|
+
|
|
388
|
+
K = ring.base_ring()
|
|
389
|
+
|
|
390
|
+
# make sure we use the polynomial ring as ring not the monoid
|
|
391
|
+
ring = (ring(1) + ring(1)).parent()
|
|
392
|
+
|
|
393
|
+
if not isinstance(K, FiniteField) or K.characteristic() != 2:
|
|
394
|
+
return PolynomialSequence_generic(parts, ring, immutable=immutable, cr=cr, cr_str=cr_str)
|
|
395
|
+
elif K.degree() == 1:
|
|
396
|
+
return PolynomialSequence_gf2(parts, ring, immutable=immutable, cr=cr, cr_str=cr_str)
|
|
397
|
+
elif K.degree() > 1:
|
|
398
|
+
return PolynomialSequence_gf2e(parts, ring, immutable=immutable, cr=cr, cr_str=cr_str)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
class PolynomialSequence_generic(Sequence_generic):
|
|
402
|
+
def __init__(self, parts, ring, immutable=False, cr=False, cr_str=None):
|
|
403
|
+
"""
|
|
404
|
+
Construct a new system of multivariate polynomials.
|
|
405
|
+
|
|
406
|
+
INPUT:
|
|
407
|
+
|
|
408
|
+
- ``parts`` -- a list of lists with polynomials
|
|
409
|
+
|
|
410
|
+
- ``ring`` -- a multivariate polynomial ring
|
|
411
|
+
|
|
412
|
+
- ``immutable`` -- if ``True`` the sequence is immutable (default: ``False``)
|
|
413
|
+
|
|
414
|
+
- ``cr``, ``cr_str`` -- see :func:`~sage.structure.sequence.Sequence`
|
|
415
|
+
|
|
416
|
+
EXAMPLES::
|
|
417
|
+
|
|
418
|
+
sage: P.<a,b,c,d> = PolynomialRing(GF(127), 4)
|
|
419
|
+
sage: I = sage.rings.ideal.Katsura(P) # needs sage.libs.singular
|
|
420
|
+
|
|
421
|
+
sage: Sequence([I.gens()], I.ring()) # indirect doctest # needs sage.libs.singular
|
|
422
|
+
[a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
423
|
+
2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c]
|
|
424
|
+
|
|
425
|
+
If an ideal is provided, the generators are used.::
|
|
426
|
+
|
|
427
|
+
sage: Sequence(I) # needs sage.libs.singular
|
|
428
|
+
[a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
429
|
+
2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c]
|
|
430
|
+
|
|
431
|
+
If a list of polynomials is provided, the system has only one
|
|
432
|
+
part.::
|
|
433
|
+
|
|
434
|
+
sage: Sequence(I.gens(), I.ring()) # needs sage.libs.singular
|
|
435
|
+
[a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
436
|
+
2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c]
|
|
437
|
+
"""
|
|
438
|
+
|
|
439
|
+
Sequence_generic.__init__(self, sum(parts, tuple()), ring, check=False, immutable=immutable,
|
|
440
|
+
cr=cr, cr_str=cr_str, use_sage_types=True)
|
|
441
|
+
self._ring = ring
|
|
442
|
+
self._parts = parts
|
|
443
|
+
|
|
444
|
+
def __copy__(self):
|
|
445
|
+
"""
|
|
446
|
+
Return a copy of this system.
|
|
447
|
+
|
|
448
|
+
EXAMPLES::
|
|
449
|
+
|
|
450
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
451
|
+
sage: sr = mq.SR(allow_zero_inversions=True)
|
|
452
|
+
sage: F,s = sr.polynomial_system()
|
|
453
|
+
sage: copy(F) # indirect doctest
|
|
454
|
+
Polynomial Sequence with 40 Polynomials in 20 Variables
|
|
455
|
+
sage: type(F) == type(copy(F))
|
|
456
|
+
True
|
|
457
|
+
"""
|
|
458
|
+
return self.__class__(self._parts, self._ring, immutable=self.is_immutable())
|
|
459
|
+
|
|
460
|
+
def ring(self):
|
|
461
|
+
"""
|
|
462
|
+
Return the polynomial ring all elements live in.
|
|
463
|
+
|
|
464
|
+
EXAMPLES::
|
|
465
|
+
|
|
466
|
+
sage: sr = mq.SR(allow_zero_inversions=True, gf2=True, order='block') # needs sage.rings.polynomial.pbori
|
|
467
|
+
sage: F, s = sr.polynomial_system() # needs sage.rings.polynomial.pbori
|
|
468
|
+
sage: print(F.ring().repr_long()) # needs sage.rings.polynomial.pbori
|
|
469
|
+
Polynomial Ring
|
|
470
|
+
Base Ring : Finite Field of size 2
|
|
471
|
+
Size : 20 Variables
|
|
472
|
+
Block 0 : Ordering : deglex
|
|
473
|
+
Names : k100, k101, k102, k103, x100, x101, x102, x103, w100, w101, w102, w103, s000, s001, s002, s003
|
|
474
|
+
Block 1 : Ordering : deglex
|
|
475
|
+
Names : k000, k001, k002, k003
|
|
476
|
+
"""
|
|
477
|
+
return self._ring
|
|
478
|
+
|
|
479
|
+
universe = ring
|
|
480
|
+
|
|
481
|
+
def nparts(self):
|
|
482
|
+
"""
|
|
483
|
+
Return number of parts of this system.
|
|
484
|
+
|
|
485
|
+
EXAMPLES::
|
|
486
|
+
|
|
487
|
+
sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori
|
|
488
|
+
sage: F, s = sr.polynomial_system() # needs sage.rings.polynomial.pbori
|
|
489
|
+
sage: F.nparts() # needs sage.rings.polynomial.pbori
|
|
490
|
+
4
|
|
491
|
+
"""
|
|
492
|
+
return len(self._parts)
|
|
493
|
+
|
|
494
|
+
def parts(self):
|
|
495
|
+
"""
|
|
496
|
+
Return a tuple of parts of this system.
|
|
497
|
+
|
|
498
|
+
EXAMPLES::
|
|
499
|
+
|
|
500
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
501
|
+
sage: sr = mq.SR(allow_zero_inversions=True)
|
|
502
|
+
sage: F, s = sr.polynomial_system()
|
|
503
|
+
sage: l = F.parts()
|
|
504
|
+
sage: len(l)
|
|
505
|
+
4
|
|
506
|
+
"""
|
|
507
|
+
return tuple(self._parts)
|
|
508
|
+
|
|
509
|
+
def part(self, i):
|
|
510
|
+
"""
|
|
511
|
+
Return ``i``-th part of this system.
|
|
512
|
+
|
|
513
|
+
EXAMPLES::
|
|
514
|
+
|
|
515
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
516
|
+
sage: sr = mq.SR(allow_zero_inversions=True)
|
|
517
|
+
sage: F, s = sr.polynomial_system()
|
|
518
|
+
sage: R0 = F.part(1)
|
|
519
|
+
sage: R0
|
|
520
|
+
(k000^2 + k001, k001^2 + k002, k002^2 + k003, k003^2 + k000)
|
|
521
|
+
"""
|
|
522
|
+
return self._parts[i]
|
|
523
|
+
|
|
524
|
+
def ideal(self):
|
|
525
|
+
"""
|
|
526
|
+
Return ideal spanned by the elements of this system.
|
|
527
|
+
|
|
528
|
+
EXAMPLES::
|
|
529
|
+
|
|
530
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
531
|
+
sage: sr = mq.SR(allow_zero_inversions=True)
|
|
532
|
+
sage: F, s = sr.polynomial_system()
|
|
533
|
+
sage: P = F.ring()
|
|
534
|
+
sage: I = F.ideal()
|
|
535
|
+
sage: J = I.elimination_ideal(P.gens()[4:-4]) # needs sage.libs.singular
|
|
536
|
+
sage: J <= I # needs sage.libs.singular
|
|
537
|
+
True
|
|
538
|
+
sage: set(J.gens().variables()).issubset(P.gens()[:4] + P.gens()[-4:]) # needs sage.libs.singular
|
|
539
|
+
True
|
|
540
|
+
"""
|
|
541
|
+
return self._ring.ideal(tuple(self))
|
|
542
|
+
|
|
543
|
+
def groebner_basis(self, *args, **kwargs):
|
|
544
|
+
"""
|
|
545
|
+
Compute and return a Groebner basis for the ideal spanned by
|
|
546
|
+
the polynomials in this system.
|
|
547
|
+
|
|
548
|
+
INPUT:
|
|
549
|
+
|
|
550
|
+
- ``args`` -- list of arguments passed to
|
|
551
|
+
``MPolynomialIdeal.groebner_basis`` call
|
|
552
|
+
|
|
553
|
+
- ``kwargs`` -- dictionary of arguments passed to
|
|
554
|
+
``MPolynomialIdeal.groebner_basis`` call
|
|
555
|
+
|
|
556
|
+
EXAMPLES::
|
|
557
|
+
|
|
558
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
559
|
+
sage: sr = mq.SR(allow_zero_inversions=True)
|
|
560
|
+
sage: F, s = sr.polynomial_system()
|
|
561
|
+
sage: gb = F.groebner_basis() # needs sage.libs.singular
|
|
562
|
+
sage: Ideal(gb).basis_is_groebner() # needs sage.libs.singular
|
|
563
|
+
True
|
|
564
|
+
|
|
565
|
+
TESTS:
|
|
566
|
+
|
|
567
|
+
Check that this method also works for boolean polynomials
|
|
568
|
+
(:issue:`10680`)::
|
|
569
|
+
|
|
570
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
571
|
+
sage: B.<a,b,c,d> = BooleanPolynomialRing()
|
|
572
|
+
sage: F0 = Sequence(map(lambda f: f.lm(), [a,b,c,d]))
|
|
573
|
+
sage: F0.groebner_basis()
|
|
574
|
+
[a, b, c, d]
|
|
575
|
+
sage: F1 = Sequence([a,b,c*d,d^2])
|
|
576
|
+
sage: F1.groebner_basis()
|
|
577
|
+
[a, b, d]
|
|
578
|
+
"""
|
|
579
|
+
return self.ideal().groebner_basis(*args, **kwargs)
|
|
580
|
+
|
|
581
|
+
def monomials(self):
|
|
582
|
+
"""
|
|
583
|
+
Return an unordered tuple of monomials in this polynomial system.
|
|
584
|
+
|
|
585
|
+
EXAMPLES::
|
|
586
|
+
|
|
587
|
+
sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori
|
|
588
|
+
sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori
|
|
589
|
+
sage: len(F.monomials()) # needs sage.rings.polynomial.pbori
|
|
590
|
+
49
|
|
591
|
+
"""
|
|
592
|
+
M = set()
|
|
593
|
+
for f in self:
|
|
594
|
+
for m in f.monomials():
|
|
595
|
+
M.add(m)
|
|
596
|
+
return tuple(M)
|
|
597
|
+
|
|
598
|
+
def nmonomials(self):
|
|
599
|
+
"""
|
|
600
|
+
Return the number of monomials present in this system.
|
|
601
|
+
|
|
602
|
+
EXAMPLES::
|
|
603
|
+
|
|
604
|
+
sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori
|
|
605
|
+
sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori
|
|
606
|
+
sage: F.nmonomials() # needs sage.rings.polynomial.pbori
|
|
607
|
+
49
|
|
608
|
+
"""
|
|
609
|
+
return len(self.monomials())
|
|
610
|
+
|
|
611
|
+
def variables(self):
|
|
612
|
+
"""
|
|
613
|
+
Return all variables present in this system. This tuple may or
|
|
614
|
+
may not be equal to the generators of the ring of this system.
|
|
615
|
+
|
|
616
|
+
EXAMPLES::
|
|
617
|
+
|
|
618
|
+
sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori
|
|
619
|
+
sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori
|
|
620
|
+
sage: F.variables()[:10] # needs sage.rings.polynomial.pbori
|
|
621
|
+
(k003, k002, k001, k000, s003, s002, s001, s000, w103, w102)
|
|
622
|
+
"""
|
|
623
|
+
V = set()
|
|
624
|
+
for f in self:
|
|
625
|
+
for v in f.variables():
|
|
626
|
+
V.add(v)
|
|
627
|
+
return tuple(sorted(V))
|
|
628
|
+
|
|
629
|
+
def nvariables(self):
|
|
630
|
+
"""
|
|
631
|
+
Return number of variables present in this system.
|
|
632
|
+
|
|
633
|
+
EXAMPLES::
|
|
634
|
+
|
|
635
|
+
sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori
|
|
636
|
+
sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori
|
|
637
|
+
sage: F.nvariables() # needs sage.rings.polynomial.pbori
|
|
638
|
+
20
|
|
639
|
+
"""
|
|
640
|
+
return len(self.variables())
|
|
641
|
+
|
|
642
|
+
def algebraic_dependence(self):
|
|
643
|
+
r"""
|
|
644
|
+
Return the ideal of annihilating polynomials for the
|
|
645
|
+
polynomials in ``self``, if those polynomials are algebraically
|
|
646
|
+
dependent.
|
|
647
|
+
Otherwise, return the zero ideal.
|
|
648
|
+
|
|
649
|
+
OUTPUT:
|
|
650
|
+
|
|
651
|
+
If the polynomials `f_1,\ldots,f_r` in ``self`` are algebraically
|
|
652
|
+
dependent, then the output is the ideal
|
|
653
|
+
`\{F \in K[T_1,\ldots,T_r] : F(f_1,\ldots,f_r) = 0\}` of
|
|
654
|
+
annihilating polynomials of `f_1,\ldots,f_r`.
|
|
655
|
+
Here `K` is the coefficient ring of polynomial ring of `f_1,\ldots,f_r`
|
|
656
|
+
and `T_1,\ldots,T_r` are new indeterminates.
|
|
657
|
+
If `f_1,\ldots,f_r` are algebraically independent, then the output
|
|
658
|
+
is the zero ideal in `K[T_1,\ldots,T_r]`.
|
|
659
|
+
|
|
660
|
+
EXAMPLES::
|
|
661
|
+
|
|
662
|
+
sage: # needs sage.libs.singular
|
|
663
|
+
sage: R.<x,y> = PolynomialRing(QQ)
|
|
664
|
+
sage: S = Sequence([x, x*y])
|
|
665
|
+
sage: I = S.algebraic_dependence(); I
|
|
666
|
+
Ideal (0) of Multivariate Polynomial Ring in T0, T1 over Rational Field
|
|
667
|
+
|
|
668
|
+
::
|
|
669
|
+
|
|
670
|
+
sage: # needs sage.libs.singular
|
|
671
|
+
sage: R.<x,y> = PolynomialRing(QQ)
|
|
672
|
+
sage: S = Sequence([x, (x^2 + y^2 - 1)^2, x*y - 2])
|
|
673
|
+
sage: I = S.algebraic_dependence(); I
|
|
674
|
+
Ideal (16 + 32*T2 - 8*T0^2 + 24*T2^2 - 8*T0^2*T2 + 8*T2^3 + 9*T0^4 - 2*T0^2*T2^2
|
|
675
|
+
+ T2^4 - T0^4*T1 + 8*T0^4*T2 - 2*T0^6 + 2*T0^4*T2^2 + T0^8)
|
|
676
|
+
of Multivariate Polynomial Ring in T0, T1, T2 over Rational Field
|
|
677
|
+
sage: [F(S) for F in I.gens()]
|
|
678
|
+
[0]
|
|
679
|
+
|
|
680
|
+
::
|
|
681
|
+
|
|
682
|
+
sage: # needs sage.libs.singular
|
|
683
|
+
sage: R.<x,y> = PolynomialRing(GF(7))
|
|
684
|
+
sage: S = Sequence([x, (x^2 + y^2 - 1)^2, x*y - 2])
|
|
685
|
+
sage: I = S.algebraic_dependence(); I
|
|
686
|
+
Ideal (2 - 3*T2 - T0^2 + 3*T2^2 - T0^2*T2 + T2^3 + 2*T0^4 - 2*T0^2*T2^2
|
|
687
|
+
+ T2^4 - T0^4*T1 + T0^4*T2 - 2*T0^6 + 2*T0^4*T2^2 + T0^8)
|
|
688
|
+
of Multivariate Polynomial Ring in T0, T1, T2 over Finite Field of size 7
|
|
689
|
+
sage: [F(S) for F in I.gens()]
|
|
690
|
+
[0]
|
|
691
|
+
|
|
692
|
+
.. NOTE::
|
|
693
|
+
|
|
694
|
+
This function's code also works for sequences of polynomials from a
|
|
695
|
+
univariate polynomial ring, but i don't know where in the Sage codebase
|
|
696
|
+
to put it to use it to that effect.
|
|
697
|
+
|
|
698
|
+
AUTHORS:
|
|
699
|
+
|
|
700
|
+
- Alex Raichev (2011-06-22)
|
|
701
|
+
"""
|
|
702
|
+
R = self.ring()
|
|
703
|
+
K = R.base_ring()
|
|
704
|
+
Xs = list(R.gens())
|
|
705
|
+
r = len(self)
|
|
706
|
+
d = len(Xs)
|
|
707
|
+
|
|
708
|
+
# Expand R by r new variables.
|
|
709
|
+
T = 'T'
|
|
710
|
+
while T in [str(x) for x in Xs]:
|
|
711
|
+
T = T + 'T'
|
|
712
|
+
Ts = [T + str(j) for j in range(r)]
|
|
713
|
+
RR = PolynomialRing(K, d + r, tuple(Xs + Ts))
|
|
714
|
+
Vs = list(RR.gens())
|
|
715
|
+
Xs = Vs[0:d]
|
|
716
|
+
Ts = Vs[d:]
|
|
717
|
+
|
|
718
|
+
J = RR.ideal([Ts[j] - RR(self[j]) for j in range(r)])
|
|
719
|
+
JJ = J.elimination_ideal(Xs)
|
|
720
|
+
# By the elimination theorem, JJ is the kernel of the ring morphism
|
|
721
|
+
# `phi:K[\bar T] \to K[\bar X]` that fixes `K` and sends each
|
|
722
|
+
# `T_i` to `f_i`.
|
|
723
|
+
# So JJ is the ideal of annihilating polynomials of `f_1,\ldots,f_r`,
|
|
724
|
+
# which is the zero ideal in case `f_1,\ldots,f_r` are algebraically
|
|
725
|
+
# independent.
|
|
726
|
+
|
|
727
|
+
# Coerce JJ into `K[T_1,\ldots,T_r]`.
|
|
728
|
+
# Choosing the negdeglex order simply because i find it useful in my work.
|
|
729
|
+
RRR = PolynomialRing(K, r, tuple(Ts), order='negdeglex')
|
|
730
|
+
return RRR.ideal(JJ.gens())
|
|
731
|
+
|
|
732
|
+
def coefficients_monomials(self, order=None, sparse=True):
|
|
733
|
+
"""
|
|
734
|
+
Return the matrix of coefficients ``A`` and
|
|
735
|
+
the matching vector of monomials ``v``, such that ``A*v == vector(self)``.
|
|
736
|
+
|
|
737
|
+
Thus value of ``A[i,j]`` corresponds the coefficient of the
|
|
738
|
+
monomial ``v[j]`` in the ``i``-th polynomial in this system.
|
|
739
|
+
|
|
740
|
+
Monomials are ordered w.r.t. the term ordering of ``order``
|
|
741
|
+
if given; otherwise, they are ordered w.r.t. ``self.ring()``
|
|
742
|
+
in reverse order, i.e., such that the smallest entry comes last.
|
|
743
|
+
|
|
744
|
+
INPUT:
|
|
745
|
+
|
|
746
|
+
- ``sparse`` -- construct a sparse matrix (default: ``True``)
|
|
747
|
+
- ``order`` -- list or tuple specifying the order of monomials (default: ``None``)
|
|
748
|
+
|
|
749
|
+
EXAMPLES::
|
|
750
|
+
|
|
751
|
+
sage: # needs sage.libs.singular
|
|
752
|
+
sage: P.<a,b,c,d> = PolynomialRing(GF(127), 4)
|
|
753
|
+
sage: I = sage.rings.ideal.Katsura(P)
|
|
754
|
+
sage: I.gens()
|
|
755
|
+
[a + 2*b + 2*c + 2*d - 1,
|
|
756
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
757
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
758
|
+
b^2 + 2*a*c + 2*b*d - c]
|
|
759
|
+
sage: F = Sequence(I)
|
|
760
|
+
sage: A,v = F.coefficients_monomials()
|
|
761
|
+
sage: A
|
|
762
|
+
[ 0 0 0 0 0 0 0 0 0 1 2 2 2 126]
|
|
763
|
+
[ 1 0 2 0 0 2 0 0 2 126 0 0 0 0]
|
|
764
|
+
[ 0 2 0 0 2 0 0 2 0 0 126 0 0 0]
|
|
765
|
+
[ 0 0 1 2 0 0 2 0 0 0 0 126 0 0]
|
|
766
|
+
sage: v
|
|
767
|
+
(a^2, a*b, b^2, a*c, b*c, c^2, b*d, c*d, d^2, a, b, c, d, 1)
|
|
768
|
+
sage: A*v
|
|
769
|
+
(a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
770
|
+
2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c)
|
|
771
|
+
"""
|
|
772
|
+
from sage.modules.free_module_element import vector
|
|
773
|
+
from sage.matrix.constructor import matrix
|
|
774
|
+
|
|
775
|
+
if order is None:
|
|
776
|
+
v = sorted(self.monomials(), reverse=True)
|
|
777
|
+
else:
|
|
778
|
+
if isinstance(order, (list, tuple)):
|
|
779
|
+
v = order
|
|
780
|
+
else:
|
|
781
|
+
raise ValueError("order argument can only accept list or tuple")
|
|
782
|
+
|
|
783
|
+
y = dict(zip(v, range(len(v)))) # construct dictionary for fast lookups
|
|
784
|
+
A = matrix(self.ring().base_ring(), len(self), len(v), sparse=sparse)
|
|
785
|
+
for x, poly in enumerate(self):
|
|
786
|
+
for c, m in poly:
|
|
787
|
+
try:
|
|
788
|
+
A[x, y[m]] = c
|
|
789
|
+
except KeyError:
|
|
790
|
+
raise ValueError("order argument does not contain all monomials")
|
|
791
|
+
return A, vector(v)
|
|
792
|
+
|
|
793
|
+
def coefficient_matrix(self, sparse=True):
|
|
794
|
+
"""
|
|
795
|
+
Return tuple ``(A,v)`` where ``A`` is the coefficient matrix
|
|
796
|
+
of this system and ``v`` the matching monomial vector.
|
|
797
|
+
|
|
798
|
+
Thus value of ``A[i,j]`` corresponds the coefficient of the
|
|
799
|
+
monomial ``v[j]`` in the ``i``-th polynomial in this system.
|
|
800
|
+
|
|
801
|
+
Monomials are order w.r.t. the term ordering of
|
|
802
|
+
``self.ring()`` in reverse order, i.e. such that the smallest
|
|
803
|
+
entry comes last.
|
|
804
|
+
|
|
805
|
+
INPUT:
|
|
806
|
+
|
|
807
|
+
- ``sparse`` -- construct a sparse matrix (default: ``True``)
|
|
808
|
+
|
|
809
|
+
EXAMPLES::
|
|
810
|
+
|
|
811
|
+
sage: # needs sage.libs.singular
|
|
812
|
+
sage: P.<a,b,c,d> = PolynomialRing(GF(127), 4)
|
|
813
|
+
sage: I = sage.rings.ideal.Katsura(P)
|
|
814
|
+
sage: I.gens()
|
|
815
|
+
[a + 2*b + 2*c + 2*d - 1,
|
|
816
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
817
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
818
|
+
b^2 + 2*a*c + 2*b*d - c]
|
|
819
|
+
sage: F = Sequence(I)
|
|
820
|
+
sage: A,v = F.coefficient_matrix()
|
|
821
|
+
doctest:warning...
|
|
822
|
+
DeprecationWarning: the function coefficient_matrix is deprecated; use coefficients_monomials instead
|
|
823
|
+
See https://github.com/sagemath/sage/issues/37035 for details.
|
|
824
|
+
sage: A
|
|
825
|
+
[ 0 0 0 0 0 0 0 0 0 1 2 2 2 126]
|
|
826
|
+
[ 1 0 2 0 0 2 0 0 2 126 0 0 0 0]
|
|
827
|
+
[ 0 2 0 0 2 0 0 2 0 0 126 0 0 0]
|
|
828
|
+
[ 0 0 1 2 0 0 2 0 0 0 0 126 0 0]
|
|
829
|
+
sage: v
|
|
830
|
+
[a^2]
|
|
831
|
+
[a*b]
|
|
832
|
+
[b^2]
|
|
833
|
+
[a*c]
|
|
834
|
+
[b*c]
|
|
835
|
+
[c^2]
|
|
836
|
+
[b*d]
|
|
837
|
+
[c*d]
|
|
838
|
+
[d^2]
|
|
839
|
+
[ a]
|
|
840
|
+
[ b]
|
|
841
|
+
[ c]
|
|
842
|
+
[ d]
|
|
843
|
+
[ 1]
|
|
844
|
+
sage: A*v
|
|
845
|
+
[ a + 2*b + 2*c + 2*d - 1]
|
|
846
|
+
[a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a]
|
|
847
|
+
[ 2*a*b + 2*b*c + 2*c*d - b]
|
|
848
|
+
[ b^2 + 2*a*c + 2*b*d - c]
|
|
849
|
+
"""
|
|
850
|
+
from sage.matrix.constructor import matrix
|
|
851
|
+
from sage.misc.superseded import deprecation
|
|
852
|
+
deprecation(37035, "the function coefficient_matrix is deprecated; use coefficients_monomials instead")
|
|
853
|
+
|
|
854
|
+
R = self.ring()
|
|
855
|
+
A, v = self.coefficients_monomials(sparse=sparse)
|
|
856
|
+
return A, matrix(R, len(v), 1, v)
|
|
857
|
+
|
|
858
|
+
def macaulay_matrix(self, degree,
|
|
859
|
+
homogeneous=False,
|
|
860
|
+
variables=None,
|
|
861
|
+
return_indices=False,
|
|
862
|
+
remove_zero=False,
|
|
863
|
+
reverse_column_order=False,
|
|
864
|
+
row_order=None):
|
|
865
|
+
r"""
|
|
866
|
+
Return the Macaulay matrix of degree ``degree`` for this sequence
|
|
867
|
+
of polynomials.
|
|
868
|
+
|
|
869
|
+
INPUT:
|
|
870
|
+
|
|
871
|
+
- ``homogeneous`` -- boolean (default: ``False``);
|
|
872
|
+
when ``False``, the polynomials in the sequence do not need to be homogeneous
|
|
873
|
+
the rows of the Macaulay matrix correspond to all possible products
|
|
874
|
+
between a polynomial from the sequence and monomials of the polynomial
|
|
875
|
+
ring up to degree ``degree``;
|
|
876
|
+
when ``True``, all polynomials in the sequence must be homogeneous, and
|
|
877
|
+
the rows of the Macaulay matrix then represent all possible products
|
|
878
|
+
between a polynomial in the sequence and a monomial of the polynomial
|
|
879
|
+
ring such that the resulting product is homogeneous of degree
|
|
880
|
+
``degree + d_max``, where ``d_max`` is the maximum degree among the
|
|
881
|
+
input polynomials
|
|
882
|
+
|
|
883
|
+
- ``variables`` -- list (default: ``None``);
|
|
884
|
+
when ``None``, ``variables`` is interpreted as being the list of
|
|
885
|
+
all variables of the ring of the polynomials in the sequence;
|
|
886
|
+
otherwise ``variables`` is a list describing a subset of these
|
|
887
|
+
variables, and only these variables are used (instead of all ring
|
|
888
|
+
variables) when forming monomials to multiply the polynomials of the
|
|
889
|
+
sequence
|
|
890
|
+
|
|
891
|
+
- ``return_indices`` -- boolean (default: ``False``);
|
|
892
|
+
when ``False``, only return the Macaulay matrix;
|
|
893
|
+
when ``True``, return the Macaulay matrix and two lists: the first
|
|
894
|
+
one is a list of pairs, each of them containing a monomial and the
|
|
895
|
+
index in the sequence of the input polynomial, whose product
|
|
896
|
+
describes the corresponding row of the matrix; the second one is the
|
|
897
|
+
list of monomials corresponding to the columns of the matrix
|
|
898
|
+
|
|
899
|
+
- ``remove_zero`` -- boolean (default: ``False``);
|
|
900
|
+
when ``False``, all monomials of the polynomial ring up to
|
|
901
|
+
degree ``degree``are included as columns in the Macaulay matrix;
|
|
902
|
+
when ``True``, only the monomials that actually appear in the polynomial
|
|
903
|
+
sequence are included
|
|
904
|
+
|
|
905
|
+
- ``reverse_column_order`` -- boolean (default: ``False``);
|
|
906
|
+
when ``False``, by default, the order of the columns is the same
|
|
907
|
+
as the order of the polynomial ring;
|
|
908
|
+
when ``True``, the order of the columns is the reverse of the order
|
|
909
|
+
of the polynomial ring
|
|
910
|
+
|
|
911
|
+
- ``row_order`` -- str (default: ``None``);
|
|
912
|
+
determines the ordering of the rows in the matrix;
|
|
913
|
+
when ``None`` (or ``"POT"``), a **position over term** (POT) order is used:
|
|
914
|
+
rows are first ordered by the index of the corresponding polynomial
|
|
915
|
+
in the sequence, and then by the (multiplicative) monomials;
|
|
916
|
+
when set to ``"TOP"``, the rows follow a **term over position**
|
|
917
|
+
(TOP) order: rows are first ordered by the (multiplicative) monomials
|
|
918
|
+
and then by the index of the corresponding polynomial
|
|
919
|
+
in the sequence
|
|
920
|
+
|
|
921
|
+
EXAMPLES::
|
|
922
|
+
|
|
923
|
+
sage: R.<x,y,z> = PolynomialRing(GF(7), order='deglex')
|
|
924
|
+
sage: L = Sequence([2*x*z - y*z + 2*z^2 + 3*x - 1,
|
|
925
|
+
....: 2*x^2 - 3*y*z + z^2 - 3*y + 3,
|
|
926
|
+
....: -x^2 - 2*x*z - 3*y*z + 3*x])
|
|
927
|
+
sage: L.macaulay_matrix(0) # needs sage.combinat sage.modules
|
|
928
|
+
[0 0 2 0 6 2 3 0 0 6]
|
|
929
|
+
[2 0 0 0 4 1 0 4 0 3]
|
|
930
|
+
[6 0 5 0 4 0 3 0 0 0]
|
|
931
|
+
|
|
932
|
+
Example with a sequence of homogeneous polynomials::
|
|
933
|
+
|
|
934
|
+
sage: R.<x,y,z> = PolynomialRing(QQ)
|
|
935
|
+
sage: L = Sequence([x*y^2 + y^3 + x*y*z + y*z^2,
|
|
936
|
+
....: x^2*y + x*y^2 + x*y*z + 3*x*z^2 + z^3,
|
|
937
|
+
....: x^3 + 2*y^3 + x^2*z + 2*x*y*z + 2*z^3])
|
|
938
|
+
sage: L.macaulay_matrix(1, homogeneous=True) # needs sage.combinat sage.modules
|
|
939
|
+
[0 0 0 0 0 0 0 1 1 0 1 0 0 1 0]
|
|
940
|
+
[0 0 0 1 1 0 0 1 0 0 0 1 0 0 0]
|
|
941
|
+
[0 0 1 1 0 0 1 0 0 0 1 0 0 0 0]
|
|
942
|
+
[0 0 0 0 0 0 1 1 0 0 1 0 3 0 1]
|
|
943
|
+
[0 0 1 1 0 0 0 1 0 0 3 0 0 1 0]
|
|
944
|
+
[0 1 1 0 0 0 1 0 0 3 0 0 1 0 0]
|
|
945
|
+
[0 0 0 0 0 1 0 0 2 1 2 0 0 0 2]
|
|
946
|
+
[0 1 0 0 2 0 1 2 0 0 0 0 0 2 0]
|
|
947
|
+
[1 0 0 2 0 1 2 0 0 0 0 0 2 0 0]
|
|
948
|
+
|
|
949
|
+
Same example for which we now ask to remove monomials that do not
|
|
950
|
+
appear in the sequence (``remove_zero=True``), and to return the row
|
|
951
|
+
and column indices::
|
|
952
|
+
|
|
953
|
+
sage: R.<x,y,z> = PolynomialRing(QQ)
|
|
954
|
+
sage: L = Sequence([x*y + 2*z^2, y^2 + y*z, x*z])
|
|
955
|
+
sage: L.macaulay_matrix(1, homogeneous=True, remove_zero=True, # needs sage.combinat sage.modules
|
|
956
|
+
....: return_indices=True)
|
|
957
|
+
(
|
|
958
|
+
[0 0 0 0 1 0 0 0 2]
|
|
959
|
+
[0 1 0 0 0 0 0 2 0]
|
|
960
|
+
[1 0 0 0 0 0 2 0 0]
|
|
961
|
+
[0 0 0 0 0 1 0 1 0]
|
|
962
|
+
[0 0 1 0 0 1 0 0 0]
|
|
963
|
+
[0 1 0 0 1 0 0 0 0]
|
|
964
|
+
[0 0 0 0 0 0 1 0 0]
|
|
965
|
+
[0 0 0 0 1 0 0 0 0]
|
|
966
|
+
[0 0 0 1 0 0 0 0 0],
|
|
967
|
+
[(z, 0), (y, 0), (x, 0), (z, 1), (y, 1), (x, 1), (z, 2), (y, 2), (x, 2)],
|
|
968
|
+
[x^2*y, x*y^2, y^3, x^2*z, x*y*z, y^2*z, x*z^2, y*z^2, z^3]
|
|
969
|
+
)
|
|
970
|
+
|
|
971
|
+
Example in which we build rows using monomials that involve only a
|
|
972
|
+
subset of the ring variables (``variables=['x']``)::
|
|
973
|
+
|
|
974
|
+
sage: R.<x,y,z> = PolynomialRing(QQ)
|
|
975
|
+
sage: L = Sequence([2*y*z - 2*z^2 - 3*x + z - 3,
|
|
976
|
+
....: -3*y^2 + 3*y*z + 2*z^2 - 2*x - 2*y,
|
|
977
|
+
....: -2*y - z - 3])
|
|
978
|
+
sage: L.macaulay_matrix(1, variables=['x'], remove_zero=True, # needs sage.combinat sage.modules
|
|
979
|
+
....: return_indices=True)
|
|
980
|
+
(
|
|
981
|
+
[ 0 0 0 0 0 0 0 0 0 2 -2 -3 0 1 -3]
|
|
982
|
+
[ 0 0 0 2 -2 -3 0 0 1 0 0 -3 0 0 0]
|
|
983
|
+
[ 0 0 0 0 0 0 0 -3 0 3 2 -2 -2 0 0]
|
|
984
|
+
[ 0 -3 0 3 2 -2 -2 0 0 0 0 0 0 0 0]
|
|
985
|
+
[ 0 0 0 0 0 0 0 0 0 0 0 0 -2 -1 -3]
|
|
986
|
+
[ 0 0 0 0 0 0 -2 0 -1 0 0 -3 0 0 0]
|
|
987
|
+
[-2 0 -1 0 0 -3 0 0 0 0 0 0 0 0 0],
|
|
988
|
+
[(1, 0), (x, 0), (1, 1), (x, 1), (1, 2), (x, 2), (x^2, 2)],
|
|
989
|
+
[x^2*y, x*y^2, x^2*z, x*y*z, x*z^2, x^2, x*y, y^2, x*z, y*z, z^2, x, y, z, 1]
|
|
990
|
+
)
|
|
991
|
+
|
|
992
|
+
TESTS::
|
|
993
|
+
|
|
994
|
+
sage: R.<x,y,z> = PolynomialRing(GF(7),order='deglex')
|
|
995
|
+
sage: from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence_generic
|
|
996
|
+
sage: PolynomialSequence_generic([], R).macaulay_matrix(1)
|
|
997
|
+
Traceback (most recent call last):
|
|
998
|
+
...
|
|
999
|
+
ValueError: the sequence of polynomials must be nonempty
|
|
1000
|
+
|
|
1001
|
+
sage: Sequence([x*y, x**2]).macaulay_matrix(-1)
|
|
1002
|
+
Traceback (most recent call last):
|
|
1003
|
+
...
|
|
1004
|
+
ValueError: the degree must be nonnegative
|
|
1005
|
+
|
|
1006
|
+
sage: Sequence([y*z + z^2 - 1,x*y - z^2 - x ]).macaulay_matrix(0, homogeneous=True)
|
|
1007
|
+
Traceback (most recent call last):
|
|
1008
|
+
...
|
|
1009
|
+
ValueError: all the polynomials of the sequence must be homogeneous
|
|
1010
|
+
|
|
1011
|
+
sage:Sequence([y*z + z^2 - 1,x*y - z^2 - x ]).macaulay_matrix(0, row_order="POP")
|
|
1012
|
+
Traceback (most recent call last):
|
|
1013
|
+
...
|
|
1014
|
+
ValueError: the argument of ``row_order`` must be ``None``, "TOP" or "POT"
|
|
1015
|
+
|
|
1016
|
+
sage: R1.<t>=PolynomialRing(GF(3))
|
|
1017
|
+
sage: Sequence([y*z + z^2 - 1,x*y - z^2 - x ]).macaulay_matrix(1, variables=[t])
|
|
1018
|
+
Traceback (most recent call last):
|
|
1019
|
+
...
|
|
1020
|
+
ValueError: the variables must be in the polynomial ring
|
|
1021
|
+
|
|
1022
|
+
sage: Sequence([y*z + z^2 - 1,x*y - z^2 - x ]).macaulay_matrix(1, row_order="increasing")
|
|
1023
|
+
Traceback (most recent call last):
|
|
1024
|
+
...
|
|
1025
|
+
ValueError: the argument of ``row_order`` must be ``None``, "TOP" or "POT"
|
|
1026
|
+
|
|
1027
|
+
sage: R.<x,y,z> = PolynomialRing(GF(7),order='degrevlex(2),neglex(1)')
|
|
1028
|
+
sage: Sequence([y*z + z^2 - 1,x*y - z^2 - x ]).macaulay_matrix(1, variables=[x,z])
|
|
1029
|
+
Traceback (most recent call last):
|
|
1030
|
+
...
|
|
1031
|
+
ValueError: impossible to use the original term order (most likely because it was a block order). Please specify the term order for the subring
|
|
1032
|
+
|
|
1033
|
+
REFERENCES:
|
|
1034
|
+
|
|
1035
|
+
[Mac1902]_, Chapter 1 of [Mac1916]_
|
|
1036
|
+
"""
|
|
1037
|
+
m = len(self)
|
|
1038
|
+
|
|
1039
|
+
# handle unsuitable input
|
|
1040
|
+
if m == 0:
|
|
1041
|
+
raise ValueError('the sequence of polynomials must be nonempty')
|
|
1042
|
+
if degree < 0:
|
|
1043
|
+
raise ValueError('the degree must be nonnegative')
|
|
1044
|
+
if homogeneous:
|
|
1045
|
+
for i in range(m):
|
|
1046
|
+
if not (self[i].is_homogeneous()):
|
|
1047
|
+
raise ValueError('all the polynomials of the sequence must be homogeneous')
|
|
1048
|
+
if not (row_order is None or row_order == "TOP" or row_order == "POT"):
|
|
1049
|
+
raise ValueError('the argument of ``row_order`` must be ``None``, "TOP" or "POT"')
|
|
1050
|
+
|
|
1051
|
+
# handle subset of variables
|
|
1052
|
+
S = self.ring()
|
|
1053
|
+
F = S.base_ring()
|
|
1054
|
+
if variables is None:
|
|
1055
|
+
R = S
|
|
1056
|
+
else:
|
|
1057
|
+
vars_names_base_ring = list(S.variable_names())
|
|
1058
|
+
for x in variables:
|
|
1059
|
+
if str(x) not in vars_names_base_ring:
|
|
1060
|
+
raise ValueError("the variables must be in the polynomial ring")
|
|
1061
|
+
try:
|
|
1062
|
+
R = PolynomialRing(F, variables,
|
|
1063
|
+
order=S.term_order())
|
|
1064
|
+
except ValueError:
|
|
1065
|
+
raise ValueError("impossible to use the original term order (most likely because it was a block order). Please specify the term order for the subring")
|
|
1066
|
+
|
|
1067
|
+
# maximum degree for monomials appearing in considered polynomial multiples
|
|
1068
|
+
target_degree = self.maximal_degree() + degree
|
|
1069
|
+
|
|
1070
|
+
# precompute `monomials_of_degree(deg)` for the relevant values of `deg`
|
|
1071
|
+
# homogeneous:
|
|
1072
|
+
# row_indices: we need them for deg = target_degree - self[i].degree(),
|
|
1073
|
+
# for all i = 0 ... len(self)-1
|
|
1074
|
+
# column_indices: we need them for deg = target_degree
|
|
1075
|
+
# non homogeneous:
|
|
1076
|
+
# row_indices: we need them for deg = 0 ... target_degree - self[i].degree(),
|
|
1077
|
+
# for all i = 0 ... len(self)-1,
|
|
1078
|
+
# -> i.e. for deg = 0 ... target_degree - min(self[i].degree() for all i)
|
|
1079
|
+
# column_indices: we need them for deg = 0 ... target_degree
|
|
1080
|
+
R_monomials_of_degree = {}
|
|
1081
|
+
S_monomials_of_degree = {}
|
|
1082
|
+
if homogeneous:
|
|
1083
|
+
for poly_deg in {poly.degree() for poly in self}:
|
|
1084
|
+
deg = target_degree - poly_deg
|
|
1085
|
+
R_monomials_of_degree[deg] = R.monomials_of_degree(deg)
|
|
1086
|
+
S_monomials_of_degree[target_degree] = S.monomials_of_degree(target_degree)
|
|
1087
|
+
else:
|
|
1088
|
+
max_deg = target_degree - min(poly.degree() for poly in self)
|
|
1089
|
+
for deg in range(max_deg + 1):
|
|
1090
|
+
R_monomials_of_degree[deg] = R.monomials_of_degree(deg)
|
|
1091
|
+
for deg in range(target_degree + 1):
|
|
1092
|
+
S_monomials_of_degree[deg] = S.monomials_of_degree(deg)
|
|
1093
|
+
|
|
1094
|
+
# compute list of extended monomials (ring monomials + polynomial position)
|
|
1095
|
+
# that will be used to construct the rows
|
|
1096
|
+
row_indices = []
|
|
1097
|
+
if homogeneous:
|
|
1098
|
+
# order the rows with POT (or None)
|
|
1099
|
+
if row_order is None or row_order == "POT":
|
|
1100
|
+
for i in range(m):
|
|
1101
|
+
deg = target_degree - self[i].degree()
|
|
1102
|
+
R_monomials_of_degree[deg].sort()
|
|
1103
|
+
row_indices += [(mon, i) for mon in R_monomials_of_degree[deg]]
|
|
1104
|
+
# order the rows with TOP
|
|
1105
|
+
else:
|
|
1106
|
+
R_monomials_useful = []
|
|
1107
|
+
for i in range(degree, target_degree-self.minimal_degree()+1):
|
|
1108
|
+
R_monomials_useful += R_monomials_of_degree[i]
|
|
1109
|
+
R_monomials_useful.sort()
|
|
1110
|
+
for mon in R_monomials_useful:
|
|
1111
|
+
row_indices += [(mon, i) for i in range(m) if self[i].degree() + mon.degree() == target_degree]
|
|
1112
|
+
else:
|
|
1113
|
+
# order the row with POT (or None)
|
|
1114
|
+
if row_order is None or row_order == "POT":
|
|
1115
|
+
for i in range(m):
|
|
1116
|
+
R_monomials_useful = []
|
|
1117
|
+
for deg in range(target_degree - self[i].degree() + 1):
|
|
1118
|
+
R_monomials_useful += R_monomials_of_degree[deg]
|
|
1119
|
+
R_monomials_useful.sort()
|
|
1120
|
+
row_indices += [(mon, i) for mon in R_monomials_useful]
|
|
1121
|
+
# order the row with TOP
|
|
1122
|
+
else:
|
|
1123
|
+
R_monomials_useful = []
|
|
1124
|
+
for deg in range(max_deg + 1):
|
|
1125
|
+
R_monomials_useful += R_monomials_of_degree[deg]
|
|
1126
|
+
R_monomials_useful.sort()
|
|
1127
|
+
for mon in R_monomials_useful:
|
|
1128
|
+
row_indices += [(mon, i) for i in range(m)
|
|
1129
|
+
if mon.degree() + self[i].degree() <= target_degree]
|
|
1130
|
+
|
|
1131
|
+
# compute sorted list of monomials that index the columns
|
|
1132
|
+
if remove_zero:
|
|
1133
|
+
# FIXME clean (and refactor multiplications?)
|
|
1134
|
+
column_indices = list(set(sum(((mon * self[i]).monomials() for mon, i in row_indices), [])))
|
|
1135
|
+
else:
|
|
1136
|
+
if homogeneous:
|
|
1137
|
+
column_indices = S_monomials_of_degree[target_degree]
|
|
1138
|
+
else:
|
|
1139
|
+
column_indices = [mon for deg in range(target_degree + 1)
|
|
1140
|
+
for mon in S_monomials_of_degree[deg]]
|
|
1141
|
+
column_indices.sort(reverse=not reverse_column_order)
|
|
1142
|
+
dict_columns = {mon.exponents()[0]: j for (j, mon) in enumerate(column_indices)}
|
|
1143
|
+
|
|
1144
|
+
# actually build the Macaulay matrix
|
|
1145
|
+
from sage.matrix.constructor import matrix
|
|
1146
|
+
|
|
1147
|
+
macaulay_mat = matrix(F, len(row_indices), len(column_indices))
|
|
1148
|
+
for (ii, (mrow, i)) in enumerate(row_indices):
|
|
1149
|
+
# in row ii, we put coefficients of the multiple mrow * self[i]
|
|
1150
|
+
poly = mrow * self[i]
|
|
1151
|
+
for mon, coeff in poly.iterator_exp_coeff():
|
|
1152
|
+
macaulay_mat[ii, dict_columns[mon]] = coeff
|
|
1153
|
+
|
|
1154
|
+
if not return_indices:
|
|
1155
|
+
return macaulay_mat
|
|
1156
|
+
else:
|
|
1157
|
+
return macaulay_mat, row_indices, column_indices
|
|
1158
|
+
|
|
1159
|
+
def subs(self, *args, **kwargs):
|
|
1160
|
+
"""
|
|
1161
|
+
Substitute variables for every polynomial in this system and
|
|
1162
|
+
return a new system. See :meth:`MPolynomial.subs` for calling
|
|
1163
|
+
convention.
|
|
1164
|
+
|
|
1165
|
+
INPUT:
|
|
1166
|
+
|
|
1167
|
+
- ``args`` -- arguments to be passed to :meth:`MPolynomial.subs`
|
|
1168
|
+
- ``kwargs`` -- keyword arguments to be passed to :meth:`MPolynomial.subs`
|
|
1169
|
+
|
|
1170
|
+
EXAMPLES::
|
|
1171
|
+
|
|
1172
|
+
sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori
|
|
1173
|
+
sage: F, s = sr.polynomial_system(); F # needs sage.rings.polynomial.pbori
|
|
1174
|
+
Polynomial Sequence with 40 Polynomials in 20 Variables
|
|
1175
|
+
sage: F = F.subs(s); F # needs sage.rings.polynomial.pbori
|
|
1176
|
+
Polynomial Sequence with 40 Polynomials in 16 Variables
|
|
1177
|
+
"""
|
|
1178
|
+
return PolynomialSequence(self._ring, [tuple([f.subs(*args, **kwargs) for f in r]) for r in self._parts])
|
|
1179
|
+
|
|
1180
|
+
def _singular_(self):
|
|
1181
|
+
"""
|
|
1182
|
+
Return Singular ideal representation of this system.
|
|
1183
|
+
|
|
1184
|
+
EXAMPLES::
|
|
1185
|
+
|
|
1186
|
+
sage: # needs sage.libs.singular
|
|
1187
|
+
sage: P.<a,b,c,d> = PolynomialRing(GF(127))
|
|
1188
|
+
sage: I = sage.rings.ideal.Katsura(P)
|
|
1189
|
+
sage: F = Sequence(I); F
|
|
1190
|
+
[a + 2*b + 2*c + 2*d - 1,
|
|
1191
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
1192
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
1193
|
+
b^2 + 2*a*c + 2*b*d - c]
|
|
1194
|
+
sage: F._singular_()
|
|
1195
|
+
a+2*b+2*c+2*d-1,
|
|
1196
|
+
a^2+2*b^2+2*c^2+2*d^2-a,
|
|
1197
|
+
2*a*b+2*b*c+2*c*d-b,
|
|
1198
|
+
b^2+2*a*c+2*b*d-c
|
|
1199
|
+
"""
|
|
1200
|
+
return singular.ideal(list(self))
|
|
1201
|
+
|
|
1202
|
+
def _magma_init_(self, magma):
|
|
1203
|
+
"""
|
|
1204
|
+
Return Magma ideal representation of the ideal spanned by this
|
|
1205
|
+
system.
|
|
1206
|
+
|
|
1207
|
+
EXAMPLES::
|
|
1208
|
+
|
|
1209
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
1210
|
+
sage: sr = mq.SR(allow_zero_inversions=True, gf2=True)
|
|
1211
|
+
sage: F,s = sr.polynomial_system()
|
|
1212
|
+
sage: F.set_immutable()
|
|
1213
|
+
sage: magma(F) # optional - magma
|
|
1214
|
+
Ideal of Boolean polynomial ring of rank 20 over GF(2)
|
|
1215
|
+
Order: Graded Lexicographical (bit vector word)
|
|
1216
|
+
Variables: k100, k101, k102, k103, x100, x101, x102, x103, w100, w101, w102, w103, s000, s001, s002, s003, k000, k001, k002, k003
|
|
1217
|
+
Basis:
|
|
1218
|
+
[
|
|
1219
|
+
...
|
|
1220
|
+
]
|
|
1221
|
+
"""
|
|
1222
|
+
P = magma(self.ring()).name()
|
|
1223
|
+
v = [x._magma_init_(magma) for x in list(self)]
|
|
1224
|
+
return 'ideal<%s|%s>' % (P, ','.join(v))
|
|
1225
|
+
|
|
1226
|
+
def _is_short_for_repr(self):
|
|
1227
|
+
"""
|
|
1228
|
+
Return whether this system is considered short for :meth:`_repr_`.
|
|
1229
|
+
"""
|
|
1230
|
+
return len(self) < 20
|
|
1231
|
+
|
|
1232
|
+
def _repr_(self):
|
|
1233
|
+
"""
|
|
1234
|
+
Return a string representation of this system.
|
|
1235
|
+
Typically, :meth:`_repr_pretty_` is used instead of this method.
|
|
1236
|
+
|
|
1237
|
+
EXAMPLES::
|
|
1238
|
+
|
|
1239
|
+
sage: # needs sage.libs.singular
|
|
1240
|
+
sage: P.<a,b,c,d> = PolynomialRing(GF(127))
|
|
1241
|
+
sage: I = sage.rings.ideal.Katsura(P)
|
|
1242
|
+
sage: F = Sequence(I); print(F._repr_())
|
|
1243
|
+
[a + 2*b + 2*c + 2*d - 1,
|
|
1244
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
1245
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
1246
|
+
b^2 + 2*a*c + 2*b*d - c]
|
|
1247
|
+
|
|
1248
|
+
If the system contains 20 or more polynomials, a short summary
|
|
1249
|
+
is printed::
|
|
1250
|
+
|
|
1251
|
+
sage: sr = mq.SR(allow_zero_inversions=True, gf2=True) # needs sage.rings.polynomial.pbori
|
|
1252
|
+
sage: F,s = sr.polynomial_system(); F # needs sage.rings.polynomial.pbori
|
|
1253
|
+
Polynomial Sequence with 36 Polynomials in 20 Variables
|
|
1254
|
+
"""
|
|
1255
|
+
if self._is_short_for_repr():
|
|
1256
|
+
return super()._repr_()
|
|
1257
|
+
else:
|
|
1258
|
+
return "Polynomial Sequence with %d Polynomials in %d Variables" % (len(self), self.nvariables())
|
|
1259
|
+
|
|
1260
|
+
def _repr_pretty_(self, p, cycle):
|
|
1261
|
+
"""
|
|
1262
|
+
For pretty printing in the Sage command prompt.
|
|
1263
|
+
|
|
1264
|
+
EXAMPLES::
|
|
1265
|
+
|
|
1266
|
+
sage: # needs sage.libs.singular
|
|
1267
|
+
sage: P.<a,b,c,d> = PolynomialRing(GF(127))
|
|
1268
|
+
sage: I = sage.rings.ideal.Katsura(P)
|
|
1269
|
+
sage: F = Sequence(I); F # indirect doctest
|
|
1270
|
+
[a + 2*b + 2*c + 2*d - 1,
|
|
1271
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
1272
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
1273
|
+
b^2 + 2*a*c + 2*b*d - c]
|
|
1274
|
+
|
|
1275
|
+
If the system contains 20 or more polynomials, a short summary
|
|
1276
|
+
is printed::
|
|
1277
|
+
|
|
1278
|
+
sage: sr = mq.SR(allow_zero_inversions=True, gf2=True) # needs sage.rings.polynomial.pbori
|
|
1279
|
+
sage: F,s = sr.polynomial_system(); F # needs sage.rings.polynomial.pbori
|
|
1280
|
+
Polynomial Sequence with 36 Polynomials in 20 Variables
|
|
1281
|
+
"""
|
|
1282
|
+
if self._is_short_for_repr():
|
|
1283
|
+
super()._repr_pretty_(p, cycle)
|
|
1284
|
+
else:
|
|
1285
|
+
p.text(repr(self))
|
|
1286
|
+
|
|
1287
|
+
def __add__(self, right):
|
|
1288
|
+
"""
|
|
1289
|
+
Add polynomial systems together, i.e. create a union of their
|
|
1290
|
+
polynomials.
|
|
1291
|
+
|
|
1292
|
+
EXAMPLES::
|
|
1293
|
+
|
|
1294
|
+
sage: # needs sage.libs.singular
|
|
1295
|
+
sage: P.<a,b,c,d> = PolynomialRing(GF(127))
|
|
1296
|
+
sage: I = sage.rings.ideal.Katsura(P)
|
|
1297
|
+
sage: F = Sequence(I)
|
|
1298
|
+
sage: F + [a^127 + a]
|
|
1299
|
+
[a + 2*b + 2*c + 2*d - 1,
|
|
1300
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
1301
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
1302
|
+
b^2 + 2*a*c + 2*b*d - c,
|
|
1303
|
+
a^127 + a]
|
|
1304
|
+
sage: F + P.ideal([a^127 + a])
|
|
1305
|
+
[a + 2*b + 2*c + 2*d - 1,
|
|
1306
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
1307
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
1308
|
+
b^2 + 2*a*c + 2*b*d - c,
|
|
1309
|
+
a^127 + a]
|
|
1310
|
+
sage: F + Sequence([a^127 + a], P)
|
|
1311
|
+
[a + 2*b + 2*c + 2*d - 1,
|
|
1312
|
+
a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a,
|
|
1313
|
+
2*a*b + 2*b*c + 2*c*d - b,
|
|
1314
|
+
b^2 + 2*a*c + 2*b*d - c,
|
|
1315
|
+
a^127 + a]
|
|
1316
|
+
"""
|
|
1317
|
+
if isinstance(right, PolynomialSequence_generic) and right.ring() == self.ring():
|
|
1318
|
+
return PolynomialSequence(self.ring(), self.parts() + right.parts())
|
|
1319
|
+
|
|
1320
|
+
elif isinstance(right, (tuple, list)) and all((x.parent() == self.ring() for x in right)):
|
|
1321
|
+
return PolynomialSequence(self.ring(), self.parts() + (right,))
|
|
1322
|
+
|
|
1323
|
+
elif isinstance(right, MPolynomialIdeal) and (right.ring() is self.ring() or right.ring() == self.ring()):
|
|
1324
|
+
return PolynomialSequence(self.ring(), self.parts() + (right.gens(),))
|
|
1325
|
+
|
|
1326
|
+
else:
|
|
1327
|
+
raise TypeError("right must be a system over same ring as self.")
|
|
1328
|
+
|
|
1329
|
+
def connection_graph(self):
|
|
1330
|
+
"""
|
|
1331
|
+
Return the graph which has the variables of this system as
|
|
1332
|
+
vertices and edges between two variables if they appear in the
|
|
1333
|
+
same polynomial.
|
|
1334
|
+
|
|
1335
|
+
EXAMPLES::
|
|
1336
|
+
|
|
1337
|
+
sage: # needs sage.graphs sage.rings.polynomial.pbori
|
|
1338
|
+
sage: B.<x,y,z> = BooleanPolynomialRing()
|
|
1339
|
+
sage: F = Sequence([x*y + y + 1, z + 1])
|
|
1340
|
+
sage: G = F.connection_graph(); G
|
|
1341
|
+
Graph on 3 vertices
|
|
1342
|
+
sage: G.is_connected()
|
|
1343
|
+
False
|
|
1344
|
+
sage: F = Sequence([x])
|
|
1345
|
+
sage: F.connection_graph()
|
|
1346
|
+
Graph on 1 vertex
|
|
1347
|
+
|
|
1348
|
+
TESTS::
|
|
1349
|
+
|
|
1350
|
+
sage: # needs sage.graphs sage.rings.polynomial.pbori
|
|
1351
|
+
sage: F = Sequence([], B)
|
|
1352
|
+
sage: F.connection_graph()
|
|
1353
|
+
Graph on 0 vertices
|
|
1354
|
+
sage: F = Sequence([1], B)
|
|
1355
|
+
sage: F.connection_graph()
|
|
1356
|
+
Graph on 0 vertices
|
|
1357
|
+
sage: F = Sequence([x])
|
|
1358
|
+
sage: F.connection_graph()
|
|
1359
|
+
Graph on 1 vertex
|
|
1360
|
+
sage: F = Sequence([x, y])
|
|
1361
|
+
sage: F.connection_graph()
|
|
1362
|
+
Graph on 2 vertices
|
|
1363
|
+
sage: F = Sequence([x*y*z])
|
|
1364
|
+
sage: F.connection_graph().is_clique()
|
|
1365
|
+
True
|
|
1366
|
+
sage: F = Sequence([x*y, y*z])
|
|
1367
|
+
sage: F.connection_graph().is_clique()
|
|
1368
|
+
False
|
|
1369
|
+
"""
|
|
1370
|
+
from sage.graphs.graph import Graph
|
|
1371
|
+
g = Graph()
|
|
1372
|
+
for f in self:
|
|
1373
|
+
g.add_clique(f.variables())
|
|
1374
|
+
return g
|
|
1375
|
+
|
|
1376
|
+
def connected_components(self):
|
|
1377
|
+
"""
|
|
1378
|
+
Split the polynomial system in systems which do not share any
|
|
1379
|
+
variables.
|
|
1380
|
+
|
|
1381
|
+
EXAMPLES:
|
|
1382
|
+
|
|
1383
|
+
As an example consider one part of AES, which naturally
|
|
1384
|
+
splits into four subsystems which are independent::
|
|
1385
|
+
|
|
1386
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
1387
|
+
sage: sr = mq.SR(2, 4, 4, 8, gf2=True, polybori=True)
|
|
1388
|
+
sage: while True: # workaround (see :issue:`31891`)
|
|
1389
|
+
....: try:
|
|
1390
|
+
....: F, s = sr.polynomial_system()
|
|
1391
|
+
....: break
|
|
1392
|
+
....: except ZeroDivisionError:
|
|
1393
|
+
....: pass
|
|
1394
|
+
sage: Fz = Sequence(F.part(2))
|
|
1395
|
+
sage: Fz.connected_components()
|
|
1396
|
+
[Polynomial Sequence with 128 Polynomials in 128 Variables,
|
|
1397
|
+
Polynomial Sequence with 128 Polynomials in 128 Variables,
|
|
1398
|
+
Polynomial Sequence with 128 Polynomials in 128 Variables,
|
|
1399
|
+
Polynomial Sequence with 128 Polynomials in 128 Variables]
|
|
1400
|
+
|
|
1401
|
+
TESTS:
|
|
1402
|
+
|
|
1403
|
+
Check the order of the output (:issue:`35518`)::
|
|
1404
|
+
|
|
1405
|
+
sage: R.<x,y,z> = PolynomialRing(ZZ)
|
|
1406
|
+
sage: Sequence([x,z,y]).connected_components()
|
|
1407
|
+
[[x], [z], [y]]
|
|
1408
|
+
sage: Sequence([x,z,x*y*z,y]).connected_components()
|
|
1409
|
+
[[x, z, x*y*z, y]]
|
|
1410
|
+
"""
|
|
1411
|
+
# precompute the list of variables in each polynomial
|
|
1412
|
+
vss = [f.variables() for f in self]
|
|
1413
|
+
|
|
1414
|
+
# Use a union-find data structure to encode relationships between
|
|
1415
|
+
# variables, i.e., that they belong to a same polynomial
|
|
1416
|
+
from sage.sets.disjoint_set import DisjointSet
|
|
1417
|
+
DS = DisjointSet(set().union(*vss))
|
|
1418
|
+
for u, *vs in vss:
|
|
1419
|
+
for v in vs:
|
|
1420
|
+
DS.union(u, v)
|
|
1421
|
+
|
|
1422
|
+
Ps = {} # map root element -> polynomials in this component
|
|
1423
|
+
for f, vs in zip(self, vss):
|
|
1424
|
+
r = DS.find(vs[0])
|
|
1425
|
+
if r in Ps:
|
|
1426
|
+
Ps[r].append(f)
|
|
1427
|
+
else:
|
|
1428
|
+
Ps[r] = [f]
|
|
1429
|
+
|
|
1430
|
+
return [PolynomialSequence(self.ring(), p) for p in Ps.values()]
|
|
1431
|
+
|
|
1432
|
+
def _groebner_strategy(self):
|
|
1433
|
+
"""
|
|
1434
|
+
Return the Singular Groebner Strategy object.
|
|
1435
|
+
|
|
1436
|
+
This object allows to compute normal forms efficiently, since
|
|
1437
|
+
all conversion overhead is avoided.
|
|
1438
|
+
|
|
1439
|
+
EXAMPLES::
|
|
1440
|
+
|
|
1441
|
+
sage: P.<x,y,z> = PolynomialRing(GF(127))
|
|
1442
|
+
sage: F = Sequence([x*y + z, y + z + 1])
|
|
1443
|
+
sage: F._groebner_strategy() # needs sage.libs.singular
|
|
1444
|
+
Groebner Strategy for ideal generated by 2 elements over
|
|
1445
|
+
Multivariate Polynomial Ring in x, y, z over Finite Field of size 127
|
|
1446
|
+
"""
|
|
1447
|
+
from sage.libs.singular.groebner_strategy import GroebnerStrategy
|
|
1448
|
+
return GroebnerStrategy(self.ideal())
|
|
1449
|
+
|
|
1450
|
+
def maximal_degree(self):
|
|
1451
|
+
"""
|
|
1452
|
+
Return the maximal degree of any polynomial in this sequence.
|
|
1453
|
+
|
|
1454
|
+
EXAMPLES::
|
|
1455
|
+
|
|
1456
|
+
sage: P.<x,y,z> = PolynomialRing(GF(7))
|
|
1457
|
+
sage: F = Sequence([x*y + x, x])
|
|
1458
|
+
sage: F.maximal_degree()
|
|
1459
|
+
2
|
|
1460
|
+
sage: P.<x,y,z> = PolynomialRing(GF(7))
|
|
1461
|
+
sage: F = Sequence([], universe=P)
|
|
1462
|
+
sage: F.maximal_degree()
|
|
1463
|
+
-1
|
|
1464
|
+
"""
|
|
1465
|
+
try:
|
|
1466
|
+
return max(f.degree() for f in self)
|
|
1467
|
+
except ValueError:
|
|
1468
|
+
return -1 # empty sequence
|
|
1469
|
+
|
|
1470
|
+
def minimal_degree(self):
|
|
1471
|
+
"""
|
|
1472
|
+
Return the minimal degree of any polynomial in this sequence.
|
|
1473
|
+
|
|
1474
|
+
EXAMPLES::
|
|
1475
|
+
|
|
1476
|
+
sage: P.<x,y,z> = PolynomialRing(GF(7))
|
|
1477
|
+
sage: F = Sequence([x*y + x, x])
|
|
1478
|
+
sage: F.minimal_degree()
|
|
1479
|
+
1
|
|
1480
|
+
sage: P.<x,y,z> = PolynomialRing(GF(7))
|
|
1481
|
+
sage: F = Sequence([], universe=P)
|
|
1482
|
+
sage: F.minimal_degree()
|
|
1483
|
+
-1
|
|
1484
|
+
"""
|
|
1485
|
+
try:
|
|
1486
|
+
return min(f.degree() for f in self)
|
|
1487
|
+
except ValueError:
|
|
1488
|
+
return -1 # empty sequence
|
|
1489
|
+
|
|
1490
|
+
def __reduce__(self):
|
|
1491
|
+
"""
|
|
1492
|
+
TESTS::
|
|
1493
|
+
|
|
1494
|
+
sage: P.<x,y,z> = PolynomialRing(GF(127))
|
|
1495
|
+
sage: F = Sequence([x*y + z, y + z + 1])
|
|
1496
|
+
sage: loads(dumps(F)) == F
|
|
1497
|
+
True
|
|
1498
|
+
|
|
1499
|
+
We check that :issue:`26354` is fixed::
|
|
1500
|
+
|
|
1501
|
+
sage: f = P.hom([y,z,x])
|
|
1502
|
+
sage: hash(f) == hash(loads(dumps(f)))
|
|
1503
|
+
True
|
|
1504
|
+
"""
|
|
1505
|
+
return PolynomialSequence, (self._ring, self._parts, self._is_immutable,
|
|
1506
|
+
self._Sequence_generic__cr, self._Sequence_generic__cr_str)
|
|
1507
|
+
|
|
1508
|
+
@singular_gb_standard_options
|
|
1509
|
+
@libsingular_gb_standard_options
|
|
1510
|
+
def reduced(self):
|
|
1511
|
+
r"""
|
|
1512
|
+
If this sequence is `(f_1, ..., f_n)` then this method
|
|
1513
|
+
returns `(g_1, ..., g_s)` such that:
|
|
1514
|
+
|
|
1515
|
+
- `(f_1,...,f_n) = (g_1,...,g_s)`
|
|
1516
|
+
|
|
1517
|
+
- `LT(g_i) \neq LT(g_j)` for all `i \neq j`
|
|
1518
|
+
|
|
1519
|
+
- `LT(g_i)` does not divide `m` for all monomials `m` of
|
|
1520
|
+
`\{g_1,...,g_{i-1},g_{i+1},...,g_s\}`
|
|
1521
|
+
|
|
1522
|
+
- `LC(g_i) = 1` for all `i` if the coefficient ring is a field.
|
|
1523
|
+
|
|
1524
|
+
EXAMPLES::
|
|
1525
|
+
|
|
1526
|
+
sage: R.<x,y,z> = PolynomialRing(QQ)
|
|
1527
|
+
sage: F = Sequence([z*x+y^3,z+y^3,z+x*y])
|
|
1528
|
+
sage: F.reduced() # needs sage.libs.singular
|
|
1529
|
+
[y^3 + z, x*y + z, x*z - z]
|
|
1530
|
+
|
|
1531
|
+
Note that tail reduction for local orderings is not well-defined::
|
|
1532
|
+
|
|
1533
|
+
sage: R.<x,y,z> = PolynomialRing(QQ,order='negdegrevlex')
|
|
1534
|
+
sage: F = Sequence([z*x+y^3,z+y^3,z+x*y])
|
|
1535
|
+
sage: F.reduced() # needs sage.libs.singular
|
|
1536
|
+
[z + x*y, x*y - y^3, x^2*y - y^3]
|
|
1537
|
+
|
|
1538
|
+
A fixed error with nonstandard base fields::
|
|
1539
|
+
|
|
1540
|
+
sage: R.<t>=QQ['t']
|
|
1541
|
+
sage: K.<x,y>=R.fraction_field()['x,y']
|
|
1542
|
+
sage: I=t*x*K
|
|
1543
|
+
sage: I.basis.reduced() # needs sage.libs.singular
|
|
1544
|
+
[x]
|
|
1545
|
+
|
|
1546
|
+
The interreduced basis of 0 is 0::
|
|
1547
|
+
|
|
1548
|
+
sage: P.<x,y,z> = GF(2)[]
|
|
1549
|
+
sage: Sequence([P(0)]).reduced() # needs sage.libs.singular
|
|
1550
|
+
[0]
|
|
1551
|
+
|
|
1552
|
+
Leading coefficients are reduced to 1::
|
|
1553
|
+
|
|
1554
|
+
sage: P.<x,y> = QQ[]
|
|
1555
|
+
sage: Sequence([2*x,y]).reduced() # needs sage.libs.singular
|
|
1556
|
+
[x, y]
|
|
1557
|
+
|
|
1558
|
+
sage: P.<x,y> = CC[] # needs sage.rings.real_mpfr
|
|
1559
|
+
sage: Sequence([2*x,y]).reduced() # needs sage.libs.singular sage.rings.real_mpfr
|
|
1560
|
+
[x, y]
|
|
1561
|
+
|
|
1562
|
+
ALGORITHM:
|
|
1563
|
+
|
|
1564
|
+
Uses Singular's interred command or
|
|
1565
|
+
:func:`sage.rings.polynomial.toy_buchberger.inter_reduction`
|
|
1566
|
+
if conversion to Singular fails.
|
|
1567
|
+
|
|
1568
|
+
TESTS:
|
|
1569
|
+
|
|
1570
|
+
Check that :issue:`26952` is fixed::
|
|
1571
|
+
|
|
1572
|
+
sage: # needs sage.rings.padics
|
|
1573
|
+
sage: Qp = pAdicField(2)
|
|
1574
|
+
sage: R.<x,y,z> = PolynomialRing(Qp, implementation='generic')
|
|
1575
|
+
sage: F = Sequence([z*x+y^3,z+y^3,3*z+x*y])
|
|
1576
|
+
sage: F.reduced()
|
|
1577
|
+
[y^3 + z, x*y + (1 + 2 + O(2^20))*z, x*z - z]
|
|
1578
|
+
"""
|
|
1579
|
+
from sage.rings.polynomial.multi_polynomial_ideal_libsingular import \
|
|
1580
|
+
interred_libsingular
|
|
1581
|
+
from sage.rings.polynomial.multi_polynomial_libsingular import \
|
|
1582
|
+
MPolynomialRing_libsingular
|
|
1583
|
+
|
|
1584
|
+
R = self.ring()
|
|
1585
|
+
|
|
1586
|
+
if isinstance(R, MPolynomialRing_libsingular):
|
|
1587
|
+
return PolynomialSequence(R, interred_libsingular(self), immutable=True)
|
|
1588
|
+
else:
|
|
1589
|
+
try:
|
|
1590
|
+
s = self._singular_().parent()
|
|
1591
|
+
o = s.option("get")
|
|
1592
|
+
s.option("redTail")
|
|
1593
|
+
ret = []
|
|
1594
|
+
for f in self._singular_().interred():
|
|
1595
|
+
f = R(f)
|
|
1596
|
+
ret.append(f.lc()**(-1) * f) # lead coeffs are not reduced by interred
|
|
1597
|
+
s.option("set", o)
|
|
1598
|
+
except TypeError:
|
|
1599
|
+
from sage.rings.polynomial.toy_buchberger import \
|
|
1600
|
+
inter_reduction
|
|
1601
|
+
ret = inter_reduction(self)
|
|
1602
|
+
|
|
1603
|
+
ret = sorted(ret, reverse=True)
|
|
1604
|
+
ret = PolynomialSequence(R, ret, immutable=True)
|
|
1605
|
+
return ret
|
|
1606
|
+
|
|
1607
|
+
@cached_method
|
|
1608
|
+
@singular_gb_standard_options
|
|
1609
|
+
def is_groebner(self, singular=singular):
|
|
1610
|
+
r"""
|
|
1611
|
+
Return ``True`` if the generators of this ideal (``self.gens()``)
|
|
1612
|
+
form a Groebner basis.
|
|
1613
|
+
|
|
1614
|
+
Let `I` be the set of generators of this ideal. The check is
|
|
1615
|
+
performed by trying to lift `Syz(LM(I))` to `Syz(I)` as `I`
|
|
1616
|
+
forms a Groebner basis if and only if for every element `S` in
|
|
1617
|
+
`Syz(LM(I))`:
|
|
1618
|
+
|
|
1619
|
+
.. MATH::
|
|
1620
|
+
|
|
1621
|
+
S \star G = \sum_{i=0}^{m} h_i g_i \longrightarrow_G 0.
|
|
1622
|
+
|
|
1623
|
+
EXAMPLES::
|
|
1624
|
+
|
|
1625
|
+
sage: # needs sage.libs.singular
|
|
1626
|
+
sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127), 10)
|
|
1627
|
+
sage: I = sage.rings.ideal.Cyclic(R, 4)
|
|
1628
|
+
sage: I.basis.is_groebner()
|
|
1629
|
+
False
|
|
1630
|
+
sage: I2 = Ideal(I.groebner_basis())
|
|
1631
|
+
sage: I2.basis.is_groebner()
|
|
1632
|
+
True
|
|
1633
|
+
"""
|
|
1634
|
+
return self.ideal().basis_is_groebner()
|
|
1635
|
+
|
|
1636
|
+
|
|
1637
|
+
class PolynomialSequence_gf2(PolynomialSequence_generic):
|
|
1638
|
+
r"""
|
|
1639
|
+
Polynomial Sequences over `\GF{2}`.
|
|
1640
|
+
"""
|
|
1641
|
+
|
|
1642
|
+
def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reductors=False, use_polybori=False):
|
|
1643
|
+
"""
|
|
1644
|
+
Return a new system where linear leading variables are
|
|
1645
|
+
eliminated if the tail of the polynomial has length at most
|
|
1646
|
+
``maxlength``.
|
|
1647
|
+
|
|
1648
|
+
INPUT:
|
|
1649
|
+
|
|
1650
|
+
- ``maxlength`` -- an optional upper bound on the number of
|
|
1651
|
+
monomials by which a variable is replaced. If
|
|
1652
|
+
``maxlength==+Infinity`` then no condition is checked.
|
|
1653
|
+
(default: +Infinity).
|
|
1654
|
+
|
|
1655
|
+
- ``skip`` -- an optional callable to skip eliminations. It
|
|
1656
|
+
must accept two parameters and return either ``True`` or
|
|
1657
|
+
``False``. The two parameters are the leading term and the
|
|
1658
|
+
tail of a polynomial (default: ``None``).
|
|
1659
|
+
|
|
1660
|
+
- ``return_reductors`` -- if ``True`` the list of polynomials
|
|
1661
|
+
with linear leading terms which were used for reduction is
|
|
1662
|
+
also returned (default: ``False``).
|
|
1663
|
+
|
|
1664
|
+
- ``use_polybori`` -- if ``True`` then ``polybori.ll.eliminate`` is
|
|
1665
|
+
called. While this is typically faster than what is implemented here, it
|
|
1666
|
+
is less flexible (``skip`` is not supported) and may increase the
|
|
1667
|
+
degree (default: ``False``)
|
|
1668
|
+
|
|
1669
|
+
OUTPUT:
|
|
1670
|
+
|
|
1671
|
+
With ``return_reductors=True``, a pair of sequences of
|
|
1672
|
+
boolean polynomials are returned, along with the promises that:
|
|
1673
|
+
|
|
1674
|
+
1. The union of the two sequences spans the
|
|
1675
|
+
same boolean ideal as the argument of the method
|
|
1676
|
+
|
|
1677
|
+
2. The second sequence only contains linear polynomials, and
|
|
1678
|
+
it forms a reduced groebner basis (they all have pairwise
|
|
1679
|
+
distinct leading variables, and the leading variable of a
|
|
1680
|
+
polynomial does not occur anywhere in other polynomials).
|
|
1681
|
+
|
|
1682
|
+
3. The leading variables of the second sequence do not occur
|
|
1683
|
+
anywhere in the first sequence (these variables have been
|
|
1684
|
+
eliminated).
|
|
1685
|
+
|
|
1686
|
+
With ``return_reductors=False``, only the first sequence is
|
|
1687
|
+
returned.
|
|
1688
|
+
|
|
1689
|
+
EXAMPLES::
|
|
1690
|
+
|
|
1691
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
1692
|
+
sage: B.<a,b,c,d> = BooleanPolynomialRing()
|
|
1693
|
+
sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c])
|
|
1694
|
+
sage: F.eliminate_linear_variables() # everything vanishes
|
|
1695
|
+
[]
|
|
1696
|
+
sage: F.eliminate_linear_variables(maxlength=2)
|
|
1697
|
+
[b + c + d + 1, b*c + b*d + c, b*c*d + c]
|
|
1698
|
+
sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a')
|
|
1699
|
+
[a + c + d, a*c + a*d + a + c, c*d + c]
|
|
1700
|
+
|
|
1701
|
+
The list of reductors can be requested by setting ``return_reductors`` to ``True``::
|
|
1702
|
+
|
|
1703
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
1704
|
+
sage: B.<a,b,c,d> = BooleanPolynomialRing()
|
|
1705
|
+
sage: F = Sequence([a + b + d, a + b + c])
|
|
1706
|
+
sage: F, R = F.eliminate_linear_variables(return_reductors=True)
|
|
1707
|
+
sage: F
|
|
1708
|
+
[]
|
|
1709
|
+
sage: R
|
|
1710
|
+
[a + b + d, c + d]
|
|
1711
|
+
|
|
1712
|
+
|
|
1713
|
+
If the input system is detected to be inconsistent then ``[1]`` is returned,
|
|
1714
|
+
and the list of reductors is empty::
|
|
1715
|
+
|
|
1716
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
1717
|
+
sage: R.<x,y,z> = BooleanPolynomialRing()
|
|
1718
|
+
sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z])
|
|
1719
|
+
sage: S.eliminate_linear_variables()
|
|
1720
|
+
[1]
|
|
1721
|
+
sage: R.<x,y,z> = BooleanPolynomialRing()
|
|
1722
|
+
sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z])
|
|
1723
|
+
sage: S.eliminate_linear_variables(return_reductors=True)
|
|
1724
|
+
([1], [])
|
|
1725
|
+
|
|
1726
|
+
|
|
1727
|
+
TESTS:
|
|
1728
|
+
|
|
1729
|
+
The function should really dispose of linear equations (:issue:`13968`)::
|
|
1730
|
+
|
|
1731
|
+
sage: R.<x,y,z> = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori
|
|
1732
|
+
sage: S = Sequence([x + y + z + 1, y + z]) # needs sage.rings.polynomial.pbori
|
|
1733
|
+
sage: S.eliminate_linear_variables(return_reductors=True) # needs sage.rings.polynomial.pbori
|
|
1734
|
+
([], [x + 1, y + z])
|
|
1735
|
+
|
|
1736
|
+
|
|
1737
|
+
The function should take care of linear variables created by previous
|
|
1738
|
+
substitution of linear variables ::
|
|
1739
|
+
|
|
1740
|
+
sage: R.<x,y,z> = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori
|
|
1741
|
+
sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y]) # needs sage.rings.polynomial.pbori
|
|
1742
|
+
sage: S.eliminate_linear_variables(return_reductors=True) # needs sage.rings.polynomial.pbori
|
|
1743
|
+
([], [x + y, z + 1])
|
|
1744
|
+
|
|
1745
|
+
We test a case which would increase the degree with ``polybori=True``::
|
|
1746
|
+
|
|
1747
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
1748
|
+
sage: B.<a,b,c,d> = BooleanPolynomialRing()
|
|
1749
|
+
sage: f = a*d + a + b*d + c*d + 1
|
|
1750
|
+
sage: Sequence([f, a + b*c + c+d + 1]).eliminate_linear_variables()
|
|
1751
|
+
[a*d + a + b*d + c*d + 1, a + b*c + c + d + 1]
|
|
1752
|
+
sage: B.<a,b,c,d> = BooleanPolynomialRing()
|
|
1753
|
+
sage: f = a*d + a + b*d + c*d + 1
|
|
1754
|
+
sage: Sequence([f, a + b*c + c+d + 1]).eliminate_linear_variables(use_polybori=True)
|
|
1755
|
+
[b*c*d + b*c + b*d + c + d]
|
|
1756
|
+
|
|
1757
|
+
.. NOTE::
|
|
1758
|
+
|
|
1759
|
+
This is called "massaging" in [BCJ2007]_.
|
|
1760
|
+
"""
|
|
1761
|
+
from sage.rings.polynomial.multi_polynomial_ring_base import \
|
|
1762
|
+
BooleanPolynomialRing_base
|
|
1763
|
+
|
|
1764
|
+
R = self.ring()
|
|
1765
|
+
|
|
1766
|
+
if not isinstance(R, BooleanPolynomialRing_base):
|
|
1767
|
+
raise NotImplementedError("Only BooleanPolynomialRing's are supported.")
|
|
1768
|
+
|
|
1769
|
+
from sage.rings.polynomial.pbori.ll import (eliminate, ll_encode,
|
|
1770
|
+
ll_red_nf_redsb)
|
|
1771
|
+
from sage.rings.polynomial.pbori.pbori import gauss_on_polys
|
|
1772
|
+
|
|
1773
|
+
F = self
|
|
1774
|
+
reductors = []
|
|
1775
|
+
|
|
1776
|
+
if use_polybori and skip is None and maxlength == Infinity:
|
|
1777
|
+
# faster solution based on polybori.ll.eliminate
|
|
1778
|
+
while True:
|
|
1779
|
+
(this_step_reductors, _, higher) = eliminate(F)
|
|
1780
|
+
if this_step_reductors == []:
|
|
1781
|
+
break
|
|
1782
|
+
reductors.extend(this_step_reductors)
|
|
1783
|
+
F = higher
|
|
1784
|
+
else:
|
|
1785
|
+
# slower, more flexible solution
|
|
1786
|
+
if skip is None:
|
|
1787
|
+
def skip(lm, tail):
|
|
1788
|
+
return False
|
|
1789
|
+
|
|
1790
|
+
while True:
|
|
1791
|
+
linear = []
|
|
1792
|
+
higher = []
|
|
1793
|
+
|
|
1794
|
+
for f in F:
|
|
1795
|
+
if f.degree() == 1 and len(f) <= maxlength + 1:
|
|
1796
|
+
flm = f.lex_lead()
|
|
1797
|
+
if skip(flm, f - flm):
|
|
1798
|
+
higher.append(f)
|
|
1799
|
+
continue
|
|
1800
|
+
linear.append(f)
|
|
1801
|
+
else:
|
|
1802
|
+
higher.append(f)
|
|
1803
|
+
|
|
1804
|
+
if not linear:
|
|
1805
|
+
break
|
|
1806
|
+
|
|
1807
|
+
linear = gauss_on_polys(linear)
|
|
1808
|
+
if 1 in linear:
|
|
1809
|
+
if return_reductors:
|
|
1810
|
+
return PolynomialSequence(R, [R(1)]), PolynomialSequence(R, [])
|
|
1811
|
+
else:
|
|
1812
|
+
return PolynomialSequence(R, [R(1)])
|
|
1813
|
+
rb = ll_encode(linear)
|
|
1814
|
+
reductors.extend(linear)
|
|
1815
|
+
|
|
1816
|
+
F = []
|
|
1817
|
+
for f in higher:
|
|
1818
|
+
f = ll_red_nf_redsb(f, rb)
|
|
1819
|
+
if f != 0:
|
|
1820
|
+
F.append(f)
|
|
1821
|
+
|
|
1822
|
+
ret = PolynomialSequence(R, higher)
|
|
1823
|
+
if return_reductors:
|
|
1824
|
+
reduced_reductors = gauss_on_polys(reductors)
|
|
1825
|
+
return ret, PolynomialSequence(R, reduced_reductors)
|
|
1826
|
+
else:
|
|
1827
|
+
return ret
|
|
1828
|
+
|
|
1829
|
+
def _groebner_strategy(self):
|
|
1830
|
+
"""
|
|
1831
|
+
Return the Singular Groebner Strategy object.
|
|
1832
|
+
|
|
1833
|
+
This object allows to compute normal forms efficiently, since
|
|
1834
|
+
all conversion overhead is avoided.
|
|
1835
|
+
|
|
1836
|
+
EXAMPLES::
|
|
1837
|
+
|
|
1838
|
+
sage: P.<x,y,z> = PolynomialRing(GF(2))
|
|
1839
|
+
sage: F = Sequence([x*y + z, y + z + 1])
|
|
1840
|
+
sage: F._groebner_strategy() # needs sage.libs.singular
|
|
1841
|
+
Groebner Strategy for ideal generated by 2 elements over
|
|
1842
|
+
Multivariate Polynomial Ring in x, y, z over Finite Field of size 2
|
|
1843
|
+
|
|
1844
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
1845
|
+
sage: P.<x,y,z> = BooleanPolynomialRing()
|
|
1846
|
+
sage: F = Sequence([x*y + z, y + z + 1])
|
|
1847
|
+
sage: F._groebner_strategy() # needs sage.libs.singular
|
|
1848
|
+
<sage.rings.polynomial.pbori.pbori.GroebnerStrategy object at 0x...>
|
|
1849
|
+
"""
|
|
1850
|
+
from sage.rings.polynomial.multi_polynomial_ring_base import \
|
|
1851
|
+
BooleanPolynomialRing_base
|
|
1852
|
+
|
|
1853
|
+
R = self.ring()
|
|
1854
|
+
|
|
1855
|
+
if not isinstance(R, BooleanPolynomialRing_base):
|
|
1856
|
+
from sage.libs.singular.groebner_strategy import GroebnerStrategy
|
|
1857
|
+
return GroebnerStrategy(self.ideal())
|
|
1858
|
+
else:
|
|
1859
|
+
from sage.rings.polynomial.pbori.pbori import GroebnerStrategy
|
|
1860
|
+
g = GroebnerStrategy(R)
|
|
1861
|
+
for p in self:
|
|
1862
|
+
g.add_as_you_wish(p)
|
|
1863
|
+
g.reduction_strategy.opt_red_tail = True
|
|
1864
|
+
return g
|
|
1865
|
+
|
|
1866
|
+
def solve(self, algorithm='polybori', n=1,
|
|
1867
|
+
eliminate_linear_variables=True, verbose=False, **kwds):
|
|
1868
|
+
r"""
|
|
1869
|
+
Find solutions of this boolean polynomial system.
|
|
1870
|
+
|
|
1871
|
+
This function provide a unified interface to several algorithms
|
|
1872
|
+
dedicated to solving systems of boolean equations. Depending on
|
|
1873
|
+
the particular nature of the system, some might be much faster
|
|
1874
|
+
than some others.
|
|
1875
|
+
|
|
1876
|
+
INPUT:
|
|
1877
|
+
|
|
1878
|
+
- ``self`` -- a sequence of boolean polynomials
|
|
1879
|
+
|
|
1880
|
+
- ``algorithm`` -- the method to use. Possible values are
|
|
1881
|
+
``'polybori'``, ``'sat'`` and ``'exhaustive_search'``. (default:
|
|
1882
|
+
``'polybori'``, since it is always available)
|
|
1883
|
+
|
|
1884
|
+
- ``n`` -- (default: 1) number of solutions to return. If
|
|
1885
|
+
``n == +Infinity`` then all solutions are returned. If `n < \infty`
|
|
1886
|
+
then `n` solutions are returned if the equations have at least `n`
|
|
1887
|
+
solutions. Otherwise, all the solutions are returned.
|
|
1888
|
+
|
|
1889
|
+
- ``eliminate_linear_variables`` -- whether to eliminate
|
|
1890
|
+
variables that appear linearly. This reduces the number of
|
|
1891
|
+
variables (makes solving faster a priori), but is likely to
|
|
1892
|
+
make the equations denser (may make solving slower depending
|
|
1893
|
+
on the method).
|
|
1894
|
+
|
|
1895
|
+
- ``verbose`` -- boolean (default: ``False``); whether to display
|
|
1896
|
+
progress and (potentially) useful information while the computation
|
|
1897
|
+
runs
|
|
1898
|
+
|
|
1899
|
+
EXAMPLES:
|
|
1900
|
+
|
|
1901
|
+
Without argument, a single arbitrary solution is returned::
|
|
1902
|
+
|
|
1903
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
1904
|
+
sage: R.<x,y,z> = BooleanPolynomialRing()
|
|
1905
|
+
sage: S = Sequence([x*y + z, y*z + x, x + y + z + 1])
|
|
1906
|
+
sage: sol = S.solve()
|
|
1907
|
+
sage: sol
|
|
1908
|
+
[{z: 0, y: 1, x: 0}]
|
|
1909
|
+
|
|
1910
|
+
We check that it is actually a solution::
|
|
1911
|
+
|
|
1912
|
+
sage: S.subs(sol[0]) # needs sage.rings.polynomial.pbori
|
|
1913
|
+
[0, 0, 0]
|
|
1914
|
+
|
|
1915
|
+
We obtain all solutions::
|
|
1916
|
+
|
|
1917
|
+
sage: sols = S.solve(n=Infinity) # needs sage.rings.polynomial.pbori
|
|
1918
|
+
sage: sols # needs sage.rings.polynomial.pbori
|
|
1919
|
+
[{z: 0, y: 1, x: 0}, {z: 1, y: 1, x: 1}]
|
|
1920
|
+
sage: [S.subs(x) for x in sols] # needs sage.rings.polynomial.pbori
|
|
1921
|
+
[[0, 0, 0], [0, 0, 0]]
|
|
1922
|
+
|
|
1923
|
+
We can force the use of exhaustive search if the optional
|
|
1924
|
+
package ``FES`` is present::
|
|
1925
|
+
|
|
1926
|
+
sage: sol = S.solve(algorithm='exhaustive_search') # optional - fes # needs sage.rings.polynomial.pbori
|
|
1927
|
+
sage: sol # optional - fes # needs sage.rings.polynomial.pbori
|
|
1928
|
+
[{z: 1, y: 1, x: 1}]
|
|
1929
|
+
sage: S.subs(sol[0]) # optional - fes # needs sage.rings.polynomial.pbori
|
|
1930
|
+
[0, 0, 0]
|
|
1931
|
+
|
|
1932
|
+
And we may use SAT-solvers if they are available::
|
|
1933
|
+
|
|
1934
|
+
sage: sol = S.solve(algorithm='sat') # optional - pycryptosat # needs sage.rings.polynomial.pbori
|
|
1935
|
+
sage: sol # optional - pycryptosat # needs sage.rings.polynomial.pbori
|
|
1936
|
+
[{z: 0, y: 1, x: 0}]
|
|
1937
|
+
sage: S.subs(sol[0]) # needs sage.rings.polynomial.pbori
|
|
1938
|
+
[0, 0, 0]
|
|
1939
|
+
|
|
1940
|
+
TESTS:
|
|
1941
|
+
|
|
1942
|
+
Make sure that variables not occurring in the equations are no problem::
|
|
1943
|
+
|
|
1944
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
1945
|
+
sage: R.<x,y,z,t> = BooleanPolynomialRing()
|
|
1946
|
+
sage: S = Sequence([x*y + z, y*z + x, x + y + z + 1])
|
|
1947
|
+
sage: sols = S.solve(n=Infinity)
|
|
1948
|
+
sage: [S.subs(x) for x in sols]
|
|
1949
|
+
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
|
|
1950
|
+
|
|
1951
|
+
Not eliminating linear variables::
|
|
1952
|
+
|
|
1953
|
+
sage: sols = S.solve(n=Infinity, eliminate_linear_variables=False) # needs sage.rings.polynomial.pbori
|
|
1954
|
+
sage: [S.subs(x) for x in sols] # needs sage.rings.polynomial.pbori
|
|
1955
|
+
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
|
|
1956
|
+
|
|
1957
|
+
A tricky case where the linear equations are insatisfiable::
|
|
1958
|
+
|
|
1959
|
+
sage: R.<x,y,z> = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori
|
|
1960
|
+
sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z]) # needs sage.rings.polynomial.pbori
|
|
1961
|
+
sage: S.solve() # needs sage.rings.polynomial.pbori
|
|
1962
|
+
[]
|
|
1963
|
+
"""
|
|
1964
|
+
from sage.modules.free_module import VectorSpace
|
|
1965
|
+
|
|
1966
|
+
S = self
|
|
1967
|
+
R_origin = R_solving = self.ring()
|
|
1968
|
+
reductors = []
|
|
1969
|
+
|
|
1970
|
+
if eliminate_linear_variables:
|
|
1971
|
+
T, reductors = self.eliminate_linear_variables(return_reductors=True)
|
|
1972
|
+
if T.variables() != ():
|
|
1973
|
+
from sage.rings.polynomial.pbori.pbori import \
|
|
1974
|
+
BooleanPolynomialRing
|
|
1975
|
+
|
|
1976
|
+
R_solving = BooleanPolynomialRing(T.nvariables(), [str(_) for _ in list(T.variables())])
|
|
1977
|
+
S = PolynomialSequence(R_solving, [R_solving(f) for f in T])
|
|
1978
|
+
|
|
1979
|
+
if S != []:
|
|
1980
|
+
if algorithm == "polybori":
|
|
1981
|
+
I = S.ideal()
|
|
1982
|
+
if verbose:
|
|
1983
|
+
I.groebner_basis(full_prot=True, **kwds)
|
|
1984
|
+
else:
|
|
1985
|
+
I.groebner_basis(**kwds)
|
|
1986
|
+
solutions = I.variety()
|
|
1987
|
+
if len(solutions) >= n:
|
|
1988
|
+
solutions = solutions[:n]
|
|
1989
|
+
|
|
1990
|
+
elif algorithm == "sat":
|
|
1991
|
+
from sage.sat.boolean_polynomials import solve as solve_sat
|
|
1992
|
+
if verbose:
|
|
1993
|
+
solutions = solve_sat(S, n=n, s_verbosity=1, **kwds)
|
|
1994
|
+
else:
|
|
1995
|
+
solutions = solve_sat(S, n=n, **kwds)
|
|
1996
|
+
else:
|
|
1997
|
+
raise ValueError("unknown 'algorithm' value")
|
|
1998
|
+
else:
|
|
1999
|
+
solutions = []
|
|
2000
|
+
|
|
2001
|
+
if S.variables() == ():
|
|
2002
|
+
solved_variables = set()
|
|
2003
|
+
else:
|
|
2004
|
+
solved_variables = {R_origin(x).lm() for x in R_solving.gens()}
|
|
2005
|
+
eliminated_variables = {f.lex_lead() for f in reductors}
|
|
2006
|
+
leftover_variables = {x.lm() for x in R_origin.gens()} - solved_variables - eliminated_variables
|
|
2007
|
+
|
|
2008
|
+
def key_convert(x):
|
|
2009
|
+
return R_origin(x).lm()
|
|
2010
|
+
|
|
2011
|
+
if leftover_variables != set():
|
|
2012
|
+
partial_solutions = solutions
|
|
2013
|
+
solutions = []
|
|
2014
|
+
for sol in partial_solutions:
|
|
2015
|
+
for v in VectorSpace(GF(2), len(leftover_variables)):
|
|
2016
|
+
new_solution = KeyConvertingDict(key_convert, sol)
|
|
2017
|
+
for var, val in zip(leftover_variables, v):
|
|
2018
|
+
new_solution[var] = val
|
|
2019
|
+
solutions.append(new_solution)
|
|
2020
|
+
else:
|
|
2021
|
+
solutions = [KeyConvertingDict(key_convert, sol)
|
|
2022
|
+
for sol in solutions]
|
|
2023
|
+
|
|
2024
|
+
for r in reductors:
|
|
2025
|
+
for sol in solutions:
|
|
2026
|
+
sol[r.lm()] = r.subs(sol).constant_coefficient()
|
|
2027
|
+
|
|
2028
|
+
return solutions
|
|
2029
|
+
|
|
2030
|
+
def reduced(self):
|
|
2031
|
+
r"""
|
|
2032
|
+
If this sequence is `f_1, ..., f_n`, return `g_1, ..., g_s` such that:
|
|
2033
|
+
|
|
2034
|
+
- `(f_1,...,f_n) = (g_1,...,g_s)`
|
|
2035
|
+
- `LT(g_i) \neq LT(g_j)` for all `i \neq j`
|
|
2036
|
+
- `LT(g_i)` does not divide `m` for all monomials `m` of
|
|
2037
|
+
`{g_1,...,g_{i-1},g_{i+1},...,g_s}`
|
|
2038
|
+
|
|
2039
|
+
EXAMPLES::
|
|
2040
|
+
|
|
2041
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
2042
|
+
sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True)
|
|
2043
|
+
sage: while True: # workaround (see :issue:`31891`)
|
|
2044
|
+
....: try:
|
|
2045
|
+
....: F, s = sr.polynomial_system()
|
|
2046
|
+
....: break
|
|
2047
|
+
....: except ZeroDivisionError:
|
|
2048
|
+
....: pass
|
|
2049
|
+
sage: g = F.reduced()
|
|
2050
|
+
sage: len(g) == len(set(gi.lt() for gi in g))
|
|
2051
|
+
True
|
|
2052
|
+
sage: for i in range(len(g)):
|
|
2053
|
+
....: for j in range(len(g)):
|
|
2054
|
+
....: if i == j:
|
|
2055
|
+
....: continue
|
|
2056
|
+
....: for t in list(g[j]):
|
|
2057
|
+
....: assert g[i].lt() not in t.divisors()
|
|
2058
|
+
"""
|
|
2059
|
+
|
|
2060
|
+
from sage.rings.polynomial.multi_polynomial_ring_base import \
|
|
2061
|
+
BooleanPolynomialRing_base
|
|
2062
|
+
|
|
2063
|
+
R = self.ring()
|
|
2064
|
+
|
|
2065
|
+
if isinstance(R, BooleanPolynomialRing_base):
|
|
2066
|
+
from sage.rings.polynomial.pbori.interred import \
|
|
2067
|
+
interred as inter_red
|
|
2068
|
+
|
|
2069
|
+
l = [p for p in self if not p == 0]
|
|
2070
|
+
l = sorted(inter_red(l, completely=True), reverse=True)
|
|
2071
|
+
return PolynomialSequence(l, R, immutable=True)
|
|
2072
|
+
else:
|
|
2073
|
+
return PolynomialSequence_generic.reduced(self)
|
|
2074
|
+
|
|
2075
|
+
def coefficients_monomials(self, order=None, sparse=True):
|
|
2076
|
+
"""
|
|
2077
|
+
Return the matrix of coefficients ``A`` and
|
|
2078
|
+
the matching vector of monomials ``v``, such that ``A*v == vector(self)``.
|
|
2079
|
+
|
|
2080
|
+
Thus value of ``A[i,j]`` corresponds the coefficient of the
|
|
2081
|
+
monomial ``v[j]`` in the ``i``-th polynomial in this system.
|
|
2082
|
+
|
|
2083
|
+
Monomials are ordered w.r.t. the term ordering of ``order``
|
|
2084
|
+
if given; otherwise, they are ordered w.r.t. ``self.ring()``
|
|
2085
|
+
in reverse order, i.e., such that the smallest entry comes last.
|
|
2086
|
+
|
|
2087
|
+
INPUT:
|
|
2088
|
+
|
|
2089
|
+
- ``sparse`` -- construct a sparse matrix (default: ``True``)
|
|
2090
|
+
- ``order`` -- list or tuple specifying the order of monomials (default: ``None``)
|
|
2091
|
+
|
|
2092
|
+
EXAMPLES::
|
|
2093
|
+
|
|
2094
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
2095
|
+
sage: B.<x,y,z> = BooleanPolynomialRing()
|
|
2096
|
+
sage: F = Sequence([x*y + y + 1, z + 1])
|
|
2097
|
+
sage: A, v = F.coefficients_monomials()
|
|
2098
|
+
sage: A
|
|
2099
|
+
[1 1 0 1]
|
|
2100
|
+
[0 0 1 1]
|
|
2101
|
+
sage: v
|
|
2102
|
+
(x*y, y, z, 1)
|
|
2103
|
+
sage: A*v
|
|
2104
|
+
(x*y + y + 1, z + 1)
|
|
2105
|
+
|
|
2106
|
+
TESTS:
|
|
2107
|
+
|
|
2108
|
+
Check that :issue:`37837` has been fixed::
|
|
2109
|
+
|
|
2110
|
+
sage: # needs sage.modules
|
|
2111
|
+
sage: R.<a,b,c> = PolynomialRing(GF(2), ['a', 'b', 'c'])
|
|
2112
|
+
sage: A, v = Sequence([a+b+c]).coefficients_monomials()
|
|
2113
|
+
sage: A
|
|
2114
|
+
[1 1 1]
|
|
2115
|
+
sage: v
|
|
2116
|
+
(a, b, c)
|
|
2117
|
+
sage: A*v
|
|
2118
|
+
(a + b + c)
|
|
2119
|
+
"""
|
|
2120
|
+
from sage.modules.free_module_element import vector
|
|
2121
|
+
from sage.matrix.constructor import matrix
|
|
2122
|
+
from sage.rings.polynomial.multi_polynomial_ring_base import \
|
|
2123
|
+
BooleanPolynomialRing_base
|
|
2124
|
+
|
|
2125
|
+
if order is None:
|
|
2126
|
+
v = sorted(self.monomials(), reverse=True)
|
|
2127
|
+
else:
|
|
2128
|
+
if isinstance(order, (list, tuple)):
|
|
2129
|
+
v = order
|
|
2130
|
+
else:
|
|
2131
|
+
raise ValueError("order argument can only accept list or tuple")
|
|
2132
|
+
|
|
2133
|
+
R = self.ring()
|
|
2134
|
+
K = R.base_ring()
|
|
2135
|
+
y = dict(zip(v, range(len(v)))) # construct dictionary for fast lookups
|
|
2136
|
+
A = matrix(K, len(self), len(v), sparse=sparse)
|
|
2137
|
+
|
|
2138
|
+
if isinstance(R, BooleanPolynomialRing_base):
|
|
2139
|
+
one = K.one()
|
|
2140
|
+
for x, poly in enumerate(self):
|
|
2141
|
+
for m in poly:
|
|
2142
|
+
try:
|
|
2143
|
+
A[x, y[m]] = one
|
|
2144
|
+
except KeyError:
|
|
2145
|
+
raise ValueError("order argument does not contain all monomials")
|
|
2146
|
+
else:
|
|
2147
|
+
for x, poly in enumerate(self):
|
|
2148
|
+
for c, m in poly:
|
|
2149
|
+
try:
|
|
2150
|
+
A[x, y[m]] = c
|
|
2151
|
+
except KeyError:
|
|
2152
|
+
raise ValueError("order argument does not contain all monomials")
|
|
2153
|
+
|
|
2154
|
+
return A, vector(v)
|
|
2155
|
+
|
|
2156
|
+
|
|
2157
|
+
class PolynomialSequence_gf2e(PolynomialSequence_generic):
|
|
2158
|
+
r"""
|
|
2159
|
+
PolynomialSequence over `\GF{2^e}`, i.e extensions over
|
|
2160
|
+
`\GF(2)`.
|
|
2161
|
+
"""
|
|
2162
|
+
|
|
2163
|
+
def weil_restriction(self):
|
|
2164
|
+
r"""
|
|
2165
|
+
Project this polynomial system to `\GF{2}`.
|
|
2166
|
+
|
|
2167
|
+
That is, compute the Weil restriction of scalars for the
|
|
2168
|
+
variety corresponding to this polynomial system and express it
|
|
2169
|
+
as a polynomial system over `\GF{2}`.
|
|
2170
|
+
|
|
2171
|
+
EXAMPLES::
|
|
2172
|
+
|
|
2173
|
+
sage: # needs sage.rings.finite_rings
|
|
2174
|
+
sage: k.<a> = GF(2^2)
|
|
2175
|
+
sage: P.<x,y> = PolynomialRing(k, 2)
|
|
2176
|
+
sage: a = P.base_ring().gen()
|
|
2177
|
+
sage: F = Sequence([x*y + 1, a*x + 1], P)
|
|
2178
|
+
sage: F2 = F.weil_restriction(); F2 # needs sage.libs.singular
|
|
2179
|
+
[x0*y0 + x1*y1 + 1, x1*y0 + x0*y1 + x1*y1, x1 + 1, x0 + x1, x0^2 + x0,
|
|
2180
|
+
x1^2 + x1, y0^2 + y0, y1^2 + y1]
|
|
2181
|
+
|
|
2182
|
+
Another bigger example for a small scale AES::
|
|
2183
|
+
|
|
2184
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
2185
|
+
sage: sr = mq.SR(1, 1, 1, 4, gf2=False)
|
|
2186
|
+
sage: while True: # workaround (see :issue:`31891`)
|
|
2187
|
+
....: try:
|
|
2188
|
+
....: F, s = sr.polynomial_system()
|
|
2189
|
+
....: break
|
|
2190
|
+
....: except ZeroDivisionError:
|
|
2191
|
+
....: pass
|
|
2192
|
+
sage: F
|
|
2193
|
+
Polynomial Sequence with 40 Polynomials in 20 Variables
|
|
2194
|
+
sage: F2 = F.weil_restriction(); F2 # needs sage.libs.singular
|
|
2195
|
+
Polynomial Sequence with 240 Polynomials in 80 Variables
|
|
2196
|
+
"""
|
|
2197
|
+
from sage.rings.ideal import FieldIdeal
|
|
2198
|
+
J = self.ideal().weil_restriction()
|
|
2199
|
+
J += FieldIdeal(J.ring())
|
|
2200
|
+
return PolynomialSequence(J)
|
|
2201
|
+
|
|
2202
|
+
|
|
2203
|
+
register_unpickle_override("sage.crypto.mq.mpolynomialsystem", "MPolynomialSystem_generic", PolynomialSequence_generic)
|
|
2204
|
+
register_unpickle_override("sage.crypto.mq.mpolynomialsystem", "MPolynomialRoundSystem_generic", PolynomialSequence_generic)
|