robotology / osqp-eigen

Simple Eigen-C++ wrapper for OSQP library
https://robotology.github.io/osqp-eigen/
BSD 3-Clause "New" or "Revised" License
385 stars 114 forks source link

Solve unconstrained optimization problems #84

Closed GiulioRomualdi closed 3 years ago

GiulioRomualdi commented 3 years ago

This issue shows how to set osqp-eigen to solve an unconstrained optimization problem

We now want to solve the following optimization problem

qp

The solution of the problem is x = [0 0]

osqp-eigen can be used to solve the problem as follows

Initialize the variables. Please notice that the constraintMatrix size is 0 x 2 (i.e. number of constraints x number of unknowns)

Eigen::SparseMatrix<double> hessian(2,2);
Eigen::SparseMatrix<double> constraintMatrix(0,2);
Eigen::Vector2d gradient;
Eigen::VectorXd bound(0);

gradient.setZero();
hessian.insert(0,0) = 1;
hessian.insert(1,1) = 1;

Now you can initialize the problem as usual

OsqpEigen::Solver solver;
solver.data()->setNumberOfVariables(2);
solver.data()->setNumberOfConstraints(0);
if(!solver.data()->setHessianMatrix(hessian)) return 1;
if(!solver.data()->setGradient(gradient)) return 1;
if(!solver.data()->setLinearConstraintsMatrix(constraintMatrix)) return 1;
if(!solver.data()->setLowerBound(bound)) return 1;
if(!solver.data()->setUpperBound(bound)) return 1;

You can finally solve the problem

if(!solver.initSolver()) return 1;
if(!solver.solve()) return 1;

Here the entire example

#include <iostream>

#include <Eigen/Sparse>
#include <Eigen/Dense>

#include <OsqpEigen/OsqpEigen.h>

int main()
{
    Eigen::SparseMatrix<double> hessian(2,2);
    Eigen::SparseMatrix<double> constraintMatrix(0,2);
    Eigen::Vector2d gradient;
    Eigen::VectorXd bound(0);

    gradient.setZero();
    hessian.insert(0,0) = 1;
    hessian.insert(1,1) = 1;

    OsqpEigen::Solver solver;
    solver.data()->setNumberOfVariables(2);
    solver.data()->setNumberOfConstraints(0);
    if(!solver.data()->setHessianMatrix(hessian)) return 1;
    if(!solver.data()->setGradient(gradient)) return 1;
    if(!solver.data()->setLinearConstraintsMatrix(constraintMatrix)) return 1;
    if(!solver.data()->setLowerBound(bound)) return 1;
    if(!solver.data()->setUpperBound(bound)) return 1;

    if(!solver.initSolver()) return 1;
    if(!solver.solve()) return 1;

    std::cout << "Solution = " << solver.getSolution().transpose() << std::endl;

    return 0;
}

This is the CMakeLists.txt that you can use to run the example

project(osqp-eigen-test)

cmake_minimum_required(VERSION 3.0)

find_package(OsqpEigen REQUIRED)
find_package(osqp REQUIRED)
find_package(Eigen3 REQUIRED)

add_executable(osqp-eigen-test main.cpp)
target_link_libraries(osqp-eigen-test OsqpEigen::OsqpEigen osqp::osqp Eigen3::Eigen)

The fact that the user should set the constraint matrix and the bounds even if the problem is unconstrained is counterintuitive.

cc @S-Dafarra @traversaro @lrapetti

S-Dafarra commented 3 years ago

Just to understand, what is the output if you add no constraints at all?

GiulioRomualdi commented 3 years ago

Just to understand, what is the output if you add no constraints at all?

[OsqpEigen::Solver::initSolver] Some data are not set.
S-Dafarra commented 3 years ago

Ok this sounds like a logical problem then. That should be easy to solve then. https://github.com/robotology/osqp-eigen/blob/9b0091038cf0fb9099a5d6c55820d6e5846034a7/src/Data.cpp#L88-L97

should become

    return m_isNumberOfVariablesSet &&
        m_isNumberOfConstraintsSet &&
        m_isHessianMatrixSet &&
        m_isGradientSet &&
        (m_data->m ==0 || m_isLinearConstraintsMatrixSet ) &&
        m_isLowerBoundSet &&
        m_isUpperBoundSet;

right?

GiulioRomualdi commented 3 years ago

I don't know if it's so simple (We should investigate the side effects)

S-Dafarra commented 3 years ago

In any case, I think that it does not make sense to require the constraint matrix to be set if there are no constraints. If something else breaks, we shall fix it as well :grin:

Could you add the unconstrained problem as a test case?

GiulioRomualdi commented 3 years ago

I think that it does not make sense to require the constraint matrix to be set if there are no constraints

I agree

GiulioRomualdi commented 3 years ago

Related issue https://github.com/oxfordcontrol/osqp/issues/295

S-Dafarra commented 3 years ago

Related issue oxfordcontrol/osqp#295

Ah, nice! So if it is also a limitation of osqp, the solution you proposed in the OP seems the way to go then.