Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/groups/matrix_gps/matrix_group.py
4058 views
1
"""
2
Matrix Groups
3
4
AUTHORS:
5
6
- William Stein: initial version
7
8
- David Joyner (2006-03-15): degree, base_ring, _contains_, list,
9
random, order methods; examples
10
11
- William Stein (2006-12): rewrite
12
13
- David Joyner (2007-12): Added invariant_generators (with Martin
14
Albrecht and Simon King)
15
16
- David Joyner (2008-08): Added module_composition_factors (interface
17
to GAP's MeatAxe implementation) and as_permutation_group (returns
18
isomorphic PermutationGroup).
19
20
- Simon King (2010-05): Improve invariant_generators by using GAP
21
for the construction of the Reynolds operator in Singular.
22
23
This class is designed for computing with matrix groups defined by
24
a (relatively small) finite set of generating matrices.
25
26
EXAMPLES::
27
28
sage: F = GF(3)
29
sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F, 2, [1,1,0,1])]
30
sage: G = MatrixGroup(gens)
31
sage: G.conjugacy_class_representatives()
32
[
33
[1 0]
34
[0 1],
35
[0 1]
36
[2 1],
37
[0 1]
38
[2 2],
39
[0 2]
40
[1 1],
41
[0 2]
42
[1 2],
43
[0 1]
44
[2 0],
45
[2 0]
46
[0 2]
47
]
48
49
Loading, saving, ... works::
50
51
sage: G = GL(2,5); G
52
General Linear Group of degree 2 over Finite Field of size 5
53
sage: TestSuite(G).run()
54
55
sage: g = G.1; g
56
[4 1]
57
[4 0]
58
sage: TestSuite(g).run()
59
60
We test that #9437 is fixed::
61
62
sage: len(list(SL(2, Zmod(4))))
63
48
64
"""
65
66
##############################################################################
67
# Copyright (C) 2006 David Joyner and William Stein <[email protected]>
68
#
69
# Distributed under the terms of the GNU General Public License (GPL)
70
#
71
# The full text of the GPL is available at:
72
#
73
# http://www.gnu.org/licenses/
74
##############################################################################
75
76
77
from sage.misc.randstate import current_randstate
78
from sage.categories.groups import Groups
79
from sage.categories.finite_groups import FiniteGroups
80
from sage.structure.parent import Parent
81
from matrix_group_element import MatrixGroupElement
82
from sage.groups.group import Group
83
from sage.rings.all import is_Ring, infinity
84
from sage.rings.finite_rings.constructor import is_FiniteField
85
from sage.interfaces.gap import gap
86
from sage.matrix.all import MatrixSpace, is_MatrixSpace, is_Matrix
87
import sage.rings.integer as integer
88
from sage.misc.latex import latex
89
from sage.structure.sequence import Sequence
90
from sage.structure.sage_object import SageObject
91
from sage.groups.class_function import ClassFunction
92
from sage.misc.decorators import rename_keyword
93
94
#################################################################
95
96
class MatrixGroup_generic(Group):
97
pass
98
99
def is_MatrixGroup(x):
100
"""
101
EXAMPLES::
102
103
sage: from sage.groups.matrix_gps.matrix_group import is_MatrixGroup
104
sage: is_MatrixGroup(MatrixSpace(QQ,3))
105
False
106
sage: is_MatrixGroup(Mat(QQ,3))
107
False
108
sage: is_MatrixGroup(GL(2,ZZ))
109
True
110
sage: is_MatrixGroup(MatrixGroup([matrix(2,[1,1,0,1])]))
111
True
112
"""
113
return isinstance(x, MatrixGroup_generic)
114
115
def MatrixGroup(gens):
116
r"""
117
Return the matrix group with given generators.
118
119
INPUT:
120
121
122
- ``gens`` - list of matrices in a matrix space or
123
matrix group
124
125
126
EXAMPLES::
127
128
sage: F = GF(5)
129
sage: gens = [matrix(F,2,[1,2, -1, 1]), matrix(F,2, [1,1, 0,1])]
130
sage: G = MatrixGroup(gens); G
131
Matrix group over Finite Field of size 5 with 2 generators:
132
[[[1, 2], [4, 1]], [[1, 1], [0, 1]]]
133
134
In the second example, the generators are a matrix over
135
`\ZZ`, a matrix over a finite field, and the integer
136
`2`. Sage determines that they both canonically map to
137
matrices over the finite field, so creates that matrix group
138
there.
139
140
::
141
142
sage: gens = [matrix(2,[1,2, -1, 1]), matrix(GF(7), 2, [1,1, 0,1]), 2]
143
sage: G = MatrixGroup(gens); G
144
Matrix group over Finite Field of size 7 with 3 generators:
145
[[[1, 2], [6, 1]], [[1, 1], [0, 1]], [[2, 0], [0, 2]]]
146
147
Each generator must be invertible::
148
149
sage: G = MatrixGroup([matrix(ZZ,2,[1,2,3,4])])
150
Traceback (most recent call last):
151
...
152
ValueError: each generator must be an invertible matrix but one is not:
153
[1 2]
154
[3 4]
155
156
Some groups aren't supported::
157
158
sage: SL(2, CC).gens()
159
Traceback (most recent call last):
160
...
161
NotImplementedError: Matrix group over Complex Field with 53 bits of precision not implemented.
162
sage: G = SL(0, QQ)
163
Traceback (most recent call last):
164
...
165
ValueError: The degree must be at least 1
166
"""
167
if len(gens) == 0:
168
raise ValueError, "gens must have positive length"
169
try:
170
R = gens[0].base_ring()
171
except AttributeError:
172
raise TypeError, "gens must be a list of matrices"
173
for i in range(len(gens)):
174
if not is_Matrix(gens[i]):
175
try:
176
gens[i] = gens[i].matrix()
177
except AttributeError:
178
pass
179
if is_FiniteField(R):
180
return MatrixGroup_gens_finite_field(gens)
181
else:
182
return MatrixGroup_gens(gens)
183
184
class MatrixGroup_gap(MatrixGroup_generic):
185
Element = MatrixGroupElement
186
187
def __init__(self, n, R, var='a', category = None):
188
"""
189
INPUT:
190
191
192
- ``n`` - the degree
193
194
- ``R`` - the base ring
195
196
- ``var`` - variable used to define field of
197
definition of actual matrices in this group.
198
"""
199
if not is_Ring(R):
200
raise TypeError, "R (=%s) must be a ring"%R
201
202
203
self._var = var
204
self.__n = integer.Integer(n)
205
if self.__n <= 0:
206
raise ValueError, "The degree must be at least 1"
207
self.__R = R
208
209
if self.base_ring().is_finite():
210
default_category = FiniteGroups()
211
else:
212
# Should we ask GAP whether the group is finite?
213
default_category = Groups()
214
if category is None:
215
category = default_category
216
else:
217
assert category.is_subcategory(default_category), \
218
"%s is not a subcategory of %s"%(category, default_category)
219
Parent.__init__(self, category = category)
220
# TODO: inherit from ParentWithBase, once the Group class will
221
# be fully replaced by the Groups() category
222
# ParentWithBase.__init__(self, base, category = category)
223
224
def _gap_(self, G=None):
225
try:
226
return SageObject._gap_(self, G)
227
except TypeError:
228
raise NotImplementedError, "Matrix group over %s not implemented."%self.__R
229
230
def __cmp__(self, H):
231
if not isinstance(H, MatrixGroup_gap):
232
return cmp(type(self), type(H))
233
return cmp(gap(self), gap(H))
234
235
def __call__(self, x):
236
"""
237
EXAMPLES::
238
239
sage: F = GF(5); MS = MatrixSpace(F,2,2)
240
sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])
241
sage: G.matrix_space()
242
Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5
243
sage: G(1)
244
[1 0]
245
[0 1]
246
"""
247
if isinstance(x, self.element_class) and x.parent() is self:
248
return x
249
M = self.matrix_space()(x)
250
g = self.element_class(M, self)
251
if not gap(g) in gap(self):
252
raise TypeError, "no way to coerce element to self."
253
return g
254
255
def _Hom_(self, G, cat=None):
256
if not (cat is None or (cat is G.category() and cat is self.category())):
257
raise TypeError
258
if not is_MatrixGroup(G):
259
raise TypeError, "G (=%s) must be a matrix group."%G
260
import homset
261
return homset.MatrixGroupHomset(self, G)
262
263
def hom(self, x):
264
v = Sequence(x)
265
U = v.universe()
266
if not is_MatrixGroup(U):
267
raise TypeError, "u (=%s) must have universe a matrix group."%U
268
return self.Hom(U)(x)
269
270
def matrix_space(self):
271
"""
272
Return the matrix space corresponding to this matrix group.
273
274
This is a matrix space over the field of definition of this matrix
275
group.
276
277
EXAMPLES::
278
279
sage: F = GF(5); MS = MatrixSpace(F,2,2)
280
sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])
281
sage: G.matrix_space()
282
Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5
283
"""
284
try:
285
return self.__matrix_space
286
except AttributeError:
287
pass
288
self.__matrix_space = MatrixSpace(self.field_of_definition(), self.__n)
289
return self.__matrix_space
290
291
def degree(self):
292
"""
293
Return the degree of this matrix group.
294
295
EXAMPLES::
296
297
sage: SU(5,5).degree()
298
5
299
"""
300
return self.__n
301
302
def field_of_definition(self, var='a'):
303
"""
304
Return a field that contains all the matrices in this matrix
305
group.
306
307
EXAMPLES::
308
309
sage: G = SU(3,GF(5))
310
sage: G.base_ring()
311
Finite Field of size 5
312
sage: G.field_of_definition()
313
Finite Field in a of size 5^2
314
sage: G = GO(4,GF(7),1)
315
sage: G.field_of_definition()
316
Finite Field of size 7
317
sage: G.base_ring()
318
Finite Field of size 7
319
"""
320
return self.__R
321
322
def base_ring(self):
323
"""
324
Return the base ring of this matrix group.
325
326
EXAMPLES::
327
328
sage: GL(2,GF(3)).base_ring()
329
Finite Field of size 3
330
sage: G = SU(3,GF(5))
331
sage: G.base_ring()
332
Finite Field of size 5
333
sage: G.field_of_definition()
334
Finite Field in a of size 5^2
335
"""
336
return self.__R
337
338
base_field = base_ring
339
340
def is_abelian(self):
341
r"""
342
Return True if this group is an abelian group.
343
344
Note: The result is cached, since it tends to get called
345
rather often (e.g. by word_problem) and it's very slow to
346
use the Gap interface every time.
347
348
EXAMPLES::
349
350
sage: SL(1, 17).is_abelian()
351
True
352
sage: SL(2, 17).is_abelian()
353
False
354
"""
355
try:
356
return self.__is_abelian
357
except AttributeError:
358
self.__is_abelian = self._gap_().IsAbelian().bool()
359
return self.__is_abelian
360
361
def is_finite(self):
362
"""
363
Return True if this matrix group is finite.
364
365
EXAMPLES::
366
367
sage: G = GL(2,GF(3))
368
sage: G.is_finite()
369
True
370
sage: SL(2,ZZ).is_finite()
371
False
372
"""
373
if self.base_ring().is_finite():
374
return True
375
return self._gap_().IsFinite().bool()
376
377
def cardinality(self):
378
"""
379
Implements :meth:`EnumeratedSets.ParentMethods.cardinality`.
380
381
EXAMPLES::
382
383
sage: G = Sp(4,GF(3))
384
sage: G.cardinality()
385
51840
386
sage: G = SL(4,GF(3))
387
sage: G.cardinality()
388
12130560
389
sage: F = GF(5); MS = MatrixSpace(F,2,2)
390
sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])]
391
sage: G = MatrixGroup(gens)
392
sage: G.cardinality()
393
480
394
sage: G = MatrixGroup([matrix(ZZ,2,[1,1,0,1])])
395
sage: G.cardinality()
396
+Infinity
397
"""
398
g = self._gap_()
399
if g.IsFinite().bool():
400
return integer.Integer(gap(self).Size())
401
return infinity
402
403
def order(self):
404
"""
405
Backward compatibility alias for :meth:`.cardinality`.
406
407
Might be deprecated in the future.
408
409
EXAMPLES::
410
411
sage: G = Sp(4,GF(3))
412
sage: G.order()
413
51840
414
"""
415
return self.cardinality()
416
417
def __len__(self):
418
"""
419
__len__ has been removed ! to get the number of element in a
420
matrix group, use :meth:`.cardinality`.
421
422
EXAMPLES::
423
424
sage: G = GO(3,GF(5))
425
sage: len(G)
426
Traceback (most recent call last):
427
...
428
AttributeError: __len__ has been removed; use .cardinality() instead
429
430
"""
431
raise AttributeError, "__len__ has been removed; use .cardinality() instead"
432
433
def gens(self):
434
"""
435
Return generators for this matrix group.
436
437
EXAMPLES::
438
439
sage: G = GO(3,GF(5))
440
sage: G.gens()
441
[
442
[2 0 0]
443
[0 3 0]
444
[0 0 1],
445
[0 1 0]
446
[1 4 4]
447
[0 2 1]
448
]
449
"""
450
try:
451
return self.__gens
452
except AttributeError:
453
pass
454
F = self.field_of_definition()
455
gap_gens = list(gap(self).GeneratorsOfGroup())
456
gens = Sequence([self.element_class(g._matrix_(F), self, check=False) for g in gap_gens],
457
cr=True, universe=self, check=False)
458
self.__gens = gens
459
return gens
460
461
def ngens(self):
462
"""
463
Return the number of generators of this linear group.
464
465
EXAMPLES::
466
467
sage: G = GO(3,GF(5))
468
sage: G.ngens()
469
2
470
"""
471
return len(self.gens())
472
473
474
def gen(self, n):
475
"""
476
Return the n-th generator.
477
478
EXAMPLES::
479
480
sage: G = GU(4,GF(5), var='beta')
481
sage: G.gen(0)
482
[ beta 0 0 0]
483
[ 0 1 0 0]
484
[ 0 0 1 0]
485
[ 0 0 0 3*beta]
486
"""
487
return self.gens()[n]
488
489
def as_matrix_group(self):
490
"""
491
Return this group, but as a general matrix group, i.e., throw away
492
the extra structure of general unitary group.
493
494
EXAMPLES::
495
496
sage: G = SU(4,GF(5))
497
sage: G.as_matrix_group()
498
Matrix group over Finite Field in a of size 5^2 with 2 generators:
499
[[[a, 0, 0, 0],
500
[0, 2*a + 3, 0, 0],
501
[0, 0, 4*a + 1, 0],
502
[0, 0, 0, 3*a]],
503
[[1, 0, 4*a + 3, 0],
504
[1, 0, 0, 0],
505
[0, 2*a + 4, 0, 1],
506
[0, 3*a + 1, 0, 0]]]
507
508
::
509
510
sage: G = GO(3,GF(5))
511
sage: G.as_matrix_group()
512
Matrix group over Finite Field of size 5 with 2 generators:
513
[[[2, 0, 0], [0, 3, 0], [0, 0, 1]], [[0, 1, 0], [1, 4, 4], [0, 2, 1]]]
514
"""
515
from sage.groups.matrix_gps.matrix_group import MatrixGroup
516
return MatrixGroup([g.matrix() for g in self.gens()])
517
518
def list(self):
519
"""
520
Return list of all elements of this group.
521
522
Always returns a new list, so it is safe to change the returned
523
list.
524
525
EXAMPLES::
526
527
sage: F = GF(3)
528
sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F, 2, [1,1,0,1])]
529
sage: G = MatrixGroup(gens)
530
sage: G.cardinality()
531
24
532
sage: v = G.list()
533
sage: len(v)
534
24
535
sage: v[:2]
536
[[0 1]
537
[2 0], [0 1]
538
[2 1]]
539
sage: G.list()[0] in G
540
True
541
542
An example over a ring (see trac 5241)::
543
544
sage: M1 = matrix(ZZ,2,[[-1,0],[0,1]])
545
sage: M2 = matrix(ZZ,2,[[1,0],[0,-1]])
546
sage: M3 = matrix(ZZ,2,[[-1,0],[0,-1]])
547
sage: MG = MatrixGroup([M1, M2, M3])
548
sage: MG.list()
549
[[-1 0]
550
[ 0 -1], [-1 0]
551
[ 0 1], [ 1 0]
552
[ 0 -1], [1 0]
553
[0 1]]
554
sage: MG.list()[1]
555
[-1 0]
556
[ 0 1]
557
sage: MG.list()[1].parent()
558
Matrix group over Integer Ring with 3 generators:
559
[[[-1, 0], [0, 1]], [[1, 0], [0, -1]], [[-1, 0], [0, -1]]]
560
561
An example over a field (see trac 10515)::
562
563
sage: gens = [matrix(QQ,2,[1,0,0,1])]
564
sage: MatrixGroup(gens).list()
565
[[1 0]
566
[0 1]]
567
568
Another example over a ring (see trac 9437)::
569
570
sage: len(SL(2, Zmod(4)).list())
571
48
572
573
An error is raised if the group is not finite::
574
575
sage: GL(2,ZZ).list()
576
Traceback (most recent call last):
577
...
578
ValueError: group must be finite
579
"""
580
# We check the cache for the result
581
try:
582
return list(self.__list)
583
except AttributeError:
584
pass
585
if not self.is_finite():
586
raise ValueError, "group must be finite"
587
588
MS = self.matrix_space()
589
R = self.base_ring()
590
if not R.is_field() or not R.is_finite():
591
s = list(self._gap_().Elements())
592
v = [self.element_class(x._matrix_(R), self, check=False) for x in s]
593
self.__list = v
594
return list(v)
595
596
# Get basic properties of the field over which we are working
597
F = self.field_of_definition()
598
n = F.degree()
599
p = F.characteristic()
600
a = F.prime_subfield().multiplicative_generator()
601
b = F.multiplicative_generator()
602
603
# Get string representation of the list of elements of self.
604
# Since the output is usually big, we use a file, which can
605
# easily give us a hundred-times speedup for at all large output.
606
s = self._gap_().Elements().str(use_file=True)
607
s = ''.join(s.split())
608
609
# Replace the two types of gap-style 'power of generator' notation
610
s = s.replace('Z(%s^%s)'%(p,n),'b')
611
s = s.replace('Z(%s)'%p,'a')
612
s = s.replace('^','**')
613
# Then eval the string with a and b set to the corresponding
614
# multiplicative generators.
615
v = eval(s, {'a':a, 'b':b})
616
617
# Finally, create the matrix space in which all these matrices live,
618
# and make each element as a MatrixGroupElement.
619
v = [self.element_class(MS(x), self, check=False) for x in v]
620
self.__list = v
621
return list(v)
622
623
def irreducible_characters(self):
624
"""
625
Returns the list of irreducible characters of the group.
626
627
EXAMPLES::
628
629
sage: G = GL(2,2)
630
sage: G.irreducible_characters()
631
[Character of General Linear Group of degree 2 over Finite Field of size 2,
632
Character of General Linear Group of degree 2 over Finite Field of size 2,
633
Character of General Linear Group of degree 2 over Finite Field of size 2]
634
635
"""
636
current_randstate().set_seed_gap()
637
Irr = self._gap_().Irr()
638
L = []
639
for irr in Irr:
640
L.append(ClassFunction(self,irr))
641
return L
642
643
class MatrixGroup_gap_finite_field(MatrixGroup_gap):
644
"""
645
Python class for matrix groups over a finite field.
646
"""
647
def cardinality(self):
648
"""
649
EXAMPLES::
650
651
sage: G = Sp(4,GF(3))
652
sage: G.cardinality()
653
51840
654
sage: G = SL(4,GF(3))
655
sage: G.cardinality()
656
12130560
657
sage: F = GF(5); MS = MatrixSpace(F,2,2)
658
sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])]
659
sage: G = MatrixGroup(gens)
660
sage: G.cardinality()
661
480
662
sage: G = MatrixGroup([matrix(ZZ,2,[1,1,0,1])])
663
sage: G.cardinality()
664
+Infinity
665
"""
666
return integer.Integer(gap(self).Size())
667
668
def random_element(self):
669
"""
670
Return a random element of this group.
671
672
EXAMPLES::
673
674
sage: G = Sp(4,GF(3))
675
sage: G.random_element() # random
676
[2 1 1 1]
677
[1 0 2 1]
678
[0 1 1 0]
679
[1 0 0 1]
680
sage: G.random_element() in G
681
True
682
683
::
684
685
sage: F = GF(5); MS = MatrixSpace(F,2,2)
686
sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])]
687
sage: G = MatrixGroup(gens)
688
sage: G.random_element() # random
689
[1 3]
690
[0 3]
691
sage: G.random_element() in G
692
True
693
"""
694
# Note: even with fixed random seed, the Random() element
695
# returned by gap does depend on execution order and
696
# architecture. Presumably due to different memory loctions.
697
current_randstate().set_seed_gap()
698
F = self.field_of_definition()
699
return self.element_class(gap(self).Random()._matrix_(F), self, check=False)
700
701
def random(self):
702
"""
703
Deprecated. Use self.random_element() instead.
704
"""
705
raise NotImplementedError, "Deprecated: use random_element() instead"
706
707
708
def __contains__(self, x):
709
"""
710
Return True if `x` is an element of this abelian group.
711
712
EXAMPLES::
713
714
sage: F = GF(5); MS = MatrixSpace(F,2,2)
715
sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])
716
sage: G
717
Matrix group over Finite Field of size 5 with 2 generators:
718
[[[1, 0], [0, 1]], [[1, 2], [3, 4]]]
719
sage: G.cardinality()
720
8
721
sage: G(1)
722
[1 0]
723
[0 1]
724
sage: G.1 in G
725
True
726
sage: 1 in G
727
True
728
sage: [1,2,3,4] in G
729
True
730
sage: matrix(GF(5),2,[1,2,3,5]) in G
731
False
732
sage: G(matrix(GF(5),2,[1,2,3,5]))
733
Traceback (most recent call last):
734
...
735
TypeError: no way to coerce element to self.
736
"""
737
if isinstance(x, self.element_class):
738
if x.parent() == self:
739
return True
740
return gap(x) in gap(self)
741
try:
742
self(x)
743
return True
744
except TypeError:
745
return False
746
747
def conjugacy_class_representatives(self):
748
"""
749
Return a set of representatives for each of the conjugacy classes
750
of the group.
751
752
EXAMPLES::
753
754
sage: G = SU(3,GF(2))
755
sage: len(G.conjugacy_class_representatives())
756
16
757
sage: len(GL(2,GF(3)).conjugacy_class_representatives())
758
8
759
sage: len(GU(2,GF(5)).conjugacy_class_representatives())
760
36
761
"""
762
current_randstate().set_seed_gap()
763
try:
764
return self.__reps
765
except AttributeError:
766
pass
767
G = self._gap_().ConjugacyClasses()
768
reps = list(gap.List(G, 'x -> Representative(x)'))
769
F = self.field_of_definition()
770
self.__reps = Sequence([self(g._matrix_(F)) for g in reps], cr=True, universe=self, check=False)
771
return self.__reps
772
773
def center(self):
774
"""
775
Return the center of this linear group as a matrix group.
776
777
EXAMPLES::
778
779
sage: G = SU(3,GF(2))
780
sage: G.center()
781
Matrix group over Finite Field in a of size 2^2 with 1 generators:
782
[[[a, 0, 0], [0, a, 0], [0, 0, a]]]
783
sage: GL(2,GF(3)).center()
784
Matrix group over Finite Field of size 3 with 1 generators:
785
[[[2, 0], [0, 2]]]
786
sage: GL(3,GF(3)).center()
787
Matrix group over Finite Field of size 3 with 1 generators:
788
[[[2, 0, 0], [0, 2, 0], [0, 0, 2]]]
789
sage: GU(3,GF(2)).center()
790
Matrix group over Finite Field in a of size 2^2 with 1 generators:
791
[[[a + 1, 0, 0], [0, a + 1, 0], [0, 0, a + 1]]]
792
sage: A=Matrix(FiniteField(5), [[2,0,0], [0,3,0], [0,0,1]])
793
sage: B=Matrix(FiniteField(5), [[1,0,0], [0,1,0], [0,1,1]])
794
sage: MatrixGroup([A,B]).center()
795
Matrix group over Finite Field of size 5 with 1 generators:
796
[[[1, 0, 0], [0, 1, 0], [0, 0, 1]]]
797
"""
798
try:
799
return self.__center
800
except AttributeError:
801
pass
802
G = list(self._gap_().Center().GeneratorsOfGroup())
803
from sage.groups.matrix_gps.matrix_group import MatrixGroup
804
if len(G) == 0:
805
self.__center = MatrixGroup([self.one()])
806
else:
807
F = self.field_of_definition()
808
self.__center = MatrixGroup([g._matrix_(F) for g in G])
809
return self.__center
810
811
812
class MatrixGroup_gens(MatrixGroup_gap):
813
"""
814
EXAMPLES:
815
816
A ValueError is raised if one of the generators is not invertible.
817
818
::
819
820
sage: F = GF(5); MS = MatrixSpace(F,2,2)
821
sage: G = MatrixGroup([MS.0])
822
Traceback (most recent call last):
823
...
824
ValueError: each generator must be an invertible matrix but one is not:
825
[1 0]
826
[0 0]
827
"""
828
def __init__(self, gensG, category = None):
829
v = Sequence(gensG, immutable=True)
830
M = v.universe()
831
if not is_MatrixSpace(M):
832
raise TypeError, "universe of sequence (=%s) of generators must be a matrix space"%M
833
if M.nrows() != M.ncols():
834
raise ValueError, "matrices must be square."
835
for x in v:
836
if not x.is_invertible():
837
raise ValueError, "each generator must be an invertible matrix but one is not:\n%s"%x
838
self._gensG = v
839
MatrixGroup_gap.__init__(self, M.nrows(), M.base_ring(), category = category)
840
841
@rename_keyword(deprecated='Sage version 4.6', method="algorithm")
842
def as_permutation_group(self, algorithm=None):
843
r"""
844
Return a permutation group representation for the group.
845
846
In most cases occurring in practice, this is a permutation
847
group of minimal degree (the degree begin determined from
848
orbits under the group action). When these orbits are hard to
849
compute, the procedure can be time-consuming and the degree
850
may not be minimal.
851
852
INPUT:
853
854
- ``algorithm`` -- ``None`` or ``'smaller'``. In the latter
855
case, try harder to find a permutation representation of
856
small degree.
857
858
OUTPUT:
859
860
A permutation group isomorphic to ``self``. The
861
``algorithm='smaller'`` option tries to return an isomorphic
862
group of low degree, but is not guaranteed to find the
863
smallest one.
864
865
EXAMPLES::
866
867
sage: MS = MatrixSpace(GF(2), 5, 5)
868
sage: A = MS([[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0]])
869
sage: G = MatrixGroup([A])
870
sage: G.as_permutation_group()
871
Permutation Group with generators [(1,2)]
872
sage: MS = MatrixSpace( GF(7), 12, 12)
873
sage: GG = gap("ImfMatrixGroup( 12, 3 )")
874
sage: GG.GeneratorsOfGroup().Length()
875
3
876
sage: g1 = MS(eval(str(GG.GeneratorsOfGroup()[1]).replace("\n","")))
877
sage: g2 = MS(eval(str(GG.GeneratorsOfGroup()[2]).replace("\n","")))
878
sage: g3 = MS(eval(str(GG.GeneratorsOfGroup()[3]).replace("\n","")))
879
sage: G = MatrixGroup([g1, g2, g3])
880
sage: G.cardinality()
881
21499084800
882
sage: set_random_seed(0); current_randstate().set_seed_gap()
883
sage: P = G.as_permutation_group()
884
sage: P.cardinality()
885
21499084800
886
sage: P.degree() # random output
887
144
888
sage: set_random_seed(3); current_randstate().set_seed_gap()
889
sage: Psmaller = G.as_permutation_group(algorithm="smaller")
890
sage: Psmaller.cardinality()
891
21499084800
892
sage: Psmaller.degree() # random output
893
108
894
895
In this case, the "smaller" option returned an isomorphic group of
896
lower degree. The above example used GAP's library of irreducible
897
maximal finite ("imf") integer matrix groups to construct the
898
MatrixGroup G over GF(7). The section "Irreducible Maximal Finite
899
Integral Matrix Groups" in the GAP reference manual has more
900
details.
901
"""
902
# Note that the output of IsomorphismPermGroup() depends on
903
# memory locations and will change if you change the order of
904
# doctests and/or architecture
905
from sage.groups.perm_gps.permgroup import PermutationGroup
906
if not self.is_finite():
907
raise NotImplementedError, "Group must be finite."
908
n = self.degree()
909
MS = MatrixSpace(self.base_ring(), n, n)
910
mats = [] # initializing list of mats by which the gens act on self
911
for g in self.gens():
912
p = MS(g.matrix())
913
m = p.rows()
914
mats.append(m)
915
mats_str = str(gap([[list(r) for r in m] for m in mats]))
916
gap.eval("iso:=IsomorphismPermGroup(Group("+mats_str+"))")
917
if algorithm == "smaller":
918
gap.eval("small:= SmallerDegreePermutationRepresentation( Image( iso ) );")
919
C = gap("Image( small )")
920
else:
921
C = gap("Image( iso )")
922
return PermutationGroup(gap_group=C)
923
924
@rename_keyword(deprecated='Sage version 4.6', method="algorithm")
925
def module_composition_factors(self, algorithm=None):
926
r"""
927
Returns a list of triples consisting of [base field, dimension,
928
irreducibility], for each of the Meataxe composition factors
929
modules. The algorithm="verbose" option returns more information, but
930
in Meataxe notation.
931
932
EXAMPLES::
933
934
sage: F=GF(3);MS=MatrixSpace(F,4,4)
935
sage: M=MS(0)
936
sage: M[0,1]=1;M[1,2]=1;M[2,3]=1;M[3,0]=1
937
sage: G = MatrixGroup([M])
938
sage: G.module_composition_factors()
939
[(Finite Field of size 3, 1, True),
940
(Finite Field of size 3, 1, True),
941
(Finite Field of size 3, 2, True)]
942
sage: F = GF(7); MS = MatrixSpace(F,2,2)
943
sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])]
944
sage: G = MatrixGroup(gens)
945
sage: G.module_composition_factors()
946
[(Finite Field of size 7, 2, True)]
947
948
Type "G.module_composition_factors(algorithm='verbose')" to get a
949
more verbose version.
950
951
For more on MeatAxe notation, see
952
http://www.gap-system.org/Manuals/doc/htm/ref/CHAP067.htm
953
"""
954
from sage.misc.sage_eval import sage_eval
955
F = self.base_ring()
956
if not(F.is_finite()):
957
raise NotImplementedError, "Base ring must be finite."
958
q = F.cardinality()
959
gens = self.gens()
960
n = self.degree()
961
MS = MatrixSpace(F,n,n)
962
mats = [] # initializing list of mats by which the gens act on self
963
W = self.matrix_space().row_space()
964
for g in gens:
965
p = MS(g.matrix())
966
m = p.rows()
967
mats.append(m)
968
mats_str = str(gap([[list(r) for r in m] for m in mats]))
969
gap.eval("M:=GModuleByMats("+mats_str+", GF("+str(q)+"))")
970
gap.eval("MCFs := MTX.CompositionFactors( M )")
971
N = eval(gap.eval("Length(MCFs)"))
972
if algorithm == "verbose":
973
print gap.eval('MCFs')+"\n"
974
L = []
975
for i in range(1,N+1):
976
gap.eval("MCF := MCFs[%s]"%i)
977
L.append(tuple([sage_eval(gap.eval("MCF.field")),
978
eval(gap.eval("MCF.dimension")),
979
sage_eval(gap.eval("MCF.IsIrreducible")) ]))
980
return sorted(L)
981
982
def gens(self):
983
"""
984
EXAMPLES::
985
986
sage: F = GF(3); MS = MatrixSpace(F,2,2)
987
sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])]
988
sage: G = MatrixGroup(gens)
989
sage: gens[0] in G
990
True
991
sage: gens = G.gens()
992
sage: gens[0] in G
993
True
994
sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])]
995
996
::
997
998
sage: F = GF(5); MS = MatrixSpace(F,2,2)
999
sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])
1000
sage: G
1001
Matrix group over Finite Field of size 5 with 2 generators:
1002
[[[1, 0], [0, 1]], [[1, 2], [3, 4]]]
1003
sage: G.gens()
1004
[[1 0]
1005
[0 1], [1 2]
1006
[3 4]]
1007
"""
1008
try:
1009
return self.__gens
1010
except AttributeError:
1011
t = Sequence([self.element_class(x, self) for x in self._gensG],
1012
immutable=True, universe=self)
1013
self.__gens = t
1014
return t
1015
1016
def _gap_init_(self):
1017
"""
1018
Returns a string representation of the corresponding GAP object.
1019
1020
EXAMPLES::
1021
1022
sage: F = GF(5); MS = MatrixSpace(F,2,2)
1023
sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])]
1024
sage: G = MatrixGroup(gens)
1025
sage: G._gap_init_() # The variable $sage11 belongs to gap(F) and is somehow random
1026
'Group([[Z(5)^0,Z(5)^1],[Z(5)^2,Z(5)^0]]*One($sage11),[[Z(5)^0,Z(5)^0],[0*Z(5),Z(5)^0]]*One($sage11))'
1027
sage: gap(G._gap_init_())
1028
Group([ [ [ Z(5)^0, Z(5) ], [ Z(5)^2, Z(5)^0 ] ],
1029
[ [ Z(5)^0, Z(5)^0 ], [ 0*Z(5), Z(5)^0 ] ] ])
1030
"""
1031
gens_gap = ','.join([x._gap_init_() for x in self._gensG])
1032
return 'Group(%s)'%gens_gap
1033
1034
def _repr_(self):
1035
"""
1036
EXAMPLES::
1037
1038
sage: F = GF(5); MS = MatrixSpace(F,2,2)
1039
sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])]
1040
sage: G = MatrixGroup(gens)
1041
sage: G
1042
Matrix group over Finite Field of size 5 with 2 generators:
1043
[[[1, 2], [4, 1]], [[1, 1], [0, 1]]]
1044
"""
1045
gns = [x.list() for x in self.gens()]
1046
return "Matrix group over %s with %s generators: \n %s"%(self.base_ring(), self.ngens(), gns)
1047
1048
def _latex_(self):
1049
r"""
1050
EXAMPLES::
1051
1052
sage: F = GF(5); MS = MatrixSpace(F,2,2)
1053
sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])]
1054
sage: G = MatrixGroup(gens)
1055
sage: latex(G)
1056
\left\langle \left(\begin{array}{rr}
1057
1 & 2 \\
1058
4 & 1
1059
\end{array}\right), \left(\begin{array}{rr}
1060
1 & 1 \\
1061
0 & 1
1062
\end{array}\right) \right\rangle
1063
"""
1064
gens = ', '.join([latex(x) for x in self.gens()])
1065
return '\\left\\langle %s \\right\\rangle'%gens
1066
1067
def invariant_generators(self):
1068
"""
1069
Wraps Singular's invariant_algebra_reynolds and invariant_ring
1070
in finvar.lib, with help from Simon King and Martin Albrecht.
1071
Computes generators for the polynomial ring
1072
`F[x_1,\ldots,x_n]^G`, where G in GL(n,F) is a finite
1073
matrix group.
1074
1075
In the "good characteristic" case the polynomials returned form a
1076
minimal generating set for the algebra of G-invariant polynomials.
1077
In the "bad" case, the polynomials returned are primary and
1078
secondary invariants, forming a not necessarily minimal generating
1079
set for the algebra of G-invariant polynomials.
1080
1081
EXAMPLES::
1082
1083
sage: F = GF(7); MS = MatrixSpace(F,2,2)
1084
sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])]
1085
sage: G = MatrixGroup(gens)
1086
sage: G.invariant_generators()
1087
[x1^7*x2 - x1*x2^7, x1^12 - 2*x1^9*x2^3 - x1^6*x2^6 + 2*x1^3*x2^9 + x2^12, x1^18 + 2*x1^15*x2^3 + 3*x1^12*x2^6 + 3*x1^6*x2^12 - 2*x1^3*x2^15 + x2^18]
1088
sage: q = 4; a = 2
1089
sage: MS = MatrixSpace(QQ, 2, 2)
1090
sage: gen1 = [[1/a,(q-1)/a],[1/a, -1/a]]; gen2 = [[1,0],[0,-1]]; gen3 = [[-1,0],[0,1]]
1091
sage: G = MatrixGroup([MS(gen1),MS(gen2),MS(gen3)])
1092
sage: G.cardinality()
1093
12
1094
sage: G.invariant_generators()
1095
[x1^2 + 3*x2^2, x1^6 + 15*x1^4*x2^2 + 15*x1^2*x2^4 + 33*x2^6]
1096
sage: F = GF(5); MS = MatrixSpace(F,2,2)
1097
sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[-1,1]])]
1098
sage: G = MatrixGroup(gens)
1099
sage: G.invariant_generators() # long time (67s on sage.math, 2012)
1100
[x1^20 + x1^16*x2^4 + x1^12*x2^8 + x1^8*x2^12 + x1^4*x2^16 + x2^20, x1^20*x2^4 + x1^16*x2^8 + x1^12*x2^12 + x1^8*x2^16 + x1^4*x2^20]
1101
sage: F=CyclotomicField(8)
1102
sage: z=F.gen()
1103
sage: a=z+1/z
1104
sage: b=z^2
1105
sage: MS=MatrixSpace(F,2,2)
1106
sage: g1=MS([[1/a,1/a],[1/a,-1/a]])
1107
sage: g2=MS([[1,0],[0,b]])
1108
sage: g3=MS([[b,0],[0,1]])
1109
sage: G=MatrixGroup([g1,g2,g3])
1110
sage: G.invariant_generators() # long time (12s on sage.math, 2011)
1111
[x1^8 + 14*x1^4*x2^4 + x2^8,
1112
x1^24 + 10626/1025*x1^20*x2^4 + 735471/1025*x1^16*x2^8 + 2704156/1025*x1^12*x2^12 + 735471/1025*x1^8*x2^16 + 10626/1025*x1^4*x2^20 + x2^24]
1113
1114
AUTHORS:
1115
1116
- David Joyner, Simon King and Martin Albrecht.
1117
1118
REFERENCES:
1119
1120
- Singular reference manual
1121
1122
- B. Sturmfels, "Algorithms in invariant theory", Springer-Verlag, 1993.
1123
1124
- S. King, "Minimal Generating Sets of non-modular invariant rings of
1125
finite groups", arXiv:math.AC/0703035
1126
"""
1127
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
1128
from sage.interfaces.singular import singular
1129
gens = self.gens()
1130
singular.LIB("finvar.lib")
1131
n = self.degree() #len((gens[0].matrix()).rows())
1132
F = self.base_ring()
1133
q = F.characteristic()
1134
## test if the field is admissible
1135
if F.gen()==1: # we got the rationals or GF(prime)
1136
FieldStr = str(F.characteristic())
1137
elif hasattr(F,'polynomial'): # we got an algebraic extension
1138
if len(F.gens())>1:
1139
raise NotImplementedError, "can only deal with finite fields and (simple algebraic extensions of) the rationals"
1140
FieldStr = '(%d,%s)'%(F.characteristic(),str(F.gen()))
1141
else: # we have a transcendental extension
1142
FieldStr = '(%d,%s)'%(F.characteristic(),','.join([str(p) for p in F.gens()]))
1143
1144
## Setting Singular's variable names
1145
## We need to make sure that field generator and variables get different names.
1146
if str(F.gen())[0]=='x':
1147
VarStr = 'y'
1148
else:
1149
VarStr = 'x'
1150
VarNames='('+','.join((VarStr+str(i+1) for i in range(n)))+')'
1151
R=singular.ring(FieldStr,VarNames,'dp')
1152
if hasattr(F,'polynomial') and F.gen()!=1: # we have to define minpoly
1153
singular.eval('minpoly = '+str(F.polynomial()).replace('x',str(F.gen())))
1154
A = [singular.matrix(n,n,str((x.matrix()).list())) for x in gens]
1155
Lgens = ','.join((x.name() for x in A))
1156
PR = PolynomialRing(F,n,[VarStr+str(i) for i in range(1,n+1)])
1157
if q == 0 or (q > 0 and self.cardinality()%q != 0):
1158
from sage.all import Integer, Matrix
1159
try:
1160
gapself = gap(self)
1161
# test whether the backwards transformation works as well:
1162
for i in range(self.ngens()):
1163
if Matrix(gapself.gen(i+1),F) != self.gen(i).matrix():
1164
raise ValueError
1165
except (TypeError,ValueError):
1166
gapself is None
1167
if gapself is not None:
1168
ReyName = 't'+singular._next_var_name()
1169
singular.eval('matrix %s[%d][%d]'%(ReyName,self.cardinality(),n))
1170
En = gapself.Enumerator()
1171
for i in range(1,self.cardinality()+1):
1172
M = Matrix(En[i],F)
1173
D = [{} for foobar in range(self.degree())]
1174
for x,y in M.dict().items():
1175
D[x[0]][x[1]] = y
1176
for row in range(self.degree()):
1177
for t in D[row].items():
1178
singular.eval('%s[%d,%d]=%s[%d,%d]+(%s)*var(%d)'%(ReyName,i,row+1,ReyName,i,row+1, repr(t[1]),t[0]+1))
1179
foobar = singular(ReyName)
1180
IRName = 't'+singular._next_var_name()
1181
singular.eval('matrix %s = invariant_algebra_reynolds(%s)'%(IRName,ReyName))
1182
else:
1183
ReyName = 't'+singular._next_var_name()
1184
singular.eval('list %s=group_reynolds((%s))'%(ReyName,Lgens))
1185
IRName = 't'+singular._next_var_name()
1186
singular.eval('matrix %s = invariant_algebra_reynolds(%s[1])'%(IRName,ReyName))
1187
1188
OUT = [singular.eval(IRName+'[1,%d]'%(j)) for j in range(1,1+singular('ncols('+IRName+')'))]
1189
return [PR(gen) for gen in OUT]
1190
if self.cardinality()%q == 0:
1191
PName = 't'+singular._next_var_name()
1192
SName = 't'+singular._next_var_name()
1193
singular.eval('matrix %s,%s=invariant_ring(%s)'%(PName,SName,Lgens))
1194
OUT = [singular.eval(PName+'[1,%d]'%(j)) for j in range(1,1+singular('ncols('+PName+')'))] + [singular.eval(SName+'[1,%d]'%(j)) for j in range(2,1+singular('ncols('+SName+')'))]
1195
return [PR(gen) for gen in OUT]
1196
1197
1198
class MatrixGroup_gens_finite_field(MatrixGroup_gens, MatrixGroup_gap_finite_field):
1199
pass
1200
1201
## def conjugacy_class_representatives_gap(self):
1202
## """
1203
## Wraps GAP Representative+ConjugactClasses but returns a list of
1204
## strings representing the GAP matrices which form a complete
1205
## set of representatives of the conjugacy classes of the group.
1206
1207
## EXAMPLES:
1208
## sage: F = GF(3); MS = MatrixSpace(F,2,2)
1209
## sage: gens = [MS([[1,0],[-1,1]]),MS([[1,1],[0,1]])]
1210
## sage: G = MatrixGroup(gens)
1211
## sage: G.conjugacy_class_representatives_gap()
1212
## ['[ [ Z(3)^0, 0*Z(3) ], [ 0*Z(3), Z(3)^0 ] ]',
1213
## '[ [ 0*Z(3), Z(3)^0 ], [ Z(3), Z(3)^0 ] ]',
1214
## '[ [ 0*Z(3), Z(3)^0 ], [ Z(3), Z(3) ] ]',
1215
## '[ [ 0*Z(3), Z(3) ], [ Z(3)^0, Z(3)^0 ] ]',
1216
## '[ [ 0*Z(3), Z(3) ], [ Z(3)^0, Z(3) ] ]',
1217
## '[ [ 0*Z(3), Z(3)^0 ], [ Z(3), 0*Z(3) ] ]',
1218
## '[ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3) ] ]']
1219
1220
## AUTHOR: David Joyner (1-2006)
1221
## """
1222
## F = self.__R
1223
## deg = self.__n
1224
## gp_gens = self.gens()
1225
## L = [gap(A) for A in gp_gens]
1226
## sL = ','.join(str(x) for x in L)
1227
## if is_FiniteField(F):
1228
## q = F.cardinality()
1229
## gap.eval("cl:=ConjugacyClasses(Group(["+sL+"]))")
1230
## m = eval(gap.eval("Length(cl)"))
1231
## gap.eval("reps:=List(cl,x->Representative(x))")
1232
## sreps = [gap.eval("reps["+str(i+1)+"]") for i in range(m)]
1233
## return sreps
1234
## raise TypeError, "R (=%s) must be a finite field"%R
1235
1236
1237
1238
1239