From 9779490b5024c0c02a9435695c639906274a9a1c Mon Sep 17 00:00:00 2001 From: Theo GF Date: Fri, 11 Jan 2019 15:10:45 +0100 Subject: [PATCH 1/5] Moving to ARD, generalized all parameters to vector --- Manifest.toml | 8 +- src/basefunctions/scalarproduct.jl | 4 +- src/basefunctions/squaredeuclidean.jl | 2 +- src/basematrix.jl | 107 +++++++++++++++--- src/deprecated.jl | 6 +- src/kernelfunctions.jl | 8 +- src/kernelfunctions/mercer/exponential.jl | 51 ++++----- src/kernelfunctions/mercer/exponentiated.jl | 16 +-- src/kernelfunctions/mercer/matern.jl | 20 ++-- src/kernelfunctions/mercer/polynomial.jl | 22 ++-- .../mercer/rationalquadratic.jl | 24 ++-- src/kernelfunctions/negativedefinite/log.jl | 14 +-- src/kernelfunctions/negativedefinite/power.jl | 6 +- src/kernelfunctions/sigmoid.jl | 14 +-- src/kernelmatrix.jl | 32 +++--- src/nystrom.jl | 4 +- test/ARD.jl | 27 +++++ 17 files changed, 230 insertions(+), 135 deletions(-) create mode 100644 test/ARD.jl diff --git a/Manifest.toml b/Manifest.toml index a172572..965400b 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -9,15 +9,15 @@ version = "0.8.10" [[BinaryProvider]] deps = ["Libdl", "Pkg", "SHA", "Test"] -git-tree-sha1 = "9930c1a6cd49d9fcd7218df6be417e6ae4f1468a" +git-tree-sha1 = "055eb2690182ebc31087859c3dd8598371d3ef9e" uuid = "b99e7846-7c00-51b0-8f62-c81ae34c0232" -version = "0.5.2" +version = "0.5.3" [[Compat]] deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] -git-tree-sha1 = "2d9e14d19bad3f9ad5cc5e4cffabc3cfa59de825" +git-tree-sha1 = "ec61a16eed883ad0cfa002d7489b3ce6d039bb9a" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "1.3.0" +version = "1.4.0" [[Dates]] deps = ["Printf"] diff --git a/src/basefunctions/scalarproduct.jl b/src/basefunctions/scalarproduct.jl index a59f894..9b3d466 100644 --- a/src/basefunctions/scalarproduct.jl +++ b/src/basefunctions/scalarproduct.jl @@ -1,6 +1,6 @@ @doc raw""" ScalarProduct() - + The scalar product is an inner product of the form: ```math @@ -8,4 +8,4 @@ f(\mathbf{x}, \mathbf{y}) = \mathbf{x}^{\intercal}\mathbf{y} ``` """ struct ScalarProduct <: InnerProduct end -@inline base_aggregate(::ScalarProduct, s::T, x::T, y::T) where {T} = s + x*y \ No newline at end of file +@inline base_aggregate(::ScalarProduct, s::T, scale::T, x::T, y::T) where {T} = s + scale*x*y diff --git a/src/basefunctions/squaredeuclidean.jl b/src/basefunctions/squaredeuclidean.jl index dc1cea4..2518682 100644 --- a/src/basefunctions/squaredeuclidean.jl +++ b/src/basefunctions/squaredeuclidean.jl @@ -9,7 +9,7 @@ f(\mathbf{x}, \mathbf{y}) = (\mathbf{x} - \mathbf{y})^{\intercal}(\mathbf{x} - \ """ struct SquaredEuclidean <: Metric end -@inline base_aggregate(::SquaredEuclidean, s::T, x::T, y::T) where {T} = s + (x-y)^2 +@inline base_aggregate(::SquaredEuclidean, s::T, scale::T, x::T, y::T) where {T} = s + scale*(x-y)^2 @inline isstationary(::SquaredEuclidean) = true @inline isisotropic(::SquaredEuclidean) = true diff --git a/src/basematrix.jl b/src/basematrix.jl index adc852a..a434382 100644 --- a/src/basematrix.jl +++ b/src/basematrix.jl @@ -3,36 +3,68 @@ @inline base_initiate(::BaseFunction, ::Type{T}) where {T} = zero(T) @inline base_return(::BaseFunction, s::T) where {T} = s -function base_evaluate(f::BaseFunction, x::T, y::T) where {T<:AbstractFloat} +function base_evaluate(f::BaseFunction, x::T, y::T) where {T<:Real} base_return(f, base_aggregate(f, base_initiate(f,T), x, y)) end # Note: no checks, assumes length(x) == length(y) >= 1 function unsafe_base_evaluate( f::BaseFunction, + scale::AbstractArray{T}, x::AbstractArray{T}, - y::AbstractArray{T} - ) where {T<:AbstractFloat} + y::AbstractArray{T}, + ) where {T<:Real} + s = base_initiate(f, T) + @simd for I in eachindex(x, y) + @inbounds xi = x[I] + @inbounds yi = y[I] + @inbounds si = scale[I] + s = base_aggregate(f, s, si, xi, yi) + end + base_return(f, s) +end + +function unsafe_base_evaluate( + f::BaseFunction, + scale::T, + x::AbstractArray{T}, + y::AbstractArray{T}, + ) where {T<:Real} s = base_initiate(f, T) @simd for I in eachindex(x, y) @inbounds xi = x[I] @inbounds yi = y[I] - s = base_aggregate(f, s, xi, yi) + s = base_aggregate(f, s, scale, xi, yi) end base_return(f, s) end function base_evaluate( f::BaseFunction, + scale::AbstractArray{T}, x::AbstractArray{T}, y::AbstractArray{T} - ) where {T<:AbstractFloat} - if (n = length(x)) != length(y) + ) where {T<:Real} + if (n = length(x)) != length(y) || n != length(scale) throw(DimensionMismatch("Arrays x and y must have the same length.")) elseif n == 0 throw(DimensionMismatch("Arrays x and y must be at least of length 1.")) end - unsafe_base_evaluate(f, x, y) + unsafe_base_evaluate(f, scale, x, y) +end + +function base_evaluate( + f::BaseFunction, + scale::T, + x::AbstractArray{T}, + y::AbstractArray{T} + ) where {T<:Real} + if (n = length(x)) != length(y) || n != length(scale) + throw(DimensionMismatch("Arrays x and y must have the same length.")) + elseif n == 0 + throw(DimensionMismatch("Arrays x and y must be at least of length 1.")) + end + unsafe_base_evaluate(f, scale, x, y) end @@ -57,7 +89,7 @@ for orientation in (:row, :col) @inline function allocate_basematrix( ::Val{$(Meta.quot(orientation))}, X::AbstractMatrix{T} - ) where {T<:AbstractFloat} + ) where {T<:Real} Array{T}(undef, size(X,$dim_obs), size(X,$dim_obs)) end @@ -65,7 +97,7 @@ for orientation in (:row, :col) ::Val{$(Meta.quot(orientation))}, X::AbstractMatrix{T}, Y::AbstractMatrix{T} - ) where {T<:AbstractFloat} + ) where {T<:Real} Array{T}(undef, size(X,$dim_obs), size(Y,$dim_obs)) end @@ -112,15 +144,35 @@ function basematrix!( σ::Orientation, P::Matrix{T}, f::BaseFunction, + scale::AbstractArray{T}, + X::AbstractMatrix{T}, + symmetrize::Bool + ) where {T<:Real} + n = checkdimensions(σ, P, X) + for j = 1:n + xj = subvector(σ, X, j) + for i = 1:j + xi = subvector(σ, X, i) + @inbounds P[i,j] = unsafe_base_evaluate(f, scale, xi, xj) + end + end + symmetrize ? LinearAlgebra.copytri!(P, 'U', false) : P +end + +function basematrix!( + σ::Orientation, + P::Matrix{T}, + f::BaseFunction, + scale::T, X::AbstractMatrix{T}, symmetrize::Bool - ) where {T<:AbstractFloat} + ) where {T<:Real} n = checkdimensions(σ, P, X) for j = 1:n xj = subvector(σ, X, j) for i = 1:j xi = subvector(σ, X, i) - @inbounds P[i,j] = unsafe_base_evaluate(f, xi, xj) + @inbounds P[i,j] = unsafe_base_evaluate(f, scale, xi, xj) end end symmetrize ? LinearAlgebra.copytri!(P, 'U', false) : P @@ -130,20 +182,39 @@ function basematrix!( σ::Orientation, P::Matrix{T}, f::BaseFunction, + scale::AbstractArray{T}, X::AbstractMatrix{T}, Y::AbstractMatrix{T}, - ) where {T<:AbstractFloat} + ) where {T<:Real} n, m = checkdimensions(σ, P, X, Y) for j = 1:m yj = subvector(σ, Y, j) for i = 1:n xi = subvector(σ, X, i) - @inbounds P[i,j] = unsafe_base_evaluate(f, xi, yj) + @inbounds P[i,j] = unsafe_base_evaluate(f, scale, xi, yj) end end P end +function basematrix!( + σ::Orientation, + P::Matrix{T}, + f::BaseFunction, + scale::T, + X::AbstractMatrix{T}, + Y::AbstractMatrix{T}, + ) where {T<:Real} + n, m = checkdimensions(σ, P, X, Y) + for j = 1:m + yj = subvector(σ, Y, j) + for i = 1:n + xi = subvector(σ, X, i) + @inbounds P[i,j] = unsafe_base_evaluate(f, scale, xi, yj) + end + end + P +end # ScalarProduct using BLAS/Built-In methods ================================================ @@ -174,7 +245,7 @@ function squared_distance!( G::Matrix{T}, xᵀx::Vector{T}, symmetrize::Bool - ) where {T<:AbstractFloat} + ) where {T<:Real} if !((n = size(G,1)) == size(G,2)) throw(DimensionMismatch("Gramian matrix must be square.")) end @@ -195,7 +266,7 @@ function squared_distance!( G::Matrix{T}, xᵀx::Vector{T}, yᵀy::Vector{T} - ) where {T<:AbstractFloat} + ) where {T<:Real} n, m = size(G) if length(xᵀx) != n throw(DimensionMismatch("Length of xᵀx must match rows of G")) @@ -217,7 +288,7 @@ function fix_negatives!( X::Matrix{T}, symmetrize::Bool, ϵ::T=zero(T) - ) where {T<:AbstractFloat} + ) where {T<:Real} if !((n = size(D,1)) == size(D,2)) throw(DimensionMismatch("Distance matrix must be square.")) end @@ -239,7 +310,7 @@ function fix_negatives!( X::Matrix{T}, Y::Matrix{T}, ϵ::T=zero(T) - ) where {T<:AbstractFloat} + ) where {T<:Real} n, m = size(D) for j = 1:m yj = subvector(σ, Y, j) @@ -279,4 +350,4 @@ function basematrix!( yᵀy = dotvectors(σ, Y) squared_distance!(P, xᵀx, yᵀy) fix_negatives!(σ, P, X, Y) -end \ No newline at end of file +end diff --git a/src/deprecated.jl b/src/deprecated.jl index 2ad2962..c5525f3 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -9,9 +9,9 @@ struct SineSquared <: PreMetric end @inline base_aggregate(::SineSquared, s::T, x::T, y::T) where {T} = s + sin(x-y)^2 @inline isstationary(::SineSquared) = true -struct PeriodicKernel{T<:AbstractFloat} <: MercerKernel{T} +struct PeriodicKernel{T<:Real} <: MercerKernel{T} α::T - function PeriodicKernel{T}(α::Real) where {T<:AbstractFloat} + function PeriodicKernel{T}(α::Real) where {T<:Real} Base.depwarn("PeriodicKernel will be removed in the next major release", :PeriodicKernel) @check_args(PeriodicKernel, α, α > zero(α), "α > 0") new{T}(α) @@ -23,4 +23,4 @@ PeriodicKernel(α::T₁ = 1.0) where {T₁<:Real} = PeriodicKernel{promote_float @inline function kappa(κ::PeriodicKernel{T}, z::T) where {T} return exp(-κ.α*z) -end \ No newline at end of file +end diff --git a/src/kernelfunctions.jl b/src/kernelfunctions.jl index 9cb29fe..3e959a3 100644 --- a/src/kernelfunctions.jl +++ b/src/kernelfunctions.jl @@ -1,6 +1,6 @@ # Kernel Functions ========================================================================= -abstract type Kernel{T<:AbstractFloat} end +abstract type Kernel{T<:Real} end function string(κ::Kernel{T}) where {T} args = [string(getfield(κ,θ)) for θ in fieldnames(typeof(κ))] @@ -46,7 +46,7 @@ isisotropic(κ::Kernel) = isisotropic(basefunction(κ)) # Mercer Kernels =========================================================================== -abstract type MercerKernel{T<:AbstractFloat} <: Kernel{T} end +abstract type MercerKernel{T<:Real} <: Kernel{T} end @inline ismercer(::MercerKernel) = true @@ -65,7 +65,7 @@ end # Negative Definite Kernels ================================================================ -abstract type NegativeDefiniteKernel{T<:AbstractFloat} <: Kernel{T} end +abstract type NegativeDefiniteKernel{T<:Real} <: Kernel{T} end @inline isnegdef(::NegativeDefiniteKernel) = true @@ -87,4 +87,4 @@ const other_kernels = [ for kname in other_kernels include(joinpath("kernelfunctions", "$(kname).jl")) -end \ No newline at end of file +end diff --git a/src/kernelfunctions/mercer/exponential.jl b/src/kernelfunctions/mercer/exponential.jl index 0e3f6f9..7ad0aa1 100644 --- a/src/kernelfunctions/mercer/exponential.jl +++ b/src/kernelfunctions/mercer/exponential.jl @@ -1,6 +1,6 @@ -# Abstract Exponential Kernel ============================================================== +Real# Abstract Exponential Kernel ============================================================== -abstract type AbstractExponentialKernel{T<:AbstractFloat} <: MercerKernel{T} end +abstract type AbstractExponentialKernel{T<:Real} <: MercerKernel{T} end @inline basefunction(::AbstractExponentialKernel) = SquaredEuclidean() @@ -28,16 +28,15 @@ julia> ExponentialKernel(2.0f0) ExponentialKernel{Float32}(2.0) ``` """ -struct ExponentialKernel{T<:AbstractFloat} <: AbstractExponentialKernel{T} - α::T - function ExponentialKernel{T}(α::Real=T(1)) where {T<:AbstractFloat} - @check_args(ExponentialKernel, α, α > zero(T), "α > 0") - return new{T}(α) +struct ExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} + α::A + function ExponentialKernel{T}(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} + @check_args(ExponentialKernel, α, count(α .<= zero(T)) == 0, "α > 0") + return new{T,typeof(α)}(α.^2) end end -ExponentialKernel(α::T=1.0) where {T<:Real} = ExponentialKernel{promote_float(T)}(α) -@inline kappa(κ::ExponentialKernel{T}, d²::T) where {T} = exp(-κ.α*√(d²)) +@inline kappa(κ::ExponentialKernel{T}, d²::T) where {T} = exp(-√(d²)) function convert(::Type{K}, κ::ExponentialKernel) where {K>:ExponentialKernel{T}} where T return ExponentialKernel{T}(κ.α) @@ -74,18 +73,19 @@ julia> SquaredExponentialKernel(2.0f0) SquaredExponentialKernel{Float32}(2.0) ``` """ -struct SquaredExponentialKernel{T<:AbstractFloat} <: AbstractExponentialKernel{T} - α::T - function SquaredExponentialKernel{T}(α::Real=T(1)) where {T<:AbstractFloat} +struct SquaredExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} + α::A + function SquaredExponentialKernel{T}(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} + @check_args(SquaredExponentialKernel, α, count(α .<= zero(T))==0, "α > 0") + return new{T,typeof(α)}(α) + end + function SquaredExponentialKernel{T}(α::T=one(T)) where {T<:Real} @check_args(SquaredExponentialKernel, α, α > zero(T), "α > 0") - return new{T}(α) + return new{T,T}(α) end end -function SquaredExponentialKernel(α::T=1.0) where {T<:Real} - return SquaredExponentialKernel{promote_float(T)}(α) -end -@inline kappa(κ::SquaredExponentialKernel{T}, d²::T) where {T} = exp(-κ.α*d²) +@inline kappa(κ::SquaredExponentialKernel{T}, d²::T) where {T} = exp(-d²) function convert( ::Type{K}, @@ -135,24 +135,21 @@ julia> GammaExponentialKernel(2.0, 0.5) GammaExponentialKernel{Float64}(2.0,0.5) ``` """ -struct GammaExponentialKernel{T<:AbstractFloat} <: AbstractExponentialKernel{T} - α::T +struct GammaExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} + α::A γ::T - function GammaExponentialKernel{T}(α::Real=T(1), γ::Real=T(1)) where {T<:AbstractFloat} - @check_args(GammaExponentialKernel, α, α > zero(T), "α > 0") + function GammaExponentialKernel{T}(α::Union{T,AbstractVector{T}}=T(1), γ::T=T(1)) where {T<:Real} + @check_args(GammaExponentialKernel, α, count(α .<= zero(T))==0, "α > 0") @check_args(GammaExponentialKernel, γ, one(T) >= γ > zero(T), "γ ∈ (0,1]") - return new{T}(α, γ) + return new{T,typeof(α)}(α.^{-γ}, γ) end end -function GammaExponentialKernel(α::T₁=1.0, γ::T₂=T₁(1)) where {T₁<:Real, T₂<:Real} - return GammaExponentialKernel{promote_float(T₁,T₂)}(α, γ) -end -@inline kappa(κ::GammaExponentialKernel{T}, d²::T) where {T} = exp(-κ.α*d²^κ.γ) +@inline kappa(κ::GammaExponentialKernel{T}, d²::T) where {T} = exp(-d²^κ.γ) function convert( ::Type{K}, κ::GammaExponentialKernel ) where {K>:GammaExponentialKernel{T}} where T return GammaExponentialKernel{T}(κ.α, κ.γ) -end \ No newline at end of file +end diff --git a/src/kernelfunctions/mercer/exponentiated.jl b/src/kernelfunctions/mercer/exponentiated.jl index 5b45497..1dfae01 100644 --- a/src/kernelfunctions/mercer/exponentiated.jl +++ b/src/kernelfunctions/mercer/exponentiated.jl @@ -21,22 +21,22 @@ julia> ExponentiatedKernel(2.0f0) ExponentiatedKernel{Float32}(2.0) ``` """ -struct ExponentiatedKernel{T<:AbstractFloat} <: MercerKernel{T} - α::T - function ExponentiatedKernel{T}(α::Real=T(1)) where {T<:AbstractFloat} - @check_args(ExponentiatedKernel, α, α > zero(T), "α > 0") - return new{T}(α) +struct ExponentiatedKernel{T<:Real,A} <: MercerKernel{T} + α::A + function ExponentiatedKernel{T}(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} + @check_args(ExponentiatedKernel, α, count(α .<= zero(T))==0, "α > 0") + return new{T,typeof(α)}(α) end end -ExponentiatedKernel(α::T=1.0) where {T<:Real} = ExponentiatedKernel{promote_float(T)}(α) +ExponentiatedKernel(α::T=1.0) where {T<:Real} = ExponentiatedKernel{T}(α) @inline basefunction(::ExponentiatedKernel) = ScalarProduct() -@inline kappa(κ::ExponentiatedKernel{T}, xᵀy::T) where {T} = exp(κ.α*xᵀy) +@inline kappa(κ::ExponentiatedKernel{T}, xᵀy::T) where {T} = exp(xᵀy) function convert( ::Type{K}, κ::ExponentiatedKernel ) where {K>:ExponentiatedKernel{T}} where T return ExponentiatedKernel{T}(κ.α) -end \ No newline at end of file +end diff --git a/src/kernelfunctions/mercer/matern.jl b/src/kernelfunctions/mercer/matern.jl index a81694b..30609fb 100644 --- a/src/kernelfunctions/mercer/matern.jl +++ b/src/kernelfunctions/mercer/matern.jl @@ -17,28 +17,28 @@ julia> MaternKernel(2.0f0, 2.0) MaternKernel{Float64}(2.0,2.0) ``` """ -struct MaternKernel{T<:AbstractFloat} <: MercerKernel{T} +struct MaternKernel{T<:Real,A} <: MercerKernel{T} ν::T - ρ::T - function MaternKernel{T}(ν::Real=T(1), ρ::Real=T(1)) where {T<:AbstractFloat} + ρ::A + function MaternKernel{T}(ν::T=T(1), ρ::Union{T,AbstractVector{T}}=T(1)) where {T<:Real} @check_args(MaternKernel, ν, ν > zero(T), "ν > 0") - @check_args(MaternKernel, ρ, ρ > zero(T), "ρ > 0") - return new{T}(ν, ρ) + @check_args(MaternKernel, ρ, count(ρ .<= zero(T)) == 0, "ρ > 0") + return new{T,typeof(ρ)}(ν, 1.0./ρ.^2) end end -function MaternKernel(ν::T₁=1.0, ρ::T₂=T₁(1)) where {T₁<:Real,T₂<:Real} - MaternKernel{promote_float(T₁,T₂)}(ν,ρ) -end +# function MaternKernel(ν::T₁=1.0, ρ::T₂=T₁(1)) where {T₁<:Real,T₂<:Real} +# MaternKernel{promote_float(T₁,T₂)}(ν,ρ) +# end @inline basefunction(::MaternKernel) = SquaredEuclidean() @inline function kappa(κ::MaternKernel{T}, d²::T) where {T} d = √(d²) d = d < eps(T) ? eps(T) : d # If d is zero, besselk will return NaN - tmp = √(2κ.ν)*d/κ.ρ + tmp = √(2κ.ν)*d return (convert(T, 2)^(one(T) - κ.ν))*(tmp^κ.ν)*besselk(κ.ν, tmp)/gamma(κ.ν) end function convert(::Type{K}, κ::MaternKernel) where {K>:MaternKernel{T}} where T return MaternKernel{T}(κ.ν, κ.ρ) -end \ No newline at end of file +end diff --git a/src/kernelfunctions/mercer/polynomial.jl b/src/kernelfunctions/mercer/polynomial.jl index 530154a..eb3ebf9 100644 --- a/src/kernelfunctions/mercer/polynomial.jl +++ b/src/kernelfunctions/mercer/polynomial.jl @@ -20,18 +20,18 @@ julia> PolynomialKernel(2.0f0, 2.0, 2) PolynomialKernel{Float64}(2.0,2.0,2) ``` """ -struct PolynomialKernel{T<:AbstractFloat} <: MercerKernel{T} - a::T +struct PolynomialKernel{T<:Real,A} <: MercerKernel{T} + a::A c::T d::T function PolynomialKernel{T}( - a::Real=T(1), - c::Real=T(1), - d::Real=T(3) - ) where {T<:AbstractFloat} - @check_args(PolynomialKernel, a, a > zero(a), "a > 0") - @check_args(PolynomialKernel, c, c >= zero(c), "c ≧ 0") - @check_args(PolynomialKernel, d, d >= one(d) && d == trunc(d), "d ∈ ℤ₊") + a::Union{T,AbstractVector{T}}=T(1), + c::T=T(1), + d::T=T(3) + ) where {T<:Real} + @check_args(PolynomialKernel, a, count(a .<= zero(T)) == 0, "a > 0") + @check_args(PolynomialKernel, c, c >= zero(T), "c ≧ 0") + @check_args(PolynomialKernel, d, d >= one(T) && d == trunc(d), "d ∈ ℤ₊") return new{T}(a, c, d) end end @@ -48,9 +48,9 @@ end @inline basefunction(::PolynomialKernel) = ScalarProduct() @inline function kappa(κ::PolynomialKernel{T}, xᵀy::T) where {T} - return (κ.a*xᵀy + κ.c)^(κ.d) + return (xᵀy + κ.c)^(κ.d) end function convert(::Type{K}, κ::PolynomialKernel) where {K>:PolynomialKernel{T}} where T return PolynomialKernel{T}(κ.a, κ.c, κ.d) -end \ No newline at end of file +end diff --git a/src/kernelfunctions/mercer/rationalquadratic.jl b/src/kernelfunctions/mercer/rationalquadratic.jl index 9e1ecc4..0ec726c 100644 --- a/src/kernelfunctions/mercer/rationalquadratic.jl +++ b/src/kernelfunctions/mercer/rationalquadratic.jl @@ -1,5 +1,5 @@ # Abstract Rational-Quadratic Kernel ======================================================= -abstract type AbstractRationalQuadraticKernel{T<:AbstractFloat} <: MercerKernel{T} end +abstract type AbstractRationalQuadraticKernel{T<:Real <: MercerKernel{T} end @inline basefunction(::AbstractRationalQuadraticKernel) = SquaredEuclidean() @@ -30,16 +30,16 @@ julia> RationalQuadraticKernel(2.0f0, 2.0) RationalQuadraticKernel{Float64}(2.0,2.0) ``` """ -struct RationalQuadraticKernel{T<:AbstractFloat} <: AbstractRationalQuadraticKernel{T} - α::T +struct RationalQuadraticKernel{T<:Real} <: AbstractRationalQuadraticKernel{T} + α::A β::T function RationalQuadraticKernel{T}( - α::Real=T(1), - β::Real=T(1) - ) where {T<:AbstractFloat} - @check_args(RationalQuadraticKernel, α, α > zero(T), "α > 0") + α::Union{T,AbstractVector{T}}=T(1), + β::T=T(1) + ) where {T<:Real} + @check_args(RationalQuadraticKernel, α, count(α .<= zero(T))==0, "α > 0") @check_args(RationalQuadraticKernel, β, β > zero(T), "β > 0") - return new{T}(α, β) + return new{T,typeof(α)}(α, β) end end function RationalQuadraticKernel( @@ -50,7 +50,7 @@ function RationalQuadraticKernel( end @inline function kappa(κ::RationalQuadraticKernel{T}, d²::T) where {T} - return (one(T) + κ.α*d²)^(-κ.β) + return (one(T) + d²)^(-κ.β) end function convert( @@ -90,7 +90,7 @@ julia> GammaRationalQuadraticKernel(2.0f0, 2.0f0, 0.5f0) GammaRationalQuadraticKernel{Float32}(2.0,2.0,0.5) ``` """ -struct GammaRationalQuadraticKernel{T<:AbstractFloat} <: AbstractRationalQuadraticKernel{T} +struct GammaRationalQuadraticKernel{T<:Real} <: AbstractRationalQuadraticKernel{T} α::T β::T γ::T @@ -98,7 +98,7 @@ struct GammaRationalQuadraticKernel{T<:AbstractFloat} <: AbstractRationalQuadrat α::Real=T(1), β::Real=T(1), γ::Real=T(1) - ) where {T<:AbstractFloat} + ) where {T<:Real} @check_args(GammaRationalQuadraticKernel, α, α > zero(T), "α > 0") @check_args(GammaRationalQuadraticKernel, β, β > zero(T), "β > 0") @check_args(GammaRationalQuadraticKernel, γ, one(T) >= γ > zero(T), "γ ∈ (0,1]") @@ -122,4 +122,4 @@ function convert( κ::GammaRationalQuadraticKernel ) where {K>:GammaRationalQuadraticKernel{T}} where T return GammaRationalQuadraticKernel{T}(κ.α, κ.β, κ.γ) -end \ No newline at end of file +end diff --git a/src/kernelfunctions/negativedefinite/log.jl b/src/kernelfunctions/negativedefinite/log.jl index d075984..8da69cf 100644 --- a/src/kernelfunctions/negativedefinite/log.jl +++ b/src/kernelfunctions/negativedefinite/log.jl @@ -21,13 +21,13 @@ julia> LogKernel(0.5, 0.5) LogKernel{Float64}(0.5,0.5) ``` """ -struct LogKernel{T<:AbstractFloat} <: NegativeDefiniteKernel{T} - α::T +struct LogKernel{T<:Real,A} <: NegativeDefiniteKernel{T} + α::A γ::T - function LogKernel{T}(α::Real=T(1), γ::Real=T(1)) where {T<:AbstractFloat} - @check_args(LogKernel, α, α > zero(T), "α > 0") + function LogKernel{T}(α::Union{T,AbstractVector{T}}=T(1), γ::T=T(1)) where {T<:Real} + @check_args(LogKernel, α, count(α .<= zero(T))==0, "α > 0") @check_args(LogKernel, γ, one(T) >= γ > zero(T), "γ ∈ (0,1]") - return new{T}(α, γ) + return new{T,typeof(α)}(α.^(-γ), γ) end end function LogKernel(α::T₁=1.0, γ::T₂=T₁(1)) where {T₁<:Real,T₂<:Real} @@ -36,8 +36,8 @@ end @inline basefunction(::LogKernel) = SquaredEuclidean() -@inline kappa(κ::LogKernel{T}, d²::T) where {T} = log(one(T) + κ.α*d²^(κ.γ)) +@inline kappa(κ::LogKernel{T}, d²::T) where {T} = log(one(T) + d²^(κ.γ)) function convert(::Type{K}, κ::LogKernel) where {K>:LogKernel{T}} where T return LogKernel{T}(κ.α, κ.γ) -end \ No newline at end of file +end diff --git a/src/kernelfunctions/negativedefinite/power.jl b/src/kernelfunctions/negativedefinite/power.jl index f37a9b3..8de22e0 100644 --- a/src/kernelfunctions/negativedefinite/power.jl +++ b/src/kernelfunctions/negativedefinite/power.jl @@ -17,9 +17,9 @@ julia> PowerKernel(0.5f0) PowerKernel{Float32}(0.5) ``` """ -struct PowerKernel{T<:AbstractFloat} <: NegativeDefiniteKernel{T} +struct PowerKernel{T<:Real} <: NegativeDefiniteKernel{T} γ::T - function PowerKernel{T}(γ::Real=T(1)) where {T<:AbstractFloat} + function PowerKernel{T}(γ::Real=T(1)) where {T<:Real} @check_args(PowerKernel, γ, one(T) >= γ > zero(T), "γ ∈ (0,1]") new{T}(γ) end @@ -32,4 +32,4 @@ PowerKernel(γ::T=1.0) where {T<:Real} = PowerKernel{promote_float(T)}(γ) function convert(::Type{K}, κ::PowerKernel) where {K>:PowerKernel{T}} where T return PowerKernel{T}(κ.γ) -end \ No newline at end of file +end diff --git a/src/kernelfunctions/sigmoid.jl b/src/kernelfunctions/sigmoid.jl index 3a83f76..8a9afb0 100644 --- a/src/kernelfunctions/sigmoid.jl +++ b/src/kernelfunctions/sigmoid.jl @@ -19,13 +19,13 @@ julia> SigmoidKernel(0.5f0, 0.5) SigmoidKernel{Float64}(0.5,0.5) ``` """ -struct SigmoidKernel{T<:AbstractFloat} <: Kernel{T} - a::T +struct SigmoidKernel{T<:Real,A} <: Kernel{T} + a::A c::T - function SigmoidKernel{T}(a::Real=T(1), c::Real=T(1)) where {T<:AbstractFloat} - @check_args(SigmoidKernel, a, a > zero(T), "a > 0") + function SigmoidKernel{T}(a::Union{T,AbstractVector{T}}=T(1), c::T=T(1)) where {T<:Real} + @check_args(SigmoidKernel, a, count(a .<= zero(T))==0, "a > 0") @check_args(SigmoidKernel, c, c >= zero(T), "c ≧ 0") - return new{T}(a, c) + return new{T,typeof(a)}(a, c) end end function SigmoidKernel(a::T₁=1.0, c::T₂=T₁(1)) where {T₁<:Real,T₂<:Real} @@ -34,8 +34,8 @@ end @inline basefunction(::SigmoidKernel) = ScalarProduct() -@inline kappa(κ::SigmoidKernel{T}, xᵀy::T) where {T} = tanh(κ.a*xᵀy + κ.c) +@inline kappa(κ::SigmoidKernel{T}, xᵀy::T) where {T} = tanh(xᵀy + κ.c) function convert(::Type{K}, κ::SigmoidKernel) where {K>:SigmoidKernel{T}} where T return SigmoidKernel{T}(κ.a, κ.c) -end \ No newline at end of file +end diff --git a/src/kernelmatrix.jl b/src/kernelmatrix.jl index 9205b94..dcd9ad9 100644 --- a/src/kernelmatrix.jl +++ b/src/kernelmatrix.jl @@ -1,21 +1,21 @@ # Kernel Scalar & Vector Operation ======================================================== -function kernel(κ::Kernel{T}, x::T, y::T) where {T<:AbstractFloat} - kappa(κ, base_evaluate(basefunction(κ), x, y)) +function kernel(κ::Kernel{T}, x::T, y::T) where {T<:Real} + kappa(κ, base_evaluate(basefunction(κ), κ.α, x, y)) end function kernel( κ::Kernel{T}, x::AbstractArray{T}, y::AbstractArray{T} - ) where {T<:AbstractFloat} - kappa(κ, base_evaluate(basefunction(κ), x, y)) + ) where {T<:Real} + kappa(κ, base_evaluate(basefunction(κ), κ.α, x, y)) end # Kernel Matrix Calculation ================================================================ -function kappamatrix!(κ::Kernel{T}, P::AbstractMatrix{T}) where {T<:AbstractFloat} +function kappamatrix!(κ::Kernel{T}, P::AbstractMatrix{T}) where {T<:Real} for i in eachindex(P) @inbounds P[i] = kappa(κ, P[i]) end @@ -26,7 +26,7 @@ function symmetric_kappamatrix!( κ::Kernel{T}, P::AbstractMatrix{T}, symmetrize::Bool - ) where {T<:AbstractFloat} + ) where {T<:Real} if !((n = size(P,1)) == size(P,2)) throw(DimensionMismatch("Pairwise matrix must be square.")) end @@ -48,8 +48,8 @@ function kernelmatrix!( κ::Kernel{T}, X::AbstractMatrix{T}, symmetrize::Bool - ) where {T<:AbstractFloat} - basematrix!(σ, K, basefunction(κ), X, false) + ) where {T<:Real} + basematrix!(σ, K, basefunction(κ), κ.α, X, false) symmetric_kappamatrix!(κ, K, symmetrize) end @@ -65,8 +65,8 @@ function kernelmatrix!( κ::Kernel{T}, X::AbstractMatrix{T}, Y::AbstractMatrix{T} - ) where {T<:AbstractFloat} - basematrix!(σ, K, basefunction(κ), X, Y) + ) where {T<:Real} + basematrix!(σ, K, basefunction(κ), κ.α, X, Y) kappamatrix!(κ, K) end @@ -75,9 +75,9 @@ function kernelmatrix( κ::Kernel{T}, X::AbstractMatrix{T}, symmetrize::Bool = true - ) where {T<:AbstractFloat} + ) where {T<:Real} K = allocate_basematrix(σ, X) - symmetric_kappamatrix!(κ, basematrix!(σ, K, basefunction(κ), X, false), symmetrize) + symmetric_kappamatrix!(κ, basematrix!(σ, K, basefunction(κ), κ.α, X, false), symmetrize) end function kernelmatrix( @@ -85,9 +85,9 @@ function kernelmatrix( κ::Kernel{T}, X::AbstractMatrix{T}, Y::AbstractMatrix{T} - ) where {T<:AbstractFloat} + ) where {T<:Real} K = allocate_basematrix(σ, X, Y) - kappamatrix!(κ, basematrix!(σ, K, basefunction(κ), X, Y)) + kappamatrix!(κ, basematrix!(σ, K, basefunction(κ), κ.α, X, Y)) end @@ -182,7 +182,7 @@ Where ``\mathbf{\mu}_{\phi\mathbf{x}}`` and ``\mathbf{\mu}_{\phi\mathbf{x}}`` ar = \frac{1}{m} \sum_{i=1}^m \phi(\mathbf{y}_i) ``` """ -function centerkernelmatrix!(K::Matrix{T}) where {T<:AbstractFloat} +function centerkernelmatrix!(K::Matrix{T}) where {T<:Real} μx = Statistics.mean(K, dims = 2) μy = Statistics.mean(K, dims = 1) μ = Statistics.mean(K) @@ -191,4 +191,4 @@ function centerkernelmatrix!(K::Matrix{T}) where {T<:AbstractFloat} return K end -centerkernelmatrix(K::Matrix) = centerkernelmatrix!(copy(K)) \ No newline at end of file +centerkernelmatrix(K::Matrix) = centerkernelmatrix!(copy(K)) diff --git a/src/nystrom.jl b/src/nystrom.jl index 526cccc..7beadba 100644 --- a/src/nystrom.jl +++ b/src/nystrom.jl @@ -8,7 +8,7 @@ for orientation in (:row, :col) σ::Val{$(Meta.quot(orientation))}, X::Matrix, r::T - ) where {T<:AbstractFloat} + ) where {T<:Real} 0 < r <= 1 || error("Sample rate must be in range (0,1]") n = size(X, $dim) s = max(Int64(trunc(n*r)),1) @@ -21,7 +21,7 @@ for orientation in (:row, :col) κ::Kernel{T}, X::Matrix{T}, S::Vector{U} - ) where {T<:AbstractFloat,U<:Integer} + ) where {T<:Real,U<:Integer} Xs = getindex(X, $S, $fulldim) C = kernelmatrix(σ, κ, Xs, X) # kernel matrix of X and sampled X Cs = getindex(C, :, S) # purely sampled component of C diff --git a/test/ARD.jl b/test/ARD.jl new file mode 100644 index 0000000..75ad4ee --- /dev/null +++ b/test/ARD.jl @@ -0,0 +1,27 @@ +using MLKernels +using ForwardDiff, LinearAlgebra +using Random: seed! +seed!(42) +cd(dirname(@__FILE__)) + +k = SquaredExponentialKernel([1.0,3.0]) +X= rand(10,2) +y = rand(100,2) + +KXy = kernelmatrix(k,X,y) + +KXY = kernelmatrix(k,X) + +A = rand(10,10) +B = rand(100,100) +function tracekernel(x) + k = SquaredExponentialKernel(x) + KXY = kernelmatrix(k,X,y) + KX = kernelmatrix(k,X) + return tr(inv(KX+1e-7*I)*A*KX + KXY*B*KXY') +end + +tracekernel([1.0,3.0]) +ForwardDiff.gradient(tracekernel,[1.0,3.0]) + +k.α = [2.0,3.0] From 065e123cc36371030e3bd40f13c0a81d11ccc150 Mon Sep 17 00:00:00 2001 From: Theo GF Date: Fri, 11 Jan 2019 16:03:39 +0100 Subject: [PATCH 2/5] Created constructors for each kernel, started adapting tests --- src/basematrix.jl | 13 +++++-- src/kernelfunctions/mercer/exponential.jl | 20 ++++++----- src/kernelfunctions/mercer/exponentiated.jl | 2 +- src/kernelfunctions/mercer/matern.jl | 5 ++- src/kernelfunctions/mercer/polynomial.jl | 4 +-- .../mercer/rationalquadratic.jl | 6 ++-- src/kernelfunctions/negativedefinite/log.jl | 2 +- src/kernelfunctions/sigmoid.jl | 4 +-- test/basefunctions.jl | 10 +++--- test/basematrix.jl | 35 +++++++++++-------- test/reference.jl | 34 +++++++++--------- 11 files changed, 74 insertions(+), 61 deletions(-) diff --git a/src/basematrix.jl b/src/basematrix.jl index a434382..075ad4d 100644 --- a/src/basematrix.jl +++ b/src/basematrix.jl @@ -3,10 +3,15 @@ @inline base_initiate(::BaseFunction, ::Type{T}) where {T} = zero(T) @inline base_return(::BaseFunction, s::T) where {T} = s -function base_evaluate(f::BaseFunction, x::T, y::T) where {T<:Real} - base_return(f, base_aggregate(f, base_initiate(f,T), x, y)) +function base_evaluate(f::BaseFunction, scale::T, x::T, y::T) where {T<:Real} + base_return(f, base_aggregate(f, base_initiate(f,T), scale, x, y)) end +function base_evaluate(f::BaseFunction, scale::AbstractVector{T}, x::T, y::T) where {T<:Real} + base_return(f, base_aggregate(f, base_initiate(f,T), scale[1], x, y)) +end + + # Note: no checks, assumes length(x) == length(y) >= 1 function unsafe_base_evaluate( f::BaseFunction, @@ -45,8 +50,10 @@ function base_evaluate( x::AbstractArray{T}, y::AbstractArray{T} ) where {T<:Real} - if (n = length(x)) != length(y) || n != length(scale) + if (n = length(x)) != length(y) throw(DimensionMismatch("Arrays x and y must have the same length.")) + elseif n != length(scale) + throw(DimensionMismatch("Arrays x and y must have the same length as the scaling vector of the kernel")) elseif n == 0 throw(DimensionMismatch("Arrays x and y must be at least of length 1.")) end diff --git a/src/kernelfunctions/mercer/exponential.jl b/src/kernelfunctions/mercer/exponential.jl index 7ad0aa1..f7f915f 100644 --- a/src/kernelfunctions/mercer/exponential.jl +++ b/src/kernelfunctions/mercer/exponential.jl @@ -1,4 +1,4 @@ -Real# Abstract Exponential Kernel ============================================================== +# Abstract Exponential Kernel ============================================================== abstract type AbstractExponentialKernel{T<:Real} <: MercerKernel{T} end @@ -36,6 +36,8 @@ struct ExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} end end +ExponentialKernel(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} = ExponentialKernel{promote_float(T)}(α) + @inline kappa(κ::ExponentialKernel{T}, d²::T) where {T} = exp(-√(d²)) function convert(::Type{K}, κ::ExponentialKernel) where {K>:ExponentialKernel{T}} where T @@ -75,16 +77,14 @@ SquaredExponentialKernel{Float32}(2.0) """ struct SquaredExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} α::A - function SquaredExponentialKernel{T}(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} + function SquaredExponentialKernel{T}(α::Union{T,AbstractVector{T}}=T(1)) where {T<:Real} @check_args(SquaredExponentialKernel, α, count(α .<= zero(T))==0, "α > 0") return new{T,typeof(α)}(α) end - function SquaredExponentialKernel{T}(α::T=one(T)) where {T<:Real} - @check_args(SquaredExponentialKernel, α, α > zero(T), "α > 0") - return new{T,T}(α) - end end +SquaredExponentialKernel(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} = SquaredExponentialKernel{promote_float{T}}(α) + @inline kappa(κ::SquaredExponentialKernel{T}, d²::T) where {T} = exp(-d²) function convert( @@ -119,7 +119,7 @@ The ``\gamma``-exponential kernel is an isotropic Mercer kernel given by the for κ(x,y) = exp(α‖x-y‖²ᵞ) α > 0, γ ∈ (0,1] ``` where `α` is a scaling parameter and `γ` is a shape parameter of the Euclidean distance. -When `γ = 1` use [`SquaredExponentialKernel`](@ref) and [`SquaredExponentialKernel`](@ref) +When `γ = 1` use [`SquaredExponentialKernel`](@ref) and [`ExponentialKernel`](@ref) when `γ = 0.5` since these are more efficient implementations. # Examples @@ -141,10 +141,14 @@ struct GammaExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} function GammaExponentialKernel{T}(α::Union{T,AbstractVector{T}}=T(1), γ::T=T(1)) where {T<:Real} @check_args(GammaExponentialKernel, α, count(α .<= zero(T))==0, "α > 0") @check_args(GammaExponentialKernel, γ, one(T) >= γ > zero(T), "γ ∈ (0,1]") - return new{T,typeof(α)}(α.^{-γ}, γ) + return new{T,typeof(α)}(α.^(-γ), γ) end end +function GammaExponentialKernel(α::Union{T₁,AbstractVector{T₁}}=1.0, γ::T₂=T₁(1)) where {T₁<:Real, T₂<:Real} + return GammaExponentialKernel{promote_float(T₁,T₂)}(α, γ) +end + @inline kappa(κ::GammaExponentialKernel{T}, d²::T) where {T} = exp(-d²^κ.γ) function convert( diff --git a/src/kernelfunctions/mercer/exponentiated.jl b/src/kernelfunctions/mercer/exponentiated.jl index 1dfae01..beee9ee 100644 --- a/src/kernelfunctions/mercer/exponentiated.jl +++ b/src/kernelfunctions/mercer/exponentiated.jl @@ -28,7 +28,7 @@ struct ExponentiatedKernel{T<:Real,A} <: MercerKernel{T} return new{T,typeof(α)}(α) end end -ExponentiatedKernel(α::T=1.0) where {T<:Real} = ExponentiatedKernel{T}(α) +ExponentiatedKernel(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} = ExponentiatedKernel{T}(α) @inline basefunction(::ExponentiatedKernel) = ScalarProduct() diff --git a/src/kernelfunctions/mercer/matern.jl b/src/kernelfunctions/mercer/matern.jl index 30609fb..54b8f5a 100644 --- a/src/kernelfunctions/mercer/matern.jl +++ b/src/kernelfunctions/mercer/matern.jl @@ -26,9 +26,8 @@ struct MaternKernel{T<:Real,A} <: MercerKernel{T} return new{T,typeof(ρ)}(ν, 1.0./ρ.^2) end end -# function MaternKernel(ν::T₁=1.0, ρ::T₂=T₁(1)) where {T₁<:Real,T₂<:Real} -# MaternKernel{promote_float(T₁,T₂)}(ν,ρ) -# end + +MaternKernel(ν::Union{T₁,AbstractVector{T₁}}=1.0, ρ::T₂=T₁(1)) where {T₁<:Real,T₂<:Real} = MaternKernel{promote_float(T₁,T₂)}(ν,ρ) @inline basefunction(::MaternKernel) = SquaredEuclidean() diff --git a/src/kernelfunctions/mercer/polynomial.jl b/src/kernelfunctions/mercer/polynomial.jl index eb3ebf9..1380e0b 100644 --- a/src/kernelfunctions/mercer/polynomial.jl +++ b/src/kernelfunctions/mercer/polynomial.jl @@ -32,12 +32,12 @@ struct PolynomialKernel{T<:Real,A} <: MercerKernel{T} @check_args(PolynomialKernel, a, count(a .<= zero(T)) == 0, "a > 0") @check_args(PolynomialKernel, c, c >= zero(T), "c ≧ 0") @check_args(PolynomialKernel, d, d >= one(T) && d == trunc(d), "d ∈ ℤ₊") - return new{T}(a, c, d) + return new{T,typeof{a}}(a, c, d) end end function PolynomialKernel( - a::T₁=1.0, + a::Union{T₁,AbstractVector{T₁}}=1.0, c::T₂=T₁(1), d::T₃=convert(promote_float(T₁,T₂), 3) ) where {T₁<:Real,T₂<:Real,T₃<:Real} diff --git a/src/kernelfunctions/mercer/rationalquadratic.jl b/src/kernelfunctions/mercer/rationalquadratic.jl index 0ec726c..8c359e4 100644 --- a/src/kernelfunctions/mercer/rationalquadratic.jl +++ b/src/kernelfunctions/mercer/rationalquadratic.jl @@ -1,5 +1,5 @@ # Abstract Rational-Quadratic Kernel ======================================================= -abstract type AbstractRationalQuadraticKernel{T<:Real <: MercerKernel{T} end +abstract type AbstractRationalQuadraticKernel{T<:Real} <: MercerKernel{T} end @inline basefunction(::AbstractRationalQuadraticKernel) = SquaredEuclidean() @@ -30,7 +30,7 @@ julia> RationalQuadraticKernel(2.0f0, 2.0) RationalQuadraticKernel{Float64}(2.0,2.0) ``` """ -struct RationalQuadraticKernel{T<:Real} <: AbstractRationalQuadraticKernel{T} +struct RationalQuadraticKernel{T<:Real,A} <: AbstractRationalQuadraticKernel{T} α::A β::T function RationalQuadraticKernel{T}( @@ -43,7 +43,7 @@ struct RationalQuadraticKernel{T<:Real} <: AbstractRationalQuadraticKernel{T} end end function RationalQuadraticKernel( - α::T₁=1.0, + α::Union{T₁,AbstractVector{T₁}}=1.0, β::T₂=T₁(1) ) where {T₁<:Real, T₂<:Real} RationalQuadraticKernel{promote_float(T₁, T₂)}(α, β) diff --git a/src/kernelfunctions/negativedefinite/log.jl b/src/kernelfunctions/negativedefinite/log.jl index 8da69cf..0a4c8b5 100644 --- a/src/kernelfunctions/negativedefinite/log.jl +++ b/src/kernelfunctions/negativedefinite/log.jl @@ -30,7 +30,7 @@ struct LogKernel{T<:Real,A} <: NegativeDefiniteKernel{T} return new{T,typeof(α)}(α.^(-γ), γ) end end -function LogKernel(α::T₁=1.0, γ::T₂=T₁(1)) where {T₁<:Real,T₂<:Real} +function LogKernel(α::Union{T₁,AbstractVector{T₁}}=1.0, γ::T₂=T₁(1)) where {T₁<:Real,T₂<:Real} LogKernel{promote_float(T₁,T₂)}(α, γ) end diff --git a/src/kernelfunctions/sigmoid.jl b/src/kernelfunctions/sigmoid.jl index 8a9afb0..1283fee 100644 --- a/src/kernelfunctions/sigmoid.jl +++ b/src/kernelfunctions/sigmoid.jl @@ -28,9 +28,7 @@ struct SigmoidKernel{T<:Real,A} <: Kernel{T} return new{T,typeof(a)}(a, c) end end -function SigmoidKernel(a::T₁=1.0, c::T₂=T₁(1)) where {T₁<:Real,T₂<:Real} - SigmoidKernel{promote_float(T₁,T₂)}(a,c) -end +SigmoidKernel(a::Union{T₁,AbstractVector{T₁}}=1.0, c::T₂=T₁(1)) where {T₁<:Real,T₂<:Real} = SigmoidKernel{promote_float(T₁,T₂)}(a,c) @inline basefunction(::SigmoidKernel) = ScalarProduct() diff --git a/test/basefunctions.jl b/test/basefunctions.jl index a553d9b..a02ebca 100644 --- a/test/basefunctions.jl +++ b/test/basefunctions.jl @@ -21,10 +21,10 @@ function test_base_function(f) # Test that aggregation works correctly @testset "Testing $(MLK.base_aggregate)" begin for T in FloatingPointTypes - f_tmp = get(base_functions_aggregate, f, (s,x,y) -> convert(T, NaN)) - for x in (T(0), T(1), T(2)), y in (T(0), T(1), T(2)) - s = MLK.base_aggregate(F, T(1), x, y) - s_tmp = f_tmp(T(1), x, y) + f_tmp = get(base_functions_aggregate, f, (s,scale,x,y) -> convert(T, NaN)) + for x in (T(0), T(1), T(2)), y in (T(0), T(1), T(2)), scale in (T(1), T(2)) + s = MLK.base_aggregate(F, T(1), scale, x, y) + s_tmp = f_tmp(T(1), scale, x, y) @test typeof(s) == T @test s == s_tmp @@ -51,4 +51,4 @@ for f in base_functions @testset "Testing $f" begin test_base_function(f) end -end \ No newline at end of file +end diff --git a/test/basematrix.jl b/test/basematrix.jl index 289e5ff..4473a4f 100644 --- a/test/basematrix.jl +++ b/test/basematrix.jl @@ -5,20 +5,20 @@ p = 5 @testset "Testing $(MLK.unsafe_base_evaluate)" begin for f in base_functions F = (f)() - f_agg_tmp = get(base_functions_aggregate, f, (s,x,y) -> NaN) + f_agg_tmp = get(base_functions_aggregate, f, (s,scale,x,y) -> NaN) f_ret_tmp = get(base_functions_return, f, s -> s) for T in FloatingPointTypes x = rand(T,p) y = rand(T,p) - + scale = rand(T,p) s = zero(T) for i = 1:p - s = f_agg_tmp(s, x[i], y[i]) + s = f_agg_tmp(s, scale[i], x[i], y[i]) end s = f_ret_tmp(s) - @test isapprox(s, MLK.unsafe_base_evaluate(F, x, y)) + @test isapprox(s, MLK.unsafe_base_evaluate(F, scale, x, y)) end end end @@ -29,15 +29,18 @@ end for T in FloatingPointTypes v = rand(T,p+1) + scale = rand(T,p) + scale_f = rand(T,p+1) x = rand(T,p) y = rand(T,p) - @test isapprox(MLK.base_evaluate(F, x, y), MLK.unsafe_base_evaluate(F, x, y)) - @test isapprox(MLK.base_evaluate(F, x[1], y[1]), MLK.unsafe_base_evaluate(F, x[1:1], y[1:1])) + @test isapprox(MLK.base_evaluate(F, scale, x, y), MLK.unsafe_base_evaluate(F, scale, x, y)) + @test isapprox(MLK.base_evaluate(F, scale[1], x[1], y[1]), MLK.unsafe_base_evaluate(F, scale[1:1], x[1:1], y[1:1])) - @test_throws DimensionMismatch MLK.base_evaluate(F, x, v) - @test_throws DimensionMismatch MLK.base_evaluate(F, v, x) - @test_throws DimensionMismatch MLK.base_evaluate(F, T[], T[]) + @test_throws DimensionMismatch MLK.base_evaluate(F, scale, x, v) + @test_throws DimensionMismatch MLK.base_evaluate(F, scale, v, x) + @test_throws DimensionMismatch MLK.base_evaluate(F, scale_f, x, y) + @test_throws DimensionMismatch MLK.base_evaluate(F, scale, T[], T[]) end end end @@ -113,6 +116,7 @@ end for T in (Float32, Float64) X_set = [rand(T,p) for i = 1:n] Y_set = [rand(T,p) for i = 1:m] + scale = rand(T,p) P_tst_nn = Array{T}(undef, n, n) P_tst_nm = Array{T}(undef, n, m) @@ -133,11 +137,11 @@ end X = layout == Val(:row) ? permutedims(hcat(X_set...)) : hcat(X_set...) Y = layout == Val(:row) ? permutedims(hcat(Y_set...)) : hcat(Y_set...) - P = [MLK.base_evaluate(F,x,y) for x in X_set, y in X_set] - @test isapprox(P, MLK.basematrix!(layout, P_tst_nn, F, X, true)) + P = [MLK.base_evaluate(F,scale,x,y) for x in X_set, y in X_set] + @test isapprox(P, MLK.basematrix!(layout, P_tst_nn, F, scale, X, true)) - P = [MLK.base_evaluate(F,x,y) for x in X_set, y in Y_set] - @test isapprox(P, MLK.basematrix!(layout, P_tst_nm, F, X, Y)) + P = [MLK.base_evaluate(F,scale,x,y) for x in X_set, y in Y_set] + @test isapprox(P, MLK.basematrix!(layout, P_tst_nm, F, scale, X, Y)) end end end @@ -157,8 +161,9 @@ end F = SquaredEuclidean() X = layout == Val(:row) ? permutedims(hcat(v1, v2)) : hcat(v1, v2) Y = layout == Val(:row) ? permutedims(hcat(v1, v2, v3)) : hcat(v1, v2, v3) + scale = ones(Float64,3) - @test all(MLK.basematrix!(layout, Array{Float64}(undef, 2,2), F, X, true) .>= 0.0) - @test all(MLK.basematrix!(layout, Array{Float64}(undef, 2,3), F, X, Y) .>= 0.0) + @test all(MLK.basematrix!(layout, Array{Float64}(undef, 2,2), F, scale, X, true) .>= 0.0) + @test all(MLK.basematrix!(layout, Array{Float64}(undef, 2,3), F, scale, X, Y) .>= 0.0) end end diff --git a/test/reference.jl b/test/reference.jl index 67524b6..751b35b 100644 --- a/test/reference.jl +++ b/test/reference.jl @@ -2,7 +2,7 @@ struct Euclidean <: Metric end -MLK.base_aggregate(::Euclidean, s::T, x::T, y::T) where {T} = s + (x-y)^2 +MLK.base_aggregate(::Euclidean, s::T, scale::T, x::T, y::T) where {T} = s + scale*(x-y)^2 MLK.base_return(::Euclidean, s::T) where {T} = sqrt(s) @@ -13,7 +13,7 @@ const base_functions = ( ScalarProduct, Euclidean ) - + const base_functions_initiate = Dict( SquaredEuclidean => 0, ScalarProduct => 0, @@ -21,9 +21,9 @@ const base_functions_initiate = Dict( ) const base_functions_aggregate = Dict( - SquaredEuclidean => (s,x,y) -> s + (x-y)^2, - ScalarProduct => (s,x,y) -> s + x*y, - Euclidean => (s,x,y) -> s + (x-y)^2 + SquaredEuclidean => (s,scale,x,y) -> s + scale*(x-y)^2, + ScalarProduct => (s,scale,x,y) -> s + scale*x*y, + Euclidean => (s,scale,x,y) -> s + scale*(x-y)^2 ) const base_functions_return = Dict( @@ -57,7 +57,7 @@ const kernel_functions = ( ) const kernel_functions_arguments = Dict( - ExponentialKernel => ((1.0,), (2.0,)), + ExponentialKernel => ((1.0,), (2.0,) ), SquaredExponentialKernel => ((1.0,), (2.0,)), GammaExponentialKernel => ((1.0,1.0), (2.0,0.5)), RationalQuadraticKernel => ((1.0,1.0), (2.0,2.0)), @@ -71,28 +71,28 @@ const kernel_functions_arguments = Dict( ) const kernel_functions_kappa = Dict( - ExponentialKernel => (z,α) -> exp(-α*sqrt(z)), - SquaredExponentialKernel => (z,α) -> exp(-α*z), - GammaExponentialKernel => (z,α,γ) -> exp(-α*z^γ), - RationalQuadraticKernel => (z,α,β) -> (1 + α*z)^(-β), - GammaRationalQuadraticKernel => (z,α,β,γ) -> (1 + α*z^γ)^(-β), + ExponentialKernel => (z,α) -> exp(-sqrt(z)), + SquaredExponentialKernel => (z,α) -> exp(-z), + GammaExponentialKernel => (z,α,γ) -> exp(-z^γ), + RationalQuadraticKernel => (z,α,β) -> (1 + z)^(-β), + GammaRationalQuadraticKernel => (z,α,β,γ) -> (1 + z^γ)^(-β), MaternKernel => (z,ν,ρ) -> begin d = √(z) T = typeof(z) d = d < eps(T) ? eps(T) : d - tmp1 = √(2*ν)*d/ρ + tmp1 = √(2*ν)*d tmp2 = 2^(1 - ν) tmp2*(tmp1^ν)*besselk(ν, tmp1)/gamma(ν) end, - PolynomialKernel => (z,a,c,d) -> (a*z+c)^d, - ExponentiatedKernel => (z,a) -> exp(a*z), + PolynomialKernel => (z,a,c,d) -> (z+c)^d, + ExponentiatedKernel => (z,a) -> exp(z), PowerKernel => (z,γ) -> z^γ, - LogKernel => (z,α,γ) -> log(α*z^γ+1), - SigmoidKernel => (z,a,c) -> tanh(a*z+c) + LogKernel => (z,α,γ) -> log(z^γ+1), + SigmoidKernel => (z,a,c) -> tanh(z+c) ) const kernel_functions_base = Dict( PolynomialKernel => ScalarProduct, ExponentiatedKernel => ScalarProduct, SigmoidKernel => ScalarProduct -) \ No newline at end of file +) From 88c5a2a5d3b80e2d32025876aae3b49594bde277 Mon Sep 17 00:00:00 2001 From: Theo GF Date: Fri, 11 Jan 2019 18:33:07 +0100 Subject: [PATCH 3/5] Validation of all the tests --- src/basematrix.jl | 2 +- src/kernelfunctions/mercer/exponential.jl | 23 ++++++++++-------- src/kernelfunctions/mercer/exponentiated.jl | 8 +++---- src/kernelfunctions/mercer/matern.jl | 8 +++---- src/kernelfunctions/mercer/polynomial.jl | 17 +++++++------ .../mercer/rationalquadratic.jl | 24 +++++++++---------- src/kernelfunctions/negativedefinite/log.jl | 6 ++--- src/kernelfunctions/negativedefinite/power.jl | 9 +++---- src/kernelfunctions/sigmoid.jl | 8 +++---- test/kernelfunctions.jl | 9 +++---- test/kernelmatrix.jl | 5 ++-- test/runtests.jl | 2 +- 12 files changed, 63 insertions(+), 58 deletions(-) diff --git a/src/basematrix.jl b/src/basematrix.jl index 075ad4d..f1bb96a 100644 --- a/src/basematrix.jl +++ b/src/basematrix.jl @@ -66,7 +66,7 @@ function base_evaluate( x::AbstractArray{T}, y::AbstractArray{T} ) where {T<:Real} - if (n = length(x)) != length(y) || n != length(scale) + if (n = length(x)) != length(y) throw(DimensionMismatch("Arrays x and y must have the same length.")) elseif n == 0 throw(DimensionMismatch("Arrays x and y must be at least of length 1.")) diff --git a/src/kernelfunctions/mercer/exponential.jl b/src/kernelfunctions/mercer/exponential.jl index f7f915f..5fcc52f 100644 --- a/src/kernelfunctions/mercer/exponential.jl +++ b/src/kernelfunctions/mercer/exponential.jl @@ -30,7 +30,7 @@ ExponentialKernel{Float32}(2.0) """ struct ExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} α::A - function ExponentialKernel{T}(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} + function ExponentialKernel{T}(α::Union{Real,AbstractVector{Real}}=T(1)) where {T<:Real} @check_args(ExponentialKernel, α, count(α .<= zero(T)) == 0, "α > 0") return new{T,typeof(α)}(α.^2) end @@ -40,8 +40,8 @@ ExponentialKernel(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} = Exponent @inline kappa(κ::ExponentialKernel{T}, d²::T) where {T} = exp(-√(d²)) -function convert(::Type{K}, κ::ExponentialKernel) where {K>:ExponentialKernel{T}} where T - return ExponentialKernel{T}(κ.α) +function Base.convert(::Type{K}, κ::ExponentialKernel) where {K>:ExponentialKernel{T,A} where A} where T + return ExponentialKernel{T}(T.(sqrt.(κ.α))) end """ @@ -77,21 +77,24 @@ SquaredExponentialKernel{Float32}(2.0) """ struct SquaredExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} α::A - function SquaredExponentialKernel{T}(α::Union{T,AbstractVector{T}}=T(1)) where {T<:Real} + function SquaredExponentialKernel{T}(α::Union{Real,AbstractVector{Real}}=T(1)) where {T<:Real} @check_args(SquaredExponentialKernel, α, count(α .<= zero(T))==0, "α > 0") return new{T,typeof(α)}(α) end end -SquaredExponentialKernel(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} = SquaredExponentialKernel{promote_float{T}}(α) +function SquaredExponentialKernel(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} + SquaredExponentialKernel{T}(α) + # SquaredExponentialKernel{promote_float(T)}(α) +end @inline kappa(κ::SquaredExponentialKernel{T}, d²::T) where {T} = exp(-d²) function convert( ::Type{K}, κ::SquaredExponentialKernel - ) where {K>:SquaredExponentialKernel{T}} where T - return SquaredExponentialKernel{T}(κ.α) + ) where {K>:SquaredExponentialKernel{T,A} where A} where T + return SquaredExponentialKernel{T}(T.(κ.α)) end """ @@ -138,7 +141,7 @@ GammaExponentialKernel{Float64}(2.0,0.5) struct GammaExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} α::A γ::T - function GammaExponentialKernel{T}(α::Union{T,AbstractVector{T}}=T(1), γ::T=T(1)) where {T<:Real} + function GammaExponentialKernel{T}(α::Union{Real,AbstractVector{Real}}=T(1), γ::Real=T(1)) where {T<:Real} @check_args(GammaExponentialKernel, α, count(α .<= zero(T))==0, "α > 0") @check_args(GammaExponentialKernel, γ, one(T) >= γ > zero(T), "γ ∈ (0,1]") return new{T,typeof(α)}(α.^(-γ), γ) @@ -154,6 +157,6 @@ end function convert( ::Type{K}, κ::GammaExponentialKernel - ) where {K>:GammaExponentialKernel{T}} where T - return GammaExponentialKernel{T}(κ.α, κ.γ) + ) where {K>:GammaExponentialKernel{T,A} where A} where T + return GammaExponentialKernel{T}(T.(κ.α.^(κ.γ)), T.(κ.γ)) end diff --git a/src/kernelfunctions/mercer/exponentiated.jl b/src/kernelfunctions/mercer/exponentiated.jl index beee9ee..3904609 100644 --- a/src/kernelfunctions/mercer/exponentiated.jl +++ b/src/kernelfunctions/mercer/exponentiated.jl @@ -23,12 +23,12 @@ ExponentiatedKernel{Float32}(2.0) """ struct ExponentiatedKernel{T<:Real,A} <: MercerKernel{T} α::A - function ExponentiatedKernel{T}(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} + function ExponentiatedKernel{T}(α::Union{Real,AbstractVector{Real}}=1.0) where {T<:Real} @check_args(ExponentiatedKernel, α, count(α .<= zero(T))==0, "α > 0") return new{T,typeof(α)}(α) end end -ExponentiatedKernel(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} = ExponentiatedKernel{T}(α) +ExponentiatedKernel(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} = ExponentiatedKernel{promote_float(T)}(α) @inline basefunction(::ExponentiatedKernel) = ScalarProduct() @@ -37,6 +37,6 @@ ExponentiatedKernel(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} = Expone function convert( ::Type{K}, κ::ExponentiatedKernel - ) where {K>:ExponentiatedKernel{T}} where T - return ExponentiatedKernel{T}(κ.α) + ) where {K>:ExponentiatedKernel{T,A} where A} where T + return ExponentiatedKernel{T}(T.(κ.α)) end diff --git a/src/kernelfunctions/mercer/matern.jl b/src/kernelfunctions/mercer/matern.jl index 54b8f5a..89235e9 100644 --- a/src/kernelfunctions/mercer/matern.jl +++ b/src/kernelfunctions/mercer/matern.jl @@ -19,8 +19,8 @@ MaternKernel{Float64}(2.0,2.0) """ struct MaternKernel{T<:Real,A} <: MercerKernel{T} ν::T - ρ::A - function MaternKernel{T}(ν::T=T(1), ρ::Union{T,AbstractVector{T}}=T(1)) where {T<:Real} + α::A + function MaternKernel{T}(ν::Real=T(1), ρ::Union{Real,AbstractVector{Real}}=T(1)) where {T<:Real} @check_args(MaternKernel, ν, ν > zero(T), "ν > 0") @check_args(MaternKernel, ρ, count(ρ .<= zero(T)) == 0, "ρ > 0") return new{T,typeof(ρ)}(ν, 1.0./ρ.^2) @@ -38,6 +38,6 @@ MaternKernel(ν::Union{T₁,AbstractVector{T₁}}=1.0, ρ::T₂=T₁(1)) where { return (convert(T, 2)^(one(T) - κ.ν))*(tmp^κ.ν)*besselk(κ.ν, tmp)/gamma(κ.ν) end -function convert(::Type{K}, κ::MaternKernel) where {K>:MaternKernel{T}} where T - return MaternKernel{T}(κ.ν, κ.ρ) +function convert(::Type{K}, κ::MaternKernel) where {K>:MaternKernel{T,A} where A} where T + return MaternKernel{T}(T(κ.ν), T.(1.0./sqrt.(κ.α))) end diff --git a/src/kernelfunctions/mercer/polynomial.jl b/src/kernelfunctions/mercer/polynomial.jl index 1380e0b..f7a5201 100644 --- a/src/kernelfunctions/mercer/polynomial.jl +++ b/src/kernelfunctions/mercer/polynomial.jl @@ -21,18 +21,18 @@ PolynomialKernel{Float64}(2.0,2.0,2) ``` """ struct PolynomialKernel{T<:Real,A} <: MercerKernel{T} - a::A + α::A c::T d::T function PolynomialKernel{T}( - a::Union{T,AbstractVector{T}}=T(1), - c::T=T(1), - d::T=T(3) + a::Union{Real,AbstractVector{Real}}=T(1), + c::Real=T(1), + d::Real=T(3) ) where {T<:Real} @check_args(PolynomialKernel, a, count(a .<= zero(T)) == 0, "a > 0") @check_args(PolynomialKernel, c, c >= zero(T), "c ≧ 0") @check_args(PolynomialKernel, d, d >= one(T) && d == trunc(d), "d ∈ ℤ₊") - return new{T,typeof{a}}(a, c, d) + return new{T,typeof(a)}(a, c, d) end end @@ -41,8 +41,7 @@ function PolynomialKernel( c::T₂=T₁(1), d::T₃=convert(promote_float(T₁,T₂), 3) ) where {T₁<:Real,T₂<:Real,T₃<:Real} - T = promote_float(T₁,T₂,T₃) - return PolynomialKernel{T}(a, c, d) + return PolynomialKernel{promote_float(T₁,T₂,T₃)}(a, c, d) end @inline basefunction(::PolynomialKernel) = ScalarProduct() @@ -51,6 +50,6 @@ end return (xᵀy + κ.c)^(κ.d) end -function convert(::Type{K}, κ::PolynomialKernel) where {K>:PolynomialKernel{T}} where T - return PolynomialKernel{T}(κ.a, κ.c, κ.d) +function convert(::Type{K}, κ::PolynomialKernel) where {K>:PolynomialKernel{T,A} where A} where T + return PolynomialKernel{T}(T.(κ.α), T(κ.c), T(κ.d)) end diff --git a/src/kernelfunctions/mercer/rationalquadratic.jl b/src/kernelfunctions/mercer/rationalquadratic.jl index 8c359e4..1256a9b 100644 --- a/src/kernelfunctions/mercer/rationalquadratic.jl +++ b/src/kernelfunctions/mercer/rationalquadratic.jl @@ -34,8 +34,8 @@ struct RationalQuadraticKernel{T<:Real,A} <: AbstractRationalQuadraticKernel{T} α::A β::T function RationalQuadraticKernel{T}( - α::Union{T,AbstractVector{T}}=T(1), - β::T=T(1) + α::Union{Real,AbstractVector{Real}}=T(1), + β::Real=T(1) ) where {T<:Real} @check_args(RationalQuadraticKernel, α, count(α .<= zero(T))==0, "α > 0") @check_args(RationalQuadraticKernel, β, β > zero(T), "β > 0") @@ -56,8 +56,8 @@ end function convert( ::Type{K}, κ::RationalQuadraticKernel - ) where {K>:RationalQuadraticKernel{T}} where T - return RationalQuadraticKernel{T}(κ.α, κ.β) + ) where {K>:RationalQuadraticKernel{T,A} where A} where T + return RationalQuadraticKernel{T}(T.(κ.α), T(κ.β)) end @@ -90,23 +90,23 @@ julia> GammaRationalQuadraticKernel(2.0f0, 2.0f0, 0.5f0) GammaRationalQuadraticKernel{Float32}(2.0,2.0,0.5) ``` """ -struct GammaRationalQuadraticKernel{T<:Real} <: AbstractRationalQuadraticKernel{T} - α::T +struct GammaRationalQuadraticKernel{T<:Real,A} <: AbstractRationalQuadraticKernel{T} + α::A β::T γ::T function GammaRationalQuadraticKernel{T}( - α::Real=T(1), + α::Union{Real,AbstractVector{Real}}=T(1), β::Real=T(1), γ::Real=T(1) ) where {T<:Real} @check_args(GammaRationalQuadraticKernel, α, α > zero(T), "α > 0") @check_args(GammaRationalQuadraticKernel, β, β > zero(T), "β > 0") @check_args(GammaRationalQuadraticKernel, γ, one(T) >= γ > zero(T), "γ ∈ (0,1]") - return new{T}(α, β, γ) + return new{T,typeof(α)}(α.^(-γ), β, γ) end end function GammaRationalQuadraticKernel( - α::T₁ = 1.0, + α::Union{T₁,AbstractVector{T₁}} = 1.0, β::T₂ = T₁(1), γ::T₃ = one(promote_float(T₁, T₂)) ) where {T₁<:Real, T₂<:Real, T₃<:Real} @@ -114,12 +114,12 @@ function GammaRationalQuadraticKernel( end @inline function kappa(κ::GammaRationalQuadraticKernel{T}, d²::T) where {T} - return (one(T) + κ.α*(d²^κ.γ))^(-κ.β) + return (one(T) + (d²^κ.γ))^(-κ.β) end function convert( ::Type{K}, κ::GammaRationalQuadraticKernel - ) where {K>:GammaRationalQuadraticKernel{T}} where T - return GammaRationalQuadraticKernel{T}(κ.α, κ.β, κ.γ) + ) where {K>:GammaRationalQuadraticKernel{T,A} where A} where T + return GammaRationalQuadraticKernel{T}(T.(κ.α.^κ.γ), T(κ.β), T(κ.γ)) end diff --git a/src/kernelfunctions/negativedefinite/log.jl b/src/kernelfunctions/negativedefinite/log.jl index 0a4c8b5..bc5a11d 100644 --- a/src/kernelfunctions/negativedefinite/log.jl +++ b/src/kernelfunctions/negativedefinite/log.jl @@ -24,7 +24,7 @@ LogKernel{Float64}(0.5,0.5) struct LogKernel{T<:Real,A} <: NegativeDefiniteKernel{T} α::A γ::T - function LogKernel{T}(α::Union{T,AbstractVector{T}}=T(1), γ::T=T(1)) where {T<:Real} + function LogKernel{T}(α::Union{Real,AbstractVector{Real}}=T(1), γ::Real=T(1)) where {T<:Real} @check_args(LogKernel, α, count(α .<= zero(T))==0, "α > 0") @check_args(LogKernel, γ, one(T) >= γ > zero(T), "γ ∈ (0,1]") return new{T,typeof(α)}(α.^(-γ), γ) @@ -38,6 +38,6 @@ end @inline kappa(κ::LogKernel{T}, d²::T) where {T} = log(one(T) + d²^(κ.γ)) -function convert(::Type{K}, κ::LogKernel) where {K>:LogKernel{T}} where T - return LogKernel{T}(κ.α, κ.γ) +function convert(::Type{K}, κ::LogKernel) where {K>:LogKernel{T,A} where A} where T + return LogKernel{T}(T.(κ.α.^(κ.γ)), T.(κ.γ)) end diff --git a/src/kernelfunctions/negativedefinite/power.jl b/src/kernelfunctions/negativedefinite/power.jl index 8de22e0..a960323 100644 --- a/src/kernelfunctions/negativedefinite/power.jl +++ b/src/kernelfunctions/negativedefinite/power.jl @@ -17,11 +17,12 @@ julia> PowerKernel(0.5f0) PowerKernel{Float32}(0.5) ``` """ -struct PowerKernel{T<:Real} <: NegativeDefiniteKernel{T} +struct PowerKernel{T<:Real,A} <: NegativeDefiniteKernel{T} γ::T + α::A function PowerKernel{T}(γ::Real=T(1)) where {T<:Real} @check_args(PowerKernel, γ, one(T) >= γ > zero(T), "γ ∈ (0,1]") - new{T}(γ) + new{T,T}(γ,one(T)) end end PowerKernel(γ::T=1.0) where {T<:Real} = PowerKernel{promote_float(T)}(γ) @@ -30,6 +31,6 @@ PowerKernel(γ::T=1.0) where {T<:Real} = PowerKernel{promote_float(T)}(γ) @inline kappa(κ::PowerKernel{T}, d²::T) where {T} = d²^κ.γ -function convert(::Type{K}, κ::PowerKernel) where {K>:PowerKernel{T}} where T - return PowerKernel{T}(κ.γ) +function convert(::Type{K}, κ::PowerKernel) where {K>:PowerKernel{T,A} where A} where T + return PowerKernel{T}(T(κ.γ)) end diff --git a/src/kernelfunctions/sigmoid.jl b/src/kernelfunctions/sigmoid.jl index 1283fee..2ec4812 100644 --- a/src/kernelfunctions/sigmoid.jl +++ b/src/kernelfunctions/sigmoid.jl @@ -20,9 +20,9 @@ SigmoidKernel{Float64}(0.5,0.5) ``` """ struct SigmoidKernel{T<:Real,A} <: Kernel{T} - a::A + α::A c::T - function SigmoidKernel{T}(a::Union{T,AbstractVector{T}}=T(1), c::T=T(1)) where {T<:Real} + function SigmoidKernel{T}(a::Union{Real,AbstractVector{Real}}=T(1), c::Real=T(1)) where {T<:Real} @check_args(SigmoidKernel, a, count(a .<= zero(T))==0, "a > 0") @check_args(SigmoidKernel, c, c >= zero(T), "c ≧ 0") return new{T,typeof(a)}(a, c) @@ -34,6 +34,6 @@ SigmoidKernel(a::Union{T₁,AbstractVector{T₁}}=1.0, c::T₂=T₁(1)) where {T @inline kappa(κ::SigmoidKernel{T}, xᵀy::T) where {T} = tanh(xᵀy + κ.c) -function convert(::Type{K}, κ::SigmoidKernel) where {K>:SigmoidKernel{T}} where T - return SigmoidKernel{T}(κ.a, κ.c) +function convert(::Type{K}, κ::SigmoidKernel) where {K>:SigmoidKernel{T,A} where A} where T + return SigmoidKernel{T}(T.(κ.α), T(κ.c)) end diff --git a/test/kernelfunctions.jl b/test/kernelfunctions.jl index 8a95b2a..b3ef4fe 100644 --- a/test/kernelfunctions.jl +++ b/test/kernelfunctions.jl @@ -12,9 +12,10 @@ function test_kernel_function(k) for T in FloatingPointTypes, i = 1:n K = (k)([T(a) for a in alt_args[1:i]]...) - for j = 1:n - @test getfield(K,j) == (j <= i ? alt_args[j] : default_args[j]) - end + # Temporarily commented out since transformation of arguments (maybe duplicate the arguments?) + # for j = 1:n + # @test getfield(K,j) == (j <= i ? alt_args[j] : default_args[j]) + # end @test eltype(K) == T end end @@ -64,4 +65,4 @@ for k in kernel_functions @testset "Testing $k" begin test_kernel_function(k) end -end \ No newline at end of file +end diff --git a/test/kernelmatrix.jl b/test/kernelmatrix.jl index 3c2df08..09809c5 100644 --- a/test/kernelmatrix.jl +++ b/test/kernelmatrix.jl @@ -6,6 +6,7 @@ p = 5 for T in (Float32, Float64) x = rand(T,p) y = rand(T,p) + scale = one(T) x_alt = rand(T == Float32 ? Float64 : Float32, p) @@ -13,8 +14,8 @@ p = 5 P = (get(kernel_functions_base, f, SquaredEuclidean))() F = convert(f{T}, (f)()) - @test isapprox(MLK.kernel(F, x[1], y[1]), MLK.kappa(F, MLK.base_evaluate(P, x[1], y[1]))) - @test isapprox(MLK.kernel(F, x, y), MLK.kappa(F, MLK.base_evaluate(P, x, y))) + @test isapprox(MLK.kernel(F, x[1], y[1]), MLK.kappa(F, MLK.base_evaluate(P, scale, x[1], y[1]))) + @test isapprox(MLK.kernel(F, x, y), MLK.kappa(F, MLK.base_evaluate(P, scale, x, y))) z = MLK.kernel(F, x_alt[1], y[1]) @test typeof(z) == T diff --git a/test/runtests.jl b/test/runtests.jl index 7062cc4..04da2fe 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -44,4 +44,4 @@ end @testset "Testing nystrom" begin include("nystrom.jl") -end \ No newline at end of file +end From 0ce0df54c85fb4fe4bba615319aacb545a12e38a Mon Sep 17 00:00:00 2001 From: Theo GF Date: Fri, 11 Jan 2019 18:55:50 +0100 Subject: [PATCH 4/5] Fixed constructor for ARD, but convert has still some issues --- src/kernelfunctions/mercer/exponential.jl | 10 +++++----- src/kernelfunctions/mercer/exponentiated.jl | 2 +- src/kernelfunctions/mercer/matern.jl | 2 +- src/kernelfunctions/mercer/polynomial.jl | 2 +- src/kernelfunctions/mercer/rationalquadratic.jl | 4 ++-- src/kernelfunctions/negativedefinite/log.jl | 2 +- src/kernelfunctions/sigmoid.jl | 2 +- src/utils.jl | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/kernelfunctions/mercer/exponential.jl b/src/kernelfunctions/mercer/exponential.jl index 5fcc52f..8546601 100644 --- a/src/kernelfunctions/mercer/exponential.jl +++ b/src/kernelfunctions/mercer/exponential.jl @@ -30,7 +30,7 @@ ExponentialKernel{Float32}(2.0) """ struct ExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} α::A - function ExponentialKernel{T}(α::Union{Real,AbstractVector{Real}}=T(1)) where {T<:Real} + function ExponentialKernel{T}(α::Union{Real,AbstractVector{<:Real}}=T(1)) where {T<:Real} @check_args(ExponentialKernel, α, count(α .<= zero(T)) == 0, "α > 0") return new{T,typeof(α)}(α.^2) end @@ -77,15 +77,15 @@ SquaredExponentialKernel{Float32}(2.0) """ struct SquaredExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} α::A - function SquaredExponentialKernel{T}(α::Union{Real,AbstractVector{Real}}=T(1)) where {T<:Real} + function SquaredExponentialKernel{T}(α::Union{Real,AbstractVector{<:Real}}=T(1)) where {T<:Real} @check_args(SquaredExponentialKernel, α, count(α .<= zero(T))==0, "α > 0") return new{T,typeof(α)}(α) end end function SquaredExponentialKernel(α::Union{T,AbstractVector{T}}=1.0) where {T<:Real} - SquaredExponentialKernel{T}(α) - # SquaredExponentialKernel{promote_float(T)}(α) + # SquaredExponentialKernel{T}(α) + SquaredExponentialKernel{promote_float(T)}(α) end @inline kappa(κ::SquaredExponentialKernel{T}, d²::T) where {T} = exp(-d²) @@ -141,7 +141,7 @@ GammaExponentialKernel{Float64}(2.0,0.5) struct GammaExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} α::A γ::T - function GammaExponentialKernel{T}(α::Union{Real,AbstractVector{Real}}=T(1), γ::Real=T(1)) where {T<:Real} + function GammaExponentialKernel{T}(α::Union{Real,AbstractVector{<:Real}}=T(1), γ::Real=T(1)) where {T<:Real} @check_args(GammaExponentialKernel, α, count(α .<= zero(T))==0, "α > 0") @check_args(GammaExponentialKernel, γ, one(T) >= γ > zero(T), "γ ∈ (0,1]") return new{T,typeof(α)}(α.^(-γ), γ) diff --git a/src/kernelfunctions/mercer/exponentiated.jl b/src/kernelfunctions/mercer/exponentiated.jl index 3904609..e93fb18 100644 --- a/src/kernelfunctions/mercer/exponentiated.jl +++ b/src/kernelfunctions/mercer/exponentiated.jl @@ -23,7 +23,7 @@ ExponentiatedKernel{Float32}(2.0) """ struct ExponentiatedKernel{T<:Real,A} <: MercerKernel{T} α::A - function ExponentiatedKernel{T}(α::Union{Real,AbstractVector{Real}}=1.0) where {T<:Real} + function ExponentiatedKernel{T}(α::Union{Real,AbstractVector{<:Real}}=1.0) where {T<:Real} @check_args(ExponentiatedKernel, α, count(α .<= zero(T))==0, "α > 0") return new{T,typeof(α)}(α) end diff --git a/src/kernelfunctions/mercer/matern.jl b/src/kernelfunctions/mercer/matern.jl index 89235e9..b018073 100644 --- a/src/kernelfunctions/mercer/matern.jl +++ b/src/kernelfunctions/mercer/matern.jl @@ -20,7 +20,7 @@ MaternKernel{Float64}(2.0,2.0) struct MaternKernel{T<:Real,A} <: MercerKernel{T} ν::T α::A - function MaternKernel{T}(ν::Real=T(1), ρ::Union{Real,AbstractVector{Real}}=T(1)) where {T<:Real} + function MaternKernel{T}(ν::Real=T(1), ρ::Union{Real,AbstractVector{<:Real}}=T(1)) where {T<:Real} @check_args(MaternKernel, ν, ν > zero(T), "ν > 0") @check_args(MaternKernel, ρ, count(ρ .<= zero(T)) == 0, "ρ > 0") return new{T,typeof(ρ)}(ν, 1.0./ρ.^2) diff --git a/src/kernelfunctions/mercer/polynomial.jl b/src/kernelfunctions/mercer/polynomial.jl index f7a5201..ccc6317 100644 --- a/src/kernelfunctions/mercer/polynomial.jl +++ b/src/kernelfunctions/mercer/polynomial.jl @@ -25,7 +25,7 @@ struct PolynomialKernel{T<:Real,A} <: MercerKernel{T} c::T d::T function PolynomialKernel{T}( - a::Union{Real,AbstractVector{Real}}=T(1), + a::Union{Real,AbstractVector{<:Real}}=T(1), c::Real=T(1), d::Real=T(3) ) where {T<:Real} diff --git a/src/kernelfunctions/mercer/rationalquadratic.jl b/src/kernelfunctions/mercer/rationalquadratic.jl index 1256a9b..9d6ed58 100644 --- a/src/kernelfunctions/mercer/rationalquadratic.jl +++ b/src/kernelfunctions/mercer/rationalquadratic.jl @@ -34,7 +34,7 @@ struct RationalQuadraticKernel{T<:Real,A} <: AbstractRationalQuadraticKernel{T} α::A β::T function RationalQuadraticKernel{T}( - α::Union{Real,AbstractVector{Real}}=T(1), + α::Union{Real,AbstractVector{<:Real}}=T(1), β::Real=T(1) ) where {T<:Real} @check_args(RationalQuadraticKernel, α, count(α .<= zero(T))==0, "α > 0") @@ -95,7 +95,7 @@ struct GammaRationalQuadraticKernel{T<:Real,A} <: AbstractRationalQuadraticKerne β::T γ::T function GammaRationalQuadraticKernel{T}( - α::Union{Real,AbstractVector{Real}}=T(1), + α::Union{Real,AbstractVector{<:Real}}=T(1), β::Real=T(1), γ::Real=T(1) ) where {T<:Real} diff --git a/src/kernelfunctions/negativedefinite/log.jl b/src/kernelfunctions/negativedefinite/log.jl index bc5a11d..d2f189f 100644 --- a/src/kernelfunctions/negativedefinite/log.jl +++ b/src/kernelfunctions/negativedefinite/log.jl @@ -24,7 +24,7 @@ LogKernel{Float64}(0.5,0.5) struct LogKernel{T<:Real,A} <: NegativeDefiniteKernel{T} α::A γ::T - function LogKernel{T}(α::Union{Real,AbstractVector{Real}}=T(1), γ::Real=T(1)) where {T<:Real} + function LogKernel{T}(α::Union{Real,AbstractVector{<:Real}}=T(1), γ::Real=T(1)) where {T<:Real} @check_args(LogKernel, α, count(α .<= zero(T))==0, "α > 0") @check_args(LogKernel, γ, one(T) >= γ > zero(T), "γ ∈ (0,1]") return new{T,typeof(α)}(α.^(-γ), γ) diff --git a/src/kernelfunctions/sigmoid.jl b/src/kernelfunctions/sigmoid.jl index 2ec4812..2446498 100644 --- a/src/kernelfunctions/sigmoid.jl +++ b/src/kernelfunctions/sigmoid.jl @@ -22,7 +22,7 @@ SigmoidKernel{Float64}(0.5,0.5) struct SigmoidKernel{T<:Real,A} <: Kernel{T} α::A c::T - function SigmoidKernel{T}(a::Union{Real,AbstractVector{Real}}=T(1), c::Real=T(1)) where {T<:Real} + function SigmoidKernel{T}(a::Union{Real,AbstractVector{<:Real}}=T(1), c::Real=T(1)) where {T<:Real} @check_args(SigmoidKernel, a, count(a .<= zero(T))==0, "a > 0") @check_args(SigmoidKernel, c, c >= zero(T), "c ≧ 0") return new{T,typeof(a)}(a, c) diff --git a/src/utils.jl b/src/utils.jl index 7df545c..2e563f6 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -29,7 +29,7 @@ function promote_float(Tₖ::DataType...) return Float64 end T = promote_type(Tₖ...) - return T <: AbstractFloat ? T : Float64 + return T <: Real ? T : Float64 end From ad07d19fa9f077aa47919f4a7c39424562f67c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Wed, 17 Apr 2019 14:51:56 +0200 Subject: [PATCH 5/5] Test for AD --- src/kernelfunctions/mercer/exponential.jl | 4 +-- test/AD_tests.jl | 32 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 test/AD_tests.jl diff --git a/src/kernelfunctions/mercer/exponential.jl b/src/kernelfunctions/mercer/exponential.jl index 8546601..30d01d0 100644 --- a/src/kernelfunctions/mercer/exponential.jl +++ b/src/kernelfunctions/mercer/exponential.jl @@ -78,7 +78,7 @@ SquaredExponentialKernel{Float32}(2.0) struct SquaredExponentialKernel{T<:Real,A} <: AbstractExponentialKernel{T} α::A function SquaredExponentialKernel{T}(α::Union{Real,AbstractVector{<:Real}}=T(1)) where {T<:Real} - @check_args(SquaredExponentialKernel, α, count(α .<= zero(T))==0, "α > 0") + @check_args(SquaredExponentialKernel, α, all(α .> zero(T)), "α > 0") return new{T,typeof(α)}(α) end end @@ -93,7 +93,7 @@ end function convert( ::Type{K}, κ::SquaredExponentialKernel - ) where {K>:SquaredExponentialKernel{T,A} where A} where T + ) where {K>:SquaredExponentialKernel{T,A} where {T,A}} return SquaredExponentialKernel{T}(T.(κ.α)) end diff --git a/test/AD_tests.jl b/test/AD_tests.jl new file mode 100644 index 0000000..d320c86 --- /dev/null +++ b/test/AD_tests.jl @@ -0,0 +1,32 @@ +using Zygote +using ForwardDiff +using Flux.Tracker +using BenchmarkTools +using LinearAlgebra +using MLKernels + +l = 0.5 +X = rand(10,2) +Y = rand(100,2) +function approxK(l) + k = SquaredExponentialKernel(l) + Kx = kernelmatrix(k,X) + Ky = kernelmatrix(k,Y) + Kxy = kernelmatrix(k,X,Y) + tr(Ky-Kxy'*inv(Kx)*Kxy) +end + +approxK([l,l+0.5]) +## Testing +# Zygote.gradient(trK,l) +# Zygote not working because of copytru + +ForwardDiff.gradient(approxK,[l,l+0.5]) +# Works nicely with everything +Tracker.data(Tracker.gradient(approxK,[l,l+0.5])) +# Only works for iso kernels + +##Performance +# @btime Zygote.gradient(trK,l) +@btime ForwardDiff.gradient(approxK,[$l,$l+0.5]); +@btime Tracker.data(Tracker.gradient(approxK,[$l,$l+0.5]))[1];