Skip to content

Commit

Permalink
make extensino return an extension and add iso(FP...)
Browse files Browse the repository at this point in the history
the "same" should work for Pc - but we don't have the interface to
sanely query the pc-relations (yet)
  • Loading branch information
fieker committed Sep 26, 2024
1 parent 75fce4b commit 6d4c896
Show file tree
Hide file tree
Showing 2 changed files with 234 additions and 1 deletion.
2 changes: 1 addition & 1 deletion experimental/GModule/src/Cohomology.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1944,7 +1944,7 @@ the corresponding elt in the extension.
If the gmodule is defined via a pc-group and the 1st argument is the
`Type{PcGroup}`, the resulting group is also pc.
"""
function extension(c::CoChain{2,<:Oscar.GAPGroupElem})
function extension(::Type{FPGroup}, c::CoChain{2,<:Oscar.GAPGroupElem})
C = c.C
G = Group(C)
F = codomain(isomorphism(FPGroup, G, on_gens=true))
Expand Down
233 changes: 233 additions & 0 deletions experimental/GModule/src/GrpExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ using Oscar
import Base: *, ==, one, rand, show, iterate
export GrpExt, GrpExtElem
export commutator_decomposition_map
import Oscar.GAPWrap

"""
A type representing the group extension by a 2-co-cycle.
Expand All @@ -26,6 +27,222 @@ function show(io::IO, G::GrpExt)
print(io, "Extension via $(gmodule(G))")
end

function Oscar.extension(c::Oscar.GrpCoh.CoChain{2,<:Oscar.GAPGroupElem})
return GrpExt(c)
end

#g in H
# -> g in G where the gens to be used in G are different
function shiftgens(g::FPGroupElem, G, offset)
w = GapObj(g)
famG = GAPWrap.ElementsFamily(GAPWrap.FamilyObj(GapObj(G)))
if GAP.Globals.IsLetterAssocWordRep(w)
l = copy(GAP.Globals.LetterRepAssocWord(w))
for i in 1:length(l)
if l[i] > 0
l[i] = l[i] + offset
else
l[i] = l[i] - offset
end
end
ll = GAP.Globals.AssocWordByLetterRep(famG, l)
else
l = copy(GAPWrap.ExtRepOfObj(w))
for i in 1:2:length(l)
l[i] = l[i] + offset
end
ll = GAPWrap.ObjByExtRep(famG, l)
end
return FPGroupElem(G, ll)
end

function Oscar.isomorphism(::Type{FPGroup}, E::GrpExt)
c = E.c
C = c.C
G = C.G
mGF = Oscar.isomorphism(FPGroup, G, on_gens=true)
F = codomain(mGF)
M = C.M
ac = action(C)
mfM = inv(Oscar.isomorphism(FPGroup, M))
fM = domain(mfM)

N = free_group(ngens(G) + ngens(fM))

s = map(x->shiftgens(x, N, ngens(G)), relators(fM))
for R = relators(F)
t = map_word(R, gens(E)[1:ngens(G)])
push!(s, shiftgens(R, N, 0)*(shiftgens(preimage(mfM, t.m), N, ngens(fM))))
end
for i=1:ngens(G)
for j=1:ngens(fM)
#g[i]*t = m[j]*g[i] = g[i] m[j]^g[i] = m[j] g[i] (cancellation in conj)
t = preimage(mfM, ac[i](gen(M, j)))
push!(s, gen(N, ngens(G)+j)*gen(N, i)*inv(shiftgens(t, N, ngens(fM))) * inv(gen(N, i)))
end
end
Q, mQ = quo(N, s)
@assert ngens(Q) == ngens(N)
function EtoQ(x::GrpExtElem)
w = mGF(x.g)
ww = map_word(w, gens(E)[1:ngens(G)]) #this performs a collection
#and will transform x.g into
#canonical form
return mQ(shiftgens(w, N, 0)*shiftgens(preimage(mfM, x.m-ww.m), N, ngens(fM)))

end
return MapFromFunc(E, Q, EtoQ, y->map_word(y, gens(E)))
#the projection will be hom(Q, G, vcat(gens(G), ones(G, ???)
#the injection should be hom(M, Q, gens(Q)[ngens(G)+1:end])
#both can/ should be handled by shiftgens (or sylable/ create)
end

#=
function isomorphism(::Type{PcGroup}, E::GrpExt)
c = E.c
C = c.C
G = Group(C)
@assert isa(G, PcGroup)
M = Module(C)
ac = action(C)
iac = inv_action(C)
fM, mfM = pc_group_with_isomorphism(M)
N = free_group(ngens(G) + ngens(fM))
Gp = GAP.Globals.Pcgs(GapObj(G))
@assert length(Gp) == ngens(G)
# @assert all(x->Gp[x] == GapObj(gen(G, x)), 1:ngens(G))
Go = GAP.Globals.RelativeOrders(Gp)
Mp = GAP.Globals.Pcgs(GapObj(fM))
@assert length(Mp) == ngens(fM) == ngens(M)
# @assert all(x->Mp[x] == GapObj(gen(fM, x)), 1:ngens(M))
#problem/ TODO: Z/100Z has a useful GAP-pc-group has 4 gens (of
#order 2, 2, 5, 5
#so need to switch GAP to the other Pc-Groups and/or drop this
#assert
Mo = GAP.Globals.RelativeOrders(Mp)
CN = GAP.Globals.SingleCollector(GapObj(N), GAP.Globals.Concatenation(Go, Mo))
FN = GAP.Globals.FamilyObj(GapObj(N[1]))
for i=1:ngens(fM)
lp = deepcopy(GAPWrap.ExtRepOfObj(Mp[i]^Mo[i]))
for k=1:2:length(lp)
lp[k] += ngens(G)
end
m = GAP.Globals.ObjByExtRep(FN, lp)
GAP.Globals.SetPower(CN, i+ngens(G), m)
for j=i+1:ngens(fM)
p = Mp[j]^Mp[i]
@assert p == Mp[j]
lp = deepcopy(GAPWrap.ExtRepOfObj(p))
for k=1:2:length(lp)
lp[k] += ngens(G)
end
GAP.Globals.SetConjugate(CN, j+ngens(G), i+ngens(G), GAP.Globals.ObjByExtRep(FN, lp))
end
end
fMtoN = function(x)
lp = deepcopy(GAPWrap.ExtRepOfObj(GapObj(x)))
for k=1:2:length(lp)
@assert lp[k] > 0
lp[k] += ngens(G)
end
return GAP.Globals.ObjByExtRep(FN, lp)
end
word = function(y)
z = GAPWrap.UnderlyingElement(y)
return map(Int, GAP.Globals.LetterRepAssocWord(z))
end
#for W = (w1, ... w_n) compute ((w1, 0), ..., (wn, 0))
#and return the tail only.
word_to_elem = function(W)
t = zero(M)
g = one(G)
r = one(N)
for w = W
if w > 0
t = ac[w](t) + c(g, gen(G, w))
g = g*gen(G, w)
r = r*gen(N, w)
else
t = iac[-w](t) + c(g, inv(gen(G, -w))) - c(gen(G, -w), inv(gen(G, -w)))
g = g*inv(gen(G, -w))
r = r*inv(gen(N, -w))
end
end
return t
return fMtoN(mfM(t))
end
#to lift the pc-relations:
# F^p = w (order relation)
# compute (F, 0)^p = (?, t) = (?, 0)(1, t)
# compute (w, 0) = (?, s) = (?, 0)(1, s)
# so (?, 0) = (w, 0)(1,s)^-1= (w, 0)(1,-s) if chain is normalized
# thus (F, 0)^p = (?, 0)(1, t) = (w, 0)(1,-s)(1, t)
# the ? should be identical, namely the collected version of w
# then (F, 0)^p = (w, t-s) might be the answer
# F^G = w (conjugate relation): same
# (F, 0)^(G, 0) = (?, t) = (?, 0)(1, t)
# (w, 0) = (?, s) = (?, 0)(1, s)
# thus (F, 0)^(G, 0) = (w, t-s)
for i=1:ngens(G)
p = Gp[i]^Go[i]
pp = GAP.Globals.ObjByExtRep(FN, GAPWrap.ExtRepOfObj(p))
m = fMtoN(mfM(word_to_elem([i for k=1:Go[i]])-word_to_elem(word(p))))
GAP.Globals.SetPower(CN, i, pp*m)
for j=i+1:ngens(G)
p = Gp[j]^Gp[i]
m = fMtoN(mfM(word_to_elem([-i, j, i])-word_to_elem(word(p))))
pp = GAP.Globals.ObjByExtRep(FN, GAPWrap.ExtRepOfObj(p))
GAP.Globals.SetConjugate(CN, j, i, pp*m)
end
for j=1:ngens(fM)
m = fMtoN(mfM(action(C, gen(G, i), preimage(mfM, gen(fM, j)))))
GAP.Globals.SetConjugate(CN, j+ngens(G), i, m)
end
end
# l = GAP.Obj([])
# GAP.Globals.FinitePolycyclicCollector_IsConfluent(CN, l)
# @show l
# z = GAP.Globals.GroupByRwsNC(CN)
# s = GAP.Globals.GapInputPcGroup(z, GAP.Obj("Z"))
# @show GAP.gap_to_julia(s)
Q = PcGroup(GAP.Globals.GroupByRws(CN))
fQ = GAP.Globals.FamilyObj(GapObj(one(Q)))
mQ = hom(N, Q, gens(N), gens(Q); check = false)
@assert ngens(Q) == ngens(N)
MtoQ = hom(fM, Q, gens(fM), gens(Q)[ngens(G)+1:end]; check = false)
QtoG = hom(Q, G, gens(Q), vcat(gens(G), [one(G) for i=1:ngens(fM)]); check = false)
@assert domain(mfM) == M
@assert codomain(mfM) == fM
# @assert is_surjective(QtoG)
# @assert is_injective(MtoQ)
mfG = epimorphism_from_free_group(G)
mffM = epimorphism_from_free_group(fM)
function GMtoQ(wg, m)
wm = GAP.gap_to_julia(GAPWrap.ExtRepOfObj(GapObj(preimage(mffM, mfM(m)))))
for i=1:2:length(wm)
push!(wg, wm[i]+ngens(G))
push!(wg, wm[i+1])
end
return mQ(FPGroupElem(N, GAP.Globals.ObjByExtRep(FN, GAP.Obj(wg))))
end
return Q, mfM*MtoQ, QtoG, GMtoQ
end
=#

"""
The elements of the extension, given via a 2-co-chain.
"""
Expand All @@ -48,11 +265,27 @@ _module(P::GrpExt) = gmodule(P).M
_group(P::GrpExt) = gmodule(P).G

Oscar.parent(g::GrpExtElem) = g.P
Oscar.elem_type(::Type{GrpExt{S, T}}) where {S, T} = GrpExtElem{S, T}

function one(G::GrpExt)
return GrpExtElem(G, one(_group(G)), zero(_module(G)))
end

function Oscar.gen(G::GrpExt, i::Int)
i == 0 && return one(G)
i < 0 && return inv(gen(G, -i))
i > ngens(G) && error("index out of range")
gr = _group(G)
mo = _module(G)
if i <= ngens(gr)
return GrpExtElem(G, gen(gr, i), zero(mo))
end
return GrpExtElem(G, one(gr), gen(mo, i-ngens(gr)))
end

function Oscar.ngens(G::GrpExt)
return ngens(_group(G)) + ngens(_module(G))
end
function Oscar.gens(G::GrpExt)
gr = _group(G)
mo = _module(G)
Expand Down

0 comments on commit 6d4c896

Please sign in to comment.