From c6123dd876d333847878afd6c324c835d09f8853 Mon Sep 17 00:00:00 2001 From: David Widmann Date: Tue, 2 Nov 2021 02:37:22 +0100 Subject: [PATCH 1/2] Add `InverseMultiquadricKernel` --- Project.toml | 2 +- src/KernelFunctions.jl | 1 + src/basekernels/rational.jl | 68 ++++++++++++++++++++++++++++++++++++ test/basekernels/rational.jl | 44 +++++++++++++++++++++++ 4 files changed, 114 insertions(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index d3a56f055..925f510ed 100644 --- a/Project.toml +++ b/Project.toml @@ -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" diff --git a/src/KernelFunctions.jl b/src/KernelFunctions.jl index 37bde4a65..b7749e4f9 100644 --- a/src/KernelFunctions.jl +++ b/src/KernelFunctions.jl @@ -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 diff --git a/src/basekernels/rational.jl b/src/basekernels/rational.jl index 8ed396b51..c9a68b57b 100644 --- a/src/basekernels/rational.jl +++ b/src/basekernels/rational.jl @@ -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`. + +# 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}. +``` +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α} + 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 diff --git a/test/basekernels/rational.jl b/test/basekernels/rational.jl index f1a4faa86..675613e70 100644 --- a/test/basekernels/rational.jl +++ b/test/basekernels/rational.jl @@ -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 From 6ad3f0cf83e9773a77386f5342e0a3daf3d6b4fa Mon Sep 17 00:00:00 2001 From: David Widmann Date: Tue, 2 Nov 2021 03:02:37 +0100 Subject: [PATCH 2/2] Add kernel to documentation --- docs/src/kernels.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/kernels.md b/docs/src/kernels.md index 56f3cfb9b..0929b732e 100644 --- a/docs/src/kernels.md +++ b/docs/src/kernels.md @@ -95,6 +95,7 @@ PolynomialKernel RationalKernel RationalQuadraticKernel GammaRationalKernel +InverseMultiQuadricKernel ``` ### Spectral Mixture Kernels