Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/local_comp/smoothchar.py
4057 views
1
r"""
2
Smooth characters of `p`-adic fields
3
4
Let `F` be a finite extension of `\QQ_p`. Then we may consider the group of
5
smooth (i.e. locally constant) group homomorphisms `F^\times \to L^\times`, for
6
`L` any field. Such characters are important since they can be used to
7
parametrise smooth representations of `\mathrm{GL}_2(\QQ_p)`, which arise as
8
the local components of modular forms.
9
10
This module contains classes to represent such characters when `F` is `\QQ_p`
11
or a quadratic extension. In the latter case, we choose a quadratic extension
12
`K` of `\QQ` whose completion at `p` is `F`, and use Sage's wrappers of the
13
Pari ``idealstar`` and ``ideallog`` methods to work in the finite group
14
`\mathcal{O}_K / p^c` for `c \ge 0`.
15
16
An example with characters of `\QQ_7`::
17
18
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
19
sage: K.<z> = CyclotomicField(42)
20
sage: G = SmoothCharacterGroupQp(7, K)
21
sage: G.unit_gens(2), G.exponents(2)
22
([3, 7], [42, 0])
23
24
The output of the last line means that the group `\QQ_7^\times / (1 + 7^2
25
\ZZ_7)` is isomorphic to `C_{42} \times \ZZ`, with the two factors being
26
generated by `3` and `7` respectively. We create a character by specifying the
27
images of these generators::
28
29
sage: chi = G.character(2, [z^5, 11 + z]); chi
30
Character of Q_7*, of level 2, mapping 3 |--> z^5, 7 |--> z + 11
31
sage: chi(4)
32
z^8
33
sage: chi(42)
34
z^10 + 11*z^9
35
36
Characters are themselves group elements, and basic arithmetic on them works::
37
38
sage: chi**3
39
Character of Q_7*, of level 2, mapping 3 |--> z^8 - z, 7 |--> z^3 + 33*z^2 + 363*z + 1331
40
sage: chi.multiplicative_order()
41
+Infinity
42
"""
43
44
import operator
45
from sage.structure.element import MultiplicativeGroupElement
46
from sage.structure.parent_base import ParentWithBase
47
from sage.structure.sequence import Sequence
48
from sage.rings.all import QQ, ZZ, Zmod, NumberField, is_Ring
49
from sage.misc.cachefunc import cached_method
50
from sage.misc.abstract_method import abstract_method
51
from sage.misc.misc_c import prod
52
from sage.categories.groups import Groups
53
from sage.functions.other import ceil
54
from sage.misc.mrange import xmrange
55
56
from sage.structure.element import FieldElement
57
58
class SmoothCharacterGeneric(MultiplicativeGroupElement):
59
r"""
60
A smooth (i.e. locally constant) character of `F^\times`, for `F` some
61
finite extension of `\QQ_p`.
62
"""
63
def __init__(self, parent, c, values_on_gens):
64
r"""
65
Standard init function.
66
67
EXAMPLES::
68
69
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
70
sage: G = SmoothCharacterGroupUnramifiedQuadratic(2, QQ)
71
sage: G.character(0, [17]) # indirect doctest
72
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 0, mapping 2 |--> 17
73
sage: G.character(1, [1, 17]) # indirect doctest
74
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 0, mapping 2 |--> 17
75
sage: G.character(2, [1, -1, 1, 17]) # indirect doctest
76
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 2, mapping s |--> 1, 2*s + 1 |--> -1, -1 |--> 1, 2 |--> 17
77
sage: G.character(2, [1, 1, 1, 17]) # indirect doctest
78
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 0, mapping 2 |--> 17
79
"""
80
MultiplicativeGroupElement.__init__(self, parent)
81
self._c = c
82
self._values_on_gens = values_on_gens
83
self._check_level()
84
85
def _check_level(self):
86
r"""
87
Checks that this character has the level it claims to have, and if not,
88
decrement the level by 1. This is called by :meth:`__init__`.
89
90
EXAMPLES::
91
92
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
93
sage: SmoothCharacterGroupQp(5, QQ).character(5, [-1, 7]) # indirect doctest
94
Character of Q_5*, of level 1, mapping 2 |--> -1, 5 |--> 7
95
"""
96
if self.level() == 0: return
97
v = self.parent().subgroup_gens(self.level())
98
if all([self(x) == 1 for x in v]):
99
new_gens = self.parent().unit_gens(self.level() - 1)
100
new_values = [self(x) for x in new_gens]
101
self._values_on_gens = Sequence(new_values, universe=self.base_ring(), immutable=True)
102
self._c = self._c - 1
103
self._check_level()
104
105
def __cmp__(self, other):
106
r"""
107
Compare self and other. Note that this only gets called when the
108
parents of self and other are identical.
109
110
EXAMPLE::
111
112
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp, SmoothCharacterGroupUnramifiedQuadratic
113
sage: SmoothCharacterGroupQp(7, Zmod(3)).character(1, [2, 1]) == SmoothCharacterGroupQp(7, ZZ).character(1, [-1, 1])
114
True
115
sage: chi1 = SmoothCharacterGroupUnramifiedQuadratic(7, QQ).character(0, [1])
116
sage: chi2 = SmoothCharacterGroupQp(7, QQ).character(0, [1])
117
sage: chi1 == chi2
118
False
119
sage: chi2.parent()(chi1) == chi2
120
True
121
sage: chi1 == loads(dumps(chi1))
122
True
123
"""
124
assert other.parent() is self.parent()
125
return cmp(self.level(), other.level()) or cmp(self._values_on_gens, other._values_on_gens)
126
127
def multiplicative_order(self):
128
r"""
129
Return the order of this character as an element of the character group.
130
131
EXAMPLE::
132
133
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
134
sage: K.<z> = CyclotomicField(42)
135
sage: G = SmoothCharacterGroupQp(7, K)
136
sage: G.character(3, [z^10 - z^3, 11]).multiplicative_order()
137
+Infinity
138
sage: G.character(3, [z^10 - z^3, 1]).multiplicative_order()
139
42
140
sage: G.character(1, [z^7, z^14]).multiplicative_order()
141
6
142
sage: G.character(0, [1]).multiplicative_order()
143
1
144
"""
145
from sage.rings.arith import lcm
146
from sage.rings.infinity import Infinity
147
if self._values_on_gens[-1].multiplicative_order() == Infinity:
148
return Infinity
149
else:
150
return lcm([x.multiplicative_order() for x in self._values_on_gens])
151
152
def level(self):
153
r"""
154
Return the level of this character, i.e. the smallest integer `c \ge 0`
155
such that it is trivial on `1 + \mathfrak{p}^c`.
156
157
EXAMPLES::
158
159
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
160
sage: SmoothCharacterGroupQp(7, QQ).character(2, [-1, 1]).level()
161
1
162
"""
163
return self._c
164
165
def __call__(self, x):
166
r"""
167
Evaluate the character at ``x``, which should be a nonzero element of
168
the number field of the parent group.
169
170
EXAMPLES::
171
172
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
173
sage: K.<z> = CyclotomicField(42)
174
sage: chi = SmoothCharacterGroupQp(7, K).character(3, [z^10 - z^3, 11])
175
sage: [chi(x) for x in [1, 2, 3, 9, 21, 1/12345678]]
176
[1, -z, z^10 - z^3, -z^11 - z^10 + z^8 + z^7 - z^6 - z^5 + z^3 + z^2 - 1, 11*z^10 - 11*z^3, z^7 - 1]
177
178
Non-examples::
179
180
sage: chi(QuadraticField(-1,'i').gen())
181
Traceback (most recent call last):
182
...
183
TypeError: no canonical coercion from Number Field in i with defining polynomial x^2 + 1 to Rational Field
184
sage: chi(0)
185
Traceback (most recent call last):
186
...
187
ValueError: cannot evaluate at zero
188
sage: chi(Mod(1, 12))
189
Traceback (most recent call last):
190
...
191
TypeError: no canonical coercion from Ring of integers modulo 12 to Rational Field
192
193
Some examples with an unramified quadratic extension, where the choice
194
of generators is arbitrary (but deterministic)::
195
196
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
197
sage: K.<z> = CyclotomicField(30)
198
sage: G = SmoothCharacterGroupUnramifiedQuadratic(5, K)
199
sage: chi = G.character(2, [z**5, z**(-6), z**6, 3]); chi
200
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 2, mapping 11*s - 10 |--> z^5, 6 |--> -z^7 - z^6 + z^3 + z^2 - 1, 5*s + 1 |--> z^6, 5 |--> 3
201
sage: chi(G.unit_gens(2)[0]**7 / G.unit_gens(2)[1]/5)
202
1/3*z^6 - 1/3*z
203
sage: chi(2)
204
-z^3
205
"""
206
v = self.parent().discrete_log(self.level(), x)
207
return prod([self._values_on_gens[i] ** v[i] for i in xrange(len(v))])
208
209
def _repr_(self):
210
r"""
211
String representation of this character.
212
213
EXAMPLES::
214
215
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
216
sage: K.<z> = CyclotomicField(20)
217
sage: SmoothCharacterGroupQp(5, K).character(2, [z, z+1])._repr_()
218
'Character of Q_5*, of level 2, mapping 2 |--> z, 5 |--> z + 1'
219
220
Examples over field extensions::
221
222
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
223
sage: K.<z> = CyclotomicField(15)
224
sage: SmoothCharacterGroupUnramifiedQuadratic(5, K).character(2, [z**5, z**3, 1, z+1])._repr_()
225
'Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 2, mapping 11*s - 10 |--> z^5, 6 |--> z^3, 5*s + 1 |--> 1, 5 |--> z + 1'
226
"""
227
gens = self.parent().unit_gens(self.level())
228
mapst = ", ".join( str(gens[i]) + ' |--> ' + str(self._values_on_gens[i]) for i in range(len(gens)) )
229
return "Character of %s, of level %s, mapping %s" % (self.parent()._field_name(), self.level(), mapst)
230
231
def _mul_(self, other):
232
r"""
233
Product of self and other.
234
235
EXAMPLES::
236
237
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
238
sage: K.<z> = CyclotomicField(20)
239
sage: chi1 = SmoothCharacterGroupQp(5, K).character(2, [z, z+1])
240
sage: chi2 = SmoothCharacterGroupQp(5, K).character(2, [z^4, 3])
241
sage: chi1 * chi2 # indirect doctest
242
Character of Q_5*, of level 1, mapping 2 |--> z^5, 5 |--> 3*z + 3
243
sage: chi2 * chi1 # indirect doctest
244
Character of Q_5*, of level 1, mapping 2 |--> z^5, 5 |--> 3*z + 3
245
sage: chi1 * SmoothCharacterGroupQp(5, QQ).character(2, [-1, 7]) # indirect doctest
246
Character of Q_5*, of level 2, mapping 2 |--> -z, 5 |--> 7*z + 7
247
"""
248
if other.level() > self.level():
249
return other * self
250
return self.parent().character(self.level(), [self(x) * other(x) for x in self.parent().unit_gens(self.level())])
251
252
def __invert__(self):
253
r"""
254
Multiplicative inverse of self.
255
256
EXAMPLES::
257
258
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
259
sage: K.<z> = CyclotomicField(12)
260
sage: chi = SmoothCharacterGroupUnramifiedQuadratic(2, K).character(4, [z**4, z**3, z**9, -1, 7]); chi
261
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 4, mapping s |--> z^2 - 1, 2*s + 1 |--> z^3, 4*s + 1 |--> -z^3, -1 |--> -1, 2 |--> 7
262
sage: chi**(-1) # indirect doctest
263
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 4, mapping s |--> -z^2, 2*s + 1 |--> -z^3, 4*s + 1 |--> z^3, -1 |--> -1, 2 |--> 1/7
264
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).character(0, [7]) / chi # indirect doctest
265
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 4, mapping s |--> -z^2, 2*s + 1 |--> -z^3, 4*s + 1 |--> z^3, -1 |--> -1, 2 |--> 1
266
"""
267
return self.parent().character(self.level(), [~self(x) for x in self.parent().unit_gens(self.level())])
268
269
def restrict_to_Qp(self):
270
r"""
271
Return the restriction of this character to `\QQ_p^\times`, embedded as
272
a subfield of `F^\times`.
273
274
EXAMPLE::
275
276
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
277
sage: SmoothCharacterGroupRamifiedQuadratic(3, 0, QQ).character(0, [2]).restrict_to_Qp()
278
Character of Q_3*, of level 0, mapping 3 |--> 4
279
"""
280
G = SmoothCharacterGroupQp(self.parent().prime(), self.base_ring())
281
ugs = G.unit_gens(self.level())
282
return G.character(self.level(), [self(x) for x in ugs])
283
284
def galois_conjugate(self):
285
r"""
286
Return the composite of this character with the order `2` automorphism of
287
`K / \QQ_p` (assuming `K` is quadratic).
288
289
Note that this is the Galois operation on the *domain*, not on the
290
*codomain*.
291
292
EXAMPLE::
293
294
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
295
sage: K.<w> = CyclotomicField(3)
296
sage: G = SmoothCharacterGroupUnramifiedQuadratic(2, K)
297
sage: chi = G.character(2, [w, -1,-1, 3*w])
298
sage: chi2 = chi.galois_conjugate(); chi2
299
Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 2, mapping s |--> -w - 1, 2*s + 1 |--> 1, -1 |--> -1, 2 |--> 3*w
300
301
sage: chi.restrict_to_Qp() == chi2.restrict_to_Qp()
302
True
303
sage: chi * chi2 == chi.parent().compose_with_norm(chi.restrict_to_Qp())
304
True
305
"""
306
K,s = self.parent().number_field().objgen()
307
if K.absolute_degree() != 2:
308
raise ValueError( "Character must be defined on a quadratic extension" )
309
sigs = K.embeddings(K)
310
sig = [x for x in sigs if x(s) != s][0]
311
return self.parent().character(self.level(), [self(sig(x)) for x in self.parent().unit_gens(self.level())])
312
313
314
class SmoothCharacterGroupGeneric(ParentWithBase):
315
r"""
316
The group of smooth (i.e. locally constant) characters of a `p`-adic field,
317
with values in some ring `R`. This is an abstract base class and should not
318
be instantiated directly.
319
"""
320
321
Element = SmoothCharacterGeneric
322
323
def __init__(self, p, base_ring):
324
r"""
325
TESTS::
326
327
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
328
sage: G = SmoothCharacterGroupGeneric(3, QQ)
329
sage: SmoothCharacterGroupGeneric(3, "hello")
330
Traceback (most recent call last):
331
...
332
TypeError: base ring (=hello) must be a ring
333
"""
334
if not is_Ring(base_ring):
335
raise TypeError( "base ring (=%s) must be a ring" % base_ring )
336
ParentWithBase.__init__(self, base=base_ring, category=Groups())
337
if not (p in ZZ and ZZ(p).is_prime()):
338
raise ValueError( "p (=%s) must be a prime integer" % p )
339
self._p = ZZ.coerce(p)
340
341
def _element_constructor_(self, x):
342
r"""
343
Construct an element of this group from ``x`` (possibly noncanonically).
344
This only works if ``x`` is a character of a field containing the field of
345
self, whose values lie in a field that can be converted into self.
346
347
EXAMPLES::
348
349
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
350
sage: K.<i> = QuadraticField(-1)
351
sage: G = SmoothCharacterGroupQp(3, QQ)
352
sage: GK = SmoothCharacterGroupQp(3, K)
353
sage: chi = GK(G.character(0, [4])); chi # indirect doctest
354
Character of Q_3*, of level 0, mapping 3 |--> 4
355
sage: chi.parent() is GK
356
True
357
sage: G(GK.character(0, [7])) # indirect doctest
358
Character of Q_3*, of level 0, mapping 3 |--> 7
359
sage: G(GK.character(0, [i])) # indirect doctest
360
Traceback (most recent call last):
361
...
362
TypeError: Unable to coerce i to a rational
363
"""
364
if x == 1:
365
return self.character(0, [1])
366
if hasattr(x, 'parent') \
367
and isinstance(x.parent(), SmoothCharacterGroupGeneric) \
368
and x.parent().number_field().has_coerce_map_from(self.number_field()):
369
return self.character(x.level(), [x(v) for v in self.unit_gens(x.level())])
370
else:
371
raise TypeError
372
373
def __cmp__(self, other):
374
r"""
375
TESTS::
376
377
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
378
sage: G = SmoothCharacterGroupQp(3, QQ)
379
sage: G == SmoothCharacterGroupQp(3, QQ[I])
380
False
381
sage: G == 7
382
False
383
sage: G == SmoothCharacterGroupQp(7, QQ)
384
False
385
sage: G == SmoothCharacterGroupQp(3, QQ)
386
True
387
"""
388
return cmp(type(self), type(other)) \
389
or cmp(self.prime(), other.prime()) \
390
or cmp(self.number_field(), other.number_field()) \
391
or cmp(self.base_ring(), other.base_ring())
392
393
def _coerce_map_from_(self, other):
394
r"""
395
Return True if self has a canonical coerce map from other.
396
397
EXAMPLES::
398
399
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
400
sage: K.<i> = QuadraticField(-1)
401
sage: G = SmoothCharacterGroupQp(3, QQ)
402
sage: GK = SmoothCharacterGroupQp(3, K)
403
sage: G.has_coerce_map_from(GK)
404
False
405
sage: GK.has_coerce_map_from(G)
406
True
407
sage: GK.coerce(G.character(0, [4]))
408
Character of Q_3*, of level 0, mapping 3 |--> 4
409
sage: G.coerce(GK.character(0, [4]))
410
Traceback (most recent call last):
411
...
412
TypeError: no canonical coercion from Group of smooth characters of Q_3* with values in Number Field in i with defining polynomial x^2 + 1 to Group of smooth characters of Q_3* with values in Rational Field
413
sage: G.character(0, [4]) in GK # indirect doctest
414
True
415
416
The coercion framework handles base extension, so we test that too::
417
418
sage: K.<i> = QuadraticField(-1)
419
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
420
sage: G = SmoothCharacterGroupUnramifiedQuadratic(3, QQ)
421
sage: G.character(0, [1]).base_extend(K)
422
Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), of level 0, mapping 3 |--> 1
423
424
"""
425
if isinstance(other, SmoothCharacterGroupGeneric) \
426
and other.number_field() == self.number_field() \
427
and self.base_ring().has_coerce_map_from(other.base_ring()):
428
return True
429
else:
430
return False
431
432
def prime(self):
433
r"""
434
The residue characteristic of the underlying field.
435
436
EXAMPLE::
437
438
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
439
sage: SmoothCharacterGroupGeneric(3, QQ).prime()
440
3
441
"""
442
return self._p
443
444
@abstract_method
445
def change_ring(self, ring):
446
r"""
447
Return the character group of the same field, but with values in a
448
different coefficient ring. To be implemented by all derived classes
449
(since the generic base class can't know the parameters).
450
451
EXAMPLE::
452
453
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
454
sage: SmoothCharacterGroupGeneric(3, QQ).change_ring(ZZ)
455
Traceback (most recent call last):
456
...
457
NotImplementedError: <abstract method change_ring at ...>
458
"""
459
pass
460
461
def base_extend(self, ring):
462
r"""
463
Return the character group of the same field, but with values in a new
464
coefficient ring into which the old coefficient ring coerces. An error
465
will be raised if there is no coercion map from the old coefficient
466
ring to the new one.
467
468
EXAMPLE::
469
470
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
471
sage: G = SmoothCharacterGroupQp(3, QQ)
472
sage: G.base_extend(QQbar)
473
Group of smooth characters of Q_3* with values in Algebraic Field
474
sage: G.base_extend(Zmod(3))
475
Traceback (most recent call last):
476
...
477
TypeError: no canonical coercion from Rational Field to Ring of integers modulo 3
478
479
"""
480
if not ring.has_coerce_map_from(self.base_ring()) :
481
ring.coerce(self.base_ring().an_element())
482
# this is here to flush out errors
483
484
return self.change_ring(ring)
485
486
@abstract_method
487
def _field_name(self):
488
r"""
489
A string representing the name of the p-adic field of which this is the
490
character group. To be overridden by derived subclasses.
491
492
EXAMPLE::
493
494
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
495
sage: SmoothCharacterGroupGeneric(3, QQ)._field_name()
496
Traceback (most recent call last):
497
...
498
NotImplementedError: <abstract method _field_name at ...>
499
"""
500
pass
501
502
def _repr_(self):
503
r"""
504
String representation of self.
505
506
EXAMPLE::
507
508
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
509
sage: SmoothCharacterGroupQp(7, QQ)._repr_()
510
'Group of smooth characters of Q_7* with values in Rational Field'
511
"""
512
return "Group of smooth characters of %s with values in %s" % (self._field_name(), self.base_ring())
513
514
@abstract_method
515
def ideal(self, level):
516
r"""
517
Return the ``level``-th power of the maximal ideal of the ring of
518
integers of the p-adic field. Since we approximate by using number
519
field arithmetic, what is actually returned is an ideal in a number
520
field.
521
522
EXAMPLE::
523
524
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
525
sage: SmoothCharacterGroupGeneric(3, QQ).ideal(3)
526
Traceback (most recent call last):
527
...
528
NotImplementedError: <abstract method ideal at ...>
529
"""
530
pass
531
532
@abstract_method
533
def unit_gens(self, level):
534
r"""
535
A list of generators `x_1, \dots, x_d` of the abelian group `F^\times /
536
(1 + \mathfrak{p}^c)^\times`, where `c` is the given level, satisfying
537
no relations other than `x_i^{n_i} = 1` for each `i` (where the
538
integers `n_i` are returned by :meth:`exponents`). We adopt the
539
convention that the final generator `x_d` is a uniformiser (and `n_d =
540
0`).
541
542
EXAMPLE::
543
544
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
545
sage: SmoothCharacterGroupGeneric(3, QQ).unit_gens(3)
546
Traceback (most recent call last):
547
...
548
NotImplementedError: <abstract method unit_gens at ...>
549
"""
550
pass
551
552
@abstract_method
553
def exponents(self, level):
554
r"""
555
The orders `n_1, \dots, n_d` of the generators `x_i` of `F^\times / (1
556
+ \mathfrak{p}^c)^\times` returned by :meth:`unit_gens`.
557
558
EXAMPLE::
559
560
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
561
sage: SmoothCharacterGroupGeneric(3, QQ).exponents(3)
562
Traceback (most recent call last):
563
...
564
NotImplementedError: <abstract method exponents at ...>
565
"""
566
pass
567
568
@abstract_method
569
def subgroup_gens(self, level):
570
r"""
571
A set of elements of `(\mathcal{O}_F / \mathfrak{p}^c)^\times`
572
generating the kernel of the reduction map to `(\mathcal{O}_F /
573
\mathfrak{p}^{c-1})^\times`.
574
575
EXAMPLE::
576
577
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
578
sage: SmoothCharacterGroupGeneric(3, QQ).subgroup_gens(3)
579
Traceback (most recent call last):
580
...
581
NotImplementedError: <abstract method subgroup_gens at ...>
582
"""
583
pass
584
585
@abstract_method
586
def discrete_log(self, level):
587
r"""
588
Given an element `x \in F^\times` (lying in the number field `K` of
589
which `F` is a completion, see module docstring), express the class of
590
`x` in terms of the generators of `F^\times / (1 +
591
\mathfrak{p}^c)^\times` returned by :meth:`unit_gens`.
592
593
This should be overridden by all derived classes. The method should
594
first attempt to canonically coerce `x` into ``self.number_field()``,
595
and check that the result is not zero.
596
597
EXAMPLE::
598
599
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupGeneric
600
sage: SmoothCharacterGroupGeneric(3, QQ).discrete_log(3)
601
Traceback (most recent call last):
602
...
603
NotImplementedError: <abstract method discrete_log at ...>
604
"""
605
pass
606
607
def character(self, level, values_on_gens):
608
r"""
609
Return the unique character of the given level whose values on the
610
generators returned by ``self.unit_gens(level)`` are
611
``values_on_gens``.
612
613
INPUT:
614
615
- ``level`` (integer) an integer `\ge 0`
616
- ``values_on_gens`` (sequence) a sequence of elements of length equal
617
to the length of ``self.unit_gens(level)``. The values should be
618
convertible (that is, possibly noncanonically) into the base ring of self; they
619
should all be units, and all but the last must be roots of unity (of
620
the orders given by ``self.exponents(level)``.
621
622
.. note::
623
624
The character returned may have level less than ``level`` in general.
625
626
EXAMPLES::
627
628
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
629
sage: K.<z> = CyclotomicField(42)
630
sage: G = SmoothCharacterGroupQp(7, K)
631
sage: G.character(2, [z^6, 8])
632
Character of Q_7*, of level 2, mapping 3 |--> z^6, 7 |--> 8
633
sage: G.character(2, [z^7, 8])
634
Character of Q_7*, of level 1, mapping 3 |--> z^7, 7 |--> 8
635
636
Non-examples::
637
638
sage: G.character(1, [z, 1])
639
Traceback (most recent call last):
640
...
641
ValueError: value on generator 3 (=z) should be a root of unity of order 6
642
sage: G.character(1, [1, 0])
643
Traceback (most recent call last):
644
...
645
ValueError: value on uniformiser 7 (=0) should be a unit
646
647
An example with a funky coefficient ring::
648
649
sage: G = SmoothCharacterGroupQp(7, Zmod(9))
650
sage: G.character(1, [2, 2])
651
Character of Q_7*, of level 1, mapping 3 |--> 2, 7 |--> 2
652
sage: G.character(1, [2, 3])
653
Traceback (most recent call last):
654
...
655
ValueError: value on uniformiser 7 (=3) should be a unit
656
657
TESTS::
658
659
sage: G.character(1, [2])
660
Traceback (most recent call last):
661
...
662
AssertionError: 2 images must be given
663
"""
664
S = Sequence(values_on_gens, universe=self.base_ring(), immutable=True)
665
assert len(S) == len(self.unit_gens(level)), "{0} images must be given".format(len(self.unit_gens(level)))
666
n = self.exponents(level)
667
for i in xrange(len(S)):
668
if n[i] != 0 and not S[i]**n[i] == 1:
669
raise ValueError( "value on generator %s (=%s) should be a root of unity of order %s" % (self.unit_gens(level)[i], S[i], n[i]) )
670
elif n[i] == 0 and not S[i].is_unit():
671
raise ValueError( "value on uniformiser %s (=%s) should be a unit" % (self.unit_gens(level)[i], S[i]) )
672
return self.element_class(self, level, S)
673
674
def _an_element_(self):
675
r"""
676
Return an element of this group. Required by the coercion machinery.
677
678
EXAMPLE::
679
680
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
681
sage: K.<z> = CyclotomicField(42)
682
sage: G = SmoothCharacterGroupQp(7, K)
683
sage: G.an_element() # indirect doctest
684
Character of Q_7*, of level 0, mapping 7 |--> z
685
"""
686
return self.character(0, [self.base_ring().an_element()])
687
688
689
690
def _test_unitgens(self, **options):
691
r"""
692
Test that the generators returned by ``unit_gens`` are consistent with
693
the exponents returned by ``exponents``.
694
695
EXAMPLE::
696
697
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
698
sage: SmoothCharacterGroupUnramifiedQuadratic(2, Zmod(8))._test_unitgens()
699
"""
700
T = self._tester(**options)
701
for c in xrange(6):
702
gens = self.unit_gens(c)
703
exps = self.exponents(c)
704
T.assert_(exps[-1] == 0)
705
T.assert_(all([u != 0 for u in exps[:-1]]))
706
T.assert_(all([u.parent() is self.number_field() for u in gens]))
707
708
I = self.ideal(c)
709
for i in xrange(len(exps[:-1])):
710
g = gens[i]
711
for m in xrange(1, exps[i]):
712
if (g - 1 in I):
713
T.fail("For generator g=%s, g^%s = %s = 1 mod I, but order should be %s" % (gens[i], m, g, exps[i]))
714
g = g * gens[i]
715
# reduce g mod I
716
if hasattr(I, "small_residue"):
717
g = I.small_residue(g)
718
else: # I is an ideal of ZZ
719
g = g % (I.gen())
720
if not (g - 1 in I):
721
T.fail("For generator g=%s, g^%s = %s, which is not 1 mod I" % (gens[i], exps[i], g))
722
I = self.prime() if self.number_field() == QQ else self.ideal(1)
723
T.assert_(gens[-1].valuation(I) == 1)
724
725
# This implicitly tests that the gens really are gens!
726
_ = self.discrete_log(c, -1)
727
728
def _test_subgroupgens(self, **options):
729
r"""
730
Test that the values returned by :meth:`~subgroup_gens` are valid.
731
732
EXAMPLE::
733
734
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
735
sage: SmoothCharacterGroupQp(2, CC)._test_subgroupgens()
736
"""
737
T = self._tester(**options)
738
for c in xrange(1, 6):
739
sgs = self.subgroup_gens(c)
740
I2 = self.ideal(c-1)
741
T.assert_(all([x-1 in I2 for x in sgs]), "Kernel gens at level %s not in kernel!" % c)
742
743
# now find the exponent of the kernel
744
745
n1 = prod(self.exponents(c)[:-1])
746
n2 = prod(self.exponents(c-1)[:-1])
747
n = n1 // n2
748
# if c > 1, n will be a prime here, so that logs below gets calculated correctly
749
750
logs = []
751
for idx in xmrange(len(sgs)*[n]):
752
y = prod( map(operator.pow, sgs, idx) )
753
L = tuple(self.discrete_log(c, y))
754
if L not in logs:
755
logs.append(L)
756
T.assert_(n2 * len(logs) == n1, "Kernel gens at level %s don't generate everything!" % c)
757
758
def compose_with_norm(self, chi):
759
r"""
760
Calculate the character of `K^\times` given by `\chi \circ \mathrm{Norm}_{K/\QQ_p}`.
761
Here `K` should be a quadratic extension and `\chi` a character of `\QQ_p^\times`.
762
763
EXAMPLE:
764
765
When `K` is the unramified quadratic extension, the level of the new character is the same as the old::
766
767
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp, SmoothCharacterGroupRamifiedQuadratic, SmoothCharacterGroupUnramifiedQuadratic
768
sage: K.<w> = CyclotomicField(6)
769
sage: G = SmoothCharacterGroupQp(3, K)
770
sage: chi = G.character(2, [w, 5])
771
sage: H = SmoothCharacterGroupUnramifiedQuadratic(3, K)
772
sage: H.compose_with_norm(chi)
773
Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), of level 2, mapping -2*s |--> -1, 4 |--> -w, 3*s + 1 |--> w - 1, 3 |--> 25
774
775
In ramified cases, the level of the new character may be larger:
776
777
.. link
778
779
::
780
781
sage: H = SmoothCharacterGroupRamifiedQuadratic(3, 0, K)
782
sage: H.compose_with_norm(chi)
783
Character of ramified extension Q_3(s)* (s^2 - 3 = 0), of level 3, mapping 2 |--> w - 1, s + 1 |--> -w, s |--> -5
784
785
On the other hand, since norm is not surjective, the result can even be trivial:
786
787
.. link
788
789
::
790
791
sage: chi = G.character(1, [-1, -1]); chi
792
Character of Q_3*, of level 1, mapping 2 |--> -1, 3 |--> -1
793
sage: H.compose_with_norm(chi)
794
Character of ramified extension Q_3(s)* (s^2 - 3 = 0), of level 0, mapping s |--> 1
795
"""
796
if chi.parent().number_field() != QQ: raise ValueError
797
if self.number_field().absolute_degree() != 2: raise ValueError
798
n = chi.level()
799
P = chi.parent().prime() ** n
800
m = self.number_field()(P).valuation(self.ideal(1))
801
return self.character(m, [chi(x.norm(QQ)) for x in self.unit_gens(m)])
802
803
class SmoothCharacterGroupQp(SmoothCharacterGroupGeneric):
804
r"""
805
The group of smooth characters of `\QQ_p^\times`, with values in some fixed
806
base ring.
807
808
EXAMPLES::
809
810
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
811
sage: G = SmoothCharacterGroupQp(7, QQ); G
812
Group of smooth characters of Q_7* with values in Rational Field
813
sage: TestSuite(G).run()
814
sage: G == loads(dumps(G))
815
True
816
"""
817
def unit_gens(self, level):
818
r"""
819
Return a set of generators `x_1, \dots, x_d` for `\QQ_p^\times / (1 +
820
p^c \ZZ_p)^\times`. These must be independent in the sense that there
821
are no relations between them other than relations of the form
822
`x_i^{n_i} = 1`. They need not, however, be in Smith normal form.
823
824
EXAMPLE::
825
826
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
827
sage: SmoothCharacterGroupQp(7, QQ).unit_gens(3)
828
[3, 7]
829
sage: SmoothCharacterGroupQp(2, QQ).unit_gens(4)
830
[15, 5, 2]
831
"""
832
if level == 0:
833
return [QQ(self.prime())]
834
else:
835
return [QQ(x) for x in Zmod(self.prime()**level).unit_gens()] + [QQ(self.prime())]
836
837
def exponents(self, level):
838
r"""
839
Return the exponents of the generators returned by :meth:`unit_gens`.
840
841
EXAMPLE::
842
843
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
844
sage: SmoothCharacterGroupQp(7, QQ).exponents(3)
845
[294, 0]
846
sage: SmoothCharacterGroupQp(2, QQ).exponents(4)
847
[2, 4, 0]
848
"""
849
if level == 0: return [0]
850
return [x.multiplicative_order() for x in Zmod(self.prime()**level).unit_gens()] + [0]
851
852
def change_ring(self, ring):
853
r"""
854
Return the group of characters of the same field but with values in a
855
different ring. This need not have anything to do with the original
856
base ring, and in particular there won't generally be a coercion map
857
from self to the new group -- use
858
:meth:`~SmoothCharacterGroupGeneric.base_extend` if you want this.
859
860
EXAMPLE::
861
862
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
863
sage: SmoothCharacterGroupQp(7, Zmod(3)).change_ring(CC)
864
Group of smooth characters of Q_7* with values in Complex Field with 53 bits of precision
865
"""
866
return SmoothCharacterGroupQp(self.prime(), ring)
867
868
def number_field(self):
869
r"""
870
Return the number field used for calculations (a dense subfield of the
871
local field of which this is the character group). In this case, this
872
is always the rational field.
873
874
EXAMPLE::
875
876
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
877
sage: SmoothCharacterGroupQp(7, Zmod(3)).number_field()
878
Rational Field
879
"""
880
return QQ
881
882
def ideal(self, level):
883
r"""
884
Return the ``level``-th power of the maximal ideal. Since we
885
approximate by using rational arithmetic, what is actually returned is
886
an ideal of `\ZZ`.
887
888
EXAMPLE::
889
890
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
891
sage: SmoothCharacterGroupQp(7, Zmod(3)).ideal(2)
892
Principal ideal (49) of Integer Ring
893
"""
894
return ZZ.ideal(self.prime() ** level)
895
896
def _field_name(self):
897
r"""
898
Return a string representation of the field unit group of which this is
899
the character group.
900
901
EXAMPLE::
902
903
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
904
sage: SmoothCharacterGroupQp(7, Zmod(3))._field_name()
905
'Q_7*'
906
"""
907
return "Q_%s*" % self.prime()
908
909
def discrete_log(self, level, x):
910
r"""
911
Express the class of `x` in `\QQ_p^\times / (1 + p^c)^\times` in terms
912
of the generators returned by :meth:`unit_gens`.
913
914
EXAMPLE::
915
916
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
917
sage: G = SmoothCharacterGroupQp(7, QQ)
918
sage: G.discrete_log(0, 14)
919
[1]
920
sage: G.discrete_log(1, 14)
921
[2, 1]
922
sage: G.discrete_log(5, 14)
923
[9308, 1]
924
"""
925
x = self.number_field().coerce(x)
926
if x == 0: raise ValueError( "cannot evaluate at zero" )
927
s = x.valuation(self.prime())
928
return Zmod(self.prime()**level)(x / self.prime()**s).generalised_log() + [s]
929
930
def subgroup_gens(self, level):
931
r"""
932
Return a list of generators for the kernel of the map `(\ZZ_p / p^c)^\times
933
\to (\ZZ_p / p^{c-1})^\times`.
934
935
INPUT:
936
937
- ``c`` (integer) an integer `\ge 1`
938
939
EXAMPLES::
940
941
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp
942
sage: G = SmoothCharacterGroupQp(7, QQ)
943
sage: G.subgroup_gens(1)
944
[3]
945
sage: G.subgroup_gens(2)
946
[8]
947
948
sage: G = SmoothCharacterGroupQp(2, QQ)
949
sage: G.subgroup_gens(1)
950
[]
951
sage: G.subgroup_gens(2)
952
[3]
953
sage: G.subgroup_gens(3)
954
[5]
955
"""
956
if level == 0:
957
raise ValueError
958
elif level == 1:
959
return self.unit_gens(level)[:-1]
960
else:
961
return [1 + self.prime()**(level - 1)]
962
963
class SmoothCharacterGroupUnramifiedQuadratic(SmoothCharacterGroupGeneric):
964
r"""
965
The group of smooth characters of `\QQ_{p^2}^\times`, where `\QQ_{p^2}` is
966
the unique unramified quadratic extension of `\QQ_p`. We represent
967
`\QQ_{p^2}^\times` internally as the completion at the prime above `p` of a
968
quadratic number field, defined by (the obvious lift to `\ZZ` of) the
969
Conway polynomial modulo `p` of degree 2.
970
971
EXAMPLE::
972
973
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
974
sage: G = SmoothCharacterGroupUnramifiedQuadratic(3, QQ); G
975
Group of smooth characters of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0) with values in Rational Field
976
sage: G.unit_gens(3)
977
[-11*s, 4, 3*s + 1, 3]
978
sage: TestSuite(G).run()
979
sage: TestSuite(SmoothCharacterGroupUnramifiedQuadratic(2, QQ)).run()
980
"""
981
982
def __init__(self, prime, base_ring, names='s'):
983
r"""
984
Standard initialisation function.
985
986
EXAMPLE::
987
988
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
989
sage: G = SmoothCharacterGroupUnramifiedQuadratic(3, QQ, 'foo'); G
990
Group of smooth characters of unramified extension Q_3(foo)* (foo^2 + 2*foo + 2 = 0) with values in Rational Field
991
sage: G == loads(dumps(G))
992
True
993
"""
994
SmoothCharacterGroupGeneric.__init__(self, prime, base_ring)
995
self._name = names
996
997
def change_ring(self, ring):
998
r"""
999
Return the character group of the same field, but with values in a
1000
different coefficient ring. This need not have anything to do with the
1001
original base ring, and in particular there won't generally be a
1002
coercion map from self to the new group -- use
1003
:meth:`~SmoothCharacterGroupGeneric.base_extend` if you want this.
1004
1005
EXAMPLE::
1006
1007
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
1008
sage: SmoothCharacterGroupUnramifiedQuadratic(7, Zmod(3), names='foo').change_ring(CC)
1009
Group of smooth characters of unramified extension Q_7(foo)* (foo^2 + 6*foo + 3 = 0) with values in Complex Field with 53 bits of precision
1010
"""
1011
# We want to make sure that both G and the base-extended version have
1012
# the same values in the cache.
1013
from copy import copy
1014
G = SmoothCharacterGroupUnramifiedQuadratic(self.prime(), ring, self._name)
1015
try:
1016
G._cache___ideal = copy(self._cache___ideal)
1017
except AttributeError:
1018
pass
1019
return G
1020
1021
def _field_name(self):
1022
r"""
1023
A string representing the unit group of which this is the character group.
1024
1025
EXAMPLE::
1026
1027
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
1028
sage: SmoothCharacterGroupUnramifiedQuadratic(7, Zmod(3), 'a')._field_name()
1029
'unramified extension Q_7(a)* (a^2 + 6*a + 3 = 0)'
1030
"""
1031
return "unramified extension Q_%s(%s)* (%s = 0)" % (self.prime(), self._name, self.number_field().polynomial().change_variable_name(self._name))
1032
1033
def number_field(self):
1034
r"""
1035
Return a number field of which this is the completion at `p`, defined by a polynomial
1036
whose discriminant is not divisible by `p`.
1037
1038
EXAMPLES::
1039
1040
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
1041
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ, 'a').number_field()
1042
Number Field in a with defining polynomial x^2 + 6*x + 3
1043
sage: SmoothCharacterGroupUnramifiedQuadratic(5, QQ, 'b').number_field()
1044
Number Field in b with defining polynomial x^2 + 4*x + 2
1045
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ, 'c').number_field()
1046
Number Field in c with defining polynomial x^2 + x + 1
1047
"""
1048
from sage.rings.all import conway_polynomial, PolynomialRing
1049
fbar = conway_polynomial(self.prime(), 2)
1050
f = PolynomialRing(QQ,'x')([a.lift() for a in fbar])
1051
return NumberField(f, self._name)
1052
1053
@cached_method
1054
def ideal(self, c):
1055
r"""
1056
Return the ideal `p^c` of ``self.number_field()``. The result is
1057
cached, since we use the methods
1058
:meth:`~sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal.idealstar` and
1059
:meth:`~sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal.ideallog` which
1060
cache a Pari ``bid`` structure.
1061
1062
EXAMPLES::
1063
1064
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
1065
sage: G = SmoothCharacterGroupUnramifiedQuadratic(7, QQ, 'a'); I = G.ideal(3); I
1066
Fractional ideal (343)
1067
sage: I is G.ideal(3)
1068
True
1069
"""
1070
return self.number_field().ideal(self.prime()**c)
1071
1072
@cached_method
1073
def unit_gens(self, c):
1074
r"""
1075
A list of generators `x_1, \dots, x_d` of the abelian group `F^\times /
1076
(1 + \mathfrak{p}^c)^\times`, where `c` is the given level, satisfying
1077
no relations other than `x_i^{n_i} = 1` for each `i` (where the
1078
integers `n_i` are returned by :meth:`exponents`). We adopt the
1079
convention that the final generator `x_d` is a uniformiser (and `n_d =
1080
0`).
1081
1082
ALGORITHM: Use Teichmueller lifts.
1083
1084
EXAMPLE::
1085
1086
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
1087
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).unit_gens(0)
1088
[7]
1089
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).unit_gens(1)
1090
[s, 7]
1091
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).unit_gens(2)
1092
[22*s, 8, 7*s + 1, 7]
1093
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).unit_gens(3)
1094
[169*s + 49, 8, 7*s + 1, 7]
1095
1096
In the 2-adic case there can be more than 4 generators::
1097
1098
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).unit_gens(0)
1099
[2]
1100
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).unit_gens(1)
1101
[s, 2]
1102
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).unit_gens(2)
1103
[s, 2*s + 1, -1, 2]
1104
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).unit_gens(3)
1105
[s, 2*s + 1, 4*s + 1, -1, 2]
1106
"""
1107
# special cases
1108
1109
p = self.prime()
1110
K = self.number_field()
1111
a = K.gen()
1112
1113
if c == 0:
1114
return [K(p)]
1115
elif c == 1:
1116
return [a, K(p)]
1117
elif p == 2:
1118
if c == 2:
1119
return [a, 1 + 2*a, K(-1), K(2)]
1120
else:
1121
return [a, 1 + 2*a, 1 + 4*a, K(-1), K(2)]
1122
1123
# general case
1124
1125
b = a
1126
I = self.ideal(c)
1127
1128
while b**(p**2 - 1) - 1 not in I:
1129
b = I.reduce(b**(self.prime()**2))
1130
return [b, K(1 + p), 1 + a*p, K(p)]
1131
1132
def exponents(self, c):
1133
r"""
1134
The orders `n_1, \dots, n_d` of the generators `x_i` of `F^\times / (1
1135
+ \mathfrak{p}^c)^\times` returned by :meth:`unit_gens`.
1136
1137
EXAMPLE::
1138
1139
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
1140
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).exponents(2)
1141
[48, 7, 7, 0]
1142
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).exponents(3)
1143
[3, 4, 2, 2, 0]
1144
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).exponents(2)
1145
[3, 2, 2, 0]
1146
"""
1147
p = self.prime()
1148
if c == 0: return [0]
1149
elif c == 1: return [p**2 - 1, 0]
1150
elif p == 2 and c >= 3:
1151
return [p**2 - 1, p**(c-1), p**(c-2), 2, 0]
1152
else: return [p**2 - 1, p**(c-1), p**(c-1),0]
1153
1154
def subgroup_gens(self, level):
1155
r"""
1156
A set of elements of `(\mathcal{O}_F / \mathfrak{p}^c)^\times`
1157
generating the kernel of the reduction map to `(\mathcal{O}_F /
1158
\mathfrak{p}^{c-1})^\times`.
1159
1160
EXAMPLE::
1161
1162
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
1163
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).subgroup_gens(1)
1164
[s]
1165
sage: SmoothCharacterGroupUnramifiedQuadratic(7, QQ).subgroup_gens(2)
1166
[8, 7*s + 1]
1167
sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).subgroup_gens(2)
1168
[3, 2*s + 1]
1169
"""
1170
if level == 0:
1171
raise ValueError
1172
elif level == 1:
1173
return self.unit_gens(level)[:-1]
1174
else:
1175
return [1 + self.prime()**(level - 1), 1 + self.prime()**(level - 1) * self.number_field().gen()]
1176
1177
def quotient_gen(self, level):
1178
r"""
1179
Find an element generating the quotient
1180
1181
.. math::
1182
1183
\mathcal{O}_F^\times / \ZZ_p^\times \cdot (1 + p^c \mathcal{O}_F),
1184
1185
where `c` is the given level.
1186
1187
EXAMPLE::
1188
1189
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
1190
sage: G = SmoothCharacterGroupUnramifiedQuadratic(7,QQ)
1191
sage: G.quotient_gen(1)
1192
s
1193
sage: G.quotient_gen(2)
1194
-20*s - 21
1195
sage: G.quotient_gen(3)
1196
-69*s - 70
1197
1198
For `p = 2` an error will be raised for level `\ge 3`, as the quotient is not cyclic::
1199
1200
sage: G = SmoothCharacterGroupUnramifiedQuadratic(2,QQ)
1201
sage: G.quotient_gen(1)
1202
s
1203
sage: G.quotient_gen(2)
1204
-s + 2
1205
sage: G.quotient_gen(3)
1206
Traceback (most recent call last):
1207
...
1208
ValueError: Quotient group not cyclic
1209
"""
1210
if level == 0:
1211
raise ValueError( "Quotient group is trivial" )
1212
elif self.prime() == 2 and level >= 3:
1213
raise ValueError( "Quotient group not cyclic" )
1214
elif level == 1:
1215
return self.unit_gens(level)[0]
1216
else:
1217
return self.ideal(level).reduce(self.unit_gens(level)[0] * (1 + self.prime() * self.number_field().gen()))
1218
1219
def extend_character(self, level, chi, x, check=True):
1220
r"""
1221
Return the unique character of `F^\times` which coincides with `\chi`
1222
on `\QQ_p^\times` and maps the generator `\alpha` returned by
1223
:meth:`quotient_gen` to `x`.
1224
1225
INPUT:
1226
1227
- ``chi``: a smooth character of `\QQ_p`, where `p` is the residue
1228
characteristic of `F`, with values in the base ring of self (or some
1229
other ring coercible to it)
1230
- ``level``: the level of the new character (which should be at least
1231
the level of ``chi``)
1232
- ``x``: an element of the base ring of self (or some other ring
1233
coercible to it).
1234
1235
A ``ValueError`` will be raised if `x^t \ne \chi(\alpha^t)`, where `t`
1236
is the smallest integer such that `\alpha^t` is congruent modulo
1237
`p^{\rm level}` to an element of `\QQ_p`.
1238
1239
EXAMPLES:
1240
1241
We extend an unramified character of `\QQ_3^\times` to the unramified
1242
quadratic extension in various ways.
1243
1244
::
1245
1246
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupQp, SmoothCharacterGroupUnramifiedQuadratic
1247
sage: chi = SmoothCharacterGroupQp(5, QQ).character(0, [7]); chi
1248
Character of Q_5*, of level 0, mapping 5 |--> 7
1249
sage: G = SmoothCharacterGroupUnramifiedQuadratic(5, QQ)
1250
sage: G.extend_character(1, chi, -1)
1251
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -1, 5 |--> 7
1252
sage: G.extend_character(2, chi, -1)
1253
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -1, 5 |--> 7
1254
sage: G.extend_character(3, chi, 1)
1255
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 0, mapping 5 |--> 7
1256
sage: K.<z> = CyclotomicField(6); G.base_extend(K).extend_character(1, chi, z)
1257
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> z, 5 |--> 7
1258
1259
We extend the nontrivial quadratic character::
1260
1261
sage: chi = SmoothCharacterGroupQp(5, QQ).character(1, [-1, 7])
1262
sage: K.<z> = CyclotomicField(24); G.base_extend(K).extend_character(1, chi, z^6)
1263
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> z^6, 5 |--> 7
1264
1265
Extensions of higher level::
1266
1267
sage: K.<z> = CyclotomicField(20); rho = G.base_extend(K).extend_character(2, chi, z); rho
1268
Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 2, mapping 11*s - 10 |--> z^5, 6 |--> 1, 5*s + 1 |--> -z^6, 5 |--> 7
1269
sage: rho(3)
1270
-1
1271
1272
Examples where it doesn't work::
1273
1274
sage: G.extend_character(1, chi, 1)
1275
Traceback (most recent call last):
1276
...
1277
ValueError: Value at s must satisfy x^6 = chi(2) = -1, but it does not
1278
1279
sage: G = SmoothCharacterGroupQp(2, QQ); H = SmoothCharacterGroupUnramifiedQuadratic(2, QQ)
1280
sage: chi = G.character(3, [1, -1, 7])
1281
sage: H.extend_character(2, chi, -1)
1282
Traceback (most recent call last):
1283
...
1284
ValueError: Level of extended character cannot be smaller than level of character of Qp
1285
"""
1286
chi = chi.base_extend(self.base_ring())
1287
if chi.level() > level:
1288
raise ValueError, "Level of extended character cannot be smaller than level of character of Qp"
1289
1290
# check it makes sense
1291
e = (self.prime() + 1) * (self.prime()**(level - 1))
1292
v = self.ideal(level).reduce(self.quotient_gen(level) ** e)
1293
1294
v = QQ(v)
1295
if x**e != chi(v):
1296
raise ValueError( "Value at %s must satisfy x^%s = chi(%s) = %s, but it does not" % (self.quotient_gen(level), e, v, chi(v)) )
1297
1298
# now do the calculation
1299
values_on_standard_gens = []
1300
other_gens = [self.quotient_gen(level)] + [ZZ(z) for z in Zmod(self.prime()**level).unit_gens()]
1301
values_on_other_gens = [x] + [chi(u) for u in other_gens[1:]]
1302
for s in self.unit_gens(level)[:-1]:
1303
t = self.ideal(level).ideallog(s, other_gens)
1304
values_on_standard_gens.append( prod([values_on_other_gens[i] ** t[i] for i in xrange(len(t))]) )
1305
values_on_standard_gens.append(chi(self.prime()))
1306
chiE = self.character(level, values_on_standard_gens)
1307
1308
# check it makes sense (optional but on by default)
1309
if check:
1310
assert chiE(self.quotient_gen(level)) == x
1311
assert chiE.restrict_to_Qp() == chi
1312
1313
return chiE
1314
1315
def discrete_log(self, level, x):
1316
r"""
1317
Express the class of `x` in `F^\times / (1 + \mathfrak{p}^c)^\times` in
1318
terms of the generators returned by ``self.unit_gens(level)``.
1319
1320
EXAMPLE::
1321
1322
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupUnramifiedQuadratic
1323
sage: G = SmoothCharacterGroupUnramifiedQuadratic(2, QQ)
1324
sage: G.discrete_log(0, 12)
1325
[2]
1326
sage: G.discrete_log(1, 12)
1327
[0, 2]
1328
sage: v = G.discrete_log(5, 12); v
1329
[0, 2, 0, 1, 2]
1330
sage: g = G.unit_gens(5); prod([g[i]**v[i] for i in [0..4]])/12 - 1 in G.ideal(5)
1331
True
1332
sage: G.discrete_log(3,G.number_field()([1,1]))
1333
[2, 0, 0, 1, 0]
1334
sage: H = SmoothCharacterGroupUnramifiedQuadratic(5, QQ)
1335
sage: x = H.number_field()([1,1]); x
1336
s + 1
1337
sage: v = H.discrete_log(5, x); v
1338
[22, 263, 379, 0]
1339
sage: h = H.unit_gens(5); prod([h[i]**v[i] for i in [0..3]])/x - 1 in H.ideal(5)
1340
True
1341
"""
1342
x = self.number_field().coerce(x)
1343
if x == 0: raise ValueError( "cannot evaluate at zero" )
1344
n1 = x.valuation(self.number_field().ideal(self.prime()))
1345
x1 = x / self.prime() ** n1
1346
if level == 0:
1347
return [n1]
1348
else:
1349
return self.ideal(level).ideallog(x1, self.unit_gens(level)[:-1]) + [n1]
1350
1351
1352
class SmoothCharacterGroupRamifiedQuadratic(SmoothCharacterGroupGeneric):
1353
r"""
1354
The group of smooth characters of `K^\times`, where `K` is a ramified
1355
quadratic extension of `\QQ_p`, and `p \ne 2`.
1356
"""
1357
def __init__(self, prime, flag, base_ring, names='s'):
1358
r"""
1359
Standard initialisation function.
1360
1361
INPUT:
1362
1363
- ``prime`` -- a prime integer
1364
- ``flag`` -- either 0 or 1
1365
- ``base_ring`` -- a ring
1366
- ``names`` -- a variable name (default ``s``)
1367
1368
If ``flag`` is 0, return the group of characters of the multiplicative
1369
group of the field `\QQ_p(\sqrt{p})`. If ``flag`` is 1, use the
1370
extension `\QQ_p(\sqrt{dp})`, where `d` is `-1` (if `p = 3 \pmod 4`) or
1371
the smallest positive quadratic nonresidue mod `p` otherwise.
1372
1373
EXAMPLE::
1374
1375
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
1376
sage: G1 = SmoothCharacterGroupRamifiedQuadratic(3, 0, QQ); G1
1377
Group of smooth characters of ramified extension Q_3(s)* (s^2 - 3 = 0) with values in Rational Field
1378
sage: G2 = SmoothCharacterGroupRamifiedQuadratic(3, 1, QQ); G2
1379
Group of smooth characters of ramified extension Q_3(s)* (s^2 + 3 = 0) with values in Rational Field
1380
sage: G3 = SmoothCharacterGroupRamifiedQuadratic(5, 1, QQ); G3
1381
Group of smooth characters of ramified extension Q_5(s)* (s^2 - 10 = 0) with values in Rational Field
1382
1383
TESTS:
1384
1385
.. link
1386
1387
::
1388
1389
sage: TestSuite(G1).run()
1390
sage: TestSuite(G2).run()
1391
sage: TestSuite(G3).run()
1392
"""
1393
if prime == 2: raise NotImplementedError( "Wildly ramified extensions not supported" )
1394
SmoothCharacterGroupGeneric.__init__(self, prime, base_ring)
1395
self._name = names
1396
if flag not in [0, 1]:
1397
raise ValueError( "Flag must be 0 (for Qp(sqrt(p)) ) or 1 (for the other ramified extension)" )
1398
self._flag = flag
1399
if flag == 0:
1400
self._unif_sqr = self.prime()
1401
else:
1402
if self.prime() % 4 == 3:
1403
self._unif_sqr = -self.prime()
1404
else:
1405
self._unif_sqr = ZZ(Zmod(self.prime()).quadratic_nonresidue()) * self.prime()
1406
1407
def change_ring(self, ring):
1408
r"""
1409
Return the character group of the same field, but with values in a
1410
different coefficient ring. This need not have anything to do with the
1411
original base ring, and in particular there won't generally be a
1412
coercion map from self to the new group -- use
1413
:meth:`~SmoothCharacterGroupGeneric.base_extend` if you want this.
1414
1415
EXAMPLE::
1416
1417
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
1418
sage: SmoothCharacterGroupRamifiedQuadratic(7, 1, Zmod(3), names='foo').change_ring(CC)
1419
Group of smooth characters of ramified extension Q_7(foo)* (foo^2 + 7 = 0) with values in Complex Field with 53 bits of precision
1420
"""
1421
return SmoothCharacterGroupRamifiedQuadratic(self.prime(), self._flag, ring, self._name)
1422
1423
def _field_name(self):
1424
r"""
1425
A string representing the unit group of which this is the character group.
1426
1427
EXAMPLE::
1428
1429
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
1430
sage: SmoothCharacterGroupRamifiedQuadratic(7, 0, Zmod(3), 'a')._field_name()
1431
'ramified extension Q_7(a)* (a^2 - 7 = 0)'
1432
"""
1433
return "ramified extension Q_%s(%s)* (%s = 0)" % (self.prime(), self._name, self.number_field().polynomial().change_variable_name(self._name))
1434
1435
def number_field(self):
1436
r"""
1437
Return a number field of which this is the completion at `p`.
1438
1439
EXAMPLES::
1440
1441
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
1442
sage: SmoothCharacterGroupRamifiedQuadratic(7, 0, QQ, 'a').number_field()
1443
Number Field in a with defining polynomial x^2 - 7
1444
sage: SmoothCharacterGroupRamifiedQuadratic(5, 1, QQ, 'b').number_field()
1445
Number Field in b with defining polynomial x^2 - 10
1446
sage: SmoothCharacterGroupRamifiedQuadratic(7, 1, Zmod(6), 'c').number_field()
1447
Number Field in c with defining polynomial x^2 + 7
1448
"""
1449
from sage.rings.all import PolynomialRing
1450
R, x = PolynomialRing(QQ, 'x').objgen()
1451
f = x**2 - self._unif_sqr
1452
return NumberField(f, self._name)
1453
1454
@cached_method
1455
def ideal(self, c):
1456
r"""
1457
Return the ideal `p^c` of ``self.number_field()``. The result is
1458
cached, since we use the methods
1459
:meth:`~sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal.idealstar` and
1460
:meth:`~sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal.ideallog` which
1461
cache a Pari ``bid`` structure.
1462
1463
EXAMPLES::
1464
1465
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
1466
sage: G = SmoothCharacterGroupRamifiedQuadratic(5, 1, QQ, 'a'); I = G.ideal(3); I
1467
Fractional ideal (25, 5*a)
1468
sage: I is G.ideal(3)
1469
True
1470
"""
1471
return self.number_field().ideal([self.prime(), self.number_field().gen()])**c
1472
1473
def unit_gens(self, c):
1474
r"""
1475
A list of generators `x_1, \dots, x_d` of the abelian group `F^\times /
1476
(1 + \mathfrak{p}^c)^\times`, where `c` is the given level, satisfying
1477
no relations other than `x_i^{n_i} = 1` for each `i` (where the
1478
integers `n_i` are returned by :meth:`exponents`). We adopt the
1479
convention that the final generator `x_d` is a uniformiser.
1480
1481
EXAMPLE::
1482
1483
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
1484
sage: G = SmoothCharacterGroupRamifiedQuadratic(5, 0, QQ)
1485
sage: G.unit_gens(0)
1486
[s]
1487
sage: G.unit_gens(1)
1488
[2, s]
1489
sage: G.unit_gens(8)
1490
[2, s + 1, s]
1491
"""
1492
d = ceil(ZZ(c) / 2)
1493
p = self.prime()
1494
K,s = self.number_field().objgen()
1495
zpgens = [K(ZZ(x)) for x in Zmod(p**d).unit_gens()]
1496
if c == 0:
1497
return [s]
1498
if c == 1:
1499
return zpgens + [s]
1500
elif p > 3 or self._unif_sqr == 3 or c <= 3:
1501
return zpgens + [1 + s, s]
1502
else:
1503
# Awkward case: K = Q_3(sqrt(-3)). Here the exponential map doesn't
1504
# converge on 1 + P, and the quotient (O_K*) / (Zp*) isn't
1505
# topologically cyclic. I don't know an explicit set of good
1506
# generators here, so we let Pari do the work and put up with the
1507
# rather arbitrary (nondeterministic?) results.
1508
return list(self.ideal(c).idealstar(2).gens()) + [s]
1509
1510
def exponents(self, c):
1511
r"""
1512
Return the orders of the independent generators of the unit group
1513
returned by :meth:`~unit_gens`.
1514
1515
EXAMPLE::
1516
1517
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
1518
sage: G = SmoothCharacterGroupRamifiedQuadratic(5, 0, QQ)
1519
sage: G.exponents(0)
1520
[0]
1521
sage: G.exponents(1)
1522
[4, 0]
1523
sage: G.exponents(8)
1524
[500, 625, 0]
1525
"""
1526
c = ZZ(c)
1527
d = ceil(c / 2)
1528
p = self.prime()
1529
if c == 0:
1530
return [0]
1531
elif c == 1:
1532
return [p - 1, 0]
1533
elif p > 3 or self._unif_sqr == 3 or c <= 3:
1534
return [p**(d-1)*(p - 1), p**ceil((c - 1)/2), 0]
1535
else:
1536
# awkward case, see above
1537
return self.ideal(c).idealstar(2).invariants() + [0]
1538
1539
def subgroup_gens(self, level):
1540
r"""
1541
A set of elements of `(\mathcal{O}_F / \mathfrak{p}^c)^\times`
1542
generating the kernel of the reduction map to `(\mathcal{O}_F /
1543
\mathfrak{p}^{c-1})^\times`.
1544
1545
EXAMPLE::
1546
1547
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
1548
sage: G = SmoothCharacterGroupRamifiedQuadratic(3, 1, QQ)
1549
sage: G.subgroup_gens(2)
1550
[s + 1]
1551
"""
1552
if level == 0:
1553
raise ValueError
1554
elif level == 1:
1555
return self.unit_gens(level)[:-1]
1556
else:
1557
return [1 + self.number_field().gen()**(level - 1)]
1558
1559
def discrete_log(self, level, x):
1560
r"""
1561
Solve the discrete log problem in the unit group.
1562
1563
EXAMPLE::
1564
1565
sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
1566
sage: G = SmoothCharacterGroupRamifiedQuadratic(3, 1, QQ)
1567
sage: s = G.number_field().gen()
1568
sage: G.discrete_log(4, 3 + 2*s)
1569
[5, 2, 1, 1]
1570
sage: gs = G.unit_gens(4); gs[0]^5 * gs[1]^2 * gs[2] * gs[3] - (3 + 2*s) in G.ideal(4)
1571
True
1572
"""
1573
x = self.number_field().coerce(x)
1574
if x == 0: raise ValueError, "cannot evaluate at zero"
1575
n1 = x.valuation(self.ideal(1))
1576
x1 = x / self.number_field().gen()**n1
1577
if level == 0:
1578
return [n1]
1579
else:
1580
return self.ideal(level).ideallog(x1, self.unit_gens(level)[:-1]) + [n1]
1581
1582