4 个版本 (2 个破坏性更新)

0.3.0 2021 年 10 月 24 日
0.2.0 2020 年 8 月 24 日
0.1.1 2020 年 6 月 30 日
0.1.0 2020 年 6 月 24 日

算法 中排名 848

Download history 41/week @ 2024-03-13 65/week @ 2024-03-20 81/week @ 2024-03-27 75/week @ 2024-04-03 80/week @ 2024-04-10 53/week @ 2024-04-17 109/week @ 2024-04-24 77/week @ 2024-05-01 78/week @ 2024-05-08 195/week @ 2024-05-15 158/week @ 2024-05-22 64/week @ 2024-05-29 46/week @ 2024-06-05 114/week @ 2024-06-12 344/week @ 2024-06-19 250/week @ 2024-06-26

每月下载 774
2 crates 中使用

MIT 许可证

105KB
2.5K SLoC

acap

crates.io Documentation License CI Status

尽可能接近 —— Rust 中的 最近邻搜索

示例

use acap::euclid::Euclidean;
use acap::vp::VpTree;
use acap::NearestNeighbors;

let tree = VpTree::balanced(vec![
    Euclidean([3, 4]),
    Euclidean([5, 12]),
    Euclidean([8, 15]),
    Euclidean([7, 24]),
]);

let nearest = tree.nearest(&[7, 7]).unwrap();
assert_eq!(nearest.item, &Euclidean([3, 4]));
assert_eq!(nearest.distance, 5);

lib.rs:

尽可能接近 —— Rust 中的 最近邻搜索

概述

点之间距离的概念由 Proximity 特性来捕捉。其 distance() 方法返回一个 Distance,可以通过 value() 获取实际的数值距离。这些抽象层允许 acap 以泛型方式使用不同类型的不同距离函数。

Proximity 计算的距离没有限制。例如,它们不必是对称的、次可加的,甚至不必是正的。具有这些理想属性的实现将额外实现 Metric 标记特性。这种区分允许 acap 支持多种有用的度量和非度量距离。

作为一个具体的例子,考虑 Euclidean<[i32; 2]>Euclidean 包装器为任何具有 坐标 的类型配备了 欧几里得距离 函数作为其 Proximity 实现的 Proximity

 use acap::distance::Proximity;
 use acap::euclid::Euclidean;

 let a = Euclidean([3, 4]);
 let b = Euclidean([7, 7]);
 assert_eq!(a.distance(&b), 5);

在这种情况下,distance() 并不直接返回一个数字;作为一种优化,它返回一个 EuclideanDistance 包装器。这个包装器存储距离的平方值,以避免在绝对必要之前计算平方根。尽管如此,它仍然可以透明地支持与数值的比较。

 # use acap::distance::Proximity;
 # use acap::euclid::Euclidean;
 # let a = Euclidean([3, 4]);
 # let b = Euclidean([7, 7]);
 use acap::distance::Distance;

 let d = a.distance(&b);
 assert!(d > 4 && d < 6);
 assert_eq!(d, 5);
 assert_eq!(d.value(), 5.0f32);

为了从一个点的一组其他点中找到最近的邻居,NearestNeighbors trait 提供了一个统一接口来访问许多不同的相似性搜索数据结构。其中之一是 vantage-point tree,在 acap 中作为 VpTree 提供。

 # use acap::euclid::Euclidean;
 use acap::vp::VpTree;

 let tree = VpTree::balanced(vec![
     Euclidean([3, 4]),
     Euclidean([5, 12]),
     Euclidean([8, 15]),
     Euclidean([7, 24]),
 ]);

VpTree 实现了 NearestNeighbors,它有一个 nearest() 方法,该方法返回一个可选的 NeighborNeighbor 结构体包含找到的实际邻居以及与目标点的距离。

 # use acap::euclid::Euclidean;
 # use acap::vp::VpTree;
 use acap::knn::NearestNeighbors;

 # let tree = VpTree::balanced(
 #     vec![Euclidean([3, 4]), Euclidean([5, 12]), Euclidean([8, 15]), Euclidean([7, 24])]
 # );
 let nearest = tree.nearest(&[7, 7]).unwrap();
 assert_eq!(nearest.item, &Euclidean([3, 4]));
 assert_eq!(nearest.distance, 5);

NearestNeighbors 还提供了 nearest_within()k_nearest()k_nearest_within() 方法,这些方法在可能的阈值内找到最多 k 个邻居。

精确计算最近邻居可能很昂贵,特别是在高维空间中。出于性能原因,NearestNeighbors 实现可以返回近似结果。许多实现都有速度/精度权衡,可以进行调整。那些总是返回精确结果的实现也将实现 ExactNeighbors 标记特征。例如,当 Proximity 函数是一个 Metric 时,VpTree 将是精确的。

示例

无所有权的搜索

由于 Proximity 为引用提供了通用实现,因此你可以在最近邻索引中存储引用,而不是让它自己持有数据。

 use acap::euclid::Euclidean;
 use acap::knn::NearestNeighbors;
 use acap::vp::VpTree;

 let points = vec![
     Euclidean([3, 4]),
     Euclidean([5, 12]),
     Euclidean([8, 15]),
     Euclidean([7, 24]),
 ];

 let tree = VpTree::balanced(points.iter());

 let nearest = tree.nearest(&&[7, 7]).unwrap();
 assert!(std::ptr::eq(*nearest.item, &points[0]));

自定义距离函数

请参阅 Proximity 文档。

依赖项

~155KB