use faer::linalg::solvers::DenseSolveCore;
use ndarray::{Array1, Array2};
use robust_rs_core::rho::RhoFunction;
use robust_rs_core::types::Scale;
const QUAD: usize = 128;
pub struct RegressionFit {
pub coefficients: Array1<f64>,
pub scale: Scale,
pub residuals: Array1<f64>,
pub weights: Array1<f64>,
pub rho: Box<dyn RhoFunction>,
pub breakdown_point: f64,
}
pub trait RobustEstimator {
fn coefficients(&self) -> &Array1<f64>;
fn scale(&self) -> Scale;
fn influence_function(&self) -> Box<dyn Fn(f64) -> f64 + '_>;
fn asymptotic_variance(&self) -> f64;
fn gaussian_efficiency(&self) -> f64;
fn coef_covariance(&self, x: &Array2<f64>) -> Array2<f64>;
fn breakdown_point(&self) -> f64;
}
impl RobustEstimator for RegressionFit {
fn coefficients(&self) -> &Array1<f64> {
&self.coefficients
}
fn scale(&self) -> Scale {
self.scale
}
fn influence_function(&self) -> Box<dyn Fn(f64) -> f64 + '_> {
Box::new(robust_rs_core::theory::influence_function(&*self.rho, QUAD))
}
fn asymptotic_variance(&self) -> f64 {
robust_rs_core::theory::asymptotic_variance(&*self.rho, QUAD)
}
fn gaussian_efficiency(&self) -> f64 {
robust_rs_core::theory::gaussian_efficiency(&*self.rho, QUAD)
}
fn coef_covariance(&self, x: &Array2<f64>) -> Array2<f64> {
let p = x.ncols();
let s = self.scale.get();
let factor = s * s * self.asymptotic_variance();
let xtx = x.t().dot(x);
let a = faer::Mat::from_fn(p, p, |i, j| xtx[[i, j]]);
let inv = a.partial_piv_lu().inverse();
Array2::from_shape_fn((p, p), |(i, j)| inv[(i, j)] * factor)
}
fn breakdown_point(&self) -> f64 {
self.breakdown_point
}
}