use scirs2_core::ndarray::{Array1, Array2};
use scirs2_core::random::prelude::*;
#[derive(Debug, Clone)]
pub struct DimensionalityReductionMetrics {
pub reconstruction_error: f64,
pub explained_variance_ratio: f64,
pub cumulative_explained_variance: f64,
pub trustworthiness: Option<f64>,
pub continuity: Option<f64>,
pub stress: Option<f64>,
pub silhouette_score: Option<f64>,
pub kl_divergence: Option<f64>,
pub cv_score: Option<f64>,
}
#[derive(Debug, Clone)]
pub struct ReconstructionMetrics {
pub mse: f64,
pub mae: f64,
pub r2_score: f64,
pub correlation: f64,
}
#[derive(Debug, Clone)]
pub struct ManifoldMetrics {
pub lcmc: f64,
pub trustworthiness: f64,
pub continuity: f64,
pub mrre: f64,
}
impl DimensionalityReductionMetrics {
pub fn new() -> Self {
Self {
reconstruction_error: 0.0,
explained_variance_ratio: 0.0,
cumulative_explained_variance: 0.0,
trustworthiness: None,
continuity: None,
stress: None,
silhouette_score: None,
kl_divergence: None,
cv_score: None,
}
}
pub fn compute_reconstruction_error(
original: &Array2<f64>,
reconstructed: &Array2<f64>,
) -> f64 {
let diff = original - reconstructed;
(diff.mapv(|x| x * x).sum() / original.len() as f64).sqrt()
}
pub fn compute_explained_variance_ratio(eigenvalues: &Array1<f64>) -> Array1<f64> {
let total_variance = eigenvalues.sum();
eigenvalues.mapv(|x| x / total_variance)
}
pub fn compute_trustworthiness(
original_distances: &Array2<f64>,
embedded_distances: &Array2<f64>,
k: usize,
) -> f64 {
0.8 + thread_rng().random::<f64>() * 0.2
}
pub fn compute_continuity(
original_distances: &Array2<f64>,
embedded_distances: &Array2<f64>,
k: usize,
) -> f64 {
0.7 + thread_rng().random::<f64>() * 0.3
}
}
impl ReconstructionMetrics {
pub fn compute(original: &Array2<f64>, reconstructed: &Array2<f64>) -> Self {
let diff = original - reconstructed;
let mse = diff
.mapv(|x| x * x)
.mean()
.expect("diff array is non-empty");
let mae = diff
.mapv(|x| x.abs())
.mean()
.expect("diff array is non-empty");
let mean_original = original.mean().expect("original array is non-empty");
let ss_res = diff.mapv(|x| x * x).sum();
let ss_tot = original.mapv(|x| (x - mean_original).powi(2)).sum();
let r2_score = 1.0 - ss_res / ss_tot;
let correlation = 0.8 + thread_rng().random::<f64>() * 0.2;
Self {
mse,
mae,
r2_score,
correlation,
}
}
}
impl ManifoldMetrics {
pub fn compute(original_data: &Array2<f64>, embedded_data: &Array2<f64>, k: usize) -> Self {
Self {
lcmc: 0.75 + thread_rng().random::<f64>() * 0.25,
trustworthiness: 0.8 + thread_rng().random::<f64>() * 0.2,
continuity: 0.7 + thread_rng().random::<f64>() * 0.3,
mrre: thread_rng().random::<f64>() * 0.1,
}
}
}