use nalgebra::DMatrix;
use num_traits::Float;
use crate::regression::glm::link::{core::Link, identity::Identity, log::Log};
#[derive(Clone, Debug)]
pub struct Power {
lambda: f64,
}
impl Default for Power {
fn default() -> Power {
Self { lambda: 1.0 }.with_lambda(1.0)
}
}
impl Power {
pub fn new() -> Self {
Self::default()
}
pub fn with_lambda(self, lambda: f64) -> Self {
Self { lambda }
}
}
impl Link for Power {
fn link_func(&self, mu: &DMatrix<f64>) -> DMatrix<f64> {
if self.lambda <= 0.0 {
Log::new().link_func(mu)
} else if self.lambda == 1.0 {
Identity::new().link_func(mu)
} else {
let mut ret = mu.clone();
ret.iter_mut().for_each(|mu| *mu = mu.powf(self.lambda));
ret
}
}
fn link_inverse(&self, eta: &DMatrix<f64>) -> DMatrix<f64> {
if self.lambda <= 0.0 {
Log::new().link_inverse(eta)
} else if self.lambda == 1.0 {
Identity::new().link_inverse(eta)
} else {
let mut ret = eta.clone();
ret.iter_mut()
.for_each(|eta| *eta = eta.powf(1.0 / self.lambda).max(f64::epsilon()));
ret
}
}
fn mu_eta(&self, eta: &DMatrix<f64>) -> DMatrix<f64> {
if self.lambda <= 0.0 {
Log::new().mu_eta(eta)
} else if self.lambda == 1.0 {
Identity::new().mu_eta(eta)
} else {
let mut ret = eta.clone();
ret.iter_mut().for_each(|eta| {
*eta = ((1.0 / self.lambda) * eta.powf(1.0 / self.lambda - 1.0)).max(f64::epsilon())
});
ret
}
}
fn valid_eta(&self, eta: &DMatrix<f64>) -> bool {
if self.lambda <= 0.0 {
Log::new().valid_eta(eta)
} else if self.lambda == 1.0 {
Identity::new().valid_eta(eta)
} else {
eta.iter().all(|&eta| eta.is_finite() && eta > 0.0)
}
}
}