//! Implement a custom optimizer by implementing `Optimizer

` directly. //! //! Demonstrates spec ยง2.3: a junior engineer can add a new algorithm by //! implementing a single trait, with no framework gymnastics required. //! //! Run with: //! //! ```bash //! cargo run --example custom_optimizer //! ``` use heuropt::prelude::*; /// A trivial single-objective hill-climber: sample one point, then repeatedly /// jitter it with `GaussianMutation` and keep the better feasible result. struct HillClimber { iterations: usize, sigma: f64, initializer: RealBounds, seed: u64, } impl

Optimizer

for HillClimber where P: Problem>, { fn run(&mut self, problem: &P) -> OptimizationResult { let objectives = problem.objectives(); assert!( objectives.is_single_objective(), "HillClimber needs one objective" ); let mut rng = rng_from_seed(self.seed); let mut variation = GaussianMutation { sigma: self.sigma }; let mut current = self.initializer.initialize(1, &mut rng).remove(0); let mut current_eval = problem.evaluate(¤t); let mut evaluations = 1; for _ in 0..self.iterations { let children = variation.vary(&[current.clone()], &mut rng); let candidate = children.into_iter().next().unwrap(); let candidate_eval = problem.evaluate(&candidate); evaluations += 1; // Accept on direction-correct improvement (Sphere is minimize). let accept = candidate_eval.objectives[0] < current_eval.objectives[0]; if accept { current = candidate; current_eval = candidate_eval; } } let best = Candidate::new(current.clone(), current_eval.clone()); let population = Population::new(vec![best.clone()]); let pareto_front = vec![best.clone()]; OptimizationResult::new( population, pareto_front, Some(best), evaluations, self.iterations, ) } } struct Sphere1D; impl Problem for Sphere1D { type Decision = Vec; fn objectives(&self) -> ObjectiveSpace { ObjectiveSpace::new(vec![Objective::minimize("f")]) } fn evaluate(&self, x: &Vec) -> Evaluation { Evaluation::new(vec![x[0] * x[0]]) } } fn main() { let mut climber = HillClimber { iterations: 500, sigma: 0.5, initializer: RealBounds::new(vec![(-5.0, 5.0)]), seed: 11, }; let result = climber.run(&Sphere1D); let best = result.best.expect("single-objective always has a best"); println!("Hill-climber best f = {:.6}", best.evaluation.objectives[0]); println!("Total evaluations: {}", result.evaluations); }