use crate::types::{InverseLink, LikelihoodSpec, LinkFunction, ResponseFamily};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnsupportedLinkError {
pub family: &'static str,
pub link_name: String,
}
impl UnsupportedLinkError {
#[inline]
pub fn new(family: &'static str, link: &InverseLink) -> Self {
Self {
family,
link_name: inverse_link_diagnostic_name(link),
}
}
}
impl std::fmt::Display for UnsupportedLinkError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"inverse link `{}` is not supported by the {} response family",
self.link_name, self.family
)
}
}
impl std::error::Error for UnsupportedLinkError {}
#[inline]
fn inverse_link_diagnostic_name(link: &InverseLink) -> String {
match link {
InverseLink::Standard(lf) => lf.name().to_string(),
InverseLink::LatentCLogLog(_) => "latent-cloglog".to_string(),
InverseLink::Sas(_) => "sas".to_string(),
InverseLink::BetaLogistic(_) => "beta-logistic".to_string(),
InverseLink::Mixture(_) => "mixture".to_string(),
}
}
#[inline]
pub const fn likelihood_spec(response: ResponseFamily, link: InverseLink) -> LikelihoodSpec {
LikelihoodSpec::new(response, link)
}
#[inline]
pub fn inverse_link_to_binomial_spec(
link: &InverseLink,
) -> Result<LikelihoodSpec, UnsupportedLinkError> {
match link {
InverseLink::Standard(LinkFunction::Logit)
| InverseLink::Standard(LinkFunction::Probit)
| InverseLink::Standard(LinkFunction::CLogLog) => {
Ok(LikelihoodSpec::new(ResponseFamily::Binomial, link.clone()))
}
InverseLink::LatentCLogLog(_)
| InverseLink::Sas(_)
| InverseLink::BetaLogistic(_)
| InverseLink::Mixture(_) => {
Ok(LikelihoodSpec::new(ResponseFamily::Binomial, link.clone()))
}
InverseLink::Standard(LinkFunction::Log)
| InverseLink::Standard(LinkFunction::Identity)
| InverseLink::Standard(LinkFunction::Sas)
| InverseLink::Standard(LinkFunction::BetaLogistic) => {
Err(UnsupportedLinkError::new("binomial", link))
}
}
}