robust_rs_core/rho/
huber.rs1use crate::error::RobustError;
4use crate::rho::RhoFunction;
5
6#[derive(Debug, Clone, Copy)]
9pub struct Huber {
10 k: f64,
11}
12
13impl Huber {
14 pub fn new(k: f64) -> Result<Self, RobustError> {
16 if k.is_finite() && k > 0.0 {
17 Ok(Self { k })
18 } else {
19 Err(RobustError::InvalidTuning { value: k })
20 }
21 }
22}
23
24impl Default for Huber {
25 fn default() -> Self {
27 Self { k: 1.345 }
28 }
29}
30
31impl RhoFunction for Huber {
32 fn rho(&self, r: f64) -> f64 {
33 if r.abs() <= self.k {
34 r.powi(2) / 2.0
35 } else {
36 self.k * r.abs() - self.k.powi(2) / 2.0
37 }
38 }
39 fn psi(&self, r: f64) -> f64 {
40 r.clamp(-self.k, self.k)
41 }
42 fn weight(&self, r: f64) -> f64 {
43 if r == 0.0 {
44 1.0
45 } else {
46 (self.k / r.abs()).min(1.0)
47 }
48 }
49 fn psi_prime(&self, r: f64) -> f64 {
50 if r.abs() <= self.k {
51 1.0
52 } else {
53 0.0
54 }
55 }
56 fn tuning(&self) -> f64 {
57 self.k
58 }
59 fn is_redescending(&self) -> bool {
60 false
61 }
62 fn rho_sup(&self) -> Option<f64> {
63 None
64 }
65}