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,3550 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
# sage.doctest: needs sage.libs.pari sage.rings.number_field
|
|
3
|
+
"""
|
|
4
|
+
Ideals of number fields
|
|
5
|
+
|
|
6
|
+
AUTHORS:
|
|
7
|
+
|
|
8
|
+
- Steven Sivek (2005-05-16): initial version
|
|
9
|
+
- William Stein (2007-09-06): vastly improved the doctesting
|
|
10
|
+
- William Stein and John Cremona (2007-01-28): new class
|
|
11
|
+
NumberFieldFractionalIdeal now used for all except the 0 ideal
|
|
12
|
+
- Radoslav Kirov and Alyson Deines (2010-06-22):
|
|
13
|
+
prime_to_S_part, is_S_unit, is_S_integral
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
# ****************************************************************************
|
|
17
|
+
# Copyright (C) 2004 William Stein <wstein@gmail.com>
|
|
18
|
+
#
|
|
19
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
20
|
+
#
|
|
21
|
+
# This code is distributed in the hope that it will be useful,
|
|
22
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
23
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
24
|
+
# General Public License for more details.
|
|
25
|
+
#
|
|
26
|
+
# The full text of the GPL is available at:
|
|
27
|
+
#
|
|
28
|
+
# https://www.gnu.org/licenses/
|
|
29
|
+
# ****************************************************************************
|
|
30
|
+
|
|
31
|
+
SMALL_DISC = 1000000
|
|
32
|
+
|
|
33
|
+
import sage.misc.latex as latex
|
|
34
|
+
|
|
35
|
+
import sage.rings.rational_field as rational_field
|
|
36
|
+
import sage.rings.integer_ring as integer_ring
|
|
37
|
+
from sage.arith.misc import kronecker as kronecker_symbol
|
|
38
|
+
from sage.arith.misc import GCD as gcd
|
|
39
|
+
from sage.rings.finite_rings.finite_field_constructor import FiniteField
|
|
40
|
+
|
|
41
|
+
from sage.rings.ideal import Ideal_generic, Ideal_fractional
|
|
42
|
+
from sage.misc.misc_c import prod
|
|
43
|
+
from sage.misc.mrange import xmrange_iter
|
|
44
|
+
from sage.misc.cachefunc import cached_method
|
|
45
|
+
from sage.structure.element import MultiplicativeGroupElement
|
|
46
|
+
from sage.structure.factorization import Factorization
|
|
47
|
+
from sage.structure.sequence import Sequence
|
|
48
|
+
from sage.structure.proof.proof import get_flag
|
|
49
|
+
from sage.structure.richcmp import richcmp
|
|
50
|
+
|
|
51
|
+
QQ = rational_field.RationalField()
|
|
52
|
+
ZZ = integer_ring.IntegerRing()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class NumberFieldIdeal(Ideal_generic):
|
|
56
|
+
"""
|
|
57
|
+
An ideal of a number field.
|
|
58
|
+
|
|
59
|
+
EXAMPLES::
|
|
60
|
+
|
|
61
|
+
sage: x = polygen(ZZ)
|
|
62
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
63
|
+
sage: K.ideal(7)
|
|
64
|
+
Fractional ideal (7)
|
|
65
|
+
|
|
66
|
+
Initialization from PARI::
|
|
67
|
+
|
|
68
|
+
sage: K.ideal(pari(7))
|
|
69
|
+
Fractional ideal (7)
|
|
70
|
+
sage: K.ideal(pari(4), pari(4 + 2*i))
|
|
71
|
+
Fractional ideal (2)
|
|
72
|
+
sage: K.ideal(pari("i + 2"))
|
|
73
|
+
Fractional ideal (i + 2)
|
|
74
|
+
sage: K.ideal(pari("[3,0;0,3]"))
|
|
75
|
+
Fractional ideal (3)
|
|
76
|
+
sage: F = pari(K).idealprimedec(5)
|
|
77
|
+
sage: K.ideal(F[0])
|
|
78
|
+
Fractional ideal (-2*i - 1)
|
|
79
|
+
|
|
80
|
+
TESTS:
|
|
81
|
+
|
|
82
|
+
Check that ``_pari_prime`` is set when initializing from a PARI
|
|
83
|
+
prime ideal::
|
|
84
|
+
|
|
85
|
+
sage: K.ideal(pari(K).idealprimedec(5)[0])._pari_prime
|
|
86
|
+
[5, [-2, 1]~, 1, 1, [2, -1; 1, 2]]
|
|
87
|
+
|
|
88
|
+
Number fields defined by non-monic and non-integral
|
|
89
|
+
polynomials are supported (:issue:`252`)::
|
|
90
|
+
|
|
91
|
+
sage: K.<a> = NumberField(2*x^2 - 1/3)
|
|
92
|
+
sage: I = K.ideal(a); I
|
|
93
|
+
Fractional ideal (a)
|
|
94
|
+
sage: I.norm()
|
|
95
|
+
1/6
|
|
96
|
+
"""
|
|
97
|
+
def __init__(self, field, gens, coerce=True):
|
|
98
|
+
"""
|
|
99
|
+
INPUT:
|
|
100
|
+
|
|
101
|
+
- ``field`` -- a number field
|
|
102
|
+
|
|
103
|
+
- ``gens`` -- list of :class:`NumberFieldElement` objects belonging to
|
|
104
|
+
the field
|
|
105
|
+
|
|
106
|
+
TESTS:
|
|
107
|
+
|
|
108
|
+
We test that pickling works::
|
|
109
|
+
|
|
110
|
+
sage: x = polygen(ZZ)
|
|
111
|
+
sage: K.<a> = NumberField(x^2 - 5)
|
|
112
|
+
sage: I = K.ideal(2/(5+a))
|
|
113
|
+
sage: I == loads(dumps(I))
|
|
114
|
+
True
|
|
115
|
+
"""
|
|
116
|
+
from .number_field import NumberField_generic
|
|
117
|
+
if not isinstance(field, NumberField_generic):
|
|
118
|
+
raise TypeError("field (=%s) must be a number field." % field)
|
|
119
|
+
|
|
120
|
+
if len(gens) == 1 and isinstance(gens[0], (list, tuple)):
|
|
121
|
+
gens = gens[0]
|
|
122
|
+
from cypari2.gen import Gen as pari_gen
|
|
123
|
+
if len(gens) == 1 and isinstance(gens[0], pari_gen):
|
|
124
|
+
# Init from PARI
|
|
125
|
+
gens = gens[0]
|
|
126
|
+
if gens.type() == "t_MAT":
|
|
127
|
+
# Assume columns are generators
|
|
128
|
+
gens = [field(x, check=False) for x in field.pari_zk() * gens]
|
|
129
|
+
elif gens.type() == "t_VEC":
|
|
130
|
+
# Assume prime ideal form
|
|
131
|
+
self._pari_prime = gens
|
|
132
|
+
gens = [ZZ(gens.pr_get_p()), field(gens.pr_get_gen())]
|
|
133
|
+
else:
|
|
134
|
+
# Assume one element of the field
|
|
135
|
+
gens = [field(gens, check=False)]
|
|
136
|
+
if len(gens) == 0:
|
|
137
|
+
raise ValueError("gens must have length at least 1 (zero ideal is not a fractional ideal)")
|
|
138
|
+
Ideal_generic.__init__(self, field, gens, coerce)
|
|
139
|
+
if field.absolute_degree() == 2:
|
|
140
|
+
self.quadratic_form = self._quadratic_form
|
|
141
|
+
|
|
142
|
+
def _magma_init_(self, magma):
|
|
143
|
+
"""
|
|
144
|
+
Return Magma version of this ideal.
|
|
145
|
+
|
|
146
|
+
INPUT:
|
|
147
|
+
|
|
148
|
+
- ``magma`` -- a Magma interpreter
|
|
149
|
+
|
|
150
|
+
OUTPUT: :class:`MagmaElement` corresponding to this ideal
|
|
151
|
+
|
|
152
|
+
EXAMPLES::
|
|
153
|
+
|
|
154
|
+
sage: x = polygen(ZZ)
|
|
155
|
+
sage: K.<a> = NumberField(x^3 + 2) # optional - magma
|
|
156
|
+
sage: I = K.ideal(5) # optional - magma
|
|
157
|
+
sage: I._magma_init_(magma) # optional - magma
|
|
158
|
+
'(_sage_[...]![5, 0, 0]) * _sage_[...]'
|
|
159
|
+
"""
|
|
160
|
+
O = magma(self.number_field().maximal_order())
|
|
161
|
+
g = self.gens()[0]
|
|
162
|
+
ans = magma(g) * O
|
|
163
|
+
for g in self.gens()[1:]:
|
|
164
|
+
ans += magma(g) * O
|
|
165
|
+
return '+'.join('%s * %s' % (g._magma_init_(magma), O.name())
|
|
166
|
+
for g in self.gens())
|
|
167
|
+
|
|
168
|
+
def __hash__(self):
|
|
169
|
+
"""
|
|
170
|
+
EXAMPLES::
|
|
171
|
+
|
|
172
|
+
sage: x = polygen(ZZ)
|
|
173
|
+
sage: NumberField(x^2 + 1, 'a').ideal(7).__hash__() # random
|
|
174
|
+
7806919040325273549
|
|
175
|
+
"""
|
|
176
|
+
try:
|
|
177
|
+
return self._hash
|
|
178
|
+
except AttributeError:
|
|
179
|
+
# At some point in the future (e.g., for relative extensions),
|
|
180
|
+
# we'll likely have to consider other hashes.
|
|
181
|
+
self._hash = hash(self.pari_hnf())
|
|
182
|
+
return self._hash
|
|
183
|
+
|
|
184
|
+
def _latex_(self):
|
|
185
|
+
r"""
|
|
186
|
+
EXAMPLES::
|
|
187
|
+
|
|
188
|
+
sage: x = polygen(ZZ)
|
|
189
|
+
sage: K.<a> = NumberField(x^2 + 23)
|
|
190
|
+
sage: K.ideal([2, 1/2*a - 1/2])._latex_()
|
|
191
|
+
'\\left(2, \\frac{1}{2} a - \\frac{1}{2}\\right)'
|
|
192
|
+
sage: latex(K.ideal([2, 1/2*a - 1/2]))
|
|
193
|
+
\left(2, \frac{1}{2} a - \frac{1}{2}\right)
|
|
194
|
+
|
|
195
|
+
The gens are reduced only if the norm of the discriminant of
|
|
196
|
+
the defining polynomial is at most
|
|
197
|
+
sage.rings.number_field.number_field_ideal.SMALL_DISC::
|
|
198
|
+
|
|
199
|
+
sage: K.<a> = NumberField(x^2 + 902384092834); K
|
|
200
|
+
Number Field in a with defining polynomial x^2 + 902384092834
|
|
201
|
+
sage: I = K.factor(19)[0][0]; I._latex_()
|
|
202
|
+
'\\left(19\\right)'
|
|
203
|
+
|
|
204
|
+
We can make the generators reduced by increasing SMALL_DISC.
|
|
205
|
+
We had better also set proof to False, or computing reduced
|
|
206
|
+
gens could take too long::
|
|
207
|
+
|
|
208
|
+
sage: proof.number_field(False)
|
|
209
|
+
sage: sage.rings.number_field.number_field_ideal.SMALL_DISC = 10^20
|
|
210
|
+
sage: K.<a> = NumberField(x^4 + 3*x^2 - 17)
|
|
211
|
+
sage: K.ideal([17*a,17,17,17*a])._latex_()
|
|
212
|
+
'\\left(17\\right)'
|
|
213
|
+
|
|
214
|
+
TESTS:
|
|
215
|
+
|
|
216
|
+
Reset SMALL_DISC for continued testing::
|
|
217
|
+
|
|
218
|
+
sage: sage.rings.number_field.number_field_ideal.SMALL_DISC = 1000000
|
|
219
|
+
"""
|
|
220
|
+
return '\\left(%s\\right)' % (", ".join(map(latex.latex, self._gens_repr())))
|
|
221
|
+
|
|
222
|
+
def _richcmp_(self, other, op):
|
|
223
|
+
"""
|
|
224
|
+
Compare an ideal of a number field to something else.
|
|
225
|
+
|
|
226
|
+
REMARK:
|
|
227
|
+
|
|
228
|
+
By default, comparing ideals is the same as comparing
|
|
229
|
+
their generator list. But of course, different generators
|
|
230
|
+
can give rise to the same ideal. And this can easily
|
|
231
|
+
be detected using Hermite normal form.
|
|
232
|
+
|
|
233
|
+
As an implementation detail (this may change in the future),
|
|
234
|
+
the Hermite normal form is with respect to the integral basis
|
|
235
|
+
computed by Pari, and this may be different across different
|
|
236
|
+
runs and operating systems.
|
|
237
|
+
|
|
238
|
+
EXAMPLES::
|
|
239
|
+
|
|
240
|
+
sage: x = polygen(ZZ)
|
|
241
|
+
sage: K.<a> = NumberField(x^2 + 3); K
|
|
242
|
+
Number Field in a with defining polynomial x^2 + 3
|
|
243
|
+
sage: f = K.factor(15); f
|
|
244
|
+
(Fractional ideal (-a))^2 * (Fractional ideal (5))
|
|
245
|
+
sage: (f[0][0] < f[1][0]) # potentially random
|
|
246
|
+
True
|
|
247
|
+
sage: (f[0][0] == f[0][0])
|
|
248
|
+
True
|
|
249
|
+
sage: (f[1][0] > f[0][0])
|
|
250
|
+
True
|
|
251
|
+
sage: f[1][0] == 5
|
|
252
|
+
True
|
|
253
|
+
sage: f[1][0] == GF(7)(5)
|
|
254
|
+
False
|
|
255
|
+
|
|
256
|
+
TESTS::
|
|
257
|
+
|
|
258
|
+
sage: L.<b> = NumberField(x^8-x^4+1)
|
|
259
|
+
sage: F_2 = L.fractional_ideal(b^2-1)
|
|
260
|
+
sage: F_4 = L.fractional_ideal(b^4-1)
|
|
261
|
+
sage: F_2 == F_4
|
|
262
|
+
True
|
|
263
|
+
"""
|
|
264
|
+
if not isinstance(other, NumberFieldIdeal):
|
|
265
|
+
return NotImplemented
|
|
266
|
+
return richcmp(self.pari_hnf().sage(), other.pari_hnf().sage(), op)
|
|
267
|
+
|
|
268
|
+
def _mul_(self, other):
|
|
269
|
+
"""
|
|
270
|
+
Return the product of ``self`` and ``other``.
|
|
271
|
+
|
|
272
|
+
This is implemented by just calling PARI to do the multiplication.
|
|
273
|
+
|
|
274
|
+
EXAMPLES::
|
|
275
|
+
|
|
276
|
+
sage: # needs sage.symbolic
|
|
277
|
+
sage: K.<I>=QQ[i]
|
|
278
|
+
sage: A = K.ideal([5, 2 + I])
|
|
279
|
+
sage: B = K.ideal([13, 5 + 12*I])
|
|
280
|
+
sage: A*B
|
|
281
|
+
Fractional ideal (-4*I + 7)
|
|
282
|
+
sage: (K.ideal(3 + I) * K.ideal(7 + I)).gens()
|
|
283
|
+
(10*I + 20,)
|
|
284
|
+
|
|
285
|
+
TESTS:
|
|
286
|
+
|
|
287
|
+
Make sure that :issue:`13958` is fixed::
|
|
288
|
+
|
|
289
|
+
sage: I = QuadraticField(-5).ideal(2).factor()[0][0]
|
|
290
|
+
sage: I = I * I * I; I.ngens() == 2
|
|
291
|
+
True
|
|
292
|
+
sage: I = I^301; I.ngens() == 2
|
|
293
|
+
True
|
|
294
|
+
"""
|
|
295
|
+
if self.ngens() == 1 and other.ngens() == 1:
|
|
296
|
+
return self.ring().ideal(self.gen(0) * other.gen(0))
|
|
297
|
+
|
|
298
|
+
K = self.ring()
|
|
299
|
+
K_pari = K.pari_nf()
|
|
300
|
+
return K.ideal(K_pari.idealmul(self, other))
|
|
301
|
+
|
|
302
|
+
def coordinates(self, x):
|
|
303
|
+
r"""
|
|
304
|
+
Return the coordinate vector of `x` with respect to this ideal.
|
|
305
|
+
|
|
306
|
+
INPUT:
|
|
307
|
+
|
|
308
|
+
- ``x`` -- an element of the number field (or ring of integers) of this
|
|
309
|
+
ideal
|
|
310
|
+
|
|
311
|
+
OUTPUT:
|
|
312
|
+
|
|
313
|
+
List giving the coordinates of `x` with respect to the integral basis
|
|
314
|
+
of the ideal. In general this will be a vector of
|
|
315
|
+
rationals; it will consist of integers if and only if `x`
|
|
316
|
+
is in the ideal.
|
|
317
|
+
|
|
318
|
+
AUTHOR: John Cremona 2008-10-31
|
|
319
|
+
|
|
320
|
+
ALGORITHM:
|
|
321
|
+
|
|
322
|
+
Uses linear algebra.
|
|
323
|
+
Provides simpler implementations for :meth:`_contains_`,
|
|
324
|
+
:meth:`is_integral` and :meth:`smallest_integer`.
|
|
325
|
+
|
|
326
|
+
EXAMPLES::
|
|
327
|
+
|
|
328
|
+
sage: K.<i> = QuadraticField(-1)
|
|
329
|
+
sage: I = K.ideal(7 + 3*i)
|
|
330
|
+
sage: Ibasis = I.integral_basis(); Ibasis
|
|
331
|
+
[58, i + 41]
|
|
332
|
+
sage: a = 23 - 14*i
|
|
333
|
+
sage: acoords = I.coordinates(a); acoords
|
|
334
|
+
(597/58, -14)
|
|
335
|
+
sage: sum([Ibasis[j]*acoords[j] for j in range(2)]) == a
|
|
336
|
+
True
|
|
337
|
+
sage: b = 123 + 456*i
|
|
338
|
+
sage: bcoords = I.coordinates(b); bcoords
|
|
339
|
+
(-18573/58, 456)
|
|
340
|
+
sage: sum([Ibasis[j]*bcoords[j] for j in range(2)]) == b
|
|
341
|
+
True
|
|
342
|
+
sage: J = K.ideal(0)
|
|
343
|
+
sage: J.coordinates(0)
|
|
344
|
+
()
|
|
345
|
+
sage: J.coordinates(1)
|
|
346
|
+
Traceback (most recent call last):
|
|
347
|
+
...
|
|
348
|
+
TypeError: vector is not in free module
|
|
349
|
+
"""
|
|
350
|
+
K = self.number_field()
|
|
351
|
+
V, from_V, to_V = K.absolute_vector_space()
|
|
352
|
+
try:
|
|
353
|
+
return self.free_module().coordinate_vector(to_V(K(x)))
|
|
354
|
+
except ArithmeticError as e:
|
|
355
|
+
raise TypeError(e)
|
|
356
|
+
|
|
357
|
+
def _contains_(self, x):
|
|
358
|
+
"""
|
|
359
|
+
Return ``True`` if `x` is an element of this ideal.
|
|
360
|
+
|
|
361
|
+
This function is called (indirectly) when the ``in`` operator is used.
|
|
362
|
+
|
|
363
|
+
EXAMPLES::
|
|
364
|
+
|
|
365
|
+
sage: x = polygen(ZZ)
|
|
366
|
+
sage: K.<a> = NumberField(x^2 + 23); K
|
|
367
|
+
Number Field in a with defining polynomial x^2 + 23
|
|
368
|
+
sage: I = K.factor(13)[0][0]; I
|
|
369
|
+
Fractional ideal (13, 1/2*a + 9/2)
|
|
370
|
+
sage: I._contains_(a)
|
|
371
|
+
False
|
|
372
|
+
sage: a in I
|
|
373
|
+
False
|
|
374
|
+
sage: 13 in I
|
|
375
|
+
True
|
|
376
|
+
sage: 13/2 in I
|
|
377
|
+
False
|
|
378
|
+
sage: a + 9 in I
|
|
379
|
+
True
|
|
380
|
+
sage: J = K.ideal(0)
|
|
381
|
+
sage: 0 in J
|
|
382
|
+
True
|
|
383
|
+
sage: 1 in J
|
|
384
|
+
False
|
|
385
|
+
|
|
386
|
+
sage: K.<a> = NumberField(x^4 + 3); K
|
|
387
|
+
Number Field in a with defining polynomial x^4 + 3
|
|
388
|
+
sage: I = K.factor(13)[0][0]
|
|
389
|
+
sage: I # random sign in output
|
|
390
|
+
Fractional ideal (-2*a^2 - 1)
|
|
391
|
+
sage: 2/3 in I
|
|
392
|
+
False
|
|
393
|
+
sage: 1 in I
|
|
394
|
+
False
|
|
395
|
+
sage: 13 in I
|
|
396
|
+
True
|
|
397
|
+
sage: 1 in I*I^(-1)
|
|
398
|
+
True
|
|
399
|
+
sage: I # random sign in output
|
|
400
|
+
Fractional ideal (-2*a^2 - 1)
|
|
401
|
+
|
|
402
|
+
sage: K.<y>=NumberField(x^2-3)
|
|
403
|
+
sage: L.<z>=K.extension(x^2-5)
|
|
404
|
+
sage: 0 in L.ideal(0)
|
|
405
|
+
True
|
|
406
|
+
sage: 1 in L.ideal(0)
|
|
407
|
+
False
|
|
408
|
+
"""
|
|
409
|
+
return self.coordinates(x).denominator() == 1
|
|
410
|
+
|
|
411
|
+
def __elements_from_hnf(self, hnf):
|
|
412
|
+
"""
|
|
413
|
+
Convert a PARI Hermite normal form matrix to a list of
|
|
414
|
+
NumberFieldElements.
|
|
415
|
+
|
|
416
|
+
EXAMPLES::
|
|
417
|
+
|
|
418
|
+
sage: x = polygen(ZZ)
|
|
419
|
+
sage: K.<a> = NumberField(x^3 + 389); K
|
|
420
|
+
Number Field in a with defining polynomial x^3 + 389
|
|
421
|
+
sage: I = K.factor(17)[0][0]
|
|
422
|
+
sage: I # random sign in generator
|
|
423
|
+
Fractional ideal (-100*a^2 + 730*a - 5329)
|
|
424
|
+
sage: hnf = I.pari_hnf(); hnf
|
|
425
|
+
[17, 0, 13; 0, 17, 8; 0, 0, 1]
|
|
426
|
+
sage: I._NumberFieldIdeal__elements_from_hnf(hnf)
|
|
427
|
+
[17, 17*a, a^2 + 8*a + 13]
|
|
428
|
+
sage: I._NumberFieldIdeal__elements_from_hnf(hnf^(-1))
|
|
429
|
+
[1/17, 1/17*a, a^2 - 8/17*a - 13/17]
|
|
430
|
+
"""
|
|
431
|
+
K = self.number_field()
|
|
432
|
+
return [K(x, check=False) for x in K.pari_zk() * hnf]
|
|
433
|
+
|
|
434
|
+
def _repr_(self):
|
|
435
|
+
"""
|
|
436
|
+
Return the string representation of this number field ideal.
|
|
437
|
+
|
|
438
|
+
.. NOTE::
|
|
439
|
+
|
|
440
|
+
Only the zero ideal actually has type NumberFieldIdeal; all
|
|
441
|
+
others have type NumberFieldFractionalIdeal. So this function
|
|
442
|
+
will only ever be called on the zero ideal.
|
|
443
|
+
|
|
444
|
+
EXAMPLES::
|
|
445
|
+
|
|
446
|
+
sage: x = polygen(ZZ)
|
|
447
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
448
|
+
sage: I = K.ideal(0); I
|
|
449
|
+
Ideal (0) of Number Field in a with defining polynomial x^3 - 2
|
|
450
|
+
sage: type(I)
|
|
451
|
+
<class 'sage.rings.number_field.number_field_ideal.NumberFieldIdeal'>
|
|
452
|
+
sage: I = K.ideal(1); I
|
|
453
|
+
Fractional ideal (1)
|
|
454
|
+
sage: type(I)
|
|
455
|
+
<class 'sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal'>
|
|
456
|
+
sage: I = K.ideal(a); I
|
|
457
|
+
Fractional ideal (a)
|
|
458
|
+
sage: type(I)
|
|
459
|
+
<class 'sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal'>
|
|
460
|
+
sage: I = K.ideal(1/a); I
|
|
461
|
+
Fractional ideal (1/2*a^2)
|
|
462
|
+
sage: type(I)
|
|
463
|
+
<class 'sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal'>
|
|
464
|
+
"""
|
|
465
|
+
return "Ideal %s of %s" % (self._repr_short(), self.number_field())
|
|
466
|
+
|
|
467
|
+
def _repr_short(self):
|
|
468
|
+
"""
|
|
469
|
+
Compact string representation of this ideal. When the norm of
|
|
470
|
+
the discriminant of the defining polynomial of the number field
|
|
471
|
+
is less than
|
|
472
|
+
|
|
473
|
+
sage.rings.number_field.number_field_ideal.SMALL_DISC
|
|
474
|
+
|
|
475
|
+
then display reduced generators. Otherwise display two
|
|
476
|
+
generators.
|
|
477
|
+
|
|
478
|
+
EXAMPLES::
|
|
479
|
+
|
|
480
|
+
sage: x = polygen(ZZ)
|
|
481
|
+
sage: K.<a> = NumberField(x^4 + 389); K
|
|
482
|
+
Number Field in a with defining polynomial x^4 + 389
|
|
483
|
+
sage: I = K.factor(17)[0][0]; I
|
|
484
|
+
Fractional ideal (17, a^2 + 6)
|
|
485
|
+
sage: I._repr_short()
|
|
486
|
+
'(17, a^2 + 6)'
|
|
487
|
+
|
|
488
|
+
We use reduced gens, because the discriminant is small::
|
|
489
|
+
|
|
490
|
+
sage: K.<a> = NumberField(x^2 + 17); K
|
|
491
|
+
Number Field in a with defining polynomial x^2 + 17
|
|
492
|
+
sage: I = K.factor(17)[0][0]; I
|
|
493
|
+
Fractional ideal (a)
|
|
494
|
+
|
|
495
|
+
Here the discriminant is 'large', so the gens aren't reduced::
|
|
496
|
+
|
|
497
|
+
sage: sage.rings.number_field.number_field_ideal.SMALL_DISC
|
|
498
|
+
1000000
|
|
499
|
+
sage: K.<a> = NumberField(x^2 + 902384094); K
|
|
500
|
+
Number Field in a with defining polynomial x^2 + 902384094
|
|
501
|
+
sage: I = K.factor(19)[0][0]; I
|
|
502
|
+
Fractional ideal (19, a + 5)
|
|
503
|
+
sage: I.gens_reduced()
|
|
504
|
+
(19, a + 5)
|
|
505
|
+
"""
|
|
506
|
+
return '(%s)' % (', '.join(map(str, self._gens_repr())))
|
|
507
|
+
|
|
508
|
+
def _gens_repr(self):
|
|
509
|
+
"""
|
|
510
|
+
Return tuple of generators to be used for printing this number
|
|
511
|
+
field ideal. The gens are reduced only if the absolute value of
|
|
512
|
+
the norm of the discriminant of the defining polynomial is at
|
|
513
|
+
most sage.rings.number_field.number_field_ideal.SMALL_DISC.
|
|
514
|
+
|
|
515
|
+
EXAMPLES::
|
|
516
|
+
|
|
517
|
+
sage: x = polygen(ZZ)
|
|
518
|
+
sage: sage.rings.number_field.number_field_ideal.SMALL_DISC
|
|
519
|
+
1000000
|
|
520
|
+
sage: K.<a> = NumberField(x^4 + 3*x^2 - 17)
|
|
521
|
+
sage: K.discriminant() # too big
|
|
522
|
+
-1612688
|
|
523
|
+
sage: I = K.ideal([17*a*(2*a-2),17*a*(2*a-3)]); I._gens_repr()
|
|
524
|
+
(289, 17*a)
|
|
525
|
+
sage: I.gens_reduced()
|
|
526
|
+
(17*a,)
|
|
527
|
+
"""
|
|
528
|
+
# If the discriminant is small, it is easy to find nice gens.
|
|
529
|
+
# Otherwise it is potentially very hard.
|
|
530
|
+
try:
|
|
531
|
+
if abs(self.number_field().defining_polynomial().discriminant().norm()) <= SMALL_DISC:
|
|
532
|
+
return self.gens_reduced()
|
|
533
|
+
except TypeError:
|
|
534
|
+
# In some cases with relative extensions, computing the
|
|
535
|
+
# discriminant of the defining polynomial is not
|
|
536
|
+
# supported.
|
|
537
|
+
pass
|
|
538
|
+
# Return two generators unless the second one is zero
|
|
539
|
+
two_gens = self.gens_two()
|
|
540
|
+
if two_gens[1]:
|
|
541
|
+
return two_gens
|
|
542
|
+
else:
|
|
543
|
+
return (two_gens[0],)
|
|
544
|
+
|
|
545
|
+
def __pari__(self):
|
|
546
|
+
"""
|
|
547
|
+
Return PARI Hermite Normal Form representations of this
|
|
548
|
+
ideal.
|
|
549
|
+
|
|
550
|
+
EXAMPLES::
|
|
551
|
+
|
|
552
|
+
sage: x = polygen(ZZ)
|
|
553
|
+
sage: K.<w> = NumberField(x^2 + 23)
|
|
554
|
+
sage: I = K.class_group().0.ideal(); I
|
|
555
|
+
Fractional ideal (2, 1/2*w - 1/2)
|
|
556
|
+
sage: I.__pari__()
|
|
557
|
+
[2, 0; 0, 1]
|
|
558
|
+
"""
|
|
559
|
+
return self.pari_hnf()
|
|
560
|
+
|
|
561
|
+
def _pari_init_(self):
|
|
562
|
+
"""
|
|
563
|
+
Return ``self`` in PARI Hermite Normal Form as a string.
|
|
564
|
+
|
|
565
|
+
EXAMPLES::
|
|
566
|
+
|
|
567
|
+
sage: x = polygen(ZZ)
|
|
568
|
+
sage: K.<w> = NumberField(x^2 + 23)
|
|
569
|
+
sage: I = K.class_group().0.ideal()
|
|
570
|
+
sage: I._pari_init_()
|
|
571
|
+
'[2, 0; 0, 1]'
|
|
572
|
+
"""
|
|
573
|
+
return str(self.__pari__())
|
|
574
|
+
|
|
575
|
+
def pari_hnf(self):
|
|
576
|
+
"""
|
|
577
|
+
Return PARI's representation of this ideal in Hermite normal form.
|
|
578
|
+
|
|
579
|
+
EXAMPLES::
|
|
580
|
+
|
|
581
|
+
sage: x = polygen(ZZ)
|
|
582
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
583
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
584
|
+
sage: I = K.ideal(2/(5+a))
|
|
585
|
+
sage: I.pari_hnf()
|
|
586
|
+
[2, 0, 50/127; 0, 2, 244/127; 0, 0, 2/127]
|
|
587
|
+
"""
|
|
588
|
+
try:
|
|
589
|
+
return self.__pari_hnf
|
|
590
|
+
except AttributeError:
|
|
591
|
+
nf = self.number_field().pari_nf()
|
|
592
|
+
self.__pari_hnf = nf.idealhnf(0)
|
|
593
|
+
hnflist = [ nf.idealhnf(x) for x in self.gens() ]
|
|
594
|
+
for ideal in hnflist:
|
|
595
|
+
self.__pari_hnf = nf.idealadd(self.__pari_hnf, ideal)
|
|
596
|
+
return self.__pari_hnf
|
|
597
|
+
|
|
598
|
+
@cached_method
|
|
599
|
+
def basis(self):
|
|
600
|
+
r"""
|
|
601
|
+
Return a basis for this ideal viewed as a `\ZZ`-module.
|
|
602
|
+
|
|
603
|
+
OUTPUT:
|
|
604
|
+
|
|
605
|
+
An immutable sequence of elements of this ideal (note: their
|
|
606
|
+
parent is the number field) forming a basis for this ideal.
|
|
607
|
+
|
|
608
|
+
EXAMPLES::
|
|
609
|
+
|
|
610
|
+
sage: K.<z> = CyclotomicField(7)
|
|
611
|
+
sage: I = K.factor(11)[0][0]
|
|
612
|
+
sage: I.basis() # warning -- choice of basis can be somewhat random
|
|
613
|
+
[11, 11*z, 11*z^2, z^3 + 5*z^2 + 4*z + 10,
|
|
614
|
+
z^4 + z^2 + z + 5, z^5 + z^4 + z^3 + 2*z^2 + 6*z + 5]
|
|
615
|
+
|
|
616
|
+
An example of a non-integral ideal.::
|
|
617
|
+
|
|
618
|
+
sage: J = 1/I
|
|
619
|
+
sage: J # warning -- choice of generators can be somewhat random
|
|
620
|
+
Fractional ideal (2/11*z^5 + 2/11*z^4 + 3/11*z^3 + 2/11)
|
|
621
|
+
sage: J.basis() # warning -- choice of basis can be somewhat random
|
|
622
|
+
[1, z, z^2, 1/11*z^3 + 7/11*z^2 + 6/11*z + 10/11,
|
|
623
|
+
1/11*z^4 + 1/11*z^2 + 1/11*z + 7/11,
|
|
624
|
+
1/11*z^5 + 1/11*z^4 + 1/11*z^3 + 2/11*z^2 + 8/11*z + 7/11]
|
|
625
|
+
|
|
626
|
+
Number fields defined by non-monic and non-integral
|
|
627
|
+
polynomials are supported (:issue:`252`)::
|
|
628
|
+
|
|
629
|
+
sage: x = polygen(ZZ)
|
|
630
|
+
sage: K.<a> = NumberField(2*x^2 - 1/3)
|
|
631
|
+
sage: K.ideal(a).basis()
|
|
632
|
+
[1, a]
|
|
633
|
+
"""
|
|
634
|
+
hnf = self.pari_hnf()
|
|
635
|
+
v = self.__elements_from_hnf(hnf)
|
|
636
|
+
return Sequence(v, immutable=True)
|
|
637
|
+
|
|
638
|
+
@cached_method
|
|
639
|
+
def free_module(self):
|
|
640
|
+
r"""
|
|
641
|
+
Return the free `\ZZ`-module contained in the vector space
|
|
642
|
+
associated to the ambient number field, that corresponds
|
|
643
|
+
to this ideal.
|
|
644
|
+
|
|
645
|
+
EXAMPLES::
|
|
646
|
+
|
|
647
|
+
sage: K.<z> = CyclotomicField(7)
|
|
648
|
+
sage: I = K.factor(11)[0][0]; I
|
|
649
|
+
Fractional ideal (-3*z^4 - 2*z^3 - 2*z^2 - 2)
|
|
650
|
+
sage: A = I.free_module()
|
|
651
|
+
sage: A # warning -- choice of basis can be somewhat random
|
|
652
|
+
Free module of degree 6 and rank 6 over Integer Ring
|
|
653
|
+
User basis matrix:
|
|
654
|
+
[11 0 0 0 0 0]
|
|
655
|
+
[ 0 11 0 0 0 0]
|
|
656
|
+
[ 0 0 11 0 0 0]
|
|
657
|
+
[10 4 5 1 0 0]
|
|
658
|
+
[ 5 1 1 0 1 0]
|
|
659
|
+
[ 5 6 2 1 1 1]
|
|
660
|
+
|
|
661
|
+
However, the actual `\ZZ`-module is not at all random::
|
|
662
|
+
|
|
663
|
+
sage: A.basis_matrix().change_ring(ZZ).echelon_form()
|
|
664
|
+
[ 1 0 0 5 1 1]
|
|
665
|
+
[ 0 1 0 1 1 7]
|
|
666
|
+
[ 0 0 1 7 6 10]
|
|
667
|
+
[ 0 0 0 11 0 0]
|
|
668
|
+
[ 0 0 0 0 11 0]
|
|
669
|
+
[ 0 0 0 0 0 11]
|
|
670
|
+
|
|
671
|
+
The ideal doesn't have to be integral::
|
|
672
|
+
|
|
673
|
+
sage: J = I^(-1)
|
|
674
|
+
sage: B = J.free_module()
|
|
675
|
+
sage: B.echelonized_basis_matrix()
|
|
676
|
+
[ 1/11 0 0 7/11 1/11 1/11]
|
|
677
|
+
[ 0 1/11 0 1/11 1/11 5/11]
|
|
678
|
+
[ 0 0 1/11 5/11 4/11 10/11]
|
|
679
|
+
[ 0 0 0 1 0 0]
|
|
680
|
+
[ 0 0 0 0 1 0]
|
|
681
|
+
[ 0 0 0 0 0 1]
|
|
682
|
+
|
|
683
|
+
This also works for relative extensions::
|
|
684
|
+
|
|
685
|
+
sage: x = polygen(ZZ)
|
|
686
|
+
sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 2])
|
|
687
|
+
sage: I = K.fractional_ideal(4)
|
|
688
|
+
sage: I.free_module()
|
|
689
|
+
Free module of degree 4 and rank 4 over Integer Ring
|
|
690
|
+
User basis matrix:
|
|
691
|
+
[ 4 0 0 0]
|
|
692
|
+
[ 3 7 1 1]
|
|
693
|
+
[ 0 10 0 2]
|
|
694
|
+
[ 3 -7 1 -1]
|
|
695
|
+
sage: J = I^(-1); J.free_module()
|
|
696
|
+
Free module of degree 4 and rank 4 over Integer Ring
|
|
697
|
+
User basis matrix:
|
|
698
|
+
[ 1/4 0 0 0]
|
|
699
|
+
[ 3/16 7/16 1/16 1/16]
|
|
700
|
+
[ 0 5/8 0 1/8]
|
|
701
|
+
[ 3/16 -7/16 1/16 -1/16]
|
|
702
|
+
|
|
703
|
+
An example of intersecting ideals by intersecting free modules.::
|
|
704
|
+
|
|
705
|
+
sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8)
|
|
706
|
+
sage: I = K.factor(2)
|
|
707
|
+
sage: p1 = I[0][0]; p2 = I[1][0]
|
|
708
|
+
sage: N = p1.free_module().intersection(p2.free_module()); N
|
|
709
|
+
Free module of degree 3 and rank 3 over Integer Ring
|
|
710
|
+
Echelon basis matrix:
|
|
711
|
+
[ 1 1/2 1/2]
|
|
712
|
+
[ 0 1 1]
|
|
713
|
+
[ 0 0 2]
|
|
714
|
+
sage: N.index_in(p1.free_module()).abs()
|
|
715
|
+
2
|
|
716
|
+
|
|
717
|
+
TESTS:
|
|
718
|
+
|
|
719
|
+
Sage can find the free module associated to quite large ideals
|
|
720
|
+
quickly (see :issue:`4627`)::
|
|
721
|
+
|
|
722
|
+
sage: y = polygen(ZZ)
|
|
723
|
+
sage: M.<a> = NumberField(y^20 - 2*y^19 + 10*y^17 - 15*y^16 + 40*y^14 - 64*y^13 + 46*y^12 + 8*y^11 - 32*y^10 + 8*y^9 + 46*y^8 - 64*y^7 + 40*y^6 - 15*y^4 + 10*y^3 - 2*y + 1)
|
|
724
|
+
sage: M.ideal(prod(prime_range(6000, 6200))).free_module()
|
|
725
|
+
Free module of degree 20 and rank 20 over Integer Ring
|
|
726
|
+
User basis matrix:
|
|
727
|
+
20 x 20 dense matrix over Rational Field
|
|
728
|
+
"""
|
|
729
|
+
return basis_to_module(self.basis(), self.number_field())
|
|
730
|
+
|
|
731
|
+
def reduce_equiv(self):
|
|
732
|
+
"""
|
|
733
|
+
Return a small ideal that is equivalent to ``self`` in the group
|
|
734
|
+
of fractional ideals modulo principal ideals. Very often (but
|
|
735
|
+
not always) if ``self`` is principal then this function returns
|
|
736
|
+
the unit ideal.
|
|
737
|
+
|
|
738
|
+
ALGORITHM: Calls :pari:`idealred` function.
|
|
739
|
+
|
|
740
|
+
EXAMPLES::
|
|
741
|
+
|
|
742
|
+
sage: x = polygen(ZZ)
|
|
743
|
+
sage: K.<w> = NumberField(x^2 + 23)
|
|
744
|
+
sage: I = ideal(w*23^5); I
|
|
745
|
+
Fractional ideal (6436343*w)
|
|
746
|
+
sage: I.reduce_equiv()
|
|
747
|
+
Fractional ideal (1)
|
|
748
|
+
sage: I = K.class_group().0.ideal()^10; I
|
|
749
|
+
Fractional ideal (1024, 1/2*w + 979/2)
|
|
750
|
+
sage: I.reduce_equiv()
|
|
751
|
+
Fractional ideal (2, 1/2*w - 1/2)
|
|
752
|
+
"""
|
|
753
|
+
K = self.number_field()
|
|
754
|
+
P = K.pari_nf()
|
|
755
|
+
hnf = P.idealred(self.pari_hnf())
|
|
756
|
+
gens = self.__elements_from_hnf(hnf)
|
|
757
|
+
return K.ideal(gens)
|
|
758
|
+
|
|
759
|
+
def gens_reduced(self, proof=None):
|
|
760
|
+
r"""
|
|
761
|
+
Express this ideal in terms of at most two generators, and one
|
|
762
|
+
if possible.
|
|
763
|
+
|
|
764
|
+
This function indirectly uses :pari:`bnfisprincipal`, so set
|
|
765
|
+
``proof=True`` if you want to prove correctness (which *is* the
|
|
766
|
+
default).
|
|
767
|
+
|
|
768
|
+
EXAMPLES::
|
|
769
|
+
|
|
770
|
+
sage: x = polygen(ZZ)
|
|
771
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
772
|
+
sage: K.<a> = NumberField(x^2 + 5)
|
|
773
|
+
sage: K.ideal(0).gens_reduced()
|
|
774
|
+
(0,)
|
|
775
|
+
sage: J = K.ideal([a + 2, 9])
|
|
776
|
+
sage: J.gens()
|
|
777
|
+
(a + 2, 9)
|
|
778
|
+
sage: J.gens_reduced() # random sign
|
|
779
|
+
(a + 2,)
|
|
780
|
+
sage: K.ideal([a + 2, 3]).gens_reduced()
|
|
781
|
+
(3, a + 2)
|
|
782
|
+
|
|
783
|
+
TESTS::
|
|
784
|
+
|
|
785
|
+
sage: len(J.gens_reduced()) == 1
|
|
786
|
+
True
|
|
787
|
+
|
|
788
|
+
sage: all(j.parent() is K for j in J.gens())
|
|
789
|
+
True
|
|
790
|
+
sage: all(j.parent() is K for j in J.gens_reduced())
|
|
791
|
+
True
|
|
792
|
+
|
|
793
|
+
sage: K.<a> = NumberField(x^4 + 10*x^2 + 20)
|
|
794
|
+
sage: J = K.prime_above(5)
|
|
795
|
+
sage: J.is_principal()
|
|
796
|
+
False
|
|
797
|
+
sage: J.gens_reduced()
|
|
798
|
+
(5, -a)
|
|
799
|
+
sage: all(j.parent() is K for j in J.gens())
|
|
800
|
+
True
|
|
801
|
+
sage: all(j.parent() is K for j in J.gens_reduced())
|
|
802
|
+
True
|
|
803
|
+
|
|
804
|
+
Make sure this works with large ideals (:issue:`11836`)::
|
|
805
|
+
|
|
806
|
+
sage: R.<x> = QQ['x']
|
|
807
|
+
sage: L.<b> = NumberField(x^10 - 10*x^8 - 20*x^7 + 165*x^6 - 12*x^5 - 760*x^3 + 2220*x^2 + 5280*x + 7744)
|
|
808
|
+
sage: z_x = -96698852571685/2145672615243325696*b^9 + 2472249905907/195061146840302336*b^8 + 916693155514421/2145672615243325696*b^7 + 1348520950997779/2145672615243325696*b^6 - 82344497086595/12191321677518896*b^5 + 2627122040194919/536418153810831424*b^4 - 452199105143745/48765286710075584*b^3 + 4317002771457621/536418153810831424*b^2 + 2050725777454935/67052269226353928*b + 3711967683469209/3047830419379724
|
|
809
|
+
|
|
810
|
+
sage: # needs database_cremona_mini_ellcurve sage.schemes
|
|
811
|
+
sage: P = EllipticCurve(L, '57a1').lift_x(z_x) * 3
|
|
812
|
+
sage: ideal = L.fractional_ideal(P[0], P[1])
|
|
813
|
+
sage: ideal.is_principal(proof=False)
|
|
814
|
+
True
|
|
815
|
+
sage: len(ideal.gens_reduced(proof=False))
|
|
816
|
+
1
|
|
817
|
+
"""
|
|
818
|
+
if len(self.gens()) <= 1:
|
|
819
|
+
self._is_principal = True
|
|
820
|
+
self._reduced_generators = self.gens()
|
|
821
|
+
return self._reduced_generators
|
|
822
|
+
self._cache_bnfisprincipal(proof=proof, gens=True)
|
|
823
|
+
return self._reduced_generators
|
|
824
|
+
|
|
825
|
+
def gens_two(self) -> tuple:
|
|
826
|
+
r"""
|
|
827
|
+
Express this ideal using exactly two generators, the first of
|
|
828
|
+
which is a generator for the intersection of the ideal with `\QQ`.
|
|
829
|
+
|
|
830
|
+
ALGORITHM: uses PARI's :pari:`idealtwoelt` function, which runs in
|
|
831
|
+
randomized polynomial time and is very fast in practice.
|
|
832
|
+
|
|
833
|
+
EXAMPLES::
|
|
834
|
+
|
|
835
|
+
sage: x = polygen(ZZ)
|
|
836
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
837
|
+
sage: K.<a> = NumberField(x^2 + 5)
|
|
838
|
+
sage: J = K.ideal([a + 2, 9])
|
|
839
|
+
sage: J.gens()
|
|
840
|
+
(a + 2, 9)
|
|
841
|
+
sage: J.gens_two()
|
|
842
|
+
(9, a + 2)
|
|
843
|
+
sage: K.ideal([a + 5, a + 8]).gens_two()
|
|
844
|
+
(3, a + 2)
|
|
845
|
+
sage: K.ideal(0).gens_two()
|
|
846
|
+
(0, 0)
|
|
847
|
+
|
|
848
|
+
The second generator is zero if and only if the ideal is
|
|
849
|
+
generated by a rational, in contrast to the PARI function
|
|
850
|
+
:pari:`idealtwoelt`::
|
|
851
|
+
|
|
852
|
+
sage: I = K.ideal(12)
|
|
853
|
+
sage: pari(K).idealtwoelt(I) # Note that second element is not zero
|
|
854
|
+
[12, [0, 12]~]
|
|
855
|
+
sage: I.gens_two()
|
|
856
|
+
(12, 0)
|
|
857
|
+
"""
|
|
858
|
+
try:
|
|
859
|
+
return self.__two_generators
|
|
860
|
+
except AttributeError:
|
|
861
|
+
pass
|
|
862
|
+
|
|
863
|
+
K = self.number_field()
|
|
864
|
+
|
|
865
|
+
if self.is_zero():
|
|
866
|
+
self.__two_generators = (K.zero(), K.zero())
|
|
867
|
+
else:
|
|
868
|
+
HNF = self.pari_hnf()
|
|
869
|
+
# Check whether the ideal is generated by an integer, i.e.
|
|
870
|
+
# whether HNF is a multiple of the identity matrix
|
|
871
|
+
if HNF.gequal(HNF[0, 0]):
|
|
872
|
+
a = HNF[0, 0]
|
|
873
|
+
alpha = 0
|
|
874
|
+
else:
|
|
875
|
+
a, alpha = K.pari_nf().idealtwoelt(HNF)
|
|
876
|
+
self.__two_generators = (K(a), K(alpha))
|
|
877
|
+
|
|
878
|
+
return self.__two_generators
|
|
879
|
+
|
|
880
|
+
def integral_basis(self):
|
|
881
|
+
r"""
|
|
882
|
+
Return a list of generators for this ideal as a `\ZZ`-module.
|
|
883
|
+
|
|
884
|
+
EXAMPLES::
|
|
885
|
+
|
|
886
|
+
sage: x = polygen(ZZ)
|
|
887
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
888
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
889
|
+
sage: J = K.ideal(i + 1)
|
|
890
|
+
sage: J.integral_basis()
|
|
891
|
+
[2, i + 1]
|
|
892
|
+
"""
|
|
893
|
+
hnf = self.pari_hnf()
|
|
894
|
+
return self.__elements_from_hnf(hnf)
|
|
895
|
+
|
|
896
|
+
def integral_split(self):
|
|
897
|
+
r"""
|
|
898
|
+
Return a tuple `(I, d)`, where `I` is an integral ideal, and `d` is the
|
|
899
|
+
smallest positive integer such that this ideal is equal to `I/d`.
|
|
900
|
+
|
|
901
|
+
EXAMPLES::
|
|
902
|
+
|
|
903
|
+
sage: x = polygen(ZZ)
|
|
904
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
905
|
+
sage: K.<a> = NumberField(x^2 - 5)
|
|
906
|
+
sage: I = K.ideal(2/(5+a))
|
|
907
|
+
sage: I.is_integral()
|
|
908
|
+
False
|
|
909
|
+
sage: J, d = I.integral_split()
|
|
910
|
+
sage: J
|
|
911
|
+
Fractional ideal (-1/2*a + 5/2)
|
|
912
|
+
sage: J.is_integral()
|
|
913
|
+
True
|
|
914
|
+
sage: d
|
|
915
|
+
5
|
|
916
|
+
sage: I == J/d
|
|
917
|
+
True
|
|
918
|
+
"""
|
|
919
|
+
try:
|
|
920
|
+
return self.__integral_split
|
|
921
|
+
except AttributeError:
|
|
922
|
+
if self.is_integral():
|
|
923
|
+
self.__integral_split = (self, ZZ(1))
|
|
924
|
+
else:
|
|
925
|
+
factors = self.factor()
|
|
926
|
+
denom_list = [p_e for p_e in factors if p_e[1] < 0]
|
|
927
|
+
denominator = prod([ p.smallest_integer()**(-e)
|
|
928
|
+
for (p,e) in denom_list ])
|
|
929
|
+
## Get a list of the primes dividing the denominator
|
|
930
|
+
plist = [ p.smallest_integer() for (p,e) in denom_list ]
|
|
931
|
+
for p in plist:
|
|
932
|
+
while denominator % p == 0 and (self*(denominator/p)).is_integral():
|
|
933
|
+
denominator //= p
|
|
934
|
+
self.__integral_split = (self*denominator, denominator)
|
|
935
|
+
return self.__integral_split
|
|
936
|
+
|
|
937
|
+
def intersection(self, other):
|
|
938
|
+
r"""
|
|
939
|
+
Return the intersection of ``self`` and ``other``.
|
|
940
|
+
|
|
941
|
+
EXAMPLES::
|
|
942
|
+
|
|
943
|
+
sage: K.<a> = QuadraticField(-11)
|
|
944
|
+
sage: p = K.ideal((a + 1)/2); q = K.ideal((a + 3)/2)
|
|
945
|
+
sage: p.intersection(q) == q.intersection(p) == K.ideal(a - 2)
|
|
946
|
+
True
|
|
947
|
+
|
|
948
|
+
An example with non-principal ideals::
|
|
949
|
+
|
|
950
|
+
sage: x = polygen(ZZ)
|
|
951
|
+
sage: L.<a> = NumberField(x^3 - 7)
|
|
952
|
+
sage: p = L.ideal(a^2 + a + 1, 2)
|
|
953
|
+
sage: q = L.ideal(a + 1)
|
|
954
|
+
sage: p.intersection(q) == L.ideal(8, 2*a + 2)
|
|
955
|
+
True
|
|
956
|
+
|
|
957
|
+
A relative example::
|
|
958
|
+
|
|
959
|
+
sage: L.<a,b> = NumberField([x^2 + 11, x^2 - 5])
|
|
960
|
+
sage: A = L.ideal([15, (-3/2*b + 7/2)*a - 8])
|
|
961
|
+
sage: B = L.ideal([6, (-1/2*b + 1)*a - b - 5/2])
|
|
962
|
+
sage: A.intersection(B) == L.ideal(-1/2*a - 3/2*b - 1)
|
|
963
|
+
True
|
|
964
|
+
|
|
965
|
+
TESTS:
|
|
966
|
+
|
|
967
|
+
Test that this works with non-integral ideals (:issue:`10767`)::
|
|
968
|
+
|
|
969
|
+
sage: K = QuadraticField(-2)
|
|
970
|
+
sage: I = K.ideal(1/2)
|
|
971
|
+
sage: I.intersection(I)
|
|
972
|
+
Fractional ideal (1/2)
|
|
973
|
+
"""
|
|
974
|
+
L = self.number_field()
|
|
975
|
+
other = L.ideal(other)
|
|
976
|
+
nf = L.pari_nf()
|
|
977
|
+
hnf = nf.idealintersect(self.pari_hnf(), other.pari_hnf())
|
|
978
|
+
I = L.ideal(self._NumberFieldIdeal__elements_from_hnf(hnf))
|
|
979
|
+
I.__pari_hnf = hnf
|
|
980
|
+
return I
|
|
981
|
+
|
|
982
|
+
def is_integral(self):
|
|
983
|
+
"""
|
|
984
|
+
Return ``True`` if this ideal is integral.
|
|
985
|
+
|
|
986
|
+
EXAMPLES::
|
|
987
|
+
|
|
988
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
989
|
+
sage: K.<a> = NumberField(x^5 - x + 1)
|
|
990
|
+
sage: K.ideal(a).is_integral()
|
|
991
|
+
True
|
|
992
|
+
sage: (K.ideal(1) / (3*a+1)).is_integral()
|
|
993
|
+
False
|
|
994
|
+
"""
|
|
995
|
+
try:
|
|
996
|
+
return self.__is_integral
|
|
997
|
+
except AttributeError:
|
|
998
|
+
one = self.number_field().ideal(1)
|
|
999
|
+
self.__is_integral = all(a in one for a in self.integral_basis())
|
|
1000
|
+
return self.__is_integral
|
|
1001
|
+
|
|
1002
|
+
def is_maximal(self):
|
|
1003
|
+
"""
|
|
1004
|
+
Return ``True`` if this ideal is maximal. This is equivalent to
|
|
1005
|
+
``self`` being prime and nonzero.
|
|
1006
|
+
|
|
1007
|
+
EXAMPLES::
|
|
1008
|
+
|
|
1009
|
+
sage: x = polygen(ZZ)
|
|
1010
|
+
sage: K.<a> = NumberField(x^3 + 3); K
|
|
1011
|
+
Number Field in a with defining polynomial x^3 + 3
|
|
1012
|
+
sage: K.ideal(5).is_maximal()
|
|
1013
|
+
False
|
|
1014
|
+
sage: K.ideal(7).is_maximal()
|
|
1015
|
+
True
|
|
1016
|
+
"""
|
|
1017
|
+
return self.is_prime() and not self.is_zero()
|
|
1018
|
+
|
|
1019
|
+
def is_prime(self):
|
|
1020
|
+
"""
|
|
1021
|
+
Return ``True`` if this ideal is prime.
|
|
1022
|
+
|
|
1023
|
+
EXAMPLES::
|
|
1024
|
+
|
|
1025
|
+
sage: x = polygen(ZZ)
|
|
1026
|
+
sage: K.<a> = NumberField(x^2 - 17); K
|
|
1027
|
+
Number Field in a with defining polynomial x^2 - 17
|
|
1028
|
+
sage: K.ideal(5).is_prime() # inert prime
|
|
1029
|
+
True
|
|
1030
|
+
sage: K.ideal(13).is_prime() # split
|
|
1031
|
+
False
|
|
1032
|
+
sage: K.ideal(17).is_prime() # ramified
|
|
1033
|
+
False
|
|
1034
|
+
|
|
1035
|
+
TESTS:
|
|
1036
|
+
|
|
1037
|
+
Check that we do not factor the norm of the ideal, this used
|
|
1038
|
+
to take half an hour, see :issue:`33360`::
|
|
1039
|
+
|
|
1040
|
+
sage: K.<a,b,c> = NumberField([x^2 - 2, x^2 - 3, x^2 - 5])
|
|
1041
|
+
sage: t = (((-2611940*c + 1925290/7653)*b - 1537130/7653*c
|
|
1042
|
+
....: + 10130950)*a + (1343014/7653*c - 8349770)*b
|
|
1043
|
+
....: + 6477058*c - 2801449990/4002519)
|
|
1044
|
+
sage: t.is_prime()
|
|
1045
|
+
False
|
|
1046
|
+
"""
|
|
1047
|
+
try:
|
|
1048
|
+
return self._pari_prime is not None
|
|
1049
|
+
except AttributeError:
|
|
1050
|
+
pass
|
|
1051
|
+
|
|
1052
|
+
K = self.number_field().pari_nf()
|
|
1053
|
+
I = self.pari_hnf()
|
|
1054
|
+
|
|
1055
|
+
candidate = K.idealismaximal(I) or None
|
|
1056
|
+
|
|
1057
|
+
# PARI uses probabilistic primality testing inside idealismaximal().
|
|
1058
|
+
if get_flag(None, 'arithmetic'):
|
|
1059
|
+
# proof required, check using isprime()
|
|
1060
|
+
if candidate and not candidate[0].isprime():
|
|
1061
|
+
candidate = None
|
|
1062
|
+
|
|
1063
|
+
self._pari_prime = candidate
|
|
1064
|
+
|
|
1065
|
+
return self._pari_prime is not None
|
|
1066
|
+
|
|
1067
|
+
def pari_prime(self):
|
|
1068
|
+
r"""
|
|
1069
|
+
Return a PARI prime ideal corresponding to the ideal ``self``.
|
|
1070
|
+
|
|
1071
|
+
INPUT:
|
|
1072
|
+
|
|
1073
|
+
- ``self`` -- a prime ideal
|
|
1074
|
+
|
|
1075
|
+
OUTPUT: a PARI "prime ideal", i.e. a five-component vector `[p,a,e,f,b]`
|
|
1076
|
+
representing the prime ideal `p O_K + a O_K`, `e`, `f` as usual, `a` as
|
|
1077
|
+
vector of components on the integral basis, `b` Lenstra's constant.
|
|
1078
|
+
|
|
1079
|
+
EXAMPLES::
|
|
1080
|
+
|
|
1081
|
+
sage: K.<i> = QuadraticField(-1)
|
|
1082
|
+
sage: K.ideal(3).pari_prime()
|
|
1083
|
+
[3, [3, 0]~, 1, 2, 1]
|
|
1084
|
+
sage: K.ideal(2+i).pari_prime()
|
|
1085
|
+
[5, [2, 1]~, 1, 1, [-2, -1; 1, -2]]
|
|
1086
|
+
sage: K.ideal(2).pari_prime()
|
|
1087
|
+
Traceback (most recent call last):
|
|
1088
|
+
...
|
|
1089
|
+
ValueError: Fractional ideal (2) is not a prime ideal
|
|
1090
|
+
"""
|
|
1091
|
+
if not self.is_prime():
|
|
1092
|
+
raise ValueError("%s is not a prime ideal" % self)
|
|
1093
|
+
return self._pari_prime
|
|
1094
|
+
|
|
1095
|
+
def _cache_bnfisprincipal(self, proof=None, gens=False):
|
|
1096
|
+
r"""
|
|
1097
|
+
This function is essentially the implementation of
|
|
1098
|
+
:meth:`is_principal`, :meth:`gens_reduced` and
|
|
1099
|
+
:meth:`ideal_class_log`.
|
|
1100
|
+
|
|
1101
|
+
INPUT:
|
|
1102
|
+
|
|
1103
|
+
- ``self`` -- an ideal
|
|
1104
|
+
|
|
1105
|
+
- ``proof`` -- proof flag. If ``proof=False``, assume GRH
|
|
1106
|
+
|
|
1107
|
+
- ``gens`` -- boolean (default: ``False``); if ``True``, also computes
|
|
1108
|
+
the reduced generators of the ideal
|
|
1109
|
+
|
|
1110
|
+
OUTPUT:
|
|
1111
|
+
|
|
1112
|
+
None. This function simply caches the results: it sets
|
|
1113
|
+
``_ideal_class_log`` (see :meth:`ideal_class_log`),
|
|
1114
|
+
``_is_principal`` (see :meth:`is_principal`) and
|
|
1115
|
+
``_reduced_generators``.
|
|
1116
|
+
|
|
1117
|
+
TESTS:
|
|
1118
|
+
|
|
1119
|
+
Check that no warnings are triggered from PARI/GP (see :issue:`30801`)::
|
|
1120
|
+
|
|
1121
|
+
sage: x = polygen(ZZ)
|
|
1122
|
+
sage: K.<a> = NumberField(x^2 - x + 112941801)
|
|
1123
|
+
sage: I = K.ideal((112941823, a + 49942513))
|
|
1124
|
+
sage: I.is_principal()
|
|
1125
|
+
False
|
|
1126
|
+
"""
|
|
1127
|
+
# Since pari_bnf() is cached, this call to pari_bnf() should not
|
|
1128
|
+
# influence the run-time much. Also, this simplifies the handling
|
|
1129
|
+
# of the proof flag: if we computed bnfisprincipal() in the past
|
|
1130
|
+
# with proof=False, then we do not need to recompute the result.
|
|
1131
|
+
# We just need to check correctness of pari_bnf().
|
|
1132
|
+
proof = get_flag(proof, "number_field")
|
|
1133
|
+
bnf = self.number_field().pari_bnf(proof)
|
|
1134
|
+
|
|
1135
|
+
# If we already have _reduced_generators, no need to compute them again
|
|
1136
|
+
if hasattr(self, "_reduced_generators"):
|
|
1137
|
+
gens = False
|
|
1138
|
+
|
|
1139
|
+
# Is there something to do?
|
|
1140
|
+
if hasattr(self, "_ideal_class_log") and not gens:
|
|
1141
|
+
self._is_principal = not any(self._ideal_class_log)
|
|
1142
|
+
return
|
|
1143
|
+
|
|
1144
|
+
if not gens:
|
|
1145
|
+
v = bnf.bnfisprincipal(self.pari_hnf(), 0)
|
|
1146
|
+
self._ideal_class_log = list(v)
|
|
1147
|
+
self._is_principal = not any(self._ideal_class_log)
|
|
1148
|
+
else:
|
|
1149
|
+
# TODO: this is a bit of a waste. We ask bnfisprincipal to compute the compact form and then
|
|
1150
|
+
# convert this compact form back into an expanded form.
|
|
1151
|
+
# (though calling with 3 instead of 5 most likely triggers an error with memory allocation failure)
|
|
1152
|
+
v = bnf.bnfisprincipal(self.pari_hnf(), 5)
|
|
1153
|
+
e = v[0]
|
|
1154
|
+
t = v[1]
|
|
1155
|
+
t = bnf.nfbasistoalg(bnf.nffactorback(t))
|
|
1156
|
+
self._ideal_class_log = list(e)
|
|
1157
|
+
self._is_principal = not any(self._ideal_class_log)
|
|
1158
|
+
|
|
1159
|
+
if self._is_principal:
|
|
1160
|
+
g = self.number_field()(t)
|
|
1161
|
+
self._reduced_generators = (g,)
|
|
1162
|
+
elif gens:
|
|
1163
|
+
# Non-principal ideal
|
|
1164
|
+
self._reduced_generators = self.gens_two()
|
|
1165
|
+
|
|
1166
|
+
def is_principal(self, proof=None):
|
|
1167
|
+
r"""
|
|
1168
|
+
Return ``True`` if this ideal is principal.
|
|
1169
|
+
|
|
1170
|
+
Since it uses the PARI method :pari:`bnfisprincipal`, specify
|
|
1171
|
+
``proof=True`` (this is the default setting) to prove the correctness
|
|
1172
|
+
of the output.
|
|
1173
|
+
|
|
1174
|
+
EXAMPLES::
|
|
1175
|
+
|
|
1176
|
+
sage: K = QuadraticField(-119,'a')
|
|
1177
|
+
sage: P = K.factor(2)[1][0]
|
|
1178
|
+
sage: P.is_principal()
|
|
1179
|
+
False
|
|
1180
|
+
sage: I = P^5
|
|
1181
|
+
sage: I.is_principal()
|
|
1182
|
+
True
|
|
1183
|
+
sage: I # random
|
|
1184
|
+
Fractional ideal (-1/2*a + 3/2)
|
|
1185
|
+
sage: P = K.ideal([2]).factor()[1][0]
|
|
1186
|
+
sage: I = P^5
|
|
1187
|
+
sage: I.is_principal()
|
|
1188
|
+
True
|
|
1189
|
+
"""
|
|
1190
|
+
if len(self.gens()) <= 1:
|
|
1191
|
+
self._is_principal = True
|
|
1192
|
+
self._reduced_generators = self.gens()
|
|
1193
|
+
return self._is_principal
|
|
1194
|
+
self._cache_bnfisprincipal(proof)
|
|
1195
|
+
return self._is_principal
|
|
1196
|
+
|
|
1197
|
+
def ideal_class_log(self, proof=None):
|
|
1198
|
+
r"""
|
|
1199
|
+
Return the output of PARI's :pari:`bnfisprincipal` for this ideal,
|
|
1200
|
+
i.e. a vector expressing the class of this ideal in terms of a
|
|
1201
|
+
set of generators for the class group.
|
|
1202
|
+
|
|
1203
|
+
Since it uses the PARI method :pari:`bnfisprincipal`, specify
|
|
1204
|
+
``proof=True`` (this is the default setting) to prove the correctness
|
|
1205
|
+
of the output.
|
|
1206
|
+
|
|
1207
|
+
EXAMPLES:
|
|
1208
|
+
|
|
1209
|
+
When the class number is 1, the result is always the empty list::
|
|
1210
|
+
|
|
1211
|
+
sage: K.<a> = QuadraticField(-163)
|
|
1212
|
+
sage: J = K.primes_above(random_prime(10^6))[0]
|
|
1213
|
+
sage: J.ideal_class_log()
|
|
1214
|
+
[]
|
|
1215
|
+
|
|
1216
|
+
An example with class group of order 2. The first ideal is
|
|
1217
|
+
not principal, the second one is::
|
|
1218
|
+
|
|
1219
|
+
sage: K.<a> = QuadraticField(-5)
|
|
1220
|
+
sage: J = K.ideal(23).factor()[0][0]
|
|
1221
|
+
sage: J.ideal_class_log()
|
|
1222
|
+
[1]
|
|
1223
|
+
sage: (J^10).ideal_class_log()
|
|
1224
|
+
[0]
|
|
1225
|
+
|
|
1226
|
+
An example with a more complicated class group::
|
|
1227
|
+
|
|
1228
|
+
sage: x = polygen(ZZ)
|
|
1229
|
+
sage: K.<a, b> = NumberField([x^3 - x + 1, x^2 + 26])
|
|
1230
|
+
sage: K.class_group()
|
|
1231
|
+
Class group of order 18 with structure C6 x C3 of
|
|
1232
|
+
Number Field in a with defining polynomial x^3 - x + 1 over its base field
|
|
1233
|
+
sage: K.primes_above(7)[0].ideal_class_log() # random
|
|
1234
|
+
[1, 2]
|
|
1235
|
+
"""
|
|
1236
|
+
self._cache_bnfisprincipal(proof)
|
|
1237
|
+
return self._ideal_class_log
|
|
1238
|
+
|
|
1239
|
+
def S_ideal_class_log(self, S):
|
|
1240
|
+
r"""
|
|
1241
|
+
S-class group version of :meth:`ideal_class_log`.
|
|
1242
|
+
|
|
1243
|
+
EXAMPLES::
|
|
1244
|
+
|
|
1245
|
+
sage: K.<a> = QuadraticField(-14)
|
|
1246
|
+
sage: S = K.primes_above(2)
|
|
1247
|
+
sage: I = K.ideal(3, a + 1)
|
|
1248
|
+
sage: I.S_ideal_class_log(S)
|
|
1249
|
+
[1]
|
|
1250
|
+
sage: I.S_ideal_class_log([])
|
|
1251
|
+
[3]
|
|
1252
|
+
|
|
1253
|
+
TESTS::
|
|
1254
|
+
|
|
1255
|
+
sage: K.<a> = QuadraticField(-974)
|
|
1256
|
+
sage: S = K.primes_above(2)
|
|
1257
|
+
sage: G = K.S_class_group(S)
|
|
1258
|
+
sage: I0 = G.0.ideal(); I1 = G.1.ideal()
|
|
1259
|
+
sage: for p in prime_range(100):
|
|
1260
|
+
....: for P in K.primes_above(p):
|
|
1261
|
+
....: v = P.S_ideal_class_log(S)
|
|
1262
|
+
....: assert(G(P) == G(I0^v[0] * I1^v[1]))
|
|
1263
|
+
"""
|
|
1264
|
+
from sage.modules.free_module_element import vector
|
|
1265
|
+
from sage.rings.finite_rings.integer_mod_ring import Zmod
|
|
1266
|
+
v = vector(ZZ, self.ideal_class_log())
|
|
1267
|
+
if all(P.is_principal() for P in S):
|
|
1268
|
+
L = v.list()
|
|
1269
|
+
invs = self.number_field().class_group().invariants()
|
|
1270
|
+
else:
|
|
1271
|
+
M = self.number_field()._S_class_group_quotient_matrix(tuple(S))
|
|
1272
|
+
L = (v * M).list()
|
|
1273
|
+
D = self.number_field()._S_class_group_and_units(tuple(S))[1]
|
|
1274
|
+
invs = [x[1] for x in D]
|
|
1275
|
+
return [Zmod(invs[i])(L[i]) for i in range(len(L))]
|
|
1276
|
+
|
|
1277
|
+
def is_zero(self):
|
|
1278
|
+
"""
|
|
1279
|
+
Return ``True`` iff ``self`` is the zero ideal.
|
|
1280
|
+
|
|
1281
|
+
Note that `(0)` is a :class:`NumberFieldIdeal`, not a
|
|
1282
|
+
:class:`NumberFieldFractionalIdeal`.
|
|
1283
|
+
|
|
1284
|
+
EXAMPLES::
|
|
1285
|
+
|
|
1286
|
+
sage: x = polygen(ZZ)
|
|
1287
|
+
sage: K.<a> = NumberField(x^2 + 2); K
|
|
1288
|
+
Number Field in a with defining polynomial x^2 + 2
|
|
1289
|
+
sage: K.ideal(3).is_zero()
|
|
1290
|
+
False
|
|
1291
|
+
sage: I = K.ideal(0); I.is_zero()
|
|
1292
|
+
True
|
|
1293
|
+
sage: I
|
|
1294
|
+
Ideal (0) of Number Field in a with defining polynomial x^2 + 2
|
|
1295
|
+
"""
|
|
1296
|
+
return self == self.number_field().ideal(0)
|
|
1297
|
+
|
|
1298
|
+
def norm(self):
|
|
1299
|
+
"""
|
|
1300
|
+
Return the norm of this fractional ideal as a rational number.
|
|
1301
|
+
|
|
1302
|
+
EXAMPLES::
|
|
1303
|
+
|
|
1304
|
+
sage: x = polygen(ZZ)
|
|
1305
|
+
sage: K.<a> = NumberField(x^4 + 23); K
|
|
1306
|
+
Number Field in a with defining polynomial x^4 + 23
|
|
1307
|
+
sage: I = K.ideal(19); I
|
|
1308
|
+
Fractional ideal (19)
|
|
1309
|
+
sage: factor(I.norm())
|
|
1310
|
+
19^4
|
|
1311
|
+
sage: F = I.factor()
|
|
1312
|
+
sage: F[0][0].norm().factor()
|
|
1313
|
+
19^2
|
|
1314
|
+
"""
|
|
1315
|
+
try:
|
|
1316
|
+
return self._norm
|
|
1317
|
+
except AttributeError:
|
|
1318
|
+
pass
|
|
1319
|
+
self._norm = QQ(self.number_field().pari_nf().idealnorm(self.pari_hnf()))
|
|
1320
|
+
return self._norm
|
|
1321
|
+
|
|
1322
|
+
# synonyms (using terminology of relative number fields)
|
|
1323
|
+
|
|
1324
|
+
def absolute_norm(self):
|
|
1325
|
+
"""
|
|
1326
|
+
A synonym for :meth:`norm`.
|
|
1327
|
+
|
|
1328
|
+
EXAMPLES::
|
|
1329
|
+
|
|
1330
|
+
sage: x = polygen(ZZ)
|
|
1331
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
1332
|
+
sage: K.ideal(1 + 2*i).absolute_norm()
|
|
1333
|
+
5
|
|
1334
|
+
"""
|
|
1335
|
+
return self.norm()
|
|
1336
|
+
|
|
1337
|
+
def relative_norm(self):
|
|
1338
|
+
"""
|
|
1339
|
+
A synonym for :meth:`norm`.
|
|
1340
|
+
|
|
1341
|
+
EXAMPLES::
|
|
1342
|
+
|
|
1343
|
+
sage: x = polygen(ZZ)
|
|
1344
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
1345
|
+
sage: K.ideal(1 + 2*i).relative_norm()
|
|
1346
|
+
5
|
|
1347
|
+
"""
|
|
1348
|
+
return self.norm()
|
|
1349
|
+
|
|
1350
|
+
def absolute_ramification_index(self):
|
|
1351
|
+
"""
|
|
1352
|
+
A synonym for :meth:`ramification_index`.
|
|
1353
|
+
|
|
1354
|
+
EXAMPLES::
|
|
1355
|
+
|
|
1356
|
+
sage: x = polygen(ZZ)
|
|
1357
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
1358
|
+
sage: K.ideal(1 + i).absolute_ramification_index()
|
|
1359
|
+
2
|
|
1360
|
+
"""
|
|
1361
|
+
return self.ramification_index()
|
|
1362
|
+
|
|
1363
|
+
def relative_ramification_index(self):
|
|
1364
|
+
"""
|
|
1365
|
+
A synonym for :meth:`ramification_index`.
|
|
1366
|
+
|
|
1367
|
+
EXAMPLES::
|
|
1368
|
+
|
|
1369
|
+
sage: x = polygen(ZZ)
|
|
1370
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
1371
|
+
sage: K.ideal(1 + i).relative_ramification_index()
|
|
1372
|
+
2
|
|
1373
|
+
"""
|
|
1374
|
+
return self.ramification_index()
|
|
1375
|
+
|
|
1376
|
+
def number_field(self):
|
|
1377
|
+
"""
|
|
1378
|
+
Return the number field that this is a fractional ideal in.
|
|
1379
|
+
|
|
1380
|
+
EXAMPLES::
|
|
1381
|
+
|
|
1382
|
+
sage: x = polygen(ZZ)
|
|
1383
|
+
sage: K.<a> = NumberField(x^2 + 2); K
|
|
1384
|
+
Number Field in a with defining polynomial x^2 + 2
|
|
1385
|
+
sage: K.ideal(3).number_field()
|
|
1386
|
+
Number Field in a with defining polynomial x^2 + 2
|
|
1387
|
+
sage: K.ideal(0).number_field() # not tested (not implemented)
|
|
1388
|
+
Number Field in a with defining polynomial x^2 + 2
|
|
1389
|
+
"""
|
|
1390
|
+
return self.ring()
|
|
1391
|
+
|
|
1392
|
+
def smallest_integer(self):
|
|
1393
|
+
r"""
|
|
1394
|
+
Return the smallest nonnegative integer in `I \cap \ZZ`,
|
|
1395
|
+
where `I` is this ideal. If `I = 0`, returns 0.
|
|
1396
|
+
|
|
1397
|
+
EXAMPLES::
|
|
1398
|
+
|
|
1399
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
1400
|
+
sage: K.<a> = NumberField(x^2 + 6)
|
|
1401
|
+
sage: I = K.ideal([4, a])/7; I
|
|
1402
|
+
Fractional ideal (2/7, 1/7*a)
|
|
1403
|
+
sage: I.smallest_integer()
|
|
1404
|
+
2
|
|
1405
|
+
|
|
1406
|
+
TESTS::
|
|
1407
|
+
|
|
1408
|
+
sage: K.<i> = QuadraticField(-1)
|
|
1409
|
+
sage: P1, P2 = [P for P,e in K.factor(13)]
|
|
1410
|
+
sage: all((P1^i*P2^j).smallest_integer() == 13^max(i,j,0) for i in range(-3,3) for j in range(-3,3))
|
|
1411
|
+
True
|
|
1412
|
+
sage: I = K.ideal(0)
|
|
1413
|
+
sage: I.smallest_integer()
|
|
1414
|
+
0
|
|
1415
|
+
|
|
1416
|
+
See :issue:`4392`::
|
|
1417
|
+
|
|
1418
|
+
sage: K.<a>=QuadraticField(-5)
|
|
1419
|
+
sage: I=K.ideal(7)
|
|
1420
|
+
sage: I.smallest_integer()
|
|
1421
|
+
7
|
|
1422
|
+
|
|
1423
|
+
sage: K.<z> = CyclotomicField(13)
|
|
1424
|
+
sage: a = K([-8, -4, -4, -6, 3, -4, 8, 0, 7, 4, 1, 2])
|
|
1425
|
+
sage: I = K.ideal(a)
|
|
1426
|
+
sage: I.smallest_integer()
|
|
1427
|
+
146196692151
|
|
1428
|
+
sage: I.norm()
|
|
1429
|
+
1315770229359
|
|
1430
|
+
sage: I.norm() / I.smallest_integer()
|
|
1431
|
+
9
|
|
1432
|
+
"""
|
|
1433
|
+
if self.is_zero():
|
|
1434
|
+
return ZZ(0)
|
|
1435
|
+
|
|
1436
|
+
# There is no need for caching since pari_hnf() is already cached.
|
|
1437
|
+
q = self.pari_hnf()[0,0] # PARI integer or rational
|
|
1438
|
+
return ZZ(q.numerator())
|
|
1439
|
+
|
|
1440
|
+
#Old code by John Cremona, 2008-10-30, using the new coordinates()
|
|
1441
|
+
#function instead of factorization.
|
|
1442
|
+
#
|
|
1443
|
+
#Idea: We write 1 as a Q-linear combination of the Z-basis of self,
|
|
1444
|
+
#and return the denominator of this vector.
|
|
1445
|
+
#
|
|
1446
|
+
#self.__smallest_integer = self.coordinates(1).denominator()
|
|
1447
|
+
#return self.__smallest_integer
|
|
1448
|
+
|
|
1449
|
+
def valuation(self, p):
|
|
1450
|
+
r"""
|
|
1451
|
+
Return the valuation of ``self`` at ``p``.
|
|
1452
|
+
|
|
1453
|
+
INPUT:
|
|
1454
|
+
|
|
1455
|
+
- ``p`` -- a prime ideal `\mathfrak{p}` of this number field
|
|
1456
|
+
|
|
1457
|
+
OUTPUT:
|
|
1458
|
+
|
|
1459
|
+
(integer) The valuation of this fractional ideal at the prime
|
|
1460
|
+
`\mathfrak{p}`. If `\mathfrak{p}` is not prime, raise a
|
|
1461
|
+
:exc:`ValueError`.
|
|
1462
|
+
|
|
1463
|
+
EXAMPLES::
|
|
1464
|
+
|
|
1465
|
+
sage: x = polygen(ZZ)
|
|
1466
|
+
sage: K.<a> = NumberField(x^5 + 2); K
|
|
1467
|
+
Number Field in a with defining polynomial x^5 + 2
|
|
1468
|
+
sage: i = K.ideal(38); i
|
|
1469
|
+
Fractional ideal (38)
|
|
1470
|
+
sage: i.valuation(K.factor(19)[0][0])
|
|
1471
|
+
1
|
|
1472
|
+
sage: i.valuation(K.factor(2)[0][0])
|
|
1473
|
+
5
|
|
1474
|
+
sage: i.valuation(K.factor(3)[0][0])
|
|
1475
|
+
0
|
|
1476
|
+
sage: i.valuation(0)
|
|
1477
|
+
Traceback (most recent call last):
|
|
1478
|
+
...
|
|
1479
|
+
ValueError: p (= Ideal (0) of Number Field in a
|
|
1480
|
+
with defining polynomial x^5 + 2) must be nonzero
|
|
1481
|
+
sage: K.ideal(0).valuation(K.factor(2)[0][0])
|
|
1482
|
+
+Infinity
|
|
1483
|
+
"""
|
|
1484
|
+
if not isinstance(p, NumberFieldIdeal):
|
|
1485
|
+
p = self.number_field().ideal(p)
|
|
1486
|
+
if not p:
|
|
1487
|
+
raise ValueError("p (= %s) must be nonzero" % p)
|
|
1488
|
+
if not p.is_prime():
|
|
1489
|
+
raise ValueError("p (= %s) must be a prime" % p)
|
|
1490
|
+
if p.ring() != self.number_field():
|
|
1491
|
+
raise ValueError("p (= %s) must be an ideal in %s" % self.number_field())
|
|
1492
|
+
nf = self.number_field().pari_nf()
|
|
1493
|
+
return nf.idealval(self.pari_hnf(), p.pari_prime()).sage()
|
|
1494
|
+
|
|
1495
|
+
def decomposition_group(self):
|
|
1496
|
+
r"""
|
|
1497
|
+
Return the decomposition group of ``self``, as a subset of the
|
|
1498
|
+
automorphism group of the number field of ``self``. Raises an
|
|
1499
|
+
error if the field isn't Galois. See the :meth:`GaloisGroup_v2.decomposition_group`
|
|
1500
|
+
method for further examples and doctests.
|
|
1501
|
+
|
|
1502
|
+
EXAMPLES::
|
|
1503
|
+
|
|
1504
|
+
sage: QuadraticField(-23, 'w').primes_above(7)[0].decomposition_group() # needs sage.groups
|
|
1505
|
+
Subgroup generated by [(1,2)] of (Galois group 2T1 (S2) with order 2 of x^2 + 23)
|
|
1506
|
+
"""
|
|
1507
|
+
return self.number_field().galois_group().decomposition_group(self)
|
|
1508
|
+
|
|
1509
|
+
def ramification_group(self, v):
|
|
1510
|
+
r"""
|
|
1511
|
+
Return the `v`-th ramification group of ``self``, i.e. the set of
|
|
1512
|
+
elements `s` of the Galois group of the number field of ``self``
|
|
1513
|
+
(which we assume is Galois) such that `s` acts trivially
|
|
1514
|
+
modulo the `(v+1)`'st power of ``self``. See the
|
|
1515
|
+
:meth:`GaloisGroup.ramification_group` method for
|
|
1516
|
+
further examples and doctests.
|
|
1517
|
+
|
|
1518
|
+
EXAMPLES::
|
|
1519
|
+
|
|
1520
|
+
sage: QuadraticField(-23, 'w').primes_above(23)[0].ramification_group(0) # needs sage.groups
|
|
1521
|
+
Subgroup generated by [(1,2)] of (Galois group 2T1 (S2) with order 2 of x^2 + 23)
|
|
1522
|
+
sage: QuadraticField(-23, 'w').primes_above(23)[0].ramification_group(1) # needs sage.groups
|
|
1523
|
+
Subgroup generated by [()] of (Galois group 2T1 (S2) with order 2 of x^2 + 23)
|
|
1524
|
+
"""
|
|
1525
|
+
|
|
1526
|
+
return self.number_field().galois_group().ramification_group(self, v)
|
|
1527
|
+
|
|
1528
|
+
def inertia_group(self):
|
|
1529
|
+
r"""
|
|
1530
|
+
Return the inertia group of ``self``, i.e. the set of elements `s` of the
|
|
1531
|
+
Galois group of the number field of ``self`` (which we assume is Galois)
|
|
1532
|
+
such that `s` acts trivially modulo ``self``. This is the same as the 0th
|
|
1533
|
+
ramification group of ``self``. See the
|
|
1534
|
+
:meth:`GaloisGroup_v2.inertia_group` method further examples and doctests.
|
|
1535
|
+
|
|
1536
|
+
EXAMPLES::
|
|
1537
|
+
|
|
1538
|
+
sage: QuadraticField(-23, 'w').primes_above(23)[0].inertia_group() # needs sage.groups
|
|
1539
|
+
Subgroup generated by [(1,2)] of (Galois group 2T1 (S2) with order 2 of x^2 + 23)
|
|
1540
|
+
"""
|
|
1541
|
+
return self.ramification_group(0)
|
|
1542
|
+
|
|
1543
|
+
def random_element(self, *args, **kwds):
|
|
1544
|
+
r"""
|
|
1545
|
+
Return a random element of this ideal.
|
|
1546
|
+
|
|
1547
|
+
INPUT:
|
|
1548
|
+
|
|
1549
|
+
- ``*args``, ``*kwds`` -- parameters passed to the random integer
|
|
1550
|
+
function. See the documentation of ``ZZ.random_element()`` for
|
|
1551
|
+
details.
|
|
1552
|
+
|
|
1553
|
+
OUTPUT:
|
|
1554
|
+
|
|
1555
|
+
A random element of this fractional ideal, computed as a random
|
|
1556
|
+
`\ZZ`-linear combination of the basis.
|
|
1557
|
+
|
|
1558
|
+
EXAMPLES::
|
|
1559
|
+
|
|
1560
|
+
sage: x = polygen(ZZ)
|
|
1561
|
+
sage: K.<a> = NumberField(x^3 + 2)
|
|
1562
|
+
sage: I = K.ideal(1 - a)
|
|
1563
|
+
sage: I.random_element() # random output
|
|
1564
|
+
-a^2 - a - 19
|
|
1565
|
+
sage: I.random_element(distribution='uniform') # random output
|
|
1566
|
+
a^2 - 2*a - 8
|
|
1567
|
+
sage: I.random_element(-30, 30) # random output
|
|
1568
|
+
-7*a^2 - 17*a - 75
|
|
1569
|
+
sage: I.random_element(-100, 200).is_integral()
|
|
1570
|
+
True
|
|
1571
|
+
sage: I.random_element(-30, 30).parent() is K
|
|
1572
|
+
True
|
|
1573
|
+
|
|
1574
|
+
A relative example::
|
|
1575
|
+
|
|
1576
|
+
sage: K.<a, b> = NumberField([x^2 + 2, x^2 + 1000*x + 1])
|
|
1577
|
+
sage: I = K.ideal(1 - a)
|
|
1578
|
+
sage: I.random_element() # random output
|
|
1579
|
+
17/500002*a^3 + 737253/250001*a^2 - 1494505893/500002*a + 752473260/250001
|
|
1580
|
+
sage: I.random_element().is_integral()
|
|
1581
|
+
True
|
|
1582
|
+
sage: I.random_element(-100, 200).parent() is K
|
|
1583
|
+
True
|
|
1584
|
+
"""
|
|
1585
|
+
if self.number_field().is_absolute():
|
|
1586
|
+
basis = self.basis()
|
|
1587
|
+
else:
|
|
1588
|
+
basis = self.absolute_ideal().basis()
|
|
1589
|
+
return self.number_field()(sum([ZZ.random_element(*args, **kwds)*a for a in basis]))
|
|
1590
|
+
|
|
1591
|
+
def artin_symbol(self):
|
|
1592
|
+
r"""
|
|
1593
|
+
Return the Artin symbol `(K / \QQ, P)`, where `K` is the
|
|
1594
|
+
number field of `P` = ``self``. This is the unique element `s` of
|
|
1595
|
+
the decomposition group of `P` such that `s(x) = x^p \pmod{P}`
|
|
1596
|
+
where `p` is the residue characteristic of `P`. (Here `P`
|
|
1597
|
+
(``self``) should be prime and unramified.)
|
|
1598
|
+
|
|
1599
|
+
See the :meth:`GaloisGroup_v2.artin_symbol` method
|
|
1600
|
+
for further documentation and examples.
|
|
1601
|
+
|
|
1602
|
+
EXAMPLES::
|
|
1603
|
+
|
|
1604
|
+
sage: QuadraticField(-23, 'w').primes_above(7)[0].artin_symbol() # needs sage.groups
|
|
1605
|
+
(1,2)
|
|
1606
|
+
"""
|
|
1607
|
+
return self.number_field().galois_group().artin_symbol(self)
|
|
1608
|
+
|
|
1609
|
+
def residue_symbol(self, e, m, check=True):
|
|
1610
|
+
r"""
|
|
1611
|
+
The `m`-th power residue symbol for an element `e` and the proper ideal.
|
|
1612
|
+
|
|
1613
|
+
.. MATH:: \left(\frac{\alpha}{\mathbf{P}}\right) \equiv \alpha^{\frac{N(\mathbf{P})-1}{m}} \operatorname{mod} \mathbf{P}
|
|
1614
|
+
|
|
1615
|
+
.. NOTE:: accepts `m=1`, in which case returns 1
|
|
1616
|
+
|
|
1617
|
+
.. NOTE:: can also be called for an element from sage.rings.number_field_element.residue_symbol
|
|
1618
|
+
|
|
1619
|
+
.. NOTE:: `e` is coerced into the number field of ``self``
|
|
1620
|
+
|
|
1621
|
+
.. NOTE::
|
|
1622
|
+
|
|
1623
|
+
if `m=2`, `e` is an integer, and ``self.number_field()`` has absolute degree 1 (i.e. it is a copy of the rationals),
|
|
1624
|
+
then this calls :func:`kronecker_symbol`, which is implemented using GMP.
|
|
1625
|
+
|
|
1626
|
+
INPUT:
|
|
1627
|
+
|
|
1628
|
+
- ``e`` -- element of the number field
|
|
1629
|
+
|
|
1630
|
+
- ``m`` -- positive integer
|
|
1631
|
+
|
|
1632
|
+
OUTPUT: an `m`-th root of unity in the number field
|
|
1633
|
+
|
|
1634
|
+
EXAMPLES:
|
|
1635
|
+
|
|
1636
|
+
Quadratic Residue (7 is not a square modulo 11)::
|
|
1637
|
+
|
|
1638
|
+
sage: x = polygen(ZZ)
|
|
1639
|
+
sage: K.<a> = NumberField(x - 1)
|
|
1640
|
+
sage: K.ideal(11).residue_symbol(7,2)
|
|
1641
|
+
-1
|
|
1642
|
+
|
|
1643
|
+
Cubic Residue::
|
|
1644
|
+
|
|
1645
|
+
sage: K.<w> = NumberField(x^2 - x + 1)
|
|
1646
|
+
sage: K.ideal(17).residue_symbol(w^2 + 3, 3)
|
|
1647
|
+
-w
|
|
1648
|
+
|
|
1649
|
+
The field must contain the `m`-th roots of unity::
|
|
1650
|
+
|
|
1651
|
+
sage: K.<w> = NumberField(x^2 - x + 1)
|
|
1652
|
+
sage: K.ideal(17).residue_symbol(w^2 + 3, 5)
|
|
1653
|
+
Traceback (most recent call last):
|
|
1654
|
+
...
|
|
1655
|
+
ValueError: The residue symbol to that power is not defined for the number field
|
|
1656
|
+
"""
|
|
1657
|
+
K = self.ring()
|
|
1658
|
+
if m == 2 and K.absolute_degree() == 1:
|
|
1659
|
+
try:
|
|
1660
|
+
ze = ZZ(e)
|
|
1661
|
+
zp = self.smallest_integer()
|
|
1662
|
+
except TypeError:
|
|
1663
|
+
pass
|
|
1664
|
+
else:
|
|
1665
|
+
return kronecker_symbol(ze, zp)
|
|
1666
|
+
if check:
|
|
1667
|
+
if self.is_trivial():
|
|
1668
|
+
raise ValueError("Ideal must be proper")
|
|
1669
|
+
if m < 1:
|
|
1670
|
+
raise ValueError("Power must be positive")
|
|
1671
|
+
if not self.is_coprime(e):
|
|
1672
|
+
raise ValueError("Element is not coprime to the ideal")
|
|
1673
|
+
if not self.is_coprime(m):
|
|
1674
|
+
raise ValueError("Ideal is not coprime to the power")
|
|
1675
|
+
primroot = K.primitive_root_of_unity()
|
|
1676
|
+
rootorder = primroot.multiplicative_order()
|
|
1677
|
+
if check:
|
|
1678
|
+
if rootorder % m:
|
|
1679
|
+
raise ValueError("The residue symbol to that power is not defined for the number field")
|
|
1680
|
+
if not self.is_prime():
|
|
1681
|
+
return prod(Q.residue_symbol(e,m,check=False)**i for Q, i in self.factor())
|
|
1682
|
+
k = self.residue_field()
|
|
1683
|
+
try:
|
|
1684
|
+
r = k(e)
|
|
1685
|
+
except TypeError:
|
|
1686
|
+
raise ValueError("Element and ideal must be in a common number field")
|
|
1687
|
+
r = k(r**((k.order()-1)/m))
|
|
1688
|
+
resroot = primroot**(rootorder/m)
|
|
1689
|
+
from sage.groups.generic import discrete_log
|
|
1690
|
+
j = discrete_log(k(r), k(resroot), ord=m)
|
|
1691
|
+
return resroot**j
|
|
1692
|
+
|
|
1693
|
+
def _quadratic_form(self):
|
|
1694
|
+
r"""
|
|
1695
|
+
If this is a quadratic extension over `\QQ`, return the binary
|
|
1696
|
+
quadratic form associated with this ideal.
|
|
1697
|
+
|
|
1698
|
+
EXAMPLES::
|
|
1699
|
+
|
|
1700
|
+
sage: K.<a> = QuadraticField(23)
|
|
1701
|
+
sage: K.ideal(a).quadratic_form()
|
|
1702
|
+
23*x^2 - y^2
|
|
1703
|
+
|
|
1704
|
+
sage: K.<a> = QuadraticField(-5)
|
|
1705
|
+
sage: K.class_group().order()
|
|
1706
|
+
2
|
|
1707
|
+
sage: A = K.class_group().gen()
|
|
1708
|
+
sage: A.ideal().quadratic_form().reduced_form()
|
|
1709
|
+
2*x^2 + 2*x*y + 3*y^2
|
|
1710
|
+
sage: (A^2).ideal().quadratic_form().reduced_form()
|
|
1711
|
+
x^2 + 5*y^2
|
|
1712
|
+
|
|
1713
|
+
sage: K.<a> = QuadraticField(-40)
|
|
1714
|
+
sage: K.class_group().order()
|
|
1715
|
+
2
|
|
1716
|
+
sage: A = K.class_group().gen()
|
|
1717
|
+
sage: A.ideal().quadratic_form().reduced_form()
|
|
1718
|
+
2*x^2 + 5*y^2
|
|
1719
|
+
sage: (A^2).ideal().quadratic_form().reduced_form()
|
|
1720
|
+
x^2 + 10*y^2
|
|
1721
|
+
|
|
1722
|
+
One more check::
|
|
1723
|
+
|
|
1724
|
+
sage: K = QuadraticField(-79)
|
|
1725
|
+
sage: A = K.class_group().gen()
|
|
1726
|
+
sage: [(A**i).ideal().quadratic_form().discriminant()
|
|
1727
|
+
....: for i in range(5)]
|
|
1728
|
+
[-79, -79, -79, -79, -79]
|
|
1729
|
+
|
|
1730
|
+
This is not defined for higher-degree extensions::
|
|
1731
|
+
|
|
1732
|
+
sage: x = polygen(ZZ)
|
|
1733
|
+
sage: K.<a> = NumberField(x**3 - x - 1)
|
|
1734
|
+
sage: K.ideal(a)._quadratic_form()
|
|
1735
|
+
Traceback (most recent call last):
|
|
1736
|
+
...
|
|
1737
|
+
ValueError: not defined for ideals in number fields of degree > 2 over Q.
|
|
1738
|
+
|
|
1739
|
+
REFERENCES:
|
|
1740
|
+
|
|
1741
|
+
- [Coh1993]_
|
|
1742
|
+
"""
|
|
1743
|
+
K = self.number_field()
|
|
1744
|
+
if K.degree() == 2:
|
|
1745
|
+
from sage.quadratic_forms.binary_qf import BinaryQF
|
|
1746
|
+
gens = self.gens_reduced()
|
|
1747
|
+
if len(gens) == 1:
|
|
1748
|
+
u, v = K.ring_of_integers().basis()
|
|
1749
|
+
alpha, beta = gens[0] * u, gens[0] * v
|
|
1750
|
+
else:
|
|
1751
|
+
alpha, beta = gens
|
|
1752
|
+
if QQ((beta * alpha.galois_conjugate() - alpha * beta.galois_conjugate()) / K.gen()) < 0:
|
|
1753
|
+
alpha, beta = beta, alpha
|
|
1754
|
+
N = self.norm()
|
|
1755
|
+
a = alpha.norm() // N
|
|
1756
|
+
b = ZZ(alpha * beta.galois_conjugate() +
|
|
1757
|
+
beta * alpha.galois_conjugate()) // N
|
|
1758
|
+
c = beta.norm() // N
|
|
1759
|
+
return BinaryQF([a, b, c])
|
|
1760
|
+
|
|
1761
|
+
raise ValueError("not defined for ideals in number fields of degree > 2 over Q.")
|
|
1762
|
+
|
|
1763
|
+
|
|
1764
|
+
def basis_to_module(B, K):
|
|
1765
|
+
r"""
|
|
1766
|
+
Given a basis `B` of elements for a `\ZZ`-submodule of a number
|
|
1767
|
+
field `K`, return the corresponding `\ZZ`-submodule.
|
|
1768
|
+
|
|
1769
|
+
EXAMPLES::
|
|
1770
|
+
|
|
1771
|
+
sage: x = polygen(ZZ)
|
|
1772
|
+
sage: K.<w> = NumberField(x^4 + 1)
|
|
1773
|
+
sage: from sage.rings.number_field.number_field_ideal import basis_to_module
|
|
1774
|
+
sage: basis_to_module([K.0, K.0^2 + 3], K)
|
|
1775
|
+
Free module of degree 4 and rank 2 over Integer Ring
|
|
1776
|
+
User basis matrix:
|
|
1777
|
+
[0 1 0 0]
|
|
1778
|
+
[3 0 1 0]
|
|
1779
|
+
"""
|
|
1780
|
+
V, from_V, to_V = K.absolute_vector_space()
|
|
1781
|
+
M = ZZ**(V.dimension())
|
|
1782
|
+
C = [to_V(K(b)) for b in B]
|
|
1783
|
+
return M.span_of_basis(C)
|
|
1784
|
+
|
|
1785
|
+
|
|
1786
|
+
def is_NumberFieldIdeal(x):
|
|
1787
|
+
"""
|
|
1788
|
+
Return ``True`` if `x` is an ideal of a number field.
|
|
1789
|
+
|
|
1790
|
+
EXAMPLES::
|
|
1791
|
+
|
|
1792
|
+
sage: from sage.rings.number_field.number_field_ideal import is_NumberFieldIdeal
|
|
1793
|
+
sage: is_NumberFieldIdeal(2/3)
|
|
1794
|
+
doctest:warning...
|
|
1795
|
+
DeprecationWarning: The function is_NumberFieldIdeal is deprecated;
|
|
1796
|
+
use 'isinstance(..., NumberFieldIdeal)' instead.
|
|
1797
|
+
See https://github.com/sagemath/sage/issues/38124 for details.
|
|
1798
|
+
False
|
|
1799
|
+
sage: is_NumberFieldIdeal(ideal(5))
|
|
1800
|
+
False
|
|
1801
|
+
|
|
1802
|
+
sage: x = polygen(ZZ)
|
|
1803
|
+
sage: k.<a> = NumberField(x^2 + 2)
|
|
1804
|
+
sage: I = k.ideal([a + 1]); I
|
|
1805
|
+
Fractional ideal (a + 1)
|
|
1806
|
+
sage: is_NumberFieldIdeal(I)
|
|
1807
|
+
True
|
|
1808
|
+
sage: Z = k.ideal(0); Z
|
|
1809
|
+
Ideal (0) of Number Field in a with defining polynomial x^2 + 2
|
|
1810
|
+
sage: is_NumberFieldIdeal(Z)
|
|
1811
|
+
True
|
|
1812
|
+
"""
|
|
1813
|
+
from sage.misc.superseded import deprecation
|
|
1814
|
+
deprecation(38124,
|
|
1815
|
+
"The function is_NumberFieldIdeal is deprecated; "
|
|
1816
|
+
"use 'isinstance(..., NumberFieldIdeal)' instead.")
|
|
1817
|
+
return isinstance(x, NumberFieldIdeal)
|
|
1818
|
+
|
|
1819
|
+
|
|
1820
|
+
class NumberFieldFractionalIdeal(MultiplicativeGroupElement, NumberFieldIdeal, Ideal_fractional):
|
|
1821
|
+
r"""
|
|
1822
|
+
A fractional ideal in a number field.
|
|
1823
|
+
|
|
1824
|
+
EXAMPLES::
|
|
1825
|
+
|
|
1826
|
+
sage: x = polygen(ZZ)
|
|
1827
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
1828
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
1829
|
+
sage: I = K.ideal(2/(5+a))
|
|
1830
|
+
sage: J = I^2
|
|
1831
|
+
sage: Jinv = I^(-2)
|
|
1832
|
+
sage: J*Jinv
|
|
1833
|
+
Fractional ideal (1)
|
|
1834
|
+
|
|
1835
|
+
TESTS:
|
|
1836
|
+
|
|
1837
|
+
Number-field fractional ideals are fractional ideals (:issue:`32380`)::
|
|
1838
|
+
|
|
1839
|
+
sage: from sage.rings.ideal import Ideal_fractional
|
|
1840
|
+
sage: isinstance(I, Ideal_fractional)
|
|
1841
|
+
True
|
|
1842
|
+
"""
|
|
1843
|
+
def __init__(self, field, gens, coerce=True):
|
|
1844
|
+
"""
|
|
1845
|
+
INPUT:
|
|
1846
|
+
|
|
1847
|
+
- ``field`` -- a number field
|
|
1848
|
+
- ``x`` -- list of NumberFieldElements of the field, not all zero
|
|
1849
|
+
|
|
1850
|
+
EXAMPLES::
|
|
1851
|
+
|
|
1852
|
+
sage: x = polygen(ZZ)
|
|
1853
|
+
sage: NumberField(x^2 + 1, 'a').ideal(7)
|
|
1854
|
+
Fractional ideal (7)
|
|
1855
|
+
"""
|
|
1856
|
+
from .number_field import NumberField_generic
|
|
1857
|
+
if not isinstance(field, NumberField_generic):
|
|
1858
|
+
raise TypeError("field (=%s) must be a number field." % field)
|
|
1859
|
+
|
|
1860
|
+
if not gens:
|
|
1861
|
+
raise ValueError("gens must have length at least 1 (zero ideal is not a fractional ideal)")
|
|
1862
|
+
if len(gens) == 1 and isinstance(gens[0], (list, tuple)):
|
|
1863
|
+
gens = gens[0]
|
|
1864
|
+
if any(bool(x) for x in gens):
|
|
1865
|
+
NumberFieldIdeal.__init__(self, field, gens)
|
|
1866
|
+
else:
|
|
1867
|
+
raise ValueError("gens must have a nonzero element (zero ideal is not a fractional ideal)")
|
|
1868
|
+
|
|
1869
|
+
def _repr_(self):
|
|
1870
|
+
"""
|
|
1871
|
+
Return the string representation of this number field fractional ideal.
|
|
1872
|
+
|
|
1873
|
+
.. NOTE::
|
|
1874
|
+
|
|
1875
|
+
Only the zero ideal actually has type NumberFieldIdeal; all
|
|
1876
|
+
others have type NumberFieldFractionalIdeal.
|
|
1877
|
+
|
|
1878
|
+
EXAMPLES::
|
|
1879
|
+
|
|
1880
|
+
sage: x = polygen(ZZ)
|
|
1881
|
+
sage: K.<a> = NumberField(x^2 + 5)
|
|
1882
|
+
sage: I = K.ideal([2,1+a]); I
|
|
1883
|
+
Fractional ideal (2, a + 1)
|
|
1884
|
+
sage: type(I)
|
|
1885
|
+
<class 'sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal'>
|
|
1886
|
+
"""
|
|
1887
|
+
return "Fractional ideal %s" % self._repr_short()
|
|
1888
|
+
|
|
1889
|
+
def divides(self, other):
|
|
1890
|
+
"""
|
|
1891
|
+
Return ``True`` if this ideal divides ``other`` and ``False`` otherwise.
|
|
1892
|
+
|
|
1893
|
+
EXAMPLES::
|
|
1894
|
+
|
|
1895
|
+
sage: K.<a> = CyclotomicField(11); K
|
|
1896
|
+
Cyclotomic Field of order 11 and degree 10
|
|
1897
|
+
sage: I = K.factor(31)[0][0]; I
|
|
1898
|
+
Fractional ideal (31, a^5 + 10*a^4 - a^3 + a^2 + 9*a - 1)
|
|
1899
|
+
sage: I.divides(I)
|
|
1900
|
+
True
|
|
1901
|
+
sage: I.divides(31)
|
|
1902
|
+
True
|
|
1903
|
+
sage: I.divides(29)
|
|
1904
|
+
False
|
|
1905
|
+
"""
|
|
1906
|
+
if not isinstance(other, NumberFieldIdeal):
|
|
1907
|
+
other = self.number_field().ideal(other)
|
|
1908
|
+
return (other / self).is_integral()
|
|
1909
|
+
|
|
1910
|
+
def factor(self):
|
|
1911
|
+
"""
|
|
1912
|
+
Factorization of this ideal in terms of prime ideals.
|
|
1913
|
+
|
|
1914
|
+
EXAMPLES::
|
|
1915
|
+
|
|
1916
|
+
sage: x = polygen(ZZ)
|
|
1917
|
+
sage: K.<a> = NumberField(x^4 + 23); K
|
|
1918
|
+
Number Field in a with defining polynomial x^4 + 23
|
|
1919
|
+
sage: I = K.ideal(19); I
|
|
1920
|
+
Fractional ideal (19)
|
|
1921
|
+
sage: F = I.factor(); F
|
|
1922
|
+
(Fractional ideal (19, 1/2*a^2 + a - 17/2))
|
|
1923
|
+
* (Fractional ideal (19, 1/2*a^2 - a - 17/2))
|
|
1924
|
+
sage: type(F)
|
|
1925
|
+
<class 'sage.structure.factorization.Factorization'>
|
|
1926
|
+
sage: list(F)
|
|
1927
|
+
[(Fractional ideal (19, 1/2*a^2 + a - 17/2), 1),
|
|
1928
|
+
(Fractional ideal (19, 1/2*a^2 - a - 17/2), 1)]
|
|
1929
|
+
sage: F.prod()
|
|
1930
|
+
Fractional ideal (19)
|
|
1931
|
+
|
|
1932
|
+
TESTS:
|
|
1933
|
+
|
|
1934
|
+
Number fields defined by non-monic and non-integral
|
|
1935
|
+
polynomials are supported (:issue:`252`);
|
|
1936
|
+
the representation depends on the PARI version::
|
|
1937
|
+
|
|
1938
|
+
sage: F.<a> = NumberField(2*x^3 + x + 1)
|
|
1939
|
+
sage: fact = F.factor(2)
|
|
1940
|
+
sage: (fact[0][1], fact[1][1])
|
|
1941
|
+
(2, 1)
|
|
1942
|
+
sage: fact[0][0] == F.ideal(2*a^2 + 1)
|
|
1943
|
+
True
|
|
1944
|
+
sage: fact[1][0] == F.ideal(-2*a^2)
|
|
1945
|
+
True
|
|
1946
|
+
sage: [p[0].norm() for p in fact]
|
|
1947
|
+
[2, 2]
|
|
1948
|
+
"""
|
|
1949
|
+
try:
|
|
1950
|
+
return self.__factorization
|
|
1951
|
+
except AttributeError:
|
|
1952
|
+
K = self.number_field()
|
|
1953
|
+
F = K.pari_nf().idealfactor(self.pari_hnf())
|
|
1954
|
+
A = []
|
|
1955
|
+
for j in range(0, len(F[0])):
|
|
1956
|
+
I = K.ideal(F[j,0])
|
|
1957
|
+
A.append((I,ZZ(F[j,1])))
|
|
1958
|
+
self.__factorization = Factorization(A)
|
|
1959
|
+
return self.__factorization
|
|
1960
|
+
|
|
1961
|
+
def prime_factors(self):
|
|
1962
|
+
"""
|
|
1963
|
+
Return a list of the prime ideal factors of ``self``.
|
|
1964
|
+
|
|
1965
|
+
OUTPUT:
|
|
1966
|
+
|
|
1967
|
+
list of prime ideals (a new list is returned
|
|
1968
|
+
each time this function is called)
|
|
1969
|
+
|
|
1970
|
+
EXAMPLES::
|
|
1971
|
+
|
|
1972
|
+
sage: x = polygen(ZZ)
|
|
1973
|
+
sage: K.<w> = NumberField(x^2 + 23)
|
|
1974
|
+
sage: I = ideal(w+1)
|
|
1975
|
+
sage: I.prime_factors()
|
|
1976
|
+
[Fractional ideal (2, 1/2*w - 1/2),
|
|
1977
|
+
Fractional ideal (2, 1/2*w + 1/2),
|
|
1978
|
+
Fractional ideal (3, 1/2*w + 1/2)]
|
|
1979
|
+
"""
|
|
1980
|
+
return [x[0] for x in self.factor()]
|
|
1981
|
+
|
|
1982
|
+
support = prime_factors
|
|
1983
|
+
|
|
1984
|
+
def _div_(self, other):
|
|
1985
|
+
"""
|
|
1986
|
+
Return the quotient ``self`` / ``other``.
|
|
1987
|
+
|
|
1988
|
+
EXAMPLES::
|
|
1989
|
+
|
|
1990
|
+
sage: x = polygen(ZZ)
|
|
1991
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
1992
|
+
sage: K.<a> = NumberField(x^2 - 5)
|
|
1993
|
+
sage: I = K.ideal(2/(5+a))
|
|
1994
|
+
sage: J = K.ideal(17+a)
|
|
1995
|
+
sage: I/J
|
|
1996
|
+
Fractional ideal (-11/1420*a + 9/284)
|
|
1997
|
+
sage: (I/J) * J == I
|
|
1998
|
+
True
|
|
1999
|
+
"""
|
|
2000
|
+
K = self.ring()
|
|
2001
|
+
if self.ngens() == 1 and other.ngens() == 1:
|
|
2002
|
+
return K.ideal(self.gen(0) / other.gen(0))
|
|
2003
|
+
return K.ideal(K.pari_nf().idealdiv(self, other))
|
|
2004
|
+
|
|
2005
|
+
def __invert__(self):
|
|
2006
|
+
"""
|
|
2007
|
+
Return the multiplicative inverse of ``self``. Call with ``~self``.
|
|
2008
|
+
|
|
2009
|
+
EXAMPLES::
|
|
2010
|
+
|
|
2011
|
+
sage: x = polygen(ZZ)
|
|
2012
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
2013
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
2014
|
+
sage: I = K.ideal(2/(5+a))
|
|
2015
|
+
sage: ~I
|
|
2016
|
+
Fractional ideal (1/2*a + 5/2)
|
|
2017
|
+
sage: 1/I
|
|
2018
|
+
Fractional ideal (1/2*a + 5/2)
|
|
2019
|
+
sage: (1/I) * I
|
|
2020
|
+
Fractional ideal (1)
|
|
2021
|
+
"""
|
|
2022
|
+
nf = self.number_field().pari_nf()
|
|
2023
|
+
hnf = nf.idealdiv(self.number_field().ideal(1).pari_hnf(),
|
|
2024
|
+
self.pari_hnf())
|
|
2025
|
+
I = self.number_field().ideal(NumberFieldIdeal._NumberFieldIdeal__elements_from_hnf(self,hnf))
|
|
2026
|
+
I.__pari_hnf = hnf
|
|
2027
|
+
return I
|
|
2028
|
+
|
|
2029
|
+
def is_maximal(self):
|
|
2030
|
+
"""
|
|
2031
|
+
Return ``True`` if this ideal is maximal. This is equivalent to
|
|
2032
|
+
``self`` being prime, since it is nonzero.
|
|
2033
|
+
|
|
2034
|
+
EXAMPLES::
|
|
2035
|
+
|
|
2036
|
+
sage: x = polygen(ZZ)
|
|
2037
|
+
sage: K.<a> = NumberField(x^3 + 3); K
|
|
2038
|
+
Number Field in a with defining polynomial x^3 + 3
|
|
2039
|
+
sage: K.ideal(5).is_maximal()
|
|
2040
|
+
False
|
|
2041
|
+
sage: K.ideal(7).is_maximal()
|
|
2042
|
+
True
|
|
2043
|
+
"""
|
|
2044
|
+
return self.is_prime()
|
|
2045
|
+
|
|
2046
|
+
def is_trivial(self, proof=None):
|
|
2047
|
+
"""
|
|
2048
|
+
Return ``True`` if this is a trivial ideal.
|
|
2049
|
+
|
|
2050
|
+
EXAMPLES::
|
|
2051
|
+
|
|
2052
|
+
sage: F.<a> = QuadraticField(-5)
|
|
2053
|
+
sage: I = F.ideal(3)
|
|
2054
|
+
sage: I.is_trivial()
|
|
2055
|
+
False
|
|
2056
|
+
sage: J = F.ideal(5)
|
|
2057
|
+
sage: J.is_trivial()
|
|
2058
|
+
False
|
|
2059
|
+
sage: (I + J).is_trivial()
|
|
2060
|
+
True
|
|
2061
|
+
"""
|
|
2062
|
+
return self == self.number_field().ideal(1)
|
|
2063
|
+
|
|
2064
|
+
def ramification_index(self):
|
|
2065
|
+
r"""
|
|
2066
|
+
Return the ramification index of this fractional ideal,
|
|
2067
|
+
assuming it is prime. Otherwise, raise a :exc:`ValueError`.
|
|
2068
|
+
|
|
2069
|
+
The ramification index is the power of this prime appearing in
|
|
2070
|
+
the factorization of the prime in `\ZZ` that this prime lies
|
|
2071
|
+
over.
|
|
2072
|
+
|
|
2073
|
+
EXAMPLES::
|
|
2074
|
+
|
|
2075
|
+
sage: x = polygen(ZZ)
|
|
2076
|
+
sage: K.<a> = NumberField(x^2 + 2); K
|
|
2077
|
+
Number Field in a with defining polynomial x^2 + 2
|
|
2078
|
+
sage: f = K.factor(2); f
|
|
2079
|
+
(Fractional ideal (a))^2
|
|
2080
|
+
sage: f[0][0].ramification_index()
|
|
2081
|
+
2
|
|
2082
|
+
sage: K.ideal(13).ramification_index()
|
|
2083
|
+
1
|
|
2084
|
+
sage: K.ideal(17).ramification_index()
|
|
2085
|
+
Traceback (most recent call last):
|
|
2086
|
+
...
|
|
2087
|
+
ValueError: Fractional ideal (17) is not a prime ideal
|
|
2088
|
+
"""
|
|
2089
|
+
return ZZ(self.pari_prime().pr_get_e())
|
|
2090
|
+
|
|
2091
|
+
def reduce(self, f):
|
|
2092
|
+
r"""
|
|
2093
|
+
Return the canonical reduction of the element `f` modulo the ideal
|
|
2094
|
+
`I` (= ``self``). This is an element of `R` (the ring of integers of the
|
|
2095
|
+
number field) that is equivalent modulo `I` to `f`.
|
|
2096
|
+
|
|
2097
|
+
An error is raised if this fractional ideal is not integral or
|
|
2098
|
+
the element `f` is not integral.
|
|
2099
|
+
|
|
2100
|
+
INPUT:
|
|
2101
|
+
|
|
2102
|
+
- ``f`` -- an integral element of the number field
|
|
2103
|
+
|
|
2104
|
+
OUTPUT:
|
|
2105
|
+
|
|
2106
|
+
An integral element `g`, such that `f - g` belongs to the ideal ``self``
|
|
2107
|
+
and such that `g` is a canonical reduced representative of the coset
|
|
2108
|
+
`f + I` (where `I` = ``self``) as described in the method :meth:`residues`,
|
|
2109
|
+
namely an integral element with coordinates `(r_0, \dots,r_{n-1})`, where:
|
|
2110
|
+
|
|
2111
|
+
- `r_i` is reduced modulo `d_i`
|
|
2112
|
+
- `d_i = b_i[i]`, with `\{b_0, b_1, \dots, b_n\}` HNF basis
|
|
2113
|
+
of the ideal ``self``.
|
|
2114
|
+
|
|
2115
|
+
.. NOTE::
|
|
2116
|
+
|
|
2117
|
+
The reduced element `g` is not necessarily small. To get a
|
|
2118
|
+
small `g` use the method :meth:`small_residue`.
|
|
2119
|
+
|
|
2120
|
+
EXAMPLES::
|
|
2121
|
+
|
|
2122
|
+
sage: x = polygen(ZZ)
|
|
2123
|
+
sage: k.<a> = NumberField(x^3 + 11)
|
|
2124
|
+
sage: I = k.ideal(5, a^2 - a + 1)
|
|
2125
|
+
sage: c = 4*a + 9
|
|
2126
|
+
sage: I.reduce(c)
|
|
2127
|
+
a^2 - 2*a
|
|
2128
|
+
sage: c - I.reduce(c) in I
|
|
2129
|
+
True
|
|
2130
|
+
|
|
2131
|
+
The reduced element is in the list of canonical representatives
|
|
2132
|
+
returned by the ``residues`` method:
|
|
2133
|
+
|
|
2134
|
+
::
|
|
2135
|
+
|
|
2136
|
+
sage: I.reduce(c) in list(I.residues())
|
|
2137
|
+
True
|
|
2138
|
+
|
|
2139
|
+
The reduced element does not necessarily have smaller norm (use
|
|
2140
|
+
:meth:`small_residue` for that)
|
|
2141
|
+
|
|
2142
|
+
::
|
|
2143
|
+
|
|
2144
|
+
sage: c.norm()
|
|
2145
|
+
25
|
|
2146
|
+
sage: (I.reduce(c)).norm()
|
|
2147
|
+
209
|
|
2148
|
+
sage: (I.small_residue(c)).norm()
|
|
2149
|
+
10
|
|
2150
|
+
|
|
2151
|
+
Sometimes the canonical reduced representative of `1` won't be `1`
|
|
2152
|
+
(it depends on the choice of basis for the ring of integers):
|
|
2153
|
+
|
|
2154
|
+
::
|
|
2155
|
+
|
|
2156
|
+
sage: k.<a> = NumberField(x^2 + 23)
|
|
2157
|
+
sage: I = k.ideal(3)
|
|
2158
|
+
sage: I.reduce(3*a + 1)
|
|
2159
|
+
-3/2*a - 1/2
|
|
2160
|
+
sage: k.ring_of_integers().basis()
|
|
2161
|
+
[1/2*a + 1/2, a]
|
|
2162
|
+
|
|
2163
|
+
AUTHOR: Maite Aranes.
|
|
2164
|
+
"""
|
|
2165
|
+
|
|
2166
|
+
if not self.is_integral():
|
|
2167
|
+
raise ValueError("reduce only defined for integral ideals")
|
|
2168
|
+
|
|
2169
|
+
R = self.number_field().maximal_order()
|
|
2170
|
+
|
|
2171
|
+
if f not in R:
|
|
2172
|
+
raise TypeError("reduce only defined for integral elements")
|
|
2173
|
+
|
|
2174
|
+
Rbasis = R.basis()
|
|
2175
|
+
n = len(Rbasis)
|
|
2176
|
+
from sage.matrix.matrix_space import MatrixSpace
|
|
2177
|
+
M = MatrixSpace(ZZ,n)([R.coordinates(y) for y in self.basis()])
|
|
2178
|
+
|
|
2179
|
+
D = M.hermite_form()
|
|
2180
|
+
d = [D[i, i] for i in range(n)]
|
|
2181
|
+
|
|
2182
|
+
v = R.coordinates(f)
|
|
2183
|
+
|
|
2184
|
+
for i in range(n):
|
|
2185
|
+
q, r = ZZ(v[i]).quo_rem(d[i])
|
|
2186
|
+
# v is a vector of rationals, we want division of integers
|
|
2187
|
+
if 2*r > d[i]:
|
|
2188
|
+
q = q + 1
|
|
2189
|
+
v = v - q*D[i]
|
|
2190
|
+
|
|
2191
|
+
return sum([v[i] * Rbasis[i] for i in range(n)])
|
|
2192
|
+
|
|
2193
|
+
def residues(self):
|
|
2194
|
+
r"""
|
|
2195
|
+
Return a iterator through a complete list of residues modulo this integral ideal.
|
|
2196
|
+
|
|
2197
|
+
An error is raised if this fractional ideal is not integral.
|
|
2198
|
+
|
|
2199
|
+
OUTPUT:
|
|
2200
|
+
|
|
2201
|
+
An iterator through a complete list of residues modulo the integral
|
|
2202
|
+
ideal ``self``. This list is the set of canonical reduced representatives
|
|
2203
|
+
given by all integral elements with coordinates `(r_0, \dots,r_{n-1})`,
|
|
2204
|
+
where:
|
|
2205
|
+
|
|
2206
|
+
- `r_i` is reduced modulo `d_i`
|
|
2207
|
+
|
|
2208
|
+
- `d_i = b_i[i]`, with `\{b_0, b_1, \dots, b_n\}` HNF basis
|
|
2209
|
+
of the ideal.
|
|
2210
|
+
|
|
2211
|
+
AUTHOR: John Cremona (modified by Maite Aranes)
|
|
2212
|
+
|
|
2213
|
+
EXAMPLES::
|
|
2214
|
+
|
|
2215
|
+
sage: x = polygen(ZZ)
|
|
2216
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
2217
|
+
sage: res = K.ideal(2).residues(); res
|
|
2218
|
+
xmrange_iter([[0, 1], [0, 1]], <function ...<lambda> at 0x...>)
|
|
2219
|
+
sage: list(res)
|
|
2220
|
+
[0, i, 1, i + 1]
|
|
2221
|
+
sage: list(K.ideal(2 + i).residues())
|
|
2222
|
+
[-2*i, -i, 0, i, 2*i]
|
|
2223
|
+
sage: list(K.ideal(i).residues())
|
|
2224
|
+
[0]
|
|
2225
|
+
sage: I = K.ideal(3 + 6*i)
|
|
2226
|
+
sage: reps = I.residues()
|
|
2227
|
+
sage: len(list(reps)) == I.norm()
|
|
2228
|
+
True
|
|
2229
|
+
sage: all(r == s or not (r-s) in I # long time (6s on sage.math, 2011)
|
|
2230
|
+
....: for r in reps for s in reps)
|
|
2231
|
+
True
|
|
2232
|
+
|
|
2233
|
+
sage: K.<a> = NumberField(x^3 - 10)
|
|
2234
|
+
sage: I = K.ideal(a - 1)
|
|
2235
|
+
sage: len(list(I.residues())) == I.norm()
|
|
2236
|
+
True
|
|
2237
|
+
|
|
2238
|
+
sage: K.<z> = CyclotomicField(11)
|
|
2239
|
+
sage: len(list(K.primes_above(3)[0].residues())) == 3**5 # long time (5s on sage.math, 2011)
|
|
2240
|
+
True
|
|
2241
|
+
"""
|
|
2242
|
+
if not self.is_integral():
|
|
2243
|
+
raise ValueError("residues only defined for integral ideals")
|
|
2244
|
+
|
|
2245
|
+
R = self.number_field().maximal_order()
|
|
2246
|
+
Rbasis = R.basis()
|
|
2247
|
+
n = len(Rbasis)
|
|
2248
|
+
from sage.matrix.matrix_space import MatrixSpace
|
|
2249
|
+
M = MatrixSpace(ZZ, n)([R.coordinates(_) for _ in self.basis()])
|
|
2250
|
+
|
|
2251
|
+
D = M.hermite_form()
|
|
2252
|
+
d = [D[i, i] for i in range(n)]
|
|
2253
|
+
coord_ranges = [list(range((-di+2)//2,(di+2)//2)) for di in d]
|
|
2254
|
+
combo = lambda c: sum(c[i] * Rbasis[i] for i in range(n))
|
|
2255
|
+
return xmrange_iter(coord_ranges, combo)
|
|
2256
|
+
|
|
2257
|
+
def invertible_residues(self, reduce=True):
|
|
2258
|
+
r"""
|
|
2259
|
+
Return an iterator through a list of invertible residues
|
|
2260
|
+
modulo this integral ideal.
|
|
2261
|
+
|
|
2262
|
+
An error is raised if this fractional ideal is not integral.
|
|
2263
|
+
|
|
2264
|
+
INPUT:
|
|
2265
|
+
|
|
2266
|
+
- ``reduce`` -- boolean; if ``True`` (default), use ``small_residue`` to get
|
|
2267
|
+
small representatives of the residues
|
|
2268
|
+
|
|
2269
|
+
OUTPUT:
|
|
2270
|
+
|
|
2271
|
+
An iterator through a list of invertible residues modulo this ideal
|
|
2272
|
+
`I`, i.e. a list of elements in the ring of integers `R` representing
|
|
2273
|
+
the elements of `(R/I)^*`.
|
|
2274
|
+
|
|
2275
|
+
ALGORITHM: Use :pari:`idealstar` to find the group structure and
|
|
2276
|
+
generators of the multiplicative group modulo the ideal.
|
|
2277
|
+
|
|
2278
|
+
EXAMPLES::
|
|
2279
|
+
|
|
2280
|
+
sage: x = polygen(ZZ)
|
|
2281
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
2282
|
+
sage: ires = K.ideal(2).invertible_residues(); ires
|
|
2283
|
+
xmrange_iter([[0, 1]], <function ...<lambda> at 0x...>)
|
|
2284
|
+
sage: list(ires)
|
|
2285
|
+
[1, -i]
|
|
2286
|
+
sage: list(K.ideal(2 + i).invertible_residues())
|
|
2287
|
+
[1, 2, 4, 3]
|
|
2288
|
+
sage: list(K.ideal(i).residues())
|
|
2289
|
+
[0]
|
|
2290
|
+
sage: list(K.ideal(i).invertible_residues())
|
|
2291
|
+
[1]
|
|
2292
|
+
sage: I = K.ideal(3 + 6*i)
|
|
2293
|
+
sage: units = I.invertible_residues()
|
|
2294
|
+
sage: len(list(units)) == I.euler_phi()
|
|
2295
|
+
True
|
|
2296
|
+
|
|
2297
|
+
sage: K.<a> = NumberField(x^3 - 10)
|
|
2298
|
+
sage: I = K.ideal(a - 1)
|
|
2299
|
+
sage: len(list(I.invertible_residues())) == I.euler_phi()
|
|
2300
|
+
True
|
|
2301
|
+
|
|
2302
|
+
sage: K.<z> = CyclotomicField(10)
|
|
2303
|
+
sage: len(list(K.primes_above(3)[0].invertible_residues()))
|
|
2304
|
+
80
|
|
2305
|
+
|
|
2306
|
+
TESTS:
|
|
2307
|
+
|
|
2308
|
+
Check that the integrality is not lost, cf. :issue:`30801`::
|
|
2309
|
+
|
|
2310
|
+
sage: K.<a> = NumberField(x^2 + x + 1)
|
|
2311
|
+
sage: all(x.is_integral() for x in K.ideal(8).invertible_residues())
|
|
2312
|
+
True
|
|
2313
|
+
|
|
2314
|
+
AUTHOR: John Cremona
|
|
2315
|
+
"""
|
|
2316
|
+
return self.invertible_residues_mod(subgp_gens=None, reduce=reduce)
|
|
2317
|
+
|
|
2318
|
+
def invertible_residues_mod(self, subgp_gens=[], reduce=True):
|
|
2319
|
+
r"""
|
|
2320
|
+
Return a iterator through a list of representatives for the invertible
|
|
2321
|
+
residues modulo this integral ideal, modulo the subgroup generated by
|
|
2322
|
+
the elements in the list ``subgp_gens``.
|
|
2323
|
+
|
|
2324
|
+
INPUT:
|
|
2325
|
+
|
|
2326
|
+
- ``subgp_gens`` -- either ``None`` or a list of elements of the number
|
|
2327
|
+
field of ``self``. These need not be integral, but should be coprime to
|
|
2328
|
+
the ideal ``self``. If the list is empty or ``None``, the function returns
|
|
2329
|
+
an iterator through a list of representatives for the invertible
|
|
2330
|
+
residues modulo the integral ideal ``self``.
|
|
2331
|
+
|
|
2332
|
+
- ``reduce`` -- boolean; if ``True`` (default), use ``small_residues`` to
|
|
2333
|
+
get small representatives of the residues
|
|
2334
|
+
|
|
2335
|
+
.. NOTE::
|
|
2336
|
+
|
|
2337
|
+
See also :meth:`invertible_residues` for a simpler version without the subgroup.
|
|
2338
|
+
|
|
2339
|
+
OUTPUT:
|
|
2340
|
+
|
|
2341
|
+
An iterator through a list of representatives for the invertible
|
|
2342
|
+
residues modulo ``self`` and modulo the group generated by
|
|
2343
|
+
``subgp_gens``, i.e. a list of elements in the ring of integers `R`
|
|
2344
|
+
representing the elements of `(R/I)^*/U`, where `I` is this ideal and
|
|
2345
|
+
`U` is the subgroup of `(R/I)^*` generated by ``subgp_gens``.
|
|
2346
|
+
|
|
2347
|
+
EXAMPLES:
|
|
2348
|
+
|
|
2349
|
+
::
|
|
2350
|
+
|
|
2351
|
+
sage: x = polygen(ZZ)
|
|
2352
|
+
sage: k.<a> = NumberField(x^2 + 23)
|
|
2353
|
+
sage: I = k.ideal(a)
|
|
2354
|
+
sage: list(I.invertible_residues_mod([-1]))
|
|
2355
|
+
[1, 5, 2, 10, 4, 20, 8, 17, 16, 11, 9]
|
|
2356
|
+
sage: list(I.invertible_residues_mod([1/2]))
|
|
2357
|
+
[1, 5]
|
|
2358
|
+
sage: list(I.invertible_residues_mod([23]))
|
|
2359
|
+
Traceback (most recent call last):
|
|
2360
|
+
...
|
|
2361
|
+
TypeError: the element must be invertible mod the ideal
|
|
2362
|
+
|
|
2363
|
+
::
|
|
2364
|
+
|
|
2365
|
+
sage: K.<a> = NumberField(x^3 - 10)
|
|
2366
|
+
sage: I = K.ideal(a - 1)
|
|
2367
|
+
sage: len(list(I.invertible_residues_mod([]))) == I.euler_phi()
|
|
2368
|
+
True
|
|
2369
|
+
|
|
2370
|
+
sage: I = K.ideal(1)
|
|
2371
|
+
sage: list(I.invertible_residues_mod([]))
|
|
2372
|
+
[1]
|
|
2373
|
+
|
|
2374
|
+
::
|
|
2375
|
+
|
|
2376
|
+
sage: K.<z> = CyclotomicField(10)
|
|
2377
|
+
sage: len(list(K.primes_above(3)[0].invertible_residues_mod([])))
|
|
2378
|
+
80
|
|
2379
|
+
|
|
2380
|
+
AUTHOR: Maite Aranes.
|
|
2381
|
+
"""
|
|
2382
|
+
if self.norm() == 1:
|
|
2383
|
+
return xmrange_iter([[1]], lambda l: l[0])
|
|
2384
|
+
|
|
2385
|
+
G = self.idealstar(2)
|
|
2386
|
+
|
|
2387
|
+
invs = G.invariants()
|
|
2388
|
+
g = G.gens_values()
|
|
2389
|
+
n = G.ngens()
|
|
2390
|
+
|
|
2391
|
+
from sage.matrix.constructor import Matrix
|
|
2392
|
+
from sage.matrix.special import diagonal_matrix
|
|
2393
|
+
|
|
2394
|
+
M = diagonal_matrix(ZZ, invs)
|
|
2395
|
+
if subgp_gens:
|
|
2396
|
+
Units = Matrix(ZZ, [self.ideallog(_) for _ in subgp_gens])
|
|
2397
|
+
M = M.stack(Units)
|
|
2398
|
+
|
|
2399
|
+
A, U, V = M.smith_form()
|
|
2400
|
+
|
|
2401
|
+
V = V.inverse()
|
|
2402
|
+
new_basis = [prod([g[j]**(V[i, j] % invs[j]) for j in range(n)]) for i in range(n)]
|
|
2403
|
+
|
|
2404
|
+
if reduce:
|
|
2405
|
+
combo = lambda c: self.small_residue(prod(new_basis[i] ** c[i]
|
|
2406
|
+
for i in range(n)))
|
|
2407
|
+
else:
|
|
2408
|
+
combo = lambda c: prod(new_basis[i] ** c[i] for i in range(n))
|
|
2409
|
+
|
|
2410
|
+
coord_ranges = [list(range(A[i, i])) for i in range(n)]
|
|
2411
|
+
|
|
2412
|
+
return xmrange_iter(coord_ranges, combo)
|
|
2413
|
+
|
|
2414
|
+
def denominator(self):
|
|
2415
|
+
r"""
|
|
2416
|
+
Return the denominator ideal of this fractional ideal. Each
|
|
2417
|
+
fractional ideal has a unique expression as `N/D` where `N`,
|
|
2418
|
+
`D` are coprime integral ideals; the denominator is `D`.
|
|
2419
|
+
|
|
2420
|
+
EXAMPLES::
|
|
2421
|
+
|
|
2422
|
+
sage: x = polygen(ZZ)
|
|
2423
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
2424
|
+
sage: I = K.ideal((3+4*i)/5); I
|
|
2425
|
+
Fractional ideal (4/5*i + 3/5)
|
|
2426
|
+
sage: I.denominator()
|
|
2427
|
+
Fractional ideal (-2*i - 1)
|
|
2428
|
+
sage: I.numerator()
|
|
2429
|
+
Fractional ideal (2*i - 1)
|
|
2430
|
+
sage: I.numerator().is_integral() and I.denominator().is_integral()
|
|
2431
|
+
True
|
|
2432
|
+
sage: I.numerator() + I.denominator() == K.unit_ideal()
|
|
2433
|
+
True
|
|
2434
|
+
sage: I.numerator()/I.denominator() == I
|
|
2435
|
+
True
|
|
2436
|
+
"""
|
|
2437
|
+
try:
|
|
2438
|
+
return self._denom_ideal
|
|
2439
|
+
except AttributeError:
|
|
2440
|
+
pass
|
|
2441
|
+
self._denom_ideal = (self + self.number_field().unit_ideal())**(-1)
|
|
2442
|
+
return self._denom_ideal
|
|
2443
|
+
|
|
2444
|
+
def numerator(self):
|
|
2445
|
+
r"""
|
|
2446
|
+
Return the numerator ideal of this fractional ideal.
|
|
2447
|
+
|
|
2448
|
+
Each fractional ideal has a unique expression as `N/D` where `N`,
|
|
2449
|
+
`D` are coprime integral ideals. The numerator is `N`.
|
|
2450
|
+
|
|
2451
|
+
EXAMPLES::
|
|
2452
|
+
|
|
2453
|
+
sage: x = polygen(ZZ)
|
|
2454
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
2455
|
+
sage: I = K.ideal((3+4*i)/5); I
|
|
2456
|
+
Fractional ideal (4/5*i + 3/5)
|
|
2457
|
+
sage: I.denominator()
|
|
2458
|
+
Fractional ideal (-2*i - 1)
|
|
2459
|
+
sage: I.numerator()
|
|
2460
|
+
Fractional ideal (2*i - 1)
|
|
2461
|
+
sage: I.numerator().is_integral() and I.denominator().is_integral()
|
|
2462
|
+
True
|
|
2463
|
+
sage: I.numerator() + I.denominator() == K.unit_ideal()
|
|
2464
|
+
True
|
|
2465
|
+
sage: I.numerator()/I.denominator() == I
|
|
2466
|
+
True
|
|
2467
|
+
"""
|
|
2468
|
+
try:
|
|
2469
|
+
return self._num_ideal
|
|
2470
|
+
except AttributeError:
|
|
2471
|
+
pass
|
|
2472
|
+
self._num_ideal = self * self.denominator()
|
|
2473
|
+
return self._num_ideal
|
|
2474
|
+
|
|
2475
|
+
def is_coprime(self, other):
|
|
2476
|
+
"""
|
|
2477
|
+
Return ``True`` if this ideal is coprime to ``other``, else ``False``.
|
|
2478
|
+
|
|
2479
|
+
INPUT:
|
|
2480
|
+
|
|
2481
|
+
- ``other`` -- another ideal of the same field, or generators
|
|
2482
|
+
of an ideal
|
|
2483
|
+
|
|
2484
|
+
OUTPUT: ``True`` if ``self`` and ``other`` are coprime, else ``False``
|
|
2485
|
+
|
|
2486
|
+
.. NOTE::
|
|
2487
|
+
|
|
2488
|
+
This function works for fractional ideals as well as
|
|
2489
|
+
integral ideals.
|
|
2490
|
+
|
|
2491
|
+
AUTHOR: John Cremona
|
|
2492
|
+
|
|
2493
|
+
EXAMPLES::
|
|
2494
|
+
|
|
2495
|
+
sage: x = polygen(ZZ)
|
|
2496
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
2497
|
+
sage: I = K.ideal(2 + i)
|
|
2498
|
+
sage: J = K.ideal(2 - i)
|
|
2499
|
+
sage: I.is_coprime(J)
|
|
2500
|
+
True
|
|
2501
|
+
sage: (I^-1).is_coprime(J^3)
|
|
2502
|
+
True
|
|
2503
|
+
sage: I.is_coprime(5)
|
|
2504
|
+
False
|
|
2505
|
+
sage: I.is_coprime(6 + i)
|
|
2506
|
+
True
|
|
2507
|
+
|
|
2508
|
+
See :issue:`4536`::
|
|
2509
|
+
|
|
2510
|
+
sage: E.<a> = NumberField(x^5 + 7*x^4 + 18*x^2 + x - 3)
|
|
2511
|
+
sage: i,j,k = [u[0] for u in factor(3*E)]
|
|
2512
|
+
sage: (i/j).is_coprime(j/k)
|
|
2513
|
+
False
|
|
2514
|
+
sage: (j/k).is_coprime(j/k)
|
|
2515
|
+
False
|
|
2516
|
+
|
|
2517
|
+
sage: F.<a, b> = NumberField([x^2 - 2, x^2 - 3])
|
|
2518
|
+
sage: F.ideal(3 - a*b).is_coprime(F.ideal(3))
|
|
2519
|
+
False
|
|
2520
|
+
"""
|
|
2521
|
+
# Catch invalid inputs by making sure that we can make an ideal out of other.
|
|
2522
|
+
K = self.number_field()
|
|
2523
|
+
one = K.unit_ideal()
|
|
2524
|
+
other = K.ideal(other)
|
|
2525
|
+
if self.is_integral() and other.is_integral():
|
|
2526
|
+
if gcd(ZZ(self.absolute_norm()), ZZ(other.absolute_norm())) == 1:
|
|
2527
|
+
return True
|
|
2528
|
+
else:
|
|
2529
|
+
return self+other == one
|
|
2530
|
+
# This special case is necessary since the zero ideal is not a
|
|
2531
|
+
# fractional ideal!
|
|
2532
|
+
if other.absolute_norm() == 0:
|
|
2533
|
+
return self == one
|
|
2534
|
+
D1 = self.denominator()
|
|
2535
|
+
N1 = self.numerator()
|
|
2536
|
+
D2 = other.denominator()
|
|
2537
|
+
N2 = other.numerator()
|
|
2538
|
+
return N1+N2 == one and N1+D2 == one and D1+N2 == one and D1+D2 == one
|
|
2539
|
+
|
|
2540
|
+
def idealcoprime(self, J):
|
|
2541
|
+
"""
|
|
2542
|
+
Return `l` such that ``l*self`` is coprime to `J`.
|
|
2543
|
+
|
|
2544
|
+
INPUT:
|
|
2545
|
+
|
|
2546
|
+
- ``J`` -- another integral ideal of the same field as ``self``, which
|
|
2547
|
+
must also be integral
|
|
2548
|
+
|
|
2549
|
+
OUTPUT: an element `l` such that ``l*self`` is coprime to the ideal `J`
|
|
2550
|
+
|
|
2551
|
+
.. TODO::
|
|
2552
|
+
|
|
2553
|
+
Extend the implementation to non-integral ideals.
|
|
2554
|
+
|
|
2555
|
+
EXAMPLES::
|
|
2556
|
+
|
|
2557
|
+
sage: x = polygen(ZZ)
|
|
2558
|
+
sage: k.<a> = NumberField(x^2 + 23)
|
|
2559
|
+
sage: A = k.ideal(a + 1)
|
|
2560
|
+
sage: B = k.ideal(3)
|
|
2561
|
+
sage: A.is_coprime(B)
|
|
2562
|
+
False
|
|
2563
|
+
sage: lam = A.idealcoprime(B)
|
|
2564
|
+
sage: lam # representation depends, not tested
|
|
2565
|
+
-1/6*a + 1/6
|
|
2566
|
+
sage: (lam*A).is_coprime(B)
|
|
2567
|
+
True
|
|
2568
|
+
|
|
2569
|
+
ALGORITHM: Uses Pari function :pari:`idealcoprime`.
|
|
2570
|
+
|
|
2571
|
+
TESTS:
|
|
2572
|
+
|
|
2573
|
+
Check the above doctests, where the representation
|
|
2574
|
+
depends on the PARI version::
|
|
2575
|
+
|
|
2576
|
+
sage: k.<a> = NumberField(x^2 + 23)
|
|
2577
|
+
sage: A = k.ideal(a + 1)
|
|
2578
|
+
sage: B = k.ideal(3)
|
|
2579
|
+
sage: lam = A.idealcoprime(B)
|
|
2580
|
+
sage: lam in (-1/6*a + 1/6, 1/6*a - 1/6)
|
|
2581
|
+
True
|
|
2582
|
+
"""
|
|
2583
|
+
if not (self.is_integral() and J.is_integral()):
|
|
2584
|
+
raise ValueError("Both ideals must be integral.")
|
|
2585
|
+
|
|
2586
|
+
k = self.number_field()
|
|
2587
|
+
# Catch invalid inputs by making sure that J is an ideal of the same field as self:
|
|
2588
|
+
assert k == J.number_field()
|
|
2589
|
+
l = k.pari_nf().idealcoprime(self.pari_hnf(), J.pari_hnf())
|
|
2590
|
+
return k(l)
|
|
2591
|
+
|
|
2592
|
+
def small_residue(self, f):
|
|
2593
|
+
r"""
|
|
2594
|
+
Given an element `f` of the ambient number field, return an
|
|
2595
|
+
element `g` such that `f - g` belongs to the ideal ``self`` (which
|
|
2596
|
+
must be integral), and `g` is small.
|
|
2597
|
+
|
|
2598
|
+
.. NOTE::
|
|
2599
|
+
|
|
2600
|
+
The reduced representative returned is not uniquely determined.
|
|
2601
|
+
|
|
2602
|
+
ALGORITHM: Uses PARI function :pari:`nfeltreduce`.
|
|
2603
|
+
|
|
2604
|
+
EXAMPLES:
|
|
2605
|
+
|
|
2606
|
+
::
|
|
2607
|
+
|
|
2608
|
+
sage: x = polygen(ZZ)
|
|
2609
|
+
sage: k.<a> = NumberField(x^2 + 5)
|
|
2610
|
+
sage: I = k.ideal(a)
|
|
2611
|
+
sage: I.small_residue(14)
|
|
2612
|
+
4
|
|
2613
|
+
|
|
2614
|
+
::
|
|
2615
|
+
|
|
2616
|
+
sage: K.<a> = NumberField(x^5 + 7*x^4 + 18*x^2 + x - 3)
|
|
2617
|
+
sage: I = K.ideal(5)
|
|
2618
|
+
sage: I.small_residue(a^2 -13)
|
|
2619
|
+
a^2 + 5*a - 3
|
|
2620
|
+
"""
|
|
2621
|
+
if not self.is_integral():
|
|
2622
|
+
raise ValueError("The ideal must be integral")
|
|
2623
|
+
k = self.number_field()
|
|
2624
|
+
return k(k.pari_nf().nfeltreduce(f, self.pari_hnf()))
|
|
2625
|
+
|
|
2626
|
+
def _pari_bid_(self, flag=1):
|
|
2627
|
+
"""
|
|
2628
|
+
Return the PARI structure ``bid`` associated to the ideal ``self``.
|
|
2629
|
+
|
|
2630
|
+
INPUT:
|
|
2631
|
+
|
|
2632
|
+
- ``flag`` -- when ``flag=2`` it computes the generators of the group
|
|
2633
|
+
`(O_K/I)^*`, which takes more time. By default
|
|
2634
|
+
``flag=1`` (no generators are computed).
|
|
2635
|
+
|
|
2636
|
+
OUTPUT: the PARI special structure ``bid``
|
|
2637
|
+
|
|
2638
|
+
EXAMPLES::
|
|
2639
|
+
|
|
2640
|
+
sage: x = polygen(ZZ)
|
|
2641
|
+
sage: k.<a> = NumberField(x^4 + 13)
|
|
2642
|
+
sage: I = k.ideal(2, a^2 + 1)
|
|
2643
|
+
sage: hasattr(I, '_bid')
|
|
2644
|
+
False
|
|
2645
|
+
sage: bid = I._pari_bid_()
|
|
2646
|
+
sage: hasattr(I, '_bid')
|
|
2647
|
+
True
|
|
2648
|
+
sage: bid.getattr('clgp')
|
|
2649
|
+
[2, [2]]
|
|
2650
|
+
"""
|
|
2651
|
+
from cypari2.handle_error import PariError
|
|
2652
|
+
try:
|
|
2653
|
+
bid = self._bid
|
|
2654
|
+
if flag == 2:
|
|
2655
|
+
# Try to access generators, we get PariError if this fails.
|
|
2656
|
+
bid.bid_get_gen()
|
|
2657
|
+
except (AttributeError, PariError):
|
|
2658
|
+
k = self.number_field()
|
|
2659
|
+
bid = k.pari_nf().idealstar(self.pari_hnf(), flag)
|
|
2660
|
+
self._bid = bid
|
|
2661
|
+
return bid
|
|
2662
|
+
|
|
2663
|
+
def idealstar(self, flag=1):
|
|
2664
|
+
r"""
|
|
2665
|
+
Return the finite abelian group `(O_K/I)^*`, where `I` is the ideal ``self``
|
|
2666
|
+
of the number field `K`, and `O_K` is the ring of integers of `K`.
|
|
2667
|
+
|
|
2668
|
+
INPUT:
|
|
2669
|
+
|
|
2670
|
+
- ``flag`` -- integer (default: 1); when ``flag==2``, it also
|
|
2671
|
+
computes the generators of the group `(O_K/I)^*`, which
|
|
2672
|
+
takes more time. By default ``flag`` is 1 (no generators are
|
|
2673
|
+
computed). In both cases the special PARI structure ``bid``
|
|
2674
|
+
is computed as well. If ``flag`` is 0 (deprecated) it computes
|
|
2675
|
+
only the group structure of `(O_K/I)^*` (with generators)
|
|
2676
|
+
and not the special ``bid`` structure.
|
|
2677
|
+
|
|
2678
|
+
OUTPUT:
|
|
2679
|
+
|
|
2680
|
+
The finite abelian group `(O_K/I)^*`.
|
|
2681
|
+
|
|
2682
|
+
.. NOTE::
|
|
2683
|
+
|
|
2684
|
+
Uses the PARI function :pari:`idealstar`. The PARI function outputs
|
|
2685
|
+
a special ``bid`` structure which is stored in the internal
|
|
2686
|
+
field ``_bid`` of the ideal (when ``flag`` = 1,2). The special structure
|
|
2687
|
+
``bid`` is used in the PARI function :pari:`ideallog`
|
|
2688
|
+
to compute discrete logarithms.
|
|
2689
|
+
|
|
2690
|
+
EXAMPLES::
|
|
2691
|
+
|
|
2692
|
+
sage: x = polygen(ZZ)
|
|
2693
|
+
sage: k.<a> = NumberField(x^3 - 11)
|
|
2694
|
+
sage: A = k.ideal(5)
|
|
2695
|
+
sage: G = A.idealstar(); G
|
|
2696
|
+
Multiplicative Abelian group isomorphic to C24 x C4
|
|
2697
|
+
sage: G.gens()
|
|
2698
|
+
(f0, f1)
|
|
2699
|
+
|
|
2700
|
+
sage: G = A.idealstar(2)
|
|
2701
|
+
sage: G.gens()
|
|
2702
|
+
(f0, f1)
|
|
2703
|
+
sage: G.gens_values() # random output
|
|
2704
|
+
(2*a^2 - 1, 2*a^2 + 2*a - 2)
|
|
2705
|
+
sage: all(G.gen(i).value() in k for i in range(G.ngens()))
|
|
2706
|
+
True
|
|
2707
|
+
|
|
2708
|
+
TESTS::
|
|
2709
|
+
|
|
2710
|
+
sage: k.<a> = NumberField(x^2 + 1)
|
|
2711
|
+
sage: k.ideal(a+1).idealstar(2)
|
|
2712
|
+
Trivial Abelian group
|
|
2713
|
+
|
|
2714
|
+
ALGORITHM: Uses Pari function :pari:`idealstar`
|
|
2715
|
+
"""
|
|
2716
|
+
k = self.number_field()
|
|
2717
|
+
if flag == 0 and not hasattr(self, '_bid'):
|
|
2718
|
+
G = k.pari_nf().idealstar(self.pari_hnf(), 0)
|
|
2719
|
+
else:
|
|
2720
|
+
G = self._pari_bid_(flag)
|
|
2721
|
+
inv = [ZZ(c) for c in G.bid_get_cyc()]
|
|
2722
|
+
|
|
2723
|
+
if flag == 2 or flag == 0:
|
|
2724
|
+
from sage.groups.abelian_gps.values import AbelianGroupWithValues
|
|
2725
|
+
g = G.bid_get_gen()
|
|
2726
|
+
AG = AbelianGroupWithValues(tuple(map(k, g)), inv, values_group=k)
|
|
2727
|
+
else:
|
|
2728
|
+
from sage.groups.abelian_gps.abelian_group import AbelianGroup
|
|
2729
|
+
AG = AbelianGroup(inv)
|
|
2730
|
+
return AG
|
|
2731
|
+
|
|
2732
|
+
def ideallog(self, x, gens=None, check=True):
|
|
2733
|
+
r"""
|
|
2734
|
+
Return the discrete logarithm of `x` with respect to the generators
|
|
2735
|
+
given in the ``bid`` structure of the ideal ``self``, or with respect to
|
|
2736
|
+
the generators ``gens`` if these are given.
|
|
2737
|
+
|
|
2738
|
+
INPUT:
|
|
2739
|
+
|
|
2740
|
+
- ``x`` -- a nonzero element of the number field of ``self``,
|
|
2741
|
+
which must have valuation equal to 0 at all prime ideals in
|
|
2742
|
+
the support of the ideal ``self``
|
|
2743
|
+
- ``gens`` -- list of elements of the number field which generate `(R
|
|
2744
|
+
/ I)^*`, where `R` is the ring of integers of the field and `I` is
|
|
2745
|
+
this ideal, or ``None``. If ``None``, use the generators calculated
|
|
2746
|
+
by :meth:`~idealstar`.
|
|
2747
|
+
- ``check`` -- if ``True``, do a consistency check on the results.
|
|
2748
|
+
Ignored if ``gens`` is ``None``.
|
|
2749
|
+
|
|
2750
|
+
OUTPUT:
|
|
2751
|
+
|
|
2752
|
+
a list of nonnegative integers `(x_i)` such that `x =
|
|
2753
|
+
\prod_i g_i^{x_i}` in `(R/I)^*`, where `x_i` are the generators, and
|
|
2754
|
+
the list `(x_i)` is lexicographically minimal with respect to this
|
|
2755
|
+
requirement. If the `x_i` generate independent cyclic factors of
|
|
2756
|
+
order `d_i`, as is the case for the default generators calculated by
|
|
2757
|
+
:meth:`~idealstar`, this just means that `0 \le x_i < d_i`.
|
|
2758
|
+
|
|
2759
|
+
A :exc:`ValueError` will be raised if the elements specified in ``gens``
|
|
2760
|
+
do not in fact generate the unit group (even if the element `x` is in
|
|
2761
|
+
the subgroup they generate).
|
|
2762
|
+
|
|
2763
|
+
EXAMPLES::
|
|
2764
|
+
|
|
2765
|
+
sage: x = polygen(ZZ)
|
|
2766
|
+
sage: k.<a> = NumberField(x^3 - 11)
|
|
2767
|
+
sage: A = k.ideal(5)
|
|
2768
|
+
sage: G = A.idealstar(2)
|
|
2769
|
+
sage: l = A.ideallog(a^2 + 3)
|
|
2770
|
+
sage: r = G(l).value()
|
|
2771
|
+
sage: (a^2 + 3) - r in A
|
|
2772
|
+
True
|
|
2773
|
+
sage: A.small_residue(r) # random
|
|
2774
|
+
a^2 - 2
|
|
2775
|
+
|
|
2776
|
+
Examples with custom generators::
|
|
2777
|
+
|
|
2778
|
+
sage: K.<a> = NumberField(x^2 - 7)
|
|
2779
|
+
sage: I = K.ideal(17)
|
|
2780
|
+
sage: I.ideallog(a + 7, [1 + a, 2])
|
|
2781
|
+
[10, 3]
|
|
2782
|
+
sage: I.ideallog(a + 7, [2, 1 + a])
|
|
2783
|
+
[0, 118]
|
|
2784
|
+
|
|
2785
|
+
sage: L.<b> = NumberField(x^4 - x^3 - 7*x^2 + 3*x + 2)
|
|
2786
|
+
sage: J = L.ideal(-b^3 - b^2 - 2)
|
|
2787
|
+
sage: u = -14*b^3 + 21*b^2 + b - 1
|
|
2788
|
+
sage: v = 4*b^2 + 2*b - 1
|
|
2789
|
+
sage: J.ideallog(5 + 2*b, [u, v], check=True)
|
|
2790
|
+
[4, 13]
|
|
2791
|
+
|
|
2792
|
+
A non-example::
|
|
2793
|
+
|
|
2794
|
+
sage: I.ideallog(a + 7, [2])
|
|
2795
|
+
Traceback (most recent call last):
|
|
2796
|
+
...
|
|
2797
|
+
ValueError: Given elements do not generate unit group --
|
|
2798
|
+
they generate a subgroup of index 36
|
|
2799
|
+
|
|
2800
|
+
ALGORITHM: Uses PARI function :pari:`ideallog`, and (if ``gens`` is not
|
|
2801
|
+
``None``) a Hermite normal form calculation to express the result in terms
|
|
2802
|
+
of the generators ``gens``.
|
|
2803
|
+
"""
|
|
2804
|
+
# sanitise input
|
|
2805
|
+
|
|
2806
|
+
k = self.number_field()
|
|
2807
|
+
if not all(k(x).valuation(p) == 0 for p, e in self.factor()):
|
|
2808
|
+
raise TypeError("the element must be invertible mod the ideal")
|
|
2809
|
+
|
|
2810
|
+
# calculate ideal log w.r.t. standard gens
|
|
2811
|
+
|
|
2812
|
+
#Now it is important to call _pari_bid_() with flag=2 to make sure
|
|
2813
|
+
#we fix a basis, since the log would be different for a different
|
|
2814
|
+
#choice of basis.
|
|
2815
|
+
L = [ZZ(_) for _ in k.pari_nf().ideallog(x, self._pari_bid_(2))]
|
|
2816
|
+
|
|
2817
|
+
if gens is None:
|
|
2818
|
+
return L
|
|
2819
|
+
|
|
2820
|
+
# otherwise translate answer in terms of given gens
|
|
2821
|
+
G = self.idealstar(2)
|
|
2822
|
+
invs = G.invariants()
|
|
2823
|
+
|
|
2824
|
+
from sage.matrix.constructor import matrix
|
|
2825
|
+
from sage.matrix.special import identity_matrix
|
|
2826
|
+
from sage.matrix.special import zero_matrix
|
|
2827
|
+
from sage.matrix.special import diagonal_matrix
|
|
2828
|
+
from sage.matrix.special import block_matrix
|
|
2829
|
+
|
|
2830
|
+
# We use Hermite normal form twice: once to express the standard
|
|
2831
|
+
# generators in terms of the new ones (independently of x) and once to
|
|
2832
|
+
# reduce the resulting logarithm of x so it is lexicographically
|
|
2833
|
+
# minimal.
|
|
2834
|
+
|
|
2835
|
+
mat = matrix(ZZ, [self.ideallog(_) for _ in gens]).augment(identity_matrix(ZZ, len(gens)))
|
|
2836
|
+
mat = mat.stack( diagonal_matrix(ZZ, invs).augment(zero_matrix(ZZ, len(invs), len(gens))))
|
|
2837
|
+
hmat = mat.hermite_form()
|
|
2838
|
+
A = hmat[0:len(invs), 0:len(invs)]
|
|
2839
|
+
if A != identity_matrix(len(invs)):
|
|
2840
|
+
raise ValueError("Given elements do not generate unit group -- they generate a subgroup of index %s" % A.det())
|
|
2841
|
+
B = hmat[0:len(invs), len(invs):]
|
|
2842
|
+
C = hmat[len(invs):, len(invs):]
|
|
2843
|
+
M = (matrix(ZZ, L) * B)
|
|
2844
|
+
N = block_matrix(2, 2, [[identity_matrix(1), M], [zero_matrix(len(gens), 1), C]], subdivide=False)
|
|
2845
|
+
ans = N.hermite_form()[0, 1:].list()
|
|
2846
|
+
|
|
2847
|
+
if check:
|
|
2848
|
+
from sage.rings.finite_rings.integer_mod_ring import Zmod
|
|
2849
|
+
Z_norm = Zmod(self.norm().numerator()) # norm is an integer ?
|
|
2850
|
+
t = 1
|
|
2851
|
+
for gi, ai in zip(gens, ans):
|
|
2852
|
+
t = self.reduce(t * gi**ai)
|
|
2853
|
+
assert t == self.reduce(x * x.denominator() * (~Z_norm(x.denominator())).lift())
|
|
2854
|
+
|
|
2855
|
+
return ans
|
|
2856
|
+
|
|
2857
|
+
def element_1_mod(self, other):
|
|
2858
|
+
r"""
|
|
2859
|
+
Return an element `r` in this ideal such that `1-r` is in ``other``.
|
|
2860
|
+
|
|
2861
|
+
An error is raised if either ideal is not integral of if they
|
|
2862
|
+
are not coprime.
|
|
2863
|
+
|
|
2864
|
+
INPUT:
|
|
2865
|
+
|
|
2866
|
+
- ``other`` -- another ideal of the same field, or generators
|
|
2867
|
+
of an ideal
|
|
2868
|
+
|
|
2869
|
+
OUTPUT: an element `r` of the ideal ``self`` such that `1-r` is in the
|
|
2870
|
+
ideal ``other``
|
|
2871
|
+
|
|
2872
|
+
AUTHOR: Maite Aranes (modified to use PARI's :pari:`idealaddtoone` by Francis Clarke)
|
|
2873
|
+
|
|
2874
|
+
EXAMPLES::
|
|
2875
|
+
|
|
2876
|
+
sage: x = polygen(ZZ)
|
|
2877
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
2878
|
+
sage: A = K.ideal(a + 1); A; A.norm()
|
|
2879
|
+
Fractional ideal (a + 1)
|
|
2880
|
+
3
|
|
2881
|
+
sage: B = K.ideal(a^2 - 4*a + 2); B; B.norm()
|
|
2882
|
+
Fractional ideal (a^2 - 4*a + 2)
|
|
2883
|
+
68
|
|
2884
|
+
sage: r = A.element_1_mod(B); r
|
|
2885
|
+
-33
|
|
2886
|
+
sage: r in A
|
|
2887
|
+
True
|
|
2888
|
+
sage: 1 - r in B
|
|
2889
|
+
True
|
|
2890
|
+
|
|
2891
|
+
TESTS::
|
|
2892
|
+
|
|
2893
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
2894
|
+
sage: A = K.ideal(a+1)
|
|
2895
|
+
sage: B = K.ideal(a^2-4*a+1); B; B.norm()
|
|
2896
|
+
Fractional ideal (a^2 - 4*a + 1)
|
|
2897
|
+
99
|
|
2898
|
+
sage: A.element_1_mod(B)
|
|
2899
|
+
Traceback (most recent call last):
|
|
2900
|
+
...
|
|
2901
|
+
TypeError: Fractional ideal (a + 1), Fractional ideal (a^2 - 4*a + 1) are not coprime ideals
|
|
2902
|
+
|
|
2903
|
+
sage: B = K.ideal(1/a); B
|
|
2904
|
+
Fractional ideal (1/2*a^2)
|
|
2905
|
+
sage: A.element_1_mod(B)
|
|
2906
|
+
Traceback (most recent call last):
|
|
2907
|
+
...
|
|
2908
|
+
TypeError: Fractional ideal (1/2*a^2) is not an integral ideal
|
|
2909
|
+
"""
|
|
2910
|
+
if not self.is_integral():
|
|
2911
|
+
raise TypeError("%s is not an integral ideal" % self)
|
|
2912
|
+
|
|
2913
|
+
# Catch invalid inputs by making sure that we can make an ideal out of other.
|
|
2914
|
+
K = self.number_field()
|
|
2915
|
+
other = K.ideal(other)
|
|
2916
|
+
if not other.is_integral():
|
|
2917
|
+
raise TypeError("%s is not an integral ideal" % other)
|
|
2918
|
+
|
|
2919
|
+
if not self.is_coprime(other):
|
|
2920
|
+
raise TypeError("%s, %s are not coprime ideals" % (self, other))
|
|
2921
|
+
|
|
2922
|
+
bnf = K.pari_bnf()
|
|
2923
|
+
r = bnf.idealaddtoone(self.pari_hnf(), other.pari_hnf())[0]
|
|
2924
|
+
return K(r)
|
|
2925
|
+
|
|
2926
|
+
def euler_phi(self):
|
|
2927
|
+
r"""
|
|
2928
|
+
Return the Euler `\varphi`-function of this integral ideal.
|
|
2929
|
+
|
|
2930
|
+
This is the order of the multiplicative group of the quotient
|
|
2931
|
+
modulo the ideal.
|
|
2932
|
+
|
|
2933
|
+
An error is raised if the ideal is not integral.
|
|
2934
|
+
|
|
2935
|
+
EXAMPLES::
|
|
2936
|
+
|
|
2937
|
+
sage: x = polygen(ZZ)
|
|
2938
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
2939
|
+
sage: I = K.ideal(2 + i)
|
|
2940
|
+
sage: [r for r in I.residues() if I.is_coprime(r)]
|
|
2941
|
+
[-2*i, -i, i, 2*i]
|
|
2942
|
+
sage: I.euler_phi()
|
|
2943
|
+
4
|
|
2944
|
+
sage: J = I^3
|
|
2945
|
+
sage: J.euler_phi()
|
|
2946
|
+
100
|
|
2947
|
+
sage: len([r for r in J.residues() if J.is_coprime(r)])
|
|
2948
|
+
100
|
|
2949
|
+
sage: J = K.ideal(3 - 2*i)
|
|
2950
|
+
sage: I.is_coprime(J)
|
|
2951
|
+
True
|
|
2952
|
+
sage: I.euler_phi()*J.euler_phi() == (I*J).euler_phi()
|
|
2953
|
+
True
|
|
2954
|
+
sage: L.<b> = K.extension(x^2 - 7)
|
|
2955
|
+
sage: L.ideal(3).euler_phi()
|
|
2956
|
+
64
|
|
2957
|
+
"""
|
|
2958
|
+
if not self.is_integral():
|
|
2959
|
+
raise ValueError("euler_phi only defined for integral ideals")
|
|
2960
|
+
it = ((p.absolute_norm(), e) for p, e in self.factor())
|
|
2961
|
+
return prod((np - 1) * np**(e - 1) for np, e in it)
|
|
2962
|
+
|
|
2963
|
+
def prime_to_S_part(self, S):
|
|
2964
|
+
r"""
|
|
2965
|
+
Return the part of this fractional ideal which is coprime to
|
|
2966
|
+
the prime ideals in the list `S`.
|
|
2967
|
+
|
|
2968
|
+
.. NOTE::
|
|
2969
|
+
|
|
2970
|
+
This function assumes that `S` is a list of prime ideals,
|
|
2971
|
+
but does not check this. This function will fail if `S` is
|
|
2972
|
+
not a list of prime ideals.
|
|
2973
|
+
|
|
2974
|
+
INPUT:
|
|
2975
|
+
|
|
2976
|
+
- ``S`` -- list of prime ideals
|
|
2977
|
+
|
|
2978
|
+
OUTPUT:
|
|
2979
|
+
|
|
2980
|
+
A fractional ideal coprime to the primes in `S`, whose prime
|
|
2981
|
+
factorization is that of ``self`` with the primes in `S`
|
|
2982
|
+
removed.
|
|
2983
|
+
|
|
2984
|
+
EXAMPLES::
|
|
2985
|
+
|
|
2986
|
+
sage: x = polygen(ZZ)
|
|
2987
|
+
sage: K.<a> = NumberField(x^2 - 23)
|
|
2988
|
+
sage: I = K.ideal(24)
|
|
2989
|
+
sage: S = [K.ideal(-a + 5), K.ideal(5)]
|
|
2990
|
+
sage: I.prime_to_S_part(S)
|
|
2991
|
+
Fractional ideal (3)
|
|
2992
|
+
sage: J = K.ideal(15)
|
|
2993
|
+
sage: J.prime_to_S_part(S)
|
|
2994
|
+
Fractional ideal (3)
|
|
2995
|
+
|
|
2996
|
+
sage: K.<a> = NumberField(x^5 - 23)
|
|
2997
|
+
sage: I = K.ideal(24)
|
|
2998
|
+
sage: S = [K.ideal(15161*a^4 + 28383*a^3 + 53135*a^2 + 99478*a + 186250),
|
|
2999
|
+
....: K.ideal(2*a^4 + 3*a^3 + 4*a^2 + 15*a + 11),
|
|
3000
|
+
....: K.ideal(101)]
|
|
3001
|
+
sage: I.prime_to_S_part(S)
|
|
3002
|
+
Fractional ideal (24)
|
|
3003
|
+
"""
|
|
3004
|
+
a = self
|
|
3005
|
+
for p in S:
|
|
3006
|
+
n = a.valuation(p)
|
|
3007
|
+
a = a*p**(-n)
|
|
3008
|
+
return a
|
|
3009
|
+
|
|
3010
|
+
def is_S_unit(self, S):
|
|
3011
|
+
r"""
|
|
3012
|
+
Return ``True`` if this fractional ideal is a unit with respect to the list of primes `S`.
|
|
3013
|
+
|
|
3014
|
+
INPUT:
|
|
3015
|
+
|
|
3016
|
+
- ``S`` -- list of prime ideals (not checked if they are
|
|
3017
|
+
indeed prime)
|
|
3018
|
+
|
|
3019
|
+
.. NOTE::
|
|
3020
|
+
|
|
3021
|
+
This function assumes that `S` is a list of prime ideals,
|
|
3022
|
+
but does not check this. This function will fail if `S` is
|
|
3023
|
+
not a list of prime ideals.
|
|
3024
|
+
|
|
3025
|
+
OUTPUT:
|
|
3026
|
+
|
|
3027
|
+
``True``, if the ideal is an `S`-unit: that is, if the valuations of
|
|
3028
|
+
the ideal at all primes not in `S` are zero. ``False``, otherwise.
|
|
3029
|
+
|
|
3030
|
+
EXAMPLES::
|
|
3031
|
+
|
|
3032
|
+
sage: x = polygen(ZZ)
|
|
3033
|
+
sage: K.<a> = NumberField(x^2 + 23)
|
|
3034
|
+
sage: I = K.ideal(2)
|
|
3035
|
+
sage: P = I.factor()[0][0]
|
|
3036
|
+
sage: I.is_S_unit([P])
|
|
3037
|
+
False
|
|
3038
|
+
"""
|
|
3039
|
+
return self.prime_to_S_part(S).is_trivial()
|
|
3040
|
+
|
|
3041
|
+
def is_S_integral(self, S):
|
|
3042
|
+
r"""
|
|
3043
|
+
Return ``True`` if this fractional ideal is integral with respect to the list of primes `S`.
|
|
3044
|
+
|
|
3045
|
+
INPUT:
|
|
3046
|
+
|
|
3047
|
+
- ``S`` -- list of prime ideals (not checked if they are indeed prime)
|
|
3048
|
+
|
|
3049
|
+
.. NOTE::
|
|
3050
|
+
|
|
3051
|
+
This function assumes that `S` is a list of prime ideals,
|
|
3052
|
+
but does not check this. This function will fail if `S` is
|
|
3053
|
+
not a list of prime ideals.
|
|
3054
|
+
|
|
3055
|
+
OUTPUT:
|
|
3056
|
+
|
|
3057
|
+
``True``, if the ideal is `S`-integral: that is, if the valuations
|
|
3058
|
+
of the ideal at all primes not in `S` are nonnegative. ``False``,
|
|
3059
|
+
otherwise.
|
|
3060
|
+
|
|
3061
|
+
EXAMPLES::
|
|
3062
|
+
|
|
3063
|
+
sage: x = polygen(ZZ)
|
|
3064
|
+
sage: K.<a> = NumberField(x^2 + 23)
|
|
3065
|
+
sage: I = K.ideal(1/2)
|
|
3066
|
+
sage: P = K.ideal(2, 1/2*a - 1/2)
|
|
3067
|
+
sage: I.is_S_integral([P])
|
|
3068
|
+
False
|
|
3069
|
+
|
|
3070
|
+
sage: J = K.ideal(1/5)
|
|
3071
|
+
sage: J.is_S_integral([K.ideal(5)])
|
|
3072
|
+
True
|
|
3073
|
+
"""
|
|
3074
|
+
if self.is_integral():
|
|
3075
|
+
return True
|
|
3076
|
+
return self.prime_to_S_part(S).is_integral()
|
|
3077
|
+
|
|
3078
|
+
def prime_to_idealM_part(self, M):
|
|
3079
|
+
r"""
|
|
3080
|
+
Version for integral ideals of the ``prime_to_m_part`` function over `\ZZ`.
|
|
3081
|
+
Return the largest divisor of ``self`` that is coprime to the ideal `M`.
|
|
3082
|
+
|
|
3083
|
+
INPUT:
|
|
3084
|
+
|
|
3085
|
+
- ``M`` -- an integral ideal of the same field, or generators of an ideal
|
|
3086
|
+
|
|
3087
|
+
OUTPUT: an ideal which is the largest divisor of ``self`` that is coprime to `M`
|
|
3088
|
+
|
|
3089
|
+
AUTHOR: Maite Aranes
|
|
3090
|
+
|
|
3091
|
+
EXAMPLES::
|
|
3092
|
+
|
|
3093
|
+
sage: x = polygen(ZZ)
|
|
3094
|
+
sage: k.<a> = NumberField(x^2 + 23)
|
|
3095
|
+
sage: I = k.ideal(a + 1)
|
|
3096
|
+
sage: M = k.ideal(2, 1/2*a - 1/2)
|
|
3097
|
+
sage: J = I.prime_to_idealM_part(M); J
|
|
3098
|
+
Fractional ideal (12, 1/2*a + 13/2)
|
|
3099
|
+
sage: J.is_coprime(M)
|
|
3100
|
+
True
|
|
3101
|
+
|
|
3102
|
+
sage: J = I.prime_to_idealM_part(2); J
|
|
3103
|
+
Fractional ideal (3, 1/2*a + 1/2)
|
|
3104
|
+
sage: J.is_coprime(M)
|
|
3105
|
+
True
|
|
3106
|
+
"""
|
|
3107
|
+
# Catch invalid inputs by making sure that we can make an ideal out of M.
|
|
3108
|
+
k = self.number_field()
|
|
3109
|
+
M = k.ideal(M)
|
|
3110
|
+
|
|
3111
|
+
if not self.is_integral or not M.is_integral():
|
|
3112
|
+
raise TypeError("prime_to_idealM_part defined only for integral ideals")
|
|
3113
|
+
|
|
3114
|
+
if self.is_coprime(M):
|
|
3115
|
+
return self
|
|
3116
|
+
G = self + M
|
|
3117
|
+
I = self
|
|
3118
|
+
while not G.is_trivial():
|
|
3119
|
+
I = I/G
|
|
3120
|
+
G = I + G
|
|
3121
|
+
return I
|
|
3122
|
+
|
|
3123
|
+
def _p_quotient(self, p):
|
|
3124
|
+
"""
|
|
3125
|
+
This is an internal technical function that is used for example for
|
|
3126
|
+
computing the quotient of the ring of integers by a prime ideal.
|
|
3127
|
+
|
|
3128
|
+
INPUT:
|
|
3129
|
+
|
|
3130
|
+
- ``p`` -- a prime number contained in ``self``
|
|
3131
|
+
|
|
3132
|
+
OUTPUT:
|
|
3133
|
+
|
|
3134
|
+
- ``V`` -- a vector space of characteristic `p`
|
|
3135
|
+
- ``quo`` -- a partially defined quotient homomorphism from the
|
|
3136
|
+
ambient number field to `V`
|
|
3137
|
+
- ``lift`` -- a section of ``quo``
|
|
3138
|
+
|
|
3139
|
+
EXAMPLES::
|
|
3140
|
+
|
|
3141
|
+
sage: x = polygen(ZZ)
|
|
3142
|
+
sage: K.<i> = NumberField(x^2 + 1); O = K.maximal_order()
|
|
3143
|
+
sage: I = K.factor(3)[0][0]
|
|
3144
|
+
sage: Q, quo, lift = I._p_quotient(3); Q
|
|
3145
|
+
Vector space quotient V/W of dimension 2 over Finite Field of size 3 where
|
|
3146
|
+
V: Vector space of dimension 2 over Finite Field of size 3
|
|
3147
|
+
W: Vector space of degree 2 and dimension 0 over Finite Field of size 3
|
|
3148
|
+
Basis matrix:
|
|
3149
|
+
[]
|
|
3150
|
+
|
|
3151
|
+
We do an example with a split prime and show both the quo
|
|
3152
|
+
and lift maps::
|
|
3153
|
+
|
|
3154
|
+
sage: K.<i> = NumberField(x^2 + 1); O = K.maximal_order()
|
|
3155
|
+
sage: I = K.factor(5)[0][0]
|
|
3156
|
+
sage: Q, quo, lift = I._p_quotient(5)
|
|
3157
|
+
sage: lift(quo(i))
|
|
3158
|
+
3
|
|
3159
|
+
sage: lift(quo(i)) - i in I
|
|
3160
|
+
True
|
|
3161
|
+
sage: quo(lift(Q.0))
|
|
3162
|
+
(1)
|
|
3163
|
+
sage: Q.0
|
|
3164
|
+
(1)
|
|
3165
|
+
sage: Q
|
|
3166
|
+
Vector space quotient V/W of dimension 1 over Finite Field of size 5 where
|
|
3167
|
+
V: Vector space of dimension 2 over Finite Field of size 5
|
|
3168
|
+
W: Vector space of degree 2 and dimension 1 over Finite Field of size 5
|
|
3169
|
+
Basis matrix:
|
|
3170
|
+
[1 3]
|
|
3171
|
+
sage: quo
|
|
3172
|
+
Partially defined quotient map
|
|
3173
|
+
from Number Field in i with defining polynomial x^2 + 1
|
|
3174
|
+
to an explicit vector space representation for the quotient of
|
|
3175
|
+
the ring of integers by (p,I) for the ideal I=Fractional ideal (2*i - 1).
|
|
3176
|
+
sage: lift
|
|
3177
|
+
Lifting map
|
|
3178
|
+
to Gaussian Integers generated by i in Number Field in i with defining polynomial x^2 + 1
|
|
3179
|
+
from quotient of integers by Fractional ideal (2*i - 1)
|
|
3180
|
+
"""
|
|
3181
|
+
return quotient_char_p(self, p)
|
|
3182
|
+
|
|
3183
|
+
def residue_field(self, names=None):
|
|
3184
|
+
r"""
|
|
3185
|
+
Return the residue class field of this fractional ideal, which
|
|
3186
|
+
must be prime.
|
|
3187
|
+
|
|
3188
|
+
EXAMPLES::
|
|
3189
|
+
|
|
3190
|
+
sage: x = polygen(ZZ)
|
|
3191
|
+
sage: K.<a> = NumberField(x^3 - 7)
|
|
3192
|
+
sage: P = K.ideal(29).factor()[0][0]
|
|
3193
|
+
sage: P.residue_field()
|
|
3194
|
+
Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10)
|
|
3195
|
+
sage: P.residue_field('z')
|
|
3196
|
+
Residue field in z of Fractional ideal (2*a^2 + 3*a - 10)
|
|
3197
|
+
|
|
3198
|
+
Another example::
|
|
3199
|
+
|
|
3200
|
+
sage: K.<a> = NumberField(x^3 - 7)
|
|
3201
|
+
sage: P = K.ideal(389).factor()[0][0]; P
|
|
3202
|
+
Fractional ideal (389, a^2 - 44*a - 9)
|
|
3203
|
+
sage: P.residue_class_degree()
|
|
3204
|
+
2
|
|
3205
|
+
sage: P.residue_field()
|
|
3206
|
+
Residue field in abar of Fractional ideal (389, a^2 - 44*a - 9)
|
|
3207
|
+
sage: P.residue_field('z')
|
|
3208
|
+
Residue field in z of Fractional ideal (389, a^2 - 44*a - 9)
|
|
3209
|
+
sage: FF.<w> = P.residue_field()
|
|
3210
|
+
sage: FF
|
|
3211
|
+
Residue field in w of Fractional ideal (389, a^2 - 44*a - 9)
|
|
3212
|
+
sage: FF((a+1)^390)
|
|
3213
|
+
36
|
|
3214
|
+
sage: FF(a)
|
|
3215
|
+
w
|
|
3216
|
+
|
|
3217
|
+
An example of reduction maps to the residue field: these are defined on
|
|
3218
|
+
the whole valuation ring, i.e. the subring of the number field
|
|
3219
|
+
consisting of elements with nonnegative valuation. This shows that the
|
|
3220
|
+
issue raised in :issue:`1951` has been fixed::
|
|
3221
|
+
|
|
3222
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
3223
|
+
sage: P1, P2 = [g[0] for g in K.factor(5)]; P1, P2
|
|
3224
|
+
(Fractional ideal (2*i - 1), Fractional ideal (-2*i - 1))
|
|
3225
|
+
sage: a = 1/(1+2*i)
|
|
3226
|
+
sage: F1, F2 = [g.residue_field() for g in [P1, P2]]; F1, F2
|
|
3227
|
+
(Residue field of Fractional ideal (2*i - 1),
|
|
3228
|
+
Residue field of Fractional ideal (-2*i - 1))
|
|
3229
|
+
sage: a.valuation(P1)
|
|
3230
|
+
0
|
|
3231
|
+
sage: F1(i/7)
|
|
3232
|
+
4
|
|
3233
|
+
sage: F1(a)
|
|
3234
|
+
3
|
|
3235
|
+
sage: a.valuation(P2)
|
|
3236
|
+
-1
|
|
3237
|
+
sage: F2(a)
|
|
3238
|
+
Traceback (most recent call last):
|
|
3239
|
+
...
|
|
3240
|
+
ZeroDivisionError: Cannot reduce field element -2/5*i + 1/5
|
|
3241
|
+
modulo Fractional ideal (-2*i - 1): it has negative valuation
|
|
3242
|
+
|
|
3243
|
+
An example with a relative number field::
|
|
3244
|
+
|
|
3245
|
+
sage: L.<a,b> = NumberField([x^2 + 1, x^2 - 5])
|
|
3246
|
+
sage: p = L.ideal((-1/2*b - 1/2)*a + 1/2*b - 1/2)
|
|
3247
|
+
sage: R = p.residue_field(); R
|
|
3248
|
+
Residue field in abar of Fractional ideal ((-1/2*b - 1/2)*a + 1/2*b - 1/2)
|
|
3249
|
+
sage: R.cardinality()
|
|
3250
|
+
9
|
|
3251
|
+
sage: R(17)
|
|
3252
|
+
2
|
|
3253
|
+
sage: R((a + b)/17)
|
|
3254
|
+
abar
|
|
3255
|
+
sage: R(1/b)
|
|
3256
|
+
2*abar
|
|
3257
|
+
|
|
3258
|
+
We verify that :issue:`8721` is fixed::
|
|
3259
|
+
|
|
3260
|
+
sage: L.<a, b> = NumberField([x^2 - 3, x^2 - 5])
|
|
3261
|
+
sage: L.ideal(a).residue_field()
|
|
3262
|
+
Residue field in abar of Fractional ideal (a)
|
|
3263
|
+
"""
|
|
3264
|
+
if not self.is_prime():
|
|
3265
|
+
raise ValueError("The ideal must be prime")
|
|
3266
|
+
return self.number_field().residue_field(self, names=names)
|
|
3267
|
+
|
|
3268
|
+
def residue_class_degree(self):
|
|
3269
|
+
r"""
|
|
3270
|
+
Return the residue class degree of this fractional ideal,
|
|
3271
|
+
assuming it is prime. Otherwise, raise a :exc:`ValueError`.
|
|
3272
|
+
|
|
3273
|
+
The residue class degree of a prime ideal `I` is the degree of
|
|
3274
|
+
the extension `O_K/I` of its prime subfield.
|
|
3275
|
+
|
|
3276
|
+
EXAMPLES::
|
|
3277
|
+
|
|
3278
|
+
sage: x = polygen(ZZ)
|
|
3279
|
+
sage: K.<a> = NumberField(x^5 + 2); K
|
|
3280
|
+
Number Field in a with defining polynomial x^5 + 2
|
|
3281
|
+
sage: f = K.factor(19); f
|
|
3282
|
+
(Fractional ideal (a^2 + a - 3))
|
|
3283
|
+
* (Fractional ideal (2*a^4 + a^2 - 2*a + 1))
|
|
3284
|
+
* (Fractional ideal (a^2 + a - 1))
|
|
3285
|
+
sage: [i.residue_class_degree() for i, _ in f]
|
|
3286
|
+
[2, 2, 1]
|
|
3287
|
+
"""
|
|
3288
|
+
return ZZ(self.pari_prime().pr_get_f())
|
|
3289
|
+
|
|
3290
|
+
def ray_class_number(self):
|
|
3291
|
+
r"""
|
|
3292
|
+
Return the order of the ray class group modulo this ideal. This is a
|
|
3293
|
+
wrapper around PARI's :pari:`bnrclassno` function.
|
|
3294
|
+
|
|
3295
|
+
EXAMPLES::
|
|
3296
|
+
|
|
3297
|
+
sage: K.<z> = QuadraticField(-23)
|
|
3298
|
+
sage: p = K.primes_above(3)[0]
|
|
3299
|
+
sage: p.ray_class_number()
|
|
3300
|
+
3
|
|
3301
|
+
|
|
3302
|
+
sage: x = polygen(K)
|
|
3303
|
+
sage: L.<w> = K.extension(x^3 - z)
|
|
3304
|
+
sage: I = L.ideal(5)
|
|
3305
|
+
sage: I.ray_class_number()
|
|
3306
|
+
5184
|
|
3307
|
+
"""
|
|
3308
|
+
bid = self._pari_bid_()
|
|
3309
|
+
return ZZ(self.number_field().pari_bnf().bnrclassno(bid))
|
|
3310
|
+
|
|
3311
|
+
|
|
3312
|
+
def is_NumberFieldFractionalIdeal(x):
|
|
3313
|
+
"""
|
|
3314
|
+
Return ``True`` if `x` is a fractional ideal of a number field.
|
|
3315
|
+
|
|
3316
|
+
EXAMPLES::
|
|
3317
|
+
|
|
3318
|
+
sage: from sage.rings.number_field.number_field_ideal import is_NumberFieldFractionalIdeal
|
|
3319
|
+
sage: is_NumberFieldFractionalIdeal(2/3)
|
|
3320
|
+
doctest:warning...
|
|
3321
|
+
DeprecationWarning: The function is_NumberFieldFractionalIdeal is deprecated;
|
|
3322
|
+
use 'isinstance(..., NumberFieldFractionalIdeal)' instead.
|
|
3323
|
+
See https://github.com/sagemath/sage/issues/38124 for details.
|
|
3324
|
+
False
|
|
3325
|
+
sage: is_NumberFieldFractionalIdeal(ideal(5))
|
|
3326
|
+
False
|
|
3327
|
+
sage: x = polygen(ZZ)
|
|
3328
|
+
sage: k.<a> = NumberField(x^2 + 2)
|
|
3329
|
+
sage: I = k.ideal([a + 1]); I
|
|
3330
|
+
Fractional ideal (a + 1)
|
|
3331
|
+
sage: is_NumberFieldFractionalIdeal(I)
|
|
3332
|
+
True
|
|
3333
|
+
sage: Z = k.ideal(0); Z
|
|
3334
|
+
Ideal (0) of Number Field in a with defining polynomial x^2 + 2
|
|
3335
|
+
sage: is_NumberFieldFractionalIdeal(Z)
|
|
3336
|
+
False
|
|
3337
|
+
"""
|
|
3338
|
+
from sage.misc.superseded import deprecation
|
|
3339
|
+
deprecation(38124,
|
|
3340
|
+
"The function is_NumberFieldFractionalIdeal is deprecated; "
|
|
3341
|
+
"use 'isinstance(..., NumberFieldFractionalIdeal)' instead.")
|
|
3342
|
+
return isinstance(x, NumberFieldFractionalIdeal)
|
|
3343
|
+
|
|
3344
|
+
|
|
3345
|
+
class QuotientMap:
|
|
3346
|
+
"""
|
|
3347
|
+
Class to hold data needed by quotient maps from number field
|
|
3348
|
+
orders to residue fields. These are only partial maps: the exact
|
|
3349
|
+
domain is the appropriate valuation ring. For examples, see
|
|
3350
|
+
:meth:`~sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal.residue_field`.
|
|
3351
|
+
"""
|
|
3352
|
+
def __init__(self, K, M_OK_change, Q, I):
|
|
3353
|
+
"""
|
|
3354
|
+
Initialize this QuotientMap.
|
|
3355
|
+
|
|
3356
|
+
EXAMPLES::
|
|
3357
|
+
|
|
3358
|
+
sage: x = polygen(ZZ)
|
|
3359
|
+
sage: K.<a> = NumberField(x^3 + 4)
|
|
3360
|
+
sage: f = K.ideal(1 + a^2/2).residue_field().reduction_map(); f # indirect doctest
|
|
3361
|
+
Partially defined reduction map:
|
|
3362
|
+
From: Number Field in a with defining polynomial x^3 + 4
|
|
3363
|
+
To: Residue field of Fractional ideal (1/2*a^2 + 1)
|
|
3364
|
+
sage: f.__class__
|
|
3365
|
+
<class 'sage.rings.finite_rings.residue_field.ReductionMap'>
|
|
3366
|
+
"""
|
|
3367
|
+
self.__M_OK_change = M_OK_change
|
|
3368
|
+
self.__Q = Q
|
|
3369
|
+
self.__K = K
|
|
3370
|
+
self.__I = I
|
|
3371
|
+
self.__L, self.__from_L, self.__to_L = K.absolute_vector_space()
|
|
3372
|
+
|
|
3373
|
+
def __call__(self, x):
|
|
3374
|
+
"""
|
|
3375
|
+
Apply this QuotientMap to an element of the number field.
|
|
3376
|
+
|
|
3377
|
+
INPUT:
|
|
3378
|
+
|
|
3379
|
+
- ``x`` -- an element of the field
|
|
3380
|
+
|
|
3381
|
+
EXAMPLES::
|
|
3382
|
+
|
|
3383
|
+
sage: x = polygen(ZZ)
|
|
3384
|
+
sage: K.<a> = NumberField(x^3 + 4)
|
|
3385
|
+
sage: f = K.ideal(1 + a^2/2).residue_field().reduction_map()
|
|
3386
|
+
sage: f(a)
|
|
3387
|
+
2
|
|
3388
|
+
"""
|
|
3389
|
+
v = self.__to_L(x)
|
|
3390
|
+
w = v * self.__M_OK_change
|
|
3391
|
+
return self.__Q( list(w) )
|
|
3392
|
+
|
|
3393
|
+
def __repr__(self):
|
|
3394
|
+
r"""
|
|
3395
|
+
Return a string representation of this QuotientMap.
|
|
3396
|
+
|
|
3397
|
+
EXAMPLES::
|
|
3398
|
+
|
|
3399
|
+
sage: x = polygen(ZZ)
|
|
3400
|
+
sage: K.<a> = NumberField(x^3 + 4)
|
|
3401
|
+
sage: f = K.ideal(1 + a^2/2).residue_field().reduction_map()
|
|
3402
|
+
sage: repr(f)
|
|
3403
|
+
'Partially defined reduction map:\n From: Number Field in a with defining polynomial x^3 + 4\n To: Residue field of Fractional ideal (1/2*a^2 + 1)'
|
|
3404
|
+
"""
|
|
3405
|
+
return "Partially defined quotient map from %s to an explicit vector space representation for the quotient of the ring of integers by (p,I) for the ideal I=%s." % (self.__K, self.__I)
|
|
3406
|
+
|
|
3407
|
+
|
|
3408
|
+
class LiftMap:
|
|
3409
|
+
"""
|
|
3410
|
+
Class to hold data needed by lifting maps from residue fields to
|
|
3411
|
+
number field orders.
|
|
3412
|
+
"""
|
|
3413
|
+
def __init__(self, OK, M_OK_map, Q, I):
|
|
3414
|
+
"""
|
|
3415
|
+
Initialize this LiftMap.
|
|
3416
|
+
|
|
3417
|
+
EXAMPLES::
|
|
3418
|
+
|
|
3419
|
+
sage: x = polygen(ZZ)
|
|
3420
|
+
sage: K.<a> = NumberField(x^3 + 4)
|
|
3421
|
+
sage: I = K.ideal(1 + a^2/2)
|
|
3422
|
+
sage: f = I.residue_field().lift_map()
|
|
3423
|
+
sage: f.__class__
|
|
3424
|
+
<class 'sage.rings.finite_rings.residue_field.LiftingMap'>
|
|
3425
|
+
"""
|
|
3426
|
+
self.__I = I
|
|
3427
|
+
self.__OK = OK
|
|
3428
|
+
self.__Q = Q
|
|
3429
|
+
self.__M_OK_map = M_OK_map
|
|
3430
|
+
self.__Kgen = OK.number_field().absolute_generator()
|
|
3431
|
+
|
|
3432
|
+
def __call__(self, x):
|
|
3433
|
+
"""
|
|
3434
|
+
Apply this LiftMap to an element of the residue field.
|
|
3435
|
+
|
|
3436
|
+
EXAMPLES::
|
|
3437
|
+
|
|
3438
|
+
sage: x = polygen(ZZ)
|
|
3439
|
+
sage: K.<a> = NumberField(x^3 + 4)
|
|
3440
|
+
sage: R = K.ideal(1 + a^2/2).residue_field()
|
|
3441
|
+
sage: f = R.lift_map()
|
|
3442
|
+
sage: f(R(a/17))
|
|
3443
|
+
1
|
|
3444
|
+
|
|
3445
|
+
A relative example, which used to fail but is fixed by :issue:`8721`::
|
|
3446
|
+
|
|
3447
|
+
sage: L.<a, b> = NumberField([x^2 + 1, x^2 - 5])
|
|
3448
|
+
sage: p = L.ideal(2*a + 3)
|
|
3449
|
+
sage: V, to_V, from_V = p._p_quotient(13)
|
|
3450
|
+
sage: from_V(V.0)
|
|
3451
|
+
(-1/2*b + 7/2)*a - 1/2*b + 3/2
|
|
3452
|
+
"""
|
|
3453
|
+
# This lifts to OK tensor F_p
|
|
3454
|
+
v = self.__Q.lift(x)
|
|
3455
|
+
# This lifts to ZZ^n (= OK)
|
|
3456
|
+
w = v.lift()
|
|
3457
|
+
# Write back in terms of K
|
|
3458
|
+
z = (w * self.__M_OK_map).list()
|
|
3459
|
+
return self.__OK(sum(z[i] * self.__Kgen ** i for i in range(len(z))))
|
|
3460
|
+
|
|
3461
|
+
def __repr__(self):
|
|
3462
|
+
r"""
|
|
3463
|
+
Return a string representation of this QuotientMap.
|
|
3464
|
+
|
|
3465
|
+
EXAMPLES::
|
|
3466
|
+
|
|
3467
|
+
sage: x = polygen(ZZ)
|
|
3468
|
+
sage: K.<a> = NumberField(x^3 + 4)
|
|
3469
|
+
sage: R = K.ideal(1 + a^2/2).residue_field()
|
|
3470
|
+
sage: repr(R.lift_map())
|
|
3471
|
+
'Lifting map:\n From: Residue field of Fractional ideal (1/2*a^2 + 1)\n To: Maximal Order generated by [a, 1/2*a^2] in Number Field in a with defining polynomial x^3 + 4'
|
|
3472
|
+
"""
|
|
3473
|
+
return "Lifting map to %s from quotient of integers by %s" % (self.__OK, self.__I)
|
|
3474
|
+
|
|
3475
|
+
|
|
3476
|
+
def quotient_char_p(I, p):
|
|
3477
|
+
r"""
|
|
3478
|
+
Given an integral ideal `I` that contains a prime number `p`, compute
|
|
3479
|
+
a vector space `V = (O_K \mod p) / (I \mod p)`, along with a
|
|
3480
|
+
homomorphism `O_K \to V` and a section `V \to O_K`.
|
|
3481
|
+
|
|
3482
|
+
EXAMPLES::
|
|
3483
|
+
|
|
3484
|
+
sage: from sage.rings.number_field.number_field_ideal import quotient_char_p
|
|
3485
|
+
|
|
3486
|
+
sage: x = polygen(ZZ)
|
|
3487
|
+
sage: K.<i> = NumberField(x^2 + 1); O = K.maximal_order(); I = K.fractional_ideal(15)
|
|
3488
|
+
sage: quotient_char_p(I, 5)[0]
|
|
3489
|
+
Vector space quotient V/W of dimension 2 over Finite Field of size 5 where
|
|
3490
|
+
V: Vector space of dimension 2 over Finite Field of size 5
|
|
3491
|
+
W: Vector space of degree 2 and dimension 0 over Finite Field of size 5
|
|
3492
|
+
Basis matrix:
|
|
3493
|
+
[]
|
|
3494
|
+
sage: quotient_char_p(I, 3)[0]
|
|
3495
|
+
Vector space quotient V/W of dimension 2 over Finite Field of size 3 where
|
|
3496
|
+
V: Vector space of dimension 2 over Finite Field of size 3
|
|
3497
|
+
W: Vector space of degree 2 and dimension 0 over Finite Field of size 3
|
|
3498
|
+
Basis matrix:
|
|
3499
|
+
[]
|
|
3500
|
+
|
|
3501
|
+
sage: I = K.factor(13)[0][0]; I
|
|
3502
|
+
Fractional ideal (3*i + 2)
|
|
3503
|
+
sage: I.residue_class_degree()
|
|
3504
|
+
1
|
|
3505
|
+
sage: quotient_char_p(I, 13)[0]
|
|
3506
|
+
Vector space quotient V/W of dimension 1 over Finite Field of size 13 where
|
|
3507
|
+
V: Vector space of dimension 2 over Finite Field of size 13
|
|
3508
|
+
W: Vector space of degree 2 and dimension 1 over Finite Field of size 13
|
|
3509
|
+
Basis matrix:
|
|
3510
|
+
[1 8]
|
|
3511
|
+
"""
|
|
3512
|
+
if not I.is_integral():
|
|
3513
|
+
raise ValueError("I must be an integral ideal.")
|
|
3514
|
+
|
|
3515
|
+
K = I.number_field()
|
|
3516
|
+
OK = K.maximal_order() # will in the long run only really need a p-maximal order.
|
|
3517
|
+
M_OK = OK.free_module()
|
|
3518
|
+
M_I = I.free_module()
|
|
3519
|
+
|
|
3520
|
+
# Now we have to quite explicitly find a way to compute
|
|
3521
|
+
# with OK / I viewed as a quotient of two F_p vector spaces,
|
|
3522
|
+
# and itself viewed as an F_p vector space.
|
|
3523
|
+
|
|
3524
|
+
# Step 1. Write each basis vector for I (as a ZZ-module)
|
|
3525
|
+
# in terms of the basis for OK.
|
|
3526
|
+
|
|
3527
|
+
M_OK_mat = M_OK.basis_matrix()
|
|
3528
|
+
M_OK_change = M_OK_mat**(-1)
|
|
3529
|
+
B_I_in_terms_of_M = M_I.basis_matrix() * M_OK_change
|
|
3530
|
+
|
|
3531
|
+
# Step 2. Define "M_OK mod p" to just be (F_p)^n and
|
|
3532
|
+
# "M_I mod p" to be the reduction mod p of the elements
|
|
3533
|
+
# compute in step 1.
|
|
3534
|
+
|
|
3535
|
+
n = K.absolute_degree()
|
|
3536
|
+
k = FiniteField(p)
|
|
3537
|
+
M_OK_modp = k**n
|
|
3538
|
+
B_mod = B_I_in_terms_of_M.change_ring(k)
|
|
3539
|
+
M_I_modp = M_OK_modp.span(B_mod.row_space())
|
|
3540
|
+
|
|
3541
|
+
# Step 3. Compute the quotient of these two F_p vector space.
|
|
3542
|
+
|
|
3543
|
+
Q = M_OK_modp.quotient(M_I_modp)
|
|
3544
|
+
|
|
3545
|
+
# Step 4. Now we get the maps we need from the above data.
|
|
3546
|
+
|
|
3547
|
+
K_to_Q = QuotientMap(K, M_OK_change, Q, I)
|
|
3548
|
+
Q_to_OK = LiftMap(OK, M_OK_mat, Q, I)
|
|
3549
|
+
|
|
3550
|
+
return Q, K_to_Q, Q_to_OK
|