Skip to content

Commit

Permalink
add stuff to compute representations for PcGroups
Browse files Browse the repository at this point in the history
(any characteristic)
This should work (possibly after the UngradeModule fix)
```@julia
  G = small_group(24, 12)
  z = Oscar.RepPc.reps(abelian_closure(QQ)[1], G)
  z = Oscar.RepPc.reps(cyclotomic_field(24)[1], G)
  z = Oscar.RepPc.reps(cyclotomic_field(4)[1], G)
  z = Oscar.RepPc.reps(FiniteField(3, 10)[1], G)
```
  • Loading branch information
fieker committed Jan 11, 2022
1 parent 46ab5e6 commit 6bb57f6
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 6bb57f6

Please sign in to comment.