converge-analytics 3.7.2

Analytics and ML pipeline for Converge agents
Documentation
use super::types::*;
use converge_pack::gate::GateResult as Result;
use converge_pack::gate::{ProblemSpec, ReplayEnvelope, SolverReport};

pub struct ZScoreSolver;

impl ZScoreSolver {
    pub fn solve(
        &self,
        input: &AnomalyDetectionInput,
        spec: &ProblemSpec,
    ) -> Result<(AnomalyDetectionOutput, SolverReport)> {
        let n = input.values.len() as f64;
        let mean = input.values.iter().sum::<f64>() / n;
        let variance = input.values.iter().map(|v| (v - mean).powi(2)).sum::<f64>() / n;
        let std_dev = variance.sqrt();

        let anomalies = if std_dev > 0.0 {
            input
                .values
                .iter()
                .enumerate()
                .filter_map(|(i, &v)| {
                    let z = (v - mean).abs() / std_dev;
                    if z > input.threshold {
                        Some(AnomalyRecord {
                            index: i,
                            value: v,
                            z_score: z,
                            label: input.labels.as_ref().map(|l| l[i].clone()),
                        })
                    } else {
                        None
                    }
                })
                .collect()
        } else {
            vec![]
        };

        let anomaly_count = anomalies.len();
        let total_points = input.values.len();

        let output = AnomalyDetectionOutput {
            anomalies,
            mean,
            std_dev,
            total_points,
            anomaly_count,
        };

        let confidence = (1.0 - (anomaly_count as f64 / total_points as f64)).clamp(0.3, 0.95);

        let replay = ReplayEnvelope::minimal(spec.seed());
        let report = SolverReport::optimal("z-score-v1", confidence, replay);

        Ok((output, report))
    }
}