use abd_clam::{graph::Vertex, Cluster, PartitionCriteria, Tree};
use abd_clam::{Dataset, Instance, VecDataset};
use distances::Number;
use tempdir::TempDir;
mod utils;
#[test]
fn save_load_vertex() {
let data = utils::gen_dataset(1000, 10, 42, utils::euclidean);
let metric = data.metric();
let criteria = PartitionCriteria::default();
let raw_tree = Tree::new(data, Some(42))
.partition(&criteria, Some(42))
.normalize_ratios();
let tree_dir = TempDir::new("tree_medium_vertex").unwrap();
raw_tree.save(tree_dir.path()).unwrap();
let rec_tree = Tree::load(tree_dir.path(), metric, false).unwrap();
assert_eq!(raw_tree.depth(), rec_tree.depth(), "Tree depths not equal.");
assert_subtree_equal(
raw_tree.root(),
raw_tree.data(),
rec_tree.root(),
rec_tree.data(),
metric,
);
}
fn assert_subtree_equal<I: Instance, U: Number, M: Instance>(
raw_cluster: &Vertex<U>,
raw_data: &VecDataset<I, U, M>,
rec_cluster: &Vertex<U>,
rec_data: &VecDataset<I, U, M>,
metric: fn(&I, &I) -> U,
) {
assert_eq!(
raw_cluster.cardinality(),
rec_cluster.cardinality(),
"Cardinalities are not equal."
);
let (raw_center, rec_center) = (&raw_data[raw_cluster.arg_center()], &rec_data[rec_cluster.arg_center()]);
let (raw_radial, rec_radial) = (&raw_data[raw_cluster.arg_radial()], &rec_data[rec_cluster.arg_radial()]);
for (r1, r2) in raw_cluster.ratios().iter().zip(rec_cluster.ratios()) {
float_cmp::assert_approx_eq!(f64, *r1, r2, epsilon = 0.00000003);
}
assert_eq!(metric(raw_center, rec_center), U::zero(), "Centers are not equal.");
assert_eq!(metric(raw_radial, rec_radial), U::zero(), "Radials are not equal.");
let (raw_children, rec_children) = (&raw_cluster.children(), &rec_cluster.children());
match raw_children {
None => assert!(rec_children.is_none(), "One cluster has children, the other does not"),
Some([left_1, right_1]) => {
assert!(rec_children.is_some(), "One cluster has children, the other does not");
let [left_2, right_2] = rec_children.unwrap();
assert_subtree_equal(left_1, raw_data, left_2, rec_data, metric);
assert_subtree_equal(right_1, raw_data, right_2, rec_data, metric);
}
}
}
#[test]
fn ratios() {
let data = utils::gen_dataset_from(
vec![vec![10.], vec![1.], vec![3.]],
utils::euclidean::<f32, f32>,
vec![true, true, false],
);
let partition_criteria = PartitionCriteria::default();
let root = Tree::<_, _, _, Vertex<_>>::new(data, Some(42)).partition(&partition_criteria, None);
let all_ratios = root
.root()
.subtree()
.into_iter()
.map(|c| c.ratios())
.collect::<Vec<_>>();
let all_cardinalities = root
.root()
.subtree()
.into_iter()
.map(|c| c.cardinality())
.collect::<Vec<_>>();
let all_lfd = root.root().subtree().into_iter().map(|c| c.lfd()).collect::<Vec<_>>();
let all_radius = root
.root()
.subtree()
.into_iter()
.map(|c| c.radius())
.collect::<Vec<_>>();
let root_ratios = [
all_cardinalities[0] as f64,
all_radius[0] as f64,
all_lfd[0],
-1.,
-1.,
-1.,
];
let lc_ratios = [
all_cardinalities[1] as f64 / root_ratios[0] as f64,
all_radius[1] as f64 / root_ratios[1] as f64,
all_lfd[1] / root_ratios[2],
-1.,
-1.,
-1.,
];
let lclc_ratios = [
all_cardinalities[2] as f64 / lc_ratios[0] as f64,
all_radius[2] as f64 / lc_ratios[1] as f64,
all_lfd[2] / lc_ratios[2],
-1.,
-1.,
-1.,
];
let lcrc_ratios = [
all_cardinalities[3] as f64 / lc_ratios[0] as f64,
all_radius[3] as f64 / lc_ratios[1] as f64,
all_lfd[3] / lc_ratios[2],
-1.,
-1.,
-1.,
];
let rc_ratios = [
all_cardinalities[4] as f64 / root_ratios[0] as f64,
all_radius[4] as f64 / root_ratios[1] as f64,
all_lfd[4] / root_ratios[2],
-1.,
-1.,
-1.,
];
assert_eq!(all_ratios[0][..3], root_ratios[..3], "root not correct");
assert_eq!(all_ratios[1][..3], lc_ratios[..3], "lc not correct");
assert_eq!(all_ratios[2][..3], lclc_ratios[..3], "lclc not correct");
assert_eq!(all_ratios[3][..3], lcrc_ratios[..3], "lcrc not correct");
assert_eq!(all_ratios[4][..3], rc_ratios[..3], "rc not correct");
}
#[test]
fn normalized_ratios() {
let data = utils::gen_dataset(1000, 10, 42, utils::euclidean);
let partition_criteria = PartitionCriteria::new(true).with_max_depth(3).with_min_cardinality(1);
let raw_tree = Tree::<_, _, _, Vertex<_>>::new(data, None)
.partition(&partition_criteria, None)
.normalize_ratios();
let all_ratios = raw_tree
.root()
.subtree()
.into_iter()
.map(|c| c.ratios())
.collect::<Vec<_>>();
for row in &all_ratios {
for val in row {
assert!(*val >= 0. && *val <= 1.);
}
}
}