From d607b883f003a6004b1729f2d7f37953a4460572 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Tue, 27 Aug 2024 12:24:45 +0200 Subject: [PATCH] Clean up `src/NemoStuff.jl` (#1769) * Clean up `src/NemoStuff.jl` * Some tests * Don't deprecate `zero_matrix(MatElem, ...)` and `identity_matrix(MatElem, ...)` --- src/AbsSeries.jl | 8 + src/AbstractAlgebra.jl | 4 +- src/Deprecations.jl | 3 + src/MPoly.jl | 49 +++ src/Map.jl | 2 + src/Matrix.jl | 72 ++++ src/NCRings.jl | 2 + src/NemoStuff.jl | 438 --------------------- src/NumFields.jl | 28 ++ src/Poly.jl | 6 + src/RelSeries.jl | 34 ++ src/Rings.jl | 2 - src/generic/MPoly.jl | 2 + src/generic/Misc/Localization.jl | 1 + src/generic/Poly.jl | 2 + src/generic/RationalFunctionField.jl | 15 + src/generic/Residue.jl | 44 +++ src/julia/Float.jl | 4 + src/julia/GF.jl | 18 +- src/julia/Integer.jl | 6 + src/julia/Rational.jl | 34 ++ test/generic/AbsSeries-test.jl | 9 + test/generic/FreeAssAlgebra-test.jl | 6 + test/generic/MPoly-test.jl | 9 + test/generic/Matrix-test.jl | 22 ++ test/generic/ModuleHomomorphism-test.jl | 4 + test/generic/Poly-test.jl | 1 + test/generic/RationalFunctionField-test.jl | 6 + test/generic/RelSeries-test.jl | 11 + test/generic/Residue-test.jl | 8 + test/julia/Floats-test.jl | 5 + test/julia/Rationals-test.jl | 35 ++ 32 files changed, 445 insertions(+), 445 deletions(-) delete mode 100644 src/NemoStuff.jl create mode 100644 src/NumFields.jl diff --git a/src/AbsSeries.jl b/src/AbsSeries.jl index 40fce09cc8..0f750ed24f 100644 --- a/src/AbsSeries.jl +++ b/src/AbsSeries.jl @@ -81,6 +81,14 @@ function Base.hash(a::AbsPowerSeriesRingElem, h::UInt) return b end +function lift(R::PolyRing{T}, s::AbsPowerSeriesRingElem{T}) where {T} + t = R() + for x = 0:pol_length(s) + setcoeff!(t, x, polcoeff(s, x)) + end + return t +end + ############################################################################### # # Similar and zero diff --git a/src/AbstractAlgebra.jl b/src/AbstractAlgebra.jl index aee0d26af7..ff581edb16 100644 --- a/src/AbstractAlgebra.jl +++ b/src/AbstractAlgebra.jl @@ -286,11 +286,11 @@ using .Solve ################################################################################ # -# Stuff moved from Nemo (to be cleaned up eventually) +# Number fields (some stuff moved from Nemo) # ################################################################################ -include("NemoStuff.jl") +include("NumFields.jl") ################################################################################ # diff --git a/src/Deprecations.jl b/src/Deprecations.jl index 971bb858f7..fdca2f3b84 100644 --- a/src/Deprecations.jl +++ b/src/Deprecations.jl @@ -54,3 +54,6 @@ import .Generic: exponent; @deprecate exponent(a::Generic.MPoly{T}, i::Int, j::I import .Generic: set_exponent_vector!; @deprecate set_exponent_vector!(a::Generic.MPoly{T}, i::Int, exps::Vector{Int}, ::Type{Val{ord}}) where {T <: RingElement, ord} set_exponent_vector!(a, i, exps, Val(ord)) import .Generic: is_gen; @deprecate is_gen(x::Generic.MPoly{T}, ::Type{Val{ord}}) where {T <: RingElement, ord} is_gen(x, Val(ord)) import .Generic: degree; @deprecate degree(f::Generic.MPoly{T}, i::Int, ::Type{Val{ord}}) where {T <: RingElement, ord} degree(f, i, Val(ord)) + +# deprecated during 0.42.* +@deprecate change_base_ring(p::MPolyRingElem{T}, g, new_polynomial_ring) where {T<:RingElement} map_coefficients(g, p, parent = new_polynomial_ring) diff --git a/src/MPoly.jl b/src/MPoly.jl index d9b27d88cb..b580e48c7a 100644 --- a/src/MPoly.jl +++ b/src/MPoly.jl @@ -1209,6 +1209,55 @@ function coefficients_of_univariate(p::MPolyRingElem, return coeffs end +############################################################################### +# +# As univariate polynomials +# +############################################################################### + +@doc raw""" + coefficients(f::MPolyRingElem, i::Int) + +Return the coefficients of `f` when viewed as a univariate polynomial in the `i`-th +variable. +""" +function coefficients(f::MPolyRingElem, i::Int) + d = degree(f, i) + cf = [MPolyBuildCtx(parent(f)) for j = 0:d] + for (c, e) = zip(coefficients(f), exponent_vectors(f)) + a = e[i] + e[i] = 0 + push_term!(cf[a+1], c, e) + end + return map(finish, cf) +end + +#check with Nemo/ Dan if there are better solutions +#the block is also not used here I think +#functionality to view mpoly as upoly in variable `i`, so the +#coefficients are mpoly's without variable `i`. +function leading_coefficient(f::MPolyRingElem, i::Int) + g = MPolyBuildCtx(parent(f)) + d = degree(f, i) + for (c, e) = zip(coefficients(f), exponent_vectors(f)) + if e[i] == d + e[i] = 0 + push_term!(g, c, e) + end + end + return finish(g) +end + +@doc raw""" + content(f::MPolyRingElem, i::Int) + +Return the content of `f` as a polynomial in the variable `i`, i.e. the gcd of +all the coefficients when viewed as univariate polynomial in `i`. +""" +function content(f::MPolyRingElem, i::Int) + return reduce(gcd, coefficients(f, i)) +end + ################################################################################ # # Change base ring diff --git a/src/Map.jl b/src/Map.jl index 67ae52c509..2f65133eda 100644 --- a/src/Map.jl +++ b/src/Map.jl @@ -55,6 +55,8 @@ end Base.broadcastable(M::Map) = Ref(M) +Base.:\(f::Map, x) = preimage(f, x) + ############################################################################### # # CompositeMap diff --git a/src/Matrix.jl b/src/Matrix.jl index 61ccc981a0..3ffbb8c4e4 100644 --- a/src/Matrix.jl +++ b/src/Matrix.jl @@ -426,6 +426,8 @@ function _to_indices(x, rows, cols) (rows, cols) end +sub(M::MatElem, r::AbstractVector{<:Integer}, c::AbstractVector{<:Integer}) = M[r, c] + function Base.view(M::MatElem, rows::Union{Int,Colon,AbstractVector{Int}}, cols::Union{Int,Colon,AbstractVector{Int}}) @@ -790,6 +792,52 @@ function *(x::MatElem{T}, y::MatElem{T}) where {T <: NCRingElement} return A end +function add!(c::MatrixElem{T}, a::MatrixElem{T}, b::MatrixElem{T}) where T <: NCRingElement + check_parent(a, b) + check_parent(a, c) + for i = 1:nrows(c) + for j = 1:ncols(c) + c[i, j] = add!(c[i, j], a[i, j], b[i, j]) + end + end + return c +end + +function mul!(c::MatElem{T}, a::MatElem{T}, b::MatElem{T}) where T <: NCRingElement + @assert base_ring(a) === base_ring(b) && base_ring(a) === base_ring(c) + ncols(a) != nrows(b) && error("Incompatible matrix dimensions") + nrows(c) != nrows(a) && error("Incompatible matrix dimensions") + ncols(c) != ncols(b) && error("Incompatible matrix dimensions") + + if c === a || c === b + d = parent(a)() + return mul!(d, a, b) + end + + t = base_ring(a)() + for i = 1:nrows(a) + for j = 1:ncols(b) + c[i, j] = zero!(c[i, j]) + for k = 1:ncols(a) + c[i, j] = addmul_delayed_reduction!(c[i, j], a[i, k], b[k, j], t) + end + c[i, j] = reduce!(c[i, j]) + end + end + return c +end + +function sub!(c::MatrixElem{T}, a::MatrixElem{T}, b::MatrixElem{T}) where T <: NCRingElement + check_parent(a, b) + check_parent(a, c) + for i = 1:nrows(c) + for j = 1:ncols(c) + c[i, j] = sub!(c[i, j], a[i, j], b[i, j]) + end + end + return c +end + ############################################################################### # # Ad hoc binary operators @@ -1013,6 +1061,25 @@ function *(x::Vector{T}, y::MatrixElem{T}) where T <: NCRingElement return mul!(T[base_ring(y)() for j in 1:ncols(y)], x, y) end +function mul!(c::MatrixElem{T}, a::MatrixElem{T}, b::T) where T <: NCRingElement + @assert base_ring(a) === parent(b) && base_ring(a) === base_ring(c) + nrows(c) != nrows(a) && error("Incompatible matrix dimensions") + ncols(c) != ncols(a) && error("Incompatible matrix dimensions") + + if c === a + d = parent(a)() + return mul!(d, a, b) + end + + t = base_ring(a)() + for i = 1:nrows(a) + for j = 1:ncols(a) + c[i, j] = mul!(c[i, j], a[i, j], b) + end + end + return c +end + ################################################################################ # # Promotion @@ -1373,6 +1440,7 @@ julia> B = transpose(A) """ transpose(x::MatrixElem{T}) where T <: NCRingElement +transpose!(A::MatrixElem) = transpose(A) ############################################################################### # @@ -6506,6 +6574,8 @@ function zero_matrix(R::NCRing, r::Int, c::Int) return z end +zero_matrix(::Type{MatElem}, R::Ring, n::Int, m::Int) = zero_matrix(R, n, m) + ################################################################################ # # Ones matrix @@ -6560,6 +6630,8 @@ function identity_matrix(M::MatElem{T}, n::Int) where T <: NCRingElement z end +identity_matrix(::Type{MatElem}, R::Ring, n::Int) = identity_matrix(R, n) + ################################################################################ # # Scalar matrix diff --git a/src/NCRings.jl b/src/NCRings.jl index 9558b21a3e..c41d6d08e4 100644 --- a/src/NCRings.jl +++ b/src/NCRings.jl @@ -152,6 +152,8 @@ function addmul!(z::T, x::T, y::T, c::T) where T <: NCRingElem return z end +addmul!(z::T, x::T, y::T) where T <: NCRingElem = addmul!(z, x, y, parent(z)()) + ############################################################################### # # Basic manipulation diff --git a/src/NemoStuff.jl b/src/NemoStuff.jl deleted file mode 100644 index 5a081d81ac..0000000000 --- a/src/NemoStuff.jl +++ /dev/null @@ -1,438 +0,0 @@ -function neg!(w::Vector{Int}) - w .*= -1 -end - -sub!(z::T, x::T, y::T) where {T} = x - y - -sub!(z::Rational{Int}, x::Rational{Int}, y::Int) = x - y - -neg!(z::Rational{Int}, x::Rational{Int}) = -x - -add!(z::Rational{Int}, x::Rational{Int}, y::Int) = x + y - -mul!(z::Rational{Int}, x::Rational{Int}, y::Int) = x * y - -is_negative(n::T) where T<:Real = n < zero(T) -is_positive(n::T) where T<:Real = n > zero(T) - -# TODO (CF): -# should be Bernstein'ed: this is slow for large valuations -# returns the maximal v s.th. z mod p^v == 0 and z div p^v -# also useful if p is not prime.... -# -# TODO: what happens to z = 0??? - -function remove(z::Rational{T}, p::T) where {T<:Integer} - z == 0 && return (0, z) - v, d = remove(denominator(z), p) - w, n = remove(numerator(z), p) - return w - v, n // d -end - -function valuation(z::Rational{T}, p::T) where {T<:Integer} - z == 0 && error("Not yet implemented") - v = valuation(denominator(z), p) - w = valuation(numerator(z), p) - return w - v -end - -base_ring(::Vector{Int}) = Int - -################################################################################ -# -# Zero matrix constructors -# -################################################################################ - -function zero_matrix(::Type{MatElem}, R::Ring, n::Int, m::Int) - return zero_matrix(R, n, m) -end - -function identity_matrix(::Type{MatElem}, R::Ring, n::Int) - return identity_matrix(R, n) -end - -################################################################################ -# -# Unsafe functions for generic matrices -# -################################################################################ - -#function zero!(a::MatElem) -# for i in 1:nrows(a) -# for j in 1:ncols(a) -# a[i, j] = zero!(a[i, j]) -# end -# end -# return a -#end - -function mul!(c::MatElem, a::MatElem, b::MatElem) - ncols(a) != nrows(b) && error("Incompatible matrix dimensions") - nrows(c) != nrows(a) && error("Incompatible matrix dimensions") - ncols(c) != ncols(b) && error("Incompatible matrix dimensions") - - if c === a || c === b - d = parent(a)() - return mul!(d, a, b) - end - - t = base_ring(a)() - for i = 1:nrows(a) - for j = 1:ncols(b) - c[i, j] = zero!(c[i, j]) - for k = 1:ncols(a) - c[i, j] = addmul_delayed_reduction!(c[i, j], a[i, k], b[k, j], t) - end - c[i, j] = reduce!(c[i, j]) - end - end - return c -end - -function mul!(c::MatElem, a::MatElem, b::RingElement) - nrows(c) != nrows(a) && error("Incompatible matrix dimensions") - - if c === a || c === b - d = parent(a)() - return mul!(d, a, b) - end - - t = base_ring(a)() - for i = 1:nrows(a) - for j = 1:ncols(a) - c[i, j] = mul!(c[i, j], a[i, j], b) - end - end - return c -end - -function add!(c::MatElem, a::MatElem, b::MatElem) - parent(a) != parent(b) && error("Parents don't match.") - parent(c) != parent(b) && error("Parents don't match.") - for i = 1:nrows(c) - for j = 1:ncols(c) - c[i, j] = add!(c[i, j], a[i, j], b[i, j]) - end - end - return c -end - -function addmul!(z::T, x::T, y::T) where {T<:RingElement} - zz = parent(z)() - zz = mul!(zz, x, y) - return addeq!(z, zz) -end - -#TODO: should be done in Nemo/AbstractAlgebra s.w. -# needed by ^ (the generic power in Base using square and multiply) -Base.copy(f::Generic.MPoly) = deepcopy(f) -Base.copy(f::Generic.Poly) = deepcopy(f) -Base.copy(a::PolyRingElem) = deepcopy(a) -Base.copy(a::SeriesElem) = deepcopy(a) - -############################################################################### -# -# Sub -# -############################################################################### - -function sub(M::MatElem, rows::Vector{Int}, cols::Vector{Int}) - N = zero_matrix(base_ring(M), length(rows), length(cols)) - for i = 1:length(rows) - for j = 1:length(cols) - N[i, j] = M[rows[i], cols[j]] - end - end - return N -end - -function sub(M::MatElem{T}, r::AbstractUnitRange{<:Integer}, c::AbstractUnitRange{<:Integer}) where {T} - z = similar(M, length(r), length(c)) - for i in 1:length(r) - for j in 1:length(c) - z[i, j] = M[r[i], c[j]] - end - end - return z -end - -function sub(M::Generic.Mat, rows::AbstractUnitRange{Int}, cols::AbstractUnitRange{Int}) - @assert step(rows) == 1 && step(cols) == 1 - z = zero_matrix(base_ring(M), length(rows), length(cols)) - for i in rows - for j in cols - z[i-first(rows)+1, j-first(cols)+1] = M[i, j] - end - end - return z -end - -gens(L::SimpleNumField{T}) where {T} = [gen(L)] - -function gen(L::SimpleNumField{T}, i::Int) where {T} - i == 1 || error("index must be 1") - return gen(L) -end - -function Base.getindex(L::SimpleNumField{T}, i::Int) where {T} - if i == 0 - return one(L) - elseif i == 1 - return gen(L) - else - error("index has to be 0 or 1") - end -end - -number_of_generators(L::SimpleNumField{T}) where {T} = 1 - -is_unit(a::NumFieldElem) = !iszero(a) - -canonical_unit(a::NumFieldElem) = a - -""" -The coefficients of `f` when viewed as a univariate polynomial in the `i`-th -variable. -""" -function coefficients(f::MPolyRingElem, i::Int) - d = degree(f, i) - cf = [MPolyBuildCtx(parent(f)) for j = 0:d] - for (c, e) = zip(coefficients(f), exponent_vectors(f)) - a = e[i] - e[i] = 0 - push_term!(cf[a+1], c, e) - end - return map(finish, cf) -end - -function change_base_ring(p::MPolyRingElem{T}, g, new_polynomial_ring) where {T<:RingElement} - cvzip = zip(coefficients(p), exponent_vectors(p)) - M = MPolyBuildCtx(new_polynomial_ring) - for (c, v) in cvzip - res = g(c) - if !iszero(res) - push_term!(M, g(c), v) - end - end - return finish(M)::elem_type(new_polynomial_ring) -end - -#check with Nemo/ Dan if there are better solutions -#the block is also not used here I think -#functionality to view mpoly as upoly in variable `i`, so the -#coefficients are mpoly's without variable `i`. -function leading_coefficient(f::MPolyRingElem, i::Int) - g = MPolyBuildCtx(parent(f)) - d = degree(f, i) - for (c, e) = zip(coefficients(f), exponent_vectors(f)) - if e[i] == d - e[i] = 0 - push_term!(g, c, e) - end - end - return finish(g) -end - -""" -`content` as a polynomial in the variable `i`, i.e. the gcd of all the -coefficients when viewed as univariate polynomial in `i`. -""" -function content(f::MPolyRingElem, i::Int) - return reduce(gcd, coefficients(f, i)) -end - -function content(a::PolyRingElem{<:FieldElem}) - return one(base_ring(a)) -end - -function canonical_unit(a::SeriesElem) - iszero(a) && return one(parent(a)) - v = valuation(a) - v == 0 && return a - v > 0 && return shift_right(a, v) - return shift_left(a, -v) -end - -# should be Nemo/AA -# TODO: symbols vs strings -# lift(PolyRing, Series) -# lift(FracField, Series) -# (to be in line with lift(ZZ, PadicFieldElem) and lift(QQ, PadicFieldElem) -#TODO: some of this would only work for Abs, not Rel, however, this should be fine here -function map_coefficients(f::T, a::RelPowerSeriesRingElem; parent::SeriesRing) where T - c = typeof(f(coeff(a, 0)))[] - for i = 0:pol_length(a)-1 - push!(c, f(polcoeff(a, i))) - end - b = parent(c, length(c), precision(a), valuation(a)) - return b -end - -#= -function map_coefficients(f, a::RelPowerSeriesRingElem) - d = f(coeff(a, 0)) - T = parent(a) - if parent(d) == base_ring(T) - S = T - else - S = power_series_ring(parent(d), max_precision(T), string(var(T)), cached = false)[1] - end - c = typeof(d)[d] - for i=1:pol_length(a)-1 - push!(c, f(polcoeff(a, i))) - end - b = S(c, length(c), precision(a), valuation(a)) - return b -end -=# -function lift(R::PolyRing{S}, s::SeriesElem{S}) where {S} - t = R() - for x = 0:pol_length(s) - setcoeff!(t, x, polcoeff(s, x)) - end - return shift_left(t, valuation(s)) -end - -#TODO: this is for rings, not for fields, maybe different types? -function Base.gcd(a::T, b::T) where {T<:SeriesElem} - iszero(a) && iszero(b) && return a - iszero(a) && return gen(parent(a))^valuation(b) - iszero(b) && return gen(parent(a))^valuation(a) - return gen(parent(a))^min(valuation(a), valuation(b)) -end - -function Base.lcm(a::T, b::T) where {T<:SeriesElem} - iszero(a) && iszero(b) && return a - iszero(a) && return a - iszero(b) && return b - return gen(parent(a))^max(valuation(a), valuation(b)) -end - -function gen(R::Union{EuclideanRingResidueRing{T},EuclideanRingResidueField{T}}) where {T<:PolyRingElem} - return R(gen(base_ring(R))) -end - -function characteristic(R::Union{EuclideanRingResidueRing{T},EuclideanRingResidueField{T}}) where {T<:PolyRingElem} - return characteristic(base_ring(base_ring(R))) -end - -function size(R::Union{EuclideanRingResidueRing{T},EuclideanRingResidueField{T}}) where {T<:ResElem} - return size(base_ring(base_ring(R)))^degree(modulus(R)) -end - -function size(R::Union{EuclideanRingResidueRing{T},EuclideanRingResidueField{T}}) where {T<:PolyRingElem} - return size(base_ring(base_ring(R)))^degree(R.modulus) -end - -function rand(R::Union{EuclideanRingResidueRing{T},EuclideanRingResidueField{T}}) where {T<:PolyRingElem} - r = rand(base_ring(base_ring(R))) - g = gen(R) - for i = 1:degree(R.modulus) - r = r * g + rand(base_ring(base_ring(R))) - end - return r -end - -function gens(R::Union{EuclideanRingResidueRing{T},EuclideanRingResidueField{T}}) where {T<:PolyRingElem} ## probably needs more cases - ## as the other residue functions - g = gen(R) - r = Vector{typeof(g)}() - push!(r, one(R)) - if degree(R.modulus) == 1 - return r - end - push!(r, g) - for i = 2:degree(R.modulus)-1 - push!(r, r[end] * g) - end - return r -end - -promote_rule(::Type{LocalizedEuclideanRingElem{T}}, ::Type{T}) where {T} = LocalizedEuclideanRingElem{T} - -promote_rule(::Type{T}, ::Type{S}) where {S<:NumFieldElem,T<:Integer} = S - -promote_rule(::Type{S}, ::Type{T}) where {S<:NumFieldElem,T<:Integer} = S - -function mulmod(a::S, b::S, mod::Vector{S}) where {S<:MPolyRingElem{T}} where {T<:RingElem} - return Base.divrem(a * b, mod)[2] -end - -Base.:\(f::Map, x) = preimage(f, x) - -function set_precision(f::PolyRingElem{T}, n::Int) where {T<:SeriesElem} - g = parent(f)() - for i = 0:length(f) - setcoeff!(g, i, set_precision(coeff(f, i), n)) - end - return g -end - -function set_precision!(f::PolyRingElem{T}, n::Int) where {T<:SeriesElem} - for i = 0:length(f) - setcoeff!(f, i, set_precision!(coeff(f, i), n)) - end - return f -end - -function Base.minimum(::typeof(precision), a::Vector{<:SeriesElem}) - return minimum(map(precision, a)) -end - -function Base.maximum(::typeof(precision), a::Vector{<:SeriesElem}) - return maximum(map(precision, a)) -end - -#TODO: in Nemo, rename to setprecision -# fix/report series add for different length -function set_precision(a::SeriesElem, i::Int) - b = deepcopy(a) - set_precision!(b, i) - return b -end - -Random.gentype(::Type{T}) where {T<:FinField} = elem_type(T) - -transpose!(A::MatrixElem) = transpose(A) - -function Base.div(f::PolyRingElem, g::PolyRingElem) - q, r = divrem(f, g) - return q -end - -function Base.rem(f::PolyRingElem, g::PolyRingElem) - return mod(f, g) -end - -############################################################################### -# -# Random functions -# -############################################################################### - -Random.Sampler(::Type{RNG}, K::FinField, n::Random.Repetition) where {RNG<:AbstractRNG} = - Random.SamplerSimple(K, Random.Sampler(RNG, BigInt(0):BigInt(characteristic(K) - 1), n)) - -function rand(rng::AbstractRNG, Ksp::Random.SamplerSimple{<:FinField}) - K = Ksp[] - r = degree(K) - alpha = gen(K) - res = zero(K) - for i = 0:(r-1) - c = rand(rng, Ksp.data) - res += c * alpha^i - end - return res -end - -function (R::Generic.PolyRing{T})(x::Generic.RationalFunctionFieldElem{T,U}) where {T<:RingElem,U} - @assert isone(denominator(x)) - @assert parent(numerator(x)) === R - return numerator(x) -end -function (R::PolyRing{T})(x::Generic.RationalFunctionFieldElem{T,U}) where {T<:RingElem,U} - @assert isone(denominator(x)) - @assert parent(numerator(x)) === R - return numerator(x) -end diff --git a/src/NumFields.jl b/src/NumFields.jl new file mode 100644 index 0000000000..317403b490 --- /dev/null +++ b/src/NumFields.jl @@ -0,0 +1,28 @@ +gens(L::SimpleNumField{T}) where {T} = [gen(L)] + +function gen(L::SimpleNumField{T}, i::Int) where {T} + i == 1 || error("index must be 1") + return gen(L) +end + +function Base.getindex(L::SimpleNumField{T}, i::Int) where {T} + if i == 0 + return one(L) + elseif i == 1 + return gen(L) + else + error("index has to be 0 or 1") + end +end + +number_of_generators(L::SimpleNumField{T}) where {T} = 1 + +is_unit(a::NumFieldElem) = !iszero(a) + +canonical_unit(a::NumFieldElem) = a + +characteristic(F::NumField) = 0 + +promote_rule(::Type{T}, ::Type{S}) where {S<:NumFieldElem,T<:Integer} = S + +promote_rule(::Type{S}, ::Type{T}) where {S<:NumFieldElem,T<:Integer} = S diff --git a/src/Poly.jl b/src/Poly.jl index d7f44016a0..8386cd7bb6 100644 --- a/src/Poly.jl +++ b/src/Poly.jl @@ -49,6 +49,8 @@ number_of_variables(a::PolyRing) = 1 characteristic(a::PolyRing) = characteristic(base_ring(a)) +Base.copy(a::PolyRingElem) = deepcopy(a) + ############################################################################### # # Basic manipulation @@ -1962,6 +1964,10 @@ function content(a::PolyRingElem) return z end +function content(a::PolyRingElem{<:FieldElem}) + return one(base_ring(a)) +end + @doc raw""" primpart(a::PolyRingElem) diff --git a/src/RelSeries.jl b/src/RelSeries.jl index ec835b6144..cb1265b2dc 100644 --- a/src/RelSeries.jl +++ b/src/RelSeries.jl @@ -43,6 +43,8 @@ this is returned as a `Symbol` not a `String`. """ var(a::SeriesRing) = a.S +Base.copy(a::SeriesElem) = deepcopy(a) + ############################################################################### # # Basic manipulation @@ -105,6 +107,23 @@ function set_precision!(a::SeriesElem, prec::Int) return a end +set_precision(a::SeriesElem, i::Int) = set_precision!(deepcopy(a), i) + +function set_precision(f::PolyRingElem{T}, n::Int) where {T<:SeriesElem} + g = parent(f)() + for i = 0:length(f) + setcoeff!(g, i, set_precision(coeff(f, i), n)) + end + return g +end + +function set_precision!(f::PolyRingElem{T}, n::Int) where {T<:SeriesElem} + for i = 0:length(f) + setcoeff!(f, i, set_precision!(coeff(f, i), n)) + end + return f +end + function set_valuation!(a::RelPowerSeriesRingElem, val::Int) a.val = val return a @@ -170,6 +189,21 @@ function renormalize!(z::RelPowerSeriesRingElem) return nothing end +function canonical_unit(a::SeriesElem) + iszero(a) && return one(parent(a)) + v = valuation(a) + v == 0 && return a + return shift_right(a, v) +end + +function lift(R::PolyRing{T}, s::RelPowerSeriesRingElem{T}) where {T} + t = R() + for x = 0:pol_length(s) + setcoeff!(t, x, polcoeff(s, x)) + end + return shift_left(t, valuation(s)) +end + ############################################################################### # # Similar and zero diff --git a/src/Rings.jl b/src/Rings.jl index d55bf5fbca..bce7a0c9c6 100644 --- a/src/Rings.jl +++ b/src/Rings.jl @@ -186,5 +186,3 @@ is_perfect(F::Field) = characteristic(F) == 0 || F isa FinField || is_finite(F::FinField) = true is_finite(F::Field) = characteristic(F) != 0 && throw(NotImplementedError(:is_finite, F)) - -characteristic(F::NumField) = 0 diff --git a/src/generic/MPoly.jl b/src/generic/MPoly.jl index a765189b84..daec0d6ec9 100644 --- a/src/generic/MPoly.jl +++ b/src/generic/MPoly.jl @@ -851,6 +851,8 @@ function Base.deepcopy_internal(a::MPoly{T}, dict::IdDict) where {T <: RingEleme return parent(a)(Rc, Re) end +Base.copy(f::Generic.MPoly) = deepcopy(f) + ############################################################################### # # Iterators diff --git a/src/generic/Misc/Localization.jl b/src/generic/Misc/Localization.jl index 8668118853..8c8288e679 100644 --- a/src/generic/Misc/Localization.jl +++ b/src/generic/Misc/Localization.jl @@ -354,6 +354,7 @@ end promote_rule(::Type{LocalizedEuclideanRingElem{T}}, ::Type{LocalizedEuclideanRingElem{T}}) where {T <: RingElement} = LocalizedEuclideanRingElem{T} +promote_rule(::Type{LocalizedEuclideanRingElem{T}}, ::Type{T}) where {T} = LocalizedEuclideanRingElem{T} ############################################################################### # diff --git a/src/generic/Poly.jl b/src/generic/Poly.jl index 4be08bb330..3e805287fc 100644 --- a/src/generic/Poly.jl +++ b/src/generic/Poly.jl @@ -73,6 +73,8 @@ function deepcopy_internal(a::Poly{T}, dict::IdDict) where T <: RingElement return parent(a)(coeffs) end +Base.copy(f::Generic.Poly) = deepcopy(f) + ############################################################################### # # Karatsuba multiplication diff --git a/src/generic/RationalFunctionField.jl b/src/generic/RationalFunctionField.jl index 27a6d12378..a97513e686 100644 --- a/src/generic/RationalFunctionField.jl +++ b/src/generic/RationalFunctionField.jl @@ -91,6 +91,21 @@ function Base.denominator(a::RationalFunctionFieldElem, canonicalise::Bool=true) return denominator(data(a), canonicalise) end +function (R::AbstractAlgebra.PolyRing{T})(x::RationalFunctionFieldElem{T, U}) where {T <: RingElement, U} + @assert isone(denominator(x)) + y = numerator(x) + @assert parent(y) === R + return y +end + +# Avoid ambiguity with (::Generic.PolyRing{T})(::RingElement) +function (R::PolyRing{T})(x::RationalFunctionFieldElem{T, U}) where {T <: RingElement, U} + @assert isone(denominator(x)) + y = numerator(x) + @assert parent(y) === R + return y +end + zero(R::RationalFunctionField) = R() one(R::RationalFunctionField) = R(1) diff --git a/src/generic/Residue.jl b/src/generic/Residue.jl index 431ab8285f..cd11206004 100644 --- a/src/generic/Residue.jl +++ b/src/generic/Residue.jl @@ -81,3 +81,47 @@ function preimage(f::EuclideanRingResidueMap, a) parent(a) != codomain(f) && error("Not an element of the codomain") return lift(a) end + +############################################################################### +# +# Some functions for residue rings of polynomial rings +# +############################################################################### + +function gen(R::Union{EuclideanRingResidueRing{T}, EuclideanRingResidueField{T}}) where {T<:PolyRingElem} + return R(gen(base_ring(R))) +end + +# TODO: the names `gen` (algebra generator) and `gens` (module generators) are +# very unfortunate +function gens(R::Union{EuclideanRingResidueRing{T}, EuclideanRingResidueField{T}}) where {T<:PolyRingElem} ## probably needs more cases + ## as the other residue functions + g = gen(R) + r = Vector{typeof(g)}() + push!(r, one(R)) + if degree(modulus(R)) == 1 + return r + end + push!(r, g) + for i = 2:degree(modulus(R))-1 + push!(r, r[end] * g) + end + return r +end + +function characteristic(R::Union{EuclideanRingResidueRing{T}, EuclideanRingResidueField{T}}) where {T<:PolyRingElem} + return characteristic(base_ring(base_ring(R))) +end + +function size(R::Union{EuclideanRingResidueRing{T}, EuclideanRingResidueField{T}}) where {T<:PolyRingElem} + return size(base_ring(base_ring(R)))^degree(modulus(R)) +end + +function rand(R::Union{EuclideanRingResidueRing{T}, EuclideanRingResidueField{T}}) where {T<:PolyRingElem} + r = rand(base_ring(base_ring(R))) + g = gen(R) + for i = 1:degree(modulus(R)) + r = r * g + rand(base_ring(base_ring(R))) + end + return r +end diff --git a/src/julia/Float.jl b/src/julia/Float.jl index 2508f1a339..61648a7779 100644 --- a/src/julia/Float.jl +++ b/src/julia/Float.jl @@ -44,6 +44,10 @@ canonical_unit(a::AbstractFloat) = a characteristic(a::Floats{T}) where T <: AbstractFloat = 0 +is_negative(n::T) where T<:Real = n < zero(T) + +is_positive(n::T) where T<:Real = n > zero(T) + ############################################################################### # # String I/O diff --git a/src/julia/GF.jl b/src/julia/GF.jl index 170ae456db..1e03f3648f 100644 --- a/src/julia/GF.jl +++ b/src/julia/GF.jl @@ -411,13 +411,25 @@ end # ############################################################################### -Random.Sampler(RNG::Type{<:AbstractRNG}, R::GFField, n::Random.Repetition) = - Random.SamplerSimple(R, Random.Sampler(RNG, 0:R.p - 1, n)) +Random.Sampler(RNG::Type{<:AbstractRNG}, R::FinField, n::Random.Repetition) = + Random.SamplerSimple(R, Random.Sampler(RNG, BigInt(0):BigInt(characteristic(R) - 1), n)) rand(rng::AbstractRNG, R::Random.SamplerSimple{GFField{T}}) where T = GFElem{T}(rand(rng, R.data), R[]) -Random.gentype(T::Type{<:GFField}) = elem_type(T) +function rand(rng::AbstractRNG, Ksp::Random.SamplerSimple{<:FinField}) + K = Ksp[] + r = degree(K) + alpha = gen(K) + res = zero(K) + for i = 0:(r-1) + c = rand(rng, Ksp.data) + res += c * alpha^i + end + return res +end + +Random.gentype(T::Type{<:FinField}) = elem_type(T) ############################################################################### # diff --git a/src/julia/Integer.jl b/src/julia/Integer.jl index a6ca1ba508..f629aff4c1 100644 --- a/src/julia/Integer.jl +++ b/src/julia/Integer.jl @@ -28,6 +28,8 @@ is_exact_type(::Type{T}) where T <: Integer = true is_domain_type(::Type{T}) where T <: Integer = true +base_ring(::Vector{T}) where T <: Integer = T + ############################################################################### # # Basic manipulation @@ -557,6 +559,10 @@ function addmul!(a::T, b::T, c::T) where T <: Integer # special case, no tempora return a + b*c end +function neg!(w::Vector{<:Integer}) + return w .*= -1 +end + ############################################################################### # # Random generation diff --git a/src/julia/Rational.jl b/src/julia/Rational.jl index b82fb92e87..caef7d85ad 100644 --- a/src/julia/Rational.jl +++ b/src/julia/Rational.jl @@ -285,6 +285,14 @@ function addmul!(a::Rational{T}, b::Rational{T}, c::Rational{T}, d::Rational{T}) return a end +sub!(z::Rational{T}, x::Rational{T}, y::T) where T <: Integer = x - y + +neg!(z::Rational{T}, x::Rational{T}) where T <: Integer = -x + +add!(z::Rational{T}, x::Rational{T}, y::T) where T <: Integer = x + y + +mul!(z::Rational{T}, x::Rational{T}, y::T) where T <: Integer = x * y + ############################################################################### # # Random generation @@ -310,6 +318,32 @@ rand(rng::AbstractRNG, R::Rationals, n) = rand(rng, make(R, n)) rand(R::Rationals, n) = rand(Random.GLOBAL_RNG, R, n) +############################################################################### +# +# valutaion / remove +# +############################################################################### + +# TODO (CF): +# should be Bernstein'ed: this is slow for large valuations +# returns the maximal v s.th. z mod p^v == 0 and z div p^v +# also useful if p is not prime.... +# +# TODO: what happens to z = 0??? +function remove(z::Rational{T}, p::T) where {T<:Integer} + z == 0 && return (0, z) + v, d = remove(denominator(z), p) + w, n = remove(numerator(z), p) + return w - v, n // d +end + +function valuation(z::Rational{T}, p::T) where {T<:Integer} + z == 0 && error("Not yet implemented") + v = valuation(denominator(z), p) + w = valuation(numerator(z), p) + return w - v +end + ############################################################################### # # Parent object call overload diff --git a/test/generic/AbsSeries-test.jl b/test/generic/AbsSeries-test.jl index 5e254111a6..6088f9ac87 100644 --- a/test/generic/AbsSeries-test.jl +++ b/test/generic/AbsSeries-test.jl @@ -1315,3 +1315,12 @@ end @test isequal(set_precision(b, 1), O(x)) @test is_zero(set_precision(b, 1)) end + +@testset "Generic.AbsSeries.lift" begin + R, x = power_series_ring(QQ, 20, "x", model = :capped_absolute) + f = x^2 + 2*x^5 + x^6 + + S, y = polynomial_ring(QQ, "y") + g = lift(S, f) + @test g == y^2 + 2*y^5 + y^6 +end diff --git a/test/generic/FreeAssAlgebra-test.jl b/test/generic/FreeAssAlgebra-test.jl index 73d3016817..6a50a1141c 100644 --- a/test/generic/FreeAssAlgebra-test.jl +++ b/test/generic/FreeAssAlgebra-test.jl @@ -83,6 +83,12 @@ end @test f1 == f4 + f4 = zero(S) + for t in zip(coefficients(f1), monomials(f1)) + f4 = addmul!(f4, S(t[1]), t[2]) + end + @test f1 == f4 + if !iszero(f1) @test leading_term(f1) == leading_coefficient(f1)*leading_monomial(f1) @test total_degree(f1) >= total_degree(f1 - leading_term(f1)) diff --git a/test/generic/MPoly-test.jl b/test/generic/MPoly-test.jl index 2d0ca6ea5a..961ba23121 100644 --- a/test/generic/MPoly-test.jl +++ b/test/generic/MPoly-test.jl @@ -326,6 +326,7 @@ end f = rand(S, 0:5, 0:100, 0:0, -100:100) @test f == deepcopy(f) + @test f == copy(f) @test hash(f) == hash(deepcopy(f)) @@ -1695,3 +1696,11 @@ end @test_throws Exception mpoly_ring_type(Char) @test_throws ArgumentError mpoly_type(Char) end + +@testset "Generic.MPoly.as_univariate" begin + R, (x, y) = polynomial_ring(QQ, ["x", "y"]) + f = x * y + 2 * x^2 * y + x * y^2 + @test coefficients(f, 1) == typeof(f)[R(), y + y^2, 2 * y] + @test leading_coefficient(f, 1) == coefficients(f, 1)[end] + @test content(f, 1) == y +end diff --git a/test/generic/Matrix-test.jl b/test/generic/Matrix-test.jl index 621ece4dc8..487aa6397d 100644 --- a/test/generic/Matrix-test.jl +++ b/test/generic/Matrix-test.jl @@ -4382,3 +4382,25 @@ end @test M + X == N + matrix(X) end end + +@testset "Generic.Mat.unsafe" begin + a = QQ[1 2 3; 4 5 6] + b = QQ[1 1 1; 1 1 1] + c = zero_matrix(QQ, 2, 3) + c = add!(c, a, b) + @test c == a + b + c = sub!(c, a, b) + @test c == a - b + + b = transpose(b) + c = zero_matrix(QQ, 2, 2) + c = mul!(c, a, b) + @test c == a * b + + c = zero_matrix(QQ, 2, 3) + c = mul!(c, a, QQ(2)) + @test c == a * QQ(2) + + b = transpose(a) + @test AbstractAlgebra.transpose!(a) == b +end diff --git a/test/generic/ModuleHomomorphism-test.jl b/test/generic/ModuleHomomorphism-test.jl index 2064ca2a56..d970603479 100644 --- a/test/generic/ModuleHomomorphism-test.jl +++ b/test/generic/ModuleHomomorphism-test.jl @@ -136,12 +136,16 @@ end n = f(m) x = preimage(f, n) @test x == m + y = f\n + @test y == m for i in 0:5 m = elem_type(M)[ rand(M, -10:10) for j in 1:i ] n = elem_type(N)[ f(mm) for mm in m ] x = preimage(f, n) @test x == m + y = f\n + @test y == m end end end diff --git a/test/generic/Poly-test.jl b/test/generic/Poly-test.jl index 8f04675095..0e5ac0716e 100644 --- a/test/generic/Poly-test.jl +++ b/test/generic/Poly-test.jl @@ -363,6 +363,7 @@ end @test canonical_unit(-x*y + x + 1) == -1 @test deepcopy(h) == h + @test copy(h) == h @test is_term_recursive(2*x*y^2) @test !is_term_recursive(2*(x + 1)*y^2) diff --git a/test/generic/RationalFunctionField-test.jl b/test/generic/RationalFunctionField-test.jl index 76e31ee327..e56b8ad82d 100644 --- a/test/generic/RationalFunctionField-test.jl +++ b/test/generic/RationalFunctionField-test.jl @@ -138,6 +138,12 @@ end @test numerator((x + 1)//(-x^2 + 1)) == -1 + S = parent(numerator(x)) + @test S(x) == gen(S) + @test_throws AssertionError S(1//x) + T, _ = polynomial_ring(QQ, "x", cached = false) + @test_throws AssertionError T(x) + @test iszero(zero(R)) @test isone(one(R)) diff --git a/test/generic/RelSeries-test.jl b/test/generic/RelSeries-test.jl index f1aa9e5069..245a4a958c 100644 --- a/test/generic/RelSeries-test.jl +++ b/test/generic/RelSeries-test.jl @@ -151,6 +151,8 @@ end @test isequal(deepcopy(a), a) @test isequal(deepcopy(b), b) + @test isequal(copy(a), a) + @test isequal(copy(b), b) @test normalise(a, 3) == 3 @@ -1351,3 +1353,12 @@ end @test isequal(set_precision(b, 1), O(x)) @test is_zero(set_precision(b, 1)) end + +@testset "Generic.RelSeries.lift" begin + R, x = power_series_ring(QQ, 20, "x") + f = x^2 + 2*x^5 + x^6 + + S, y = polynomial_ring(QQ, "y") + g = lift(S, f) + @test g == y^2 + 2*y^5 + y^6 +end diff --git a/test/generic/Residue-test.jl b/test/generic/Residue-test.jl index 59af5c4434..e3b8b1c9f4 100644 --- a/test/generic/Residue-test.jl +++ b/test/generic/Residue-test.jl @@ -462,3 +462,11 @@ end end end end + +@testset "EuclideanRingResidueRingElem.polynomials" begin + R, x = polynomial_ring(GF(5), "x") + S, _ = residue_ring(R, x^3) + + @test gen(S) == S(x) + @test gens(S) == elem_type(S)[one(S), gen(S), gen(S)^2] +end diff --git a/test/julia/Floats-test.jl b/test/julia/Floats-test.jl index 0eb2f01f5d..38f6c2f6b2 100644 --- a/test/julia/Floats-test.jl +++ b/test/julia/Floats-test.jl @@ -32,6 +32,11 @@ end @test is_unit(R(3)) @test is_unit(S(3)) + + @test is_negative(R(-3)) + @test !is_negative(R(0)) + @test !is_positive(R(-3)) + @test !is_positive(R(0)) end @testset "Julia.Floats.exact_division" begin diff --git a/test/julia/Rationals-test.jl b/test/julia/Rationals-test.jl index aead6091d8..9c81990782 100644 --- a/test/julia/Rationals-test.jl +++ b/test/julia/Rationals-test.jl @@ -207,3 +207,38 @@ end @test AbstractAlgebra.divrem(r,s) == (r/s,0) end end + +@testset "Julia.Rationals.valuation" begin + z = QQ(1//6) + p = ZZ(3) + v, x = remove(z, p) + @test v == -1 + @test v == valuation(z, p) + @test x == QQ(1//2) + + p = ZZ(5) + v, x = remove(z, p) + @test v == 0 + @test v == valuation(z, p) + @test x == z + + z = QQ(0) + v, x = remove(z, p) + @test v == 0 + @test x == z + @test_throws ErrorException valuation(z, p) +end + +@testset "Julia.Rationals.unsafe_operations" begin + a = QQ(2//3) + b = QQ(3//4) + c = QQ() + @test neg!(c, a) == -a + @test add!(c, a, b) == a + b + @test mul!(c, a, b) == a * b + + b = ZZ(3) + @test sub!(c, a, b) == a - b + @test add!(c, a, b) == a + b + @test mul!(c, a, b) == a * b +end