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 also be dropped in your catkin workspace.
Author/Maintainer: Alexander W. Winkler
The code is currently maintained at the Robotic Systems Lab.
... 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:
-
In order for ifopt to know for which solvers to build the code, set the environmental variable pointing to the libraries and headers of the solver. If you have IPOPT 3.12.8 installed, add
export IPOPT_DIR=/home/path/to/ipopt/Ipopt-3.12.8
to your ~/.bashrc and re-source. Alternatively you can also supply the location of the shared libraries and header files directly in the CMakeLists.txt.
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. You can also execute these manually by running e.g.
$ ./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:
0 1
The 3 classes representing variables, costs and constraints are defined as follows:
class ExVariables : public VariableSet {
public:
ExVariables() : VariableSet(2, "var_set1")
{ // initial values
x0_ = 0.0;
x1_ = 0.0;
}
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) = NoBound;
bounds.at(1) = Bounds(-1.0, 1.0);
return bounds;
}
private:
double x0_, x1_;
};
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, +inf); // between 1 and inifinity
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
}
}
};
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
}
}
};
Please report bugs and request features using the Issue Tracker.