Skip to content

Commit a405c5d

Browse files
committed
fixed pairwise for non-symmetric kernels (fixed #143)
1 parent febc53f commit a405c5d

File tree

2 files changed

+24
-12
lines changed

2 files changed

+24
-12
lines changed

src/common.jl

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,29 +122,30 @@ end
122122

123123
# calculate pairwise kernel
124124
function pairwise!(K::AbstractVecOrMat{<:Real}, kernel::Function,
125-
X::AbstractVecOrMat{<:Real}, Y::AbstractVecOrMat{<:Real})
125+
X::AbstractVecOrMat{<:Real}, Y::AbstractVecOrMat{<:Real};
126+
force_symmetry=false)
126127
n = size(X, 2)
127128
m = size(Y, 2)
128129
for j = 1:m
129130
aj = view(Y, :, j)
130-
for i in j:n
131+
for i in (force_symmetry ? j : 1):n
131132
@inbounds K[i, j] = kernel(view(X, :, i), aj)[]
132133
end
133-
j <= n && for i in 1:(j - 1)
134+
force_symmetry && j <= n && for i in 1:(j - 1)
134135
@inbounds K[i, j] = K[j, i] # leveraging the symmetry
135136
end
136137
end
137138
K
138139
end
139140

140-
pairwise!(K::AbstractVecOrMat{<:Real}, kernel::Function, X::AbstractVecOrMat{<:Real}) =
141-
pairwise!(K, kernel, X, X)
141+
pairwise!(K::AbstractVecOrMat{<:Real}, kernel::Function, X::AbstractVecOrMat{<:Real}; kwargs...) =
142+
pairwise!(K, kernel, X, X; force_symmetry=true)
142143

143-
function pairwise(kernel::Function, X::AbstractVecOrMat{<:Real}, Y::AbstractVecOrMat{<:Real})
144+
function pairwise(kernel::Function, X::AbstractVecOrMat{<:Real}, Y::AbstractVecOrMat{<:Real}; kwargs...)
144145
n = size(X, 2)
145146
m = size(Y, 2)
146147
K = similar(X, n, m)
147-
pairwise!(K, kernel, X, Y)
148+
pairwise!(K, kernel, X, Y; kwargs...)
148149
end
149150

150-
pairwise(kernel::Function, X::AbstractVecOrMat{<:Real}) = pairwise(kernel, X, X)
151+
pairwise(kernel::Function, X::AbstractVecOrMat{<:Real}) = pairwise(kernel, X, X; force_symmetry=true)

test/kpca.jl

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,29 @@ import Random
3434
end
3535

3636
# kernel calculations
37-
K = MultivariateStats.pairwise((x,y)->norm(x-y), X, X[:,1:2])
37+
ker1 = (x,y)->x'y
38+
ker2 = (x,y)->norm(x-y)
39+
40+
K = MultivariateStats.pairwise(ker1, X)
41+
@test size(K) == (n,n)
42+
@test K[1,2] == K[2,1]
43+
44+
K = MultivariateStats.pairwise(ker1, X, X.+1)
45+
@test size(K) == (n,n)
46+
@test K[1,2] != K[2,1]
47+
48+
K = MultivariateStats.pairwise(ker2, X, X[:,1:2])
3849
@test size(K) == (n, 2)
3950
@test K[1,1] == 0
4051
@test K[3,2] == norm(X[:,3] - X[:,2])
4152

42-
K = MultivariateStats.pairwise((x,y)->norm(x-y), X[:,1:3], X)
53+
K = MultivariateStats.pairwise(ker2, X[:,1:3], X)
4354
@test size(K) == (3, n)
4455
@test K[1,1] == 0
4556
@test K[3,2] == norm(X[:,2] - X[:,3])
4657

4758
K = similar(X, n, n)
48-
MultivariateStats.pairwise!(K, (x,y)->norm(x-y), X)
59+
MultivariateStats.pairwise!(K, ker2, X)
4960
@test size(K) == (n, n)
5061
@test K[1,1] == 0
5162
@test K[2,1] == norm(X[:,2] - X[:,1])
@@ -54,7 +65,7 @@ import Random
5465
Iₙ = ones(n,n)/n
5566
@test MultivariateStats.transform!(KC, copy(K)) K - Iₙ*K - K*Iₙ + Iₙ*K*Iₙ
5667

57-
K = MultivariateStats.pairwise((x,y)->norm(x-y), X, X[:,1])
68+
K = MultivariateStats.pairwise(ker2, X, X[:,1])
5869
@test size(K) == (n, 1)
5970
@test K[1,1] == 0
6071
@test K[2,1] == norm(X[:,2] - X[:,1])

0 commit comments

Comments
 (0)