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,2044 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
r"""
|
|
3
|
+
Ring `\ZZ/n\ZZ` of integers modulo `n`
|
|
4
|
+
|
|
5
|
+
EXAMPLES::
|
|
6
|
+
|
|
7
|
+
sage: R = Integers(97)
|
|
8
|
+
sage: a = R(5)
|
|
9
|
+
sage: a**100000000000000000000000000000000000000000000000000000000000000
|
|
10
|
+
61
|
|
11
|
+
|
|
12
|
+
This example illustrates the relation between
|
|
13
|
+
`\ZZ/p\ZZ` and `\GF{p}`. In
|
|
14
|
+
particular, there is a canonical map to `\GF{p}`, but not in
|
|
15
|
+
the other direction.
|
|
16
|
+
|
|
17
|
+
::
|
|
18
|
+
|
|
19
|
+
sage: r = Integers(7)
|
|
20
|
+
sage: s = GF(7)
|
|
21
|
+
sage: r.has_coerce_map_from(s)
|
|
22
|
+
False
|
|
23
|
+
sage: s.has_coerce_map_from(r)
|
|
24
|
+
True
|
|
25
|
+
sage: s(1) + r(1)
|
|
26
|
+
2
|
|
27
|
+
sage: parent(s(1) + r(1))
|
|
28
|
+
Finite Field of size 7
|
|
29
|
+
sage: parent(r(1) + s(1))
|
|
30
|
+
Finite Field of size 7
|
|
31
|
+
|
|
32
|
+
We list the elements of `\ZZ/3\ZZ`::
|
|
33
|
+
|
|
34
|
+
sage: R = Integers(3)
|
|
35
|
+
sage: list(R)
|
|
36
|
+
[0, 1, 2]
|
|
37
|
+
|
|
38
|
+
AUTHORS:
|
|
39
|
+
|
|
40
|
+
- William Stein (initial code)
|
|
41
|
+
|
|
42
|
+
- David Joyner (2005-12-22): most examples
|
|
43
|
+
|
|
44
|
+
- Robert Bradshaw (2006-08-24): convert to SageX (Cython)
|
|
45
|
+
|
|
46
|
+
- William Stein (2007-04-29): square_roots_of_one
|
|
47
|
+
|
|
48
|
+
- Simon King (2011-04-21): allow to prescribe a category
|
|
49
|
+
|
|
50
|
+
- Simon King (2013-09): Only allow to prescribe the category of fields
|
|
51
|
+
|
|
52
|
+
- Kyle Hofmann (2024-02): New implementation of root-finding
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
# ****************************************************************************
|
|
56
|
+
# Copyright (C) 2005 William Stein <wstein@gmail.com>
|
|
57
|
+
#
|
|
58
|
+
# This program is free software: you can redistribute it and/or modify
|
|
59
|
+
# it under the terms of the GNU General Public License as published by
|
|
60
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
61
|
+
# (at your option) any later version.
|
|
62
|
+
# https://www.gnu.org/licenses/
|
|
63
|
+
# ****************************************************************************
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
import sage.misc.prandom as random
|
|
67
|
+
|
|
68
|
+
from sage.arith.misc import factor
|
|
69
|
+
from sage.arith.misc import primitive_root
|
|
70
|
+
from sage.arith.misc import CRT_basis
|
|
71
|
+
from sage.rings.ring import Field
|
|
72
|
+
from sage.misc.mrange import cartesian_product_iterator
|
|
73
|
+
import sage.rings.abc
|
|
74
|
+
from sage.rings.finite_rings import integer_mod
|
|
75
|
+
import sage.rings.integer as integer
|
|
76
|
+
import sage.rings.integer_ring as integer_ring
|
|
77
|
+
import sage.rings.quotient_ring as quotient_ring
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
from sage.libs.pari import pari
|
|
81
|
+
from cypari2.handle_error import PariError
|
|
82
|
+
except ImportError:
|
|
83
|
+
class PariError(Exception):
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
from sage.misc.cachefunc import cached_method
|
|
87
|
+
|
|
88
|
+
from sage.structure.factory import UniqueFactory
|
|
89
|
+
from sage.structure.richcmp import richcmp, richcmp_method
|
|
90
|
+
|
|
91
|
+
from sage.interfaces.abc import GapElement
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class IntegerModFactory(UniqueFactory):
|
|
95
|
+
r"""
|
|
96
|
+
Return the quotient ring `\ZZ / n\ZZ`.
|
|
97
|
+
|
|
98
|
+
INPUT:
|
|
99
|
+
|
|
100
|
+
- ``order`` -- integer (default: 0); positive or negative
|
|
101
|
+
- ``is_field`` -- boolean (default: ``False``); assert that the order is
|
|
102
|
+
prime and hence the quotient ring belongs to the category of fields
|
|
103
|
+
- ``category`` -- (optional) the category that the quotient ring belongs to
|
|
104
|
+
|
|
105
|
+
.. NOTE::
|
|
106
|
+
|
|
107
|
+
The optional argument ``is_field`` is not part of the cache key.
|
|
108
|
+
Hence, this factory will create precisely one instance of `\ZZ /
|
|
109
|
+
n\ZZ`. However, if ``is_field`` is true, then a previously created
|
|
110
|
+
instance of the quotient ring will be updated to be in the category of
|
|
111
|
+
fields.
|
|
112
|
+
|
|
113
|
+
**Use with care!** Erroneously putting `\ZZ / n\ZZ` into the category
|
|
114
|
+
of fields may have consequences that can compromise a whole Sage
|
|
115
|
+
session, so that a restart will be needed.
|
|
116
|
+
|
|
117
|
+
EXAMPLES::
|
|
118
|
+
|
|
119
|
+
sage: IntegerModRing(15)
|
|
120
|
+
Ring of integers modulo 15
|
|
121
|
+
sage: IntegerModRing(7)
|
|
122
|
+
Ring of integers modulo 7
|
|
123
|
+
sage: IntegerModRing(-100)
|
|
124
|
+
Ring of integers modulo 100
|
|
125
|
+
|
|
126
|
+
Note that you can also use ``Integers``, which is a
|
|
127
|
+
synonym for ``IntegerModRing``.
|
|
128
|
+
|
|
129
|
+
::
|
|
130
|
+
|
|
131
|
+
sage: Integers(18)
|
|
132
|
+
Ring of integers modulo 18
|
|
133
|
+
sage: Integers() is Integers(0) is ZZ
|
|
134
|
+
True
|
|
135
|
+
|
|
136
|
+
.. NOTE::
|
|
137
|
+
|
|
138
|
+
Testing whether a quotient ring `\ZZ / n\ZZ` is a field can of
|
|
139
|
+
course be very costly. By default, it is not tested whether `n`
|
|
140
|
+
is prime or not, in contrast to
|
|
141
|
+
:func:`~sage.rings.finite_rings.finite_field_constructor.GF`. If the user
|
|
142
|
+
is sure that the modulus is prime and wants to avoid a primality
|
|
143
|
+
test, (s)he can provide ``category=Fields()`` when constructing
|
|
144
|
+
the quotient ring, and then the result will behave like a field.
|
|
145
|
+
If the category is not provided during initialisation, and it is
|
|
146
|
+
found out later that the ring is in fact a field, then the category
|
|
147
|
+
will be changed at runtime, having the same effect as providing
|
|
148
|
+
``Fields()`` during initialisation.
|
|
149
|
+
|
|
150
|
+
EXAMPLES::
|
|
151
|
+
|
|
152
|
+
sage: R = IntegerModRing(5)
|
|
153
|
+
sage: R.category()
|
|
154
|
+
Join of Category of finite commutative rings
|
|
155
|
+
and Category of subquotients of monoids
|
|
156
|
+
and Category of quotients of semigroups
|
|
157
|
+
and Category of finite enumerated sets
|
|
158
|
+
sage: R in Fields()
|
|
159
|
+
True
|
|
160
|
+
sage: R.category()
|
|
161
|
+
Join of Category of finite enumerated fields
|
|
162
|
+
and Category of subquotients of monoids
|
|
163
|
+
and Category of quotients of semigroups
|
|
164
|
+
sage: S = IntegerModRing(5, is_field=True)
|
|
165
|
+
sage: S is R
|
|
166
|
+
True
|
|
167
|
+
|
|
168
|
+
.. WARNING::
|
|
169
|
+
|
|
170
|
+
If the optional argument ``is_field`` was used by mistake, there is
|
|
171
|
+
currently no way to revert its impact, even though
|
|
172
|
+
:meth:`IntegerModRing_generic.is_field` with the optional argument
|
|
173
|
+
``proof=True`` would return the correct answer. So, prescribe
|
|
174
|
+
``is_field=True`` only if you know what your are doing!
|
|
175
|
+
|
|
176
|
+
EXAMPLES::
|
|
177
|
+
|
|
178
|
+
sage: R = IntegerModRing(33, is_field=True)
|
|
179
|
+
sage: R in Fields()
|
|
180
|
+
True
|
|
181
|
+
sage: R.is_field()
|
|
182
|
+
True
|
|
183
|
+
|
|
184
|
+
If the optional argument `proof=True` is provided, primality is tested and
|
|
185
|
+
the mistaken category assignment is reported::
|
|
186
|
+
|
|
187
|
+
sage: R.is_field(proof=True)
|
|
188
|
+
Traceback (most recent call last):
|
|
189
|
+
...
|
|
190
|
+
ValueError: THIS SAGE SESSION MIGHT BE SERIOUSLY COMPROMISED!
|
|
191
|
+
The order 33 is not prime, but this ring has been put
|
|
192
|
+
into the category of fields. This may already have consequences
|
|
193
|
+
in other parts of Sage. Either it was a mistake of the user,
|
|
194
|
+
or a probabilistic primality test has failed.
|
|
195
|
+
In the latter case, please inform the developers.
|
|
196
|
+
|
|
197
|
+
However, the mistaken assignment is not automatically corrected::
|
|
198
|
+
|
|
199
|
+
sage: R in Fields()
|
|
200
|
+
True
|
|
201
|
+
|
|
202
|
+
To avoid side-effects of this test on other tests, we clear the cache of
|
|
203
|
+
the ring factory::
|
|
204
|
+
|
|
205
|
+
sage: IntegerModRing._cache.clear()
|
|
206
|
+
"""
|
|
207
|
+
def get_object(self, version, key, extra_args):
|
|
208
|
+
out = super().get_object(version, key, extra_args)
|
|
209
|
+
category = extra_args.get('category', None)
|
|
210
|
+
if category is not None:
|
|
211
|
+
out._refine_category_(category)
|
|
212
|
+
out._factory_data[3]['category'] = category
|
|
213
|
+
return out
|
|
214
|
+
|
|
215
|
+
def create_key_and_extra_args(self, order=0, is_field=False, category=None):
|
|
216
|
+
"""
|
|
217
|
+
An integer mod ring is specified uniquely by its order.
|
|
218
|
+
|
|
219
|
+
EXAMPLES::
|
|
220
|
+
|
|
221
|
+
sage: Zmod.create_key_and_extra_args(7)
|
|
222
|
+
(7, {})
|
|
223
|
+
sage: Zmod.create_key_and_extra_args(7, True)
|
|
224
|
+
(7, {'category': Category of fields})
|
|
225
|
+
"""
|
|
226
|
+
if is_field:
|
|
227
|
+
from sage.categories.fields import Fields
|
|
228
|
+
return order, {'category': Fields()}
|
|
229
|
+
return order, {}
|
|
230
|
+
|
|
231
|
+
def create_object(self, version, order, **kwds):
|
|
232
|
+
"""
|
|
233
|
+
EXAMPLES::
|
|
234
|
+
|
|
235
|
+
sage: R = Integers(10)
|
|
236
|
+
sage: TestSuite(R).run() # indirect doctest
|
|
237
|
+
"""
|
|
238
|
+
if isinstance(order, tuple):
|
|
239
|
+
# this is for unpickling old data
|
|
240
|
+
order, category = order
|
|
241
|
+
kwds.setdefault('category', category)
|
|
242
|
+
if order < 0:
|
|
243
|
+
order = -order
|
|
244
|
+
if order == 0:
|
|
245
|
+
return integer_ring.IntegerRing(**kwds)
|
|
246
|
+
else:
|
|
247
|
+
return IntegerModRing_generic(order, **kwds)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
Zmod = Integers = IntegerModRing = IntegerModFactory("IntegerModRing")
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
from sage.categories.noetherian_rings import NoetherianRings
|
|
254
|
+
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
|
|
255
|
+
from sage.categories.category import JoinCategory
|
|
256
|
+
default_category = JoinCategory((NoetherianRings(), FiniteEnumeratedSets()))
|
|
257
|
+
ZZ = integer_ring.IntegerRing()
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def _unit_gens_primepowercase(p, r):
|
|
261
|
+
r"""
|
|
262
|
+
Return a list of generators for `(\ZZ/p^r\ZZ)^*` and their orders.
|
|
263
|
+
|
|
264
|
+
EXAMPLES::
|
|
265
|
+
|
|
266
|
+
sage: from sage.rings.finite_rings.integer_mod_ring import _unit_gens_primepowercase
|
|
267
|
+
sage: _unit_gens_primepowercase(2, 3)
|
|
268
|
+
[(7, 2), (5, 2)]
|
|
269
|
+
sage: _unit_gens_primepowercase(17, 1) # needs sage.libs.pari
|
|
270
|
+
[(3, 16)]
|
|
271
|
+
sage: _unit_gens_primepowercase(3, 3) # needs sage.libs.pari
|
|
272
|
+
[(2, 18)]
|
|
273
|
+
"""
|
|
274
|
+
pr = p**r
|
|
275
|
+
if p == 2:
|
|
276
|
+
if r == 1:
|
|
277
|
+
return []
|
|
278
|
+
if r == 2:
|
|
279
|
+
return [(integer_mod.Mod(3, 4), integer.Integer(2))]
|
|
280
|
+
return [(integer_mod.Mod(-1, pr), integer.Integer(2)),
|
|
281
|
+
(integer_mod.Mod(5, pr), integer.Integer(2**(r - 2)))]
|
|
282
|
+
|
|
283
|
+
# odd prime
|
|
284
|
+
return [(integer_mod.Mod(primitive_root(pr, check=False), pr),
|
|
285
|
+
integer.Integer(p**(r - 1) * (p - 1)))]
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
@richcmp_method
|
|
289
|
+
class IntegerModRing_generic(quotient_ring.QuotientRing_generic, sage.rings.abc.IntegerModRing):
|
|
290
|
+
"""
|
|
291
|
+
The ring of integers modulo `N`.
|
|
292
|
+
|
|
293
|
+
INPUT:
|
|
294
|
+
|
|
295
|
+
- ``order`` -- integer
|
|
296
|
+
|
|
297
|
+
- ``category`` -- a subcategory of ``CommutativeRings()`` (the default)
|
|
298
|
+
|
|
299
|
+
OUTPUT: the ring of integers modulo `N`
|
|
300
|
+
|
|
301
|
+
EXAMPLES:
|
|
302
|
+
|
|
303
|
+
First we compute with integers modulo `29`.
|
|
304
|
+
|
|
305
|
+
::
|
|
306
|
+
|
|
307
|
+
sage: FF = IntegerModRing(29)
|
|
308
|
+
sage: FF
|
|
309
|
+
Ring of integers modulo 29
|
|
310
|
+
sage: FF.category()
|
|
311
|
+
Join of Category of finite commutative rings
|
|
312
|
+
and Category of subquotients of monoids
|
|
313
|
+
and Category of quotients of semigroups
|
|
314
|
+
and Category of finite enumerated sets
|
|
315
|
+
sage: FF.is_field()
|
|
316
|
+
True
|
|
317
|
+
sage: FF.characteristic()
|
|
318
|
+
29
|
|
319
|
+
sage: FF.order()
|
|
320
|
+
29
|
|
321
|
+
|
|
322
|
+
sage: # needs sage.groups sage.libs.pari sage.modules
|
|
323
|
+
sage: gens = FF.unit_gens()
|
|
324
|
+
sage: a = gens[0]
|
|
325
|
+
sage: a
|
|
326
|
+
2
|
|
327
|
+
sage: a.is_square()
|
|
328
|
+
False
|
|
329
|
+
sage: def pow(i): return a**i
|
|
330
|
+
sage: [pow(i) for i in range(16)]
|
|
331
|
+
[1, 2, 4, 8, 16, 3, 6, 12, 24, 19, 9, 18, 7, 14, 28, 27]
|
|
332
|
+
sage: TestSuite(FF).run()
|
|
333
|
+
|
|
334
|
+
We have seen above that an integer mod ring is, by default, not
|
|
335
|
+
initialised as an object in the category of fields. However, one
|
|
336
|
+
can force it to be. Moreover, testing containment in the category
|
|
337
|
+
of fields my re-initialise the category of the integer mod ring::
|
|
338
|
+
|
|
339
|
+
sage: F19 = IntegerModRing(19, is_field=True)
|
|
340
|
+
sage: F19.category().is_subcategory(Fields())
|
|
341
|
+
True
|
|
342
|
+
sage: F23 = IntegerModRing(23)
|
|
343
|
+
sage: F23.category().is_subcategory(Fields())
|
|
344
|
+
False
|
|
345
|
+
sage: F23 in Fields()
|
|
346
|
+
True
|
|
347
|
+
sage: F23.category().is_subcategory(Fields())
|
|
348
|
+
True
|
|
349
|
+
sage: TestSuite(F19).run()
|
|
350
|
+
sage: TestSuite(F23).run()
|
|
351
|
+
|
|
352
|
+
By :issue:`15229`, there is a unique instance of the
|
|
353
|
+
integral quotient ring of a given order. Using the
|
|
354
|
+
:func:`IntegerModRing` factory twice, and using
|
|
355
|
+
``is_field=True`` the second time, will update the
|
|
356
|
+
category of the unique instance::
|
|
357
|
+
|
|
358
|
+
sage: F31a = IntegerModRing(31)
|
|
359
|
+
sage: F31a.category().is_subcategory(Fields())
|
|
360
|
+
False
|
|
361
|
+
sage: F31b = IntegerModRing(31, is_field=True)
|
|
362
|
+
sage: F31a is F31b
|
|
363
|
+
True
|
|
364
|
+
sage: F31a.category().is_subcategory(Fields())
|
|
365
|
+
True
|
|
366
|
+
|
|
367
|
+
Next we compute with the integers modulo `16`.
|
|
368
|
+
|
|
369
|
+
::
|
|
370
|
+
|
|
371
|
+
sage: Z16 = IntegerModRing(16)
|
|
372
|
+
sage: Z16.category()
|
|
373
|
+
Join of Category of finite commutative rings
|
|
374
|
+
and Category of subquotients of monoids
|
|
375
|
+
and Category of quotients of semigroups
|
|
376
|
+
and Category of finite enumerated sets
|
|
377
|
+
sage: Z16.is_field()
|
|
378
|
+
False
|
|
379
|
+
sage: Z16.order()
|
|
380
|
+
16
|
|
381
|
+
sage: Z16.characteristic()
|
|
382
|
+
16
|
|
383
|
+
|
|
384
|
+
sage: # needs sage.groups sage.modules
|
|
385
|
+
sage: gens = Z16.unit_gens()
|
|
386
|
+
sage: gens
|
|
387
|
+
(15, 5)
|
|
388
|
+
sage: a = gens[0]
|
|
389
|
+
sage: b = gens[1]
|
|
390
|
+
sage: def powa(i): return a**i
|
|
391
|
+
sage: def powb(i): return b**i
|
|
392
|
+
sage: gp_exp = FF.unit_group_exponent()
|
|
393
|
+
sage: gp_exp
|
|
394
|
+
28
|
|
395
|
+
sage: [powa(i) for i in range(15)]
|
|
396
|
+
[1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1]
|
|
397
|
+
sage: [powb(i) for i in range(15)]
|
|
398
|
+
[1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9]
|
|
399
|
+
sage: a.multiplicative_order()
|
|
400
|
+
2
|
|
401
|
+
sage: b.multiplicative_order()
|
|
402
|
+
4
|
|
403
|
+
|
|
404
|
+
sage: TestSuite(Z16).run()
|
|
405
|
+
|
|
406
|
+
Saving and loading::
|
|
407
|
+
|
|
408
|
+
sage: R = Integers(100000)
|
|
409
|
+
sage: TestSuite(R).run() # long time (17s on sage.math, 2011)
|
|
410
|
+
|
|
411
|
+
Testing ideals and quotients::
|
|
412
|
+
|
|
413
|
+
sage: Z10 = Integers(10)
|
|
414
|
+
sage: I = Z10.principal_ideal(0)
|
|
415
|
+
sage: Z10.quotient(I) == Z10
|
|
416
|
+
True
|
|
417
|
+
sage: I = Z10.principal_ideal(2)
|
|
418
|
+
sage: Z10.quotient(I) == Z10
|
|
419
|
+
False
|
|
420
|
+
sage: I.is_prime()
|
|
421
|
+
True
|
|
422
|
+
|
|
423
|
+
::
|
|
424
|
+
|
|
425
|
+
sage: R = IntegerModRing(97)
|
|
426
|
+
sage: a = R(5)
|
|
427
|
+
sage: a**(10^62)
|
|
428
|
+
61
|
|
429
|
+
"""
|
|
430
|
+
def __init__(self, order, cache=None, category=None):
|
|
431
|
+
"""
|
|
432
|
+
Create with the command ``IntegerModRing(order)``.
|
|
433
|
+
|
|
434
|
+
TESTS::
|
|
435
|
+
|
|
436
|
+
sage: FF = IntegerModRing(29)
|
|
437
|
+
sage: TestSuite(FF).run()
|
|
438
|
+
sage: F19 = IntegerModRing(19, is_field=True)
|
|
439
|
+
sage: TestSuite(F19).run()
|
|
440
|
+
sage: F23 = IntegerModRing(23)
|
|
441
|
+
sage: F23 in Fields()
|
|
442
|
+
True
|
|
443
|
+
sage: TestSuite(F23).run()
|
|
444
|
+
sage: Z16 = IntegerModRing(16)
|
|
445
|
+
sage: TestSuite(Z16).run()
|
|
446
|
+
sage: R = Integers(100000)
|
|
447
|
+
sage: TestSuite(R).run() # long time (17s on sage.math, 2011)
|
|
448
|
+
|
|
449
|
+
sage: R = IntegerModRing(18)
|
|
450
|
+
sage: R.is_finite()
|
|
451
|
+
True
|
|
452
|
+
|
|
453
|
+
TESTS::
|
|
454
|
+
|
|
455
|
+
sage: Integers(8).is_noetherian()
|
|
456
|
+
True
|
|
457
|
+
"""
|
|
458
|
+
order = ZZ(order)
|
|
459
|
+
if order <= 0:
|
|
460
|
+
raise ZeroDivisionError("order must be positive")
|
|
461
|
+
self.__order = order
|
|
462
|
+
self._pyx_order = integer_mod.NativeIntStruct(order)
|
|
463
|
+
global default_category
|
|
464
|
+
if category is None:
|
|
465
|
+
category = default_category
|
|
466
|
+
else:
|
|
467
|
+
# If the category is given, e.g., as Fields(), then we still
|
|
468
|
+
# know that the result will also live in default_category.
|
|
469
|
+
# Hence, we use the join of the default and the given category.
|
|
470
|
+
category = category.join([category, default_category])
|
|
471
|
+
# Give the generator a 'name' to make quotients work. The
|
|
472
|
+
# name 'x' is used because it's also used for the ring of
|
|
473
|
+
# integers: see the __init__ method for IntegerRing_class in
|
|
474
|
+
# sage/rings/integer_ring.pyx.
|
|
475
|
+
quotient_ring.QuotientRing_generic.__init__(self, ZZ, ZZ.ideal(order),
|
|
476
|
+
names=('x',),
|
|
477
|
+
category=category)
|
|
478
|
+
# We want that the ring is its own base ring.
|
|
479
|
+
self._base = self
|
|
480
|
+
if cache is None:
|
|
481
|
+
cache = order < 500
|
|
482
|
+
if cache:
|
|
483
|
+
self._precompute_table()
|
|
484
|
+
self._zero_element = integer_mod.IntegerMod(self, 0)
|
|
485
|
+
self._one_element = integer_mod.IntegerMod(self, 1)
|
|
486
|
+
|
|
487
|
+
def _macaulay2_init_(self, macaulay2=None) -> str:
|
|
488
|
+
"""
|
|
489
|
+
EXAMPLES::
|
|
490
|
+
|
|
491
|
+
sage: macaulay2(Integers(7)) # optional - macaulay2
|
|
492
|
+
ZZ
|
|
493
|
+
--
|
|
494
|
+
7
|
|
495
|
+
|
|
496
|
+
::
|
|
497
|
+
|
|
498
|
+
sage: macaulay2(Integers(10)) # optional - macaulay2
|
|
499
|
+
ZZ[]
|
|
500
|
+
----
|
|
501
|
+
10
|
|
502
|
+
"""
|
|
503
|
+
return "ZZ/{}".format(self.order())
|
|
504
|
+
|
|
505
|
+
def _axiom_init_(self) -> str:
|
|
506
|
+
"""
|
|
507
|
+
Return a string representation of ``self`` in (Pan)Axiom.
|
|
508
|
+
|
|
509
|
+
EXAMPLES::
|
|
510
|
+
|
|
511
|
+
sage: Z7 = Integers(7)
|
|
512
|
+
sage: Z7._axiom_init_()
|
|
513
|
+
'IntegerMod(7)'
|
|
514
|
+
|
|
515
|
+
sage: axiom(Z7) #optional - axiom
|
|
516
|
+
IntegerMod 7
|
|
517
|
+
|
|
518
|
+
sage: fricas(Z7) #optional - fricas
|
|
519
|
+
IntegerMod(7)
|
|
520
|
+
"""
|
|
521
|
+
return 'IntegerMod({})'.format(self.order())
|
|
522
|
+
|
|
523
|
+
_fricas_init_ = _axiom_init_
|
|
524
|
+
|
|
525
|
+
def krull_dimension(self):
|
|
526
|
+
"""
|
|
527
|
+
Return the Krull dimension of ``self``.
|
|
528
|
+
|
|
529
|
+
EXAMPLES::
|
|
530
|
+
|
|
531
|
+
sage: Integers(18).krull_dimension()
|
|
532
|
+
0
|
|
533
|
+
"""
|
|
534
|
+
return integer.Integer(0)
|
|
535
|
+
|
|
536
|
+
def extension(self, poly, name=None, names=None, **kwds):
|
|
537
|
+
"""
|
|
538
|
+
Return an algebraic extension of ``self``. See
|
|
539
|
+
:meth:`sage.rings.ring.CommutativeRing.extension()` for more
|
|
540
|
+
information.
|
|
541
|
+
|
|
542
|
+
EXAMPLES::
|
|
543
|
+
|
|
544
|
+
sage: R.<t> = QQ[]
|
|
545
|
+
sage: Integers(8).extension(t^2 - 3)
|
|
546
|
+
Univariate Quotient Polynomial Ring in t
|
|
547
|
+
over Ring of integers modulo 8 with modulus t^2 + 5
|
|
548
|
+
"""
|
|
549
|
+
if self.modulus() == 1:
|
|
550
|
+
return self
|
|
551
|
+
|
|
552
|
+
from sage.rings.ring import CommutativeRing
|
|
553
|
+
return CommutativeRing.extension(self, poly, name, names, **kwds)
|
|
554
|
+
|
|
555
|
+
@cached_method
|
|
556
|
+
def is_prime_field(self) -> bool:
|
|
557
|
+
"""
|
|
558
|
+
Return ``True`` if the order is prime.
|
|
559
|
+
|
|
560
|
+
EXAMPLES::
|
|
561
|
+
|
|
562
|
+
sage: Zmod(7).is_prime_field()
|
|
563
|
+
True
|
|
564
|
+
sage: Zmod(8).is_prime_field()
|
|
565
|
+
False
|
|
566
|
+
"""
|
|
567
|
+
return self.__order.is_prime()
|
|
568
|
+
|
|
569
|
+
def _precompute_table(self) -> None:
|
|
570
|
+
"""
|
|
571
|
+
Compute a table of elements so that elements are unique.
|
|
572
|
+
|
|
573
|
+
EXAMPLES::
|
|
574
|
+
|
|
575
|
+
sage: R = Zmod(500); R._precompute_table()
|
|
576
|
+
sage: R(7) + R(13) is R(3) + R(17)
|
|
577
|
+
True
|
|
578
|
+
"""
|
|
579
|
+
self._pyx_order.precompute_table(self)
|
|
580
|
+
|
|
581
|
+
def list_of_elements_of_multiplicative_group(self) -> list:
|
|
582
|
+
"""
|
|
583
|
+
Return a list of all invertible elements, as python ints.
|
|
584
|
+
|
|
585
|
+
EXAMPLES::
|
|
586
|
+
|
|
587
|
+
sage: R = Zmod(12)
|
|
588
|
+
sage: L = R.list_of_elements_of_multiplicative_group(); L
|
|
589
|
+
[1, 5, 7, 11]
|
|
590
|
+
sage: type(L[0])
|
|
591
|
+
<... 'int'>
|
|
592
|
+
sage: Zmod(1).list_of_elements_of_multiplicative_group()
|
|
593
|
+
[0]
|
|
594
|
+
"""
|
|
595
|
+
import sage.rings.fast_arith as a
|
|
596
|
+
if self.__order <= 46340: # todo: don't hard code
|
|
597
|
+
gcd = a.arith_int().gcd_int
|
|
598
|
+
elif self.__order <= 2147483647: # todo: don't hard code
|
|
599
|
+
gcd = a.arith_llong().gcd_longlong
|
|
600
|
+
else:
|
|
601
|
+
raise NotImplementedError("list_of_elements_of_multiplicative_group() is not implemented for large moduli")
|
|
602
|
+
N = self.__order
|
|
603
|
+
# Don't use N.coprime_integers() here because we want Python ints
|
|
604
|
+
return [i for i in range(N) if gcd(i, N) == 1]
|
|
605
|
+
|
|
606
|
+
@cached_method
|
|
607
|
+
def multiplicative_subgroups(self):
|
|
608
|
+
r"""
|
|
609
|
+
Return generators for each subgroup of `(\ZZ/N\ZZ)^*`.
|
|
610
|
+
|
|
611
|
+
EXAMPLES::
|
|
612
|
+
|
|
613
|
+
sage: # optional - gap_package_polycyclic, needs sage.groups sage.libs.pari sage.modules
|
|
614
|
+
sage: Integers(5).multiplicative_subgroups()
|
|
615
|
+
((2,), (4,), ())
|
|
616
|
+
sage: Integers(15).multiplicative_subgroups()
|
|
617
|
+
((11, 7), (11, 4), (2,), (11,), (14,), (7,), (4,), ())
|
|
618
|
+
sage: Integers(2).multiplicative_subgroups()
|
|
619
|
+
((),)
|
|
620
|
+
sage: len(Integers(341).multiplicative_subgroups())
|
|
621
|
+
80
|
|
622
|
+
|
|
623
|
+
TESTS::
|
|
624
|
+
|
|
625
|
+
sage: # needs sage.groups sage.modules
|
|
626
|
+
sage: IntegerModRing(1).multiplicative_subgroups()
|
|
627
|
+
((),)
|
|
628
|
+
sage: IntegerModRing(2).multiplicative_subgroups()
|
|
629
|
+
((),)
|
|
630
|
+
sage: IntegerModRing(3).multiplicative_subgroups() # optional - gap_package_polycyclic
|
|
631
|
+
((2,), ())
|
|
632
|
+
"""
|
|
633
|
+
return tuple(tuple(g.value() for g in H.gens())
|
|
634
|
+
for H in self.unit_group().subgroups())
|
|
635
|
+
|
|
636
|
+
def is_integral_domain(self, proof=None):
|
|
637
|
+
"""
|
|
638
|
+
Return ``True`` if and only if the order of ``self`` is prime.
|
|
639
|
+
|
|
640
|
+
EXAMPLES::
|
|
641
|
+
|
|
642
|
+
sage: Integers(389).is_integral_domain()
|
|
643
|
+
True
|
|
644
|
+
sage: Integers(389^2).is_integral_domain() # needs sage.libs.pari
|
|
645
|
+
False
|
|
646
|
+
|
|
647
|
+
TESTS:
|
|
648
|
+
|
|
649
|
+
Check that :issue:`17453` is fixed::
|
|
650
|
+
|
|
651
|
+
sage: R = Zmod(5)
|
|
652
|
+
sage: R in IntegralDomains()
|
|
653
|
+
True
|
|
654
|
+
"""
|
|
655
|
+
return self.is_field(proof)
|
|
656
|
+
|
|
657
|
+
def is_unique_factorization_domain(self, proof=None):
|
|
658
|
+
"""
|
|
659
|
+
Return ``True`` if and only if the order of ``self`` is prime.
|
|
660
|
+
|
|
661
|
+
EXAMPLES::
|
|
662
|
+
|
|
663
|
+
sage: Integers(389).is_unique_factorization_domain()
|
|
664
|
+
True
|
|
665
|
+
sage: Integers(389^2).is_unique_factorization_domain() # needs sage.libs.pari
|
|
666
|
+
False
|
|
667
|
+
"""
|
|
668
|
+
return self.is_field(proof)
|
|
669
|
+
|
|
670
|
+
@cached_method
|
|
671
|
+
def is_field(self, proof=None):
|
|
672
|
+
r"""
|
|
673
|
+
Return ``True`` precisely if the order is prime.
|
|
674
|
+
|
|
675
|
+
INPUT:
|
|
676
|
+
|
|
677
|
+
- ``proof`` -- boolean or ``None`` (default). If ``False``, then test
|
|
678
|
+
whether the category of the quotient is a subcategory of
|
|
679
|
+
``Fields()``, or do a probabilistic primality test. If ``None``, then
|
|
680
|
+
test the category and then do a primality test according to the
|
|
681
|
+
global arithmetic proof settings. If ``True``, do a deterministic
|
|
682
|
+
primality test.
|
|
683
|
+
|
|
684
|
+
If it is found (perhaps probabilistically) that the ring is a field,
|
|
685
|
+
then the category of the ring is refined to include the category
|
|
686
|
+
of fields. This may change the Python class of the ring!
|
|
687
|
+
|
|
688
|
+
EXAMPLES::
|
|
689
|
+
|
|
690
|
+
sage: R = IntegerModRing(18)
|
|
691
|
+
sage: R.is_field()
|
|
692
|
+
False
|
|
693
|
+
sage: FF = IntegerModRing(17)
|
|
694
|
+
sage: FF.is_field()
|
|
695
|
+
True
|
|
696
|
+
|
|
697
|
+
By :issue:`15229`, the category of the ring is refined,
|
|
698
|
+
if it is found that the ring is in fact a field::
|
|
699
|
+
|
|
700
|
+
sage: R = IntegerModRing(127)
|
|
701
|
+
sage: R.category()
|
|
702
|
+
Join of Category of finite commutative rings
|
|
703
|
+
and Category of subquotients of monoids
|
|
704
|
+
and Category of quotients of semigroups
|
|
705
|
+
and Category of finite enumerated sets
|
|
706
|
+
sage: R.is_field()
|
|
707
|
+
True
|
|
708
|
+
sage: R.category()
|
|
709
|
+
Join of Category of finite enumerated fields
|
|
710
|
+
and Category of subquotients of monoids
|
|
711
|
+
and Category of quotients of semigroups
|
|
712
|
+
|
|
713
|
+
It is possible to mistakenly put `\ZZ/n\ZZ` into the category of fields.
|
|
714
|
+
In this case, :meth:`is_field` will return ``True`` without performing a
|
|
715
|
+
primality check. However, if the optional argument ``proof=True`` is
|
|
716
|
+
provided, primality is tested and the mistake is uncovered in a warning
|
|
717
|
+
message::
|
|
718
|
+
|
|
719
|
+
sage: R = IntegerModRing(21, is_field=True)
|
|
720
|
+
sage: R.is_field()
|
|
721
|
+
True
|
|
722
|
+
sage: R.is_field(proof=True)
|
|
723
|
+
Traceback (most recent call last):
|
|
724
|
+
...
|
|
725
|
+
ValueError: THIS SAGE SESSION MIGHT BE SERIOUSLY COMPROMISED!
|
|
726
|
+
The order 21 is not prime, but this ring has been put
|
|
727
|
+
into the category of fields. This may already have consequences
|
|
728
|
+
in other parts of Sage. Either it was a mistake of the user,
|
|
729
|
+
or a probabilistic primality test has failed.
|
|
730
|
+
In the latter case, please inform the developers.
|
|
731
|
+
|
|
732
|
+
To avoid side-effects of this test on other tests, we clear the cache
|
|
733
|
+
of the ring factory::
|
|
734
|
+
|
|
735
|
+
sage: IntegerModRing._cache.clear()
|
|
736
|
+
"""
|
|
737
|
+
from sage.categories.fields import Fields
|
|
738
|
+
if not proof:
|
|
739
|
+
if self.category().is_subcategory(Fields()):
|
|
740
|
+
return True
|
|
741
|
+
is_prime = self.order().is_prime(proof=proof)
|
|
742
|
+
if is_prime:
|
|
743
|
+
self._refine_category_(Fields())
|
|
744
|
+
self._factory_data[3]['category'] = Fields()
|
|
745
|
+
else:
|
|
746
|
+
if self.category().is_subcategory(Fields()):
|
|
747
|
+
raise ValueError(("THIS SAGE SESSION MIGHT BE SERIOUSLY COMPROMISED!\n"
|
|
748
|
+
"The order {} is not prime, but this ring has been put\n"
|
|
749
|
+
"into the category of fields. This may already have consequences\n"
|
|
750
|
+
"in other parts of Sage. Either it was a mistake of the user,\n"
|
|
751
|
+
"or a probabilistic primality test has failed.\n"
|
|
752
|
+
"In the latter case, please inform the developers.").format(self.order()))
|
|
753
|
+
return is_prime
|
|
754
|
+
|
|
755
|
+
@cached_method
|
|
756
|
+
def field(self):
|
|
757
|
+
"""
|
|
758
|
+
If this ring is a field, return the corresponding field as a finite
|
|
759
|
+
field, which may have extra functionality and structure. Otherwise,
|
|
760
|
+
raise a :exc:`ValueError`.
|
|
761
|
+
|
|
762
|
+
EXAMPLES::
|
|
763
|
+
|
|
764
|
+
sage: R = Integers(7); R
|
|
765
|
+
Ring of integers modulo 7
|
|
766
|
+
sage: R.field()
|
|
767
|
+
Finite Field of size 7
|
|
768
|
+
sage: R = Integers(9)
|
|
769
|
+
sage: R.field()
|
|
770
|
+
Traceback (most recent call last):
|
|
771
|
+
...
|
|
772
|
+
ValueError: self must be a field
|
|
773
|
+
"""
|
|
774
|
+
try:
|
|
775
|
+
return self.__field
|
|
776
|
+
except AttributeError:
|
|
777
|
+
if not self.is_field():
|
|
778
|
+
raise ValueError("self must be a field")
|
|
779
|
+
from . import finite_field_constructor
|
|
780
|
+
k = finite_field_constructor.FiniteField(self.order())
|
|
781
|
+
self.__field = k
|
|
782
|
+
return k
|
|
783
|
+
|
|
784
|
+
def _pseudo_fraction_field(self):
|
|
785
|
+
"""
|
|
786
|
+
If ``self`` is composite, we may still want to do division by elements
|
|
787
|
+
of ``self``.
|
|
788
|
+
|
|
789
|
+
EXAMPLES::
|
|
790
|
+
|
|
791
|
+
sage: Integers(15).fraction_field()
|
|
792
|
+
Traceback (most recent call last):
|
|
793
|
+
...
|
|
794
|
+
TypeError: self must be an integral domain.
|
|
795
|
+
sage: Integers(15)._pseudo_fraction_field()
|
|
796
|
+
Ring of integers modulo 15
|
|
797
|
+
sage: R.<x> = Integers(15)[]
|
|
798
|
+
sage: (x+5)/2
|
|
799
|
+
8*x + 10
|
|
800
|
+
|
|
801
|
+
This should be very fast::
|
|
802
|
+
|
|
803
|
+
sage: R.<x> = Integers(next_prime(10^101)*next_prime(10^100))[] # needs sage.libs.pari
|
|
804
|
+
sage: x / R.base_ring()(2) # needs sage.libs.pari
|
|
805
|
+
500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000401*x
|
|
806
|
+
"""
|
|
807
|
+
return self
|
|
808
|
+
|
|
809
|
+
@cached_method
|
|
810
|
+
def multiplicative_group_is_cyclic(self):
|
|
811
|
+
"""
|
|
812
|
+
Return ``True`` if the multiplicative group of this field is cyclic.
|
|
813
|
+
This is the case exactly when the order is less than 8, a power
|
|
814
|
+
of an odd prime, or twice a power of an odd prime.
|
|
815
|
+
|
|
816
|
+
EXAMPLES::
|
|
817
|
+
|
|
818
|
+
sage: R = Integers(7); R
|
|
819
|
+
Ring of integers modulo 7
|
|
820
|
+
sage: R.multiplicative_group_is_cyclic()
|
|
821
|
+
True
|
|
822
|
+
sage: R = Integers(9)
|
|
823
|
+
sage: R.multiplicative_group_is_cyclic() # needs sage.libs.pari
|
|
824
|
+
True
|
|
825
|
+
sage: Integers(8).multiplicative_group_is_cyclic()
|
|
826
|
+
False
|
|
827
|
+
sage: Integers(4).multiplicative_group_is_cyclic()
|
|
828
|
+
True
|
|
829
|
+
sage: Integers(25*3).multiplicative_group_is_cyclic() # needs sage.libs.pari
|
|
830
|
+
False
|
|
831
|
+
|
|
832
|
+
We test that :issue:`5250` is fixed::
|
|
833
|
+
|
|
834
|
+
sage: Integers(162).multiplicative_group_is_cyclic() # needs sage.libs.pari
|
|
835
|
+
True
|
|
836
|
+
"""
|
|
837
|
+
n = self.order()
|
|
838
|
+
if n < 8:
|
|
839
|
+
return True
|
|
840
|
+
|
|
841
|
+
if n % 4 == 0:
|
|
842
|
+
return False # know n > 7, so n=4 case not a problem
|
|
843
|
+
if n % 4 == 2:
|
|
844
|
+
n = n // 2
|
|
845
|
+
|
|
846
|
+
return n.is_prime_power()
|
|
847
|
+
|
|
848
|
+
@cached_method
|
|
849
|
+
def multiplicative_generator(self):
|
|
850
|
+
"""
|
|
851
|
+
Return a generator for the multiplicative group of this ring,
|
|
852
|
+
assuming the multiplicative group is cyclic.
|
|
853
|
+
|
|
854
|
+
Use the unit_gens function to obtain generators even in the
|
|
855
|
+
non-cyclic case.
|
|
856
|
+
|
|
857
|
+
EXAMPLES::
|
|
858
|
+
|
|
859
|
+
sage: # needs sage.groups sage.libs.pari
|
|
860
|
+
sage: R = Integers(7); R
|
|
861
|
+
Ring of integers modulo 7
|
|
862
|
+
sage: R.multiplicative_generator()
|
|
863
|
+
3
|
|
864
|
+
sage: R = Integers(9)
|
|
865
|
+
sage: R.multiplicative_generator()
|
|
866
|
+
2
|
|
867
|
+
sage: Integers(8).multiplicative_generator()
|
|
868
|
+
Traceback (most recent call last):
|
|
869
|
+
...
|
|
870
|
+
ValueError: multiplicative group of this ring is not cyclic
|
|
871
|
+
sage: Integers(4).multiplicative_generator()
|
|
872
|
+
3
|
|
873
|
+
sage: Integers(25*3).multiplicative_generator()
|
|
874
|
+
Traceback (most recent call last):
|
|
875
|
+
...
|
|
876
|
+
ValueError: multiplicative group of this ring is not cyclic
|
|
877
|
+
sage: Integers(25*3).unit_gens()
|
|
878
|
+
(26, 52)
|
|
879
|
+
sage: Integers(162).unit_gens()
|
|
880
|
+
(83,)
|
|
881
|
+
"""
|
|
882
|
+
try:
|
|
883
|
+
return self.__mult_gen
|
|
884
|
+
except AttributeError:
|
|
885
|
+
if self.is_field():
|
|
886
|
+
a = self(self.field().multiplicative_generator())
|
|
887
|
+
self.__mult_gen = a
|
|
888
|
+
return a
|
|
889
|
+
if self.multiplicative_group_is_cyclic():
|
|
890
|
+
v = self.unit_gens()
|
|
891
|
+
if len(v) != 1:
|
|
892
|
+
raise ArithmeticError
|
|
893
|
+
return v[0]
|
|
894
|
+
|
|
895
|
+
raise ValueError("multiplicative group of this ring is not cyclic")
|
|
896
|
+
|
|
897
|
+
def quadratic_nonresidue(self):
|
|
898
|
+
"""
|
|
899
|
+
Return a quadratic non-residue in ``self``.
|
|
900
|
+
|
|
901
|
+
EXAMPLES::
|
|
902
|
+
|
|
903
|
+
sage: R = Integers(17)
|
|
904
|
+
sage: R.quadratic_nonresidue() # needs sage.libs.pari
|
|
905
|
+
3
|
|
906
|
+
sage: R(3).is_square()
|
|
907
|
+
False
|
|
908
|
+
"""
|
|
909
|
+
try:
|
|
910
|
+
return self._nonresidue
|
|
911
|
+
except AttributeError:
|
|
912
|
+
for a in self:
|
|
913
|
+
if not a.is_square():
|
|
914
|
+
self._nonresidue = a
|
|
915
|
+
return a
|
|
916
|
+
|
|
917
|
+
def square_roots_of_one(self):
|
|
918
|
+
"""
|
|
919
|
+
Return all square roots of 1 in self, i.e., all solutions to
|
|
920
|
+
`x^2 - 1 = 0`.
|
|
921
|
+
|
|
922
|
+
OUTPUT: the square roots of 1 in ``self`` as a tuple
|
|
923
|
+
|
|
924
|
+
EXAMPLES::
|
|
925
|
+
|
|
926
|
+
sage: R = Integers(2^10)
|
|
927
|
+
sage: [x for x in R if x^2 == 1]
|
|
928
|
+
[1, 511, 513, 1023]
|
|
929
|
+
sage: R.square_roots_of_one()
|
|
930
|
+
(1, 511, 513, 1023)
|
|
931
|
+
|
|
932
|
+
::
|
|
933
|
+
|
|
934
|
+
sage: # needs sage.libs.pari
|
|
935
|
+
sage: v = Integers(9*5).square_roots_of_one(); v
|
|
936
|
+
(1, 19, 26, 44)
|
|
937
|
+
sage: [x^2 for x in v]
|
|
938
|
+
[1, 1, 1, 1]
|
|
939
|
+
sage: v = Integers(9*5*8).square_roots_of_one(); v
|
|
940
|
+
(1, 19, 71, 89, 91, 109, 161, 179, 181, 199, 251, 269, 271, 289, 341, 359)
|
|
941
|
+
sage: [x^2 for x in v]
|
|
942
|
+
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
|
943
|
+
"""
|
|
944
|
+
try:
|
|
945
|
+
return self.__square_roots_of_one
|
|
946
|
+
except AttributeError:
|
|
947
|
+
pass
|
|
948
|
+
n = self.__order
|
|
949
|
+
if n.is_prime_power():
|
|
950
|
+
if n % 2 == 0:
|
|
951
|
+
# power of 2
|
|
952
|
+
if n == 2:
|
|
953
|
+
v = [self(1)]
|
|
954
|
+
elif n == 4:
|
|
955
|
+
v = [self(1), self(3)]
|
|
956
|
+
else: # n >= 8
|
|
957
|
+
half_ord = n // 2
|
|
958
|
+
v = [self(1), self(-1),
|
|
959
|
+
self(half_ord - 1), self(half_ord + 1)]
|
|
960
|
+
else:
|
|
961
|
+
v = [self(1), self(-1)]
|
|
962
|
+
else:
|
|
963
|
+
# Reduce to the prime power case.
|
|
964
|
+
F = self.factored_order()
|
|
965
|
+
vmod = []
|
|
966
|
+
moduli = []
|
|
967
|
+
for p, e in F:
|
|
968
|
+
k = p**e
|
|
969
|
+
R = IntegerModRing(p**e)
|
|
970
|
+
w = [self(x) for x in R.square_roots_of_one()]
|
|
971
|
+
vmod.append(w)
|
|
972
|
+
moduli.append(k)
|
|
973
|
+
# Now combine in all possible ways using the CRT
|
|
974
|
+
basis = CRT_basis(moduli)
|
|
975
|
+
from sage.misc.mrange import cartesian_product_iterator
|
|
976
|
+
v = []
|
|
977
|
+
for x in cartesian_product_iterator(vmod):
|
|
978
|
+
# x is a specific choice of roots modulo each prime power divisor
|
|
979
|
+
a = sum([basis[i] * x[i] for i in range(len(x))])
|
|
980
|
+
v.append(a)
|
|
981
|
+
|
|
982
|
+
v.sort()
|
|
983
|
+
v = tuple(v)
|
|
984
|
+
self.__square_roots_of_one = v
|
|
985
|
+
return v
|
|
986
|
+
|
|
987
|
+
@cached_method
|
|
988
|
+
def factored_order(self):
|
|
989
|
+
"""
|
|
990
|
+
EXAMPLES::
|
|
991
|
+
|
|
992
|
+
sage: R = IntegerModRing(18)
|
|
993
|
+
sage: FF = IntegerModRing(17)
|
|
994
|
+
sage: R.factored_order()
|
|
995
|
+
2 * 3^2
|
|
996
|
+
sage: FF.factored_order()
|
|
997
|
+
17
|
|
998
|
+
"""
|
|
999
|
+
return factor(self.__order, int_=(self.__order < 2**31))
|
|
1000
|
+
|
|
1001
|
+
def factored_unit_order(self):
|
|
1002
|
+
r"""
|
|
1003
|
+
Return a list of :class:`Factorization` objects, each the factorization
|
|
1004
|
+
of the order of the units in a `\ZZ / p^n \ZZ` component of this group
|
|
1005
|
+
(using the Chinese Remainder Theorem).
|
|
1006
|
+
|
|
1007
|
+
EXAMPLES::
|
|
1008
|
+
|
|
1009
|
+
sage: R = Integers(8*9*25*17*29)
|
|
1010
|
+
sage: R.factored_unit_order()
|
|
1011
|
+
[2^2, 2 * 3, 2^2 * 5, 2^4, 2^2 * 7]
|
|
1012
|
+
"""
|
|
1013
|
+
ans = []
|
|
1014
|
+
from sage.structure.factorization import Factorization
|
|
1015
|
+
for p, e in self.factored_order():
|
|
1016
|
+
ans.append(Factorization([(p, e - 1)]) *
|
|
1017
|
+
factor(p - 1, int_=(self.__order < 2**31)))
|
|
1018
|
+
return ans
|
|
1019
|
+
|
|
1020
|
+
def characteristic(self):
|
|
1021
|
+
"""
|
|
1022
|
+
EXAMPLES::
|
|
1023
|
+
|
|
1024
|
+
sage: R = IntegerModRing(18)
|
|
1025
|
+
sage: FF = IntegerModRing(17)
|
|
1026
|
+
sage: FF.characteristic()
|
|
1027
|
+
17
|
|
1028
|
+
sage: R.characteristic()
|
|
1029
|
+
18
|
|
1030
|
+
"""
|
|
1031
|
+
return self.__order
|
|
1032
|
+
|
|
1033
|
+
def _repr_(self):
|
|
1034
|
+
"""
|
|
1035
|
+
String representation.
|
|
1036
|
+
|
|
1037
|
+
EXAMPLES::
|
|
1038
|
+
|
|
1039
|
+
sage: Zmod(87)
|
|
1040
|
+
Ring of integers modulo 87
|
|
1041
|
+
"""
|
|
1042
|
+
return "Ring of integers modulo {}".format(self.__order)
|
|
1043
|
+
|
|
1044
|
+
def _latex_(self):
|
|
1045
|
+
r"""
|
|
1046
|
+
Latex representation.
|
|
1047
|
+
|
|
1048
|
+
EXAMPLES::
|
|
1049
|
+
|
|
1050
|
+
sage: latex(Zmod(87))
|
|
1051
|
+
\ZZ/87\ZZ
|
|
1052
|
+
"""
|
|
1053
|
+
return "\\ZZ/{}\\ZZ".format(self.__order)
|
|
1054
|
+
|
|
1055
|
+
def modulus(self):
|
|
1056
|
+
r"""
|
|
1057
|
+
Return the polynomial `x - 1` over this ring.
|
|
1058
|
+
|
|
1059
|
+
.. NOTE::
|
|
1060
|
+
|
|
1061
|
+
This function exists for consistency with the finite-field
|
|
1062
|
+
modulus function.
|
|
1063
|
+
|
|
1064
|
+
EXAMPLES::
|
|
1065
|
+
|
|
1066
|
+
sage: R = IntegerModRing(18)
|
|
1067
|
+
sage: R.modulus()
|
|
1068
|
+
x + 17
|
|
1069
|
+
sage: R = IntegerModRing(17)
|
|
1070
|
+
sage: R.modulus()
|
|
1071
|
+
x + 16
|
|
1072
|
+
"""
|
|
1073
|
+
try:
|
|
1074
|
+
return self.__modulus
|
|
1075
|
+
except AttributeError:
|
|
1076
|
+
x = self['x'].gen()
|
|
1077
|
+
self.__modulus = x - 1
|
|
1078
|
+
return self.__modulus
|
|
1079
|
+
|
|
1080
|
+
def order(self):
|
|
1081
|
+
"""
|
|
1082
|
+
Return the order of this ring.
|
|
1083
|
+
|
|
1084
|
+
EXAMPLES::
|
|
1085
|
+
|
|
1086
|
+
sage: Zmod(87).order()
|
|
1087
|
+
87
|
|
1088
|
+
"""
|
|
1089
|
+
return self.__order
|
|
1090
|
+
|
|
1091
|
+
def cardinality(self):
|
|
1092
|
+
"""
|
|
1093
|
+
Return the cardinality of this ring.
|
|
1094
|
+
|
|
1095
|
+
EXAMPLES::
|
|
1096
|
+
|
|
1097
|
+
sage: Zmod(87).cardinality()
|
|
1098
|
+
87
|
|
1099
|
+
"""
|
|
1100
|
+
return self.order()
|
|
1101
|
+
|
|
1102
|
+
def _pari_order(self):
|
|
1103
|
+
"""
|
|
1104
|
+
Return the pari integer representing the order of this ring.
|
|
1105
|
+
|
|
1106
|
+
EXAMPLES::
|
|
1107
|
+
|
|
1108
|
+
sage: Zmod(87)._pari_order() # needs sage.libs.pari
|
|
1109
|
+
87
|
|
1110
|
+
"""
|
|
1111
|
+
try:
|
|
1112
|
+
return self.__pari_order
|
|
1113
|
+
except AttributeError:
|
|
1114
|
+
self.__pari_order = pari(self.order())
|
|
1115
|
+
return self.__pari_order
|
|
1116
|
+
|
|
1117
|
+
def _element_constructor_(self, x):
|
|
1118
|
+
"""
|
|
1119
|
+
TESTS::
|
|
1120
|
+
|
|
1121
|
+
sage: # needs sage.rings.finite_rings
|
|
1122
|
+
sage: K2 = GF(2)
|
|
1123
|
+
sage: K3 = GF(3)
|
|
1124
|
+
sage: K8 = GF(8, 'a')
|
|
1125
|
+
sage: K8(5) # indirect doctest
|
|
1126
|
+
1
|
|
1127
|
+
sage: K8('a+1')
|
|
1128
|
+
a + 1
|
|
1129
|
+
sage: K8(K2(1))
|
|
1130
|
+
1
|
|
1131
|
+
|
|
1132
|
+
The following test refers to :issue:`6468`::
|
|
1133
|
+
|
|
1134
|
+
sage: class foo_parent(Parent):
|
|
1135
|
+
....: pass
|
|
1136
|
+
sage: class foo(RingElement):
|
|
1137
|
+
....: def lift(self):
|
|
1138
|
+
....: raise PariError
|
|
1139
|
+
sage: P = foo_parent()
|
|
1140
|
+
sage: F = foo(P)
|
|
1141
|
+
sage: GF(2)(F)
|
|
1142
|
+
Traceback (most recent call last):
|
|
1143
|
+
...
|
|
1144
|
+
TypeError: error coercing to finite field
|
|
1145
|
+
|
|
1146
|
+
The following test refers to :issue:`8970`::
|
|
1147
|
+
|
|
1148
|
+
sage: R = Zmod(13); a = R(2)
|
|
1149
|
+
sage: a == R(gap(a)) # needs sage.libs.gap
|
|
1150
|
+
True
|
|
1151
|
+
|
|
1152
|
+
libgap interface (:issue:`23714`)::
|
|
1153
|
+
|
|
1154
|
+
sage: a = libgap.eval("Z(13)^2") # needs sage.libs.gap
|
|
1155
|
+
sage: a.sage() # needs sage.libs.gap
|
|
1156
|
+
4
|
|
1157
|
+
sage: libgap(a.sage()) == a # needs sage.libs.gap
|
|
1158
|
+
True
|
|
1159
|
+
|
|
1160
|
+
better syntax for libgap interface::
|
|
1161
|
+
|
|
1162
|
+
sage: a = libgap.Z(13)^2 # needs sage.libs.gap
|
|
1163
|
+
sage: libgap(a.sage()) == a # needs sage.libs.gap
|
|
1164
|
+
True
|
|
1165
|
+
"""
|
|
1166
|
+
try:
|
|
1167
|
+
return integer_mod.IntegerMod(self, x)
|
|
1168
|
+
except (NotImplementedError, PariError):
|
|
1169
|
+
raise TypeError("error coercing to finite field")
|
|
1170
|
+
except TypeError:
|
|
1171
|
+
if isinstance(x, GapElement):
|
|
1172
|
+
from sage.libs.gap.libgap import libgap
|
|
1173
|
+
return libgap(x).sage()
|
|
1174
|
+
raise # Continue up with the original TypeError
|
|
1175
|
+
|
|
1176
|
+
def __iter__(self):
|
|
1177
|
+
"""
|
|
1178
|
+
EXAMPLES::
|
|
1179
|
+
|
|
1180
|
+
sage: R = IntegerModRing(3)
|
|
1181
|
+
sage: for i in R:
|
|
1182
|
+
....: print(i)
|
|
1183
|
+
0
|
|
1184
|
+
1
|
|
1185
|
+
2
|
|
1186
|
+
sage: L = [i for i in R]
|
|
1187
|
+
sage: L[0].parent()
|
|
1188
|
+
Ring of integers modulo 3
|
|
1189
|
+
"""
|
|
1190
|
+
i = 0
|
|
1191
|
+
order = int(self.__order)
|
|
1192
|
+
while i < order:
|
|
1193
|
+
yield self(i)
|
|
1194
|
+
i = i + 1
|
|
1195
|
+
|
|
1196
|
+
def _coerce_map_from_(self, S):
|
|
1197
|
+
r"""
|
|
1198
|
+
EXAMPLES::
|
|
1199
|
+
|
|
1200
|
+
sage: R = Integers(15)
|
|
1201
|
+
sage: f = R.coerce_map_from(Integers(450)); f # indirect doctest
|
|
1202
|
+
Natural morphism:
|
|
1203
|
+
From: Ring of integers modulo 450
|
|
1204
|
+
To: Ring of integers modulo 15
|
|
1205
|
+
sage: f(-1)
|
|
1206
|
+
14
|
|
1207
|
+
sage: f = R.coerce_map_from(int); f
|
|
1208
|
+
Native morphism:
|
|
1209
|
+
From: Set of Python objects of class 'int'
|
|
1210
|
+
To: Ring of integers modulo 15
|
|
1211
|
+
sage: f(-1r)
|
|
1212
|
+
14
|
|
1213
|
+
sage: f = R.coerce_map_from(ZZ); f
|
|
1214
|
+
Natural morphism:
|
|
1215
|
+
From: Integer Ring
|
|
1216
|
+
To: Ring of integers modulo 15
|
|
1217
|
+
sage: f(-1)
|
|
1218
|
+
14
|
|
1219
|
+
sage: f = R.coerce_map_from(Integers(10)); print(f)
|
|
1220
|
+
None
|
|
1221
|
+
sage: f = R.coerce_map_from(QQ); print(f)
|
|
1222
|
+
None
|
|
1223
|
+
|
|
1224
|
+
sage: R = IntegerModRing(17)
|
|
1225
|
+
sage: a = R(3)
|
|
1226
|
+
sage: b = R.coerce(3)
|
|
1227
|
+
sage: b
|
|
1228
|
+
3
|
|
1229
|
+
sage: a==b
|
|
1230
|
+
True
|
|
1231
|
+
|
|
1232
|
+
This is allowed::
|
|
1233
|
+
|
|
1234
|
+
sage: R(2/3)
|
|
1235
|
+
12
|
|
1236
|
+
|
|
1237
|
+
But this is not, since there is no (canonical or not!) ring
|
|
1238
|
+
homomorphism from `\QQ` to `\GF{17}`.
|
|
1239
|
+
|
|
1240
|
+
::
|
|
1241
|
+
|
|
1242
|
+
sage: R.coerce(2/3)
|
|
1243
|
+
Traceback (most recent call last):
|
|
1244
|
+
...
|
|
1245
|
+
TypeError: no canonical coercion from Rational Field to Ring of integers modulo 17
|
|
1246
|
+
|
|
1247
|
+
We do not allow the coercion ``GF(p) -> Z/pZ``, because in case of a
|
|
1248
|
+
canonical isomorphism, there is a coercion map in only one
|
|
1249
|
+
direction, i.e., to the object in the smaller category.
|
|
1250
|
+
"""
|
|
1251
|
+
if S is int:
|
|
1252
|
+
return integer_mod.Int_to_IntegerMod(self)
|
|
1253
|
+
elif S is integer_ring.ZZ:
|
|
1254
|
+
return integer_mod.Integer_to_IntegerMod(self)
|
|
1255
|
+
elif isinstance(S, IntegerModRing_generic):
|
|
1256
|
+
if isinstance(S, Field):
|
|
1257
|
+
return None
|
|
1258
|
+
try:
|
|
1259
|
+
return integer_mod.IntegerMod_to_IntegerMod(S, self)
|
|
1260
|
+
except TypeError:
|
|
1261
|
+
pass
|
|
1262
|
+
to_ZZ = integer_ring.ZZ._internal_coerce_map_from(S)
|
|
1263
|
+
if to_ZZ is not None:
|
|
1264
|
+
return integer_mod.Integer_to_IntegerMod(self) * to_ZZ
|
|
1265
|
+
|
|
1266
|
+
def _convert_map_from_(self, other):
|
|
1267
|
+
"""
|
|
1268
|
+
Conversion from `p`-adic fields.
|
|
1269
|
+
|
|
1270
|
+
EXAMPLES::
|
|
1271
|
+
|
|
1272
|
+
sage: Zmod(81).convert_map_from(Qp(3)) # needs sage.rings.padics
|
|
1273
|
+
Reduction morphism:
|
|
1274
|
+
From: 3-adic Field with capped relative precision 20
|
|
1275
|
+
To: Ring of integers modulo 81
|
|
1276
|
+
"""
|
|
1277
|
+
from sage.rings.padics.padic_generic import pAdicGeneric, ResidueReductionMap
|
|
1278
|
+
if isinstance(other, pAdicGeneric) and other.degree() == 1:
|
|
1279
|
+
p = other.prime()
|
|
1280
|
+
N = self.cardinality()
|
|
1281
|
+
n = N.exact_log(p)
|
|
1282
|
+
if p**n == N:
|
|
1283
|
+
return ResidueReductionMap._create_(other, self)
|
|
1284
|
+
|
|
1285
|
+
def __richcmp__(self, other, op):
|
|
1286
|
+
"""
|
|
1287
|
+
EXAMPLES::
|
|
1288
|
+
|
|
1289
|
+
sage: Z11 = IntegerModRing(11); Z11
|
|
1290
|
+
Ring of integers modulo 11
|
|
1291
|
+
sage: Z12 = IntegerModRing(12); Z12
|
|
1292
|
+
Ring of integers modulo 12
|
|
1293
|
+
sage: Z13 = IntegerModRing(13); Z13
|
|
1294
|
+
Ring of integers modulo 13
|
|
1295
|
+
sage: Z11 == Z11, Z11 == Z12, Z11 == Z13
|
|
1296
|
+
(True, False, False)
|
|
1297
|
+
sage: F = GF(11); F
|
|
1298
|
+
Finite Field of size 11
|
|
1299
|
+
sage: Z11 == F
|
|
1300
|
+
False
|
|
1301
|
+
|
|
1302
|
+
In :issue:`15229`, the following was implemented::
|
|
1303
|
+
|
|
1304
|
+
sage: R1 = IntegerModRing(5)
|
|
1305
|
+
sage: R2 = IntegerModRing(5, is_field=True)
|
|
1306
|
+
sage: R1 is R2 # used to return False
|
|
1307
|
+
True
|
|
1308
|
+
sage: R2 == GF(5)
|
|
1309
|
+
False
|
|
1310
|
+
"""
|
|
1311
|
+
# We want that GF(p) and IntegerModRing(p) evaluate unequal.
|
|
1312
|
+
# However, we cannot just compare the types, since the
|
|
1313
|
+
# choice of a different category also changes the type.
|
|
1314
|
+
# But if we go to the base class, we avoid the influence
|
|
1315
|
+
# of the category.
|
|
1316
|
+
try:
|
|
1317
|
+
c = bool(other.__class__.__base__ != self.__class__.__base__)
|
|
1318
|
+
except AttributeError: # __base__ does not always exists
|
|
1319
|
+
c = bool(type(other) is not type(self))
|
|
1320
|
+
if c:
|
|
1321
|
+
return NotImplemented
|
|
1322
|
+
return richcmp(self.__order, other.__order, op)
|
|
1323
|
+
|
|
1324
|
+
def unit_gens(self, **kwds):
|
|
1325
|
+
r"""
|
|
1326
|
+
Return generators for the unit group `(\ZZ/N\ZZ)^*`.
|
|
1327
|
+
|
|
1328
|
+
We compute the list of generators using a deterministic algorithm, so
|
|
1329
|
+
the generators list will always be the same. For each odd prime divisor
|
|
1330
|
+
of `N` there will be exactly one corresponding generator; if `N` is
|
|
1331
|
+
even there will be 0, 1 or 2 generators according to whether 2 divides
|
|
1332
|
+
`N` to order 1, 2 or `\geq 3`.
|
|
1333
|
+
|
|
1334
|
+
OUTPUT: a tuple containing the units of ``self``
|
|
1335
|
+
|
|
1336
|
+
EXAMPLES::
|
|
1337
|
+
|
|
1338
|
+
sage: # needs sage.groups sage.libs.pari sage.modules
|
|
1339
|
+
sage: R = IntegerModRing(18)
|
|
1340
|
+
sage: R.unit_gens()
|
|
1341
|
+
(11,)
|
|
1342
|
+
sage: R = IntegerModRing(17)
|
|
1343
|
+
sage: R.unit_gens()
|
|
1344
|
+
(3,)
|
|
1345
|
+
sage: IntegerModRing(next_prime(10^30)).unit_gens()
|
|
1346
|
+
(5,)
|
|
1347
|
+
|
|
1348
|
+
The choice of generators is affected by the optional keyword
|
|
1349
|
+
``algorithm``; this can be ``'sage'`` (default) or ``'pari'``.
|
|
1350
|
+
See :meth:`unit_group` for details. ::
|
|
1351
|
+
|
|
1352
|
+
sage: # needs sage.groups sage.modules
|
|
1353
|
+
sage: A = Zmod(55)
|
|
1354
|
+
sage: A.unit_gens(algorithm='sage')
|
|
1355
|
+
(12, 46)
|
|
1356
|
+
sage: A.unit_gens(algorithm='pari') # needs sage.libs.pari
|
|
1357
|
+
(2, 21)
|
|
1358
|
+
|
|
1359
|
+
TESTS::
|
|
1360
|
+
|
|
1361
|
+
sage: # needs sage.groups sage.modules
|
|
1362
|
+
sage: IntegerModRing(2).unit_gens()
|
|
1363
|
+
()
|
|
1364
|
+
sage: IntegerModRing(4).unit_gens()
|
|
1365
|
+
(3,)
|
|
1366
|
+
sage: IntegerModRing(8).unit_gens()
|
|
1367
|
+
(7, 5)
|
|
1368
|
+
"""
|
|
1369
|
+
return self.unit_group(**kwds).gens_values()
|
|
1370
|
+
|
|
1371
|
+
def unit_group_exponent(self):
|
|
1372
|
+
"""
|
|
1373
|
+
EXAMPLES::
|
|
1374
|
+
|
|
1375
|
+
sage: # needs sage.groups sage.libs.pari sage.modules
|
|
1376
|
+
sage: R = IntegerModRing(17)
|
|
1377
|
+
sage: R.unit_group_exponent()
|
|
1378
|
+
16
|
|
1379
|
+
sage: R = IntegerModRing(18)
|
|
1380
|
+
sage: R.unit_group_exponent()
|
|
1381
|
+
6
|
|
1382
|
+
"""
|
|
1383
|
+
return self.unit_group().exponent()
|
|
1384
|
+
|
|
1385
|
+
def unit_group_order(self):
|
|
1386
|
+
"""
|
|
1387
|
+
Return the order of the unit group of this residue class ring.
|
|
1388
|
+
|
|
1389
|
+
EXAMPLES::
|
|
1390
|
+
|
|
1391
|
+
sage: R = Integers(500)
|
|
1392
|
+
sage: R.unit_group_order() # needs sage.groups sage.libs.pari sage.modules
|
|
1393
|
+
200
|
|
1394
|
+
"""
|
|
1395
|
+
return self.unit_group().order()
|
|
1396
|
+
|
|
1397
|
+
@cached_method
|
|
1398
|
+
def unit_group(self, algorithm='sage'):
|
|
1399
|
+
r"""
|
|
1400
|
+
Return the unit group of ``self``.
|
|
1401
|
+
|
|
1402
|
+
INPUT:
|
|
1403
|
+
|
|
1404
|
+
- ``self`` -- the ring `\ZZ/n\ZZ` for a positive integer `n`
|
|
1405
|
+
|
|
1406
|
+
- ``algorithm`` -- either ``'sage'`` (default) or ``'pari'``
|
|
1407
|
+
|
|
1408
|
+
OUTPUT:
|
|
1409
|
+
|
|
1410
|
+
The unit group of ``self``. This is a finite Abelian group
|
|
1411
|
+
equipped with a distinguished set of generators, which is
|
|
1412
|
+
computed using a deterministic algorithm depending on the
|
|
1413
|
+
``algorithm`` parameter.
|
|
1414
|
+
|
|
1415
|
+
- If ``algorithm == 'sage'``, the generators correspond to the
|
|
1416
|
+
prime factors `p \mid n` (one generator for each odd `p`;
|
|
1417
|
+
the number of generators for `p = 2` is 0, 1 or 2 depending
|
|
1418
|
+
on the order to which 2 divides `n`).
|
|
1419
|
+
|
|
1420
|
+
- If ``algorithm == 'pari'``, the generators are chosen such
|
|
1421
|
+
that their orders form a decreasing sequence with respect to
|
|
1422
|
+
divisibility.
|
|
1423
|
+
|
|
1424
|
+
EXAMPLES:
|
|
1425
|
+
|
|
1426
|
+
The output of the algorithms ``'sage'`` and ``'pari'`` can
|
|
1427
|
+
differ in various ways. In the following example, the same
|
|
1428
|
+
cyclic factors are computed, but in a different order::
|
|
1429
|
+
|
|
1430
|
+
sage: # needs sage.groups sage.libs.pari sage.modules
|
|
1431
|
+
sage: A = Zmod(15)
|
|
1432
|
+
sage: G = A.unit_group(); G
|
|
1433
|
+
Multiplicative Abelian group isomorphic to C2 x C4
|
|
1434
|
+
sage: G.gens_values()
|
|
1435
|
+
(11, 7)
|
|
1436
|
+
sage: H = A.unit_group(algorithm='pari'); H # needs sage.libs.pari
|
|
1437
|
+
Multiplicative Abelian group isomorphic to C4 x C2
|
|
1438
|
+
sage: H.gens_values() # needs sage.libs.pari
|
|
1439
|
+
(7, 11)
|
|
1440
|
+
|
|
1441
|
+
Here are two examples where the cyclic factors are isomorphic,
|
|
1442
|
+
but are ordered differently and have different generators::
|
|
1443
|
+
|
|
1444
|
+
sage: # needs sage.groups sage.libs.pari sage.modules
|
|
1445
|
+
sage: A = Zmod(40)
|
|
1446
|
+
sage: G = A.unit_group(); G
|
|
1447
|
+
Multiplicative Abelian group isomorphic to C2 x C2 x C4
|
|
1448
|
+
sage: G.gens_values()
|
|
1449
|
+
(31, 21, 17)
|
|
1450
|
+
sage: H = A.unit_group(algorithm='pari'); H
|
|
1451
|
+
Multiplicative Abelian group isomorphic to C4 x C2 x C2
|
|
1452
|
+
sage: H.gens_values()
|
|
1453
|
+
(17, 31, 21)
|
|
1454
|
+
|
|
1455
|
+
sage: # needs sage.groups sage.libs.pari sage.modules
|
|
1456
|
+
sage: A = Zmod(192)
|
|
1457
|
+
sage: G = A.unit_group(); G
|
|
1458
|
+
Multiplicative Abelian group isomorphic to C2 x C16 x C2
|
|
1459
|
+
sage: G.gens_values()
|
|
1460
|
+
(127, 133, 65)
|
|
1461
|
+
sage: H = A.unit_group(algorithm='pari'); H
|
|
1462
|
+
Multiplicative Abelian group isomorphic to C16 x C2 x C2
|
|
1463
|
+
sage: H.gens_values()
|
|
1464
|
+
(133, 127, 65)
|
|
1465
|
+
|
|
1466
|
+
In the following examples, the cyclic factors are not even
|
|
1467
|
+
isomorphic::
|
|
1468
|
+
|
|
1469
|
+
sage: # needs sage.groups sage.libs.pari sage.modules
|
|
1470
|
+
sage: A = Zmod(319)
|
|
1471
|
+
sage: A.unit_group()
|
|
1472
|
+
Multiplicative Abelian group isomorphic to C10 x C28
|
|
1473
|
+
sage: A.unit_group(algorithm='pari')
|
|
1474
|
+
Multiplicative Abelian group isomorphic to C140 x C2
|
|
1475
|
+
sage: A = Zmod(30.factorial())
|
|
1476
|
+
sage: A.unit_group()
|
|
1477
|
+
Multiplicative Abelian group isomorphic to
|
|
1478
|
+
C2 x C16777216 x C3188646 x C62500 x C2058 x C110 x C156 x C16 x C18 x C22 x C28
|
|
1479
|
+
sage: A.unit_group(algorithm='pari')
|
|
1480
|
+
Multiplicative Abelian group isomorphic to
|
|
1481
|
+
C20499647385305088000000 x C55440 x C12 x C12 x C4 x C2 x C2 x C2 x C2 x C2 x C2
|
|
1482
|
+
|
|
1483
|
+
TESTS:
|
|
1484
|
+
|
|
1485
|
+
We test the cases where the unit group is trivial::
|
|
1486
|
+
|
|
1487
|
+
sage: # needs sage.groups sage.libs.pari sage.modules
|
|
1488
|
+
sage: A = Zmod(1)
|
|
1489
|
+
sage: A.unit_group()
|
|
1490
|
+
Trivial Abelian group
|
|
1491
|
+
sage: A.unit_group(algorithm='pari')
|
|
1492
|
+
Trivial Abelian group
|
|
1493
|
+
sage: A = Zmod(2)
|
|
1494
|
+
sage: A.unit_group()
|
|
1495
|
+
Trivial Abelian group
|
|
1496
|
+
sage: A.unit_group(algorithm='pari')
|
|
1497
|
+
Trivial Abelian group
|
|
1498
|
+
sage: Zmod(3).unit_group(algorithm='bogus')
|
|
1499
|
+
Traceback (most recent call last):
|
|
1500
|
+
...
|
|
1501
|
+
ValueError: unknown algorithm 'bogus' for computing the unit group
|
|
1502
|
+
"""
|
|
1503
|
+
from sage.groups.abelian_gps.values import AbelianGroupWithValues
|
|
1504
|
+
if algorithm == 'sage':
|
|
1505
|
+
n = self.order()
|
|
1506
|
+
gens = []
|
|
1507
|
+
orders = []
|
|
1508
|
+
for p, r in self.factored_order():
|
|
1509
|
+
m = n // (p**r)
|
|
1510
|
+
for g, o in _unit_gens_primepowercase(p, r):
|
|
1511
|
+
x = g.crt(integer_mod.Mod(1, m))
|
|
1512
|
+
gens.append(x)
|
|
1513
|
+
orders.append(o)
|
|
1514
|
+
elif algorithm == 'pari':
|
|
1515
|
+
_, orders, gens = self.order().__pari__().znstar()
|
|
1516
|
+
gens = [self(g) for g in gens]
|
|
1517
|
+
orders = [integer.Integer(o) for o in orders]
|
|
1518
|
+
else:
|
|
1519
|
+
raise ValueError('unknown algorithm %r for computing the unit group' % algorithm)
|
|
1520
|
+
return AbelianGroupWithValues(gens, orders, values_group=self)
|
|
1521
|
+
|
|
1522
|
+
def random_element(self, bound=None):
|
|
1523
|
+
"""
|
|
1524
|
+
Return a random element of this ring.
|
|
1525
|
+
|
|
1526
|
+
INPUT:
|
|
1527
|
+
|
|
1528
|
+
- ``bound`` -- positive integer or ``None`` (the default); if given,
|
|
1529
|
+
return the coercion of an integer in the interval
|
|
1530
|
+
``[-bound, bound]`` into this ring
|
|
1531
|
+
|
|
1532
|
+
EXAMPLES::
|
|
1533
|
+
|
|
1534
|
+
sage: R = IntegerModRing(18)
|
|
1535
|
+
sage: R.random_element().parent() is R
|
|
1536
|
+
True
|
|
1537
|
+
sage: found = [False]*18
|
|
1538
|
+
sage: while not all(found):
|
|
1539
|
+
....: found[R.random_element()] = True
|
|
1540
|
+
|
|
1541
|
+
We test the ``bound`` option::
|
|
1542
|
+
|
|
1543
|
+
sage: R.random_element(2) in [R(-2), R(-1), R(0), R(1), R(2)]
|
|
1544
|
+
True
|
|
1545
|
+
"""
|
|
1546
|
+
if bound is not None:
|
|
1547
|
+
a = random.randint(-bound, bound)
|
|
1548
|
+
else:
|
|
1549
|
+
a = random.randint(0, self.order() - 1)
|
|
1550
|
+
return self(a)
|
|
1551
|
+
|
|
1552
|
+
@staticmethod
|
|
1553
|
+
def _lift_residue_field_root(p, e, f, fprime, root):
|
|
1554
|
+
"""Lifts a root of f
|
|
1555
|
+
|
|
1556
|
+
INPUT:
|
|
1557
|
+
|
|
1558
|
+
- ``p`` -- integer, a prime number
|
|
1559
|
+
- ``e`` -- positive integer
|
|
1560
|
+
- ``f`` -- polynomial with coefficients in ``IntegerModRing(p**e)``
|
|
1561
|
+
- ``fprime`` -- derivative of ``f``
|
|
1562
|
+
- ``root`` -- Element of ``IntegerModRing(p)`` with ``f(root) = 0``
|
|
1563
|
+
|
|
1564
|
+
OUTPUT: iterable of roots of ``f`` modulo ``p**e``. Each root is an
|
|
1565
|
+
``IntegerModRing(p**e)`` element.
|
|
1566
|
+
|
|
1567
|
+
TESTS::
|
|
1568
|
+
|
|
1569
|
+
sage: R = Zmod(2)
|
|
1570
|
+
sage: S.<x> = R[]
|
|
1571
|
+
sage: R._lift_residue_field_root(2, 1, S.zero(), S.zero(), R(0))
|
|
1572
|
+
(0,)
|
|
1573
|
+
|
|
1574
|
+
Lifting roots of the zero polynomial::
|
|
1575
|
+
|
|
1576
|
+
sage: R = Zmod(41)
|
|
1577
|
+
sage: S.<x> = R[]
|
|
1578
|
+
sage: R._lift_residue_field_root(41, 1, S.zero(), S.zero(), R(12))
|
|
1579
|
+
(12,)
|
|
1580
|
+
sage: R = Zmod(5**2)
|
|
1581
|
+
sage: S.<x> = R[]
|
|
1582
|
+
sage: R._lift_residue_field_root(5, 2, S.zero(), S.zero(), R(2))
|
|
1583
|
+
[2, 7, 12, 17, 22]
|
|
1584
|
+
sage: R = Zmod(2**3)
|
|
1585
|
+
sage: S.<x> = R[]
|
|
1586
|
+
sage: R._lift_residue_field_root(2, 3, S.zero(), S.zero(), R(1))
|
|
1587
|
+
[1, 5, 3, 7]
|
|
1588
|
+
|
|
1589
|
+
Trivial case where ``e == 1``::
|
|
1590
|
+
|
|
1591
|
+
sage: R = Zmod(41)
|
|
1592
|
+
sage: S.<x> = R[]
|
|
1593
|
+
sage: f = x^2 - 2
|
|
1594
|
+
sage: R._lift_residue_field_root(41, 1, f, f.derivative(), R(17))
|
|
1595
|
+
(17,)
|
|
1596
|
+
|
|
1597
|
+
sage: R = Zmod(43)
|
|
1598
|
+
sage: S.<x> = R[]
|
|
1599
|
+
sage: f = x^43 - 3
|
|
1600
|
+
sage: R._lift_residue_field_root(43, 1, f, f.derivative(), R(3))
|
|
1601
|
+
(3,)
|
|
1602
|
+
|
|
1603
|
+
Non-singular cases with one step of lifting::
|
|
1604
|
+
|
|
1605
|
+
sage: R = Zmod(2**2)
|
|
1606
|
+
sage: S.<x> = R[]
|
|
1607
|
+
sage: f = x - 1
|
|
1608
|
+
sage: R._lift_residue_field_root(2, 2, f, f.derivative(), R(1))
|
|
1609
|
+
(1,)
|
|
1610
|
+
sage: f = x - 3
|
|
1611
|
+
sage: R._lift_residue_field_root(2, 2, f, f.derivative(), R(1))
|
|
1612
|
+
(3,)
|
|
1613
|
+
|
|
1614
|
+
sage: # needs sage.libs.pari
|
|
1615
|
+
sage: R = Zmod(4001**2)
|
|
1616
|
+
sage: S.<x> = R[]
|
|
1617
|
+
sage: f = x^3 - 2
|
|
1618
|
+
sage: R._lift_residue_field_root(4001, 2, f, f.derivative(), R(3981))
|
|
1619
|
+
(5309307,)
|
|
1620
|
+
sage: f = x^3 - 3
|
|
1621
|
+
sage: R._lift_residue_field_root(4001, 2, f, f.derivative(), R(1091))
|
|
1622
|
+
(11035849,)
|
|
1623
|
+
|
|
1624
|
+
Non-singular cases with multiple steps of lifting::
|
|
1625
|
+
|
|
1626
|
+
sage: R = Zmod(2**10)
|
|
1627
|
+
sage: S.<x> = R[]
|
|
1628
|
+
sage: f = x + 1
|
|
1629
|
+
sage: R._lift_residue_field_root(2, 10, f, f.derivative(), Zmod(2)(1))
|
|
1630
|
+
(1023,)
|
|
1631
|
+
|
|
1632
|
+
sage: R = Zmod(2**16)
|
|
1633
|
+
sage: S.<x> = R[]
|
|
1634
|
+
sage: f = x + 1
|
|
1635
|
+
sage: R._lift_residue_field_root(2, 16, f, f.derivative(), Zmod(2)(1))
|
|
1636
|
+
(65535,)
|
|
1637
|
+
|
|
1638
|
+
sage: # needs sage.libs.pari
|
|
1639
|
+
sage: R = Zmod(7**4)
|
|
1640
|
+
sage: S.<x> = R[]
|
|
1641
|
+
sage: f = x^4 - 2
|
|
1642
|
+
sage: R._lift_residue_field_root(7, 4, f, f.derivative(), Zmod(7)(2))
|
|
1643
|
+
(121,)
|
|
1644
|
+
|
|
1645
|
+
Singular cases::
|
|
1646
|
+
|
|
1647
|
+
sage: R = Zmod(2**3)
|
|
1648
|
+
sage: S.<x> = R[]
|
|
1649
|
+
sage: f = x^2 - 1
|
|
1650
|
+
sage: R._lift_residue_field_root(2, 3, f, f.derivative(), Zmod(2)(1))
|
|
1651
|
+
[1, 5, 3, 7]
|
|
1652
|
+
sage: f = 2*x
|
|
1653
|
+
sage: R._lift_residue_field_root(2, 3, f, f.derivative(), Zmod(2)(0))
|
|
1654
|
+
[0, 4]
|
|
1655
|
+
|
|
1656
|
+
sage: R = Zmod(11**2)
|
|
1657
|
+
sage: S.<x> = R[]
|
|
1658
|
+
sage: f = x^2 + 13*x + 1
|
|
1659
|
+
sage: R._lift_residue_field_root(11, 2, f, f.derivative(), Zmod(11)(10))
|
|
1660
|
+
[]
|
|
1661
|
+
|
|
1662
|
+
sage: # needs sage.libs.pari
|
|
1663
|
+
sage: R = Zmod(11**3)
|
|
1664
|
+
sage: S.<x> = R[]
|
|
1665
|
+
sage: f = x^2 + 123*x + 1
|
|
1666
|
+
sage: R._lift_residue_field_root(11, 3, f, f.derivative(), Zmod(11)(10))
|
|
1667
|
+
[10, 131, 252, 373, 494, 615, 736, 857, 978, 1099, 1220, 109, 230, 351, 472, 593, 714, 835, 956, 1077, 1198, 1319]
|
|
1668
|
+
"""
|
|
1669
|
+
if e == 1:
|
|
1670
|
+
# Nothing to do
|
|
1671
|
+
return (root,)
|
|
1672
|
+
deriv = fprime(root)
|
|
1673
|
+
if deriv:
|
|
1674
|
+
# Unique lift, use Newton iteration
|
|
1675
|
+
prec = 1
|
|
1676
|
+
while True:
|
|
1677
|
+
prec = min(2*prec, e)
|
|
1678
|
+
Zp_prec = Zmod(p**prec)
|
|
1679
|
+
root = Zp_prec(root.lift())
|
|
1680
|
+
deriv = fprime(root)
|
|
1681
|
+
step = f(root) / deriv
|
|
1682
|
+
root -= step
|
|
1683
|
+
if prec >= e:
|
|
1684
|
+
return (root,)
|
|
1685
|
+
else:
|
|
1686
|
+
# Non-unique lift, go one power at a time
|
|
1687
|
+
prec = 1
|
|
1688
|
+
new_power = 1
|
|
1689
|
+
new_mod = p
|
|
1690
|
+
current_roots = (root,)
|
|
1691
|
+
for _ in range(e - 1):
|
|
1692
|
+
prec += 1
|
|
1693
|
+
new_power = new_mod
|
|
1694
|
+
new_mod *= p
|
|
1695
|
+
new_roots = []
|
|
1696
|
+
Zp_prec = Zmod(new_mod)
|
|
1697
|
+
for rt in current_roots:
|
|
1698
|
+
rt = Zp_prec(rt.lift())
|
|
1699
|
+
if f(rt):
|
|
1700
|
+
continue
|
|
1701
|
+
new_roots.append(rt)
|
|
1702
|
+
for _ in range(p - 1):
|
|
1703
|
+
rt += new_power
|
|
1704
|
+
new_roots.append(rt)
|
|
1705
|
+
current_roots = new_roots
|
|
1706
|
+
|
|
1707
|
+
return current_roots
|
|
1708
|
+
|
|
1709
|
+
def _roots_univariate_polynomial(self, f, ring=None, multiplicities=True, algorithm=None):
|
|
1710
|
+
r"""
|
|
1711
|
+
Return the roots of ``f`` in the ring ``ring``.
|
|
1712
|
+
|
|
1713
|
+
INPUT:
|
|
1714
|
+
|
|
1715
|
+
- ``f`` - a polynomial defined over this ring
|
|
1716
|
+
|
|
1717
|
+
- ``ring`` - the ring to find roots in. Control flow elsewhere
|
|
1718
|
+
ensures that the only cases we need to handle are ``self`` and
|
|
1719
|
+
``None``. Otherwise we raise ``NotImplementedError``.
|
|
1720
|
+
|
|
1721
|
+
- ``multiplicities`` - bool (default: ``True``). If ``True``, return
|
|
1722
|
+
list of pairs `(r, n)`, where `r` is a root and `n` is its
|
|
1723
|
+
multiplicity. If ``False``, just return the unique roots, with no
|
|
1724
|
+
information about multiplicities. Multiplicities are only defined
|
|
1725
|
+
over fields, and this method raises ``NotImplementedError`` if this
|
|
1726
|
+
is ``True`` but the ring is not a field.
|
|
1727
|
+
|
|
1728
|
+
- ``algorithm`` - ignored
|
|
1729
|
+
|
|
1730
|
+
ALGORITHM:
|
|
1731
|
+
|
|
1732
|
+
The algorithm is adapted from [Gou2020]_, section 4.5, and [Coh1993]_,
|
|
1733
|
+
section 3.5.3. It is a combination of the Chinese Remainder Theorem
|
|
1734
|
+
and Hensel's lemma. As a base case, if `N` is prime, then we find
|
|
1735
|
+
roots by factoring `f`. If `N` is a prime power `p^e`, then we find
|
|
1736
|
+
roots modulo `p` and lift them. Finally, for general `N`, we first
|
|
1737
|
+
factor the modulus `N` into prime powers, list all roots modulo those
|
|
1738
|
+
prime powers, and combine the roots using the Chinese Remainder
|
|
1739
|
+
Theorem.
|
|
1740
|
+
|
|
1741
|
+
Suppose that we are trying to find roots modulo `p^e` and that `r` is
|
|
1742
|
+
a root of `f(x)` modulo `p`. The easy case is when `f'(r) \not\equiv
|
|
1743
|
+
0 \pmod{p}`, for then Hensel's lemma implies that there is a unique
|
|
1744
|
+
`r_e \in \Zmod{p^e}` with `r_e \equiv r \pmod{p}`.
|
|
1745
|
+
Moreover, this `r_e` can be found by applying Newton's method for
|
|
1746
|
+
numerically approximating roots. Each iteration of Newton's method
|
|
1747
|
+
doubles the precision to which the root is known.
|
|
1748
|
+
|
|
1749
|
+
But if `f'(r) \equiv 0 \pmod{p}`, then this is no longer true. In
|
|
1750
|
+
fact, in this case roots modulo `p^e` are not the same as `p`-adic
|
|
1751
|
+
roots, and finding all the latter does not guarantee that we have
|
|
1752
|
+
found all the former. For example, if `f(x) = 2x` and `p = 2`, then
|
|
1753
|
+
there is only one `p`-adic root, namely zero. But the solutions of
|
|
1754
|
+
`2x \equiv 0 \pmod{2^k}` are `0` and `2^{k-1}`; the former lifts to
|
|
1755
|
+
two roots modulo `2^{k+1}`, namely `0` and `2^k`, while the latter
|
|
1756
|
+
does not lift at all. We handle this case by lifting one power at a
|
|
1757
|
+
time. While we can no longer use Newton's method to solve for a lift,
|
|
1758
|
+
the Taylor series it is based on still yields constraints on the roots
|
|
1759
|
+
modulo `p^{k+1}`: If `r_k` is a root of `f` modulo `p^k`, then either
|
|
1760
|
+
every lift of `r_k` to `\Zmod{p^{k + 1}}` is a root of `f`
|
|
1761
|
+
modulo `p^{k+1}` or none of them are. Consequently we may find roots
|
|
1762
|
+
modulo `p^e` by lifting one power at a time.
|
|
1763
|
+
|
|
1764
|
+
When `f'(r) \equiv 0 \pmod{p}`, an alternative approach is to change
|
|
1765
|
+
variables, factor out the root, and then factor out powers of `p`.
|
|
1766
|
+
This has the advantage that it will eventually reach a situation where
|
|
1767
|
+
the lift converges quadratically, but it is not presently implemented.
|
|
1768
|
+
A different form of Hensel's lemma applies once we are close enough to
|
|
1769
|
+
a `p`-adic root (see [Gou2020]_, problem 120), but it seems delicate
|
|
1770
|
+
to use it directly to find all roots modulo `p^e` (consider our
|
|
1771
|
+
earlier example of `f(x) = 2x`), so we do not presently attempt to
|
|
1772
|
+
apply Hensel's lemma in this way.
|
|
1773
|
+
|
|
1774
|
+
EXAMPLES::
|
|
1775
|
+
|
|
1776
|
+
sage: # needs sage.libs.pari
|
|
1777
|
+
sage: R.<x> = Zmod(41)[]
|
|
1778
|
+
sage: (x^3 + x).roots()
|
|
1779
|
+
[(0, 1), (32, 1), (9, 1)]
|
|
1780
|
+
sage: (x^3 + x).roots(multiplicities=False)
|
|
1781
|
+
[0, 32, 9]
|
|
1782
|
+
sage: (x^6 + x^5 + 9*x^4 + 20*x^3 + 3*x^2 + 18*x + 7).roots()
|
|
1783
|
+
[(19, 1), (20, 2), (21, 3)]
|
|
1784
|
+
sage: (x^6 + x^5 + 9*x^4 + 20*x^3 + 3*x^2 + 18*x + 7).roots(multiplicities=False)
|
|
1785
|
+
[19, 20, 21]
|
|
1786
|
+
|
|
1787
|
+
We can find roots without multiplicities over a ring whose modulus is
|
|
1788
|
+
a prime power, even a big power:
|
|
1789
|
+
|
|
1790
|
+
sage: # needs sage.libs.pari
|
|
1791
|
+
sage: R.<x> = Zmod(7^3)[]
|
|
1792
|
+
sage: (x^2 + x + 1).roots(multiplicities=False)
|
|
1793
|
+
[18, 324]
|
|
1794
|
+
sage: R.<x> = Zmod(2^50)[]
|
|
1795
|
+
sage: (x + 1).roots(multiplicities=False)
|
|
1796
|
+
[1125899906842623]
|
|
1797
|
+
|
|
1798
|
+
We can also find roots without multiplicities over a ring whose modulus
|
|
1799
|
+
is a product of primes or prime powers:
|
|
1800
|
+
|
|
1801
|
+
sage: R.<x> = Zmod(60)[]
|
|
1802
|
+
sage: (x^2 - 1).roots(multiplicities=False) # needs sage.libs.pari
|
|
1803
|
+
[29, 41, 49, 1, 59, 11, 19, 31]
|
|
1804
|
+
|
|
1805
|
+
We may also ask for roots modulo a quotient of the ring over which the
|
|
1806
|
+
polynomial is defined:
|
|
1807
|
+
|
|
1808
|
+
sage: R.<x> = Zmod(120)[]
|
|
1809
|
+
sage: (x^2 - 1).roots(multiplicities=False) # needs sage.libs.pari
|
|
1810
|
+
[89, 41, 49, 1, 29, 101, 109, 61, 59, 11, 19, 91, 119, 71, 79, 31]
|
|
1811
|
+
sage: (x^2 - 1).roots(Zmod(60), multiplicities=False) # needs sage.libs.pari
|
|
1812
|
+
[29, 41, 49, 1, 59, 11, 19, 31]
|
|
1813
|
+
|
|
1814
|
+
TESTS::
|
|
1815
|
+
|
|
1816
|
+
sage: R.<x> = Zmod(2)[]
|
|
1817
|
+
sage: x.roots() # needs sage.libs.pari
|
|
1818
|
+
[(0, 1)]
|
|
1819
|
+
|
|
1820
|
+
Test polynomials with content:
|
|
1821
|
+
|
|
1822
|
+
sage: R.<x> = Zmod(4)[]
|
|
1823
|
+
sage: (2*x).roots(multiplicities=False) # needs sage.libs.pari
|
|
1824
|
+
[0, 2]
|
|
1825
|
+
|
|
1826
|
+
sage: R.<x> = Zmod(6)[]
|
|
1827
|
+
sage: (3*x).roots(multiplicities=False) # needs sage.libs.pari
|
|
1828
|
+
[0, 4, 2]
|
|
1829
|
+
|
|
1830
|
+
Test polynomial with many roots:
|
|
1831
|
+
|
|
1832
|
+
sage: R.<x> = Zmod(6)[]
|
|
1833
|
+
sage: f = x * (x - 1) * (x - 2) * (x - 3) * (x - 4) * (x - 5)
|
|
1834
|
+
sage: len(f.roots(multiplicities=False)) # needs sage.libs.pari
|
|
1835
|
+
6
|
|
1836
|
+
|
|
1837
|
+
Test finding roots over large prime powers:
|
|
1838
|
+
|
|
1839
|
+
sage: R.<x> = Zmod(2**16)[]
|
|
1840
|
+
sage: (x^3 + 5).roots(multiplicities=False) # needs sage.libs.pari
|
|
1841
|
+
[45475]
|
|
1842
|
+
sage: (x^2 + 46*x + 1).roots(multiplicities=False) # needs sage.libs.pari
|
|
1843
|
+
[421, 33189, 16805, 49573, 8613, 41381, 24997, 57765, 7725, 40493, 24109, 56877, 15917, 48685, 32301, 65069]
|
|
1844
|
+
|
|
1845
|
+
sage: # needs sage.libs.pari
|
|
1846
|
+
sage: R.<x> = Zmod(3**16)[]
|
|
1847
|
+
sage: (x^2 + 2).roots(multiplicities=False)
|
|
1848
|
+
[24620738, 18425983]
|
|
1849
|
+
sage: (x^2 + 11*x + 1).roots(multiplicities=False)
|
|
1850
|
+
[633836, 14982743, 29331650, 13715060, 28063967, 42412874]
|
|
1851
|
+
sage: (x^3 + 8).roots(multiplicities=False)
|
|
1852
|
+
[14348905, 28697812, 43046719]
|
|
1853
|
+
|
|
1854
|
+
Test some larger primes:
|
|
1855
|
+
|
|
1856
|
+
sage: # needs sage.libs.pari
|
|
1857
|
+
sage: R.<x> = Zmod(41**4)[]
|
|
1858
|
+
sage: (x^2 + 2).roots(multiplicities=False)
|
|
1859
|
+
[2208905, 616856]
|
|
1860
|
+
sage: R.<x> = Zmod(43**4)[]
|
|
1861
|
+
sage: (x^2 + 3).roots(multiplicities=False)
|
|
1862
|
+
[3269879, 148922]
|
|
1863
|
+
|
|
1864
|
+
We can't find roots with multiplicities in non-fields:
|
|
1865
|
+
|
|
1866
|
+
sage: # needs sage.libs.pari
|
|
1867
|
+
sage: R.<x> = Zmod(6)[]
|
|
1868
|
+
sage: (x + 1).roots()
|
|
1869
|
+
Traceback (most recent call last):
|
|
1870
|
+
...
|
|
1871
|
+
NotImplementedError: root finding with multiplicities for this polynomial not implemented (try the multiplicities=False option)
|
|
1872
|
+
sage: R.<x> = Zmod(8)[]
|
|
1873
|
+
sage: (x + 1).roots()
|
|
1874
|
+
Traceback (most recent call last):
|
|
1875
|
+
...
|
|
1876
|
+
NotImplementedError: root finding with multiplicities for this polynomial not implemented (try the multiplicities=False option)
|
|
1877
|
+
sage: R.<x> = Zmod(12)[]
|
|
1878
|
+
sage: (x + 1).roots()
|
|
1879
|
+
Traceback (most recent call last):
|
|
1880
|
+
...
|
|
1881
|
+
NotImplementedError: root finding with multiplicities for this polynomial not implemented (try the multiplicities=False option)
|
|
1882
|
+
|
|
1883
|
+
The zero polynomial has every residue class as a root, but we don't
|
|
1884
|
+
support multiplicities even over fields (they would all be infinite).
|
|
1885
|
+
|
|
1886
|
+
sage: R.<x> = Zmod(6)[]
|
|
1887
|
+
sage: R.zero().roots()
|
|
1888
|
+
Traceback (most recent call last):
|
|
1889
|
+
...
|
|
1890
|
+
NotImplementedError: root finding with multiplicities for this polynomial not implemented (try the multiplicities=False option)
|
|
1891
|
+
sage: R.zero().roots(multiplicities=False)
|
|
1892
|
+
[0, 1, 2, 3, 4, 5]
|
|
1893
|
+
|
|
1894
|
+
sage: R.<x> = Zmod(7)[]
|
|
1895
|
+
sage: R.zero().roots()
|
|
1896
|
+
Traceback (most recent call last):
|
|
1897
|
+
...
|
|
1898
|
+
NotImplementedError: root finding with multiplicities for this polynomial not implemented (try the multiplicities=False option)
|
|
1899
|
+
sage: R.zero().roots(multiplicities=False)
|
|
1900
|
+
[0, 1, 2, 3, 4, 5, 6]
|
|
1901
|
+
|
|
1902
|
+
sage: R.<x> = Zmod(8)[]
|
|
1903
|
+
sage: R.zero().roots()
|
|
1904
|
+
Traceback (most recent call last):
|
|
1905
|
+
...
|
|
1906
|
+
NotImplementedError: root finding with multiplicities for this polynomial not implemented (try the multiplicities=False option)
|
|
1907
|
+
sage: R.zero().roots(multiplicities=False)
|
|
1908
|
+
[0, 1, 2, 3, 4, 5, 6, 7]
|
|
1909
|
+
|
|
1910
|
+
This method doesn't support root-finding over rings that aren't Z/nZ:
|
|
1911
|
+
|
|
1912
|
+
sage: R.<x> = Zmod(120)[]
|
|
1913
|
+
sage: f = x^2 - 1
|
|
1914
|
+
sage: f.base_ring()._roots_univariate_polynomial(f, ring=RR, multiplicities=False)
|
|
1915
|
+
Traceback (most recent call last):
|
|
1916
|
+
...
|
|
1917
|
+
NotImplementedError
|
|
1918
|
+
|
|
1919
|
+
Sage allows us to coerce polynomials from one modulus to another,
|
|
1920
|
+
and that makes the following defined:
|
|
1921
|
+
|
|
1922
|
+
sage: # needs sage.libs.pari
|
|
1923
|
+
sage: R.<x> = Zmod(100)[]
|
|
1924
|
+
sage: (x^2 - 1).roots(Zmod(99), multiplicities=False) == (x^2 - 1).change_ring(Zmod(99)).roots(multiplicities=False)
|
|
1925
|
+
True
|
|
1926
|
+
"""
|
|
1927
|
+
|
|
1928
|
+
# This function only supports roots in an IntegerModRing
|
|
1929
|
+
if ring is not self and ring is not None:
|
|
1930
|
+
raise NotImplementedError
|
|
1931
|
+
|
|
1932
|
+
deg = f.degree()
|
|
1933
|
+
|
|
1934
|
+
if multiplicities:
|
|
1935
|
+
if deg < 0 or not self.is_field():
|
|
1936
|
+
raise NotImplementedError(
|
|
1937
|
+
"root finding with multiplicities for this polynomial not"
|
|
1938
|
+
" implemented (try the multiplicities=False option)"
|
|
1939
|
+
)
|
|
1940
|
+
# Roots of non-zero polynomial over finite fields by factorization
|
|
1941
|
+
return f._roots_from_factorization(f.factor(), multiplicities)
|
|
1942
|
+
|
|
1943
|
+
# Zero polynomial is a base case
|
|
1944
|
+
if deg < 0:
|
|
1945
|
+
# All residue classes are roots of the zero polynomial
|
|
1946
|
+
return [*map(self, range(self.cardinality()))]
|
|
1947
|
+
|
|
1948
|
+
# Finite fields are a base case
|
|
1949
|
+
if self.is_field():
|
|
1950
|
+
return f._roots_from_factorization(f.factor(), False)
|
|
1951
|
+
|
|
1952
|
+
# Otherwise, find roots modulo each prime power
|
|
1953
|
+
fac = self.factored_order()
|
|
1954
|
+
prime_power_roots = []
|
|
1955
|
+
for p, e in fac:
|
|
1956
|
+
Zpe = Zmod(p**e)
|
|
1957
|
+
fpe = f.change_ring(Zpe)
|
|
1958
|
+
fpe_prime = fpe.derivative()
|
|
1959
|
+
fp = fpe.change_ring(Zmod(p))
|
|
1960
|
+
|
|
1961
|
+
mod_p_roots = fp.roots(multiplicities=False)
|
|
1962
|
+
|
|
1963
|
+
this_prime_power = []
|
|
1964
|
+
for root in mod_p_roots:
|
|
1965
|
+
this_prime_power.extend(
|
|
1966
|
+
self._lift_residue_field_root(p, e, fpe, fpe_prime, root)
|
|
1967
|
+
)
|
|
1968
|
+
prime_power_roots.append(this_prime_power)
|
|
1969
|
+
|
|
1970
|
+
# Combine using Chinese Remainder Theorem
|
|
1971
|
+
ppwr_basis = CRT_basis([p**e for p, e in fac])
|
|
1972
|
+
result = []
|
|
1973
|
+
for res in cartesian_product_iterator(prime_power_roots):
|
|
1974
|
+
root = self.zero()
|
|
1975
|
+
for c, x in zip(ppwr_basis, res):
|
|
1976
|
+
root += c*x.lift()
|
|
1977
|
+
result.append(root)
|
|
1978
|
+
return result
|
|
1979
|
+
|
|
1980
|
+
#######################################################
|
|
1981
|
+
# Suppose for interfaces
|
|
1982
|
+
#######################################################
|
|
1983
|
+
def _gap_init_(self):
|
|
1984
|
+
"""
|
|
1985
|
+
EXAMPLES::
|
|
1986
|
+
|
|
1987
|
+
sage: R = Integers(12345678900)
|
|
1988
|
+
sage: R
|
|
1989
|
+
Ring of integers modulo 12345678900
|
|
1990
|
+
sage: gap(R) # indirect doctest # needs sage.libs.gap
|
|
1991
|
+
(Integers mod 12345678900)
|
|
1992
|
+
"""
|
|
1993
|
+
return 'ZmodnZ({})'.format(self.order())
|
|
1994
|
+
|
|
1995
|
+
def _magma_init_(self, magma):
|
|
1996
|
+
"""
|
|
1997
|
+
EXAMPLES::
|
|
1998
|
+
|
|
1999
|
+
sage: R = Integers(12345678900)
|
|
2000
|
+
sage: R
|
|
2001
|
+
Ring of integers modulo 12345678900
|
|
2002
|
+
sage: magma(R) # indirect doctest, optional - magma
|
|
2003
|
+
Residue class ring of integers modulo 12345678900
|
|
2004
|
+
"""
|
|
2005
|
+
return 'Integers({})'.format(self.order())
|
|
2006
|
+
|
|
2007
|
+
def degree(self):
|
|
2008
|
+
"""
|
|
2009
|
+
Return 1.
|
|
2010
|
+
|
|
2011
|
+
EXAMPLES::
|
|
2012
|
+
|
|
2013
|
+
sage: R = Integers(12345678900)
|
|
2014
|
+
sage: R.degree()
|
|
2015
|
+
1
|
|
2016
|
+
"""
|
|
2017
|
+
return integer.Integer(1)
|
|
2018
|
+
|
|
2019
|
+
|
|
2020
|
+
# Register unpickling methods for backward compatibility.
|
|
2021
|
+
|
|
2022
|
+
from sage.misc.persist import register_unpickle_override
|
|
2023
|
+
register_unpickle_override('sage.rings.integer_mod_ring', 'IntegerModRing_generic', IntegerModRing_generic)
|
|
2024
|
+
|
|
2025
|
+
|
|
2026
|
+
def crt(v):
|
|
2027
|
+
"""
|
|
2028
|
+
INPUT:
|
|
2029
|
+
|
|
2030
|
+
- ``v`` -- (list) a lift of elements of ``rings.IntegerMod(n)``, for
|
|
2031
|
+
various coprime moduli ``n``
|
|
2032
|
+
|
|
2033
|
+
EXAMPLES::
|
|
2034
|
+
|
|
2035
|
+
sage: from sage.rings.finite_rings.integer_mod_ring import crt
|
|
2036
|
+
sage: crt([mod(3, 8), mod(1,19), mod(7, 15)])
|
|
2037
|
+
1027
|
|
2038
|
+
"""
|
|
2039
|
+
if len(v) == 0:
|
|
2040
|
+
return IntegerModRing(1).one()
|
|
2041
|
+
x = v[0]
|
|
2042
|
+
for i in range(1, len(v)):
|
|
2043
|
+
x = x.crt(v[i])
|
|
2044
|
+
return x
|