9x25dillon's picture
Upload 19 files
60a3e1e verified
export Polynomial
# Invariant:
# a and x might be empty: meaning it is the zero polynomial
# a does not contain any zeros
# x is increasing in the monomial order (i.e. grlex)
struct Polynomial{C, T} <: AbstractPolynomial{T}
a::Vector{T}
x::MonomialVector{C}
function Polynomial{C, T}(a::Vector{T}, x::MonomialVector{C}) where {C, T}
length(a) == length(x) || throw(ArgumentError("There should be as many coefficient than monomials"))
zeroidx = Int[]
for (i,α) in enumerate(a)
if iszero(α)
push!(zeroidx, i)
end
end
if !isempty(zeroidx)
isnz = ones(Bool, length(a))
isnz[zeroidx] .= false
nzidx = findall(isnz)
a = a[nzidx]
x = x[nzidx]
end
new{C, T}(a, x)
end
end
iscomm(::Type{Polynomial{C, T}}) where {C, T} = C
Base.broadcastable(p::Polynomial) = Ref(p)
Base.copy(p::Polynomial{C, T}) where {C, T} = Polynomial{C, T}(copy(p.a), copy(p.x))
Base.zero(::Type{Polynomial{C, T}}) where {C, T} = Polynomial(T[], MonomialVector{C}())
Base.one(::Type{Polynomial{C, T}}) where {C, T} = Polynomial([one(T)], MonomialVector{C}(PolyVar{C}[], [Int[]]))
Base.zero(p::Polynomial{C, T}) where {C, T} = Polynomial(T[], emptymonovec(_vars(p)))
Base.one(p::Polynomial{C, T}) where {C, T} = Polynomial([one(T)], MonomialVector(_vars(p), [zeros(Int, nvariables(p))]))
Polynomial{C, T}(a::AbstractVector, x::MonomialVector) where {C, T} = Polynomial{C, T}(Vector{T}(a), x)
Polynomial{C, T}(a::AbstractVector, X::DMonoVec) where {C, T} = Polynomial{C, T}(monovec(a, X)...)
Polynomial{C}(a::Vector{T}, x) where {C, T} = Polynomial{C, T}(a, x)
Polynomial(af::Union{Function, Vector}, x::DMonoVec{C}) where {C} = Polynomial{C}(af, x)
# TODO Remove with MP v0.2.8
Polynomial{C, T}(p::Polynomial{C, T}) where {C, T} = p
Base.convert(::Type{Polynomial{C, T}}, p::Polynomial{C, T}) where {C, T} = p
function Base.convert(::Type{Polynomial{C, T}},
p::Polynomial{C, S}) where {C, S, T}
return Polynomial{C}(convert(Vector{T}, p.a), p.x)
end
#function convert(::Type{Polynomial{C, T}},
# p::AbstractPolynomialLike) where {C, T}
# return convert(Polynomial{C, T}, polynomial(p, T))
#end
function Base.convert(::Type{Polynomial{C, T}}, t::Term{C}) where {C, T}
return Polynomial{C, T}(T[t.α], [t.x])
end
function Base.convert(::Type{Polynomial{C, T}}, m::DMonomialLike{C}) where {C, T}
return Polynomial(convert(Term{C, T}, m))
end
function MP.convertconstant(::Type{Polynomial{C, T}}, α) where {C, T}
return Polynomial(convert(Term{C, T}, α))
end
Polynomial{C}(p::Union{Polynomial{C}, Term{C}, Monomial{C}, PolyVar{C}}) where {C} = Polynomial(p)
Polynomial{C}(α) where {C} = Polynomial(Term{C}(α))
Polynomial(p::Polynomial) = p
Polynomial(t::Term{C, T}) where {C, T} = Polynomial{C, T}([t.α], [t.x])
Polynomial(x::Union{PolyVar{C}, Monomial{C}}) where {C} = Polynomial(Term{C}(x))
#Base.convert(::Type{TermContainer{C, T}}, p::Polynomial{C}) where {C, T} = Polynomial{C, T}(p)
function Polynomial{C, T}(f::Function, x::MonomialVector{C}) where {C, T}
a = T[f(i) for i in 1:length(x)]
Polynomial{C, T}(a, x)
end
function Polynomial{C, T}(f::Function, x::AbstractVector) where {C, T}
σ, X = sortmonovec(x)
a = T[f(i) for i in σ]
Polynomial{C, T}(a, X)
end
Polynomial{C}(f::Function, x) where {C} = Polynomial{C, Base.promote_op(f, Int)}(f, x)
#Base.convert(::Type{PolyType{C}}, p::TermContainer{C}) where {C} = p
# needed to build [p Q; Q p] where p is a polynomial and Q is a matpolynomial in Julia v0.5
#Base.convert(::Type{TermType{C}}, p::TermContainer{C}) where {C} = p
#Base.convert(::Type{TermType{C, T}}, p::TermContainer{C, T}) where {C, T} = p
Base.length(p::Polynomial) = length(p.a)
Base.isempty(p::Polynomial) = isempty(p.a)
Base.iterate(p::Polynomial) = isempty(p) ? nothing : (p[1], 1)
function Base.iterate(p::Polynomial, state::Int)
state < length(p) ? (p[state+1], state+1) : nothing
end
#eltype(::Type{Polynomial{C, T}}) where {C, T} = T
Base.getindex(p::Polynomial, I::Int) = Term(p.a[I[1]], p.x[I[1]])
#Base.transpose(p::Polynomial) = Polynomial(map(transpose, p.a), p.x) # FIXME invalid age range update
struct TermIterator{C, T} <: AbstractVector{Term{C, T}}
p::Polynomial{C, T}
end
Base.firstindex(p::TermIterator) = firstindex(p.p.a)
Base.lastindex(p::TermIterator) = lastindex(p.p.a)
Base.length(p::TermIterator) = length(p.p.a)
Base.size(p::TermIterator) = (length(p),)
Base.isempty(p::TermIterator) = isempty(p.p.a)
Base.iterate(p::TermIterator) = isempty(p) ? nothing : (p[1], 1)
function Base.iterate(p::TermIterator, state::Int)
state < length(p) ? (p[state+1], state+1) : nothing
end
Base.getindex(p::TermIterator, I::Int) = Term(p.p.a[I[1]], p.p.x[I[1]])
MP.terms(p::Polynomial) = TermIterator(p)
MP.coefficients(p::Polynomial) = p.a
MP.monomials(p::Polynomial) = p.x
_vars(p::Polynomial) = _vars(p.x)
MP.extdegree(p::Polynomial) = extdegree(p.x)
MP.mindegree(p::Polynomial) = mindegree(p.x)
MP.maxdegree(p::Polynomial) = maxdegree(p.x)
MP.leadingcoefficient(p::Polynomial{C, T}) where {C, T} = iszero(p) ? zero(T) : first(p.a)
MP.leadingmonomial(p::Polynomial) = iszero(p) ? constantmonomial(p) : first(p.x)
MP.leadingterm(p::Polynomial) = iszero(p) ? zeroterm(p) : first(terms(p))
function MP.removeleadingterm(p::Polynomial)
Polynomial(p.a[2:end], p.x[2:end])
end
function MP.removemonomials(p::Polynomial, x::MonomialVector)
# use the fact that monomials are sorted to do this O(n) instead of O(n^2)
j = 1
I = Int[]
for (i,t) in enumerate(p)
while j <= length(x) && x[j] > t.x
j += 1
end
if j > length(x) || x[j] != t.x
push!(I, i)
end
end
Polynomial(p.a[I], p.x[I])
end
MP.removemonomials(p::Polynomial, x::Vector) = removemonomials(p, MonomialVector(x))
function removedups(adup::Vector{T}, Zdup::Vector{Vector{Int}}) where {T}
σ = sortperm(Zdup, rev=true, lt=grlex)
Z = Vector{Vector{Int}}()
a = Vector{T}()
i = 0
j = 1
while j <= length(adup)
k = σ[j]
if j == 1 || Zdup[k] != Zdup[σ[j-1]]
push!(Z, Zdup[k])
push!(a, adup[k])
i += 1
else
a[i] += adup[k]
end
j += 1
end
a, Z
end
function polynomialclean(vars::Vector{PolyVar{C}}, adup::Vector{T}, Zdup::Vector{Vector{Int}}) where {C, T}
a, Z = removedups(adup, Zdup)
Polynomial{C, T}(a, MonomialVector{C}(vars, Z))
end
MP.polynomial(a::AbstractVector, x::DMonoVec, s::MP.ListState) = Polynomial(collect(a), x)
#MP.polynomial(f::Function, x::AbstractVector) = Polynomial(f, x)
#MP.polynomial(ts::AbstractVector{Term{C, T}}) where {C, T} = Polynomial(coefficient.(ts), monomial.(ts)) # FIXME invalid age range update
# i < j
function trimap(i, j, n)
div(n*(n+1), 2) - div((n-i+1)*(n-i+2), 2) + j-i+1
end
MP.polynomial(Q::AbstractMatrix{T}, mv::MonomialVector) where T = MP.polynomial(Q, mv, Base.promote_op(+, T, T))
function MP.polynomial(Q::AbstractMatrix, mv::MonomialVector{C}, ::Type{T}) where {C, T}
if isempty(Q)
zero(Polynomial{C, T})
else
n = length(mv)
if C
N = trimap(n, n, n)
Z = Vector{Vector{Int}}(undef, N)
a = Vector{T}(undef, N)
for i in 1:n
for j in i:n
k = trimap(i, j, n)
Z[k] = mv.Z[i] + mv.Z[j]
if i == j
a[k] = Q[i, j]
else
a[k] = Q[i, j] + Q[j, i]
end
end
end
v = _vars(mv)
else
N = n^2
x = Vector{Monomial{C}}(undef, N)
a = Vector{T}(undef, N)
offset = 0
for i in 1:n
# for j in 1:n wouldn't be cache friendly for Q
for j in i:n
k = trimap(i, j, n)
q = Q[i, j]
x[offset+k] = mv[i] * mv[j]
a[offset+k] = q
if i != j
offset += 1
x[offset+k] = mv[j] * mv[i]
a[offset+k] = q
end
end
end
a, X = monovec(a, x)
v = _vars(X)
Z = X.Z
end
polynomialclean(v, a, Z)
end
end