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:
+23
-15
@@ -1,3 +1,5 @@
|
||||
use std::cell::RefCell;
|
||||
|
||||
use optimizer::parameter::{CategoricalParam, FloatParam, IntParam, Parameter};
|
||||
use optimizer::sampler::random::RandomSampler;
|
||||
use optimizer::{Direction, Error, Study};
|
||||
@@ -7,18 +9,20 @@ fn test_random_sampler_uniform_float_distribution() {
|
||||
let study: Study<f64> = Study::with_sampler(Direction::Minimize, RandomSampler::with_seed(42));
|
||||
|
||||
let n_samples = 1000;
|
||||
let mut samples = Vec::with_capacity(n_samples);
|
||||
let samples = RefCell::new(Vec::with_capacity(n_samples));
|
||||
|
||||
let x_param = FloatParam::new(0.0, 1.0);
|
||||
|
||||
study
|
||||
.optimize(n_samples, |trial| {
|
||||
.optimize(n_samples, |trial: &mut optimizer::Trial| {
|
||||
let x = x_param.suggest(trial)?;
|
||||
samples.push(x);
|
||||
samples.borrow_mut().push(x);
|
||||
Ok::<_, Error>(x)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut samples = samples.into_inner();
|
||||
|
||||
// All samples should be in range
|
||||
for &s in &samples {
|
||||
assert!((0.0..=1.0).contains(&s), "sample {s} out of range [0, 1]");
|
||||
@@ -44,19 +48,20 @@ fn test_random_sampler_uniform_int_distribution() {
|
||||
let study: Study<f64> = Study::with_sampler(Direction::Minimize, RandomSampler::with_seed(123));
|
||||
|
||||
let n_samples = 5000;
|
||||
let mut counts = [0u32; 10]; // counts for values 1-10
|
||||
let counts = RefCell::new([0u32; 10]); // counts for values 1-10
|
||||
|
||||
let n_param = IntParam::new(1, 10);
|
||||
|
||||
study
|
||||
.optimize(n_samples, |trial| {
|
||||
.optimize(n_samples, |trial: &mut optimizer::Trial| {
|
||||
let n = n_param.suggest(trial)?;
|
||||
assert!((1..=10).contains(&n), "sample {n} out of range [1, 10]");
|
||||
counts[(n - 1) as usize] += 1;
|
||||
counts.borrow_mut()[(n - 1) as usize] += 1;
|
||||
Ok::<_, Error>(n as f64)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let counts = counts.into_inner();
|
||||
let expected = n_samples as f64 / 10.0;
|
||||
for (i, &count) in counts.iter().enumerate() {
|
||||
let diff = (count as f64 - expected).abs() / expected;
|
||||
@@ -76,20 +81,21 @@ fn test_random_sampler_uniform_categorical_distribution() {
|
||||
let study: Study<f64> = Study::with_sampler(Direction::Minimize, RandomSampler::with_seed(456));
|
||||
|
||||
let n_samples = 2000;
|
||||
let mut counts = [0u32; 4];
|
||||
let counts = RefCell::new([0u32; 4]);
|
||||
let choices = ["a", "b", "c", "d"];
|
||||
|
||||
let cat_param = CategoricalParam::new(choices.to_vec());
|
||||
|
||||
study
|
||||
.optimize(n_samples, |trial| {
|
||||
.optimize(n_samples, |trial: &mut optimizer::Trial| {
|
||||
let choice = cat_param.suggest(trial)?;
|
||||
let idx = choices.iter().position(|&c| c == choice).unwrap();
|
||||
counts[idx] += 1;
|
||||
counts.borrow_mut()[idx] += 1;
|
||||
Ok::<_, Error>(idx as f64)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let counts = counts.into_inner();
|
||||
let expected = n_samples as f64 / 4.0;
|
||||
for (i, &count) in counts.iter().enumerate() {
|
||||
let diff = (count as f64 - expected).abs() / expected;
|
||||
@@ -111,28 +117,30 @@ fn test_random_sampler_reproducibility() {
|
||||
let study2: Study<f64> =
|
||||
Study::with_sampler(Direction::Minimize, RandomSampler::with_seed(999));
|
||||
|
||||
let mut values1 = Vec::new();
|
||||
let mut values2 = Vec::new();
|
||||
let values1 = RefCell::new(Vec::new());
|
||||
let values2 = RefCell::new(Vec::new());
|
||||
|
||||
let x_param1 = FloatParam::new(0.0, 100.0);
|
||||
let x_param2 = FloatParam::new(0.0, 100.0);
|
||||
|
||||
study1
|
||||
.optimize(100, |trial| {
|
||||
.optimize(100, |trial: &mut optimizer::Trial| {
|
||||
let x = x_param1.suggest(trial)?;
|
||||
values1.push(x);
|
||||
values1.borrow_mut().push(x);
|
||||
Ok::<_, Error>(x)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
study2
|
||||
.optimize(100, |trial| {
|
||||
.optimize(100, |trial: &mut optimizer::Trial| {
|
||||
let x = x_param2.suggest(trial)?;
|
||||
values2.push(x);
|
||||
values2.borrow_mut().push(x);
|
||||
Ok::<_, Error>(x)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let values1 = values1.into_inner();
|
||||
let values2 = values2.into_inner();
|
||||
for (i, (v1, v2)) in values1.iter().zip(values2.iter()).enumerate() {
|
||||
assert_eq!(
|
||||
v1, v2,
|
||||
|
||||
Reference in New Issue
Block a user