Skip to content

Commit 7fa544e

Browse files
authored
Merge pull request #88 from aytekinar/87-handling-nans
Handle `NaN`s in `Poly` objects and do some cleanup
2 parents e0b9ff0 + 9196e1c commit 7fa544e

File tree

2 files changed

+78
-23
lines changed

2 files changed

+78
-23
lines changed

src/Polynomials.jl

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ export Pade, padeval
1414

1515
import Base: length, endof, getindex, setindex!, copy, zero, one, convert, norm, gcd
1616
import Base: show, print, *, /, //, -, +, ==, divrem, div, rem, eltype, .*, .-, .+
17-
import Base: promote_rule, truncate, chop, call, conj, ctranspose, dot, hash
17+
import Base: promote_rule, truncate, chop, call, conj, transpose, dot, hash
18+
import Base: isequal
1819

1920
eps{T}(::Type{T}) = zero(T)
2021
eps{F<:AbstractFloat}(x::Type{F}) = Base.eps(F)
@@ -204,6 +205,9 @@ norm(q::Poly, args...) = norm(coeffs(q), args...)
204205
"""
205206
conj{T<:Complex}(p::Poly{T}) = Poly(conj(coeffs(p)))
206207

208+
# Define the no-op `transpose` explicitly to avoid future warnings in Julia
209+
transpose(p::Poly) = p
210+
207211
"""
208212
209213
* `getindex(p::Poly, i)`: If `p=a_n x^n + a_{n-1}x^{n-1} + ... + a_1 x^1 + a_0`, then `p[i]` returns `a_i`.
@@ -239,6 +243,7 @@ one{T}(::Type{Poly{T}}) = Poly([one(T)])
239243
*{T<:Number,S}(p::Poly{S}, c::T) = Poly(p.a * c, p.var)
240244
dot{T<:Number,S}(p::Poly{S}, c::T) = p * c
241245
dot{T<:Number,S}(c::T, p::Poly{S}) = c * p
246+
dot(p1::Poly, p2::Poly) = p1 * p2
242247
.*{T<:Number,S}(c::T, p::Poly{S}) = Poly(c * p.a, p.var)
243248
.*{T<:Number,S}(p::Poly{S}, c::T) = Poly(p.a * c, p.var)
244249
/(p::Poly, c::Number) = Poly(p.a / c, p.var)
@@ -344,6 +349,7 @@ function ==(p1::Poly, p2::Poly)
344349
end
345350

346351
hash(f::Poly, h::UInt) = hash(f.var, hash(f.a, h))
352+
isequal(p1::Poly, p2::Poly) = hash(p1) == hash(p2)
347353

348354
"""
349355
* `polyval(p::Poly, x::Number)`: Evaluate the polynomial `p` at `x` using Horner's method.
@@ -375,7 +381,7 @@ function polyval{T,S}(p::Poly{T}, x::S)
375381
end
376382
end
377383

378-
polyval(p::Poly, v::AbstractVector) = map(x->polyval(p, x), v)
384+
polyval(p::Poly, v::AbstractArray) = map(x->polyval(p, x), v)
379385

380386
@compat (p::Poly)(x) = polyval(p, x)
381387

@@ -392,9 +398,33 @@ polyint(Poly([1, 0, -1]), 2) # Poly(2.0 + x - 0.3333333333333333x^3)
392398
```
393399
394400
"""
395-
function polyint{T}(p::Poly{T}, k::Number=0)
401+
# if we do not have any initial condition, assume k = zero(Int)
402+
polyint{T}(p::Poly{T}) = polyint(p, 0)
403+
404+
# if we have coefficients that have `NaN` representation
405+
function polyint{T<:Union{Real,Complex},S<:Number}(p::Poly{T}, k::S)
406+
any(isnan(p.a)) && return Poly(promote_type(T,S)[NaN])
407+
_polyint(p, k)
408+
end
409+
410+
# if we have initial condition that can represent `NaN`
411+
function polyint{T,S<:Union{Real,Complex}}(p::Poly{T}, k::S)
412+
isnan(k) && return Poly(promote_type(T,S)[NaN])
413+
_polyint(p, k)
414+
end
415+
416+
# if we have both coefficients and initial condition that can take `NaN`
417+
function polyint{T<:Union{Real,Complex},S<:Union{Real,Complex}}(p::Poly{T}, k::S)
418+
(any(isnan(p.a)) || isnan(k)) && return Poly(promote_type(T,S)[NaN])
419+
_polyint(p, k)
420+
end
421+
422+
# otherwise, catch all
423+
polyint{T,S<:Number}(p::Poly{T}, k::S) = _polyint(p, k)
424+
425+
function _polyint{T,S<:Number}(p::Poly{T}, k::S)
396426
n = length(p)
397-
R = typeof(one(T)/1)
427+
R = promote_type(typeof(one(T)/1), S)
398428
a2 = Array(R, n+1)
399429
a2[1] = k
400430
for i = 1:n
@@ -414,30 +444,37 @@ Example:
414444
polyder(Poly([1, 3, -1])) # Poly(3 - 2x)
415445
```
416446
"""
447+
# if we have coefficients that can represent `NaN`s
448+
function polyder{T<:Union{Real,Complex}}(p::Poly{T}, order::Int=1)
449+
n = length(p)
450+
order < 0 && error("Order of derivative must be non-negative")
451+
order == 0 && return p
452+
any(isnan(p.a)) && return Poly(T[NaN], p.var)
453+
n <= order && return Poly(T[], p.var)
454+
_polyder(p, order)
455+
end
456+
457+
# otherwise
417458
function polyder{T}(p::Poly{T}, order::Int=1)
418-
n = length(p)
419-
if order < 0
420-
error("Order of derivative must be non-negative")
421-
elseif n <= order
422-
return Poly(zeros(T,0),p.var)
423-
elseif order == 0
424-
return p
425-
else
426-
a2 = Array(T, n-order)
427-
for i = order:n-1
428-
a2[i-order+1] = p[i] * prod((i-order+1):i)
429-
end
430-
return Poly(a2, p.var)
431-
end
459+
n = length(p)
460+
order < 0 && error("Order of derivative must be non-negative")
461+
order == 0 && return p
462+
n <= order && return Poly(T[], p.var)
463+
_polyder(p, order)
432464
end
433-
ctranspose{T}(p::Poly{T}) = polyder(p)
434465

435-
polyint{T}(a::Array{Poly{T},1}, k::Number = 0) = [ polyint(p,k) for p in a ]
436-
polyder{T}(a::Array{Poly{T},1}, order::Int = 1) = [ polyder(p,order) for p in a ]
437-
polyint{n,T}(a::Array{Poly{T},n}, k::Number = 0) = map(p->polyint(p,k),a)
438-
polyder{n,T}(a::Array{Poly{T},n}, order::Int = 1) = map(p->polyder(p,order),a)
466+
function _polyder{T}(p::Poly{T}, order::Int=1)
467+
n = length(p)
468+
a2 = Array(T, n-order)
469+
for i = order:n-1
470+
a2[i-order+1] = p[i] * prod((i-order+1):i)
471+
end
439472

473+
return Poly(a2, p.var)
474+
end
440475

476+
polyint{T}(a::AbstractArray{Poly{T}}, k::Number = 0) = map(p->polyint(p,k), a)
477+
polyder{T}(a::AbstractArray{Poly{T}}, order::Int = 1) = map(p->polyder(p,order),a)
441478

442479
##################################################
443480
##

test/runtests.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ sprint(show, pNULL)
4747
@test polyval(poly([1//2, 3//2]), 1//2) == 0//1
4848
@test polyder(polyint(pN)) == pN
4949
@test polyder(pR) == Poly([-2//1,2//1])
50+
@test_throws ErrorException polyder(pR, -1)
5051
@test polyint(pNULL,1) == p1
5152
@test polyint(Poly(Rational[1,2,3])) == Poly(Rational[0, 1, 1, 1])
5253
@test polyder(p3) == Poly([2,2])
@@ -258,3 +259,20 @@ p2 = Poly([0, Inf])
258259
@test isnan(p1(-Inf))
259260
@test isnan(p1(0))
260261
@test p2(-Inf) == -Inf
262+
263+
## Check for isequal
264+
p1 = Poly([-0., 5., Inf])
265+
p2 = Poly([0., 5., Inf])
266+
p3 = Poly([0, NaN])
267+
268+
@test p1 == p2 && !isequal(p1, p2)
269+
@test is(p3, p3) && p3 p3 && isequal(p3, p3)
270+
271+
## Handling of `NaN`s
272+
p = Poly([NaN, 1, 5])
273+
pder = polyder(p)
274+
pint = polyint(p)
275+
276+
@test isnan(p(1)) # p(1) evaluates to NaN
277+
@test isequal(pder, Poly([NaN])) # derivative will give Poly([NaN])
278+
@test isequal(pint, Poly([NaN])) # integral will give Poly([NaN])

0 commit comments

Comments
 (0)