#![allow(clippy::excessive_precision)]
use std::f64::consts::PI;
use fdars_core::coclustering::{co_cluster, CoClusterConfig};
use fdars_core::frechet::frechet_anova;
use fdars_core::matrix::FdMatrix;
fn co_cluster_data(n: usize, m: usize) -> (FdMatrix, Vec<f64>) {
let argvals: Vec<f64> = (0..m).map(|j| j as f64 / (m - 1) as f64).collect();
let mut data = vec![0.0; n * m];
for i in 0..n {
let grp = i % 2;
let phase = if grp == 0 { 0.0 } else { 0.35 } + 0.05 * ((i as f64 * 1.7).sin());
let amp = 1.0 + 0.3 * ((i as f64 * 0.9).sin()) + if grp == 0 { 0.0 } else { 0.5 };
for j in 0..m {
data[i + j * n] = amp * (2.0 * PI * (argvals[j] + phase)).sin();
}
}
(FdMatrix::from_column_major(data, n, m).unwrap(), argvals)
}
fn co_cluster_config(n_init: usize) -> CoClusterConfig {
let mut cfg = CoClusterConfig::default();
cfg.n_row_blocks = 2;
cfg.n_col_blocks = 2;
cfg.ncomp = 3;
cfg.max_iter = 50;
cfg.tol = 1e-6;
cfg.n_init = n_init;
cfg.seed = 42;
cfg
}
#[test]
fn golden_co_cluster_parallel() {
let (data, argvals) = co_cluster_data(60, 40);
let r = co_cluster(&data, &argvals, &co_cluster_config(4)).unwrap();
assert_eq!(r.log_likelihood, 4.34232518676733207e2);
let row_ref: Vec<usize> = (0..60).map(|i| if i % 2 == 0 { 1 } else { 0 }).collect();
assert_eq!(r.row_labels, row_ref);
let col_ref = vec![
1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
];
assert_eq!(r.col_labels, col_ref);
}
#[test]
fn golden_co_cluster_below_threshold() {
let (data, argvals) = co_cluster_data(60, 40);
let r = co_cluster(&data, &argvals, &co_cluster_config(2)).unwrap();
assert_eq!(r.log_likelihood, 4.15588733019948734e2);
let row_ref: Vec<usize> = (0..60).map(|i| if i % 2 == 0 { 1 } else { 0 }).collect();
assert_eq!(r.row_labels, row_ref);
let col_ref = vec![
0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
assert_eq!(r.col_labels, col_ref);
}
fn two_group_densities(n_per: usize, m: usize) -> (FdMatrix, Vec<f64>, Vec<usize>) {
let argvals: Vec<f64> = (0..m)
.map(|j| -3.0 + 6.0 * j as f64 / (m - 1) as f64)
.collect();
let n = 2 * n_per;
let mut data = vec![0.0; n * m];
let mut labels = vec![0usize; n];
for i in 0..n {
let g = if i < n_per { 0 } else { 1 };
labels[i] = g;
let mu = if g == 0 { -0.5 } else { 0.5 } + 0.2 * ((i as f64 * 1.7).sin());
let sigma = 0.7 + 0.2 * ((i as f64 * 1.3).sin().abs());
for j in 0..m {
let z = (argvals[j] - mu) / sigma;
data[i + j * n] = (-0.5 * z * z).exp() / sigma + 1e-6;
}
}
(
FdMatrix::from_column_major(data, n, m).unwrap(),
argvals,
labels,
)
}
#[test]
fn helpers_smoke() {
let (d, a, l) = two_group_densities(6, 20);
assert_eq!(d.shape(), (12, 20));
assert_eq!(a.len(), 20);
assert_eq!(l, vec![0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1]);
let _ = PI;
}
#[test]
fn golden_frechet_anova_parallel() {
let (data, argvals, labels) = two_group_densities(12, 20);
let r = frechet_anova(&data, &argvals, &labels, 999, 42).unwrap();
assert_eq!(r.statistic, 1.17320834419366224e3);
assert_eq!(r.p_value_permutation, 1.00000000000000002e-3);
assert_eq!(r.p_value_asymptotic, 4.05441402554881990e-257);
}
#[test]
fn golden_frechet_anova_below_threshold() {
let (data, argvals, labels) = two_group_densities(12, 20);
let r = frechet_anova(&data, &argvals, &labels, 50, 42).unwrap();
assert_eq!(r.statistic, 1.17320834419366224e3);
assert_eq!(r.p_value_permutation, 1.96078431372549017e-2);
}