Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 12 additions & 35 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,49 +69,26 @@ MP.nvariables(::Union{Term{C,M},Type{Term{C,M}},Polynomial{C,Term{C,M}},Type{<:P
MP.variables(::Union{AbstractVector{PT},Type{<:AbstractVector{PT}}}) where {C,M<:Monomial,PT<:Union{MonomialLike,Term{C,M},Polynomial{C,Term{C,M}}}} = variables(PT)
MP.nvariables(::Union{AbstractVector{PT},Type{<:AbstractVector{PT}}}) where {C,M<:Monomial,PT<:Union{MonomialLike,Term{C,M},Polynomial{C,Term{C,M}}}} = nvariables(PT)

# TODO replace by MP function
function _error_for_negative_degree(deg)
if deg < 0
throw(ArgumentError("The degree should be a nonnegative number but the provided degree `$deg` is negative."))
end
end

# Based on fillZfordeg!() from MultivariatePolynomials.jl by Benoit Legat
# https://github.com/blegat/MultivariatePolynomials.jl/blob/d85ad85de413afa20fc8f5354c980387218ced2c/src/mono.jl#L186-L259
function monomial_powers(::Val{N}, degree) where N
_error_for_negative_degree(degree)
result = Vector{NTuple{N, Int}}()
powers = zeros(Int, N)
powers[end] = degree
while true
push!(result, NTuple{N, Int}(powers))
if powers[1] == degree
break
end
i = findfirst(i -> !iszero(powers[i]), N:-1:2)
j = (N:-1:2)[i]
p = powers[j]
powers[j] = 0
powers[end] = p - 1
powers[j-1] += 1
end
result
end

function MP.monomials(vars::Tuple{Vararg{Variable}}, degree::Integer, filter::Function=m->true)
checksorted(vars, >) || throw(ArgumentError("Variables must be in order"))
Monomial{vars, length(vars)}[Monomial{vars}(p) for p in monomial_powers(Val{length(vars)}(), degree) if filter(Monomial{vars}(p))]
return MP.monomials(vars, [degree], filter)
end

function MP.monomials(vars::Tuple{Vararg{Variable}}, degrees::AbstractArray, filter::Function=m->true)
checksorted(vars, >) || throw(ArgumentError("Variables must be in order"))
if isempty(degrees)
# Otherwise, the following error is thrown: "ArgumentError: argument to Flatten must contain at least one iterator"
Monomial{vars, length(vars)}[]
else
Monomial{vars, length(vars)}[Monomial{vars}(p) for d in sort(degrees)
for p in monomial_powers(Val{length(vars)}(), d) if filter(Monomial{vars}(p))]
return Monomial{vars, length(vars)}[]
end
degs = sort(degrees)
it = Iterators.Filter(MP.ExponentsIterator{MP.Graded{MP.LexOrder}}(
zeros(Int, length(vars));
mindegree = minimum(degrees),
maxdegree = maximum(degrees),
)) do p
mono = Monomial{vars}(p)
MP.degree(mono) in degs && filter(mono)
end
return Monomial{vars, length(vars)}[Monomial{vars}(p) for p in it]
end

MP.promote_variables(a::MonomialLike, b::MonomialLike) = promote(a, b)
12 changes: 0 additions & 12 deletions test/generators.jl
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
@testset "monomial generation" begin
@polyvar x y z

@test TypedPolynomials.monomial_powers(Val{3}(), 3) == reverse([
(3, 0, 0),
(2, 1, 0),
(2, 0, 1),
(1, 2, 0),
(1, 1, 1),
(1, 0, 2),
(0, 3, 0),
(0, 2, 1),
(0, 1, 2),
(0, 0, 3),
])
@test @inferred(monomials((x, y), 2)) == reverse([x^2, x * y, y^2])
@test @inferred(monomials((x, y), 0:2)) == reverse([x^2, x * y, y^2, x, y, 1])
@test @inferred(monomials((x, y), [1, 0, 2])) == reverse([x^2, x * y, y^2, x, y, 1])
Expand Down