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,2465 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
# sage.doctest: needs sage.libs.pari
|
|
3
|
+
"""
|
|
4
|
+
Quotients of Univariate Polynomial Rings
|
|
5
|
+
|
|
6
|
+
EXAMPLES::
|
|
7
|
+
|
|
8
|
+
sage: R.<x> = QQ[]
|
|
9
|
+
sage: S = R.quotient(x**3 - 3*x + 1, 'alpha')
|
|
10
|
+
sage: S.gen()**2 in S
|
|
11
|
+
True
|
|
12
|
+
sage: x in S
|
|
13
|
+
True
|
|
14
|
+
sage: S.gen() in R
|
|
15
|
+
False
|
|
16
|
+
sage: 1 in S
|
|
17
|
+
True
|
|
18
|
+
|
|
19
|
+
TESTS::
|
|
20
|
+
|
|
21
|
+
sage: # needs sage.libs.flint sage.libs.singular
|
|
22
|
+
sage: Pol.<y> = CBF[]
|
|
23
|
+
sage: Quo.<y> = Pol.quotient(y^3)
|
|
24
|
+
sage: CBF.zero()*y
|
|
25
|
+
0
|
|
26
|
+
sage: ((x - 1)/(x + 1))(1 + y)
|
|
27
|
+
-0.2500000000000000*y^2 + 0.5000000000000000*y
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
#*****************************************************************************
|
|
31
|
+
# Copyright (C) 2005, 2006 William Stein <wstein@gmail.com>
|
|
32
|
+
# 2016 Julian Rüth <julian.rueth@fsfe.org>
|
|
33
|
+
#
|
|
34
|
+
# This program is free software: you can redistribute it and/or modify
|
|
35
|
+
# it under the terms of the GNU General Public License as published by
|
|
36
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
37
|
+
# (at your option) any later version.
|
|
38
|
+
# https://www.gnu.org/licenses/
|
|
39
|
+
#*****************************************************************************
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
from . import polynomial_element
|
|
43
|
+
import sage.rings.rational_field
|
|
44
|
+
|
|
45
|
+
from sage.arith.misc import crt
|
|
46
|
+
from sage.rings.ring import Field, CommutativeRing
|
|
47
|
+
|
|
48
|
+
from sage.misc.cachefunc import cached_method
|
|
49
|
+
from sage.rings.polynomial.polynomial_quotient_ring_element import PolynomialQuotientRingElement
|
|
50
|
+
from sage.rings.polynomial.polynomial_ring import PolynomialRing_commutative
|
|
51
|
+
|
|
52
|
+
from sage.categories.commutative_algebras import CommutativeAlgebras
|
|
53
|
+
from sage.categories.commutative_rings import CommutativeRings
|
|
54
|
+
|
|
55
|
+
from sage.rings.quotient_ring import QuotientRing_generic
|
|
56
|
+
|
|
57
|
+
from sage.structure.category_object import normalize_names
|
|
58
|
+
from sage.structure.coerce_maps import DefaultConvertMap_unique
|
|
59
|
+
from sage.structure.factory import UniqueFactory
|
|
60
|
+
|
|
61
|
+
from sage.rings.polynomial.infinite_polynomial_ring import GenDictWithBasering
|
|
62
|
+
|
|
63
|
+
from sage.structure.richcmp import richcmp
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class PolynomialQuotientRingFactory(UniqueFactory):
|
|
67
|
+
r"""
|
|
68
|
+
Create a quotient of a polynomial ring.
|
|
69
|
+
|
|
70
|
+
INPUT:
|
|
71
|
+
|
|
72
|
+
- ``ring`` -- a univariate polynomial ring
|
|
73
|
+
|
|
74
|
+
- ``polynomial`` -- an element of ``ring`` with a unit leading coefficient
|
|
75
|
+
|
|
76
|
+
- ``names`` -- (optional) name for the variable
|
|
77
|
+
|
|
78
|
+
OUTPUT: creates the quotient ring `R/I`, where `R` is the ring and `I` is
|
|
79
|
+
the principal ideal generated by ``polynomial``.
|
|
80
|
+
|
|
81
|
+
EXAMPLES:
|
|
82
|
+
|
|
83
|
+
We create the quotient ring `\ZZ[x]/(x^3+7)`, and
|
|
84
|
+
demonstrate many basic functions with it::
|
|
85
|
+
|
|
86
|
+
sage: Z = IntegerRing()
|
|
87
|
+
sage: R = PolynomialRing(Z, 'x'); x = R.gen()
|
|
88
|
+
sage: S = R.quotient(x^3 + 7, 'a'); a = S.gen()
|
|
89
|
+
sage: S
|
|
90
|
+
Univariate Quotient Polynomial Ring in a
|
|
91
|
+
over Integer Ring with modulus x^3 + 7
|
|
92
|
+
sage: a^3
|
|
93
|
+
-7
|
|
94
|
+
sage: S.is_field()
|
|
95
|
+
False
|
|
96
|
+
sage: a in S
|
|
97
|
+
True
|
|
98
|
+
sage: x in S
|
|
99
|
+
True
|
|
100
|
+
sage: a in R
|
|
101
|
+
False
|
|
102
|
+
sage: S.polynomial_ring()
|
|
103
|
+
Univariate Polynomial Ring in x over Integer Ring
|
|
104
|
+
sage: S.modulus()
|
|
105
|
+
x^3 + 7
|
|
106
|
+
sage: S.degree()
|
|
107
|
+
3
|
|
108
|
+
|
|
109
|
+
We create the "iterated" polynomial ring quotient
|
|
110
|
+
|
|
111
|
+
.. MATH::
|
|
112
|
+
|
|
113
|
+
R = (\GF{2}[y]/(y^{2}+y+1))[x]/(x^3 - 5).
|
|
114
|
+
|
|
115
|
+
::
|
|
116
|
+
|
|
117
|
+
sage: # needs sage.libs.ntl
|
|
118
|
+
sage: A.<y> = PolynomialRing(GF(2)); A
|
|
119
|
+
Univariate Polynomial Ring in y over Finite Field of size 2 (using GF2X)
|
|
120
|
+
sage: B = A.quotient(y^2 + y + 1, 'y2'); B
|
|
121
|
+
Univariate Quotient Polynomial Ring in y2 over Finite Field of size 2
|
|
122
|
+
with modulus y^2 + y + 1
|
|
123
|
+
sage: C = PolynomialRing(B, 'x'); x = C.gen(); C
|
|
124
|
+
Univariate Polynomial Ring in x
|
|
125
|
+
over Univariate Quotient Polynomial Ring in y2
|
|
126
|
+
over Finite Field of size 2 with modulus y^2 + y + 1
|
|
127
|
+
sage: R = C.quotient(x^3 - 5); R
|
|
128
|
+
Univariate Quotient Polynomial Ring in xbar
|
|
129
|
+
over Univariate Quotient Polynomial Ring in y2
|
|
130
|
+
over Finite Field of size 2 with modulus y^2 + y + 1
|
|
131
|
+
with modulus x^3 + 1
|
|
132
|
+
|
|
133
|
+
Next we create a number field, but viewed as a quotient of a
|
|
134
|
+
polynomial ring over `\QQ`::
|
|
135
|
+
|
|
136
|
+
sage: R = PolynomialRing(RationalField(), 'x'); x = R.gen()
|
|
137
|
+
sage: S = R.quotient(x^3 + 2*x - 5, 'a'); S
|
|
138
|
+
Univariate Quotient Polynomial Ring in a over Rational Field
|
|
139
|
+
with modulus x^3 + 2*x - 5
|
|
140
|
+
sage: S.is_field()
|
|
141
|
+
True
|
|
142
|
+
sage: S.degree()
|
|
143
|
+
3
|
|
144
|
+
|
|
145
|
+
There are conversion functions for easily going back and forth
|
|
146
|
+
between quotients of polynomial rings over `\QQ` and
|
|
147
|
+
number fields::
|
|
148
|
+
|
|
149
|
+
sage: K = S.number_field(); K # needs sage.rings.number_field
|
|
150
|
+
Number Field in a with defining polynomial x^3 + 2*x - 5
|
|
151
|
+
sage: K.polynomial_quotient_ring() # needs sage.rings.number_field
|
|
152
|
+
Univariate Quotient Polynomial Ring in a
|
|
153
|
+
over Rational Field with modulus x^3 + 2*x - 5
|
|
154
|
+
|
|
155
|
+
The leading coefficient must be a unit (but need not be 1).
|
|
156
|
+
|
|
157
|
+
::
|
|
158
|
+
|
|
159
|
+
sage: R = PolynomialRing(Integers(9), 'x'); x = R.gen()
|
|
160
|
+
sage: S = R.quotient(2*x^4 + 2*x^3 + x + 2, 'a')
|
|
161
|
+
sage: S = R.quotient(3*x^4 + 2*x^3 + x + 2, 'a')
|
|
162
|
+
Traceback (most recent call last):
|
|
163
|
+
...
|
|
164
|
+
TypeError: polynomial must have unit leading coefficient
|
|
165
|
+
|
|
166
|
+
Another example::
|
|
167
|
+
|
|
168
|
+
sage: R.<x> = PolynomialRing(IntegerRing())
|
|
169
|
+
sage: f = x^2 + 1
|
|
170
|
+
sage: R.quotient(f)
|
|
171
|
+
Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1
|
|
172
|
+
|
|
173
|
+
This shows that the issue at :issue:`5482` is solved::
|
|
174
|
+
|
|
175
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
176
|
+
sage: f = x^2 - 1
|
|
177
|
+
sage: R.quotient_by_principal_ideal(f)
|
|
178
|
+
Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 - 1
|
|
179
|
+
"""
|
|
180
|
+
def create_key(self, ring, polynomial, names=None):
|
|
181
|
+
r"""
|
|
182
|
+
Return a unique description of the quotient ring specified by the
|
|
183
|
+
arguments.
|
|
184
|
+
|
|
185
|
+
EXAMPLES::
|
|
186
|
+
|
|
187
|
+
sage: R.<x> = QQ[]
|
|
188
|
+
sage: PolynomialQuotientRing.create_key(R, x + 1)
|
|
189
|
+
(Univariate Polynomial Ring in x over Rational Field, x + 1, ('xbar',))
|
|
190
|
+
|
|
191
|
+
TESTS:
|
|
192
|
+
|
|
193
|
+
We do not normalize the modulus even though we could divide out the
|
|
194
|
+
leading coefficient here::
|
|
195
|
+
|
|
196
|
+
sage: PolynomialQuotientRing.create_key(R, 2*x + 2)
|
|
197
|
+
(Univariate Polynomial Ring in x over Rational Field, 2*x + 2, ('xbar',))
|
|
198
|
+
|
|
199
|
+
Consequently, you get two distinct objects::
|
|
200
|
+
|
|
201
|
+
sage: S = PolynomialQuotientRing(R, x + 1); S
|
|
202
|
+
Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x + 1
|
|
203
|
+
sage: T = PolynomialQuotientRing(R, 2*x + 2); T
|
|
204
|
+
Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus 2*x + 2
|
|
205
|
+
sage: S is T
|
|
206
|
+
False
|
|
207
|
+
sage: S == T
|
|
208
|
+
False
|
|
209
|
+
|
|
210
|
+
In most applications this will not be a concern since the calling code
|
|
211
|
+
takes care of normalizing the generators::
|
|
212
|
+
|
|
213
|
+
sage: R.quo(x + 1) is R.quo(2*x + 2)
|
|
214
|
+
True
|
|
215
|
+
"""
|
|
216
|
+
if not isinstance(ring, PolynomialRing_commutative):
|
|
217
|
+
raise TypeError("ring must be a polynomial ring")
|
|
218
|
+
if not isinstance(polynomial, polynomial_element.Polynomial):
|
|
219
|
+
raise TypeError("must be a polynomial")
|
|
220
|
+
if polynomial.parent() is not ring:
|
|
221
|
+
raise TypeError("polynomial must be in ring")
|
|
222
|
+
|
|
223
|
+
c = polynomial.leading_coefficient()
|
|
224
|
+
if not c.is_unit():
|
|
225
|
+
raise TypeError("polynomial must have unit leading coefficient")
|
|
226
|
+
|
|
227
|
+
if names is None:
|
|
228
|
+
names = tuple([x + 'bar' for x in ring.variable_names()])
|
|
229
|
+
else:
|
|
230
|
+
names = normalize_names(ring.ngens(), names)
|
|
231
|
+
|
|
232
|
+
return ring, polynomial, names
|
|
233
|
+
|
|
234
|
+
def create_object(self, version, key):
|
|
235
|
+
r"""
|
|
236
|
+
Return the quotient ring specified by ``key``.
|
|
237
|
+
|
|
238
|
+
EXAMPLES::
|
|
239
|
+
|
|
240
|
+
sage: R.<x> = QQ[]
|
|
241
|
+
sage: PolynomialQuotientRing.create_object((8, 0, 0),
|
|
242
|
+
....: (R, x^2 - 1, ('xbar')))
|
|
243
|
+
Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 - 1
|
|
244
|
+
"""
|
|
245
|
+
ring, polynomial, names = key
|
|
246
|
+
|
|
247
|
+
R = ring.base_ring()
|
|
248
|
+
from sage.categories.integral_domains import IntegralDomains
|
|
249
|
+
from sage.categories.fields import Fields
|
|
250
|
+
if R in IntegralDomains():
|
|
251
|
+
try:
|
|
252
|
+
is_irreducible = polynomial.is_irreducible()
|
|
253
|
+
except NotImplementedError: # is_irreducible sometimes not implemented
|
|
254
|
+
pass
|
|
255
|
+
else:
|
|
256
|
+
if is_irreducible:
|
|
257
|
+
if R in Fields():
|
|
258
|
+
return PolynomialQuotientRing_field(ring, polynomial, names)
|
|
259
|
+
else:
|
|
260
|
+
return PolynomialQuotientRing_domain(ring, polynomial, names)
|
|
261
|
+
return PolynomialQuotientRing_generic(ring, polynomial, names)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
PolynomialQuotientRing = PolynomialQuotientRingFactory("PolynomialQuotientRing")
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def is_PolynomialQuotientRing(x):
|
|
268
|
+
from sage.misc.superseded import deprecation
|
|
269
|
+
deprecation(38266,
|
|
270
|
+
"The function is_PolynomialQuotientRing is deprecated; "
|
|
271
|
+
"use 'isinstance(..., PolynomialQuotientRing_generic)' instead.")
|
|
272
|
+
return isinstance(x, PolynomialQuotientRing_generic)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class PolynomialQuotientRing_generic(QuotientRing_generic):
|
|
276
|
+
"""
|
|
277
|
+
Quotient of a univariate polynomial ring by an ideal.
|
|
278
|
+
|
|
279
|
+
EXAMPLES::
|
|
280
|
+
|
|
281
|
+
sage: R.<x> = PolynomialRing(Integers(8)); R
|
|
282
|
+
Univariate Polynomial Ring in x over Ring of integers modulo 8
|
|
283
|
+
sage: S.<xbar> = R.quotient(x^2 + 1); S
|
|
284
|
+
Univariate Quotient Polynomial Ring in xbar over Ring of integers modulo 8
|
|
285
|
+
with modulus x^2 + 1
|
|
286
|
+
|
|
287
|
+
We demonstrate object persistence.
|
|
288
|
+
|
|
289
|
+
::
|
|
290
|
+
|
|
291
|
+
sage: loads(S.dumps()) == S
|
|
292
|
+
True
|
|
293
|
+
sage: loads(xbar.dumps()) == xbar
|
|
294
|
+
True
|
|
295
|
+
|
|
296
|
+
We create some sample homomorphisms;
|
|
297
|
+
|
|
298
|
+
::
|
|
299
|
+
|
|
300
|
+
sage: R.<x> = PolynomialRing(ZZ)
|
|
301
|
+
sage: S = R.quo(x^2 - 4)
|
|
302
|
+
sage: f = S.hom([2])
|
|
303
|
+
sage: f
|
|
304
|
+
Ring morphism:
|
|
305
|
+
From: Univariate Quotient Polynomial Ring in xbar over Integer Ring
|
|
306
|
+
with modulus x^2 - 4
|
|
307
|
+
To: Integer Ring
|
|
308
|
+
Defn: xbar |--> 2
|
|
309
|
+
sage: f(x)
|
|
310
|
+
2
|
|
311
|
+
sage: f(x^2 - 4)
|
|
312
|
+
0
|
|
313
|
+
sage: f(x^2)
|
|
314
|
+
4
|
|
315
|
+
|
|
316
|
+
TESTS:
|
|
317
|
+
|
|
318
|
+
By :issue:`11900`, polynomial quotient rings use Sage's
|
|
319
|
+
category framework. They do so in an unusual way: During their
|
|
320
|
+
initialisation, they are declared to be objects in the category of
|
|
321
|
+
quotients of commutative algebras over a base ring. However, if it
|
|
322
|
+
is tested whether a quotient ring is actually a field, the
|
|
323
|
+
category might be refined, which also includes a change of the
|
|
324
|
+
class of the quotient ring and its newly created elements.
|
|
325
|
+
|
|
326
|
+
Thus, in order to document that this works fine, we go into some detail::
|
|
327
|
+
|
|
328
|
+
sage: P.<x> = QQ[]
|
|
329
|
+
sage: Q = P.quotient(x^2 + 2)
|
|
330
|
+
sage: Q.category()
|
|
331
|
+
Category of commutative no zero divisors quotients of algebras over
|
|
332
|
+
(number fields and quotient fields and metric spaces)
|
|
333
|
+
|
|
334
|
+
We verify that the elements belong to the correct element class.
|
|
335
|
+
Also, we list the attributes that are provided by the element
|
|
336
|
+
class of the category, and store the current class of the quotient
|
|
337
|
+
ring::
|
|
338
|
+
|
|
339
|
+
sage: isinstance(Q.an_element(), Q.element_class)
|
|
340
|
+
True
|
|
341
|
+
sage: [s for s in dir(Q.category().element_class) if not s.startswith('_')]
|
|
342
|
+
['cartesian_product', 'inverse', 'inverse_of_unit', 'is_idempotent',
|
|
343
|
+
'is_one', 'is_unit', 'lift', 'powers']
|
|
344
|
+
sage: first_class = Q.__class__
|
|
345
|
+
|
|
346
|
+
We try to find out whether `Q` is a field. Indeed it is, and thus its category,
|
|
347
|
+
including its class and element class, is changed accordingly::
|
|
348
|
+
|
|
349
|
+
sage: Q in Fields()
|
|
350
|
+
True
|
|
351
|
+
sage: Q.category()
|
|
352
|
+
Category of commutative division no zero divisors quotients of algebras
|
|
353
|
+
over (number fields and quotient fields and metric spaces)
|
|
354
|
+
sage: first_class == Q.__class__
|
|
355
|
+
False
|
|
356
|
+
sage: [s for s in dir(Q.category().element_class) if not s.startswith('_')]
|
|
357
|
+
['cartesian_product',
|
|
358
|
+
'euclidean_degree',
|
|
359
|
+
'factor',
|
|
360
|
+
'gcd',
|
|
361
|
+
'inverse',
|
|
362
|
+
'inverse_of_unit',
|
|
363
|
+
'is_idempotent',
|
|
364
|
+
'is_one',
|
|
365
|
+
'is_unit',
|
|
366
|
+
'lcm',
|
|
367
|
+
'lift',
|
|
368
|
+
'powers',
|
|
369
|
+
'quo_rem',
|
|
370
|
+
'radical',
|
|
371
|
+
'squarefree_part',
|
|
372
|
+
'xgcd']
|
|
373
|
+
|
|
374
|
+
As one can see, the elements are now inheriting additional
|
|
375
|
+
methods: lcm and gcd. Even though ``Q.an_element()`` belongs to
|
|
376
|
+
the old and not to the new element class, it still inherits the
|
|
377
|
+
new methods from the category of fields, thanks to
|
|
378
|
+
:meth:`Element.__getattr__`::
|
|
379
|
+
|
|
380
|
+
sage: e = Q.an_element()
|
|
381
|
+
sage: isinstance(e, Q.element_class)
|
|
382
|
+
False
|
|
383
|
+
sage: e.gcd(e + 1)
|
|
384
|
+
1
|
|
385
|
+
|
|
386
|
+
The test suite passes. However, we have to skip the test for its elements,
|
|
387
|
+
since ``an_element`` has been cached in the call above and its class does not
|
|
388
|
+
match the new category's element class anymore::
|
|
389
|
+
|
|
390
|
+
sage: TestSuite(Q).run(skip=['_test_elements']) # needs sage.rings.number_field
|
|
391
|
+
|
|
392
|
+
Newly created elements are fine, though, and their test suite passes::
|
|
393
|
+
|
|
394
|
+
sage: TestSuite(Q(x)).run()
|
|
395
|
+
sage: isinstance(Q(x), Q.element_class)
|
|
396
|
+
True
|
|
397
|
+
"""
|
|
398
|
+
Element = PolynomialQuotientRingElement
|
|
399
|
+
|
|
400
|
+
def __init__(self, ring, polynomial, name=None, category=None):
|
|
401
|
+
"""
|
|
402
|
+
TESTS::
|
|
403
|
+
|
|
404
|
+
sage: R.<x> = PolynomialRing(ZZ)
|
|
405
|
+
sage: S = R.quo(x^2 - 4)
|
|
406
|
+
sage: from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic
|
|
407
|
+
sage: S == PolynomialQuotientRing_generic(R, x^2 - 4, 'xbar')
|
|
408
|
+
True
|
|
409
|
+
|
|
410
|
+
Check that :issue:`26161` has been resolved::
|
|
411
|
+
|
|
412
|
+
sage: R.<x> = GF(2)[]
|
|
413
|
+
sage: S = R.quo(x) # needs sage.rings.finite_rings
|
|
414
|
+
sage: S in FiniteFields() # needs sage.rings.finite_rings
|
|
415
|
+
True
|
|
416
|
+
sage: type(S).mro() # needs sage.rings.finite_rings
|
|
417
|
+
[<class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_field_with_category'>,
|
|
418
|
+
...
|
|
419
|
+
<class 'sage.categories.finite_fields.FiniteFields.parent_class'>,
|
|
420
|
+
...
|
|
421
|
+
"""
|
|
422
|
+
if not isinstance(ring, PolynomialRing_commutative):
|
|
423
|
+
raise TypeError("R must be a univariate polynomial ring.")
|
|
424
|
+
|
|
425
|
+
if not isinstance(polynomial, polynomial_element.Polynomial):
|
|
426
|
+
raise TypeError("f must be a Polynomial")
|
|
427
|
+
|
|
428
|
+
if polynomial.parent() != ring:
|
|
429
|
+
raise TypeError("f must have parent R")
|
|
430
|
+
|
|
431
|
+
self.__ring = ring
|
|
432
|
+
self.__polynomial = polynomial
|
|
433
|
+
category = CommutativeAlgebras(ring.base_ring().category()).Quotients().or_subcategory(category)
|
|
434
|
+
if self.is_finite():
|
|
435
|
+
# We refine the category for finite quotients.
|
|
436
|
+
# Note that is_finite() is cheap so it does not seem to do a lazy
|
|
437
|
+
# _refine_category_() in is_finite() as we do for is_field()
|
|
438
|
+
category = category.Finite()
|
|
439
|
+
|
|
440
|
+
QuotientRing_generic.__init__(self, ring, ring.ideal(polynomial), names=name, category=category)
|
|
441
|
+
self._base = ring # backwards compatibility -- different from QuotientRing_generic
|
|
442
|
+
|
|
443
|
+
_ideal_class_ = QuotientRing_generic._ideal_class_
|
|
444
|
+
|
|
445
|
+
def _element_constructor_(self, x):
|
|
446
|
+
"""
|
|
447
|
+
Convert x into this quotient ring. Anything that can be converted into
|
|
448
|
+
the polynomial ring can be converted into the quotient.
|
|
449
|
+
|
|
450
|
+
INPUT:
|
|
451
|
+
|
|
452
|
+
- ``x`` -- object to be converted
|
|
453
|
+
|
|
454
|
+
OUTPUT: an element obtained by converting x into this ring
|
|
455
|
+
|
|
456
|
+
EXAMPLES::
|
|
457
|
+
|
|
458
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
459
|
+
sage: S.<alpha> = R.quotient(x^3 - 3*x + 1)
|
|
460
|
+
sage: S(x)
|
|
461
|
+
alpha
|
|
462
|
+
sage: S(x^3)
|
|
463
|
+
3*alpha - 1
|
|
464
|
+
sage: S([1,2])
|
|
465
|
+
2*alpha + 1
|
|
466
|
+
sage: S([1,2,3,4,5])
|
|
467
|
+
18*alpha^2 + 9*alpha - 3
|
|
468
|
+
sage: S(S.gen()+1)
|
|
469
|
+
alpha + 1
|
|
470
|
+
sage: S(S.gen()^10+1)
|
|
471
|
+
90*alpha^2 - 109*alpha + 28
|
|
472
|
+
|
|
473
|
+
TESTS:
|
|
474
|
+
|
|
475
|
+
Conversion should work even if there is no coercion.
|
|
476
|
+
This was fixed in :issue:`8800`::
|
|
477
|
+
|
|
478
|
+
sage: P.<x> = QQ[]
|
|
479
|
+
sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)])
|
|
480
|
+
sage: Q = P.quo([(x^2+1)^2])
|
|
481
|
+
sage: Q1.has_coerce_map_from(Q)
|
|
482
|
+
False
|
|
483
|
+
sage: Q1(Q.gen())
|
|
484
|
+
xbar
|
|
485
|
+
|
|
486
|
+
Here we test against several issues discussed in :issue:`8992`::
|
|
487
|
+
|
|
488
|
+
sage: P.<x> = QQ[]
|
|
489
|
+
sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)])
|
|
490
|
+
sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)])
|
|
491
|
+
sage: p = Q1.gen() + Q2.gen()
|
|
492
|
+
sage: p
|
|
493
|
+
2*xbar
|
|
494
|
+
sage: p.parent()
|
|
495
|
+
Univariate Quotient Polynomial Ring in xbar over Rational Field
|
|
496
|
+
with modulus x^4 + 2*x^2 + 1
|
|
497
|
+
sage: p.parent()('xbar')
|
|
498
|
+
xbar
|
|
499
|
+
|
|
500
|
+
Note that the result of string conversion has the correct parent, even
|
|
501
|
+
when the given string suggests an element of the cover ring or the base
|
|
502
|
+
ring::
|
|
503
|
+
|
|
504
|
+
sage: a = Q1('x'); a
|
|
505
|
+
xbar
|
|
506
|
+
sage: a.parent() is Q1
|
|
507
|
+
True
|
|
508
|
+
sage: b = Q1('1'); b
|
|
509
|
+
1
|
|
510
|
+
sage: b.parent() is Q1
|
|
511
|
+
True
|
|
512
|
+
|
|
513
|
+
Conversion may lift an element of one quotient ring to the base ring of
|
|
514
|
+
another quotient ring::
|
|
515
|
+
|
|
516
|
+
sage: R.<y> = P[]
|
|
517
|
+
sage: Q3 = R.quo([(y^2+1)])
|
|
518
|
+
sage: Q3(Q1.gen())
|
|
519
|
+
x
|
|
520
|
+
sage: Q3.has_coerce_map_from(Q1)
|
|
521
|
+
False
|
|
522
|
+
|
|
523
|
+
String conversion takes into account both the generators of the quotient
|
|
524
|
+
ring and its base ring::
|
|
525
|
+
|
|
526
|
+
sage: Q3('x*ybar^2')
|
|
527
|
+
-x
|
|
528
|
+
"""
|
|
529
|
+
if not isinstance(x, str):
|
|
530
|
+
try:
|
|
531
|
+
return self.element_class(self, self.__ring(x) , check=True)
|
|
532
|
+
except TypeError:
|
|
533
|
+
xlift = getattr(x,'lift',None)
|
|
534
|
+
if xlift is not None: # duck typing for quotient ring elements
|
|
535
|
+
return self.element_class(self, self.__ring(x.lift()), check=False)
|
|
536
|
+
# The problem with the string representation is that it could in principle
|
|
537
|
+
# mix elements of self with elements of self's cover ring. We therefore
|
|
538
|
+
# resort to sage_eval.
|
|
539
|
+
# Interpretation in self has priority over interpretation in self.__ring
|
|
540
|
+
try:
|
|
541
|
+
from sage.misc.sage_eval import sage_eval
|
|
542
|
+
out = sage_eval(x, GenDictWithBasering(self,self.gens_dict()))
|
|
543
|
+
if out.parent() is not self:
|
|
544
|
+
return self(out)
|
|
545
|
+
return out
|
|
546
|
+
except (TypeError, NameError):
|
|
547
|
+
pass
|
|
548
|
+
try:
|
|
549
|
+
return self.element_class(self, self.__ring(x), check=False)
|
|
550
|
+
except TypeError:
|
|
551
|
+
raise TypeError("unable to convert %r to an element of %s" % (x, self))
|
|
552
|
+
|
|
553
|
+
def _coerce_map_from_(self, R):
|
|
554
|
+
r"""
|
|
555
|
+
Return a coerce map from ``R``.
|
|
556
|
+
|
|
557
|
+
Anything coercing into the underlying polynomial ring coerces into this
|
|
558
|
+
quotient. Furthermore, for quotients `R=A[x]/(f)` and `S=B[x]/(g)` with
|
|
559
|
+
a coercion `R\to S` there is a coercion iff `f` divides `g`.
|
|
560
|
+
|
|
561
|
+
AUTHOR:
|
|
562
|
+
|
|
563
|
+
- Simon King (2010-12): :issue:`8800`
|
|
564
|
+
|
|
565
|
+
TESTS::
|
|
566
|
+
|
|
567
|
+
sage: P5.<x> = GF(5)[]
|
|
568
|
+
sage: Q = P5.quo([(x^2+1)^2])
|
|
569
|
+
sage: P.<x> = ZZ[]
|
|
570
|
+
sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)])
|
|
571
|
+
sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)])
|
|
572
|
+
sage: Q.has_coerce_map_from(Q1) #indirect doctest
|
|
573
|
+
True
|
|
574
|
+
sage: Q1.has_coerce_map_from(Q)
|
|
575
|
+
False
|
|
576
|
+
sage: Q1.has_coerce_map_from(Q2)
|
|
577
|
+
False
|
|
578
|
+
|
|
579
|
+
The following tests against a bug fixed in :issue:`8992`::
|
|
580
|
+
|
|
581
|
+
sage: P.<x> = QQ[]
|
|
582
|
+
sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)])
|
|
583
|
+
sage: R.<y> = P[]
|
|
584
|
+
sage: Q2 = R.quo([(y^2 + 1)])
|
|
585
|
+
sage: Q2.has_coerce_map_from(Q1)
|
|
586
|
+
False
|
|
587
|
+
"""
|
|
588
|
+
if self.__ring.has_coerce_map_from(R):
|
|
589
|
+
return True
|
|
590
|
+
if isinstance(R, PolynomialQuotientRing_generic):
|
|
591
|
+
try:
|
|
592
|
+
if not self.__polynomial.divides(R.modulus()):
|
|
593
|
+
return False
|
|
594
|
+
except (ZeroDivisionError,ArithmeticError):
|
|
595
|
+
return False
|
|
596
|
+
from sage.categories.homset import Hom
|
|
597
|
+
parent = Hom(R, self, category=self.category()._meet_(R.category()))
|
|
598
|
+
return parent.__make_element_class__(PolynomialQuotientRing_coercion)(R, self, category=parent.homset_category())
|
|
599
|
+
|
|
600
|
+
def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None):
|
|
601
|
+
"""
|
|
602
|
+
EXAMPLES::
|
|
603
|
+
|
|
604
|
+
sage: # needs sage.rings.number_field
|
|
605
|
+
sage: T.<t> = ZZ[]
|
|
606
|
+
sage: K.<i> = NumberField(t^2 + 1)
|
|
607
|
+
sage: R.<x> = K[]
|
|
608
|
+
sage: S.<a> = R.quotient(x^2 - i)
|
|
609
|
+
sage: Q8.<z> = CyclotomicField(8)
|
|
610
|
+
sage: S._is_valid_homomorphism_(Q8, [z]) # no coercion from K to Q8
|
|
611
|
+
False
|
|
612
|
+
sage: S._is_valid_homomorphism_(Q8, [z], K.hom([z^2]))
|
|
613
|
+
True
|
|
614
|
+
sage: S._is_valid_homomorphism_(Q8, [1/z], K.hom([z^-2]))
|
|
615
|
+
True
|
|
616
|
+
"""
|
|
617
|
+
if base_map is None and not codomain.has_coerce_map_from(self.base_ring()):
|
|
618
|
+
# If no base_map given, we need that elements of the base ring
|
|
619
|
+
# of the polynomial ring map canonically into codomain.
|
|
620
|
+
return False
|
|
621
|
+
|
|
622
|
+
# We also need that the polynomial modulus maps to 0, after twisting by the base_map
|
|
623
|
+
f = self.modulus()
|
|
624
|
+
try:
|
|
625
|
+
if base_map is not None:
|
|
626
|
+
f = f.map_coefficients(base_map)
|
|
627
|
+
return codomain(f(im_gens[0])) == 0
|
|
628
|
+
except (TypeError, ValueError):
|
|
629
|
+
return False
|
|
630
|
+
|
|
631
|
+
def _coerce_impl(self, x):
|
|
632
|
+
"""
|
|
633
|
+
Return the coercion of x into this polynomial quotient ring.
|
|
634
|
+
|
|
635
|
+
The rings that coerce into the quotient ring canonically are:
|
|
636
|
+
|
|
637
|
+
- this ring
|
|
638
|
+
|
|
639
|
+
- any canonically isomorphic ring
|
|
640
|
+
|
|
641
|
+
- anything that coerces into the ring of which this is the
|
|
642
|
+
quotient
|
|
643
|
+
"""
|
|
644
|
+
if isinstance(x, PolynomialQuotientRingElement):
|
|
645
|
+
if x.parent() == self:
|
|
646
|
+
return self.element_class(self, self.__ring(x.lift()), check=False)
|
|
647
|
+
# any ring that coerces to the base ring of this polynomial ring.
|
|
648
|
+
return self(self.polynomial_ring().coerce(x))
|
|
649
|
+
|
|
650
|
+
############################################
|
|
651
|
+
# Methods to make the category framework happy...
|
|
652
|
+
#
|
|
653
|
+
|
|
654
|
+
retract = _coerce_impl
|
|
655
|
+
ambient = CommutativeRing.base
|
|
656
|
+
|
|
657
|
+
def lift(self, x):
|
|
658
|
+
"""
|
|
659
|
+
Return an element of the ambient ring mapping to the given argument.
|
|
660
|
+
|
|
661
|
+
EXAMPLES::
|
|
662
|
+
|
|
663
|
+
sage: P.<x> = QQ[]
|
|
664
|
+
sage: Q = P.quotient(x^2 + 2)
|
|
665
|
+
sage: Q.lift(Q.0^3)
|
|
666
|
+
-2*x
|
|
667
|
+
sage: Q(-2*x)
|
|
668
|
+
-2*xbar
|
|
669
|
+
sage: Q.0^3
|
|
670
|
+
-2*xbar
|
|
671
|
+
"""
|
|
672
|
+
return x.lift()
|
|
673
|
+
|
|
674
|
+
def __eq__(self, other):
|
|
675
|
+
"""
|
|
676
|
+
Check whether ``self`` is equal to ``other``.
|
|
677
|
+
|
|
678
|
+
EXAMPLES::
|
|
679
|
+
|
|
680
|
+
sage: Rx.<x> = PolynomialRing(QQ)
|
|
681
|
+
sage: Ry.<y> = PolynomialRing(QQ)
|
|
682
|
+
sage: Rx == Ry
|
|
683
|
+
False
|
|
684
|
+
sage: Qx = Rx.quotient(x^2 + 1)
|
|
685
|
+
sage: Qy = Ry.quotient(y^2 + 1)
|
|
686
|
+
sage: Qx == Qy
|
|
687
|
+
False
|
|
688
|
+
sage: Qx == Qx
|
|
689
|
+
True
|
|
690
|
+
sage: Qz = Rx.quotient(x^2 + 1)
|
|
691
|
+
sage: Qz == Qx
|
|
692
|
+
True
|
|
693
|
+
"""
|
|
694
|
+
if not isinstance(other, PolynomialQuotientRing_generic):
|
|
695
|
+
return False
|
|
696
|
+
return (self.polynomial_ring() == other.polynomial_ring() and
|
|
697
|
+
self.modulus() == other.modulus())
|
|
698
|
+
|
|
699
|
+
def __ne__(self, other):
|
|
700
|
+
"""
|
|
701
|
+
Check whether ``self`` is not equal to ``other``.
|
|
702
|
+
|
|
703
|
+
EXAMPLES::
|
|
704
|
+
|
|
705
|
+
sage: Rx.<x> = PolynomialRing(QQ)
|
|
706
|
+
sage: Ry.<y> = PolynomialRing(QQ)
|
|
707
|
+
sage: Rx != Ry
|
|
708
|
+
True
|
|
709
|
+
sage: Qx = Rx.quotient(x^2 + 1)
|
|
710
|
+
sage: Qy = Ry.quotient(y^2 + 1)
|
|
711
|
+
sage: Qx != Qy
|
|
712
|
+
True
|
|
713
|
+
sage: Qx != Qx
|
|
714
|
+
False
|
|
715
|
+
sage: Qz = Rx.quotient(x^2 + 1)
|
|
716
|
+
sage: Qz != Qx
|
|
717
|
+
False
|
|
718
|
+
"""
|
|
719
|
+
return not (self == other)
|
|
720
|
+
|
|
721
|
+
def __hash__(self):
|
|
722
|
+
"""
|
|
723
|
+
Return the hash of ``self``.
|
|
724
|
+
|
|
725
|
+
EXAMPLES::
|
|
726
|
+
|
|
727
|
+
sage: Rx.<x> = PolynomialRing(QQ)
|
|
728
|
+
sage: Ry.<y> = PolynomialRing(QQ)
|
|
729
|
+
sage: hash(Rx) == hash(Ry)
|
|
730
|
+
False
|
|
731
|
+
sage: Qx = Rx.quotient(x^2 + 1)
|
|
732
|
+
sage: Qy = Ry.quotient(y^2 + 1)
|
|
733
|
+
sage: hash(Qx) == hash(Qy)
|
|
734
|
+
False
|
|
735
|
+
sage: hash(Qx) == hash(Qx)
|
|
736
|
+
True
|
|
737
|
+
sage: Qz = Rx.quotient(x^2 + 1)
|
|
738
|
+
sage: hash(Qz) == hash(Qx)
|
|
739
|
+
True
|
|
740
|
+
"""
|
|
741
|
+
return hash((self.polynomial_ring(), self.modulus()))
|
|
742
|
+
|
|
743
|
+
def _singular_init_(self, S=None):
|
|
744
|
+
"""
|
|
745
|
+
Represent ``self`` in the Singular interface.
|
|
746
|
+
|
|
747
|
+
TESTS::
|
|
748
|
+
|
|
749
|
+
sage: P.<x> = QQ[]
|
|
750
|
+
sage: Q = P.quo([(x^2 + 1)])
|
|
751
|
+
sage: singular(Q) # indirect doctest # needs sage.libs.singular
|
|
752
|
+
polynomial ring, over a field, global ordering
|
|
753
|
+
// coefficients: QQ...
|
|
754
|
+
// number of vars : 1
|
|
755
|
+
// block 1 : ordering lp
|
|
756
|
+
// : names xbar
|
|
757
|
+
// block 2 : ordering C
|
|
758
|
+
// quotient ring from ideal
|
|
759
|
+
_[1]=xbar^2+1
|
|
760
|
+
sage: singular(Q.gen()) # needs sage.libs.singular
|
|
761
|
+
xbar
|
|
762
|
+
"""
|
|
763
|
+
if S is None:
|
|
764
|
+
from sage.interfaces.singular import singular as S
|
|
765
|
+
Rpoly = S(self.polynomial_ring())
|
|
766
|
+
Rpoly.set_ring()
|
|
767
|
+
modulus = S(self.modulus()) # should live in Rpoly
|
|
768
|
+
Rtmp = S(self.polynomial_ring().change_var(self.variable_name()))
|
|
769
|
+
Rtmp.set_ring()
|
|
770
|
+
self.__singular = S("ideal(fetch(%s,%s))" % (Rpoly.name(),modulus.name()),"qring")
|
|
771
|
+
return self.__singular
|
|
772
|
+
|
|
773
|
+
def _repr_(self):
|
|
774
|
+
return "Univariate Quotient Polynomial Ring in %s over %s with modulus %s" % (
|
|
775
|
+
self.variable_name(), self.base_ring(), self.modulus())
|
|
776
|
+
|
|
777
|
+
def construction(self):
|
|
778
|
+
"""
|
|
779
|
+
Functorial construction of ``self``.
|
|
780
|
+
|
|
781
|
+
EXAMPLES::
|
|
782
|
+
|
|
783
|
+
sage: P.<t> = ZZ[]
|
|
784
|
+
sage: Q = P.quo(5 + t^2)
|
|
785
|
+
sage: F, R = Q.construction()
|
|
786
|
+
sage: F(R) == Q
|
|
787
|
+
True
|
|
788
|
+
sage: P.<t> = GF(3)[]
|
|
789
|
+
sage: Q = P.quo([2 + t^2])
|
|
790
|
+
sage: F, R = Q.construction()
|
|
791
|
+
sage: F(R) == Q
|
|
792
|
+
True
|
|
793
|
+
|
|
794
|
+
AUTHOR:
|
|
795
|
+
|
|
796
|
+
-- Simon King (2010-05)
|
|
797
|
+
"""
|
|
798
|
+
from sage.categories.pushout import QuotientFunctor
|
|
799
|
+
Cover = self.__ring
|
|
800
|
+
kwds = {}
|
|
801
|
+
if Cover in CommutativeRings():
|
|
802
|
+
kwds['domain'] = kwds['codomain'] = CommutativeRings()
|
|
803
|
+
return QuotientFunctor([self.modulus()]*Cover, self.variable_names(), **kwds), Cover
|
|
804
|
+
|
|
805
|
+
@cached_method
|
|
806
|
+
def base_ring(self):
|
|
807
|
+
r"""
|
|
808
|
+
Return the base ring of the polynomial ring, of which this ring is
|
|
809
|
+
a quotient.
|
|
810
|
+
|
|
811
|
+
EXAMPLES:
|
|
812
|
+
|
|
813
|
+
The base ring of
|
|
814
|
+
`\ZZ[z]/(z^3 + z^2 + z + 1)` is
|
|
815
|
+
`\ZZ`.
|
|
816
|
+
|
|
817
|
+
::
|
|
818
|
+
|
|
819
|
+
sage: R.<z> = PolynomialRing(ZZ)
|
|
820
|
+
sage: S.<beta> = R.quo(z^3 + z^2 + z + 1)
|
|
821
|
+
sage: S.base_ring()
|
|
822
|
+
Integer Ring
|
|
823
|
+
|
|
824
|
+
Next we make a polynomial quotient ring over `S` and ask
|
|
825
|
+
for its base ring.
|
|
826
|
+
|
|
827
|
+
::
|
|
828
|
+
|
|
829
|
+
sage: T.<t> = PolynomialRing(S)
|
|
830
|
+
sage: W = T.quotient(t^99 + 99)
|
|
831
|
+
sage: W.base_ring()
|
|
832
|
+
Univariate Quotient Polynomial Ring in beta
|
|
833
|
+
over Integer Ring with modulus z^3 + z^2 + z + 1
|
|
834
|
+
"""
|
|
835
|
+
return self.__ring.base_ring()
|
|
836
|
+
|
|
837
|
+
def cardinality(self):
|
|
838
|
+
"""
|
|
839
|
+
Return the number of elements of this quotient ring.
|
|
840
|
+
|
|
841
|
+
``order`` is an alias of ``cardinality``.
|
|
842
|
+
|
|
843
|
+
EXAMPLES::
|
|
844
|
+
|
|
845
|
+
sage: R.<x> = ZZ[]
|
|
846
|
+
sage: R.quo(1).cardinality()
|
|
847
|
+
1
|
|
848
|
+
sage: R.quo(x^3 - 2).cardinality()
|
|
849
|
+
+Infinity
|
|
850
|
+
|
|
851
|
+
sage: R.quo(1).order()
|
|
852
|
+
1
|
|
853
|
+
sage: R.quo(x^3 - 2).order()
|
|
854
|
+
+Infinity
|
|
855
|
+
|
|
856
|
+
::
|
|
857
|
+
|
|
858
|
+
sage: # needs sage.rings.finite_rings
|
|
859
|
+
sage: R.<x> = GF(9, 'a')[]
|
|
860
|
+
sage: R.quo(2*x^3 + x + 1).cardinality()
|
|
861
|
+
729
|
|
862
|
+
sage: GF(9, 'a').extension(2*x^3 + x + 1).cardinality()
|
|
863
|
+
729
|
|
864
|
+
sage: R.quo(2).cardinality()
|
|
865
|
+
1
|
|
866
|
+
|
|
867
|
+
TESTS::
|
|
868
|
+
|
|
869
|
+
sage: parent(QQ['x'].quo(1).cardinality())
|
|
870
|
+
Integer Ring
|
|
871
|
+
sage: parent(QQ['x'].quo(1).order())
|
|
872
|
+
Integer Ring
|
|
873
|
+
"""
|
|
874
|
+
if not self.is_finite():
|
|
875
|
+
from sage.rings.infinity import Infinity
|
|
876
|
+
return Infinity
|
|
877
|
+
f = self.modulus()
|
|
878
|
+
# Two cases where the quotient is finite (see is_finite())
|
|
879
|
+
# 1) R[x]/(1)
|
|
880
|
+
if f.degree() == 0:
|
|
881
|
+
from sage.rings.integer_ring import ZZ
|
|
882
|
+
return ZZ.one()
|
|
883
|
+
# 2) F[x]/(f) where F is finite
|
|
884
|
+
else:
|
|
885
|
+
return self.base_ring().cardinality() ** f.degree()
|
|
886
|
+
|
|
887
|
+
order = cardinality
|
|
888
|
+
|
|
889
|
+
def is_finite(self):
|
|
890
|
+
"""
|
|
891
|
+
Return whether or not this quotient ring is finite.
|
|
892
|
+
|
|
893
|
+
EXAMPLES::
|
|
894
|
+
|
|
895
|
+
sage: R.<x> = ZZ[]
|
|
896
|
+
sage: R.quo(1).is_finite()
|
|
897
|
+
True
|
|
898
|
+
sage: R.quo(x^3 - 2).is_finite()
|
|
899
|
+
False
|
|
900
|
+
|
|
901
|
+
::
|
|
902
|
+
|
|
903
|
+
sage: R.<x> = GF(9, 'a')[] # needs sage.rings.finite_rings
|
|
904
|
+
sage: R.quo(2*x^3 + x + 1).is_finite() # needs sage.rings.finite_rings
|
|
905
|
+
True
|
|
906
|
+
sage: R.quo(2).is_finite() # needs sage.rings.finite_rings
|
|
907
|
+
True
|
|
908
|
+
|
|
909
|
+
::
|
|
910
|
+
|
|
911
|
+
sage: P.<v> = GF(2)[]
|
|
912
|
+
sage: P.quotient(v^2 - v).is_finite()
|
|
913
|
+
True
|
|
914
|
+
"""
|
|
915
|
+
f = self.modulus()
|
|
916
|
+
|
|
917
|
+
# note: the constructor assumes that the leading coefficient is a
|
|
918
|
+
# unit. However, this function would be very wrong if otherwise.
|
|
919
|
+
# As a safety measure, we check that again here.
|
|
920
|
+
assert f.leading_coefficient().is_unit()
|
|
921
|
+
|
|
922
|
+
return f.degree() == 0 or self.base_ring().is_finite()
|
|
923
|
+
|
|
924
|
+
def __iter__(self):
|
|
925
|
+
r"""
|
|
926
|
+
EXAMPLES::
|
|
927
|
+
|
|
928
|
+
sage: R.<x> = GF(3)[]
|
|
929
|
+
sage: Q = R.quo(x^3 - x^2 - x - 1)
|
|
930
|
+
sage: list(Q)
|
|
931
|
+
[0,
|
|
932
|
+
1,
|
|
933
|
+
2,
|
|
934
|
+
xbar,
|
|
935
|
+
xbar + 1,
|
|
936
|
+
xbar + 2,
|
|
937
|
+
2*xbar,
|
|
938
|
+
...
|
|
939
|
+
2*xbar^2 + 2*xbar + 1,
|
|
940
|
+
2*xbar^2 + 2*xbar + 2]
|
|
941
|
+
sage: len(_) == Q.cardinality() == 27
|
|
942
|
+
True
|
|
943
|
+
"""
|
|
944
|
+
if not self.is_finite():
|
|
945
|
+
raise NotImplementedError('not possible to iterate through infinite quotient')
|
|
946
|
+
|
|
947
|
+
R = self.polynomial_ring()
|
|
948
|
+
yield self.zero()
|
|
949
|
+
for i in range(self.modulus().degree()):
|
|
950
|
+
for p in R.polynomials(of_degree=i):
|
|
951
|
+
yield self(p)
|
|
952
|
+
|
|
953
|
+
def characteristic(self):
|
|
954
|
+
"""
|
|
955
|
+
Return the characteristic of this quotient ring.
|
|
956
|
+
|
|
957
|
+
This is always the same as the characteristic of the base ring.
|
|
958
|
+
|
|
959
|
+
EXAMPLES::
|
|
960
|
+
|
|
961
|
+
sage: R.<z> = PolynomialRing(ZZ)
|
|
962
|
+
sage: S.<a> = R.quo(z - 19)
|
|
963
|
+
sage: S.characteristic()
|
|
964
|
+
0
|
|
965
|
+
sage: R.<x> = PolynomialRing(GF(9, 'a')) # needs sage.rings.finite_rings
|
|
966
|
+
sage: S = R.quotient(x^3 + 1) # needs sage.rings.finite_rings
|
|
967
|
+
sage: S.characteristic() # needs sage.rings.finite_rings
|
|
968
|
+
3
|
|
969
|
+
"""
|
|
970
|
+
return self.base_ring().characteristic()
|
|
971
|
+
|
|
972
|
+
def degree(self):
|
|
973
|
+
"""
|
|
974
|
+
Return the degree of this quotient ring. The degree is the degree
|
|
975
|
+
of the polynomial that we quotiented out by.
|
|
976
|
+
|
|
977
|
+
EXAMPLES::
|
|
978
|
+
|
|
979
|
+
sage: R.<x> = PolynomialRing(GF(3))
|
|
980
|
+
sage: S = R.quotient(x^2005 + 1)
|
|
981
|
+
sage: S.degree()
|
|
982
|
+
2005
|
|
983
|
+
"""
|
|
984
|
+
return self.modulus().degree()
|
|
985
|
+
|
|
986
|
+
def discriminant(self, v=None):
|
|
987
|
+
"""
|
|
988
|
+
Return the discriminant of this ring over the base ring. This is by
|
|
989
|
+
definition the discriminant of the polynomial that we quotiented
|
|
990
|
+
out by.
|
|
991
|
+
|
|
992
|
+
EXAMPLES::
|
|
993
|
+
|
|
994
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
995
|
+
sage: S = R.quotient(x^3 + x^2 + x + 1)
|
|
996
|
+
sage: S.discriminant()
|
|
997
|
+
-16
|
|
998
|
+
sage: S = R.quotient((x + 1) * (x + 1))
|
|
999
|
+
sage: S.discriminant()
|
|
1000
|
+
0
|
|
1001
|
+
|
|
1002
|
+
The discriminant of the quotient polynomial ring need not equal the
|
|
1003
|
+
discriminant of the corresponding number field, since the
|
|
1004
|
+
discriminant of a number field is by definition the discriminant of
|
|
1005
|
+
the ring of integers of the number field::
|
|
1006
|
+
|
|
1007
|
+
sage: S = R.quotient(x^2 - 8)
|
|
1008
|
+
sage: S.number_field().discriminant() # needs sage.rings.number_field
|
|
1009
|
+
8
|
|
1010
|
+
sage: S.discriminant()
|
|
1011
|
+
32
|
|
1012
|
+
"""
|
|
1013
|
+
return self.modulus().discriminant()
|
|
1014
|
+
|
|
1015
|
+
def gen(self, n=0):
|
|
1016
|
+
"""
|
|
1017
|
+
Return the generator of this quotient ring. This is the equivalence
|
|
1018
|
+
class of the image of the generator of the polynomial ring.
|
|
1019
|
+
|
|
1020
|
+
EXAMPLES::
|
|
1021
|
+
|
|
1022
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
1023
|
+
sage: S = R.quotient(x^2 - 8, 'gamma')
|
|
1024
|
+
sage: S.gen()
|
|
1025
|
+
gamma
|
|
1026
|
+
"""
|
|
1027
|
+
if n != 0:
|
|
1028
|
+
raise IndexError("Only one generator.")
|
|
1029
|
+
try:
|
|
1030
|
+
return self.__gen
|
|
1031
|
+
except AttributeError:
|
|
1032
|
+
self.__gen = self(self.polynomial_ring().gen())
|
|
1033
|
+
return self.__gen
|
|
1034
|
+
|
|
1035
|
+
def is_field(self, proof=True):
|
|
1036
|
+
"""
|
|
1037
|
+
Return whether or not this quotient ring is a field.
|
|
1038
|
+
|
|
1039
|
+
EXAMPLES::
|
|
1040
|
+
|
|
1041
|
+
sage: R.<z> = PolynomialRing(ZZ)
|
|
1042
|
+
sage: S = R.quo(z^2 - 2)
|
|
1043
|
+
sage: S.is_field()
|
|
1044
|
+
False
|
|
1045
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
1046
|
+
sage: S = R.quotient(x^2 - 2)
|
|
1047
|
+
sage: S.is_field()
|
|
1048
|
+
True
|
|
1049
|
+
|
|
1050
|
+
If proof is ``True``, requires the ``is_irreducible`` method of the
|
|
1051
|
+
modulus to be implemented::
|
|
1052
|
+
|
|
1053
|
+
sage: # needs sage.rings.padics
|
|
1054
|
+
sage: R1.<x> = Qp(2)[]
|
|
1055
|
+
sage: F1 = R1.quotient_ring(x^2 + x + 1)
|
|
1056
|
+
sage: R2.<x> = F1[]
|
|
1057
|
+
sage: F2 = R2.quotient_ring(x^2 + x + 1)
|
|
1058
|
+
sage: F2.is_field()
|
|
1059
|
+
Traceback (most recent call last):
|
|
1060
|
+
...
|
|
1061
|
+
NotImplementedError: cannot rewrite Univariate Quotient Polynomial Ring in
|
|
1062
|
+
xbar over 2-adic Field with capped relative precision 20 with modulus
|
|
1063
|
+
(1 + O(2^20))*x^2 + (1 + O(2^20))*x + 1 + O(2^20) as an isomorphic ring
|
|
1064
|
+
sage: F2.is_field(proof = False)
|
|
1065
|
+
False
|
|
1066
|
+
"""
|
|
1067
|
+
ret = self.base_ring().is_field(proof)
|
|
1068
|
+
try:
|
|
1069
|
+
ret = ret and self.modulus().is_irreducible()
|
|
1070
|
+
except NotImplementedError:
|
|
1071
|
+
if proof:
|
|
1072
|
+
raise
|
|
1073
|
+
else:
|
|
1074
|
+
ret = False
|
|
1075
|
+
|
|
1076
|
+
if ret:
|
|
1077
|
+
from sage.categories.fields import Fields
|
|
1078
|
+
self._refine_category_(Fields())
|
|
1079
|
+
return ret
|
|
1080
|
+
|
|
1081
|
+
def is_integral_domain(self, proof=True):
|
|
1082
|
+
"""
|
|
1083
|
+
Return whether or not this quotient ring is an integral domain.
|
|
1084
|
+
|
|
1085
|
+
EXAMPLES::
|
|
1086
|
+
|
|
1087
|
+
sage: R.<z> = PolynomialRing(ZZ)
|
|
1088
|
+
|
|
1089
|
+
sage: S = R.quotient(z^2 - z)
|
|
1090
|
+
sage: S.is_integral_domain()
|
|
1091
|
+
False
|
|
1092
|
+
sage: T = R.quotient(z^2 + 1)
|
|
1093
|
+
sage: T.is_integral_domain()
|
|
1094
|
+
True
|
|
1095
|
+
sage: U = R.quotient(-1)
|
|
1096
|
+
sage: U.is_integral_domain()
|
|
1097
|
+
False
|
|
1098
|
+
|
|
1099
|
+
sage: # needs sage.libs.singular
|
|
1100
|
+
sage: R2.<y> = PolynomialRing(R)
|
|
1101
|
+
sage: S2 = R2.quotient(z^2 - y^3)
|
|
1102
|
+
sage: S2.is_integral_domain()
|
|
1103
|
+
True
|
|
1104
|
+
sage: S3 = R2.quotient(z^2 - 2*y*z + y^2)
|
|
1105
|
+
sage: S3.is_integral_domain()
|
|
1106
|
+
False
|
|
1107
|
+
|
|
1108
|
+
sage: R.<z> = PolynomialRing(ZZ.quotient(4))
|
|
1109
|
+
sage: S = R.quotient(z - 1)
|
|
1110
|
+
sage: S.is_integral_domain()
|
|
1111
|
+
False
|
|
1112
|
+
|
|
1113
|
+
TESTS:
|
|
1114
|
+
|
|
1115
|
+
Here is an example of a quotient ring which is not an integral
|
|
1116
|
+
domain, even though the base ring is integral and the modulus is
|
|
1117
|
+
irreducible::
|
|
1118
|
+
|
|
1119
|
+
sage: # needs sage.rings.number_field
|
|
1120
|
+
sage: x = polygen(ZZ, 'x')
|
|
1121
|
+
sage: B = ZZ.extension(x^2 - 5, 'a')
|
|
1122
|
+
sage: R.<y> = PolynomialRing(B)
|
|
1123
|
+
sage: S = R.quotient(y^2 - y - 1)
|
|
1124
|
+
sage: S.is_integral_domain()
|
|
1125
|
+
Traceback (most recent call last):
|
|
1126
|
+
...
|
|
1127
|
+
NotImplementedError
|
|
1128
|
+
sage: S.is_integral_domain(proof=False)
|
|
1129
|
+
False
|
|
1130
|
+
|
|
1131
|
+
The reason that the modulus y^2 - y - 1 is not prime is that it
|
|
1132
|
+
divides the product
|
|
1133
|
+
(2*y-(1+a))*(2*y-(1-a)) = 4*y^2 - 4*y - 4.
|
|
1134
|
+
|
|
1135
|
+
Unfortunately, the program above is already unable to determine
|
|
1136
|
+
that the modulus is irreducible.
|
|
1137
|
+
"""
|
|
1138
|
+
from sage.categories.integral_domains import IntegralDomains
|
|
1139
|
+
if self.category().is_subcategory(IntegralDomains()):
|
|
1140
|
+
return True
|
|
1141
|
+
ret = self.base_ring().is_integral_domain(proof)
|
|
1142
|
+
if ret:
|
|
1143
|
+
try:
|
|
1144
|
+
irr = self.modulus().is_irreducible()
|
|
1145
|
+
if not irr:
|
|
1146
|
+
# since the modulus is nonzero, the condition of the base ring being an
|
|
1147
|
+
# integral domain and the modulus being irreducible are
|
|
1148
|
+
# necessary but not sufficient
|
|
1149
|
+
ret = False
|
|
1150
|
+
else:
|
|
1151
|
+
from sage.categories.gcd_domains import GcdDomains
|
|
1152
|
+
if self.base_ring() in GcdDomains():
|
|
1153
|
+
# if the base ring is a GCD domain, the conditions are sufficient
|
|
1154
|
+
ret = True
|
|
1155
|
+
else:
|
|
1156
|
+
raise NotImplementedError
|
|
1157
|
+
except NotImplementedError:
|
|
1158
|
+
if proof:
|
|
1159
|
+
raise
|
|
1160
|
+
else:
|
|
1161
|
+
ret = False
|
|
1162
|
+
|
|
1163
|
+
if ret:
|
|
1164
|
+
self._refine_category_(IntegralDomains())
|
|
1165
|
+
return ret
|
|
1166
|
+
|
|
1167
|
+
def krull_dimension(self):
|
|
1168
|
+
"""
|
|
1169
|
+
Return the Krull dimension.
|
|
1170
|
+
|
|
1171
|
+
This is the Krull dimension of the base ring, unless the
|
|
1172
|
+
quotient is zero.
|
|
1173
|
+
|
|
1174
|
+
EXAMPLES::
|
|
1175
|
+
|
|
1176
|
+
sage: x = polygen(ZZ, 'x')
|
|
1177
|
+
sage: R = PolynomialRing(ZZ, 'x').quotient(x**6 - 1)
|
|
1178
|
+
sage: R.krull_dimension()
|
|
1179
|
+
1
|
|
1180
|
+
sage: R = PolynomialRing(ZZ, 'x').quotient(1)
|
|
1181
|
+
sage: R.krull_dimension()
|
|
1182
|
+
-1
|
|
1183
|
+
"""
|
|
1184
|
+
if self.is_zero():
|
|
1185
|
+
return -1
|
|
1186
|
+
return self.base_ring().krull_dimension()
|
|
1187
|
+
|
|
1188
|
+
def modulus(self):
|
|
1189
|
+
"""
|
|
1190
|
+
Return the polynomial modulus of this quotient ring.
|
|
1191
|
+
|
|
1192
|
+
EXAMPLES::
|
|
1193
|
+
|
|
1194
|
+
sage: R.<x> = PolynomialRing(GF(3))
|
|
1195
|
+
sage: S = R.quotient(x^2 - 2)
|
|
1196
|
+
sage: S.modulus()
|
|
1197
|
+
x^2 + 1
|
|
1198
|
+
"""
|
|
1199
|
+
return self.__polynomial
|
|
1200
|
+
|
|
1201
|
+
def ngens(self):
|
|
1202
|
+
"""
|
|
1203
|
+
Return the number of generators of this quotient ring over the base
|
|
1204
|
+
ring. This function always returns 1.
|
|
1205
|
+
|
|
1206
|
+
EXAMPLES::
|
|
1207
|
+
|
|
1208
|
+
sage: # needs sage.libs.singular
|
|
1209
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
1210
|
+
sage: S.<y> = PolynomialRing(R)
|
|
1211
|
+
sage: T.<z> = S.quotient(y + x)
|
|
1212
|
+
sage: T
|
|
1213
|
+
Univariate Quotient Polynomial Ring in z over
|
|
1214
|
+
Univariate Polynomial Ring in x over Rational Field with modulus y + x
|
|
1215
|
+
sage: T.ngens()
|
|
1216
|
+
1
|
|
1217
|
+
"""
|
|
1218
|
+
return 1
|
|
1219
|
+
|
|
1220
|
+
def number_field(self):
|
|
1221
|
+
"""
|
|
1222
|
+
Return the number field isomorphic to this quotient polynomial
|
|
1223
|
+
ring, if possible.
|
|
1224
|
+
|
|
1225
|
+
EXAMPLES::
|
|
1226
|
+
|
|
1227
|
+
sage: # needs sage.rings.number_field
|
|
1228
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
1229
|
+
sage: S.<alpha> = R.quotient(x^29 - 17*x - 1)
|
|
1230
|
+
sage: K = S.number_field(); K
|
|
1231
|
+
Number Field in alpha with defining polynomial x^29 - 17*x - 1
|
|
1232
|
+
sage: alpha = K.gen()
|
|
1233
|
+
sage: alpha^29
|
|
1234
|
+
17*alpha + 1
|
|
1235
|
+
"""
|
|
1236
|
+
if self.characteristic() != 0:
|
|
1237
|
+
raise ArithmeticError("Polynomial quotient ring is not isomorphic to a number field (it has positive characteristic).")
|
|
1238
|
+
|
|
1239
|
+
if not isinstance(self.base_ring(), sage.rings.rational_field.RationalField):
|
|
1240
|
+
raise NotImplementedError("Computation of number field only implemented for quotients of the polynomial ring over the rational field.")
|
|
1241
|
+
from sage.rings.number_field.number_field import NumberField
|
|
1242
|
+
return NumberField(self.modulus(), self.variable_name())
|
|
1243
|
+
|
|
1244
|
+
def polynomial_ring(self):
|
|
1245
|
+
"""
|
|
1246
|
+
Return the polynomial ring of which this ring is the quotient.
|
|
1247
|
+
|
|
1248
|
+
EXAMPLES::
|
|
1249
|
+
|
|
1250
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
1251
|
+
sage: S = R.quotient(x^2 - 2)
|
|
1252
|
+
sage: S.polynomial_ring()
|
|
1253
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
1254
|
+
"""
|
|
1255
|
+
return self.__ring
|
|
1256
|
+
|
|
1257
|
+
cover_ring = polynomial_ring
|
|
1258
|
+
|
|
1259
|
+
def random_element(self, degree=None, *args, **kwds):
|
|
1260
|
+
"""
|
|
1261
|
+
Return a random element of this quotient ring.
|
|
1262
|
+
|
|
1263
|
+
INPUT:
|
|
1264
|
+
|
|
1265
|
+
- ``degree`` -- (optional) argument; either an integer for fixing the
|
|
1266
|
+
degree, or a tuple of the minimum and maximum degree. By default the
|
|
1267
|
+
degree is n - 1 with n the degree of the polynomial ring. Note that
|
|
1268
|
+
the degree of the polynomial is fixed before the modulo calculation.
|
|
1269
|
+
So when `degree` is bigger than the degree of the polynomial ring, the
|
|
1270
|
+
degree of the returned polynomial would be lower than `degree`.
|
|
1271
|
+
- ``*args``, ``**kwds`` -- arguments for randomization that are passed
|
|
1272
|
+
on to the ``random_element`` method of the polynomial ring, and from
|
|
1273
|
+
there to the base ring
|
|
1274
|
+
|
|
1275
|
+
OUTPUT: element of this quotient ring
|
|
1276
|
+
|
|
1277
|
+
EXAMPLES::
|
|
1278
|
+
|
|
1279
|
+
sage: # needs sage.modules sage.rings.finite_rings
|
|
1280
|
+
sage: F1.<a> = GF(2^7)
|
|
1281
|
+
sage: P1.<x> = F1[]
|
|
1282
|
+
sage: F2 = F1.extension(x^2 + x + 1, 'u')
|
|
1283
|
+
sage: F2.random_element().parent() is F2
|
|
1284
|
+
True
|
|
1285
|
+
"""
|
|
1286
|
+
if degree is None:
|
|
1287
|
+
degree = self.degree() - 1
|
|
1288
|
+
|
|
1289
|
+
return self(self.polynomial_ring().random_element(
|
|
1290
|
+
degree=degree, *args, **kwds))
|
|
1291
|
+
|
|
1292
|
+
@cached_method
|
|
1293
|
+
def _S_decomposition(self, S):
|
|
1294
|
+
"""
|
|
1295
|
+
Compute the decomposition of ``self`` into a product of number fields.
|
|
1296
|
+
|
|
1297
|
+
This is an internal function used by
|
|
1298
|
+
:meth:`S_class_group`, :meth:`S_units` and :meth:`selmer_generators`.
|
|
1299
|
+
|
|
1300
|
+
EXAMPLES::
|
|
1301
|
+
|
|
1302
|
+
sage: # needs sage.rings.number_field
|
|
1303
|
+
sage: K.<a> = QuadraticField(-5)
|
|
1304
|
+
sage: R.<x> = K[]
|
|
1305
|
+
sage: S.<xbar> = R.quotient((x^2 + 23) * (x^2 + 31))
|
|
1306
|
+
sage: fields, isos, iso_classes = S._S_decomposition(tuple(K.primes_above(3)))
|
|
1307
|
+
|
|
1308
|
+
Representatives of the number fields up to isomorphism that
|
|
1309
|
+
occur in the decomposition::
|
|
1310
|
+
|
|
1311
|
+
sage: fields # needs sage.rings.number_field
|
|
1312
|
+
[Number Field in x0 with defining polynomial x^2 + 23 over its base field,
|
|
1313
|
+
Number Field in x1 with defining polynomial x^2 + 31 over its base field]
|
|
1314
|
+
|
|
1315
|
+
In this case, the isomorphisms of these representatives to the components
|
|
1316
|
+
are the identity maps::
|
|
1317
|
+
|
|
1318
|
+
sage: isos # needs sage.rings.number_field
|
|
1319
|
+
[(Ring endomorphism of Number Field in y0 with defining polynomial x^4 + 56*x^2 + 324
|
|
1320
|
+
Defn: y0 |--> y0,
|
|
1321
|
+
0),
|
|
1322
|
+
(Ring endomorphism of Number Field in y1 with defining polynomial x^4 + 72*x^2 + 676
|
|
1323
|
+
Defn: y1 |--> y1,
|
|
1324
|
+
1)]
|
|
1325
|
+
|
|
1326
|
+
There are four primes above 3 in the first component and two
|
|
1327
|
+
in the second component::
|
|
1328
|
+
|
|
1329
|
+
sage: len(iso_classes[0][1]) # needs sage.rings.number_field
|
|
1330
|
+
4
|
|
1331
|
+
sage: len(iso_classes[1][1]) # needs sage.rings.number_field
|
|
1332
|
+
2
|
|
1333
|
+
"""
|
|
1334
|
+
from sage.rings.number_field.number_field_base import NumberField
|
|
1335
|
+
K = self.base_ring()
|
|
1336
|
+
if not isinstance(K, NumberField) or not self.__polynomial.is_squarefree():
|
|
1337
|
+
raise NotImplementedError
|
|
1338
|
+
|
|
1339
|
+
from sage.rings.ideal import Ideal_generic
|
|
1340
|
+
for p in S:
|
|
1341
|
+
# second check due to inconsistency over QQ - see # 7596
|
|
1342
|
+
if not (isinstance(p, Ideal_generic)
|
|
1343
|
+
and (p.ring() is K or p.ring() is K.ring_of_integers())
|
|
1344
|
+
and p.is_prime()):
|
|
1345
|
+
raise TypeError("S must be a list of prime ideals of the base field.")
|
|
1346
|
+
|
|
1347
|
+
F = self.__polynomial.factor()
|
|
1348
|
+
fields = []
|
|
1349
|
+
isos = []
|
|
1350
|
+
iso_classes = []
|
|
1351
|
+
i = 0
|
|
1352
|
+
for f, _ in F:
|
|
1353
|
+
D = K.extension(f, 'x'+str(i))
|
|
1354
|
+
fields.append(D)
|
|
1355
|
+
D_abs = D.absolute_field('y'+str(i))
|
|
1356
|
+
i += 1
|
|
1357
|
+
|
|
1358
|
+
seen_before = False
|
|
1359
|
+
j = 0
|
|
1360
|
+
for D_iso, _ in iso_classes:
|
|
1361
|
+
if D_abs.is_isomorphic(D_iso):
|
|
1362
|
+
seen_before = True
|
|
1363
|
+
break
|
|
1364
|
+
j += 1
|
|
1365
|
+
if not seen_before:
|
|
1366
|
+
S_abs = []
|
|
1367
|
+
for p in S:
|
|
1368
|
+
# next line looks a bit silly,
|
|
1369
|
+
# due to inconsistency over QQ - see # 7596
|
|
1370
|
+
abs_gens = [D_abs.structure()[1](g)
|
|
1371
|
+
for g in D.ideal(p.gens()).gens()]
|
|
1372
|
+
S_abs += [pp for pp, _ in D_abs.ideal(abs_gens).factor()]
|
|
1373
|
+
iso_classes.append((D_abs, S_abs))
|
|
1374
|
+
isos.append((D_abs.embeddings(D_abs)[0], j))
|
|
1375
|
+
return fields, isos, iso_classes
|
|
1376
|
+
|
|
1377
|
+
def S_class_group(self, S, proof=True):
|
|
1378
|
+
r"""
|
|
1379
|
+
If ``self`` is an étale algebra `D` over a number field `K` (i.e.
|
|
1380
|
+
a quotient of `K[x]` by a squarefree polynomial) and `S` is a
|
|
1381
|
+
finite set of places of `K`, return a list of generators of
|
|
1382
|
+
the `S`-class group of `D`.
|
|
1383
|
+
|
|
1384
|
+
NOTE:
|
|
1385
|
+
|
|
1386
|
+
Since the ``ideal`` function behaves differently over number
|
|
1387
|
+
fields than over polynomial quotient rings (the quotient does
|
|
1388
|
+
not even know its ring of integers), we return a set of pairs
|
|
1389
|
+
``(gen, order)``, where ``gen`` is a tuple of generators of an
|
|
1390
|
+
ideal `I` and ``order`` is the order of `I` in the `S`-class
|
|
1391
|
+
group.
|
|
1392
|
+
|
|
1393
|
+
INPUT:
|
|
1394
|
+
|
|
1395
|
+
- ``S`` -- set of primes of the coefficient ring
|
|
1396
|
+
|
|
1397
|
+
- ``proof`` -- if ``False``, assume the GRH in computing the class group
|
|
1398
|
+
|
|
1399
|
+
OUTPUT:
|
|
1400
|
+
|
|
1401
|
+
A list of generators of the `S`-class group, in the form
|
|
1402
|
+
``(gen, order)``, where ``gen`` is a tuple of elements
|
|
1403
|
+
generating a fractional ideal `I` and ``order`` is the order
|
|
1404
|
+
of `I` in the `S`-class group.
|
|
1405
|
+
|
|
1406
|
+
EXAMPLES:
|
|
1407
|
+
|
|
1408
|
+
A trivial algebra over `\QQ(\sqrt{-5})` has the same class group as its
|
|
1409
|
+
base::
|
|
1410
|
+
|
|
1411
|
+
sage: # needs sage.rings.number_field
|
|
1412
|
+
sage: K.<a> = QuadraticField(-5)
|
|
1413
|
+
sage: R.<x> = K[]
|
|
1414
|
+
sage: S.<xbar> = R.quotient(x)
|
|
1415
|
+
sage: S.S_class_group([])
|
|
1416
|
+
[((2, -a + 1), 2)]
|
|
1417
|
+
|
|
1418
|
+
When we include the prime `(2, -a+1)`, the `S`-class group
|
|
1419
|
+
becomes trivial::
|
|
1420
|
+
|
|
1421
|
+
sage: S.S_class_group([K.ideal(2, -a+1)]) # needs sage.rings.number_field
|
|
1422
|
+
[]
|
|
1423
|
+
|
|
1424
|
+
Here is an example where the base and the extension both contribute to
|
|
1425
|
+
the class group::
|
|
1426
|
+
|
|
1427
|
+
sage: # needs sage.rings.number_field
|
|
1428
|
+
sage: K.<a> = QuadraticField(-5)
|
|
1429
|
+
sage: K.class_group()
|
|
1430
|
+
Class group of order 2 with structure C2 of Number Field in a
|
|
1431
|
+
with defining polynomial x^2 + 5 with a = 2.236067977499790?*I
|
|
1432
|
+
sage: R.<x> = K[]
|
|
1433
|
+
sage: S.<xbar> = R.quotient(x^2 + 23)
|
|
1434
|
+
sage: S.S_class_group([])
|
|
1435
|
+
[((2, a + 1, -1/2*xbar + 3/2, 1/2*a*xbar - 1/2*a + 1), 6)]
|
|
1436
|
+
sage: S.S_class_group([K.ideal(3, a-1)])
|
|
1437
|
+
[]
|
|
1438
|
+
sage: S.S_class_group([K.ideal(2, a+1)])
|
|
1439
|
+
[]
|
|
1440
|
+
sage: S.S_class_group([K.ideal(a)])
|
|
1441
|
+
[((2, a + 1, -1/2*xbar + 3/2, 1/2*a*xbar - 1/2*a + 1), 6)]
|
|
1442
|
+
|
|
1443
|
+
Now we take an example over a nontrivial base with two factors, each
|
|
1444
|
+
contributing to the class group::
|
|
1445
|
+
|
|
1446
|
+
sage: # needs sage.rings.number_field
|
|
1447
|
+
sage: K.<a> = QuadraticField(-5)
|
|
1448
|
+
sage: R.<x> = K[]
|
|
1449
|
+
sage: S.<xbar> = R.quotient((x^2 + 23) * (x^2 + 31))
|
|
1450
|
+
sage: S.S_class_group([]) # not tested
|
|
1451
|
+
[((1/4*xbar^2 + 31/4,
|
|
1452
|
+
(-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8,
|
|
1453
|
+
1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16,
|
|
1454
|
+
-1/16*a*xbar^3 + (1/16*a + 1/8)*xbar^2 - 31/16*a*xbar + 31/16*a + 31/8),
|
|
1455
|
+
6),
|
|
1456
|
+
((-1/4*xbar^2 - 23/4,
|
|
1457
|
+
(1/8*a - 1/8)*xbar^2 + 23/8*a - 23/8,
|
|
1458
|
+
-1/16*xbar^3 - 1/16*xbar^2 - 23/16*xbar - 23/16,
|
|
1459
|
+
1/16*a*xbar^3 + (-1/16*a - 1/8)*xbar^2 + 23/16*a*xbar - 23/16*a - 23/8),
|
|
1460
|
+
6),
|
|
1461
|
+
((-5/4*xbar^2 - 115/4,
|
|
1462
|
+
1/4*a*xbar^2 + 23/4*a,
|
|
1463
|
+
-1/16*xbar^3 - 7/16*xbar^2 - 23/16*xbar - 161/16,
|
|
1464
|
+
1/16*a*xbar^3 - 1/16*a*xbar^2 + 23/16*a*xbar - 23/16*a),
|
|
1465
|
+
2)]
|
|
1466
|
+
|
|
1467
|
+
By using the ideal `(a)`, we cut the part of the class group coming from
|
|
1468
|
+
`x^2 + 31` from 12 to 2, i.e. we lose a generator of order 6 (this was
|
|
1469
|
+
fixed in :issue:`14489`)::
|
|
1470
|
+
|
|
1471
|
+
sage: S.S_class_group([K.ideal(a)]) # representation varies # not tested, needs sage.rings.number_field
|
|
1472
|
+
[((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8,
|
|
1473
|
+
1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16,
|
|
1474
|
+
-1/16*a*xbar^3 + (1/16*a + 1/8)*xbar^2 - 31/16*a*xbar + 31/16*a + 31/8),
|
|
1475
|
+
6),
|
|
1476
|
+
((-1/4*xbar^2 - 23/4, (1/8*a - 1/8)*xbar^2 + 23/8*a - 23/8,
|
|
1477
|
+
-1/16*xbar^3 - 1/16*xbar^2 - 23/16*xbar - 23/16,
|
|
1478
|
+
1/16*a*xbar^3 + (-1/16*a - 1/8)*xbar^2 + 23/16*a*xbar - 23/16*a - 23/8),
|
|
1479
|
+
2)]
|
|
1480
|
+
|
|
1481
|
+
Note that all the returned values live where we expect them to::
|
|
1482
|
+
|
|
1483
|
+
sage: # needs sage.rings.number_field
|
|
1484
|
+
sage: CG = S.S_class_group([])
|
|
1485
|
+
sage: type(CG[0][0][1])
|
|
1486
|
+
<class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_generic_with_category.element_class'>
|
|
1487
|
+
sage: type(CG[0][1])
|
|
1488
|
+
<class 'sage.rings.integer.Integer'>
|
|
1489
|
+
|
|
1490
|
+
TESTS:
|
|
1491
|
+
|
|
1492
|
+
We verify the above test, where the representation depends on the PARI version::
|
|
1493
|
+
|
|
1494
|
+
sage: # needs sage.rings.number_field
|
|
1495
|
+
sage: K.<a> = QuadraticField(-5)
|
|
1496
|
+
sage: R.<x> = K[]
|
|
1497
|
+
sage: S.<xbar> = R.quotient((x^2 + 23) * (x^2 + 31))
|
|
1498
|
+
sage: C = S.S_class_group([])
|
|
1499
|
+
sage: C[:2]
|
|
1500
|
+
[((1/4*xbar^2 + 31/4,
|
|
1501
|
+
(1/8*a + 1/8)*xbar^2 + 31/8*a + 31/8,
|
|
1502
|
+
-1/16*xbar^3 + 3/16*xbar^2 - 31/16*xbar + 93/16,
|
|
1503
|
+
1/16*a*xbar^3 + (-1/16*a + 1/8)*xbar^2 + 31/16*a*xbar - 31/16*a + 31/8),
|
|
1504
|
+
6),
|
|
1505
|
+
((-1/4*xbar^2 - 23/4,
|
|
1506
|
+
(-1/8*a - 1/8)*xbar^2 - 23/8*a - 23/8,
|
|
1507
|
+
1/16*xbar^3 + 1/16*xbar^2 + 23/16*xbar + 23/16,
|
|
1508
|
+
-1/16*a*xbar^3 + (1/16*a - 1/8)*xbar^2 - 23/16*a*xbar + 23/16*a - 23/8),
|
|
1509
|
+
6)]
|
|
1510
|
+
sage: C[2][1]
|
|
1511
|
+
2
|
|
1512
|
+
sage: gens = C[2][0]
|
|
1513
|
+
sage: expected_gens = (
|
|
1514
|
+
....: -5/4*xbar^2 - 115/4,
|
|
1515
|
+
....: 1/4*a*xbar^2 + 23/4*a,
|
|
1516
|
+
....: -1/16*xbar^3 - 7/16*xbar^2 - 23/16*xbar - 161/16,
|
|
1517
|
+
....: 1/16*a*xbar^3 - 1/16*a*xbar^2 + 23/16*a*xbar - 23/16*a)
|
|
1518
|
+
sage: gens[0] == expected_gens[0]
|
|
1519
|
+
True
|
|
1520
|
+
sage: gens[1] in (expected_gens[1], expected_gens[1]/2 + expected_gens[0]/2, -expected_gens[1]/2 + expected_gens[0]/2)
|
|
1521
|
+
True
|
|
1522
|
+
sage: gens[2] in (expected_gens[2], expected_gens[2] + expected_gens[0]/2, -expected_gens[2] + expected_gens[0]/2)
|
|
1523
|
+
True
|
|
1524
|
+
sage: gens[3] in (expected_gens[3], expected_gens[3] + expected_gens[0]/2, -expected_gens[3] + expected_gens[0]/2)
|
|
1525
|
+
True
|
|
1526
|
+
"""
|
|
1527
|
+
fields, isos, iso_classes = self._S_decomposition(tuple(S))
|
|
1528
|
+
n = len(fields)
|
|
1529
|
+
|
|
1530
|
+
component_S_class_groups = []
|
|
1531
|
+
for D_iso, S_iso in iso_classes:
|
|
1532
|
+
# compute S-class group for each distinct component
|
|
1533
|
+
clgp_gens = D_iso._S_class_group_and_units(tuple(S_iso), proof=proof)[1]
|
|
1534
|
+
component_S_class_groups.append(clgp_gens)
|
|
1535
|
+
|
|
1536
|
+
clgp_gens = []
|
|
1537
|
+
moduli = [D.relative_polynomial() for D in fields]
|
|
1538
|
+
for i in range(n):
|
|
1539
|
+
phi = isos[i][0]
|
|
1540
|
+
back_to_rel = phi.codomain().structure()[0]
|
|
1541
|
+
|
|
1542
|
+
for clgp_gen, gen_order in component_S_class_groups[isos[i][1]]:
|
|
1543
|
+
ideal_gens = []
|
|
1544
|
+
for ideal_gen in clgp_gen.gens():
|
|
1545
|
+
rel_ideal_gen = back_to_rel(phi(ideal_gen))
|
|
1546
|
+
prod_ideal_gen = [0]*i + [rel_ideal_gen.lift()] + [0]*(n - i - 1)
|
|
1547
|
+
poly_ideal_gen = self(crt(prod_ideal_gen, moduli))
|
|
1548
|
+
ideal_gens.append(poly_ideal_gen)
|
|
1549
|
+
clgp_gens.append((tuple(ideal_gens), gen_order))
|
|
1550
|
+
|
|
1551
|
+
return clgp_gens
|
|
1552
|
+
|
|
1553
|
+
def class_group(self, proof=True):
|
|
1554
|
+
r"""
|
|
1555
|
+
If ``self`` is a quotient ring of a polynomial ring over a number
|
|
1556
|
+
field `K`, by a polynomial of nonzero discriminant, return a
|
|
1557
|
+
list of generators of the class group.
|
|
1558
|
+
|
|
1559
|
+
NOTE:
|
|
1560
|
+
|
|
1561
|
+
Since the ``ideal`` function behaves differently over number
|
|
1562
|
+
fields than over polynomial quotient rings (the quotient does
|
|
1563
|
+
not even know its ring of integers), we return a set of pairs
|
|
1564
|
+
``(gen, order)``, where ``gen`` is a tuple of generators of an
|
|
1565
|
+
ideal `I` and ``order`` is the order of `I` in the class group.
|
|
1566
|
+
|
|
1567
|
+
INPUT:
|
|
1568
|
+
|
|
1569
|
+
- ``proof`` -- if ``False``, assume the GRH in computing the class group
|
|
1570
|
+
|
|
1571
|
+
OUTPUT:
|
|
1572
|
+
|
|
1573
|
+
A list of pairs ``(gen, order)``, where ``gen`` is a tuple of
|
|
1574
|
+
elements generating a fractional ideal and ``order`` is
|
|
1575
|
+
the order of `I` in the class group.
|
|
1576
|
+
|
|
1577
|
+
EXAMPLES::
|
|
1578
|
+
|
|
1579
|
+
sage: # needs sage.rings.number_field
|
|
1580
|
+
sage: K.<a> = QuadraticField(-3)
|
|
1581
|
+
sage: K.class_group()
|
|
1582
|
+
Class group of order 1 of Number Field in a
|
|
1583
|
+
with defining polynomial x^2 + 3 with a = 1.732050807568878?*I
|
|
1584
|
+
sage: x = polygen(QQ, 'x')
|
|
1585
|
+
sage: K.<a> = QQ['x'].quotient(x^2 + 3)
|
|
1586
|
+
sage: K.class_group()
|
|
1587
|
+
[]
|
|
1588
|
+
|
|
1589
|
+
A trivial algebra over `\QQ(\sqrt{-5})` has the same class group as its
|
|
1590
|
+
base::
|
|
1591
|
+
|
|
1592
|
+
sage: # needs sage.rings.number_field
|
|
1593
|
+
sage: K.<a> = QuadraticField(-5)
|
|
1594
|
+
sage: R.<x> = K[]
|
|
1595
|
+
sage: S.<xbar> = R.quotient(x)
|
|
1596
|
+
sage: S.class_group()
|
|
1597
|
+
[((2, -a + 1), 2)]
|
|
1598
|
+
|
|
1599
|
+
The same algebra constructed in a different way::
|
|
1600
|
+
|
|
1601
|
+
sage: x = polygen(ZZ, 'x')
|
|
1602
|
+
sage: K.<a> = QQ['x'].quotient(x^2 + 5)
|
|
1603
|
+
sage: K.class_group(()) # needs sage.rings.number_field
|
|
1604
|
+
[((2, a + 1), 2)]
|
|
1605
|
+
|
|
1606
|
+
Here is an example where the base and the extension both contribute to
|
|
1607
|
+
the class group::
|
|
1608
|
+
|
|
1609
|
+
sage: # needs sage.rings.number_field
|
|
1610
|
+
sage: K.<a> = QuadraticField(-5)
|
|
1611
|
+
sage: K.class_group()
|
|
1612
|
+
Class group of order 2 with structure C2 of Number Field in a
|
|
1613
|
+
with defining polynomial x^2 + 5 with a = 2.236067977499790?*I
|
|
1614
|
+
sage: R.<x> = K[]
|
|
1615
|
+
sage: S.<xbar> = R.quotient(x^2 + 23)
|
|
1616
|
+
sage: S.class_group()
|
|
1617
|
+
[((2, a + 1, -1/2*xbar + 3/2, 1/2*a*xbar - 1/2*a + 1), 6)]
|
|
1618
|
+
|
|
1619
|
+
Here is an example of a product of number fields, both of which
|
|
1620
|
+
contribute to the class group::
|
|
1621
|
+
|
|
1622
|
+
sage: # needs sage.rings.number_field
|
|
1623
|
+
sage: R.<x> = QQ[]
|
|
1624
|
+
sage: S.<xbar> = R.quotient((x^2 + 23) * (x^2 + 47))
|
|
1625
|
+
sage: S.class_group()
|
|
1626
|
+
[((1/12*xbar^2 + 47/12,
|
|
1627
|
+
1/48*xbar^3 - 1/48*xbar^2 + 47/48*xbar - 47/48),
|
|
1628
|
+
3),
|
|
1629
|
+
((-1/12*xbar^2 - 23/12,
|
|
1630
|
+
-1/48*xbar^3 - 1/48*xbar^2 - 23/48*xbar - 23/48),
|
|
1631
|
+
5)]
|
|
1632
|
+
|
|
1633
|
+
Now we take an example over a nontrivial base with two factors, each
|
|
1634
|
+
contributing to the class group::
|
|
1635
|
+
|
|
1636
|
+
sage: # needs sage.rings.number_field
|
|
1637
|
+
sage: K.<a> = QuadraticField(-5)
|
|
1638
|
+
sage: R.<x> = K[]
|
|
1639
|
+
sage: S.<xbar> = R.quotient((x^2 + 23) * (x^2 + 31))
|
|
1640
|
+
sage: S.class_group() # not tested
|
|
1641
|
+
[((1/4*xbar^2 + 31/4,
|
|
1642
|
+
(-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8,
|
|
1643
|
+
1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16,
|
|
1644
|
+
-1/16*a*xbar^3 + (1/16*a + 1/8)*xbar^2 - 31/16*a*xbar + 31/16*a + 31/8),
|
|
1645
|
+
6),
|
|
1646
|
+
((-1/4*xbar^2 - 23/4,
|
|
1647
|
+
(1/8*a - 1/8)*xbar^2 + 23/8*a - 23/8,
|
|
1648
|
+
-1/16*xbar^3 - 1/16*xbar^2 - 23/16*xbar - 23/16,
|
|
1649
|
+
1/16*a*xbar^3 + (-1/16*a - 1/8)*xbar^2 + 23/16*a*xbar - 23/16*a - 23/8),
|
|
1650
|
+
6),
|
|
1651
|
+
((-5/4*xbar^2 - 115/4,
|
|
1652
|
+
1/4*a*xbar^2 + 23/4*a,
|
|
1653
|
+
-1/16*xbar^3 - 7/16*xbar^2 - 23/16*xbar - 161/16,
|
|
1654
|
+
1/16*a*xbar^3 - 1/16*a*xbar^2 + 23/16*a*xbar - 23/16*a),
|
|
1655
|
+
2)]
|
|
1656
|
+
|
|
1657
|
+
Note that all the returned values live where we expect them to::
|
|
1658
|
+
|
|
1659
|
+
sage: # needs sage.rings.number_field
|
|
1660
|
+
sage: CG = S.class_group()
|
|
1661
|
+
sage: type(CG[0][0][1])
|
|
1662
|
+
<class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_generic_with_category.element_class'>
|
|
1663
|
+
sage: type(CG[0][1])
|
|
1664
|
+
<class 'sage.rings.integer.Integer'>
|
|
1665
|
+
"""
|
|
1666
|
+
return self.S_class_group((), proof=proof)
|
|
1667
|
+
|
|
1668
|
+
def S_units(self, S, proof=True):
|
|
1669
|
+
"""
|
|
1670
|
+
If ``self`` is an étale algebra `D` over a number field `K` (i.e.
|
|
1671
|
+
a quotient of `K[x]` by a squarefree polynomial) and `S` is a
|
|
1672
|
+
finite set of places of `K`, return a list of generators of
|
|
1673
|
+
the group of `S`-units of `D`.
|
|
1674
|
+
|
|
1675
|
+
INPUT:
|
|
1676
|
+
|
|
1677
|
+
- ``S`` -- set of primes of the base field
|
|
1678
|
+
|
|
1679
|
+
- ``proof`` -- if ``False``, assume the GRH in computing the class group
|
|
1680
|
+
|
|
1681
|
+
OUTPUT:
|
|
1682
|
+
|
|
1683
|
+
A list of generators of the `S`-unit group, in the form
|
|
1684
|
+
``(gen, order)``, where ``gen`` is a unit of order ``order``.
|
|
1685
|
+
|
|
1686
|
+
EXAMPLES::
|
|
1687
|
+
|
|
1688
|
+
sage: K.<a> = QuadraticField(-3) # needs sage.rings.number_field
|
|
1689
|
+
sage: K.unit_group() # needs sage.rings.number_field
|
|
1690
|
+
Unit group with structure C6 of Number Field in a
|
|
1691
|
+
with defining polynomial x^2 + 3 with a = 1.732050807568878?*I
|
|
1692
|
+
|
|
1693
|
+
sage: # needs sage.rings.number_field
|
|
1694
|
+
sage: x = polygen(ZZ, 'x')
|
|
1695
|
+
sage: K.<a> = QQ['x'].quotient(x^2 + 3)
|
|
1696
|
+
sage: u, o = K.S_units([])[0]; o
|
|
1697
|
+
6
|
|
1698
|
+
sage: 2*u - 1 in {a, -a}
|
|
1699
|
+
True
|
|
1700
|
+
sage: u^6
|
|
1701
|
+
1
|
|
1702
|
+
sage: u^3
|
|
1703
|
+
-1
|
|
1704
|
+
sage: 2*u^2 + 1 in {a, -a}
|
|
1705
|
+
True
|
|
1706
|
+
|
|
1707
|
+
::
|
|
1708
|
+
|
|
1709
|
+
sage: # needs sage.rings.number_field
|
|
1710
|
+
sage: K.<a> = QuadraticField(-3)
|
|
1711
|
+
sage: y = polygen(K)
|
|
1712
|
+
sage: L.<b> = K['y'].quotient(y^3 + 5); L
|
|
1713
|
+
Univariate Quotient Polynomial Ring in b over Number Field in a
|
|
1714
|
+
with defining polynomial x^2 + 3 with a = 1.732050807568878?*I
|
|
1715
|
+
with modulus y^3 + 5
|
|
1716
|
+
sage: [u for u, o in L.S_units([]) if o is Infinity]
|
|
1717
|
+
[(-1/3*a - 1)*b^2 - 4/3*a*b - 4/3*a + 3,
|
|
1718
|
+
(-1/3*a - 1)*b^2 + (2/3*a - 2)*b + 13/6*a - 1/2]
|
|
1719
|
+
sage: [u for u, o in L.S_units([K.ideal(1/2*a - 3/2)])
|
|
1720
|
+
....: if o is Infinity]
|
|
1721
|
+
[(-1/6*a - 1/2)*b^2 + (1/3*a - 1)*b + 4/3*a,
|
|
1722
|
+
(-1/3*a - 1)*b^2 - 4/3*a*b - 4/3*a + 3,
|
|
1723
|
+
(-1/3*a - 1)*b^2 + (2/3*a - 2)*b + 13/6*a - 1/2]
|
|
1724
|
+
sage: [u for u, o in L.S_units([K.ideal(2)]) if o is Infinity]
|
|
1725
|
+
[(1/2*a - 1/2)*b^2 + (a + 1)*b + 3,
|
|
1726
|
+
(1/6*a + 1/2)*b^2 + (-1/3*a + 1)*b - 5/6*a - 1/2,
|
|
1727
|
+
1/3*a*b^2 + (1/3*a + 1)*b - 1/6*a + 3/2,
|
|
1728
|
+
(-1/3*a - 1)*b^2 - 4/3*a*b - 4/3*a + 3,
|
|
1729
|
+
(-1/3*a - 1)*b^2 + (2/3*a - 2)*b + 13/6*a - 1/2]
|
|
1730
|
+
|
|
1731
|
+
Note that all the returned values live where we expect them to::
|
|
1732
|
+
|
|
1733
|
+
sage: # needs sage.rings.number_field
|
|
1734
|
+
sage: U = L.S_units([])
|
|
1735
|
+
sage: type(U[0][0])
|
|
1736
|
+
<class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_field_with_category.element_class'>
|
|
1737
|
+
sage: type(U[0][1])
|
|
1738
|
+
<class 'sage.rings.integer.Integer'>
|
|
1739
|
+
sage: type(U[1][1])
|
|
1740
|
+
<class 'sage.rings.infinity.PlusInfinity'>
|
|
1741
|
+
"""
|
|
1742
|
+
fields, isos, iso_classes = self._S_decomposition(tuple(S))
|
|
1743
|
+
n = len(fields)
|
|
1744
|
+
|
|
1745
|
+
component_S_units = []
|
|
1746
|
+
for D_iso, S_iso in iso_classes:
|
|
1747
|
+
# compute S-units for each distinct component
|
|
1748
|
+
units = D_iso.S_units(S_iso, proof=proof)
|
|
1749
|
+
component_S_units.append(units)
|
|
1750
|
+
|
|
1751
|
+
units = []
|
|
1752
|
+
moduli = [D.relative_polynomial() for D in fields]
|
|
1753
|
+
for i in range(n):
|
|
1754
|
+
phi = isos[i][0]
|
|
1755
|
+
back_to_rel = phi.codomain().structure()[0]
|
|
1756
|
+
|
|
1757
|
+
for unit in component_S_units[isos[i][1]]:
|
|
1758
|
+
mul_order = unit.multiplicative_order()
|
|
1759
|
+
rel_unit = back_to_rel(phi(unit))
|
|
1760
|
+
prod_unit = [1]*i + [rel_unit.lift()] + [1]*(n - i - 1)
|
|
1761
|
+
poly_unit = self(crt(prod_unit, moduli))
|
|
1762
|
+
units.append((poly_unit, mul_order))
|
|
1763
|
+
|
|
1764
|
+
return units
|
|
1765
|
+
|
|
1766
|
+
def units(self, proof=True):
|
|
1767
|
+
"""
|
|
1768
|
+
If this quotient ring is over a number field K, by a polynomial of
|
|
1769
|
+
nonzero discriminant, returns a list of generators of the units.
|
|
1770
|
+
|
|
1771
|
+
INPUT:
|
|
1772
|
+
|
|
1773
|
+
- ``proof`` -- if ``False``, assume the GRH in computing the class group
|
|
1774
|
+
|
|
1775
|
+
OUTPUT:
|
|
1776
|
+
|
|
1777
|
+
A list of generators of the unit group, in the form ``(gen, order)``,
|
|
1778
|
+
where ``gen`` is a unit of order ``order``.
|
|
1779
|
+
|
|
1780
|
+
EXAMPLES::
|
|
1781
|
+
|
|
1782
|
+
sage: K.<a> = QuadraticField(-3) # needs sage.rings.number_field
|
|
1783
|
+
sage: K.unit_group() # needs sage.rings.number_field
|
|
1784
|
+
Unit group with structure C6 of
|
|
1785
|
+
Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I
|
|
1786
|
+
|
|
1787
|
+
sage: # needs sage.rings.number_field
|
|
1788
|
+
sage: x = polygen(ZZ, 'x')
|
|
1789
|
+
sage: K.<a> = QQ['x'].quotient(x^2 + 3)
|
|
1790
|
+
sage: u = K.units()[0][0]
|
|
1791
|
+
sage: 2*u - 1 in {a, -a}
|
|
1792
|
+
True
|
|
1793
|
+
sage: u^6
|
|
1794
|
+
1
|
|
1795
|
+
sage: u^3
|
|
1796
|
+
-1
|
|
1797
|
+
sage: 2*u^2 + 1 in {a, -a}
|
|
1798
|
+
True
|
|
1799
|
+
sage: x = polygen(ZZ, 'x')
|
|
1800
|
+
sage: K.<a> = QQ['x'].quotient(x^2 + 5)
|
|
1801
|
+
sage: K.units(())
|
|
1802
|
+
[(-1, 2)]
|
|
1803
|
+
|
|
1804
|
+
::
|
|
1805
|
+
|
|
1806
|
+
sage: # needs sage.rings.number_field
|
|
1807
|
+
sage: K.<a> = QuadraticField(-3)
|
|
1808
|
+
sage: y = polygen(K)
|
|
1809
|
+
sage: L.<b> = K['y'].quotient(y^3 + 5); L
|
|
1810
|
+
Univariate Quotient Polynomial Ring in b over Number Field in a
|
|
1811
|
+
with defining polynomial x^2 + 3 with a = 1.732050807568878?*I
|
|
1812
|
+
with modulus y^3 + 5
|
|
1813
|
+
sage: [u for u, o in L.units() if o is Infinity]
|
|
1814
|
+
[(-1/3*a - 1)*b^2 - 4/3*a*b - 4/3*a + 3,
|
|
1815
|
+
(-1/3*a - 1)*b^2 + (2/3*a - 2)*b + 13/6*a - 1/2]
|
|
1816
|
+
sage: L.<b> = K.extension(y^3 + 5)
|
|
1817
|
+
sage: L.unit_group()
|
|
1818
|
+
Unit group with structure C6 x Z x Z of
|
|
1819
|
+
Number Field in b with defining polynomial x^3 + 5 over its base field
|
|
1820
|
+
sage: L.unit_group().gens() # abstract generators
|
|
1821
|
+
(u0, u1, u2)
|
|
1822
|
+
sage: L.unit_group().gens_values()[1:]
|
|
1823
|
+
[(-1/3*a - 1)*b^2 - 4/3*a*b - 4/3*a + 3,
|
|
1824
|
+
(-1/3*a - 1)*b^2 + (2/3*a - 2)*b + 13/6*a - 1/2]
|
|
1825
|
+
|
|
1826
|
+
Note that all the returned values live where we expect them to::
|
|
1827
|
+
|
|
1828
|
+
sage: # needs sage.rings.number_field
|
|
1829
|
+
sage: L.<b> = K['y'].quotient(y^3 + 5)
|
|
1830
|
+
sage: U = L.units()
|
|
1831
|
+
sage: type(U[0][0])
|
|
1832
|
+
<class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_field_with_category.element_class'>
|
|
1833
|
+
sage: type(U[0][1])
|
|
1834
|
+
<class 'sage.rings.integer.Integer'>
|
|
1835
|
+
sage: type(U[1][1])
|
|
1836
|
+
<class 'sage.rings.infinity.PlusInfinity'>
|
|
1837
|
+
"""
|
|
1838
|
+
return self.S_units((), proof=proof)
|
|
1839
|
+
|
|
1840
|
+
def selmer_generators(self, S, m, proof=True):
|
|
1841
|
+
r"""
|
|
1842
|
+
If ``self`` is an étale algebra `D` over a number field `K` (i.e.
|
|
1843
|
+
a quotient of `K[x]` by a squarefree polynomial) and `S` is a
|
|
1844
|
+
finite set of places of `K`, compute the Selmer group
|
|
1845
|
+
`D(S,m)`. This is the subgroup of `D^*/(D^*)^m` consisting of
|
|
1846
|
+
elements `a` such that `D(\sqrt[m]{a})/D` is unramified at all
|
|
1847
|
+
primes of `D` lying above a place outside of `S`.
|
|
1848
|
+
|
|
1849
|
+
INPUT:
|
|
1850
|
+
|
|
1851
|
+
- ``S`` -- set of primes of the coefficient ring (which is a number field)
|
|
1852
|
+
|
|
1853
|
+
- ``m`` -- positive integer
|
|
1854
|
+
|
|
1855
|
+
- ``proof`` -- if ``False``, assume the GRH in computing the class group
|
|
1856
|
+
|
|
1857
|
+
OUTPUT:
|
|
1858
|
+
|
|
1859
|
+
A list of generators of `D(S,m)`.
|
|
1860
|
+
|
|
1861
|
+
EXAMPLES::
|
|
1862
|
+
|
|
1863
|
+
sage: # needs sage.rings.number_field
|
|
1864
|
+
sage: K.<a> = QuadraticField(-5)
|
|
1865
|
+
sage: R.<x> = K[]
|
|
1866
|
+
sage: D.<T> = R.quotient(x)
|
|
1867
|
+
sage: D.selmer_generators((), 2)
|
|
1868
|
+
[-1, 2]
|
|
1869
|
+
sage: D.selmer_generators([K.ideal(2, -a + 1)], 2)
|
|
1870
|
+
[2, -1]
|
|
1871
|
+
sage: D.selmer_generators([K.ideal(2, -a + 1), K.ideal(3, a + 1)], 2)
|
|
1872
|
+
[2, a + 1, -1]
|
|
1873
|
+
sage: D.selmer_generators((K.ideal(2, -a + 1), K.ideal(3, a + 1)), 4)
|
|
1874
|
+
[2, a + 1, -1]
|
|
1875
|
+
sage: D.selmer_generators([K.ideal(2, -a + 1)], 3)
|
|
1876
|
+
[2]
|
|
1877
|
+
sage: D.selmer_generators([K.ideal(2, -a + 1), K.ideal(3, a + 1)], 3)
|
|
1878
|
+
[2, a + 1]
|
|
1879
|
+
sage: D.selmer_generators([K.ideal(2, -a + 1),
|
|
1880
|
+
....: K.ideal(3, a + 1),
|
|
1881
|
+
....: K.ideal(a)], 3)
|
|
1882
|
+
[2, a + 1, a]
|
|
1883
|
+
"""
|
|
1884
|
+
fields, isos, iso_classes = self._S_decomposition(tuple(S))
|
|
1885
|
+
n = len(fields)
|
|
1886
|
+
|
|
1887
|
+
component_selmer_groups = []
|
|
1888
|
+
for D_iso, S_iso in iso_classes:
|
|
1889
|
+
sel = D_iso.selmer_generators(S_iso, m, proof=proof)
|
|
1890
|
+
component_selmer_groups.append(sel)
|
|
1891
|
+
|
|
1892
|
+
gens = []
|
|
1893
|
+
moduli = [D.relative_polynomial() for D in fields]
|
|
1894
|
+
for i in range(n):
|
|
1895
|
+
phi = isos[i][0]
|
|
1896
|
+
back_to_rel = phi.codomain().structure()[0]
|
|
1897
|
+
|
|
1898
|
+
for gen in component_selmer_groups[isos[i][1]]:
|
|
1899
|
+
rel_gen = back_to_rel(phi(gen))
|
|
1900
|
+
prod_gen = [1]*i + [rel_gen.lift()] + [1]*(n - i - 1)
|
|
1901
|
+
poly_gen = self(crt(prod_gen, moduli))
|
|
1902
|
+
gens.append(poly_gen)
|
|
1903
|
+
|
|
1904
|
+
return gens
|
|
1905
|
+
|
|
1906
|
+
# For backwards compatibility:
|
|
1907
|
+
selmer_group = selmer_generators
|
|
1908
|
+
|
|
1909
|
+
def _factor_multivariate_polynomial(self, f, proof=True):
|
|
1910
|
+
r"""
|
|
1911
|
+
Return the factorization of ``f`` over this ring.
|
|
1912
|
+
|
|
1913
|
+
TESTS::
|
|
1914
|
+
|
|
1915
|
+
sage: # needs sage.rings.finite_rings
|
|
1916
|
+
sage: k.<a> = GF(4)
|
|
1917
|
+
sage: R.<b> = k[]
|
|
1918
|
+
sage: l.<b> = k.extension(b^2 + b + a)
|
|
1919
|
+
sage: K.<x> = FunctionField(l)
|
|
1920
|
+
sage: R.<t> = K[]
|
|
1921
|
+
sage: F = t * x
|
|
1922
|
+
sage: F.factor(proof=False) # needs sage.modules
|
|
1923
|
+
(x) * t
|
|
1924
|
+
"""
|
|
1925
|
+
from sage.structure.factorization import Factorization
|
|
1926
|
+
|
|
1927
|
+
if f.is_zero():
|
|
1928
|
+
raise ValueError("factorization of 0 not defined")
|
|
1929
|
+
|
|
1930
|
+
from_isomorphic_ring, to_isomorphic_ring, isomorphic_ring = self._isomorphic_ring()
|
|
1931
|
+
g = f.map_coefficients(to_isomorphic_ring)
|
|
1932
|
+
F = g.factor()
|
|
1933
|
+
unit = f.parent(from_isomorphic_ring(F.unit().constant_coefficient()))
|
|
1934
|
+
return Factorization([(factor.map_coefficients(from_isomorphic_ring), e) for factor,e in F], unit=unit)
|
|
1935
|
+
|
|
1936
|
+
def _factor_univariate_polynomial(self, f):
|
|
1937
|
+
r"""
|
|
1938
|
+
Return the factorization of ``f`` over this ring.
|
|
1939
|
+
|
|
1940
|
+
TESTS::
|
|
1941
|
+
|
|
1942
|
+
sage: # needs sage.rings.finite_rings
|
|
1943
|
+
sage: K = GF(2)
|
|
1944
|
+
sage: R.<x> = K[]
|
|
1945
|
+
sage: L.<x> = K.extension(x^2 + x + 1)
|
|
1946
|
+
sage: R.<y> = L[]
|
|
1947
|
+
sage: M.<y> = L.extension(y^2 + y + x)
|
|
1948
|
+
sage: R.<T> = M[]
|
|
1949
|
+
sage: R(y).factor() # indirect doctest
|
|
1950
|
+
y
|
|
1951
|
+
sage: (T^2 + T + x).factor() # indirect doctest # needs sage.modules
|
|
1952
|
+
(T + y) * (T + y + 1)
|
|
1953
|
+
sage: (y*T^2 + y*T + y*x).factor() # indirect doctest # needs sage.modules
|
|
1954
|
+
(y) * (T + y) * (T + y + 1)
|
|
1955
|
+
"""
|
|
1956
|
+
from sage.structure.factorization import Factorization
|
|
1957
|
+
|
|
1958
|
+
if f.is_zero():
|
|
1959
|
+
raise ValueError("factorization of 0 not defined")
|
|
1960
|
+
|
|
1961
|
+
unit = f.leading_coefficient()
|
|
1962
|
+
if not unit.is_unit():
|
|
1963
|
+
raise NotImplementedError("factorization of polynomials with non-unit leading coefficient")
|
|
1964
|
+
unit = f.parent()(unit)
|
|
1965
|
+
|
|
1966
|
+
f = f.monic()
|
|
1967
|
+
if f.degree() == 0:
|
|
1968
|
+
return Factorization(unit=unit)
|
|
1969
|
+
elif f.degree() == 1:
|
|
1970
|
+
return Factorization([(f,1)], unit=unit)
|
|
1971
|
+
else:
|
|
1972
|
+
from_isomorphic_ring, to_isomorphic_ring, isomorphic_ring = self._isomorphic_ring()
|
|
1973
|
+
g = f.map_coefficients(to_isomorphic_ring)
|
|
1974
|
+
F = g.factor()
|
|
1975
|
+
unit *= g.parent()(F.unit()).map_coefficients(from_isomorphic_ring)
|
|
1976
|
+
return Factorization([(factor.map_coefficients(from_isomorphic_ring), e) for factor,e in F], unit=unit)
|
|
1977
|
+
|
|
1978
|
+
@cached_method
|
|
1979
|
+
def _isomorphic_ring(self):
|
|
1980
|
+
"""
|
|
1981
|
+
Return a ring isomorphic to this ring which is not a
|
|
1982
|
+
:class:`PolynomialQuotientRing` but of a type which offers more
|
|
1983
|
+
functionality.
|
|
1984
|
+
|
|
1985
|
+
OUTPUT:
|
|
1986
|
+
|
|
1987
|
+
a triple ``from, to, ring`` consisting of an isomorphism from the
|
|
1988
|
+
isomorphic ring to this ring, the inverse of that isomorphism, and the
|
|
1989
|
+
isomorphic ring
|
|
1990
|
+
|
|
1991
|
+
EXAMPLES::
|
|
1992
|
+
|
|
1993
|
+
sage: # needs sage.modules sage.rings.finite_rings
|
|
1994
|
+
sage: K.<a> = GF(4)
|
|
1995
|
+
sage: R.<b> = K[]
|
|
1996
|
+
sage: L.<b> = K.extension(b^2 + b + a); L
|
|
1997
|
+
Univariate Quotient Polynomial Ring in b
|
|
1998
|
+
over Finite Field in a of size 2^2 with modulus b^2 + b + a
|
|
1999
|
+
sage: from_M, to_M, M = L._isomorphic_ring(); M
|
|
2000
|
+
Finite Field in z4 of size 2^4
|
|
2001
|
+
sage: R.<c> = L[]
|
|
2002
|
+
sage: M.<c> = L.extension(c^2 + b*c + b); M
|
|
2003
|
+
Univariate Quotient Polynomial Ring in c
|
|
2004
|
+
over Univariate Quotient Polynomial Ring in b
|
|
2005
|
+
over Finite Field in a of size 2^2 with modulus b^2 + b + a
|
|
2006
|
+
with modulus c^2 + b*c + b
|
|
2007
|
+
sage: from_N, to_N, N = M._isomorphic_ring(); N
|
|
2008
|
+
Finite Field in z8 of size 2^8
|
|
2009
|
+
|
|
2010
|
+
sage: R.<x> = QQ[]
|
|
2011
|
+
sage: K = R.quo(x^2 + 1)
|
|
2012
|
+
sage: from_L, to_L, L = K._isomorphic_ring() # needs sage.rings.number_field
|
|
2013
|
+
sage: L # needs sage.rings.number_field
|
|
2014
|
+
Number Field in xbar with defining polynomial x^2 + 1
|
|
2015
|
+
|
|
2016
|
+
TESTS:
|
|
2017
|
+
|
|
2018
|
+
Verify that this works for trivial extensions::
|
|
2019
|
+
|
|
2020
|
+
sage: K.<a> = GF(4) # needs sage.rings.finite_rings
|
|
2021
|
+
sage: R.<b> = K[] # needs sage.rings.finite_rings
|
|
2022
|
+
sage: from_L, to_L, L = R.quo(b)._isomorphic_ring(); L # needs sage.rings.finite_rings
|
|
2023
|
+
Finite Field in a of size 2^2
|
|
2024
|
+
"""
|
|
2025
|
+
from sage.categories.homset import Hom
|
|
2026
|
+
from sage.categories.morphism import SetMorphism
|
|
2027
|
+
|
|
2028
|
+
if isinstance(self.base_ring(), PolynomialQuotientRing_generic):
|
|
2029
|
+
# rewrite this ring over the isomorphic version of the base ring
|
|
2030
|
+
isomorphic_base_to_base, base_to_isomorphic_base, isomorphic_base = self.base_ring()._isomorphic_ring()
|
|
2031
|
+
modulus = self.modulus().map_coefficients(base_to_isomorphic_base)
|
|
2032
|
+
isomorphic_quotient = modulus.parent().quo(modulus)
|
|
2033
|
+
# we do not construct the isomorphisms yet because we want to know
|
|
2034
|
+
# the category that our final result lives in
|
|
2035
|
+
|
|
2036
|
+
# recursively try to rewrite the isomorphic_quotient
|
|
2037
|
+
isomorphic_ring_to_isomorphic_quotient, isomorphic_quotient_to_isomorphic_ring, isomorphic_ring = isomorphic_quotient._isomorphic_ring()
|
|
2038
|
+
|
|
2039
|
+
# the process has likely refined the category of
|
|
2040
|
+
# isomorphic_quotient (to Fields e.g.) so we use the same category
|
|
2041
|
+
# for self
|
|
2042
|
+
self._refine_category_(isomorphic_quotient.category())
|
|
2043
|
+
|
|
2044
|
+
homspace = Hom(isomorphic_quotient, self)
|
|
2045
|
+
from_isomorphic_quotient = homspace.__make_element_class__(SetMorphism)(homspace,
|
|
2046
|
+
lambda f: f.lift().map_coefficients(isomorphic_base_to_base)(self.gen()))
|
|
2047
|
+
|
|
2048
|
+
homspace = Hom(self, isomorphic_quotient)
|
|
2049
|
+
to_isomorphic_quotient = homspace.__make_element_class__(SetMorphism)(homspace,
|
|
2050
|
+
lambda f: f.lift().map_coefficients(base_to_isomorphic_base)(isomorphic_quotient.gen()))
|
|
2051
|
+
|
|
2052
|
+
return (from_isomorphic_quotient * isomorphic_ring_to_isomorphic_quotient,
|
|
2053
|
+
isomorphic_quotient_to_isomorphic_ring * to_isomorphic_quotient,
|
|
2054
|
+
isomorphic_ring)
|
|
2055
|
+
|
|
2056
|
+
if self.modulus().degree() == 1:
|
|
2057
|
+
# this quotient is a trivial extension of the base ring, we can just
|
|
2058
|
+
# return the base ring
|
|
2059
|
+
isomorphic_ring = self.base_ring()
|
|
2060
|
+
|
|
2061
|
+
# With this knowledge we can refine the category of self (and of the resulting morphisms.)
|
|
2062
|
+
# However, we cannot just refine self to
|
|
2063
|
+
# isomorphic_ring.category() because that category might expect an
|
|
2064
|
+
# interface which we cannot provide (e.g. NumberFields).
|
|
2065
|
+
# So we just check some important special cases here (note that
|
|
2066
|
+
# integral domains is already handled elsewhere.)
|
|
2067
|
+
from sage.categories.fields import Fields
|
|
2068
|
+
if isomorphic_ring in Fields():
|
|
2069
|
+
self._refine_category_(Fields())
|
|
2070
|
+
|
|
2071
|
+
from_isomorphic_ring = isomorphic_ring.hom(self)
|
|
2072
|
+
|
|
2073
|
+
homspace = Hom(self, isomorphic_ring)
|
|
2074
|
+
to_isomorphic_ring = homspace.__make_element_class__(SetMorphism)(homspace, lambda f: isomorphic_ring(f.lift()))
|
|
2075
|
+
return from_isomorphic_ring, to_isomorphic_ring, isomorphic_ring
|
|
2076
|
+
|
|
2077
|
+
if self.is_finite() and self.is_field():
|
|
2078
|
+
# for a finite field, we return the isomorphic simple extensions of
|
|
2079
|
+
# the underlying prime field
|
|
2080
|
+
N = self.cardinality()
|
|
2081
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
2082
|
+
isomorphic_ring = GF(N)
|
|
2083
|
+
|
|
2084
|
+
# the map to GF(N) maps our generator to a root of our modulus in the isomorphic_ring
|
|
2085
|
+
base_image = self.base_ring().modulus().change_ring(isomorphic_ring).any_root()
|
|
2086
|
+
base_to_isomorphic_ring = self.base_ring().hom([isomorphic_ring(base_image)])
|
|
2087
|
+
modulus = self.modulus().map_coefficients(base_to_isomorphic_ring)
|
|
2088
|
+
gen = modulus.any_root(assume_squarefree=True, degree=1, assume_equal_deg=True)
|
|
2089
|
+
|
|
2090
|
+
homspace = Hom(self, isomorphic_ring)
|
|
2091
|
+
to_isomorphic_ring = homspace.__make_element_class__(SetMorphism)(homspace,
|
|
2092
|
+
lambda f: f.lift().map_coefficients(base_to_isomorphic_ring)(gen))
|
|
2093
|
+
|
|
2094
|
+
# For the map from GF(N) we need to figure out where the primitive
|
|
2095
|
+
# element of GF(N) goes. We write down a basis of self over GF(p),
|
|
2096
|
+
# send it to isomorphic_ring, and solve the linear equation which
|
|
2097
|
+
# writes the primitive element of GF(N) as a linear combination of
|
|
2098
|
+
# that basis.
|
|
2099
|
+
basis = [self.gen()**i*self.base_ring().gen()**j
|
|
2100
|
+
for i in range(self.degree())
|
|
2101
|
+
for j in range(self.base_ring().degree())]
|
|
2102
|
+
assert (len(basis) == isomorphic_ring.degree())
|
|
2103
|
+
from sage.matrix.constructor import matrix
|
|
2104
|
+
A = matrix([to_isomorphic_ring(b)._vector_() for b in basis])
|
|
2105
|
+
assert (A.is_square())
|
|
2106
|
+
# solve x*A = (0,1,0,…,0)
|
|
2107
|
+
x = A.solve_left(A.column_space().basis()[1])
|
|
2108
|
+
primitive_element = sum(c*b for c,b in zip(x.list(), basis))
|
|
2109
|
+
from_isomorphic_ring = isomorphic_ring.hom([primitive_element], check=False)
|
|
2110
|
+
|
|
2111
|
+
return from_isomorphic_ring, to_isomorphic_ring, isomorphic_ring
|
|
2112
|
+
|
|
2113
|
+
from sage.categories.number_fields import NumberFields
|
|
2114
|
+
if self.base_ring() in NumberFields():
|
|
2115
|
+
try:
|
|
2116
|
+
isomorphic_ring = self.base_ring().extension(self.modulus(), names=self.variable_names())
|
|
2117
|
+
except ValueError:
|
|
2118
|
+
pass # modulus is not irreducible
|
|
2119
|
+
else:
|
|
2120
|
+
if isomorphic_ring not in NumberFields():
|
|
2121
|
+
raise NotImplementedError("cannot handle extensions of number fields that do not produce number fields")
|
|
2122
|
+
# refine the category of self
|
|
2123
|
+
if not self.is_field():
|
|
2124
|
+
assert False, "self is isomorphic to a field"
|
|
2125
|
+
|
|
2126
|
+
from_isomorphic_ring = isomorphic_ring.hom([self.gen()])
|
|
2127
|
+
to_isomorphic_ring = self.hom([isomorphic_ring.gen()])
|
|
2128
|
+
return from_isomorphic_ring, to_isomorphic_ring, isomorphic_ring
|
|
2129
|
+
|
|
2130
|
+
raise NotImplementedError("cannot rewrite %r as an isomorphic ring" % (self,))
|
|
2131
|
+
|
|
2132
|
+
def _test_isomorphic_ring(self, **options):
|
|
2133
|
+
r"""
|
|
2134
|
+
Check that :meth:`_isomorphic_ring` works correctly.
|
|
2135
|
+
|
|
2136
|
+
TESTS::
|
|
2137
|
+
|
|
2138
|
+
sage: # needs sage.modules sage.rings.finite_rings
|
|
2139
|
+
sage: K.<a> = GF(4)
|
|
2140
|
+
sage: R.<b> = K[]
|
|
2141
|
+
sage: L.<b> = K.extension(b^2 + b + a)
|
|
2142
|
+
sage: L._test_isomorphic_ring()
|
|
2143
|
+
sage: R.<c> = L[]
|
|
2144
|
+
sage: M.<c> = L.extension(c^2 + b*c + b)
|
|
2145
|
+
sage: M._test_isomorphic_ring()
|
|
2146
|
+
"""
|
|
2147
|
+
tester = self._tester(**options)
|
|
2148
|
+
|
|
2149
|
+
try:
|
|
2150
|
+
from_isomorphic_ring, to_isomorphic_ring, ring = self._isomorphic_ring()
|
|
2151
|
+
except NotImplementedError:
|
|
2152
|
+
return
|
|
2153
|
+
|
|
2154
|
+
tester.assertNotIsInstance(ring, PolynomialQuotientRing_generic)
|
|
2155
|
+
|
|
2156
|
+
from sage.categories.fields import Fields
|
|
2157
|
+
from sage.categories.integral_domains import IntegralDomains
|
|
2158
|
+
if ring.category().is_subcategory(IntegralDomains()):
|
|
2159
|
+
category = IntegralDomains()
|
|
2160
|
+
if ring.category().is_subcategory(Fields()):
|
|
2161
|
+
category = Fields()
|
|
2162
|
+
tester.assertTrue(self.category().is_subcategory(category))
|
|
2163
|
+
tester.assertTrue(from_isomorphic_ring.category_for().is_subcategory(category))
|
|
2164
|
+
tester.assertTrue(to_isomorphic_ring.category_for().is_subcategory(category))
|
|
2165
|
+
|
|
2166
|
+
for x in tester.some_elements():
|
|
2167
|
+
y = to_isomorphic_ring(x)
|
|
2168
|
+
tester.assertIn(y, ring)
|
|
2169
|
+
tester.assertEqual(from_isomorphic_ring(y), x)
|
|
2170
|
+
|
|
2171
|
+
|
|
2172
|
+
class PolynomialQuotientRing_coercion(DefaultConvertMap_unique):
|
|
2173
|
+
r"""
|
|
2174
|
+
A coercion map from a :class:`PolynomialQuotientRing` to a
|
|
2175
|
+
:class:`PolynomialQuotientRing` that restricts to the coercion map on the
|
|
2176
|
+
underlying ring of constants.
|
|
2177
|
+
|
|
2178
|
+
EXAMPLES::
|
|
2179
|
+
|
|
2180
|
+
sage: R.<x> = ZZ[]
|
|
2181
|
+
sage: S.<x> = QQ[]
|
|
2182
|
+
sage: f = S.quo(x^2 + 1).coerce_map_from(R.quo(x^2 + 1)); f
|
|
2183
|
+
Coercion map:
|
|
2184
|
+
From: Univariate Quotient Polynomial Ring in xbar over Integer Ring
|
|
2185
|
+
with modulus x^2 + 1
|
|
2186
|
+
To: Univariate Quotient Polynomial Ring in xbar over Rational Field
|
|
2187
|
+
with modulus x^2 + 1
|
|
2188
|
+
|
|
2189
|
+
TESTS::
|
|
2190
|
+
|
|
2191
|
+
sage: from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_coercion
|
|
2192
|
+
sage: isinstance(f, PolynomialQuotientRing_coercion)
|
|
2193
|
+
True
|
|
2194
|
+
sage: TestSuite(f).run(skip=['_test_pickling'])
|
|
2195
|
+
|
|
2196
|
+
Pickling works::
|
|
2197
|
+
|
|
2198
|
+
sage: g = loads(dumps(f)); g
|
|
2199
|
+
Coercion map:
|
|
2200
|
+
From: Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1
|
|
2201
|
+
To: Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 + 1
|
|
2202
|
+
sage: f == g
|
|
2203
|
+
True
|
|
2204
|
+
"""
|
|
2205
|
+
def is_injective(self):
|
|
2206
|
+
r"""
|
|
2207
|
+
Return whether this coercion is injective.
|
|
2208
|
+
|
|
2209
|
+
EXAMPLES:
|
|
2210
|
+
|
|
2211
|
+
If the modulus of the domain and the codomain is the same and the
|
|
2212
|
+
leading coefficient is a unit in the domain, then the map is injective
|
|
2213
|
+
if the underlying map on the constants is::
|
|
2214
|
+
|
|
2215
|
+
sage: R.<x> = ZZ[]
|
|
2216
|
+
sage: S.<x> = QQ[]
|
|
2217
|
+
sage: f = S.quo(x^2 + 1).coerce_map_from(R.quo(x^2 + 1))
|
|
2218
|
+
sage: f.is_injective()
|
|
2219
|
+
True
|
|
2220
|
+
"""
|
|
2221
|
+
if (self.domain().modulus().change_ring(self.codomain().base_ring()) == self.codomain().modulus()
|
|
2222
|
+
and self.domain().modulus().leading_coefficient().is_unit()):
|
|
2223
|
+
if self.codomain().base_ring().coerce_map_from(self.domain().base_ring()).is_injective():
|
|
2224
|
+
return True
|
|
2225
|
+
else:
|
|
2226
|
+
return self.domain().modulus().degree() == 0 # domain and codomain are the zero ring
|
|
2227
|
+
return super().is_injective()
|
|
2228
|
+
|
|
2229
|
+
def is_surjective(self):
|
|
2230
|
+
r"""
|
|
2231
|
+
Return whether this coercion is surjective.
|
|
2232
|
+
|
|
2233
|
+
EXAMPLES:
|
|
2234
|
+
|
|
2235
|
+
If the underlying map on constants is surjective, then this coercion is
|
|
2236
|
+
surjective since the modulus of the codomain divides the modulus of the
|
|
2237
|
+
domain::
|
|
2238
|
+
|
|
2239
|
+
sage: R.<x> = ZZ[]
|
|
2240
|
+
sage: f = R.quo(x).coerce_map_from(R.quo(x^2))
|
|
2241
|
+
sage: f.is_surjective()
|
|
2242
|
+
True
|
|
2243
|
+
|
|
2244
|
+
If the modulus of the domain and the codomain is the same, then the map
|
|
2245
|
+
is surjective iff the underlying map on the constants is::
|
|
2246
|
+
|
|
2247
|
+
sage: # needs sage.rings.padics
|
|
2248
|
+
sage: A.<a> = ZqCA(9)
|
|
2249
|
+
sage: R.<x> = A[]
|
|
2250
|
+
sage: S.<x> = A.fraction_field()[]
|
|
2251
|
+
sage: f = S.quo(x^2 + 2).coerce_map_from(R.quo(x^2 + 2))
|
|
2252
|
+
sage: f.is_surjective()
|
|
2253
|
+
False
|
|
2254
|
+
"""
|
|
2255
|
+
constant_map_is_surjective = self.codomain().base_ring().coerce_map_from(self.domain().base_ring()).is_surjective()
|
|
2256
|
+
if constant_map_is_surjective:
|
|
2257
|
+
return True
|
|
2258
|
+
if self.domain().modulus().change_ring(self.codomain().base_ring()) == self.codomain().modulus():
|
|
2259
|
+
return constant_map_is_surjective
|
|
2260
|
+
return super().is_surjective()
|
|
2261
|
+
|
|
2262
|
+
def _richcmp_(self, other, op):
|
|
2263
|
+
r"""
|
|
2264
|
+
Compare this morphism to ``other``.
|
|
2265
|
+
|
|
2266
|
+
EXAMPLES::
|
|
2267
|
+
|
|
2268
|
+
sage: R.<x> = ZZ[]
|
|
2269
|
+
sage: S.<x> = ZZ[]
|
|
2270
|
+
sage: f = S.quo(x).coerce_map_from(R.quo(x^2))
|
|
2271
|
+
sage: g = S.quo(x).coerce_map_from(R.quo(x^3))
|
|
2272
|
+
sage: f == g
|
|
2273
|
+
False
|
|
2274
|
+
sage: f == f
|
|
2275
|
+
True
|
|
2276
|
+
"""
|
|
2277
|
+
if type(self) is not type(other):
|
|
2278
|
+
return NotImplemented
|
|
2279
|
+
return richcmp(self.parent(), other.parent(), op)
|
|
2280
|
+
|
|
2281
|
+
|
|
2282
|
+
class PolynomialQuotientRing_domain(PolynomialQuotientRing_generic, CommutativeRing):
|
|
2283
|
+
"""
|
|
2284
|
+
EXAMPLES::
|
|
2285
|
+
|
|
2286
|
+
sage: R.<x> = PolynomialRing(ZZ)
|
|
2287
|
+
sage: S.<xbar> = R.quotient(x^2 + 1)
|
|
2288
|
+
sage: S
|
|
2289
|
+
Univariate Quotient Polynomial Ring in xbar
|
|
2290
|
+
over Integer Ring with modulus x^2 + 1
|
|
2291
|
+
sage: loads(S.dumps()) == S
|
|
2292
|
+
True
|
|
2293
|
+
sage: loads(xbar.dumps()) == xbar
|
|
2294
|
+
True
|
|
2295
|
+
"""
|
|
2296
|
+
def __init__(self, ring, polynomial, name=None, category=None):
|
|
2297
|
+
r"""
|
|
2298
|
+
Initialize ``self``.
|
|
2299
|
+
|
|
2300
|
+
TESTS::
|
|
2301
|
+
|
|
2302
|
+
sage: R.<x> = PolynomialRing(ZZ)
|
|
2303
|
+
sage: S.<xbar> = R.quotient(x^2 + 1)
|
|
2304
|
+
sage: TestSuite(S).run()
|
|
2305
|
+
|
|
2306
|
+
Check that :issue:`17450` is fixed::
|
|
2307
|
+
|
|
2308
|
+
sage: S in IntegralDomains()
|
|
2309
|
+
True
|
|
2310
|
+
|
|
2311
|
+
Check that :issue:`29017` is fixed::
|
|
2312
|
+
|
|
2313
|
+
sage: R.<x> = ZZ[]
|
|
2314
|
+
sage: Q = R.quo(x - 1)
|
|
2315
|
+
sage: H = R.Hom(Q)
|
|
2316
|
+
sage: h = R.hom(Q)
|
|
2317
|
+
sage: h.parent() is H
|
|
2318
|
+
True
|
|
2319
|
+
"""
|
|
2320
|
+
category = CommutativeAlgebras(ring.base_ring().category()).Quotients().NoZeroDivisors().or_subcategory(category)
|
|
2321
|
+
PolynomialQuotientRing_generic.__init__(self, ring, polynomial, name, category)
|
|
2322
|
+
|
|
2323
|
+
def field_extension(self, names):
|
|
2324
|
+
r"""
|
|
2325
|
+
Take a polynomial quotient ring, and return a tuple with three
|
|
2326
|
+
elements: the :class:`NumberField` defined by the same polynomial quotient
|
|
2327
|
+
ring, a homomorphism from its parent to the :class:`NumberField` sending the
|
|
2328
|
+
generators to one another, and the inverse isomorphism.
|
|
2329
|
+
|
|
2330
|
+
OUTPUT:
|
|
2331
|
+
|
|
2332
|
+
- field
|
|
2333
|
+
|
|
2334
|
+
- homomorphism from ``self`` to field
|
|
2335
|
+
|
|
2336
|
+
- homomorphism from field to ``self``
|
|
2337
|
+
|
|
2338
|
+
EXAMPLES::
|
|
2339
|
+
|
|
2340
|
+
sage: # needs sage.rings.number_field
|
|
2341
|
+
sage: R.<x> = PolynomialRing(Rationals())
|
|
2342
|
+
sage: S.<alpha> = R.quotient(x^3 - 2)
|
|
2343
|
+
sage: F.<b>, f, g = S.field_extension()
|
|
2344
|
+
sage: F
|
|
2345
|
+
Number Field in b with defining polynomial x^3 - 2
|
|
2346
|
+
sage: a = F.gen()
|
|
2347
|
+
sage: f(alpha)
|
|
2348
|
+
b
|
|
2349
|
+
sage: g(a)
|
|
2350
|
+
alpha
|
|
2351
|
+
|
|
2352
|
+
Note that the parent ring must be an integral domain::
|
|
2353
|
+
|
|
2354
|
+
sage: R.<x> = GF(25, 'f25')['x'] # needs sage.rings.finite_rings
|
|
2355
|
+
sage: S.<a> = R.quo(x^3 - 2) # needs sage.rings.finite_rings
|
|
2356
|
+
sage: F, g, h = S.field_extension('b') # needs sage.rings.finite_rings
|
|
2357
|
+
Traceback (most recent call last):
|
|
2358
|
+
...
|
|
2359
|
+
AttributeError: 'PolynomialQuotientRing_generic_with_category' object has no attribute 'field_extension'...
|
|
2360
|
+
|
|
2361
|
+
Over a finite field, the corresponding field extension is not a
|
|
2362
|
+
number field::
|
|
2363
|
+
|
|
2364
|
+
sage: # needs sage.modules sage.rings.finite_rings sage.rings.number_field
|
|
2365
|
+
sage: R.<x> = GF(25, 'a')['x']
|
|
2366
|
+
sage: S.<a> = R.quo(x^3 + 2*x + 1)
|
|
2367
|
+
sage: F, g, h = S.field_extension('b')
|
|
2368
|
+
sage: h(F.0^2 + 3)
|
|
2369
|
+
a^2 + 3
|
|
2370
|
+
sage: g(x^2 + 2)
|
|
2371
|
+
b^2 + 2
|
|
2372
|
+
|
|
2373
|
+
We do an example involving a relative number field::
|
|
2374
|
+
|
|
2375
|
+
sage: # needs sage.rings.number_field
|
|
2376
|
+
sage: R.<x> = QQ['x']
|
|
2377
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
2378
|
+
sage: S.<X> = K['X']
|
|
2379
|
+
sage: Q.<b> = S.quo(X^3 + 2*X + 1)
|
|
2380
|
+
sage: Q.field_extension('b')
|
|
2381
|
+
(Number Field in b with defining polynomial X^3 + 2*X + 1 over its base field, ...
|
|
2382
|
+
Defn: b |--> b, Relative number field morphism:
|
|
2383
|
+
From: Number Field in b with defining polynomial X^3 + 2*X + 1 over its base field
|
|
2384
|
+
To: Univariate Quotient Polynomial Ring in b over Number Field in a with defining polynomial x^3 - 2 with modulus X^3 + 2*X + 1
|
|
2385
|
+
Defn: b |--> b
|
|
2386
|
+
a |--> a)
|
|
2387
|
+
|
|
2388
|
+
We slightly change the example above so it works.
|
|
2389
|
+
|
|
2390
|
+
::
|
|
2391
|
+
|
|
2392
|
+
sage: # needs sage.rings.number_field
|
|
2393
|
+
sage: R.<x> = QQ['x']
|
|
2394
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
2395
|
+
sage: S.<X> = K['X']
|
|
2396
|
+
sage: f = (X+a)^3 + 2*(X+a) + 1
|
|
2397
|
+
sage: f
|
|
2398
|
+
X^3 + 3*a*X^2 + (3*a^2 + 2)*X + 2*a + 3
|
|
2399
|
+
sage: Q.<z> = S.quo(f)
|
|
2400
|
+
sage: F.<w>, g, h = Q.field_extension()
|
|
2401
|
+
sage: c = g(z)
|
|
2402
|
+
sage: f(c)
|
|
2403
|
+
0
|
|
2404
|
+
sage: h(g(z))
|
|
2405
|
+
z
|
|
2406
|
+
sage: g(h(w))
|
|
2407
|
+
w
|
|
2408
|
+
|
|
2409
|
+
AUTHORS:
|
|
2410
|
+
|
|
2411
|
+
- Craig Citro (2006-08-07)
|
|
2412
|
+
|
|
2413
|
+
- William Stein (2006-08-06)
|
|
2414
|
+
"""
|
|
2415
|
+
|
|
2416
|
+
return self.gen().field_extension(names)
|
|
2417
|
+
|
|
2418
|
+
|
|
2419
|
+
class PolynomialQuotientRing_field(PolynomialQuotientRing_domain, Field):
|
|
2420
|
+
"""
|
|
2421
|
+
EXAMPLES::
|
|
2422
|
+
|
|
2423
|
+
sage: # needs sage.rings.number_field
|
|
2424
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
2425
|
+
sage: S.<xbar> = R.quotient(x^2 + 1)
|
|
2426
|
+
sage: S
|
|
2427
|
+
Univariate Quotient Polynomial Ring in xbar over Rational Field
|
|
2428
|
+
with modulus x^2 + 1
|
|
2429
|
+
sage: loads(S.dumps()) == S
|
|
2430
|
+
True
|
|
2431
|
+
sage: loads(xbar.dumps()) == xbar
|
|
2432
|
+
True
|
|
2433
|
+
"""
|
|
2434
|
+
def __init__(self, ring, polynomial, name=None, category=None):
|
|
2435
|
+
PolynomialQuotientRing_domain.__init__(self, ring, polynomial, name, category)
|
|
2436
|
+
|
|
2437
|
+
def base_field(self):
|
|
2438
|
+
r"""
|
|
2439
|
+
Alias for :meth:`base_ring`, when we're defined over a field.
|
|
2440
|
+
"""
|
|
2441
|
+
return self.base_ring()
|
|
2442
|
+
|
|
2443
|
+
def complex_embeddings(self, prec=53):
|
|
2444
|
+
r"""
|
|
2445
|
+
Return all homomorphisms of this ring into the approximate complex
|
|
2446
|
+
field with precision ``prec``.
|
|
2447
|
+
|
|
2448
|
+
EXAMPLES::
|
|
2449
|
+
|
|
2450
|
+
sage: # needs sage.rings.number_field
|
|
2451
|
+
sage: R.<x> = QQ[]
|
|
2452
|
+
sage: f = x^5 + x + 17
|
|
2453
|
+
sage: k = R.quotient(f)
|
|
2454
|
+
sage: v = k.complex_embeddings(100)
|
|
2455
|
+
sage: [phi(k.0^2) for phi in v]
|
|
2456
|
+
[2.9757207403766761469671194565,
|
|
2457
|
+
-2.4088994371613850098316292196 + 1.9025410530350528612407363802*I,
|
|
2458
|
+
-2.4088994371613850098316292196 - 1.9025410530350528612407363802*I,
|
|
2459
|
+
0.92103906697304693634806949137 - 3.0755331188457794473265418086*I,
|
|
2460
|
+
0.92103906697304693634806949137 + 3.0755331188457794473265418086*I]
|
|
2461
|
+
"""
|
|
2462
|
+
from sage.rings.complex_mpfr import ComplexField
|
|
2463
|
+
CC = ComplexField(prec)
|
|
2464
|
+
v = self.modulus().roots(multiplicities=False, ring=CC)
|
|
2465
|
+
return [self.hom([a], check=False) for a in v]
|