1use faer::linalg::solvers::DenseSolveCore;
5use ndarray::{Array1, Array2};
6use robust_rs_core::rho::RhoFunction;
7use robust_rs_core::types::Scale;
8
9const QUAD: usize = 128;
10
11pub struct RegressionFit {
13 pub coefficients: Array1<f64>,
15 pub scale: Scale,
17 pub residuals: Array1<f64>,
19 pub weights: Array1<f64>,
21 pub rho: Box<dyn RhoFunction>,
25 pub breakdown_point: f64,
30}
31
32pub trait RobustEstimator {
34 fn coefficients(&self) -> &Array1<f64>;
36 fn scale(&self) -> Scale;
38 fn influence_function(&self) -> Box<dyn Fn(f64) -> f64 + '_>;
40 fn asymptotic_variance(&self) -> f64;
42 fn gaussian_efficiency(&self) -> f64;
44 fn coef_covariance(&self, x: &Array2<f64>) -> Array2<f64>;
46 fn breakdown_point(&self) -> f64;
48}
49
50impl RobustEstimator for RegressionFit {
51 fn coefficients(&self) -> &Array1<f64> {
52 &self.coefficients
53 }
54 fn scale(&self) -> Scale {
55 self.scale
56 }
57 fn influence_function(&self) -> Box<dyn Fn(f64) -> f64 + '_> {
58 Box::new(robust_rs_core::theory::influence_function(&*self.rho, QUAD))
59 }
60 fn asymptotic_variance(&self) -> f64 {
61 robust_rs_core::theory::asymptotic_variance(&*self.rho, QUAD)
62 }
63 fn gaussian_efficiency(&self) -> f64 {
64 robust_rs_core::theory::gaussian_efficiency(&*self.rho, QUAD)
65 }
66 fn coef_covariance(&self, x: &Array2<f64>) -> Array2<f64> {
67 let p = x.ncols();
68 let s = self.scale.get();
69 let factor = s * s * self.asymptotic_variance();
70
71 let xtx = x.t().dot(x);
73 let a = faer::Mat::from_fn(p, p, |i, j| xtx[[i, j]]);
74 let inv = a.partial_piv_lu().inverse();
75
76 Array2::from_shape_fn((p, p), |(i, j)| inv[(i, j)] * factor)
77 }
78 fn breakdown_point(&self) -> f64 {
79 self.breakdown_point
80 }
81}