Commit 624b6955 authored by Max Lyon's avatar Max Lyon

Merge branch 'cleanup-ipopt-solvers' into 'master'

Cleanup ipopt solvers

See merge request !48
parents c5b51cc2 2c20415f
Pipeline #12798 passed with stages
in 6 minutes and 2 seconds
......@@ -114,14 +114,13 @@ int main(void)
std::cout << "---------- 5) Solve with IPOPT solver... " << std::endl;
COMISO::IPOPTSolver ipopt;
ipopt.app().Options()->SetStringValue("derivative_test", "second-order");
ipopt.set_ipopt_option("derivative_test", "second-order");
ipopt.solve(&lsqp, constraints);
#endif
std::cout << "---------- 6) Print solution..." << std::endl;
for( int i=0; i<n; ++i)
std::cerr << "x_" << i << " = " << lsqp.x()[i] << std::endl;
return 0;
}
//=============================================================================
//
// STRUCT IPOPTCallbackParameters
//
//=============================================================================
#ifndef COMISO_IPOPTCALLBACKPARAMETERS_HH
#define COMISO_IPOPTCALLBACKPARAMETERS_HH
#include <IpTNLP.hpp>
//== TYPE DEFINITION CALLBACK PARAMETERS ======================================
namespace COMISO {
struct IPOPTCallbackParameters {
Ipopt::AlgorithmMode mode;
Ipopt::Index iter;
Ipopt::Number obj_value;
Ipopt::Number inf_pr;
Ipopt::Number inf_du;
Ipopt::Number mu;
Ipopt::Number d_norm;
Ipopt::Number regularization_size;
Ipopt::Number alpha_du;
Ipopt::Number alpha_pr;
Ipopt::Index ls_trials;
const Ipopt::IpoptData* ip_data;
Ipopt::IpoptCalculatedQuantities* ip_cq;
};
}
#endif
......@@ -11,21 +11,18 @@
#if COMISO_IPOPT_AVAILABLE
//=============================================================================
#include "CoMISo/Utils/CoMISoError.hh"
#include <CoMISo/Utils/gmm.hh>
#include <Base/Debug/DebTime.hh>
#include "NProblemIPOPT.hh"
#include "NProblemGmmInterface.hh"
#include "NProblemInterface.hh"
#include "NConstraintInterface.hh"
#include "BoundConstraint.hh"
#include "CoMISo/Utils/CoMISoError.hh"
#include <Base/Debug/DebTime.hh>
#include <CoMISo/Utils/gmm.hh>
#include "IPOPTCallbackParameters.hh"
#include <IpTNLP.hpp>
#include <IpIpoptApplication.hpp>
#include <IpSolveStatistics.hpp>
#include "IPOPTProblemInstance.hh"
//== NAMESPACES ===============================================================
......@@ -33,11 +30,10 @@ namespace COMISO {
//== IMPLEMENTATION PROBLEM INSTANCE==========================================================
//== IMPLEMENTATION PROBLEM INSTANCE===========================================
void
NProblemIPOPT::
IPOPTProblemInstance::
split_constraints(const std::vector<NConstraintInterface*>& _constraints)
{
DEB_enter_func;
......@@ -61,7 +57,7 @@ split_constraints(const std::vector<NConstraintInterface*>& _constraints)
void
NProblemIPOPT::
IPOPTProblemInstance::
analyze_special_properties(const NProblemInterface* _problem, const std::vector<NConstraintInterface*>& _constraints)
{
hessian_constant_ = true;
......@@ -98,7 +94,7 @@ analyze_special_properties(const NProblemInterface* _problem, const std::vector<
//-----------------------------------------------------------------------------
bool NProblemIPOPT::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
bool IPOPTProblemInstance::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
Index& nnz_h_lag, IndexStyleEnum& index_style)
{
DEB_enter_func;
......@@ -161,7 +157,7 @@ bool NProblemIPOPT::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
//-----------------------------------------------------------------------------
bool NProblemIPOPT::get_bounds_info(Index n, Number* x_l, Number* x_u,
bool IPOPTProblemInstance::get_bounds_info(Index n, Number* x_l, Number* x_u,
Index m, Number* g_l, Number* g_u)
{
DEB_enter_func;
......@@ -230,7 +226,7 @@ bool NProblemIPOPT::get_bounds_info(Index n, Number* x_l, Number* x_u,
//-----------------------------------------------------------------------------
bool NProblemIPOPT::get_starting_point(Index n, bool init_x, Number* x,
bool IPOPTProblemInstance::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)
......@@ -246,7 +242,7 @@ bool NProblemIPOPT::get_starting_point(Index n, bool init_x, Number* x,
//-----------------------------------------------------------------------------
bool NProblemIPOPT::eval_f(Index n, const Number* x, bool new_x, Number& obj_value)
bool IPOPTProblemInstance::eval_f(Index n, const Number* x, bool new_x, Number& obj_value)
{
DEB_enter_func;
// return the value of the objective function
......@@ -258,7 +254,7 @@ bool NProblemIPOPT::eval_f(Index n, const Number* x, bool new_x, Number& obj_val
//-----------------------------------------------------------------------------
bool NProblemIPOPT::eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f)
bool IPOPTProblemInstance::eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f)
{
DEB_enter_func;
problem_->eval_gradient(x, grad_f);
......@@ -270,7 +266,7 @@ bool NProblemIPOPT::eval_grad_f(Index n, const Number* x, bool new_x, Number* gr
//-----------------------------------------------------------------------------
bool NProblemIPOPT::eval_g(Index n, const Number* x, bool new_x, Index m, Number* g)
bool IPOPTProblemInstance::eval_g(Index n, const Number* x, bool new_x, Index m, Number* g)
{
DEB_enter_func;
// evaluate all constraint functions
......@@ -284,7 +280,7 @@ bool NProblemIPOPT::eval_g(Index n, const Number* x, bool new_x, Index m, Number
//-----------------------------------------------------------------------------
bool NProblemIPOPT::eval_jac_g(Index n, const Number* x, bool new_x,
bool IPOPTProblemInstance::eval_jac_g(Index n, const Number* x, bool new_x,
Index m, Index nele_jac, Index* iRow, Index *jCol,
Number* values)
{
......@@ -342,7 +338,7 @@ bool NProblemIPOPT::eval_jac_g(Index n, const Number* x, bool new_x,
//-----------------------------------------------------------------------------
bool NProblemIPOPT::eval_h(Index n, const Number* x, bool new_x,
bool IPOPTProblemInstance::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)
......@@ -476,7 +472,7 @@ bool NProblemIPOPT::eval_h(Index n, const Number* x, bool new_x,
double _QNT(const double x) { return x; }
void NProblemIPOPT::finalize_solution(SolverReturn status,
void IPOPTProblemInstance::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,
......@@ -516,21 +512,44 @@ void NProblemIPOPT::finalize_solution(SolverReturn status,
//-----------------------------------------------------------------------------
void
IPOPTProblemInstance::
set_callback_function
(std::function<bool(const IPOPTCallbackParameters &)> func)
{
intermediate_callback_ = func;
}
bool NProblemIPOPT::intermediate_callback(
Ipopt::AlgorithmMode /*mode*/,
Index /*iter*/, Number /*obj_value*/,
Number /*inf_pr*/, Number /*inf_du*/,
Number /*mu*/, Number /*d_norm*/,
Number /*regularization_size*/,
Number /*alpha_du*/, Number /*alpha_pr*/,
Index /*ls_trials*/,
const IpoptData* /*ip_data*/,
IpoptCalculatedQuantities* /*ip_cq*/
)
bool IPOPTProblemInstance::intermediate_callback(
Ipopt::AlgorithmMode mode,
Index iter, Number obj_value,
Number inf_pr, Number inf_du,
Number mu, Number d_norm,
Number regularization_size,
Number alpha_du, Number alpha_pr,
Index ls_trials,
const IpoptData* ip_data,
IpoptCalculatedQuantities* ip_cq
)
{
PROGRESS_TICK;
if(intermediate_callback_) {
IPOPTCallbackParameters callbackParameters {
mode,
iter, obj_value,
inf_pr, inf_du,
mu, d_norm,
regularization_size,
alpha_du, alpha_pr,
ls_trials,
ip_data,
ip_cq
};
return intermediate_callback_(callbackParameters);
}
return true;
}
......@@ -538,7 +557,7 @@ bool NProblemIPOPT::intermediate_callback(
//-----------------------------------------------------------------------------
bool NProblemIPOPT::hessian_constant() const
bool IPOPTProblemInstance::hessian_constant() const
{
return hessian_constant_;
}
......@@ -547,7 +566,7 @@ bool NProblemIPOPT::hessian_constant() const
//-----------------------------------------------------------------------------
bool NProblemIPOPT::jac_c_constant() const
bool IPOPTProblemInstance::jac_c_constant() const
{
return jac_c_constant_;
}
......@@ -556,7 +575,7 @@ bool NProblemIPOPT::jac_c_constant() const
//-----------------------------------------------------------------------------
bool NProblemIPOPT::jac_d_constant() const
bool IPOPTProblemInstance::jac_d_constant() const
{
return jac_d_constant_;
}
......@@ -565,7 +584,7 @@ bool NProblemIPOPT::jac_d_constant() const
//== IMPLEMENTATION PROBLEM INSTANCE==========================================================
bool NProblemGmmIPOPT::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
bool IPOPTProblemInstanceGmm::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
Index& nnz_h_lag, IndexStyleEnum& index_style)
{
DEB_enter_func;
......@@ -657,7 +676,7 @@ bool NProblemGmmIPOPT::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
//-----------------------------------------------------------------------------
bool NProblemGmmIPOPT::get_bounds_info(Index n, Number* x_l, Number* x_u,
bool IPOPTProblemInstanceGmm::get_bounds_info(Index n, Number* x_l, Number* x_u,
Index m, Number* g_l, Number* g_u)
{
DEB_enter_func;
......@@ -691,7 +710,7 @@ bool NProblemGmmIPOPT::get_bounds_info(Index n, Number* x_l, Number* x_u,
//-----------------------------------------------------------------------------
bool NProblemGmmIPOPT::get_starting_point(Index n, bool init_x, Number* x,
bool IPOPTProblemInstanceGmm::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)
......@@ -707,7 +726,7 @@ bool NProblemGmmIPOPT::get_starting_point(Index n, bool init_x, Number* x,
//-----------------------------------------------------------------------------
bool NProblemGmmIPOPT::eval_f(Index n, const Number* x, bool new_x, Number& obj_value)
bool IPOPTProblemInstanceGmm::eval_f(Index n, const Number* x, bool new_x, Number& obj_value)
{
DEB_enter_func;
// return the value of the objective function
......@@ -719,7 +738,7 @@ bool NProblemGmmIPOPT::eval_f(Index n, const Number* x, bool new_x, Number& obj_
//-----------------------------------------------------------------------------
bool NProblemGmmIPOPT::eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f)
bool IPOPTProblemInstanceGmm::eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f)
{
DEB_enter_func;
problem_->eval_gradient(x, grad_f);
......@@ -731,7 +750,7 @@ bool NProblemGmmIPOPT::eval_grad_f(Index n, const Number* x, bool new_x, Number*
//-----------------------------------------------------------------------------
bool NProblemGmmIPOPT::eval_g(Index n, const Number* x, bool new_x, Index m, Number* g)
bool IPOPTProblemInstanceGmm::eval_g(Index n, const Number* x, bool new_x, Index m, Number* g)
{
DEB_enter_func;
// evaluate all constraint functions
......@@ -745,7 +764,7 @@ bool NProblemGmmIPOPT::eval_g(Index n, const Number* x, bool new_x, Index m, Num
//-----------------------------------------------------------------------------
bool NProblemGmmIPOPT::eval_jac_g(Index n, const Number* x, bool new_x,
bool IPOPTProblemInstanceGmm::eval_jac_g(Index n, const Number* x, bool new_x,
Index m, Index nele_jac, Index* iRow, Index *jCol,
Number* values)
{
......@@ -791,7 +810,7 @@ bool NProblemGmmIPOPT::eval_jac_g(Index n, const Number* x, bool new_x,
//-----------------------------------------------------------------------------
bool NProblemGmmIPOPT::eval_h(Index n, const Number* x, bool new_x,
bool IPOPTProblemInstanceGmm::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)
......@@ -865,7 +884,7 @@ bool NProblemGmmIPOPT::eval_h(Index n, const Number* x, bool new_x,
//-----------------------------------------------------------------------------
void NProblemGmmIPOPT::finalize_solution(SolverReturn status,
void IPOPTProblemInstanceGmm::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,
......@@ -877,19 +896,43 @@ void NProblemGmmIPOPT::finalize_solution(SolverReturn status,
problem_->store_result(x);
}
bool NProblemGmmIPOPT::intermediate_callback(
Ipopt::AlgorithmMode /*mode*/,
Index /*iter*/, Number /*obj_value*/,
Number /*inf_pr*/, Number /*inf_du*/,
Number /*mu*/, Number /*d_norm*/,
Number /*regularization_size*/,
Number /*alpha_du*/, Number /*alpha_pr*/,
Index /*ls_trials*/,
const IpoptData* /*ip_data*/,
IpoptCalculatedQuantities* /*ip_cq*/
)
void
IPOPTProblemInstanceGmm::
set_callback_function
(std::function<bool(const IPOPTCallbackParameters &)> func)
{
intermediate_callback_ = func;
}
bool IPOPTProblemInstanceGmm::intermediate_callback(
Ipopt::AlgorithmMode mode,
Index iter, Number obj_value,
Number inf_pr, Number inf_du,
Number mu, Number d_norm,
Number regularization_size,
Number alpha_du, Number alpha_pr,
Index ls_trials,
const IpoptData* ip_data,
IpoptCalculatedQuantities* ip_cq
)
{
PROGRESS_TICK;
if(intermediate_callback_) {
IPOPTCallbackParameters callbackParameters {
mode,
iter, obj_value,
inf_pr, inf_du,
mu, d_norm,
regularization_size,
alpha_du, alpha_pr,
ls_trials,
ip_data,
ip_cq
};
return intermediate_callback_(callbackParameters);
}
return true;
}
......
......@@ -15,10 +15,13 @@
//== INCLUDES =================================================================
#include <vector>
#include <cstddef>
#include <functional>
#include <CoMISo/Config/CoMISoDefines.hh>
#include "NProblemGmmInterface.hh"
#include "NProblemInterface.hh"
#include "IPOPTSolverLean.hh"
#include "NProblemGmmInterface.hh"
#include "NProblemInterface.hh"
#include "NConstraintInterface.hh"
......@@ -32,23 +35,19 @@
#include <IpTNLP.hpp>
#include <IpIpoptApplication.hpp>
#include <IpSolveStatistics.hpp>
#include <vector>
#include <cstddef>
//== NAMESPACES ===============================================================
namespace COMISO {
//== FORWARDDECLARATIONS ======================================================
class NProblemGmmInterface; // deprecated
class NProblemInterface;
class NConstraintInterface;
struct IPOPTCallbackParameters;
//== CLASS DEFINITION PROBLEM INSTANCE=========================================================
class NProblemIPOPT : public Ipopt::TNLP
//== CLASS DEFINITION PROBLEM INSTANCE ========================================
class IPOPTProblemInstance : public Ipopt::TNLP
{
public:
......@@ -65,8 +64,11 @@ public:
typedef NProblemInterface::SMatrixNP SMatrixNP;
/** default constructor */
NProblemIPOPT(NProblemInterface* _problem, const std::vector<NConstraintInterface*>& _constraints, const bool _hessian_approximation = false)
: problem_(_problem), store_solution_(false), hessian_approximation_(_hessian_approximation)
IPOPTProblemInstance(NProblemInterface* _problem,
const std::vector<NConstraintInterface*>& _constraints,
const bool _hessian_approximation = false)
: problem_(_problem), store_solution_(false),
hessian_approximation_(_hessian_approximation)
{
split_constraints(_constraints);
analyze_special_properties(_problem, _constraints);
......@@ -127,6 +129,9 @@ public:
IpoptCalculatedQuantities* ip_cq) override;
//@}
/** Set intermediate callback function object **/
void set_callback_function(std::function<bool(const IPOPTCallbackParameters &)>);
/** Intermediate Callback method for the user. Providing dummy
* default implementation. For details see IntermediateCallBack
* in IpNLP.hpp. */
......@@ -163,8 +168,8 @@ private:
*/
//@{
// MyNLP();
NProblemIPOPT(const NProblemIPOPT&);
NProblemIPOPT& operator=(const NProblemIPOPT&);
IPOPTProblemInstance(const IPOPTProblemInstance&);
IPOPTProblemInstance& operator=(const IPOPTProblemInstance&);
//@}
// split user-provided constraints into general-constraints and bound-constraints
......@@ -193,13 +198,15 @@ private:
std::vector<double> x_;
bool hessian_approximation_;
std::function<bool(const IPOPTCallbackParameters &)> intermediate_callback_;
};
//== CLASS DEFINITION PROBLEM INSTANCE=========================================================
class NProblemGmmIPOPT : public Ipopt::TNLP
class IPOPTProblemInstanceGmm : public Ipopt::TNLP
{
public:
......@@ -226,7 +233,7 @@ public:
typedef gmm::linalg_traits<SVectorNP>::iterator SVectorNP_iter;
/** default constructor */
NProblemGmmIPOPT(NProblemGmmInterface* _problem, std::vector<NConstraintInterface*>& _constraints)
IPOPTProblemInstanceGmm(NProblemGmmInterface* _problem, std::vector<NConstraintInterface*>& _constraints)
: problem_(_problem), constraints_(_constraints), nnz_jac_g_(0), nnz_h_lag_(0)
{}
......@@ -285,6 +292,9 @@ public:
IpoptCalculatedQuantities* ip_cq) override;
//@}
/** Set intermediate callback function object **/
void set_callback_function(std::function<bool(const IPOPTCallbackParameters &)>);
/** Intermediate Callback method for the user. Providing dummy
* default implementation. For details see IntermediateCallBack
* in IpNLP.hpp. */
......@@ -314,8 +324,8 @@ private:
*/
//@{
// MyNLP();
NProblemGmmIPOPT(const NProblemGmmIPOPT&);
NProblemGmmIPOPT& operator=(const NProblemGmmIPOPT&);
IPOPTProblemInstanceGmm(const IPOPTProblemInstanceGmm&);
IPOPTProblemInstanceGmm& operator=(const IPOPTProblemInstanceGmm&);
//@}
......@@ -337,6 +347,8 @@ private:
// Sparse Matrix of problem (don't initialize every time!!!)
SMatrixNP HP_;
std::function<bool(const IPOPTCallbackParameters &)> intermediate_callback_;
};
//=============================================================================
......@@ -347,4 +359,3 @@ private:
//=============================================================================
#endif // COMISO_NPROBLEMIPOPT_HH
//=============================================================================
This diff is collapsed.
......@@ -8,134 +8,144 @@
#ifndef COMISO_IPOPTSOLVER_HH
#define COMISO_IPOPTSOLVER_HH
//== COMPILE-TIME PACKAGE REQUIREMENTS ========================================
#include <CoMISo/Config/config.hh>
#if COMISO_IPOPT_AVAILABLE
//== INCLUDES =================================================================
#include <CoMISo/Config/CoMISoDefines.hh>
#include <CoMISo/Utils/StopWatch.hh>
#include <CoMISo/Utils/gmm.hh>
#include <vector>
#include <cstddef>
#include "NProblemGmmInterface.hh"
#include "NProblemInterface.hh"
#include "NProblemIPOPT.hh"
#include "NConstraintInterface.hh"
#include "BoundConstraint.hh"
#include <IpTNLP.hpp>
#include <IpIpoptApplication.hpp>
#include <IpSolveStatistics.hpp>
#include <functional>
#include <vector>
#include <string>
//== FORWARDDECLARATIONS ======================================================
#include <CoMISo/Config/CoMISoDefines.hh>
//== NAMESPACES ===============================================================
namespace COMISO {
//== FORWARDDECLARATIONS ======================================================
class NProblemInterface;
class NConstraintInterface;
struct IPOPTCallbackParameters;
//== CLASS DEFINITION =========================================================
/** \class IPOPTSolver
Solver for Interior Point optimization problems.
/** \class NewtonSolver NewtonSolver.hh <ACG/.../NewtonSolver.hh>
Solves an interior point problem, given an NProblemInterface
instance and optionally a set of constraints as well as "lazy
constraints" via NConstraintInterface.
Brief Description.
A more elaborate description follows.
Lazy constraints are not active while the initial solution to the
problem is computed. After the first solution is found, the lazy
constraints are checked and added to the set of active constraints
if they are violated. This process is then repeated until all
constraints are satisfied OR a maximum number of solution attempts
has been reached. In that case the optimization is started once
more, with all lazy constraints active.
*/
class COMISODLLEXPORT IPOPTSolver
{
public:
/// Default constructor -> set up IpOptApplication
IPOPTSolver();
// ********** SOLVE **************** //
// solve -> returns ipopt status code
//------------------------------------------------------
// enum ApplicationReturnStatus
// {
// Solve_Succeeded=0,
// Solved_To_Acceptable_Level=1,
// Infeasible_Problem_Detected=2,
// Search_Direction_Becomes_Too_Small=3,
// Diverging_Iterates=4,
// User_Requested_Stop=5,
// Feasible_Point_Found=6,
//
// Maximum_Iterations_Exceeded=-1,
// Restoration_Failed=-2,
// Error_In_Step_Computation=-3,
// Maximum_CpuTime_Exceeded=-4,
// Not_Enough_Degrees_Of_Freedom=-10,
// Invalid_Problem_Definition=-11,
// Invalid_Option=-12,
// Invalid_Number_Detected=-13,
//
// Unrecoverable_Exception=-100,
// NonIpopt_Exception_Thrown=-101,
// Insufficient_Memory=-102,
// Internal_Error=-199
// };
//------------------------------------------------------
int solve(NProblemInterface* _problem, const std::vector<NConstraintInterface*>& _constraints);
// same as above with additional lazy constraints that are only added iteratively to the problem if not satisfied
int solve(NProblemInterface* _problem,
const std::vector<NConstraintInterface*>& _constraints,
const std::vector<NConstraintInterface*>& _lazy_constraints,
const double _almost_infeasible = 0.5,
const int _max_passes = 5 );
// for convenience, if no constraints are given
int solve(NProblemInterface* _problem);
// deprecated interface for backwards compatibility
int solve(NProblemGmmInterface* _problem, std::vector<NConstraintInterface*>& _constraints);
// ********* CONFIGURATION ********************* //
// access the ipopt-application (for setting parameters etc.)
// examples: app().Options()->SetIntegerValue("max_iter", 100);
// app().Options()->SetStringValue("derivative_test", "second-order");
// app().Options()->SetStringValue("hessian_approximation", "limited-memory");
IPOPTSolver();
~IPOPTSolver();
// *********** OPTIONS **************//
/*!
Set options of the underlying ipopt solver.
For a thorough list and documentation of available options, refer
to: https://www.coin-or.org/Ipopt/documentation/node40.html
*/
void set_ipopt_option(std::string, const int&);