Open in CoCalc
1
# This file was *autogenerated* from the file local_matrix_group.sage
2
from sage.all_cmdline import * # import sage library
3
_sage_const_2 = Integer(2); _sage_const_1 = Integer(1); _sage_const_0 = Integer(0)
4
"""
5
Local Matrix Groups
6
7
This module contains several extensions to classes inherited from sage matrix group classes.
8
It fills in missing methods
9
10
##############################################################################
11
# Copyright (C) 2016 Sebastian Oehms <[email protected]>
12
#
13
# Distributed under the terms of the GNU General Public License (GPL)
14
#
15
# The full text of the GPL is available at:
16
#
17
# http://www.gnu.org/licenses/
18
##############################################################################
19
20
21
This module contains extensions of the following classes
22
23
sage class | extended class
24
-------------------------------------------------------------------------------
25
UnitaryMatrixGroup_generic | local_UnitaryMatrixGroup_generic
26
UnitaryMatrixGroup_gap | local_UnitaryMatrixGroup_gap
27
28
29
This module contains the following new classes
30
31
new class | inherited from
32
-------------------------------------------------------------------------------
33
MatrixGroup_subgroup: | FinitelyGeneratedMatrixGroup_gap
34
35
AUTHOR
36
37
- Sebastian Oehms, Sept. 2016
38
39
"""
40
41
42
####################################################################################################
43
# Extension to UnitaryMatrixGroup_gap and GU()
44
####################################################################################################
45
from sage.groups.matrix_gps.unitary import *
46
from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap
47
from sage.groups.libgap_wrapper import ParentLibGAP
48
from lib.utils_gap_interface import *
49
50
51
52
class MatrixGroup_subgroup(FinitelyGeneratedMatrixGroup_gap):
53
"""
54
This class can be used to create subgroups of matrix_groups beeing generated by a finite list of generators in the
55
ambient group. It is an analogy to the PermutationGroup_subgroup class It can be used in cases of matrix groups
56
which don't pocess a subgroup attribute.
57
58
If you don't see this well formatted type
59
60
sage: print MatrixGroup_subgroup.__doc__
61
62
This class has two methods overwriting the corresponding methods of FinitelyGeneratedMatrixGroup_gap class.
63
64
- "__init__": to register the information corresponding to the ambient group
65
66
- "_repr_: to print a representing string containing the ambient group
67
68
69
INPUT (to the constructor):
70
71
- "ambient": the matrix group for which the subgroup shoul be craeted
72
73
- "generators": list of elements in the ambient group generating the subgroup to be defined
74
75
76
EXAMPLE:
77
78
sage: UCF = UniversalCyclotomicField()
79
sage: G = GL(2, UCF)
80
sage: M = matrix( UCF, [[1, E(12)], [0,-1]] ); M
81
[ 1 -E(12)^7]
82
[ 0 -1]
83
sage: S = G.subgroup([M])
84
---------------------------------------------------------------------------
85
AttributeError Traceback (most recent call last)
86
.......
87
AttributeError: 'LinearMatrixGroup_generic_with_category' object has no attribute 'subgroup'
88
sage:
89
sage: from lib.local_matrix_group import *
90
sage: S = MatrixGroup_subgroup(G, [M])
91
sage: S
92
Subgroup of General Linear Group of degree 2 over Universal Cyclotomic Field generated by ([ 1 -E(12)^7]
93
[ 0 -1],)
94
sage:
95
96
TESTS:
97
98
sage: UCF = UniversalCyclotomicField()
99
sage: G = GL(2, UCF)
100
sage: M = matrix( UCF, [[1, E(12)], [0,-1]] )
101
sage: S = MatrixGroup_subgroup(G, [M])
102
sage: TestSuite(S).run()
103
104
AUTHOR
105
106
- Sebastian Oehms, Okt. 2016
107
108
109
"""
110
111
def __init__(self, ambient, generators ):
112
"""
113
Python constructor.
114
115
for more information type
116
117
sage: print MatrixGroup_subgroup.__doc__
118
119
120
AUTHOR
121
122
- Sebastian Oehms, Sept. 2016
123
124
"""
125
126
for g in generators:
127
if g not in ambient:
128
raise ValueError("Generator %s is not in the group"%(g))
129
gap_gens = [libgap(matrix_gen) for matrix_gen in generators]
130
gap_group = libgap.Group(gap_gens)
131
base_ring = ambient.base_ring()
132
degree = ambient.degree()
133
FinitelyGeneratedMatrixGroup_gap.__init__(self, degree, base_ring, gap_group)
134
self._ambient = ambient
135
136
137
138
def _repr_(self):
139
"""
140
Return a string representation
141
142
If you don't see this well formatted type
143
144
sage: print MatrixGroup_subgroup._repr_.__doc__
145
146
OUTPUT:
147
148
String decribing self
149
150
TESTS:
151
152
sage: UCF = UniversalCyclotomicField()
153
sage: G = GL(2, UCF)
154
sage: M = matrix( UCF, [[1, E(12)], [0,-1]] )
155
sage: S = MatrixGroup_subgroup(G, [M])
156
sage: S
157
Subgroup of General Linear Group of degree 2 over Universal Cyclotomic Field generated by ([ 1 -E(12)^7]
158
[ 0 -1],)
159
sage:
160
"""
161
162
return "Subgroup of %s generated by:\n%s"%(self._ambient ,self.gens())
163
164
165
166
167
class local_UnitaryMatrixGroup_generic(UnitaryMatrixGroup_generic):
168
"""
169
This class is an extension of the sage class UnitaryMatrixGroup_generic
170
171
If you don't see this well formatted type
172
173
sage: print local_UnitaryMatrixGroup_generic.__doc__
174
175
This class contains the following additional methods
176
177
- _conjugate
178
- _adjoined
179
180
- subgroup
181
- invariant_bilinear_form / invariant_form
182
183
Furthermore the original method
184
185
- _check_matrix
186
187
has been overwritten since the original one does not behave correctly in the case of finite fields
188
189
EXAMPLES:
190
191
See the method documentation. For instance, type:
192
193
sage: print local_UnitaryMatrixGroup_generic.subgroup.__doc__
194
sage: print local_UnitaryMatrixGroup_generic.invariant_bilinea_form.__doc__
195
196
197
TESTS:
198
199
sage: G34 = GU(3,4)
200
sage: TestSuite(G33).run()
201
sage: UCF = UniversalCyclotomicField()
202
sage: G3UCF = GU(3, UCF)
203
sage: TestSuite(G3UCF).run()
204
sage: h=matrix(UCF, 3,3,[[0,0,1],[0,1,0],[1,0,0]] )
205
sage: G3h = GU(3, UCF, hermitian_form=h)
206
sage: TestSuite(G3h).run()
207
208
209
AUTHOR
210
211
- Sebastian Oehms, Sept. 2016
212
213
"""
214
215
_hermitian_form_ = None
216
217
218
def subgroup(self, generators):
219
"""
220
Return the subgroup generated by the given generators
221
222
If you don't see this well formatted type
223
224
sage: print local_UnitaryMatrixGroup_generic.subgroup.__doc__
225
226
In case where self is an instance of ParentLibGAP this method is identical to the corresponding method of that class.
227
In all other cases an instance of the class MatrixGroup_subgroup is returned
228
229
INPUT:
230
231
- ``generators`` -- a list/tuple/iterable of group elements of self
232
233
OUTPUT:
234
235
The subgroup generated by ``generators`` as an in instance of
236
237
- FinitelyGeneratedMatrixGroup_gap if self is an instance of ParentLibGAP
238
239
- MatrixGroup_subgroup elsewise
240
241
EAMPLE:
242
243
sage: from lib.local_matrix_group import *
244
sage: UCF = UniversalCyclotomicField()
245
sage: M = matrix( UCF, [[0, 1], [1,0]] )
246
sage: GU2=GU(2,UCF, hermitian_form=M); GU2
247
General Unitary Group of degree 2 over Universal Cyclotomic Field with respect to hermitian form [0 1]
248
[1 0]
249
sage: S = GU2.subgroup( [M] ); S
250
Subgroup of General Unitary Group of degree 2 over Universal Cyclotomic Field with respect to hermitian form [0 1]
251
[1 0] generated by ([0 1]
252
[1 0],)
253
sage: isinstance( GU3, ParentLibGAP)
254
False
255
sage: isinstance( S, ParentLibGAP)
256
True
257
sage: isinstance( S, MatrixGroup_subgroup )
258
True
259
sage:
260
261
TESTS:
262
263
see the tests for the class
264
265
AUTHOR:
266
267
- Sebastian Oehms, Sept. 2016
268
269
270
"""
271
272
if isinstance( self, ParentLibGAP ):
273
try:
274
SubGroup = ParentLibGAP.subgroup( self, generators )
275
except:
276
SubGroup = MatrixGroup_subgroup(self, generators )
277
else:
278
SubGroup = MatrixGroup_subgroup(self, generators )
279
return SubGroup
280
281
282
def __set_hermitian_form__(self, hermitian_form ):
283
"""
284
This method registers the hermitian form to which should be kept invariant be self
285
"""
286
self._hermitian_form_ = hermitian_form
287
288
289
290
291
292
# @cached_method
293
def invariant_bilinear_form(self):
294
"""
295
Return the sesquilinear form preserved by the unitary group.
296
297
If you don't see this well formatted type
298
299
sage: print local_UnitaryMatrixGroup_generic.invariant_bilinear_form.__doc__
300
301
If a hermitian_form has been set explicitely by the method __set_hermitian_form__ it will be returned.
302
Elsewise the gap function "InvariantSesquilinearForm" is used.
303
304
Compare the corresponding methods with respect to the orthogonal groups
305
306
OUTPUT:
307
308
the hermitian form as a matrix with entries in the base_ring
309
310
EXAMPLES:
311
312
sage: GU25 = GU(2,5)
313
sage: GU52.invariant_bilinear_form()
314
[0 0 0 0 1]
315
[0 0 0 1 0]
316
[0 0 1 0 0]
317
[0 1 0 0 0]
318
[1 0 0 0 0]
319
sage: GU3Q = GU(3,QQ)
320
sage: GU3Q.invariant_bilinear_form()
321
[1 0 0]
322
[0 1 0]
323
[0 0 1]
324
325
326
TESTS:
327
328
see the tests for the class
329
330
AUTHOR
331
332
- Sebastian Oehms, Sept. 2016
333
334
"""
335
if self._hermitian_form_ != None:
336
return self._hermitian_form_
337
338
if self.degree() > _sage_const_1 :
339
try:
340
m = self.gap().InvariantSesquilinearForm()['matrix'].matrix()
341
except AttributeError:
342
m = self.one().matrix()
343
else:
344
m = matrix( _sage_const_1 ,_sage_const_1 , [_sage_const_1 ] )
345
m.set_immutable()
346
return m
347
348
349
350
# @cached_method
351
def invariant_form(self):
352
"""
353
Return the sesquilinear form preserved by the unitary group. Compare the corresponding methods with respect to the
354
symplectic groups. It is identical to invariant_bilinear_form (duplicate names in sage). For more information type
355
356
sage: print local_UnitaryMatrixGroup_generic.invariant_bilinear_form.__doc__
357
"""
358
359
return self.invariant_bilinear_form()
360
361
362
363
def _conjugate(self, mat):
364
"""
365
This internal method calculates the elementwise conjugate of the matrix mat
366
367
INPUT:
368
369
- mat matrix with entries from the base_ring of self
370
371
OUTPUT:
372
373
- the conjugate of mat as matrix of the same type
374
375
EXAMPLES:
376
377
sage: from lib.local_matrix_group import *
378
sage: GU52 = GU(5,2)
379
sage: gl = GU52.some_elements()
380
sage: g = gl[0]; g
381
[1 0 0 0 0]
382
[0 a 0 0 0]
383
[0 0 1 0 0]
384
[0 0 0 a 0]
385
[0 0 0 0 1]
386
sage: GU52._conjugate( g.matrix() )
387
[ 1 0 0 0 0]
388
[ 0 a + 1 0 0 0]
389
[ 0 0 1 0 0]
390
[ 0 0 0 a + 1 0]
391
[ 0 0 0 0 1]
392
sage:
393
394
TESTS:
395
396
see the tests for the class
397
398
AUTHOR
399
400
- Sebastian Oehms, Sept. 2016
401
402
"""
403
if isinstance(self.base_ring(), UniversalCyclotomicField):
404
# Note: UniversalCyclotomicField.is_finite() gives True, a bug?
405
result = mat.conjugate()
406
elif finite_field_sqrt( self.base_ring() ):
407
matconj = mat.dict()
408
for ind in matconj.keys():
409
matconj.update({ind:matconj[ind].frobenius()})
410
result = matrix(matconj)
411
else:
412
result = mat.conjugate()
413
return result
414
415
def _adjoint(self, mat):
416
"""
417
Return the adjoint (conjugate and transpose) matrix of mat.
418
419
INPUT:
420
421
- mat matrix with entries from the base_ring of self
422
423
OUTPUT:
424
425
- the conjugate and transpose of mat as matrix of the same type
426
427
EXAMPLES:
428
429
sage: from lib.local_matrix_group import *
430
sage: GU52 = GU(5,2)
431
sage: gl = GU52.gens()
432
sage: g = gl[1]; g
433
[0 1 0 0 0]
434
[a 0 1 0 1]
435
[1 0 1 0 0]
436
[1 0 0 0 0]
437
[0 0 0 1 0]
438
sage: GU52._adjoint( g.matrix() )
439
[ 0 a + 1 1 1 0]
440
[ 1 0 0 0 0]
441
[ 0 1 1 0 0]
442
[ 0 0 0 0 1]
443
[ 0 1 0 0 0]
444
sage:
445
446
TESTS:
447
448
see the tests for the class
449
450
AUTHOR
451
452
- Sebastian Oehms, Sept. 2016
453
454
"""
455
result = self._conjugate(mat.transpose())
456
return result
457
458
459
def _check_matrix(self, x, *args):
460
"""
461
Check whether the matrix ``x`` is unitary. This method overwrites the original sage-method with the same name. In
462
addition to it
463
464
- it takes into acount a special user defined hermitian form
465
- it works well in the case of a finite field (which is not the case for the original version)
466
467
If you don't see this well formatted type
468
469
sage: print local_UnitaryMatrixGroup_generic._check_matrix.__doc__
470
471
To read the original docstring type:
472
473
sage: print sage.groups.matrix_gps.unitary.UnitaryMatrixGroup_generic._check_matrix.__doc__
474
475
Description of the bug wich should be avoided by this variation of the original method:
476
477
If an element of a finite unitary group is converted to the underlying matrix class it can not be converted
478
back to the unitary group since the method unitary for the matrix gives false (see example below)
479
Note: the unitary method attached to the matrix is not changed. It continues to returns false for elements of finite
480
unitary groups.
481
482
483
INPUT:
484
485
same as for the original method
486
487
OUTPUT:
488
489
same as for the original method
490
491
EXAMPLES:
492
493
First try with the original method to convert an element of a unitary group to a matrix and back:
494
495
sage: G32=GU(3,2)
496
sage: g1, g2 =G32.gens()
497
sage: g1m = g1.matrix(); g1m
498
[a 0 0]
499
[0 1 0]
500
[0 0 a]
501
sage: g1m.is_unitary()
502
False
503
sage: g1m in G32
504
False
505
506
Now, do the same thing using local_UnitaryMatrixGroup_generic._check_matrix.__doc__:
507
508
sage: from lib.local_matrix_group import *
509
sage: G32=GU(3,2)
510
sage: g1, g2 = G32.gens()
511
sage: g1m=g1.matrix()
512
sage: g1m.is_unitary()
513
False
514
sage: g1m in G32
515
True
516
517
TESTS:
518
519
see the tests for the class
520
521
522
AUTHOR
523
524
- Sebastian Oehms, Sept. 2016
525
526
"""
527
528
try:
529
finite_field = finite_field_sqrt( self.base_ring() )
530
except:
531
finite_field = False
532
533
def check_unitary( self, x ):
534
"""
535
This function supports an alternative check to x.is_unitary()
536
for finite fields or explicit hermitian form
537
"""
538
if self._hermitian_form_ != None or finite_field:
539
540
xadjoint = self._adjoint( x )
541
F = self.invariant_bilinear_form()
542
xadFx = xadjoint * F * x
543
result = ( F == xadFx )
544
if result == True:
545
return result
546
547
# if result is not True this may be caused by differnt types
548
549
try:
550
Fmat = F.matrix()
551
except AttributeError:
552
Fmat = F
553
try:
554
xadFxmat = xadFx.matrix()
555
except AttributeError:
556
xadFxmat = xadFx
557
diff = Fmat - xadFxmat
558
result = diff.is_zero()
559
return result
560
561
else:
562
563
return x.is_unitary()
564
565
566
if self._special and x.determinant() != _sage_const_1 :
567
raise TypeError('matrix must have determinant one')
568
if not check_unitary(self, x ):
569
raise TypeError('matrix must be unitary')
570
571
572
# -------------------------------------------------------------------------------
573
# Methods for test_suite
574
# -------------------------------------------------------------------------------
575
def _test_extensions(self, **options):
576
"""
577
Method called by TestSuite
578
579
If you don't see this well formatted type
580
581
sage: print CubicBraidGroup_class._test_constructions.__doc__
582
583
the following is checked:
584
- if _check_matrix works
585
- if subgroup works
586
587
AUTHOR
588
589
- Sebastian Oehms, Sept. 2016
590
591
"""
592
593
#------------------------------------------------------------------------------------
594
# Test _check_matrix
595
#------------------------------------------------------------------------------------
596
try:
597
genList = self.gens()
598
except AttributeError:
599
genList = self.some_elements()
600
g = genList[_sage_const_0 ]
601
gm = g.matrix()
602
test_check_matrix = self._tester(**options)
603
test_check_matrix.assert_( gm in self )
604
605
#------------------------------------------------------------------------------------
606
# Test subgroup
607
#------------------------------------------------------------------------------------
608
SubGroup = self.subgroup( [gm] )
609
test_subgroup = self._tester(**options)
610
test_subgroup.assert_( SubGroup.ambient() == self )
611
612
613
614
615
class local_UnitaryMatrixGroup_gap(local_UnitaryMatrixGroup_generic, NamedMatrixGroup_gap):
616
pass
617
618
619
###############################################################################
620
# General Unitary Group
621
###############################################################################
622
623
def GU(n, R, var='a', hermitian_form=None ):
624
"""
625
This function overwrites the sage-Funtion with the same name. It uses the extended classes
626
local_UnitaryMatrixGroup_gap and local_UnitaryMatrixGroup_generic in stead of the original classes
627
UnitaryMatrixGroup_gap and UnitaryMatrixGroup_generic additional features are:
628
629
- use a special hermitain form via keyword-paremeter: "hermitian_form= ..."
630
- ask for the hermitian form to which GU is related via method "invariant_form"
631
- define a subgroup of GU to a list of generators via method "subgroup"
632
633
to read to original docstring of GU type:
634
635
sage print sage.groups.matrix_gps.unitary.GU.__doc__
636
637
EXAMPLES:
638
639
sage: from lib.local_matrix_group import *
640
sage: K=UniversalCyclotomicField()
641
sage: h=matrix(K, 3,3,[[0,0,1],[0,1,0],[1,0,0]] )
642
sage: GU3h=GU(3, K, hermitian_form=h); GU3h
643
Unitary Group of degree 3 over Universal Cyclotomic Field with respect to hermitian form
644
[0 0 1]
645
[0 1 0]
646
[1 0 0]
647
sage: GU3=GU(3, K); GU3
648
General Unitary Group of degree 3 over Universal Cyclotomic Field
649
sage: GU3 == GU3h
650
False
651
sage: x=matrix(K, 3,3,[[0,1,0],[0,0,1],[1,0,0]] ); x
652
[0 1 0]
653
[0 0 1]
654
[1 0 0]
655
sage: x in GU3h
656
False
657
sage: x in GU3
658
True
659
660
AUTHOR
661
662
- Sebastian Oehms, Sept. 2016
663
664
"""
665
666
degree, ring = normalize_args_vectorspace(n, R, var=var)
667
if is_FiniteField(ring):
668
q = ring.cardinality()
669
if var not in ring:
670
ring = GF(q ** _sage_const_2 , name=var)
671
if hermitian_form == None:
672
name = 'General Unitary Group of degree {0} over {1}'.format(degree, ring)
673
ltx = r'\text{{GU}}_{{{0}}}({1})'.format(degree, latex(ring))
674
else:
675
name = 'Unitary Group of degree {0} over {1} with respect to hermitian form\n{2}'.format(degree, ring, hermitian_form)
676
ltx = r'\text{{GU}}_{{{0}}}({1},{2})'.format(degree, latex(ring), latex(hermitian_form))
677
678
if is_FiniteField(ring):
679
# unitary groups in gap are defined for finite fields only
680
cmd = 'GU({0}, {1})'.format(degree, q)
681
UnitaryGroup = local_UnitaryMatrixGroup_gap(degree, ring, False, name, ltx, cmd )
682
else:
683
UnitaryGroup = local_UnitaryMatrixGroup_generic(degree, ring, False, name, ltx )
684
685
UnitaryGroup.__set_hermitian_form__(hermitian_form)
686
687
return UnitaryGroup
688
689
690