From 45096ed8b96226cc174f1d4636016b4906129750 Mon Sep 17 00:00:00 2001 From: Steffen Ridderbusch Date: Thu, 26 Aug 2021 13:48:53 +0100 Subject: [PATCH 01/11] Restore additions --- docs/src/api.md | 5 +++++ src/KernelFunctions.jl | 1 + src/mokernels/intrinsiccoregion.jl | 4 ++++ src/mokernels/lmm.jl | 4 ++++ src/mokernels/mokernel.jl | 13 +++++++++++++ src/mokernels/slfm.jl | 4 ++++ test/mokernels/intrinsiccoregion.jl | 4 ++++ test/mokernels/lmm.jl | 4 ++++ test/mokernels/slfm.jl | 5 +++++ 9 files changed, 44 insertions(+) diff --git a/docs/src/api.md b/docs/src/api.md index 7ac2dacc3..2232eb527 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -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. diff --git a/src/KernelFunctions.jl b/src/KernelFunctions.jl index 4fded7dc5..102055703 100644 --- a/src/KernelFunctions.jl +++ b/src/KernelFunctions.jl @@ -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 # Reexports export tensor, ⊗, compose diff --git a/src/mokernels/intrinsiccoregion.jl b/src/mokernels/intrinsiccoregion.jl index db1050fe4..93d9fd440 100644 --- a/src/mokernels/intrinsiccoregion.jl +++ b/src/mokernels/intrinsiccoregion.jl @@ -42,6 +42,10 @@ function (k::IntrinsicCoregionMOKernel)((x, px)::Tuple{Any,Int}, (y, py)::Tuple{ 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} diff --git a/src/mokernels/lmm.jl b/src/mokernels/lmm.jl index 87f2fd465..00ec987fb 100644 --- a/src/mokernels/lmm.jl +++ b/src/mokernels/lmm.jl @@ -37,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) + 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 diff --git a/src/mokernels/mokernel.jl b/src/mokernels/mokernel.jl index 2ebb07aad..755befc01 100644 --- a/src/mokernels/mokernel.jl +++ b/src/mokernels/mokernel.jl @@ -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. +""" +function matrixkernel(k::MOKernel, x, y, outputsize) + @assert size(x) == size(y) + xMO = MOInputIsotopicByFeatures([x], outputsize) + yMO = MOInputIsotopicByFeatures([y], outputsize) + return kernelmatrix(k, xMO, yMO) +end diff --git a/src/mokernels/slfm.jl b/src/mokernels/slfm.jl index 521d07de7..ff88c7467 100644 --- a/src/mokernels/slfm.jl +++ b/src/mokernels/slfm.jl @@ -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) + 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) || diff --git a/test/mokernels/intrinsiccoregion.jl b/test/mokernels/intrinsiccoregion.jl index 2d6ee9913..55e2228d7 100644 --- a/test/mokernels/intrinsiccoregion.jl +++ b/test/mokernels/intrinsiccoregion.jl @@ -31,6 +31,10 @@ @test icoregionkernel(XIF[1], XIF[end]) ≈ B[XIF[1][2], XIF[end][2]] * kernel(XIF[1][1], XIF[end][1]) + + @test matrixkernel(icoregionkernel, XIF.x[1], XIF.x[2]) ≈ + icoregionkernel.kernel(XIF.x[1], XIF.x[2]) * icoregionkernel.B + # kernelmatrix KernelFunctions.TestUtils.test_interface(icoregionkernel, XIF, YIF, ZIF) diff --git a/test/mokernels/lmm.jl b/test/mokernels/lmm.jl index d73ce7a64..0dce1b9fc 100644 --- a/test/mokernels/lmm.jl +++ b/test/mokernels/lmm.jl @@ -43,6 +43,10 @@ TestUtils.test_interface(k, x1IF, x2IF, x3IF) + a = KernelFunctions.MOInputIsotopicByOutputs([rand(rng, in_dim)], out_dim) + b = KernelFunctions.MOInputIsotopicByOutputs([rand(rng, in_dim)], out_dim) + @test matrixkernel(k, a.x[1], b.x[1]) ≈ k.(a, permutedims(b)) + k = LinearMixingModelKernel(SEKernel(), H) @test k isa LinearMixingModelKernel diff --git a/test/mokernels/slfm.jl b/test/mokernels/slfm.jl index ac0bd1313..488323d76 100644 --- a/test/mokernels/slfm.jl +++ b/test/mokernels/slfm.jl @@ -36,6 +36,11 @@ TestUtils.test_interface(k, x1IF, x2IF, x3IF) + # matrixkernel + a = KernelFunctions.MOInputIsotopicByOutputs([rand(rng, in_dim)], out_dim) + b = KernelFunctions.MOInputIsotopicByOutputs([rand(rng, in_dim)], out_dim) + @test matrixkernel(k, a.x[1], b.x[1]) ≈ k.(a, permutedims(b)) + @test string(k) == "Semi-parametric Latent Factor Multi-Output Kernel" @test repr("text/plain", k) == ( "Semi-parametric Latent Factor Multi-Output Kernel\n" * From 738348cb1cdcb1416383c9d8c923b9217d0b5f1c Mon Sep 17 00:00:00 2001 From: Steffen Ridderbusch Date: Fri, 27 Aug 2021 18:08:39 +0100 Subject: [PATCH 02/11] Further improvements --- docs/src/api.md | 4 +++- src/mokernels/independent.jl | 2 ++ src/mokernels/intrinsiccoregion.jl | 4 +--- src/mokernels/mokernel.jl | 7 +++---- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/src/api.md b/docs/src/api.md index 2232eb527..4faa760ab 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -80,10 +80,12 @@ 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 +If you are interested in the matrix-kernel interpretation, Kernelfunction provides a convenience function that computes the resulting kernel for a pair of inputs directly. ```@docs matrixkernel ``` + + ## Generic Utilities diff --git a/src/mokernels/independent.jl b/src/mokernels/independent.jl index d7dde0cba..341c971da 100644 --- a/src/mokernels/independent.jl +++ b/src/mokernels/independent.jl @@ -44,6 +44,8 @@ function kernelmatrix( return _kernelmatrix_kron_helper(x, Kfeatures, Eye{mtype}(x.out_dim)) end +matrixkernel(k::IndependentMOKernel, x, y) = k.kernel(x, y) * I + if VERSION >= v"1.6" function _kernelmatrix_kron_helper!(K, ::MOInputIsotopicByFeatures, Kfeatures, B) return kron!(K, Kfeatures, B) diff --git a/src/mokernels/intrinsiccoregion.jl b/src/mokernels/intrinsiccoregion.jl index 93d9fd440..77fdc5780 100644 --- a/src/mokernels/intrinsiccoregion.jl +++ b/src/mokernels/intrinsiccoregion.jl @@ -42,9 +42,7 @@ function (k::IntrinsicCoregionMOKernel)((x, px)::Tuple{Any,Int}, (y, py)::Tuple{ 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 +matrixkernel(k::IntrinsicCoregionMOKernel, x, y) = k.kernel(x, y) * k.B function kernelmatrix( k::IntrinsicCoregionMOKernel, x::MOI, y::MOI diff --git a/src/mokernels/mokernel.jl b/src/mokernels/mokernel.jl index 755befc01..03ffbdafc 100644 --- a/src/mokernels/mokernel.jl +++ b/src/mokernels/mokernel.jl @@ -7,13 +7,12 @@ 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. """ -function matrixkernel(k::MOKernel, x, y, outputsize) +function matrixkernel(k::MOKernel, x, y, out_dim) @assert size(x) == size(y) - xMO = MOInputIsotopicByFeatures([x], outputsize) - yMO = MOInputIsotopicByFeatures([y], outputsize) + xMO = MOInputIsotopicByFeatures([x], out_dim) + yMO = MOInputIsotopicByFeatures([y], out_dim) return kernelmatrix(k, xMO, yMO) end From 7ef2db54d82143b9507abebb6ec953af2b9fe551 Mon Sep 17 00:00:00 2001 From: Steffen Ridderbusch Date: Fri, 27 Aug 2021 23:21:03 +0100 Subject: [PATCH 03/11] Added missing method for _mod --- src/basekernels/fbm.jl | 1 + test/basekernels/fbm.jl | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/basekernels/fbm.jl b/src/basekernels/fbm.jl index 3f4d88ca0..553e1dde5 100644 --- a/src/basekernels/fbm.jl +++ b/src/basekernels/fbm.jl @@ -43,6 +43,7 @@ end _fbm(modX, modY, modXY, h) = (modX^h + modY^h - modXY^h) / 2 _mod(x::AbstractVector{<:Real}) = abs2.(x) +_mod(x::AbstractVector{<:AbstractVector{<:Real}}) = sum.(abs2, x) _mod(x::ColVecs) = vec(sum(abs2, x.X; dims=1)) _mod(x::RowVecs) = vec(sum(abs2, x.X; dims=2)) diff --git a/test/basekernels/fbm.jl b/test/basekernels/fbm.jl index 6ab3704d9..fbe859c8f 100644 --- a/test/basekernels/fbm.jl +++ b/test/basekernels/fbm.jl @@ -15,6 +15,8 @@ @test repr(k) == "Fractional Brownian Motion Kernel (h = $(h))" test_ADs(FBMKernel; ADs=[:ReverseDiff]) + # ToDo: needs tests for _mod + # Tests failing for ForwardDiff and Zygote@0.6. # Related to: https://github.com/FluxML/Zygote.jl/issues/1036 f(x, y) = x^y From 4af63ac7e927adf0b8a017c6bbb97f79aad38e4a Mon Sep 17 00:00:00 2001 From: Steffen Ridderbusch Date: Fri, 27 Aug 2021 23:23:36 +0100 Subject: [PATCH 04/11] Add comment --- src/basekernels/fbm.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/basekernels/fbm.jl b/src/basekernels/fbm.jl index 553e1dde5..213cb3c36 100644 --- a/src/basekernels/fbm.jl +++ b/src/basekernels/fbm.jl @@ -44,6 +44,7 @@ _fbm(modX, modY, modXY, h) = (modX^h + modY^h - modXY^h) / 2 _mod(x::AbstractVector{<:Real}) = abs2.(x) _mod(x::AbstractVector{<:AbstractVector{<:Real}}) = sum.(abs2, x) +# two lines above could be combined into the second (dispatching on general AbstractVectors), but this (somewhat) more performant _mod(x::ColVecs) = vec(sum(abs2, x.X; dims=1)) _mod(x::RowVecs) = vec(sum(abs2, x.X; dims=2)) From 68ef765cd646af8cd73c227039859c3dcd46a15e Mon Sep 17 00:00:00 2001 From: Steffen Ridderbusch Date: Fri, 27 Aug 2021 23:52:53 +0100 Subject: [PATCH 05/11] Performance improvement lmm kernel --- src/mokernels/lmm.jl | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/mokernels/lmm.jl b/src/mokernels/lmm.jl index 00ec987fb..4b973270c 100644 --- a/src/mokernels/lmm.jl +++ b/src/mokernels/lmm.jl @@ -37,8 +37,45 @@ 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 +## current implementation +# julia> @benchmark KernelFunctions.kernelmatrix(k, x1IO, x2IO) +# BenchmarkTools.Trial: 3478 samples with 1 evaluation. +# Range (min … max): 1.362 ms … 5.498 ms ┊ GC (min … max): 0.00% … 72.47% +# Time (median): 1.396 ms ┊ GC (median): 0.00% +# Time (mean ± σ): 1.435 ms ± 358.577 μs ┊ GC (mean ± σ): 2.28% ± 6.70% + +# ▂▆█▇▄▂ ▂▁ ▁ +# ███████▆██▅▅▁▄▁▁▁▁▁▁▁▁▄▁▁▁▁▁▁▁▁▁▃▁▁▁▁▁▁▁▁▁▁▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▃ █ +# 1.36 ms Histogram: log(frequency) by time 2.1 ms < + +# Memory estimate: 410.73 KiB, allocs estimate: 23090. + +## proposed improvement +# julia> @benchmark KernelFunctions.kernelmatrix2(k, x1IO, x2IO) +# BenchmarkTools.Trial: 10000 samples with 1 evaluation. +# Range (min … max): 16.871 μs … 3.440 ms ┊ GC (min … max): 0.00% … 97.80% +# Time (median): 18.625 μs ┊ GC (median): 0.00% +# Time (mean ± σ): 24.734 μs ± 129.308 μs ┊ GC (mean ± σ): 20.63% ± 3.92% + +# ▄▆███▇▆▅▄▄▂▂ ▁ ▁ ▂ +# ████████████████▇▆▄▅▅▄▅▅▅▅▅▆▃▄▅▃▂▂▃▃▄▆▇▇████████▅▆▅▃▅▄▆▅▆▆▆▇ █ +# 16.9 μs Histogram: log(frequency) by time 36.4 μs < + +# Memory estimate: 84.56 KiB, allocs estimate: 338. + +function kernelmatrix2(k::LinearMixingModelKernel, X, Y) + K = [kernelmatrix(ki, X.x, Y.x) for ki in k.K] + L = size(k.H, 2) + return reduce(hcat, [reduce(vcat, [sum(k.H[:,i].*(K .* k.H[:,j])) for i in 1:L]) for j in 1:L]) +end + +# function matrixkernel(k::LinearMixingModelKernel, x, y) +# return matrixkernel(k, x, y, size(k.H, 2)) +# end + function matrixkernel(k::LinearMixingModelKernel, x, y) - return matrixkernel(k, x, y, size(k.H, 2)) + K = [ki(x, y) for ki in k.K] + return k.H' * ( K .* k.H) end function Base.show(io::IO, k::LinearMixingModelKernel) From 7a9ba3d5c029f6cbac1bf2c52041e3dd2d72d4ca Mon Sep 17 00:00:00 2001 From: Steffen Ridderbusch Date: Sat, 28 Aug 2021 00:03:20 +0100 Subject: [PATCH 06/11] Specialized for slfm --- src/mokernels/slfm.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/mokernels/slfm.jl b/src/mokernels/slfm.jl index ff88c7467..c2e9bdd6e 100644 --- a/src/mokernels/slfm.jl +++ b/src/mokernels/slfm.jl @@ -33,8 +33,15 @@ 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) +# return matrixkernel(k, x, y, size(k.A, 1)) +# end + function matrixkernel(k::LatentFactorMOKernel, x, y) - return matrixkernel(k, x, y, size(k.A, 1)) + W = [col * col' for col in eachcol(k.A)] + h = [gi(x, y) for gi in k.g] + w_h = sum(Wi * Hi for (Wi, Hi) in zip(W, h)) + return w_h + matrixkernel(k.e, x, y) end function kernelmatrix(k::LatentFactorMOKernel, x::MOInput, y::MOInput) From de510781f80bbcea84f6c658605b91a210cc3c99 Mon Sep 17 00:00:00 2001 From: Steffen Ridderbusch Date: Sat, 28 Aug 2021 00:18:12 +0100 Subject: [PATCH 07/11] Move helper, fix slfm for both MOInput types --- src/mokernels/independent.jl | 8 -------- src/mokernels/mokernel.jl | 9 +++++++++ src/mokernels/slfm.jl | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/mokernels/independent.jl b/src/mokernels/independent.jl index 341c971da..9f896c8e1 100644 --- a/src/mokernels/independent.jl +++ b/src/mokernels/independent.jl @@ -27,14 +27,6 @@ function (κ::IndependentMOKernel)((x, px)::Tuple{Any,Int}, (y, py)::Tuple{Any,I return κ.kernel(x, y) * (px == py) end -function _kernelmatrix_kron_helper(::MOInputIsotopicByFeatures, Kfeatures, B) - return kron(Kfeatures, B) -end - -function _kernelmatrix_kron_helper(::MOInputIsotopicByOutputs, Kfeatures, B) - return kron(B, Kfeatures) -end - function kernelmatrix( k::IndependentMOKernel, x::MOI, y::MOI ) where {MOI<:IsotopicMOInputsUnion} diff --git a/src/mokernels/mokernel.jl b/src/mokernels/mokernel.jl index 03ffbdafc..696cb56d3 100644 --- a/src/mokernels/mokernel.jl +++ b/src/mokernels/mokernel.jl @@ -16,3 +16,12 @@ function matrixkernel(k::MOKernel, x, y, out_dim) yMO = MOInputIsotopicByFeatures([y], out_dim) return kernelmatrix(k, xMO, yMO) end + + +function _kernelmatrix_kron_helper(::MOInputIsotopicByFeatures, Kfeatures, Koutputs) + return kron(Kfeatures, Koutputs) +end + +function _kernelmatrix_kron_helper(::MOInputIsotopicByOutputs, Kfeatures, Koutputs) + return kron(Koutputs, Kfeatures) +end \ No newline at end of file diff --git a/src/mokernels/slfm.jl b/src/mokernels/slfm.jl index c2e9bdd6e..dff26d3b6 100644 --- a/src/mokernels/slfm.jl +++ b/src/mokernels/slfm.jl @@ -44,7 +44,7 @@ function matrixkernel(k::LatentFactorMOKernel, x, y) return w_h + matrixkernel(k.e, x, y) end -function kernelmatrix(k::LatentFactorMOKernel, x::MOInput, y::MOInput) +function kernelmatrix(k::LatentFactorMOKernel, x::IsotopicMOInputsUnion, y::IsotopicMOInputsUnion) x.out_dim == y.out_dim || error("`x` and `y` should have the same output dimension") x.out_dim == size(k.A, 1) || error("Kernel not compatible with the given multi-output inputs") @@ -56,7 +56,7 @@ function kernelmatrix(k::LatentFactorMOKernel, x::MOInput, y::MOInput) H = [gi.(x.x, permutedims(y.x)) for gi in k.g] # Weighted latent kernel matrix ((N*out_dim) x (N*out_dim)) - W_H = sum(kron(Wi, Hi) for (Wi, Hi) in zip(W, H)) + W_H = sum(_kernelmatrix_kron_helper(x, Wi, Hi) for (Wi, Hi) in zip(W, H)) return W_H .+ kernelmatrix(k.e, x, y) end From 61aca2bd863a0d89c066d46e6bc4c49cdb016aaa Mon Sep 17 00:00:00 2001 From: Steffen Ridderbusch Date: Sat, 28 Aug 2021 00:28:34 +0100 Subject: [PATCH 08/11] Switch order --- src/KernelFunctions.jl | 2 +- src/mokernels/slfm.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/KernelFunctions.jl b/src/KernelFunctions.jl index 102055703..ec1ce8083 100644 --- a/src/KernelFunctions.jl +++ b/src/KernelFunctions.jl @@ -106,8 +106,8 @@ include(joinpath("kernels", "neuralkernelnetwork.jl")) include(joinpath("approximations", "nystrom.jl")) include("generic.jl") -include(joinpath("mokernels", "mokernel.jl")) include(joinpath("mokernels", "moinput.jl")) +include(joinpath("mokernels", "mokernel.jl")) include(joinpath("mokernels", "independent.jl")) include(joinpath("mokernels", "slfm.jl")) include(joinpath("mokernels", "intrinsiccoregion.jl")) diff --git a/src/mokernels/slfm.jl b/src/mokernels/slfm.jl index dff26d3b6..d94faa520 100644 --- a/src/mokernels/slfm.jl +++ b/src/mokernels/slfm.jl @@ -56,7 +56,7 @@ function kernelmatrix(k::LatentFactorMOKernel, x::IsotopicMOInputsUnion, y::Isot H = [gi.(x.x, permutedims(y.x)) for gi in k.g] # Weighted latent kernel matrix ((N*out_dim) x (N*out_dim)) - W_H = sum(_kernelmatrix_kron_helper(x, Wi, Hi) for (Wi, Hi) in zip(W, H)) + W_H = sum(_kernelmatrix_kron_helper(x, Hi, Wi) for (Wi, Hi) in zip(W, H)) return W_H .+ kernelmatrix(k.e, x, y) end From 47b64e43ad80b0fc5c52bd5e9c6adbc4a2f9df3c Mon Sep 17 00:00:00 2001 From: Steffen Ridderbusch Date: Sat, 28 Aug 2021 10:07:50 +0100 Subject: [PATCH 09/11] Formatter and fallback --- src/mokernels/lmm.jl | 6 ++++-- src/mokernels/mokernel.jl | 9 ++++++++- src/mokernels/slfm.jl | 4 +++- test/mokernels/intrinsiccoregion.jl | 5 ++--- test/mokernels/lmm.jl | 2 +- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/mokernels/lmm.jl b/src/mokernels/lmm.jl index 4b973270c..ad949d748 100644 --- a/src/mokernels/lmm.jl +++ b/src/mokernels/lmm.jl @@ -66,7 +66,9 @@ end function kernelmatrix2(k::LinearMixingModelKernel, X, Y) K = [kernelmatrix(ki, X.x, Y.x) for ki in k.K] L = size(k.H, 2) - return reduce(hcat, [reduce(vcat, [sum(k.H[:,i].*(K .* k.H[:,j])) for i in 1:L]) for j in 1:L]) + return reduce( + hcat, [reduce(vcat, [sum(k.H[:, i] .* (K .* k.H[:, j])) for i in 1:L]) for j in 1:L] + ) end # function matrixkernel(k::LinearMixingModelKernel, x, y) @@ -75,7 +77,7 @@ end function matrixkernel(k::LinearMixingModelKernel, x, y) K = [ki(x, y) for ki in k.K] - return k.H' * ( K .* k.H) + return k.H' * (K .* k.H) end function Base.show(io::IO, k::LinearMixingModelKernel) diff --git a/src/mokernels/mokernel.jl b/src/mokernels/mokernel.jl index 696cb56d3..00e52da42 100644 --- a/src/mokernels/mokernel.jl +++ b/src/mokernels/mokernel.jl @@ -17,6 +17,13 @@ function matrixkernel(k::MOKernel, x, y, out_dim) return kernelmatrix(k, xMO, yMO) end +function matrixkernel(k:MOKernel, x, y) + return throw( + ArgumentError( + "This kernel does not have a specific matrixkernel implementation, you can call `matrixkernel(k, x, y, out_dim)`", + ), + ) +end function _kernelmatrix_kron_helper(::MOInputIsotopicByFeatures, Kfeatures, Koutputs) return kron(Kfeatures, Koutputs) @@ -24,4 +31,4 @@ end function _kernelmatrix_kron_helper(::MOInputIsotopicByOutputs, Kfeatures, Koutputs) return kron(Koutputs, Kfeatures) -end \ No newline at end of file +end diff --git a/src/mokernels/slfm.jl b/src/mokernels/slfm.jl index d94faa520..7538e5734 100644 --- a/src/mokernels/slfm.jl +++ b/src/mokernels/slfm.jl @@ -44,7 +44,9 @@ function matrixkernel(k::LatentFactorMOKernel, x, y) return w_h + matrixkernel(k.e, x, y) end -function kernelmatrix(k::LatentFactorMOKernel, x::IsotopicMOInputsUnion, y::IsotopicMOInputsUnion) +function kernelmatrix( + k::LatentFactorMOKernel, x::IsotopicMOInputsUnion, y::IsotopicMOInputsUnion +) x.out_dim == y.out_dim || error("`x` and `y` should have the same output dimension") x.out_dim == size(k.A, 1) || error("Kernel not compatible with the given multi-output inputs") diff --git a/test/mokernels/intrinsiccoregion.jl b/test/mokernels/intrinsiccoregion.jl index 55e2228d7..915ab55e4 100644 --- a/test/mokernels/intrinsiccoregion.jl +++ b/test/mokernels/intrinsiccoregion.jl @@ -31,9 +31,8 @@ @test icoregionkernel(XIF[1], XIF[end]) ≈ B[XIF[1][2], XIF[end][2]] * kernel(XIF[1][1], XIF[end][1]) - - @test matrixkernel(icoregionkernel, XIF.x[1], XIF.x[2]) ≈ - icoregionkernel.kernel(XIF.x[1], XIF.x[2]) * icoregionkernel.B + @test matrixkernel(icoregionkernel, XIF.x[1], XIF.x[2]) ≈ + icoregionkernel.kernel(XIF.x[1], XIF.x[2]) * icoregionkernel.B # kernelmatrix KernelFunctions.TestUtils.test_interface(icoregionkernel, XIF, YIF, ZIF) diff --git a/test/mokernels/lmm.jl b/test/mokernels/lmm.jl index 0dce1b9fc..0414e47de 100644 --- a/test/mokernels/lmm.jl +++ b/test/mokernels/lmm.jl @@ -46,7 +46,7 @@ a = KernelFunctions.MOInputIsotopicByOutputs([rand(rng, in_dim)], out_dim) b = KernelFunctions.MOInputIsotopicByOutputs([rand(rng, in_dim)], out_dim) @test matrixkernel(k, a.x[1], b.x[1]) ≈ k.(a, permutedims(b)) - + k = LinearMixingModelKernel(SEKernel(), H) @test k isa LinearMixingModelKernel From 2de7f5f5f6b57489fdd87bf01f35a722ed4b4af2 Mon Sep 17 00:00:00 2001 From: Steffen Ridderbusch Date: Sat, 28 Aug 2021 11:57:02 +0100 Subject: [PATCH 10/11] Add tests --- src/mokernels/mokernel.jl | 2 +- test/mokernels/mokernel.jl | 14 ++++++++++++++ test/runtests.jl | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 test/mokernels/mokernel.jl diff --git a/src/mokernels/mokernel.jl b/src/mokernels/mokernel.jl index 00e52da42..0be3f2fb7 100644 --- a/src/mokernels/mokernel.jl +++ b/src/mokernels/mokernel.jl @@ -17,7 +17,7 @@ function matrixkernel(k::MOKernel, x, y, out_dim) return kernelmatrix(k, xMO, yMO) end -function matrixkernel(k:MOKernel, x, y) +function matrixkernel(k::MOKernel, x, y) return throw( ArgumentError( "This kernel does not have a specific matrixkernel implementation, you can call `matrixkernel(k, x, y, out_dim)`", diff --git a/test/mokernels/mokernel.jl b/test/mokernels/mokernel.jl new file mode 100644 index 000000000..d768b3b20 --- /dev/null +++ b/test/mokernels/mokernel.jl @@ -0,0 +1,14 @@ +@testset "mokernel" begin + struct TestMOKernel <: MOKernel end + @test_throws ArgumentError matrixkernel(TestMOKernel(), rand(3), rand(3)) + + out_dim = 3 + A = rand(out_dim, out_dim) + A = A * A' + k = IntrinsicCoregionMOKernel(GaussianKernel(), A) + + in_dim = 4 + x = rand(in_dim) + y = rand(in_dim) + @test matrixkernel(k, x, y, 3) ≈ matrixkernel(k, x, y) +end diff --git a/test/runtests.jl b/test/runtests.jl index f94a228aa..cd40a36cf 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -133,6 +133,7 @@ include("test_utils.jl") if GROUP == "" || GROUP == "MultiOutput" @testset "multi_output" begin include(joinpath("mokernels", "moinput.jl")) + include(joinpath("mokernels", "mokernel.jl")) include(joinpath("mokernels", "independent.jl")) include(joinpath("mokernels", "slfm.jl")) include(joinpath("mokernels", "intrinsiccoregion.jl")) From 03338a3d45b54f4a7457aba35399cd7154983a08 Mon Sep 17 00:00:00 2001 From: Steffen Ridderbusch Date: Thu, 16 Sep 2021 11:48:49 +0100 Subject: [PATCH 11/11] Apply suggestions from code review Co-authored-by: st-- --- src/mokernels/mokernel.jl | 4 ++-- test/mokernels/intrinsiccoregion.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mokernels/mokernel.jl b/src/mokernels/mokernel.jl index 0be3f2fb7..304b15faf 100644 --- a/src/mokernels/mokernel.jl +++ b/src/mokernels/mokernel.jl @@ -6,9 +6,9 @@ Abstract type for kernels with multiple outpus. abstract type MOKernel <: Kernel end """ - matrixkernel(k::MOK, x, y) + matrixkernel(k::MOKernel, x, y) -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`. """ function matrixkernel(k::MOKernel, x, y, out_dim) @assert size(x) == size(y) diff --git a/test/mokernels/intrinsiccoregion.jl b/test/mokernels/intrinsiccoregion.jl index 915ab55e4..7e81a64a7 100644 --- a/test/mokernels/intrinsiccoregion.jl +++ b/test/mokernels/intrinsiccoregion.jl @@ -32,7 +32,7 @@ B[XIF[1][2], XIF[end][2]] * kernel(XIF[1][1], XIF[end][1]) @test matrixkernel(icoregionkernel, XIF.x[1], XIF.x[2]) ≈ - icoregionkernel.kernel(XIF.x[1], XIF.x[2]) * icoregionkernel.B + matrixkernel(icoregionkernel, XIF.x[1], XIF.x[2], dims.out) # kernelmatrix KernelFunctions.TestUtils.test_interface(icoregionkernel, XIF, YIF, ZIF)