From 06f09442b5bc2332e33e5461eafdacd5146c3dd4 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Fri, 24 Oct 2025 15:11:50 +0200 Subject: [PATCH 01/12] Towards inplace iterators for exponents of multivariate polynomials etc. --- src/MPoly.jl | 20 ++++--- src/exports.jl | 3 + src/generic/GenericTypes.jl | 10 +++- src/generic/MPoly.jl | 109 ++++++++++++++++++------------------ src/generic/exports.jl | 3 + 5 files changed, 80 insertions(+), 65 deletions(-) diff --git a/src/MPoly.jl b/src/MPoly.jl index c7396bebe7..24b6bfb1b7 100644 --- a/src/MPoly.jl +++ b/src/MPoly.jl @@ -500,8 +500,9 @@ end Return an iterator for the coefficients of the given polynomial. To retrieve an array of the coefficients, use `collect(coefficients(a))`. """ -function coefficients(a::MPolyRingElem{T}) where T <: RingElement - return Generic.MPolyCoeffs(a) +function coefficients(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement + t = zero(coefficient_ring(parent(a))) + return Generic.MPolyCoeffs(a, inplace, t) end @doc raw""" @@ -511,8 +512,9 @@ Return an iterator for the exponent vectors of the given polynomial. To retrieve an array of the exponent vectors, use `collect(exponent_vectors(a))`. """ -function exponent_vectors(a::MPolyRingElem{T}) where T <: RingElement - return Generic.MPolyExponentVectors(a) +function exponent_vectors(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement + t = zeros(Int, nvars(parent(a))) + return Generic.MPolyExponentVectors(a, inplace, t) end @doc raw""" @@ -521,8 +523,9 @@ end Return an iterator for the monomials of the given polynomial. To retrieve an array of the monomials, use `collect(monomials(a))`. """ -function monomials(a::MPolyRingElem{T}) where T <: RingElement - return Generic.MPolyMonomials(a) +function monomials(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement + t = zero(parent(a)) + return Generic.MPolyMonomials(a, inplace, t) end @doc raw""" @@ -531,8 +534,9 @@ end Return an iterator for the terms of the given polynomial. To retrieve an array of the terms, use `collect(terms(a))`. """ -function terms(a::MPolyRingElem{T}) where T <: RingElement - return Generic.MPolyTerms(a) +function terms(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement + t = zero(parent(a)) + return Generic.MPolyTerms(a, inplace, t) end ############################################################################### diff --git a/src/exports.jl b/src/exports.jl index 964222f42b..049c9c7dbf 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -154,6 +154,7 @@ export check_composable export check_parent export codomain export coeff +export coeff! export coefficient_ring export coefficient_ring_type export coefficients @@ -211,6 +212,7 @@ export evaluate export exp_gcd export exponent export exponent_vector +export exponent_vector! export exponent_vectors export exponent_word export exponent_words @@ -579,6 +581,7 @@ export symbols export tail export term export terms +export term! export to_univariate export total_degree export total_ring_of_fractions diff --git a/src/generic/GenericTypes.jl b/src/generic/GenericTypes.jl index bdb61fde40..4351334f26 100644 --- a/src/generic/GenericTypes.jl +++ b/src/generic/GenericTypes.jl @@ -385,20 +385,28 @@ end # Iterators -struct MPolyCoeffs{T <: AbstractAlgebra.NCRingElem} +struct MPolyCoeffs{T <: AbstractAlgebra.NCRingElem, S <: AbstractAlgebra.RingElement} poly::T + inplace::Bool + temp::S # only used if inplace == true end struct MPolyExponentVectors{T <: AbstractAlgebra.RingElem} poly::T + inplace::Bool + temp::Vector{Int} # only used if inplace == true end struct MPolyTerms{T <: AbstractAlgebra.NCRingElem} poly::T + inplace::Bool + temp::T # only used if inplace == true end struct MPolyMonomials{T <: AbstractAlgebra.NCRingElem} poly::T + inplace::Bool + temp::T # only used if inplace == true end mutable struct MPolyBuildCtx{T, S} diff --git a/src/generic/MPoly.jl b/src/generic/MPoly.jl index 29a5b337da..4f130b2354 100644 --- a/src/generic/MPoly.jl +++ b/src/generic/MPoly.jl @@ -125,19 +125,31 @@ are given in the order of the variables for the ring, as supplied when the ring was created. """ function exponent_vector(a::MPoly{T}, i::Int) where T <: RingElement + e = Vector{Int}(undef, nvars(parent(a))) + return exponent_vector!(e, a, i) +end + +function exponent_vector!(e::Vector{Int}, a::MPoly{T}, i::Int) where T <: RingElement + @assert length(e) == nvars(parent(a)) A = a.exps N = size(A, 1) ord = internal_ordering(parent(a)) if ord == :lex - return [Int(A[j, i]) for j in N:-1:1] + range = N:-1:1 elseif ord == :deglex - return [Int(A[j, i]) for j in N - 1:-1:1] + range = N - 1:-1:1 elseif ord == :degrevlex - return [Int(A[j, i]) for j in 1:N - 1] + range = 1:N - 1 else error("invalid ordering") end + k = 1 + for j in range + e[k] = Int(A[j, i]) + k += 1 + end + return e end @doc raw""" @@ -635,6 +647,11 @@ function coeff(x::MPoly, i::Int) return x.coeffs[i] end +# Only for compatibility, we can't do anything in place here +function coeff!(c::T, x::MPoly{T}, i::Int) where T <: RingElement + return x.coeffs[i] +end + function trailing_coefficient(p::MPoly{T}) where T <: RingElement @req !iszero(p) "Zero polynomial does not have a leading monomial" return coeff(p, length(p)) @@ -664,7 +681,9 @@ function monomial!(m::MPoly{T}, x::MPoly{T}, i::Int) where T <: RingElement N = size(x.exps, 1) fit!(m, 1) monomial_set!(m.exps, 1, x.exps, i, N) - m.coeffs[1] = one(base_ring(x)) + if !isassigned(m.coeffs, 1) || !is_one(m.coeffs[1]) + m.coeffs[1] = one(base_ring(x)) + end m.length = 1 return m end @@ -675,11 +694,17 @@ end Return the $i$-th nonzero term of the polynomial $x$ (as a polynomial). """ function term(x::MPoly, i::Int) - R = base_ring(x) + y = zero(parent(x)) + return term!(y, x, i) +end + +function term!(y::T, x::T, i::Int) where T <: MPoly N = size(x.exps, 1) - exps = Matrix{UInt}(undef, N, 1) - monomial_set!(exps, 1, x.exps, i, N) - return parent(x)([deepcopy(x.coeffs[i])], exps) + fit!(y, 1) + monomial_set!(y.exps, 1, x.exps, i, N) + y.coeffs[1] = deepcopy(x.coeffs[i]) + y.length = 1 + return y end @doc raw""" @@ -804,69 +829,41 @@ Base.copy(f::Generic.MPoly) = deepcopy(f) # ############################################################################### -function Base.iterate(x::MPolyCoeffs) - if length(x.poly) >= 1 - return coeff(x.poly, 1), 1 - else - return nothing - end -end - -function Base.iterate(x::MPolyCoeffs, state) - state += 1 - if length(x.poly) >= state - return coeff(x.poly, state), state - else - return nothing - end -end - -function Base.iterate(x::MPolyExponentVectors) - if length(x.poly) >= 1 - return exponent_vector(x.poly, 1), 1 - else - return nothing - end -end - -function Base.iterate(x::MPolyExponentVectors, state) - state += 1 - if length(x.poly) >= state - return exponent_vector(x.poly, state), state - else - return nothing - end -end - -function Base.iterate(x::MPolyTerms) - if length(x.poly) >= 1 - return term(x.poly, 1), 1 +function Base.iterate(x::MPolyCoeffs, state::Union{Nothing, Int} = nothing) + s = isnothing(state) ? 1 : state + 1 + if length(x.poly) >= s + c = x.inplace ? coeff!(x.temp, x.poly, s) : coeff(x.poly, s) + return c, s else return nothing end end -function Base.iterate(x::MPolyTerms, state) - state += 1 - if length(x.poly) >= state - return term(x.poly, state), state +function Base.iterate(x::MPolyExponentVectors, state::Union{Nothing, Int} = nothing) + s = isnothing(state) ? 1 : state + 1 + if length(x.poly) >= s + v = x.inplace ? exponent_vector!(x.temp, x.poly, s) : exponent_vector(x.poly, s) + return v, s else return nothing end end -function Base.iterate(x::MPolyMonomials) - if length(x.poly) >= 1 - return monomial(x.poly, 1), 1 +function Base.iterate(x::MPolyTerms, state::Union{Nothing, Int} = nothing) + s = isnothing(state) ? 1 : state + 1 + if length(x.poly) >= s + t = x.inplace ? term!(x.temp, x.poly, s) : term(x.poly, s) + return t, s else return nothing end end -function Base.iterate(x::MPolyMonomials, state) - state += 1 - if length(x.poly) >= state - return monomial(x.poly, state), state +function Base.iterate(x::MPolyMonomials, state::Union{Nothing, Int} = nothing) + s = isnothing(state) ? 1 : state + 1 + if length(x.poly) >= s + m = x.inplace ? monomial!(x.temp, x.poly, s) : monomial(x.poly, s) + return m, s else return nothing end diff --git a/src/generic/exports.jl b/src/generic/exports.jl index 62b978d326..938c95db7a 100644 --- a/src/generic/exports.jl +++ b/src/generic/exports.jl @@ -12,6 +12,7 @@ export abs_series_type export base_field export basis export character +export coeff! export collength export combine_like_terms! export cycles @@ -25,6 +26,7 @@ export enable_cache! export exp_gcd export exponent export exponent_vector +export exponent_vector! export exponent_word export falling_factorial export finish @@ -122,6 +124,7 @@ export summands export supermodule export term export terms +export term! export to_univariate export total_degree export trailing_coefficient From 7f67fd9ee72cb22f6e307fa740ff4dcc364c9032 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Wed, 29 Oct 2025 14:20:24 +0100 Subject: [PATCH 02/12] Add one-element constructors --- src/generic/GenericTypes.jl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/generic/GenericTypes.jl b/src/generic/GenericTypes.jl index 4351334f26..9072298eb7 100644 --- a/src/generic/GenericTypes.jl +++ b/src/generic/GenericTypes.jl @@ -391,24 +391,40 @@ struct MPolyCoeffs{T <: AbstractAlgebra.NCRingElem, S <: AbstractAlgebra.RingEle temp::S # only used if inplace == true end +function MPolyCoeffs(f::AbstractAlgebra.NCRingElem) + return MPolyCoeffs(f, false, zero(coefficient_ring(parent(f)))) +end + struct MPolyExponentVectors{T <: AbstractAlgebra.RingElem} poly::T inplace::Bool temp::Vector{Int} # only used if inplace == true end +function MPolyExponentVectors(f::AbstractAlgebra.RingElem) + return MPolyExponentVectors(f, false, Vector{Int}()) +end + struct MPolyTerms{T <: AbstractAlgebra.NCRingElem} poly::T inplace::Bool temp::T # only used if inplace == true end +function MPolyTerms(f::AbstractAlgebra.NCRingElem) + return MPolyTerms(f, false, zero(parent(f))) +end + struct MPolyMonomials{T <: AbstractAlgebra.NCRingElem} poly::T inplace::Bool temp::T # only used if inplace == true end +function MPolyMonomials(f::NCRingElem) + return MPolyMonomials(f, false, zero(parent(f))) +end + mutable struct MPolyBuildCtx{T, S} poly::T state::S From 85a8cbf1e629cda23192c5b52e28fd11b4a3fbba Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Wed, 29 Oct 2025 14:48:19 +0100 Subject: [PATCH 03/12] Fix type signature --- src/generic/MPoly.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generic/MPoly.jl b/src/generic/MPoly.jl index 4f130b2354..a57c77ca11 100644 --- a/src/generic/MPoly.jl +++ b/src/generic/MPoly.jl @@ -873,7 +873,7 @@ function Base.length(x::Union{MPolyCoeffs, MPolyExponentVectors, MPolyTerms, MPo return length(x.poly) end -function Base.eltype(::Type{MPolyCoeffs{T}}) where T <: AbstractAlgebra.MPolyRingElem{S} where S <: RingElement +function Base.eltype(::Type{MPolyCoeffs{T, S}}) where {T <: AbstractAlgebra.MPolyRingElem, S <: RingElement} return S end From 235f8b2267565df4df3fcdde836a639814578326 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Wed, 29 Oct 2025 16:04:03 +0100 Subject: [PATCH 04/12] Allow "arbitrary" types for exponent vectors --- src/MPoly.jl | 6 +++++- src/generic/GenericTypes.jl | 6 ++++-- src/generic/MPoly.jl | 8 ++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/MPoly.jl b/src/MPoly.jl index 24b6bfb1b7..abcde12211 100644 --- a/src/MPoly.jl +++ b/src/MPoly.jl @@ -513,7 +513,11 @@ retrieve an array of the exponent vectors, use `collect(exponent_vectors(a))`. """ function exponent_vectors(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement - t = zeros(Int, nvars(parent(a))) + return exponent_vectors(Vector{Int}, a, inplace=inplace) +end + +function exponent_vectors(::Type{Vector{S}}, a::MPolyRingElem{T}; inplace::Bool = false) where {T <: RingElement, S} + t = zeros(S, nvars(parent(a))) return Generic.MPolyExponentVectors(a, inplace, t) end diff --git a/src/generic/GenericTypes.jl b/src/generic/GenericTypes.jl index 9072298eb7..be65203391 100644 --- a/src/generic/GenericTypes.jl +++ b/src/generic/GenericTypes.jl @@ -395,10 +395,12 @@ function MPolyCoeffs(f::AbstractAlgebra.NCRingElem) return MPolyCoeffs(f, false, zero(coefficient_ring(parent(f)))) end -struct MPolyExponentVectors{T <: AbstractAlgebra.RingElem} +# S may be the type of anything that can store an exponent vector, for example +# Vector{Int}, ZZMatrix, ... +struct MPolyExponentVectors{T <: AbstractAlgebra.RingElem, S} poly::T inplace::Bool - temp::Vector{Int} # only used if inplace == true + temp::S # only used if inplace == true end function MPolyExponentVectors(f::AbstractAlgebra.RingElem) diff --git a/src/generic/MPoly.jl b/src/generic/MPoly.jl index a57c77ca11..f8e37b72ae 100644 --- a/src/generic/MPoly.jl +++ b/src/generic/MPoly.jl @@ -129,7 +129,7 @@ function exponent_vector(a::MPoly{T}, i::Int) where T <: RingElement return exponent_vector!(e, a, i) end -function exponent_vector!(e::Vector{Int}, a::MPoly{T}, i::Int) where T <: RingElement +function exponent_vector!(e::Vector{S}, a::MPoly{T}, i::Int) where {T <: RingElement, S} @assert length(e) == nvars(parent(a)) A = a.exps N = size(A, 1) @@ -146,7 +146,7 @@ function exponent_vector!(e::Vector{Int}, a::MPoly{T}, i::Int) where T <: RingEl end k = 1 for j in range - e[k] = Int(A[j, i]) + e[k] = S(A[j, i]) k += 1 end return e @@ -877,8 +877,8 @@ function Base.eltype(::Type{MPolyCoeffs{T, S}}) where {T <: AbstractAlgebra.MPol return S end -function Base.eltype(::Type{MPolyExponentVectors{T}}) where T <: AbstractAlgebra.MPolyRingElem{S} where S <: RingElement - return Vector{Int} +function Base.eltype(::Type{MPolyExponentVectors{T, V}}) where {V, T <: AbstractAlgebra.MPolyRingElem{S} where S <: RingElement} + return V end function Base.eltype(::Type{MPolyMonomials{T}}) where T <: AbstractAlgebra.MPolyRingElem{S} where S <: RingElement From 2f4465a77fd2976417dd2f43ab3a8ecd0a772c74 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Wed, 29 Oct 2025 16:19:35 +0100 Subject: [PATCH 05/12] Add a small test --- test/generic/MPoly-test.jl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/generic/MPoly-test.jl b/test/generic/MPoly-test.jl index 8e7d36cd91..4a3a10bd0e 100644 --- a/test/generic/MPoly-test.jl +++ b/test/generic/MPoly-test.jl @@ -1877,3 +1877,20 @@ end R2, (x2, y2) = polynomial_ring(QQ, [:x, :y]) @test_throws ErrorException z1 + y2 end + +@testset "Generic.MPoly.Iterators" begin + R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]) + f = x * y + 2 * x - 3 * z + + @test @inferred collect(exponent_vectors(f)) == [[1, 1, 0], [1, 0, 0], [0, 0, 1]] + @test @inferred collect(exponent_vectors(Vector{UInt}, f)) == [UInt[1, 1, 0], UInt[1, 0, 0], UInt[0, 0, 1]] + @test @inferred collect(coefficients(f)) == [QQ(1), QQ(2), QQ(-3)] + @test @inferred collect(terms(f)) == [x * y, 2 * x, -3 * z] + @test @inferred collect(monomials(f)) == [x * y, x, z] + + @test @inferred first(exponent_vectors(f, inplace = true)) == [1, 1, 0] + @test @inferred first(exponent_vectors(Vector{UInt}, f, inplace = true)) == UInt[1, 1, 0] + @test @inferred first(coefficients(f, inplace = true)) == QQ(1) + @test @inferred first(monomials(f, inplace = true)) == x * y + @test @inferred first(terms(f, inplace = true)) == x * y +end From 6757cb361fb81b811630947729ea4313f327e513 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Wed, 29 Oct 2025 16:55:27 +0100 Subject: [PATCH 06/12] Make it Nemo proof --- src/MPoly.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MPoly.jl b/src/MPoly.jl index abcde12211..b404cb3ef2 100644 --- a/src/MPoly.jl +++ b/src/MPoly.jl @@ -517,7 +517,8 @@ function exponent_vectors(a::MPolyRingElem{T}; inplace::Bool = false) where T <: end function exponent_vectors(::Type{Vector{S}}, a::MPolyRingElem{T}; inplace::Bool = false) where {T <: RingElement, S} - t = zeros(S, nvars(parent(a))) + # Don't use `zeros`: If S === ZZRingElem, then all the entries would be identical + t = [zero(S) for _ in 1:nvars(parent(a))] return Generic.MPolyExponentVectors(a, inplace, t) end From a83914e1d012270c42cfe48e08e6ee0687aface8 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Wed, 5 Nov 2025 15:22:22 +0100 Subject: [PATCH 07/12] Only allocate when asked --- src/MPoly.jl | 30 +++++++++++++------ src/generic/GenericTypes.jl | 60 +++++++++++++++++++++++++++---------- 2 files changed, 65 insertions(+), 25 deletions(-) diff --git a/src/MPoly.jl b/src/MPoly.jl index b404cb3ef2..1e17b03985 100644 --- a/src/MPoly.jl +++ b/src/MPoly.jl @@ -501,8 +501,11 @@ Return an iterator for the coefficients of the given polynomial. To retrieve an array of the coefficients, use `collect(coefficients(a))`. """ function coefficients(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement - t = zero(coefficient_ring(parent(a))) - return Generic.MPolyCoeffs(a, inplace, t) + if inplace + t = zero(coefficient_ring(parent(a))) + return Generic.MPolyCoeffs(a, inplace, t) + end + return Generic.MPolyCoeffs(a) end @doc raw""" @@ -517,9 +520,12 @@ function exponent_vectors(a::MPolyRingElem{T}; inplace::Bool = false) where T <: end function exponent_vectors(::Type{Vector{S}}, a::MPolyRingElem{T}; inplace::Bool = false) where {T <: RingElement, S} - # Don't use `zeros`: If S === ZZRingElem, then all the entries would be identical - t = [zero(S) for _ in 1:nvars(parent(a))] - return Generic.MPolyExponentVectors(a, inplace, t) + if inplace + # Don't use `zeros`: If S === ZZRingElem, then all the entries would be identical + t = [zero(S) for _ in 1:nvars(parent(a))] + return Generic.MPolyExponentVectors(a, inplace, t) + end + return Generic.MPolyExponentVectors(Vector{S}, a) end @doc raw""" @@ -529,8 +535,11 @@ Return an iterator for the monomials of the given polynomial. To retrieve an array of the monomials, use `collect(monomials(a))`. """ function monomials(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement - t = zero(parent(a)) - return Generic.MPolyMonomials(a, inplace, t) + if inplace + t = zero(parent(a)) + return Generic.MPolyMonomials(a, inplace, t) + end + return Generic.MPolyMonomials(a) end @doc raw""" @@ -540,8 +549,11 @@ Return an iterator for the terms of the given polynomial. To retrieve an array of the terms, use `collect(terms(a))`. """ function terms(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement - t = zero(parent(a)) - return Generic.MPolyTerms(a, inplace, t) + if inplace + t = zero(parent(a)) + return Generic.MPolyTerms(a, inplace, t) + end + return Generic.MPolyTerms(a) end ############################################################################### diff --git a/src/generic/GenericTypes.jl b/src/generic/GenericTypes.jl index be65203391..78b5a312c9 100644 --- a/src/generic/GenericTypes.jl +++ b/src/generic/GenericTypes.jl @@ -385,46 +385,74 @@ end # Iterators -struct MPolyCoeffs{T <: AbstractAlgebra.NCRingElem, S <: AbstractAlgebra.RingElement} +mutable struct MPolyCoeffs{T <: AbstractAlgebra.NCRingElem, S <: AbstractAlgebra.RingElement} poly::T inplace::Bool temp::S # only used if inplace == true -end -function MPolyCoeffs(f::AbstractAlgebra.NCRingElem) - return MPolyCoeffs(f, false, zero(coefficient_ring(parent(f)))) + function MPolyCoeffs(f::AbstractAlgebra.NCRingElem) + I = new{typeof(f), elem_type(coefficient_ring_type(f))}() + I.poly = f + I.inplace = false + return I + end + + function MPolyCoeffs(f::AbstractAlgebra.NCRingElem, inplace::Bool, temp::AbstractAlgebra.RingElement) + return new{typeof(f), typeof(temp)}(f, inplace, temp) + end end # S may be the type of anything that can store an exponent vector, for example # Vector{Int}, ZZMatrix, ... -struct MPolyExponentVectors{T <: AbstractAlgebra.RingElem, S} +mutable struct MPolyExponentVectors{T <: AbstractAlgebra.RingElem, S} poly::T inplace::Bool temp::S # only used if inplace == true -end -function MPolyExponentVectors(f::AbstractAlgebra.RingElem) - return MPolyExponentVectors(f, false, Vector{Int}()) + function MPolyExponentVectors(::Type{S}, f::AbstractAlgebra.NCRingElem) where S + I = new{typeof(f), S}() + I.poly = f + I.inplace = false + return I + end + + function MPolyExponentVectors(f::AbstractAlgebra.NCRingElem, inplace::Bool, temp::S) where S + return new{typeof(f), S}(f, inplace, temp) + end end -struct MPolyTerms{T <: AbstractAlgebra.NCRingElem} +mutable struct MPolyTerms{T <: AbstractAlgebra.NCRingElem} poly::T inplace::Bool temp::T # only used if inplace == true -end -function MPolyTerms(f::AbstractAlgebra.NCRingElem) - return MPolyTerms(f, false, zero(parent(f))) + function MPolyTerms(f::AbstractAlgebra.NCRingElem) + I = new{typeof(f)}() + I.poly = f + I.inplace = false + return I + end + + function MPolyTerms(f::T, inplace::Bool, temp::T) where {T <: AbstractAlgebra.NCRingElem} + return new{T}(f, inplace, temp) + end end -struct MPolyMonomials{T <: AbstractAlgebra.NCRingElem} +mutable struct MPolyMonomials{T <: AbstractAlgebra.NCRingElem} poly::T inplace::Bool temp::T # only used if inplace == true -end -function MPolyMonomials(f::NCRingElem) - return MPolyMonomials(f, false, zero(parent(f))) + function MPolyMonomials(f::AbstractAlgebra.NCRingElem) + I = new{typeof(f)}() + I.poly = f + I.inplace = false + return I + end + + function MPolyMonomials(f::T, inplace::Bool, temp::T) where {T <: AbstractAlgebra.NCRingElem} + return new{T}(f, inplace, temp) + end end mutable struct MPolyBuildCtx{T, S} From 18cde7d5db63861dba8c986c5ac24579ab757499 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Wed, 5 Nov 2025 15:35:09 +0100 Subject: [PATCH 08/12] Provide "abstract" fallbacks --- src/MPoly.jl | 16 ++++++++++++++++ src/generic/imports.jl | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/src/MPoly.jl b/src/MPoly.jl index 1e17b03985..8389d2f660 100644 --- a/src/MPoly.jl +++ b/src/MPoly.jl @@ -488,6 +488,22 @@ function is_monomial(x::MPolyRingElem{T}) where T <: RingElement return length(x) == 1 && isone(first(coefficients(x))) end +function exponent_vector!(e::Vector{S}, a::MPolyRingElem{T}, i::Int) where {T <: RingElement, S} + return S.(exponent_vector(a, i)) +end + +function coeff!(c::T, a::MPolyRingElem{T}, i::Int) where {T <: RingElement} + return coeff(a, i) +end + +function term!(t::T, a::T, i::Int) where {T <: MPolyRingElem} + return term(a, i) +end + +function monomial!(m::T, a::T, i::Int) where {T <: MPolyRingElem} + return monomial(a, i) +end + ############################################################################### # # Iterators diff --git a/src/generic/imports.jl b/src/generic/imports.jl index a99bd175ee..928fd83b8f 100644 --- a/src/generic/imports.jl +++ b/src/generic/imports.jl @@ -107,6 +107,7 @@ import ..AbstractAlgebra: characteristic import ..AbstractAlgebra: check_parent import ..AbstractAlgebra: codomain import ..AbstractAlgebra: coeff +import ..AbstractAlgebra: coeff! import ..AbstractAlgebra: coefficient_ring import ..AbstractAlgebra: coefficient_ring_type import ..AbstractAlgebra: coefficients @@ -131,6 +132,7 @@ import ..AbstractAlgebra: elem_type import ..AbstractAlgebra: evaluate import ..AbstractAlgebra: exp import ..AbstractAlgebra: exponent_vectors +import ..AbstractAlgebra: exponent_vector! import ..AbstractAlgebra: expressify import ..AbstractAlgebra: factor import ..AbstractAlgebra: factor_squarefree @@ -178,6 +180,7 @@ import ..AbstractAlgebra: max_precision import ..AbstractAlgebra: minpoly import ..AbstractAlgebra: modulus import ..AbstractAlgebra: monomials +import ..AbstractAlgebra: monomial! import ..AbstractAlgebra: mul! import ..AbstractAlgebra: mul_classical import ..AbstractAlgebra: mul_karatsuba @@ -217,6 +220,7 @@ import ..AbstractAlgebra: symbols import ..AbstractAlgebra: tail import ..AbstractAlgebra: term_degree import ..AbstractAlgebra: terms +import ..AbstractAlgebra: term! import ..AbstractAlgebra: terms_degrees import ..AbstractAlgebra: terse import ..AbstractAlgebra: to_univariate From d6fdbb74e1f33667fd305dfc9c52780a43f95299 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Wed, 5 Nov 2025 15:40:47 +0100 Subject: [PATCH 09/12] Re-add the "default" constructor --- src/generic/GenericTypes.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/generic/GenericTypes.jl b/src/generic/GenericTypes.jl index 78b5a312c9..4c4aa420b4 100644 --- a/src/generic/GenericTypes.jl +++ b/src/generic/GenericTypes.jl @@ -416,6 +416,10 @@ mutable struct MPolyExponentVectors{T <: AbstractAlgebra.RingElem, S} return I end + function MPolyExponentVectors(f::AbstractAlgebra.NCRingElem) + return MPolyExponentVectors(Vector{Int}, f) + end + function MPolyExponentVectors(f::AbstractAlgebra.NCRingElem, inplace::Bool, temp::S) where S return new{typeof(f), S}(f, inplace, temp) end From 4adaf5dc1ea22ed4c45dfbac671d001e71062ba8 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Wed, 5 Nov 2025 16:28:20 +0100 Subject: [PATCH 10/12] Do it differently --- src/MPoly.jl | 27 ++------ src/generic/GenericTypes.jl | 121 ++++++++++++++++++++---------------- 2 files changed, 72 insertions(+), 76 deletions(-) diff --git a/src/MPoly.jl b/src/MPoly.jl index 8389d2f660..864ba7710c 100644 --- a/src/MPoly.jl +++ b/src/MPoly.jl @@ -517,11 +517,7 @@ Return an iterator for the coefficients of the given polynomial. To retrieve an array of the coefficients, use `collect(coefficients(a))`. """ function coefficients(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement - if inplace - t = zero(coefficient_ring(parent(a))) - return Generic.MPolyCoeffs(a, inplace, t) - end - return Generic.MPolyCoeffs(a) + return Generic.MPolyCoeffs(a, inplace=inplace) end @doc raw""" @@ -532,16 +528,11 @@ retrieve an array of the exponent vectors, use `collect(exponent_vectors(a))`. """ function exponent_vectors(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement - return exponent_vectors(Vector{Int}, a, inplace=inplace) + return Generic.MPolyExponentVectors(a, inplace=inplace) end function exponent_vectors(::Type{Vector{S}}, a::MPolyRingElem{T}; inplace::Bool = false) where {T <: RingElement, S} - if inplace - # Don't use `zeros`: If S === ZZRingElem, then all the entries would be identical - t = [zero(S) for _ in 1:nvars(parent(a))] - return Generic.MPolyExponentVectors(a, inplace, t) - end - return Generic.MPolyExponentVectors(Vector{S}, a) + return Generic.MPolyExponentVectors(Vector{S}, a, inplace=inplace) end @doc raw""" @@ -551,11 +542,7 @@ Return an iterator for the monomials of the given polynomial. To retrieve an array of the monomials, use `collect(monomials(a))`. """ function monomials(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement - if inplace - t = zero(parent(a)) - return Generic.MPolyMonomials(a, inplace, t) - end - return Generic.MPolyMonomials(a) + return Generic.MPolyMonomials(a, inplace=inplace) end @doc raw""" @@ -565,11 +552,7 @@ Return an iterator for the terms of the given polynomial. To retrieve an array of the terms, use `collect(terms(a))`. """ function terms(a::MPolyRingElem{T}; inplace::Bool = false) where T <: RingElement - if inplace - t = zero(parent(a)) - return Generic.MPolyTerms(a, inplace, t) - end - return Generic.MPolyTerms(a) + return Generic.MPolyTerms(a, inplace=inplace) end ############################################################################### diff --git a/src/generic/GenericTypes.jl b/src/generic/GenericTypes.jl index 4c4aa420b4..d0ab9feed7 100644 --- a/src/generic/GenericTypes.jl +++ b/src/generic/GenericTypes.jl @@ -386,77 +386,90 @@ end # Iterators mutable struct MPolyCoeffs{T <: AbstractAlgebra.NCRingElem, S <: AbstractAlgebra.RingElement} - poly::T - inplace::Bool - temp::S # only used if inplace == true - - function MPolyCoeffs(f::AbstractAlgebra.NCRingElem) - I = new{typeof(f), elem_type(coefficient_ring_type(f))}() - I.poly = f - I.inplace = false - return I - end + poly::T + inplace::Bool + temp::S # only used if inplace == true + + function MPolyCoeffs(f::AbstractAlgebra.NCRingElem; inplace::Bool = false) + I = new{typeof(f), elem_type(coefficient_ring_type(f))}() + I.poly = f + I.inplace = inplace + if inplace + I.temp = zero(coefficient_ring(parent(f))) + end + return I + end - function MPolyCoeffs(f::AbstractAlgebra.NCRingElem, inplace::Bool, temp::AbstractAlgebra.RingElement) - return new{typeof(f), typeof(temp)}(f, inplace, temp) - end + function MPolyCoeffs(f::AbstractAlgebra.NCRingElem, inplace::Bool, temp::AbstractAlgebra.RingElement) + return new{typeof(f), typeof(temp)}(f, inplace, temp) + end end # S may be the type of anything that can store an exponent vector, for example # Vector{Int}, ZZMatrix, ... mutable struct MPolyExponentVectors{T <: AbstractAlgebra.RingElem, S} - poly::T - inplace::Bool - temp::S # only used if inplace == true + poly::T + inplace::Bool + temp::S # only used if inplace == true - function MPolyExponentVectors(::Type{S}, f::AbstractAlgebra.NCRingElem) where S - I = new{typeof(f), S}() - I.poly = f - I.inplace = false - return I - end + function MPolyExponentVectors(f::AbstractAlgebra.NCRingElem; inplace::Bool = false) + return MPolyExponentVectors(Vector{Int}, f, inplace=inplace) + end - function MPolyExponentVectors(f::AbstractAlgebra.NCRingElem) - return MPolyExponentVectors(Vector{Int}, f) - end + function MPolyExponentVectors(::Type{Vector{S}}, f::AbstractAlgebra.NCRingElem; inplace::Bool = false) where S + I = new{typeof(f), Vector{S}}() + I.poly = f + I.inplace = inplace + if inplace + # Don't use `zeros`: If S === ZZRingElem, then all the entries would be identical + I.temp = [zero(S) for _ in 1:nvars(parent(f))] + end + return I + end - function MPolyExponentVectors(f::AbstractAlgebra.NCRingElem, inplace::Bool, temp::S) where S - return new{typeof(f), S}(f, inplace, temp) - end + function MPolyExponentVectors(f::AbstractAlgebra.NCRingElem, inplace::Bool, temp::S) where S + return new{typeof(f), S}(f, inplace, temp) + end end mutable struct MPolyTerms{T <: AbstractAlgebra.NCRingElem} - poly::T - inplace::Bool - temp::T # only used if inplace == true - - function MPolyTerms(f::AbstractAlgebra.NCRingElem) - I = new{typeof(f)}() - I.poly = f - I.inplace = false - return I - end + poly::T + inplace::Bool + temp::T # only used if inplace == true + + function MPolyTerms(f::AbstractAlgebra.NCRingElem; inplace::Bool = false) + I = new{typeof(f)}() + I.poly = f + I.inplace = inplace + if inplace + I.temp = zero(parent(f)) + end + return I + end - function MPolyTerms(f::T, inplace::Bool, temp::T) where {T <: AbstractAlgebra.NCRingElem} - return new{T}(f, inplace, temp) - end + function MPolyTerms(f::T, inplace::Bool, temp::T) where {T <: AbstractAlgebra.NCRingElem} + return new{T}(f, inplace, temp) + end end mutable struct MPolyMonomials{T <: AbstractAlgebra.NCRingElem} - poly::T - inplace::Bool - temp::T # only used if inplace == true - - function MPolyMonomials(f::AbstractAlgebra.NCRingElem) - I = new{typeof(f)}() - I.poly = f - I.inplace = false - return I - end + poly::T + inplace::Bool + temp::T # only used if inplace == true + + function MPolyMonomials(f::AbstractAlgebra.NCRingElem; inplace::Bool = false) + I = new{typeof(f)}() + I.poly = f + I.inplace = inplace + if inplace + I.temp = zero(parent(f)) + end + return I + end - function MPolyMonomials(f::T, inplace::Bool, temp::T) where {T <: AbstractAlgebra.NCRingElem} - return new{T}(f, inplace, temp) - end + function MPolyMonomials(f::T, inplace::Bool, temp::T) where {T <: AbstractAlgebra.NCRingElem} + return new{T}(f, inplace, temp) + end end mutable struct MPolyBuildCtx{T, S} From 48c294806aecf6df3ba6e83005528303c21f02ec Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Thu, 6 Nov 2025 09:41:32 +0100 Subject: [PATCH 11/12] Remove some constructors --- src/generic/GenericTypes.jl | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/generic/GenericTypes.jl b/src/generic/GenericTypes.jl index d0ab9feed7..a32fa3358f 100644 --- a/src/generic/GenericTypes.jl +++ b/src/generic/GenericTypes.jl @@ -399,10 +399,6 @@ mutable struct MPolyCoeffs{T <: AbstractAlgebra.NCRingElem, S <: AbstractAlgebra end return I end - - function MPolyCoeffs(f::AbstractAlgebra.NCRingElem, inplace::Bool, temp::AbstractAlgebra.RingElement) - return new{typeof(f), typeof(temp)}(f, inplace, temp) - end end # S may be the type of anything that can store an exponent vector, for example @@ -426,10 +422,6 @@ mutable struct MPolyExponentVectors{T <: AbstractAlgebra.RingElem, S} end return I end - - function MPolyExponentVectors(f::AbstractAlgebra.NCRingElem, inplace::Bool, temp::S) where S - return new{typeof(f), S}(f, inplace, temp) - end end mutable struct MPolyTerms{T <: AbstractAlgebra.NCRingElem} @@ -446,10 +438,6 @@ mutable struct MPolyTerms{T <: AbstractAlgebra.NCRingElem} end return I end - - function MPolyTerms(f::T, inplace::Bool, temp::T) where {T <: AbstractAlgebra.NCRingElem} - return new{T}(f, inplace, temp) - end end mutable struct MPolyMonomials{T <: AbstractAlgebra.NCRingElem} @@ -466,10 +454,6 @@ mutable struct MPolyMonomials{T <: AbstractAlgebra.NCRingElem} end return I end - - function MPolyMonomials(f::T, inplace::Bool, temp::T) where {T <: AbstractAlgebra.NCRingElem} - return new{T}(f, inplace, temp) - end end mutable struct MPolyBuildCtx{T, S} From a597880774658a891c31e0e953e58251534f6513 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Thu, 6 Nov 2025 09:54:49 +0100 Subject: [PATCH 12/12] Increase the odds --- src/generic/GenericTypes.jl | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/generic/GenericTypes.jl b/src/generic/GenericTypes.jl index a32fa3358f..d35094a6b8 100644 --- a/src/generic/GenericTypes.jl +++ b/src/generic/GenericTypes.jl @@ -391,9 +391,7 @@ mutable struct MPolyCoeffs{T <: AbstractAlgebra.NCRingElem, S <: AbstractAlgebra temp::S # only used if inplace == true function MPolyCoeffs(f::AbstractAlgebra.NCRingElem; inplace::Bool = false) - I = new{typeof(f), elem_type(coefficient_ring_type(f))}() - I.poly = f - I.inplace = inplace + I = new{typeof(f), elem_type(coefficient_ring_type(f))}(f, inplace) if inplace I.temp = zero(coefficient_ring(parent(f))) end @@ -413,9 +411,7 @@ mutable struct MPolyExponentVectors{T <: AbstractAlgebra.RingElem, S} end function MPolyExponentVectors(::Type{Vector{S}}, f::AbstractAlgebra.NCRingElem; inplace::Bool = false) where S - I = new{typeof(f), Vector{S}}() - I.poly = f - I.inplace = inplace + I = new{typeof(f), Vector{S}}(f, inplace) if inplace # Don't use `zeros`: If S === ZZRingElem, then all the entries would be identical I.temp = [zero(S) for _ in 1:nvars(parent(f))] @@ -430,9 +426,7 @@ mutable struct MPolyTerms{T <: AbstractAlgebra.NCRingElem} temp::T # only used if inplace == true function MPolyTerms(f::AbstractAlgebra.NCRingElem; inplace::Bool = false) - I = new{typeof(f)}() - I.poly = f - I.inplace = inplace + I = new{typeof(f)}(f, inplace) if inplace I.temp = zero(parent(f)) end @@ -446,9 +440,7 @@ mutable struct MPolyMonomials{T <: AbstractAlgebra.NCRingElem} temp::T # only used if inplace == true function MPolyMonomials(f::AbstractAlgebra.NCRingElem; inplace::Bool = false) - I = new{typeof(f)}() - I.poly = f - I.inplace = inplace + I = new{typeof(f)}(f, inplace) if inplace I.temp = zero(parent(f)) end