Welcome To Our Shell

Mister Spy & Souheyl Bypass Shell

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
Upload File :
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

bypass 1.0, Devloped By El Moujahidin (the source has been moved and devloped)
Email: contact@elmoujehidin.net bypass 1.0, Devloped By El Moujahidin (the source has been moved and devloped) Email: contact@elmoujehidin.net