feat: v0.6.0 — observer / stop-conditions / tracing / IGD / R2

Theme: production lifecycle. heuropt becomes deployable for long-
running, real-world workloads. No breaking changes — Optimizer trait
gains a default-impl run_with method that falls back to run.

Adds:
- src/observer/ module: Snapshot, Observer trait, ControlFlow, plus
  built-in MaxTime / MaxIterations / TargetFitness / Stagnation /
  Periodic / AnyOf / AllOf and a closure impl.
- Optimizer::run_with(problem, observer): default-impl on the trait,
  overridden for full per-gen visibility on Nsga2, RandomSearch, and
  DifferentialEvolution. Other algorithms inherit a final-only
  notification — full per-gen support follows incrementally.
- New 'tracing' optional feature plus TracingObserver that emits
  structured debug! events per generation.
- src/metrics/igd.rs: IGD + IGD+ performance indicators against a
  reference set.
- src/metrics/r2.rs: R2 indicator using the weighted Tchebycheff
  utility; pair with das_dennis for the canonical weight set.
- examples/constrained.rs: BNH constrained 2-objective problem
  solved with NSGA-II + observer composition (MaxTime.or(Periodic)).

Bumps Cargo.toml to 0.6.0; CHANGELOG entry consolidates the above.
Existing 247 unit + 38 doctest + 32 algorithm-property + property /
metric / numerical-stability tests all pass; bit-identical compare
output verified post-DE refactor.
This commit is contained in:
2026-05-05 15:07:05 -06:00
parent fa3f2e8fb0
commit b0f580841d
16 changed files with 1381 additions and 36 deletions
+74 -1
View File
@@ -7,6 +7,79 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.6.0] — 2026-05-05
Theme: production lifecycle. heuropt becomes deployable for long-
running, real-world optimization workloads — callbacks, stop
conditions, tracing, and two new performance indicators.
No breaking changes to the public API. Existing `Optimizer<P>` impls
keep compiling — `run_with` is added as a default-impl method that
falls back to `run` plus a single final notification.
### Added
#### Observer + stop-conditions API
A new module `heuropt::observer` introduces:
- `Snapshot<'a, D>` — per-generation observation payload with
`iteration`, `evaluations`, `elapsed`, `population`,
`pareto_front`, `best`, and `objectives`.
- `Observer<D>` trait — single method `observe(&Snapshot) ->
ControlFlow<()>`. Closures of the right shape implement it
automatically. `()` is the no-op observer.
- `Optimizer::run_with(problem, observer)` — new method on the
`Optimizer` trait with a default impl that falls back to `run`.
Algorithms that override `run_with` (so far: `Nsga2`,
`RandomSearch`, `DifferentialEvolution`) call the observer once
per generation; others call it once at the end. Returning
`ControlFlow::Break` halts the optimizer and returns the partial
result.
#### Built-in observers (`observer::builtin`)
- `MaxTime(Duration)` — wall-clock cap.
- `MaxIterations(usize)` — generation cap.
- `TargetFitness(f64)` — direction-aware single-objective target.
- `Stagnation { window, tolerance }` — halt when the best fitness
hasn't improved by `tolerance` over `window` generations.
- `Periodic::new(every, |snap| { … })` — call a user closure every
`every` generations.
- `AnyOf` / `AllOf` plus `Observer::or` / `Observer::and` for
composition.
- `TracingObserver` (behind the new `tracing` feature) — emits
structured `debug!` events per generation.
#### Tracing feature
New optional feature `tracing`, gated on the
[`tracing`](https://crates.io/crates/tracing) crate. Adds
`TracingObserver` to the prelude when enabled.
#### Performance indicators
- `metrics::igd::igd` — Inverted Generational Distance against a
reference set (typically the true Pareto front).
- `metrics::igd::igd_plus` — Pareto-compliant IGD+ variant; adding
a dominated point never improves the score.
- `metrics::r2::r2` — R2 indicator using the weighted Tchebycheff
utility. Pair with `pareto::das_dennis` for the canonical weight
set.
#### Constrained example
`examples/constrained.rs` — solves the BNH constrained 2-objective
problem (Binh & Korn 1996) with NSGA-II + the new observer API,
demonstrating `Periodic` progress logging and `MaxTime` /
composition.
### Changed
- `Population::as_slice()` — new convenience accessor.
[0.6.0]: https://github.com/swaits/heuropt/releases/tag/v0.6.0
## [0.5.0] — 2026-05-05
Theme: comprehensive documentation and project polish. No public-API
@@ -469,5 +542,5 @@ Initial release.
`RandomSearch`, `Nsga2`, and `DifferentialEvolution`. Seeded runs stay
bit-identical to serial mode.
[Unreleased]: https://github.com/swaits/heuropt/compare/v0.5.0...HEAD
[Unreleased]: https://github.com/swaits/heuropt/compare/v0.6.0...HEAD
[0.1.0]: https://github.com/swaits/heuropt/releases/tag/v0.1.0