use ndarray::{Array1, Array2, array};
#[cfg(feature = "checkpointing")]
use globalsearch::{
local_solver::builders::NelderMeadBuilder,
oqnlp::OQNLP,
problem::Problem,
types::{CheckpointConfig, EvaluationError, LocalSolverType, OQNLPParams},
};
#[cfg(feature = "checkpointing")]
use std::path::PathBuf;
#[cfg(not(feature = "checkpointing"))]
use globalsearch::{problem::Problem, types::EvaluationError};
#[derive(Debug, Clone)]
pub struct SixHumpCamel;
impl Problem for SixHumpCamel {
fn objective(&self, x: &Array1<f64>) -> Result<f64, EvaluationError> {
Ok((4.0 - 2.1 * x[0].powi(2) + x[0].powi(4) / 3.0) * x[0].powi(2)
+ x[0] * x[1]
+ (-4.0 + 4.0 * x[1].powi(2)) * x[1].powi(2))
}
fn gradient(&self, x: &Array1<f64>) -> Result<Array1<f64>, EvaluationError> {
Ok(array![
(8.0 - 8.4 * x[0].powi(2) + 2.0 * x[0].powi(4)) * x[0] + x[1],
x[0] + (-8.0 + 16.0 * x[1].powi(2)) * x[1]
])
}
fn hessian(&self, x: &Array1<f64>) -> Result<Array2<f64>, EvaluationError> {
Ok(array![
[
(4.0 * x[0].powi(2) - 4.2) * x[0].powi(2)
+ 4.0 * (4.0 / 3.0 * x[0].powi(3) - 4.2 * x[0]) * x[0]
+ 2.0 * (x[0].powi(4) / 3.0 - 2.1 * x[0].powi(2) + 4.0),
1.0
],
[1.0, 40.0 * x[1].powi(2) + 2.0 * (4.0 * x[1].powi(2) - 4.0)]
])
}
fn variable_bounds(&self) -> Array2<f64> {
array![[-3.0, 3.0], [-2.0, 2.0]]
}
}
#[cfg(feature = "checkpointing")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("OQNLP Checkpointing Example with Parameter Modification");
println!("======================================================");
let problem = SixHumpCamel;
let params = OQNLPParams {
local_solver_type: LocalSolverType::NelderMead,
local_solver_config: NelderMeadBuilder::default().build(),
iterations: 15, population_size: 200, wait_cycle: 10, ..OQNLPParams::default()
};
let checkpoint_config = CheckpointConfig {
checkpoint_dir: PathBuf::from("./oqnlp_checkpoints"),
checkpoint_name: "sixhump_camel".to_string(),
save_frequency: 10, keep_all: false, auto_resume: true, };
println!("Checkpoint configuration:");
println!(" Directory: {}", checkpoint_config.checkpoint_dir.display());
println!(" Save frequency: every {} iterations", checkpoint_config.save_frequency);
println!(" Auto-resume: {}", checkpoint_config.auto_resume);
println!();
println!("Starting initial optimization with {} iterations...", params.iterations);
let mut oqnlp = OQNLP::new(problem.clone(), params.clone())?
.with_checkpointing(checkpoint_config)?
.verbose();
let result = oqnlp.run()?;
println!("Initial optimization completed!");
println!("{}", result);
let extended_params = OQNLPParams {
iterations: 80, population_size: 1000, ..params
};
println!(
"\nContinuing optimization with {} iterations and expanded population to {} to find additional solutions...",
extended_params.iterations, extended_params.population_size
);
let mut continued_oqnlp = OQNLP::new(problem, extended_params.clone())?
.with_checkpointing(CheckpointConfig {
checkpoint_dir: PathBuf::from("./oqnlp_checkpoints"),
checkpoint_name: "sixhump_camel".to_string(),
save_frequency: 20,
keep_all: false,
auto_resume: false, })?
.verbose();
if continued_oqnlp.resume_with_modified_params(extended_params)? {
println!("Successfully resumed from checkpoint with extended parameters!");
let final_result = continued_oqnlp.run()?;
println!("Extended optimization completed!");
println!("{}", final_result)
} else {
println!("No checkpoint found to continue from!");
}
println!();
println!("This example demonstrates:");
println!("1. Running an initial optimization with checkpointing");
println!("2. Loading a checkpoint and continuing with modified parameters");
println!("3. Comparing results between the initial and extended runs");
Ok(())
}
#[cfg(not(feature = "checkpointing"))]
fn main() {
println!("This example requires the 'checkpointing' feature to be enabled.");
println!("Run with: cargo run --example checkpointing_example --features checkpointing");
}