Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/groups/matrix_gps/matrix_group.py
8815 views
1
"""
2
Base classes for Matrix Groups
3
4
Loading, saving, ... works::
5
6
sage: G = GL(2,5); G
7
General Linear Group of degree 2 over Finite Field of size 5
8
sage: TestSuite(G).run()
9
10
sage: g = G.1; g
11
[4 1]
12
[4 0]
13
sage: TestSuite(g).run()
14
15
We test that :trac:`9437` is fixed::
16
17
sage: len(list(SL(2, Zmod(4))))
18
48
19
20
AUTHORS:
21
22
- William Stein: initial version
23
24
- David Joyner (2006-03-15): degree, base_ring, _contains_, list,
25
random, order methods; examples
26
27
- William Stein (2006-12): rewrite
28
29
- David Joyner (2007-12): Added invariant_generators (with Martin
30
Albrecht and Simon King)
31
32
- David Joyner (2008-08): Added module_composition_factors (interface
33
to GAP's MeatAxe implementation) and as_permutation_group (returns
34
isomorphic PermutationGroup).
35
36
- Simon King (2010-05): Improve invariant_generators by using GAP
37
for the construction of the Reynolds operator in Singular.
38
"""
39
40
##############################################################################
41
# Copyright (C) 2006 David Joyner and William Stein <[email protected]>
42
#
43
# Distributed under the terms of the GNU General Public License (GPL)
44
#
45
# The full text of the GPL is available at:
46
#
47
# http://www.gnu.org/licenses/
48
##############################################################################
49
50
from sage.rings.all import ZZ
51
from sage.rings.integer import is_Integer
52
from sage.rings.ring import is_Ring
53
from sage.rings.finite_rings.constructor import is_FiniteField
54
from sage.interfaces.gap import gap
55
from sage.matrix.matrix import is_Matrix
56
from sage.matrix.matrix_space import MatrixSpace, is_MatrixSpace
57
from sage.misc.latex import latex
58
from sage.structure.sequence import Sequence
59
from sage.structure.sage_object import SageObject
60
from sage.misc.decorators import rename_keyword
61
from sage.misc.cachefunc import cached_method
62
63
from sage.groups.group import Group
64
from sage.groups.libgap_wrapper import ParentLibGAP
65
from sage.groups.libgap_mixin import GroupMixinLibGAP
66
67
from sage.groups.matrix_gps.group_element import (
68
is_MatrixGroupElement, MatrixGroupElement_generic, MatrixGroupElement_gap)
69
70
#################################################################
71
72
def is_MatrixGroup(x):
73
"""
74
Test whether ``x`` is a matrix group.
75
76
EXAMPLES::
77
78
sage: from sage.groups.matrix_gps.matrix_group import is_MatrixGroup
79
sage: is_MatrixGroup(MatrixSpace(QQ,3))
80
False
81
sage: is_MatrixGroup(Mat(QQ,3))
82
False
83
sage: is_MatrixGroup(GL(2,ZZ))
84
True
85
sage: is_MatrixGroup(MatrixGroup([matrix(2,[1,1,0,1])]))
86
True
87
"""
88
return isinstance(x, MatrixGroup_base)
89
90
###################################################################
91
#
92
# Base class for all matrix groups
93
#
94
###################################################################
95
96
97
class MatrixGroup_base(Group):
98
"""
99
Base class for all matrix groups.
100
101
This base class just holds the base ring, but not the degree. So
102
it can be a base for affine groups where the natural matrix is
103
larger than the degree of the affine group. Makes no assumption
104
about the group except that its elements have a ``matrix()``
105
method.
106
"""
107
108
def _check_matrix(self, x, *args):
109
"""
110
Check whether the matrix ``x`` defines a group element.
111
112
This is used by the element constructor (if you pass
113
``check=True``, the default) that the defining matrix is valid
114
for this parent. Derived classes must override this to verify
115
that the matrix is, for example, orthogonal or symplectic.
116
117
INPUT:
118
119
- ``x`` -- a Sage matrix in the correct matrix space (degree
120
and base ring).
121
122
- ``*args`` -- optional other representations of ``x``,
123
depending on the group implementation. Ignored by default.
124
125
OUTPUT:
126
127
A ``TypeError`` must be raised if ``x`` is invalid.
128
129
EXAMPLES::
130
131
sage: G = SU(2,GF(5))
132
sage: G._check_matrix(identity_matrix(GF(5),2))
133
sage: G._check_matrix(matrix(GF(5),[[1,1],[0,1]]))
134
Traceback (most recent call last):
135
...
136
TypeError: matrix must be unitary
137
"""
138
if not x.is_invertible():
139
raise TypeError('matrix is not invertible')
140
141
def as_matrix_group(self):
142
"""
143
Return a new matrix group from the generators.
144
145
This will throw away any extra structure (encoded in a derived
146
class) that a group of special matrices has.
147
148
EXAMPLES::
149
150
sage: G = SU(4,GF(5))
151
sage: G.as_matrix_group()
152
Matrix group over Finite Field in a of size 5^2 with 2 generators (
153
[ a 0 0 0] [ 1 0 4*a + 3 0]
154
[ 0 2*a + 3 0 0] [ 1 0 0 0]
155
[ 0 0 4*a + 1 0] [ 0 2*a + 4 0 1]
156
[ 0 0 0 3*a], [ 0 3*a + 1 0 0]
157
)
158
159
sage: G = GO(3,GF(5))
160
sage: G.as_matrix_group()
161
Matrix group over Finite Field of size 5 with 2 generators (
162
[2 0 0] [0 1 0]
163
[0 3 0] [1 4 4]
164
[0 0 1], [0 2 1]
165
)
166
"""
167
from sage.groups.matrix_gps.finitely_generated import MatrixGroup
168
return MatrixGroup(self.gens())
169
170
def field_of_definition(self, **kwds):
171
"""
172
Return a field that contains all the matrices in this matrix
173
group.
174
175
EXAMPLES::
176
177
sage: G = SU(3,GF(5))
178
sage: G.base_ring()
179
Finite Field in a of size 5^2
180
sage: G.field_of_definition()
181
doctest:...: DeprecationWarning: Use base_ring() instead.
182
See http://trac.sagemath.org/14014 for details.
183
Finite Field in a of size 5^2
184
sage: G = GO(4,GF(7),1)
185
sage: G.field_of_definition()
186
Finite Field of size 7
187
sage: G.base_ring()
188
Finite Field of size 7
189
"""
190
from sage.misc.superseded import deprecation
191
deprecation(14014, 'Use base_ring() instead.')
192
return self.base_ring()
193
194
def base_field(self):
195
"""
196
Deprecated alias of :meth:`base_ring`
197
198
EXAMPLES::
199
200
sage: G = SU(3,GF(5))
201
sage: G.base_field()
202
doctest:...: DeprecationWarning: Use base_ring() instead.
203
See http://trac.sagemath.org/14014 for details.
204
Finite Field in a of size 5^2
205
"""
206
from sage.misc.superseded import deprecation
207
deprecation(14014, 'Use base_ring() instead.')
208
return self.base_ring()
209
210
def _repr_(self):
211
"""
212
Return a string representation.
213
214
OUTPUT:
215
216
String.
217
218
EXAMPLES::
219
220
sage: F = GF(5); MS = MatrixSpace(F,2,2)
221
sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])]
222
sage: G = MatrixGroup(gens)
223
sage: G
224
Matrix group over Finite Field of size 5 with 2 generators (
225
[1 2] [1 1]
226
[4 1], [0 1]
227
)
228
"""
229
if self.ngens() > 5:
230
return 'Matrix group over {0} with {1} generators'.format(
231
self.base_ring(), self.ngens())
232
else:
233
from sage.misc.displayhook import format_list
234
return 'Matrix group over {0} with {1} generators {2}'.format(
235
self.base_ring(), self.ngens(), format_list(self.gens()))
236
237
def _repr_option(self, key):
238
"""
239
Metadata about the :meth:`_repr_` output.
240
241
See :meth:`sage.structure.parent._repr_option` for details.
242
243
EXAMPLES::
244
245
sage: SO3 = groups.matrix.SO(3, QQ)
246
sage: SO3._repr_option('element_ascii_art')
247
True
248
"""
249
if key == 'element_ascii_art':
250
return True
251
return super(MatrixGroup_base, self)._repr_option(key)
252
253
def _latex_(self):
254
r"""
255
EXAMPLES::
256
257
sage: MS = MatrixSpace(GF(5), 2, 2)
258
sage: G = MatrixGroup(MS([[1,2],[-1,1]]),MS([[1,1],[0,1]]))
259
sage: latex(G)
260
\left\langle \left(\begin{array}{rr}
261
1 & 2 \\
262
4 & 1
263
\end{array}\right), \left(\begin{array}{rr}
264
1 & 1 \\
265
0 & 1
266
\end{array}\right) \right\rangle
267
"""
268
gens = ', '.join([latex(x) for x in self.gens()])
269
return '\\left\\langle %s \\right\\rangle'%gens
270
271
272
273
###################################################################
274
#
275
# Matrix group over a generic ring
276
#
277
###################################################################
278
279
class MatrixGroup_generic(MatrixGroup_base):
280
281
Element = MatrixGroupElement_generic
282
283
def __init__(self, degree, base_ring, category=None):
284
"""
285
Base class for matrix groups over generic base rings
286
287
You should not use this class directly. Instead, use one of
288
the more specialized derived classes.
289
290
INPUT:
291
292
- ``degree`` -- integer. The degree (matrix size) of the
293
matrix group.
294
295
- ``base_ring`` -- ring. The base ring of the matrices.
296
297
TESTS::
298
299
sage: G = GL(2, QQ)
300
sage: from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic
301
sage: isinstance(G, MatrixGroup_generic)
302
True
303
"""
304
assert is_Ring(base_ring)
305
assert is_Integer(degree)
306
307
self._deg = degree
308
if self._deg <= 0:
309
raise ValueError('the degree must be at least 1')
310
311
if (category is None) and is_FiniteField(base_ring):
312
from sage.categories.finite_groups import FiniteGroups
313
category = FiniteGroups()
314
super(MatrixGroup_generic, self).__init__(base=base_ring, category=category)
315
316
def degree(self):
317
"""
318
Return the degree of this matrix group.
319
320
OUTPUT:
321
322
Integer. The size (number of rows equals number of columns) of
323
the matrices.
324
325
EXAMPLES::
326
327
sage: SU(5,5).degree()
328
5
329
"""
330
return self._deg
331
332
@cached_method
333
def matrix_space(self):
334
"""
335
Return the matrix space corresponding to this matrix group.
336
337
This is a matrix space over the field of definition of this matrix
338
group.
339
340
EXAMPLES::
341
342
sage: F = GF(5); MS = MatrixSpace(F,2,2)
343
sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])
344
sage: G.matrix_space()
345
Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5
346
sage: G.matrix_space() is MS
347
True
348
"""
349
return MatrixSpace(self.base_ring(), self.degree())
350
351
def _cmp_generators(self, other):
352
"""
353
Implement comparison
354
355
We treat two matrix groups as equal if their generators are
356
the same in the same order. Infinitely-generated groups are
357
compared by identity.
358
359
INPUT:
360
361
- ``other`` -- anything.
362
363
OUTPUT:
364
365
``-1``, ``0``, or ``+1``.
366
367
EXAMPLES::
368
369
sage: G = GL(2,3)
370
sage: H = MatrixGroup(G.gens())
371
sage: G._cmp_generators(H)
372
0
373
sage: cmp(G,H)
374
0
375
sage: cmp(H,G)
376
0
377
sage: G == H
378
True
379
"""
380
if not is_MatrixGroup(other):
381
return cmp(type(self), type(other))
382
c = cmp(self.matrix_space(), other.matrix_space())
383
if c != 0:
384
return c
385
386
def identity_cmp():
387
return cmp(id(self), id(other))
388
389
# compare number of generators
390
try:
391
n_self = self.ngens()
392
n_other = other.ngens()
393
except (AttributeError, NotImplementedError):
394
return identity_cmp()
395
c = cmp(n_self, n_other)
396
if c != 0:
397
return c
398
from sage.structure.element import is_InfinityElement
399
if is_InfinityElement(n_self) or is_InfinityElement(n_other):
400
return identity_cmp()
401
402
# compacte generator matrices
403
try:
404
self_gens = self.gens()
405
other_gens = other.gens()
406
except (AttributeError, NotImplementedError):
407
return identity_cmp()
408
assert(n_self == n_other)
409
for g,h in zip(self_gens, other_gens):
410
c = cmp(g.matrix(), h.matrix())
411
if c != 0:
412
return c
413
return c
414
415
def __cmp__(self, other):
416
"""
417
Implement comparison
418
419
EXAMPLES::
420
421
sage: MS = MatrixSpace(SR, 2, 2)
422
sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])
423
sage: from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic
424
sage: MatrixGroup_generic.__cmp__(G, G)
425
0
426
sage: cmp(G,G)
427
0
428
sage: cmp(G, MatrixGroup(G.gens()))
429
0
430
sage: G == MatrixGroup(G.gens())
431
True
432
"""
433
return self._cmp_generators(other)
434
435
def _Hom_(self, G, cat=None):
436
"""
437
Construct a homset.
438
439
INPUT:
440
441
- ``G`` -- group. The codomain.
442
443
- ``cat`` -- a category. Must be unset.
444
445
OUTPUT:
446
447
The set of homomorphisms from ``self`` to ``G``.
448
449
EXAMPLES::
450
451
sage: MS = MatrixSpace(SR, 2, 2)
452
sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])
453
sage: G.Hom(G)
454
Set of Homomorphisms from Matrix group over Symbolic Ring with 2 generators (
455
[1 0] [1 2]
456
[0 1], [3 4]
457
) to Matrix group over Symbolic Ring with 2 generators (
458
[1 0] [1 2]
459
[0 1], [3 4]
460
)
461
"""
462
if not (cat is None or (cat is G.category() and cat is self.category())):
463
raise TypeError
464
if not is_MatrixGroup(G):
465
raise TypeError, "G (=%s) must be a matrix group."%G
466
import homset
467
return homset.MatrixGroupHomset(self, G)
468
469
def hom(self, x):
470
"""
471
Return the group homomorphism defined by ``x``
472
473
INPUT:
474
475
- ``x`` -- a list/tuple/iterable of matrix group elements.
476
477
OUTPUT:
478
479
The group homomorphism defined by ``x``.
480
481
EXAMPLES::
482
483
sage: G = MatrixGroup([matrix(GF(5), [[1,3],[0,1]])])
484
sage: H = MatrixGroup([matrix(GF(5), [[1,2],[0,1]])])
485
sage: G.hom([H.gen(0)])
486
Homomorphism : Matrix group over Finite Field of size 5 with 1 generators (
487
[1 3]
488
[0 1]
489
) --> Matrix group over Finite Field of size 5 with 1 generators (
490
[1 2]
491
[0 1]
492
)
493
"""
494
v = Sequence(x)
495
U = v.universe()
496
if not is_MatrixGroup(U):
497
raise TypeError, "u (=%s) must have universe a matrix group."%U
498
return self.Hom(U)(x)
499
500
501
502
###################################################################
503
#
504
# Matrix group over a ring that GAP understands
505
#
506
###################################################################
507
508
class MatrixGroup_gap(GroupMixinLibGAP, MatrixGroup_generic, ParentLibGAP):
509
510
Element = MatrixGroupElement_gap
511
512
def __init__(self, degree, base_ring, libgap_group, ambient=None, category=None):
513
"""
514
Base class for matrix groups that implements GAP interface.
515
516
INPUT:
517
518
- ``degree`` -- integer. The degree (matrix size) of the
519
matrix group.
520
521
- ``base_ring`` -- ring. The base ring of the matrices.
522
523
- ``libgap_group`` -- the defining libgap group.
524
525
- ``ambient`` -- A derived class of :class:`ParentLibGAP` or
526
``None`` (default). The ambient class if ``libgap_group``
527
has been defined as a subgroup.
528
529
TESTS::
530
531
sage: from sage.groups.matrix_gps.matrix_group import MatrixGroup_gap
532
sage: MatrixGroup_gap(2, ZZ, libgap.eval('GL(2, Integers)'))
533
Matrix group over Integer Ring with 3 generators (
534
[0 1] [-1 0] [1 1]
535
[1 0], [ 0 1], [0 1]
536
)
537
"""
538
ParentLibGAP.__init__(self, libgap_group, ambient=ambient)
539
MatrixGroup_generic.__init__(self, degree, base_ring, category=category)
540
541
def _check_matrix(self, x_sage, x_gap):
542
"""
543
Check whether the matrix ``x`` defines a group element.
544
545
This is used by the element constructor (if you pass
546
``check=True``, the default) that the defining matrix is valid
547
for this parent. Derived classes must override this to verify
548
that the matrix is, for example, orthogonal or symplectic.
549
550
INPUT:
551
552
- ``x_sage`` -- a Sage matrix in the correct matrix space (degree
553
and base ring).
554
555
- ``x_gap`` -- the corresponding LibGAP matrix.
556
557
OUTPUT:
558
559
A ``TypeError`` must be raised if ``x`` is invalid.
560
561
EXAMPLES::
562
563
sage: m1 = matrix(GF(11), [(0, -1), (1, 0)])
564
sage: m2 = matrix(GF(11), [(0, -1), (1, -1)])
565
sage: G = MatrixGroup([m1, m2])
566
sage: G([1,2,0,1])
567
[1 2]
568
[0 1]
569
sage: G([1,1,1,0])
570
Traceback (most recent call last):
571
...
572
TypeError: matrix is not in the finitely generated group
573
"""
574
from sage.libs.gap.libgap import libgap
575
libgap_contains = libgap.eval('\in')
576
is_contained = libgap_contains(x_gap, self.gap())
577
if not is_contained.sage():
578
raise TypeError('matrix is not in the finitely generated group')
579
580
def _subgroup_constructor(self, libgap_subgroup):
581
"""
582
Return a finitely generated subgroup.
583
584
See
585
:meth:`sage.groups.libgap_wrapper.ParentLibGAP._subgroup_constructor`
586
for details.
587
588
TESTS::
589
590
sage: SL2Z = SL(2,ZZ)
591
sage: S, T = SL2Z.gens()
592
sage: G = SL2Z.subgroup([T^2]); G # indirect doctest
593
Matrix group over Integer Ring with 1 generators (
594
[1 2]
595
[0 1]
596
)
597
sage: G.ambient() is SL2Z
598
True
599
"""
600
from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap
601
return FinitelyGeneratedMatrixGroup_gap(self.degree(), self.base_ring(),
602
libgap_subgroup, ambient=self)
603
604
def __iter__(self):
605
"""
606
Iterate over the elements of the group.
607
608
This method overrides the matrix group enumerator in GAP which
609
is very slow, see http://tracker.gap-system.org/issues/369.
610
611
EXAMPLES::
612
613
sage: i = iter(GL(6,5))
614
sage: [ i.next() for j in range(8) ]
615
[
616
[1 0 0 0 0 0] [4 0 0 0 0 1] [0 4 0 0 0 0] [0 4 0 0 0 0]
617
[0 1 0 0 0 0] [4 0 0 0 0 0] [0 0 4 0 0 0] [0 0 4 0 0 0]
618
[0 0 1 0 0 0] [0 4 0 0 0 0] [0 0 0 4 0 0] [0 0 0 4 0 0]
619
[0 0 0 1 0 0] [0 0 4 0 0 0] [0 0 0 0 4 0] [0 0 0 0 4 0]
620
[0 0 0 0 1 0] [0 0 0 4 0 0] [0 0 0 0 0 4] [0 0 0 0 0 4]
621
[0 0 0 0 0 1], [0 0 0 0 4 0], [1 4 0 0 0 0], [2 4 0 0 0 0],
622
<BLANKLINE>
623
[3 0 0 0 0 1] [4 0 0 1 3 3] [0 0 0 2 0 0] [1 0 0 0 4 4]
624
[3 0 0 0 0 0] [4 0 0 0 3 3] [0 0 0 0 4 0] [1 0 0 0 0 4]
625
[0 4 0 0 0 0] [3 0 0 0 0 1] [2 2 0 0 0 2] [1 0 0 0 0 0]
626
[0 0 4 0 0 0] [3 0 0 0 0 0] [1 4 0 0 0 0] [0 1 0 0 0 0]
627
[0 0 0 4 0 0] [0 4 0 0 0 0] [0 2 4 0 0 0] [0 0 1 0 0 0]
628
[4 0 0 0 2 3], [2 0 3 4 4 4], [0 0 1 4 0 0], [0 0 0 1 0 0]
629
]
630
631
This is the direct computation in GAP, which will just run
632
(almost) forever. If you find that this works then the
633
``MatrixGroup_gap.__iter__`` and ``MatrixGroup_gap.list``
634
methods can be removed::
635
636
sage: G = GL(6,5).gap()
637
sage: G.Enumerator() # not tested
638
sage: G.Iterator() # not tested
639
"""
640
if not self.is_finite():
641
# use implementation from category framework
642
for g in super(Group, self).__iter__():
643
yield g
644
return
645
# Use the standard GAP iterator for small groups
646
if self.cardinality() < 1000:
647
for g in super(MatrixGroup_gap, self).__iter__():
648
yield g
649
return
650
# Override for large but finite groups
651
iso = self.gap().IsomorphismPermGroup()
652
P = iso.Image()
653
iterator = P.Iterator()
654
while not iterator.IsDoneIterator().sage():
655
p = iterator.NextIterator()
656
g = iso.PreImageElm(p)
657
yield self(g, check=False)
658
659
@cached_method
660
def list(self):
661
"""
662
List all elements of this group.
663
664
This method overrides the matrix group enumerator in GAP which
665
is very slow, see http://tracker.gap-system.org/issues/369.
666
667
OUTPUT:
668
669
A tuple containing all group elements in a random but fixed
670
order.
671
672
EXAMPLES::
673
674
sage: F = GF(3)
675
sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F, 2, [1,1,0,1])]
676
sage: G = MatrixGroup(gens)
677
sage: G.cardinality()
678
24
679
sage: v = G.list()
680
sage: len(v)
681
24
682
sage: v[:5]
683
(
684
[0 1] [0 1] [0 1] [0 2] [0 2]
685
[2 0], [2 1], [2 2], [1 0], [1 1]
686
)
687
sage: all(g in G for g in G.list())
688
True
689
690
An example over a ring (see trac 5241)::
691
692
sage: M1 = matrix(ZZ,2,[[-1,0],[0,1]])
693
sage: M2 = matrix(ZZ,2,[[1,0],[0,-1]])
694
sage: M3 = matrix(ZZ,2,[[-1,0],[0,-1]])
695
sage: MG = MatrixGroup([M1, M2, M3])
696
sage: MG.list()
697
(
698
[-1 0] [-1 0] [ 1 0] [1 0]
699
[ 0 -1], [ 0 1], [ 0 -1], [0 1]
700
)
701
sage: MG.list()[1]
702
[-1 0]
703
[ 0 1]
704
sage: MG.list()[1].parent()
705
Matrix group over Integer Ring with 3 generators (
706
[-1 0] [ 1 0] [-1 0]
707
[ 0 1], [ 0 -1], [ 0 -1]
708
)
709
710
An example over a field (see trac 10515)::
711
712
sage: gens = [matrix(QQ,2,[1,0,0,1])]
713
sage: MatrixGroup(gens).list()
714
(
715
[1 0]
716
[0 1]
717
)
718
719
Another example over a ring (see trac 9437)::
720
721
sage: len(SL(2, Zmod(4)).list())
722
48
723
724
An error is raised if the group is not finite::
725
726
sage: GL(2,ZZ).list()
727
Traceback (most recent call last):
728
...
729
NotImplementedError: group must be finite
730
"""
731
if not self.is_finite():
732
raise NotImplementedError('group must be finite')
733
return tuple(iter(self))
734
735