use core::fmt;
pub type PowerLawRange = (f64, f64);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PowerLawDecay {
pub k: f64,
pub alpha: f64,
pub range: Option<PowerLawRange>,
}
impl PowerLawDecay {
pub fn new(k: f64, alpha: f64, range: Option<PowerLawRange>) -> Result<Self, PowerLawError> {
let payload = Self { k, alpha, range };
payload.validate()?;
Ok(payload)
}
pub fn validate(&self) -> Result<(), PowerLawError> {
if !self.k.is_finite() {
return Err(PowerLawError::InvalidStrength { k: self.k });
}
if !self.alpha.is_finite() {
return Err(PowerLawError::InvalidExponent { alpha: self.alpha });
}
if let Some((min, max)) = self.range {
if !min.is_finite() || !max.is_finite() || min < 0.0 || max < min {
return Err(PowerLawError::InvalidRange { min, max });
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum PowerLawError {
InvalidStrength {
k: f64,
},
InvalidExponent {
alpha: f64,
},
InvalidRange {
min: f64,
max: f64,
},
}
impl fmt::Display for PowerLawError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidStrength { k } => {
write!(f, "power-law strength must be finite; got {k}")
}
Self::InvalidExponent { alpha } => {
write!(f, "power-law exponent must be finite; got {alpha}")
}
Self::InvalidRange { min, max } => write!(
f,
"power-law active range must satisfy finite 0 <= min <= max; got min={min}, max={max}"
),
}
}
}
impl std::error::Error for PowerLawError {}