use crate::error::RobustError;
use crate::rho::RhoFunction;
#[derive(Debug, Clone, Copy)]
pub struct Huber {
k: f64,
}
impl Huber {
pub fn new(k: f64) -> Result<Self, RobustError> {
if k.is_finite() && k > 0.0 {
Ok(Self { k })
} else {
Err(RobustError::InvalidTuning { value: k })
}
}
}
impl Default for Huber {
fn default() -> Self {
Self { k: 1.345 }
}
}
impl RhoFunction for Huber {
fn rho(&self, r: f64) -> f64 {
if r.abs() <= self.k {
r.powi(2) / 2.0
} else {
self.k * r.abs() - self.k.powi(2) / 2.0
}
}
fn psi(&self, r: f64) -> f64 {
r.clamp(-self.k, self.k)
}
fn weight(&self, r: f64) -> f64 {
if r == 0.0 {
1.0
} else {
(self.k / r.abs()).min(1.0)
}
}
fn psi_prime(&self, r: f64) -> f64 {
if r.abs() <= self.k {
1.0
} else {
0.0
}
}
fn tuning(&self) -> f64 {
self.k
}
fn is_redescending(&self) -> bool {
false
}
fn rho_sup(&self) -> Option<f64> {
None
}
}