use super::datastructures::{NewCenters, OpeningList};
use crate::types::{CenterIdx, ColorCount, ColorIdx, Distance, PointCount, PointIdx};
use crate::{Centers, ClusteringProblem, ColoredMetric};
use std::collections::{hash_map, HashMap, VecDeque};
mod neighborhood;
use neighborhood::determine_neighborhood;
mod color_flow;
use color_flow::compute_assignment_by_flow;
use rayon::ThreadPoolBuilder;
use std::sync::mpsc;
#[derive(Debug, Clone, Copy, PartialOrd, PartialEq)]
struct ColorEdge {
d: Distance, center: CenterIdx, point: PointIdx, color: ColorIdx, }
#[derive(Debug)]
struct ShiftedCenters {
forrest_radius: Distance, assignment_radius: Distance,
new_centers: Vec<PNodeIdx>,
origins: Vec<CenterIdx>, }
type PNodeIdx = usize; type CNodeIdx = usize;
pub(crate) fn phase4<M: ColoredMetric>(
space: &M,
prob: &ClusteringProblem,
mut opening_lists: Vec<Vec<OpeningList>>,
gonzalez: &Centers,
thread_count: usize,
) -> (Vec<NewCenters>, Vec<usize>) {
let sum_of_a: PointCount = prob.rep_intervals.iter().map(|interval| interval.0).sum();
let mut shifted_centers: Vec<Option<ShiftedCenters>> = (0..prob.k).map(|_| None).collect();
let mut counts = vec![0; prob.k]; let mut node_to_point_list: Vec<Vec<PointIdx>> = Vec::with_capacity(prob.k);
let edges_of_cluster: Vec<Vec<ColorEdge>> = determine_neighborhood(space, prob, gonzalez);
let thread_pool = ThreadPoolBuilder::new()
.num_threads(thread_count)
.build()
.unwrap();
let mut receivers = VecDeque::with_capacity(prob.k);
thread_pool.scope(|pool| {
for i in (0..prob.k).rev() {
let opening_list = opening_lists.pop().unwrap();
let (tx, rx) = mpsc::channel();
receivers.push_front(rx);
let edges_of_cluster_ref = &edges_of_cluster;
let problem = &prob;
pool.spawn(move |_| {
let (centers, node_to_point, count) =
shift_centers(problem, sum_of_a, i, edges_of_cluster_ref, opening_list);
tx.send((centers, node_to_point, count)).unwrap();
});
}
for i in 0..prob.k {
let (centers, node_to_point, count) = receivers[i].recv().unwrap();
shifted_centers[i] = centers;
node_to_point_list.push(node_to_point); counts[i] = count;
}
});
let mut new_centers: Vec<NewCenters> = Vec::with_capacity(prob.k + 1);
for (i, c) in shifted_centers.into_iter().enumerate() {
let best_centers = c.unwrap();
let mut centers: Centers = Centers::with_capacity(best_centers.new_centers.len());
let mut new_center_idx_of_cluster = vec![Vec::new(); i + 1];
for (l, &idx) in best_centers.new_centers.iter().enumerate() {
let point = space.get_point(node_to_point_list[i][idx]).unwrap();
centers.push(point);
new_center_idx_of_cluster[best_centers.origins[l]].push(centers.m() - 1);
}
new_centers.push(NewCenters {
as_points: centers,
forrest_radius: best_centers.forrest_radius,
assignment_radius: best_centers.assignment_radius,
new_centers_of_cluster: new_center_idx_of_cluster,
});
}
(new_centers, counts)
}
fn shift_centers(
prob: &ClusteringProblem,
sum_of_a: PointCount,
i: CenterIdx,
edges_of_cluster: &Vec<Vec<ColorEdge>>,
opening_lists: Vec<OpeningList>,
) -> (Option<ShiftedCenters>, Vec<PointIdx>, usize) {
let mut edges: Vec<&ColorEdge> = Vec::with_capacity((i + 1) * prob.k); (0..i + 1).for_each(|j| {
edges.extend(edges_of_cluster[j].iter());
});
edges.sort_by(|a, b| a.partial_cmp(b).unwrap());
let mut point_to_node: HashMap<PointIdx, PNodeIdx> = HashMap::with_capacity((i + 1) * prob.k); let mut node_to_point: Vec<PointIdx> = Vec::with_capacity((i + 1) * prob.k); let mut point_counter = 0;
let mut a: Vec<PointCount> = Vec::with_capacity((i + 1) * prob.k); let mut b: Vec<PointCount> = Vec::with_capacity((i + 1) * prob.k); let mut color_to_node: HashMap<ColorIdx, CNodeIdx> = HashMap::with_capacity((i + 1) * prob.k); let mut color_counter = 0;
let mut point_idx_to_color_idx: Vec<ColorIdx> = Vec::with_capacity((i + 1) * prob.k);
for e in edges.iter() {
if let hash_map::Entry::Vacant(entry) = color_to_node.entry(e.color) {
entry.insert(color_counter);
if e.color >= prob.rep_intervals.len() {
a.push(0);
b.push(<PointCount>::MAX);
} else {
a.push(prob.rep_intervals[e.color].0);
b.push(prob.rep_intervals[e.color].1);
}
color_counter += 1;
}
if let hash_map::Entry::Vacant(entry) = point_to_node.entry(e.point) {
entry.insert(point_counter);
node_to_point.push(e.point);
point_idx_to_color_idx.push(*color_to_node.get(&e.color).unwrap());
point_counter += 1;
}
}
let mut edges_by_color_node: Vec<Vec<&ColorEdge>> = vec![Vec::new(); color_counter];
let mut edges_by_point_node: Vec<Vec<&ColorEdge>> = vec![Vec::new(); point_counter];
let mut count = 0;
for e in edges.iter() {
edges_by_color_node[color_to_node[&e.color]].push(e);
edges_by_point_node[point_to_node[&e.point]].push(e);
}
edges_by_color_node.sort_by(|a, b| a.partial_cmp(b).unwrap());
edges_by_point_node.sort_by(|a, b| a.partial_cmp(b).unwrap());
let mut current_best_radius = <Distance>::MAX;
let mut centers = None;
for (j, opening) in opening_lists.iter().enumerate() {
if current_best_radius <= opening.forrest_radius {
continue;
}
if sum_of_a > opening.eta.iter().sum() {
continue;
}
let mut has_been_solved = false;
for open_list in opening_lists.iter().take(j) {
let old_eta = &open_list.eta;
let mut old_equal_or_bigger = true;
for (l, eta) in old_eta.iter().enumerate() {
if opening.eta[l] > *eta {
old_equal_or_bigger = false;
break;
}
}
if old_equal_or_bigger {
has_been_solved = true;
break;
}
}
if has_been_solved {
continue;
}
let network = Network {
edges: &edges,
k: prob.k,
opening,
i,
number_of_points: point_counter,
number_of_colors: color_counter,
sum_of_a,
a: &a,
b: &b,
edges_of_cluster,
point_to_node: &point_to_node,
point_idx_to_color_idx: &point_idx_to_color_idx,
edges_by_color_node: &edges_by_color_node,
edges_by_point_node: &edges_by_point_node,
};
count += 1;
let new = compute_assignment_by_flow(&network);
if current_best_radius > new.forrest_radius + new.assignment_radius {
current_best_radius = new.forrest_radius + new.assignment_radius;
centers = Some(new);
}
}
(centers, node_to_point, count)
}
struct Network<'a> {
edges: &'a Vec<&'a ColorEdge>,
k: CenterIdx,
opening: &'a OpeningList,
i: CenterIdx,
number_of_points: PointCount,
number_of_colors: ColorCount,
sum_of_a: PointCount,
a: &'a Vec<PointCount>,
b: &'a Vec<PointCount>,
edges_of_cluster: &'a Vec<Vec<ColorEdge>>,
point_to_node: &'a HashMap<PointIdx, PNodeIdx>,
point_idx_to_color_idx: &'a Vec<CNodeIdx>,
edges_by_color_node: &'a Vec<Vec<&'a ColorEdge>>,
edges_by_point_node: &'a Vec<Vec<&'a ColorEdge>>,
}