|
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 <: AbstractPolynomial |
|
a::Vector |
|
x::MonomialVector |
|
|
|
function Polynomial(a::Vector{T}, x::MonomialVector{C}) where |
|
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(a, x) |
|
end |
|
end |
|
|
|
iscomm(::Type{Polynomial{C, T}}) where = C |
|
|
|
Base.broadcastable(p::Polynomial) = Ref(p) |
|
Base.copy(p::Polynomial{C, T}) where = Polynomial(copy(p.a), copy(p.x)) |
|
Base.zero(::Type{Polynomial{C, T}}) where = Polynomial(T[], MonomialVector{C}()) |
|
Base.one(::Type{Polynomial{C, T}}) where = Polynomial([one(T)], MonomialVector(PolyVar{C}[], [Int[]])) |
|
Base.zero(p::Polynomial{C, T}) where = Polynomial(T[], emptymonovec(_vars(p))) |
|
Base.one(p::Polynomial{C, T}) where = Polynomial([one(T)], MonomialVector(_vars(p), [zeros(Int, nvariables(p))])) |
|
|
|
Polynomial(a::AbstractVector, x::MonomialVector) where = Polynomial(Vector{T}(a), x) |
|
Polynomial(a::AbstractVector, X::DMonoVec) where = Polynomial(monovec(a, X)...) |
|
Polynomial(a::Vector{T}, x) where = Polynomial(a, x) |
|
Polynomial(af::Union{Function, Vector}, x::DMonoVec{C}) where = Polynomial(af, x) |
|
|
|
# TODO Remove with MP v0.2.8 |
|
Polynomial(p::Polynomial{C, T}) where = p |
|
|
|
Base.convert(::Type{Polynomial{C, T}}, p::Polynomial{C, T}) where = p |
|
function Base.convert(::Type{Polynomial{C, T}}, |
|
p::Polynomial{C, S}) where |
|
return Polynomial(convert(Vector{T}, p.a), p.x) |
|
end |
|
#function convert(::Type{Polynomial{C, T}}, |
|
# p::AbstractPolynomialLike) where |
|
# return convert(Polynomial{C, T}, polynomial(p, T)) |
|
#end |
|
function Base.convert(::Type{Polynomial{C, T}}, t::Term{C}) where |
|
return Polynomial(T[t.α], [t.x]) |
|
end |
|
function Base.convert(::Type{Polynomial{C, T}}, m::DMonomialLike{C}) where |
|
return Polynomial(convert(Term{C, T}, m)) |
|
end |
|
function MP.convertconstant(::Type{Polynomial{C, T}}, α) where |
|
return Polynomial(convert(Term{C, T}, α)) |
|
end |
|
|
|
Polynomial(p::Union{Polynomial{C}, Term{C}, Monomial{C}, PolyVar{C}}) where = Polynomial(p) |
|
Polynomial(α) where = Polynomial(Term{C}(α)) |
|
|
|
Polynomial(p::Polynomial) = p |
|
Polynomial(t::Term{C, T}) where = Polynomial([t.α], [t.x]) |
|
Polynomial(x::Union{PolyVar{C}, Monomial{C}}) where = Polynomial(Term{C}(x)) |
|
|
|
#Base.convert(::Type{TermContainer{C, T}}, p::Polynomial{C}) where = Polynomial(p) |
|
|
|
function Polynomial(f::Function, x::MonomialVector{C}) where |
|
a = T[f(i) for i in 1:length(x)] |
|
Polynomial(a, x) |
|
end |
|
function Polynomial(f::Function, x::AbstractVector) where |
|
σ, X = sortmonovec(x) |
|
a = T[f(i) for i in σ] |
|
Polynomial(a, X) |
|
end |
|
Polynomial(f::Function, x) where = Polynomial(f, x) |
|
|
|
#Base.convert(::Type{PolyType{C}}, p::TermContainer{C}) where = 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}, p::TermContainer) where = p |
|
#Base.convert(::Type}, p::TermContainer) where = 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}) where = 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 <: AbstractVector} |
|
p::Polynomial |
|
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) where = 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 |
|
σ = sortperm(Zdup, rev=true, lt=grlex) |
|
Z = Vector}() |
|
a = Vector() |
|
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 |
|
a, Z = removedups(adup, Zdup) |
|
Polynomial(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 = 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 |
|
if isempty(Q) |
|
zero(Polynomial{C, T}) |
|
else |
|
n = length(mv) |
|
if C |
|
N = trimap(n, n, n) |
|
Z = Vector}(undef, N) |
|
a = Vector(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}(undef, N) |
|
a = Vector(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 |
|
|