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

Add InverseMultiQuadricKernel #396

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "KernelFunctions"
uuid = "ec8451be-7e33-11e9-00cf-bbf324bd1392"
version = "0.10.26"
version = "0.10.27"

[deps]
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
Expand Down
1 change: 1 addition & 0 deletions docs/src/kernels.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ PolynomialKernel
RationalKernel
RationalQuadraticKernel
GammaRationalKernel
InverseMultiQuadricKernel
```

### Spectral Mixture Kernels
Expand Down
1 change: 1 addition & 0 deletions src/KernelFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export FBMKernel
export MaternKernel, Matern12Kernel, Matern32Kernel, Matern52Kernel
export LinearKernel, PolynomialKernel
export RationalKernel, RationalQuadraticKernel, GammaRationalKernel
export InverseMultiQuadricKernel
export PiecewisePolynomialKernel
export PeriodicKernel, NeuralNetworkKernel
export KernelSum, KernelProduct, KernelTensorProduct
Expand Down
68 changes: 68 additions & 0 deletions src/basekernels/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,71 @@ function Base.show(io::IO, κ::GammaRationalKernel)
")",
)
end

@doc raw"""
InverseMultiQuadricKernel(; α::Real=1.0, c::Real=1.0, metric=Euclidean())

Inverse multiquadric kernel with respect to the `metric` with parameters `α` and `c`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this sentence is needed, it does not bring anything

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I guess one has to know at least what the inverse multiquadric kernel is. However, the same problem exists in all other docstrings. I added this sentence only to be consistent with them.


# Definition

For inputs ``x, x'`` and metric ``d(\cdot, \cdot)``, the inverse multiquadric kernel with
parameters ``\alpha, c > 0`` is defined as
```math
k(x, x'; \alpha, c) = \big(c + d(x, x')^2\big)^{-\alpha}.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this, it looks extremely similar to the polynomial kernel (except for -alpha < 0). Could this eventually be unified?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it is more similar to the rational quadratic kernel, therefore I put it in this file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the tests show it is the same as scaling an RQ kernel with rescaled inputs. The construction is a bit annoying though, so the question is more: should it be a separate kernel or a function that constructs the corresponding RQ kernel?

```
By default, ``d`` is the Euclidean metric ``d(x, x') = \|x - x'\|_2``.

For ``\alpha = c = 1``, the [`GammaRationalKernel`](@ref) with parameters ``\alpha = 1``
and ``\gamma = 2`` is recovered.

For ``\alpha = 1/2`` and ``c = 1``, the [`RationalQuadraticKernel`](@ref) with parameter
``\alpha = 1/2`` is recovered.

# References

Micchelli, C.A. (1986). Interpolation of scattered data: Distance matrices and conditionally
positive definite functions. Constructive Approximation 2, 11-22.
"""
struct InverseMultiQuadricKernel{Tα<:Real,Tc<:Real,M} <: SimpleKernel
α::Vector{Tα}
theogf marked this conversation as resolved.
Show resolved Hide resolved
c::Vector{Tc}
metric::M

function InverseMultiQuadricKernel(α::Real, c::Real, metric)
@check_args(InverseMultiQuadricKernel, α, α > zero(α), "α > 0")
@check_args(InverseMultiQuadricKernel, c, c > zero(c), "c > 0")
return new{typeof(α),typeof(c),typeof(metric)}([α], [c], metric)
end
end

function InverseMultiQuadricKernel(;
alpha::Real=1.0, α::Real=alpha, c::Real=1.0, metric=Euclidean()
)
return InverseMultiQuadricKernel(α, c, metric)
end

@functor InverseMultiQuadricKernel

function kappa(k::InverseMultiQuadricKernel, d::Real)
return (first(k.c) + d^2)^(-first(k.α))
end
function kappa(k::InverseMultiQuadricKernel{<:Real,<:Real,<:Euclidean}, d2::Real)
return (first(k.c) + d2)^(-first(k.α))
end

metric(k::InverseMultiQuadricKernel) = k.metric
metric(::InverseMultiQuadricKernel{<:Real,<:Real,<:Euclidean}) = SqEuclidean()

function Base.show(io::IO, k::InverseMultiQuadricKernel)
return print(
io,
"Inverse Multiquadric Kernel (α = ",
first(k.α),
", c = ",
first(k.c),
", metric = ",
k.metric,
")",
)
end
44 changes: 44 additions & 0 deletions test/basekernels/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,48 @@
test_ADs(x -> GammaRationalKernel(; α=x[1], γ=x[2]), [a, 1 + 0.5 * rand()])
test_params(GammaRationalKernel(; α=a, γ=x), ([a], [x]))
end

@testset "InverseMultiQuadricKernel" begin
α = rand()
c = rand()
k = InverseMultiQuadricKernel(; α=α, c=c)

@testset "IMQ (α = c = 1) ≈ GammaRationalKernel (α = 1, γ = 2)" begin
@test isapprox(
InverseMultiQuadricKernel(; α=1, c=1)(v1, v2),
GammaRationalKernel(; α=1, γ=2)(v1, v2);
atol=1e-6,
rtol=1e-6,
)
end

@testset "IMQ (α = 1/2, c = 1) ≈ RationalQuadraticKernel (α = 1/2)" begin
@test isapprox(
InverseMultiQuadricKernel(; α=0.5, c=1)(v1, v2),
RationalQuadraticKernel(; α=0.5)(v1, v2);
atol=1e-6,
rtol=1e-6,
)
end

@testset "IMQ ≈ c^(-α) * RationalQuadraticKernel for same α and rescaled inputs" begin
rqkernel =
c^(-α) * RationalQuadraticKernel(; α=α) ∘ ScaleTransform(sqrt(2 * α / c))
@test isapprox(k(v1, v2), rqkernel(v1, v2); atol=1e-6, rtol=1e-6)
end

@test metric(InverseMultiQuadricKernel()) == SqEuclidean()
@test metric(InverseMultiQuadricKernel(; α=α, c=c)) == SqEuclidean()
@test repr(k) ==
"Inverse Multiquadric Kernel (α = $α, c = $c, metric = Euclidean(0.0))"

k2 = InverseMultiQuadricKernel(; α=α, c=c, metric=WeightedEuclidean(ones(3)))
@test metric(k2) isa WeightedEuclidean
@test k2(v1, v2) ≈ k(v1, v2)

# Standardised tests.
TestUtils.test_interface(k, Float64)
test_ADs(x -> InverseMultiQuadricKernel(; alpha=exp(x[1]), c=exp(x[2])), [α, c])
test_params(k, ([α], [c]))
end
end