Skip to content

Commit

Permalink
cache automorphism groups of number fields (#2436)
Browse files Browse the repository at this point in the history
* cache automorphism groups of number fields

and related:
 - aut grp local fields
 - IdelClassGmodule
 - allow for use of lll-order by changeing ideal parents
 - galois group via cohomolgy: make sure the rcf is normal

* add tests...

* remove debugging assertion

* and another border case

* more trivia
  • Loading branch information
fieker committed Jun 2, 2023
1 parent a94bc0e commit 57cffdc
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 15 deletions.
34 changes: 26 additions & 8 deletions experimental/GModule/GModule.jl
Original file line number Diff line number Diff line change
Expand Up @@ -915,10 +915,28 @@ function hom_base(C::_T, D::_T) where _T <: GModule{<:Any, <:Generic.FreeModule{
for i=1:length(z1)
push!(t, hom_base(z1[i], z2[i]))
end
tt = [Hecke.modular_lift([t[i][j] for i=1:length(z1)], me) for j=1:length(t[1])]
if length(tt) == 0
#should actually compute an rref of the hom base to make sure
if any(x->length(x) != length(t[1]), t)
#bad prime...
continue
end
if length(t[1]) == 0
return []
end
pv = [findfirst(!iszero, x) for x = t[1]]
if any(!isequal(pv[1]), pv)
continue
end
for i=1:length(pv)
for j=1:length(t)
if !isone(t[j][i][pv[i]])
t[j][i] *= inv(t[j][i][pv[i]])
end
end
end
@assert all(i->all(x->x[pv[i]] == 1, t[i]), 1:length(pv))

tt = [Hecke.modular_lift([t[i][j] for i=1:length(z1)], me) for j=1:length(t[1])]
@assert base_ring(tt[1]) == k
if isone(pp)
pp = ZZRingElem(p)
Expand All @@ -929,7 +947,7 @@ function hom_base(C::_T, D::_T) where _T <: GModule{<:Any, <:Generic.FreeModule{
pp *= p
S = []
for t = T
fl, s = induce_rational_reconstruction(t, pp)
fl, s = induce_rational_reconstruction(t, pp)# , ErrorTolerant = true)
fl || break
push!(S, s)
end
Expand Down Expand Up @@ -992,7 +1010,7 @@ function hom_base(C::_T, D::_T) where _T <: GModule{<:Any, <:Generic.FreeModule{
reco *= 2
end
for t = T
fl, s = induce_rational_reconstruction(t, pp)
fl, s = induce_rational_reconstruction(t, pp, ErrorTolerant = true)
fl || break
push!(S, s)
end
Expand Down Expand Up @@ -1228,22 +1246,22 @@ function Hecke.induce_crt(a::Generic.MatSpaceElem{nf_elem}, b::Generic.MatSpaceE
return c
end

function Hecke.induce_rational_reconstruction(a::Generic.MatSpaceElem{nf_elem}, pg::ZZRingElem)
function Hecke.induce_rational_reconstruction(a::Generic.MatSpaceElem{nf_elem}, pg::ZZRingElem; ErrorTolerant::Bool = false)
c = parent(a)()
for i=1:nrows(a)
for j=1:ncols(a)
fl, c[i,j] = rational_reconstruction(a[i,j], pg)
fl, c[i,j] = rational_reconstruction(a[i,j], pg)#, ErrorTolerant = ErrorTolerant)
fl || return fl, c
end
end
return true, c
end

function Hecke.induce_rational_reconstruction(a::ZZMatrix, pg::ZZRingElem)
function Hecke.induce_rational_reconstruction(a::ZZMatrix, pg::ZZRingElem; ErrorTolerant::Bool = false)
c = zero_matrix(QQ, nrows(a), ncols(a))
for i=1:nrows(a)
for j=1:ncols(a)
fl, n, d = rational_reconstruction(a[i,j], pg, ErrorTolerant = true)
fl, n, d = rational_reconstruction(a[i,j], pg, ErrorTolerant = ErrorTolerant)
fl || return fl, c
c[i,j] = n//d
end
Expand Down
68 changes: 61 additions & 7 deletions experimental/GModule/GaloisCohomology.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,47 @@ export local_index
Oscar.elem_type(::Type{Hecke.NfMorSet{T}}) where {T <: Hecke.LocalField} = Hecke.LocalFieldMor{T, T}
parent(f::Hecke.LocalFieldMor) = Hecke.NfMorSet(domain(f))

_can_cache_aut(::FlintPadicField) = nothing
function _can_cache_aut(k)
a = get_attribute(k, :AutGroup)
if a === nothing
a = Dict{Tuple, Map}()
set_attribute!(k, :AutGroup => a)
end
return a
end
#not type restricted: used for number fields as well as
#LocalFields
#could be extended to allow more group types
function Oscar.automorphism_group(::Type{PermGroup}, k)
a = _can_cache_aut(k)
if a !== nothing && haskey(a, (PermGroup, ))
mG = a[(PermGroup, )]
return domain(mG), mG
end
G, mG = automorphism_group(k)
mH = isomorphism(PermGroup, G)
return codomain(mH), inv(mH)*mG
mmH = inv(mH)*mG
if a !== nothing
a[(PermGroup, )] = mmH
end
return codomain(mH), mmH
end

function Oscar.automorphism_group(::Type{PermGroup}, K, k)
a = _can_cache_aut(k)
if a !== nothing && haskey(a, (PermGroup, k))
mG = a[(PermGroup, k)]
return domain(mG), mG
end

G, mG = automorphism_group(K, k)
mH = isomorphism(PermGroup, G)
return codomain(mH), inv(mH)*mG
mmH = inv(mH)*mG
if a !== nothing
a[(PermGroup, k)] = mmH
end
return codomain(mH), mmH
end


Expand All @@ -45,11 +73,17 @@ end
The natural `ZZ[G]` module where `G`, the
automorphism group, acts on the ideal group defining the class field.
"""
function Oscar.gmodule(R::ClassField, mG = automorphism_group(PermGroup, base_field(R))[2])
function Oscar.gmodule(R::ClassField, mG = automorphism_group(PermGroup, base_field(R))[2]; check::Bool = true)
k = base_field(R)
G = domain(mG)
mR = R.rayclassgroupmap
mq = R.quotientmap
if check
c, mc = conductor(R)
@req all(x -> c == Hecke.induce_image(mG(x), c), gens(G)) "field is not normal"
s1 = Set(mc)
@req all(x -> s1 == Set(Hecke.induce_image(mG(x), y) for y = s1), gens(G)) "field is not normal"
end

ac = Hecke.induce_action(mR, [image(mG, g) for g = gens(G)], mq)
return GModule(G, ac)
Expand Down Expand Up @@ -655,8 +689,13 @@ or Ali,
Find a gmodule C s.th. C is cohomology-equivalent to the cohomology
of the idel-class group. The primes in `s` will always be used.
"""
function idel_class_gmodule(k::AnticNumberField, s::Vector{Int} = Int[])
@vprint :GaloisCohomology 1 "Ideal class group cohomology for $k\n"
function idel_class_gmodule(k::AnticNumberField, s::Vector{Int} = Int[]; redo::Bool=false)
@vprint :GaloisCohomology 2 "Ideal class group cohomology for $k\n"
I = get_attribute(k, :IdelClassGmodule)
if !redo && I !== nothing
return I
end

I = IdelParent()
I.k = k
G, mG = automorphism_group(PermGroup, k)
Expand Down Expand Up @@ -799,7 +838,7 @@ function idel_class_gmodule(k::AnticNumberField, s::Vector{Int} = Int[])
W, pro, inj = direct_product(V, F, task = :both)
@assert isdefined(W, :hnf)

ac = GrpAbFinGenMap(pro[1]*psi*sigma*pseudo_inv(psi)*inj[1])+ GrpAbFinGenMap(pro[2]*hom(F, W, [inj[1](preimage(psi, x[i])) - inj[2](F[i-1]) for i=2:length(x)]))
ac = GrpAbFinGenMap(pro[1]*psi*sigma*pseudo_inv(psi)*inj[1])+ GrpAbFinGenMap(pro[2]*hom(F, W, GrpAbFinGenElem[inj[1](preimage(psi, x[i])) - inj[2](F[i-1]) for i=2:length(x)]))
Et = gmodule(G_inf, [ac])
@assert is_consistent(Et)
mq = pseudo_inv(psi)*inj[1]
Expand Down Expand Up @@ -857,6 +896,7 @@ function idel_class_gmodule(k::AnticNumberField, s::Vector{Int} = Int[])
@hassert :GaloisCohomology 1 is_consistent(q)
I.mq = mq
I.data = (q, F[1])
set_attribute!(k, :IdelClassGmodule=>I)
return I
end

Expand Down Expand Up @@ -905,6 +945,12 @@ end
function Oscar.ideal(I::IdelParent, a::GrpAbFinGenElem; coprime::Union{NfOrdIdl, Nothing})
a = preimage(I.mq, a)
zk = maximal_order(I.k)
o_zk = zk
if coprime !== nothing && order(coprime) !== zk
o_zk = order(coprime)
coprime = zk*coprime
@assert order(coprime) === zk
end
id = 1*zk
for p = I.S
lp = prime_decomposition(zk, minimum(p))
Expand All @@ -922,7 +968,7 @@ function Oscar.ideal(I::IdelParent, a::GrpAbFinGenElem; coprime::Union{NfOrdIdl,
end
end
end
return id
return o_zk*id
end

function Oscar.galois_group(A::ClassField)
Expand Down Expand Up @@ -964,6 +1010,14 @@ function Oscar.galois_group(A::ClassField, ::QQField; idel_parent::IdelParent =
mR = A.rayclassgroupmap
mQ = A.quotientmap
zk = order(m0)
@req order(automorphism_group(nf(zk))[1]) == degree(zk) "base field must be normal"
if !Hecke.is_normal(A)
A = normal_closure(A)
mR = A.rayclassgroupmap
mQ = A.quotientmap
m0, m_inf = defining_modulus(A)
@assert length(m_inf) == 0
end
qI = cohomology_group(idel_parent, 2)
q, mq = snf(qI[1])
a = qI[2](image(mq, q[1])) # should be a 2-cycle in q
Expand Down
37 changes: 37 additions & 0 deletions test/Experimental/gmodule.jl
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,40 @@ end
@test order(preimage(q[2], c)) == 6
end

@testset "GlobalFundClass" begin
k, a = quadratic_field(-101)
H = hilbert_class_field(k)
G, _ = galois_group(H, QQ)
@test describe(G) == "D28"

r = ray_class_field(49*maximal_order(k), n_quo = 7)
G, _ = galois_group(r, QQ)
@test describe(G) == "C7 x D14"

lp = collect(keys(factor(7*maximal_order(k))))
s = ray_class_field(lp[1])
G, _ = galois_group(s, QQ)
@test describe(G) == "C6 x D42"

@test degree(normal_closure(s)) == 126
end

@testset "BrauerGroup" begin
G = transitive_group(24, 201)
T = character_table(G)
R = gmodule(T[9])
S = gmodule(CyclotomicField, R)

@test schur_index(T[9]) == 2

B, mB = relative_brauer_group(base_ring(S), character_field(S))
b = B(S)

C = grunwald_wang(Dict(2*ZZ => 2), Dict(complex_embeddings(QQ)[1] => 2))
@test degree(C) == 2
K, m1, m2 = compositum(base_ring(S), absolute_simple_field(number_field(C))[1])

SS = Oscar.GModuleFromGap.gmodule_over(m2, gmodule(K, S))

@test degree(base_ring(SS)) == 2
end

0 comments on commit 57cffdc

Please sign in to comment.