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

Some improvement and additions to MO kernels #354

Merged
merged 54 commits into from
Aug 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
8427ae5
Fix type stability of independent kernel
Crown421 Aug 6, 2021
1a5ac23
Add convenience functions
Crown421 Aug 6, 2021
d79d24b
Add/fix tests
Crown421 Aug 7, 2021
4f23240
Suggested change for kernelmatrix computation
Crown421 Aug 7, 2021
a33c312
Add results to test script
Crown421 Aug 10, 2021
a729c01
Switching to new kernelmatrix for independent kernel, tests
Crown421 Aug 10, 2021
e1f92a8
Change type stability
Crown421 Aug 10, 2021
e7d7db9
New kernelmatrix for IntrinsicCoregion kernel, tests
Crown421 Aug 10, 2021
ee69c6e
JuliaFormatter
Crown421 Aug 10, 2021
d1d8d45
Improve code reuse, Traits
Crown421 Aug 10, 2021
d80453c
Use FillArray
Crown421 Aug 11, 2021
06cbb3d
Remove traits, move to explicit function
Crown421 Aug 11, 2021
d03b951
Relax matrixkernel types
Crown421 Aug 11, 2021
c8f8093
Adjust MOInput specifications
Crown421 Aug 11, 2021
cd6dedc
Merge branch 'mo-improvements' of github.com:Crown421/KernelFunctions…
Crown421 Aug 11, 2021
8b7410a
Merge branch 'master' into mo-improvements
Crown421 Aug 11, 2021
1978e25
Change supertype, move matrixkernel
Crown421 Aug 11, 2021
3ffd436
JuliaFormatter
Crown421 Aug 11, 2021
c42e43d
Merge branch 'master' into mo-improvements
Crown421 Aug 11, 2021
96bf55e
Remove forced typesymmetry, and improve fallback
Crown421 Aug 11, 2021
b649e65
Improve documentation, add matrixkernel to other kernels
Crown421 Aug 11, 2021
fe81b0a
Comment out specialized kernelmatrix!
Crown421 Aug 11, 2021
509dfd6
Add kernelmatrix! back in with version check
Crown421 Aug 11, 2021
33f3e87
Formatter
Crown421 Aug 11, 2021
0f9ce64
Improve doc phrasing
Crown421 Aug 12, 2021
51a3736
Merge branch 'master' into mo-improvements
Crown421 Aug 12, 2021
8459d0c
Change Union name
Crown421 Aug 12, 2021
1675598
Substantially improve tests
Crown421 Aug 12, 2021
0672a1f
Add ed clarity for lazy kronecker
Crown421 Aug 12, 2021
cf8e8f3
Improve tests for lmm and slfm
Crown421 Aug 12, 2021
31620e2
Formatter
Crown421 Aug 12, 2021
9b27b58
Update src/mokernels/mokernel.jl
Crown421 Aug 12, 2021
d68f86e
Remove comments
Crown421 Aug 13, 2021
59ff2c8
Add check for lmm kernel, tests
Crown421 Aug 13, 2021
7c99633
Merge branch 'mo-improvements' of github.com:Crown421/KernelFunctions…
Crown421 Aug 13, 2021
286d5d5
Fix constructor mistake
Crown421 Aug 13, 2021
cb37e0f
Remove kwarg dispatch
Crown421 Aug 13, 2021
fee8eaf
Remove matrixkernel and lazy kron
Crown421 Aug 15, 2021
3466daa
Merge branch 'master' into mo-improvements
Crown421 Aug 15, 2021
533f8fd
Remove matrixkernel export
Crown421 Aug 16, 2021
213b606
Update src/matrix/kernelkroneckermat.jl
Crown421 Aug 16, 2021
f2c6ae6
Update src/mokernels/independent.jl
Crown421 Aug 16, 2021
407ca80
Update src/mokernels/independent.jl
Crown421 Aug 16, 2021
6bcc83d
Update src/mokernels/mokernel.jl
Crown421 Aug 16, 2021
d5571df
helper function name, formatter
Crown421 Aug 16, 2021
13427a7
Merge branch 'master' into mo-improvements
Crown421 Aug 16, 2021
48db5a0
Remove explicit in-place tests
Crown421 Aug 16, 2021
43a5ab9
Remove temp file and bump patch
Crown421 Aug 16, 2021
f2ac5ed
Change helper function name
Crown421 Aug 16, 2021
dac5db7
Fixed rename oversight
Crown421 Aug 16, 2021
e61a668
Fix missing Union
Crown421 Aug 16, 2021
8cbb1eb
Silly mistake
Crown421 Aug 16, 2021
c72efd9
Make arguments more consistent
Crown421 Aug 16, 2021
11e6d56
Forgot to uncomment
Crown421 Aug 16, 2021
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.15"
version = "0.10.16"

[deps]
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
Expand Down
44 changes: 36 additions & 8 deletions src/mokernels/independent.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,45 @@ struct IndependentMOKernel{Tkernel<:Kernel} <: MOKernel
end

function (κ::IndependentMOKernel)((x, px)::Tuple{Any,Int}, (y, py)::Tuple{Any,Int})
if px == py
return κ.kernel(x, y)
else
return 0.0
end
return κ.kernel(x, y) * (px == py)
Crown421 marked this conversation as resolved.
Show resolved Hide resolved
end

function _kernelmatrix_kron_helper(::MOInputIsotopicByFeatures, Kfeatures, B)
return kron(Kfeatures, B)
end

function kernelmatrix(k::IndependentMOKernel, x::MOInput, y::MOInput)
function _kernelmatrix_kron_helper(::MOInputIsotopicByOutputs, Kfeatures, B)
return kron(B, Kfeatures)
end

function kernelmatrix(
k::IndependentMOKernel, x::MOI, y::MOI
) where {MOI<:IsotopicMOInputsUnion}
@assert x.out_dim == y.out_dim
temp = k.kernel.(x.x, permutedims(y.x))
return cat((temp for _ in 1:(y.out_dim))...; dims=(1, 2))
Kfeatures = kernelmatrix(k.kernel, x.x, y.x)
mtype = eltype(Kfeatures)
return _kernelmatrix_kron_helper(x, Kfeatures, Eye{mtype}(x.out_dim))
end

if VERSION >= v"1.6"
function _kernelmatrix_kron_helper!(K, ::MOInputIsotopicByFeatures, Kfeatures, B)
return kron!(K, Kfeatures, B)
end

function _kernelmatrix_kron_helper!(K, ::MOInputIsotopicByOutputs, Kfeatures, B)
return kron!(K, B, Kfeatures)
end

function kernelmatrix!(
K::AbstractMatrix, k::IndependentMOKernel, x::MOI, y::MOI
) where {MOI<:IsotopicMOInputsUnion}
@assert x.out_dim == y.out_dim
Ktmp = kernelmatrix(k.kernel, x.x, y.x)
mtype = eltype(Ktmp)
return _kernelmatrix_kron_helper!(
K, x, Ktmp, Matrix{mtype}(I, x.out_dim, x.out_dim)
)
end
end

function Base.show(io::IO, k::IndependentMOKernel)
Expand Down
22 changes: 22 additions & 0 deletions src/mokernels/intrinsiccoregion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,32 @@ function IntrinsicCoregionMOKernel(; kernel::Kernel, B::AbstractMatrix)
return IntrinsicCoregionMOKernel{typeof(kernel),typeof(B)}(kernel, B)
end

function IntrinsicCoregionMOKernel(kernel::Kernel, B::AbstractMatrix)
return IntrinsicCoregionMOKernel{typeof(kernel),typeof(B)}(kernel, B)
end
st-- marked this conversation as resolved.
Show resolved Hide resolved

function (k::IntrinsicCoregionMOKernel)((x, px)::Tuple{Any,Int}, (y, py)::Tuple{Any,Int})
return k.B[px, py] * k.kernel(x, y)
end

function kernelmatrix(
k::IntrinsicCoregionMOKernel, x::MOI, y::MOI
) where {MOI<:IsotopicMOInputsUnion}
@assert x.out_dim == y.out_dim
Kfeatures = kernelmatrix(k.kernel, x.x, y.x)
return _kernelmatrix_kron_helper(x, Kfeatures, k.B)
end

if VERSION >= v"1.6"
function kernelmatrix!(
K::AbstractMatrix, k::IntrinsicCoregionMOKernel, x::MOI, y::MOI
) where {MOI<:IsotopicMOInputsUnion}
@assert x.out_dim == y.out_dim
Kfeatures = kernelmatrix(k.kernel, x.x, y.x)
return _kernelmatrix_kron_helper!(K, x, Kfeatures, k.B)
end
end

function Base.show(io::IO, k::IntrinsicCoregionMOKernel)
return print(
io, "Intrinsic Coregion Kernel: ", k.kernel, " with ", size(k.B, 1), " outputs"
Expand Down
9 changes: 7 additions & 2 deletions src/mokernels/lmm.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
@doc raw"""
LinearMixingModelKernel(g, e::MOKernel, A::AbstractMatrix)
LinearMixingModelKernel(k::Kernel, H::AbstractMatrix)
LinearMixingModelKernel(Tk::AbstractVector{<:Kernel},Th::AbstractMatrix)

Kernel associated with the linear mixing model.
Kernel associated with the linear mixing model, taking a vector of `m` kernels and a `m × p` matrix H for a function with `p` outputs. Also accepts a single kernel `k` for use across all `m` basis vectors.

# Definition

Expand All @@ -20,6 +21,10 @@ mixing matrix of ``m`` basis vectors spanning the output space.
struct LinearMixingModelKernel{Tk<:AbstractVector{<:Kernel},Th<:AbstractMatrix} <: MOKernel
K::Tk
H::Th
function LinearMixingModelKernel(Tk::AbstractVector{<:Kernel}, H::AbstractMatrix)
@assert length(Tk) == size(H, 1) "Number of kernels and number of rows in H must match"
return new{typeof(Tk),typeof(H)}(Tk, H)
end
end

function LinearMixingModelKernel(k::Kernel, H::AbstractMatrix)
Expand Down
4 changes: 2 additions & 2 deletions src/mokernels/moinput.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ struct MOInputIsotopicByOutputs{S,T<:AbstractVector{S}} <: AbstractVector{Tuple{
out_dim::Integer
end

const IsotopicMOInputs = Union{MOInputIsotopicByFeatures,MOInputIsotopicByOutputs}
const IsotopicMOInputsUnion = Union{MOInputIsotopicByFeatures,MOInputIsotopicByOutputs}

function Base.getindex(inp::MOInputIsotopicByOutputs, ind::Integer)
@boundscheck checkbounds(inp, ind)
Expand All @@ -74,7 +74,7 @@ function Base.getindex(inp::MOInputIsotopicByFeatures, ind::Integer)
return feature, output_index
end

Base.size(inp::IsotopicMOInputs) = (inp.out_dim * length(inp.x),)
Base.size(inp::IsotopicMOInputsUnion) = (inp.out_dim * length(inp.x),)

function Base.vcat(x::MOInputIsotopicByFeatures, y::MOInputIsotopicByFeatures)
x.out_dim == y.out_dim || throw(DimensionMismatch("out_dim mismatch"))
Expand Down
2 changes: 1 addition & 1 deletion src/mokernels/slfm.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@doc raw"""
LatentFactorMOKernel(g, e::MOKernel, A::AbstractMatrix)
LatentFactorMOKernel(g::AbstractVector{<:Kernel}, e::MOKernel, A::AbstractMatrix)

Kernel associated with the semiparametric latent factor model.

Expand Down
24 changes: 17 additions & 7 deletions test/mokernels/independent.jl
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
@testset "independent" begin
x = MOInput([rand(5) for _ in 1:4], 3)
y = MOInput([rand(5) for _ in 1:4], 3)
outdim = 3
x = KernelFunctions.MOInputIsotopicByOutputs([rand(5) for _ in 1:4], outdim)
y = KernelFunctions.MOInputIsotopicByOutputs([rand(5) for _ in 1:4], outdim)
z = KernelFunctions.MOInputIsotopicByOutputs([rand(5) for _ in 1:2], outdim)

xIF = KernelFunctions.MOInputIsotopicByFeatures(x.x, outdim)
yIF = KernelFunctions.MOInputIsotopicByFeatures(y.x, outdim)
zIF = KernelFunctions.MOInputIsotopicByFeatures(z.x, outdim)

k = IndependentMOKernel(GaussianKernel())
@test k isa IndependentMOKernel
@test k isa MOKernel
@test k isa Kernel
@test k.kernel isa Kernel
@test k(x[2], y[2]) isa Real

@test kernelmatrix(k, x, y) == kernelmatrix(k, collect(x), collect(y))
@test kernelmatrix(k, x, x) == kernelmatrix(k, x)

x1 = MOInput(rand(5), 3) # Single dim input
@test k(x1[1], x1[1]) isa Real
@test kernelmatrix(k, x1) isa Matrix
## accuracy
KernelFunctions.TestUtils.test_interface(k, x, y, z)
KernelFunctions.TestUtils.test_interface(k, xIF, yIF, zIF)

# type stability (maybe move to test_interface?)
x2 = MOInput(rand(Float32, 4), 2)
@test k(x2[1], x2[2]) isa Float32
@test k(x2[1], x2[1]) isa Float32
@test eltype(typeof(kernelmatrix(k, x2))) <: Float32

@test string(k) ==
"Independent Multi-Output Kernel\n" *
Expand Down
31 changes: 25 additions & 6 deletions test/mokernels/intrinsiccoregion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,39 @@
rng = MersenneTwister(123)

dims = (in=3, out=2, obs=3)
rank = 1
r = 1

A = randn(dims.out, rank)
A = randn(dims.out, r)
B = A * transpose(A) + Diagonal(rand(dims.out))

X = [(rand(dims.in), rand(1:(dims.out))) for i in 1:(dims.obs)]
# XIF = [(rand(dims.in), rand(1:(dims.out))) for i in 1:(dims.obs)]
x = [rand(dims.in) for _ in 1:2]
XIF = KernelFunctions.MOInputIsotopicByFeatures(x, dims.out)
XIO = KernelFunctions.MOInputIsotopicByOutputs(x, dims.out)
y = [rand(dims.in) for _ in 1:2]
YIF = KernelFunctions.MOInputIsotopicByFeatures(y, dims.out)
YIO = KernelFunctions.MOInputIsotopicByOutputs(y, dims.out)
z = [rand(dims.in) for _ in 1:3]
ZIF = KernelFunctions.MOInputIsotopicByFeatures(z, dims.out)
ZIO = KernelFunctions.MOInputIsotopicByOutputs(z, dims.out)

kernel = SqExponentialKernel()
icoregionkernel = IntrinsicCoregionMOKernel(; kernel=kernel, B=B)
icoregionkernel = IntrinsicCoregionMOKernel(kernel, B)

icoregionkernel2 = IntrinsicCoregionMOKernel(; kernel=kernel, B=B)
@test icoregionkernel == icoregionkernel2

@test icoregionkernel.B == B
@test icoregionkernel.kernel == kernel
@test icoregionkernel(X[1], X[1]) ≈ B[X[1][2], X[1][2]] * kernel(X[1][1], X[1][1])
@test icoregionkernel(X[1], X[end]) ≈ B[X[1][2], X[end][2]] * kernel(X[1][1], X[end][1])
@test icoregionkernel(XIF[1], XIF[1]) ≈
B[XIF[1][2], XIF[1][2]] * kernel(XIF[1][1], XIF[1][1])
@test icoregionkernel(XIF[1], XIF[end]) ≈
B[XIF[1][2], XIF[end][2]] * kernel(XIF[1][1], XIF[end][1])

# kernelmatrix
KernelFunctions.TestUtils.test_interface(icoregionkernel, XIF, YIF, ZIF)

KernelFunctions.TestUtils.test_interface(icoregionkernel, XIO, YIO, ZIO)

KernelFunctions.TestUtils.test_interface(
icoregionkernel, Vector{Tuple{Float64,Int}}; dim_out=dims.out
Expand Down
36 changes: 27 additions & 9 deletions test/mokernels/lmm.jl
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
@testset "lmm" begin
rng = MersenneTwister(123)
FDM = FiniteDifferences.central_fdm(5, 1)
N = 10
N = 6
in_dim = 3
out_dim = 6
x1 = MOInput([rand(rng, in_dim) for _ in 1:N], out_dim)
x2 = MOInput([rand(rng, in_dim) for _ in 1:N], out_dim)
H = rand(4, 6)

k = LinearMixingModelKernel(
[Matern32Kernel(), SqExponentialKernel(), FBMKernel(), Matern32Kernel()], H
out_dim = 3
x1IO = KernelFunctions.MOInputIsotopicByOutputs(
[rand(rng, in_dim) for _ in 1:N], out_dim
)
x2IO = KernelFunctions.MOInputIsotopicByOutputs(
[rand(rng, in_dim) for _ in 1:N], out_dim
)
x3IO = KernelFunctions.MOInputIsotopicByOutputs(
[rand(rng, in_dim) for _ in 1:div(N, 2)], out_dim
)

latentkernels = [Matern32Kernel(), SqExponentialKernel(), FBMKernel(), Matern32Kernel()]
H = rand(length(latentkernels), out_dim)
k = LinearMixingModelKernel(latentkernels, H)

badH = rand(length(latentkernels) - 1, out_dim)
@test_throws AssertionError LinearMixingModelKernel(latentkernels, badH)

@test k isa LinearMixingModelKernel
@test k isa MOKernel
@test k isa Kernel
@test k(x1[1], x2[1]) isa Real
@test k(x1IO[1], x2IO[1]) isa Real

@test string(k) == "Linear Mixing Model Multi-Output Kernel"
@test repr("text/plain", k) == (
Expand All @@ -25,6 +35,14 @@
"\tMatern 3/2 Kernel (metric = Euclidean(0.0))"
)

TestUtils.test_interface(k, x1IO, x2IO, x3IO)

x1IF = KernelFunctions.MOInputIsotopicByFeatures(x1IO.x, out_dim)
x2IF = KernelFunctions.MOInputIsotopicByFeatures(x2IO.x, out_dim)
x3IF = KernelFunctions.MOInputIsotopicByFeatures(x3IO.x, out_dim)

TestUtils.test_interface(k, x1IF, x2IF, x3IF)

k = LinearMixingModelKernel(SEKernel(), H)

@test k isa LinearMixingModelKernel
Expand Down
34 changes: 25 additions & 9 deletions test/mokernels/slfm.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
@testset "slfm" begin
rng = MersenneTwister(123)
FDM = FiniteDifferences.central_fdm(5, 1)
N = 10
in_dim = 5
N = 6
in_dim = 3
out_dim = 4
x1 = MOInput([rand(rng, in_dim) for _ in 1:N], out_dim)
x2 = MOInput([rand(rng, in_dim) for _ in 1:N], out_dim)
x1IO = KernelFunctions.MOInputIsotopicByOutputs(
[rand(rng, in_dim) for _ in 1:N], out_dim
)
x2IO = KernelFunctions.MOInputIsotopicByOutputs(
[rand(rng, in_dim) for _ in 1:N], out_dim
)
x3IO = KernelFunctions.MOInputIsotopicByOutputs(
[rand(rng, in_dim) for _ in 1:div(N, 2)], out_dim
)
x1IO = MOInput([rand(rng, in_dim) for _ in 1:N], out_dim)
x2IO = MOInput([rand(rng, in_dim) for _ in 1:N], out_dim)

k = LatentFactorMOKernel(
[Matern32Kernel(), SqExponentialKernel(), FBMKernel()],
Expand All @@ -15,10 +24,17 @@
@test k isa LatentFactorMOKernel
@test k isa MOKernel
@test k isa Kernel
@test k(x1[1], x2[1]) isa Real
@test k(x1IO[1], x2IO[1]) isa Real

@test kernelmatrix(k, x1IO, x2IO) ≈ kernelmatrix(k, collect(x1IO), collect(x2IO))

TestUtils.test_interface(k, x1IO, x2IO, x3IO)

x1IF = KernelFunctions.MOInputIsotopicByFeatures(x1IO.x, out_dim)
x2IF = KernelFunctions.MOInputIsotopicByFeatures(x2IO.x, out_dim)
x3IF = KernelFunctions.MOInputIsotopicByFeatures(x3IO.x, out_dim)

@test kernelmatrix(k, x1, x2) ≈ kernelmatrix(k, collect(x1), collect(x2))
@test kernelmatrix(k, x1, x1) ≈ kernelmatrix(k, x1)
TestUtils.test_interface(k, x1IF, x2IF, x3IF)

@test string(k) == "Semi-parametric Latent Factor Multi-Output Kernel"
@test repr("text/plain", k) == (
Expand All @@ -31,13 +47,13 @@
)

# AD test
function test_slfm(A::AbstractMatrix, x1, x2)
function test_slfm(A::AbstractMatrix, x1IO, x2IO)
k = LatentFactorMOKernel(
[Matern32Kernel(), SqExponentialKernel(), FBMKernel()],
IndependentMOKernel(GaussianKernel()),
A,
)
return k((x1, 1), (x2, 1))
return k((x1IO, 1), (x2IO, 1))
end

k = LatentFactorMOKernel(
Expand Down