Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/groups/perm_gps/permgroup.py
4057 views
1
r"""
2
Permutation groups
3
4
A permutation group is a finite group `G` whose elements are
5
permutations of a given finite set `X` (i.e., bijections
6
`X \longrightarrow X`) and whose group operation is the composition of
7
permutations. The number of elements of `X` is called the degree of `G`.
8
9
In Sage, a permutation is represented as either a string that
10
defines a permutation using disjoint cycle notation, or a list of
11
tuples, which represent disjoint cycles. That is::
12
13
(a,...,b)(c,...,d)...(e,...,f) <--> [(a,...,b), (c,...,d),..., (e,...,f)]
14
() = identity <--> []
15
16
You can make the "named" permutation groups (see
17
``permgp_named.py``) and use the following
18
constructions:
19
20
- permutation group generated by elements,
21
- ``direct_product_permgroups``, which takes a list of permutation
22
groups and returns their direct product.
23
24
JOKE: Q: What's hot, chunky, and acts on a polygon? A: Dihedral
25
soup. Renteln, P. and Dundes, A. "Foolproof: A Sampling of
26
Mathematical Folk Humor." Notices Amer. Math. Soc. 52, 24-34,
27
2005.
28
29
AUTHORS:
30
31
- David Joyner (2005-10-14): first version
32
33
- David Joyner (2005-11-17)
34
35
- William Stein (2005-11-26): rewrite to better wrap Gap
36
37
- David Joyner (2005-12-21)
38
39
- William Stein and David Joyner (2006-01-04): added conjugacy_class_representatives
40
41
- David Joyner (2006-03): reorganization into subdirectory perm_gps;
42
added __contains__, has_element; fixed _cmp_; added subgroup
43
class+methods, PGL,PSL,PSp, PSU classes,
44
45
- David Joyner (2006-06): added PGU, functionality to SymmetricGroup,
46
AlternatingGroup, direct_product_permgroups
47
48
- David Joyner (2006-08): added degree,
49
ramification_module_decomposition_modular_curve and
50
ramification_module_decomposition_hurwitz_curve methods to PSL(2,q),
51
MathieuGroup, is_isomorphic
52
53
- Bobby Moretti (2006)-10): Added KleinFourGroup, fixed bug in DihedralGroup
54
55
- David Joyner (2006-10): added is_subgroup (fixing a bug found by
56
Kiran Kedlaya), is_solvable, normalizer, is_normal_subgroup, Suzuki
57
58
- David Kohel (2007-02): fixed __contains__ to not enumerate group
59
elements, following the convention for __call__
60
61
- David Harvey, Mike Hansen, Nick Alexander, William Stein
62
(2007-02,03,04,05): Various patches
63
64
- Nathan Dunfield (2007-05): added orbits
65
66
- David Joyner (2007-06): added subgroup method (suggested by David
67
Kohel), composition_series, lower_central_series,
68
upper_central_series, cayley_table, quotient_group, sylow_subgroup,
69
is_cyclic, homology, homology_part, cohomology, cohomology_part,
70
poincare_series, molien_series, is_simple, is_monomial,
71
is_supersolvable, is_nilpotent, is_perfect, is_polycyclic,
72
is_elementary_abelian, is_pgroup, gens_small,
73
isomorphism_type_info_simple_group. moved all the"named"
74
groups to a new file.
75
76
- Nick Alexander (2007-07): move is_isomorphic to isomorphism_to, add
77
from_gap_list
78
79
- William Stein (2007-07): put is_isomorphic back (and make it better)
80
81
- David Joyner (2007-08): fixed bugs in composition_series,
82
upper/lower_central_series, derived_series,
83
84
- David Joyner (2008-06): modified is_normal (reported by
85
W. J. Palenstijn), and added normalizes
86
87
- David Joyner (2008-08): Added example to docstring of cohomology.
88
89
- Simon King (2009-04): __cmp__ methods for PermutationGroup_generic and PermutationGroup_subgroup
90
91
- Nicolas Borie (2009): Added orbit, transversals, stabiliser and strong_generating_system methods
92
93
- Christopher Swenson (2012): Added a special case to compute the order efficiently.
94
(This patch Copyright 2012 Google Inc. All Rights Reserved. )
95
96
REFERENCES:
97
98
- Cameron, P., Permutation Groups. New York: Cambridge University
99
Press, 1999.
100
101
- Wielandt, H., Finite Permutation Groups. New York: Academic Press,
102
1964.
103
104
- Dixon, J. and Mortimer, B., Permutation Groups, Springer-Verlag,
105
Berlin/New York, 1996.
106
107
.. note::
108
109
Though Suzuki groups are okay, Ree groups should *not* be wrapped
110
as permutation groups - the construction is too slow - unless (for
111
small values or the parameter) they are made using explicit
112
generators.
113
114
"""
115
116
#*****************************************************************************
117
# Copyright (C) 2006 William Stein <[email protected]>
118
# David Joyner <[email protected]>
119
#
120
# Distributed under the terms of the GNU General Public License (GPL)
121
# http://www.gnu.org/licenses/
122
#*****************************************************************************
123
from functools import wraps
124
125
from sage.misc.randstate import current_randstate
126
import sage.groups.group as group
127
128
from sage.rings.all import QQ, Integer
129
from sage.interfaces.all import is_ExpectElement
130
from sage.interfaces.gap import gap, GapElement
131
from sage.groups.perm_gps.permgroup_element import PermutationGroupElement, standardize_generator
132
from sage.groups.abelian_gps.abelian_group import AbelianGroup
133
from sage.misc.cachefunc import cached_method
134
from sage.groups.class_function import ClassFunction
135
from sage.misc.package import is_package_installed
136
from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
137
from sage.categories.all import FiniteEnumeratedSets
138
from sage.functions.other import factorial
139
140
def load_hap():
141
"""
142
Load the GAP hap package into the default GAP interpreter
143
interface. If this fails, try one more time to load it.
144
145
EXAMPLES::
146
147
sage: sage.groups.perm_gps.permgroup.load_hap()
148
"""
149
try:
150
gap.eval('LoadPackage("hap")')
151
except:
152
gap.eval('LoadPackage("hap")')
153
154
def hap_decorator(f):
155
"""
156
A decorator for permutation group methods that require HAP. It
157
checks to see that HAP is installed as well as checks that the
158
argument ``p`` is either 0 or prime.
159
160
EXAMPLES::
161
162
sage: from sage.groups.perm_gps.permgroup import hap_decorator
163
sage: def foo(self, n, p=0): print "Done"
164
sage: foo = hap_decorator(foo)
165
sage: foo(None, 3) #optional - gap_packages
166
Done
167
sage: foo(None, 3, 0) #optional - gap packages
168
Done
169
sage: foo(None, 3, 5) #optional - gap packages
170
Done
171
sage: foo(None, 3, 4) #optional - gap_packages
172
Traceback (most recent call last):
173
...
174
ValueError: p must be 0 or prime
175
"""
176
@wraps(f)
177
def wrapped(self, n, p=0):
178
if not is_package_installed('gap_packages'):
179
raise RuntimeError, "You must install the optional gap_packages package."
180
load_hap()
181
from sage.rings.arith import is_prime
182
if not (p == 0 or is_prime(p)):
183
raise ValueError, "p must be 0 or prime"
184
185
return f(self, n, p=p)
186
return wrapped
187
188
def direct_product_permgroups(P):
189
"""
190
Takes the direct product of the permutation groups listed in ``P``.
191
192
EXAMPLES::
193
194
sage: G1 = AlternatingGroup([1,2,4,5])
195
sage: G2 = AlternatingGroup([3,4,6,7])
196
sage: D = direct_product_permgroups([G1,G2,G1])
197
sage: D.order()
198
1728
199
sage: D = direct_product_permgroups([G1])
200
sage: D==G1
201
True
202
sage: direct_product_permgroups([])
203
Symmetric group of order 0! as a permutation group
204
"""
205
n = len(P)
206
if n == 0:
207
from sage.groups.perm_gps.permgroup_named import SymmetricGroup
208
return SymmetricGroup(0)
209
elif n == 1:
210
return P[0]
211
else:
212
G = gap.DirectProduct(*P)
213
return PermutationGroup(gap_group=G)
214
215
def from_gap_list(G, src):
216
r"""
217
Convert a string giving a list of GAP permutations into a list of
218
elements of ``G``.
219
220
EXAMPLES::
221
222
sage: from sage.groups.perm_gps.permgroup import from_gap_list
223
sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])
224
sage: L = from_gap_list(G, "[(1,2,3)(4,5), (3,4)]"); L
225
[(1,2,3)(4,5), (3,4)]
226
sage: L[0].parent() is G
227
True
228
sage: L[1].parent() is G
229
True
230
"""
231
# trim away the list constructs
232
src = src.replace("[", "").replace("]", "")
233
# cut out the individual elements
234
srcs = src.split("),")
235
for i in range(len(srcs[:-1])):
236
srcs[i] = srcs[i] + ")"
237
srcs = map(G, srcs)
238
return srcs
239
240
def PermutationGroup(gens=None, gap_group=None, domain=None, canonicalize=True, category=None):
241
"""
242
Return the permutation group associated to `x` (typically a
243
list of generators).
244
245
INPUT:
246
247
248
- ``gens`` - list of generators (default: ``None``)
249
250
- ``gap_group`` - a gap permutation group (default: ``None``)
251
252
- ``canonicalize`` - bool (default: ``True``); if ``True``,
253
sort generators and remove duplicates
254
255
256
OUTPUT:
257
258
- A permutation group.
259
260
EXAMPLES::
261
262
sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])
263
sage: G
264
Permutation Group with generators [(3,4), (1,2,3)(4,5)]
265
266
We can also make permutation groups from PARI groups::
267
268
sage: H = pari('x^4 - 2*x^3 - 2*x + 1').polgalois()
269
sage: G = PariGroup(H, 4); G
270
PARI group [8, -1, 3, "D(4)"] of degree 4
271
sage: H = PermutationGroup(G); H # optional - database_gap
272
Transitive group number 3 of degree 4
273
sage: H.gens() # optional - database_gap
274
[(1,2,3,4), (1,3)]
275
276
We can also create permutation groups whose generators are Gap
277
permutation objects::
278
279
sage: p = gap('(1,2)(3,7)(4,6)(5,8)'); p
280
(1,2)(3,7)(4,6)(5,8)
281
sage: PermutationGroup([p])
282
Permutation Group with generators [(1,2)(3,7)(4,6)(5,8)]
283
284
There is an underlying gap object that implements each
285
permutation group::
286
287
sage: G = PermutationGroup([[(1,2,3,4)]])
288
sage: G._gap_()
289
Group( [ (1,2,3,4) ] )
290
sage: gap(G)
291
Group( [ (1,2,3,4) ] )
292
sage: gap(G) is G._gap_()
293
True
294
sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])
295
sage: current_randstate().set_seed_gap()
296
sage: G._gap_().DerivedSeries()
297
[ Group( [ (3,4), (1,2,3)(4,5) ] ), Group( [ (1,5)(3,4), (1,5)(2,4), (1,5,3) ] ) ]
298
299
TESTS::
300
301
sage: r = Permutation("(1,7,9,3)(2,4,8,6)")
302
sage: f = Permutation("(1,3)(4,6)(7,9)")
303
sage: PermutationGroup([r,f]) #See Trac #12597
304
Permutation Group with generators [(1,3)(4,6)(7,9), (1,7,9,3)(2,4,8,6)]
305
306
sage: PermutationGroup(SymmetricGroup(5))
307
Traceback (most recent call last):
308
...
309
TypeError: gens must be a tuple, list, or GapElement
310
"""
311
if not is_ExpectElement(gens) and hasattr(gens, '_permgroup_'):
312
return gens._permgroup_()
313
if gens is not None and not isinstance(gens, (tuple, list, GapElement)):
314
raise TypeError, "gens must be a tuple, list, or GapElement"
315
return PermutationGroup_generic(gens=gens, gap_group=gap_group, domain=domain,
316
canonicalize=canonicalize, category=category)
317
318
319
class PermutationGroup_generic(group.Group):
320
"""
321
EXAMPLES::
322
323
sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])
324
sage: G
325
Permutation Group with generators [(3,4), (1,2,3)(4,5)]
326
sage: G.center()
327
Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()]
328
sage: G.group_id() # optional - database_gap
329
[120, 34]
330
sage: n = G.order(); n
331
120
332
sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])
333
sage: TestSuite(G).run()
334
"""
335
def __init__(self, gens=None, gap_group=None, canonicalize=True, domain=None, category=None):
336
r"""
337
INPUT:
338
339
340
- ``gens`` - list of generators (default: ``None``)
341
342
- ``gap_group`` - a gap permutation group (default: ``None``)
343
344
- ``canonicalize`` - bool (default: ``True``); if ``True``,
345
sort generators and remove duplicates
346
347
348
OUTPUT:
349
350
- A permutation group.
351
352
EXAMPLES:
353
354
We explicitly construct the alternating group on four
355
elements::
356
357
sage: A4 = PermutationGroup([[(1,2,3)],[(2,3,4)]]); A4
358
Permutation Group with generators [(2,3,4), (1,2,3)]
359
sage: A4.__init__([[(1,2,3)],[(2,3,4)]]); A4
360
Permutation Group with generators [(2,3,4), (1,2,3)]
361
sage: A4.center()
362
Subgroup of (Permutation Group with generators [(2,3,4), (1,2,3)]) generated by [()]
363
sage: A4.category()
364
Category of finite permutation groups
365
sage: TestSuite(A4).run()
366
367
TESTS::
368
369
sage: TestSuite(PermutationGroup([[]])).run()
370
sage: TestSuite(PermutationGroup([])).run()
371
"""
372
from sage.categories.finite_permutation_groups import FinitePermutationGroups
373
super(PermutationGroup_generic, self).__init__(category = FinitePermutationGroups().or_subcategory(category))
374
if (gens is None and gap_group is None):
375
raise ValueError, "you must specify gens or gap_group"
376
377
#Handle the case where only the GAP group is specified.
378
if gens is None:
379
if isinstance(gap_group, str):
380
gap_group = gap(gap_group)
381
gens = [gen for gen in gap_group.GeneratorsOfGroup()]
382
383
if domain is None:
384
gens = [standardize_generator(x) for x in gens]
385
domain = set()
386
for x in gens:
387
for cycle in x:
388
domain = domain.union(cycle)
389
domain = sorted(domain)
390
391
#Here we need to check if all of the points are integers
392
#to make the domain contain all integers up to the max.
393
#This is needed for backward compatibility
394
if all(isinstance(p, (Integer, int, long)) for p in domain):
395
domain = range(1, max([1] + domain)+1)
396
397
if domain not in FiniteEnumeratedSets():
398
domain = FiniteEnumeratedSet(domain)
399
400
self._domain = domain
401
self._deg = len(self._domain)
402
self._domain_to_gap = dict((key, i+1) for i, key in enumerate(self._domain))
403
self._domain_from_gap = dict((i+1, key) for i, key in enumerate(self._domain))
404
405
if not gens: # length 0
406
gens = [()]
407
gens = [self._element_class()(x, self, check=False) for x in gens]
408
if canonicalize:
409
gens = sorted(set(gens))
410
self._gens = gens
411
412
def construction(self):
413
"""
414
EXAMPLES::
415
416
sage: P1 = PermutationGroup([[(1,2)]])
417
sage: P1.construction()
418
(PermutationGroupFunctor[(1,2)], Permutation Group with generators [()])
419
420
sage: PermutationGroup([]).construction() is None
421
True
422
423
This allows us to perform computations like the following::
424
425
sage: P1 = PermutationGroup([[(1,2)]]); p1 = P1.gen()
426
sage: P2 = PermutationGroup([[(1,3)]]); p2 = P2.gen()
427
sage: p = p1*p2; p
428
(1,2,3)
429
sage: p.parent()
430
Permutation Group with generators [(1,2), (1,3)]
431
sage: p.parent().domain()
432
{1, 2, 3}
433
434
Note that this will merge permutation groups with different
435
domains::
436
437
sage: g1 = PermutationGroupElement([(1,2),(3,4,5)])
438
sage: g2 = PermutationGroup([('a','b')], domain=['a', 'b']).gens()[0]
439
sage: g2
440
('a','b')
441
sage: p = g1*g2; p
442
(1,2)(3,4,5)('a','b')
443
"""
444
gens = self.gens()
445
if len(gens) == 1 and gens[0].is_one():
446
return None
447
else:
448
from sage.categories.pushout import PermutationGroupFunctor
449
return (PermutationGroupFunctor(gens, self.domain()),
450
PermutationGroup([]))
451
452
@cached_method
453
def _has_natural_domain(self):
454
"""
455
Returns True if the underlying domain is of the form (1,...,n)
456
457
EXAMPLES::
458
459
sage: SymmetricGroup(3)._has_natural_domain()
460
True
461
sage: SymmetricGroup((1,2,3))._has_natural_domain()
462
True
463
sage: SymmetricGroup((1,3))._has_natural_domain()
464
False
465
sage: SymmetricGroup((3,2,1))._has_natural_domain()
466
False
467
"""
468
domain = self.domain()
469
natural_domain = FiniteEnumeratedSet(range(1, len(domain)+1))
470
return domain == natural_domain
471
472
def _gap_init_(self):
473
r"""
474
Returns a string showing how to declare / initialize ``self`` in Gap.
475
Stored in the ``self._gap_string`` attribute.
476
477
EXAMPLES:
478
479
The ``_gap_init_`` method shows how you
480
would define the Sage ``PermutationGroup_generic``
481
object in Gap::
482
483
sage: A4 = PermutationGroup([[(1,2,3)],[(2,3,4)]]); A4
484
Permutation Group with generators [(2,3,4), (1,2,3)]
485
sage: A4._gap_init_()
486
'Group([PermList([1, 3, 4, 2]), PermList([2, 3, 1, 4])])'
487
"""
488
return 'Group([%s])'%(', '.join([g._gap_init_() for g in self.gens()]))
489
490
def _magma_init_(self, magma):
491
r"""
492
Returns a string showing how to declare / initialize self in Magma.
493
494
EXAMPLES:
495
496
We explicitly construct the alternating group on four
497
elements. In Magma, one would type the string below to construct
498
the group::
499
500
sage: A4 = PermutationGroup([[(1,2,3)],[(2,3,4)]]); A4
501
Permutation Group with generators [(2,3,4), (1,2,3)]
502
sage: A4._magma_init_(magma)
503
'PermutationGroup<4 | (2,3,4), (1,2,3)>'
504
505
sage: S = SymmetricGroup(['a', 'b', 'c'])
506
sage: S._magma_init_(magma)
507
'PermutationGroup<3 | (1,2,3), (1,2)>'
508
"""
509
g = ', '.join([g._gap_cycle_string() for g in self.gens()])
510
return 'PermutationGroup<%s | %s>'%(self.degree(), g)
511
512
def __cmp__(self, right):
513
"""
514
Compare ``self`` and ``right``.
515
516
The comparison extends the subgroup relation. Hence, it is first checked
517
whether one of the groups is subgroup of the other. If this is not the
518
case then the ordering is whatever it is in Gap.
519
520
NOTE:
521
The comparison does not provide a total ordering, as can be seen
522
in the examples below.
523
524
EXAMPLES::
525
526
sage: G1 = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])
527
sage: G2 = PermutationGroup([[(1,2,3),(4,5)]])
528
sage: G1 > G2 # since G2 is a subgroup of G1
529
True
530
sage: G1 < G2
531
False
532
533
The following example shows that the comparison does not yield a total
534
ordering::
535
536
sage: H1 = PermutationGroup([[(1,2)],[(5,6)]])
537
sage: H2 = PermutationGroup([[(3,4)]])
538
sage: H3 = PermutationGroup([[(1,2)]])
539
sage: H1 < H2 # according to Gap's ordering
540
True
541
sage: H2 < H3 # according to Gap's ordering
542
True
543
sage: H3 < H1 # since H3 is a subgroup of H1
544
True
545
"""
546
if (not isinstance(right, PermutationGroup_generic) or
547
self.domain() != right.domain()):
548
return -1
549
if self is right:
550
return 0
551
gSelf = self._gap_()
552
gRight = right._gap_()
553
gapcmp = gSelf.__cmp__(gRight)
554
if not gapcmp:
555
return 0
556
if gSelf.IsSubgroup(gRight):
557
return 1
558
if gRight.IsSubgroup(gSelf):
559
return -1
560
return gapcmp
561
562
def _element_class(self):
563
r"""
564
Return the class to be used for creating elements of this group. By
565
default this is
566
``sage.groups.perm_gps.permgroup_element.PermutationGroupElement``, but
567
it may be overridden in derived subclasses (most importantly
568
``sage.rings.number_field.galois_group.GaloisGroup_v2``).
569
570
EXAMPLE::
571
572
sage: SymmetricGroup(17)._element_class()
573
<type 'sage.groups.perm_gps.permgroup_element.PermutationGroupElement'>
574
"""
575
return PermutationGroupElement
576
577
def __call__(self, x, check=True):
578
"""
579
Coerce ``x`` into this permutation group.
580
581
The input can be either a string that defines a permutation in
582
cycle notation, a permutation group element, a list of integers
583
that gives the permutation as a mapping, a list of tuples, or the
584
integer 1.
585
586
EXAMPLES:
587
588
We illustrate each way to make a permutation in `S_4`::
589
590
sage: G = SymmetricGroup(4)
591
sage: G((1,2,3,4))
592
(1,2,3,4)
593
sage: G([(1,2),(3,4)])
594
(1,2)(3,4)
595
sage: G('(1,2)(3,4)')
596
(1,2)(3,4)
597
sage: G('(1,2)(3)(4)')
598
(1,2)
599
sage: G(((1,2,3),(4,)))
600
(1,2,3)
601
sage: G(((1,2,3,4),))
602
(1,2,3,4)
603
sage: G([1,2,4,3])
604
(3,4)
605
sage: G([2,3,4,1])
606
(1,2,3,4)
607
sage: G(G((1,2,3,4)))
608
(1,2,3,4)
609
sage: G(1)
610
()
611
612
Some more examples::
613
614
sage: G = PermutationGroup([(1,2,3,4)])
615
sage: G([(1,3), (2,4)])
616
(1,3)(2,4)
617
sage: G(G.0^3)
618
(1,4,3,2)
619
sage: G(1)
620
()
621
sage: G((1,4,3,2))
622
(1,4,3,2)
623
sage: G([(1,2)])
624
Traceback (most recent call last):
625
...
626
TypeError: permutation [(1, 2)] not in Permutation Group with generators [(1,2,3,4)]
627
"""
628
try:
629
if x.parent() is self:
630
return x
631
except AttributeError:
632
pass
633
634
if isinstance(x, (int, long, Integer)) and x == 1:
635
return self.identity()
636
637
return self._element_class()(x, self, check=check)
638
639
def _coerce_impl(self, x):
640
r"""
641
Implicit coercion of ``x`` into ``self``.
642
643
EXAMPLES:
644
645
We illustrate some arithmetic that involves implicit
646
coercion of elements in different permutation groups::
647
648
sage: g1 = PermutationGroupElement([(1,2),(3,4,5)])
649
sage: g1.parent()
650
Symmetric group of order 5! as a permutation group
651
sage: g2 = PermutationGroupElement([(1,2)])
652
sage: g2.parent()
653
Symmetric group of order 2! as a permutation group
654
sage: g1*g2
655
(3,4,5)
656
sage: g2*g2
657
()
658
sage: g2*g1
659
(3,4,5)
660
661
We try to implicitly coerce in a non-permutation, which raises a
662
TypeError::
663
664
sage: G = PermutationGroup([[(1,2,3,4)], [(1,2)]])
665
sage: G._coerce_impl(1)
666
Traceback (most recent call last):
667
...
668
TypeError: no implicit coercion of element into permutation group
669
"""
670
from permgroup_named import SymmetricGroup
671
if isinstance(x, PermutationGroupElement):
672
x_parent = x.parent()
673
if x_parent is self:
674
return x
675
676
compatible_domains = all(point in self._domain_to_gap for point in x_parent.domain())
677
if compatible_domains and (self.__class__ == SymmetricGroup or x._gap_() in self._gap_()):
678
return self._element_class()(x.cycle_tuples(), self, check=False)
679
raise TypeError, "no implicit coercion of element into permutation group"
680
681
@cached_method
682
def list(self):
683
"""
684
Return list of all elements of this group.
685
686
EXAMPLES::
687
688
sage: G = PermutationGroup([[(1,2,3,4)], [(1,2)]])
689
sage: G.list()
690
[(), (3,4), (2,3), (2,3,4), (2,4,3), (2,4), (1,2), (1,2)(3,4), (1,2,3), (1,2,3,4), (1,2,4,3), (1,2,4), (1,3,2), (1,3,4,2), (1,3), (1,3,4), (1,3)(2,4), (1,3,2,4), (1,4,3,2), (1,4,2), (1,4,3), (1,4), (1,4,2,3), (1,4)(2,3)]
691
692
sage: G = PermutationGroup([[('a','b')]], domain=('a', 'b')); G
693
Permutation Group with generators [('a','b')]
694
sage: G.list()
695
[(), ('a','b')]
696
"""
697
return list(self.__iter__())
698
699
def __contains__(self, item):
700
"""
701
Returns boolean value of ``item in self``.
702
703
EXAMPLES::
704
705
sage: G = SymmetricGroup(16)
706
sage: g = G.gen(0)
707
sage: h = G.gen(1)
708
sage: g^7*h*g*h in G
709
True
710
sage: G = SymmetricGroup(4)
711
sage: g = G((1,2,3,4))
712
sage: h = G((1,2))
713
sage: H = PermutationGroup([[(1,2,3,4)], [(1,2),(3,4)]])
714
sage: g in H
715
True
716
sage: h in H
717
False
718
719
sage: G = PermutationGroup([[('a','b')]], domain=('a', 'b'))
720
sage: [('a', 'b')] in G
721
True
722
"""
723
try:
724
item = self(item, check=True)
725
except:
726
return False
727
return True
728
729
730
def has_element(self, item):
731
"""
732
Returns boolean value of ``item in self`` - however *ignores*
733
parentage.
734
735
EXAMPLES::
736
737
sage: G = CyclicPermutationGroup(4)
738
sage: gens = G.gens()
739
sage: H = DihedralGroup(4)
740
sage: g = G([(1,2,3,4)]); g
741
(1,2,3,4)
742
sage: G.has_element(g)
743
True
744
sage: h = H([(1,2),(3,4)]); h
745
(1,2)(3,4)
746
sage: G.has_element(h)
747
False
748
"""
749
return item in self
750
751
def __iter__(self):
752
"""
753
Return an iterator over the elements of this group.
754
755
EXAMPLES::
756
757
sage: G = PermutationGroup([[(1,2,3)], [(1,2)]])
758
sage: [a for a in G]
759
[(), (2,3), (1,2), (1,2,3), (1,3,2), (1,3)]
760
"""
761
for g in self._gap_().Elements():
762
yield self._element_class()(g, self, check=False)
763
764
def gens(self):
765
"""
766
Return tuple of generators of this group. These need not be
767
minimal, as they are the generators used in defining this group.
768
769
EXAMPLES::
770
771
sage: G = PermutationGroup([[(1,2,3)], [(1,2)]])
772
sage: G.gens()
773
[(1,2), (1,2,3)]
774
775
Note that the generators need not be minimal, though duplicates are
776
removed::
777
778
sage: G = PermutationGroup([[(1,2)], [(1,3)], [(2,3)], [(1,2)]])
779
sage: G.gens()
780
[(2,3), (1,2), (1,3)]
781
782
We can use index notation to access the generators returned by
783
``self.gens``::
784
785
sage: G = PermutationGroup([[(1,2,3,4), (5,6)], [(1,2)]])
786
sage: g = G.gens()
787
sage: g[0]
788
(1,2)
789
sage: g[1]
790
(1,2,3,4)(5,6)
791
792
TESTS:
793
794
We make sure that the trivial group gets handled correctly::
795
796
sage: SymmetricGroup(1).gens()
797
[()]
798
"""
799
return self._gens
800
801
802
def gens_small(self):
803
"""
804
For this group, returns a generating set which has few elements.
805
As neither irredundancy nor minimal length is proven, it is fast.
806
807
EXAMPLES::
808
809
sage: R = "(25,27,32,30)(26,29,31,28)( 3,38,43,19)( 5,36,45,21)( 8,33,48,24)" ## R = right
810
sage: U = "( 1, 3, 8, 6)( 2, 5, 7, 4)( 9,33,25,17)(10,34,26,18)(11,35,27,19)" ## U = top
811
sage: L = "( 9,11,16,14)(10,13,15,12)( 1,17,41,40)( 4,20,44,37)( 6,22,46,35)" ## L = left
812
sage: F = "(17,19,24,22)(18,21,23,20)( 6,25,43,16)( 7,28,42,13)( 8,30,41,11)" ## F = front
813
sage: B = "(33,35,40,38)(34,37,39,36)( 3, 9,46,32)( 2,12,47,29)( 1,14,48,27)" ## B = back or rear
814
sage: D = "(41,43,48,46)(42,45,47,44)(14,22,30,38)(15,23,31,39)(16,24,32,40)" ## D = down or bottom
815
sage: G = PermutationGroup([R,L,U,F,B,D])
816
sage: len(G.gens_small())
817
2
818
819
The output may be unpredictable, due to the use of randomized
820
algorithms in GAP. Note that both the following answers are equally valid.
821
822
::
823
824
sage: G = PermutationGroup([[('a','b')], [('b', 'c')], [('a', 'c')]])
825
sage: G.gens_small() # random
826
[('b','c'), ('a','c','b')] ## (on 64-bit Linux)
827
[('a','b'), ('a','c','b')] ## (on Solaris)
828
sage: len(G.gens_small()) == 2
829
True
830
"""
831
gens = self._gap_().SmallGeneratingSet()
832
return [self._element_class()(x, self, check=False) for x in gens]
833
834
def gen(self, i=None):
835
r"""
836
Returns the i-th generator of ``self``; that is, the i-th element of
837
the list ``self.gens()``.
838
839
The argument `i` may be omitted if there is only one generator (but
840
this will raise an error otherwise).
841
842
EXAMPLES:
843
844
We explicitly construct the alternating group on four
845
elements::
846
847
sage: A4 = PermutationGroup([[(1,2,3)],[(2,3,4)]]); A4
848
Permutation Group with generators [(2,3,4), (1,2,3)]
849
sage: A4.gens()
850
[(2,3,4), (1,2,3)]
851
sage: A4.gen(0)
852
(2,3,4)
853
sage: A4.gen(1)
854
(1,2,3)
855
sage: A4.gens()[0]; A4.gens()[1]
856
(2,3,4)
857
(1,2,3)
858
859
sage: P1 = PermutationGroup([[(1,2)]]); P1.gen()
860
(1,2)
861
"""
862
gens = self.gens()
863
if i is None:
864
if len(gens) == 1:
865
return gens[0]
866
else:
867
raise ValueError, "You must specify which generator you want"
868
else:
869
return gens[i]
870
871
def identity(self):
872
"""
873
Return the identity element of this group.
874
875
EXAMPLES::
876
877
sage: G = PermutationGroup([[(1,2,3),(4,5)]])
878
sage: e = G.identity()
879
sage: e
880
()
881
sage: g = G.gen(0)
882
sage: g*e
883
(1,2,3)(4,5)
884
sage: e*g
885
(1,2,3)(4,5)
886
887
sage: S = SymmetricGroup(['a','b','c'])
888
sage: S.identity()
889
()
890
"""
891
return self._element_class()([], self, check=True)
892
893
def exponent(self):
894
"""
895
Computes the exponent of the group. The exponent `e` of a
896
group `G` is the LCM of the orders of its elements, that
897
is, `e` is the smallest integer such that `g^e=1`
898
for all `g \in G`.
899
900
EXAMPLES::
901
902
sage: G = AlternatingGroup(4)
903
sage: G.exponent()
904
6
905
"""
906
return Integer(self._gap_().Exponent())
907
908
def largest_moved_point(self):
909
"""
910
Return the largest point moved by a permutation in this group.
911
912
EXAMPLES::
913
914
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]])
915
sage: G.largest_moved_point()
916
4
917
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
918
sage: G.largest_moved_point()
919
10
920
921
::
922
923
sage: G = PermutationGroup([[('a','b','c'),('d','e')]])
924
sage: G.largest_moved_point()
925
'e'
926
927
.. warning::
928
929
The name of this function is not good; this function
930
should be deprecated in term of degree::
931
932
sage: P = PermutationGroup([[1,2,3,4]])
933
sage: P.largest_moved_point()
934
4
935
sage: P.cardinality()
936
1
937
"""
938
try:
939
return self._domain_from_gap[Integer(self._gap_().LargestMovedPoint())]
940
except KeyError:
941
return self.degree()
942
943
def degree(self):
944
"""
945
Returns the degree of this permutation group.
946
947
EXAMPLES::
948
949
sage: S = SymmetricGroup(['a','b','c'])
950
sage: S.degree()
951
3
952
sage: G = PermutationGroup([(1,3),(4,5)])
953
sage: G.degree()
954
5
955
956
Note that you can explicitly specify the domain to get a
957
permutation group of smaller degree::
958
959
sage: G = PermutationGroup([(1,3),(4,5)], domain=[1,3,4,5])
960
sage: G.degree()
961
4
962
"""
963
return Integer(len(self._domain))
964
965
def domain(self):
966
r"""
967
Returns the underlying set that this permutation group acts
968
on.
969
970
EXAMPLES::
971
972
sage: P = PermutationGroup([(1,2),(3,5)])
973
sage: P.domain()
974
{1, 2, 3, 4, 5}
975
sage: S = SymmetricGroup(['a', 'b', 'c'])
976
sage: S.domain()
977
{'a', 'b', 'c'}
978
"""
979
return self._domain
980
981
def _domain_gap(self, domain=None):
982
"""
983
Returns a GAP string representation of the underlying set
984
that this group acts on. See also :meth:`domain`.
985
986
EXAMPLES::
987
988
sage: P = PermutationGroup([(1,2),(3,5)])
989
sage: P._domain_gap()
990
'[1, 2, 3, 4, 5]'
991
"""
992
if domain is None:
993
return repr(range(1, self.degree()+1))
994
else:
995
try:
996
return repr([self._domain_to_gap[point] for point in domain])
997
except KeyError:
998
raise ValueError, "domain must be a subdomain of self.domain()"
999
1000
@cached_method
1001
def smallest_moved_point(self):
1002
"""
1003
Return the smallest point moved by a permutation in this group.
1004
1005
EXAMPLES::
1006
1007
sage: G = PermutationGroup([[(3,4)], [(2,3,4)]])
1008
sage: G.smallest_moved_point()
1009
2
1010
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
1011
sage: G.smallest_moved_point()
1012
1
1013
1014
Note that this function uses the ordering from the domain::
1015
1016
sage: S = SymmetricGroup(['a','b','c'])
1017
sage: S.smallest_moved_point()
1018
'a'
1019
"""
1020
return self._domain_from_gap[Integer(self._gap_().SmallestMovedPoint())]
1021
1022
@cached_method
1023
def orbits(self):
1024
"""
1025
Returns the orbits of the elements of the domain under the
1026
group action.
1027
1028
EXAMPLES::
1029
1030
sage: G = PermutationGroup([ [(3,4)], [(1,3)] ])
1031
sage: G.orbits()
1032
[[1, 3, 4], [2]]
1033
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
1034
sage: G.orbits()
1035
[[1, 2, 3, 4, 10], [5], [6], [7], [8], [9]]
1036
1037
sage: G = PermutationGroup([ [('c','d')], [('a','c')],[('b',)]])
1038
sage: G.orbits()
1039
[['a', 'c', 'd'], ['b']]
1040
1041
The answer is cached::
1042
1043
sage: G.orbits() is G.orbits()
1044
True
1045
1046
AUTHORS:
1047
1048
- Nathan Dunfield
1049
"""
1050
return [[self._domain_from_gap[x] for x in orbit] for orbit in
1051
self._gap_().Orbits(self._domain_gap()).sage()]
1052
1053
@cached_method
1054
def orbit(self, point):
1055
"""
1056
Return the orbit of the given point under the group action.
1057
1058
EXAMPLES::
1059
1060
sage: G = PermutationGroup([ [(3,4)], [(1,3)] ])
1061
sage: G.orbit(3)
1062
[3, 4, 1]
1063
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
1064
sage: G.orbit(3)
1065
[3, 4, 10, 1, 2]
1066
1067
sage: G = PermutationGroup([ [('c','d')], [('a','c')] ])
1068
sage: G.orbit('a')
1069
['a', 'c', 'd']
1070
"""
1071
point = self._domain_to_gap[point]
1072
return [self._domain_from_gap[x] for x in self._gap_().Orbit(point).sage()]
1073
1074
def transversals(self, point):
1075
"""
1076
If G is a permutation group acting on the set `X = \{1, 2, ...., n\}`
1077
and H is the stabilizer subgroup of <integer>, a right
1078
(respectively left) transversal is a set containing exactly
1079
one element from each right (respectively left) coset of H. This
1080
method returns a right transversal of ``self`` by the stabilizer
1081
of ``self`` on <integer> position.
1082
1083
EXAMPLES::
1084
1085
sage: G = PermutationGroup([ [(3,4)], [(1,3)] ])
1086
sage: G.transversals(1)
1087
[(), (1,3,4), (1,4,3)]
1088
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
1089
sage: G.transversals(1)
1090
[(), (1,2)(3,4), (1,3,2,10,4), (1,4,2,10,3), (1,10,4,3,2)]
1091
1092
sage: G = PermutationGroup([ [('c','d')], [('a','c')] ])
1093
sage: G.transversals('a')
1094
[(), ('a','c','d'), ('a','d','c')]
1095
"""
1096
G = self._gap_()
1097
return [self(G.RepresentativeAction(self._domain_to_gap[point], self._domain_to_gap[i]))
1098
for i in self.orbit(point)]
1099
1100
def stabilizer(self, point):
1101
"""
1102
Return the subgroup of ``self`` which stabilize the given position.
1103
``self`` and its stabilizers must have same degree.
1104
1105
EXAMPLES::
1106
1107
sage: G = PermutationGroup([ [(3,4)], [(1,3)] ])
1108
sage: G.stabilizer(1)
1109
Subgroup of (Permutation Group with generators [(3,4), (1,3)]) generated by [(3,4)]
1110
sage: G.stabilizer(3)
1111
Subgroup of (Permutation Group with generators [(3,4), (1,3)]) generated by [(1,4)]
1112
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
1113
sage: G.stabilizer(10)
1114
Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) generated by [(2,3,4), (1,2)(3,4)]
1115
sage: G.stabilizer(1)
1116
Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) generated by [(2,3)(4,10), (2,10,4)]
1117
sage: G = PermutationGroup([[(2,3,4)],[(6,7)]])
1118
sage: G.stabilizer(1)
1119
Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7), (2,3,4)]
1120
sage: G.stabilizer(2)
1121
Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7)]
1122
sage: G.stabilizer(3)
1123
Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7)]
1124
sage: G.stabilizer(4)
1125
Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7)]
1126
sage: G.stabilizer(5)
1127
Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7), (2,3,4)]
1128
sage: G.stabilizer(6)
1129
Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(2,3,4)]
1130
sage: G.stabilizer(7)
1131
Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(2,3,4)]
1132
sage: G.stabilizer(8)
1133
Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7), (2,3,4)]
1134
"""
1135
try:
1136
position = self._domain_to_gap[point]
1137
except KeyError:
1138
return self.subgroup(gens=self.gens())
1139
return self.subgroup(gap_group=gap.Stabilizer(self, point))
1140
1141
def base(self, seed=None):
1142
r"""
1143
Returns a (minimum) base of this permutation group. A base $B$
1144
of a permutation group is a subset of the domain of the group
1145
such that the only group element stabilizing all of $B$ is the
1146
identity.
1147
1148
The argument `seed` is optional and must be a subset of the domain
1149
of `base`. When used, an attempt to create a base containing all or part
1150
of `seed` will be made.
1151
1152
EXAMPLES::
1153
1154
sage: G = PermutationGroup([(1,2,3),(6,7,8)])
1155
sage: G.base()
1156
[1, 6]
1157
sage: G.base([2])
1158
[2, 6]
1159
1160
sage: H = PermutationGroup([('a','b','c'),('a','y')])
1161
sage: H.base()
1162
['a', 'b', 'c']
1163
1164
sage: S = SymmetricGroup(13)
1165
sage: S.base()
1166
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
1167
1168
sage: S = MathieuGroup(12)
1169
sage: S.base()
1170
[1, 2, 3, 4, 5]
1171
sage: S.base([1,3,5,7,9,11]) # create a base for M12 with only odd integers
1172
[1, 3, 5, 7, 9]
1173
"""
1174
if seed is None:
1175
seed = self.domain()
1176
1177
try:
1178
seed = [self._domain_to_gap[point] for point in seed]
1179
except KeyError:
1180
raise ValueError, "seed must be a subset of self.domain()"
1181
1182
return [self._domain_from_gap[x] for x in self._gap_().StabChain(seed).BaseStabChain().sage()]
1183
1184
def strong_generating_system(self, base_of_group=None):
1185
"""
1186
Return a Strong Generating System of ``self`` according the given
1187
base for the right action of ``self`` on itself.
1188
1189
``base_of_group`` is a list of the positions on which ``self`` acts,
1190
in any order. The algorithm returns a list of transversals and each
1191
transversal is a list of permutations. By default, ``base_of_group``
1192
is ``[1, 2, 3, ..., d]`` where `d` is the degree of the group.
1193
1194
For ``base_of_group`` =
1195
`[ \mathrm{pos}_1, \mathrm{pos}_2, \dots , \mathrm{pos}_d]`
1196
let `G_i` be the subgroup of `G` = ``self`` which stabilizes
1197
`\mathrm{pos}_1, \mathrm{pos}_2, \dots , \mathrm{pos}_i`, so
1198
1199
.. math::
1200
1201
G = G_0 \supset G_1 \supset G_2 \supset \dots \supset G_n = \{e\}
1202
1203
Then the algorithm returns `[ G_i.\mathrm{transversals}(\mathrm{pos}_{i+1})]_{1 \leq i \leq n}`
1204
1205
INPUT:
1206
1207
- ``base_of_group`` (optional) -- default: ``[1, 2, 3, ..., d]``
1208
-- a list containing the integers
1209
`1, 2, \dots , d` in any order (`d` is the degree of ``self``)
1210
1211
OUTPUT:
1212
1213
- A list of lists of permutations from the group, which form a strong
1214
generating system.
1215
1216
TESTS::
1217
1218
sage: G = SymmetricGroup(10)
1219
sage: H = PermutationGroup([G.random_element() for i in range(randrange(1,3,1))])
1220
sage: prod(map(lambda x : len(x), H.strong_generating_system()),1) == H.cardinality()
1221
True
1222
1223
EXAMPLES::
1224
1225
sage: G = PermutationGroup([[(7,8)],[(3,4)],[(4,5)]])
1226
sage: G.strong_generating_system()
1227
[[()], [()], [(), (3,4,5), (3,5)], [(), (4,5)], [()], [()], [(), (7,8)], [()]]
1228
sage: G = PermutationGroup([[(1,2,3,4)],[(1,2)]])
1229
sage: G.strong_generating_system()
1230
[[(), (1,2)(3,4), (1,3)(2,4), (1,4)(2,3)], [(), (2,3,4), (2,4,3)], [(), (3,4)], [()]]
1231
sage: G = PermutationGroup([[(1,2,3)],[(4,5,7)],[(1,4,6)]])
1232
sage: G.strong_generating_system()
1233
[[(), (1,2,3), (1,4,6), (1,3,2), (1,5,7,4,6), (1,6,4), (1,7,5,4,6)], [(), (2,6,3), (2,5,7,6,3), (2,3,6), (2,7,5,6,3), (2,4,7,6,3)], [(), (3,6,7), (3,5,6), (3,7,6), (3,4,7,5,6)], [(), (4,5)(6,7), (4,7)(5,6), (4,6)(5,7)], [(), (5,7,6), (5,6,7)], [()], [()]]
1234
sage: G = PermutationGroup([[(1,2,3)],[(2,3,4)],[(3,4,5)]])
1235
sage: G.strong_generating_system([5,4,3,2,1])
1236
[[(), (1,5,3,4,2), (1,5,4,3,2), (1,5)(2,3), (1,5,2)], [(), (1,3)(2,4), (1,2)(3,4), (1,4)(2,3)], [(), (1,3,2), (1,2,3)], [()], [()]]
1237
sage: G = PermutationGroup([[(3,4)]])
1238
sage: G.strong_generating_system()
1239
[[()], [()], [(), (3,4)], [()]]
1240
sage: G.strong_generating_system(base_of_group=[3,1,2,4])
1241
[[(), (3,4)], [()], [()], [()]]
1242
sage: G = TransitiveGroup(12,17) # optional
1243
sage: G.strong_generating_system() # optional
1244
[[(), (1,4,11,2)(3,6,5,8)(7,10,9,12), (1,8,3,2)(4,11,10,9)(5,12,7,6), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), (1,12,7,2)(3,10,9,8)(4,11,6,5), (1,11)(2,8)(3,5)(4,10)(6,12)(7,9), (1,10,11,8)(2,3,12,5)(4,9,6,7), (1,3)(2,8)(4,10)(5,7)(6,12)(9,11), (1,2,3,8)(4,9,10,11)(5,6,7,12), (1,6,7,8)(2,3,4,9)(5,10,11,12), (1,5,9)(3,11,7), (1,9,5)(3,7,11)], [(), (2,6,10)(4,12,8), (2,10,6)(4,8,12)], [()], [()], [()], [()], [()], [()], [()], [()], [()], [()]]
1245
"""
1246
sgs = []
1247
stab = self
1248
if base_of_group is None:
1249
base_of_group = self.domain()
1250
for j in base_of_group:
1251
sgs.append(stab.transversals(j))
1252
stab = stab.stabilizer(j)
1253
return sgs
1254
1255
1256
def _repr_(self):
1257
r"""
1258
Returns a string describing ``self``.
1259
1260
EXAMPLES:
1261
1262
We explicitly construct the alternating group on four
1263
elements. Note that the ``AlternatingGroup`` class has
1264
its own representation string::
1265
1266
sage: A4 = PermutationGroup([[(1,2,3)],[(2,3,4)]]); A4
1267
Permutation Group with generators [(2,3,4), (1,2,3)]
1268
sage: A4._repr_()
1269
'Permutation Group with generators [(2,3,4), (1,2,3)]'
1270
sage: AlternatingGroup(4)._repr_()
1271
'Alternating group of order 4!/2 as a permutation group'
1272
"""
1273
return "Permutation Group with generators %s"%self.gens()
1274
1275
def _latex_(self):
1276
r"""
1277
Method for describing ``self`` in LaTeX. Encapsulates
1278
``self.gens()`` in angle brackets to denote that ``self``
1279
is generated by these elements. Called by the
1280
``latex()`` function.
1281
1282
EXAMPLES:
1283
1284
We explicitly construct the alternating group on four
1285
elements::
1286
1287
sage: A4 = PermutationGroup([[(1,2,3)],[(2,3,4)]]); A4
1288
Permutation Group with generators [(2,3,4), (1,2,3)]
1289
sage: latex(A4)
1290
\langle (2,3,4), (1,2,3) \rangle
1291
sage: A4._latex_()
1292
'\\langle (2,3,4), (1,2,3) \\rangle'
1293
1294
sage: S = SymmetricGroup(['a','b','c'])
1295
sage: latex(S)
1296
\langle (\verb|a|,\verb|b|,\verb|c|), (\verb|a|,\verb|b|) \rangle
1297
"""
1298
return '\\langle ' + \
1299
', '.join([x._latex_() for x in self.gens()]) + ' \\rangle'
1300
1301
def _order(self):
1302
"""
1303
This handles a few special cases of computing the subgroup order much
1304
faster than GAP.
1305
1306
This currently operates very quickly for stabilizer subgroups of
1307
permutation groups, for one.
1308
1309
Will return None if the we could not easily compute it.
1310
1311
Author: Christopher Swenson
1312
1313
EXAMPLES::
1314
1315
sage: SymmetricGroup(10).stabilizer(4)._order()
1316
362880
1317
sage: SymmetricGroup(10).stabilizer(4).stabilizer(5)._order()
1318
40320
1319
sage: SymmetricGroup(200).stabilizer(100)._order() == factorial(199) # this should be very fast
1320
True
1321
1322
TESTS::
1323
1324
sage: [SymmetricGroup(n).stabilizer(1)._gap_().Size() for n in [4..10]]
1325
[6, 24, 120, 720, 5040, 40320, 362880]
1326
sage: [SymmetricGroup(n).stabilizer(1)._order() for n in [4..10]]
1327
[6, 24, 120, 720, 5040, 40320, 362880]
1328
"""
1329
gens = self.gens()
1330
# This special case only works with more than 1 generator.
1331
if not gens or len(gens) < 2:
1332
return None
1333
# Special case: certain subgroups of the symmetric group for which Gap reports
1334
# generators of the form ((1, 2), (1, 3), ...)
1335
# This means that this group is isomorphic to a smaller symmetric group
1336
# S_n, where n is the number of generators supported.
1337
#
1338
# The code that follows checks that the following assumptions hold:
1339
# * All generators are transpositions (i.e., permutations
1340
# that switch two elements and leave everything else fixed),
1341
# * All generators share a common element.
1342
#
1343
# We then know that this group is isomorphic to S_n,
1344
# and therefore its order is n!.
1345
1346
# Check that all generators are order 2 and have length-1 cycle tuples.
1347
for g in gens:
1348
if g.order() != 2:
1349
return None
1350
if len(g.cycle_tuples()) != 1:
1351
return None
1352
# Find the common element.
1353
g0 = gens[0].cycle_tuples()[0]
1354
g1 = gens[1].cycle_tuples()[0]
1355
a, b = g0
1356
if a not in g1 and b not in g1:
1357
return None
1358
if a in g1:
1359
elem = a
1360
else:
1361
elem = b
1362
# Count the number of unique elements in the generators.
1363
unique = set()
1364
for g in gens:
1365
a, b = g.cycle_tuples()[0]
1366
if a != elem and b != elem:
1367
return None
1368
unique.add(a)
1369
unique.add(b)
1370
# Compute the order.
1371
return factorial(len(unique))
1372
1373
def order(self):
1374
"""
1375
Return the number of elements of this group.
1376
1377
EXAMPLES::
1378
1379
sage: G = PermutationGroup([[(1,2,3),(4,5)], [(1,2)]])
1380
sage: G.order()
1381
12
1382
sage: G = PermutationGroup([()])
1383
sage: G.order()
1384
1
1385
sage: G = PermutationGroup([])
1386
sage: G.order()
1387
1
1388
"""
1389
if not self.gens() or self.gens() == [self(1)]:
1390
return Integer(1)
1391
subgroup_order = self._order()
1392
if subgroup_order is not None:
1393
return subgroup_order
1394
return Integer(self._gap_().Size())
1395
1396
def random_element(self):
1397
"""
1398
Return a random element of this group.
1399
1400
EXAMPLES::
1401
1402
sage: G = PermutationGroup([[(1,2,3),(4,5)], [(1,2)]])
1403
sage: a = G.random_element()
1404
sage: a in G
1405
True
1406
sage: a.parent() is G
1407
True
1408
sage: a^6
1409
()
1410
"""
1411
current_randstate().set_seed_gap()
1412
return self(self._gap_().Random(), check=False)
1413
1414
def group_id(self):
1415
"""
1416
Return the ID code of this group, which is a list of two integers.
1417
Requires "optional" database_gap-4.4.x package.
1418
1419
EXAMPLES::
1420
1421
sage: G = PermutationGroup([[(1,2,3),(4,5)], [(1,2)]])
1422
sage: G.group_id() # optional - database_gap
1423
[12, 4]
1424
"""
1425
return [Integer(n) for n in self._gap_().IdGroup()]
1426
1427
def id(self):
1428
"""
1429
(Same as ``self.group_id()``.) Return the ID code of this group, which
1430
is a list of two integers. Requires "optional" database_gap-4.4.x
1431
package.
1432
1433
EXAMPLES::
1434
1435
sage: G = PermutationGroup([[(1,2,3),(4,5)], [(1,2)]])
1436
sage: G.group_id() # optional - database_gap
1437
[12, 4]
1438
"""
1439
return self.group_id()
1440
1441
def center(self):
1442
"""
1443
Return the subgroup of elements that commute with every element
1444
of this group.
1445
1446
EXAMPLES::
1447
1448
sage: G = PermutationGroup([[(1,2,3,4)]])
1449
sage: G.center()
1450
Subgroup of (Permutation Group with generators [(1,2,3,4)]) generated by [(1,2,3,4)]
1451
sage: G = PermutationGroup([[(1,2,3,4)], [(1,2)]])
1452
sage: G.center()
1453
Subgroup of (Permutation Group with generators [(1,2), (1,2,3,4)]) generated by [()]
1454
"""
1455
return self.subgroup(gap_group=self._gap_().Center())
1456
1457
def socle(self):
1458
r"""
1459
Returns the socle of ``self``. The socle of a group $G$ is
1460
the subgroup generated by all minimal normal subgroups.
1461
1462
EXAMPLES::
1463
1464
sage: G=SymmetricGroup(4)
1465
sage: G.socle()
1466
Subgroup of (Symmetric group of order 4! as a permutation group) generated by [(1,2)(3,4), (1,4)(2,3)]
1467
sage: G.socle().socle()
1468
Subgroup of (Subgroup of (Symmetric group of order 4! as a permutation group) generated by [(1,2)(3,4), (1,4)(2,3)]) generated by [(1,3)(2,4), (1,4)(2,3)]
1469
1470
"""
1471
return self.subgroup(gap_group=self._gap_().Socle())
1472
1473
def frattini_subgroup(self):
1474
r"""
1475
Returns the Frattini subgroup of ``self``. The Frattini
1476
subgroup of a group $G$ is the intersection of all
1477
maximal subgroups of $G$.
1478
1479
EXAMPLES::
1480
1481
sage: G=PermutationGroup([[(1,2,3,4)],[(2,4)]])
1482
sage: G.frattini_subgroup()
1483
Subgroup of (Permutation Group with generators [(2,4), (1,2,3,4)]) generated by [(1,3)(2,4)]
1484
sage: G=SymmetricGroup(4)
1485
sage: G.frattini_subgroup()
1486
Subgroup of (Symmetric group of order 4! as a permutation group) generated by [()]
1487
1488
"""
1489
return self.subgroup(gap_group=self._gap_().FrattiniSubgroup())
1490
1491
def fitting_subgroup(self):
1492
r"""
1493
Returns the Fitting subgroup of ``self``. The Fitting
1494
subgroup of a group $G$ is the largest nilpotent normal
1495
subgroup of $G$.
1496
1497
EXAMPLES::
1498
1499
sage: G=PermutationGroup([[(1,2,3,4)],[(2,4)]])
1500
sage: G.fitting_subgroup()
1501
Subgroup of (Permutation Group with generators [(2,4), (1,2,3,4)]) generated by [(2,4), (1,2,3,4), (1,3)]
1502
sage: G=PermutationGroup([[(1,2,3,4)],[(1,2)]])
1503
sage: G.fitting_subgroup()
1504
Subgroup of (Permutation Group with generators [(1,2), (1,2,3,4)]) generated by [(1,2)(3,4), (1,3)(2,4)]
1505
1506
"""
1507
return self.subgroup(gap_group=self._gap_().FittingSubgroup())
1508
1509
def solvable_radical(self):
1510
r"""
1511
Returns the solvable radical of ``self``. The solvable
1512
radical (or just radical) of a group $G$ is the largest
1513
solvable normal subgroup of $G$.
1514
1515
EXAMPLES::
1516
1517
sage: G=SymmetricGroup(4)
1518
sage: G.solvable_radical()
1519
Subgroup of (Symmetric group of order 4! as a permutation group) generated by [(1,2), (1,2,3,4)]
1520
sage: G=SymmetricGroup(5)
1521
sage: G.solvable_radical()
1522
Subgroup of (Symmetric group of order 5! as a permutation group) generated by [()]
1523
1524
"""
1525
return self.subgroup(gap_group=self._gap_().RadicalGroup())
1526
1527
def intersection(self, other):
1528
r"""
1529
Returns the permutation group that is the intersection of
1530
``self`` and ``other``.
1531
1532
INPUT:
1533
1534
- ``other`` - a permutation group.
1535
1536
OUTPUT:
1537
1538
A permutation group that is the set-theoretic intersection of ``self``
1539
with ``other``. The groups are viewed as subgroups of a symmetric
1540
group big enough to contain both group's symbol sets. So there is
1541
no strict notion of the two groups being subgroups of a common parent.
1542
1543
EXAMPLES::
1544
1545
sage: H = DihedralGroup(4)
1546
1547
sage: K = CyclicPermutationGroup(4)
1548
sage: H.intersection(K)
1549
Permutation Group with generators [(1,2,3,4)]
1550
1551
sage: L = DihedralGroup(5)
1552
sage: H.intersection(L)
1553
Permutation Group with generators [(1,4)(2,3)]
1554
1555
sage: M = PermutationGroup(["()"])
1556
sage: H.intersection(M)
1557
Permutation Group with generators [()]
1558
1559
Some basic properties. ::
1560
1561
sage: H = DihedralGroup(4)
1562
sage: L = DihedralGroup(5)
1563
sage: H.intersection(L) == L.intersection(H)
1564
True
1565
sage: H.intersection(H) == H
1566
True
1567
1568
The group ``other`` is verified as such. ::
1569
1570
sage: H = DihedralGroup(4)
1571
sage: H.intersection('junk')
1572
Traceback (most recent call last):
1573
...
1574
TypeError: junk is not a permutation group
1575
"""
1576
from sage.categories.finite_permutation_groups import FinitePermutationGroups
1577
if other not in FinitePermutationGroups():
1578
raise TypeError("{0} is not a permutation group".format(other))
1579
return PermutationGroup(gap_group=gap.Intersection(self, other))
1580
1581
def conjugate(self, g):
1582
r"""
1583
Returns the group formed by conjugating ``self`` with ``g``.
1584
1585
INPUT:
1586
1587
- ``g`` - a permutation group element, or an object that converts
1588
to a permutation group element, such as a list of integers or
1589
a string of cycles.
1590
1591
OUTPUT:
1592
1593
If ``self`` is the group denoted by `H`, then this method computes
1594
the group
1595
1596
.. math::
1597
1598
g^{-1}Hg = \{g^{-1}hg\vert h\in H\}
1599
1600
which is the group `H` conjugated by `g`.
1601
1602
There are no restrictions on ``self`` and ``g`` belonging to
1603
a common permutation group, and correspondingly, there is no
1604
relationship (such as a common parent) between ``self`` and the
1605
output group.
1606
1607
EXAMPLES::
1608
1609
sage: G = DihedralGroup(6)
1610
sage: a = PermutationGroupElement("(1,2,3,4)")
1611
sage: G.conjugate(a)
1612
Permutation Group with generators [(1,4)(2,6)(3,5), (1,5,6,2,3,4)]
1613
1614
The element performing the conjugation can be specified in
1615
several ways. ::
1616
1617
sage: G = DihedralGroup(6)
1618
sage: strng = "(1,2,3,4)"
1619
sage: G.conjugate(strng)
1620
Permutation Group with generators [(1,4)(2,6)(3,5), (1,5,6,2,3,4)]
1621
sage: G = DihedralGroup(6)
1622
sage: lst = [2,3,4,1]
1623
sage: G.conjugate(lst)
1624
Permutation Group with generators [(1,4)(2,6)(3,5), (1,5,6,2,3,4)]
1625
sage: G = DihedralGroup(6)
1626
sage: cycles = [(1,2,3,4)]
1627
sage: G.conjugate(cycles)
1628
Permutation Group with generators [(1,4)(2,6)(3,5), (1,5,6,2,3,4)]
1629
1630
Conjugation is a group automorphism, so conjugate groups
1631
will be isomorphic. ::
1632
1633
sage: G = DiCyclicGroup(6)
1634
sage: G.degree()
1635
11
1636
sage: cycle = [i+1 for i in range(1,11)] + [1]
1637
sage: C = G.conjugate(cycle)
1638
sage: G.is_isomorphic(C)
1639
True
1640
1641
The conjugating element may be from a symmetric group with
1642
larger degree than the group being conjugated. ::
1643
1644
sage: G = AlternatingGroup(5)
1645
sage: G.degree()
1646
5
1647
sage: g = "(1,3)(5,6,7)"
1648
sage: H = G.conjugate(g); H
1649
Permutation Group with generators [(1,4,6,3,2), (1,4,6)]
1650
sage: H.degree()
1651
6
1652
1653
The conjugating element is checked. ::
1654
1655
sage: G = SymmetricGroup(3)
1656
sage: G.conjugate("junk")
1657
Traceback (most recent call last):
1658
...
1659
TypeError: junk does not convert to a permutation group element
1660
"""
1661
try:
1662
g = PermutationGroupElement(g)
1663
except:
1664
raise TypeError("{0} does not convert to a permutation group element".format(g))
1665
return PermutationGroup(gap_group=gap.ConjugateGroup(self, g))
1666
1667
def direct_product(self, other, maps=True):
1668
"""
1669
Wraps GAP's ``DirectProduct``, ``Embedding``, and ``Projection``.
1670
1671
Sage calls GAP's ``DirectProduct``, which chooses an efficient
1672
representation for the direct product. The direct product of
1673
permutation groups will be a permutation group again. For a direct
1674
product ``D``, the GAP operation ``Embedding(D,i)`` returns the
1675
homomorphism embedding the i-th factor into ``D``. The GAP operation
1676
``Projection(D,i)`` gives the projection of ``D`` onto the i-th factor.
1677
This method returns a 5-tuple: a permutation group and 4 morphisms.
1678
1679
INPUT:
1680
1681
- ``self, other`` - permutation groups
1682
1683
OUTPUT:
1684
1685
- ``D`` - a direct product of the inputs, returned as
1686
a permutation group as well
1687
1688
- ``iota1`` - an embedding of ``self`` into ``D``
1689
1690
- ``iota2`` - an embedding of ``other`` into ``D``
1691
1692
- ``pr1`` - the projection of ``D`` onto ``self`` (giving a
1693
splitting 1 - other - D - self - 1)
1694
1695
- ``pr2`` - the projection of ``D`` onto ``other`` (giving a
1696
splitting 1 - self - D - other - 1)
1697
1698
EXAMPLES::
1699
1700
sage: G = CyclicPermutationGroup(4)
1701
sage: D = G.direct_product(G,False)
1702
sage: D
1703
Permutation Group with generators [(5,6,7,8), (1,2,3,4)]
1704
sage: D,iota1,iota2,pr1,pr2 = G.direct_product(G)
1705
sage: D; iota1; iota2; pr1; pr2
1706
Permutation Group with generators [(5,6,7,8), (1,2,3,4)]
1707
Permutation group morphism:
1708
From: Cyclic group of order 4 as a permutation group
1709
To: Permutation Group with generators [(5,6,7,8), (1,2,3,4)]
1710
Defn: Embedding( Group( [ (1,2,3,4), (5,6,7,8) ] ), 1 )
1711
Permutation group morphism:
1712
From: Cyclic group of order 4 as a permutation group
1713
To: Permutation Group with generators [(5,6,7,8), (1,2,3,4)]
1714
Defn: Embedding( Group( [ (1,2,3,4), (5,6,7,8) ] ), 2 )
1715
Permutation group morphism:
1716
From: Permutation Group with generators [(5,6,7,8), (1,2,3,4)]
1717
To: Cyclic group of order 4 as a permutation group
1718
Defn: Projection( Group( [ (1,2,3,4), (5,6,7,8) ] ), 1 )
1719
Permutation group morphism:
1720
From: Permutation Group with generators [(5,6,7,8), (1,2,3,4)]
1721
To: Cyclic group of order 4 as a permutation group
1722
Defn: Projection( Group( [ (1,2,3,4), (5,6,7,8) ] ), 2 )
1723
sage: g=D([(1,3),(2,4)]); g
1724
(1,3)(2,4)
1725
sage: d=D([(1,4,3,2),(5,7),(6,8)]); d
1726
(1,4,3,2)(5,7)(6,8)
1727
sage: iota1(g); iota2(g); pr1(d); pr2(d)
1728
(1,3)(2,4)
1729
(5,7)(6,8)
1730
(1,4,3,2)
1731
(1,3)(2,4)
1732
"""
1733
G = self._gap_().DirectProduct(other)
1734
D = PermutationGroup(gap_group=G)
1735
if not maps:
1736
return D
1737
else:
1738
from sage.groups.perm_gps.permgroup_morphism import PermutationGroupMorphism_from_gap
1739
iota1 = PermutationGroupMorphism_from_gap(self, D, G.Embedding(1))
1740
iota2 = PermutationGroupMorphism_from_gap(other, D, G.Embedding(2))
1741
pr1 = PermutationGroupMorphism_from_gap(D, self, G.Projection(1))
1742
pr2 = PermutationGroupMorphism_from_gap(D, other, G.Projection(2))
1743
return D, iota1, iota2, pr1, pr2
1744
1745
def subgroup(self, gens=None, gap_group=None, domain=None, category=None, canonicalize=True, check=True):
1746
"""
1747
Wraps the ``PermutationGroup_subgroup`` constructor. The argument
1748
``gens`` is a list of elements of ``self``.
1749
1750
EXAMPLES::
1751
1752
sage: G = PermutationGroup([(1,2,3),(3,4,5)])
1753
sage: g = G((1,2,3))
1754
sage: G.subgroup([g])
1755
Subgroup of (Permutation Group with generators [(3,4,5), (1,2,3)]) generated by [(1,2,3)]
1756
"""
1757
return PermutationGroup_subgroup(self, gens=gens, gap_group=gap_group, domain=None,
1758
category=category, canonicalize=canonicalize, check=check)
1759
1760
def quotient(self, N):
1761
"""
1762
Returns the quotient of this permutation group by the normal
1763
subgroup `N`, as a permutation group.
1764
1765
Wraps the GAP operator "/".
1766
1767
EXAMPLES::
1768
1769
sage: G = PermutationGroup([(1,2,3), (2,3)])
1770
sage: N = PermutationGroup([(1,2,3)])
1771
sage: G.quotient(N)
1772
Permutation Group with generators [(1,2)]
1773
sage: G.quotient(G)
1774
Permutation Group with generators [()]
1775
"""
1776
Q = self._gap_() / N._gap_()
1777
# Return Q as a permutation group
1778
# This is currently done using the right regular representation
1779
# FIXME: GAP certainly knows of a better way!
1780
phi = Q.RegularActionHomomorphism()
1781
return PermutationGroup(gap_group=phi.Image())
1782
1783
def quotient_group(self, N):
1784
"""
1785
This function has been deprecated and will be removed in a
1786
future version of Sage; use ``quotient`` instead.
1787
1788
Original docstring follows.
1789
1790
Returns the quotient of this permutation group by the normal
1791
subgroup `N`.
1792
1793
Wraps the GAP operator "/".
1794
1795
TESTS::
1796
1797
sage: G = PermutationGroup([(1,2,3), (2,3)])
1798
sage: N = PermutationGroup([(1,2,3)])
1799
sage: G.quotient_group(N)
1800
doctest:...: DeprecationWarning: quotient_group() is deprecated; use quotient() instead.
1801
Permutation Group with generators [(1,2)]
1802
"""
1803
from sage.misc.misc import deprecation
1804
deprecation('quotient_group() is deprecated; use quotient() instead.')
1805
return self.quotient(N)
1806
1807
def commutator(self, other=None):
1808
r"""
1809
Returns the commutator subgroup of a group, or of a pair of groups.
1810
1811
INPUT:
1812
1813
- ``other`` - default: ``None`` - a permutation group.
1814
1815
OUTPUT:
1816
1817
Let $G$ denote ``self``. If ``other`` is ``None`` then this method
1818
returns the subgroup of $G$ generated by the set of commutators,
1819
1820
.. math::
1821
1822
\{[g_1,g_2]\vert g_1, g_2\in G\} = \{g_1^{-1}g_2^{-1}g_1g_2\vert g_1, g_2\in G\}
1823
1824
Let $H$ denote ``other``, in the case that it is not ``None``. Then
1825
this method returns the group generated by the set of commutators,
1826
1827
.. math::
1828
1829
\{[g,h]\vert g\in G\, h\in H\} = \{g^{-1}h^{-1}gh\vert g\in G\, h\in H\}
1830
1831
The two groups need only be permutation groups, there is no notion
1832
of requiring them to explicitly be subgroups of some other group.
1833
1834
.. note::
1835
1836
For the identical statement, the generators of the returned
1837
group can vary from one execution to the next.
1838
1839
EXAMPLES::
1840
1841
sage: G = DiCyclicGroup(4)
1842
sage: G.commutator()
1843
Permutation Group with generators [(1,3,5,7)(2,4,6,8)(9,11,13,15)(10,12,14,16)]
1844
1845
sage: G = SymmetricGroup(5)
1846
sage: H = CyclicPermutationGroup(5)
1847
sage: C = G.commutator(H)
1848
sage: C.is_isomorphic(AlternatingGroup(5))
1849
True
1850
1851
An abelian group will have a trivial commutator. ::
1852
1853
sage: G = CyclicPermutationGroup(10)
1854
sage: G.commutator()
1855
Permutation Group with generators [()]
1856
1857
The quotient of a group by its commutator is always abelian. ::
1858
1859
sage: G = DihedralGroup(20)
1860
sage: C = G.commutator()
1861
sage: Q = G.quotient(C)
1862
sage: Q.is_abelian()
1863
True
1864
1865
When forming commutators from two groups, the order of the
1866
groups does not matter. ::
1867
1868
sage: D = DihedralGroup(3)
1869
sage: S = SymmetricGroup(2)
1870
sage: C1 = D.commutator(S); C1
1871
Permutation Group with generators [(1,2,3)]
1872
sage: C2 = S.commutator(D); C2
1873
Permutation Group with generators [(1,3,2)]
1874
sage: C1 == C2
1875
True
1876
1877
This method calls two different functions in GAP, so
1878
this tests that their results are consistent. The
1879
commutator groups may have different generators, but the
1880
groups are equal. ::
1881
1882
sage: G = DiCyclicGroup(3)
1883
sage: C = G.commutator(); C
1884
Permutation Group with generators [(5,7,6)]
1885
sage: CC = G.commutator(G); CC
1886
Permutation Group with generators [(5,6,7)]
1887
sage: C == CC
1888
True
1889
1890
The second group is checked. ::
1891
1892
sage: G = SymmetricGroup(2)
1893
sage: G.commutator('junk')
1894
Traceback (most recent call last):
1895
...
1896
TypeError: junk is not a permutation group
1897
"""
1898
if other is None:
1899
return PermutationGroup(gap_group=gap.DerivedSubgroup(self))
1900
else:
1901
from sage.categories.finite_permutation_groups import FinitePermutationGroups
1902
if other not in FinitePermutationGroups():
1903
raise TypeError("{0} is not a permutation group".format(other))
1904
return PermutationGroup(gap_group=gap.CommutatorSubgroup(self, other))
1905
1906
@hap_decorator
1907
def cohomology(self, n, p = 0):
1908
r"""
1909
Computes the group cohomology `H^n(G, F)`, where `F = \ZZ`
1910
if `p=0` and `F = \ZZ / p \ZZ` if `p > 0` is a prime.
1911
Wraps HAP's ``GroupHomology`` function, written by Graham Ellis.
1912
1913
REQUIRES: GAP package HAP (in gap_packages-\*.spkg).
1914
1915
EXAMPLES::
1916
1917
sage: G = SymmetricGroup(4)
1918
sage: G.cohomology(1,2) # optional - gap_packages
1919
Multiplicative Abelian Group isomorphic to C2
1920
sage: G = SymmetricGroup(3)
1921
sage: G.cohomology(5) # optional - gap_packages
1922
Trivial Abelian Group
1923
sage: G.cohomology(5,2) # optional - gap_packages
1924
Multiplicative Abelian Group isomorphic to C2
1925
sage: G.homology(5,3) # optional - gap_packages
1926
Trivial Abelian Group
1927
sage: G.homology(5,4) # optional - gap_packages
1928
Traceback (most recent call last):
1929
...
1930
ValueError: p must be 0 or prime
1931
1932
This computes `H^4(S_3, \ZZ)` and
1933
`H^4(S_3, \ZZ / 2 \ZZ)`, respectively.
1934
1935
AUTHORS:
1936
1937
- David Joyner and Graham Ellis
1938
1939
REFERENCES:
1940
1941
- G. Ellis, 'Computing group resolutions', J. Symbolic
1942
Computation. Vol.38, (2004)1077-1118 (Available at
1943
http://hamilton.nuigalway.ie/).
1944
1945
- D. Joyner, 'A primer on computational group homology and
1946
cohomology', http://front.math.ucdavis.edu/0706.0549.
1947
"""
1948
if p == 0:
1949
L = self._gap_().GroupCohomology(n).sage()
1950
else:
1951
L = self._gap_().GroupCohomology(n, p).sage()
1952
return AbelianGroup(len(L), L)
1953
1954
@hap_decorator
1955
def cohomology_part(self, n, p = 0):
1956
"""
1957
Computes the p-part of the group cohomology `H^n(G, F)`,
1958
where `F = \ZZ` if `p=0` and `F = \ZZ / p \ZZ` if
1959
`p > 0` is a prime. Wraps HAP's Homology function, written
1960
by Graham Ellis, applied to the `p`-Sylow subgroup of
1961
`G`.
1962
1963
REQUIRES: GAP package HAP (in gap_packages-\*.spkg).
1964
1965
EXAMPLES::
1966
1967
sage: G = SymmetricGroup(5)
1968
sage: G.cohomology_part(7,2) # optional - gap_packages
1969
Multiplicative Abelian Group isomorphic to C2 x C2 x C2
1970
sage: G = SymmetricGroup(3)
1971
sage: G.cohomology_part(2,3) # optional - gap_packages
1972
Multiplicative Abelian Group isomorphic to C3
1973
1974
AUTHORS:
1975
1976
- David Joyner and Graham Ellis
1977
"""
1978
if p == 0:
1979
return AbelianGroup(1, [1])
1980
else:
1981
G = self._gap_()
1982
S = G.SylowSubgroup(p)
1983
R = S.ResolutionFiniteGroup(n+1)
1984
HR = R.HomToIntegers()
1985
L = HR.Cohomology(n).sage()
1986
return AbelianGroup(len(L), L)
1987
1988
@hap_decorator
1989
def homology(self, n, p = 0):
1990
r"""
1991
Computes the group homology `H_n(G, F)`, where
1992
`F = \ZZ` if `p=0` and `F = \ZZ / p \ZZ` if
1993
`p > 0` is a prime. Wraps HAP's ``GroupHomology`` function,
1994
written by Graham Ellis.
1995
1996
REQUIRES: GAP package HAP (in gap_packages-\*.spkg).
1997
1998
AUTHORS:
1999
2000
- David Joyner and Graham Ellis
2001
2002
The example below computes `H_7(S_5, \ZZ)`,
2003
`H_7(S_5, \ZZ / 2 \ZZ)`,
2004
`H_7(S_5, \ZZ / 3 \ZZ)`, and
2005
`H_7(S_5, \ZZ / 5 \ZZ)`, respectively. To compute the
2006
`2`-part of `H_7(S_5, \ZZ)`, use the ``homology_part``
2007
function.
2008
2009
EXAMPLES::
2010
2011
sage: G = SymmetricGroup(5)
2012
sage: G.homology(7) # optional - gap_packages
2013
Multiplicative Abelian Group isomorphic to C2 x C2 x C4 x C3 x C5
2014
sage: G.homology(7,2) # optional - gap_packages
2015
Multiplicative Abelian Group isomorphic to C2 x C2 x C2 x C2 x C2
2016
sage: G.homology(7,3) # optional - gap_packages
2017
Multiplicative Abelian Group isomorphic to C3
2018
sage: G.homology(7,5) # optional - gap_packages
2019
Multiplicative Abelian Group isomorphic to C5
2020
2021
REFERENCES:
2022
2023
- G. Ellis, "Computing group resolutions", J. Symbolic
2024
Computation. Vol.38, (2004)1077-1118 (Available at
2025
http://hamilton.nuigalway.ie/.
2026
2027
- D. Joyner, "A primer on computational group homology and cohomology",
2028
http://front.math.ucdavis.edu/0706.0549
2029
"""
2030
if p == 0:
2031
L = self._gap_().GroupHomology(n).sage()
2032
else:
2033
L = self._gap_().GroupHomology(n, p).sage()
2034
return AbelianGroup(len(L), L)
2035
2036
@hap_decorator
2037
def homology_part(self, n, p = 0):
2038
r"""
2039
Computes the `p`-part of the group homology
2040
`H_n(G, F)`, where `F = \ZZ` if `p=0` and
2041
`F = \ZZ / p \ZZ` if `p > 0` is a prime. Wraps HAP's
2042
``Homology`` function, written by Graham Ellis, applied to the
2043
`p`-Sylow subgroup of `G`.
2044
2045
REQUIRES: GAP package HAP (in gap_packages-\*.spkg).
2046
2047
EXAMPLES::
2048
2049
sage: G = SymmetricGroup(5)
2050
sage: G.homology_part(7,2) # optional - gap_packages
2051
Multiplicative Abelian Group isomorphic to C2 x C2 x C2 x C2 x C4
2052
2053
AUTHORS:
2054
2055
- David Joyner and Graham Ellis
2056
"""
2057
if p == 0:
2058
return AbelianGroup(1, [1])
2059
else:
2060
S = self._gap_().SylowSubgroup(p)
2061
R = S.ResolutionFiniteGroup(n+1)
2062
TR = R.TensorWithIntegers()
2063
L = TR.Homology(n).sage()
2064
return AbelianGroup(len(L), L)
2065
2066
def character_table(self):
2067
r"""
2068
Returns the matrix of values of the irreducible characters of a
2069
permutation group `G` at the conjugacy classes of
2070
`G`. The columns represent the conjugacy classes of
2071
`G` and the rows represent the different irreducible
2072
characters in the ordering given by GAP.
2073
2074
EXAMPLES::
2075
2076
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3)]])
2077
sage: G.order()
2078
12
2079
sage: G.character_table()
2080
[ 1 1 1 1]
2081
[ 1 1 -zeta3 - 1 zeta3]
2082
[ 1 1 zeta3 -zeta3 - 1]
2083
[ 3 -1 0 0]
2084
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3)]])
2085
sage: CT = gap(G).CharacterTable()
2086
2087
Type ``print gap.eval("Display(%s)"%CT.name())`` to display this
2088
nicely.
2089
2090
::
2091
2092
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]])
2093
sage: G.order()
2094
8
2095
sage: G.character_table()
2096
[ 1 1 1 1 1]
2097
[ 1 -1 -1 1 1]
2098
[ 1 -1 1 -1 1]
2099
[ 1 1 -1 -1 1]
2100
[ 2 0 0 0 -2]
2101
sage: CT = gap(G).CharacterTable()
2102
2103
Again, type ``print gap.eval("Display(%s)"%CT.name())`` to display this
2104
nicely.
2105
2106
::
2107
2108
sage: SymmetricGroup(2).character_table()
2109
[ 1 -1]
2110
[ 1 1]
2111
sage: SymmetricGroup(3).character_table()
2112
[ 1 -1 1]
2113
[ 2 0 -1]
2114
[ 1 1 1]
2115
sage: SymmetricGroup(5).character_table()
2116
[ 1 -1 1 1 -1 -1 1]
2117
[ 4 -2 0 1 1 0 -1]
2118
[ 5 -1 1 -1 -1 1 0]
2119
[ 6 0 -2 0 0 0 1]
2120
[ 5 1 1 -1 1 -1 0]
2121
[ 4 2 0 1 -1 0 -1]
2122
[ 1 1 1 1 1 1 1]
2123
sage: list(AlternatingGroup(6).character_table())
2124
[(1, 1, 1, 1, 1, 1, 1), (5, 1, 2, -1, -1, 0, 0), (5, 1, -1, 2, -1, 0, 0), (8, 0, -1, -1, 0, zeta5^3 + zeta5^2 + 1, -zeta5^3 - zeta5^2), (8, 0, -1, -1, 0, -zeta5^3 - zeta5^2, zeta5^3 + zeta5^2 + 1), (9, 1, 0, 0, 1, -1, -1), (10, -2, 1, 1, 0, 0, 0)]
2125
2126
Suppose that you have a class function `f(g)` on
2127
`G` and you know the values `v_1, \ldots, v_n` on
2128
the conjugacy class elements in
2129
``conjugacy_classes_representatives(G)`` =
2130
`[g_1, \ldots, g_n]`. Since the irreducible characters
2131
`\rho_1, \ldots, \rho_n` of `G` form an
2132
`E`-basis of the space of all class functions (`E`
2133
a "sufficiently large" cyclotomic field), such a class function is
2134
a linear combination of these basis elements,
2135
`f = c_1 \rho_1 + \cdots + c_n \rho_n`. To find
2136
the coefficients `c_i`, you simply solve the linear system
2137
``character_table_values(G)`` `[v_1, ..., v_n] = [c_1, ..., c_n]`,
2138
where `[v_1, \ldots, v_n]` = ``character_table_values(G)`` `^{(-1)}[c_1, ..., c_n]`.
2139
2140
AUTHORS:
2141
2142
- David Joyner and William Stein (2006-01-04)
2143
2144
"""
2145
G = self._gap_()
2146
cl = G.ConjugacyClasses()
2147
n = Integer(cl.Length())
2148
irrG = G.Irr()
2149
ct = [[irrG[i+1, j+1] for j in range(n)] for i in range(n)]
2150
2151
from sage.rings.all import CyclotomicField
2152
e = irrG.Flat().Conductor()
2153
K = CyclotomicField(e)
2154
ct = [[K(x) for x in v] for v in ct]
2155
2156
# Finally return the result as a matrix.
2157
from sage.matrix.all import MatrixSpace
2158
MS = MatrixSpace(K, n)
2159
return MS(ct)
2160
2161
def irreducible_characters(self):
2162
r"""
2163
Returns a list of the irreducible characters of ``self``.
2164
2165
EXAMPLES::
2166
2167
sage: irr = SymmetricGroup(3).irreducible_characters()
2168
sage: [x.values() for x in irr]
2169
[[1, -1, 1], [2, 0, -1], [1, 1, 1]]
2170
"""
2171
return [ClassFunction(self, irr) for irr in self._gap_().Irr()]
2172
2173
def trivial_character(self):
2174
r"""
2175
Returns the trivial character of ``self``.
2176
2177
EXAMPLES::
2178
2179
sage: SymmetricGroup(3).trivial_character()
2180
Character of Symmetric group of order 3! as a permutation group
2181
"""
2182
values = [1]*self._gap_().NrConjugacyClasses().sage()
2183
return self.character(values)
2184
2185
def character(self, values):
2186
r"""
2187
Returns a group character from ``values``, where ``values`` is
2188
a list of the values of the character evaluated on the conjugacy
2189
classes.
2190
2191
EXAMPLES::
2192
2193
sage: G = AlternatingGroup(4)
2194
sage: n = len(G.conjugacy_classes_representatives())
2195
sage: G.character([1]*n)
2196
Character of Alternating group of order 4!/2 as a permutation group
2197
"""
2198
return ClassFunction(self, values)
2199
2200
def conjugacy_classes_representatives(self):
2201
"""
2202
Returns a complete list of representatives of conjugacy classes in
2203
a permutation group `G`. The ordering is that given by GAP.
2204
2205
EXAMPLES::
2206
2207
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]])
2208
sage: cl = G.conjugacy_classes_representatives(); cl
2209
[(), (2,4), (1,2)(3,4), (1,2,3,4), (1,3)(2,4)]
2210
sage: cl[3] in G
2211
True
2212
2213
::
2214
2215
sage: G = SymmetricGroup(5)
2216
sage: G.conjugacy_classes_representatives()
2217
[(), (1,2), (1,2)(3,4), (1,2,3), (1,2,3)(4,5), (1,2,3,4), (1,2,3,4,5)]
2218
2219
::
2220
2221
sage: S = SymmetricGroup(['a','b','c'])
2222
sage: S.conjugacy_classes_representatives()
2223
[(), ('a','b'), ('a','b','c')]
2224
2225
AUTHORS:
2226
2227
- David Joyner and William Stein (2006-01-04)
2228
"""
2229
cl = self._gap_().ConjugacyClasses()
2230
return [self(rep.Representative(), check=False) for rep in cl]
2231
2232
def conjugacy_classes_subgroups(self):
2233
"""
2234
Returns a complete list of representatives of conjugacy classes of
2235
subgroups in a permutation group `G`. The ordering is that given by
2236
GAP.
2237
2238
EXAMPLES::
2239
2240
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]])
2241
sage: cl = G.conjugacy_classes_subgroups()
2242
sage: cl
2243
[Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [()], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2)(3,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,3)(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2)(3,4), (1,4)(2,3)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,3)(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2,3,4), (1,3)(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2)(3,4), (1,2,3,4), (1,3)(2,4)]]
2244
2245
::
2246
2247
sage: G = SymmetricGroup(3)
2248
sage: G.conjugacy_classes_subgroups()
2249
[Subgroup of (Symmetric group of order 3! as a permutation group) generated by [()], Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(2,3)], Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2,3)], Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2), (1,3,2)]]
2250
2251
AUTHORS:
2252
2253
- David Joyner (2006-10)
2254
"""
2255
cl = self._gap_().ConjugacyClassesSubgroups()
2256
return [self.subgroup(gap_group=sub.Representative()) for sub in cl]
2257
2258
def subgroups(self):
2259
r"""
2260
Returns a list of all the subgroups of ``self``.
2261
2262
OUTPUT:
2263
2264
Each possible subgroup of ``self`` is contained once
2265
in the returned list. The list is in order, according
2266
to the size of the subgroups, from the trivial subgroup
2267
with one element on through up to the whole group.
2268
Conjugacy classes of subgroups are contiguous in the list.
2269
2270
.. warning::
2271
2272
For even relatively small groups this method can
2273
take a very long time to execute, or create vast
2274
amounts of output. Likely both. Its purpose is
2275
instructional, as it can be useful for studying
2276
small groups. The 156 subgroups of the full
2277
symmetric group on 5 symbols of order 120, `S_5`,
2278
can be computed in about a minute on commodity hardware
2279
in 2011. The 64 subgroups of the cyclic group of order
2280
`30030 = 2\cdot 3\cdot 5\cdot 7\cdot 11\cdot 13` takes
2281
about twice as long.
2282
2283
For faster results, which still exhibit the structure of
2284
the possible subgroups, use
2285
:meth:`conjugacy_classes_subgroups`.
2286
2287
EXAMPLES::
2288
2289
sage: G = SymmetricGroup(3)
2290
sage: G.subgroups()
2291
[Permutation Group with generators [()],
2292
Permutation Group with generators [(2,3)],
2293
Permutation Group with generators [(1,2)],
2294
Permutation Group with generators [(1,3)],
2295
Permutation Group with generators [(1,2,3)],
2296
Permutation Group with generators [(1,2), (1,3,2)]]
2297
2298
sage: G = CyclicPermutationGroup(14)
2299
sage: G.subgroups()
2300
[Permutation Group with generators [()],
2301
Permutation Group with generators [(1,8)(2,9)(3,10)(4,11)(5,12)(6,13)(7,14)],
2302
Permutation Group with generators [(1,3,5,7,9,11,13)(2,4,6,8,10,12,14)],
2303
Permutation Group with generators [(1,2,3,4,5,6,7,8,9,10,11,12,13,14)]]
2304
2305
AUTHOR:
2306
2307
- Rob Beezer (2011-01-24)
2308
"""
2309
all_sg = []
2310
ccs = self._gap_().ConjugacyClassesSubgroups()
2311
for cc in ccs:
2312
for h in cc.Elements():
2313
all_sg.append(PermutationGroup(gap_group=h))
2314
return all_sg
2315
2316
def cosets(self, S, side='right'):
2317
r"""
2318
Returns a list of the cosets of ``S`` in ``self``.
2319
2320
INPUT:
2321
2322
- ``S`` - a subgroup of ``self``. An error is raised
2323
if ``S`` is not a subgroup.
2324
2325
- ``side`` - default: 'right' - determines if right cosets or
2326
left cosets are returned. ``side`` refers to where the
2327
representative is placed in the products forming the cosets
2328
and thus allowable values are only 'right' and 'left'.
2329
2330
OUTPUT:
2331
2332
A list of lists. Each inner list is a coset of the subgroup
2333
in the group. The first element of each coset is the smallest
2334
element (based on the ordering of the elements of ``self``)
2335
of all the group elements that have not yet appeared in a
2336
previous coset. The elements of each coset are in the same
2337
order as the subgroup elements used to build the coset's
2338
elements.
2339
2340
As a consequence, the subgroup itself is the first coset,
2341
and its first element is the identity element. For each coset,
2342
the first element listed is the element used as a representative
2343
to build the coset. These representatives form an increasing
2344
sequence across the list of cosets, and within a coset the
2345
representative is the smallest element of its coset (both
2346
orderings are based on of the ordering of elements of ``self``).
2347
2348
In the case of a normal subgroup, left and right cosets should
2349
appear in the same order as part of the outer list. However,
2350
the list of the elements of a particular coset may be in a
2351
different order for the right coset versus the order in the
2352
left coset. So, if you check to see if a subgroup is normal,
2353
it is necessary to sort each individual coset first (but not
2354
the list of cosets, due to the ordering of the representatives).
2355
See below for examples of this.
2356
2357
.. note::
2358
2359
This is a naive implementation intended for instructional
2360
purposes, and hence is slow for larger groups. Sage and GAP
2361
provide more sophisticated functions for working quickly with
2362
cosets of larger groups.
2363
2364
EXAMPLES:
2365
2366
The default is to build right cosets. This example works with
2367
the symmetry group of an 8-gon and a normal subgroup.
2368
Notice that a straight check on the equality of the output
2369
is not sufficient to check normality, while sorting the
2370
individual cosets is sufficient to then simply test equality of
2371
the list of lists. Study the second coset in each list to understand the
2372
need for sorting the elements of the cosets. ::
2373
2374
sage: G = DihedralGroup(8)
2375
sage: quarter_turn = G.list()[5]; quarter_turn
2376
(1,3,5,7)(2,4,6,8)
2377
sage: S = G.subgroup([quarter_turn])
2378
sage: rc = G.cosets(S); rc
2379
[[(), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8), (1,7,5,3)(2,8,6,4)],
2380
[(2,8)(3,7)(4,6), (1,7)(2,6)(3,5), (1,5)(2,4)(6,8), (1,3)(4,8)(5,7)],
2381
[(1,2)(3,8)(4,7)(5,6), (1,8)(2,7)(3,6)(4,5), (1,6)(2,5)(3,4)(7,8), (1,4)(2,3)(5,8)(6,7)],
2382
[(1,2,3,4,5,6,7,8), (1,4,7,2,5,8,3,6), (1,6,3,8,5,2,7,4), (1,8,7,6,5,4,3,2)]]
2383
sage: lc = G.cosets(S, side='left'); lc
2384
[[(), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8), (1,7,5,3)(2,8,6,4)],
2385
[(2,8)(3,7)(4,6), (1,3)(4,8)(5,7), (1,5)(2,4)(6,8), (1,7)(2,6)(3,5)],
2386
[(1,2)(3,8)(4,7)(5,6), (1,4)(2,3)(5,8)(6,7), (1,6)(2,5)(3,4)(7,8), (1,8)(2,7)(3,6)(4,5)],
2387
[(1,2,3,4,5,6,7,8), (1,4,7,2,5,8,3,6), (1,6,3,8,5,2,7,4), (1,8,7,6,5,4,3,2)]]
2388
2389
sage: S.is_normal(G)
2390
True
2391
sage: rc == lc
2392
False
2393
sage: rc_sorted = [sorted(c) for c in rc]
2394
sage: lc_sorted = [sorted(c) for c in lc]
2395
sage: rc_sorted == lc_sorted
2396
True
2397
2398
An example with the symmetry group of a regular
2399
tetrahedron and a subgroup that is not normal.
2400
Thus, the right and left cosets are different
2401
(and so are the representatives). With each
2402
individual coset sorted, a naive test of normality
2403
is possible. ::
2404
2405
sage: A = AlternatingGroup(4)
2406
sage: face_turn = A.list()[4]; face_turn
2407
(1,2,3)
2408
sage: stabilizer = A.subgroup([face_turn])
2409
sage: rc = A.cosets(stabilizer, side='right'); rc
2410
[[(), (1,2,3), (1,3,2)],
2411
[(2,3,4), (1,3)(2,4), (1,4,2)],
2412
[(2,4,3), (1,4,3), (1,2)(3,4)],
2413
[(1,2,4), (1,4)(2,3), (1,3,4)]]
2414
sage: lc = A.cosets(stabilizer, side='left'); lc
2415
[[(), (1,2,3), (1,3,2)],
2416
[(2,3,4), (1,2)(3,4), (1,3,4)],
2417
[(2,4,3), (1,2,4), (1,3)(2,4)],
2418
[(1,4,2), (1,4,3), (1,4)(2,3)]]
2419
2420
sage: stabilizer.is_normal(A)
2421
False
2422
sage: rc_sorted = [sorted(c) for c in rc]
2423
sage: lc_sorted = [sorted(c) for c in lc]
2424
sage: rc_sorted == lc_sorted
2425
False
2426
2427
TESTS:
2428
2429
The keyword ``side`` is checked for the two possible values. ::
2430
2431
sage: G = SymmetricGroup(3)
2432
sage: S = G.subgroup([G("(1,2)")])
2433
sage: G.cosets(S, side='junk')
2434
Traceback (most recent call last):
2435
...
2436
ValueError: side should be 'right' or 'left', not junk
2437
2438
The subgroup argument is checked to see if it is a permutation group.
2439
Even a legitimate GAP object can be rejected. ::
2440
2441
sage: G=SymmetricGroup(3)
2442
sage: G.cosets(gap(3))
2443
Traceback (most recent call last):
2444
...
2445
TypeError: 3 is not a permutation group
2446
2447
The subgroup is verified as a subgroup of ``self``. ::
2448
2449
sage: A = AlternatingGroup(3)
2450
sage: G = SymmetricGroup(3)
2451
sage: S = G.subgroup([G("(1,2)")])
2452
sage: A.cosets(S)
2453
Traceback (most recent call last):
2454
...
2455
ValueError: Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2)] is not a subgroup of Alternating group of order 3!/2 as a permutation group
2456
2457
AUTHOR:
2458
2459
- Rob Beezer (2011-01-31)
2460
"""
2461
from copy import copy
2462
from sage.categories.finite_permutation_groups import FinitePermutationGroups
2463
2464
if not side in ['right','left']:
2465
raise ValueError("side should be 'right' or 'left', not %s" % side)
2466
if not S in FinitePermutationGroups():
2467
raise TypeError("%s is not a permutation group" % S)
2468
if not S.is_subgroup(self):
2469
raise ValueError("%s is not a subgroup of %s" % (S, self))
2470
2471
group = copy(self.list())
2472
group.sort()
2473
subgroup = [self(s) for s in S.list()]
2474
subgroup.sort()
2475
decomposition = []
2476
while group:
2477
rep = group[0]
2478
if side == 'right':
2479
coset = [e*rep for e in subgroup]
2480
if side == 'left':
2481
coset = [rep*e for e in subgroup]
2482
for e in coset:
2483
group.remove(e)
2484
decomposition.append(coset)
2485
return decomposition
2486
2487
def normalizer(self, g):
2488
"""
2489
Returns the normalizer of ``g`` in ``self``.
2490
2491
EXAMPLES::
2492
2493
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]])
2494
sage: g = G([(1,3)])
2495
sage: G.normalizer(g)
2496
Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,3)]
2497
sage: g = G([(1,2,3,4)])
2498
sage: G.normalizer(g)
2499
Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,2,3,4), (1,3)(2,4)]
2500
sage: H = G.subgroup([G([(1,2,3,4)])])
2501
sage: G.normalizer(H)
2502
Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,2,3,4), (1,3)(2,4)]
2503
"""
2504
return self.subgroup(gap_group=self._gap_().Normalizer(g))
2505
2506
def centralizer(self, g):
2507
"""
2508
Returns the centralizer of ``g`` in ``self``.
2509
2510
EXAMPLES::
2511
2512
sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]])
2513
sage: g = G([(1,3)])
2514
sage: G.centralizer(g)
2515
Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,3)]
2516
sage: g = G([(1,2,3,4)])
2517
sage: G.centralizer(g)
2518
Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2,3,4)]
2519
sage: H = G.subgroup([G([(1,2,3,4)])])
2520
sage: G.centralizer(H)
2521
Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2,3,4)]
2522
"""
2523
return self.subgroup(gap_group=self._gap_().Centralizer(g))
2524
2525
def isomorphism_type_info_simple_group(self):
2526
"""
2527
If the group is simple, then this returns the name of the group.
2528
2529
EXAMPLES::
2530
2531
sage: G = CyclicPermutationGroup(5)
2532
sage: G.isomorphism_type_info_simple_group()
2533
rec( series := "Z", parameter := 5, name := "Z(5)" )
2534
2535
TESTS: This shows that the issue at trac ticket 7360 is fixed::
2536
2537
sage: G = KleinFourGroup()
2538
sage: G.is_simple()
2539
False
2540
sage: G.isomorphism_type_info_simple_group()
2541
Traceback (most recent call last):
2542
...
2543
TypeError: Group must be simple.
2544
"""
2545
if self.is_simple():
2546
info = self._gap_().IsomorphismTypeInfoFiniteSimpleGroup()
2547
return info
2548
else:
2549
raise TypeError, "Group must be simple."
2550
2551
###################### Boolean tests #####################
2552
2553
def is_abelian(self):
2554
"""
2555
Return ``True`` if this group is abelian.
2556
2557
EXAMPLES::
2558
2559
sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)'])
2560
sage: G.is_abelian()
2561
False
2562
sage: G = PermutationGroup(['(1,2,3)(4,5)'])
2563
sage: G.is_abelian()
2564
True
2565
"""
2566
return self._gap_().IsAbelian().bool()
2567
2568
def is_commutative(self):
2569
"""
2570
Return ``True`` if this group is commutative.
2571
2572
EXAMPLES::
2573
2574
sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)'])
2575
sage: G.is_commutative()
2576
False
2577
sage: G = PermutationGroup(['(1,2,3)(4,5)'])
2578
sage: G.is_commutative()
2579
True
2580
"""
2581
return self.is_abelian()
2582
2583
def is_cyclic(self):
2584
"""
2585
Return ``True`` if this group is cyclic.
2586
2587
EXAMPLES::
2588
2589
sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)'])
2590
sage: G.is_cyclic()
2591
False
2592
sage: G = PermutationGroup(['(1,2,3)(4,5)'])
2593
sage: G.is_cyclic()
2594
True
2595
"""
2596
return self._gap_().IsCyclic().bool()
2597
2598
def is_elementary_abelian(self):
2599
"""
2600
Return ``True`` if this group is elementary abelian. An elementary
2601
abelian group is a finite abelian group, where every nontrivial
2602
element has order `p`, where `p` is a prime.
2603
2604
EXAMPLES::
2605
2606
sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)'])
2607
sage: G.is_elementary_abelian()
2608
False
2609
sage: G = PermutationGroup(['(1,2,3)','(4,5,6)'])
2610
sage: G.is_elementary_abelian()
2611
True
2612
"""
2613
return self._gap_().IsElementaryAbelian().bool()
2614
2615
def isomorphism_to(self, right):
2616
"""
2617
Return an isomorphism from ``self`` to ``right`` if the groups
2618
are isomorphic, otherwise ``None``.
2619
2620
INPUT:
2621
2622
2623
- ``self`` - this group
2624
2625
- ``right`` - a permutation group
2626
2627
2628
OUTPUT:
2629
2630
- ``None`` or a morphism of permutation groups.
2631
2632
EXAMPLES::
2633
2634
sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)'])
2635
sage: H = PermutationGroup(['(1,2,3)(4,5)'])
2636
sage: G.isomorphism_to(H) is None
2637
True
2638
sage: G = PermutationGroup([(1,2,3), (2,3)])
2639
sage: H = PermutationGroup([(1,2,4), (1,4)])
2640
sage: G.isomorphism_to(H) # not tested, see below
2641
Permutation group morphism:
2642
From: Permutation Group with generators [(2,3), (1,2,3)]
2643
To: Permutation Group with generators [(1,2,4), (1,4)]
2644
Defn: [(2,3), (1,2,3)] -> [(2,4), (1,2,4)]
2645
2646
TESTS:
2647
2648
Partial check that the output makes some sense::
2649
2650
sage: G.isomorphism_to(H)
2651
Permutation group morphism:
2652
From: Permutation Group with generators [(2,3), (1,2,3)]
2653
To: Permutation Group with generators [(1,2,4), (1,4)]
2654
Defn: [(2,3), (1,2,3)] -> [...]
2655
"""
2656
current_randstate().set_seed_gap()
2657
if not isinstance(right, PermutationGroup_generic):
2658
raise TypeError, "right must be a permutation group"
2659
2660
iso = self._gap_().IsomorphismGroups(right)
2661
if str(iso) == "fail":
2662
return None
2663
2664
dsts = [right(iso.Image(x), check=False) for x in self.gens()]
2665
2666
from permgroup_morphism import PermutationGroupMorphism_im_gens
2667
return PermutationGroupMorphism_im_gens(self, right, dsts)
2668
2669
def is_isomorphic(self, right):
2670
"""
2671
Return ``True`` if the groups are isomorphic.
2672
2673
INPUT:
2674
2675
2676
- ``self`` - this group
2677
2678
- ``right`` - a permutation group
2679
2680
2681
OUTPUT:
2682
2683
- boolean; ``True`` if ``self`` and ``right`` are isomorphic groups;
2684
``False`` otherwise.
2685
2686
EXAMPLES::
2687
2688
sage: v = ['(1,2,3)(4,5)', '(1,2,3,4,5)']
2689
sage: G = PermutationGroup(v)
2690
sage: H = PermutationGroup(['(1,2,3)(4,5)'])
2691
sage: G.is_isomorphic(H)
2692
False
2693
sage: G.is_isomorphic(G)
2694
True
2695
sage: G.is_isomorphic(PermutationGroup(list(reversed(v))))
2696
True
2697
"""
2698
if not isinstance(right, PermutationGroup_generic):
2699
raise TypeError, "right must be a permutation group"
2700
iso = self._gap_().IsomorphismGroups(right)
2701
return str(iso) != 'fail'
2702
2703
def is_monomial(self):
2704
"""
2705
Returns ``True`` if the group is monomial. A finite group is monomial
2706
if every irreducible complex character is induced from a linear
2707
character of a subgroup.
2708
2709
EXAMPLES::
2710
2711
sage: G = PermutationGroup(['(1,2,3)(4,5)'])
2712
sage: G.is_monomial()
2713
True
2714
"""
2715
return self._gap_().IsMonomialGroup().bool()
2716
2717
def is_nilpotent(self):
2718
"""
2719
Return ``True`` if this group is nilpotent.
2720
2721
EXAMPLES::
2722
2723
sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)'])
2724
sage: G.is_nilpotent()
2725
False
2726
sage: G = PermutationGroup(['(1,2,3)(4,5)'])
2727
sage: G.is_nilpotent()
2728
True
2729
"""
2730
return self._gap_().IsNilpotent().bool()
2731
2732
def is_normal(self, other):
2733
"""
2734
Return ``True`` if this group is a normal subgroup of ``other``.
2735
2736
EXAMPLES::
2737
2738
sage: AlternatingGroup(4).is_normal(SymmetricGroup(4))
2739
True
2740
sage: H = PermutationGroup(['(1,2,3)(4,5)'])
2741
sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)'])
2742
sage: H.is_normal(G)
2743
False
2744
"""
2745
if not(self.is_subgroup(other)):
2746
raise TypeError("%s must be a subgroup of %s"%(self, other))
2747
return other._gap_().IsNormal(self).bool()
2748
2749
def is_perfect(self):
2750
"""
2751
Return ``True`` if this group is perfect. A group is perfect if it
2752
equals its derived subgroup.
2753
2754
EXAMPLES::
2755
2756
sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)'])
2757
sage: G.is_perfect()
2758
False
2759
sage: G = PermutationGroup(['(1,2,3)(4,5)'])
2760
sage: G.is_perfect()
2761
False
2762
"""
2763
return self._gap_().IsPerfectGroup().bool()
2764
2765
def is_pgroup(self):
2766
"""
2767
Returns ``True`` if this group is a `p`-group. A finite group is
2768
a `p`-group if its order is of the form `p^n` for a prime integer
2769
`p` and a nonnegative integer `n`.
2770
2771
EXAMPLES::
2772
2773
sage: G = PermutationGroup(['(1,2,3,4,5)'])
2774
sage: G.is_pgroup()
2775
True
2776
"""
2777
return self._gap_().IsPGroup().bool()
2778
2779
def is_polycyclic(self):
2780
r"""
2781
Return ``True`` if this group is polycyclic. A group is polycyclic if
2782
it has a subnormal series with cyclic factors. (For finite groups,
2783
this is the same as if the group is solvable - see
2784
``is_solvable``.)
2785
2786
EXAMPLES::
2787
2788
sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)'])
2789
sage: G.is_polycyclic()
2790
False
2791
sage: G = PermutationGroup(['(1,2,3)(4,5)'])
2792
sage: G.is_polycyclic()
2793
True
2794
"""
2795
return self._gap_().IsPolycyclicGroup().bool()
2796
2797
def is_simple(self):
2798
"""
2799
Returns ``True`` if the group is simple. A group is simple if it has no
2800
proper normal subgroups.
2801
2802
EXAMPLES::
2803
2804
sage: G = PermutationGroup(['(1,2,3)(4,5)'])
2805
sage: G.is_simple()
2806
False
2807
"""
2808
return self._gap_().IsSimpleGroup().bool()
2809
2810
def is_solvable(self):
2811
"""
2812
Returns ``True`` if the group is solvable.
2813
2814
EXAMPLES::
2815
2816
sage: G = PermutationGroup(['(1,2,3)(4,5)'])
2817
sage: G.is_solvable()
2818
True
2819
"""
2820
return self._gap_().IsSolvableGroup().bool()
2821
2822
def is_subgroup(self, other):
2823
"""
2824
Returns ``True`` if ``self`` is a subgroup of ``other``.
2825
2826
EXAMPLES::
2827
2828
sage: G = AlternatingGroup(5)
2829
sage: H = SymmetricGroup(5)
2830
sage: G.is_subgroup(H)
2831
True
2832
"""
2833
return all((x in other) for x in self.gens())
2834
2835
def is_supersolvable(self):
2836
"""
2837
Returns ``True`` if the group is supersolvable. A finite group is
2838
supersolvable if it has a normal series with cyclic factors.
2839
2840
EXAMPLES::
2841
2842
sage: G = PermutationGroup(['(1,2,3)(4,5)'])
2843
sage: G.is_supersolvable()
2844
True
2845
"""
2846
return self._gap_().IsSupersolvableGroup().bool()
2847
2848
def non_fixed_points(self):
2849
r"""
2850
Returns the list of points not fixed by ``self``, i.e., the subset
2851
of ``self.domain()`` moved by some element of ``self``.
2852
2853
EXAMPLES::
2854
2855
sage: G = PermutationGroup([[(3,4,5)],[(7,10)]])
2856
sage: G.non_fixed_points()
2857
[3, 4, 5, 7, 10]
2858
sage: G = PermutationGroup([[(2,3,6)],[(9,)]]) # note: 9 is fixed
2859
sage: G.non_fixed_points()
2860
[2, 3, 6]
2861
"""
2862
pnts = set()
2863
for gens in self.gens():
2864
for cycles in gens.cycle_tuples():
2865
for thispnt in cycles:
2866
if thispnt not in pnts:
2867
pnts.add(thispnt)
2868
return sorted(pnts)
2869
2870
def fixed_points(self):
2871
r"""
2872
Returns the list of points fixed by ``self``, i.e., the subset
2873
of ``.domain()`` not moved by any element of ``self``.
2874
2875
EXAMPLES::
2876
2877
sage: G=PermutationGroup([(1,2,3)])
2878
sage: G.fixed_points()
2879
[]
2880
sage: G=PermutationGroup([(1,2,3),(5,6)])
2881
sage: G.fixed_points()
2882
[4]
2883
sage: G=PermutationGroup([[(1,4,7)],[(4,3),(6,7)]])
2884
sage: G.fixed_points()
2885
[2, 5]
2886
"""
2887
non_fixed_points = self.non_fixed_points()
2888
return [i for i in self.domain() if i not in non_fixed_points]
2889
2890
def is_transitive(self, domain=None):
2891
"""
2892
Returns ``True`` if ``self`` acts transitively on ``domain``.
2893
A group $G$ acts transitively on set $S$ if for all $x,y\in S$
2894
there is some $g\in G$ such that $x^g=y$.
2895
2896
EXAMPLES::
2897
2898
sage: G = SymmetricGroup(5)
2899
sage: G.is_transitive()
2900
True
2901
sage: G = PermutationGroup(['(1,2)(3,4)(5,6)'])
2902
sage: G.is_transitive()
2903
False
2904
2905
::
2906
2907
sage: G = PermutationGroup([[(1,2,3,4,5)],[(1,2)]]) #S_5 on [1..5]
2908
sage: G.is_transitive([1,4,5])
2909
True
2910
sage: G.is_transitive([2..6])
2911
False
2912
sage: G.is_transitive(G.non_fixed_points())
2913
True
2914
sage: H = PermutationGroup([[(1,2,3)],[(4,5,6)]])
2915
sage: H.is_transitive(H.non_fixed_points())
2916
False
2917
2918
Note that this differs from the definition in GAP, where
2919
``IsTransitive`` returns whether the group is transitive on the
2920
set of points moved by the group.
2921
2922
::
2923
2924
sage: G = PermutationGroup([(2,3)])
2925
sage: G.is_transitive()
2926
False
2927
sage: gap(G).IsTransitive()
2928
true
2929
"""
2930
#If the domain is not a subset of self.domain(), then the
2931
#action isn't transitive.
2932
try:
2933
domain = self._domain_gap(domain)
2934
except ValueError:
2935
return False
2936
2937
return self._gap_().IsTransitive(domain).bool()
2938
2939
2940
def is_primitive(self, domain=None):
2941
r"""
2942
Returns ``True`` if ``self`` acts primitively on ``domain``.
2943
A group $G$ acts primitively on a set $S$ if
2944
2945
1. $G$ acts transitively on $S$ and
2946
2947
2. the action induces no non-trivial block system on $S$.
2948
2949
INPUT:
2950
2951
- ``domain`` (optional)
2952
2953
EXAMPLES:
2954
2955
By default, test for primitivity of ``self`` on its domain.
2956
2957
sage: G = PermutationGroup([[(1,2,3,4)],[(1,2)]])
2958
sage: G.is_primitive()
2959
True
2960
sage: G = PermutationGroup([[(1,2,3,4)],[(2,4)]])
2961
sage: G.is_primitive()
2962
False
2963
2964
You can specify a domain on which to test primitivity::
2965
2966
sage: G = PermutationGroup([[(1,2,3,4)],[(2,4)]])
2967
sage: G.is_primitive([1..4])
2968
False
2969
sage: G.is_primitive([1,2,3])
2970
True
2971
sage: G = PermutationGroup([[(3,4,5,6)],[(3,4)]]) #S_4 on [3..6]
2972
sage: G.is_primitive(G.non_fixed_points())
2973
True
2974
2975
"""
2976
#If the domain is not a subset of self.domain(), then the
2977
#action isn't primitive.
2978
try:
2979
domain = self._domain_gap(domain)
2980
except ValueError:
2981
return False
2982
2983
return self._gap_().IsPrimitive(domain).bool()
2984
2985
def is_semi_regular(self, domain=None):
2986
r"""
2987
Returns ``True`` if ``self`` acts semi-regularly on ``domain``.
2988
A group $G$ acts semi-regularly on a set $S$ if the point
2989
stabilizers of $S$ in $G$ are trivial.
2990
2991
``domain`` is optional and may take several forms. See examples.
2992
2993
EXAMPLES::
2994
2995
sage: G = PermutationGroup([[(1,2,3,4)]])
2996
sage: G.is_semi_regular()
2997
True
2998
sage: G = PermutationGroup([[(1,2,3,4)],[(5,6)]])
2999
sage: G.is_semi_regular()
3000
False
3001
3002
You can pass in a domain to test semi-regularity::
3003
3004
sage: G = PermutationGroup([[(1,2,3,4)],[(5,6)]])
3005
sage: G.is_semi_regular([1..4])
3006
True
3007
sage: G.is_semi_regular(G.non_fixed_points())
3008
False
3009
3010
"""
3011
try:
3012
domain = self._domain_gap(domain)
3013
except ValueError:
3014
return False
3015
return self._gap_().IsSemiRegular(domain).bool()
3016
3017
def is_regular(self, domain=None):
3018
r"""
3019
Returns ``True`` if ``self`` acts regularly on ``domain``.
3020
A group $G$ acts regularly on a set $S$ if
3021
3022
1. $G$ acts transitively on $S$ and
3023
2. $G$ acts semi-regularly on $S$.
3024
3025
EXAMPLES::
3026
3027
sage: G = PermutationGroup([[(1,2,3,4)]])
3028
sage: G.is_regular()
3029
True
3030
sage: G = PermutationGroup([[(1,2,3,4)],[(5,6)]])
3031
sage: G.is_regular()
3032
False
3033
3034
You can pass in a domain on which to test regularity::
3035
3036
sage: G = PermutationGroup([[(1,2,3,4)],[(5,6)]])
3037
sage: G.is_regular([1..4])
3038
True
3039
sage: G.is_regular(G.non_fixed_points())
3040
False
3041
3042
"""
3043
try:
3044
domain = self._domain_gap(domain)
3045
except ValueError:
3046
return False
3047
return self._gap_().IsRegular(domain).bool()
3048
3049
3050
def normalizes(self, other):
3051
r"""
3052
Returns ``True`` if the group ``other`` is normalized by ``self``.
3053
Wraps GAP's ``IsNormal`` function.
3054
3055
A group `G` normalizes a group `U` if and only if for every
3056
`g \in G` and `u \in U` the element `u^g`
3057
is a member of `U`. Note that `U` need not be a subgroup of `G`.
3058
3059
EXAMPLES::
3060
3061
sage: G = PermutationGroup(['(1,2,3)(4,5)'])
3062
sage: H = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)'])
3063
sage: H.normalizes(G)
3064
False
3065
sage: G = SymmetricGroup(3)
3066
sage: H = PermutationGroup( [ (4,5,6) ] )
3067
sage: G.normalizes(H)
3068
True
3069
sage: H.normalizes(G)
3070
True
3071
3072
In the last example, `G` and `H` are disjoint, so each normalizes the
3073
other.
3074
"""
3075
return self._gap_().IsNormal(other).bool()
3076
3077
############## Series ######################
3078
3079
def composition_series(self):
3080
"""
3081
Return the composition series of this group as a list of
3082
permutation groups.
3083
3084
EXAMPLES:
3085
3086
These computations use pseudo-random numbers, so we set
3087
the seed for reproducible testing.
3088
3089
::
3090
3091
sage: set_random_seed(0)
3092
sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])
3093
sage: G.composition_series() # random output
3094
[Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,3), (1,5,4)], Permutation Group with generators [()]]
3095
sage: G = PermutationGroup([[(1,2,3),(4,5)], [(1,2)]])
3096
sage: CS = G.composition_series()
3097
sage: CS[3]
3098
Subgroup of (Permutation Group with generators [(1,2), (1,2,3)(4,5)]) generated by [()]
3099
"""
3100
current_randstate().set_seed_gap()
3101
CS = self._gap_().CompositionSeries()
3102
return [self.subgroup(gap_group=group) for group in CS]
3103
3104
def derived_series(self):
3105
"""
3106
Return the derived series of this group as a list of permutation
3107
groups.
3108
3109
EXAMPLES:
3110
3111
These computations use pseudo-random numbers, so we set
3112
the seed for reproducible testing.
3113
3114
::
3115
3116
sage: set_random_seed(0)
3117
sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])
3118
sage: G.derived_series() # random output
3119
[Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (2,4)(3,5)]]
3120
"""
3121
current_randstate().set_seed_gap()
3122
DS = self._gap_().DerivedSeries()
3123
return [self.subgroup(gap_group=group) for group in DS]
3124
3125
def lower_central_series(self):
3126
"""
3127
Return the lower central series of this group as a list of
3128
permutation groups.
3129
3130
EXAMPLES:
3131
3132
These computations use pseudo-random numbers, so we set
3133
the seed for reproducible testing.
3134
3135
::
3136
3137
sage: set_random_seed(0)
3138
sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])
3139
sage: G.lower_central_series() # random output
3140
[Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,3), (1,3)(2,4)]]
3141
"""
3142
current_randstate().set_seed_gap()
3143
LCS = self._gap_().LowerCentralSeriesOfGroup()
3144
return [self.subgroup(gap_group=group) for group in LCS]
3145
3146
def molien_series(self):
3147
r"""
3148
Returns the Molien series of a transitive permutation group. The
3149
function
3150
3151
.. math::
3152
3153
M(x) = (1/|G|)\sum_{g\in G} \det(1-x*g)^{-1}
3154
3155
3156
is sometimes called the "Molien series" of `G`. GAP's
3157
``MolienSeries`` is associated to a character of a
3158
group `G`. How are these related? A group `G`, given as a permutation
3159
group on `n` points, has a "natural" representation of dimension `n`,
3160
given by permutation matrices. The Molien series of `G` is the one
3161
associated to that permutation representation of `G` using the above
3162
formula. Character values then count fixed points of the
3163
corresponding permutations.
3164
3165
EXAMPLES::
3166
3167
sage: G = SymmetricGroup(5)
3168
sage: G.molien_series()
3169
1/(-x^15 + x^14 + x^13 - x^10 - x^9 - x^8 + x^7 + x^6 + x^5 - x^2 - x + 1)
3170
sage: G = SymmetricGroup(3)
3171
sage: G.molien_series()
3172
1/(-x^6 + x^5 + x^4 - x^2 - x + 1)
3173
"""
3174
pi = self._gap_().NaturalCharacter()
3175
cc = pi.ConstituentsOfCharacter()
3176
M = cc.Sum().MolienSeries()
3177
3178
R = QQ['x']
3179
nn = M.NumeratorOfRationalFunction()
3180
dd = M.DenominatorOfRationalFunction()
3181
return (R(str(nn).replace("_1","")) /
3182
R(str(dd).replace("_1","")))
3183
3184
def normal_subgroups(self):
3185
"""
3186
Return the normal subgroups of this group as a (sorted in
3187
increasing order) list of permutation groups.
3188
3189
The normal subgroups of `H = PSL(2,7) \\times PSL(2,7)` are
3190
`1`, two copies of `PSL(2,7)` and `H`
3191
itself, as the following example shows.
3192
3193
EXAMPLES::
3194
3195
sage: G = PSL(2,7)
3196
sage: D = G.direct_product(G)
3197
sage: H = D[0]
3198
sage: NH = H.normal_subgroups()
3199
sage: len(NH)
3200
4
3201
sage: NH[1].is_isomorphic(G)
3202
True
3203
sage: NH[2].is_isomorphic(G)
3204
True
3205
"""
3206
NS = self._gap_().NormalSubgroups()
3207
return [self.subgroup(gap_group=group) for group in NS]
3208
3209
def poincare_series(self, p=2, n=10):
3210
"""
3211
Returns the Poincare series of `G \mod p` (`p \geq 2` must be a
3212
prime), for `n` large. In other words, if you input a finite
3213
group `G`, a prime `p`, and a positive integer `n`, it returns a
3214
quotient of polynomials `f(x) = P(x) / Q(x)` whose coefficient of
3215
`x^k` equals the rank of the vector space
3216
`H_k(G, \ZZ / p \ZZ)`, for all `k` in the
3217
range `1 \leq k \leq n`.
3218
3219
REQUIRES: GAP package HAP (in gap_packages-\*.spkg).
3220
3221
EXAMPLES::
3222
3223
sage: G = SymmetricGroup(5)
3224
sage: G.poincare_series(2,10) # optional - gap_packages
3225
(x^2 + 1)/(x^4 - x^3 - x + 1)
3226
sage: G = SymmetricGroup(3)
3227
sage: G.poincare_series(2,10) # optional - gap_packages
3228
1/(-x + 1)
3229
3230
AUTHORS:
3231
3232
- David Joyner and Graham Ellis
3233
"""
3234
if not is_package_installed('gap_packages'):
3235
raise RuntimeError, "You must install the optional gap_packages package."
3236
load_hap()
3237
from sage.rings.arith import is_prime
3238
if not (p == 0 or is_prime(p)):
3239
raise ValueError, "p must be 0 or prime"
3240
3241
ff = self._gap_().PoincareSeriesPrimePart(p, n)
3242
R = QQ['x']
3243
nn = ff.NumeratorOfRationalFunction()
3244
dd = ff.DenominatorOfRationalFunction()
3245
return (R(str(nn).replace('x_1', 'x')) /
3246
R(str(dd).replace('x_1', 'x')))
3247
3248
3249
def sylow_subgroup(self, p):
3250
"""
3251
Returns a Sylow `p`-subgroup of the finite group `G`, where `p` is a
3252
prime. This is a `p`-subgroup of `G` whose index in `G` is coprime to
3253
`p`. Wraps the GAP function ``SylowSubgroup``.
3254
3255
EXAMPLES::
3256
3257
sage: G = PermutationGroup(['(1,2,3)', '(2,3)'])
3258
sage: G.sylow_subgroup(2)
3259
Subgroup of (Permutation Group with generators [(2,3), (1,2,3)]) generated by [(2,3)]
3260
sage: G.sylow_subgroup(5)
3261
Subgroup of (Permutation Group with generators [(2,3), (1,2,3)]) generated by [()]
3262
3263
TESTS:
3264
3265
Implementation details should not prevent us from computing
3266
large subgroups (trac #5491)::
3267
3268
sage: PSL(10,2).sylow_subgroup(7)
3269
Subgroup of...
3270
3271
"""
3272
return self.subgroup(gap_group=self._gap_().SylowSubgroup(p))
3273
3274
def upper_central_series(self):
3275
"""
3276
Return the upper central series of this group as a list of
3277
permutation groups.
3278
3279
EXAMPLES:
3280
3281
These computations use pseudo-random numbers, so we set
3282
the seed for reproducible testing::
3283
3284
sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])
3285
sage: G.upper_central_series()
3286
[Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()]]
3287
"""
3288
current_randstate().set_seed_gap()
3289
UCS = self._gap_().UpperCentralSeriesOfGroup()
3290
return [self.subgroup(gap_group=group) for group in UCS]
3291
3292
class PermutationGroup_subgroup(PermutationGroup_generic):
3293
"""
3294
Subgroup subclass of ``PermutationGroup_generic``, so instance methods
3295
are inherited.
3296
3297
EXAMPLES::
3298
3299
sage: G = CyclicPermutationGroup(4)
3300
sage: gens = G.gens()
3301
sage: H = DihedralGroup(4)
3302
sage: H.subgroup(gens)
3303
Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)]
3304
sage: K = H.subgroup(gens)
3305
sage: K.list()
3306
[(), (1,2,3,4), (1,3)(2,4), (1,4,3,2)]
3307
sage: K.ambient_group()
3308
Dihedral group of order 8 as a permutation group
3309
sage: K.gens()
3310
[(1,2,3,4)]
3311
"""
3312
def __init__(self, ambient, gens=None, gap_group=None, domain=None,
3313
category=None, canonicalize=True, check=True):
3314
r"""
3315
Initialization method for the
3316
``PermutationGroup_subgroup`` class.
3317
3318
INPUTS:
3319
3320
- ``ambient`` - the ambient group from which to construct this
3321
subgroup
3322
3323
- ``gens`` - the generators of the subgroup
3324
3325
- ``from_group`` - ``True``: subgroup is generated from a Gap
3326
string representation of the generators (default: ``False``)
3327
3328
- ``check`` - ``True``: checks if ``gens`` are indeed elements of the
3329
ambient group
3330
3331
- ``canonicalize`` - boolean (default: ``True``); if ``True``, sort
3332
generators and remove duplicates
3333
3334
EXAMPLES:
3335
3336
An example involving the dihedral group on four elements.
3337
`D_8` contains a cyclic subgroup or order four::
3338
3339
sage: G = DihedralGroup(4)
3340
sage: H = CyclicPermutationGroup(4)
3341
sage: gens = H.gens(); gens
3342
[(1,2,3,4)]
3343
sage: S = G.subgroup(gens)
3344
sage: S
3345
Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)]
3346
sage: S.list()
3347
[(), (1,2,3,4), (1,3)(2,4), (1,4,3,2)]
3348
sage: S.ambient_group()
3349
Dihedral group of order 8 as a permutation group
3350
3351
However, `D_8` does not contain a cyclic subgroup of order
3352
three::
3353
3354
sage: G = DihedralGroup(4)
3355
sage: H = CyclicPermutationGroup(3)
3356
sage: gens = H.gens()
3357
sage: S = PermutationGroup_subgroup(G,list(gens))
3358
Traceback (most recent call last):
3359
...
3360
TypeError: each generator must be in the ambient group
3361
"""
3362
if not isinstance(ambient, PermutationGroup_generic):
3363
raise TypeError, "ambient (=%s) must be perm group."%ambient
3364
if domain is None:
3365
domain = ambient.domain()
3366
if category is None:
3367
category = ambient.category()
3368
PermutationGroup_generic.__init__(self, gens=gens, gap_group=gap_group, domain=domain,
3369
category=category, canonicalize=canonicalize)
3370
3371
self._ambient_group = ambient
3372
if check:
3373
for g in self.gens():
3374
if g not in ambient:
3375
raise TypeError, "each generator must be in the ambient group"
3376
3377
def __cmp__(self, other):
3378
r"""
3379
Compare ``self`` and ``other``.
3380
3381
First, ``self`` and ``other`` are compared as permutation
3382
groups, see :method:`PermutationGroup_generic.__cmp__`.
3383
Second, if both are equal, the ambient groups are compared,
3384
where (if necessary) ``other`` is considered a subgroup of
3385
itself.
3386
3387
EXAMPLES::
3388
3389
sage: G=SymmetricGroup(6)
3390
sage: G1=G.subgroup([G((1,2,3,4,5)),G((1,2))])
3391
sage: G2=G.subgroup([G((1,2,3,4)),G((1,2))])
3392
sage: K=G2.subgroup([G2((1,2,3))])
3393
sage: H=G1.subgroup([G1(())])
3394
3395
``H`` is subgroup of ``K``, and therefore we have::
3396
3397
sage: H<K
3398
True
3399
sage: K<H
3400
False
3401
3402
In the next example, both ``H`` and ``H2`` are trivial
3403
groups, but the ambient group of ``H2`` is strictly contained
3404
in the ambient group of ``H``, and thus we obtain::
3405
3406
sage: H2=G2.subgroup([G2(())])
3407
sage: H2<H
3408
True
3409
3410
Of course, ``G`` as a permutation group and ``G`` considered
3411
as sub-group of itself are different objects. But they
3412
compare equal, both when considered as permutation groups
3413
or permutation subgroups::
3414
3415
sage: G3 = G.subgroup([G((1,2,3,4,5,6)),G((1,2))])
3416
sage: G
3417
Symmetric group of order 6! as a permutation group
3418
sage: G3
3419
Subgroup of (Symmetric group of order 6! as a permutation group) generated by [(1,2), (1,2,3,4,5,6)]
3420
sage: G is G3
3421
False
3422
sage: G == G3 # as permutation groups
3423
True
3424
sage: G3 == G # as permutation subgroups
3425
True
3426
3427
TESTS::
3428
3429
sage: G = SymmetricGroup(4)
3430
sage: G.subgroup([G((1,2,3))]) == G.subgroup([G((2,3,1))])
3431
True
3432
sage: G.subgroup([G((1,2,3))]) == G.subgroup([G((1,3,2))])
3433
True
3434
3435
"""
3436
if self is other:
3437
return 0
3438
if not isinstance(other, PermutationGroup_generic):
3439
return -1
3440
c = PermutationGroup_generic.__cmp__(self, other)
3441
if c:
3442
return c
3443
if hasattr(other, 'ambient_group'):
3444
o_ambient = other.ambient_group()
3445
else:
3446
o_ambient = other
3447
return cmp(self.ambient_group(), o_ambient)
3448
3449
def _repr_(self):
3450
r"""
3451
Returns a string representation / description of the permutation
3452
subgroup.
3453
3454
EXAMPLES:
3455
3456
An example involving the dihedral group on four elements,
3457
`D_8`::
3458
3459
sage: G = DihedralGroup(4)
3460
sage: H = CyclicPermutationGroup(4)
3461
sage: gens = H.gens()
3462
sage: S = PermutationGroup_subgroup(G, list(gens))
3463
sage: S
3464
Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)]
3465
sage: S._repr_()
3466
'Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)]'
3467
"""
3468
s = "Subgroup of (%s) generated by %s"%(self.ambient_group(), self.gens())
3469
return s
3470
3471
def _latex_(self):
3472
r"""
3473
Return LaTeX representation of this group.
3474
3475
EXAMPLES:
3476
3477
An example involving the dihedral group on four elements,
3478
`D_8`::
3479
3480
sage: G = DihedralGroup(4)
3481
sage: H = CyclicPermutationGroup(4)
3482
sage: gens = H.gens()
3483
sage: S = PermutationGroup_subgroup(G, list(gens))
3484
sage: latex(S)
3485
Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)]
3486
sage: S._latex_()
3487
'Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)]'
3488
"""
3489
return self._repr_()
3490
3491
3492
def ambient_group(self):
3493
"""
3494
Return the ambient group related to ``self``.
3495
3496
EXAMPLES:
3497
3498
An example involving the dihedral group on four elements,
3499
`D_8`::
3500
3501
sage: G = DihedralGroup(4)
3502
sage: H = CyclicPermutationGroup(4)
3503
sage: gens = H.gens()
3504
sage: S = PermutationGroup_subgroup(G, list(gens))
3505
sage: S.ambient_group()
3506
Dihedral group of order 8 as a permutation group
3507
sage: S.ambient_group() == G
3508
True
3509
"""
3510
return self._ambient_group
3511
3512
3513
def is_normal(self, other=None):
3514
"""
3515
Return ``True`` if this group is a normal subgroup of
3516
``other``. If ``other`` is not specified, then it is assumed
3517
to be the ambient group.
3518
3519
EXAMPLES::
3520
3521
sage: S = SymmetricGroup(['a','b','c'])
3522
sage: H = S.subgroup([('a', 'b', 'c')]); H
3523
Subgroup of (Symmetric group of order 3! as a permutation group) generated by [('a','b','c')]
3524
sage: H.is_normal()
3525
True
3526
3527
"""
3528
if other is None:
3529
other = self.ambient_group()
3530
return PermutationGroup_generic.is_normal(self, other)
3531
3532
3533