From 000fbf5cf9532af926d7a507bb2282b1e08533e2 Mon Sep 17 00:00:00 2001 From: Elias Carvalho Date: Wed, 9 Oct 2024 16:10:31 -0300 Subject: [PATCH 1/9] Add 'MinkowskiMetric' abstract type --- README.md | 10 ++++++++-- src/generic.jl | 7 +++++++ src/metrics.jl | 19 +++++++++++-------- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6123e77..0b87e4d 100644 --- a/README.md +++ b/README.md @@ -165,14 +165,20 @@ At the top of this hierarchy is an abstract class **PreMetric**, which is define d(x, x) == 0 for all x d(x, y) >= 0 for all x, y -**SemiMetric** is a abstract type that refines **PreMetric**. Formally, a *semi-metric* is a *pre-metric* that is also symmetric, as +**SemiMetric** is an abstract type that refines **PreMetric**. Formally, a *semi-metric* is a *pre-metric* that is also symmetric, as d(x, y) == d(y, x) for all x, y -**Metric** is a abstract type that further refines **SemiMetric**. Formally, a *metric* is a *semi-metric* that also satisfies triangle inequality, as +**Metric** is an abstract type that further refines **SemiMetric**. Formally, a *metric* is a *semi-metric* that also satisfies triangle inequality, as d(x, z) <= d(x, y) + d(y, z) for all x, y, z +**MinkowskiMetric** is an abstract type that encompasses a family of metrics defined by the formula + + d(x, y) = sum((x - y) .^ p) ^ (1 / p) + +where the `p` parameter defines the metric. + This type system has practical significance. For example, when computing pairwise distances between a set of vectors, you may only perform computation for half of the pairs, derive the values immediately for the remaining half by leveraging the symmetry of *semi-metrics*. Note diff --git a/src/generic.jl b/src/generic.jl index 090bddb..293f6b5 100644 --- a/src/generic.jl +++ b/src/generic.jl @@ -21,6 +21,13 @@ abstract type SemiMetric <: PreMetric end # abstract type Metric <: SemiMetric end +# a minkowski metric is a metric that is defined by the formula: +# +# d(x, y) = sum((x - y) .^ p) ^ (1 / p) +# +# where the `p` parameter defines the metric. +abstract type MinkowskiMetric <: Metric end + evaluate(dist::PreMetric, a, b) = dist(a, b) # Generic functions diff --git a/src/metrics.jl b/src/metrics.jl index 8595e2a..bbc8a83 100644 --- a/src/metrics.jl +++ b/src/metrics.jl @@ -12,13 +12,15 @@ abstract type UnionSemiMetric <: SemiMetric end abstract type UnionMetric <: Metric end +abstract type UnionMinkowskiMetric <: MinkowskiMetric end + ########################################################### # # Metric types # ########################################################### -struct Euclidean <: UnionMetric +struct Euclidean <: UnionMinkowskiMetric thresh::Float64 end @@ -52,7 +54,7 @@ julia> pairwise(Euclidean(1e-12), x, x) """ Euclidean() = Euclidean(0) -struct WeightedEuclidean{W} <: UnionMetric +struct WeightedEuclidean{W} <: UnionMinkowskiMetric weights::W end @@ -94,10 +96,10 @@ struct WeightedSqEuclidean{W} <: UnionSemiMetric weights::W end -struct Chebyshev <: UnionMetric end +struct Chebyshev <: UnionMinkowskiMetric end -struct Cityblock <: UnionMetric end -struct WeightedCityblock{W} <: UnionMetric +struct Cityblock <: UnionMinkowskiMetric end +struct WeightedCityblock{W} <: UnionMinkowskiMetric weights::W end @@ -105,10 +107,10 @@ struct TotalVariation <: UnionMetric end struct Jaccard <: UnionMetric end struct RogersTanimoto <: UnionMetric end -struct Minkowski{T <: Real} <: UnionMetric +struct Minkowski{T <: Real} <: UnionMinkowskiMetric p::T end -struct WeightedMinkowski{W,T <: Real} <: UnionMetric +struct WeightedMinkowski{W,T <: Real} <: UnionMinkowskiMetric weights::W p::T end @@ -197,7 +199,7 @@ struct NormRMSDeviation <: PreMetric end # Union types const metrics = (Euclidean,SqEuclidean,PeriodicEuclidean,Chebyshev,Cityblock,TotalVariation,Minkowski,Hamming,Jaccard,RogersTanimoto,CosineDist,ChiSqDist,KLDivergence,RenyiDivergence,BrayCurtis,JSDivergence,SpanNormDist,GenKLDivergence) const weightedmetrics = (WeightedEuclidean,WeightedSqEuclidean,WeightedCityblock,WeightedMinkowski,WeightedHamming) -const UnionMetrics = Union{UnionPreMetric,UnionSemiMetric,UnionMetric} +const UnionMetrics = Union{UnionPreMetric,UnionSemiMetric,UnionMetric,UnionMinkowskiMetric} ########################################################### # @@ -208,6 +210,7 @@ const UnionMetrics = Union{UnionPreMetric,UnionSemiMetric,UnionMetric} parameters(::UnionPreMetric) = nothing parameters(::UnionSemiMetric) = nothing parameters(::UnionMetric) = nothing +parameters(::UnionMinkowskiMetric) = nothing parameters(d::PeriodicEuclidean) = d.periods for dist in weightedmetrics @eval parameters(d::$dist) = d.weights From c9587a198eec3b8022177800f6163c7b0b45bd42 Mon Sep 17 00:00:00 2001 From: Elias Carvalho Date: Thu, 17 Oct 2024 09:19:22 -0300 Subject: [PATCH 2/9] Apply suggestions --- src/generic.jl | 7 ------- src/metrics.jl | 24 ++++++++++++++---------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/generic.jl b/src/generic.jl index 293f6b5..090bddb 100644 --- a/src/generic.jl +++ b/src/generic.jl @@ -21,13 +21,6 @@ abstract type SemiMetric <: PreMetric end # abstract type Metric <: SemiMetric end -# a minkowski metric is a metric that is defined by the formula: -# -# d(x, y) = sum((x - y) .^ p) ^ (1 / p) -# -# where the `p` parameter defines the metric. -abstract type MinkowskiMetric <: Metric end - evaluate(dist::PreMetric, a, b) = dist(a, b) # Generic functions diff --git a/src/metrics.jl b/src/metrics.jl index bbc8a83..8d648ee 100644 --- a/src/metrics.jl +++ b/src/metrics.jl @@ -12,7 +12,12 @@ abstract type UnionSemiMetric <: SemiMetric end abstract type UnionMetric <: Metric end -abstract type UnionMinkowskiMetric <: MinkowskiMetric end +# a minkowski metric is a metric that is defined by the formula: +# +# d(x, y) = sum((x - y) .^ p) ^ (1 / p) +# +# where the `p` parameter defines the metric. +abstract type MinkowskiMetric <: UnionMetric end ########################################################### # @@ -20,7 +25,7 @@ abstract type UnionMinkowskiMetric <: MinkowskiMetric end # ########################################################### -struct Euclidean <: UnionMinkowskiMetric +struct Euclidean <: MinkowskiMetric thresh::Float64 end @@ -54,7 +59,7 @@ julia> pairwise(Euclidean(1e-12), x, x) """ Euclidean() = Euclidean(0) -struct WeightedEuclidean{W} <: UnionMinkowskiMetric +struct WeightedEuclidean{W} <: MinkowskiMetric weights::W end @@ -96,10 +101,10 @@ struct WeightedSqEuclidean{W} <: UnionSemiMetric weights::W end -struct Chebyshev <: UnionMinkowskiMetric end +struct Chebyshev <: MinkowskiMetric end -struct Cityblock <: UnionMinkowskiMetric end -struct WeightedCityblock{W} <: UnionMinkowskiMetric +struct Cityblock <: MinkowskiMetric end +struct WeightedCityblock{W} <: MinkowskiMetric weights::W end @@ -107,10 +112,10 @@ struct TotalVariation <: UnionMetric end struct Jaccard <: UnionMetric end struct RogersTanimoto <: UnionMetric end -struct Minkowski{T <: Real} <: UnionMinkowskiMetric +struct Minkowski{T <: Real} <: MinkowskiMetric p::T end -struct WeightedMinkowski{W,T <: Real} <: UnionMinkowskiMetric +struct WeightedMinkowski{W,T <: Real} <: MinkowskiMetric weights::W p::T end @@ -199,7 +204,7 @@ struct NormRMSDeviation <: PreMetric end # Union types const metrics = (Euclidean,SqEuclidean,PeriodicEuclidean,Chebyshev,Cityblock,TotalVariation,Minkowski,Hamming,Jaccard,RogersTanimoto,CosineDist,ChiSqDist,KLDivergence,RenyiDivergence,BrayCurtis,JSDivergence,SpanNormDist,GenKLDivergence) const weightedmetrics = (WeightedEuclidean,WeightedSqEuclidean,WeightedCityblock,WeightedMinkowski,WeightedHamming) -const UnionMetrics = Union{UnionPreMetric,UnionSemiMetric,UnionMetric,UnionMinkowskiMetric} +const UnionMetrics = Union{UnionPreMetric,UnionSemiMetric,UnionMetric} ########################################################### # @@ -210,7 +215,6 @@ const UnionMetrics = Union{UnionPreMetric,UnionSemiMetric,UnionMetric,UnionMinko parameters(::UnionPreMetric) = nothing parameters(::UnionSemiMetric) = nothing parameters(::UnionMetric) = nothing -parameters(::UnionMinkowskiMetric) = nothing parameters(d::PeriodicEuclidean) = d.periods for dist in weightedmetrics @eval parameters(d::$dist) = d.weights From b73f0bf1ac300497c77bdc485c981c079bbc5103 Mon Sep 17 00:00:00 2001 From: Elias Carvalho <73039601+eliascarv@users.noreply.github.com> Date: Thu, 17 Oct 2024 16:06:53 -0300 Subject: [PATCH 3/9] Update README.md Co-authored-by: Daniel Karrasch --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0b87e4d..5b2cf3d 100644 --- a/README.md +++ b/README.md @@ -175,9 +175,9 @@ At the top of this hierarchy is an abstract class **PreMetric**, which is define **MinkowskiMetric** is an abstract type that encompasses a family of metrics defined by the formula - d(x, y) = sum((x - y) .^ p) ^ (1 / p) + d(x, y) = sum(w .* (x - y) .^ p) ^ (1 / p) -where the `p` parameter defines the metric. +where the `p` parameter defines the metric and `w` is a potential weight vector (all 1's by default). This type system has practical significance. For example, when computing pairwise distances between a set of vectors, you may only perform computation for half of the pairs, derive the From 4415e2afd8460904a06a7ee87ca09bd3b7b14e2e Mon Sep 17 00:00:00 2001 From: Elias Carvalho Date: Thu, 17 Oct 2024 16:09:00 -0300 Subject: [PATCH 4/9] Update comment --- src/metrics.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/metrics.jl b/src/metrics.jl index 8d648ee..92300fc 100644 --- a/src/metrics.jl +++ b/src/metrics.jl @@ -14,9 +14,10 @@ abstract type UnionMetric <: Metric end # a minkowski metric is a metric that is defined by the formula: # -# d(x, y) = sum((x - y) .^ p) ^ (1 / p) +# d(x, y) = sum(w .* (x - y) .^ p) ^ (1 / p) # -# where the `p` parameter defines the metric. +# where the `p` parameter defines the metric +# and `w` is a potential weight vector (all 1's by default). abstract type MinkowskiMetric <: UnionMetric end ########################################################### From 39ea853b9eeed2cca38a072380bfb2a3102670b6 Mon Sep 17 00:00:00 2001 From: Elias Carvalho Date: Mon, 21 Oct 2024 13:46:47 -0300 Subject: [PATCH 5/9] Apply suggestions --- src/metrics.jl | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/metrics.jl b/src/metrics.jl index 92300fc..3b4be83 100644 --- a/src/metrics.jl +++ b/src/metrics.jl @@ -12,12 +12,27 @@ abstract type UnionSemiMetric <: SemiMetric end abstract type UnionMetric <: Metric end -# a minkowski metric is a metric that is defined by the formula: -# -# d(x, y) = sum(w .* (x - y) .^ p) ^ (1 / p) -# -# where the `p` parameter defines the metric -# and `w` is a potential weight vector (all 1's by default). +""" + MinkowskiMetric + +A Minkowski metric is a metric that is defined by the formula: + +`d(x, y) = sum(w .* (x - y) .^ p) ^ (1 / p)` + +where the `p` parameter defines the metric +and `w` is a potential weight vector (all 1's by default). + +Common Minkowski metrics: +* `Cityblock`/`WeightedCityblock`: Minkowski metric with `p=1`; +* `Euclidean`/`WeightedEuclidean`: Minkowski metric with `p=2`; +* `Chebyshev`: Limit of `d` as `p` approaches infinity; +* `Minkowski`/`WeightedMinkowski`: generic Minkowski metric for any `p`. + +## Notes +* The difference between `Minkowski`/`WeightedMinkowski` and `MinkowskiMetric` + is that while the first are generic Minkowski metrics, + the second is the parent type of these metrics. +""" abstract type MinkowskiMetric <: UnionMetric end ########################################################### From afb94e48e11ab48c4c01c380d815b08081d62807 Mon Sep 17 00:00:00 2001 From: Elias Carvalho Date: Tue, 22 Oct 2024 08:08:11 -0300 Subject: [PATCH 6/9] Apply suggestions --- src/generic.jl | 23 +++++++++++++++++++++++ src/metrics.jl | 40 ++++++++++------------------------------ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/generic.jl b/src/generic.jl index 090bddb..d3f186d 100644 --- a/src/generic.jl +++ b/src/generic.jl @@ -21,6 +21,29 @@ abstract type SemiMetric <: PreMetric end # abstract type Metric <: SemiMetric end +""" + MinkowskiMetric + +A Minkowski metric is a metric that is defined by the formula: + +`d(x, y) = sum(w .* (x - y) .^ p) ^ (1 / p)` + +where the `p` parameter defines the metric +and `w` is a potential weight vector (all 1's by default). + +Common Minkowski metrics: +* `Cityblock`/`WeightedCityblock`: Minkowski metric with `p=1`; +* `Euclidean`/`WeightedEuclidean`: Minkowski metric with `p=2`; +* `Chebyshev`: Limit of `d` as `p` approaches infinity; +* `Minkowski`/`WeightedMinkowski`: generic Minkowski metric for any `p`. + +## Notes +* The difference between `Minkowski`/`WeightedMinkowski` and `MinkowskiMetric` + is that while the first are generic Minkowski metrics, + the second is the parent type of these metrics. +""" +abstract type MinkowskiMetric <: Metric end + evaluate(dist::PreMetric, a, b) = dist(a, b) # Generic functions diff --git a/src/metrics.jl b/src/metrics.jl index 3b4be83..bbc8a83 100644 --- a/src/metrics.jl +++ b/src/metrics.jl @@ -12,28 +12,7 @@ abstract type UnionSemiMetric <: SemiMetric end abstract type UnionMetric <: Metric end -""" - MinkowskiMetric - -A Minkowski metric is a metric that is defined by the formula: - -`d(x, y) = sum(w .* (x - y) .^ p) ^ (1 / p)` - -where the `p` parameter defines the metric -and `w` is a potential weight vector (all 1's by default). - -Common Minkowski metrics: -* `Cityblock`/`WeightedCityblock`: Minkowski metric with `p=1`; -* `Euclidean`/`WeightedEuclidean`: Minkowski metric with `p=2`; -* `Chebyshev`: Limit of `d` as `p` approaches infinity; -* `Minkowski`/`WeightedMinkowski`: generic Minkowski metric for any `p`. - -## Notes -* The difference between `Minkowski`/`WeightedMinkowski` and `MinkowskiMetric` - is that while the first are generic Minkowski metrics, - the second is the parent type of these metrics. -""" -abstract type MinkowskiMetric <: UnionMetric end +abstract type UnionMinkowskiMetric <: MinkowskiMetric end ########################################################### # @@ -41,7 +20,7 @@ abstract type MinkowskiMetric <: UnionMetric end # ########################################################### -struct Euclidean <: MinkowskiMetric +struct Euclidean <: UnionMinkowskiMetric thresh::Float64 end @@ -75,7 +54,7 @@ julia> pairwise(Euclidean(1e-12), x, x) """ Euclidean() = Euclidean(0) -struct WeightedEuclidean{W} <: MinkowskiMetric +struct WeightedEuclidean{W} <: UnionMinkowskiMetric weights::W end @@ -117,10 +96,10 @@ struct WeightedSqEuclidean{W} <: UnionSemiMetric weights::W end -struct Chebyshev <: MinkowskiMetric end +struct Chebyshev <: UnionMinkowskiMetric end -struct Cityblock <: MinkowskiMetric end -struct WeightedCityblock{W} <: MinkowskiMetric +struct Cityblock <: UnionMinkowskiMetric end +struct WeightedCityblock{W} <: UnionMinkowskiMetric weights::W end @@ -128,10 +107,10 @@ struct TotalVariation <: UnionMetric end struct Jaccard <: UnionMetric end struct RogersTanimoto <: UnionMetric end -struct Minkowski{T <: Real} <: MinkowskiMetric +struct Minkowski{T <: Real} <: UnionMinkowskiMetric p::T end -struct WeightedMinkowski{W,T <: Real} <: MinkowskiMetric +struct WeightedMinkowski{W,T <: Real} <: UnionMinkowskiMetric weights::W p::T end @@ -220,7 +199,7 @@ struct NormRMSDeviation <: PreMetric end # Union types const metrics = (Euclidean,SqEuclidean,PeriodicEuclidean,Chebyshev,Cityblock,TotalVariation,Minkowski,Hamming,Jaccard,RogersTanimoto,CosineDist,ChiSqDist,KLDivergence,RenyiDivergence,BrayCurtis,JSDivergence,SpanNormDist,GenKLDivergence) const weightedmetrics = (WeightedEuclidean,WeightedSqEuclidean,WeightedCityblock,WeightedMinkowski,WeightedHamming) -const UnionMetrics = Union{UnionPreMetric,UnionSemiMetric,UnionMetric} +const UnionMetrics = Union{UnionPreMetric,UnionSemiMetric,UnionMetric,UnionMinkowskiMetric} ########################################################### # @@ -231,6 +210,7 @@ const UnionMetrics = Union{UnionPreMetric,UnionSemiMetric,UnionMetric} parameters(::UnionPreMetric) = nothing parameters(::UnionSemiMetric) = nothing parameters(::UnionMetric) = nothing +parameters(::UnionMinkowskiMetric) = nothing parameters(d::PeriodicEuclidean) = d.periods for dist in weightedmetrics @eval parameters(d::$dist) = d.weights From 2b7c189117493f707ac2b378d809e8639e702812 Mon Sep 17 00:00:00 2001 From: Elias Carvalho Date: Tue, 22 Oct 2024 08:15:10 -0300 Subject: [PATCH 7/9] Bump version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 405b8c7..3dc80fd 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "Distances" uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" -version = "0.10.11" +version = "0.10.12" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" From 0413fa8ae5e345d70cfde2677f22a6403e3b2ab9 Mon Sep 17 00:00:00 2001 From: Elias Carvalho <73039601+eliascarv@users.noreply.github.com> Date: Tue, 22 Oct 2024 10:05:05 -0300 Subject: [PATCH 8/9] Update src/generic.jl Co-authored-by: Milan Bouchet-Valat --- src/generic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generic.jl b/src/generic.jl index d3f186d..c91a2ec 100644 --- a/src/generic.jl +++ b/src/generic.jl @@ -22,7 +22,7 @@ abstract type SemiMetric <: PreMetric end abstract type Metric <: SemiMetric end """ - MinkowskiMetric + MinkowskiMetric <: Metric A Minkowski metric is a metric that is defined by the formula: From 9bca62a73662f52bd96a7b8b4db71d05c8773440 Mon Sep 17 00:00:00 2001 From: Elias Carvalho Date: Tue, 22 Oct 2024 10:06:41 -0300 Subject: [PATCH 9/9] Export 'MinkowskiMetric' --- src/Distances.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Distances.jl b/src/Distances.jl index 854e28c..dc1f35a 100644 --- a/src/Distances.jl +++ b/src/Distances.jl @@ -9,6 +9,7 @@ export PreMetric, SemiMetric, Metric, + MinkowskiMetric, # generic functions result_type,