Skip to content
Merged
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
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ jobs:
matrix:
version:
- '1'
- '1.6'
- 'lts'
os:
- ubuntu-latest
Expand Down
16 changes: 12 additions & 4 deletions 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.67"
version = "0.11.0"

[deps]
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
Expand All @@ -13,14 +13,21 @@ IrrationalConstants = "92d709cd-6900-40b7-9082-c6be49f344b6"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
LogExpFunctions = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
TensorCore = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
ZygoteRules = "700de1a5-db45-46bc-99cf-38207098b444"

[weakdeps]
Kronecker = "2c470bb0-bcc8-11e8-3dad-c9649493f05e"
PDMats = "90014a1f-27ba-587c-ab20-58faa44d9150"

[extensions]
KernelFunctionsKroneckerExt = "Kronecker"
KernelFunctionsPDMatsExt = "PDMats"

[compat]
ChainRulesCore = "1"
Compat = "3.7, 4"
Expand All @@ -29,11 +36,12 @@ Distances = "0.10.9"
FillArrays = "0.10, 0.11, 0.12, 0.13, 1"
Functors = "0.1, 0.2, 0.3, 0.4, 0.5"
IrrationalConstants = "0.1, 0.2"
Kronecker = "0.4, 0.5"
LogExpFunctions = "0.2.1, 0.3"
Requires = "1.0.1"
PDMats = "0.11"
SpecialFunctions = "0.8, 0.9, 0.10, 1, 2"
Statistics = "1"
StatsBase = "0.32, 0.33, 0.34"
TensorCore = "0.1"
ZygoteRules = "0.2"
julia = "1.6"
julia = "1.10"
2 changes: 1 addition & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
[compat]
Distances = "0.10"
Documenter = "1"
KernelFunctions = "0.10"
KernelFunctions = "0.11"
Kronecker = "0.4, 0.5"
PDMats = "0.11"
Statistics = "1"
Expand Down
4 changes: 3 additions & 1 deletion docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ NystromFact
```

## Conditional Utilities
To keep the dependencies of KernelFunctions lean, some functionality is only available if specific other packages are explicitly loaded (`using`).
To keep the dependencies of KernelFunctions lean, it uses [package extensions](https://pkgdocs.julialang.org/v1/creating-packages/#Conditional-loading-of-code-in-packages-(Extensions)) to
conditionally load some code. In order to enable the following functions, load the required
packages with `using`.

### Kronecker.jl
[*https://github.com/MichielStock/Kronecker.jl*](https://github.com/MichielStock/Kronecker.jl)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
module KernelFunctionsKroneckerExt

using KernelFunctions:
KernelFunctions,
Kernel,
MOKernel,
IndependentMOKernel,
IntrinsicCoregionMOKernel,
IsotopicMOInputsUnion,
MOInputIsotopicByFeatures,
MOInputIsotopicByOutputs,
kernelmatrix,
_mo_output_covariance
using Kronecker: Kronecker

# Since Kronecker does not implement `TensorCore.:⊗` but instead exports its own function
# `Kronecker.:⊗`, only the module is imported and Kronecker.:⊗ and Kronecker.kronecker are
# called explicitly.
using .Kronecker: Kronecker

export kernelkronmat
export kronecker_kernelmatrix

@doc raw"""
kernelkronmat(κ::Kernel, X::AbstractVector{<:Real}, dims::Int) -> KroneckerPower
Expand All @@ -16,8 +27,8 @@ where `D` is given by `dims`.

Requires `Kronecker.jl` and for `iskroncompatible(κ)` to return `true`.
"""
function kernelkronmat(κ::Kernel, X::AbstractVector{<:Real}, dims::Int)
checkkroncompatible(κ)
function KernelFunctions.kernelkronmat(κ::Kernel, X::AbstractVector{<:Real}, dims::Int)
KernelFunctions.checkkroncompatible(κ)
K = kernelmatrix(κ, X)
return Kronecker.kronecker(K, dims)
end
Expand All @@ -32,32 +43,12 @@ Returns a `KroneckerProduct` matrix on the grid built with the collection of vec

Requires `Kronecker.jl` and for `iskroncompatible(κ)` to return `true`.
"""
function kernelkronmat(κ::Kernel, X::AbstractVector{<:AbstractVector})
checkkroncompatible(κ)
function KernelFunctions.kernelkronmat(κ::Kernel, X::AbstractVector{<:AbstractVector})
KernelFunctions.checkkroncompatible(κ)
Ks = kernelmatrix.(κ, X)
return reduce(Kronecker.:⊗, Ks)
end

@doc raw"""
iskroncompatible(k::Kernel)

Determine whether kernel `k` is compatible with Kronecker constructions such as [`kernelkronmat`](@ref)

The function returns `false` by default. If `k` is compatible it must satisfy for all ``x, x' \in \mathbb{R}^D`:
```math
k(x, x') = \prod_{i=1}^D k(x_i, x'_i).
```
"""
@inline iskroncompatible(κ::Kernel) = false # Default return for kernels

function checkkroncompatible(κ::Kernel)
return iskroncompatible(κ) || throw(
ArgumentError(
"The chosen kernel is not compatible for Kronecker matrices (see [`iskroncompatible`](@ref))",
),
)
end

function _kernelmatrix_kroneckerjl_helper(
::Type{<:MOInputIsotopicByFeatures}, Kfeatures, Koutputs
)
Expand All @@ -79,7 +70,7 @@ Requires Kronecker.jl: Computes the `kernelmatrix` for the `IndependentMOKernel`
`IntrinsicCoregionMOKernel`, but returns a lazy kronecker product. This object can be very
efficiently inverted or decomposed. See also [`kernelmatrix`](@ref).
"""
function kronecker_kernelmatrix(
function KernelFunctions.kronecker_kernelmatrix(
k::Union{IndependentMOKernel,IntrinsicCoregionMOKernel}, x::MOI, y::MOI
) where {MOI<:IsotopicMOInputsUnion}
x.out_dim == y.out_dim ||
Expand All @@ -89,22 +80,24 @@ function kronecker_kernelmatrix(
return _kernelmatrix_kroneckerjl_helper(MOI, Kfeatures, Koutputs)
end

function kronecker_kernelmatrix(
function KernelFunctions.kronecker_kernelmatrix(
k::Union{IndependentMOKernel,IntrinsicCoregionMOKernel}, x::MOI
) where {MOI<:IsotopicMOInputsUnion}
Kfeatures = kernelmatrix(k.kernel, x.x)
Koutputs = _mo_output_covariance(k, x.out_dim)
return _kernelmatrix_kroneckerjl_helper(MOI, Kfeatures, Koutputs)
end

function kronecker_kernelmatrix(
function KernelFunctions.kronecker_kernelmatrix(
k::MOKernel, x::IsotopicMOInputsUnion, y::IsotopicMOInputsUnion
)
return throw(
ArgumentError("This kernel does not support a lazy kronecker kernelmatrix.")
)
end

function kronecker_kernelmatrix(k::MOKernel, x::IsotopicMOInputsUnion)
return kronecker_kernelmatrix(k, x, x)
function KernelFunctions.kronecker_kernelmatrix(k::MOKernel, x::IsotopicMOInputsUnion)
return KernelFunctions.kronecker_kernelmatrix(k, x, x)
end

end
17 changes: 12 additions & 5 deletions src/matrix/kernelpdmat.jl → ext/KernelFunctionsPDMatsExt.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using .PDMats: PDMat
module KernelFunctionsPDMatsExt

export kernelpdmat
using KernelFunctions:
KernelFunctions, Kernel, ColVecs, RowVecs, kernelmatrix, vec_of_vecs, defaultobs
using LinearAlgebra: I, isposdef
using PDMats: PDMat

"""
kernelpdmat(k::Kernel, X::AbstractVector)
Expand All @@ -10,7 +13,7 @@ with the Cholesky decomposition precomputed.
The algorithm adds a diagonal "nugget" term to the kernel matrix which is increased until positive
definiteness is achieved. The algorithm gives up with an error if the nugget becomes larger than 1% of the largest value in the kernel matrix.
"""
function kernelpdmat(κ::Kernel, X::AbstractVector)
function KernelFunctions.kernelpdmat(κ::Kernel, X::AbstractVector)
K = kernelmatrix(κ, X)
Kmax = maximum(K)
α = eps(eltype(K))
Expand All @@ -35,6 +38,10 @@ If `obsdim=2`, equivalent to `kernelpdmat(k, ColVecs(X))`.

See also: [`ColVecs`](@ref), [`RowVecs`](@ref)
"""
function kernelpdmat(κ::Kernel, X::AbstractMatrix; obsdim::Union{Int,Nothing}=defaultobs)
return kernelpdmat(κ, vec_of_vecs(X; obsdim=obsdim))
function KernelFunctions.kernelpdmat(
κ::Kernel, X::AbstractMatrix; obsdim::Union{Int,Nothing}=defaultobs
)
return KernelFunctions.kernelpdmat(κ, vec_of_vecs(X; obsdim=obsdim))
end

end
36 changes: 28 additions & 8 deletions src/KernelFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ export median_heuristic_transform

export NystromFact, nystrom

export kernelkronmat, kronecker_kernelmatrix, iskroncompatible
export kernelpdmat

export gaborkernel
export spectral_mixture_kernel, spectral_mixture_product_kernel

Expand All @@ -54,7 +57,6 @@ using Distances
using FillArrays
using Functors
using LinearAlgebra
using Requires
using SpecialFunctions: loggamma, besselk, polygamma
using IrrationalConstants: logtwo, twoπ, invsqrt2
using LogExpFunctions: softplus
Expand Down Expand Up @@ -126,13 +128,31 @@ include("zygoterules.jl")

include("TestUtils.jl")

function __init__()
@require Kronecker = "2c470bb0-bcc8-11e8-3dad-c9649493f05e" begin
include("matrix/kernelkroneckermat.jl")
end
@require PDMats = "90014a1f-27ba-587c-ab20-58faa44d9150" begin
include("matrix/kernelpdmat.jl")
end
# Kronecker extension stubs
@doc raw"""
iskroncompatible(k::Kernel)

Determine whether kernel `k` is compatible with Kronecker constructions such as [`kernelkronmat`](@ref)

The function returns `false` by default. If `k` is compatible it must satisfy for all ``x, x' \in \mathbb{R}^D`:
```math
k(x, x') = \prod_{i=1}^D k(x_i, x'_i).
```
"""
@inline iskroncompatible(κ::Kernel) = false

function checkkroncompatible(κ::Kernel)
return iskroncompatible(κ) || throw(
ArgumentError(
"The chosen kernel is not compatible for Kronecker matrices (see [`iskroncompatible`](@ref))",
),
)
end

function kernelkronmat end
function kronecker_kernelmatrix end

# PDMats extension stub
function kernelpdmat end

end
Loading