#include "IpStdInterfaceTNLP.hpp"
#include "IpBlas.hpp"
namespace Ipopt
{
StdInterfaceTNLP::StdInterfaceTNLP(
Index n_var,
const Number* x_L,
const Number* x_U,
Index n_con,
const Number* g_L,
const Number* g_U,
Index nele_jac,
Index nele_hess,
Index index_style,
const Number* start_x,
const Number* start_lam,
const Number* start_z_L,
const Number* start_z_U,
Eval_F_CB eval_f,
Eval_G_CB eval_g,
Eval_Grad_F_CB eval_grad_f,
Eval_Jac_G_CB eval_jac_g,
Eval_H_CB eval_h,
Intermediate_CB intermediate_cb,
Number* x_sol,
Number* z_L_sol,
Number* z_U_sol,
Number* g_sol,
Number* lam_sol,
Number* obj_sol,
UserDataPtr user_data,
Number obj_scaling ,
const Number* x_scaling ,
const Number* g_scaling
)
: TNLP(),
n_var_(n_var),
n_con_(n_con),
x_L_(x_L),
x_U_(x_U),
g_L_(g_L),
g_U_(g_U),
nele_jac_(nele_jac),
nele_hess_(nele_hess),
index_style_(index_style),
start_x_(start_x),
start_lam_(start_lam),
start_z_L_(start_z_L),
start_z_U_(start_z_U),
eval_f_(eval_f),
eval_g_(eval_g),
eval_grad_f_(eval_grad_f),
eval_jac_g_(eval_jac_g),
eval_h_(eval_h),
intermediate_cb_(intermediate_cb),
user_data_(user_data),
obj_scaling_(obj_scaling),
x_scaling_(NULL),
g_scaling_(NULL),
non_const_x_(NULL),
x_sol_(x_sol),
z_L_sol_(z_L_sol),
z_U_sol_(z_U_sol),
g_sol_(g_sol),
lambda_sol_(lam_sol),
obj_sol_(obj_sol),
ip_data_(NULL),
ip_cq_(NULL)
{
ASSERT_EXCEPTION(n_var_ > 0, INVALID_STDINTERFACE_NLP, "The number of variables must be at least 1.");
ASSERT_EXCEPTION(n_con_ >= 0, INVALID_STDINTERFACE_NLP, "The number of constrains must be non-negative.");
ASSERT_EXCEPTION(x_L_, INVALID_STDINTERFACE_NLP, "No lower bounds for variables provided.");
ASSERT_EXCEPTION(x_U_, INVALID_STDINTERFACE_NLP, "No upper bounds for variables provided.");
ASSERT_EXCEPTION(g_L_ || n_con_ == 0, INVALID_STDINTERFACE_NLP, "No lower bounds for constraints provided.");
ASSERT_EXCEPTION(g_U_ || n_con_ == 0, INVALID_STDINTERFACE_NLP, "No upper bounds for constraints provided.");
ASSERT_EXCEPTION(nele_jac_ >= 0, INVALID_STDINTERFACE_NLP, "Number of non-zero elements in constraint Jacobian must be non-negative.");
ASSERT_EXCEPTION(nele_hess_ >= 0, INVALID_STDINTERFACE_NLP, "Number of non-zero elements in Hessian of Lagrangian must be non-negative.");
ASSERT_EXCEPTION(index_style_ == 0 || index_style_ == 1, INVALID_STDINTERFACE_NLP, "Valid index styles are 0 (C style) or 1 (Fortran style)");
ASSERT_EXCEPTION(start_x_, INVALID_STDINTERFACE_NLP, "No initial point for the variables provided.");
ASSERT_EXCEPTION(eval_f_, INVALID_STDINTERFACE_NLP, "No callback function for evaluating the value of objective function provided.");
ASSERT_EXCEPTION(eval_g_, INVALID_STDINTERFACE_NLP, "No callback function for evaluating the values of constraints provided.");
ASSERT_EXCEPTION(eval_grad_f_, INVALID_STDINTERFACE_NLP, "No callback function for evaluating the gradient of objective function provided.");
ASSERT_EXCEPTION(eval_jac_g_, INVALID_STDINTERFACE_NLP, "No callback function for evaluating the Jacobian of the constraints provided.");
ASSERT_EXCEPTION(eval_h_, INVALID_STDINTERFACE_NLP, "No callback function for evaluating the Hessian of the constraints provided.");
if( x_scaling != NULL )
{
Number* tmp = new Number[n_var_];
Ipopt::IpBlasCopy(n_var_, x_scaling, 1, tmp, 1);
x_scaling_ = tmp;
}
if( g_scaling )
{
Number* tmp = new Number[n_con_];
Ipopt::IpBlasCopy(n_con_, g_scaling, 1, tmp, 1);
g_scaling_ = tmp;
}
}
StdInterfaceTNLP::~StdInterfaceTNLP()
{
delete[] non_const_x_;
delete[] x_scaling_;
delete[] g_scaling_;
}
bool StdInterfaceTNLP::get_nlp_info(
Index& n,
Index& m,
Index& nnz_jac_g,
Index& nnz_h_lag,
IndexStyleEnum& index_style
)
{
n = n_var_; m = n_con_; nnz_jac_g = nele_jac_; nnz_h_lag = nele_hess_;
index_style = (index_style_ == 0) ? C_STYLE : FORTRAN_STYLE;
return true;
}
bool StdInterfaceTNLP::get_bounds_info(
Index n,
Number* x_l,
Number* x_u,
Index m,
Number* g_l,
Number* g_u
)
{
DBG_ASSERT(n == n_var_);
DBG_ASSERT(m == n_con_);
Ipopt::IpBlasCopy(n, x_L_, 1, x_l, 1);
Ipopt::IpBlasCopy(n, x_U_, 1, x_u, 1);
Ipopt::IpBlasCopy(m, g_L_, 1, g_l, 1);
Ipopt::IpBlasCopy(m, g_U_, 1, g_u, 1);
return true;
}
bool StdInterfaceTNLP::get_scaling_parameters(
Number& obj_scaling,
bool& use_x_scaling,
Index n,
Number* x_scaling,
bool& use_g_scaling,
Index m,
Number* g_scaling
)
{
DBG_ASSERT(n == n_var_);
(void) n;
DBG_ASSERT(m == n_con_);
(void) m;
obj_scaling = obj_scaling_;
if( x_scaling_ != NULL )
{
use_x_scaling = true;
Ipopt::IpBlasCopy(n_var_, x_scaling_, 1, x_scaling, 1);
}
else
{
use_x_scaling = false;
}
if( g_scaling_ != NULL )
{
use_g_scaling = true;
Ipopt::IpBlasCopy(n_con_, g_scaling_, 1, g_scaling, 1);
}
else
{
use_g_scaling = false;
}
return true;
}
bool StdInterfaceTNLP::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
)
{
bool retval = true;
DBG_ASSERT(n == n_var_);
DBG_ASSERT(m == n_con_);
if( init_x )
{
Ipopt::IpBlasCopy(n, start_x_, 1, x, 1);
}
if( init_z )
{
if( start_z_L_ == NULL )
{
retval = false;
}
else
{
Ipopt::IpBlasCopy(n, start_z_L_, 1, z_L, 1);
}
if( start_z_U_ == NULL )
{
retval = false;
}
else
{
Ipopt::IpBlasCopy(n, start_z_U_, 1, z_U, 1);
}
}
if( init_lambda )
{
if( start_lam_ == NULL )
{
retval = false;
}
else
{
Ipopt::IpBlasCopy(m, start_lam_, 1, lambda, 1);
}
}
return retval;
}
bool StdInterfaceTNLP::eval_f(
Index n,
const Number* x,
bool new_x,
Number& obj_value
)
{
DBG_ASSERT(n == n_var_);
apply_new_x(new_x, n, x);
Bool retval = (*eval_f_)(n, non_const_x_, (Bool) new_x, &obj_value, user_data_);
return (retval != 0);
}
bool StdInterfaceTNLP::eval_grad_f(
Index n,
const Number* x,
bool new_x,
Number* grad_f
)
{
DBG_ASSERT(n == n_var_);
apply_new_x(new_x, n, x);
Bool retval = (*eval_grad_f_)(n, non_const_x_, (Bool) new_x, grad_f, user_data_);
return (retval != 0);
}
bool StdInterfaceTNLP::eval_g(
Index n,
const Number* x,
bool new_x,
Index m,
Number* g
)
{
DBG_ASSERT(n == n_var_);
DBG_ASSERT(m == n_con_);
apply_new_x(new_x, n, x);
Bool retval = (*eval_g_)(n, non_const_x_, (Bool) new_x, m, g, user_data_);
return (retval != 0);
}
bool StdInterfaceTNLP::eval_jac_g(
Index n,
const Number* x,
bool new_x,
Index m,
Index nele_jac,
Index* iRow,
Index* jCol,
Number* values
)
{
DBG_ASSERT(n == n_var_);
DBG_ASSERT(nele_jac == nele_jac_);
DBG_ASSERT((iRow != NULL && jCol != NULL && values == NULL) || (iRow == NULL && jCol == NULL && values != NULL));
apply_new_x(new_x, n, x);
Bool retval = (*eval_jac_g_)(n, non_const_x_, (Bool) new_x, m, nele_jac, iRow, jCol, values, user_data_);
return (retval != 0);
}
bool StdInterfaceTNLP::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
)
{
DBG_ASSERT(n == n_var_);
DBG_ASSERT(m == n_con_);
DBG_ASSERT(nele_hess == nele_hess_);
DBG_ASSERT((iRow != NULL && jCol != NULL && values == NULL) || (iRow == NULL && jCol == NULL && values != NULL));
apply_new_x(new_x, n, x);
Number* non_const_lambda = new Number[m];
if( lambda )
{
Ipopt::IpBlasCopy(m, lambda, 1, non_const_lambda, 1);
}
Bool retval = (*eval_h_)(n, non_const_x_, (Bool) new_x, obj_factor, m, non_const_lambda, (Bool) new_lambda, nele_hess, iRow, jCol, values, user_data_);
delete[] non_const_lambda;
return (retval != 0);
}
bool StdInterfaceTNLP::intermediate_callback(
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
)
{
if( !intermediate_cb_ )
{
return true;
}
ip_data_ = ip_data;
ip_cq_ = ip_cq;
Bool retval = (*intermediate_cb_)((Index) mode, iter, obj_value, inf_pr, inf_du, mu, d_norm, regularization_size,
alpha_du, alpha_pr, ls_trials, user_data_);
ip_data_ = NULL;
ip_cq_ = NULL;
return (retval != 0);
}
void StdInterfaceTNLP::finalize_solution(
SolverReturn ,
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* ,
IpoptCalculatedQuantities*
)
{
if( x_sol_ != NULL )
{
IpBlasCopy(n, x, 1, x_sol_, 1);
}
if( z_L_sol_ != NULL )
{
IpBlasCopy(n, z_L, 1, z_L_sol_, 1);
}
if( z_U_sol_ != NULL )
{
IpBlasCopy(n, z_U, 1, z_U_sol_, 1);
}
if( g_sol_ != NULL )
{
IpBlasCopy(m, g, 1, g_sol_, 1);
}
if( lambda_sol_ != NULL )
{
IpBlasCopy(m, lambda, 1, lambda_sol_, 1);
}
if( obj_sol_ != NULL )
{
*obj_sol_ = obj_value;
}
}
void StdInterfaceTNLP::apply_new_x(
bool new_x,
Index n,
const Number* x
)
{
if( new_x )
{
DBG_ASSERT(x != NULL);
if( non_const_x_ == NULL )
{
non_const_x_ = new Number[n];
}
Ipopt::IpBlasCopy(n, x, 1, non_const_x_, 1);
}
}
}