#![doc = include_str!("../README.md")]
mod domain;
mod macros;
mod multinormal;
mod multivariate;
mod particle;
mod univariate;
#[cfg(feature = "pyo3")]
pub mod pytypes;
#[cfg(test)]
mod tests;
pub use domain::Domain;
pub use multinormal::MultivariateNormalDensity;
pub use multivariate::MultivariateDensity;
pub use particle::ParticleDensity;
pub use univariate::{
ConstantDensity, CosineDensity, LogUniformDensity, LognormalDensity, NormalDensity,
UniformDensity, UnivariateDensity,
};
use nalgebra::{DefaultAllocator, Dim, OVector, RealField, VectorView, allocator::Allocator};
use rand::RngExt;
use serde::{Deserialize, Serialize};
pub trait Density<T, D>: Clone
where
T: RealField,
D: Dim,
{
fn density<RStride: Dim, CStride: Dim>(
&self,
sample: &VectorView<T, D, RStride, CStride>,
) -> Option<T>;
fn domain(&self) -> Domain<T, D>
where
DefaultAllocator: Allocator<D>;
fn mean(&self) -> OVector<T, D>
where
DefaultAllocator: Allocator<D>;
fn ndims(&self) -> usize where DefaultAllocator: Allocator<D> {
self.domain().shape_generic().value()
}
fn sample(&self, rng: &mut impl RngExt, mode: &SamplingMode) -> Option<OVector<T, D>>
where
DefaultAllocator: Allocator<D>;
fn sample_iter(&self, rng: &mut impl RngExt) -> impl Iterator<Item = Option<OVector<T, D>>>
where
DefaultAllocator: Allocator<D>;
fn variance(&self) -> OVector<T, D>
where
DefaultAllocator: Allocator<D>;
}
impl<T, D, G> Density<T, D> for &G
where
T: RealField,
D: Dim,
G: Density<T, D>,
{
fn density<RStride: Dim, CStride: Dim>(
&self,
sample: &VectorView<T, D, RStride, CStride>,
) -> Option<T> {
(**self).density(sample)
}
fn domain(&self) -> Domain<T, D>
where
DefaultAllocator: Allocator<D>,
{
(**self).domain()
}
fn mean(&self) -> OVector<T, D>
where
DefaultAllocator: Allocator<D>,
{
(**self).mean()
}
fn sample(&self, rng: &mut impl RngExt, mode: &SamplingMode) -> Option<OVector<T, D>>
where
DefaultAllocator: Allocator<D>,
{
(**self).sample(rng, mode)
}
fn sample_iter(&self, rng: &mut impl RngExt) -> impl Iterator<Item = Option<OVector<T, D>>>
where
DefaultAllocator: Allocator<D>,
{
(**self).sample_iter(rng)
}
fn variance(&self) -> OVector<T, D>
where
DefaultAllocator: Allocator<D>,
{
(**self).variance()
}
}
pub trait RejectionSampler<T, D>: Density<T, D>
where
T: RealField,
D: Dim,
{
fn generate_candidate(&self, rng: &mut impl RngExt) -> OVector<T, D>
where
DefaultAllocator: Allocator<D>;
fn rejection_sample(&self, rng: &mut impl RngExt, mode: &SamplingMode) -> Option<OVector<T, D>>
where
DefaultAllocator: Allocator<D>,
{
let mut attempts = 0;
loop {
let candidate = self.generate_candidate(rng);
if self.domain().contains(&candidate.as_view()) {
return Some(candidate);
}
match mode {
SamplingMode::SingleAttempt => return None,
SamplingMode::UntilValid { max_attempts } => {
if attempts >= *max_attempts {
return None;
}
attempts += 1;
}
SamplingMode::UntilValidNoLimit => {
attempts += 1;
}
SamplingMode::UntilValidOrClamp { max_attempts } => {
if attempts >= *max_attempts {
return Some(self.domain().clamp(&candidate.as_view()));
}
attempts += 1;
}
}
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum SamplingMode {
SingleAttempt,
UntilValid {
max_attempts: usize,
},
UntilValidOrClamp {
max_attempts: usize,
},
UntilValidNoLimit,
}
impl Default for SamplingMode {
fn default() -> Self {
SamplingMode::UntilValid { max_attempts: 512 }
}
}