Loading [MathJax]/extensions/tex2jax.js
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
utils.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021-2025, NVIDIA CORPORATION.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include "../condensed_hierarchy.cu"
20 
21 #include <common/fast_int_div.cuh>
22 
23 #include <cuml/cluster/hdbscan.hpp>
24 
25 #include <raft/core/device_mdspan.hpp>
26 #include <raft/label/classlabels.cuh>
27 #include <raft/linalg/matrix_vector_op.cuh>
28 #include <raft/linalg/norm.cuh>
29 #include <raft/sparse/convert/csr.cuh>
30 #include <raft/sparse/op/sort.cuh>
31 #include <raft/util/cudart_utils.hpp>
32 
33 #include <rmm/device_uvector.hpp>
34 #include <rmm/exec_policy.hpp>
35 
36 #include <cub/cub.cuh>
37 #include <cuda/functional>
38 #include <thrust/copy.h>
39 #include <thrust/execution_policy.h>
40 #include <thrust/for_each.h>
41 #include <thrust/functional.h>
42 #include <thrust/iterator/zip_iterator.h>
43 #include <thrust/reduce.h>
44 #include <thrust/sort.h>
45 #include <thrust/transform.h>
46 #include <thrust/transform_reduce.h>
47 #include <thrust/tuple.h>
48 
49 #include <algorithm>
50 
51 namespace ML {
52 namespace HDBSCAN {
53 namespace detail {
54 namespace Utils {
55 
69 template <typename value_idx, typename value_t, typename CUBReduceFunc>
70 void cub_segmented_reduce(const value_t* in,
71  value_t* out,
72  int n_segments,
73  const value_idx* offsets,
74  cudaStream_t stream,
75  CUBReduceFunc cub_reduce_func)
76 {
77  rmm::device_uvector<char> d_temp_storage(0, stream);
78  size_t temp_storage_bytes = 0;
79  cub_reduce_func(nullptr, temp_storage_bytes, in, out, n_segments, offsets, offsets + 1, stream);
80  d_temp_storage.resize(temp_storage_bytes, stream);
81 
82  cub_reduce_func(
83  d_temp_storage.data(), temp_storage_bytes, in, out, n_segments, offsets, offsets + 1, stream);
84 }
85 
95 template <typename value_idx, typename value_t>
97  const raft::handle_t& handle, Common::CondensedHierarchy<value_idx, value_t>& condensed_tree)
98 {
99  auto stream = handle.get_stream();
100  auto thrust_policy = handle.get_thrust_policy();
101  auto parents = condensed_tree.get_parents();
102  auto children = condensed_tree.get_children();
103  auto lambdas = condensed_tree.get_lambdas();
104  auto sizes = condensed_tree.get_sizes();
105 
106  value_idx cluster_tree_edges = thrust::transform_reduce(
107  thrust_policy,
108  sizes,
109  sizes + condensed_tree.get_n_edges(),
110  cuda::proclaim_return_type<value_idx>(
111  [=] __device__(value_idx a) -> value_idx { return static_cast<value_idx>(a > 1); }),
112  static_cast<value_idx>(0),
113  cuda::std::plus<value_idx>());
114 
115  // remove leaves from condensed tree
116  rmm::device_uvector<value_idx> cluster_parents(cluster_tree_edges, stream);
117  rmm::device_uvector<value_idx> cluster_children(cluster_tree_edges, stream);
118  rmm::device_uvector<value_t> cluster_lambdas(cluster_tree_edges, stream);
119  rmm::device_uvector<value_idx> cluster_sizes(cluster_tree_edges, stream);
120 
121  auto in = thrust::make_zip_iterator(thrust::make_tuple(parents, children, lambdas, sizes));
122 
123  auto out = thrust::make_zip_iterator(thrust::make_tuple(
124  cluster_parents.data(), cluster_children.data(), cluster_lambdas.data(), cluster_sizes.data()));
125 
126  thrust::copy_if(thrust_policy,
127  in,
128  in + (condensed_tree.get_n_edges()),
129  sizes,
130  out,
131  [=] __device__(value_idx a) { return a > 1; });
132 
133  auto n_leaves = condensed_tree.get_n_leaves();
134  thrust::transform(thrust_policy,
135  cluster_parents.begin(),
136  cluster_parents.end(),
137  cluster_parents.begin(),
138  [n_leaves] __device__(value_idx a) { return a - n_leaves; });
139  thrust::transform(thrust_policy,
140  cluster_children.begin(),
141  cluster_children.end(),
142  cluster_children.begin(),
143  [n_leaves] __device__(value_idx a) { return a - n_leaves; });
144 
146  condensed_tree.get_n_leaves(),
147  cluster_tree_edges,
148  condensed_tree.get_n_clusters(),
149  std::move(cluster_parents),
150  std::move(cluster_children),
151  std::move(cluster_lambdas),
152  std::move(cluster_sizes));
153 }
154 
164 template <typename value_idx, typename value_t>
165 void parent_csr(const raft::handle_t& handle,
167  value_idx* sorted_parents,
168  value_idx* indptr)
169 {
170  auto stream = handle.get_stream();
171  auto thrust_policy = handle.get_thrust_policy();
172 
173  auto children = condensed_tree.get_children();
174  auto sizes = condensed_tree.get_sizes();
175  auto n_edges = condensed_tree.get_n_edges();
176  auto n_leaves = condensed_tree.get_n_leaves();
177  auto n_clusters = condensed_tree.get_n_clusters();
178 
179  // 0-index sorted parents by subtracting n_leaves for offsets and birth/stability indexing
180  auto index_op = [n_leaves] __device__(const auto& x) { return x - n_leaves; };
182  thrust_policy, sorted_parents, sorted_parents + n_edges, sorted_parents, index_op);
183 
184  raft::sparse::convert::sorted_coo_to_csr(sorted_parents, n_edges, indptr, n_clusters + 1, stream);
185 }
186 
187 template <typename value_idx, typename value_t>
188 void normalize(value_t* data, value_idx n, size_t m, cudaStream_t stream)
189 {
190  rmm::device_uvector<value_t> sums(m, stream);
191 
192  // Compute row sums
193  raft::linalg::rowNorm<value_t, size_t>(
194  sums.data(), data, (size_t)n, m, raft::linalg::L1Norm, true, stream);
195 
196  // Divide vector by row sums (modify in place)
197  raft::linalg::matrixVectorOp(
198  data,
199  const_cast<value_t*>(data),
200  sums.data(),
201  n,
202  (value_idx)m,
203  true,
204  false,
205  [] __device__(value_t mat_in, value_t vec_in) { return mat_in / vec_in; },
206  stream);
207 }
208 
219 template <typename value_idx, typename value_t>
220 void softmax(const raft::handle_t& handle, value_t* data, value_idx n, size_t m)
221 {
222  rmm::device_uvector<value_t> linf_norm(m, handle.get_stream());
223 
224  auto data_const_view =
225  raft::make_device_matrix_view<const value_t, value_idx, raft::row_major>(data, (int)m, n);
226  auto data_view =
227  raft::make_device_matrix_view<value_t, value_idx, raft::row_major>(data, (int)m, n);
228  auto linf_norm_const_view =
229  raft::make_device_vector_view<const value_t, value_idx>(linf_norm.data(), (int)m);
230  auto linf_norm_view = raft::make_device_vector_view<value_t, value_idx>(linf_norm.data(), (int)m);
231 
232  raft::linalg::norm(handle,
233  data_const_view,
234  linf_norm_view,
235  raft::linalg::LinfNorm,
236  raft::linalg::Apply::ALONG_ROWS);
237 
238  raft::linalg::matrix_vector_op(
239  handle,
240  data_const_view,
241  linf_norm_const_view,
242  data_view,
243  raft::linalg::Apply::ALONG_COLUMNS,
244  [] __device__(value_t mat_in, value_t vec_in) { return exp(mat_in - vec_in); });
245 }
246 
247 }; // namespace Utils
248 }; // namespace detail
249 }; // namespace HDBSCAN
250 }; // namespace ML
Definition: hdbscan.hpp:40
value_idx * get_sizes()
Definition: hdbscan.hpp:118
value_t * get_lambdas()
Definition: hdbscan.hpp:117
value_idx get_n_leaves() const
Definition: hdbscan.hpp:121
value_idx get_n_edges()
Definition: hdbscan.hpp:119
value_idx * get_children()
Definition: hdbscan.hpp:116
int get_n_clusters()
Definition: hdbscan.hpp:120
value_idx * get_parents()
Definition: hdbscan.hpp:115
Common::CondensedHierarchy< value_idx, value_t > make_cluster_tree(const raft::handle_t &handle, Common::CondensedHierarchy< value_idx, value_t > &condensed_tree)
Definition: utils.h:96
void softmax(const raft::handle_t &handle, value_t *data, value_idx n, size_t m)
Definition: utils.h:220
void normalize(value_t *data, value_idx n, size_t m, cudaStream_t stream)
Definition: utils.h:188
void cub_segmented_reduce(const value_t *in, value_t *out, int n_segments, const value_idx *offsets, cudaStream_t stream, CUBReduceFunc cub_reduce_func)
Definition: utils.h:70
void parent_csr(const raft::handle_t &handle, Common::CondensedHierarchy< value_idx, value_t > &condensed_tree, value_idx *sorted_parents, value_idx *indptr)
Definition: utils.h:165
void transform(const raft::handle_t &handle, const KMeansParams ¶ms, const float *centroids, const float *X, int n_samples, int n_features, float *X_new)
Transform X to a cluster-distance space.
Definition: dbscan.hpp:30