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