use super::rngtraits::SequenceGenerator;
use super::{Seeded, UniformRng};
use crate::errors::QlResult;
use crate::math::distributions::normal::InverseCumulativeNormal;
use crate::math::distributions::poisson::InverseCumulativePoisson;
use crate::math::distributions::{Probability, Quantile};
use crate::methods::montecarlo::Sample;
use crate::require;
use crate::types::Real;
pub trait FallibleInverseCumulative {
fn try_evaluate(&self, uniform: Real) -> QlResult<Real>;
}
impl FallibleInverseCumulative for InverseCumulativeNormal {
fn try_evaluate(&self, uniform: Real) -> QlResult<Real> {
require!(
uniform > 0.0 && uniform < 1.0,
"normal uniform must lie in (0, 1)"
);
self.value(uniform)
}
}
impl FallibleInverseCumulative for InverseCumulativePoisson {
fn try_evaluate(&self, uniform: Real) -> QlResult<Real> {
require!(
(0.0..1.0).contains(&uniform),
"Poisson uniform must lie in [0, 1)"
);
self.quantile(Probability::try_from(uniform)?)
}
}
#[derive(Clone)]
pub struct InverseCumulativeRng<R, IC> {
uniform: R,
inverse: IC,
}
impl<R: UniformRng, IC: FallibleInverseCumulative> InverseCumulativeRng<R, IC> {
pub fn new(uniform: R, inverse: IC) -> Self {
Self { uniform, inverse }
}
pub fn next_sample(&mut self) -> QlResult<Sample<Real>> {
Ok(Sample::new(
self.inverse.try_evaluate(self.uniform.next_real())?,
1.0,
))
}
}
impl<R: Seeded, IC> Seeded for InverseCumulativeRng<R, IC> {
type Seed = R::Seed;
fn seed(&self) -> R::Seed {
self.uniform.seed()
}
}
#[derive(Clone)]
pub struct FallibleInverseCumulativeRsg<USG, IC> {
uniform: USG,
inverse: IC,
last: Sample<Vec<Real>>,
}
impl<USG: SequenceGenerator, IC: FallibleInverseCumulative> FallibleInverseCumulativeRsg<USG, IC> {
pub fn new(uniform: USG, inverse: IC) -> Self {
let last = Sample::new(vec![0.0; uniform.dimension()], 1.0);
Self {
uniform,
inverse,
last,
}
}
pub fn next_sequence(&mut self) -> QlResult<&Sample<Vec<Real>>> {
let sample = self.uniform.next_sequence();
let value = sample
.value
.iter()
.map(|&x| self.inverse.try_evaluate(x))
.collect::<QlResult<Vec<_>>>()?;
self.last = Sample::new(value, sample.weight);
Ok(&self.last)
}
pub fn last_sequence(&self) -> &Sample<Vec<Real>> {
&self.last
}
pub fn dimension(&self) -> usize {
self.uniform.dimension()
}
}
impl<USG: Seeded, IC> Seeded for FallibleInverseCumulativeRsg<USG, IC> {
type Seed = USG::Seed;
fn seed(&self) -> USG::Seed {
self.uniform.seed()
}
}