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