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