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,3082 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
r"""
|
|
3
|
+
Base class for elements of multivariate polynomial rings
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# ********************************************************************
|
|
7
|
+
# Copyright (C) 2005 William Stein <wstein@gmail.com>
|
|
8
|
+
#
|
|
9
|
+
# This program is free software: you can redistribute it and/or modify
|
|
10
|
+
# it under the terms of the GNU General Public License as published by
|
|
11
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
12
|
+
# (at your option) any later version.
|
|
13
|
+
# https://www.gnu.org/licenses/
|
|
14
|
+
# ********************************************************************
|
|
15
|
+
from itertools import chain
|
|
16
|
+
|
|
17
|
+
from sage.rings.integer cimport Integer
|
|
18
|
+
from sage.rings.integer_ring import ZZ
|
|
19
|
+
from sage.structure.coerce cimport coercion_model
|
|
20
|
+
from sage.misc.derivative import multi_derivative
|
|
21
|
+
from sage.misc.misc_c import prod
|
|
22
|
+
from sage.misc.superseded import deprecated_function_alias
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def is_MPolynomial(x):
|
|
26
|
+
from sage.misc.superseded import deprecation
|
|
27
|
+
deprecation(32709, "the function is_MPolynomial is deprecated; use isinstance(x, sage.rings.polynomial.multi_polynomial.MPolynomial) instead")
|
|
28
|
+
|
|
29
|
+
return isinstance(x, MPolynomial)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
33
|
+
from sage.categories.map cimport Map
|
|
34
|
+
from sage.rings.rational_field import QQ
|
|
35
|
+
|
|
36
|
+
from sage.rings.polynomial.polydict cimport ETuple
|
|
37
|
+
from sage.rings.polynomial.polynomial_element cimport Polynomial
|
|
38
|
+
|
|
39
|
+
cdef class MPolynomial(CommutativePolynomial):
|
|
40
|
+
|
|
41
|
+
# -------------------------
|
|
42
|
+
# Some standard conversions
|
|
43
|
+
# -------------------------
|
|
44
|
+
def _scalar_conversion(self, R):
|
|
45
|
+
r"""
|
|
46
|
+
TESTS::
|
|
47
|
+
|
|
48
|
+
sage: # needs sage.rings.real_mpfr
|
|
49
|
+
sage: ZZ(RR['x,y'](0)) # indirect doctest
|
|
50
|
+
0
|
|
51
|
+
sage: ZZ(RR['x,y'](0.5))
|
|
52
|
+
Traceback (most recent call last):
|
|
53
|
+
...
|
|
54
|
+
TypeError: Attempt to coerce non-integral RealNumber to Integer
|
|
55
|
+
sage: ZZ(RR['x,y'].gen(0))
|
|
56
|
+
Traceback (most recent call last):
|
|
57
|
+
...
|
|
58
|
+
TypeError: unable to convert non-constant polynomial x to Integer Ring
|
|
59
|
+
|
|
60
|
+
sage: # needs sage.rings.real_mpfr
|
|
61
|
+
sage: RR(RR['x,y'](0)) # indirect doctest
|
|
62
|
+
0.000000000000000
|
|
63
|
+
sage: RR(ZZ['x,y'].gen(0))
|
|
64
|
+
Traceback (most recent call last):
|
|
65
|
+
...
|
|
66
|
+
TypeError: unable to convert non-constant polynomial x to Real Field with 53 bits of precision
|
|
67
|
+
|
|
68
|
+
sage: # needs sage.rings.real_mpfr
|
|
69
|
+
sage: CC(RR['x,y'](0)) # indirect doctest
|
|
70
|
+
0.000000000000000
|
|
71
|
+
sage: CC(ZZ['x,y'].gen(0))
|
|
72
|
+
Traceback (most recent call last):
|
|
73
|
+
...
|
|
74
|
+
TypeError: unable to convert non-constant polynomial x to Complex Field with 53 bits of precision
|
|
75
|
+
|
|
76
|
+
sage: # needs sage.rings.real_mpfr
|
|
77
|
+
sage: RDF(RR['x,y'](0))
|
|
78
|
+
0.0
|
|
79
|
+
sage: RDF(ZZ['x,y'].gen(0))
|
|
80
|
+
Traceback (most recent call last):
|
|
81
|
+
...
|
|
82
|
+
TypeError: unable to convert non-constant polynomial x to Real Double Field
|
|
83
|
+
|
|
84
|
+
sage: # needs sage.rings.real_mpfr
|
|
85
|
+
sage: CDF(RR['x,y'](0)) # indirect doctest
|
|
86
|
+
0.0
|
|
87
|
+
sage: CDF(ZZ['x,y'].gen(0))
|
|
88
|
+
Traceback (most recent call last):
|
|
89
|
+
...
|
|
90
|
+
TypeError: unable to convert non-constant polynomial x to Complex Double Field
|
|
91
|
+
|
|
92
|
+
sage: # needs sage.libs.flint sage.rings.real_mpfr
|
|
93
|
+
sage: a = RR['x,y'](1)
|
|
94
|
+
sage: RBF(a)
|
|
95
|
+
1.000000000000000
|
|
96
|
+
sage: RIF(a)
|
|
97
|
+
1
|
|
98
|
+
sage: CBF(a)
|
|
99
|
+
1.000000000000000
|
|
100
|
+
sage: CIF(a)
|
|
101
|
+
1
|
|
102
|
+
sage: CBF(RR['x,y'](1)) # indirect doctest
|
|
103
|
+
1.000000000000000
|
|
104
|
+
sage: CBF(ZZ['x,y'].gen(0))
|
|
105
|
+
Traceback (most recent call last):
|
|
106
|
+
...
|
|
107
|
+
TypeError: unable to convert non-constant polynomial x to Complex ball field with 53 bits of precision
|
|
108
|
+
|
|
109
|
+
sage: x = polygen(QQ)
|
|
110
|
+
sage: A.<u> = NumberField(x^3 - 2) # needs sage.rings.number_field
|
|
111
|
+
sage: A(A['x,y'](u)) # needs sage.rings.number_field
|
|
112
|
+
u
|
|
113
|
+
"""
|
|
114
|
+
if self.degree() <= 0:
|
|
115
|
+
return R(self.constant_coefficient())
|
|
116
|
+
raise TypeError(f"unable to convert non-constant polynomial {self} to {R}")
|
|
117
|
+
|
|
118
|
+
_real_double_ = _scalar_conversion
|
|
119
|
+
_complex_double_ = _scalar_conversion
|
|
120
|
+
_mpfr_ = _scalar_conversion
|
|
121
|
+
_complex_mpfr_ = _scalar_conversion
|
|
122
|
+
_real_mpfi_ = _scalar_conversion
|
|
123
|
+
_complex_mpfi_ = _scalar_conversion
|
|
124
|
+
_arb_ = _scalar_conversion
|
|
125
|
+
_acb_ = _scalar_conversion
|
|
126
|
+
_integer_ = _scalar_conversion
|
|
127
|
+
_algebraic_ = _scalar_conversion
|
|
128
|
+
_number_field_ = _scalar_conversion
|
|
129
|
+
|
|
130
|
+
def __int__(self):
|
|
131
|
+
r"""
|
|
132
|
+
TESTS::
|
|
133
|
+
|
|
134
|
+
sage: type(RR['x,y'])
|
|
135
|
+
<class 'sage.rings.polynomial.multi_polynomial_ring.MPolynomialRing_polydict_domain_with_category'>
|
|
136
|
+
sage: type(RR['x, y'](0))
|
|
137
|
+
<class 'sage.rings.polynomial.multi_polynomial_element.MPolynomial_polydict'>
|
|
138
|
+
|
|
139
|
+
sage: int(RR['x,y'](0)) # indirect doctest
|
|
140
|
+
0
|
|
141
|
+
sage: int(RR['x,y'](10))
|
|
142
|
+
10
|
|
143
|
+
sage: int(ZZ['x,y'].gen(0))
|
|
144
|
+
Traceback (most recent call last):
|
|
145
|
+
...
|
|
146
|
+
TypeError: unable to convert non-constant polynomial x to <class 'int'>
|
|
147
|
+
|
|
148
|
+
sage: ZZ(RR['x,y'](0)) # indirect doctest
|
|
149
|
+
0
|
|
150
|
+
sage: ZZ(RR['x,y'](0.5)) # needs sage.rings.real_mpfr
|
|
151
|
+
Traceback (most recent call last):
|
|
152
|
+
...
|
|
153
|
+
TypeError: Attempt to coerce non-integral RealNumber to Integer
|
|
154
|
+
sage: ZZ(RR['x,y'].gen(0))
|
|
155
|
+
Traceback (most recent call last):
|
|
156
|
+
...
|
|
157
|
+
TypeError: unable to convert non-constant polynomial x to Integer Ring
|
|
158
|
+
"""
|
|
159
|
+
return self._scalar_conversion(int)
|
|
160
|
+
|
|
161
|
+
def __float__(self):
|
|
162
|
+
r"""
|
|
163
|
+
TESTS::
|
|
164
|
+
|
|
165
|
+
sage: float(RR['x,y'](0)) # indirect doctest
|
|
166
|
+
0.0
|
|
167
|
+
sage: float(ZZ['x,y'].gen(0))
|
|
168
|
+
Traceback (most recent call last):
|
|
169
|
+
...
|
|
170
|
+
TypeError: unable to convert non-constant polynomial x to <class 'float'>
|
|
171
|
+
"""
|
|
172
|
+
return self._scalar_conversion(float)
|
|
173
|
+
|
|
174
|
+
def _rational_(self):
|
|
175
|
+
r"""
|
|
176
|
+
TESTS::
|
|
177
|
+
|
|
178
|
+
sage: QQ(RR['x,y'](0.5)) # indirect doctest
|
|
179
|
+
1/2
|
|
180
|
+
sage: QQ(RR['x,y'].gen(0))
|
|
181
|
+
Traceback (most recent call last):
|
|
182
|
+
...
|
|
183
|
+
TypeError: unable to convert non-constant polynomial x to Rational Field
|
|
184
|
+
"""
|
|
185
|
+
from sage.rings.rational_field import QQ
|
|
186
|
+
return self._scalar_conversion(QQ)
|
|
187
|
+
|
|
188
|
+
def _symbolic_(self, R):
|
|
189
|
+
r"""
|
|
190
|
+
EXAMPLES::
|
|
191
|
+
|
|
192
|
+
sage: # needs sage.symbolic
|
|
193
|
+
sage: R.<x,y> = QQ[]
|
|
194
|
+
sage: f = x^3 + y
|
|
195
|
+
sage: g = f._symbolic_(SR); g
|
|
196
|
+
x^3 + y
|
|
197
|
+
sage: g(x=2, y=2)
|
|
198
|
+
10
|
|
199
|
+
sage: g = SR(f)
|
|
200
|
+
sage: g(x=2, y=2)
|
|
201
|
+
10
|
|
202
|
+
"""
|
|
203
|
+
d = dict([(repr(g), R.var(g)) for g in self.parent().gens()])
|
|
204
|
+
return self.subs(**d)
|
|
205
|
+
|
|
206
|
+
def _polynomial_(self, R):
|
|
207
|
+
var = R.variable_name()
|
|
208
|
+
if var in self._parent.variable_names():
|
|
209
|
+
return R(self.polynomial(self._parent(var)))
|
|
210
|
+
return R([self])
|
|
211
|
+
|
|
212
|
+
def leading_support(self, *args, **kwds):
|
|
213
|
+
r"""
|
|
214
|
+
Return the maximal element of the support of ``self``,
|
|
215
|
+
according to the term order.
|
|
216
|
+
|
|
217
|
+
If the term ordering of the basis elements is not what is
|
|
218
|
+
desired, a comparison key, ``key(x)``, can be provided.
|
|
219
|
+
|
|
220
|
+
EXAMPLES::
|
|
221
|
+
|
|
222
|
+
sage: R.<x,y,z> = PolynomialRing(QQ)
|
|
223
|
+
sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_support()
|
|
224
|
+
(0, 4, 0)
|
|
225
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, order='lex')
|
|
226
|
+
sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_support()
|
|
227
|
+
(1, 2, 0)
|
|
228
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, order='invlex')
|
|
229
|
+
sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_support()
|
|
230
|
+
(0, 1, 3)
|
|
231
|
+
"""
|
|
232
|
+
if 'key' in kwds:
|
|
233
|
+
return max(self.support(), *args, **kwds)
|
|
234
|
+
kwds['key'] = self._parent.term_order().sortkey
|
|
235
|
+
return max(self.support(), *args, **kwds)
|
|
236
|
+
|
|
237
|
+
def trailing_support(self, *args, **kwds):
|
|
238
|
+
r"""
|
|
239
|
+
Return the minimal element of the support of ``self``,
|
|
240
|
+
according to the term order.
|
|
241
|
+
|
|
242
|
+
If the term ordering of the basis elements is not what is
|
|
243
|
+
desired, a comparison key, ``key(x)``, can be provided.
|
|
244
|
+
|
|
245
|
+
EXAMPLES::
|
|
246
|
+
|
|
247
|
+
sage: R.<x,y,z> = PolynomialRing(QQ)
|
|
248
|
+
sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_support()
|
|
249
|
+
(1, 1, 1)
|
|
250
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, order='lex')
|
|
251
|
+
sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_support()
|
|
252
|
+
(0, 1, 3)
|
|
253
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, order='invlex')
|
|
254
|
+
sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_support()
|
|
255
|
+
(1, 2, 0)
|
|
256
|
+
"""
|
|
257
|
+
if 'key' in kwds:
|
|
258
|
+
return min(self.support(), *args, **kwds)
|
|
259
|
+
kwds['key'] = self._parent.term_order().sortkey
|
|
260
|
+
return min(self.support(), *args, **kwds)
|
|
261
|
+
|
|
262
|
+
def coefficients(self):
|
|
263
|
+
r"""
|
|
264
|
+
Return the nonzero coefficients of this polynomial in a list.
|
|
265
|
+
|
|
266
|
+
The returned list is decreasingly ordered by the term ordering
|
|
267
|
+
of ``self.parent()``, i.e. the list of coefficients matches the list
|
|
268
|
+
of monomials returned by
|
|
269
|
+
:meth:`sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular.monomials`.
|
|
270
|
+
|
|
271
|
+
EXAMPLES::
|
|
272
|
+
|
|
273
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, 3, order='degrevlex')
|
|
274
|
+
sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z
|
|
275
|
+
sage: f.coefficients()
|
|
276
|
+
[23, 6, 1]
|
|
277
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, 3, order='lex')
|
|
278
|
+
sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z
|
|
279
|
+
sage: f.coefficients()
|
|
280
|
+
[6, 23, 1]
|
|
281
|
+
|
|
282
|
+
Test the same stuff with base ring `\ZZ` -- different implementation::
|
|
283
|
+
|
|
284
|
+
sage: R.<x,y,z> = PolynomialRing(ZZ, 3, order='degrevlex')
|
|
285
|
+
sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z
|
|
286
|
+
sage: f.coefficients()
|
|
287
|
+
[23, 6, 1]
|
|
288
|
+
sage: R.<x,y,z> = PolynomialRing(ZZ, 3, order='lex')
|
|
289
|
+
sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z
|
|
290
|
+
sage: f.coefficients()
|
|
291
|
+
[6, 23, 1]
|
|
292
|
+
|
|
293
|
+
AUTHOR:
|
|
294
|
+
|
|
295
|
+
- Didier Deshommes
|
|
296
|
+
"""
|
|
297
|
+
d = self.monomial_coefficients()
|
|
298
|
+
return [d[i] for i in self.exponents()]
|
|
299
|
+
|
|
300
|
+
def truncate(self, var, n):
|
|
301
|
+
r"""
|
|
302
|
+
Return a new multivariate polynomial obtained from ``self`` by
|
|
303
|
+
deleting all terms that involve the given variable to a power
|
|
304
|
+
at least ``n``.
|
|
305
|
+
"""
|
|
306
|
+
cdef int ind
|
|
307
|
+
R = self.parent()
|
|
308
|
+
G = R.gens()
|
|
309
|
+
Z = list(G)
|
|
310
|
+
try:
|
|
311
|
+
ind = Z.index(var)
|
|
312
|
+
except ValueError:
|
|
313
|
+
raise ValueError("var must be one of the generators of the parent polynomial ring.")
|
|
314
|
+
return R({k: c for k, c in self.monomial_coefficients().items()
|
|
315
|
+
if k[ind] < n})
|
|
316
|
+
|
|
317
|
+
def _fast_callable_(self, etb):
|
|
318
|
+
r"""
|
|
319
|
+
Given an :class:`ExpressionTreeBuilder`, return an :class:`Expression` representing
|
|
320
|
+
this value.
|
|
321
|
+
|
|
322
|
+
EXAMPLES::
|
|
323
|
+
|
|
324
|
+
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
|
|
325
|
+
sage: etb = ExpressionTreeBuilder(vars=['x','y','z'])
|
|
326
|
+
sage: K.<x,y,z> = QQ[]
|
|
327
|
+
sage: v = -6/5*x*y*z + 2*y*z^2 - x
|
|
328
|
+
sage: v._fast_callable_(etb)
|
|
329
|
+
add(add(add(0, mul(-6/5, mul(mul(ipow(v_0, 1), ipow(v_1, 1)), ipow(v_2, 1)))), mul(2, mul(ipow(v_1, 1), ipow(v_2, 2)))), mul(-1, ipow(v_0, 1)))
|
|
330
|
+
|
|
331
|
+
TESTS::
|
|
332
|
+
|
|
333
|
+
sage: v = K(0)
|
|
334
|
+
sage: vf = fast_callable(v)
|
|
335
|
+
sage: type(v(0r, 0r, 0r))
|
|
336
|
+
<class 'sage.rings.rational.Rational'>
|
|
337
|
+
sage: type(vf(0r, 0r, 0r))
|
|
338
|
+
<class 'sage.rings.rational.Rational'>
|
|
339
|
+
sage: K.<x,y,z> = QQ[]
|
|
340
|
+
sage: from sage.ext.fast_eval import fast_float
|
|
341
|
+
sage: fast_float(K(0)).op_list()
|
|
342
|
+
[('load_const', 0.0), 'return']
|
|
343
|
+
sage: fast_float(K(17)).op_list()
|
|
344
|
+
[('load_const', 0.0), ('load_const', 17.0), 'add', 'return']
|
|
345
|
+
sage: fast_float(y).op_list()
|
|
346
|
+
[('load_const', 0.0), ('load_const', 1.0), ('load_arg', 1), ('ipow', 1), 'mul', 'add', 'return']
|
|
347
|
+
"""
|
|
348
|
+
my_vars = self.parent().variable_names()
|
|
349
|
+
x = [etb.var(v) for v in my_vars]
|
|
350
|
+
n = len(x)
|
|
351
|
+
|
|
352
|
+
expr = etb.constant(self.base_ring().zero())
|
|
353
|
+
for m, c in self.monomial_coefficients().items():
|
|
354
|
+
monom = prod([x[i] ** m[i] for i in range(n) if m[i] != 0],
|
|
355
|
+
etb.constant(c))
|
|
356
|
+
expr = expr + monom
|
|
357
|
+
return expr
|
|
358
|
+
|
|
359
|
+
def derivative(self, *args):
|
|
360
|
+
r"""
|
|
361
|
+
The formal derivative of this polynomial, with respect to
|
|
362
|
+
variables supplied in ``args``.
|
|
363
|
+
|
|
364
|
+
Multiple variables and iteration counts may be supplied; see
|
|
365
|
+
documentation for the global function :func:`derivative` for more details.
|
|
366
|
+
|
|
367
|
+
.. SEEALSO:: :meth:`._derivative`
|
|
368
|
+
|
|
369
|
+
EXAMPLES:
|
|
370
|
+
|
|
371
|
+
Polynomials implemented via Singular::
|
|
372
|
+
|
|
373
|
+
sage: # needs sage.libs.singular
|
|
374
|
+
sage: R.<x, y> = PolynomialRing(FiniteField(5))
|
|
375
|
+
sage: f = x^3*y^5 + x^7*y
|
|
376
|
+
sage: type(f)
|
|
377
|
+
<class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>
|
|
378
|
+
sage: f.derivative(x)
|
|
379
|
+
2*x^6*y - 2*x^2*y^5
|
|
380
|
+
sage: f.derivative(y)
|
|
381
|
+
x^7
|
|
382
|
+
|
|
383
|
+
Generic multivariate polynomials::
|
|
384
|
+
|
|
385
|
+
sage: R.<t> = PowerSeriesRing(QQ)
|
|
386
|
+
sage: S.<x, y> = PolynomialRing(R)
|
|
387
|
+
sage: f = (t^2 + O(t^3))*x^2*y^3 + (37*t^4 + O(t^5))*x^3
|
|
388
|
+
sage: type(f)
|
|
389
|
+
<class 'sage.rings.polynomial.multi_polynomial_element.MPolynomial_polydict'>
|
|
390
|
+
sage: f.derivative(x) # with respect to x
|
|
391
|
+
(2*t^2 + O(t^3))*x*y^3 + (111*t^4 + O(t^5))*x^2
|
|
392
|
+
sage: f.derivative(y) # with respect to y
|
|
393
|
+
(3*t^2 + O(t^3))*x^2*y^2
|
|
394
|
+
sage: f.derivative(t) # with respect to t (recurses into base ring)
|
|
395
|
+
(2*t + O(t^2))*x^2*y^3 + (148*t^3 + O(t^4))*x^3
|
|
396
|
+
sage: f.derivative(x, y) # with respect to x and then y
|
|
397
|
+
(6*t^2 + O(t^3))*x*y^2
|
|
398
|
+
sage: f.derivative(y, 3) # with respect to y three times
|
|
399
|
+
(6*t^2 + O(t^3))*x^2
|
|
400
|
+
sage: f.derivative() # can't figure out the variable
|
|
401
|
+
Traceback (most recent call last):
|
|
402
|
+
...
|
|
403
|
+
ValueError: must specify which variable to differentiate with respect to
|
|
404
|
+
|
|
405
|
+
Polynomials over the symbolic ring (just for fun....)::
|
|
406
|
+
|
|
407
|
+
sage: # needs sage.symbolic
|
|
408
|
+
sage: x = var("x")
|
|
409
|
+
sage: S.<u, v> = PolynomialRing(SR)
|
|
410
|
+
sage: f = u*v*x
|
|
411
|
+
sage: f.derivative(x) == u*v
|
|
412
|
+
True
|
|
413
|
+
sage: f.derivative(u) == v*x
|
|
414
|
+
True
|
|
415
|
+
"""
|
|
416
|
+
return multi_derivative(self, args)
|
|
417
|
+
|
|
418
|
+
def polynomial(self, var):
|
|
419
|
+
r"""
|
|
420
|
+
Let ``var`` be one of the variables of the parent of ``self``. This
|
|
421
|
+
returns ``self`` viewed as a univariate polynomial in ``var`` over the
|
|
422
|
+
polynomial ring generated by all the other variables of the parent.
|
|
423
|
+
|
|
424
|
+
EXAMPLES::
|
|
425
|
+
|
|
426
|
+
sage: R.<x,w,z> = QQ[]
|
|
427
|
+
sage: f = x^3 + 3*w*x + w^5 + (17*w^3)*x + z^5
|
|
428
|
+
sage: f.polynomial(x)
|
|
429
|
+
x^3 + (17*w^3 + 3*w)*x + w^5 + z^5
|
|
430
|
+
sage: parent(f.polynomial(x))
|
|
431
|
+
Univariate Polynomial Ring in x
|
|
432
|
+
over Multivariate Polynomial Ring in w, z over Rational Field
|
|
433
|
+
|
|
434
|
+
sage: f.polynomial(w)
|
|
435
|
+
w^5 + 17*x*w^3 + 3*x*w + z^5 + x^3
|
|
436
|
+
sage: f.polynomial(z)
|
|
437
|
+
z^5 + w^5 + 17*x*w^3 + x^3 + 3*x*w
|
|
438
|
+
sage: R.<x,w,z,k> = ZZ[]
|
|
439
|
+
sage: f = x^3 + 3*w*x + w^5 + (17*w^3)*x + z^5 +x*w*z*k + 5
|
|
440
|
+
sage: f.polynomial(x)
|
|
441
|
+
x^3 + (17*w^3 + w*z*k + 3*w)*x + w^5 + z^5 + 5
|
|
442
|
+
sage: f.polynomial(w)
|
|
443
|
+
w^5 + 17*x*w^3 + (x*z*k + 3*x)*w + z^5 + x^3 + 5
|
|
444
|
+
sage: f.polynomial(z)
|
|
445
|
+
z^5 + x*w*k*z + w^5 + 17*x*w^3 + x^3 + 3*x*w + 5
|
|
446
|
+
sage: f.polynomial(k)
|
|
447
|
+
x*w*z*k + w^5 + z^5 + 17*x*w^3 + x^3 + 3*x*w + 5
|
|
448
|
+
sage: R.<x,y> = GF(5)[]
|
|
449
|
+
sage: f = x^2 + x + y
|
|
450
|
+
sage: f.polynomial(x)
|
|
451
|
+
x^2 + x + y
|
|
452
|
+
sage: f.polynomial(y)
|
|
453
|
+
y + x^2 + x
|
|
454
|
+
"""
|
|
455
|
+
cdef int ind
|
|
456
|
+
R = self._parent
|
|
457
|
+
cdef list Z = list(R.gens())
|
|
458
|
+
cdef Py_ssize_t i
|
|
459
|
+
cdef dict c, w
|
|
460
|
+
cdef list v
|
|
461
|
+
try:
|
|
462
|
+
ind = Z.index(var)
|
|
463
|
+
except ValueError:
|
|
464
|
+
raise ValueError("var must be one of the generators of the parent polynomial ring")
|
|
465
|
+
|
|
466
|
+
if len(Z) <= 1:
|
|
467
|
+
return self.univariate_polynomial()
|
|
468
|
+
|
|
469
|
+
del Z[ind]
|
|
470
|
+
|
|
471
|
+
# Make polynomial ring over all variables except var.
|
|
472
|
+
S = PolynomialRing(R.base_ring(), Z)
|
|
473
|
+
ring = S[var]
|
|
474
|
+
if not self:
|
|
475
|
+
return ring(0)
|
|
476
|
+
|
|
477
|
+
d = self.degree(var)
|
|
478
|
+
B = ring.base_ring()
|
|
479
|
+
w = {remove_from_tuple(e, ind): val
|
|
480
|
+
for e, val in self.monomial_coefficients().items() if not e[ind]}
|
|
481
|
+
v = [B(w)] # coefficients that don't involve var
|
|
482
|
+
z = var
|
|
483
|
+
for i in range(1, d+1):
|
|
484
|
+
c = <dict> self.coefficient(z).monomial_coefficients()
|
|
485
|
+
w = {remove_from_tuple(e, ind): val for e, val in c.items()}
|
|
486
|
+
v.append(B(w))
|
|
487
|
+
z *= var
|
|
488
|
+
return ring(v)
|
|
489
|
+
|
|
490
|
+
cpdef dict _mpoly_dict_recursive(self, tuple vars=None, base_ring=None):
|
|
491
|
+
r"""
|
|
492
|
+
Return a ``dict`` of coefficient entries suitable for construction
|
|
493
|
+
of a ``MPolynomial_polydict`` with the given variables.
|
|
494
|
+
|
|
495
|
+
EXAMPLES::
|
|
496
|
+
|
|
497
|
+
sage: R = Integers(10)['x,y,z']['t,s']
|
|
498
|
+
sage: t,s = R.gens()
|
|
499
|
+
sage: x,y,z = R.base_ring().gens()
|
|
500
|
+
sage: (x+y+2*z*s+3*t)._mpoly_dict_recursive(('z','t','s'))
|
|
501
|
+
{(0, 0, 0): x + y, (0, 1, 0): 3, (1, 0, 1): 2}
|
|
502
|
+
|
|
503
|
+
TESTS::
|
|
504
|
+
|
|
505
|
+
sage: # needs sage.rings.padics
|
|
506
|
+
sage: R = Qp(7)['x,y,z,t,p']; S = ZZ['x,z,t']['p']
|
|
507
|
+
sage: R(S.0)
|
|
508
|
+
p
|
|
509
|
+
sage: R = QQ['x,y,z,t,p']; S = ZZ['x']['y,z,t']['p']
|
|
510
|
+
sage: z = S.base_ring().gen(1)
|
|
511
|
+
sage: R(z)
|
|
512
|
+
z
|
|
513
|
+
sage: R = QQ['x,y,z,t,p']; S = ZZ['x']['y,z,t']['p']
|
|
514
|
+
sage: z = S.base_ring().gen(1); p = S.0; x = S.base_ring().base_ring().gen()
|
|
515
|
+
sage: R(z+p)
|
|
516
|
+
z + p
|
|
517
|
+
sage: R = Qp(7)['x,y,z,p']; S = ZZ['x']['y,z,t']['p'] # shouldn't work, but should throw a better error
|
|
518
|
+
sage: R(S.0)
|
|
519
|
+
p
|
|
520
|
+
|
|
521
|
+
See :issue:`2601`::
|
|
522
|
+
|
|
523
|
+
sage: R.<a,b,c> = PolynomialRing(QQ, 3)
|
|
524
|
+
sage: a._mpoly_dict_recursive(('c', 'b', 'a'))
|
|
525
|
+
{(0, 0, 1): 1}
|
|
526
|
+
sage: testR.<a,b,c> = PolynomialRing(QQ,3)
|
|
527
|
+
sage: id_ringA = ideal([a^2 - b, b^2 - c, c^2 - a])
|
|
528
|
+
sage: id_ringB = ideal(id_ringA.gens()).change_ring(PolynomialRing(QQ,'c,b,a'))
|
|
529
|
+
"""
|
|
530
|
+
if not self:
|
|
531
|
+
return {}
|
|
532
|
+
|
|
533
|
+
if vars is None:
|
|
534
|
+
vars = self._parent.variable_names_recursive()
|
|
535
|
+
cdef tuple my_vars = self._parent.variable_names()
|
|
536
|
+
if vars == my_vars:
|
|
537
|
+
return <dict> self.monomial_coefficients()
|
|
538
|
+
elif my_vars[-1] not in vars:
|
|
539
|
+
x = base_ring(self) if base_ring is not None else self
|
|
540
|
+
const_ix = ETuple((0,)*len(vars))
|
|
541
|
+
return {const_ix: x}
|
|
542
|
+
elif not set(my_vars).issubset(set(vars)):
|
|
543
|
+
# we need to split it up
|
|
544
|
+
p = self.polynomial(self._parent.gen(len(my_vars)-1))
|
|
545
|
+
if not isinstance(p, MPolynomial):
|
|
546
|
+
# Not a multivariate polynomial, so it must be a univariate
|
|
547
|
+
return (<Polynomial> p)._mpoly_dict_recursive(vars, base_ring)
|
|
548
|
+
return (<MPolynomial> p)._mpoly_dict_recursive(vars, base_ring)
|
|
549
|
+
|
|
550
|
+
cdef dict D = {}
|
|
551
|
+
cdef list mapping = [vars.index(z) for z in my_vars]
|
|
552
|
+
cdef list new_map
|
|
553
|
+
cdef Py_ssize_t m = min(mapping)
|
|
554
|
+
cdef tuple prev_vars = vars[:m]
|
|
555
|
+
cdef list tmp
|
|
556
|
+
cdef ETuple postfix
|
|
557
|
+
cdef Py_ssize_t k
|
|
558
|
+
cdef dict mpoly
|
|
559
|
+
if prev_vars:
|
|
560
|
+
new_map = list(mapping)
|
|
561
|
+
for k in range(len(mapping)):
|
|
562
|
+
new_map[k] -= m
|
|
563
|
+
tmp = [0] * (len(vars) - m)
|
|
564
|
+
try:
|
|
565
|
+
for ix, a in self.monomial_coefficients().items():
|
|
566
|
+
for k in range(len(my_vars)):
|
|
567
|
+
tmp[new_map[k]] = ix[k]
|
|
568
|
+
postfix = ETuple(tmp)
|
|
569
|
+
mpoly = <dict> a._mpoly_dict_recursive(prev_vars, base_ring)
|
|
570
|
+
for prefix, b in mpoly.items():
|
|
571
|
+
D[prefix + postfix] = b
|
|
572
|
+
return D
|
|
573
|
+
|
|
574
|
+
except AttributeError:
|
|
575
|
+
pass
|
|
576
|
+
|
|
577
|
+
if base_ring is self.base_ring():
|
|
578
|
+
base_ring = None
|
|
579
|
+
|
|
580
|
+
tmp = [0] * len(vars)
|
|
581
|
+
for ix, a in self.monomial_coefficients().items():
|
|
582
|
+
for k in range(len(my_vars)):
|
|
583
|
+
tmp[mapping[k]] = ix[k]
|
|
584
|
+
if base_ring is not None:
|
|
585
|
+
a = base_ring(a)
|
|
586
|
+
D[ETuple(tmp)] = a
|
|
587
|
+
return D
|
|
588
|
+
|
|
589
|
+
cdef long _hash_c(self) except -1:
|
|
590
|
+
r"""
|
|
591
|
+
This hash incorporates the variable name in an effort to respect the obvious inclusions
|
|
592
|
+
into multi-variable polynomial rings.
|
|
593
|
+
|
|
594
|
+
The tuple algorithm is borrowed from http://effbot.org/zone/python-hash.htm.
|
|
595
|
+
|
|
596
|
+
EXAMPLES::
|
|
597
|
+
|
|
598
|
+
sage: T.<y>=QQ[]
|
|
599
|
+
sage: R.<x>=ZZ[]
|
|
600
|
+
sage: S.<x,y>=ZZ[]
|
|
601
|
+
sage: hash(S.0)==hash(R.0) # respect inclusions into mpoly rings (with matching base rings)
|
|
602
|
+
True
|
|
603
|
+
sage: hash(S.1)==hash(T.0) # respect inclusions into mpoly rings (with unmatched base rings)
|
|
604
|
+
True
|
|
605
|
+
sage: hash(S(12))==hash(12) # respect inclusions of the integers into an mpoly ring
|
|
606
|
+
True
|
|
607
|
+
sage: # the point is to make for more flexible dictionary look ups
|
|
608
|
+
sage: d={S.0:12}
|
|
609
|
+
sage: d[R.0]
|
|
610
|
+
12
|
|
611
|
+
sage: # or, more to the point, make subs in fraction field elements work
|
|
612
|
+
sage: f=x/y
|
|
613
|
+
sage: f.subs({x:1})
|
|
614
|
+
1/y
|
|
615
|
+
|
|
616
|
+
TESTS:
|
|
617
|
+
|
|
618
|
+
Verify that :issue:`16251` has been resolved, i.e., polynomials with
|
|
619
|
+
unhashable coefficients are unhashable::
|
|
620
|
+
|
|
621
|
+
sage: K.<a> = Qq(9) # needs sage.rings.padics
|
|
622
|
+
sage: R.<t,s> = K[] # needs sage.rings.padics
|
|
623
|
+
sage: hash(t) # needs sage.rings.padics
|
|
624
|
+
Traceback (most recent call last):
|
|
625
|
+
...
|
|
626
|
+
TypeError: ...unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement'...
|
|
627
|
+
"""
|
|
628
|
+
cdef long result = 0 # store it in a c-int and just let the overflowing additions wrap
|
|
629
|
+
cdef long result_mon
|
|
630
|
+
var_name_hash = [hash(v) for v in self._parent.variable_names()]
|
|
631
|
+
cdef long c_hash
|
|
632
|
+
for m, c in self.monomial_coefficients().items():
|
|
633
|
+
# I'm assuming (incorrectly) that hashes of zero indicate that the element is 0.
|
|
634
|
+
# This assumption is not true, but I think it is true enough for the purposes and it
|
|
635
|
+
# it allows us to write fast code that omits terms with 0 coefficients. This is
|
|
636
|
+
# important if we want to maintain the '==' relationship with sparse polys.
|
|
637
|
+
c_hash = hash(c)
|
|
638
|
+
if c_hash != 0: # this is always going to be true, because we are sparse (correct?)
|
|
639
|
+
# Hash (self[i], gen_a, exp_a, gen_b, exp_b, gen_c, exp_c, ...) as a tuple according to the algorithm.
|
|
640
|
+
# I omit gen,exp pairs where the exponent is zero.
|
|
641
|
+
result_mon = c_hash
|
|
642
|
+
for p in m.nonzero_positions():
|
|
643
|
+
result_mon = (1000003 * result_mon) ^ var_name_hash[p]
|
|
644
|
+
result_mon = (1000003 * result_mon) ^ m[p]
|
|
645
|
+
result += result_mon
|
|
646
|
+
if result == -1:
|
|
647
|
+
return -2
|
|
648
|
+
return result
|
|
649
|
+
|
|
650
|
+
# you may have to replicate this boilerplate code in derived classes if you override
|
|
651
|
+
# __richcmp__. The python documentation at https://docs.python.org/api/type-structs.html
|
|
652
|
+
# explains how __richcmp__, __hash__, and __cmp__ are tied together.
|
|
653
|
+
def __hash__(self):
|
|
654
|
+
return self._hash_c()
|
|
655
|
+
|
|
656
|
+
def args(self):
|
|
657
|
+
r"""
|
|
658
|
+
Return the names of the arguments of ``self``, in the
|
|
659
|
+
order they are accepted from call.
|
|
660
|
+
|
|
661
|
+
EXAMPLES::
|
|
662
|
+
|
|
663
|
+
sage: R.<x,y> = ZZ[]
|
|
664
|
+
sage: x.args()
|
|
665
|
+
(x, y)
|
|
666
|
+
"""
|
|
667
|
+
return self._parent.gens()
|
|
668
|
+
|
|
669
|
+
def homogenize(self, var='h'):
|
|
670
|
+
r"""
|
|
671
|
+
Return the homogenization of this polynomial.
|
|
672
|
+
|
|
673
|
+
The polynomial itself is returned if it is homogeneous already.
|
|
674
|
+
Otherwise, the monomials are multiplied with the smallest powers of
|
|
675
|
+
``var`` such that they all have the same total degree.
|
|
676
|
+
|
|
677
|
+
INPUT:
|
|
678
|
+
|
|
679
|
+
- ``var`` -- a variable in the polynomial ring (as a string, an element of
|
|
680
|
+
the ring, or a zero-based index in the list of variables) or a name
|
|
681
|
+
for a new variable (default: ``'h'``)
|
|
682
|
+
|
|
683
|
+
OUTPUT:
|
|
684
|
+
|
|
685
|
+
If ``var`` specifies a variable in the polynomial ring, then a
|
|
686
|
+
homogeneous element in that ring is returned. Otherwise, a homogeneous
|
|
687
|
+
element is returned in a polynomial ring with an extra last variable
|
|
688
|
+
``var``.
|
|
689
|
+
|
|
690
|
+
EXAMPLES::
|
|
691
|
+
|
|
692
|
+
sage: R.<x,y> = QQ[]
|
|
693
|
+
sage: f = x^2 + y + 1 + 5*x*y^10
|
|
694
|
+
sage: f.homogenize()
|
|
695
|
+
5*x*y^10 + x^2*h^9 + y*h^10 + h^11
|
|
696
|
+
|
|
697
|
+
The parameter ``var`` can be used to specify the name of the variable::
|
|
698
|
+
|
|
699
|
+
sage: g = f.homogenize('z'); g
|
|
700
|
+
5*x*y^10 + x^2*z^9 + y*z^10 + z^11
|
|
701
|
+
sage: g.parent()
|
|
702
|
+
Multivariate Polynomial Ring in x, y, z over Rational Field
|
|
703
|
+
|
|
704
|
+
However, if the polynomial is homogeneous already, then that parameter
|
|
705
|
+
is ignored and no extra variable is added to the polynomial ring::
|
|
706
|
+
|
|
707
|
+
sage: f = x^2 + y^2
|
|
708
|
+
sage: g = f.homogenize('z'); g
|
|
709
|
+
x^2 + y^2
|
|
710
|
+
sage: g.parent()
|
|
711
|
+
Multivariate Polynomial Ring in x, y over Rational Field
|
|
712
|
+
|
|
713
|
+
If you want the ring of the result to be independent of whether the
|
|
714
|
+
polynomial is homogenized, you can use ``var`` to use an existing
|
|
715
|
+
variable to homogenize::
|
|
716
|
+
|
|
717
|
+
sage: R.<x,y,z> = QQ[]
|
|
718
|
+
sage: f = x^2 + y^2
|
|
719
|
+
sage: g = f.homogenize(z); g
|
|
720
|
+
x^2 + y^2
|
|
721
|
+
sage: g.parent()
|
|
722
|
+
Multivariate Polynomial Ring in x, y, z over Rational Field
|
|
723
|
+
sage: f = x^2 - y
|
|
724
|
+
sage: g = f.homogenize(z); g
|
|
725
|
+
x^2 - y*z
|
|
726
|
+
sage: g.parent()
|
|
727
|
+
Multivariate Polynomial Ring in x, y, z over Rational Field
|
|
728
|
+
|
|
729
|
+
The parameter ``var`` can also be given as a zero-based index in the
|
|
730
|
+
list of variables::
|
|
731
|
+
|
|
732
|
+
sage: g = f.homogenize(2); g
|
|
733
|
+
x^2 - y*z
|
|
734
|
+
|
|
735
|
+
If the variable specified by ``var`` is not present in the polynomial,
|
|
736
|
+
then setting it to 1 yields the original polynomial::
|
|
737
|
+
|
|
738
|
+
sage: g(x,y,1)
|
|
739
|
+
x^2 - y
|
|
740
|
+
|
|
741
|
+
If it is present already, this might not be the case::
|
|
742
|
+
|
|
743
|
+
sage: g = f.homogenize(x); g
|
|
744
|
+
x^2 - x*y
|
|
745
|
+
sage: g(1,y,z)
|
|
746
|
+
-y + 1
|
|
747
|
+
|
|
748
|
+
In particular, this can be surprising in positive characteristic::
|
|
749
|
+
|
|
750
|
+
sage: R.<x,y> = GF(2)[]
|
|
751
|
+
sage: f = x + 1
|
|
752
|
+
sage: f.homogenize(x)
|
|
753
|
+
0
|
|
754
|
+
|
|
755
|
+
TESTS::
|
|
756
|
+
|
|
757
|
+
sage: R = PolynomialRing(QQ, 'x', 5)
|
|
758
|
+
sage: p = R.random_element()
|
|
759
|
+
sage: q1 = p.homogenize()
|
|
760
|
+
sage: q2 = p.homogenize()
|
|
761
|
+
sage: q1.parent() is q2.parent()
|
|
762
|
+
True
|
|
763
|
+
"""
|
|
764
|
+
P = self.parent()
|
|
765
|
+
|
|
766
|
+
if self.is_homogeneous():
|
|
767
|
+
return self
|
|
768
|
+
|
|
769
|
+
if isinstance(var, str):
|
|
770
|
+
V = list(P.variable_names())
|
|
771
|
+
try:
|
|
772
|
+
i = V.index(var)
|
|
773
|
+
return self._homogenize(i)
|
|
774
|
+
except ValueError:
|
|
775
|
+
P = PolynomialRing(P.base_ring(), len(V)+1, V + [var], order=P.term_order())
|
|
776
|
+
return P(self)._homogenize(len(V))
|
|
777
|
+
|
|
778
|
+
elif isinstance(var, MPolynomial) and \
|
|
779
|
+
((<MPolynomial>var)._parent is P or (<MPolynomial>var)._parent == P):
|
|
780
|
+
V = list(P.gens())
|
|
781
|
+
try:
|
|
782
|
+
i = V.index(var)
|
|
783
|
+
return self._homogenize(i)
|
|
784
|
+
except ValueError:
|
|
785
|
+
P = P.change_ring(names=P.variable_names() + [str(var)])
|
|
786
|
+
return P(self)._homogenize(len(V))
|
|
787
|
+
|
|
788
|
+
elif isinstance(var, (int, Integer)):
|
|
789
|
+
if 0 <= var < P.ngens():
|
|
790
|
+
return self._homogenize(var)
|
|
791
|
+
else:
|
|
792
|
+
raise TypeError("Variable index %d must be < parent(self).ngens()." % var)
|
|
793
|
+
else:
|
|
794
|
+
raise TypeError("Parameter var must be either a variable, a string or an integer.")
|
|
795
|
+
|
|
796
|
+
def is_homogeneous(self):
|
|
797
|
+
r"""
|
|
798
|
+
Return ``True`` if ``self`` is a homogeneous polynomial.
|
|
799
|
+
|
|
800
|
+
TESTS::
|
|
801
|
+
|
|
802
|
+
sage: from sage.rings.polynomial.multi_polynomial import MPolynomial
|
|
803
|
+
sage: P.<x, y> = PolynomialRing(QQ, 2)
|
|
804
|
+
sage: MPolynomial.is_homogeneous(x+y)
|
|
805
|
+
True
|
|
806
|
+
sage: MPolynomial.is_homogeneous(P(0))
|
|
807
|
+
True
|
|
808
|
+
sage: MPolynomial.is_homogeneous(x+y^2)
|
|
809
|
+
False
|
|
810
|
+
sage: MPolynomial.is_homogeneous(x^2 + y^2)
|
|
811
|
+
True
|
|
812
|
+
sage: MPolynomial.is_homogeneous(x^2 + y^2*x)
|
|
813
|
+
False
|
|
814
|
+
sage: MPolynomial.is_homogeneous(x^2*y + y^2*x)
|
|
815
|
+
True
|
|
816
|
+
|
|
817
|
+
.. NOTE::
|
|
818
|
+
|
|
819
|
+
This is a generic implementation which is likely overridden by
|
|
820
|
+
subclasses.
|
|
821
|
+
"""
|
|
822
|
+
M = self.monomials()
|
|
823
|
+
if M == []:
|
|
824
|
+
return True
|
|
825
|
+
d = M.pop().degree()
|
|
826
|
+
for m in M:
|
|
827
|
+
if m.degree() != d:
|
|
828
|
+
return False
|
|
829
|
+
else:
|
|
830
|
+
return True
|
|
831
|
+
|
|
832
|
+
def homogeneous_components(self):
|
|
833
|
+
r"""
|
|
834
|
+
Return the homogeneous components of this polynomial.
|
|
835
|
+
|
|
836
|
+
OUTPUT: a dictionary mapping degrees to homogeneous polynomials
|
|
837
|
+
|
|
838
|
+
EXAMPLES::
|
|
839
|
+
|
|
840
|
+
sage: R.<x,y> = QQ[]
|
|
841
|
+
sage: (x^3 + 2*x*y^3 + 4*y^3 + y).homogeneous_components()
|
|
842
|
+
{1: y, 3: x^3 + 4*y^3, 4: 2*x*y^3}
|
|
843
|
+
sage: R.zero().homogeneous_components()
|
|
844
|
+
{}
|
|
845
|
+
|
|
846
|
+
In case of weighted term orders, the polynomials are homogeneous with
|
|
847
|
+
respect to the weights::
|
|
848
|
+
|
|
849
|
+
sage: S.<a,b,c> = PolynomialRing(ZZ, order=TermOrder('wdegrevlex', (1,2,3)))
|
|
850
|
+
sage: (a^6 + b^3 + b*c + a^2*c + c + a + 1).homogeneous_components()
|
|
851
|
+
{0: 1, 1: a, 3: c, 5: a^2*c + b*c, 6: a^6 + b^3}
|
|
852
|
+
"""
|
|
853
|
+
cdef ETuple e
|
|
854
|
+
from collections import defaultdict
|
|
855
|
+
d = defaultdict(dict)
|
|
856
|
+
if self._parent.term_order()._weights:
|
|
857
|
+
for c, m in self:
|
|
858
|
+
d[m.degree()][m.exponents()[0]] = c
|
|
859
|
+
else:
|
|
860
|
+
# Otherwise it is unweighted, so we use a faster implementation
|
|
861
|
+
for e, c in self.iterator_exp_coeff():
|
|
862
|
+
d[e.unweighted_degree()][e] = c
|
|
863
|
+
return {k: self._parent(d[k]) for k in d}
|
|
864
|
+
|
|
865
|
+
cpdef _mod_(self, other):
|
|
866
|
+
r"""
|
|
867
|
+
EXAMPLES::
|
|
868
|
+
|
|
869
|
+
sage: R.<x,y> = PolynomialRing(QQ)
|
|
870
|
+
sage: f = (x^2*y + 2*x - 3)
|
|
871
|
+
sage: g = (x + 1)*f
|
|
872
|
+
sage: g % f # needs sage.libs.singular
|
|
873
|
+
0
|
|
874
|
+
|
|
875
|
+
sage: (g+1) % f # needs sage.libs.singular
|
|
876
|
+
1
|
|
877
|
+
|
|
878
|
+
sage: M = x*y
|
|
879
|
+
sage: N = x^2*y^3
|
|
880
|
+
sage: M.divides(N) # needs sage.libs.singular
|
|
881
|
+
True
|
|
882
|
+
"""
|
|
883
|
+
try:
|
|
884
|
+
quo_rem = self.quo_rem
|
|
885
|
+
except AttributeError:
|
|
886
|
+
raise NotImplementedError
|
|
887
|
+
else:
|
|
888
|
+
_, r = quo_rem(other)
|
|
889
|
+
return r
|
|
890
|
+
|
|
891
|
+
def change_ring(self, R):
|
|
892
|
+
r"""
|
|
893
|
+
Return this polynomial with coefficients converted to ``R``.
|
|
894
|
+
|
|
895
|
+
INPUT:
|
|
896
|
+
|
|
897
|
+
- ``R`` -- a ring or morphism; if a morphism, the coefficients
|
|
898
|
+
are mapped to the codomain of ``R``
|
|
899
|
+
|
|
900
|
+
OUTPUT: a new polynomial with the base ring changed to ``R``
|
|
901
|
+
|
|
902
|
+
EXAMPLES::
|
|
903
|
+
|
|
904
|
+
sage: R.<x,y> = QQ[]
|
|
905
|
+
sage: f = x^3 + 3/5*y + 1
|
|
906
|
+
sage: f.change_ring(GF(7))
|
|
907
|
+
x^3 + 2*y + 1
|
|
908
|
+
sage: g = x^2 + 5*y
|
|
909
|
+
sage: g.change_ring(GF(5))
|
|
910
|
+
x^2
|
|
911
|
+
|
|
912
|
+
::
|
|
913
|
+
|
|
914
|
+
sage: # needs sage.rings.finite_rings
|
|
915
|
+
sage: R.<x,y> = GF(9,'a')[]
|
|
916
|
+
sage: (x+2*y).change_ring(GF(3))
|
|
917
|
+
x - y
|
|
918
|
+
|
|
919
|
+
::
|
|
920
|
+
|
|
921
|
+
sage: # needs sage.rings.finite_rings
|
|
922
|
+
sage: F.<a> = GF(7^2)
|
|
923
|
+
sage: R.<x,y> = F[]
|
|
924
|
+
sage: f = x^2 + a^2*y^2 + a*x + a^3*y
|
|
925
|
+
sage: g = f.change_ring(F.frobenius_endomorphism()); g
|
|
926
|
+
x^2 + (-a - 2)*y^2 + (-a + 1)*x + (2*a + 2)*y
|
|
927
|
+
sage: g.change_ring(F.frobenius_endomorphism()) == f
|
|
928
|
+
True
|
|
929
|
+
|
|
930
|
+
::
|
|
931
|
+
|
|
932
|
+
sage: # needs sage.rings.number_field
|
|
933
|
+
sage: K.<z> = CyclotomicField(3)
|
|
934
|
+
sage: R.<x,y> = K[]
|
|
935
|
+
sage: f = x^2 + z*y
|
|
936
|
+
sage: f.change_ring(K.embeddings(CC)[1])
|
|
937
|
+
x^2 + (-0.500000000000000 - 0.866025403784438*I)*y
|
|
938
|
+
|
|
939
|
+
::
|
|
940
|
+
|
|
941
|
+
sage: # needs sage.rings.number_field
|
|
942
|
+
sage: K.<w> = CyclotomicField(5)
|
|
943
|
+
sage: R.<x,y> = K[]
|
|
944
|
+
sage: f = x^2 + w*y
|
|
945
|
+
sage: f.change_ring(K.embeddings(QQbar)[1])
|
|
946
|
+
x^2 + (-0.8090169943749474? + 0.5877852522924731?*I)*y
|
|
947
|
+
|
|
948
|
+
TESTS:
|
|
949
|
+
|
|
950
|
+
Check that :issue:`25022` is fixed::
|
|
951
|
+
|
|
952
|
+
sage: # needs sage.rings.number_field sage.symbolic
|
|
953
|
+
sage: K.<x,y> = ZZ[]
|
|
954
|
+
sage: (x*y).change_ring(SR).monomials()
|
|
955
|
+
[x*y]
|
|
956
|
+
|
|
957
|
+
Check that :issue:`36832` is fixed::
|
|
958
|
+
|
|
959
|
+
sage: F = GF(11)
|
|
960
|
+
sage: phi = Hom(F,F).an_element()
|
|
961
|
+
sage: R.<x,y> = F[]
|
|
962
|
+
sage: x.change_ring(phi)
|
|
963
|
+
x
|
|
964
|
+
"""
|
|
965
|
+
if isinstance(R, Map):
|
|
966
|
+
return self.map_coefficients(R)
|
|
967
|
+
return self.parent().change_ring(R)(self.monomial_coefficients())
|
|
968
|
+
|
|
969
|
+
def is_symmetric(self, group=None):
|
|
970
|
+
r"""
|
|
971
|
+
Return whether this polynomial is symmetric.
|
|
972
|
+
|
|
973
|
+
INPUT:
|
|
974
|
+
|
|
975
|
+
- ``group`` -- (default: symmetric group) if set, test whether the
|
|
976
|
+
polynomial is invariant with respect to the given permutation group
|
|
977
|
+
|
|
978
|
+
EXAMPLES::
|
|
979
|
+
|
|
980
|
+
sage: # needs sage.groups
|
|
981
|
+
sage: R.<x,y,z> = QQ[]
|
|
982
|
+
sage: p = (x+y+z)**2 - 3 * (x+y)*(x+z)*(y+z)
|
|
983
|
+
sage: p.is_symmetric()
|
|
984
|
+
True
|
|
985
|
+
sage: (x + y - z).is_symmetric()
|
|
986
|
+
False
|
|
987
|
+
sage: R.one().is_symmetric()
|
|
988
|
+
True
|
|
989
|
+
sage: p = (x-y)*(y-z)*(z-x)
|
|
990
|
+
sage: p.is_symmetric()
|
|
991
|
+
False
|
|
992
|
+
sage: p.is_symmetric(AlternatingGroup(3))
|
|
993
|
+
True
|
|
994
|
+
|
|
995
|
+
sage: R.<x,y> = QQ[]
|
|
996
|
+
sage: ((x + y)**2).is_symmetric() # needs sage.groups
|
|
997
|
+
True
|
|
998
|
+
sage: R.one().is_symmetric() # needs sage.groups
|
|
999
|
+
True
|
|
1000
|
+
sage: (x + 2*y).is_symmetric() # needs sage.groups
|
|
1001
|
+
False
|
|
1002
|
+
|
|
1003
|
+
An example with a GAP permutation group (here the quaternions)::
|
|
1004
|
+
|
|
1005
|
+
sage: R = PolynomialRing(QQ, 'x', 8)
|
|
1006
|
+
sage: x = R.gens()
|
|
1007
|
+
sage: p = sum(prod(x[i] for i in e)
|
|
1008
|
+
....: for e in [(0,1,2), (0,1,7), (0,2,7), (1,2,7),
|
|
1009
|
+
....: (3,4,5), (3,4,6), (3,5,6), (4,5,6)])
|
|
1010
|
+
sage: p.is_symmetric(libgap.TransitiveGroup(8, 5)) # needs gap_pkg_transgrp sage.groups
|
|
1011
|
+
True
|
|
1012
|
+
sage: p = sum(prod(x[i] for i in e)
|
|
1013
|
+
....: for e in [(0,1,2), (0,1,7), (0,2,7), (1,2,7),
|
|
1014
|
+
....: (3,4,5), (3,4,6), (3,5,6)])
|
|
1015
|
+
sage: p.is_symmetric(libgap.TransitiveGroup(8, 5)) # needs gap_pkg_transgrp sage.groups
|
|
1016
|
+
False
|
|
1017
|
+
|
|
1018
|
+
TESTS::
|
|
1019
|
+
|
|
1020
|
+
sage: R = PolynomialRing(QQ, 'x', 3)
|
|
1021
|
+
sage: R.one().is_symmetric(3) # needs sage.groups
|
|
1022
|
+
Traceback (most recent call last):
|
|
1023
|
+
...
|
|
1024
|
+
ValueError: argument must be a permutation group
|
|
1025
|
+
|
|
1026
|
+
sage: R.one().is_symmetric(SymmetricGroup(4)) # needs sage.groups
|
|
1027
|
+
Traceback (most recent call last):
|
|
1028
|
+
...
|
|
1029
|
+
ValueError: invalid data to initialize a permutation
|
|
1030
|
+
"""
|
|
1031
|
+
n = self.parent().ngens()
|
|
1032
|
+
if n <= 1:
|
|
1033
|
+
return True
|
|
1034
|
+
|
|
1035
|
+
from sage.groups.perm_gps.permgroup_named import SymmetricGroup
|
|
1036
|
+
S = SymmetricGroup(n)
|
|
1037
|
+
if group is None:
|
|
1038
|
+
gens = S.gens()
|
|
1039
|
+
else:
|
|
1040
|
+
try:
|
|
1041
|
+
# for Sage group
|
|
1042
|
+
gens = group.gens()
|
|
1043
|
+
except AttributeError:
|
|
1044
|
+
# for GAP group
|
|
1045
|
+
try:
|
|
1046
|
+
gens = group.GeneratorsOfGroup()
|
|
1047
|
+
except AttributeError:
|
|
1048
|
+
raise ValueError("argument must be a permutation group")
|
|
1049
|
+
gens = [S(g) for g in gens]
|
|
1050
|
+
|
|
1051
|
+
cdef dict coeffs = self.monomial_coefficients()
|
|
1052
|
+
zero = self.base_ring().zero()
|
|
1053
|
+
return all(coeffs.get(g._act_on_etuple_on_position(e), zero) == coeff
|
|
1054
|
+
for e, coeff in coeffs.items() for g in gens)
|
|
1055
|
+
|
|
1056
|
+
def _gap_(self, gap):
|
|
1057
|
+
r"""
|
|
1058
|
+
Return a representation of ``self`` in the GAP interface.
|
|
1059
|
+
|
|
1060
|
+
INPUT:
|
|
1061
|
+
|
|
1062
|
+
- ``gap`` -- a GAP or libgap instance
|
|
1063
|
+
|
|
1064
|
+
TESTS:
|
|
1065
|
+
|
|
1066
|
+
Multivariate polynomial over integers::
|
|
1067
|
+
|
|
1068
|
+
sage: # needs sage.libs.gap
|
|
1069
|
+
sage: R.<x,y,z> = ZZ[]
|
|
1070
|
+
sage: gap(-x*y + 3*z) # indirect doctest
|
|
1071
|
+
-x*y+3*z
|
|
1072
|
+
sage: gap(R.zero()) # indirect doctest
|
|
1073
|
+
0
|
|
1074
|
+
sage: (x+y+z)._gap_(libgap)
|
|
1075
|
+
x+y+z
|
|
1076
|
+
|
|
1077
|
+
sage: g = gap(x - y + 3*x*y*z) # needs sage.libs.gap
|
|
1078
|
+
sage: R(g) # needs sage.libs.gap
|
|
1079
|
+
3*x*y*z + x - y
|
|
1080
|
+
|
|
1081
|
+
sage: g = libgap(5*x - y*z) # needs sage.libs.gap
|
|
1082
|
+
sage: R(g) # needs sage.libs.gap
|
|
1083
|
+
-y*z + 5*x
|
|
1084
|
+
|
|
1085
|
+
Multivariate polynomial over a cyclotomic field::
|
|
1086
|
+
|
|
1087
|
+
sage: # needs sage.libs.gap sage.rings.number_field
|
|
1088
|
+
sage: F.<zeta> = CyclotomicField(8)
|
|
1089
|
+
sage: P.<x,y> = F[]
|
|
1090
|
+
sage: p = zeta + zeta^2*x + zeta^3*y + (1+zeta)*x*y
|
|
1091
|
+
sage: gap(p) # indirect doctest
|
|
1092
|
+
(1+E(8))*x*y+E(4)*x+E(8)^3*y+E(8)
|
|
1093
|
+
sage: libgap(p) # indirect doctest
|
|
1094
|
+
(1+E(8))*x*y+E(4)*x+E(8)^3*y+E(8)
|
|
1095
|
+
|
|
1096
|
+
Multivariate polynomial over a polynomial ring over a cyclotomic field::
|
|
1097
|
+
|
|
1098
|
+
sage: # needs sage.libs.gap sage.rings.number_field
|
|
1099
|
+
sage: S.<z> = F[]
|
|
1100
|
+
sage: P.<x,y> = S[]
|
|
1101
|
+
sage: p = zeta + zeta^2*x*z + zeta^3*y*z^2 + (1+zeta)*x*y*z
|
|
1102
|
+
sage: gap(p) # indirect doctest
|
|
1103
|
+
((1+E(8))*z)*x*y+E(4)*z*x+E(8)^3*z^2*y+E(8)
|
|
1104
|
+
sage: libgap(p) # indirect doctest
|
|
1105
|
+
((1+E(8))*z)*x*y+E(4)*z*x+E(8)^3*z^2*y+E(8)
|
|
1106
|
+
"""
|
|
1107
|
+
R = gap(self.parent())
|
|
1108
|
+
variables = R.IndeterminatesOfPolynomialRing()
|
|
1109
|
+
return self(*variables)
|
|
1110
|
+
|
|
1111
|
+
def _lean_init_(self):
|
|
1112
|
+
r"""
|
|
1113
|
+
Return polynomial as Lean mathlib input.
|
|
1114
|
+
"""
|
|
1115
|
+
# as in https://github.com/leanprover-community/mathlib/blob/master/scripts/polyrith_sage_helper.py
|
|
1116
|
+
raise NotImplementedError
|
|
1117
|
+
|
|
1118
|
+
def _libgap_(self):
|
|
1119
|
+
r"""
|
|
1120
|
+
TESTS::
|
|
1121
|
+
|
|
1122
|
+
sage: R.<x,y,z> = ZZ[]
|
|
1123
|
+
sage: libgap(-x*y + 3*z) # indirect doctest # needs sage.libs.gap
|
|
1124
|
+
-x*y+3*z
|
|
1125
|
+
sage: libgap(R.zero()) # indirect doctest # needs sage.libs.gap
|
|
1126
|
+
0
|
|
1127
|
+
"""
|
|
1128
|
+
from sage.libs.gap.libgap import libgap
|
|
1129
|
+
return self._gap_(libgap)
|
|
1130
|
+
|
|
1131
|
+
def _magma_init_(self, magma):
|
|
1132
|
+
r"""
|
|
1133
|
+
Return a Magma string representation of ``self`` valid in the
|
|
1134
|
+
given magma session.
|
|
1135
|
+
|
|
1136
|
+
EXAMPLES::
|
|
1137
|
+
|
|
1138
|
+
sage: # optional - magma, needs sage.rings.finite_rings
|
|
1139
|
+
sage: k.<b> = GF(25); R.<x,y> = k[]
|
|
1140
|
+
sage: f = y*x^2*b + x*(b+1) + 1
|
|
1141
|
+
sage: magma = Magma() # so var names same below
|
|
1142
|
+
sage: magma(f)
|
|
1143
|
+
b*x^2*y + b^22*x + 1
|
|
1144
|
+
sage: f._magma_init_(magma)
|
|
1145
|
+
'_sage_[...]!((_sage_[...]!(_sage_[...]))*_sage_[...]^2*_sage_[...]+(_sage_[...]!(_sage_[...] + 1))*_sage_[...]+(_sage_[...]!(1))*1)'
|
|
1146
|
+
|
|
1147
|
+
A more complicated nested example::
|
|
1148
|
+
|
|
1149
|
+
sage: # optional - magma
|
|
1150
|
+
sage: R.<x,y> = QQ[]; S.<z,w> = R[]; f = (2/3)*x^3*z + w^2 + 5
|
|
1151
|
+
sage: f._magma_init_(magma)
|
|
1152
|
+
'_sage_[...]!((_sage_[...]!((1/1)*1))*_sage_[...]^2+(_sage_[...]!((2/3)*_sage_[...]^3))*_sage_[...]+(_sage_[...]!((5/1)*1))*1)'
|
|
1153
|
+
sage: magma(f)
|
|
1154
|
+
w^2 + 2/3*x^3*z + 5
|
|
1155
|
+
"""
|
|
1156
|
+
R = magma(self.parent())
|
|
1157
|
+
g = R.gen_names()
|
|
1158
|
+
v = []
|
|
1159
|
+
for m, c in zip(self.monomials(), self.coefficients()):
|
|
1160
|
+
v.append('(%s)*%s' % (c._magma_init_(magma),
|
|
1161
|
+
m._repr_with_changed_varnames(g)))
|
|
1162
|
+
if len(v) == 0:
|
|
1163
|
+
s = '0'
|
|
1164
|
+
else:
|
|
1165
|
+
s = '+'.join(v)
|
|
1166
|
+
|
|
1167
|
+
return '%s!(%s)' % (R.name(), s)
|
|
1168
|
+
|
|
1169
|
+
def _giac_init_(self):
|
|
1170
|
+
r"""
|
|
1171
|
+
Return a Giac string representation of this polynomial.
|
|
1172
|
+
|
|
1173
|
+
TESTS::
|
|
1174
|
+
|
|
1175
|
+
sage: # needs giac
|
|
1176
|
+
sage: R.<x,y,z> = GF(101)['e,i'][]
|
|
1177
|
+
sage: f = R('e*i') * x + y^2
|
|
1178
|
+
sage: f._giac_init_()
|
|
1179
|
+
'((1)*1)*sageVARy^2+((1)*sageVARe*sageVARi)*sageVARx'
|
|
1180
|
+
sage: giac(f)
|
|
1181
|
+
sageVARy^2+sageVARe*sageVARi*sageVARx
|
|
1182
|
+
sage: giac(R.zero())
|
|
1183
|
+
0
|
|
1184
|
+
"""
|
|
1185
|
+
g = ['sageVAR' + x for x in self.parent().variable_names()]
|
|
1186
|
+
s = '+'.join('(%s)*%s' % (c._giac_init_(),
|
|
1187
|
+
m._repr_with_changed_varnames(g))
|
|
1188
|
+
for c, m in self)
|
|
1189
|
+
return s if s else '0'
|
|
1190
|
+
|
|
1191
|
+
def gradient(self):
|
|
1192
|
+
r"""
|
|
1193
|
+
Return a list of partial derivatives of this polynomial,
|
|
1194
|
+
ordered by the variables of ``self.parent()``.
|
|
1195
|
+
|
|
1196
|
+
EXAMPLES::
|
|
1197
|
+
|
|
1198
|
+
sage: P.<x,y,z> = PolynomialRing(ZZ, 3)
|
|
1199
|
+
sage: f = x*y + 1
|
|
1200
|
+
sage: f.gradient()
|
|
1201
|
+
[y, x, 0]
|
|
1202
|
+
"""
|
|
1203
|
+
return [ self.derivative(var) for var in self.parent().gens() ]
|
|
1204
|
+
|
|
1205
|
+
def jacobian_ideal(self):
|
|
1206
|
+
r"""
|
|
1207
|
+
Return the Jacobian ideal of the polynomial ``self``.
|
|
1208
|
+
|
|
1209
|
+
EXAMPLES::
|
|
1210
|
+
|
|
1211
|
+
sage: R.<x,y,z> = QQ[]
|
|
1212
|
+
sage: f = x^3 + y^3 + z^3
|
|
1213
|
+
sage: f.jacobian_ideal()
|
|
1214
|
+
Ideal (3*x^2, 3*y^2, 3*z^2) of
|
|
1215
|
+
Multivariate Polynomial Ring in x, y, z over Rational Field
|
|
1216
|
+
"""
|
|
1217
|
+
return self.parent().ideal(self.gradient())
|
|
1218
|
+
|
|
1219
|
+
def newton_polytope(self):
|
|
1220
|
+
r"""
|
|
1221
|
+
Return the Newton polytope of this polynomial.
|
|
1222
|
+
|
|
1223
|
+
EXAMPLES::
|
|
1224
|
+
|
|
1225
|
+
sage: R.<x,y> = QQ[]
|
|
1226
|
+
sage: f = 1 + x*y + x^3 + y^3
|
|
1227
|
+
sage: P = f.newton_polytope(); P # needs sage.geometry.polyhedron
|
|
1228
|
+
A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices
|
|
1229
|
+
sage: P.is_simple() # needs sage.geometry.polyhedron
|
|
1230
|
+
True
|
|
1231
|
+
|
|
1232
|
+
TESTS::
|
|
1233
|
+
|
|
1234
|
+
sage: R.<x,y> = QQ[]
|
|
1235
|
+
sage: R(0).newton_polytope() # needs sage.geometry.polyhedron
|
|
1236
|
+
The empty polyhedron in ZZ^0
|
|
1237
|
+
sage: R(1).newton_polytope() # needs sage.geometry.polyhedron
|
|
1238
|
+
A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex
|
|
1239
|
+
sage: R(x^2+y^2).newton_polytope().integral_points() # needs sage.geometry.polyhedron
|
|
1240
|
+
((0, 2), (1, 1), (2, 0))
|
|
1241
|
+
"""
|
|
1242
|
+
from sage.geometry.polyhedron.constructor import Polyhedron
|
|
1243
|
+
e = self.exponents()
|
|
1244
|
+
P = Polyhedron(vertices=e, base_ring=ZZ)
|
|
1245
|
+
return P
|
|
1246
|
+
|
|
1247
|
+
def __iter__(self):
|
|
1248
|
+
r"""
|
|
1249
|
+
Facilitates iterating over the monomials of ``self``,
|
|
1250
|
+
returning tuples of the form ``(coeff, mon)`` for each
|
|
1251
|
+
nonzero monomial.
|
|
1252
|
+
|
|
1253
|
+
EXAMPLES::
|
|
1254
|
+
|
|
1255
|
+
sage: P.<x,y,z> = PolynomialRing(QQ,3)
|
|
1256
|
+
sage: f = 3*x^3*y + 16*x + 7
|
|
1257
|
+
sage: [(c,m) for c,m in f]
|
|
1258
|
+
[(3, x^3*y), (16, x), (7, 1)]
|
|
1259
|
+
sage: f = P.random_element(12,14)
|
|
1260
|
+
sage: sum(c*m for c,m in f) == f
|
|
1261
|
+
True
|
|
1262
|
+
"""
|
|
1263
|
+
for exp, coeff in self.iterator_exp_coeff():
|
|
1264
|
+
yield (coeff, self.monomial(exp))
|
|
1265
|
+
|
|
1266
|
+
def iterator_exp_coeff(self, as_ETuples=True):
|
|
1267
|
+
r"""
|
|
1268
|
+
Iterate over ``self`` as pairs of ((E)Tuple, coefficient).
|
|
1269
|
+
|
|
1270
|
+
INPUT:
|
|
1271
|
+
|
|
1272
|
+
- ``as_ETuples`` -- boolean (default: ``True``); if ``True``, iterate over
|
|
1273
|
+
pairs whose first element is an :class:`ETuple`, otherwise as a tuples
|
|
1274
|
+
|
|
1275
|
+
EXAMPLES::
|
|
1276
|
+
|
|
1277
|
+
sage: R.<a,b,c> = QQ[]
|
|
1278
|
+
sage: f = a*c^3 + a^2*b + 2*b^4
|
|
1279
|
+
sage: list(f.iterator_exp_coeff())
|
|
1280
|
+
[((0, 4, 0), 2), ((1, 0, 3), 1), ((2, 1, 0), 1)]
|
|
1281
|
+
sage: list(f.iterator_exp_coeff(as_ETuples=False))
|
|
1282
|
+
[((0, 4, 0), 2), ((1, 0, 3), 1), ((2, 1, 0), 1)]
|
|
1283
|
+
|
|
1284
|
+
sage: R.<a,b,c> = PolynomialRing(QQ, 3, order='lex')
|
|
1285
|
+
sage: f = a*c^3 + a^2*b + 2*b^4
|
|
1286
|
+
sage: list(f.iterator_exp_coeff())
|
|
1287
|
+
[((2, 1, 0), 1), ((1, 0, 3), 1), ((0, 4, 0), 2)]
|
|
1288
|
+
"""
|
|
1289
|
+
for exp in self.exponents():
|
|
1290
|
+
yield (exp, self.monomial_coefficient(exp))
|
|
1291
|
+
|
|
1292
|
+
def content(self):
|
|
1293
|
+
r"""
|
|
1294
|
+
Return the content of this polynomial. Here, we define content as
|
|
1295
|
+
the gcd of the coefficients in the base ring.
|
|
1296
|
+
|
|
1297
|
+
.. SEEALSO::
|
|
1298
|
+
|
|
1299
|
+
:meth:`content_ideal`
|
|
1300
|
+
|
|
1301
|
+
EXAMPLES::
|
|
1302
|
+
|
|
1303
|
+
sage: R.<x,y> = ZZ[]
|
|
1304
|
+
sage: f = 4*x+6*y
|
|
1305
|
+
sage: f.content()
|
|
1306
|
+
2
|
|
1307
|
+
sage: f.content().parent()
|
|
1308
|
+
Integer Ring
|
|
1309
|
+
|
|
1310
|
+
TESTS:
|
|
1311
|
+
|
|
1312
|
+
Since :issue:`10771`, the gcd in QQ restricts to the gcd in ZZ::
|
|
1313
|
+
|
|
1314
|
+
sage: R.<x,y> = QQ[]
|
|
1315
|
+
sage: f = 4*x+6*y
|
|
1316
|
+
sage: f.content(); f.content().parent()
|
|
1317
|
+
2
|
|
1318
|
+
Rational Field
|
|
1319
|
+
"""
|
|
1320
|
+
from sage.arith.misc import GCD as gcd
|
|
1321
|
+
return gcd(self.coefficients())
|
|
1322
|
+
|
|
1323
|
+
def content_ideal(self):
|
|
1324
|
+
r"""
|
|
1325
|
+
Return the content ideal of this polynomial, defined as the ideal
|
|
1326
|
+
generated by its coefficients.
|
|
1327
|
+
|
|
1328
|
+
.. SEEALSO::
|
|
1329
|
+
|
|
1330
|
+
:meth:`content`
|
|
1331
|
+
|
|
1332
|
+
EXAMPLES::
|
|
1333
|
+
|
|
1334
|
+
sage: R.<x,y> = ZZ[]
|
|
1335
|
+
sage: f = 2*x*y + 6*x - 4*y + 2
|
|
1336
|
+
sage: f.content_ideal()
|
|
1337
|
+
Principal ideal (2) of Integer Ring
|
|
1338
|
+
sage: S.<z,t> = R[]
|
|
1339
|
+
sage: g = x*z + y*t
|
|
1340
|
+
sage: g.content_ideal()
|
|
1341
|
+
Ideal (x, y) of Multivariate Polynomial Ring in x, y over Integer Ring
|
|
1342
|
+
"""
|
|
1343
|
+
return self.base_ring().ideal(self.coefficients())
|
|
1344
|
+
|
|
1345
|
+
def is_gen(self):
|
|
1346
|
+
r"""
|
|
1347
|
+
Return ``True`` if this polynomial is a generator of its parent.
|
|
1348
|
+
|
|
1349
|
+
EXAMPLES::
|
|
1350
|
+
|
|
1351
|
+
sage: R.<x,y> = ZZ[]
|
|
1352
|
+
sage: x.is_gen()
|
|
1353
|
+
True
|
|
1354
|
+
sage: (x + y - y).is_gen()
|
|
1355
|
+
True
|
|
1356
|
+
sage: (x*y).is_gen()
|
|
1357
|
+
False
|
|
1358
|
+
sage: R.<x,y> = QQ[]
|
|
1359
|
+
sage: x.is_gen()
|
|
1360
|
+
True
|
|
1361
|
+
sage: (x + y - y).is_gen()
|
|
1362
|
+
True
|
|
1363
|
+
sage: (x*y).is_gen()
|
|
1364
|
+
False
|
|
1365
|
+
|
|
1366
|
+
TESTS::
|
|
1367
|
+
|
|
1368
|
+
sage: R.<x,y> = ZZ[]
|
|
1369
|
+
sage: x.is_generator()
|
|
1370
|
+
doctest:warning...:
|
|
1371
|
+
DeprecationWarning: is_generator is deprecated. Please use is_gen instead.
|
|
1372
|
+
See https://github.com/sagemath/sage/issues/38942 for details.
|
|
1373
|
+
True
|
|
1374
|
+
"""
|
|
1375
|
+
return self in self.parent().gens()
|
|
1376
|
+
|
|
1377
|
+
is_generator = deprecated_function_alias(38942, is_gen)
|
|
1378
|
+
|
|
1379
|
+
def map_coefficients(self, f, new_base_ring=None):
|
|
1380
|
+
r"""
|
|
1381
|
+
Return the polynomial obtained by applying ``f`` to the nonzero
|
|
1382
|
+
coefficients of ``self``.
|
|
1383
|
+
|
|
1384
|
+
If ``f`` is a :class:`sage.categories.map.Map`, then the resulting
|
|
1385
|
+
polynomial will be defined over the codomain of ``f``. Otherwise, the
|
|
1386
|
+
resulting polynomial will be over the same ring as ``self``. Set
|
|
1387
|
+
``new_base_ring`` to override this behaviour.
|
|
1388
|
+
|
|
1389
|
+
INPUT:
|
|
1390
|
+
|
|
1391
|
+
- ``f`` -- a callable that will be applied to the coefficients of ``self``
|
|
1392
|
+
|
|
1393
|
+
- ``new_base_ring`` -- (optional) if given, the resulting polynomial
|
|
1394
|
+
will be defined over this ring
|
|
1395
|
+
|
|
1396
|
+
EXAMPLES::
|
|
1397
|
+
|
|
1398
|
+
sage: k.<a> = GF(9); R.<x,y> = k[]; f = x*a + 2*x^3*y*a + a # needs sage.rings.finite_rings
|
|
1399
|
+
sage: f.map_coefficients(lambda a: a + 1) # needs sage.rings.finite_rings
|
|
1400
|
+
(-a + 1)*x^3*y + (a + 1)*x + (a + 1)
|
|
1401
|
+
|
|
1402
|
+
Examples with different base ring::
|
|
1403
|
+
|
|
1404
|
+
sage: # needs sage.rings.finite_rings
|
|
1405
|
+
sage: R.<r> = GF(9); S.<s> = GF(81)
|
|
1406
|
+
sage: h = Hom(R,S)[0]; h
|
|
1407
|
+
Ring morphism:
|
|
1408
|
+
From: Finite Field in r of size 3^2
|
|
1409
|
+
To: Finite Field in s of size 3^4
|
|
1410
|
+
Defn: r |--> 2*s^3 + 2*s^2 + 1
|
|
1411
|
+
sage: T.<X,Y> = R[]
|
|
1412
|
+
sage: f = r*X + Y
|
|
1413
|
+
sage: g = f.map_coefficients(h); g
|
|
1414
|
+
(-s^3 - s^2 + 1)*X + Y
|
|
1415
|
+
sage: g.parent()
|
|
1416
|
+
Multivariate Polynomial Ring in X, Y over Finite Field in s of size 3^4
|
|
1417
|
+
sage: h = lambda x: x.trace()
|
|
1418
|
+
sage: g = f.map_coefficients(h); g
|
|
1419
|
+
X - Y
|
|
1420
|
+
sage: g.parent()
|
|
1421
|
+
Multivariate Polynomial Ring in X, Y over Finite Field in r of size 3^2
|
|
1422
|
+
sage: g = f.map_coefficients(h, new_base_ring=GF(3)); g
|
|
1423
|
+
X - Y
|
|
1424
|
+
sage: g.parent()
|
|
1425
|
+
Multivariate Polynomial Ring in X, Y over Finite Field of size 3
|
|
1426
|
+
"""
|
|
1427
|
+
R = self.parent()
|
|
1428
|
+
if new_base_ring is not None:
|
|
1429
|
+
R = R.change_ring(new_base_ring)
|
|
1430
|
+
elif isinstance(f, Map):
|
|
1431
|
+
R = R.change_ring(f.codomain())
|
|
1432
|
+
return R({k: f(v) for k, v in self.monomial_coefficients().items()})
|
|
1433
|
+
|
|
1434
|
+
def _norm_over_nonprime_finite_field(self):
|
|
1435
|
+
r"""
|
|
1436
|
+
Given a multivariate polynomial over a nonprime finite field
|
|
1437
|
+
`\GF{p^e}`, compute the norm of the polynomial down to `\GF{p}`.
|
|
1438
|
+
|
|
1439
|
+
This is the product of the conjugates by the Frobenius action
|
|
1440
|
+
on coefficients, where Frobenius acts by `p`-th power.
|
|
1441
|
+
|
|
1442
|
+
This is (currently) an internal function used in factoring over finite
|
|
1443
|
+
fields.
|
|
1444
|
+
|
|
1445
|
+
EXAMPLES::
|
|
1446
|
+
|
|
1447
|
+
sage: # needs sage.rings.finite_rings
|
|
1448
|
+
sage: k.<a> = GF(9)
|
|
1449
|
+
sage: R.<x,y> = PolynomialRing(k)
|
|
1450
|
+
sage: f = (x-a) * (y-a)
|
|
1451
|
+
sage: f._norm_over_nonprime_finite_field()
|
|
1452
|
+
x^2*y^2 - x^2*y - x*y^2 - x^2 + x*y - y^2 + x + y + 1
|
|
1453
|
+
"""
|
|
1454
|
+
P = self.parent()
|
|
1455
|
+
k = P.base_ring()
|
|
1456
|
+
if not k.is_field() and k.is_finite():
|
|
1457
|
+
raise TypeError("k must be a finite field")
|
|
1458
|
+
p = k.characteristic()
|
|
1459
|
+
e = k.degree()
|
|
1460
|
+
v = [self] + [self.map_coefficients(k.hom([k.gen()**(p**i)])) for i in range(1, e)]
|
|
1461
|
+
return prod(v).change_ring(k.prime_subfield())
|
|
1462
|
+
|
|
1463
|
+
def sylvester_matrix(self, right, variable=None):
|
|
1464
|
+
r"""
|
|
1465
|
+
Given two nonzero polynomials ``self`` and ``right``, return the Sylvester
|
|
1466
|
+
matrix of the polynomials with respect to a given variable.
|
|
1467
|
+
|
|
1468
|
+
Note that the Sylvester matrix is not defined if one of the polynomials
|
|
1469
|
+
is zero.
|
|
1470
|
+
|
|
1471
|
+
INPUT:
|
|
1472
|
+
|
|
1473
|
+
- ``self``, ``right`` -- multivariate polynomials
|
|
1474
|
+
- ``variable`` -- (optional) compute the Sylvester matrix with respect
|
|
1475
|
+
to this variable. If ``variable`` is not provided, the first variable
|
|
1476
|
+
of the polynomial ring is used.
|
|
1477
|
+
|
|
1478
|
+
OUTPUT: the Sylvester matrix of ``self`` and ``right``
|
|
1479
|
+
|
|
1480
|
+
EXAMPLES::
|
|
1481
|
+
|
|
1482
|
+
sage: R.<x, y> = PolynomialRing(ZZ)
|
|
1483
|
+
sage: f = (y + 1)*x + 3*x**2
|
|
1484
|
+
sage: g = (y + 2)*x + 4*x**2
|
|
1485
|
+
sage: M = f.sylvester_matrix(g, x) # needs sage.modules
|
|
1486
|
+
sage: M # needs sage.modules
|
|
1487
|
+
[ 3 y + 1 0 0]
|
|
1488
|
+
[ 0 3 y + 1 0]
|
|
1489
|
+
[ 4 y + 2 0 0]
|
|
1490
|
+
[ 0 4 y + 2 0]
|
|
1491
|
+
|
|
1492
|
+
If the polynomials share a non-constant common factor then the
|
|
1493
|
+
determinant of the Sylvester matrix will be zero::
|
|
1494
|
+
|
|
1495
|
+
sage: M.determinant() # needs sage.modules
|
|
1496
|
+
0
|
|
1497
|
+
|
|
1498
|
+
sage: f.sylvester_matrix(1 + g, x).determinant() # needs sage.modules
|
|
1499
|
+
y^2 - y + 7
|
|
1500
|
+
|
|
1501
|
+
If both polynomials are of positive degree with respect to ``variable``, the
|
|
1502
|
+
determinant of the Sylvester matrix is the resultant::
|
|
1503
|
+
|
|
1504
|
+
sage: f = R.random_element(4) or (x^2 * y^2)
|
|
1505
|
+
sage: g = R.random_element(4) or (x^2 * y^2)
|
|
1506
|
+
sage: f.sylvester_matrix(g, x).determinant() == f.resultant(g, x) # needs sage.libs.singular sage.modules
|
|
1507
|
+
True
|
|
1508
|
+
|
|
1509
|
+
TESTS:
|
|
1510
|
+
|
|
1511
|
+
The variable is optional::
|
|
1512
|
+
|
|
1513
|
+
sage: f = x + y
|
|
1514
|
+
sage: g = x + y
|
|
1515
|
+
sage: f.sylvester_matrix(g) # needs sage.modules
|
|
1516
|
+
[1 y]
|
|
1517
|
+
[1 y]
|
|
1518
|
+
|
|
1519
|
+
Polynomials must be defined over compatible base rings::
|
|
1520
|
+
|
|
1521
|
+
sage: # needs sage.modules
|
|
1522
|
+
sage: K.<x, y> = QQ[]
|
|
1523
|
+
sage: f = x + y
|
|
1524
|
+
sage: L.<x, y> = ZZ[]
|
|
1525
|
+
sage: g = x + y
|
|
1526
|
+
sage: R.<x, y> = GF(25, 'a')[] # needs sage.rings.finite_rings
|
|
1527
|
+
sage: h = x + y
|
|
1528
|
+
sage: f.sylvester_matrix(g, 'x')
|
|
1529
|
+
[1 y]
|
|
1530
|
+
[1 y]
|
|
1531
|
+
sage: g.sylvester_matrix(h, 'x') # needs sage.rings.finite_rings
|
|
1532
|
+
[1 y]
|
|
1533
|
+
[1 y]
|
|
1534
|
+
sage: f.sylvester_matrix(h, 'x') # needs sage.rings.finite_rings
|
|
1535
|
+
Traceback (most recent call last):
|
|
1536
|
+
...
|
|
1537
|
+
TypeError: no common canonical parent for objects with parents:
|
|
1538
|
+
'Multivariate Polynomial Ring in x, y over Rational Field' and
|
|
1539
|
+
'Multivariate Polynomial Ring in x, y over Finite Field in a of size 5^2'
|
|
1540
|
+
sage: K.<x, y, z> = QQ[]
|
|
1541
|
+
sage: f = x + y
|
|
1542
|
+
sage: L.<x, z> = QQ[]
|
|
1543
|
+
sage: g = x + z
|
|
1544
|
+
sage: f.sylvester_matrix(g)
|
|
1545
|
+
[1 y]
|
|
1546
|
+
[1 z]
|
|
1547
|
+
|
|
1548
|
+
Corner cases::
|
|
1549
|
+
|
|
1550
|
+
sage: # needs sage.modules
|
|
1551
|
+
sage: K.<x, y> = QQ[]
|
|
1552
|
+
sage: f = x^2 + 1
|
|
1553
|
+
sage: g = K(0)
|
|
1554
|
+
sage: f.sylvester_matrix(g)
|
|
1555
|
+
Traceback (most recent call last):
|
|
1556
|
+
...
|
|
1557
|
+
ValueError: The Sylvester matrix is not defined for zero polynomials
|
|
1558
|
+
sage: g.sylvester_matrix(f)
|
|
1559
|
+
Traceback (most recent call last):
|
|
1560
|
+
...
|
|
1561
|
+
ValueError: The Sylvester matrix is not defined for zero polynomials
|
|
1562
|
+
sage: g.sylvester_matrix(g)
|
|
1563
|
+
Traceback (most recent call last):
|
|
1564
|
+
...
|
|
1565
|
+
ValueError: The Sylvester matrix is not defined for zero polynomials
|
|
1566
|
+
sage: K(3).sylvester_matrix(x^2)
|
|
1567
|
+
[3 0]
|
|
1568
|
+
[0 3]
|
|
1569
|
+
sage: K(3).sylvester_matrix(K(4))
|
|
1570
|
+
[]
|
|
1571
|
+
"""
|
|
1572
|
+
|
|
1573
|
+
# This code is almost exactly the same as that of
|
|
1574
|
+
# sylvester_matrix() in polynomial_element.pyx.
|
|
1575
|
+
|
|
1576
|
+
from sage.matrix.constructor import matrix
|
|
1577
|
+
|
|
1578
|
+
if self.parent() != right.parent():
|
|
1579
|
+
a, b = coercion_model.canonical_coercion(self,right)
|
|
1580
|
+
if variable:
|
|
1581
|
+
variable = a.parent()(variable)
|
|
1582
|
+
#We add the variable in case right is a multivariate polynomial
|
|
1583
|
+
return a.sylvester_matrix(b, variable)
|
|
1584
|
+
|
|
1585
|
+
if not variable:
|
|
1586
|
+
variable = self.parent().gen()
|
|
1587
|
+
|
|
1588
|
+
#coerce the variable to a polynomial
|
|
1589
|
+
if variable.parent() != self.parent():
|
|
1590
|
+
variable = self.parent()(variable)
|
|
1591
|
+
|
|
1592
|
+
if self.is_zero() or right.is_zero():
|
|
1593
|
+
raise ValueError("The Sylvester matrix is not defined for zero polynomials")
|
|
1594
|
+
|
|
1595
|
+
m = self.degree(variable)
|
|
1596
|
+
n = right.degree(variable)
|
|
1597
|
+
|
|
1598
|
+
M = matrix(self.parent(), m + n, m + n)
|
|
1599
|
+
|
|
1600
|
+
r = 0
|
|
1601
|
+
offset = 0
|
|
1602
|
+
for _ in range(n):
|
|
1603
|
+
for c in range(m, -1, -1):
|
|
1604
|
+
M[r, m - c + offset] = self.coefficient({variable:c})
|
|
1605
|
+
offset += 1
|
|
1606
|
+
r += 1
|
|
1607
|
+
|
|
1608
|
+
offset = 0
|
|
1609
|
+
for _ in range(m):
|
|
1610
|
+
for c in range(n, -1, -1):
|
|
1611
|
+
M[r, n - c + offset] = right.coefficient({variable:c})
|
|
1612
|
+
offset += 1
|
|
1613
|
+
r += 1
|
|
1614
|
+
|
|
1615
|
+
return M
|
|
1616
|
+
|
|
1617
|
+
def discriminant(self, variable):
|
|
1618
|
+
r"""
|
|
1619
|
+
Return the discriminant of ``self`` with respect to the given variable.
|
|
1620
|
+
|
|
1621
|
+
INPUT:
|
|
1622
|
+
|
|
1623
|
+
- ``variable`` -- the variable with respect to which we compute
|
|
1624
|
+
the discriminant
|
|
1625
|
+
|
|
1626
|
+
OUTPUT: an element of the base ring of the polynomial ring
|
|
1627
|
+
|
|
1628
|
+
EXAMPLES::
|
|
1629
|
+
|
|
1630
|
+
sage: R.<x,y,z> = QQ[]
|
|
1631
|
+
sage: f = 4*x*y^2 + 1/4*x*y*z + 3/2*x*z^2 - 1/2*z^2
|
|
1632
|
+
sage: f.discriminant(x) # needs sage.libs.singular
|
|
1633
|
+
1
|
|
1634
|
+
sage: f.discriminant(y) # needs sage.libs.singular
|
|
1635
|
+
-383/16*x^2*z^2 + 8*x*z^2
|
|
1636
|
+
sage: f.discriminant(z) # needs sage.libs.singular
|
|
1637
|
+
-383/16*x^2*y^2 + 8*x*y^2
|
|
1638
|
+
|
|
1639
|
+
Note that, unlike the univariate case, the result lives in
|
|
1640
|
+
the same ring as the polynomial::
|
|
1641
|
+
|
|
1642
|
+
sage: R.<x,y> = QQ[]
|
|
1643
|
+
sage: f = x^5*y + 3*x^2*y^2 - 2*x + y - 1
|
|
1644
|
+
sage: f.discriminant(y) # needs sage.libs.singular
|
|
1645
|
+
x^10 + 2*x^5 + 24*x^3 + 12*x^2 + 1
|
|
1646
|
+
sage: f.polynomial(y).discriminant() # needs sage.libs.pari sage.modules
|
|
1647
|
+
x^10 + 2*x^5 + 24*x^3 + 12*x^2 + 1
|
|
1648
|
+
sage: f.discriminant(y).parent() == f.polynomial(y).discriminant().parent() # needs sage.libs.singular sage.modules
|
|
1649
|
+
False
|
|
1650
|
+
|
|
1651
|
+
TESTS:
|
|
1652
|
+
|
|
1653
|
+
Test polynomials over QQbar (:issue:`25265`)::
|
|
1654
|
+
|
|
1655
|
+
sage: # needs sage.rings.number_field
|
|
1656
|
+
sage: R.<x,y> = QQbar[]
|
|
1657
|
+
sage: f = x^5*y + 3*x^2*y^2 - 2*x + y - 1
|
|
1658
|
+
sage: f.discriminant(y) # needs sage.libs.singular
|
|
1659
|
+
x^10 + 2*x^5 + 24*x^3 + 12*x^2 + 1
|
|
1660
|
+
|
|
1661
|
+
AUTHOR: Miguel Marco
|
|
1662
|
+
"""
|
|
1663
|
+
if self.is_zero():
|
|
1664
|
+
return self.parent().zero()
|
|
1665
|
+
n = self.degree(variable)
|
|
1666
|
+
d = self.derivative(variable)
|
|
1667
|
+
k = d.degree(variable)
|
|
1668
|
+
|
|
1669
|
+
r = n % 4
|
|
1670
|
+
u = -1 # (-1)**(n*(n-1)/2)
|
|
1671
|
+
if r == 0 or r == 1:
|
|
1672
|
+
u = 1
|
|
1673
|
+
an = self.coefficient(variable**n)**(n - k - 2)
|
|
1674
|
+
return self.parent()(u * self.resultant(d, variable) * an)
|
|
1675
|
+
|
|
1676
|
+
def subresultants(self, other, variable=None):
|
|
1677
|
+
r"""
|
|
1678
|
+
Return the nonzero subresultant polynomials of ``self`` and ``other``.
|
|
1679
|
+
|
|
1680
|
+
INPUT:
|
|
1681
|
+
|
|
1682
|
+
- ``other`` -- a polynomial
|
|
1683
|
+
|
|
1684
|
+
OUTPUT: list of polynomials in the same ring as ``self``
|
|
1685
|
+
|
|
1686
|
+
EXAMPLES::
|
|
1687
|
+
|
|
1688
|
+
sage: R.<x,y> = QQ[]
|
|
1689
|
+
sage: p = (y^2 + 6)*(x - 1) - y*(x^2 + 1)
|
|
1690
|
+
sage: q = (x^2 + 6)*(y - 1) - x*(y^2 + 1)
|
|
1691
|
+
sage: p.subresultants(q, y)
|
|
1692
|
+
[2*x^6 - 22*x^5 + 102*x^4 - 274*x^3 + 488*x^2 - 552*x + 288,
|
|
1693
|
+
-x^3 - x^2*y + 6*x^2 + 5*x*y - 11*x - 6*y + 6]
|
|
1694
|
+
sage: p.subresultants(q, x)
|
|
1695
|
+
[2*y^6 - 22*y^5 + 102*y^4 - 274*y^3 + 488*y^2 - 552*y + 288,
|
|
1696
|
+
x*y^2 + y^3 - 5*x*y - 6*y^2 + 6*x + 11*y - 6]
|
|
1697
|
+
"""
|
|
1698
|
+
R = self.parent()
|
|
1699
|
+
if variable is None:
|
|
1700
|
+
x = R.gen(0)
|
|
1701
|
+
else:
|
|
1702
|
+
x = variable
|
|
1703
|
+
p = self.polynomial(x)
|
|
1704
|
+
q = other.polynomial(x)
|
|
1705
|
+
return [R(f) for f in p.subresultants(q)]
|
|
1706
|
+
|
|
1707
|
+
def macaulay_resultant(self, *args):
|
|
1708
|
+
r"""
|
|
1709
|
+
This is an implementation of the Macaulay resultant. It computes
|
|
1710
|
+
the resultant of universal polynomials as well as polynomials
|
|
1711
|
+
with constant coefficients. This is a project done in
|
|
1712
|
+
sage days 55. It's based on the implementation in Maple by
|
|
1713
|
+
Manfred Minimair, which in turn is based on the references [CLO], [Can], [Mac].
|
|
1714
|
+
It calculates the Macaulay resultant for a list of Polynomials,
|
|
1715
|
+
up to sign!
|
|
1716
|
+
|
|
1717
|
+
AUTHORS:
|
|
1718
|
+
|
|
1719
|
+
- Hao Chen, Solomon Vishkautsan (7-2014)
|
|
1720
|
+
|
|
1721
|
+
INPUT:
|
|
1722
|
+
|
|
1723
|
+
- ``args`` -- list of `n-1` homogeneous polynomials in `n` variables;
|
|
1724
|
+
works when ``args[0]`` is the list of polynomials, or ``args`` is
|
|
1725
|
+
itself the list of polynomials
|
|
1726
|
+
|
|
1727
|
+
OUTPUT: the Macaulay resultant
|
|
1728
|
+
|
|
1729
|
+
EXAMPLES:
|
|
1730
|
+
|
|
1731
|
+
The number of polynomials has to match the number of variables::
|
|
1732
|
+
|
|
1733
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, 3)
|
|
1734
|
+
sage: y.macaulay_resultant(x + z) # needs sage.modules
|
|
1735
|
+
Traceback (most recent call last):
|
|
1736
|
+
...
|
|
1737
|
+
TypeError: number of polynomials(= 2) must equal number of variables (= 3)
|
|
1738
|
+
|
|
1739
|
+
The polynomials need to be all homogeneous::
|
|
1740
|
+
|
|
1741
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, 3)
|
|
1742
|
+
sage: y.macaulay_resultant([x + z, z + x^3]) # needs sage.modules
|
|
1743
|
+
Traceback (most recent call last):
|
|
1744
|
+
...
|
|
1745
|
+
TypeError: resultant for non-homogeneous polynomials is not supported
|
|
1746
|
+
|
|
1747
|
+
All polynomials must be in the same ring::
|
|
1748
|
+
|
|
1749
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, 3)
|
|
1750
|
+
sage: S.<x,y> = PolynomialRing(QQ, 2)
|
|
1751
|
+
sage: y.macaulay_resultant(z + x, z) # needs sage.modules
|
|
1752
|
+
Traceback (most recent call last):
|
|
1753
|
+
...
|
|
1754
|
+
TypeError: not all inputs are polynomials in the calling ring
|
|
1755
|
+
|
|
1756
|
+
The following example recreates Proposition 2.10 in Ch.3 of Using Algebraic Geometry::
|
|
1757
|
+
|
|
1758
|
+
sage: K.<x,y> = PolynomialRing(ZZ, 2)
|
|
1759
|
+
sage: flist, R = K._macaulay_resultant_universal_polynomials([1,1,2])
|
|
1760
|
+
sage: flist[0].macaulay_resultant(flist[1:]) # needs sage.modules
|
|
1761
|
+
u2^2*u4^2*u6 - 2*u1*u2*u4*u5*u6 + u1^2*u5^2*u6 - u2^2*u3*u4*u7 + u1*u2*u3*u5*u7
|
|
1762
|
+
+ u0*u2*u4*u5*u7 - u0*u1*u5^2*u7 + u1*u2*u3*u4*u8 - u0*u2*u4^2*u8 - u1^2*u3*u5*u8
|
|
1763
|
+
+ u0*u1*u4*u5*u8 + u2^2*u3^2*u9 - 2*u0*u2*u3*u5*u9 + u0^2*u5^2*u9
|
|
1764
|
+
- u1*u2*u3^2*u10 + u0*u2*u3*u4*u10 + u0*u1*u3*u5*u10 - u0^2*u4*u5*u10
|
|
1765
|
+
+ u1^2*u3^2*u11 - 2*u0*u1*u3*u4*u11 + u0^2*u4^2*u11
|
|
1766
|
+
|
|
1767
|
+
The following example degenerates into the determinant of a `3\times 3` matrix::
|
|
1768
|
+
|
|
1769
|
+
sage: K.<x,y> = PolynomialRing(ZZ, 2)
|
|
1770
|
+
sage: flist, R = K._macaulay_resultant_universal_polynomials([1,1,1])
|
|
1771
|
+
sage: flist[0].macaulay_resultant(flist[1:]) # needs sage.modules
|
|
1772
|
+
-u2*u4*u6 + u1*u5*u6 + u2*u3*u7 - u0*u5*u7 - u1*u3*u8 + u0*u4*u8
|
|
1773
|
+
|
|
1774
|
+
The following example is by Patrick Ingram (:arxiv:`1310.4114`)::
|
|
1775
|
+
|
|
1776
|
+
sage: U = PolynomialRing(ZZ,'y',2); y0,y1 = U.gens()
|
|
1777
|
+
sage: R = PolynomialRing(U,'x',3); x0,x1,x2 = R.gens()
|
|
1778
|
+
sage: f0 = y0*x2^2 - x0^2 + 2*x1*x2
|
|
1779
|
+
sage: f1 = y1*x2^2 - x1^2 + 2*x0*x2
|
|
1780
|
+
sage: f2 = x0*x1 - x2^2
|
|
1781
|
+
sage: f0.macaulay_resultant(f1, f2) # needs sage.modules
|
|
1782
|
+
y0^2*y1^2 - 4*y0^3 - 4*y1^3 + 18*y0*y1 - 27
|
|
1783
|
+
|
|
1784
|
+
a simple example with constant rational coefficients::
|
|
1785
|
+
|
|
1786
|
+
sage: R.<x,y,z,w> = PolynomialRing(QQ, 4)
|
|
1787
|
+
sage: w.macaulay_resultant([z, y, x]) # needs sage.modules
|
|
1788
|
+
1
|
|
1789
|
+
|
|
1790
|
+
an example where the resultant vanishes::
|
|
1791
|
+
|
|
1792
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, 3)
|
|
1793
|
+
sage: (x + y).macaulay_resultant([y^2, x]) # needs sage.modules
|
|
1794
|
+
0
|
|
1795
|
+
|
|
1796
|
+
an example of bad reduction at a prime ``p = 5``::
|
|
1797
|
+
|
|
1798
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, 3)
|
|
1799
|
+
sage: y.macaulay_resultant([x^3 + 25*y^2*x, 5*z]) # needs sage.libs.pari sage.modules
|
|
1800
|
+
125
|
|
1801
|
+
|
|
1802
|
+
The input can given as an unpacked list of polynomials::
|
|
1803
|
+
|
|
1804
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, 3)
|
|
1805
|
+
sage: y.macaulay_resultant(x^3 + 25*y^2*x, 5*z) # needs sage.libs.pari sage.modules
|
|
1806
|
+
125
|
|
1807
|
+
|
|
1808
|
+
an example when the coefficients live in a finite field::
|
|
1809
|
+
|
|
1810
|
+
sage: F = FiniteField(11)
|
|
1811
|
+
sage: R.<x,y,z,w> = PolynomialRing(F, 4)
|
|
1812
|
+
sage: z.macaulay_resultant([x^3, 5*y, w]) # needs sage.modules sage.rings.finite_rings
|
|
1813
|
+
4
|
|
1814
|
+
|
|
1815
|
+
example when the denominator in the algorithm vanishes(in this case
|
|
1816
|
+
the resultant is the constant term of the quotient of
|
|
1817
|
+
char polynomials of numerator/denominator)::
|
|
1818
|
+
|
|
1819
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, 3)
|
|
1820
|
+
sage: y.macaulay_resultant([x + z, z^2]) # needs sage.libs.pari sage.modules
|
|
1821
|
+
-1
|
|
1822
|
+
|
|
1823
|
+
When there are only 2 polynomials, the Macaulay resultant degenerates to the traditional resultant::
|
|
1824
|
+
|
|
1825
|
+
sage: R.<x> = PolynomialRing(QQ, 1)
|
|
1826
|
+
sage: f = x^2 + 1; g = x^5 + 1
|
|
1827
|
+
sage: fh = f.homogenize()
|
|
1828
|
+
sage: gh = g.homogenize()
|
|
1829
|
+
sage: RH = fh.parent()
|
|
1830
|
+
sage: f.resultant(g) == fh.macaulay_resultant(gh) # needs sage.modules
|
|
1831
|
+
True
|
|
1832
|
+
"""
|
|
1833
|
+
if len(args) == 1 and isinstance(args[0],list):
|
|
1834
|
+
return self.parent().macaulay_resultant(self, *args[0])
|
|
1835
|
+
return self.parent().macaulay_resultant(self, *args)
|
|
1836
|
+
|
|
1837
|
+
def denominator(self):
|
|
1838
|
+
r"""
|
|
1839
|
+
Return a denominator of ``self``.
|
|
1840
|
+
|
|
1841
|
+
First, the lcm of the denominators of the entries of ``self``
|
|
1842
|
+
is computed and returned. If this computation fails, the
|
|
1843
|
+
unit of the parent of ``self`` is returned.
|
|
1844
|
+
|
|
1845
|
+
Note that some subclasses may implement its own denominator
|
|
1846
|
+
function.
|
|
1847
|
+
|
|
1848
|
+
.. warning::
|
|
1849
|
+
|
|
1850
|
+
This is not the denominator of the rational function
|
|
1851
|
+
defined by ``self``, which would always be 1 since ``self`` is a
|
|
1852
|
+
polynomial.
|
|
1853
|
+
|
|
1854
|
+
EXAMPLES:
|
|
1855
|
+
|
|
1856
|
+
First we compute the denominator of a polynomial with
|
|
1857
|
+
integer coefficients, which is of course 1.
|
|
1858
|
+
|
|
1859
|
+
::
|
|
1860
|
+
|
|
1861
|
+
sage: R.<x,y> = ZZ[]
|
|
1862
|
+
sage: f = x^3 + 17*y + x + y
|
|
1863
|
+
sage: f.denominator()
|
|
1864
|
+
1
|
|
1865
|
+
|
|
1866
|
+
Next we compute the denominator of a polynomial over a number field.
|
|
1867
|
+
|
|
1868
|
+
::
|
|
1869
|
+
|
|
1870
|
+
sage: # needs sage.rings.number_field sage.symbolic
|
|
1871
|
+
sage: R.<x,y> = NumberField(symbolic_expression(x^2+3),'a')['x,y']
|
|
1872
|
+
sage: f = (1/17)*x^19 + (1/6)*y - (2/3)*x + 1/3; f
|
|
1873
|
+
1/17*x^19 - 2/3*x + 1/6*y + 1/3
|
|
1874
|
+
sage: f.denominator()
|
|
1875
|
+
102
|
|
1876
|
+
|
|
1877
|
+
Finally, we try to compute the denominator of a polynomial with
|
|
1878
|
+
coefficients in the real numbers, which is a ring whose elements do
|
|
1879
|
+
not have a denominator method.
|
|
1880
|
+
|
|
1881
|
+
::
|
|
1882
|
+
|
|
1883
|
+
sage: # needs sage.rings.real_mpfr
|
|
1884
|
+
sage: R.<a,b,c> = RR[]
|
|
1885
|
+
sage: f = a + b + RR('0.3'); f
|
|
1886
|
+
a + b + 0.300000000000000
|
|
1887
|
+
sage: f.denominator()
|
|
1888
|
+
1.00000000000000
|
|
1889
|
+
|
|
1890
|
+
Check that the denominator is an element over the base whenever the base
|
|
1891
|
+
has no denominator function. This closes :issue:`9063`::
|
|
1892
|
+
|
|
1893
|
+
sage: R.<a,b,c> = GF(5)[]
|
|
1894
|
+
sage: x = R(0)
|
|
1895
|
+
sage: x.denominator()
|
|
1896
|
+
1
|
|
1897
|
+
sage: type(x.denominator())
|
|
1898
|
+
<class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>
|
|
1899
|
+
sage: type(a.denominator())
|
|
1900
|
+
<class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>
|
|
1901
|
+
sage: from sage.rings.polynomial.multi_polynomial_element import MPolynomial
|
|
1902
|
+
sage: isinstance(a / b, MPolynomial)
|
|
1903
|
+
False
|
|
1904
|
+
sage: isinstance(a.numerator() / a.denominator(), MPolynomial)
|
|
1905
|
+
True
|
|
1906
|
+
"""
|
|
1907
|
+
if self.degree() == -1:
|
|
1908
|
+
return self.base_ring().one()
|
|
1909
|
+
x = self.coefficients()
|
|
1910
|
+
try:
|
|
1911
|
+
d = x[0].denominator()
|
|
1912
|
+
for y in x:
|
|
1913
|
+
d = d.lcm(y.denominator())
|
|
1914
|
+
return d
|
|
1915
|
+
except AttributeError:
|
|
1916
|
+
return self.base_ring().one()
|
|
1917
|
+
|
|
1918
|
+
def numerator(self):
|
|
1919
|
+
r"""
|
|
1920
|
+
Return a numerator of ``self``, computed as ``self * self.denominator()``.
|
|
1921
|
+
|
|
1922
|
+
Note that some subclasses may implement its own numerator
|
|
1923
|
+
function.
|
|
1924
|
+
|
|
1925
|
+
.. warning::
|
|
1926
|
+
|
|
1927
|
+
This is not the numerator of the rational function
|
|
1928
|
+
defined by ``self``, which would always be ``self`` since ``self`` is a
|
|
1929
|
+
polynomial.
|
|
1930
|
+
|
|
1931
|
+
EXAMPLES:
|
|
1932
|
+
|
|
1933
|
+
First we compute the numerator of a polynomial with
|
|
1934
|
+
integer coefficients, which is of course ``self``.
|
|
1935
|
+
|
|
1936
|
+
::
|
|
1937
|
+
|
|
1938
|
+
sage: R.<x, y> = ZZ[]
|
|
1939
|
+
sage: f = x^3 + 17*x + y + 1
|
|
1940
|
+
sage: f.numerator()
|
|
1941
|
+
x^3 + 17*x + y + 1
|
|
1942
|
+
sage: f == f.numerator()
|
|
1943
|
+
True
|
|
1944
|
+
|
|
1945
|
+
Next we compute the numerator of a polynomial over a number field.
|
|
1946
|
+
|
|
1947
|
+
::
|
|
1948
|
+
|
|
1949
|
+
sage: # needs sage.rings.number_field sage.symbolic
|
|
1950
|
+
sage: R.<x,y> = NumberField(symbolic_expression(x^2+3), 'a')['x,y']
|
|
1951
|
+
sage: f = (1/17)*y^19 - (2/3)*x + 1/3; f
|
|
1952
|
+
1/17*y^19 - 2/3*x + 1/3
|
|
1953
|
+
sage: f.numerator()
|
|
1954
|
+
3*y^19 - 34*x + 17
|
|
1955
|
+
sage: f == f.numerator()
|
|
1956
|
+
False
|
|
1957
|
+
|
|
1958
|
+
We try to compute the numerator of a polynomial with coefficients in
|
|
1959
|
+
the finite field of 3 elements.
|
|
1960
|
+
|
|
1961
|
+
::
|
|
1962
|
+
|
|
1963
|
+
sage: K.<x,y,z> = GF(3)['x, y, z']
|
|
1964
|
+
sage: f = 2*x*z + 2*z^2 + 2*y + 1; f
|
|
1965
|
+
-x*z - z^2 - y + 1
|
|
1966
|
+
sage: f.numerator()
|
|
1967
|
+
-x*z - z^2 - y + 1
|
|
1968
|
+
|
|
1969
|
+
We check that the computation the numerator and denominator
|
|
1970
|
+
are valid.
|
|
1971
|
+
|
|
1972
|
+
::
|
|
1973
|
+
|
|
1974
|
+
sage: # needs sage.rings.number_field sage.symbolic
|
|
1975
|
+
sage: K = NumberField(symbolic_expression('x^3+2'), 'a')['x']['s,t']
|
|
1976
|
+
sage: f = K.random_element()
|
|
1977
|
+
sage: f.numerator() / f.denominator() == f
|
|
1978
|
+
True
|
|
1979
|
+
sage: R = RR['x,y,z']
|
|
1980
|
+
sage: f = R.random_element()
|
|
1981
|
+
sage: f.numerator() / f.denominator() == f
|
|
1982
|
+
True
|
|
1983
|
+
"""
|
|
1984
|
+
return self * self.denominator()
|
|
1985
|
+
|
|
1986
|
+
def lift(self, I):
|
|
1987
|
+
r"""
|
|
1988
|
+
Given an ideal `I = (f_1,\dots,f_r)` that contains ``self``,
|
|
1989
|
+
find `s_1,\dots,s_r` such that ``self`` `= s_1 f_1 + ... + s_r f_r`.
|
|
1990
|
+
|
|
1991
|
+
INPUT:
|
|
1992
|
+
|
|
1993
|
+
- ``I`` -- an ideal in ``self.parent()`` or tuple of generators of that ideal
|
|
1994
|
+
|
|
1995
|
+
EXAMPLES::
|
|
1996
|
+
|
|
1997
|
+
sage: # needs sage.rings.real_mpfr
|
|
1998
|
+
sage: A.<x,y> = PolynomialRing(CC, 2, order='degrevlex')
|
|
1999
|
+
sage: I = A.ideal([x^10 + x^9*y^2, y^8 - x^2*y^7 ])
|
|
2000
|
+
sage: f = x*y^13 + y^12
|
|
2001
|
+
sage: M = f.lift(I); M # needs sage.libs.singular
|
|
2002
|
+
[y^7, x^7*y^2 + x^8 + x^5*y^3 + x^6*y + x^3*y^4 + x^4*y^2 + x*y^5 + x^2*y^3 + y^4]
|
|
2003
|
+
sage: sum(map(mul, zip(M, I.gens()))) == f # needs sage.libs.singular
|
|
2004
|
+
True
|
|
2005
|
+
"""
|
|
2006
|
+
raise NotImplementedError
|
|
2007
|
+
|
|
2008
|
+
def inverse_mod(self, I):
|
|
2009
|
+
r"""
|
|
2010
|
+
Return an inverse of ``self`` modulo the polynomial ideal `I`,
|
|
2011
|
+
namely a multivariate polynomial `f` such that
|
|
2012
|
+
``self * f - 1`` belongs to `I`.
|
|
2013
|
+
|
|
2014
|
+
INPUT:
|
|
2015
|
+
|
|
2016
|
+
- ``I`` -- an ideal of the polynomial ring in which ``self`` lives,
|
|
2017
|
+
or a single polynomial
|
|
2018
|
+
|
|
2019
|
+
OUTPUT: a multivariate polynomial representing the inverse of ``f`` modulo `I`
|
|
2020
|
+
|
|
2021
|
+
EXAMPLES::
|
|
2022
|
+
|
|
2023
|
+
sage: R.<x1,x2> = QQ[]
|
|
2024
|
+
sage: I = R.ideal(x2**2 + x1 - 2, x1**2 - 1)
|
|
2025
|
+
sage: f = x1 + 3*x2^2; g = f.inverse_mod(I); g # needs sage.libs.singular
|
|
2026
|
+
1/16*x1 + 3/16
|
|
2027
|
+
sage: (f*g).reduce(I) # needs sage.libs.singular
|
|
2028
|
+
1
|
|
2029
|
+
|
|
2030
|
+
Test a non-invertible element::
|
|
2031
|
+
|
|
2032
|
+
sage: R.<x1,x2> = QQ[]
|
|
2033
|
+
sage: I = R.ideal(x2**2 + x1 - 2, x1**2 - 1)
|
|
2034
|
+
sage: f = x1 + x2
|
|
2035
|
+
sage: f.inverse_mod(I) # needs sage.libs.singular
|
|
2036
|
+
Traceback (most recent call last):
|
|
2037
|
+
...
|
|
2038
|
+
ArithmeticError: element is non-invertible
|
|
2039
|
+
|
|
2040
|
+
TESTS::
|
|
2041
|
+
|
|
2042
|
+
sage: R.<x,y> = ZZ[]
|
|
2043
|
+
sage: x.inverse_mod(x*y - 1) # needs sage.libs.singular
|
|
2044
|
+
y
|
|
2045
|
+
"""
|
|
2046
|
+
P = self.parent()
|
|
2047
|
+
from sage.rings.ideal import Ideal_generic
|
|
2048
|
+
B = I.gens() if isinstance(I, Ideal_generic) else (I,)
|
|
2049
|
+
try:
|
|
2050
|
+
XY = P.one().lift((self,) + tuple(B))
|
|
2051
|
+
return P(XY[0])
|
|
2052
|
+
except ValueError:
|
|
2053
|
+
raise ArithmeticError("element is non-invertible")
|
|
2054
|
+
|
|
2055
|
+
def weighted_degree(self, *weights):
|
|
2056
|
+
r"""
|
|
2057
|
+
Return the weighted degree of ``self``, which is the maximum weighted
|
|
2058
|
+
degree of all monomials in ``self``; the weighted degree of a monomial
|
|
2059
|
+
is the sum of all powers of the variables in the monomial, each power
|
|
2060
|
+
multiplied with its respective weight in ``weights``.
|
|
2061
|
+
|
|
2062
|
+
This method is given for convenience. It is faster to use polynomial
|
|
2063
|
+
rings with weighted term orders and the standard ``degree`` function.
|
|
2064
|
+
|
|
2065
|
+
INPUT:
|
|
2066
|
+
|
|
2067
|
+
- ``weights`` -- either individual numbers, an iterable or a dictionary,
|
|
2068
|
+
specifying the weights of each variable. If it is a dictionary, it
|
|
2069
|
+
maps each variable of ``self`` to its weight. If it is a sequence of
|
|
2070
|
+
individual numbers or a tuple, the weights are specified in the order
|
|
2071
|
+
of the generators as given by ``self.parent().gens()``.
|
|
2072
|
+
|
|
2073
|
+
EXAMPLES::
|
|
2074
|
+
|
|
2075
|
+
sage: R.<x,y,z> = GF(7)[]
|
|
2076
|
+
sage: p = x^3 + y + x*z^2
|
|
2077
|
+
sage: p.weighted_degree({z:0, x:1, y:2})
|
|
2078
|
+
3
|
|
2079
|
+
sage: p.weighted_degree(1, 2, 0)
|
|
2080
|
+
3
|
|
2081
|
+
sage: p.weighted_degree((1, 4, 2))
|
|
2082
|
+
5
|
|
2083
|
+
sage: p.weighted_degree((1, 4, 1))
|
|
2084
|
+
4
|
|
2085
|
+
sage: p.weighted_degree(2**64, 2**50, 2**128)
|
|
2086
|
+
680564733841876926945195958937245974528
|
|
2087
|
+
sage: q = R.random_element(100, 20)
|
|
2088
|
+
sage: q.weighted_degree(1, 1, 1) == q.total_degree()
|
|
2089
|
+
True
|
|
2090
|
+
|
|
2091
|
+
You may also work with negative weights
|
|
2092
|
+
|
|
2093
|
+
::
|
|
2094
|
+
|
|
2095
|
+
sage: p.weighted_degree(-1, -2, -1)
|
|
2096
|
+
-2
|
|
2097
|
+
|
|
2098
|
+
Note that only integer weights are allowed
|
|
2099
|
+
|
|
2100
|
+
::
|
|
2101
|
+
|
|
2102
|
+
sage: p.weighted_degree(x, 1, 1)
|
|
2103
|
+
Traceback (most recent call last):
|
|
2104
|
+
...
|
|
2105
|
+
TypeError: unable to convert non-constant polynomial x to Integer Ring
|
|
2106
|
+
sage: p.weighted_degree(2/1, 1, 1)
|
|
2107
|
+
6
|
|
2108
|
+
|
|
2109
|
+
The :meth:`weighted_degree` coincides with the :meth:`degree` of a weighted
|
|
2110
|
+
polynomial ring, but the latter is faster.
|
|
2111
|
+
|
|
2112
|
+
::
|
|
2113
|
+
|
|
2114
|
+
sage: K = PolynomialRing(QQ, 'x,y', order=TermOrder('wdegrevlex', (2,3)))
|
|
2115
|
+
sage: p = K.random_element(10)
|
|
2116
|
+
sage: p.degree() == p.weighted_degree(2,3)
|
|
2117
|
+
True
|
|
2118
|
+
|
|
2119
|
+
TESTS::
|
|
2120
|
+
|
|
2121
|
+
sage: # needs sage.modules
|
|
2122
|
+
sage: R = PolynomialRing(QQ, 'a', 5)
|
|
2123
|
+
sage: f = R.random_element(terms=20)
|
|
2124
|
+
sage: w = random_vector(ZZ,5)
|
|
2125
|
+
sage: d1 = f.weighted_degree(w)
|
|
2126
|
+
sage: d2 = (f*1.0).weighted_degree(w)
|
|
2127
|
+
sage: d1 == d2
|
|
2128
|
+
True
|
|
2129
|
+
"""
|
|
2130
|
+
if self.is_zero():
|
|
2131
|
+
#Corner case, note that the degree of zero is an Integer
|
|
2132
|
+
return Integer(-1)
|
|
2133
|
+
|
|
2134
|
+
if len(weights) == 1:
|
|
2135
|
+
# First unwrap it if it is given as one element argument
|
|
2136
|
+
weights = weights[0]
|
|
2137
|
+
|
|
2138
|
+
if isinstance(weights, dict):
|
|
2139
|
+
weights = [weights[g] for g in self.parent().gens()]
|
|
2140
|
+
|
|
2141
|
+
weights = [Integer(w) for w in weights]
|
|
2142
|
+
|
|
2143
|
+
# Go through each monomial, calculating the weight
|
|
2144
|
+
cdef int n = self.parent().ngens()
|
|
2145
|
+
cdef int i, j
|
|
2146
|
+
cdef Integer deg
|
|
2147
|
+
cdef Integer l
|
|
2148
|
+
cdef tuple m
|
|
2149
|
+
A = self.exponents(as_ETuples=False)
|
|
2150
|
+
l = Integer(0)
|
|
2151
|
+
m = <tuple>(A[0])
|
|
2152
|
+
for i in range(n):
|
|
2153
|
+
l += weights[i]*m[i]
|
|
2154
|
+
deg = l
|
|
2155
|
+
for j in range(1, len(A)):
|
|
2156
|
+
l = Integer(0)
|
|
2157
|
+
m = <tuple> A[j]
|
|
2158
|
+
for i in range(n):
|
|
2159
|
+
l += weights[i]*m[i]
|
|
2160
|
+
if deg < l:
|
|
2161
|
+
deg = l
|
|
2162
|
+
return deg
|
|
2163
|
+
|
|
2164
|
+
def gcd(self, other):
|
|
2165
|
+
r"""
|
|
2166
|
+
Return a greatest common divisor of this polynomial and ``other``.
|
|
2167
|
+
|
|
2168
|
+
INPUT:
|
|
2169
|
+
|
|
2170
|
+
- ``other`` -- a polynomial with the same parent as this polynomial
|
|
2171
|
+
|
|
2172
|
+
EXAMPLES::
|
|
2173
|
+
|
|
2174
|
+
sage: Q.<z> = Frac(QQ['z'])
|
|
2175
|
+
sage: R.<x,y> = Q[]
|
|
2176
|
+
sage: r = x*y - (2*z-1)/(z^2+z+1) * x + y/z
|
|
2177
|
+
sage: p = r * (x + z*y - 1/z^2)
|
|
2178
|
+
sage: q = r * (x*y*z + 1)
|
|
2179
|
+
sage: gcd(p, q)
|
|
2180
|
+
(z^3 + z^2 + z)*x*y + (-2*z^2 + z)*x + (z^2 + z + 1)*y
|
|
2181
|
+
|
|
2182
|
+
Polynomials over polynomial rings are converted to a simpler polynomial
|
|
2183
|
+
ring with all variables to compute the gcd::
|
|
2184
|
+
|
|
2185
|
+
sage: A.<z,t> = ZZ[]
|
|
2186
|
+
sage: B.<x,y> = A[]
|
|
2187
|
+
sage: r = x*y*z*t + 1
|
|
2188
|
+
sage: p = r * (x - y + z - t + 1)
|
|
2189
|
+
sage: q = r * (x*z - y*t)
|
|
2190
|
+
sage: gcd(p, q) # needs sage.libs.singular
|
|
2191
|
+
z*t*x*y + 1
|
|
2192
|
+
sage: _.parent()
|
|
2193
|
+
Multivariate Polynomial Ring in x, y over
|
|
2194
|
+
Multivariate Polynomial Ring in z, t over Integer Ring
|
|
2195
|
+
|
|
2196
|
+
Some multivariate polynomial rings have no gcd implementation::
|
|
2197
|
+
|
|
2198
|
+
sage: R.<x,y> = GaussianIntegers()[] # needs sage.rings.number_field
|
|
2199
|
+
sage: x.gcd(x)
|
|
2200
|
+
Traceback (most recent call last):
|
|
2201
|
+
...
|
|
2202
|
+
NotImplementedError: GCD is not implemented for multivariate polynomials over
|
|
2203
|
+
Gaussian Integers generated by I in Number Field in I with defining polynomial x^2 + 1 with I = 1*I
|
|
2204
|
+
|
|
2205
|
+
TESTS::
|
|
2206
|
+
|
|
2207
|
+
sage: Pol = QQ['x']['x','y']
|
|
2208
|
+
sage: Pol.one().gcd(1)
|
|
2209
|
+
1
|
|
2210
|
+
|
|
2211
|
+
sage: P = PolynomialRing(QQ, 'x', 0)
|
|
2212
|
+
sage: P.gens()
|
|
2213
|
+
()
|
|
2214
|
+
"""
|
|
2215
|
+
flatten = self._parent.flattening_morphism()
|
|
2216
|
+
tgt = flatten.codomain()
|
|
2217
|
+
if tgt is not self._parent and tgt._has_singular:
|
|
2218
|
+
g = flatten(self).gcd(flatten(other))
|
|
2219
|
+
return flatten.section()(g)
|
|
2220
|
+
|
|
2221
|
+
try:
|
|
2222
|
+
self._parent._singular_().set_ring()
|
|
2223
|
+
g = self._singular_().gcd(other._singular_())
|
|
2224
|
+
return self._parent(g)
|
|
2225
|
+
except (TypeError, AttributeError, ImportError):
|
|
2226
|
+
pass
|
|
2227
|
+
|
|
2228
|
+
gens = self.parent().gens()
|
|
2229
|
+
if not gens:
|
|
2230
|
+
# no variables
|
|
2231
|
+
base = self.parent().base_ring()
|
|
2232
|
+
return base(self).gcd(base(other))
|
|
2233
|
+
|
|
2234
|
+
x = gens[-1]
|
|
2235
|
+
uniself = self.polynomial(x)
|
|
2236
|
+
unibase = uniself.base_ring()
|
|
2237
|
+
try:
|
|
2238
|
+
doit = unibase._gcd_univariate_polynomial
|
|
2239
|
+
except AttributeError:
|
|
2240
|
+
raise NotImplementedError("GCD is not implemented for multivariate polynomials over {}".format(self._parent._mpoly_base_ring()))
|
|
2241
|
+
else:
|
|
2242
|
+
return self.parent()(doit(uniself, other.polynomial(x)))
|
|
2243
|
+
|
|
2244
|
+
def nth_root(self, n):
|
|
2245
|
+
r"""
|
|
2246
|
+
Return a `n`-th root of this element.
|
|
2247
|
+
|
|
2248
|
+
If there is no such root, a :exc:`ValueError` is raised.
|
|
2249
|
+
|
|
2250
|
+
EXAMPLES::
|
|
2251
|
+
|
|
2252
|
+
sage: R.<x,y,z> = QQ[]
|
|
2253
|
+
sage: a = 32 * (x*y + 1)^5 * (x+y+z)^5
|
|
2254
|
+
sage: a.nth_root(5)
|
|
2255
|
+
2*x^2*y + 2*x*y^2 + 2*x*y*z + 2*x + 2*y + 2*z
|
|
2256
|
+
sage: b = x + 2*y + 3*z
|
|
2257
|
+
sage: b.nth_root(42)
|
|
2258
|
+
Traceback (most recent call last):
|
|
2259
|
+
...
|
|
2260
|
+
ValueError: not a 42nd power
|
|
2261
|
+
|
|
2262
|
+
sage: R.<x,y> = QQ[]
|
|
2263
|
+
sage: S.<z,t> = R[]
|
|
2264
|
+
sage: T.<u,v> = S[]
|
|
2265
|
+
sage: p = (1 + x*u + y + v) * (1 + z*t)
|
|
2266
|
+
sage: (p**3).nth_root(3)
|
|
2267
|
+
(x*z*t + x)*u + (z*t + 1)*v + (y + 1)*z*t + y + 1
|
|
2268
|
+
sage: (p**3).nth_root(3).parent() is p.parent()
|
|
2269
|
+
True
|
|
2270
|
+
sage: ((1+x+z+t)**2).nth_root(3)
|
|
2271
|
+
Traceback (most recent call last):
|
|
2272
|
+
...
|
|
2273
|
+
ValueError: not a 3rd power
|
|
2274
|
+
"""
|
|
2275
|
+
R = self.parent()
|
|
2276
|
+
phi = R.flattening_morphism()
|
|
2277
|
+
S = phi.codomain()
|
|
2278
|
+
p = phi(self)
|
|
2279
|
+
|
|
2280
|
+
V = p.variables()
|
|
2281
|
+
if not V:
|
|
2282
|
+
# constant
|
|
2283
|
+
root = self.constant_coefficient().nth_root(n)
|
|
2284
|
+
return phi.section()(S(root))
|
|
2285
|
+
elif len(V) == 1:
|
|
2286
|
+
# univariate
|
|
2287
|
+
U = PolynomialRing(S.base_ring(), str(V[0]))
|
|
2288
|
+
pU = U(p)
|
|
2289
|
+
else:
|
|
2290
|
+
# specialize one variable
|
|
2291
|
+
# (in order to call the univariate case)
|
|
2292
|
+
U0 = PolynomialRing(S.base_ring(), [str(v) for v in V[:-1]])
|
|
2293
|
+
U = U0[str(V[-1])]
|
|
2294
|
+
pU = U(p)
|
|
2295
|
+
|
|
2296
|
+
# recursive call
|
|
2297
|
+
root = pU.nth_root(n)
|
|
2298
|
+
return phi.section()(S(root))
|
|
2299
|
+
|
|
2300
|
+
def is_square(self, root=False):
|
|
2301
|
+
r"""
|
|
2302
|
+
Test whether this polynomial is a square.
|
|
2303
|
+
|
|
2304
|
+
INPUT:
|
|
2305
|
+
|
|
2306
|
+
- ``root`` -- if set to ``True``, return a pair ``(True, root)``
|
|
2307
|
+
where ``root`` is a square root or ``(False, None)`` if
|
|
2308
|
+
it is not a square.
|
|
2309
|
+
|
|
2310
|
+
EXAMPLES::
|
|
2311
|
+
|
|
2312
|
+
sage: R.<a,b> = QQ[]
|
|
2313
|
+
sage: a.is_square()
|
|
2314
|
+
False
|
|
2315
|
+
sage: ((1+a*b^2)^2).is_square()
|
|
2316
|
+
True
|
|
2317
|
+
sage: ((1+a*b^2)^2).is_square(root=True)
|
|
2318
|
+
(True, a*b^2 + 1)
|
|
2319
|
+
"""
|
|
2320
|
+
try:
|
|
2321
|
+
sqrt = self.nth_root(2)
|
|
2322
|
+
except ValueError:
|
|
2323
|
+
return (False,None) if root else False
|
|
2324
|
+
else:
|
|
2325
|
+
return (True,sqrt) if root else True
|
|
2326
|
+
|
|
2327
|
+
def specialization(self, D=None, phi=None):
|
|
2328
|
+
r"""
|
|
2329
|
+
Specialization of this polynomial.
|
|
2330
|
+
|
|
2331
|
+
Given a family of polynomials defined over a polynomial ring. A specialization
|
|
2332
|
+
is a particular member of that family. The specialization can be specified either
|
|
2333
|
+
by a dictionary or a :class:`SpecializationMorphism`.
|
|
2334
|
+
|
|
2335
|
+
INPUT:
|
|
2336
|
+
|
|
2337
|
+
- ``D`` -- dictionary (optional)
|
|
2338
|
+
|
|
2339
|
+
- ``phi`` -- :class:`SpecializationMorphism` (optional)
|
|
2340
|
+
|
|
2341
|
+
OUTPUT: a new polynomial
|
|
2342
|
+
|
|
2343
|
+
EXAMPLES::
|
|
2344
|
+
|
|
2345
|
+
sage: R.<c> = PolynomialRing(QQ)
|
|
2346
|
+
sage: S.<x,y> = PolynomialRing(R)
|
|
2347
|
+
sage: F = x^2 + c*y^2
|
|
2348
|
+
sage: F.specialization({c:2})
|
|
2349
|
+
x^2 + 2*y^2
|
|
2350
|
+
|
|
2351
|
+
::
|
|
2352
|
+
|
|
2353
|
+
sage: S.<a,b> = PolynomialRing(QQ)
|
|
2354
|
+
sage: P.<x,y,z> = PolynomialRing(S)
|
|
2355
|
+
sage: RR.<c,d> = PolynomialRing(P)
|
|
2356
|
+
sage: f = a*x^2 + b*y^3 + c*y^2 - b*a*d + d^2 - a*c*b*z^2
|
|
2357
|
+
sage: f.specialization({a:2, z:4, d:2})
|
|
2358
|
+
(y^2 - 32*b)*c + b*y^3 + 2*x^2 - 4*b + 4
|
|
2359
|
+
|
|
2360
|
+
Check that we preserve multi- versus uni-variate::
|
|
2361
|
+
|
|
2362
|
+
sage: R.<l> = PolynomialRing(QQ, 1)
|
|
2363
|
+
sage: S.<k> = PolynomialRing(R)
|
|
2364
|
+
sage: K.<a, b, c> = PolynomialRing(S)
|
|
2365
|
+
sage: F = a*k^2 + b*l + c^2
|
|
2366
|
+
sage: F.specialization({b:56, c:5}).parent()
|
|
2367
|
+
Univariate Polynomial Ring in a over Univariate Polynomial Ring in k
|
|
2368
|
+
over Multivariate Polynomial Ring in l over Rational Field
|
|
2369
|
+
"""
|
|
2370
|
+
if D is None:
|
|
2371
|
+
if phi is None:
|
|
2372
|
+
raise ValueError("either the dictionary or the specialization must be provided")
|
|
2373
|
+
else:
|
|
2374
|
+
from sage.rings.polynomial.flatten import SpecializationMorphism
|
|
2375
|
+
phi = SpecializationMorphism(self.parent(),D)
|
|
2376
|
+
return phi(self)
|
|
2377
|
+
|
|
2378
|
+
def reduced_form(self, **kwds):
|
|
2379
|
+
r"""
|
|
2380
|
+
Return a reduced form of this polynomial.
|
|
2381
|
+
|
|
2382
|
+
The algorithm is from Stoll and Cremona's "On the Reduction Theory of
|
|
2383
|
+
Binary Forms" [CS2003]_. This takes a two variable homogeneous polynomial and
|
|
2384
|
+
finds a reduced form. This is a `SL(2,\ZZ)`-equivalent binary form
|
|
2385
|
+
whose covariant in the upper half plane is in the fundamental domain.
|
|
2386
|
+
If the polynomial has multiple roots, they are removed and the algorithm
|
|
2387
|
+
is applied to the portion without multiple roots.
|
|
2388
|
+
|
|
2389
|
+
This reduction should also minimize the sum of the squares of the coefficients,
|
|
2390
|
+
but this is not always the case. By default the coefficient minimizing
|
|
2391
|
+
algorithm in [HS2018]_ is applied. The coefficients can be minimized
|
|
2392
|
+
either with respect to the sum of their squares or the maximum of their
|
|
2393
|
+
global heights.
|
|
2394
|
+
|
|
2395
|
+
A portion of the algorithm uses Newton's method to find a solution to
|
|
2396
|
+
a system of equations. If Newton's method fails to converge to a point
|
|
2397
|
+
in the upper half plane, the function will use the less precise `z_0`
|
|
2398
|
+
covariant from the `Q_0` form as defined on page 7 of [CS2003]_.
|
|
2399
|
+
Additionally, if this polynomial has
|
|
2400
|
+
a root with multiplicity at least half the total degree of the polynomial,
|
|
2401
|
+
then we must also use the `z_0` covariant. See [CS2003]_ for details.
|
|
2402
|
+
|
|
2403
|
+
Note that, if the covariant is within ``error_limit`` of the boundary
|
|
2404
|
+
but outside the fundamental domain, our function will erroneously move
|
|
2405
|
+
it to within the fundamental domain, hence our conjugation will be off
|
|
2406
|
+
by 1. If you don't want this to happen, decrease your ``error_limit``
|
|
2407
|
+
and increase your precision.
|
|
2408
|
+
|
|
2409
|
+
Implemented by Rebecca Lauren Miller as part of GSOC 2016. Smallest
|
|
2410
|
+
coefficients added by Ben Hutz July 2018.
|
|
2411
|
+
|
|
2412
|
+
INPUT: keyword arguments:
|
|
2413
|
+
|
|
2414
|
+
- ``prec`` -- integer (default: 300); sets the precision
|
|
2415
|
+
|
|
2416
|
+
- ``return_conjugation`` -- boolean (default: ``True``); whether to
|
|
2417
|
+
return element of `SL(2, \ZZ)`
|
|
2418
|
+
|
|
2419
|
+
- ``error_limit`` -- sets the error tolerance (default: 0.000001)
|
|
2420
|
+
|
|
2421
|
+
- ``smallest_coeffs`` -- boolean (default: ``True``); whether to find the
|
|
2422
|
+
model with smallest coefficients
|
|
2423
|
+
|
|
2424
|
+
- ``norm_type`` -- either ``'norm'`` or ``'height'``; what type of norm
|
|
2425
|
+
to use for smallest coefficients
|
|
2426
|
+
|
|
2427
|
+
- ``emb`` -- (optional) embedding of based field into ``CC``
|
|
2428
|
+
|
|
2429
|
+
OUTPUT:
|
|
2430
|
+
|
|
2431
|
+
- a polynomial (reduced binary form)
|
|
2432
|
+
|
|
2433
|
+
- a matrix (element of `SL(2, \ZZ)`)
|
|
2434
|
+
|
|
2435
|
+
.. TODO::
|
|
2436
|
+
|
|
2437
|
+
When Newton's Method doesn't converge to a root in the upper half plane.
|
|
2438
|
+
Now we just return `z_0`. It would be better to modify and find the unique root
|
|
2439
|
+
in the upper half plane.
|
|
2440
|
+
|
|
2441
|
+
EXAMPLES::
|
|
2442
|
+
|
|
2443
|
+
sage: R.<x,h> = PolynomialRing(QQ)
|
|
2444
|
+
sage: f = 19*x^8 - 262*x^7*h + 1507*x^6*h^2 - 4784*x^5*h^3 + 9202*x^4*h^4\
|
|
2445
|
+
....: -10962*x^3*h^5 + 7844*x^2*h^6 - 3040*x*h^7 + 475*h^8
|
|
2446
|
+
sage: f.reduced_form(prec=200, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2447
|
+
(
|
|
2448
|
+
-x^8 - 2*x^7*h + 7*x^6*h^2 + 16*x^5*h^3 + 2*x^4*h^4 - 2*x^3*h^5 + 4*x^2*h^6 - 5*h^8,
|
|
2449
|
+
<BLANKLINE>
|
|
2450
|
+
[ 1 -2]
|
|
2451
|
+
[ 1 -1]
|
|
2452
|
+
)
|
|
2453
|
+
|
|
2454
|
+
An example where the multiplicity is too high::
|
|
2455
|
+
|
|
2456
|
+
sage: R.<x,y> = PolynomialRing(QQ)
|
|
2457
|
+
sage: f = x^3 + 378666*x^2*y - 12444444*x*y^2 + 1234567890*y^3
|
|
2458
|
+
sage: j = f * (x-545*y)^9
|
|
2459
|
+
sage: j.reduced_form(prec=200, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2460
|
+
Traceback (most recent call last):
|
|
2461
|
+
...
|
|
2462
|
+
ValueError: cannot have a root with multiplicity >= 12/2
|
|
2463
|
+
|
|
2464
|
+
An example where Newton's Method does not find the right root::
|
|
2465
|
+
|
|
2466
|
+
sage: R.<x,y> = PolynomialRing(QQ)
|
|
2467
|
+
sage: F = x^6 + 3*x^5*y - 8*x^4*y^2 - 2*x^3*y^3 - 44*x^2*y^4 - 8*x*y^5
|
|
2468
|
+
sage: F.reduced_form(smallest_coeffs=False, prec=400) # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2469
|
+
Traceback (most recent call last):
|
|
2470
|
+
...
|
|
2471
|
+
ArithmeticError: Newton's method converged to z not in the upper half plane
|
|
2472
|
+
|
|
2473
|
+
An example with covariant on the boundary, therefore a non-unique form::
|
|
2474
|
+
|
|
2475
|
+
sage: R.<x,y> = PolynomialRing(QQ)
|
|
2476
|
+
sage: F = 5*x^2*y - 5*x*y^2 - 30*y^3
|
|
2477
|
+
sage: F.reduced_form(smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2478
|
+
(
|
|
2479
|
+
[1 1]
|
|
2480
|
+
5*x^2*y + 5*x*y^2 - 30*y^3, [0 1]
|
|
2481
|
+
)
|
|
2482
|
+
|
|
2483
|
+
An example where precision needs to be increased::
|
|
2484
|
+
|
|
2485
|
+
sage: R.<x,y> = PolynomialRing(QQ)
|
|
2486
|
+
sage: F = (-16*x^7 - 114*x^6*y - 345*x^5*y^2 - 599*x^4*y^3
|
|
2487
|
+
....: - 666*x^3*y^4 - 481*x^2*y^5 - 207*x*y^6 - 40*y^7)
|
|
2488
|
+
sage: F.reduced_form(prec=50, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2489
|
+
Traceback (most recent call last):
|
|
2490
|
+
...
|
|
2491
|
+
ValueError: accuracy of Newton's root not within tolerance(0.000012... > 1e-06),
|
|
2492
|
+
increase precision
|
|
2493
|
+
sage: F.reduced_form(prec=100, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2494
|
+
(
|
|
2495
|
+
[-1 -1]
|
|
2496
|
+
-x^5*y^2 - 24*x^3*y^4 - 3*x^2*y^5 - 2*x*y^6 + 16*y^7, [ 1 0]
|
|
2497
|
+
)
|
|
2498
|
+
|
|
2499
|
+
::
|
|
2500
|
+
|
|
2501
|
+
sage: R.<x,y> = PolynomialRing(QQ)
|
|
2502
|
+
sage: F = - 8*x^4 - 3933*x^3*y - 725085*x^2*y^2 - 59411592*x*y^3 - 1825511633*y^4
|
|
2503
|
+
sage: F.reduced_form(return_conjugation=False) # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2504
|
+
x^4 + 9*x^3*y - 3*x*y^3 - 8*y^4
|
|
2505
|
+
|
|
2506
|
+
::
|
|
2507
|
+
|
|
2508
|
+
sage: R.<x,y> = QQ[]
|
|
2509
|
+
sage: F = -2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3
|
|
2510
|
+
sage: F.reduced_form() # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2511
|
+
(
|
|
2512
|
+
[1 4]
|
|
2513
|
+
-2*x^3 - 22*x^2*y - 77*x*y^2 + 43*y^3, [0 1]
|
|
2514
|
+
)
|
|
2515
|
+
|
|
2516
|
+
::
|
|
2517
|
+
|
|
2518
|
+
sage: R.<x,y> = QQ[]
|
|
2519
|
+
sage: F = -2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3
|
|
2520
|
+
sage: F.reduced_form(norm_type='height') # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2521
|
+
(
|
|
2522
|
+
[5 4]
|
|
2523
|
+
-58*x^3 - 47*x^2*y + 52*x*y^2 + 43*y^3, [1 1]
|
|
2524
|
+
)
|
|
2525
|
+
|
|
2526
|
+
::
|
|
2527
|
+
|
|
2528
|
+
sage: R.<x,y,z> = PolynomialRing(QQ)
|
|
2529
|
+
sage: F = x^4 + x^3*y*z + y^2*z
|
|
2530
|
+
sage: F.reduced_form() # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2531
|
+
Traceback (most recent call last):
|
|
2532
|
+
...
|
|
2533
|
+
ValueError: (=x^3*y*z + x^4 + y^2*z) must have two variables
|
|
2534
|
+
|
|
2535
|
+
::
|
|
2536
|
+
|
|
2537
|
+
sage: R.<x,y> = PolynomialRing(ZZ)
|
|
2538
|
+
sage: F = - 8*x^6 - 3933*x^3*y - 725085*x^2*y^2 - 59411592*x*y^3 - 99*y^6
|
|
2539
|
+
sage: F.reduced_form(return_conjugation=False) # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2540
|
+
Traceback (most recent call last):
|
|
2541
|
+
...
|
|
2542
|
+
ValueError: (=-8*x^6 - 99*y^6 - 3933*x^3*y - 725085*x^2*y^2 -
|
|
2543
|
+
59411592*x*y^3) must be homogeneous
|
|
2544
|
+
|
|
2545
|
+
::
|
|
2546
|
+
|
|
2547
|
+
sage: R.<x,y> = PolynomialRing(RR)
|
|
2548
|
+
sage: F = (217.992172373276*x^3 + 96023.1505442490*x^2*y
|
|
2549
|
+
....: + 1.40987971253579e7*x*y^2 + 6.90016027113216e8*y^3)
|
|
2550
|
+
sage: F.reduced_form(smallest_coeffs=False) # tol 1e-8 # needs sage.modules sage.rings.complex_interval_field sage.schemes
|
|
2551
|
+
(
|
|
2552
|
+
-39.5673942565918*x^3 + 111.874026298523*x^2*y
|
|
2553
|
+
+ 231.052762985229*x*y^2 - 138.380829811096*y^3,
|
|
2554
|
+
<BLANKLINE>
|
|
2555
|
+
[-147 -148]
|
|
2556
|
+
[ 1 1]
|
|
2557
|
+
)
|
|
2558
|
+
|
|
2559
|
+
::
|
|
2560
|
+
|
|
2561
|
+
sage: R.<x,y> = PolynomialRing(CC) # needs sage.rings.real_mpfr
|
|
2562
|
+
sage: F = ((0.759099196558145 + 0.845425869641446*CC.0)*x^3 # needs sage.rings.real_mpfr
|
|
2563
|
+
....: + (84.8317207268542 + 93.8840848648033*CC.0)*x^2*y
|
|
2564
|
+
....: + (3159.07040755858 + 3475.33037377779*CC.0)*x*y^2
|
|
2565
|
+
....: + (39202.5965389079 + 42882.5139724962*CC.0)*y^3)
|
|
2566
|
+
sage: F.reduced_form(smallest_coeffs=False) # tol 1e-11 # needs sage.modules sage.rings.complex_interval_field sage.rings.real_mpfr sage.schemes
|
|
2567
|
+
(
|
|
2568
|
+
(-0.759099196558145 - 0.845425869641446*I)*x^3
|
|
2569
|
+
+ (-0.571709908900118 - 0.0418133346027929*I)*x^2*y
|
|
2570
|
+
+ (0.856525964330103 - 0.0721403997649759*I)*x*y^2
|
|
2571
|
+
+ (-0.965531044130330 + 0.754252314465703*I)*y^3,
|
|
2572
|
+
<BLANKLINE>
|
|
2573
|
+
[-1 37]
|
|
2574
|
+
[ 0 -1]
|
|
2575
|
+
)
|
|
2576
|
+
"""
|
|
2577
|
+
from sage.matrix.constructor import matrix
|
|
2578
|
+
from sage.modules.free_module_element import vector
|
|
2579
|
+
from sage.rings.complex_interval_field import ComplexIntervalField
|
|
2580
|
+
from sage.rings.real_mpfr import RealField
|
|
2581
|
+
|
|
2582
|
+
if self.parent().ngens() != 2:
|
|
2583
|
+
raise ValueError("(=%s) must have two variables" % self)
|
|
2584
|
+
if not self.is_homogeneous():
|
|
2585
|
+
raise ValueError("(=%s) must be homogeneous" % self)
|
|
2586
|
+
|
|
2587
|
+
prec = kwds.get('prec', 300)
|
|
2588
|
+
return_conjugation = kwds.get('return_conjugation', True)
|
|
2589
|
+
emb = kwds.get('emb', None)
|
|
2590
|
+
|
|
2591
|
+
# getting a numerical approximation of the roots of our polynomial
|
|
2592
|
+
CF = ComplexIntervalField(prec=prec) # keeps trac of our precision error
|
|
2593
|
+
RF = RealField(prec=prec)
|
|
2594
|
+
R = self.parent()
|
|
2595
|
+
x, y = R.gens()
|
|
2596
|
+
|
|
2597
|
+
# finding quadratic Q_0, gives us our covariant, z_0
|
|
2598
|
+
from sage.rings.polynomial.binary_form_reduce import covariant_z0
|
|
2599
|
+
try:
|
|
2600
|
+
z, th = covariant_z0(self, prec=prec, emb=emb, z0_cov=True)
|
|
2601
|
+
except ValueError:# multiple roots
|
|
2602
|
+
F = self.lc()*prod([p for p, e in self.factor()])
|
|
2603
|
+
z, th = covariant_z0(F, prec=prec, emb=emb, z0_cov=True)
|
|
2604
|
+
z = CF(z)
|
|
2605
|
+
# this moves z_0 to our fundamental domain using the three steps laid
|
|
2606
|
+
# out in the algorithm by [CS2003]
|
|
2607
|
+
# this is found in section 5 of their paper
|
|
2608
|
+
M = matrix(QQ, [[1,0], [0,1]]) # used to keep track of how our z is moved.
|
|
2609
|
+
zc = z.center()
|
|
2610
|
+
while zc.real() < RF(-0.5) or zc.real() >= RF(0.5) or (zc.real() <= RF(0) and zc.abs() < RF(1))\
|
|
2611
|
+
or (zc.real() > RF(0) and zc.abs() <= RF(1)):
|
|
2612
|
+
if (zc.real() < RF(-0.5)) or (zc.real() >= RF(0.5)):
|
|
2613
|
+
# moves z into fundamental domain by m
|
|
2614
|
+
m = zc.real().round() # finds amount to move z's real part by
|
|
2615
|
+
Qm = QQ(m)
|
|
2616
|
+
M = M * matrix(QQ, [[1, Qm], [0, 1]]) # move
|
|
2617
|
+
z -= m # M.inverse()*z is supposed to move z by m
|
|
2618
|
+
elif (zc.real() <= RF(0) and zc.abs() < RF(1)) or (zc.real() > RF(0) and zc.abs() <= RF(1)): # flips z
|
|
2619
|
+
z = -1/z
|
|
2620
|
+
M = M * matrix(QQ, [[0, -1], [1, 0]])# multiply on left because we are taking inverse matrices
|
|
2621
|
+
zc = z.center()
|
|
2622
|
+
|
|
2623
|
+
smallest_coeffs = kwds.get('smallest_coeffs', True)
|
|
2624
|
+
if smallest_coeffs:
|
|
2625
|
+
# since we are searching anyway, don't need the 'true' reduced covariant
|
|
2626
|
+
from sage.rings.polynomial.binary_form_reduce import smallest_poly
|
|
2627
|
+
norm_type = kwds.get('norm_type', 'norm')
|
|
2628
|
+
_, sm_m = smallest_poly(self(tuple(M * vector([x, y]))), prec=prec,
|
|
2629
|
+
norm_type=norm_type, emb=emb)
|
|
2630
|
+
M = M*sm_m
|
|
2631
|
+
else:
|
|
2632
|
+
# solve the minimization problem for 'true' covariant
|
|
2633
|
+
z, th = covariant_z0(self(tuple(M * vector([x,y]))), prec=prec, emb=emb)
|
|
2634
|
+
z = CF(z)
|
|
2635
|
+
zc = z.center()
|
|
2636
|
+
# moves our z to fundamental domain as before
|
|
2637
|
+
while zc.real() < RF(-0.5) or zc.real() >= RF(0.5) or (zc.real() <= RF(0) and zc.abs() < RF(1))\
|
|
2638
|
+
or (zc.real() > RF(0) and zc.abs() <= RF(1)):
|
|
2639
|
+
if (zc.real() < RF(-0.5)) or (zc.real() >= RF(0.5)):
|
|
2640
|
+
# moves z into fundamental domain by m
|
|
2641
|
+
m = zc.real().round() # finds amount to move z's real part by
|
|
2642
|
+
Qm = QQ(m)
|
|
2643
|
+
M = M * matrix(QQ, [[1,Qm], [0,1]]) # move
|
|
2644
|
+
z -= m # M.inverse()*z is supposed to move z by m
|
|
2645
|
+
elif (zc.real() <= RF(0) and zc.abs() < RF(1)) or (zc.real() > RF(0) and zc.abs() <= RF(1)): # flips z
|
|
2646
|
+
z = -1/z
|
|
2647
|
+
M = M * matrix(QQ, [[0,-1], [1,0]])# multiply on left because we are taking inverse matrices
|
|
2648
|
+
zc = z.center()
|
|
2649
|
+
|
|
2650
|
+
if return_conjugation:
|
|
2651
|
+
return (self(tuple(M * vector([x,y]))), M)
|
|
2652
|
+
return self(tuple(M * vector([x,y])))
|
|
2653
|
+
|
|
2654
|
+
def is_unit(self) -> bool:
|
|
2655
|
+
r"""
|
|
2656
|
+
Return ``True`` if ``self`` is a unit, that is, has a
|
|
2657
|
+
multiplicative inverse.
|
|
2658
|
+
|
|
2659
|
+
EXAMPLES::
|
|
2660
|
+
|
|
2661
|
+
sage: # needs sage.rings.number_field
|
|
2662
|
+
sage: R.<x,y> = QQbar[]
|
|
2663
|
+
sage: (x + y).is_unit()
|
|
2664
|
+
False
|
|
2665
|
+
sage: R(0).is_unit()
|
|
2666
|
+
False
|
|
2667
|
+
sage: R(-1).is_unit()
|
|
2668
|
+
True
|
|
2669
|
+
sage: R(-1 + x).is_unit()
|
|
2670
|
+
False
|
|
2671
|
+
sage: R(2).is_unit()
|
|
2672
|
+
True
|
|
2673
|
+
|
|
2674
|
+
Check that :issue:`22454` is fixed::
|
|
2675
|
+
|
|
2676
|
+
sage: _.<x,y> = Zmod(4)[]
|
|
2677
|
+
sage: (1 + 2*x).is_unit()
|
|
2678
|
+
True
|
|
2679
|
+
sage: (x*y).is_unit()
|
|
2680
|
+
False
|
|
2681
|
+
sage: _.<x,y> = Zmod(36)[]
|
|
2682
|
+
sage: (7+ 6*x + 12*y - 18*x*y).is_unit()
|
|
2683
|
+
True
|
|
2684
|
+
"""
|
|
2685
|
+
# EXERCISE (Atiyah-McDonald, Ch 1): Let `A[x]` be a polynomial
|
|
2686
|
+
# ring in one variable. Then `f=\sum a_i x^i \in A[x]` is a unit\
|
|
2687
|
+
# if and only if `a_0` is a unit and `a_1,\ldots, a_n` are nilpotent.
|
|
2688
|
+
# (Also noted in Dummit and Foote, "Abstract Algebra", 1991,
|
|
2689
|
+
# Section 7.3 Exercise 33).
|
|
2690
|
+
# Also f is nilpotent if and only if all a_i are nilpotent.
|
|
2691
|
+
# This generalizes easily to the multivariate case, by considering
|
|
2692
|
+
# K[x,y,...] as K[x][y]...
|
|
2693
|
+
if not self.constant_coefficient().is_unit():
|
|
2694
|
+
return False
|
|
2695
|
+
cdef dict d = self.monomial_coefficients()
|
|
2696
|
+
cdef ETuple zero_key = ETuple({}, int(self.parent().ngens()))
|
|
2697
|
+
d.pop(zero_key, None)
|
|
2698
|
+
return all(d[k].is_nilpotent() for k in d)
|
|
2699
|
+
|
|
2700
|
+
def is_nilpotent(self):
|
|
2701
|
+
r"""
|
|
2702
|
+
Return ``True`` if ``self`` is nilpotent, i.e., some power of ``self``
|
|
2703
|
+
is 0.
|
|
2704
|
+
|
|
2705
|
+
EXAMPLES::
|
|
2706
|
+
|
|
2707
|
+
sage: R.<x,y> = QQbar[] # needs sage.rings.number_field
|
|
2708
|
+
sage: (x + y).is_nilpotent() # needs sage.rings.number_field
|
|
2709
|
+
False
|
|
2710
|
+
sage: R(0).is_nilpotent() # needs sage.rings.number_field
|
|
2711
|
+
True
|
|
2712
|
+
sage: _.<x,y> = Zmod(4)[]
|
|
2713
|
+
sage: (2*x).is_nilpotent()
|
|
2714
|
+
True
|
|
2715
|
+
sage: (2 + y*x).is_nilpotent()
|
|
2716
|
+
False
|
|
2717
|
+
sage: _.<x,y> = Zmod(36)[]
|
|
2718
|
+
sage: (4 + 6*x).is_nilpotent()
|
|
2719
|
+
False
|
|
2720
|
+
sage: (6*x + 12*y + 18*x*y + 24*(x^2+y^2)).is_nilpotent()
|
|
2721
|
+
True
|
|
2722
|
+
"""
|
|
2723
|
+
# EXERCISE (Atiyah-McDonald, Ch 1): Let `A[x]` be a polynomial
|
|
2724
|
+
# ring in one variable. Then `f=\sum a_i x^i \in A[x]` is
|
|
2725
|
+
# nilpotent if and only if `a_0,\ldots, a_n` are nilpotent.
|
|
2726
|
+
# (Also noted in Dummit and Foote, "Abstract Algebra", 1991,
|
|
2727
|
+
# Section 7.3 Exercise 33).
|
|
2728
|
+
# This generalizes easily to the multivariate case, by considering
|
|
2729
|
+
# K[x,y,...] as K[x][y]...
|
|
2730
|
+
d = self.monomial_coefficients()
|
|
2731
|
+
return all(c.is_nilpotent() for c in d.values())
|
|
2732
|
+
|
|
2733
|
+
def _test_subs(self, tester=None, **options):
|
|
2734
|
+
r"""
|
|
2735
|
+
Run some tests using the ``subs`` method.
|
|
2736
|
+
|
|
2737
|
+
TESTS::
|
|
2738
|
+
|
|
2739
|
+
sage: R.<x,y> = QQbar[] # needs sage.rings.number_field
|
|
2740
|
+
sage: (x + y)._test_subs() # needs sage.rings.number_field
|
|
2741
|
+
"""
|
|
2742
|
+
if tester is None:
|
|
2743
|
+
tester = self._tester(**options)
|
|
2744
|
+
|
|
2745
|
+
gens = self.parent().gens()
|
|
2746
|
+
|
|
2747
|
+
if gens:
|
|
2748
|
+
# substituting all variables (in a polynomial ring with variables) with 0
|
|
2749
|
+
d = {str(gen): self.base_ring().zero() for gen in gens}
|
|
2750
|
+
tester.assertEqual(self.subs(**d).parent(), self.parent().base_ring())
|
|
2751
|
+
|
|
2752
|
+
# substituting all variables (in a polynomial ring with variables)
|
|
2753
|
+
# with elements of another ring
|
|
2754
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
2755
|
+
other = PolynomialRing(self.parent().base_ring(), 'other', len(gens))
|
|
2756
|
+
other_gens = other.gens()
|
|
2757
|
+
d = {str(gen): other_gen for gen, other_gen in zip(gens, other_gens)}
|
|
2758
|
+
tester.assertEqual(self.subs(**d).parent(), other)
|
|
2759
|
+
|
|
2760
|
+
if len(gens) > 1:
|
|
2761
|
+
# substituting one variable (in a polynomial ring with variables) with 0
|
|
2762
|
+
d = {str(gens[0]): self.base_ring().zero()}
|
|
2763
|
+
tester.assertEqual(self.subs(**d).parent(), self.parent())
|
|
2764
|
+
|
|
2765
|
+
# test error checking: partial substitution by elements
|
|
2766
|
+
# from another ring is not allowed
|
|
2767
|
+
d = {str(gens[0]): other_gens[0]}
|
|
2768
|
+
with tester.assertRaises((ValueError, TypeError)):
|
|
2769
|
+
self.subs(**d)
|
|
2770
|
+
|
|
2771
|
+
def is_lorentzian(self, explain=False):
|
|
2772
|
+
r"""
|
|
2773
|
+
Return whether this is a Lorentzian polynomial.
|
|
2774
|
+
|
|
2775
|
+
INPUT:
|
|
2776
|
+
|
|
2777
|
+
- ``explain`` -- boolean (default: ``False``); if ``True``
|
|
2778
|
+
return a tuple whose first element is the boolean result of the test,
|
|
2779
|
+
and the second element is a string describing the reason the test failed,
|
|
2780
|
+
or ``None`` if the test succeeded.
|
|
2781
|
+
|
|
2782
|
+
Lorentzian polynomials are a class of polynomials connected with the area
|
|
2783
|
+
of discrete convex analysis. A polynomial `f` with positive real coefficients
|
|
2784
|
+
is Lorentzian if:
|
|
2785
|
+
|
|
2786
|
+
- `f` is homogeneous;
|
|
2787
|
+
|
|
2788
|
+
- the support of `f` is `M`-convex
|
|
2789
|
+
|
|
2790
|
+
- `f` has degree less than `2`, or if its degree is at least two,
|
|
2791
|
+
the collection of sequential partial derivatives of `f` which are
|
|
2792
|
+
quadratic forms have Gram matrices with at most one positive eigenvalue.
|
|
2793
|
+
|
|
2794
|
+
Note in particular that the zero polynomial is Lorentzian. Examples of
|
|
2795
|
+
Lorentzian polynomials include homogeneous stable polynomials, volume
|
|
2796
|
+
polynomials of convex bodies and projective varieties, and Schur polynomials
|
|
2797
|
+
after renormalizing the coefficient of each monomial `x^\alpha` by `1/\alpha!`.
|
|
2798
|
+
|
|
2799
|
+
EXAMPLES:
|
|
2800
|
+
|
|
2801
|
+
Renormalized Schur polynomials are Lorentzian, but not in general if the
|
|
2802
|
+
renormalization is skipped::
|
|
2803
|
+
|
|
2804
|
+
sage: P.<x,y> = QQ[]
|
|
2805
|
+
sage: p = (x^2 / 2) + x*y + (y^2 / 2)
|
|
2806
|
+
sage: p.is_lorentzian()
|
|
2807
|
+
True
|
|
2808
|
+
sage: p = x^2 + x*y + y^2
|
|
2809
|
+
sage: p.is_lorentzian()
|
|
2810
|
+
False
|
|
2811
|
+
|
|
2812
|
+
Homogeneous linear forms and constant polynomials with positive
|
|
2813
|
+
coefficients are Lorentzian, as well as the zero polynomial::
|
|
2814
|
+
|
|
2815
|
+
sage: p = x + 2*y
|
|
2816
|
+
sage: p.is_lorentzian()
|
|
2817
|
+
True
|
|
2818
|
+
sage: p = P(5)
|
|
2819
|
+
sage: p.is_lorentzian()
|
|
2820
|
+
True
|
|
2821
|
+
sage: P.zero().is_lorentzian()
|
|
2822
|
+
True
|
|
2823
|
+
|
|
2824
|
+
Inhomogeneous polynomials and polynomials with negative coefficients
|
|
2825
|
+
are not Lorentzian::
|
|
2826
|
+
|
|
2827
|
+
sage: p = x^2 + 2*x + y^2
|
|
2828
|
+
sage: p.is_lorentzian()
|
|
2829
|
+
False
|
|
2830
|
+
sage: p = 2*x^2 - y^2
|
|
2831
|
+
sage: p.is_lorentzian()
|
|
2832
|
+
False
|
|
2833
|
+
|
|
2834
|
+
It is an error to check if a polynomial is Lorentzian if its base ring
|
|
2835
|
+
is not a subring of the real numbers, as the notion is not defined in
|
|
2836
|
+
this case::
|
|
2837
|
+
|
|
2838
|
+
sage: # needs sage.rings.real_mpfr
|
|
2839
|
+
sage: Q.<z,w> = CC[]
|
|
2840
|
+
sage: q = z^2 + w^2
|
|
2841
|
+
sage: q.is_lorentzian()
|
|
2842
|
+
Traceback (most recent call last):
|
|
2843
|
+
...
|
|
2844
|
+
NotImplementedError: is_lorentzian only implemented for real polynomials
|
|
2845
|
+
|
|
2846
|
+
The method can give a reason for a polynomial failing to be Lorentzian::
|
|
2847
|
+
|
|
2848
|
+
sage: p = x^2 + 2*x + y^2
|
|
2849
|
+
sage: p.is_lorentzian(explain=True)
|
|
2850
|
+
(False, 'inhomogeneous')
|
|
2851
|
+
|
|
2852
|
+
REFERENCES:
|
|
2853
|
+
|
|
2854
|
+
For full definitions and related discussion, see [BrHu2019]_ and
|
|
2855
|
+
[HMMS2019]_. The second reference gives the characterization of
|
|
2856
|
+
Lorentzian polynomials applied in this implementation explicitly.
|
|
2857
|
+
"""
|
|
2858
|
+
from sage.rings.imaginary_unit import I
|
|
2859
|
+
|
|
2860
|
+
# function to handle return value when reason requested
|
|
2861
|
+
def result(val, explanation=None):
|
|
2862
|
+
return (val, explanation) if explain else val
|
|
2863
|
+
|
|
2864
|
+
try:
|
|
2865
|
+
# this would better be handled by a category of RealFields()
|
|
2866
|
+
self.base_ring()(I)
|
|
2867
|
+
except (ValueError, TypeError):
|
|
2868
|
+
pass
|
|
2869
|
+
else:
|
|
2870
|
+
raise NotImplementedError("is_lorentzian only implemented for real polynomials")
|
|
2871
|
+
|
|
2872
|
+
if self.is_zero():
|
|
2873
|
+
return result(True)
|
|
2874
|
+
|
|
2875
|
+
if not self.is_homogeneous():
|
|
2876
|
+
return result(False, "inhomogeneous")
|
|
2877
|
+
|
|
2878
|
+
if any(coeff < 0 for coeff in self.coefficients()):
|
|
2879
|
+
return result(False, "negative coefficient")
|
|
2880
|
+
|
|
2881
|
+
# for degree <= 1, homogeneous with positive coefficients is sufficient
|
|
2882
|
+
if self.degree() <= 1:
|
|
2883
|
+
return result(True)
|
|
2884
|
+
|
|
2885
|
+
# check support is M-convex
|
|
2886
|
+
if not _is_M_convex_(self.exponents()):
|
|
2887
|
+
return result(False, "not M-convex")
|
|
2888
|
+
|
|
2889
|
+
# compute quadratic forms coming from a sequence of partial derivatives
|
|
2890
|
+
if self.degree() == 2:
|
|
2891
|
+
quadratic_derivs = set([self])
|
|
2892
|
+
else:
|
|
2893
|
+
from sage.combinat.integer_lists.invlex import IntegerListsLex
|
|
2894
|
+
|
|
2895
|
+
gens = self.parent().gens()
|
|
2896
|
+
quadratic_derivs = set()
|
|
2897
|
+
multi_exponents = IntegerListsLex(self.degree() - 2, length=len(gens))
|
|
2898
|
+
for alpha in multi_exponents:
|
|
2899
|
+
# construct list [gen_1, exp_1, ..., gen_n, exp_n] for derivative function
|
|
2900
|
+
d_list = chain(*zip(gens, alpha))
|
|
2901
|
+
d = self.derivative(*d_list)
|
|
2902
|
+
quadratic_derivs.add(d)
|
|
2903
|
+
|
|
2904
|
+
# check derivative quadratic forms have at most one positive eigenvalue
|
|
2905
|
+
for deriv in quadratic_derivs:
|
|
2906
|
+
from sage.quadratic_forms.quadratic_form import QuadraticForm
|
|
2907
|
+
G = QuadraticForm(deriv).Gram_matrix()
|
|
2908
|
+
spectrum = sorted(G.eigenvalues(), reverse=True)
|
|
2909
|
+
if len(spectrum) > 1 and spectrum[1] > 0:
|
|
2910
|
+
return result(False, "multiple positive eigenvalues")
|
|
2911
|
+
|
|
2912
|
+
return result(True)
|
|
2913
|
+
|
|
2914
|
+
def crt(self, y, m, n):
|
|
2915
|
+
"""
|
|
2916
|
+
Return a polynomial congruent to ``self`` modulo ``m`` and
|
|
2917
|
+
to ``y`` modulo ``n``.
|
|
2918
|
+
|
|
2919
|
+
INPUT:
|
|
2920
|
+
|
|
2921
|
+
- ``y`` -- a polynomial in the same ring as ``self``
|
|
2922
|
+
- ``m``, ``n`` -- polynomials or ideals in the same ring as ``self``; ideals
|
|
2923
|
+
may also be specified as a list/tuple of generators
|
|
2924
|
+
|
|
2925
|
+
EXAMPLES::
|
|
2926
|
+
|
|
2927
|
+
sage: # needs sage.libs.singular
|
|
2928
|
+
sage: R.<x> = PolynomialRing(QQ, implementation="singular")
|
|
2929
|
+
sage: f = R(3)
|
|
2930
|
+
sage: f.crt(5, x-1, x-2) % ((x-1)*(x-2))
|
|
2931
|
+
2*x + 1
|
|
2932
|
+
sage: f.crt(5, R.ideal(x-1), [x-2]) % ((x-1)*(x-2))
|
|
2933
|
+
2*x + 1
|
|
2934
|
+
"""
|
|
2935
|
+
# could be moved up to ModuleElement as long as lift() is defined
|
|
2936
|
+
# the current definition of lift() requires ideal(), so maybe only RingElement
|
|
2937
|
+
R = self._parent
|
|
2938
|
+
y = R(y)
|
|
2939
|
+
m = R.ideal(m).gens()
|
|
2940
|
+
n = R.ideal(n).gens()
|
|
2941
|
+
# result == self - sum a_i * m_i == y + sum b_i * n_i
|
|
2942
|
+
# self - y == sum b_i * n_i + sum a_i * m_i
|
|
2943
|
+
ab_values = (self - y).lift(m + n)
|
|
2944
|
+
return R.sum([y] + [bi * ni for bi, ni in zip(ab_values[len(m):], n)])
|
|
2945
|
+
|
|
2946
|
+
def canonical_associate(self):
|
|
2947
|
+
"""
|
|
2948
|
+
Return a canonical associate.
|
|
2949
|
+
|
|
2950
|
+
EXAMPLES::
|
|
2951
|
+
|
|
2952
|
+
sage: R.<x,y>=QQ[]
|
|
2953
|
+
sage: (-2*x^2+3*x+5*y).canonical_associate()
|
|
2954
|
+
(x^2 - 3/2*x - 5/2*y, -2)
|
|
2955
|
+
sage: R.<x,y>=ZZ[]
|
|
2956
|
+
sage: (-2*x^2+3*x+5*y).canonical_associate()
|
|
2957
|
+
(2*x^2 - 3*x - 5*y, -1)
|
|
2958
|
+
"""
|
|
2959
|
+
lc = self.leading_coefficient()
|
|
2960
|
+
n, u = lc.canonical_associate()
|
|
2961
|
+
return (u.inverse_of_unit() * self, u)
|
|
2962
|
+
|
|
2963
|
+
|
|
2964
|
+
def _is_M_convex_(points) -> bool:
|
|
2965
|
+
r"""
|
|
2966
|
+
Return whether ``points`` represents a set of integer lattice points
|
|
2967
|
+
which are M-convex.
|
|
2968
|
+
|
|
2969
|
+
Utility function for method ``is_lorentzian``, which would more properly
|
|
2970
|
+
fit with code related to discrete convex geometry, generalized permutahedra,
|
|
2971
|
+
or polymatroids, which are not currently implemented in Sage.
|
|
2972
|
+
|
|
2973
|
+
INPUT:
|
|
2974
|
+
|
|
2975
|
+
- ``points`` -- iterable for a list of integer lattice points of the
|
|
2976
|
+
same dimension
|
|
2977
|
+
|
|
2978
|
+
Examples of M-convex sets include the vertices of a matroid polytope, and the
|
|
2979
|
+
support sets of Schur polynomials.
|
|
2980
|
+
|
|
2981
|
+
EXAMPLES:
|
|
2982
|
+
|
|
2983
|
+
The following points represent the vertices of a matroid polytope (indicator
|
|
2984
|
+
vectors of the bases) of rank `2` on five elements::
|
|
2985
|
+
|
|
2986
|
+
sage: from sage.rings.polynomial.multi_polynomial import _is_M_convex_
|
|
2987
|
+
sage: P = [[1,1,0,0], [1,0,1,0], [0,1,1,0], [0,1,0,1], [0,0,1,1]]
|
|
2988
|
+
sage: _is_M_convex_(P)
|
|
2989
|
+
True
|
|
2990
|
+
|
|
2991
|
+
These points are the support of the Schur polynomial in three variables for
|
|
2992
|
+
the partition `(2,2)`::
|
|
2993
|
+
|
|
2994
|
+
sage: P = [[2,2,0], [2,0,2], [0,2,2], [2,1,1], [1,2,1], [1,1,2]]
|
|
2995
|
+
sage: _is_M_convex_(P)
|
|
2996
|
+
True
|
|
2997
|
+
|
|
2998
|
+
The following are not examples of `M`-convex sets of points::
|
|
2999
|
+
|
|
3000
|
+
sage: P = [[1, 0, 0], [1, 1, 0], [1, 1, 1]]
|
|
3001
|
+
sage: _is_M_convex_(P)
|
|
3002
|
+
False
|
|
3003
|
+
|
|
3004
|
+
sage: P = [[0, 1, 2], [2, 1]]
|
|
3005
|
+
sage: _is_M_convex_(P)
|
|
3006
|
+
Traceback (most recent call last):
|
|
3007
|
+
...
|
|
3008
|
+
ValueError: input points are not the same dimension
|
|
3009
|
+
|
|
3010
|
+
sage: P = [[0, 0.5, 1], [1, 1.5, 2]]
|
|
3011
|
+
sage: _is_M_convex_(P)
|
|
3012
|
+
Traceback (most recent call last):
|
|
3013
|
+
...
|
|
3014
|
+
ValueError: input points are not integer lattice points
|
|
3015
|
+
|
|
3016
|
+
REFERENCES:
|
|
3017
|
+
|
|
3018
|
+
See [BrHu2019]_ for a definition of M-convexity.
|
|
3019
|
+
"""
|
|
3020
|
+
points_set = set(map(tuple, points))
|
|
3021
|
+
if not points_set:
|
|
3022
|
+
return True
|
|
3023
|
+
dim = len(next(iter(points_set)))
|
|
3024
|
+
if any(len(p) != dim for p in points_set):
|
|
3025
|
+
raise ValueError("input points are not the same dimension")
|
|
3026
|
+
if any(entry not in ZZ for p in points_set for entry in p):
|
|
3027
|
+
raise ValueError("input points are not integer lattice points")
|
|
3028
|
+
for p1 in points_set:
|
|
3029
|
+
list_p1 = list(p1)
|
|
3030
|
+
for p2 in points_set:
|
|
3031
|
+
if p2 == p1:
|
|
3032
|
+
continue
|
|
3033
|
+
for i in range(dim):
|
|
3034
|
+
if p2[i] > p1[i]:
|
|
3035
|
+
# modify list_p1 to represent point p1 + e_i - e_j for various i, j
|
|
3036
|
+
list_p1[i] += 1 # add e_i
|
|
3037
|
+
# check exchange condition is satisfied by some index j
|
|
3038
|
+
for j in range(dim):
|
|
3039
|
+
if p2[j] < p1[j]:
|
|
3040
|
+
list_p1[j] -= 1 # subtract e_j
|
|
3041
|
+
exch = tuple(list_p1) # p1 + e_i - e_j
|
|
3042
|
+
list_p1[j] += 1 # add e_j again
|
|
3043
|
+
if tuple(exch) in points_set:
|
|
3044
|
+
break
|
|
3045
|
+
else:
|
|
3046
|
+
return False
|
|
3047
|
+
list_p1[i] -= 1 # subtract e_i
|
|
3048
|
+
# list_p1 should now have same entries as p1 again
|
|
3049
|
+
return True
|
|
3050
|
+
|
|
3051
|
+
|
|
3052
|
+
cdef remove_from_tuple(e, int ind):
|
|
3053
|
+
w = list(e)
|
|
3054
|
+
del w[ind]
|
|
3055
|
+
if len(w) == 1:
|
|
3056
|
+
return w[0]
|
|
3057
|
+
else:
|
|
3058
|
+
return tuple(w)
|
|
3059
|
+
|
|
3060
|
+
|
|
3061
|
+
cdef class MPolynomial_libsingular(MPolynomial):
|
|
3062
|
+
r"""
|
|
3063
|
+
Abstract base class for :class:`~sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular`.
|
|
3064
|
+
|
|
3065
|
+
This class is defined for the purpose of :func:`isinstance` tests. It should not be
|
|
3066
|
+
instantiated.
|
|
3067
|
+
|
|
3068
|
+
EXAMPLES::
|
|
3069
|
+
|
|
3070
|
+
sage: from sage.rings.polynomial.multi_polynomial import MPolynomial_libsingular
|
|
3071
|
+
sage: R1.<x> = QQ[]
|
|
3072
|
+
sage: isinstance(x, MPolynomial_libsingular)
|
|
3073
|
+
False
|
|
3074
|
+
sage: R2.<y,z> = QQ[]
|
|
3075
|
+
sage: isinstance(y, MPolynomial_libsingular) # needs sage.libs.singular
|
|
3076
|
+
True
|
|
3077
|
+
|
|
3078
|
+
By design, there is a unique direct subclass::
|
|
3079
|
+
|
|
3080
|
+
sage: len(sage.rings.polynomial.multi_polynomial.MPolynomial_libsingular.__subclasses__()) <= 1
|
|
3081
|
+
True
|
|
3082
|
+
"""
|