Commit Graph
4 Commits
Author SHA1 Message Date
swaits 6aee6d6318 style: rustfmt the Phase 1 test additions
The per-file Phase 1 test commits were written without running rustfmt
as I went; this pass formats the new test code (long assert_eq! lines
wrapped, etc.). Formatting-only — no behavioural change.
2026-05-14 03:41:38 -06:00
swaits c94357abe3 test(explorer): pin ExplorerExport, builders, ToDecisionValues outputs
Phase 0.3 of the mutation-testing campaign. Extends the inline tests in
src/explorer/mod.rs with 24 new tests covering the gaps cargo-mutants
identified — about 30 surviving mutants in this one file.

Coverage added:
- Exact-output tests for ToDecisionValues impls on Vec<f64>, Vec<i64>,
  Vec<bool>, Vec<usize> (the previous tests only asserted lengths or
  spot-checked individual entries).
- from_result propagates evaluations / generations from the
  OptimizationResult into RunMeta.
- with_problem_name / with_wall_clock / with_timestamp each set their
  field and preserve the rest of the export.
- to_json emits a JSON containing schema_version, candidates, problem
  name, and algorithm name strings.
- to_writer and to_file round-trip the same bytes.
- Free top-level to_json / to_writer / to_file convenience functions
  exercised end-to-end (round-trip through tmp file).
- pad_decision_schema at all three boundaries (< target / == target /
  > target) to pin the < comparison.
- candidate_to_export's in_pareto_front toggles at front_rank == 0.
- candidate_to_export's feasible toggles at constraint_violation <= 0.
- candidate_to_export pads short objective vectors and truncates long
  ones (the defensive branch).
2026-05-13 20:22:40 -06:00
swaits 6371d82f40 docs(0.9): release notes, cookbook recipe, README polish
Companion to the feat(explorer) commit. Bumps the version and
brings every cross-referencing doc up to v0.9 currency.

- Cargo.toml: version 0.8.0 -> 0.9.0.
- CHANGELOG: 0.9.0 entry covering the explorer export, the
  Problem-side metadata additions, the AlgorithmInfo trait, the
  pick_a_car example, and the new cookbook recipe.
- README: closing paragraph of the PickACar example points users
  at the explorer with a one-call snippet
  (`ExplorerExport::from_result(...).with_algorithm_info(...)
  .to_file(...)?`). Version snippets bumped 0.8 -> 0.9.
- New cookbook recipe at docs/book/src/cookbook/explorer.md
  covering: enabling the serde feature, enriching Problem with
  labels/units/decision-schema, the export call, the JSON schema,
  and custom decision-type handling.
- SUMMARY.md and cookbook.md link the new recipe.
- migration.md: new "To 0.9" section documenting the additive
  changes (purely backwards-compatible upgrade from 0.8.x).
- introduction.md, comparison.md, choosing-an-algorithm.md,
  stability.md: version refs bumped 0.8 -> 0.9.
- cookbook/parallel.md, cookbook/async.md: version refs bumped
  0.8 -> 0.9.
- getting-started.md: version refs bumped, serde feature
  description expanded to mention the explorer module.
- SECURITY.md: supported-versions table moves to 0.9.x.
2026-05-06 22:45:59 -06:00
swaits 729842c260 feat(explorer): JSON export module + supporting metadata + example
Adds a tiny additive surface that turns any OptimizationResult into
a self-describing JSON file the heuropt-explorer webapp can load.
Real Pareto fronts have 50–200+ candidates spanning 2–7+ objectives;
reading them as numbers in a terminal scales badly. This commit
ships the heuropt-side of the explorer — the schema and the export
API. The webapp itself lives in a separate repo on its own cadence.

Three trait/type extensions, all with working defaults so existing
impls compile untouched:

- Objective gains optional `label: Option<String>` and
  `unit: Option<String>` fields, plus fluent builders
  `.with_label("Price").with_unit(\"\$k\")`. Existing
  `Objective::minimize(name)` / `Objective::maximize(name)` are
  unchanged. Both fields are #[serde(default,
  skip_serializing_if = \"Option::is_none\")] so existing JSON
  round-trips cleanly.
- Problem trait gains an optional
  `fn decision_schema(&self) -> Vec<DecisionVariable>` with default
  empty impl. Override it to provide pretty names / labels / units /
  bounds for the explorer; the default produces fallback x[0],
  x[1], … names. New DecisionVariable type at
  `heuropt::core::DecisionVariable` with builder methods.
- New `heuropt::traits::AlgorithmInfo` trait with `name()`
  (required) and `seed()` (default None). Every built-in algorithm
  — all 33 — implements it. Separate from Optimizer<P> so
  multi-fidelity Hyperband (which uses PartialProblem) implements
  it uniformly.

The new explorer module:

- `heuropt::explorer::ExplorerExport` envelope with versioned
  schema (SCHEMA_VERSION = 1).
- ExplorerCandidate per row, with front_rank from
  non_dominated_sort attached at export time so downstream tools
  don't re-derive it.
- ToDecisionValues adapter trait with provided impls for Vec<f64>,
  Vec<bool>, Vec<usize>, Vec<i64>; custom decision types implement
  one method.
- Free functions to_json / to_writer / to_file plus a builder API
  (with_algorithm_info, with_problem_name, with_wall_clock,
  with_timestamp).
- Gated on the existing `serde` feature, which now also pulls in
  `serde_json` as a dep.

The example:

- `examples/pick_a_car.rs` — promotes the README's PickACar to a
  real example, fully enriched with Objective labels/units and a
  decision_schema. Runs NSGA-III for 200 generations, prints a
  sample slice, writes pick_a_car.json. Gated on `serde`.

10 new explorer unit tests cover round-trip serde, fallback
decision-variable names, enriched export, AlgorithmInfo flow,
front-rank correctness, and the ToDecisionValues impls. Lib test
count went from 229 to 242.
2026-05-06 12:48:01 -06:00