Skip to content

Commit

Permalink
change fp_group_with_isomorphism, pc_group_with_isomorphism (#3563)
Browse files Browse the repository at this point in the history
- add optional boolean `on_gens` for `isomorphism(FPGroup, G)`
  (changes the internal structure of the `:isomorphisms` attribute)
- reverse the direction of the maps returned by `fp_group_with_isomorphism`
  and `pc_group_with_isomorphism`
- do not export `fp_group_with_isomorphism`, `pc_group_with_isomorphism`
- create a collector for a pc group in Oscar not in GAP
- fix code using sparse matrices
  (add a test for the case that did not work before)
  • Loading branch information
ThomasBreuer authored Apr 9, 2024
1 parent 1a1c795 commit b9a5045
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 83 deletions.
2 changes: 1 addition & 1 deletion docs/src/Groups/grouphom.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ isomorphism(G::GAPGroup, H::GAPGroup)
```

```@docs
isomorphism(::Type{T}, G::GAPGroup) where T <: Union{FPGroup, PcGroup, PermGroup}
isomorphism(::Type{T}, G::GAPGroup) where T <: Union{PcGroup, PermGroup}
isomorphism(::Type{FinGenAbGroup}, G::GAPGroup)
simplified_fp_group(G::FPGroup)
```
Expand Down
119 changes: 57 additions & 62 deletions experimental/GModule/Cohomology.jl
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Base.hash(a::MultGrpElem, u::UInt = UInt(1235)) = hash(a.data. u)
end

F::Group # G as an Fp-group (if set)
mF::GAPGroupHomomorphism # F -> G, maps F[i] to G[i]
mF::GAPGroupHomomorphism # G -> F, maps G[i] to F[i]

iac::Vector{Map} # the inverses of ac
end
Expand Down Expand Up @@ -150,14 +150,14 @@ Checks if the action maps satisfy the same relations
as the generators of `G`.
"""
function is_consistent(M::GModule)
G, mG = fp_group_with_isomorphism(M)
G, mG = fp_group_with_isomorphism(M) # mG: group(M) -> G
V = Module(M)
R = relators(G)
for r = R
w = word(r)
a = action(M, mG(w[1]< 0 ? inv(gen(G, -w[1])) : gen(G, w[1])))
a = action(M, preimage(mG, w[1]< 0 ? inv(gen(G, -w[1])) : gen(G, w[1])))
for i=2:length(w)
a = a* action(M, mG(w[i]< 0 ? inv(gen(G, -w[i])) : gen(G, w[i])))
a = a* action(M, preimage(mG, w[i]< 0 ? inv(gen(G, -w[i])) : gen(G, w[i])))
end
all(x->a(x) == x, gens(V)) || (@show r; return false)
end
Expand Down Expand Up @@ -186,7 +186,7 @@ function fp_group_with_isomorphism(C::GModule)
if !isdefined(C, :F)
if (!isa(group(C), FPGroup)) && is_trivial(group(C))
C.F = free_group(0)
C.mF = hom(C.F, group(C), gens(C.F), elem_type(group(C))[])
C.mF = hom(group(C), C.F, gens(group(C)), elem_type(C.F)[])
else
C.F, C.mF = fp_group_with_isomorphism(gens(group(C)))
end
Expand Down Expand Up @@ -215,7 +215,7 @@ function action(C::GModule, g, v::Array)
end

F, mF = fp_group_with_isomorphism(C)
for i = word(preimage(mF, g))
for i = word(mF(g))
if i > 0
v = map(ac[i], v)
else
Expand Down Expand Up @@ -261,7 +261,7 @@ function action(C::GModule, g)

F, mF = fp_group_with_isomorphism(C)
h = id_hom(C.M)
for i = word(preimage(mF, g))
for i = word(mF(g))
if i > 0
h = h*ac[i]
# v = map(ac[i], v)
Expand Down Expand Up @@ -297,7 +297,9 @@ function induce(C::GModule{<:Oscar.GAPGroup, FinGenAbGroup}, h::Map, D = nothing
iU = image(h)[1]

# ra = right_coset_action(G, image(h)[1]) # will not always match
# the transversal, so cannot use. There is a PR in Gap to return "both"
# the transversal, so cannot use.
# See https://github.com/gap-system/gap/issues/5337
# for a discussion whether to return both transversal and action on it.
g = right_transversal(G, iU)
S = symmetric_group(length(g))
ra = hom(G, S, [S([findfirst(x->x*inv(z*y) in iU, g) for z = g]) for y in gens(G)])
Expand Down Expand Up @@ -483,8 +485,8 @@ function Oscar.inflate(C::GModule, h)
return gmodule(G, [action(C, h(g)) for g = gens(G)])
end

export GModule, gmodule, word, fp_group_with_isomorphism, confluent_fp_group
export action, cohomology_group, extension, pc_group_with_isomorphism
export GModule, gmodule, word, confluent_fp_group
export action, cohomology_group, extension
export induce, is_consistent, istwo_cocycle, all_extensions
export split_extension, extension_with_abelian_kernel

Expand All @@ -502,16 +504,14 @@ Oscar.group(C::GModule) = C.G
###########################################################

"""
Compute an fp-presentation of the group generated by 'g'
and returns both the group and the map from the new group to the
parent of the generators.
Compute an fp-presentation of the common parent 'G' of 'g'
and return both the group and the map from 'G' to the new group.
"""
function fp_group_with_isomorphism(g::Vector{<:Oscar.GAPGroupElem})
G = parent(g[1])
@assert all(x->parent(x) == G, g)
X = GAPWrap.IsomorphismFpGroupByGenerators(G.X, GAPWrap.GeneratorsOfGroup(G.X))
F = FPGroup(GAPWrap.Range(X))
return F, GAPGroupHomomorphism(F, G, GAP.Globals.InverseGeneralMapping(X))
iso = isomorphism(FPGroup, G, on_gens=true)
return codomain(iso), iso
end

"""
Expand Down Expand Up @@ -647,8 +647,8 @@ function (C::CoChain{1})(g::Oscar.BasicGAPGroupElem)
G = parent(g)
@assert G == group(C.C)
@assert ngens(F) == ngens(G)
@assert all(i->mF(gen(F, i)) == gen(G, i), 1:ngens(G))
w = word(preimage(mF, g))
@assert all(i-> preimage(mF, gen(F, i)) == gen(G, i), 1:ngens(G))
w = word(mF(g))
t = zero(Module(C.C))
ac = action(C.C)
iac = inv_action(C.C)
Expand Down Expand Up @@ -804,6 +804,7 @@ function H_one_maps(C::GModule; task::Symbol = :maps)
F, mF = fp_group_with_isomorphism(C)
@assert ngens(F) == ngens(G)
@assert all(i->mF(gen(F, i)) == gen(G, i), 1:ngens(G))
@assert all(i->preimage(mF, gen(F, i)) == gen(G, i), 1:ngens(G))

R = relators(F)
# @assert G == F
Expand Down Expand Up @@ -866,7 +867,7 @@ function H_one(C::GModule)
return domain(z), z
end

g, gg, pro, inj, mF = H_one_maps(C, task = :all)
g, gg, pro, inj, _ = H_one_maps(C, task = :all)

K = kernel(gg)[1]
D = domain(gg)
Expand Down Expand Up @@ -1076,7 +1077,7 @@ function H_two(C::GModule; force_rws::Bool = false, redo::Bool = false, lazy::Bo
@vprint :GroupCohomology 1 "starting H^2 for group of size $(order(G)) and module with $(ngens(M)) gens\n"

id = hom(M, M, gens(M), check = false)
F, mF = fp_group_with_isomorphism(C) #mF: F -> G
F, _ = fp_group_with_isomorphism(C)

if !force_rws && (isa(G, PcGroup) || is_solvable(G))
@vprint :GroupCohomology 2 "using pc-presentation ...\n"
Expand Down Expand Up @@ -1736,10 +1737,11 @@ function cohomology_group(C::GModule, i::Int; Tate::Bool = false)
error("only H^0, H^1 and H^2 are supported")
end

# return an f.p. group `F` and an isomorphism `M -> F`
function fp_group_with_isomorphism(M::AbstractAlgebra.FPModule{<:FinFieldElem})
p, mp = pc_group_with_isomorphism(M, refine = false)
mf = isomorphism(FPGroup, p)
return codomain(mf), inv(mf)*mp
return codomain(mf), mf*mp
end

#########################################################
Expand Down Expand Up @@ -1809,6 +1811,7 @@ end
function Oscar.id_hom(A::AbstractAlgebra.FPModule)
return Generic.ModuleHomomorphism(A, A, identity_matrix(base_ring(A), ngens(A)))
end

###########################################################

#=
Expand All @@ -1819,7 +1822,8 @@ end
=#

"""
Compute an isomorphic pc-group (and the isomorphism). If `refine` is true,
Compute an isomorphic pc-group `G` (and the isomorphism from `M` to `G`).
If `refine` is true,
the pc-generators will all have prime relative order, thus the
group should be safe to use.
If `refine` is false, then the relative orders are just used from the hnf
Expand Down Expand Up @@ -1857,8 +1861,8 @@ function pc_group_with_isomorphism(M::FinGenAbGroup; refine::Bool = true)
for i=1:nrows(h)
for j=i+1:ncols(h)
if !iszero(h[i,j])
push!(r.rows[gp[i]], gp[j])
push!(r.values(gp[i], h[i,j]))
push!(r.rows[gp[i]].pos, gp[j])
push!(r.rows[gp[i]].values, h[i,j])
end
end
end
Expand All @@ -1874,21 +1878,16 @@ function pc_group_with_isomorphism(M::FinGenAbGroup; refine::Bool = true)
h = rels(M)
@assert !any(x->h[x,x] == 1, 1:ncols(h))

C = GAP.Globals.SingleCollector(G.X, GAP.Obj([h[i,i] for i=1:nrows(h)], recursive = true))
F = GAP.Globals.FamilyObj(GAP.Globals.Identity(G.X))

for i=1:ngens(M)-1
r = ZZRingElem[]
for j=i+1:ngens(M)
push!(r, j)
push!(r, -h[i, j])
GAP.Globals.SetConjugate(C, j, i, gen(G, j).X)
C = collector(nrows(h))
set_relative_orders!(C, [h[i,i] for i in 1:nrows(h)])
for i in 1:ngens(M)
r = Pair{Int, ZZRingElem}[]
for j in i+1:ngens(M)
push!(r, j => -h[i, j])
end
rr = GAP.Globals.ObjByExtRep(F, GAP.Obj(r, recursive = true))
GAP.Globals.SetPower(C, i, rr)
set_power!(C, i, r)
end

B = PcGroup(GAP.Globals.GroupByRws(C))
B = pc_group(C)
FB = GAP.Globals.FamilyObj(GAP.Globals.Identity(B.X))

Julia_to_gap = function(a::FinGenAbGroupElem)
Expand Down Expand Up @@ -1916,9 +1915,9 @@ function pc_group_with_isomorphism(M::FinGenAbGroup; refine::Bool = true)
@assert is_isomorphic(B, fp_group(M))

return B, MapFromFunc(
B, codomain(mM),
x->image(mM, gap_to_julia(x.X)),
y->PcGroupElem(B, Julia_to_gap(preimage(mM, y))))
codomain(mM), B,
y->PcGroupElem(B, Julia_to_gap(preimage(mM, y))),
x->image(mM, gap_to_julia(x.X)))
end

function (k::Nemo.fpField)(a::Vector)
Expand All @@ -1944,7 +1943,13 @@ function pc_group_with_isomorphism(M::AbstractAlgebra.FPModule{<:FinFieldElem};
GAP.Obj([p for i=1:ngens(G)], recursive = true))
F = GAP.Globals.FamilyObj(GAP.Globals.Identity(G.X))

# Note that we have specified all relative orders as `p`.
# Missing commutator and power relators are interpreted as trivial,
# thus `C` describes an elementary abelian group.
B = PcGroup(GAP.Globals.GroupByRws(C))
@assert is_abelian(B)
@assert order(B) == order(M)

FB = GAP.Globals.FamilyObj(GAP.Globals.Identity(B.X))

function Julia_to_gap(a::AbstractAlgebra.FPModuleElem{<:Union{fpFieldElem, FpFieldElem, FqFieldElem}})
Expand Down Expand Up @@ -1993,20 +1998,10 @@ function pc_group_with_isomorphism(M::AbstractAlgebra.FPModule{<:FinFieldElem};
return M(c)
end

for i=1:ngens(M)-1
r = ZZRingElem[]
for j=i+1:ngens(M)
GAP.Globals.SetConjugate(C, j, i, gen(G, j).X)
end
GAP.Globals.SetPower(C, i, GAP.Globals.Identity(F))
end
@assert is_abelian(B)
@assert order(B) == order(M)

return B, MapFromFunc(
B, M,
x->gap_to_julia(x.X),
y->PcGroupElem(B, Julia_to_gap(y)))
M, B,
y->PcGroupElem(B, Julia_to_gap(y)),
x->gap_to_julia(x.X))
end


Expand All @@ -2026,7 +2021,7 @@ If the gmodule is defined via a pc-group and the 1st argument is the
function extension(c::CoChain{2,<:Oscar.GAPGroupElem})
C = c.C
G = Group(C)
F, mF = fp_group_with_isomorphism(gens(G))
F, _ = fp_group_with_isomorphism(gens(G))
M = Module(C)
ac = action(C)
iac = inv_action(C)
Expand Down Expand Up @@ -2154,7 +2149,7 @@ function extension(::Type{PcGroup}, c::CoChain{2,<:Oscar.PcGroupElem})
end
end
return t
return fMtoN(preimage(mfM, t))
return fMtoN(mfM(t))
end

#to lift the pc-relations:
Expand All @@ -2172,16 +2167,16 @@ function extension(::Type{PcGroup}, c::CoChain{2,<:Oscar.PcGroupElem})
for i=1:ngens(G)
p = Gp[i]^Go[i]
pp = GAP.Globals.ObjByExtRep(FN, GAPWrap.ExtRepOfObj(p))
m = fMtoN(preimage(mfM, word_to_elem([i for k=1:Go[i]])-word_to_elem(word(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(preimage(mfM, word_to_elem([-i, j, i])-word_to_elem(word(p))))
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(preimage(mfM, action(C, gen(G, i), mfM(gen(fM, j)))))
m = fMtoN(mfM(action(C, gen(G, i), preimage(mfM, gen(fM, j)))))
GAP.Globals.SetConjugate(CN, j+ngens(G), i, m)
end
end
Expand All @@ -2200,24 +2195,24 @@ function extension(::Type{PcGroup}, c::CoChain{2,<:Oscar.PcGroupElem})
@assert ngens(Q) == ngens(N)
MtoQ = hom(fM, Q, gens(fM), gens(Q)[ngens(G)+1:end])
QtoG = hom(Q, G, gens(Q), vcat(gens(G), [one(G) for i=1:ngens(fM)]))
@assert domain(mfM) ==fM
@assert codomain(mfM) == M
@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(preimage(mffM, preimage(mfM, m)).X))
wm = GAP.gap_to_julia(GAPWrap.ExtRepOfObj(preimage(mffM, mfM(m)).X))
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, inv(mfM)*MtoQ, QtoG, GMtoQ
return Q, mfM*MtoQ, QtoG, GMtoQ
end

"""
Expand Down
8 changes: 8 additions & 0 deletions experimental/GModule/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
end


@testset "Experimental.gmodule: pc group of FinGenAbGroup" begin
M = abelian_group([2 6 9; 1 5 3; 1 1 0])
G1, _ = Oscar.GrpCoh.pc_group_with_isomorphism(M)
G2 = codomain(isomorphism(PcGroup, M))
@test describe(G1) == describe(G2)
end


@testset "Experimental.gmodule" begin

G = small_group(7*3, 1)
Expand Down
Loading

0 comments on commit b9a5045

Please sign in to comment.