Skip to content

Commit

Permalink
Merge pull request #964 from oscar-system/Reps
Browse files Browse the repository at this point in the history
add stuff to compute representations for PcGroups
  • Loading branch information
fieker authored Jan 12, 2022
2 parents b157668 + 6bb57f6 commit af90aae
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 18 deletions.
61 changes: 50 additions & 11 deletions experimental/GModule/Cohomology.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@ import Oscar:action
import AbstractAlgebra: Group, Module
import Base: parent

#TODO: rename into GModule
@attributes mutable struct GModule{gT,mT}
G::gT
M::mT
ac::Vector{Map} # automorphisms of M, one for each generator of G

function GModule(G::T, ac::Vector{<:Map}) where {T <: Oscar.GAPGroup}
r = new{T,typeof(domain(ac[1]))}()
function GModule(M, G::T, ac::Vector{<:Map}) where {T <: Oscar.GAPGroup}
r = new{T,typeof(M)}()
r.G = G
r.ac = ac
r.M = domain(ac[1])
r.M = M
@assert all(x -> domain(x) == codomain(x) == r.M, ac)
return r
end


function GModule(G::T, ac::Vector{<:Map}) where {T <: Oscar.GAPGroup}
return GModule(domain(ac[1]), G, ac)
end

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

Expand Down Expand Up @@ -62,6 +66,21 @@ function Oscar.relations(F::FPGroup)
return [(x, z) for x = R]
end

function Oscar.relations(G::Oscar.GAPGroup)
f = GAP.Globals.IsomorphismFpGroupByGenerators(G.X, GAP.Globals.GeneratorsOfGroup(G.X))
f !=GAP.Globals.fail || throw(ArgumentError("Could not convert group into a group of type FPGroup"))
H = FPGroup(GAP.Globals.Image(f))
return relations(H)
end

function Oscar.relations(G::PcGroup)
f = GAP.Globals.IsomorphismFpGroupByPcgs(GAP.Globals.FamilyPcgs(G.X), GAP.julia_to_gap("g"))
f !=GAP.Globals.fail || throw(ArgumentError("Could not convert group into a group of type FPGroup"))
H = FPGroup(GAP.Globals.Image(f))
return relations(H)
end


AbstractAlgebra.Group(C::GModule) = C.G
AbstractAlgebra.Module(C::GModule) = C.M
action(C::GModule) = C.ac
Expand Down Expand Up @@ -183,6 +202,22 @@ function H_zero(C::GModule)
return k, z
end

#= TODO
- break out coboundaries and cochains
- depending on the module type:
- intersect yields an embedding (Z-module) or not GrpAb
- make sure that image/ kernel are consisten
- preimage
- issubset yields (for GrpAb) only true/ false, not the map
- issubgroup has the "wrong" order of arguments (and cannot apply
to modules)
- quo does ONLY work if B is a direct submodule of A (Z-modules)
- mat or matrix is used to get "the matrix" from a hom
- zero_hom/ zero_obj/ identity_hom is missing
- Janko-Module-Homs have different types, they probably need to
come under a common abstract type or be more selective
=#

function H_one(C::GModule)
z = get_attribute(C, :H_one)
if z !== nothing
Expand All @@ -197,8 +232,8 @@ function H_one(C::GModule)
X(r_i) corresponds to some map phi_i : M^r -> M
phi_i = oplus h_j M for some homs h_j coming from the word in r
so, a kernel computation again
=#

G = Group(C)
n = ngens(G)
M = Module(C)
Expand Down Expand Up @@ -407,6 +442,11 @@ function Oscar.mat(M::FreeModuleHom{FreeMod{QabElem}, FreeMod{QabElem}})
return M.matrix
end

#= Hulpke-Dietrich:
UNIVERSAL COVERS OF FINITE GROUPS
https://arxiv.org/pdf/1910.11453.pdf
almost the same as Holt
=#
function H_two(C::GModule)
z = get_attribute(C, :H_two)
if z !== nothing
Expand Down Expand Up @@ -693,7 +733,7 @@ function H_two(C::GModule)
end

"""
For a cohomology module `C` compute the `i`-th cohomology group
For a gmodule `C` compute the `i`-th cohomology group
where `i` can be `0`, `1` or `2`.
Together with the abstract module, a map is provided that will
produce explicit cochains.
Expand Down Expand Up @@ -817,6 +857,9 @@ Note: we do not check that this defined indeed a `ZZ[H]` module.
function gmodule(H::Oscar.GAPGroup, ac::Vector{<:Map})
return GModule(H, ac)
end
function gmodule(M, H::Oscar.GAPGroup, ac::Vector{<:Map})
return GModule(M, H, ac)
end

function _gmodule(k::AnticNumberField, H::PermGroup, mu::Map{GrpAbFinGen, FacElemMon{AnticNumberField}})
u = domain(mu)
Expand Down Expand Up @@ -927,7 +970,7 @@ Oscar.group(C::GModule) = C.G

#= TODO
for Z, Z/nZ, F_p and F_q moduln -> find Fp-presentation
#done: for GrpAbFinGen -> find Fp-presentation
#done: for GrpAbFinGen -> find Fp-presentation
#done: for a in H^2 find Fp-presentation
for a in H^2 find (low degree) perm group using the perm group we have?
Magma's DistinctExtensions
Expand All @@ -938,9 +981,6 @@ Sort:
- move (and fix) the ModuleHom stuff
- add proper quo for Modules
group better: the GModule should
- cache the H^i's that are computed
features
- inflation, restriction, long exact sequence
Expand All @@ -954,7 +994,6 @@ Sort:
- understand Derek Holt and use BSGS for large perm groups
rather than the RWS (or use BSGS to get an RWS?)
GModule for
- local field (add (trivial) and mult)
- (S-)units
Expand Down
151 changes: 145 additions & 6 deletions experimental/GModule/GModule.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,14 @@ function irreducible_modules(G::Oscar.GAPGroup)
K = abelian_closure(QQ)[1]
for m in im
z = map(x->matrix(map(y->map(K, y), m(x.X))), gens(G))
F = free_module(K, nrows(z[1]))
push!(IM, gmodule(G, map(x->hom(F, F, x), z)))
if ngens(G) == 0
F = free_module(K, 0)
zz = typeof(hom(F, F, elem_type(F)[]))[]
else
F = free_module(K, nrows(z[1]))
zz = map(x->hom(F, F, x), z)
end
push!(IM, gmodule(F, G, zz))
end
return IM
end
Expand Down Expand Up @@ -116,9 +122,13 @@ function gmodule(::typeof(CyclotomicField), C::GModule)
for g = C.ac
l = lcm(l, lcm(collect(map_entries(x->Hecke.iscyclotomic_type(parent(x.data))[2], mat(g)))))
end
K = cyclotomic_field(l, cached = false)[1]
K = cyclotomic_field(base_ring(C), l)[1]
F = free_module(K, dim(C))
return gmodule(group(C), [hom(F, F, map_entries(x->K(x.data), mat(x))) for x = C.ac])
if d == 0
h = hom(F, F, elem_type(F)[])
return gmodule(F, group(C), typeof(h)[hom(F, F, map_entries(x->K(x.data), mat(x))) for x = C.ac])
end
return gmodule(F, group(C), [hom(F, F, map_entries(x->K(x.data), mat(x))) for x = C.ac])
end

import Base: ^
Expand All @@ -133,12 +143,12 @@ end

function ^(C::GModule{<:Any, Generic.FreeModule{QabElem}}, phi::Map{QabField, QabField})
F = free_module(codomain(phi), dim(C))
return GModule(group(C), [hom(F, F, map_entries(phi, mat(x))) for x = C.ac])
return GModule(F, group(C), [hom(F, F, map_entries(phi, mat(x))) for x = C.ac])
end

function gmodule(::FlintRationalField, C::GModule{<:Any, Generic.FreeModule{nf_elem}})
F = free_module(QQ, dim(C)*degree(base_ring(C)))
return GModule(group(C), [hom(F, F, hvcat(dim(C), [representation_matrix(x) for x = transpose(mat(y))]...)) for y = C.ac])
return GModule(F, group(C), [hom(F, F, hvcat(dim(C), [representation_matrix(x) for x = transpose(mat(y))]...)) for y = C.ac])
end

function gmodule(k::Nemo.GaloisField, C::GModule{<:Any, Generic.FreeModule{fmpq}})
Expand Down Expand Up @@ -245,6 +255,9 @@ function hom_base(C::_T, D::_T) where _T <: GModule{<:Any, <:Generic.FreeModule{
push!(t, hom_base(z1[i], z2[i]))
end
tt = [Hecke.modular_lift([t[i][j] for i=1:length(z1)], me) for j=1:length(t[1])]
if length(tt) == 0
return []
end
@assert base_ring(tt[1]) == k
if isone(pp)
pp = fmpz(p)
Expand Down Expand Up @@ -321,6 +334,39 @@ function hom_base(C::_T, D::_T) where _T <: GModule{<:Any, <:Generic.FreeModule{
end
end

function gmodule(K::AnticNumberField, M::GModule{<:Any, <:Generic.FreeModule{nf_elem}})
F = free_module(K, dim(M))
return gmodule(F, group(M), [hom(F, F, map_entries(K, mat(x))) for x = M.ac])
end

function (K::QabField)(a::nf_elem)
fl, f = Hecke.iscyclotomic_type(parent(a))
@assert fl
return QabElem(a, f)
end

function hom_base(C::_T, D::_T) where _T <: GModule{<:Any, <:Generic.FreeModule{QabElem}}
C1 = gmodule(CyclotomicField, C)
D1 = gmodule(CyclotomicField, D)
fl, Cf = Hecke.iscyclotomic_type(base_ring(C1))
@assert fl
fl, Df = Hecke.iscyclotomic_type(base_ring(D1))
@assert fl
l = lcm(Cf, Df)
K, _ = cyclotomic_field(base_ring(C), l)
if l != Cf
C1 = gmodule(K, C1)
end
if l != Df
D1 = gmodule(K, D1)
end
h = hom_base(C1, D1)
if length(h) == 0
return h
end
return map(x->map_entries(base_ring(C), x), h)
end

function gmodule(::FlintRationalField, C::GModule{<:Any, <:Generic.FreeModule{fmpz}})
F = free_module(QQ, dim(C))
return GModule(group(C), [hom(F, F, map_entries(QQ, mat(x))) for x = C.ac])
Expand Down Expand Up @@ -518,3 +564,96 @@ end #module GModuleFromGap
using .GModuleFromGap

export irreducible_modules, isabsolutely_irreducible, isdecomposable

module RepPc
using Oscar

Base.pairs(M::MatElem) = Base.pairs(IndexCartesian(), M)
Base.pairs(::IndexCartesian, M::MatElem) = Base.Pairs(M, CartesianIndices(axes(M)))

function Hecke.roots(a::fq_nmod, i::Int)
kx, x = PolynomialRing(parent(a), cached = false)
return roots(x^i-a)
end

#=TODO
- construct characters along the way as well?
- compare characters rather than the hom_base
- maybe reason from theory what reps are going to be new?
- conjugate to smallest field?
- allow trivial stuff
=#

function reps(K, G::PcGroup)
s, ms = sub(G, [gens(G)[end]])
o = Int(order(s))
@assert isprime(o)
z = roots(K(1), o)
F = free_module(K, 1)
R = [gmodule(F, s, [hom(F, F, [r*F[1]])]) for r = z]

for i=ngens(G)-1:-1:1
h = G[i]
ns, mns = sub(G, gens(G)[i:end])
p = Int(divexact(order(ns), order(s)))
@assert isprime(p)
new_R = []
for r = R
F = r.M
rh = gmodule(group(r), [action(r, preimage(ms, x^h)) for x = gens(s)])
l = Oscar.GModuleFromGap.hom_base(r, rh)
@assert length(l) <= 1
nr = []
Y = mat(action(r, preimage(ms, h^p)))
if length(l) == 1
X = l[1]
Xp = X^p
#Brueckner: C*Xp == Y for some scalar C
i = findfirst(x->!iszero(x), Xp)
@assert !iszero(Y[i])
C = divexact(Y[i], Xp[i])
@assert C*Xp == Y
# I think they should always be roots of one here.
rt = roots(C, p)
Y = r.ac
for x = rt
nw = gmodule(F, ns, vcat([hom(F, F, x*X)], Y))
push!(nr, nw)
end
else #need to extend dim
n = dim(r)
F = free_module(K, dim(r)*p)
z = zero_matrix(K, dim(F), dim(F))
z[(p-1)*n+1:end, 1:n] = Y
for i=1:p-1
z[(i-1)*n+1:i*n, i*n+1:(i+1)*n] = identity_matrix(K, n)
end
md = [hom(F, F, z)]
for g = gens(s)
z = zero_matrix(K, dim(F), dim(F))
for j=1:p
Y = action(r, g)
z[(j-1)*n+1:j*n, (j-1)*n+1:j*n] = mat(Y)
g = preimage(ms, g^h)
end
push!(md, hom(F, F, z))
end
push!(nr, gmodule(F, ns, md))
end
for nw = nr
if any(x->length(Oscar.GModuleFromGap.hom_base(x, nw))>0, new_R)
continue
else
push!(new_R, nw)
end
end
end
s, ms = ns, mns
R = new_R
end
return R
end

end #module RepPc

using .RepPc
2 changes: 1 addition & 1 deletion src/Rings/AbelianClosure.jl
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ _variable(K::QabField) = K.s

_variable(b::QabElem) = Expr(:call, Symbol(_variable(_Qab)), b.c)

function cyclotomic_field(K::QabField, c::Int)
function Hecke.cyclotomic_field(K::QabField, c::Int)
if haskey(K.fields, c)
k = K.fields[c]
return k, gen(k)
Expand Down

0 comments on commit af90aae

Please sign in to comment.