use crate::continuous::integrate::{default_quad_tol, integrate_fn};
use crate::continuous::sampler::ContinuousSampler;
use crate::continuous::CdfSource;
use crate::error::SampleError;
impl<D> ContinuousSampler<D>
where
D: CdfSource,
{
pub fn pdf(&self, x: f64) -> Option<f64> {
self.pdf_at(x)
}
pub fn logpdf(&self, x: f64) -> Option<f64> {
self.pdf(x).and_then(|p| {
if p > 0.0 {
Some(p.ln())
} else {
None
}
})
}
pub fn logcdf(&self, x: f64) -> f64 {
let p = self.cdf(x).clamp(0.0, 1.0);
if p <= 0.0 {
f64::NEG_INFINITY
} else {
p.ln()
}
}
pub fn sf(&self, x: f64) -> f64 {
let p = self.cdf(x);
(1.0 - p).max(0.0)
}
pub fn logsf(&self, x: f64) -> f64 {
let p = self.cdf(x).clamp(0.0, 1.0);
if p >= 1.0 {
f64::NEG_INFINITY
} else {
(1.0 - p).ln()
}
}
pub fn isf(&self, q: f64) -> Result<f64, SampleError> {
self.ppf(1.0 - q)
}
pub fn median(&self) -> Result<f64, SampleError> {
self.ppf(0.5)
}
pub fn mean(&self) -> Result<f64, SampleError> {
self.expect(|x| x, default_quad_tol())
}
pub fn var(&self) -> Result<f64, SampleError> {
let m = self.mean()?;
let m2 = self.expect(|x| x * x, default_quad_tol())?;
Ok((m2 - m * m).max(0.0))
}
pub fn std(&self) -> Result<f64, SampleError> {
Ok(self.var()?.sqrt())
}
pub fn entropy(&self) -> Result<f64, SampleError> {
let support = self.support();
let tol = default_quad_tol();
let h = integrate_fn(
&|x| {
self.pdf(x)
.filter(|&p| p > 0.0)
.map(|p| -p * p.ln())
.unwrap_or(0.0)
},
support.lo,
support.hi,
tol,
);
if h.is_finite() {
Ok(h)
} else {
Err(SampleError::IntegrationFailed)
}
}
pub fn expect(&self, func: impl Fn(f64) -> f64, tol: f64) -> Result<f64, SampleError> {
if !self.has_pdf() {
return Err(SampleError::PdfRequired);
}
let support = self.support();
let m = integrate_fn(
&|x| {
self.pdf(x)
.map(|p| func(x) * p)
.unwrap_or(0.0)
},
support.lo,
support.hi,
tol,
);
if m.is_finite() {
Ok(m)
} else {
Err(SampleError::IntegrationFailed)
}
}
pub fn interval(&self, confidence: f64) -> Result<(f64, f64), SampleError> {
if !(confidence > 0.0 && confidence < 1.0) {
return Err(SampleError::InvalidConfidence { confidence });
}
let tail = 0.5 * (1.0 - confidence);
let lo = self.ppf(tail)?;
let hi = self.ppf(1.0 - tail)?;
Ok((lo, hi))
}
}