From 1fdc3d2230ee0c620bd563f3f1629cbdc585f14f Mon Sep 17 00:00:00 2001 From: Luca Brivio Date: Thu, 19 Oct 2017 20:21:47 +0200 Subject: [PATCH] Add pairwise distance computation in condensed form for symmetrical metrics. --- README.md | 11 +++++++++-- src/Distances.jl | 1 + src/generic.jl | 22 ++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 40be705..295976a 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,13 @@ R = pairwise(dist, X) ``` This statement will result in an ``m-by-m`` matrix, where ``R[i,j]`` is the distance between ``X[:,i]`` and ``X[:,j]``. -``pairwise(dist, X)`` is typically more efficient than ``pairwise(dist, X, X)``, as the former will take advantage of the symmetry when ``dist`` is a semi-metric (including metric). +``pairwise(dist, X)`` is typically more efficient than ``pairwise(dist, X, X)``, as the former will take advantage of the symmetry when ``dist`` is a semi-metric (including metric). You can also compute symmetric distances in a condensed vector representation: + +```julia +r = cond_pairwise(dist, X) +``` + +This will return a vector ``r`` of length ``n * (n - 1) / 2``, containing the corresponding matrix elements arranged in the order ``(2,1), (3,1), ..., (m,1), (3,2), ..., (m,2), ..., (m,m–1)``. #### Computing column-wise and pairwise distances inplace @@ -103,9 +109,10 @@ If the vector/matrix to store the results are pre-allocated, you may use the sto colwise!(r, dist, X, Y) pairwise!(R, dist, X, Y) pairwise!(R, dist, X) +pairwise!(r, dist, X) ``` -Please pay attention to the difference, the functions for inplace computation are ``colwise!`` and ``pairwise!`` (instead of ``colwise`` and ``pairwise``). +Please pay attention to the difference, the functions for inplace computation are ``colwise!`` and ``pairwise!`` (instead of ``colwise`` and ``pairwise``/``cond_pairwise``). ## Distance type hierarchy diff --git a/src/Distances.jl b/src/Distances.jl index f949b73..0672cf0 100644 --- a/src/Distances.jl +++ b/src/Distances.jl @@ -12,6 +12,7 @@ export result_type, colwise, pairwise, + cond_pairwise, colwise!, pairwise!, evaluate, diff --git a/src/generic.jl b/src/generic.jl index 20fbd66..a78064f 100644 --- a/src/generic.jl +++ b/src/generic.jl @@ -126,3 +126,25 @@ function pairwise(metric::PreMetric, a::AbstractMatrix) r = Matrix{result_type(metric, a, a)}(n, n) pairwise!(r, metric, a) end + +# Generic pairwise evaluation to a condensed form, for symmetrical distances + +function pairwise!(r::AbstractVector, metric::SemiMetric, a::AbstractMatrix) + n = size(a, 2) + length(r) == div((n * (n - 1)), 2) || throw(DimensionMismatch("Incorrect size of r.")) + k = 1 + for j = 1:n + aj = view(a, :, j) + for i = (j + 1):n + @inbounds r[k] = evaluate(metric, view(a, :, i), aj) + k += 1 + end + end + r +end + +function cond_pairwise(metric::SemiMetric, a::AbstractMatrix) + n = size(a, 2) + r = Vector{result_type(metric, a, a)}(div(n * (n - 1), 2)) + pairwise!(r, metric, a) +end