dsfb-semiconductor 0.1.0

Deterministic DSFB semiconductor benchmark companion for SECOM and PHM-style dataset adapters
Documentation
#[cfg(feature = "std")]
use crate::preprocessing::PreparedDataset;
#[cfg(feature = "std")]
use crate::nominal::NominalModel;
use serde::Serialize;
#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};

#[derive(Debug, Clone, Serialize)]
pub struct ResidualFeatureTrace {
    pub feature_index: usize,
    pub feature_name: String,
    pub imputed_values: Vec<f64>,
    pub residuals: Vec<f64>,
    pub norms: Vec<f64>,
    pub threshold_alarm: Vec<bool>,
    pub is_imputed: Vec<bool>,
}

#[derive(Debug, Clone, Serialize)]
pub struct ResidualSet {
    pub traces: Vec<ResidualFeatureTrace>,
}

#[cfg(feature = "std")]
pub fn compute_residuals(dataset: &PreparedDataset, nominal: &NominalModel) -> ResidualSet {
    let run_count = dataset.raw_values.len();
    let feature_count = dataset.feature_names.len();
    let mut traces = Vec::with_capacity(feature_count);

    for feature_index in 0..feature_count {
        let feature = &nominal.features[feature_index];
        let mut imputed_values = Vec::with_capacity(run_count);
        let mut residuals = Vec::with_capacity(run_count);
        let mut norms = Vec::with_capacity(run_count);
        let mut threshold_alarm = Vec::with_capacity(run_count);
        let mut is_imputed = Vec::with_capacity(run_count);

        for row in &dataset.raw_values {
            let is_missing = row[feature_index].is_none();
            let value = row[feature_index].unwrap_or(feature.healthy_mean);
            let residual = value - feature.healthy_mean;
            let norm = residual.abs();
            imputed_values.push(value);
            residuals.push(residual);
            norms.push(norm);
            threshold_alarm.push(feature.analyzable && norm > feature.rho);
            is_imputed.push(is_missing);
        }

        traces.push(ResidualFeatureTrace {
            feature_index,
            feature_name: feature.feature_name.clone(),
            imputed_values,
            residuals,
            norms,
            threshold_alarm,
            is_imputed,
        });
    }

    ResidualSet { traces }
}