use optimization_engine::{
alm::*,
core::{constraints::*, panoc::*},
matrix_operations, SolverError,
};
pub fn f(u: &[f64], cost: &mut f64) -> Result<(), SolverError> {
*cost = 0.5 * matrix_operations::norm2_squared(u) + matrix_operations::sum(u);
Ok(())
}
pub fn df(u: &[f64], grad: &mut [f64]) -> Result<(), SolverError> {
grad.iter_mut()
.zip(u.iter())
.for_each(|(grad_i, u_i)| *grad_i = u_i + 1.0);
Ok(())
}
pub fn f2(u: &[f64], res: &mut [f64]) -> Result<(), SolverError> {
res[0] = matrix_operations::norm2_squared(u) - 1.;
Ok(())
}
pub fn jf2t(u: &[f64], d: &[f64], res: &mut [f64]) -> Result<(), crate::SolverError> {
res.iter_mut()
.zip(u.iter())
.for_each(|(res_i, u_i)| *res_i = u_i * d[0]);
Ok(())
}
fn main() {
let tolerance = 1e-4;
let nx = 3;
let n1 = 0;
let n2 = 1;
let lbfgs_mem = 5;
let panoc_cache = PANOCCache::new(nx, tolerance, lbfgs_mem);
let mut alm_cache = AlmCache::new(panoc_cache, n1, n2);
let bounds = NoConstraints::new();
let factory = AlmFactory::new(
f,
df,
NO_MAPPING,
NO_JACOBIAN_MAPPING,
Some(f2),
Some(jf2t),
NO_SET,
n2,
);
let alm_problem = AlmProblem::new(
bounds,
NO_SET,
NO_SET,
|u: &[f64], xi: &[f64], cost: &mut f64| -> Result<(), SolverError> {
factory.psi(u, xi, cost)
},
|u: &[f64], xi: &[f64], grad: &mut [f64]| -> Result<(), SolverError> {
factory.d_psi(u, xi, grad)
},
NO_MAPPING,
Some(f2),
n1,
n2,
);
let mut alm_optimizer = AlmOptimizer::new(&mut alm_cache, alm_problem)
.with_delta_tolerance(1e-6)
.with_epsilon_tolerance(1e-5)
.with_max_outer_iterations(20)
.with_max_inner_iterations(1000)
.with_initial_penalty(5000.0)
.with_penalty_update_factor(2.2);
let mut u = vec![0.1; nx];
let solver_result = alm_optimizer.solve(&mut u);
let r = solver_result.unwrap();
println!("\n\nSolver result : {:#.7?}\n", r);
println!("Solution u = {:#.6?}", u);
}