use std::fmt;
use crate::api::context::Context;
use crate::api::expr::{BoolEx, Ex};
use crate::base::errors::SymplexError;
use super::events::event_region;
use super::family::Distribution;
use super::sample::Rng;
use super::support::Support;
#[derive(Clone, Debug)]
pub struct RandomVariable {
symbol: Ex,
dist: Distribution,
}
impl RandomVariable {
pub fn new(ctx: &Context, name: &str, dist: Distribution) -> Self {
let symbol = ctx.symbol(name);
if let Some((_, first)) = dist.parameters().first() {
let _ = symbol.checked_id(first);
}
RandomVariable { symbol, dist }
}
pub fn try_new(ctx: &Context, name: &str, dist: Distribution) -> Result<Self, SymplexError> {
if dist.context().id != ctx.id {
return Err(SymplexError::invalid_argument(
"RandomVariable::new",
"the distribution's parameters live in another context",
));
}
Ok(RandomVariable {
symbol: ctx.symbol(name),
dist,
})
}
pub(crate) fn with_symbol(symbol: Ex, dist: Distribution) -> Self {
RandomVariable { symbol, dist }
}
pub fn symbol(&self) -> &Ex {
&self.symbol
}
pub fn distribution(&self) -> &Distribution {
&self.dist
}
pub fn context(&self) -> Context {
self.symbol.context()
}
pub fn support(&self) -> Support {
self.dist.support()
}
pub fn density(&self, var: &Ex) -> Ex {
self.dist.density(var)
}
pub fn mean(&self) -> Ex {
self.dist.mean()
}
pub fn variance(&self) -> Ex {
self.dist.variance()
}
pub fn std(&self) -> Ex {
self.dist.std()
}
pub fn moment(&self, n: u32) -> Ex {
self.dist.moment(n)
}
pub fn central_moment(&self, n: u32) -> Ex {
self.dist.central_moment(n)
}
pub fn skewness(&self) -> Ex {
self.dist.skewness()
}
pub fn kurtosis(&self) -> Ex {
self.dist.kurtosis()
}
pub fn cdf(&self, var: &Ex) -> Ex {
self.dist.cdf(var)
}
pub fn mgf(&self, t: &Ex) -> Ex {
self.dist.mgf(t)
}
pub fn characteristic_function(&self, t: &Ex) -> Ex {
self.dist.characteristic_function(t)
}
pub fn quantile(&self, p: &Ex) -> Option<Ex> {
self.dist.quantile(p)
}
pub fn median(&self) -> Option<Ex> {
self.dist.median()
}
pub fn entropy(&self) -> Ex {
self.dist.entropy()
}
pub fn expectation(&self, g: &Ex) -> Ex {
self.dist.expectation(g, &self.symbol)
}
pub fn event_region(&self, event: &BoolEx) -> Result<Support, SymplexError> {
let _ = self.symbol.checked_id(event);
event_region(&self.symbol, event)
}
pub fn probability(&self, event: &BoolEx) -> Result<Ex, SymplexError> {
let region = self.event_region(event)?;
self.dist.probability_of(®ion)
}
pub fn given(&self, event: &BoolEx) -> Result<RandomVariable, SymplexError> {
let region = self.event_region(event)?;
let dist = self.dist.truncated(®ion)?;
Ok(RandomVariable::with_symbol(self.symbol.clone(), dist))
}
pub fn transform(&self, name: &str, g: &Ex) -> Result<RandomVariable, SymplexError> {
let _ = self.symbol.checked_id(g);
let dist = self.dist.transformed(&self.symbol, g)?;
Ok(RandomVariable::with_symbol(
self.context().symbol(name),
dist,
))
}
pub fn sample(&self, n: usize, rng: &mut Rng) -> Result<Vec<f64>, SymplexError> {
self.dist.sample(n, rng)
}
pub fn sample_one(&self, rng: &mut Rng) -> Result<f64, SymplexError> {
self.dist.sample_one(rng)
}
}
impl fmt::Display for RandomVariable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} ~ {}", self.symbol, self.dist)
}
}