Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/groups/abelian_gps/dual_abelian_group.py
8815 views
1
r"""
2
Dual groups of Finite Multiplicative Abelian Groups
3
4
The basic idea is very simple. Let G be an abelian group and `G^*` its
5
dual (i.e., the group of homomorphisms from G to `\CC^\times`). Let
6
`g_j`, `j=1,..,n`, denote generators of `G` - say `g_j` is of order
7
`m_j>1`. There are generators `X_j`, `j=1,..,n`, of `G^*` for which
8
`X_j(g_j)=\exp(2\pi i/m_j)` and `X_i(g_j)=1` if `i\not= j`. These are
9
used to construct `G^*`.
10
11
Sage supports multiplicative abelian groups on any prescribed finite
12
number `n > 0` of generators. Use
13
:func:`~sage.groups.abelian_gps.abelian_group.AbelianGroup` function
14
to create an abelian group, the
15
:meth:`~sage.groups.abelian_gps.abelian_group.AbelianGroup_class.dual_group`
16
method to create its dual, and then the :meth:`gen` and :meth:`gens`
17
methods to obtain the corresponding generators. You can print the
18
generators as arbitrary strings using the optional ``names`` argument
19
to the
20
:meth:`~sage.groups.abelian_gps.abelian_group.AbelianGroup_class.dual_group`
21
method.
22
23
EXAMPLES::
24
25
sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')
26
sage: (a, b, c, d, e) = F.gens()
27
28
sage: Fd = F.dual_group(names='ABCDE')
29
sage: Fd.base_ring()
30
Cyclotomic Field of order 2520 and degree 576
31
sage: A,B,C,D,E = Fd.gens()
32
sage: A(a)
33
-1
34
sage: A(b), A(c), A(d), A(e)
35
(1, 1, 1, 1)
36
37
sage: Fd = F.dual_group(names='ABCDE', base_ring=CC)
38
sage: A,B,C,D,E = Fd.gens()
39
sage: A(a) # abs tol 1e-8
40
-1.00000000000000 + 0.00000000000000*I
41
sage: A(b); A(c); A(d); A(e)
42
1.00000000000000
43
1.00000000000000
44
1.00000000000000
45
1.00000000000000
46
47
AUTHORS:
48
49
- David Joyner (2006-08) (based on abelian_groups)
50
51
- David Joyner (2006-10) modifications suggested by William Stein
52
53
- Volker Braun (2012-11) port to new Parent base. Use tuples for immutables.
54
Default to cyclotomic base ring.
55
"""
56
57
###########################################################################
58
# Copyright (C) 2006 William Stein <[email protected]>
59
# Copyright (C) 2006 David Joyner <[email protected]>
60
# Copyright (C) 2012 Volker Braun <[email protected]>
61
#
62
# Distributed under the terms of the GNU General Public License (GPL)
63
# http://www.gnu.org/licenses/
64
###########################################################################
65
66
from sage.rings.infinity import infinity
67
from sage.structure.unique_representation import UniqueRepresentation
68
from sage.groups.abelian_gps.dual_abelian_group_element import (
69
DualAbelianGroupElement, is_DualAbelianGroupElement )
70
from sage.misc.mrange import mrange
71
from sage.misc.cachefunc import cached_method
72
from sage.groups.group import AbelianGroup as AbelianGroupBase
73
74
75
def is_DualAbelianGroup(x):
76
"""
77
Return True if `x` is the dual group of an abelian group.
78
79
EXAMPLES::
80
81
sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroup
82
sage: F = AbelianGroup(5,[3,5,7,8,9], names=list("abcde"))
83
sage: Fd = F.dual_group()
84
sage: is_DualAbelianGroup(Fd)
85
True
86
sage: F = AbelianGroup(3,[1,2,3], names='a')
87
sage: Fd = F.dual_group()
88
sage: Fd.gens()
89
(1, X1, X2)
90
sage: F.gens()
91
(1, a1, a2)
92
"""
93
return isinstance(x, DualAbelianGroup_class)
94
95
96
class DualAbelianGroup_class(UniqueRepresentation, AbelianGroupBase):
97
"""
98
Dual of abelian group.
99
100
EXAMPLES::
101
102
sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde")
103
sage: F.dual_group()
104
Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
105
over Cyclotomic Field of order 2520 and degree 576
106
sage: F = AbelianGroup(4,[15,7,8,9], names="abcd")
107
sage: F.dual_group(base_ring=CC)
108
Dual of Abelian Group isomorphic to Z/15Z x Z/7Z x Z/8Z x Z/9Z
109
over Complex Field with 53 bits of precision
110
"""
111
Element = DualAbelianGroupElement
112
113
def __init__(self, G, names, base_ring):
114
"""
115
The Python constructor
116
117
EXAMPLES::
118
119
sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde")
120
sage: F.dual_group()
121
Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
122
over Cyclotomic Field of order 2520 and degree 576
123
"""
124
self._base_ring = base_ring
125
self._group = G
126
names = self.normalize_names(G.ngens(), names)
127
self._assign_names(names)
128
AbelianGroupBase.__init__(self) # TODO: category=CommutativeGroups()
129
130
def group(self):
131
"""
132
Return the group that ``self`` is the dual of.
133
134
EXAMPLES::
135
136
sage: F = AbelianGroup(3,[5,64,729], names=list("abc"))
137
sage: Fd = F.dual_group(base_ring=CC)
138
sage: Fd.group() is F
139
True
140
"""
141
return self._group
142
143
def base_ring(self):
144
"""
145
Return the scalars over which the group is dualized.
146
147
EXAMPLES::
148
149
sage: F = AbelianGroup(3,[5,64,729], names=list("abc"))
150
sage: Fd = F.dual_group(base_ring=CC)
151
sage: Fd.base_ring()
152
Complex Field with 53 bits of precision
153
"""
154
return self._base_ring
155
156
def __str__(self):
157
"""
158
Print method.
159
160
EXAMPLES::
161
162
sage: F = AbelianGroup(3,[5,64,729], names=list("abc"))
163
sage: Fd = F.dual_group(base_ring=CC)
164
sage: print Fd
165
DualAbelianGroup( AbelianGroup ( 3, (5, 64, 729) ) )
166
"""
167
s = "DualAbelianGroup( AbelianGroup ( %s, %s ) )"%(self.ngens(), self.gens_orders())
168
return s
169
170
def _repr_(self):
171
"""
172
Return a string representation.
173
174
EXAMPLES::
175
176
sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')
177
sage: Fd = F.dual_group(names='ABCDE', base_ring=CyclotomicField(2*5*7*8*9))
178
sage: Fd # indirect doctest
179
Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
180
over Cyclotomic Field of order 5040 and degree 1152
181
sage: Fd = F.dual_group(names='ABCDE', base_ring=CC)
182
sage: Fd
183
Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
184
over Complex Field with 53 bits of precision
185
"""
186
G = self.group()
187
eldv = G.gens_orders()
188
gp = ""
189
for x in eldv:
190
if x!=0:
191
gp = gp + "Z/%sZ x "%x
192
if x==0:
193
gp = gp + "Z x "
194
gp = gp[:-2].strip()
195
s = 'Dual of Abelian Group isomorphic to ' + gp + ' over ' + str(self.base_ring())
196
return s
197
198
def _latex_(self):
199
r"""
200
Return latex representation of this group.
201
202
EXAMPLES::
203
204
sage: F = AbelianGroup(3, [2]*3)
205
sage: Fd = F.dual_group()
206
sage: Fd._latex_()
207
'$\\mathrm{DualAbelianGroup}( AbelianGroup ( 3, (2, 2, 2) ) )$'
208
"""
209
s = "$\mathrm{DualAbelianGroup}( AbelianGroup ( %s, %s ) )$"%(self.ngens(), self.gens_orders())
210
return s
211
212
def random_element(self):
213
"""
214
Return a random element of this dual group.
215
216
EXAMPLES::
217
218
sage: G = AbelianGroup([2,3,9])
219
sage: Gd = G.dual_group(base_ring=CC)
220
sage: Gd.random_element()
221
X1^2
222
223
sage: N = 43^2-1
224
sage: G = AbelianGroup([N],names="a")
225
sage: Gd = G.dual_group(names="A", base_ring=CC)
226
sage: a, = G.gens()
227
sage: A, = Gd.gens()
228
sage: x = a^(N/4); y = a^(N/3); z = a^(N/14)
229
sage: X = A*Gd.random_element(); X
230
A^615
231
sage: len([a for a in [x,y,z] if abs(X(a)-1)>10^(-8)])
232
2
233
"""
234
from sage.misc.prandom import randint
235
result = self.one()
236
for g in self.gens():
237
order = g.order()
238
result *= g**(randint(0,order))
239
return result
240
241
def gen(self, i=0):
242
"""
243
The `i`-th generator of the abelian group.
244
245
EXAMPLES::
246
247
sage: F = AbelianGroup(3,[1,2,3],names='a')
248
sage: Fd = F.dual_group(names="A")
249
sage: Fd.0
250
1
251
sage: Fd.1
252
A1
253
sage: Fd.gens_orders()
254
(1, 2, 3)
255
"""
256
n = self.group().ngens()
257
if i < 0 or i >= n:
258
raise IndexError, "Argument i (= %s) must be between 0 and %s."%(i, n-1)
259
x = [0]*n
260
if self.gens_orders()[i] != 1:
261
x[i] = 1
262
return self.element_class(self, x)
263
264
def gens(self):
265
"""
266
Return the generators for the group.
267
268
OUTPUT:
269
270
A tuple of group elements generating the group.
271
272
EXAMPLES::
273
274
sage: F = AbelianGroup([7,11]).dual_group()
275
sage: F.gens()
276
(X0, X1)
277
"""
278
n = self.group().ngens()
279
return tuple(self.gen(i) for i in range(n))
280
281
def ngens(self):
282
"""
283
The number of generators of the dual group.
284
285
EXAMPLES::
286
287
sage: F = AbelianGroup([7]*100)
288
sage: Fd = F.dual_group()
289
sage: Fd.ngens()
290
100
291
"""
292
return self.group().ngens()
293
294
def gens_orders(self):
295
"""
296
The orders of the generators of the dual group.
297
298
OUTPUT:
299
300
A tuple of integers.
301
302
EXAMPLES::
303
304
sage: F = AbelianGroup([5]*1000)
305
sage: Fd = F.dual_group()
306
sage: invs = Fd.gens_orders(); len(invs)
307
1000
308
"""
309
return self.group().gens_orders()
310
311
def invariants(self):
312
"""
313
The invariants of the dual group.
314
315
You should use :meth:`gens_orders` instead.
316
317
EXAMPLES::
318
319
sage: F = AbelianGroup([5]*1000)
320
sage: Fd = F.dual_group()
321
sage: invs = Fd.gens_orders(); len(invs)
322
1000
323
"""
324
# TODO: deprecate
325
return self.group().gens_orders()
326
327
def __contains__(self,X):
328
"""
329
Implements "in".
330
331
EXAMPLES::
332
333
sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde")
334
sage: a,b,c,d,e = F.gens()
335
sage: Fd = F.dual_group(names = "ABCDE")
336
sage: A,B,C,D,E = Fd.gens()
337
sage: A*B^2*D^7 in Fd
338
True
339
"""
340
return X.parent() == self and is_DualAbelianGroupElement(X)
341
342
def order(self):
343
"""
344
Return the order of this group.
345
346
EXAMPLES::
347
348
sage: G = AbelianGroup([2,3,9])
349
sage: Gd = G.dual_group()
350
sage: Gd.order()
351
54
352
"""
353
G = self.group()
354
return G.order()
355
356
def is_commutative(self):
357
"""
358
Return True since this group is commutative.
359
360
EXAMPLES::
361
362
sage: G = AbelianGroup([2,3,9])
363
sage: Gd = G.dual_group()
364
sage: Gd.is_commutative()
365
True
366
sage: Gd.is_abelian()
367
True
368
"""
369
return True
370
371
@cached_method
372
def list(self):
373
"""
374
Return tuple of all elements of this group.
375
376
EXAMPLES::
377
378
sage: G = AbelianGroup([2,3], names="ab")
379
sage: Gd = G.dual_group(names="AB")
380
sage: Gd.list()
381
(1, B, B^2, A, A*B, A*B^2)
382
"""
383
if not(self.is_finite()):
384
raise NotImplementedError, "Group must be finite"
385
invs = self.gens_orders()
386
T = mrange(invs)
387
n = self.order()
388
L = tuple( self(t) for t in T )
389
return L
390
391
def __iter__(self):
392
"""
393
Return an iterator over the elements of this group.
394
395
EXAMPLES::
396
397
sage: G = AbelianGroup([2,3], names="ab")
398
sage: Gd = G.dual_group(names="AB")
399
sage: [X for X in Gd]
400
[1, B, B^2, A, A*B, A*B^2]
401
sage: N = 43^2-1
402
sage: G = AbelianGroup([N],names="a")
403
sage: Gd = G.dual_group(names="A", base_ring=CC)
404
sage: a, = G.gens()
405
sage: A, = Gd.gens()
406
sage: x = a^(N/4)
407
sage: y = a^(N/3)
408
sage: z = a^(N/14)
409
sage: len([X for X in Gd if abs(X(x)-1)>0.01 and abs(X(y)-1)>0.01 and abs(X(z)-1)>0.01])
410
880
411
"""
412
for g in self.list():
413
yield g
414
415
416
417
418