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,2701 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
"""
|
|
3
|
+
Generic data structures for multivariate polynomials
|
|
4
|
+
|
|
5
|
+
This module provides an implementation of a generic data structure
|
|
6
|
+
:class:`PolyDict` and the underlying arithmetic for multi-variate polynomial
|
|
7
|
+
rings. It uses a sparse representation of polynomials encoded as a Python
|
|
8
|
+
dictionary where keys are exponents and values coefficients.
|
|
9
|
+
|
|
10
|
+
``{(e1,...,er):c1,...} <-> c1*x1^e1*...*xr^er+...``,
|
|
11
|
+
|
|
12
|
+
The exponent ``(e1,...,er)`` in this representation is an instance of the class
|
|
13
|
+
:class:`ETuple`.
|
|
14
|
+
|
|
15
|
+
AUTHORS:
|
|
16
|
+
|
|
17
|
+
- William Stein
|
|
18
|
+
- David Joyner
|
|
19
|
+
- Martin Albrecht (ETuple)
|
|
20
|
+
- Joel B. Mohler (2008-03-17) -- ETuple rewrite as sparse C array
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
# ****************************************************************************
|
|
24
|
+
# Copyright (C) 2005 William Stein <wstein@gmail.com>
|
|
25
|
+
# 2022 Vincent Delecroix <20100.delecroix@gmail.com>
|
|
26
|
+
#
|
|
27
|
+
# This program is free software: you can redistribute it and/or modify
|
|
28
|
+
# it under the terms of the GNU General Public License as published by
|
|
29
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
30
|
+
# (at your option) any later version.
|
|
31
|
+
# https://www.gnu.org/licenses/
|
|
32
|
+
# ****************************************************************************
|
|
33
|
+
|
|
34
|
+
from libc.string cimport memcpy
|
|
35
|
+
from cpython.dict cimport *
|
|
36
|
+
cimport cython
|
|
37
|
+
from cpython.object cimport (Py_EQ, Py_NE, Py_LT, Py_LE, Py_GT, Py_GE)
|
|
38
|
+
from cysignals.memory cimport sig_malloc, sig_free
|
|
39
|
+
|
|
40
|
+
from sage.structure.richcmp cimport rich_to_bool
|
|
41
|
+
|
|
42
|
+
from functools import reduce
|
|
43
|
+
from pprint import pformat
|
|
44
|
+
|
|
45
|
+
from sage.misc.latex import latex
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
cpdef int gen_index(PolyDict x) noexcept:
|
|
49
|
+
r"""
|
|
50
|
+
Return the index of the variable represented by ``x`` or ``-1`` if ``x``
|
|
51
|
+
is not a monomial of degree one.
|
|
52
|
+
|
|
53
|
+
EXAMPLES::
|
|
54
|
+
|
|
55
|
+
sage: from sage.rings.polynomial.polydict import PolyDict, gen_index
|
|
56
|
+
sage: gen_index(PolyDict({(1, 0): 1}))
|
|
57
|
+
0
|
|
58
|
+
sage: gen_index(PolyDict({(0, 1): 1}))
|
|
59
|
+
1
|
|
60
|
+
sage: gen_index(PolyDict({}))
|
|
61
|
+
-1
|
|
62
|
+
"""
|
|
63
|
+
if len(x.__repn) != 1:
|
|
64
|
+
return -1
|
|
65
|
+
cdef ETuple e = next(iter(x.__repn))
|
|
66
|
+
if e._nonzero != 1 or e._data[1] != 1:
|
|
67
|
+
return -1
|
|
68
|
+
if not next(iter(x.__repn.values())).is_one():
|
|
69
|
+
return -1
|
|
70
|
+
return e._data[0]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
cpdef ETuple monomial_exponent(PolyDict p):
|
|
74
|
+
r"""
|
|
75
|
+
Return the unique exponent of ``p`` if it is a monomial or raise a
|
|
76
|
+
:exc:`ValueError`.
|
|
77
|
+
|
|
78
|
+
EXAMPLES::
|
|
79
|
+
|
|
80
|
+
sage: from sage.rings.polynomial.polydict import PolyDict, monomial_exponent
|
|
81
|
+
sage: monomial_exponent(PolyDict({(2, 3): 1}))
|
|
82
|
+
(2, 3)
|
|
83
|
+
sage: monomial_exponent(PolyDict({(2, 3): 3}))
|
|
84
|
+
Traceback (most recent call last):
|
|
85
|
+
...
|
|
86
|
+
ValueError: not a monomial
|
|
87
|
+
sage: monomial_exponent(PolyDict({(1, 0): 1, (0, 1): 1}))
|
|
88
|
+
Traceback (most recent call last):
|
|
89
|
+
...
|
|
90
|
+
ValueError: not a monomial
|
|
91
|
+
"""
|
|
92
|
+
if len(p.__repn) != 1 or not next(iter(p.__repn.values())).is_one():
|
|
93
|
+
raise ValueError('not a monomial')
|
|
94
|
+
return next(iter(p.__repn))
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
cdef class PolyDict:
|
|
98
|
+
r"""
|
|
99
|
+
Data structure for multivariate polynomials.
|
|
100
|
+
|
|
101
|
+
A PolyDict holds a dictionary all of whose keys are :class:`ETuple` and
|
|
102
|
+
whose values are coefficients on which it is implicitely assumed that
|
|
103
|
+
arithmetic operations can be performed.
|
|
104
|
+
|
|
105
|
+
No arithmetic operation on :class:`PolyDict` clear zero coefficients as of
|
|
106
|
+
now there is no reliable way of testing it in the most general setting, see
|
|
107
|
+
:issue:`35319`. For removing zero coefficients from a :class:`PolyDict` you
|
|
108
|
+
can use the method :meth:`remove_zeros` which can be parametrized by a zero
|
|
109
|
+
test.
|
|
110
|
+
"""
|
|
111
|
+
def __init__(self, pdict, zero=None, remove_zero=None, force_int_exponents=None, force_etuples=None, bint check=True):
|
|
112
|
+
"""
|
|
113
|
+
INPUT:
|
|
114
|
+
|
|
115
|
+
- ``pdict`` -- dictionary or list, which represents a multi-variable
|
|
116
|
+
polynomial with the distribute representation (a copy is made)
|
|
117
|
+
|
|
118
|
+
- ``zero`` -- deprecated
|
|
119
|
+
|
|
120
|
+
- ``remove_zero`` -- deprecated
|
|
121
|
+
|
|
122
|
+
- ``force_int_exponents`` -- deprecated
|
|
123
|
+
|
|
124
|
+
- ``force_etuples`` -- deprecated
|
|
125
|
+
|
|
126
|
+
- ``check`` -- if set to ``False`` then assumes that the exponents are
|
|
127
|
+
all valid ``ETuple``; in that case the construction is a bit faster
|
|
128
|
+
|
|
129
|
+
EXAMPLES::
|
|
130
|
+
|
|
131
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
132
|
+
sage: PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
133
|
+
PolyDict with representation {(1, 2): 3, (2, 1): 4, (2, 3): 2}
|
|
134
|
+
|
|
135
|
+
sage: PolyDict({(2, 3): 0, (1, 2): 3, (2, 1): 4})
|
|
136
|
+
PolyDict with representation {(1, 2): 3, (2, 1): 4, (2, 3): 0}
|
|
137
|
+
|
|
138
|
+
sage: PolyDict({(0, 0): RIF(-1,1)}) # needs sage.rings.real_interval_field
|
|
139
|
+
PolyDict with representation {(0, 0): 0.?}
|
|
140
|
+
|
|
141
|
+
TESTS::
|
|
142
|
+
|
|
143
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
144
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
145
|
+
sage: len(f)
|
|
146
|
+
3
|
|
147
|
+
sage: f = PolyDict({}, zero=3, force_int_exponents=True, force_etuples=True)
|
|
148
|
+
doctest:warning
|
|
149
|
+
...
|
|
150
|
+
DeprecationWarning: the arguments "zero", "forced_int_exponents"
|
|
151
|
+
and "forced_etuples" of PolyDict constructor are deprecated
|
|
152
|
+
See https://github.com/sagemath/sage/issues/34000 for details.
|
|
153
|
+
sage: f = PolyDict({}, remove_zero=False)
|
|
154
|
+
doctest:warning
|
|
155
|
+
...
|
|
156
|
+
DeprecationWarning: the argument "remove_zero" of PolyDict
|
|
157
|
+
constructor is deprecated; call the method remove_zeros
|
|
158
|
+
See https://github.com/sagemath/sage/issues/34000 for details.
|
|
159
|
+
"""
|
|
160
|
+
if zero is not None or force_int_exponents is not None or force_etuples is not None:
|
|
161
|
+
from sage.misc.superseded import deprecation
|
|
162
|
+
deprecation(34000, 'the arguments "zero", "forced_int_exponents" and "forced_etuples" of PolyDict constructor are deprecated')
|
|
163
|
+
|
|
164
|
+
self.__repn = {}
|
|
165
|
+
cdef bint has_only_etuple = True
|
|
166
|
+
if isinstance(pdict, (tuple, list)):
|
|
167
|
+
for coeff, exp in pdict:
|
|
168
|
+
if check and type(exp) is not ETuple:
|
|
169
|
+
exp = ETuple(exp)
|
|
170
|
+
self.__repn[exp] = coeff
|
|
171
|
+
elif isinstance(pdict, dict):
|
|
172
|
+
if check:
|
|
173
|
+
for k in (<dict> pdict):
|
|
174
|
+
if type(k) is not ETuple:
|
|
175
|
+
has_only_etuple = False
|
|
176
|
+
break
|
|
177
|
+
if has_only_etuple:
|
|
178
|
+
self.__repn = (<dict> pdict).copy()
|
|
179
|
+
else:
|
|
180
|
+
self.__repn = {}
|
|
181
|
+
for exp, coeff in pdict.items():
|
|
182
|
+
if type(exp) is not ETuple:
|
|
183
|
+
exp = ETuple(exp)
|
|
184
|
+
self.__repn[exp] = coeff
|
|
185
|
+
else:
|
|
186
|
+
raise TypeError("pdict must be a dict or a list of pairs (coeff, exponent)")
|
|
187
|
+
|
|
188
|
+
if remove_zero is not None:
|
|
189
|
+
from sage.misc.superseded import deprecation
|
|
190
|
+
deprecation(34000, 'the argument "remove_zero" of PolyDict constructor is deprecated; call the method remove_zeros')
|
|
191
|
+
if remove_zero:
|
|
192
|
+
self.remove_zeros()
|
|
193
|
+
|
|
194
|
+
cdef PolyDict _new(self, dict pdict):
|
|
195
|
+
cdef PolyDict ans = PolyDict.__new__(PolyDict)
|
|
196
|
+
ans.__repn = pdict
|
|
197
|
+
return ans
|
|
198
|
+
|
|
199
|
+
cpdef remove_zeros(self, zero_test=None):
|
|
200
|
+
r"""
|
|
201
|
+
Remove the entries with zero coefficients.
|
|
202
|
+
|
|
203
|
+
INPUT:
|
|
204
|
+
|
|
205
|
+
- ``zero_test`` -- (optional) function that performs test to zero of a coefficient
|
|
206
|
+
|
|
207
|
+
EXAMPLES::
|
|
208
|
+
|
|
209
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
210
|
+
sage: f = PolyDict({(2, 3):0})
|
|
211
|
+
sage: f
|
|
212
|
+
PolyDict with representation {(2, 3): 0}
|
|
213
|
+
sage: f.remove_zeros()
|
|
214
|
+
sage: f
|
|
215
|
+
PolyDict with representation {}
|
|
216
|
+
|
|
217
|
+
The following example shows how to remove only exact zeros from a ``PolyDict``
|
|
218
|
+
containing univariate power series::
|
|
219
|
+
|
|
220
|
+
sage: R.<t> = PowerSeriesRing(QQ)
|
|
221
|
+
sage: f = PolyDict({(1, 1): O(t), (1, 0): R.zero()})
|
|
222
|
+
sage: f.remove_zeros(lambda s: s.is_zero() and s.prec() is Infinity)
|
|
223
|
+
sage: f
|
|
224
|
+
PolyDict with representation {(1, 1): O(t^1)}
|
|
225
|
+
"""
|
|
226
|
+
if not self.__repn:
|
|
227
|
+
return
|
|
228
|
+
# NOTE: in each of the conditional statements below, what the first
|
|
229
|
+
# loop does is equivalent to
|
|
230
|
+
#
|
|
231
|
+
# if all(self.__repn.values()):
|
|
232
|
+
# return
|
|
233
|
+
#
|
|
234
|
+
# and
|
|
235
|
+
#
|
|
236
|
+
# if all(not zero_test(coeff) for coeff in self.__repn.values()):
|
|
237
|
+
# return
|
|
238
|
+
#
|
|
239
|
+
# However, 'all(...)' is badly handled by the Cython compiler and we
|
|
240
|
+
# rather unfold it for efficiency.
|
|
241
|
+
cdef bint has_zero_coefficient = False
|
|
242
|
+
if zero_test is None:
|
|
243
|
+
for coeff in self.__repn.values():
|
|
244
|
+
if not coeff:
|
|
245
|
+
has_zero_coefficient = True
|
|
246
|
+
break
|
|
247
|
+
if not has_zero_coefficient:
|
|
248
|
+
return
|
|
249
|
+
for k in list(self.__repn):
|
|
250
|
+
if not self.__repn[k]:
|
|
251
|
+
del self.__repn[k]
|
|
252
|
+
else:
|
|
253
|
+
for coeff in self.__repn.values():
|
|
254
|
+
if zero_test(coeff):
|
|
255
|
+
has_zero_coefficient = True
|
|
256
|
+
break
|
|
257
|
+
if not has_zero_coefficient:
|
|
258
|
+
return
|
|
259
|
+
for k in list(self.__repn):
|
|
260
|
+
if zero_test(self.__repn[k]):
|
|
261
|
+
del self.__repn[k]
|
|
262
|
+
|
|
263
|
+
def apply_map(self, f):
|
|
264
|
+
r"""
|
|
265
|
+
Apply the map ``f`` on the coefficients (inplace).
|
|
266
|
+
|
|
267
|
+
EXAMPLES::
|
|
268
|
+
|
|
269
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
270
|
+
sage: f = PolyDict({(1, 0): 1, (1, 1): -2})
|
|
271
|
+
sage: f.apply_map(lambda x: x^2)
|
|
272
|
+
sage: f
|
|
273
|
+
PolyDict with representation {(1, 0): 1, (1, 1): 4}
|
|
274
|
+
"""
|
|
275
|
+
for k, v in self.__repn.items():
|
|
276
|
+
self.__repn[k] = f(v)
|
|
277
|
+
|
|
278
|
+
def coerce_coefficients(self, A):
|
|
279
|
+
r"""
|
|
280
|
+
Coerce the coefficients in the parent ``A``.
|
|
281
|
+
|
|
282
|
+
EXAMPLES::
|
|
283
|
+
|
|
284
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
285
|
+
sage: f = PolyDict({(2, 3): 0})
|
|
286
|
+
sage: f
|
|
287
|
+
PolyDict with representation {(2, 3): 0}
|
|
288
|
+
sage: f.coerce_coefficients(QQ)
|
|
289
|
+
doctest:warning
|
|
290
|
+
...
|
|
291
|
+
DeprecationWarning: coerce_cefficients is deprecated; use apply_map instead
|
|
292
|
+
See https://github.com/sagemath/sage/issues/34000 for details.
|
|
293
|
+
sage: f
|
|
294
|
+
PolyDict with representation {(2, 3): 0}
|
|
295
|
+
"""
|
|
296
|
+
from sage.misc.superseded import deprecation
|
|
297
|
+
deprecation(34000, 'coerce_cefficients is deprecated; use apply_map instead')
|
|
298
|
+
self.apply_map(A.coerce)
|
|
299
|
+
|
|
300
|
+
def __hash__(self):
|
|
301
|
+
"""
|
|
302
|
+
Return the hash.
|
|
303
|
+
|
|
304
|
+
EXAMPLES::
|
|
305
|
+
|
|
306
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
307
|
+
sage: PD1 = PolyDict({(2, 3): 0, (1, 2): 3, (2, 1): 4})
|
|
308
|
+
sage: PD2 = PolyDict({(2, 3): 0, (1, 2): 3, (2, 1): 4})
|
|
309
|
+
sage: PD3 = PolyDict({(2, 3): 1, (1, 2): 3, (2, 1): 4})
|
|
310
|
+
sage: hash(PD1) == hash(PD2)
|
|
311
|
+
True
|
|
312
|
+
sage: hash(PD1) == hash(PD3)
|
|
313
|
+
False
|
|
314
|
+
"""
|
|
315
|
+
return hash(frozenset(self.__repn.items()))
|
|
316
|
+
|
|
317
|
+
def __bool__(self):
|
|
318
|
+
"""
|
|
319
|
+
Return whether the PolyDict is empty.
|
|
320
|
+
|
|
321
|
+
EXAMPLES::
|
|
322
|
+
|
|
323
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
324
|
+
sage: PD1 = PolyDict({(2, 3): 0, (1, 2): 3, (2, 1): 4})
|
|
325
|
+
sage: bool(PD1)
|
|
326
|
+
True
|
|
327
|
+
"""
|
|
328
|
+
return bool(self.__repn)
|
|
329
|
+
|
|
330
|
+
def __len__(self):
|
|
331
|
+
"""
|
|
332
|
+
Return the number of terms of this polynomial.
|
|
333
|
+
|
|
334
|
+
EXAMPLES::
|
|
335
|
+
|
|
336
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
337
|
+
sage: PD1 = PolyDict({(2, 3): 0, (1, 2): 3, (2, 1): 4})
|
|
338
|
+
sage: len(PD1)
|
|
339
|
+
3
|
|
340
|
+
"""
|
|
341
|
+
return len(self.__repn)
|
|
342
|
+
|
|
343
|
+
def __richcmp__(PolyDict left, PolyDict right, int op):
|
|
344
|
+
"""
|
|
345
|
+
Implement the ``__richcmp__`` protocol for `PolyDict`s.
|
|
346
|
+
|
|
347
|
+
EXAMPLES::
|
|
348
|
+
|
|
349
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
350
|
+
sage: p1 = PolyDict({(0,): 1})
|
|
351
|
+
sage: p2 = PolyDict({(0,): 2})
|
|
352
|
+
sage: p1 == p2
|
|
353
|
+
False
|
|
354
|
+
sage: p1 < p2
|
|
355
|
+
Traceback (most recent call last):
|
|
356
|
+
...
|
|
357
|
+
TypeError: unsupported comparison between PolyDict
|
|
358
|
+
"""
|
|
359
|
+
if op == Py_EQ:
|
|
360
|
+
return left.__repn == right.__repn
|
|
361
|
+
elif op == Py_NE:
|
|
362
|
+
return left.__repn != right.__repn
|
|
363
|
+
|
|
364
|
+
raise TypeError('unsupported comparison between PolyDict')
|
|
365
|
+
|
|
366
|
+
def rich_compare(self, PolyDict other, int op, sortkey=None):
|
|
367
|
+
"""
|
|
368
|
+
Compare two `PolyDict`s using a specified term ordering ``sortkey``.
|
|
369
|
+
|
|
370
|
+
EXAMPLES::
|
|
371
|
+
|
|
372
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
373
|
+
sage: from sage.structure.richcmp import op_EQ, op_NE, op_LT
|
|
374
|
+
sage: p1 = PolyDict({(0,): 1})
|
|
375
|
+
sage: p2 = PolyDict({(0,): 2})
|
|
376
|
+
sage: O = TermOrder()
|
|
377
|
+
sage: p1.rich_compare(PolyDict({(0,): 1}), op_EQ, O.sortkey)
|
|
378
|
+
True
|
|
379
|
+
sage: p1.rich_compare(p2, op_EQ, O.sortkey)
|
|
380
|
+
False
|
|
381
|
+
sage: p1.rich_compare(p2, op_NE, O.sortkey)
|
|
382
|
+
True
|
|
383
|
+
sage: p1.rich_compare(p2, op_LT, O.sortkey)
|
|
384
|
+
True
|
|
385
|
+
|
|
386
|
+
sage: p3 = PolyDict({(3, 2, 4): 1, (3, 2, 5): 2})
|
|
387
|
+
sage: p4 = PolyDict({(3, 2, 4): 1, (3, 2, 3): 2})
|
|
388
|
+
sage: p3.rich_compare(p4, op_LT, O.sortkey)
|
|
389
|
+
False
|
|
390
|
+
|
|
391
|
+
TESTS::
|
|
392
|
+
|
|
393
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
394
|
+
sage: from sage.structure.richcmp import op_EQ, op_NE, op_LT
|
|
395
|
+
sage: p = PolyDict({})
|
|
396
|
+
sage: ans = p.rich_compare(p, op_EQ)
|
|
397
|
+
doctest:warning
|
|
398
|
+
...
|
|
399
|
+
DeprecationWarning: the argument "sortkey" will become mandatory in future sage versions
|
|
400
|
+
See https://github.com/sagemath/sage/issues/34000 for details.
|
|
401
|
+
sage: ans
|
|
402
|
+
True
|
|
403
|
+
"""
|
|
404
|
+
if sortkey is None:
|
|
405
|
+
from sage.misc.superseded import deprecation
|
|
406
|
+
deprecation(34000, 'the argument "sortkey" will become mandatory in future sage versions')
|
|
407
|
+
|
|
408
|
+
if op == Py_EQ:
|
|
409
|
+
return self.__repn == other.__repn
|
|
410
|
+
elif op == Py_NE:
|
|
411
|
+
return self.__repn != other.__repn
|
|
412
|
+
|
|
413
|
+
if sortkey is None:
|
|
414
|
+
raise TypeError("ordering of PolyDicts requires a sortkey")
|
|
415
|
+
|
|
416
|
+
# start with biggest
|
|
417
|
+
cdef list left = sorted(self.__repn, key=sortkey, reverse=True)
|
|
418
|
+
cdef list right = sorted(other.__repn, key=sortkey, reverse=True)
|
|
419
|
+
|
|
420
|
+
cdef size_t i
|
|
421
|
+
for i in range(min(len(left), len(right))):
|
|
422
|
+
m = left[i]
|
|
423
|
+
n = right[i]
|
|
424
|
+
keym = sortkey(m)
|
|
425
|
+
keyn = sortkey(n)
|
|
426
|
+
|
|
427
|
+
# first compare the leading monomials
|
|
428
|
+
if keym > keyn:
|
|
429
|
+
return rich_to_bool(op, 1)
|
|
430
|
+
elif keym < keyn:
|
|
431
|
+
return rich_to_bool(op, -1)
|
|
432
|
+
|
|
433
|
+
# same leading monomial, compare their coefficients
|
|
434
|
+
coefm = self.__repn[m]
|
|
435
|
+
coefn = other.__repn[n]
|
|
436
|
+
if coefm > coefn:
|
|
437
|
+
return rich_to_bool(op, 1)
|
|
438
|
+
elif coefm < coefn:
|
|
439
|
+
return rich_to_bool(op, -1)
|
|
440
|
+
|
|
441
|
+
return rich_to_bool(op, (len(left) > len(right)) - (len(left) < len(right)))
|
|
442
|
+
|
|
443
|
+
def list(self):
|
|
444
|
+
"""
|
|
445
|
+
Return a list that defines ``self``.
|
|
446
|
+
|
|
447
|
+
EXAMPLES::
|
|
448
|
+
|
|
449
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
450
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
451
|
+
sage: sorted(f.list())
|
|
452
|
+
[[2, [2, 3]], [3, [1, 2]], [4, [2, 1]]]
|
|
453
|
+
"""
|
|
454
|
+
return [[c, list(e)] for e, c in self.__repn.items()]
|
|
455
|
+
|
|
456
|
+
def dict(self):
|
|
457
|
+
"""
|
|
458
|
+
Return a copy of the dict that defines ``self``.
|
|
459
|
+
|
|
460
|
+
EXAMPLES::
|
|
461
|
+
|
|
462
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
463
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
464
|
+
sage: f.dict()
|
|
465
|
+
{(1, 2): 3, (2, 1): 4, (2, 3): 2}
|
|
466
|
+
"""
|
|
467
|
+
return self.__repn.copy()
|
|
468
|
+
|
|
469
|
+
def coefficients(self):
|
|
470
|
+
"""
|
|
471
|
+
Return the coefficients of ``self``.
|
|
472
|
+
|
|
473
|
+
EXAMPLES::
|
|
474
|
+
|
|
475
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
476
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
477
|
+
sage: sorted(f.coefficients())
|
|
478
|
+
[2, 3, 4]
|
|
479
|
+
"""
|
|
480
|
+
return list(self.__repn.values())
|
|
481
|
+
|
|
482
|
+
def exponents(self):
|
|
483
|
+
"""
|
|
484
|
+
Return the exponents of ``self``.
|
|
485
|
+
|
|
486
|
+
EXAMPLES::
|
|
487
|
+
|
|
488
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
489
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
490
|
+
sage: sorted(f.exponents())
|
|
491
|
+
[(1, 2), (2, 1), (2, 3)]
|
|
492
|
+
"""
|
|
493
|
+
return list(self.__repn)
|
|
494
|
+
|
|
495
|
+
def __getitem__(self, e):
|
|
496
|
+
"""
|
|
497
|
+
Return a coefficient of the polynomial.
|
|
498
|
+
|
|
499
|
+
EXAMPLES::
|
|
500
|
+
|
|
501
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
502
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
503
|
+
sage: f[1, 2]
|
|
504
|
+
3
|
|
505
|
+
sage: f[(2, 1)]
|
|
506
|
+
4
|
|
507
|
+
"""
|
|
508
|
+
if type(e) is not ETuple:
|
|
509
|
+
e = ETuple(e)
|
|
510
|
+
return self.__repn[e]
|
|
511
|
+
|
|
512
|
+
def get(self, ETuple e, default=None):
|
|
513
|
+
r"""
|
|
514
|
+
Return the coefficient of the ETuple ``e`` if present and ``default`` otherwise.
|
|
515
|
+
|
|
516
|
+
EXAMPLES::
|
|
517
|
+
|
|
518
|
+
sage: from sage.rings.polynomial.polydict import PolyDict, ETuple
|
|
519
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
520
|
+
sage: f.get(ETuple([1,2]))
|
|
521
|
+
3
|
|
522
|
+
sage: f.get(ETuple([1,1]), 'hello')
|
|
523
|
+
'hello'
|
|
524
|
+
"""
|
|
525
|
+
return self.__repn.get(e, default)
|
|
526
|
+
|
|
527
|
+
def __repr__(self):
|
|
528
|
+
r"""
|
|
529
|
+
String representation.
|
|
530
|
+
"""
|
|
531
|
+
repn = ' '.join(pformat(self.__repn).splitlines())
|
|
532
|
+
return 'PolyDict with representation %s' % repn
|
|
533
|
+
|
|
534
|
+
def degree(self, PolyDict x=None):
|
|
535
|
+
r"""
|
|
536
|
+
Return the total degree or the maximum degree in the variable ``x``.
|
|
537
|
+
|
|
538
|
+
EXAMPLES::
|
|
539
|
+
|
|
540
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
541
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
542
|
+
sage: f.degree()
|
|
543
|
+
5
|
|
544
|
+
sage: f.degree(PolyDict({(1, 0): 1}))
|
|
545
|
+
2
|
|
546
|
+
sage: f.degree(PolyDict({(0, 1): 1}))
|
|
547
|
+
3
|
|
548
|
+
"""
|
|
549
|
+
if x is None:
|
|
550
|
+
return self.total_degree()
|
|
551
|
+
cdef int i = gen_index(x)
|
|
552
|
+
if i < 0:
|
|
553
|
+
raise ValueError('x must be a generator')
|
|
554
|
+
if not self.__repn:
|
|
555
|
+
return -1
|
|
556
|
+
return max((<ETuple> e).get_exp(i) for e in self.__repn)
|
|
557
|
+
|
|
558
|
+
def total_degree(self, tuple w=None):
|
|
559
|
+
r"""
|
|
560
|
+
Return the total degree.
|
|
561
|
+
|
|
562
|
+
INPUT:
|
|
563
|
+
|
|
564
|
+
- ``w`` -- (optional) a tuple of weights
|
|
565
|
+
|
|
566
|
+
EXAMPLES::
|
|
567
|
+
|
|
568
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
569
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
570
|
+
sage: f.total_degree()
|
|
571
|
+
5
|
|
572
|
+
sage: f.total_degree((3, 1))
|
|
573
|
+
9
|
|
574
|
+
sage: PolyDict({}).degree()
|
|
575
|
+
-1
|
|
576
|
+
"""
|
|
577
|
+
if not self.__repn:
|
|
578
|
+
return -1
|
|
579
|
+
if w is None:
|
|
580
|
+
return max((<ETuple> e).unweighted_degree() for e in self.__repn)
|
|
581
|
+
else:
|
|
582
|
+
return max((<ETuple> e).weighted_degree(w) for e in self.__repn)
|
|
583
|
+
|
|
584
|
+
def monomial_coefficient(self, mon):
|
|
585
|
+
"""
|
|
586
|
+
Return the coefficient of the monomial ``mon``.
|
|
587
|
+
|
|
588
|
+
INPUT:
|
|
589
|
+
|
|
590
|
+
- ``mon`` -- a PolyDict with a single key
|
|
591
|
+
|
|
592
|
+
EXAMPLES::
|
|
593
|
+
|
|
594
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
595
|
+
sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4})
|
|
596
|
+
sage: f.monomial_coefficient(PolyDict({(2,1):1}).dict())
|
|
597
|
+
doctest:warning
|
|
598
|
+
...
|
|
599
|
+
DeprecationWarning: PolyDict.monomial_coefficient is deprecated; use PolyDict.get instead
|
|
600
|
+
See https://github.com/sagemath/sage/issues/34000 for details.
|
|
601
|
+
4
|
|
602
|
+
"""
|
|
603
|
+
from sage.misc.superseded import deprecation
|
|
604
|
+
deprecation(34000, 'PolyDict.monomial_coefficient is deprecated; use PolyDict.get instead')
|
|
605
|
+
K, = mon.keys()
|
|
606
|
+
if K not in self.__repn:
|
|
607
|
+
return 0
|
|
608
|
+
return self.__repn[K]
|
|
609
|
+
|
|
610
|
+
def polynomial_coefficient(self, degrees):
|
|
611
|
+
"""
|
|
612
|
+
Return a polydict that defines the coefficient in the current
|
|
613
|
+
polynomial viewed as a tower of polynomial extensions.
|
|
614
|
+
|
|
615
|
+
INPUT:
|
|
616
|
+
|
|
617
|
+
- ``degrees`` -- list of degree restrictions; list elements are ``None``
|
|
618
|
+
if the variable in that position should be unrestricted
|
|
619
|
+
|
|
620
|
+
EXAMPLES::
|
|
621
|
+
|
|
622
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
623
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
624
|
+
sage: f.polynomial_coefficient([2, None])
|
|
625
|
+
PolyDict with representation {(0, 1): 4, (0, 3): 2}
|
|
626
|
+
sage: f = PolyDict({(0, 3): 2, (0, 2): 3, (2, 1): 4})
|
|
627
|
+
sage: f.polynomial_coefficient([0, None])
|
|
628
|
+
PolyDict with representation {(0, 2): 3, (0, 3): 2}
|
|
629
|
+
"""
|
|
630
|
+
nz = []
|
|
631
|
+
cdef int i
|
|
632
|
+
for i in range(len(degrees)):
|
|
633
|
+
if degrees[i] is not None:
|
|
634
|
+
nz.append(i)
|
|
635
|
+
cdef dict ans = {}
|
|
636
|
+
cdef bint exactly_divides
|
|
637
|
+
for S in self.__repn:
|
|
638
|
+
exactly_divides = True
|
|
639
|
+
for j in nz:
|
|
640
|
+
if S[j] != degrees[j]:
|
|
641
|
+
exactly_divides = False
|
|
642
|
+
break
|
|
643
|
+
if exactly_divides:
|
|
644
|
+
t = list(S)
|
|
645
|
+
for m in nz:
|
|
646
|
+
t[m] = 0
|
|
647
|
+
ans[ETuple(t)] = self.__repn[S]
|
|
648
|
+
return self._new(ans)
|
|
649
|
+
|
|
650
|
+
def coefficient(self, mon):
|
|
651
|
+
"""
|
|
652
|
+
Return a polydict that defines a polynomial in 1 less number
|
|
653
|
+
of variables that gives the coefficient of mon in this
|
|
654
|
+
polynomial.
|
|
655
|
+
|
|
656
|
+
The coefficient is defined as follows. If f is this
|
|
657
|
+
polynomial, then the coefficient is the sum T/mon where the
|
|
658
|
+
sum is over terms T in f that are exactly divisible by mon.
|
|
659
|
+
"""
|
|
660
|
+
K, = mon.keys()
|
|
661
|
+
nz = K.nonzero_positions() # set([i for i in range(len(K)) if K[i] != 0])
|
|
662
|
+
ans = {}
|
|
663
|
+
for S in self.__repn:
|
|
664
|
+
exactly_divides = True
|
|
665
|
+
for j in nz:
|
|
666
|
+
if S[j] != K[j]:
|
|
667
|
+
exactly_divides = False
|
|
668
|
+
break
|
|
669
|
+
if exactly_divides:
|
|
670
|
+
t = list(S)
|
|
671
|
+
for m in nz:
|
|
672
|
+
t[m] = 0
|
|
673
|
+
ans[ETuple(t)] = self.__repn[S]
|
|
674
|
+
return self._new(ans)
|
|
675
|
+
|
|
676
|
+
def is_homogeneous(self, tuple w=None):
|
|
677
|
+
r"""
|
|
678
|
+
Return whether this polynomial is homogeneous.
|
|
679
|
+
|
|
680
|
+
EXAMPLES::
|
|
681
|
+
|
|
682
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
683
|
+
sage: PolyDict({}).is_homogeneous()
|
|
684
|
+
True
|
|
685
|
+
sage: PolyDict({(1, 2): 1, (0, 3): -2}).is_homogeneous()
|
|
686
|
+
True
|
|
687
|
+
sage: PolyDict({(1, 0): 1, (1, 2): 3}).is_homogeneous()
|
|
688
|
+
False
|
|
689
|
+
"""
|
|
690
|
+
if not self.__repn:
|
|
691
|
+
return True
|
|
692
|
+
cdef size_t s
|
|
693
|
+
it = iter(self.__repn)
|
|
694
|
+
if w is None:
|
|
695
|
+
s = (<ETuple> next(it)).unweighted_degree()
|
|
696
|
+
for elt in it:
|
|
697
|
+
if (<ETuple> elt).unweighted_degree() != s:
|
|
698
|
+
return False
|
|
699
|
+
return True
|
|
700
|
+
else:
|
|
701
|
+
s = (<ETuple> next(it)).weighted_degree(w)
|
|
702
|
+
for elt in it:
|
|
703
|
+
if (<ETuple> elt).weighted_degree(w) != s:
|
|
704
|
+
return False
|
|
705
|
+
return True
|
|
706
|
+
|
|
707
|
+
def is_constant(self):
|
|
708
|
+
"""
|
|
709
|
+
Return whether this polynomial is constant.
|
|
710
|
+
|
|
711
|
+
EXAMPLES::
|
|
712
|
+
|
|
713
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
714
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
715
|
+
sage: f.is_constant()
|
|
716
|
+
False
|
|
717
|
+
sage: g = PolyDict({(0, 0): 2})
|
|
718
|
+
sage: g.is_constant()
|
|
719
|
+
True
|
|
720
|
+
sage: h = PolyDict({})
|
|
721
|
+
sage: h.is_constant()
|
|
722
|
+
True
|
|
723
|
+
"""
|
|
724
|
+
if not self.__repn:
|
|
725
|
+
return True
|
|
726
|
+
if len(self.__repn) > 1:
|
|
727
|
+
return False
|
|
728
|
+
return not any(self.__repn)
|
|
729
|
+
|
|
730
|
+
def homogenize(self, size_t var):
|
|
731
|
+
r"""
|
|
732
|
+
Return the homogeneization of ``self`` by increasing the degree of the
|
|
733
|
+
variable ``var``.
|
|
734
|
+
|
|
735
|
+
EXAMPLES::
|
|
736
|
+
|
|
737
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
738
|
+
sage: f = PolyDict({(0, 0): 1, (2, 1): 3, (1, 1): 5})
|
|
739
|
+
sage: f.homogenize(0)
|
|
740
|
+
PolyDict with representation {(2, 1): 8, (3, 0): 1}
|
|
741
|
+
sage: f.homogenize(1)
|
|
742
|
+
PolyDict with representation {(0, 3): 1, (1, 2): 5, (2, 1): 3}
|
|
743
|
+
|
|
744
|
+
sage: PolyDict({(0, 1): 1, (1, 1): -1}).homogenize(0)
|
|
745
|
+
PolyDict with representation {(1, 1): 0}
|
|
746
|
+
"""
|
|
747
|
+
cdef dict H = {}
|
|
748
|
+
cdef int deg = self.degree()
|
|
749
|
+
cdef int shift
|
|
750
|
+
for e, val in self.__repn.items():
|
|
751
|
+
shift = deg - (<ETuple> e).unweighted_degree()
|
|
752
|
+
if shift:
|
|
753
|
+
f = (<ETuple> e).eadd_p(shift, var)
|
|
754
|
+
else:
|
|
755
|
+
f = e
|
|
756
|
+
if f in H:
|
|
757
|
+
H[f] += val
|
|
758
|
+
else:
|
|
759
|
+
H[f] = val
|
|
760
|
+
return self._new(H)
|
|
761
|
+
|
|
762
|
+
def latex(self, vars, atomic_exponents=True,
|
|
763
|
+
atomic_coefficients=True, sortkey=None):
|
|
764
|
+
r"""
|
|
765
|
+
Return a nice polynomial latex representation of this PolyDict, where
|
|
766
|
+
the vars are substituted in.
|
|
767
|
+
|
|
768
|
+
INPUT:
|
|
769
|
+
|
|
770
|
+
- ``vars`` -- list
|
|
771
|
+
- ``atomic_exponents`` -- boolean (default: ``True``)
|
|
772
|
+
- ``atomic_coefficients`` -- boolean (default: ``True``)
|
|
773
|
+
|
|
774
|
+
EXAMPLES::
|
|
775
|
+
|
|
776
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
777
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
778
|
+
sage: f.latex(['a', 'WW'])
|
|
779
|
+
'2 a^{2} WW^{3} + 4 a^{2} WW + 3 a WW^{2}'
|
|
780
|
+
|
|
781
|
+
TESTS:
|
|
782
|
+
|
|
783
|
+
We check that the issue on :issue:`9478` is resolved::
|
|
784
|
+
|
|
785
|
+
sage: R2.<a> = QQ[]
|
|
786
|
+
sage: R3.<xi, x> = R2[]
|
|
787
|
+
sage: print(latex(xi*x))
|
|
788
|
+
\xi x
|
|
789
|
+
|
|
790
|
+
TESTS:
|
|
791
|
+
|
|
792
|
+
Check that :issue:`29604` is fixed::
|
|
793
|
+
|
|
794
|
+
sage: PolyDict({(1, 0): GF(2)(1)}).latex(['x', 'y'])
|
|
795
|
+
'x'
|
|
796
|
+
"""
|
|
797
|
+
if not self:
|
|
798
|
+
return "0"
|
|
799
|
+
|
|
800
|
+
poly = ""
|
|
801
|
+
|
|
802
|
+
sort_kwargs = {'reverse': True}
|
|
803
|
+
if sortkey:
|
|
804
|
+
sort_kwargs['key'] = sortkey
|
|
805
|
+
|
|
806
|
+
E = sorted(self.__repn, **sort_kwargs)
|
|
807
|
+
|
|
808
|
+
try:
|
|
809
|
+
ring = self.__repn[E[0]].parent()
|
|
810
|
+
pos_one = ring.one()
|
|
811
|
+
neg_one = -pos_one
|
|
812
|
+
except (AttributeError, ArithmeticError):
|
|
813
|
+
# AritchmeticError occurs when self.__repn[E[0]] is a tropical
|
|
814
|
+
# semiring element
|
|
815
|
+
# probably self.__repn[E[0]] is not a ring element
|
|
816
|
+
pos_one = 1
|
|
817
|
+
neg_one = -1
|
|
818
|
+
|
|
819
|
+
is_characteristic_2 = bool(pos_one == neg_one)
|
|
820
|
+
|
|
821
|
+
for e in E:
|
|
822
|
+
c = self.__repn[e]
|
|
823
|
+
sign_switch = False
|
|
824
|
+
# First determine the multinomial:
|
|
825
|
+
multi = " ".join([vars[j] +
|
|
826
|
+
("^{%s}" % e[j] if e[j] != 1 else "")
|
|
827
|
+
for j in e.nonzero_positions(sort=True)])
|
|
828
|
+
# Next determine coefficient of multinomial
|
|
829
|
+
if len(multi) == 0:
|
|
830
|
+
multi = latex(c)
|
|
831
|
+
elif c == neg_one and not is_characteristic_2:
|
|
832
|
+
# handle -1 specially because it's a pain
|
|
833
|
+
if len(poly) > 0:
|
|
834
|
+
sign_switch = True
|
|
835
|
+
else:
|
|
836
|
+
multi = "-%s" % multi
|
|
837
|
+
elif c != pos_one:
|
|
838
|
+
c = latex(c)
|
|
839
|
+
if (not atomic_coefficients and multi and
|
|
840
|
+
('+' in c or '-' in c or ' ' in c)):
|
|
841
|
+
c = "\\left(%s\\right)" % c
|
|
842
|
+
multi = "%s %s" % (c, multi)
|
|
843
|
+
|
|
844
|
+
# Now add on coefficiented multinomials
|
|
845
|
+
if len(poly) > 0:
|
|
846
|
+
if sign_switch:
|
|
847
|
+
poly = poly + " - "
|
|
848
|
+
else:
|
|
849
|
+
poly = poly + " + "
|
|
850
|
+
poly = poly + multi
|
|
851
|
+
poly = poly.lstrip().rstrip()
|
|
852
|
+
poly = poly.replace("+ -", "- ")
|
|
853
|
+
if len(poly) == 0:
|
|
854
|
+
return "0"
|
|
855
|
+
return poly
|
|
856
|
+
|
|
857
|
+
def poly_repr(self, vars, atomic_exponents=True,
|
|
858
|
+
atomic_coefficients=True, sortkey=None):
|
|
859
|
+
"""
|
|
860
|
+
Return a nice polynomial string representation of this PolyDict, where
|
|
861
|
+
the vars are substituted in.
|
|
862
|
+
|
|
863
|
+
INPUT:
|
|
864
|
+
|
|
865
|
+
- ``vars`` -- list
|
|
866
|
+
- ``atomic_exponents`` -- boolean (default: ``True``)
|
|
867
|
+
- ``atomic_coefficients`` -- boolean (default: ``True``)
|
|
868
|
+
|
|
869
|
+
EXAMPLES::
|
|
870
|
+
|
|
871
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
872
|
+
sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4})
|
|
873
|
+
sage: f.poly_repr(['a', 'WW'])
|
|
874
|
+
'2*a^2*WW^3 + 4*a^2*WW + 3*a*WW^2'
|
|
875
|
+
|
|
876
|
+
We check to make sure that when we are in characteristic two, we
|
|
877
|
+
don't put negative signs on the generators. ::
|
|
878
|
+
|
|
879
|
+
sage: Integers(2)['x, y'].gens()
|
|
880
|
+
(x, y)
|
|
881
|
+
|
|
882
|
+
We make sure that intervals are correctly represented. ::
|
|
883
|
+
|
|
884
|
+
sage: f = PolyDict({(2, 3): RIF(1/2,3/2), (1, 2): RIF(-1,1)}) # needs sage.rings.real_interval_field
|
|
885
|
+
sage: f.poly_repr(['x', 'y']) # needs sage.rings.real_interval_field
|
|
886
|
+
'1.?*x^2*y^3 + 0.?*x*y^2'
|
|
887
|
+
|
|
888
|
+
TESTS:
|
|
889
|
+
|
|
890
|
+
Check that :issue:`29604` is fixed::
|
|
891
|
+
|
|
892
|
+
sage: PolyDict({(1, 0): GF(4)(1)}).poly_repr(['x', 'y']) # needs sage.rings.finite_rings
|
|
893
|
+
'x'
|
|
894
|
+
|
|
895
|
+
sage: # needs sage.modules
|
|
896
|
+
sage: P.<x,y> = LaurentPolynomialRing(GF(2), 2)
|
|
897
|
+
sage: P.gens()
|
|
898
|
+
(x, y)
|
|
899
|
+
sage: -x - y
|
|
900
|
+
x + y
|
|
901
|
+
"""
|
|
902
|
+
poly = ""
|
|
903
|
+
sort_kwargs = {'reverse': True}
|
|
904
|
+
if sortkey:
|
|
905
|
+
sort_kwargs['key'] = sortkey
|
|
906
|
+
|
|
907
|
+
E = sorted(self.__repn, **sort_kwargs)
|
|
908
|
+
|
|
909
|
+
if not E:
|
|
910
|
+
return "0"
|
|
911
|
+
try:
|
|
912
|
+
ring = self.__repn[E[0]].parent()
|
|
913
|
+
pos_one = ring.one()
|
|
914
|
+
neg_one = -pos_one
|
|
915
|
+
except (AttributeError, ArithmeticError):
|
|
916
|
+
# AritchmeticError occurs when self.__repn[E[0]] is a tropical
|
|
917
|
+
# semiring element
|
|
918
|
+
# probably self.__repn[E[0]] is not a ring element
|
|
919
|
+
pos_one = 1
|
|
920
|
+
neg_one = -1
|
|
921
|
+
|
|
922
|
+
is_characteristic_2 = bool(pos_one == neg_one)
|
|
923
|
+
|
|
924
|
+
for e in E:
|
|
925
|
+
c = self.__repn[e]
|
|
926
|
+
sign_switch = False
|
|
927
|
+
# First determine the multinomial:
|
|
928
|
+
multi = ""
|
|
929
|
+
for j in e.nonzero_positions(sort=True):
|
|
930
|
+
if multi:
|
|
931
|
+
multi = multi + "*"
|
|
932
|
+
multi = multi + vars[j]
|
|
933
|
+
if e[j] != 1:
|
|
934
|
+
if atomic_exponents:
|
|
935
|
+
multi = multi + "^%s" % e[j]
|
|
936
|
+
else:
|
|
937
|
+
multi = multi + "^(%s)" % e[j]
|
|
938
|
+
# Next determine coefficient of multinomial
|
|
939
|
+
if not multi:
|
|
940
|
+
multi = str(c)
|
|
941
|
+
elif c == neg_one and not is_characteristic_2:
|
|
942
|
+
# handle -1 specially because it's a pain
|
|
943
|
+
if poly:
|
|
944
|
+
sign_switch = True
|
|
945
|
+
else:
|
|
946
|
+
multi = "-%s" % multi
|
|
947
|
+
elif not c == pos_one:
|
|
948
|
+
if not atomic_coefficients:
|
|
949
|
+
c = str(c)
|
|
950
|
+
if c.find("+") != -1 or c.find("-") != -1 or c.find(" ") != -1:
|
|
951
|
+
c = "(%s)" % c
|
|
952
|
+
multi = "%s*%s" % (c, multi)
|
|
953
|
+
|
|
954
|
+
# Now add on coefficiented multinomials
|
|
955
|
+
if poly:
|
|
956
|
+
if sign_switch:
|
|
957
|
+
poly = poly + " - "
|
|
958
|
+
else:
|
|
959
|
+
poly = poly + " + "
|
|
960
|
+
poly = poly + multi
|
|
961
|
+
poly = poly.lstrip().rstrip()
|
|
962
|
+
poly = poly.replace("+ -", "- ")
|
|
963
|
+
if not poly:
|
|
964
|
+
return "0"
|
|
965
|
+
return poly
|
|
966
|
+
|
|
967
|
+
def __iadd__(PolyDict self, PolyDict other):
|
|
968
|
+
r"""
|
|
969
|
+
Inplace addition.
|
|
970
|
+
|
|
971
|
+
EXAMPLES::
|
|
972
|
+
|
|
973
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
974
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
975
|
+
sage: g = PolyDict({(1, 5): -3, (2, 3): -2, (1, 1): 3})
|
|
976
|
+
sage: f += g
|
|
977
|
+
sage: f
|
|
978
|
+
PolyDict with representation {(1, 1): 3, (1, 2): 3, (1, 5): -3, (2, 1): 4, (2, 3): 0}
|
|
979
|
+
"""
|
|
980
|
+
cdef dict D = self.__repn
|
|
981
|
+
if self is other:
|
|
982
|
+
for e in D:
|
|
983
|
+
v = D[e]
|
|
984
|
+
D[e] += v
|
|
985
|
+
else:
|
|
986
|
+
for e, c in other.__repn.items():
|
|
987
|
+
if e in D:
|
|
988
|
+
D[e] += c
|
|
989
|
+
else:
|
|
990
|
+
D[e] = c
|
|
991
|
+
return self
|
|
992
|
+
|
|
993
|
+
def __neg__(self):
|
|
994
|
+
r"""
|
|
995
|
+
TESTS::
|
|
996
|
+
|
|
997
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
998
|
+
sage: -PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
999
|
+
PolyDict with representation {(1, 2): -3, (2, 1): -4, (2, 3): -2}
|
|
1000
|
+
"""
|
|
1001
|
+
cdef dict D = self.__repn.copy()
|
|
1002
|
+
for e, c in D.items():
|
|
1003
|
+
D[e] = -c
|
|
1004
|
+
return self._new(D)
|
|
1005
|
+
|
|
1006
|
+
def __add__(PolyDict self, PolyDict other):
|
|
1007
|
+
"""
|
|
1008
|
+
Add two PolyDict's in the same number of variables.
|
|
1009
|
+
|
|
1010
|
+
EXAMPLES:
|
|
1011
|
+
|
|
1012
|
+
We add two polynomials in 2 variables::
|
|
1013
|
+
|
|
1014
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1015
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
1016
|
+
sage: g = PolyDict({(1, 5): -3, (2, 3): -2, (1, 1): 3})
|
|
1017
|
+
sage: f + g
|
|
1018
|
+
PolyDict with representation {(1, 1): 3, (1, 2): 3, (1, 5): -3, (2, 1): 4, (2, 3): 0}
|
|
1019
|
+
|
|
1020
|
+
sage: K = GF(2)
|
|
1021
|
+
sage: f = PolyDict({(1, 1): K(1)})
|
|
1022
|
+
sage: f + f
|
|
1023
|
+
PolyDict with representation {(1, 1): 0}
|
|
1024
|
+
"""
|
|
1025
|
+
cdef dict D = self.__repn
|
|
1026
|
+
cdef dict R = other.__repn
|
|
1027
|
+
if len(D) < len(R):
|
|
1028
|
+
D, R = R, D
|
|
1029
|
+
D = D.copy()
|
|
1030
|
+
for e, c in R.items():
|
|
1031
|
+
if e in D:
|
|
1032
|
+
D[e] += c
|
|
1033
|
+
else:
|
|
1034
|
+
D[e] = c
|
|
1035
|
+
return self._new(D)
|
|
1036
|
+
|
|
1037
|
+
def __mul__(PolyDict self, PolyDict right):
|
|
1038
|
+
"""
|
|
1039
|
+
Multiply two PolyDict's in the same number of variables.
|
|
1040
|
+
|
|
1041
|
+
The algorithm do not test whether a product of coefficients is zero
|
|
1042
|
+
or whether a final coefficient is zero because there is no reliable way
|
|
1043
|
+
to do so in general (eg power series ring or `p`-adic rings).
|
|
1044
|
+
|
|
1045
|
+
EXAMPLES:
|
|
1046
|
+
|
|
1047
|
+
Multiplication of polynomials in 2 variables with rational coefficients::
|
|
1048
|
+
|
|
1049
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1050
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
1051
|
+
sage: g = PolyDict({(1, 5): -3, (2, 3): -2, (1, 1): 3})
|
|
1052
|
+
sage: f * g
|
|
1053
|
+
PolyDict with representation {(2, 3): 9, (2, 7): -9, (3, 2): 12, (3, 4): 6, (3, 5): -6, (3, 6): -12, (3, 8): -6, (4, 4): -8, (4, 6): -4}
|
|
1054
|
+
|
|
1055
|
+
Multiplication of polynomials in 2 variables with power series coefficients::
|
|
1056
|
+
|
|
1057
|
+
sage: R.<t> = PowerSeriesRing(QQ)
|
|
1058
|
+
sage: f = PolyDict({(1, 0): 1 + O(t), (0, 1): 1 + O(t^2)})
|
|
1059
|
+
sage: g = PolyDict({(1, 0): 1, (0, 1): -1})
|
|
1060
|
+
sage: f * g
|
|
1061
|
+
PolyDict with representation {(0, 2): -1 + O(t^2), (1, 1): O(t^1), (2, 0): 1 + O(t)}
|
|
1062
|
+
sage: f = PolyDict({(1, 0): O(t), (0, 1): O(t)})
|
|
1063
|
+
sage: g = PolyDict({(1, 0): 1, (0, 1): O(t)})
|
|
1064
|
+
sage: f * g
|
|
1065
|
+
PolyDict with representation {(0, 2): O(t^2), (1, 1): O(t^1), (2, 0): O(t^1)}
|
|
1066
|
+
"""
|
|
1067
|
+
cdef PyObject *cc
|
|
1068
|
+
cdef dict newpoly
|
|
1069
|
+
if not self.__repn or not right.__repn:
|
|
1070
|
+
return self._new({})
|
|
1071
|
+
newpoly = {}
|
|
1072
|
+
for e0, c0 in self.__repn.items():
|
|
1073
|
+
for e1, c1 in right.__repn.items():
|
|
1074
|
+
e = (<ETuple> e0).eadd(<ETuple> e1)
|
|
1075
|
+
c = c0 * c1
|
|
1076
|
+
cc = PyDict_GetItem(newpoly, e)
|
|
1077
|
+
if cc == <PyObject*> 0:
|
|
1078
|
+
PyDict_SetItem(newpoly, e, c)
|
|
1079
|
+
else:
|
|
1080
|
+
PyDict_SetItem(newpoly, e, <object> cc + c)
|
|
1081
|
+
return self._new(newpoly)
|
|
1082
|
+
|
|
1083
|
+
def scalar_rmult(self, s):
|
|
1084
|
+
"""
|
|
1085
|
+
Return the right scalar multiplication of ``self`` by ``s``.
|
|
1086
|
+
|
|
1087
|
+
EXAMPLES::
|
|
1088
|
+
|
|
1089
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1090
|
+
|
|
1091
|
+
sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat
|
|
1092
|
+
sage: f = PolyDict({(2, 3): x}) # needs sage.combinat
|
|
1093
|
+
sage: f.scalar_rmult(y) # needs sage.combinat
|
|
1094
|
+
PolyDict with representation {(2, 3): x*y}
|
|
1095
|
+
|
|
1096
|
+
sage: f = PolyDict({(2,3):2, (1, 2): 3, (2, 1): 4})
|
|
1097
|
+
sage: f.scalar_rmult(-2)
|
|
1098
|
+
PolyDict with representation {(1, 2): -6, (2, 1): -8, (2, 3): -4}
|
|
1099
|
+
sage: f.scalar_rmult(RIF(-1,1)) # needs sage.rings.real_interval_field
|
|
1100
|
+
PolyDict with representation {(1, 2): 0.?e1, (2, 1): 0.?e1, (2, 3): 0.?e1}
|
|
1101
|
+
"""
|
|
1102
|
+
cdef dict v = {}
|
|
1103
|
+
for e, c in self.__repn.items():
|
|
1104
|
+
v[e] = c * s
|
|
1105
|
+
return self._new(v)
|
|
1106
|
+
|
|
1107
|
+
def scalar_lmult(self, s):
|
|
1108
|
+
"""
|
|
1109
|
+
Return the left scalar multiplication of ``self`` by ``s``.
|
|
1110
|
+
|
|
1111
|
+
EXAMPLES::
|
|
1112
|
+
|
|
1113
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1114
|
+
|
|
1115
|
+
sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat
|
|
1116
|
+
sage: f = PolyDict({(2,3):x}) # needs sage.combinat
|
|
1117
|
+
sage: f.scalar_lmult(y) # needs sage.combinat
|
|
1118
|
+
PolyDict with representation {(2, 3): y*x}
|
|
1119
|
+
|
|
1120
|
+
sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4})
|
|
1121
|
+
sage: f.scalar_lmult(-2)
|
|
1122
|
+
PolyDict with representation {(1, 2): -6, (2, 1): -8, (2, 3): -4}
|
|
1123
|
+
sage: f.scalar_lmult(RIF(-1,1)) # needs sage.rings.real_interval_field
|
|
1124
|
+
PolyDict with representation {(1, 2): 0.?e1, (2, 1): 0.?e1, (2, 3): 0.?e1}
|
|
1125
|
+
"""
|
|
1126
|
+
cdef dict v = {}
|
|
1127
|
+
for e, c in self.__repn.items():
|
|
1128
|
+
v[e] = s * c
|
|
1129
|
+
return self._new(v)
|
|
1130
|
+
|
|
1131
|
+
def term_lmult(self, exponent, s):
|
|
1132
|
+
"""
|
|
1133
|
+
Return this element multiplied by ``s`` on the left and with exponents
|
|
1134
|
+
shifted by ``exponent``.
|
|
1135
|
+
|
|
1136
|
+
INPUT:
|
|
1137
|
+
|
|
1138
|
+
- ``exponent`` -- a ETuple
|
|
1139
|
+
|
|
1140
|
+
- ``s`` -- a scalar
|
|
1141
|
+
|
|
1142
|
+
EXAMPLES::
|
|
1143
|
+
|
|
1144
|
+
sage: from sage.rings.polynomial.polydict import ETuple, PolyDict
|
|
1145
|
+
|
|
1146
|
+
sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat
|
|
1147
|
+
sage: f = PolyDict({(2, 3): x}) # needs sage.combinat
|
|
1148
|
+
sage: f.term_lmult(ETuple((1, 2)), y) # needs sage.combinat
|
|
1149
|
+
PolyDict with representation {(3, 5): y*x}
|
|
1150
|
+
|
|
1151
|
+
sage: f = PolyDict({(2,3): 2, (1,2): 3, (2,1): 4})
|
|
1152
|
+
sage: f.term_lmult(ETuple((1, 2)), -2)
|
|
1153
|
+
PolyDict with representation {(2, 4): -6, (3, 3): -8, (3, 5): -4}
|
|
1154
|
+
"""
|
|
1155
|
+
cdef dict v = {}
|
|
1156
|
+
for e, c in self.__repn.items():
|
|
1157
|
+
v[(<ETuple> e).eadd(exponent)] = s*c
|
|
1158
|
+
return self._new(v)
|
|
1159
|
+
|
|
1160
|
+
def term_rmult(self, exponent, s):
|
|
1161
|
+
"""
|
|
1162
|
+
Return this element multiplied by ``s`` on the right and with exponents
|
|
1163
|
+
shifted by ``exponent``.
|
|
1164
|
+
|
|
1165
|
+
INPUT:
|
|
1166
|
+
|
|
1167
|
+
- ``exponent`` -- a ETuple
|
|
1168
|
+
|
|
1169
|
+
- ``s`` -- a scalar
|
|
1170
|
+
|
|
1171
|
+
EXAMPLES::
|
|
1172
|
+
|
|
1173
|
+
sage: from sage.rings.polynomial.polydict import ETuple, PolyDict
|
|
1174
|
+
|
|
1175
|
+
sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat
|
|
1176
|
+
sage: f = PolyDict({(2, 3): x}) # needs sage.combinat
|
|
1177
|
+
sage: f.term_rmult(ETuple((1, 2)), y) # needs sage.combinat
|
|
1178
|
+
PolyDict with representation {(3, 5): x*y}
|
|
1179
|
+
|
|
1180
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
1181
|
+
sage: f.term_rmult(ETuple((1, 2)), -2)
|
|
1182
|
+
PolyDict with representation {(2, 4): -6, (3, 3): -8, (3, 5): -4}
|
|
1183
|
+
"""
|
|
1184
|
+
cdef dict v = {}
|
|
1185
|
+
for e, c in self.__repn.items():
|
|
1186
|
+
v[(<ETuple> e).eadd(exponent)] = c * s
|
|
1187
|
+
return self._new(v)
|
|
1188
|
+
|
|
1189
|
+
def __sub__(PolyDict self, PolyDict other):
|
|
1190
|
+
"""
|
|
1191
|
+
Subtract two PolyDict's.
|
|
1192
|
+
|
|
1193
|
+
EXAMPLES::
|
|
1194
|
+
|
|
1195
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1196
|
+
sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4})
|
|
1197
|
+
sage: g = PolyDict({(2,3):2, (1,1):-10})
|
|
1198
|
+
sage: f - g
|
|
1199
|
+
PolyDict with representation {(1, 1): 10, (1, 2): 3, (2, 1): 4, (2, 3): 0}
|
|
1200
|
+
sage: g - f
|
|
1201
|
+
PolyDict with representation {(1, 1): -10, (1, 2): -3, (2, 1): -4, (2, 3): 0}
|
|
1202
|
+
sage: f - f
|
|
1203
|
+
PolyDict with representation {(1, 2): 0, (2, 1): 0, (2, 3): 0}
|
|
1204
|
+
"""
|
|
1205
|
+
cdef dict D = self.__repn.copy()
|
|
1206
|
+
cdef dict R = other.__repn
|
|
1207
|
+
for e, c in R.items():
|
|
1208
|
+
if e in D:
|
|
1209
|
+
D[e] -= c
|
|
1210
|
+
else:
|
|
1211
|
+
D[e] = -c
|
|
1212
|
+
return self._new(D)
|
|
1213
|
+
|
|
1214
|
+
def derivative_i(self, size_t i):
|
|
1215
|
+
r"""
|
|
1216
|
+
Return the derivative of ``self`` with respect to the ``i``-th variable.
|
|
1217
|
+
|
|
1218
|
+
EXAMPLES::
|
|
1219
|
+
|
|
1220
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1221
|
+
sage: PolyDict({(1, 1): 1}).derivative_i(0)
|
|
1222
|
+
PolyDict with representation {(0, 1): 1}
|
|
1223
|
+
"""
|
|
1224
|
+
cdef dict D = {}
|
|
1225
|
+
for e, c in self.__repn.items():
|
|
1226
|
+
D[(<ETuple> e).eadd_p(-1, i)] = c * (<ETuple> e).get_exp(i)
|
|
1227
|
+
return self._new(D)
|
|
1228
|
+
|
|
1229
|
+
def derivative(self, PolyDict x):
|
|
1230
|
+
r"""
|
|
1231
|
+
Return the derivative of ``self`` with respect to ``x``.
|
|
1232
|
+
|
|
1233
|
+
EXAMPLES::
|
|
1234
|
+
|
|
1235
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1236
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
1237
|
+
sage: f.derivative(PolyDict({(1, 0): 1}))
|
|
1238
|
+
PolyDict with representation {(0, 2): 3, (1, 1): 8, (1, 3): 4}
|
|
1239
|
+
sage: f.derivative(PolyDict({(0, 1): 1}))
|
|
1240
|
+
PolyDict with representation {(1, 1): 6, (2, 0): 4, (2, 2): 6}
|
|
1241
|
+
|
|
1242
|
+
sage: PolyDict({(-1,): 1}).derivative(PolyDict({(1,): 1}))
|
|
1243
|
+
PolyDict with representation {(-2,): -1}
|
|
1244
|
+
sage: PolyDict({(-2,): 1}).derivative(PolyDict({(1,): 1}))
|
|
1245
|
+
PolyDict with representation {(-3,): -2}
|
|
1246
|
+
|
|
1247
|
+
sage: PolyDict({}).derivative(PolyDict({(1, 1): 1}))
|
|
1248
|
+
Traceback (most recent call last):
|
|
1249
|
+
...
|
|
1250
|
+
ValueError: x must be a generator
|
|
1251
|
+
"""
|
|
1252
|
+
cdef int i = gen_index(x)
|
|
1253
|
+
if i < 0:
|
|
1254
|
+
raise ValueError('x must be a generator')
|
|
1255
|
+
return self.derivative_i(i)
|
|
1256
|
+
|
|
1257
|
+
def integral_i(self, size_t i):
|
|
1258
|
+
r"""
|
|
1259
|
+
Return the derivative of ``self`` with respect to the ``i``-th variable.
|
|
1260
|
+
|
|
1261
|
+
EXAMPLES::
|
|
1262
|
+
|
|
1263
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1264
|
+
sage: PolyDict({(1, 1): 1}).integral_i(0)
|
|
1265
|
+
PolyDict with representation {(2, 1): 1/2}
|
|
1266
|
+
"""
|
|
1267
|
+
cdef dict D = {}
|
|
1268
|
+
cdef int exp
|
|
1269
|
+
for e, c in self.__repn.items():
|
|
1270
|
+
exp = (<ETuple> e).get_exp(i)
|
|
1271
|
+
if exp == -1:
|
|
1272
|
+
raise ArithmeticError('integral of monomial with exponent -1')
|
|
1273
|
+
D[(<ETuple> e).eadd_p(1, i)] = c / (exp + 1)
|
|
1274
|
+
return self._new(D)
|
|
1275
|
+
|
|
1276
|
+
def integral(self, PolyDict x):
|
|
1277
|
+
r"""
|
|
1278
|
+
Return the integral of ``self`` with respect to ``x``.
|
|
1279
|
+
|
|
1280
|
+
EXAMPLES::
|
|
1281
|
+
|
|
1282
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1283
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
1284
|
+
sage: f.integral(PolyDict({(1, 0): 1}))
|
|
1285
|
+
PolyDict with representation {(2, 2): 3/2, (3, 1): 4/3, (3, 3): 2/3}
|
|
1286
|
+
sage: f.integral(PolyDict({(0, 1): 1}))
|
|
1287
|
+
PolyDict with representation {(1, 3): 1, (2, 2): 2, (2, 4): 1/2}
|
|
1288
|
+
|
|
1289
|
+
sage: PolyDict({(-1,): 1}).integral(PolyDict({(1,): 1}))
|
|
1290
|
+
Traceback (most recent call last):
|
|
1291
|
+
...
|
|
1292
|
+
ArithmeticError: integral of monomial with exponent -1
|
|
1293
|
+
sage: PolyDict({(-2,): 1}).integral(PolyDict({(1,): 1}))
|
|
1294
|
+
PolyDict with representation {(-1,): -1}
|
|
1295
|
+
sage: PolyDict({}).integral(PolyDict({(1, 1): 1}))
|
|
1296
|
+
Traceback (most recent call last):
|
|
1297
|
+
...
|
|
1298
|
+
ValueError: x must be a generator
|
|
1299
|
+
"""
|
|
1300
|
+
cdef int i = gen_index(x)
|
|
1301
|
+
if i < 0:
|
|
1302
|
+
raise ValueError('x must be a generator')
|
|
1303
|
+
return self.integral_i(i)
|
|
1304
|
+
|
|
1305
|
+
def lcmt(self, greater_etuple):
|
|
1306
|
+
"""
|
|
1307
|
+
Provides functionality of lc, lm, and lt by calling the tuple
|
|
1308
|
+
compare function on the provided term order T.
|
|
1309
|
+
|
|
1310
|
+
INPUT:
|
|
1311
|
+
|
|
1312
|
+
- ``greater_etuple`` -- a term order
|
|
1313
|
+
"""
|
|
1314
|
+
try:
|
|
1315
|
+
return ETuple(reduce(greater_etuple, self.__repn))
|
|
1316
|
+
except KeyError:
|
|
1317
|
+
raise ArithmeticError("%s not supported", greater_etuple)
|
|
1318
|
+
|
|
1319
|
+
def __reduce__(self):
|
|
1320
|
+
"""
|
|
1321
|
+
|
|
1322
|
+
EXAMPLES::
|
|
1323
|
+
|
|
1324
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1325
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
1326
|
+
sage: loads(dumps(f)) == f
|
|
1327
|
+
True
|
|
1328
|
+
"""
|
|
1329
|
+
return PolyDict, (self.__repn,)
|
|
1330
|
+
|
|
1331
|
+
def min_exp(self):
|
|
1332
|
+
"""
|
|
1333
|
+
Return an ETuple containing the minimum exponents appearing. If
|
|
1334
|
+
there are no terms at all in the PolyDict, it returns None.
|
|
1335
|
+
|
|
1336
|
+
The nvars parameter is necessary because a PolyDict doesn't know it
|
|
1337
|
+
from the data it has (and an empty PolyDict offers no clues).
|
|
1338
|
+
|
|
1339
|
+
EXAMPLES::
|
|
1340
|
+
|
|
1341
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1342
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
1343
|
+
sage: f.min_exp()
|
|
1344
|
+
(1, 1)
|
|
1345
|
+
sage: PolyDict({}).min_exp() # returns None
|
|
1346
|
+
"""
|
|
1347
|
+
cdef ETuple r
|
|
1348
|
+
if self.__repn:
|
|
1349
|
+
it = iter(self.__repn)
|
|
1350
|
+
r = next(it)
|
|
1351
|
+
for e in it:
|
|
1352
|
+
r = r.emin(e)
|
|
1353
|
+
return r
|
|
1354
|
+
else:
|
|
1355
|
+
return None
|
|
1356
|
+
|
|
1357
|
+
def max_exp(self):
|
|
1358
|
+
"""
|
|
1359
|
+
Return an ETuple containing the maximum exponents appearing. If
|
|
1360
|
+
there are no terms at all in the PolyDict, it returns None.
|
|
1361
|
+
|
|
1362
|
+
The nvars parameter is necessary because a PolyDict doesn't know it
|
|
1363
|
+
from the data it has (and an empty PolyDict offers no clues).
|
|
1364
|
+
|
|
1365
|
+
EXAMPLES::
|
|
1366
|
+
|
|
1367
|
+
sage: from sage.rings.polynomial.polydict import PolyDict
|
|
1368
|
+
sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4})
|
|
1369
|
+
sage: f.max_exp()
|
|
1370
|
+
(2, 3)
|
|
1371
|
+
sage: PolyDict({}).max_exp() # returns None
|
|
1372
|
+
"""
|
|
1373
|
+
cdef ETuple r
|
|
1374
|
+
if self.__repn:
|
|
1375
|
+
it = iter(self.__repn)
|
|
1376
|
+
r = next(it)
|
|
1377
|
+
for e in it:
|
|
1378
|
+
r = r.emax(e)
|
|
1379
|
+
return r
|
|
1380
|
+
else:
|
|
1381
|
+
return None
|
|
1382
|
+
|
|
1383
|
+
cdef inline bint dual_etuple_iter(ETuple self, ETuple other, size_t *ind1, size_t *ind2, size_t *index, int *exp1, int *exp2) noexcept:
|
|
1384
|
+
"""
|
|
1385
|
+
This function is a crucial helper function for a number of methods of
|
|
1386
|
+
the ETuple class.
|
|
1387
|
+
|
|
1388
|
+
This is a rather fragile function. Perhaps some Cython guru could make
|
|
1389
|
+
it appear a little less stilted -- a principal difficulty is passing
|
|
1390
|
+
C types by reference. In any case, the complicated features of looping
|
|
1391
|
+
through two ETuple _data members is all packaged up right here and
|
|
1392
|
+
shouldn't be allowed to spread.
|
|
1393
|
+
"""
|
|
1394
|
+
if ind1[0] >= self._nonzero and ind2[0] >= other._nonzero:
|
|
1395
|
+
return 0
|
|
1396
|
+
if ind1[0] < self._nonzero and ind2[0] < other._nonzero:
|
|
1397
|
+
if self._data[2*ind1[0]] == other._data[2*ind2[0]]:
|
|
1398
|
+
exp1[0] = self._data[2*ind1[0]+1]
|
|
1399
|
+
exp2[0] = other._data[2*ind2[0]+1]
|
|
1400
|
+
index[0] = self._data[2*ind1[0]]
|
|
1401
|
+
ind1[0] += 1
|
|
1402
|
+
ind2[0] += 1
|
|
1403
|
+
elif self._data[2*ind1[0]] > other._data[2*ind2[0]]:
|
|
1404
|
+
exp1[0] = 0
|
|
1405
|
+
exp2[0] = other._data[2*ind2[0]+1]
|
|
1406
|
+
index[0] = other._data[2*ind2[0]]
|
|
1407
|
+
ind2[0] += 1
|
|
1408
|
+
else:
|
|
1409
|
+
exp1[0] = self._data[2*ind1[0]+1]
|
|
1410
|
+
exp2[0] = 0
|
|
1411
|
+
index[0] = self._data[2*ind1[0]]
|
|
1412
|
+
ind1[0] += 1
|
|
1413
|
+
else:
|
|
1414
|
+
if ind2[0] >= other._nonzero:
|
|
1415
|
+
exp1[0] = self._data[2*ind1[0]+1]
|
|
1416
|
+
exp2[0] = 0
|
|
1417
|
+
index[0] = self._data[2*ind1[0]]
|
|
1418
|
+
ind1[0] += 1
|
|
1419
|
+
elif ind1[0] >= self._nonzero:
|
|
1420
|
+
exp1[0] = 0
|
|
1421
|
+
exp2[0] = other._data[2*ind2[0]+1]
|
|
1422
|
+
index[0] = other._data[2*ind2[0]]
|
|
1423
|
+
ind2[0] += 1
|
|
1424
|
+
return 1
|
|
1425
|
+
|
|
1426
|
+
cdef class ETuple:
|
|
1427
|
+
"""
|
|
1428
|
+
Representation of the exponents of a polydict monomial. If
|
|
1429
|
+
(0,0,3,0,5) is the exponent tuple of x_2^3*x_4^5 then this class
|
|
1430
|
+
only stores {2:3, 4:5} instead of the full tuple. This sparse
|
|
1431
|
+
information may be obtained by provided methods.
|
|
1432
|
+
|
|
1433
|
+
The index/value data is all stored in the _data C int array member
|
|
1434
|
+
variable. For the example above, the C array would contain
|
|
1435
|
+
2,3,4,5. The indices are interlaced with the values.
|
|
1436
|
+
|
|
1437
|
+
This data structure is very nice to work with for some functions
|
|
1438
|
+
implemented in this class, but tricky for others. One reason that
|
|
1439
|
+
I really like the format is that it requires a single memory
|
|
1440
|
+
allocation for all of the values. A hash table would require more
|
|
1441
|
+
allocations and presumably be slower. I didn't benchmark this
|
|
1442
|
+
question (although, there is no question that this is much faster
|
|
1443
|
+
than the prior use of python dicts).
|
|
1444
|
+
"""
|
|
1445
|
+
cdef ETuple _new(self):
|
|
1446
|
+
"""
|
|
1447
|
+
Quickly create a new initialized ETuple with the
|
|
1448
|
+
same length as ``self``.
|
|
1449
|
+
"""
|
|
1450
|
+
cdef type t = type(self)
|
|
1451
|
+
cdef ETuple x = <ETuple>t.__new__(t)
|
|
1452
|
+
x._length = self._length
|
|
1453
|
+
return x
|
|
1454
|
+
|
|
1455
|
+
def __init__(self, data=None, length=None):
|
|
1456
|
+
"""
|
|
1457
|
+
- ``ETuple()`` -> an empty ETuple
|
|
1458
|
+
- ``ETuple(sequence)`` -> ETuple initialized from sequence's items
|
|
1459
|
+
|
|
1460
|
+
If the argument is an ETuple, the return value is the same object.
|
|
1461
|
+
|
|
1462
|
+
EXAMPLES::
|
|
1463
|
+
|
|
1464
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1465
|
+
sage: ETuple([1, 1, 0])
|
|
1466
|
+
(1, 1, 0)
|
|
1467
|
+
sage: ETuple({int(1): int(2)}, int(3))
|
|
1468
|
+
(0, 2, 0)
|
|
1469
|
+
sage: ETuple([1, -1, 0])
|
|
1470
|
+
(1, -1, 0)
|
|
1471
|
+
|
|
1472
|
+
TESTS:
|
|
1473
|
+
|
|
1474
|
+
Iterators are not accepted::
|
|
1475
|
+
|
|
1476
|
+
sage: ETuple(iter([2, 3, 4]))
|
|
1477
|
+
Traceback (most recent call last):
|
|
1478
|
+
...
|
|
1479
|
+
TypeError: Error in ETuple((), <list... object at ...>, None)
|
|
1480
|
+
"""
|
|
1481
|
+
if data is None:
|
|
1482
|
+
return
|
|
1483
|
+
cdef size_t ind
|
|
1484
|
+
cdef int v
|
|
1485
|
+
from sage.combinat.integer_vector import IntegerVector
|
|
1486
|
+
if isinstance(data, ETuple):
|
|
1487
|
+
self._length = (<ETuple>data)._length
|
|
1488
|
+
self._nonzero = (<ETuple>data)._nonzero
|
|
1489
|
+
self._data = <int*>sig_malloc(sizeof(int)*self._nonzero*2)
|
|
1490
|
+
memcpy(self._data, (<ETuple>data)._data, sizeof(int)*self._nonzero*2)
|
|
1491
|
+
elif isinstance(data, dict) and isinstance(length, int):
|
|
1492
|
+
self._length = length
|
|
1493
|
+
self._nonzero = len(data)
|
|
1494
|
+
self._data = <int*>sig_malloc(sizeof(int)*self._nonzero*2)
|
|
1495
|
+
nz_elts = sorted(data.items())
|
|
1496
|
+
ind = 0
|
|
1497
|
+
for index, exp in nz_elts:
|
|
1498
|
+
self._data[2*ind] = index
|
|
1499
|
+
self._data[2*ind+1] = exp
|
|
1500
|
+
ind += 1
|
|
1501
|
+
elif isinstance(data, (list, tuple, IntegerVector)):
|
|
1502
|
+
self._length = len(data)
|
|
1503
|
+
self._nonzero = 0
|
|
1504
|
+
for v in data:
|
|
1505
|
+
if v != 0:
|
|
1506
|
+
self._nonzero += 1
|
|
1507
|
+
ind = 0
|
|
1508
|
+
self._data = <int*>sig_malloc(sizeof(int)*self._nonzero*2)
|
|
1509
|
+
for i from 0 <= i < self._length:
|
|
1510
|
+
v = data[i]
|
|
1511
|
+
if v != 0:
|
|
1512
|
+
self._data[ind] = i
|
|
1513
|
+
self._data[ind+1] = v
|
|
1514
|
+
ind += 2
|
|
1515
|
+
else:
|
|
1516
|
+
raise TypeError("Error in ETuple(%s, %s, %s)" % (self, data, length))
|
|
1517
|
+
|
|
1518
|
+
def __cinit__(self):
|
|
1519
|
+
self._data = <int*>0
|
|
1520
|
+
|
|
1521
|
+
def __dealloc__(self):
|
|
1522
|
+
if self._data != <int*>0:
|
|
1523
|
+
sig_free(self._data)
|
|
1524
|
+
|
|
1525
|
+
def __bool__(self):
|
|
1526
|
+
r"""
|
|
1527
|
+
Return whether ``self`` is nonzero.
|
|
1528
|
+
|
|
1529
|
+
TESTS::
|
|
1530
|
+
|
|
1531
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1532
|
+
sage: bool(ETuple([1]))
|
|
1533
|
+
True
|
|
1534
|
+
sage: bool(ETuple([]))
|
|
1535
|
+
False
|
|
1536
|
+
sage: bool(ETuple([0, 0, 0]))
|
|
1537
|
+
False
|
|
1538
|
+
"""
|
|
1539
|
+
return bool(self._nonzero)
|
|
1540
|
+
|
|
1541
|
+
# methods to simulate tuple
|
|
1542
|
+
|
|
1543
|
+
def __add__(ETuple self, ETuple other):
|
|
1544
|
+
"""
|
|
1545
|
+
``x.__add__(n) <==> x+n``.
|
|
1546
|
+
|
|
1547
|
+
Concatenate two ETuples.
|
|
1548
|
+
|
|
1549
|
+
EXAMPLES::
|
|
1550
|
+
|
|
1551
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1552
|
+
sage: ETuple([1, 1, 0]) + ETuple({int(1): int(2)}, int(3))
|
|
1553
|
+
(1, 1, 0, 0, 2, 0)
|
|
1554
|
+
"""
|
|
1555
|
+
cdef size_t index = 0
|
|
1556
|
+
cdef ETuple result = <ETuple>ETuple.__new__(ETuple)
|
|
1557
|
+
result._length = self._length+other._length
|
|
1558
|
+
result._nonzero = self._nonzero+other._nonzero
|
|
1559
|
+
result._data = <int*>sig_malloc(sizeof(int)*result._nonzero*2)
|
|
1560
|
+
for index from 0 <= index < self._nonzero:
|
|
1561
|
+
result._data[2*index] = self._data[2*index]
|
|
1562
|
+
result._data[2*index+1] = self._data[2*index+1]
|
|
1563
|
+
for index from 0 <= index < other._nonzero:
|
|
1564
|
+
result._data[2*(index+self._nonzero)] = other._data[2*index]+self._length # offset the second tuple (append to end!)
|
|
1565
|
+
result._data[2*(index+self._nonzero)+1] = other._data[2*index+1]
|
|
1566
|
+
return result
|
|
1567
|
+
|
|
1568
|
+
def __mul__(ETuple self, factor):
|
|
1569
|
+
"""
|
|
1570
|
+
``x.__mul__(n) <==> x*n``.
|
|
1571
|
+
|
|
1572
|
+
EXAMPLES::
|
|
1573
|
+
|
|
1574
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1575
|
+
sage: ETuple([1, 2, 3])*2
|
|
1576
|
+
(1, 2, 3, 1, 2, 3)
|
|
1577
|
+
"""
|
|
1578
|
+
cdef int _factor = factor
|
|
1579
|
+
cdef ETuple result = <ETuple>ETuple.__new__(ETuple)
|
|
1580
|
+
if factor <= 0:
|
|
1581
|
+
result._length = 0
|
|
1582
|
+
result._nonzero = 0
|
|
1583
|
+
return result
|
|
1584
|
+
cdef size_t index
|
|
1585
|
+
cdef size_t f
|
|
1586
|
+
result._length = self._length * factor
|
|
1587
|
+
result._nonzero = self._nonzero * factor
|
|
1588
|
+
result._data = <int*>sig_malloc(sizeof(int)*result._nonzero*2)
|
|
1589
|
+
for index from 0 <= index < self._nonzero:
|
|
1590
|
+
for f from 0 <= f < factor:
|
|
1591
|
+
result._data[2*(f*self._nonzero+index)] = self._data[2*index]+f*self._length
|
|
1592
|
+
result._data[2*(f*self._nonzero+index)+1] = self._data[2*index+1]
|
|
1593
|
+
return result
|
|
1594
|
+
|
|
1595
|
+
def __getitem__(self, i):
|
|
1596
|
+
"""
|
|
1597
|
+
EXAMPLES::
|
|
1598
|
+
|
|
1599
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1600
|
+
sage: m = ETuple([1, 2, 0, 3])
|
|
1601
|
+
sage: m[2]
|
|
1602
|
+
0
|
|
1603
|
+
sage: m[1]
|
|
1604
|
+
2
|
|
1605
|
+
sage: e = ETuple([1, 2, 3])
|
|
1606
|
+
sage: e[1:]
|
|
1607
|
+
(2, 3)
|
|
1608
|
+
sage: e[:1]
|
|
1609
|
+
(1,)
|
|
1610
|
+
"""
|
|
1611
|
+
cdef size_t ind
|
|
1612
|
+
if isinstance(i, slice):
|
|
1613
|
+
start, stop = i.start, i.stop
|
|
1614
|
+
if start is None:
|
|
1615
|
+
start = 0
|
|
1616
|
+
elif start < 0:
|
|
1617
|
+
start = start % self._length
|
|
1618
|
+
elif start > self._length:
|
|
1619
|
+
start = self._length
|
|
1620
|
+
|
|
1621
|
+
if stop is None or stop > self._length:
|
|
1622
|
+
stop = self._length
|
|
1623
|
+
elif stop < 0:
|
|
1624
|
+
stop = stop % self._length
|
|
1625
|
+
|
|
1626
|
+
# this is not particularly fast, but I doubt many people care
|
|
1627
|
+
# if you do, feel free to tweak!
|
|
1628
|
+
d = [self[ind] for ind from start <= ind < stop]
|
|
1629
|
+
return ETuple(d)
|
|
1630
|
+
else:
|
|
1631
|
+
return self.get_exp(i)
|
|
1632
|
+
|
|
1633
|
+
cdef size_t get_position(self, size_t i, size_t start, size_t end) noexcept:
|
|
1634
|
+
r"""
|
|
1635
|
+
Return where to insert ``i`` in the data between ``start`` and ``end``.
|
|
1636
|
+
"""
|
|
1637
|
+
if end <= start:
|
|
1638
|
+
return start
|
|
1639
|
+
cdef size_t left = start
|
|
1640
|
+
cdef size_t right = end - 1
|
|
1641
|
+
cdef size_t mid
|
|
1642
|
+
if self._data[2 * left] >= i:
|
|
1643
|
+
return left
|
|
1644
|
+
if self._data[2 * right] < i:
|
|
1645
|
+
return end
|
|
1646
|
+
if self._data[2 * right] == i:
|
|
1647
|
+
return right
|
|
1648
|
+
while right - left > 1:
|
|
1649
|
+
mid = (left + right) / 2
|
|
1650
|
+
if self._data[2 * mid] == i:
|
|
1651
|
+
return mid
|
|
1652
|
+
if self._data[2 * mid] > i:
|
|
1653
|
+
right = mid
|
|
1654
|
+
else:
|
|
1655
|
+
left = mid
|
|
1656
|
+
return right
|
|
1657
|
+
|
|
1658
|
+
cdef int get_exp(self, size_t i) noexcept:
|
|
1659
|
+
"""
|
|
1660
|
+
Return the exponent for the ``i``-th variable.
|
|
1661
|
+
"""
|
|
1662
|
+
cdef size_t ind = self.get_position(i, 0, self._nonzero)
|
|
1663
|
+
if ind != self._nonzero and self._data[2 * ind] == i:
|
|
1664
|
+
return self._data[2 * ind + 1]
|
|
1665
|
+
return 0
|
|
1666
|
+
|
|
1667
|
+
def __hash__(self):
|
|
1668
|
+
"""
|
|
1669
|
+
x.__hash__() <==> hash(x)
|
|
1670
|
+
"""
|
|
1671
|
+
cdef int i
|
|
1672
|
+
cdef int result = 0
|
|
1673
|
+
for i in range(self._nonzero):
|
|
1674
|
+
result += (1000003 * result) ^ self._data[2*i]
|
|
1675
|
+
result += (1000003 * result) ^ self._data[2*i+1]
|
|
1676
|
+
result = (1000003 * result) ^ self._length
|
|
1677
|
+
return result
|
|
1678
|
+
|
|
1679
|
+
def __len__(self):
|
|
1680
|
+
"""
|
|
1681
|
+
``x.__len__() <==> len(x)``.
|
|
1682
|
+
|
|
1683
|
+
EXAMPLES::
|
|
1684
|
+
|
|
1685
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1686
|
+
sage: e = ETuple([1, 0, 2, 0, 3])
|
|
1687
|
+
sage: len(e)
|
|
1688
|
+
5
|
|
1689
|
+
"""
|
|
1690
|
+
return self._length
|
|
1691
|
+
|
|
1692
|
+
def __contains__(self, elem):
|
|
1693
|
+
"""
|
|
1694
|
+
``x.__contains__(n) <==> n in x``.
|
|
1695
|
+
|
|
1696
|
+
EXAMPLES::
|
|
1697
|
+
|
|
1698
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1699
|
+
sage: e = ETuple({int(1): int(2)}, int(3))
|
|
1700
|
+
sage: e
|
|
1701
|
+
(0, 2, 0)
|
|
1702
|
+
sage: 1 in e
|
|
1703
|
+
False
|
|
1704
|
+
sage: 2 in e
|
|
1705
|
+
True
|
|
1706
|
+
"""
|
|
1707
|
+
if elem==0:
|
|
1708
|
+
return self._length > self._nonzero
|
|
1709
|
+
|
|
1710
|
+
cdef size_t ind = 0
|
|
1711
|
+
for ind in range(self._nonzero):
|
|
1712
|
+
if elem == self._data[2 * ind + 1]:
|
|
1713
|
+
return True
|
|
1714
|
+
return False
|
|
1715
|
+
|
|
1716
|
+
def __richcmp__(ETuple self, ETuple other, op):
|
|
1717
|
+
"""
|
|
1718
|
+
EXAMPLES::
|
|
1719
|
+
|
|
1720
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1721
|
+
sage: ETuple([1, 1, 0])<ETuple([1, 1, 0])
|
|
1722
|
+
False
|
|
1723
|
+
sage: ETuple([1, 1, 0])<ETuple([1, 0, 0])
|
|
1724
|
+
False
|
|
1725
|
+
sage: ETuple([1, 1, 0])<ETuple([1, 2, 0])
|
|
1726
|
+
True
|
|
1727
|
+
sage: ETuple([1, 1, 0])<ETuple([1, -1, 0])
|
|
1728
|
+
False
|
|
1729
|
+
sage: ETuple([0, -2, 0])<ETuple([1, -1, 0])
|
|
1730
|
+
True
|
|
1731
|
+
sage: ETuple([1, 1, 0])>ETuple([1, 1, 0])
|
|
1732
|
+
False
|
|
1733
|
+
sage: ETuple([1, 1, 0])>ETuple([1, 0, 0])
|
|
1734
|
+
True
|
|
1735
|
+
sage: ETuple([1, 1, 0])>ETuple([1, 2, 0])
|
|
1736
|
+
False
|
|
1737
|
+
sage: ETuple([1, 1, 0])>ETuple([1, -1, 0])
|
|
1738
|
+
True
|
|
1739
|
+
sage: ETuple([0, -2, 0])>ETuple([1, -1, 0])
|
|
1740
|
+
False
|
|
1741
|
+
"""
|
|
1742
|
+
cdef size_t ind = 0
|
|
1743
|
+
if op == Py_EQ: # ==
|
|
1744
|
+
if self._nonzero != other._nonzero:
|
|
1745
|
+
return False
|
|
1746
|
+
for ind in range(self._nonzero):
|
|
1747
|
+
if self._data[2 * ind] != other._data[2 * ind]:
|
|
1748
|
+
return False
|
|
1749
|
+
if self._data[2 * ind + 1] != other._data[2 * ind + 1]:
|
|
1750
|
+
return False
|
|
1751
|
+
return self._length == other._length
|
|
1752
|
+
|
|
1753
|
+
if op == Py_LT: # <
|
|
1754
|
+
while ind < self._nonzero and ind < other._nonzero:
|
|
1755
|
+
if self._data[2*ind] < other._data[2*ind]:
|
|
1756
|
+
return self._data[2*ind+1] < 0
|
|
1757
|
+
if self._data[2*ind] > other._data[2*ind]:
|
|
1758
|
+
return other._data[2*ind+1] > 0
|
|
1759
|
+
if self._data[2*ind] == other._data[2*ind] and self._data[2*ind+1] != other._data[2*ind+1]:
|
|
1760
|
+
return self._data[2*ind+1] < other._data[2*ind+1]
|
|
1761
|
+
ind += 1
|
|
1762
|
+
if ind < self._nonzero and ind == other._nonzero:
|
|
1763
|
+
return self._data[2*ind+1] < 0
|
|
1764
|
+
if ind < other._nonzero and ind == self._nonzero:
|
|
1765
|
+
return other._data[2*ind+1] > 0
|
|
1766
|
+
return self._length < other._length
|
|
1767
|
+
|
|
1768
|
+
if op == Py_GT: # >
|
|
1769
|
+
while ind < self._nonzero and ind < other._nonzero:
|
|
1770
|
+
if self._data[2*ind] < other._data[2*ind]:
|
|
1771
|
+
return self._data[2*ind+1] > 0
|
|
1772
|
+
if self._data[2*ind] > other._data[2*ind]:
|
|
1773
|
+
return other._data[2*ind+1] < 0
|
|
1774
|
+
if self._data[2*ind] == other._data[2*ind] and self._data[2*ind+1] != other._data[2*ind+1]:
|
|
1775
|
+
return self._data[2*ind+1] > other._data[2*ind+1]
|
|
1776
|
+
ind += 1
|
|
1777
|
+
if ind < self._nonzero and ind == other._nonzero:
|
|
1778
|
+
return self._data[2*ind+1] > 0
|
|
1779
|
+
if ind < other._nonzero and ind == self._nonzero:
|
|
1780
|
+
return other._data[2*ind+1] < 0
|
|
1781
|
+
return self._length < other._length
|
|
1782
|
+
|
|
1783
|
+
# the rest of these are not particularly fast
|
|
1784
|
+
|
|
1785
|
+
if op == Py_LE: # <=
|
|
1786
|
+
return tuple(self) <= tuple(other)
|
|
1787
|
+
|
|
1788
|
+
if op == Py_NE: # !=
|
|
1789
|
+
return tuple(self) != tuple(other)
|
|
1790
|
+
|
|
1791
|
+
if op == Py_GE: # >=
|
|
1792
|
+
return tuple(self) >= tuple(other)
|
|
1793
|
+
|
|
1794
|
+
def __iter__(self):
|
|
1795
|
+
"""
|
|
1796
|
+
``x.__iter__() <==> iter(x)``.
|
|
1797
|
+
|
|
1798
|
+
TESTS::
|
|
1799
|
+
|
|
1800
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1801
|
+
sage: e = ETuple((4, 0, 0, 2, 0))
|
|
1802
|
+
sage: list(e)
|
|
1803
|
+
[4, 0, 0, 2, 0]
|
|
1804
|
+
|
|
1805
|
+
Check that :issue:`28178` is fixed::
|
|
1806
|
+
|
|
1807
|
+
sage: it = iter(e)
|
|
1808
|
+
sage: iter(it) is it
|
|
1809
|
+
True
|
|
1810
|
+
"""
|
|
1811
|
+
cdef size_t i
|
|
1812
|
+
cdef size_t ind = 0
|
|
1813
|
+
|
|
1814
|
+
for i in range(self._length):
|
|
1815
|
+
if ind >= self._nonzero:
|
|
1816
|
+
yield 0
|
|
1817
|
+
elif self._data[2*ind] == i:
|
|
1818
|
+
yield self._data[2*ind + 1]
|
|
1819
|
+
ind += 1
|
|
1820
|
+
else:
|
|
1821
|
+
yield 0
|
|
1822
|
+
|
|
1823
|
+
def __str__(self):
|
|
1824
|
+
return repr(self)
|
|
1825
|
+
|
|
1826
|
+
def __repr__(self):
|
|
1827
|
+
r"""
|
|
1828
|
+
TESTS::
|
|
1829
|
+
|
|
1830
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1831
|
+
sage: ETuple((0,))
|
|
1832
|
+
(0,)
|
|
1833
|
+
sage: ETuple((1,))
|
|
1834
|
+
(1,)
|
|
1835
|
+
sage: ETuple((0, 1, 2))
|
|
1836
|
+
(0, 1, 2)
|
|
1837
|
+
"""
|
|
1838
|
+
if self._length == 1:
|
|
1839
|
+
if self._nonzero:
|
|
1840
|
+
return '(%d,)' % self._data[1]
|
|
1841
|
+
else:
|
|
1842
|
+
return '(0,)'
|
|
1843
|
+
else:
|
|
1844
|
+
return '(' + ', '.join(map(str, self)) + ')'
|
|
1845
|
+
|
|
1846
|
+
def __reduce__(self):
|
|
1847
|
+
"""
|
|
1848
|
+
EXAMPLES::
|
|
1849
|
+
|
|
1850
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1851
|
+
sage: e = ETuple([1, 1, 0])
|
|
1852
|
+
sage: e == loads(dumps(e))
|
|
1853
|
+
True
|
|
1854
|
+
"""
|
|
1855
|
+
cdef size_t ind
|
|
1856
|
+
d = {self._data[2 * ind]: self._data[2 * ind + 1] for ind in range(self._nonzero)}
|
|
1857
|
+
return ETuple, (d, int(self._length))
|
|
1858
|
+
|
|
1859
|
+
# additional methods
|
|
1860
|
+
|
|
1861
|
+
cdef int _unweighted_degree(self) except *:
|
|
1862
|
+
r"""
|
|
1863
|
+
Return the sum of entries.
|
|
1864
|
+
|
|
1865
|
+
EXAMPLES::
|
|
1866
|
+
|
|
1867
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1868
|
+
sage: ETuple([1, 1, 0, 2, 0]).unweighted_degree()
|
|
1869
|
+
4
|
|
1870
|
+
sage: ETuple([-1, 1]).unweighted_degree()
|
|
1871
|
+
0
|
|
1872
|
+
"""
|
|
1873
|
+
cdef int degree = 0
|
|
1874
|
+
cdef size_t i
|
|
1875
|
+
for i in range(self._nonzero):
|
|
1876
|
+
degree += self._data[2 * i + 1]
|
|
1877
|
+
return degree
|
|
1878
|
+
|
|
1879
|
+
cpdef int unweighted_degree(self) except *:
|
|
1880
|
+
r"""
|
|
1881
|
+
Return the sum of entries.
|
|
1882
|
+
|
|
1883
|
+
EXAMPLES::
|
|
1884
|
+
|
|
1885
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1886
|
+
sage: ETuple([1, 1, 0, 2, 0]).unweighted_degree()
|
|
1887
|
+
4
|
|
1888
|
+
sage: ETuple([-1, 1]).unweighted_degree()
|
|
1889
|
+
0
|
|
1890
|
+
"""
|
|
1891
|
+
return self._unweighted_degree()
|
|
1892
|
+
|
|
1893
|
+
@cython.boundscheck(False)
|
|
1894
|
+
@cython.wraparound(False)
|
|
1895
|
+
cpdef int weighted_degree(self, tuple w) except *:
|
|
1896
|
+
r"""
|
|
1897
|
+
Return the weighted sum of entries.
|
|
1898
|
+
|
|
1899
|
+
INPUT:
|
|
1900
|
+
|
|
1901
|
+
- ``w`` -- tuple of nonnegative integers
|
|
1902
|
+
|
|
1903
|
+
EXAMPLES::
|
|
1904
|
+
|
|
1905
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
1906
|
+
sage: e = ETuple([1, 1, 0, 2, 0])
|
|
1907
|
+
sage: e.weighted_degree((1, 2, 3, 4, 5))
|
|
1908
|
+
11
|
|
1909
|
+
sage: ETuple([-1, 1]).weighted_degree((1, 2))
|
|
1910
|
+
1
|
|
1911
|
+
|
|
1912
|
+
sage: ETuple([1, 0]).weighted_degree((1, 2, 3))
|
|
1913
|
+
Traceback (most recent call last):
|
|
1914
|
+
...
|
|
1915
|
+
ValueError: w must be of the same length as the ETuple
|
|
1916
|
+
"""
|
|
1917
|
+
if len(w) != self._length:
|
|
1918
|
+
raise ValueError('w must be of the same length as the ETuple')
|
|
1919
|
+
|
|
1920
|
+
cdef size_t i
|
|
1921
|
+
cdef int deg = 0
|
|
1922
|
+
if len(w) != self._length:
|
|
1923
|
+
raise ValueError
|
|
1924
|
+
# NOTE: cython does optimize range(a) and range(a, b) but not range(a, b, c)
|
|
1925
|
+
for i in range(self._nonzero):
|
|
1926
|
+
deg += self._data[2 * i + 1] * <int> w[self._data[2 * i]]
|
|
1927
|
+
return deg
|
|
1928
|
+
|
|
1929
|
+
cpdef int unweighted_quotient_degree(self, ETuple other) except *:
|
|
1930
|
+
"""
|
|
1931
|
+
Return the degree of ``self`` divided by its gcd with ``other``.
|
|
1932
|
+
|
|
1933
|
+
It amounts to counting the nonnegative entries of
|
|
1934
|
+
``self.esub(other)``.
|
|
1935
|
+
"""
|
|
1936
|
+
cdef size_t ind1 = 0 # both ind1 and ind2 will be increased in double steps.
|
|
1937
|
+
cdef size_t ind2 = 0
|
|
1938
|
+
cdef int exponent
|
|
1939
|
+
cdef int position
|
|
1940
|
+
cdef size_t selfnz = 2 * self._nonzero
|
|
1941
|
+
cdef size_t othernz = 2 * other._nonzero
|
|
1942
|
+
|
|
1943
|
+
cdef int deg = 0
|
|
1944
|
+
while ind1 < selfnz:
|
|
1945
|
+
position = self._data[ind1]
|
|
1946
|
+
exponent = self._data[ind1 + 1]
|
|
1947
|
+
while ind2 < othernz and other._data[ind2] < position:
|
|
1948
|
+
ind2 += 2
|
|
1949
|
+
if ind2 == othernz:
|
|
1950
|
+
while ind1 < selfnz:
|
|
1951
|
+
deg += self._data[ind1 + 1]
|
|
1952
|
+
ind1 += 2
|
|
1953
|
+
return deg
|
|
1954
|
+
if other._data[ind2] > position:
|
|
1955
|
+
# other[position] = 0
|
|
1956
|
+
deg += exponent
|
|
1957
|
+
elif other._data[ind2 + 1] < exponent:
|
|
1958
|
+
# There is a positive difference that we have to insert
|
|
1959
|
+
deg += (exponent - other._data[ind2 + 1])
|
|
1960
|
+
ind1 += 2
|
|
1961
|
+
return deg
|
|
1962
|
+
|
|
1963
|
+
@cython.boundscheck(False)
|
|
1964
|
+
@cython.wraparound(False)
|
|
1965
|
+
cpdef int weighted_quotient_degree(self, ETuple other, tuple w) except *:
|
|
1966
|
+
r"""
|
|
1967
|
+
Return the weighted degree of ``self`` divided by its gcd with ``other``.
|
|
1968
|
+
|
|
1969
|
+
INPUT:
|
|
1970
|
+
|
|
1971
|
+
- ``other`` -- an :class:`~sage.rings.polynomial.polydict.ETuple`
|
|
1972
|
+
- ``w`` -- tuple of nonnegative integers
|
|
1973
|
+
"""
|
|
1974
|
+
if len(w) != self._length:
|
|
1975
|
+
raise ValueError('w must be of the same length as the ETuple')
|
|
1976
|
+
|
|
1977
|
+
cdef size_t ind1 = 0 # both ind1 and ind2 will be increased in double steps.
|
|
1978
|
+
cdef size_t ind2 = 0
|
|
1979
|
+
cdef size_t exponent
|
|
1980
|
+
cdef int position
|
|
1981
|
+
cdef size_t selfnz = 2 * self._nonzero
|
|
1982
|
+
cdef size_t othernz = 2 * other._nonzero
|
|
1983
|
+
|
|
1984
|
+
cdef size_t deg = 0
|
|
1985
|
+
assert len(w) == self._length
|
|
1986
|
+
while ind1 < selfnz:
|
|
1987
|
+
position = self._data[ind1]
|
|
1988
|
+
exponent = self._data[ind1+1]
|
|
1989
|
+
while ind2 < othernz and other._data[ind2] < position:
|
|
1990
|
+
ind2 += 2
|
|
1991
|
+
if ind2 == othernz:
|
|
1992
|
+
while ind1 < selfnz:
|
|
1993
|
+
deg += <size_t>self._data[ind1+1] * <size_t> w[self._data[ind1]]
|
|
1994
|
+
ind1 += 2
|
|
1995
|
+
return deg
|
|
1996
|
+
if other._data[ind2] > position:
|
|
1997
|
+
# other[position] = 0
|
|
1998
|
+
deg += exponent * <size_t>w[position]
|
|
1999
|
+
elif other._data[ind2+1] < exponent:
|
|
2000
|
+
# There is a positive difference that we have to insert
|
|
2001
|
+
deg += <size_t> (exponent - other._data[ind2+1]) * <size_t>w[position]
|
|
2002
|
+
ind1 += 2
|
|
2003
|
+
return deg
|
|
2004
|
+
|
|
2005
|
+
cpdef ETuple eadd(self, ETuple other):
|
|
2006
|
+
"""
|
|
2007
|
+
Return the vector addition of ``self`` with ``other``.
|
|
2008
|
+
|
|
2009
|
+
EXAMPLES::
|
|
2010
|
+
|
|
2011
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2012
|
+
sage: e = ETuple([1, 0, 2])
|
|
2013
|
+
sage: f = ETuple([0, 1, 1])
|
|
2014
|
+
sage: e.eadd(f)
|
|
2015
|
+
(1, 1, 3)
|
|
2016
|
+
|
|
2017
|
+
Verify that :issue:`6428` has been addressed::
|
|
2018
|
+
|
|
2019
|
+
sage: # needs sage.libs.singular
|
|
2020
|
+
sage: R.<y, z> = Frac(QQ['x'])[]
|
|
2021
|
+
sage: type(y)
|
|
2022
|
+
<class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>
|
|
2023
|
+
sage: y^(2^32)
|
|
2024
|
+
Traceback (most recent call last):
|
|
2025
|
+
...
|
|
2026
|
+
OverflowError: exponent overflow (...) # 64-bit
|
|
2027
|
+
OverflowError: Python int too large to convert to C unsigned long # 32-bit
|
|
2028
|
+
"""
|
|
2029
|
+
if self._length != other._length:
|
|
2030
|
+
raise ArithmeticError('ETuple of different lengths')
|
|
2031
|
+
|
|
2032
|
+
cdef size_t ind1 = 0
|
|
2033
|
+
cdef size_t ind2 = 0
|
|
2034
|
+
cdef size_t index
|
|
2035
|
+
cdef int exp1
|
|
2036
|
+
cdef int exp2
|
|
2037
|
+
cdef int s # sum
|
|
2038
|
+
cdef size_t alloc_len = self._nonzero + other._nonzero # we simply guesstimate the length -- there might be double the correct amount allocated -- who cares?
|
|
2039
|
+
if alloc_len > self._length:
|
|
2040
|
+
alloc_len = self._length
|
|
2041
|
+
cdef ETuple result = <ETuple>self._new()
|
|
2042
|
+
result._nonzero = 0 # we don't know the correct length quite yet
|
|
2043
|
+
result._data = <int*>sig_malloc(sizeof(int)*alloc_len*2)
|
|
2044
|
+
while dual_etuple_iter(self, other, &ind1, &ind2, &index, &exp1, &exp2):
|
|
2045
|
+
s = exp1 + exp2
|
|
2046
|
+
# Check for overflow and underflow
|
|
2047
|
+
if (exp2 > 0 and s < exp1) or (exp2 < 0 and s > exp1):
|
|
2048
|
+
raise OverflowError("exponent overflow (%s)" % (int(exp1)+int(exp2)))
|
|
2049
|
+
if s != 0:
|
|
2050
|
+
result._data[2*result._nonzero] = index
|
|
2051
|
+
result._data[2*result._nonzero+1] = s
|
|
2052
|
+
result._nonzero += 1
|
|
2053
|
+
return result
|
|
2054
|
+
|
|
2055
|
+
cpdef ETuple eadd_p(self, int other, size_t pos):
|
|
2056
|
+
"""
|
|
2057
|
+
Add ``other`` to ``self`` at position ``pos``.
|
|
2058
|
+
|
|
2059
|
+
EXAMPLES::
|
|
2060
|
+
|
|
2061
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2062
|
+
sage: e = ETuple([1, 0, 2])
|
|
2063
|
+
sage: e.eadd_p(5, 1)
|
|
2064
|
+
(1, 5, 2)
|
|
2065
|
+
sage: e = ETuple([0]*7)
|
|
2066
|
+
sage: e.eadd_p(5, 4)
|
|
2067
|
+
(0, 0, 0, 0, 5, 0, 0)
|
|
2068
|
+
|
|
2069
|
+
sage: ETuple([0,1]).eadd_p(1, 0) == ETuple([1,1])
|
|
2070
|
+
True
|
|
2071
|
+
|
|
2072
|
+
sage: e = ETuple([0, 1, 0])
|
|
2073
|
+
sage: e.eadd_p(0, 0).nonzero_positions()
|
|
2074
|
+
[1]
|
|
2075
|
+
sage: e.eadd_p(0, 1).nonzero_positions()
|
|
2076
|
+
[1]
|
|
2077
|
+
sage: e.eadd_p(0, 2).nonzero_positions()
|
|
2078
|
+
[1]
|
|
2079
|
+
|
|
2080
|
+
TESTS:
|
|
2081
|
+
|
|
2082
|
+
Test segmentation faults occurring as described in :issue:`34000`::
|
|
2083
|
+
|
|
2084
|
+
sage: ETuple([0, 1, 1]).eadd_p(1, 0)
|
|
2085
|
+
(1, 1, 1)
|
|
2086
|
+
sage: ETuple([0, 2, 4, 3]).eadd_p(5, 0)
|
|
2087
|
+
(5, 2, 4, 3)
|
|
2088
|
+
sage: ETuple([0, 2]).eadd_p(5, 0)
|
|
2089
|
+
(5, 2)
|
|
2090
|
+
sage: e = ETuple([0, 1, 0])
|
|
2091
|
+
sage: e.eadd_p(0, 0).nonzero_positions()
|
|
2092
|
+
[1]
|
|
2093
|
+
sage: e.eadd_p(0, 1).nonzero_positions()
|
|
2094
|
+
[1]
|
|
2095
|
+
sage: e.eadd_p(0, 2).nonzero_positions()
|
|
2096
|
+
[1]
|
|
2097
|
+
sage: e.eadd_p(-1, 1).nonzero_positions()
|
|
2098
|
+
[]
|
|
2099
|
+
"""
|
|
2100
|
+
cdef size_t sindex = 0
|
|
2101
|
+
cdef size_t rindex = 0
|
|
2102
|
+
cdef int new_value
|
|
2103
|
+
if pos >= self._length:
|
|
2104
|
+
raise ValueError("pos must be between 0 and %s" % self._length)
|
|
2105
|
+
|
|
2106
|
+
cdef ETuple result = self._new()
|
|
2107
|
+
result._nonzero = self._nonzero
|
|
2108
|
+
if not other:
|
|
2109
|
+
# return a copy
|
|
2110
|
+
result._data = <int*> sig_malloc(sizeof(int) * self._nonzero * 2)
|
|
2111
|
+
memcpy(result._data, self._data, sizeof(int) * self._nonzero * 2)
|
|
2112
|
+
return result
|
|
2113
|
+
|
|
2114
|
+
result._data = <int*> sig_malloc(sizeof(int) * (self._nonzero + 1) * 2)
|
|
2115
|
+
while sindex < self._nonzero and self._data[2 * sindex] < pos:
|
|
2116
|
+
result._data[2 * sindex] = self._data[2 * sindex]
|
|
2117
|
+
result._data[2 * sindex + 1] = self._data[2 * sindex + 1]
|
|
2118
|
+
sindex += 1
|
|
2119
|
+
|
|
2120
|
+
if sindex < self._nonzero and self._data[2 * sindex] == pos:
|
|
2121
|
+
new_value = self._data[2 * sindex + 1] + other
|
|
2122
|
+
if new_value:
|
|
2123
|
+
result._data[2 * sindex] = pos
|
|
2124
|
+
result._data[2 * sindex + 1] = new_value
|
|
2125
|
+
sindex += 1
|
|
2126
|
+
rindex = sindex
|
|
2127
|
+
else:
|
|
2128
|
+
result._nonzero -= 1
|
|
2129
|
+
rindex = sindex
|
|
2130
|
+
sindex += 1
|
|
2131
|
+
else:
|
|
2132
|
+
result._data[2 * sindex] = pos
|
|
2133
|
+
result._data[2 * sindex + 1] = other
|
|
2134
|
+
result._nonzero += 1
|
|
2135
|
+
rindex = sindex + 1
|
|
2136
|
+
|
|
2137
|
+
memcpy(result._data + 2 * rindex,
|
|
2138
|
+
self._data + 2 * sindex,
|
|
2139
|
+
sizeof(int) * 2 * (self._nonzero - sindex))
|
|
2140
|
+
|
|
2141
|
+
return result
|
|
2142
|
+
|
|
2143
|
+
cpdef ETuple eadd_scaled(self, ETuple other, int scalar):
|
|
2144
|
+
"""
|
|
2145
|
+
Vector addition of ``self`` with ``scalar * other``.
|
|
2146
|
+
|
|
2147
|
+
EXAMPLES::
|
|
2148
|
+
|
|
2149
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2150
|
+
sage: e = ETuple([1, 0, 2])
|
|
2151
|
+
sage: f = ETuple([0, 1, 1])
|
|
2152
|
+
sage: e.eadd_scaled(f, 3)
|
|
2153
|
+
(1, 3, 5)
|
|
2154
|
+
"""
|
|
2155
|
+
if self._length != other._length:
|
|
2156
|
+
raise ArithmeticError('ETuple of different lengths')
|
|
2157
|
+
|
|
2158
|
+
cdef size_t ind1 = 0
|
|
2159
|
+
cdef size_t ind2 = 0
|
|
2160
|
+
cdef size_t index
|
|
2161
|
+
cdef int exp1
|
|
2162
|
+
cdef int exp2
|
|
2163
|
+
cdef int s # sum
|
|
2164
|
+
cdef size_t alloc_len = self._nonzero + other._nonzero # we simply guesstimate the length -- there might be double the correct amount allocated -- who cares?
|
|
2165
|
+
if alloc_len > self._length:
|
|
2166
|
+
alloc_len = self._length
|
|
2167
|
+
cdef ETuple result = <ETuple>self._new()
|
|
2168
|
+
result._nonzero = 0 # we don't know the correct length quite yet
|
|
2169
|
+
result._data = <int*>sig_malloc(sizeof(int)*alloc_len*2)
|
|
2170
|
+
while dual_etuple_iter(self, other, &ind1, &ind2, &index, &exp1, &exp2):
|
|
2171
|
+
exp2 *= scalar
|
|
2172
|
+
s = exp1 + exp2
|
|
2173
|
+
# Check for overflow and underflow
|
|
2174
|
+
if (exp2 > 0 and s < exp1) or (exp2 < 0 and s > exp1):
|
|
2175
|
+
raise OverflowError("exponent overflow (%s)" % (int(exp1)+int(exp2)))
|
|
2176
|
+
if s != 0:
|
|
2177
|
+
result._data[2*result._nonzero] = index
|
|
2178
|
+
result._data[2*result._nonzero+1] = s
|
|
2179
|
+
result._nonzero += 1
|
|
2180
|
+
return result
|
|
2181
|
+
|
|
2182
|
+
cpdef ETuple esub(self, ETuple other):
|
|
2183
|
+
"""
|
|
2184
|
+
Vector subtraction of ``self`` with ``other``.
|
|
2185
|
+
|
|
2186
|
+
EXAMPLES::
|
|
2187
|
+
|
|
2188
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2189
|
+
sage: e = ETuple([1, 0, 2])
|
|
2190
|
+
sage: f = ETuple([0, 1, 1])
|
|
2191
|
+
sage: e.esub(f)
|
|
2192
|
+
(1, -1, 1)
|
|
2193
|
+
"""
|
|
2194
|
+
if self._length!=other._length:
|
|
2195
|
+
raise ArithmeticError
|
|
2196
|
+
|
|
2197
|
+
cdef size_t ind1 = 0
|
|
2198
|
+
cdef size_t ind2 = 0
|
|
2199
|
+
cdef size_t index
|
|
2200
|
+
cdef int exp1
|
|
2201
|
+
cdef int exp2
|
|
2202
|
+
cdef int d # difference
|
|
2203
|
+
cdef size_t alloc_len = self._nonzero + other._nonzero # we simply guesstimate the length -- there might be double the correct amount allocated -- who cares?
|
|
2204
|
+
if alloc_len > self._length:
|
|
2205
|
+
alloc_len = self._length
|
|
2206
|
+
cdef ETuple result = <ETuple>self._new()
|
|
2207
|
+
result._nonzero = 0 # we don't know the correct length quite yet
|
|
2208
|
+
result._data = <int*>sig_malloc(sizeof(int)*alloc_len*2)
|
|
2209
|
+
while dual_etuple_iter(self, other, &ind1, &ind2, &index, &exp1, &exp2):
|
|
2210
|
+
# Check for overflow and underflow
|
|
2211
|
+
d = exp1 - exp2
|
|
2212
|
+
if (exp2 > 0 and d > exp1) or (exp2 < 0 and d < exp1):
|
|
2213
|
+
raise OverflowError("Exponent overflow (%s)" % (int(exp1)-int(exp2)))
|
|
2214
|
+
if d != 0:
|
|
2215
|
+
result._data[2*result._nonzero] = index
|
|
2216
|
+
result._data[2*result._nonzero+1] = d
|
|
2217
|
+
result._nonzero += 1
|
|
2218
|
+
return result
|
|
2219
|
+
|
|
2220
|
+
cpdef ETuple emul(self, int factor):
|
|
2221
|
+
"""
|
|
2222
|
+
Scalar Vector multiplication of ``self``.
|
|
2223
|
+
|
|
2224
|
+
EXAMPLES::
|
|
2225
|
+
|
|
2226
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2227
|
+
sage: e = ETuple([1, 0, 2])
|
|
2228
|
+
sage: e.emul(2)
|
|
2229
|
+
(2, 0, 4)
|
|
2230
|
+
"""
|
|
2231
|
+
cdef size_t ind
|
|
2232
|
+
cdef ETuple result = <ETuple>self._new()
|
|
2233
|
+
if factor == 0:
|
|
2234
|
+
result._nonzero = 0 # all zero, no nonzero entries!
|
|
2235
|
+
result._data = <int*>sig_malloc(sizeof(int) * result._nonzero * 2)
|
|
2236
|
+
else:
|
|
2237
|
+
result._nonzero = self._nonzero
|
|
2238
|
+
result._data = <int*>sig_malloc(sizeof(int) * result._nonzero * 2)
|
|
2239
|
+
for ind in range(self._nonzero):
|
|
2240
|
+
result._data[2 * ind] = self._data[2 * ind]
|
|
2241
|
+
result._data[2 * ind + 1] = self._data[2 * ind + 1] * factor
|
|
2242
|
+
return result
|
|
2243
|
+
|
|
2244
|
+
cpdef ETuple emax(self, ETuple other):
|
|
2245
|
+
"""
|
|
2246
|
+
Vector of maximum of components of ``self`` and ``other``.
|
|
2247
|
+
|
|
2248
|
+
EXAMPLES::
|
|
2249
|
+
|
|
2250
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2251
|
+
sage: e = ETuple([1, 0, 2])
|
|
2252
|
+
sage: f = ETuple([0, 1, 1])
|
|
2253
|
+
sage: e.emax(f)
|
|
2254
|
+
(1, 1, 2)
|
|
2255
|
+
sage: e = ETuple((1, 2, 3, 4))
|
|
2256
|
+
sage: f = ETuple((4, 0, 2, 1))
|
|
2257
|
+
sage: f.emax(e)
|
|
2258
|
+
(4, 2, 3, 4)
|
|
2259
|
+
sage: e = ETuple((1, -2, -2, 4))
|
|
2260
|
+
sage: f = ETuple((4, 0, 0, 0))
|
|
2261
|
+
sage: f.emax(e)
|
|
2262
|
+
(4, 0, 0, 4)
|
|
2263
|
+
sage: f.emax(e).nonzero_positions()
|
|
2264
|
+
[0, 3]
|
|
2265
|
+
"""
|
|
2266
|
+
if self._length!=other._length:
|
|
2267
|
+
raise ArithmeticError
|
|
2268
|
+
|
|
2269
|
+
cdef size_t ind1 = 0
|
|
2270
|
+
cdef size_t ind2 = 0
|
|
2271
|
+
cdef size_t index
|
|
2272
|
+
cdef int exp1
|
|
2273
|
+
cdef int exp2
|
|
2274
|
+
cdef size_t alloc_len = self._nonzero + other._nonzero # we simply guesstimate the length -- there might be double the correct amount allocated -- who cares?
|
|
2275
|
+
if alloc_len > self._length:
|
|
2276
|
+
alloc_len = self._length
|
|
2277
|
+
cdef ETuple result = <ETuple>self._new()
|
|
2278
|
+
result._nonzero = 0 # we don't know the correct length quite yet
|
|
2279
|
+
result._data = <int*>sig_malloc(sizeof(int)*alloc_len*2)
|
|
2280
|
+
while dual_etuple_iter(self, other, &ind1, &ind2, &index, &exp1, &exp2):
|
|
2281
|
+
if exp1 >= exp2 and exp1 != 0:
|
|
2282
|
+
result._data[2*result._nonzero] = index
|
|
2283
|
+
result._data[2*result._nonzero+1] = exp1
|
|
2284
|
+
result._nonzero += 1
|
|
2285
|
+
elif exp2 >= exp1 and exp2 != 0:
|
|
2286
|
+
result._data[2*result._nonzero] = index
|
|
2287
|
+
result._data[2*result._nonzero+1] = exp2
|
|
2288
|
+
result._nonzero += 1
|
|
2289
|
+
return result
|
|
2290
|
+
|
|
2291
|
+
cpdef ETuple emin(self, ETuple other):
|
|
2292
|
+
"""
|
|
2293
|
+
Vector of minimum of components of ``self`` and ``other``.
|
|
2294
|
+
|
|
2295
|
+
EXAMPLES::
|
|
2296
|
+
|
|
2297
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2298
|
+
sage: e = ETuple([1, 0, 2])
|
|
2299
|
+
sage: f = ETuple([0, 1, 1])
|
|
2300
|
+
sage: e.emin(f)
|
|
2301
|
+
(0, 0, 1)
|
|
2302
|
+
sage: e = ETuple([1, 0, -1])
|
|
2303
|
+
sage: f = ETuple([0, -2, 1])
|
|
2304
|
+
sage: e.emin(f)
|
|
2305
|
+
(0, -2, -1)
|
|
2306
|
+
"""
|
|
2307
|
+
if self._length != other._length:
|
|
2308
|
+
raise ArithmeticError
|
|
2309
|
+
|
|
2310
|
+
cdef size_t ind1 = 0
|
|
2311
|
+
cdef size_t ind2 = 0
|
|
2312
|
+
cdef size_t index
|
|
2313
|
+
cdef int exp1
|
|
2314
|
+
cdef int exp2
|
|
2315
|
+
cdef size_t alloc_len = self._nonzero + other._nonzero # we simply guesstimate the length -- there might be double the correct amount allocated -- who cares?
|
|
2316
|
+
if alloc_len > self._length:
|
|
2317
|
+
alloc_len = self._length
|
|
2318
|
+
cdef ETuple result = <ETuple>self._new()
|
|
2319
|
+
result._nonzero = 0 # we don't know the correct length quite yet
|
|
2320
|
+
result._data = <int*>sig_malloc(sizeof(int)*alloc_len*2)
|
|
2321
|
+
while dual_etuple_iter(self, other, &ind1, &ind2, &index, &exp1, &exp2):
|
|
2322
|
+
if exp1 <= exp2 and exp1 != 0:
|
|
2323
|
+
result._data[2*result._nonzero] = index
|
|
2324
|
+
result._data[2*result._nonzero+1] = exp1
|
|
2325
|
+
result._nonzero += 1
|
|
2326
|
+
elif exp2 <= exp1 and exp2 != 0:
|
|
2327
|
+
result._data[2*result._nonzero] = index
|
|
2328
|
+
result._data[2*result._nonzero+1] = exp2
|
|
2329
|
+
result._nonzero += 1
|
|
2330
|
+
return result
|
|
2331
|
+
|
|
2332
|
+
cpdef int dotprod(self, ETuple other) except *:
|
|
2333
|
+
"""
|
|
2334
|
+
Return the dot product of this tuple by ``other``.
|
|
2335
|
+
|
|
2336
|
+
EXAMPLES::
|
|
2337
|
+
|
|
2338
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2339
|
+
sage: e = ETuple([1, 0, 2])
|
|
2340
|
+
sage: f = ETuple([0, 1, 1])
|
|
2341
|
+
sage: e.dotprod(f)
|
|
2342
|
+
2
|
|
2343
|
+
sage: e = ETuple([1, 1, -1])
|
|
2344
|
+
sage: f = ETuple([0, -2, 1])
|
|
2345
|
+
sage: e.dotprod(f)
|
|
2346
|
+
-3
|
|
2347
|
+
"""
|
|
2348
|
+
if self._length != other._length:
|
|
2349
|
+
raise ArithmeticError
|
|
2350
|
+
|
|
2351
|
+
cdef size_t ind1 = 0
|
|
2352
|
+
cdef size_t ind2 = 0
|
|
2353
|
+
cdef size_t index
|
|
2354
|
+
cdef int exp1
|
|
2355
|
+
cdef int exp2
|
|
2356
|
+
cdef int result = 0
|
|
2357
|
+
while dual_etuple_iter(self, other, &ind1, &ind2, &index, &exp1, &exp2):
|
|
2358
|
+
result += exp1 * exp2
|
|
2359
|
+
return result
|
|
2360
|
+
|
|
2361
|
+
cpdef ETuple escalar_div(self, int n):
|
|
2362
|
+
r"""
|
|
2363
|
+
Divide each exponent by ``n``.
|
|
2364
|
+
|
|
2365
|
+
EXAMPLES::
|
|
2366
|
+
|
|
2367
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2368
|
+
sage: ETuple([1, 0, 2]).escalar_div(2)
|
|
2369
|
+
(0, 0, 1)
|
|
2370
|
+
sage: ETuple([0, 3, 12]).escalar_div(3)
|
|
2371
|
+
(0, 1, 4)
|
|
2372
|
+
|
|
2373
|
+
sage: ETuple([1, 5, 2]).escalar_div(0)
|
|
2374
|
+
Traceback (most recent call last):
|
|
2375
|
+
...
|
|
2376
|
+
ZeroDivisionError
|
|
2377
|
+
|
|
2378
|
+
TESTS:
|
|
2379
|
+
|
|
2380
|
+
Checking that memory allocation works fine::
|
|
2381
|
+
|
|
2382
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2383
|
+
sage: t = ETuple(list(range(2048)))
|
|
2384
|
+
sage: for n in range(1, 9):
|
|
2385
|
+
....: t = t.escalar_div(n)
|
|
2386
|
+
sage: assert t.is_constant()
|
|
2387
|
+
"""
|
|
2388
|
+
if not n:
|
|
2389
|
+
raise ZeroDivisionError
|
|
2390
|
+
cdef size_t i
|
|
2391
|
+
cdef ETuple result = self._new()
|
|
2392
|
+
result._data = <int*> sig_malloc(sizeof(int) * 2 * self._nonzero)
|
|
2393
|
+
result._nonzero = 0
|
|
2394
|
+
# NOTE: cython does optimize range(a) and range(a, b) but not range(a, b, c)
|
|
2395
|
+
for i in range(self._nonzero):
|
|
2396
|
+
result._data[2 * result._nonzero + 1] = self._data[2 * i + 1] / n
|
|
2397
|
+
if result._data[2 * result._nonzero + 1]:
|
|
2398
|
+
result._data[2 * result._nonzero] = self._data[2 * i]
|
|
2399
|
+
result._nonzero += 1
|
|
2400
|
+
return result
|
|
2401
|
+
|
|
2402
|
+
cpdef ETuple divide_by_gcd(self, ETuple other):
|
|
2403
|
+
"""
|
|
2404
|
+
Return ``self / gcd(self, other)``.
|
|
2405
|
+
|
|
2406
|
+
The entries of the result are the maximum of 0 and the
|
|
2407
|
+
difference of the corresponding entries of ``self`` and ``other``.
|
|
2408
|
+
"""
|
|
2409
|
+
if self._length != other._length:
|
|
2410
|
+
raise ArithmeticError('ETuple of different lengths')
|
|
2411
|
+
cdef size_t ind1 = 0 # both ind1 and ind2 will be increased in 2-steps.
|
|
2412
|
+
cdef size_t ind2 = 0
|
|
2413
|
+
cdef int exponent
|
|
2414
|
+
cdef int position
|
|
2415
|
+
cdef size_t selfnz = 2 * self._nonzero
|
|
2416
|
+
cdef size_t othernz = 2 * other._nonzero
|
|
2417
|
+
cdef ETuple result = <ETuple> self._new()
|
|
2418
|
+
result._nonzero = 0
|
|
2419
|
+
result._data = <int*> sig_malloc(sizeof(int)*self._nonzero*2)
|
|
2420
|
+
while ind1 < selfnz:
|
|
2421
|
+
position = self._data[ind1]
|
|
2422
|
+
exponent = self._data[ind1+1]
|
|
2423
|
+
while ind2 < othernz and other._data[ind2] < position:
|
|
2424
|
+
ind2 += 2
|
|
2425
|
+
if ind2 == othernz:
|
|
2426
|
+
while ind1 < selfnz:
|
|
2427
|
+
result._data[2*result._nonzero] = self._data[ind1]
|
|
2428
|
+
result._data[2*result._nonzero+1] = self._data[ind1+1]
|
|
2429
|
+
result._nonzero += 1
|
|
2430
|
+
ind1 += 2
|
|
2431
|
+
return result
|
|
2432
|
+
if other._data[ind2] > position:
|
|
2433
|
+
# other[position] == 0
|
|
2434
|
+
result._data[2*result._nonzero] = position
|
|
2435
|
+
result._data[2*result._nonzero+1] = exponent
|
|
2436
|
+
result._nonzero += 1
|
|
2437
|
+
elif other._data[ind2+1] < exponent:
|
|
2438
|
+
# There is a positive difference that we have to insert
|
|
2439
|
+
result._data[2*result._nonzero] = position
|
|
2440
|
+
result._data[2*result._nonzero+1] = exponent - other._data[ind2+1]
|
|
2441
|
+
result._nonzero += 1
|
|
2442
|
+
ind1 += 2
|
|
2443
|
+
return result
|
|
2444
|
+
|
|
2445
|
+
cpdef ETuple divide_by_var(self, size_t pos):
|
|
2446
|
+
"""
|
|
2447
|
+
Return division of ``self`` by the variable with index ``pos``.
|
|
2448
|
+
|
|
2449
|
+
If ``self[pos] == 0`` then a :exc:`ArithmeticError` is raised. Otherwise,
|
|
2450
|
+
an :class:`~sage.rings.polynomial.polydict.ETuple` is returned that is
|
|
2451
|
+
zero in position ``pos`` and coincides with ``self`` in the other
|
|
2452
|
+
positions.
|
|
2453
|
+
|
|
2454
|
+
EXAMPLES::
|
|
2455
|
+
|
|
2456
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2457
|
+
sage: e = ETuple([1, 2, 0, 1])
|
|
2458
|
+
sage: e.divide_by_var(0)
|
|
2459
|
+
(0, 2, 0, 1)
|
|
2460
|
+
sage: e.divide_by_var(1)
|
|
2461
|
+
(1, 1, 0, 1)
|
|
2462
|
+
sage: e.divide_by_var(3)
|
|
2463
|
+
(1, 2, 0, 0)
|
|
2464
|
+
sage: e.divide_by_var(2)
|
|
2465
|
+
Traceback (most recent call last):
|
|
2466
|
+
...
|
|
2467
|
+
ArithmeticError: not divisible by this variable
|
|
2468
|
+
"""
|
|
2469
|
+
cdef int exp1
|
|
2470
|
+
cdef ETuple result
|
|
2471
|
+
cdef size_t ind
|
|
2472
|
+
|
|
2473
|
+
ind = self.get_position(pos, 0, self._nonzero)
|
|
2474
|
+
if ind == self._nonzero or self._data[2 * ind] != pos:
|
|
2475
|
+
raise ArithmeticError('not divisible by this variable')
|
|
2476
|
+
result = <ETuple> self._new()
|
|
2477
|
+
result._data = <int*> sig_malloc(sizeof(int) * 2 * self._nonzero)
|
|
2478
|
+
exp1 = self._data[2 * ind + 1]
|
|
2479
|
+
if exp1 > 1:
|
|
2480
|
+
# division doesn't change the number of nonzero positions
|
|
2481
|
+
result._nonzero = self._nonzero
|
|
2482
|
+
memcpy(result._data, self._data, sizeof(int) * 2 * self._nonzero)
|
|
2483
|
+
result._data[2 * ind + 1] = exp1 - 1
|
|
2484
|
+
else:
|
|
2485
|
+
# var(pos) disappears from self
|
|
2486
|
+
result._nonzero = self._nonzero - 1
|
|
2487
|
+
memcpy(result._data, self._data, sizeof(int) * 2 * ind)
|
|
2488
|
+
if ind + 1 < self._nonzero:
|
|
2489
|
+
memcpy(result._data + 2 * ind, self._data + 2 * (ind + 1), sizeof(int) * 2 * (self._nonzero - ind - 1))
|
|
2490
|
+
return result
|
|
2491
|
+
|
|
2492
|
+
cpdef bint divides(self, ETuple other) except *:
|
|
2493
|
+
"""
|
|
2494
|
+
Return whether ``self`` divides ``other``, i.e., no entry of ``self``
|
|
2495
|
+
exceeds that of ``other``.
|
|
2496
|
+
|
|
2497
|
+
EXAMPLES::
|
|
2498
|
+
|
|
2499
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2500
|
+
sage: ETuple([1, 1, 0, 1, 0]).divides(ETuple([2, 2, 2, 2, 2]))
|
|
2501
|
+
True
|
|
2502
|
+
sage: ETuple([0, 3, 0, 1, 0]).divides(ETuple([2, 2, 2, 2, 2]))
|
|
2503
|
+
False
|
|
2504
|
+
sage: ETuple([0, 3, 0, 1, 0]).divides(ETuple([0, 3, 2, 2, 2]))
|
|
2505
|
+
True
|
|
2506
|
+
sage: ETuple([0, 0, 0, 0, 0]).divides(ETuple([2, 2, 2, 2, 2]))
|
|
2507
|
+
True
|
|
2508
|
+
|
|
2509
|
+
sage: ETuple({104: 18, 256: 25, 314:78}, length=400r).divides(ETuple({104: 19, 105: 20, 106: 21}, length=400r))
|
|
2510
|
+
False
|
|
2511
|
+
sage: ETuple({104: 18, 256: 25, 314:78}, length=400r).divides(ETuple({104: 19, 105: 20, 106: 21, 255: 2, 256: 25, 312: 5, 314: 79, 315: 28}, length=400r))
|
|
2512
|
+
True
|
|
2513
|
+
"""
|
|
2514
|
+
cdef size_t ind1 = 0
|
|
2515
|
+
cdef size_t ind2 = 0
|
|
2516
|
+
cdef int pos1
|
|
2517
|
+
|
|
2518
|
+
if self._length != other._length:
|
|
2519
|
+
raise ArithmeticError('ETuple of different length')
|
|
2520
|
+
|
|
2521
|
+
while ind1 < self._nonzero:
|
|
2522
|
+
if self._nonzero - ind1 > other._nonzero - ind2:
|
|
2523
|
+
return False
|
|
2524
|
+
pos1 = self._data[2 * ind1]
|
|
2525
|
+
ind2 = other.get_position(pos1, ind2, other._nonzero)
|
|
2526
|
+
if ind2 == other._nonzero or other._data[2 * ind2] != pos1 or other._data[2 * ind2 + 1] < self._data[2 * ind1 + 1]:
|
|
2527
|
+
return False
|
|
2528
|
+
ind1 += 1
|
|
2529
|
+
ind2 += 1
|
|
2530
|
+
|
|
2531
|
+
return True
|
|
2532
|
+
|
|
2533
|
+
cpdef bint is_constant(self) noexcept:
|
|
2534
|
+
"""
|
|
2535
|
+
Return if all exponents are zero in the tuple.
|
|
2536
|
+
|
|
2537
|
+
EXAMPLES::
|
|
2538
|
+
|
|
2539
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2540
|
+
sage: e = ETuple([1, 0, 2])
|
|
2541
|
+
sage: e.is_constant()
|
|
2542
|
+
False
|
|
2543
|
+
sage: e = ETuple([0, 0])
|
|
2544
|
+
sage: e.is_constant()
|
|
2545
|
+
True
|
|
2546
|
+
"""
|
|
2547
|
+
return self._nonzero == 0
|
|
2548
|
+
|
|
2549
|
+
cpdef bint is_multiple_of(self, int n) except *:
|
|
2550
|
+
r"""
|
|
2551
|
+
Test whether each entry is a multiple of ``n``.
|
|
2552
|
+
|
|
2553
|
+
EXAMPLES::
|
|
2554
|
+
|
|
2555
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2556
|
+
|
|
2557
|
+
sage: ETuple([0, 0]).is_multiple_of(3)
|
|
2558
|
+
True
|
|
2559
|
+
sage: ETuple([0, 3, 12, 0, 6]).is_multiple_of(3)
|
|
2560
|
+
True
|
|
2561
|
+
sage: ETuple([0, 0, 2]).is_multiple_of(3)
|
|
2562
|
+
False
|
|
2563
|
+
"""
|
|
2564
|
+
if not n:
|
|
2565
|
+
raise ValueError('n should not be zero')
|
|
2566
|
+
cdef size_t i
|
|
2567
|
+
for i in range(self._nonzero):
|
|
2568
|
+
if self._data[2 * i + 1] % n:
|
|
2569
|
+
return False
|
|
2570
|
+
return True
|
|
2571
|
+
|
|
2572
|
+
cpdef list nonzero_positions(self, bint sort=False):
|
|
2573
|
+
"""
|
|
2574
|
+
Return the positions of nonzero exponents in the tuple.
|
|
2575
|
+
|
|
2576
|
+
INPUT:
|
|
2577
|
+
|
|
2578
|
+
- ``sort`` -- boolean (default: ``False``); if ``True`` a sorted list is
|
|
2579
|
+
returned; if ``False`` an unsorted list is returned
|
|
2580
|
+
|
|
2581
|
+
EXAMPLES::
|
|
2582
|
+
|
|
2583
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2584
|
+
sage: e = ETuple([1, 0, 2])
|
|
2585
|
+
sage: e.nonzero_positions()
|
|
2586
|
+
[0, 2]
|
|
2587
|
+
"""
|
|
2588
|
+
cdef size_t ind
|
|
2589
|
+
return [self._data[2 * ind] for ind in range(self._nonzero)]
|
|
2590
|
+
|
|
2591
|
+
cpdef common_nonzero_positions(self, ETuple other, bint sort=False):
|
|
2592
|
+
"""
|
|
2593
|
+
Return an optionally sorted list of nonzero positions either
|
|
2594
|
+
in ``self`` or other, i.e. the only positions that need to be
|
|
2595
|
+
considered for any vector operation.
|
|
2596
|
+
|
|
2597
|
+
EXAMPLES::
|
|
2598
|
+
|
|
2599
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2600
|
+
sage: e = ETuple([1, 0, 2])
|
|
2601
|
+
sage: f = ETuple([0, 0, 1])
|
|
2602
|
+
sage: e.common_nonzero_positions(f)
|
|
2603
|
+
{0, 2}
|
|
2604
|
+
sage: e.common_nonzero_positions(f, sort=True)
|
|
2605
|
+
[0, 2]
|
|
2606
|
+
"""
|
|
2607
|
+
# TODO: we should probably make a fast version of this!
|
|
2608
|
+
res = set(self.nonzero_positions()).union(other.nonzero_positions())
|
|
2609
|
+
if sort:
|
|
2610
|
+
return sorted(res)
|
|
2611
|
+
else:
|
|
2612
|
+
return res
|
|
2613
|
+
|
|
2614
|
+
cpdef list nonzero_values(self, bint sort=True):
|
|
2615
|
+
"""
|
|
2616
|
+
Return the nonzero values of the tuple.
|
|
2617
|
+
|
|
2618
|
+
INPUT:
|
|
2619
|
+
|
|
2620
|
+
- ``sort`` -- boolean (default: ``True``); if ``True`` the values are
|
|
2621
|
+
sorted by their indices. Otherwise the values are returned unsorted.
|
|
2622
|
+
|
|
2623
|
+
EXAMPLES::
|
|
2624
|
+
|
|
2625
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2626
|
+
sage: e = ETuple([2, 0, 1])
|
|
2627
|
+
sage: e.nonzero_values()
|
|
2628
|
+
[2, 1]
|
|
2629
|
+
sage: f = ETuple([0, -1, 1])
|
|
2630
|
+
sage: f.nonzero_values(sort=True)
|
|
2631
|
+
[-1, 1]
|
|
2632
|
+
"""
|
|
2633
|
+
cdef size_t ind
|
|
2634
|
+
return [self._data[2 * ind + 1] for ind in range(self._nonzero)]
|
|
2635
|
+
|
|
2636
|
+
cpdef ETuple reversed(self):
|
|
2637
|
+
"""
|
|
2638
|
+
Return the reversed ETuple of ``self``.
|
|
2639
|
+
|
|
2640
|
+
EXAMPLES::
|
|
2641
|
+
|
|
2642
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2643
|
+
sage: e = ETuple([1, 2, 3])
|
|
2644
|
+
sage: e.reversed()
|
|
2645
|
+
(3, 2, 1)
|
|
2646
|
+
"""
|
|
2647
|
+
cdef size_t ind
|
|
2648
|
+
cdef ETuple result = <ETuple>self._new()
|
|
2649
|
+
result._nonzero = self._nonzero
|
|
2650
|
+
result._data = <int*>sig_malloc(sizeof(int) * result._nonzero * 2)
|
|
2651
|
+
for ind in range(self._nonzero):
|
|
2652
|
+
result._data[2 * (result._nonzero - ind - 1)] = self._length - self._data[2 * ind] - 1
|
|
2653
|
+
result._data[2 * (result._nonzero - ind - 1) + 1] = self._data[2 * ind + 1]
|
|
2654
|
+
return result
|
|
2655
|
+
|
|
2656
|
+
def sparse_iter(self):
|
|
2657
|
+
"""
|
|
2658
|
+
Iterator over the elements of ``self`` where the elements are returned
|
|
2659
|
+
as ``(i, e)`` where ``i`` is the position of ``e`` in the tuple.
|
|
2660
|
+
|
|
2661
|
+
EXAMPLES::
|
|
2662
|
+
|
|
2663
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2664
|
+
sage: e = ETuple([1, 0, 2, 0, 3])
|
|
2665
|
+
sage: list(e.sparse_iter())
|
|
2666
|
+
[(0, 1), (2, 2), (4, 3)]
|
|
2667
|
+
"""
|
|
2668
|
+
cdef size_t ind
|
|
2669
|
+
for ind in range(self._nonzero):
|
|
2670
|
+
yield (self._data[2 * ind], self._data[2 * ind + 1])
|
|
2671
|
+
|
|
2672
|
+
def combine_to_positives(self, ETuple other):
|
|
2673
|
+
"""
|
|
2674
|
+
Given a pair of ETuples (self, other), returns a triple of
|
|
2675
|
+
ETuples (a, b, c) so that self = a + b, other = a + c and b and c
|
|
2676
|
+
have all positive entries.
|
|
2677
|
+
|
|
2678
|
+
EXAMPLES::
|
|
2679
|
+
|
|
2680
|
+
sage: from sage.rings.polynomial.polydict import ETuple
|
|
2681
|
+
sage: e = ETuple([-2, 1, -5, 3, 1, 0])
|
|
2682
|
+
sage: f = ETuple([1, -3, -3, 4, 0, 2])
|
|
2683
|
+
sage: e.combine_to_positives(f)
|
|
2684
|
+
((-2, -3, -5, 3, 0, 0), (0, 4, 0, 0, 1, 0), (3, 0, 2, 1, 0, 2))
|
|
2685
|
+
"""
|
|
2686
|
+
m = self.emin(other)
|
|
2687
|
+
return m, self.esub(m), other.esub(m)
|
|
2688
|
+
|
|
2689
|
+
|
|
2690
|
+
def make_PolyDict(data):
|
|
2691
|
+
r"""
|
|
2692
|
+
Ensure support for pickled data from older sage versions.
|
|
2693
|
+
"""
|
|
2694
|
+
return PolyDict(data)
|
|
2695
|
+
|
|
2696
|
+
|
|
2697
|
+
def make_ETuple(data, length):
|
|
2698
|
+
r"""
|
|
2699
|
+
Ensure support for pickled data from older sage versions.
|
|
2700
|
+
"""
|
|
2701
|
+
return ETuple(data, length)
|