diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index cb2ef40cd73a..7e82e0d702b0 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -1,13 +1,13 @@ isdefined(Oscar, :word) || function word end include("Cohomology.jl") +include("Types.jl") include("GaloisCohomology.jl") include("GrpExt.jl") include("Misc.jl") module GModuleFromGap using Oscar -using Hecke import Hecke: data #XXX: clash of names! @@ -43,7 +43,7 @@ julia> C = gmodule(CyclotomicField, C); julia> h = subfields(base_ring(C), degree = 2)[1][2]; julia> restriction_of_scalars(C, h) -G-module for G acting on vector space of dimension 4 over number field +(G-module for G acting on vector space of dimension 4 over number field, Map: C -> g-module for G acting on vector space of dimension 4 over number field) julia> restriction_of_scalars(C, QQ) G-module for G acting on vector space of dimension 8 over QQ @@ -56,9 +56,15 @@ function restriction_of_scalars(M::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.F @assert codomain(phi) == base_ring(M) d = divexact(degree(codomain(phi)), degree(domain(phi))) F = free_module(domain(phi), dim(M)*d) - _, _, rep = relative_field(phi) + _, coord, rep = relative_field(phi) - return GModule(F, group(M), [hom(F, F, hvcat(dim(M), [rep(x) for x in transpose(matrix(y))]...)) for y in M.ac]) + D = GModule(F, group(M), [hom(F, F, hvcat(dim(M), [rep(x) for x in transpose(matrix(y))]...)) for y in M.ac]) + #the blow-up function is not a "nice" module hom as tis is used + #to make from a K-Module to e.g. a QQ-module, so the map + #will be QQ-linear and we'd need to get QQ-gens from a K-module + #also: pre-image is not working (not implemented) (needs more info from + #relative_field) + return D, hom(M, D, MapFromFunc(M.M, D.M, x->D.M(vcat([coord(t) for t = x.v[1,:]]...))); check = false) end function restriction_of_scalars(C::GModule{<:Any, <:AbstractAlgebra.FPModule{AbsSimpleNumFieldElem}}, ::QQField) @@ -313,7 +319,7 @@ function maximal_submodule_bases(M::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra. return res end -function maximal_submodules(M::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.FPModule{<:FinFieldElem}}) +function Oscar.maximal_submodules(M::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.FPModule{<:FinFieldElem}}) return [sub(M, s) for s = maximal_submodule_bases(M)] end @@ -496,7 +502,7 @@ function _minimize(V::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.FPModule{AbsSi k char field | Q - + So: V is given as G -> GL(n, K) This is represented by sigma: Gal(K/k)^2 -> K a 2-chain @@ -520,7 +526,7 @@ function _minimize(V::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.FPModule{AbsSi split by A in GL(n, K) Now, technically, A V A^-1 has values in Gl(n, E) Step 7: - Replacing V -> A V A^-1 changes + Replacing V -> A V A^-1 changes X_g -> A^g X A^-1 As A V A^-1 is in GL(n, E), A^g X A^-1 can be normlized (mult. by scalar in K) to be in Gl(n, E) @@ -543,7 +549,7 @@ function _minimize(V::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.FPModule{AbsSi d = reduce(lcm, [x[2] for x = ld], init = 1) s = subfields(base_ring(V)) - + s = [x for x in s if degree(x[1]) >= d*degree(k)] sort!(s, lt = (a,b) -> degree(a[1]) < degree(b[1])) for (m, mm) in s @@ -600,7 +606,7 @@ function _minimize(V::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.FPModule{AbsSi #we need Gal(E/k) as the quotient of A/U q, mq = quo(domain(mA), U) X = Dict( g => map_entries(mA(preimage(mq, g)), AA) * X[preimage(mq, g)] * AAi for g = q) - for (g, x) = X + for (g, x) = X lf = findfirst(!iszero, x) x *= inv(x[lf]) X[g] = map_entries(pseudo_inv(mm), x) @@ -636,7 +642,7 @@ function _minimize(V::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.FPModule{AbsSi LD = Dict{AbsSimpleNumFieldOrderIdeal, Int}() LI = Dict{AbsSimpleNumFieldEmbedding, Int}() for (p, d) = ld - if p == -1 + if p == -1 @assert d == 2 if signature(k)[2] == 0 for e = real_embeddings(k) @@ -659,13 +665,13 @@ function _minimize(V::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.FPModule{AbsSi C, mC = automorphism_group(PermGroup, EF) gE = mE_EF(E[1]) hBC = hom(C, B, [[b for b = B if mC(c)(gE) == mE_EF(mB(b)(E[1]))][1] for c = gens(C)]) - gF = mF_EF(F[1]) - U, mU = sub(C, [c for c = C if mC(c)(gF) == gF]) + gF = mF_EF(F[1]) + U, mU = sub(C, [c for c = C if mC(c)(gF) == gF]) MEF = MultGrp(EF) #inflate s = Dict{NTuple{2, elem_type(U)}, elem_type(MEF)}((f, g) => MEF(mE_EF(s[(hBC(f), hBC(g))])) for f = U for g = U) - + D = gmodule(U, [hom(MEF, MEF, mC(mU(x))) for x = gens(U)]) Sigma = CoChain{2,PermGroupElem, MultGrpElem{AbsSimpleNumFieldElem}}(D, s) @@ -673,7 +679,7 @@ function _minimize(V::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.FPModule{AbsSi @assert fl #inflate X X = Dict( g => map_entries(mE_EF, X[preimage(h, hBC(mU(g)))]) *mu(g).data for g = U) - @hassert :MinField 1 isone_cochain(X, mU*mC) + @hassert :MinField 1 isone_cochain(X, mU*mC) @vtime :MinField 2 BB, BBi = hilbert90_generic(X, mU*mC) c = content_ideal(BB) sd = Hecke.short_elem(inv(c)) @@ -697,7 +703,8 @@ end function irreducible_modules(::QQField, G::Oscar.GAPGroup) #if cyclo is not minimal, this is not irreducible z = irreducible_modules(CyclotomicField, G) - return [gmodule(QQ, descent_to_minimal_degree_field(m)) for m in z] + temp = map(x -> galois_orbit_sum(character(x)), z) + return [gmodule(QQ, descent_to_minimal_degree_field(z[i])) for i in unique(i -> temp[i], 1:length(temp))] end function irreducible_modules(::ZZRing, G::Oscar.GAPGroup) @@ -926,7 +933,8 @@ function Oscar.sub(C::GModule{<:Any, <:AbstractAlgebra.FPModule{T}}, m::MatElem{ y = GAP.Globals.MTX.InducedActionSubmoduleNB(g, x) F = free_module(k, nrows(b)) - return gmodule(F, Group(C), [hom(F, F, matrix([preimage(h, x[i, j]) for i in 1:GAPWrap.NrRows(x), j in 1:GAPWrap.NrCols(x)])) for x = y.generators]), hom(F, C.M, b) + D = gmodule(F, Group(C), [hom(F, F, matrix([preimage(h, x[i, j]) for i in 1:GAPWrap.NrRows(x), j in 1:GAPWrap.NrCols(x)])) for x = y.generators]) + return D, hom(C, D, b) return b end @@ -936,7 +944,8 @@ function Oscar.sub(M::GModule{<:Any, <:AbstractAlgebra.FPModule{T}}, f::Abstract @assert codomain(f) == M.M S = domain(f) Sac = [hom(S, S, [preimage(f, h(f(x))) for x in gens(S)]) for h in M.ac] - return gmodule(S, M.G, Sac) + D = gmodule(S, M.G, Sac) + return D, hom(D, M, f) end function gmodule(k::Nemo.FinField, C::GModule{<:Any, <:AbstractAlgebra.FPModule{<:FinFieldElem}}) @@ -1324,14 +1333,14 @@ function Oscar.is_coboundary(c::CoChain{1,PermGroupElem,MultGrpElem{AbsSimpleNum cnt = 0 while true local Y - while true + while true Y = rand(K, -5:5) iszero(Y) || break end cnt += 1 S = sum(mA(emb(g))(Y)*c((g,)).data for g = G) is_zero(S) || return true, mK(S) - if cnt > 10 + if cnt > 10 error("should not happen") end end diff --git a/experimental/GModule/src/Misc.jl b/experimental/GModule/src/Misc.jl index dcca294ca93a..bd04a1d6cc6e 100644 --- a/experimental/GModule/src/Misc.jl +++ b/experimental/GModule/src/Misc.jl @@ -245,6 +245,9 @@ Hecke.restrict(::Hecke.NumFieldEmb, ::Map{QQField, AbsSimpleNumField}) = complex function relative_field(m::Map{<:AbstractAlgebra.Field, <:AbstractAlgebra.Field}) k = domain(m) K = codomain(m) + if k == base_field(K) + return defining_polynomial(K), Hecke.coordinates, representation_matrix + end @assert base_field(k) == base_field(K) kt, t = polynomial_ring(k, cached = false) f = defining_polynomial(K) diff --git a/experimental/GModule/src/Types.jl b/experimental/GModule/src/Types.jl new file mode 100644 index 000000000000..ade8fccf68f5 --- /dev/null +++ b/experimental/GModule/src/Types.jl @@ -0,0 +1,93 @@ +mutable struct GModuleHom{ G, T1, T2} <: Map{GModule{G, T1}, GModule{G, T2}, OscarMap, GModuleHom} + + GM1::GModule{G, T1} + GM2::GModule{G, T2} + module_map::Map{T1, T2} + + function GModuleHom( + M1::GModule, + M2::GModule, + mp::Map; + check::Bool = false + ) + # Need to require that + # 1. Both GModules have the same group + # 2. The group action is respected + @req M1.G === M2.G "groups need to be identical" + @req domain(mp) === M1.M && codomain(mp) === M2.M "map need to map 1st module into 2nd" + #not every hom is a G-Hom...that is what check is supposed to do - eventually + #see 2. + if check #only works if mp is a morphism so that "*" and "==" are doing + #s.th. useful + @assert all(g->action(M1, g)*mp == mp*action(M2, g), gens(M1.G)) + end + + return new{typeof(M1.G), typeof(M1.M), typeof(M2.M)}(M1, M2, mp) + end +end + +function hom(M1::GModule{T}, M2::GModule{T}, mp::Map; check::Bool = true) where T <: AbstractAlgebra.Group + return GModuleHom(M1, M2, mp; check) +end + +function hom(M1::GModule{T}, M2::GModule{T}, mp::MatElem; check::Bool = true) where T <: AbstractAlgebra.Group + return GModuleHom(M1, M2, hom(M1.M, M2.M, mp); check) +end + +domain(M::GModuleHom) = M.GM1 +codomain(M::GModuleHom) = M.GM2 +parent(M::GModuleHom) = Hecke.MapParent(domain(M), codomain(M), "homomorphisms") + +mutable struct GModuleElem{T} + parent::GModule + data::T +end + +parent(a::GModuleElem) = a.parent + +function (C::GModule)(a::Union{ModuleElem, FinGenAbGroupElem}) + @req parent(a) === C.M "wrong parent for $a" + return GModuleElem(C, a) +end + +function ==(a::GModuleElem, b::GModuleElem) + @req parent(a) === parent(b) "parents differ" + return a.data == b.data +end + +function hash(a::GModuleElem, u::UInt) + return hash(a.data, u) +end + +function +(a::GModuleElem, b::GModuleElem) + @req parent(a) === parent(b) "parents differ" + return GModuleElem(parent(a), a.data + b.data) +end + +function -(a::GModuleElem, b::GModuleElem) + @req parent(a) === parent(b) "parents differ" + return GModuleElem(parent(a), a.data - b.data) +end + +function -(a::GModuleElem) + return GModuleElem(parent(a), -a.data) +end + +function *(a::GModuleElem, g::GroupElem) + @req parent(a).G === parent(g) "group element has wrong parent" + return GModuleElem(parent(a), action(parent(a), g, a.data)) +end + +function (A::GModuleHom)(a::GModuleElem) + @req parent(a) === domain(A) "element has wrong parent" + return GModuleElem(codomain(A), A.module_map(a.data)) +end + +function kernel(A::GModuleHom) + return sub(A, kernel(A.module_map)[2]) +end + +function image(A::GModuleHom) + return sub(A, image(A.module_map)[2]) +end +