Skip to content

Commit

Permalink
fixed pairwise for non-symmetric kernels (fixed #143)
Browse files Browse the repository at this point in the history
  • Loading branch information
wildart committed Mar 14, 2021
1 parent febc53f commit a405c5d
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 12 deletions.
17 changes: 9 additions & 8 deletions src/common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -122,29 +122,30 @@ end

# calculate pairwise kernel
function pairwise!(K::AbstractVecOrMat{<:Real}, kernel::Function,
X::AbstractVecOrMat{<:Real}, Y::AbstractVecOrMat{<:Real})
X::AbstractVecOrMat{<:Real}, Y::AbstractVecOrMat{<:Real};
force_symmetry=false)
n = size(X, 2)
m = size(Y, 2)
for j = 1:m
aj = view(Y, :, j)
for i in j:n
for i in (force_symmetry ? j : 1):n
@inbounds K[i, j] = kernel(view(X, :, i), aj)[]
end
j <= n && for i in 1:(j - 1)
force_symmetry && j <= n && for i in 1:(j - 1)
@inbounds K[i, j] = K[j, i] # leveraging the symmetry
end
end
K
end

pairwise!(K::AbstractVecOrMat{<:Real}, kernel::Function, X::AbstractVecOrMat{<:Real}) =
pairwise!(K, kernel, X, X)
pairwise!(K::AbstractVecOrMat{<:Real}, kernel::Function, X::AbstractVecOrMat{<:Real}; kwargs...) =
pairwise!(K, kernel, X, X; force_symmetry=true)

function pairwise(kernel::Function, X::AbstractVecOrMat{<:Real}, Y::AbstractVecOrMat{<:Real})
function pairwise(kernel::Function, X::AbstractVecOrMat{<:Real}, Y::AbstractVecOrMat{<:Real}; kwargs...)
n = size(X, 2)
m = size(Y, 2)
K = similar(X, n, m)
pairwise!(K, kernel, X, Y)
pairwise!(K, kernel, X, Y; kwargs...)
end

pairwise(kernel::Function, X::AbstractVecOrMat{<:Real}) = pairwise(kernel, X, X)
pairwise(kernel::Function, X::AbstractVecOrMat{<:Real}) = pairwise(kernel, X, X; force_symmetry=true)
19 changes: 15 additions & 4 deletions test/kpca.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,29 @@ import Random
end

# kernel calculations
K = MultivariateStats.pairwise((x,y)->norm(x-y), X, X[:,1:2])
ker1 = (x,y)->x'y
ker2 = (x,y)->norm(x-y)

K = MultivariateStats.pairwise(ker1, X)
@test size(K) == (n,n)
@test K[1,2] == K[2,1]

K = MultivariateStats.pairwise(ker1, X, X.+1)
@test size(K) == (n,n)
@test K[1,2] != K[2,1]

K = MultivariateStats.pairwise(ker2, X, X[:,1:2])
@test size(K) == (n, 2)
@test K[1,1] == 0
@test K[3,2] == norm(X[:,3] - X[:,2])

K = MultivariateStats.pairwise((x,y)->norm(x-y), X[:,1:3], X)
K = MultivariateStats.pairwise(ker2, X[:,1:3], X)
@test size(K) == (3, n)
@test K[1,1] == 0
@test K[3,2] == norm(X[:,2] - X[:,3])

K = similar(X, n, n)
MultivariateStats.pairwise!(K, (x,y)->norm(x-y), X)
MultivariateStats.pairwise!(K, ker2, X)
@test size(K) == (n, n)
@test K[1,1] == 0
@test K[2,1] == norm(X[:,2] - X[:,1])
Expand All @@ -54,7 +65,7 @@ import Random
Iₙ = ones(n,n)/n
@test MultivariateStats.transform!(KC, copy(K)) K - Iₙ*K - K*Iₙ + Iₙ*K*Iₙ

K = MultivariateStats.pairwise((x,y)->norm(x-y), X, X[:,1])
K = MultivariateStats.pairwise(ker2, X, X[:,1])
@test size(K) == (n, 1)
@test K[1,1] == 0
@test K[2,1] == norm(X[:,2] - X[:,1])
Expand Down

0 comments on commit a405c5d

Please sign in to comment.