feat(async): add run_async to every algorithm in the catalog
Async coverage was incomplete in 0.7 (only RandomSearch and DifferentialEvolution had run_async). 0.8 closes the gap: every one of the 33 algorithms now exposes run_async(&problem, concurrency).await, gated on the async feature. - Population-based algorithms fan out per-generation evaluations through evaluate_batch_async with concurrency-bounded FuturesOrdered chunks. - Steady-state algorithms (HillClimber, SimulatedAnnealing, OnePlusOneEs, Paes, NelderMead) await each step sequentially; they accept the concurrency parameter for API uniformity. - TabuSearch fans out the K-neighbor batch each step. - Surrogate algorithms (BayesianOpt, Tpe) batch the initial design and await per-iteration acquisitions sequentially so the surrogate can update between picks. - Hyperband uses a new AsyncPartialProblem trait (mirroring PartialProblem for multi-fidelity workloads) and a parallel evaluate_batch_at_budget_async helper; each Successive-Halving rung fans out its budgeted evaluations. All paths preserve seeded determinism: RNG draws happen on the main task in the same order as the sync path, and only the evaluations are concurrent. Adds a dedicated cookbook recipe at docs/book/src/cookbook/async.md with a worked example (DifferentialEvolution under tokio) and guidance on picking concurrency. Cross-references in SUMMARY.md and cookbook.md are updated to surface the new recipe. The follow-up docs commit reconciles the rest of the user guide and README to describe the new feature; this commit is the bare async surface.
This commit is contained in:
@@ -7,10 +7,12 @@
|
||||
//! thread.
|
||||
//!
|
||||
//! [`AsyncProblem`] mirrors [`Problem`](crate::core::Problem) but its
|
||||
//! `evaluate_async` returns a future. Algorithms that support async
|
||||
//! evaluation (NSGA-II, DE, RandomSearch as of v0.7.0; others land
|
||||
//! incrementally) expose a `run_async` method that drives evaluations
|
||||
//! through a user-chosen async runtime (typically tokio).
|
||||
//! `evaluate_async` returns a future. Every algorithm in heuropt exposes
|
||||
//! a `run_async` method that drives evaluations through a user-chosen
|
||||
//! async runtime (typically tokio). Hyperband uses
|
||||
//! [`AsyncPartialProblem`] instead, which mirrors
|
||||
//! [`PartialProblem`](crate::core::partial_problem::PartialProblem) for
|
||||
//! multi-fidelity workloads.
|
||||
//!
|
||||
//! Available only with the `async` feature.
|
||||
|
||||
@@ -52,3 +54,28 @@ pub trait AsyncProblem: Sync {
|
||||
/// invoked from.
|
||||
fn evaluate_async(&self, decision: &Self::Decision) -> impl Future<Output = Evaluation> + Send;
|
||||
}
|
||||
|
||||
/// Async equivalent of [`PartialProblem`](crate::core::partial_problem::PartialProblem)
|
||||
/// for multi-fidelity workloads — used by Hyperband's `run_async`.
|
||||
///
|
||||
/// Like [`AsyncProblem`], `evaluate_at_budget_async` returns a future
|
||||
/// so callers can fan out budgeted evaluations across an async runtime.
|
||||
pub trait AsyncPartialProblem: Sync {
|
||||
/// The thing the optimizer changes. Same constraints as
|
||||
/// [`PartialProblem::Decision`](crate::core::partial_problem::PartialProblem::Decision).
|
||||
type Decision: Clone + Send + Sync;
|
||||
|
||||
/// Return the objectives for this problem.
|
||||
fn objectives(&self) -> ObjectiveSpace;
|
||||
|
||||
/// Evaluate `decision` at the given fidelity `budget` asynchronously.
|
||||
///
|
||||
/// Same monotonicity contract as
|
||||
/// [`PartialProblem::evaluate_at_budget`](crate::core::partial_problem::PartialProblem::evaluate_at_budget):
|
||||
/// higher budget should give a more accurate estimate.
|
||||
fn evaluate_at_budget_async(
|
||||
&self,
|
||||
decision: &Self::Decision,
|
||||
budget: f64,
|
||||
) -> impl Future<Output = Evaluation> + Send;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user