Skip to content
36 changes: 28 additions & 8 deletions src/MPoly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -500,8 +516,8 @@ 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
return Generic.MPolyCoeffs(a, inplace=inplace)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return Generic.MPolyCoeffs(a, inplace=inplace)
return Generic.MPolyCoeffs(a; inplace)

IMO a bit neater, but I don't really care

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never really got the hang of this syntax, so if you don't care, I'll prefer my version.

end

@doc raw"""
Expand All @@ -511,8 +527,12 @@ 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
return Generic.MPolyExponentVectors(a, inplace=inplace)
end

function exponent_vectors(::Type{Vector{S}}, a::MPolyRingElem{T}; inplace::Bool = false) where {T <: RingElement, S}
return Generic.MPolyExponentVectors(Vector{S}, a, inplace=inplace)
end

@doc raw"""
Expand All @@ -521,8 +541,8 @@ 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
return Generic.MPolyMonomials(a, inplace=inplace)
end

@doc raw"""
Expand All @@ -531,8 +551,8 @@ 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
return Generic.MPolyTerms(a, inplace=inplace)
end

###############################################################################
Expand Down
3 changes: 3 additions & 0 deletions src/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
63 changes: 55 additions & 8 deletions src/generic/GenericTypes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -385,20 +385,67 @@ end

# Iterators

struct MPolyCoeffs{T <: AbstractAlgebra.NCRingElem}
poly::T
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; inplace::Bool = false)
I = new{typeof(f), elem_type(coefficient_ring_type(f))}(f, inplace)
if inplace
I.temp = zero(coefficient_ring(parent(f)))
end
return I
end
end

struct MPolyExponentVectors{T <: AbstractAlgebra.RingElem}
poly::T
# 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

function MPolyExponentVectors(f::AbstractAlgebra.NCRingElem; inplace::Bool = false)
return MPolyExponentVectors(Vector{Int}, f, inplace=inplace)
end

function MPolyExponentVectors(::Type{Vector{S}}, f::AbstractAlgebra.NCRingElem; inplace::Bool = false) where S
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))]
end
return I
end
end

struct MPolyTerms{T <: AbstractAlgebra.NCRingElem}
poly::T
mutable struct MPolyTerms{T <: AbstractAlgebra.NCRingElem}
poly::T
inplace::Bool
temp::T # only used if inplace == true

function MPolyTerms(f::AbstractAlgebra.NCRingElem; inplace::Bool = false)
I = new{typeof(f)}(f, inplace)
if inplace
I.temp = zero(parent(f))
end
return I
end
end

struct MPolyMonomials{T <: AbstractAlgebra.NCRingElem}
poly::T
mutable struct MPolyMonomials{T <: AbstractAlgebra.NCRingElem}
poly::T
inplace::Bool
temp::T # only used if inplace == true

function MPolyMonomials(f::AbstractAlgebra.NCRingElem; inplace::Bool = false)
I = new{typeof(f)}(f, inplace)
if inplace
I.temp = zero(parent(f))
end
return I
end
end

mutable struct MPolyBuildCtx{T, S}
Expand Down
115 changes: 56 additions & 59 deletions src/generic/MPoly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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{S}, a::MPoly{T}, i::Int) where {T <: RingElement, S}
@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] = S(A[j, i])
k += 1
end
return e
end

@doc raw"""
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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
Comment on lines +684 to +686
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit ugly, but it gets the monomials iterator to constant allocations. Otherwise it would allocate a new 1 all the time. Is this too much of a corner case?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine to me

m.length = 1
return m
end
Expand All @@ -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"""
Expand Down Expand Up @@ -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
Expand All @@ -876,12 +873,12 @@ 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

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
Expand Down
3 changes: 3 additions & 0 deletions src/generic/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -122,6 +124,7 @@ export summands
export supermodule
export term
export terms
export term!
export to_univariate
export total_degree
export trailing_coefficient
Expand Down
Loading
Loading