forked from JuliaMath/Polynomials.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Polynomial.jl
138 lines (113 loc) · 4.03 KB
/
Polynomial.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
export Polynomial
"""
Polynomial{T<:Number, X}(coeffs::AbstractVector{T}, [var = :x])
Construct a polynomial from its coefficients `coeffs`, lowest order first, optionally in
terms of the given variable `var` which may be a character, symbol, or a string.
If ``p = a_n x^n + \\ldots + a_2 x^2 + a_1 x + a_0``, we construct this through
`Polynomial([a_0, a_1, ..., a_n])`.
The usual arithmetic operators are overloaded to work with polynomials as well as
with combinations of polynomials and scalars. However, operations involving two
polynomials of different variables causes an error except those involving a constant polynomial.
!!! note
`Polynomial` is not axis-aware, and it treats `coeffs` simply as a list of coefficients with the first
index always corresponding to the constant term. In order to use the axis of `coeffs` as exponents,
consider using a [`LaurentPolynomial`](@ref) or possibly a [`SparsePolynomial`](@ref).
# Examples
```jldoctest
julia> Polynomial([1, 0, 3, 4])
Polynomial(1 + 3*x^2 + 4*x^3)
julia> Polynomial([1, 2, 3], :s)
Polynomial(1 + 2*s + 3*s^2)
julia> one(Polynomial)
Polynomial(1.0)
```
"""
struct Polynomial{T <: Number, X} <: StandardBasisPolynomial{T, X}
coeffs::Vector{T}
function Polynomial{T, X}(coeffs::AbstractVector{S}) where {T <: Number, X, S}
if Base.has_offset_axes(coeffs)
@warn "ignoring the axis offset of the coefficient vector"
end
N = findlast(!iszero, coeffs)
isnothing(N) && return new{T,X}(zeros(T,1))
cs = T[coeffs[i] for i ∈ firstindex(coeffs):N]
new{T,X}(cs)
end
# non-copying alternative assuming !iszero(coeffs[end])
function Polynomial{T, X}(checked::Val{false}, coeffs::AbstractVector{T}) where {T <: Number, X}
new{T, X}(coeffs)
end
end
@register Polynomial
"""
(p::Polynomial)(x)
Evaluate the polynomial using [Horner's Method](https://en.wikipedia.org/wiki/Horner%27s_method), also known as synthetic division, as implemented in `evalpoly` of base `Julia`.
# Examples
```jldoctest
julia> p = Polynomial([1, 0, 3])
Polynomial(1 + 3*x^2)
julia> p(0)
1
julia> p.(0:3)
4-element Array{Int64,1}:
1
4
13
28
```
"""
(p::Polynomial{T})(x::S) where {T,S} = evalpoly(x, coeffs(p))
# scalar _,* faster than standard-basis/common versions
function Base.:+(p::P, c::S) where {T, X, P <: Polynomial{T, X}, S<:Number}
R = promote_type(T, S)
Q = Polynomial{R,X}
as = convert(Vector{R}, copy(coeffs(p)))
as[1] += c
iszero(as[end]) ? Q(as) : Q(Val(false), as)
end
function Base.:*(p::P, c::S) where {T, X, P <: Polynomial{T,X} , S <: Number}
R = promote_type(T,S)
Q = Polynomial{R, X}
as = R[aᵢ * c for aᵢ ∈ coeffs(p)]
iszero(as[end]) ? Q(as) : Q(Val(false), as)
end
function Base.:+(p1::Polynomial{T}, p2::Polynomial{S}) where {T, S}
isconstant(p1) && return p2 + p1[0]
isconstant(p2) && return p1 + p2[0]
X, Y = indeterminate(p1), indeterminate(p2)
X != Y && error("Polynomials must have same variable")
n1, n2 = length(p1), length(p2)
R = promote_type(T,S)
c = zeros(R, max(n1, n2))
if n1 >= n2
c .= p1.coeffs
for i in eachindex(p2.coeffs)
c[i] += p2.coeffs[i]
end
else
c .= p2.coeffs
for i in eachindex(p1.coeffs)
c[i] += p1.coeffs[i]
end
end
Q = Polynomial{R,X}
return iszero(c[end]) ? Q(c) : Q(Val(false), c)
end
function Base.:*(p1::Polynomial{T}, p2::Polynomial{S}) where {T,S}
n, m = length(p1)-1, length(p2)-1 # not degree, so pNULL works
X, Y = indeterminate(p1), indeterminate(p2)
R = promote_type(T, S)
if n > 0 && m > 0
X != Y && error("Polynomials must have same variable")
c = zeros(R, m + n + 1)
for i in 0:n, j in 0:m
@inbounds c[i + j + 1] += p1[i] * p2[j]
end
Q = Polynomial{R,X}
return iszero(c[end]) ? Q(c) : Q(Val(false), c)
elseif n <= 0
return Polynomial{R, Y}(p2.coeffs * p1[0])
else
return Polynomial{R, X}(p1.coeffs * p2[0])
end
end