use crate::numerics::linalg;
pub struct DetectionResult {
pub risk_score: f64,
pub clustering_detected: bool,
pub price_anomaly: bool,
pub confidence: f64,
}
pub fn detect(bids: &[f64], refs: &[f64]) -> DetectionResult {
let n = bids.len();
if n >= 3 {
let matrix: Vec<Vec<f64>> = bids.iter().map(|&b| vec![b, 1.0]).collect();
if let Ok(svd) = linalg::SVD::new().decompose(&matrix) {
let cn = if *svd.s.last().unwrap() > 0.0 { svd.s[0] / svd.s.last().unwrap() } else { 1e6 };
let mean_bid = bids.iter().sum::<f64>() / n as f64;
let mean_ref = refs.iter().sum::<f64>() / refs.len() as f64;
let dev = (mean_bid - mean_ref).abs() / mean_ref;
let clustering = cn > 100.0;
let anomaly = dev > 0.15;
let score = (cn.min(1e4) / 1e4 * 0.6 + dev.min(1.0) * 0.4).min(1.0);
let confidence = if clustering { 0.85 } else { 0.60 + score * 0.3 };
return DetectionResult {
risk_score: (score * 100.0).round() / 100.0,
clustering_detected: clustering,
price_anomaly: anomaly,
confidence,
};
}
}
DetectionResult { risk_score: 0.0, clustering_detected: false, price_anomaly: false, confidence: 0.5 }
}