eqsolver/integrators/
mod.rs

1mod adaptive_newton_cotes;
2mod miser;
3mod monte_carlo;
4mod newton_cotes;
5
6pub use adaptive_newton_cotes::AdaptiveNewtonCotes;
7pub use miser::MISER;
8pub use monte_carlo::MonteCarlo;
9pub use newton_cotes::{Formula, NewtonCotes, DEFAULT_SUBDIVISIONS};
10
11use crate::{MeanVariance, SolverResult};
12use rand::{rng, Rng};
13
14/// Default number of cuts the interval is split in during adaptive integration methods
15pub const DEFAULT_MAXIMUM_CUT_COUNT: usize = 1000;
16
17/// Default number of samples drawn during Monte Carlo integration algorithms
18pub const DEFAULT_SAMPLE_COUNT: usize = 1000;
19
20/// Orthotope Random Integrator
21///
22/// Provides an interface for Monte Carlo-like integrators that use randomness to evaluate
23/// integrals over `[a1, b1] x [a2, b2] x ... x [an, bn]` for `a1, ..., an, b1, ..., bn ∈ Rn`.
24/// The randomness can be controlled using by providing a `rand::Rng`, otherwise, the default is
25/// `rand::rng()` (previously known as `rand::thread_rng()`.
26pub trait OrthotopeRandomIntegrator<V, T> {
27    /// Run the integrator over an interval or a Cartesian product of intervals. Represented as
28    /// either a `Float` or a `nalgebra::Vector`. Since the integrator is random, a random number
29    /// generator is also an input to this function of type `rng::Rng`.
30    ///
31    /// ## Examples
32    ///
33    /// ### 1D Monte Carlo
34    /// ```
35    /// use eqsolver::integrators::{OrthotopeRandomIntegrator, MonteCarlo};
36    /// use rand_chacha::{ChaCha8Rng, rand_core::SeedableRng}; // or any rng you like
37    /// const SOLUTION: f64 = 0.746824132812427025;
38    /// let mut rng = ChaCha8Rng::seed_from_u64(1729);
39    /// let f = |x: f64| (-x * x).exp();
40    /// let result = MonteCarlo::new(f).integrate_with_rng(0., 1., &mut rng);
41    /// assert!((result.unwrap().mean - SOLUTION).abs() <= 0.1);
42    /// ```
43    ///
44    /// ### 2D Monte Carlo
45    /// ```
46    /// use eqsolver::integrators::{OrthotopeRandomIntegrator, MonteCarlo};
47    /// use nalgebra::{Vector2, vector};
48    /// use rand_chacha::{ChaCha8Rng, rand_core::SeedableRng}; // or any rng you like
49    /// const SOLUTION: f64 = 0.9248464799519;
50    /// let mut rng = ChaCha8Rng::seed_from_u64(1729);
51    /// let f = |v: Vector2<f64>| (v[1].cos() + v[0]).sin();
52    /// let result = MonteCarlo::new(f)
53    ///     .integrate_with_rng(vector![0., 0.], vector![1., 1.], &mut rng);
54    /// assert!((result.unwrap().mean - SOLUTION).abs() <= 0.1);
55    /// ```
56    fn integrate_with_rng(
57        &self,
58        from: V,
59        to: V,
60        rng: &mut impl Rng,
61    ) -> SolverResult<MeanVariance<T>>;
62
63    /// Run the integrator over an interval or a Cartesian product of intervals using the
64    /// `rand::rng()` as the underlying random number generator. The output of this function is the
65    /// mean and variance of the output of the randomised integration algorithm represented as a
66    /// [`MeanVariance`].
67    ///
68    /// This function is equivalent to
69    /// ```ignore
70    /// OrthotopeRandomIntegrator::integrate_with_rng(from, to, &mut rng())
71    /// ```
72    /// i.e. the RNG used is
73    /// `rand::rng()` (formerly known as `thread_rng()`). Therefore, for examples, please read the
74    /// docstring of [`OrthotopeRandomIntegrator::integrate_with_rng`].
75    fn integrate_to_mean_variance(&self, from: V, to: V) -> SolverResult<MeanVariance<T>> {
76        self.integrate_with_rng(from, to, &mut rng())
77    }
78
79    /// Run the integrator over an interval or a Cartesian product of intervals using `rand::rng()`
80    /// as the underlying random number generator and return only the mean.
81    ///
82    /// This function is equivalent to
83    /// ```ignore
84    /// OrthotopeRandomIntegrator::integrate_to_mean_variance(from, to)
85    ///                           .map(|result| result.mean)
86    /// ```
87    /// which in turn is equivalent to
88    /// ```ignore
89    /// OrthotopeRandomIntegrator::integrate_with_rng(from, to, &mut rng())
90    ///                           .map(|result| result.mean)
91    /// ```
92    /// Therefore, for details and examples, please read the docstring of
93    /// [`OrthotopeRandomIntegrator::integrate_with_rng`] and
94    /// [`OrthotopeRandomIntegrator::integrate_to_mean_variance`]
95    fn integrate(&self, from: V, to: V) -> SolverResult<T> {
96        self.integrate_to_mean_variance(from, to)
97            .map(|result| result.mean)
98    }
99}