use approx::assert_relative_eq;
use std::cell::RefCell;
use ipopt::*;
struct NLP {
z: bool,
iterations: usize,
x_start: RefCell<Vec<f64>>, }
impl NLP {
fn count_iterations_cb(&mut self, data: IntermediateCallbackData) -> bool {
self.iterations = data.iter_count as usize;
true
}
fn save_solution_for_warm_start(&mut self, solution: Solution) {
self.x_start.borrow_mut().clear();
self.x_start
.borrow_mut()
.extend_from_slice(&solution.primal_variables);
}
}
impl BasicProblem for NLP {
fn num_variables(&self) -> usize {
let n = if self.z { 3 } else { 2 };
self.x_start.borrow_mut().resize(n, 0.0);
n
}
fn bounds(&self, x_l: &mut [Number], x_u: &mut [Number]) -> bool {
let n = x_l.len();
assert_eq!(x_l.len(), x_u.len());
assert_eq!(n, self.num_variables());
x_l.swap_with_slice(vec![-1e20; n].as_mut_slice());
x_u.swap_with_slice(vec![1e20; n].as_mut_slice());
true
}
fn initial_point(&self, x: &mut [Number]) -> bool {
let n = x.len();
assert_eq!(n, self.num_variables());
x.copy_from_slice(&self.x_start.borrow());
true
}
fn objective(&self, x: &[Number], _: bool, obj: &mut Number) -> bool {
*obj = 0.0;
for &val in x.iter() {
*obj += (val - 1.0) * (val - 1.0);
}
*obj *= 0.5;
true
}
fn objective_grad(&self, x: &[Number], _: bool, grad_f: &mut [Number]) -> bool {
for (g, &val) in grad_f.iter_mut().zip(x.iter()) {
*g = val - 1.0;
}
true
}
}
impl NewtonProblem for NLP {
fn num_hessian_non_zeros(&self) -> usize {
self.num_variables()
}
fn hessian_indices(&self, rows: &mut [Index], cols: &mut [Index]) -> bool {
for i in 0..self.num_hessian_non_zeros() {
rows[i] = i as Index;
cols[i] = i as Index;
}
true
}
fn hessian_values(&self, _x: &[Number], vals: &mut [Number]) -> bool {
for i in 0..self.num_hessian_non_zeros() {
vals[i] = 1.0;
}
true
}
}
#[test]
fn quadratic_test() {
let nlp = NLP {
z: false,
iterations: 0,
x_start: RefCell::new(vec![0.0; 2]),
};
let mut ipopt = Ipopt::new_newton(nlp).unwrap();
ipopt.set_intermediate_callback(Some(NLP::count_iterations_cb));
ipopt.set_option("tol", 1e-9);
ipopt.set_option("mu_strategy", "adaptive");
ipopt.set_option("sb", "yes"); ipopt.set_option("print_level", 0);
{
let SolveResult {
solver_data: SolverDataMut {
problem, solution, ..
},
objective_value: obj,
status,
..
} = ipopt.solve();
let x = solution.primal_variables;
assert_eq!(status, SolveStatus::SolveSucceeded);
assert_eq!(problem.iterations, 1);
assert_relative_eq!(x[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(x[1], 1.0, epsilon = 1e-10);
assert_relative_eq!(obj, 0.0, epsilon = 1e-10);
problem.save_solution_for_warm_start(solution);
}
ipopt.set_option("warm_start_init_point", "yes");
{
let SolveResult {
solver_data: SolverDataMut { problem, .. },
status,
..
} = ipopt.solve();
assert_eq!(status, SolveStatus::SolveSucceeded);
assert_eq!(problem.iterations, 0);
}
ipopt.solver_data_mut().problem.z = true;
{
let SolveResult {
solver_data:
SolverDataMut {
problem,
solution:
Solution {
primal_variables: x,
..
},
},
objective_value: obj,
status,
..
} = ipopt.solve();
assert_eq!(status, SolveStatus::SolveSucceeded);
assert_eq!(problem.iterations, 1);
assert_relative_eq!(x[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(x[1], 1.0, epsilon = 1e-10);
assert_relative_eq!(x[2], 1.0, epsilon = 1e-10);
assert_relative_eq!(obj, 0.0, epsilon = 1e-10);
}
}