use super::{flow, flow::State, Edge, EdgeIdx};
use crate::types::{CenterIdx, Distance, PointCount};
use crate::{utilities, Centers, Clustering, ColoredMetric};
pub(super) fn settle<'a, M: ColoredMetric>(
edge_cursor: EdgeIdx,
bucket: &mut [Edge<'a>],
i: CenterIdx,
privacy_bound: PointCount,
state: &mut State<'a>,
centers: &Centers,
space: &M,
) -> Clustering {
let k = centers.m();
let mut cursor = edge_cursor;
let edges_present =
if edge_cursor >= bucket.len()/2 { while cursor < bucket.len() {
flow::add_edge(bucket[cursor],i,k,privacy_bound,state);
cursor += 1;
}
true
} else { while cursor > 0 {
cursor -= 1;
flow::remove_edge(bucket[cursor],i,k,privacy_bound,state);
}
false
};
let _radius = search_for_radius(
edges_present,
bucket,
&mut cursor,
i,
k,
privacy_bound,
state,
);
let mut center_prefix = Centers::with_capacity(i + 1);
for c in centers.get_all(space).iter().take(i + 1) {
center_prefix.push(c);
}
let clustering = Clustering::new(center_prefix, state.center_of.clone(), space);
while cursor > 0 {
cursor -= 1;
flow::remove_edge(bucket[cursor], i, k, privacy_bound, state);
}
clustering
}
fn search_for_radius<'a>(
edges_present: bool,
list: &mut [Edge<'a>],
cursor: &mut EdgeIdx,
i: CenterIdx,
k: PointCount,
privacy_bound: PointCount,
state: &mut State<'a>,
) -> Distance {
let list_len = list.len();
debug_assert!(list_len > 0, "Empty list in binary search");
if list_len == 1 {
if !edges_present {
flow::add_edge(list[0], i, k, privacy_bound, state);
*cursor += 1;
}
debug_assert_eq!(
state.max_flow,
(i + 1) * privacy_bound,
"Something went wrong in the binary search."
);
return list[0].d;
}
let (smaller, bigger) = utilities::split_in_half(list);
if edges_present {
for e in bigger.iter().rev() {
flow::remove_edge(*e, i, k, privacy_bound, state);
*cursor -= 1;
}
} else {
for e in smaller.iter() {
flow::add_edge(*e, i, k, privacy_bound, state);
*cursor += 1;
}
}
if state.max_flow >= (i + 1) * privacy_bound {
search_for_radius(true, smaller, cursor, i, k, privacy_bound, state)
} else {
search_for_radius(false, bigger, cursor, i, k, privacy_bound, state)
}
}