Skip to content

Commit 929c5b0

Browse files
committed
add docstrings from README, move show/print commands to separate file
1 parent 2994946 commit 929c5b0

File tree

2 files changed

+235
-90
lines changed

2 files changed

+235
-90
lines changed

src/Polynomials.jl

Lines changed: 153 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ using Compat
88
export Poly, polyval, polyint, polyder, poly, roots
99
export Pade, padeval, degree
1010

11-
import Base: length, endof, getindex, setindex!, copy, zero, one, convert
11+
import Base: length, endof, getindex, setindex!, copy, zero, one, convert, norm, gcd
1212
import Base: show, print, *, /, //, -, +, ==, divrem, div, rem, eltype
1313
import Base: promote_rule
1414
if VERSION >= v"0.4"
@@ -19,6 +19,43 @@ eps{T}(::Type{T}) = zero(T)
1919
eps{F<:AbstractFloat}(x::Type{F}) = Base.eps(F)
2020
eps{T}(x::Type{Complex{T}}) = eps(T)
2121

22+
23+
"""
24+
25+
* `Poly{T<:Number}(a::Vector)`: Construct a polynomial from its coefficients, lowest order first. That is if `p=a_n x^n + ... + a_2 x^2 + a_1 x^1 + a_0`, we construct this through `Poly([a_0, a_1, ..., a_n])`.
26+
27+
Example:
28+
```
29+
Poly([1,0,3,4]) # Poly(1 + 3x^2 + 4x^3)
30+
```
31+
32+
An optional variable parameter can be added:
33+
34+
```
35+
Poly([1,2,3], :s) # Poly(1 + 2s + 3s^2)
36+
```
37+
38+
The usual arithmetic operators are overloaded to work on polynomials, and combinations of polynomials and scalars.
39+
40+
```
41+
p = Poly([1,2]) # Poly(1 + 2x)
42+
q = Poly([1, 0, -1]) # Poly(1 - x^2)
43+
2p # Poly(2 + 4x)
44+
2+p # Poly(3 + 2x)
45+
p - q # Poly(2x + x^2)
46+
p*q # Poly(1 + 2x - x^2 - 2x^3)
47+
q/2 # Poly(0.5 - 0.5x^2)
48+
```
49+
50+
Note that operations involving polynomials with different variables will error:
51+
52+
```j
53+
p = Poly([1, 2, 3], :x)
54+
q = Poly([1, 2, 3], :s)
55+
p + q # ERROR: Polynomials must have same variable.
56+
```
57+
58+
"""
2259
immutable Poly{T<:Number}
2360
a::Vector{T}
2461
var::Symbol
@@ -36,16 +73,48 @@ end
3673

3774
@compat Poly{T<:Number}(a::Vector{T}, var::Union{AbstractString,Symbol,Char}=:x) = Poly{T}(a, var)
3875

76+
include("show.jl")
77+
3978
convert{T}(::Type{Poly{T}}, p::Poly) = Poly(convert(Vector{T}, p.a), p.var)
4079
convert{T, S<:Number}(::Type{Poly{T}}, x::S) = Poly(promote_type(T, S)[x])
4180
convert{T, S<:Number,n}(::Type{Poly{T}}, x::Array{S,n}) = map(el->convert(Poly{promote_type(T,S)},el),x)
4281
promote_rule{T, S}(::Type{Poly{T}}, ::Type{Poly{S}}) = Poly{promote_type(T, S)}
4382
eltype{T}(::Poly{T}) = T
4483

84+
"""
85+
86+
`legnth(p::Poly)`: return length of coefficient vector
87+
88+
"""
4589
length(p::Poly) = length(p.a)
46-
degree(p::Poly) = length(p)-1
90+
91+
"""
92+
93+
`degree(p::Poly)`: return degree of polynomial `p`
94+
95+
"""
96+
degree(p::Poly) = length(p) - 1
4797
endof(p::Poly) = length(p) - 1
4898

99+
"""
100+
101+
`coeffs(p::Poly)`: return coefficient vector [a_0, a_1, ..., a_n]
102+
103+
"""
104+
coeffs(p::Poly) = p.a
105+
106+
"""
107+
108+
* `norm(q::Poly, [p])`: return `p` norm of polynomial `q`
109+
110+
"""
111+
norm(q::Poly, args...) = norm(coeffs(q), args...)
112+
113+
"""
114+
115+
* `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`.
116+
117+
"""
49118
getindex{T}(p::Poly{T}, i) = (i+1 > length(p.a) ? zero(T) : p.a[i+1])
50119
function setindex!(p::Poly, v, i)
51120
n = length(p.a)
@@ -64,93 +133,11 @@ zero{T}(::Type{Poly{T}}) = Poly(T[])
64133
one{T}(p::Poly{T}) = Poly([one(T)], p.var)
65134
one{T}(::Type{Poly{T}}) = Poly([one(T)])
66135

67-
function show(io::IO, p::Poly)
68-
print(io,"Poly(")
69-
print(io,p)
70-
print(io,")")
71-
end
72-
73-
function printexponent(io,var,i)
74-
if i == 0
75-
elseif i == 1
76-
print(io,var)
77-
else
78-
print(io,var,"^",i)
79-
end
80-
end
81-
82-
function printterm{T}(io::IO,p::Poly{T},j,first)
83-
pj = p[j]
84-
if pj == zero(T)
85-
return false
86-
end
87-
neg = pj < 0
88-
if first
89-
neg && print(io, "-") #Prepend - if first and negative
90-
else
91-
neg ? print(io, " - ") : print(io," + ")
92-
end
93-
pj = abs(pj)
94-
if pj != one(T) || j == 0
95-
show(io,pj)
96-
end
97-
printexponent(io,p.var,j)
98-
true
99-
end
100-
101-
function printterm{T<:Complex}(io::IO,p::Poly{T},j,first)
102-
pj = p[j]
103-
abs_repj = abs(real(pj))
104-
abs_impj = abs(imag(pj))
105-
if abs_repj < 2*eps(T) && abs_impj < 2*eps(T)
106-
return false
107-
end
108-
109-
# We show a negative sign either for any complex number with negative
110-
# real part (and then negate the immaginary part) of for complex
111-
# numbers that are pure imaginary with negative imaginary part
112-
113-
neg = ((abs_repj > 2*eps(T)) && real(pj) < 0) ||
114-
((abs_impj > 2*eps(T)) && imag(pj) < 0)
115-
116-
if first
117-
neg && print(io, "-") #Prepend - if first and negative
118-
else
119-
neg ? print(io," - ") : print(io," + ")
120-
end
121-
122-
if abs_repj > 2*eps(T) #Real part is not 0
123-
if abs_impj > 2*eps(T) #Imag part is not 0
124-
print(io,'(',neg ? -pj : pj,')')
125-
else
126-
print(io, neg ? -real(pj) : real(pj))
127-
end
128-
else
129-
if abs_impj > 2*eps(T)
130-
print(io,'(', imag(pj),"im)")
131-
end
132-
end
133-
printexponent(io,p.var,j)
134-
true
135-
end
136-
137-
function print{T}(io::IO, p::Poly{T})
138-
first = true
139-
printed_anything = false
140-
n = length(p)-1
141-
for i = 0:n
142-
printed = printterm(io,p,i,first)
143-
first &= !printed
144-
printed_anything |= printed
145-
end
146-
printed_anything || print(io,zero(T))
147-
end
148-
136+
## Overload arithmetic operators for polynomial operations between polynomials and scalars
149137
*{T<:Number,S}(c::T, p::Poly{S}) = Poly(c * p.a, p.var)
150138
*{T<:Number,S}(p::Poly{S}, c::T) = Poly(p.a * c, p.var)
151139
/(p::Poly, c::Number) = Poly(p.a / c, p.var)
152140
-(p::Poly) = Poly(-p.a, p.var)
153-
154141
-(p::Poly, c::Number) = +(p, -c)
155142
+(c::Number, p::Poly) = +(p, c)
156143
function +(p::Poly, c::Number)
@@ -220,7 +207,7 @@ function divrem{T, S}(num::Poly{T}, den::Poly{S})
220207

221208
aQ = zeros(R, deg)
222209
# aR = deepcopy(num.a)
223-
@show num.a
210+
# @show num.a
224211
aR = R[ num.a[i] for i = 1:n+1 ]
225212
for i = n:-1:m
226213
quot = aR[i+1] / den[m]
@@ -248,6 +235,22 @@ function ==(p1::Poly, p2::Poly)
248235
end
249236
end
250237

238+
"""
239+
* `polyval(p::Poly, x::Number)`: Evaluate the polynomial `p` at `x` using Horner's method.
240+
241+
Example:
242+
```
243+
polyval(Poly([1, 0, -1]), 0.1) # 0.99
244+
```
245+
246+
For `julia` version `0.4` or greater, the `call` method can be used:
247+
248+
```
249+
p = Poly([1,2,3])
250+
p(4) # 57 = 1 + 2*4 + 3*4^2
251+
```
252+
253+
"""
251254
function polyval{T,S}(p::Poly{T}, x::S)
252255
R = promote_type(T,S)
253256
lenp = length(p)
@@ -268,6 +271,19 @@ if VERSION >= v"0.4"
268271
call(p::Poly, x) = polyval(p, x)
269272
end
270273

274+
"""
275+
276+
* `polyint(p::Poly, k::Number=0)`: Integrate the polynomial `p` term
277+
by term, optionally adding constant term `k`. The order of the
278+
resulting polynomial is one higher than the order of `p`.
279+
280+
Examples:
281+
```
282+
polyint(Poly([1, 0, -1])) # Poly(x - 0.3333333333333333x^3)
283+
polyint(Poly([1, 0, -1]), 2) # Poly(2.0 + x - 0.3333333333333333x^3)
284+
```
285+
286+
"""
271287
function polyint{T}(p::Poly{T}, k::Number=0)
272288
n = length(p)
273289
R = typeof(one(T)/1)
@@ -279,6 +295,17 @@ function polyint{T}(p::Poly{T}, k::Number=0)
279295
return Poly(a2, p.var)
280296
end
281297

298+
"""
299+
300+
* `polyder(p::Poly)`: Differentiate the polynomial `p` term by
301+
term. The order of the resulting polynomial is one lower than the
302+
order of `p`.
303+
304+
Example:
305+
```
306+
polyder(Poly([1, 3, -1])) # Poly(3 - 2x)
307+
```
308+
"""
282309
function polyder{T}(p::Poly{T}, order::Int=1)
283310
n = length(p)
284311
if order < 0
@@ -301,7 +328,19 @@ polyder{T}(a::Array{Poly{T},1}, order::Int = 1) = [ polyder(p,order) for p in a
301328
polyint{n,T}(a::Array{Poly{T},n}, k::Number = 0) = map(p->polyint(p,k),a)
302329
polyder{n,T}(a::Array{Poly{T},n}, order::Int = 1) = map(p->polyder(p,order),a)
303330

304-
# create a Poly object from its roots
331+
# create a Poly object from its roots
332+
"""
333+
334+
* `poly(r::AbstractVector)`: Construct a polynomial from its
335+
roots. This is in contrast to the `Poly` constructor, which
336+
constructs a polynomial from its coefficients.
337+
338+
Example:
339+
```
340+
## Represents (x-1)*(x-2)*(x-3)
341+
poly([1,2,3]) # Poly(-6 + 11x - 6x^2 + x^3)
342+
```
343+
"""
305344
function poly{T}(r::AbstractVector{T}, var=:x)
306345
n = length(r)
307346
c = zeros(T, n+1)
@@ -317,10 +356,24 @@ poly(A::Matrix, var=:x) = poly(eig(A)[1], var)
317356
poly(A::Matrix, var::AbstractString) = poly(eig(A)[1], symbol(var))
318357
poly(A::Matrix, var::Char) = poly(eig(A)[1], symbol(var))
319358

359+
320360
roots{T}(p::Poly{Rational{T}}) = roots(convert(Poly{promote_type(T, Float64)}, p))
321361

322362

323-
# compute the roots of a polynomial
363+
# compute the roots of a polynomial
364+
"""
365+
366+
* `roots(p::Poly)`: Return the roots (zeros) of `p`, with
367+
multiplicity. The number of roots returned is equal to the order of
368+
`p`. The returned roots may be real or complex.
369+
370+
Examples:
371+
```
372+
roots(Poly([1, 0, -1])) # [-1.0, 1.0]
373+
roots(Poly([1, 0, 1])) # [0.0+1.0im, 0.0-1.0im]
374+
roots(Poly([0, 0, 1])) # [0.0, 0.0]
375+
```
376+
"""
324377
function roots{T}(p::Poly{T})
325378
R = promote_type(T, Float64)
326379
length(p) == 0 && return zeros(R, 0)
@@ -355,9 +408,18 @@ function roots{T}(p::Poly{T})
355408
return r
356409
end
357410

411+
"""
412+
413+
* `gcd(a::Poly, b::Poly)`: Finds the Greatest Common Denominator of
414+
two polynomials recursively using [Euclid's
415+
algorithm](http://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor#Euclid.27s_algorithm).
416+
417+
Example:
418+
```
419+
gcd(poly([1,1,2]), poly([1,2,3])) # returns (x-1)*(x-2)
420+
```
421+
"""
358422
function gcd{T, S}(a::Poly{T}, b::Poly{S})
359-
#Finds the Greatest Common Denominator of two polynomials recursively using
360-
#Euclid's algorithm: http://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor#Euclid.27s_algorithm
361423
if all(abs(b.a).<=2*eps(S))
362424
return a
363425
else
@@ -366,6 +428,7 @@ function gcd{T, S}(a::Poly{T}, b::Poly{S})
366428
end
367429
end
368430

431+
### Pull in others
369432
include("pade.jl")
370433

371434
end # module Poly

0 commit comments

Comments
 (0)