Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/groups/abelian_gps/abelian_group.py
4100 views
1
r"""
2
Multiplicative Abelian Groups
3
4
AUTHORS:
5
6
- William Stein, David Joyner (2008-12): added (user requested) is_cyclic,
7
fixed elementary_divisors.
8
9
- David Joyner (2006-03): (based on free abelian monoids by David
10
Kohel)
11
12
- David Joyner (2006-05) several significant bug fixes
13
14
- David Joyner (2006-08) trivial changes to docs, added random, fixed
15
bug in how invariants are recorded
16
17
- David Joyner (2006-10) added dual_group method
18
19
- David Joyner (2008-02) fixed serious bug in word_problem
20
21
- David Joyner (2008-03) fixed bug in trivial group case
22
23
- David Loeffler (2009-05) added subgroups method
24
25
26
TODO:
27
28
- additive abelian groups should also be supported
29
30
Background on invariant factors and the Smith normal form
31
(according to section 4.1 of [C1]): An abelian group is a
32
group A for which there exists an exact sequence
33
`\ZZ^k \rightarrow \ZZ^\ell \rightarrow A \rightarrow 1`,
34
for some positive integers
35
`k,\ell` with `k\leq \ell`. For example, a finite abelian group has a
36
decomposition
37
38
.. math::
39
40
A = \langle a_1\rangle \times \dots \times \langle a_\ell\rangle ,
41
42
where `ord(a_i)=p_i^{c_i}`, for some primes `p_i` and some
43
positive integers `c_i`, `i=1,...,\ell`. GAP calls the
44
list (ordered by size) of the `p_i^{c_i}` the *abelian invariants*.
45
In Sage they will be called *invariants*.
46
In this situation, `k=\ell` and `\phi: \ZZ^\ell \rightarrow A` is the map
47
`\phi(x_1,...,x_\ell) = a_1^{x_1}...a_\ell^{x_\ell}`,
48
for `(x_1,...,x_\ell)\in \ZZ^\ell`. The matrix of relations
49
`M:\ZZ^k \rightarrow \ZZ^\ell` is the matrix
50
whose rows generate the kernel of `\phi` as a `\ZZ`-module.
51
In other words, `M=(M_{ij})` is a `\ell\times \ell`
52
diagonal matrix with `M_{ii}=p_i^{c_i}`. Consider now the
53
subgroup `B\subset A` generated by
54
`b_1 = a_1^{f_{1,1}}...a_\ell^{f_{\ell,1}}`, ...,
55
`b_m = a_1^{f_{1,m}}...a_\ell^{f_{\ell,m}}`.
56
The kernel of the map `\phi_B: \ZZ^m \rightarrow B` defined by
57
`\phi_B(y_1,...,y_m) = b_1^{y_1}...b_m^{y_m}`,
58
for `(y_1,...,y_m)\in \ZZ^m`, is the kernel of the matrix
59
60
.. math::
61
62
F=
63
\left(
64
\begin{array}{cccc}
65
f_{11} & f_{12} & \dots & f_{1m}\\
66
f_{21} & f_{22} & \dots & f_{2m}\\
67
\vdots & & \ddots & \vdots \\
68
f_{\ell,1} & f_{\ell,2} & \dots & f_{\ell,m}
69
\end{array}
70
\right),
71
72
regarded as a map
73
`\ZZ^m\rightarrow (\ZZ/p_1^{c_1}\ZZ)\times ...\times (\ZZ/p_\ell^{c_\ell}\ZZ)`.
74
In particular, `B\cong \ZZ^m/ker(F)`. If `B=A` then the
75
Smith normal form (SNF) of a generator matrix of
76
`ker(F)` and the SNF of `M` are the same. The diagonal entries `s_i` of the
77
SNF `S = diag[s_1,s_2,s_3, ... s_r,0,0,...0]`,
78
are called *determinantal divisors* of `F`.
79
where `r` is the rank. The {\it invariant factors} of A are:
80
81
.. math::
82
83
s_1, s_2/s_1, s_3/s_2, ... s_r/s_{r-1}.
84
85
86
87
Sage supports multiplicative abelian groups on any prescribed finite
88
number `n \geq 0` of generators. Use the ``AbelianGroup`` function
89
to create an abelian group, and the ``gen`` and ``gens``
90
functions to obtain the corresponding generators. You can print the
91
generators as arbitrary strings using the optional ``names``
92
argument to the ``AbelianGroup`` function.
93
94
EXAMPLE 1:
95
96
We create an abelian group in zero or more variables; the syntax T(1)
97
creates the identity element even in the rank zero case.
98
99
::
100
101
sage: T = AbelianGroup(0,[])
102
sage: T
103
Trivial Abelian Group
104
sage: T.gens()
105
()
106
sage: T(1)
107
1
108
109
EXAMPLE 2: An abelian group uses a multiplicative representation of
110
elements, but the underlying representation is lists of integer
111
exponents.
112
113
::
114
115
sage: F = AbelianGroup(5,[3,4,5,5,7],names = list("abcde"))
116
sage: F
117
Multiplicative Abelian Group isomorphic to C3 x C4 x C5 x C5 x C7
118
sage: (a,b,c,d,e) = F.gens()
119
sage: a*b^2*e*d
120
a*b^2*d*e
121
sage: x = b^2*e*d*a^7
122
sage: x
123
a*b^2*d*e
124
sage: x.list()
125
[1, 2, 0, 1, 1]
126
127
REFERENCES:
128
129
- [C1] H. Cohen Advanced topics in computational number theory,
130
Springer, 2000.
131
132
- [C2] ----, A course in computational algebraic number theory,
133
Springer, 1996.
134
135
- [R] J. Rotman, An introduction to the theory of
136
groups, 4th ed, Springer, 1995.
137
138
.. warning::
139
140
Many basic properties for infinite abelian groups are not
141
implemented.
142
"""
143
144
##########################################################################
145
# Copyright (C) 2006 David Joyner and William Stein
146
#
147
# Distributed under the terms of the GNU General Public License (GPL):
148
#
149
# http://www.gnu.org/licenses/
150
##########################################################################
151
152
# TODO: change the "invariants" terminology everywhere to elementary_divisors
153
154
155
156
from sage.rings.integer import Integer
157
158
from sage.rings.infinity import infinity
159
from sage.rings.arith import divisors, gcd
160
from abelian_group_element import AbelianGroupElement
161
from sage.misc.misc import prod
162
from sage.misc.mrange import mrange, cartesian_product_iterator
163
import sage.groups.group as group
164
from sage.rings.integer_ring import IntegerRing
165
from sage.rings.arith import lcm
166
ZZ = IntegerRing()
167
168
# TODO: this uses perm groups - the AbelianGroupElement instance method
169
# uses a different implementation.
170
171
172
def word_problem(words, g, verbose = False):
173
r"""
174
G and H are abelian, g in G, H is a subgroup of G generated by a
175
list (words) of elements of G. If g is in H, return the expression
176
for g as a word in the elements of (words).
177
178
The 'word problem' for a finite abelian group G boils down to the
179
following matrix-vector analog of the Chinese remainder theorem.
180
181
Problem: Fix integers `1<n_1\leq n_2\leq ...\leq n_k`
182
(indeed, these `n_i` will all be prime powers), fix a
183
generating set `g_i=(a_{i1},...,a_{ik})` (with
184
`a_{ij}\in \mathrm{Z}/n_j\mathrm{Z}`), for `1\leq i\leq \ell`,
185
for the group `G`, and let `d = (d_1,...,d_k)` be
186
an element of the direct product
187
`\mathrm{Z}/n_1\mathrm{Z} \times ...\times \mathrm{Z}/n_k\mathrm{Z}`. Find, if they
188
exist, integers `c_1,...,c_\ell` such that
189
`c_1g_1+...+c_\ell g_\ell = d`. In other words, solve
190
the equation `cA=d` for `c\in \mathrm{Z}^\ell`, where
191
`A` is the matrix whose rows are the `g_i`'s. Of
192
course, it suffices to restrict the `c_i`'s to the range
193
`0\leq c_i\leq N-1`, where `N` denotes the least
194
common multiple of the integers `n_1,...,n_k`.
195
196
This function does not solve this directly, as perhaps it should.
197
Rather (for both speed and as a model for a similar function valid
198
for more general groups), it pushes it over to GAP, which has optimized
199
(non-deterministic) algorithms for the word problem. Essentially,
200
this function is a wrapper for the GAP function 'Factorization'.
201
202
EXAMPLE::
203
204
sage: G.<a,b,c> = AbelianGroup(3,[2,3,4]); G
205
Multiplicative Abelian Group isomorphic to C2 x C3 x C4
206
sage: w = word_problem([a*b,a*c], b*c); w #random
207
[[a*b, 1], [a*c, 1]]
208
sage: prod([x^i for x,i in w]) == b*c
209
True
210
sage: w = word_problem([a*c,c],a); w #random
211
[[a*c, 1], [c, -1]]
212
sage: prod([x^i for x,i in w]) == a
213
True
214
sage: word_problem([a*c,c],a,verbose=True) #random
215
a = (a*c)^1*(c)^-1
216
[[a*c, 1], [c, -1]]
217
218
::
219
220
sage: A.<a,b,c,d,e> = AbelianGroup(5,[4, 5, 5, 7, 8])
221
sage: b1 = a^3*b*c*d^2*e^5
222
sage: b2 = a^2*b*c^2*d^3*e^3
223
sage: b3 = a^7*b^3*c^5*d^4*e^4
224
sage: b4 = a^3*b^2*c^2*d^3*e^5
225
sage: b5 = a^2*b^4*c^2*d^4*e^5
226
sage: w = word_problem([b1,b2,b3,b4,b5],e); w #random
227
[[a^3*b*c*d^2*e^5, 1], [a^2*b*c^2*d^3*e^3, 1], [a^3*b^3*d^4*e^4, 3], [a^2*b^4*c^2*d^4*e^5, 1]]
228
sage: prod([x^i for x,i in w]) == e
229
True
230
sage: word_problem([a,b,c,d,e],e)
231
[[e, 1]]
232
sage: word_problem([a,b,c,d,e],b)
233
[[b, 1]]
234
235
.. warning::
236
237
1. Might have unpleasant effect when the word problem
238
cannot be solved.
239
240
2. Uses permutation groups, so may be slow when group is large.
241
The instance method word_problem of the class
242
AbelianGroupElement is implemented differently (wrapping
243
GAP's 'EpimorphismFromFreeGroup' and
244
'PreImagesRepresentative') and may be faster.
245
246
"""
247
from sage.interfaces.all import gap
248
G = g.parent()
249
invs = G.invariants()
250
gap.eval("l:=One(Rationals)")
251
s1 = 'A:=AbelianGroup(%s)'%invs
252
gap.eval(s1)
253
s2 = 'phi:=IsomorphismPermGroup(A)'
254
gap.eval(s2)
255
s3 = "gens := GeneratorsOfGroup(A)"
256
gap.eval(s3)
257
L = g.list()
258
gap.eval("L1:="+str(L))
259
s4 = "L2:=List([l..%s], i->gens[i]^L1[i]);"%len(L)
260
gap.eval(s4)
261
gap.eval("g:=Product(L2); gensH:=[]")
262
for w in words:
263
L = w.list()
264
gap.eval("L1:="+str(L))
265
s4 = "L2:=List([1..%s], i->gens[i]^L1[i]);"%len(L)
266
gap.eval(s4)
267
gap.eval("w:=Product(L2)")
268
gap.eval("gensH:=Concatenation(gensH,[w])")
269
s5 = 'H:=Group(gensH)'
270
gap.eval(s5)
271
gap.eval("x:=Factorization(H,g)")
272
l3 = eval(gap.eval("L3:=ExtRepOfObj(x)"))
273
nn = gap.eval("n:=Int(Length(L3)/2)")
274
LL = eval(gap.eval("L4:=List([l..n],i->L3[2*i])"))
275
if verbose:
276
#print gap.eval("x"), l3, nn, LL
277
v = '*'.join(['(%s)^%s'%(words[l3[2*i]-1], LL[i]) for i in range(len(LL))])
278
print '%s = %s'%(g, v)
279
return [[words[l3[2*i]-1],LL[i]] for i in range(len(LL))]
280
281
282
def AbelianGroup(n, invfac=None, names="f"):
283
r"""
284
Create the multiplicative abelian group in `n` generators
285
with given invariants (which need not be prime powers).
286
287
INPUT:
288
289
290
- ``n`` - integer
291
292
- ``invfac`` - (the"invariant factors") a list of
293
non-negative integers in the form [a0, a1,...,a(n-1)], typically
294
written in increasing order. This list is padded with zeros if it
295
has length less than n.
296
297
- ``names`` - (optional) names of generators
298
299
Alternatively, you can also give input in the following form:
300
301
``AbelianGroup(invfac, names="f")``,
302
303
where names must be explicitly named.
304
305
306
OUTPUT: Abelian group with generators and invariant type. The
307
default name for generator A.i is fi, as in GAP.
308
309
EXAMPLES::
310
311
sage: F = AbelianGroup(5, [5,5,7,8,9], names='abcde')
312
sage: F(1)
313
1
314
sage: (a, b, c, d, e) = F.gens()
315
sage: mul([ a, b, a, c, b, d, c, d ], F(1))
316
a^2*b^2*c^2*d^2
317
sage: d * b**2 * c**3
318
b^2*c^3*d
319
sage: F = AbelianGroup(3,[2]*3); F
320
Multiplicative Abelian Group isomorphic to C2 x C2 x C2
321
sage: H = AbelianGroup([2,3], names="xy"); H
322
Multiplicative Abelian Group isomorphic to C2 x C3
323
sage: AbelianGroup(5)
324
Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z
325
sage: AbelianGroup(5).order()
326
+Infinity
327
328
Notice how `0`'s are padded on.
329
330
::
331
332
sage: AbelianGroup(5, [2,3,4])
333
Multiplicative Abelian Group isomorphic to Z x Z x C2 x C3 x C4
334
335
The invariant list can't be longer than the number of generators.
336
337
::
338
339
sage: AbelianGroup(2, [2,3,4])
340
Traceback (most recent call last):
341
...
342
ValueError: invfac (=[2, 3, 4]) must have length n (=2)
343
"""
344
if invfac is None:
345
if isinstance(n, (list, tuple)):
346
invfac = n
347
n = len(n)
348
else:
349
invfac = []
350
if len(invfac) < n:
351
invfac = [0] * (n - len(invfac)) + invfac
352
elif len(invfac) > n:
353
raise ValueError, "invfac (=%s) must have length n (=%s)"%(invfac, n)
354
M = AbelianGroup_class(n, invfac, names)
355
return M
356
357
def is_AbelianGroup(x):
358
"""
359
Return True if `x` is an abelian group.
360
361
EXAMPLES::
362
363
sage: from sage.groups.abelian_gps.abelian_group import is_AbelianGroup
364
sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F
365
Multiplicative Abelian Group isomorphic to C5 x C5 x C7 x C8 x C9
366
sage: is_AbelianGroup(F)
367
True
368
sage: is_AbelianGroup(AbelianGroup(7, [3]*7))
369
True
370
"""
371
return isinstance(x, AbelianGroup_class)
372
373
374
class AbelianGroup_class(group.AbelianGroup):
375
"""
376
Abelian group on `n` generators. The invariant factors
377
`[a_1,a_2,...,a_k]` need not be prime powers.
378
divisors will be).
379
380
EXAMPLES::
381
382
sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F
383
Multiplicative Abelian Group isomorphic to C5 x C5 x C7 x C8 x C9
384
sage: F = AbelianGroup(5,[2, 4, 12, 24, 120],names = list("abcde")); F
385
Multiplicative Abelian Group isomorphic to C2 x C4 x C12 x C24 x C120
386
sage: F.elementary_divisors()
387
[2, 4, 12, 24, 120]
388
389
The entry 1 in the list of invariants is ignored::
390
391
sage: F = AbelianGroup(3,[1,2,3],names='a')
392
sage: F.invariants()
393
[2, 3]
394
sage: F.gens()
395
(a0, a1)
396
sage: F.ngens()
397
2
398
sage: (F.0).order()
399
2
400
sage: (F.1).order()
401
3
402
sage: AbelianGroup(1, [1], names='e')
403
Multiplicative Abelian Group isomorphic to C1
404
sage: AbelianGroup(1, [1], names='e').gens()
405
(e,)
406
sage: AbelianGroup(1, [1], names='e').list()
407
[1]
408
sage: AbelianGroup(3, [2, 1, 2], names=list('abc')).list()
409
[1, b, a, a*b]
410
411
sage: F.category()
412
Category of groups
413
414
"""
415
def __init__(self, n, invfac, names="f"):
416
#invfac.sort()
417
n = Integer(n)
418
# if necessary, remove 1 from invfac first
419
if n != 1:
420
while True:
421
try:
422
i = invfac.index(1)
423
except ValueError:
424
break
425
else:
426
del invfac[i]
427
n = n-1
428
429
if n < 0:
430
raise ValueError, "n (=%s) must be nonnegative."%n
431
432
self.__invariants = invfac
433
434
# *now* define ngens
435
self.__ngens = len(self.__invariants)
436
self._assign_names(names[:n])
437
from sage.categories.groups import Groups
438
group.Group.__init__(self, category = Groups()) # should be CommutativeGroups()
439
440
def __call__(self, x):
441
"""
442
Create an element of this abelian group from `x`.
443
444
EXAMPLES::
445
446
sage: F = AbelianGroup(10, [2]*10)
447
sage: F(F.2)
448
f2
449
sage: F(1)
450
1
451
"""
452
if isinstance(x, AbelianGroupElement) and x.parent() is self:
453
return x
454
return AbelianGroupElement(self, x)
455
456
def __contains__(self, x):
457
"""
458
Return True if `x` is an element of this abelian group.
459
460
EXAMPLES::
461
462
sage: F = AbelianGroup(10,[2]*10)
463
sage: F.2 * F.3 in F
464
True
465
"""
466
return isinstance(x, AbelianGroupElement) and x.parent() == self
467
468
def __eq__(self, right):
469
"""
470
Compare self and right.
471
472
The ordering is the ordering induced by that on the invariant
473
factors lists.
474
475
EXAMPLES::
476
477
sage: G1 = AbelianGroup([2,3,4,5])
478
sage: G2 = AbelianGroup([2,3,4,5,1])
479
sage: G1 < G2
480
False
481
sage: G1 > G2
482
False
483
sage: G1 == G2
484
True
485
"""
486
if not is_AbelianGroup(right):
487
return False
488
if set(self.variable_names()) != set(right.variable_names()):
489
return False
490
svars = list(self.variable_names())
491
sinvs = self.invariants()
492
rvars = list(right.variable_names())
493
rinvs = right.invariants()
494
for i in xrange(len(svars)):
495
if rinvs[rvars.index(svars[i])] != sinvs[i]:
496
return False
497
return True
498
499
def __ne__(self, right):
500
return not self == right
501
502
def __ge__(self, right):
503
for a in right.gens():
504
if a not in self:
505
return False
506
return True
507
508
def __lt__(self, right):
509
"""
510
EXAMPLE::
511
512
sage: G.<a, b> = AbelianGroup(2)
513
sage: H.<c> = AbelianGroup(1)
514
sage: H < G
515
False
516
"""
517
return self <= right and self != right
518
519
def __gt__(self, right):
520
return self >= right and self != right
521
522
def __le__(self, right):
523
for a in self.gens():
524
if a not in right:
525
return False
526
return True
527
528
def __nonzero__(self):
529
"""
530
Returns True if this group is nontrivial.
531
532
EXAMPLES::
533
534
sage: T = AbelianGroup([2, 3])
535
sage: bool(T) # indirect doctest
536
True
537
sage: bool(AbelianGroup([]))
538
False
539
"""
540
return len(self.invariants()) != 0
541
542
def dual_group(self):
543
"""
544
Returns the dual group.
545
546
EXAMPLES:
547
"""
548
from sage.groups.abelian_gps.dual_abelian_group import DualAbelianGroup
549
return DualAbelianGroup(self)
550
551
def elementary_divisors(self):
552
r"""
553
This returns the elementary divisors of the group, using Pari.
554
555
.. note::
556
557
Here is another algorithm for computing the elementary divisors
558
`d_1, d_2, d_3, \ldots`, of a finite abelian group (where `d_1 | d_2 | d_3 | \ldots`
559
are composed of prime powers dividing the invariants of the group
560
in a way described below). Just factor the invariants `a_i` that
561
define the abelian group. Then the biggest `d_i` is the product
562
of the maximum prime powers dividing some `a_j`. In other words, the
563
largest `d_i` is the product of `p^v`, where `v = max(ord_p(a_j) \mathrm{ for all } j`).
564
Now divide out all those `p^v`'s into the list of invariants `a_i`,
565
and get a new list of "smaller invariants"". Repeat the above procedure
566
on these ""smaller invariants"" to compute `d_{i-1}`, and so on.
567
(Thanks to Robert Miller for communicating this algorithm.)
568
569
EXAMPLES::
570
571
sage: G = AbelianGroup(2,[2,3])
572
sage: G.elementary_divisors()
573
[6]
574
sage: G = AbelianGroup(1, [6])
575
sage: G.elementary_divisors()
576
[6]
577
sage: G = AbelianGroup(2,[2,6])
578
sage: G
579
Multiplicative Abelian Group isomorphic to C2 x C6
580
sage: G.invariants()
581
[2, 6]
582
sage: G.elementary_divisors()
583
[2, 6]
584
sage: J = AbelianGroup([1,3,5,12])
585
sage: J.elementary_divisors()
586
[3, 60]
587
sage: G = AbelianGroup(2,[0,6])
588
sage: G.elementary_divisors()
589
[6, 0]
590
sage: AbelianGroup([3,4,5]).elementary_divisors()
591
[60]
592
"""
593
from sage.matrix.constructor import diagonal_matrix
594
ed = diagonal_matrix(ZZ, self.invariants()).elementary_divisors()
595
return [d for d in ed if d!=1]
596
597
def exponent(self):
598
"""
599
Return the exponent of this abelian group.
600
601
EXAMPLES::
602
603
sage: G = AbelianGroup([2,3,7]); G
604
Multiplicative Abelian Group isomorphic to C2 x C3 x C7
605
sage: G.exponent()
606
42
607
sage: G = AbelianGroup([2,4,6]); G
608
Multiplicative Abelian Group isomorphic to C2 x C4 x C6
609
sage: G.exponent()
610
12
611
"""
612
try:
613
return self.__exponent
614
except AttributeError:
615
self.__exponent = e = lcm(self.invariants())
616
return e
617
618
619
def identity(self):
620
r"""
621
Return the identity element of this group.
622
623
EXAMPLES::
624
625
sage: G = AbelianGroup([2,2])
626
sage: e = G.identity()
627
sage: e
628
1
629
sage: g = G.gen(0)
630
sage: g*e
631
f0
632
sage: e*g
633
f0
634
"""
635
return self(1)
636
637
638
def _group_notation(self, eldv):
639
v = []
640
for x in eldv:
641
if x:
642
v.append("C%s"%x)
643
else:
644
v.append("Z")
645
return ' x '.join(v)
646
647
def _latex_(self):
648
r"""
649
Return latex representation of this group.
650
651
EXAMPLES::
652
653
sage: F = AbelianGroup(10, [2]*10)
654
sage: F._latex_()
655
'$\\mathrm{AbelianGroup}( 10, [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] )$'
656
"""
657
s = "$\mathrm{AbelianGroup}( %s, %s )$"%(len(self.invariants()), self.invariants())
658
return s
659
660
def _gap_init_(self):
661
r"""
662
Return string that defines corresponding abelian group in GAP.
663
664
EXAMPLES::
665
666
sage: G = AbelianGroup([2,3,9])
667
sage: G._gap_init_()
668
'AbelianGroup([2, 3, 9])'
669
sage: gap(G)
670
Group( [ f1, f2, f3 ] )
671
672
Only works for finite groups.
673
674
::
675
676
sage: G = AbelianGroup(3,[0,3,4],names="abc"); G
677
Multiplicative Abelian Group isomorphic to Z x C3 x C4
678
sage: G._gap_init_()
679
Traceback (most recent call last):
680
...
681
TypeError: abelian groups in GAP are finite, but self is infinite
682
"""
683
# TODO: Use the package polycyclic has AbelianPcpGroup, which can handle
684
# the infinite case but it is a GAP package not GPL'd.
685
# Use this when the group is infinite...
686
if (False and prod(self.invariants())==0): # if False for now...
687
return 'AbelianPcpGroup(%s)'%self.invariants()
688
if not self.is_finite():
689
raise TypeError, "abelian groups in GAP are finite, but self is infinite"
690
return 'AbelianGroup(%s)'%self.invariants()
691
692
def gen(self, i=0):
693
"""
694
The `i`-th generator of the abelian group.
695
696
EXAMPLES::
697
698
sage: F = AbelianGroup(5,[],names='a')
699
sage: F.0
700
a0
701
sage: F.2
702
a2
703
sage: F.invariants()
704
[0, 0, 0, 0, 0]
705
"""
706
n = self.__ngens
707
if i < 0 or i >= n:
708
raise IndexError, "Argument i (= %s) must be between 0 and %s."%(i, n-1)
709
x = [0]*int(n)
710
x[int(i)] = 1
711
return AbelianGroupElement(self, x)
712
713
def invariants(self):
714
"""
715
Return a copy of the list of invariants of this group.
716
717
It is safe to modify the returned list.
718
719
EXAMPLES::
720
721
sage: J = AbelianGroup([2,3])
722
sage: J.invariants()
723
[2, 3]
724
sage: v = J.invariants(); v
725
[2, 3]
726
sage: v[0] = 5
727
sage: J.invariants()
728
[2, 3]
729
sage: J.invariants() is J.invariants()
730
False
731
"""
732
return list(self.__invariants)
733
734
def is_cyclic(self):
735
"""
736
Return True if the group is a cyclic group.
737
738
EXAMPLES::
739
740
sage: J = AbelianGroup([2,3])
741
sage: J.invariants()
742
[2, 3]
743
sage: J.elementary_divisors()
744
[6]
745
sage: J.is_cyclic()
746
True
747
sage: G = AbelianGroup([6])
748
sage: G.invariants()
749
[6]
750
sage: G.is_cyclic()
751
True
752
sage: H = AbelianGroup([2,2])
753
sage: H.invariants()
754
[2, 2]
755
sage: H.is_cyclic()
756
False
757
sage: H = AbelianGroup([2,4])
758
sage: H.elementary_divisors()
759
[2, 4]
760
sage: H.is_cyclic()
761
False
762
sage: H.permutation_group().is_cyclic()
763
False
764
sage: T = AbelianGroup([])
765
sage: T.is_cyclic()
766
True
767
sage: T = AbelianGroup(1,[0]); T
768
Multiplicative Abelian Group isomorphic to Z
769
sage: T.is_cyclic()
770
True
771
sage: B = AbelianGroup([3,4,5])
772
sage: B.is_cyclic()
773
True
774
"""
775
return len(self.elementary_divisors()) <= 1
776
777
def ngens(self):
778
"""
779
The number of free generators of the abelian group.
780
781
EXAMPLES::
782
783
sage: F = AbelianGroup(10000)
784
sage: F.ngens()
785
10000
786
"""
787
return self.__ngens
788
789
def order(self):
790
"""
791
Return the order of this group.
792
793
EXAMPLES::
794
795
sage: G = AbelianGroup(2,[2,3])
796
sage: G.order()
797
6
798
sage: G = AbelianGroup(3,[2,3,0])
799
sage: G.order()
800
+Infinity
801
"""
802
try:
803
return self.__len
804
except AttributeError:
805
from sage.rings.all import infinity, Integer
806
if len(self.invariants()) < self.ngens():
807
self.__len = infinity
808
else:
809
self.__len = Integer(prod(self.invariants()))
810
if self.__len == 0:
811
self.__len = infinity
812
return self.__len
813
814
def permutation_group(self):
815
r"""
816
Return the permutation group isomorphic to this abelian group.
817
818
If the invariants are `q_1, \ldots, q_n` then the
819
generators of the permutation will be of order
820
`q_1, \ldots, q_n`, respectively.
821
822
EXAMPLES::
823
824
sage: G = AbelianGroup(2,[2,3]); G
825
Multiplicative Abelian Group isomorphic to C2 x C3
826
sage: G.permutation_group()
827
Permutation Group with generators [(1,2,3)(4,5,6), (1,4)(2,5)(3,6)]
828
"""
829
from sage.groups.perm_gps.permgroup import PermutationGroup
830
s = 'Image(IsomorphismPermGroup(%s))'%self._gap_init_()
831
return PermutationGroup(gap_group=s)
832
833
834
def is_commutative(self):
835
"""
836
Return True since this group is commutative.
837
838
EXAMPLES::
839
840
sage: G = AbelianGroup([2,3,9, 0])
841
sage: G.is_commutative()
842
True
843
sage: G.is_abelian()
844
True
845
"""
846
return True
847
848
def random_element(self):
849
"""
850
Return a random element of this group. (Renamed random to
851
random_element.)
852
853
EXAMPLES::
854
855
sage: G = AbelianGroup([2,3,9])
856
sage: G.random_element()
857
f0*f1^2*f2
858
"""
859
from sage.misc.prandom import randint
860
if self.order() is infinity:
861
NotImplementedError, "The group must be finite"
862
gens = self.gens()
863
g = gens[0]**0
864
for i in range(len(gens)):
865
g = g*gens[i]**(randint(1,gens[i].order()))
866
return g
867
868
869
def _repr_(self):
870
eldv = self.invariants()
871
if len(eldv) == 0:
872
return "Trivial Abelian Group"
873
g = self._group_notation(eldv)
874
return "Multiplicative Abelian Group isomorphic to " + g
875
876
877
def subgroup(self, gensH, names="f"):
878
"""
879
Create a subgroup of this group. The "big" group must be defined
880
using "named" generators.
881
882
INPUT:
883
884
885
- ``gensH`` - list of elements which are products of
886
the generators of the ambient abelian group G = self
887
888
889
EXAMPLES::
890
891
sage: G.<a,b,c> = AbelianGroup(3, [2,3,4]); G
892
Multiplicative Abelian Group isomorphic to C2 x C3 x C4
893
sage: H = G.subgroup([a*b,a]); H
894
Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
895
Multiplicative Abelian Group isomorphic to C2 x C3 x C4
896
generated by [a*b, a]
897
sage: H < G
898
True
899
sage: F = G.subgroup([a,b^2])
900
sage: F
901
Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
902
Multiplicative Abelian Group isomorphic to C2 x C3 x C4
903
generated by [a, b^2]
904
sage: F.gens()
905
[a, b^2]
906
sage: F = AbelianGroup(5,[30,64,729],names = list("abcde"))
907
sage: a,b,c,d,e = F.gens()
908
sage: F.subgroup([a,b])
909
Multiplicative Abelian Group isomorphic to Z x Z, which is
910
the subgroup of Multiplicative Abelian Group isomorphic to
911
Z x Z x C30 x C64 x C729 generated by [a, b]
912
sage: F.subgroup([c,e])
913
Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x
914
C729, which is the subgroup of Multiplicative Abelian
915
Group isomorphic to Z x Z x C30 x C64 x C729 generated by
916
[c, e]
917
"""
918
if not isinstance(gensH, (list, tuple)):
919
raise TypeError, "gensH = (%s) must be a list or tuple"%(gensH)
920
921
G = self
922
for i in range(len(gensH)):
923
if not(gensH[i] in G):
924
raise TypeError, "Subgroup generators must belong to the given group."
925
return AbelianGroup_subgroup(self, gensH, names)
926
927
def list(self):
928
"""
929
Return list of all elements of this group.
930
931
EXAMPLES::
932
933
sage: G = AbelianGroup([2,3], names = "ab")
934
sage: G.list()
935
[1, b, b^2, a, a*b, a*b^2]
936
937
::
938
939
sage: G = AbelianGroup([]); G
940
Trivial Abelian Group
941
sage: G.list()
942
[1]
943
"""
944
try:
945
return list(self.__list)
946
except AttributeError:
947
pass
948
if not(self.is_finite()):
949
raise NotImplementedError, "Group must be finite"
950
self.__list = list(self.__iter__())
951
return list(self.__list)
952
953
def __iter__(self):
954
"""
955
Return an iterator over the elements of this group.
956
957
EXAMPLES::
958
959
sage: G = AbelianGroup([2,3], names = "ab")
960
sage: [a for a in G]
961
[1, b, b^2, a, a*b, a*b^2]
962
sage: L = list(G); L
963
[1, b, b^2, a, a*b, a*b^2]
964
965
The returned list is a reference; mutating it does not allow the
966
user to (accidentally?) alter the computed generators::
967
968
sage: L[0] = 0
969
sage: list(G)
970
[1, b, b^2, a, a*b, a*b^2]
971
sage: G = AbelianGroup([1], names="a")
972
sage: list(G)
973
[1]
974
sage: G = AbelianGroup([])
975
sage: G.list()
976
[1]
977
sage: list(G)
978
[1]
979
"""
980
invs = self.invariants()
981
for t in mrange(invs):
982
yield AbelianGroupElement(self, t)
983
984
985
def subgroups(self, check=False):
986
r"""
987
Compute all the subgroups of this abelian group (which must be finite).
988
989
TODO: This is *many orders of magnitude* slower than Magma.
990
991
INPUT:
992
993
- check: if True, performs the same computation in GAP and checks that
994
the number of subgroups generated is the same. (I don't know how to
995
convert GAP's output back into Sage, so we don't actually compare the
996
subgroups).
997
998
ALGORITHM:
999
1000
If the group is cyclic, the problem is easy. Otherwise, write it as
1001
a direct product A x B, where B is cyclic. Compute the subgroups of
1002
A (by recursion).
1003
1004
Now, for every subgroup C of A x B, let G be its *projection onto*
1005
A and H its *intersection with* B. Then there is a well-defined
1006
homomorphism f: G -> B/H that sends a in G to the class mod H of b,
1007
where (a,b) is any element of C lifting a; and every subgroup C
1008
arises from a unique triple (G, H, f).
1009
1010
EXAMPLES::
1011
1012
sage: AbelianGroup([2,3]).subgroups()
1013
[Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
1014
Multiplicative Abelian Group isomorphic to C2 x C3
1015
generated by [f0*f1^2],
1016
Multiplicative Abelian Group isomorphic to C2, which is the subgroup of
1017
Multiplicative Abelian Group isomorphic to C2 x C3
1018
generated by [f0],
1019
Multiplicative Abelian Group isomorphic to C3, which is the subgroup of
1020
Multiplicative Abelian Group isomorphic to C2 x C3
1021
generated by [f1],
1022
Trivial Abelian Group, which is the subgroup of
1023
Multiplicative Abelian Group isomorphic to C2 x C3
1024
generated by []]
1025
1026
sage: len(AbelianGroup([2,4,8]).subgroups())
1027
81
1028
1029
"""
1030
if not self.is_finite(): raise ValueError, "Group must be finite"
1031
from sage.misc.misc import verbose
1032
1033
v = self.invariants()
1034
1035
1036
if len(v) <= 1:
1037
if v == [] or v[0] == 1:
1038
return [self]
1039
else:
1040
return [ self.subgroup([self.gen(0)**i]) for i in divisors(v[0])[:-1]] + [self.subgroup([])]
1041
1042
A = AbelianGroup(v[:-1])
1043
x = v[-1]
1044
1045
Wsubs = A.subgroups()
1046
1047
subgps = []
1048
for G in Wsubs:
1049
verbose("G = subgp generated by %s" % G.gens())
1050
verbose("invariants are:", [t.order() for t in G.gens()]) # G.invariants() doesn't work
1051
for H in divisors(x):
1052
# H = the subgroup of *index* H.
1053
its = [xrange(0, H, H/gcd(H, G.gen(i).order())) for i in xrange(len(G.gens()))]
1054
for f in cartesian_product_iterator(its):
1055
verbose("using hom from G to C_%s sending gens to %s" % (H,f))
1056
new_sub = []
1057
for a in xrange(len(G.gens())):
1058
new_sub.append(G.gen(a).list() + [f[a]])
1059
if H != x:
1060
new_sub.append([0]*A.ngens() + [H])
1061
subgps.append(self.subgroup_reduced(new_sub))
1062
1063
if check:
1064
from sage.interfaces.all import gap
1065
verbose("Running Gap cross-check")
1066
t = ZZ(gap.eval("Size(SubgroupsSolvableGroup(AbelianGroup(%s)))" % v))
1067
if t != len(subgps):
1068
raise ArithmeticError, "For %s Gap finds %s subgroups, I found %s" % (v, t, len(subgps))
1069
verbose("Gap check OK for %s: %s" % (v, t))
1070
return subgps
1071
1072
def subgroup_reduced(self,elts, verbose=False):
1073
r"""
1074
Given a list of lists of integers (corresponding to elements of self),
1075
find a set of independent generators for the subgroup generated by
1076
these elements, and return the subgroup with these as generators,
1077
forgetting the original generators.
1078
1079
This is used by the ``subgroups`` routine.
1080
1081
An error will be raised if the elements given are not linearly
1082
independent over QQ.
1083
1084
EXAMPLE::
1085
1086
sage: G = AbelianGroup([4,4])
1087
sage: G.subgroup( [ G([1,0]), G([1,2]) ])
1088
Multiplicative Abelian Group isomorphic to C2 x C4, which is the subgroup of
1089
Multiplicative Abelian Group isomorphic to C4 x C4
1090
generated by [f0, f0*f1^2]
1091
sage: AbelianGroup([4,4]).subgroup_reduced( [ [1,0], [1,2] ])
1092
Multiplicative Abelian Group isomorphic to C2 x C4, which is the subgroup of
1093
Multiplicative Abelian Group isomorphic to C4 x C4
1094
generated by [f1^2, f0]
1095
"""
1096
from sage.matrix.constructor import matrix
1097
d = self.ngens()
1098
X = ZZ**d
1099
try:
1100
elt_lattice = X.submodule_with_basis(elts)
1101
except ValueError, e:
1102
# can't happen?
1103
print "Vectors not LI: ", elts
1104
raise e
1105
rel_lattice = X.span([X.gen(i) * self.invariants()[i] for i in xrange(d)])
1106
isect = elt_lattice.intersection(rel_lattice)
1107
mat = matrix([elt_lattice.coordinate_vector(x) for x in isect.gens()]).change_ring(ZZ)
1108
D,U,V = mat.smith_form()
1109
new_basis = [(elt_lattice.linear_combination_of_basis((~V).row(i)).list(), D[i,i]) for i in xrange(U.ncols())]
1110
return self.subgroup([self([x[0][i] % self.invariants()[i] for i in xrange(d)]) for x in new_basis if x[1] != 1])
1111
1112
class AbelianGroup_subgroup(AbelianGroup_class):
1113
"""
1114
Subgroup subclass of AbelianGroup_class, so instance methods are
1115
inherited.
1116
1117
TODO:
1118
1119
- There should be a way to coerce an element of a subgroup
1120
into the ambient group.
1121
"""
1122
def __init__(self, ambient, gens, names="f"):
1123
"""
1124
EXAMPLES::
1125
1126
sage: F = AbelianGroup(5,[30,64,729],names = list("abcde"))
1127
sage: a,b,c,d,e = F.gens()
1128
sage: F.subgroup([a^3,b])
1129
Multiplicative Abelian Group isomorphic to Z x Z, which is the subgroup of
1130
Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729
1131
generated by [a^3, b]
1132
1133
::
1134
1135
sage: F.subgroup([c])
1136
Multiplicative Abelian Group isomorphic to C2 x C3 x C5, which is the subgroup of
1137
Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729
1138
generated by [c]
1139
1140
::
1141
1142
sage: F.subgroup([a,c])
1143
Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x
1144
Z, which is the subgroup of Multiplicative Abelian Group
1145
isomorphic to Z x Z x C30 x C64 x C729 generated by [a, c]
1146
1147
::
1148
1149
sage: F.subgroup([a,b*c])
1150
Multiplicative Abelian Group isomorphic to Z x Z, which is
1151
the subgroup of Multiplicative Abelian Group isomorphic to
1152
Z x Z x C30 x C64 x C729 generated by [a, b*c]
1153
1154
::
1155
1156
sage: F.subgroup([b*c,d])
1157
Multiplicative Abelian Group isomorphic to C64 x Z, which
1158
is the subgroup of Multiplicative Abelian Group isomorphic
1159
to Z x Z x C30 x C64 x C729 generated by [b*c, d]
1160
1161
::
1162
1163
sage: F.subgroup([a*b,c^6,d],names = list("xyz"))
1164
Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
1165
which is the subgroup of Multiplicative Abelian Group
1166
isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,
1167
c^6, d]
1168
1169
::
1170
1171
sage: H.<x,y,z> = F.subgroup([a*b, c^6, d]); H
1172
Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
1173
which is the subgroup of Multiplicative Abelian Group
1174
isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,
1175
c^6, d]
1176
1177
::
1178
1179
sage: G = F.subgroup([a*b,c^6,d],names = list("xyz")); G
1180
Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
1181
which is the subgroup of Multiplicative Abelian Group
1182
isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,
1183
c^6, d]
1184
sage: x,y,z = G.gens()
1185
sage: x.order()
1186
+Infinity
1187
sage: y.order()
1188
5
1189
sage: z.order()
1190
64
1191
sage: A = AbelianGroup(5,[3, 5, 5, 7, 8], names = "abcde")
1192
sage: a,b,c,d,e = A.gens()
1193
sage: A.subgroup([a,b])
1194
Multiplicative Abelian Group isomorphic to C3 x C5, which is the subgroup of
1195
Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
1196
generated by [a, b]
1197
sage: A.subgroup([a,b,c,d^2,e])
1198
Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8, which is the subgroup of
1199
Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
1200
generated by [a, b, c, d^2, e]
1201
sage: A.subgroup([a,b,c,d^2,e^2])
1202
Multiplicative Abelian Group isomorphic to C3 x C4 x C5 x C5 x C7, which is the subgroup of
1203
Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
1204
generated by [a, b, c, d^2, e^2]
1205
sage: B = A.subgroup([a^3,b,c,d,e^2]); B
1206
Multiplicative Abelian Group isomorphic to C4 x C5 x C5 x C7, which is the subgroup of
1207
Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
1208
generated by [b, c, d, e^2]
1209
sage: B.invariants()
1210
[4, 5, 5, 7]
1211
sage: A = AbelianGroup(4,[1009, 2003, 3001, 4001], names = "abcd")
1212
sage: a,b,c,d = A.gens()
1213
sage: B = A.subgroup([a^3,b,c,d])
1214
sage: B.invariants()
1215
[1009, 2003, 3001, 4001]
1216
sage: A.order()
1217
24266473210027
1218
sage: B.order()
1219
24266473210027
1220
sage: A = AbelianGroup(4,[1008, 2003, 3001, 4001], names = "abcd")
1221
sage: a,b,c,d = A.gens()
1222
sage: B = A.subgroup([a^3,b,c,d]); B
1223
Multiplicative Abelian Group isomorphic to C3 x C7 x C16 x
1224
C2003 x C3001 x C4001, which is the subgroup of
1225
Multiplicative Abelian Group isomorphic to C1008 x C2003 x
1226
C3001 x C4001 generated by [a^3, b, c, d]
1227
1228
Infinite groups can also be handled::
1229
1230
sage: G = AbelianGroup([3,4,0], names = "abc")
1231
sage: a,b,c = G.gens()
1232
sage: F = G.subgroup([a,b^2,c]); F
1233
Multiplicative Abelian Group isomorphic to C2 x C3 x Z,
1234
which is the subgroup of Multiplicative Abelian Group
1235
isomorphic to C3 x C4 x Z generated by [a, b^2, c]
1236
1237
::
1238
1239
sage: F.invariants()
1240
[2, 3, 0]
1241
sage: F.gens()
1242
[a, b^2, c]
1243
sage: F.order()
1244
+Infinity
1245
"""
1246
from sage.interfaces.all import gap
1247
if not isinstance(ambient, AbelianGroup_class):
1248
raise TypeError, "ambient (=%s) must be an abelian group."%ambient
1249
if not isinstance(gens, list):
1250
raise TypeError, "gens (=%s) must be a list"%gens
1251
1252
self.__ambient_group = ambient
1253
Hgens = [x for x in gens if x != ambient(1)] ## in case someone puts 1 in the list of generators
1254
self.__gens = Hgens
1255
m = len(gens)
1256
ell = len(ambient.gens())
1257
ambient_invs = ambient.invariants()
1258
invsf = [x for x in ambient_invs if x > 0] ## fixes the problem with
1259
invs0 = [x for x in ambient_invs if x == 0] ## the infinite parts
1260
Ggens = list(ambient.variable_names())
1261
if invs0!=[]:
1262
Gfgens = [x for x in ambient.variable_names() if
1263
ambient_invs[Ggens.index(x)] != 0]
1264
Ggens0 = [x for x in ambient.variable_names() if
1265
ambient_invs[Ggens.index(x)] == 0]
1266
## ^^ only look at "finite" names
1267
Gf = AbelianGroup_class(len(invsf), invsf, names = Gfgens)
1268
s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%Gf._gap_init_()
1269
gap.eval(s1)
1270
Hgensf = [x for x in Hgens if len(set(Ggens0).intersection(set(list(str(x)))))==0]
1271
# computes the gens of H which do not occur ^^ in the infinite part of G
1272
Hgens0 = [x for x in Hgens if not(x in Hgensf)]
1273
# the "infinite" generators of H
1274
for i in range(len(Gfgens)):
1275
cmd = ("%s := gens["+str(i+1)+"]")%Gfgens[i]
1276
gap.eval(cmd)
1277
if invs0==[]:
1278
Hgensf = Hgens
1279
Hgens0 = [] # added for consistency
1280
G = ambient
1281
s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%G._gap_init_()
1282
gap.eval(s1)
1283
for i in range(len(Ggens)):
1284
cmd = '%s := gens[%s]'%(Ggens[i], i+1)
1285
#print i," \n",cmd
1286
gap.eval(cmd)
1287
s2 = "gensH:=%s"%Hgensf #### remove from this the ones <--> 0 invar
1288
gap.eval(s2)
1289
s3 = 'H:=Subgroup(G,gensH)'
1290
gap.eval(s3)
1291
# a GAP command which returns the "invariants" of the
1292
# subgroup as an AbelianPcpGroup, RelativeOrdersOfPcp(Pcp(G)),
1293
# works if G is the subgroup declared as a AbelianPcpGroup
1294
self.__abinvs = eval(gap.eval("AbelianInvariants(H)"))
1295
invs = self.__abinvs
1296
#print s3, invs
1297
if Hgens0 != []:
1298
for x in Hgens0:
1299
invs.append(0)
1300
#print Hgensf, invs, invs0
1301
AbelianGroup_class.__init__(self, len(invs), invs, names)
1302
1303
def __contains__(self, x):
1304
"""
1305
Return True if `x` is an element of this subgroup.
1306
1307
EXAMPLES::
1308
1309
sage: G.<a,b> = AbelianGroup(2)
1310
sage: A = G.subgroup([a])
1311
sage: a in G
1312
True
1313
sage: a in A
1314
True
1315
"""
1316
if not isinstance(x, AbelianGroupElement):
1317
return False
1318
if x.parent() is self:
1319
return True
1320
elif x in self.ambient_group():
1321
amb_inv = self.ambient_group().invariants()
1322
for a in xrange(len(amb_inv)):
1323
if amb_inv[a] == 0 and x.list()[a] != 0:
1324
for g in self.__gens:
1325
if g.list()[a] == 0:
1326
continue
1327
if abs(x.list()[a]%g.list()[a]) < abs(x.list()[a]):
1328
if g.list()[a]*x.list()[a] < 0:
1329
x *= g**(x.list()[a]/g.list()[a])
1330
else:
1331
x *= g**((-1)*(x.list()[a]/g.list()[a]))
1332
if x.list()[a] == 0:
1333
break
1334
elif x.list()[a] != 0:
1335
for g in self.__gens:
1336
if g.list()[a] == 0:
1337
continue
1338
if abs(x.list()[a]%g.list()[a])%abs(amb_inv[a]) < x.list()[a]%abs(amb_inv[a]):
1339
x *= g**((-1)*(x.list()[a]/g.list()[a]))
1340
if x.list()[a] == 0:
1341
break
1342
return x == x.parent()(1)
1343
1344
def ambient_group(self):
1345
"""
1346
Return the ambient group related to self.
1347
"""
1348
return self.__ambient_group
1349
1350
def __eq__(self, right):
1351
"""
1352
::
1353
1354
sage: G = AbelianGroup(3, [2,3,4], names="abc"); G
1355
Multiplicative Abelian Group isomorphic to C2 x C3 x C4
1356
sage: a,b,c = G.gens()
1357
sage: F=G.subgroup([a,b^2]); F
1358
Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
1359
Multiplicative Abelian Group isomorphic to C2 x C3 x C4
1360
generated by [a, b^2]
1361
sage: F<G
1362
True
1363
1364
::
1365
1366
sage: A = AbelianGroup(1, [6])
1367
sage: A.subgroup(list(A.gens())) == A
1368
True
1369
1370
::
1371
1372
sage: G.<a,b> = AbelianGroup(2)
1373
sage: A = G.subgroup([a])
1374
sage: B = G.subgroup([b])
1375
sage: A == B
1376
False
1377
"""
1378
if not is_AbelianGroup(right):
1379
return -1
1380
return self <= right and right <= self
1381
1382
def _repr_(self):
1383
return '%s, which is the subgroup of\n%s\ngenerated by %s'%(
1384
AbelianGroup_class._repr_(self),
1385
self.ambient_group(),
1386
self.gens())
1387
1388
def invs(self):
1389
"""
1390
Return the invariants for this subgroup.
1391
"""
1392
G = self.ambient_group()
1393
invsG = G.invariants()
1394
Hgap = self._gap_init_()
1395
1396
1397
def gens(self):
1398
"""
1399
Return the generators for this subgroup.
1400
"""
1401
return self.__gens
1402
1403
def gen(self, n):
1404
"""
1405
Return the nth generator of this subgroup.
1406
1407
EXAMPLE::
1408
1409
sage: G.<a,b> = AbelianGroup(2)
1410
sage: A = G.subgroup([a])
1411
sage: A.gen(0)
1412
a
1413
"""
1414
return self.__gens[n]
1415
1416
1417