# coercion into/from subgroup or Tietze of generator change

Hi there,

do you know of a function, which solves the Tietze for subgroups or converts elements from parentgroup to elements of subgroup and the other way round (if possible)? Neither of the commented codes work (but I hope it is clear what I want):

F.<a,b,c> = FreeGroup()
x=a*b/c

H=F.subgroup([a*b,b,b*c])
y=H.gens()*H.gens()

x in H
y in F
#F(y)
#F.coerce(y)
#H.coerce(x).Tietze()
#H(x)


I am using cocalc, if this is a version thing. I know something like that exists for quotient groups (s. http://doc.sagemath.org/html/en/refer... )

In my use-case I have a free group $F$ and an element $x \in F$ in it. Now I want for a given list of generators (e.g. in above [ ab, b, bc ]) the $x$ as a word of these generators, hence I would like to see $x$ as an element in $H$ and use x.Tietze().

Another solution to my problem would be to swap the generators, but I can't see a way to do that either?

edit retag close merge delete

Can we consider only the case when the subgroup $H$ is in fact the full free group $F$, and where the human hand can describe how to write the "gens" of the one group, as they are considered in sage, w.r.t. the "gens" of the other group (in bothe directions)?

Is it enough for the application to get the Tietze representation of a word in H, considered "as is" as a word in $F$ ?!

(I took a look into the code, the class of H is hard to understand and use, most of the time one gets more information from the gap-objects associated. But combining this information is hard.)

Yes, we can consider $H$ to be the full free group $F$.

Per se it is possible to write the generators as words of the other ones and vice versa (meaning if I would do it by hand I could do it). The problem here is, that I don't know beforehand which generators will be passed, so in practise we only know how to write the generators (and hence any element) of $H$ as word of the generators of $F$.

I need a word of $F$ to be looked at, as if it was in $H$ and the Tietze of it in $H$.

So far I managed the coercing by $y=H(x.gap())$. The problem here is, that as a subgroup $H$ lacks the Tietze function... Currently I tried to translate it completly to gap (via sage) and solve it there , but I can't find the proper ...(more)

Sort by » oldest newest most voted

It was quite some pain and looks pretty ugly, but this does the job, The interesting part is done in GAP but sadly most of the code is wasted for translation... Feel free to improve it (there is a lot to improve here)

#the variables we want to change (feel free to edit this block)
F.<a,b,c>= FreeGroup();
x=a*b/c;
gens=[a*b,b,b*c]

#make it compatible for translation into GAP
rank = len(gens)
xTietze= list(x.Tietze())
tgens=[list(word.Tietze()) for word in gens]
print 'x as Tietze: ', xTietze

#translate word and generators to GAP:
gap.eval('tWord := %s;; tgens:=%s;; rank:= %s;;'  %(xTietze, tgens, rank))
gap.eval('G := FreeGroup(rank);; Ggens:=GeneratorsOfGroup(G);;')
gap.eval('word:=One(G);; for i in tWord do nextLetter:=Ggens[AbsInt(i)]; if i>0 then word:=word*nextLetter; else word:=word/nextLetter; fi;  od;')
gap.eval('newGens:=[];; for tWord in tgens do newGen:=One(G);; for i in tWord do nextLetter:=Ggens[AbsInt(i)]; if i>0 then newGen:=newGen*nextLetter; else newGen:=newGen/nextLetter; fi;  od; Add(newGens, newGen); od;')
print 'conversion of new base in GAP: ', gap('newGens')
gap.eval('H:=Subgroup(G,newGens);;')
print 'x after conversion in GAP: ', gap('word')

#change the base in GAP
gap.eval('hom:=EpimorphismFromFreeGroup(H);;')
print 'written with new basis'
gap.eval('newWord := PreImagesRepresentative(hom,word);')

#and translate new Tietze-word back to sage
newTietze=gap('TietzeWordAbstractWord(newWord);').sage()
print 'back in sage as Tietze: ', newTietze

more

The type of solution i had in mind, while typing the comment, was of the following shape:

F.<a,b,c> = FreeGroup()
H.<s,t,u> = FreeGroup()

h2f_DIC = { 1: a*b ,    # s "is" a*b  ::  map s -> a*b
2: b   ,    # t "is" b    ::  map t -> b
3: b*c ,    # u "is" b*c  ::  map u -> b*c
}

f2h_DIC = { 1: s*t^(-1),
2: t       ,
3: t^(-1)*u, }

for dic in h2f_DIC, f2h_DIC:
for key, val in dic.items():
dic[-key] = val^(-1)

def h2f( d ):
"""d is an element of F.<a,b,c>, map it to H by using f2h_DIC
"""
return prod( [ f2h_DIC[j] for j in d.Tietze() ] )

def f2h( w ):
"""w is an element of H.<s,t,u>, map it to F by using h2f_DIC
"""
return prod( [ h2f_DIC[j] for j in w.Tietze() ] )

d = a * b * a * b^-1 * c * a^2 * c^3 * b * c^-3
print "d          = %s" % d
print "d.Tietze() = %s" % str( d.Tietze() )

w = h2f( d )
print "w          = %s" % w
print "w.Tietze() = %s" % str( w.Tietze() )

print "f2h( h2f( d ) ) == d is %s" % bool( f2h( h2f( d ) ) == d )


which delivers:

d          = a*b*a*b^-1*c*a^2*c^3*b*c^-3
d.Tietze() = (1, 2, 1, -2, 3, 1, 1, 3, 3, 3, 2, -3, -3, -3)
w          = s^2*t^-3*u*(s*t^-1)^2*(t^-1*u)^3*(t*u^-1)^3*t
w.Tietze() = (1, 1, -2, -2, -2, 3, 1, -2, 1, -2, -2, 3, -2, 3, -2, 3, 2, -3, 2, -3, 2, -3, 2)
f2h( h2f( d ) ) == d is True


However not in this ugly, unstructural way do define morphisms by hand, well, i hoped for us, that something like F.hom( ... ) would work. No chance... The above is the best i can deliver in time...

Anyway, the above is the best structural solution i could see, that works without too much pain in both directions, $F\to H$, and $H\to F$. The composition $F\to H\to F$ was tested above to be the identity, at least when applied on some random element $d$.

(We really need the usual structural morphisms. As seen above, there should be not so complicated to implement them somehow, even also not optimal for a first approach...)

more