use core::{iter::Map, slice};
use alloc::vec::{self, Vec};
use pgat::{ProxyView, ReferenceProxy, View};
use crate::{ApproximateSpace, ExactSpace, Knn, Metric, SpatialContainer, linear_nn};
pub fn linear_knn<'a, 'b, M, P, V>(
metric: M,
dataset: impl Iterator<Item = (View<'a, P>, View<'a, V>)>,
query: View<'b, P>,
num: usize,
) -> Vec<(M::Unit, View<'a, P>, View<'a, V>)>
where
M: Metric<P>,
P: ProxyView,
V: ProxyView,
{
let mut dataset = dataset.map(|(pt, val)| (metric.distance(pt, query), pt, val));
let mut neighbors = Vec::with_capacity(num);
neighbors.extend((&mut dataset).take(num));
neighbors.sort_unstable_by_key(|n| n.0);
for point in dataset {
let position = neighbors.partition_point(|n| n.0 <= point.0);
if position != num {
neighbors.pop();
neighbors.insert(position, point);
}
}
neighbors
}
pub struct LinearSearch<'a, M, P, V, PP = ReferenceProxy<P>, VP = ReferenceProxy<V>> {
pub metric: M,
pub data: &'a [(P, V)],
pub _phantom: core::marker::PhantomData<(PP, VP)>,
}
impl<'a, M, P, V, PP, VP> LinearSearch<'a, M, P, V, PP, VP>
where
M: Metric<PP>,
PP: ProxyView<Owned = P>,
VP: ProxyView<Owned = V>,
{
pub fn new(metric: M, data: &'a [(P, V)]) -> Self {
Self {
metric,
data,
_phantom: core::marker::PhantomData,
}
}
}
impl<'a, M, P, V, PP, VP> ApproximateSpace for LinearSearch<'a, M, P, V, PP, VP>
where
M: Metric<PP>,
PP: ProxyView<Owned = P>,
VP: ProxyView<Owned = V>,
{
type PointProxy = PP;
type ValueProxy = VP;
type Metric = M;
}
impl<'a, M, P, V, PP, VP> ExactSpace for LinearSearch<'a, M, P, V, PP, VP>
where
M: Metric<PP>,
PP: ProxyView<Owned = P>,
VP: ProxyView<Owned = V>,
{
}
impl<'c, M, P, V, PP, VP> Knn for LinearSearch<'c, M, P, V, PP, VP>
where
M: Metric<PP>,
PP: ProxyView<Owned = P>,
VP: ProxyView<Owned = V>,
{
type KnnIter<'a>
= vec::IntoIter<(M::Unit, View<'a, PP>, View<'a, VP>)>
where
Self: 'a;
fn knn<'a, 'b>(&'a self, query: View<'b, Self::PointProxy>, num: usize) -> Self::KnnIter<'a> {
linear_knn::<M, PP, VP>(
self.metric,
self.data
.iter()
.map(|(pt, val)| (PP::view(pt), VP::view(val))),
query,
num,
)
.into_iter()
}
fn nn<'a, 'b>(
&'a self,
query: View<'b, Self::PointProxy>,
) -> Option<(M::Unit, View<'a, PP>, View<'a, VP>)> {
linear_nn::<M, PP, VP>(
self.metric,
self.data
.iter()
.map(|(pt, val)| (PP::view(pt), VP::view(val))),
query,
)
}
}
pub struct LinearContainer<M, P, V, PP = ReferenceProxy<P>, VP = ReferenceProxy<V>> {
pub metric: M,
pub data: Vec<(P, V)>,
pub _phantom: core::marker::PhantomData<(PP, VP)>,
}
impl<M, P, V, PP, VP> ApproximateSpace for LinearContainer<M, P, V, PP, VP>
where
M: Metric<PP>,
PP: ProxyView<Owned = P>,
VP: ProxyView<Owned = V>,
{
type PointProxy = PP;
type ValueProxy = VP;
type Metric = M;
}
impl<M, P, V, PP, VP> ExactSpace for LinearContainer<M, P, V, PP, VP>
where
M: Metric<PP>,
PP: ProxyView<Owned = P>,
VP: ProxyView<Owned = V>,
{
}
impl<M, P, V, PP, VP> SpatialContainer for LinearContainer<M, P, V, PP, VP>
where
M: Metric<PP>,
PP: ProxyView<Owned = P>,
VP: ProxyView<Owned = V>,
{
type SpatialIter<'a>
= Map<slice::Iter<'a, (P, V)>, fn(&'a (P, V)) -> (View<'a, PP>, View<'a, VP>)>
where
Self: 'a;
fn with_metric(metric: Self::Metric) -> Self {
Self {
metric,
data: Vec::new(),
_phantom: core::marker::PhantomData,
}
}
fn insert(&mut self, point: P, value: V) {
self.data.push((point, value));
}
fn iter(&self) -> Self::SpatialIter<'_> {
self.data.iter().map(|(p, v)| (PP::view(p), VP::view(v)))
}
}
impl<M, P, V, PP, VP> Knn for LinearContainer<M, P, V, PP, VP>
where
M: Metric<PP>,
PP: ProxyView<Owned = P>,
VP: ProxyView<Owned = V>,
{
type KnnIter<'a>
= vec::IntoIter<(M::Unit, View<'a, PP>, View<'a, VP>)>
where
Self: 'a;
fn knn<'a, 'b>(&'a self, query: View<'b, Self::PointProxy>, num: usize) -> Self::KnnIter<'a> {
linear_knn::<M, PP, VP>(
self.metric,
self.data
.iter()
.map(|(pt, val)| (PP::view(pt), VP::view(val))),
query,
num,
)
.into_iter()
}
fn nn<'a, 'b>(
&'a self,
query: View<'b, Self::PointProxy>,
) -> Option<(M::Unit, View<'a, PP>, View<'a, VP>)> {
linear_nn::<M, PP, VP>(
self.metric,
self.data
.iter()
.map(|(pt, val)| (PP::view(pt), VP::view(val))),
query,
)
}
}