From 8ed70d8f36c26a0a77736c19880b4dabcbde70f2 Mon Sep 17 00:00:00 2001 From: john verzani Date: Fri, 8 Sep 2023 16:59:22 -0400 Subject: [PATCH] Sparse vector polynomial (#536) * WIP, add SparseVectorPolynomial * add SparseVector container * SparseVectorPolynomial needs zero(T) * NaN poisons, Inf propogates. No good rational, but ... --- Project.toml | 3 +- src/Polynomials.jl | 5 +- src/common.jl | 20 +- .../immutable-dense-polynomial.jl | 2 +- .../mutable-sparse-vector-polynomial.jl | 242 ++++++++++++++++++ .../standard-basis/sparse-polynomial.jl | 4 +- .../sparse-vector-polynomial.jl | 87 +++++++ .../standard-basis/standard-basis.jl | 13 +- test/StandardBasis.jl | 16 +- 9 files changed, 364 insertions(+), 28 deletions(-) create mode 100644 src/polynomial-container-types/mutable-sparse-vector-polynomial.jl create mode 100644 src/polynomials/standard-basis/sparse-vector-polynomial.jl diff --git a/Project.toml b/Project.toml index 7e92cdef..f683573f 100644 --- a/Project.toml +++ b/Project.toml @@ -2,13 +2,14 @@ name = "Polynomials" uuid = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" license = "MIT" author = "JuliaMath" -version = "4.0.2" +version = "4.0.3" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [weakdeps] ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" diff --git a/src/Polynomials.jl b/src/Polynomials.jl index 3fbf66ec..61ab46f2 100644 --- a/src/Polynomials.jl +++ b/src/Polynomials.jl @@ -4,6 +4,7 @@ module Polynomials using LinearAlgebra import Base: evalpoly using Setfield +using SparseArrays include("abstract.jl") include("show.jl") @@ -20,8 +21,9 @@ include("polynomial-container-types/mutable-dense-view-polynomial.jl") include("polynomial-container-types/mutable-dense-laurent-polynomial.jl") include("polynomial-container-types/immutable-dense-polynomial.jl") include("polynomial-container-types/mutable-sparse-polynomial.jl") +include("polynomial-container-types/mutable-sparse-vector-polynomial.jl") const PolynomialContainerTypes = (:MutableDensePolynomial, :MutableDenseViewPolynomial, :ImmutableDensePolynomial, - :MutableDenseLaurentPolynomial, :MutableSparsePolynomial) # useful for some purposes + :MutableDenseLaurentPolynomial, :MutableSparsePolynomial, :MutableSparseVectorPolynomial) # useful for some purposes const ZeroBasedDensePolynomialContainerTypes = (:MutableDensePolynomial, :MutableDenseViewPolynomial, :ImmutableDensePolynomial) include("polynomials/standard-basis/standard-basis.jl") @@ -30,6 +32,7 @@ include("polynomials/standard-basis/pn-polynomial.jl") include("polynomials/standard-basis/laurent-polynomial.jl") include("polynomials/standard-basis/immutable-polynomial.jl") include("polynomials/standard-basis/sparse-polynomial.jl") +include("polynomials/standard-basis/sparse-vector-polynomial.jl") include("polynomials/ngcd.jl") include("polynomials/multroot.jl") diff --git a/src/common.jl b/src/common.jl index 6bc837d8..4d7af6cb 100644 --- a/src/common.jl +++ b/src/common.jl @@ -311,15 +311,17 @@ end In-place version of [`truncate`](@ref) """ -function truncate!(p::AbstractPolynomial{T}; +truncate!(p::AbstractPolynomial; kwargs...) = _truncate!(p; kwargs...) + +function _truncate!(p::AbstractPolynomial{T}; rtol::Real = Base.rtoldefault(real(T)), atol::Real = 0,) where {T} - truncate!(p.coeffs, rtol=rtol, atol=atol) + _truncate!(p.coeffs, rtol=rtol, atol=atol) chop!(p, rtol = rtol, atol = atol) end -## truncate! underlying storage type -function truncate!(ps::Vector{T}; +## _truncate! underlying storage type +function _truncate!(ps::Vector{T}; rtol::Real = Base.rtoldefault(real(T)), atol::Real = 0,) where {T} max_coeff = norm(ps, Inf) @@ -332,7 +334,7 @@ function truncate!(ps::Vector{T}; nothing end -function truncate!(ps::Dict{S,T}; +function _truncate!(ps::Dict{S,T}; rtol::Real = Base.rtoldefault(real(T)), atol::Real = 0,) where {S,T} @@ -348,7 +350,7 @@ function truncate!(ps::Dict{S,T}; nothing end -truncate!(ps::NTuple; kwargs...) = throw(ArgumentError("`truncate!` not defined.")) +_truncate!(ps::NTuple; kwargs...) = throw(ArgumentError("`truncate!` not defined for tuples.")) # _truncate(ps::NTuple{0}; kwargs...) = ps # function _truncate(ps::NTuple{N,T}; @@ -370,7 +372,7 @@ Rounds off coefficients close to zero, as determined by `rtol` and `atol`, and t function Base.truncate(p::AbstractPolynomial{T}; rtol::Real = Base.rtoldefault(real(T)), atol::Real = 0,) where {T} - truncate!(deepcopy(p), rtol = rtol, atol = atol) + _truncate!(deepcopy(p), rtol = rtol, atol = atol) end """ @@ -455,8 +457,8 @@ end # for generic usage, as immutable types are not mutable -chop!!(p::AbstractPolynomial; kwargs...) = (p = chop!(p); p) -truncate!!(p::AbstractPolynomial; kwargs...) = truncate!(p) +chop!!(p::AbstractPolynomial; kwargs...) = (p = chop!(p; kwargs...); p) +truncate!!(p::AbstractPolynomial; kwargs...) = _truncate!(p; kwargs...) ## -------------------------------------------------- diff --git a/src/polynomial-container-types/immutable-dense-polynomial.jl b/src/polynomial-container-types/immutable-dense-polynomial.jl index 1d30d4f9..d8fb2b96 100644 --- a/src/polynomial-container-types/immutable-dense-polynomial.jl +++ b/src/polynomial-container-types/immutable-dense-polynomial.jl @@ -128,7 +128,7 @@ end chop!(p::ImmutableDensePolynomial; kwargs...) = chop(p; kwargs...) ## misnamed, should be chop!! chop!!(p::ImmutableDensePolynomial; kwargs...) = chop(p; kwargs...) -function truncate!(p::ImmutableDensePolynomial{B,T,X,N}; +function _truncate!(p::ImmutableDensePolynomial{B,T,X,N}; rtol::Real = Base.rtoldefault(real(T)), atol::Real = 0) where {B,T,X,N} diff --git a/src/polynomial-container-types/mutable-sparse-vector-polynomial.jl b/src/polynomial-container-types/mutable-sparse-vector-polynomial.jl new file mode 100644 index 00000000..ac8960ac --- /dev/null +++ b/src/polynomial-container-types/mutable-sparse-vector-polynomial.jl @@ -0,0 +1,242 @@ +""" + MutableSparseVectorPolynomial{B,T,X} + +This polynomial type uses an `SparseVector{T,Int}` to store the coefficients of a polynomial relative to the basis `B` with indeterminate `X`. +The type `T` should have `zero(T)` defined. + + +""" +struct MutableSparseVectorPolynomial{B,T,X} <: AbstractUnivariatePolynomial{B, T,X} + coeffs::SparseVector{T, Int} + function MutableSparseVectorPolynomial{B,T,X}(cs::SparseVector{S,Int}, order::Int=0) where {B,T,S,X} + new{B,T,Symbol(X)}(cs) + end +end + +MutableSparseVectorPolynomial{B,T,X}(check::Val{:false}, coeffs::SparseVector{Int,S}) where {B,T,S,X} = + MutableSparseVectorPolynomial{B,T,X}(coeffs) +MutableSparseVectorPolynomial{B,T,X}(checked::Val{:true}, coeffs::SparseVector{Int,T}) where {B,T,X<:Symbol} = + MutableSparseVectorPolynomial{B,T,X}(coeffs) + +# --- +function MutableSparseVectorPolynomial{B,T}(coeffs::SparseVector{S,Int}, var::SymbolLike=Var(:x)) where {B,T,S} + MutableSparseVectorPolynomial{B,T,Symbol(var)}(coeffs) +end + +function MutableSparseVectorPolynomial{B}(cs::SparseVector{T,Int}, var::SymbolLike=Var(:x)) where {B,T} + MutableSparseVectorPolynomial{B,T,Symbol(var)}(cs) +end + +# From a Dictionary +function MutableSparseVectorPolynomial{B,X}(cs::AbstractDict{Int, T}) where {B,T,X} + N = maximum(keys(cs)) + 1 + v = SparseVector(N, 1 .+ keys(cs), collect(values(cs))) + MutableSparseVectorPolynomial{B,T,X}(v) +end + +function MutableSparseVectorPolynomial{B}(cs::AbstractDict{Int, T}, var::SymbolLike=Var(:x)) where {B,T} + MutableSparseVectorPolynomial{B,Symbol(var)}(cs) +end + + +# abstract vector has order/symbol +function MutableSparseVectorPolynomial{B,T,X}(coeffs::AbstractVector{S}, order::Int=0) where {B,T,S,X} + if Base.has_offset_axes(coeffs) + @warn "ignoring the axis offset of the coefficient vector" + coeffs = parent(coeffs) + end + + MutableSparseVectorPolynomial{B,T,X}(convert(SparseVector, coeffs)) +end + + +# # cs iterable of pairs; ensuring tight value of T +# function MutableSparseVectorPolynomial{B}(cs::Tuple, var::SymbolLike=:x) where {B} +# isempty(cs) && throw(ArgumentError("No type attached")) +# X = Var(var) +# if length(cs) == 1 +# c = only(cs) +# d = Dict(first(c) => last(c)) +# T = eltype(last(c)) +# return MutableSparseVectorPolynomial{B,T,X}(d) +# else +# c₁, c... = cs +# T = typeof(last(c₁)) +# for b ∈ c +# T = promote_type(T, typeof(b)) +# end +# ks = 0:length(cs)-1 +# vs = cs +# d = Dict{Int,T}(Base.Generator(=>, ks, vs)) +# return MutableSparseVectorPolynomial{B,T,X}(d) +# end +# end + +constructorof(::Type{<:MutableSparseVectorPolynomial{B}}) where {B <: AbstractBasis} = MutableSparseVectorPolynomial{B} +@poly_register MutableSparseVectorPolynomial + +function Base.map(fn, p::P, args...) where {B,T,X, P<:MutableSparseVectorPolynomial{B,T,X}} + xs = map(fn, p.coeffs) + R = eltype(xs) + return MutableSparseVectorPolynomial{B, R, X}(xs) +end + +function Base.map!(fn, q::Q, p::P, args...) where {B,T,X, P<:MutableSparseVectorPolynomial{B,T,X},S,Q<:MutableSparseVectorPolynomial{B,S,X}} + map!(fn, p.coeffs, p.coeffs) + nothing +end + +## --- +Base.collect(p::MutableSparseVectorPolynomial) = collect(p.coeffs) +Base.collect(::Type{T}, p::MutableSparseVectorPolynomial) where {T} = collect(T, p.coeffs) +minimumexponent(::Type{<:MutableSparseVectorPolynomial}) = 0 + +Base.length(p::MutableSparseVectorPolynomial) = length(p.coeffs) + +function degree(p::MutableSparseVectorPolynomial) + idx = findall(!iszero, p.coeffs) + isempty(idx) && return -1 + n = maximum(idx) + n - 1 +end + +Base.copy(p::MutableSparseVectorPolynomial{B,T,X}) where {B,T,X} = MutableSparseVectorPolynomial{B,T,X}(copy(p.coeffs)) + +function Base.convert(::Type{MutableSparseVectorPolynomial{B,T,X}}, p::MutableSparseVectorPolynomial{B,S,X}) where {B,T,S,X} + cs = convert(SparseVector{T,Int}, p.coeffs) + MutableSparseVectorPolynomial{B,T,X}(cs) +end + +function Base.:(==)(p1::P, p2::P) where {P <: MutableSparseVectorPolynomial} + iszero(p1) && iszero(p2) && return true + + ks1 = findall(!iszero, p1.coeffs) + ks2 = findall(!iszero, p2.coeffs) + length(ks1) == length(ks2) || return false + idx = sortperm(ks1) + for i ∈ idx + ks1[i] == ks2[i] || return false + p1.coeffs[ks1[i]] == p2.coeffs[ks2[i]] || return false + end + + return true + # # eachindex(p1) == eachindex(p2) || return false + # # coeffs(p1) == coeffs(p2), but non-allocating + # p1val = (p1[i] for i in eachindex(p1)) + # p2val = (p2[i] for i in eachindex(p2)) + # all(((a,b),) -> a == b, zip(p1val, p2val)) +end + +# --- + +Base.firstindex(p::MutableSparseVectorPolynomial) = 0 +function Base.lastindex(p::MutableSparseVectorPolynomial) + isempty(p.coeffs) && return 0 + maximum(keys(p.coeffs)) +end + +function Base.getindex(p::MutableSparseVectorPolynomial{B,T,X}, i::Int) where {B,T,X} + get(p.coeffs, i + 1, zero(T)) +end + +# errors if extending +function Base.setindex!(p::MutableSparseVectorPolynomial{B,T,X}, value, i::Int) where {B,T,X} + p.coeffs[i+1] = value +end + + +function Base.pairs(p::MutableSparseVectorPolynomial) + ks, vs = findnz(p.coeffs) + idx = sortperm(ks) # guarantee order here + Base.Generator(=>, ks[idx] .- 1, vs) +end +Base.keys(p::MutableSparseVectorPolynomial) = Base.Generator(first, pairs(p)) +Base.values(p::MutableSparseVectorPolynomial) = Base.Generator(last, pairs(p)) + +basis(P::Type{<:MutableSparseVectorPolynomial{B, T, X}}, i::Int) where {B,T,X} = P(SparseVector(1+i, [i+1], [1])) + +# return coeffs as a vector +function coeffs(p::MutableSparseVectorPolynomial{B,T}) where {B,T} + d = degree(p) + ps = p.coeffs + [ps[i] for i ∈ 1:(d+1)] +end + + +hasnan(p::MutableSparseVectorPolynomial) = any(hasnan, values(p.coeffs))::Bool + + +offset(p::MutableSparseVectorPolynomial) = 1 + +function keys_union(p::MutableSparseVectorPolynomial, q::MutableSparseVectorPolynomial) + # IterTools.distinct(Base.Iterators.flatten((keys(p), keys(q)))) may allocate less + unique(Base.Iterators.flatten((keys(p), keys(q)))) +end + + + +## --- + +chop_exact_zeros!(d::SparseVector{T, Int}) where {T} = d + + +function _truncate!(v::SparseVector{T,X}; + rtol::Real = Base.rtoldefault(real(T)), + atol::Real = 0) where {T,X} + isempty(v) && return v + δ = something(rtol,0) + ϵ = something(atol,0) + τ = max(ϵ, norm(values(v),2) * δ) + for (i,pᵢ) ∈ pairs(v) + abs(pᵢ) ≤ τ && (v[i] = zero(T)) + end + v +end + + +chop!(p::MutableSparseVectorPolynomial; kwargs...) = (chop!(p.coeffs; kwargs...); p) +function chop!(d::SparseVector{T, Int}; atol=nothing, rtol=nothing) where {T} + isempty(d) && return d + δ = something(rtol,0) + ϵ = something(atol,0) + τ = max(ϵ, norm(values(d),2) * δ) + for (i, pᵢ) ∈ Base.Iterators.reverse(pairs(d)) + abs(pᵢ) ≥ τ && break + d[i] = zero(T) + end + d +end + +## --- + +_zeros(::Type{MutableSparseVectorPolynomial{B,T,X}}, z::S, N) where {B,T,X,S} = zeros(T, N) + +Base.zero(::Type{MutableSparseVectorPolynomial{B,T,X}}) where {B,T,X} = MutableSparseVectorPolynomial{B,T,X}(spzeros(T,0)) + +## --- + +function isconstant(p::MutableSparseVectorPolynomial) + degree(p) <= 0 +end + +Base.:+(p::MutableSparseVectorPolynomial{B,T,X}, q::MutableSparseVectorPolynomial{B,S,X}) where{B,X,T,S} = + _sparse_vector_combine(+, p, q) +Base.:-(p::MutableSparseVectorPolynomial{B,T,X}, q::MutableSparseVectorPolynomial{B,S,X}) where{B,X,T,S} = + _sparse_vector_combine(-, p, q) + +# embed into bigger vector +function _embed(v::SparseVector{T, Int}, l) where {T} + l == length(v) && return v + ks,vs = findnz(v) + SparseVector(l, ks, vs) +end + + +function _sparse_vector_combine(op, p::MutableSparseVectorPolynomial{B,T,X}, q::MutableSparseVectorPolynomial{B,S,X}) where{B,X,T,S} + R = promote_type(T,S) + ps, qs = p.coeffs, q.coeffs + m = max(length(ps), length(qs)) + ps′, qs′ = _embed(ps, m), _embed(qs, m) + cs = op(ps′, qs′) + MutableSparseVectorPolynomial{B,R,X}(cs) +end diff --git a/src/polynomials/standard-basis/sparse-polynomial.jl b/src/polynomials/standard-basis/sparse-polynomial.jl index 92fcbee6..ae2b7cfd 100644 --- a/src/polynomials/standard-basis/sparse-polynomial.jl +++ b/src/polynomials/standard-basis/sparse-polynomial.jl @@ -45,9 +45,9 @@ export SparsePolynomial _typealias(::Type{P}) where {P<:SparsePolynomial} = "SparsePolynomial" -function evalpoly(x, p::MutableSparsePolynomial) +function evalpoly(x, p::SparsePolynomial) tot = zero(p[0]*x) - for (i, cᵢ) ∈ p.coeffs + for (i, cᵢ) ∈ pairs(p) tot = muladd(cᵢ, x^i, tot) end return tot diff --git a/src/polynomials/standard-basis/sparse-vector-polynomial.jl b/src/polynomials/standard-basis/sparse-vector-polynomial.jl new file mode 100644 index 00000000..7a6e7186 --- /dev/null +++ b/src/polynomials/standard-basis/sparse-vector-polynomial.jl @@ -0,0 +1,87 @@ +""" + SparseVectorPolynomial{T, [X]}(coeffs::AbstractVector{T}, [var = :x]) + +A polynomial using a sparse vector for holding the coefficients. + +Expects `zero(T)` to be defined. + +See also [SparsePolynomial](@ref) which uses a dictionary to store the coefficients. Compared to that, some basic operations are faster, some not so (addition). +``` +""" +const SparseVectorPolynomial = MutableSparseVectorPolynomial{StandardBasis} +#export SparseVectorPolynomial + +_typealias(::Type{P}) where {P<:SparseVectorPolynomial} = "SparseVectorPolynomial" + +# generally faster to use zip(findnz(p.coeffs)...) with an offset than pairs(p), which sorts +function evalpoly(x, p::SparseVectorPolynomial) + tot = zero(p[0]*x) + for (i, cᵢ) ∈ zip(findnz(p.coeffs)...) + j = i - 1 + tot = muladd(cᵢ, x^j, tot) + end + return tot +end + +function scalar_add(c::S, p::P) where {B<:StandardBasis, S, T, X, P<:MutableSparseVectorPolynomial{B,T,X}} + R = promote_type(S,T) + Q = MutableSparseVectorPolynomial{B,R,X} + isempty(p.coeffs) && return Q([c]) + + cs = similar(p.coeffs, R) + copy!(cs, p.coeffs) + cs[1] += c + Q(cs) + +end + +function Base.:*(p::MutableSparseVectorPolynomial{StandardBasis,T,X}, + q::MutableSparseVectorPolynomial{StandardBasis,S,X}) where {T,S,X} + + n,m = length(p), length(q) + R = promote_type(T,S) + cs = spzeros(R, 1 + n + m) + + @inbounds for (i, aᵢ) ∈ zip(findnz(p.coeffs)...) #pairs(p) + for (j, aⱼ) ∈ zip(findnz(q.coeffs)...) #pairs(q) + k = i + j - 2 + cs[k + 1] = muladd(aᵢ, aⱼ, cs[k+1]) + end + end + + MutableSparseVectorPolynomial{StandardBasis,R,X}(cs) +end + +function derivative(p:: MutableSparseVectorPolynomial{B,T,X}) where {B<:StandardBasis,T,X} + n = length(p) + R = promote_type(T, Int) + P = MutableSparseVectorPolynomial{StandardBasis,R,X} + iszero(n) && return zero(P) + + cs = spzeros(R, n) + + @inbounds for (i, aᵢ) ∈ zip(findnz(p.coeffs)...) #pairs(p) + !isfinite(aᵢ) && isnan(aᵢ) && return P([NaN]) + j = i - 1 + iszero(j) && continue + cs[j] = j * aᵢ + end + + P(cs) +end + +function integrate(p::MutableSparseVectorPolynomial{B,T,X}) where {B<:StandardBasis,T,X} + n = length(p) + R = Base.promote_op(/, T, Int) + P = MutableSparseVectorPolynomial{StandardBasis,R,X} + iszero(n) && return zero(P) + cs = spzeros(R, n+1) + + @inbounds for (i, aᵢ) ∈ zip(findnz(p.coeffs)...) #pairs(p) + !isfinite(aᵢ) && isnan(aᵢ) && return P([NaN]) + j = i# + 1 + cs[j + 1] = aᵢ / j + end + + P(cs) +end diff --git a/src/polynomials/standard-basis/standard-basis.jl b/src/polynomials/standard-basis/standard-basis.jl index 7d55c242..38f9952f 100644 --- a/src/polynomials/standard-basis/standard-basis.jl +++ b/src/polynomials/standard-basis/standard-basis.jl @@ -113,6 +113,14 @@ function LinearAlgebra.mul!(cs, p::AbstractDenseUnivariatePolynomial, q::Abstrac nothing end +# check for finite +function is_finite_polynomial(pᵢ, P) + isfinite(pᵢ) && return (true, nothing) + isnan(pᵢ) && return (false, P([NaN])) + isinf(pᵢ) && return (false, P([Inf])) + return (true, nothing) +end + # derivative function derivative(p::P) where {B<:StandardBasis, T,X,P<:AbstractDenseUnivariatePolynomial{B,T,X}} @@ -408,7 +416,7 @@ function fromroots(P::Type{<:AbstractDenseUnivariatePolynomial{StandardBasis}}, end function companion(p::P) where {T, P <: AbstractUnivariatePolynomial{StandardBasis,T}} - d = length(p) - 1 + d = degree(p) d < 1 && throw(ArgumentError("Series must have degree greater than 1")) d == 1 && return diagm(0 => [-p[0] / p[1]]) @@ -416,7 +424,7 @@ function companion(p::P) where {T, P <: AbstractUnivariatePolynomial{StandardBas R = eltype(one(T)/one(T)) comp = diagm(-1 => ones(R, d - 1)) - ani = 1 / p[end] + ani = 1 / p[d] for j in 0:(degree(p)-1) comp[1,(d-j)] = -p[j] * ani # along top row has smaller residual than down column end @@ -486,7 +494,6 @@ function roots(p::P; kwargs...) where {T, P <: AbstractUnivariatePolynomial{S k = findfirst(!iszero, as)::Int k == K && return zeros(R, k-1) - # find eigenvalues of the companion matrix of the 0-deflated polynomial comp = companion(⟒(P)(as[k:K], Var(indeterminate(p)))) L = eigvals(comp; kwargs...) diff --git a/test/StandardBasis.jl b/test/StandardBasis.jl index 19a73b93..6d3c9892 100644 --- a/test/StandardBasis.jl +++ b/test/StandardBasis.jl @@ -28,7 +28,7 @@ _isimmutable(::Type{P}) where {P <: Union{ImmutablePolynomial, FactoredPolynomia _isimmutable(P) = false -Ps = (ImmutablePolynomial, Polynomial, SparsePolynomial, LaurentPolynomial, FactoredPolynomial) +Ps = (ImmutablePolynomial, Polynomial, SparsePolynomial, LaurentPolynomial, FactoredPolynomial, Polynomials.SparseVectorPolynomial) @testset "Construction" begin @testset for coeff in Any[ @@ -524,7 +524,7 @@ end # evaluation at special cases different number types @testset for P ∈ Ps - P ∈ (SparsePolynomial, FactoredPolynomial) && continue + P ∈ (SparsePolynomial, Polynomials.SparseVectorPolynomial, FactoredPolynomial) && continue # vector coefficients v₀, v₁ = [1,1,1], [1,2,3] p₁ = P([v₀]) @@ -548,7 +548,7 @@ end # p - p requires a zero @testset for P ∈ Ps - P ∈ (LaurentPolynomial, SparsePolynomial,FactoredPolynomial) && continue + P ∈ (LaurentPolynomial, SparsePolynomial, Polynomials.SparseVectorPolynomial, FactoredPolynomial) && continue for v ∈ ([1,2,3], [[1,2,3],[1,2,3]], [[1 2;3 4], [3 4; 5 6]] @@ -625,7 +625,7 @@ end # Check for isequal p1 = P([1.0, -0.0, 5.0, Inf]) p2 = P([1.0, 0.0, 5.0, Inf]) - !(P ∈ (FactoredPolynomial, SparsePolynomial)) && (@test p1 == p2 && !isequal(p1, p2)) # SparsePolynomial doesn't store -0.0, 0.0. + !(P ∈ (FactoredPolynomial, SparsePolynomial, Polynomials.SparseVectorPolynomial)) && (@test p1 == p2 && !isequal(p1, p2)) # SparsePolynomial doesn't store -0.0, 0.0. p3 = P([0, NaN]) @test p3 === p3 && p3 ≠ p3 && isequal(p3, p3) @@ -1061,12 +1061,6 @@ end @test_throws ArgumentError derivative(pR, -1) @test integrate(P([1,1,0,0]), 0, 2) == 4.0 - @test derivative(integrate(pN)) ==ᵟ pN - @test integrate(pNULL, 1) ==ᵟ p1 - rc = Rational{Int64}[1,2,3] - @test integrate(P(rc)) == P{eltype(rc)}([0, 1, 1, 1]) - - P <: FactoredPolynomial && continue @testset for i in 1:10 @@ -1320,7 +1314,7 @@ end # setindex p1 = P([1,2,1]) - if !_isimmutable(P) + if !_isimmutable(P) && P != Polynomials.SparseVectorPolynomial p1[5] = 1 @test p1[5] == 1 @test p1 == P([1,2,1,0,0,1])