pub(crate) use super::*;
#[test]
fn test_r_squared_perfect() {
let y_true = Vector::from_slice(&[1.0, 2.0, 3.0, 4.0, 5.0]);
let y_pred = Vector::from_slice(&[1.0, 2.0, 3.0, 4.0, 5.0]);
let r2 = r_squared(&y_pred, &y_true);
assert!((r2 - 1.0).abs() < 1e-6);
}
#[test]
fn test_r_squared_good() {
let y_true = Vector::from_slice(&[3.0, -0.5, 2.0, 7.0]);
let y_pred = Vector::from_slice(&[2.5, 0.0, 2.0, 8.0]);
let r2 = r_squared(&y_pred, &y_true);
assert!(r2 > 0.9);
assert!(r2 < 1.0);
}
#[test]
fn test_r_squared_mean_prediction() {
let y_true = Vector::from_slice(&[1.0, 2.0, 3.0, 4.0, 5.0]);
let mean = y_true.mean();
let y_pred = Vector::from_slice(&[mean, mean, mean, mean, mean]);
let r2 = r_squared(&y_pred, &y_true);
assert!(r2.abs() < 1e-6);
}
#[test]
fn test_r_squared_negative() {
let y_true = Vector::from_slice(&[1.0, 2.0, 3.0]);
let y_pred = Vector::from_slice(&[10.0, 10.0, 10.0]);
let r2 = r_squared(&y_pred, &y_true);
assert!(r2 < 0.0);
}
#[test]
fn test_mse() {
let y_true = Vector::from_slice(&[3.0, -0.5, 2.0, 7.0]);
let y_pred = Vector::from_slice(&[2.5, 0.0, 2.0, 8.0]);
let error = mse(&y_pred, &y_true);
assert!((error - 0.375).abs() < 1e-6);
}
#[test]
fn test_mse_perfect() {
let y_true = Vector::from_slice(&[1.0, 2.0, 3.0]);
let y_pred = Vector::from_slice(&[1.0, 2.0, 3.0]);
let error = mse(&y_pred, &y_true);
assert!(error.abs() < 1e-6);
}
#[test]
fn test_mae() {
let y_true = Vector::from_slice(&[3.0, -0.5, 2.0, 7.0]);
let y_pred = Vector::from_slice(&[2.5, 0.0, 2.0, 8.0]);
let error = mae(&y_pred, &y_true);
assert!((error - 0.5).abs() < 1e-6);
}
#[test]
fn test_mae_perfect() {
let y_true = Vector::from_slice(&[1.0, 2.0, 3.0]);
let y_pred = Vector::from_slice(&[1.0, 2.0, 3.0]);
let error = mae(&y_pred, &y_true);
assert!(error.abs() < 1e-6);
}
#[test]
fn test_rmse() {
let y_true = Vector::from_slice(&[3.0, -0.5, 2.0, 7.0]);
let y_pred = Vector::from_slice(&[2.5, 0.0, 2.0, 8.0]);
let error = rmse(&y_pred, &y_true);
assert!((error - 0.375_f32.sqrt()).abs() < 1e-6);
}
#[test]
fn test_inertia() {
let data = Matrix::from_vec(4, 2, vec![0.0, 0.0, 1.0, 0.0, 10.0, 10.0, 11.0, 10.0])
.expect("Matrix dimensions (4x2) match data length (8)");
let centroids = Matrix::from_vec(
2,
2,
vec![
0.5, 0.0, 10.5, 10.0, ],
)
.expect("Matrix dimensions (2x2) match data length (4)");
let labels = vec![0, 0, 1, 1];
let score = inertia(&data, ¢roids, &labels);
assert!((score - 1.0).abs() < 1e-6);
}
#[test]
fn test_silhouette_score_good() {
let data = Matrix::from_vec(4, 2, vec![0.0, 0.0, 0.1, 0.1, 10.0, 10.0, 10.1, 10.1])
.expect("Matrix dimensions (4x2) match data length (8)");
let labels = vec![0, 0, 1, 1];
let score = silhouette_score(&data, &labels);
assert!(score > 0.9);
}
#[test]
fn test_silhouette_score_poor() {
let data = Matrix::from_vec(4, 2, vec![0.0, 0.0, 1.0, 1.0, 0.5, 0.5, 1.5, 1.5])
.expect("Matrix dimensions (4x2) match data length (8)");
let labels = vec![0, 0, 1, 1];
let score = silhouette_score(&data, &labels);
assert!(score < 0.9);
}
#[test]
fn test_silhouette_score_single_cluster() {
let data = Matrix::from_vec(4, 2, vec![0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0, 3.0])
.expect("Matrix dimensions (4x2) match data length (8)");
let labels = vec![0, 0, 0, 0];
let score = silhouette_score(&data, &labels);
assert!((score - 0.0).abs() < 1e-6);
}
#[test]
fn test_silhouette_score_single_sample() {
let data = Matrix::from_vec(1, 2, vec![0.0, 0.0])
.expect("Matrix dimensions (1x2) match data length (2)");
let labels = vec![0];
let score = silhouette_score(&data, &labels);
assert!((score - 0.0).abs() < 1e-6);
}
#[test]
fn test_silhouette_score_two_samples() {
let data = Matrix::from_vec(2, 2, vec![0.0, 0.0, 10.0, 10.0])
.expect("Matrix dimensions (2x2) match data length (4)");
let labels = vec![0, 1];
let score = silhouette_score(&data, &labels);
assert!(
score.abs() > 0.0,
"Score with 2 samples should be non-zero, got {score}"
);
}
#[test]
fn test_silhouette_score_distance_calculation() {
let data = Matrix::from_vec(
6,
1,
vec![
0.0, 1.0, 2.0, 100.0, 101.0, 102.0, ],
)
.expect("Matrix dimensions (6x1) match data length (6)");
let labels = vec![0, 0, 0, 1, 1, 1];
let score = silhouette_score(&data, &labels);
assert!(
score > 0.9,
"Well-separated clusters should have high score, got {score}"
);
assert!(score <= 1.0, "Score should be <= 1.0, got {score}");
}
#[test]
fn test_silhouette_score_mean_not_one() {
let data = Matrix::from_vec(
4,
1,
vec![
0.0, 10.0, 50.0, 60.0, ],
)
.expect("Matrix dimensions (4x1) match data length (4)");
let labels = vec![0, 0, 1, 1];
let score = silhouette_score(&data, &labels);
assert!(
score > 0.5,
"Score should be high for well-separated clusters, got {score}"
);
}
#[test]
fn test_metrics_consistency() {
let y_true = Vector::from_slice(&[1.0, 2.0, 3.0, 4.0, 5.0]);
let y_pred = Vector::from_slice(&[1.1, 2.2, 2.9, 4.1, 5.0]);
let mse_val = mse(&y_pred, &y_true);
let rmse_val = rmse(&y_pred, &y_true);
assert!((rmse_val - mse_val.sqrt()).abs() < 1e-6);
}
#[test]
fn test_silhouette_intra_cluster_averaging() {
let data = Matrix::from_vec(6, 1, vec![0.0, 1.0, 2.0, 100.0, 101.0, 102.0])
.expect("Matrix dimensions (6x1) match data length (6)");
let labels = vec![0, 0, 0, 1, 1, 1];
let score = silhouette_score(&data, &labels);
assert!(
score > 0.9,
"Should have high silhouette for well-separated clusters, got {score}"
);
assert!(score <= 1.0, "Silhouette score must be <= 1.0, got {score}");
}
#[test]
fn test_silhouette_inter_cluster_distance() {
let data = Matrix::from_vec(4, 1, vec![0.0, 1.0, 1000.0, 1001.0])
.expect("Matrix dimensions (4x1) match data length (4)");
let labels = vec![0, 0, 1, 1];
let score = silhouette_score(&data, &labels);
assert!(
score > 0.99,
"Very well-separated clusters should have score > 0.99, got {score}"
);
}
#[test]
fn test_silhouette_score_exact_boundary() {
let data = Matrix::from_vec(2, 1, vec![0.0, 100.0])
.expect("Matrix dimensions (2x1) match data length (2)");
let labels = vec![0, 1];
let score = silhouette_score(&data, &labels);
assert!(
score.abs() > 1e-6 || score == 0.0,
"Score should be computed for 2 samples"
);
}
#[test]
fn test_silhouette_many_clusters() {
let data = Matrix::from_vec(
8,
1,
vec![
0.0, 1.0, 100.0, 101.0, 200.0, 201.0, 300.0, 301.0, ],
)
.expect("Matrix dimensions (8x1) match data length (8)");
let labels = vec![0, 0, 1, 1, 2, 2, 3, 3];
let score = silhouette_score(&data, &labels);
assert!(
score > 0.9,
"Well-separated multi-cluster should have high score, got {score}"
);
}