passagemath-flint 10.6.1rc10__cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_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_flint-10.6.1rc10.dist-info/METADATA +122 -0
- passagemath_flint-10.6.1rc10.dist-info/RECORD +360 -0
- passagemath_flint-10.6.1rc10.dist-info/WHEEL +6 -0
- passagemath_flint-10.6.1rc10.dist-info/top_level.txt +2 -0
- passagemath_flint.libs/libflint-3701249d.so.21.0.0 +0 -0
- passagemath_flint.libs/libgf2x-fbd36f80.so.3.0.0 +0 -0
- passagemath_flint.libs/libgfortran-8a9a71bc.so.5.0.0 +0 -0
- passagemath_flint.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
- passagemath_flint.libs/libgsl-e3525837.so.28.0.0 +0 -0
- passagemath_flint.libs/libmpfi-ad12a86d.so.0.0.0 +0 -0
- passagemath_flint.libs/libmpfr-e0f11cf3.so.6.2.1 +0 -0
- passagemath_flint.libs/libntl-1004113e.so.44.0.1 +0 -0
- passagemath_flint.libs/libopenblasp-r0-4c5b64b1.3.29.so +0 -0
- sage/all__sagemath_flint.py +29 -0
- sage/combinat/all__sagemath_flint.py +1 -0
- sage/combinat/posets/all__sagemath_flint.py +1 -0
- sage/combinat/posets/hasse_cython_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython_flint.pyx +194 -0
- sage/data_structures/all__sagemath_flint.py +1 -0
- sage/data_structures/bounded_integer_sequences.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/data_structures/bounded_integer_sequences.pxd +62 -0
- sage/data_structures/bounded_integer_sequences.pyx +1418 -0
- sage/graphs/all__sagemath_flint.py +1 -0
- sage/graphs/chrompoly.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/graphs/chrompoly.pyx +555 -0
- sage/graphs/matchpoly.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/graphs/matchpoly.pyx +412 -0
- sage/libs/all__sagemath_flint.py +17 -0
- sage/libs/arb/__init__.py +1 -0
- sage/libs/arb/acb.pxd +154 -0
- sage/libs/arb/acb_calc.pxd +9 -0
- sage/libs/arb/acb_elliptic.pxd +25 -0
- sage/libs/arb/acb_hypgeom.pxd +74 -0
- sage/libs/arb/acb_mat.pxd +62 -0
- sage/libs/arb/acb_modular.pxd +17 -0
- sage/libs/arb/acb_poly.pxd +216 -0
- sage/libs/arb/arb.pxd +240 -0
- sage/libs/arb/arb_fmpz_poly.pxd +21 -0
- sage/libs/arb/arb_hypgeom.pxd +83 -0
- sage/libs/arb/arb_wrap.h +34 -0
- sage/libs/arb/arf.pxd +131 -0
- sage/libs/arb/arith.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/arb/arith.pyx +87 -0
- sage/libs/arb/bernoulli.pxd +6 -0
- sage/libs/arb/mag.pxd +77 -0
- sage/libs/arb/types.pxd +37 -0
- sage/libs/flint/__init__.py +1 -0
- sage/libs/flint/acb.pxd +270 -0
- sage/libs/flint/acb_calc.pxd +22 -0
- sage/libs/flint/acb_dft.pxd +51 -0
- sage/libs/flint/acb_dirichlet.pxd +112 -0
- sage/libs/flint/acb_elliptic.pxd +42 -0
- sage/libs/flint/acb_hypgeom.pxd +169 -0
- sage/libs/flint/acb_macros.pxd +9 -0
- sage/libs/flint/acb_mat.pxd +136 -0
- sage/libs/flint/acb_mat_macros.pxd +10 -0
- sage/libs/flint/acb_modular.pxd +62 -0
- sage/libs/flint/acb_poly.pxd +251 -0
- sage/libs/flint/acb_poly_macros.pxd +8 -0
- sage/libs/flint/acb_theta.pxd +124 -0
- sage/libs/flint/acf.pxd +32 -0
- sage/libs/flint/aprcl.pxd +84 -0
- sage/libs/flint/arb.pxd +382 -0
- sage/libs/flint/arb_calc.pxd +31 -0
- sage/libs/flint/arb_fmpz_poly.pxd +34 -0
- sage/libs/flint/arb_fpwrap.pxd +215 -0
- sage/libs/flint/arb_hypgeom.pxd +147 -0
- sage/libs/flint/arb_macros.pxd +9 -0
- sage/libs/flint/arb_mat.pxd +140 -0
- sage/libs/flint/arb_mat_macros.pxd +10 -0
- sage/libs/flint/arb_poly.pxd +237 -0
- sage/libs/flint/arf.pxd +167 -0
- sage/libs/flint/arith.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/arith.pxd +76 -0
- sage/libs/flint/arith.pyx +77 -0
- sage/libs/flint/arith_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/arith_sage.pyx +308 -0
- sage/libs/flint/bernoulli.pxd +28 -0
- sage/libs/flint/bool_mat.pxd +52 -0
- sage/libs/flint/ca.pxd +203 -0
- sage/libs/flint/ca_ext.pxd +34 -0
- sage/libs/flint/ca_field.pxd +32 -0
- sage/libs/flint/ca_mat.pxd +117 -0
- sage/libs/flint/ca_poly.pxd +104 -0
- sage/libs/flint/ca_vec.pxd +46 -0
- sage/libs/flint/calcium.pxd +27 -0
- sage/libs/flint/d_mat.pxd +39 -0
- sage/libs/flint/d_vec.pxd +32 -0
- sage/libs/flint/dirichlet.pxd +57 -0
- sage/libs/flint/dlog.pxd +53 -0
- sage/libs/flint/double_extras.pxd +24 -0
- sage/libs/flint/double_interval.pxd +36 -0
- sage/libs/flint/fexpr.pxd +104 -0
- sage/libs/flint/fexpr_builtin.pxd +20 -0
- sage/libs/flint/fft.pxd +66 -0
- sage/libs/flint/flint.pxd +36 -0
- sage/libs/flint/flint_ntl_wrap.h +35 -0
- sage/libs/flint/flint_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/flint_sage.pyx +163 -0
- sage/libs/flint/flint_wrap.h +190 -0
- sage/libs/flint/fmpq.pxd +137 -0
- sage/libs/flint/fmpq_mat.pxd +105 -0
- sage/libs/flint/fmpq_mat_macros.pxd +10 -0
- sage/libs/flint/fmpq_mpoly.pxd +165 -0
- sage/libs/flint/fmpq_mpoly_factor.pxd +30 -0
- sage/libs/flint/fmpq_poly.pxd +241 -0
- sage/libs/flint/fmpq_poly_macros.pxd +9 -0
- sage/libs/flint/fmpq_poly_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpq_poly_sage.pxd +31 -0
- sage/libs/flint/fmpq_poly_sage.pyx +48 -0
- sage/libs/flint/fmpq_vec.pxd +27 -0
- sage/libs/flint/fmpz.pxd +256 -0
- sage/libs/flint/fmpz_extras.pxd +32 -0
- sage/libs/flint/fmpz_factor.pxd +42 -0
- sage/libs/flint/fmpz_factor_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_factor_sage.pxd +4 -0
- sage/libs/flint/fmpz_factor_sage.pyx +29 -0
- sage/libs/flint/fmpz_lll.pxd +49 -0
- sage/libs/flint/fmpz_macros.pxd +8 -0
- sage/libs/flint/fmpz_mat.pxd +184 -0
- sage/libs/flint/fmpz_mat_macros.pxd +10 -0
- sage/libs/flint/fmpz_mod.pxd +46 -0
- sage/libs/flint/fmpz_mod_mat.pxd +71 -0
- sage/libs/flint/fmpz_mod_mpoly.pxd +161 -0
- sage/libs/flint/fmpz_mod_mpoly_factor.pxd +28 -0
- sage/libs/flint/fmpz_mod_poly.pxd +249 -0
- sage/libs/flint/fmpz_mod_poly_factor.pxd +46 -0
- sage/libs/flint/fmpz_mod_vec.pxd +27 -0
- sage/libs/flint/fmpz_mpoly.pxd +224 -0
- sage/libs/flint/fmpz_mpoly_factor.pxd +29 -0
- sage/libs/flint/fmpz_mpoly_q.pxd +57 -0
- sage/libs/flint/fmpz_poly.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_poly.pxd +407 -0
- sage/libs/flint/fmpz_poly.pyx +19 -0
- sage/libs/flint/fmpz_poly_factor.pxd +33 -0
- sage/libs/flint/fmpz_poly_macros.pxd +8 -0
- sage/libs/flint/fmpz_poly_mat.pxd +71 -0
- sage/libs/flint/fmpz_poly_q.pxd +55 -0
- sage/libs/flint/fmpz_poly_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_poly_sage.pxd +20 -0
- sage/libs/flint/fmpz_poly_sage.pyx +500 -0
- sage/libs/flint/fmpz_vec.pxd +80 -0
- sage/libs/flint/fmpzi.pxd +52 -0
- sage/libs/flint/fq.pxd +97 -0
- sage/libs/flint/fq_default.pxd +84 -0
- sage/libs/flint/fq_default_mat.pxd +70 -0
- sage/libs/flint/fq_default_poly.pxd +97 -0
- sage/libs/flint/fq_default_poly_factor.pxd +39 -0
- sage/libs/flint/fq_embed.pxd +28 -0
- sage/libs/flint/fq_mat.pxd +83 -0
- sage/libs/flint/fq_nmod.pxd +95 -0
- sage/libs/flint/fq_nmod_embed.pxd +28 -0
- sage/libs/flint/fq_nmod_mat.pxd +83 -0
- sage/libs/flint/fq_nmod_mpoly.pxd +130 -0
- sage/libs/flint/fq_nmod_mpoly_factor.pxd +28 -0
- sage/libs/flint/fq_nmod_poly.pxd +202 -0
- sage/libs/flint/fq_nmod_poly_factor.pxd +47 -0
- sage/libs/flint/fq_nmod_vec.pxd +33 -0
- sage/libs/flint/fq_poly.pxd +204 -0
- sage/libs/flint/fq_poly_factor.pxd +47 -0
- sage/libs/flint/fq_vec.pxd +33 -0
- sage/libs/flint/fq_zech.pxd +99 -0
- sage/libs/flint/fq_zech_embed.pxd +28 -0
- sage/libs/flint/fq_zech_mat.pxd +78 -0
- sage/libs/flint/fq_zech_poly.pxd +198 -0
- sage/libs/flint/fq_zech_poly_factor.pxd +47 -0
- sage/libs/flint/fq_zech_vec.pxd +33 -0
- sage/libs/flint/gr.pxd +174 -0
- sage/libs/flint/gr_generic.pxd +215 -0
- sage/libs/flint/gr_mat.pxd +161 -0
- sage/libs/flint/gr_mpoly.pxd +68 -0
- sage/libs/flint/gr_poly.pxd +276 -0
- sage/libs/flint/gr_special.pxd +237 -0
- sage/libs/flint/gr_vec.pxd +120 -0
- sage/libs/flint/hypgeom.pxd +24 -0
- sage/libs/flint/long_extras.pxd +23 -0
- sage/libs/flint/mag.pxd +131 -0
- sage/libs/flint/mag_macros.pxd +8 -0
- sage/libs/flint/mpf_mat.pxd +36 -0
- sage/libs/flint/mpf_vec.pxd +34 -0
- sage/libs/flint/mpfr_mat.pxd +27 -0
- sage/libs/flint/mpfr_vec.pxd +25 -0
- sage/libs/flint/mpn_extras.pxd +41 -0
- sage/libs/flint/mpoly.pxd +72 -0
- sage/libs/flint/nf.pxd +19 -0
- sage/libs/flint/nf_elem.pxd +74 -0
- sage/libs/flint/nmod.pxd +35 -0
- sage/libs/flint/nmod_mat.pxd +104 -0
- sage/libs/flint/nmod_mpoly.pxd +144 -0
- sage/libs/flint/nmod_mpoly_factor.pxd +28 -0
- sage/libs/flint/nmod_poly.pxd +339 -0
- sage/libs/flint/nmod_poly_factor.pxd +44 -0
- sage/libs/flint/nmod_poly_linkage.pxi +710 -0
- sage/libs/flint/nmod_poly_mat.pxd +76 -0
- sage/libs/flint/nmod_vec.pxd +40 -0
- sage/libs/flint/ntl_interface.pxd +17 -0
- sage/libs/flint/padic.pxd +93 -0
- sage/libs/flint/padic_mat.pxd +64 -0
- sage/libs/flint/padic_poly.pxd +88 -0
- sage/libs/flint/partitions.pxd +23 -0
- sage/libs/flint/perm.pxd +26 -0
- sage/libs/flint/profiler.pxd +24 -0
- sage/libs/flint/qadic.pxd +77 -0
- sage/libs/flint/qfb.pxd +44 -0
- sage/libs/flint/qqbar.pxd +172 -0
- sage/libs/flint/qsieve.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/qsieve.pxd +41 -0
- sage/libs/flint/qsieve.pyx +21 -0
- sage/libs/flint/qsieve_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/qsieve_sage.pyx +67 -0
- sage/libs/flint/thread_pool.pxd +25 -0
- sage/libs/flint/types.pxd +2076 -0
- sage/libs/flint/ulong_extras.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/ulong_extras.pxd +141 -0
- sage/libs/flint/ulong_extras.pyx +21 -0
- sage/libs/flint/ulong_extras_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/ulong_extras_sage.pyx +21 -0
- sage/matrix/all__sagemath_flint.py +1 -0
- sage/matrix/change_ring.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/change_ring.pyx +43 -0
- sage/matrix/matrix_complex_ball_dense.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_complex_ball_dense.pxd +14 -0
- sage/matrix/matrix_complex_ball_dense.pyx +973 -0
- sage/matrix/matrix_cyclo_dense.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_cyclo_dense.pxd +16 -0
- sage/matrix/matrix_cyclo_dense.pyx +1761 -0
- sage/matrix/matrix_integer_dense.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_integer_dense.pxd +32 -0
- sage/matrix/matrix_integer_dense.pyx +5801 -0
- sage/matrix/matrix_integer_dense_hnf.py +1294 -0
- sage/matrix/matrix_integer_dense_saturation.py +346 -0
- sage/matrix/matrix_integer_sparse.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_integer_sparse.pxd +9 -0
- sage/matrix/matrix_integer_sparse.pyx +1090 -0
- sage/matrix/matrix_rational_dense.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_rational_dense.pxd +23 -0
- sage/matrix/matrix_rational_dense.pyx +2995 -0
- sage/matrix/matrix_rational_sparse.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_rational_sparse.pxd +11 -0
- sage/matrix/matrix_rational_sparse.pyx +789 -0
- sage/matrix/misc_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/misc_flint.pyx +109 -0
- sage/modular/all__sagemath_flint.py +1 -0
- sage/modular/modform/all__sagemath_flint.py +1 -0
- sage/modular/modform/eis_series_cython.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/modular/modform/eis_series_cython.pyx +226 -0
- sage/modular/modsym/all__sagemath_flint.py +1 -0
- sage/modular/modsym/apply.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/modular/modsym/apply.pxd +6 -0
- sage/modular/modsym/apply.pyx +113 -0
- sage/modular/modsym/heilbronn.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/modular/modsym/heilbronn.pyx +966 -0
- sage/modular/pollack_stevens/all__sagemath_flint.py +1 -0
- sage/modular/pollack_stevens/dist.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/modular/pollack_stevens/dist.pxd +38 -0
- sage/modular/pollack_stevens/dist.pyx +1439 -0
- sage/quivers/algebra.py +691 -0
- sage/quivers/algebra_elements.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/quivers/algebra_elements.pxd +97 -0
- sage/quivers/algebra_elements.pxi +1324 -0
- sage/quivers/algebra_elements.pyx +1424 -0
- sage/quivers/all.py +1 -0
- sage/quivers/ar_quiver.py +917 -0
- sage/quivers/homspace.py +640 -0
- sage/quivers/morphism.py +1282 -0
- sage/quivers/path_semigroup.py +1155 -0
- sage/quivers/paths.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/quivers/paths.pxd +13 -0
- sage/quivers/paths.pyx +809 -0
- sage/quivers/representation.py +2975 -0
- sage/rings/all__sagemath_flint.py +37 -0
- sage/rings/cif.py +4 -0
- sage/rings/complex_arb.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_arb.pxd +29 -0
- sage/rings/complex_arb.pyx +5176 -0
- sage/rings/complex_interval.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_interval.pxd +30 -0
- sage/rings/complex_interval.pyx +2475 -0
- sage/rings/complex_interval_field.py +711 -0
- sage/rings/convert/all.py +1 -0
- sage/rings/convert/mpfi.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/convert/mpfi.pxd +6 -0
- sage/rings/convert/mpfi.pyx +576 -0
- sage/rings/factorint_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/factorint_flint.pyx +99 -0
- sage/rings/fraction_field_FpT.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/fraction_field_FpT.pxd +28 -0
- sage/rings/fraction_field_FpT.pyx +2043 -0
- sage/rings/imaginary_unit.py +5 -0
- sage/rings/monomials.py +73 -0
- sage/rings/number_field/S_unit_solver.py +2870 -0
- sage/rings/number_field/all__sagemath_flint.py +7 -0
- sage/rings/number_field/bdd_height.py +664 -0
- sage/rings/number_field/class_group.py +762 -0
- sage/rings/number_field/galois_group.py +1307 -0
- sage/rings/number_field/homset.py +612 -0
- sage/rings/number_field/maps.py +687 -0
- sage/rings/number_field/morphism.py +272 -0
- sage/rings/number_field/number_field.py +12820 -0
- sage/rings/number_field/number_field_element.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_element.pxd +59 -0
- sage/rings/number_field/number_field_element.pyx +5735 -0
- sage/rings/number_field/number_field_element_quadratic.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_element_quadratic.pxd +34 -0
- sage/rings/number_field/number_field_element_quadratic.pyx +3185 -0
- sage/rings/number_field/number_field_ideal_rel.py +925 -0
- sage/rings/number_field/number_field_morphisms.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_morphisms.pyx +781 -0
- sage/rings/number_field/number_field_rel.py +2734 -0
- sage/rings/number_field/order.py +2981 -0
- sage/rings/number_field/order_ideal.py +804 -0
- sage/rings/number_field/selmer_group.py +715 -0
- sage/rings/number_field/small_primes_of_degree_one.py +242 -0
- sage/rings/number_field/splitting_field.py +606 -0
- sage/rings/number_field/structure.py +380 -0
- sage/rings/number_field/unit_group.py +721 -0
- sage/rings/padics/all__sagemath_flint.py +3 -0
- sage/rings/polynomial/all__sagemath_flint.py +1 -0
- sage/rings/polynomial/complex_roots.py +312 -0
- sage/rings/polynomial/evaluation_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/evaluation_flint.pxd +7 -0
- sage/rings/polynomial/evaluation_flint.pyx +68 -0
- sage/rings/polynomial/hilbert.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/hilbert.pyx +602 -0
- sage/rings/polynomial/polynomial_complex_arb.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_complex_arb.pxd +7 -0
- sage/rings/polynomial/polynomial_complex_arb.pyx +963 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.pxd +13 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.pyx +1881 -0
- sage/rings/polynomial/polynomial_number_field.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_number_field.pyx +345 -0
- sage/rings/polynomial/polynomial_rational_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_rational_flint.pxd +20 -0
- sage/rings/polynomial/polynomial_rational_flint.pyx +2598 -0
- sage/rings/polynomial/polynomial_zmod_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_zmod_flint.pxd +20 -0
- sage/rings/polynomial/polynomial_zmod_flint.pyx +1063 -0
- sage/rings/polynomial/real_roots.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/real_roots.pxd +81 -0
- sage/rings/polynomial/real_roots.pyx +4704 -0
- sage/rings/polynomial/refine_root.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/refine_root.pyx +142 -0
- sage/rings/polynomial/weil/all.py +4 -0
- sage/rings/polynomial/weil/power_sums.h +46 -0
- sage/rings/polynomial/weil/weil_polynomials.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/weil/weil_polynomials.pyx +596 -0
- sage/rings/qqbar.py +9025 -0
- sage/rings/real_arb.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/real_arb.pxd +21 -0
- sage/rings/real_arb.pyx +4065 -0
- sage/rings/real_interval_absolute.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/real_interval_absolute.pyx +1073 -0
- sage/rings/real_mpfi.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/real_mpfi.pyx +5428 -0
- sage/schemes/all__sagemath_flint.py +1 -0
- sage/schemes/elliptic_curves/all__sagemath_flint.py +1 -0
- sage/schemes/elliptic_curves/descent_two_isogeny.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/schemes/elliptic_curves/descent_two_isogeny.pyx +1387 -0
- sage/schemes/elliptic_curves/descent_two_isogeny_pari.pxd +5 -0
@@ -0,0 +1,1307 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-flint
|
2
|
+
# sage.doctest: needs sage.groups sage.rings.number_field
|
3
|
+
"""
|
4
|
+
Galois groups of number fields
|
5
|
+
|
6
|
+
AUTHORS:
|
7
|
+
|
8
|
+
- William Stein (2004, 2005): initial version
|
9
|
+
- David Loeffler (2009): rewrote to give explicit homomorphism groups
|
10
|
+
"""
|
11
|
+
|
12
|
+
from sage.structure.sage_object import SageObject
|
13
|
+
from sage.groups.galois_group import _alg_key
|
14
|
+
from sage.groups.galois_group_perm import GaloisGroup_perm, GaloisSubgroup_perm
|
15
|
+
from sage.groups.perm_gps.permgroup import standardize_generator
|
16
|
+
from sage.groups.perm_gps.permgroup_element import PermutationGroupElement
|
17
|
+
from sage.misc.superseded import deprecation
|
18
|
+
from sage.misc.cachefunc import cached_method
|
19
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
20
|
+
from sage.libs.pari import pari
|
21
|
+
from sage.rings.infinity import infinity
|
22
|
+
from sage.rings.number_field.number_field import refine_embedding
|
23
|
+
from sage.rings.number_field.morphism import NumberFieldHomomorphism_im_gens
|
24
|
+
from sage.rings.integer_ring import ZZ
|
25
|
+
from sage.rings.rational_field import QQ
|
26
|
+
|
27
|
+
|
28
|
+
class GaloisGroup_v1(SageObject):
|
29
|
+
r"""
|
30
|
+
A wrapper around a class representing an abstract transitive group.
|
31
|
+
|
32
|
+
This is just a fairly minimal object at present. To get the underlying
|
33
|
+
group, do ``G.group()``, and to get the corresponding number field do
|
34
|
+
``G.number_field()``. For a more sophisticated interface use the
|
35
|
+
``type=None`` option.
|
36
|
+
|
37
|
+
EXAMPLES::
|
38
|
+
|
39
|
+
sage: # needs sage.symbolic
|
40
|
+
sage: from sage.rings.number_field.galois_group import GaloisGroup_v1
|
41
|
+
sage: K = QQ[2^(1/3)]
|
42
|
+
sage: pK = K.absolute_polynomial()
|
43
|
+
sage: G = GaloisGroup_v1(pK.galois_group(pari_group=True), K); G
|
44
|
+
...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2
|
45
|
+
See https://github.com/sagemath/sage/issues/28782 for details.
|
46
|
+
Galois group PARI group [6, -1, 2, "S3"] of degree 3 of the
|
47
|
+
Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873?
|
48
|
+
sage: G.order()
|
49
|
+
6
|
50
|
+
sage: G.group()
|
51
|
+
PARI group [6, -1, 2, "S3"] of degree 3
|
52
|
+
sage: G.number_field()
|
53
|
+
Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873?
|
54
|
+
"""
|
55
|
+
|
56
|
+
def __init__(self, group, number_field):
|
57
|
+
"""
|
58
|
+
Create a Galois group.
|
59
|
+
|
60
|
+
EXAMPLES::
|
61
|
+
|
62
|
+
sage: from sage.rings.number_field.galois_group import GaloisGroup_v1
|
63
|
+
sage: x = polygen(ZZ, 'x')
|
64
|
+
sage: K = NumberField([x^2 + 1, x^2 + 2],'a')
|
65
|
+
sage: GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K)
|
66
|
+
...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2
|
67
|
+
See https://github.com/sagemath/sage/issues/28782 for details.
|
68
|
+
Galois group PARI group [4, 1, 2, "E(4) = 2[x]2"] of degree 4 of the
|
69
|
+
Number Field in a0 with defining polynomial x^2 + 1 over its base field
|
70
|
+
|
71
|
+
TESTS::
|
72
|
+
|
73
|
+
sage: x = polygen(ZZ, 'x')
|
74
|
+
sage: G = NumberField(x^3 + 2, 'alpha').galois_group(names='beta'); G
|
75
|
+
Galois group 3T2 (S3) with order 6 of x^3 + 2
|
76
|
+
sage: G == loads(dumps(G))
|
77
|
+
True
|
78
|
+
"""
|
79
|
+
deprecation(28782, "GaloisGroup_v1 is deprecated; please use GaloisGroup_v2")
|
80
|
+
self.__group = group
|
81
|
+
self.__number_field = number_field
|
82
|
+
|
83
|
+
def __eq__(self, other):
|
84
|
+
"""
|
85
|
+
Compare two number field Galois groups.
|
86
|
+
|
87
|
+
First the number fields are compared, then the Galois groups
|
88
|
+
if the number fields are equal. (Of course, if the number
|
89
|
+
fields are the same, the Galois groups are automatically
|
90
|
+
equal.)
|
91
|
+
|
92
|
+
EXAMPLES::
|
93
|
+
|
94
|
+
sage: from sage.rings.number_field.galois_group import GaloisGroup_v1
|
95
|
+
sage: x = polygen(ZZ, 'x')
|
96
|
+
sage: K = NumberField(x^3 + 2, 'alpha')
|
97
|
+
sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K)
|
98
|
+
...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2
|
99
|
+
See https://github.com/sagemath/sage/issues/28782 for details.
|
100
|
+
|
101
|
+
sage: # needs sage.symbolic
|
102
|
+
sage: L = QQ[sqrt(2)]
|
103
|
+
sage: H = GaloisGroup_v1(L.absolute_polynomial().galois_group(pari_group=True), L)
|
104
|
+
sage: H == G
|
105
|
+
False
|
106
|
+
sage: H == H
|
107
|
+
True
|
108
|
+
sage: G == G
|
109
|
+
True
|
110
|
+
"""
|
111
|
+
if not isinstance(other, GaloisGroup_v1):
|
112
|
+
return False
|
113
|
+
if self.__number_field == other.__number_field:
|
114
|
+
return True
|
115
|
+
if self.__group == other.__group:
|
116
|
+
return True
|
117
|
+
return False
|
118
|
+
|
119
|
+
def __ne__(self, other):
|
120
|
+
"""
|
121
|
+
Test for unequality.
|
122
|
+
|
123
|
+
EXAMPLES::
|
124
|
+
|
125
|
+
sage: from sage.rings.number_field.galois_group import GaloisGroup_v1
|
126
|
+
sage: x = polygen(ZZ, 'x')
|
127
|
+
sage: K = NumberField(x^3 + 2, 'alpha')
|
128
|
+
sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K)
|
129
|
+
...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2
|
130
|
+
See https://github.com/sagemath/sage/issues/28782 for details.
|
131
|
+
|
132
|
+
sage: # needs sage.symbolic
|
133
|
+
sage: L = QQ[sqrt(2)]
|
134
|
+
sage: H = GaloisGroup_v1(L.absolute_polynomial().galois_group(pari_group=True), L)
|
135
|
+
sage: H != G
|
136
|
+
True
|
137
|
+
sage: H != H
|
138
|
+
False
|
139
|
+
sage: G != G
|
140
|
+
False
|
141
|
+
"""
|
142
|
+
return not (self == other)
|
143
|
+
|
144
|
+
def __repr__(self):
|
145
|
+
"""
|
146
|
+
Display print representation of a Galois group.
|
147
|
+
|
148
|
+
EXAMPLES::
|
149
|
+
|
150
|
+
sage: from sage.rings.number_field.galois_group import GaloisGroup_v1
|
151
|
+
sage: x = polygen(ZZ, 'x')
|
152
|
+
sage: K = NumberField(x^4 + 2*x + 2, 'a')
|
153
|
+
sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K)
|
154
|
+
...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2
|
155
|
+
See https://github.com/sagemath/sage/issues/28782 for details.
|
156
|
+
sage: G.__repr__()
|
157
|
+
'Galois group PARI group [24, -1, 5, "S4"] of degree 4 of the Number Field in a with defining polynomial x^4 + 2*x + 2'
|
158
|
+
"""
|
159
|
+
return "Galois group %s of the %s" % (self.__group,
|
160
|
+
self.__number_field)
|
161
|
+
|
162
|
+
def group(self):
|
163
|
+
"""
|
164
|
+
Return the underlying abstract group.
|
165
|
+
|
166
|
+
EXAMPLES::
|
167
|
+
|
168
|
+
sage: from sage.rings.number_field.galois_group import GaloisGroup_v1
|
169
|
+
sage: x = polygen(ZZ, 'x')
|
170
|
+
sage: K = NumberField(x^3 + 2*x + 2, 'theta')
|
171
|
+
sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K)
|
172
|
+
...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2
|
173
|
+
See https://github.com/sagemath/sage/issues/28782 for details.
|
174
|
+
sage: H = G.group(); H
|
175
|
+
PARI group [6, -1, 2, "S3"] of degree 3
|
176
|
+
sage: P = H.permutation_group(); P
|
177
|
+
Transitive group number 2 of degree 3
|
178
|
+
sage: sorted(P)
|
179
|
+
[(), (2,3), (1,2), (1,2,3), (1,3,2), (1,3)]
|
180
|
+
"""
|
181
|
+
return self.__group
|
182
|
+
|
183
|
+
def order(self):
|
184
|
+
"""
|
185
|
+
Return the order of this Galois group.
|
186
|
+
|
187
|
+
EXAMPLES::
|
188
|
+
|
189
|
+
sage: from sage.rings.number_field.galois_group import GaloisGroup_v1
|
190
|
+
sage: x = polygen(ZZ, 'x')
|
191
|
+
sage: K = NumberField(x^5 + 2, 'theta_1')
|
192
|
+
sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K); G
|
193
|
+
...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2
|
194
|
+
See https://github.com/sagemath/sage/issues/28782 for details.
|
195
|
+
Galois group PARI group [20, -1, 3, "F(5) = 5:4"] of degree 5 of the
|
196
|
+
Number Field in theta_1 with defining polynomial x^5 + 2
|
197
|
+
sage: G.order()
|
198
|
+
20
|
199
|
+
"""
|
200
|
+
return self.__group.order()
|
201
|
+
|
202
|
+
def number_field(self):
|
203
|
+
"""
|
204
|
+
Return the number field of which this is the Galois group.
|
205
|
+
|
206
|
+
EXAMPLES::
|
207
|
+
|
208
|
+
sage: from sage.rings.number_field.galois_group import GaloisGroup_v1
|
209
|
+
sage: x = polygen(ZZ, 'x')
|
210
|
+
sage: K = NumberField(x^6 + 2, 't')
|
211
|
+
sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K); G
|
212
|
+
...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2
|
213
|
+
See https://github.com/sagemath/sage/issues/28782 for details.
|
214
|
+
Galois group PARI group [12, -1, 3, "D(6) = S(3)[x]2"] of degree 6 of the
|
215
|
+
Number Field in t with defining polynomial x^6 + 2
|
216
|
+
sage: G.number_field()
|
217
|
+
Number Field in t with defining polynomial x^6 + 2
|
218
|
+
"""
|
219
|
+
return self.__number_field
|
220
|
+
|
221
|
+
|
222
|
+
class GaloisGroup_v2(GaloisGroup_perm):
|
223
|
+
r"""
|
224
|
+
The Galois group of an (absolute) number field.
|
225
|
+
|
226
|
+
.. NOTE::
|
227
|
+
|
228
|
+
We define the Galois group of a non-normal field `K` to be the
|
229
|
+
Galois group of its Galois closure `L`, and elements are stored as
|
230
|
+
permutations of the roots of the defining polynomial of `L`, *not* as
|
231
|
+
permutations of the roots (in `L`) of the defining polynomial of `K`. The
|
232
|
+
latter would probably be preferable, but is harder to implement. Thus
|
233
|
+
the permutation group that is returned is always simply-transitive.
|
234
|
+
|
235
|
+
The 'arithmetical' features (decomposition and ramification groups,
|
236
|
+
Artin symbols etc) are only available for Galois fields.
|
237
|
+
|
238
|
+
EXAMPLES::
|
239
|
+
|
240
|
+
sage: x = polygen(ZZ, 'x')
|
241
|
+
sage: G = NumberField(x^3 - x - 1, 'a').galois_closure('b').galois_group()
|
242
|
+
sage: G.subgroup([G([(1,2,3),(4,5,6)])])
|
243
|
+
Subgroup generated by [(1,2,3)(4,5,6)] of
|
244
|
+
(Galois group 6T2 ([3]2) with order 6 of x^6 - 6*x^4 + 9*x^2 + 23)
|
245
|
+
|
246
|
+
Subgroups can be specified using generators (:issue:`26816`)::
|
247
|
+
|
248
|
+
sage: K.<a> = NumberField(x^6 - 6*x^4 + 9*x^2 + 23)
|
249
|
+
sage: G = K.galois_group()
|
250
|
+
sage: list(G)
|
251
|
+
[(),
|
252
|
+
(1,2,3)(4,5,6),
|
253
|
+
(1,3,2)(4,6,5),
|
254
|
+
(1,4)(2,6)(3,5),
|
255
|
+
(1,5)(2,4)(3,6),
|
256
|
+
(1,6)(2,5)(3,4)]
|
257
|
+
sage: g = G[1]
|
258
|
+
sage: h = G[3]
|
259
|
+
sage: list(G.subgroup([]))
|
260
|
+
[()]
|
261
|
+
sage: list(G.subgroup([g]))
|
262
|
+
[(), (1,2,3)(4,5,6), (1,3,2)(4,6,5)]
|
263
|
+
sage: list(G.subgroup([h]))
|
264
|
+
[(), (1,4)(2,6)(3,5)]
|
265
|
+
sage: sorted(G.subgroup([g,h])) == sorted(G)
|
266
|
+
True
|
267
|
+
"""
|
268
|
+
|
269
|
+
def __init__(self, number_field, algorithm='pari', names=None, gc_numbering=None, _type=None):
|
270
|
+
r"""
|
271
|
+
Create a Galois group.
|
272
|
+
|
273
|
+
EXAMPLES::
|
274
|
+
|
275
|
+
sage: QuadraticField(-23,'a').galois_group()
|
276
|
+
Galois group 2T1 (S2) with order 2 of x^2 + 23
|
277
|
+
|
278
|
+
You can specify the variable name for the Galois closure::
|
279
|
+
|
280
|
+
sage: x = polygen(ZZ, 'x')
|
281
|
+
sage: G = NumberField(x^3 - 2, 'b').galois_group(names='c'); G
|
282
|
+
Galois group 3T2 (S3) with order 6 of x^3 - 2
|
283
|
+
sage: G._galois_closure
|
284
|
+
Number Field in c with defining polynomial x^6 + 108
|
285
|
+
|
286
|
+
Or have one chosen automatically (``c`` is appended to the variable name)::
|
287
|
+
|
288
|
+
sage: G = NumberField(x^3 - 2, 'b').galois_group()
|
289
|
+
sage: G._galois_closure
|
290
|
+
Number Field in bc with defining polynomial x^6 + 108
|
291
|
+
|
292
|
+
TESTS::
|
293
|
+
|
294
|
+
sage: F.<z> = CyclotomicField(7)
|
295
|
+
sage: G = F.galois_group()
|
296
|
+
|
297
|
+
We test that a method inherited from PermutationGroup_generic returns
|
298
|
+
the right type of element (see :issue:`133`)::
|
299
|
+
|
300
|
+
sage: phi = G.random_element()
|
301
|
+
sage: type(phi) is G.element_class
|
302
|
+
True
|
303
|
+
sage: phi(z) # random
|
304
|
+
z^3
|
305
|
+
"""
|
306
|
+
if not number_field.is_absolute():
|
307
|
+
# We eventually want to support relative Galois groups, which currently just create the Galois group of the absolute field
|
308
|
+
deprecation(28782, "Use .absolute_field().galois_group() if you want the Galois group of the absolute field")
|
309
|
+
if gc_numbering is None:
|
310
|
+
gc_numbering = algorithm != 'magma'
|
311
|
+
# For the deprecated group() method of GaloisGroup_v1
|
312
|
+
self._type = _type
|
313
|
+
super().__init__(number_field, algorithm, names, gc_numbering)
|
314
|
+
|
315
|
+
@cached_method(key=GaloisGroup_perm._get_algorithm)
|
316
|
+
def _pol_galgp(self, algorithm=None):
|
317
|
+
"""
|
318
|
+
Return the Galois group object associated to the defining polynomial of this field extension.
|
319
|
+
|
320
|
+
EXAMPLES::
|
321
|
+
|
322
|
+
sage: R.<x> = ZZ[]
|
323
|
+
sage: x = polygen(ZZ, 'x')
|
324
|
+
sage: K.<a> = NumberField(x^3 + 2*x + 2)
|
325
|
+
sage: G = K.galois_group()
|
326
|
+
sage: G._pol_galgp()
|
327
|
+
PARI group [6, -1, 2, "S3"] of degree 3
|
328
|
+
sage: G._pol_galgp(algorithm='gap') # optional - gap_packages
|
329
|
+
Transitive group number 2 of degree 3
|
330
|
+
"""
|
331
|
+
algorithm = self._get_algorithm(algorithm)
|
332
|
+
f = self._field.absolute_polynomial()
|
333
|
+
pari_group = (self._type != "gap") # while GaloisGroup_v1 is deprecated
|
334
|
+
return f.galois_group(pari_group=pari_group, algorithm=algorithm)
|
335
|
+
|
336
|
+
def group(self):
|
337
|
+
"""
|
338
|
+
While :class:`GaloisGroup_v1` is being deprecated, this provides public access to the PARI/GAP group
|
339
|
+
in order to keep all aspects of that API.
|
340
|
+
|
341
|
+
EXAMPLES::
|
342
|
+
|
343
|
+
sage: R.<x> = ZZ[]
|
344
|
+
sage: x = polygen(ZZ, 'x')
|
345
|
+
sage: K.<a> = NumberField(x^3 + 2*x + 2)
|
346
|
+
sage: G = K.galois_group(type='pari')
|
347
|
+
...DeprecationWarning: the different Galois types have been merged into one class
|
348
|
+
See https://github.com/sagemath/sage/issues/28782 for details.
|
349
|
+
sage: G.group()
|
350
|
+
...DeprecationWarning: the group method is deprecated;
|
351
|
+
you can use _pol_galgp if you really need it
|
352
|
+
See https://github.com/sagemath/sage/issues/28782 for details.
|
353
|
+
PARI group [6, -1, 2, "S3"] of degree 3
|
354
|
+
"""
|
355
|
+
deprecation(28782, "the group method is deprecated; you can use _pol_galgp if you really need it")
|
356
|
+
return self._pol_galgp()
|
357
|
+
|
358
|
+
@cached_method(key=_alg_key)
|
359
|
+
def order(self, algorithm=None, recompute=False):
|
360
|
+
"""
|
361
|
+
Return the order of this Galois group.
|
362
|
+
|
363
|
+
EXAMPLES::
|
364
|
+
|
365
|
+
sage: R.<x> = ZZ[]
|
366
|
+
sage: x = polygen(ZZ, 'x')
|
367
|
+
sage: K.<a> = NumberField(x^3 + 2*x + 2)
|
368
|
+
sage: G = K.galois_group()
|
369
|
+
sage: G.order()
|
370
|
+
6
|
371
|
+
"""
|
372
|
+
algorithm = self._get_algorithm(algorithm)
|
373
|
+
K = self._field
|
374
|
+
if K.absolute_degree() < 12 or algorithm != "pari":
|
375
|
+
return self._pol_galgp(algorithm=algorithm).order()
|
376
|
+
else:
|
377
|
+
return self._galois_closure.absolute_degree()
|
378
|
+
|
379
|
+
def easy_order(self, algorithm=None):
|
380
|
+
"""
|
381
|
+
Return the order of this Galois group if it's quick to compute.
|
382
|
+
|
383
|
+
EXAMPLES::
|
384
|
+
|
385
|
+
sage: R.<x> = ZZ[]
|
386
|
+
sage: x = polygen(ZZ, 'x')
|
387
|
+
sage: K.<a> = NumberField(x^3 + 2*x + 2)
|
388
|
+
sage: G = K.galois_group()
|
389
|
+
sage: G.easy_order()
|
390
|
+
6
|
391
|
+
sage: x = polygen(ZZ, 'x')
|
392
|
+
sage: L.<b> = NumberField(x^72 + 2*x + 2)
|
393
|
+
sage: H = L.galois_group()
|
394
|
+
sage: H.easy_order()
|
395
|
+
"""
|
396
|
+
algorithm = self._get_algorithm(algorithm)
|
397
|
+
if self.order.cache:
|
398
|
+
return next(iter(self.order.cache.values()))
|
399
|
+
K = self._field
|
400
|
+
if K.absolute_degree() < 12 or algorithm != "pari":
|
401
|
+
size = self._pol_galgp(algorithm=algorithm).order()
|
402
|
+
self.order.cache[None] = size
|
403
|
+
return size
|
404
|
+
|
405
|
+
@cached_method(key=_alg_key)
|
406
|
+
def transitive_number(self, algorithm=None, recompute=False):
|
407
|
+
"""
|
408
|
+
Regardless of the value of ``gc_numbering``, give the transitive number
|
409
|
+
for the action on the roots of the defining polynomial of the original number field,
|
410
|
+
not the Galois closure.
|
411
|
+
|
412
|
+
INPUT:
|
413
|
+
|
414
|
+
- ``algorithm`` -- string, specify the algorithm to be used
|
415
|
+
- ``recompute`` -- boolean, whether to recompute the result even if known by another algorithm
|
416
|
+
|
417
|
+
EXAMPLES::
|
418
|
+
|
419
|
+
sage: R.<x> = ZZ[]
|
420
|
+
sage: x = polygen(ZZ, 'x')
|
421
|
+
sage: K.<a> = NumberField(x^3 + 2*x + 2)
|
422
|
+
sage: G = K.galois_group()
|
423
|
+
sage: G.transitive_number()
|
424
|
+
2
|
425
|
+
sage: x = polygen(ZZ, 'x')
|
426
|
+
sage: L.<b> = NumberField(x^13 + 2*x + 2)
|
427
|
+
sage: H = L.galois_group(algorithm='gap')
|
428
|
+
sage: H.transitive_number() # optional - gap_packages
|
429
|
+
9
|
430
|
+
"""
|
431
|
+
algorithm = self._get_algorithm(algorithm)
|
432
|
+
K = self._field
|
433
|
+
if K.absolute_degree() < 12 or algorithm != "pari":
|
434
|
+
return self._pol_galgp(algorithm=algorithm).transitive_number()
|
435
|
+
else:
|
436
|
+
if self._gc_numbering:
|
437
|
+
G = self._field.galois_group(algorithm=self._default_algorithm, names=self._gc_names, gc_numbering=False)
|
438
|
+
else:
|
439
|
+
G = self
|
440
|
+
return ZZ(G.gap().TransitiveIdentification())
|
441
|
+
|
442
|
+
def pari_label(self):
|
443
|
+
"""
|
444
|
+
Return the label assigned by PARI for this Galois group, an attempt at giving a human readable description of the group.
|
445
|
+
|
446
|
+
EXAMPLES::
|
447
|
+
|
448
|
+
sage: R.<x> = ZZ[]
|
449
|
+
sage: x = polygen(ZZ, 'x')
|
450
|
+
sage: K.<a> = NumberField(x^8 - x^5 + x^4 - x^3 + 1)
|
451
|
+
sage: G = K.galois_group()
|
452
|
+
sage: G.transitive_label()
|
453
|
+
'8T44'
|
454
|
+
sage: G.pari_label()
|
455
|
+
'[2^4]S(4)'
|
456
|
+
"""
|
457
|
+
return self._pol_galgp().label()
|
458
|
+
|
459
|
+
@cached_method
|
460
|
+
def signature(self):
|
461
|
+
"""
|
462
|
+
Return `1` if contained in the alternating group, `-1` otherwise.
|
463
|
+
|
464
|
+
EXAMPLES::
|
465
|
+
|
466
|
+
sage: R.<x> = ZZ[]
|
467
|
+
sage: x = polygen(ZZ, 'x')
|
468
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
469
|
+
sage: K.galois_group().signature()
|
470
|
+
-1
|
471
|
+
sage: K.<a> = NumberField(x^3 - 3*x - 1)
|
472
|
+
sage: K.galois_group().signature()
|
473
|
+
1
|
474
|
+
"""
|
475
|
+
if self._field.absolute_degree() < 12:
|
476
|
+
return self._pol_galgp().signature()
|
477
|
+
elif self._field.absolute_polynomial().discriminant().is_square():
|
478
|
+
return ZZ(1)
|
479
|
+
else:
|
480
|
+
return ZZ(-1)
|
481
|
+
|
482
|
+
# We compute various attributes lazily so that we can support quick lookup
|
483
|
+
# of some that are more easily computed. This allows us to emulate
|
484
|
+
# having initialized as a permutation group.
|
485
|
+
@lazy_attribute
|
486
|
+
def _gcdata(self):
|
487
|
+
"""
|
488
|
+
Return the Galois closure, together with the embedding of the top field into it.
|
489
|
+
|
490
|
+
EXAMPLES::
|
491
|
+
|
492
|
+
sage: R.<x> = ZZ[]
|
493
|
+
sage: x = polygen(ZZ, 'x')
|
494
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
495
|
+
sage: G = K.galois_group()
|
496
|
+
sage: G._gcdata
|
497
|
+
(Number Field in ac with defining polynomial x^6 + 108,
|
498
|
+
Ring morphism:
|
499
|
+
From: Number Field in a with defining polynomial x^3 - 2
|
500
|
+
To: Number Field in ac with defining polynomial x^6 + 108
|
501
|
+
Defn: a |--> -1/36*ac^4 - 1/2*ac)
|
502
|
+
|
503
|
+
TESTS:
|
504
|
+
|
505
|
+
Check that it works for relative number fields. This behavior will change in the future::
|
506
|
+
|
507
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
508
|
+
sage: L.<b> = NumberField(x^2 - x + 17*a)
|
509
|
+
sage: G = L.galois_group()
|
510
|
+
...DeprecationWarning: Use .absolute_field().galois_group() if you want the Galois group of the absolute field
|
511
|
+
See https://github.com/sagemath/sage/issues/28782 for details.
|
512
|
+
sage: M, emb = G._gcdata
|
513
|
+
sage: emb.domain() is L
|
514
|
+
True
|
515
|
+
sage: emb.codomain() is M
|
516
|
+
True
|
517
|
+
sage: G
|
518
|
+
Galois group 6T11 (2 wr S(3)) with order 48 of x^2 - x + 17*a
|
519
|
+
sage: M.degree()
|
520
|
+
48
|
521
|
+
"""
|
522
|
+
K = self._field
|
523
|
+
if self.is_galois():
|
524
|
+
return K, K.hom(K.gen(), K)
|
525
|
+
else:
|
526
|
+
if K.is_relative():
|
527
|
+
# Switch to the absolute field
|
528
|
+
K = K.absolute_field(K.variable_name() + 'a')
|
529
|
+
from_abs, to_abs = K.structure()
|
530
|
+
else:
|
531
|
+
to_abs = None
|
532
|
+
L, emb = K.galois_closure(names=self._gc_names, map=True)
|
533
|
+
if to_abs is not None:
|
534
|
+
emb = emb * to_abs
|
535
|
+
return L, emb
|
536
|
+
|
537
|
+
@lazy_attribute
|
538
|
+
def _pari_data(self):
|
539
|
+
"""
|
540
|
+
Return the corresponding PARI Galois group structure.
|
541
|
+
|
542
|
+
EXAMPLES::
|
543
|
+
|
544
|
+
sage: R.<x> = ZZ[]
|
545
|
+
sage: x = polygen(ZZ, 'x')
|
546
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
547
|
+
sage: G = K.galois_group()
|
548
|
+
sage: G._pari_data
|
549
|
+
[y^6 + 108, ...]
|
550
|
+
"""
|
551
|
+
return self._galois_closure.__pari__().galoisinit()
|
552
|
+
|
553
|
+
@lazy_attribute
|
554
|
+
def _elts(self):
|
555
|
+
"""
|
556
|
+
Return the list of all elements of this group.
|
557
|
+
|
558
|
+
EXAMPLES::
|
559
|
+
|
560
|
+
sage: R.<x> = ZZ[]
|
561
|
+
sage: x = polygen(ZZ, 'x')
|
562
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
563
|
+
sage: G = K.galois_group()
|
564
|
+
sage: G._elts
|
565
|
+
[(),
|
566
|
+
(1,2,3)(4,5,6),
|
567
|
+
(1,3,2)(4,6,5),
|
568
|
+
(1,4)(2,6)(3,5),
|
569
|
+
(1,5)(2,4)(3,6),
|
570
|
+
(1,6)(2,5)(3,4)]
|
571
|
+
sage: G = K.galois_group(gc_numbering=False)
|
572
|
+
sage: G._elts
|
573
|
+
[(), (2,3), (1,2), (1,2,3), (1,3,2), (1,3)]
|
574
|
+
"""
|
575
|
+
if self._gc_numbering:
|
576
|
+
# PARI computes all the elements of self anyway, so we might as well store them
|
577
|
+
return sorted(self(x, check=False) for x in self._pari_data[5])
|
578
|
+
return sorted(self.iteration())
|
579
|
+
|
580
|
+
@lazy_attribute
|
581
|
+
def _gens(self):
|
582
|
+
"""
|
583
|
+
Compute the generators as permutations.
|
584
|
+
|
585
|
+
EXAMPLES::
|
586
|
+
|
587
|
+
sage: R.<x> = ZZ[]
|
588
|
+
sage: x = polygen(ZZ, 'x')
|
589
|
+
sage: K.<a> = NumberField(x^5 - 2)
|
590
|
+
sage: G = K.galois_group(gc_numbering=False); G
|
591
|
+
Galois group 5T3 (5:4) with order 20 of x^5 - 2
|
592
|
+
sage: G._gens
|
593
|
+
[(1,2,3,5), (1,4,3,2,5)]
|
594
|
+
sage: G = K.galois_group(gc_numbering=True)
|
595
|
+
sage: G._gens
|
596
|
+
[(1,2,15,3)(4,19,11,8)(5,20,13,7)(6,9,10,16)(12,17,18,14),
|
597
|
+
(1,7,17,11,6)(2,8,5,9,18)(3,12,16,13,19)(4,14,20,15,10)]
|
598
|
+
"""
|
599
|
+
if self._gc_numbering:
|
600
|
+
gens = [standardize_generator(x, as_cycles=True) for x in self._pari_data[6]]
|
601
|
+
if not gens:
|
602
|
+
gens = [()]
|
603
|
+
gens = [self.element_class(x, self, check=False) for x in gens]
|
604
|
+
return sorted(set(gens))
|
605
|
+
else:
|
606
|
+
G = self._field.galois_group(algorithm=self._default_algorithm, names=self._gc_names, gc_numbering=True)
|
607
|
+
self._galois_closure = L = G._galois_closure
|
608
|
+
gens = [g.as_hom() for g in G._gens]
|
609
|
+
if gens:
|
610
|
+
# We add None so that we're 1-indexed
|
611
|
+
roots = [None] + self._field.absolute_polynomial().roots(L, multiplicities=False)
|
612
|
+
new_gens = []
|
613
|
+
for g in gens:
|
614
|
+
seen = set()
|
615
|
+
cycles = []
|
616
|
+
for start in range(1, len(roots)):
|
617
|
+
if start in seen:
|
618
|
+
continue
|
619
|
+
cycle = [start]
|
620
|
+
r = roots[start]
|
621
|
+
while True:
|
622
|
+
r = g(r)
|
623
|
+
i = roots.index(r)
|
624
|
+
seen.add(i)
|
625
|
+
if i == start:
|
626
|
+
break
|
627
|
+
cycle.append(i)
|
628
|
+
cycles.append(tuple(cycle))
|
629
|
+
new_gens.append(cycles)
|
630
|
+
else:
|
631
|
+
new_gens = [()]
|
632
|
+
# Want order to match G's, so don't sort
|
633
|
+
return [self.element_class(x, self, check=False) for x in new_gens]
|
634
|
+
|
635
|
+
def _element_constructor_(self, x, check=True):
|
636
|
+
"""
|
637
|
+
Create an element of ``self`` from ``x``.
|
638
|
+
|
639
|
+
INPUT:
|
640
|
+
|
641
|
+
- ``x`` -- one of the following (`G` is this Galois group):
|
642
|
+
|
643
|
+
- the integer 1, denoting the identity of `G`;
|
644
|
+
|
645
|
+
- an element of `G`;
|
646
|
+
|
647
|
+
- a permutation of the right length that defines an element
|
648
|
+
of `G`, or anything that coerces into such a permutation;
|
649
|
+
|
650
|
+
- an automorphism of the underlying number field.
|
651
|
+
|
652
|
+
EXAMPLES::
|
653
|
+
|
654
|
+
sage: K.<a> = QuadraticField(-23)
|
655
|
+
sage: G = K.galois_group()
|
656
|
+
sage: G(1)
|
657
|
+
()
|
658
|
+
sage: G(G.gens()[0])
|
659
|
+
(1,2)
|
660
|
+
sage: G([(1,2)])
|
661
|
+
(1,2)
|
662
|
+
sage: G(K.hom(-a, K))
|
663
|
+
(1,2)
|
664
|
+
"""
|
665
|
+
if x == 1:
|
666
|
+
return self.identity()
|
667
|
+
|
668
|
+
if isinstance(x, NumberFieldHomomorphism_im_gens) and x.parent() == self.number_field().Hom(self.number_field()):
|
669
|
+
l = [g for g in self if g.as_hom() == x]
|
670
|
+
if len(l) != 1:
|
671
|
+
raise ArithmeticError
|
672
|
+
return l[0]
|
673
|
+
return self.element_class(x, self, check=check)
|
674
|
+
|
675
|
+
def is_galois(self):
|
676
|
+
r"""
|
677
|
+
Whether the underlying number field is Galois.
|
678
|
+
|
679
|
+
EXAMPLES::
|
680
|
+
|
681
|
+
sage: x = polygen(ZZ, 'x')
|
682
|
+
sage: NumberField(x^3 - x + 1,'a').galois_group(names='b').is_galois()
|
683
|
+
False
|
684
|
+
sage: NumberField(x^2 - x + 1,'a').galois_group().is_galois()
|
685
|
+
True
|
686
|
+
"""
|
687
|
+
K = self._field
|
688
|
+
d = K.absolute_degree()
|
689
|
+
if d < 12:
|
690
|
+
return self._pol_galgp().order() == d
|
691
|
+
else:
|
692
|
+
return len(K.automorphisms()) == d
|
693
|
+
|
694
|
+
def _repr_(self):
|
695
|
+
r"""
|
696
|
+
String representation of this Galois group.
|
697
|
+
|
698
|
+
EXAMPLES::
|
699
|
+
|
700
|
+
sage: G = QuadraticField(-23, 'a').galois_group()
|
701
|
+
sage: G._repr_()
|
702
|
+
'Galois group 2T1 (S2) with order 2 of x^2 + 23'
|
703
|
+
sage: x = polygen(ZZ, 'x')
|
704
|
+
sage: G = NumberField(x^3 - 2, 'a').galois_group(names='b')
|
705
|
+
sage: G._repr_()
|
706
|
+
'Galois group 3T2 (S3) with order 6 of x^3 - 2'
|
707
|
+
"""
|
708
|
+
K = self.number_field()
|
709
|
+
f = K.defining_polynomial()
|
710
|
+
d = K.absolute_degree()
|
711
|
+
if d < 12:
|
712
|
+
plabel = self.pari_label().split('=')[-1].strip()
|
713
|
+
tlabel = "%sT%s (%s) with order %s " % (d, self.transitive_number(), plabel, self.order())
|
714
|
+
else:
|
715
|
+
tlabel = ""
|
716
|
+
if d < 12 or self.is_galois():
|
717
|
+
return "Galois group %sof %s" % (tlabel, f)
|
718
|
+
else:
|
719
|
+
return "Galois group %sof (non-Galois) %s" % (tlabel, f)
|
720
|
+
|
721
|
+
def number_field(self):
|
722
|
+
r"""
|
723
|
+
The ambient number field.
|
724
|
+
|
725
|
+
EXAMPLES::
|
726
|
+
|
727
|
+
sage: x = polygen(ZZ, 'x')
|
728
|
+
sage: K = NumberField(x^3 - x + 1, 'a')
|
729
|
+
sage: K.galois_group(names='b').number_field() is K
|
730
|
+
True
|
731
|
+
"""
|
732
|
+
return self._field
|
733
|
+
|
734
|
+
def list(self):
|
735
|
+
r"""
|
736
|
+
List of the elements of ``self``.
|
737
|
+
|
738
|
+
EXAMPLES::
|
739
|
+
|
740
|
+
sage: x = polygen(ZZ, 'x')
|
741
|
+
sage: NumberField(x^3 - 3*x + 1,'a').galois_group().list()
|
742
|
+
[(), (1,2,3), (1,3,2)]
|
743
|
+
"""
|
744
|
+
return self._elts
|
745
|
+
|
746
|
+
def unrank(self, i):
|
747
|
+
r"""
|
748
|
+
Return the `i`-th element of ``self``.
|
749
|
+
|
750
|
+
INPUT:
|
751
|
+
|
752
|
+
- ``i`` -- integer between `0` and `n-1` where
|
753
|
+
`n` is the cardinality of this set
|
754
|
+
|
755
|
+
EXAMPLES::
|
756
|
+
|
757
|
+
sage: x = polygen(ZZ, 'x')
|
758
|
+
sage: G = NumberField(x^3 - 3*x + 1,'a').galois_group()
|
759
|
+
sage: [G.unrank(i) for i in range(G.cardinality())]
|
760
|
+
[(), (1,2,3), (1,3,2)]
|
761
|
+
|
762
|
+
TESTS::
|
763
|
+
|
764
|
+
sage: x = polygen(ZZ, 'x')
|
765
|
+
sage: G = NumberField(x^3 - 3*x + 1,'a').galois_group()
|
766
|
+
sage: L = [G.unrank(i) for i in range(G.cardinality())]
|
767
|
+
sage: L == G.list()
|
768
|
+
True
|
769
|
+
"""
|
770
|
+
return self._elts[i]
|
771
|
+
|
772
|
+
def __iter__(self):
|
773
|
+
"""
|
774
|
+
Iterate over ``self``.
|
775
|
+
|
776
|
+
EXAMPLES::
|
777
|
+
|
778
|
+
sage: x = polygen(ZZ, 'x')
|
779
|
+
sage: G = NumberField(x^3 - 3*x + 1,'a').galois_group()
|
780
|
+
sage: list(G) == G.list()
|
781
|
+
True
|
782
|
+
"""
|
783
|
+
return iter(self._elts)
|
784
|
+
|
785
|
+
# Proper number theory starts here. All the functions below make no sense
|
786
|
+
# unless the field is Galois.
|
787
|
+
|
788
|
+
@cached_method
|
789
|
+
def _ramgroups(self, P):
|
790
|
+
"""
|
791
|
+
Compute ramification data using PARI.
|
792
|
+
|
793
|
+
INPUT:
|
794
|
+
|
795
|
+
- ``P`` -- a prime ideal
|
796
|
+
|
797
|
+
OUTPUT:
|
798
|
+
|
799
|
+
A PARI vector holding the decomposition group, inertia groups,
|
800
|
+
and higher ramification groups.
|
801
|
+
|
802
|
+
ALGORITHM:
|
803
|
+
|
804
|
+
This uses the PARI function :pari:`idealramgroups`.
|
805
|
+
|
806
|
+
EXAMPLES::
|
807
|
+
|
808
|
+
sage: x = polygen(ZZ, 'x')
|
809
|
+
sage: K.<a> = NumberField(x^4 - 2*x^2 + 2,'b').galois_closure()
|
810
|
+
sage: P = K.ideal([17, a^2])
|
811
|
+
sage: G = K.galois_group()
|
812
|
+
sage: G._ramgroups(P)
|
813
|
+
[[[Vecsmall([8, 7, 6, 5, 4, 3, 2, 1])], Vecsmall([2])]]
|
814
|
+
"""
|
815
|
+
K = self.number_field()
|
816
|
+
P = K.ideal_monoid()(P).pari_prime()
|
817
|
+
return pari(K).idealramgroups(self._pari_data, P)
|
818
|
+
|
819
|
+
def decomposition_group(self, P):
|
820
|
+
r"""
|
821
|
+
Decomposition group of a prime ideal `P`, i.e., the subgroup of elements
|
822
|
+
that map `P` to itself. This is the same as the Galois group of the
|
823
|
+
extension of local fields obtained by completing at `P`.
|
824
|
+
|
825
|
+
This function will raise an error if `P` is not prime or the given number
|
826
|
+
field is not Galois.
|
827
|
+
|
828
|
+
`P` can also be an infinite prime, i.e., an embedding into `\RR` or `\CC`.
|
829
|
+
|
830
|
+
EXAMPLES::
|
831
|
+
|
832
|
+
sage: x = polygen(ZZ, 'x')
|
833
|
+
sage: K.<a> = NumberField(x^4 - 2*x^2 + 2, 'b').galois_closure()
|
834
|
+
sage: P = K.ideal([17, a^2])
|
835
|
+
sage: G = K.galois_group()
|
836
|
+
sage: G.decomposition_group(P)
|
837
|
+
Subgroup generated by [(1,8)(2,7)(3,6)(4,5)] of
|
838
|
+
(Galois group 8T4 ([4]2) with order 8 of x^8 - 20*x^6 + 104*x^4 - 40*x^2 + 1156)
|
839
|
+
sage: G.decomposition_group(P^2)
|
840
|
+
Traceback (most recent call last):
|
841
|
+
...
|
842
|
+
ValueError: Fractional ideal (...) is not a prime ideal
|
843
|
+
sage: G.decomposition_group(17)
|
844
|
+
Traceback (most recent call last):
|
845
|
+
...
|
846
|
+
ValueError: Fractional ideal (17) is not a prime ideal
|
847
|
+
|
848
|
+
An example with an infinite place::
|
849
|
+
|
850
|
+
sage: x = polygen(ZZ, 'x')
|
851
|
+
sage: L.<b> = NumberField(x^3 - 2,'a').galois_closure(); G = L.galois_group()
|
852
|
+
sage: x = L.places()[0]
|
853
|
+
sage: G.decomposition_group(x).order()
|
854
|
+
2
|
855
|
+
"""
|
856
|
+
if not self.is_galois():
|
857
|
+
raise TypeError("Decomposition groups only defined for Galois extensions")
|
858
|
+
|
859
|
+
if isinstance(P, NumberFieldHomomorphism_im_gens):
|
860
|
+
if self.number_field().is_totally_real():
|
861
|
+
return self.subgroup([])
|
862
|
+
else:
|
863
|
+
return self.subgroup([self.complex_conjugation(P)])
|
864
|
+
else:
|
865
|
+
return self.ramification_group(P, -1)
|
866
|
+
|
867
|
+
def complex_conjugation(self, P=None):
|
868
|
+
"""
|
869
|
+
Return the unique element of ``self`` corresponding to complex conjugation,
|
870
|
+
for a specified embedding `P` into the complex numbers. If `P` is not
|
871
|
+
specified, use the "standard" embedding, whenever that is well-defined.
|
872
|
+
|
873
|
+
EXAMPLES::
|
874
|
+
|
875
|
+
sage: L.<z> = CyclotomicField(7)
|
876
|
+
sage: G = L.galois_group()
|
877
|
+
sage: conj = G.complex_conjugation(); conj
|
878
|
+
(1,4)(2,5)(3,6)
|
879
|
+
sage: conj(z)
|
880
|
+
-z^5 - z^4 - z^3 - z^2 - z - 1
|
881
|
+
|
882
|
+
An example where the field is not CM, so complex conjugation really
|
883
|
+
depends on the choice of embedding::
|
884
|
+
|
885
|
+
sage: x = polygen(ZZ, 'x')
|
886
|
+
sage: L = NumberField(x^6 + 40*x^3 + 1372, 'a')
|
887
|
+
sage: G = L.galois_group()
|
888
|
+
sage: [G.complex_conjugation(x) for x in L.places()]
|
889
|
+
[(1,3)(2,6)(4,5), (1,5)(2,4)(3,6), (1,2)(3,4)(5,6)]
|
890
|
+
"""
|
891
|
+
if P is None:
|
892
|
+
Q = self.number_field().specified_complex_embedding()
|
893
|
+
if Q is None:
|
894
|
+
raise ValueError("No default complex embedding specified")
|
895
|
+
P = Q
|
896
|
+
|
897
|
+
P = refine_embedding(P, infinity)
|
898
|
+
|
899
|
+
if not self.number_field().is_galois():
|
900
|
+
raise TypeError("Extension is not Galois")
|
901
|
+
if self.number_field().is_totally_real():
|
902
|
+
raise TypeError("No complex conjugation (field is real)")
|
903
|
+
|
904
|
+
g = self.number_field().gen()
|
905
|
+
gconj = P(g).conjugate()
|
906
|
+
elts = [s for s in self if P(s(g)) == gconj]
|
907
|
+
if len(elts) != 1:
|
908
|
+
raise ArithmeticError("Something has gone very wrong here")
|
909
|
+
return elts[0]
|
910
|
+
|
911
|
+
def ramification_group(self, P, v):
|
912
|
+
"""
|
913
|
+
Return the `v`-th ramification group of ``self`` for the prime `P`, i.e., the set
|
914
|
+
of elements `s` of ``self`` such that `s` acts trivially modulo `P^{(v+1)}`. This
|
915
|
+
is only defined for Galois fields.
|
916
|
+
|
917
|
+
EXAMPLES::
|
918
|
+
|
919
|
+
sage: x = polygen(ZZ, 'x')
|
920
|
+
sage: K.<b> = NumberField(x^3 - 3, 'a').galois_closure()
|
921
|
+
sage: G=K.galois_group()
|
922
|
+
sage: P = K.primes_above(3)[0]
|
923
|
+
sage: G.ramification_group(P, 3)
|
924
|
+
Subgroup generated by [(1,2,4)(3,5,6)] of
|
925
|
+
(Galois group 6T2 ([3]2) with order 6 of x^6 + 243)
|
926
|
+
sage: G.ramification_group(P, 5)
|
927
|
+
Subgroup generated by [()] of (Galois group 6T2 ([3]2) with order 6 of x^6 + 243)
|
928
|
+
"""
|
929
|
+
if not self.is_galois():
|
930
|
+
raise TypeError("Ramification groups only defined for Galois extensions")
|
931
|
+
ramdata = self._ramgroups(P)
|
932
|
+
if v < -1:
|
933
|
+
raise ValueError("v must be at least -1")
|
934
|
+
elif v + 1 >= len(ramdata):
|
935
|
+
return self.subgroup([])
|
936
|
+
else:
|
937
|
+
return self.subgroup(ramdata[v + 1][0])
|
938
|
+
|
939
|
+
def inertia_group(self, P):
|
940
|
+
"""
|
941
|
+
Return the inertia group of the prime `P`, i.e., the group of elements acting
|
942
|
+
trivially modulo `P`. This is just the 0th ramification group of `P`.
|
943
|
+
|
944
|
+
EXAMPLES::
|
945
|
+
|
946
|
+
sage: x = polygen(ZZ, 'x')
|
947
|
+
sage: K.<b> = NumberField(x^2 - 3, 'a')
|
948
|
+
sage: G = K.galois_group()
|
949
|
+
sage: G.inertia_group(K.primes_above(2)[0])
|
950
|
+
Subgroup generated by [(1,2)] of (Galois group 2T1 (S2) with order 2 of x^2 - 3)
|
951
|
+
sage: G.inertia_group(K.primes_above(5)[0])
|
952
|
+
Subgroup generated by [()] of (Galois group 2T1 (S2) with order 2 of x^2 - 3)
|
953
|
+
"""
|
954
|
+
if not self.is_galois():
|
955
|
+
raise TypeError("Inertia groups only defined for Galois extensions")
|
956
|
+
return self.ramification_group(P, 0)
|
957
|
+
|
958
|
+
def ramification_breaks(self, P):
|
959
|
+
r"""
|
960
|
+
Return the set of ramification breaks of the prime ideal `P`, i.e., the
|
961
|
+
set of indices `i` such that the ramification group `G_{i+1} \ne G_{i}`.
|
962
|
+
This is only defined for Galois fields.
|
963
|
+
|
964
|
+
EXAMPLES::
|
965
|
+
|
966
|
+
sage: x = polygen(ZZ, 'x')
|
967
|
+
sage: K.<b> = NumberField(x^8 - 20*x^6 + 104*x^4 - 40*x^2 + 1156)
|
968
|
+
sage: G = K.galois_group()
|
969
|
+
sage: P = K.primes_above(2)[0]
|
970
|
+
sage: G.ramification_breaks(P)
|
971
|
+
{1, 3, 5}
|
972
|
+
sage: min(G.ramification_group(P, i).order()
|
973
|
+
....: / G.ramification_group(P, i + 1).order()
|
974
|
+
....: for i in G.ramification_breaks(P))
|
975
|
+
2
|
976
|
+
"""
|
977
|
+
if not self.is_galois():
|
978
|
+
raise TypeError("Ramification breaks only defined for Galois extensions")
|
979
|
+
ramdata = self._ramgroups(P)
|
980
|
+
n = len(ramdata)
|
981
|
+
from sage.sets.set import Set
|
982
|
+
return Set([i - 1 for i in range(n - 1)
|
983
|
+
if ramdata[i][1] != ramdata[i + 1][1]] + [n - 2])
|
984
|
+
|
985
|
+
def artin_symbol(self, P):
|
986
|
+
r"""
|
987
|
+
Return the Artin symbol `\left(\frac{K /
|
988
|
+
\QQ}{\mathfrak{P}}\right)`, where `K` is the number field of ``self``,
|
989
|
+
and `\mathfrak{P}` is an unramified prime ideal. This is the unique
|
990
|
+
element `s` of the decomposition group of `\mathfrak{P}` such that `s(x) = x^p \bmod
|
991
|
+
\mathfrak{P}`, where `p` is the residue characteristic of `\mathfrak{P}`.
|
992
|
+
|
993
|
+
EXAMPLES::
|
994
|
+
|
995
|
+
sage: x = polygen(ZZ, 'x')
|
996
|
+
sage: K.<b> = NumberField(x^4 - 2*x^2 + 2, 'a').galois_closure()
|
997
|
+
sage: G = K.galois_group()
|
998
|
+
sage: sorted([G.artin_symbol(P) for P in K.primes_above(7)]) # random (see remark in primes_above)
|
999
|
+
[(1,4)(2,3)(5,8)(6,7),
|
1000
|
+
(1,4)(2,3)(5,8)(6,7),
|
1001
|
+
(1,5)(2,6)(3,7)(4,8),
|
1002
|
+
(1,5)(2,6)(3,7)(4,8)]
|
1003
|
+
sage: G.artin_symbol(17)
|
1004
|
+
Traceback (most recent call last):
|
1005
|
+
...
|
1006
|
+
ValueError: Fractional ideal (17) is not prime
|
1007
|
+
sage: QuadraticField(-7,'c').galois_group().artin_symbol(13)
|
1008
|
+
(1,2)
|
1009
|
+
sage: G.artin_symbol(K.primes_above(2)[0])
|
1010
|
+
Traceback (most recent call last):
|
1011
|
+
...
|
1012
|
+
ValueError: Fractional ideal (...) is ramified
|
1013
|
+
"""
|
1014
|
+
if not self.is_galois():
|
1015
|
+
raise TypeError("Artin symbols only defined for Galois extensions")
|
1016
|
+
|
1017
|
+
P = self.number_field().ideal_monoid()(P)
|
1018
|
+
if not P.is_prime():
|
1019
|
+
raise ValueError("%s is not prime" % P)
|
1020
|
+
p = P.smallest_integer()
|
1021
|
+
t = []
|
1022
|
+
gens = self.number_field().ring_of_integers().ring_generators()
|
1023
|
+
for s in self.decomposition_group(P):
|
1024
|
+
w = [(s(g) - g**p).valuation(P) for g in gens]
|
1025
|
+
if min(w) >= 1:
|
1026
|
+
t.append(s)
|
1027
|
+
if len(t) > 1:
|
1028
|
+
raise ValueError("%s is ramified" % P)
|
1029
|
+
return t[0]
|
1030
|
+
|
1031
|
+
|
1032
|
+
class GaloisGroup_subgroup(GaloisSubgroup_perm):
|
1033
|
+
r"""
|
1034
|
+
A subgroup of a Galois group, as returned by functions such as
|
1035
|
+
``decomposition_group``.
|
1036
|
+
|
1037
|
+
INPUT:
|
1038
|
+
|
1039
|
+
- ``ambient`` -- the ambient Galois group
|
1040
|
+
|
1041
|
+
- ``gens`` -- list of generators for the group
|
1042
|
+
|
1043
|
+
- ``gap_group`` -- a gap or libgap permutation group, or a string
|
1044
|
+
defining one (default: ``None``)
|
1045
|
+
|
1046
|
+
- ``domain`` -- set on which this permutation group acts; extracted from
|
1047
|
+
``ambient`` if not specified
|
1048
|
+
|
1049
|
+
- ``category`` -- the category for this object
|
1050
|
+
|
1051
|
+
- ``canonicalize`` -- if ``True``, sorts and removes duplicates
|
1052
|
+
|
1053
|
+
- ``check`` -- whether to check that generators actually lie in the
|
1054
|
+
ambient group
|
1055
|
+
|
1056
|
+
EXAMPLES::
|
1057
|
+
|
1058
|
+
sage: from sage.rings.number_field.galois_group import GaloisGroup_subgroup
|
1059
|
+
sage: x = polygen(ZZ, 'x')
|
1060
|
+
sage: G = NumberField(x^3 - x - 1, 'a').galois_closure('b').galois_group()
|
1061
|
+
sage: GaloisGroup_subgroup( G, [G([(1,2,3),(4,5,6)])])
|
1062
|
+
Subgroup generated by [(1,2,3)(4,5,6)] of
|
1063
|
+
(Galois group 6T2 ([3]2) with order 6 of x^6 - 6*x^4 + 9*x^2 + 23)
|
1064
|
+
|
1065
|
+
sage: K.<a> = NumberField(x^6 - 3*x^2 - 1)
|
1066
|
+
sage: L.<b> = K.galois_closure()
|
1067
|
+
sage: G = L.galois_group()
|
1068
|
+
sage: P = L.primes_above(3)[0]
|
1069
|
+
sage: H = G.decomposition_group(P)
|
1070
|
+
sage: H.order()
|
1071
|
+
3
|
1072
|
+
|
1073
|
+
sage: G = NumberField(x^3 - x - 1, 'a').galois_closure('b').galois_group()
|
1074
|
+
sage: H = G.subgroup([G([(1,2,3),(4,5,6)])])
|
1075
|
+
sage: H
|
1076
|
+
Subgroup generated by [(1,2,3)(4,5,6)] of
|
1077
|
+
(Galois group 6T2 ([3]2) with order 6 of x^6 - 6*x^4 + 9*x^2 + 23)
|
1078
|
+
|
1079
|
+
TESTS:
|
1080
|
+
|
1081
|
+
Check that :issue:`17664` is fixed::
|
1082
|
+
|
1083
|
+
sage: L.<c> = QuadraticField(-1)
|
1084
|
+
sage: P = L.primes_above(5)[0]
|
1085
|
+
sage: G = L.galois_group()
|
1086
|
+
sage: H = G.decomposition_group(P)
|
1087
|
+
sage: H.domain()
|
1088
|
+
{1, 2}
|
1089
|
+
sage: G.artin_symbol(P)
|
1090
|
+
()
|
1091
|
+
"""
|
1092
|
+
@lazy_attribute
|
1093
|
+
def _pari_data(self):
|
1094
|
+
"""
|
1095
|
+
Access to PARI information for the ambient Galois group.
|
1096
|
+
|
1097
|
+
EXAMPLES::
|
1098
|
+
|
1099
|
+
sage: x = polygen(ZZ, 'x')
|
1100
|
+
sage: L.<a> = NumberField(x^4 + 1)
|
1101
|
+
sage: G = L.galois_group()
|
1102
|
+
sage: H = G.decomposition_group(L.primes_above(3)[0])
|
1103
|
+
sage: H._pari_data
|
1104
|
+
[y^4 + 1, ...]
|
1105
|
+
"""
|
1106
|
+
return self._ambient_group._pari_data
|
1107
|
+
|
1108
|
+
def fixed_field(self, name=None, polred=None, threshold=None):
|
1109
|
+
r"""
|
1110
|
+
Return the fixed field of this subgroup (as a subfield of the Galois
|
1111
|
+
closure of the number field associated to the ambient Galois group).
|
1112
|
+
|
1113
|
+
INPUT:
|
1114
|
+
|
1115
|
+
- ``name`` -- a variable name for the new field
|
1116
|
+
|
1117
|
+
- ``polred`` -- whether to optimize the generator of the newly created field
|
1118
|
+
for a simpler polynomial, using PARI's :pari:`polredbest`.
|
1119
|
+
Defaults to ``True`` when the degree of the fixed field is at most 8.
|
1120
|
+
|
1121
|
+
- ``threshold`` -- positive number; polred only performed if the cost is at most this threshold
|
1122
|
+
|
1123
|
+
EXAMPLES::
|
1124
|
+
|
1125
|
+
sage: x = polygen(ZZ, 'x')
|
1126
|
+
sage: L.<a> = NumberField(x^4 + 1)
|
1127
|
+
sage: G = L.galois_group()
|
1128
|
+
sage: H = G.decomposition_group(L.primes_above(3)[0])
|
1129
|
+
sage: H.fixed_field()
|
1130
|
+
(Number Field in a0 with defining polynomial x^2 + 2 with a0 = a^3 + a,
|
1131
|
+
Ring morphism:
|
1132
|
+
From: Number Field in a0 with defining polynomial x^2 + 2 with a0 = a^3 + a
|
1133
|
+
To: Number Field in a with defining polynomial x^4 + 1
|
1134
|
+
Defn: a0 |--> a^3 + a)
|
1135
|
+
|
1136
|
+
You can use the ``polred`` option to get a simpler defining polynomial::
|
1137
|
+
|
1138
|
+
sage: K.<a> = NumberField(x^5 - 5*x^2 - 3)
|
1139
|
+
sage: G = K.galois_group(); G
|
1140
|
+
Galois group 5T2 (5:2) with order 10 of x^5 - 5*x^2 - 3
|
1141
|
+
sage: sigma, tau = G.gens()
|
1142
|
+
sage: H = G.subgroup([tau])
|
1143
|
+
sage: H.fixed_field(polred=False)
|
1144
|
+
(Number Field in a0 with defining polynomial x^2 + 84375
|
1145
|
+
with a0 = 5*ac^5 + 25*ac^3,
|
1146
|
+
Ring morphism:
|
1147
|
+
From: Number Field in a0 with defining polynomial x^2 + 84375
|
1148
|
+
with a0 = 5*ac^5 + 25*ac^3
|
1149
|
+
To: Number Field in ac with defining polynomial x^10 + 10*x^8 + 25*x^6 + 3375
|
1150
|
+
Defn: a0 |--> 5*ac^5 + 25*ac^3)
|
1151
|
+
sage: H.fixed_field(polred=True)
|
1152
|
+
(Number Field in a0 with defining polynomial x^2 - x + 4
|
1153
|
+
with a0 = -1/30*ac^5 - 1/6*ac^3 + 1/2,
|
1154
|
+
Ring morphism:
|
1155
|
+
From: Number Field in a0 with defining polynomial x^2 - x + 4
|
1156
|
+
with a0 = -1/30*ac^5 - 1/6*ac^3 + 1/2
|
1157
|
+
To: Number Field in ac with defining polynomial x^10 + 10*x^8 + 25*x^6 + 3375
|
1158
|
+
Defn: a0 |--> -1/30*ac^5 - 1/6*ac^3 + 1/2)
|
1159
|
+
sage: G.splitting_field()
|
1160
|
+
Number Field in ac with defining polynomial x^10 + 10*x^8 + 25*x^6 + 3375
|
1161
|
+
|
1162
|
+
An embedding is returned also if the subgroup is trivial
|
1163
|
+
(:issue:`26817`)::
|
1164
|
+
|
1165
|
+
sage: H = G.subgroup([])
|
1166
|
+
sage: H.fixed_field()
|
1167
|
+
(Number Field in ac with defining polynomial x^10 + 10*x^8 + 25*x^6 + 3375,
|
1168
|
+
Identity endomorphism of
|
1169
|
+
Number Field in ac with defining polynomial x^10 + 10*x^8 + 25*x^6 + 3375)
|
1170
|
+
"""
|
1171
|
+
G = self._ambient_group
|
1172
|
+
L = G._galois_closure
|
1173
|
+
if self.order() == G.order():
|
1174
|
+
return QQ, L.coerce_map_from(QQ)
|
1175
|
+
elif self.order() == 1:
|
1176
|
+
return L, L.coerce_map_from(L)
|
1177
|
+
vecs = [pari(g.domain()).Vecsmall() for g in self.iteration()]
|
1178
|
+
v = G._pari_data.galoisfixedfield(vecs)
|
1179
|
+
x = v[1]
|
1180
|
+
if polred is None:
|
1181
|
+
index = G.order() // self.order()
|
1182
|
+
polred = (index <= 8)
|
1183
|
+
if polred:
|
1184
|
+
f = x.minpoly()
|
1185
|
+
bitsize = ZZ(QQ(f[0]).numerator().nbits() + QQ(f[0]).denominator().nbits())
|
1186
|
+
cost = 2 * bitsize.nbits() + 5 * ZZ(f.poldegree()).nbits()
|
1187
|
+
# time(polredbest) ≈ b²d⁵
|
1188
|
+
if threshold is None or cost <= threshold:
|
1189
|
+
f, elt_back = f.polredbest(flag=1)
|
1190
|
+
x = elt_back.modreverse().lift()(x)
|
1191
|
+
if name is None:
|
1192
|
+
name = G._field.variable_name() + '0'
|
1193
|
+
return L.subfield(x, name=name)
|
1194
|
+
|
1195
|
+
|
1196
|
+
class GaloisGroupElement(PermutationGroupElement):
|
1197
|
+
r"""
|
1198
|
+
An element of a Galois group. This is stored as a permutation, but may also
|
1199
|
+
be made to act on elements of the field (generally returning elements of
|
1200
|
+
its Galois closure).
|
1201
|
+
|
1202
|
+
EXAMPLES::
|
1203
|
+
|
1204
|
+
sage: K.<w> = QuadraticField(-7); G = K.galois_group()
|
1205
|
+
sage: G[1]
|
1206
|
+
(1,2)
|
1207
|
+
sage: G[1](w + 2)
|
1208
|
+
-w + 2
|
1209
|
+
|
1210
|
+
sage: x = polygen(ZZ, 'x')
|
1211
|
+
sage: L.<v> = NumberField(x^3 - 2); G = L.galois_group(names='y')
|
1212
|
+
sage: G[4]
|
1213
|
+
(1,5)(2,4)(3,6)
|
1214
|
+
sage: G[4](v)
|
1215
|
+
1/18*y^4
|
1216
|
+
sage: G[4](G[4](v))
|
1217
|
+
-1/36*y^4 - 1/2*y
|
1218
|
+
sage: G[4](G[4](G[4](v)))
|
1219
|
+
1/18*y^4
|
1220
|
+
"""
|
1221
|
+
@cached_method
|
1222
|
+
def as_hom(self):
|
1223
|
+
r"""
|
1224
|
+
Return the homomorphism `L \to L` corresponding to ``self``, where `L` is the
|
1225
|
+
Galois closure of the ambient number field.
|
1226
|
+
|
1227
|
+
EXAMPLES::
|
1228
|
+
|
1229
|
+
sage: G = QuadraticField(-7,'w').galois_group()
|
1230
|
+
sage: G[1].as_hom()
|
1231
|
+
Ring endomorphism of Number Field in w with defining polynomial x^2 + 7
|
1232
|
+
with w = 2.645751311064591?*I
|
1233
|
+
Defn: w |--> -w
|
1234
|
+
|
1235
|
+
TESTS:
|
1236
|
+
|
1237
|
+
Number fields defined by non-monic and non-integral
|
1238
|
+
polynomials are supported (:issue:`252`)::
|
1239
|
+
|
1240
|
+
sage: R.<x> = QQ[]
|
1241
|
+
sage: x = polygen(ZZ, 'x')
|
1242
|
+
sage: f = 7/9*x^3 + 7/3*x^2 - 56*x + 123
|
1243
|
+
sage: K.<a> = NumberField(f)
|
1244
|
+
sage: G = K.galois_group()
|
1245
|
+
sage: G[1].as_hom()
|
1246
|
+
Ring endomorphism of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123
|
1247
|
+
Defn: a |--> -7/15*a^2 - 18/5*a + 96/5
|
1248
|
+
sage: prod(x - sigma(a) for sigma in G) == f.monic()
|
1249
|
+
True
|
1250
|
+
"""
|
1251
|
+
G = self.parent()
|
1252
|
+
L = G.splitting_field()
|
1253
|
+
# First compute the image of the standard generator of the
|
1254
|
+
# PARI number field.
|
1255
|
+
a = G._pari_data.galoispermtopol(pari(self.domain()).Vecsmall())
|
1256
|
+
# Now convert this to a conjugate of the standard generator of
|
1257
|
+
# the Sage number field.
|
1258
|
+
P = L._pari_absolute_structure()[1].lift()
|
1259
|
+
a = L(P(a.Mod(L.pari_polynomial('y'))))
|
1260
|
+
return L.hom(a, L)
|
1261
|
+
|
1262
|
+
def __call__(self, x):
|
1263
|
+
r"""
|
1264
|
+
Return the action of ``self`` on an element x in the number field of
|
1265
|
+
``self`` (or its Galois closure).
|
1266
|
+
|
1267
|
+
EXAMPLES::
|
1268
|
+
|
1269
|
+
sage: K.<w> = QuadraticField(-7)
|
1270
|
+
sage: f = K.galois_group()[1]
|
1271
|
+
sage: f(w)
|
1272
|
+
-w
|
1273
|
+
"""
|
1274
|
+
if x.parent() == self.parent().splitting_field():
|
1275
|
+
return self.as_hom()(x)
|
1276
|
+
else:
|
1277
|
+
return self.as_hom()(self.parent()._gc_map(x))
|
1278
|
+
|
1279
|
+
def ramification_degree(self, P):
|
1280
|
+
"""
|
1281
|
+
Return the greatest value of `v` such that `s` acts trivially modulo `P^v`.
|
1282
|
+
Should only be used if `P` is prime and `s` is in the decomposition group of `P`.
|
1283
|
+
|
1284
|
+
EXAMPLES::
|
1285
|
+
|
1286
|
+
sage: x = polygen(ZZ, 'x')
|
1287
|
+
sage: K.<b> = NumberField(x^3 - 3, 'a').galois_closure()
|
1288
|
+
sage: G = K.galois_group()
|
1289
|
+
sage: P = K.primes_above(3)[0]
|
1290
|
+
sage: s = hom(K, K, 1/18*b^4 - 1/2*b)
|
1291
|
+
sage: G(s).ramification_degree(P)
|
1292
|
+
4
|
1293
|
+
"""
|
1294
|
+
if not self.parent().is_galois():
|
1295
|
+
raise TypeError("Ramification degree only defined for Galois extensions")
|
1296
|
+
gens = self.parent().number_field().ring_of_integers().ring_generators()
|
1297
|
+
w = [(self(g) - g).valuation(P) for g in gens]
|
1298
|
+
return min(w)
|
1299
|
+
|
1300
|
+
|
1301
|
+
GaloisGroup_v2.Element = GaloisGroupElement
|
1302
|
+
GaloisGroup_v2.Subgroup = GaloisGroup_subgroup
|
1303
|
+
GaloisGroup_subgroup.Element = GaloisGroupElement
|
1304
|
+
|
1305
|
+
# For unpickling purposes we rebind GaloisGroup as GaloisGroup_v1.
|
1306
|
+
|
1307
|
+
GaloisGroup = GaloisGroup_v1
|