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 37 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
5 changes: 5 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ type enables specialised implementations of e.g. [`kernelmatrix`](@ref) for

To find out more about the background, read this [review of kernels for vector-valued functions](https://arxiv.org/pdf/1106.6251.pdf).

If you are interested in the matrix-kernel interpretation, Kernelfunction.jl provides a convenience function that computes the resulting kernel when applied to a pair of inputs
```@docs
matrixkernel
```

## Generic Utilities

KernelFunctions also provides miscellaneous utility functions.
Expand Down
1 change: 1 addition & 0 deletions src/KernelFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export ColVecs, RowVecs
export MOInput, prepare_isotopic_multi_output_data, prepare_heterotopic_multi_output_data
export IndependentMOKernel,
LatentFactorMOKernel, IntrinsicCoregionMOKernel, LinearMixingModelKernel
export matrixkernel
Crown421 marked this conversation as resolved.
Show resolved Hide resolved

# Reexports
export tensor, ⊗, compose
Expand Down
34 changes: 34 additions & 0 deletions src/matrix/kernelkroneckermat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,37 @@ end
k(x,x') = ∏ᵢᴰ k(xᵢ,x'ᵢ)
"""
@inline iskroncompatible(κ::Kernel) = false # Default return for kernels

@inline ismatrixkroncompatible(κ::MOKernel) = false # Default return for kernels
@inline ismatrixkroncompatible(κ::IndependentMOKernel) = true
@inline ismatrixkroncompatible(κ::IntrinsicCoregionMOKernel) = true
Copy link
Member

Choose a reason for hiding this comment

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

Why would this be separate from iskroncompatible? If it's not possible to reuse iskroncompatible, could you add a docstring explaining why this one is different (and how so)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question. I did this because I wanted to avoid confusion with the first two functions, because the MO kernel matrix construction is distinct from the kronecker construction that was there already.
I realize now that I should have used a different name than kernelkronmat for this.

Copy link
Member

Choose a reason for hiding this comment

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

kernelkronmat seems fine to me - it's basically saying "please give me a lazy Kronecker" whether it's because we have outputs-as-inputs or seperable-on-grid-of-features or something else


function _mo_kernelmatrix_kron(::MOInputIsotopicByFeatures, K, B)
return Kronecker.kronecker(K, B)
end

function _mo_kernelmatrix_kron(::MOInputIsotopicByOutputs, K, B)
return Kronecker.kronecker(B, K)
end

function kernelkronmat(
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 _mo_kernelmatrix_kron(Ktmp, Eye{mtype}(x.out_dim), x)
end

function kernelkronmat(
k::IntrinsicCoregionMOKernel, x::MOI, y::MOI
) where {MOI<:IsotopicMOInputsUnion}
@assert x.out_dim == y.out_dim
Ktmp = kernelmatrix(k.kernel, x.x, y.x)
return _mo_kernelmatrix_kron(Ktmp, k.B, x)
end
Copy link
Member

Choose a reason for hiding this comment

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

We could unify these if we had a function that returns the "covariance over outputs" based on the kernel type

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think I understand this?

Copy link
Member

Choose a reason for hiding this comment

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

Along the lines of

Suggested change
function kernelkronmat(
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 _mo_kernelmatrix_kron(Ktmp, Eye{mtype}(x.out_dim), x)
end
function kernelkronmat(
k::IntrinsicCoregionMOKernel, x::MOI, y::MOI
) where {MOI<:IsotopicMOInputsUnion}
@assert x.out_dim == y.out_dim
Ktmp = kernelmatrix(k.kernel, x.x, y.x)
return _mo_kernelmatrix_kron(Ktmp, k.B, x)
end
_mo_output_covariance(k::IndependentMOKernel, out_dim) = Eye{Bool}(out_dim)
function _mo_output_covariance(k::IndependentMOKernel, out_dim)
@assert size(k.B) == (out_dim, out_dim)
return k.B
end
function kernelkronmat
k::Union{IndependentMOKernel, IntrinsicCoregionMOKernel}, x::MOI, y::MOI
) where {MOI<:IsotopicMOInputsUnion}
@assert x.out_dim == y.out_dim
Kfeatures = kernelmatrix(k.kernel, x.x, y.x)
Koutputs = _mo_output_covariance(k, x.out_dim)
return _mo_kernelmatrix_kron(Kfeatures, Koutputs)
end


function kernelkronmat(k::MOK, x::MOI) where {MOI<:IsotopicMOInputsUnion,MOK<:MOKernel}
willtebbutt marked this conversation as resolved.
Show resolved Hide resolved
@assert ismatrixkroncompatible(κ) "The chosen kernel is not compatible for Kronecker matrices"
return kernelkronmat(k, x, x)
Copy link
Member

Choose a reason for hiding this comment

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

This is going to be (somewhat) less efficient than separate implementations that then only call kernelmatrix(k.kernel, x.x)

Copy link
Member

Choose a reason for hiding this comment

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

that is, do we want separate methods for the sake of optimal efficiency? @willtebbutt

Copy link
Member

Choose a reason for hiding this comment

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

It would probably be nice, but I'm not going to insist on it going in in this PR provided it gets sorted in a follow up.

Copy link
Member

Choose a reason for hiding this comment

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

It would probably be nice, but I'm not going to insist on it going in in this PR provided it gets sorted in a follow up.

@Crown421 if you don't want to do it in this PR, please open a new issue for it instead then: )

end
42 changes: 34 additions & 8 deletions src/mokernels/independent.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,43 @@ 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 _kronkernelmatrix(Ktmp, B, ::MOInputIsotopicByFeatures)
Copy link
Member

@st-- st-- Aug 12, 2021

Choose a reason for hiding this comment

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

It's starting to get a bit confusing with _kronkernelmatrix, _kroneckerkernelmatrix, kernelkronmat... how about at least clarifying in the method name that this is multioutput-specific? e.g.

Suggested change
function _kronkernelmatrix(Ktmp, B, ::MOInputIsotopicByFeatures)
function _mo_kernelmatrix_kron(::MOInputIsotopicByFeatures, Kfeatures, Koutputs)

(moving the argument on which we actually dispatch to the front)

Copy link
Member

Choose a reason for hiding this comment

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

I'm not quite happy with this being a different pattern from kernelkronmat when they should otherwise be the same, kron vs Kronecker being the only difference. Could it be a single method that returns either dense kron() or lazy Kronecker? If that would lead to type instability issues, could dispatch on a Val{} maybe? lazy=Val{true} vs lazy=Val{false} (it's just an internal function anyways)

Copy link
Member

Choose a reason for hiding this comment

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

I agree with @st-- regarding argument names in particular -- Kfeatures and Koutputs are quite a bit more informative than Ktmp and B. The function name also makes more sense to me.

return kron(Ktmp, B)
end

function kernelmatrix(k::IndependentMOKernel, x::MOInput, y::MOInput)
function _kronkernelmatrix(Ktmp, B, ::MOInputIsotopicByOutputs)
return kron(B, Ktmp)
end
Crown421 marked this conversation as resolved.
Show resolved Hide resolved

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))
Ktmp = kernelmatrix(k.kernel, x.x, y.x)
mtype = eltype(Ktmp)
return _kronkernelmatrix(Ktmp, Eye{mtype}(x.out_dim), x)
end

if VERSION >= v"1.6"
function _kronkernelmatrix!(K, Ktmp, B, ::MOInputIsotopicByFeatures)
return kron!(K, Ktmp, B)
end
Crown421 marked this conversation as resolved.
Show resolved Hide resolved

function _kronkernelmatrix!(K, Ktmp, B, ::MOInputIsotopicByOutputs)
return kron!(K, B, Ktmp)
end
Crown421 marked this conversation as resolved.
Show resolved Hide resolved

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 _kronkernelmatrix!(K, Ktmp, Matrix{mtype}(I, x.out_dim, x.out_dim), x)
end
end

function Base.show(io::IO, k::IndependentMOKernel)
Expand Down
26 changes: 26 additions & 0 deletions src/mokernels/intrinsiccoregion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,36 @@ 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 matrixkernel(k::IntrinsicCoregionMOKernel, x, y)
return matrixkernel(k, x, y, size(k.B, 1))
end

function kernelmatrix(
k::IntrinsicCoregionMOKernel, x::MOI, y::MOI
) where {MOI<:IsotopicMOInputsUnion}
@assert x.out_dim == y.out_dim
Ktmp = kernelmatrix(k.kernel, x.x, y.x)
return _kronkernelmatrix(Ktmp, k.B, x)
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
Ktmp = kernelmatrix(k.kernel, x.x, y.x)
return _kronkernelmatrix!(K, Ktmp, k.B, x)
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
13 changes: 11 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 All @@ -32,6 +37,10 @@ function (κ::LinearMixingModelKernel)((x, px)::Tuple{Any,Int}, (y, py)::Tuple{A
return sum(κ.H[i, px] * κ.K[i](x, y) * κ.H[i, py] for i in 1:length(κ.K))
end

function matrixkernel(k::LinearMixingModelKernel, x, y)
Crown421 marked this conversation as resolved.
Show resolved Hide resolved
return matrixkernel(k, x, y, size(k.H, 2))
end

function Base.show(io::IO, k::LinearMixingModelKernel)
return print(io, "Linear Mixing Model Multi-Output Kernel")
end
Expand Down
2 changes: 2 additions & 0 deletions src/mokernels/moinput.jl
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ function prepare_isotopic_multi_output_data(x::AbstractVector, y::RowVecs)
return MOInputIsotopicByOutputs(x, size(y.X, 2)), vec(y.X)
end

IsotopicMOInputsUnion = Union{MOInputIsotopicByFeatures,MOInputIsotopicByOutputs}

"""
prepare_heterotopic_multi_output_data(
x::AbstractVector, y::AbstractVector{<:Real}, output_indices::AbstractVector{Int},
Expand Down
13 changes: 13 additions & 0 deletions src/mokernels/mokernel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,16 @@
Abstract type for kernels with multiple outpus.
"""
abstract type MOKernel <: Kernel end

"""
matrixkernel(k::MOK, x, y)
matrixkernel(k::IndependentMOKernel, x, y, outputsize)

Convenience function to compute the matrix kernel for two inputs `x` and `y`. The `outputsize` keyword is only required for the `IndependentMOKernel` to indicated the number of outputs.
Copy link
Member

Choose a reason for hiding this comment

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

Style: line length

Additionally, it would be helpful to add a doctest here.

Copy link
Member Author

Choose a reason for hiding this comment

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

I have unfortunately never used documenter, will need to read up on this. Style should be fixed by formatter now.

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Convenience function to compute the matrix kernel for two inputs `x` and `y`. The `outputsize` keyword is only required for the `IndependentMOKernel` to indicated the number of outputs.
Convenience function to compute the matrix kernel for two inputs `x` and `y`. The `outputsize` keyword is only required for the `IndependentMOKernel` to indicate the number of outputs.

Also, how about instead just having

matrixkernel(k::IndependentMOKernel, x, y) = error("You must provide the number of outputs, call `matrixkernel(k, x, y, out_dim)`")
matrixkernel(k::IndependentMOKernel, x, y, out_dim) = ...

"""
function matrixkernel(k::MOKernel, x, y, outputsize)
@assert size(x) == size(y)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
@assert size(x) == size(y)

x and y could be types on which size isn't defined (e.g. a string)

xMO = MOInputIsotopicByFeatures([x], outputsize)
yMO = MOInputIsotopicByFeatures([y], outputsize)
return kernelmatrix(k, xMO, yMO)
end
6 changes: 5 additions & 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 Expand Up @@ -33,6 +33,10 @@ function (κ::LatentFactorMOKernel)((x, px)::Tuple{Any,Int}, (y, py)::Tuple{Any,
return cov_f + κ.e((x, px), (y, py))
end

function matrixkernel(k::LatentFactorMOKernel, x, y)
Crown421 marked this conversation as resolved.
Show resolved Hide resolved
return matrixkernel(k, x, y, size(k.A, 1))
end

function kernelmatrix(k::LatentFactorMOKernel, x::MOInput, y::MOInput)
x.out_dim == y.out_dim || error("`x` and `y` should have the same output dimension")
x.out_dim == size(k.A, 1) ||
Expand Down
78 changes: 78 additions & 0 deletions temporary_script.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# this script should be removed when the alternative MO kernelmatrix is accepted or rejected.

using KernelFunctions, BenchmarkTools
using LinearAlgebra

mrank = 1
dims = (in=5, out=3)
x = [rand(dims.in) for _ in 1:20]

xMOF = KernelFunctions.MOInputIsotopicByFeatures(x, dims.out)
xMOO = KernelFunctions.MOInputIsotopicByOutputs(x, dims.out)

indk = IndependentMOKernel(GaussianKernel())

Kind1 = kernelmatrix(indk, xMOF, xMOF)
Kind2 = kernelmatrix2(indk, xMOF, xMOF)

Kind1 ≈ Kind2
willtebbutt marked this conversation as resolved.
Show resolved Hide resolved
# true

@benchmark kernelmatrix($indk, $xMOF, $xMOF)
# BenchmarkTools.Trial: 756 samples with 1 evaluation.
# Range (min … max): 6.186 ms … 11.470 ms ┊ GC (min … max): 0.00% … 35.30%
# Time (median): 6.423 ms ┊ GC (median): 0.00%
# Time (mean ± σ): 6.614 ms ± 806.792 μs ┊ GC (mean ± σ): 2.76% ± 7.77%

# ▅▇█▇▃
# ▆██████▅▆▄▅▄▁▄▁▄▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▄▁▁▁▁▁▁▁▁▁▁▁▁▁▄▁▁▁▁▁▁▆██▇▇ ▇
# 6.19 ms Histogram: log(frequency) by time 10 ms <

# Memory estimate: 2.34 MiB, allocs estimate: 60060.

@benchmark kernelmatrix2($indk, $xMOF, $xMOF)
# BenchmarkTools.Trial: 10000 samples with 5 evaluations.
# Range (min … max): 6.162 μs … 341.226 μs ┊ GC (min … max): 0.00% … 96.29%
# Time (median): 6.947 μs ┊ GC (median): 0.00%
# Time (mean ± σ): 8.235 μs ± 16.802 μs ┊ GC (mean ± σ): 12.37% ± 5.92%

# ▁▄▆▇██▇▆▅▄▃▂▁▁▁ ▂
# ▅██████████████████▇▇▆▇▅▆▆▆▅▅▆▅▅▃▄▅▅▅▁▁▃▁▃▅▅▆▆▆▇▇▇▇▇▇▇██▇▇▇ █
# 6.16 μs Histogram: log(frequency) by time 13.7 μs <

# Memory estimate: 34.89 KiB, allocs estimate: 7.

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

ickernel = IntrinsicCoregionMOKernel(GaussianKernel(), B)

Kic1 = kernelmatrix(ickernel, xMOF, xMOF)
Kic2 = kernelmatrix2(ickernel, xMOF, xMOF)

Kic1 ≈ Kic2
#true

@benchmark kernelmatrix($ickernel, $xMOF, $xMOF)
# BenchmarkTools.Trial: 1874 samples with 1 evaluation.
# Range (min … max): 2.522 ms … 5.424 ms ┊ GC (min … max): 0.00% … 51.13%
# Time (median): 2.601 ms ┊ GC (median): 0.00%
# Time (mean ± σ): 2.666 ms ± 369.030 μs ┊ GC (mean ± σ): 2.01% ± 7.04%

# ▂█▆▁ ▁
# ███████▅▄▅▅▃▁▁▃▅▁▁▁▃▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▇▇ █
# 2.52 ms Histogram: log(frequency) by time 570 ms <

# Memory estimate: 985.47 KiB, allocs estimate: 39639.

@benchmark kernelmatrix2($ickernel, $xMOF, $xMOF)
# BenchmarkTools.Trial: 10000 samples with 5 evaluations.
# Range (min … max): 6.152 μs … 322.002 μs ┊ GC (min … max): 0.00% … 96.14%
# Time (median): 6.676 μs ┊ GC (median): 0.00%
# Time (mean ± σ): 8.100 μs ± 16.959 μs ┊ GC (mean ± σ): 12.53% ± 5.85%

# ▄▇██▇▅▄▃▂▁▁ ▁▁▁▁ ▂
# ▆██████████████▇▇▇▆▆▇▇▇▇▆▇▆▄▅▄▃▆▁▅▄▅▆▆▅▅▄▅▄▆▇▇█▇▇▇▇██████▇▇ █
# 6.15 μs Histogram: log(frequency) by time 13.5 μs <

# Memory estimate: 34.77 KiB, allocs estimate: 6.
35 changes: 28 additions & 7 deletions test/mokernels/independent.jl
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
@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)

# in-place
if VERSION >= v"1.6"
K = zeros(12, 12)
kernelmatrix!(K, k, x, y)
@test K ≈ k.(x, permutedims(y))

K = zeros(12, 12)
kernelmatrix!(K, k, xIF, yIF)
@test K ≈ k.(xIF, permutedims(yIF))
end

# 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
Loading