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,3784 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
"""
|
|
3
|
+
Univariate Polynomial Rings
|
|
4
|
+
|
|
5
|
+
Sage implements sparse and dense polynomials over commutative and
|
|
6
|
+
non-commutative rings. In the non-commutative case, the polynomial
|
|
7
|
+
variable commutes with the elements of the base ring.
|
|
8
|
+
|
|
9
|
+
AUTHOR:
|
|
10
|
+
|
|
11
|
+
- William Stein
|
|
12
|
+
|
|
13
|
+
- Kiran Kedlaya (2006-02-13): added macaulay2 option
|
|
14
|
+
|
|
15
|
+
- Martin Albrecht (2006-08-25): removed it again as it isn't needed anymore
|
|
16
|
+
|
|
17
|
+
- Simon King (2011-05): Dense and sparse polynomial rings must not be equal.
|
|
18
|
+
|
|
19
|
+
- Simon King (2011-10): Choice of categories for polynomial rings.
|
|
20
|
+
|
|
21
|
+
EXAMPLES::
|
|
22
|
+
|
|
23
|
+
sage: z = QQ['z'].0
|
|
24
|
+
sage: (z^3 + z - 1)^3
|
|
25
|
+
z^9 + 3*z^7 - 3*z^6 + 3*z^5 - 6*z^4 + 4*z^3 - 3*z^2 + 3*z - 1
|
|
26
|
+
|
|
27
|
+
Saving and loading of polynomial rings works::
|
|
28
|
+
|
|
29
|
+
sage: loads(dumps(QQ['x'])) == QQ['x']
|
|
30
|
+
True
|
|
31
|
+
sage: k = PolynomialRing(QQ['x'],'y'); loads(dumps(k))==k
|
|
32
|
+
True
|
|
33
|
+
sage: k = PolynomialRing(ZZ,'y'); loads(dumps(k)) == k
|
|
34
|
+
True
|
|
35
|
+
sage: k = PolynomialRing(ZZ,'y', sparse=True); loads(dumps(k))
|
|
36
|
+
Sparse Univariate Polynomial Ring in y over Integer Ring
|
|
37
|
+
|
|
38
|
+
Rings with different variable names are not equal; in fact,
|
|
39
|
+
by :issue:`9944`, polynomial rings are equal if and only
|
|
40
|
+
if they are identical (which should be the case for all parent
|
|
41
|
+
structures in Sage)::
|
|
42
|
+
|
|
43
|
+
sage: QQ['y'] != QQ['x']
|
|
44
|
+
True
|
|
45
|
+
sage: QQ['y'] != QQ['z']
|
|
46
|
+
True
|
|
47
|
+
|
|
48
|
+
We create a polynomial ring over a quaternion algebra::
|
|
49
|
+
|
|
50
|
+
sage: # needs sage.combinat sage.libs.singular sage.modules
|
|
51
|
+
sage: A.<i,j,k> = QuaternionAlgebra(QQ, -1,-1)
|
|
52
|
+
sage: R.<w> = PolynomialRing(A, sparse=True)
|
|
53
|
+
sage: f = w^3 + (i+j)*w + 1
|
|
54
|
+
sage: f
|
|
55
|
+
w^3 + (i + j)*w + 1
|
|
56
|
+
sage: f^2
|
|
57
|
+
w^6 + (2*i + 2*j)*w^4 + 2*w^3 - 2*w^2 + (2*i + 2*j)*w + 1
|
|
58
|
+
sage: f = w + i ; g = w + j
|
|
59
|
+
sage: f * g
|
|
60
|
+
w^2 + (i + j)*w + k
|
|
61
|
+
sage: g * f
|
|
62
|
+
w^2 + (i + j)*w - k
|
|
63
|
+
|
|
64
|
+
:issue:`9944` introduced some changes related with
|
|
65
|
+
coercion. Previously, a dense and a sparse polynomial ring with the
|
|
66
|
+
same variable name over the same base ring evaluated equal, but of
|
|
67
|
+
course they were not identical. Coercion maps are cached - but if a
|
|
68
|
+
coercion to a dense ring is requested and a coercion to a sparse ring
|
|
69
|
+
is returned instead (since the cache keys are equal!), all hell breaks
|
|
70
|
+
loose.
|
|
71
|
+
|
|
72
|
+
Therefore, the coercion between rings of sparse and dense polynomials
|
|
73
|
+
works as follows::
|
|
74
|
+
|
|
75
|
+
sage: R.<x> = PolynomialRing(QQ, sparse=True)
|
|
76
|
+
sage: S.<x> = QQ[]
|
|
77
|
+
sage: S == R
|
|
78
|
+
False
|
|
79
|
+
sage: S.has_coerce_map_from(R)
|
|
80
|
+
True
|
|
81
|
+
sage: R.has_coerce_map_from(S)
|
|
82
|
+
False
|
|
83
|
+
sage: (R.0 + S.0).parent()
|
|
84
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
85
|
+
sage: (S.0 + R.0).parent()
|
|
86
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
87
|
+
|
|
88
|
+
It may be that one has rings of dense or sparse polynomials over
|
|
89
|
+
different base rings. In that situation, coercion works by means of
|
|
90
|
+
the :func:`~sage.categories.pushout.pushout` formalism::
|
|
91
|
+
|
|
92
|
+
sage: R.<x> = PolynomialRing(GF(5), sparse=True)
|
|
93
|
+
sage: S.<x> = PolynomialRing(ZZ)
|
|
94
|
+
sage: R.has_coerce_map_from(S)
|
|
95
|
+
False
|
|
96
|
+
sage: S.has_coerce_map_from(R)
|
|
97
|
+
False
|
|
98
|
+
sage: S.0 + R.0
|
|
99
|
+
2*x
|
|
100
|
+
sage: (S.0 + R.0).parent()
|
|
101
|
+
Univariate Polynomial Ring in x over Finite Field of size 5
|
|
102
|
+
sage: (S.0 + R.0).parent().is_sparse()
|
|
103
|
+
False
|
|
104
|
+
|
|
105
|
+
Similarly, there is a coercion from the (non-default) NTL
|
|
106
|
+
implementation for univariate polynomials over the integers
|
|
107
|
+
to the default FLINT implementation, but not vice versa::
|
|
108
|
+
|
|
109
|
+
sage: R.<x> = PolynomialRing(ZZ, implementation='NTL') # needs sage.libs.ntl
|
|
110
|
+
sage: S.<x> = PolynomialRing(ZZ, implementation='FLINT')
|
|
111
|
+
sage: (S.0 + R.0).parent() is S # needs sage.libs.flint sage.libs.ntl
|
|
112
|
+
True
|
|
113
|
+
sage: (R.0 + S.0).parent() is S # needs sage.libs.flint sage.libs.ntl
|
|
114
|
+
True
|
|
115
|
+
|
|
116
|
+
TESTS::
|
|
117
|
+
|
|
118
|
+
sage: K.<x> = FractionField(QQ['x'])
|
|
119
|
+
sage: V.<z> = K[]
|
|
120
|
+
sage: x+z
|
|
121
|
+
z + x
|
|
122
|
+
|
|
123
|
+
Check that :issue:`5562` has been fixed::
|
|
124
|
+
|
|
125
|
+
sage: R.<u> = PolynomialRing(RDF, 1)
|
|
126
|
+
sage: v1 = vector([u]) # needs sage.modules
|
|
127
|
+
sage: v2 = vector([CDF(2)]) # needs sage.modules
|
|
128
|
+
sage: v1 * v2 # needs sage.modules
|
|
129
|
+
2.0*u
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
# ****************************************************************************
|
|
133
|
+
# Copyright (C) 2006 William Stein <wstein@gmail.com>
|
|
134
|
+
#
|
|
135
|
+
# This program is free software: you can redistribute it and/or modify
|
|
136
|
+
# it under the terms of the GNU General Public License as published by
|
|
137
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
138
|
+
# (at your option) any later version.
|
|
139
|
+
# https://www.gnu.org/licenses/
|
|
140
|
+
# ****************************************************************************
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
import sys
|
|
144
|
+
|
|
145
|
+
from sage.misc.superseded import deprecation
|
|
146
|
+
from sage.structure.element import Element
|
|
147
|
+
from sage.structure.category_object import check_default_category
|
|
148
|
+
|
|
149
|
+
import sage.categories as categories
|
|
150
|
+
from sage.categories.morphism import IdentityMorphism
|
|
151
|
+
from sage.categories.principal_ideal_domains import PrincipalIdealDomains
|
|
152
|
+
from sage.categories.rings import Rings
|
|
153
|
+
|
|
154
|
+
from sage.rings.ring import Ring, CommutativeRing
|
|
155
|
+
from sage.structure.element import RingElement
|
|
156
|
+
import sage.rings.rational_field as rational_field
|
|
157
|
+
from sage.rings.rational_field import QQ
|
|
158
|
+
from sage.rings.integer_ring import ZZ
|
|
159
|
+
from sage.rings.integer import Integer
|
|
160
|
+
from sage.rings.number_field.number_field_base import NumberField
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
from cypari2.gen import Gen as pari_gen
|
|
164
|
+
except ImportError:
|
|
165
|
+
pari_gen = ()
|
|
166
|
+
|
|
167
|
+
from sage.rings.polynomial.polynomial_ring_constructor import polynomial_default_category
|
|
168
|
+
|
|
169
|
+
import sage.misc.latex as latex
|
|
170
|
+
from sage.misc.cachefunc import cached_method
|
|
171
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
|
172
|
+
|
|
173
|
+
import sage.rings.abc
|
|
174
|
+
from sage.rings.fraction_field_element import FractionFieldElement
|
|
175
|
+
from sage.rings.finite_rings.element_base import FiniteRingElement
|
|
176
|
+
from sage.rings.polynomial.polynomial_singular_interface import PolynomialRing_singular_repr
|
|
177
|
+
from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular
|
|
178
|
+
from sage.rings.power_series_ring_element import PowerSeries
|
|
179
|
+
|
|
180
|
+
_CommutativeRings = categories.commutative_rings.CommutativeRings()
|
|
181
|
+
|
|
182
|
+
import sage.interfaces.abc
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def is_PolynomialRing(x):
|
|
186
|
+
"""
|
|
187
|
+
Return ``True`` if ``x`` is a *univariate* polynomial ring (and not a
|
|
188
|
+
sparse multivariate polynomial ring in one variable).
|
|
189
|
+
|
|
190
|
+
EXAMPLES::
|
|
191
|
+
|
|
192
|
+
sage: from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
|
|
193
|
+
sage: from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing
|
|
194
|
+
sage: is_PolynomialRing(2)
|
|
195
|
+
doctest:warning...
|
|
196
|
+
DeprecationWarning: The function is_PolynomialRing is deprecated;
|
|
197
|
+
use 'isinstance(..., PolynomialRing_generic)' instead.
|
|
198
|
+
See https://github.com/sagemath/sage/issues/38266 for details.
|
|
199
|
+
False
|
|
200
|
+
|
|
201
|
+
This polynomial ring is not univariate.
|
|
202
|
+
|
|
203
|
+
::
|
|
204
|
+
|
|
205
|
+
sage: is_PolynomialRing(ZZ['x,y,z'])
|
|
206
|
+
False
|
|
207
|
+
sage: is_MPolynomialRing(ZZ['x,y,z'])
|
|
208
|
+
doctest:warning...
|
|
209
|
+
DeprecationWarning: The function is_MPolynomialRing is deprecated;
|
|
210
|
+
use 'isinstance(..., MPolynomialRing_base)' instead.
|
|
211
|
+
See https://github.com/sagemath/sage/issues/38266 for details.
|
|
212
|
+
True
|
|
213
|
+
|
|
214
|
+
::
|
|
215
|
+
|
|
216
|
+
sage: is_PolynomialRing(ZZ['w'])
|
|
217
|
+
True
|
|
218
|
+
|
|
219
|
+
Univariate means not only in one variable, but is a specific data
|
|
220
|
+
type. There is a multivariate (sparse) polynomial ring data type,
|
|
221
|
+
which supports a single variable as a special case.
|
|
222
|
+
|
|
223
|
+
::
|
|
224
|
+
|
|
225
|
+
sage: # needs sage.libs.singular
|
|
226
|
+
sage: R.<w> = PolynomialRing(ZZ, implementation='singular'); R
|
|
227
|
+
Multivariate Polynomial Ring in w over Integer Ring
|
|
228
|
+
sage: is_PolynomialRing(R)
|
|
229
|
+
False
|
|
230
|
+
sage: type(R)
|
|
231
|
+
<class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomialRing_libsingular'>
|
|
232
|
+
"""
|
|
233
|
+
deprecation(38266,
|
|
234
|
+
"The function is_PolynomialRing is deprecated; "
|
|
235
|
+
"use 'isinstance(..., PolynomialRing_generic)' instead.")
|
|
236
|
+
return isinstance(x, PolynomialRing_generic)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
#########################################################################################
|
|
240
|
+
|
|
241
|
+
class PolynomialRing_generic(Ring):
|
|
242
|
+
"""
|
|
243
|
+
Univariate polynomial ring over a ring.
|
|
244
|
+
"""
|
|
245
|
+
|
|
246
|
+
def __init__(self, base_ring, name=None, sparse=False, implementation=None,
|
|
247
|
+
element_class=None, category=None):
|
|
248
|
+
"""
|
|
249
|
+
EXAMPLES::
|
|
250
|
+
|
|
251
|
+
sage: R.<x> = QQ['x']
|
|
252
|
+
sage: R(-1) + R(1)
|
|
253
|
+
0
|
|
254
|
+
sage: (x - 2/3)*(x^2 - 8*x + 16)
|
|
255
|
+
x^3 - 26/3*x^2 + 64/3*x - 32/3
|
|
256
|
+
|
|
257
|
+
sage: category(ZZ['x'])
|
|
258
|
+
Join of Category of unique factorization domains
|
|
259
|
+
and Category of algebras with basis over
|
|
260
|
+
(Dedekind domains and euclidean domains
|
|
261
|
+
and noetherian rings and infinite enumerated sets
|
|
262
|
+
and metric spaces)
|
|
263
|
+
and Category of commutative algebras over
|
|
264
|
+
(Dedekind domains and euclidean domains
|
|
265
|
+
and noetherian rings and infinite enumerated sets
|
|
266
|
+
and metric spaces)
|
|
267
|
+
and Category of infinite sets
|
|
268
|
+
|
|
269
|
+
sage: category(GF(7)['x'])
|
|
270
|
+
Join of Category of euclidean domains
|
|
271
|
+
and Category of algebras with basis over
|
|
272
|
+
(finite enumerated fields and subquotients of monoids
|
|
273
|
+
and quotients of semigroups)
|
|
274
|
+
and Category of commutative algebras over
|
|
275
|
+
(finite enumerated fields and subquotients of monoids
|
|
276
|
+
and quotients of semigroups)
|
|
277
|
+
and Category of infinite sets
|
|
278
|
+
|
|
279
|
+
TESTS:
|
|
280
|
+
|
|
281
|
+
Verify that :issue:`15232` has been resolved::
|
|
282
|
+
|
|
283
|
+
sage: K.<x> = FunctionField(QQ)
|
|
284
|
+
sage: R.<y> = K[]
|
|
285
|
+
sage: TestSuite(R).run()
|
|
286
|
+
|
|
287
|
+
Check that category for zero ring::
|
|
288
|
+
|
|
289
|
+
sage: PolynomialRing(Zmod(1), 'x').category()
|
|
290
|
+
Category of finite commutative rings
|
|
291
|
+
|
|
292
|
+
Check ``is_finite`` inherited from category (:issue:`24432`)::
|
|
293
|
+
|
|
294
|
+
sage: Zmod(1)['x'].is_finite()
|
|
295
|
+
True
|
|
296
|
+
|
|
297
|
+
sage: GF(7)['x'].is_finite()
|
|
298
|
+
False
|
|
299
|
+
|
|
300
|
+
sage: Zmod(1)['x']['y'].is_finite()
|
|
301
|
+
True
|
|
302
|
+
|
|
303
|
+
sage: GF(7)['x']['y'].is_finite()
|
|
304
|
+
False
|
|
305
|
+
"""
|
|
306
|
+
# We trust that, if category is given, it is useful and does not need to be joined
|
|
307
|
+
# with the default category
|
|
308
|
+
if base_ring.is_zero():
|
|
309
|
+
category = categories.rings.Rings().Commutative().Finite()
|
|
310
|
+
else:
|
|
311
|
+
defaultcat = polynomial_default_category(base_ring.category(), 1)
|
|
312
|
+
category = check_default_category(defaultcat, category)
|
|
313
|
+
self.__is_sparse = sparse
|
|
314
|
+
if element_class:
|
|
315
|
+
self._polynomial_class = element_class
|
|
316
|
+
else:
|
|
317
|
+
if sparse:
|
|
318
|
+
from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_sparse
|
|
319
|
+
self._polynomial_class = Polynomial_generic_sparse
|
|
320
|
+
else:
|
|
321
|
+
from sage.rings.polynomial.polynomial_element import Polynomial_generic_dense
|
|
322
|
+
self._polynomial_class = Polynomial_generic_dense
|
|
323
|
+
self.Element = self._polynomial_class
|
|
324
|
+
self.__cyclopoly_cache = {}
|
|
325
|
+
self._has_singular = False
|
|
326
|
+
Ring.__init__(self, base_ring, names=name, normalize=True, category=category)
|
|
327
|
+
from sage.rings.semirings.non_negative_integer_semiring import NonNegativeIntegerSemiring
|
|
328
|
+
self._indices = NonNegativeIntegerSemiring()
|
|
329
|
+
self._populate_coercion_lists_(convert_method_name='_polynomial_')
|
|
330
|
+
|
|
331
|
+
def __reduce__(self):
|
|
332
|
+
from sage.rings.polynomial.polynomial_ring_constructor import unpickle_PolynomialRing
|
|
333
|
+
args = (self.base_ring(), self.variable_names(), None, self.is_sparse())
|
|
334
|
+
return unpickle_PolynomialRing, args
|
|
335
|
+
|
|
336
|
+
def _element_constructor_(self, x=None, check=True, is_gen=False,
|
|
337
|
+
construct=False, **kwds):
|
|
338
|
+
r"""
|
|
339
|
+
Convert ``x`` into this univariate polynomial ring,
|
|
340
|
+
possibly non-canonically.
|
|
341
|
+
|
|
342
|
+
Conversion from power series::
|
|
343
|
+
|
|
344
|
+
sage: R.<x> = QQ[]
|
|
345
|
+
sage: R(1 + x + x^2 + O(x^3))
|
|
346
|
+
x^2 + x + 1
|
|
347
|
+
|
|
348
|
+
Stacked polynomial rings coerce into constants if possible. First,
|
|
349
|
+
the univariate case::
|
|
350
|
+
|
|
351
|
+
sage: R.<x> = QQ[]
|
|
352
|
+
sage: S.<u> = R[]
|
|
353
|
+
sage: S(u + 2)
|
|
354
|
+
u + 2
|
|
355
|
+
sage: S(x + 3)
|
|
356
|
+
x + 3
|
|
357
|
+
sage: S(x + 3).degree()
|
|
358
|
+
0
|
|
359
|
+
|
|
360
|
+
Second, the multivariate case::
|
|
361
|
+
|
|
362
|
+
sage: R.<x,y> = QQ[]
|
|
363
|
+
sage: S.<u> = R[]
|
|
364
|
+
sage: S(x + 2*y)
|
|
365
|
+
x + 2*y
|
|
366
|
+
sage: S(x + 2*y).degree()
|
|
367
|
+
0
|
|
368
|
+
sage: S(u + 2*x)
|
|
369
|
+
u + 2*x
|
|
370
|
+
sage: S(u + 2*x).degree()
|
|
371
|
+
1
|
|
372
|
+
|
|
373
|
+
Foreign polynomial rings coerce into the highest ring; the point
|
|
374
|
+
here is that an element of T could coerce to an element of R or an
|
|
375
|
+
element of S; it is anticipated that an element of T is more likely
|
|
376
|
+
to be "the right thing" and is historically consistent.
|
|
377
|
+
|
|
378
|
+
::
|
|
379
|
+
|
|
380
|
+
sage: R.<x> = QQ[]
|
|
381
|
+
sage: S.<u> = R[]
|
|
382
|
+
sage: T.<a> = QQ[]
|
|
383
|
+
sage: S(a)
|
|
384
|
+
u
|
|
385
|
+
|
|
386
|
+
Coercing in pari elements::
|
|
387
|
+
|
|
388
|
+
sage: QQ['x'](pari('[1,2,3/5]')) # needs sage.libs.pari
|
|
389
|
+
3/5*x^2 + 2*x + 1
|
|
390
|
+
sage: QQ['x'](pari('(-1/3)*x^10 + (2/3)*x - 1/5')) # needs sage.libs.pari
|
|
391
|
+
-1/3*x^10 + 2/3*x - 1/5
|
|
392
|
+
|
|
393
|
+
Coercing strings::
|
|
394
|
+
|
|
395
|
+
sage: QQ['y']('-y')
|
|
396
|
+
-y
|
|
397
|
+
|
|
398
|
+
TESTS:
|
|
399
|
+
|
|
400
|
+
Python 3 range is allowed::
|
|
401
|
+
|
|
402
|
+
sage: R = PolynomialRing(ZZ,'x')
|
|
403
|
+
sage: R(range(4))
|
|
404
|
+
3*x^3 + 2*x^2 + x
|
|
405
|
+
|
|
406
|
+
This shows that the issue at :issue:`4106` is fixed::
|
|
407
|
+
|
|
408
|
+
sage: # needs sage.symbolic
|
|
409
|
+
sage: x = var('x')
|
|
410
|
+
sage: R = IntegerModRing(4)
|
|
411
|
+
sage: S = R['x']
|
|
412
|
+
sage: S(x)
|
|
413
|
+
x
|
|
414
|
+
|
|
415
|
+
Throw a :exc:`TypeError` if any of the coefficients cannot be coerced
|
|
416
|
+
into the base ring (:issue:`6777`)::
|
|
417
|
+
|
|
418
|
+
sage: RealField(300)['x']( [ 1, ComplexField(300).gen(), 0 ]) # needs sage.rings.real_mpfr
|
|
419
|
+
Traceback (most recent call last):
|
|
420
|
+
...
|
|
421
|
+
TypeError: unable to convert '1.00...00*I' to a real number
|
|
422
|
+
|
|
423
|
+
Check that the bug in :issue:`11239` is fixed::
|
|
424
|
+
|
|
425
|
+
sage: # needs sage.rings.finite_rings
|
|
426
|
+
sage: K.<a> = GF(5^2, prefix='z')
|
|
427
|
+
sage: L.<b> = GF(5^4, prefix='z')
|
|
428
|
+
sage: f = K['x'].gen() + a
|
|
429
|
+
sage: L['x'](f)
|
|
430
|
+
x + b^3 + b^2 + b + 3
|
|
431
|
+
|
|
432
|
+
A test from :issue:`14485` ::
|
|
433
|
+
|
|
434
|
+
sage: x = SR.var('x') # needs sage.symbolic
|
|
435
|
+
sage: QQbar[x](x^6 + x^5 + x^4 - x^3 + x^2 - x + 2/5) # needs sage.rings.number_field sage.symbolic
|
|
436
|
+
x^6 + x^5 + x^4 - x^3 + x^2 - x + 2/5
|
|
437
|
+
|
|
438
|
+
Check support for unicode characters (:issue:`29280`)::
|
|
439
|
+
|
|
440
|
+
sage: QQ['λ']('λ^2')
|
|
441
|
+
λ^2
|
|
442
|
+
"""
|
|
443
|
+
C = self.element_class
|
|
444
|
+
if isinstance(x, (list, tuple)):
|
|
445
|
+
return C(self, x, check=check, is_gen=False, construct=construct)
|
|
446
|
+
if isinstance(x, range):
|
|
447
|
+
return C(self, list(x), check=check, is_gen=False,
|
|
448
|
+
construct=construct)
|
|
449
|
+
if isinstance(x, Element):
|
|
450
|
+
P = x.parent()
|
|
451
|
+
if P is self:
|
|
452
|
+
return x
|
|
453
|
+
elif P is self.base_ring():
|
|
454
|
+
# It *is* the base ring, hence, we should not need to check.
|
|
455
|
+
# Moreover, if x is equal to zero then we usually need to
|
|
456
|
+
# provide [] to the polynomial class, not [x], if we don't want
|
|
457
|
+
# to check (normally, polynomials like to strip trailing zeroes).
|
|
458
|
+
# However, in the padic case, we WANT that trailing
|
|
459
|
+
# zeroes are not stripped, because O(5)==0, but still it must
|
|
460
|
+
# not be forgotten. It should be the job of the __init__ method
|
|
461
|
+
# to decide whether to strip or not to strip.
|
|
462
|
+
return C(self, [x], check=False, is_gen=False,
|
|
463
|
+
construct=construct)
|
|
464
|
+
elif P == self.base_ring():
|
|
465
|
+
return C(self, [x], check=True, is_gen=False,
|
|
466
|
+
construct=construct)
|
|
467
|
+
if isinstance(x, sage.interfaces.abc.SingularElement) and self._has_singular:
|
|
468
|
+
self._singular_().set_ring()
|
|
469
|
+
try:
|
|
470
|
+
return x.sage_poly(self)
|
|
471
|
+
except Exception:
|
|
472
|
+
raise TypeError("Unable to coerce singular object")
|
|
473
|
+
elif isinstance(x, str):
|
|
474
|
+
try:
|
|
475
|
+
from sage.misc.parser import Parser, LookupNameMaker
|
|
476
|
+
R = self.base_ring()
|
|
477
|
+
p = Parser(Integer, R, LookupNameMaker({self.variable_name(): self.gen()}, R))
|
|
478
|
+
return self(p.parse(x))
|
|
479
|
+
except NameError:
|
|
480
|
+
raise TypeError("Unable to coerce string")
|
|
481
|
+
elif isinstance(x, FractionFieldElement):
|
|
482
|
+
if x.denominator().is_unit():
|
|
483
|
+
x = x.numerator() * x.denominator().inverse_of_unit()
|
|
484
|
+
else:
|
|
485
|
+
raise TypeError("denominator must be a unit")
|
|
486
|
+
elif isinstance(x, pari_gen):
|
|
487
|
+
if x.type() == 't_RFRAC':
|
|
488
|
+
raise TypeError("denominator must be a unit")
|
|
489
|
+
if x.type() != 't_POL':
|
|
490
|
+
x = x.Polrev()
|
|
491
|
+
elif isinstance(x, FiniteRingElement):
|
|
492
|
+
try:
|
|
493
|
+
return self(x.polynomial())
|
|
494
|
+
except AttributeError:
|
|
495
|
+
pass
|
|
496
|
+
elif isinstance(x, PowerSeries):
|
|
497
|
+
x = x.truncate()
|
|
498
|
+
return C(self, x, check, is_gen, construct=construct, **kwds)
|
|
499
|
+
|
|
500
|
+
@classmethod
|
|
501
|
+
def _implementation_names(cls, implementation, base_ring, sparse=False):
|
|
502
|
+
"""
|
|
503
|
+
Check whether this class can handle the implementation
|
|
504
|
+
``implementation`` over the given base ring and sparseness.
|
|
505
|
+
|
|
506
|
+
This is a simple wrapper around :meth:`_implementation_names_impl`
|
|
507
|
+
which does the real work.
|
|
508
|
+
|
|
509
|
+
.. NOTE::
|
|
510
|
+
|
|
511
|
+
It is assumed that the ``base_ring`` argument is a base ring
|
|
512
|
+
which the class can handle.
|
|
513
|
+
|
|
514
|
+
INPUT:
|
|
515
|
+
|
|
516
|
+
- ``implementation`` -- either a string denoting a specific
|
|
517
|
+
implementation or ``None`` for the default
|
|
518
|
+
|
|
519
|
+
- ``base_ring`` -- the base ring for the polynomial ring
|
|
520
|
+
|
|
521
|
+
- ``sparse`` -- boolean; whether the implementation is sparse
|
|
522
|
+
|
|
523
|
+
OUTPUT:
|
|
524
|
+
|
|
525
|
+
- if the implementation is supported, the output is a list of
|
|
526
|
+
all names (possibly including ``None``) which refer to the
|
|
527
|
+
given implementation. The first element of the list is the
|
|
528
|
+
canonical name. If the ``__init__`` method does not take an
|
|
529
|
+
``implementation`` keyword, then the first element must be
|
|
530
|
+
``None``.
|
|
531
|
+
|
|
532
|
+
- if the implementation is not supported, raise a
|
|
533
|
+
:exc:`ValueError`.
|
|
534
|
+
|
|
535
|
+
EXAMPLES::
|
|
536
|
+
|
|
537
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic
|
|
538
|
+
sage: PolynomialRing_generic._implementation_names(None, ZZ, True)
|
|
539
|
+
[None, 'generic']
|
|
540
|
+
sage: PolynomialRing_generic._implementation_names("generic", ZZ, True)
|
|
541
|
+
[None, 'generic']
|
|
542
|
+
sage: PolynomialRing_generic._implementation_names("xyzzy", ZZ, True)
|
|
543
|
+
Traceback (most recent call last):
|
|
544
|
+
...
|
|
545
|
+
ValueError: unknown implementation 'xyzzy' for sparse polynomial rings over Integer Ring
|
|
546
|
+
"""
|
|
547
|
+
names = cls._implementation_names_impl(implementation, base_ring, sparse)
|
|
548
|
+
if names is NotImplemented:
|
|
549
|
+
raise ValueError("unknown implementation %r for %s polynomial rings over %r" %
|
|
550
|
+
(implementation, "sparse" if sparse else "dense", base_ring))
|
|
551
|
+
assert isinstance(names, list)
|
|
552
|
+
assert implementation in names
|
|
553
|
+
return names
|
|
554
|
+
|
|
555
|
+
@staticmethod
|
|
556
|
+
def _implementation_names_impl(implementation, base_ring, sparse):
|
|
557
|
+
"""
|
|
558
|
+
The underlying implementation of :meth:`_implementation_names`.
|
|
559
|
+
|
|
560
|
+
The behaviour is exactly the same, except that an unknown
|
|
561
|
+
implementation returns ``NotImplemented`` instead of raising
|
|
562
|
+
:exc:`ValueError`.
|
|
563
|
+
|
|
564
|
+
EXAMPLES::
|
|
565
|
+
|
|
566
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic
|
|
567
|
+
sage: PolynomialRing_generic._implementation_names_impl("xyzzy", ZZ, True)
|
|
568
|
+
NotImplemented
|
|
569
|
+
"""
|
|
570
|
+
if implementation is None or implementation == "generic":
|
|
571
|
+
return [None, "generic"]
|
|
572
|
+
return NotImplemented
|
|
573
|
+
|
|
574
|
+
def is_integral_domain(self, proof=True):
|
|
575
|
+
"""
|
|
576
|
+
EXAMPLES::
|
|
577
|
+
|
|
578
|
+
sage: ZZ['x'].is_integral_domain()
|
|
579
|
+
True
|
|
580
|
+
sage: Integers(8)['x'].is_integral_domain()
|
|
581
|
+
False
|
|
582
|
+
"""
|
|
583
|
+
return self.base_ring().is_integral_domain(proof)
|
|
584
|
+
|
|
585
|
+
def is_unique_factorization_domain(self, proof=True):
|
|
586
|
+
"""
|
|
587
|
+
EXAMPLES::
|
|
588
|
+
|
|
589
|
+
sage: ZZ['x'].is_unique_factorization_domain()
|
|
590
|
+
True
|
|
591
|
+
sage: Integers(8)['x'].is_unique_factorization_domain()
|
|
592
|
+
False
|
|
593
|
+
"""
|
|
594
|
+
return self.base_ring().is_unique_factorization_domain(proof)
|
|
595
|
+
|
|
596
|
+
def is_noetherian(self):
|
|
597
|
+
return self.base_ring().is_noetherian()
|
|
598
|
+
|
|
599
|
+
def some_elements(self):
|
|
600
|
+
r"""
|
|
601
|
+
Return a list of polynomials.
|
|
602
|
+
|
|
603
|
+
This is typically used for running generic tests.
|
|
604
|
+
|
|
605
|
+
EXAMPLES::
|
|
606
|
+
|
|
607
|
+
sage: R.<x> = QQ[]
|
|
608
|
+
sage: R.some_elements()
|
|
609
|
+
[x, 0, 1, 1/2, x^2 + 2*x + 1, x^3, x^2 - 1, x^2 + 1, 2*x^2 + 2]
|
|
610
|
+
"""
|
|
611
|
+
# the comments in the following lines describe the motivation for
|
|
612
|
+
# adding these elements, they are not accurate over all rings and in
|
|
613
|
+
# all contexts
|
|
614
|
+
R = self.base_ring()
|
|
615
|
+
# Doing things this way is a little robust against rings where
|
|
616
|
+
# 2 might not convert in
|
|
617
|
+
one = R.one()
|
|
618
|
+
return [self.gen(),
|
|
619
|
+
self.zero(), self(one), self(R.an_element()), # elements of the base ring
|
|
620
|
+
self([one,2*one,one]), # a square
|
|
621
|
+
self([0,0,0,one]), # a power but not a square
|
|
622
|
+
self([-one,0,one]), # a reducible element
|
|
623
|
+
self([one,0,one]), # an irreducible element
|
|
624
|
+
self([2*one,0,2*one]), # an element with non-trivial content
|
|
625
|
+
]
|
|
626
|
+
|
|
627
|
+
def monomials_of_degree(self, degree):
|
|
628
|
+
r"""
|
|
629
|
+
Return the list of all monomials of the given total
|
|
630
|
+
degree in this univariate polynomial ring, which is simply the list with one element ``[self.gen()**degree]``.
|
|
631
|
+
|
|
632
|
+
.. SEEALSO::
|
|
633
|
+
|
|
634
|
+
:meth:`sage.rings.polynomial.multi_polynomial_ring_base.MPolynomialRing_base.monomials_of_degree`
|
|
635
|
+
|
|
636
|
+
EXAMPLES::
|
|
637
|
+
|
|
638
|
+
sage: R.<x> = ZZ[]
|
|
639
|
+
sage: mons = R.monomials_of_degree(2)
|
|
640
|
+
sage: mons
|
|
641
|
+
[x^2]
|
|
642
|
+
"""
|
|
643
|
+
return [self.gen()**degree]
|
|
644
|
+
|
|
645
|
+
@cached_method
|
|
646
|
+
def flattening_morphism(self):
|
|
647
|
+
r"""
|
|
648
|
+
Return the flattening morphism of this polynomial ring.
|
|
649
|
+
|
|
650
|
+
EXAMPLES::
|
|
651
|
+
|
|
652
|
+
sage: QQ['a','b']['x'].flattening_morphism()
|
|
653
|
+
Flattening morphism:
|
|
654
|
+
From: Univariate Polynomial Ring in x over
|
|
655
|
+
Multivariate Polynomial Ring in a, b over Rational Field
|
|
656
|
+
To: Multivariate Polynomial Ring in a, b, x over Rational Field
|
|
657
|
+
|
|
658
|
+
sage: QQ['x'].flattening_morphism()
|
|
659
|
+
Identity endomorphism of Univariate Polynomial Ring in x over Rational Field
|
|
660
|
+
"""
|
|
661
|
+
from .multi_polynomial_ring import MPolynomialRing_base
|
|
662
|
+
base = self.base_ring()
|
|
663
|
+
if isinstance(base, (PolynomialRing_generic, MPolynomialRing_base)):
|
|
664
|
+
from .flatten import FlatteningMorphism
|
|
665
|
+
return FlatteningMorphism(self)
|
|
666
|
+
else:
|
|
667
|
+
return IdentityMorphism(self)
|
|
668
|
+
|
|
669
|
+
def construction(self):
|
|
670
|
+
"""
|
|
671
|
+
Return the construction functor.
|
|
672
|
+
"""
|
|
673
|
+
return categories.pushout.PolynomialFunctor(self.variable_name(), sparse=self.__is_sparse), self.base_ring()
|
|
674
|
+
|
|
675
|
+
def completion(self, p=None, prec=20, extras=None):
|
|
676
|
+
r"""
|
|
677
|
+
Return the completion of ``self`` with respect to the irreducible
|
|
678
|
+
polynomial ``p``.
|
|
679
|
+
|
|
680
|
+
Currently only implemented for ``p=self.gen()`` (the default), i.e. you
|
|
681
|
+
can only complete `R[x]` with respect to `x`, the result being a ring
|
|
682
|
+
of power series in `x`. The ``prec`` variable controls the precision
|
|
683
|
+
used in the power series ring. If ``prec`` is `\infty`, then this
|
|
684
|
+
returns a :class:`LazyPowerSeriesRing`.
|
|
685
|
+
|
|
686
|
+
EXAMPLES::
|
|
687
|
+
|
|
688
|
+
sage: P.<x> = PolynomialRing(QQ)
|
|
689
|
+
sage: P
|
|
690
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
691
|
+
sage: PP = P.completion(x)
|
|
692
|
+
sage: PP
|
|
693
|
+
Power Series Ring in x over Rational Field
|
|
694
|
+
sage: f = 1 - x
|
|
695
|
+
sage: PP(f)
|
|
696
|
+
1 - x
|
|
697
|
+
sage: 1 / f
|
|
698
|
+
-1/(x - 1)
|
|
699
|
+
sage: g = 1 / PP(f); g
|
|
700
|
+
1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8 + x^9 + x^10 + x^11
|
|
701
|
+
+ x^12 + x^13 + x^14 + x^15 + x^16 + x^17 + x^18 + x^19 + O(x^20)
|
|
702
|
+
sage: 1 / g
|
|
703
|
+
1 - x + O(x^20)
|
|
704
|
+
|
|
705
|
+
sage: # needs sage.combinat
|
|
706
|
+
sage: PP = P.completion(x, prec=oo); PP
|
|
707
|
+
Lazy Taylor Series Ring in x over Rational Field
|
|
708
|
+
sage: g = 1 / PP(f); g
|
|
709
|
+
1 + x + x^2 + O(x^3)
|
|
710
|
+
sage: 1 / g == f
|
|
711
|
+
True
|
|
712
|
+
"""
|
|
713
|
+
if p is None or str(p) == self._names[0]:
|
|
714
|
+
if prec == float('inf'):
|
|
715
|
+
from sage.rings.lazy_series_ring import LazyPowerSeriesRing
|
|
716
|
+
return LazyPowerSeriesRing(self.base_ring(), names=(self._names[0],),
|
|
717
|
+
sparse=self.is_sparse())
|
|
718
|
+
from sage.rings.power_series_ring import PowerSeriesRing
|
|
719
|
+
return PowerSeriesRing(self.base_ring(), name=self._names[0],
|
|
720
|
+
default_prec=prec, sparse=self.is_sparse())
|
|
721
|
+
|
|
722
|
+
raise NotImplementedError("cannot complete %s with respect to %s" % (self, p))
|
|
723
|
+
|
|
724
|
+
def _coerce_map_from_base_ring(self):
|
|
725
|
+
"""
|
|
726
|
+
Return a coercion map from the base ring of ``self``.
|
|
727
|
+
|
|
728
|
+
EXAMPLES::
|
|
729
|
+
|
|
730
|
+
sage: R.<x> = QQ[]
|
|
731
|
+
sage: R.coerce_map_from(QQ)
|
|
732
|
+
Polynomial base injection morphism:
|
|
733
|
+
From: Rational Field
|
|
734
|
+
To: Univariate Polynomial Ring in x over Rational Field
|
|
735
|
+
sage: R.coerce_map_from(ZZ)
|
|
736
|
+
Composite map:
|
|
737
|
+
From: Integer Ring
|
|
738
|
+
To: Univariate Polynomial Ring in x over Rational Field
|
|
739
|
+
Defn: Natural morphism:
|
|
740
|
+
From: Integer Ring
|
|
741
|
+
To: Rational Field
|
|
742
|
+
then
|
|
743
|
+
Polynomial base injection morphism:
|
|
744
|
+
From: Rational Field
|
|
745
|
+
To: Univariate Polynomial Ring in x over Rational Field
|
|
746
|
+
sage: R.coerce_map_from(GF(7))
|
|
747
|
+
"""
|
|
748
|
+
from sage.rings.polynomial.polynomial_element import PolynomialBaseringInjection
|
|
749
|
+
|
|
750
|
+
return PolynomialBaseringInjection(self.base_ring(), self)
|
|
751
|
+
|
|
752
|
+
def _coerce_map_from_(self, P):
|
|
753
|
+
"""
|
|
754
|
+
The rings that canonically coerce to this polynomial ring are:
|
|
755
|
+
|
|
756
|
+
- this ring itself
|
|
757
|
+
|
|
758
|
+
- any ring that canonically coerces to the base ring of this ring.
|
|
759
|
+
|
|
760
|
+
- polynomial rings in the same variable over any base ring that
|
|
761
|
+
canonically coerces to the base ring of this ring.
|
|
762
|
+
|
|
763
|
+
- a multivariate polynomial ring P such that ``self``'s variable name
|
|
764
|
+
is among the variable names of P, and the ring obtained by
|
|
765
|
+
removing that variable is different from the base ring of ``self``,
|
|
766
|
+
but coerces into it. (see :issue:`813` for a discussion of this)
|
|
767
|
+
|
|
768
|
+
Caveat: There is no coercion from a dense into a sparse
|
|
769
|
+
polynomial ring. So, when adding a dense and a sparse
|
|
770
|
+
polynomial, the result will be dense. See :issue:`9944`.
|
|
771
|
+
|
|
772
|
+
EXAMPLES::
|
|
773
|
+
|
|
774
|
+
sage: R = QQ['x']
|
|
775
|
+
sage: R.has_coerce_map_from(ZZ['x'])
|
|
776
|
+
True
|
|
777
|
+
sage: R.has_coerce_map_from(ZZ['y'])
|
|
778
|
+
False
|
|
779
|
+
|
|
780
|
+
Here we test against the change in the coercions introduced
|
|
781
|
+
in :issue:`9944`::
|
|
782
|
+
|
|
783
|
+
sage: R.<x> = PolynomialRing(QQ, sparse=True)
|
|
784
|
+
sage: S.<x> = QQ[]
|
|
785
|
+
sage: (R.0 + S.0).parent()
|
|
786
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
787
|
+
sage: (S.0 + R.0).parent()
|
|
788
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
789
|
+
|
|
790
|
+
Here we test a feature that was implemented in :issue:`813`::
|
|
791
|
+
|
|
792
|
+
sage: P = QQ['x','y']
|
|
793
|
+
sage: Q = Frac(QQ['x'])['y']
|
|
794
|
+
sage: Q.has_coerce_map_from(P)
|
|
795
|
+
True
|
|
796
|
+
sage: P.0 + Q.0
|
|
797
|
+
y + x
|
|
798
|
+
|
|
799
|
+
In order to avoid bidirectional coercions (which are generally
|
|
800
|
+
problematic), we only have a coercion from P to Q if the base
|
|
801
|
+
ring of Q is more complicated than "P minus one variable"::
|
|
802
|
+
|
|
803
|
+
sage: Q = QQ['x']['y']
|
|
804
|
+
sage: P.has_coerce_map_from(Q)
|
|
805
|
+
True
|
|
806
|
+
sage: Q.has_coerce_map_from(P)
|
|
807
|
+
False
|
|
808
|
+
sage: Q.base_ring() is P.remove_var(Q.variable_name())
|
|
809
|
+
True
|
|
810
|
+
|
|
811
|
+
Over the integers, there is a coercion from the NTL and generic
|
|
812
|
+
implementation to the default FLINT implementation::
|
|
813
|
+
|
|
814
|
+
sage: del R, S # clear values from doctests above
|
|
815
|
+
sage: R = PolynomialRing(ZZ, 't', implementation='NTL') # needs sage.libs.ntl
|
|
816
|
+
sage: S = PolynomialRing(ZZ, 't', implementation='FLINT') # needs sage.libs.flint
|
|
817
|
+
sage: T = PolynomialRing(ZZ, 't', implementation='generic')
|
|
818
|
+
sage: R.has_coerce_map_from(S) # needs sage.libs.flint sage.libs.ntl
|
|
819
|
+
False
|
|
820
|
+
sage: R.has_coerce_map_from(T) # needs sage.libs.ntl
|
|
821
|
+
False
|
|
822
|
+
sage: S.has_coerce_map_from(T) # needs sage.libs.flint
|
|
823
|
+
True
|
|
824
|
+
sage: S.has_coerce_map_from(R) # needs sage.libs.flint sage.libs.ntl
|
|
825
|
+
True
|
|
826
|
+
sage: T.has_coerce_map_from(R) # needs sage.libs.ntl
|
|
827
|
+
False
|
|
828
|
+
sage: T.has_coerce_map_from(S) # needs sage.libs.flint
|
|
829
|
+
False
|
|
830
|
+
"""
|
|
831
|
+
base_ring = self.base_ring()
|
|
832
|
+
|
|
833
|
+
# workaround, useful for the zero ring
|
|
834
|
+
if P == base_ring:
|
|
835
|
+
return self._coerce_map_from_base_ring()
|
|
836
|
+
|
|
837
|
+
# handle constants that canonically coerce into self.base_ring()
|
|
838
|
+
# first, if possible
|
|
839
|
+
try:
|
|
840
|
+
connecting = base_ring.coerce_map_from(P)
|
|
841
|
+
if connecting is not None:
|
|
842
|
+
return self.coerce_map_from(base_ring) * connecting
|
|
843
|
+
except TypeError:
|
|
844
|
+
pass
|
|
845
|
+
|
|
846
|
+
# polynomial rings in the same variable over a base that canonically
|
|
847
|
+
# coerces into self.base_ring()
|
|
848
|
+
if isinstance(P, PolynomialRing_generic):
|
|
849
|
+
if self.construction()[0] != P.construction()[0]:
|
|
850
|
+
# Construction (including variable names) must be the
|
|
851
|
+
# same to allow coercion
|
|
852
|
+
return False
|
|
853
|
+
self_sparse = self.is_sparse()
|
|
854
|
+
P_sparse = P.is_sparse()
|
|
855
|
+
if self_sparse and not P_sparse:
|
|
856
|
+
# Coerce only sparse -> dense
|
|
857
|
+
return False
|
|
858
|
+
|
|
859
|
+
if P.base_ring() is base_ring:
|
|
860
|
+
# Same base ring but different implementations.
|
|
861
|
+
# Ideally, we should avoid cyclic coercions (a coercion
|
|
862
|
+
# from A to B and also from B to A), but this is
|
|
863
|
+
# currently hard to do:
|
|
864
|
+
# see https://github.com/sagemath/sage/issues/24319
|
|
865
|
+
if not self_sparse and P_sparse:
|
|
866
|
+
# Always allow coercion sparse -> dense
|
|
867
|
+
pass
|
|
868
|
+
elif base_ring is ZZ:
|
|
869
|
+
# Over ZZ, only allow coercion from any ZZ['x']
|
|
870
|
+
# implementation to the default FLINT implementation
|
|
871
|
+
try:
|
|
872
|
+
from .polynomial_integer_dense_flint import Polynomial_integer_dense_flint
|
|
873
|
+
except ImportError:
|
|
874
|
+
return None
|
|
875
|
+
if self.element_class is not Polynomial_integer_dense_flint:
|
|
876
|
+
return None
|
|
877
|
+
# Other rings: always allow coercion
|
|
878
|
+
# To be fixed in Issue #24319
|
|
879
|
+
f = base_ring.coerce_map_from(P.base_ring())
|
|
880
|
+
if f is None:
|
|
881
|
+
return None
|
|
882
|
+
from sage.rings.homset import RingHomset
|
|
883
|
+
from sage.rings.polynomial.polynomial_ring_homomorphism import PolynomialRingHomomorphism_from_base
|
|
884
|
+
return PolynomialRingHomomorphism_from_base(RingHomset(P, self), f)
|
|
885
|
+
|
|
886
|
+
# Last, we consider multivariate polynomial rings:
|
|
887
|
+
from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base
|
|
888
|
+
if isinstance(P, MPolynomialRing_base) and self.variable_name() in P.variable_names():
|
|
889
|
+
P_ = P.remove_var(self.variable_name())
|
|
890
|
+
return self.base_ring() != P_ and self.base_ring().has_coerce_map_from(P_)
|
|
891
|
+
|
|
892
|
+
def _lean_init_(self):
|
|
893
|
+
"""
|
|
894
|
+
|
|
895
|
+
EXAMPLES::
|
|
896
|
+
|
|
897
|
+
sage: ZZ['x']._lean_init_()
|
|
898
|
+
'polynomial int'
|
|
899
|
+
|
|
900
|
+
"""
|
|
901
|
+
# data.polynomial.basic
|
|
902
|
+
return 'polynomial ' + self.base_ring()._lean_init_()
|
|
903
|
+
|
|
904
|
+
def _magma_init_(self, magma):
|
|
905
|
+
"""
|
|
906
|
+
Used in converting this ring to the corresponding ring in MAGMA.
|
|
907
|
+
|
|
908
|
+
EXAMPLES::
|
|
909
|
+
|
|
910
|
+
sage: # optional - magma
|
|
911
|
+
sage: R = QQ['y']
|
|
912
|
+
sage: R._magma_init_(magma)
|
|
913
|
+
'SageCreateWithNames(PolynomialRing(_sage_ref...),["y"])'
|
|
914
|
+
sage: S = magma(R)
|
|
915
|
+
sage: S
|
|
916
|
+
Univariate Polynomial Ring in y over Rational Field
|
|
917
|
+
sage: S.1
|
|
918
|
+
y
|
|
919
|
+
sage: magma(PolynomialRing(GF(7), 'x')) # needs sage.rings.finite_rings
|
|
920
|
+
Univariate Polynomial Ring in x over GF(7)
|
|
921
|
+
sage: magma(PolynomialRing(GF(49,'a'), 'x')) # needs sage.rings.finite_rings
|
|
922
|
+
Univariate Polynomial Ring in x over GF(7^2)
|
|
923
|
+
sage: magma(PolynomialRing(PolynomialRing(ZZ,'w'), 'x'))
|
|
924
|
+
Univariate Polynomial Ring in x over Univariate Polynomial Ring in w over Integer Ring
|
|
925
|
+
|
|
926
|
+
Watch out, Magma has different semantics from Sage, i.e., in Magma
|
|
927
|
+
there is a unique univariate polynomial ring, and the variable name
|
|
928
|
+
has no intrinsic meaning (it only impacts printing), so can't be
|
|
929
|
+
reliably set because of caching.
|
|
930
|
+
|
|
931
|
+
::
|
|
932
|
+
|
|
933
|
+
sage: # optional - magma
|
|
934
|
+
sage: m = Magma()
|
|
935
|
+
sage: m(QQ['w'])
|
|
936
|
+
Univariate Polynomial Ring in w over Rational Field
|
|
937
|
+
sage: m(QQ['x'])
|
|
938
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
939
|
+
sage: m(QQ['w'])
|
|
940
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
941
|
+
|
|
942
|
+
A nested example over a Givaro finite field::
|
|
943
|
+
|
|
944
|
+
sage: k.<a> = GF(9) # needs sage.rings.finite_rings
|
|
945
|
+
sage: R.<x> = k[] # needs sage.rings.finite_rings
|
|
946
|
+
sage: magma(a^2*x^3 + (a+1)*x + a) # optional - magma # needs sage.rings.finite_rings
|
|
947
|
+
a^2*x^3 + a^2*x + a
|
|
948
|
+
"""
|
|
949
|
+
B = magma(self.base_ring())
|
|
950
|
+
Bref = B._ref()
|
|
951
|
+
s = 'PolynomialRing(%s)' % (Bref)
|
|
952
|
+
return magma._with_names(s, self.variable_names())
|
|
953
|
+
|
|
954
|
+
def _gap_init_(self, gap=None):
|
|
955
|
+
"""
|
|
956
|
+
String for representing this polynomial ring in GAP.
|
|
957
|
+
|
|
958
|
+
INPUT:
|
|
959
|
+
|
|
960
|
+
- ``gap`` -- (optional GAP instance) used for representing the base ring
|
|
961
|
+
|
|
962
|
+
EXAMPLES::
|
|
963
|
+
|
|
964
|
+
sage: R.<z> = ZZ[]
|
|
965
|
+
sage: gap(R) # needs sage.libs.gap
|
|
966
|
+
PolynomialRing( Integers, ["z"] )
|
|
967
|
+
sage: gap(R) is gap(R) # needs sage.libs.gap
|
|
968
|
+
True
|
|
969
|
+
sage: gap(z^2 + z) # needs sage.libs.gap
|
|
970
|
+
z^2+z
|
|
971
|
+
|
|
972
|
+
A univariate polynomial ring over a multivariate polynomial
|
|
973
|
+
ring over a number field::
|
|
974
|
+
|
|
975
|
+
sage: # needs sage.rings.number_field
|
|
976
|
+
sage: Q.<t> = QQ[]
|
|
977
|
+
sage: K.<tau> = NumberField(t^2 + t + 1)
|
|
978
|
+
sage: P.<x,y> = K[]
|
|
979
|
+
sage: S.<z> = P[]
|
|
980
|
+
sage: gap(S) # needs sage.libs.gap
|
|
981
|
+
PolynomialRing( PolynomialRing( <algebraic extension over the Rationals of degree 2>, ["x", "y"] ), ["z"] )
|
|
982
|
+
sage: gap(S) is gap(S) # needs sage.libs.gap
|
|
983
|
+
True
|
|
984
|
+
"""
|
|
985
|
+
if gap is not None:
|
|
986
|
+
base_ring = gap(self.base_ring()).name()
|
|
987
|
+
else:
|
|
988
|
+
base_ring = self.base_ring()._gap_init_()
|
|
989
|
+
return 'PolynomialRing(%s, ["%s"])' % (base_ring, self.variable_name())
|
|
990
|
+
|
|
991
|
+
def _sage_input_(self, sib, coerced):
|
|
992
|
+
r"""
|
|
993
|
+
Produce an expression which will reproduce this value when
|
|
994
|
+
evaluated.
|
|
995
|
+
|
|
996
|
+
EXAMPLES::
|
|
997
|
+
|
|
998
|
+
sage: sage_input(GF(5)['x']['y'], verify=True)
|
|
999
|
+
# Verified
|
|
1000
|
+
GF(5)['x']['y']
|
|
1001
|
+
sage: from sage.misc.sage_input import SageInputBuilder
|
|
1002
|
+
sage: ZZ['z']._sage_input_(SageInputBuilder(), False)
|
|
1003
|
+
{constr_parent: {subscr: {atomic:ZZ}[{atomic:'z'}]} with gens: ('z',)}
|
|
1004
|
+
"""
|
|
1005
|
+
base = sib(self.base_ring())
|
|
1006
|
+
sie = base[self.variable_name()]
|
|
1007
|
+
gens_syntax = sib.empty_subscript(base)
|
|
1008
|
+
return sib.parent_with_gens(self, sie, self.variable_names(), 'R',
|
|
1009
|
+
gens_syntax=gens_syntax)
|
|
1010
|
+
|
|
1011
|
+
def _macaulay2_init_(self, macaulay2=None):
|
|
1012
|
+
"""
|
|
1013
|
+
EXAMPLES::
|
|
1014
|
+
|
|
1015
|
+
sage: R = QQ['x']
|
|
1016
|
+
sage: macaulay2(R).describe() # optional - macaulay2
|
|
1017
|
+
QQ[x, Degrees => {1}, Heft => {1}, MonomialOrder => {MonomialSize => 16}]
|
|
1018
|
+
{GRevLex => {1} }
|
|
1019
|
+
{Position => Up }
|
|
1020
|
+
|
|
1021
|
+
TESTS:
|
|
1022
|
+
|
|
1023
|
+
Check that results are cached (:issue:`28074`)::
|
|
1024
|
+
|
|
1025
|
+
sage: R = ZZ['t']
|
|
1026
|
+
sage: macaulay2(R) is macaulay2(R) # optional - macaulay2
|
|
1027
|
+
True
|
|
1028
|
+
"""
|
|
1029
|
+
if macaulay2 is None:
|
|
1030
|
+
from sage.interfaces.macaulay2 import macaulay2 as m2_default
|
|
1031
|
+
macaulay2 = m2_default
|
|
1032
|
+
return macaulay2._macaulay2_input_ring(self.base_ring(), self.gens())
|
|
1033
|
+
|
|
1034
|
+
def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None):
|
|
1035
|
+
"""
|
|
1036
|
+
EXAMPLES::
|
|
1037
|
+
|
|
1038
|
+
sage: R.<x> = QQ[]
|
|
1039
|
+
sage: R._is_valid_homomorphism_(GF(7), [5])
|
|
1040
|
+
False
|
|
1041
|
+
sage: R._is_valid_homomorphism_(Qp(7), [5]) # needs sage.rings.padics
|
|
1042
|
+
True
|
|
1043
|
+
"""
|
|
1044
|
+
# Since poly rings are free, any image of the gen
|
|
1045
|
+
# determines a homomorphism
|
|
1046
|
+
if base_map is None:
|
|
1047
|
+
# If no base map is given, the only requirement is that the
|
|
1048
|
+
# base ring coerces into the codomain
|
|
1049
|
+
return codomain.has_coerce_map_from(self.base_ring())
|
|
1050
|
+
return True
|
|
1051
|
+
|
|
1052
|
+
# Polynomial rings should be unique parents. Hence,
|
|
1053
|
+
# no need for any comparison method
|
|
1054
|
+
|
|
1055
|
+
def __hash__(self):
|
|
1056
|
+
# should be faster than just relying on the string representation
|
|
1057
|
+
try:
|
|
1058
|
+
return self._cached_hash
|
|
1059
|
+
except AttributeError:
|
|
1060
|
+
pass
|
|
1061
|
+
h = self._cached_hash = hash((self.base_ring(),self.variable_name()))
|
|
1062
|
+
return h
|
|
1063
|
+
|
|
1064
|
+
def _repr_(self):
|
|
1065
|
+
try:
|
|
1066
|
+
return self._cached_repr
|
|
1067
|
+
except AttributeError:
|
|
1068
|
+
pass
|
|
1069
|
+
s = "Univariate Polynomial Ring in %s over %s" % (
|
|
1070
|
+
self.variable_name(), self.base_ring())
|
|
1071
|
+
if self.is_sparse():
|
|
1072
|
+
s = "Sparse " + s
|
|
1073
|
+
self._cached_repr = s
|
|
1074
|
+
return s
|
|
1075
|
+
|
|
1076
|
+
def _latex_(self):
|
|
1077
|
+
r"""
|
|
1078
|
+
EXAMPLES::
|
|
1079
|
+
|
|
1080
|
+
sage: S.<alpha12> = ZZ[]
|
|
1081
|
+
sage: latex(S)
|
|
1082
|
+
\Bold{Z}[\alpha_{12}]
|
|
1083
|
+
"""
|
|
1084
|
+
return "%s[%s]" % (latex.latex(self.base_ring()), self.latex_variable_names()[0])
|
|
1085
|
+
|
|
1086
|
+
def base_extend(self, R):
|
|
1087
|
+
"""
|
|
1088
|
+
Return the base extension of this polynomial ring to `R`.
|
|
1089
|
+
|
|
1090
|
+
EXAMPLES::
|
|
1091
|
+
|
|
1092
|
+
sage: # needs sage.rings.real_mpfr
|
|
1093
|
+
sage: R.<x> = RR[]; R
|
|
1094
|
+
Univariate Polynomial Ring in x over Real Field with 53 bits of precision
|
|
1095
|
+
sage: R.base_extend(CC)
|
|
1096
|
+
Univariate Polynomial Ring in x over Complex Field with 53 bits of precision
|
|
1097
|
+
sage: R.base_extend(QQ)
|
|
1098
|
+
Traceback (most recent call last):
|
|
1099
|
+
...
|
|
1100
|
+
TypeError: no such base extension
|
|
1101
|
+
sage: R.change_ring(QQ)
|
|
1102
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
1103
|
+
"""
|
|
1104
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
1105
|
+
|
|
1106
|
+
if R.has_coerce_map_from(self.base_ring()):
|
|
1107
|
+
return PolynomialRing(R, names=self.variable_name(), sparse=self.is_sparse())
|
|
1108
|
+
else:
|
|
1109
|
+
raise TypeError("no such base extension")
|
|
1110
|
+
|
|
1111
|
+
def change_ring(self, R):
|
|
1112
|
+
"""
|
|
1113
|
+
Return the polynomial ring in the same variable as ``self`` over `R`.
|
|
1114
|
+
|
|
1115
|
+
EXAMPLES::
|
|
1116
|
+
|
|
1117
|
+
sage: # needs sage.rings.finite_rings sage.rings.real_interval_field
|
|
1118
|
+
sage: R.<ZZZ> = RealIntervalField()[]; R
|
|
1119
|
+
Univariate Polynomial Ring in ZZZ over
|
|
1120
|
+
Real Interval Field with 53 bits of precision
|
|
1121
|
+
sage: R.change_ring(GF(19^2, 'b'))
|
|
1122
|
+
Univariate Polynomial Ring in ZZZ over Finite Field in b of size 19^2
|
|
1123
|
+
"""
|
|
1124
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
1125
|
+
|
|
1126
|
+
return PolynomialRing(R, names=self.variable_name(), sparse=self.is_sparse())
|
|
1127
|
+
|
|
1128
|
+
def change_var(self, var):
|
|
1129
|
+
r"""
|
|
1130
|
+
Return the polynomial ring in variable ``var`` over the same base
|
|
1131
|
+
ring.
|
|
1132
|
+
|
|
1133
|
+
EXAMPLES::
|
|
1134
|
+
|
|
1135
|
+
sage: R.<x> = ZZ[]; R
|
|
1136
|
+
Univariate Polynomial Ring in x over Integer Ring
|
|
1137
|
+
sage: R.change_var('y')
|
|
1138
|
+
Univariate Polynomial Ring in y over Integer Ring
|
|
1139
|
+
"""
|
|
1140
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
1141
|
+
|
|
1142
|
+
return PolynomialRing(self.base_ring(), names=var, sparse=self.is_sparse())
|
|
1143
|
+
|
|
1144
|
+
def extend_variables(self, added_names, order='degrevlex'):
|
|
1145
|
+
r"""
|
|
1146
|
+
Return a multivariate polynomial ring with the same base ring but
|
|
1147
|
+
with ``added_names`` as additional variables.
|
|
1148
|
+
|
|
1149
|
+
EXAMPLES::
|
|
1150
|
+
|
|
1151
|
+
sage: R.<x> = ZZ[]; R
|
|
1152
|
+
Univariate Polynomial Ring in x over Integer Ring
|
|
1153
|
+
sage: R.extend_variables('y, z')
|
|
1154
|
+
Multivariate Polynomial Ring in x, y, z over Integer Ring
|
|
1155
|
+
sage: R.extend_variables(('y', 'z'))
|
|
1156
|
+
Multivariate Polynomial Ring in x, y, z over Integer Ring
|
|
1157
|
+
"""
|
|
1158
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
1159
|
+
|
|
1160
|
+
if isinstance(added_names, str):
|
|
1161
|
+
added_names = added_names.split(',')
|
|
1162
|
+
return PolynomialRing(self.base_ring(), names=self.variable_names() + tuple(added_names), order=order)
|
|
1163
|
+
|
|
1164
|
+
def variable_names_recursive(self, depth=sage.rings.infinity.infinity):
|
|
1165
|
+
r"""
|
|
1166
|
+
Return the list of variable names of this ring and its base rings,
|
|
1167
|
+
as if it were a single multi-variate polynomial.
|
|
1168
|
+
|
|
1169
|
+
INPUT:
|
|
1170
|
+
|
|
1171
|
+
- ``depth`` -- integer or :mod:`Infinity <sage.rings.infinity>`
|
|
1172
|
+
|
|
1173
|
+
OUTPUT: a tuple of strings
|
|
1174
|
+
|
|
1175
|
+
EXAMPLES::
|
|
1176
|
+
|
|
1177
|
+
sage: R = QQ['x']['y']['z']
|
|
1178
|
+
sage: R.variable_names_recursive()
|
|
1179
|
+
('x', 'y', 'z')
|
|
1180
|
+
sage: R.variable_names_recursive(2)
|
|
1181
|
+
('y', 'z')
|
|
1182
|
+
"""
|
|
1183
|
+
if depth <= 0:
|
|
1184
|
+
return ()
|
|
1185
|
+
elif depth == 1:
|
|
1186
|
+
return self.variable_names()
|
|
1187
|
+
else:
|
|
1188
|
+
my_vars = self.variable_names()
|
|
1189
|
+
try:
|
|
1190
|
+
return self.base_ring().variable_names_recursive(depth - len(my_vars)) + my_vars
|
|
1191
|
+
except AttributeError:
|
|
1192
|
+
return my_vars
|
|
1193
|
+
|
|
1194
|
+
def _mpoly_base_ring(self, variables=None):
|
|
1195
|
+
r"""
|
|
1196
|
+
Return the base ring if this is viewed as a polynomial ring over
|
|
1197
|
+
``variables``. See also ``Polynomial._mpoly_dict_recursive``.
|
|
1198
|
+
"""
|
|
1199
|
+
if variables is None:
|
|
1200
|
+
variables = self.variable_names_recursive()
|
|
1201
|
+
variables = list(variables)
|
|
1202
|
+
var = self.variable_name()
|
|
1203
|
+
if var not in variables:
|
|
1204
|
+
return self
|
|
1205
|
+
else:
|
|
1206
|
+
try:
|
|
1207
|
+
return self.base_ring()._mpoly_base_ring(variables[:variables.index(var)])
|
|
1208
|
+
except AttributeError:
|
|
1209
|
+
return self.base_ring()
|
|
1210
|
+
|
|
1211
|
+
def characteristic(self):
|
|
1212
|
+
"""
|
|
1213
|
+
Return the characteristic of this polynomial ring, which is the
|
|
1214
|
+
same as that of its base ring.
|
|
1215
|
+
|
|
1216
|
+
EXAMPLES::
|
|
1217
|
+
|
|
1218
|
+
sage: # needs sage.rings.real_interval_field
|
|
1219
|
+
sage: R.<ZZZ> = RealIntervalField()[]; R
|
|
1220
|
+
Univariate Polynomial Ring in ZZZ over Real Interval Field with 53 bits of precision
|
|
1221
|
+
sage: R.characteristic()
|
|
1222
|
+
0
|
|
1223
|
+
sage: S = R.change_ring(GF(19^2, 'b')); S # needs sage.rings.finite_rings
|
|
1224
|
+
Univariate Polynomial Ring in ZZZ over Finite Field in b of size 19^2
|
|
1225
|
+
sage: S.characteristic() # needs sage.rings.finite_rings
|
|
1226
|
+
19
|
|
1227
|
+
"""
|
|
1228
|
+
return self.base_ring().characteristic()
|
|
1229
|
+
|
|
1230
|
+
def cyclotomic_polynomial(self, n):
|
|
1231
|
+
"""
|
|
1232
|
+
Return the `n`-th cyclotomic polynomial as a polynomial in this
|
|
1233
|
+
polynomial ring. For details of the implementation, see the
|
|
1234
|
+
documentation for
|
|
1235
|
+
:func:`sage.rings.polynomial.cyclotomic.cyclotomic_coeffs`.
|
|
1236
|
+
|
|
1237
|
+
EXAMPLES::
|
|
1238
|
+
|
|
1239
|
+
sage: R = ZZ['x']
|
|
1240
|
+
sage: R.cyclotomic_polynomial(8)
|
|
1241
|
+
x^4 + 1
|
|
1242
|
+
sage: R.cyclotomic_polynomial(12)
|
|
1243
|
+
x^4 - x^2 + 1
|
|
1244
|
+
|
|
1245
|
+
sage: S = PolynomialRing(FiniteField(7), 'x')
|
|
1246
|
+
sage: S.cyclotomic_polynomial(12)
|
|
1247
|
+
x^4 + 6*x^2 + 1
|
|
1248
|
+
sage: S.cyclotomic_polynomial(1)
|
|
1249
|
+
x + 6
|
|
1250
|
+
|
|
1251
|
+
TESTS:
|
|
1252
|
+
|
|
1253
|
+
Make sure it agrees with other systems for the trivial case::
|
|
1254
|
+
|
|
1255
|
+
sage: ZZ['x'].cyclotomic_polynomial(1)
|
|
1256
|
+
x - 1
|
|
1257
|
+
sage: gp('polcyclo(1)') # needs sage.libs.pari
|
|
1258
|
+
x - 1
|
|
1259
|
+
"""
|
|
1260
|
+
if n <= 0:
|
|
1261
|
+
raise ArithmeticError("n=%s must be positive" % n)
|
|
1262
|
+
elif n == 1:
|
|
1263
|
+
return self.gen() - 1
|
|
1264
|
+
else:
|
|
1265
|
+
from .cyclotomic import cyclotomic_coeffs
|
|
1266
|
+
return self(cyclotomic_coeffs(n), check=True)
|
|
1267
|
+
|
|
1268
|
+
@cached_method
|
|
1269
|
+
def gen(self, n=0):
|
|
1270
|
+
"""
|
|
1271
|
+
Return the indeterminate generator of this polynomial ring.
|
|
1272
|
+
|
|
1273
|
+
EXAMPLES::
|
|
1274
|
+
|
|
1275
|
+
sage: R.<abc> = Integers(8)[]; R
|
|
1276
|
+
Univariate Polynomial Ring in abc over Ring of integers modulo 8
|
|
1277
|
+
sage: t = R.gen(); t
|
|
1278
|
+
abc
|
|
1279
|
+
sage: t.is_gen()
|
|
1280
|
+
True
|
|
1281
|
+
|
|
1282
|
+
An identical generator is always returned.
|
|
1283
|
+
|
|
1284
|
+
::
|
|
1285
|
+
|
|
1286
|
+
sage: t is R.gen()
|
|
1287
|
+
True
|
|
1288
|
+
"""
|
|
1289
|
+
if n != 0:
|
|
1290
|
+
raise IndexError("generator n not defined")
|
|
1291
|
+
return self.element_class(self, [0,1], is_gen=True)
|
|
1292
|
+
|
|
1293
|
+
def gens_dict(self) -> dict:
|
|
1294
|
+
"""
|
|
1295
|
+
Return a dictionary whose entries are ``{name:variable,...}``,
|
|
1296
|
+
where ``name`` stands for the variable names of this
|
|
1297
|
+
object (as strings) and ``variable`` stands for the corresponding
|
|
1298
|
+
generators (as elements of this object).
|
|
1299
|
+
|
|
1300
|
+
EXAMPLES::
|
|
1301
|
+
|
|
1302
|
+
sage: R.<y,x,a42> = RR[]
|
|
1303
|
+
sage: R.gens_dict()
|
|
1304
|
+
{'a42': a42, 'x': x, 'y': y}
|
|
1305
|
+
"""
|
|
1306
|
+
gens = self.gens()
|
|
1307
|
+
names = self.variable_names()
|
|
1308
|
+
assert len(gens) == len(names)
|
|
1309
|
+
return dict(zip(names, gens))
|
|
1310
|
+
|
|
1311
|
+
def parameter(self):
|
|
1312
|
+
"""
|
|
1313
|
+
Return the generator of this polynomial ring.
|
|
1314
|
+
|
|
1315
|
+
This is the same as ``self.gen()``.
|
|
1316
|
+
"""
|
|
1317
|
+
return self.gen()
|
|
1318
|
+
|
|
1319
|
+
@cached_method
|
|
1320
|
+
def is_exact(self):
|
|
1321
|
+
return self.base_ring().is_exact()
|
|
1322
|
+
|
|
1323
|
+
def is_field(self, proof=True):
|
|
1324
|
+
"""
|
|
1325
|
+
Return ``False``, since polynomial rings are never fields.
|
|
1326
|
+
|
|
1327
|
+
EXAMPLES::
|
|
1328
|
+
|
|
1329
|
+
sage: # needs sage.libs.ntl
|
|
1330
|
+
sage: R.<z> = Integers(2)[]; R
|
|
1331
|
+
Univariate Polynomial Ring in z over Ring of integers modulo 2 (using GF2X)
|
|
1332
|
+
sage: R.is_field()
|
|
1333
|
+
False
|
|
1334
|
+
"""
|
|
1335
|
+
return False
|
|
1336
|
+
|
|
1337
|
+
def is_sparse(self):
|
|
1338
|
+
"""
|
|
1339
|
+
Return ``True`` if elements of this polynomial ring have a sparse
|
|
1340
|
+
representation.
|
|
1341
|
+
|
|
1342
|
+
EXAMPLES::
|
|
1343
|
+
|
|
1344
|
+
sage: R.<z> = Integers(8)[]; R
|
|
1345
|
+
Univariate Polynomial Ring in z over Ring of integers modulo 8
|
|
1346
|
+
sage: R.is_sparse()
|
|
1347
|
+
False
|
|
1348
|
+
sage: R.<W> = PolynomialRing(QQ, sparse=True); R
|
|
1349
|
+
Sparse Univariate Polynomial Ring in W over Rational Field
|
|
1350
|
+
sage: R.is_sparse()
|
|
1351
|
+
True
|
|
1352
|
+
"""
|
|
1353
|
+
return self.__is_sparse
|
|
1354
|
+
|
|
1355
|
+
def monomial(self, exponent):
|
|
1356
|
+
"""
|
|
1357
|
+
Return the monomial with the ``exponent``.
|
|
1358
|
+
|
|
1359
|
+
INPUT:
|
|
1360
|
+
|
|
1361
|
+
- ``exponent`` -- nonnegative integer
|
|
1362
|
+
|
|
1363
|
+
EXAMPLES::
|
|
1364
|
+
|
|
1365
|
+
sage: R.<x> = PolynomialRing(ZZ)
|
|
1366
|
+
sage: R.monomial(5)
|
|
1367
|
+
x^5
|
|
1368
|
+
sage: e=(10,)
|
|
1369
|
+
sage: R.monomial(*e)
|
|
1370
|
+
x^10
|
|
1371
|
+
sage: m = R.monomial(100)
|
|
1372
|
+
sage: R.monomial(m.degree()) == m
|
|
1373
|
+
True
|
|
1374
|
+
"""
|
|
1375
|
+
return self({exponent: self.base_ring().one()})
|
|
1376
|
+
|
|
1377
|
+
def krull_dimension(self):
|
|
1378
|
+
"""
|
|
1379
|
+
Return the Krull dimension of this polynomial ring, which is one
|
|
1380
|
+
more than the Krull dimension of the base ring.
|
|
1381
|
+
|
|
1382
|
+
EXAMPLES::
|
|
1383
|
+
|
|
1384
|
+
sage: R.<x> = QQ[]
|
|
1385
|
+
sage: R.krull_dimension()
|
|
1386
|
+
1
|
|
1387
|
+
|
|
1388
|
+
sage: # needs sage.rings.finite_rings
|
|
1389
|
+
sage: R.<z> = GF(9, 'a')[]; R
|
|
1390
|
+
Univariate Polynomial Ring in z over Finite Field in a of size 3^2
|
|
1391
|
+
sage: R.krull_dimension()
|
|
1392
|
+
1
|
|
1393
|
+
sage: S.<t> = R[]
|
|
1394
|
+
sage: S.krull_dimension()
|
|
1395
|
+
2
|
|
1396
|
+
sage: for n in range(10):
|
|
1397
|
+
....: S = PolynomialRing(S, 'w')
|
|
1398
|
+
sage: S.krull_dimension()
|
|
1399
|
+
12
|
|
1400
|
+
"""
|
|
1401
|
+
return self.base_ring().krull_dimension() + 1
|
|
1402
|
+
|
|
1403
|
+
def ngens(self):
|
|
1404
|
+
"""
|
|
1405
|
+
Return the number of generators of this polynomial ring, which is 1
|
|
1406
|
+
since it is a univariate polynomial ring.
|
|
1407
|
+
|
|
1408
|
+
EXAMPLES::
|
|
1409
|
+
|
|
1410
|
+
sage: R.<z> = Integers(8)[]; R
|
|
1411
|
+
Univariate Polynomial Ring in z over Ring of integers modulo 8
|
|
1412
|
+
sage: R.ngens()
|
|
1413
|
+
1
|
|
1414
|
+
"""
|
|
1415
|
+
return 1
|
|
1416
|
+
|
|
1417
|
+
def random_element(self, degree=(-1, 2), monic=False, *args, **kwds):
|
|
1418
|
+
r"""
|
|
1419
|
+
Return a random polynomial of given degree (bounds).
|
|
1420
|
+
|
|
1421
|
+
INPUT:
|
|
1422
|
+
|
|
1423
|
+
- ``degree`` -- (default: ``(-1, 2)``) integer for fixing the degree or
|
|
1424
|
+
a tuple of minimum and maximum degrees
|
|
1425
|
+
|
|
1426
|
+
- ``monic`` -- boolean (default: ``False``); indicate whether the sampled
|
|
1427
|
+
polynomial should be monic
|
|
1428
|
+
|
|
1429
|
+
- ``*args, **kwds`` -- additional keyword parameters passed on to the
|
|
1430
|
+
``random_element`` method for the base ring
|
|
1431
|
+
|
|
1432
|
+
EXAMPLES::
|
|
1433
|
+
|
|
1434
|
+
sage: R.<x> = ZZ[]
|
|
1435
|
+
sage: f = R.random_element(10, x=5, y=10)
|
|
1436
|
+
sage: f.degree()
|
|
1437
|
+
10
|
|
1438
|
+
sage: f.parent() is R
|
|
1439
|
+
True
|
|
1440
|
+
sage: all(a in range(5, 10) for a in f.coefficients())
|
|
1441
|
+
True
|
|
1442
|
+
sage: R.random_element(6).degree()
|
|
1443
|
+
6
|
|
1444
|
+
|
|
1445
|
+
If a tuple of two integers is given for the ``degree`` argument, a
|
|
1446
|
+
polynomial is chosen among all polynomials with degree between them. If
|
|
1447
|
+
the base ring can be sampled uniformly, then this method also samples
|
|
1448
|
+
uniformly::
|
|
1449
|
+
|
|
1450
|
+
sage: R.random_element(degree=(0, 4)).degree() in range(0, 5)
|
|
1451
|
+
True
|
|
1452
|
+
sage: found = [False]*5
|
|
1453
|
+
sage: while not all(found):
|
|
1454
|
+
....: found[R.random_element(degree=(0, 4)).degree()] = True
|
|
1455
|
+
|
|
1456
|
+
Note that the zero polynomial has degree `-1`, so if you want to
|
|
1457
|
+
consider it set the minimum degree to `-1`::
|
|
1458
|
+
|
|
1459
|
+
sage: while R.random_element(degree=(-1,2), x=-1, y=1) != R.zero():
|
|
1460
|
+
....: pass
|
|
1461
|
+
|
|
1462
|
+
Monic polynomials are chosen among all monic polynomials with degree
|
|
1463
|
+
between the given ``degree`` argument::
|
|
1464
|
+
|
|
1465
|
+
sage: all(R.random_element(degree=(-1, 1), monic=True).is_monic() for _ in range(10^3))
|
|
1466
|
+
True
|
|
1467
|
+
sage: all(R.random_element(degree=(0, 1), monic=True).is_monic() for _ in range(10^3))
|
|
1468
|
+
True
|
|
1469
|
+
|
|
1470
|
+
TESTS::
|
|
1471
|
+
|
|
1472
|
+
sage: R.random_element(degree=[5])
|
|
1473
|
+
Traceback (most recent call last):
|
|
1474
|
+
...
|
|
1475
|
+
ValueError: degree argument must be an integer or a tuple of 2 integers (min_degree, max_degree)
|
|
1476
|
+
|
|
1477
|
+
sage: R.random_element(degree=(5,4))
|
|
1478
|
+
Traceback (most recent call last):
|
|
1479
|
+
...
|
|
1480
|
+
ValueError: minimum degree must be less or equal than maximum degree
|
|
1481
|
+
|
|
1482
|
+
Check that :issue:`16682` is fixed::
|
|
1483
|
+
|
|
1484
|
+
sage: R = PolynomialRing(GF(2), 'z')
|
|
1485
|
+
sage: for _ in range(100):
|
|
1486
|
+
....: d = randint(-1, 20)
|
|
1487
|
+
....: P = R.random_element(degree=d)
|
|
1488
|
+
....: assert P.degree() == d
|
|
1489
|
+
|
|
1490
|
+
In :issue:`37118`, ranges including integers below `-1` no longer raise
|
|
1491
|
+
an error::
|
|
1492
|
+
|
|
1493
|
+
sage: R.random_element(degree=(-2, 3)) # random
|
|
1494
|
+
z^3 + z^2 + 1
|
|
1495
|
+
|
|
1496
|
+
::
|
|
1497
|
+
|
|
1498
|
+
sage: 0 in [R.random_element(degree=(-1, 2), monic=True) for _ in range(500)]
|
|
1499
|
+
False
|
|
1500
|
+
|
|
1501
|
+
Testing error handling::
|
|
1502
|
+
|
|
1503
|
+
sage: R.random_element(degree=-5)
|
|
1504
|
+
Traceback (most recent call last):
|
|
1505
|
+
...
|
|
1506
|
+
ValueError: degree (=-5) must be at least -1
|
|
1507
|
+
|
|
1508
|
+
sage: R.random_element(degree=(-3, -2))
|
|
1509
|
+
Traceback (most recent call last):
|
|
1510
|
+
...
|
|
1511
|
+
ValueError: maximum degree (=-2) must be at least -1
|
|
1512
|
+
|
|
1513
|
+
Testing uniformity::
|
|
1514
|
+
|
|
1515
|
+
sage: from collections import Counter
|
|
1516
|
+
sage: R = GF(3)["x"]
|
|
1517
|
+
sage: samples = [R.random_element(degree=(-1, 2)) for _ in range(27000)] # long time
|
|
1518
|
+
sage: assert all(750 <= f <= 1250 for f in Counter(samples).values()) # long time
|
|
1519
|
+
|
|
1520
|
+
sage: samples = [R.random_element(degree=(-1, 2), monic=True) for _ in range(13000)] # long time
|
|
1521
|
+
sage: assert all(750 <= f <= 1250 for f in Counter(samples).values()) # long time
|
|
1522
|
+
"""
|
|
1523
|
+
R = self.base_ring()
|
|
1524
|
+
|
|
1525
|
+
if isinstance(degree, (list, tuple)):
|
|
1526
|
+
if len(degree) != 2:
|
|
1527
|
+
raise ValueError("degree argument must be an integer or a tuple of 2 integers (min_degree, max_degree)")
|
|
1528
|
+
if degree[0] > degree[1]:
|
|
1529
|
+
raise ValueError("minimum degree must be less or equal than maximum degree")
|
|
1530
|
+
if degree[1] < -1:
|
|
1531
|
+
raise ValueError(f"maximum degree (={degree[1]}) must be at least -1")
|
|
1532
|
+
else:
|
|
1533
|
+
if degree < -1:
|
|
1534
|
+
raise ValueError(f"degree (={degree}) must be at least -1")
|
|
1535
|
+
degree = (degree, degree)
|
|
1536
|
+
|
|
1537
|
+
if degree[0] <= -2:
|
|
1538
|
+
degree = (-1, degree[1])
|
|
1539
|
+
|
|
1540
|
+
# If the coefficient range only contains 0, then
|
|
1541
|
+
# * if the degree range includes -1, return the zero polynomial,
|
|
1542
|
+
# * otherwise raise a value error
|
|
1543
|
+
if args == (0, 1):
|
|
1544
|
+
if degree[0] == -1:
|
|
1545
|
+
return self.zero()
|
|
1546
|
+
else:
|
|
1547
|
+
raise ValueError("No polynomial of degree >= 0 has all coefficients zero")
|
|
1548
|
+
|
|
1549
|
+
if degree == (-1, -1):
|
|
1550
|
+
return self.zero()
|
|
1551
|
+
|
|
1552
|
+
# If `monic` is set, zero should be ignored
|
|
1553
|
+
if degree[0] == -1 and monic:
|
|
1554
|
+
if degree[1] == -1:
|
|
1555
|
+
raise ValueError("the maximum degree of monic polynomials needs to be at least 0")
|
|
1556
|
+
if degree[1] == 0:
|
|
1557
|
+
return self.one()
|
|
1558
|
+
degree = (0, degree[1])
|
|
1559
|
+
|
|
1560
|
+
# Pick random coefficients
|
|
1561
|
+
end = degree[1]
|
|
1562
|
+
if degree[0] == -1:
|
|
1563
|
+
return self([R.random_element(*args, **kwds) for _ in range(end + 1)])
|
|
1564
|
+
|
|
1565
|
+
nonzero = False
|
|
1566
|
+
coefs = [None] * (end + 1)
|
|
1567
|
+
|
|
1568
|
+
while not nonzero:
|
|
1569
|
+
# Pick leading coefficients, if `monic` is set it's handle here.
|
|
1570
|
+
if monic:
|
|
1571
|
+
for i in range(degree[1] - degree[0] + 1):
|
|
1572
|
+
coefs[end - i] = R.random_element(*args, **kwds)
|
|
1573
|
+
if not nonzero and not coefs[end - i].is_zero():
|
|
1574
|
+
coefs[end - i] = R.one()
|
|
1575
|
+
nonzero = True
|
|
1576
|
+
else:
|
|
1577
|
+
# Fast path
|
|
1578
|
+
for i in range(degree[1] - degree[0] + 1):
|
|
1579
|
+
coefs[end - i] = R.random_element(*args, **kwds)
|
|
1580
|
+
nonzero |= not coefs[end - i].is_zero()
|
|
1581
|
+
|
|
1582
|
+
# Now we pick the remaining coefficients.
|
|
1583
|
+
for i in range(degree[1] - degree[0] + 1, degree[1] + 1):
|
|
1584
|
+
coefs[end - i] = R.random_element(*args, **kwds)
|
|
1585
|
+
|
|
1586
|
+
return self(coefs)
|
|
1587
|
+
|
|
1588
|
+
def _monics_degree(self, of_degree):
|
|
1589
|
+
"""
|
|
1590
|
+
Refer to monics() for full documentation.
|
|
1591
|
+
"""
|
|
1592
|
+
base = self.base_ring()
|
|
1593
|
+
for coeffs in sage.misc.mrange.xmrange_iter([[base.one()]]+[base]*of_degree):
|
|
1594
|
+
# Each iteration returns a *new* list!
|
|
1595
|
+
# safe to mutate the return
|
|
1596
|
+
coeffs.reverse()
|
|
1597
|
+
yield self(coeffs)
|
|
1598
|
+
|
|
1599
|
+
def _monics_max(self, max_degree):
|
|
1600
|
+
"""
|
|
1601
|
+
Refer to monics() for full documentation.
|
|
1602
|
+
"""
|
|
1603
|
+
for degree in range(max_degree + 1):
|
|
1604
|
+
yield from self._monics_degree(degree)
|
|
1605
|
+
|
|
1606
|
+
def _polys_degree(self, of_degree):
|
|
1607
|
+
"""
|
|
1608
|
+
Refer to polynomials() for full documentation.
|
|
1609
|
+
"""
|
|
1610
|
+
base = self.base_ring()
|
|
1611
|
+
base0 = base.zero()
|
|
1612
|
+
for leading_coeff in base:
|
|
1613
|
+
if leading_coeff != base0:
|
|
1614
|
+
for lt1 in sage.misc.mrange.xmrange_iter([base]*(of_degree)):
|
|
1615
|
+
# Each iteration returns a *new* list!
|
|
1616
|
+
# safe to mutate the return
|
|
1617
|
+
coeffs = [leading_coeff] + lt1
|
|
1618
|
+
coeffs.reverse()
|
|
1619
|
+
yield self(coeffs)
|
|
1620
|
+
|
|
1621
|
+
def _polys_max(self, max_degree):
|
|
1622
|
+
"""
|
|
1623
|
+
Refer to polynomials() for full documentation.
|
|
1624
|
+
"""
|
|
1625
|
+
base = self.base_ring()
|
|
1626
|
+
for coeffs in sage.misc.mrange.xmrange_iter([base]*(max_degree+1)):
|
|
1627
|
+
# Each iteration returns a *new* list!
|
|
1628
|
+
# safe to mutate the return
|
|
1629
|
+
coeffs.reverse()
|
|
1630
|
+
yield self(coeffs)
|
|
1631
|
+
|
|
1632
|
+
@lazy_attribute
|
|
1633
|
+
def _Karatsuba_threshold(self):
|
|
1634
|
+
"""
|
|
1635
|
+
Return the default Karatsuba threshold.
|
|
1636
|
+
|
|
1637
|
+
EXAMPLES::
|
|
1638
|
+
|
|
1639
|
+
sage: R.<x> = QQbar[] # needs sage.rings.number_field
|
|
1640
|
+
sage: R._Karatsuba_threshold # needs sage.rings.number_field
|
|
1641
|
+
8
|
|
1642
|
+
sage: MS = MatrixSpace(ZZ, 2, 2) # needs sage.modules
|
|
1643
|
+
sage: R.<x> = MS[] # needs sage.modules
|
|
1644
|
+
sage: R._Karatsuba_threshold # needs sage.modules
|
|
1645
|
+
0
|
|
1646
|
+
"""
|
|
1647
|
+
base_ring = self.base_ring()
|
|
1648
|
+
if isinstance(base_ring, PolynomialRing_generic):
|
|
1649
|
+
return 0
|
|
1650
|
+
try:
|
|
1651
|
+
from sage.matrix.matrix_space import MatrixSpace
|
|
1652
|
+
except ImportError:
|
|
1653
|
+
pass
|
|
1654
|
+
else:
|
|
1655
|
+
if isinstance(base_ring, MatrixSpace):
|
|
1656
|
+
return 0
|
|
1657
|
+
from sage.rings.fraction_field import FractionField_generic
|
|
1658
|
+
if isinstance(base_ring, FractionField_generic):
|
|
1659
|
+
return 1 << 60
|
|
1660
|
+
# Generic default value
|
|
1661
|
+
return 8
|
|
1662
|
+
|
|
1663
|
+
def karatsuba_threshold(self):
|
|
1664
|
+
"""
|
|
1665
|
+
Return the Karatsuba threshold used for this ring by the method
|
|
1666
|
+
:meth:`_mul_karatsuba` to fall back to the schoolbook algorithm.
|
|
1667
|
+
|
|
1668
|
+
EXAMPLES::
|
|
1669
|
+
|
|
1670
|
+
sage: K = QQ['x']
|
|
1671
|
+
sage: K.karatsuba_threshold()
|
|
1672
|
+
8
|
|
1673
|
+
sage: K = QQ['x']['y']
|
|
1674
|
+
sage: K.karatsuba_threshold()
|
|
1675
|
+
0
|
|
1676
|
+
"""
|
|
1677
|
+
return self._Karatsuba_threshold
|
|
1678
|
+
|
|
1679
|
+
def set_karatsuba_threshold(self, Karatsuba_threshold):
|
|
1680
|
+
"""
|
|
1681
|
+
Changes the default threshold for this ring in the method
|
|
1682
|
+
:meth:`_mul_karatsuba` to fall back to the schoolbook algorithm.
|
|
1683
|
+
|
|
1684
|
+
.. warning::
|
|
1685
|
+
|
|
1686
|
+
This method may have a negative performance impact in polynomial
|
|
1687
|
+
arithmetic. So use it at your own risk.
|
|
1688
|
+
|
|
1689
|
+
EXAMPLES::
|
|
1690
|
+
|
|
1691
|
+
sage: K = QQ['x']
|
|
1692
|
+
sage: K.karatsuba_threshold()
|
|
1693
|
+
8
|
|
1694
|
+
sage: K.set_karatsuba_threshold(0)
|
|
1695
|
+
sage: K.karatsuba_threshold()
|
|
1696
|
+
0
|
|
1697
|
+
"""
|
|
1698
|
+
self._Karatsuba_threshold = int(Karatsuba_threshold)
|
|
1699
|
+
|
|
1700
|
+
def polynomials(self, of_degree=None, max_degree=None):
|
|
1701
|
+
"""
|
|
1702
|
+
Return an iterator over the polynomials of specified degree.
|
|
1703
|
+
|
|
1704
|
+
INPUT: Pass exactly one of:
|
|
1705
|
+
|
|
1706
|
+
- ``max_degree`` -- an int; the iterator will generate all polynomials
|
|
1707
|
+
which have degree less than or equal to ``max_degree``
|
|
1708
|
+
|
|
1709
|
+
- ``of_degree`` -- an int; the iterator will generate
|
|
1710
|
+
all polynomials which have degree ``of_degree``
|
|
1711
|
+
|
|
1712
|
+
OUTPUT: an iterator
|
|
1713
|
+
|
|
1714
|
+
EXAMPLES::
|
|
1715
|
+
|
|
1716
|
+
sage: P = PolynomialRing(GF(3), 'y')
|
|
1717
|
+
sage: for p in P.polynomials(of_degree=2): print(p)
|
|
1718
|
+
y^2
|
|
1719
|
+
y^2 + 1
|
|
1720
|
+
y^2 + 2
|
|
1721
|
+
y^2 + y
|
|
1722
|
+
y^2 + y + 1
|
|
1723
|
+
y^2 + y + 2
|
|
1724
|
+
y^2 + 2*y
|
|
1725
|
+
y^2 + 2*y + 1
|
|
1726
|
+
y^2 + 2*y + 2
|
|
1727
|
+
2*y^2
|
|
1728
|
+
2*y^2 + 1
|
|
1729
|
+
2*y^2 + 2
|
|
1730
|
+
2*y^2 + y
|
|
1731
|
+
2*y^2 + y + 1
|
|
1732
|
+
2*y^2 + y + 2
|
|
1733
|
+
2*y^2 + 2*y
|
|
1734
|
+
2*y^2 + 2*y + 1
|
|
1735
|
+
2*y^2 + 2*y + 2
|
|
1736
|
+
sage: for p in P.polynomials(max_degree=1): print(p)
|
|
1737
|
+
0
|
|
1738
|
+
1
|
|
1739
|
+
2
|
|
1740
|
+
y
|
|
1741
|
+
y + 1
|
|
1742
|
+
y + 2
|
|
1743
|
+
2*y
|
|
1744
|
+
2*y + 1
|
|
1745
|
+
2*y + 2
|
|
1746
|
+
sage: for p in P.polynomials(max_degree=1, of_degree=3): print(p)
|
|
1747
|
+
Traceback (most recent call last):
|
|
1748
|
+
...
|
|
1749
|
+
ValueError: you should pass exactly one of of_degree and max_degree
|
|
1750
|
+
|
|
1751
|
+
AUTHORS:
|
|
1752
|
+
|
|
1753
|
+
- Joel B. Mohler
|
|
1754
|
+
"""
|
|
1755
|
+
|
|
1756
|
+
if self.base_ring().order() is sage.rings.infinity.infinity:
|
|
1757
|
+
raise NotImplementedError
|
|
1758
|
+
if of_degree is not None and max_degree is None:
|
|
1759
|
+
return self._polys_degree( of_degree )
|
|
1760
|
+
if max_degree is not None and of_degree is None:
|
|
1761
|
+
return self._polys_max( max_degree )
|
|
1762
|
+
raise ValueError("you should pass exactly one of of_degree and max_degree")
|
|
1763
|
+
|
|
1764
|
+
def monics(self, of_degree=None, max_degree=None):
|
|
1765
|
+
"""
|
|
1766
|
+
Return an iterator over the monic polynomials of specified degree.
|
|
1767
|
+
|
|
1768
|
+
INPUT: Pass exactly one of:
|
|
1769
|
+
|
|
1770
|
+
|
|
1771
|
+
- ``max_degree`` -- an int; the iterator will generate all monic
|
|
1772
|
+
polynomials which have degree less than or equal to ``max_degree``
|
|
1773
|
+
|
|
1774
|
+
- ``of_degree`` -- an int; the iterator will generate
|
|
1775
|
+
all monic polynomials which have degree ``of_degree``
|
|
1776
|
+
|
|
1777
|
+
OUTPUT: an iterator
|
|
1778
|
+
|
|
1779
|
+
EXAMPLES::
|
|
1780
|
+
|
|
1781
|
+
sage: # needs sage.rings.finite_rings
|
|
1782
|
+
sage: P = PolynomialRing(GF(4, 'a'), 'y')
|
|
1783
|
+
sage: for p in P.monics(of_degree=2): print(p)
|
|
1784
|
+
y^2
|
|
1785
|
+
y^2 + a
|
|
1786
|
+
y^2 + a + 1
|
|
1787
|
+
y^2 + 1
|
|
1788
|
+
y^2 + a*y
|
|
1789
|
+
y^2 + a*y + a
|
|
1790
|
+
y^2 + a*y + a + 1
|
|
1791
|
+
y^2 + a*y + 1
|
|
1792
|
+
y^2 + (a + 1)*y
|
|
1793
|
+
y^2 + (a + 1)*y + a
|
|
1794
|
+
y^2 + (a + 1)*y + a + 1
|
|
1795
|
+
y^2 + (a + 1)*y + 1
|
|
1796
|
+
y^2 + y
|
|
1797
|
+
y^2 + y + a
|
|
1798
|
+
y^2 + y + a + 1
|
|
1799
|
+
y^2 + y + 1
|
|
1800
|
+
sage: for p in P.monics(max_degree=1): print(p)
|
|
1801
|
+
1
|
|
1802
|
+
y
|
|
1803
|
+
y + a
|
|
1804
|
+
y + a + 1
|
|
1805
|
+
y + 1
|
|
1806
|
+
sage: for p in P.monics(max_degree=1, of_degree=3): print(p)
|
|
1807
|
+
Traceback (most recent call last):
|
|
1808
|
+
...
|
|
1809
|
+
ValueError: you should pass exactly one of of_degree and max_degree
|
|
1810
|
+
|
|
1811
|
+
AUTHORS:
|
|
1812
|
+
|
|
1813
|
+
- Joel B. Mohler
|
|
1814
|
+
"""
|
|
1815
|
+
|
|
1816
|
+
if self.base_ring().order() is sage.rings.infinity.infinity:
|
|
1817
|
+
raise NotImplementedError
|
|
1818
|
+
if of_degree is not None and max_degree is None:
|
|
1819
|
+
return self._monics_degree( of_degree )
|
|
1820
|
+
if max_degree is not None and of_degree is None:
|
|
1821
|
+
return self._monics_max( max_degree )
|
|
1822
|
+
raise ValueError("you should pass exactly one of of_degree and max_degree")
|
|
1823
|
+
|
|
1824
|
+
|
|
1825
|
+
# PolynomialRing_general is deprecated since 2024-12-03. See Issue #38207.
|
|
1826
|
+
PolynomialRing_general = PolynomialRing_generic
|
|
1827
|
+
|
|
1828
|
+
|
|
1829
|
+
class PolynomialRing_commutative(PolynomialRing_generic):
|
|
1830
|
+
"""
|
|
1831
|
+
Univariate polynomial ring over a commutative ring.
|
|
1832
|
+
"""
|
|
1833
|
+
def __init__(self, base_ring, name=None, sparse=False, implementation=None,
|
|
1834
|
+
element_class=None, category=None):
|
|
1835
|
+
if base_ring not in _CommutativeRings:
|
|
1836
|
+
raise TypeError("Base ring %s must be a commutative ring." % repr(base_ring))
|
|
1837
|
+
# We trust that, if a category is given, that it is useful.
|
|
1838
|
+
if base_ring.is_zero():
|
|
1839
|
+
category = categories.algebras.Algebras(base_ring.category()).Commutative().Finite()
|
|
1840
|
+
else:
|
|
1841
|
+
defaultcat = polynomial_default_category(base_ring.category(), 1)
|
|
1842
|
+
category = check_default_category(defaultcat, category)
|
|
1843
|
+
PolynomialRing_generic.__init__(self, base_ring, name=name,
|
|
1844
|
+
sparse=sparse, implementation=implementation,
|
|
1845
|
+
element_class=element_class, category=category)
|
|
1846
|
+
|
|
1847
|
+
def quotient_by_principal_ideal(self, f, names=None, **kwds):
|
|
1848
|
+
"""
|
|
1849
|
+
Return the quotient of this polynomial ring by the principal
|
|
1850
|
+
ideal (generated by) `f`.
|
|
1851
|
+
|
|
1852
|
+
INPUT:
|
|
1853
|
+
|
|
1854
|
+
- ``f`` -- either a polynomial in ``self``, or a principal
|
|
1855
|
+
ideal of ``self``
|
|
1856
|
+
- further named arguments that are passed to the quotient constructor
|
|
1857
|
+
|
|
1858
|
+
EXAMPLES::
|
|
1859
|
+
|
|
1860
|
+
sage: R.<x> = QQ[]
|
|
1861
|
+
sage: I = (x^2 - 1) * R
|
|
1862
|
+
sage: R.quotient_by_principal_ideal(I) # needs sage.libs.pari
|
|
1863
|
+
Univariate Quotient Polynomial Ring in xbar
|
|
1864
|
+
over Rational Field with modulus x^2 - 1
|
|
1865
|
+
|
|
1866
|
+
The same example, using the polynomial instead of the ideal,
|
|
1867
|
+
and customizing the variable name::
|
|
1868
|
+
|
|
1869
|
+
sage: R.<x> = QQ[]
|
|
1870
|
+
sage: R.quotient_by_principal_ideal(x^2 - 1, names=('foo',)) # needs sage.libs.pari
|
|
1871
|
+
Univariate Quotient Polynomial Ring in foo
|
|
1872
|
+
over Rational Field with modulus x^2 - 1
|
|
1873
|
+
|
|
1874
|
+
TESTS:
|
|
1875
|
+
|
|
1876
|
+
Quotienting by the zero ideal returns ``self`` (:issue:`5978`)::
|
|
1877
|
+
|
|
1878
|
+
sage: R = QQ['x']
|
|
1879
|
+
sage: R.quotient_by_principal_ideal(R.zero_ideal()) is R
|
|
1880
|
+
True
|
|
1881
|
+
sage: R.quotient_by_principal_ideal(0) is R
|
|
1882
|
+
True
|
|
1883
|
+
"""
|
|
1884
|
+
from sage.rings.ideal import Ideal
|
|
1885
|
+
I = Ideal(f)
|
|
1886
|
+
if I.is_zero():
|
|
1887
|
+
return self
|
|
1888
|
+
f = I.gen()
|
|
1889
|
+
from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing
|
|
1890
|
+
return PolynomialQuotientRing(self, f, names, **kwds)
|
|
1891
|
+
|
|
1892
|
+
def weyl_algebra(self):
|
|
1893
|
+
"""
|
|
1894
|
+
Return the Weyl algebra generated from ``self``.
|
|
1895
|
+
|
|
1896
|
+
EXAMPLES::
|
|
1897
|
+
|
|
1898
|
+
sage: R = QQ['x']
|
|
1899
|
+
sage: W = R.weyl_algebra(); W # needs sage.modules
|
|
1900
|
+
Differential Weyl algebra of polynomials in x over Rational Field
|
|
1901
|
+
sage: W.polynomial_ring() == R # needs sage.modules
|
|
1902
|
+
True
|
|
1903
|
+
"""
|
|
1904
|
+
from sage.algebras.weyl_algebra import DifferentialWeylAlgebra
|
|
1905
|
+
return DifferentialWeylAlgebra(self)
|
|
1906
|
+
|
|
1907
|
+
def _roots_univariate_polynomial(self, p, ring=None, multiplicities=True, algorithm=None, degree_bound=None):
|
|
1908
|
+
"""
|
|
1909
|
+
Return the list of roots of ``p``.
|
|
1910
|
+
|
|
1911
|
+
INPUT:
|
|
1912
|
+
|
|
1913
|
+
- ``p`` -- the polynomial whose roots are computed
|
|
1914
|
+
- ``ring`` -- the ring to find roots (default: the base ring of ``p``)
|
|
1915
|
+
- ``multiplicities`` -- boolean (default: ``True``); if ``True``,
|
|
1916
|
+
return a list of pairs ``(root, multiplicity)``; if ``False`` return
|
|
1917
|
+
a list of roots
|
|
1918
|
+
- ``algorithm`` -- ignored (TODO: remove)
|
|
1919
|
+
- ``degree_bound`` -- if not ``None``, return only roots of degree at
|
|
1920
|
+
most ``degree_bound``
|
|
1921
|
+
|
|
1922
|
+
EXAMPLES::
|
|
1923
|
+
|
|
1924
|
+
sage: # needs sage.libs.singular
|
|
1925
|
+
sage: R.<x> = QQ[]
|
|
1926
|
+
sage: S.<y> = R[]
|
|
1927
|
+
sage: p = y^3 + (-x^2 - 3)*y^2 + (2*x^3 - x^2 + 3)*y - x^4 + 2*x^2 - 1
|
|
1928
|
+
sage: p.roots()
|
|
1929
|
+
[(x^2 - 2*x + 1, 1), (x + 1, 2)]
|
|
1930
|
+
sage: p.roots(multiplicities=False)
|
|
1931
|
+
[x^2 - 2*x + 1, x + 1]
|
|
1932
|
+
sage: p.roots(degree_bound=1)
|
|
1933
|
+
[(x + 1, 2)]
|
|
1934
|
+
|
|
1935
|
+
TESTS:
|
|
1936
|
+
|
|
1937
|
+
Check that :issue:`23639` is fixed::
|
|
1938
|
+
|
|
1939
|
+
sage: foo = QQ['x']['y'].one()
|
|
1940
|
+
sage: foo.roots(QQ)
|
|
1941
|
+
[]
|
|
1942
|
+
"""
|
|
1943
|
+
if ring is not None and ring is not self:
|
|
1944
|
+
p = p.change_ring(ring)
|
|
1945
|
+
if degree_bound is None:
|
|
1946
|
+
return p.roots(multiplicities=multiplicities, algorithm=algorithm)
|
|
1947
|
+
return p.roots(multiplicities=multiplicities, algorithm=algorithm, degree_bound=degree_bound)
|
|
1948
|
+
|
|
1949
|
+
roots = p._roots_from_factorization(p.factor(), multiplicities)
|
|
1950
|
+
if degree_bound is not None:
|
|
1951
|
+
if multiplicities:
|
|
1952
|
+
roots = [(r,m) for (r,m) in roots if r.degree() <= degree_bound]
|
|
1953
|
+
else:
|
|
1954
|
+
roots = [r for r in roots if r.degree() <= degree_bound]
|
|
1955
|
+
return roots
|
|
1956
|
+
|
|
1957
|
+
|
|
1958
|
+
class PolynomialRing_integral_domain(PolynomialRing_commutative, PolynomialRing_singular_repr, CommutativeRing):
|
|
1959
|
+
def __init__(self, base_ring, name='x', sparse=False, implementation=None,
|
|
1960
|
+
element_class=None, category=None):
|
|
1961
|
+
"""
|
|
1962
|
+
TESTS::
|
|
1963
|
+
|
|
1964
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_integral_domain as PRing
|
|
1965
|
+
sage: R = PRing(ZZ, 'x'); R
|
|
1966
|
+
Univariate Polynomial Ring in x over Integer Ring
|
|
1967
|
+
sage: type(R.gen()) # needs sage.libs.flint
|
|
1968
|
+
<class 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'>
|
|
1969
|
+
|
|
1970
|
+
sage: R = PRing(ZZ, 'x', implementation='NTL'); R # needs sage.libs.ntl
|
|
1971
|
+
Univariate Polynomial Ring in x over Integer Ring (using NTL)
|
|
1972
|
+
sage: type(R.gen()) # needs sage.libs.ntl
|
|
1973
|
+
<class 'sage.rings.polynomial.polynomial_integer_dense_ntl.Polynomial_integer_dense_ntl'>
|
|
1974
|
+
"""
|
|
1975
|
+
self._implementation_repr = ''
|
|
1976
|
+
if element_class is None:
|
|
1977
|
+
given_implementation = implementation
|
|
1978
|
+
for implementation in self._implementation_names(implementation, base_ring, sparse):
|
|
1979
|
+
if base_ring is ZZ:
|
|
1980
|
+
if implementation == 'NTL':
|
|
1981
|
+
try:
|
|
1982
|
+
from sage.rings.polynomial.polynomial_integer_dense_ntl \
|
|
1983
|
+
import Polynomial_integer_dense_ntl as element_class
|
|
1984
|
+
except ImportError:
|
|
1985
|
+
if given_implementation:
|
|
1986
|
+
raise
|
|
1987
|
+
continue
|
|
1988
|
+
self._implementation_repr = ' (using NTL)'
|
|
1989
|
+
elif implementation == 'FLINT':
|
|
1990
|
+
try:
|
|
1991
|
+
from .polynomial_integer_dense_flint \
|
|
1992
|
+
import Polynomial_integer_dense_flint as element_class
|
|
1993
|
+
except ImportError:
|
|
1994
|
+
if given_implementation:
|
|
1995
|
+
raise
|
|
1996
|
+
continue
|
|
1997
|
+
break
|
|
1998
|
+
PolynomialRing_commutative.__init__(self, base_ring, name=name,
|
|
1999
|
+
sparse=sparse, implementation=implementation,
|
|
2000
|
+
element_class=element_class, category=category)
|
|
2001
|
+
self._has_singular = can_convert_to_singular(self)
|
|
2002
|
+
|
|
2003
|
+
@cached_method(key=lambda self, d, q, sign, lead: (d, q, sign, tuple([x if isinstance(x, (tuple, list)) else (x, 0) for x in lead]) if isinstance(lead, (tuple, list)) else ((lead, 0))))
|
|
2004
|
+
def weil_polynomials(self, d, q, sign=1, lead=1):
|
|
2005
|
+
r"""
|
|
2006
|
+
Return all integer polynomials whose complex roots all have a specified
|
|
2007
|
+
absolute value.
|
|
2008
|
+
|
|
2009
|
+
Such polynomials `f` satisfy a functional equation
|
|
2010
|
+
|
|
2011
|
+
.. MATH::
|
|
2012
|
+
|
|
2013
|
+
T^d f(q/T) = s q^{d/2} f(T)
|
|
2014
|
+
|
|
2015
|
+
where `d` is the degree of `f`, `s` is a sign and `q^{1/2}` is the
|
|
2016
|
+
absolute value of the roots of `f`.
|
|
2017
|
+
|
|
2018
|
+
INPUT:
|
|
2019
|
+
|
|
2020
|
+
- ``d`` -- integer; the degree of the polynomials
|
|
2021
|
+
|
|
2022
|
+
- ``q`` -- integer; the square of the complex absolute value of the
|
|
2023
|
+
roots
|
|
2024
|
+
|
|
2025
|
+
- ``sign`` -- integer (default: `1`); the sign `s` of the functional
|
|
2026
|
+
equation
|
|
2027
|
+
|
|
2028
|
+
- ``lead`` -- integer; list of integers or list of pairs of integers
|
|
2029
|
+
(default: `1`), constraints on the leading few coefficients of the
|
|
2030
|
+
generated polynomials. If pairs `(a, b)` of integers are given, they
|
|
2031
|
+
are treated as a constraint of the form `\equiv a \pmod{b}`; the
|
|
2032
|
+
moduli must be in decreasing order by divisibility, and the modulus
|
|
2033
|
+
of the leading coefficient must be 0.
|
|
2034
|
+
|
|
2035
|
+
.. SEEALSO::
|
|
2036
|
+
|
|
2037
|
+
More documentation and additional options are available using the
|
|
2038
|
+
iterator
|
|
2039
|
+
:class:`sage.rings.polynomial.weil.weil_polynomials.WeilPolynomials`
|
|
2040
|
+
directly. In addition, polynomials have a method
|
|
2041
|
+
:meth:`is_weil_polynomial` to test whether or not the given
|
|
2042
|
+
polynomial is a Weil polynomial.
|
|
2043
|
+
|
|
2044
|
+
EXAMPLES::
|
|
2045
|
+
|
|
2046
|
+
sage: # needs sage.libs.flint
|
|
2047
|
+
sage: R.<T> = ZZ[]
|
|
2048
|
+
sage: L = R.weil_polynomials(4, 2)
|
|
2049
|
+
sage: len(L)
|
|
2050
|
+
35
|
|
2051
|
+
sage: L[9]
|
|
2052
|
+
T^4 + T^3 + 2*T^2 + 2*T + 4
|
|
2053
|
+
sage: all(p.is_weil_polynomial() for p in L)
|
|
2054
|
+
True
|
|
2055
|
+
|
|
2056
|
+
Setting multiple leading coefficients::
|
|
2057
|
+
|
|
2058
|
+
sage: R.<T> = QQ[]
|
|
2059
|
+
sage: l = R.weil_polynomials(4, 2, lead=((1,0), (2,4), (1,2))); l # needs sage.libs.flint
|
|
2060
|
+
[T^4 + 2*T^3 + 5*T^2 + 4*T + 4,
|
|
2061
|
+
T^4 + 2*T^3 + 3*T^2 + 4*T + 4,
|
|
2062
|
+
T^4 - 2*T^3 + 5*T^2 - 4*T + 4,
|
|
2063
|
+
T^4 - 2*T^3 + 3*T^2 - 4*T + 4]
|
|
2064
|
+
|
|
2065
|
+
We do not require Weil polynomials to be monic. This example generates Weil
|
|
2066
|
+
polynomials associated to K3 surfaces over `\GF{2}` of Picard number at least 12::
|
|
2067
|
+
|
|
2068
|
+
sage: R.<T> = QQ[]
|
|
2069
|
+
sage: l = R.weil_polynomials(10, 1, lead=2) # needs sage.libs.flint
|
|
2070
|
+
sage: len(l) # needs sage.libs.flint
|
|
2071
|
+
4865
|
|
2072
|
+
sage: l[len(l)//2] # needs sage.libs.flint
|
|
2073
|
+
2*T^10 + T^8 + T^6 + T^4 + T^2 + 2
|
|
2074
|
+
|
|
2075
|
+
TESTS:
|
|
2076
|
+
|
|
2077
|
+
We check that products of Weil polynomials are also listed as Weil
|
|
2078
|
+
polynomials::
|
|
2079
|
+
|
|
2080
|
+
sage: all((f * g) in R.weil_polynomials(6, q) for q in [3, 4] # needs sage.libs.flint
|
|
2081
|
+
....: for f in R.weil_polynomials(2, q) for g in R.weil_polynomials(4, q))
|
|
2082
|
+
True
|
|
2083
|
+
|
|
2084
|
+
We check that irreducible Weil polynomials of degree 6 are CM::
|
|
2085
|
+
|
|
2086
|
+
sage: simples = [f for f in R.weil_polynomials(6, 3) if f.is_irreducible()] # needs sage.libs.flint
|
|
2087
|
+
sage: len(simples) # needs sage.libs.flint
|
|
2088
|
+
348
|
|
2089
|
+
sage: reals = [R([f[3+i] + sum((-3)^j * (i+2*j)/(i+j) * binomial(i+j,j) * f[3+i+2*j] # needs sage.libs.flint
|
|
2090
|
+
....: for j in range(1, (3+i)//2 + 1))
|
|
2091
|
+
....: for i in range(4)]) for f in simples]
|
|
2092
|
+
|
|
2093
|
+
Check that every polynomial in this list has 3 real roots between `-2
|
|
2094
|
+
\sqrt{3}` and `2 \sqrt{3}`::
|
|
2095
|
+
|
|
2096
|
+
sage: roots = [f.roots(RR, multiplicities=False) for f in reals] # needs sage.libs.flint
|
|
2097
|
+
sage: all(len(L) == 3 and all(x^2 <= 12 for x in L) for L in roots) # needs sage.libs.flint
|
|
2098
|
+
True
|
|
2099
|
+
|
|
2100
|
+
Finally, check that the original polynomials are reconstructed as CM
|
|
2101
|
+
polynomials::
|
|
2102
|
+
|
|
2103
|
+
sage: all(f == T^3*r(T + 3/T) for (f, r) in zip(simples, reals)) # needs sage.libs.flint
|
|
2104
|
+
True
|
|
2105
|
+
|
|
2106
|
+
A simple check (not sufficient)::
|
|
2107
|
+
|
|
2108
|
+
sage: all(f.number_of_real_roots() == 0 for f in simples) # needs sage.libs.flint
|
|
2109
|
+
True
|
|
2110
|
+
"""
|
|
2111
|
+
R = self.base_ring()
|
|
2112
|
+
if not (R is ZZ or R is QQ):
|
|
2113
|
+
raise ValueError("Weil polynomials have integer coefficients")
|
|
2114
|
+
from sage.rings.polynomial.weil.weil_polynomials import WeilPolynomials
|
|
2115
|
+
return list(WeilPolynomials(d, q, sign, lead, polring=self))
|
|
2116
|
+
|
|
2117
|
+
@staticmethod
|
|
2118
|
+
def _implementation_names_impl(implementation, base_ring, sparse):
|
|
2119
|
+
"""
|
|
2120
|
+
TESTS::
|
|
2121
|
+
|
|
2122
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_integral_domain
|
|
2123
|
+
sage: PolynomialRing_integral_domain._implementation_names_impl(None, ZZ, False)
|
|
2124
|
+
['FLINT', None]
|
|
2125
|
+
sage: PolynomialRing_integral_domain._implementation_names_impl(None, ZZ, True)
|
|
2126
|
+
[None, 'generic']
|
|
2127
|
+
sage: PolynomialRing_integral_domain._implementation_names_impl(None, QQ, False)
|
|
2128
|
+
[None, 'generic']
|
|
2129
|
+
sage: PolynomialRing_integral_domain._implementation_names_impl(None, QQ, True)
|
|
2130
|
+
[None, 'generic']
|
|
2131
|
+
"""
|
|
2132
|
+
if base_ring is ZZ and not sparse:
|
|
2133
|
+
defaults = ["FLINT", None]
|
|
2134
|
+
if implementation in defaults:
|
|
2135
|
+
return defaults
|
|
2136
|
+
elif implementation in ["NTL", "generic"]:
|
|
2137
|
+
return [implementation]
|
|
2138
|
+
elif implementation is None or implementation == "generic":
|
|
2139
|
+
return [None, "generic"]
|
|
2140
|
+
return NotImplemented
|
|
2141
|
+
|
|
2142
|
+
def _repr_(self):
|
|
2143
|
+
"""
|
|
2144
|
+
TESTS::
|
|
2145
|
+
|
|
2146
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_integral_domain as PRing
|
|
2147
|
+
sage: R = PRing(ZZ, 'x', implementation='NTL'); R # needs sage.libs.ntl
|
|
2148
|
+
Univariate Polynomial Ring in x over Integer Ring (using NTL)
|
|
2149
|
+
"""
|
|
2150
|
+
s = PolynomialRing_commutative._repr_(self)
|
|
2151
|
+
return s + self._implementation_repr
|
|
2152
|
+
|
|
2153
|
+
def construction(self):
|
|
2154
|
+
"""
|
|
2155
|
+
Return the construction functor.
|
|
2156
|
+
|
|
2157
|
+
EXAMPLES::
|
|
2158
|
+
|
|
2159
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_integral_domain as PRing
|
|
2160
|
+
sage: R = PRing(ZZ, 'x'); R
|
|
2161
|
+
Univariate Polynomial Ring in x over Integer Ring
|
|
2162
|
+
sage: functor, arg = R.construction(); functor, arg
|
|
2163
|
+
(Poly[x], Integer Ring)
|
|
2164
|
+
sage: functor.implementation is None
|
|
2165
|
+
True
|
|
2166
|
+
|
|
2167
|
+
sage: # needs sage.libs.ntl
|
|
2168
|
+
sage: R = PRing(ZZ, 'x', implementation='NTL'); R
|
|
2169
|
+
Univariate Polynomial Ring in x over Integer Ring (using NTL)
|
|
2170
|
+
sage: functor, arg = R.construction(); functor, arg
|
|
2171
|
+
(Poly[x], Integer Ring)
|
|
2172
|
+
sage: functor.implementation
|
|
2173
|
+
'NTL'
|
|
2174
|
+
"""
|
|
2175
|
+
implementation = None
|
|
2176
|
+
# NOTE: This is obviously not a complete solution. The parents
|
|
2177
|
+
# don't keep track in a clean way what the implementation is.
|
|
2178
|
+
# Issue #31852 is the task of finding a general solution for
|
|
2179
|
+
# construction functors of parents with multiple
|
|
2180
|
+
# implementations, such as MatrixSpace, Polyhedron, and
|
|
2181
|
+
# PolynomialRing.
|
|
2182
|
+
if 'NTL' in self._implementation_repr:
|
|
2183
|
+
implementation = 'NTL'
|
|
2184
|
+
return categories.pushout.PolynomialFunctor(self.variable_name(), sparse=self.is_sparse(),
|
|
2185
|
+
implementation=implementation), self.base_ring()
|
|
2186
|
+
|
|
2187
|
+
|
|
2188
|
+
class PolynomialRing_field(PolynomialRing_integral_domain):
|
|
2189
|
+
def __init__(self, base_ring, name='x', sparse=False, implementation=None,
|
|
2190
|
+
element_class=None, category=None):
|
|
2191
|
+
"""
|
|
2192
|
+
TESTS::
|
|
2193
|
+
|
|
2194
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_field as PRing
|
|
2195
|
+
sage: R = PRing(QQ, 'x'); R
|
|
2196
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
2197
|
+
sage: type(R.gen()) # needs sage.libs.flint
|
|
2198
|
+
<class 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>
|
|
2199
|
+
sage: R = PRing(QQ, 'x', sparse=True); R
|
|
2200
|
+
Sparse Univariate Polynomial Ring in x over Rational Field
|
|
2201
|
+
sage: type(R.gen())
|
|
2202
|
+
<class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category.element_class'>
|
|
2203
|
+
|
|
2204
|
+
sage: # needs sage.rings.real_mpfr
|
|
2205
|
+
sage: R = PRing(CC, 'x'); R
|
|
2206
|
+
Univariate Polynomial Ring in x over Complex Field with 53 bits of precision
|
|
2207
|
+
sage: type(R.gen())
|
|
2208
|
+
<class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category.element_class'>
|
|
2209
|
+
|
|
2210
|
+
Demonstrate that :issue:`8762` is fixed::
|
|
2211
|
+
|
|
2212
|
+
sage: R.<x> = PolynomialRing(GF(next_prime(10^20)), sparse=True) # needs sage.rings.finite_rings
|
|
2213
|
+
sage: x^(10^20) # this should be fast # needs sage.rings.finite_rings
|
|
2214
|
+
x^100000000000000000000
|
|
2215
|
+
"""
|
|
2216
|
+
def _element_class():
|
|
2217
|
+
if element_class:
|
|
2218
|
+
return element_class
|
|
2219
|
+
if sparse:
|
|
2220
|
+
from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_sparse_field
|
|
2221
|
+
return Polynomial_generic_sparse_field
|
|
2222
|
+
if isinstance(base_ring, rational_field.RationalField):
|
|
2223
|
+
try:
|
|
2224
|
+
from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint
|
|
2225
|
+
return Polynomial_rational_flint
|
|
2226
|
+
except ImportError:
|
|
2227
|
+
pass
|
|
2228
|
+
elif isinstance(base_ring, NumberField):
|
|
2229
|
+
if base_ring.is_absolute():
|
|
2230
|
+
from sage.rings.polynomial.polynomial_number_field import Polynomial_absolute_number_field_dense
|
|
2231
|
+
return Polynomial_absolute_number_field_dense
|
|
2232
|
+
else:
|
|
2233
|
+
from sage.rings.polynomial.polynomial_number_field import Polynomial_relative_number_field_dense
|
|
2234
|
+
return Polynomial_relative_number_field_dense
|
|
2235
|
+
elif isinstance(base_ring, sage.rings.abc.RealField):
|
|
2236
|
+
try:
|
|
2237
|
+
from .polynomial_real_mpfr_dense import PolynomialRealDense
|
|
2238
|
+
return PolynomialRealDense
|
|
2239
|
+
except ImportError:
|
|
2240
|
+
pass
|
|
2241
|
+
elif isinstance(base_ring, sage.rings.abc.ComplexBallField):
|
|
2242
|
+
try:
|
|
2243
|
+
from sage.rings.polynomial.polynomial_complex_arb import Polynomial_complex_arb
|
|
2244
|
+
return Polynomial_complex_arb
|
|
2245
|
+
except ImportError:
|
|
2246
|
+
pass
|
|
2247
|
+
from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_dense_field
|
|
2248
|
+
return Polynomial_generic_dense_field
|
|
2249
|
+
|
|
2250
|
+
if category is None:
|
|
2251
|
+
cat = PrincipalIdealDomains()
|
|
2252
|
+
else:
|
|
2253
|
+
cat = category & PrincipalIdealDomains()
|
|
2254
|
+
|
|
2255
|
+
PolynomialRing_integral_domain.__init__(self, base_ring, name=name,
|
|
2256
|
+
sparse=sparse, implementation=implementation,
|
|
2257
|
+
element_class=_element_class(), category=cat)
|
|
2258
|
+
|
|
2259
|
+
def _ideal_class_(self, n=0):
|
|
2260
|
+
"""
|
|
2261
|
+
Return the class representing ideals in univariate polynomial rings
|
|
2262
|
+
over fields.
|
|
2263
|
+
|
|
2264
|
+
EXAMPLES::
|
|
2265
|
+
|
|
2266
|
+
sage: R.<t> = GF(5)[]
|
|
2267
|
+
sage: R._ideal_class_()
|
|
2268
|
+
<class 'sage.rings.polynomial.ideal.Ideal_1poly_field'>
|
|
2269
|
+
"""
|
|
2270
|
+
from sage.rings.polynomial.ideal import Ideal_1poly_field
|
|
2271
|
+
return Ideal_1poly_field
|
|
2272
|
+
|
|
2273
|
+
def divided_difference(self, points, full_table=False):
|
|
2274
|
+
r"""
|
|
2275
|
+
Return the Newton divided-difference coefficients of the
|
|
2276
|
+
Lagrange interpolation polynomial through ``points``.
|
|
2277
|
+
|
|
2278
|
+
INPUT:
|
|
2279
|
+
|
|
2280
|
+
- ``points`` -- list of pairs `(x_0, y_0), (x_1, y_1),
|
|
2281
|
+
\dots, (x_n, y_n)` of elements of the base ring of ``self``,
|
|
2282
|
+
where `x_i - x_j` is invertible for `i \neq j`. This method
|
|
2283
|
+
converts the `x_i` and `y_i` into the base ring of ``self``.
|
|
2284
|
+
|
|
2285
|
+
- ``full_table`` -- boolean (default: ``False``); if ``True``,
|
|
2286
|
+
return the full divided-difference table. If ``False``,
|
|
2287
|
+
only return entries along the main diagonal; these are the
|
|
2288
|
+
Newton divided-difference coefficients `F_{i,i}`.
|
|
2289
|
+
|
|
2290
|
+
OUTPUT:
|
|
2291
|
+
|
|
2292
|
+
The Newton divided-difference coefficients of the `n`-th
|
|
2293
|
+
Lagrange interpolation polynomial `P_n(x)` that passes through
|
|
2294
|
+
the points in ``points`` (see :meth:`lagrange_polynomial`).
|
|
2295
|
+
These are the coefficients `F_{0,0}, F_{1,1}, \dots, F_{n,n}`
|
|
2296
|
+
in the base ring of ``self`` such that
|
|
2297
|
+
|
|
2298
|
+
.. MATH::
|
|
2299
|
+
|
|
2300
|
+
P_n(x) = \sum_{i=0}^n F_{i,i} \prod_{j=0}^{i-1} (x - x_j)
|
|
2301
|
+
|
|
2302
|
+
EXAMPLES:
|
|
2303
|
+
|
|
2304
|
+
Only return the divided-difference coefficients `F_{i,i}`.
|
|
2305
|
+
This example is taken from Example 1, page 121 of [BF2005]_::
|
|
2306
|
+
|
|
2307
|
+
sage: # needs sage.rings.real_mpfr
|
|
2308
|
+
sage: points = [(1.0, 0.7651977), (1.3, 0.6200860), (1.6, 0.4554022),
|
|
2309
|
+
....: (1.9, 0.2818186), (2.2, 0.1103623)]
|
|
2310
|
+
sage: R = PolynomialRing(RR, "x")
|
|
2311
|
+
sage: R.divided_difference(points)
|
|
2312
|
+
[0.765197700000000,
|
|
2313
|
+
-0.483705666666666,
|
|
2314
|
+
-0.108733888888889,
|
|
2315
|
+
0.0658783950617283,
|
|
2316
|
+
0.00182510288066044]
|
|
2317
|
+
|
|
2318
|
+
Now return the full divided-difference table::
|
|
2319
|
+
|
|
2320
|
+
sage: # needs sage.rings.real_mpfr
|
|
2321
|
+
sage: points = [(1.0, 0.7651977), (1.3, 0.6200860), (1.6, 0.4554022),
|
|
2322
|
+
....: (1.9, 0.2818186), (2.2, 0.1103623)]
|
|
2323
|
+
sage: R = PolynomialRing(RR, "x")
|
|
2324
|
+
sage: R.divided_difference(points, full_table=True)
|
|
2325
|
+
[[0.765197700000000],
|
|
2326
|
+
[0.620086000000000, -0.483705666666666],
|
|
2327
|
+
[0.455402200000000, -0.548946000000000, -0.108733888888889],
|
|
2328
|
+
[0.281818600000000, -0.578612000000000,
|
|
2329
|
+
-0.0494433333333339, 0.0658783950617283],
|
|
2330
|
+
[0.110362300000000, -0.571520999999999, 0.0118183333333349,
|
|
2331
|
+
0.0680685185185209, 0.00182510288066044]]
|
|
2332
|
+
|
|
2333
|
+
The following example is taken from Example 4.12, page 225 of
|
|
2334
|
+
[MF1999]_::
|
|
2335
|
+
|
|
2336
|
+
sage: points = [(1, -3), (2, 0), (3, 15), (4, 48), (5, 105), (6, 192)]
|
|
2337
|
+
sage: R = PolynomialRing(QQ, "x")
|
|
2338
|
+
sage: R.divided_difference(points)
|
|
2339
|
+
[-3, 3, 6, 1, 0, 0]
|
|
2340
|
+
sage: R.divided_difference(points, full_table=True)
|
|
2341
|
+
[[-3],
|
|
2342
|
+
[0, 3],
|
|
2343
|
+
[15, 15, 6],
|
|
2344
|
+
[48, 33, 9, 1],
|
|
2345
|
+
[105, 57, 12, 1, 0],
|
|
2346
|
+
[192, 87, 15, 1, 0, 0]]
|
|
2347
|
+
"""
|
|
2348
|
+
to_base_ring = self.base_ring()
|
|
2349
|
+
points = [tuple(to_base_ring(c) for c in p) for p in points]
|
|
2350
|
+
n = len(points)
|
|
2351
|
+
F = [[points[i][1]] for i in range(n)]
|
|
2352
|
+
for i in range(1, n):
|
|
2353
|
+
for j in range(1, i+1):
|
|
2354
|
+
numer = F[i][j-1] - F[i-1][j-1]
|
|
2355
|
+
denom = points[i][0] - points[i-j][0]
|
|
2356
|
+
F[i].append(numer / denom)
|
|
2357
|
+
if full_table:
|
|
2358
|
+
return F
|
|
2359
|
+
else:
|
|
2360
|
+
return [F[i][i] for i in range(n)]
|
|
2361
|
+
|
|
2362
|
+
def lagrange_polynomial(self, points, algorithm='divided_difference',
|
|
2363
|
+
previous_row=None):
|
|
2364
|
+
r"""
|
|
2365
|
+
Return the Lagrange interpolation polynomial through the
|
|
2366
|
+
given points.
|
|
2367
|
+
|
|
2368
|
+
INPUT:
|
|
2369
|
+
|
|
2370
|
+
- ``points`` -- list of pairs `(x_0, y_0), (x_1, y_1),
|
|
2371
|
+
\dots, (x_n, y_n)` of elements of the base ring of ``self``,
|
|
2372
|
+
where `x_i - x_j` is invertible for `i \neq j`. This method
|
|
2373
|
+
converts the `x_i` and `y_i` into the base ring of ``self``.
|
|
2374
|
+
|
|
2375
|
+
- ``algorithm`` -- (default: ``'divided_difference'``) one of
|
|
2376
|
+
the following:
|
|
2377
|
+
|
|
2378
|
+
- ``'divided_difference'``: use the method of divided
|
|
2379
|
+
differences.
|
|
2380
|
+
|
|
2381
|
+
- ``'neville'``: adapt Neville's method as
|
|
2382
|
+
described on page 144 of [BF2005]_ to recursively generate
|
|
2383
|
+
the Lagrange interpolation polynomial. Neville's method
|
|
2384
|
+
generates a table of approximating polynomials, where the
|
|
2385
|
+
last row of that table contains the `n`-th Lagrange
|
|
2386
|
+
interpolation polynomial. The adaptation implemented by
|
|
2387
|
+
this method is to only generate the last row of this
|
|
2388
|
+
table, instead of the full table itself. Generating the
|
|
2389
|
+
full table can be memory inefficient.
|
|
2390
|
+
|
|
2391
|
+
- ``'pari'``: use Pari's function :pari:`polinterpolate`
|
|
2392
|
+
|
|
2393
|
+
- ``previous_row`` -- (default: ``None``) this option is only
|
|
2394
|
+
relevant if used with ``algorithm='neville'``. If provided,
|
|
2395
|
+
this should be the last row of the table resulting from a
|
|
2396
|
+
previous use of Neville's method. If such a row is passed,
|
|
2397
|
+
then ``points`` should consist of both previous and new
|
|
2398
|
+
interpolating points. Neville's method will then use that
|
|
2399
|
+
last row and the interpolating points to generate a new row
|
|
2400
|
+
containing an interpolation polynomial for the new points.
|
|
2401
|
+
|
|
2402
|
+
OUTPUT:
|
|
2403
|
+
|
|
2404
|
+
The Lagrange interpolation polynomial through the points
|
|
2405
|
+
`(x_0, y_0), (x_1, y_1), \dots, (x_n, y_n)`. This is the
|
|
2406
|
+
unique polynomial `P_n` of degree at most `n` in ``self``
|
|
2407
|
+
satisfying `P_n(x_i) = y_i` for `0 \le i \le n`.
|
|
2408
|
+
|
|
2409
|
+
EXAMPLES:
|
|
2410
|
+
|
|
2411
|
+
By default, we use the method of divided differences::
|
|
2412
|
+
|
|
2413
|
+
sage: R = PolynomialRing(QQ, 'x')
|
|
2414
|
+
sage: f = R.lagrange_polynomial([(0,1), (2,2), (3,-2), (-4,9)]); f
|
|
2415
|
+
-23/84*x^3 - 11/84*x^2 + 13/7*x + 1
|
|
2416
|
+
sage: f(0)
|
|
2417
|
+
1
|
|
2418
|
+
sage: f(2)
|
|
2419
|
+
2
|
|
2420
|
+
sage: f(3)
|
|
2421
|
+
-2
|
|
2422
|
+
sage: f(-4)
|
|
2423
|
+
9
|
|
2424
|
+
|
|
2425
|
+
sage: # needs sage.rings.finite_rings
|
|
2426
|
+
sage: R = PolynomialRing(GF(2**3, 'a'), 'x')
|
|
2427
|
+
sage: a = R.base_ring().gen()
|
|
2428
|
+
sage: f = R.lagrange_polynomial([(a^2+a, a), (a, 1), (a^2, a^2+a+1)]); f
|
|
2429
|
+
a^2*x^2 + a^2*x + a^2
|
|
2430
|
+
sage: f(a^2 + a)
|
|
2431
|
+
a
|
|
2432
|
+
sage: f(a)
|
|
2433
|
+
1
|
|
2434
|
+
sage: f(a^2)
|
|
2435
|
+
a^2 + a + 1
|
|
2436
|
+
|
|
2437
|
+
Now use a memory efficient version of Neville's method::
|
|
2438
|
+
|
|
2439
|
+
sage: R = PolynomialRing(QQ, 'x')
|
|
2440
|
+
sage: R.lagrange_polynomial([(0,1), (2,2), (3,-2), (-4,9)],
|
|
2441
|
+
....: algorithm='neville')
|
|
2442
|
+
[9,
|
|
2443
|
+
-11/7*x + 19/7,
|
|
2444
|
+
-17/42*x^2 - 83/42*x + 53/7,
|
|
2445
|
+
-23/84*x^3 - 11/84*x^2 + 13/7*x + 1]
|
|
2446
|
+
|
|
2447
|
+
sage: # needs sage.rings.finite_rings
|
|
2448
|
+
sage: R = PolynomialRing(GF(2**3, 'a'), 'x')
|
|
2449
|
+
sage: a = R.base_ring().gen()
|
|
2450
|
+
sage: R.lagrange_polynomial([(a^2+a, a), (a, 1), (a^2, a^2+a+1)],
|
|
2451
|
+
....: algorithm='neville')
|
|
2452
|
+
[a^2 + a + 1, x + a + 1, a^2*x^2 + a^2*x + a^2]
|
|
2453
|
+
|
|
2454
|
+
Repeated use of Neville's method to get better Lagrange
|
|
2455
|
+
interpolation polynomials::
|
|
2456
|
+
|
|
2457
|
+
sage: R = PolynomialRing(QQ, 'x')
|
|
2458
|
+
sage: p = R.lagrange_polynomial([(0,1), (2,2)], algorithm='neville')
|
|
2459
|
+
sage: R.lagrange_polynomial([(0,1), (2,2), (3,-2), (-4,9)],
|
|
2460
|
+
....: algorithm='neville', previous_row=p)[-1]
|
|
2461
|
+
-23/84*x^3 - 11/84*x^2 + 13/7*x + 1
|
|
2462
|
+
|
|
2463
|
+
sage: # needs sage.rings.finite_rings
|
|
2464
|
+
sage: R = PolynomialRing(GF(2**3, 'a'), 'x')
|
|
2465
|
+
sage: a = R.base_ring().gen()
|
|
2466
|
+
sage: p = R.lagrange_polynomial([(a^2+a, a), (a, 1)], algorithm='neville')
|
|
2467
|
+
sage: R.lagrange_polynomial([(a^2+a, a), (a, 1), (a^2, a^2+a+1)],
|
|
2468
|
+
....: algorithm='neville', previous_row=p)[-1]
|
|
2469
|
+
a^2*x^2 + a^2*x + a^2
|
|
2470
|
+
|
|
2471
|
+
One can also use ``Pari``'s implementation::
|
|
2472
|
+
|
|
2473
|
+
sage: R = PolynomialRing(QQ, 'x')
|
|
2474
|
+
sage: data = [(0,1), (2,5), (3,10)]
|
|
2475
|
+
sage: p = R.lagrange_polynomial(data, algorithm='pari'); p # needs sage.libs.pari
|
|
2476
|
+
x^2 + 1
|
|
2477
|
+
|
|
2478
|
+
TESTS:
|
|
2479
|
+
|
|
2480
|
+
The value for ``algorithm`` must be either
|
|
2481
|
+
``'divided_difference'`` (default), ``'neville'`` or ``'pari'``::
|
|
2482
|
+
|
|
2483
|
+
sage: R = PolynomialRing(QQ, 'x')
|
|
2484
|
+
sage: R.lagrange_polynomial([(0,1),(2,2),(3,-2),(-4,9)], algorithm='abc')
|
|
2485
|
+
Traceback (most recent call last):
|
|
2486
|
+
...
|
|
2487
|
+
ValueError: algorithm can be 'divided_difference', 'neville' or 'pari'
|
|
2488
|
+
|
|
2489
|
+
Make sure that :issue:`10304` is fixed. The return value
|
|
2490
|
+
should always be an element of ``self`` in the case of
|
|
2491
|
+
``divided_difference``, or a list of elements of ``self`` in
|
|
2492
|
+
the case of ``neville``::
|
|
2493
|
+
|
|
2494
|
+
sage: R = PolynomialRing(QQ, 'x')
|
|
2495
|
+
sage: R.lagrange_polynomial([]).parent() == R
|
|
2496
|
+
True
|
|
2497
|
+
sage: R.lagrange_polynomial([(2, 3)]).parent() == R
|
|
2498
|
+
True
|
|
2499
|
+
sage: row = R.lagrange_polynomial([], algorithm='neville')
|
|
2500
|
+
sage: all(poly.parent() == R for poly in row)
|
|
2501
|
+
True
|
|
2502
|
+
sage: row = R.lagrange_polynomial([(2, 3)], algorithm='neville')
|
|
2503
|
+
sage: all(poly.parent() == R for poly in row)
|
|
2504
|
+
True
|
|
2505
|
+
|
|
2506
|
+
Check that base fields of positive characteristic are treated
|
|
2507
|
+
correctly (see :issue:`9787`)::
|
|
2508
|
+
|
|
2509
|
+
sage: R.<x> = GF(101)[]
|
|
2510
|
+
sage: R.lagrange_polynomial([[1, 0], [2, 0]])
|
|
2511
|
+
0
|
|
2512
|
+
sage: R.lagrange_polynomial([[1, 0], [2, 0], [3, 0]])
|
|
2513
|
+
0
|
|
2514
|
+
"""
|
|
2515
|
+
# Perhaps we should be slightly stricter on the input and use
|
|
2516
|
+
# self.base_ring().coerce here and in the divided_difference()
|
|
2517
|
+
# method above. However, this breaks an example in
|
|
2518
|
+
# sage.tests.french_book.nonlinear_doctest where the base ring
|
|
2519
|
+
# is CC, but the function values lie in the symbolic ring.
|
|
2520
|
+
to_base_ring = self.base_ring()
|
|
2521
|
+
points = [[to_base_ring(u) for u in x] for x in points]
|
|
2522
|
+
var = self.gen()
|
|
2523
|
+
|
|
2524
|
+
# use the method of divided-difference
|
|
2525
|
+
if algorithm == "divided_difference":
|
|
2526
|
+
# Evaluate in nested form, similar to Horner's method. This is
|
|
2527
|
+
# more efficient than evaluation using the definition of
|
|
2528
|
+
# Lagrange interpolation polynomial by means of divided
|
|
2529
|
+
# difference.
|
|
2530
|
+
n = len(points)
|
|
2531
|
+
if n == 0:
|
|
2532
|
+
return self.zero()
|
|
2533
|
+
|
|
2534
|
+
F = self.divided_difference(points)
|
|
2535
|
+
P = self.coerce(F[n-1])
|
|
2536
|
+
for i in range(n-2, -1, -1):
|
|
2537
|
+
P *= (var - points[i][0])
|
|
2538
|
+
P += F[i]
|
|
2539
|
+
return P
|
|
2540
|
+
|
|
2541
|
+
# Evaluate using the definition of Lagrange interpolation
|
|
2542
|
+
# polynomial by means of divided difference. This is slow
|
|
2543
|
+
# compared to that above, which is in nested form.
|
|
2544
|
+
# P = 0
|
|
2545
|
+
# for i in range(n):
|
|
2546
|
+
# prod = 1
|
|
2547
|
+
# for j in range(i):
|
|
2548
|
+
# prod *= (var - points[j][0])
|
|
2549
|
+
# P += (F[i] * prod)
|
|
2550
|
+
# return P
|
|
2551
|
+
|
|
2552
|
+
# using Neville's method for recursively generating the
|
|
2553
|
+
# Lagrange interpolation polynomial
|
|
2554
|
+
elif algorithm == "neville":
|
|
2555
|
+
if previous_row is None:
|
|
2556
|
+
previous_row = []
|
|
2557
|
+
N = len(points)
|
|
2558
|
+
M = len(previous_row)
|
|
2559
|
+
# During the computation, P keeps track of the previous row,
|
|
2560
|
+
# and Q keeps track of the current row
|
|
2561
|
+
P = previous_row + [None] * (N - M) # use results of previous computation if available
|
|
2562
|
+
Q = [None] * N
|
|
2563
|
+
for i in range(M, N):
|
|
2564
|
+
Q[0] = self.coerce(points[i][1]) # start populating the current row
|
|
2565
|
+
for j in range(1, 1 + i):
|
|
2566
|
+
numer = (var - points[i - j][0]) * Q[j - 1] - (var - points[i][0]) * P[j - 1]
|
|
2567
|
+
denom = points[i][0] - points[i - j][0]
|
|
2568
|
+
Q[j] = numer / denom
|
|
2569
|
+
P, Q = Q, P # the current row is complete, reuse the old P to hold the next row
|
|
2570
|
+
return P # return the last row in the Neville table
|
|
2571
|
+
|
|
2572
|
+
elif algorithm == "pari":
|
|
2573
|
+
from sage.libs.pari import pari
|
|
2574
|
+
positions = pari([a for a, b in points])
|
|
2575
|
+
values = pari([b for a, b in points])
|
|
2576
|
+
return self(pari.polinterpolate(positions, values))
|
|
2577
|
+
|
|
2578
|
+
raise ValueError("algorithm can be 'divided_difference', 'neville' or 'pari'")
|
|
2579
|
+
|
|
2580
|
+
@cached_method
|
|
2581
|
+
def fraction_field(self):
|
|
2582
|
+
"""
|
|
2583
|
+
Return the fraction field of ``self``.
|
|
2584
|
+
|
|
2585
|
+
EXAMPLES::
|
|
2586
|
+
|
|
2587
|
+
sage: QQbar['x'].fraction_field() # needs sage.rings.number_field
|
|
2588
|
+
Fraction Field of Univariate Polynomial Ring in x over Algebraic
|
|
2589
|
+
Field
|
|
2590
|
+
|
|
2591
|
+
TESTS:
|
|
2592
|
+
|
|
2593
|
+
Check that :issue:`25449` has been resolved::
|
|
2594
|
+
|
|
2595
|
+
sage: # needs sage.rings.finite_rings
|
|
2596
|
+
sage: k = GF(25453)
|
|
2597
|
+
sage: F.<x> = FunctionField(k)
|
|
2598
|
+
sage: R.<t> = k[]
|
|
2599
|
+
sage: t(x)
|
|
2600
|
+
x
|
|
2601
|
+
|
|
2602
|
+
sage: # needs sage.rings.finite_rings
|
|
2603
|
+
sage: k = GF(55667)
|
|
2604
|
+
sage: F.<x> = FunctionField(k)
|
|
2605
|
+
sage: R.<t> = k[]
|
|
2606
|
+
sage: t(x)
|
|
2607
|
+
x
|
|
2608
|
+
|
|
2609
|
+
Fixed :issue:`37374`::
|
|
2610
|
+
|
|
2611
|
+
sage: x = PolynomialRing(GF(37), ['x'], sparse=True).fraction_field().gen()
|
|
2612
|
+
sage: type(x.numerator())
|
|
2613
|
+
<class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category.element_class'>
|
|
2614
|
+
sage: (x^8 + 16*x^6 + 4*x^4 + x^2 + 12).numerator() - 1
|
|
2615
|
+
x^8 + 16*x^6 + 4*x^4 + x^2 + 11
|
|
2616
|
+
"""
|
|
2617
|
+
from sage.rings.fraction_field import FractionField_1poly_field
|
|
2618
|
+
return FractionField_1poly_field(self)
|
|
2619
|
+
|
|
2620
|
+
|
|
2621
|
+
class PolynomialRing_dense_finite_field(PolynomialRing_field):
|
|
2622
|
+
"""
|
|
2623
|
+
Univariate polynomial ring over a finite field.
|
|
2624
|
+
|
|
2625
|
+
EXAMPLES::
|
|
2626
|
+
|
|
2627
|
+
sage: R = PolynomialRing(GF(27, 'a'), 'x') # needs sage.rings.finite_rings
|
|
2628
|
+
sage: type(R) # needs sage.rings.finite_rings
|
|
2629
|
+
<class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_finite_field_with_category'>
|
|
2630
|
+
"""
|
|
2631
|
+
def __init__(self, base_ring, name='x', element_class=None, implementation=None):
|
|
2632
|
+
"""
|
|
2633
|
+
TESTS::
|
|
2634
|
+
|
|
2635
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_finite_field
|
|
2636
|
+
sage: R = PolynomialRing_dense_finite_field(GF(5), implementation='generic')
|
|
2637
|
+
sage: type(R(0))
|
|
2638
|
+
<class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_finite_field_with_category.element_class'>
|
|
2639
|
+
|
|
2640
|
+
sage: S = PolynomialRing_dense_finite_field(GF(25, 'a'), implementation='NTL') # needs sage.libs.ntl sage.rings.finite_rings
|
|
2641
|
+
sage: type(S(0)) # needs sage.libs.ntl sage.rings.finite_rings
|
|
2642
|
+
<class 'sage.rings.polynomial.polynomial_zz_pex.Polynomial_ZZ_pEX'>
|
|
2643
|
+
|
|
2644
|
+
sage: S = PolynomialRing_dense_finite_field(GF(64), implementation='superfast') # needs sage.rings.finite_rings
|
|
2645
|
+
Traceback (most recent call last):
|
|
2646
|
+
...
|
|
2647
|
+
ValueError: unknown implementation 'superfast' for dense polynomial rings over Finite Field in z6 of size 2^6
|
|
2648
|
+
"""
|
|
2649
|
+
if element_class is None:
|
|
2650
|
+
given_implementation = implementation
|
|
2651
|
+
for implementation in self._implementation_names(implementation, base_ring):
|
|
2652
|
+
if implementation == "NTL":
|
|
2653
|
+
try:
|
|
2654
|
+
from sage.libs.ntl.ntl_ZZ_pEContext import ntl_ZZ_pEContext
|
|
2655
|
+
from sage.libs.ntl.ntl_ZZ_pX import ntl_ZZ_pX
|
|
2656
|
+
from sage.rings.polynomial.polynomial_zz_pex import Polynomial_ZZ_pEX
|
|
2657
|
+
except ImportError:
|
|
2658
|
+
if given_implementation:
|
|
2659
|
+
raise
|
|
2660
|
+
continue
|
|
2661
|
+
p = base_ring.characteristic()
|
|
2662
|
+
self._modulus = ntl_ZZ_pEContext(ntl_ZZ_pX(list(base_ring.modulus()), p))
|
|
2663
|
+
element_class = Polynomial_ZZ_pEX
|
|
2664
|
+
break
|
|
2665
|
+
PolynomialRing_field.__init__(self, base_ring, sparse=False, name=name,
|
|
2666
|
+
implementation=implementation, element_class=element_class)
|
|
2667
|
+
|
|
2668
|
+
@staticmethod
|
|
2669
|
+
def _implementation_names_impl(implementation, base_ring, sparse):
|
|
2670
|
+
"""
|
|
2671
|
+
TESTS::
|
|
2672
|
+
|
|
2673
|
+
sage: # needs sage.rings.finite_rings
|
|
2674
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_finite_field
|
|
2675
|
+
sage: PolynomialRing_dense_finite_field._implementation_names_impl("NTL", GF(4), False)
|
|
2676
|
+
['NTL', None]
|
|
2677
|
+
sage: PolynomialRing_dense_finite_field._implementation_names_impl(None, GF(4), False)
|
|
2678
|
+
['NTL', None]
|
|
2679
|
+
sage: PolynomialRing_dense_finite_field._implementation_names_impl("generic", GF(4), False)
|
|
2680
|
+
['generic']
|
|
2681
|
+
sage: PolynomialRing_dense_finite_field._implementation_names_impl("FLINT", GF(4), False)
|
|
2682
|
+
NotImplemented
|
|
2683
|
+
sage: PolynomialRing_dense_finite_field._implementation_names_impl(None, GF(4), True)
|
|
2684
|
+
NotImplemented
|
|
2685
|
+
"""
|
|
2686
|
+
if sparse:
|
|
2687
|
+
return NotImplemented
|
|
2688
|
+
defaults = ["NTL", None]
|
|
2689
|
+
if implementation in defaults:
|
|
2690
|
+
return defaults
|
|
2691
|
+
elif implementation == "generic":
|
|
2692
|
+
return [implementation]
|
|
2693
|
+
return NotImplemented
|
|
2694
|
+
|
|
2695
|
+
def irreducible_element(self, n, algorithm=None):
|
|
2696
|
+
"""
|
|
2697
|
+
Construct a monic irreducible polynomial of degree `n`.
|
|
2698
|
+
|
|
2699
|
+
INPUT:
|
|
2700
|
+
|
|
2701
|
+
- ``n`` -- integer; degree of the polynomial to construct
|
|
2702
|
+
|
|
2703
|
+
- ``algorithm`` -- string (algorithm to use) or ``None``:
|
|
2704
|
+
|
|
2705
|
+
- ``'random'`` or ``None``:
|
|
2706
|
+
try random polynomials until an irreducible one is found
|
|
2707
|
+
|
|
2708
|
+
- ``'first_lexicographic'``: try polynomials in
|
|
2709
|
+
lexicographic order until an irreducible one is found
|
|
2710
|
+
|
|
2711
|
+
OUTPUT: a monic irreducible polynomial of degree `n` in ``self``
|
|
2712
|
+
|
|
2713
|
+
EXAMPLES::
|
|
2714
|
+
|
|
2715
|
+
sage: # needs sage.modules sage.rings.finite_rings
|
|
2716
|
+
sage: f = GF(5^3, 'a')['x'].irreducible_element(2)
|
|
2717
|
+
sage: f.degree()
|
|
2718
|
+
2
|
|
2719
|
+
sage: f.is_irreducible()
|
|
2720
|
+
True
|
|
2721
|
+
sage: R = GF(19)['x']
|
|
2722
|
+
sage: R.irreducible_element(21, algorithm='first_lexicographic')
|
|
2723
|
+
x^21 + x + 5
|
|
2724
|
+
sage: R = GF(5**2, 'a')['x']
|
|
2725
|
+
sage: R.irreducible_element(17, algorithm='first_lexicographic')
|
|
2726
|
+
x^17 + a*x + 4*a + 3
|
|
2727
|
+
|
|
2728
|
+
AUTHORS:
|
|
2729
|
+
|
|
2730
|
+
- Peter Bruin (June 2013)
|
|
2731
|
+
- Jean-Pierre Flori (May 2014)
|
|
2732
|
+
"""
|
|
2733
|
+
if n < 1:
|
|
2734
|
+
raise ValueError("degree must be at least 1")
|
|
2735
|
+
|
|
2736
|
+
if algorithm is None:
|
|
2737
|
+
algorithm = "random"
|
|
2738
|
+
|
|
2739
|
+
if algorithm == "random":
|
|
2740
|
+
while True:
|
|
2741
|
+
f = self.gen()**n + self.random_element(degree=(0, n - 1))
|
|
2742
|
+
if f.is_irreducible():
|
|
2743
|
+
return f
|
|
2744
|
+
elif algorithm == "first_lexicographic":
|
|
2745
|
+
for g in self.polynomials(max_degree=n-1):
|
|
2746
|
+
f = self.gen()**n + g
|
|
2747
|
+
if f.is_irreducible():
|
|
2748
|
+
return f
|
|
2749
|
+
else:
|
|
2750
|
+
raise ValueError("no such algorithm for finding an irreducible polynomial: %s" % algorithm)
|
|
2751
|
+
|
|
2752
|
+
def _roth_ruckenstein(self, p, degree_bound, precision):
|
|
2753
|
+
r"""
|
|
2754
|
+
Return all polynomials which are a solution to the, possibly modular,
|
|
2755
|
+
root-finding problem.
|
|
2756
|
+
|
|
2757
|
+
This is the core of Roth-Ruckenstein's algorithm where all conversions,
|
|
2758
|
+
checks and parent-extraction have been done.
|
|
2759
|
+
|
|
2760
|
+
INPUT:
|
|
2761
|
+
|
|
2762
|
+
- ``p`` -- a nonzero polynomial over ``F[x][y]``. The polynomial ``p``
|
|
2763
|
+
should be first truncated to ``precision``
|
|
2764
|
+
|
|
2765
|
+
- ``degree_bound`` -- a bound on the degree of the roots of ``p`` that
|
|
2766
|
+
the algorithm computes
|
|
2767
|
+
|
|
2768
|
+
- ``precision`` -- if given, roots are computed modulo `x^d` where `d` is
|
|
2769
|
+
``precision`` (see below)
|
|
2770
|
+
|
|
2771
|
+
OUTPUT: the list of roots of ``p`` of degree at most ``degree_bound``:
|
|
2772
|
+
|
|
2773
|
+
- If `precision = None` actual roots are computed, i.e. all `f \in F[x]`
|
|
2774
|
+
such that `p(f) = 0`.
|
|
2775
|
+
|
|
2776
|
+
- If ``precision = k`` for some integer ``k``, then all `f \in \F[x]` such
|
|
2777
|
+
that `Q(f) \equiv 0 \mod x^k` are computed. This set is infinite, thus it
|
|
2778
|
+
represented as a list of pairs in `F[x] \times \ZZ_+`, where
|
|
2779
|
+
`(f, d)` denotes that `Q(f + x^d h) \equiv 0 \mod x^k` for any `h \in
|
|
2780
|
+
F[[x]]`.
|
|
2781
|
+
|
|
2782
|
+
EXAMPLES::
|
|
2783
|
+
|
|
2784
|
+
sage: # needs sage.rings.finite_rings
|
|
2785
|
+
sage: F = GF(17)
|
|
2786
|
+
sage: Px.<x> = F[]
|
|
2787
|
+
sage: Pxy.<y> = Px[]
|
|
2788
|
+
sage: p = (y - (x**2 + x + 1)) * (y**2 - x + 1) * (y - (x**3 + 4*x + 16))
|
|
2789
|
+
sage: Px._roth_ruckenstein(p, 3, None)
|
|
2790
|
+
[x^3 + 4*x + 16, x^2 + x + 1]
|
|
2791
|
+
sage: Px._roth_ruckenstein(p, 2, None)
|
|
2792
|
+
[x^2 + x + 1]
|
|
2793
|
+
sage: Px._roth_ruckenstein(p, 1, 2)
|
|
2794
|
+
[(4*x + 16, 2), (2*x + 13, 2), (15*x + 4, 2), (x + 1, 2)]
|
|
2795
|
+
"""
|
|
2796
|
+
def roth_rec(p, lam, k, g):
|
|
2797
|
+
r"""
|
|
2798
|
+
Recursive core method for Roth-Ruckenstein algorithm.
|
|
2799
|
+
|
|
2800
|
+
INPUT:
|
|
2801
|
+
|
|
2802
|
+
- ``p`` -- the current value of the polynomial
|
|
2803
|
+
- ``lam`` -- is the power of x whose coefficient is being computed
|
|
2804
|
+
- ``k`` -- the remaining precision to handle (if ``precision`` is given)
|
|
2805
|
+
- ``g`` -- the root being computed
|
|
2806
|
+
"""
|
|
2807
|
+
if precision and k <= 0:
|
|
2808
|
+
solutions.append((g, lam))
|
|
2809
|
+
return
|
|
2810
|
+
val = min(c.valuation() for c in p)
|
|
2811
|
+
if precision:
|
|
2812
|
+
k = k - val
|
|
2813
|
+
T = p.map_coefficients(lambda c:c.shift(-val))
|
|
2814
|
+
Ty = T.map_coefficients(lambda c:c[0]).change_ring(F)
|
|
2815
|
+
if Ty.is_zero() or (precision and k <= 0):
|
|
2816
|
+
if precision:
|
|
2817
|
+
solutions.append((g, lam))
|
|
2818
|
+
else:
|
|
2819
|
+
solutions.append(g)
|
|
2820
|
+
return
|
|
2821
|
+
roots = Ty.roots(multiplicities=False)
|
|
2822
|
+
for gamma in roots:
|
|
2823
|
+
g_new = g + gamma*x**lam
|
|
2824
|
+
if lam < degree_bound:
|
|
2825
|
+
Tg = T(x*y + gamma)
|
|
2826
|
+
roth_rec(Tg , lam+1, k, g_new)
|
|
2827
|
+
else:
|
|
2828
|
+
if precision:
|
|
2829
|
+
solutions.append((g_new, lam+1))
|
|
2830
|
+
elif p(gamma).is_zero():
|
|
2831
|
+
solutions.append(g_new)
|
|
2832
|
+
return
|
|
2833
|
+
|
|
2834
|
+
x = self.gen()
|
|
2835
|
+
y = p.parent().gen()
|
|
2836
|
+
F = self.base_ring()
|
|
2837
|
+
solutions = []
|
|
2838
|
+
g = self.zero()
|
|
2839
|
+
|
|
2840
|
+
roth_rec(p, 0, precision, g)
|
|
2841
|
+
return solutions
|
|
2842
|
+
|
|
2843
|
+
def _alekhnovich(self, p, degree_bound, precision=None, dc_threshold=None):
|
|
2844
|
+
r"""
|
|
2845
|
+
Use Alekhnovich's Divide & Conquer variant of Roth-Ruckenstein's
|
|
2846
|
+
rootfinding algorithm to find roots modulo-up-to-some-precision of a `Q \in
|
|
2847
|
+
F[x][y]` where `F` is a finite field. Supports a mixed strategy with
|
|
2848
|
+
Roth-Ruckenstein applied at lowest precision.
|
|
2849
|
+
|
|
2850
|
+
INPUT:
|
|
2851
|
+
|
|
2852
|
+
- ``p`` -- a nonzero polynomial over ``F[x][y]``. The polynomial ``p``
|
|
2853
|
+
should be first truncated to ``precision``
|
|
2854
|
+
|
|
2855
|
+
- ``degree_bound`` -- a bound on the degree of the roots of ``p`` that
|
|
2856
|
+
the algorithm computes
|
|
2857
|
+
|
|
2858
|
+
- ``precision`` -- if given, roots are computed modulo `x^d` where `d` is
|
|
2859
|
+
``precision`` (see below)
|
|
2860
|
+
|
|
2861
|
+
- ``dc_threshold`` -- if given, the algorithm calls :meth:`_roth_ruckenetein`
|
|
2862
|
+
to compute roots of degree at most ``dc_threshold``
|
|
2863
|
+
|
|
2864
|
+
OUTPUT: the list of roots of ``p`` of degree at most ``degree_bound``:
|
|
2865
|
+
|
|
2866
|
+
- If `precision = None` actual roots are computed, i.e. all `f \in F[x]`
|
|
2867
|
+
such that `p(f) = 0`.
|
|
2868
|
+
|
|
2869
|
+
- If ``precision = k`` for some integer ``k``, then all `f \in \F[x]` such
|
|
2870
|
+
that `Q(f) \equiv 0 \mod x^k` are computed. This set is infinite, thus it
|
|
2871
|
+
represented as a list of pairs in `F[x] \times \ZZ_+`, where
|
|
2872
|
+
`(f, d)` denotes that `Q(f + x^d h) \equiv 0 \mod x^k` for any `h \in
|
|
2873
|
+
F[[x]]`.
|
|
2874
|
+
|
|
2875
|
+
.. NOTE::
|
|
2876
|
+
|
|
2877
|
+
Non-exhaustive testing tends to indicate that ``dc_threhold = None`` is,
|
|
2878
|
+
surprisingly, the best strategy. (See the example section.)
|
|
2879
|
+
|
|
2880
|
+
EXAMPLES::
|
|
2881
|
+
|
|
2882
|
+
sage: # needs sage.rings.finite_rings
|
|
2883
|
+
sage: R.<x> = GF(17)[]
|
|
2884
|
+
sage: S.<y> = R[]
|
|
2885
|
+
sage: p = (y - 2*x^2 - 3*x - 14) * (y - 3*x + 2) * (y - 1)
|
|
2886
|
+
sage: R._alekhnovich(p, 2)
|
|
2887
|
+
[3*x + 15, 2*x^2 + 3*x + 14, 1]
|
|
2888
|
+
sage: R._alekhnovich(p, 1)
|
|
2889
|
+
[3*x + 15, 1]
|
|
2890
|
+
sage: R._alekhnovich(p, 1, precision=2)
|
|
2891
|
+
[(3*x + 15, 2), (3*x + 14, 2), (1, 2)]
|
|
2892
|
+
|
|
2893
|
+
Example of benchmark to check that `dc_threshold = None` is better::
|
|
2894
|
+
|
|
2895
|
+
sage: # not tested, needs sage.rings.finite_rings
|
|
2896
|
+
sage: p = prod(y - R.random_element(20)
|
|
2897
|
+
....: for _ in range(10)) * S.random_element(10,10)
|
|
2898
|
+
sage: %timeit _alekhnovich(R, p, 20, dc_threshold = None)
|
|
2899
|
+
1 loop, best of 3: 418 ms per loop
|
|
2900
|
+
sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 1)
|
|
2901
|
+
1 loop, best of 3: 416 ms per loop
|
|
2902
|
+
sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 2)
|
|
2903
|
+
1 loop, best of 3: 418 ms per loop
|
|
2904
|
+
sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 3)
|
|
2905
|
+
1 loop, best of 3: 454 ms per loop
|
|
2906
|
+
sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 4)
|
|
2907
|
+
1 loop, best of 3: 519 ms per loop
|
|
2908
|
+
|
|
2909
|
+
AUTHORS:
|
|
2910
|
+
|
|
2911
|
+
- Johan Rosenkilde (2015) -- Original implementation
|
|
2912
|
+
- Bruno Grenet (August 2016) -- Incorporation into SageMath and polishing
|
|
2913
|
+
"""
|
|
2914
|
+
def alekh_rec(p, k, degree_bound, lvl):
|
|
2915
|
+
r"""
|
|
2916
|
+
Recursive core method for Alekhnovich algorithm.
|
|
2917
|
+
|
|
2918
|
+
INPUT:
|
|
2919
|
+
|
|
2920
|
+
- ``p`` -- the current value of the polynomial
|
|
2921
|
+
- ``k`` -- the number of coefficients left to be computed
|
|
2922
|
+
- ``degree_bound`` -- the current degree bound
|
|
2923
|
+
- ``lvl`` -- the level in the recursion tree
|
|
2924
|
+
"""
|
|
2925
|
+
if k <= 0:
|
|
2926
|
+
return [ (self.zero(),0) ]
|
|
2927
|
+
elif degree_bound < 0:
|
|
2928
|
+
# The only possible root of (current) p, if any, is y = 0
|
|
2929
|
+
if p(0).is_zero() or p(0).valuation() >= k:
|
|
2930
|
+
return [ (self.zero(),0) ]
|
|
2931
|
+
else:
|
|
2932
|
+
return []
|
|
2933
|
+
elif k == 1 or degree_bound == 0:
|
|
2934
|
+
#Either one coefficient left to be computed, or p has only one coefficient
|
|
2935
|
+
py = self([c[0] for c in p.list()]) # py = p(x=0, y)
|
|
2936
|
+
if py.is_zero():
|
|
2937
|
+
return [ (self.zero(), 0) ]
|
|
2938
|
+
roots = py.roots(multiplicities=False)
|
|
2939
|
+
return [ (self(r),1) for r in roots ]
|
|
2940
|
+
elif k < dc_threshold:
|
|
2941
|
+
# Run Roth-Ruckenstein
|
|
2942
|
+
return self._roth_ruckenstein(p, degree_bound=degree_bound, precision=k)
|
|
2943
|
+
else:
|
|
2944
|
+
p = p.map_coefficients(lambda c:c.truncate(k))
|
|
2945
|
+
half_roots = alekh_rec(p, k//2, degree_bound, lvl+1)
|
|
2946
|
+
whole_roots = []
|
|
2947
|
+
for (hi, di) in half_roots:
|
|
2948
|
+
QhatT = p(hi + y*x**di)
|
|
2949
|
+
if not QhatT:
|
|
2950
|
+
whole_roots.append((hi,di))
|
|
2951
|
+
else:
|
|
2952
|
+
val = min(c.valuation() for c in QhatT)
|
|
2953
|
+
Qhat = QhatT.map_coefficients(lambda c:c.shift(-val))
|
|
2954
|
+
sec_half = alekh_rec(Qhat, k-val, degree_bound - di, lvl+1)
|
|
2955
|
+
whole_roots.extend([ (hi + hij.shift(di), di+dij) for (hij, dij) in sec_half ])
|
|
2956
|
+
return whole_roots
|
|
2957
|
+
|
|
2958
|
+
x = self.gen()
|
|
2959
|
+
y = p.parent().gen()
|
|
2960
|
+
|
|
2961
|
+
# If precision is not given, find actual roots. To be sure, precision then
|
|
2962
|
+
# needs to be more than wdeg{1,degree_bound}(Q) since a root might have degree degree_bound.
|
|
2963
|
+
if precision is None:
|
|
2964
|
+
k = 1 + max( p[i].degree() + degree_bound*i for i in range(1+p.degree()))
|
|
2965
|
+
else:
|
|
2966
|
+
k = precision
|
|
2967
|
+
|
|
2968
|
+
mod_roots = alekh_rec(p, k, degree_bound, 0)
|
|
2969
|
+
|
|
2970
|
+
if precision is None:
|
|
2971
|
+
roots = []
|
|
2972
|
+
for hi,_ in mod_roots:
|
|
2973
|
+
if p(hi).is_zero():
|
|
2974
|
+
roots.append(hi)
|
|
2975
|
+
return roots
|
|
2976
|
+
else:
|
|
2977
|
+
return mod_roots
|
|
2978
|
+
|
|
2979
|
+
def _roots_univariate_polynomial(self, p, ring=None, multiplicities=False, algorithm=None, degree_bound=None):
|
|
2980
|
+
"""
|
|
2981
|
+
Return the list of roots of ``p``.
|
|
2982
|
+
|
|
2983
|
+
INPUT:
|
|
2984
|
+
|
|
2985
|
+
- ``p`` -- the polynomial whose roots are computed
|
|
2986
|
+
- ``ring`` -- the ring to find roots (default: the base ring of ``p``)
|
|
2987
|
+
- ``multiplicities`` -- boolean (default: ``True``); currently, roots are only
|
|
2988
|
+
computed without their multiplicities
|
|
2989
|
+
- ``algorithm`` -- the algorithm to use: either ``'Alekhnovich'`` (default)
|
|
2990
|
+
or ``'Roth-Ruckenstein'``
|
|
2991
|
+
- ``degree_bound`` -- if not ``None``, return only roots of degree at
|
|
2992
|
+
most ``degree_bound``
|
|
2993
|
+
|
|
2994
|
+
EXAMPLES::
|
|
2995
|
+
|
|
2996
|
+
sage: # needs sage.rings.finite_rings
|
|
2997
|
+
sage: R.<x> = GF(13)[]
|
|
2998
|
+
sage: S.<y> = R[]
|
|
2999
|
+
sage: p = y^2 + (12*x^2 + x + 11)*y + x^3 + 12*x^2 + 12*x + 1
|
|
3000
|
+
sage: p.roots(multiplicities=False)
|
|
3001
|
+
[x^2 + 11*x + 1, x + 1]
|
|
3002
|
+
sage: p.roots(multiplicities=False, degree_bound=1)
|
|
3003
|
+
[x + 1]
|
|
3004
|
+
sage: p.roots(multiplicities=False, algorithm='Roth-Ruckenstein')
|
|
3005
|
+
[x^2 + 11*x + 1, x + 1]
|
|
3006
|
+
|
|
3007
|
+
TESTS:
|
|
3008
|
+
|
|
3009
|
+
Check that :issue:`23639` is fixed::
|
|
3010
|
+
|
|
3011
|
+
sage: R = GF(3)['x']['y']
|
|
3012
|
+
sage: R.one().roots(multiplicities=False)
|
|
3013
|
+
[]
|
|
3014
|
+
sage: R.zero().roots(multiplicities=False)
|
|
3015
|
+
Traceback (most recent call last):
|
|
3016
|
+
...
|
|
3017
|
+
ArithmeticError: roots of 0 are not defined
|
|
3018
|
+
"""
|
|
3019
|
+
if multiplicities:
|
|
3020
|
+
raise NotImplementedError("Use multiplicities=False")
|
|
3021
|
+
|
|
3022
|
+
if degree_bound is None:
|
|
3023
|
+
l = p.degree()
|
|
3024
|
+
if l < 0:
|
|
3025
|
+
raise ArithmeticError("roots of 0 are not defined")
|
|
3026
|
+
if l == 0:
|
|
3027
|
+
return []
|
|
3028
|
+
dl = p[l].degree()
|
|
3029
|
+
degree_bound = max((p[i].degree() - dl)//(l - i) for i in range(l) if p[i])
|
|
3030
|
+
|
|
3031
|
+
if algorithm is None:
|
|
3032
|
+
algorithm = "Alekhnovich"
|
|
3033
|
+
|
|
3034
|
+
if algorithm == "Roth-Ruckenstein":
|
|
3035
|
+
return self._roth_ruckenstein(p, degree_bound, None)
|
|
3036
|
+
|
|
3037
|
+
elif algorithm == "Alekhnovich":
|
|
3038
|
+
return self._alekhnovich(p, degree_bound)
|
|
3039
|
+
|
|
3040
|
+
else:
|
|
3041
|
+
raise ValueError("unknown algorithm '{}'".format(algorithm))
|
|
3042
|
+
|
|
3043
|
+
|
|
3044
|
+
class PolynomialRing_cdvr(PolynomialRing_integral_domain):
|
|
3045
|
+
r"""
|
|
3046
|
+
A class for polynomial ring over complete discrete valuation rings
|
|
3047
|
+
"""
|
|
3048
|
+
def __init__(self, base_ring, name=None, sparse=False, implementation=None,
|
|
3049
|
+
element_class=None, category=None):
|
|
3050
|
+
r"""
|
|
3051
|
+
TESTS::
|
|
3052
|
+
|
|
3053
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_cdvr
|
|
3054
|
+
|
|
3055
|
+
sage: S.<x> = ZZ[]
|
|
3056
|
+
sage: isinstance(S, PolynomialRing_cdvr)
|
|
3057
|
+
False
|
|
3058
|
+
|
|
3059
|
+
sage: # needs sage.rings.padics
|
|
3060
|
+
sage: S.<x> = Zp(5)[]
|
|
3061
|
+
sage: isinstance(S, PolynomialRing_cdvr)
|
|
3062
|
+
True
|
|
3063
|
+
"""
|
|
3064
|
+
if element_class is None:
|
|
3065
|
+
if sparse:
|
|
3066
|
+
from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_sparse_cdvr
|
|
3067
|
+
element_class = Polynomial_generic_sparse_cdvr
|
|
3068
|
+
else:
|
|
3069
|
+
from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_dense_cdvr
|
|
3070
|
+
element_class = Polynomial_generic_dense_cdvr
|
|
3071
|
+
PolynomialRing_integral_domain.__init__(self, base_ring, name, sparse,
|
|
3072
|
+
implementation=implementation,
|
|
3073
|
+
element_class=element_class, category=category)
|
|
3074
|
+
|
|
3075
|
+
|
|
3076
|
+
class PolynomialRing_cdvf(PolynomialRing_cdvr, PolynomialRing_field):
|
|
3077
|
+
"""
|
|
3078
|
+
A class for polynomial ring over complete discrete valuation fields
|
|
3079
|
+
"""
|
|
3080
|
+
def __init__(self, base_ring, name=None, sparse=False, implementation=None,
|
|
3081
|
+
element_class=None, category=None):
|
|
3082
|
+
r"""
|
|
3083
|
+
TESTS::
|
|
3084
|
+
|
|
3085
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_cdvf
|
|
3086
|
+
|
|
3087
|
+
sage: S.<x> = QQ[]
|
|
3088
|
+
sage: isinstance(S, PolynomialRing_cdvf)
|
|
3089
|
+
False
|
|
3090
|
+
|
|
3091
|
+
sage: S.<x> = Qp(5)[] # needs sage.rings.padics
|
|
3092
|
+
sage: isinstance(S, PolynomialRing_cdvf) # needs sage.rings.padics
|
|
3093
|
+
True
|
|
3094
|
+
"""
|
|
3095
|
+
if element_class is None:
|
|
3096
|
+
if sparse:
|
|
3097
|
+
from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_sparse_cdvf
|
|
3098
|
+
element_class = Polynomial_generic_sparse_cdvf
|
|
3099
|
+
else:
|
|
3100
|
+
from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_dense_cdvf
|
|
3101
|
+
element_class = Polynomial_generic_dense_cdvf
|
|
3102
|
+
PolynomialRing_field.__init__(self, base_ring, name, sparse,
|
|
3103
|
+
implementation=implementation, element_class=element_class,
|
|
3104
|
+
category=category)
|
|
3105
|
+
|
|
3106
|
+
|
|
3107
|
+
class PolynomialRing_dense_padic_ring_generic(PolynomialRing_cdvr):
|
|
3108
|
+
r"""
|
|
3109
|
+
A class for dense polynomial ring over `p`-adic rings
|
|
3110
|
+
"""
|
|
3111
|
+
def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None):
|
|
3112
|
+
PolynomialRing_cdvr.__init__(self, base_ring, sparse=False, name=name,
|
|
3113
|
+
implementation=implementation, element_class=element_class,
|
|
3114
|
+
category=category)
|
|
3115
|
+
|
|
3116
|
+
@staticmethod
|
|
3117
|
+
def _implementation_names_impl(implementation, base_ring, sparse):
|
|
3118
|
+
"""
|
|
3119
|
+
Only support ``implementation=None`` and ``sparse=False``.
|
|
3120
|
+
|
|
3121
|
+
TESTS::
|
|
3122
|
+
|
|
3123
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_ring_generic
|
|
3124
|
+
sage: PolynomialRing_dense_padic_ring_generic._implementation_names_impl(None, Zp(2), False) # needs sage.rings.padics
|
|
3125
|
+
[None]
|
|
3126
|
+
sage: PolynomialRing_dense_padic_ring_generic._implementation_names_impl(None, Zp(2), True) # needs sage.rings.padics
|
|
3127
|
+
NotImplemented
|
|
3128
|
+
sage: PolynomialRing_dense_padic_ring_generic._implementation_names_impl("generic", Zp(2), False) # needs sage.rings.padics
|
|
3129
|
+
NotImplemented
|
|
3130
|
+
"""
|
|
3131
|
+
if implementation is None and not sparse:
|
|
3132
|
+
return [None] # Not a "generic" implementation
|
|
3133
|
+
return NotImplemented
|
|
3134
|
+
|
|
3135
|
+
|
|
3136
|
+
class PolynomialRing_dense_padic_field_generic(PolynomialRing_cdvf):
|
|
3137
|
+
r"""
|
|
3138
|
+
A class for dense polynomial ring over `p`-adic fields
|
|
3139
|
+
"""
|
|
3140
|
+
def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None):
|
|
3141
|
+
PolynomialRing_cdvf.__init__(self, base_ring, sparse=False, name=name,
|
|
3142
|
+
implementation=implementation, element_class=element_class,
|
|
3143
|
+
category=category)
|
|
3144
|
+
|
|
3145
|
+
@staticmethod
|
|
3146
|
+
def _implementation_names_impl(implementation, base_ring, sparse):
|
|
3147
|
+
"""
|
|
3148
|
+
Only support ``implementation=None`` and ``sparse=False``.
|
|
3149
|
+
|
|
3150
|
+
TESTS::
|
|
3151
|
+
|
|
3152
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_field_generic
|
|
3153
|
+
sage: PolynomialRing_dense_padic_field_generic._implementation_names_impl(None, Qp(2), False) # needs sage.rings.padics
|
|
3154
|
+
[None]
|
|
3155
|
+
sage: PolynomialRing_dense_padic_field_generic._implementation_names_impl(None, Qp(2), True) # needs sage.rings.padics
|
|
3156
|
+
NotImplemented
|
|
3157
|
+
sage: PolynomialRing_dense_padic_field_generic._implementation_names_impl("generic", Qp(2), False) # needs sage.rings.padics
|
|
3158
|
+
NotImplemented
|
|
3159
|
+
"""
|
|
3160
|
+
if implementation is None and not sparse:
|
|
3161
|
+
return [None] # Not a "generic" implementation
|
|
3162
|
+
return NotImplemented
|
|
3163
|
+
|
|
3164
|
+
|
|
3165
|
+
class PolynomialRing_dense_padic_ring_capped_relative(PolynomialRing_dense_padic_ring_generic):
|
|
3166
|
+
def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None):
|
|
3167
|
+
"""
|
|
3168
|
+
TESTS::
|
|
3169
|
+
|
|
3170
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_ring_capped_relative as PRing
|
|
3171
|
+
sage: R = PRing(Zp(13), name='t'); R # needs sage.rings.padics
|
|
3172
|
+
Univariate Polynomial Ring in t over 13-adic Ring with capped relative precision 20
|
|
3173
|
+
sage: type(R.gen()) # needs sage.rings.padics
|
|
3174
|
+
<class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_padic_ring_capped_relative_with_category.element_class'>
|
|
3175
|
+
"""
|
|
3176
|
+
if element_class is None:
|
|
3177
|
+
from sage.rings.polynomial.padics.\
|
|
3178
|
+
polynomial_padic_capped_relative_dense import \
|
|
3179
|
+
Polynomial_padic_capped_relative_dense
|
|
3180
|
+
element_class = Polynomial_padic_capped_relative_dense
|
|
3181
|
+
PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name,
|
|
3182
|
+
implementation=implementation,
|
|
3183
|
+
element_class=element_class, category=category)
|
|
3184
|
+
|
|
3185
|
+
|
|
3186
|
+
class PolynomialRing_dense_padic_ring_capped_absolute(PolynomialRing_dense_padic_ring_generic):
|
|
3187
|
+
def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None):
|
|
3188
|
+
"""
|
|
3189
|
+
TESTS::
|
|
3190
|
+
|
|
3191
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_ring_capped_absolute as PRing
|
|
3192
|
+
sage: R = PRing(Zp(13, type='capped-abs'), name='t'); R # needs sage.rings.padics
|
|
3193
|
+
Univariate Polynomial Ring in t over 13-adic Ring with capped absolute precision 20
|
|
3194
|
+
sage: type(R.gen()) # needs sage.rings.padics
|
|
3195
|
+
<class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_padic_ring_capped_absolute_with_category.element_class'>
|
|
3196
|
+
"""
|
|
3197
|
+
if element_class is None:
|
|
3198
|
+
from sage.rings.polynomial.padics.polynomial_padic_flat import \
|
|
3199
|
+
Polynomial_padic_flat
|
|
3200
|
+
element_class = Polynomial_padic_flat
|
|
3201
|
+
PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name,
|
|
3202
|
+
implementation=implementation,
|
|
3203
|
+
element_class=element_class, category=category)
|
|
3204
|
+
|
|
3205
|
+
|
|
3206
|
+
class PolynomialRing_dense_padic_ring_fixed_mod(PolynomialRing_dense_padic_ring_generic):
|
|
3207
|
+
def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None):
|
|
3208
|
+
"""
|
|
3209
|
+
TESTS::
|
|
3210
|
+
|
|
3211
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_ring_fixed_mod as PRing
|
|
3212
|
+
sage: R = PRing(Zp(13, type='fixed-mod'), name='t'); R # needs sage.rings.padics
|
|
3213
|
+
Univariate Polynomial Ring in t over 13-adic Ring of fixed modulus 13^20
|
|
3214
|
+
|
|
3215
|
+
sage: type(R.gen()) # needs sage.rings.padics
|
|
3216
|
+
<class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_padic_ring_fixed_mod_with_category.element_class'>
|
|
3217
|
+
"""
|
|
3218
|
+
if element_class is None:
|
|
3219
|
+
from sage.rings.polynomial.padics.polynomial_padic_flat import \
|
|
3220
|
+
Polynomial_padic_flat
|
|
3221
|
+
element_class = Polynomial_padic_flat
|
|
3222
|
+
PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name,
|
|
3223
|
+
implementation=implementation,
|
|
3224
|
+
element_class=element_class, category=category)
|
|
3225
|
+
|
|
3226
|
+
|
|
3227
|
+
class PolynomialRing_dense_padic_field_capped_relative(PolynomialRing_dense_padic_field_generic):
|
|
3228
|
+
def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None):
|
|
3229
|
+
"""
|
|
3230
|
+
TESTS::
|
|
3231
|
+
|
|
3232
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_field_capped_relative as PRing
|
|
3233
|
+
sage: R = PRing(Qp(13), name='t'); R # needs sage.rings.padics
|
|
3234
|
+
Univariate Polynomial Ring in t over 13-adic Field with capped relative precision 20
|
|
3235
|
+
sage: type(R.gen()) # needs sage.rings.padics
|
|
3236
|
+
<class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_padic_field_capped_relative_with_category.element_class'>
|
|
3237
|
+
"""
|
|
3238
|
+
if element_class is None:
|
|
3239
|
+
from sage.rings.polynomial.padics.\
|
|
3240
|
+
polynomial_padic_capped_relative_dense import \
|
|
3241
|
+
Polynomial_padic_capped_relative_dense
|
|
3242
|
+
element_class = Polynomial_padic_capped_relative_dense
|
|
3243
|
+
PolynomialRing_dense_padic_field_generic.__init__(self, base_ring, name=name,
|
|
3244
|
+
implementation=implementation,
|
|
3245
|
+
element_class=element_class, category=category)
|
|
3246
|
+
|
|
3247
|
+
|
|
3248
|
+
class PolynomialRing_dense_mod_n(PolynomialRing_commutative):
|
|
3249
|
+
def __init__(self, base_ring, name=None, element_class=None,
|
|
3250
|
+
implementation=None, category=None):
|
|
3251
|
+
"""
|
|
3252
|
+
TESTS::
|
|
3253
|
+
|
|
3254
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_mod_n as PRing
|
|
3255
|
+
sage: R = PRing(Zmod(15), 'x'); R
|
|
3256
|
+
Univariate Polynomial Ring in x over Ring of integers modulo 15
|
|
3257
|
+
sage: type(R.gen()) # needs sage.libs.flint
|
|
3258
|
+
<class 'sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint'>
|
|
3259
|
+
|
|
3260
|
+
sage: R = PRing(Zmod(15), 'x', implementation='NTL'); R # needs sage.libs.ntl
|
|
3261
|
+
Univariate Polynomial Ring in x over Ring of integers modulo 15 (using NTL)
|
|
3262
|
+
sage: type(R.gen()) # needs sage.libs.ntl
|
|
3263
|
+
<class 'sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_modn_ntl_zz'>
|
|
3264
|
+
|
|
3265
|
+
sage: R = PRing(Zmod(2**63*3), 'x', implementation='NTL'); R # needs sage.libs.ntl
|
|
3266
|
+
Univariate Polynomial Ring in x over Ring of integers modulo 27670116110564327424 (using NTL)
|
|
3267
|
+
sage: type(R.gen()) # needs sage.libs.ntl
|
|
3268
|
+
<class 'sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_modn_ntl_ZZ'>
|
|
3269
|
+
|
|
3270
|
+
sage: R = PRing(Zmod(2**63*3), 'x', implementation='FLINT')
|
|
3271
|
+
Traceback (most recent call last):
|
|
3272
|
+
...
|
|
3273
|
+
ValueError: FLINT does not support modulus 27670116110564327424
|
|
3274
|
+
|
|
3275
|
+
sage: R = PRing(Zmod(2**63*3), 'x'); R # needs sage.libs.ntl
|
|
3276
|
+
Univariate Polynomial Ring in x over Ring of integers modulo 27670116110564327424 (using NTL)
|
|
3277
|
+
sage: type(R.gen()) # needs sage.libs.ntl
|
|
3278
|
+
<class 'sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_modn_ntl_ZZ'>
|
|
3279
|
+
"""
|
|
3280
|
+
if element_class is None:
|
|
3281
|
+
self._implementation_repr = ''
|
|
3282
|
+
given_implementation = implementation
|
|
3283
|
+
for implementation in self._implementation_names(implementation, base_ring):
|
|
3284
|
+
if implementation == "FLINT":
|
|
3285
|
+
try:
|
|
3286
|
+
from .polynomial_zmod_flint import Polynomial_zmod_flint as element_class
|
|
3287
|
+
except ImportError:
|
|
3288
|
+
if given_implementation:
|
|
3289
|
+
raise
|
|
3290
|
+
continue
|
|
3291
|
+
self._implementation_repr = ''
|
|
3292
|
+
elif implementation == "NTL":
|
|
3293
|
+
modulus = base_ring.order()
|
|
3294
|
+
try:
|
|
3295
|
+
from . import polynomial_modn_dense_ntl as modn_dense_ntl
|
|
3296
|
+
except ImportError:
|
|
3297
|
+
if given_implementation:
|
|
3298
|
+
raise
|
|
3299
|
+
continue
|
|
3300
|
+
if modulus < ZZ(modn_dense_ntl.zz_p_max):
|
|
3301
|
+
element_class = modn_dense_ntl.Polynomial_dense_modn_ntl_zz
|
|
3302
|
+
else:
|
|
3303
|
+
element_class = modn_dense_ntl.Polynomial_dense_modn_ntl_ZZ
|
|
3304
|
+
self._implementation_repr = ' (using NTL)'
|
|
3305
|
+
break
|
|
3306
|
+
|
|
3307
|
+
PolynomialRing_commutative.__init__(self, base_ring, name=name, implementation=implementation,
|
|
3308
|
+
element_class=element_class, category=category)
|
|
3309
|
+
|
|
3310
|
+
@staticmethod
|
|
3311
|
+
def _implementation_names_impl(implementation, base_ring, sparse):
|
|
3312
|
+
"""
|
|
3313
|
+
TESTS::
|
|
3314
|
+
|
|
3315
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_mod_n
|
|
3316
|
+
sage: PolynomialRing_dense_mod_n._implementation_names_impl("FLINT", IntegerModRing(10), False)
|
|
3317
|
+
['FLINT', None]
|
|
3318
|
+
sage: PolynomialRing_dense_mod_n._implementation_names_impl("NTL", IntegerModRing(10), False)
|
|
3319
|
+
['NTL']
|
|
3320
|
+
sage: PolynomialRing_dense_mod_n._implementation_names_impl(None, IntegerModRing(10), False)
|
|
3321
|
+
['FLINT', None]
|
|
3322
|
+
sage: PolynomialRing_dense_mod_n._implementation_names_impl("generic", IntegerModRing(10), False)
|
|
3323
|
+
NotImplemented
|
|
3324
|
+
sage: PolynomialRing_dense_mod_n._implementation_names_impl("FLINT", IntegerModRing(10^30), False)
|
|
3325
|
+
Traceback (most recent call last):
|
|
3326
|
+
...
|
|
3327
|
+
ValueError: FLINT does not support modulus 1000000000000000000000000000000
|
|
3328
|
+
sage: PolynomialRing_dense_mod_n._implementation_names_impl("NTL", IntegerModRing(10^30), False)
|
|
3329
|
+
['NTL', None]
|
|
3330
|
+
sage: PolynomialRing_dense_mod_n._implementation_names_impl(None, IntegerModRing(10^30), False)
|
|
3331
|
+
['NTL', None]
|
|
3332
|
+
sage: PolynomialRing_dense_mod_n._implementation_names_impl("generic", IntegerModRing(10^30), False)
|
|
3333
|
+
NotImplemented
|
|
3334
|
+
sage: PolynomialRing_dense_mod_n._implementation_names_impl(None, IntegerModRing(10^30), True)
|
|
3335
|
+
NotImplemented
|
|
3336
|
+
"""
|
|
3337
|
+
if sparse:
|
|
3338
|
+
return NotImplemented
|
|
3339
|
+
modulus = base_ring.order()
|
|
3340
|
+
if modulus <= sys.maxsize:
|
|
3341
|
+
defaults = ["FLINT", None]
|
|
3342
|
+
elif implementation == "FLINT":
|
|
3343
|
+
raise ValueError("FLINT does not support modulus %s" % modulus)
|
|
3344
|
+
else:
|
|
3345
|
+
defaults = ["NTL", None]
|
|
3346
|
+
if implementation in defaults:
|
|
3347
|
+
return defaults
|
|
3348
|
+
elif implementation == "NTL":
|
|
3349
|
+
return [implementation]
|
|
3350
|
+
return NotImplemented
|
|
3351
|
+
|
|
3352
|
+
@cached_method
|
|
3353
|
+
def modulus(self):
|
|
3354
|
+
"""
|
|
3355
|
+
EXAMPLES::
|
|
3356
|
+
|
|
3357
|
+
sage: R.<x> = Zmod(15)[]
|
|
3358
|
+
sage: R.modulus()
|
|
3359
|
+
15
|
|
3360
|
+
"""
|
|
3361
|
+
return self.base_ring().characteristic()
|
|
3362
|
+
|
|
3363
|
+
def _repr_(self):
|
|
3364
|
+
"""
|
|
3365
|
+
TESTS::
|
|
3366
|
+
|
|
3367
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_integral_domain as PRing
|
|
3368
|
+
sage: R = PRing(ZZ, 'x', implementation='NTL'); R # needs sage.libs.ntl
|
|
3369
|
+
Univariate Polynomial Ring in x over Integer Ring (using NTL)
|
|
3370
|
+
"""
|
|
3371
|
+
s = PolynomialRing_commutative._repr_(self)
|
|
3372
|
+
return s + self._implementation_repr
|
|
3373
|
+
|
|
3374
|
+
def residue_field(self, ideal, names=None):
|
|
3375
|
+
"""
|
|
3376
|
+
Return the residue finite field at the given ideal.
|
|
3377
|
+
|
|
3378
|
+
EXAMPLES::
|
|
3379
|
+
|
|
3380
|
+
sage: # needs sage.libs.ntl sage.libs.pari
|
|
3381
|
+
sage: R.<t> = GF(2)[]
|
|
3382
|
+
sage: k.<a> = R.residue_field(t^3 + t + 1); k
|
|
3383
|
+
Residue field in a
|
|
3384
|
+
of Principal ideal (t^3 + t + 1) of Univariate Polynomial Ring in t
|
|
3385
|
+
over Finite Field of size 2 (using GF2X)
|
|
3386
|
+
sage: k.list()
|
|
3387
|
+
[0, a, a^2, a + 1, a^2 + a, a^2 + a + 1, a^2 + 1, 1]
|
|
3388
|
+
sage: R.residue_field(t)
|
|
3389
|
+
Residue field of Principal ideal (t) of Univariate Polynomial Ring in t
|
|
3390
|
+
over Finite Field of size 2 (using GF2X)
|
|
3391
|
+
sage: P = R.irreducible_element(8) * R
|
|
3392
|
+
sage: P
|
|
3393
|
+
Principal ideal (t^8 + t^4 + t^3 + t^2 + 1) of Univariate Polynomial Ring in t
|
|
3394
|
+
over Finite Field of size 2 (using GF2X)
|
|
3395
|
+
sage: k.<a> = R.residue_field(P); k
|
|
3396
|
+
Residue field in a
|
|
3397
|
+
of Principal ideal (t^8 + t^4 + t^3 + t^2 + 1) of Univariate Polynomial Ring in t
|
|
3398
|
+
over Finite Field of size 2 (using GF2X)
|
|
3399
|
+
sage: k.cardinality()
|
|
3400
|
+
256
|
|
3401
|
+
|
|
3402
|
+
Non-maximal ideals are not accepted::
|
|
3403
|
+
|
|
3404
|
+
sage: # needs sage.libs.ntl sage.libs.pari
|
|
3405
|
+
sage: R.residue_field(t^2 + 1)
|
|
3406
|
+
Traceback (most recent call last):
|
|
3407
|
+
...
|
|
3408
|
+
ArithmeticError: ideal is not maximal
|
|
3409
|
+
sage: R.residue_field(0)
|
|
3410
|
+
Traceback (most recent call last):
|
|
3411
|
+
...
|
|
3412
|
+
ArithmeticError: ideal is not maximal
|
|
3413
|
+
sage: R.residue_field(1)
|
|
3414
|
+
Traceback (most recent call last):
|
|
3415
|
+
...
|
|
3416
|
+
ArithmeticError: ideal is not maximal
|
|
3417
|
+
"""
|
|
3418
|
+
ideal = self.ideal(ideal)
|
|
3419
|
+
if not ideal.is_maximal():
|
|
3420
|
+
raise ArithmeticError("ideal is not maximal")
|
|
3421
|
+
return ideal.residue_field(names)
|
|
3422
|
+
|
|
3423
|
+
|
|
3424
|
+
class PolynomialRing_dense_mod_p(PolynomialRing_dense_finite_field,
|
|
3425
|
+
PolynomialRing_dense_mod_n,
|
|
3426
|
+
PolynomialRing_singular_repr):
|
|
3427
|
+
def __init__(self, base_ring, name='x', implementation=None, element_class=None, category=None):
|
|
3428
|
+
"""
|
|
3429
|
+
TESTS::
|
|
3430
|
+
|
|
3431
|
+
sage: P = GF(2)['x']; P # needs sage.libs.ntl
|
|
3432
|
+
Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X)
|
|
3433
|
+
sage: type(P.gen()) # needs sage.libs.ntl
|
|
3434
|
+
<class 'sage.rings.polynomial.polynomial_gf2x.Polynomial_GF2X'>
|
|
3435
|
+
|
|
3436
|
+
sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_mod_p
|
|
3437
|
+
sage: P = PolynomialRing_dense_mod_p(GF(5), 'x'); P
|
|
3438
|
+
Univariate Polynomial Ring in x over Finite Field of size 5
|
|
3439
|
+
sage: type(P.gen()) # needs sage.libs.flint
|
|
3440
|
+
<class 'sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint'>
|
|
3441
|
+
|
|
3442
|
+
sage: # needs sage.libs.ntl
|
|
3443
|
+
sage: P = PolynomialRing_dense_mod_p(GF(5), 'x', implementation='NTL'); P
|
|
3444
|
+
Univariate Polynomial Ring in x over Finite Field of size 5 (using NTL)
|
|
3445
|
+
sage: type(P.gen())
|
|
3446
|
+
<class 'sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_mod_p'>
|
|
3447
|
+
|
|
3448
|
+
sage: P = PolynomialRing_dense_mod_p(GF(9223372036854775837), 'x'); P # needs sage.libs.ntl sage.rings.finite_rings
|
|
3449
|
+
Univariate Polynomial Ring in x over Finite Field of size 9223372036854775837 (using NTL)
|
|
3450
|
+
sage: type(P.gen()) # needs sage.libs.ntl sage.rings.finite_rings
|
|
3451
|
+
<class 'sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_mod_p'>
|
|
3452
|
+
|
|
3453
|
+
This caching bug was fixed in :issue:`24264`::
|
|
3454
|
+
|
|
3455
|
+
sage: # needs sage.rings.finite_rings
|
|
3456
|
+
sage: p = 2^64 + 13
|
|
3457
|
+
sage: A = GF(p^2)
|
|
3458
|
+
sage: B = GF(p^3)
|
|
3459
|
+
sage: R = A.modulus().parent()
|
|
3460
|
+
sage: S = B.modulus().parent()
|
|
3461
|
+
sage: R is S
|
|
3462
|
+
True
|
|
3463
|
+
"""
|
|
3464
|
+
if element_class is None:
|
|
3465
|
+
given_implementation = implementation
|
|
3466
|
+
for implementation in self._implementation_names(implementation, base_ring):
|
|
3467
|
+
if implementation == "FLINT":
|
|
3468
|
+
try:
|
|
3469
|
+
from .polynomial_zmod_flint import Polynomial_zmod_flint as element_class
|
|
3470
|
+
except ImportError:
|
|
3471
|
+
if given_implementation:
|
|
3472
|
+
raise
|
|
3473
|
+
continue
|
|
3474
|
+
self._implementation_repr = ''
|
|
3475
|
+
elif implementation == "NTL":
|
|
3476
|
+
try:
|
|
3477
|
+
from .polynomial_modn_dense_ntl import Polynomial_dense_mod_p as element_class
|
|
3478
|
+
except ImportError:
|
|
3479
|
+
if given_implementation:
|
|
3480
|
+
raise
|
|
3481
|
+
continue
|
|
3482
|
+
self._implementation_repr = ' (using NTL)'
|
|
3483
|
+
elif implementation == "GF2X":
|
|
3484
|
+
try:
|
|
3485
|
+
from .polynomial_gf2x import Polynomial_GF2X as element_class
|
|
3486
|
+
except ImportError:
|
|
3487
|
+
if given_implementation:
|
|
3488
|
+
raise
|
|
3489
|
+
continue
|
|
3490
|
+
self._implementation_repr = ' (using GF2X)'
|
|
3491
|
+
break
|
|
3492
|
+
|
|
3493
|
+
category = check_default_category(PrincipalIdealDomains(),
|
|
3494
|
+
category)
|
|
3495
|
+
|
|
3496
|
+
PolynomialRing_dense_mod_n.__init__(self, base_ring, name=name, implementation=implementation,
|
|
3497
|
+
element_class=element_class, category=category)
|
|
3498
|
+
|
|
3499
|
+
self._has_singular = can_convert_to_singular(self)
|
|
3500
|
+
|
|
3501
|
+
@staticmethod
|
|
3502
|
+
def _implementation_names_impl(implementation, base_ring, sparse):
|
|
3503
|
+
"""
|
|
3504
|
+
TESTS::
|
|
3505
|
+
|
|
3506
|
+
sage: # needs sage.libs.ntl
|
|
3507
|
+
sage: PolynomialRing(GF(2), 'x', implementation='GF2X')
|
|
3508
|
+
Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X)
|
|
3509
|
+
sage: PolynomialRing(GF(2), 'x', implementation='NTL')
|
|
3510
|
+
Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X)
|
|
3511
|
+
sage: PolynomialRing(GF(2), 'x', implementation=None)
|
|
3512
|
+
Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X)
|
|
3513
|
+
sage: PolynomialRing(GF(3), 'x', implementation='GF2X')
|
|
3514
|
+
Traceback (most recent call last):
|
|
3515
|
+
...
|
|
3516
|
+
ValueError: GF2X only supports modulus 2
|
|
3517
|
+
sage: A = PolynomialRing(Zmod(2), 'x'); A
|
|
3518
|
+
Univariate Polynomial Ring in x over Ring of integers modulo 2 (using GF2X)
|
|
3519
|
+
sage: A in PrincipalIdealDomains()
|
|
3520
|
+
True
|
|
3521
|
+
|
|
3522
|
+
sage: PolynomialRing(GF(2), 'x', implementation="FLINT") # needs sage.libs.flint
|
|
3523
|
+
Univariate Polynomial Ring in x over Finite Field of size 2
|
|
3524
|
+
"""
|
|
3525
|
+
if sparse:
|
|
3526
|
+
return NotImplemented
|
|
3527
|
+
modulus = base_ring.characteristic()
|
|
3528
|
+
if modulus == 2:
|
|
3529
|
+
defaults = ["GF2X", "NTL", None]
|
|
3530
|
+
elif implementation == "GF2X":
|
|
3531
|
+
raise ValueError("GF2X only supports modulus 2")
|
|
3532
|
+
elif modulus <= sys.maxsize:
|
|
3533
|
+
defaults = ["FLINT", None]
|
|
3534
|
+
elif implementation == "FLINT":
|
|
3535
|
+
raise ValueError("FLINT does not support modulus %s" % modulus)
|
|
3536
|
+
else:
|
|
3537
|
+
defaults = ["NTL", None]
|
|
3538
|
+
if implementation in defaults:
|
|
3539
|
+
return defaults
|
|
3540
|
+
elif implementation in ["NTL", "FLINT"]:
|
|
3541
|
+
return [implementation]
|
|
3542
|
+
return NotImplemented
|
|
3543
|
+
|
|
3544
|
+
def irreducible_element(self, n, algorithm=None):
|
|
3545
|
+
"""
|
|
3546
|
+
Construct a monic irreducible polynomial of degree `n`.
|
|
3547
|
+
|
|
3548
|
+
INPUT:
|
|
3549
|
+
|
|
3550
|
+
- ``n`` -- integer; the degree of the polynomial to construct
|
|
3551
|
+
|
|
3552
|
+
- ``algorithm`` -- string (algorithm to use) or ``None``;
|
|
3553
|
+
currently available options are:
|
|
3554
|
+
|
|
3555
|
+
- ``'adleman-lenstra'``: a variant of the Adleman--Lenstra
|
|
3556
|
+
algorithm as implemented in PARI.
|
|
3557
|
+
|
|
3558
|
+
- ``'conway'``: look up the Conway polynomial of degree `n`
|
|
3559
|
+
over the field of `p` elements in the database; raise a
|
|
3560
|
+
:exc:`RuntimeError` if it is not found.
|
|
3561
|
+
|
|
3562
|
+
- ``'ffprimroot'``: use the :pari:`ffprimroot` function from
|
|
3563
|
+
PARI.
|
|
3564
|
+
|
|
3565
|
+
- ``'first_lexicographic'``: return the lexicographically
|
|
3566
|
+
smallest irreducible polynomial of degree `n`.
|
|
3567
|
+
|
|
3568
|
+
- ``'minimal_weight'``: return an irreducible polynomial of
|
|
3569
|
+
degree `n` with minimal number of non-zero coefficients.
|
|
3570
|
+
Only implemented for `p = 2`.
|
|
3571
|
+
|
|
3572
|
+
- ``'primitive'``: return a polynomial `f` such that a root of
|
|
3573
|
+
`f` generates the multiplicative group of the finite field
|
|
3574
|
+
extension defined by `f`. This uses the Conway polynomial if
|
|
3575
|
+
possible, otherwise it uses ``'ffprimroot'``.
|
|
3576
|
+
|
|
3577
|
+
- ``'random'``: try random polynomials until an irreducible
|
|
3578
|
+
one is found.
|
|
3579
|
+
|
|
3580
|
+
If ``algorithm`` is ``None``, use `x - 1` in degree 1. In
|
|
3581
|
+
degree > 1, the Conway polynomial is used if it is found in
|
|
3582
|
+
the database. Otherwise, the algorithm ``minimal_weight``
|
|
3583
|
+
is used if `p = 2`, and the algorithm ``'adleman-lenstra'`` if
|
|
3584
|
+
`p > 2`.
|
|
3585
|
+
|
|
3586
|
+
OUTPUT: a monic irreducible polynomial of degree `n` in ``self``
|
|
3587
|
+
|
|
3588
|
+
EXAMPLES::
|
|
3589
|
+
|
|
3590
|
+
sage: # needs sage.rings.finite_rings
|
|
3591
|
+
sage: GF(5)['x'].irreducible_element(2)
|
|
3592
|
+
x^2 + 4*x + 2
|
|
3593
|
+
sage: GF(5)['x'].irreducible_element(2, algorithm='adleman-lenstra')
|
|
3594
|
+
x^2 + x + 1
|
|
3595
|
+
sage: GF(5)['x'].irreducible_element(2, algorithm='primitive')
|
|
3596
|
+
x^2 + 4*x + 2
|
|
3597
|
+
sage: GF(5)['x'].irreducible_element(32, algorithm='first_lexicographic')
|
|
3598
|
+
x^32 + 2
|
|
3599
|
+
sage: GF(5)['x'].irreducible_element(32, algorithm='conway')
|
|
3600
|
+
Traceback (most recent call last):
|
|
3601
|
+
...
|
|
3602
|
+
RuntimeError: requested Conway polynomial not in database.
|
|
3603
|
+
sage: GF(5)['x'].irreducible_element(32, algorithm='primitive')
|
|
3604
|
+
x^32 + ...
|
|
3605
|
+
|
|
3606
|
+
In characteristic 2::
|
|
3607
|
+
|
|
3608
|
+
sage: GF(2)['x'].irreducible_element(33) # needs sage.rings.finite_rings
|
|
3609
|
+
x^33 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^3 + 1
|
|
3610
|
+
sage: GF(2)['x'].irreducible_element(33, algorithm='minimal_weight') # needs sage.libs.ntl sage.rings.finite_rings
|
|
3611
|
+
x^33 + x^10 + 1
|
|
3612
|
+
|
|
3613
|
+
In degree 1::
|
|
3614
|
+
|
|
3615
|
+
sage: GF(97)['x'].irreducible_element(1) # needs sage.rings.finite_rings
|
|
3616
|
+
x + 96
|
|
3617
|
+
sage: GF(97)['x'].irreducible_element(1, algorithm='conway') # needs sage.rings.finite_rings
|
|
3618
|
+
x + 92
|
|
3619
|
+
sage: GF(97)['x'].irreducible_element(1, algorithm='adleman-lenstra') # needs sage.rings.finite_rings
|
|
3620
|
+
x
|
|
3621
|
+
|
|
3622
|
+
AUTHORS:
|
|
3623
|
+
|
|
3624
|
+
- Peter Bruin (June 2013)
|
|
3625
|
+
|
|
3626
|
+
- Jeroen Demeyer (September 2014): add "ffprimroot" algorithm,
|
|
3627
|
+
see :issue:`8373`.
|
|
3628
|
+
"""
|
|
3629
|
+
from sage.libs.pari import pari
|
|
3630
|
+
from sage.rings.finite_rings.conway_polynomials import (conway_polynomial,
|
|
3631
|
+
exists_conway_polynomial)
|
|
3632
|
+
|
|
3633
|
+
p = self.characteristic()
|
|
3634
|
+
n = int(n)
|
|
3635
|
+
if n < 1:
|
|
3636
|
+
raise ValueError("degree must be at least 1")
|
|
3637
|
+
|
|
3638
|
+
if algorithm is None:
|
|
3639
|
+
if n == 1:
|
|
3640
|
+
return self((-1,1)) # Polynomial x - 1
|
|
3641
|
+
elif exists_conway_polynomial(p, n):
|
|
3642
|
+
algorithm = "conway"
|
|
3643
|
+
elif p == 2:
|
|
3644
|
+
try:
|
|
3645
|
+
from .polynomial_gf2x import GF2X_BuildSparseIrred_list
|
|
3646
|
+
except ImportError:
|
|
3647
|
+
algorithm = "adleman-lenstra"
|
|
3648
|
+
else:
|
|
3649
|
+
algorithm = "minimal_weight"
|
|
3650
|
+
else:
|
|
3651
|
+
algorithm = "adleman-lenstra"
|
|
3652
|
+
elif algorithm == "primitive":
|
|
3653
|
+
if exists_conway_polynomial(p, n):
|
|
3654
|
+
algorithm = "conway"
|
|
3655
|
+
else:
|
|
3656
|
+
algorithm = "ffprimroot"
|
|
3657
|
+
|
|
3658
|
+
if algorithm == "adleman-lenstra":
|
|
3659
|
+
return self(pari(p).ffinit(n))
|
|
3660
|
+
elif algorithm == "conway":
|
|
3661
|
+
return self(conway_polynomial(p, n))
|
|
3662
|
+
elif algorithm == "first_lexicographic":
|
|
3663
|
+
if p == 2:
|
|
3664
|
+
try:
|
|
3665
|
+
from .polynomial_gf2x import GF2X_BuildIrred_list
|
|
3666
|
+
except ImportError:
|
|
3667
|
+
pass
|
|
3668
|
+
else:
|
|
3669
|
+
return self(GF2X_BuildIrred_list(n))
|
|
3670
|
+
else:
|
|
3671
|
+
# Fallback to PolynomialRing_dense_finite_field.irreducible_element
|
|
3672
|
+
pass
|
|
3673
|
+
elif algorithm == "ffprimroot":
|
|
3674
|
+
return self(pari(p).ffinit(n).ffgen().ffprimroot().charpoly())
|
|
3675
|
+
elif algorithm == "minimal_weight":
|
|
3676
|
+
if p == 2:
|
|
3677
|
+
from .polynomial_gf2x import GF2X_BuildSparseIrred_list
|
|
3678
|
+
return self(GF2X_BuildSparseIrred_list(n))
|
|
3679
|
+
else:
|
|
3680
|
+
raise NotImplementedError("'minimal_weight' option only implemented for p = 2")
|
|
3681
|
+
elif algorithm == "random":
|
|
3682
|
+
if p == 2:
|
|
3683
|
+
try:
|
|
3684
|
+
from .polynomial_gf2x import GF2X_BuildRandomIrred_list
|
|
3685
|
+
except ImportError:
|
|
3686
|
+
pass
|
|
3687
|
+
else:
|
|
3688
|
+
return self(GF2X_BuildRandomIrred_list(n))
|
|
3689
|
+
else:
|
|
3690
|
+
pass
|
|
3691
|
+
|
|
3692
|
+
# No suitable algorithm found, try algorithms from the base class.
|
|
3693
|
+
return PolynomialRing_dense_finite_field.irreducible_element(self, n, algorithm)
|
|
3694
|
+
|
|
3695
|
+
@cached_method
|
|
3696
|
+
def fraction_field(self):
|
|
3697
|
+
"""
|
|
3698
|
+
Return the fraction field of ``self``.
|
|
3699
|
+
|
|
3700
|
+
EXAMPLES::
|
|
3701
|
+
|
|
3702
|
+
sage: R.<t> = GF(5)[]
|
|
3703
|
+
sage: R.fraction_field()
|
|
3704
|
+
Fraction Field of Univariate Polynomial Ring in t
|
|
3705
|
+
over Finite Field of size 5
|
|
3706
|
+
"""
|
|
3707
|
+
try:
|
|
3708
|
+
from sage.rings.fraction_field_FpT import FpT
|
|
3709
|
+
from sage.rings.polynomial.polynomial_zmod_flint import Polynomial_zmod_flint
|
|
3710
|
+
except ImportError:
|
|
3711
|
+
pass
|
|
3712
|
+
else:
|
|
3713
|
+
p = self.base_ring().characteristic()
|
|
3714
|
+
if (issubclass(self.element_class, Polynomial_zmod_flint)
|
|
3715
|
+
and 2 < p < FpT.INTEGER_LIMIT):
|
|
3716
|
+
return FpT(self)
|
|
3717
|
+
return super().fraction_field()
|
|
3718
|
+
|
|
3719
|
+
|
|
3720
|
+
def polygen(ring_or_element, name='x'):
|
|
3721
|
+
"""
|
|
3722
|
+
Return a polynomial indeterminate.
|
|
3723
|
+
|
|
3724
|
+
INPUT:
|
|
3725
|
+
|
|
3726
|
+
- ``polygen(base_ring, name='x')``
|
|
3727
|
+
|
|
3728
|
+
- ``polygen(ring_element, name='x')``
|
|
3729
|
+
|
|
3730
|
+
If the first input is a ring, return a polynomial generator over
|
|
3731
|
+
that ring. If it is a ring element, return a polynomial generator
|
|
3732
|
+
over the parent of the element.
|
|
3733
|
+
|
|
3734
|
+
EXAMPLES::
|
|
3735
|
+
|
|
3736
|
+
sage: z = polygen(QQ, 'z')
|
|
3737
|
+
sage: z^3 + z +1
|
|
3738
|
+
z^3 + z + 1
|
|
3739
|
+
sage: parent(z)
|
|
3740
|
+
Univariate Polynomial Ring in z over Rational Field
|
|
3741
|
+
|
|
3742
|
+
.. NOTE::
|
|
3743
|
+
|
|
3744
|
+
If you give a list or comma-separated string to :func:`polygen`, you'll
|
|
3745
|
+
get a tuple of indeterminates, exactly as if you called
|
|
3746
|
+
:func:`polygens`.
|
|
3747
|
+
"""
|
|
3748
|
+
if isinstance(ring_or_element, RingElement):
|
|
3749
|
+
base_ring = ring_or_element.parent()
|
|
3750
|
+
elif ring_or_element in Rings():
|
|
3751
|
+
base_ring = ring_or_element
|
|
3752
|
+
else:
|
|
3753
|
+
raise TypeError("input must be a ring or ring element")
|
|
3754
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
3755
|
+
|
|
3756
|
+
t = PolynomialRing(base_ring, name)
|
|
3757
|
+
if t.ngens() > 1:
|
|
3758
|
+
return t.gens()
|
|
3759
|
+
return t.gen()
|
|
3760
|
+
|
|
3761
|
+
|
|
3762
|
+
def polygens(base_ring, names='x', *args):
|
|
3763
|
+
"""
|
|
3764
|
+
Return indeterminates over the given base ring with the given
|
|
3765
|
+
names.
|
|
3766
|
+
|
|
3767
|
+
EXAMPLES::
|
|
3768
|
+
|
|
3769
|
+
sage: x,y,z = polygens(QQ,'x,y,z')
|
|
3770
|
+
sage: (x+y+z)^2
|
|
3771
|
+
x^2 + 2*x*y + y^2 + 2*x*z + 2*y*z + z^2
|
|
3772
|
+
sage: parent(x)
|
|
3773
|
+
Multivariate Polynomial Ring in x, y, z over Rational Field
|
|
3774
|
+
sage: t = polygens(QQ, ['x','yz','abc'])
|
|
3775
|
+
sage: t
|
|
3776
|
+
(x, yz, abc)
|
|
3777
|
+
|
|
3778
|
+
The number of generators can be passed as a third argument::
|
|
3779
|
+
|
|
3780
|
+
sage: polygens(QQ, 'x', 4)
|
|
3781
|
+
(x0, x1, x2, x3)
|
|
3782
|
+
"""
|
|
3783
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
3784
|
+
return PolynomialRing(base_ring, names, *args).gens()
|