Raw File
test_ipopt.cpp
/* -*- mode: c++; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; show-trailing-whitespace: t  -*-

  This file is part of the Feel library

  Author(s): Christophe Prud'homme <christophe.prudhomme@feelpp.org>
       Date: 2014-07-15

  Copyright (C) 2014-2016 Feel++ Consortium

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
/**
   \file test_nlopt.cpp
   \author Guillaume Dolle <gdolle@unistra.fr>
   \date 2014-07-15
   Test based on Ipopt tutorial (authors: Carl Laird, Andreas Waechter IBM 2004-11-05)
 */
#include <iostream>
#include <cassert>
#include <feel/feelconfig.h>
#include <feel/feelcore/environment.hpp>

#if defined( FEELPP_HAS_IPOPT )

#include <coin/IpTNLP.hpp>
#include <coin/IpIpoptApplication.hpp>
#include <coin/IpSolveStatistics.hpp>

using namespace Ipopt;

/** C++ Example NLP for interfacing a problem with IPOPT.
 *
 * min_x f(x) = -(x2-2)^2
 *  s.t.
 *       0 = x1^2 + x2 - 1
 *       -1 <= x1 <= 1
 *
 */
class MyNLP : public TNLP
{
    public:
        /** default constructor */
        MyNLP(){};

        /** default destructor */
        virtual ~MyNLP(){};

        /**@name Overloaded from TNLP */
        //@{
        /** Method to return some info about the nlp */
        virtual bool get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
                Index& nnz_h_lag, IndexStyleEnum& index_style)
        {
            n = 2;
            m = 1;
            nnz_jac_g = 2;
            nnz_h_lag = 2;
            index_style = FORTRAN_STYLE;
            return true;
        }

        /** Method to return the bounds for my problem */
        virtual bool get_bounds_info(Index n, Number* x_l, Number* x_u,
                Index m, Number* g_l, Number* g_u)
        {
            assert(n == 2);
            assert(m == 1);
            // upper and lower bounds
            x_l[0] = -1.0;
            x_u[0] = 1.0;
            x_l[1] = -1.0e19;
            x_u[1] = +1.0e19;
            g_l[0] = g_u[0] = 0.0;

            return true;
        }

        /** Method to return the starting point for the algorithm */
        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)
        {
            assert(init_x == true);
            assert(init_z == false);
            assert(init_lambda == false);

            // we initialize x in bounds, in the upper right quadrant
            x[0] = 0.5;
            x[1] = 1.5;

            return true;
        }

        /** Method to return the objective value */
        virtual bool eval_f(Index n, const Number* x, bool new_x, Number& obj_value)
        {
            Number x2 = x[1];
            obj_value = -(x2 - 2.0) * (x2 - 2.0);
            return true;
        }

        /** Method to return the gradient of the objective */
        virtual bool eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f)
        {
            grad_f[0] = 0.0;
            Number x2 = x[1];
            grad_f[1] = -2.0*(x2 - 2.0);
            return true;
        }

        /** Method to return the constraint residuals */
        virtual bool eval_g(Index n, const Number* x, bool new_x, Index m, Number* g)
        {
            Number x1 = x[0];
            Number x2 = x[1];
            g[0] = -(x1*x1 + x2 - 1.0);
            return true;
        }

        /** Method to return:
         *   1) The structure of the jacobian (if "values" is NULL)
         *   2) The values of the jacobian (if "values" is not NULL)
         */
        virtual bool eval_jac_g(Index n, const Number* x, bool new_x,
                Index m, Index nele_jac, Index* iRow, Index *jCol,
                Number* values)
        {
            if (values == NULL) {
                iRow[0] = 1;
                jCol[0] = 1;
                iRow[1] = 1;
                jCol[1] = 2;
            }
            else {
                Number x1 = x[0];
                values[0] = -2.0 * x1;
                values[1] = -1.0;
            }

            return true;
        }

        /** Method to return:
         *   1) The structure of the hessian of the lagrangian (if "values" is NULL)
         *   2) The values of the hessian of the lagrangian (if "values" is not NULL)
         */
        virtual bool eval_h(Index n, const Number* x, bool new_x,
                Number obj_factor, Index m, const Number* lambda,
                bool new_lambda, Index nele_hess, Index* iRow,
                Index* jCol, Number* values)
        {
            if (values == NULL)
            {
                iRow[0] = 1;
                jCol[0] = 1;
                iRow[1] = 2;
                jCol[1] = 2;
            }
            else
            {
                values[0] = -2.0 * lambda[0];
                values[1] = -2.0 * obj_factor;
            }
            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)
        {
        }

    private:
        MyNLP(const MyNLP&);
        MyNLP& operator=(const MyNLP&);
};


int main(int argc, char* argv[])
{
    using namespace Feel;
	Environment env( _argc=argc, _argv=argv,
                     _about=about(_name="test_ipopt",
                                  _author="Feel++ Consortium",
                                  _email="feelpp-devel@feelpp.org"));

    SmartPtr<TNLP> mynlp = new MyNLP();
    SmartPtr<IpoptApplication> app = IpoptApplicationFactory();

    auto status = app->Initialize();
    if (status != Solve_Succeeded)
    {
        std::cout << std::endl << std::endl << "*** Error during initialization!" << std::endl;
        return (int) status;
    }

    status = app->OptimizeTNLP(mynlp);

    if (status == Solve_Succeeded)
    {
        // Retrieve some statistics about the solve
        Index iter_count = app->Statistics()->IterationCount();
        std::cout << std::endl << std::endl << "*** The problem solved in " << iter_count << " iterations!" << std::endl;

        Number final_obj = app->Statistics()->FinalObjective();
        std::cout << std::endl << std::endl << "*** The final value of the objective function is " << final_obj << '.' << std::endl;
    }
    return 0;
}

#endif
back to top