1use crate::error::{RillError, ensure_finite_target};
6
7#[derive(Debug, Clone, Default)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct SquaredError;
11
12impl SquaredError {
13 pub const fn new() -> Self {
15 Self
16 }
17
18 pub fn loss(prediction: f64, target: f64) -> f64 {
20 let diff = prediction - target;
21 0.5 * diff * diff
22 }
23
24 pub fn gradient(prediction: f64, target: f64) -> f64 {
26 prediction - target
27 }
28
29 pub fn validate(prediction: f64, target: f64) -> Result<(), RillError> {
31 crate::error::ensure_finite("prediction", prediction)?;
32 ensure_finite_target(target)
33 }
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 #[test]
41 fn loss_at_zero_residual_is_zero() {
42 assert_eq!(SquaredError::loss(5.0, 5.0), 0.0);
43 }
44
45 #[test]
46 fn loss_value() {
47 assert!((SquaredError::loss(3.0, 1.0) - 2.0).abs() < 1e-12);
48 }
49
50 #[test]
51 fn gradient_sign() {
52 assert!((SquaredError::gradient(3.0, 1.0) - 2.0).abs() < 1e-12);
53 assert!((SquaredError::gradient(1.0, 3.0) + 2.0).abs() < 1e-12);
54 }
55}