use globalsearch::problem::Problem;
use globalsearch::{
local_solver::builders::COBYLABuilder,
oqnlp::OQNLP,
types::{EvaluationError, LocalSolverType, OQNLPParams, SolutionSet},
};
use ndarray::{Array1, Array2, array};
#[derive(Debug, Clone)]
pub struct Rosenbrock {
a: f64,
b: f64,
}
impl Rosenbrock {
pub fn new(a: f64, b: f64) -> Self {
Self { a, b }
}
pub fn standard() -> Self {
Self::new(1.0, 100.0)
}
}
impl Problem for Rosenbrock {
fn objective(&self, x: &Array1<f64>) -> Result<f64, EvaluationError> {
if x.len() != 2 {
return Err(EvaluationError::InvalidInput {
reason: "Rosenbrock function requires exactly 2 variables".to_string(),
});
}
let x_val = x[0];
let y_val = x[1];
let term1 = (self.a - x_val).powi(2);
let term2 = self.b * (y_val - x_val.powi(2)).powi(2);
Ok(term1 + term2)
}
fn variable_bounds(&self) -> Array2<f64> {
array![
[-5.0, 10.0], [-5.0, 10.0] ]
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Optimizing the Rosenbrock function: f(x,y) = (1-x)² + 100(y-x²)²");
println!("Global minimum: f(1, 1) = 0");
println!();
let problem = Rosenbrock::standard();
let local_solver_config = COBYLABuilder::default()
.max_iter(500) .initial_step_size(0.1) .ftol_rel(1e-10) .ftol_abs(1e-12) .build();
let params = OQNLPParams {
iterations: 750, population_size: 1500, wait_cycle: 15, threshold_factor: 0.65, distance_factor: 0.10, local_solver_type: LocalSolverType::COBYLA,
local_solver_config, seed: 0, };
println!("Optimization Settings:");
println!("- Stage two iterations: {}", params.iterations);
println!("- Population size: {}", params.population_size);
println!("- Local solver: {:?}", params.local_solver_type);
println!("- Random seed: {}", params.seed);
println!();
println!("Starting optimization...");
let mut oqnlp: OQNLP<Rosenbrock> = OQNLP::new(problem, params)?;
let solution_set: SolutionSet = oqnlp.run()?;
println!("Optimization completed!");
println!("{}", solution_set);
if let Some(best) = solution_set.best_solution() {
println!("Detailed Analysis:");
println!("=================");
let x_opt = best.point[0];
let y_opt = best.point[1];
let f_opt = best.objective;
println!("Distance from global minimum (1, 1):");
let distance = ((x_opt - 1.0).powi(2) + (y_opt - 1.0).powi(2)).sqrt();
println!(" Euclidean distance: {:.6}", distance);
println!(" Error in objective: {:.8}", f_opt);
println!();
if f_opt < 1e-4 {
println!("Found global minimum with high precision");
} else if f_opt < 1e-2 {
println!("Close to the global minimum");
} else if f_opt < 1.0 {
println!("Good solution, near the global minimum");
} else {
println!("Solution found, but may be a local minimum");
}
} else {
println!("No solutions found");
}
Ok(())
}