49 static_assert(std::is_same_v<T, float>,
50 "AutoMstBackend<T> supports only float; a double specialization is out of scope.");
53#ifdef CLUSTERING_HDBSCAN_BORUVKA_LOW_DIM_CEIL
63 static constexpr std::size_t
boruvkaLowDimCeil = CLUSTERING_HDBSCAN_BORUVKA_LOW_DIM_CEIL;
69#ifdef CLUSTERING_HDBSCAN_BORUVKA_DIM_CEIL
76 static constexpr std::size_t
boruvkaDimCeil = CLUSTERING_HDBSCAN_BORUVKA_DIM_CEIL;
84 "boruvkaLowDimCeil must not exceed boruvkaDimCeil; the dispatch order assumes a "
85 "nested Boruvka regime at low d and a relaxed one at moderate d.");
99 return n <= kNsqBudget / n;
113 ensureShape(X.
dim(0), X.
dim(1));
114 std::visit([&](
auto &b) { b.run(X, minSamples, pool, out); }, m_held);
124 [[nodiscard]] std::size_t
heldIndex() const noexcept {
return m_held.index(); }
134 std::size_t
peekArm(std::size_t n, std::size_t d) {
136 return m_held.index();
140 void ensureShape(std::size_t n, std::size_t d) {
141 if (n == m_lastN && d == m_lastD) {
145 if (!std::holds_alternative<BoruvkaMstBackend<T>>(m_held)) {
146 m_held.template emplace<BoruvkaMstBackend<T>>();
153 if (!std::holds_alternative<PrimMstBackend<T>>(m_held)) {
154 m_held.template emplace<PrimMstBackend<T>>();
157 if (!std::holds_alternative<BoruvkaMstBackend<T>>(m_held)) {
158 m_held.template emplace<BoruvkaMstBackend<T>>();
161 if (!std::holds_alternative<NnDescentMstBackend<T>>(m_held)) {
162 m_held.template emplace<NnDescentMstBackend<T>>();
170 std::variant<BoruvkaMstBackend<T>, PrimMstBackend<T>, NnDescentMstBackend<T>> m_held{
171 std::in_place_type<PrimMstBackend<T>>};
172 std::size_t m_lastN = 0;
173 std::size_t m_lastD = 0;
Represents a multidimensional array (NDArray) of a fixed number of dimensions N and element type T.
size_t dim(std::size_t index) const noexcept
Returns the size of a specific dimension of the NDArray.
std::size_t peekArm(std::size_t n, std::size_t d)
Resolve the variant arm for (n, d) without running the pipeline.
static constexpr std::size_t boruvkaDimCeil
Dimensional ceiling above which KDTree Boruvka gives way to NN-Descent when Prim is out of byte budge...
void run(const NDArray< T, 2 > &X, std::size_t minSamples, math::Pool pool, MstOutput< T > &out)
Fit a backend arm chosen on the input shape and delegate run to it.
std::size_t heldIndex() const noexcept
Index of the currently held variant arm.
static constexpr std::size_t boruvkaLowDimCeil
Low-dimensional ceiling at or below which Boruvka is preferred regardless of N.
static constexpr bool primFitsBudget(std::size_t n) noexcept
Whether the Prim regime applies at n under the dense-MRD byte budget.
constexpr std::size_t kPrimMrdMatrixByteBudget
Equivalent byte-budget phrasing of kPrimMaxN, kept so callers that gate on n*n*sizeof(T) <= kPrimMrdM...
Frozen output contract of every MST backend.
Thin injection wrapper around a BS::light_thread_pool.