From d7b7045d9b5c794db0eb56e14727f577a1e69e7f Mon Sep 17 00:00:00 2001 From: Morgan Rodgers Date: Mon, 16 Sep 2024 12:16:43 +0200 Subject: [PATCH 01/30] add bad first attempt at `GModuleHom` type --- experimental/GModule/src/Types.jl | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 experimental/GModule/src/Types.jl diff --git a/experimental/GModule/src/Types.jl b/experimental/GModule/src/Types.jl new file mode 100644 index 000000000000..8d3b4369773c --- /dev/null +++ b/experimental/GModule/src/Types.jl @@ -0,0 +1,73 @@ +mutable struct GModuleHom{ + G<:Any + T1<:Any, + T2<:Any, + RingMapType<:Any} <: Map{GModule{G, T1}, GModule{G, T2}} + + GM1::GModule{G, T1} + GM2::GModule{G, T2} + module_map::Map{T1, T2} + + function GModuleHom( + M1::GModule{G, AbstractFreeMod}, + M2::GModule{G, S}, + a::Vector{ModuleElemType} + ) where {G, S<:ModuleFP, ModuleElemtype<:ModuleFPElem} + # Need to require that + # 1. Both GModules have the same group + # 2. The group action is respected + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, M2.mT, a)) + end + + function GModuleHom( + M1::GModule{G, AbstractFreeMod}, + M2::GModule{G, S}, + a::Vector{ModuleElemType}, + h::RingMapType + ) where {G, S, ModuleElemType<:ModuleFPElem, RingMapType} + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, RingMapType}(M1, M2, FreeModuleHom(M1.mT, M2.mT, a, h)) + end +end + + + + + + +function GModuleHom( + M1::GModule{G, AbstractFreeMod{T}}, + M2::GModule{G, S}, + mat::MatElem{T}) where {T<:RingElem, S<:AbstractFreeMod} + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat)) +end + +function GModuleHom( + M1::GModule{G, AbstractFreeMod{T}}, + M2::GModule{G, S}, + mat::MatElem{T}) where {T<:RingElem, S<:ModuleFP} + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat)) +end + +function GModuleHom( + M1::GModule{G, AbstractFreeMod{T}}, + M2::GModule{G, S}, + mat::MatElem{T}, h::RingMapType) where {T<:RingElem, S<:AbstractFreeMod, RingMapType} + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat, h)) +end + +function GModuleHom( + M1::GModule{G, AbstractFreeMod{T}}, + M2::GModule{G, S}, + mat::MatElem{T}, h::RingMapType) where {T<:RingElem, S<:ModuleFP, RingMapType} + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat, h)) +end + + +domain(M::Map(GModuleHom)) = M.Gm1 +codomain(M::Map(GModuleHom)) = M.Gm2 From f05a8abe0ea7c8ca90ddf68d40ecef116e5d9846 Mon Sep 17 00:00:00 2001 From: Morgan Rodgers Date: Tue, 17 Sep 2024 10:22:04 +0200 Subject: [PATCH 02/30] fix `irreducible_modules(QQ,G)` returning duplicate modules --- experimental/GModule/src/GModule.jl | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index cb2ef40cd73a..d7adf4cbe678 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -496,7 +496,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 +520,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 +543,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 +600,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 +636,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 +659,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 +673,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 +697,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)), VQ) + 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) @@ -1324,14 +1325,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 From 8a9d8dee443d772b4475caf5c44b698ff456222d Mon Sep 17 00:00:00 2001 From: Morgan Rodgers Date: Tue, 17 Sep 2024 11:32:34 +0200 Subject: [PATCH 03/30] fix variable name --- experimental/GModule/src/GModule.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index d7adf4cbe678..f7886c0b61d8 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -697,7 +697,7 @@ end function irreducible_modules(::QQField, G::Oscar.GAPGroup) #if cyclo is not minimal, this is not irreducible z = irreducible_modules(CyclotomicField, G) - temp = map(x -> galois_orbit_sum(character(x)), VQ) + 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 From 20c68251ab3b985ed4f9b737f6412e43434d4cab Mon Sep 17 00:00:00 2001 From: Morgan Rodgers Date: Tue, 17 Sep 2024 14:17:54 +0200 Subject: [PATCH 04/30] add missing `}` --- experimental/GModule/src/Types.jl | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/experimental/GModule/src/Types.jl b/experimental/GModule/src/Types.jl index 8d3b4369773c..73d5acec9756 100644 --- a/experimental/GModule/src/Types.jl +++ b/experimental/GModule/src/Types.jl @@ -1,5 +1,5 @@ mutable struct GModuleHom{ - G<:Any + G<:Any, T1<:Any, T2<:Any, RingMapType<:Any} <: Map{GModule{G, T1}, GModule{G, T2}} @@ -32,10 +32,6 @@ mutable struct GModuleHom{ end - - - - function GModuleHom( M1::GModule{G, AbstractFreeMod{T}}, M2::GModule{G, S}, From 2a16d7c10c877bc626a1b943986cfcd75bd194d5 Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Wed, 18 Sep 2024 12:02:34 +0200 Subject: [PATCH 05/30] extend the GHom's - almost useful now --- experimental/GModule/src/GModule.jl | 1 + experimental/GModule/src/Types.jl | 125 +++++++++++++++++----------- 2 files changed, 77 insertions(+), 49 deletions(-) diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index f7886c0b61d8..4242fcbd7d14 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -1,6 +1,7 @@ isdefined(Oscar, :word) || function word end include("Cohomology.jl") +include("Types.jl") include("GaloisCohomology.jl") include("GrpExt.jl") include("Misc.jl") diff --git a/experimental/GModule/src/Types.jl b/experimental/GModule/src/Types.jl index 73d5acec9756..c79b46f12108 100644 --- a/experimental/GModule/src/Types.jl +++ b/experimental/GModule/src/Types.jl @@ -4,66 +4,93 @@ mutable struct GModuleHom{ T2<:Any, RingMapType<:Any} <: Map{GModule{G, T1}, GModule{G, T2}} - GM1::GModule{G, T1} - GM2::GModule{G, T2} - module_map::Map{T1, T2} - - function GModuleHom( - M1::GModule{G, AbstractFreeMod}, - M2::GModule{G, S}, - a::Vector{ModuleElemType} - ) where {G, S<:ModuleFP, ModuleElemtype<:ModuleFPElem} - # Need to require that - # 1. Both GModules have the same group - # 2. The group action is respected - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, M2.mT, a)) - end + GM1::GModule{G, T1} + GM2::GModule{G, T2} + module_map::MP - function GModuleHom( - M1::GModule{G, AbstractFreeMod}, - M2::GModule{G, S}, - a::Vector{ModuleElemType}, - h::RingMapType - ) where {G, S, ModuleElemType<:ModuleFPElem, RingMapType} - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, RingMapType}(M1, M2, FreeModuleHom(M1.mT, M2.mT, a, h)) + 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 + @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), typeof(mp)}(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") -function GModuleHom( - M1::GModule{G, AbstractFreeMod{T}}, - M2::GModule{G, S}, - mat::MatElem{T}) where {T<:RingElem, S<:AbstractFreeMod} - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat)) +mutable struct GModuleElem{T} + parent::GModule + data::T end -function GModuleHom( - M1::GModule{G, AbstractFreeMod{T}}, - M2::GModule{G, S}, - mat::MatElem{T}) where {T<:RingElem, S<:ModuleFP} - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat)) +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 GModuleHom( - M1::GModule{G, AbstractFreeMod{T}}, - M2::GModule{G, S}, - mat::MatElem{T}, h::RingMapType) where {T<:RingElem, S<:AbstractFreeMod, RingMapType} - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat, h)) +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 GModuleHom( - M1::GModule{G, AbstractFreeMod{T}}, - M2::GModule{G, S}, - mat::MatElem{T}, h::RingMapType) where {T<:RingElem, S<:ModuleFP, RingMapType} - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat, h)) +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)) +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 -domain(M::Map(GModuleHom)) = M.Gm1 -codomain(M::Map(GModuleHom)) = M.Gm2 From e12fb1e06cf550d2e62765f46eea642e147c2f67 Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Wed, 18 Sep 2024 12:22:58 +0200 Subject: [PATCH 06/30] typos --- experimental/GModule/src/Types.jl | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/experimental/GModule/src/Types.jl b/experimental/GModule/src/Types.jl index c79b46f12108..a3acc85136f9 100644 --- a/experimental/GModule/src/Types.jl +++ b/experimental/GModule/src/Types.jl @@ -1,12 +1,8 @@ -mutable struct GModuleHom{ - G<:Any, - T1<:Any, - T2<:Any, - RingMapType<:Any} <: Map{GModule{G, T1}, GModule{G, T2}} +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::MP + module_map::Map{T1, T2} function GModuleHom( M1::GModule, @@ -25,7 +21,7 @@ mutable struct GModuleHom{ @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), typeof(mp)}(M1, M2, mp) + return new{typeof(M1.G), typeof(M1.M), typeof(M2.M)}(M1, M2, mp) end end From d9612fe6b6b78c36c73cbb80dbc747308687789f Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Wed, 18 Sep 2024 15:36:20 +0200 Subject: [PATCH 07/30] proof of comcept: use map in restriction --- experimental/GModule/src/GModule.jl | 21 ++++++++++++++------- experimental/GModule/src/Misc.jl | 3 +++ experimental/GModule/src/Types.jl | 9 +++++---- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index 4242fcbd7d14..7e82e0d702b0 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -8,7 +8,6 @@ include("Misc.jl") module GModuleFromGap using Oscar -using Hecke import Hecke: data #XXX: clash of names! @@ -44,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 @@ -57,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) @@ -314,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 @@ -928,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 @@ -938,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}}) 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 index a3acc85136f9..ade8fccf68f5 100644 --- a/experimental/GModule/src/Types.jl +++ b/experimental/GModule/src/Types.jl @@ -17,7 +17,8 @@ mutable struct GModuleHom{ G, T1, T2} <: Map{GModule{G, T1}, GModule{G, T2}, Osc @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 + 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 @@ -33,8 +34,8 @@ function hom(M1::GModule{T}, M2::GModule{T}, mp::MatElem; check::Bool = true) wh return GModuleHom(M1, M2, hom(M1.M, M2.M, mp); check) end -domain(M::GModuleHom) = M.Gm1 -codomain(M::GModuleHom) = M.Gm2 +domain(M::GModuleHom) = M.GM1 +codomain(M::GModuleHom) = M.GM2 parent(M::GModuleHom) = Hecke.MapParent(domain(M), codomain(M), "homomorphisms") mutable struct GModuleElem{T} @@ -79,7 +80,7 @@ end function (A::GModuleHom)(a::GModuleElem) @req parent(a) === domain(A) "element has wrong parent" - return GModuleElem(codomain(A), A.module_map(a)) + return GModuleElem(codomain(A), A.module_map(a.data)) end function kernel(A::GModuleHom) From 697ea8fae7a6fcd505ae4e38b5c3652333d9c3dd Mon Sep 17 00:00:00 2001 From: Morgan Rodgers Date: Mon, 16 Sep 2024 12:16:43 +0200 Subject: [PATCH 08/30] add bad first attempt at `GModuleHom` type --- experimental/GModule/src/Types.jl | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 experimental/GModule/src/Types.jl diff --git a/experimental/GModule/src/Types.jl b/experimental/GModule/src/Types.jl new file mode 100644 index 000000000000..8d3b4369773c --- /dev/null +++ b/experimental/GModule/src/Types.jl @@ -0,0 +1,73 @@ +mutable struct GModuleHom{ + G<:Any + T1<:Any, + T2<:Any, + RingMapType<:Any} <: Map{GModule{G, T1}, GModule{G, T2}} + + GM1::GModule{G, T1} + GM2::GModule{G, T2} + module_map::Map{T1, T2} + + function GModuleHom( + M1::GModule{G, AbstractFreeMod}, + M2::GModule{G, S}, + a::Vector{ModuleElemType} + ) where {G, S<:ModuleFP, ModuleElemtype<:ModuleFPElem} + # Need to require that + # 1. Both GModules have the same group + # 2. The group action is respected + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, M2.mT, a)) + end + + function GModuleHom( + M1::GModule{G, AbstractFreeMod}, + M2::GModule{G, S}, + a::Vector{ModuleElemType}, + h::RingMapType + ) where {G, S, ModuleElemType<:ModuleFPElem, RingMapType} + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, RingMapType}(M1, M2, FreeModuleHom(M1.mT, M2.mT, a, h)) + end +end + + + + + + +function GModuleHom( + M1::GModule{G, AbstractFreeMod{T}}, + M2::GModule{G, S}, + mat::MatElem{T}) where {T<:RingElem, S<:AbstractFreeMod} + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat)) +end + +function GModuleHom( + M1::GModule{G, AbstractFreeMod{T}}, + M2::GModule{G, S}, + mat::MatElem{T}) where {T<:RingElem, S<:ModuleFP} + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat)) +end + +function GModuleHom( + M1::GModule{G, AbstractFreeMod{T}}, + M2::GModule{G, S}, + mat::MatElem{T}, h::RingMapType) where {T<:RingElem, S<:AbstractFreeMod, RingMapType} + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat, h)) +end + +function GModuleHom( + M1::GModule{G, AbstractFreeMod{T}}, + M2::GModule{G, S}, + mat::MatElem{T}, h::RingMapType) where {T<:RingElem, S<:ModuleFP, RingMapType} + @assert M1.gT == M2.gT + r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat, h)) +end + + +domain(M::Map(GModuleHom)) = M.Gm1 +codomain(M::Map(GModuleHom)) = M.Gm2 From 24eaaff9951b965a75abcb450b629a90d18cd982 Mon Sep 17 00:00:00 2001 From: Morgan Rodgers Date: Tue, 17 Sep 2024 10:22:04 +0200 Subject: [PATCH 09/30] fix `irreducible_modules(QQ,G)` returning duplicate modules --- experimental/GModule/src/GModule.jl | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index 6e0e2bba84b3..511a8a68972c 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -496,7 +496,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 +520,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 +543,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 +600,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 +636,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 +659,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 +673,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 +697,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)), VQ) + 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) @@ -1324,14 +1325,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 From 657bf521d458e621a07b4cf230c82bd4c373cdb0 Mon Sep 17 00:00:00 2001 From: Morgan Rodgers Date: Tue, 17 Sep 2024 11:32:34 +0200 Subject: [PATCH 10/30] fix variable name --- experimental/GModule/src/GModule.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index 511a8a68972c..aa349adbc957 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -697,7 +697,7 @@ end function irreducible_modules(::QQField, G::Oscar.GAPGroup) #if cyclo is not minimal, this is not irreducible z = irreducible_modules(CyclotomicField, G) - temp = map(x -> galois_orbit_sum(character(x)), VQ) + 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 From 106165bfb20034887011e496ee6b52648480bf2d Mon Sep 17 00:00:00 2001 From: Morgan Rodgers Date: Tue, 17 Sep 2024 14:17:54 +0200 Subject: [PATCH 11/30] add missing `}` --- experimental/GModule/src/Types.jl | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/experimental/GModule/src/Types.jl b/experimental/GModule/src/Types.jl index 8d3b4369773c..73d5acec9756 100644 --- a/experimental/GModule/src/Types.jl +++ b/experimental/GModule/src/Types.jl @@ -1,5 +1,5 @@ mutable struct GModuleHom{ - G<:Any + G<:Any, T1<:Any, T2<:Any, RingMapType<:Any} <: Map{GModule{G, T1}, GModule{G, T2}} @@ -32,10 +32,6 @@ mutable struct GModuleHom{ end - - - - function GModuleHom( M1::GModule{G, AbstractFreeMod{T}}, M2::GModule{G, S}, From 4630411fed7c448b416bd55a8bb4c0a6a16cfa65 Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Wed, 18 Sep 2024 12:02:34 +0200 Subject: [PATCH 12/30] extend the GHom's - almost useful now --- experimental/GModule/src/GModule.jl | 1 + experimental/GModule/src/Types.jl | 125 +++++++++++++++++----------- 2 files changed, 77 insertions(+), 49 deletions(-) diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index aa349adbc957..fbd9628de1a9 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -1,6 +1,7 @@ isdefined(Oscar, :word) || function word end include("Cohomology.jl") +include("Types.jl") include("GaloisCohomology.jl") include("GrpExt.jl") include("Misc.jl") diff --git a/experimental/GModule/src/Types.jl b/experimental/GModule/src/Types.jl index 73d5acec9756..c79b46f12108 100644 --- a/experimental/GModule/src/Types.jl +++ b/experimental/GModule/src/Types.jl @@ -4,66 +4,93 @@ mutable struct GModuleHom{ T2<:Any, RingMapType<:Any} <: Map{GModule{G, T1}, GModule{G, T2}} - GM1::GModule{G, T1} - GM2::GModule{G, T2} - module_map::Map{T1, T2} - - function GModuleHom( - M1::GModule{G, AbstractFreeMod}, - M2::GModule{G, S}, - a::Vector{ModuleElemType} - ) where {G, S<:ModuleFP, ModuleElemtype<:ModuleFPElem} - # Need to require that - # 1. Both GModules have the same group - # 2. The group action is respected - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, M2.mT, a)) - end + GM1::GModule{G, T1} + GM2::GModule{G, T2} + module_map::MP - function GModuleHom( - M1::GModule{G, AbstractFreeMod}, - M2::GModule{G, S}, - a::Vector{ModuleElemType}, - h::RingMapType - ) where {G, S, ModuleElemType<:ModuleFPElem, RingMapType} - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, RingMapType}(M1, M2, FreeModuleHom(M1.mT, M2.mT, a, h)) + 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 + @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), typeof(mp)}(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") -function GModuleHom( - M1::GModule{G, AbstractFreeMod{T}}, - M2::GModule{G, S}, - mat::MatElem{T}) where {T<:RingElem, S<:AbstractFreeMod} - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat)) +mutable struct GModuleElem{T} + parent::GModule + data::T end -function GModuleHom( - M1::GModule{G, AbstractFreeMod{T}}, - M2::GModule{G, S}, - mat::MatElem{T}) where {T<:RingElem, S<:ModuleFP} - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat)) +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 GModuleHom( - M1::GModule{G, AbstractFreeMod{T}}, - M2::GModule{G, S}, - mat::MatElem{T}, h::RingMapType) where {T<:RingElem, S<:AbstractFreeMod, RingMapType} - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat, h)) +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 GModuleHom( - M1::GModule{G, AbstractFreeMod{T}}, - M2::GModule{G, S}, - mat::MatElem{T}, h::RingMapType) where {T<:RingElem, S<:ModuleFP, RingMapType} - @assert M1.gT == M2.gT - r = new{G, typeof(M1.mT), S, Nothing}(M1, M2, FreeModuleHom(M1.mT, m2.mT, mat, h)) +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)) +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 -domain(M::Map(GModuleHom)) = M.Gm1 -codomain(M::Map(GModuleHom)) = M.Gm2 From d29002dec0e85c28682a685ee6e32a609f0d07ba Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Wed, 18 Sep 2024 12:22:58 +0200 Subject: [PATCH 13/30] typos --- experimental/GModule/src/Types.jl | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/experimental/GModule/src/Types.jl b/experimental/GModule/src/Types.jl index c79b46f12108..a3acc85136f9 100644 --- a/experimental/GModule/src/Types.jl +++ b/experimental/GModule/src/Types.jl @@ -1,12 +1,8 @@ -mutable struct GModuleHom{ - G<:Any, - T1<:Any, - T2<:Any, - RingMapType<:Any} <: Map{GModule{G, T1}, GModule{G, T2}} +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::MP + module_map::Map{T1, T2} function GModuleHom( M1::GModule, @@ -25,7 +21,7 @@ mutable struct GModuleHom{ @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), typeof(mp)}(M1, M2, mp) + return new{typeof(M1.G), typeof(M1.M), typeof(M2.M)}(M1, M2, mp) end end From 6c9ad76247c607bcb64c65c4f027b529b58c428e Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Wed, 18 Sep 2024 15:36:20 +0200 Subject: [PATCH 14/30] proof of comcept: use map in restriction --- experimental/GModule/src/GModule.jl | 21 ++++++++++++++------- experimental/GModule/src/Misc.jl | 3 +++ experimental/GModule/src/Types.jl | 9 +++++---- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index fbd9628de1a9..1cf4a6e76165 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -8,7 +8,6 @@ include("Misc.jl") module GModuleFromGap using Oscar -using Hecke import Hecke: data #XXX: clash of names! @@ -44,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 @@ -57,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) @@ -314,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 @@ -928,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 @@ -938,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}}) 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 index a3acc85136f9..ade8fccf68f5 100644 --- a/experimental/GModule/src/Types.jl +++ b/experimental/GModule/src/Types.jl @@ -17,7 +17,8 @@ mutable struct GModuleHom{ G, T1, T2} <: Map{GModule{G, T1}, GModule{G, T2}, Osc @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 + 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 @@ -33,8 +34,8 @@ function hom(M1::GModule{T}, M2::GModule{T}, mp::MatElem; check::Bool = true) wh return GModuleHom(M1, M2, hom(M1.M, M2.M, mp); check) end -domain(M::GModuleHom) = M.Gm1 -codomain(M::GModuleHom) = M.Gm2 +domain(M::GModuleHom) = M.GM1 +codomain(M::GModuleHom) = M.GM2 parent(M::GModuleHom) = Hecke.MapParent(domain(M), codomain(M), "homomorphisms") mutable struct GModuleElem{T} @@ -79,7 +80,7 @@ end function (A::GModuleHom)(a::GModuleElem) @req parent(a) === domain(A) "element has wrong parent" - return GModuleElem(codomain(A), A.module_map(a)) + return GModuleElem(codomain(A), A.module_map(a.data)) end function kernel(A::GModuleHom) From 9a4c7ed9c8eb5491c87e31f7c2e44377de738c43 Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Thu, 26 Sep 2024 16:36:21 +0200 Subject: [PATCH 15/30] make extensino return an extension and add iso(FP...) the "same" should work for Pc - but we don't have the interface to sanely query the pc-relations (yet) --- experimental/GModule/src/Cohomology.jl | 2 +- experimental/GModule/src/GrpExt.jl | 233 +++++++++++++++++++++++++ 2 files changed, 234 insertions(+), 1 deletion(-) diff --git a/experimental/GModule/src/Cohomology.jl b/experimental/GModule/src/Cohomology.jl index 51af4ffaf8f2..1a7fb116c638 100644 --- a/experimental/GModule/src/Cohomology.jl +++ b/experimental/GModule/src/Cohomology.jl @@ -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)) diff --git a/experimental/GModule/src/GrpExt.jl b/experimental/GModule/src/GrpExt.jl index 3f8f08b8e4c6..a640d387309e 100644 --- a/experimental/GModule/src/GrpExt.jl +++ b/experimental/GModule/src/GrpExt.jl @@ -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. @@ -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. """ @@ -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) From 4053099b6c5d9ad17707a0ae8f74f08d5db2af0a Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Fri, 27 Sep 2024 14:35:46 +0200 Subject: [PATCH 16/30] more functionality for collector objects create an Oscar collector from a GAP collector --- src/Groups/pcgroup.jl | 60 ++++++++++++++++++++++++++++++++++++++++++ test/Groups/pcgroup.jl | 10 +++++++ 2 files changed, 70 insertions(+) diff --git a/src/Groups/pcgroup.jl b/src/Groups/pcgroup.jl index 923170798e44..380df8850d5c 100644 --- a/src/Groups/pcgroup.jl +++ b/src/Groups/pcgroup.jl @@ -365,3 +365,63 @@ function pc_group(c::GAP_Collector) end end + +# Create an Oscar collector from a GAP collector. + +""" + collector([::Type{T} = ZZRingElem, ]G::PcGroup) where T <: IntegerUnion + +Return a collector object for `G`. + +# Examples +```jldoctest +julia> g = small_group(12, 3) +Pc group of order 12 + +julia> c = collector(g); + +julia> gc = pc_group(c) +Pc group of order 12 + +julia> is_isomorphic(g, gc) +true +``` +""" +function collector(::Type{T}, G::PcGroup) where T <: IntegerUnion + Fam = GAPWrap.ElementsFamily(GAPWrap.FamilyObj(GapObj(G))) + GapC = GAP.getbangproperty(Fam, :rewritingSystem)::GapObj + + n = GAP.getbangindex(GapC, 3)::Int + c = collector(n, T) + + c.relorders = Vector{T}(GAP.getbangindex(GapC, 6)::GapObj) + + Gap_powers = GAP.gap_to_julia(GAP.getbangindex(GapC, 7)::GapObj, recursive = false) + for i in 1:length(Gap_powers) + if Gap_powers[i] !== nothing + l = GAPWrap.ExtRepOfObj(Gap_powers[i]) + c.powers[i] = Pair{Int,T}[l[k-1] => T(l[k]) for k in 2:2:length(l)] + end + end + + Gap_conj = GAP.gap_to_julia(GAP.getbangindex(GapC, 8)::GapObj, recursive = false) + for i in 1:length(Gap_conj) + Gap_conj_i = GAP.gap_to_julia(Gap_conj[i]::GapObj, recursive = false) + for j in 1:length(Gap_conj_i) + if Gap_conj_i[j] !== nothing + l = GAPWrap.ExtRepOfObj(Gap_conj_i[j]) + c.conjugates[j,i] = Pair{Int,T}[l[k-1] => T(l[k]) for k in 2:2:length(l)] + end + end + end + +# c.X = GapC +# c.F = FPGroup(GAP.getbangproperty(GAP.getbangindex(GapC, 1)::GapObj, :freeGroup)::GapObj) +#TODO: Set these known data. +# Currently this does not work because somehow `GroupByRws` +# requires a *mutable* GAP collector, and `GapC` is immutable. + + return c +end + +collector(G::PcGroup) = collector(ZZRingElem, G) diff --git a/test/Groups/pcgroup.jl b/test/Groups/pcgroup.jl index 8ec1f2c3cd3c..32d622c192e7 100644 --- a/test/Groups/pcgroup.jl +++ b/test/Groups/pcgroup.jl @@ -82,3 +82,13 @@ end @test GAP.Globals.IsMutable(cgg) @test cgg !== c.X end + +@testset "create collectors from polycyclic groups" begin + for i in rand(1:number_small_groups(96), 10) + g = small_group(96, i) + c = collector(Int64, g) + gc = pc_group(c) + f = hom(g, gc, gens(gc)) + @test is_bijective(f) + end +end From d45516c3b1a3899b48c38b8fee1b4bdfc0acf5d8 Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Wed, 9 Oct 2024 10:24:14 +0200 Subject: [PATCH 17/30] Update test/Groups/pcgroup.jl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lars Göttgens --- test/Groups/pcgroup.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Groups/pcgroup.jl b/test/Groups/pcgroup.jl index 32d622c192e7..983446ed8011 100644 --- a/test/Groups/pcgroup.jl +++ b/test/Groups/pcgroup.jl @@ -84,7 +84,7 @@ end end @testset "create collectors from polycyclic groups" begin - for i in rand(1:number_small_groups(96), 10) + for i in rand(1:number_of_small_groups(96), 10) g = small_group(96, i) c = collector(Int64, g) gc = pc_group(c) From 091592023ce6edd9ca4fd8da1ec988d898530730 Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Wed, 9 Oct 2024 10:28:02 +0200 Subject: [PATCH 18/30] change ordering to make it work --- experimental/GModule/src/GrpExt.jl | 49 +++++++++++++++--------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/experimental/GModule/src/GrpExt.jl b/experimental/GModule/src/GrpExt.jl index a640d387309e..9194b520d77e 100644 --- a/experimental/GModule/src/GrpExt.jl +++ b/experimental/GModule/src/GrpExt.jl @@ -27,6 +27,31 @@ function show(io::IO, G::GrpExt) print(io, "Extension via $(gmodule(G))") end +""" +The elements of the extension, given via a 2-co-chain. +""" +struct GrpExtElem{S, T} <: AbstractAlgebra.GroupElem + P::GrpExt{S, T} #parent + g::S #the group bit + m::T #the module bit + function GrpExtElem(P::GrpExt{A, B}, g::A, m::B) where A where B + return new{A, B}(P, g, m) + end +end + +function show(io::IO, g::GrpExtElem) + print(io, "($(g.g), $(g.m))") +end + +Oscar.gmodule(P::GrpExt) = P.c.C +Oscar.gmodule(P::GrpExtElem) = gmodule(parent(P)) +_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 Oscar.extension(c::Oscar.GrpCoh.CoChain{2,<:Oscar.GAPGroupElem}) return GrpExt(c) end @@ -243,30 +268,6 @@ function isomorphism(::Type{PcGroup}, E::GrpExt) end =# -""" -The elements of the extension, given via a 2-co-chain. -""" -struct GrpExtElem{S, T} <: AbstractAlgebra.GroupElem - P::GrpExt{S, T} #parent - g::S #the group bit - m::T #the module bit - function GrpExtElem(P::GrpExt{A, B}, g::A, m::B) where A where B - return new{A, B}(P, g, m) - end -end - -function show(io::IO, g::GrpExtElem) - print(io, "($(g.g), $(g.m))") -end - -Oscar.gmodule(P::GrpExt) = P.c.C -Oscar.gmodule(P::GrpExtElem) = gmodule(parent(P)) -_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 From 3122e45547c44af790d2b6f42485f66624a23d7e Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Wed, 9 Oct 2024 16:03:59 +0200 Subject: [PATCH 19/30] fix iso(FPGroup, E) and ass iso(PcGroup, E) the following should/ will work: C = trivial_gmodule(pc_group(symmetric_group(4)), abelian_group([2,3])) q = cohomology_group(C, 2); h = q[2](q[1][1]) E = extension(h) m1 = isomorphism(FPGroup, E) m2 = isomorphism(PcGroup, E) is_isomorphic(codomain(m1), codomain(m2)) However, m2 will not work as a map, there is code missing to legally convert a syllable back into a PcGroup Or a shiftgens for PcGroups The syllables function for Pc is possibly dodgy --- experimental/GModule/src/GrpExt.jl | 172 +++++++---------------------- 1 file changed, 38 insertions(+), 134 deletions(-) diff --git a/experimental/GModule/src/GrpExt.jl b/experimental/GModule/src/GrpExt.jl index 9194b520d77e..e80392948dfd 100644 --- a/experimental/GModule/src/GrpExt.jl +++ b/experimental/GModule/src/GrpExt.jl @@ -85,7 +85,7 @@ function Oscar.isomorphism(::Type{FPGroup}, E::GrpExt) c = E.c C = c.C G = C.G - mGF = Oscar.isomorphism(FPGroup, G, on_gens=true) + mGF = Oscar.isomorphism(FPGroup, G, on_gens=true) #G -> F F = codomain(mGF) M = C.M ac = action(C) @@ -97,13 +97,13 @@ function Oscar.isomorphism(::Type{FPGroup}, E::GrpExt) 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)))) + push!(s, shiftgens(R, N, 0)*(shiftgens(preimage(mfM, t.m), N, ngens(G)))) 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))) + push!(s, gen(N, ngens(G)+j)*gen(N, i)*inv(shiftgens(t, N, ngens(G))) * inv(gen(N, i))) end end Q, mQ = quo(N, s) @@ -113,7 +113,7 @@ function Oscar.isomorphism(::Type{FPGroup}, E::GrpExt) 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))) + return mQ(shiftgens(w, N, 0)*shiftgens(preimage(mfM, x.m-ww.m), N, ngens(G))) end return MapFromFunc(E, Q, EtoQ, y->map_word(y, gens(E))) @@ -122,151 +122,55 @@ function Oscar.isomorphism(::Type{FPGroup}, E::GrpExt) #both can/ should be handled by shiftgens (or sylable/ create) end -#= -function isomorphism(::Type{PcGroup}, E::GrpExt) +function Oscar.syllables(g::Union{PcGroupElem, SubPcGroupElem}) + l = GAPWrap.ExtRepOfObj(GapObj(g)) + @assert iseven(length(l)) + return Pair{Int, ZZRingElem}[l[i-1] => l[i] for i = 2:2:length(l)] +end + +function Oscar.isomorphism(::Type{PcGroup}, E::GrpExt) c = E.c C = c.C - G = Group(C) + G = C.G @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])) + M = C.M + mMf = Oscar.isomorphism(PcGroup, M) # M -> PcGroup + fM = codomain(mMf) - 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 + cM = collector(fM) + cG = collector(G) + nG = ngens(G) + cE = collector(nG + ngens(fM)) - 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 + set_relative_orders!(cE, vcat(cG.relorders, cM.relorders)) - word = function(y) - z = GAPWrap.UnderlyingElement(y) - return map(Int, GAP.Globals.LetterRepAssocWord(z)) + for i=1:ngens(fM) + set_power!(cE, i + nG, [g[1] + nG => g[2] for g = cM.powers[i]]) 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)) + + for i=1:nG + x = E[i]^Int(cG.relorders[i]) + t = vcat(Oscar.syllables(x.g), [ g[1] + nG => g[2] for g = Oscar.syllables(mMf(x.m))]) + set_power!(cE, i, 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) + for i=1:nG + for j=i+1:nG+ngens(fM) + x = E[j]^E[i] + t = vcat(Oscar.syllables(x.g), [ g[1] + nG => g[2] for g = Oscar.syllables(mMf(x.m))]) + set_conjugate!(cE, j, i, t) 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) + G = pc_group(cE) - @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)))) + function EtoG(x::GrpExtElem) + #need some inverse of syllables to make this efficient. + error("missing") + return shiftgens(w, N, 0)*shiftgens(preimage(mfM, x.m-ww.m), N, ngens(G)) end - - return Q, mfM*MtoQ, QtoG, GMtoQ + return MapFromFunc(E, G, EtoG, y->map_word(y, gens(E))) end -=# function one(G::GrpExt) return GrpExtElem(G, one(_group(G)), zero(_module(G))) From 5174b908061667e3bad8e5cfb27eeb1f198d7aa3 Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Fri, 27 Sep 2024 14:35:46 +0200 Subject: [PATCH 20/30] more functionality for collector objects create an Oscar collector from a GAP collector From 9a7c554b36f4b2c3fb4c0e21859fa751a8a660c7 Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Wed, 9 Oct 2024 14:04:10 +0200 Subject: [PATCH 21/30] add `get_relative_order`, `get_power`, `get_conjugate` --- src/Groups/pcgroup.jl | 101 ++++++++++++++++++++++++++++++++++++++++-- src/exports.jl | 4 ++ 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/Groups/pcgroup.jl b/src/Groups/pcgroup.jl index 380df8850d5c..d73a7dc0a0e3 100644 --- a/src/Groups/pcgroup.jl +++ b/src/Groups/pcgroup.jl @@ -51,7 +51,7 @@ true collector(n::Int, ::Type{T} = ZZRingElem) where T <: IntegerUnion = GAP_Collector{T}(n) -# Provide functions for entering data into the collector. +# Provide functions for entering data into the collector and accessing data. # utility: # Convert a vector of pairs to a generator-exponent vector in GAP. @@ -98,13 +98,33 @@ function set_relative_order!(c::Collector{T}, i::Int, relord::T) where T <: Inte end end +""" + get_relative_order(c::Collector{T}, i::Int) where T <: IntegerUnion + +Get the relative order of the `i`-th generator of `c`. + +# Examples +```jldoctest +julia> c = collector(2, Int); + +julia> set_relative_order!(c, 1, 2) + +julia> get_relative_order(c, 1) +2 +``` +""" +function get_relative_order(c::Collector{T}, i::Int) where T <: IntegerUnion + @req (0 < i && i <= c.ngens) "the collector has only $(c.ngens) generators not $i" + return c.relorders[i] +end + """ set_relative_orders!(c::Collector{T}, relords::Vector{T}) Set all relative orders of the generators of `c`, where the length of `relords` must be equal to the number of generators of `c`, and `relords[i]` denotes the relative order of the `i`-th generator. -which must be either `0` (meaning infinite order) or a positive integer.. +which must be either `0` (meaning infinite order) or a positive integer. # Examples ```jldoctest @@ -131,6 +151,26 @@ function set_relative_orders!(c::Collector{T}, relords::Vector{T}) where T <: In end end +""" + get_relative_orders(c::Collector{T}) + +Get the `Vector{T}` of all relative orders of the generators of `c`. + +# Examples +```jldoctest +julia> c = collector(2); + +julia> set_relative_orders!(c, ZZRingElem[2, 0]) + +julia> get_relative_orders(c) +2-element Vector{ZZRingElem}: + 2 + 0 +""" +function get_relative_orders(c::Collector{T}) where T <: IntegerUnion + return c.relorders +end + """ set_power!(c::Collector{T}, i::Int, rhs::Vector{Pair{Int, T}}) where T <: IntegerUnion @@ -165,6 +205,32 @@ function set_power!(c::Collector{T}, i::Int, rhs::Vector{Pair{Int, T}}) where T end end +""" + get_power(c::Collector{T}, i::Int) where T <: IntegerUnion + +Get the `Vector{Pair{Int, T}}` that describes the `c.relorders[i]`-th power +of the `i`-th generator of `c`. + +# Examples +```jldoctest +julia> c = collector(2, Int); + +julia> set_relative_order!(c, 1, 2) + +julia> set_relative_order!(c, 2, 3) + +julia> set_power!(c, 1, [2 => 1]) + +julia> get_power(c, 1) +1-element Vector{Pair{Int64, Int64}}: + 2 => 1 +``` +""" +function get_power(c::Collector{T}, i::Int) where T <: IntegerUnion + @req 0 < i <= c.ngens "the collector has only $(c.ngens) generators not $i" + return c.powers[i] +end + """ set_conjugate!(c::Collector{T}, j::Int, i::Int, rhs::Vector{Pair{Int, T}}) where T <: IntegerUnion @@ -199,6 +265,31 @@ function set_conjugate!(c::Collector{T}, j::Int, i::Int, rhs::Vector{Pair{Int, T end end +""" + get_conjugate(c::Collector{T}, j::Int, i::Int) where T <: IntegerUnion + +Get the `Vector{Pair{Int, T}}` that describes the conjugate of the `j`-th +generator of `c` by the `i`-th generator of `c`, for `i < j`. + +# Examples +```jldoctest +julia> c = collector(2, Int); + +julia> set_relative_orders!(c, [2, 3]) + +julia> set_conjugate!(c, 2, 1, [2 => 2]) + +julia> get_conjugate(c, 2, 1) +1-element Vector{Pair{Int64, Int64}}: + 2 => 2 +``` +""" +function get_conjugate(c::Collector{T}, j::Int, i::Int) where T <: IntegerUnion + @req 0 < i <= c.ngens "the collector has only $(c.ngens) generators not $i" + @req i < j "only for i < j, but i = $i, j = $j" + return c.conjugates[i,j] +end + """ set_commutator!(c::Collector{T}, j::Int, i::Int, rhs::Vector{Pair{Int, T}}) where T <: IntegerUnion @@ -215,7 +306,7 @@ julia> set_commutator!(c, 2, 1, [2 => 1]) ``` """ function set_commutator!(c::Collector{T}, j::Int, i::Int, rhs::Vector{Pair{Int, T}}) where T <: IntegerUnion - @req 0 < i <= c.ngens "the collector has only $(c.ngens) generators not $i" + @req 0 < j <= c.ngens "the collector has only $(c.ngens) generators not $j" @req i < j "only for i < j, but i = $i, j = $j" if length(rhs) > 0 && rhs[1].first == j # freely reduce @@ -415,11 +506,15 @@ function collector(::Type{T}, G::PcGroup) where T <: IntegerUnion end end +#TODO: deal also with the from-the-left-collector from the Polycyclic package + # c.X = GapC # c.F = FPGroup(GAP.getbangproperty(GAP.getbangindex(GapC, 1)::GapObj, :freeGroup)::GapObj) #TODO: Set these known data. # Currently this does not work because somehow `GroupByRws` # requires a *mutable* GAP collector, and `GapC` is immutable. +# (Change `pc_group` to not call `GroupByRWS` in this case? +# Forbid `set_power!` etc. in this case?) return c end diff --git a/src/exports.jl b/src/exports.jl index cce9ee01c6e0..6c85a66f1011 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -617,6 +617,10 @@ export gens, has_gens export gens_of_rational_equivalence_classes export geometric_genus export geometric_irreducible_components +export get_conjugate +export get_power +export get_relative_order +export get_relative_orders export getindex_safe export girth export gkz_vector From 5b04090a3b851e120446ac73409a12874a7a5f72 Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Thu, 10 Oct 2024 18:56:16 +0200 Subject: [PATCH 22/30] use Thomas' new functions and do the iso --- experimental/GModule/src/GrpExt.jl | 90 +++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 14 deletions(-) diff --git a/experimental/GModule/src/GrpExt.jl b/experimental/GModule/src/GrpExt.jl index e80392948dfd..50a0d03f4a09 100644 --- a/experimental/GModule/src/GrpExt.jl +++ b/experimental/GModule/src/GrpExt.jl @@ -128,6 +128,26 @@ function Oscar.syllables(g::Union{PcGroupElem, SubPcGroupElem}) return Pair{Int, ZZRingElem}[l[i-1] => l[i] for i = 2:2:length(l)] end +# convert syllables in canonical form into exponent vector +#Thomas +function exponent_vector(sylls::Vector{Pair{Int64, ZZRingElem}}, n) + res = zeros(ZZRingElem, n) + for pair in sylls + @assert res[pair.first] == 0 #just to make sure + res[pair.first] = pair.second + end + return res +end + +# convert syllables in canonical form into group element +#Thomas +function (G::PcGroup)(sylls::Vector{Pair{Int64, ZZRingElem}}) + e = exponent_vector(sylls, ngens(G)) + pcgs = Oscar.GAPWrap.FamilyPcgs(GapObj(G)) + x = Oscar.GAPWrap.PcElementByExponentsNC(pcgs, GapObj(e, true)) + return Oscar.group_element(G, x) +end + function Oscar.isomorphism(::Type{PcGroup}, E::GrpExt) c = E.c C = c.C @@ -135,6 +155,9 @@ function Oscar.isomorphism(::Type{PcGroup}, E::GrpExt) @assert isa(G, PcGroup) M = C.M mMf = Oscar.isomorphism(PcGroup, M) # M -> PcGroup + #TODO: this group is internal only. Should it be made available? + #TODO: this should be using the new syllable/ expo vector interface and + # not do any group arithmetic fM = codomain(mMf) cM = collector(fM) @@ -142,14 +165,18 @@ function Oscar.isomorphism(::Type{PcGroup}, E::GrpExt) nG = ngens(G) cE = collector(nG + ngens(fM)) - set_relative_orders!(cE, vcat(cG.relorders, cM.relorders)) + set_relative_orders!(cE, vcat(get_relative_orders(cG), get_relative_orders(cM))) for i=1:ngens(fM) - set_power!(cE, i + nG, [g[1] + nG => g[2] for g = cM.powers[i]]) + set_power!(cE, i + nG, [g[1] + nG => g[2] for g = get_power(cM, i)]) end - + + #TODO: if all is well, then the tails used to compute H^2 will match exactly + #the data required here - thus no computation will be required + #well for the conjugates the action on the module for i=1:nG - x = E[i]^Int(cG.relorders[i]) + #XXX: only since we don't have GrpEltElem^ZZRingElem (yet) + x = E[i]^Int(get_relative_order(cG, i)) t = vcat(Oscar.syllables(x.g), [ g[1] + nG => g[2] for g = Oscar.syllables(mMf(x.m))]) set_power!(cE, i, t) end @@ -162,16 +189,48 @@ function Oscar.isomorphism(::Type{PcGroup}, E::GrpExt) end end - G = pc_group(cE) + Q = pc_group(cE) - function EtoG(x::GrpExtElem) - #need some inverse of syllables to make this efficient. - error("missing") - return shiftgens(w, N, 0)*shiftgens(preimage(mfM, x.m-ww.m), N, ngens(G)) + function EtoQ(x::GrpExtElem) + @assert parent(x) == E + t = vcat(Oscar.syllables(x.g), [ g[1] + nG => g[2] for g = Oscar.syllables(mMf(x.m))]) + return Q(t) end - return MapFromFunc(E, G, EtoG, y->map_word(y, gens(E))) -end + function QtoE(x::PcGroupElem) + #implicitly assumes the syllables to be a normalized expo vector + #in particular the module part needs to be in the end + @assert parent(x) == Q + s = Oscar.syllables(x) + a = Pair{Int, ZZRingElem}[] + b = Pair{Int, ZZRingElem}[] + for i = s + if i[1] <= nG + push!(a, i) + else + push!(b, i[1]-nG => i[2]) + end + end + return E(G(a), preimage(mMf, fM(b))) + end + #XXX: this is not yet good: + # - we use elt -> syllable + # - but create elt from exponent vector (well this is hidden) + # why is the collector using syllables + # + #the collector has a type parameter for the exponents. This is "ignored" + #here + + return MapFromFunc(E, Q, EtoQ, QtoE) #y->map_word(y, gens(E))) +end +#= +Thomas: +Fuer die Umkehrabbildung kann man statt y -> map_word(y, gens(E)) +dann y in Syllables auspacken, an der richtigen Stelle in zwei Teile +aufteilen und die mit Hilfe der Kollektoren cM und cG in Elemente +verpacken, aus denen dann ein GrpExtElem gebaut wird. + +=# function one(G::GrpExt) return GrpExtElem(G, one(_group(G)), zero(_module(G))) end @@ -215,6 +274,9 @@ end function ==(g::GrpExtElem, h::GrpExtElem) @assert g.P === h.P + #XXX: will this work for FPGroupElems? They may not be normalized + # if the element is obtained through E(g, m) + # if it comes from arithmetic, I think it will be fine return g.g == h.g && g.m == h.m end @@ -260,13 +322,13 @@ function Oscar.is_stem_extension(P::GrpExt) G = _group(P) # part of algo is explained in Cohomology.jl # - # a commutator (comm(X, Y)) does not depend on X,m and Y.m + # a commutator (comm(X, Y)) does not depend on X.m and Y.m # We need to check M <= P' - # in P, M ;ooks like (1, M) + # in P, M looks like (1, M) # any word evaluated in P will have the G part as the evaluation # only on the G part (the G part is the projection, hence a hom) # any word evaluated in P to get a (1, M) will be a relator of G' - # Writig such a relator as a word in commutators make the evaluation + # Writing such a relator as a word in commutators make the evaluation # depend only on the co-chain, not on other choices. E, mE = derived_subgroup(G) h = commutator_decomposition_map(mE) From 5f020190a5ec12276ee30ec4dcb30e5a9f540021 Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Thu, 10 Oct 2024 18:56:51 +0200 Subject: [PATCH 23/30] add comment - it will fail... --- src/Groups/pcgroup.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Groups/pcgroup.jl b/src/Groups/pcgroup.jl index d73a7dc0a0e3..1f701f02c699 100644 --- a/src/Groups/pcgroup.jl +++ b/src/Groups/pcgroup.jl @@ -287,6 +287,8 @@ julia> get_conjugate(c, 2, 1) function get_conjugate(c::Collector{T}, j::Int, i::Int) where T <: IntegerUnion @req 0 < i <= c.ngens "the collector has only $(c.ngens) generators not $i" @req i < j "only for i < j, but i = $i, j = $j" + #XXX: will crash if this pair is not defined as they commute... + # needs thinking, is_assigned(c.com, i, j), ..., return c.conjugates[i,j] end From 9d621859c4c75c043f19cfeda0940266448f9a5e Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Thu, 28 Nov 2024 13:57:34 +0100 Subject: [PATCH 24/30] add/ fix support for sub/ image/ kernel for G-modules via abelian groups. This should work now: Zx, x = ZZ[:x]; k, a= number_field(swinnerton_dyer(4, x)) zk = lll(maximal_order(k)) p2 = prime_decomposition(zk, 2); C, mC = completion(k, p2[1][1]); G = gmodule(C); z = free_abelian_group(1) h = hom((G[1]).M, z, [z([Int(absolute_ramification_index(C)*valuation(G[3](x)))]) for x = gens((G[1]).M)]) hom(G[1], trivial_gmodule((G[1]).G, z), h) U = kernel(ans) cohomology_group(U[1], 1)[1] --- experimental/GModule/src/GModule.jl | 9 +++++++++ experimental/GModule/src/Types.jl | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index 1cf4a6e76165..02f098adcc57 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -948,6 +948,15 @@ function Oscar.sub(M::GModule{<:Any, <:AbstractAlgebra.FPModule{T}}, f::Abstract return D, hom(D, M, f) end +function Oscar.sub(M::GModule{<:Any, FinGenAbGroup}, f::FinGenAbGroupHom) + @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] + D = gmodule(S, M.G, Sac) + return D, hom(D, M, f) +end + + function gmodule(k::Nemo.FinField, C::GModule{<:Any, <:AbstractAlgebra.FPModule{<:FinFieldElem}}) @assert absolute_degree(k) == 1 F = free_module(k, dim(C)*absolute_degree(base_ring(C))) diff --git a/experimental/GModule/src/Types.jl b/experimental/GModule/src/Types.jl index ade8fccf68f5..6f4cf95d5bc3 100644 --- a/experimental/GModule/src/Types.jl +++ b/experimental/GModule/src/Types.jl @@ -84,10 +84,10 @@ function (A::GModuleHom)(a::GModuleElem) end function kernel(A::GModuleHom) - return sub(A, kernel(A.module_map)[2]) + return sub(domain(A), kernel(A.module_map)[2]) end function image(A::GModuleHom) - return sub(A, image(A.module_map)[2]) + return sub(codomain(A), image(A.module_map)[2]) end From 423540d56c0d0485d4c08ddff76fd2cff4ae4eac Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Fri, 27 Sep 2024 14:35:46 +0200 Subject: [PATCH 25/30] more functionality for collector objects create an Oscar collector from a GAP collector From ccb5ee4d58a296408e810e9438182d94a401e1b9 Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Thu, 12 Dec 2024 11:26:05 +0100 Subject: [PATCH 26/30] problems with forms... --- experimental/GModule/src/GModule.jl | 16 +++++++++++++--- experimental/GModule/src/GrpExt.jl | 7 ++++++- src/Rings/AbelianClosure.jl | 5 +++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index ca7db54fe705..d2d5eb380ee9 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -1842,8 +1842,8 @@ end function invariant_forms(C::GModule{<:Any, <:AbstractAlgebra.FPModule}) D = Oscar.dual(C) h = hom_base(C, D) - k = kernel(transpose(reduce(vcat, [matrix(base_ring(C), 1, dim(C)^2, _vec(x-transpose(x))) for x = h]))) - return [sum(h[i]*k[i, j] for i=1:length(h)) for j=1:ncols(k)] + k = kernel((reduce(vcat, [matrix(base_ring(C), 1, dim(C)^2, _vec(x-transpose(x))) for x = h]))) + return [sum(h[i]*k[j,i] for i=1:length(h)) for j=1:nrows(k)] end function Oscar.is_isomorphic(A::GModule{T, <:AbstractAlgebra.FPModule{<:FinFieldElem}}, B::GModule{T, <:AbstractAlgebra.FPModule{<:FinFieldElem}}) where T @@ -1952,12 +1952,22 @@ function action_matrices(C::GModule{<:Any, <:AbstractAlgebra.FPModule}) end function Oscar.simplify(C::GModule{<:Any, <:AbstractAlgebra.FPModule{ZZRingElem}}) - f = invariant_forms(C)[1] +# f = invariant_forms(C)[1] +#thsi will not give pos. def. forms!!! we need to go via Reynolds. # @assert all(i->det(f[1:i, 1:i])>0, 1:nrows(f)) m = map(matrix, C.ac) S = identity_matrix(ZZ, dim(C)) while true + f = zero_matrix(ZZ, dim(C), dim(C)) + for i=gens(C.G) + x = action(C, i) + f = f + matrix(x)*transpose(matrix(x)) + end +# @assert is_symmetric(f) +# @assert is_positive_definite(f) L, T = lll_gram_with_transform(f) +# @assert L == T*f*transpose(T) + Ti = inv(T) n = [T*x*Ti for x = m] if length(string(n)) >= length(string(m)) diff --git a/experimental/GModule/src/GrpExt.jl b/experimental/GModule/src/GrpExt.jl index 50a0d03f4a09..92ff6273a8aa 100644 --- a/experimental/GModule/src/GrpExt.jl +++ b/experimental/GModule/src/GrpExt.jl @@ -51,7 +51,6 @@ _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 Oscar.extension(c::Oscar.GrpCoh.CoChain{2,<:Oscar.GAPGroupElem}) return GrpExt(c) end @@ -122,12 +121,15 @@ function Oscar.isomorphism(::Type{FPGroup}, E::GrpExt) #both can/ should be handled by shiftgens (or sylable/ create) end +<<<<<<< Updated upstream function Oscar.syllables(g::Union{PcGroupElem, SubPcGroupElem}) l = GAPWrap.ExtRepOfObj(GapObj(g)) @assert iseven(length(l)) return Pair{Int, ZZRingElem}[l[i-1] => l[i] for i = 2:2:length(l)] end +======= +>>>>>>> Stashed changes # convert syllables in canonical form into exponent vector #Thomas function exponent_vector(sylls::Vector{Pair{Int64, ZZRingElem}}, n) @@ -139,6 +141,7 @@ function exponent_vector(sylls::Vector{Pair{Int64, ZZRingElem}}, n) return res end +<<<<<<< Updated upstream # convert syllables in canonical form into group element #Thomas function (G::PcGroup)(sylls::Vector{Pair{Int64, ZZRingElem}}) @@ -148,6 +151,8 @@ function (G::PcGroup)(sylls::Vector{Pair{Int64, ZZRingElem}}) return Oscar.group_element(G, x) end +======= +>>>>>>> Stashed changes function Oscar.isomorphism(::Type{PcGroup}, E::GrpExt) c = E.c C = c.C diff --git a/src/Rings/AbelianClosure.jl b/src/Rings/AbelianClosure.jl index 76d38f6b6e4d..36f44f95286d 100644 --- a/src/Rings/AbelianClosure.jl +++ b/src/Rings/AbelianClosure.jl @@ -503,6 +503,11 @@ conductor(a::AbsSimpleNumFieldElem) = conductor(parent(minimize(CyclotomicField, function conductor(k::AbsSimpleNumField) f, c = Hecke.is_cyclotomic_type(k) f || error("field is not of cyclotomic type") + if is_conductor(c) + return c + else + return div(c, 2) + end return c end From 58cb2935444eec10dccbdb8355f8fff04589ee03 Mon Sep 17 00:00:00 2001 From: Claus Fieker Date: Thu, 12 Dec 2024 11:35:52 +0100 Subject: [PATCH 27/30] remove stuff --- experimental/GModule/src/GrpExt.jl | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/experimental/GModule/src/GrpExt.jl b/experimental/GModule/src/GrpExt.jl index 92ff6273a8aa..669543b4850f 100644 --- a/experimental/GModule/src/GrpExt.jl +++ b/experimental/GModule/src/GrpExt.jl @@ -121,15 +121,6 @@ function Oscar.isomorphism(::Type{FPGroup}, E::GrpExt) #both can/ should be handled by shiftgens (or sylable/ create) end -<<<<<<< Updated upstream -function Oscar.syllables(g::Union{PcGroupElem, SubPcGroupElem}) - l = GAPWrap.ExtRepOfObj(GapObj(g)) - @assert iseven(length(l)) - return Pair{Int, ZZRingElem}[l[i-1] => l[i] for i = 2:2:length(l)] -end - -======= ->>>>>>> Stashed changes # convert syllables in canonical form into exponent vector #Thomas function exponent_vector(sylls::Vector{Pair{Int64, ZZRingElem}}, n) @@ -141,18 +132,6 @@ function exponent_vector(sylls::Vector{Pair{Int64, ZZRingElem}}, n) return res end -<<<<<<< Updated upstream -# convert syllables in canonical form into group element -#Thomas -function (G::PcGroup)(sylls::Vector{Pair{Int64, ZZRingElem}}) - e = exponent_vector(sylls, ngens(G)) - pcgs = Oscar.GAPWrap.FamilyPcgs(GapObj(G)) - x = Oscar.GAPWrap.PcElementByExponentsNC(pcgs, GapObj(e, true)) - return Oscar.group_element(G, x) -end - -======= ->>>>>>> Stashed changes function Oscar.isomorphism(::Type{PcGroup}, E::GrpExt) c = E.c C = c.C From 653309500121ce43c21cb738dad8238f7ee511cd Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Thu, 12 Dec 2024 17:12:34 +0100 Subject: [PATCH 28/30] fix a `conductor` call Note that `conductor` got corrected in a previous commit. --- src/GAP/iso_oscar_gap.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/GAP/iso_oscar_gap.jl b/src/GAP/iso_oscar_gap.jl index 7d87de40db34..a1e7af95d8fd 100644 --- a/src/GAP/iso_oscar_gap.jl +++ b/src/GAP/iso_oscar_gap.jl @@ -239,7 +239,8 @@ end # in Oscar and GAP, respectively. # (Cyclotomic fields are easier to handle than general number fields.) function _iso_oscar_gap_field_cyclotomic_functions(FO::AbsSimpleNumField, FG::GapObj) - N = conductor(FO) + flag, N = Hecke.is_cyclotomic_type(FO) + @req flag "FO was not constructed as a cyclotomic field" cycpol = GAPWrap.CyclotomicPol(N) dim = length(cycpol)-1 From 1cd883340868eddfd30a525976eac58c9504b51b Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Fri, 13 Dec 2024 12:57:28 +0100 Subject: [PATCH 29/30] make the tests pass - call `extension(FPGroup, c)` instead of `extension(c)` - in `invariant_lattice_classes`, put not the result of `sub` into the result but its first component - a prescribed test result was wrong, now it is corrent - `Map{T1,T2}` does actually not match the type of a `AbstractAlgebra.Generic.ModuleHomomorphism` (although domain and codomain are correct) --- experimental/GModule/src/Cohomology.jl | 4 ++-- experimental/GModule/src/GModule.jl | 2 +- experimental/GModule/src/Types.jl | 2 +- experimental/GModule/test/runtests.jl | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/experimental/GModule/src/Cohomology.jl b/experimental/GModule/src/Cohomology.jl index 1a7fb116c638..9e0bfe52f294 100644 --- a/experimental/GModule/src/Cohomology.jl +++ b/experimental/GModule/src/Cohomology.jl @@ -2253,7 +2253,7 @@ function split_extension(C::GModule) c = Dict((g, h) => zero(C.M) for g = C.G for h = C.G) S = elem_type(C.G) T = elem_type(C.M) - return extension(CoChain{2, S, T}(C, c)) + return extension(FPGroup, CoChain{2, S, T}(C, c)) end function split_extension(::Type{PcGroup}, C::GModule{<:PcGroupElem}) @@ -2396,7 +2396,7 @@ function pc_group(c::CoChain{2, <:Oscar.PcGroupElem}) end function Oscar.permutation_group(c::CoChain{2}) - g = extension(c)[1] + g = extension(FPGroup, c)[1] return permutation_group(g) end diff --git a/experimental/GModule/src/GModule.jl b/experimental/GModule/src/GModule.jl index d2d5eb380ee9..0d620735e4e0 100644 --- a/experimental/GModule/src/GModule.jl +++ b/experimental/GModule/src/GModule.jl @@ -287,7 +287,7 @@ function invariant_lattice_classes(M::GModule{<:Oscar.GAPGroup, <:AbstractAlgebr pG = p.*gens(M.M) for s in S x, mx = sub(M.M, vcat(pG, [M.M(map_entries(x->lift(ZZ, x), s[i:i, :])) for i in 1:nrows(s)])) - r = (sub(M, mx), mx) + r = (sub(M, mx)[1], mx) if any(x->is_isomorphic(r[1], x[1]), res) continue else diff --git a/experimental/GModule/src/Types.jl b/experimental/GModule/src/Types.jl index 6f4cf95d5bc3..996f21437265 100644 --- a/experimental/GModule/src/Types.jl +++ b/experimental/GModule/src/Types.jl @@ -2,7 +2,7 @@ mutable struct GModuleHom{ G, T1, T2} <: Map{GModule{G, T1}, GModule{G, T2}, Osc GM1::GModule{G, T1} GM2::GModule{G, T2} - module_map::Map{T1, T2} + module_map::Map function GModuleHom( M1::GModule, diff --git a/experimental/GModule/test/runtests.jl b/experimental/GModule/test/runtests.jl index 63864ed432c3..9da7d19a35dc 100644 --- a/experimental/GModule/test/runtests.jl +++ b/experimental/GModule/test/runtests.jl @@ -38,7 +38,7 @@ end @test length(z) == 5 z = irreducible_modules(ZZ, G) - @test length(z) == 5 + @test length(z) == 3 l = irreducible_modules(AbsSimpleNumField, small_group(48, 17), minimal_degree = true) ds = degree.(base_ring.(l)) @@ -130,7 +130,7 @@ end H2 = Oscar.GrpCoh.cohomology_group(M, 2) x = collect(H2[1])[1] c = H2[2](x) - e = extension(c) + e = extension(FPGroup, c) GG = e[1] @test order(GG) == 216 @test GG isa FPGroup @@ -189,7 +189,7 @@ end X = cyclic_group(4) M, _ = sub(X, [X[1]^2]) C, c = extension_with_abelian_kernel(X, M) - @test is_isomorphic(extension(c)[1], X) + @test is_isomorphic(extension(FPGroup, c)[1], X) end @testset "Experimental Schur" begin @@ -203,7 +203,7 @@ end M = trivial_gmodule(G, Z2) h, mh = cohomology_group(M, 2) @test Set(is_stem_extension(Oscar.GrpExt(mh(x))) for x = h) == Set([0,1]) - @test Set(is_stem_extension(extension(mh(x))[2]) for x = h) == Set([0,1]) + @test Set(is_stem_extension(extension(mh(x))) for x = h) == Set([0,1]) end From b81c70e44ff4497729c8725596337146e4b2c8b7 Mon Sep 17 00:00:00 2001 From: Morgan Rodgers Date: Wed, 15 Jan 2025 14:14:56 +0100 Subject: [PATCH 30/30] Update src/Rings/AbelianClosure.jl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lars Göttgens --- src/Rings/AbelianClosure.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Rings/AbelianClosure.jl b/src/Rings/AbelianClosure.jl index 36f44f95286d..598eb93f9aa6 100644 --- a/src/Rings/AbelianClosure.jl +++ b/src/Rings/AbelianClosure.jl @@ -508,7 +508,6 @@ function conductor(k::AbsSimpleNumField) else return div(c, 2) end - return c end conductor(a::QQAbFieldElem) = conductor(data(a))