Files
heuropt/docs/book/src/getting-started.md
T
swaits fa3f2e8fb0 feat: v0.5.0 — comprehensive documentation release
Theme: documentation and project polish. No public-API changes; this
is the v0.5 release that elevates heuropt's docs/onboarding/governance
to bar-setting status.

Adds:
- mdbook user guide at docs/book/ with intro, getting-started,
  defining-problems, choosing-an-algorithm, cookbook (7 recipes),
  comparison vs other libraries, stability/SemVer, migration guides.
  Deploys to https://swaits.github.io/heuropt/ via .github/workflows/
  docs.yml.
- Runnable rustdoc examples on every algorithm (35 of them), all
  exercised by cargo test --doc.
- Three real-world examples: portfolio.rs (multi-obj with budget
  constraint), hyperparam_tuning.rs (BO + TPE), scheduling.rs
  (permutation via SA + SwapMutation against Smith's-rule oracle).
- Governance: CONTRIBUTING.md, SECURITY.md, CODE_OF_CONDUCT.md
  (adopting builderscode.org's Builder's Code of Conduct), GitHub
  issue templates, PR template.

Polishes:
- README hero with badges + user-guide link.
- lib.rs crate-level docs.
- CHANGELOG entry for 0.5.0.

Bumps Cargo.toml to 0.5.0.
2026-05-05 14:33:12 -06:00

3.9 KiB

Five-minute walkthrough

The shortest path from a fresh project to a working optimizer.

1. Add heuropt to your Cargo.toml

[dependencies]
heuropt = "0.5"

The default feature set is small. Optional features:

  • parallel — rayon-backed parallel population evaluation.
  • serdeSerialize / Deserialize derives on the core data types.
heuropt = { version = "0.5", features = ["parallel"] }

2. Define a problem

A problem is a struct that implements the Problem trait. You tell heuropt what kind of decision your problem takes (Vec<f64>, Vec<bool>, …), what objectives it has (minimize or maximize), and how to score one decision.

use heuropt::prelude::*;

struct Sphere;

impl Problem for Sphere {
    type Decision = Vec<f64>;

    fn objectives(&self) -> ObjectiveSpace {
        ObjectiveSpace::new(vec![Objective::minimize("f")])
    }

    fn evaluate(&self, x: &Vec<f64>) -> Evaluation {
        let f: f64 = x.iter().map(|v| v * v).sum();
        Evaluation::new(vec![f])
    }
}

The Sphere function is a single-objective continuous problem: minimize f(x) = Σ xᵢ². The optimum is x = 0, f = 0.

3. Pick an algorithm and run it

For a smooth single-objective continuous problem, CmaEs is a strong default. Configure it, build it, run it.

# use heuropt::prelude::*;
# struct Sphere;
# impl Problem for Sphere {
#     type Decision = Vec<f64>;
#     fn objectives(&self) -> ObjectiveSpace {
#         ObjectiveSpace::new(vec![Objective::minimize("f")])
#     }
#     fn evaluate(&self, x: &Vec<f64>) -> Evaluation {
#         Evaluation::new(vec![x.iter().map(|v| v * v).sum::<f64>()])
#     }
# }
let bounds = RealBounds::new(vec![(-5.0, 5.0); 5]); // 5-dim search box

let mut opt = CmaEs::new(
    CmaEsConfig {
        population_size: 12,
        generations: 80,
        initial_sigma: 1.0,
        eigen_decomposition_period: 1,
        initial_mean: None,
        seed: 42,
    },
    bounds,
);

let result = opt.run(&Sphere);

let best = result.best.expect("at least one feasible candidate");
println!("best f = {:.3e} at x = {:?}", best.evaluation.objectives[0], best.decision);

Run with cargo run --release — heuristic optimization is allergic to debug builds. Expect output like:

best f = 1.4e-29 at x = [-1.6e-15, 4.5e-16, ...]

CMA-ES drops to machine epsilon on the Sphere in well under 80 generations.

4. What just happened

  • Problem is the what you're optimizing.
  • CmaEs (or any other optimizer) is the how.
  • CmaEsConfig is a plain public-field struct: there are no builders, no chained setters, just public fields you set directly.
  • Optimizer::run returns an OptimizationResult containing the full final population, the pareto_front (just the best for single-objective), the best candidate, the total evaluations, and the number of generations.

5. Where to go next

  • Multi-objective: see Defining a problem for how to express two or more objectives, and Choosing an algorithm for which optimizer fits.
  • Want to know which algorithm to pick: read the README's decision tree, or jump straight to the choosing-an-algorithm chapter for the long form.
  • Production patterns: the cookbook has recipes for parallelism, expensive evaluations, comparing algorithms, and more.