Expand description
Sampler trait and implementations for parameter sampling.
A sampler generates parameter values for each trial. It receives a
Distribution describing the parameter space, a monotonically increasing
trial_id, and the list of all CompletedTrials so far, and returns a
ParamValue that matches the distribution variant.
§Available samplers
§Single-objective
| Sampler | Algorithm | Best for |
|---|---|---|
RandomSampler | Uniform independent sampling | Baselines, startup phases |
TpeSampler | Tree-Parzen Estimator | General-purpose Bayesian optimization |
TpeSampler (multivariate) | Multivariate TPE with tree-structured Parzen | Correlated parameters |
GridSampler | Exhaustive grid evaluation | Small discrete spaces |
[SobolSampler]* | Quasi-random Sobol sequences | Uniform coverage without model |
[CmaEsSampler]* | Covariance Matrix Adaptation | Continuous, non-separable problems |
[GpSampler]* | Gaussian Process with EI | Expensive, low-dimensional functions |
DESampler | Differential Evolution | Population-based, multi-modal landscapes |
BohbSampler | Bayesian Optimization + HyperBand | Combined sampling and pruning |
*Requires a feature flag (sobol, cma-es, or gp).
§Multi-objective
| Sampler | Algorithm | Best for |
|---|---|---|
Nsga2Sampler | NSGA-II | General multi-objective with 2-3 objectives |
Nsga3Sampler | NSGA-III | Many-objective (4+ objectives) |
MoeadSampler | MOEA/D with decomposition | Structured Pareto front exploration |
MotpeSampler | Multi-objective TPE | Bayesian multi-objective |
§Implementing a custom sampler
Implement the Sampler trait with its single method:
use optimizer::sampler::{Sampler, CompletedTrial};
use optimizer::distribution::Distribution;
use optimizer::param::ParamValue;
/// A sampler that always picks the midpoint of each distribution.
struct MidpointSampler;
impl Sampler for MidpointSampler {
fn sample(
&self,
distribution: &Distribution,
_trial_id: u64,
_history: &[CompletedTrial],
) -> ParamValue {
match distribution {
Distribution::Float(fd) => {
ParamValue::Float((fd.low + fd.high) / 2.0)
}
Distribution::Int(id) => {
ParamValue::Int((id.low + id.high) / 2)
}
Distribution::Categorical(cd) => {
ParamValue::Categorical(cd.n_choices / 2)
}
}
}
}The arguments to Sampler::sample:
distribution— aDistribution::Float,Distribution::Int, orDistribution::Categoricalthat describes the parameter bounds, log-scale flag, and optional step size.trial_id— a monotonically increasing identifier. Useful for deterministic RNG seeding (see Stateless vs stateful samplers).history— all completed trials so far. May be empty on the first trial. Model-based samplers use this to guide future sampling.- Return value — the
ParamValuevariant must match the distribution variant (Float→ParamValue::Float, etc.).
§Stateless vs stateful samplers
Stateless samplers derive all randomness from a deterministic function
of seed + trial_id + distribution. They use an AtomicU64 call-sequence
counter to disambiguate multiple calls within the same trial, but need no
Mutex. See RandomSampler and TpeSampler for this pattern.
Stateful samplers maintain mutable state (e.g. a population pool)
across calls. Wrap mutable state in parking_lot::Mutex<State> and lock
for the duration of Sampler::sample. See DESampler and
GridSampler for this pattern.
§Cold start handling
Model-based samplers need completed trials before their surrogate model is
useful. The standard pattern is to check history.len() < n_startup_trials
and fall back to random sampling during the startup phase. Expose this as a
builder parameter so users can tune the trade-off between exploration and
exploitation. See TpeSampler for a reference implementation.
§Reading trial history
The history slice contains only completed trials (never pending ones).
Common operations:
- Extract a parameter value:
trial.params.get(¶m_id)returnsOption<&ParamValue>. - Find the best trial:
history.iter().min_by(|a, b| a.value.partial_cmp(&b.value).unwrap()). - Filter by state:
history.iter().filter(|t| t.state == TrialState::Complete). - Check feasibility:
trial.is_feasible()returnstruewhen all constraints are ≤ 0.
§Thread safety
The Sampler trait requires Send + Sync. Study stores
the sampler as Arc<dyn Sampler>, so multiple threads may call
Sampler::sample concurrently.
- Stateless:
AtomicU64counters satisfySend + Syncwithout locking. - Stateful: use
parking_lot::Mutex(the crate convention) orstd::sync::Mutexto protect mutable state.
§Testing custom samplers
Recommended test categories:
- Bounds compliance — sample many values and assert they fall within the distribution range.
- Step / log-scale correctness — verify that discretized and log-scaled distributions produce valid values.
- Reproducibility — the same seed must produce the same output.
- History sensitivity — model-based samplers should produce different (better) samples as history grows.
- Empty history —
sample()must not panic whenhistoryis empty.
§Using a custom sampler with Study
use optimizer::{Direction, Study};
use optimizer::sampler::{Sampler, CompletedTrial};
use optimizer::distribution::Distribution;
use optimizer::param::ParamValue;
struct MySampler;
impl Sampler for MySampler {
fn sample(
&self,
distribution: &Distribution,
_trial_id: u64,
_history: &[CompletedTrial],
) -> ParamValue {
match distribution {
Distribution::Float(fd) => ParamValue::Float(fd.low),
Distribution::Int(id) => ParamValue::Int(id.low),
Distribution::Categorical(_) => ParamValue::Categorical(0),
}
}
}
let study: Study<f64> = Study::with_sampler(Direction::Minimize, MySampler);The sampler is wrapped in Arc<dyn Sampler> internally.
§Reference implementations
RandomSampler— simplest sampler; stateless, ignores history.TpeSampler— model-based with cold start fallback.DESampler— stateful, population-based.GridSampler— deterministic, exhaustive search.
Re-exports§
pub use bohb::BohbSampler;pub use de::DESampler;pub use de::DEStrategy;pub use grid::GridSampler;pub use moead::Decomposition;pub use moead::MoeadSampler;pub use motpe::MotpeSampler;pub use nsga2::Nsga2Sampler;pub use nsga3::Nsga3Sampler;pub use random::RandomSampler;pub use tpe::TpeSampler;
Modules§
- bohb
- BOHB (Bayesian Optimization +
HyperBand) sampler. - de
- Differential Evolution (DE) sampler.
- grid
- Grid search sampler — exhaustive evaluation of discretized parameter spaces.
- moead
- MOEA/D (Multi-Objective Evolutionary Algorithm based on Decomposition) sampler.
- motpe
- Multi-Objective Tree-Parzen Estimator (MOTPE) sampler.
- nsga2
- NSGA-II (Non-dominated Sorting Genetic Algorithm II) sampler.
- nsga3
- NSGA-III (Non-dominated Sorting Genetic Algorithm III) sampler.
- random
- Random sampler — uniform independent sampling.
- tpe
- Tree-Parzen Estimator (TPE) sampler family for Bayesian optimization.
Structs§
- Completed
Trial - A completed trial with its parameters, distributions, and objective value.
- Pending
Trial - A pending (running) trial with its parameters and distributions, but no objective value yet.
Traits§
- Sampler
- Trait for pluggable parameter sampling strategies.