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}