pub struct Ensemble { /* private fields */ }Expand description
A set of independent samples to run.
Cheap to build and to copy; it holds a seed, a count and a thread count, and does the work in
Ensemble::run.
Implementations§
Source§impl Ensemble
impl Ensemble
Sourcepub fn new(seed: u64, count: u64) -> Ensemble
pub fn new(seed: u64, count: u64) -> Ensemble
count samples, each drawing from Rng::for_index(seed, i).
Sequential until with_threads says otherwise, which is the
right default: threads are a performance decision and this crate does not make those for
a caller who has not asked.
Sourcepub fn with_threads(self, threads: usize) -> Ensemble
pub fn with_threads(self, threads: usize) -> Ensemble
How many threads to spread the samples over. 1 is sequential.
The answer does not change. That is the whole point, and it is asserted rather than asserted-in-prose: a test runs the same ensemble at one, three and sixteen threads and compares the results bit for bit. If you find a thread count that changes an answer, the sample closure is reading something it does not own.
Clamped to at least one, and never more than there are samples.
Sourcepub fn run<T, F>(&self, sample: F) -> Vec<T>
pub fn run<T, F>(&self, sample: F) -> Vec<T>
Run every sample and collect the results in index order.
The closure receives the sample’s index and its own generator. Give it everything else it
needs by capture; it must not mutate shared state, and Fn rather than FnMut is how
that is enforced rather than requested.
Index order matters more than it looks. A caller folding the result — a mean, a variance, a histogram — folds in that order whatever the thread count was, so the floating-point sum is the same sum. Collecting into a shared accumulator instead would make the answer depend on which thread finished first, in the last bits, invisibly.
Sourcepub fn estimate<F>(&self, sample: F) -> Option<Estimate>
pub fn estimate<F>(&self, sample: F) -> Option<Estimate>
Run every sample and reduce to a mean and a standard error, folded in index order.
The two numbers a Monte Carlo study is usually for: the estimate, and how much to trust
it. The standard error is s/√N with the sample standard deviation, so it falls as
1/√N — which is the rate this workspace asks a tolerance to be earned against, and the
reason samples is reported beside it rather than left implicit.
Returns None for fewer than two samples, because a variance over one is not a small
number, it is not defined.
Sourcepub fn blocks<B, M, F>(&self, of_block: M, sample: &F) -> Vec<B>
pub fn blocks<B, M, F>(&self, of_block: M, sample: &F) -> Vec<B>
Run the samples in fixed-size blocks and return one value per block.
The block size does not depend on the thread count, and that is the whole reason for
it. A reduction split per thread combines a different number of partial sums on four
cores than on sixteen, and floating-point addition is not associative, so the answer
moves — quietly, in the last bits, looking like nothing. Splitting per fixed block makes
the association a function of count alone.
A caller wanting a reduction this crate does not provide — a histogram, a maximum, a quantile — should build it here for the same reason.