
| Current Path : /var/www/web-klick.de/dsh/50_dev2017/1310__algorithms/Julia/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : /var/www/web-klick.de/dsh/50_dev2017/1310__algorithms/Julia/interpolation.jl |
# interpolation of missing data
# this implements mathematical routines for solving
# the gridding problem, also known as missing data problem
# the whole module is carefully designed to get the most
# efficient interpolation on a grid, which means "avoid temporaries!"
#
# the interpolation functionality does quite a bit more than
# Matlab's utilities, such as efficient computation of
# derivatives and quadratic interpolation, which is often the best
# choice for applications.
# Author: Stefan Schwarz <stdlibdev@gmail.com>
# Copyright: esrlabs GmbH All rights reserved.
import Base: eltype, getindex, isvalid, ndims, show, size
solve! = isdefined(Base.LinAlg, :solve!) ? Base.LinAlg.solve! : Base.LinAlg.solve
abstract InterpolationType
type InterpolationNearest <: InterpolationType; end
type InterpolationLinear <: InterpolationType; end
type InterpolationQuadratic <: InterpolationType; end
type InterpolationGridCoefs{T, IT<:InterpolationType}
coord1d::Vector{Vector{Int}} # for 1-d positions
coef1d::Vector{Vector{T}} # for 1-d coefficients
gcoef1d::Vector{Vector{T}} # for 1-d coefficients of the gradient
c1d::Vector{Vector{T}} # temp space for switch btw value & gradient
dims::Vector{Int}
strides::Vector{Int}
offset::Vector{Int} # the default N-d offset when there is no wrapping
offset_base::Int
index::Vector{Int} # the alternative N-d index, needed when wrapping
wrap::Bool # which of these two indices to use
valid::Bool # some Boundary conditions return NaN when wrapping
coef::Vector{T} # the N-d coefficient of each neighbor (val & gradient)
end
abstract BoundaryCondition
type BCnil <: BoundaryCondition; end # ignore edges (error when invalid)
type BCnan <: BoundaryCondition; end # NaN when over the edge
type BCna <: BoundaryCondition; end # Normalize to available data (NaN when none)
type BCreflect <: BoundaryCondition; end # Reflecting boundary conditions
type BCperiodic <: BoundaryCondition; end # Periodic boundary conditions
type BCnearest <: BoundaryCondition; end # Return closest edge element
type BCfill <: BoundaryCondition; end # Use specified fill value
# Note: for interpolation, BCna is currently defined to be identical
# to BCnan. Other applications might define different behavior,
# particularly for filtering operations.
#needs_validating{BC<:BoundaryCondition}(::Type{BC}) = false
#needs_validating{BC<:Union(BCnil,BCnan,BCna)}(::Type{BC}) = true
isvalid{BC<:BoundaryCondition}(::Type{BC}, pos::Int, min::Int, max::Int) = true
isvalid{BC<:Union(BCnan,BCna)}(::Type{BC}, pos::Int, min::Int, max::Int) = min <= pos <= max
wrap{BC<:BoundaryCondition}(::Type{BC}, pos::Int, len::Int) = pos
wrap(::Type{BCreflect}, pos::Int, len::Int) = wraprefl(mod(pos-1, 2*len), len)
wraprefl(posrem::Int, len::Int) = posrem < len ? posrem+1 : 2*len-posrem
wrap(::Type{BCperiodic}, pos::Int, len::Int) = mod(pos-1, len) + 1
wrap{BC<:Union(BCnearest,BCfill)}(::Type{BC}, pos::Int, len::Int) = pos < 1 ? 1 : (pos > len ? len : pos)
type InterpolationGrid{T<:FloatingPoint, N, BC<:BoundaryCondition, IT<:InterpolationType} <: AbstractArray{T,N}
coefs::Array{T,N}
ic::InterpolationGridCoefs{T, IT}
x::Vector{T}
fillval::T # used only for BCfill (if ever)
end
function InterpolationGrid{T<:FloatingPoint, BC<:BoundaryCondition,
IT<:InterpolationType}(A::Array{T}, ::Type{BC}, ::Type{IT})
if BC == BCfill
error("Construct BCfill InterpGrids by supplying the fill value")
end
coefs = copy(A)
interpolate_invert!(coefs, BC, IT, 1:ndims(A))
ic = InterpolationGridCoefs(coefs, IT)
x = zeros(T, ndims(A))
InterpolationGrid{T, ndims(A), BC, IT}(coefs, ic, x, nan(T))
end
function InterpolationpGrid{T<:FloatingPoint, IT<:InterpolationType}(A::Array{T},
f::Number, ::Type{IT})
coefs = pad1(A, f, 1:ndims(A))
interpolate_invert!(coefs, BCnearest, IT, 1:ndims(A))
ic = InterpolationGridCoefs(coefs, IT)
x = zeros(T, ndims(A))
InterpolationGrid{T, ndims(A), BCfill, IT}(coefs, ic, x, convert(T, f))
end
setx{T}(G::InterpolationGrid{T,1}, x::Real) = G.x[1] = x
function setx{T}(G::InterpolationGrid{T,2}, x::Real, y::Real)
xG = G.x
xG[1] = x
xG[2] = y
end
function setx{T}(G::InterpolationGrid{T,3}, x::Real, y::Real, z::Real)
xG = G.x
xG[1] = x
xG[2] = y
xG[3] = z
end
function setx{T,N}(G::InterpolationGrid{T,N}, x::Real...)
if length(x) != N
error("Incorrect number of dimensions supplied")
end
xG = G.x
for idim = 1:N
xG[idim] = x[idim]
end
end
# a version that corrects for the padding of BCfill types
setx{T}(G::InterpolationGrid{T,1,BCfill}, x::Real) = G.x[1] = x+1
function setx{T}(G::InterpolationGrid{T,2,BCfill}, x::Real, y::Real)
xG = G.x
xG[1] = x+1
xG[2] = y+1
end
function setx{T}(G::InterpolationGrid{T,3,BCfill}, x::Real, y::Real, z::Real)
xG = G.x
xG[1] = x+1
xG[2] = y+1
xG[3] = z+1
end
function setx{T,N}(G::InterpolationGrid{T,N,BCfill}, x::Real...)
if length(x) != N
error("Incorrect number of dimensions supplied")
end
xG = G.x
for idim = 1:N
xG[idim] = x[idim]+1
end
end
## Evaluation at single points
function _getindex{T}(G::InterpolationGrid{T})
set_position(G.ic, boundarycondition(G), false, G.x)
interpolate(G.ic, G.coefs)
end
function getindex(G::InterpolationGrid, x::Real...)
setx(G, x...)
_getindex(G)
end
function _valgrad{T,N}(g::Vector{T}, G::InterpolationGrid{T,N})
if length(g) != N
error("Wrong number of components for the gradient")
end
ic = G.ic
coefs = G.coefs
set_position(ic, boundarycondition(G), true, G.x)
val = interpolate(ic, coefs)
for idim = 1:N
set_gradient_coordinate(ic, idim)
g[idim] = interp(ic, coefs)
end
return val
end
function _valgrad{T}(G::InterpolationGrid{T,1})
ic = G.ic
coefs = G.coefs
set_position(ic, boundarycondition(G), true, G.x)
val = interp(ic, coefs)
set_gradient_coordinate(ic, 1)
g = interpolate(ic, coefs)
return val, g
end
function valgrad{T}(G::InterpolationGrid{T,1}, x::Real)
setx(G, x)
_valgrad(G)
end
function valgrad{T}(G::InterpolationGrid{T}, x::Real...)
setx(G, x...)
g = Array(T, length(x))
val = _valgrad(g, G)
return val, g
end
function valgrad{T}(g::Vector{T}, G::InterpolationGrid{T}, x::Real...)
setx(G, x...)
_valgrad(g, G)
end
## Vectorized evaluation at multiple points
function getindex{T,R<:Real}(G::InterpolationGrid{T,1}, x::AbstractVector{R})
n = length(x)
v = Array(T, n)
for i = 1:n
setx(G, x[i])
v[i] = _getindex(G)
end
v
end
getindex{T,N,R<:Real}(G::InterpolationGrid{T,N}, x::AbstractVector{R}) = error("Linear indexing not supported")
function getindex{T,R<:Real}(G::InterpolationGrid{T,2}, x::AbstractVector{R}, y::AbstractVector{R})
nx, ny = length(x), length(y)
v = Array(T, nx, ny)
for i = 1:nx
for j = 1:ny
setx(G, x[i], y[j])
v[i,j] = _getindex(G)
end
end
end
function getindex{T,N,R<:Real}(G::InterpolationGrid{T,N}, x::AbstractVector{R}, xrest::AbstractVector{R}...)
if length(xrest) != N-1
error("Dimensionality mismatch")
end
nx = length(x)
nrest = [length(y) for y in xrest]
v = Array(T, nx, nrest...)
for c in Counter(nrest)
for i = 1:nx
setx(G, x[i], ntuple(N-1, i->xrest[i][c[i]])...) # FIXME performance?? May not matter...
v[i,c...] = _getindex(G)
end
end
end
## type InterpolationIrregular{T<:FloatingPoint, N, BC<:BoundaryCondition, IT<:InterpolationType} <: AbstractArray{T,N}
## grid::Vector{Vector{T}}
## coefs::Array{T,N}
## x::Vector{T}
## fillval::T # used only for BCfill (if ever)
## end
## InterpolationIrregular{T<:FloatingPoint, BC<:BoundaryCondition, IT<:Union(InterpolationNearest,InterpolationLinear)}(grid::Vector{T}, A::AbstractVector, ::Type{BC}, ::Type{IT}) =
## InterpolationIrregular(Vector{T}[grid], A, BC, IT) # special 1d syntax
## InterpolationIrregular{T<:FloatingPoint, BC<:BoundaryCondition, IT<:Union(InterpolationNearest,InterpolationLinear)}(grid::(Vector{T}...), A::AbstractVector, ::Type{BC}, ::Type{IT}) =
## InterpolationIrregular(Vector{T}[grid...], A, BC, IT)
function set_position{T,BC<:BoundaryCondition,IT<:InterpolationType}(ic::InterpolationGridCoefs{T,IT}, ::Type{BC},
calc_grad::Bool, x::Vector{T})
N = ndims(ic)
if length(x) != N
error("Dimensionality mismatch")
end
valid = true
for idim = 1:N
if !isvalid(BC, IT, x[idim], ic.dims[idim])
valid = false
break
end
end
ic.valid = valid
wrap = false
if valid
ib::Int = 0
for idim = 1:N
ix::Int, dx::T, twrap::Bool = interpolate_coords_1d(ic.coord1d[idim], BC, IT, x[idim], ic.dims[idim])
wrap = wrap | twrap
ib += (ix-1)*ic.strides[idim]
interpolate_coefs_1d(ic.coef1d[idim], BC, IT, dx)
if calc_grad
interpolate_gcoefs_1d(ic.gcoef1d[idim], BC, IT, dx)
end
end
if wrap
interpolate_index_coef(ic.index, ic.coef, ic.coord1d, ic.coef1d, ic.strides)
else
ic.offset_base = ib
interpolate_coef(ic.coef, ic.coef1d)
end
end
ic.wrap = wrap
end
function set_gradient_coordinate(ic::InterpolationGridCoefs, i::Int)
if !ic.valid
return
end
N = ndims(ic)
if i < 1 || i > N
error("Wrong dimension index")
end
for idim = 1:N
if idim == i
ic.c1d[idim] = ic.gcoef1d[idim]
else
ic.c1d[idim] = ic.coef1d[idim]
end
end
interpolate_coef(ic.coef, ic.c1d)# , npoints(IT), N)
end
function interpolate{T}(ic::InterpolationGridCoefs{T}, A::AbstractArray, index::Int)
if !ic.valid
return nan(T)
end
coef = ic.coef
if ic.wrap
offset = ic.index
index -= 1
else
offset = ic.offset
index += ic.offset_base
end
val = zero(T)
for i = 1:length(coef)
c = coef[i]
val += c == zero(T) ? zero(T) : c*convert(T,A[offset[i]+index])
end
return convert(T, val)
end
interpolate(ic::InterpolationGridCoefs, A::AbstractArray) = interpolate(ic, A, 1)
function set_size(ic::InterpolationGridCoefs, dims, strides)
N = ndims(ic)
if length(strides) != N
error("Strides do not have the correct dimensionality")
end
if length(dims) != N
error("Dimensions do not have the correct dimensionality")
end
d = [dims...]
s = [strides...]
for idim = 1:N
ic.dims[idim] = d[idim]
ic.strides[idim] = s[idim]
interpolate_coords_1d(ic.coord1d[idim], interptype(ic))
end
interpolate_index(ic.offset, ic.coord1d, s)
end
function set_size(ic::InterpolationGridCoefs, dims)
N = length(dims)
s = Array(Int, N)
s[1] = 1
for i = 1:N-1
s[i+1] = s[i]*dims[i]
end
set_size(ic, dims, s)
end
function InterpolationGridCoefs{T<:FloatingPoint,IT<:InterpolationType}(::Type{T}, ::Type{IT}, dims::Union(Dims,Vector{Int}), strides::Union(Dims,Vector{Int}))
N = length(strides)
if length(dims) != N
error("Length of dims and strides must match")
end
coord1d = Array(Vector{Int}, N)
coef1d = Array(Vector{T}, N)
gcoef1d = Array(Vector{T}, N)
c1d = Array(Vector{T}, N)
l = npoints(IT)
for idim = 1:N
coord1d[idim] = Array(Int, l)
coef1d[idim] = Array(T, l)
gcoef1d[idim] = Array(T, l)
# do not allocate entries for c1d
end
n_coef = l^N
offset = Array(Int, n_coef)
index = Array(Int, n_coef)
coef = Array(T, n_coef)
# Pre-calculate the default offset from the strides
for idim = 1:N
interpolate_coords_1d(coord1d[idim], IT)
end
interpolate_index(offset, coord1d, strides)
InterpolationGridCoefs{T,IT}(coord1d,coef1d,gcoef1d,c1d,[dims...],[strides...],offset,0,index,false,false,coef)
end
InterpolationGridCoefs{IT<:InterpolationType}(A::Array, ::Type{IT}) = InterpolationGridCoefs(eltype(A), IT, [size(A)...], [strides(A)...])
# version for offsets
function interpolate_coords_1d(coord1d::Vector{Int}, ::Type{InterpolationNearest})
coord1d[1] = 0
end
# version for indices
function interpolate_coords_1d{BC<:BoundaryCondition}(coord1d::Vector{Int},
::Type{BC}, ::Type{InterpolationNearest}, x, len::Int)
ix = wrap(BC, iround(x), len)
coord1d[1] = ix
return ix, zero(typeof(x)), false
end
# version for offsets
function interpolate_coords_1d(coord1d::Vector{Int}, ::Type{InterpolationLinear})
coord1d[1] = 0
coord1d[2] = 1
end
# version for indices
function interpolate_coords_1d{T,BC<:BoundaryCondition}(coord1d::Vector{Int},
::Type{BC}, ::Type{InterpolationLinear}, x::T, len::Int)
ix::Int = wrap(BC, ifloor(x), len)
dx::T = x-trunc(x)
coord1d[1] = ix
iswrap::Bool = (ix == len && dx > 0)
coord1d[2] = wrap(BC, ix+1, len)
return ix, dx, iswrap
end
function interpolate_coords_1d{T}(coord1d::Vector{Int}, ::Type{BCreflect},
::Type{InterpolationLinear}, x::T, len::Int)
ix = mod(ifloor(x)-1, 2*len)
dx = x-trunc(x)
if ix < len
ix += 1
ixp = ix+1
if ixp > len
ixp = len
end
else
ix = 2*len-ix-1
dx = one(T)-dx
ixp = ix+1
if ix == 0
ix = 1
end
end
coord1d[1] = ix
coord1d[2] = wrap(BCreflect, ixp, len)
iswrap = (ix == ixp && dx > 0)
return ix, dx, iswrap
end
# version for offsets
function interpolate_coords_1d(coord1d::Vector{Int}, ::Type{InterpolationQuadratic})
coord1d[1] = -1
coord1d[2] = 0
coord1d[3] = 1
end
# versions for indices
function interpolate_coords_1d{BC<:BoundaryCondition}(coord1d::Vector{Int},
::Type{BC}, ::Type{InterpolationQuadratic}, x, len::Int)
ix = iround(x)
dx = x-ix
ix = wrap(BC, ix, len)
coord1d[2] = ix
iswrap = (ix == 1 || ix == len)
if iswrap
coord1d[1] = wrap(BC, ix-1, len)
coord1d[3] = wrap(BC, ix+1, len)
else
coord1d[1] = ix-1
coord1d[3] = ix+1
end
return ix, dx, iswrap
end
# for InterpQuadratic, several require special handling
# BCnil, Bnan, BCna: for 1 <= x <= 1.5, continue the quadratic centered at x=2
function interpolate_coords_1d{BC<:Union(BCnil,BCnan,BCna)}(coord1d::Vector{Int},
::Type{BC}, ::Type{InterpolationQuadratic}, x, len::Int)
if x > 1.5 && x+0.5 < len
ix = iround(x)
elseif x <= 1.5
ix = 2
else
ix = len-1
end
dx = x-ix
coord1d[1] = ix-1
coord1d[2] = ix
coord1d[3] = ix+1
return ix, dx, false
end
# BCnearest & BCfill: for 1 <= x <= 1.5, ensure the slope tends to 0 at x=1
function interpolate_coords_1d{T,BC<:Union(BCnearest,BCfill)}(coord1d::Vector{Int},
::Type{BC}, ::Type{InterpolationQuadratic}, x::T, len::Int)
if x > 1.5 && x+0.5 < len
ix = iround(x)
coord1d[1] = ix-1
coord1d[2] = ix
coord1d[3] = ix+1
iswrap = false
dx = x-ix
elseif x <= 1.5
ix = one(T)
coord1d[1] = 2
coord1d[2] = 1
coord1d[3] = 2
iswrap = true
if x < 1
dx = zero(T)
else
dx = x-ix
end
else
ix = convert(T, len)
coord1d[1] = len-1
coord1d[2] = len
coord1d[3] = len-1
iswrap = true
if x > len
dx = zero(T)
else
dx = x-ix
end
end
return ix, dx, iswrap
end
function interpolate_coords_1d(coord1d::Vector{Int}, ::Type{BCreflect},
::Type{InterpolationQuadratic}, x, len::Int)
ix = iround(x)
dx = x-ix
ix = mod(ix-1, 2*len)
if ix < len
ix += 1
else
dx = -dx
ix = 2*len-ix
end
coord1d[2] = ix
iswrap = (ix == 1 || ix == len)
if iswrap
coord1d[1] = wrap(BCreflect, ix-1, len)
coord1d[3] = wrap(BCreflect, ix+1, len)
else
coord1d[1] = ix-1
coord1d[3] = ix+1
end
return ix, dx, iswrap
end
function interpolate_coefs_1d{T,BC<:BoundaryCondition}(coef1d::Vector{T}, ::Type{BC},
::Type{InterpolationNearest}, dx::T)
coef1d[1] = one(T)
end
function interpolate_gcoefs_1d{T,BC<:BoundaryCondition}(coef1d::Vector{T}, ::Type{BC},
::Type{InterpolationQuadratic}, dx::T)
coef1d[1] = zero(T)
end
function interpolate_coefs_1d{T,BC<:BoundaryCondition}(coef1d::Vector{T}, ::Type{BC},
::Type{InterpolationLinear}, dx::T)
coef1d[1] = 1.0-dx
coef1d[2] = dx
end
function interpolate_gcoefs_1d{T,BC<:BoundaryCondition}(coef1d::Vector{T}, ::Type{BC},
::Type{InterpolationQuadratic}, dx::T)
coef1d[1] = -one(T)
coef1d[2] = one(T)
end
function interpolate_coefs_1d{T,BC<:BoundaryCondition}(coef1d::Vector{T}, ::Type{BC},
::Type{InterpolationQuadratic}, dx::T)
coef1d[1] = (dx-0.5)^2/2
coef1d[2] = 0.75-dx^2
coef1d[3] = (dx+0.5)^2/2
end
function interpolate_gcoefs_1d{T,BC<:BoundaryCondition}(coef1d::Vector{T}, ::Type{BC},
::Type{InterpolationQuadratic}, dx::T)
coef1d[1] = dx-0.5
coef1d[2] = -2dx
coef1d[3] = dx+0.5
end
npoints(::Type{InterpolationNearest}) = 1
npoints(::Type{InterpolationLinear}) = 2
npoints(::Type{InterpolationQuadratic}) = 3
isvalid{BC<:BoundaryCondition,IT<:InterpolationType}(::Type{BC},::Type{IT}, x, len::Int) = true
isvalid{BC<:Union(BCnil,BCnan,BCna)}(::Type{BC}, ::Type{InterpolationNearest}, x, len::Int) = x >= 0.5 && x-0.5 <= len
isvalid{BC<:Union(BCnil,BCnan,BCna)}(::Type{BC}, ::Type{InterpolationLinear}, x, len::Int) = x >= 1 && x <= len
isvalid{BC<:Union(BCnil,BCnan,BCna)}(::Type{BC}, ::Type{InterpolationQuadratic}, x, len::Int) = x >= 1 && x <= len
eltype{T, N, BC, IT}(G::InterpolationGrid{T, N, BC, IT}) = T
ndims{T, N, BC, IT}(G::InterpolationGrid{T, N, BC, IT}) = N
boundarycondition{T, N, BC, IT}(G::InterpolationGrid{T, N, BC, IT}) = BC
interptype{T, N, BC, IT}(G::InterpolationGrid{T, N, BC, IT}) = IT
size(G::InterpolationGrid) = size(G.coefs)
size(G::InterpolationGrid, i::Integer) = size(G.coefs, i)
#eltype{T, N, BC, IT}(G::InterpolationIrregular{T, N, BC, IT}) = T
#ndims{T, N, BC, IT}(G::InterpolationIrregular{T, N, BC, IT}) = N
#boundarycondition{T, N, BC, IT}(G::InterpolationIrregular{T, N, BC, IT}) = BC
#interptype{T, N, BC, IT}(G::InterpolationIrregular{T, N, BC, IT}) = IT
#size(G::InterpolationIrregular) = size(G.coefs)
#size(G::InterpolationIrregular, i::Integer) = size(G.coefs, i)
eltype{T,IT<:InterpolationType}(ic::InterpolationGridCoefs{T,IT}) = T
interptype{IT<:InterpolationType,T}(ic::InterpolationGridCoefs{T,IT}) = IT
ndims(ic::InterpolationGridCoefs) = length(ic.coord1d)
show(io::IO, ic::InterpolationGridCoefs) = print(io, "InterpolationGridCoefs{", eltype(ic), ",", interptype(ic), "}")
interpolate_invert!{BC<:BoundaryCondition}(A::Array, ::Type{BC}, ::Type{InterpolationNearest}, dimlist) = A
interpolate_invert!{BC<:BoundaryCondition}(A::Array, ::Type{BC}, ::Type{InterpolationLinear}, dimlist) = A
function interpolate_invert!{BC<:BoundaryCondition}(A::Array, ::Type{BC}, ::Type{InterpolationQuadratic}, dimlist)
sizeA = [size(A)...]
stridesA = [strides(A)...]
for idim = dimlist
n = size(A, idim)
# Set up the tridiagonal system
du = fill(convert(eltype(A), 1/8), n-1)
d = fill(convert(eltype(A), 3/4), n)
dl = copy(du)
M = _interpolate_invert_matrix(BC, InterpolationQuadratic, dl, d, du)
sizeA[idim] = 1 # don't iterate over the dimension we're solving on
for cc in Counter(sizeA)
rng = Range(coords2lin(cc, stridesA), stridesA[idim], n)
solve!(A, rng, M, A, rng) # in-place
end
sizeA[idim] = size(A, idim)
end
A
end
interpolate_invert!{BC<:Union(BoundaryCondition,Number)}(A::Array, ::Type{BC}, IT) = interpolate_invert!(A, BC, IT, 1:ndims(A))
interpolate_invert!{BC<:Union(BoundaryCondition,Number)}(A::Array, ::Type{BC}, IT, dimlist...) = interpolate_invert!(A, BC, IT, dimlist)
function _interpolate_invert_matrix{BC<:Union(BCnil,BCnan,BCna),T}(::Type{BC}, ::Type{InterpolationQuadratic},
dl::Vector{T}, d::Vector{T}, du::Vector{T})
# For these, the quadratic centered on x=2 is continued down to
# 1 rather than terminating at 1.5
n = length(d)
d[1] = d[n] = 9/8
dl[n-1] = du[1] = -1/4
MT = Tridiagonal(dl, d, du)
# Woodbury correction to add 1/8 for row 1, col 3 and row n, col n-2
U = zeros(T, n, 2)
V = zeros(T, 2, n)
C = zeros(T, 2, 2)
C[1,1] = C[2,2] = 1/8
U[1,1] = U[n,2] = 1
V[1,3] = V[2,n-2] = 1
M = Woodbury(MT, U, C, V)
end
function _interpolate_invert_matrix{T}(::Type{BCreflect}, ::Type{InterpolationQuadratic}, dl::Vector{T}, d::Vector{T}, du::Vector{T})
n = length(d)
d[1] += 1/8
d[n] += 1/8
M = Tridiagonal(dl, d, du)
end
function _interpolate_invert_matrix{T}(::Type{BCperiodic}, ::Type{InterpolationQuadratic},
dl::Vector{T}, d::Vector{T}, du::Vector{T})
n = length(d)
MT = Tridiagonal(dl, d, du)
# Woodbury correction to wrap around
U = zeros(T, n, 2)
V = zeros(T, 2, n)
C = zeros(T, 2, 2)
C[1,1] = C[2,2] = 1/8
U[1,1] = U[n,2] = 1
V[1,n] = V[2,1] = 1
M = Woodbury(MT, U, C, V)
end
function _interpolate_invert_matrix{T,BC<:Union(BCnearest,BCfill)}(::Type{BC},
::Type{InterpolationQuadratic},
dl::Vector{T}, d::Vector{T}, du::Vector{T})
n = length(d)
du[1] += 1/8
dl[n-1] += 1/8
M = Tridiagonal(dl, d, du)
end
# We have 3 functions for computing indices and coefficients:
# interp_coef: fast, computes just the coefficients
# interp_index_coef: fast, computes both indices and coefficients
# interp_index: slow, computes just the indices
# The latter is rarely used (presumably, only upon InterpGridCoefs
# allocation), and hence should not be performance-critical, so the
# code is kept simple.
# The motivation for this organization is that in the "generic" case
# (see below), the overhead of looping is such that it's better to
# compute the indices and coefficients at the same time. However, when
# you don't need the indices, for fixed dimensions it's a significant
# savings (roughly 2x, at least for 3d) to just compute the
# coefficients.
function interpolate_index(index::Vector{Int}, coord1d::Vector{Vector{Int}}, s)
N = length(coord1d)
l = map(length, coord1d)
i = 1
for c in Counter(l)
indx = s[1]*coord1d[1][c[1]]
for idim = 2:N
indx += s[idim]*coord1d[idim][c[idim]]
end
index[i] = indx
i += 1
end
end
# This is the main bottleneck, so it pays handsomely to specialize on
# dimension.
function interpolate_index_coef{T}(indices::Array{Int}, coefs::Array{T},
coord1d::Vector{Vector{Int}}, coef1d::Vector{Vector{T}}, strides)
n_dims = length(coef1d)
l = length(coef1d[1])
if n_dims == 1
copy!(coefs, coef1d[1])
s = strides[1]
c = coord1d[1]
for i = 1:l
indices[i] = (c[i]-1)*s + 1
end
elseif n_dims == 2
s1 = strides[1]
s2 = strides[2]
cd1 = coord1d[1]
cd2 = coord1d[2]
cf1 = coef1d[1]
cf2 = coef1d[2]
ind = 1
for i2 = 1:l
offset = (cd2[i2]-1)*s2
p = cf2[i2]
for i1 = 1:l
indices[ind] = offset + (cd1[i1]-1)*s1 + 1
coefs[ind] = p*cf1[i1]
ind += 1
end
end
elseif n_dims == 3
s1 = strides[1]
s2 = strides[2]
s3 = strides[3]
cd1 = coord1d[1]
cd2 = coord1d[2]
cd3 = coord1d[3]
cf1 = coef1d[1]
cf2 = coef1d[2]
cf3 = coef1d[3]
ind = 1
for i3 = 1:l
offset3 = (cd3[i3]-1)*s3
p3 = cf3[i3]
for i2 = 1:l
offset2 = offset3 + (cd2[i2]-1)*s2
p2 = p3*cf2[i2]
for i1 = 1:l
indices[ind] = offset2 + (cd1[i1]-1)*s1 + 1
coefs[ind] = p2*cf1[i1]
ind += 1
end
end
end
elseif n_dims == 4
s1 = strides[1]
s2 = strides[2]
s3 = strides[3]
s4 = strides[4]
cd1 = coord1d[1]
cd2 = coord1d[2]
cd3 = coord1d[3]
cd4 = coord1d[4]
cf1 = coef1d[1]
cf2 = coef1d[2]
cf3 = coef1d[3]
cf4 = coef1d[4]
ind = 1
for i4 = 1:l
offset4 = (cd4[i4]-1)*s4
p4 = cf4[i4]
for i3 = 1:l
offset3 = offset4 + (cd3[i3]-1)*s3
p3 = p4*cf3[i3]
for i2 = 1:l
offset2 = offset3 + (cd2[i2]-1)*s2
p2 = p3*cf2[i2]
for i1 = 1:l
indices[ind] = offset2 + (cd1[i1]-1)*s1 + 1
coefs[ind] = p2*cf1[i1]
ind += 1
end
end
end
end
else
interpolate_index_coef_generic(indices, coefs, coord1d, coef1d, strides)
end
end
function interpolate_coef{T}(coefs::Array{T}, coef1d::Vector{Vector{T}})
n_dims = length(coef1d)
l = length(coef1d[1])
if n_dims == 1
copy!(coefs, coef1d[1])
elseif n_dims == 2
cf1 = coef1d[1]
cf2 = coef1d[2]
ind = 1
for i2 = 1:l
p = cf2[i2]
for i1 = 1:l
coefs[ind] = p*cf1[i1]
ind += 1
end
end
elseif n_dims == 3
cf1 = coef1d[1]
cf2 = coef1d[2]
cf3 = coef1d[3]
ind = 1
for i3 = 1:l
p3 = cf3[i3]
for i2 = 1:l
p2 = p3*cf2[i2]
for i1 = 1:l
coefs[ind] = p2*cf1[i1]
ind += 1
end
end
end
elseif n_dims == 4
cf1 = coef1d[1]
cf2 = coef1d[2]
cf3 = coef1d[3]
cf4 = coef1d[4]
ind = 1
for i4 = 1:l
p4 = cf4[i4]
for i3 = 1:l
p3 = p4*cf3[i3]
for i2 = 1:l
p2 = p3*cf2[i2]
for i1 = 1:l
coefs[ind] = p2*cf1[i1]
ind += 1
end
end
end
end
else
interp_coef_generic(coefs, coef1d)
end
end
function interpolate_index_coef_generic{T}(indices::Array{Int}, coefs::Array{T},
coord1d::Vector{Vector{Int}}, coef1d::Vector{Vector{T}}, strides)
n_dims = length(coord1d)
l = length(coord1d[1])
c = fill(1, n_dims)
offset = Array(Int, n_dims)
p = Array(T, n_dims)
offset[end] = (coord1d[end][1]-1)*strides[end]
p[end] = coef1d[end][1]
for idim = n_dims-1:-1:1
offset[idim] = offset[idim+1] + (coord1d[idim][1]-1)*strides[idim]
p[idim] = p[idim+1] * coef1d[idim][1]
end
ind = 1
while c[n_dims] <= l
indices[ind] = offset[1]+1
coefs[ind] = p[1]
ind += 1
c[1] += 1
thisc = c[1]
if thisc <= l
if n_dims > 1
p[1] = p[2] * coef1d[1][thisc]
offset[1] = offset[2] + (coord1d[1][thisc]-1)*strides[1]
else
p[1] = coef1d[1][thisc]
offset[1] = (coord1d[1][thisc]-1)*strides[1]
end
else
idim = 1
while c[idim] > l && idim < n_dims
c[idim] = 1
c[idim+1] += 1
idim += 1
end
if idim == n_dims
thisc = c[idim]
if thisc <= l
p[idim] = coef1d[idim][thisc]
offset[idim] = (coord1d[idim][thisc]-1)*strides[idim]
idim -= 1
end
end
while idim > 0 && idim < n_dims
thisc = c[idim]
offset[idim] = offset[idim+1] + (coord1d[idim][thisc]-1)*strides[idim]
p[idim] = p[idim+1] * coef1d[idim][thisc]
idim -= 1
end
end
end
end
function interpolate_coef_generic{T}(indices::Array{Int}, coefs::Array{T},
coord1d::Vector{Vector{Int}}, coef1d::Vector{Vector{T}}, strides)
n_dims = length(coord1d)
l = length(coord1d[1])
c = ones(Int, n_dims)
offset = Array(Int, n_dims)
p = Array(T, n_dims)
p[end] = coef1d[end][1]
for idim = n_dims-1:-1:1
p[idim] = p[idim+1] * coef1d[idim][1]
end
ind = 1
while c[n_dims] <= l
coefs[ind] = p[1]
ind += 1
c[1] += 1
thisc = c[1]
if thisc <= l
if n_dims > 1
p[1] = p[2] * coef1d[1][thisc]
else
p[1] = coef1d[1][thisc]
end
else
idim = 1
while c[idim] > l && idim < n_dims
c[idim] = 1
c[idim+1] += 1
idim += 1
end
if idim == n_dims
thisc = c[idim]
if thisc <= l
p[idim] = coef1d[idim][thisc]
idim -= 1
end
end
while idim > 0 && idim < n_dims
thisc = c[idim]
p[idim] = p[idim+1] * coef1d[idim][thisc]
idim -= 1
end
end
end
end
function pad1_index(szt::Tuple, dimpad)
szv = [szt...]
for i in dimpad
szv[i] += 2
end
N = length(szt)
ind = cell(N)
for i in 1:N
if szv[i] > szt[i]
ind[i] = 2:szv[i]-1
else
ind[i] = 1:szv[i]
end
end
return szv, ind
end
pad1{BC<:BoundaryCondition}(Ain::AbstractArray, ::Type{BC}, dimpad...) = copy(Ain) # no padding needed for most types
pad1(Ain::AbstractArray, ::Type{BCfill}, dimpad...) = error("For BCfill, specify the fill value instead of the type BCfill")
function pad1(Ain::AbstractArray, f::Number, dimpad...)
sz, ind = pad1_index(size(Ain), dimpad)
A = fill(convert(eltype(Ain), f), sz...)
A[ind...] = Ain
return A
end