Clustering
C++20 header-only: DBSCAN, HDBSCAN, k-means.
Loading...
Searching...
No Matches
distance.h
Go to the documentation of this file.
1#pragma once
2
3#include <cmath>
4#include <cstddef>
5#include <type_traits>
6#include <utility>
7
9
10#ifdef CLUSTERING_USE_AVX2
11#include "clustering/math/detail/distance_avx2.h"
12#endif
13
15
23
27struct CosineTag {};
28
32struct ManhattanTag {};
33
34namespace detail {
35
43struct PointwiseSqFn {
44 template <class Tag, class A, class B>
45 constexpr auto operator()(Tag tag, A &&a, B &&b) const
46 noexcept(noexcept(tag_invoke(std::declval<const PointwiseSqFn &>(), tag, std::forward<A>(a),
47 std::forward<B>(b))))
48 -> decltype(tag_invoke(std::declval<const PointwiseSqFn &>(), tag, std::forward<A>(a),
49 std::forward<B>(b))) {
50 return tag_invoke(*this, tag, std::forward<A>(a), std::forward<B>(b));
51 }
52};
53
54} // namespace detail
55
68inline constexpr detail::PointwiseSqFn pointwiseSq{};
69
91template <class T, Layout LA, Layout LB>
92T tag_invoke(const detail::PointwiseSqFn & /*cpo*/, SqEuclideanTag, const NDArray<T, 1, LA> &a,
93 const NDArray<T, 1, LB> &b) noexcept {
94 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
95 "pointwiseSq: integer element types not supported");
96 const std::size_t n = a.dim(0);
97#ifdef CLUSTERING_USE_AVX2
98 if constexpr (std::is_same_v<T, float>) {
99 // _mm256_load_ps issues an 8-lane contiguous aligned read. Gate dispatch on contiguity
100 // (a strided view shares element type but not memory layout), 32-byte alignment (misaligned
101 // load is UB), and the 8-dim floor (below 8 the horizontal-sum epilogue is pure tax; matches
102 // the kdtree dispatch rationale).
103 if (n >= 8 && a.isContiguous() && b.isContiguous() && a.template isAligned<32>() &&
104 b.template isAligned<32>()) {
105 return detail::sqEuclideanAvx2F32(a.template alignedData<32>(), b.template alignedData<32>(),
106 n);
107 }
108 }
109#endif
110 T sum = T{0};
111 for (std::size_t i = 0; i < n; ++i) {
112 const T diff = a(i) - b(i);
113 sum += diff * diff;
114 }
115 return sum;
116}
117
134template <class T, Layout LA, Layout LB>
135T tag_invoke(const detail::PointwiseSqFn & /*cpo*/, ManhattanTag, const NDArray<T, 1, LA> &a,
136 const NDArray<T, 1, LB> &b) noexcept {
137 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
138 "pointwiseSq: integer element types not supported");
139 const std::size_t n = a.dim(0);
140 T sum = T{0};
141 for (std::size_t i = 0; i < n; ++i) {
142 const T diff = a(i) - b(i);
143 sum += diff < T{0} ? -diff : diff;
144 }
145 return sum;
146}
147
164template <class T, Layout LA, Layout LB>
165T tag_invoke(const detail::PointwiseSqFn & /*cpo*/, CosineTag, const NDArray<T, 1, LA> &a,
166 const NDArray<T, 1, LB> &b) noexcept {
167 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
168 "pointwiseSq: integer element types not supported");
169 const std::size_t n = a.dim(0);
170 T dot = T{0};
171 T na = T{0};
172 T nb = T{0};
173 for (std::size_t i = 0; i < n; ++i) {
174 const T ai = a(i);
175 const T bi = b(i);
176 dot += ai * bi;
177 na += ai * ai;
178 nb += bi * bi;
179 }
180 if (na == T{0} || nb == T{0}) {
181 return T{1};
182 }
183 return T{1} - (dot / std::sqrt(na * nb));
184}
185
186} // namespace clustering::math::distance
Represents a multidimensional array (NDArray) of a fixed number of dimensions N and element type T.
Definition ndarray.h:136
T tag_invoke(const detail::PointwiseSqFn &, SqEuclideanTag, const NDArray< T, 1, LA > &a, const NDArray< T, 1, LB > &b) noexcept
Squared Euclidean distance between two rank-1 NDArrays.
Definition distance.h:92
constexpr detail::PointwiseSqFn pointwiseSq
Customization-point object for pairwise squared distances between two rank-1 arrays.
Definition distance.h:68
T sum(const NDArray< T, 1, L > &x) noexcept
Naive single-pass sum of a rank-1 array.
Definition reduce.h:25
Tag selecting the cosine distance metric (1 - cos(angle)).
Definition distance.h:27
Tag selecting the Manhattan (L1) metric: sum of absolute differences.
Definition distance.h:32
Tag selecting the squared Euclidean metric.
Definition distance.h:22