feat: unify optimize and optimize_with via blanket Objective impl

- Add blanket `impl Objective<V> for Fn(&mut Trial) -> Result<V, E>`
  so closures work directly with `optimize`
- Rewrite optimize, optimize_async, optimize_parallel to accept
  `impl Objective<V>` with before_trial/after_trial hooks
- Remove optimize_with, optimize_with_async, optimize_with_parallel
- Remove max_retries and retry logic from Objective trait
- Add explicit closure type annotations for HRTB inference
- Convert FnMut test closures to Fn via RefCell/Cell
This commit is contained in:
Manuel Raimann
2026-02-12 13:09:14 +01:00
parent c20a53dfba
commit 47b5f9cec8
41 changed files with 316 additions and 793 deletions
+10 -10
View File
@@ -10,7 +10,7 @@ fn sphere_function() {
let y = FloatParam::new(-5.0, 5.0).name("y");
study
.optimize(200, |trial| {
.optimize(200, |trial: &mut optimizer::Trial| {
let xv = x.suggest(trial)?;
let yv = y.suggest(trial)?;
Ok::<_, Error>(xv * xv + yv * yv)
@@ -34,7 +34,7 @@ fn rosenbrock_function() {
let y = FloatParam::new(-5.0, 5.0).name("y");
study
.optimize(300, |trial| {
.optimize(300, |trial: &mut optimizer::Trial| {
let xv = x.suggest(trial)?;
let yv = y.suggest(trial)?;
let val = (1.0 - xv).powi(2) + 100.0 * (yv - xv * xv).powi(2);
@@ -60,7 +60,7 @@ fn bounds_respected() {
let y = FloatParam::new(0.0, 10.0).name("y");
study
.optimize(100, |trial| {
.optimize(100, |trial: &mut optimizer::Trial| {
let xv = x.suggest(trial)?;
let yv = y.suggest(trial)?;
Ok::<_, Error>(xv + yv)
@@ -84,7 +84,7 @@ fn mixed_params_float_and_categorical() {
let cat = CategoricalParam::new(vec!["a", "b", "c"]).name("cat");
study
.optimize(50, |trial| {
.optimize(50, |trial: &mut optimizer::Trial| {
let xv = x.suggest(trial)?;
let cv = cat.suggest(trial)?;
let penalty = match cv {
@@ -114,7 +114,7 @@ fn seeded_reproducibility() {
let sampler = CmaEsSampler::with_seed(seed);
let study: Study<f64> = Study::with_sampler(Direction::Minimize, sampler);
study
.optimize(50, |trial| {
.optimize(50, |trial: &mut optimizer::Trial| {
let xv = x.suggest(trial)?;
let yv = y.suggest(trial)?;
Ok::<_, Error>(xv * xv + yv * yv)
@@ -137,7 +137,7 @@ fn different_seeds_different_results() {
let sampler = CmaEsSampler::with_seed(seed);
let study: Study<f64> = Study::with_sampler(Direction::Minimize, sampler);
study
.optimize(20, |trial| {
.optimize(20, |trial: &mut optimizer::Trial| {
let xv = x.suggest(trial)?;
let yv = y.suggest(trial)?;
Ok::<_, Error>(xv * xv + yv * yv)
@@ -162,7 +162,7 @@ fn single_dimension() {
let x = FloatParam::new(-10.0, 10.0).name("x");
study
.optimize(100, |trial| {
.optimize(100, |trial: &mut optimizer::Trial| {
let xv = x.suggest(trial)?;
Ok::<_, Error>((xv - 3.0).powi(2))
})
@@ -184,7 +184,7 @@ fn integer_params() {
let n = IntParam::new(1, 20).name("n");
study
.optimize(100, |trial| {
.optimize(100, |trial: &mut optimizer::Trial| {
let nv = n.suggest(trial)?;
// Minimum at n = 10
Ok::<_, Error>(((nv - 10) * (nv - 10)) as f64)
@@ -212,7 +212,7 @@ fn log_scale_params() {
let lr = FloatParam::new(1e-5, 1.0).log_scale().name("lr");
study
.optimize(100, |trial| {
.optimize(100, |trial: &mut optimizer::Trial| {
let lrv = lr.suggest(trial)?;
// Minimum at lr = 0.01
Ok::<_, Error>((lrv.ln() - 0.01_f64.ln()).powi(2))
@@ -241,7 +241,7 @@ fn custom_population_size_and_sigma() {
let y = FloatParam::new(-5.0, 5.0).name("y");
study
.optimize(100, |trial| {
.optimize(100, |trial: &mut optimizer::Trial| {
let xv = x.suggest(trial)?;
let yv = y.suggest(trial)?;
Ok::<_, Error>(xv * xv + yv * yv)