Open in CoCalc
1
# This file was *autogenerated* from the file utils_gap_interface.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); _sage_const_5 = Integer(5); _sage_const_4 = Integer(4)
4
"""
5
####################################################################################################
6
# This module contains utilities for using the sage-gap-interface
7
####################################################################################################
8
9
10
11
12
##############################################################################
13
# Copyright (C) 2016 Sebastian Oehms <[email protected]>
14
#
15
# Distributed under the terms of the GNU General Public License (GPL)
16
#
17
# The full text of the GPL is available at:
18
#
19
# http://www.gnu.org/licenses/
20
##############################################################################
21
22
23
24
This module contains the following functions:
25
26
- "gap_word_problem": an improvement of the sage method word_problem belonging to the matrix group and permutation group
27
classes which uses the gap function "EpimorphismFromFreeGroup"
28
29
- "expand_map_from_generators": function to create a map between groups given on generators by use of the gap_word_problem
30
function. It can be used in some cases where the gap function "GroupHomomorphismByImages" fails
31
32
- "gap_hom": function to create a map between groups given on generators by use of the gap function
33
"GroupHomomorphismByImages" or the former function "expand_map_from_generators" in the cases where
34
"GroupHomomorphismByImages" fails
35
36
- "gap_centralizer": calculates the centralizer of an element in a group using the gap function "Centralizer"
37
38
- "gap_extend_workspace": extends the gap workspace by use of the sage gap_extend_workspace function
39
40
AUTHOR
41
42
- Sebastian Oehms, Sept. 2016
43
44
"""
45
46
from sage.groups.libgap_wrapper import ParentLibGAP
47
from lib.utils_sys import *
48
49
50
51
###############################################################################
52
# Capsules needed in the main functions
53
###############################################################################
54
55
# -------------------------------------------------------------------------------
56
# gap_result
57
# return the gap-boolean fail as None
58
# -------------------------------------------------------------------------------
59
def gap_result( gap_element ):
60
"""
61
this function converts the gap boolean fail into a None object
62
63
INPUT:
64
65
- an arbtrary gap_element
66
67
OUTPUT:
68
69
the element itself or None if it is the gap-boolean fail.
70
71
"""
72
if gap_element != None:
73
if 'is_bool' in dir(gap_element):
74
if gap_element.is_bool():
75
if gap_element == libgap.eval('fail'):
76
return None
77
return gap_element
78
79
80
81
82
# -------------------------------------------------------------------------------
83
# gap_group_map
84
# used to convert gap maps into sage function objects
85
# -------------------------------------------------------------------------------
86
def gap_group_map( groupEle, GroupTo, gapHom ):
87
"""
88
This function can be used to converts a gap group map which was defined by the gap functions like
89
'GroupHomomorphismByImages' or 'IsomorhismPermGroup' or others having an ImageElm attribute into a
90
sage function object
91
92
If you don't see this well formatted type
93
94
sage: print gap_group_map.__doc__
95
96
INPUT:
97
98
- "groupEle": an element of the source group, whose image should be obtained, as a sage object.
99
100
- "GroupTo": the target group as a sage object
101
102
- "gapHom": the gap homomorphism which should be applied to groupEle and which has been defined by a gap functions
103
like 'GroupHomomorphismByImages' or 'IsomorhismPermGroup'
104
105
OUTPUT:
106
107
the value of groupEle under gap_hom as object of GroupTo
108
109
RAISE:
110
111
- RuntimeError: "gap cannot compute image of %s" If gap fails to compute the image
112
113
USAGE:
114
115
if you have defined a target group 'my_target_group' in your programm and a gap function 'my_gap_hom' then you
116
can obtain a sage function object by setting
117
118
def my_group_map( groupEle ):
119
return gap_group_map( groupEle, my_target_group, my_gap_hom )
120
121
EXAMPLE:
122
123
isoToPerm = Group_gap.IsomorphismPermGroup()
124
125
permGens = isoToPerm.Image().GeneratorsOfGroup().sage()
126
PermGroup = PermutationGroup( permGens )
127
128
def groupIso( groupEle ):
129
return gap_group_map( groupEle, PermGroup, isoToPerm )
130
131
132
AUTHOR
133
134
- Sebastian Oehms, Sept. 2016
135
136
"""
137
try:
138
groupEle_gap = groupEle.gap()
139
except:
140
groupEle_gap = gap(groupEle)
141
142
imGroupEle_gap = gap_result( gapHom.ImageElm( groupEle_gap ) )
143
144
if imGroupEle_gap == None:
145
raise RuntimeError( "gap cannot compute image of %s"%(groupEle_gap) )
146
147
try:
148
imGroupEle = GroupTo(imGroupEle_gap.sage())
149
except:
150
imGroupEle = GroupTo( imGroupEle_gap )
151
152
return imGroupEle
153
154
155
156
157
158
159
160
# -------------------------------------------------------------------------------
161
# register_hom
162
# definition as homomorphism and registration
163
# -------------------------------------------------------------------------------
164
def register_hom( GroupFrom, GroupTo, groupMap, verbose = False ):
165
"""
166
This function registers the function object GroupMap as a Hom-Object, coerecion and conversion to the sage group
167
GroupTo
168
169
If you don't see this well formatted type
170
171
sage: print register_hom.__doc__
172
173
INPUT:
174
175
- "GroupFrom": source group as a sage object
176
177
- "GroupTo": target group as a sage object
178
179
- "GroupMap": the map to be registered as a sage function object
180
181
- "verbose": optional keyword to print time stamp debugging messages
182
This keyword uses the timeStampControl class. For more information on this type
183
184
print setupTimeStamp.__doc__
185
print timeStampControl.__doc__
186
print timeStampControl.print_timestamp.__doc__
187
print print_time_tb.__doc__
188
189
OUTPUT:
190
191
the function object groupMap as an element of Hom( GroupFrom, GroupTo )
192
193
194
AUTHOR
195
196
- Sebastian Oehms, Sept. 2016
197
198
"""
199
200
TimeStamp = setupTimeStamp( verbose = verbose )
201
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
202
203
204
try:
205
#---------------------------------------------------------------------------------------
206
# Note: for sage version less than 7.2 this may succeed even though groupMap fails to
207
# be a homomorhism (see differences in groups/matrix_gps/morphism.py
208
# and groups/matrix_gps/homset.py)
209
#---------------------------------------------------------------------------------------
210
groupHom = Hom( GroupFrom, GroupTo )(groupMap)
211
except:
212
groupHom = groupMap
213
TimeStamp.print_timestamp( Text = "no hom", Level = TsLevel.Debug )
214
215
try:
216
GroupTo.register_coercion( groupHom )
217
except:
218
TimeStamp.print_timestamp( Text = "no coercion", Level = TsLevel.Debug )
219
220
try:
221
GroupTo.register_conversion( groupHom )
222
except:
223
TimeStamp.print_timestamp( Text = "no conversion", Level = TsLevel.Debug )
224
225
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
226
227
return groupHom
228
229
230
231
###############################################################################
232
# Group Hom Via GAP main-Function: gap_hom
233
###############################################################################
234
235
# -------------------------------------------------------------------------------
236
# gap_word_problem (needed in expand_map_from_generators)
237
# -------------------------------------------------------------------------------
238
def gap_word_problem( element, genList, verbose = False ):
239
"""
240
variant of the sage word_problem-method which behaves identical for permutation
241
groups as well as for matrix-group and other groups
242
243
If you don't see this well formatted type
244
245
sage: print gap_word_problem.__doc__
246
247
Three sage-classes have got a word_problem method as an implementation of the gap function "EpimorphismFromFreeGroup":
248
249
- GroupElementMixinLibGAP ( sage.groups.libgap_mixin )
250
- PermutationGroupElement ( sage.groups.perm_gps.permgroup_element )
251
- DualAbelianGroupElement ( sage.groups.abelian_gps.dual_abelian_group_element )
252
253
But all three methods behave different and are implemented differently. None of these methods returns the result as
254
a list, in order to use it in a function. It seems that the original purpose is only to display the result.
255
Also note, that the PermutationGroupElement method displays the result returned by gap in a wrong way, as can be seen
256
from the following example:
257
258
sage: S3=SymmetricGroup(4)
259
sage: s1, s2 = S3.gens()
260
sage: s = s1**3*s2*s1; s
261
(2,3)
262
sage: sw = s.word_problem(S3.gens())
263
x2^-1*x1^-1*(x1^-1*x2^-1)^2*x2^-1*x1^-2*x2^-1*x1^-1
264
[['(1,2)', -1], ['(1,2,3,4)', -1], ['((1,2,3,4)', -1], ['(1,2)', -1], ['(1,2,3,4)', -2],
265
['(1,2)', -1], ['(1,2,3,4)', -1]]
266
sage: sw
267
('x2^-1*x1^-1*(x1^-1*x2^-1)^2*x2^-1*x1^-2*x2^-1*x1^-1',
268
'(1,2)^-1*(1,2,3,4)^-1*((1,2,3,4)^-1*(1,2)^-1)^2*(1,2)^-1*(1,2,3,4)^-2*(1,2)^-1*(1,2,3,4)^-1')
269
270
Here the output displayed in the second line (which is only printed and not returned as result of the function)
271
ignores the brackets (...)**2 (around the expression "x1^-1*x2^-1") returned by gap.
272
273
The function "gap_word_problem" deals with the same task, but returns the result in list form. Continuing with the
274
above example we get
275
276
sage: swg = gap_word_problem(s, S3.gens()); swg
277
[(1,2), -1, (1,2,3,4), -2, (1,2), -1, (1,2,3,4), -1, (1,2), -2, (1,2,3,4), -2, (1,2), -1, (1,2,3,4), -1]
278
sage: check=S3.one()
279
sage: for i in range(len(swg)/2):
280
check = check * swg[2*i]**swg[2*i+1]
281
....:
282
sage: check == s
283
True
284
285
286
INPUT:
287
288
- "element": an element in a group to be represented in terms of a set of generators
289
290
- "genList": list of generators in the same group as element, such that element lies in the subgroup generated
291
by them
292
- "verbose": optional keyword to print time stamp debugging messages
293
This keyword uses the timeStampControl class. For more information on this type
294
295
print setupTimeStamp.__doc__
296
print timeStampControl.__doc__
297
print timeStampControl.print_timestamp.__doc__
298
print print_time_tb.__doc__
299
300
301
OUTPUT:
302
303
a word in the generators in "genList" representing "element" as a list of length 2*l if l is the length of the
304
word. This list has the form (w_1, e_1, w_2, e_2, .... , w_l, e_l) where the w_i in genList are the generators
305
in the word expression whereas the e_i are the corresponding exponents, that is
306
307
element = w_1**e_1 * w_2**e_2 * .... * w_l**e_
308
309
RAISE:
310
311
- TypeError: "generator genList[0] must have a parent" if the first element of genList has no attribute "parent"
312
313
- TypeError: "parent of generator genList[0] must be an instance of Group" if the first element of genList does
314
not belong to a group
315
316
EXAMPLE:
317
318
continuing the example above we look at the type returned
319
320
sage: type(sw)
321
<type 'tuple'>
322
sage: type(sw[1])
323
<type 'str'>
324
sage: type(sw[0])
325
<type 'str'>
326
327
sage: type(swg)
328
<type 'list'>
329
sage: type(swg[0])
330
<type 'sage.groups.perm_gps.permgroup_element.PermutationGroupElement'>
331
sage: type(swg[1])
332
<type 'sage.rings.integer.Integer'>
333
sage:
334
335
an example of matrix groups
336
337
sage: GL3_3=GL(3,3)
338
sage: g1, g2 = GL3_3.gens()
339
sage: g1, g2 = GL3_3.gens(); g1, g2
340
(
341
[2 0 0] [2 0 1]
342
[0 1 0] [2 0 0]
343
[0 0 1], [0 2 0]
344
)
345
sage: g = g1**2*g2*g1; g
346
[1 0 1]
347
[1 0 0]
348
[0 2 0]
349
sage: gwg = gap_word_problem(g, [g1,g2] ); gwg
350
[
351
[2 0 1] [2 0 0]
352
[2 0 0] [0 1 0]
353
[0 2 0], 1, [0 0 1], -1
354
]
355
sage:
356
sage: check=GL3_3.one()
357
sage: for i in range(len(gwg)/2):
358
check = check * gwg[2*i]**gwg[2*i+1]
359
....:
360
sage: check == g
361
True
362
363
an example of fintely preseted groups
364
365
sage: B3 = BraidGroup(3); B3
366
Braid group on 3 strands
367
sage: b1, b2 = B3.gens()
368
sage: b1, b2 = B3.gens(); b1, b2
369
(s0, s1)
370
sage:
371
sage:
372
sage: b = b1**2*b2*b1; b
373
s0^2*s1*s0
374
sage: bwg = gap_word_problem(b, [b1,b2] ); bwg
375
[s0, 1, s0, 1, s1, 1, s0, 1]
376
sage: check=B3.one()
377
sage: for i in range(len(bwg)/2):
378
check = check * bwg[2*i]**bwg[2*i+1]
379
....:
380
sage: check == b
381
True
382
383
384
AUTHOR
385
386
- Sebastian Oehms, Sept. 2016
387
388
"""
389
390
TimeStamp = setupTimeStamp( verbose = verbose )
391
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
392
393
if 'Tietze' in dir(element):
394
result = []
395
for i in element.Tietze():
396
if i > _sage_const_0 :
397
result.append( genList[i-_sage_const_1 ] )
398
result.append( _sage_const_1 )
399
elif i < _sage_const_0 :
400
result.append( genList[-i-_sage_const_1 ] )
401
result.append( -_sage_const_1 )
402
return result
403
404
n=len(genList)
405
cmd="Fg:=FreeGroup(%d);"%(n)
406
libgap.eval(cmd)
407
for i in range(n):
408
cmd="x%d := GeneratorsOfGroup(Fg)[%d];"%(i+_sage_const_1 ,i+_sage_const_1 )
409
libgap.eval(cmd)
410
411
if 'parent' not in dir( genList[_sage_const_0 ] ):
412
raise TypeError( "generator %s must have a parent"%(genList[_sage_const_0 ]) )
413
414
GroupFrom = genList[_sage_const_0 ].parent()
415
416
if isinstance( GroupFrom, sage.groups.old.Group ) == False and isinstance( GroupFrom, sage.groups.group.Group ) == False:
417
raise TypeError( "parent of generator %s must be an instance of Group"%(genList[_sage_const_0 ]) )
418
419
420
if 'gap' in dir(GroupFrom):
421
G = GroupFrom.gap()
422
else:
423
G = gap(GroupFrom)
424
425
if 'gap' in dir(GroupFrom(element)):
426
g = GroupFrom(element).gap()
427
else:
428
g = GroupFrom(element)
429
430
try:
431
genList_gap = [gen.gap() for gen in genList]
432
except:
433
genList_gap = [libgap(gen) for gen in genList]
434
435
H=G.Subgroup( genList_gap )
436
ans = H.EpimorphismFromFreeGroup().PreImagesRepresentative(g)
437
ans_repl = ans.UnderlyingElement()
438
num = ans_repl.NumberSyllables().sage()
439
440
result = []
441
exponent_syllable = libgap.eval('ExponentSyllable')
442
generator_syllable = libgap.eval('GeneratorSyllable')
443
for i in range(num):
444
exponent = exponent_syllable(ans_repl, i+_sage_const_1 ).sage()
445
generator = generator_syllable(ans_repl, i+_sage_const_1 ).sage() - _sage_const_1
446
result.append( genList[generator] )
447
result.append( exponent )
448
449
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
450
451
return result
452
453
454
455
456
# -------------------------------------------------------------------------------
457
# expand_map_from_generators (needed in gap_hom)
458
# -------------------------------------------------------------------------------
459
def expand_map_from_generators( GroupFrom, GroupTo, GensFrom = None, GensTo = None, verbose = False):
460
"""
461
expand a map given on generators of GroupFrom into another GroupTo. If the optional keyword GensFrom and GensTo
462
are not set the generators of GroupFrom and GroupTo will be used instead
463
464
Note: it is not checked if this gives a well defined homomorphis. This must be known or checked separately
465
466
467
If you don't see this well formatted type
468
469
sage: print expand_map_from_generators.__doc__
470
471
This functin is based on the gap_word_problem function and therefor on the gap function "EpimorphismFromFreeGroup"
472
473
INPUT:
474
475
- "GroupFrom": the source group of the map to be generated
476
477
- "GroupTo": the target group of the map to be generated
478
479
- "GensFrom": (optional keyword, default = None takes GroupFrom.gens()) set of generators of GroupFrom which
480
should be mapped to the according elements (same order) of GensTo resp. GroupTo.gens()
481
482
- "GensTo": (optional keyword, default = None takes Groupo.gens()) set of generators of GroupTo which
483
should be the images of the according elements (same order) of GensFrom resp. GroupFrom.gens()
484
485
- "verbose": optional keyword to print time stamp debugging messages
486
This keyword uses the timeStampControl class. For more information on this type
487
488
print setupTimeStamp.__doc__
489
print timeStampControl.__doc__
490
print timeStampControl.print_timestamp.__doc__
491
print print_time_tb.__doc__
492
493
494
OUTPUT:
495
496
a function object of the following form:
497
498
INPUT:
499
500
- "Ele" an arbitrary element of GroupFrom
501
502
OUTPUT:
503
504
the corresponding element in GroupTo under the map defined
505
506
507
RAISE:
508
509
- TypeError: "GroupFrom must be an instance of Group"
510
511
- TypeError: "GroupTo must be an instance of Group"
512
513
- ValueError: "incompatible length of generator sets" if the list of generators of source and targed have different
514
length
515
516
EXAMPLE:
517
518
sage: S3=SymmetricGroup(4); S3
519
Symmetric group of order 4! as a permutation group
520
521
sage: s1, s2 = S3.gens()
522
sage: s = s1**3*s2*s1; s
523
(2,3)
524
sage:
525
sage: GU3 = GU(3,2); GU3
526
General Unitary Group of degree 3 over Finite Field in a of size 2^2 with respect to hermitian form
527
[0 0 1]
528
[0 1 0]
529
[1 0 0]
530
sage:
531
sage: S3toGU3 = expand_map_from_generators( S3, GU3); S3toGU3
532
<function Map at 0x9ac3e0d4>
533
sage: g = S3toGU3(s); g
534
[1 a a]
535
[a a 0]
536
[a 0 0]
537
538
note that S3toGU3 is not a group homomorphism
539
540
sage: g1 = S3toGU3(s1); g1
541
[a 0 0]
542
[0 1 0]
543
[0 0 a]
544
sage: g2 = S3toGU3(s2); g2
545
[ 0 0 1]
546
[ 0 1 1]
547
[ 1 1 a + 1]
548
sage: g_check = g1**3*g2*g1; g_check
549
[0 0 a]
550
[0 1 a]
551
[a 1 1]
552
sage: g == g_check
553
False
554
555
556
AUTHOR
557
558
- Sebastian Oehms, Sept. 2016
559
560
"""
561
562
TimeStamp = setupTimeStamp( verbose = verbose )
563
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
564
565
if isinstance( GroupFrom, sage.groups.old.Group ) == False and isinstance( GroupFrom, sage.groups.group.Group ) == False:
566
raise TypeError( "GroupFrom must be an instance of Group" )
567
568
if isinstance( GroupTo, sage.groups.old.Group ) == False and isinstance( GroupTo, sage.groups.group.Group ) == False:
569
raise TypeError( "GroupTo must be an instance of Group" )
570
571
if GensFrom != None:
572
Fgens = [GroupFrom(g) for g in GensFrom]
573
else:
574
Fgens = GroupFrom.gens()
575
576
if GensTo != None:
577
Tgens = [GroupTo(g) for g in GensTo]
578
else:
579
Tgens = GroupTo.gens()
580
581
if len(Fgens) !=len(Tgens):
582
raise ValueError( "incompatible length of generator sets" )
583
584
def Map( Ele ):
585
EleGens = gap_word_problem(Ele, Fgens)
586
anzLetter = len( EleGens )/_sage_const_2
587
ToEle = GroupTo.one()
588
for i in range(anzLetter):
589
for fGen in Fgens:
590
if EleGens[_sage_const_2 *i] == fGen:
591
tGen = Tgens[Fgens.index(fGen)]
592
ToEle = ToEle * tGen**(EleGens[_sage_const_2 *i+_sage_const_1 ])
593
return ToEle
594
595
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
596
597
return Map
598
599
600
601
# -------------------------------------------------------------------------------
602
# -------------------------------------------------------------------------------
603
# gap_hom (main-function)
604
# -------------------------------------------------------------------------------
605
# -------------------------------------------------------------------------------
606
def gap_hom( GroupFrom, GroupTo, GensFrom=None, GensTo=None, check = False, verbose = False ):
607
"""
608
This function creates a map from GroupFrom to GroupTo via the GAP-function 'GroupHomomorphismByImages' such that
609
generators GensFrom are mapped to GensTo. If the optional parameter GensFrom and GensTo are not set the generators
610
of GroupFrom and GroupTo will be used instead.
611
612
If GroupHomomorphismByImages fails on the task the function expand_map_from_generators is used for a second try
613
This function is based on GAP-function 'EpimorphismFromFreeGroup' (via gap_word_problem). For more information
614
on this type
615
616
sage: print expand_map_from_generators.__doc__
617
sage: print gap_word_problem.__doc__
618
619
620
Note: it is not checked if this gives a well defined homomorphism by default. To achieve this set the
621
keyword check = True
622
623
If you don't see this well formatted type
624
625
sage: print expand_map_from_generators.__doc__
626
627
INPUT:
628
629
- "GroupFrom": the source group of the map to be generated
630
631
- "GroupTo": the target group of the map to be generated
632
633
- "GensFrom": (optional keyword, default = None takes GroupFrom.gens()) set of generators of GroupFrom which
634
should be mapped to the according elements (same order) of GensTo resp. GroupTo.gens()
635
636
- "GensTo": (optional keyword, default = None takes Groupo.gens()) set of generators of GroupTo which
637
should be the images of the according elements (same order) of GensFrom resp. GroupFrom.gens()
638
639
- "check": optional boolean, default = False. If set to True the constructed map is tested to be a a well
640
defined group homomorphism. Depending wether the gap function "GroupHomomorphismByImages"
641
can be used the check is perfomed by gap. In the other case a NotImplemented Exception is raised.
642
643
- "verbose": optional keyword to print time stamp debugging messages
644
This keyword uses the timeStampControl class. For more information on this type
645
646
print setupTimeStamp.__doc__
647
print timeStampControl.__doc__
648
print timeStampControl.print_timestamp.__doc__
649
print print_time_tb.__doc__
650
651
652
OUTPUT:
653
654
an element of Hom( GroupFrom, GroupTo )
655
656
657
RAISE:
658
659
- TypeError: "GroupFrom must be an instance of Group"
660
661
- TypeError: "GroupTo must be an instance of Group"
662
663
- ValueError: "incompatible length of generator sets" if the list of generators of source and targed have different
664
length
665
666
- RuntimeError: "One does not map to one" if check = True, else a warning
667
668
- RuntimeError: "No map definition possible" the test that the contructed map works failed
669
670
- RuntimeError: "gap cannot compute image of ..." occurs when the constructed map is applied: calculation of
671
the image of a specific element failed
672
673
- NotImplementedError: "no check for expand_map_from_generators - try again with check = False" occurs if
674
check is set to True and gap function "GroupHomomorphismByImages" can not be applied
675
676
677
EXAMPLE:
678
679
680
sage: B3 = BraidGroup(3)
681
sage: S3=SymmetricGroup(3)
682
sage: Im=[S3((1,2)), S3((2,3))]; Im
683
[(1,2), (2,3)]
684
sage: b2s = gap_hom( B3, S3, GensTo=Im ); b2s
685
Generic morphism:
686
From: Braid group on 3 strands
687
To: Symmetric group of order 3! as a permutation group
688
sage: b1, b2 = B3.gens(); b1, b2
689
(s0, s1)
690
sage: b2s(b1*b2*b1)
691
(1,3)
692
sage: b2s(b2*b1*b2)
693
(1,3)
694
695
check if the map is indeed a homomorphism of groups
696
697
sage: b2s_check = gap_hom( B3, S3, GensTo=Im, check=True )
698
sage: b2s(b1) == b2s_check(b1)
699
True
700
sage: b2s(b2) == b2s_check(b2)
701
True
702
703
CAUTION: by default it is not checked if the map is well defined nor a homomorphism:
704
705
sage: b2s_wrong = gap_hom( B3, S3 ); b2s_wrong
706
Generic morphism:
707
From: Braid group on 3 strands
708
To: Symmetric group of order 3! as a permutation group
709
sage:
710
sage: b = b1*b2*b1
711
sage: bb = b2*b1*b2
712
sage: b == bb
713
True
714
sage: b2s_wrong(b) == b2s_wrong(bb)
715
False
716
717
You can check this as follows:
718
719
sage: b2s_wrong = gap_hom( B3, S3, check=True ); b2s_wrong
720
............
721
722
RuntimeError: No map definition possible
723
sage:
724
725
726
AUTHOR
727
728
- Sebastian Oehms, Sept. 2016
729
730
"""
731
732
TimeStamp = setupTimeStamp( verbose = verbose )
733
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
734
735
736
# -----------------------------------------------------------------------------------------------------
737
# checks and preperations
738
# -----------------------------------------------------------------------------------------------------
739
740
if isinstance( GroupFrom, sage.groups.old.Group ) == False and isinstance( GroupFrom, sage.groups.group.Group ) == False:
741
raise TypeError( "GroupFrom must be an instance of Group" )
742
743
if isinstance( GroupTo, sage.groups.old.Group ) == False and isinstance( GroupTo, sage.groups.group.Group ) == False:
744
raise TypeError( "GroupTo must be an instance of Group" )
745
746
747
try:
748
GroupFrom_gap = GroupFrom.gap()
749
except:
750
GroupFrom_gap = gap(GroupFrom)
751
TimeStamp.print_timestamp( Text = "gap(GroupFrom)", Level = TsLevel.Debug )
752
753
try:
754
GroupTo_gap = GroupTo.gap()
755
except:
756
GroupTo_gap = gap(GroupTo)
757
TimeStamp.print_timestamp( Text = "gap(GroupTo)", Level = TsLevel.Debug )
758
759
if GensFrom == None:
760
GensFrom_gap = GroupFrom_gap.GeneratorsOfGroup()
761
else:
762
try:
763
GensFrom_gap = [gen.gap() for gen in GensFrom]
764
except:
765
GensFrom_gap = [libgap(gen) for gen in GensFrom]
766
TimeStamp.print_timestamp( Text = "libgap(gen) GensFrom", Level = TsLevel.Debug )
767
768
if GensTo == None:
769
GensTo_gap = GroupTo_gap.GeneratorsOfGroup()
770
else:
771
try:
772
GensTo_gap = [gen.gap() for gen in GensTo]
773
except:
774
GensTo_gap = [libgap(gen) for gen in GensTo]
775
TimeStamp.print_timestamp( Text = "libgap(gen) GensTo", Level = TsLevel.Debug )
776
777
778
if len(GensFrom_gap) !=len(GensTo_gap):
779
raise ValueError( "incompatible length of generator sets" )
780
781
# -----------------------------------------------------------------------------------------------------
782
# do the job
783
# -----------------------------------------------------------------------------------------------------
784
785
try:
786
if check == False:
787
gHom_gap = gap_result( GroupFrom_gap.GroupHomomorphismByImagesNC( GroupTo_gap, GensFrom_gap, GensTo_gap ) )
788
else:
789
gHom_gap = gap_result( GroupFrom_gap.GroupHomomorphismByImages( GroupTo_gap, GensFrom_gap, GensTo_gap ) )
790
791
if gHom_gap == None:
792
if check == False:
793
groupMap = expand_map_from_generators( GroupFrom, GroupTo, GensFrom, GensTo, verbose = verbose )
794
else:
795
raise NotImplementedError( "no check for expand_map_from_generators - try again with check = False" )
796
797
TimeStamp.print_timestamp( Text = "expand_map_from_generators pos1", Level = TsLevel.Debug )
798
else:
799
def groupMap( groupEle ):
800
return gap_group_map( groupEle, GroupTo, gHom_gap )
801
802
TimeStamp.print_timestamp( Text = "GroupHomomorphis", Level = TsLevel.Debug )
803
804
except:
805
if check == False:
806
groupMap = expand_map_from_generators( GroupFrom, GroupTo, GensFrom, GensTo, verbose = verbose )
807
else:
808
raise NotImplementedError( "no check for expand_map_from_generators - try again with check = False" )
809
810
TimeStamp.print_timestamp( Text = "expand_map_from_generators pos2", Level = TsLevel.Debug )
811
812
813
# -------------------------------------------------------------------------------------
814
# Check if groupMap works
815
# -------------------------------------------------------------------------------------
816
817
try:
818
One = groupMap( GroupFrom.one() )
819
TimeStamp.print_timestamp( Text = "checked if groupMap works", Level = TsLevel.Debug )
820
if One != GroupTo.one():
821
if check == True:
822
raise RuntimeError( "One does not map to one" )
823
else:
824
print "Warning: one does not map to one"
825
except:
826
raise RuntimeError( "No map definition possible" )
827
828
829
# -------------------------------------------------------------------------------------
830
# definition as homomorphism and registration
831
# -------------------------------------------------------------------------------------
832
833
groupHom = register_hom( GroupFrom, GroupTo, groupMap, verbose = verbose )
834
835
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
836
837
return groupHom
838
839
840
841
842
843
844
845
846
847
848
849
850
# -------------------------------------------------------------------------------
851
# gap_as_permutation_group
852
# -------------------------------------------------------------------------------
853
def gap_as_permutation_group( Group, verbose = False ):
854
"""
855
This function is an extension of the Sage as_permutation_group-method of the classes
856
857
- sage.groups.matrix_gps/finitely_generated.FinitelyGeneratedMatrixGroup_gap
858
- sage.groups.finitely_presente.FinitelyPresentedGroup
859
860
using the GAP-function 'IsomorphismPermGroup'. It can be applied to other cases of groups.
861
Furthermore the isompophism map returned by gap is registered as a conversion map to and from the permutation group
862
defined (which is not the case for the above mentioned methods)
863
864
If you don't see this well formatted type
865
866
sage: print gap_as_permutation_group.__doc__
867
868
INPUT:
869
870
- "Group": the group for which an isomorphism to a permutation group should be found
871
872
- "verbose": optional keyword to print time stamp debugging messages
873
This keyword uses the timeStampControl class. For more information on this type
874
875
print setupTimeStamp.__doc__
876
print timeStampControl.__doc__
877
print timeStampControl.print_timestamp.__doc__
878
print print_time_tb.__doc__
879
880
OUTPUT:
881
882
- an isomporphic permutation group to Group together with the isomorphism registered as conversion maps
883
for Group and the returned permutation group
884
885
RAISE:
886
887
- TypeError: "Group must be an instance of Group"
888
889
- RuntimeError: "gap fails to compute permutation group!"
890
891
- NotImplementedError: "Group must be finite."
892
893
EXAMPLE:
894
895
sage: Sp4 = Sp(4,3); Sp4
896
Symplectic Group of degree 4 over Finite Field of size 3
897
sage: PSp4 = gap_as_permutation_group( Sp4 ); PSp4
898
Permutation Group with generators [(1,2)(3,5)(4,7)(6,10)(8,13)(9,15)(11,18)(12,20)(14,19)(16,24)(17,26)(21,31)
899
(22,33)(23,35)(25,32)(27,40)(28,42)(29,44)(30,46)(34,51)(36,53)(37,54)(38,55)(39,50)(43,60)(45,62)(47,56)(48,59)
900
(49,64)(57,66)(58,65)(61,63)(69,73)(71,75)(74,78)(76,77), (1,3,6,11,19,29,45,63,72)(2,4,8,14,18,28,43,61,70)
901
(5,9,16,25,38,56,62,71,76)(7,12,21,32,49,53,60,69,74)(10,17,27,41,59,68,40,58,44)(13,22,34,52,54,67,51,66,42)
902
(15,23,36)(20,30,47)(24,37,55)(26,39,57)(31,48,64)(33,50,65)(73,77,79)(75,78,80)]
903
sage: s1, s2 = Sp4.gens(); s1, s2
904
(
905
[2 0 0 0] [1 0 1 0]
906
[0 1 0 0] [1 0 0 0]
907
[0 0 1 0] [0 1 0 1]
908
[0 0 0 2], [0 2 0 0]
909
)
910
sage: s = s1*s2**2; s
911
[2 2 2 2]
912
[1 0 1 0]
913
[1 2 0 0]
914
[1 0 0 0]
915
sage:
916
sage: sp2p = PSp4.convert_map_from( Sp4 )
917
sage: p2sp = Sp4.convert_map_from( PSp4 )
918
sage:
919
sage: p1 = sp2p( s1 ); p1
920
(1,2)(3,5)(4,7)(6,10)(8,13)(9,15)(11,18)(12,20)(14,19)(16,24)(17,26)(21,31)(22,33)(23,35)(25,32)(27,40)(28,42)(29,44)
921
(30,46)(34,51)(36,53)(37,54)(38,55)(39,50)(43,60)(45,62)(47,56)(48,59)(49,64)(57,66)(58,65)(61,63)(69,73)(71,75)
922
(74,78)(76,77)
923
sage: p2 = sp2p( s2 ); p2
924
(1,3,6,11,19,29,45,63,72)(2,4,8,14,18,28,43,61,70)(5,9,16,25,38,56,62,71,76)(7,12,21,32,49,53,60,69,74)
925
(10,17,27,41,59,68,40,58,44)(13,22,34,52,54,67,51,66,42)(15,23,36)(20,30,47)(24,37,55)(26,39,57)(31,48,64)(33,50,65)
926
(73,77,79)(75,78,80)
927
sage: p = sp2p( s ); p
928
(1,8,34,42,61)(2,6,27,44,63)(3,16,55,62,72)(4,21,64,60,70)(5,11,43,74,75)(7,14,45,76,73)(9,36,69,79,77)
929
(10,19,28,22,65)(12,47,71,80,78)(13,18,29,17,57)(15,25,53,23,35)(20,32,56,30,46)(24,38,37,51,54)(26,41,68,58,50)
930
(31,49,48,40,59)(33,52,67,66,39)
931
sage: s1 == p2sp( p1 )
932
True
933
sage: s2 == p2sp( p2 )
934
True
935
sage: s == p2sp( p)
936
True
937
sage:
938
939
940
941
AUTHOR
942
943
- Sebastian Oehms, Sept. 2016
944
945
"""
946
947
TimeStamp = setupTimeStamp( verbose = verbose )
948
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
949
950
# -----------------------------------------------------------------------------------------------------
951
# checks and preperations
952
# -----------------------------------------------------------------------------------------------------
953
954
if isinstance( Group, sage.groups.old.Group ) == False and isinstance( Group, sage.groups.group.Group ) == False:
955
raise TypeError( "Group must be an instance of Group" )
956
957
if not Group.is_finite():
958
raise NotImplementedError("Group must be finite.")
959
960
try:
961
Group_gap = Group.gap()
962
except:
963
Group_gap = gap(Group)
964
965
isoToPerm = gap_result( Group_gap.IsomorphismPermGroup() )
966
967
if isoToPerm == None:
968
raise RuntimeError("gap fails to compute permutation group!")
969
970
isoToPermInv = isoToPerm.InverseGeneralMapping()
971
permGens = isoToPerm.Image().GeneratorsOfGroup().sage()
972
PermGroup = PermutationGroup( permGens )
973
974
TimeStamp.print_timestamp( Text = "PermutationGroup defined", Level = TsLevel.Debug )
975
976
def groupIso( groupEle ):
977
return gap_group_map( groupEle, PermGroup, isoToPerm )
978
979
def groupIsoInv ( groupEle ):
980
return gap_group_map( groupEle, Group, isoToPermInv )
981
982
TimeStamp.print_timestamp( Text = "groupIso defined", Level = TsLevel.Debug )
983
984
985
# -------------------------------------------------------------------------------------
986
# definition as homomorphism and registration
987
# -------------------------------------------------------------------------------------
988
989
register_hom( Group, PermGroup, groupIso, verbose = verbose )
990
991
992
# -------------------------------------------------------------------------------------
993
# now for inverse mapping
994
# -------------------------------------------------------------------------------------
995
996
register_hom( PermGroup, Group, groupIsoInv, verbose = verbose )
997
998
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
999
1000
return PermGroup
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
# -------------------------------------------------------------------------------
1021
# gap_centralizer
1022
# -------------------------------------------------------------------------------
1023
def gap_centralizer( Group, Element, verbose = False ):
1024
"""
1025
This function returns the centralizer of an Element of the Group using the GAP-function
1026
'Centralizer'. This extends the use of this GAP-function in sage to Groups which are not
1027
permutation groups (note that the sage-method centralizer is defined for peremutation group, only)
1028
1029
If you don't see this well formatted type
1030
1031
sage: print gap_centralizer.__doc__
1032
1033
INPUT:
1034
1035
- "Group": the group in which the centralizer should be calculated
1036
1037
- "Element": element in Group which shoul commute with all elements of the centralizer
1038
1039
- "verbose": optional keyword to print time stamp debugging messages
1040
This keyword uses the timeStampControl class. For more information on this type
1041
1042
print setupTimeStamp.__doc__
1043
print timeStampControl.__doc__
1044
print timeStampControl.print_timestamp.__doc__
1045
print print_time_tb.__doc__
1046
1047
OUTPUT:
1048
1049
the maximal subgroup of "Group" whose elements commute with the given "Element" as sage subgroup of "Group"
1050
1051
1052
EXAMPLES:
1053
1054
sage: Sp4 = Sp(4,3)
1055
sage: s1, s2 = Sp4.gens(); s1, s2
1056
(
1057
[2 0 0 0] [1 0 1 0]
1058
[0 1 0 0] [1 0 0 0]
1059
[0 0 1 0] [0 1 0 1]
1060
[0 0 0 2], [0 2 0 0]
1061
)
1062
sage: s = s1*s2**2; s
1063
[2 2 2 2]
1064
[1 0 1 0]
1065
[1 2 0 0]
1066
[1 0 0 0]
1067
sage: CSp4s = gap_centralizer( Sp4, s ); CSp4s
1068
Matrix group over Finite Field of size 3 with 2 generators (
1069
[2 2 2 2] [2 0 0 0]
1070
[1 0 1 0] [0 2 0 0]
1071
[1 2 0 0] [0 0 2 0]
1072
[1 0 0 0], [0 0 0 2]
1073
)
1074
sage: c1, c2 = CSp4s.gens()
1075
sage: cs1=Sp4(c1); cs1
1076
[2 2 2 2]
1077
[1 0 1 0]
1078
[1 2 0 0]
1079
[1 0 0 0]
1080
sage: cs2=Sp4(c2); cs2
1081
[2 0 0 0]
1082
[0 2 0 0]
1083
[0 0 2 0]
1084
[0 0 0 2]
1085
sage: cs1*s == s * cs1
1086
True
1087
sage: cs2*s == s * cs2
1088
True
1089
sage:
1090
1091
1092
AUTHOR
1093
1094
- Sebastian Oehms, Sept. 2016
1095
1096
"""
1097
1098
TimeStamp = setupTimeStamp( verbose = verbose )
1099
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
1100
1101
try:
1102
Group_gap = Group.gap()
1103
except:
1104
Group_gap = gap(Group)
1105
1106
try:
1107
Element_gap = Element.gap()
1108
except:
1109
Element_gap = gap(Element)
1110
1111
TimeStamp.print_timestamp( Text = "Calling Gap", Level = TsLevel.Body )
1112
1113
centralizer_gap = Group_gap.Centralizer(Element_gap)
1114
1115
TimeStamp.print_timestamp( Text = "setting sage generator list", Level = TsLevel.Body )
1116
1117
GenList = [ Group(gen) for gen in centralizer_gap.GeneratorsOfGroup() ]
1118
1119
TimeStamp.print_timestamp( Text = "defining subgroup", Level = TsLevel.Body )
1120
1121
centralizer = Group.subgroup( GenList )
1122
1123
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
1124
1125
return centralizer
1126
1127
1128
1129
1130
1131
def gap_extend_workspace( new_size ):
1132
"""
1133
extends the minimum GAP workspace to the given value if possible:
1134
1135
1136
If you don't see this well formatted type
1137
1138
sage: print gap_extend_workspace.__doc__
1139
1140
INPUT:
1141
1142
- "new_size" the new size in byte to which the gap workspace should be extended
1143
1144
RAISE:
1145
1146
TypeError: "new_size must be of type Integer!"
1147
1148
MESSAGES:
1149
1150
informational:
1151
1152
"Note: GAP workspace has been extended: %d -> %d"%(akt_memory_pool_size, new_memory_pool_size)
1153
1154
warning:
1155
1156
"Warning: cannont extend the GAP workspace more than half of swap and 4/5 of ram" if new_size is byond the limits
1157
of hardware recources
1158
1159
1160
EXAMPLES::
1161
1162
on an Acer AO Happy under LinuxMint 17.3 Mate with 2 GB RAM:
1163
1164
sage: oneHundertMB = 100*1024**2
1165
sage: gap_extend_workspace( 8*oneHundertMB )
1166
Note: GAP workspace has been extended: 262144000 -> 838860800
1167
sage:
1168
sage: gap_extend_workspace( 13*oneHundertMB )
1169
Warning: cannont extend the GAP workspace more than half of swap and 4/5 of ram
1170
Note: GAP workspace has been extended: 262144000 -> 1058121318
1171
sage:
1172
1173
AUTHOR
1174
1175
- Sebastian Oehms, Sept. 2016
1176
1177
"""
1178
1179
if isinstance( new_size, Integer ) == False:
1180
raise TypeError( "new_size must be of type Integer!" )
1181
1182
from sage.interfaces.gap import get_gap_memory_pool_size, set_gap_memory_pool_size
1183
from sage.misc.memory_info import MemoryInfo
1184
1185
akt_memory_pool_size = get_gap_memory_pool_size()
1186
new_memory_pool_size = int(new_size)
1187
1188
mem = MemoryInfo()
1189
1190
if ( new_memory_pool_size > mem.available_swap() // _sage_const_2 ) and ( new_memory_pool_size > _sage_const_4 * mem.available_ram() // _sage_const_5 ):
1191
print "Warning: cannont extend the GAP workspace more than half of swap and 4/5 of ram"
1192
new_memory_pool_size = max(mem.available_swap() // _sage_const_2 , _sage_const_4 *mem.available_ram() // _sage_const_5 )
1193
1194
if new_memory_pool_size > akt_memory_pool_size:
1195
gap_reset_workspace( max_workspace_size = new_memory_pool_size )
1196
print "Note: GAP workspace has been extended: %d -> %d"%(akt_memory_pool_size, new_memory_pool_size)
1197
1198
1199
1200