use crate::space::Point;
use crate::types::{CenterIdx, Distance, PointCount, PointIdx};
#[derive(Debug, Clone)]
pub struct Centers {
centers: Vec<PointIdx>,
}
use std::fs::File;
use std::io::prelude::*;
impl Centers {
pub fn new(centers: Vec<PointIdx>) -> Centers {
Centers { centers }
}
pub fn m(&self) -> PointCount {
self.centers.len()
}
pub fn get<'a, M: ColoredMetric>(&self, i: CenterIdx, space: &'a M) -> &'a Point {
space
.get_point(self.centers[i])
.expect("Error: Center is not a point of the current space.")
}
pub fn push(&mut self, c: &Point) {
self.centers.push(c.idx());
}
pub fn get_all<'a, M: ColoredMetric>(&self, space: &'a M) -> Vec<&'a Point> {
self.centers
.iter()
.map(|&c| {
space
.get_point(c)
.expect("Error: Some center is not a point of the current space.")
})
.collect()
}
fn iter_idx(&self) -> std::slice::Iter<PointIdx> {
self.centers.iter()
}
pub fn save_to_file(&self, file_path: &str) {
let mut f = File::create(file_path).expect("Cannot open file for writing centers");
let mut text = String::new();
for c in self.centers.iter() {
text = text + &format!("{},", c);
}
text.pop(); f.write_all(text.as_bytes())
.expect("Could not write into centers-file");
}
pub fn with_capacity(capacity: PointCount) -> Centers {
Centers {
centers: Vec::with_capacity(capacity),
}
}
}
use std::fmt;
impl fmt::Display for Centers {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut iter = self.centers.iter();
if let Some(c) = iter.next() {
write!(f, "{}", c)?;
for c in iter {
write!(f, ", {}", c)?;
}
}
Ok(())
}
}
pub struct Clustering {
centers: Centers,
center_of: Vec<Option<CenterIdx>>, cluster: Vec<Vec<PointIdx>>,
radius: Distance,
radius_valid: bool,
cluster_sizes: Vec<PointCount>,
}
use crate::ColoredMetric;
impl Clustering {
pub fn new<M: ColoredMetric>(
centers: Centers,
center_of: Vec<Option<CenterIdx>>,
space: &M,
) -> Clustering {
assert_eq!(
center_of.len(),
space.n(),
"The assignment center_of must have an entry for each point"
);
let mut cluster: Vec<Vec<PointIdx>> = vec![Vec::new(); centers.m()];
let mut cluster_sizes: Vec<PointCount> = vec![0; centers.m()];
let mut radius = <Distance>::MIN;
for p in space.point_iter() {
let covered_by = center_of[p.idx()];
if let Some(c) = covered_by {
cluster[c].push(p.idx());
cluster_sizes[c] += 1;
let dist = space.dist(p, centers.get(c, space));
if dist > radius {
radius = dist;
}
}
}
Clustering {
centers,
center_of,
cluster,
radius,
radius_valid: true,
cluster_sizes,
}
}
pub fn get_centers(&self) -> &Centers {
&self.centers
}
pub fn get_assignment(&self) -> &Vec<Option<CenterIdx>> {
&self.center_of
}
pub fn get_cluster_of<'a, M: ColoredMetric>(
&self,
center_idx: CenterIdx,
space: &'a M,
) -> Vec<&'a Point> {
assert!(
center_idx < self.cluster.len(),
"center_idx must be between 0 and m-1"
);
self.cluster[center_idx]
.iter()
.filter(|&&p| self.center_of[p] == Some(center_idx))
.map(|&p| {
space
.get_point(p)
.expect("Some point is not part of the metric space anymore")
})
.collect()
}
pub fn get_radius(&self) -> Distance {
if !self.radius_valid {
println!("Radius is outdated and needs to be computed again! Please call update_radius(space).");
}
self.radius
}
pub fn update_radius<M: ColoredMetric>(&mut self, space: &M) {
if !self.radius_valid {
self.radius = Distance::MIN;
for p in space.point_iter() {
if self.center_of[p.idx()].is_some() {
let dist =
space.dist(p, self.centers.get(self.center_of[p.idx()].unwrap(), space));
if dist > self.radius {
self.radius = dist;
}
}
}
self.radius_valid = true;
}
}
pub fn get_cluster_sizes(&self) -> &Vec<PointCount> {
&self.cluster_sizes
}
pub fn m(&self) -> PointCount {
self.centers.m()
}
pub fn get_center<'a, M: ColoredMetric>(
&self,
center_idx: CenterIdx,
space: &'a M,
) -> &'a Point {
self.centers.get(center_idx, space)
}
pub fn assign<M: ColoredMetric>(&mut self, p: &Point, center_idx: CenterIdx, space: &M) {
if self.center_of[p.idx()].is_some() {
let old_center = self.center_of[p.idx()].unwrap();
if space.dist(p, self.centers.get(old_center, space)) >= self.radius {
#[cfg(debug_assertions)]
println!("WARNING: Point {} is already assigned to {} and is reassigned to {}; Radius is probably wrong (too large) now! Call update_radius()", p.idx(), old_center, center_idx);
self.radius_valid = false;
}
self.cluster_sizes[old_center] -= 1;
}
self.center_of[p.idx()] = Some(center_idx);
self.cluster[center_idx].push(p.idx());
self.cluster_sizes[center_idx] += 1;
let dist = space.dist(p, self.centers.get(center_idx, space));
if dist >= self.radius {
self.radius = dist;
if !self.radius_valid {
#[cfg(debug_assertions)]
println!("Radius is valid again!");
self.radius_valid = true;
}
}
}
pub fn fill_up<M: ColoredMetric>(&mut self, space: &M) {
for p in space.point_iter() {
if self.center_of[p.idx()].is_none() {
let mut current_dist = <Distance>::MAX;
let mut best_center = 0;
for (j, ¢er) in self.centers.get_all(space).iter().enumerate() {
let dist = space.dist(center, p);
if dist < current_dist {
current_dist = dist;
best_center = j;
}
}
self.center_of[p.idx()] = Some(best_center);
self.cluster[best_center].push(p.idx());
self.cluster_sizes[best_center] += 1;
if current_dist > self.radius {
self.radius = current_dist;
}
}
}
}
pub fn save_to_file(&self, file_path: &str) {
let mut clients_of: Vec<Vec<PointIdx>> = vec![Vec::new(); self.centers.m()];
for (point_idx, ¢er_idx) in self.center_of.iter().enumerate() {
if let Some(c) = center_idx {
clients_of[c].push(point_idx);
}
}
let mut f = File::create(file_path).expect("Cannot open file for writing clustering");
let mut text = String::new();
for (center_idx, center) in self.centers.iter_idx().enumerate() {
text = text + &format!("{}:", center);
for point_idx in clients_of.get(center_idx).unwrap().iter() {
text = text + &format!("{},", point_idx);
}
text += "\n";
}
text.pop(); f.write_all(text.as_bytes())
.expect("Could not write into centers-file");
}
}