Ifopt is a unified Eigen-based interface to use Nonlinear Programming solvers, such as Ipopt and Snopt. The user defines the solver independent optimization problem by set of C++ classes resembling variables, cost and constraints. Subsequently, the problem can then be solved with either solver. This package can be dropped in your catkin workspace.
Author/Maintainer Alexander W. Winkler
... also we only need 928 lines of code to allow the generation of (1) solver indenpendent problem formulations, (2) automatic ordering of independent variable and constraint sets in the overall problem, (3) Eigen sparse-matrix exploitation for fast performance, (4) constraint-jacobian and cost-gradient ordering and (5) implementation of interfaces to Ipopt and Snopt.
-
Install Eigen
$ sudo apt-get install libeigen3-dev
-
Depending on which solver you want to use, install either Ipopt or Snopt. Follow the instructions provided here:
-
To build [ifopt_snopt] or [ifopt_ipopt] set the location of the shared libraries and header files directly in the CMakeLists.txt of the corresponding solver.
Vanilla cmake as
$ git clone https://github.com/ethz-adrl/ifopt.git
$ cd ifopt
$ mkdir build
$ cd build
$ cmake ..
$ make
or if you are using catkin, simply clone this repo into your catkin workspace
$ cd catkin_workspace/src
$ git clone https://github.com/ethz-adrl/ifopt.git
$ cd ..
$ catkin_make
Make sure everything installed correctly by running the unit tests through
$ make test
This should solve the example problem with your installed solver. Assume you have IPOPT installed, you can also run this manually by running the executable
$ ./ifopt/test/ipopt_test
of if you are using catkin or
$ cd catkin_workspace
$ catkin_make run_tests
$ (catkin build ifopt --no-deps --verbose --catkin-make-args run_tests)
See test/ex_problem.h for detailed comments and explanation of the below code line by line. The optimization problem to solve is defined as:
#include <ifopt/test/ex_problem.h>
#include <ifopt/solvers/ipopt_adapter.h>
int main()
{
Problem nlp;
nlp.AddVariableSet (std::make_shared<ExVariables>());
nlp.AddConstraintSet(std::make_shared<ExConstraint>());
nlp.AddCostSet (std::make_shared<ExCost>());
IpoptAdapter::Solve(nlp); // or SnoptAdapter::Solve(nlp);
std::cout << nlp.GetOptVariables()->GetValues();
}
Output:
1.0 0.0
The 3 classes representing variables, costs and constraints are defined as in the following. The variables x0 and x1 with their bound -1 <= x0 <= 1 is formulated as follows:
class ExVariables : public VariableSet {
public:
ExVariables() : VariableSet(2, "var_set1")
{ // initial values
x0_ = 0.5;
x1_ = 1.5;
}
virtual void SetVariables(const VectorXd& x)
{
x0_ = x(0);
x1_ = x(1);
};
virtual VectorXd GetValues() const
{
return Vector2d(x0_, x1_);
};
VecBound GetBounds() const override
{
VecBound bounds(GetRows());
bounds.at(0) = Bounds(-1.0, 1.0);
bounds.at(1) = NoBound;
return bounds;
}
private:
double x0_, x1_;
};
The example constraint 0 = x0^2 + x1 - 1 is formulated as follows:
class ExConstraint : public ConstraintSet {
public:
ExConstraint() : ConstraintSet(1, "constraint1") {}
virtual VectorXd GetValues() const override
{
VectorXd g(GetRows());
Vector2d x = GetVariables()->GetComponent("var_set1")->GetValues();
g(0) = std::pow(x(0),2) + x(1);
return g;
};
VecBound GetBounds() const override
{
VecBound b(GetRows());
b.at(0) = Bounds(1.0, 1.0);
return b;
}
void FillJacobianBlock (std::string var_set, Jacobian& jac) const override
{
if (var_set == "var_set1") {
Vector2d x = GetVariables()->GetComponent("var_set1")->GetValues();
jac.coeffRef(0, 0) = 2.0*x(0); // derivative of first constraint w.r.t x0
jac.coeffRef(0, 1) = 1.0; // derivative of first constraint w.r.t x1
}
}
};
The example cost f(x) = -(x1-2)^2 is formulated as follows:
class ExCost: public CostTerm {
public:
ExCost() : CostTerm("cost_term1") {}
virtual double GetCost() const override
{
Vector2d x = GetVariables()->GetComponent("var_set1")->GetValues();
return -std::pow(x(1)-2,2);
};
void FillJacobianBlock (std::string var_set, Jacobian& jac) const override
{
if (var_set == "var_set1") {
Vector2d x = GetVariables()->GetComponent("var_set1")->GetValues();
jac.coeffRef(0, 0) = 0.0; // derivative of cost w.r.t x0
jac.coeffRef(0, 1) = -2.0*(x(1)-2.0); // derivative of cost w.r.t x1
}
}
};
If you use this work in an academic context, please cite the currently released version as shown here.
Please report bugs and request features using the Issue Tracker.