diff --git a/experimental/GModule/Brueckner.jl b/experimental/GModule/Brueckner.jl index 75d87619162b..b943de1edbd8 100644 --- a/experimental/GModule/Brueckner.jl +++ b/experimental/GModule/Brueckner.jl @@ -353,15 +353,13 @@ function lift(C::GModule, mp::Map) @assert isa(N, PcGroup) @assert codomain(mp) == N - _ = Oscar.GrpCoh.H_two(C) - ssc, mH2 = get_attribute(C, :H_two_symbolic_chain) - sc = (x,y) -> ssc(x, y)[1] + H2, z, _ = Oscar.GrpCoh.H_two(C; lazy = true) + if order(H2) > 1 + global last_in = (C, mp) + end R = relators(G) M = C.M D, pro, inj = direct_product([M for i=1:ngens(G)]..., task = :both) - a = sc(one(N), one(N)) - E = domain(a) - DE, pDE, iDE = direct_product(D, E, task = :both) #= G -->> N @@ -376,98 +374,71 @@ function lift(C::GModule, mp::Map) g_i is mapped to (m(g_i), pro[i](D)) this needs to be "collected" - - sc(a, b) yields sigma(a, b): E -> M, the value of the cohain as a map - (ie. the once e in E is chosen, sc(a, b)(e) is THE cochain =# K, pK, iK = direct_product([M for i=1:length(R)]..., task = :both) - s = hom(DE, K, [zero(K) for i=1:ngens(DE)]) - j = 1 - for r = R - a = (one(N), hom(DE, M, [zero(M) for i=1:ngens(DE)])) - for i = Oscar.GrpCoh.word(r) - if i<0 - h = inv(mp(G[-i])) - m = -pDE[1]*pro[-i]*action(C, h) - pDE[2]*sc(inv(h), h) - else - h = mp(G[i]) - m = pDE[1]*pro[i] - end - # a *(h, m) = (x, y)(h, m) = (xh, m + y^h + si(x, h)) - a = (a[1]*h, m + a[2]*action(C, h) + pDE[2]*sc(a[1], h)) - end - @assert isone(a[1]) - s += a[2]*iK[j] - j += 1 + S = relators(N) + if length(S) != 0 + X, pX, iX = direct_product([M for i=1:length(S)]..., task = :both) end - #so kern(s) should be exactly all possible quotients that allow a - #projection of G. They are not all surjective. However, lets try: - k, mk = kernel(s) + allG = [] - z = get_attribute(C, :H_two)[1] #tail (H2) -> cochain - - seen = Set{Tuple{elem_type(D), elem_type(codomain(mH2))}}() - #TODO: the projection maps seem to be rather slow - in particular - # as they SHOULD be trivial... - for x = k - epi = pDE[1](mk(x)) #the map - chn = mH2(pDE[2](mk(x))) #the tail data - if (epi,chn) in seen - continue - else - push!(seen, (epi, chn)) + + for h = H2 + GG, GGinj, GGpro, GMtoGG = Oscar.GrpCoh.extension(PcGroup, z(h)) + + s = hom(D, K, [zero(K) for i=1:ngens(D)]) + gns = [GMtoGG([x for x = GAP.Globals.ExtRepOfObj(h.X)], zero(M)) for h = gens(N)] + gns = [map_word(mp(g), gns, init = one(GG)) for g = gens(G)] + + rel = [map_word(r, gns, init = one(GG)) for r = relators(G)] + @assert all(x->isone(GGpro(x)), rel) + rhs = [preimage(GGinj, x) for x = rel] + s = hom(D, K, [K([preimage(GGinj, map_word(r, [gns[i] * GGinj(pro[i](h)) for i=1:ngens(G)])) for r = relators(G)] .- rhs) for h = gens(D)]) + + k, mk = kernel(s) + + if is_zero(h) && length(S) > 0 #Satz 15 in Brueckner, parts a and b + u = [preimage(mp, x) for x = gens(N)] + ss = elem_type(X)[] + sss = elem_type(D)[] + for h = gens(D) + uu = [map_word(x, [gns[i] * GGinj(pro[i](h)) for i=1:ngens(G)]) for x = u] + push!(ss, X([preimage(GGinj, map_word(r, uu, init = one(GG))) for r = relators(N)])) + push!(sss, D([preimage(GGinj, map_word(mp(G[i]), uu, init = one(GG))*inv(gns[i] * GGinj(pro[i](h)))) for i = 1:ngens(G)])) + end + ss = hom(D, X, ss) + sss = hom(D, D, sss) + kk, mkk = intersect(kernel(ss)[1], kernel(sss)[1]) + q, mq = quo(k, kk) + k = q + mk = pseudo_inv(mq)*mk end - #TODO: not all "chn" yield distinct groups - the factoring by the - # co-boundaries is missing - # not all "epi" are epi, ie. surjective. The part of the thm - # is missing... - # (Thm 15, part b & c) (and the weird lemma) -# @hassert :BruecknerSQ 2 all(x->all(y->sc(x, y)(chn) == last_c(x, y), gens(N)), gens(N)) - - - @hassert :BruecknerSQ 2 preimage(z, z(chn)) == chn - GG, GGinj, GGpro, GMtoGG = Oscar.GrpCoh.extension(PcGroup, z(chn)) - @assert is_surjective(GGpro) - if get_assertion_level(:BruecknerSQ) > 1 - _GG, _ = Oscar.GrpCoh.extension(z(chn)) - @assert is_isomorphic(GG, _GG) + + fl, pe = try + true, preimage(s, K(rhs)) + catch + false, zero(D) + end + if !fl + @show :no_sol + continue end - function reduce(g) #in G - h = mp(g) - c = ssc(h, one(N))[2] - if length(c) == 0 - return c + for x = k + if is_zero(h) && is_zero(x) + @show :skip, dim(k) + continue end - d = Int[abs(c[1]), sign(c[1])] - for i=c[2:end] - if abs(i) == d[end-1] - d[end] += sign(i) - else - push!(d, abs(i), sign(i)) - end + hm = hom(G, GG, [gns[i] * GGinj(pro[i](-pe + mk(x))) for i=1:ngens(G)]) + if is_surjective(hm) + push!(allG, hm) + else #should not be possible any more + @show :not_sur end - return d end - l= [GMtoGG(reduce(gen(G, i)), pro[i](epi)) for i=1:ngens(G)] -# @show map(order, l), order(prod(l)) -# @show map(order, gens(G)), order(prod(gens(G))) - - h = try - hom(G, GG, l) - catch - @show :crash - continue - end - if !is_surjective(h) -# @show :darn - continue - else -# @show :bingo - end - push!(allG, h) end + return allG end @@ -476,6 +447,53 @@ function solvable_quotient(G::Oscar.GAPGroup) mp = hom(G, q, [one(q) for g in gens(G)]) end +#= issues/ TODO + - does one need all SQs? are all maximal ones (in the sense of + no further extension possible) isomorphic? + - part c: this will extend by the modules several times (a maximal + number of times), useful if as above, any maximal chain will do + - use (or not) compatible pairs to construct fewer possibilities + (if legal...) + - gmodules as gset, support the interface? in particular orbits? + (for fewer extensions) + - gmodule -> matrix group (in some cases) + - filter for special targets (which???) + - does this work with gmodules in char 0? +=# + +#= EXAMPLE +F = free_group("a", "b"); a,b = gens(F); +G, hom = quo(F, [a^2*b*a^-1*b*a^-1*b^-1*a*b^-2, a^2*b^-1*a*b^-1*a*b*a^ +-1*b^2]) +f1 = Oscar.RepPc.solvable_quotient(G) +f2 = Oscar.RepPc.brueckner(f1; primes = [2]) +Oscar.RepPc.brueckner(f2[1]; primes = [2]) +f3 = ans; +f2 = Oscar.RepPc.brueckner(f1; primes = [2]) +f3 = Oscar.RepPc.brueckner(f2[1]; primes = [2]) +f4 = Oscar.RepPc.brueckner(f3[1]; primes = [3]) +f5 = Oscar.RepPc.brueckner(f4[1]; primes = [2]) +f6 = Oscar.RepPc.brueckner(f5[1]; primes = [2]) +f7 = Oscar.RepPc.brueckner(f6[1], primes = [2]) + +(there is a [5] step missing) + +H2, mH2, _ = Oscar.GrpCoh.H_two(C; redo = true, lazy = true); +T, mT = Oscar.GrpCoh.compatible_pairs(C) +G = gmodule(T, [Oscar.hom(H2, H2, [preimage(mH2, mT(g, mH2(a))) for a = gens(H2)]) for g = gens(T)]) + +then ones wants the orbits of "elements" in G... + +gset(matrix_group([matrix(x) for x= action(G)])) +@time orbits(ans) + +this works, but constracts all elements... + +G = gset(T, (a, g) -> preimage(mH2, mT(g, mH2(a))), collect(H2), closed = true) +orbits(G) + +=# + end #module RepPc using .RepPc diff --git a/experimental/GModule/Cohomology.jl b/experimental/GModule/Cohomology.jl index 14411657dbfa..a5dd87480ec8 100644 --- a/experimental/GModule/Cohomology.jl +++ b/experimental/GModule/Cohomology.jl @@ -543,6 +543,10 @@ function Oscar.relations(F::FPGroup) return [(x, z) for x = R] end +function Oscar.relators(F::PcGroup) + return [x[1] for x = relations(F)] +end + function Oscar.relations(G::PcGroup) # Call `GAPWrap.IsomorphismFpGroupByPcgs` only if `gens(G)` is a pcgs. Ggens = GAPWrap.GeneratorsOfGroup(G.X) @@ -572,16 +576,25 @@ end struct CoChain{N, G, M} C::GModule d::Dict{NTuple{N, G}, M} + D::Function function CoChain{N, G, M}(C::GModule, d::Dict{NTuple{N, G}, M}) where {N, G, M} return new{N, G, M}(C, d) end + + function CoChain{N, G, M}(C::GModule, d::Dict{NTuple{N, G}, M}, D) where {N, G, M} + return new{N, G, M}(C, d, D::Function) + end end function Base.show(io::IO, C::CoChain{N}) where {N} print(io, "$N-cochain with values in ", C.C.M) end +function Base.keys(C::CoChain{N}) where {N} + return Iterators.ProductIterator(Tuple([C.C.G for i=1:N])) +end + Oscar.Nemo.elem_type(::Type{AllCoChains{N,G,M}}) where {N,G,M} = CoChain{N,G,M} Oscar.Nemo.parent_type(::Type{CoChain{N,G,M}}) where {N,G,M} = AllCoChains{N,G,M} Oscar.parent(::CoChain{N,G,M}) where {N, G, M} = AllCoChains{N, G, M}() @@ -599,11 +612,19 @@ function differential(C::CoChain{N, G, M}) where {N, G, M} end function action(C::CoChain, g::PermGroupElem) - C = deepcopy(C) - for x = keys(C.d) - C.d[x] = action(C.C, g, C.d[x]) + CC = deepcopy(C) + if isdefined(C, :D) + for x = keys(CC.d) + CC.d[x] = action(C.C, g, C.d[x]) + end + CC.D = x->action(C.C, g, C.D(x)) + else + for x = keys(C) + CC.d[x] = action(C.C, g, C[x]) + end end - return C + + return CC end @@ -652,6 +673,7 @@ end (C::CoChain{1})(g::NTuple{1, <:Oscar.BasicGAPGroupElem}) = C(g[1]) #should support lazy via call-back. +#which should be used by default... """ Evaluate a 2-cochain, a 2-cochain is a map from pairs of group elements into the module @@ -660,6 +682,7 @@ function (C::CoChain{2})(g::Oscar.BasicGAPGroupElem, h::Oscar.BasicGAPGroupElem) if haskey(C.d, (g,h)) return C.d[(g,h)] end + return C.d[(g,h)] = C.D((g, h)) end (C::CoChain{2})(g::NTuple{2, <:Oscar.BasicGAPGroupElem}) = C(g[1], g[2]) @@ -1040,7 +1063,8 @@ UNIVERSAL COVERS OF FINITE GROUPS https://arxiv.org/pdf/1910.11453.pdf almost the same as Holt =# -function H_two(C::GModule; force_rws::Bool = false, redo::Bool = false) +#TODO: lazy = true, or even remove it +function H_two(C::GModule; force_rws::Bool = false, redo::Bool = false, lazy::Bool = false) z = get_attribute(C, :H_two) if !redo && z !== nothing return domain(z[1]), z[1], z[2] @@ -1406,6 +1430,37 @@ function H_two(C::GModule; force_rws::Bool = false, redo::Bool = false) return CoChain{2,elem_type(G),elem_type(M)}(C, di) end + function TailToCoChainLazy(t, g, h) + c.f = function(C::CollectCtx, w::Vector{Int}, r::Int, p::Int) + #w = ABC and B == r[1], B -> r[2] * tail[r] + # -> A r[2] C C(tail) + # C = c1 c2 ... C(tail): + @assert w[p:p+length(R[r][1])-1] == R[r][1] + + if pos[r] == 0 + return + end + T = pro[pos[r]](t) + for i=w[p+length(R[r][1]):end] + if i < 0 + T = iac[-i](T) + else + T = ac[i](T) + end + end + C.T += T + end + + c.T = zero(M) + if order(G) > 1 + gg = collect(word(preimage(mFF, g)), c) + hh = collect(word(preimage(mFF, h)), c) + c.T = zero(M) + d = collect(vcat(gg, hh), c) + end + return c.T + end + symbolic_chain = function(g, h) c.f = symbolic_collect if order(G) == 1 @@ -1464,10 +1519,19 @@ function H_two(C::GModule; force_rws::Bool = false, redo::Bool = false) return mH2(preimage(mE, T)) end - z = (MapFromFunc(H2, AllCoChains{2,elem_type(G),elem_type(M)}(), + if !lazy + z = (MapFromFunc(H2, AllCoChains{2,elem_type(G),elem_type(M)}(), x->TailToCoChain(mE(preimage(mH2, x))), z2), + is_coboundary) + else + z = (MapFromFunc(H2, AllCoChains{2,elem_type(G),elem_type(M)}(), + x->CoChain{2, elem_type(G),elem_type(M)}(C, Dict{NTuple{2, elem_type(G)}, elem_type(M)}(), t->TailToCoChainLazy(mE(preimage(mH2, x)), t[1], t[2])), + z2), +# x->TailToCoChain(mE(preimage(mH2, x))), z2), # y->TailFromCoChain(y), D, AllCoChains{2,elem_type(G),elem_type(M)}()), is_coboundary) + end + set_attribute!(C, :H_two => z) return H2, z[1], z[2] #now the rest... @@ -1505,7 +1569,7 @@ function istwo_cocycle(c::CoChain{2}) However, if we mix the conventions, all bets are off... =# - a = c.d[(g, h*k)] + c.d[(h, k)] - action(C, k, c.d[(g, h)])- c.d[(g*h, k)] + a = c(g, h*k) + c(h, k) - action(C, k, c(g, h))- c(g*h, k) # @show a, iszero(a) || valuation(a) iszero(a) || (@show g, h, k, a ; return false) @assert iszero(a) # only for local stuff...|| valuation(a) > 20 @@ -2176,6 +2240,21 @@ function extension_with_abelian_kernel(X::Oscar.GAPGroup, M::Oscar.GAPGroup) return C, CoChain{2, PermGroupElem, FinGenAbGroupElem}(C, c) end +function Oscar.automorphism_group(F::AbstractAlgebra.Generic.FreeModule{FqFieldElem}) + G = GL(dim(F), base_ring(F)) + return G, MapFromFunc(G, Hecke.MapParent(F, F, "homomorphisms"), + x->hom(F, F, x.elm), + y->G(matrix(y))) +end + +function (G::MatrixGroup{T})(h::AbstractAlgebra.Generic.ModuleHomomorphism{T}) where T + return G(matrix(h)) +end + +function (G::MatrixGroupElem{T})(h::AbstractAlgebra.FPModuleElem{T}) where T + return h*G +end + """ Let C be a G-module with G action on M. Then this function find the subgroup of 'Aut(M) x Aut(G)' that is compatible with the G-module @@ -2196,14 +2275,22 @@ function compatible_pairs(C::GModule) autG = automorphism_group(G) autM = automorphism_group(M) + if isa(autM, Tuple) + autM = autM[1] + end D, emb, pro = direct_product(autM, autG, morphisms = true) function action_on_chain(g::GAPGroupElem, c::CoChain{2, S, T}) where {S, T} al = pro[1](func(g)::elem_type(D))::elem_type(autM) ga = pro[2](func(g)::elem_type(D))::elem_type(autG) - d = Dict{Tuple{S, S}, T}(ab=> al(c((inv(ga)(ab[1]), inv(ga)(ab[2])))) for ab = keys(c.d)) - return CoChain{2, S, T}(C, d) + if isdefined(c, :D) + d = Dict{Tuple{S, S}, T}(ab=> al(c((inv(ga)(ab[1]), inv(ga)(ab[2])))) for ab = keys(c.d)) + return CoChain{2, S, T}(C, d, ab->al(c((inv(ga)(ab[1]), inv(ga)(ab[2]))))) + else + d = Dict{Tuple{S, S}, T}(ab=> al(c((inv(ga)(ab[1]), inv(ga)(ab[2])))) for ab = keys(c)) + return CoChain{2, S, T}(C, d) + end end h = hom(G, autM, [autM(x) for x = C.ac]) diff --git a/experimental/GModule/GModule.jl b/experimental/GModule/GModule.jl index c7e823a2cc1b..76e30d603bd2 100644 --- a/experimental/GModule/GModule.jl +++ b/experimental/GModule/GModule.jl @@ -24,6 +24,7 @@ import Base: parent function relative_field(m::Map{<:AbstractAlgebra.Field, <:AbstractAlgebra.Field}) k = domain(m) K = codomain(m) + @assert base_field(k) == base_field(K) kt, t = polynomial_ring(k, cached = false) f = defining_polynomial(K) Qt = parent(f) @@ -42,7 +43,7 @@ function relative_field(m::Map{<:AbstractAlgebra.Field, <:AbstractAlgebra.Field} m = collect(Hecke.coefficients(c)) m = vcat(m, zeros(k, degree(h) - length(m))) r = m - for i=2:degree(h) + for i in 2:degree(h) c = shift_left(c, 1) % h m = collect(Hecke.coefficients(c)) m = vcat(m, zeros(k, degree(h) - length(m))) @@ -90,12 +91,12 @@ function restriction_of_scalars(M::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.F F = free_module(domain(phi), dim(M)*d) _, _, rep = relative_field(phi) - return GModule(F, group(M), [hom(F, F, hvcat(dim(M), [rep(x) for x = transpose(matrix(y))]...)) for y = M.ac]) + return GModule(F, group(M), [hom(F, F, hvcat(dim(M), [rep(x) for x in transpose(matrix(y))]...)) for y in M.ac]) end function restriction_of_scalars(C::GModule{<:Any, <:AbstractAlgebra.FPModule{AbsSimpleNumFieldElem}}, ::QQField) F = free_module(QQ, dim(C)*degree(base_ring(C))) - return GModule(F, group(C), [hom(F, F, hvcat(dim(C), [representation_matrix(x) for x = transpose(matrix(y))]...)) for y = C.ac]) + return GModule(F, group(C), [hom(F, F, hvcat(dim(C), [representation_matrix(x) for x in transpose(matrix(y))]...)) for y in C.ac]) end @@ -142,6 +143,23 @@ function can_be_defined_over(M::GModule, phi::Map) error("not yet ...") end +function can_be_defined_over(M::GModule{<:Any, <:AbstractAlgebra.FPModule{<:FinFieldElem}}, phi::Map) + # Only works for irreducible modules + k = domain(phi) + K = base_ring(M) + d = absolute_degree(k) + @assert absolute_degree(K) != d + s = absolute_frobenius(K, d) + os = divexact(absolute_degree(K), d) + hB = hom_base(M, gmodule(M.M, Group(M), + [hom(M.M, M.M, map_entries(s, matrix(x))) for x = M.ac])) + if length(hB) != 1 + length(hB) > 1 && error("Module not irreducible") + length(hB) == 0 && return false + end + return true +end + """ can_be_defined_over_with_data(M::GModule, phi::Map) @@ -161,6 +179,39 @@ function can_be_defined_over_with_data(M::GModule, phi::Map) error("not yet ...") end +function can_be_defined_over_with_data(M::GModule{<:Any, <:AbstractAlgebra.FPModule{<:FinFieldElem}}, phi::Map) + # Only works for irreducible modules + k = domain(phi) + K = base_ring(M) + d = absolute_degree(k) + @assert absolute_degree(K) != d + + s = absolute_frobenius(K, d) + os = divexact(absolute_degree(K), d) + hB = hom_base(M, gmodule(M.M, Group(M), + [hom(M.M, M.M, map_entries(s, matrix(x))) for x = M.ac])) + if length(hB) != 1 + length(hB) > 1 && error("Module not irreducible") + length(hB) == 0 && return false + end + + B = hB[1] + D = norm(B, s, os) + lambda = D[1,1] + @hassert :MinField 2 D == lambda*identity_matrix(K, dim(C)) + alpha = norm_equation(K, preimage(phi, lambda)) + B *= inv(alpha) + @hassert :MinField 2 isone(norm(B, s, os)) + D = hilbert90_cyclic(B, s, os) + Di = inv(D) + F = free_module(k, dim(M)) + N = gmodule(F, Group(M), [hom(F, F, map_entries(x -> preimage(phi, x), Di*matrix(x)*D)) for x = C.ac]) + # TODO: Get this map working + # psi = GModuleHom(N, M, , phi) + psi = nothing + return (true, N, psi) +end + """ descent_to(M::GModule, phi::Map) @@ -185,6 +236,15 @@ function descent_to(M::GModule, phi::Map) end +function descent_to(M::GModule{<:Any, <:AbstractAlgebra.FPModule{<:FinFieldElem}}, phi::Map) + # Only works for irreducible modules + k = domain(phi) + success, N, psi = can_be_defined_over_with_data(M, phi) + success || error("Module cannot be written over $k") + return N +end + + """ descent_to_minimal_degree_field(M::GModule) @@ -200,8 +260,26 @@ where `M` is a module over `R`. (modules over finite fields or number fields) """ -function descent_to_minimal_degree_field(M::GModule) - error("not yet ...") +function descent_to_minimal_degree_field(C::GModule{<:Any, <:AbstractAlgebra.FPModule{fpFieldElem}}) + return C +end + +function descent_to_minimal_degree_field(C::GModule{<:Any, <:AbstractAlgebra.FPModule{<:FinFieldElem}}) + #always over char field + K = base_ring(C) + d = 0 + while d < absolute_degree(K)-1 + d += 1 + absolute_degree(K) % d == 0 || continue + k = GF(characteristic(K), d) + D = gmodule_over(k, C, do_error = false) + D === nothing || return D + end + return C +end + +function descent_to_minimal_degree_field(C::GModule{<:Any, <:AbstractAlgebra.FPModule{AbsSimpleNumFieldElem}}) + return _minimize(C) end @@ -241,13 +319,13 @@ function invariant_lattice_classes(M::GModule{<:Oscar.GAPGroup, <:AbstractAlgebr for X in res[sres:end] for p in lp F = free_module(GF(p), dim(M)) - pM = gmodule(M.G, [hom(F, F, map_entries(base_ring(F), x)) for x = map(matrix, action(M))]) + pM = gmodule(M.G, [hom(F, F, map_entries(base_ring(F), x)) for x in map(matrix, action(M))]) S = maximal_submodule_bases(pM) pG = p.*gens(M.M) - for s = S - x, mx = sub(M.M, vcat(pG, [M.M(map_entries(x->lift(ZZ, x), s[i:i, :])) for i=1:nrows(s)])) + 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 = (gmodule(M.G, [_hom(mx*h*pseudo_inv(mx)) for h = M.ac]), mx) + r = (gmodule(M.G, [_hom(mx*h*pseudo_inv(mx)) for h in M.ac]), mx) if any(x->is_isomorphic(r[1], x[1]), res) continue else @@ -267,7 +345,7 @@ Oscar.rank(M::AbstractAlgebra.Generic.Submodule{ZZRingElem}) = ngens(M) function maximal_submodule_bases(M::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.FPModule{<:FinFieldElem}}) C = Gap(M) S = GAP.Globals.MTX.BasesMaximalSubmodules(C) - res = [] + res = dense_matrix_type(base_ring(M))[] for s = S if length(s) == 0 m = matrix(base_ring(M), 0, dim(M), []) @@ -395,9 +473,9 @@ function _minimize(V::GModule{<:Oscar.GAPGroup, <:AbstractAlgebra.FPModule{AbsSi d = 1 # only a lower bound is known end s = subfields(base_ring(V)) - s = [x for x = s if degree(x[1]) >= d*degree(k)] + 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) = s + for (m, mm) in s if m == base_ring(V) @vprint :MinField 1 "no smaller field possible\n" return V @@ -420,7 +498,7 @@ 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, m) for m in z] + return [gmodule(QQ, descent_to_minimal_degree_field(m)) for m in z] end function irreducible_modules(::ZZRing, G::Oscar.GAPGroup) @@ -433,7 +511,7 @@ end TODO """ -function gmodule(::typeof(CyclotomicField), C::GModule) +function gmodule(a::Type{CyclotomicField}, C::GModule) @assert isa(base_ring(C), QQAbField) d = dim(C) l = 1 @@ -501,9 +579,10 @@ function _character(C::GModule{<:Any, <:AbstractAlgebra.FPModule{<:AbstractAlgeb push!(chr, (c, K(n))) continue end - #use T = action(C, r) instead? - p = preimage(phi, r) - T = map_word(p, ac; genimgs_inv = iac) + #use T = action(C, r) instead? Trying this, seems to work. + # p = preimage(phi, r) + # T = map_word(p, ac; genimgs_inv = iac) + T = action(C,r) push!(chr, (c, trace(matrix(T)))) end return chr @@ -608,7 +687,7 @@ function Hecke.frobenius(K::FinField, i::Int=1) end function Hecke.absolute_frobenius(K::FinField, i::Int=1) - MapFromFunc(K, K, x->Hecke.absolute_frobenius(x, i), y -> Hecke.absolute_frobenius(x, degree(K)-i)) + MapFromFunc(K, K, x->Hecke.absolute_frobenius(x, i), y -> Hecke.absolute_frobenius(x, absolute_degree(K)-i)) end @doc raw""" @@ -625,10 +704,10 @@ function gmodule_minimal_field(C::GModule{<:Any, <:AbstractAlgebra.FPModule{<:Fi #always over char field K = base_ring(C) d = 0 - while d < degree(K)-1 + while d < absolute_degree(K)-1 d += 1 - degree(K) % d == 0 || continue - k = GF(Int(characteristic(K)), d) + absolute_degree(K) % d == 0 || continue + k = GF(characteristic(K), d) D = gmodule_over(k, C, do_error = false) D === nothing || return D end @@ -640,7 +719,7 @@ function gmodule_minimal_field(C::GModule{<:Any, <:AbstractAlgebra.FPModule{AbsS end """ - gmodule_over(Field, GModule) + gmodule_over(k::Field, C::GModule) """ function gmodule_over(k::FinField, C::GModule{<:Any, <:AbstractAlgebra.FPModule{<:FinFieldElem}}; do_error::Bool = false) #mathematically, k needs to contain the character field @@ -1478,22 +1557,17 @@ function Oscar.gmodule(G::Oscar.GAPGroup, v::Vector{<:MatElem}) return gmodule(G, [hom(F, F, x) for x = v]) end - -function Oscar.gmodule(::Type{FinGenAbGroup}, C::GModule{T, AbstractAlgebra.FPModule{ZZRingElem}}) where {T <: Oscar.GAPGroup} - A = free_abelian_group(rank(C.M)) - return Oscar.gmodule(Group(C), [hom(A, A, matrix(x)) for x = C.ac]) +function Oscar.gmodule(::Type{FinGenAbGroup}, C::GModule{T, <:AbstractAlgebra.FPModule{FqFieldElem}}) where {T <: Oscar.GAPGroup} + k = base_ring(C.M) + A = abelian_group([characteristic(k) for i=1:rank(C.M)*absolute_degree(k)]) + return GModule(group(C), [hom(A, A, map_entries(x->lift(ZZ, x), hvcat(dim(C), [absolute_representation_matrix(x) for x = transpose(matrix(y))]...))) for y = C.ac]) end -function Oscar.gmodule(::Type{FinGenAbGroup}, C::GModule{T, AbstractAlgebra.FPModule{FpFieldElem}}) where {T <: Oscar.GAPGroup} +function Oscar.gmodule(::Type{FinGenAbGroup}, C::GModule{T, <:AbstractAlgebra.FPModule{<:Union{FpFieldElem, fpFieldElem}}}) where {T <: Oscar.GAPGroup} A = abelian_group([characteristic(base_ring(C)) for i=1:rank(C.M)]) return Oscar.gmodule(A, Group(C), [hom(A, A, map_entries(lift, matrix(x))) for x = C.ac]) end -function Oscar.gmodule(::Type{FinGenAbGroup}, C::GModule{T, <:AbstractAlgebra.FPModule{fpFieldElem}}) where {T <: Oscar.GAPGroup} - A = abelian_group([characteristic(base_ring(C)) for i=1:dim(C.M)]) - return Oscar.gmodule(A, Group(C), [hom(A, A, map_entries(lift, matrix(x))) for x = C.ac]) -end - function Oscar.abelian_group(M::Generic.FreeModule{ZZRingElem}) A = free_abelian_group(rank(M)) return A, MapFromFunc(A, M, x->M(x.coeff), y->A(y.v)) @@ -1504,6 +1578,7 @@ function Oscar.gmodule(::Type{FinGenAbGroup}, C::GModule{T, <:AbstractAlgebra.FP return Oscar.gmodule(A, Group(C), [hom(A, A, matrix(x)) for x = C.ac]) end +#TODO: for modern fin. fields as well function Oscar.abelian_group(M::AbstractAlgebra.FPModule{fqPolyRepFieldElem}) k = base_ring(M) A = abelian_group([characteristic(k) for i = 1:dim(M)*degree(k)]) @@ -1566,7 +1641,7 @@ end function Oscar.simplify(C::GModule{<:Any, <:AbstractAlgebra.FPModule{ZZRingElem}}) f = invariant_forms(C)[1] - global last_f = f + # global last_f = f @assert all(i->det(f[1:i, 1:i])>0, 1:nrows(f)) m = map(matrix, C.ac) S = identity_matrix(ZZ, dim(C)) diff --git a/experimental/GModule/test/runtests.jl b/experimental/GModule/test/runtests.jl index a7e7bb979172..e71825ae8a18 100644 --- a/experimental/GModule/test/runtests.jl +++ b/experimental/GModule/test/runtests.jl @@ -67,9 +67,9 @@ end @test extension_of_scalars(M, phi) == GModule(mE, G, [hom(mE, mE, a) for a in LE]) - G = Oscar.GrpCoh.fp_group_with_isomorphism(gens(G))[1] - q, mq = maximal_abelian_quotient(PcGroup, G) - @test length(Oscar.RepPc.brueckner(mq)) == 24 + # G = Oscar.GrpCoh.fp_group_with_isomorphism(gens(G))[1] + # q, mq = maximal_abelian_quotient(PcGroup, G) + # @test length(Oscar.RepPc.brueckner(mq)) == 24 end @testset "Experimental LocalH2" begin