Skip to content

Commit 5c1d5fb

Browse files
committed
added definitions for lp-distances. Faster than just using norm
1 parent 8cc4216 commit 5c1d5fb

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

src/generic.jl

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,87 @@ opnorm(v::TransposeAbsVec) = norm(v.parent)
892892

893893
norm(v::AdjOrTrans, p::Real) = norm(v.parent, p)
894894

895+
"""
896+
lpdist(x::T, y::T, p::Int) where {T <: AbstractVector}
897+
lpdist(x::T, y::T, p::Real) where {T <: AbstractVector}
898+
899+
Computes the Lₚ distance between two vectors `x` and `y`, defined as:
900+
for 0 < p < Inf: Lₚ dist = ᵖ√(Σ|xᵢ - yᵢ|ᵖ)
901+
for p = 0: count of mismatches for p = 0
902+
for p + Inf: L_∞ = maxᵢ(abs(xᵢ - yᵢ))
903+
"""
904+
905+
function _lpunnorm(x::T, y::T, fn) where {T}
906+
r = 0.0
907+
for i in eachindex(x,y)
908+
@inbounds r += fn(x[i] - y[i])
909+
end
910+
end
911+
912+
913+
function lpdist(x::T, y::T, p::Int) where {T <: AbstractVector}
914+
p < 0 && throw(DomainError("p must be non-negative"))
915+
length(x) == length(y) || throw(DimensionMismatch("x and y have different lenghts"))
916+
if p == 0
917+
@warn("Technically not a distance metric for p = 0")
918+
fn = !iszero # simply count number of nonzeros
919+
elseif p == 1
920+
fn = abs
921+
elseif p == 2
922+
fn = abs2
923+
else
924+
fn = x -> abs(u)^p
925+
end
926+
r = _lpunnorm(x, y, fn)
927+
928+
p <= 1 && return r
929+
p == 2 && return r
930+
931+
return r^(1/p)
932+
end
933+
934+
function lpdist(x::T, y::T, p::Real) where {T <: AbstractVector}
935+
length(x) == length(y) || throw(DimensionMismatch("x and y have different lenghts"))
936+
p < 0 && throw(DomainError("p must be non-negative"))
937+
p < 1 || @warn("Technically not a distance metric for 0 < p < 1")
938+
939+
# handle inf norm separatey
940+
if p == Inf
941+
r = 0.0
942+
for i in eachindex(x,y)
943+
@inbounds r = max(x[i] - y[i], r)
944+
end
945+
return r
946+
elseif iszero(p)
947+
return lpdist(x, y, 0)
948+
else
949+
fn = u -> abs(u)^p
950+
end
951+
r = _lpunnorm(x, y, fn)
952+
953+
return r^(1/p)
954+
end
955+
956+
"""
957+
euclidean(x::T, y::T)
958+
l2dist(x::T, y::T)
959+
960+
Compute the L₂ distance between vectors x and y.
961+
Basically just aliases for lpdist(x, y, 2)
962+
"""
963+
euclidean(x::T, y::T) where {T <: AbstractVector} = lpdist(x, y, 2)
964+
l2dist(x::T, y::T) where {T <: AbstractVector} = lpdist(x, y, 2)
965+
966+
"""
967+
l1dist(x::T, y::T)
968+
969+
Compute the L₁ distance between vectors x and y.
970+
Basically just an alias for lpdist(x, y, 1)
971+
"""
972+
l1dist(x::T, y::T) where {T <: AbstractVector} = lpdist(x, y, 1)
973+
974+
975+
## dot products
895976
"""
896977
dot(x, y)
897978
x ⋅ y

0 commit comments

Comments
 (0)