use globalsearch::local_solver::builders::COBYLABuilder;
use globalsearch::observers::Observer;
use globalsearch::oqnlp::OQNLP;
use globalsearch::problem::Problem;
use globalsearch::types::{EvaluationError, LocalSolverType, OQNLPParams};
use ndarray::{Array1, Array2, array};
#[derive(Debug, Clone)]
pub struct Shubert;
impl Problem for Shubert {
fn objective(&self, x: &Array1<f64>) -> Result<f64, EvaluationError> {
let x1 = x[0];
let x2 = x[1];
let sum1: f64 = (1..=5)
.map(|i| {
let i_f64 = i as f64;
i_f64 * ((i_f64 + 1.0) * x1 + i_f64).cos()
})
.sum();
let sum2: f64 = (1..=5)
.map(|i| {
let i_f64 = i as f64;
i_f64 * ((i_f64 + 1.0) * x2 + i_f64).cos()
})
.sum();
Ok(sum1 * sum2)
}
fn variable_bounds(&self) -> Array2<f64> {
array![[-10.0, 10.0], [-10.0, 10.0]]
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Shubert Function Optimization with Observer\n");
println!("Global minimum: f(x*) = -186.7309");
println!("Number of global minima: 18");
println!("Bounds: [-10.0, 10.0] for each dimension\n");
let problem = Shubert;
let params = OQNLPParams {
iterations: 5000,
wait_cycle: 25,
threshold_factor: 0.3,
distance_factor: 0.8,
population_size: 13000,
local_solver_type: LocalSolverType::COBYLA,
local_solver_config: COBYLABuilder::default().max_iter(75).initial_step_size(1.0).build(),
seed: 0,
};
let observer = Observer::new()
.with_stage1_tracking()
.with_stage2_tracking()
.with_timing()
.with_default_callback();
println!("Running optimization...\n");
let mut oqnlp = OQNLP::new(problem.clone(), params)?.add_observer(observer);
let solution_set = oqnlp.run()?;
println!("\nOptimization Complete");
println!("{}", solution_set);
Ok(())
}