use rustc_hash::FxHashSet;
pub mod traits;
pub mod utils;
pub mod builder;
#[cfg(test)]
mod tests;
pub use crate::traits::PointInterface;
pub use crate::traits::GraphInterface;
pub use crate::builder::*;
use crate::utils::*;
pub fn search<P, G>(
graph: &mut G,
query_point: &P,
k: usize,
) -> (Vec<(f32, u32)>, Vec<(f32, u32)>)
where
P: PointInterface,
G: GraphInterface<P>,
{
let builder_l = graph.size_l();
assert!(builder_l >= k);
let mut visited: Vec<(f32, u32)> = Vec::with_capacity(builder_l * 2);
let mut touched = FxHashSet::default();
touched.reserve(builder_l * 100);
let mut list: Vec<(f32, u32, bool)> = Vec::with_capacity(builder_l);
let s = graph.start_id();
let (s_point, _) = graph.get(&s);
list.push((query_point.distance(&s_point), s, true));
let mut working = Some(list[0]);
visited.push((list[0].0, list[0].1));
touched.insert(list[0].1);
while let Some((_, nearest_i, _)) = working {
let (_, nearest_n_out) = graph.get(&nearest_i);
let mut nouts: Vec<(f32, u32, bool)> = Vec::with_capacity(nearest_n_out.len());
for out_i in nearest_n_out {
if !touched.contains(&out_i) {
touched.insert(out_i);
let (out_point, _) = graph.get(&out_i);
nouts.push((query_point.distance(&out_point), out_i, false))
}
}
sort_list_by_dist(&mut nouts);
let mut new_list = Vec::with_capacity(builder_l);
let mut new_list_idx = 0;
let mut l_idx = 0; let mut n_idx = 0;
working = None;
while new_list_idx < builder_l {
let mut new_min = if l_idx >= list.len() && n_idx >= nouts.len() {
break;
} else if l_idx >= list.len() {
let new_min = nouts[n_idx];
n_idx += 1;
new_min
} else if n_idx >= nouts.len() {
let new_min = list[l_idx];
l_idx += 1;
new_min
} else {
let l_min = list[l_idx];
let n_min = nouts[n_idx];
if l_min.0 <= n_min.0 {
l_idx += 1;
l_min
} else {
n_idx += 1;
n_min
}
};
let is_not_visited = !new_min.2;
if working.is_none() && is_not_visited {
new_min.2 = true; working = Some(new_min);
visited.push((new_min.0, new_min.1));
}
if !graph.cemetery().contains(&new_min.1) || is_not_visited {
new_list.push(new_min);
new_list_idx += 1;
}
}
list = new_list;
}
let mut k_anns = list
.into_iter()
.map(|(dist, id, _)| (dist, id))
.collect::<Vec<(f32, u32)>>();
k_anns.truncate(k);
sort_list_by_dist_v1(&mut visited);
(k_anns, visited)
}
pub fn insert<P, G>(graph: &mut G, new_p: P) -> u32
where
P: PointInterface,
G: GraphInterface<P>,
{
let new_id = graph.alloc(new_p.clone());
let r = graph.size_r();
let a = graph.size_a();
let (_list, mut visited) = search(graph, &new_p, 1);
let n_out = prune(|id| graph.get(id), &mut visited, &r, &a);
graph.overwirte_out_edges(&new_id, n_out.clone());
for j in &n_out {
let (j_point, mut j_n_out) = graph.get(j);
j_n_out.push(new_id);
j_n_out.sort();
j_n_out.dedup();
if j_n_out.len() > r {
let mut j_n_out_with_dist = j_n_out
.iter()
.map(|j_out_idx| (j_point.distance(&new_p), *j_out_idx))
.collect::<Vec<(f32, u32)>>();
sort_list_by_dist_v1(&mut j_n_out_with_dist);
j_n_out = prune(|id| graph.get(id), &mut j_n_out_with_dist, &r, &a);
}
graph.overwirte_out_edges(j, j_n_out);
}
new_id
}
pub fn delete<P, G>(graph: &mut G)
where
P: PointInterface,
G: GraphInterface<P>,
{
let mut ps = Vec::new();
let mut cemetery = graph.cemetery();
cemetery.sort();
cemetery.dedup();
for grave_i in &cemetery {
ps.extend(graph.backlink(grave_i))
}
ps.sort();
ps.dedup();
ps = diff_ids(&ps, &cemetery);
for p in ps {
let (_, p_n_out) = graph.get(&p);
let d = intersect_ids(&p_n_out, &cemetery);
let mut c = diff_ids(&p_n_out, &d);
for u in &d {
let (_, u_n_out) = graph.get(u);
c.extend(u_n_out);
c.sort();
c.dedup();
}
c = diff_ids(&c, &cemetery);
let (p_point, _) = graph.get(&p);
let mut c_with_dist: Vec<(f32, u32)> = c
.into_iter()
.map(|id| (p_point.distance(&graph.get(&id).0), id))
.collect();
sort_list_by_dist_v1(&mut c_with_dist);
let r = graph.size_r();
let a = graph.size_a();
let new_edges = prune(|id| graph.get(id), &mut c_with_dist, &r, &a);
graph.overwirte_out_edges(&p, new_edges);
}
for grave_i in &cemetery {
graph.overwirte_out_edges(grave_i, vec![]); }
for grave_i in &cemetery {
graph.free(grave_i)
}
graph.clear_cemetery();
}
fn prune<P, F>(
mut get: F,
candidates: &mut Vec<(f32, u32)>,
builder_r: &usize,
builder_a: &f32,
) -> Vec<u32>
where
P: PointInterface,
F: FnMut(&u32) -> (P, Vec<u32>),
{
let mut new_n_out = vec![];
while let Some((first, rest)) = candidates.split_first() {
let (_, pa) = *first; new_n_out.push(pa);
if new_n_out.len() == *builder_r {
break;
}
*candidates = rest.to_vec();
candidates.retain(|&(dist_xp_pd, pd)| {
let (pa_point, _) = get(&pa);
let (pd_point, _) = get(&pd);
let dist_pa_pd = pa_point.distance(&pd_point);
builder_a * dist_pa_pd > dist_xp_pd
})
}
new_n_out
}