hipvs/distance/mod.rs
1/*
2 * Copyright (c) 2024-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
17use crate::distance_type::DistanceType;
18use crate::dlpack::ManagedTensor;
19use crate::error::{check_cuvs, Result};
20use crate::resources::Resources;
21
22/// Compute pairwise distances between X and Y
23///
24/// # Arguments
25///
26/// * `res` - Resources to use
27/// * `x` - A matrix in device memory - shape (m, k)
28/// * `y` - A matrix in device memory - shape (n, k)
29/// * `distances` - A matrix in device memory that receives the output distances - shape (m, n)
30/// * `metric` - DistanceType to use for building the index
31/// * `metric_arg` - Optional value of `p` for Minkowski distances
32pub fn pairwise_distance(
33 res: &Resources,
34 x: &ManagedTensor,
35 y: &ManagedTensor,
36 distances: &ManagedTensor,
37 metric: DistanceType,
38 metric_arg: Option<f32>,
39) -> Result<()> {
40 unsafe {
41 check_cuvs(ffi::cuvsPairwiseDistance(
42 res.0,
43 x.as_ptr(),
44 y.as_ptr(),
45 distances.as_ptr(),
46 metric,
47 metric_arg.unwrap_or(2.0),
48 ))
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use ndarray_rand::rand_distr::Uniform;
56 use ndarray_rand::RandomExt;
57
58 #[test]
59 fn test_pairwise_distance() {
60 let res = Resources::new().unwrap();
61
62 // Create a new random dataset to index
63 let n_datapoints = 256;
64 let n_features = 16;
65 let dataset =
66 ndarray::Array::<f32, _>::random((n_datapoints, n_features), Uniform::new(0., 1.0));
67 let dataset_device = ManagedTensor::from(&dataset).to_device(&res).unwrap();
68
69 let mut distances_host = ndarray::Array::<f32, _>::zeros((n_datapoints, n_datapoints));
70 let distances = ManagedTensor::from(&distances_host)
71 .to_device(&res)
72 .unwrap();
73
74 pairwise_distance(
75 &res,
76 &dataset_device,
77 &dataset_device,
78 &distances,
79 DistanceType::L2Expanded,
80 None,
81 )
82 .unwrap();
83
84 // Copy back to host memory
85 distances.to_host(&res, &mut distances_host).unwrap();
86
87 // Self distance should be 0
88 assert_eq!(distances_host[[0, 0]], 0.0);
89 }
90}