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,3310 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
# sage.doctest: needs sage.libs.pari
|
|
3
|
+
r"""
|
|
4
|
+
Dirichlet characters
|
|
5
|
+
|
|
6
|
+
A :class:`DirichletCharacter` is the extension of a homomorphism
|
|
7
|
+
|
|
8
|
+
.. MATH::
|
|
9
|
+
|
|
10
|
+
(\ZZ/N\ZZ)^* \to R^*,
|
|
11
|
+
|
|
12
|
+
for some ring `R`, to the map `\ZZ/N\ZZ \to R` obtained by sending
|
|
13
|
+
those `x\in\ZZ/N\ZZ` with `\gcd(N,x)>1` to `0`.
|
|
14
|
+
|
|
15
|
+
EXAMPLES::
|
|
16
|
+
|
|
17
|
+
sage: G = DirichletGroup(35)
|
|
18
|
+
sage: x = G.gens()
|
|
19
|
+
sage: e = x[0]*x[1]^2; e
|
|
20
|
+
Dirichlet character modulo 35 of conductor 35
|
|
21
|
+
mapping 22 |--> zeta12^3, 31 |--> zeta12^2 - 1
|
|
22
|
+
sage: e.order()
|
|
23
|
+
12
|
|
24
|
+
|
|
25
|
+
This illustrates a canonical coercion::
|
|
26
|
+
|
|
27
|
+
sage: e = DirichletGroup(5, QQ).0
|
|
28
|
+
sage: f = DirichletGroup(5, CyclotomicField(4)).0
|
|
29
|
+
sage: e*f
|
|
30
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -zeta4
|
|
31
|
+
|
|
32
|
+
AUTHORS:
|
|
33
|
+
|
|
34
|
+
- William Stein (2005-09-02): Fixed bug in comparison of Dirichlet
|
|
35
|
+
characters. It was checking that their values were the same, but
|
|
36
|
+
not checking that they had the same level!
|
|
37
|
+
|
|
38
|
+
- William Stein (2006-01-07): added more examples
|
|
39
|
+
|
|
40
|
+
- William Stein (2006-05-21): added examples of everything; fix a
|
|
41
|
+
*lot* of tiny bugs and design problem that became clear when
|
|
42
|
+
creating examples.
|
|
43
|
+
|
|
44
|
+
- Craig Citro (2008-02-16): speed up __call__ method for
|
|
45
|
+
Dirichlet characters, miscellaneous fixes
|
|
46
|
+
|
|
47
|
+
- Julian Rueth (2014-03-06): use UniqueFactory to cache DirichletGroups
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
# ****************************************************************************
|
|
51
|
+
# Copyright (C) 2004-2006 William Stein <wstein@gmail.com>
|
|
52
|
+
# Copyright (C) 2014 Julian Rueth <julian.rueth@fsfe.org>
|
|
53
|
+
#
|
|
54
|
+
# This program is free software: you can redistribute it and/or modify
|
|
55
|
+
# it under the terms of the GNU General Public License as published by
|
|
56
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
57
|
+
# (at your option) any later version.
|
|
58
|
+
# https://www.gnu.org/licenses/
|
|
59
|
+
# ****************************************************************************
|
|
60
|
+
|
|
61
|
+
import sage.misc.prandom as random
|
|
62
|
+
import sage.modules.free_module_element as free_module_element
|
|
63
|
+
import sage.rings.abc
|
|
64
|
+
|
|
65
|
+
from sage.arith.functions import lcm
|
|
66
|
+
from sage.arith.misc import bernoulli, factorial, kronecker, factor, gcd, fundamental_discriminant, euler_phi, valuation
|
|
67
|
+
from sage.categories.map import Map
|
|
68
|
+
from sage.categories.objects import Objects
|
|
69
|
+
from sage.categories.rings import Rings
|
|
70
|
+
from sage.misc.cachefunc import cached_method
|
|
71
|
+
from sage.misc.fast_methods import WithEqualityById
|
|
72
|
+
from sage.misc.functional import round
|
|
73
|
+
from sage.misc.lazy_import import lazy_import
|
|
74
|
+
from sage.misc.misc_c import prod
|
|
75
|
+
from sage.modules.free_module import FreeModule
|
|
76
|
+
from sage.rings.finite_rings.integer_mod import Mod
|
|
77
|
+
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
|
|
78
|
+
from sage.rings.integer import Integer
|
|
79
|
+
from sage.rings.integer_ring import ZZ
|
|
80
|
+
from sage.rings.power_series_ring import PowerSeriesRing
|
|
81
|
+
from sage.rings.rational_field import QQ, RationalField
|
|
82
|
+
from sage.structure.element import MultiplicativeGroupElement
|
|
83
|
+
from sage.structure.factory import UniqueFactory
|
|
84
|
+
from sage.structure.gens_py import multiplicative_iterator
|
|
85
|
+
from sage.structure.parent import Parent
|
|
86
|
+
from sage.structure.richcmp import richcmp
|
|
87
|
+
from sage.structure.sequence import Sequence
|
|
88
|
+
|
|
89
|
+
lazy_import('sage.libs.pari', 'pari')
|
|
90
|
+
lazy_import('sage.rings.number_field.number_field', ['CyclotomicField', 'NumberField', 'NumberField_generic'])
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def trivial_character(N, base_ring=QQ):
|
|
94
|
+
r"""
|
|
95
|
+
Return the trivial character of the given modulus, with values in the given
|
|
96
|
+
base ring.
|
|
97
|
+
|
|
98
|
+
EXAMPLES::
|
|
99
|
+
|
|
100
|
+
sage: t = trivial_character(7)
|
|
101
|
+
sage: [t(x) for x in [0..20]]
|
|
102
|
+
[0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1]
|
|
103
|
+
sage: t(1).parent()
|
|
104
|
+
Rational Field
|
|
105
|
+
sage: trivial_character(7, Integers(3))(1).parent()
|
|
106
|
+
Ring of integers modulo 3
|
|
107
|
+
"""
|
|
108
|
+
return DirichletGroup(N, base_ring)(1)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
TrivialCharacter = trivial_character
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def kronecker_character(d):
|
|
115
|
+
"""
|
|
116
|
+
Return the quadratic Dirichlet character (d/.) of minimal
|
|
117
|
+
conductor.
|
|
118
|
+
|
|
119
|
+
EXAMPLES::
|
|
120
|
+
|
|
121
|
+
sage: kronecker_character(97*389*997^2)
|
|
122
|
+
Dirichlet character modulo 37733 of conductor 37733
|
|
123
|
+
mapping 1557 |--> -1, 37346 |--> -1
|
|
124
|
+
|
|
125
|
+
::
|
|
126
|
+
|
|
127
|
+
sage: a = kronecker_character(1)
|
|
128
|
+
sage: b = DirichletGroup(2401,QQ)(a) # NOTE -- over QQ!
|
|
129
|
+
sage: b.modulus()
|
|
130
|
+
2401
|
|
131
|
+
|
|
132
|
+
AUTHORS:
|
|
133
|
+
|
|
134
|
+
- Jon Hanke (2006-08-06)
|
|
135
|
+
"""
|
|
136
|
+
d = Integer(d)
|
|
137
|
+
if d == 0:
|
|
138
|
+
raise ValueError("d must be nonzero")
|
|
139
|
+
|
|
140
|
+
D = fundamental_discriminant(d)
|
|
141
|
+
G = DirichletGroup(abs(D), QQ)
|
|
142
|
+
return G([kronecker(D, u) for u in G.unit_gens()])
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def kronecker_character_upside_down(d):
|
|
146
|
+
"""
|
|
147
|
+
Return the quadratic Dirichlet character (./d) of conductor d, for
|
|
148
|
+
d > 0.
|
|
149
|
+
|
|
150
|
+
EXAMPLES::
|
|
151
|
+
|
|
152
|
+
sage: kronecker_character_upside_down(97*389*997^2)
|
|
153
|
+
Dirichlet character modulo 37506941597 of conductor 37733
|
|
154
|
+
mapping 13533432536 |--> -1, 22369178537 |--> -1, 14266017175 |--> 1
|
|
155
|
+
|
|
156
|
+
AUTHORS:
|
|
157
|
+
|
|
158
|
+
- Jon Hanke (2006-08-06)
|
|
159
|
+
"""
|
|
160
|
+
d = Integer(d)
|
|
161
|
+
if d <= 0:
|
|
162
|
+
raise ValueError("d must be positive")
|
|
163
|
+
|
|
164
|
+
G = DirichletGroup(d, QQ)
|
|
165
|
+
return G([kronecker(u.lift(), d) for u in G.unit_gens()])
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def is_DirichletCharacter(x) -> bool:
|
|
169
|
+
r"""
|
|
170
|
+
Return ``True`` if ``x`` is of type ``DirichletCharacter``.
|
|
171
|
+
|
|
172
|
+
EXAMPLES::
|
|
173
|
+
|
|
174
|
+
sage: from sage.modular.dirichlet import is_DirichletCharacter
|
|
175
|
+
sage: is_DirichletCharacter(trivial_character(3))
|
|
176
|
+
doctest:warning...
|
|
177
|
+
DeprecationWarning: The function is_DirichletCharacter is deprecated;
|
|
178
|
+
use 'isinstance(..., DirichletCharacter)' instead.
|
|
179
|
+
See https://github.com/sagemath/sage/issues/38184 for details.
|
|
180
|
+
True
|
|
181
|
+
sage: is_DirichletCharacter([1])
|
|
182
|
+
False
|
|
183
|
+
"""
|
|
184
|
+
from sage.misc.superseded import deprecation
|
|
185
|
+
deprecation(38184,
|
|
186
|
+
"The function is_DirichletCharacter is deprecated; "
|
|
187
|
+
"use 'isinstance(..., DirichletCharacter)' instead.")
|
|
188
|
+
return isinstance(x, DirichletCharacter)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class DirichletCharacter(MultiplicativeGroupElement):
|
|
192
|
+
"""
|
|
193
|
+
A Dirichlet character.
|
|
194
|
+
"""
|
|
195
|
+
def __init__(self, parent, x, check=True) -> None:
|
|
196
|
+
r"""
|
|
197
|
+
Create a Dirichlet character with specified values on
|
|
198
|
+
generators of `(\ZZ/n\ZZ)^*`.
|
|
199
|
+
|
|
200
|
+
INPUT:
|
|
201
|
+
|
|
202
|
+
- ``parent`` -- :class:`DirichletGroup`, a group of Dirichlet
|
|
203
|
+
characters
|
|
204
|
+
|
|
205
|
+
- ``x`` -- one of the following:
|
|
206
|
+
|
|
207
|
+
- tuple or list of ring elements: the values of the
|
|
208
|
+
Dirichlet character on the standard generators of
|
|
209
|
+
`(\ZZ/N\ZZ)^*` as returned by
|
|
210
|
+
:meth:`sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic.unit_gens`.
|
|
211
|
+
|
|
212
|
+
- vector over `\ZZ/e\ZZ`, where `e` is the order of the
|
|
213
|
+
standard root of unity for ``parent``.
|
|
214
|
+
|
|
215
|
+
In both cases, the orders of the elements must divide the
|
|
216
|
+
orders of the respective generators of `(\ZZ/N\ZZ)^*`.
|
|
217
|
+
|
|
218
|
+
OUTPUT:
|
|
219
|
+
|
|
220
|
+
The Dirichlet character defined by `x` (type
|
|
221
|
+
:class:`DirichletCharacter`).
|
|
222
|
+
|
|
223
|
+
EXAMPLES::
|
|
224
|
+
|
|
225
|
+
sage: G.<e> = DirichletGroup(13)
|
|
226
|
+
sage: G
|
|
227
|
+
Group of Dirichlet characters modulo 13 with values
|
|
228
|
+
in Cyclotomic Field of order 12 and degree 4
|
|
229
|
+
sage: e
|
|
230
|
+
Dirichlet character modulo 13 of conductor 13 mapping 2 |--> zeta12
|
|
231
|
+
sage: loads(e.dumps()) == e
|
|
232
|
+
True
|
|
233
|
+
|
|
234
|
+
::
|
|
235
|
+
|
|
236
|
+
sage: G, x = DirichletGroup(35).objgens()
|
|
237
|
+
sage: e = x[0]*x[1]; e
|
|
238
|
+
Dirichlet character modulo 35 of conductor 35
|
|
239
|
+
mapping 22 |--> zeta12^3, 31 |--> zeta12^2
|
|
240
|
+
sage: e.order()
|
|
241
|
+
12
|
|
242
|
+
sage: loads(e.dumps()) == e
|
|
243
|
+
True
|
|
244
|
+
|
|
245
|
+
TESTS::
|
|
246
|
+
|
|
247
|
+
sage: G = DirichletGroup(10)
|
|
248
|
+
sage: TestSuite(G[1]).run()
|
|
249
|
+
|
|
250
|
+
It is checked that the orders of the elements in `x` are
|
|
251
|
+
admissible (see :issue:`17283`)::
|
|
252
|
+
|
|
253
|
+
sage: k.<i> = CyclotomicField(4)
|
|
254
|
+
sage: G = DirichletGroup(192)
|
|
255
|
+
sage: G([i, -1, -1])
|
|
256
|
+
Traceback (most recent call last):
|
|
257
|
+
...
|
|
258
|
+
ValueError: values (= (zeta16^4, -1, -1)) must have
|
|
259
|
+
multiplicative orders dividing (2, 16, 2), respectively
|
|
260
|
+
|
|
261
|
+
sage: from sage.modular.dirichlet import DirichletCharacter
|
|
262
|
+
sage: M = FreeModule(Zmod(16), 3)
|
|
263
|
+
sage: DirichletCharacter(G, M([4, 8, 8]))
|
|
264
|
+
Traceback (most recent call last):
|
|
265
|
+
...
|
|
266
|
+
ValueError: values (= (4, 8, 8) modulo 16) must have
|
|
267
|
+
additive orders dividing (2, 16, 2), respectively
|
|
268
|
+
"""
|
|
269
|
+
MultiplicativeGroupElement.__init__(self, parent)
|
|
270
|
+
if check:
|
|
271
|
+
orders = parent.integers_mod().unit_group().gens_orders()
|
|
272
|
+
if len(x) != len(orders):
|
|
273
|
+
raise ValueError("wrong number of values (= {}) on generators (want {})".format(x, len(orders)))
|
|
274
|
+
if isinstance(x, free_module_element.FreeModuleElement):
|
|
275
|
+
x = parent._module(x)
|
|
276
|
+
if any(u * v for u, v in zip(x, orders)):
|
|
277
|
+
raise ValueError("values (= {} modulo {}) must have additive orders dividing {}, respectively"
|
|
278
|
+
.format(x, parent.zeta_order(), orders))
|
|
279
|
+
self.element.set_cache(x)
|
|
280
|
+
else:
|
|
281
|
+
R = parent.base_ring()
|
|
282
|
+
x = tuple(map(R, x))
|
|
283
|
+
if R.is_exact() and any(u**v != 1 for u, v in zip(x, orders)):
|
|
284
|
+
raise ValueError("values (= {}) must have multiplicative orders dividing {}, respectively"
|
|
285
|
+
.format(x, orders))
|
|
286
|
+
self.values_on_gens.set_cache(x)
|
|
287
|
+
else:
|
|
288
|
+
if isinstance(x, free_module_element.FreeModuleElement):
|
|
289
|
+
self.element.set_cache(x)
|
|
290
|
+
else:
|
|
291
|
+
self.values_on_gens.set_cache(x)
|
|
292
|
+
|
|
293
|
+
@cached_method
|
|
294
|
+
def __eval_at_minus_one(self):
|
|
295
|
+
r"""
|
|
296
|
+
Efficiently evaluate the character at -1 using knowledge of its
|
|
297
|
+
order. This is potentially much more efficient than computing the
|
|
298
|
+
value of -1 directly using dlog and a large power of the image root
|
|
299
|
+
of unity.
|
|
300
|
+
|
|
301
|
+
We use the following. Proposition: Suppose eps is a character mod
|
|
302
|
+
`p^n`, where `p` is a prime. Then
|
|
303
|
+
`\varepsilon(-1) = -1` if and only if `p = 2` and
|
|
304
|
+
the factor of eps at 4 is nontrivial or `p > 2` and 2 does
|
|
305
|
+
not divide `\phi(p^n)/\mbox{\rm ord}(\varepsilon)`.
|
|
306
|
+
|
|
307
|
+
EXAMPLES::
|
|
308
|
+
|
|
309
|
+
sage: chi = DirichletGroup(20).0; chi._DirichletCharacter__eval_at_minus_one()
|
|
310
|
+
-1
|
|
311
|
+
"""
|
|
312
|
+
D = self.decomposition()
|
|
313
|
+
val = self.base_ring()(1)
|
|
314
|
+
for e in D:
|
|
315
|
+
if e.modulus() % 2 == 0:
|
|
316
|
+
if e.modulus() % 4 == 0:
|
|
317
|
+
val *= e.values_on_gens()[0] # first gen is -1 for 2-power modulus
|
|
318
|
+
elif (euler_phi(e.parent().modulus()) / e.order()) % 2:
|
|
319
|
+
val *= -1
|
|
320
|
+
return val
|
|
321
|
+
|
|
322
|
+
def __call__(self, m):
|
|
323
|
+
"""
|
|
324
|
+
Return the value of this character at the integer `m`.
|
|
325
|
+
|
|
326
|
+
.. warning::
|
|
327
|
+
|
|
328
|
+
A table of values of the character is made the first time
|
|
329
|
+
you call this (unless `m` equals -1)
|
|
330
|
+
|
|
331
|
+
EXAMPLES::
|
|
332
|
+
|
|
333
|
+
sage: G = DirichletGroup(60)
|
|
334
|
+
sage: e = prod(G.gens(), G(1))
|
|
335
|
+
sage: e
|
|
336
|
+
Dirichlet character modulo 60 of conductor 60 mapping 31 |--> -1, 41 |--> -1, 37 |--> zeta4
|
|
337
|
+
sage: e(-1)
|
|
338
|
+
-1
|
|
339
|
+
sage: e(2)
|
|
340
|
+
0
|
|
341
|
+
sage: e(7)
|
|
342
|
+
-zeta4
|
|
343
|
+
sage: Integers(60).unit_gens()
|
|
344
|
+
(31, 41, 37)
|
|
345
|
+
sage: e(31)
|
|
346
|
+
-1
|
|
347
|
+
sage: e(41)
|
|
348
|
+
-1
|
|
349
|
+
sage: e(37)
|
|
350
|
+
zeta4
|
|
351
|
+
sage: e(31*37)
|
|
352
|
+
-zeta4
|
|
353
|
+
sage: parent(e(31*37))
|
|
354
|
+
Cyclotomic Field of order 4 and degree 2
|
|
355
|
+
"""
|
|
356
|
+
N = self.modulus()
|
|
357
|
+
m = m % N
|
|
358
|
+
if self.values.is_in_cache() or m != N - 1:
|
|
359
|
+
return self.values()[m]
|
|
360
|
+
else:
|
|
361
|
+
return self.__eval_at_minus_one()
|
|
362
|
+
|
|
363
|
+
def change_ring(self, R):
|
|
364
|
+
"""
|
|
365
|
+
Return the base extension of ``self`` to ``R``.
|
|
366
|
+
|
|
367
|
+
INPUT:
|
|
368
|
+
|
|
369
|
+
- ``R`` -- either a ring admitting a conversion map from the
|
|
370
|
+
base ring of ``self``, or a ring homomorphism with the base
|
|
371
|
+
ring of ``self`` as its domain
|
|
372
|
+
|
|
373
|
+
EXAMPLES::
|
|
374
|
+
|
|
375
|
+
sage: e = DirichletGroup(7, QQ).0
|
|
376
|
+
sage: f = e.change_ring(QuadraticField(3, 'a'))
|
|
377
|
+
sage: f.parent()
|
|
378
|
+
Group of Dirichlet characters modulo 7 with values in Number Field in a
|
|
379
|
+
with defining polynomial x^2 - 3 with a = 1.732050807568878?
|
|
380
|
+
|
|
381
|
+
::
|
|
382
|
+
|
|
383
|
+
sage: e = DirichletGroup(13).0
|
|
384
|
+
sage: e.change_ring(QQ)
|
|
385
|
+
Traceback (most recent call last):
|
|
386
|
+
...
|
|
387
|
+
TypeError: Unable to coerce zeta12 to a rational
|
|
388
|
+
|
|
389
|
+
We test the case where `R` is a map (:issue:`18072`)::
|
|
390
|
+
|
|
391
|
+
sage: K.<i> = QuadraticField(-1)
|
|
392
|
+
sage: chi = DirichletGroup(5, K)[1]
|
|
393
|
+
sage: chi(2)
|
|
394
|
+
i
|
|
395
|
+
sage: f = K.complex_embeddings()[0]
|
|
396
|
+
sage: psi = chi.change_ring(f)
|
|
397
|
+
sage: psi(2)
|
|
398
|
+
-1.83697019872103e-16 - 1.00000000000000*I
|
|
399
|
+
"""
|
|
400
|
+
if self.base_ring() is R:
|
|
401
|
+
return self
|
|
402
|
+
G = self.parent().change_ring(R)
|
|
403
|
+
return G.element_class(G, [R(x) for x in self.values_on_gens()])
|
|
404
|
+
|
|
405
|
+
def _richcmp_(self, other, op) -> bool:
|
|
406
|
+
"""
|
|
407
|
+
Compare ``self`` to ``other``.
|
|
408
|
+
|
|
409
|
+
.. NOTE::
|
|
410
|
+
|
|
411
|
+
Since there is no coercion between Dirichlet groups
|
|
412
|
+
of different moduli, characters of different moduli
|
|
413
|
+
compare as unequal, even if they define identical
|
|
414
|
+
functions on ``ZZ``.
|
|
415
|
+
|
|
416
|
+
EXAMPLES::
|
|
417
|
+
|
|
418
|
+
sage: # needs sage.rings.number_field
|
|
419
|
+
sage: e = DirichletGroup(16)([-1, 1])
|
|
420
|
+
sage: f = e.restrict(8)
|
|
421
|
+
sage: e == e
|
|
422
|
+
True
|
|
423
|
+
sage: f == f
|
|
424
|
+
True
|
|
425
|
+
sage: e == f
|
|
426
|
+
False
|
|
427
|
+
sage: k = DirichletGroup(7)([-1])
|
|
428
|
+
sage: k == e
|
|
429
|
+
False
|
|
430
|
+
"""
|
|
431
|
+
return richcmp(self.values_on_gens(), other.values_on_gens(), op)
|
|
432
|
+
|
|
433
|
+
def __hash__(self) -> int:
|
|
434
|
+
"""
|
|
435
|
+
Return the hash of ``self``.
|
|
436
|
+
|
|
437
|
+
EXAMPLES::
|
|
438
|
+
|
|
439
|
+
sage: # needs sage.rings.number_field
|
|
440
|
+
sage: e = DirichletGroup(16)([-1, 1])
|
|
441
|
+
sage: hash(e) == hash((-1,1))
|
|
442
|
+
True
|
|
443
|
+
"""
|
|
444
|
+
return hash(self.values_on_gens())
|
|
445
|
+
|
|
446
|
+
def __invert__(self):
|
|
447
|
+
"""
|
|
448
|
+
Return the multiplicative inverse of ``self``.
|
|
449
|
+
|
|
450
|
+
EXAMPLES::
|
|
451
|
+
|
|
452
|
+
sage: e = DirichletGroup(13).0
|
|
453
|
+
sage: f = ~e
|
|
454
|
+
sage: f*e
|
|
455
|
+
Dirichlet character modulo 13 of conductor 1 mapping 2 |--> 1
|
|
456
|
+
"""
|
|
457
|
+
G = self.parent()
|
|
458
|
+
if G.zeta.is_in_cache():
|
|
459
|
+
x = -self.element()
|
|
460
|
+
else:
|
|
461
|
+
x = tuple(~z for z in self.values_on_gens())
|
|
462
|
+
return G.element_class(G, x, check=False)
|
|
463
|
+
|
|
464
|
+
def _mul_(self, other):
|
|
465
|
+
"""
|
|
466
|
+
Return the product of ``self`` and ``other``.
|
|
467
|
+
|
|
468
|
+
EXAMPLES::
|
|
469
|
+
|
|
470
|
+
sage: G.<a,b> = DirichletGroup(20)
|
|
471
|
+
sage: a
|
|
472
|
+
Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1
|
|
473
|
+
sage: b
|
|
474
|
+
Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> zeta4
|
|
475
|
+
sage: a*b # indirect doctest
|
|
476
|
+
Dirichlet character modulo 20 of conductor 20 mapping 11 |--> -1, 17 |--> zeta4
|
|
477
|
+
|
|
478
|
+
Multiplying elements whose parents have different zeta orders works::
|
|
479
|
+
|
|
480
|
+
sage: a = DirichletGroup(3, QQ, zeta=1, zeta_order=1)(1)
|
|
481
|
+
sage: b = DirichletGroup(3, QQ, zeta=-1, zeta_order=2)([-1])
|
|
482
|
+
sage: a * b # indirect doctest
|
|
483
|
+
Dirichlet character modulo 3 of conductor 3 mapping 2 |--> -1
|
|
484
|
+
"""
|
|
485
|
+
G = self.parent()
|
|
486
|
+
if G.zeta.is_in_cache():
|
|
487
|
+
x = self.element() + other.element()
|
|
488
|
+
else:
|
|
489
|
+
x = tuple(y * z for y, z in zip(self.values_on_gens(), other.values_on_gens()))
|
|
490
|
+
return G.element_class(G, x, check=False)
|
|
491
|
+
|
|
492
|
+
def __copy__(self):
|
|
493
|
+
"""
|
|
494
|
+
Return a (shallow) copy of this Dirichlet character.
|
|
495
|
+
|
|
496
|
+
EXAMPLES::
|
|
497
|
+
|
|
498
|
+
sage: G.<a> = DirichletGroup(11)
|
|
499
|
+
sage: b = copy(a)
|
|
500
|
+
sage: a is b
|
|
501
|
+
False
|
|
502
|
+
sage: a.element() is b.element()
|
|
503
|
+
False
|
|
504
|
+
sage: a.values_on_gens() is b.values_on_gens()
|
|
505
|
+
True
|
|
506
|
+
"""
|
|
507
|
+
# This method exists solely because of a bug in the cPickle module --
|
|
508
|
+
# see modsym/manin_symbols.py.
|
|
509
|
+
G = self.parent()
|
|
510
|
+
return G.element_class(G, self.values_on_gens(), check=False)
|
|
511
|
+
|
|
512
|
+
def __pow__(self, n):
|
|
513
|
+
"""
|
|
514
|
+
Return ``self`` raised to the power of ``n``.
|
|
515
|
+
|
|
516
|
+
EXAMPLES::
|
|
517
|
+
|
|
518
|
+
sage: G.<a,b> = DirichletGroup(20)
|
|
519
|
+
sage: a^2
|
|
520
|
+
Dirichlet character modulo 20 of conductor 1 mapping 11 |--> 1, 17 |--> 1
|
|
521
|
+
sage: b^2
|
|
522
|
+
Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -1
|
|
523
|
+
"""
|
|
524
|
+
G = self.parent()
|
|
525
|
+
if G.zeta.is_in_cache():
|
|
526
|
+
x = n * self.element()
|
|
527
|
+
else:
|
|
528
|
+
x = tuple(z**n for z in self.values_on_gens())
|
|
529
|
+
return G.element_class(G, x, check=False)
|
|
530
|
+
|
|
531
|
+
def _repr_short_(self) -> str:
|
|
532
|
+
r"""
|
|
533
|
+
A short string representation of ``self``, often used in string representations of modular forms.
|
|
534
|
+
|
|
535
|
+
EXAMPLES::
|
|
536
|
+
|
|
537
|
+
sage: chi = DirichletGroup(24).0
|
|
538
|
+
sage: chi._repr_short_()
|
|
539
|
+
'[-1, 1, 1]'
|
|
540
|
+
"""
|
|
541
|
+
return str(list(self.values_on_gens()))
|
|
542
|
+
|
|
543
|
+
def _repr_(self) -> str:
|
|
544
|
+
"""
|
|
545
|
+
String representation of ``self``.
|
|
546
|
+
|
|
547
|
+
EXAMPLES::
|
|
548
|
+
|
|
549
|
+
sage: G.<a,b> = DirichletGroup(20)
|
|
550
|
+
sage: repr(a) # indirect doctest
|
|
551
|
+
'Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1'
|
|
552
|
+
|
|
553
|
+
TESTS:
|
|
554
|
+
|
|
555
|
+
Dirichlet characters modulo 1 and 2 are printed correctly (see
|
|
556
|
+
:issue:`17338`)::
|
|
557
|
+
|
|
558
|
+
sage: DirichletGroup(1)[0]
|
|
559
|
+
Dirichlet character modulo 1 of conductor 1
|
|
560
|
+
sage: DirichletGroup(2)[0]
|
|
561
|
+
Dirichlet character modulo 2 of conductor 1
|
|
562
|
+
"""
|
|
563
|
+
s = 'Dirichlet character modulo %s of conductor %s' % (self.modulus(), self.conductor())
|
|
564
|
+
r = len(self.values_on_gens())
|
|
565
|
+
if r:
|
|
566
|
+
s += ' mapping '
|
|
567
|
+
for i in range(r):
|
|
568
|
+
if i:
|
|
569
|
+
s += ', '
|
|
570
|
+
s += str(self.parent().unit_gens()[i]) + ' |--> ' + str(self.values_on_gens()[i])
|
|
571
|
+
return s
|
|
572
|
+
|
|
573
|
+
def _latex_(self) -> str:
|
|
574
|
+
r"""
|
|
575
|
+
LaTeX representation of ``self``.
|
|
576
|
+
|
|
577
|
+
EXAMPLES::
|
|
578
|
+
|
|
579
|
+
sage: # needs sage.rings.number_field
|
|
580
|
+
sage: G.<a,b> = DirichletGroup(16)
|
|
581
|
+
sage: latex(b) # indirect doctest
|
|
582
|
+
\hbox{Dirichlet character modulo } 16 \hbox{ of conductor } 16 \hbox{ mapping } 15 \mapsto 1,\ 5 \mapsto \zeta_{4}
|
|
583
|
+
|
|
584
|
+
TESTS:
|
|
585
|
+
|
|
586
|
+
Dirichlet characters modulo 1 and 2 are printed correctly (see
|
|
587
|
+
:issue:`17338`)::
|
|
588
|
+
|
|
589
|
+
sage: latex(DirichletGroup(1)[0])
|
|
590
|
+
\hbox{Dirichlet character modulo } 1 \hbox{ of conductor } 1
|
|
591
|
+
sage: latex(DirichletGroup(2)[0])
|
|
592
|
+
\hbox{Dirichlet character modulo } 2 \hbox{ of conductor } 1
|
|
593
|
+
"""
|
|
594
|
+
s = r'\hbox{Dirichlet character modulo } %s \hbox{ of conductor } %s' % (self.modulus(), self.conductor())
|
|
595
|
+
r = len(self.values_on_gens())
|
|
596
|
+
if r != 0:
|
|
597
|
+
s += r' \hbox{ mapping } '
|
|
598
|
+
for i in range(r):
|
|
599
|
+
if i != 0:
|
|
600
|
+
s += r',\ '
|
|
601
|
+
s += self.parent().unit_gens()[i]._latex_() + r' \mapsto ' + self.values_on_gens()[i]._latex_()
|
|
602
|
+
return s
|
|
603
|
+
|
|
604
|
+
def base_ring(self):
|
|
605
|
+
"""
|
|
606
|
+
Return the base ring of this Dirichlet character.
|
|
607
|
+
|
|
608
|
+
EXAMPLES::
|
|
609
|
+
|
|
610
|
+
sage: G = DirichletGroup(11)
|
|
611
|
+
sage: G.gen(0).base_ring()
|
|
612
|
+
Cyclotomic Field of order 10 and degree 4
|
|
613
|
+
sage: G = DirichletGroup(11, RationalField())
|
|
614
|
+
sage: G.gen(0).base_ring()
|
|
615
|
+
Rational Field
|
|
616
|
+
"""
|
|
617
|
+
return self.parent().base_ring()
|
|
618
|
+
|
|
619
|
+
def bar(self):
|
|
620
|
+
"""
|
|
621
|
+
Return the complex conjugate of this Dirichlet character.
|
|
622
|
+
|
|
623
|
+
EXAMPLES::
|
|
624
|
+
|
|
625
|
+
sage: e = DirichletGroup(5).0
|
|
626
|
+
sage: e
|
|
627
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> zeta4
|
|
628
|
+
sage: e.bar()
|
|
629
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -zeta4
|
|
630
|
+
"""
|
|
631
|
+
return ~self
|
|
632
|
+
|
|
633
|
+
def bernoulli(self, k, algorithm='recurrence', cache=True, **opts):
|
|
634
|
+
r"""
|
|
635
|
+
Return the generalized Bernoulli number `B_{k,eps}`.
|
|
636
|
+
|
|
637
|
+
INPUT:
|
|
638
|
+
|
|
639
|
+
- ``k`` -- nonnegative integer
|
|
640
|
+
|
|
641
|
+
- ``algorithm`` -- either ``'recurrence'`` (default) or
|
|
642
|
+
``'definition'``
|
|
643
|
+
|
|
644
|
+
- ``cache`` -- if ``True``, cache answers
|
|
645
|
+
|
|
646
|
+
- ``**opts`` -- optional arguments; not used directly, but
|
|
647
|
+
passed to the :func:`bernoulli` function if this is called
|
|
648
|
+
|
|
649
|
+
OUTPUT:
|
|
650
|
+
|
|
651
|
+
Let `\varepsilon` be a (not necessarily primitive) character
|
|
652
|
+
of modulus `N`. This function returns the generalized
|
|
653
|
+
Bernoulli number `B_{k,\varepsilon}`, as defined by the
|
|
654
|
+
following identity of power series (see for example
|
|
655
|
+
[DI1995]_, Section 2.2):
|
|
656
|
+
|
|
657
|
+
.. MATH::
|
|
658
|
+
|
|
659
|
+
\sum_{a=1}^N \frac{\varepsilon(a) t e^{at}}{e^{Nt}-1}
|
|
660
|
+
= \sum_{k=0}^{\infty} \frac{B_{k,\varepsilon}}{k!} t^k.
|
|
661
|
+
|
|
662
|
+
ALGORITHM:
|
|
663
|
+
|
|
664
|
+
The ``'recurrence'`` algorithm computes generalized Bernoulli
|
|
665
|
+
numbers via classical Bernoulli numbers using the formula in
|
|
666
|
+
[Coh2007]_, Proposition 9.4.5; this is usually optimal. The
|
|
667
|
+
``definition`` algorithm uses the definition directly.
|
|
668
|
+
|
|
669
|
+
.. WARNING::
|
|
670
|
+
|
|
671
|
+
In the case of the trivial Dirichlet character modulo 1,
|
|
672
|
+
this function returns `B_{1,\varepsilon} = 1/2`, in
|
|
673
|
+
accordance with the above definition, but in contrast to
|
|
674
|
+
the value `B_1 = -1/2` for the classical Bernoulli number.
|
|
675
|
+
Some authors use an alternative definition giving
|
|
676
|
+
`B_{1,\varepsilon} = -1/2`; see the discussion in
|
|
677
|
+
[Coh2007]_, Section 9.4.1.
|
|
678
|
+
|
|
679
|
+
EXAMPLES::
|
|
680
|
+
|
|
681
|
+
sage: G = DirichletGroup(13)
|
|
682
|
+
sage: e = G.0
|
|
683
|
+
sage: e.bernoulli(5)
|
|
684
|
+
7430/13*zeta12^3 - 34750/13*zeta12^2 - 11380/13*zeta12 + 9110/13
|
|
685
|
+
sage: eps = DirichletGroup(9).0
|
|
686
|
+
sage: eps.bernoulli(3)
|
|
687
|
+
10*zeta6 + 4
|
|
688
|
+
sage: eps.bernoulli(3, algorithm='definition')
|
|
689
|
+
10*zeta6 + 4
|
|
690
|
+
|
|
691
|
+
TESTS:
|
|
692
|
+
|
|
693
|
+
Check that :issue:`17586` is fixed::
|
|
694
|
+
|
|
695
|
+
sage: DirichletGroup(1)[0].bernoulli(1)
|
|
696
|
+
1/2
|
|
697
|
+
"""
|
|
698
|
+
if cache:
|
|
699
|
+
try:
|
|
700
|
+
self.__bernoulli
|
|
701
|
+
except AttributeError:
|
|
702
|
+
self.__bernoulli = {}
|
|
703
|
+
if k in self.__bernoulli:
|
|
704
|
+
return self.__bernoulli[k]
|
|
705
|
+
N = self.modulus()
|
|
706
|
+
K = self.base_ring()
|
|
707
|
+
|
|
708
|
+
if N == 1:
|
|
709
|
+
# By definition, the first Bernoulli number of the trivial
|
|
710
|
+
# character is 1/2, in contrast to the value B_1 = -1/2.
|
|
711
|
+
ber = K.one() / 2 if k == 1 else K(bernoulli(k))
|
|
712
|
+
elif self(-1) != K((-1)**k):
|
|
713
|
+
ber = K.zero()
|
|
714
|
+
elif algorithm == "recurrence":
|
|
715
|
+
# The following code is pretty fast, at least compared to
|
|
716
|
+
# the other algorithm below. That said, I'm sure it could
|
|
717
|
+
# be sped up by a factor of 10 or more in many cases,
|
|
718
|
+
# especially since we end up computing all the Bernoulli
|
|
719
|
+
# numbers up to k, which should be done with power series
|
|
720
|
+
# instead of calls to the Bernoulli function. Likewise
|
|
721
|
+
# computing all binomial coefficients can be done much
|
|
722
|
+
# more efficiently.
|
|
723
|
+
v = self.values()
|
|
724
|
+
|
|
725
|
+
def S(n):
|
|
726
|
+
return sum(v[r] * r**n for r in range(1, N))
|
|
727
|
+
|
|
728
|
+
ber = sum(ZZ(k).binomial(j) * bernoulli(j, **opts) *
|
|
729
|
+
N**(j - 1) * S(k - j) for j in range(k + 1))
|
|
730
|
+
elif algorithm == "definition":
|
|
731
|
+
# This is better since it computes the same thing, but requires
|
|
732
|
+
# no arith in a poly ring over a number field.
|
|
733
|
+
prec = k + 2
|
|
734
|
+
R = PowerSeriesRing(QQ, 't')
|
|
735
|
+
t = R.gen()
|
|
736
|
+
# g(t) = t/(e^{Nt}-1)
|
|
737
|
+
g = t / ((N * t).exp(prec) - 1)
|
|
738
|
+
# h(n) = g(t)*e^{nt}
|
|
739
|
+
h = [0] + [g * ((n * t).exp(prec)) for n in range(1, N + 1)]
|
|
740
|
+
ber = sum([self(a) * h[a][k] for a in range(1, N + 1)]) * factorial(k)
|
|
741
|
+
else:
|
|
742
|
+
raise ValueError(f"algorithm = '{algorithm}' unknown")
|
|
743
|
+
|
|
744
|
+
if cache:
|
|
745
|
+
self.__bernoulli[k] = ber
|
|
746
|
+
return ber
|
|
747
|
+
|
|
748
|
+
def lfunction(self, prec=53, algorithm='pari'):
|
|
749
|
+
"""
|
|
750
|
+
Return the `L`-function of ``self``.
|
|
751
|
+
|
|
752
|
+
The result is a wrapper around a PARI `L`-function or around
|
|
753
|
+
the ``lcalc`` program.
|
|
754
|
+
|
|
755
|
+
INPUT:
|
|
756
|
+
|
|
757
|
+
- ``prec`` -- precision (default: 53)
|
|
758
|
+
|
|
759
|
+
- ``algorithm`` -- 'pari' (default) or 'lcalc'
|
|
760
|
+
|
|
761
|
+
EXAMPLES::
|
|
762
|
+
|
|
763
|
+
sage: G.<a,b> = DirichletGroup(20)
|
|
764
|
+
sage: L = a.lfunction(); L
|
|
765
|
+
PARI L-function associated to Dirichlet character modulo 20
|
|
766
|
+
of conductor 4 mapping 11 |--> -1, 17 |--> 1
|
|
767
|
+
sage: L(4)
|
|
768
|
+
0.988944551741105
|
|
769
|
+
|
|
770
|
+
With the algorithm "lcalc"::
|
|
771
|
+
|
|
772
|
+
sage: a = a.primitive_character()
|
|
773
|
+
sage: L = a.lfunction(algorithm='lcalc'); L # needs lcalc
|
|
774
|
+
L-function with complex Dirichlet coefficients
|
|
775
|
+
sage: L.value(4) # abs tol 1e-8 # needs lcalc
|
|
776
|
+
0.988944551741105 + 0.0*I
|
|
777
|
+
"""
|
|
778
|
+
if algorithm is None:
|
|
779
|
+
algorithm = 'pari'
|
|
780
|
+
|
|
781
|
+
if algorithm == 'pari':
|
|
782
|
+
from sage.lfunctions.pari import lfun_character, LFunction
|
|
783
|
+
Z = LFunction(lfun_character(self), prec=prec)
|
|
784
|
+
Z.rename('PARI L-function associated to %s' % self)
|
|
785
|
+
return Z
|
|
786
|
+
elif algorithm == 'lcalc':
|
|
787
|
+
from sage.libs.lcalc.lcalc_Lfunction import Lfunction_from_character
|
|
788
|
+
return Lfunction_from_character(self)
|
|
789
|
+
|
|
790
|
+
raise ValueError('algorithm must be "pari" or "lcalc"')
|
|
791
|
+
|
|
792
|
+
@cached_method
|
|
793
|
+
def conductor(self):
|
|
794
|
+
"""
|
|
795
|
+
Compute and return the conductor of this character.
|
|
796
|
+
|
|
797
|
+
EXAMPLES::
|
|
798
|
+
|
|
799
|
+
sage: G.<a,b> = DirichletGroup(20)
|
|
800
|
+
sage: a.conductor()
|
|
801
|
+
4
|
|
802
|
+
sage: b.conductor()
|
|
803
|
+
5
|
|
804
|
+
sage: (a*b).conductor()
|
|
805
|
+
20
|
|
806
|
+
|
|
807
|
+
TESTS::
|
|
808
|
+
|
|
809
|
+
sage: G.<a, b> = DirichletGroup(20)
|
|
810
|
+
sage: type(G(1).conductor())
|
|
811
|
+
<class 'sage.rings.integer.Integer'>
|
|
812
|
+
"""
|
|
813
|
+
if self.modulus() == 1 or self.is_trivial():
|
|
814
|
+
return Integer(1)
|
|
815
|
+
F = factor(self.modulus())
|
|
816
|
+
if len(F) > 1:
|
|
817
|
+
return prod([d.conductor() for d in self.decomposition()])
|
|
818
|
+
p = F[0][0]
|
|
819
|
+
# When p is odd, and x =/= 1, the conductor is the smallest p**r such that
|
|
820
|
+
# Order(x) divides EulerPhi(p**r) = p**(r-1)*(p-1).
|
|
821
|
+
# For a given r, whether or not the above divisibility holds
|
|
822
|
+
# depends only on the factor of p**(r-1) on the right hand side.
|
|
823
|
+
# Since p-1 is coprime to p, this smallest r such that the
|
|
824
|
+
# divisibility holds equals Valuation(Order(x),p)+1.
|
|
825
|
+
cond = p**(valuation(self.order(), p) + 1)
|
|
826
|
+
if p == 2 and F[0][1] > 2 and self.values_on_gens()[1].multiplicative_order() != 1:
|
|
827
|
+
cond *= 2
|
|
828
|
+
return Integer(cond)
|
|
829
|
+
|
|
830
|
+
@cached_method
|
|
831
|
+
def fixed_field_polynomial(self, algorithm='pari'):
|
|
832
|
+
r"""
|
|
833
|
+
Given a Dirichlet character, this will return a
|
|
834
|
+
polynomial generating the abelian extension fixed by the kernel
|
|
835
|
+
of the corresponding Galois character.
|
|
836
|
+
|
|
837
|
+
ALGORITHM: (Sage)
|
|
838
|
+
|
|
839
|
+
A formula by Gauss for the products of periods;
|
|
840
|
+
see Disquisitiones §343. See the source code for more.
|
|
841
|
+
|
|
842
|
+
OUTPUT: a polynomial with integer coefficients
|
|
843
|
+
|
|
844
|
+
EXAMPLES::
|
|
845
|
+
|
|
846
|
+
sage: G = DirichletGroup(37)
|
|
847
|
+
sage: chi = G.0
|
|
848
|
+
sage: psi = chi^18
|
|
849
|
+
sage: psi.fixed_field_polynomial()
|
|
850
|
+
x^2 + x - 9
|
|
851
|
+
|
|
852
|
+
sage: G = DirichletGroup(7)
|
|
853
|
+
sage: chi = G.0^2
|
|
854
|
+
sage: chi
|
|
855
|
+
Dirichlet character modulo 7 of conductor 7 mapping 3 |--> zeta6 - 1
|
|
856
|
+
sage: chi.fixed_field_polynomial()
|
|
857
|
+
x^3 + x^2 - 2*x - 1
|
|
858
|
+
|
|
859
|
+
sage: G = DirichletGroup(31)
|
|
860
|
+
sage: chi = G.0
|
|
861
|
+
sage: chi^6
|
|
862
|
+
Dirichlet character modulo 31 of conductor 31 mapping 3 |--> zeta30^6
|
|
863
|
+
sage: psi = chi^6
|
|
864
|
+
sage: psi.fixed_field_polynomial()
|
|
865
|
+
x^5 + x^4 - 12*x^3 - 21*x^2 + x + 5
|
|
866
|
+
|
|
867
|
+
sage: G = DirichletGroup(7)
|
|
868
|
+
sage: chi = G.0
|
|
869
|
+
sage: chi.fixed_field_polynomial()
|
|
870
|
+
x^6 + x^5 + x^4 + x^3 + x^2 + x + 1
|
|
871
|
+
|
|
872
|
+
sage: G = DirichletGroup(1001)
|
|
873
|
+
sage: chi = G.0
|
|
874
|
+
sage: psi = chi^3
|
|
875
|
+
sage: psi.order()
|
|
876
|
+
2
|
|
877
|
+
sage: psi.fixed_field_polynomial(algorithm='pari')
|
|
878
|
+
x^2 + x + 2
|
|
879
|
+
|
|
880
|
+
With the Sage implementation::
|
|
881
|
+
|
|
882
|
+
sage: G = DirichletGroup(37)
|
|
883
|
+
sage: chi = G.0
|
|
884
|
+
sage: psi = chi^18
|
|
885
|
+
sage: psi.fixed_field_polynomial(algorithm='sage')
|
|
886
|
+
x^2 + x - 9
|
|
887
|
+
|
|
888
|
+
sage: G = DirichletGroup(7)
|
|
889
|
+
sage: chi = G.0^2
|
|
890
|
+
sage: chi
|
|
891
|
+
Dirichlet character modulo 7 of conductor 7 mapping 3 |--> zeta6 - 1
|
|
892
|
+
sage: chi.fixed_field_polynomial(algorithm='sage')
|
|
893
|
+
x^3 + x^2 - 2*x - 1
|
|
894
|
+
|
|
895
|
+
sage: G = DirichletGroup(31)
|
|
896
|
+
sage: chi = G.0
|
|
897
|
+
sage: chi^6
|
|
898
|
+
Dirichlet character modulo 31 of conductor 31 mapping 3 |--> zeta30^6
|
|
899
|
+
sage: psi = chi^6
|
|
900
|
+
sage: psi.fixed_field_polynomial(algorithm='sage')
|
|
901
|
+
x^5 + x^4 - 12*x^3 - 21*x^2 + x + 5
|
|
902
|
+
|
|
903
|
+
sage: G = DirichletGroup(7)
|
|
904
|
+
sage: chi = G.0
|
|
905
|
+
sage: chi.fixed_field_polynomial(algorithm='sage')
|
|
906
|
+
x^6 + x^5 + x^4 + x^3 + x^2 + x + 1
|
|
907
|
+
|
|
908
|
+
sage: G = DirichletGroup(1001)
|
|
909
|
+
sage: chi = G.0
|
|
910
|
+
sage: psi = chi^3
|
|
911
|
+
sage: psi.order()
|
|
912
|
+
2
|
|
913
|
+
sage: psi.fixed_field_polynomial(algorithm='sage')
|
|
914
|
+
x^2 + x + 2
|
|
915
|
+
|
|
916
|
+
The algorithm must be one of `sage` or `pari`::
|
|
917
|
+
|
|
918
|
+
sage: G = DirichletGroup(1001)
|
|
919
|
+
sage: chi = G.0
|
|
920
|
+
sage: psi = chi^3
|
|
921
|
+
sage: psi.order()
|
|
922
|
+
2
|
|
923
|
+
sage: psi.fixed_field_polynomial(algorithm='banana')
|
|
924
|
+
Traceback (most recent call last):
|
|
925
|
+
...
|
|
926
|
+
NotImplementedError: algorithm must be one of 'pari' or 'sage'
|
|
927
|
+
"""
|
|
928
|
+
|
|
929
|
+
# this algorithm was written by Francis Clarke see issue #9407
|
|
930
|
+
|
|
931
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
932
|
+
from sage.matrix.constructor import matrix
|
|
933
|
+
|
|
934
|
+
if algorithm == "sage":
|
|
935
|
+
n = ZZ(self.conductor())
|
|
936
|
+
if not n.is_prime():
|
|
937
|
+
raise NotImplementedError('the conductor %s is supposed to be prime' % n)
|
|
938
|
+
|
|
939
|
+
d = self.order()
|
|
940
|
+
|
|
941
|
+
# check that there will be such a field of degree d inside QQ(zeta_n)
|
|
942
|
+
if euler_phi(n) % d != 0:
|
|
943
|
+
raise ValueError('No field exists because %s does not divide %s=phi(%s)' % (d, euler_phi(n), n))
|
|
944
|
+
f = euler_phi(n) // d
|
|
945
|
+
|
|
946
|
+
S = PolynomialRing(ZZ, 'x')
|
|
947
|
+
|
|
948
|
+
if f == 1:
|
|
949
|
+
from sage.misc.functional import cyclotomic_polynomial
|
|
950
|
+
return cyclotomic_polynomial(n, S.gen())
|
|
951
|
+
|
|
952
|
+
if d == 2:
|
|
953
|
+
if n.mod(4) == 1:
|
|
954
|
+
s = -1
|
|
955
|
+
else:
|
|
956
|
+
s = 1
|
|
957
|
+
return S([s * (n + s) / 4, 1, 1])
|
|
958
|
+
|
|
959
|
+
# Using the notation of van der Waerden, where $\zeta$ is a primitive
|
|
960
|
+
# $n$-root of unity,
|
|
961
|
+
# $$
|
|
962
|
+
# \eta_i = \sum_{j=0}^{f-1}\zeta^{g^{i+dj}},
|
|
963
|
+
# $$
|
|
964
|
+
# is represented by eta[i] as the list of exponents.
|
|
965
|
+
#
|
|
966
|
+
# gen_index is a dictionary such that gen_index[r] = i if the exponent r
|
|
967
|
+
# occurs in eta[i]. Thus $\eta^{(r)} = \eta_i$ in van der Waerden's
|
|
968
|
+
# notation.
|
|
969
|
+
|
|
970
|
+
R = IntegerModRing(n)
|
|
971
|
+
g = R.unit_gens()[0]
|
|
972
|
+
gen_index = {}
|
|
973
|
+
eta = []
|
|
974
|
+
for i in range(d):
|
|
975
|
+
eta.append([])
|
|
976
|
+
for j in range(f):
|
|
977
|
+
r = g**(i + d * j)
|
|
978
|
+
eta[i].append(r)
|
|
979
|
+
gen_index[r] = i
|
|
980
|
+
|
|
981
|
+
# Using Gauss's formula
|
|
982
|
+
# $$
|
|
983
|
+
# \eta^{(r)}\eta^{(s)} = \sum_{j=0}^{f-1}\eta^{(r+sg^{dj})}
|
|
984
|
+
# $$
|
|
985
|
+
# (with $r=1$), we construct the matrix representing multiplication by
|
|
986
|
+
# $\eta_0=\eta^{(1)}$ with respect to the basis consisting of the $\eta_i$.
|
|
987
|
+
# Its characteristic polynomial generates the field. The element
|
|
988
|
+
# $\eta^(0)$=f=-f\sum_{i=0}^{d-1}\eta_i$ is represented by eta_zero.
|
|
989
|
+
|
|
990
|
+
V = FreeModule(ZZ, d)
|
|
991
|
+
eta_zero = V([-f] * d)
|
|
992
|
+
m = []
|
|
993
|
+
for j in range(d):
|
|
994
|
+
v = 0
|
|
995
|
+
for e in eta[j]:
|
|
996
|
+
try:
|
|
997
|
+
s = V.gen(gen_index[1 + e])
|
|
998
|
+
except KeyError:
|
|
999
|
+
s = eta_zero
|
|
1000
|
+
v += s
|
|
1001
|
+
m.append(v)
|
|
1002
|
+
|
|
1003
|
+
xx = S.gen()
|
|
1004
|
+
return matrix(m).charpoly(xx)
|
|
1005
|
+
|
|
1006
|
+
elif algorithm == "pari":
|
|
1007
|
+
# Use pari
|
|
1008
|
+
G, chi = self._pari_init_()
|
|
1009
|
+
K = pari.charker(G, chi)
|
|
1010
|
+
H = pari.galoissubcyclo(G, K)
|
|
1011
|
+
P = PolynomialRing(QQ, "x")
|
|
1012
|
+
x = P.gen()
|
|
1013
|
+
return H.sage({"x": x})
|
|
1014
|
+
|
|
1015
|
+
else:
|
|
1016
|
+
raise NotImplementedError("algorithm must be one of 'pari' or 'sage'")
|
|
1017
|
+
|
|
1018
|
+
def fixed_field(self):
|
|
1019
|
+
r"""
|
|
1020
|
+
Given a Dirichlet character, this will return the abelian extension
|
|
1021
|
+
fixed by the kernel of the corresponding Galois character.
|
|
1022
|
+
|
|
1023
|
+
OUTPUT: a number field
|
|
1024
|
+
|
|
1025
|
+
EXAMPLES::
|
|
1026
|
+
|
|
1027
|
+
sage: G = DirichletGroup(37)
|
|
1028
|
+
sage: chi = G.0
|
|
1029
|
+
sage: psi = chi^18
|
|
1030
|
+
sage: psi.fixed_field()
|
|
1031
|
+
Number Field in a with defining polynomial x^2 + x - 9
|
|
1032
|
+
|
|
1033
|
+
|
|
1034
|
+
sage: G = DirichletGroup(7)
|
|
1035
|
+
sage: chi = G.0^2
|
|
1036
|
+
sage: chi
|
|
1037
|
+
Dirichlet character modulo 7 of conductor 7 mapping 3 |--> zeta6 - 1
|
|
1038
|
+
sage: chi.fixed_field()
|
|
1039
|
+
Number Field in a with defining polynomial x^3 + x^2 - 2*x - 1
|
|
1040
|
+
|
|
1041
|
+
sage: G = DirichletGroup(31)
|
|
1042
|
+
sage: chi = G.0
|
|
1043
|
+
sage: chi^6
|
|
1044
|
+
Dirichlet character modulo 31 of conductor 31 mapping 3 |--> zeta30^6
|
|
1045
|
+
sage: psi = chi^6
|
|
1046
|
+
sage: psi.fixed_field()
|
|
1047
|
+
Number Field in a with defining polynomial x^5 + x^4 - 12*x^3 - 21*x^2 + x + 5
|
|
1048
|
+
"""
|
|
1049
|
+
return NumberField(self.fixed_field_polynomial(), 'a')
|
|
1050
|
+
|
|
1051
|
+
@cached_method
|
|
1052
|
+
def decomposition(self) -> list:
|
|
1053
|
+
r"""
|
|
1054
|
+
Return the decomposition of ``self`` as a product of Dirichlet
|
|
1055
|
+
characters of prime power modulus, where the prime powers exactly
|
|
1056
|
+
divide the modulus of this character.
|
|
1057
|
+
|
|
1058
|
+
EXAMPLES::
|
|
1059
|
+
|
|
1060
|
+
sage: G.<a,b> = DirichletGroup(20)
|
|
1061
|
+
sage: c = a*b
|
|
1062
|
+
sage: d = c.decomposition(); d
|
|
1063
|
+
[Dirichlet character modulo 4 of conductor 4 mapping 3 |--> -1,
|
|
1064
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> zeta4]
|
|
1065
|
+
sage: d[0].parent()
|
|
1066
|
+
Group of Dirichlet characters modulo 4 with values
|
|
1067
|
+
in Cyclotomic Field of order 4 and degree 2
|
|
1068
|
+
sage: d[1].parent()
|
|
1069
|
+
Group of Dirichlet characters modulo 5 with values
|
|
1070
|
+
in Cyclotomic Field of order 4 and degree 2
|
|
1071
|
+
|
|
1072
|
+
We cannot multiply directly, since coercion of one element into the
|
|
1073
|
+
other parent fails in both cases::
|
|
1074
|
+
|
|
1075
|
+
sage: d[0]*d[1] == c
|
|
1076
|
+
Traceback (most recent call last):
|
|
1077
|
+
...
|
|
1078
|
+
TypeError: unsupported operand parent(s) for *: 'Group of Dirichlet
|
|
1079
|
+
characters modulo 4 with values in Cyclotomic Field of order 4 and
|
|
1080
|
+
degree 2' and 'Group of Dirichlet characters modulo 5 with values
|
|
1081
|
+
in Cyclotomic Field of order 4 and degree 2'
|
|
1082
|
+
|
|
1083
|
+
We can multiply if we are explicit about where we want the
|
|
1084
|
+
multiplication to take place.
|
|
1085
|
+
|
|
1086
|
+
::
|
|
1087
|
+
|
|
1088
|
+
sage: G(d[0])*G(d[1]) == c
|
|
1089
|
+
True
|
|
1090
|
+
|
|
1091
|
+
Conductors that are divisible by various powers of 2 present
|
|
1092
|
+
some problems as the multiplicative group modulo `2^k` is
|
|
1093
|
+
trivial for `k = 1` and non-cyclic for `k \ge 3`::
|
|
1094
|
+
|
|
1095
|
+
sage: (DirichletGroup(18).0).decomposition()
|
|
1096
|
+
[Dirichlet character modulo 2 of conductor 1,
|
|
1097
|
+
Dirichlet character modulo 9 of conductor 9 mapping 2 |--> zeta6]
|
|
1098
|
+
sage: (DirichletGroup(36).0).decomposition()
|
|
1099
|
+
[Dirichlet character modulo 4 of conductor 4 mapping 3 |--> -1,
|
|
1100
|
+
Dirichlet character modulo 9 of conductor 1 mapping 2 |--> 1]
|
|
1101
|
+
sage: (DirichletGroup(72).0).decomposition()
|
|
1102
|
+
[Dirichlet character modulo 8 of conductor 4 mapping 7 |--> -1, 5 |--> 1,
|
|
1103
|
+
Dirichlet character modulo 9 of conductor 1 mapping 2 |--> 1]
|
|
1104
|
+
"""
|
|
1105
|
+
D = self.parent().decomposition()
|
|
1106
|
+
vals = [[z] for z in self.values_on_gens()]
|
|
1107
|
+
if self.modulus() % 8 == 0: # 2 factors at 2.
|
|
1108
|
+
vals[0].append(vals[1][0])
|
|
1109
|
+
del vals[1]
|
|
1110
|
+
elif self.modulus() % 4 == 2: # 0 factors at 2.
|
|
1111
|
+
vals = [1] + vals
|
|
1112
|
+
return [D[i](vals[i]) for i in range(len(D))]
|
|
1113
|
+
|
|
1114
|
+
def extend(self, M):
|
|
1115
|
+
"""
|
|
1116
|
+
Return the extension of this character to a Dirichlet character
|
|
1117
|
+
modulo the multiple ``M`` of the modulus.
|
|
1118
|
+
|
|
1119
|
+
EXAMPLES::
|
|
1120
|
+
|
|
1121
|
+
sage: G.<a,b> = DirichletGroup(20)
|
|
1122
|
+
sage: H.<c> = DirichletGroup(4)
|
|
1123
|
+
sage: c.extend(20)
|
|
1124
|
+
Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1
|
|
1125
|
+
sage: a
|
|
1126
|
+
Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1
|
|
1127
|
+
sage: c.extend(20) == a
|
|
1128
|
+
True
|
|
1129
|
+
"""
|
|
1130
|
+
if M % self.modulus():
|
|
1131
|
+
raise ArithmeticError("M(=%s) must be a multiple of the modulus(=%s)" % (M, self.modulus()))
|
|
1132
|
+
H = DirichletGroup(M, self.base_ring())
|
|
1133
|
+
return H(self)
|
|
1134
|
+
|
|
1135
|
+
def _pari_init_(self):
|
|
1136
|
+
r"""
|
|
1137
|
+
Conversion of the character to Pari.
|
|
1138
|
+
|
|
1139
|
+
OUTPUT:
|
|
1140
|
+
|
|
1141
|
+
pair (G, v) where G is `(\ZZ / N \ZZ)^*` where `N` is the modulus
|
|
1142
|
+
|
|
1143
|
+
EXAMPLES::
|
|
1144
|
+
|
|
1145
|
+
sage: # needs sage.rings.number_field
|
|
1146
|
+
sage: chi4 = DirichletGroup(4).gen()
|
|
1147
|
+
sage: pari(chi4)
|
|
1148
|
+
[[[4, [0]], [2, [2], [3]], [[2]~, Vecsmall([2])],
|
|
1149
|
+
[[4], [[1, matrix(0,2)]], Mat(1), [3], [2], [0]], Mat(1)], [1]]
|
|
1150
|
+
sage: pari.charker(*pari(chi4)).sage()
|
|
1151
|
+
[2]
|
|
1152
|
+
|
|
1153
|
+
sage: chi = DirichletGroup(24)([1,-1,-1]); chi
|
|
1154
|
+
Dirichlet character modulo 24 of conductor 24
|
|
1155
|
+
mapping 7 |--> 1, 13 |--> -1, 17 |--> -1
|
|
1156
|
+
sage: pari(chi)
|
|
1157
|
+
[[[24, [0]], [8, [2, 2, 2], [7, 13, 17]],
|
|
1158
|
+
[[2, 2, 3]~, Vecsmall([3, 3, 1])],
|
|
1159
|
+
[[8, 8, 3], [[1, matrix(0,2)], [1, matrix(0,2)], [2, Mat([2, 1])]],
|
|
1160
|
+
[1, 0, 0; 0, 1, 0; 0, 0, 1], [7, 13, 17], [2, 2, 2], [0, 0, 0]],
|
|
1161
|
+
[1, 0, 0; 0, 1, 0; 0, 0, 1]], [0, 1, 1]]
|
|
1162
|
+
sage: pari.charorder(*pari(chi))
|
|
1163
|
+
2
|
|
1164
|
+
"""
|
|
1165
|
+
G = pari.znstar(self.modulus(), 1)
|
|
1166
|
+
|
|
1167
|
+
pari_orders = G[1][1]
|
|
1168
|
+
pari_gens = G[1][2]
|
|
1169
|
+
# one should use the following, but this does not work
|
|
1170
|
+
# pari_orders = G.cyc()
|
|
1171
|
+
# pari_gens = G.gen()
|
|
1172
|
+
|
|
1173
|
+
values_on_gens = (self(x) for x in pari_gens)
|
|
1174
|
+
|
|
1175
|
+
# now compute the input for pari (list of exponents)
|
|
1176
|
+
P = self.parent()
|
|
1177
|
+
if isinstance(P.base_ring(), sage.rings.abc.ComplexField):
|
|
1178
|
+
zeta = P.zeta()
|
|
1179
|
+
zeta_argument = zeta.argument()
|
|
1180
|
+
v = [int(x.argument() / zeta_argument) for x in values_on_gens]
|
|
1181
|
+
else:
|
|
1182
|
+
dlog = P._zeta_dlog
|
|
1183
|
+
v = [dlog[x] for x in values_on_gens]
|
|
1184
|
+
|
|
1185
|
+
m = P.zeta_order()
|
|
1186
|
+
v = [(vi * oi) // m for vi, oi in zip(v, pari_orders)]
|
|
1187
|
+
return (G, v)
|
|
1188
|
+
|
|
1189
|
+
def conrey_number(self):
|
|
1190
|
+
r"""
|
|
1191
|
+
Return the Conrey number for this character.
|
|
1192
|
+
|
|
1193
|
+
This is a positive integer coprime to `q` that identifies a
|
|
1194
|
+
Dirichlet character of modulus `q`.
|
|
1195
|
+
|
|
1196
|
+
See https://www.lmfdb.org/knowledge/show/character.dirichlet.conrey
|
|
1197
|
+
|
|
1198
|
+
EXAMPLES::
|
|
1199
|
+
|
|
1200
|
+
sage: # needs sage.rings.number_field
|
|
1201
|
+
sage: chi4 = DirichletGroup(4).gen()
|
|
1202
|
+
sage: chi4.conrey_number()
|
|
1203
|
+
3
|
|
1204
|
+
sage: chi = DirichletGroup(24)([1,-1,-1]); chi
|
|
1205
|
+
Dirichlet character modulo 24 of conductor 24
|
|
1206
|
+
mapping 7 |--> 1, 13 |--> -1, 17 |--> -1
|
|
1207
|
+
sage: chi.conrey_number()
|
|
1208
|
+
5
|
|
1209
|
+
|
|
1210
|
+
sage: chi = DirichletGroup(60)([1,-1,I])
|
|
1211
|
+
sage: chi.conrey_number()
|
|
1212
|
+
17
|
|
1213
|
+
|
|
1214
|
+
sage: chi = DirichletGroup(420)([1,-1,-I,1])
|
|
1215
|
+
sage: chi.conrey_number()
|
|
1216
|
+
113
|
|
1217
|
+
|
|
1218
|
+
TESTS::
|
|
1219
|
+
|
|
1220
|
+
sage: eps1 = DirichletGroup(5)([-1])
|
|
1221
|
+
sage: eps2 = DirichletGroup(5,QQ)([-1])
|
|
1222
|
+
sage: eps1.conrey_number() == eps2.conrey_number()
|
|
1223
|
+
True
|
|
1224
|
+
sage: chi = DirichletGroup(1)[0]
|
|
1225
|
+
sage: chi.conrey_number()
|
|
1226
|
+
1
|
|
1227
|
+
"""
|
|
1228
|
+
if self.modulus() == 1:
|
|
1229
|
+
return 1
|
|
1230
|
+
G, v = self._pari_init_()
|
|
1231
|
+
return pari.znconreyexp(G, v).sage()
|
|
1232
|
+
|
|
1233
|
+
def lmfdb_page(self) -> None:
|
|
1234
|
+
r"""
|
|
1235
|
+
Open the LMFDB web page of the character in a browser.
|
|
1236
|
+
|
|
1237
|
+
See https://www.lmfdb.org
|
|
1238
|
+
|
|
1239
|
+
EXAMPLES::
|
|
1240
|
+
|
|
1241
|
+
sage: # needs sage.rings.number_field
|
|
1242
|
+
sage: E = DirichletGroup(4).gen()
|
|
1243
|
+
sage: E.lmfdb_page() # optional -- webbrowser
|
|
1244
|
+
"""
|
|
1245
|
+
import webbrowser
|
|
1246
|
+
lmfdb_url = 'https://www.lmfdb.org/Character/Dirichlet/{}/{}'
|
|
1247
|
+
url = lmfdb_url.format(self.modulus(), self.conrey_number())
|
|
1248
|
+
webbrowser.open(url)
|
|
1249
|
+
|
|
1250
|
+
def galois_orbit(self, sort=True) -> list:
|
|
1251
|
+
r"""
|
|
1252
|
+
Return the orbit of this character under the action of the absolute
|
|
1253
|
+
Galois group of the prime subfield of the base ring.
|
|
1254
|
+
|
|
1255
|
+
EXAMPLES::
|
|
1256
|
+
|
|
1257
|
+
sage: G = DirichletGroup(30); e = G.1
|
|
1258
|
+
sage: e.galois_orbit()
|
|
1259
|
+
[Dirichlet character modulo 30 of conductor 5 mapping 11 |--> 1, 7 |--> -zeta4,
|
|
1260
|
+
Dirichlet character modulo 30 of conductor 5 mapping 11 |--> 1, 7 |--> zeta4]
|
|
1261
|
+
|
|
1262
|
+
Another example::
|
|
1263
|
+
|
|
1264
|
+
sage: G = DirichletGroup(13)
|
|
1265
|
+
sage: G.galois_orbits()
|
|
1266
|
+
[[Dirichlet character modulo 13 of conductor 1 mapping 2 |--> 1],
|
|
1267
|
+
...,
|
|
1268
|
+
[Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -1]]
|
|
1269
|
+
sage: e = G.0
|
|
1270
|
+
sage: e
|
|
1271
|
+
Dirichlet character modulo 13 of conductor 13 mapping 2 |--> zeta12
|
|
1272
|
+
sage: e.galois_orbit()
|
|
1273
|
+
[Dirichlet character modulo 13 of conductor 13 mapping 2 |--> zeta12,
|
|
1274
|
+
Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -zeta12^3 + zeta12,
|
|
1275
|
+
Dirichlet character modulo 13 of conductor 13 mapping 2 |--> zeta12^3 - zeta12,
|
|
1276
|
+
Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -zeta12]
|
|
1277
|
+
sage: e = G.0^2; e
|
|
1278
|
+
Dirichlet character modulo 13 of conductor 13 mapping 2 |--> zeta12^2
|
|
1279
|
+
sage: e.galois_orbit()
|
|
1280
|
+
[Dirichlet character modulo 13 of conductor 13 mapping 2 |--> zeta12^2,
|
|
1281
|
+
Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -zeta12^2 + 1]
|
|
1282
|
+
|
|
1283
|
+
A non-example::
|
|
1284
|
+
|
|
1285
|
+
sage: chi = DirichletGroup(7, Integers(9), zeta = Integers(9)(2)).0
|
|
1286
|
+
sage: chi.galois_orbit()
|
|
1287
|
+
Traceback (most recent call last):
|
|
1288
|
+
...
|
|
1289
|
+
TypeError: Galois orbits only defined if base ring is an integral domain
|
|
1290
|
+
"""
|
|
1291
|
+
if not self.base_ring().is_integral_domain():
|
|
1292
|
+
raise TypeError("Galois orbits only defined if base ring is an integral domain")
|
|
1293
|
+
k = self.order()
|
|
1294
|
+
if k <= 2:
|
|
1295
|
+
return [self]
|
|
1296
|
+
P = self.parent()
|
|
1297
|
+
z = self.element()
|
|
1298
|
+
o = int(z.additive_order())
|
|
1299
|
+
Auts = {m % o for m in P._automorphisms()}
|
|
1300
|
+
v = [P.element_class(P, m * z, check=False) for m in Auts]
|
|
1301
|
+
if sort:
|
|
1302
|
+
v.sort()
|
|
1303
|
+
return v
|
|
1304
|
+
|
|
1305
|
+
def gauss_sum(self, a=1):
|
|
1306
|
+
r"""
|
|
1307
|
+
Return a Gauss sum associated to this Dirichlet character.
|
|
1308
|
+
|
|
1309
|
+
The Gauss sum associated to `\chi` is
|
|
1310
|
+
|
|
1311
|
+
.. MATH::
|
|
1312
|
+
|
|
1313
|
+
g_a(\chi) = \sum_{r \in \ZZ/m\ZZ} \chi(r)\,\zeta^{ar},
|
|
1314
|
+
|
|
1315
|
+
where `m` is the modulus of `\chi` and `\zeta` is a primitive
|
|
1316
|
+
`m`-th root of unity.
|
|
1317
|
+
|
|
1318
|
+
FACTS: If the modulus is a prime `p` and the character is
|
|
1319
|
+
nontrivial, then the Gauss sum has absolute value `\sqrt{p}`.
|
|
1320
|
+
|
|
1321
|
+
CACHING: Computed Gauss sums are *not* cached with this character.
|
|
1322
|
+
|
|
1323
|
+
EXAMPLES::
|
|
1324
|
+
|
|
1325
|
+
sage: G = DirichletGroup(3)
|
|
1326
|
+
sage: e = G([-1])
|
|
1327
|
+
sage: e.gauss_sum(1)
|
|
1328
|
+
2*zeta6 - 1
|
|
1329
|
+
sage: e.gauss_sum(2)
|
|
1330
|
+
-2*zeta6 + 1
|
|
1331
|
+
sage: norm(e.gauss_sum())
|
|
1332
|
+
3
|
|
1333
|
+
|
|
1334
|
+
::
|
|
1335
|
+
|
|
1336
|
+
sage: G = DirichletGroup(13)
|
|
1337
|
+
sage: e = G.0
|
|
1338
|
+
sage: e.gauss_sum()
|
|
1339
|
+
-zeta156^46 + zeta156^45 + zeta156^42 + zeta156^41 + 2*zeta156^40
|
|
1340
|
+
+ zeta156^37 - zeta156^36 - zeta156^34 - zeta156^33 - zeta156^31
|
|
1341
|
+
+ 2*zeta156^30 + zeta156^28 - zeta156^24 - zeta156^22 + zeta156^21
|
|
1342
|
+
+ zeta156^20 - zeta156^19 + zeta156^18 - zeta156^16 - zeta156^15
|
|
1343
|
+
- 2*zeta156^14 - zeta156^10 + zeta156^8 + zeta156^7 + zeta156^6
|
|
1344
|
+
+ zeta156^5 - zeta156^4 - zeta156^2 - 1
|
|
1345
|
+
sage: factor(norm(e.gauss_sum()))
|
|
1346
|
+
13^24
|
|
1347
|
+
|
|
1348
|
+
TESTS:
|
|
1349
|
+
|
|
1350
|
+
The field of algebraic numbers is supported (:issue:`19056`)::
|
|
1351
|
+
|
|
1352
|
+
sage: G = DirichletGroup(7, QQbar)
|
|
1353
|
+
sage: G[1].gauss_sum()
|
|
1354
|
+
-2.440133358345538? + 1.022618791871794?*I
|
|
1355
|
+
|
|
1356
|
+
Check that :issue:`19060` is fixed::
|
|
1357
|
+
|
|
1358
|
+
sage: K.<z> = CyclotomicField(8)
|
|
1359
|
+
sage: G = DirichletGroup(13, K)
|
|
1360
|
+
sage: chi = G([z^2])
|
|
1361
|
+
sage: chi.gauss_sum()
|
|
1362
|
+
zeta52^22 + zeta52^21 + zeta52^19 - zeta52^16 + zeta52^15 + zeta52^14
|
|
1363
|
+
+ zeta52^12 - zeta52^11 - zeta52^10 - zeta52^7 - zeta52^5 + zeta52^4
|
|
1364
|
+
|
|
1365
|
+
Check that :issue:`25127` is fixed::
|
|
1366
|
+
|
|
1367
|
+
sage: G = DirichletGroup(1)
|
|
1368
|
+
sage: chi = G.one()
|
|
1369
|
+
sage: chi.gauss_sum()
|
|
1370
|
+
1
|
|
1371
|
+
|
|
1372
|
+
.. SEEALSO::
|
|
1373
|
+
|
|
1374
|
+
- :func:`sage.arith.misc.gauss_sum` for general finite fields
|
|
1375
|
+
- :func:`sage.rings.padics.misc.gauss_sum` for a `p`-adic version
|
|
1376
|
+
"""
|
|
1377
|
+
G = self.parent()
|
|
1378
|
+
K = G.base_ring()
|
|
1379
|
+
chi = self
|
|
1380
|
+
m = G.modulus()
|
|
1381
|
+
if isinstance(K, sage.rings.abc.ComplexField):
|
|
1382
|
+
return self.gauss_sum_numerical(a=a)
|
|
1383
|
+
elif isinstance(K, sage.rings.abc.AlgebraicField):
|
|
1384
|
+
L = K
|
|
1385
|
+
zeta = L.zeta(m)
|
|
1386
|
+
elif isinstance(K, (sage.rings.abc.NumberField_cyclotomic,
|
|
1387
|
+
RationalField)):
|
|
1388
|
+
chi = chi.minimize_base_ring()
|
|
1389
|
+
n = lcm(m, G.zeta_order())
|
|
1390
|
+
L = CyclotomicField(n)
|
|
1391
|
+
zeta = L.gen(0) ** (n // m)
|
|
1392
|
+
else:
|
|
1393
|
+
raise NotImplementedError("Gauss sums only currently implemented when the base ring is a cyclotomic field, QQ, QQbar, or a complex field")
|
|
1394
|
+
zeta = zeta ** a
|
|
1395
|
+
g = L(chi(0))
|
|
1396
|
+
z = L.one()
|
|
1397
|
+
for c in chi.values()[1:]:
|
|
1398
|
+
z *= zeta
|
|
1399
|
+
g += L(c) * z
|
|
1400
|
+
return g
|
|
1401
|
+
|
|
1402
|
+
def gauss_sum_numerical(self, prec=53, a=1):
|
|
1403
|
+
r"""
|
|
1404
|
+
Return a Gauss sum associated to this Dirichlet character as an
|
|
1405
|
+
approximate complex number with ``prec`` bits of precision.
|
|
1406
|
+
|
|
1407
|
+
INPUT:
|
|
1408
|
+
|
|
1409
|
+
- ``prec`` -- integer (default: 53); *bits* of precision
|
|
1410
|
+
|
|
1411
|
+
- ``a`` -- integer; as for :meth:`gauss_sum`
|
|
1412
|
+
|
|
1413
|
+
The Gauss sum associated to `\chi` is
|
|
1414
|
+
|
|
1415
|
+
.. MATH::
|
|
1416
|
+
|
|
1417
|
+
g_a(\chi) = \sum_{r \in \ZZ/m\ZZ} \chi(r)\,\zeta^{ar},
|
|
1418
|
+
|
|
1419
|
+
where `m` is the modulus of `\chi` and `\zeta` is a primitive
|
|
1420
|
+
`m`-th root of unity.
|
|
1421
|
+
|
|
1422
|
+
EXAMPLES::
|
|
1423
|
+
|
|
1424
|
+
sage: G = DirichletGroup(3)
|
|
1425
|
+
sage: e = G.0
|
|
1426
|
+
sage: abs(e.gauss_sum_numerical())
|
|
1427
|
+
1.7320508075...
|
|
1428
|
+
sage: sqrt(3.0)
|
|
1429
|
+
1.73205080756888
|
|
1430
|
+
sage: e.gauss_sum_numerical(a=2)
|
|
1431
|
+
-...e-15 - 1.7320508075...*I
|
|
1432
|
+
sage: e.gauss_sum_numerical(a=2, prec=100)
|
|
1433
|
+
4.7331654313260708324703713917e-30 - 1.7320508075688772935274463415*I
|
|
1434
|
+
sage: G = DirichletGroup(13)
|
|
1435
|
+
sage: H = DirichletGroup(13, CC)
|
|
1436
|
+
sage: e = G.0
|
|
1437
|
+
sage: f = H.0
|
|
1438
|
+
sage: e.gauss_sum_numerical()
|
|
1439
|
+
-3.07497205... + 1.8826966926...*I
|
|
1440
|
+
sage: f.gauss_sum_numerical()
|
|
1441
|
+
-3.07497205... + 1.8826966926...*I
|
|
1442
|
+
sage: abs(e.gauss_sum_numerical())
|
|
1443
|
+
3.60555127546...
|
|
1444
|
+
sage: abs(f.gauss_sum_numerical())
|
|
1445
|
+
3.60555127546...
|
|
1446
|
+
sage: sqrt(13.0)
|
|
1447
|
+
3.60555127546399
|
|
1448
|
+
|
|
1449
|
+
TESTS:
|
|
1450
|
+
|
|
1451
|
+
The field of algebraic numbers is supported (:issue:`19056`)::
|
|
1452
|
+
|
|
1453
|
+
sage: G = DirichletGroup(7, QQbar)
|
|
1454
|
+
sage: G[1].gauss_sum_numerical()
|
|
1455
|
+
-2.44013335834554 + 1.02261879187179*I
|
|
1456
|
+
"""
|
|
1457
|
+
G = self.parent()
|
|
1458
|
+
K = G.base_ring()
|
|
1459
|
+
if isinstance(K, sage.rings.abc.ComplexField):
|
|
1460
|
+
|
|
1461
|
+
def phi(t):
|
|
1462
|
+
return t
|
|
1463
|
+
CC = K
|
|
1464
|
+
elif isinstance(K, sage.rings.abc.AlgebraicField):
|
|
1465
|
+
from sage.rings.complex_mpfr import ComplexField
|
|
1466
|
+
CC = ComplexField(prec)
|
|
1467
|
+
phi = CC.coerce_map_from(K)
|
|
1468
|
+
elif isinstance(K, (sage.rings.abc.NumberField_cyclotomic,
|
|
1469
|
+
RationalField)):
|
|
1470
|
+
phi = K.complex_embedding(prec)
|
|
1471
|
+
CC = phi.codomain()
|
|
1472
|
+
else:
|
|
1473
|
+
raise NotImplementedError("Gauss sums only currently implemented when the base ring is a cyclotomic field, QQ, QQbar, or a complex field")
|
|
1474
|
+
zeta = CC.zeta(G.modulus()) ** a
|
|
1475
|
+
g = phi(self(0))
|
|
1476
|
+
z = CC.one()
|
|
1477
|
+
for c in self.values()[1:]:
|
|
1478
|
+
z *= zeta
|
|
1479
|
+
g += phi(c) * z
|
|
1480
|
+
return g
|
|
1481
|
+
|
|
1482
|
+
def jacobi_sum(self, char, check=True):
|
|
1483
|
+
r"""
|
|
1484
|
+
Return the Jacobi sum associated to these Dirichlet characters
|
|
1485
|
+
(i.e., J(self,char)).
|
|
1486
|
+
|
|
1487
|
+
This is defined as
|
|
1488
|
+
|
|
1489
|
+
.. MATH::
|
|
1490
|
+
|
|
1491
|
+
J(\chi, \psi) = \sum_{a \in \ZZ / N\ZZ} \chi(a) \psi(1-a)
|
|
1492
|
+
|
|
1493
|
+
where `\chi` and `\psi` are both characters modulo `N`.
|
|
1494
|
+
|
|
1495
|
+
EXAMPLES::
|
|
1496
|
+
|
|
1497
|
+
sage: D = DirichletGroup(13)
|
|
1498
|
+
sage: e = D.0
|
|
1499
|
+
sage: f = D[-2]
|
|
1500
|
+
sage: e.jacobi_sum(f)
|
|
1501
|
+
3*zeta12^2 + 2*zeta12 - 3
|
|
1502
|
+
sage: f.jacobi_sum(e)
|
|
1503
|
+
3*zeta12^2 + 2*zeta12 - 3
|
|
1504
|
+
sage: p = 7
|
|
1505
|
+
sage: DP = DirichletGroup(p)
|
|
1506
|
+
sage: f = DP.0
|
|
1507
|
+
sage: e.jacobi_sum(f)
|
|
1508
|
+
Traceback (most recent call last):
|
|
1509
|
+
...
|
|
1510
|
+
NotImplementedError: Characters must be from the same Dirichlet Group.
|
|
1511
|
+
|
|
1512
|
+
sage: all_jacobi_sums = [(DP[i].values_on_gens(),
|
|
1513
|
+
....: DP[j].values_on_gens(),
|
|
1514
|
+
....: DP[i].jacobi_sum(DP[j]))
|
|
1515
|
+
....: for i in range(p - 1) for j in range(i, p - 1)]
|
|
1516
|
+
sage: for s in all_jacobi_sums:
|
|
1517
|
+
....: print(s)
|
|
1518
|
+
((1,), (1,), 5)
|
|
1519
|
+
((1,), (zeta6,), -1)
|
|
1520
|
+
((1,), (zeta6 - 1,), -1)
|
|
1521
|
+
((1,), (-1,), -1)
|
|
1522
|
+
((1,), (-zeta6,), -1)
|
|
1523
|
+
((1,), (-zeta6 + 1,), -1)
|
|
1524
|
+
((zeta6,), (zeta6,), -zeta6 + 3)
|
|
1525
|
+
((zeta6,), (zeta6 - 1,), 2*zeta6 + 1)
|
|
1526
|
+
((zeta6,), (-1,), -2*zeta6 - 1)
|
|
1527
|
+
((zeta6,), (-zeta6,), zeta6 - 3)
|
|
1528
|
+
((zeta6,), (-zeta6 + 1,), 1)
|
|
1529
|
+
((zeta6 - 1,), (zeta6 - 1,), -3*zeta6 + 2)
|
|
1530
|
+
((zeta6 - 1,), (-1,), 2*zeta6 + 1)
|
|
1531
|
+
((zeta6 - 1,), (-zeta6,), -1)
|
|
1532
|
+
((zeta6 - 1,), (-zeta6 + 1,), -zeta6 - 2)
|
|
1533
|
+
((-1,), (-1,), 1)
|
|
1534
|
+
((-1,), (-zeta6,), -2*zeta6 + 3)
|
|
1535
|
+
((-1,), (-zeta6 + 1,), 2*zeta6 - 3)
|
|
1536
|
+
((-zeta6,), (-zeta6,), 3*zeta6 - 1)
|
|
1537
|
+
((-zeta6,), (-zeta6 + 1,), -2*zeta6 + 3)
|
|
1538
|
+
((-zeta6 + 1,), (-zeta6 + 1,), zeta6 + 2)
|
|
1539
|
+
|
|
1540
|
+
Let's check that trivial sums are being calculated correctly::
|
|
1541
|
+
|
|
1542
|
+
sage: N = 13
|
|
1543
|
+
sage: D = DirichletGroup(N)
|
|
1544
|
+
sage: g = D(1)
|
|
1545
|
+
sage: g.jacobi_sum(g)
|
|
1546
|
+
11
|
|
1547
|
+
sage: sum([g(x)*g(1-x) for x in IntegerModRing(N)])
|
|
1548
|
+
11
|
|
1549
|
+
|
|
1550
|
+
And sums where exactly one character is nontrivial (see :issue:`6393`)::
|
|
1551
|
+
|
|
1552
|
+
sage: G = DirichletGroup(5); X = G.list(); Y = X[0]; Z = X[1]
|
|
1553
|
+
sage: Y.jacobi_sum(Z)
|
|
1554
|
+
-1
|
|
1555
|
+
sage: Z.jacobi_sum(Y)
|
|
1556
|
+
-1
|
|
1557
|
+
|
|
1558
|
+
Now let's take a look at a non-prime modulus::
|
|
1559
|
+
|
|
1560
|
+
sage: N = 9
|
|
1561
|
+
sage: D = DirichletGroup(N)
|
|
1562
|
+
sage: g = D(1)
|
|
1563
|
+
sage: g.jacobi_sum(g)
|
|
1564
|
+
3
|
|
1565
|
+
|
|
1566
|
+
We consider a sum with values in a finite field::
|
|
1567
|
+
|
|
1568
|
+
sage: g = DirichletGroup(17, GF(9,'a')).0
|
|
1569
|
+
sage: g.jacobi_sum(g**2)
|
|
1570
|
+
2*a
|
|
1571
|
+
|
|
1572
|
+
TESTS:
|
|
1573
|
+
|
|
1574
|
+
This shows that :issue:`6393` has been fixed::
|
|
1575
|
+
|
|
1576
|
+
sage: G = DirichletGroup(5); X = G.list(); Y = X[0]; Z = X[1]
|
|
1577
|
+
sage: # Y is trivial and Z is quartic
|
|
1578
|
+
sage: sum([Y(x)*Z(1-x) for x in IntegerModRing(5)])
|
|
1579
|
+
-1
|
|
1580
|
+
sage: # The value -1 above is the correct value of the Jacobi sum J(Y, Z).
|
|
1581
|
+
sage: Y.jacobi_sum(Z); Z.jacobi_sum(Y)
|
|
1582
|
+
-1
|
|
1583
|
+
-1
|
|
1584
|
+
"""
|
|
1585
|
+
if check:
|
|
1586
|
+
if self.parent() != char.parent():
|
|
1587
|
+
raise NotImplementedError("Characters must be from the same Dirichlet Group.")
|
|
1588
|
+
|
|
1589
|
+
return sum([self(x) * char(1 - x)
|
|
1590
|
+
for x in IntegerModRing(self.modulus())])
|
|
1591
|
+
|
|
1592
|
+
def kloosterman_sum(self, a=1, b=0):
|
|
1593
|
+
r"""
|
|
1594
|
+
Return the "twisted" Kloosterman sum associated to this Dirichlet character.
|
|
1595
|
+
|
|
1596
|
+
This includes Gauss sums, classical Kloosterman sums, Salié sums, etc.
|
|
1597
|
+
|
|
1598
|
+
The Kloosterman sum associated to `\chi` and the integers a,b is
|
|
1599
|
+
|
|
1600
|
+
.. MATH::
|
|
1601
|
+
|
|
1602
|
+
K(a,b,\chi) = \sum_{r \in (\ZZ/m\ZZ)^\times} \chi(r)\,\zeta^{ar+br^{-1}},
|
|
1603
|
+
|
|
1604
|
+
where `m` is the modulus of `\chi` and `\zeta` is a primitive
|
|
1605
|
+
`m` th root of unity. This reduces to the Gauss sum if `b=0`.
|
|
1606
|
+
|
|
1607
|
+
This method performs an exact calculation and returns an element of a
|
|
1608
|
+
suitable cyclotomic field; see also :meth:`.kloosterman_sum_numerical`,
|
|
1609
|
+
which gives an inexact answer (but is generally much quicker).
|
|
1610
|
+
|
|
1611
|
+
CACHING: Computed Kloosterman sums are *not* cached with this
|
|
1612
|
+
character.
|
|
1613
|
+
|
|
1614
|
+
EXAMPLES::
|
|
1615
|
+
|
|
1616
|
+
sage: G = DirichletGroup(3)
|
|
1617
|
+
sage: e = G([-1])
|
|
1618
|
+
sage: e.kloosterman_sum(3,5)
|
|
1619
|
+
-2*zeta6 + 1
|
|
1620
|
+
sage: G = DirichletGroup(20)
|
|
1621
|
+
sage: e = G([1 for u in G.unit_gens()])
|
|
1622
|
+
sage: e.kloosterman_sum(7,17)
|
|
1623
|
+
-2*zeta20^6 + 2*zeta20^4 + 4
|
|
1624
|
+
|
|
1625
|
+
TESTS::
|
|
1626
|
+
|
|
1627
|
+
sage: # needs sage.libs.gap sage.rings.number_field
|
|
1628
|
+
sage: G = DirichletGroup(20, UniversalCyclotomicField())
|
|
1629
|
+
sage: e = G([1 for u in G.unit_gens()])
|
|
1630
|
+
sage: e.kloosterman_sum(7,17)
|
|
1631
|
+
-2*E(5) - 4*E(5)^2 - 4*E(5)^3 - 2*E(5)^4
|
|
1632
|
+
|
|
1633
|
+
sage: # needs sage.rings.number_field
|
|
1634
|
+
sage: G = DirichletGroup(12, QQbar)
|
|
1635
|
+
sage: e = G.gens()[0]
|
|
1636
|
+
sage: e.kloosterman_sum(5, 4)
|
|
1637
|
+
0.?e-17 - 4.000000000000000?*I
|
|
1638
|
+
sage: e.kloosterman_sum(5,11)
|
|
1639
|
+
0
|
|
1640
|
+
"""
|
|
1641
|
+
G = self.parent()
|
|
1642
|
+
zo = G.zeta_order()
|
|
1643
|
+
m = G.modulus()
|
|
1644
|
+
g = 0
|
|
1645
|
+
L = CyclotomicField(m.lcm(zo))
|
|
1646
|
+
zeta = L.gen(0)
|
|
1647
|
+
try:
|
|
1648
|
+
self(1) * zeta**(a + b)
|
|
1649
|
+
except TypeError:
|
|
1650
|
+
raise NotImplementedError('Kloosterman sums not implemented '
|
|
1651
|
+
'over this ring')
|
|
1652
|
+
n = zeta.multiplicative_order()
|
|
1653
|
+
zeta = zeta**(n // m)
|
|
1654
|
+
for c in m.coprime_integers(m):
|
|
1655
|
+
e = Mod(c, m)
|
|
1656
|
+
g += self(c) * zeta**int(a * e + b * e**(-1))
|
|
1657
|
+
return g
|
|
1658
|
+
|
|
1659
|
+
def kloosterman_sum_numerical(self, prec=53, a=1, b=0):
|
|
1660
|
+
r"""
|
|
1661
|
+
Return the Kloosterman sum associated to this Dirichlet character as
|
|
1662
|
+
an approximate complex number with ``prec`` bits of precision.
|
|
1663
|
+
|
|
1664
|
+
See also :meth:`.kloosterman_sum`, which calculates the sum
|
|
1665
|
+
exactly (which is generally slower).
|
|
1666
|
+
|
|
1667
|
+
INPUT:
|
|
1668
|
+
|
|
1669
|
+
- ``prec`` -- integer (default: 53); *bits* of precision
|
|
1670
|
+
- ``a`` -- integer; as for :meth:`.kloosterman_sum`
|
|
1671
|
+
- ``b`` -- integer; as for :meth:`.kloosterman_sum`
|
|
1672
|
+
|
|
1673
|
+
EXAMPLES::
|
|
1674
|
+
|
|
1675
|
+
sage: G = DirichletGroup(3)
|
|
1676
|
+
sage: e = G.0
|
|
1677
|
+
|
|
1678
|
+
The real component of the numerical value of e is near zero::
|
|
1679
|
+
|
|
1680
|
+
sage: v = e.kloosterman_sum_numerical()
|
|
1681
|
+
sage: v.real() < 1.0e15
|
|
1682
|
+
True
|
|
1683
|
+
sage: v.imag()
|
|
1684
|
+
1.73205080756888
|
|
1685
|
+
sage: G = DirichletGroup(20)
|
|
1686
|
+
sage: e = G.1
|
|
1687
|
+
sage: e.kloosterman_sum_numerical(53,3,11)
|
|
1688
|
+
3.80422606518061 - 3.80422606518061*I
|
|
1689
|
+
"""
|
|
1690
|
+
G = self.parent()
|
|
1691
|
+
K = G.base_ring()
|
|
1692
|
+
if not isinstance(K, (sage.rings.abc.NumberField_cyclotomic,
|
|
1693
|
+
RationalField)):
|
|
1694
|
+
raise NotImplementedError("Kloosterman sums only currently implemented when the base ring is a cyclotomic field or QQ")
|
|
1695
|
+
phi = K.complex_embedding(prec)
|
|
1696
|
+
CC = phi.codomain()
|
|
1697
|
+
g = 0
|
|
1698
|
+
m = G.modulus()
|
|
1699
|
+
zeta = CC.zeta(m)
|
|
1700
|
+
for c in m.coprime_integers(m):
|
|
1701
|
+
e = Mod(c, m)
|
|
1702
|
+
z = zeta ** int(a * e + b * (e**(-1)))
|
|
1703
|
+
g += phi(self(c)) * z
|
|
1704
|
+
return g
|
|
1705
|
+
|
|
1706
|
+
@cached_method
|
|
1707
|
+
def is_even(self) -> bool:
|
|
1708
|
+
r"""
|
|
1709
|
+
Return ``True`` if and only if `\varepsilon(-1) = 1`.
|
|
1710
|
+
|
|
1711
|
+
EXAMPLES::
|
|
1712
|
+
|
|
1713
|
+
sage: G = DirichletGroup(13)
|
|
1714
|
+
sage: e = G.0
|
|
1715
|
+
sage: e.is_even()
|
|
1716
|
+
False
|
|
1717
|
+
sage: e(-1)
|
|
1718
|
+
-1
|
|
1719
|
+
sage: [e.is_even() for e in G]
|
|
1720
|
+
[True, False, True, False, True, False, True, False, True, False, True, False]
|
|
1721
|
+
|
|
1722
|
+
sage: G = DirichletGroup(13, CC)
|
|
1723
|
+
sage: e = G.0
|
|
1724
|
+
sage: e.is_even()
|
|
1725
|
+
False
|
|
1726
|
+
sage: e(-1)
|
|
1727
|
+
-1.000000...
|
|
1728
|
+
sage: [e.is_even() for e in G]
|
|
1729
|
+
[True, False, True, False, True, False, True, False, True, False, True, False]
|
|
1730
|
+
|
|
1731
|
+
sage: G = DirichletGroup(100000, CC)
|
|
1732
|
+
sage: G.1.is_even()
|
|
1733
|
+
True
|
|
1734
|
+
|
|
1735
|
+
Note that ``is_even`` need not be the negation of
|
|
1736
|
+
is_odd, e.g., in characteristic 2::
|
|
1737
|
+
|
|
1738
|
+
sage: G.<e> = DirichletGroup(13, GF(4,'a'))
|
|
1739
|
+
sage: e.is_even()
|
|
1740
|
+
True
|
|
1741
|
+
sage: e.is_odd()
|
|
1742
|
+
True
|
|
1743
|
+
"""
|
|
1744
|
+
R = self.base_ring()
|
|
1745
|
+
# self(-1) is either +1 or -1
|
|
1746
|
+
if not R.is_exact():
|
|
1747
|
+
return abs(self(-1) - R.one()) < 0.5
|
|
1748
|
+
return self(-1) == R.one()
|
|
1749
|
+
|
|
1750
|
+
@cached_method
|
|
1751
|
+
def is_odd(self) -> bool:
|
|
1752
|
+
r"""
|
|
1753
|
+
Return ``True`` if and only if `\varepsilon(-1) = -1`.
|
|
1754
|
+
|
|
1755
|
+
EXAMPLES::
|
|
1756
|
+
|
|
1757
|
+
sage: G = DirichletGroup(13)
|
|
1758
|
+
sage: e = G.0
|
|
1759
|
+
sage: e.is_odd()
|
|
1760
|
+
True
|
|
1761
|
+
sage: [e.is_odd() for e in G]
|
|
1762
|
+
[False, True, False, True, False, True, False, True, False, True, False, True]
|
|
1763
|
+
|
|
1764
|
+
sage: G = DirichletGroup(13)
|
|
1765
|
+
sage: e = G.0
|
|
1766
|
+
sage: e.is_odd()
|
|
1767
|
+
True
|
|
1768
|
+
sage: [e.is_odd() for e in G]
|
|
1769
|
+
[False, True, False, True, False, True, False, True, False, True, False, True]
|
|
1770
|
+
|
|
1771
|
+
sage: G = DirichletGroup(100000, CC)
|
|
1772
|
+
sage: G.0.is_odd()
|
|
1773
|
+
True
|
|
1774
|
+
|
|
1775
|
+
Note that ``is_even`` need not be the negation of
|
|
1776
|
+
is_odd, e.g., in characteristic 2::
|
|
1777
|
+
|
|
1778
|
+
sage: G.<e> = DirichletGroup(13, GF(4,'a'))
|
|
1779
|
+
sage: e.is_even()
|
|
1780
|
+
True
|
|
1781
|
+
sage: e.is_odd()
|
|
1782
|
+
True
|
|
1783
|
+
"""
|
|
1784
|
+
R = self.base_ring()
|
|
1785
|
+
# self(-1) is either +1 or -1
|
|
1786
|
+
if not R.is_exact():
|
|
1787
|
+
return abs(self(-1) - R(-1)) < 0.5
|
|
1788
|
+
return self(-1) == R(-1)
|
|
1789
|
+
|
|
1790
|
+
@cached_method
|
|
1791
|
+
def is_primitive(self) -> bool:
|
|
1792
|
+
"""
|
|
1793
|
+
Return ``True`` if and only if this character is
|
|
1794
|
+
primitive, i.e., its conductor equals its modulus.
|
|
1795
|
+
|
|
1796
|
+
EXAMPLES::
|
|
1797
|
+
|
|
1798
|
+
sage: G.<a,b> = DirichletGroup(20)
|
|
1799
|
+
sage: a.is_primitive()
|
|
1800
|
+
False
|
|
1801
|
+
sage: b.is_primitive()
|
|
1802
|
+
False
|
|
1803
|
+
sage: (a*b).is_primitive()
|
|
1804
|
+
True
|
|
1805
|
+
sage: G.<a,b> = DirichletGroup(20, CC)
|
|
1806
|
+
sage: a.is_primitive()
|
|
1807
|
+
False
|
|
1808
|
+
sage: b.is_primitive()
|
|
1809
|
+
False
|
|
1810
|
+
sage: (a*b).is_primitive()
|
|
1811
|
+
True
|
|
1812
|
+
"""
|
|
1813
|
+
return (self.conductor() == self.modulus())
|
|
1814
|
+
|
|
1815
|
+
@cached_method
|
|
1816
|
+
def is_trivial(self) -> bool:
|
|
1817
|
+
r"""
|
|
1818
|
+
Return ``True`` if this is the trivial character,
|
|
1819
|
+
i.e., has order 1.
|
|
1820
|
+
|
|
1821
|
+
EXAMPLES::
|
|
1822
|
+
|
|
1823
|
+
sage: G.<a,b> = DirichletGroup(20)
|
|
1824
|
+
sage: a.is_trivial()
|
|
1825
|
+
False
|
|
1826
|
+
sage: (a^2).is_trivial()
|
|
1827
|
+
True
|
|
1828
|
+
"""
|
|
1829
|
+
if self.element.is_in_cache():
|
|
1830
|
+
return not self.element()
|
|
1831
|
+
one = self.base_ring().one()
|
|
1832
|
+
return all(x == one for x in self.values_on_gens())
|
|
1833
|
+
|
|
1834
|
+
def kernel(self) -> list:
|
|
1835
|
+
r"""
|
|
1836
|
+
Return the kernel of this character.
|
|
1837
|
+
|
|
1838
|
+
OUTPUT: currently the kernel is returned as a list; this may
|
|
1839
|
+
change
|
|
1840
|
+
|
|
1841
|
+
EXAMPLES::
|
|
1842
|
+
|
|
1843
|
+
sage: G.<a,b> = DirichletGroup(20)
|
|
1844
|
+
sage: a.kernel()
|
|
1845
|
+
[1, 9, 13, 17]
|
|
1846
|
+
sage: b.kernel()
|
|
1847
|
+
[1, 11]
|
|
1848
|
+
"""
|
|
1849
|
+
one = self.base_ring().one()
|
|
1850
|
+
return [x for x in range(self.modulus()) if self(x) == one]
|
|
1851
|
+
|
|
1852
|
+
def maximize_base_ring(self):
|
|
1853
|
+
r"""
|
|
1854
|
+
Let
|
|
1855
|
+
|
|
1856
|
+
.. MATH::
|
|
1857
|
+
|
|
1858
|
+
\varepsilon : (\ZZ/N\ZZ)^* \to \QQ(\zeta_n)
|
|
1859
|
+
|
|
1860
|
+
be a Dirichlet character. This function returns an equal Dirichlet
|
|
1861
|
+
character
|
|
1862
|
+
|
|
1863
|
+
.. MATH::
|
|
1864
|
+
|
|
1865
|
+
\chi : (\ZZ/N\ZZ)^* \to \QQ(\zeta_m)
|
|
1866
|
+
|
|
1867
|
+
where `m` is the least common multiple of `n` and
|
|
1868
|
+
the exponent of `(\ZZ/N\ZZ)^*`.
|
|
1869
|
+
|
|
1870
|
+
EXAMPLES::
|
|
1871
|
+
|
|
1872
|
+
sage: G.<a,b> = DirichletGroup(20,QQ)
|
|
1873
|
+
sage: b.maximize_base_ring()
|
|
1874
|
+
Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -1
|
|
1875
|
+
sage: b.maximize_base_ring().base_ring()
|
|
1876
|
+
Cyclotomic Field of order 4 and degree 2
|
|
1877
|
+
sage: DirichletGroup(20).base_ring()
|
|
1878
|
+
Cyclotomic Field of order 4 and degree 2
|
|
1879
|
+
"""
|
|
1880
|
+
g = IntegerModRing(self.modulus()).unit_group_exponent()
|
|
1881
|
+
if g == 1:
|
|
1882
|
+
g = 2
|
|
1883
|
+
z = self.base_ring().zeta()
|
|
1884
|
+
n = z.multiplicative_order()
|
|
1885
|
+
m = lcm(g, n)
|
|
1886
|
+
if n == m:
|
|
1887
|
+
return self
|
|
1888
|
+
K = CyclotomicField(m)
|
|
1889
|
+
return self.change_ring(K)
|
|
1890
|
+
|
|
1891
|
+
def minimize_base_ring(self):
|
|
1892
|
+
r"""
|
|
1893
|
+
Return a Dirichlet character that equals this one, but over as
|
|
1894
|
+
small a subfield (or subring) of the base ring as possible.
|
|
1895
|
+
|
|
1896
|
+
.. NOTE::
|
|
1897
|
+
|
|
1898
|
+
This function is currently only implemented when the base
|
|
1899
|
+
ring is a number field. It is the identity function in
|
|
1900
|
+
characteristic p.
|
|
1901
|
+
|
|
1902
|
+
EXAMPLES::
|
|
1903
|
+
|
|
1904
|
+
sage: G = DirichletGroup(13)
|
|
1905
|
+
sage: e = DirichletGroup(13).0
|
|
1906
|
+
sage: e.base_ring()
|
|
1907
|
+
Cyclotomic Field of order 12 and degree 4
|
|
1908
|
+
sage: e.minimize_base_ring().base_ring()
|
|
1909
|
+
Cyclotomic Field of order 12 and degree 4
|
|
1910
|
+
sage: (e^2).minimize_base_ring().base_ring()
|
|
1911
|
+
Cyclotomic Field of order 6 and degree 2
|
|
1912
|
+
sage: (e^3).minimize_base_ring().base_ring()
|
|
1913
|
+
Cyclotomic Field of order 4 and degree 2
|
|
1914
|
+
sage: (e^12).minimize_base_ring().base_ring()
|
|
1915
|
+
Rational Field
|
|
1916
|
+
|
|
1917
|
+
TESTS:
|
|
1918
|
+
|
|
1919
|
+
Check that :issue:`18479` is fixed::
|
|
1920
|
+
|
|
1921
|
+
sage: f = Newforms(Gamma1(25), names='a')[1]
|
|
1922
|
+
sage: eps = f.character()
|
|
1923
|
+
sage: eps.minimize_base_ring() == eps
|
|
1924
|
+
True
|
|
1925
|
+
|
|
1926
|
+
A related bug (see :issue:`18086`)::
|
|
1927
|
+
|
|
1928
|
+
sage: x = polygen(ZZ, 'x')
|
|
1929
|
+
sage: K.<a,b> = NumberField([x^2 + 1, x^2 - 3])
|
|
1930
|
+
sage: chi = DirichletGroup(7, K).0
|
|
1931
|
+
sage: chi.minimize_base_ring()
|
|
1932
|
+
Dirichlet character modulo 7 of conductor 7 mapping 3 |--> -1/2*b*a + 1/2
|
|
1933
|
+
"""
|
|
1934
|
+
R = self.base_ring()
|
|
1935
|
+
if R.is_prime_field():
|
|
1936
|
+
return self
|
|
1937
|
+
p = R.characteristic()
|
|
1938
|
+
|
|
1939
|
+
if p:
|
|
1940
|
+
K = IntegerModRing(p)
|
|
1941
|
+
elif self.order() <= 2:
|
|
1942
|
+
K = QQ
|
|
1943
|
+
elif (isinstance(R, NumberField_generic)
|
|
1944
|
+
and euler_phi(self.order()) < R.absolute_degree()):
|
|
1945
|
+
K = CyclotomicField(self.order())
|
|
1946
|
+
else:
|
|
1947
|
+
return self
|
|
1948
|
+
|
|
1949
|
+
try:
|
|
1950
|
+
return self.change_ring(K)
|
|
1951
|
+
except (TypeError, ValueError, ArithmeticError):
|
|
1952
|
+
return self
|
|
1953
|
+
|
|
1954
|
+
def modulus(self):
|
|
1955
|
+
"""
|
|
1956
|
+
Return the modulus of this character.
|
|
1957
|
+
|
|
1958
|
+
EXAMPLES::
|
|
1959
|
+
|
|
1960
|
+
sage: e = DirichletGroup(100, QQ).0
|
|
1961
|
+
sage: e.modulus()
|
|
1962
|
+
100
|
|
1963
|
+
sage: e.conductor()
|
|
1964
|
+
4
|
|
1965
|
+
"""
|
|
1966
|
+
return self.parent().modulus()
|
|
1967
|
+
|
|
1968
|
+
def level(self):
|
|
1969
|
+
"""
|
|
1970
|
+
Synonym for modulus.
|
|
1971
|
+
|
|
1972
|
+
EXAMPLES::
|
|
1973
|
+
|
|
1974
|
+
sage: e = DirichletGroup(100, QQ).0
|
|
1975
|
+
sage: e.level()
|
|
1976
|
+
100
|
|
1977
|
+
"""
|
|
1978
|
+
return self.modulus()
|
|
1979
|
+
|
|
1980
|
+
@cached_method
|
|
1981
|
+
def multiplicative_order(self):
|
|
1982
|
+
"""
|
|
1983
|
+
Return the order of this character.
|
|
1984
|
+
|
|
1985
|
+
EXAMPLES::
|
|
1986
|
+
|
|
1987
|
+
sage: e = DirichletGroup(100).1
|
|
1988
|
+
sage: e.order() # same as multiplicative_order, since group is multiplicative
|
|
1989
|
+
20
|
|
1990
|
+
sage: e.multiplicative_order()
|
|
1991
|
+
20
|
|
1992
|
+
sage: e = DirichletGroup(100).0
|
|
1993
|
+
sage: e.multiplicative_order()
|
|
1994
|
+
2
|
|
1995
|
+
"""
|
|
1996
|
+
if self.parent().zeta.is_in_cache():
|
|
1997
|
+
return self.element().additive_order()
|
|
1998
|
+
return lcm([z.multiplicative_order() for z in self.values_on_gens()])
|
|
1999
|
+
|
|
2000
|
+
def primitive_character(self):
|
|
2001
|
+
"""
|
|
2002
|
+
Return the primitive character associated to ``self``.
|
|
2003
|
+
|
|
2004
|
+
EXAMPLES::
|
|
2005
|
+
|
|
2006
|
+
sage: e = DirichletGroup(100).0; e
|
|
2007
|
+
Dirichlet character modulo 100 of conductor 4 mapping 51 |--> -1, 77 |--> 1
|
|
2008
|
+
sage: e.conductor()
|
|
2009
|
+
4
|
|
2010
|
+
sage: f = e.primitive_character(); f
|
|
2011
|
+
Dirichlet character modulo 4 of conductor 4 mapping 3 |--> -1
|
|
2012
|
+
sage: f.modulus()
|
|
2013
|
+
4
|
|
2014
|
+
"""
|
|
2015
|
+
return self.restrict(self.conductor())
|
|
2016
|
+
|
|
2017
|
+
def restrict(self, M):
|
|
2018
|
+
"""
|
|
2019
|
+
Return the restriction of this character to a Dirichlet character
|
|
2020
|
+
modulo the divisor ``M`` of the modulus, which must also be a multiple
|
|
2021
|
+
of the conductor of this character.
|
|
2022
|
+
|
|
2023
|
+
EXAMPLES::
|
|
2024
|
+
|
|
2025
|
+
sage: e = DirichletGroup(100).0
|
|
2026
|
+
sage: e.modulus()
|
|
2027
|
+
100
|
|
2028
|
+
sage: e.conductor()
|
|
2029
|
+
4
|
|
2030
|
+
sage: e.restrict(20)
|
|
2031
|
+
Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1
|
|
2032
|
+
sage: e.restrict(4)
|
|
2033
|
+
Dirichlet character modulo 4 of conductor 4 mapping 3 |--> -1
|
|
2034
|
+
sage: e.restrict(50)
|
|
2035
|
+
Traceback (most recent call last):
|
|
2036
|
+
...
|
|
2037
|
+
ValueError: conductor(=4) must divide M(=50)
|
|
2038
|
+
"""
|
|
2039
|
+
M = int(M)
|
|
2040
|
+
if self.modulus() % M:
|
|
2041
|
+
raise ValueError("M(=%s) must divide the modulus(=%s)" % (M, self.modulus()))
|
|
2042
|
+
if M % self.conductor():
|
|
2043
|
+
raise ValueError("conductor(=%s) must divide M(=%s)" % (self.conductor(), M))
|
|
2044
|
+
H = DirichletGroup(M, self.base_ring())
|
|
2045
|
+
return H(self)
|
|
2046
|
+
|
|
2047
|
+
@cached_method
|
|
2048
|
+
def values(self) -> list:
|
|
2049
|
+
"""
|
|
2050
|
+
Return a list of the values of this character on each integer
|
|
2051
|
+
between 0 and the modulus.
|
|
2052
|
+
|
|
2053
|
+
EXAMPLES::
|
|
2054
|
+
|
|
2055
|
+
sage: e = DirichletGroup(20)(1)
|
|
2056
|
+
sage: e.values()
|
|
2057
|
+
[0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1]
|
|
2058
|
+
sage: e = DirichletGroup(20).gen(0)
|
|
2059
|
+
sage: e.values()
|
|
2060
|
+
[0, 1, 0, -1, 0, 0, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0, 0, 1, 0, -1]
|
|
2061
|
+
sage: e = DirichletGroup(20).gen(1)
|
|
2062
|
+
sage: e.values()
|
|
2063
|
+
[0, 1, 0, -zeta4, 0, 0, 0, zeta4, 0, -1, 0, 1, 0, -zeta4, 0, 0, 0, zeta4, 0, -1]
|
|
2064
|
+
sage: e = DirichletGroup(21).gen(0) ; e.values()
|
|
2065
|
+
[0, 1, -1, 0, 1, -1, 0, 0, -1, 0, 1, -1, 0, 1, 0, 0, 1, -1, 0, 1, -1]
|
|
2066
|
+
sage: e = DirichletGroup(21, base_ring=GF(37)).gen(0) ; e.values()
|
|
2067
|
+
[0, 1, 36, 0, 1, 36, 0, 0, 36, 0, 1, 36, 0, 1, 0, 0, 1, 36, 0, 1, 36]
|
|
2068
|
+
sage: e = DirichletGroup(21, base_ring=GF(3)).gen(0) ; e.values()
|
|
2069
|
+
[0, 1, 2, 0, 1, 2, 0, 0, 2, 0, 1, 2, 0, 1, 0, 0, 1, 2, 0, 1, 2]
|
|
2070
|
+
|
|
2071
|
+
::
|
|
2072
|
+
|
|
2073
|
+
sage: chi = DirichletGroup(100151, CyclotomicField(10)).0
|
|
2074
|
+
sage: ls = chi.values() ; ls[0:10]
|
|
2075
|
+
[0,
|
|
2076
|
+
1,
|
|
2077
|
+
-zeta10^3,
|
|
2078
|
+
-zeta10,
|
|
2079
|
+
-zeta10,
|
|
2080
|
+
1,
|
|
2081
|
+
zeta10^3 - zeta10^2 + zeta10 - 1,
|
|
2082
|
+
zeta10,
|
|
2083
|
+
zeta10^3 - zeta10^2 + zeta10 - 1,
|
|
2084
|
+
zeta10^2]
|
|
2085
|
+
|
|
2086
|
+
TESTS:
|
|
2087
|
+
|
|
2088
|
+
Test that :issue:`11783` and :issue:`14368` are fixed::
|
|
2089
|
+
|
|
2090
|
+
sage: chi = DirichletGroup(1).list()[0]
|
|
2091
|
+
sage: chi.values()
|
|
2092
|
+
[1]
|
|
2093
|
+
sage: chi(1)
|
|
2094
|
+
1
|
|
2095
|
+
"""
|
|
2096
|
+
G = self.parent()
|
|
2097
|
+
R = G.base_ring()
|
|
2098
|
+
|
|
2099
|
+
mod = self.parent().modulus()
|
|
2100
|
+
if mod == 1:
|
|
2101
|
+
return [R.one()]
|
|
2102
|
+
elif mod == 2:
|
|
2103
|
+
return [R.zero(), R.one()]
|
|
2104
|
+
|
|
2105
|
+
result_list = [R.zero()] * mod
|
|
2106
|
+
gens = G.unit_gens()
|
|
2107
|
+
orders = G.integers_mod().unit_group().gens_orders()
|
|
2108
|
+
|
|
2109
|
+
R_values = G._zeta_powers
|
|
2110
|
+
val_on_gen = self.element()
|
|
2111
|
+
|
|
2112
|
+
exponents = [0] * len(orders)
|
|
2113
|
+
n = G.integers_mod().one()
|
|
2114
|
+
value = val_on_gen.base_ring().zero()
|
|
2115
|
+
|
|
2116
|
+
while True:
|
|
2117
|
+
# record character value on n
|
|
2118
|
+
result_list[n] = R_values[value]
|
|
2119
|
+
# iterate:
|
|
2120
|
+
# increase the exponent vector by 1,
|
|
2121
|
+
# increase n accordingly, and increase value
|
|
2122
|
+
i = 0
|
|
2123
|
+
while True:
|
|
2124
|
+
try:
|
|
2125
|
+
exponents[i] += 1
|
|
2126
|
+
except IndexError: # Done!
|
|
2127
|
+
return result_list
|
|
2128
|
+
value += val_on_gen[i]
|
|
2129
|
+
n *= gens[i]
|
|
2130
|
+
if exponents[i] < orders[i]:
|
|
2131
|
+
break
|
|
2132
|
+
exponents[i] = 0
|
|
2133
|
+
i += 1
|
|
2134
|
+
|
|
2135
|
+
@cached_method(do_pickle=True)
|
|
2136
|
+
def values_on_gens(self) -> tuple:
|
|
2137
|
+
r"""
|
|
2138
|
+
Return a tuple of the values of ``self`` on the standard
|
|
2139
|
+
generators of `(\ZZ/N\ZZ)^*`, where `N` is the modulus.
|
|
2140
|
+
|
|
2141
|
+
EXAMPLES::
|
|
2142
|
+
|
|
2143
|
+
sage: # needs sage.rings.number_field
|
|
2144
|
+
sage: e = DirichletGroup(16)([-1, 1])
|
|
2145
|
+
sage: e.values_on_gens ()
|
|
2146
|
+
(-1, 1)
|
|
2147
|
+
|
|
2148
|
+
.. NOTE::
|
|
2149
|
+
|
|
2150
|
+
The constructor of :class:`DirichletCharacter` sets the
|
|
2151
|
+
cache of :meth:`element` or of :meth:`values_on_gens`. The cache of
|
|
2152
|
+
one of these methods needs to be set for the other method to work properly,
|
|
2153
|
+
these caches have to be stored when pickling an instance of
|
|
2154
|
+
:class:`DirichletCharacter`.
|
|
2155
|
+
"""
|
|
2156
|
+
pows = self.parent()._zeta_powers
|
|
2157
|
+
return tuple([pows[i] for i in self.element()])
|
|
2158
|
+
|
|
2159
|
+
@cached_method(do_pickle=True)
|
|
2160
|
+
def element(self):
|
|
2161
|
+
r"""
|
|
2162
|
+
Return the underlying `\ZZ/n\ZZ`-module
|
|
2163
|
+
vector of exponents.
|
|
2164
|
+
|
|
2165
|
+
EXAMPLES::
|
|
2166
|
+
|
|
2167
|
+
sage: G.<a,b> = DirichletGroup(20)
|
|
2168
|
+
sage: a.element()
|
|
2169
|
+
(2, 0)
|
|
2170
|
+
sage: b.element()
|
|
2171
|
+
(0, 1)
|
|
2172
|
+
|
|
2173
|
+
.. NOTE::
|
|
2174
|
+
|
|
2175
|
+
The constructor of :class:`DirichletCharacter` sets the
|
|
2176
|
+
cache of :meth:`element` or of :meth:`values_on_gens`. The cache of
|
|
2177
|
+
one of these methods needs to be set for the other method to work properly,
|
|
2178
|
+
these caches have to be stored when pickling an instance of
|
|
2179
|
+
:class:`DirichletCharacter`.
|
|
2180
|
+
"""
|
|
2181
|
+
P = self.parent()
|
|
2182
|
+
M = P._module
|
|
2183
|
+
if isinstance(P.base_ring(), sage.rings.abc.ComplexField):
|
|
2184
|
+
zeta = P.zeta()
|
|
2185
|
+
zeta_argument = zeta.argument()
|
|
2186
|
+
v = M([int(round(x.argument() / zeta_argument))
|
|
2187
|
+
for x in self.values_on_gens()])
|
|
2188
|
+
else:
|
|
2189
|
+
dlog = P._zeta_dlog
|
|
2190
|
+
v = M([dlog[x] for x in self.values_on_gens()])
|
|
2191
|
+
v.set_immutable()
|
|
2192
|
+
return v
|
|
2193
|
+
|
|
2194
|
+
def __setstate__(self, state):
|
|
2195
|
+
r"""
|
|
2196
|
+
Restore a pickled element from ``state``.
|
|
2197
|
+
|
|
2198
|
+
TESTS::
|
|
2199
|
+
|
|
2200
|
+
sage: # needs sage.rings.number_field
|
|
2201
|
+
sage: e = DirichletGroup(16)([-1, 1])
|
|
2202
|
+
sage: loads(dumps(e)) == e
|
|
2203
|
+
True
|
|
2204
|
+
"""
|
|
2205
|
+
# values_on_gens() used an explicit cache __values_on_gens in the past
|
|
2206
|
+
# we need to set the cache of values_on_gens() from that if we encounter it in a pickle
|
|
2207
|
+
values_on_gens_key = '_DirichletCharacter__values_on_gens'
|
|
2208
|
+
values_on_gens = None
|
|
2209
|
+
state_dict = state[1]
|
|
2210
|
+
if values_on_gens_key in state_dict:
|
|
2211
|
+
values_on_gens = state_dict[values_on_gens_key]
|
|
2212
|
+
del state_dict[values_on_gens_key]
|
|
2213
|
+
|
|
2214
|
+
# element() used an explicit cache __element in the past
|
|
2215
|
+
# we need to set the cache of element() from that if we encounter it in a pickle
|
|
2216
|
+
element_key = '_DirichletCharacter__element'
|
|
2217
|
+
element = None
|
|
2218
|
+
if element_key in state_dict:
|
|
2219
|
+
element = state_dict[element_key]
|
|
2220
|
+
del state_dict[element_key]
|
|
2221
|
+
|
|
2222
|
+
super().__setstate__(state)
|
|
2223
|
+
|
|
2224
|
+
if values_on_gens is not None:
|
|
2225
|
+
self.values_on_gens.set_cache(values_on_gens)
|
|
2226
|
+
if element is not None:
|
|
2227
|
+
self.element.set_cache(element)
|
|
2228
|
+
|
|
2229
|
+
|
|
2230
|
+
class DirichletGroupFactory(UniqueFactory):
|
|
2231
|
+
r"""
|
|
2232
|
+
Construct a group of Dirichlet characters modulo `N`.
|
|
2233
|
+
|
|
2234
|
+
INPUT:
|
|
2235
|
+
|
|
2236
|
+
- ``N`` -- positive integer
|
|
2237
|
+
|
|
2238
|
+
- ``base_ring`` -- commutative ring; the value ring for the
|
|
2239
|
+
characters in this group (default: the cyclotomic field
|
|
2240
|
+
`\QQ(\zeta_n)`, where `n` is the exponent of `(\ZZ/N\ZZ)^*`)
|
|
2241
|
+
|
|
2242
|
+
- ``zeta`` -- (optional) root of unity in ``base_ring``
|
|
2243
|
+
|
|
2244
|
+
- ``zeta_order`` -- (optional) positive integer; this must be the
|
|
2245
|
+
order of ``zeta`` if both are specified
|
|
2246
|
+
|
|
2247
|
+
- ``names`` -- ignored (needed so ``G.<...> = DirichletGroup(...)``
|
|
2248
|
+
notation works)
|
|
2249
|
+
|
|
2250
|
+
- ``integral`` -- boolean (default: ``False``); whether to replace
|
|
2251
|
+
the default cyclotomic field by its rings of integers as the
|
|
2252
|
+
base ring. This is ignored if ``base_ring`` is not ``None``.
|
|
2253
|
+
|
|
2254
|
+
OUTPUT:
|
|
2255
|
+
|
|
2256
|
+
The group of Dirichlet characters modulo `N` with values in a
|
|
2257
|
+
subgroup `V` of the multiplicative group `R^*` of ``base_ring``.
|
|
2258
|
+
This is the group of homomorphisms `(\ZZ/N\ZZ)^* \to V` with
|
|
2259
|
+
pointwise multiplication. The group `V` is determined as follows:
|
|
2260
|
+
|
|
2261
|
+
- If both ``zeta`` and ``zeta_order`` are omitted, then `V` is
|
|
2262
|
+
taken to be `R^*`, or equivalently its `n`-torsion subgroup,
|
|
2263
|
+
where `n` is the exponent of `(\ZZ/N\ZZ)^*`. Many operations,
|
|
2264
|
+
such as finding a set of generators for the group, are only
|
|
2265
|
+
implemented if `V` is cyclic and a generator for `V` can be
|
|
2266
|
+
found.
|
|
2267
|
+
|
|
2268
|
+
- If ``zeta`` is specified, then `V` is taken to be the cyclic
|
|
2269
|
+
subgroup of `R^*` generated by ``zeta``. If ``zeta_order`` is
|
|
2270
|
+
also given, it must be the multiplicative order of ``zeta``;
|
|
2271
|
+
this is useful if the base ring is not exact or if the order of
|
|
2272
|
+
``zeta`` is very large.
|
|
2273
|
+
|
|
2274
|
+
- If ``zeta`` is not specified but ``zeta_order`` is, then `V` is
|
|
2275
|
+
taken to be the group of roots of unity of order dividing
|
|
2276
|
+
``zeta_order`` in `R`. In this case, `R` must be a domain (so
|
|
2277
|
+
`V` is cyclic), and `V` must have order ``zeta_order``.
|
|
2278
|
+
Furthermore, a generator ``zeta`` of `V` is computed, and an
|
|
2279
|
+
error is raised if such ``zeta`` cannot be found.
|
|
2280
|
+
|
|
2281
|
+
EXAMPLES:
|
|
2282
|
+
|
|
2283
|
+
The default base ring is a cyclotomic field of order the exponent
|
|
2284
|
+
of `(\ZZ/N\ZZ)^*`::
|
|
2285
|
+
|
|
2286
|
+
sage: DirichletGroup(20)
|
|
2287
|
+
Group of Dirichlet characters modulo 20 with values
|
|
2288
|
+
in Cyclotomic Field of order 4 and degree 2
|
|
2289
|
+
|
|
2290
|
+
We create the group of Dirichlet character mod 20 with values in
|
|
2291
|
+
the rational numbers::
|
|
2292
|
+
|
|
2293
|
+
sage: G = DirichletGroup(20, QQ); G
|
|
2294
|
+
Group of Dirichlet characters modulo 20 with values in Rational Field
|
|
2295
|
+
sage: G.order()
|
|
2296
|
+
4
|
|
2297
|
+
sage: G.base_ring()
|
|
2298
|
+
Rational Field
|
|
2299
|
+
|
|
2300
|
+
The elements of G print as lists giving the values of the character
|
|
2301
|
+
on the generators of `(Z/NZ)^*`::
|
|
2302
|
+
|
|
2303
|
+
sage: list(G)
|
|
2304
|
+
[Dirichlet character modulo 20 of conductor 1 mapping 11 |--> 1, 17 |--> 1,
|
|
2305
|
+
Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1,
|
|
2306
|
+
Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -1,
|
|
2307
|
+
Dirichlet character modulo 20 of conductor 20 mapping 11 |--> -1, 17 |--> -1]
|
|
2308
|
+
|
|
2309
|
+
Next we construct the group of Dirichlet character mod 20, but with
|
|
2310
|
+
values in `\QQ(\zeta_n)`::
|
|
2311
|
+
|
|
2312
|
+
sage: G = DirichletGroup(20)
|
|
2313
|
+
sage: G.1
|
|
2314
|
+
Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> zeta4
|
|
2315
|
+
|
|
2316
|
+
We next compute several invariants of ``G``::
|
|
2317
|
+
|
|
2318
|
+
sage: G.gens()
|
|
2319
|
+
(Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1,
|
|
2320
|
+
Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> zeta4)
|
|
2321
|
+
sage: G.unit_gens()
|
|
2322
|
+
(11, 17)
|
|
2323
|
+
sage: G.zeta()
|
|
2324
|
+
zeta4
|
|
2325
|
+
sage: G.zeta_order()
|
|
2326
|
+
4
|
|
2327
|
+
|
|
2328
|
+
In this example we create a Dirichlet group with values in a
|
|
2329
|
+
number field::
|
|
2330
|
+
|
|
2331
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
2332
|
+
sage: K.<a> = NumberField(x^4 + 1)
|
|
2333
|
+
sage: DirichletGroup(5, K)
|
|
2334
|
+
Group of Dirichlet characters modulo 5 with values
|
|
2335
|
+
in Number Field in a with defining polynomial x^4 + 1
|
|
2336
|
+
|
|
2337
|
+
An example where we give ``zeta``, but not its order::
|
|
2338
|
+
|
|
2339
|
+
sage: G = DirichletGroup(5, K, a); G
|
|
2340
|
+
Group of Dirichlet characters modulo 5 with values in the group of order 8
|
|
2341
|
+
generated by a in Number Field in a with defining polynomial x^4 + 1
|
|
2342
|
+
sage: G.list()
|
|
2343
|
+
[Dirichlet character modulo 5 of conductor 1 mapping 2 |--> 1,
|
|
2344
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> a^2,
|
|
2345
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1,
|
|
2346
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -a^2]
|
|
2347
|
+
|
|
2348
|
+
We can also restrict the order of the characters, either with or
|
|
2349
|
+
without specifying a root of unity::
|
|
2350
|
+
|
|
2351
|
+
sage: DirichletGroup(5, K, zeta=-1, zeta_order=2)
|
|
2352
|
+
Group of Dirichlet characters modulo 5 with values in the group of order 2
|
|
2353
|
+
generated by -1 in Number Field in a with defining polynomial x^4 + 1
|
|
2354
|
+
sage: DirichletGroup(5, K, zeta_order=2)
|
|
2355
|
+
Group of Dirichlet characters modulo 5 with values in the group of order 2
|
|
2356
|
+
generated by -1 in Number Field in a with defining polynomial x^4 + 1
|
|
2357
|
+
|
|
2358
|
+
::
|
|
2359
|
+
|
|
2360
|
+
sage: G.<e> = DirichletGroup(13)
|
|
2361
|
+
sage: loads(G.dumps()) == G
|
|
2362
|
+
True
|
|
2363
|
+
|
|
2364
|
+
::
|
|
2365
|
+
|
|
2366
|
+
sage: G = DirichletGroup(19, GF(5))
|
|
2367
|
+
sage: loads(G.dumps()) == G
|
|
2368
|
+
True
|
|
2369
|
+
|
|
2370
|
+
We compute a Dirichlet group over a large prime field::
|
|
2371
|
+
|
|
2372
|
+
sage: p = next_prime(10^40)
|
|
2373
|
+
sage: g = DirichletGroup(19, GF(p)); g
|
|
2374
|
+
Group of Dirichlet characters modulo 19 with values
|
|
2375
|
+
in Finite Field of size 10000000000000000000000000000000000000121
|
|
2376
|
+
|
|
2377
|
+
Note that the root of unity has small order, i.e., it is not the
|
|
2378
|
+
largest order root of unity in the field::
|
|
2379
|
+
|
|
2380
|
+
sage: g.zeta_order()
|
|
2381
|
+
2
|
|
2382
|
+
|
|
2383
|
+
::
|
|
2384
|
+
|
|
2385
|
+
sage: K = CyclotomicField(4)
|
|
2386
|
+
sage: r4 = K.ring_of_integers()
|
|
2387
|
+
sage: G = DirichletGroup(60, r4)
|
|
2388
|
+
sage: G.gens()
|
|
2389
|
+
(Dirichlet character modulo 60 of conductor 4
|
|
2390
|
+
mapping 31 |--> -1, 41 |--> 1, 37 |--> 1,
|
|
2391
|
+
Dirichlet character modulo 60 of conductor 3
|
|
2392
|
+
mapping 31 |--> 1, 41 |--> -1, 37 |--> 1,
|
|
2393
|
+
Dirichlet character modulo 60 of conductor 5
|
|
2394
|
+
mapping 31 |--> 1, 41 |--> 1, 37 |--> zeta4)
|
|
2395
|
+
sage: val = G.gens()[2].values_on_gens()[2] ; val
|
|
2396
|
+
zeta4
|
|
2397
|
+
sage: parent(val)
|
|
2398
|
+
Gaussian Integers generated by zeta4 in Cyclotomic Field of order 4 and degree 2
|
|
2399
|
+
sage: r4_29_0 = r4.residue_field(K(29).factor()[0][0]); r4_29_0(val)
|
|
2400
|
+
12
|
|
2401
|
+
sage: r4_29_0(val) * GF(29)(3)
|
|
2402
|
+
7
|
|
2403
|
+
sage: r4_29_0(G.gens()[2].values_on_gens()[2]) * 3
|
|
2404
|
+
7
|
|
2405
|
+
sage: parent(r4_29_0(G.gens()[2].values_on_gens()[2]) * 3)
|
|
2406
|
+
Residue field of Fractional ideal (-2*zeta4 - 5)
|
|
2407
|
+
|
|
2408
|
+
::
|
|
2409
|
+
|
|
2410
|
+
sage: DirichletGroup(60, integral=True)
|
|
2411
|
+
Group of Dirichlet characters modulo 60 with values in
|
|
2412
|
+
Gaussian Integers generated by zeta4 in Cyclotomic Field of order 4 and degree 2
|
|
2413
|
+
sage: parent(DirichletGroup(60, integral=True).gens()[2].values_on_gens()[2])
|
|
2414
|
+
Gaussian Integers generated by zeta4 in Cyclotomic Field of order 4 and degree 2
|
|
2415
|
+
|
|
2416
|
+
If the order of ``zeta`` cannot be determined automatically, we
|
|
2417
|
+
can specify it using ``zeta_order``::
|
|
2418
|
+
|
|
2419
|
+
sage: DirichletGroup(7, CC, zeta=exp(2*pi*I/6)) # needs sage.symbolic
|
|
2420
|
+
Traceback (most recent call last):
|
|
2421
|
+
...
|
|
2422
|
+
NotImplementedError: order of element not known
|
|
2423
|
+
|
|
2424
|
+
sage: DirichletGroup(7, CC, zeta=exp(2*pi*I/6), zeta_order=6) # needs sage.symbolic
|
|
2425
|
+
Group of Dirichlet characters modulo 7 with values in the group of order 6
|
|
2426
|
+
generated by 0.500000000000000 + 0.866025403784439*I
|
|
2427
|
+
in Complex Field with 53 bits of precision
|
|
2428
|
+
|
|
2429
|
+
If the base ring is not a domain (in which case the group of roots
|
|
2430
|
+
of unity is not necessarily cyclic), some operations still work,
|
|
2431
|
+
such as creation of elements::
|
|
2432
|
+
|
|
2433
|
+
sage: G = DirichletGroup(5, Zmod(15)); G
|
|
2434
|
+
Group of Dirichlet characters modulo 5 with values in Ring of integers modulo 15
|
|
2435
|
+
sage: chi = G([13]); chi
|
|
2436
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> 13
|
|
2437
|
+
sage: chi^2
|
|
2438
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> 4
|
|
2439
|
+
sage: chi.multiplicative_order()
|
|
2440
|
+
4
|
|
2441
|
+
|
|
2442
|
+
Other operations only work if ``zeta`` is specified::
|
|
2443
|
+
|
|
2444
|
+
sage: G.gens()
|
|
2445
|
+
Traceback (most recent call last):
|
|
2446
|
+
...
|
|
2447
|
+
NotImplementedError: factorization of polynomials over rings
|
|
2448
|
+
with composite characteristic is not implemented
|
|
2449
|
+
sage: G = DirichletGroup(5, Zmod(15), zeta=2); G
|
|
2450
|
+
Group of Dirichlet characters modulo 5 with values in the group of order 4
|
|
2451
|
+
generated by 2 in Ring of integers modulo 15
|
|
2452
|
+
sage: G.gens()
|
|
2453
|
+
(Dirichlet character modulo 5 of conductor 5 mapping 2 |--> 2,)
|
|
2454
|
+
|
|
2455
|
+
TESTS:
|
|
2456
|
+
|
|
2457
|
+
Dirichlet groups are cached, creating two groups with the same parameters
|
|
2458
|
+
yields the same object::
|
|
2459
|
+
|
|
2460
|
+
sage: DirichletGroup(60) is DirichletGroup(60)
|
|
2461
|
+
True
|
|
2462
|
+
|
|
2463
|
+
Test for pickling::
|
|
2464
|
+
|
|
2465
|
+
sage: G = DirichletGroup(9)
|
|
2466
|
+
sage: loads(dumps(G)) is G
|
|
2467
|
+
True
|
|
2468
|
+
"""
|
|
2469
|
+
def create_key(self, N, base_ring=None, zeta=None, zeta_order=None,
|
|
2470
|
+
names=None, integral=False):
|
|
2471
|
+
"""
|
|
2472
|
+
Create a key that uniquely determines a Dirichlet group.
|
|
2473
|
+
|
|
2474
|
+
TESTS::
|
|
2475
|
+
|
|
2476
|
+
sage: DirichletGroup.create_key(60)
|
|
2477
|
+
(Cyclotomic Field of order 4 and degree 2, 60, None, None)
|
|
2478
|
+
|
|
2479
|
+
An example to illustrate that ``base_ring`` is a part of the key::
|
|
2480
|
+
|
|
2481
|
+
sage: k = DirichletGroup.create_key(2, base_ring=QQ); k
|
|
2482
|
+
(Rational Field, 2, None, None)
|
|
2483
|
+
sage: l = DirichletGroup.create_key(2, base_ring=CC); l
|
|
2484
|
+
(Complex Field with 53 bits of precision, 2, None, None)
|
|
2485
|
+
sage: k == l
|
|
2486
|
+
False
|
|
2487
|
+
sage: G = DirichletGroup.create_object(None, k); G
|
|
2488
|
+
Group of Dirichlet characters modulo 2 with values in Rational Field
|
|
2489
|
+
sage: H = DirichletGroup.create_object(None, l); H
|
|
2490
|
+
Group of Dirichlet characters modulo 2 with values in Complex Field with 53 bits of precision
|
|
2491
|
+
sage: G == H
|
|
2492
|
+
False
|
|
2493
|
+
|
|
2494
|
+
If ``base_ring`` was not be a part of the key, the keys would compare
|
|
2495
|
+
equal and the caching would be broken::
|
|
2496
|
+
|
|
2497
|
+
sage: k = k[1:]; k
|
|
2498
|
+
(2, None, None)
|
|
2499
|
+
sage: l = l[1:]; l
|
|
2500
|
+
(2, None, None)
|
|
2501
|
+
sage: k == l
|
|
2502
|
+
True
|
|
2503
|
+
sage: DirichletGroup(2, base_ring=QQ) is DirichletGroup(2, base_ring=CC)
|
|
2504
|
+
False
|
|
2505
|
+
|
|
2506
|
+
If the base ring is not an integral domain, an error will be
|
|
2507
|
+
raised if only ``zeta_order`` is specified::
|
|
2508
|
+
|
|
2509
|
+
sage: DirichletGroup(17, Integers(15))
|
|
2510
|
+
Group of Dirichlet characters modulo 17 with values in Ring of integers modulo 15
|
|
2511
|
+
sage: DirichletGroup(17, Integers(15), zeta_order=4)
|
|
2512
|
+
Traceback (most recent call last):
|
|
2513
|
+
...
|
|
2514
|
+
ValueError: base ring (= Ring of integers modulo 15) must be an integral domain if only zeta_order is specified
|
|
2515
|
+
sage: G = DirichletGroup(17, Integers(15), zeta=7); G
|
|
2516
|
+
Group of Dirichlet characters modulo 17 with values in the group of order 4 generated by 7 in Ring of integers modulo 15
|
|
2517
|
+
sage: G.order()
|
|
2518
|
+
4
|
|
2519
|
+
|
|
2520
|
+
sage: DirichletGroup(-33)
|
|
2521
|
+
Traceback (most recent call last):
|
|
2522
|
+
...
|
|
2523
|
+
ValueError: modulus should be positive
|
|
2524
|
+
"""
|
|
2525
|
+
modulus = Integer(N)
|
|
2526
|
+
if modulus <= 0:
|
|
2527
|
+
raise ValueError('modulus should be positive')
|
|
2528
|
+
|
|
2529
|
+
if base_ring is None:
|
|
2530
|
+
if not (zeta is None and zeta_order is None):
|
|
2531
|
+
raise ValueError("zeta and zeta_order must be None if base_ring not specified")
|
|
2532
|
+
e = IntegerModRing(modulus).unit_group_exponent()
|
|
2533
|
+
base_ring = CyclotomicField(e)
|
|
2534
|
+
if integral:
|
|
2535
|
+
base_ring = base_ring.ring_of_integers()
|
|
2536
|
+
|
|
2537
|
+
if base_ring not in Rings():
|
|
2538
|
+
raise TypeError("base_ring (= %s) must be a ring" % base_ring)
|
|
2539
|
+
|
|
2540
|
+
# If either zeta or zeta_order is given, compute the other.
|
|
2541
|
+
if zeta is not None:
|
|
2542
|
+
zeta = base_ring(zeta)
|
|
2543
|
+
if zeta_order is None:
|
|
2544
|
+
zeta_order = zeta.multiplicative_order()
|
|
2545
|
+
elif zeta_order is not None:
|
|
2546
|
+
if not base_ring.is_integral_domain():
|
|
2547
|
+
raise ValueError("base ring (= %s) must be an integral domain if only zeta_order is specified"
|
|
2548
|
+
% base_ring)
|
|
2549
|
+
zeta_order = Integer(zeta_order)
|
|
2550
|
+
zeta = base_ring.zeta(zeta_order)
|
|
2551
|
+
|
|
2552
|
+
return (base_ring, modulus, zeta, zeta_order)
|
|
2553
|
+
|
|
2554
|
+
def create_object(self, version, key, **extra_args):
|
|
2555
|
+
"""
|
|
2556
|
+
Create the object from the key (extra arguments are ignored).
|
|
2557
|
+
|
|
2558
|
+
This is only called if the object was not found in the cache.
|
|
2559
|
+
|
|
2560
|
+
TESTS::
|
|
2561
|
+
|
|
2562
|
+
sage: # needs sage.rings.number_field
|
|
2563
|
+
sage: K = CyclotomicField(4)
|
|
2564
|
+
sage: DirichletGroup.create_object(None, (K, 60, K.gen(), 4))
|
|
2565
|
+
Group of Dirichlet characters modulo 60 with values in the group of order 4
|
|
2566
|
+
generated by zeta4 in Cyclotomic Field of order 4 and degree 2
|
|
2567
|
+
"""
|
|
2568
|
+
base_ring, modulus, zeta, zeta_order = key
|
|
2569
|
+
return DirichletGroup_class(base_ring, modulus, zeta, zeta_order)
|
|
2570
|
+
|
|
2571
|
+
|
|
2572
|
+
DirichletGroup = DirichletGroupFactory("DirichletGroup")
|
|
2573
|
+
|
|
2574
|
+
|
|
2575
|
+
def is_DirichletGroup(x) -> bool:
|
|
2576
|
+
"""
|
|
2577
|
+
Return ``True`` if ``x`` is a Dirichlet group.
|
|
2578
|
+
|
|
2579
|
+
EXAMPLES::
|
|
2580
|
+
|
|
2581
|
+
sage: from sage.modular.dirichlet import is_DirichletGroup
|
|
2582
|
+
sage: is_DirichletGroup(DirichletGroup(11))
|
|
2583
|
+
doctest:warning...
|
|
2584
|
+
DeprecationWarning: The function is_DirichletGroup is deprecated; use 'isinstance(..., DirichletGroup_class)' instead.
|
|
2585
|
+
See https://github.com/sagemath/sage/issues/38035 for details.
|
|
2586
|
+
True
|
|
2587
|
+
sage: is_DirichletGroup(11)
|
|
2588
|
+
False
|
|
2589
|
+
sage: is_DirichletGroup(DirichletGroup(11).0)
|
|
2590
|
+
False
|
|
2591
|
+
"""
|
|
2592
|
+
from sage.misc.superseded import deprecation
|
|
2593
|
+
deprecation(38035, "The function is_DirichletGroup is deprecated; use 'isinstance(..., DirichletGroup_class)' instead.")
|
|
2594
|
+
return isinstance(x, DirichletGroup_class)
|
|
2595
|
+
|
|
2596
|
+
|
|
2597
|
+
class DirichletGroup_class(WithEqualityById, Parent):
|
|
2598
|
+
"""
|
|
2599
|
+
Group of Dirichlet characters modulo `N` with values in a ring `R`.
|
|
2600
|
+
"""
|
|
2601
|
+
|
|
2602
|
+
Element = DirichletCharacter
|
|
2603
|
+
|
|
2604
|
+
def __init__(self, base_ring, modulus, zeta, zeta_order) -> None:
|
|
2605
|
+
"""
|
|
2606
|
+
Create a Dirichlet group.
|
|
2607
|
+
|
|
2608
|
+
Not to be called directly (use the factory function ``DirichletGroup``).
|
|
2609
|
+
|
|
2610
|
+
The ``DirichletGroup`` factory ensures that either both
|
|
2611
|
+
``zeta`` and ``zeta_order`` are specified, or that both are
|
|
2612
|
+
``None``. In the former case, it also ensures that ``zeta``
|
|
2613
|
+
is an element of ``base_ring`` and that ``zeta_order`` is an
|
|
2614
|
+
element of ``ZZ``.
|
|
2615
|
+
|
|
2616
|
+
TESTS::
|
|
2617
|
+
|
|
2618
|
+
sage: G = DirichletGroup(7, base_ring=Integers(9), zeta=2) # indirect doctest
|
|
2619
|
+
sage: TestSuite(G).run()
|
|
2620
|
+
sage: G.base() # check that Parent.__init__ has been called
|
|
2621
|
+
Ring of integers modulo 9
|
|
2622
|
+
|
|
2623
|
+
sage: DirichletGroup(13) == DirichletGroup(13)
|
|
2624
|
+
True
|
|
2625
|
+
sage: DirichletGroup(13) == DirichletGroup(13, QQ)
|
|
2626
|
+
False
|
|
2627
|
+
"""
|
|
2628
|
+
from sage.categories.groups import Groups
|
|
2629
|
+
category = Groups().Commutative()
|
|
2630
|
+
if base_ring.is_integral_domain() or base_ring.is_finite():
|
|
2631
|
+
# The group of n-th roots of unity in the base ring is
|
|
2632
|
+
# finite, and hence this Dirichlet group is finite too.
|
|
2633
|
+
# In particular, it is finitely generated; the added
|
|
2634
|
+
# FinitelyGenerated() here means that the group has a
|
|
2635
|
+
# distinguished set of generators.
|
|
2636
|
+
category = category.Finite().FinitelyGenerated()
|
|
2637
|
+
Parent.__init__(self, base_ring, category=category)
|
|
2638
|
+
self._zeta = zeta
|
|
2639
|
+
self._zeta_order = zeta_order
|
|
2640
|
+
self._modulus = modulus
|
|
2641
|
+
self._integers = IntegerModRing(modulus)
|
|
2642
|
+
|
|
2643
|
+
@property
|
|
2644
|
+
def _module(self):
|
|
2645
|
+
"""
|
|
2646
|
+
Return the free module used to represent Dirichlet characters.
|
|
2647
|
+
|
|
2648
|
+
TESTS::
|
|
2649
|
+
|
|
2650
|
+
sage: DirichletGroup(12)._module
|
|
2651
|
+
Vector space of dimension 2 over Ring of integers modulo 2
|
|
2652
|
+
"""
|
|
2653
|
+
return FreeModule(IntegerModRing(self.zeta_order()),
|
|
2654
|
+
len(self.unit_gens()))
|
|
2655
|
+
|
|
2656
|
+
@property
|
|
2657
|
+
def _zeta_powers(self):
|
|
2658
|
+
"""
|
|
2659
|
+
Return a list of powers of the distinguished root of unity.
|
|
2660
|
+
|
|
2661
|
+
TESTS::
|
|
2662
|
+
|
|
2663
|
+
sage: DirichletGroup(5)._zeta_powers
|
|
2664
|
+
[1, zeta4, -1, -zeta4]
|
|
2665
|
+
"""
|
|
2666
|
+
R = self.base_ring()
|
|
2667
|
+
a = R.one()
|
|
2668
|
+
w = [a]
|
|
2669
|
+
zeta = self.zeta()
|
|
2670
|
+
zeta_order = self.zeta_order()
|
|
2671
|
+
if isinstance(R, sage.rings.abc.ComplexField):
|
|
2672
|
+
for i in range(1, zeta_order):
|
|
2673
|
+
a = a * zeta
|
|
2674
|
+
a._set_multiplicative_order(zeta_order / gcd(zeta_order, i))
|
|
2675
|
+
w.append(a)
|
|
2676
|
+
else:
|
|
2677
|
+
for i in range(1, zeta_order):
|
|
2678
|
+
a = a * zeta
|
|
2679
|
+
w.append(a)
|
|
2680
|
+
return w
|
|
2681
|
+
|
|
2682
|
+
@property
|
|
2683
|
+
def _zeta_dlog(self) -> dict:
|
|
2684
|
+
"""
|
|
2685
|
+
Return a dictionary that can be used to compute discrete
|
|
2686
|
+
logarithms in the value group of this Dirichlet group.
|
|
2687
|
+
|
|
2688
|
+
TESTS::
|
|
2689
|
+
|
|
2690
|
+
sage: DirichletGroup(5)._zeta_dlog
|
|
2691
|
+
{-1: 2, -zeta4: 3, zeta4: 1, 1: 0}
|
|
2692
|
+
"""
|
|
2693
|
+
return {z: i for i, z in enumerate(self._zeta_powers)}
|
|
2694
|
+
|
|
2695
|
+
def change_ring(self, R, zeta=None, zeta_order=None):
|
|
2696
|
+
"""
|
|
2697
|
+
Return the base extension of ``self`` to ``R``.
|
|
2698
|
+
|
|
2699
|
+
INPUT:
|
|
2700
|
+
|
|
2701
|
+
- ``R`` -- either a ring admitting a conversion map from the
|
|
2702
|
+
base ring of ``self``, or a ring homomorphism with the base
|
|
2703
|
+
ring of ``self`` as its domain
|
|
2704
|
+
|
|
2705
|
+
- ``zeta`` -- (optional) root of unity in ``R``
|
|
2706
|
+
|
|
2707
|
+
- ``zeta_order`` -- (optional) order of ``zeta``
|
|
2708
|
+
|
|
2709
|
+
EXAMPLES::
|
|
2710
|
+
|
|
2711
|
+
sage: G = DirichletGroup(7,QQ); G
|
|
2712
|
+
Group of Dirichlet characters modulo 7 with values in Rational Field
|
|
2713
|
+
sage: G.change_ring(CyclotomicField(6)) # needs sage.rings.number_field
|
|
2714
|
+
Group of Dirichlet characters modulo 7 with values in
|
|
2715
|
+
Cyclotomic Field of order 6 and degree 2
|
|
2716
|
+
|
|
2717
|
+
TESTS:
|
|
2718
|
+
|
|
2719
|
+
We test the case where `R` is a map (:issue:`18072`)::
|
|
2720
|
+
|
|
2721
|
+
sage: # needs sage.rings.number_field
|
|
2722
|
+
sage: K.<i> = QuadraticField(-1)
|
|
2723
|
+
sage: f = K.complex_embeddings()[0]
|
|
2724
|
+
sage: D = DirichletGroup(5, K)
|
|
2725
|
+
sage: D.change_ring(f)
|
|
2726
|
+
Group of Dirichlet characters modulo 5 with values in
|
|
2727
|
+
Complex Field with 53 bits of precision
|
|
2728
|
+
"""
|
|
2729
|
+
if zeta is None and self._zeta is not None:
|
|
2730
|
+
# A root of unity was explicitly given; we use it over the
|
|
2731
|
+
# new base ring as well.
|
|
2732
|
+
zeta = self._zeta
|
|
2733
|
+
if zeta_order is None:
|
|
2734
|
+
# We reuse _zeta_order if we know that it stays the
|
|
2735
|
+
# same; otherwise it will be recomputed as the order
|
|
2736
|
+
# of R(zeta) by the DirichletGroup factory.
|
|
2737
|
+
p = R.characteristic()
|
|
2738
|
+
if p == 0 or p.gcd(self._zeta_order) == 1:
|
|
2739
|
+
zeta_order = self._zeta_order
|
|
2740
|
+
else:
|
|
2741
|
+
# No root of unity specified; use the same zeta_order
|
|
2742
|
+
# (which may still be None).
|
|
2743
|
+
zeta_order = self._zeta_order
|
|
2744
|
+
# Map zeta to the new parent
|
|
2745
|
+
if zeta is not None:
|
|
2746
|
+
zeta = R(zeta)
|
|
2747
|
+
if isinstance(R, Map):
|
|
2748
|
+
R = R.codomain()
|
|
2749
|
+
return DirichletGroup(self.modulus(), R,
|
|
2750
|
+
zeta=zeta,
|
|
2751
|
+
zeta_order=zeta_order)
|
|
2752
|
+
|
|
2753
|
+
def base_extend(self, R):
|
|
2754
|
+
"""
|
|
2755
|
+
Return the base extension of ``self`` to ``R``.
|
|
2756
|
+
|
|
2757
|
+
INPUT:
|
|
2758
|
+
|
|
2759
|
+
- ``R`` -- either a ring admitting a *coercion* map from the
|
|
2760
|
+
base ring of ``self``, or a ring homomorphism with the base
|
|
2761
|
+
ring of ``self`` as its domain
|
|
2762
|
+
|
|
2763
|
+
EXAMPLES::
|
|
2764
|
+
|
|
2765
|
+
sage: G = DirichletGroup(7,QQ); G
|
|
2766
|
+
Group of Dirichlet characters modulo 7 with values in Rational Field
|
|
2767
|
+
sage: H = G.base_extend(CyclotomicField(6)); H
|
|
2768
|
+
Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2
|
|
2769
|
+
|
|
2770
|
+
Note that the root of unity can change::
|
|
2771
|
+
|
|
2772
|
+
sage: H.zeta()
|
|
2773
|
+
zeta6
|
|
2774
|
+
|
|
2775
|
+
This method (in contrast to :meth:`change_ring`) requires a
|
|
2776
|
+
coercion map to exist::
|
|
2777
|
+
|
|
2778
|
+
sage: G.base_extend(ZZ)
|
|
2779
|
+
Traceback (most recent call last):
|
|
2780
|
+
...
|
|
2781
|
+
TypeError: no coercion map from Rational Field to Integer Ring is defined
|
|
2782
|
+
|
|
2783
|
+
Base-extended Dirichlet groups do not silently get roots of
|
|
2784
|
+
unity with smaller order than expected (:issue:`6018`)::
|
|
2785
|
+
|
|
2786
|
+
sage: G = DirichletGroup(10, QQ).base_extend(CyclotomicField(4))
|
|
2787
|
+
sage: H = DirichletGroup(10, CyclotomicField(4))
|
|
2788
|
+
sage: G is H
|
|
2789
|
+
True
|
|
2790
|
+
|
|
2791
|
+
sage: G3 = DirichletGroup(31, CyclotomicField(3))
|
|
2792
|
+
sage: G5 = DirichletGroup(31, CyclotomicField(5))
|
|
2793
|
+
sage: K30 = CyclotomicField(30)
|
|
2794
|
+
sage: G3.gen(0).base_extend(K30) * G5.gen(0).base_extend(K30)
|
|
2795
|
+
Dirichlet character modulo 31 of conductor 31 mapping 3 |--> -zeta30^7 + zeta30^5 + zeta30^4 + zeta30^3 - zeta30 - 1
|
|
2796
|
+
|
|
2797
|
+
When a root of unity is specified, base extension still works
|
|
2798
|
+
if the new base ring is not an integral domain::
|
|
2799
|
+
|
|
2800
|
+
sage: f = DirichletGroup(17, ZZ, zeta=-1).0
|
|
2801
|
+
sage: g = f.base_extend(Integers(15))
|
|
2802
|
+
sage: g(3)
|
|
2803
|
+
14
|
|
2804
|
+
sage: g.parent().zeta()
|
|
2805
|
+
14
|
|
2806
|
+
"""
|
|
2807
|
+
if not (isinstance(R, Map) or
|
|
2808
|
+
R.has_coerce_map_from(self.base_ring())):
|
|
2809
|
+
raise TypeError("no coercion map from %s to %s is defined"
|
|
2810
|
+
% (self.base_ring(), R))
|
|
2811
|
+
return self.change_ring(R)
|
|
2812
|
+
|
|
2813
|
+
def _element_constructor_(self, x):
|
|
2814
|
+
"""
|
|
2815
|
+
Construct a Dirichlet character from `x`.
|
|
2816
|
+
|
|
2817
|
+
EXAMPLES::
|
|
2818
|
+
|
|
2819
|
+
sage: G = DirichletGroup(13)
|
|
2820
|
+
sage: K = G.base_ring()
|
|
2821
|
+
sage: G(1)
|
|
2822
|
+
Dirichlet character modulo 13 of conductor 1 mapping 2 |--> 1
|
|
2823
|
+
sage: G([-1])
|
|
2824
|
+
Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -1
|
|
2825
|
+
sage: G([K.0])
|
|
2826
|
+
Dirichlet character modulo 13 of conductor 13 mapping 2 |--> zeta12
|
|
2827
|
+
sage: G(0)
|
|
2828
|
+
Traceback (most recent call last):
|
|
2829
|
+
...
|
|
2830
|
+
TypeError: cannot convert 0 to an element of Group of Dirichlet characters modulo 13 with values in Cyclotomic Field of order 12 and degree 4
|
|
2831
|
+
|
|
2832
|
+
sage: G = DirichletGroup(6)
|
|
2833
|
+
sage: G(DirichletGroup(3).0)
|
|
2834
|
+
Dirichlet character modulo 6 of conductor 3 mapping 5 |--> -1
|
|
2835
|
+
sage: G(DirichletGroup(15).0)
|
|
2836
|
+
Dirichlet character modulo 6 of conductor 3 mapping 5 |--> -1
|
|
2837
|
+
sage: G(DirichletGroup(15).1)
|
|
2838
|
+
Traceback (most recent call last):
|
|
2839
|
+
...
|
|
2840
|
+
TypeError: conductor must divide modulus
|
|
2841
|
+
sage: H = DirichletGroup(16, QQ); H(DirichletGroup(16).1)
|
|
2842
|
+
Traceback (most recent call last):
|
|
2843
|
+
...
|
|
2844
|
+
TypeError: Unable to coerce zeta4 to a rational
|
|
2845
|
+
"""
|
|
2846
|
+
R = self.base_ring()
|
|
2847
|
+
try:
|
|
2848
|
+
if x == R.one():
|
|
2849
|
+
x = [R.one()] * len(self.unit_gens())
|
|
2850
|
+
except (TypeError, ValueError, ArithmeticError):
|
|
2851
|
+
pass
|
|
2852
|
+
if isinstance(x, list): # list of values on each unit generator
|
|
2853
|
+
return self.element_class(self, x)
|
|
2854
|
+
elif not isinstance(x, DirichletCharacter):
|
|
2855
|
+
raise TypeError("cannot convert %s to an element of %s" % (x, self))
|
|
2856
|
+
elif not x.conductor().divides(self.modulus()):
|
|
2857
|
+
raise TypeError("conductor must divide modulus")
|
|
2858
|
+
a = []
|
|
2859
|
+
for u in self.unit_gens():
|
|
2860
|
+
v = u.lift()
|
|
2861
|
+
# have to do this, since e.g., unit gens mod 11 are not units mod 22.
|
|
2862
|
+
while x.modulus().gcd(v) != 1:
|
|
2863
|
+
v += self.modulus()
|
|
2864
|
+
a.append(R(x(v)))
|
|
2865
|
+
return self.element_class(self, a)
|
|
2866
|
+
|
|
2867
|
+
def _coerce_map_from_(self, X) -> bool:
|
|
2868
|
+
"""
|
|
2869
|
+
Decide whether there is a coercion map from `X`.
|
|
2870
|
+
|
|
2871
|
+
There is conversion between Dirichlet groups of different
|
|
2872
|
+
moduli, but no coercion. This implies that Dirichlet
|
|
2873
|
+
characters of different moduli do not compare as equal.
|
|
2874
|
+
|
|
2875
|
+
TESTS::
|
|
2876
|
+
|
|
2877
|
+
sage: trivial_character(6) == trivial_character(3) # indirect doctest
|
|
2878
|
+
False
|
|
2879
|
+
sage: trivial_character(3) == trivial_character(9)
|
|
2880
|
+
False
|
|
2881
|
+
sage: trivial_character(3) == DirichletGroup(3, QQ).0^2
|
|
2882
|
+
True
|
|
2883
|
+
"""
|
|
2884
|
+
return (isinstance(X, DirichletGroup_class) and
|
|
2885
|
+
self.modulus() == X.modulus() and
|
|
2886
|
+
self.base_ring().has_coerce_map_from(X.base_ring()) and
|
|
2887
|
+
(self._zeta is None or
|
|
2888
|
+
(X._zeta is not None and
|
|
2889
|
+
self.base_ring()(X._zeta) in self._zeta_powers)))
|
|
2890
|
+
|
|
2891
|
+
def __len__(self):
|
|
2892
|
+
"""
|
|
2893
|
+
Return the number of elements of this Dirichlet group.
|
|
2894
|
+
|
|
2895
|
+
This is the same as self.order().
|
|
2896
|
+
|
|
2897
|
+
EXAMPLES::
|
|
2898
|
+
|
|
2899
|
+
sage: len(DirichletGroup(20))
|
|
2900
|
+
8
|
|
2901
|
+
sage: len(DirichletGroup(20, QQ))
|
|
2902
|
+
4
|
|
2903
|
+
sage: len(DirichletGroup(20, GF(5)))
|
|
2904
|
+
8
|
|
2905
|
+
sage: len(DirichletGroup(20, GF(2)))
|
|
2906
|
+
1
|
|
2907
|
+
sage: len(DirichletGroup(20, GF(3)))
|
|
2908
|
+
4
|
|
2909
|
+
"""
|
|
2910
|
+
return self.order()
|
|
2911
|
+
|
|
2912
|
+
def _repr_(self) -> str:
|
|
2913
|
+
"""
|
|
2914
|
+
Return a print representation of this group, which can be renamed.
|
|
2915
|
+
|
|
2916
|
+
EXAMPLES::
|
|
2917
|
+
|
|
2918
|
+
sage: G = DirichletGroup(11)
|
|
2919
|
+
sage: repr(G) # indirect doctest
|
|
2920
|
+
'Group of Dirichlet characters modulo 11 with values in Cyclotomic Field of order 10 and degree 4'
|
|
2921
|
+
sage: G.rename('Dir(11)')
|
|
2922
|
+
sage: G
|
|
2923
|
+
Dir(11)
|
|
2924
|
+
"""
|
|
2925
|
+
s = "Group of Dirichlet characters modulo %s with values in " % self.modulus()
|
|
2926
|
+
if self._zeta is not None:
|
|
2927
|
+
s += "the group of order %s generated by %s in " % (self._zeta_order, self._zeta)
|
|
2928
|
+
s += str(self.base_ring())
|
|
2929
|
+
return s
|
|
2930
|
+
|
|
2931
|
+
@cached_method
|
|
2932
|
+
def decomposition(self) -> list:
|
|
2933
|
+
r"""
|
|
2934
|
+
Return the Dirichlet groups of prime power modulus corresponding
|
|
2935
|
+
to primes dividing modulus.
|
|
2936
|
+
|
|
2937
|
+
(Note that if the modulus is 2 mod 4, there will be a "factor" of
|
|
2938
|
+
`(\ZZ/2\ZZ)^*`, which is the trivial group.)
|
|
2939
|
+
|
|
2940
|
+
EXAMPLES::
|
|
2941
|
+
|
|
2942
|
+
sage: DirichletGroup(20).decomposition()
|
|
2943
|
+
[Group of Dirichlet characters modulo 4 with values in Cyclotomic Field of order 4 and degree 2,
|
|
2944
|
+
Group of Dirichlet characters modulo 5 with values in Cyclotomic Field of order 4 and degree 2]
|
|
2945
|
+
sage: DirichletGroup(20,GF(5)).decomposition()
|
|
2946
|
+
[Group of Dirichlet characters modulo 4 with values in Finite Field of size 5,
|
|
2947
|
+
Group of Dirichlet characters modulo 5 with values in Finite Field of size 5]
|
|
2948
|
+
"""
|
|
2949
|
+
R = self.base_ring()
|
|
2950
|
+
return Sequence([DirichletGroup(p**r, R)
|
|
2951
|
+
for p, r in factor(self.modulus())],
|
|
2952
|
+
cr=True,
|
|
2953
|
+
universe=Objects())
|
|
2954
|
+
|
|
2955
|
+
def exponent(self):
|
|
2956
|
+
"""
|
|
2957
|
+
Return the exponent of this group.
|
|
2958
|
+
|
|
2959
|
+
EXAMPLES::
|
|
2960
|
+
|
|
2961
|
+
sage: DirichletGroup(20).exponent()
|
|
2962
|
+
4
|
|
2963
|
+
sage: DirichletGroup(20,GF(3)).exponent()
|
|
2964
|
+
2
|
|
2965
|
+
sage: DirichletGroup(20,GF(2)).exponent()
|
|
2966
|
+
1
|
|
2967
|
+
sage: DirichletGroup(37).exponent()
|
|
2968
|
+
36
|
|
2969
|
+
"""
|
|
2970
|
+
return self.zeta_order()
|
|
2971
|
+
|
|
2972
|
+
@cached_method
|
|
2973
|
+
def _automorphisms(self):
|
|
2974
|
+
"""
|
|
2975
|
+
Compute the automorphisms of ``self``. These are always given by raising to
|
|
2976
|
+
a power, so the return value is a list of integers.
|
|
2977
|
+
|
|
2978
|
+
At present this is only implemented if the base ring has characteristic 0 or a prime.
|
|
2979
|
+
|
|
2980
|
+
EXAMPLES::
|
|
2981
|
+
|
|
2982
|
+
sage: DirichletGroup(17)._automorphisms()
|
|
2983
|
+
[1, 3, 5, 7, 9, 11, 13, 15]
|
|
2984
|
+
sage: DirichletGroup(17, GF(11^4, 'a'))._automorphisms()
|
|
2985
|
+
[1, 11, 121, 1331]
|
|
2986
|
+
sage: DirichletGroup(17, Integers(6), zeta=Integers(6)(5))._automorphisms()
|
|
2987
|
+
Traceback (most recent call last):
|
|
2988
|
+
...
|
|
2989
|
+
NotImplementedError: Automorphisms for finite non-field base rings not implemented
|
|
2990
|
+
sage: DirichletGroup(17, Integers(9), zeta=Integers(9)(2))._automorphisms()
|
|
2991
|
+
Traceback (most recent call last):
|
|
2992
|
+
...
|
|
2993
|
+
NotImplementedError: Automorphisms for finite non-field base rings not implemented
|
|
2994
|
+
"""
|
|
2995
|
+
n = self.zeta_order()
|
|
2996
|
+
R = self.base_ring()
|
|
2997
|
+
p = R.characteristic()
|
|
2998
|
+
if p == 0:
|
|
2999
|
+
Auts = [e for e in range(1, n) if gcd(e, n) == 1]
|
|
3000
|
+
else:
|
|
3001
|
+
if not Integer(p).is_prime():
|
|
3002
|
+
raise NotImplementedError("Automorphisms for finite non-field base rings not implemented")
|
|
3003
|
+
# The automorphisms in characteristic p are
|
|
3004
|
+
# k-th powering for
|
|
3005
|
+
# k = 1, p, p^2, ..., p^(r-1),
|
|
3006
|
+
# where p^r = 1 (mod n), so r is the mult order of p modulo n.
|
|
3007
|
+
r = IntegerModRing(n)(p).multiplicative_order()
|
|
3008
|
+
Auts = [p**m for m in range(r)]
|
|
3009
|
+
return Auts
|
|
3010
|
+
|
|
3011
|
+
def galois_orbits(self, v=None, reps_only=False, sort=True, check=True):
|
|
3012
|
+
"""
|
|
3013
|
+
Return a list of the Galois orbits of Dirichlet characters in ``self``,
|
|
3014
|
+
or in ``v`` if ``v`` is not ``None``.
|
|
3015
|
+
|
|
3016
|
+
INPUT:
|
|
3017
|
+
|
|
3018
|
+
- ``v`` -- (optional) list of elements of ``self``
|
|
3019
|
+
|
|
3020
|
+
- ``reps_only`` -- (optional: default ``False``) if ``True``
|
|
3021
|
+
only returns representatives for the orbits
|
|
3022
|
+
|
|
3023
|
+
- ``sort`` -- (optional: default ``True``) whether to sort
|
|
3024
|
+
the list of orbits and the orbits themselves (slightly faster if
|
|
3025
|
+
``False``).
|
|
3026
|
+
|
|
3027
|
+
- ``check`` -- boolean (default: ``True``); whether or not
|
|
3028
|
+
to explicitly coerce each element of ``v`` into ``self``
|
|
3029
|
+
|
|
3030
|
+
The Galois group is the absolute Galois group of the prime subfield
|
|
3031
|
+
of Frac(R). If R is not a domain, an error will be raised.
|
|
3032
|
+
|
|
3033
|
+
EXAMPLES::
|
|
3034
|
+
|
|
3035
|
+
sage: DirichletGroup(20).galois_orbits()
|
|
3036
|
+
[[Dirichlet character modulo 20 of conductor 20 mapping ...]]
|
|
3037
|
+
sage: DirichletGroup(17, Integers(6), zeta=Integers(6)(5)).galois_orbits()
|
|
3038
|
+
Traceback (most recent call last):
|
|
3039
|
+
...
|
|
3040
|
+
TypeError: Galois orbits only defined if base ring is an integral domain
|
|
3041
|
+
sage: DirichletGroup(17, Integers(9), zeta=Integers(9)(2)).galois_orbits()
|
|
3042
|
+
Traceback (most recent call last):
|
|
3043
|
+
...
|
|
3044
|
+
TypeError: Galois orbits only defined if base ring is an integral domain
|
|
3045
|
+
"""
|
|
3046
|
+
if v is None:
|
|
3047
|
+
v = self.list()
|
|
3048
|
+
else:
|
|
3049
|
+
if check:
|
|
3050
|
+
v = [self(x) for x in v]
|
|
3051
|
+
|
|
3052
|
+
G = []
|
|
3053
|
+
seen_so_far = set()
|
|
3054
|
+
for x in v:
|
|
3055
|
+
z = x.element()
|
|
3056
|
+
e = tuple(z) # change when there are immutable vectors (and below)
|
|
3057
|
+
if e in seen_so_far:
|
|
3058
|
+
continue
|
|
3059
|
+
orbit = x.galois_orbit(sort=sort)
|
|
3060
|
+
if reps_only:
|
|
3061
|
+
G.append(x)
|
|
3062
|
+
else:
|
|
3063
|
+
G.append(orbit)
|
|
3064
|
+
for z in orbit:
|
|
3065
|
+
seen_so_far.add(tuple(z.element()))
|
|
3066
|
+
G = Sequence(G, cr=True)
|
|
3067
|
+
if sort:
|
|
3068
|
+
G.sort()
|
|
3069
|
+
return G
|
|
3070
|
+
|
|
3071
|
+
def gen(self, n=0):
|
|
3072
|
+
"""
|
|
3073
|
+
Return the `n`-th generator of ``self``.
|
|
3074
|
+
|
|
3075
|
+
EXAMPLES::
|
|
3076
|
+
|
|
3077
|
+
sage: G = DirichletGroup(20)
|
|
3078
|
+
sage: G.gen(0)
|
|
3079
|
+
Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1
|
|
3080
|
+
sage: G.gen(1)
|
|
3081
|
+
Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> zeta4
|
|
3082
|
+
sage: G.gen(2)
|
|
3083
|
+
Traceback (most recent call last):
|
|
3084
|
+
...
|
|
3085
|
+
IndexError: n(=2) must be between 0 and 1
|
|
3086
|
+
|
|
3087
|
+
::
|
|
3088
|
+
|
|
3089
|
+
sage: G.gen(-1)
|
|
3090
|
+
Traceback (most recent call last):
|
|
3091
|
+
...
|
|
3092
|
+
IndexError: n(=-1) must be between 0 and 1
|
|
3093
|
+
"""
|
|
3094
|
+
n = int(n)
|
|
3095
|
+
g = self.gens()
|
|
3096
|
+
if n < 0 or n >= len(g):
|
|
3097
|
+
raise IndexError("n(=%s) must be between 0 and %s" % (n, len(g) - 1))
|
|
3098
|
+
return g[n]
|
|
3099
|
+
|
|
3100
|
+
@cached_method
|
|
3101
|
+
def gens(self) -> tuple:
|
|
3102
|
+
"""
|
|
3103
|
+
Return generators of ``self``.
|
|
3104
|
+
|
|
3105
|
+
EXAMPLES::
|
|
3106
|
+
|
|
3107
|
+
sage: G = DirichletGroup(20)
|
|
3108
|
+
sage: G.gens()
|
|
3109
|
+
(Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1, Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> zeta4)
|
|
3110
|
+
"""
|
|
3111
|
+
g = []
|
|
3112
|
+
ord = self.zeta_order()
|
|
3113
|
+
M = self._module
|
|
3114
|
+
zero = M.zero()
|
|
3115
|
+
orders = self.integers_mod().unit_group().gens_orders()
|
|
3116
|
+
for i in range(len(self.unit_gens())):
|
|
3117
|
+
z = zero.__copy__()
|
|
3118
|
+
z[i] = ord // gcd(ord, orders[i])
|
|
3119
|
+
g.append(self.element_class(self, z, check=False))
|
|
3120
|
+
return tuple(g)
|
|
3121
|
+
|
|
3122
|
+
def integers_mod(self):
|
|
3123
|
+
r"""
|
|
3124
|
+
Return the group of integers `\ZZ/N\ZZ`
|
|
3125
|
+
where `N` is the modulus of ``self``.
|
|
3126
|
+
|
|
3127
|
+
EXAMPLES::
|
|
3128
|
+
|
|
3129
|
+
sage: G = DirichletGroup(20)
|
|
3130
|
+
sage: G.integers_mod()
|
|
3131
|
+
Ring of integers modulo 20
|
|
3132
|
+
"""
|
|
3133
|
+
return self._integers
|
|
3134
|
+
|
|
3135
|
+
__iter__ = multiplicative_iterator
|
|
3136
|
+
|
|
3137
|
+
def list(self) -> list:
|
|
3138
|
+
"""
|
|
3139
|
+
Return a list of the Dirichlet characters in this group.
|
|
3140
|
+
|
|
3141
|
+
EXAMPLES::
|
|
3142
|
+
|
|
3143
|
+
sage: DirichletGroup(5).list()
|
|
3144
|
+
[Dirichlet character modulo 5 of conductor 1 mapping 2 |--> 1,
|
|
3145
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> zeta4,
|
|
3146
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1,
|
|
3147
|
+
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -zeta4]
|
|
3148
|
+
"""
|
|
3149
|
+
return self._list_from_iterator()
|
|
3150
|
+
|
|
3151
|
+
def modulus(self):
|
|
3152
|
+
"""
|
|
3153
|
+
Return the modulus of ``self``.
|
|
3154
|
+
|
|
3155
|
+
EXAMPLES::
|
|
3156
|
+
|
|
3157
|
+
sage: G = DirichletGroup(20)
|
|
3158
|
+
sage: G.modulus()
|
|
3159
|
+
20
|
|
3160
|
+
"""
|
|
3161
|
+
return self._modulus
|
|
3162
|
+
|
|
3163
|
+
def ngens(self) -> int:
|
|
3164
|
+
"""
|
|
3165
|
+
Return the number of generators of ``self``.
|
|
3166
|
+
|
|
3167
|
+
EXAMPLES::
|
|
3168
|
+
|
|
3169
|
+
sage: G = DirichletGroup(20)
|
|
3170
|
+
sage: G.ngens()
|
|
3171
|
+
2
|
|
3172
|
+
"""
|
|
3173
|
+
return len(self.gens())
|
|
3174
|
+
|
|
3175
|
+
@cached_method
|
|
3176
|
+
def order(self):
|
|
3177
|
+
"""
|
|
3178
|
+
Return the number of elements of ``self``.
|
|
3179
|
+
|
|
3180
|
+
This is the same as len(self).
|
|
3181
|
+
|
|
3182
|
+
EXAMPLES::
|
|
3183
|
+
|
|
3184
|
+
sage: DirichletGroup(20).order()
|
|
3185
|
+
8
|
|
3186
|
+
sage: DirichletGroup(37).order()
|
|
3187
|
+
36
|
|
3188
|
+
"""
|
|
3189
|
+
ord = Integer(1)
|
|
3190
|
+
for g in self.gens():
|
|
3191
|
+
ord *= int(g.order())
|
|
3192
|
+
return ord
|
|
3193
|
+
|
|
3194
|
+
def random_element(self):
|
|
3195
|
+
"""
|
|
3196
|
+
Return a random element of ``self``.
|
|
3197
|
+
|
|
3198
|
+
The element is computed by multiplying a random power of each
|
|
3199
|
+
generator together, where the power is between 0 and the order of
|
|
3200
|
+
the generator minus 1, inclusive.
|
|
3201
|
+
|
|
3202
|
+
EXAMPLES::
|
|
3203
|
+
|
|
3204
|
+
sage: D = DirichletGroup(37)
|
|
3205
|
+
sage: g = D.random_element()
|
|
3206
|
+
sage: g.parent() is D
|
|
3207
|
+
True
|
|
3208
|
+
sage: g**36
|
|
3209
|
+
Dirichlet character modulo 37 of conductor 1 mapping 2 |--> 1
|
|
3210
|
+
sage: S = set(D.random_element().conductor() for _ in range(100))
|
|
3211
|
+
sage: while S != {1, 37}:
|
|
3212
|
+
....: S.add(D.random_element().conductor())
|
|
3213
|
+
|
|
3214
|
+
sage: D = DirichletGroup(20)
|
|
3215
|
+
sage: g = D.random_element()
|
|
3216
|
+
sage: g.parent() is D
|
|
3217
|
+
True
|
|
3218
|
+
sage: g**4
|
|
3219
|
+
Dirichlet character modulo 20 of conductor 1 mapping 11 |--> 1, 17 |--> 1
|
|
3220
|
+
sage: S = set(D.random_element().conductor() for _ in range(100))
|
|
3221
|
+
sage: while S != {1, 4, 5, 20}:
|
|
3222
|
+
....: S.add(D.random_element().conductor())
|
|
3223
|
+
|
|
3224
|
+
sage: D = DirichletGroup(60)
|
|
3225
|
+
sage: g = D.random_element()
|
|
3226
|
+
sage: g.parent() is D
|
|
3227
|
+
True
|
|
3228
|
+
sage: g**4
|
|
3229
|
+
Dirichlet character modulo 60 of conductor 1 mapping 31 |--> 1, 41 |--> 1, 37 |--> 1
|
|
3230
|
+
sage: S = set(D.random_element().conductor() for _ in range(100))
|
|
3231
|
+
sage: while S != {1, 3, 4, 5, 12, 15, 20, 60}:
|
|
3232
|
+
....: S.add(D.random_element().conductor())
|
|
3233
|
+
"""
|
|
3234
|
+
e = self(1)
|
|
3235
|
+
for i in range(self.ngens()):
|
|
3236
|
+
g = self.gen(i)
|
|
3237
|
+
n = random.randrange(g.order())
|
|
3238
|
+
e *= g**n
|
|
3239
|
+
return e
|
|
3240
|
+
|
|
3241
|
+
def unit_gens(self) -> tuple:
|
|
3242
|
+
r"""
|
|
3243
|
+
Return the minimal generators for the units of
|
|
3244
|
+
`(\ZZ/N\ZZ)^*`, where `N` is the
|
|
3245
|
+
modulus of ``self``.
|
|
3246
|
+
|
|
3247
|
+
EXAMPLES::
|
|
3248
|
+
|
|
3249
|
+
sage: DirichletGroup(37).unit_gens()
|
|
3250
|
+
(2,)
|
|
3251
|
+
sage: DirichletGroup(20).unit_gens()
|
|
3252
|
+
(11, 17)
|
|
3253
|
+
sage: DirichletGroup(60).unit_gens()
|
|
3254
|
+
(31, 41, 37)
|
|
3255
|
+
sage: DirichletGroup(20,QQ).unit_gens()
|
|
3256
|
+
(11, 17)
|
|
3257
|
+
"""
|
|
3258
|
+
return self._integers.unit_gens()
|
|
3259
|
+
|
|
3260
|
+
@cached_method
|
|
3261
|
+
def zeta(self):
|
|
3262
|
+
"""
|
|
3263
|
+
Return the chosen root of unity in the base ring.
|
|
3264
|
+
|
|
3265
|
+
EXAMPLES::
|
|
3266
|
+
|
|
3267
|
+
sage: DirichletGroup(37).zeta()
|
|
3268
|
+
zeta36
|
|
3269
|
+
sage: DirichletGroup(20).zeta()
|
|
3270
|
+
zeta4
|
|
3271
|
+
sage: DirichletGroup(60).zeta()
|
|
3272
|
+
zeta4
|
|
3273
|
+
sage: DirichletGroup(60,QQ).zeta()
|
|
3274
|
+
-1
|
|
3275
|
+
sage: DirichletGroup(60, GF(25,'a')).zeta()
|
|
3276
|
+
2
|
|
3277
|
+
"""
|
|
3278
|
+
zeta = self._zeta
|
|
3279
|
+
if zeta is None:
|
|
3280
|
+
R = self.base_ring()
|
|
3281
|
+
e = self._integers.unit_group_exponent()
|
|
3282
|
+
for d in reversed(e.divisors()):
|
|
3283
|
+
try:
|
|
3284
|
+
zeta = R.zeta(d)
|
|
3285
|
+
break
|
|
3286
|
+
except ValueError:
|
|
3287
|
+
pass
|
|
3288
|
+
self.zeta_order.set_cache(d)
|
|
3289
|
+
return zeta
|
|
3290
|
+
|
|
3291
|
+
@cached_method
|
|
3292
|
+
def zeta_order(self):
|
|
3293
|
+
"""
|
|
3294
|
+
Return the order of the chosen root of unity in the base ring.
|
|
3295
|
+
|
|
3296
|
+
EXAMPLES::
|
|
3297
|
+
|
|
3298
|
+
sage: DirichletGroup(20).zeta_order()
|
|
3299
|
+
4
|
|
3300
|
+
sage: DirichletGroup(60).zeta_order()
|
|
3301
|
+
4
|
|
3302
|
+
sage: DirichletGroup(60, GF(25,'a')).zeta_order()
|
|
3303
|
+
4
|
|
3304
|
+
sage: DirichletGroup(19).zeta_order()
|
|
3305
|
+
18
|
|
3306
|
+
"""
|
|
3307
|
+
order = self._zeta_order
|
|
3308
|
+
if order is None:
|
|
3309
|
+
order = self.zeta().multiplicative_order()
|
|
3310
|
+
return order
|