passagemath-schemes 10.6.47__cp312-cp312-macosx_13_0_arm64.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_schemes/.dylibs/libflint.22.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.6.47.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.47.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.47.dist-info/RECORD +311 -0
- passagemath_schemes-10.6.47.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.47.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-312-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +745 -0
- sage/lfunctions/pari.py +818 -0
- sage/lfunctions/zero_sums.cpython-312-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5135 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
- sage/modular/abvar/abvar_newform.py +244 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +186 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +720 -0
- sage/modular/abvar/homspace.py +998 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +740 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-312-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1402 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-312-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +363 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +653 -0
- sage/modular/arithgroup/congroup_gammaH.py +1469 -0
- sage/modular/arithgroup/congroup_generic.py +628 -0
- sage/modular/arithgroup/congroup_sl2z.py +267 -0
- sage/modular/arithgroup/farey_symbol.cpython-312-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1066 -0
- sage/modular/arithgroup/tests.py +418 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3753 -0
- sage/modular/btquotients/pautomorphicform.py +2570 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1109 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +569 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1065 -0
- sage/modular/hecke/algebra.py +746 -0
- sage/modular/hecke/all.py +20 -0
- sage/modular/hecke/ambient_module.py +1019 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +325 -0
- sage/modular/hecke/hecke_operator.py +780 -0
- sage/modular/hecke/homspace.py +206 -0
- sage/modular/hecke/module.py +1767 -0
- sage/modular/hecke/morphism.py +174 -0
- sage/modular/hecke/submodule.py +989 -0
- sage/modular/hypergeometric_misc.cpython-312-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2017 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1071 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +815 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +124 -0
- sage/modular/modform/ambient_g1.py +204 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +505 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4131 -0
- sage/modular/modform/find_generators.py +59 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +133 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-312-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1860 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +381 -0
- sage/modular/modform/weight1.py +220 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3846 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-312-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1295 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-312-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +375 -0
- sage/modular/multiple_zeta.py +2632 -0
- sage/modular/multiple_zeta_F_algebra.py +786 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1878 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +778 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +859 -0
- sage/modular/pollack_stevens/modsym.py +1593 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1076 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +845 -0
- sage/modular/quasimodform/ring.py +828 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +748 -0
- sage/schemes/curves/affine_curve.py +2928 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +381 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3026 -0
- sage/schemes/curves/zariski_vankampen.py +1932 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +1036 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1102 -0
- sage/schemes/elliptic_curves/constructor.py +1552 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
- sage/schemes/elliptic_curves/ell_egros.py +459 -0
- sage/schemes/elliptic_curves/ell_field.py +2836 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4787 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7335 -0
- sage/schemes/elliptic_curves/height.py +2109 -0
- sage/schemes/elliptic_curves/hom.py +1406 -0
- sage/schemes/elliptic_curves/hom_composite.py +934 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +682 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +237 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +943 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-312-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-312-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +715 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +291 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +580 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +73 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- sage_wheels/share/ellcurves/rank9 +7 -0
|
@@ -0,0 +1,1825 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
# sage.doctest: needs sage.libs.pari sage.rings.number_field
|
|
3
|
+
r"""
|
|
4
|
+
Smooth characters of `p`-adic fields
|
|
5
|
+
|
|
6
|
+
Let `F` be a finite extension of `\QQ_p`. Then we may consider the group of
|
|
7
|
+
smooth (i.e. locally constant) group homomorphisms `F^\times \to L^\times`, for
|
|
8
|
+
`L` any field. Such characters are important since they can be used to
|
|
9
|
+
parametrise smooth representations of `\mathrm{GL}_2(\QQ_p)`, which arise as
|
|
10
|
+
the local components of modular forms.
|
|
11
|
+
|
|
12
|
+
This module contains classes to represent such characters when `F` is `\QQ_p`
|
|
13
|
+
or a quadratic extension. In the latter case, we choose a quadratic extension
|
|
14
|
+
`K` of `\QQ` whose completion at `p` is `F`, and use Sage's wrappers of the
|
|
15
|
+
Pari :pari:`idealstar` and :pari:`ideallog` methods to work in the finite group
|
|
16
|
+
`\mathcal{O}_K / p^c` for `c \ge 0`.
|
|
17
|
+
|
|
18
|
+
An example with characters of `\QQ_7`::
|
|
19
|
+
|
|
20
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
21
|
+
sage: K.<z> = CyclotomicField(42)
|
|
22
|
+
sage: G = SmoothCharacterGroupQp(7, K)
|
|
23
|
+
sage: G.unit_gens(2), G.exponents(2)
|
|
24
|
+
([3, 7], [42, 0])
|
|
25
|
+
|
|
26
|
+
The output of the last line means that the group `\QQ_7^\times / (1 + 7^2
|
|
27
|
+
\ZZ_7)` is isomorphic to `C_{42} \times \ZZ`, with the two factors being
|
|
28
|
+
generated by `3` and `7` respectively. We create a character by specifying the
|
|
29
|
+
images of these generators::
|
|
30
|
+
|
|
31
|
+
sage: chi = G.character(2, [z^5, 11 + z]); chi
|
|
32
|
+
Character of Q_7*, of level 2, mapping 3 |--> z^5, 7 |--> z + 11
|
|
33
|
+
sage: chi(4)
|
|
34
|
+
z^8
|
|
35
|
+
sage: chi(42)
|
|
36
|
+
z^10 + 11*z^9
|
|
37
|
+
|
|
38
|
+
Characters are themselves group elements, and basic arithmetic on them works::
|
|
39
|
+
|
|
40
|
+
sage: chi**3
|
|
41
|
+
Character of Q_7*, of level 2, mapping 3 |--> z^8 - z, 7 |--> z^3 + 33*z^2 + 363*z + 1331
|
|
42
|
+
sage: chi.multiplicative_order()
|
|
43
|
+
+Infinity
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
import operator
|
|
47
|
+
|
|
48
|
+
from sage.arith.functions import lcm
|
|
49
|
+
from sage.arith.misc import crt
|
|
50
|
+
from sage.categories.groups import Groups
|
|
51
|
+
from sage.categories.rings import Rings
|
|
52
|
+
from sage.misc.abstract_method import abstract_method
|
|
53
|
+
from sage.misc.cachefunc import cached_method
|
|
54
|
+
from sage.misc.lazy_import import lazy_import
|
|
55
|
+
from sage.misc.misc_c import prod
|
|
56
|
+
from sage.misc.mrange import xmrange
|
|
57
|
+
from sage.misc.verbose import verbose
|
|
58
|
+
from sage.modular.dirichlet import DirichletGroup
|
|
59
|
+
from sage.rings.finite_rings.integer_mod_ring import Zmod
|
|
60
|
+
from sage.rings.infinity import Infinity
|
|
61
|
+
from sage.rings.integer_ring import ZZ
|
|
62
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
63
|
+
from sage.rings.rational_field import QQ
|
|
64
|
+
from sage.structure.element import MultiplicativeGroupElement, parent
|
|
65
|
+
from sage.structure.parent import Parent
|
|
66
|
+
from sage.structure.richcmp import richcmp_not_equal, richcmp
|
|
67
|
+
from sage.structure.sequence import Sequence
|
|
68
|
+
|
|
69
|
+
lazy_import('sage.rings.finite_rings.conway_polynomials', 'conway_polynomial')
|
|
70
|
+
lazy_import('sage.rings.number_field.number_field', 'NumberField')
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class SmoothCharacterGeneric(MultiplicativeGroupElement):
|
|
74
|
+
r"""
|
|
75
|
+
A smooth (i.e. locally constant) character of `F^\times`, for `F` some
|
|
76
|
+
finite extension of `\QQ_p`.
|
|
77
|
+
"""
|
|
78
|
+
def __init__(self, parent, c, values_on_gens):
|
|
79
|
+
r"""
|
|
80
|
+
Standard init function.
|
|
81
|
+
|
|
82
|
+
EXAMPLES::
|
|
83
|
+
|
|
84
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
85
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(2, QQ)
|
|
86
|
+
sage: G.character(0, [17]) # indirect doctest
|
|
87
|
+
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 0, mapping 2 |--> 17
|
|
88
|
+
sage: G.character(1, [1, 17]) # indirect doctest
|
|
89
|
+
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 0, mapping 2 |--> 17
|
|
90
|
+
sage: G.character(2, [1, -1, 1, 17]) # indirect doctest
|
|
91
|
+
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 2, mapping s |--> 1, 2*s + 1 |--> -1, -1 |--> 1, 2 |--> 17
|
|
92
|
+
sage: G.character(2, [1, 1, 1, 17]) # indirect doctest
|
|
93
|
+
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 0, mapping 2 |--> 17
|
|
94
|
+
"""
|
|
95
|
+
MultiplicativeGroupElement.__init__(self, parent)
|
|
96
|
+
self._c = c
|
|
97
|
+
self._values_on_gens = Sequence(values_on_gens, universe=self.base_ring(), immutable=True)
|
|
98
|
+
self._check_level()
|
|
99
|
+
|
|
100
|
+
def _check_level(self):
|
|
101
|
+
r"""
|
|
102
|
+
Check that this character has the level it claims to have, and if not,
|
|
103
|
+
decrement the level appropriately. This is called by :meth:`__init__`.
|
|
104
|
+
|
|
105
|
+
EXAMPLES::
|
|
106
|
+
|
|
107
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
108
|
+
sage: SmoothCharacterGroupQp(5, QQ).character(5, [-1, 7]) # indirect doctest
|
|
109
|
+
Character of Q_5*, of level 1, mapping 2 |--> -1, 5 |--> 7
|
|
110
|
+
"""
|
|
111
|
+
if self.level() == 0:
|
|
112
|
+
return
|
|
113
|
+
v = self.parent().subgroup_gens(self.level())
|
|
114
|
+
if all(self(x) == 1 for x in v):
|
|
115
|
+
new_gens = self.parent().unit_gens(self.level() - 1)
|
|
116
|
+
new_values = [self(x) for x in new_gens]
|
|
117
|
+
self._values_on_gens = Sequence(new_values, universe=self.base_ring(), immutable=True)
|
|
118
|
+
self._c = self._c - 1
|
|
119
|
+
self._check_level()
|
|
120
|
+
|
|
121
|
+
def __hash__(self):
|
|
122
|
+
r"""
|
|
123
|
+
EXAMPLES::
|
|
124
|
+
|
|
125
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
126
|
+
sage: chi = SmoothCharacterGroupQp(5, QQ).character(5, [-1, 7])
|
|
127
|
+
sage: D = {chi: 7}; D[chi] # indirect doctest
|
|
128
|
+
7
|
|
129
|
+
"""
|
|
130
|
+
return hash( (self._c, self._values_on_gens) )
|
|
131
|
+
|
|
132
|
+
def _richcmp_(self, other, op):
|
|
133
|
+
r"""
|
|
134
|
+
Compare ``self`` and ``other``.
|
|
135
|
+
|
|
136
|
+
Note that this only gets called when the
|
|
137
|
+
parents of ``self`` and ``other`` are identical.
|
|
138
|
+
|
|
139
|
+
INPUT:
|
|
140
|
+
|
|
141
|
+
- ``other`` -- another smooth character
|
|
142
|
+
|
|
143
|
+
- ``op`` -- a comparison operator (see :mod:`sage.structure.richcmp`)
|
|
144
|
+
|
|
145
|
+
EXAMPLES::
|
|
146
|
+
|
|
147
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp, SmoothCharacterGroupUnramifiedQuadratic
|
|
148
|
+
sage: SmoothCharacterGroupQp(7, Zmod(3)).character(1, [2, 1]) == SmoothCharacterGroupQp(7, ZZ).character(1, [-1, 1])
|
|
149
|
+
True
|
|
150
|
+
sage: chi1 = SmoothCharacterGroupUnramifiedQuadratic(7, QQ).character(0, [1])
|
|
151
|
+
sage: chi2 = SmoothCharacterGroupQp(7, QQ).character(0, [1])
|
|
152
|
+
sage: chi1 == chi2
|
|
153
|
+
False
|
|
154
|
+
sage: chi2.parent()(chi1) == chi2
|
|
155
|
+
True
|
|
156
|
+
sage: chi1 == loads(dumps(chi1))
|
|
157
|
+
True
|
|
158
|
+
"""
|
|
159
|
+
lx = self.level()
|
|
160
|
+
rx = other.level()
|
|
161
|
+
if lx != rx:
|
|
162
|
+
return richcmp_not_equal(lx, rx, op)
|
|
163
|
+
|
|
164
|
+
return richcmp(self._values_on_gens, other._values_on_gens, op)
|
|
165
|
+
|
|
166
|
+
def multiplicative_order(self):
|
|
167
|
+
r"""
|
|
168
|
+
Return the order of this character as an element of the character group.
|
|
169
|
+
|
|
170
|
+
EXAMPLES::
|
|
171
|
+
|
|
172
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
173
|
+
sage: K.<z> = CyclotomicField(42)
|
|
174
|
+
sage: G = SmoothCharacterGroupQp(7, K)
|
|
175
|
+
sage: G.character(3, [z^10 - z^3, 11]).multiplicative_order()
|
|
176
|
+
+Infinity
|
|
177
|
+
sage: G.character(3, [z^10 - z^3, 1]).multiplicative_order()
|
|
178
|
+
42
|
|
179
|
+
sage: G.character(1, [z^7, z^14]).multiplicative_order()
|
|
180
|
+
6
|
|
181
|
+
sage: G.character(0, [1]).multiplicative_order()
|
|
182
|
+
1
|
|
183
|
+
"""
|
|
184
|
+
if self._values_on_gens[-1].multiplicative_order() == Infinity:
|
|
185
|
+
return Infinity
|
|
186
|
+
else:
|
|
187
|
+
return lcm([x.multiplicative_order() for x in self._values_on_gens])
|
|
188
|
+
|
|
189
|
+
def level(self):
|
|
190
|
+
r"""
|
|
191
|
+
Return the level of this character, i.e. the smallest integer `c \ge 0`
|
|
192
|
+
such that it is trivial on `1 + \mathfrak{p}^c`.
|
|
193
|
+
|
|
194
|
+
EXAMPLES::
|
|
195
|
+
|
|
196
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
197
|
+
sage: SmoothCharacterGroupQp(7, QQ).character(2, [-1, 1]).level()
|
|
198
|
+
1
|
|
199
|
+
"""
|
|
200
|
+
return self._c
|
|
201
|
+
|
|
202
|
+
def __call__(self, x):
|
|
203
|
+
r"""
|
|
204
|
+
Evaluate the character at ``x``, which should be a nonzero element of
|
|
205
|
+
the number field of the parent group.
|
|
206
|
+
|
|
207
|
+
EXAMPLES::
|
|
208
|
+
|
|
209
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
210
|
+
sage: K.<z> = CyclotomicField(42)
|
|
211
|
+
sage: chi = SmoothCharacterGroupQp(7, K).character(3, [z^10 - z^3, 11])
|
|
212
|
+
sage: [chi(x) for x in [1, 2, 3, 9, 21, 1/12345678]]
|
|
213
|
+
[1, -z, z^10 - z^3, -z^11 - z^10 + z^8 + z^7 - z^6 - z^5 + z^3 + z^2 - 1, 11*z^10 - 11*z^3, z^7 - 1]
|
|
214
|
+
|
|
215
|
+
Non-examples::
|
|
216
|
+
|
|
217
|
+
sage: chi(QuadraticField(-1,'i').gen())
|
|
218
|
+
Traceback (most recent call last):
|
|
219
|
+
...
|
|
220
|
+
TypeError: no canonical coercion from Number Field in i with defining polynomial x^2 + 1 with i = 1*I to Rational Field
|
|
221
|
+
sage: chi(0)
|
|
222
|
+
Traceback (most recent call last):
|
|
223
|
+
...
|
|
224
|
+
ValueError: cannot evaluate at zero
|
|
225
|
+
sage: chi(Mod(1, 12))
|
|
226
|
+
Traceback (most recent call last):
|
|
227
|
+
...
|
|
228
|
+
TypeError: no canonical coercion from Ring of integers modulo 12 to Rational Field
|
|
229
|
+
|
|
230
|
+
Some examples with an unramified quadratic extension, where the choice
|
|
231
|
+
of generators is arbitrary (but deterministic)::
|
|
232
|
+
|
|
233
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
234
|
+
sage: K.<z> = CyclotomicField(30)
|
|
235
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(5, K)
|
|
236
|
+
sage: chi = G.character(2, [z**5, z**(-6), z**6, 3]); chi
|
|
237
|
+
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 2, mapping 11*s - 10 |--> z^5, 6 |--> -z^7 - z^6 + z^3 + z^2 - 1, 5*s + 1 |--> z^6, 5 |--> 3
|
|
238
|
+
sage: chi(G.unit_gens(2)[0]**7 / G.unit_gens(2)[1]/5)
|
|
239
|
+
1/3*z^6 - 1/3*z
|
|
240
|
+
sage: chi(2)
|
|
241
|
+
-z^3
|
|
242
|
+
"""
|
|
243
|
+
v = self.parent().discrete_log(self.level(), x)
|
|
244
|
+
return prod([self._values_on_gens[i] ** v[i] for i in range(len(v))])
|
|
245
|
+
|
|
246
|
+
def _repr_(self):
|
|
247
|
+
r"""
|
|
248
|
+
String representation of this character.
|
|
249
|
+
|
|
250
|
+
EXAMPLES::
|
|
251
|
+
|
|
252
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
253
|
+
sage: K.<z> = CyclotomicField(20)
|
|
254
|
+
sage: SmoothCharacterGroupQp(5, K).character(2, [z, z+1])._repr_()
|
|
255
|
+
'Character of Q_5*, of level 2, mapping 2 |--> z, 5 |--> z + 1'
|
|
256
|
+
|
|
257
|
+
Examples over field extensions::
|
|
258
|
+
|
|
259
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
260
|
+
sage: K.<z> = CyclotomicField(15)
|
|
261
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(5, K).character(2, [z**5, z**3, 1, z+1])._repr_()
|
|
262
|
+
'Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 2, mapping 11*s - 10 |--> z^5, 6 |--> z^3, 5*s + 1 |--> 1, 5 |--> z + 1'
|
|
263
|
+
"""
|
|
264
|
+
gens = self.parent().unit_gens(self.level())
|
|
265
|
+
mapst = ", ".join( str(gens[i]) + ' |--> ' + str(self._values_on_gens[i]) for i in range(len(gens)) )
|
|
266
|
+
return "Character of %s, of level %s, mapping %s" % (self.parent()._field_name(), self.level(), mapst)
|
|
267
|
+
|
|
268
|
+
def _mul_(self, other):
|
|
269
|
+
r"""
|
|
270
|
+
Product of ``self`` and ``other``.
|
|
271
|
+
|
|
272
|
+
EXAMPLES::
|
|
273
|
+
|
|
274
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
275
|
+
sage: K.<z> = CyclotomicField(20)
|
|
276
|
+
sage: chi1 = SmoothCharacterGroupQp(5, K).character(2, [z, z+1])
|
|
277
|
+
sage: chi2 = SmoothCharacterGroupQp(5, K).character(2, [z^4, 3])
|
|
278
|
+
sage: chi1 * chi2 # indirect doctest
|
|
279
|
+
Character of Q_5*, of level 1, mapping 2 |--> z^5, 5 |--> 3*z + 3
|
|
280
|
+
sage: chi2 * chi1 # indirect doctest
|
|
281
|
+
Character of Q_5*, of level 1, mapping 2 |--> z^5, 5 |--> 3*z + 3
|
|
282
|
+
sage: chi1 * SmoothCharacterGroupQp(5, QQ).character(2, [-1, 7]) # indirect doctest
|
|
283
|
+
Character of Q_5*, of level 2, mapping 2 |--> -z, 5 |--> 7*z + 7
|
|
284
|
+
"""
|
|
285
|
+
if other.level() > self.level():
|
|
286
|
+
return other * self
|
|
287
|
+
return self.parent().character(self.level(), [self(x) * other(x) for x in self.parent().unit_gens(self.level())])
|
|
288
|
+
|
|
289
|
+
def __invert__(self):
|
|
290
|
+
r"""
|
|
291
|
+
Multiplicative inverse of ``self``.
|
|
292
|
+
|
|
293
|
+
EXAMPLES::
|
|
294
|
+
|
|
295
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
296
|
+
sage: K.<z> = CyclotomicField(12)
|
|
297
|
+
sage: chi = SmoothCharacterGroupUnramifiedQuadratic(2, K).character(4, [z**4, z**3, z**9, -1, 7]); chi
|
|
298
|
+
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 4, mapping s |--> z^2 - 1, 2*s + 1 |--> z^3, 4*s + 1 |--> -z^3, -1 |--> -1, 2 |--> 7
|
|
299
|
+
sage: chi**(-1) # indirect doctest
|
|
300
|
+
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 4, mapping s |--> -z^2, 2*s + 1 |--> -z^3, 4*s + 1 |--> z^3, -1 |--> -1, 2 |--> 1/7
|
|
301
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).character(0, [7]) / chi # indirect doctest
|
|
302
|
+
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 4, mapping s |--> -z^2, 2*s + 1 |--> -z^3, 4*s + 1 |--> z^3, -1 |--> -1, 2 |--> 1
|
|
303
|
+
"""
|
|
304
|
+
return self.parent().character(self.level(), [~self(x) for x in self.parent().unit_gens(self.level())])
|
|
305
|
+
|
|
306
|
+
def restrict_to_Qp(self):
|
|
307
|
+
r"""
|
|
308
|
+
Return the restriction of this character to `\QQ_p^\times`, embedded as
|
|
309
|
+
a subfield of `F^\times`.
|
|
310
|
+
|
|
311
|
+
EXAMPLES::
|
|
312
|
+
|
|
313
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
|
|
314
|
+
sage: SmoothCharacterGroupRamifiedQuadratic(3, 0, QQ).character(0, [2]).restrict_to_Qp()
|
|
315
|
+
Character of Q_3*, of level 0, mapping 3 |--> 4
|
|
316
|
+
"""
|
|
317
|
+
G = SmoothCharacterGroupQp(self.parent().prime(), self.base_ring())
|
|
318
|
+
ugs = G.unit_gens(self.level())
|
|
319
|
+
return G.character(self.level(), [self(x) for x in ugs])
|
|
320
|
+
|
|
321
|
+
def galois_conjugate(self):
|
|
322
|
+
r"""
|
|
323
|
+
Return the composite of this character with the order `2` automorphism of
|
|
324
|
+
`K / \QQ_p` (assuming `K` is quadratic).
|
|
325
|
+
|
|
326
|
+
Note that this is the Galois operation on the *domain*, not on the
|
|
327
|
+
*codomain*.
|
|
328
|
+
|
|
329
|
+
EXAMPLES::
|
|
330
|
+
|
|
331
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
332
|
+
sage: K.<w> = CyclotomicField(3)
|
|
333
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(2, K)
|
|
334
|
+
sage: chi = G.character(2, [w, -1,-1, 3*w])
|
|
335
|
+
sage: chi2 = chi.galois_conjugate(); chi2
|
|
336
|
+
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 2, mapping s |--> -w - 1, 2*s + 1 |--> 1, -1 |--> -1, 2 |--> 3*w
|
|
337
|
+
|
|
338
|
+
sage: chi.restrict_to_Qp() == chi2.restrict_to_Qp()
|
|
339
|
+
True
|
|
340
|
+
sage: chi * chi2 == chi.parent().compose_with_norm(chi.restrict_to_Qp())
|
|
341
|
+
True
|
|
342
|
+
"""
|
|
343
|
+
K, s = self.parent().number_field().objgen()
|
|
344
|
+
if K.absolute_degree() != 2:
|
|
345
|
+
raise ValueError("Character must be defined on a quadratic extension")
|
|
346
|
+
sigs = K.embeddings(K)
|
|
347
|
+
sig = [x for x in sigs if x(s) != s][0]
|
|
348
|
+
return self.parent().character(self.level(), [self(sig(x)) for x in self.parent().unit_gens(self.level())])
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
class SmoothCharacterGroupGeneric(Parent):
|
|
352
|
+
r"""
|
|
353
|
+
The group of smooth (i.e. locally constant) characters of a `p`-adic field,
|
|
354
|
+
with values in some ring `R`. This is an abstract base class and should not
|
|
355
|
+
be instantiated directly.
|
|
356
|
+
"""
|
|
357
|
+
|
|
358
|
+
Element = SmoothCharacterGeneric
|
|
359
|
+
|
|
360
|
+
def __init__(self, p, base_ring):
|
|
361
|
+
r"""
|
|
362
|
+
TESTS::
|
|
363
|
+
|
|
364
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
|
|
365
|
+
sage: G = SmoothCharacterGroupGeneric(3, QQ)
|
|
366
|
+
sage: SmoothCharacterGroupGeneric(3, "hello")
|
|
367
|
+
Traceback (most recent call last):
|
|
368
|
+
...
|
|
369
|
+
TypeError: base ring (=hello) must be a ring
|
|
370
|
+
"""
|
|
371
|
+
if base_ring not in Rings():
|
|
372
|
+
raise TypeError("base ring (=%s) must be a ring" % base_ring)
|
|
373
|
+
Parent.__init__(self, base=base_ring,
|
|
374
|
+
category=Groups().Commutative())
|
|
375
|
+
if not (p in ZZ and ZZ(p).is_prime()):
|
|
376
|
+
raise ValueError("p (=%s) must be a prime integer" % p)
|
|
377
|
+
self._p = ZZ.coerce(p)
|
|
378
|
+
|
|
379
|
+
def _element_constructor_(self, x):
|
|
380
|
+
r"""
|
|
381
|
+
Construct an element of this group from ``x`` (possibly noncanonically).
|
|
382
|
+
This only works if ``x`` is a character of a field containing the field of
|
|
383
|
+
``self``, whose values lie in a field that can be converted into ``self``.
|
|
384
|
+
|
|
385
|
+
EXAMPLES::
|
|
386
|
+
|
|
387
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
388
|
+
sage: K.<i> = QuadraticField(-1)
|
|
389
|
+
sage: G = SmoothCharacterGroupQp(3, QQ)
|
|
390
|
+
sage: GK = SmoothCharacterGroupQp(3, K)
|
|
391
|
+
sage: chi = GK(G.character(0, [4])); chi # indirect doctest
|
|
392
|
+
Character of Q_3*, of level 0, mapping 3 |--> 4
|
|
393
|
+
sage: chi.parent() is GK
|
|
394
|
+
True
|
|
395
|
+
sage: G(GK.character(0, [7])) # indirect doctest
|
|
396
|
+
Character of Q_3*, of level 0, mapping 3 |--> 7
|
|
397
|
+
sage: G(GK.character(0, [i])) # indirect doctest
|
|
398
|
+
Traceback (most recent call last):
|
|
399
|
+
...
|
|
400
|
+
TypeError: unable to convert i to an element of Rational Field
|
|
401
|
+
"""
|
|
402
|
+
if x == 1:
|
|
403
|
+
return self.character(0, [1])
|
|
404
|
+
P = parent(x)
|
|
405
|
+
if (isinstance(P, SmoothCharacterGroupGeneric)
|
|
406
|
+
and P.number_field().has_coerce_map_from(self.number_field())):
|
|
407
|
+
return self.character(x.level(), [x(v) for v in self.unit_gens(x.level())])
|
|
408
|
+
else:
|
|
409
|
+
raise TypeError
|
|
410
|
+
|
|
411
|
+
def __eq__(self, other):
|
|
412
|
+
r"""
|
|
413
|
+
TESTS::
|
|
414
|
+
|
|
415
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
416
|
+
sage: G = SmoothCharacterGroupQp(3, QQ)
|
|
417
|
+
sage: G == SmoothCharacterGroupQp(3, QQ[I])
|
|
418
|
+
False
|
|
419
|
+
sage: G == 7
|
|
420
|
+
False
|
|
421
|
+
sage: G == SmoothCharacterGroupQp(7, QQ)
|
|
422
|
+
False
|
|
423
|
+
sage: G == SmoothCharacterGroupQp(3, QQ)
|
|
424
|
+
True
|
|
425
|
+
"""
|
|
426
|
+
if not isinstance(other, SmoothCharacterGroupGeneric):
|
|
427
|
+
return False
|
|
428
|
+
|
|
429
|
+
return (self.prime() == other.prime() and
|
|
430
|
+
self.number_field() == other.number_field() and
|
|
431
|
+
self.base_ring() == other.base_ring())
|
|
432
|
+
|
|
433
|
+
def __ne__(self, other):
|
|
434
|
+
"""
|
|
435
|
+
Check whether ``self`` is not equal to ``other``.
|
|
436
|
+
|
|
437
|
+
EXAMPLES::
|
|
438
|
+
|
|
439
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
440
|
+
sage: G = SmoothCharacterGroupQp(3, QQ)
|
|
441
|
+
sage: G != SmoothCharacterGroupQp(3, QQ[I])
|
|
442
|
+
True
|
|
443
|
+
sage: G != 7
|
|
444
|
+
True
|
|
445
|
+
sage: G != SmoothCharacterGroupQp(7, QQ)
|
|
446
|
+
True
|
|
447
|
+
sage: G != SmoothCharacterGroupQp(3, QQ)
|
|
448
|
+
False
|
|
449
|
+
"""
|
|
450
|
+
return not (self == other)
|
|
451
|
+
|
|
452
|
+
def __hash__(self):
|
|
453
|
+
"""
|
|
454
|
+
Return the hash of ``self``.
|
|
455
|
+
|
|
456
|
+
TESTS::
|
|
457
|
+
|
|
458
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
459
|
+
sage: G = SmoothCharacterGroupQp(3, QQ)
|
|
460
|
+
sage: hash(G) == hash(SmoothCharacterGroupQp(3, QQ[I]))
|
|
461
|
+
False
|
|
462
|
+
sage: hash(G) == hash(SmoothCharacterGroupQp(7, QQ))
|
|
463
|
+
False
|
|
464
|
+
sage: hash(G) == hash(SmoothCharacterGroupQp(3, QQ))
|
|
465
|
+
True
|
|
466
|
+
"""
|
|
467
|
+
return hash((self.prime(), self.number_field(), self.base_ring()))
|
|
468
|
+
|
|
469
|
+
def _coerce_map_from_(self, other):
|
|
470
|
+
r"""
|
|
471
|
+
Return ``True`` if ``self`` has a canonical coerce map from ``other``.
|
|
472
|
+
|
|
473
|
+
EXAMPLES::
|
|
474
|
+
|
|
475
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
476
|
+
sage: K.<i> = QuadraticField(-1)
|
|
477
|
+
sage: G = SmoothCharacterGroupQp(3, QQ)
|
|
478
|
+
sage: GK = SmoothCharacterGroupQp(3, K)
|
|
479
|
+
sage: G.has_coerce_map_from(GK)
|
|
480
|
+
False
|
|
481
|
+
sage: GK.has_coerce_map_from(G)
|
|
482
|
+
True
|
|
483
|
+
sage: GK.coerce(G.character(0, [4]))
|
|
484
|
+
Character of Q_3*, of level 0, mapping 3 |--> 4
|
|
485
|
+
sage: G.coerce(GK.character(0, [4]))
|
|
486
|
+
Traceback (most recent call last):
|
|
487
|
+
...
|
|
488
|
+
TypeError: no canonical coercion from Group of smooth characters of Q_3* with values in Number Field in i with defining polynomial x^2 + 1 with i = 1*I to Group of smooth characters of Q_3* with values in Rational Field
|
|
489
|
+
sage: G.character(0, [4]) in GK # indirect doctest
|
|
490
|
+
True
|
|
491
|
+
|
|
492
|
+
The coercion framework handles base extension, so we test that too::
|
|
493
|
+
|
|
494
|
+
sage: K.<i> = QuadraticField(-1)
|
|
495
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
496
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(3, QQ)
|
|
497
|
+
sage: G.character(0, [1]).base_extend(K)
|
|
498
|
+
Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), of level 0, mapping 3 |--> 1
|
|
499
|
+
"""
|
|
500
|
+
return (isinstance(other, SmoothCharacterGroupGeneric)
|
|
501
|
+
and other.number_field() == self.number_field()
|
|
502
|
+
and self.base_ring().has_coerce_map_from(other.base_ring()))
|
|
503
|
+
|
|
504
|
+
def prime(self):
|
|
505
|
+
r"""
|
|
506
|
+
The residue characteristic of the underlying field.
|
|
507
|
+
|
|
508
|
+
EXAMPLES::
|
|
509
|
+
|
|
510
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
|
|
511
|
+
sage: SmoothCharacterGroupGeneric(3, QQ).prime()
|
|
512
|
+
3
|
|
513
|
+
"""
|
|
514
|
+
return self._p
|
|
515
|
+
|
|
516
|
+
@abstract_method
|
|
517
|
+
def change_ring(self, ring):
|
|
518
|
+
r"""
|
|
519
|
+
Return the character group of the same field, but with values in a
|
|
520
|
+
different coefficient ring. To be implemented by all derived classes
|
|
521
|
+
(since the generic base class can't know the parameters).
|
|
522
|
+
|
|
523
|
+
EXAMPLES::
|
|
524
|
+
|
|
525
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
|
|
526
|
+
sage: SmoothCharacterGroupGeneric(3, QQ).change_ring(ZZ)
|
|
527
|
+
Traceback (most recent call last):
|
|
528
|
+
...
|
|
529
|
+
NotImplementedError: <abstract method change_ring at ...>
|
|
530
|
+
"""
|
|
531
|
+
pass
|
|
532
|
+
|
|
533
|
+
def base_extend(self, ring):
|
|
534
|
+
r"""
|
|
535
|
+
Return the character group of the same field, but with values in a new
|
|
536
|
+
coefficient ring into which the old coefficient ring coerces. An error
|
|
537
|
+
will be raised if there is no coercion map from the old coefficient
|
|
538
|
+
ring to the new one.
|
|
539
|
+
|
|
540
|
+
EXAMPLES::
|
|
541
|
+
|
|
542
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
543
|
+
sage: G = SmoothCharacterGroupQp(3, QQ)
|
|
544
|
+
sage: G.base_extend(QQbar)
|
|
545
|
+
Group of smooth characters of Q_3* with values in Algebraic Field
|
|
546
|
+
sage: G.base_extend(Zmod(3))
|
|
547
|
+
Traceback (most recent call last):
|
|
548
|
+
...
|
|
549
|
+
TypeError: no canonical coercion from Rational Field to Ring of integers modulo 3
|
|
550
|
+
"""
|
|
551
|
+
if not ring.has_coerce_map_from(self.base_ring()):
|
|
552
|
+
ring.coerce(self.base_ring().an_element())
|
|
553
|
+
# this is here to flush out errors
|
|
554
|
+
|
|
555
|
+
return self.change_ring(ring)
|
|
556
|
+
|
|
557
|
+
@abstract_method
|
|
558
|
+
def _field_name(self):
|
|
559
|
+
r"""
|
|
560
|
+
A string representing the name of the `p`-adic field of which this is the
|
|
561
|
+
character group. To be overridden by derived subclasses.
|
|
562
|
+
|
|
563
|
+
EXAMPLES::
|
|
564
|
+
|
|
565
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
|
|
566
|
+
sage: SmoothCharacterGroupGeneric(3, QQ)._field_name()
|
|
567
|
+
Traceback (most recent call last):
|
|
568
|
+
...
|
|
569
|
+
NotImplementedError: <abstract method _field_name at ...>
|
|
570
|
+
"""
|
|
571
|
+
pass
|
|
572
|
+
|
|
573
|
+
def _repr_(self):
|
|
574
|
+
r"""
|
|
575
|
+
String representation of ``self``.
|
|
576
|
+
|
|
577
|
+
EXAMPLES::
|
|
578
|
+
|
|
579
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
580
|
+
sage: SmoothCharacterGroupQp(7, QQ)._repr_()
|
|
581
|
+
'Group of smooth characters of Q_7* with values in Rational Field'
|
|
582
|
+
"""
|
|
583
|
+
return "Group of smooth characters of %s with values in %s" % (self._field_name(), self.base_ring())
|
|
584
|
+
|
|
585
|
+
@abstract_method
|
|
586
|
+
def ideal(self, level):
|
|
587
|
+
r"""
|
|
588
|
+
Return the ``level``-th power of the maximal ideal of the ring of
|
|
589
|
+
integers of the `p`-adic field. Since we approximate by using number
|
|
590
|
+
field arithmetic, what is actually returned is an ideal in a number
|
|
591
|
+
field.
|
|
592
|
+
|
|
593
|
+
EXAMPLES::
|
|
594
|
+
|
|
595
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
|
|
596
|
+
sage: SmoothCharacterGroupGeneric(3, QQ).ideal(3)
|
|
597
|
+
Traceback (most recent call last):
|
|
598
|
+
...
|
|
599
|
+
NotImplementedError: <abstract method ideal at ...>
|
|
600
|
+
"""
|
|
601
|
+
pass
|
|
602
|
+
|
|
603
|
+
@abstract_method
|
|
604
|
+
def unit_gens(self, level):
|
|
605
|
+
r"""
|
|
606
|
+
A list of generators `x_1, \dots, x_d` of the abelian group `F^\times /
|
|
607
|
+
(1 + \mathfrak{p}^c)^\times`, where `c` is the given level, satisfying
|
|
608
|
+
no relations other than `x_i^{n_i} = 1` for each `i` (where the
|
|
609
|
+
integers `n_i` are returned by :meth:`exponents`). We adopt the
|
|
610
|
+
convention that the final generator `x_d` is a uniformiser (and `n_d =
|
|
611
|
+
0`).
|
|
612
|
+
|
|
613
|
+
EXAMPLES::
|
|
614
|
+
|
|
615
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
|
|
616
|
+
sage: SmoothCharacterGroupGeneric(3, QQ).unit_gens(3)
|
|
617
|
+
Traceback (most recent call last):
|
|
618
|
+
...
|
|
619
|
+
NotImplementedError: <abstract method unit_gens at ...>
|
|
620
|
+
"""
|
|
621
|
+
pass
|
|
622
|
+
|
|
623
|
+
@abstract_method
|
|
624
|
+
def exponents(self, level):
|
|
625
|
+
r"""
|
|
626
|
+
The orders `n_1, \dots, n_d` of the generators `x_i` of `F^\times / (1
|
|
627
|
+
+ \mathfrak{p}^c)^\times` returned by :meth:`unit_gens`.
|
|
628
|
+
|
|
629
|
+
EXAMPLES::
|
|
630
|
+
|
|
631
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
|
|
632
|
+
sage: SmoothCharacterGroupGeneric(3, QQ).exponents(3)
|
|
633
|
+
Traceback (most recent call last):
|
|
634
|
+
...
|
|
635
|
+
NotImplementedError: <abstract method exponents at ...>
|
|
636
|
+
"""
|
|
637
|
+
pass
|
|
638
|
+
|
|
639
|
+
@abstract_method
|
|
640
|
+
def subgroup_gens(self, level):
|
|
641
|
+
r"""
|
|
642
|
+
A set of elements of `(\mathcal{O}_F / \mathfrak{p}^c)^\times`
|
|
643
|
+
generating the kernel of the reduction map to `(\mathcal{O}_F /
|
|
644
|
+
\mathfrak{p}^{c-1})^\times`.
|
|
645
|
+
|
|
646
|
+
EXAMPLES::
|
|
647
|
+
|
|
648
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
|
|
649
|
+
sage: SmoothCharacterGroupGeneric(3, QQ).subgroup_gens(3)
|
|
650
|
+
Traceback (most recent call last):
|
|
651
|
+
...
|
|
652
|
+
NotImplementedError: <abstract method subgroup_gens at ...>
|
|
653
|
+
"""
|
|
654
|
+
pass
|
|
655
|
+
|
|
656
|
+
@abstract_method
|
|
657
|
+
def discrete_log(self, level):
|
|
658
|
+
r"""
|
|
659
|
+
Given an element `x \in F^\times` (lying in the number field `K` of
|
|
660
|
+
which `F` is a completion, see module docstring), express the class of
|
|
661
|
+
`x` in terms of the generators of `F^\times / (1 +
|
|
662
|
+
\mathfrak{p}^c)^\times` returned by :meth:`unit_gens`.
|
|
663
|
+
|
|
664
|
+
This should be overridden by all derived classes. The method should
|
|
665
|
+
first attempt to canonically coerce `x` into ``self.number_field()``,
|
|
666
|
+
and check that the result is not zero.
|
|
667
|
+
|
|
668
|
+
EXAMPLES::
|
|
669
|
+
|
|
670
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
|
|
671
|
+
sage: SmoothCharacterGroupGeneric(3, QQ).discrete_log(3)
|
|
672
|
+
Traceback (most recent call last):
|
|
673
|
+
...
|
|
674
|
+
NotImplementedError: <abstract method discrete_log at ...>
|
|
675
|
+
"""
|
|
676
|
+
pass
|
|
677
|
+
|
|
678
|
+
def character(self, level, values_on_gens):
|
|
679
|
+
r"""
|
|
680
|
+
Return the unique character of the given level whose values on the
|
|
681
|
+
generators returned by ``self.unit_gens(level)`` are
|
|
682
|
+
``values_on_gens``.
|
|
683
|
+
|
|
684
|
+
INPUT:
|
|
685
|
+
|
|
686
|
+
- ``level`` -- integer an integer `\ge 0`
|
|
687
|
+
- ``values_on_gens`` -- sequence a sequence of elements of length equal
|
|
688
|
+
to the length of ``self.unit_gens(level)``. The values should be
|
|
689
|
+
convertible (that is, possibly noncanonically) into the base ring of self; they
|
|
690
|
+
should all be units, and all but the last must be roots of unity (of
|
|
691
|
+
the orders given by ``self.exponents(level)``.
|
|
692
|
+
|
|
693
|
+
.. NOTE::
|
|
694
|
+
|
|
695
|
+
The character returned may have level less than ``level`` in general.
|
|
696
|
+
|
|
697
|
+
EXAMPLES::
|
|
698
|
+
|
|
699
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
700
|
+
sage: K.<z> = CyclotomicField(42)
|
|
701
|
+
sage: G = SmoothCharacterGroupQp(7, K)
|
|
702
|
+
sage: G.character(2, [z^6, 8])
|
|
703
|
+
Character of Q_7*, of level 2, mapping 3 |--> z^6, 7 |--> 8
|
|
704
|
+
sage: G.character(2, [z^7, 8])
|
|
705
|
+
Character of Q_7*, of level 1, mapping 3 |--> z^7, 7 |--> 8
|
|
706
|
+
|
|
707
|
+
Non-examples::
|
|
708
|
+
|
|
709
|
+
sage: G.character(1, [z, 1])
|
|
710
|
+
Traceback (most recent call last):
|
|
711
|
+
...
|
|
712
|
+
ValueError: value on generator 3 (=z) should be a root of unity of order 6
|
|
713
|
+
sage: G.character(1, [1, 0])
|
|
714
|
+
Traceback (most recent call last):
|
|
715
|
+
...
|
|
716
|
+
ValueError: value on uniformiser 7 (=0) should be a unit
|
|
717
|
+
|
|
718
|
+
An example with a funky coefficient ring::
|
|
719
|
+
|
|
720
|
+
sage: G = SmoothCharacterGroupQp(7, Zmod(9))
|
|
721
|
+
sage: G.character(1, [2, 2])
|
|
722
|
+
Character of Q_7*, of level 1, mapping 3 |--> 2, 7 |--> 2
|
|
723
|
+
sage: G.character(1, [2, 3])
|
|
724
|
+
Traceback (most recent call last):
|
|
725
|
+
...
|
|
726
|
+
ValueError: value on uniformiser 7 (=3) should be a unit
|
|
727
|
+
|
|
728
|
+
TESTS::
|
|
729
|
+
|
|
730
|
+
sage: G.character(1, [2])
|
|
731
|
+
Traceback (most recent call last):
|
|
732
|
+
...
|
|
733
|
+
AssertionError: 2 images must be given
|
|
734
|
+
"""
|
|
735
|
+
S = Sequence(values_on_gens, universe=self.base_ring(), immutable=True)
|
|
736
|
+
assert len(S) == len(self.unit_gens(level)), "{0} images must be given".format(len(self.unit_gens(level)))
|
|
737
|
+
n = self.exponents(level)
|
|
738
|
+
for i in range(len(S)):
|
|
739
|
+
if n[i] != 0 and not S[i]**n[i] == 1:
|
|
740
|
+
raise ValueError( "value on generator %s (=%s) should be a root of unity of order %s" % (self.unit_gens(level)[i], S[i], n[i]) )
|
|
741
|
+
elif n[i] == 0 and not S[i].is_unit():
|
|
742
|
+
raise ValueError( "value on uniformiser %s (=%s) should be a unit" % (self.unit_gens(level)[i], S[i]) )
|
|
743
|
+
return self.element_class(self, level, S)
|
|
744
|
+
|
|
745
|
+
def norm_character(self):
|
|
746
|
+
r"""
|
|
747
|
+
Return the normalised absolute value character in this group (mapping a
|
|
748
|
+
uniformiser to `1/q` where `q` is the order of the residue field).
|
|
749
|
+
|
|
750
|
+
EXAMPLES::
|
|
751
|
+
|
|
752
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp, SmoothCharacterGroupUnramifiedQuadratic
|
|
753
|
+
sage: SmoothCharacterGroupQp(5, QQ).norm_character()
|
|
754
|
+
Character of Q_5*, of level 0, mapping 5 |--> 1/5
|
|
755
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).norm_character()
|
|
756
|
+
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 0, mapping 2 |--> 1/4
|
|
757
|
+
"""
|
|
758
|
+
return self.character(0, [1/self.ideal(1).residue_field().cardinality()])
|
|
759
|
+
|
|
760
|
+
def _an_element_(self):
|
|
761
|
+
r"""
|
|
762
|
+
Return an element of this group. Required by the coercion machinery.
|
|
763
|
+
|
|
764
|
+
EXAMPLES::
|
|
765
|
+
|
|
766
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
767
|
+
sage: K.<z> = CyclotomicField(42)
|
|
768
|
+
sage: G = SmoothCharacterGroupQp(7, K)
|
|
769
|
+
sage: G.an_element() # indirect doctest
|
|
770
|
+
Character of Q_7*, of level 0, mapping 7 |--> z
|
|
771
|
+
"""
|
|
772
|
+
return self.character(0, [self.base_ring().an_element()])
|
|
773
|
+
|
|
774
|
+
def _test_unitgens(self, **options):
|
|
775
|
+
r"""
|
|
776
|
+
Test that the generators returned by ``unit_gens`` are consistent with
|
|
777
|
+
the exponents returned by ``exponents``.
|
|
778
|
+
|
|
779
|
+
EXAMPLES::
|
|
780
|
+
|
|
781
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
782
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(2, Zmod(8))._test_unitgens()
|
|
783
|
+
"""
|
|
784
|
+
T = self._tester(**options)
|
|
785
|
+
for c in range(6):
|
|
786
|
+
gens = self.unit_gens(c)
|
|
787
|
+
exps = self.exponents(c)
|
|
788
|
+
T.assertEqual(exps[-1], 0)
|
|
789
|
+
T.assertTrue(all(u != 0 for u in exps[:-1]))
|
|
790
|
+
T.assertTrue(all(u.parent() is self.number_field() for u in gens))
|
|
791
|
+
|
|
792
|
+
I = self.ideal(c)
|
|
793
|
+
for i in range(len(exps[:-1])):
|
|
794
|
+
g = gens[i]
|
|
795
|
+
for m in range(1, exps[i]):
|
|
796
|
+
if (g - 1 in I):
|
|
797
|
+
T.fail("For generator g=%s, g^%s = %s = 1 mod I, but order should be %s" % (gens[i], m, g, exps[i]))
|
|
798
|
+
g = g * gens[i]
|
|
799
|
+
# reduce g mod I
|
|
800
|
+
if hasattr(I, "small_residue"):
|
|
801
|
+
g = I.small_residue(g)
|
|
802
|
+
else: # I is an ideal of ZZ
|
|
803
|
+
g = g % (I.gen())
|
|
804
|
+
if g - 1 not in I:
|
|
805
|
+
T.fail("For generator g=%s, g^%s = %s, which is not 1 mod I" % (gens[i], exps[i], g))
|
|
806
|
+
I = self.prime() if self.number_field() == QQ else self.ideal(1)
|
|
807
|
+
T.assertEqual(gens[-1].valuation(I), 1)
|
|
808
|
+
|
|
809
|
+
# This implicitly tests that the gens really are gens!
|
|
810
|
+
self.discrete_log(c, -1)
|
|
811
|
+
|
|
812
|
+
def _test_subgroupgens(self, **options):
|
|
813
|
+
r"""
|
|
814
|
+
Test that the values returned by :meth:`~subgroup_gens` are valid.
|
|
815
|
+
|
|
816
|
+
EXAMPLES::
|
|
817
|
+
|
|
818
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
819
|
+
sage: SmoothCharacterGroupQp(2, CC)._test_subgroupgens()
|
|
820
|
+
"""
|
|
821
|
+
T = self._tester(**options)
|
|
822
|
+
for c in range(1, 6):
|
|
823
|
+
sgs = self.subgroup_gens(c)
|
|
824
|
+
I2 = self.ideal(c - 1)
|
|
825
|
+
T.assertTrue(all(x - 1 in I2 for x in sgs), "Kernel gens at level %s not in kernel!" % c)
|
|
826
|
+
|
|
827
|
+
# now find the exponent of the kernel
|
|
828
|
+
|
|
829
|
+
n1 = prod(self.exponents(c)[:-1])
|
|
830
|
+
n2 = prod(self.exponents(c - 1)[:-1])
|
|
831
|
+
n = n1 // n2
|
|
832
|
+
# if c > 1, n will be a prime here, so that logs below gets calculated correctly
|
|
833
|
+
|
|
834
|
+
logs = []
|
|
835
|
+
for idx in xmrange(len(sgs)*[n]):
|
|
836
|
+
y = prod( map(operator.pow, sgs, idx) )
|
|
837
|
+
L = tuple(self.discrete_log(c, y))
|
|
838
|
+
if L not in logs:
|
|
839
|
+
logs.append(L)
|
|
840
|
+
T.assertEqual(n2 * len(logs), n1, "Kernel gens at level %s don't generate everything!" % c)
|
|
841
|
+
|
|
842
|
+
def compose_with_norm(self, chi):
|
|
843
|
+
r"""
|
|
844
|
+
Calculate the character of `K^\times` given by `\chi \circ \mathrm{Norm}_{K/\QQ_p}`.
|
|
845
|
+
Here `K` should be a quadratic extension and `\chi` a character of `\QQ_p^\times`.
|
|
846
|
+
|
|
847
|
+
EXAMPLES:
|
|
848
|
+
|
|
849
|
+
When `K` is the unramified quadratic extension, the level of the new character is the same as the old::
|
|
850
|
+
|
|
851
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp, SmoothCharacterGroupRamifiedQuadratic, SmoothCharacterGroupUnramifiedQuadratic
|
|
852
|
+
sage: K.<w> = CyclotomicField(6)
|
|
853
|
+
sage: G = SmoothCharacterGroupQp(3, K)
|
|
854
|
+
sage: chi = G.character(2, [w, 5])
|
|
855
|
+
sage: H = SmoothCharacterGroupUnramifiedQuadratic(3, K)
|
|
856
|
+
sage: H.compose_with_norm(chi)
|
|
857
|
+
Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), of level 2, mapping -2*s |--> -1, 4 |--> -w, 3*s + 1 |--> w - 1, 3 |--> 25
|
|
858
|
+
|
|
859
|
+
In ramified cases, the level of the new character may be larger:
|
|
860
|
+
|
|
861
|
+
.. link
|
|
862
|
+
|
|
863
|
+
::
|
|
864
|
+
|
|
865
|
+
sage: H = SmoothCharacterGroupRamifiedQuadratic(3, 0, K)
|
|
866
|
+
sage: H.compose_with_norm(chi)
|
|
867
|
+
Character of ramified extension Q_3(s)* (s^2 - 3 = 0), of level 3, mapping 2 |--> w - 1, s + 1 |--> -w, s |--> -5
|
|
868
|
+
|
|
869
|
+
On the other hand, since norm is not surjective, the result can even be trivial:
|
|
870
|
+
|
|
871
|
+
.. link
|
|
872
|
+
|
|
873
|
+
::
|
|
874
|
+
|
|
875
|
+
sage: chi = G.character(1, [-1, -1]); chi
|
|
876
|
+
Character of Q_3*, of level 1, mapping 2 |--> -1, 3 |--> -1
|
|
877
|
+
sage: H.compose_with_norm(chi)
|
|
878
|
+
Character of ramified extension Q_3(s)* (s^2 - 3 = 0), of level 0, mapping s |--> 1
|
|
879
|
+
"""
|
|
880
|
+
if chi.parent().number_field() != QQ:
|
|
881
|
+
raise ValueError
|
|
882
|
+
if self.number_field().absolute_degree() != 2:
|
|
883
|
+
raise ValueError
|
|
884
|
+
n = chi.level()
|
|
885
|
+
P = chi.parent().prime() ** n
|
|
886
|
+
m = self.number_field()(P).valuation(self.ideal(1))
|
|
887
|
+
return self.character(m, [chi(x.norm(QQ)) for x in self.unit_gens(m)])
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
class SmoothCharacterGroupQp(SmoothCharacterGroupGeneric):
|
|
891
|
+
r"""
|
|
892
|
+
The group of smooth characters of `\QQ_p^\times`, with values in some fixed
|
|
893
|
+
base ring.
|
|
894
|
+
|
|
895
|
+
EXAMPLES::
|
|
896
|
+
|
|
897
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
898
|
+
sage: G = SmoothCharacterGroupQp(7, QQ); G
|
|
899
|
+
Group of smooth characters of Q_7* with values in Rational Field
|
|
900
|
+
sage: TestSuite(G).run()
|
|
901
|
+
sage: G == loads(dumps(G))
|
|
902
|
+
True
|
|
903
|
+
"""
|
|
904
|
+
def unit_gens(self, level):
|
|
905
|
+
r"""
|
|
906
|
+
Return a set of generators `x_1, \dots, x_d` for `\QQ_p^\times / (1 +
|
|
907
|
+
p^c \ZZ_p)^\times`. These must be independent in the sense that there
|
|
908
|
+
are no relations between them other than relations of the form
|
|
909
|
+
`x_i^{n_i} = 1`. They need not, however, be in Smith normal form.
|
|
910
|
+
|
|
911
|
+
EXAMPLES::
|
|
912
|
+
|
|
913
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
914
|
+
sage: SmoothCharacterGroupQp(7, QQ).unit_gens(3)
|
|
915
|
+
[3, 7]
|
|
916
|
+
sage: SmoothCharacterGroupQp(2, QQ).unit_gens(4)
|
|
917
|
+
[15, 5, 2]
|
|
918
|
+
"""
|
|
919
|
+
if level == 0:
|
|
920
|
+
return [QQ(self.prime())]
|
|
921
|
+
else:
|
|
922
|
+
return [QQ(x) for x in Zmod(self.prime()**level).unit_gens()] + [QQ(self.prime())]
|
|
923
|
+
|
|
924
|
+
def exponents(self, level):
|
|
925
|
+
r"""
|
|
926
|
+
Return the exponents of the generators returned by :meth:`unit_gens`.
|
|
927
|
+
|
|
928
|
+
EXAMPLES::
|
|
929
|
+
|
|
930
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
931
|
+
sage: SmoothCharacterGroupQp(7, QQ).exponents(3)
|
|
932
|
+
[294, 0]
|
|
933
|
+
sage: SmoothCharacterGroupQp(2, QQ).exponents(4)
|
|
934
|
+
[2, 4, 0]
|
|
935
|
+
"""
|
|
936
|
+
if level == 0:
|
|
937
|
+
return [0]
|
|
938
|
+
return [x.multiplicative_order() for x in Zmod(self.prime()**level).unit_gens()] + [0]
|
|
939
|
+
|
|
940
|
+
def change_ring(self, ring):
|
|
941
|
+
r"""
|
|
942
|
+
Return the group of characters of the same field but with values in a
|
|
943
|
+
different ring. This need not have anything to do with the original
|
|
944
|
+
base ring, and in particular there won't generally be a coercion map
|
|
945
|
+
from ``self`` to the new group -- use
|
|
946
|
+
:meth:`~SmoothCharacterGroupGeneric.base_extend` if you want this.
|
|
947
|
+
|
|
948
|
+
EXAMPLES::
|
|
949
|
+
|
|
950
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
951
|
+
sage: SmoothCharacterGroupQp(7, Zmod(3)).change_ring(CC)
|
|
952
|
+
Group of smooth characters of Q_7* with values in Complex Field with 53 bits of precision
|
|
953
|
+
"""
|
|
954
|
+
return SmoothCharacterGroupQp(self.prime(), ring)
|
|
955
|
+
|
|
956
|
+
def number_field(self):
|
|
957
|
+
r"""
|
|
958
|
+
Return the number field used for calculations (a dense subfield of the
|
|
959
|
+
local field of which this is the character group). In this case, this
|
|
960
|
+
is always the rational field.
|
|
961
|
+
|
|
962
|
+
EXAMPLES::
|
|
963
|
+
|
|
964
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
965
|
+
sage: SmoothCharacterGroupQp(7, Zmod(3)).number_field()
|
|
966
|
+
Rational Field
|
|
967
|
+
"""
|
|
968
|
+
return QQ
|
|
969
|
+
|
|
970
|
+
def ideal(self, level):
|
|
971
|
+
r"""
|
|
972
|
+
Return the ``level``-th power of the maximal ideal. Since we
|
|
973
|
+
approximate by using rational arithmetic, what is actually returned is
|
|
974
|
+
an ideal of `\ZZ`.
|
|
975
|
+
|
|
976
|
+
EXAMPLES::
|
|
977
|
+
|
|
978
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
979
|
+
sage: SmoothCharacterGroupQp(7, Zmod(3)).ideal(2)
|
|
980
|
+
Principal ideal (49) of Integer Ring
|
|
981
|
+
"""
|
|
982
|
+
return ZZ.ideal(self.prime() ** level)
|
|
983
|
+
|
|
984
|
+
def _field_name(self):
|
|
985
|
+
r"""
|
|
986
|
+
Return a string representation of the field unit group of which this is
|
|
987
|
+
the character group.
|
|
988
|
+
|
|
989
|
+
EXAMPLES::
|
|
990
|
+
|
|
991
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
992
|
+
sage: SmoothCharacterGroupQp(7, Zmod(3))._field_name()
|
|
993
|
+
'Q_7*'
|
|
994
|
+
"""
|
|
995
|
+
return "Q_%s*" % self.prime()
|
|
996
|
+
|
|
997
|
+
def discrete_log(self, level, x):
|
|
998
|
+
r"""
|
|
999
|
+
Express the class of `x` in `\QQ_p^\times / (1 + p^c)^\times` in terms
|
|
1000
|
+
of the generators returned by :meth:`unit_gens`.
|
|
1001
|
+
|
|
1002
|
+
EXAMPLES::
|
|
1003
|
+
|
|
1004
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
1005
|
+
sage: G = SmoothCharacterGroupQp(7, QQ)
|
|
1006
|
+
sage: G.discrete_log(0, 14)
|
|
1007
|
+
[1]
|
|
1008
|
+
sage: G.discrete_log(1, 14)
|
|
1009
|
+
[2, 1]
|
|
1010
|
+
sage: G.discrete_log(5, 14)
|
|
1011
|
+
[9308, 1]
|
|
1012
|
+
"""
|
|
1013
|
+
x = self.number_field().coerce(x)
|
|
1014
|
+
if x == 0:
|
|
1015
|
+
raise ValueError( "cannot evaluate at zero" )
|
|
1016
|
+
s = x.valuation(self.prime())
|
|
1017
|
+
return Zmod(self.prime()**level)(x / self.prime()**s).generalised_log() + [s]
|
|
1018
|
+
|
|
1019
|
+
def subgroup_gens(self, level):
|
|
1020
|
+
r"""
|
|
1021
|
+
Return a list of generators for the kernel of the map `(\ZZ_p / p^c)^\times
|
|
1022
|
+
\to (\ZZ_p / p^{c-1})^\times`.
|
|
1023
|
+
|
|
1024
|
+
INPUT:
|
|
1025
|
+
|
|
1026
|
+
- ``c`` -- integer `\ge 1`
|
|
1027
|
+
|
|
1028
|
+
EXAMPLES::
|
|
1029
|
+
|
|
1030
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
1031
|
+
sage: G = SmoothCharacterGroupQp(7, QQ)
|
|
1032
|
+
sage: G.subgroup_gens(1)
|
|
1033
|
+
[3]
|
|
1034
|
+
sage: G.subgroup_gens(2)
|
|
1035
|
+
[8]
|
|
1036
|
+
|
|
1037
|
+
sage: G = SmoothCharacterGroupQp(2, QQ)
|
|
1038
|
+
sage: G.subgroup_gens(1)
|
|
1039
|
+
[]
|
|
1040
|
+
sage: G.subgroup_gens(2)
|
|
1041
|
+
[3]
|
|
1042
|
+
sage: G.subgroup_gens(3)
|
|
1043
|
+
[5]
|
|
1044
|
+
"""
|
|
1045
|
+
if level == 0:
|
|
1046
|
+
raise ValueError
|
|
1047
|
+
elif level == 1:
|
|
1048
|
+
return self.unit_gens(level)[:-1]
|
|
1049
|
+
else:
|
|
1050
|
+
return [1 + self.prime()**(level - 1)]
|
|
1051
|
+
|
|
1052
|
+
def from_dirichlet(self, chi):
|
|
1053
|
+
r"""
|
|
1054
|
+
Given a Dirichlet character `\chi`, return the factor at p of the
|
|
1055
|
+
adelic character `\phi` which satisfies `\phi(\varpi_\ell) =
|
|
1056
|
+
\chi(\ell)` for almost all `\ell`, where `\varpi_\ell` is a uniformizer
|
|
1057
|
+
at `\ell`.
|
|
1058
|
+
|
|
1059
|
+
More concretely, if we write `\chi = \chi_p \chi_M` as a product of
|
|
1060
|
+
characters of p-power, resp prime-to-p, conductor, then this function
|
|
1061
|
+
returns the character of `\QQ_p^\times` sending `p` to `\chi_M(p)` and
|
|
1062
|
+
agreeing with `\chi_p^{-1}` on integers that are 1 modulo M and coprime
|
|
1063
|
+
to `p`.
|
|
1064
|
+
|
|
1065
|
+
EXAMPLES::
|
|
1066
|
+
|
|
1067
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
1068
|
+
sage: G = SmoothCharacterGroupQp(3, CyclotomicField(6))
|
|
1069
|
+
sage: G.from_dirichlet(DirichletGroup(9).0)
|
|
1070
|
+
Character of Q_3*, of level 2, mapping 2 |--> -zeta6 + 1, 3 |--> 1
|
|
1071
|
+
"""
|
|
1072
|
+
p = self.prime()
|
|
1073
|
+
chi = chi.primitive_character()
|
|
1074
|
+
c = chi.level().valuation(p)
|
|
1075
|
+
M = chi.level().prime_to_m_part(p)
|
|
1076
|
+
return self.character(chi.conductor().valuation(p), [~chi(crt(1, x, M, p**c)) for x in self.unit_gens(c)[:-1]] + [chi(crt(p, 1, M, p**c))])
|
|
1077
|
+
|
|
1078
|
+
def quadratic_chars(self):
|
|
1079
|
+
r"""
|
|
1080
|
+
Return a list of the (non-trivial) quadratic characters in this group.
|
|
1081
|
+
This will be a list of 3 characters, unless `p = 2` when there are 7.
|
|
1082
|
+
|
|
1083
|
+
EXAMPLES::
|
|
1084
|
+
|
|
1085
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
|
|
1086
|
+
sage: SmoothCharacterGroupQp(7, QQ).quadratic_chars()
|
|
1087
|
+
[Character of Q_7*, of level 0, mapping 7 |--> -1,
|
|
1088
|
+
Character of Q_7*, of level 1, mapping 3 |--> -1, 7 |--> -1,
|
|
1089
|
+
Character of Q_7*, of level 1, mapping 3 |--> -1, 7 |--> 1]
|
|
1090
|
+
sage: SmoothCharacterGroupQp(2, QQ).quadratic_chars()
|
|
1091
|
+
[Character of Q_2*, of level 0, mapping 2 |--> -1,
|
|
1092
|
+
Character of Q_2*, of level 2, mapping 3 |--> -1, 2 |--> -1,
|
|
1093
|
+
Character of Q_2*, of level 2, mapping 3 |--> -1, 2 |--> 1,
|
|
1094
|
+
Character of Q_2*, of level 3, mapping 7 |--> -1, 5 |--> -1, 2 |--> -1,
|
|
1095
|
+
Character of Q_2*, of level 3, mapping 7 |--> -1, 5 |--> -1, 2 |--> 1,
|
|
1096
|
+
Character of Q_2*, of level 3, mapping 7 |--> 1, 5 |--> -1, 2 |--> -1,
|
|
1097
|
+
Character of Q_2*, of level 3, mapping 7 |--> 1, 5 |--> -1, 2 |--> 1]
|
|
1098
|
+
"""
|
|
1099
|
+
if self.prime() == 2:
|
|
1100
|
+
q = 3
|
|
1101
|
+
else:
|
|
1102
|
+
q = 1
|
|
1103
|
+
ram = [self.from_dirichlet(chi) for chi in DirichletGroup(self.prime() ** q, QQ) if not chi.is_trivial()]
|
|
1104
|
+
nr = self.character(0, [-1])
|
|
1105
|
+
return sorted([nr] + list(ram) + [f*nr for f in ram])
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
class SmoothCharacterGroupQuadratic(SmoothCharacterGroupGeneric):
|
|
1109
|
+
r"""
|
|
1110
|
+
The group of smooth characters of `E^\times`, where `E` is a quadratic extension of `\QQ_p`.
|
|
1111
|
+
"""
|
|
1112
|
+
|
|
1113
|
+
def discrete_log(self, level, x, gens=None):
|
|
1114
|
+
r"""
|
|
1115
|
+
Express the class of `x` in `F^\times / (1 + \mathfrak{p}^c)^\times` in
|
|
1116
|
+
terms of the generators returned by ``self.unit_gens(level)``, or a
|
|
1117
|
+
custom set of generators if given.
|
|
1118
|
+
|
|
1119
|
+
EXAMPLES::
|
|
1120
|
+
|
|
1121
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1122
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(2, QQ)
|
|
1123
|
+
sage: G.discrete_log(0, 12)
|
|
1124
|
+
[2]
|
|
1125
|
+
sage: G.discrete_log(1, 12)
|
|
1126
|
+
[0, 2]
|
|
1127
|
+
sage: v = G.discrete_log(5, 12); v
|
|
1128
|
+
[0, 2, 0, 1, 2]
|
|
1129
|
+
sage: g = G.unit_gens(5); prod([g[i]**v[i] for i in [0..4]])/12 - 1 in G.ideal(5)
|
|
1130
|
+
True
|
|
1131
|
+
sage: G.discrete_log(3,G.number_field()([1,1]))
|
|
1132
|
+
[2, 0, 0, 1, 0]
|
|
1133
|
+
sage: H = SmoothCharacterGroupUnramifiedQuadratic(5, QQ)
|
|
1134
|
+
sage: x = H.number_field()([1,1]); x
|
|
1135
|
+
s + 1
|
|
1136
|
+
sage: v = H.discrete_log(5, x); v
|
|
1137
|
+
[22, 263, 379, 0]
|
|
1138
|
+
sage: h = H.unit_gens(5); prod([h[i]**v[i] for i in [0..3]])/x - 1 in H.ideal(5)
|
|
1139
|
+
True
|
|
1140
|
+
|
|
1141
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
|
|
1142
|
+
sage: G = SmoothCharacterGroupRamifiedQuadratic(3, 1, QQ)
|
|
1143
|
+
sage: s = G.number_field().gen()
|
|
1144
|
+
sage: dl = G.discrete_log(4, 3 + 2*s)
|
|
1145
|
+
sage: gs = G.unit_gens(4); gs[0]^dl[0] * gs[1]^dl[1] * gs[2]^dl[2] * gs[3]^dl[3] - (3 + 2*s) in G.ideal(4)
|
|
1146
|
+
True
|
|
1147
|
+
|
|
1148
|
+
An example with a custom generating set::
|
|
1149
|
+
|
|
1150
|
+
sage: G.discrete_log(2, s+3, gens=[s, s+1, 2])
|
|
1151
|
+
[1, 2, 0]
|
|
1152
|
+
"""
|
|
1153
|
+
x = self.number_field().coerce(x)
|
|
1154
|
+
if x == 0:
|
|
1155
|
+
raise ValueError( "cannot evaluate at zero" )
|
|
1156
|
+
if gens is None:
|
|
1157
|
+
n1 = x.valuation(self.ideal(1))
|
|
1158
|
+
x1 = x / self.unit_gens(0)[-1] ** n1
|
|
1159
|
+
if level == 0:
|
|
1160
|
+
return [n1]
|
|
1161
|
+
else:
|
|
1162
|
+
return self.ideal(level).ideallog(x1, self.unit_gens(level)[:-1]) + [n1]
|
|
1163
|
+
else:
|
|
1164
|
+
P = self.ideal(1)
|
|
1165
|
+
I = self.ideal(level)
|
|
1166
|
+
gens = [self.number_field().coerce(g) for g in gens]
|
|
1167
|
+
i = min(i for i in range(len(gens)) if gens[i].valuation(P) == 1) # lazy!
|
|
1168
|
+
pi = gens[i]
|
|
1169
|
+
genvals = []
|
|
1170
|
+
genunits = []
|
|
1171
|
+
for g in gens:
|
|
1172
|
+
genvals.append(g.valuation(P))
|
|
1173
|
+
gu = g / pi**genvals[-1]
|
|
1174
|
+
gu *= gu.denominator_ideal().element_1_mod(I)
|
|
1175
|
+
genunits.append(I.reduce(gu))
|
|
1176
|
+
xunit = x / pi**x.valuation(P)
|
|
1177
|
+
xunit = I.reduce(xunit * xunit.denominator_ideal().element_1_mod(I))
|
|
1178
|
+
verbose("computing log of %s in basis %s" % (xunit, genunits), level=1)
|
|
1179
|
+
dl = I.ideallog(xunit, genunits)
|
|
1180
|
+
pi_term = x.valuation(P) - sum(dl[j] * genvals[j] for j in range(len(gens)))
|
|
1181
|
+
dl[i] += pi_term
|
|
1182
|
+
X = prod(gens[j] ** dl[j] for j in range(len(gens)))
|
|
1183
|
+
assert (X/x - 1).valuation(P) >= level
|
|
1184
|
+
return dl
|
|
1185
|
+
|
|
1186
|
+
@cached_method
|
|
1187
|
+
def quotient_gens(self, n):
|
|
1188
|
+
r"""
|
|
1189
|
+
Return a list of elements of `E` which are a generating set for the
|
|
1190
|
+
quotient `E^\times / \QQ_p^\times`, consisting of elements which are
|
|
1191
|
+
"minimal" in the sense of [LW12].
|
|
1192
|
+
|
|
1193
|
+
In the examples we implement here, this quotient is almost always
|
|
1194
|
+
cyclic: the exceptions are the unramified quadratic extension of
|
|
1195
|
+
`\QQ_2` for `n \ge 3`, and the extension `\QQ_3(\sqrt{-3})` for `n \ge
|
|
1196
|
+
4`.
|
|
1197
|
+
|
|
1198
|
+
EXAMPLES::
|
|
1199
|
+
|
|
1200
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1201
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(7,QQ)
|
|
1202
|
+
sage: G.quotient_gens(1)
|
|
1203
|
+
[2*s - 2]
|
|
1204
|
+
sage: G.quotient_gens(2)
|
|
1205
|
+
[15*s + 21]
|
|
1206
|
+
sage: G.quotient_gens(3)
|
|
1207
|
+
[-75*s + 33]
|
|
1208
|
+
|
|
1209
|
+
A ramified case::
|
|
1210
|
+
|
|
1211
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
|
|
1212
|
+
sage: G = SmoothCharacterGroupRamifiedQuadratic(7, 0, QQ)
|
|
1213
|
+
sage: G.quotient_gens(3)
|
|
1214
|
+
[22*s + 21]
|
|
1215
|
+
|
|
1216
|
+
An example where the quotient group is not cyclic::
|
|
1217
|
+
|
|
1218
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(2,QQ)
|
|
1219
|
+
sage: G.quotient_gens(1)
|
|
1220
|
+
[s + 1]
|
|
1221
|
+
sage: G.quotient_gens(2)
|
|
1222
|
+
[-s + 2]
|
|
1223
|
+
sage: G.quotient_gens(3)
|
|
1224
|
+
[-17*s - 14, 3*s - 2]
|
|
1225
|
+
"""
|
|
1226
|
+
|
|
1227
|
+
# silly special case
|
|
1228
|
+
if n == 0:
|
|
1229
|
+
if self.ideal(1).norm().is_prime():
|
|
1230
|
+
return [self.unit_gens(0), [2]]
|
|
1231
|
+
else:
|
|
1232
|
+
return [[], []]
|
|
1233
|
+
|
|
1234
|
+
p = self.prime()
|
|
1235
|
+
I = self.ideal(n)
|
|
1236
|
+
gs = self.unit_gens(n)
|
|
1237
|
+
es = self.exponents(n)
|
|
1238
|
+
d = len(es)
|
|
1239
|
+
|
|
1240
|
+
A = ZZ**d
|
|
1241
|
+
R = [A.gen(i)*es[i] for i in range(d)]
|
|
1242
|
+
r = I.smallest_integer()
|
|
1243
|
+
S = [self.discrete_log(n, ZZ(s)) for s in Zmod(r).unit_gens() + (p,)]
|
|
1244
|
+
Q = A / A.span(R + S)
|
|
1245
|
+
t = None
|
|
1246
|
+
qgs = []
|
|
1247
|
+
for v in Q.gens():
|
|
1248
|
+
# choose a "nice" representative
|
|
1249
|
+
vv = v.lift()
|
|
1250
|
+
if vv[-1] < 0:
|
|
1251
|
+
vv *= -1
|
|
1252
|
+
while vv[-1] not in [0, 1]:
|
|
1253
|
+
if t is None:
|
|
1254
|
+
t = self.discrete_log(n, p)
|
|
1255
|
+
vv = [vv[i] - t[i] for i in range(d)]
|
|
1256
|
+
assert (Q(A(vv)) == v or Q(A(vv)) == -v)
|
|
1257
|
+
qgs.append( I.reduce(prod(gs[i] ** (vv[i] % es[i]) for i in range(d-1))) * gs[-1]**vv[-1] )
|
|
1258
|
+
|
|
1259
|
+
if len(qgs) == 2:
|
|
1260
|
+
x, y = qgs
|
|
1261
|
+
return [x * y, y]
|
|
1262
|
+
else:
|
|
1263
|
+
return qgs
|
|
1264
|
+
|
|
1265
|
+
def _reduce_Qp(self, level, x):
|
|
1266
|
+
r"""
|
|
1267
|
+
Utility function: given an element `x` of the number field of self,
|
|
1268
|
+
return an element of `\QQ_p^\times` which is congruent to `x` modulo a
|
|
1269
|
+
given power of the maximal ideal. An error will be raised if no such
|
|
1270
|
+
element exists.
|
|
1271
|
+
|
|
1272
|
+
EXAMPLES::
|
|
1273
|
+
|
|
1274
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1275
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(2, QQ)
|
|
1276
|
+
sage: s = G.number_field().gen()
|
|
1277
|
+
sage: G._reduce_Qp(3, -2520*s-1007)
|
|
1278
|
+
9
|
|
1279
|
+
sage: G._reduce_Qp(3, s)
|
|
1280
|
+
Traceback (most recent call last):
|
|
1281
|
+
...
|
|
1282
|
+
ValueError: s not congruent mod Fractional ideal (8) to an elt of Qp
|
|
1283
|
+
"""
|
|
1284
|
+
p = self.prime()
|
|
1285
|
+
r = ZZ(x.norm().valuation(p) / 2)
|
|
1286
|
+
y = x / p**r
|
|
1287
|
+
if p == 2 and y.trace().valuation(2) < 1:
|
|
1288
|
+
raise ValueError("%s not congruent mod %s to an elt of Qp" % (x, self.ideal(level)))
|
|
1289
|
+
Y = (y.trace() / 2) % self.ideal(level).smallest_integer()
|
|
1290
|
+
X = p**r * Y
|
|
1291
|
+
if not (X/x - 1).valuation(self.ideal(1)) >= level:
|
|
1292
|
+
if p != 2:
|
|
1293
|
+
raise ValueError("%s not congruent mod %s to an elt of Qp" % (x, self.ideal(level)))
|
|
1294
|
+
else:
|
|
1295
|
+
X += ZZ(2)**(r + level - 1)
|
|
1296
|
+
if not (X/x - 1).valuation(self.ideal(1)) >= level:
|
|
1297
|
+
raise ValueError("%s not congruent mod %s to an elt of Qp" % (x, self.ideal(level)))
|
|
1298
|
+
return X
|
|
1299
|
+
|
|
1300
|
+
def extend_character(self, level, chi, vals, check=True):
|
|
1301
|
+
r"""
|
|
1302
|
+
Return the unique character of `F^\times` which coincides with `\chi`
|
|
1303
|
+
on `\QQ_p^\times` and maps the generators of the quotient returned by
|
|
1304
|
+
:meth:`quotient_gens` to ``vals``.
|
|
1305
|
+
|
|
1306
|
+
INPUT:
|
|
1307
|
+
|
|
1308
|
+
- ``chi`` -- a smooth character of `\QQ_p`, where `p` is the residue
|
|
1309
|
+
characteristic of `F`, with values in the base ring of ``self`` (or some
|
|
1310
|
+
other ring coercible to it)
|
|
1311
|
+
- ``level`` -- the level of the new character (which should be at least
|
|
1312
|
+
the level of ``chi``)
|
|
1313
|
+
- ``vals`` -- a list of elements of the base ring of ``self`` (or some other
|
|
1314
|
+
ring coercible to it), specifying values on the quotients returned by
|
|
1315
|
+
:meth:`quotient_gens`
|
|
1316
|
+
|
|
1317
|
+
A :exc:`ValueError` will be raised if `x^t \ne \chi(\alpha^t)`, where `t`
|
|
1318
|
+
is the smallest integer such that `\alpha^t` is congruent modulo
|
|
1319
|
+
`p^{\rm level}` to an element of `\QQ_p`.
|
|
1320
|
+
|
|
1321
|
+
EXAMPLES:
|
|
1322
|
+
|
|
1323
|
+
We extend an unramified character of `\QQ_3^\times` to the unramified
|
|
1324
|
+
quadratic extension in various ways.
|
|
1325
|
+
|
|
1326
|
+
::
|
|
1327
|
+
|
|
1328
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp, SmoothCharacterGroupUnramifiedQuadratic
|
|
1329
|
+
sage: chi = SmoothCharacterGroupQp(5, QQ).character(0, [7]); chi
|
|
1330
|
+
Character of Q_5*, of level 0, mapping 5 |--> 7
|
|
1331
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(5, QQ)
|
|
1332
|
+
sage: G.extend_character(1, chi, [-1])
|
|
1333
|
+
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -1, 5 |--> 7
|
|
1334
|
+
sage: G.extend_character(2, chi, [-1])
|
|
1335
|
+
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -1, 5 |--> 7
|
|
1336
|
+
sage: G.extend_character(3, chi, [1])
|
|
1337
|
+
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 0, mapping 5 |--> 7
|
|
1338
|
+
sage: K.<z> = CyclotomicField(6); G.base_extend(K).extend_character(1, chi, [z])
|
|
1339
|
+
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -z + 1, 5 |--> 7
|
|
1340
|
+
|
|
1341
|
+
We extend the nontrivial quadratic character::
|
|
1342
|
+
|
|
1343
|
+
sage: chi = SmoothCharacterGroupQp(5, QQ).character(1, [-1, 7])
|
|
1344
|
+
sage: K.<z> = CyclotomicField(24); G.base_extend(K).extend_character(1, chi, [z^6])
|
|
1345
|
+
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -z^6, 5 |--> 7
|
|
1346
|
+
|
|
1347
|
+
Extensions of higher level::
|
|
1348
|
+
|
|
1349
|
+
sage: K.<z> = CyclotomicField(20); rho = G.base_extend(K).extend_character(2, chi, [z]); rho
|
|
1350
|
+
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 2, mapping 11*s - 10 |--> z^5, 6 |--> 1, 5*s + 1 |--> z^4, 5 |--> 7
|
|
1351
|
+
sage: rho(3)
|
|
1352
|
+
-1
|
|
1353
|
+
|
|
1354
|
+
Examples where it doesn't work::
|
|
1355
|
+
|
|
1356
|
+
sage: G.extend_character(1, chi, [1])
|
|
1357
|
+
Traceback (most recent call last):
|
|
1358
|
+
...
|
|
1359
|
+
ValueError: Invalid values for extension
|
|
1360
|
+
|
|
1361
|
+
sage: G = SmoothCharacterGroupQp(2, QQ); H = SmoothCharacterGroupUnramifiedQuadratic(2, QQ)
|
|
1362
|
+
sage: chi = G.character(3, [1, -1, 7])
|
|
1363
|
+
sage: H.extend_character(2, chi, [-1])
|
|
1364
|
+
Traceback (most recent call last):
|
|
1365
|
+
...
|
|
1366
|
+
ValueError: Level of extended character cannot be smaller than level of character of Qp
|
|
1367
|
+
"""
|
|
1368
|
+
chi = chi.base_extend(self.base_ring())
|
|
1369
|
+
|
|
1370
|
+
qs = self.quotient_gens(level)
|
|
1371
|
+
assert len(vals) == len(qs)
|
|
1372
|
+
|
|
1373
|
+
# initial sanity checks
|
|
1374
|
+
r = self.ideal(level).smallest_integer().valuation(self.prime())
|
|
1375
|
+
if chi.level() > r:
|
|
1376
|
+
raise ValueError("Level of extended character cannot be smaller than level of character of Qp")
|
|
1377
|
+
|
|
1378
|
+
# now do the calculation
|
|
1379
|
+
standard_gens = self.unit_gens(level)
|
|
1380
|
+
values_on_standard_gens = []
|
|
1381
|
+
|
|
1382
|
+
custom_gens = qs + chi.parent().unit_gens(r)
|
|
1383
|
+
values_on_custom_gens = vals + [chi(x) for x in chi.parent().unit_gens(r)]
|
|
1384
|
+
verbose("want to send %s to %s" % (custom_gens, values_on_custom_gens), level=1)
|
|
1385
|
+
|
|
1386
|
+
for x in standard_gens:
|
|
1387
|
+
d = self.discrete_log(level, x, custom_gens)
|
|
1388
|
+
chix = prod(values_on_custom_gens[i]**d[i] for i in range(len(d)))
|
|
1389
|
+
values_on_standard_gens.append(chix)
|
|
1390
|
+
|
|
1391
|
+
chiE = self.character(level, values_on_standard_gens)
|
|
1392
|
+
if not all( chiE(qs[i]) == vals[i] for i in range(len(qs)) ) or chiE.restrict_to_Qp() != chi:
|
|
1393
|
+
raise ValueError("Invalid values for extension")
|
|
1394
|
+
return chiE
|
|
1395
|
+
|
|
1396
|
+
|
|
1397
|
+
class SmoothCharacterGroupUnramifiedQuadratic(SmoothCharacterGroupQuadratic):
|
|
1398
|
+
r"""
|
|
1399
|
+
The group of smooth characters of `\QQ_{p^2}^\times`, where `\QQ_{p^2}` is
|
|
1400
|
+
the unique unramified quadratic extension of `\QQ_p`. We represent
|
|
1401
|
+
`\QQ_{p^2}^\times` internally as the completion at the prime above `p` of a
|
|
1402
|
+
quadratic number field, defined by (the obvious lift to `\ZZ` of) the
|
|
1403
|
+
Conway polynomial modulo `p` of degree 2.
|
|
1404
|
+
|
|
1405
|
+
EXAMPLES::
|
|
1406
|
+
|
|
1407
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1408
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(3, QQ); G
|
|
1409
|
+
Group of smooth characters of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0) with values in Rational Field
|
|
1410
|
+
sage: G.unit_gens(3)
|
|
1411
|
+
[-11*s, 4, 3*s + 1, 3]
|
|
1412
|
+
sage: TestSuite(G).run()
|
|
1413
|
+
sage: TestSuite(SmoothCharacterGroupUnramifiedQuadratic(2, QQ)).run()
|
|
1414
|
+
"""
|
|
1415
|
+
|
|
1416
|
+
def __init__(self, prime, base_ring, names='s'):
|
|
1417
|
+
r"""
|
|
1418
|
+
Standard initialisation function.
|
|
1419
|
+
|
|
1420
|
+
EXAMPLES::
|
|
1421
|
+
|
|
1422
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1423
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(3, QQ, 'foo'); G
|
|
1424
|
+
Group of smooth characters of unramified extension Q_3(foo)* (foo^2 + 2*foo + 2 = 0) with values in Rational Field
|
|
1425
|
+
sage: G == loads(dumps(G))
|
|
1426
|
+
True
|
|
1427
|
+
"""
|
|
1428
|
+
SmoothCharacterGroupGeneric.__init__(self, prime, base_ring)
|
|
1429
|
+
self._name = names
|
|
1430
|
+
|
|
1431
|
+
def change_ring(self, ring):
|
|
1432
|
+
r"""
|
|
1433
|
+
Return the character group of the same field, but with values in a
|
|
1434
|
+
different coefficient ring. This need not have anything to do with the
|
|
1435
|
+
original base ring, and in particular there won't generally be a
|
|
1436
|
+
coercion map from ``self`` to the new group -- use
|
|
1437
|
+
:meth:`~SmoothCharacterGroupGeneric.base_extend` if you want this.
|
|
1438
|
+
|
|
1439
|
+
EXAMPLES::
|
|
1440
|
+
|
|
1441
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1442
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(7, Zmod(3), names='foo').change_ring(CC)
|
|
1443
|
+
Group of smooth characters of unramified extension Q_7(foo)* (foo^2 + 6*foo + 3 = 0) with values in Complex Field with 53 bits of precision
|
|
1444
|
+
"""
|
|
1445
|
+
# We want to make sure that both G and the base-extended version have
|
|
1446
|
+
# the same values in the cache.
|
|
1447
|
+
from copy import copy
|
|
1448
|
+
G = SmoothCharacterGroupUnramifiedQuadratic(self.prime(), ring, self._name)
|
|
1449
|
+
try:
|
|
1450
|
+
G._cache___ideal = copy(self._cache___ideal)
|
|
1451
|
+
except AttributeError:
|
|
1452
|
+
pass
|
|
1453
|
+
return G
|
|
1454
|
+
|
|
1455
|
+
def _field_name(self):
|
|
1456
|
+
r"""
|
|
1457
|
+
A string representing the unit group of which this is the character group.
|
|
1458
|
+
|
|
1459
|
+
EXAMPLES::
|
|
1460
|
+
|
|
1461
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1462
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(7, Zmod(3), 'a')._field_name()
|
|
1463
|
+
'unramified extension Q_7(a)* (a^2 + 6*a + 3 = 0)'
|
|
1464
|
+
"""
|
|
1465
|
+
return "unramified extension Q_%s(%s)* (%s = 0)" % (self.prime(), self._name, self.number_field().polynomial().change_variable_name(self._name))
|
|
1466
|
+
|
|
1467
|
+
def number_field(self):
|
|
1468
|
+
r"""
|
|
1469
|
+
Return a number field of which this is the completion at `p`, defined by a polynomial
|
|
1470
|
+
whose discriminant is not divisible by `p`.
|
|
1471
|
+
|
|
1472
|
+
EXAMPLES::
|
|
1473
|
+
|
|
1474
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1475
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ, 'a').number_field()
|
|
1476
|
+
Number Field in a with defining polynomial x^2 + 6*x + 3
|
|
1477
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(5, QQ, 'b').number_field()
|
|
1478
|
+
Number Field in b with defining polynomial x^2 + 4*x + 2
|
|
1479
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ, 'c').number_field()
|
|
1480
|
+
Number Field in c with defining polynomial x^2 + x + 1
|
|
1481
|
+
"""
|
|
1482
|
+
fbar = conway_polynomial(self.prime(), 2)
|
|
1483
|
+
f = PolynomialRing(QQ, 'x')([a.lift() for a in fbar])
|
|
1484
|
+
return NumberField(f, self._name)
|
|
1485
|
+
|
|
1486
|
+
@cached_method
|
|
1487
|
+
def ideal(self, c):
|
|
1488
|
+
r"""
|
|
1489
|
+
Return the ideal `p^c` of ``self.number_field()``. The result is
|
|
1490
|
+
cached, since we use the methods
|
|
1491
|
+
:meth:`~sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal.idealstar` and
|
|
1492
|
+
:meth:`~sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal.ideallog` which
|
|
1493
|
+
cache a Pari ``bid`` structure.
|
|
1494
|
+
|
|
1495
|
+
EXAMPLES::
|
|
1496
|
+
|
|
1497
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1498
|
+
sage: G = SmoothCharacterGroupUnramifiedQuadratic(7, QQ, 'a'); I = G.ideal(3); I
|
|
1499
|
+
Fractional ideal (343)
|
|
1500
|
+
sage: I is G.ideal(3)
|
|
1501
|
+
True
|
|
1502
|
+
"""
|
|
1503
|
+
return self.number_field().ideal(self.prime()**c)
|
|
1504
|
+
|
|
1505
|
+
@cached_method
|
|
1506
|
+
def unit_gens(self, c):
|
|
1507
|
+
r"""
|
|
1508
|
+
A list of generators `x_1, \dots, x_d` of the abelian group `F^\times /
|
|
1509
|
+
(1 + \mathfrak{p}^c)^\times`, where `c` is the given level, satisfying
|
|
1510
|
+
no relations other than `x_i^{n_i} = 1` for each `i` (where the
|
|
1511
|
+
integers `n_i` are returned by :meth:`exponents`). We adopt the
|
|
1512
|
+
convention that the final generator `x_d` is a uniformiser (and `n_d =
|
|
1513
|
+
0`).
|
|
1514
|
+
|
|
1515
|
+
ALGORITHM: Use Teichmueller lifts.
|
|
1516
|
+
|
|
1517
|
+
EXAMPLES::
|
|
1518
|
+
|
|
1519
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1520
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).unit_gens(0)
|
|
1521
|
+
[7]
|
|
1522
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).unit_gens(1)
|
|
1523
|
+
[s, 7]
|
|
1524
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).unit_gens(2)
|
|
1525
|
+
[22*s, 8, 7*s + 1, 7]
|
|
1526
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).unit_gens(3)
|
|
1527
|
+
[169*s + 49, 8, 7*s + 1, 7]
|
|
1528
|
+
|
|
1529
|
+
In the 2-adic case there can be more than 4 generators::
|
|
1530
|
+
|
|
1531
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).unit_gens(0)
|
|
1532
|
+
[2]
|
|
1533
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).unit_gens(1)
|
|
1534
|
+
[s, 2]
|
|
1535
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).unit_gens(2)
|
|
1536
|
+
[s, 2*s + 1, -1, 2]
|
|
1537
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).unit_gens(3)
|
|
1538
|
+
[s, 2*s + 1, 4*s + 1, -1, 2]
|
|
1539
|
+
"""
|
|
1540
|
+
# special cases
|
|
1541
|
+
|
|
1542
|
+
p = self.prime()
|
|
1543
|
+
K = self.number_field()
|
|
1544
|
+
a = K.gen()
|
|
1545
|
+
|
|
1546
|
+
if c == 0:
|
|
1547
|
+
return [K(p)]
|
|
1548
|
+
elif c == 1:
|
|
1549
|
+
return [a, K(p)]
|
|
1550
|
+
elif p == 2:
|
|
1551
|
+
if c == 2:
|
|
1552
|
+
return [a, 1 + 2*a, K(-1), K(2)]
|
|
1553
|
+
else:
|
|
1554
|
+
return [a, 1 + 2*a, 1 + 4*a, K(-1), K(2)]
|
|
1555
|
+
|
|
1556
|
+
# general case
|
|
1557
|
+
|
|
1558
|
+
b = a
|
|
1559
|
+
I = self.ideal(c)
|
|
1560
|
+
|
|
1561
|
+
while b**(p**2 - 1) - 1 not in I:
|
|
1562
|
+
b = I.reduce(b**(self.prime()**2))
|
|
1563
|
+
return [b, K(1 + p), 1 + a*p, K(p)]
|
|
1564
|
+
|
|
1565
|
+
def exponents(self, c):
|
|
1566
|
+
r"""
|
|
1567
|
+
The orders `n_1, \dots, n_d` of the generators `x_i` of `F^\times / (1
|
|
1568
|
+
+ \mathfrak{p}^c)^\times` returned by :meth:`unit_gens`.
|
|
1569
|
+
|
|
1570
|
+
EXAMPLES::
|
|
1571
|
+
|
|
1572
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1573
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).exponents(2)
|
|
1574
|
+
[48, 7, 7, 0]
|
|
1575
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).exponents(3)
|
|
1576
|
+
[3, 4, 2, 2, 0]
|
|
1577
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).exponents(2)
|
|
1578
|
+
[3, 2, 2, 0]
|
|
1579
|
+
"""
|
|
1580
|
+
p = self.prime()
|
|
1581
|
+
if c == 0:
|
|
1582
|
+
return [0]
|
|
1583
|
+
elif c == 1:
|
|
1584
|
+
return [p**2 - 1, 0]
|
|
1585
|
+
elif p == 2 and c >= 3:
|
|
1586
|
+
return [p**2 - 1, p**(c-1), p**(c-2), 2, 0]
|
|
1587
|
+
else:
|
|
1588
|
+
return [p**2 - 1, p**(c-1), p**(c-1), 0]
|
|
1589
|
+
|
|
1590
|
+
def subgroup_gens(self, level):
|
|
1591
|
+
r"""
|
|
1592
|
+
A set of elements of `(\mathcal{O}_F / \mathfrak{p}^c)^\times`
|
|
1593
|
+
generating the kernel of the reduction map to `(\mathcal{O}_F /
|
|
1594
|
+
\mathfrak{p}^{c-1})^\times`.
|
|
1595
|
+
|
|
1596
|
+
EXAMPLES::
|
|
1597
|
+
|
|
1598
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
|
|
1599
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).subgroup_gens(1)
|
|
1600
|
+
[s]
|
|
1601
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).subgroup_gens(2)
|
|
1602
|
+
[8, 7*s + 1]
|
|
1603
|
+
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).subgroup_gens(2)
|
|
1604
|
+
[3, 2*s + 1]
|
|
1605
|
+
"""
|
|
1606
|
+
if level == 0:
|
|
1607
|
+
raise ValueError
|
|
1608
|
+
elif level == 1:
|
|
1609
|
+
return self.unit_gens(level)[:-1]
|
|
1610
|
+
else:
|
|
1611
|
+
return [1 + self.prime()**(level - 1), 1 + self.prime()**(level - 1) * self.number_field().gen()]
|
|
1612
|
+
|
|
1613
|
+
|
|
1614
|
+
class SmoothCharacterGroupRamifiedQuadratic(SmoothCharacterGroupQuadratic):
|
|
1615
|
+
r"""
|
|
1616
|
+
The group of smooth characters of `K^\times`, where `K` is a ramified
|
|
1617
|
+
quadratic extension of `\QQ_p`, and `p \ne 2`.
|
|
1618
|
+
"""
|
|
1619
|
+
def __init__(self, prime, flag, base_ring, names='s'):
|
|
1620
|
+
r"""
|
|
1621
|
+
Standard initialisation function.
|
|
1622
|
+
|
|
1623
|
+
INPUT:
|
|
1624
|
+
|
|
1625
|
+
- ``prime`` -- prime integer
|
|
1626
|
+
- ``flag`` -- either 0 or 1
|
|
1627
|
+
- ``base_ring`` -- a ring
|
|
1628
|
+
- ``names`` -- a variable name (default: ``'s'``)
|
|
1629
|
+
|
|
1630
|
+
If ``flag`` is 0, return the group of characters of the multiplicative
|
|
1631
|
+
group of the field `\QQ_p(\sqrt{p})`. If ``flag`` is 1, use the
|
|
1632
|
+
extension `\QQ_p(\sqrt{dp})`, where `d` is `-1` (if `p = 3 \pmod 4`) or
|
|
1633
|
+
the smallest positive quadratic nonresidue mod `p` otherwise.
|
|
1634
|
+
|
|
1635
|
+
EXAMPLES::
|
|
1636
|
+
|
|
1637
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
|
|
1638
|
+
sage: G1 = SmoothCharacterGroupRamifiedQuadratic(3, 0, QQ); G1
|
|
1639
|
+
Group of smooth characters of ramified extension Q_3(s)* (s^2 - 3 = 0) with values in Rational Field
|
|
1640
|
+
sage: G2 = SmoothCharacterGroupRamifiedQuadratic(3, 1, QQ); G2
|
|
1641
|
+
Group of smooth characters of ramified extension Q_3(s)* (s^2 - 6 = 0) with values in Rational Field
|
|
1642
|
+
sage: G3 = SmoothCharacterGroupRamifiedQuadratic(5, 1, QQ); G3
|
|
1643
|
+
Group of smooth characters of ramified extension Q_5(s)* (s^2 - 10 = 0) with values in Rational Field
|
|
1644
|
+
|
|
1645
|
+
TESTS:
|
|
1646
|
+
|
|
1647
|
+
.. link
|
|
1648
|
+
|
|
1649
|
+
::
|
|
1650
|
+
|
|
1651
|
+
sage: TestSuite(G1).run()
|
|
1652
|
+
sage: TestSuite(G2).run()
|
|
1653
|
+
sage: TestSuite(G3).run()
|
|
1654
|
+
"""
|
|
1655
|
+
prime = ZZ(prime)
|
|
1656
|
+
if prime == 2:
|
|
1657
|
+
raise NotImplementedError( "Wildly ramified extensions not supported" )
|
|
1658
|
+
SmoothCharacterGroupGeneric.__init__(self, prime, base_ring)
|
|
1659
|
+
self._name = names
|
|
1660
|
+
if flag not in [0, 1]:
|
|
1661
|
+
raise ValueError("Flag must be 0 (for Qp(sqrt(p)) ) or 1 (for the other ramified extension)")
|
|
1662
|
+
self._flag = flag
|
|
1663
|
+
|
|
1664
|
+
# Find an integer a such that sqrt(a*p) generates the right field and ZZ(sqrt(a*p)) is integrally closed
|
|
1665
|
+
for a in range(4 * prime):
|
|
1666
|
+
if (not a % prime) or (not ZZ(a).is_squarefree()) or ((a * prime) % 4 == 1):
|
|
1667
|
+
continue
|
|
1668
|
+
if (flag == 0 and Zmod(prime)(a).is_square()) or \
|
|
1669
|
+
(flag == 1 and not Zmod(prime)(a).is_square()):
|
|
1670
|
+
self._unif_sqr = a * prime
|
|
1671
|
+
break
|
|
1672
|
+
else:
|
|
1673
|
+
raise ValueError("Can't get here")
|
|
1674
|
+
|
|
1675
|
+
def change_ring(self, ring):
|
|
1676
|
+
r"""
|
|
1677
|
+
Return the character group of the same field, but with values in a
|
|
1678
|
+
different coefficient ring. This need not have anything to do with the
|
|
1679
|
+
original base ring, and in particular there won't generally be a
|
|
1680
|
+
coercion map from ``self`` to the new group -- use
|
|
1681
|
+
:meth:`~SmoothCharacterGroupGeneric.base_extend` if you want this.
|
|
1682
|
+
|
|
1683
|
+
EXAMPLES::
|
|
1684
|
+
|
|
1685
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
|
|
1686
|
+
sage: SmoothCharacterGroupRamifiedQuadratic(7, 1, Zmod(3), names='foo').change_ring(CC)
|
|
1687
|
+
Group of smooth characters of ramified extension Q_7(foo)* (foo^2 - 35 = 0) with values in Complex Field with 53 bits of precision
|
|
1688
|
+
"""
|
|
1689
|
+
return SmoothCharacterGroupRamifiedQuadratic(self.prime(), self._flag, ring, self._name)
|
|
1690
|
+
|
|
1691
|
+
def _field_name(self):
|
|
1692
|
+
r"""
|
|
1693
|
+
A string representing the unit group of which this is the character group.
|
|
1694
|
+
|
|
1695
|
+
EXAMPLES::
|
|
1696
|
+
|
|
1697
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
|
|
1698
|
+
sage: SmoothCharacterGroupRamifiedQuadratic(7, 0, Zmod(3), 'a')._field_name()
|
|
1699
|
+
'ramified extension Q_7(a)* (a^2 - 7 = 0)'
|
|
1700
|
+
"""
|
|
1701
|
+
return "ramified extension Q_%s(%s)* (%s = 0)" % (self.prime(), self._name, self.number_field().polynomial().change_variable_name(self._name))
|
|
1702
|
+
|
|
1703
|
+
def number_field(self):
|
|
1704
|
+
r"""
|
|
1705
|
+
Return a number field of which this is the completion at `p`.
|
|
1706
|
+
|
|
1707
|
+
EXAMPLES::
|
|
1708
|
+
|
|
1709
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
|
|
1710
|
+
sage: SmoothCharacterGroupRamifiedQuadratic(7, 0, QQ, 'a').number_field()
|
|
1711
|
+
Number Field in a with defining polynomial x^2 - 7
|
|
1712
|
+
sage: SmoothCharacterGroupRamifiedQuadratic(5, 1, QQ, 'b').number_field()
|
|
1713
|
+
Number Field in b with defining polynomial x^2 - 10
|
|
1714
|
+
sage: SmoothCharacterGroupRamifiedQuadratic(7, 1, Zmod(6), 'c').number_field()
|
|
1715
|
+
Number Field in c with defining polynomial x^2 - 35
|
|
1716
|
+
"""
|
|
1717
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
1718
|
+
R, x = PolynomialRing(QQ, 'x').objgen()
|
|
1719
|
+
f = x**2 - self._unif_sqr
|
|
1720
|
+
return NumberField(f, self._name)
|
|
1721
|
+
|
|
1722
|
+
@cached_method
|
|
1723
|
+
def ideal(self, c):
|
|
1724
|
+
r"""
|
|
1725
|
+
Return the ideal `p^c` of ``self.number_field()``. The result is
|
|
1726
|
+
cached, since we use the methods
|
|
1727
|
+
:meth:`~sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal.idealstar` and
|
|
1728
|
+
:meth:`~sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal.ideallog` which
|
|
1729
|
+
cache a Pari ``bid`` structure.
|
|
1730
|
+
|
|
1731
|
+
EXAMPLES::
|
|
1732
|
+
|
|
1733
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
|
|
1734
|
+
sage: G = SmoothCharacterGroupRamifiedQuadratic(5, 1, QQ, 'a'); I = G.ideal(3); I
|
|
1735
|
+
Fractional ideal (25, 5*a)
|
|
1736
|
+
sage: I is G.ideal(3)
|
|
1737
|
+
True
|
|
1738
|
+
"""
|
|
1739
|
+
return self.number_field().ideal([self.prime(), self.number_field().gen()])**c
|
|
1740
|
+
|
|
1741
|
+
def unit_gens(self, c):
|
|
1742
|
+
r"""
|
|
1743
|
+
A list of generators `x_1, \dots, x_d` of the abelian group `F^\times /
|
|
1744
|
+
(1 + \mathfrak{p}^c)^\times`, where `c` is the given level, satisfying
|
|
1745
|
+
no relations other than `x_i^{n_i} = 1` for each `i` (where the
|
|
1746
|
+
integers `n_i` are returned by :meth:`exponents`). We adopt the
|
|
1747
|
+
convention that the final generator `x_d` is a uniformiser.
|
|
1748
|
+
|
|
1749
|
+
EXAMPLES::
|
|
1750
|
+
|
|
1751
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
|
|
1752
|
+
sage: G = SmoothCharacterGroupRamifiedQuadratic(5, 0, QQ)
|
|
1753
|
+
sage: G.unit_gens(0)
|
|
1754
|
+
[s]
|
|
1755
|
+
sage: G.unit_gens(1)
|
|
1756
|
+
[2, s]
|
|
1757
|
+
sage: G.unit_gens(8)
|
|
1758
|
+
[2, s + 1, s]
|
|
1759
|
+
"""
|
|
1760
|
+
d = ZZ(c + 1) // 2
|
|
1761
|
+
p = self.prime()
|
|
1762
|
+
K, s = self.number_field().objgen()
|
|
1763
|
+
zpgens = [K(ZZ(x)) for x in Zmod(p**d).unit_gens()]
|
|
1764
|
+
if c == 0:
|
|
1765
|
+
return [s]
|
|
1766
|
+
if c == 1:
|
|
1767
|
+
return zpgens + [s]
|
|
1768
|
+
elif p > 3 or self._unif_sqr == 3 or c <= 3:
|
|
1769
|
+
return zpgens + [1 + s, s]
|
|
1770
|
+
else:
|
|
1771
|
+
# Awkward case: K = Q_3(sqrt(-3)). Here the exponential map doesn't
|
|
1772
|
+
# converge on 1 + P, and the quotient (O_K*) / (Zp*) isn't
|
|
1773
|
+
# topologically cyclic. I don't know an explicit set of good
|
|
1774
|
+
# generators here, so we let Pari do the work and put up with the
|
|
1775
|
+
# rather arbitrary (nondeterministic?) results.
|
|
1776
|
+
return list(self.ideal(c).idealstar(2).gens_values()) + [s]
|
|
1777
|
+
|
|
1778
|
+
def exponents(self, c):
|
|
1779
|
+
r"""
|
|
1780
|
+
Return the orders of the independent generators of the unit group
|
|
1781
|
+
returned by :meth:`~unit_gens`.
|
|
1782
|
+
|
|
1783
|
+
EXAMPLES::
|
|
1784
|
+
|
|
1785
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
|
|
1786
|
+
sage: G = SmoothCharacterGroupRamifiedQuadratic(5, 0, QQ)
|
|
1787
|
+
sage: G.exponents(0)
|
|
1788
|
+
(0,)
|
|
1789
|
+
sage: G.exponents(1)
|
|
1790
|
+
(4, 0)
|
|
1791
|
+
sage: G.exponents(8)
|
|
1792
|
+
(500, 625, 0)
|
|
1793
|
+
"""
|
|
1794
|
+
c = ZZ(c)
|
|
1795
|
+
p = self.prime()
|
|
1796
|
+
if c == 0:
|
|
1797
|
+
return (0,)
|
|
1798
|
+
elif c == 1:
|
|
1799
|
+
return (p - 1, 0)
|
|
1800
|
+
elif p > 3 or self._unif_sqr == 3 or c <= 3:
|
|
1801
|
+
d = (c + 1) // 2
|
|
1802
|
+
return (p**(d - 1) * (p - 1), p**(c // 2), 0)
|
|
1803
|
+
else:
|
|
1804
|
+
# awkward case, see above
|
|
1805
|
+
return self.ideal(c).idealstar(2).gens_orders() + (0,)
|
|
1806
|
+
|
|
1807
|
+
def subgroup_gens(self, level):
|
|
1808
|
+
r"""
|
|
1809
|
+
A set of elements of `(\mathcal{O}_F / \mathfrak{p}^c)^\times`
|
|
1810
|
+
generating the kernel of the reduction map to `(\mathcal{O}_F /
|
|
1811
|
+
\mathfrak{p}^{c-1})^\times`.
|
|
1812
|
+
|
|
1813
|
+
EXAMPLES::
|
|
1814
|
+
|
|
1815
|
+
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
|
|
1816
|
+
sage: G = SmoothCharacterGroupRamifiedQuadratic(3, 1, QQ)
|
|
1817
|
+
sage: G.subgroup_gens(2)
|
|
1818
|
+
[s + 1]
|
|
1819
|
+
"""
|
|
1820
|
+
if level == 0:
|
|
1821
|
+
raise ValueError
|
|
1822
|
+
elif level == 1:
|
|
1823
|
+
return self.unit_gens(level)[:-1]
|
|
1824
|
+
else:
|
|
1825
|
+
return [1 + self.number_field().gen()**(level - 1)]
|