use rand::prelude::*;
use crate::{
models::{BN, CatBN, CatSupport},
random::{Random, RngCatCPD, RngDag},
set,
types::{Error, Labels, Result},
};
pub struct RngCatBN<'a, R>
where
R: Rng,
{
rng: &'a mut R,
support: &'a CatSupport,
alpha: f64,
probability: f64,
}
impl<'a, R> RngCatBN<'a, R>
where
R: Rng,
{
pub fn new(
rng: &'a mut R,
support: &'a CatSupport,
alpha: f64,
probability: f64,
) -> Result<Self> {
if alpha <= 0.0 {
return Err(Error::InvalidParameter("alpha", "must be positive"));
}
if !(0.0..=1.0).contains(&probability) {
return Err(Error::InvalidParameter("p", "must be in [0, 1]"));
}
Ok(Self {
rng,
support,
alpha,
probability,
})
}
}
impl<R> Random for RngCatBN<'_, R>
where
R: Rng,
{
type Output = Result<CatBN>;
fn random(&mut self) -> Self::Output {
let labels: Labels = self.support.keys().cloned().collect();
let graph = RngDag::new(self.rng, &labels, self.probability)?.random()?;
let cpds = labels
.iter()
.enumerate()
.map(|(i, x)| {
let pa_i = graph.parents(&set![i])?;
let mut support = CatSupport::default();
support.insert(x.clone(), self.support[x].clone());
let conditioning_support = pa_i
.iter()
.map(|&j| {
let y = &labels[j];
(y.clone(), self.support[y].clone())
})
.collect();
RngCatCPD::new(self.rng, &support, &conditioning_support, self.alpha)?.random()
})
.collect::<Result<Vec<_>>>()?;
CatBN::new(graph, cpds)
}
}