Bump Cargo.toml to 0.11.0, pin the README install snippet to "0.11",
and add the 0.11.0 CHANGELOG section.
Release highlights:
- a full permutation crossover/mutation toolkit (OX, PMX, CX, ERX
crossovers; Inversion, Insertion, Scramble mutations);
- a micro-benchmark-guided performance pass over the combinatorial
operators and the Pareto/metrics machinery;
- a whole-program profiling campaign that cut the `compare`
workload's instruction count 357.06B -> 165.31B (-53.7%), all
bit-identical.
No public-API breaks — the release is purely additive.
34 KiB
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
0.11.0 — 2026-05-14
Theme: a full permutation-operator toolkit, plus two sweeping
performance passes. The first is a micro-benchmark-guided pass over
the combinatorial operators and the Pareto/metrics machinery; the
second is a whole-program profiling campaign that roughly halved the
instruction count of the compare example workload. Every
performance change is bit-identical — verified against per-algorithm
exact-output snapshot tests — so results are unchanged, only faster.
No public-API breaks. The release is purely additive: new permutation operators, plus internal-only performance work.
Added
- A full permutation crossover/mutation toolkit in
heuropt::operators, all re-exported from the prelude:OrderCrossover(OX),PartiallyMappedCrossover(PMX),CycleCrossover(CX), andEdgeRecombinationCrossover(ERX) crossovers, andInversionMutation,InsertionMutation, andScrambleMutationmutations — joining the pre-existingSwapMutation. The mutations preserve both strict permutations and multisets. - Combinatorial problems in the
compareexample: a bi-objective ring TSP, a 3-objective FT06 job-shop schedule, and a bi-objective knapsack — plus standalone Ulysses16 TSP and FT06 JSS benchmark examples and a bi-objective TSP crossover-comparison demo. - Many-objective problems in the
compareexample: DTLZ at 4, 8, and 10 objectives. benches/compare_profile.rs— a gungraun/callgrind benchmark that profiles the entirecompareworkload as one unit; the harness behind this release's profiling campaign.- A permutation-toolkit and multi-objective-combinatorial cookbook chapter in the mdbook.
Performance
All changes below are bit-identical — outputs are byte-for-byte unchanged, verified by the per-algorithm snapshot tests.
- Whole-program profiling campaign. Profiling the full
compareworkload under callgrind cut its instruction count from 357.06B to 165.31B (−53.7%):pareto_compareis now allocation-free — it no longer materializes two minimization-orientedVec<f64>s per call. This alone was −38%, the single biggest win.pareto_frontprecomputes its oriented buffers once and skips candidates already known to be dominated.ibeapre-exponentiates its indicator matrix, turning the survival loop'sexpsweep into plain additions.hypereuses its per-Monte-Carlo-sample scratch buffer instead of reallocating it thousands of times per call.age_moeascores only the splitting front rather than the whole combined population.
- Combinatorial-operator pass.
CycleCrossover,PartiallyMappedCrossover, andOrderCrossoverare now O(n) via position-index tables;EdgeRecombinationCrossoverremoves edges in O(degree) per step. - Pareto / metrics pass.
non_dominated_sorthalves its dominance comparisons and reads from a flattened objective buffer;crowding_distancesorts withoutVec<Vec<f64>>indirection;hypervolume_ndno longer re-sorts prefixes per slice. - Algorithm hot paths.
ant_colony_tsphoistspowfout of its tour-building loop;tpecomputes KDE bandwidths once per iteration instead of once per call;bayesian_optreuses scratch buffers in the expected-improvement acquisition loop.
Changed
- Documentation now recommends MOEA/D as the default multi- and
many-objective algorithm, with disconnected-front and sequencing
guidance corrected against fresh
compareresults. - The
compareexample's result tables are realigned and sorted, and its workload now lives in a reusable module shared with the profiling benchmark.
Internal
- A large mutation-testing-driven test-hardening pass: per-algorithm
exact-output snapshots and pinned helper-function tests across the
whole algorithm catalog and operator set, raising the cargo-mutants
catch rate from ~74% to ~85%. See
.cargo/mutants.tomlfor the campaign notes and the residual equivalent-mutant categories.
0.10.0 — 2026-05-06
Theme: every algorithm now returns its canonical name as it appears in the literature, with an academic long form available alongside, and the docs use those names everywhere. Plus the explorer JSON export now carries both forms so display tools can show the short name with a hover tooltip for the long one.
No public-API breaks beyond the value of AlgorithmInfo::name(),
which previously returned the Rust type name and now returns the
literature short name ("NSGA-II" vs "Nsga2"). If your code
matched on those strings you'll need to update — but the trait
shape itself is unchanged and algorithm.name() continues to be
the way to read it.
Added
AlgorithmInfo::full_name(&self) -> &'static str— academic long form, e.g."Non-dominated Sorting Genetic Algorithm II". Defaults toname()for algorithms whose short and long forms coincide (Random Search, Hill Climber, Tabu Search).- Every built-in algorithm overrides
full_name()with its expanded literature name. Mapping table is in the cookbook recipe atdocs/book/src/cookbook/explorer.md. ExplorerExport'sRunMetagained an optionalalgorithm_full_name: Option<String>field. Thewith_algorithm_info()builder populates both that andalgorithmfrom the sameAlgorithmInfosource. Schema version stays at 1 — the new field is#[serde(default)], so older readers tolerate it and older writers' output still loads cleanly.
Changed
AlgorithmInfo::name()return values for every built-in algorithm. Examples:"Nsga2"→"NSGA-II","Cmaes"→"CMA-ES","Mopso"→"MOPSO","Moead"→"MOEA/D","EpsilonMoea"→"ε-MOEA". Full table in the cookbook recipe.- README, mdbook chapters, decision tree, choosing-an-algorithm
guide, comparison page, getting-started, defining-problems,
cookbook recipes, and migration notes now all use the canonical
algorithm names in body prose. Code blocks (which reference the
Rust types like
Nsga2::new(...)orNsga2Config { … }) unchanged — those are still the API. - Default
cargo run --release --example pick_a_caroutput now reads"algorithm": "NSGA-III", "algorithm_full_name": "Non-dominated Sorting Genetic Algorithm III"in the JSON envelope instead of"Nsga3".
Migration
If you display optimizer.name() in your own UI, you'll suddenly
get the proper short name for free — usually a strict improvement.
The only break: code that pattern-matched on the Rust-type-shaped
strings (e.g. if name == "Nsga3") needs updating to the new
canonical strings. The names are stable now (they match the
literature), so this is a one-time fix.
0.9.0 — 2026-05-06
Theme: explorer JSON export. Real Pareto fronts have 50–200+
candidates spanning 2–7+ objectives — too many to read as numbers
in a terminal. 0.9.0 adds a tiny additive surface that turns any
OptimizationResult into a self-describing JSON file you can drop
into heuropt-explorer
to filter, brush, pin, and rank candidates interactively.
No public-API breaks. The new surface lives behind the existing
serde feature and the new methods on Problem / the new
AlgorithmInfo trait have working defaults so existing impls
compile untouched.
Added
Explorer export (the headline feature)
- New
heuropt::explorermodule (gated on theserdefeature). DefinesExplorerExport,ExplorerCandidate,RunMeta, theToDecisionValuesadapter trait, and free functionsto_json/to_writer/to_file. - Schema is versioned (
SCHEMA_VERSION = 1); the explorer webapp refuses to load files with an unknown version. front_rankis computed once vianon_dominated_sortat export time and attached to every candidate so downstream tools don't have to re-derive it.ToDecisionValuesis implemented forVec<f64>,Vec<bool>,Vec<usize>, andVec<i64>out of the box; users with custom decision types implement it themselves (one method).
Problem-side metadata (single source of truth, no duplication)
Objectivegained optionallabel: Option<String>andunit: Option<String>fields plus fluent builders.with_label("Price")/.with_unit("$k"). ExistingObjective::minimize("name")/Objective::maximize("name")unchanged. Backwards-compatible at source level and at the JSON level (the new fields use#[serde(default, skip_serializing_if = "Option::is_none")]).Problemtrait gained an optionalfn decision_schema(&self) -> Vec<DecisionVariable>with default empty impl. Override it to provide pretty names / labels / units / bounds for the explorer; the default produces fallbackx[0],x[1], … names.- New
DecisionVariabletype atheuropt::core::DecisionVariable, re-exported via the prelude. Builder methods:with_label,with_unit,with_bounds.
Algorithm metadata for the export header
- New
heuropt::traits::AlgorithmInfotrait withname() -> &'static str(required) andseed() -> Option<u64>(defaultNone). Every built-in algorithm — all 33 — implements it. Separate fromOptimizer<P>so multi-fidelity algorithms (Hyperband, which usesPartialProblem) implement it uniformly. ExplorerExport::with_algorithm_info(&optimizer)pulls the algorithm name and seed from this trait into the export'srunmetadata.
Worked example
- New
examples/pick_a_car.rs(gated onserde). Implements the README'sPickACarmulti-objective problem with a fully enricheddecision_schemaand labelled / unit-tagged objectives, runs NSGA-III, and writespick_a_car.jsonready to drop into the explorer.
Documentation
- New cookbook recipe at
docs/book/src/cookbook/explorer.mdcovering Problem enrichment, the export call, the JSON schema, and custom decision-type handling.
Notes
- The explorer webapp itself lives in a separate repo
(
heuropt-explorer) on its own release cadence. The schema inheuropt::exploreris the contract between them; bumpingSCHEMA_VERSIONis reserved for breaking changes. - Phase 1 is additive only. No existing test breaks; the lib test
count went from 229 to 242 (10 new explorer tests + 3 from the
new
Objective/DecisionVariablebuilders).
0.8.0 — 2026-05-06
Theme: async evaluation, plus the docs / governance / CI catch-up that came with finalizing the release.
heuropt now supports problems where each evaluation is a
.await-able operation — HTTP services, RPC clients, spawned
subprocesses. This is the differentiating capability vs.
pymoo / hyperopt / optuna / DEAP / MOEA Framework, none of which
ship first-class async support at the evaluation level.
No public-API breaks for synchronous users. The new surface is
gated behind a new async feature flag.
Added
Async evaluation (the headline feature)
- New optional feature
async, gated onfutures. core::async_problem::AsyncProblemtrait — mirrorsProblembut withasync fn evaluate_async(&self, decision). Adapt an existing syncProblemwith a one-line wrapper.core::async_problem::AsyncPartialProblemtrait — mirrorsPartialProblemfor multi-fidelity (Hyperband) workloads withasync fn evaluate_at_budget_async(decision, budget).- Per-algorithm
run_async(&problem, concurrency).awaitmethods on every algorithm in the catalog — all 33 of them — driving evaluations through whichever async runtime the caller is using (typically tokio).concurrencybounds in-flight evaluations. Population-based algorithms (NSGA-II, NSGA-III, SPEA2, MOEA/D, CMA-ES, DE, GA, PSO, IBEA, SMS-EMOA, HypE, ε-MOEA, PESA-II, AGE-MOEA, KnEA, GrEA, RVEA, MOPSO, TLBO, IPOP-CMA-ES, sNES, UMDA, Ant Colony, GA, Random Search) fan out per generation. Steady-state algorithms (Hill Climber, SA, (1+1)-ES, PAES, Nelder-Mead, Tabu Search) await each step sequentially. Surrogate algorithms (BO, TPE) batch the initial design and then await per-iteration acquisitions. Hyperband fans out each Successive-Halving rung throughAsyncPartialProblem. - Internal
algorithms::parallel_eval_async::evaluate_batch_asyncandevaluate_batch_at_budget_asynchelpers — usefutures::stream::FuturesOrderedwith concurrency-bounded chunks, preserve input order so seeded determinism is preserved when evaluations are themselves deterministic. examples/async_eval.rs— worked example with a simulated 20 ms remote service. At concurrency = 1 it's serial; at concurrency = 4 it's 2× faster; demonstratesDifferentialEvolutionunder tokio.
Documentation
- New cookbook recipe Async evaluation
— implementing
AsyncProblem, picking concurrency, determinism guarantees, async vs.parallel. - Comparison-with-other-libraries chapter updated:
heuropt 0.8row,Async ✅ AsyncProblem + run_asynccolumn, "When to pick heuropt" gains an explicit IO-bound bullet. - Stability chapter rewritten: removes the speculative "Observer /
Checkpoint planned" bullet (those didn't ship), documents the new
asyncfeature flag. - Migration guide: new "To 0.8" section covering both
0.5.x → 0.8(feature-additive — opt in by enabling theasyncfeature) and0.7 → 0.8(the partial async surface from 0.7 is superseded by complete coverage; existingrun_asynccallers keep working). - Runnable
cargo test --docexamples added to every public operator (10), metric (3), and Pareto utility (7) — every public item across the crate now ships with at least one example. 55 doctests in total (was 45).
CI / build
.github/workflows/docs.ymlbuilds the mdbook user guide on every push and deploys to GitHub Pages onmain/ tag pushes.mdbookbook now uses[rust] edition = "2021"to satisfymdbook 0.4.40.clamp_to_boundscargo-fuzz target tolerance loosened to1e-4 · max(simplex_total, max_abs_x, 1)so the fuzzer doesn't flag ULP-level slop in the simplex projection'smax(x_i − τ, 0)clamp boundary.
0.5.0 — 2026-05-05
Theme: comprehensive documentation and project polish. No public-API
changes — bumping heuropt = "0.5" in your Cargo.toml is enough.
Added
User guide (mdbook)
A new mdbook user guide at docs/book/, deployed to
https://swaits.github.io/heuropt/ via a CI workflow on tag pushes.
Chapters:
- Introduction — what heuropt is, who it's for, what's in the box.
- Five-minute walkthrough — install, define a problem, run an optimizer, look at the result.
- Defining a problem — the
Problemtrait in depth: single- vs multi-objective, constraints, custom decision types (Vec<f64>,Vec<bool>,Vec<usize>, custom structs). - Choosing an algorithm — the README's decision tree, expanded to a full chapter with the reasoning behind every branch.
- Cookbook — seven recipes covering parallelism, expensive evaluations, comparison harnesses, permutation problems, constraint repair, picking one answer off a Pareto front, and writing your own optimizer.
- Comparison with other libraries — heuropt vs pymoo, hyperopt, optuna, MOEA Framework, metaheuristics-rs, argmin. Honest about when not to pick heuropt.
- Stability and SemVer — explicit guarantees about which surfaces are stable; what's likely to change before 1.0; bit-identical determinism contract.
- Migration guides — per-release upgrade notes.
Runnable rustdoc examples
Every algorithm now has a runnable ```rust example block in its
rustdoc — 35 algorithms, all exercised by cargo test --doc. Plus
the existing crate-level example in lib.rs and the
CompositeVariation operator example.
Real-world examples
Three new polished examples covering distinct domains:
examples/portfolio.rs— multi-objective portfolio optimization with budget constraint viaProjectToSimplex. Pareto front of return-vs-risk trade-offs, plus a-posteriori weighted decision.examples/hyperparam_tuning.rs— sample-efficient hyperparameter tuning withBayesianOptandTpe, demonstrating mixed-scale decoding (log-uniform learning rate, integer depth) and a 60-eval budget.examples/scheduling.rs— single-machine weighted-completion-time scheduling: permutation decisions optimized viaSimulatedAnnealing+SwapMutation, comparing against the Smith's-rule oracle.
Governance docs
CONTRIBUTING.md— local-test checklist, conventional-commits requirement, contribution areas that land easily vs. those that need prior discussion.SECURITY.md— disclosure policy, supported versions, what counts as a security issue.CODE_OF_CONDUCT.md— adopts the Builder's Code of Conduct (CC0)..github/ISSUE_TEMPLATE/— bug, feature, docs templates plus aconfig.ymlthat points security reports to the private vulnerability-disclosure flow..github/PULL_REQUEST_TEMPLATE.md— short, opinionated PR template.
CI / tooling
.github/workflows/docs.yml— builds the mdbook user guide and deploys it to GitHub Pages onmainpushes and tag pushes.
Changed
- README hero block expanded with badges and a punchier opening; added explicit links to the user guide, the docs.rs API reference, and the testing-coverage breakdown.
lib.rscrate-level docs polished — better intro, points readers at the user guide and the design spec.
0.4.0 — 2026-05-05
Theme: testing infrastructure, two real bug fixes surfaced by that infrastructure, and a CPU-time optimization pass that made the comparison harness 3.27× faster end-to-end. No breaking changes to the v0.3.0 public API.
Performance
A focused, measure-and-iterate optimization pass on the Pareto-based multi-objective hot paths. Every change verified bit-identical against the v0.3.0 comparison-harness snapshot — quality metrics (hypervolume, spacing, mean L2, mean dist, front size) match to the last decimal in every benchmark.
Cumulative wall-clock impact (compare harness, 10-seed mean):
| Algorithm / Problem | v0.3.0 | v0.4.0 | Speedup |
|---|---|---|---|
| AGE-MOEA / DTLZ1 | 2299 ms | 229 ms | 10× |
| SPEA2 / DTLZ2 | 4304 ms | 513 ms | 8.4× |
| AGE-MOEA / ZDT3 | 932 ms | 193 ms | 4.8× |
| NSGA-II / ZDT1 | 268 ms | 65 ms | 4.1× |
| NSGA-II / ZDT3 | 267 ms | 65 ms | 4.1× |
| SMS-EMOA / DTLZ2 | 5643 ms | 1369 ms | 4.1× |
| NSGA-II / Rastrigin | 260 ms | 71 ms | 3.7× |
| NSGA-II / DTLZ2 | 344 ms | 106 ms | 3.2× |
| NSGA-III / DTLZ2 | 318 ms | 122 ms | 2.6× |
| NSGA-III / DTLZ1 | 303 ms | 122 ms | 2.5× |
| HypE / DTLZ2 | 80 ms | 44 ms | 1.8× |
| Total compare | 18 629 ms | 5688 ms | 3.27× |
Hot-path instruction counts (gungraun):
| Benchmark | v0.3.0 | v0.4.0 | Speedup |
|---|---|---|---|
hypervolume_nd_3d n=100 |
13 523 760 | 367 767 | 37× |
hypervolume_nd_3d n=30 |
676 902 | 70 334 | 9.6× |
non_dominated_sort_2d n=200 |
13 513 271 | 2 601 813 | 5.2× |
non_dominated_sort_2d n=50 |
852 317 | 198 574 | 4.3× |
spea2_short |
179 113 | 133 783 | 1.34× |
Changes (in commit order):
perf(hypervolume)— Rewrote the M≥3 HSO recursion inhypervolume_nd. The original cloned the active set into a fresh Vec<Vec> at the top of every recursive call, used a linear-scanpositionlookup to remove the just-processed point each band, and re-projected onto M-1 axes inside every band. Now: sort-by-index, pre-project once, slice prefixes for the active set, and skipnon_dominated_projectionwhen recursing into the M=2 base case (whose sweep already filters dominated points internally).perf(non_dominated_sort)— Cacheas_minimization/ feasibility / violation per individual once at the top of the Deb fast-non-dominated-sort, then inline the dominance test against those arrays. The naïve formulation calledpareto_comparetwice per pair, each call allocating two fresh Vecs — 4N(N-1) allocations per sort. Propagates to every Pareto-based MOEA.perf(age_moea)— Cachelp_norm(translated[i], p)once per candidate at function entry; maintain anearest[]array updated incrementally on each pick (singleminper remaining instead of a fresh full scan over the keep list). Cuts the splitting-front scoring loop from O(R · K · M) per iteration to O(R · M).perf(spea2)— Two wins. (1)compute_fitness(called twice per generation): inline dominance against cached oriented arrays, symmetric distance matrix built once. (2)build_archivetruncation: compute pairwise distances + sorted neighbor vectors once, then on victim removal use binary-search-remove on every survivor's still-sorted vector — total truncation cost O(K³ log K) → O(K² log K).perf(hypervolume)— Index-sort instead of cloning point vectors in the M≥3 recursion. The N inner-Vec clones per HV call were redundant once we'd already sorted by last-axis. Big bench win (32×→37× cumulative on n=100/3D), modest wall-clock impact because SMS-EMOA's worst-front HV calls operate on small fronts.build(release)— Enable thin LTO + codegen-units=1 in the release profile. Worth ~150 ms across the harness; only applies when heuropt is the workspace root, so downstream consumers see whatever profile their own Cargo.toml configures.perf(pareto_archive)— Cache the candidate's oriented + feasibility once perinsert, build each member's oriented vector once, and inline the two-pass dominance checks. Used by PESA-II (most impact), PAES, ε-MOEA, and any user code working through the archive directly.
Added
- Decision tree update in README to cover all v0.3.0 algorithms,
with a new top-level branch on "is each evaluation expensive?" so
BayesianOpt/Tpe/Hyperbandhave a clear home. - Comparison results snapshot at
examples/compare-results.md— reference output of the harness across 7 benchmark problems and ~20 algorithms, captured after v0.3.0 landed. - Instruction-count benchmarks via
gungraun(the Rust 2026 rename ofiai-callgrind) atbenches/hot_paths.rs. Coversnon_dominated_sort,crowding_distance,hypervolume_2d,hypervolume_nd(HSO), and one-generation costs of NSGA-II and CMA-ES, plus a short-run bench for every algorithm. Stable across machines via callgrind. - Property-based test suite expansion:
tests/properties.rs(Pareto-comparison antisymmetry, partitioning, operator bounds),tests/algorithm_properties.rs(per-algorithm determinism + population-size invariants — 32 tests, one per algorithm),tests/operator_properties.rs(everyVariation/Initializer/Repairimpl),tests/metric_properties.rs(HV / spacing invariants), andtests/numerical_stability.rs(empty / singleton / duplicate / flat-fitness / zero-width-bounds populations). - Coverage-guided fuzz harness at
fuzz/(cargo-fuzz + libFuzzer). Eight targets coveringpareto_compare,non_dominated_sort,hypervolume_2d,ParetoArchive,crowding_distance,spacing, SBX/PolyMut, and theRepairoperators. Runs in CI for a short soak per PR; longer runs locally viacargo +nightly fuzz run <target>. - cargo-mutants config at
.cargo/mutants.tomlfor advisory mutation testing. Not gated in CI; run withcargo mutantsto surface tests that don't actually check the behavior they look like they do. - GitHub Actions CI at
.github/workflows/ci.ymlwith fmt / clippy / test (4-feature matrix) / doc / MSRV / fuzz-smoke jobs, all gated on-D warnings.
Fixed
pareto::sort::non_dominated_sortpreviously dropped indices when the dominance graph contained a cycle (which arises when objectives contain NaN —pareto_comparebecomes intransitive). Fuzzing the partition invariant surfaced the bug; orphans now go into a final residual front.operators::repair::ProjectToSimplexcould silently return the all-zero vector when the input vector's magnitude dwarfedtotal(the standard Duchi/Held-Wolfe τ computation lost precision and τ ≈ max(x), somax(x_i - τ, 0)rounded to zero everywhere). Detected by theclamp_to_boundsfuzzer; now falls through to a degenerate "all mass on argmax" projection above a 1e15 magnitude ratio, and is robust to floating-point precision loss in the algorithm's inner loop.
0.3.0 — 2026-05-05
Theme: filling heuropt's expensive-evaluation, gradient-free, and constraint-handling gaps. No breaking changes to the v0.2.0 public API.
Added
New algorithms (9)
Sample-efficient / surrogate-based:
BayesianOpt— Gaussian-process Bayesian Optimization with Expected Improvement acquisition. heuropt's first sample-efficient algorithm: targets the 50–500 evaluation regime.Tpe— Bergstra et al. 2011 Tree-structured Parzen Estimator (workhorse of Hyperopt and Optuna). KDE-based surrogate; cheaper per-step than BO and more robust without hyperparameter tuning.
Classical and modern evolution strategies:
OnePlusOneEs— Rechenberg 1973 (1+1)-ES with the one-fifth success rule. Smallest possible self-adapting evolution strategy.IpopCmaEs— Auger & Hansen 2005 increasing-population CMA-ES with restart. Specifically fixes vanilla CMA-ES's known weakness on multimodal problems.SeparableNes— Wierstra et al. 2008/2014 Natural Evolution Strategy with diagonal covariance (sNES). Different theoretical foundation than CMA-ES; cheaper per-step at the cost of being unable to model rotated landscapes.
Direct search:
NelderMead— Nelder & Mead 1965 simplex method. Classical gradient- free local optimizer; superb on low-dim smooth problems (Rosenbrock 5-D: f = 0 exactly).
Multi-fidelity:
Hyperband— Li et al. 2017 multi-fidelity hyperparameter optimizer built on Successive Halving. Operates on a newPartialProblemtrait so configurations can be evaluated at adjustable fidelity budgets.
New operators
LevyMutation— heavy-tailed Lévy-flight mutation via Mantegna's algorithm. The actual algorithmic contribution from Cuckoo Search packaged as a reusableVariationoperator.
New traits + impls
PartialProblem— multi-fidelity problem contract:evaluate_at_budget(decision, budget) -> Evaluation. Used byHyperband. Intentionally not a sub-trait ofProblem.Repair<D>— in-place projection trait for restoring decisions to feasibility. Pair withVariationoperators to get bounds-aware variants. Provided impls:ClampToBoundsforVec<f64>per-axis clampingProjectToSimplexfor L1-budget / probability-simplex projection
New selection helpers
stochastic_ranking_select— Runarsson & Yao 2000 stochastic ranking. Better than strict feasibility-first tournament selection on heavily-constrained problems.
Internal helpers
internal::cholesky— Cholesky factorization + triangular solves for SPD matrices, used by the GP posterior inBayesianOpt.
Changed
CmaEsConfiggainedinitial_mean: Option<Vec<f64>>.Nonepreserves the existing midpoint-of-bounds default;IpopCmaEssets it to inject restart diversity without shrinking the search box.
0.2.0 — 2026-05-05
A substantial expansion of the algorithm catalog (21 new algorithms), five new operators, an n-D hypervolume utility, an algorithm-selection guide in the README, and a multi-seed comparison harness covering seven benchmark problems. No breaking changes to the v0.1.0 public API.
Added
New algorithms
Single-objective:
HillClimber— simplest greedy local search.SimulatedAnnealing— Kirkpatrick et al. 1983, generic over decision type.GeneticAlgorithm— generational SO GA with tournament selection + elitism.ParticleSwarm— Eberhart & Kennedy 1995 PSO forVec<f64>.CmaEs— Hansen & Ostermeier 2001 covariance-matrix adaptation.TabuSearch— Glover 1986, with a user-supplied neighbor generator.AntColonyTsp— Dorigo Ant System for permutation problems.Umda— Mühlenbein 1997 univariate marginal-distribution EDA forVec<bool>.Tlbo— Rao 2011 Teaching-Learning-Based Optimization (parameter-free).
Multi-objective:
Mopso— Coello, Pulido & Lechuga 2004 multi-objective PSO.Ibea— Zitzler & Künzli 2004 indicator-based EA.SmsEmoa— Beume, Naujoks & Emmerich 2007 S-metric selection EMOA.Hype— Bader & Zitzler 2011 Hypervolume Estimation Algorithm.Rvea— Cheng et al. 2016 Reference Vector-guided EA.PesaII— Corne et al. 2001 Pareto Envelope-based Selection II.EpsilonMoea— Deb, Mohan & Mishra 2003 ε-dominance MOEA.AgeMoea— Panichella 2019 Adaptive Geometry Estimation MOEA.Grea— Yang et al. 2013 Grid-based EA.Knea— Zhang, Tian & Jin 2015 Knee point-driven EA.
New operators
BoundedGaussianMutation— Gaussian noise + per-axis clamping.SimulatedBinaryCrossover(SBX) — Deb & Agrawal 1995 canonical real-valued crossover.PolynomialMutation— Deb's polynomial mutation, the standard NSGA-II pair to SBX.CompositeVariation— pipeline twoVariationoperators (typically crossover → mutation).LevyMutation— heavy-tailed Lévy-flight mutation via Mantegna's algorithm.
New metrics / utilities
hypervolume_nd— exact N-dimensional dominated hypervolume via the Hypervolume-by-Slicing-Objectives (HSO) algorithm, plus an internal Jacobi symmetric eigendecomposition helper used by CMA-ES.
New examples
compare— multi-seed comparison harness running every applicable algorithm across ZDT1, ZDT3, DTLZ1, DTLZ2 (multi/many-objective) and Rastrigin, Rosenbrock, Ackley (single-objective). Reports hypervolume, spacing, mean L2/dist, front size, and wall-clock ms.benchmarks— canonical reference runs of NSGA-II on ZDT1 and DE on Rastrigin.jiggly_tuning— real-world 4-objective NSGA-III firmware tuning for thejigglyUSB-mouse-jiggler, with an a-posteriori weighted-decision step that picks one recommendation off the Pareto front.
New optional feature
parallel— rayon-backed parallel population evaluation inRandomSearch,Nsga2,DifferentialEvolution,Spea2,Ibea,Mopso, and most other algorithms with batchable inner loops. Seeded runs stay bit-identical to serial mode.
Documentation
- README gained an explanatory algorithm-selection decision tree that walks newcomers through choosing an optimizer, defining the terminology (multi-objective, Pareto front, dominance, multimodality, evaluation cost) as it goes.
Changed
- Minimum supported Rust version remains 1.85 (edition 2024).
- Algorithm impls now require
P: SyncandP::Decision: Sendso the same impl serves bothparalleland serial feature builds. AnyProblem/ decision type without exotic interior mutability already satisfies these.
0.1.0 — 2026-05-04
Initial release.
Core types and traits
Direction,Objective,ObjectiveSpace(withas_minimizationdirection conversion).Evaluationwith feasibility (constraint_violation <= 0.0).Candidate<D>,Population<D>,OptimizationResult<D>.type Rng = rand::rngs::StdRngandrng_from_seedso no public trait is generic over the RNG.Problem,Optimizer<P>,Initializer<D>,Variation<D>.
Pareto utilities
pareto_compare,pareto_front,best_candidate,non_dominated_sort(Deb fast non-dominated sort),crowding_distance,ParetoArchive<D>,das_dennis(structured reference points for NSGA-III and MOEA/D).
Operators
- Real:
RealBounds,GaussianMutation,BoundedGaussianMutation,SimulatedBinaryCrossover(SBX),PolynomialMutation. - Binary:
BitFlipMutation. - Permutation:
SwapMutation. CompositeVariationpipeline (typically crossover → mutation).
Selection helpers
select_random,tournament_select_single_objective.
Reference algorithms
RandomSearch— sample-evaluate-keep baseline.Paes— small (1+1) Pareto Archived Evolution Strategy.Nsga2— canonical Pareto-based EA with crowding distance.Nsga3— many-objective NSGA-III with reference-point niching.Spea2— Strength Pareto Evolutionary Algorithm 2.Moead— decomposition-based MOEA/D with the Tchebycheff scalar.DifferentialEvolution— single-objective DE/rand/1/bin.
Metrics
spacing(Schott),hypervolume_2d(exact 2-D dominated hypervolume).
Examples
random_search,toy_nsga2,custom_optimizer— minimum-viable walkthroughs.benchmarks— ZDT1 and Rastrigin reference runs.compare— multi-seed comparison harness running every applicable algorithm on ZDT1 (2-obj), DTLZ2 (3-obj), and Rastrigin (single-obj), reporting hypervolume, spacing, mean L2, front size, and wall time.jiggly_tuning— 4-objective NSGA-III tuning of thejigglyUSB-mouse-jiggler firmware with an a-posteriori weighted-decision step that picks one recommendation off the Pareto front.
Optional features
serde—Serialize/Deserializederives on the core data types.parallel— rayon-backed parallel population evaluation inRandomSearch,Nsga2, andDifferentialEvolution. Seeded runs stay bit-identical to serial mode.