Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slight refactor of monomial basis #27

Merged
merged 15 commits into from
Jul 31, 2024
Merged
2 changes: 0 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ jobs:
fail-fast: false
matrix:
version:
- '1.6'
- '1.7'
- '1.8'
- '1.9'
Expand All @@ -28,7 +27,6 @@ jobs:
- ubuntu-latest
arch:
- x64
- x86
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
Expand Down
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "RadialBasisFunctions"
uuid = "79ee0514-adf7-4479-8807-6f72ea8967e8"
authors = ["Kyle Beggs"]
version = "0.2.2"
version = "0.2.3"

[deps]
ChunkSplitters = "ae650224-84b6-46f8-82ea-d812ca08434e"
Expand All @@ -22,7 +22,7 @@ NearestNeighbors = "0.4"
PrecompileTools = "1"
StaticArraysCore = "1.4"
SymRCM = "0.2"
julia = "1.6"
julia = "1.7"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
6 changes: 3 additions & 3 deletions src/RadialBasisFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export MonomialBasis
include("utils.jl")
export find_neighbors, reorder_points!

include("linalg/stencil.jl")
include("solve.jl")

include("operators/operators.jl")
export RadialBasisOperator, update_weights!
Expand All @@ -40,7 +40,7 @@ export Directional, directional
include("operators/virtual.jl")
export ∂virtual

include("operators/monomial.jl")
include("operators/monomial/monomial.jl")

include("operators/operator_combinations.jl")

Expand All @@ -63,7 +63,7 @@ using PrecompileTools
basis_funcs = [
IMQ(1),
Gaussian(1),
PHS(1; poly_deg=-1),
PHS(1; poly_deg=0),
PHS(3; poly_deg=0),
PHS(5; poly_deg=1),
PHS(7; poly_deg=2),
Expand Down
30 changes: 20 additions & 10 deletions src/basis/basis.jl
Original file line number Diff line number Diff line change
@@ -1,29 +1,39 @@
"""
abstract type AbstractRadialBasis end
abstract type AbstractBasis end
"""
abstract type AbstractRadialBasis end
abstract type AbstractBasis end

"""
abstract type AbstractRadialBasis <: AbstractBasis end
"""
abstract type AbstractRadialBasis <: AbstractBasis end

struct ℒRadialBasisFunction{F<:Function}
f::F
end
(ℒrbf::ℒRadialBasisFunction)(x, xᵢ) = ℒrbf.f(x, xᵢ)

struct ℒMonomial{F<:Function}
struct ℒMonomialBasis{Dim,Deg,F<:Function}
f::F
function ℒMonomialBasis(dim::T, deg::T, f) where {T<:Int}
if deg < 0
throw(ArgumentError("Monomial basis must have non-negative degree"))
end
return new{dim,deg,typeof(f)}(f)
end
end
(ℒmon::ℒMonomial)(m, x) = ℒmon.f(m, x)
function (ℒmon::ℒMonomialBasis{Dim,Deg})(x) where {Dim,Deg}
b = ones(_get_underlying_type(x), binomial(Dim + Deg, Dim))
ℒmon(b, x)
return b
end
(m::ℒMonomialBasis)(b, x) = m.f(b, x)

include("polyharmonic_spline.jl")
include("inverse_multiquadric.jl")
include("gaussian.jl")
include("monomial.jl")

function ∂(basis::B, order::T, dim::T) where {T<:Int,B<:AbstractRadialBasis}
return ∂(basis, Val(order), dim)
end
∂(basis::B, dim::T) where {T<:Int,B} = ∂(basis, Val(1), dim)
∂²(basis::B, dim::T) where {T<:Int,B} = ∂(basis, Val(2), dim)

# pretty printing
unicode_order(::Val{1}) = ""
unicode_order(::Val{2}) = "²"
Expand Down
4 changes: 2 additions & 2 deletions src/basis/gaussian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ end

(rbf::Gaussian)(x, xᵢ) = exp(-(rbf.ε * euclidean(x, xᵢ))^2)

function ∂(rbf::Gaussian, ::Val{1}, dim::Int)
function ∂(rbf::Gaussian, dim::Int)
function ∂ℒ(x, xᵢ)
return -2 * rbf.ε^2 * (x[dim] - xᵢ[dim]) * exp(-rbf.ε^2 * sqeuclidean(x, xᵢ))
end
Expand All @@ -30,7 +30,7 @@ function ∇(rbf::Gaussian)
end
end

function ∂(rbf::Gaussian, ::Val{2}, dim::Int)
function ∂²(rbf::Gaussian, dim::Int)
function ∂²ℒ(x, xᵢ)
ε2 = rbf.ε^2
return (4 * ε2^2 * (x[dim] - xᵢ[dim])^2 - 2 * ε2) * exp(-ε2 * sqeuclidean(x, xᵢ))
Expand Down
4 changes: 2 additions & 2 deletions src/basis/inverse_multiquadric.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ end

(rbf::IMQ)(x, xᵢ) = 1 / sqrt((euclidean(x, xᵢ) * rbf.ε)^2 + 1)

function ∂(rbf::IMQ, ::Val{1}, dim::Int=1)
function ∂(rbf::IMQ, dim::Int=1)
function ∂ℒ(x, xᵢ)
ε2 = rbf.ε .^ 2
return (xᵢ[dim] - x[dim]) .* (ε2 / sqrt((ε2 * sqeuclidean(x, xᵢ) + 1)^3))
Expand All @@ -29,7 +29,7 @@ function ∇(rbf::IMQ)
end
end

function ∂(rbf::IMQ, ::Val{2}, dim::Int=1)
function ∂²(rbf::IMQ, dim::Int=1)
function ∂²ℒ(x, xᵢ)
ε2 = rbf.ε .^ 2
ε4 = ε2^2
Expand Down
114 changes: 87 additions & 27 deletions src/basis/monomial.jl
Original file line number Diff line number Diff line change
@@ -1,39 +1,100 @@
"""
struct MonomialBasis{T<:Int,B<:Function}
struct MonomialBasis{Dim,Deg} <: AbstractBasis

Multivariate Monomial basis.
n ∈ N: length of array, i.e., x ∈ Rⁿ
deg ∈ N: degree
`Dim` dimensional monomial basis of order `Deg`.
"""
struct MonomialBasis{T<:Int,B}
n::T
deg::T
basis!::B
function MonomialBasis(n::T, deg::T) where {T<:Int}
struct MonomialBasis{Dim,Deg,F<:Function} <: AbstractBasis
f::F
function MonomialBasis(dim::T, deg::T) where {T<:Int}
if deg < 0
basis! = nothing
else
basis! = build_monomial_basis(n, deg)
throw(ArgumentError("Monomial basis must have non-negative degree"))
end
return new{T,typeof(basis!)}(n, deg, basis!)
f = _get_monomial_basis(Val(dim), Val(deg))
return new{dim,deg,typeof(f)}(f)
end
end

function (m::MonomialBasis)(x::AbstractVector{T}) where {T}
b = ones(T, binomial(m.n + m.deg, m.n))
m.basis!(b, x)
function (m::MonomialBasis{Dim,Deg})(x) where {Dim,Deg}
b = ones(_get_underlying_type(x), binomial(Dim + Deg, Dim))
m.f(b, x)
return b
end
(m::MonomialBasis)(b, x) = m.basis!(b, x)
(m::MonomialBasis)(b, x) = m.f(b, x)

function build_monomial_basis(n::T, deg::T) where {T<:Int}
if deg == 0
basis! = (b, x) -> b .= one(eltype(x))
return basis!
for Dim in (:1, :2, :3)
@eval begin
function _get_monomial_basis(::Val{$Dim}, ::Val{0})
return function basis!(b, x)
b[1] = one(_get_underlying_type(x))
return nothing
end
end
end
end

function _get_monomial_basis(::Val{1}, ::Val{N}) where {N}
return function basis!(b, x)
b[1] = one(_get_underlying_type(x))
if N > 0
for n in 1:N
b[n + 1] = only(x)^n
end
end
return nothing
end
end

function _get_monomial_basis(::Val{2}, ::Val{1})
return function basis!(b, x)
b[1] = one(eltype(x))
b[2] = x[1]
b[3] = x[2]
return nothing
end
end

function _get_monomial_basis(::Val{2}, ::Val{2})
return function basis!(b, x)
b[1] = one(eltype(x))
b[2] = x[1]
b[3] = x[2]
b[4] = x[1] * x[2]
b[5] = x[1] * x[1]
b[6] = x[2] * x[2]
return nothing
end
end

function _get_monomial_basis(::Val{3}, ::Val{1})
return function basis!(b, x)
b[1] = one(eltype(x))
b[2] = x[1]
b[3] = x[2]
b[4] = x[3]
return nothing
end
e = multiexponents(n + 1, deg)
e = map(i -> getindex.(e, i), 1:n)
ids = map(j -> map(i -> findall(x -> x >= i, e[j]), 1:deg), 1:n)
end

function _get_monomial_basis(::Val{3}, ::Val{2})
return function basis!(b, x)
b[1] = one(eltype(x))
b[2] = x[1]
b[3] = x[2]
b[4] = x[3]
b[5] = x[1] * x[2]
b[6] = x[1] * x[3]
b[7] = x[2] * x[3]
b[8] = x[1] * x[1]
b[9] = x[2] * x[2]
b[10] = x[3] * x[3]
return nothing
end
end

function _get_monomial_basis(::Val{Dim}, ::Val{Deg}) where {Dim,Deg}
e = multiexponents(Dim + 1, Deg)
e = map(i -> getindex.(e, i), 1:Dim)
ids = map(j -> map(i -> findall(x -> x >= i, e[j]), 1:Deg), 1:Dim)
return build_monomial_basis(ids)
end

Expand All @@ -49,7 +110,6 @@ function build_monomial_basis(ids::Vector{Vector{Vector{T}}}) where {T<:Int}
return basis!
end

# pretty printing
function Base.show(io::IO, pb::MonomialBasis)
return print(io, "MonomialBasis, deg=$(pb.deg) in $(pb.n) dimensions")
function Base.show(io::IO, ::MonomialBasis{Dim,Deg}) where {Dim,Deg}
return print(io, "MonomialBasis of degree $(Deg) in $(Dim) dimensions")
end
16 changes: 8 additions & 8 deletions src/basis/polyharmonic_spline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ struct PHS1{T<:Int} <: AbstractPHS
end

(phs::PHS1)(x, xᵢ) = euclidean(x, xᵢ)
function ∂(::PHS1, ::Val{1}, dim::Int)
function ∂(::PHS1, dim::Int)
∂ℒ(x, xᵢ) = (x[dim] - xᵢ[dim]) / (euclidean(x, xᵢ) + DIV0_OFFSET)
return ℒRadialBasisFunction(∂ℒ)
end
function ∇(::PHS1)
∇ℒ(x, xᵢ) = (x .- xᵢ) / euclidean(x, xᵢ)
return ℒRadialBasisFunction(∇ℒ)
end
function ∂(::PHS1, ::Val{2}, dim::Int)
function ∂²(::PHS1, dim::Int)
function ∂²ℒ(x, xᵢ)
return (-(x[dim] - xᵢ[dim])^2 + sqeuclidean(x, xᵢ)) /
(euclidean(x, xᵢ)^3 + DIV0_OFFSET)
Expand Down Expand Up @@ -76,15 +76,15 @@ struct PHS3{T<:Int} <: AbstractPHS
end

(phs::PHS3)(x, xᵢ) = euclidean(x, xᵢ)^3
function ∂(::PHS3, ::Val{1}, dim::Int)
function ∂(::PHS3, dim::Int)
∂ℒ(x, xᵢ) = 3 * (x[dim] - xᵢ[dim]) * euclidean(x, xᵢ)
return ℒRadialBasisFunction(∂ℒ)
end
function ∇(::PHS3)
∇ℒ(x, xᵢ) = 3 * (x .- xᵢ) * euclidean(x, xᵢ)
return ℒRadialBasisFunction(∇ℒ)
end
function ∂(::PHS3, ::Val{2}, dim::Int)
function ∂²(::PHS3, dim::Int)
function ∂²ℒ(x, xᵢ)
return 3 * (sqeuclidean(x, xᵢ) + (x[dim] - xᵢ[dim])^2) /
(euclidean(x, xᵢ) + DIV0_OFFSET)
Expand Down Expand Up @@ -114,15 +114,15 @@ struct PHS5{T<:Int} <: AbstractPHS
end

(phs::PHS5)(x, xᵢ) = euclidean(x, xᵢ)^5
function ∂(::PHS5, ::Val{1}, dim::Int)
function ∂(::PHS5, dim::Int)
∂ℒ(x, xᵢ) = 5 * (x[dim] - xᵢ[dim]) * euclidean(x, xᵢ)^3
return ℒRadialBasisFunction(∂ℒ)
end
function ∇(::PHS5)
∇ℒ(x, xᵢ) = 5 * (x .- xᵢ) * euclidean(x, xᵢ)^3
return ℒRadialBasisFunction(∇ℒ)
end
function ∂(::PHS5, ::Val{2}, dim::Int)
function ∂²(::PHS5, dim::Int)
return function ∂²ℒ(x, xᵢ)
return 5 * euclidean(x, xᵢ) * (3 * (x[dim] - xᵢ[dim])^2 + sqeuclidean(x, xᵢ))
end
Expand All @@ -149,15 +149,15 @@ struct PHS7{T<:Int} <: AbstractPHS
end

(phs::PHS7)(x, xᵢ) = euclidean(x, xᵢ)^7
function ∂(::PHS7, ::Val{1}, dim::Int)
function ∂(::PHS7, dim::Int)
∂ℒ(x, xᵢ) = 7 * (x[dim] - xᵢ[dim]) * euclidean(x, xᵢ)^5
return ℒRadialBasisFunction(∂ℒ)
end
function ∇(::PHS7)
∇ℒ(x, xᵢ) = 7 * (x .- xᵢ) * euclidean(x, xᵢ)^5
return ℒRadialBasisFunction(∇ℒ)
end
function ∂(::PHS7, ::Val{2}, dim::Int)
function ∂²(::PHS7, dim::Int)
function ∂²ℒ(x, xᵢ)
return 7 * euclidean(x, xᵢ)^3 * (5 * (x[dim] - xᵢ[dim])^2 + sqeuclidean(x, xᵢ))
end
Expand Down
7 changes: 4 additions & 3 deletions src/interpolation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ function (rbfi::Interpolator)(x::T) where {T}
poly = zero(eltype(T))
if !isempty(rbfi.monomial_weights)
val_poly = rbfi.monomial_basis(x)
for i in eachindex(rbfi.monomial_weights)
poly += rbfi.monomial_weights[i] * val_poly[i]
for (i, val) in enumerate(val_poly)
poly += rbfi.monomial_weights[i] * val
end
end
return rbf + poly
Expand All @@ -59,6 +59,7 @@ function Base.show(io::IO, op::Interpolator)
io,
"└─Basis: ",
print_basis(op.rbf_basis),
" with degree $(op.monomial_basis.deg) Monomial",
" with degree $(_get_deg(op.monomial_basis)) Monomial",
)
end
_get_deg(::MonomialBasis{Dim,Deg}) where {Dim,Deg} = Deg
12 changes: 2 additions & 10 deletions src/operators/directional.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ function directional(
k::T=autoselect_k(data, basis),
adjl=find_neighbors(data, k),
) where {D<:AbstractArray,B<:AbstractRadialBasis,T<:Int}
f = ntuple(length(first(data))) do dim
return let dim = dim
x -> ∂(x, 1, dim)
end
end
f = ntuple(dim -> Base.Fix2(∂, dim), length(first(data)))
ℒ = Directional(f, v)
return RadialBasisOperator(ℒ, data, basis; k=k, adjl=adjl)
end
Expand All @@ -42,11 +38,7 @@ function directional(
k::T=autoselect_k(data, basis),
adjl=find_neighbors(data, eval_points, k),
) where {B<:AbstractRadialBasis,T<:Int}
f = ntuple(length(first(data))) do dim
return let dim = dim
x -> ∂(x, 1, dim)
end
end
f = ntuple(dim -> Base.Fix2(∂, dim), length(first(data)))
ℒ = Directional(f, v)
return RadialBasisOperator(ℒ, data, eval_points, basis; k=k, adjl=adjl)
end
Expand Down
Loading
Loading