use std::mem;
use std::ops;
use crate::float::Float;
#[derive(Debug, Eq, Hash, PartialEq)]
pub struct Dendrogram<T> {
steps: Vec<Step<T>>,
observations: usize,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Step<T> {
pub cluster1: usize,
pub cluster2: usize,
pub dissimilarity: T,
pub size: usize,
}
impl<T> Dendrogram<T> {
pub fn new(observations: usize) -> Dendrogram<T> {
Dendrogram {
steps: Vec::with_capacity(observations),
observations: observations,
}
}
pub fn reset(&mut self, observations: usize) {
self.steps.clear();
self.observations = observations;
}
pub fn push(&mut self, step: Step<T>) {
assert!(self.len() < self.observations().saturating_sub(1));
self.steps.push(step);
}
pub fn steps(&self) -> &[Step<T>] {
&self.steps
}
pub fn steps_mut(&mut self) -> &mut [Step<T>] {
&mut self.steps
}
pub fn len(&self) -> usize {
self.steps.len()
}
pub fn is_empty(&self) -> bool {
self.steps.is_empty()
}
pub fn observations(&self) -> usize {
self.observations
}
pub fn cluster_size(&self, label: usize) -> usize {
if label < self.observations() {
1
} else {
self[label - self.observations()].size
}
}
}
impl<T: Float> Dendrogram<T> {
pub fn eq_with_epsilon(&self, other: &Dendrogram<T>, epsilon: T) -> bool {
if self.len() != other.len() {
return false;
}
for (s1, s2) in self.steps().iter().zip(other.steps()) {
if !s1.eq_with_epsilon(s2, epsilon) {
return false;
}
}
true
}
}
impl<T> ops::Index<usize> for Dendrogram<T> {
type Output = Step<T>;
fn index(&self, i: usize) -> &Step<T> {
&self.steps[i]
}
}
impl<T> ops::IndexMut<usize> for Dendrogram<T> {
fn index_mut(&mut self, i: usize) -> &mut Step<T> {
&mut self.steps[i]
}
}
impl<T> Step<T> {
pub fn new(
mut cluster1: usize,
mut cluster2: usize,
dissimilarity: T,
size: usize,
) -> Step<T> {
if cluster2 < cluster1 {
mem::swap(&mut cluster1, &mut cluster2);
}
Step {
cluster1: cluster1,
cluster2: cluster2,
dissimilarity: dissimilarity,
size: size,
}
}
pub fn set_clusters(&mut self, mut cluster1: usize, mut cluster2: usize) {
if cluster2 < cluster1 {
mem::swap(&mut cluster1, &mut cluster2);
}
self.cluster1 = cluster1;
self.cluster2 = cluster2;
}
}
impl<T: Float> Step<T> {
pub fn eq_with_epsilon(&self, other: &Step<T>, epsilon: T) -> bool {
if self == other {
return true;
}
let key1 = (self.cluster1, self.cluster2, self.size);
let key2 = (other.cluster1, other.cluster2, other.size);
if key1 != key2 {
return false;
}
if (self.dissimilarity - other.dissimilarity).abs() > epsilon {
return false;
}
true
}
}