from sage.all_cmdline import *
_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)
"""
####################################################################################################
# This module contains utilities for using the sage-gap-interface
####################################################################################################
##############################################################################
# Copyright (C) 2016 Sebastian Oehms <[email protected]>
#
# Distributed under the terms of the GNU General Public License (GPL)
#
# The full text of the GPL is available at:
#
# http://www.gnu.org/licenses/
##############################################################################
This module contains the following functions:
- "gap_word_problem": an improvement of the sage method word_problem belonging to the matrix group and permutation group
classes which uses the gap function "EpimorphismFromFreeGroup"
- "expand_map_from_generators": function to create a map between groups given on generators by use of the gap_word_problem
function. It can be used in some cases where the gap function "GroupHomomorphismByImages" fails
- "gap_hom": function to create a map between groups given on generators by use of the gap function
"GroupHomomorphismByImages" or the former function "expand_map_from_generators" in the cases where
"GroupHomomorphismByImages" fails
- "gap_centralizer": calculates the centralizer of an element in a group using the gap function "Centralizer"
- "gap_extend_workspace": extends the gap workspace by use of the sage gap_extend_workspace function
AUTHOR
- Sebastian Oehms, Sept. 2016
"""
from sage.groups.libgap_wrapper import ParentLibGAP
from lib.utils_sys import *
def gap_result( gap_element ):
"""
this function converts the gap boolean fail into a None object
INPUT:
- an arbtrary gap_element
OUTPUT:
the element itself or None if it is the gap-boolean fail.
"""
if gap_element != None:
if 'is_bool' in dir(gap_element):
if gap_element.is_bool():
if gap_element == libgap.eval('fail'):
return None
return gap_element
def gap_group_map( groupEle, GroupTo, gapHom ):
"""
This function can be used to converts a gap group map which was defined by the gap functions like
'GroupHomomorphismByImages' or 'IsomorhismPermGroup' or others having an ImageElm attribute into a
sage function object
If you don't see this well formatted type
sage: print gap_group_map.__doc__
INPUT:
- "groupEle": an element of the source group, whose image should be obtained, as a sage object.
- "GroupTo": the target group as a sage object
- "gapHom": the gap homomorphism which should be applied to groupEle and which has been defined by a gap functions
like 'GroupHomomorphismByImages' or 'IsomorhismPermGroup'
OUTPUT:
the value of groupEle under gap_hom as object of GroupTo
RAISE:
- RuntimeError: "gap cannot compute image of %s" If gap fails to compute the image
USAGE:
if you have defined a target group 'my_target_group' in your programm and a gap function 'my_gap_hom' then you
can obtain a sage function object by setting
def my_group_map( groupEle ):
return gap_group_map( groupEle, my_target_group, my_gap_hom )
EXAMPLE:
isoToPerm = Group_gap.IsomorphismPermGroup()
permGens = isoToPerm.Image().GeneratorsOfGroup().sage()
PermGroup = PermutationGroup( permGens )
def groupIso( groupEle ):
return gap_group_map( groupEle, PermGroup, isoToPerm )
AUTHOR
- Sebastian Oehms, Sept. 2016
"""
try:
groupEle_gap = groupEle.gap()
except:
groupEle_gap = gap(groupEle)
imGroupEle_gap = gap_result( gapHom.ImageElm( groupEle_gap ) )
if imGroupEle_gap == None:
raise RuntimeError( "gap cannot compute image of %s"%(groupEle_gap) )
try:
imGroupEle = GroupTo(imGroupEle_gap.sage())
except:
imGroupEle = GroupTo( imGroupEle_gap )
return imGroupEle
def register_hom( GroupFrom, GroupTo, groupMap, verbose = False ):
"""
This function registers the function object GroupMap as a Hom-Object, coerecion and conversion to the sage group
GroupTo
If you don't see this well formatted type
sage: print register_hom.__doc__
INPUT:
- "GroupFrom": source group as a sage object
- "GroupTo": target group as a sage object
- "GroupMap": the map to be registered as a sage function object
- "verbose": optional keyword to print time stamp debugging messages
This keyword uses the timeStampControl class. For more information on this type
print setupTimeStamp.__doc__
print timeStampControl.__doc__
print timeStampControl.print_timestamp.__doc__
print print_time_tb.__doc__
OUTPUT:
the function object groupMap as an element of Hom( GroupFrom, GroupTo )
AUTHOR
- Sebastian Oehms, Sept. 2016
"""
TimeStamp = setupTimeStamp( verbose = verbose )
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
try:
groupHom = Hom( GroupFrom, GroupTo )(groupMap)
except:
groupHom = groupMap
TimeStamp.print_timestamp( Text = "no hom", Level = TsLevel.Debug )
try:
GroupTo.register_coercion( groupHom )
except:
TimeStamp.print_timestamp( Text = "no coercion", Level = TsLevel.Debug )
try:
GroupTo.register_conversion( groupHom )
except:
TimeStamp.print_timestamp( Text = "no conversion", Level = TsLevel.Debug )
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
return groupHom
def gap_word_problem( element, genList, verbose = False ):
"""
variant of the sage word_problem-method which behaves identical for permutation
groups as well as for matrix-group and other groups
If you don't see this well formatted type
sage: print gap_word_problem.__doc__
Three sage-classes have got a word_problem method as an implementation of the gap function "EpimorphismFromFreeGroup":
- GroupElementMixinLibGAP ( sage.groups.libgap_mixin )
- PermutationGroupElement ( sage.groups.perm_gps.permgroup_element )
- DualAbelianGroupElement ( sage.groups.abelian_gps.dual_abelian_group_element )
But all three methods behave different and are implemented differently. None of these methods returns the result as
a list, in order to use it in a function. It seems that the original purpose is only to display the result.
Also note, that the PermutationGroupElement method displays the result returned by gap in a wrong way, as can be seen
from the following example:
sage: S3=SymmetricGroup(4)
sage: s1, s2 = S3.gens()
sage: s = s1**3*s2*s1; s
(2,3)
sage: sw = s.word_problem(S3.gens())
x2^-1*x1^-1*(x1^-1*x2^-1)^2*x2^-1*x1^-2*x2^-1*x1^-1
[['(1,2)', -1], ['(1,2,3,4)', -1], ['((1,2,3,4)', -1], ['(1,2)', -1], ['(1,2,3,4)', -2],
['(1,2)', -1], ['(1,2,3,4)', -1]]
sage: sw
('x2^-1*x1^-1*(x1^-1*x2^-1)^2*x2^-1*x1^-2*x2^-1*x1^-1',
'(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')
Here the output displayed in the second line (which is only printed and not returned as result of the function)
ignores the brackets (...)**2 (around the expression "x1^-1*x2^-1") returned by gap.
The function "gap_word_problem" deals with the same task, but returns the result in list form. Continuing with the
above example we get
sage: swg = gap_word_problem(s, S3.gens()); swg
[(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]
sage: check=S3.one()
sage: for i in range(len(swg)/2):
check = check * swg[2*i]**swg[2*i+1]
....:
sage: check == s
True
INPUT:
- "element": an element in a group to be represented in terms of a set of generators
- "genList": list of generators in the same group as element, such that element lies in the subgroup generated
by them
- "verbose": optional keyword to print time stamp debugging messages
This keyword uses the timeStampControl class. For more information on this type
print setupTimeStamp.__doc__
print timeStampControl.__doc__
print timeStampControl.print_timestamp.__doc__
print print_time_tb.__doc__
OUTPUT:
a word in the generators in "genList" representing "element" as a list of length 2*l if l is the length of the
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
in the word expression whereas the e_i are the corresponding exponents, that is
element = w_1**e_1 * w_2**e_2 * .... * w_l**e_
RAISE:
- TypeError: "generator genList[0] must have a parent" if the first element of genList has no attribute "parent"
- TypeError: "parent of generator genList[0] must be an instance of Group" if the first element of genList does
not belong to a group
EXAMPLE:
continuing the example above we look at the type returned
sage: type(sw)
<type 'tuple'>
sage: type(sw[1])
<type 'str'>
sage: type(sw[0])
<type 'str'>
sage: type(swg)
<type 'list'>
sage: type(swg[0])
<type 'sage.groups.perm_gps.permgroup_element.PermutationGroupElement'>
sage: type(swg[1])
<type 'sage.rings.integer.Integer'>
sage:
an example of matrix groups
sage: GL3_3=GL(3,3)
sage: g1, g2 = GL3_3.gens()
sage: g1, g2 = GL3_3.gens(); g1, g2
(
[2 0 0] [2 0 1]
[0 1 0] [2 0 0]
[0 0 1], [0 2 0]
)
sage: g = g1**2*g2*g1; g
[1 0 1]
[1 0 0]
[0 2 0]
sage: gwg = gap_word_problem(g, [g1,g2] ); gwg
[
[2 0 1] [2 0 0]
[2 0 0] [0 1 0]
[0 2 0], 1, [0 0 1], -1
]
sage:
sage: check=GL3_3.one()
sage: for i in range(len(gwg)/2):
check = check * gwg[2*i]**gwg[2*i+1]
....:
sage: check == g
True
an example of fintely preseted groups
sage: B3 = BraidGroup(3); B3
Braid group on 3 strands
sage: b1, b2 = B3.gens()
sage: b1, b2 = B3.gens(); b1, b2
(s0, s1)
sage:
sage:
sage: b = b1**2*b2*b1; b
s0^2*s1*s0
sage: bwg = gap_word_problem(b, [b1,b2] ); bwg
[s0, 1, s0, 1, s1, 1, s0, 1]
sage: check=B3.one()
sage: for i in range(len(bwg)/2):
check = check * bwg[2*i]**bwg[2*i+1]
....:
sage: check == b
True
AUTHOR
- Sebastian Oehms, Sept. 2016
"""
TimeStamp = setupTimeStamp( verbose = verbose )
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
if 'Tietze' in dir(element):
result = []
for i in element.Tietze():
if i > _sage_const_0 :
result.append( genList[i-_sage_const_1 ] )
result.append( _sage_const_1 )
elif i < _sage_const_0 :
result.append( genList[-i-_sage_const_1 ] )
result.append( -_sage_const_1 )
return result
n=len(genList)
cmd="Fg:=FreeGroup(%d);"%(n)
libgap.eval(cmd)
for i in range(n):
cmd="x%d := GeneratorsOfGroup(Fg)[%d];"%(i+_sage_const_1 ,i+_sage_const_1 )
libgap.eval(cmd)
if 'parent' not in dir( genList[_sage_const_0 ] ):
raise TypeError( "generator %s must have a parent"%(genList[_sage_const_0 ]) )
GroupFrom = genList[_sage_const_0 ].parent()
if isinstance( GroupFrom, sage.groups.old.Group ) == False and isinstance( GroupFrom, sage.groups.group.Group ) == False:
raise TypeError( "parent of generator %s must be an instance of Group"%(genList[_sage_const_0 ]) )
if 'gap' in dir(GroupFrom):
G = GroupFrom.gap()
else:
G = gap(GroupFrom)
if 'gap' in dir(GroupFrom(element)):
g = GroupFrom(element).gap()
else:
g = GroupFrom(element)
try:
genList_gap = [gen.gap() for gen in genList]
except:
genList_gap = [libgap(gen) for gen in genList]
H=G.Subgroup( genList_gap )
ans = H.EpimorphismFromFreeGroup().PreImagesRepresentative(g)
ans_repl = ans.UnderlyingElement()
num = ans_repl.NumberSyllables().sage()
result = []
exponent_syllable = libgap.eval('ExponentSyllable')
generator_syllable = libgap.eval('GeneratorSyllable')
for i in range(num):
exponent = exponent_syllable(ans_repl, i+_sage_const_1 ).sage()
generator = generator_syllable(ans_repl, i+_sage_const_1 ).sage() - _sage_const_1
result.append( genList[generator] )
result.append( exponent )
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
return result
def expand_map_from_generators( GroupFrom, GroupTo, GensFrom = None, GensTo = None, verbose = False):
"""
expand a map given on generators of GroupFrom into another GroupTo. If the optional keyword GensFrom and GensTo
are not set the generators of GroupFrom and GroupTo will be used instead
Note: it is not checked if this gives a well defined homomorphis. This must be known or checked separately
If you don't see this well formatted type
sage: print expand_map_from_generators.__doc__
This functin is based on the gap_word_problem function and therefor on the gap function "EpimorphismFromFreeGroup"
INPUT:
- "GroupFrom": the source group of the map to be generated
- "GroupTo": the target group of the map to be generated
- "GensFrom": (optional keyword, default = None takes GroupFrom.gens()) set of generators of GroupFrom which
should be mapped to the according elements (same order) of GensTo resp. GroupTo.gens()
- "GensTo": (optional keyword, default = None takes Groupo.gens()) set of generators of GroupTo which
should be the images of the according elements (same order) of GensFrom resp. GroupFrom.gens()
- "verbose": optional keyword to print time stamp debugging messages
This keyword uses the timeStampControl class. For more information on this type
print setupTimeStamp.__doc__
print timeStampControl.__doc__
print timeStampControl.print_timestamp.__doc__
print print_time_tb.__doc__
OUTPUT:
a function object of the following form:
INPUT:
- "Ele" an arbitrary element of GroupFrom
OUTPUT:
the corresponding element in GroupTo under the map defined
RAISE:
- TypeError: "GroupFrom must be an instance of Group"
- TypeError: "GroupTo must be an instance of Group"
- ValueError: "incompatible length of generator sets" if the list of generators of source and targed have different
length
EXAMPLE:
sage: S3=SymmetricGroup(4); S3
Symmetric group of order 4! as a permutation group
sage: s1, s2 = S3.gens()
sage: s = s1**3*s2*s1; s
(2,3)
sage:
sage: GU3 = GU(3,2); GU3
General Unitary Group of degree 3 over Finite Field in a of size 2^2 with respect to hermitian form
[0 0 1]
[0 1 0]
[1 0 0]
sage:
sage: S3toGU3 = expand_map_from_generators( S3, GU3); S3toGU3
<function Map at 0x9ac3e0d4>
sage: g = S3toGU3(s); g
[1 a a]
[a a 0]
[a 0 0]
note that S3toGU3 is not a group homomorphism
sage: g1 = S3toGU3(s1); g1
[a 0 0]
[0 1 0]
[0 0 a]
sage: g2 = S3toGU3(s2); g2
[ 0 0 1]
[ 0 1 1]
[ 1 1 a + 1]
sage: g_check = g1**3*g2*g1; g_check
[0 0 a]
[0 1 a]
[a 1 1]
sage: g == g_check
False
AUTHOR
- Sebastian Oehms, Sept. 2016
"""
TimeStamp = setupTimeStamp( verbose = verbose )
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
if isinstance( GroupFrom, sage.groups.old.Group ) == False and isinstance( GroupFrom, sage.groups.group.Group ) == False:
raise TypeError( "GroupFrom must be an instance of Group" )
if isinstance( GroupTo, sage.groups.old.Group ) == False and isinstance( GroupTo, sage.groups.group.Group ) == False:
raise TypeError( "GroupTo must be an instance of Group" )
if GensFrom != None:
Fgens = [GroupFrom(g) for g in GensFrom]
else:
Fgens = GroupFrom.gens()
if GensTo != None:
Tgens = [GroupTo(g) for g in GensTo]
else:
Tgens = GroupTo.gens()
if len(Fgens) !=len(Tgens):
raise ValueError( "incompatible length of generator sets" )
def Map( Ele ):
EleGens = gap_word_problem(Ele, Fgens)
anzLetter = len( EleGens )/_sage_const_2
ToEle = GroupTo.one()
for i in range(anzLetter):
for fGen in Fgens:
if EleGens[_sage_const_2 *i] == fGen:
tGen = Tgens[Fgens.index(fGen)]
ToEle = ToEle * tGen**(EleGens[_sage_const_2 *i+_sage_const_1 ])
return ToEle
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
return Map
def gap_hom( GroupFrom, GroupTo, GensFrom=None, GensTo=None, check = False, verbose = False ):
"""
This function creates a map from GroupFrom to GroupTo via the GAP-function 'GroupHomomorphismByImages' such that
generators GensFrom are mapped to GensTo. If the optional parameter GensFrom and GensTo are not set the generators
of GroupFrom and GroupTo will be used instead.
If GroupHomomorphismByImages fails on the task the function expand_map_from_generators is used for a second try
This function is based on GAP-function 'EpimorphismFromFreeGroup' (via gap_word_problem). For more information
on this type
sage: print expand_map_from_generators.__doc__
sage: print gap_word_problem.__doc__
Note: it is not checked if this gives a well defined homomorphism by default. To achieve this set the
keyword check = True
If you don't see this well formatted type
sage: print expand_map_from_generators.__doc__
INPUT:
- "GroupFrom": the source group of the map to be generated
- "GroupTo": the target group of the map to be generated
- "GensFrom": (optional keyword, default = None takes GroupFrom.gens()) set of generators of GroupFrom which
should be mapped to the according elements (same order) of GensTo resp. GroupTo.gens()
- "GensTo": (optional keyword, default = None takes Groupo.gens()) set of generators of GroupTo which
should be the images of the according elements (same order) of GensFrom resp. GroupFrom.gens()
- "check": optional boolean, default = False. If set to True the constructed map is tested to be a a well
defined group homomorphism. Depending wether the gap function "GroupHomomorphismByImages"
can be used the check is perfomed by gap. In the other case a NotImplemented Exception is raised.
- "verbose": optional keyword to print time stamp debugging messages
This keyword uses the timeStampControl class. For more information on this type
print setupTimeStamp.__doc__
print timeStampControl.__doc__
print timeStampControl.print_timestamp.__doc__
print print_time_tb.__doc__
OUTPUT:
an element of Hom( GroupFrom, GroupTo )
RAISE:
- TypeError: "GroupFrom must be an instance of Group"
- TypeError: "GroupTo must be an instance of Group"
- ValueError: "incompatible length of generator sets" if the list of generators of source and targed have different
length
- RuntimeError: "One does not map to one" if check = True, else a warning
- RuntimeError: "No map definition possible" the test that the contructed map works failed
- RuntimeError: "gap cannot compute image of ..." occurs when the constructed map is applied: calculation of
the image of a specific element failed
- NotImplementedError: "no check for expand_map_from_generators - try again with check = False" occurs if
check is set to True and gap function "GroupHomomorphismByImages" can not be applied
EXAMPLE:
sage: B3 = BraidGroup(3)
sage: S3=SymmetricGroup(3)
sage: Im=[S3((1,2)), S3((2,3))]; Im
[(1,2), (2,3)]
sage: b2s = gap_hom( B3, S3, GensTo=Im ); b2s
Generic morphism:
From: Braid group on 3 strands
To: Symmetric group of order 3! as a permutation group
sage: b1, b2 = B3.gens(); b1, b2
(s0, s1)
sage: b2s(b1*b2*b1)
(1,3)
sage: b2s(b2*b1*b2)
(1,3)
check if the map is indeed a homomorphism of groups
sage: b2s_check = gap_hom( B3, S3, GensTo=Im, check=True )
sage: b2s(b1) == b2s_check(b1)
True
sage: b2s(b2) == b2s_check(b2)
True
CAUTION: by default it is not checked if the map is well defined nor a homomorphism:
sage: b2s_wrong = gap_hom( B3, S3 ); b2s_wrong
Generic morphism:
From: Braid group on 3 strands
To: Symmetric group of order 3! as a permutation group
sage:
sage: b = b1*b2*b1
sage: bb = b2*b1*b2
sage: b == bb
True
sage: b2s_wrong(b) == b2s_wrong(bb)
False
You can check this as follows:
sage: b2s_wrong = gap_hom( B3, S3, check=True ); b2s_wrong
............
RuntimeError: No map definition possible
sage:
AUTHOR
- Sebastian Oehms, Sept. 2016
"""
TimeStamp = setupTimeStamp( verbose = verbose )
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
if isinstance( GroupFrom, sage.groups.old.Group ) == False and isinstance( GroupFrom, sage.groups.group.Group ) == False:
raise TypeError( "GroupFrom must be an instance of Group" )
if isinstance( GroupTo, sage.groups.old.Group ) == False and isinstance( GroupTo, sage.groups.group.Group ) == False:
raise TypeError( "GroupTo must be an instance of Group" )
try:
GroupFrom_gap = GroupFrom.gap()
except:
GroupFrom_gap = gap(GroupFrom)
TimeStamp.print_timestamp( Text = "gap(GroupFrom)", Level = TsLevel.Debug )
try:
GroupTo_gap = GroupTo.gap()
except:
GroupTo_gap = gap(GroupTo)
TimeStamp.print_timestamp( Text = "gap(GroupTo)", Level = TsLevel.Debug )
if GensFrom == None:
GensFrom_gap = GroupFrom_gap.GeneratorsOfGroup()
else:
try:
GensFrom_gap = [gen.gap() for gen in GensFrom]
except:
GensFrom_gap = [libgap(gen) for gen in GensFrom]
TimeStamp.print_timestamp( Text = "libgap(gen) GensFrom", Level = TsLevel.Debug )
if GensTo == None:
GensTo_gap = GroupTo_gap.GeneratorsOfGroup()
else:
try:
GensTo_gap = [gen.gap() for gen in GensTo]
except:
GensTo_gap = [libgap(gen) for gen in GensTo]
TimeStamp.print_timestamp( Text = "libgap(gen) GensTo", Level = TsLevel.Debug )
if len(GensFrom_gap) !=len(GensTo_gap):
raise ValueError( "incompatible length of generator sets" )
try:
if check == False:
gHom_gap = gap_result( GroupFrom_gap.GroupHomomorphismByImagesNC( GroupTo_gap, GensFrom_gap, GensTo_gap ) )
else:
gHom_gap = gap_result( GroupFrom_gap.GroupHomomorphismByImages( GroupTo_gap, GensFrom_gap, GensTo_gap ) )
if gHom_gap == None:
if check == False:
groupMap = expand_map_from_generators( GroupFrom, GroupTo, GensFrom, GensTo, verbose = verbose )
else:
raise NotImplementedError( "no check for expand_map_from_generators - try again with check = False" )
TimeStamp.print_timestamp( Text = "expand_map_from_generators pos1", Level = TsLevel.Debug )
else:
def groupMap( groupEle ):
return gap_group_map( groupEle, GroupTo, gHom_gap )
TimeStamp.print_timestamp( Text = "GroupHomomorphis", Level = TsLevel.Debug )
except:
if check == False:
groupMap = expand_map_from_generators( GroupFrom, GroupTo, GensFrom, GensTo, verbose = verbose )
else:
raise NotImplementedError( "no check for expand_map_from_generators - try again with check = False" )
TimeStamp.print_timestamp( Text = "expand_map_from_generators pos2", Level = TsLevel.Debug )
try:
One = groupMap( GroupFrom.one() )
TimeStamp.print_timestamp( Text = "checked if groupMap works", Level = TsLevel.Debug )
if One != GroupTo.one():
if check == True:
raise RuntimeError( "One does not map to one" )
else:
print "Warning: one does not map to one"
except:
raise RuntimeError( "No map definition possible" )
groupHom = register_hom( GroupFrom, GroupTo, groupMap, verbose = verbose )
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
return groupHom
def gap_as_permutation_group( Group, verbose = False ):
"""
This function is an extension of the Sage as_permutation_group-method of the classes
- sage.groups.matrix_gps/finitely_generated.FinitelyGeneratedMatrixGroup_gap
- sage.groups.finitely_presente.FinitelyPresentedGroup
using the GAP-function 'IsomorphismPermGroup'. It can be applied to other cases of groups.
Furthermore the isompophism map returned by gap is registered as a conversion map to and from the permutation group
defined (which is not the case for the above mentioned methods)
If you don't see this well formatted type
sage: print gap_as_permutation_group.__doc__
INPUT:
- "Group": the group for which an isomorphism to a permutation group should be found
- "verbose": optional keyword to print time stamp debugging messages
This keyword uses the timeStampControl class. For more information on this type
print setupTimeStamp.__doc__
print timeStampControl.__doc__
print timeStampControl.print_timestamp.__doc__
print print_time_tb.__doc__
OUTPUT:
- an isomporphic permutation group to Group together with the isomorphism registered as conversion maps
for Group and the returned permutation group
RAISE:
- TypeError: "Group must be an instance of Group"
- RuntimeError: "gap fails to compute permutation group!"
- NotImplementedError: "Group must be finite."
EXAMPLE:
sage: Sp4 = Sp(4,3); Sp4
Symplectic Group of degree 4 over Finite Field of size 3
sage: PSp4 = gap_as_permutation_group( Sp4 ); PSp4
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)
(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)
(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)
(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)
(15,23,36)(20,30,47)(24,37,55)(26,39,57)(31,48,64)(33,50,65)(73,77,79)(75,78,80)]
sage: s1, s2 = Sp4.gens(); s1, s2
(
[2 0 0 0] [1 0 1 0]
[0 1 0 0] [1 0 0 0]
[0 0 1 0] [0 1 0 1]
[0 0 0 2], [0 2 0 0]
)
sage: s = s1*s2**2; s
[2 2 2 2]
[1 0 1 0]
[1 2 0 0]
[1 0 0 0]
sage:
sage: sp2p = PSp4.convert_map_from( Sp4 )
sage: p2sp = Sp4.convert_map_from( PSp4 )
sage:
sage: p1 = sp2p( s1 ); p1
(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)
(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)
(74,78)(76,77)
sage: p2 = sp2p( s2 ); p2
(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)
(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)
(73,77,79)(75,78,80)
sage: p = sp2p( s ); p
(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)
(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)
(31,49,48,40,59)(33,52,67,66,39)
sage: s1 == p2sp( p1 )
True
sage: s2 == p2sp( p2 )
True
sage: s == p2sp( p)
True
sage:
AUTHOR
- Sebastian Oehms, Sept. 2016
"""
TimeStamp = setupTimeStamp( verbose = verbose )
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
if isinstance( Group, sage.groups.old.Group ) == False and isinstance( Group, sage.groups.group.Group ) == False:
raise TypeError( "Group must be an instance of Group" )
if not Group.is_finite():
raise NotImplementedError("Group must be finite.")
try:
Group_gap = Group.gap()
except:
Group_gap = gap(Group)
isoToPerm = gap_result( Group_gap.IsomorphismPermGroup() )
if isoToPerm == None:
raise RuntimeError("gap fails to compute permutation group!")
isoToPermInv = isoToPerm.InverseGeneralMapping()
permGens = isoToPerm.Image().GeneratorsOfGroup().sage()
PermGroup = PermutationGroup( permGens )
TimeStamp.print_timestamp( Text = "PermutationGroup defined", Level = TsLevel.Debug )
def groupIso( groupEle ):
return gap_group_map( groupEle, PermGroup, isoToPerm )
def groupIsoInv ( groupEle ):
return gap_group_map( groupEle, Group, isoToPermInv )
TimeStamp.print_timestamp( Text = "groupIso defined", Level = TsLevel.Debug )
register_hom( Group, PermGroup, groupIso, verbose = verbose )
register_hom( PermGroup, Group, groupIsoInv, verbose = verbose )
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
return PermGroup
def gap_centralizer( Group, Element, verbose = False ):
"""
This function returns the centralizer of an Element of the Group using the GAP-function
'Centralizer'. This extends the use of this GAP-function in sage to Groups which are not
permutation groups (note that the sage-method centralizer is defined for peremutation group, only)
If you don't see this well formatted type
sage: print gap_centralizer.__doc__
INPUT:
- "Group": the group in which the centralizer should be calculated
- "Element": element in Group which shoul commute with all elements of the centralizer
- "verbose": optional keyword to print time stamp debugging messages
This keyword uses the timeStampControl class. For more information on this type
print setupTimeStamp.__doc__
print timeStampControl.__doc__
print timeStampControl.print_timestamp.__doc__
print print_time_tb.__doc__
OUTPUT:
the maximal subgroup of "Group" whose elements commute with the given "Element" as sage subgroup of "Group"
EXAMPLES:
sage: Sp4 = Sp(4,3)
sage: s1, s2 = Sp4.gens(); s1, s2
(
[2 0 0 0] [1 0 1 0]
[0 1 0 0] [1 0 0 0]
[0 0 1 0] [0 1 0 1]
[0 0 0 2], [0 2 0 0]
)
sage: s = s1*s2**2; s
[2 2 2 2]
[1 0 1 0]
[1 2 0 0]
[1 0 0 0]
sage: CSp4s = gap_centralizer( Sp4, s ); CSp4s
Matrix group over Finite Field of size 3 with 2 generators (
[2 2 2 2] [2 0 0 0]
[1 0 1 0] [0 2 0 0]
[1 2 0 0] [0 0 2 0]
[1 0 0 0], [0 0 0 2]
)
sage: c1, c2 = CSp4s.gens()
sage: cs1=Sp4(c1); cs1
[2 2 2 2]
[1 0 1 0]
[1 2 0 0]
[1 0 0 0]
sage: cs2=Sp4(c2); cs2
[2 0 0 0]
[0 2 0 0]
[0 0 2 0]
[0 0 0 2]
sage: cs1*s == s * cs1
True
sage: cs2*s == s * cs2
True
sage:
AUTHOR
- Sebastian Oehms, Sept. 2016
"""
TimeStamp = setupTimeStamp( verbose = verbose )
TimeStamp.print_timestamp( Text = "Begin", Level = TsLevel.StackInfo )
try:
Group_gap = Group.gap()
except:
Group_gap = gap(Group)
try:
Element_gap = Element.gap()
except:
Element_gap = gap(Element)
TimeStamp.print_timestamp( Text = "Calling Gap", Level = TsLevel.Body )
centralizer_gap = Group_gap.Centralizer(Element_gap)
TimeStamp.print_timestamp( Text = "setting sage generator list", Level = TsLevel.Body )
GenList = [ Group(gen) for gen in centralizer_gap.GeneratorsOfGroup() ]
TimeStamp.print_timestamp( Text = "defining subgroup", Level = TsLevel.Body )
centralizer = Group.subgroup( GenList )
TimeStamp.print_timestamp( Text = "End", Level = TsLevel.StackInfo )
return centralizer
def gap_extend_workspace( new_size ):
"""
extends the minimum GAP workspace to the given value if possible:
If you don't see this well formatted type
sage: print gap_extend_workspace.__doc__
INPUT:
- "new_size" the new size in byte to which the gap workspace should be extended
RAISE:
TypeError: "new_size must be of type Integer!"
MESSAGES:
informational:
"Note: GAP workspace has been extended: %d -> %d"%(akt_memory_pool_size, new_memory_pool_size)
warning:
"Warning: cannont extend the GAP workspace more than half of swap and 4/5 of ram" if new_size is byond the limits
of hardware recources
EXAMPLES::
on an Acer AO Happy under LinuxMint 17.3 Mate with 2 GB RAM:
sage: oneHundertMB = 100*1024**2
sage: gap_extend_workspace( 8*oneHundertMB )
Note: GAP workspace has been extended: 262144000 -> 838860800
sage:
sage: gap_extend_workspace( 13*oneHundertMB )
Warning: cannont extend the GAP workspace more than half of swap and 4/5 of ram
Note: GAP workspace has been extended: 262144000 -> 1058121318
sage:
AUTHOR
- Sebastian Oehms, Sept. 2016
"""
if isinstance( new_size, Integer ) == False:
raise TypeError( "new_size must be of type Integer!" )
from sage.interfaces.gap import get_gap_memory_pool_size, set_gap_memory_pool_size
from sage.misc.memory_info import MemoryInfo
akt_memory_pool_size = get_gap_memory_pool_size()
new_memory_pool_size = int(new_size)
mem = MemoryInfo()
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 ):
print "Warning: cannont extend the GAP workspace more than half of swap and 4/5 of ram"
new_memory_pool_size = max(mem.available_swap() // _sage_const_2 , _sage_const_4 *mem.available_ram() // _sage_const_5 )
if new_memory_pool_size > akt_memory_pool_size:
gap_reset_workspace( max_workspace_size = new_memory_pool_size )
print "Note: GAP workspace has been extended: %d -> %d"%(akt_memory_pool_size, new_memory_pool_size)