#include "IpoptConfig.h"
#include "IpTNLPAdapter.hpp"
#include "IpBlas.hpp"
#include "IpIpoptData.hpp"
#include "IpIpoptCalculatedQuantities.hpp"
#include "IpDenseVector.hpp"
#include "IpExpansionMatrix.hpp"
#include "IpGenTMatrix.hpp"
#include "IpSymTMatrix.hpp"
#include "IpTDependencyDetector.hpp"
#include "IpTSymDependencyDetector.hpp"
#include "IpTripletToCSRConverter.hpp"
#ifdef IPOPT_HAS_HSL
#include "CoinHslConfig.h"
#include "IpMa28TDependencyDetector.hpp"
#endif
#ifdef IPOPT_HAS_MUMPS
# include "IpMumpsSolverInterface.hpp"
#endif
#ifdef IPOPT_HAS_WSMP
# include "IpWsmpSolverInterface.hpp"
#endif
#include <cmath>
#include <cstdio>
#include <cstring>
namespace Ipopt
{
#if IPOPT_VERBOSITY > 0
static const Index dbg_verbosity = 0;
#endif
TNLPAdapter::TNLPAdapter(
const SmartPtr<TNLP> tnlp,
const SmartPtr<const Journalist> jnlst
)
: tnlp_(tnlp),
jnlst_(jnlst),
full_x_(NULL),
full_lambda_(NULL),
full_g_(NULL),
jac_g_(NULL),
c_rhs_(NULL),
x_tag_for_iterates_(0),
y_c_tag_for_iterates_(0),
y_d_tag_for_iterates_(0),
x_tag_for_g_(0),
x_tag_for_jac_g_(0),
jac_idx_map_(NULL),
h_idx_map_(NULL),
x_fixed_map_(NULL),
findiff_jac_ia_(NULL),
findiff_jac_ja_(NULL),
findiff_jac_postriplet_(NULL),
findiff_x_l_(NULL),
findiff_x_u_(NULL)
{
ASSERT_EXCEPTION(IsValid(tnlp_), INVALID_TNLP, "The TNLP passed to TNLPAdapter is NULL. This MUST be a valid TNLP!");
}
TNLPAdapter::~TNLPAdapter()
{
delete[] full_x_;
delete[] full_lambda_;
delete[] full_g_;
delete[] jac_g_;
delete[] c_rhs_;
delete[] jac_idx_map_;
delete[] h_idx_map_;
delete[] x_fixed_map_;
delete[] findiff_jac_ia_;
delete[] findiff_jac_ja_;
delete[] findiff_jac_postriplet_;
delete[] findiff_x_l_;
delete[] findiff_x_u_;
}
void TNLPAdapter::RegisterOptions(
SmartPtr<RegisteredOptions> roptions
)
{
roptions->SetRegisteringCategory("NLP");
roptions->AddNumberOption(
"nlp_lower_bound_inf",
"any bound less or equal this value will be considered -inf (i.e. not lower bounded).",
-1e19);
roptions->AddNumberOption(
"nlp_upper_bound_inf",
"any bound greater or this value will be considered +inf (i.e. not upper bounded).",
1e19);
roptions->AddStringOption4(
"fixed_variable_treatment",
"Determines how fixed variables should be handled.",
"make_parameter",
"make_parameter", "Remove fixed variable from optimization variables",
"make_parameter_nodual", "Remove fixed variable from optimization variables and do not compute bound multipliers for fixed variables",
"make_constraint", "Add equality constraints fixing variables",
"relax_bounds", "Relax fixing bound constraints",
"The main difference between those options is that the starting point in the \"make_constraint\" case still "
"has the fixed variables at their given values, whereas in the case \"make_parameter(_nodual)\" the functions are always "
"evaluated with the fixed values for those variables. "
"Also, for \"relax_bounds\", the fixing bound constraints are relaxed (according to\" bound_relax_factor\"). "
"For all but \"make_parameter_nodual\", bound multipliers are computed for the fixed variables.");
std::vector<std::string> options;
std::vector<std::string> descrs;
options.push_back("none");
descrs.push_back("don't check; no extra work at beginning");
#ifdef IPOPT_HAS_MUMPS
options.push_back("mumps");
descrs.push_back("use MUMPS");
#endif
#ifdef IPOPT_HAS_WSMP
options.push_back("wsmp");
descrs.push_back("use WSMP");
#endif
#if ((defined(COINHSL_HAS_MA28) && !defined(IPOPT_SINGLE)) || (defined(COINHSL_HAS_MA28S) && defined(IPOPT_SINGLE))) && defined(F77_FUNC) && !defined(IPOPT_INT64)
options.push_back("ma28");
descrs.push_back("use MA28");
#endif
roptions->AddStringOption(
"dependency_detector",
"Indicates which linear solver should be used to detect linearly dependent equality constraints.",
"none",
options,
descrs,
"This is experimental and does not work well.",
true);
roptions->AddBoolOption(
"dependency_detection_with_rhs",
"Indicates if the right hand sides of the constraints should be considered in addition to gradients during dependency detection",
false,
"",
true);
roptions->AddLowerBoundedIntegerOption(
"num_linear_variables",
"Number of linear variables",
0,
0,
"When the Hessian is approximated, it is assumed that the first num_linear_variables variables are linear. "
"The Hessian is then not approximated in this space. "
"If the get_number_of_nonlinear_variables method in the TNLP is implemented, this option is ignored.",
true);
roptions->AddStringOption2(
"jacobian_approximation",
"Specifies technique to compute constraint Jacobian",
"exact",
"exact", "user-provided derivatives",
"finite-difference-values", "user-provided structure, values by finite differences",
"",
true);
roptions->AddStringOption2(
"gradient_approximation",
"Specifies technique to compute objective Gradient",
"exact",
"exact", "user-provided gradient",
"finite-difference-values", "values by finite differences",
"",
true);
roptions->AddLowerBoundedNumberOption(
"findiff_perturbation",
"Size of the finite difference perturbation for derivative approximation.",
0., true,
1e-7,
"This determines the relative perturbation of the variable entries.",
true);
roptions->SetRegisteringCategory("Derivative Checker");
roptions->AddStringOption4(
"derivative_test",
"Enable derivative checker",
"none",
"none", "do not perform derivative test",
"first-order", "perform test of first derivatives at starting point",
"second-order", "perform test of first and second derivatives at starting point",
"only-second-order", "perform test of second derivatives at starting point",
"If this option is enabled, a (slow!) derivative test will be performed before the optimization. "
"The test is performed at the user provided starting point and marks derivative values that seem suspicious");
roptions->AddLowerBoundedIntegerOption(
"derivative_test_first_index",
"Index of first quantity to be checked by derivative checker",
-2,
-2,
"If this is set to -2, then all derivatives are checked. "
"Otherwise, for the first derivative test it specifies the first variable for which the test is done (counting starts at 0). "
"For second derivatives, it specifies the first constraint for which the test is done; "
"counting of constraint indices starts at 0, and -1 refers to the objective function Hessian.");
roptions->AddLowerBoundedNumberOption(
"derivative_test_perturbation",
"Size of the finite difference perturbation in derivative test.",
0., true,
1e-8,
"This determines the relative perturbation of the variable entries.");
roptions->AddLowerBoundedNumberOption(
"derivative_test_tol",
"Threshold for indicating wrong derivative.",
0., true,
1e-4,
"If the relative deviation of the estimated derivative from the given one is larger than this value, "
"the corresponding derivative is marked as wrong.");
roptions->AddBoolOption(
"derivative_test_print_all",
"Indicates whether information for all estimated derivatives should be printed.",
false,
"Determines verbosity of derivative checker.");
roptions->AddLowerBoundedNumberOption(
"point_perturbation_radius",
"Maximal perturbation of an evaluation point.",
0., false,
10.,
"If a random perturbation of a points is required, this number indicates the maximal perturbation. "
"This is for example used when determining the center point at which the finite difference derivative test is executed.");
}
bool TNLPAdapter::ProcessOptions(
const OptionsList& options,
const std::string& prefix
)
{
DBG_START_METH("TNLPAdapter::ProcessOptions", dbg_verbosity);
options.GetNumericValue("nlp_lower_bound_inf", nlp_lower_bound_inf_, prefix);
options.GetNumericValue("nlp_upper_bound_inf", nlp_upper_bound_inf_, prefix);
ASSERT_EXCEPTION(nlp_lower_bound_inf_ < nlp_upper_bound_inf_, OPTION_INVALID,
"Option \"nlp_lower_bound_inf\" must be smaller than \"nlp_upper_bound_inf\".");
options.GetNumericValue("bound_relax_factor", bound_relax_factor_, prefix);
Index enum_int;
options.GetEnumValue("fixed_variable_treatment", enum_int, prefix);
fixed_variable_treatment_ = FixedVariableTreatmentEnum(enum_int);
options.GetEnumValue("derivative_test", enum_int, prefix);
derivative_test_ = DerivativeTestEnum(enum_int);
options.GetNumericValue("derivative_test_perturbation", derivative_test_perturbation_, prefix);
options.GetNumericValue("derivative_test_tol", derivative_test_tol_, prefix);
options.GetBoolValue("derivative_test_print_all", derivative_test_print_all_, prefix);
options.GetIntegerValue("derivative_test_first_index", derivative_test_first_index_, prefix);
options.GetBoolValue("warm_start_same_structure", warm_start_same_structure_, prefix);
options.GetEnumValue("hessian_approximation", enum_int, prefix);
hessian_approximation_ = HessianApproximationType(enum_int);
options.GetIntegerValue("num_linear_variables", num_linear_variables_, prefix);
options.GetEnumValue("jacobian_approximation", enum_int, prefix);
jacobian_approximation_ = JacobianApproxEnum(enum_int);
options.GetEnumValue("gradient_approximation", enum_int, prefix);
gradient_approximation_ = GradientApproxEnum(enum_int);
options.GetNumericValue("findiff_perturbation", findiff_perturbation_, prefix);
options.GetNumericValue("point_perturbation_radius", point_perturbation_radius_, prefix);
options.GetNumericValue("tol", tol_, prefix);
options.GetBoolValue("dependency_detection_with_rhs", dependency_detection_with_rhs_, prefix);
std::string dependency_detector;
options.GetStringValue("dependency_detector", dependency_detector, prefix);
#ifdef IPOPT_HAS_MUMPS
if( dependency_detector == "mumps" )
{
SmartPtr<SparseSymLinearSolverInterface> SolverInterface;
SolverInterface = new MumpsSolverInterface();
SmartPtr<TSymLinearSolver> ScaledSolver =
new TSymLinearSolver(SolverInterface, NULL);
dependency_detector_ = new TSymDependencyDetector(*ScaledSolver);
}
#endif
#ifdef IPOPT_HAS_WSMP
if( dependency_detector == "wsmp" )
{
SmartPtr<SparseSymLinearSolverInterface> SolverInterface;
#ifdef PARDISO_MATCHING_PREPROCESS
std::string libname;
options.GetStringValue("pardisolib", libname, prefix);
SolverInterface = new WsmpSolverInterface(new LibraryLoader(libname));
#else
SolverInterface = new WsmpSolverInterface();
#endif
SmartPtr<TSymLinearSolver> ScaledSolver =
new TSymLinearSolver(SolverInterface, NULL);
dependency_detector_ = new TSymDependencyDetector(*ScaledSolver);
}
#endif
#if ((defined(COINHSL_HAS_MA28) && !defined(IPOPT_SINGLE)) || (defined(COINHSL_HAS_MA28S) && defined(IPOPT_SINGLE))) && defined(F77_FUNC) && !defined(IPOPT_INT64)
if( dependency_detector == "ma28" )
{
dependency_detector_ = new Ma28TDependencyDetector();
}
#endif
if( IsValid(dependency_detector_) )
if( !dependency_detector_->ReducedInitialize(*jnlst_, options, prefix) )
{
return false;
}
return true;
}
bool TNLPAdapter::GetSpaces(
SmartPtr<const VectorSpace>& x_space,
SmartPtr<const VectorSpace>& c_space,
SmartPtr<const VectorSpace>& d_space,
SmartPtr<const VectorSpace>& x_l_space,
SmartPtr<const MatrixSpace>& px_l_space,
SmartPtr<const VectorSpace>& x_u_space,
SmartPtr<const MatrixSpace>& px_u_space,
SmartPtr<const VectorSpace>& d_l_space,
SmartPtr<const MatrixSpace>& pd_l_space,
SmartPtr<const VectorSpace>& d_u_space,
SmartPtr<const MatrixSpace>& pd_u_space,
SmartPtr<const MatrixSpace>& Jac_c_space,
SmartPtr<const MatrixSpace>& Jac_d_space,
SmartPtr<const SymMatrixSpace>& Hess_lagrangian_space
)
{
DBG_START_METH("TNLPAdapter::GetSpaces", dbg_verbosity);
if( derivative_test_ != NO_TEST )
{
bool retval = CheckDerivatives(derivative_test_, derivative_test_first_index_);
if( !retval )
{
return retval;
}
}
if( warm_start_same_structure_ )
{
ASSERT_EXCEPTION(full_x_, INVALID_WARMSTART,
"warm_start_same_structure chosen, but TNLPAdapter is called for the first time.");
if( IsValid(jnlst_) )
{
jnlst_->Printf(J_DETAILED, J_INITIALIZATION, "Reusing previous information for warm start in TNLPAdapter.\n");
}
}
else
{
delete[] full_x_;
full_x_ = NULL;
delete[] full_lambda_;
full_lambda_ = NULL;
delete[] full_g_;
full_g_ = NULL;
delete[] jac_g_;
jac_g_ = NULL;
delete[] c_rhs_;
c_rhs_ = NULL;
delete[] jac_idx_map_;
jac_idx_map_ = NULL;
delete[] h_idx_map_;
h_idx_map_ = NULL;
delete[] x_fixed_map_;
x_fixed_map_ = NULL;
jac_fixed_idx_map_.clear();
jac_fixed_iRow_.clear();
jac_fixed_jCol_.clear();
#if __cplusplus >= 201103L
jac_fixed_idx_map_.shrink_to_fit();
jac_fixed_iRow_.shrink_to_fit();
jac_fixed_jCol_.shrink_to_fit();
#endif
}
Index n_full_x, n_full_g, nz_full_jac_g, nz_full_h;
bool retval = tnlp_->get_nlp_info(n_full_x, n_full_g, nz_full_jac_g, nz_full_h, index_style_);
ASSERT_EXCEPTION(retval, INVALID_TNLP, "get_nlp_info returned false");
ASSERT_EXCEPTION(n_full_x >= 0, INVALID_TNLP, "number of variables negative");
ASSERT_EXCEPTION(n_full_g >= 0, INVALID_TNLP, "number of constraints negative");
ASSERT_EXCEPTION(nz_full_jac_g >= 0, INVALID_TNLP, "number of nonzeros in Jacobian negative");
ASSERT_EXCEPTION(nz_full_h >= 0, INVALID_TNLP, "number of nonzeros in Hessian negative");
ASSERT_EXCEPTION(
!warm_start_same_structure_
|| (n_full_x == n_full_x_ && n_full_g == n_full_g_ && nz_full_jac_g == nz_full_jac_g_
&& nz_full_h == nz_full_h_), INVALID_WARMSTART,
"warm_start_same_structure chosen, but problem dimensions are different.");
n_full_x_ = n_full_x;
n_full_g_ = n_full_g;
nz_full_jac_g_ = nz_full_jac_g;
nz_full_h_ = nz_full_h;
if( !warm_start_same_structure_ )
{
full_x_ = new Number[n_full_x_];
full_lambda_ = new Number[n_full_g_];
full_g_ = new Number[n_full_g_];
StringMetaDataMapType var_string_md;
IntegerMetaDataMapType var_integer_md;
NumericMetaDataMapType var_numeric_md;
StringMetaDataMapType con_string_md;
IntegerMetaDataMapType con_integer_md;
NumericMetaDataMapType con_numeric_md;
if( !tnlp_->get_var_con_metadata(n_full_x_, var_string_md, var_integer_md, var_numeric_md, n_full_g_,
con_string_md, con_integer_md, con_numeric_md) )
{
var_string_md.clear();
var_integer_md.clear();
var_numeric_md.clear();
con_string_md.clear();
con_integer_md.clear();
con_numeric_md.clear();
}
jac_g_ = new Number[nz_full_jac_g_];
Number* x_l = new Number[n_full_x_];
Number* x_u = new Number[n_full_x_];
Number* g_l = new Number[n_full_g_];
Number* g_u = new Number[n_full_g_];
retval = tnlp_->get_bounds_info(n_full_x_, x_l, x_u, n_full_g_, g_l, g_u);
ASSERT_EXCEPTION(retval, INVALID_TNLP, "get_bounds_info returned false in GetSpaces");
Index n_x_var;
Index n_x_l;
Index n_x_u;
Index* x_not_fixed_map = new Index[n_full_x_];
Index* x_l_map = new Index[n_full_x_];
Index* x_u_map = new Index[n_full_x_];
Index n_c;
Index n_d;
Index n_d_l;
Index n_d_u;
Index* c_map = new Index[n_full_g_]; Index* d_map = new Index[n_full_g_]; Index* d_l_map = new Index[n_full_g_]; Index* d_u_map = new Index[n_full_g_];
bool done = false;
while( !done )
{
n_x_var = 0;
n_x_l = 0;
n_x_u = 0;
n_x_fixed_ = 0;
Index* x_fixed_map_tmp = new Index[n_full_x_];
for( Index i = 0; i < n_full_x_; i++ )
{
Number lower_bound = x_l[i];
Number upper_bound = x_u[i];
if( lower_bound == upper_bound )
{
switch( fixed_variable_treatment_ )
{
case MAKE_PARAMETER:
case MAKE_PARAMETER_NODUAL:
full_x_[i] = lower_bound;
x_fixed_map_tmp[n_x_fixed_] = i;
n_x_fixed_++;
break;
case MAKE_CONSTRAINT:
x_fixed_map_tmp[n_x_fixed_] = i; n_x_fixed_++;
x_not_fixed_map[n_x_var] = i;
n_x_var++;
break;
case RELAX_BOUNDS:
x_l_map[n_x_l] = n_x_var;
n_x_l++;
x_u_map[n_x_u] = n_x_var;
n_x_u++;
n_x_var++;
break;
default:
DBG_ASSERT(false && "invalid fixed_variable_treatment_");
}
}
else if( lower_bound > upper_bound )
{
char string[128];
Snprintf(string, 127,
"There are inconsistent bounds on variable %" IPOPT_INDEX_FORMAT ": lower = %25.16e and upper = %25.16e.", i, lower_bound,
upper_bound);
delete[] x_l;
delete[] x_u;
delete[] g_l;
delete[] g_u;
delete[] x_not_fixed_map;
delete[] x_fixed_map_tmp;
delete[] x_l_map;
delete[] x_u_map;
delete[] c_map;
delete[] d_map;
delete[] d_l_map;
delete[] d_u_map;
THROW_EXCEPTION(INCONSISTENT_BOUNDS, string);
}
else
{
x_not_fixed_map[n_x_var] = i;
if( lower_bound > nlp_lower_bound_inf_ )
{
x_l_map[n_x_l] = n_x_var;
n_x_l++;
}
if( upper_bound < nlp_upper_bound_inf_ )
{
x_u_map[n_x_u] = n_x_var;
n_x_u++;
}
n_x_var++;
}
}
if( n_x_fixed_ > 0 )
{
delete[] x_fixed_map_;
x_fixed_map_ = NULL;
x_fixed_map_ = new Index[n_x_fixed_];
for( Index i = 0; i < n_x_fixed_; i++ )
{
x_fixed_map_[i] = x_fixed_map_tmp[i];
}
}
else
{
delete[] x_fixed_map_;
x_fixed_map_ = NULL;
}
delete[] x_fixed_map_tmp;
n_c = 0;
n_d = 0;
n_d_l = 0;
n_d_u = 0;
for( Index i = 0; i < n_full_g_; i++ )
{
Number lower_bound = g_l[i];
Number upper_bound = g_u[i];
if( lower_bound == upper_bound )
{
c_map[n_c] = i;
n_c++;
}
else if( lower_bound > upper_bound )
{
delete[] x_l;
delete[] x_u;
delete[] g_l;
delete[] g_u;
delete[] x_not_fixed_map;
delete[] x_l_map;
delete[] x_u_map;
delete[] c_map;
delete[] d_map;
delete[] d_l_map;
delete[] d_u_map;
char string[128];
Snprintf(string, 127,
"There are inconsistent bounds on constraint function %" IPOPT_INDEX_FORMAT ": lower = %25.16e and upper = %25.16e.", i,
lower_bound, upper_bound);
THROW_EXCEPTION(INCONSISTENT_BOUNDS, string);
}
else
{
d_map[n_d] = i;
if( lower_bound > nlp_lower_bound_inf_ )
{
d_l_map[n_d_l] = n_d;
n_d_l++;
}
if( upper_bound < nlp_upper_bound_inf_ )
{
d_u_map[n_d_u] = n_d;
n_d_u++;
}
n_d++;
}
}
if( fixed_variable_treatment_ == RELAX_BOUNDS || n_x_fixed_ == 0 || n_x_var >= n_c || n_x_var == 0 )
{
done = true;
}
else
{
fixed_variable_treatment_ = RELAX_BOUNDS;
jnlst_->Printf(J_WARNING, J_INITIALIZATION,
"Too few degrees of freedom (n_x = %" IPOPT_INDEX_FORMAT ", n_c = %" IPOPT_INDEX_FORMAT ").\n Trying fixed_variable_treatment = RELAX_BOUNDS\n\n",
n_x_var, n_c);
}
}
if( n_c > 0 && IsValid(dependency_detector_) )
{
std::list<Index> c_deps;
if( !DetermineDependentConstraints(n_x_var, x_not_fixed_map, x_l, x_u, g_l, g_u, n_c, c_map, c_deps) )
{
jnlst_->Printf(J_WARNING, J_INITIALIZATION,
"Dependent constraint detector had a problem, assume full rank.\n");
}
c_deps.sort();
if( !c_deps.empty() )
{
jnlst_->Printf(J_WARNING, J_INITIALIZATION,
"\nDetected %zd linearly dependent equality constraints; taking those out.\n\n", c_deps.size());
}
else
{
jnlst_->Printf(J_DETAILED, J_INITIALIZATION, "\nNo dependent constraints detected.\n\n");
}
if( jnlst_->ProduceOutput(J_DETAILED, J_INITIALIZATION) )
{
jnlst_->Printf(J_DETAILED, J_INITIALIZATION, "\nList of indices of dependent constraints:\n");
Index count = 0;
for( std::list<Index>::iterator i = c_deps.begin(); i != c_deps.end(); ++i )
{
jnlst_->Printf(J_DETAILED, J_INITIALIZATION, "c_dep[%" IPOPT_INDEX_FORMAT "] = %" IPOPT_INDEX_FORMAT "\n", count++, *i);
}
jnlst_->Printf(J_DETAILED, J_INITIALIZATION, "\n");
}
if( !c_deps.empty() )
{
std::list<Index>::iterator idep = c_deps.begin();
Index new_n_c = *idep;
for( Index i = *idep; i < n_c; i++ )
{
if( i == *idep )
{
++idep;
}
else
{
c_map[new_n_c] = c_map[i];
new_n_c++;
}
if( idep == c_deps.end() )
{
for( Index j = i + 1; j < n_c; j++ )
{
c_map[new_n_c++] = c_map[j];
}
break;
}
}
n_c = new_n_c;
const Number zero = 0.;
IpBlasCopy(n_full_g_, &zero, 0, full_lambda_, 1);
}
}
delete[] x_l;
x_l = NULL;
delete[] x_u;
x_u = NULL;
SmartPtr<DenseVectorSpace> dv_x_space = new DenseVectorSpace(n_x_var);
x_space_ = GetRawPtr(dv_x_space);
SmartPtr<DenseVectorSpace> dv_x_l_space = new DenseVectorSpace(n_x_l);
x_l_space_ = GetRawPtr(dv_x_l_space);
SmartPtr<DenseVectorSpace> dv_x_u_space = new DenseVectorSpace(n_x_u);
x_u_space_ = GetRawPtr(dv_x_u_space);
if( n_x_fixed_ > 0 && (fixed_variable_treatment_ == MAKE_PARAMETER || fixed_variable_treatment_ == MAKE_PARAMETER_NODUAL) )
{
P_x_full_x_space_ = new ExpansionMatrixSpace(n_full_x_, n_x_var, x_not_fixed_map);
P_x_full_x_ = P_x_full_x_space_->MakeNewExpansionMatrix();
}
else
{
P_x_full_x_space_ = NULL;
P_x_full_x_ = NULL;
}
P_x_x_L_space_ = new ExpansionMatrixSpace(n_x_var, n_x_l, x_l_map);
px_l_space_ = GetRawPtr(P_x_x_L_space_);
P_x_x_L_ = P_x_x_L_space_->MakeNewExpansionMatrix();
P_x_x_U_space_ = new ExpansionMatrixSpace(n_x_var, n_x_u, x_u_map);
px_u_space_ = GetRawPtr(P_x_x_U_space_);
P_x_x_U_ = P_x_x_U_space_->MakeNewExpansionMatrix();
if( var_string_md.size() > 0 )
{
for( StringMetaDataMapType::iterator iter = var_string_md.begin(); iter != var_string_md.end(); ++iter )
{
std::vector<std::string> string_md(n_x_var);
const Index* pos_idx = NULL;
if( IsValid(P_x_full_x_space_) )
{
pos_idx = P_x_full_x_->ExpandedPosIndices();
for( Index i = 0; i < n_x_var; i++ )
{
string_md[i] = iter->second[pos_idx[i]];
}
}
else
{
for( Index i = 0; i < n_x_var; i++ )
{
string_md[i] = iter->second[i];
}
}
dv_x_space->SetStringMetaData(iter->first, string_md);
string_md.clear();
string_md.resize(n_x_l);
const Index* pos_idxL = P_x_x_L_space_->ExpandedPosIndices();
for( Index i = 0; i < n_x_l; i++ )
{
if( pos_idx != NULL )
{
string_md[i] = iter->second[pos_idx[pos_idxL[i]]];
}
else
{
string_md[i] = iter->second[pos_idxL[i]];
}
}
dv_x_l_space->SetStringMetaData(iter->first, string_md);
string_md.clear();
string_md.resize(n_x_u);
const Index* pos_idxU = P_x_x_U_space_->ExpandedPosIndices();
for( Index i = 0; i < n_x_u; i++ )
{
if( pos_idx != NULL )
{
string_md[i] = iter->second[pos_idx[pos_idxU[i]]];
}
else
{
string_md[i] = iter->second[pos_idxU[i]];
}
}
dv_x_u_space->SetStringMetaData(iter->first, string_md);
}
}
if( var_integer_md.size() > 0 )
{
for( IntegerMetaDataMapType::iterator iter = var_integer_md.begin(); iter != var_integer_md.end(); ++iter )
{
std::vector<Index> integer_md(n_x_var);
const Index* pos_idx = NULL;
if( IsValid(P_x_full_x_space_) )
{
pos_idx = P_x_full_x_->ExpandedPosIndices();
for( Index i = 0; i < n_x_var; i++ )
{
integer_md[i] = iter->second[pos_idx[i]];
}
}
else
{
for( Index i = 0; i < n_x_var; i++ )
{
integer_md[i] = iter->second[i];
}
}
dv_x_space->SetIntegerMetaData(iter->first, integer_md);
integer_md.clear();
integer_md.resize(n_x_l);
const Index* pos_idxL = P_x_x_L_space_->ExpandedPosIndices();
for( Index i = 0; i < n_x_l; i++ )
{
if( pos_idx != NULL )
{
integer_md[i] = iter->second[pos_idx[pos_idxL[i]]];
}
else
{
integer_md[i] = iter->second[pos_idxL[i]];
}
}
dv_x_l_space->SetIntegerMetaData(iter->first, integer_md);
integer_md.clear();
integer_md.resize(n_x_u);
const Index* pos_idxU = P_x_x_U_space_->ExpandedPosIndices();
for( Index i = 0; i < n_x_u; i++ )
{
if( pos_idx != NULL )
{
integer_md[i] = iter->second[pos_idx[pos_idxU[i]]];
}
else
{
integer_md[i] = iter->second[pos_idxU[i]];
}
}
dv_x_u_space->SetIntegerMetaData(iter->first, integer_md);
}
}
if( var_numeric_md.size() > 0 )
{
for( NumericMetaDataMapType::iterator iter = var_numeric_md.begin(); iter != var_numeric_md.end(); ++iter )
{
std::vector<Number> numeric_md(n_x_var);
const Index* pos_idx = NULL;
if( IsValid(P_x_full_x_space_) )
{
pos_idx = P_x_full_x_->ExpandedPosIndices();
for( Index i = 0; i < n_x_var; i++ )
{
numeric_md[i] = iter->second[pos_idx[i]];
}
}
else
{
for( Index i = 0; i < n_x_var; i++ )
{
numeric_md[i] = iter->second[i];
}
}
dv_x_space->SetNumericMetaData(iter->first, numeric_md);
numeric_md.clear();
numeric_md.resize(n_x_l);
const Index* pos_idxL = P_x_x_L_space_->ExpandedPosIndices();
for( Index i = 0; i < n_x_l; i++ )
{
if( pos_idx != NULL )
{
numeric_md[i] = iter->second[pos_idx[pos_idxL[i]]];
}
else
{
numeric_md[i] = iter->second[pos_idxL[i]];
}
}
dv_x_l_space->SetNumericMetaData(iter->first, numeric_md);
numeric_md.clear();
numeric_md.resize(n_x_u);
const Index* pos_idxU = P_x_x_U_space_->ExpandedPosIndices();
for( Index i = 0; i < n_x_u; i++ )
{
if( pos_idx != NULL )
{
numeric_md[i] = iter->second[pos_idx[pos_idxU[i]]];
}
else
{
numeric_md[i] = iter->second[pos_idxU[i]];
}
}
dv_x_u_space->SetNumericMetaData(iter->first, numeric_md);
}
}
delete[] x_not_fixed_map;
x_not_fixed_map = NULL;
delete[] x_l_map;
x_l_map = NULL;
delete[] x_u_map;
x_u_map = NULL;
SmartPtr<DenseVectorSpace> dc_space;
if( n_x_fixed_ == 0 || fixed_variable_treatment_ == MAKE_PARAMETER || fixed_variable_treatment_ == MAKE_PARAMETER_NODUAL )
{
dc_space = new DenseVectorSpace(n_c);
}
else
{
dc_space = new DenseVectorSpace(n_c + n_x_fixed_);
}
c_space_ = GetRawPtr(dc_space);
c_rhs_ = new Number[dc_space->Dim()];
P_c_g_space_ = new ExpansionMatrixSpace(n_full_g_, n_c, c_map);
P_c_g_ = P_c_g_space_->MakeNewExpansionMatrix();
delete[] c_map;
c_map = NULL;
SmartPtr<DenseVectorSpace> dv_d_space = new DenseVectorSpace(n_d);
d_space_ = GetRawPtr(dv_d_space);
P_d_g_space_ = new ExpansionMatrixSpace(n_full_g_, n_d, d_map);
P_d_g_ = P_d_g_space_->MakeNewExpansionMatrix();
delete[] d_map;
d_map = NULL;
SmartPtr<DenseVectorSpace> dv_d_l_space = new DenseVectorSpace(n_d_l);
d_l_space_ = GetRawPtr(dv_d_l_space);
SmartPtr<ExpansionMatrixSpace> P_d_l_space = new ExpansionMatrixSpace(n_d, n_d_l, d_l_map);
pd_l_space_ = GetRawPtr(P_d_l_space);
delete[] d_l_map;
d_l_map = NULL;
SmartPtr<DenseVectorSpace> dv_d_u_space = new DenseVectorSpace(n_d_u);
d_u_space_ = GetRawPtr(dv_d_u_space);
SmartPtr<ExpansionMatrixSpace> P_d_u_space = new ExpansionMatrixSpace(n_d, n_d_u, d_u_map);
pd_u_space_ = GetRawPtr(P_d_u_space);
delete[] d_u_map;
d_u_map = NULL;
delete[] g_l;
g_l = NULL;
delete[] g_u;
g_u = NULL;
if( con_string_md.size() > 0 )
{
for( StringMetaDataMapType::iterator iter = con_string_md.begin(); iter != con_string_md.end(); ++iter )
{
std::vector<std::string> string_md(n_c);
const Index* pos_idx = P_c_g_space_->ExpandedPosIndices();
for( Index i = 0; i < n_c; i++ )
{
string_md[i] = iter->second[pos_idx[i]];
}
dc_space->SetStringMetaData(iter->first, string_md);
string_md.clear();
string_md.resize(n_d);
pos_idx = P_d_g_space_->ExpandedPosIndices();
for( Index i = 0; i < n_d; i++ )
{
string_md[i] = iter->second[pos_idx[i]];
}
dv_d_space->SetStringMetaData(iter->first, string_md);
string_md.clear();
string_md.resize(n_d_l);
const Index* d_pos_idx = P_d_l_space->ExpandedPosIndices();
for( Index i = 0; i < n_d_l; i++ )
{
string_md[i] = iter->second[pos_idx[d_pos_idx[i]]];
}
dv_d_l_space->SetStringMetaData(iter->first, string_md);
string_md.clear();
string_md.resize(n_d_u);
d_pos_idx = P_d_u_space->ExpandedPosIndices();
for( Index i = 0; i < n_d_u; i++ )
{
string_md[i] = iter->second[pos_idx[d_pos_idx[i]]];
}
dv_d_u_space->SetStringMetaData(iter->first, string_md);
}
}
if( con_integer_md.size() > 0 )
{
for( IntegerMetaDataMapType::iterator iter = con_integer_md.begin(); iter != con_integer_md.end(); ++iter )
{
std::vector<Index> integer_md(n_c);
const Index* pos_idx = P_c_g_space_->ExpandedPosIndices();
for( Index i = 0; i < n_c; i++ )
{
integer_md[i] = iter->second[pos_idx[i]];
}
dc_space->SetIntegerMetaData(iter->first, integer_md);
integer_md.clear();
integer_md.resize(n_d);
pos_idx = P_d_g_space_->ExpandedPosIndices();
for( Index i = 0; i < n_d; i++ )
{
integer_md[i] = iter->second[pos_idx[i]];
}
dv_d_space->SetIntegerMetaData(iter->first, integer_md);
integer_md.clear();
integer_md.resize(n_d_l);
const Index* d_pos_idx = P_d_l_space->ExpandedPosIndices();
for( Index i = 0; i < n_d_l; i++ )
{
integer_md[i] = iter->second[pos_idx[d_pos_idx[i]]];
}
dv_d_l_space->SetIntegerMetaData(iter->first, integer_md);
integer_md.clear();
integer_md.resize(n_d_u);
d_pos_idx = P_d_u_space->ExpandedPosIndices();
for( Index i = 0; i < n_d_u; i++ )
{
integer_md[i] = iter->second[pos_idx[d_pos_idx[i]]];
}
dv_d_u_space->SetIntegerMetaData(iter->first, integer_md);
}
}
if( con_numeric_md.size() > 0 )
{
for( NumericMetaDataMapType::iterator iter = con_numeric_md.begin(); iter != con_numeric_md.end(); ++iter )
{
std::vector<Number> numeric_md(n_c);
const Index* pos_idx = P_c_g_space_->ExpandedPosIndices();
for( Index i = 0; i < n_c; i++ )
{
numeric_md[i] = iter->second[pos_idx[i]];
}
dc_space->SetNumericMetaData(iter->first, numeric_md);
numeric_md.clear();
numeric_md.resize(n_d);
pos_idx = P_d_g_space_->ExpandedPosIndices();
for( Index i = 0; i < n_d; i++ )
{
numeric_md[i] = iter->second[pos_idx[i]];
}
dv_d_space->SetNumericMetaData(iter->first, numeric_md);
numeric_md.clear();
numeric_md.resize(n_d_l);
const Index* d_pos_idx = P_d_l_space->ExpandedPosIndices();
for( Index i = 0; i < n_d_l; i++ )
{
numeric_md[i] = iter->second[pos_idx[d_pos_idx[i]]];
}
dv_d_l_space->SetNumericMetaData(iter->first, numeric_md);
numeric_md.clear();
numeric_md.resize(n_d_u);
d_pos_idx = P_d_u_space->ExpandedPosIndices();
for( Index i = 0; i < n_d_u; i++ )
{
numeric_md[i] = iter->second[pos_idx[d_pos_idx[i]]];
}
dv_d_u_space->SetNumericMetaData(iter->first, numeric_md);
}
}
Index* g_iRow = new Index[nz_full_jac_g_];
Index* g_jCol = new Index[nz_full_jac_g_];
bool retval = tnlp_->eval_jac_g(n_full_x_, NULL, false, n_full_g_, nz_full_jac_g_, g_iRow, g_jCol, NULL);
if( !retval )
{
delete[] g_iRow;
delete[] g_jCol;
THROW_EXCEPTION(INVALID_TNLP, "eval_jac_g returned false in GetSpaces");
}
if( index_style_ != TNLP::FORTRAN_STYLE )
{
for( Index i = 0; i < nz_full_jac_g_; i++ )
{
DBG_ASSERT(g_iRow[i] >= 0);
DBG_ASSERT(g_iRow[i] < n_full_g_);
DBG_ASSERT(g_jCol[i] >= 0);
DBG_ASSERT(g_jCol[i] < n_full_x_);
g_iRow[i] += 1;
g_jCol[i] += 1;
}
}
#if IPOPT_CHECKLEVEL > 0
else
{
for( Index i = 0; i < nz_full_jac_g_; i++ )
{
DBG_ASSERT(g_iRow[i] > 0);
DBG_ASSERT(g_iRow[i] <= n_full_g_);
DBG_ASSERT(g_jCol[i] > 0);
DBG_ASSERT(g_jCol[i] <= n_full_x_);
}
}
#endif
if( jacobian_approximation_ == JAC_FINDIFF_VALUES )
{
initialize_findiff_jac(g_iRow, g_jCol);
}
Index nz_jac_all;
if( fixed_variable_treatment_ == MAKE_PARAMETER || fixed_variable_treatment_ == MAKE_PARAMETER_NODUAL )
{
nz_jac_all = nz_full_jac_g_;
}
else
{
nz_jac_all = nz_full_jac_g_ + n_x_fixed_;
}
jac_idx_map_ = new Index[nz_jac_all];
Index* jac_c_iRow = new Index[nz_jac_all];
Index* jac_c_jCol = new Index[nz_jac_all];
Index current_nz = 0;
const Index* c_row_pos = P_c_g_->CompressedPosIndices();
if( IsValid(P_x_full_x_) )
{
const Index* c_col_pos = P_x_full_x_->CompressedPosIndices();
for( Index i = 0; i < nz_full_jac_g_; i++ )
{
const Index& c_row = c_row_pos[g_iRow[i] - 1];
const Index& c_col = c_col_pos[g_jCol[i] - 1];
if( c_col != -1 && c_row != -1 )
{
jac_idx_map_[current_nz] = i;
jac_c_iRow[current_nz] = c_row + 1;
jac_c_jCol[current_nz] = c_col + 1;
current_nz++;
}
else if( c_col == -1 && fixed_variable_treatment_ == MAKE_PARAMETER )
{
jac_fixed_idx_map_.push_back(i);
jac_fixed_iRow_.push_back(g_iRow[i]);
jac_fixed_jCol_.push_back(g_jCol[i]);
}
}
}
else
{
for( Index i = 0; i < nz_full_jac_g_; i++ )
{
const Index& c_row = c_row_pos[g_iRow[i] - 1];
const Index& c_col = g_jCol[i] - 1;
if( c_row != -1 )
{
jac_idx_map_[current_nz] = i;
jac_c_iRow[current_nz] = c_row + 1;
jac_c_jCol[current_nz] = c_col + 1;
current_nz++;
}
}
}
nz_jac_c_no_extra_ = current_nz;
Index n_added_constr;
if( fixed_variable_treatment_ == MAKE_PARAMETER || fixed_variable_treatment_ == MAKE_PARAMETER_NODUAL )
{
nz_jac_c_ = nz_jac_c_no_extra_;
n_added_constr = 0;
}
else
{
nz_jac_c_ = nz_jac_c_no_extra_ + n_x_fixed_;
for( Index i = 0; i < n_x_fixed_; i++ )
{
jac_c_iRow[current_nz] = n_c + i + 1;
jac_c_jCol[current_nz] = x_fixed_map_[i] + 1;
current_nz++;
}
n_added_constr = n_x_fixed_;
}
Jac_c_space_ = new GenTMatrixSpace(n_c + n_added_constr, n_x_var, nz_jac_c_, jac_c_iRow, jac_c_jCol);
delete[] jac_c_iRow;
jac_c_iRow = NULL;
delete[] jac_c_jCol;
jac_c_jCol = NULL;
Index* jac_d_iRow = new Index[nz_full_jac_g_];
Index* jac_d_jCol = new Index[nz_full_jac_g_];
current_nz = 0;
const Index* d_row_pos = P_d_g_->CompressedPosIndices();
if( IsValid(P_x_full_x_) )
{
const Index* d_col_pos = P_x_full_x_->CompressedPosIndices();
for( Index i = 0; i < nz_full_jac_g_; i++ )
{
const Index& d_row = d_row_pos[g_iRow[i] - 1];
const Index& d_col = d_col_pos[g_jCol[i] - 1];
if( d_col != -1 && d_row != -1 )
{
jac_idx_map_[current_nz + nz_jac_c_no_extra_] = i;
jac_d_iRow[current_nz] = d_row + 1;
jac_d_jCol[current_nz] = d_col + 1;
current_nz++;
}
}
}
else
{
for( Index i = 0; i < nz_full_jac_g_; i++ )
{
const Index& d_row = d_row_pos[g_iRow[i] - 1];
const Index& d_col = g_jCol[i] - 1;
if( d_row != -1 )
{
jac_idx_map_[current_nz + nz_jac_c_no_extra_] = i;
jac_d_iRow[current_nz] = d_row + 1;
jac_d_jCol[current_nz] = d_col + 1;
current_nz++;
}
}
}
nz_jac_d_ = current_nz;
Jac_d_space_ = new GenTMatrixSpace(n_d, n_x_var, nz_jac_d_, jac_d_iRow, jac_d_jCol);
delete[] jac_d_iRow;
jac_d_iRow = NULL;
delete[] jac_d_jCol;
jac_d_jCol = NULL;
delete[] g_iRow;
g_iRow = NULL;
delete[] g_jCol;
g_jCol = NULL;
if( hessian_approximation_ == EXACT )
{
Index* full_h_iRow = new Index[nz_full_h_];
Index* full_h_jCol = new Index[nz_full_h_];
Index* h_iRow = new Index[nz_full_h_];
Index* h_jCol = new Index[nz_full_h_];
retval = tnlp_->eval_h(n_full_x_, NULL, false, 0, n_full_g_,
NULL, false, nz_full_h_, full_h_iRow, full_h_jCol, NULL);
if( !retval )
{
delete[] full_h_iRow;
delete[] full_h_jCol;
delete[] h_iRow;
delete[] h_jCol;
jnlst_->Printf(J_ERROR, J_INITIALIZATION,
"Option \"hessian_approximation\" is not chosen as \"limited-memory\", but eval_h returns false.\n");
THROW_EXCEPTION(OPTION_INVALID, "eval_h is called but has not been implemented");
}
if( index_style_ != TNLP::FORTRAN_STYLE )
{
for( Index i = 0; i < nz_full_h_; i++ )
{
DBG_ASSERT(full_h_iRow[i] >= 0);
DBG_ASSERT(full_h_iRow[i] < n_full_x);
DBG_ASSERT(full_h_jCol[i] >= 0);
DBG_ASSERT(full_h_jCol[i] < n_full_x);
full_h_iRow[i] += 1;
full_h_jCol[i] += 1;
}
}
#if IPOPT_CHECKLEVEL > 0
else
{
for( Index i = 0; i < nz_full_h_; i++ )
{
DBG_ASSERT(full_h_iRow[i] > 0);
DBG_ASSERT(full_h_iRow[i] <= n_full_x);
DBG_ASSERT(full_h_jCol[i] > 0);
DBG_ASSERT(full_h_jCol[i] <= n_full_x);
}
}
#endif
current_nz = 0;
if( IsValid(P_x_full_x_) )
{
h_idx_map_ = new Index[nz_full_h_];
const Index* h_pos = P_x_full_x_->CompressedPosIndices();
for( Index i = 0; i < nz_full_h_; i++ )
{
const Index& h_row = h_pos[full_h_iRow[i] - 1];
const Index& h_col = h_pos[full_h_jCol[i] - 1];
if( h_row != -1 && h_col != -1 )
{
h_idx_map_[current_nz] = i;
h_iRow[current_nz] = h_row + 1;
h_jCol[current_nz] = h_col + 1;
current_nz++;
}
}
}
else
{
h_idx_map_ = NULL;
for( Index i = 0; i < nz_full_h_; i++ )
{
const Index& h_row = full_h_iRow[i] - 1;
const Index& h_col = full_h_jCol[i] - 1;
h_iRow[i] = h_row + 1;
h_jCol[i] = h_col + 1;
current_nz++;
}
current_nz = nz_full_h_;
}
nz_h_ = current_nz;
Hess_lagrangian_space_ = new SymTMatrixSpace(n_x_var, nz_h_, h_iRow, h_jCol);
delete[] full_h_iRow;
full_h_iRow = NULL;
delete[] full_h_jCol;
full_h_jCol = NULL;
delete[] h_iRow;
h_iRow = NULL;
delete[] h_jCol;
h_jCol = NULL;
}
else
{
nz_h_ = 0;
Hess_lagrangian_space_ = NULL;
}
}
x_space = x_space_;
c_space = c_space_;
d_space = d_space_;
x_l_space = x_l_space_;
px_l_space = px_l_space_;
x_u_space = x_u_space_;
px_u_space = px_u_space_;
d_l_space = d_l_space_;
pd_l_space = pd_l_space_;
d_u_space = d_u_space_;
pd_u_space = pd_u_space_;
Jac_c_space = Jac_c_space_;
Jac_d_space = Jac_d_space_;
Hess_lagrangian_space = Hess_lagrangian_space_;
if( IsValid(jnlst_) )
{
jnlst_->Printf(J_ITERSUMMARY, J_STATISTICS, "Number of nonzeros in equality constraint Jacobian...:%9" IPOPT_INDEX_FORMAT "\n",
nz_jac_c_);
jnlst_->Printf(J_ITERSUMMARY, J_STATISTICS, "Number of nonzeros in inequality constraint Jacobian.:%9" IPOPT_INDEX_FORMAT "\n",
nz_jac_d_);
jnlst_->Printf(J_ITERSUMMARY, J_STATISTICS, "Number of nonzeros in Lagrangian Hessian.............:%9" IPOPT_INDEX_FORMAT "\n\n",
nz_h_);
}
return true;
}
bool TNLPAdapter::GetBoundsInformation(
const Matrix& Px_L,
Vector& x_L,
const Matrix& Px_U,
Vector& x_U,
const Matrix& Pd_L,
Vector& d_L,
const Matrix& Pd_U,
Vector& d_U
)
{
Number* x_l = new Number[n_full_x_];
Number* x_u = new Number[n_full_x_];
Number* g_l = new Number[n_full_g_];
Number* g_u = new Number[n_full_g_];
bool retval = tnlp_->get_bounds_info(n_full_x_, x_l, x_u, n_full_g_, g_l, g_u);
ASSERT_EXCEPTION(retval, INVALID_TNLP, "get_bounds_info returned false in GetBoundsInformation");
if( fixed_variable_treatment_ == MAKE_PARAMETER || fixed_variable_treatment_ == MAKE_PARAMETER_NODUAL )
{
for( Index i = 0; i < n_x_fixed_; i++ )
{
DBG_ASSERT(x_l[x_fixed_map_[i]] == x_u[x_fixed_map_[i]]);
full_x_[x_fixed_map_[i]] = x_l[x_fixed_map_[i]];
}
}
else if( fixed_variable_treatment_ == RELAX_BOUNDS )
{
const Number bound_relax = Max(Number(1e-8), bound_relax_factor_);
for( Index i = 0; i < n_x_fixed_; i++ )
{
if( x_l[i] == x_u[i] )
{
x_l[i] -= bound_relax * Max(Number(1.), std::abs(x_l[i]));
x_u[i] += bound_relax * Max(Number(1.), std::abs(x_u[i]));
}
}
}
DenseVector* dx_L = static_cast<DenseVector*>(&x_L);
DBG_ASSERT(dynamic_cast<DenseVector*>(&x_L));
Number* values = dx_L->Values();
const ExpansionMatrix* em_Px_L = static_cast<const ExpansionMatrix*>(&Px_L);
DBG_ASSERT(dynamic_cast<const ExpansionMatrix*>(&Px_L));
if( IsValid(P_x_full_x_) )
{
for( Index i = 0; i < Px_L.NCols(); i++ )
{
const Index& ipopt_idx = em_Px_L->ExpandedPosIndices()[i];
const Index& full_idx = P_x_full_x_->ExpandedPosIndices()[ipopt_idx];
const Number& lower_bound = x_l[full_idx];
values[i] = lower_bound;
}
}
else
{
for( Index i = 0; i < Px_L.NCols(); i++ )
{
const Index& ipopt_idx = em_Px_L->ExpandedPosIndices()[i];
const Number& lower_bound = x_l[ipopt_idx];
values[i] = lower_bound;
}
}
DenseVector* dx_U = static_cast<DenseVector*>(&x_U);
DBG_ASSERT(dynamic_cast<DenseVector*>(&x_U));
values = dx_U->Values();
const ExpansionMatrix* em_Px_U = static_cast<const ExpansionMatrix*>(&Px_U);
DBG_ASSERT(dynamic_cast<const ExpansionMatrix*>(&Px_U));
if( IsValid(P_x_full_x_) )
{
for( Index i = 0; i < Px_U.NCols(); i++ )
{
const Index& ipopt_idx = em_Px_U->ExpandedPosIndices()[i];
const Index& full_idx = P_x_full_x_->ExpandedPosIndices()[ipopt_idx];
const Number& upper_bound = x_u[full_idx];
values[i] = upper_bound;
}
}
else
{
for( Index i = 0; i < Px_U.NCols(); i++ )
{
const Index& ipopt_idx = em_Px_U->ExpandedPosIndices()[i];
const Number& upper_bound = x_u[ipopt_idx];
values[i] = upper_bound;
}
}
for( Index i = 0; i < P_c_g_->NCols(); i++ )
{
Index full_idx = P_c_g_->ExpandedPosIndices()[i];
Number rhs = g_l[full_idx];
c_rhs_[i] = rhs;
}
if( fixed_variable_treatment_ == MAKE_CONSTRAINT )
{
Index n_c_no_fixed = P_c_g_->NCols();
for( Index i = 0; i < n_x_fixed_; i++ )
{
DBG_ASSERT(x_l[x_fixed_map_[i]] == x_u[x_fixed_map_[i]]);
c_rhs_[n_c_no_fixed + i] = x_l[x_fixed_map_[i]];
}
}
DenseVector* dd_L = static_cast<DenseVector*>(&d_L);
DBG_ASSERT(dynamic_cast<DenseVector*>(&d_L));
values = dd_L->Values();
const ExpansionMatrix* em_Pd_L = static_cast<const ExpansionMatrix*>(&Pd_L);
DBG_ASSERT(dynamic_cast<const ExpansionMatrix*>(&Pd_L));
for( Index i = 0; i < Pd_L.NCols(); i++ )
{
Index d_exp_idx = em_Pd_L->ExpandedPosIndices()[i];
Index full_idx = P_d_g_->ExpandedPosIndices()[d_exp_idx];
Number lower_bound = g_l[full_idx];
values[i] = lower_bound;
}
DenseVector* dd_U = static_cast<DenseVector*>(&d_U);
DBG_ASSERT(dynamic_cast<DenseVector*>(&d_U));
values = dd_U->Values();
const ExpansionMatrix* em_Pd_U = static_cast<const ExpansionMatrix*>(&Pd_U);
DBG_ASSERT(dynamic_cast<const ExpansionMatrix*>(&Pd_U));
for( Index i = 0; i < Pd_U.NCols(); i++ )
{
Index d_exp_idx = em_Pd_U->ExpandedPosIndices()[i];
Index full_idx = P_d_g_->ExpandedPosIndices()[d_exp_idx];
Number upper_bound = g_u[full_idx];
values[i] = upper_bound;
}
if( jacobian_approximation_ != JAC_EXACT || gradient_approximation_ != OBJGRAD_EXACT )
{
delete[] findiff_x_l_;
delete[] findiff_x_u_;
findiff_x_l_ = x_l;
findiff_x_u_ = x_u;
x_l = NULL;
x_u = NULL;
}
delete[] x_l;
x_l = NULL;
delete[] x_u;
x_u = NULL;
delete[] g_l;
g_l = NULL;
delete[] g_u;
g_u = NULL;
return true;
}
bool TNLPAdapter::GetStartingPoint(
SmartPtr<Vector> x,
bool need_x,
SmartPtr<Vector> y_c,
bool need_y_c,
SmartPtr<Vector> y_d,
bool need_y_d,
SmartPtr<Vector> z_L,
bool need_z_L,
SmartPtr<Vector> z_U,
bool need_z_U
)
{
Number* full_x = new Number[n_full_x_];
Number* full_z_l = new Number[n_full_x_];
Number* full_z_u = new Number[n_full_x_];
Number* full_lambda = new Number[n_full_g_];
bool init_x = need_x;
bool init_z = need_z_L || need_z_U || (fixed_variable_treatment_ == MAKE_CONSTRAINT && n_x_fixed_ > 0 && need_y_c);
bool init_lambda = need_y_c || need_y_d;
bool retvalue = tnlp_->get_starting_point(n_full_x_, init_x, full_x, init_z, full_z_l, full_z_u, n_full_g_,
init_lambda, full_lambda);
if( !retvalue )
{
delete[] full_x;
delete[] full_z_l;
delete[] full_z_u;
delete[] full_lambda;
return false;
}
if( need_x )
{
DenseVector* dx = static_cast<DenseVector*>(GetRawPtr(x));
DBG_ASSERT(dynamic_cast<DenseVector*>(GetRawPtr(x)));
Number* values = dx->Values();
const Index& n_x_var = x->Dim();
if( IsValid(P_x_full_x_) )
{
const Index* x_pos = P_x_full_x_->ExpandedPosIndices();
for( Index i = 0; i < n_x_var; i++ )
{
values[i] = full_x[x_pos[i]];
}
}
else
{
IpBlasCopy(n_x_var, full_x, 1, values, 1);
}
}
if( need_y_c )
{
DenseVector* dy_c = static_cast<DenseVector*>(GetRawPtr(y_c));
DBG_ASSERT(dynamic_cast<DenseVector*>(GetRawPtr(y_c)));
Number* values = dy_c->Values();
const Index* y_c_pos = P_c_g_->ExpandedPosIndices();
for( Index i = 0; i < P_c_g_->NCols(); i++ )
{
values[i] = full_lambda[y_c_pos[i]];
}
if( fixed_variable_treatment_ == MAKE_CONSTRAINT )
{
for( Index i = 0; i < n_x_fixed_; i++ )
{
values[P_c_g_->NCols() + i] = full_z_u[x_fixed_map_[i]] - full_z_l[x_fixed_map_[i]];
}
}
}
if( need_y_d )
{
DenseVector* dy_d = static_cast<DenseVector*>(GetRawPtr(y_d));
DBG_ASSERT(dynamic_cast<DenseVector*>(GetRawPtr(y_d)));
Number* values = dy_d->Values();
const Index* y_d_pos = P_d_g_->ExpandedPosIndices();
for( Index i = 0; i < y_d->Dim(); i++ )
{
values[i] = full_lambda[y_d_pos[i]];
}
}
if( need_z_L )
{
DenseVector* dz_l = static_cast<DenseVector*>(GetRawPtr(z_L));
DBG_ASSERT(dynamic_cast<DenseVector*>(GetRawPtr(z_L)));
Number* values = dz_l->Values();
const Index& n_z_l = z_L->Dim();
const Index* z_l_pos = P_x_x_L_->ExpandedPosIndices();
if( IsValid(P_x_full_x_) )
{
const Index* x_pos = P_x_full_x_->ExpandedPosIndices();
for( Index i = 0; i < n_z_l; i++ )
{
Index idx = z_l_pos[i]; idx = x_pos[idx]; values[i] = full_z_l[idx];
}
}
else
{
for( Index i = 0; i < n_z_l; i++ )
{
Index idx = z_l_pos[i]; values[i] = full_z_l[idx];
}
}
}
if( need_z_U )
{
DenseVector* dz_u = static_cast<DenseVector*>(GetRawPtr(z_U));
DBG_ASSERT(dynamic_cast<DenseVector*>(GetRawPtr(z_U)));
Number* values = dz_u->Values();
const Index* z_u_pos = P_x_x_U_->ExpandedPosIndices();
if( IsValid(P_x_full_x_) )
{
const Index* x_pos = P_x_full_x_->ExpandedPosIndices();
for( Index i = 0; i < z_U->Dim(); i++ )
{
Index idx = z_u_pos[i]; idx = x_pos[idx]; values[i] = full_z_u[idx];
}
}
else
{
for( Index i = 0; i < z_U->Dim(); i++ )
{
Index idx = z_u_pos[i]; values[i] = full_z_u[idx];
}
}
}
delete[] full_x;
full_x = NULL;
delete[] full_z_l;
full_z_l = NULL;
delete[] full_z_u;
full_z_u = NULL;
delete[] full_lambda;
full_lambda = NULL;
return true;
}
bool TNLPAdapter::GetWarmStartIterate(
IteratesVector& warm_start_iterate
)
{
return tnlp_->get_warm_start_iterate(warm_start_iterate);
}
bool TNLPAdapter::Eval_f(
const Vector& x,
Number& f
)
{
bool new_x = false;
if( update_local_x(x) )
{
new_x = true;
}
return tnlp_->eval_f(n_full_x_, full_x_, new_x, f);
}
bool TNLPAdapter::Eval_grad_f(
const Vector& x,
Vector& g_f
)
{
bool retvalue = false;
bool new_x = false;
if( update_local_x(x) )
{
new_x = true;
}
DenseVector* dg_f = static_cast<DenseVector*>(&g_f);
DBG_ASSERT(dynamic_cast<DenseVector*>(&g_f));
Number* values = dg_f->Values();
if( gradient_approximation_ == OBJGRAD_EXACT )
{
if( IsValid(P_x_full_x_) )
{
Number* full_grad_f = new Number[n_full_x_];
if( tnlp_->eval_grad_f(n_full_x_, full_x_, new_x, full_grad_f) )
{
const Index* x_pos = P_x_full_x_->ExpandedPosIndices();
for( Index i = 0; i < g_f.Dim(); i++ )
{
values[i] = full_grad_f[x_pos[i]];
}
retvalue = true;
}
delete[] full_grad_f;
}
else
{
retvalue = tnlp_->eval_grad_f(n_full_x_, full_x_, new_x, values);
}
}
else
{
Number f;
retvalue = tnlp_->eval_f(n_full_x_, full_x_, new_x, f);
if( retvalue )
{
Number* full_x_pert = new Number[n_full_x_];
IpBlasCopy(n_full_x_, full_x_, 1, full_x_pert, 1);
const Index* x_pos = NULL;
if( IsValid(P_x_full_x_) )
{
x_pos = P_x_full_x_->ExpandedPosIndices();
}
for( Index i = 0; i < g_f.Dim(); i++ )
{
Index ivar = x_pos != NULL ? x_pos[i] : i;
if( findiff_x_l_[ivar] < findiff_x_u_[ivar] )
{
const Number xorig = full_x_pert[ivar];
Number this_perturbation = findiff_perturbation_ * Max(Number(1.), std::abs(full_x_[ivar]));
full_x_pert[ivar] += this_perturbation;
if( full_x_pert[ivar] > findiff_x_u_[ivar] )
{
this_perturbation = -this_perturbation;
full_x_pert[ivar] = xorig + this_perturbation;
}
Number f_pert;
retvalue = tnlp_->eval_f(n_full_x_, full_x_pert, true, f_pert);
if( !retvalue )
{
break;
}
values[i] = (f_pert - f) / this_perturbation;
full_x_pert[ivar] = xorig;
}
}
delete[] full_x_pert;
}
}
return retvalue;
}
bool TNLPAdapter::Eval_c(
const Vector& x,
Vector& c
)
{
bool new_x = false;
if( update_local_x(x) )
{
new_x = true;
}
if( internal_eval_g(new_x) )
{
DenseVector* dc = static_cast<DenseVector*>(&c);
DBG_ASSERT(dynamic_cast<DenseVector*>(&c));
Number* values = dc->Values();
const Index* c_pos = P_c_g_->ExpandedPosIndices();
Index n_c_no_fixed = P_c_g_->NCols();
for( Index i = 0; i < n_c_no_fixed; i++ )
{
values[i] = full_g_[c_pos[i]];
values[i] -= c_rhs_[i];
}
if( fixed_variable_treatment_ == MAKE_CONSTRAINT )
{
for( Index i = 0; i < n_x_fixed_; i++ )
{
values[n_c_no_fixed + i] = full_x_[x_fixed_map_[i]] - c_rhs_[n_c_no_fixed + i];
}
}
return true;
}
return false;
}
bool TNLPAdapter::Eval_jac_c(
const Vector& x,
Matrix& jac_c
)
{
bool new_x = false;
if( update_local_x(x) )
{
new_x = true;
}
if( internal_eval_jac_g(new_x) )
{
GenTMatrix* gt_jac_c = static_cast<GenTMatrix*>(&jac_c);
DBG_ASSERT(dynamic_cast<GenTMatrix*>(&jac_c));
Number* values = gt_jac_c->Values();
for( Index i = 0; i < nz_jac_c_no_extra_; i++ )
{
values[i] = jac_g_[jac_idx_map_[i]];
}
if( fixed_variable_treatment_ == MAKE_CONSTRAINT )
{
const Number one = 1.;
IpBlasCopy(n_x_fixed_, &one, 0, &values[nz_jac_c_no_extra_], 1);
}
return true;
}
return false;
}
bool TNLPAdapter::Eval_d(
const Vector& x,
Vector& d
)
{
bool new_x = false;
if( update_local_x(x) )
{
new_x = true;
}
DenseVector* dd = static_cast<DenseVector*>(&d);
DBG_ASSERT(dynamic_cast<DenseVector*>(&d));
Number* values = dd->Values();
if( internal_eval_g(new_x) )
{
const Index* d_pos = P_d_g_->ExpandedPosIndices();
for( Index i = 0; i < d.Dim(); i++ )
{
values[i] = full_g_[d_pos[i]];
}
return true;
}
return false;
}
bool TNLPAdapter::Eval_jac_d(
const Vector& x,
Matrix& jac_d
)
{
bool new_x = false;
if( update_local_x(x) )
{
new_x = true;
}
if( internal_eval_jac_g(new_x) )
{
GenTMatrix* gt_jac_d = static_cast<GenTMatrix*>(&jac_d);
DBG_ASSERT(dynamic_cast<GenTMatrix*>(&jac_d));
Number* values = gt_jac_d->Values();
for( Index i = 0; i < nz_jac_d_; i++ )
{
values[i] = jac_g_[jac_idx_map_[nz_jac_c_no_extra_ + i]];
}
return true;
}
return false;
}
bool TNLPAdapter::Eval_h(
const Vector& x,
Number obj_factor,
const Vector& yc,
const Vector& yd,
SymMatrix& h
)
{
if( obj_factor == 0. && yc.Asum() == 0. && yd.Asum() == 0. )
{
SymTMatrix* st_h = static_cast<SymTMatrix*>(&h);
DBG_ASSERT(dynamic_cast<SymTMatrix*>(&h));
Number* values = st_h->Values();
for( Index i = 0; i < nz_h_; i++ )
{
values[i] = 0.;
}
return true;
}
bool retval = false;
bool new_x = false;
if( update_local_x(x) )
{
new_x = true;
}
bool new_y = false;
if( update_local_lambda(yc, yd) )
{
new_y = true;
}
SymTMatrix* st_h = static_cast<SymTMatrix*>(&h);
DBG_ASSERT(dynamic_cast<SymTMatrix*>(&h));
Number* values = st_h->Values();
if( h_idx_map_ )
{
Number* full_h = new Number[nz_full_h_];
if( tnlp_->eval_h(n_full_x_, full_x_, new_x, obj_factor, n_full_g_, full_lambda_, new_y, nz_full_h_, NULL, NULL,
full_h) )
{
for( Index i = 0; i < nz_h_; i++ )
{
values[i] = full_h[h_idx_map_[i]];
}
retval = true;
}
delete[] full_h;
}
else
{
retval = tnlp_->eval_h(n_full_x_, full_x_, new_x, obj_factor, n_full_g_, full_lambda_, new_y, nz_full_h_, NULL,
NULL, values);
}
return retval;
}
void TNLPAdapter::GetScalingParameters(
const SmartPtr<const VectorSpace> x_space,
const SmartPtr<const VectorSpace> c_space,
const SmartPtr<const VectorSpace> d_space,
Number& obj_scaling,
SmartPtr<Vector>& x_scaling,
SmartPtr<Vector>& c_scaling,
SmartPtr<Vector>& d_scaling
) const
{
x_scaling = x_space->MakeNew();
c_scaling = c_space->MakeNew();
d_scaling = d_space->MakeNew();
DBG_ASSERT(c_scaling->Dim() + d_scaling->Dim() == n_full_g_ + (fixed_variable_treatment_ == MAKE_CONSTRAINT ? n_x_fixed_ : 0));
DenseVector* dx = static_cast<DenseVector*>(GetRawPtr(x_scaling));
DBG_ASSERT(dynamic_cast<DenseVector*>(GetRawPtr(x_scaling)));
DenseVector* dc = static_cast<DenseVector*>(GetRawPtr(c_scaling));
DBG_ASSERT(dynamic_cast<DenseVector*>(GetRawPtr(c_scaling)));
DenseVector* dd = static_cast<DenseVector*>(GetRawPtr(d_scaling));
DBG_ASSERT(dynamic_cast<DenseVector*>(GetRawPtr(d_scaling)));
Number* dx_values = dx->Values();
Number* dc_values = dc->Values();
Number* dd_values = dd->Values();
Number* full_g_scaling = new Number[n_full_g_];
bool use_x_scaling = true;
bool use_g_scaling = true;
if( IsValid(P_x_full_x_) )
{
Number* full_x_scaling = new Number[n_full_x_];
bool retval = tnlp_->get_scaling_parameters(obj_scaling, use_x_scaling, n_full_x_, full_x_scaling, use_g_scaling,
n_full_g_, full_g_scaling);
if( !retval )
{
delete[] full_x_scaling;
jnlst_->Printf(J_ERROR, J_INITIALIZATION,
"Option nlp_scaling_method selected as user-scaling, but no user-scaling available, or it cannot be computed.\n");
THROW_EXCEPTION(OPTION_INVALID, "User scaling chosen, but get_scaling_parameters returned false.");
}
if( use_x_scaling )
{
const Index* x_pos = P_x_full_x_->ExpandedPosIndices();
for( Index i = 0; i < dx->Dim(); i++ )
{
dx_values[i] = full_x_scaling[x_pos[i]];
}
}
delete[] full_x_scaling;
}
else
{
bool retval = tnlp_->get_scaling_parameters(obj_scaling, use_x_scaling, n_full_x_, dx_values, use_g_scaling,
n_full_g_, full_g_scaling);
if( !retval )
{
jnlst_->Printf(J_ERROR, J_INITIALIZATION,
"Option nlp_scaling_method selected as user-scaling, but no user-scaling available, or it cannot be computed.\n");
THROW_EXCEPTION(OPTION_INVALID, "User scaling chosen, but get_scaling_parameters returned false.");
}
}
if( !use_x_scaling )
{
x_scaling = NULL;
}
if( use_g_scaling )
{
const Index* c_pos = P_c_g_->ExpandedPosIndices();
for( Index i = 0; i < P_c_g_->NCols(); i++ )
{
dc_values[i] = full_g_scaling[c_pos[i]];
}
if( fixed_variable_treatment_ == MAKE_CONSTRAINT )
{
const Number one = 1.;
IpBlasCopy(n_x_fixed_, &one, 0, &dc_values[P_c_g_->NCols()], 1);
}
const Index* d_pos = P_d_g_->ExpandedPosIndices();
for( Index i = 0; i < dd->Dim(); i++ )
{
dd_values[i] = full_g_scaling[d_pos[i]];
}
}
else
{
c_scaling = NULL;
d_scaling = NULL;
}
delete[] full_g_scaling;
}
void TNLPAdapter::FinalizeSolution(
SolverReturn status,
const Vector& x,
const Vector& z_L,
const Vector& z_U,
const Vector& c,
const Vector& d,
const Vector& y_c,
const Vector& y_d,
Number obj_value,
const IpoptData* ip_data,
IpoptCalculatedQuantities* ip_cq
)
{
DBG_START_METH("TNLPAdapter::FinalizeSolution", dbg_verbosity);
update_local_x(x);
update_local_lambda(y_c, y_d);
ResortX(x, full_x_);
StringMetaDataMapType var_string_md;
IntegerMetaDataMapType var_integer_md;
NumericMetaDataMapType var_numeric_md;
StringMetaDataMapType con_string_md;
IntegerMetaDataMapType con_integer_md;
NumericMetaDataMapType con_numeric_md;
SmartPtr<const DenseVectorSpace> x_space = dynamic_cast<const DenseVectorSpace*>(GetRawPtr(x.OwnerSpace()));
const NumericMetaDataMapType x_meta = x_space->GetNumericMetaData();
NumericMetaDataMapType::const_iterator x_meta_iter;
for( x_meta_iter = x_meta.begin(); x_meta_iter != x_meta.end(); ++x_meta_iter )
{
if( (Index) x_meta_iter->second.size() == x.Dim() )
{
std::vector<Number> new_meta_data;
new_meta_data.resize(n_full_x_);
SmartPtr<DenseVector> x_meta_vector = x_space->MakeNewDenseVector();
x_meta_vector->SetValues(&(x_meta_iter->second)[0]);
ResortX(*x_meta_vector, &new_meta_data[0]);
var_numeric_md[x_meta_iter->first] = new_meta_data;
}
}
ResortG(y_c, y_d, full_lambda_);
SmartPtr<const DenseVectorSpace> y_c_space = dynamic_cast<const DenseVectorSpace*>(GetRawPtr(y_c.OwnerSpace()));
SmartPtr<const DenseVectorSpace> y_d_space = dynamic_cast<const DenseVectorSpace*>(GetRawPtr(y_d.OwnerSpace()));
const NumericMetaDataMapType y_c_meta = y_c_space->GetNumericMetaData();
const NumericMetaDataMapType y_d_meta = y_d_space->GetNumericMetaData();
NumericMetaDataMapType::const_iterator y_c_meta_iter;
for( y_c_meta_iter = y_c_meta.begin(); y_c_meta_iter != y_c_meta.end(); ++y_c_meta_iter )
{
if( (Index) y_c_meta_iter->second.size() == y_c.Dim() )
{
if( y_d_space->HasNumericMetaData(y_c_meta_iter->first.c_str()) && ((Index) (y_d_meta.find(y_c_meta_iter->first)->second).size()) == y_d.Dim() ) {
std::vector<Number> y_d_second = y_d_space->GetNumericMetaData(y_c_meta_iter->first);
std::vector<Number> new_g_meta_data;
new_g_meta_data.resize(n_full_g_);
SmartPtr<DenseVector> y_c_meta_vector = y_c_space->MakeNewDenseVector();
SmartPtr<DenseVector> y_d_meta_vector = y_d_space->MakeNewDenseVector();
y_c_meta_vector->SetValues(&(y_c_meta_iter->second)[0]);
if( y_d_second.size() > 0 )
{
y_d_meta_vector->SetValues(&y_d_second[0]);
}
ResortG(*y_c_meta_vector, *y_d_meta_vector, &new_g_meta_data[0]);
con_numeric_md[y_c_meta_iter->first] = new_g_meta_data;
}
}
}
Number* full_g = new Number[n_full_g_];
if( c.Dim() + d.Dim() < n_full_g_ )
{
const Number zero = 0.;
IpBlasCopy(n_full_g_, &zero, 0, full_g, 1);
}
ResortG(c, d, full_g, true);
Number* full_z_L = new Number[n_full_x_];
Number* full_z_U = new Number[n_full_x_];
switch( status )
{
case SUCCESS:
case MAXITER_EXCEEDED:
case STOP_AT_TINY_STEP:
case STOP_AT_ACCEPTABLE_POINT:
case LOCAL_INFEASIBILITY:
case USER_REQUESTED_STOP:
case FEASIBLE_POINT_FOUND:
case DIVERGING_ITERATES:
case RESTORATION_FAILURE:
case ERROR_IN_STEP_COMPUTATION:
if( !ResortBoundMultipliers(x, y_c, y_d, z_L, full_z_L, z_U, full_z_U) )
{
jnlst_->Printf(J_WARNING, J_INITIALIZATION, "Failed to evaluate gradient of objective or constraints when computing bound multipliers for fixed variables.\n");
}
break;
default:
ResortBounds(z_L, full_z_L, z_U, full_z_U);
break;
}
SmartPtr<const DenseVectorSpace> z_L_space = dynamic_cast<const DenseVectorSpace*>(GetRawPtr(z_L.OwnerSpace()));
SmartPtr<const DenseVectorSpace> z_U_space = dynamic_cast<const DenseVectorSpace*>(GetRawPtr(z_U.OwnerSpace()));
const NumericMetaDataMapType z_L_meta = z_L_space->GetNumericMetaData();
const NumericMetaDataMapType z_U_meta = z_U_space->GetNumericMetaData();
NumericMetaDataMapType::const_iterator z_L_meta_iter;
for( z_L_meta_iter = z_L_meta.begin(); z_L_meta_iter != z_L_meta.end(); ++z_L_meta_iter )
{
if( (Index) z_L_meta_iter->second.size() == z_L.Dim() )
{
if( z_U_space->HasNumericMetaData(z_L_meta_iter->first.c_str())
&& (Index) z_U_meta.find(z_L_meta_iter->first.c_str())->second.size() == z_U.Dim() )
{
std::vector<Number> z_U_second = z_U_space->GetNumericMetaData(z_L_meta_iter->first);
SmartPtr<DenseVector> z_L_meta_vector = z_L_space->MakeNewDenseVector();
SmartPtr<DenseVector> z_U_meta_vector = z_U_space->MakeNewDenseVector();
z_L_meta_vector->SetValues(&(z_L_meta_iter->second)[0]);
if( z_U_second.size() > 0 )
{
z_U_meta_vector->SetValues(&z_U_second[0]);
}
std::vector<Number> new_z_L_meta_data(n_full_x_, 0.0);
std::vector<Number> new_z_U_meta_data(n_full_x_, 0.0);
ResortBounds(*z_L_meta_vector, &new_z_L_meta_data[0], *z_U_meta_vector, &new_z_U_meta_data[0]);
std::string z_L_meta_data_tag = z_L_meta_iter->first;
std::string z_U_meta_data_tag = z_L_meta_iter->first;
z_L_meta_data_tag += "_z_L";
z_U_meta_data_tag += "_z_U";
var_numeric_md[z_L_meta_data_tag] = new_z_L_meta_data;
var_numeric_md[z_U_meta_data_tag] = new_z_U_meta_data;
}
}
}
tnlp_->finalize_metadata(n_full_x_, var_string_md, var_integer_md, var_numeric_md, n_full_g_, con_string_md,
con_integer_md, con_numeric_md);
tnlp_->finalize_solution(status, n_full_x_, full_x_, full_z_L, full_z_U, n_full_g_, full_g, full_lambda_, obj_value,
ip_data, ip_cq);
delete[] full_z_L;
full_z_L = NULL;
delete[] full_z_U;
full_z_U = NULL;
delete[] full_g;
full_g = NULL;
if( c.Dim() + d.Dim() < n_full_g_ )
{
Number max_viol = 0.;
Number* x_l = new Number[n_full_x_];
Number* x_u = new Number[n_full_x_];
Number* g_l = new Number[n_full_g_];
Number* g_u = new Number[n_full_g_];
bool retval = tnlp_->get_bounds_info(n_full_x_, x_l, x_u, n_full_g_, g_l, g_u);
ASSERT_EXCEPTION(retval, INVALID_TNLP, "get_bounds_info returned false in FinalizeSolution");
for( Index i = 0; i < n_full_g_; i++ )
{
max_viol = Max(max_viol, full_g_[i] - g_u[i], g_l[i] - full_g_[i]);
}
jnlst_->Printf(J_ITERSUMMARY, J_INITIALIZATION, "Constraint violation for ALL constraints is %e.\n", max_viol);
delete[] x_l;
delete[] x_u;
delete[] g_l;
delete[] g_u;
}
}
bool TNLPAdapter::IntermediateCallBack(
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
)
{
return tnlp_->intermediate_callback(mode, iter, obj_value, inf_pr, inf_du, mu, d_norm, regularization_size, alpha_du,
alpha_pr, ls_trials, ip_data, ip_cq);
}
void TNLPAdapter::GetQuasiNewtonApproximationSpaces(
SmartPtr<VectorSpace>& approx_space,
SmartPtr<Matrix>& P_approx
)
{
Index num_nonlin_vars = tnlp_->get_number_of_nonlinear_variables();
if( num_nonlin_vars < 0 && num_linear_variables_ == 0 )
{
approx_space = NULL;
P_approx = NULL;
return;
}
Index* pos_nonlin_vars = NULL;
if( num_nonlin_vars < 0 )
{
num_nonlin_vars = n_full_x_ - num_linear_variables_;
pos_nonlin_vars = new Index[num_nonlin_vars];
Index ii = 0;
for( Index i = num_linear_variables_; i < n_full_x_; i++ )
{
pos_nonlin_vars[ii++] = i;
}
}
else if( num_nonlin_vars > 0 )
{
pos_nonlin_vars = new Index[num_nonlin_vars];
bool retval = tnlp_->get_list_of_nonlinear_variables(num_nonlin_vars, pos_nonlin_vars);
if( !retval )
{
delete[] pos_nonlin_vars;
jnlst_->Printf(J_ERROR, J_INITIALIZATION,
"TNLP's get_number_of_nonlinear_variables returns non-negative number, but get_list_of_nonlinear_variables returns false.\n");
THROW_EXCEPTION(INVALID_TNLP, "get_list_of_nonlinear_variables has not been overwritten");
}
if( index_style_ == TNLP::FORTRAN_STYLE )
{
for( Index i = 0; i < num_nonlin_vars; i++ )
{
DBG_ASSERT(pos_nonlin_vars[i] > 0);
DBG_ASSERT(pos_nonlin_vars[i] <= n_full_x_);
pos_nonlin_vars[i]--;
}
}
#if IPOPT_CHECKLEVEL > 0
else
{
for( Index i = 0; i < num_nonlin_vars; i++ )
{
DBG_ASSERT(pos_nonlin_vars[i] >= 0);
DBG_ASSERT(pos_nonlin_vars[i] < n_full_x_);
}
}
#endif
}
if( IsNull(P_x_full_x_) )
{
if( num_nonlin_vars == n_full_x_ )
{
approx_space = NULL;
P_approx = NULL;
}
else
{
SmartPtr<ExpansionMatrixSpace> ex_sp = new ExpansionMatrixSpace(n_full_x_, num_nonlin_vars, pos_nonlin_vars);
P_approx = ex_sp->MakeNew();
approx_space = new DenseVectorSpace(num_nonlin_vars);
}
}
else
{
const Index* compr_pos = P_x_full_x_->CompressedPosIndices();
Index* nonfixed_pos_nonlin_vars = new Index[num_nonlin_vars];
Index nonfixed_nonlin_vars = 0;
for( Index i = 0; i < num_nonlin_vars; i++ )
{
Index full_pos = pos_nonlin_vars[i];
Index nonfixed_pos = compr_pos[full_pos];
if( nonfixed_pos >= 0 )
{
nonfixed_pos_nonlin_vars[nonfixed_nonlin_vars] = nonfixed_pos;
nonfixed_nonlin_vars++;
}
}
const Index n_x_free = n_full_x_ - n_x_fixed_;
if( nonfixed_nonlin_vars == n_x_free )
{
approx_space = NULL;
P_approx = NULL;
}
else
{
SmartPtr<ExpansionMatrixSpace> ex_sp = new ExpansionMatrixSpace(n_x_free, nonfixed_nonlin_vars,
nonfixed_pos_nonlin_vars);
P_approx = ex_sp->MakeNew();
approx_space = new DenseVectorSpace(nonfixed_nonlin_vars);
}
delete[] nonfixed_pos_nonlin_vars;
}
delete[] pos_nonlin_vars;
}
void TNLPAdapter::ResortX(
const Vector& x,
Number* x_orig,
bool usefixedvals
)
{
const DenseVector* dx = static_cast<const DenseVector*>(&x);
DBG_ASSERT(dynamic_cast<const DenseVector*>(&x));
if( IsValid(P_x_full_x_) )
{
const Index* x_pos = P_x_full_x_->CompressedPosIndices();
if( dx->IsHomogeneous() )
{
const Number& scalar = dx->Scalar();
for( Index i = 0; i < n_full_x_; i++ )
{
Index idx = x_pos[i];
if( idx != -1 )
{
x_orig[i] = scalar;
}
else if( usefixedvals )
{
x_orig[i] = full_x_[i];
}
else
{
x_orig[i] = 0.0;
}
}
}
else
{
const Number* x_values = dx->Values();
for( Index i = 0; i < n_full_x_; i++ )
{
Index idx = x_pos[i];
if( idx != -1 )
{
x_orig[i] = x_values[idx];
}
else if( usefixedvals )
{
x_orig[i] = full_x_[i];
}
else
{
x_orig[i] = 0.0;
}
}
}
}
else
{
if( dx->IsHomogeneous() )
{
const Number& scalar = dx->Scalar();
IpBlasCopy(n_full_x_, &scalar, 0, x_orig, 1);
}
else
{
IpBlasCopy(n_full_x_, dx->Values(), 1, x_orig, 1);
}
}
}
void TNLPAdapter::ResortG(
const Vector& c,
const Vector& d,
Number* g_orig,
bool correctrhs
)
{
const DenseVector* dc = static_cast<const DenseVector*>(&c);
DBG_ASSERT(dynamic_cast<const DenseVector*>(&c));
const Index* c_pos = P_c_g_->ExpandedPosIndices();
if( dc->IsHomogeneous() )
{
Number scalar = dc->Scalar();
for( Index i = 0; i < P_c_g_->NCols(); i++ )
{
g_orig[c_pos[i]] = scalar;
if( correctrhs )
{
g_orig[c_pos[i]] += c_rhs_[i];
}
}
}
else
{
const Number* c_values = dc->Values();
for( Index i = 0; i < P_c_g_->NCols(); i++ )
{
g_orig[c_pos[i]] = c_values[i];
if( correctrhs )
{
g_orig[c_pos[i]] += c_rhs_[i];
}
}
}
const DenseVector* dd = static_cast<const DenseVector*>(&d);
DBG_ASSERT(dynamic_cast<const DenseVector*>(&d));
const Index* d_pos = P_d_g_->ExpandedPosIndices();
if( dd->IsHomogeneous() )
{
Number scalar = dd->Scalar();
for( Index i = 0; i < d.Dim(); i++ )
{
g_orig[d_pos[i]] = scalar;
}
}
else
{
const Number* d_values = dd->Values();
for( Index i = 0; i < d.Dim(); i++ )
{
g_orig[d_pos[i]] = d_values[i];
}
}
}
void TNLPAdapter::ResortBounds(
const Vector& x_L,
Number* x_L_orig,
const Vector& x_U,
Number* x_U_orig
)
{
if( x_L_orig )
{
const DenseVector* dx_L = static_cast<const DenseVector*>(&x_L);
DBG_ASSERT(dynamic_cast<const DenseVector*>(&x_L));
const Index* bnds_pos_not_fixed = P_x_x_L_->ExpandedPosIndices();
const Index& n_xL = x_L.Dim();
if( n_xL < n_full_x_ )
{
memset(x_L_orig, 0, n_full_x_ * sizeof(Number));
}
if( IsValid(P_x_full_x_) )
{
const Index* bnds_pos_full = P_x_full_x_->ExpandedPosIndices();
if( dx_L->IsHomogeneous() )
{
Number scalar = dx_L->Scalar();
for( Index i = 0; i < n_xL; i++ )
{
Index idx = bnds_pos_not_fixed[i];
idx = bnds_pos_full[idx];
x_L_orig[idx] = scalar;
}
}
else
{
const Number* x_L_values = dx_L->Values();
for( Index i = 0; i < n_xL; i++ )
{
Index idx = bnds_pos_not_fixed[i];
idx = bnds_pos_full[idx];
x_L_orig[idx] = x_L_values[i];
}
}
}
else
{
if( dx_L->IsHomogeneous() )
{
Number scalar = dx_L->Scalar();
for( Index i = 0; i < n_xL; i++ )
{
Index idx = bnds_pos_not_fixed[i];
x_L_orig[idx] = scalar;
}
}
else
{
const Number* x_L_values = dx_L->Values();
for( Index i = 0; i < n_xL; i++ )
{
Index idx = bnds_pos_not_fixed[i];
x_L_orig[idx] = x_L_values[i];
}
}
}
}
if( x_U_orig )
{
const DenseVector* dx_U = static_cast<const DenseVector*>(&x_U);
DBG_ASSERT(dynamic_cast<const DenseVector*>(&x_U));
if( x_U.Dim() < n_full_x_ )
{
memset(x_U_orig, 0, n_full_x_ * sizeof(Number));
}
const Index* bnds_pos_not_fixed = P_x_x_U_->ExpandedPosIndices();
if( IsValid(P_x_full_x_) )
{
const Index* bnds_pos_full = P_x_full_x_->ExpandedPosIndices();
if( dx_U->IsHomogeneous() )
{
Number scalar = dx_U->Scalar();
for( Index i = 0; i < x_U.Dim(); i++ )
{
Index idx = bnds_pos_not_fixed[i];
idx = bnds_pos_full[idx];
x_U_orig[idx] = scalar;
}
}
else
{
const Number* x_U_values = dx_U->Values();
for( Index i = 0; i < x_U.Dim(); i++ )
{
Index idx = bnds_pos_not_fixed[i];
idx = bnds_pos_full[idx];
x_U_orig[idx] = x_U_values[i];
}
}
}
else
{
if( dx_U->IsHomogeneous() )
{
Number scalar = dx_U->Scalar();
for( Index i = 0; i < x_U.Dim(); i++ )
{
Index idx = bnds_pos_not_fixed[i];
x_U_orig[idx] = scalar;
}
}
else
{
const Number* x_U_values = dx_U->Values();
for( Index i = 0; i < x_U.Dim(); i++ )
{
Index idx = bnds_pos_not_fixed[i];
x_U_orig[idx] = x_U_values[i];
}
}
}
}
}
bool TNLPAdapter::ResortBoundMultipliers(
const Vector& x,
const Vector& y_c,
const Vector& y_d,
const Vector& z_L,
Number* z_L_orig,
const Vector& z_U,
Number* z_U_orig
)
{
ResortBounds(z_L, z_L_orig, z_U, z_U_orig);
if( n_x_fixed_ == 0 )
{
return true;
}
if( fixed_variable_treatment_ == MAKE_CONSTRAINT )
{
const DenseVector* dy_c = static_cast<const DenseVector*>(&y_c);
DBG_ASSERT(dynamic_cast<const DenseVector*>(&y_c));
Index n_c_no_fixed = y_c.Dim() - n_x_fixed_;
if( !dy_c->IsHomogeneous() )
{
const Number* values = dy_c->Values();
for( Index i = 0; i < n_x_fixed_; i++ )
{
if( z_L_orig != NULL )
{
z_L_orig[x_fixed_map_[i]] = Max(Number(0.), -values[n_c_no_fixed + i]);
}
if( z_U_orig != NULL )
{
z_U_orig[x_fixed_map_[i]] = Max(Number(0.), values[n_c_no_fixed + i]);
}
}
}
else
{
Number value = dy_c->Scalar();
for( Index i = 0; i < n_x_fixed_; i++ )
{
if( z_L_orig != NULL )
{
z_L_orig[x_fixed_map_[i]] = Max(Number(0.), -value);
}
if( z_U_orig != NULL )
{
z_U_orig[x_fixed_map_[i]] = Max(Number(0.), value);
}
}
}
}
if( fixed_variable_treatment_ == MAKE_PARAMETER )
{
Number* mult = new Number[n_full_x_];
memset(mult, 0, sizeof(Number) * n_full_x_);
bool new_x = update_local_x(x);
if( !tnlp_->eval_grad_f(n_full_x_, full_x_, new_x, mult) )
{
delete[] mult;
return false;
}
if( !jac_fixed_idx_map_.empty() )
{
if( !internal_eval_jac_g(false) )
{
delete[] mult;
return false;
}
DBG_ASSERT(dynamic_cast<const DenseVector*>(&y_c));
DBG_ASSERT(dynamic_cast<const DenseVector*>(&y_d));
const DenseVector* dy_c = static_cast<const DenseVector*>(&y_c);
const DenseVector* dy_d = static_cast<const DenseVector*>(&y_d);
const Index* c_row_pos = P_c_g_->CompressedPosIndices();
const Index* d_row_pos = P_d_g_->CompressedPosIndices();
for( size_t i = 0; i < jac_fixed_idx_map_.size(); i++ )
{
Index row = jac_fixed_iRow_[i] - 1;
Index col = jac_fixed_jCol_[i] - 1;
Number val = jac_g_[jac_fixed_idx_map_[i]];
DBG_ASSERT(row >= 0);
DBG_ASSERT(row < n_full_g_);
DBG_ASSERT(col >= 0);
DBG_ASSERT(col < n_full_x_);
Number lambda = 0.0;
if( c_row_pos[row] != -1 )
{
if( dy_c->IsHomogeneous() )
{
lambda = dy_c->Scalar();
}
else
{
lambda = dy_c->Values()[c_row_pos[row]];
}
}
else if( d_row_pos[row] != -1 )
{
if( dy_d->IsHomogeneous() )
{
lambda = dy_d->Scalar();
}
else
{
lambda = dy_d->Values()[d_row_pos[row]];
}
}
mult[col] += lambda * val;
}
}
for( Index i = 0; i < n_x_fixed_; ++i )
{
Index xidx = x_fixed_map_[i];
if( z_L_orig != NULL )
{
z_L_orig[xidx] = Max(Number(0.0), mult[xidx]);
}
if( z_U_orig != NULL )
{
z_U_orig[xidx] = Max(Number(0.0), -mult[xidx]);
}
}
delete[] mult;
}
return true;
}
bool TNLPAdapter::update_local_x(
const Vector& x
)
{
if( x.GetTag() == x_tag_for_iterates_ )
{
return false;
}
ResortX(x, full_x_);
x_tag_for_iterates_ = x.GetTag();
return true;
}
bool TNLPAdapter::update_local_lambda(
const Vector& y_c,
const Vector& y_d
)
{
if( y_c.GetTag() == y_c_tag_for_iterates_ && y_d.GetTag() == y_d_tag_for_iterates_ )
{
return false;
}
ResortG(y_c, y_d, full_lambda_);
y_c_tag_for_iterates_ = y_c.GetTag();
y_d_tag_for_iterates_ = y_d.GetTag();
return true;
}
bool TNLPAdapter::internal_eval_g(
bool new_x
)
{
if( x_tag_for_g_ == x_tag_for_iterates_ )
{
return true;
}
x_tag_for_g_ = x_tag_for_iterates_;
bool retval = tnlp_->eval_g(n_full_x_, full_x_, new_x, n_full_g_, full_g_);
if( !retval )
{
x_tag_for_jac_g_ = 0;
}
return retval;
}
bool TNLPAdapter::internal_eval_jac_g(
bool new_x
)
{
if( x_tag_for_jac_g_ == x_tag_for_iterates_ )
{
return true;
}
x_tag_for_jac_g_ = x_tag_for_iterates_;
bool retval;
if( jacobian_approximation_ == JAC_EXACT )
{
retval = tnlp_->eval_jac_g(n_full_x_, full_x_, new_x, n_full_g_, nz_full_jac_g_, NULL, NULL, jac_g_);
}
else
{
retval = internal_eval_g(new_x);
if( retval )
{
Number* full_g_pert = new Number[n_full_g_];
Number* full_x_pert = new Number[n_full_x_];
IpBlasCopy(n_full_x_, full_x_, 1, full_x_pert, 1);
for( Index ivar = 0; ivar < n_full_x_; ivar++ )
{
if( findiff_x_l_[ivar] < findiff_x_u_[ivar] )
{
const Number xorig = full_x_pert[ivar];
Number this_perturbation = findiff_perturbation_ * Max(Number(1.), std::abs(full_x_[ivar]));
full_x_pert[ivar] += this_perturbation;
if( full_x_pert[ivar] > findiff_x_u_[ivar] )
{
this_perturbation = -this_perturbation;
full_x_pert[ivar] = xorig + this_perturbation;
}
retval = tnlp_->eval_g(n_full_x_, full_x_pert, true, n_full_g_, full_g_pert);
if( !retval )
{
break;
}
for( Index i = findiff_jac_ia_[ivar]; i < findiff_jac_ia_[ivar + 1]; i++ )
{
const Index& icon = findiff_jac_ja_[i];
const Index& ipos = findiff_jac_postriplet_[i];
jac_g_[ipos] = (full_g_pert[icon] - full_g_[icon]) / this_perturbation;
}
full_x_pert[ivar] = xorig;
}
}
delete[] full_g_pert;
delete[] full_x_pert;
}
}
if( !retval )
{
x_tag_for_jac_g_ = 0;
}
return retval;
}
void TNLPAdapter::initialize_findiff_jac(
const Index* iRow,
const Index* jCol
)
{
SmartPtr<TripletToCSRConverter> findiff_jac_converter = new TripletToCSRConverter(0);
Index* airn = new Index[nz_full_jac_g_];
Index* ajcn = new Index[nz_full_jac_g_];
for( Index i = 0; i < nz_full_jac_g_; i++ )
{
airn[i] = jCol[i];
ajcn[i] = iRow[i] + n_full_x_;
}
findiff_jac_nnz_ = findiff_jac_converter->InitializeConverter(n_full_g_ + n_full_x_, nz_full_jac_g_, airn, ajcn);
delete[] airn;
delete[] ajcn;
if( findiff_jac_nnz_ != nz_full_jac_g_ )
{
THROW_EXCEPTION(INVALID_TNLP,
"Sparsity structure of Jacobian has multiple occurrences of the same position. This is not allowed for finite differences.");
}
delete[] findiff_jac_ia_;
delete[] findiff_jac_ja_;
delete[] findiff_jac_postriplet_;
findiff_jac_ia_ = NULL;
findiff_jac_ja_ = NULL;
findiff_jac_postriplet_ = NULL;
findiff_jac_ia_ = new Index[n_full_x_ + 1];
findiff_jac_ja_ = new Index[findiff_jac_nnz_];
findiff_jac_postriplet_ = new Index[findiff_jac_nnz_];
const Index* ia = findiff_jac_converter->IA();
if( ia != NULL )
{
for( Index i = 0; i < n_full_x_ + 1; i++ )
{
findiff_jac_ia_[i] = ia[i];
}
}
else
{
memset(findiff_jac_ia_, 0, n_full_x_ * sizeof(Index));
}
const Index* ja = findiff_jac_converter->JA();
for( Index i = 0; i < findiff_jac_nnz_; i++ )
{
findiff_jac_ja_[i] = ja[i] - n_full_x_;
}
const Index* postrip = findiff_jac_converter->iPosFirst();
for( Index i = 0; i < findiff_jac_nnz_; i++ )
{
findiff_jac_postriplet_[i] = postrip[i];
}
}
bool TNLPAdapter::CheckDerivatives(
TNLPAdapter::DerivativeTestEnum deriv_test,
Index deriv_test_start_index
)
{
if( deriv_test == NO_TEST )
{
return true;
}
Index nerrors = 0;
ASSERT_EXCEPTION(IsValid(jnlst_), ERROR_IN_TNLP_DERIVATIVE_TEST,
"No Journalist given to TNLPAdapter. Need Journalist, otherwise can't produce any output in DerivativeChecker!");
bool retval = true;
Index nx; Index ng; Index nz_jac_g; Index nz_hess_lag; TNLP::IndexStyleEnum index_style;
retval = tnlp_->get_nlp_info(nx, ng, nz_jac_g, nz_hess_lag, index_style);
ASSERT_EXCEPTION(retval, INVALID_TNLP, "get_nlp_info returned false for derivative checker");
ASSERT_EXCEPTION(nx >= 0, INVALID_TNLP, "number of variables negative");
ASSERT_EXCEPTION(ng >= 0, INVALID_TNLP, "number of constraints negative");
ASSERT_EXCEPTION(nz_jac_g >= 0, INVALID_TNLP, "number of nonzeros in Jacobian negative");
ASSERT_EXCEPTION(nz_hess_lag >= 0, INVALID_TNLP, "number of nonzeros in Hessian negative");
Number* xref = new Number[nx];
tnlp_->get_starting_point(nx, true, xref, false, NULL, NULL, ng, false, NULL);
Number* x_l = new Number[nx];
Number* x_u = new Number[nx];
Number* g_l = new Number[ng];
Number* g_u = new Number[ng];
retval = tnlp_->get_bounds_info(nx, x_l, x_u, ng, g_l, g_u);
ASSERT_EXCEPTION(retval, INVALID_TNLP, "get_bounds_info returned false in derivative checker");
IpResetRandom01();
for( Index i = 0; i < nx; i++ )
{
const Number lower = Max(x_l[i], xref[i] - point_perturbation_radius_);
const Number upper = Min(x_u[i], xref[i] + point_perturbation_radius_);
const Number interval = upper - lower;
const Number random_number = IpRandom01();
xref[i] = lower + random_number * interval;
}
delete[] x_l;
delete[] x_u;
delete[] g_l;
delete[] g_u;
bool new_x = true;
Number fref;
Number* gref = NULL;
if( ng > 0 )
{
gref = new Number[ng];
}
retval = tnlp_->eval_f(nx, xref, new_x, fref);
ASSERT_EXCEPTION(retval, ERROR_IN_TNLP_DERIVATIVE_TEST,
"In TNLP derivative test: f could not be evaluated at reference point.");
new_x = false;
if( ng > 0 )
{
retval = tnlp_->eval_g(nx, xref, new_x, ng, gref);
ASSERT_EXCEPTION(retval, ERROR_IN_TNLP_DERIVATIVE_TEST,
"In TNLP derivative test: g could not be evaluated at reference point.");
}
Number* grad_f = new Number[nx];
retval = tnlp_->eval_grad_f(nx, xref, true, grad_f);
ASSERT_EXCEPTION(retval, ERROR_IN_TNLP_DERIVATIVE_TEST,
"In TNLP derivative test: grad_f could not be evaluated at reference point.");
Index* g_iRow = NULL;
Index* g_jCol = NULL;
Number* jac_g = NULL;
if( ng > 0 )
{
g_iRow = new Index[nz_jac_g];
g_jCol = new Index[nz_jac_g];
retval = tnlp_->eval_jac_g(nx, NULL, false, ng, nz_jac_g, g_iRow, g_jCol, NULL);
ASSERT_EXCEPTION(retval, ERROR_IN_TNLP_DERIVATIVE_TEST,
"In TNLP derivative test: Jacobian structure could not be evaluated.");
if( index_style == TNLP::FORTRAN_STYLE )
{
for( Index i = 0; i < nz_jac_g; i++ )
{
DBG_ASSERT(g_iRow[i] > 0);
DBG_ASSERT(g_iRow[i] <= ng);
DBG_ASSERT(g_jCol[i] > 0);
DBG_ASSERT(g_jCol[i] <= nx);
g_iRow[i] -= 1;
g_jCol[i] -= 1;
}
}
#if IPOPT_CHECKLEVEL > 0
else
{
for( Index i = 0; i < nz_jac_g; i++ )
{
DBG_ASSERT(g_iRow[i] >= 0);
DBG_ASSERT(g_iRow[i] < ng);
DBG_ASSERT(g_jCol[i] >= 0);
DBG_ASSERT(g_jCol[i] < nx);
}
}
#endif
jac_g = new Number[nz_jac_g];
retval = tnlp_->eval_jac_g(nx, xref, new_x, ng, nz_jac_g, NULL, NULL, jac_g);
ASSERT_EXCEPTION(retval, ERROR_IN_TNLP_DERIVATIVE_TEST,
"In TNLP derivative test: Jacobian values could not be evaluated at reference point.");
}
Number* xpert = new Number[nx];
IpBlasCopy(nx, xref, 1, xpert, 1);
Number* gpert = NULL;
if( ng > 0 )
{
gpert = new Number[ng];
}
Index index_correction = 0;
if( index_style == TNLP::FORTRAN_STYLE )
{
index_correction = 1;
}
if( deriv_test == FIRST_ORDER_TEST || deriv_test == SECOND_ORDER_TEST )
{
jnlst_->Printf(J_SUMMARY, J_NLP, "Starting derivative checker for first derivatives.\n\n");
const Index ivar_first = Max(Index(0), deriv_test_start_index);
for( Index ivar = ivar_first; ivar < nx; ivar++ )
{
Number this_perturbation = derivative_test_perturbation_ * Max(Number(1.), std::abs(xref[ivar]));
xpert[ivar] = xref[ivar] + this_perturbation;
Number fpert;
new_x = true;
retval = tnlp_->eval_f(nx, xpert, new_x, fpert);
ASSERT_EXCEPTION(retval, ERROR_IN_TNLP_DERIVATIVE_TEST,
"In TNLP derivative test: f could not be evaluated at perturbed point.");
new_x = false;
Number deriv_approx = (fpert - fref) / this_perturbation;
Number deriv_exact = grad_f[ivar];
Number rel_error = std::abs(deriv_approx - deriv_exact) / Max(std::abs(deriv_approx), derivative_test_tol_);
char cflag = ' ';
if( rel_error >= derivative_test_tol_ )
{
cflag = '*';
nerrors++;
}
if( cflag != ' ' || derivative_test_print_all_ )
{
jnlst_->Printf(J_WARNING, J_NLP, "%c grad_f[ %5" IPOPT_INDEX_FORMAT "] = %23.16e ~ %23.16e [%10.3e]\n", cflag,
ivar + index_correction, deriv_exact, deriv_approx, rel_error);
}
if( ng > 0 )
{
retval = tnlp_->eval_g(nx, xpert, new_x, ng, gpert);
ASSERT_EXCEPTION(retval, ERROR_IN_TNLP_DERIVATIVE_TEST,
"In TNLP derivative test: g could not be evaluated at reference point.");
for( Index icon = 0; icon < ng; icon++ )
{
deriv_approx = (gpert[icon] - gref[icon]) / this_perturbation;
deriv_exact = 0.;
bool found = false;
for( Index i = 0; i < nz_jac_g; i++ )
{
if( g_iRow[i] == icon && g_jCol[i] == ivar )
{
found = true;
deriv_exact += jac_g[i];
}
}
rel_error = std::abs(deriv_approx - deriv_exact) / Max(std::abs(deriv_approx), derivative_test_tol_);
cflag = ' ';
if( rel_error >= derivative_test_tol_ )
{
cflag = '*';
nerrors++;
}
char sflag = ' ';
if( found )
{
sflag = 'v';
}
if( cflag != ' ' || derivative_test_print_all_ )
{
jnlst_->Printf(J_WARNING, J_NLP, "%c jac_g [%5" IPOPT_INDEX_FORMAT ",%5" IPOPT_INDEX_FORMAT "] = %23.16e %c ~ %23.16e [%10.3e]\n", cflag,
icon + index_correction, ivar + index_correction, deriv_exact, sflag, deriv_approx, rel_error);
}
}
}
xpert[ivar] = xref[ivar];
}
}
const Number zero = 0.;
if( deriv_test == SECOND_ORDER_TEST || deriv_test == ONLY_SECOND_ORDER_TEST )
{
jnlst_->Printf(J_SUMMARY, J_NLP, "Starting derivative checker for second derivatives with obj_factor or lambda[i] set to 1.5.\n\n");
Index* h_iRow = new Index[nz_hess_lag];
Index* h_jCol = new Index[nz_hess_lag];
retval = tnlp_->eval_h(nx, NULL, false, 0., ng, NULL, false, nz_hess_lag, h_iRow, h_jCol, NULL);
ASSERT_EXCEPTION(retval, ERROR_IN_TNLP_DERIVATIVE_TEST,
"In TNLP derivative test: Hessian structure could not be evaluated.");
if( index_style == TNLP::FORTRAN_STYLE )
{
for( Index i = 0; i < nz_hess_lag; i++ )
{
DBG_ASSERT(h_iRow[i] > 0);
DBG_ASSERT(h_iRow[i] <= nx);
DBG_ASSERT(h_jCol[i] > 0);
DBG_ASSERT(h_jCol[i] <= nx);
h_iRow[i] -= 1;
h_jCol[i] -= 1;
}
}
#if IPOPT_CHECKLEVEL > 0
else
{
for( Index i = 0; i < nz_hess_lag; i++ )
{
DBG_ASSERT(h_iRow[i] >= 0);
DBG_ASSERT(h_iRow[i] < nx);
DBG_ASSERT(h_jCol[i] >= 0);
DBG_ASSERT(h_jCol[i] < nx);
}
}
#endif
Number* h_values = new Number[nz_hess_lag];
Number* lambda = NULL;
if( ng > 0 )
{
lambda = new Number[ng];
IpBlasCopy(ng, &zero, 0, lambda, 1);
}
Number* gradref = new Number[nx]; Number* gradpert = new Number[nx]; Number* jacpert = new Number[nz_jac_g];
const Index icon_first = Max(Index(-1), deriv_test_start_index);
for( Index icon = icon_first; icon < ng; icon++ )
{
Number objfact = 0.;
if( icon == -1 )
{
objfact = 1.5;
IpBlasCopy(nx, grad_f, 1, gradref, 1);
}
else
{
DBG_ASSERT(lambda != NULL);
lambda[icon] = 1.5;
IpBlasCopy(nx, &zero, 0, gradref, 1);
for( Index i = 0; i < nz_jac_g; i++ )
{
if( g_iRow[i] == icon )
{
gradref[g_jCol[i]] += jac_g[i];
}
}
}
new_x = true;
bool new_y = true;
retval = tnlp_->eval_h(nx, xref, new_x, objfact, ng, lambda, new_y, nz_hess_lag, NULL, NULL, h_values);
ASSERT_EXCEPTION(retval, ERROR_IN_TNLP_DERIVATIVE_TEST,
"In TNLP derivative test: Hessian could not be evaluated at reference point.");
for( Index ivar = 0; ivar < nx; ivar++ )
{
Number this_perturbation = derivative_test_perturbation_ * Max(Number(1.), std::abs(xref[ivar]));
xpert[ivar] = xref[ivar] + this_perturbation;
new_x = true;
if( icon == -1 )
{
retval = tnlp_->eval_grad_f(nx, xpert, new_x, gradpert);
ASSERT_EXCEPTION(retval, ERROR_IN_TNLP_DERIVATIVE_TEST,
"In TNLP derivative test: grad_f could not be evaluated at perturbed point.");
}
else
{
retval = tnlp_->eval_jac_g(nx, xpert, new_x, ng, nz_jac_g, NULL, NULL, jacpert);
ASSERT_EXCEPTION(retval, ERROR_IN_TNLP_DERIVATIVE_TEST,
"In TNLP derivative test: Jacobian values could not be evaluated at reference point.");
IpBlasCopy(nx, &zero, 0, gradpert, 1);
IpBlasCopy(nx, &zero, 0, gradref, 1);
for( Index i = 0; i < nz_jac_g; i++ )
{
if( g_iRow[i] == icon )
{
gradpert[g_jCol[i]] += jacpert[i];
gradref[g_jCol[i]] += jac_g[i];
}
}
}
for( Index ivar2 = 0; ivar2 < nx; ivar2++ )
{
Number deriv_approx = 1.5 * (gradpert[ivar2] - gradref[ivar2]) / this_perturbation;
Number deriv_exact = 0.;
bool found = false;
for( Index i = 0; i < nz_hess_lag; i++ )
{
if( (h_iRow[i] == ivar && h_jCol[i] == ivar2) || (h_jCol[i] == ivar && h_iRow[i] == ivar2) )
{
deriv_exact += h_values[i];
found = true;
}
}
Number rel_error = std::abs(deriv_approx - deriv_exact) / Max(std::abs(deriv_approx), derivative_test_tol_);
char cflag = ' ';
if( rel_error >= derivative_test_tol_ )
{
cflag = '*';
nerrors++;
}
char sflag = ' ';
if( found )
{
sflag = 'v';
}
if( cflag != ' ' || derivative_test_print_all_ )
{
if( icon == -1 )
{
jnlst_->Printf(J_WARNING, J_NLP,
"%c obj_hess[%5" IPOPT_INDEX_FORMAT ",%5" IPOPT_INDEX_FORMAT "] = %23.16e %c ~ %23.16e [%10.3e]\n", cflag,
ivar + index_correction, ivar2 + index_correction, deriv_exact, sflag, deriv_approx, rel_error);
}
else
{
jnlst_->Printf(J_WARNING, J_NLP,
"%c %5" IPOPT_INDEX_FORMAT "-th constr_hess[%5" IPOPT_INDEX_FORMAT ",%5" IPOPT_INDEX_FORMAT "] = %23.16e %c ~ %23.16e [%10.3e]\n", cflag,
icon + index_correction, ivar + index_correction, ivar2 + index_correction, deriv_exact, sflag,
deriv_approx, rel_error);
}
}
}
xpert[ivar] = xref[ivar];
}
if( icon >= 0 )
{
lambda[icon] = 0.;
}
}
delete[] h_iRow;
delete[] h_jCol;
delete[] h_values;
delete[] lambda;
delete[] gradref;
delete[] gradpert;
delete[] jacpert;
}
delete[] xref;
delete[] gref;
delete[] grad_f;
delete[] xpert;
delete[] g_iRow;
delete[] g_jCol;
delete[] jac_g;
delete[] gpert;
if( nerrors == 0 )
{
jnlst_->Printf(J_SUMMARY, J_NLP, "\nNo errors detected by derivative checker.\n\n");
}
else
{
jnlst_->Printf(J_WARNING, J_NLP, "\nDerivative checker detected %" IPOPT_INDEX_FORMAT " error(s).\n\n", nerrors);
}
return retval;
}
bool TNLPAdapter::DetermineDependentConstraints(
Index n_x_var,
const Index* x_not_fixed_map,
const Number* x_l,
const Number* x_u,
const Number* g_l,
const Number* ,
Index n_c,
const Index* c_map,
std::list<Index>& c_deps
)
{
SmartPtr<ExpansionMatrixSpace> P_c_g_space = new ExpansionMatrixSpace(n_full_g_, n_c, c_map);
SmartPtr<ExpansionMatrix> P_c_g = P_c_g_space->MakeNewExpansionMatrix();
Index* g_iRow = new Index[nz_full_jac_g_];
Index* g_jCol = new Index[nz_full_jac_g_];
if( !tnlp_->eval_jac_g(n_full_x_, NULL, false, n_full_g_, nz_full_jac_g_, g_iRow, g_jCol, NULL) )
{
delete[] g_iRow;
delete[] g_jCol;
return false;
}
if( index_style_ == TNLP::FORTRAN_STYLE )
{
for( Index i = 0; i < nz_full_jac_g_; i++ )
{
DBG_ASSERT(g_iRow[i] > 0);
DBG_ASSERT(g_iRow[i] <= n_full_g_);
DBG_ASSERT(g_jCol[i] > 0);
DBG_ASSERT(g_jCol[i] <= n_full_x_);
g_iRow[i] -= 1;
g_jCol[i] -= 1;
}
}
#if IPOPT_CHECKLEVEL > 0
else
{
for( Index i = 0; i < nz_full_jac_g_; i++ )
{
DBG_ASSERT(g_iRow[i] >= 0);
DBG_ASSERT(g_iRow[i] < n_full_g_);
DBG_ASSERT(g_jCol[i] >= 0);
DBG_ASSERT(g_jCol[i] < n_full_x_);
}
}
#endif
Index* jac_c_map = new Index[nz_full_jac_g_];
Index* jac_c_iRow = new Index[nz_full_jac_g_ + n_c];
Index* jac_c_jCol = new Index[nz_full_jac_g_ + n_c];
Index nz_jac_c = 0;
const Index* c_row_pos = P_c_g->CompressedPosIndices();
Index n_fixed = n_full_x_ - n_x_var;
if( n_fixed > 0 )
{
Index* c_col_pos = new Index[n_full_x_];
for( Index i = 0; i < n_full_x_; i++ )
{
c_col_pos[i] = -1;
}
for( Index i = 0; i < n_x_var; i++ )
{
c_col_pos[x_not_fixed_map[i]] = i;
}
for( Index i = 0; i < nz_full_jac_g_; i++ )
{
const Index& c_row = c_row_pos[g_iRow[i]];
const Index& c_col = c_col_pos[g_jCol[i]];
if( c_col != -1 && c_row != -1 )
{
jac_c_map[nz_jac_c] = i;
jac_c_iRow[nz_jac_c] = c_row + 1;
jac_c_jCol[nz_jac_c] = c_col + 1;
nz_jac_c++;
}
}
delete[] c_col_pos;
}
else
{
for( Index i = 0; i < nz_full_jac_g_; i++ )
{
const Index& c_row = c_row_pos[g_iRow[i]];
const Index& c_col = g_jCol[i];
if( c_row != -1 )
{
jac_c_map[nz_jac_c] = i;
jac_c_iRow[nz_jac_c] = c_row + 1;
jac_c_jCol[nz_jac_c] = c_col + 1;
nz_jac_c++;
}
}
}
delete[] g_iRow;
delete[] g_jCol;
if( !tnlp_->get_starting_point(n_full_x_, true, full_x_, false, NULL,
NULL, n_full_g_, false, NULL) )
{
delete[] jac_c_iRow;
delete[] jac_c_jCol;
delete[] jac_c_map;
return false;
}
IpResetRandom01();
for( Index i = 0; i < n_full_x_; i++ )
{
const Number lower = Max(x_l[i], full_x_[i] - point_perturbation_radius_);
const Number upper = Min(x_u[i], full_x_[i] + point_perturbation_radius_);
const Number interval = upper - lower;
const Number random_number = IpRandom01();
full_x_[i] = lower + random_number * interval;
}
Number* g_vals = NULL;
if( dependency_detection_with_rhs_ )
{
g_vals = new Number[n_full_g_];
if( !tnlp_->eval_g(n_full_x_, full_x_, true, n_full_g_, g_vals) )
{
delete[] jac_c_iRow;
delete[] jac_c_jCol;
delete[] jac_c_map;
delete[] g_vals;
return false;
}
}
if( !tnlp_->eval_jac_g(n_full_x_, full_x_, !dependency_detection_with_rhs_, n_full_g_, nz_full_jac_g_, NULL, NULL,
jac_g_) )
{
delete[] jac_c_iRow;
delete[] jac_c_jCol;
delete[] jac_c_map;
delete[] g_vals;
return false;
}
Number* jac_c_vals = new Number[nz_jac_c + n_c];
for( Index i = 0; i < nz_jac_c; i++ )
{
jac_c_vals[i] = jac_g_[jac_c_map[i]];
}
if( dependency_detection_with_rhs_ )
{
const Index* c_row_pos2 = P_c_g->ExpandedPosIndices();
for( Index i = 0; i < n_c; i++ )
{
jac_c_iRow[nz_jac_c + i] = i + 1;
jac_c_jCol[nz_jac_c + i] = n_x_var + 1;
jac_c_vals[nz_jac_c + i] = g_vals[c_row_pos2[i]] - g_l[c_row_pos2[i]];
}
n_x_var += 1;
nz_jac_c += n_c;
}
ASSERT_EXCEPTION(IsValid(dependency_detector_), OPTION_INVALID,
"No dependency_detector_ object available in TNLPAdapter::DetermineDependentConstraints");
bool retval = dependency_detector_->DetermineDependentRows(n_c, n_x_var, nz_jac_c, jac_c_vals, jac_c_iRow,
jac_c_jCol, c_deps);
dependency_detector_ = NULL;
delete[] jac_c_iRow;
delete[] jac_c_jCol;
delete[] jac_c_map;
delete[] jac_c_vals;
delete[] g_vals;
return retval;
}
}