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(80, |trial| {
.optimize(80, |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(100, |trial| {
.optimize(100, |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);
@@ -59,7 +59,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)
@@ -83,7 +83,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 {
@@ -112,7 +112,7 @@ fn seeded_reproducibility() {
let sampler = GpSampler::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)
@@ -135,7 +135,7 @@ fn different_seeds_different_results() {
let sampler = GpSampler::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)
@@ -160,7 +160,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))
})
@@ -182,7 +182,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)?;
Ok::<_, Error>(((nv - 10) * (nv - 10)) as f64)
})
@@ -209,7 +209,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)?;
Ok::<_, Error>((lrv.ln() - 0.01_f64.ln()).powi(2))
})
@@ -238,7 +238,7 @@ fn builder_configuration() {
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)