Skip to main content

Sampler

Trait Sampler 

pub trait Sampler: Send + Sync {
    // Required methods
    fn infer_relative_space(&self, study: &StudyView) -> Result<SpaceSchema>;
    fn sample_relative(
        &self,
        study: &StudyView,
        trial: &TrialMeta,
        space: &SpaceSchema,
    ) -> Result<Assignment>;
    fn sample_independent(
        &self,
        study: &StudyView,
        trial: &TrialMeta,
        name: &str,
        dist: &Distribution,
    ) -> Result<ParamValue>;
    fn reseed(&self, seed: u64);

    // Provided methods
    fn after_trial(&self, study: &StudyView, trial: &FrozenTrial) -> Result<()> { ... }
    fn state(&self) -> Result<Option<SamplerState>> { ... }
    fn snapshots_space(&self) -> bool { ... }
    fn restore_state(&self, blob: &SamplerState) -> Result<()> { ... }
}
Expand description

Chooses parameter values for a trial.

Object-safe and Send + Sync: a study holds Arc<dyn Sampler> and calls it from every worker thread. Implementations must therefore keep any interior mutability behind a lock — and prefer, where possible, to be stateless and derive everything from TrialMeta::sampler_seed.

§Determinism

A stateless sampler must produce, for a given (study seed, trial number, space), the same assignment on every machine, in every thread, in every completion order. History-dependent samplers (TPE and later) cannot promise that under parallelism; they promise single-worker determinism plus replay, and must say so in their own documentation.

Required Methods§

fn infer_relative_space(&self, study: &StudyView) -> Result<SpaceSchema>

Determines the joint space to sample in one shot for this trial.

When the study declares a static SpaceSchema, the answer is normally that schema. Define-by-run studies infer it from history instead — which is why this can fail.

Returning an empty schema is legal and means “sample everything independently”.

§Errors

Error::Sampler if the space cannot be inferred.

fn sample_relative( &self, study: &StudyView, trial: &TrialMeta, space: &SpaceSchema, ) -> Result<Assignment>

Samples the joint space for a trial.

The returned assignment must bind every parameter in space and nothing else; each value must lie in its declared support.

§Errors

Error::Sampler on failure; Error::SpaceExhausted when an exhaustive sampler has handed out every configuration.

fn sample_independent( &self, study: &StudyView, trial: &TrialMeta, name: &str, dist: &Distribution, ) -> Result<ParamValue>

Samples one parameter that the relative space did not cover.

This is the fallback for define-by-run code that suggests a parameter nobody has seen before.

§Errors

Error::Sampler on failure.

fn reseed(&self, seed: u64)

Reseeds the sampler.

Needed for the parallel-worker case, where two workers must not draw the same auxiliary randomness. Per-trial sampling seeds arrive through TrialMeta instead and are unaffected by this call.

Provided Methods§

fn after_trial(&self, study: &StudyView, trial: &FrozenTrial) -> Result<()>

Called once a trial reaches a terminal state.

History-dependent samplers update their model here. The default does nothing, which is correct for every stateless sampler.

§Errors

Error::Sampler on failure. A failure here does not fail the trial.

fn state(&self) -> Result<Option<SamplerState>>

The sampler’s persistable state, if it has any.

The framework writes it to Scope::Sampler so that another process can pick the study up. Stateless samplers return None, which is the default.

§Errors

Error::Sampler if the state cannot be serialized.

fn snapshots_space(&self) -> bool

Whether this sampler enumerates a snapshot of the space it was constructed with, rather than the space each ask presents.

This is open-search-spaces §12.2’s clause 1, stated by the sampler itself because it is not observable from the outside: a snapshotting sampler has state() == None yet still cannot honour a growing bound — the snapshot’s cardinality would change underneath the enumeration. A study that declares an open search space refuses such a sampler at create. The default is false, which is correct for every sampler that asks the space it is handed.

fn restore_state(&self, blob: &SamplerState) -> Result<()>

Restores a sampler from a previously persisted blob.

The framework calls this once, when a study is constructed or resumed, before any sampling: it reads Scope::Sampler and, if a blob is present, hands it here so a stateful sampler continues from exactly where the last handle left off. A stateful sampler holds its state behind interior mutability (as Patient and the Wilcoxon machinery already do), so &self is enough to overwrite it.

The default is a no-op, which is correct for every stateless sampler (Random, Grid, Qmc, Tpe): they recompute their decision from the trial number and the StudyView, persist nothing (state is None, so this is never called with a blob of theirs), and would be broken by a restore. A stateful sampler (CMA-ES, whose evolution path cannot be recomputed from history) overrides both methods together, and the pair must round-trip exactly — a study torn down and resumed must reproduce, bit for bit, what a never-closed study would have sampled next.

§Errors

Error::Sampler if the blob cannot be decoded — for instance a version this sampler no longer understands.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§

§

impl Sampler for Dehb

§

impl Sampler for Grid

§

impl Sampler for Nsga2

§

impl Sampler for Qmc

§

impl Sampler for Random

§

impl Sampler for Tpe