Giter Site home page Giter Site logo

ipopt-rs's Introduction

ipopt-rs

A safe Rust interface to the Ipopt non-linear optimization library.

On crates.io On docs.rs Build status

From the Ipopt webpage:

Ipopt (Interior Point OPTimizer, pronounced eye-pea-Opt) is a software package for large-scale nonlinear optimization. It is designed to find (local) solutions of mathematical optimization problems of the from

   min     f(x)
   x in R^n

   s.t.       g_L <= g(x) <= g_U
              x_L <=  x   <= x_U

where f(x): R^n --> R is the objective function, and g(x): R^n --> R^m are the constraint functions. The vectors g_L and g_U denote the lower and upper bounds on the constraints, and the vectors x_L and x_U are the bounds on the variables x. The functions f(x) and g(x) can be nonlinear and nonconvex, but should be twice continuously differentiable. Note that equality constraints can be formulated in the above formulation by setting the corresponding components of g_L and g_U to the same value.

This crate aims to

  • Reduce the boilerplate, especially for setting up simple unconstrained problems
  • Maintain flexiblity for advanced use cases
  • Prevent common mistakes when defining optimization problems as early as possible using the type system and error checking.

Examples

Solve a simple unconstrained problem using L-BFGS: minimize (x - 1)^2 + (y -1)^2

use approx::*;
use ipopt::*;

struct NLP {
}

impl BasicProblem for NLP {
    // There are two independent variables: x and y.
    fn num_variables(&self) -> usize {
        2
    }    
    // The variables are unbounded. Any lower bound lower than -10^9 and upper bound higher
    // than 10^9 is treated effectively as infinity. These absolute infinity limits can be
    // changed via the `nlp_lower_bound_inf` and `nlp_upper_bound_inf` Ipopt options.
    fn bounds(&self, x_l: &mut [Number], x_u: &mut [Number]) -> bool {
        x_l.swap_with_slice(vec![-1e20; 2].as_mut_slice());
        x_u.swap_with_slice(vec![1e20; 2].as_mut_slice());
        true
    }

    // Set the initial conditions for the solver.
    fn initial_point(&self, x: &mut [Number]) -> bool {
        x.swap_with_slice(vec![0.0, 0.0].as_mut_slice());
        true
    }

    // The objective to be minimized.
    fn objective(&self, x: &[Number], obj: &mut Number) -> bool {
        *obj = (x[0] - 1.0)*(x[0] - 1.0) + (x[1] - 1.0)*(x[1] - 1.0);
        true
    }

    // Objective gradient is used to find a new search direction to find the critical point.
    fn objective_grad(&self, x: &[Number], grad_f: &mut [Number]) -> bool {
        grad_f[0] = 2.0*(x[0] - 1.0);
        grad_f[1] = 2.0*(x[1] - 1.0);
        true
    }
}

fn main() {
    let nlp = NLP { };
    let mut ipopt = Ipopt::new_unconstrained(nlp).unwrap();

    // Set Ipopt specific options here a list of all options is available at
    // https://www.coin-or.org/Ipopt/documentation/node40.html
    ipopt.set_option("tol", 1e-9); // set error tolerance
    ipopt.set_option("print_level", 5); // set the print level (5 is the default)

    let solve_result = ipopt.solve();

    assert_eq!(solve_result.status, SolveStatus::SolveSucceeded);
    assert_relative_eq!(solve_result.objective_value, 0.0, epsilon = 1e-10);
    let solution = solve_result.solver_data.solution;
    assert_relative_eq!(solution.primal_variables[0], 1.0, epsilon = 1e-10);
    assert_relative_eq!(solution.primal_variables[1], 1.0, epsilon = 1e-10);
}

See the tests for more examples including constrained optimization.

Getting Ipopt Binaries

As it stands, this library is still immature in terms of platform support. There is ongoing work to improve this. For instance Windows is not currently supported until I get a Windows machine or somebody else pitches in to provide the support ;)

For details on how Ipopt binaries are acquired see ipopt-sys.

License

This repository is licensed under either of

at your option.

ipopt-rs's People

Contributors

elaye avatar elrnv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

ipopt-rs's Issues

Resolve build errors on docs.rs

At the time of this writing, it looks like the docs.rs runner is missing libgfortran. There may be other issues as well.
This issue has more to do with fixing the build script to ensure that missing libraries don't cause the build to fail, but simply fall back to another method for getting the binaries such as downloading them from JuliaOpt.

Extract custom C/C++ layer into a separate lib

Currently, it is required to build Ipopt from scratch because I opted to customize the C API for rust and at build time, manually copy the modified files into the Ipopt build folder. This is awkward and prevents users from using prebuilt Ipopt binaries. Building Ipopt is not particularly quick and it is cumbersome to support all platforms and all configurations for building Ipopt, so it should be left to the user.

The action item here is splitting the custom C API and C++ wrapper into a separate library and link it to a system built Ipopt library. We could search for the location of the ipopt binaries on the system on common desktop platforms (Linux, Mac, Windows) and/or let the user provide the location via an environment variable.

Modern C++ libraries use CMake to produce platform independent builds, which should be used for this C/C++ layer as well. As such the requirements for this package outside of the Rust ecosystem should be limited to CMake (along with the platform specific C/C++ build tools), and Ipopt.

This will greatly simplify the workflow for most users, especially scientists/engineers who may already have Ipopt set up on their system and are just looking to try Rust.

Only after this issue is resolved, can this package actually be effectively used by other libraries.

Caching in BasicProblem and ConstrainedProblem methods

One issue I'm having interfacing Descent is that I make use of caching calculations between the various ipopt callbacks. It is more efficient to calculate some of the quantities at the same time rather than separately. Basically I check new_x in each relevant function to see if it is the first time I've seen that value (for this iteration). The BasicProblem and ConstrainedProblem traits don't allow passing of new_x.
I was wondering if you have any advice on progressing with this. We could change the traits to include passing on new_x, or it is might be possible to create a new Trait that does specifically this, but then it won't be compatible with Ipopt<P: BasicProblem>.

Zero out values in ipopt callbacks

Currently, the callback interface is not 100% safe in a sense that the caller may potentially cause UB if the output slices in the objective and derivative callbacks are not initialized completely.

Since these callbacks can potentially be called often we probably would want to avoid doing additional memory writes to zero out the memory all the time, but it may be possible to expose an (additional) api that takes a slice of MaybeUninit, and outputs the same slice as initialized, letting the caller call assume_init explicitly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.