Search code examples
c++mathematical-optimizationipopt

IpOpt refuses to solve unconstrained problem


I'm pretty new for IpOpt and i'm trying to solve simple unconstrained optimization problem by it. My problem is just quadratic function f(x) = (5x - 3)^2.

I created a simple class for this problem:

#include <cstdio>

#include "IpIpoptApplication.hpp"
#include "IpTNLP.hpp"

using namespace Ipopt;
class MyProblem : public Ipopt::TNLP
{
public:
    const int nVars = 1;
    virtual bool get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
                              Index& nnz_h_lag, IndexStyleEnum& index_style)
    {
        n = nVars;
        m = 0;
        nnz_jac_g = 0;
        nnz_h_lag = 1;
        index_style = IndexStyleEnum::C_STYLE;
        return true;
    }

    virtual bool get_bounds_info(Index n, Number* x_l, Number* x_u,
                                 Index m, Number* g_l, Number* g_u)
    {
        return true;
    }

    virtual bool get_starting_point(Index n, bool init_x, Number* x,
                                    bool init_z, Number* z_L, Number* z_U,
                                    Index m, bool init_lambda,
                                    Number* lambda)
    {
        std::cout << "get_starting_point" << std::endl;

        if(init_x){
            x[0] = 0.0;
        }
        return true;
    }

    virtual bool eval_f(Index n, const Number* x, bool new_x,
                        Number& obj_value)
    {
        const Number residual = (5 * x[0] - 3);
        obj_value = residual * residual;
        std::cout << "obj_value " << obj_value << std::endl;
        return true;
    }

    virtual bool eval_grad_f(Index n, const Number* x, bool new_x,
                             Number* grad_f)
    {
        const Number residual = (5 * x[0] - 3);
        grad_f[0] = 2 * 10 * residual;
        std::cout << "grad_f " << grad_f[0] << std::endl;
        return true;
    }

    virtual bool eval_g(Index n, const Number* x, bool new_x,
                        Index m, Number* g)
    {
        std::cout << "eval_g was called m=" << m << " *g " << g << std::endl;
        return true;
    }

    virtual bool eval_jac_g(Index n, const Number* x, bool new_x,
                            Index m, Index nele_jac, Index* iRow,
                            Index *jCol, Number* values)
    {
        std::cout << "eval_jac_g was called" << std::endl;
        return true;
    }

    virtual void finalize_solution(SolverReturn status,
                                   Index n, const Number* x, const Number* z_L, const Number* z_U,
                                   Index m, const Number* g, const Number* lambda,
                                   Number obj_value,
                                   const IpoptData* ip_data,
                                   IpoptCalculatedQuantities* ip_cq)
    {
        std::cout << "X final " << x[0] << std::endl;
    }
};

int main()
{    
    SmartPtr<TNLP> mynlp = new MyProblem();
    SmartPtr<IpoptApplication> app = new IpoptApplication();

    app->Initialize();
    ApplicationReturnStatus status = app->OptimizeTNLP(mynlp);
    if (status == Solve_Succeeded) {
      printf("\n\n*** The problem solved!\n");
    }
    else {
      printf("\n\n*** The problem FAILED!\n");
    }


    return 0;
}

I setted m = 0; and nnz_jac_g = 0; to show that i have no constraints

IpOpt gives me following output:

******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
 Ipopt is released as open source code under the Eclipse Public License (EPL).
         For more information visit http://projects.coin-or.org/Ipopt
******************************************************************************

This is Ipopt version 3.12.11, running with linear solver mumps.
NOTE: Other linear solvers might be more efficient (see Ipopt documentation).

eval_g was called m=0 *g 0x5559e0661fd0
obj_value 9
X final 0
All variables are fixed and constraint violation 0.000000e+00
   is below tolerance 1.000000e-08. Declaring success.

EXIT: Optimal Solution Found.


*** The problem solved!

But obviously problem's solution should be something like x = 3/5.

Whats wrong with my problem class?

As far as i can see IpOpt didn't called get_starting_point method which looks like pretty strange.

My IpOpt version is 3.12.11, gcc is 7.2.0-8ubuntu3.2. I can provide more information, but i have no idea what else i can show. Source code should be pretty enough

PS Sorry for my poor English


Solution

  • You should define var bounds.

    virtual bool get_bounds_info(Index n, Number* x_l, Number* x_u,
                                 Index m, Number* g_l, Number* g_u)
    {
        *x_l = -1e19; //nlp_lower_bound_inf
        *x_u = 1e19; //nlp_upper_bound_inf
        return true;
    }
    

    You vars are randomly (because other compilers probably provide different values for undefined bounds) frozen by zero bounds.

    There is another error. You should either define eval_h or specify hessian approximation scheme.