From b8b8e297e528d7655503d1cbda06bc478835c90c Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Wed, 29 May 2024 13:52:27 +0200 Subject: [PATCH] Add residue ring of local fields (#1529) --- examples/NFDB.jl | 2 +- src/LocalField.jl | 1 + src/LocalField/Elem.jl | 25 +- src/LocalField/ResidueRing.jl | 357 +++++++++++++++++++++ src/LocalField/Ring.jl | 149 ++++----- src/LocalField/Types.jl | 64 ++++ src/LocalField/neq.jl | 6 +- src/NumFieldOrd/NfOrd/ResidueRing.jl | 2 + src/NumFieldOrd/NfOrd/StrongEchelonForm.jl | 14 +- src/exports.jl | 1 + test/LocalField.jl | 1 + test/LocalField/ResidueRing.jl | 67 ++++ 12 files changed, 593 insertions(+), 96 deletions(-) create mode 100644 src/LocalField/ResidueRing.jl create mode 100644 test/LocalField/ResidueRing.jl diff --git a/examples/NFDB.jl b/examples/NFDB.jl index d3fe130f19..9e79ab90f5 100644 --- a/examples/NFDB.jl +++ b/examples/NFDB.jl @@ -1195,7 +1195,7 @@ function _p_adic_regulator_coates(K::AbsSimpleNumField, p::IntegerUnion) # working_prec. while true (prec > 2^12 || working_prec > 2^12) && error("Something wrong") - imK =[QadicRingElem{PadicField, PadicFieldElem}[] for i in 1:degK] + imK =[LocalFieldValuationRingElem{PadicField, PadicFieldElem}[] for i in 1:degK] Qp = PadicField(p, prec, cached = false) Zp = ring_of_integers(Qp) dK = discriminant(OK) diff --git a/src/LocalField.jl b/src/LocalField.jl index 7684525aa7..0495a7b49d 100644 --- a/src/LocalField.jl +++ b/src/LocalField.jl @@ -9,3 +9,4 @@ include("LocalField/Conjugates.jl") include("LocalField/Poly.jl") include("LocalField/Completions.jl") include("LocalField/neq.jl") +include("LocalField/ResidueRing.jl") diff --git a/src/LocalField/Elem.jl b/src/LocalField/Elem.jl index 42bcb0943c..3c1049f443 100644 --- a/src/LocalField/Elem.jl +++ b/src/LocalField/Elem.jl @@ -25,6 +25,10 @@ function Base.deepcopy_internal(x::LocalFieldElem{S, T}, dict::IdDict) where {S, return LocalFieldElem{S, T}(parent(x), Base.deepcopy_internal(x.data, dict), precision(x)) end +function Base.hash(a::LocalFieldElem, h::UInt) + return hash(a.data, h) +end + ################################################################################ # # Precision @@ -235,22 +239,21 @@ function O(K::LocalField, prec::T) where T <: IntegerUnion return K(O(base_field(K), d)) end -function zero(K::LocalField) +function zero(K::LocalField; precision=precision(K)) a = zero(parent(defining_polynomial(K))) - return setprecision(K(a), precision(K)) + return setprecision(K(a), precision) end (K::LocalField)() = zero(K) -function one(K::LocalField) +function one(K::LocalField; precision=precision(K)) a = one(parent(defining_polynomial(K))) - return setprecision(K(a), precision(K)) + return setprecision(K(a), precision) end -function zero!(a::LocalFieldElem) - K = parent(a) +function zero!(a::LocalFieldElem; precision=precision(parent(a))) zero!(a.data) - a.data = setprecision(a.data, precision(K)) + a.data = setprecision(a.data, precision) return a end @@ -283,14 +286,14 @@ end # ################################################################################ -function (K::LocalField{S, T})(a::Integer) where {S <: FieldElem, T <: LocalFieldParameter} +function (K::LocalField{S, T})(a::Integer; precision=precision(K)) where {S <: FieldElem, T <: LocalFieldParameter} el = K(parent(defining_polynomial(K))(a)) - return setprecision!(el, precision(K)) + return setprecision!(el, precision) end -function (K::LocalField{S, T})(a::Union{ZZRingElem, QQFieldElem}) where {S <: FieldElem, T <: LocalFieldParameter} +function (K::LocalField{S, T})(a::Union{ZZRingElem, QQFieldElem}; precision=precision(K)) where {S <: FieldElem, T <: LocalFieldParameter} el = K(parent(defining_polynomial(K))(a)) - return setprecision!(el, precision(K)) + return setprecision!(el, precision) end function (K::LocalField{S, T})(a::U) where {U <: Union{PadicFieldElem, QadicFieldElem}, S <: FieldElem, T <: LocalFieldParameter} diff --git a/src/LocalField/ResidueRing.jl b/src/LocalField/ResidueRing.jl new file mode 100644 index 0000000000..33ea8e40c4 --- /dev/null +++ b/src/LocalField/ResidueRing.jl @@ -0,0 +1,357 @@ +################################################################################ +# +# Parent type etc +# +################################################################################ + +parent_type(::Type{LocalFieldValuationRingResidueRingElem{S, T}}) where {S, T} = LocalFieldValuationRingResidueRing{S, T} +elem_type(::Type{LocalFieldValuationRingResidueRing{S, T}}) where {S, T} = LocalFieldValuationRingResidueRingElem{S, T} +is_domain_type(::Type{<: LocalFieldValuationRingResidueRing}) = false +is_exact_type(::Type{<: LocalFieldValuationRingResidueRing}) = true + +################################################################################ +# +# Field access +# +################################################################################ + +_valuation_ring(R::LocalFieldValuationRingResidueRing) = R.R +_field(R::LocalFieldValuationRingResidueRing) = _valuation_ring(R).Q +_exponent(R::LocalFieldValuationRingResidueRing) = R.k + +base_ring(R::LocalFieldValuationRingResidueRing) = Union{} +base_ring_type(::Type{<: LocalFieldValuationRingResidueRing}) = typeof(Union{}) + +parent(a::LocalFieldValuationRingResidueRingElem) = a.parent +data(a::LocalFieldValuationRingResidueRingElem) = a.a +lift(a::LocalFieldValuationRingResidueRingElem) = _valuation_ring(parent(a))(data(a)) + +################################################################################ +# +# Basic functionality +# +################################################################################ + +characteristic(R::LocalFieldValuationRingResidueRing) = prime(_field(R))^_exponent(R) + +zero(R::LocalFieldValuationRingResidueRing) = R() +one(R::LocalFieldValuationRingResidueRing) = R(one(_valuation_ring(R), precision = _exponent(R)), copy = false) + +is_zero(a::LocalFieldValuationRingResidueRingElem) = is_zero(data(a)) +is_one(a::LocalFieldValuationRingResidueRingElem) = is_one(data(a)) + +function is_unit(a::LocalFieldValuationRingResidueRingElem) + is_zero(a) && return false + return is_zero(valuation(data(a))) +end +is_zero_divisor(a::LocalFieldValuationRingResidueRingElem) = !is_unit(a) + +function canonical_unit(a::LocalFieldValuationRingResidueRingElem) + if is_unit(a) + return a + end + return one(parent(a)) +end + +################################################################################ +# +# Parent object overloading +# +################################################################################ + +(R::LocalFieldValuationRingResidueRing)() = R(zero(_valuation_ring(R), precision = _exponent(R)), copy = false) + +function (R::LocalFieldValuationRingResidueRing)(a::Union{Integer, ZZRingElem, QQFieldElem, Rational}) + return R(_valuation_ring(R)(a, precision = _exponent(R)), copy = false) +end + +function (R::LocalFieldValuationRingResidueRing)(a::LocalFieldValuationRingResidueRingElem) + @req parent(a) === R "The given element is not an element of the ring" + return a +end + +function (R::LocalFieldValuationRingResidueRing)(a::LocalFieldValuationRingElem; copy::Bool = true) + @req parent(a) === _valuation_ring(R) "Rings don't match" + return R(a.x, copy = copy) +end + +function (R::LocalFieldValuationRingResidueRing)(a::NonArchLocalFieldElem; copy::Bool = true, check::Bool = true) + @req parent(a) === _field(R) "Fields don't match" + if check + @req precision(a) >= _exponent(R) "Insufficient precision" + @req is_zero(a) || valuation(a) >= 0 "Not an element of the valuation ring" + end + # Make sure that we have unique representatives + if copy + b = setprecision(a, _exponent(R)) + else + b = setprecision!(a, _exponent(R)) + end + return LocalFieldValuationRingResidueRingElem(b, R) +end + +################################################################################ +# +# Printing +# +################################################################################ + +function Base.show(io::IO, R::LocalFieldValuationRingResidueRing) + @show_name(io, R) + @show_special(io, R) + + print(io, _valuation_ring(R), " modulo ", uniformizer(_field(R)), "^", _exponent(R)) +end + +function AbstractAlgebra.expressify(x::LocalFieldValuationRingResidueRingElem{PadicField}; context = nothing) + p = BigInt(prime(_field(parent(x)))) + sum = Expr(:call, :+) + v = valuation(data(x)) + u = BigInt(lift(ZZ, data(x))) + if v > 0 + u = div(u, p^v) + end + d = digits(u, base=p) + for i in 0:length(d)-1 + ppower = Expr(:call, :^, p, i + v) + push!(sum.args, Expr(:call, :*, d[i + 1], ppower)) + end + return sum +end + +function AbstractAlgebra.expressify(a::LocalFieldValuationRingResidueRingElem{QadicField}, x = var(_field(parent(a))); context = nothing) + b = data(a) + K = base_field(parent(b)) + if iszero(b) + return 0 + end + p = BigInt(prime(K)) + sum = Expr(:call, :+) + c = K(precision = precision(parent(b))) + for i in degree(parent(b)):-1:0 + ccall((:padic_poly_get_coeff_padic, libflint), Nothing, + (Ref{PadicFieldElem}, Ref{QadicFieldElem}, Int, Ref{QadicField}), + c, b, i, parent(b)) + + # expressify c (without + O(...)) + ec = Expr(:call, :+) + v = valuation(c) + u = BigInt(lift(ZZ, c)) + if v > 0 + u = div(u, p^v) + end + d = digits(u, base=p) + for i in 0:length(d)-1 + ppower = Expr(:call, :^, p, i + v) + push!(ec.args, Expr(:call, :*, d[i + 1], ppower)) + end + + if !iszero(c) + if iszero(i) + push!(sum.args, ec) + elseif isone(i) + push!(sum.args, Expr(:call, :*, ec, x)) + else + push!(sum.args, Expr(:call, :*, ec, Expr(:call, :^, x, i))) + end + end + end + return sum +end + +function show(io::IO, a::LocalFieldValuationRingResidueRingElem{<:Union{PadicField, QadicField}}) + print(io, AbstractAlgebra.obj_to_string(a, context = io)) +end + +Base.show(io::IO, a::LocalFieldValuationRingResidueRingElem) = show(io, data(a)) + +################################################################################ +# +# Hashing / deepcopy +# +################################################################################ + +function Base.deepcopy_internal(a::LocalFieldValuationRingResidueRingElem, dict::IdDict) + return LocalFieldValuationRingResidueRingElem(Base.deepcopy_internal(data(a), dict), parent(a)) +end + +function Base.hash(a::LocalFieldValuationRingResidueRingElem, h::UInt) + return hash(data(a), h) +end + +################################################################################ +# +# Comparison +# +################################################################################ + +function Base.:(==)(a::LocalFieldValuationRingResidueRingElem, b::LocalFieldValuationRingResidueRingElem) + @req parent(a) === parent(b) "Parents do not match" + return data(a) == data(b) +end + +################################################################################ +# +# Unary operations +# +################################################################################ + +function Base.:(-)(a::LocalFieldValuationRingResidueRingElem) + return parent(a)(-data(a), copy = false, check = false) +end + +################################################################################ +# +# Binary operations +# +################################################################################ + +function Base.:(+)(a::LocalFieldValuationRingResidueRingElem, b::LocalFieldValuationRingResidueRingElem) + @req parent(a) === parent(b) "Parents do not match" + return parent(a)(data(a) + data(b), copy = false, check = false) +end + +function Base.:(-)(a::LocalFieldValuationRingResidueRingElem, b::LocalFieldValuationRingResidueRingElem) + @req parent(a) === parent(b) "Parents do not match" + return parent(a)(data(a) - data(b), copy = false, check = false) +end + +function Base.:(*)(a::LocalFieldValuationRingResidueRingElem, b::LocalFieldValuationRingResidueRingElem) + @req parent(a) === parent(b) "Parents do not match" + return parent(a)(data(a) * data(b), copy = false, check = false) +end + +################################################################################ +# +# Powering +# +################################################################################ + +function Base.:(^)(a::LocalFieldValuationRingResidueRingElem, e::Int) + @req is_unit(a) || e >= 0 "Element is not invertible" + return parent(a)(data(a)^e, copy = false, check = false) +end + +################################################################################ +# +# Divexact +# +################################################################################ + +function divexact(a::LocalFieldValuationRingResidueRingElem, b::LocalFieldValuationRingResidueRingElem) + @req parent(a) === parent(b) "Parents do not match" + @req !is_zero(b) "Division by 0" + if is_zero(a) + return zero(parent(a)) + end + @req valuation(data(a)) >= valuation(data(b)) "Division not possible" + c = divexact(data(a), data(b)) + setprecision!(c, _exponent(parent(a))) + return parent(a)(c, copy = false, check = false) +end + +################################################################################ +# +# Divrem +# +################################################################################ + +function Base.divrem(a::LocalFieldValuationRingResidueRingElem, b::LocalFieldValuationRingResidueRingElem) + @req parent(a) === parent(b) "Parents do not match" + @req !is_zero(b) "Division by 0" + if !is_zero(a) && valuation(data(a)) >= valuation(data(b)) + return divexact(a, b), zero(parent(a)) + end + return zero(parent(a)), a +end + +# Return g, u, v, s, t with g = gcd(a, b), g = u*a + v*b, 0 = s*a + t*b and u*t - v*s = 1 +function xxgcd(a::LocalFieldValuationRingResidueRingElem, b::LocalFieldValuationRingResidueRingElem) + @req parent(a) === parent(b) "Parents do not match" + + R = parent(a) + if is_zero(b) + return a, one(R), zero(R), zero(R), one(R) + end + if is_zero(a) + return b, zero(R), one(R), -one(R), zero(R) + end + + if valuation(data(a)) > valuation(data(b)) + return b, zero(R), one(R), -one(R), divexact(a, b) + end + return a, one(R), zero(R), -divexact(b, a), one(R) +end + +function annihilator(a::LocalFieldValuationRingResidueRingElem) + if is_zero(a) + return one(parent(a)) + end + pi = uniformizer(_valuation_ring(parent(a))) + return parent(a)(pi)^(_exponent(parent(a)) - valuation(data(a))) +end + +################################################################################ +# +# Inverse +# +################################################################################ + +function inv(a::LocalFieldValuationRingResidueRingElem) + @req is_unit(a) "Element is not invertible" + return parent(a)(inv(data(a)), copy = false, check = false) +end + +################################################################################ +# +# Unsafe operations +# +################################################################################ + +function zero!(a::LocalFieldValuationRingResidueRingElem) + a.a = zero!(data(a)) + return a +end + +function mul!(c::LocalFieldValuationRingResidueRingElem, a::LocalFieldValuationRingResidueRingElem, b::LocalFieldValuationRingResidueRingElem) + @req parent(a) === parent(b) === parent(c) "Parents do not match" + c.a = mul!(data(c), data(a), data(b)) + return c +end + +function add!(c::LocalFieldValuationRingResidueRingElem, a::LocalFieldValuationRingResidueRingElem, b::LocalFieldValuationRingResidueRingElem) + @req parent(a) === parent(b) === parent(c) "Parents do not match" + c.a = add!(data(c), data(a), data(b)) + return c +end + +function addeq!(a::LocalFieldValuationRingResidueRingElem, b::LocalFieldValuationRingResidueRingElem) + @req parent(a) === parent(b) "Parents do not match" + a.a = addeq!(data(a), data(b)) + return a +end + +################################################################################ +# +# Promotion +# +################################################################################ + +AbstractAlgebra.promote_rule(::Type{LocalFieldValuationRingResidueRingElem{S, T}}, ::Type{LocalFieldValuationRingResidueRingElem{S, T}}) where {S, T} = LocalFieldValuationRingResidueRingElem{S, T} + +function AbstractAlgebra.promote_rule(::Type{LocalFieldValuationRingResidueRingElem{S, T}}, ::Type{U}) where {S, T, U <: RingElement} + AbstractAlgebra.promote_rule(T, U) == T ? LocalFieldValuationRingResidueRingElem{S, T} : Union{} +end + +################################################################################ +# +# Construction +# +################################################################################ + +function residue_ring(R::LocalFieldValuationRing, a::LocalFieldValuationRingElem) + @req parent(a) === R "Rings do not match" + k = Int(valuation(a)) + S = LocalFieldValuationRingResidueRing(R, k) + return S, Generic.EuclideanRingResidueMap(R, S) +end diff --git a/src/LocalField/Ring.jl b/src/LocalField/Ring.jl index 0be4dcf9f9..2b8a2065e0 100644 --- a/src/LocalField/Ring.jl +++ b/src/LocalField/Ring.jl @@ -6,69 +6,53 @@ ################################################################################ # CHECK precision!!! -mutable struct QadicRing{S, T} <: Generic.Ring - Q::S #The corresponding local field - basis::Vector{T} #The OK-basis of the ring, where OK is - #the maximal order of the base field of Q - function QadicRing{S, T}(x::S) where {S <: Union{LocalField, QadicField, PadicField}, T} - z = new{S, T}() - z.Q = x - return z - end - -end - -function Base.show(io::IO, Q::QadicRing) - println("Integers of ", Q.Q) +function Base.show(io::IO, Q::LocalFieldValuationRing) + print("Integers of ", Q.Q) end function MaximalOrder(Q::QadicField) - return QadicRing{QadicField, QadicFieldElem}(Q) + return LocalFieldValuationRing{QadicField, QadicFieldElem}(Q) end function MaximalOrder(Q::PadicField) - return QadicRing{PadicField, PadicFieldElem}(Q) + return LocalFieldValuationRing{PadicField, PadicFieldElem}(Q) end #integers(Q::QadicField) = ring_of_integers(Q) function MaximalOrder(Q::LocalField{S, T}) where {S, T <: Union{EisensteinLocalField, UnramifiedLocalField}} - return QadicRing{LocalField{S, T}, LocalFieldElem{S, T}}(Q) + return LocalFieldValuationRing{LocalField{S, T}, LocalFieldElem{S, T}}(Q) end #integers(Q::PadicField) = ring_of_integers(Q) -mutable struct QadicRingElem{S, T} <: RingElem - P::QadicRing{S, T} - x::T - function QadicRingElem(P::QadicRing{S, T}, a::T) where {S, T} - r = new{S, T}(P, a) - end -end +valuation_ring(K::NonArchLocalField) = MaximalOrder(K) + +uniformizer(R::LocalFieldValuationRing) = R(uniformizer(R.Q)) -function Base.show(io::IO, a::QadicRingElem) +function Base.show(io::IO, a::LocalFieldValuationRingElem) print(io, a.x) end -*(a::QadicRingElem, b::QadicRingElem) = QadicRingElem(a.P, a.x*b.x) -+(a::QadicRingElem, b::QadicRingElem) = QadicRingElem(a.P, a.x+b.x) --(a::QadicRingElem, b::QadicRingElem) = QadicRingElem(a.P, a.x-b.x) --(a::QadicRingElem) = QadicRingElem(a.P, -a.x) -^(a::QadicRingElem, b::QadicRingElem) = QadicRingElem(a.P, a.x^b.x) -^(a::T, b::QadicRingElem{S, T}) where {S, T} = a^b.x +*(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem) = LocalFieldValuationRingElem(a.P, a.x*b.x) ++(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem) = LocalFieldValuationRingElem(a.P, a.x+b.x) +-(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem) = LocalFieldValuationRingElem(a.P, a.x-b.x) +-(a::LocalFieldValuationRingElem) = LocalFieldValuationRingElem(a.P, -a.x) +^(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem) = LocalFieldValuationRingElem(a.P, a.x^b.x) +^(a::T, b::LocalFieldValuationRingElem{S, T}) where {S, T} = a^b.x -function inv(a::QadicRingElem) +function inv(a::LocalFieldValuationRingElem) valuation(a.x) == 0 || error("The element is not invertible!") - return QadicRingElem(a.P, inv(a.x)) + return LocalFieldValuationRingElem(a.P, inv(a.x)) end -==(a::QadicRingElem, b::QadicRingElem) = a.x == b.x +==(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem) = a.x == b.x -function divexact(a::QadicRingElem, b::QadicRingElem; check::Bool=true) +function divexact(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem; check::Bool=true) @assert !iszero(b.x) iszero(a) && return a valuation(a.x) >= valuation(b.x) || error("division not exact") - return QadicRingElem(a.P, a.x//b.x) + return LocalFieldValuationRingElem(a.P, a.x//b.x) end -function Base.divrem(a::QadicRingElem, b::QadicRingElem) +function Base.divrem(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem) if valuation(a.x) < valuation(b.x) return setprecision(a.P(0), precision(a)), a end @@ -76,7 +60,7 @@ function Base.divrem(a::QadicRingElem, b::QadicRingElem) return q, a-q*b end -function Base.div(a::QadicRingElem, b::QadicRingElem) +function Base.div(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem) if valuation(a.x) < valuation(b.x) return setprecision(a.P(0), precision(a)) end @@ -84,40 +68,51 @@ function Base.div(a::QadicRingElem, b::QadicRingElem) return q end -parent(a::QadicRingElem) = a.P -elem_type(::Type{QadicRing{S, T}}) where {S, T} = QadicRingElem{S, T} -parent_type(::Type{QadicRingElem{S, T}}) where {S, T} = QadicRing{S, T} +parent(a::LocalFieldValuationRingElem) = a.P +elem_type(::Type{LocalFieldValuationRing{S, T}}) where {S, T} = LocalFieldValuationRingElem{S, T} +parent_type(::Type{LocalFieldValuationRingElem{S, T}}) where {S, T} = LocalFieldValuationRing{S, T} -zero(Q::QadicRing) = QadicRingElem(Q, Q.Q(0)) -one(Q::QadicRing) = QadicRingElem(Q, Q.Q(1)) +function zero(Q::LocalFieldValuationRing; precision::Int=precision(Q)) + return LocalFieldValuationRingElem(Q, zero(Q.Q, precision = precision)) +end -function (Q::QadicRing{S, T})(a::T) where {S, T} +function one(Q::LocalFieldValuationRing; precision::Int=precision(Q)) + return LocalFieldValuationRingElem(Q, one(Q.Q, precision = precision)) +end + +function (Q::LocalFieldValuationRing{S, T})(a::T) where {S, T} @assert parent(a) === Q.Q - QadicRingElem(Q, a) + LocalFieldValuationRingElem(Q, a) +end +(Q::LocalFieldValuationRing)(a::LocalFieldValuationRingElem) = LocalFieldValuationRingElem(a.P, a.x) + +function (Q::LocalFieldValuationRing)(a::Integer; precision::Int=precision(Q)) + return LocalFieldValuationRingElem(Q, Q.Q(a, precision = precision)) +end + +function (Q::LocalFieldValuationRing)(a::ZZRingElem; precision::Int=precision(Q)) + return LocalFieldValuationRingElem(Q, Q.Q(a, precision = precision)) end -(Q::QadicRing)(a::QadicRingElem) = QadicRingElem(a.P, a.x) -(Q::QadicRing)(a::Integer) = QadicRingElem(Q, Q.Q(a)) -(Q::QadicRing)(a::ZZRingElem) = QadicRingElem(Q, Q.Q(a)) -function (Q::QadicRing)(a::QQFieldElem) +function (Q::LocalFieldValuationRing)(a::QQFieldElem; precision::Int=precision(Q)) p = prime(Q.Q) if iszero(mod(denominator(a), p)) error("The element is not in the ring!") end - return QadicRingElem(Q, Q.Q(a)) + return LocalFieldValuationRingElem(Q, Q.Q(a, precision = precision)) end -(Q::QadicRing)() = QadicRingElem(Q, Q.Q()) +(Q::LocalFieldValuationRing)() = LocalFieldValuationRingElem(Q, Q.Q()) -function (Q::Union{PadicField, QadicField, LocalField})(a::QadicRingElem) +function (Q::Union{PadicField, QadicField, LocalField})(a::LocalFieldValuationRingElem) if parent(a).Q !== Q error("Parent mismatch") end return a.x end -valuation(a::QadicRingElem) = valuation(a.x) -is_unit(a::QadicRingElem) = !iszero(a) && valuation(a) == 0 +valuation(a::LocalFieldValuationRingElem) = valuation(a.x) +is_unit(a::LocalFieldValuationRingElem) = !iszero(a) && valuation(a) == 0 (Q::QadicField)(a::PadicFieldElem) = _map(Q, a) #TODO: do properly function _map(Q::QadicField, a::PadicFieldElem) @@ -135,17 +130,17 @@ function _map(Q::QadicField, a::PadicFieldElem) end end -function Base.deepcopy_internal(a::QadicRingElem, dict::IdDict) - return QadicRingElem(a.P, a.x) +function Base.deepcopy_internal(a::LocalFieldValuationRingElem, dict::IdDict) + return LocalFieldValuationRingElem(a.P, a.x) end -function canonical_unit(a::QadicRingElem) +function canonical_unit(a::LocalFieldValuationRingElem) iszero(a.x) && return setprecision(a.P(1), precision(a)) v = valuation(a.x) - return QadicRingElem(a.P, inv(a.x//prime(a.P.Q)^v)) + return LocalFieldValuationRingElem(a.P, inv(a.x//prime(a.P.Q)^v)) end -function gcdx(a::QadicRingElem, b::QadicRingElem) +function gcdx(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem) if iszero(a) c = canonical_unit(b) return b*c, a, c @@ -163,55 +158,61 @@ function gcdx(a::QadicRingElem, b::QadicRingElem) end end -function mul_red!(a::QadicRingElem, b::QadicRingElem, c::QadicRingElem, f::Bool = false) +function mul_red!(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem, c::LocalFieldValuationRingElem, f::Bool = false) return b*c end -function mul!(a::QadicRingElem, b::QadicRingElem, c::QadicRingElem) +function mul!(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem, c::LocalFieldValuationRingElem) return b*c end -function add!(a::QadicRingElem, b::QadicRingElem, c::QadicRingElem) +function add!(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem, c::LocalFieldValuationRingElem) return b+c end -function addeq!(a::QadicRingElem, b::QadicRingElem) +function addeq!(a::LocalFieldValuationRingElem, b::LocalFieldValuationRingElem) return a+b end -Base.iszero(a::QadicRingElem) = iszero(a.x) -Base.isone(a::QadicRingElem) = isone(a.x) +Base.iszero(a::LocalFieldValuationRingElem) = iszero(a.x) +Base.isone(a::LocalFieldValuationRingElem) = isone(a.x) -Base.precision(Q::QadicRing) = precision(Q.Q) -Base.precision(a::QadicRingElem) = precision(a.x) +Base.precision(Q::LocalFieldValuationRing) = precision(Q.Q) +Base.precision(a::LocalFieldValuationRingElem) = precision(a.x) -function setprecision!(Q::QadicRing, n::Int) +function setprecision!(Q::LocalFieldValuationRing, n::Int) setprecision!(Q.Q, n) end -function Base.setprecision(a::QadicRingElem, n::Int) +function Base.setprecision(a::LocalFieldValuationRingElem, n::Int) return a.P(setprecision(a.x, n)) end -function setprecision!(a::QadicRingElem, n::Int) +function setprecision!(a::LocalFieldValuationRingElem, n::Int) a.x = setprecision!(a.x, n) end -function Base.setprecision(a::Generic.MatSpaceElem{QadicRingElem{QadicFieldElem}}, n::Int) +function Base.setprecision(a::Generic.MatSpaceElem{LocalFieldValuationRingElem{QadicFieldElem}}, n::Int) return map_entries(x -> setprecision(x, n), a) end -coefficient_ring(Q::QadicRing) = ring_of_integers(coefficient_ring(Q.Q)) +coefficient_ring(Q::LocalFieldValuationRing) = ring_of_integers(coefficient_ring(Q.Q)) coefficient_ring(K::LocalField) = base_field(K) -function absolute_coordinates(a::QadicRingElem) +function absolute_coordinates(a::LocalFieldValuationRingElem) v = absolute_coordinates(a.x) Zp = ring_of_integers(prime_field(parent(a.x))) return Zp.(v) end -function absolute_coordinates(Zp::QadicRing, a::QadicRingElem) +function absolute_coordinates(Zp::LocalFieldValuationRing, a::LocalFieldValuationRingElem) v = absolute_coordinates(Zp.Q, a.x) return Zp.(v) end + +AbstractAlgebra.promote_rule(::Type{LocalFieldValuationRingElem{S, T}}, ::Type{LocalFieldValuationRingElem{S, T}}) where {S, T} = LocalFieldValuationRingElem{S, T} + +function AbstractAlgebra.promote_rule(::Type{LocalFieldValuationRingElem{S, T}}, ::Type{U}) where {S, T, U <: RingElement} + AbstractAlgebra.promote_rule(T, U) == T ? LocalFieldValuationRingElem{S, T} : Union{} +end diff --git a/src/LocalField/Types.jl b/src/LocalField/Types.jl index 046d7607f8..4d77840088 100644 --- a/src/LocalField/Types.jl +++ b/src/LocalField/Types.jl @@ -1,3 +1,9 @@ +################################################################################ +# +# LocalField +# +################################################################################ + abstract type LocalFieldParameter end abstract type EisensteinLocalField <: LocalFieldParameter end abstract type UnramifiedLocalField <: LocalFieldParameter end @@ -33,6 +39,12 @@ mutable struct LocalFieldElem{S, T} <: NonArchLocalFieldElem precision::Int end +################################################################################ +# +# CompletionMap +# +################################################################################ + mutable struct CompletionMap{S, T} <: Map{AbsSimpleNumField, S, HeckeMap, CompletionMap{S, T}} header::MapHeader{AbsSimpleNumField, S} P::AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem} @@ -74,3 +86,55 @@ mutable struct CompletionMap{S, T} <: Map{AbsSimpleNumField, S, HeckeMap, Comple return z end end + +################################################################################ +# +# Valuation ring +# +################################################################################ + +mutable struct LocalFieldValuationRing{S, T} <: Generic.Ring + Q::S #The corresponding local field + basis::Vector{T} #The OK-basis of the ring, where OK is + #the maximal order of the base field of Q + function LocalFieldValuationRing{S, T}(x::S) where {S <: Union{LocalField, QadicField, PadicField}, T} + z = new{S, T}() + z.Q = x + return z + end + +end + +mutable struct LocalFieldValuationRingElem{S, T} <: RingElem + P::LocalFieldValuationRing{S, T} + x::T + function LocalFieldValuationRingElem(P::LocalFieldValuationRing{S, T}, a::T) where {S, T} + r = new{S, T}(P, a) + end +end + +################################################################################ +# +# Residue ring +# +################################################################################ + +# Type for O/m^k where O is the valuation ring of the field F and m the maximal +# ideal +@attributes mutable struct LocalFieldValuationRingResidueRing{S <: NonArchLocalField, T <: NonArchLocalFieldElem} <: Ring + R::LocalFieldValuationRing{S, T} + k::Int + + function LocalFieldValuationRingResidueRing(R::LocalFieldValuationRing{S, T}, k::Int) where {S, T} + return new{S, T}(R, k) + end +end + +mutable struct LocalFieldValuationRingResidueRingElem{S <: NonArchLocalField, T <: NonArchLocalFieldElem} <: RingElem + a::T + parent::LocalFieldValuationRingResidueRing{S, T} + + function LocalFieldValuationRingResidueRingElem(a::T, R::LocalFieldValuationRingResidueRing{S, T}) where {S, T} + return new{S, T}(a, R) + end +end diff --git a/src/LocalField/neq.jl b/src/LocalField/neq.jl index 16af1bc8f0..266c1fb253 100644 --- a/src/LocalField/neq.jl +++ b/src/LocalField/neq.jl @@ -214,9 +214,9 @@ function coordinates(a::Union{QadicFieldElem, LocalFieldElem}, k) return c end coordinates(a::PadicFieldElem, ::PadicField) = [a] -lift(a::Hecke.QadicRingElem{PadicField, PadicFieldElem}) = lift(a.x) +lift(a::Hecke.LocalFieldValuationRingElem{PadicField, PadicFieldElem}) = lift(a.x) -function setprecision!(A::Generic.MatSpaceElem{Hecke.QadicRingElem{PadicField, PadicFieldElem}}, n::Int) +function setprecision!(A::Generic.MatSpaceElem{Hecke.LocalFieldValuationRingElem{PadicField, PadicFieldElem}}, n::Int) for i=1:nrows(A) for j=1:ncols(A) setprecision!(A[i,j], n) @@ -1147,7 +1147,7 @@ function unit_group(K::LocalField) end #= -function unit_group(R::QadicRing) +function unit_group(R::LocalFieldValuationRing) K = R.Q U, mU = one_unit_group(K) k, mk = residue_field(K) diff --git a/src/NumFieldOrd/NfOrd/ResidueRing.jl b/src/NumFieldOrd/NfOrd/ResidueRing.jl index fd89a92f39..df5395aca2 100644 --- a/src/NumFieldOrd/NfOrd/ResidueRing.jl +++ b/src/NumFieldOrd/NfOrd/ResidueRing.jl @@ -464,6 +464,8 @@ function is_divisible2(x::AbsOrdQuoRingElem, y::AbsOrdQuoRingElem) return true, z end +divides(x::AbsOrdQuoRingElem, y::AbsOrdQuoRingElem) = is_divisible(x, y) + function is_divisible(x::AbsOrdQuoRingElem, y::AbsOrdQuoRingElem) check_parent(x, y) diff --git a/src/NumFieldOrd/NfOrd/StrongEchelonForm.jl b/src/NumFieldOrd/NfOrd/StrongEchelonForm.jl index eae1d140ab..32946032c1 100644 --- a/src/NumFieldOrd/NfOrd/StrongEchelonForm.jl +++ b/src/NumFieldOrd/NfOrd/StrongEchelonForm.jl @@ -57,7 +57,7 @@ function strong_echelon_form(A::Generic.Mat{AbsSimpleNumFieldOrderQuoRingElem}, end end -function triangularize!(A::Generic.Mat{AbsSimpleNumFieldOrderQuoRingElem}) +function triangularize!(A::Generic.Mat{T}) where {T <: Union{AbsSimpleNumFieldOrderQuoRingElem, LocalFieldValuationRingResidueRingElem}} n = nrows(A) m = ncols(A) d = one(base_ring(A)) @@ -82,7 +82,7 @@ function triangularize!(A::Generic.Mat{AbsSimpleNumFieldOrderQuoRingElem}) continue end - t_isdiv += @elapsed b, q = is_divisible(A[i, col], A[row, col]) + t_isdiv += @elapsed b, q = divides(A[i, col], A[row, col]) if b for k in col:m @@ -112,7 +112,7 @@ function triangularize!(A::Generic.Mat{AbsSimpleNumFieldOrderQuoRingElem}) return d end -function triangularize(A::Generic.Mat{AbsSimpleNumFieldOrderQuoRingElem}) +function triangularize(A::Generic.Mat{T}) where {T <: Union{AbsSimpleNumFieldOrderQuoRingElem, LocalFieldValuationRingResidueRingElem}} #println("copying ...") B = deepcopy(A) #println("done") @@ -128,7 +128,7 @@ end # Naive version of inplace strong echelon form # It is assumed that A has more rows then columns. -function strong_echelon_form_naive!(A::Generic.Mat{AbsSimpleNumFieldOrderQuoRingElem}) +function strong_echelon_form_naive!(A::Generic.Mat{S}) where {S <: Union{AbsSimpleNumFieldOrderQuoRingElem, LocalFieldValuationRingResidueRingElem}} #A = deepcopy(B) n = nrows(A) m = ncols(A) @@ -177,7 +177,7 @@ function strong_echelon_form_naive!(A::Generic.Mat{AbsSimpleNumFieldOrderQuoRing T[1, k], A[i, k] = A[i, k], T[1, k] end else - b, q = is_divisible(T[1, i], A[i, i]) + b, q = divides(T[1, i], A[i, i]) if b for k in i:m T[1, k] = T[1, k] - q*A[i, k] @@ -204,7 +204,7 @@ end # ################################################################################ -function howell_form!(A::Generic.Mat{AbsSimpleNumFieldOrderQuoRingElem}) +function howell_form!(A::Generic.Mat{T}) where {T <: Union{AbsSimpleNumFieldOrderQuoRingElem, LocalFieldValuationRingResidueRingElem}} @assert nrows(A) >= ncols(A) k = nrows(A) @@ -227,7 +227,7 @@ function howell_form!(A::Generic.Mat{AbsSimpleNumFieldOrderQuoRingElem}) return k end -function howell_form(A::Generic.Mat{AbsSimpleNumFieldOrderQuoRingElem}) +function howell_form(A::Generic.Mat{T}) where {T <: Union{AbsSimpleNumFieldOrderQuoRingElem, LocalFieldValuationRingResidueRingElem}} B = deepcopy(A) if nrows(B) < ncols(B) diff --git a/src/exports.jl b/src/exports.jl index 6369f73c53..b4434d4bdf 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -911,6 +911,7 @@ export unit_group export unit_group_fac_elem export unramified_extension export valuation +export valuation_ring export value_module export value_module_quadratic_form export vcat diff --git a/test/LocalField.jl b/test/LocalField.jl index 2de9830a20..13fca1e978 100644 --- a/test/LocalField.jl +++ b/test/LocalField.jl @@ -4,4 +4,5 @@ include("LocalField/LocalField.jl") include("LocalField/neq.jl") include("LocalField/Completions.jl") + include("LocalField/ResidueRing.jl") end diff --git a/test/LocalField/ResidueRing.jl b/test/LocalField/ResidueRing.jl new file mode 100644 index 0000000000..e9bc40cdf8 --- /dev/null +++ b/test/LocalField/ResidueRing.jl @@ -0,0 +1,67 @@ +function _test_elem(R::PadicField) + p = prime(R) + prec = rand(1:R.prec_max) + r = ZZRingElem(0):p-1 + return R(sum(rand(r)*p^i for i in 0:prec)) +end + +function _test_elem(R::NonArchLocalField) + d = degree(R) + a = gen(R) + x = R() + for i in 0:d - 1 + if rand() < 0.5 + # Only fill every second coefficient + continue + end + x += _test_elem(base_field(R))*a^i + end + return x +end + +function test_elem(R::Hecke.LocalFieldValuationRingResidueRing) + return R(_test_elem(Hecke._field(R))) +end + +@testset "Conformance tests" begin + # PadicField + K = padic_field(17) + R = valuation_ring(K) + pi = uniformizer(R) + S, RtoS = residue_ring(R, pi^3) + test_Ring_interface(S) + + # the euclidean conformance test seems to assume that the ring is a domain + S, RtoS = residue_ring(R, pi) + test_EuclideanRing_interface(S) + + # QadicField + K, a = qadic_field(17, 2) + R = valuation_ring(K) + pi = uniformizer(R) + S, RtoS = residue_ring(R, pi^3) + test_Ring_interface(S) + + # LocalField + F, _ = cyclotomic_field(3) + OF = maximal_order(F); + K, toK = completion(F, 2*OF); + R = valuation_ring(K) + pi = uniformizer(R) + S, RtoS = residue_ring(R, pi^3) + test_Ring_interface(S) +end + + +@testset "Howell form" begin + K = padic_field(5) + R = valuation_ring(K) + pi = uniformizer(R) + S, RtoS = residue_ring(R, pi^3) + + M = matrix(S, [5 1; 0 0]) + @test howell_form(M) == matrix(S, [5 1; 0 5^2]) + + M = matrix(S, [10 1; 12 0]) + @test howell_form(M) == matrix(S, [12 0; 0 -1]) +end