Commit Graph
6 Commits
Author SHA1 Message Date
swaits 5728ee14e2 feat(examples): add DTLZ2 (3-obj) and NSGA-III to comparison harness
NSGA-III's value over NSGA-II shows up at 3+ objectives, where
crowding distance loses its diversity signal. Adds a third comparison
section to `examples/compare.rs`:

DTLZ2 (3-objective, 12-D, the textbook benchmark for many-objective
algorithms): unit-sphere-octant Pareto front. Compares RandomSearch,
NSGA-II, SPEA2, and NSGA-III on:

- mean distance from front points to the unit sphere
  (closed-form: |1 - sqrt(f1² + f2² + f3²)|),
- spacing,
- front size,
- wall-clock ms.

NSGA-III config: H=12 reference divisions (91 reference points,
matching the canonical setup from Deb & Jain 2014).

Also wires NSGA-III into the existing ZDT1 (2-objective) section even
though it's not its sweet spot — useful as a regression check that the
algorithm at least keeps up with NSGA-II on bi-objective problems.
2026-05-04 19:57:21 -06:00
swaits 18d778a00b feat(examples): add SPEA2 to ZDT1 comparison harness
One-line addition: `zdt1_spea2` runner using bounds-aware operators
(SBX + PolyMut, same hyperparameters NSGA-II uses) and an archive of 100.
2026-05-04 19:53:07 -06:00
swaits 13f126a754 feat(examples): add multi-seed comparison harness
A comparison example that runs every applicable optimizer on ZDT1 and
Rastrigin across N seeds and reports mean ± stddev for each quality
metric. Designed so a new algorithm slots in by adding a single runner
function — no harness changes needed.

ZDT1 (multi-objective, dim=30):
  Reports hypervolume_2d (against ref point [1.1, 1.1]), spacing, mean
  L2 distance to the analytical Pareto front, front size, and wall-clock
  ms. RandomSearch, PAES, and NSGA-II all use bounds-aware operators
  (RealBounds, BoundedGaussianMutation, SBX+PolyMut) so the Problem
  itself stays unclamped — apples-to-apples.

Rastrigin (single-objective, dim=5):
  Reports mean ± stddev best objective and ms. RandomSearch, PAES,
  NSGA-II (degenerate single-obj case), and DE.

Default budget: 10 seeds × 25,000 evaluations on ZDT1, × 50,000 on
Rastrigin. Run with:

  cargo run --release --example compare
2026-05-04 19:51:39 -06:00
swaits 5b1ee99a58 docs(examples): switch ZDT1 to canonical NSGA-II operators (SBX + PolyMut)
Replace the v0.1 `GaussianMutation` + clamp-inside-`evaluate` setup
with the canonical NSGA-II operator pair: SBX (η_c=15, per-var prob 0.5)
followed by PolynomialMutation (η_m=20, per-var prob 1/dim), composed
via `CompositeVariation`. Both are bounds-aware on their own, so the
in-evaluate clamping is dropped.

Result on ZDT1 (dim=30, pop=100, gens=1000, seed=42): mean L2 distance
to the analytical Pareto front is 0.00152 — comfortably within the
published NSGA-II range for this benchmark.

Note on the previous number: the v0.1 setup reported 0.00072 at 40k
evals, but that was an artifact of clamping inside `evaluate`. Out-of-
bounds Gaussian mutations on `x[0]` were snapping to 0, which
coincides with the ZDT1 Pareto-front extreme (f1=0). The new operator
pair has no such free lunch — it runs the actual NSGA-II algorithm —
and the new measurement is what honest convergence on ZDT1 actually
looks like.

Generations bumped from 400 to 1000 (40k → 100k evaluations) to give
the operators headroom; matches the budget DE uses for Rastrigin so
the example feels balanced.
2026-05-04 19:46:56 -06:00
swaits a26849ed13 feat(examples): add ZDT1 and Rastrigin benchmark problems
Two canonical optimization benchmarks in a single runnable example:

- ZDT1 (Zitzler-Deb-Thiele 1): 30-D, two minimization objectives,
  closed-form Pareto front \\(f_2 = 1 - \\sqrt{f_1}\\) for
  \\(f_1 \\in [0, 1]\\). Solved with NSGA-II.
- Rastrigin: highly multimodal single-objective, global minimum
  \\(f = 0\\) at the origin. Solved with DE.

Both are public-domain mathematical formulas. Implemented as Problem
impls in examples/benchmarks.rs; main() runs each, prints front /
best, and (for ZDT1) reports the mean L2 distance from the known
analytical Pareto front so the example doubles as a sanity check on
solution quality.
2026-05-04 19:35:03 -06:00
swaits c58d0241f9 docs(examples): add toy_nsga2, random_search, and custom_optimizer
The three runnable examples called out in spec §18.5 / §19. All open
with `use heuropt::prelude::*;` so they double as a check that the
prelude is sufficient on its own:

- toy_nsga2.rs: Schaffer N.1 solved with NSGA-II.
- random_search.rs: 2D sphere solved with RandomSearch.
- custom_optimizer.rs: a minimal hill-climber implementing
  `Optimizer<P>` directly, demonstrating spec §2.3.
2026-05-04 19:26:54 -06:00