Skip to content

Commit 33a45ae

Browse files
authored
Close Issue 268 (#269)
* close #268; * add faster vander_solve function for one case
1 parent 48d62e2 commit 33a45ae

File tree

3 files changed

+71
-11
lines changed

3 files changed

+71
-11
lines changed

src/common.jl

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,9 @@ function fit(P::Type{<:AbstractPolynomial},
7575
x::AbstractVector{T},
7676
y::AbstractVector{T},
7777
deg::Integer = length(x) - 1;
78-
weights = nothing,
79-
var = :x,) where {T}
80-
x = mapdomain(P, x)
81-
vand = vander(P, x, deg)
82-
if weights !== nothing
83-
coeffs = _wlstsq(vand, y, weights)
84-
else
85-
coeffs = pinv(vand) * y
86-
end
87-
return P(T.(coeffs), var)
78+
weights = nothing,
79+
var = :x,) where {T}
80+
_fit(P, x, y, deg, weights, var)
8881
end
8982

9083
fit(P::Type{<:AbstractPolynomial},
@@ -108,9 +101,27 @@ fit(x::AbstractVector,
108101
weights = nothing,
109102
var = :x,) = fit(Polynomial, x, y, deg; weights = weights, var = var)
110103

104+
function _fit(P::Type{<:AbstractPolynomial},
105+
x::AbstractVector{T},
106+
y::AbstractVector{T},
107+
deg::Integer = length(x) - 1;
108+
weights = nothing,
109+
var = :x,) where {T}
110+
x = mapdomain(P, x)
111+
vand = vander(P, x, deg)
112+
if weights !== nothing
113+
coeffs = _wlstsq(vand, y, weights)
114+
else
115+
coeffs = pinv(vand) * y
116+
end
117+
R = float(T)
118+
return P(R.(coeffs), var)
119+
end
120+
121+
111122
# Weighted linear least squares
112123
_wlstsq(vand, y, W::Number) = _wlstsq(vand, y, fill!(similar(y), W))
113-
_wlstsq(vand, y, W::AbstractVector) = _wlstsq(vand, y, diagm(0 => W))
124+
_wlstsq(vand, y, W::AbstractVector) = _wlstsq(vand, y, Diagonal(W))
114125
_wlstsq(vand, y, W::AbstractMatrix) = (vand' * W * vand) \ (vand' * W * y)
115126

116127
"""

src/polynomials/standard-basis.jl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,51 @@ function vander(P::Type{<:StandardBasisPolynomial}, x::AbstractVector{T}, n::Int
301301
end
302302

303303

304+
## as noted at https://github.com/jishnub/PolyFit.jl, using method from SpecialMatrices is faster
305+
## https://github.com/JuliaMatrices/SpecialMatrices.jl/blob/master/src/vandermonde.jl
306+
## This is Algorithm 2 of https://www.maths.manchester.ac.uk/~higham/narep/narep108.pdf
307+
## Solve V(αs)⋅x = y where V is (1+n) × (1+n) Vandermonde matrix (Vᵀ in the paper)
308+
function solve_vander!(ys, αs)
309+
n = length(ys) - 1
310+
for k in 0:n-1
311+
for j in n:-1:k+1
312+
ys[1+j] = (ys[1+j] - ys[1+j-1])/(αs[1+j] - αs[1+j-k-1])
313+
end
314+
end
315+
for k in n-1:-1:0
316+
for j in k:n-1
317+
ys[1+j] = ys[1+j] - αs[1+k] * ys[1 + j + 1]
318+
end
319+
end
320+
321+
nothing
322+
end
323+
324+
# intercept one (typical) case for a faster variant
325+
function fit(P::Type{<:StandardBasisPolynomial},
326+
x::AbstractVector{T},
327+
y::AbstractVector{T},
328+
deg::Integer = length(x) - 1;
329+
weights = nothing,
330+
var = :x,) where {T}
331+
332+
if deg == length(x) -1 && weights == nothing
333+
_polynomial_fit(P, x, y; var=var)
334+
else
335+
_fit(P, x, y, deg; weights=weights, var=var)
336+
end
337+
end
338+
339+
function _polynomial_fit(P::Type{<:StandardBasisPolynomial}, x::AbstractVector{T}, y; var=:x) where {T}
340+
R = float(T)
341+
coeffs = Vector{R}(undef, length(x))
342+
copyto!(coeffs, y)
343+
solve_vander!(coeffs, x)
344+
P(R.(coeffs), var)
345+
end
346+
347+
348+
304349
## --------------------------------------------------
305350
"""
306351
compensated_horner(p::P, x)

test/StandardBasis.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,10 @@ end
306306
# issue #214 -- should error
307307
@test_throws MethodError fit(Polynomial, rand(2,2), rand(2,2))
308308

309+
# issue #268 -- inexacterror
310+
@test fit(P, 1:4, 1:4, var=:x) variable(P{Float64}, :x)
311+
@test fit(P, 1:4, 1:4, 1, var=:x) variable(P{Float64}, :x)
312+
309313
end
310314

311315
# test default (issue #228)

0 commit comments

Comments
 (0)