Crate ipopt_ad

Crate ipopt_ad 

Source
Expand description

§IPOPT-AD - Blackbox NLP solver using IPOPT and automatic differentiation

This crate provides a simple interface to the IPOPT nonlinear program (NLP) solver. By evaluating gradients and Hessians using automatic differentiation provided by the [num-dual] crate, it “converts” IPOPT into a blackbox solver without introducing numerical errors through forward differences that could diminish the robustness and accuracy. The only limitation is that the evaluation of the objective and constraints has to be implemented generically for values implementing the DualNum trait.

§Example: problem 71 from the Hock-Schittkowsky test-suite

This example demonstrates how to solve the problem that is also used as example in the documentation of IPOPT. Because the objective value and constraints are simple functions of x, the SimpleADProblem interface can be used.

use ipopt_ad::{ADProblem, BasicADProblem, SimpleADProblem};
use ipopt_ad::ipopt::Ipopt;
use num_dual::DualNum;
use approx::assert_relative_eq;

struct HS071;

impl BasicADProblem<4> for HS071 {
    fn bounds(&self) -> ([f64; 4], [f64; 4]) {
        ([1.0; 4], [5.0; 4])
    }
    fn initial_point(&self) -> [f64; 4] {
        [1.0, 5.0, 5.0, 1.0]
    }
    fn constraint_bounds(&self) -> (Vec<f64>, Vec<f64>) {
        (vec![25.0, 40.0], vec![f64::INFINITY, 40.0])
    }
}

impl SimpleADProblem<4> for HS071 {
    fn objective<D: DualNum<f64> + Copy>(&self, x: [D; 4]) -> D {
        let [x1, x2, x3, x4] = x;
        x1 * x4 * (x1 + x2 + x3) + x3
    }
    fn constraint_values<D: DualNum<f64> + Copy>(&self, x: [D; 4]) -> Vec<D> {
        let [x1, x2, x3, x4] = x;
        vec![x1 * x2 * x3 * x4, x1 * x1 + x2 * x2 + x3 * x3 + x4 * x4]
    }
}

let problem = ADProblem::new(HS071);
let mut ipopt = Ipopt::new(problem).unwrap();
ipopt.set_option("print_level", 0);
let res = ipopt.solve();
let x = res.solver_data.solution.primal_variables;
let x_lit = &[1f64, 4.74299963, 3.82114998, 1.37940829] as &[f64];
assert_relative_eq!(x, x_lit, max_relative = 1e-8);

For more complex NLPs, it can be advantageous to evaluate the objective function and constraints simultaneously, which is possible with the CachedADProblem interface. For the HS071 problem, this looks like this:

impl CachedADProblem<4> for HS071 {
    type Error = Infallible;
    fn evaluate<D: DualNum<f64> + Copy>(&self, x: [D; 4]) -> Result<(D, Vec<D>), Infallible> {
        let [x1, x2, x3, x4] = x;
        Ok((
            x1 * x4 * (x1 + x2 + x3) + x3,
            vec![x1 * x2 * x3 * x4, x1 * x1 + x2 * x2 + x3 * x3 + x4 * x4],
        ))
    }
}

let problem = ADProblem::new_cached(HS071).unwrap();
let mut ipopt = Ipopt::new(problem).unwrap();
ipopt.set_option("print_level", 0);
let res = ipopt.solve();
let x = res.solver_data.solution.primal_variables;
let x_lit = &[1f64, 4.74299963, 3.82114998, 1.37940829] as &[f64];
assert_relative_eq!(x, x_lit, max_relative = 1e-8);

Modules§

ipopt
Re-export of all functionalities in [ipopt-rs].

Structs§

ADProblem
Wrapper struct that handles caching and sparsity detection to interface between the blackbox model and IPOPT.

Traits§

BasicADProblem
The basic information that needs to be provided for every optimization problem.
CachedADProblem
The interface for an NLP in which it is more efficient to evaluate the objective and constraint value in the same function.
SimpleADProblem
The interface for a simple NLP in which the objective function and constraint values are determined separate from each other.