Skip to content

Commit

Permalink
feat: residue fields of orders in global function fields
Browse files Browse the repository at this point in the history
  • Loading branch information
fieker authored and thofma committed Sep 17, 2024
1 parent 58f5733 commit 415930f
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 27 deletions.
11 changes: 11 additions & 0 deletions src/AlgAss/AbsAlgAss.jl
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,17 @@ function _primitive_element(A::AbstractAssociativeAlgebra{QQFieldElem})
return a, minpoly(a)
end

function __primitive_element(A::AbstractAssociativeAlgebra{QQFieldElem})
return _primitive_element(A)
end

function __primitive_element(A::AbstractAssociativeAlgebra{<:NumFieldElem})
B, BtoA = restrict_scalars(A, QQ)
a, f = __primitive_element(B)
b = BtoA(a)
return b, minpoly(b)
end

function __primitive_element(A::S) where {T <: FinFieldElem, S <: AbstractAssociativeAlgebra{T}} #<: Union{zzModRingElem, FqPolyRepFieldElem, fqPolyRepFieldElem, EuclideanRingResidueRingElem{ZZRingElem}, QQFieldElem, EuclideanRingResidueFieldElem{ZZRingElem}, fpFieldElem}
d = dim(A)
a = rand(A)
Expand Down
2 changes: 2 additions & 0 deletions src/FunField/DegreeLocalization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,8 @@ function divrem(a::KInftyElem{T}, b::KInftyElem{T}, check::Bool=true) where T <:
end
end

Base.rem(a::KInftyElem{T}, b::KInftyElem{T}, checked::Bool=true) where T <: FieldElement = mod(a, b, checked)

###############################################################################
#
# GCD
Expand Down
2 changes: 1 addition & 1 deletion src/GenOrd/GenOrd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ basis_matrix_inverse(O::GenOrd{S}) where {S} = O.itrans::dense_matrix_type(elem_
#
################################################################################

function basis(O::GenOrd)
function basis(O::GenOrd; copy::Bool = true)
get_attribute!(O, :basis) do
if _is_standard(O)
return map(O, basis(field(O)))
Expand Down
56 changes: 51 additions & 5 deletions src/GenOrd/Ideal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,12 @@ function _decomposition(O::GenOrd, I::GenOrdIdl, Ip::GenOrdIdl, T::GenOrdIdl, p:
return ideals
end

function Hecke.StructureConstantAlgebra(O::GenOrd, I::GenOrdIdl, p::RingElem)
function StructureConstantAlgebra(O::GenOrd, I::GenOrdIdl, p::RingElem)
FQ, phi = residue_field(base_ring(O), p)
StructureConstantAlgebra(O, I, p, phi)
end

function StructureConstantAlgebra(O::GenOrd, I::GenOrdIdl, p::RingElem, phi)
@assert order(I) === O

n = degree(O)
Expand All @@ -746,7 +751,7 @@ function Hecke.StructureConstantAlgebra(O::GenOrd, I::GenOrdIdl, p::RingElem)
end

r = length(basis_elts)
FQ, phi = residue_field(O.R,p)
FQ = codomain(phi)

if r == 0
A = zero_algebra(FQ)
Expand Down Expand Up @@ -999,7 +1004,7 @@ end
#
################################################################################

mutable struct GenOrdToAlgAssMor{S, T} <: Map{S, StructureConstantAlgebra{T}, Hecke.HeckeMap, GenOrdToAlgAssMor}
mutable struct GenOrdToAlgAssMor{S, T} <: Map{S, StructureConstantAlgebra{T}, Hecke.HeckeMap, Any}#GenOrdToAlgAssMor}
header::Hecke.MapHeader

function GenOrdToAlgAssMor{S, T}(O::S, A::StructureConstantAlgebra{T}, _image::Function, _preimage::Function) where {S <: GenOrd, T}
Expand All @@ -1010,10 +1015,9 @@ mutable struct GenOrdToAlgAssMor{S, T} <: Map{S, StructureConstantAlgebra{T}, He
end

function GenOrdToAlgAssMor(O::GenOrd, A::StructureConstantAlgebra{T}, _image, _preimage) where {T}
return AbsOrdToAlgAssMor{typeof(O), T}(O, A, _image, _preimage)
return GenOrdToAlgAssMor{typeof(O), T}(O, A, _image, _preimage)

Check warning on line 1018 in src/GenOrd/Ideal.jl

View check run for this annotation

Codecov / codecov/patch

src/GenOrd/Ideal.jl#L1018

Added line #L1018 was not covered by tests
end


################################################################################
#
# Misc.
Expand All @@ -1033,3 +1037,45 @@ function Hecke.characteristic(R::EuclideanRingResidueField{Hecke.GenOrdElem{Gene
return characteristic(function_field(base_ring(R)))
end

mutable struct GenOrdToFqField{S, T} <: Map{S, T, Hecke.HeckeMap, Any}#GenOrdToFqField}
header::Hecke.MapHeader

function GenOrdToFqField{S, T}(O::S, A::T, _image::Function, _preimage::Function) where {S <: GenOrd, T}
z = new{S, T}()
z.header = Hecke.MapHeader(O, A, _image, _preimage)
return z
end
end

function Nemo._residue_field(f::PolyRingElem{<:NumFieldElem})
Kt = parent(f)
L, b = number_field(f, "a"; cached = false)
return L, MapFromFunc(Kt, L, x -> L(x), y -> Kt(y))
end

function residue_field(O::GenOrd, P::GenOrdIdl, check::Bool = true)
a, g, b, phi = get_residue_field_data(P)::Tuple{elem_type(O),
dense_poly_type(base_ring(O)),
Vector{dense_matrix_type(base_ring(O))},
Any} # not optimal
gg = map_coefficients(phi, g)
bb = map_entries.(phi, b)
K = base_ring(parent(gg))
F, KtoF = Nemo._residue_field(gg)
d = degree(O)
imgofbas = [KtoF(parent(gg)(bb[i][1, :])) for i in 1:d]
powersofa = powers(a, degree(g))

_image = function(x::GenOrdElem)
@assert parent(x) === O
c = base_ring(O).(coordinates(x))
return sum(phi(c[i]) * imgofbas[i] for i in 1:d)
end

_preimage = function(x)
@assert parent(x) === F
return sum(preimage(phi, coeff(x, i - 1)) * powersofa[i] for i in 1:degree(g))
end

return F, GenOrdToFqField{typeof(O), typeof(F)}(O, F, _image, _preimage)
end
4 changes: 4 additions & 0 deletions src/GenOrd/Types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ end
gen_two::GenOrdElem

princ_gen::GenOrdElem
prim_elem::GenOrdElem
min_poly_prim_elem
basis_in_prim
phi

splitting_type::Tuple{Int, Int}
#ordered as ramification index, inertia degree
Expand Down
17 changes: 9 additions & 8 deletions src/HeckeTypes.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
################################################################################
#
# Maps
#
################################################################################

include("Map/MapType.jl")

################################################################################
#
# Abstract types for number fields
Expand Down Expand Up @@ -959,6 +967,7 @@ const AbsNumFieldOrderIdealSetID = AbstractAlgebra.CacheDictType{AbsNumFieldOrde
prim_elem::AbsNumFieldOrderElem{S, T}
min_poly_prim_elem::ZZPolyRingElem # minimal polynomial modulo P
basis_in_prim::Vector{ZZMatrix} #
phi::MapFromFunc{ZZRing, FqField}

function AbsNumFieldOrderIdeal{S, T}(O::AbsNumFieldOrder{S, T}) where {S, T}
# populate the bits types (Bool, Int) with default values
Expand Down Expand Up @@ -1859,14 +1868,6 @@ function QuadBin(R, a, b, c)
return z
end

################################################################################
#
# Maps
#
################################################################################

include("Map/MapType.jl")

################################################################################
#
# NoElements
Expand Down
35 changes: 22 additions & 13 deletions src/NumFieldOrd/NfOrd/ResidueField.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,50 @@
# pi(a)
# - a vector of ZZMatrix B, such that
# pi(basis(O)[i]) = sum_j B[i][1, j] * pi(a)^j
function compute_residue_field_data(m)
function compute_residue_field_data(m, phi)
O = domain(m)
basisO = basis(O, copy = false)
B = codomain(m)
primB, minprimB, getcoordpowerbasis = _as_field(B)
f = degree(minprimB)
F = domain(phi)
@assert F === base_ring(O)
prim_elem = m\(primB)
min_poly_prim_elem = ZZPolyRingElem(ZZRingElem[lift(ZZ, coeff(minprimB, i)) for i in 0:degree(minprimB)])
min_poly_prim_elem.parent = ZZPolyRing(FlintZZ, :$, false)
basis_in_prim = Vector{ZZMatrix}(undef, degree(O))
min_poly_prim_elem = (polynomial_ring(F, :$, cached = false)[1])(elem_type(F)[preimage(phi, coeff(minprimB, i)) for i in 0:degree(minprimB)])
basis_in_prim = Vector{dense_matrix_type(F)}(undef, degree(O))
for i in 1:degree(O)
basis_in_prim[i] = zero_matrix(FlintZZ, 1, f)
basis_in_prim[i] = zero_matrix(F, 1, f)
t = getcoordpowerbasis(m(basisO[i]))
for j in 1:f
basis_in_prim[i][1, j] = lift(ZZ, t[1, j])
basis_in_prim[i][1, j] = preimage(phi, t[1, j])
end
end
return prim_elem, min_poly_prim_elem, basis_in_prim
return prim_elem, min_poly_prim_elem, basis_in_prim, phi
end

# Compute the residue field data and store it in the prime P given the map m
function compute_residue_field_data!(P, m)
P.prim_elem, P.min_poly_prim_elem, P.basis_in_prim = compute_residue_field_data(m)
function compute_residue_field_data!(P::AbsNumFieldOrderIdeal, m)
F = base_ring(codomain(m))
phi = MapFromFunc(ZZ, F, x -> F(x), y -> lift(ZZ, y))
return compute_residue_field_data!(P, m, phi)
end

function compute_residue_field_data!(P, m, phi)
P.prim_elem, P.min_poly_prim_elem, P.basis_in_prim, P.phi = compute_residue_field_data(m, phi)
return nothing
end

# Compute the residue field data given the prime P
function compute_residue_field_data!(P)
p = minimum(P)
if fits(Int, p)
if isa(p, IntegerUnion) && fits(Int, p)
smallp = Int(p)
A, m = StructureConstantAlgebra(order(P), P, smallp)
compute_residue_field_data!(P, m)
else
AA, mm = StructureConstantAlgebra(order(P), P, p)
compute_residue_field_data!(P, mm)
_, phi = residue_field(base_ring(order(P)), p)
AA, mm = StructureConstantAlgebra(order(P), P, p, phi)
compute_residue_field_data!(P, mm, phi)
end
return nothing
end
Expand All @@ -55,7 +63,7 @@ end
# data is often cached.
function get_residue_field_data(P)
if isdefined(P, :prim_elem)
return P.prim_elem, P.min_poly_prim_elem, P.basis_in_prim
return P.prim_elem, P.min_poly_prim_elem, P.basis_in_prim, P.phi
else
compute_residue_field_data!(P)
get_residue_field_data(P)
Expand Down Expand Up @@ -184,6 +192,7 @@ end
# High level functions
#
################################################################################

@doc raw"""
residue_field(O::AbsSimpleNumFieldOrder, P::AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem}, check::Bool = true) -> Field, Map
Expand Down
40 changes: 40 additions & 0 deletions test/GenOrd/Ideal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,44 @@
h = O.R(x)
L = prime_decomposition(O, h)
@test prod([f[1]^f[2] for f in L]) == Hecke.GenOrdIdl(O, h)

for (P, _) in L
F, OtoF = residue_field(O, P)
for i in 1:10
a = dot([rand(base_ring(O), 1:5, 1:5) for i in 1:degree(O)], basis(O))
b = dot([rand(base_ring(O), 1:5, 1:5) for i in 1:degree(O)], basis(O))
@test OtoF(a) * OtoF(b) == OtoF(a * b)
c = OtoF(a)
@test OtoF(OtoF\c) == c
end
end

k = GF(5)
kt, t = rational_function_field(k, "t")
ktx, x = kt["x"]
F, a = function_field(x^5+x+3*t+1)
OF = Hecke.finite_maximal_order(F)
OI = Hecke.infinite_maximal_order(F)
lp = prime_decomposition(OF, numerator(t-1))
for (P, _) in lp
K, OFtoK = residue_field(OF, P)
for i in 1:10
a = dot([rand(base_ring(OF), 1:5) for i in 1:degree(OF)], basis(OF))
b = dot([rand(base_ring(OF), 1:5) for i in 1:degree(OF)], basis(OF))
@test OFtoK(a) * OFtoK(b) == OFtoK(a * b)
c = rand(K)
@test OFtoK(OFtoK\c) == c
end
end
lp = prime_decomposition(OI, base_ring(OI)(1//t))
for (P, _) in lp
K, OItoK = residue_field(OI, P)
for i in 1:10
a = OI(numerator(rand(kt, 1:5))(1//t))
b = OI(numerator(rand(kt, 1:5))(1//t))
@test OItoK(a) * OItoK(b) == OItoK(a * b)
c = rand(K)
@test OItoK(OItoK\c) == c
end
end
end

0 comments on commit 415930f

Please sign in to comment.