use crate::core::Error;
#[derive(Debug, Clone, PartialEq)]
pub enum Loss {
L2Squared,
L1,
LInf,
Huber { delta: f64 },
}
impl Loss {
pub fn validate(&self) -> Result<(), Error> {
match self {
Self::Huber { delta } if *delta <= 0.0 => Err(Error::InvalidParameter {
message: "Huber delta must be strictly positive".to_string(),
}),
_ => Ok(()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn l2_squared_validates() {
assert!(Loss::L2Squared.validate().is_ok());
}
#[test]
fn l1_validates() {
assert!(Loss::L1.validate().is_ok());
}
#[test]
fn linf_validates() {
assert!(Loss::LInf.validate().is_ok());
}
#[test]
fn huber_positive_validates() {
assert!(Loss::Huber { delta: 1.5 }.validate().is_ok());
}
#[test]
fn huber_zero_rejects() {
let err = Loss::Huber { delta: 0.0 }.validate().unwrap_err();
match err {
Error::InvalidParameter { message } => assert!(message.contains("Huber")),
other => panic!("unexpected: {:?}", other),
}
}
#[test]
fn huber_negative_rejects() {
assert!(Loss::Huber { delta: -1.0 }.validate().is_err());
}
#[test]
fn clone_and_eq() {
assert_eq!(Loss::L2Squared, Loss::L2Squared.clone());
assert_ne!(Loss::L1, Loss::L2Squared);
}
}