use crate::{
integrators::{OrthotopeRandomIntegrator, DEFAULT_SAMPLE_COUNT},
MeanVariance, SolverError, SolverResult, VectorType,
};
use nalgebra::{allocator::Allocator, ComplexField, DefaultAllocator, Dim, Scalar};
use num_traits::Float;
use rand::Rng;
use rand_distr::{uniform::SampleUniform, Distribution, Uniform};
use std::marker::PhantomData;
pub struct MonteCarlo<F, V, T> {
f: F,
sample_count: usize,
t_phantom: PhantomData<T>,
v_phantom: PhantomData<V>,
}
impl<F, V, T> MonteCarlo<F, V, T>
where
T: Float,
F: Fn(V) -> T,
{
pub fn new(f: F) -> Self {
Self {
f,
sample_count: DEFAULT_SAMPLE_COUNT,
t_phantom: PhantomData,
v_phantom: PhantomData,
}
}
pub fn with_sample_count(&mut self, sample_count: usize) -> &mut Self {
self.sample_count = sample_count;
self
}
pub fn integrate_with_sampler(
&self,
mut sampler: impl FnMut() -> V,
volume: T,
) -> SolverResult<MeanVariance<T>> {
if volume < T::zero() {
return Err(SolverError::IncorrectInput {
details: "the input volume should be non-negative",
});
}
let mut sample_iterator = (0..self.sample_count).map(|_| (self.f)(sampler()));
MeanVariance::from_iterator_using_welford(&mut sample_iterator, true)
.map(|result| result.scale_mean(volume))
}
}
impl<F, T> OrthotopeRandomIntegrator<T, T> for MonteCarlo<F, T, T>
where
T: Float + SampleUniform,
F: Fn(T) -> T,
{
fn integrate_with_rng(
&self,
from: T,
to: T,
mut rng: &mut impl Rng,
) -> SolverResult<MeanVariance<T>> {
let uniform_sampler = Uniform::new_inclusive(from, to)
.map_err(|error| SolverError::ExternalError(error.to_string()))?;
let sampler = || uniform_sampler.sample(&mut rng);
self.integrate_with_sampler(sampler, to - from)
}
}
impl<F, T, D> OrthotopeRandomIntegrator<VectorType<T, D>, T> for MonteCarlo<F, VectorType<T, D>, T>
where
T: Float + Scalar + ComplexField<RealField = T> + SampleUniform,
D: Dim,
F: Fn(VectorType<T, D>) -> T,
DefaultAllocator: Allocator<D>,
{
fn integrate_with_rng(
&self,
from: VectorType<T, D>,
to: VectorType<T, D>,
mut rng: &mut impl Rng,
) -> SolverResult<MeanVariance<T>> {
let uniform_samplers = from
.iter()
.zip(to.iter())
.map(|(&x, &y)| Uniform::new_inclusive(x, y))
.collect::<Result<Vec<_>, _>>()
.map_err(|error| SolverError::ExternalError(error.to_string()))?;
let volume = (to - &from).product();
let sampler = || {
let mut vector = from.clone();
vector
.iter_mut()
.zip(uniform_samplers.iter())
.for_each(|(vector_i, sampler_i)| *vector_i = sampler_i.sample(&mut rng));
vector
};
self.integrate_with_sampler(sampler, volume)
}
}