use serde::{Deserialize, Serialize};
use crate::{Error, Result};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(try_from = "LogitNormalRepr")]
pub struct LogitNormalDensity {
location: f32,
scale: f32,
}
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct LogitNormalRepr {
location: f32,
scale: f32,
}
impl TryFrom<LogitNormalRepr> for LogitNormalDensity {
type Error = Error;
fn try_from(repr: LogitNormalRepr) -> Result<Self> {
Self::new(repr.location, repr.scale)
}
}
impl LogitNormalDensity {
pub const DEFAULT_LOCATION: f32 = 0.0;
pub const DEFAULT_SCALE: f32 = 1.0;
pub fn new(location: f32, scale: f32) -> Result<Self> {
if !location.is_finite() {
return Err(Error::validation(format!(
"logit-normal location must be finite, got {location}"
)));
}
if !scale.is_finite() || scale <= 0.0 {
return Err(Error::validation(format!(
"logit-normal scale must be finite and positive, got {scale}"
)));
}
Ok(Self { location, scale })
}
pub fn sample(&self, standard_normal: f32) -> f32 {
logistic(self.location + self.scale * standard_normal)
}
pub fn location(&self) -> f32 {
self.location
}
pub fn scale(&self) -> f32 {
self.scale
}
}
fn logistic(x: f32) -> f32 {
1.0 / (1.0 + (-x).exp())
}