use core::{cmp::Ordering, hash::Hash};
use distances::Number;
use priority_queue::PriorityQueue;
use crate::{Dataset, Instance, Tree};
pub(crate) mod greedy_sieve;
pub(crate) mod linear;
pub(crate) mod repeated_rnn;
pub(crate) mod sieve;
pub(crate) mod sieve_sep_center;
#[derive(Clone, Copy, Debug)]
pub enum Algorithm {
Linear,
RepeatedRnn,
GreedySieve,
Sieve,
SieveSepCenter,
}
impl Default for Algorithm {
fn default() -> Self {
Self::GreedySieve
}
}
impl Algorithm {
pub fn search<I, U, D>(self, tree: &Tree<I, U, D>, query: &I, k: usize) -> Vec<(usize, U)>
where
I: Instance,
U: Number,
D: Dataset<I, U>,
{
match self {
Self::Linear => {
let indices = (0..tree.cardinality()).collect::<Vec<_>>();
linear::search(tree.data(), query, k, &indices)
}
Self::RepeatedRnn => repeated_rnn::search(tree, query, k),
Self::GreedySieve => greedy_sieve::search(tree, query, k),
Self::Sieve => sieve::search(tree, query, k),
Self::SieveSepCenter => sieve_sep_center::search(tree, query, k),
}
}
#[must_use]
pub const fn name(&self) -> &str {
match self {
Self::Linear => "Linear",
Self::RepeatedRnn => "RepeatedRnn",
Self::GreedySieve => "GreedySieve",
Self::Sieve => "Sieve",
Self::SieveSepCenter => "SieveSepCenter",
}
}
#[must_use]
pub const fn variants<'a>() -> &'a [Self] {
&[Self::RepeatedRnn, Self::GreedySieve, Self::Sieve, Self::SieveSepCenter]
}
}
pub(crate) struct Hits<I: Hash + Eq + Copy, U: Number> {
pub queue: PriorityQueue<I, OrdNumber<U>>,
pub capacity: usize,
}
impl<I: Hash + Eq + Copy, U: Number> Hits<I, U> {
pub fn new(capacity: usize) -> Self {
Self {
queue: PriorityQueue::with_capacity(capacity),
capacity,
}
}
pub fn from_vec(capacity: usize, vec: Vec<(I, U)>) -> Self {
let mut queue = PriorityQueue::with_capacity(capacity);
for (i, d) in vec {
queue.push(i, OrdNumber(d));
}
while queue.len() > capacity {
queue.pop();
}
Self { queue, capacity }
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.queue.len()
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.queue.is_empty()
}
pub fn peek(&self) -> U {
self.queue.peek().map_or_else(U::zero, |(_, &OrdNumber(d))| d)
}
pub fn push(&mut self, i: I, d: U) {
if self.queue.len() < self.capacity {
self.queue.push(i, OrdNumber(d));
} else if d < self.peek() {
self.queue.pop();
self.queue.push(i, OrdNumber(d));
}
}
pub fn push_batch(&mut self, items: impl Iterator<Item = (I, U)>) {
items.for_each(|(i, d)| {
self.queue.push(i, OrdNumber(d));
});
while self.queue.len() > self.capacity {
self.queue.pop();
}
}
#[allow(dead_code)]
pub fn pop_until(&mut self, threshold: U) {
while threshold < self.peek() {
self.queue.pop();
}
}
pub fn extract(&self) -> Vec<(I, U)> {
self.queue.iter().map(|(&i, &OrdNumber(d))| (i, d)).collect()
}
}
#[derive(Debug)]
pub struct OrdNumber<U: Number>(U);
impl<U: Number> PartialEq for OrdNumber<U> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<U: Number> Eq for OrdNumber<U> {}
impl<U: Number> PartialOrd for OrdNumber<U> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<U: Number> Ord for OrdNumber<U> {
fn cmp(&self, other: &Self) -> Ordering {
self.0.partial_cmp(&other.0).unwrap_or(Ordering::Greater)
}
}
#[derive(Debug)]
pub struct RevNumber<U: Number>(U);
impl<U: Number> PartialEq for RevNumber<U> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<U: Number> Eq for RevNumber<U> {}
impl<U: Number> PartialOrd for RevNumber<U> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<U: Number> Ord for RevNumber<U> {
fn cmp(&self, other: &Self) -> Ordering {
other.0.partial_cmp(&self.0).unwrap_or(Ordering::Greater)
}
}