Skip to main content

Ensemble

Struct Ensemble 

Source
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

Source

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.

Source

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.

Source

pub fn seed(&self) -> u64

The seed every sample’s generator is derived from.

Source

pub fn count(&self) -> u64

How many samples.

Source

pub fn run<T, F>(&self, sample: F) -> Vec<T>
where F: Fn(u64, Rng) -> T + Sync, T: Send + Default + Clone,

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.

Source

pub fn estimate<F>(&self, sample: F) -> Option<Estimate>
where F: Fn(u64, Rng) -> f64 + Sync,

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.

Source

pub fn blocks<B, M, F>(&self, of_block: M, sample: &F) -> Vec<B>
where M: Fn(u64, u64, &F) -> B + Sync, B: Send + Default + Clone, F: Sync,

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.

Trait Implementations§

Source§

impl Clone for Ensemble

Source§

fn clone(&self) -> Ensemble

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for Ensemble

Source§

impl Debug for Ensemble

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for Ensemble

Source§

impl PartialEq for Ensemble

Source§

fn eq(&self, other: &Ensemble) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Ensemble

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.