Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/groups/additive_abelian/additive_abelian_group.py
4097 views
1
r"""
2
Additive Abelian Groups
3
4
Additive abelian groups are just modules over `\ZZ`. Hence the classes in this
5
module derive from those in the module :mod:`sage.modules.fg_pid`. The only
6
major differences are in the way elements are printed.
7
"""
8
9
from sage.groups.group import AbelianGroup
10
from sage.modules.fg_pid.fgp_module import FGP_Module_class
11
from sage.modules.fg_pid.fgp_element import FGP_Element
12
from sage.rings.all import ZZ
13
14
def AdditiveAbelianGroup(invs, remember_generators = True):
15
r"""
16
Construct a finitely-generated additive abelian group.
17
18
INPUTS:
19
20
- ``invs`` (list of integers): the invariants.
21
These should all be greater than or equal to zero.
22
23
- ``remember_generators`` (boolean): whether or not to fix a set of
24
generators (corresponding to the given invariants, which need not be in
25
Smith form).
26
27
OUTPUT:
28
29
The abelian group `\bigoplus_i \ZZ / n_i \ZZ`, where `n_i` are the invariants.
30
31
EXAMPLE::
32
33
sage: AdditiveAbelianGroup([0, 2, 4])
34
Additive abelian group isomorphic to Z/2 + Z/4 + Z
35
36
An example of the ``remember_generators`` switch::
37
38
sage: G = AdditiveAbelianGroup([0, 2, 3]); G
39
Additive abelian group isomorphic to Z/6 + Z
40
sage: G.gens()
41
((1, 0, 0), (0, 1, 0), (0, 0, 1))
42
43
sage: H = AdditiveAbelianGroup([0, 2, 3], remember_generators = False); H
44
Additive abelian group isomorphic to Z/6 + Z
45
sage: H.gens()
46
((0, 1, 2), (1, 0, 0))
47
48
There are several ways to create elements of an additive abelian group.
49
Realize that there are two sets of generators: the "obvious" ones composed
50
of zeros and ones, one for each invariant given to construct the group, the
51
other being a set of minimal generators. Which set is the default varies
52
with the use of the ``remember_generators`` switch.
53
54
First with "obvious" generators. Note that a raw list will use the
55
minimal generators and a vector (a module element) will use the generators
56
that pair up naturally with the invariants. We create the same element
57
repeatedly. ::
58
59
sage: H=AdditiveAbelianGroup([3,2,0], remember_generators=True)
60
sage: H.gens()
61
((1, 0, 0), (0, 1, 0), (0, 0, 1))
62
sage: [H.0, H.1, H.2]
63
[(1, 0, 0), (0, 1, 0), (0, 0, 1)]
64
sage: p=H.0+H.1+6*H.2; p
65
(1, 1, 6)
66
67
sage: H.smith_form_gens()
68
((2, 1, 0), (0, 0, 1))
69
sage: q=H([5,6]); q
70
(1, 1, 6)
71
sage: p==q
72
True
73
74
sage: r=H(vector([1,1,6])); r
75
(1, 1, 6)
76
sage: p==r
77
True
78
79
sage: s=H(p)
80
sage: p==s
81
True
82
83
Again, but now where the generators are the minimal set. Coercing a
84
list or a vector works as before, but the default generators are different. ::
85
86
sage: G=AdditiveAbelianGroup([3,2,0], remember_generators=False)
87
sage: G.gens()
88
((2, 1, 0), (0, 0, 1))
89
sage: [G.0, G.1]
90
[(2, 1, 0), (0, 0, 1)]
91
sage: p=5*G.0+6*G.1; p
92
(1, 1, 6)
93
94
sage: H.smith_form_gens()
95
((2, 1, 0), (0, 0, 1))
96
sage: q=G([5,6]); q
97
(1, 1, 6)
98
sage: p==q
99
True
100
101
sage: r=G(vector([1,1,6])); r
102
(1, 1, 6)
103
sage: p==r
104
True
105
106
sage: s=H(p)
107
sage: p==s
108
True
109
"""
110
invs = [ZZ(x) for x in invs]
111
if not all( [x >= 0 for x in invs] ): raise ValueError, "Invariants must be nonnegative"
112
A, B = cover_and_relations_from_invariants(invs)
113
if remember_generators:
114
G = AdditiveAbelianGroup_fixed_gens(A, B, A.gens())
115
else:
116
G = AdditiveAbelianGroup_class(A, B)
117
return G
118
119
def cover_and_relations_from_invariants(invs):
120
r"""
121
A utility function to construct modules required to initialize the super class.
122
123
Given a list of integers, this routine constructs the obvious pair of
124
free modules such that the quotient of the two free modules over `\ZZ`
125
is naturally isomorphic to the corresponding product of cyclic modules
126
(and hence isomorphic to a direct sum of cyclic groups).
127
128
EXAMPLES::
129
130
sage: from sage.groups.additive_abelian.additive_abelian_group import cover_and_relations_from_invariants as cr
131
sage: cr([0,2,3])
132
(Ambient free module of rank 3 over the principal ideal domain Integer Ring, Free module of degree 3 and rank 2 over Integer Ring
133
Echelon basis matrix:
134
[0 2 0]
135
[0 0 3])
136
"""
137
n = len(invs)
138
A = ZZ**n
139
B = A.span([A.gen(i) * invs[i] for i in xrange(n)])
140
return (A, B)
141
142
143
144
class AdditiveAbelianGroupElement(FGP_Element):
145
"""
146
An element of an :class:`AdditiveAbelianGroup_class`.
147
"""
148
149
def _hermite_lift(self):
150
r"""
151
This gives a certain canonical lifting of elements of this group
152
(represented as a quotient `G/H` of free abelian groups) to `G`, using
153
the Hermite normal form of the matrix of relations.
154
155
Mainly used by the ``_repr_`` method.
156
157
EXAMPLES::
158
159
sage: A = AdditiveAbelianGroup([2, 3])
160
sage: v = 3000001 * A.0
161
sage: v.lift()
162
(3000001, 0)
163
sage: v._hermite_lift()
164
(1, 0)
165
"""
166
y = self.lift()
167
H = self.parent().W().basis_matrix()
168
pivot_rows = H.pivot_rows()
169
pivots = H.pivots()
170
171
for i in xrange(H.nrows()):
172
if i in pivot_rows:
173
j = pivots[i]
174
N = H[i,j]
175
a = (y[j] - (y[j] % N)) // N
176
y = y - a*H.row(i)
177
return y
178
179
def _repr_(self):
180
r"""
181
String representation. This uses a canonical lifting of elements of
182
this group (represented as a quotient `G/H` of free abelian groups) to
183
`G`, using the Hermite normal form of the matrix of relations.
184
185
EXAMPLE::
186
187
sage: G = AdditiveAbelianGroup([2,3])
188
sage: repr(G.gen(0)) # indirect doctest
189
'(1, 0)'
190
sage: a = 13*G.gen(0); repr(a) # indirect doctest
191
'(1, 0)'
192
sage: a._x
193
(13, 0)
194
"""
195
return repr(self._hermite_lift())
196
197
198
# Note: It's important that the class inherits from FGP_Module_class first,
199
# since we want to inherit things like __hash__ from there rather than the
200
# hyper-generic implementation for abstract abelian groups.
201
202
class AdditiveAbelianGroup_class(FGP_Module_class, AbelianGroup):
203
r"""
204
An additive abelian group, implemented using the `\ZZ`-module machinery.
205
206
INPUT:
207
208
- ``cover`` -- the covering group as `\ZZ`-module.
209
210
- ``relations`` -- the relations as submodule of ``cover``.
211
"""
212
213
# The element class must be overridden in derived classes
214
Element = AdditiveAbelianGroupElement
215
216
def __init__(self, cover, relations):
217
r"""
218
EXAMPLE::
219
220
sage: G = AdditiveAbelianGroup([0]); G # indirect doctest
221
Additive abelian group isomorphic to Z
222
sage: G == loads(dumps(G))
223
True
224
"""
225
FGP_Module_class.__init__(self, cover, relations)
226
227
def _repr_(self):
228
r"""
229
String representation of this group.
230
231
EXAMPLES::
232
233
sage: AdditiveAbelianGroup([0, 2, 3])._repr_()
234
'Additive abelian group isomorphic to Z/6 + Z'
235
"""
236
if self.V().rank() == 0:
237
return "Trivial group"
238
else:
239
return "Additive abelian group isomorphic to %s" % self.short_name()
240
241
def _latex_(self):
242
r"""
243
Returns a Latex representation of the group, using the invariants.
244
245
EXAMPLE::
246
247
sage: G=AdditiveAbelianGroup([66, 77, 0, 0])
248
sage: G._latex_()
249
'\\frac{\\ZZ}{11\\ZZ} \\oplus \\frac{\\ZZ}{462\\ZZ} \\oplus \\ZZ \\oplus \\ZZ'
250
251
A trivial group is represented as zero, rather than Z/1Z. ::
252
253
sage: G=AdditiveAbelianGroup([1])
254
sage: G._latex_()
255
'0'
256
"""
257
inv = self.invariants()
258
if not inv:
259
inv = (1,)
260
terms=[]
261
for i in range(len(inv)):
262
if inv[i] == 0:
263
terms.append('\\ZZ')
264
elif inv[i] == 1:
265
terms.append('0')
266
else:
267
terms.append('\\frac{\\ZZ}{' + str(inv[i]) + '\\ZZ}')
268
return ' \\oplus '.join(terms)
269
270
def short_name(self):
271
r"""
272
Return a name for the isomorphism class of this group.
273
274
EXAMPLE::
275
276
sage: AdditiveAbelianGroup([0, 2,4]).short_name()
277
'Z/2 + Z/4 + Z'
278
sage: AdditiveAbelianGroup([0, 2, 3]).short_name()
279
'Z/6 + Z'
280
"""
281
invs = self.invariants()
282
if not invs: return "Trivial group"
283
s = ""
284
for j in invs:
285
if j == 0: s += "Z + "
286
else: s += "Z/%s + " % j
287
return s[:-3] # drop the final " + "
288
289
def _module_constructor(self, cover, relations):
290
r"""
291
Construct quotients of groups.
292
293
INPUT:
294
295
- ``cover`` -- the covering group as `\ZZ`-module.
296
297
- ``relations`` -- the relations as submodule of ``cover``.
298
299
EXAMPLE::
300
301
sage: G = AdditiveAbelianGroup([0, 4, 2]); G
302
Additive abelian group isomorphic to Z/2 + Z/4 + Z
303
sage: H = G.submodule([G.1]); H
304
Additive abelian group isomorphic to Z/4
305
sage: G/H # indirect test
306
Additive abelian group isomorphic to Z/2 + Z
307
sage: G._module_constructor(G.cover(),H.cover()+G.relations())
308
Additive abelian group isomorphic to Z/2 + Z
309
"""
310
return AdditiveAbelianGroup_class(cover, relations)
311
312
def order(self):
313
r"""
314
Return the order of this group (an integer or infinity)
315
316
EXAMPLES::
317
318
sage: AdditiveAbelianGroup([2,4]).order()
319
8
320
sage: AdditiveAbelianGroup([0, 2,4]).order()
321
+Infinity
322
sage: AdditiveAbelianGroup([]).order()
323
1
324
"""
325
return self.cardinality()
326
327
def exponent(self):
328
r"""
329
Return the exponent of this group (the smallest positive integer `N`
330
such that `Nx = 0` for all `x` in the group). If there is no such
331
integer, return 0.
332
333
EXAMPLES::
334
335
sage: AdditiveAbelianGroup([2,4]).exponent()
336
4
337
sage: AdditiveAbelianGroup([0, 2,4]).exponent()
338
0
339
sage: AdditiveAbelianGroup([]).exponent()
340
1
341
"""
342
if not self.invariants():
343
return 1
344
else:
345
ann = self.annihilator().gen()
346
if ann:
347
return ann
348
return ZZ(0)
349
350
def is_multiplicative(self):
351
r"""
352
Return False since this is an additive group.
353
354
EXAMPLE::
355
356
sage: AdditiveAbelianGroup([0]).is_multiplicative()
357
False
358
"""
359
return False
360
361
def is_cyclic(self):
362
r"""
363
Returns ``True`` if the group is cyclic.
364
365
EXAMPLES:
366
367
With no common factors between the orders of the generators,
368
the group will be cyclic. ::
369
370
sage: G=AdditiveAbelianGroup([6, 7, 55])
371
sage: G.is_cyclic()
372
True
373
374
Repeating primes in the orders will create a non-cyclic group. ::
375
376
sage: G=AdditiveAbelianGroup([6, 15, 21, 33])
377
sage: G.is_cyclic()
378
False
379
380
A trivial group is trivially cyclic. ::
381
382
sage: T=AdditiveAbelianGroup([1])
383
sage: T.is_cyclic()
384
True
385
"""
386
# One invariant is characteristic of a cyclic group
387
# while zero invariants is characteristic of the trivial group
388
return len(self.invariants()) < 2
389
390
391
class AdditiveAbelianGroup_fixed_gens(AdditiveAbelianGroup_class):
392
r"""
393
A variant which fixes a set of generators, which need not be in Smith form
394
(or indeed independent).
395
"""
396
def __init__(self, cover, rels, gens):
397
r"""
398
Standard initialisation function
399
400
EXAMPLE::
401
402
sage: AdditiveAbelianGroup([3]) # indirect doctest
403
Additive abelian group isomorphic to Z/3
404
"""
405
AdditiveAbelianGroup_class.__init__(self, cover, rels)
406
self._orig_gens = [self(x) for x in gens]
407
408
def gens(self):
409
r"""
410
Return the specified generators for self (as a tuple). Compare
411
``self.smithform_gens()``.
412
413
EXAMPLE::
414
415
sage: G = AdditiveAbelianGroup([2,3])
416
sage: G.gens()
417
((1, 0), (0, 1))
418
sage: G.smith_form_gens()
419
((1, 2),)
420
"""
421
return tuple(self._orig_gens)
422
423
def identity(self):
424
r"""
425
Return the identity (zero) element of this group.
426
427
EXAMPLE::
428
429
sage: G = AdditiveAbelianGroup([2, 3])
430
sage: G.identity()
431
(0, 0)
432
"""
433
return self(0)
434
435
def permutation_group(self):
436
r"""
437
Return the permutation group attached to this group.
438
439
EXAMPLE::
440
441
sage: G = AdditiveAbelianGroup([2, 3])
442
sage: G.permutation_group()
443
Permutation Group with generators [(1,4,2,5,3,6)]
444
"""
445
from sage.groups.perm_gps.permgroup import PermutationGroup
446
s = 'Image(IsomorphismPermGroup(AbelianGroup(%s)))'%(list(self.invariants()),)
447
return PermutationGroup(gap_group=s)
448
449
450