00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "IpTNLP.hpp"
00011 #include "IpIpoptApplication.hpp"
00012
00013 #include "CouenneSparseMatrix.hpp"
00014 #include "CouenneProblem.hpp"
00015 #include "CouenneProblemElem.hpp"
00016 #include "CouenneExprVar.hpp"
00017 #include "CouenneExprJac.hpp"
00018 #include "CouenneExprHess.hpp"
00019 #include "CouenneTNLP.hpp"
00020
00021 #include <stdio.h>
00022
00023 #include "CoinHelperFunctions.hpp"
00024 #include "CoinFinite.hpp"
00025
00026
00027
00028 using namespace Ipopt;
00029 using namespace Couenne;
00030
00032 CouenneTNLP::CouenneTNLP ():
00033
00034 problem_ (NULL),
00035 sol0_ (NULL),
00036 sol_ (NULL),
00037 HLa_ (NULL),
00038
00039 optHessian_ (NULL),
00040 saveOptHessian_ (false) {}
00041
00042
00044 CouenneTNLP::~CouenneTNLP () {
00045
00046 if (sol0_) delete [] sol0_;
00047 if (sol_) delete [] sol_;
00048 if (HLa_) delete HLa_;
00049 if (optHessian_) delete optHessian_;
00050
00051 for (std::vector <std::pair <int, expression *> >::iterator i = gradient_. begin ();
00052 i != gradient_. end (); ++i)
00053 delete (*i). second;
00054 }
00055
00057 int PSDize (int n, double *A, double *B, bool doSqrRoot);
00058
00059
00061 CouenneTNLP::CouenneTNLP (CouenneProblem *p):
00062
00063 problem_ (p),
00064 sol0_ (NULL),
00065 sol_ (NULL),
00066 bestZ_ (COIN_DBL_MAX),
00067 Jac_ (p),
00068 HLa_ (new ExprHess (p)),
00069 optHessian_ (NULL),
00070 saveOptHessian_ (false) {
00071
00072 std::set <int> objDep;
00073
00074 expression *obj = problem_ -> Obj (0) -> Body ();
00075
00076
00077
00078 obj -> DepList (objDep, STOP_AT_AUX);
00079
00080 for (std::set <int>::iterator i = objDep.begin (); i != objDep. end (); ++i) {
00081
00082 expression *gradcomp = obj -> differentiate (*i);
00083 gradcomp -> realign (problem_);
00084 gradient_ . push_back (std::pair <int, expression *> (*i, gradcomp));
00085 }
00086
00087
00088
00089
00090
00091
00092 for (int i = 0; i < problem_ -> nCons (); i++) {
00093
00094 expression *e = problem_ -> Con (i) -> Body ();
00095
00096
00097
00098
00099 if (e -> Type () == AUX ||
00100 e -> Type () == VAR ||
00101 e -> Linearity () <= LINEAR)
00102 continue;
00103
00104
00105
00106
00107 e -> DepList (nonLinVars_, STOP_AT_AUX);
00108 }
00109
00110
00111
00112 for (int i = 0; i < problem_ -> nVars (); i++) {
00113
00114 exprVar *e = problem_ -> Var (i);
00115
00116 if ((e -> Type () != AUX) ||
00117 (e -> Multiplicity () <= 0) ||
00118 (e -> Linearity () <= LINEAR))
00119 continue;
00120
00121 e -> Image () -> DepList (nonLinVars_, STOP_AT_AUX);
00122 }
00123 }
00124
00125
00127 CouenneTNLP::CouenneTNLP (const CouenneTNLP &rhs)
00128 {operator= (rhs);}
00129
00130
00132 CouenneTNLP &CouenneTNLP::operator= (const CouenneTNLP &rhs) {
00133
00134 problem_ = rhs.problem_;
00135
00136 sol0_ = rhs.sol0_ && problem_ ? CoinCopyOfArray (rhs.sol0_, problem_ -> nVars ()) : NULL;
00137 sol_ = rhs.sol_ && problem_ ? CoinCopyOfArray (rhs.sol_, problem_ -> nVars ()) : NULL;
00138
00139 bestZ_ = rhs.bestZ_;
00140 gradient_ = rhs.gradient_;
00141 nonLinVars_ = rhs.nonLinVars_;
00142
00143 Jac_ = rhs.Jac_;
00144 HLa_ = rhs.HLa_ ? new ExprHess (*(rhs.HLa_)) : NULL;
00145
00146 optHessian_ = rhs.optHessian_ ? new CouenneSparseMatrix (*(rhs.optHessian_)) : NULL;
00147 saveOptHessian_ = rhs.saveOptHessian_;
00148
00149 return *this;
00150 }
00151
00153 CouenneTNLP *CouenneTNLP::clone ()
00154 {return new CouenneTNLP (*this);}
00155
00156
00157
00158
00159
00160
00161
00162 bool CouenneTNLP::get_nlp_info (Index& n,
00163 Index& m,
00164 Index& nnz_jac_g,
00165 Index& nnz_h_lag,
00166 IndexStyleEnum& index_style) {
00167 n = problem_ -> nVars ();
00168 m = Jac_. nRows ();
00169
00170 nnz_jac_g = Jac_ . nnz ();
00171 nnz_h_lag = HLa_ -> nnz ();
00172
00173 index_style = C_STYLE;
00174
00175 return true;
00176 }
00177
00178
00180 void CouenneTNLP::setInitSol (const double *sol) {
00181
00182 if (sol) {
00183 if (!sol0_)
00184 sol0_ = new CouNumber [problem_ -> nVars ()];
00185 CoinCopyN (sol, problem_ -> nVars (), sol0_);
00186 }
00187 }
00188
00189
00190
00191
00192
00193
00194
00195 bool CouenneTNLP::get_bounds_info (Index n, Number* x_l, Number* x_u,
00196 Index m, Number* g_l, Number* g_u) {
00197
00198
00199
00200 #ifdef DEBUG
00201 printf ("get_bounds_info on %d cons, %d vars\n", m, n);
00202 #endif
00203
00204 for (int i = 0; i < problem_ -> nCons (); i++) {
00205
00206 CouenneConstraint *c = problem_ -> Con (i);
00207
00208 if (c -> Body () -> Type () == AUX ||
00209 c -> Body () -> Type () == VAR)
00210 continue;
00211
00212 CouNumber
00213 clb = (*c -> Lb ()) (),
00214 cub = (*c -> Ub ()) ();
00215
00216
00217 if (clb <= cub) {*g_l++ = clb; *g_u++ = cub;}
00218 else {*g_l++ = cub; *g_u++ = clb;}
00219 }
00220
00221
00222
00223 for (int i = 0; i < problem_ -> nVars (); i++) {
00224
00225 exprVar *e = problem_ -> Var (i);
00226
00227 if (e -> Multiplicity () <= 0)
00228 *x_l++ = *x_u++ = 0.;
00229 else {
00230
00231 CouNumber
00232 lb = e -> lb (),
00233 ub = e -> ub ();
00234
00235
00236 if (lb <= ub) {*x_l++ = lb; *x_u++ = ub;}
00237 else {*x_l++ = ub; *x_u++ = lb;}
00238 }
00239
00240 if ((e -> Type () != AUX) ||
00241 (e -> Multiplicity () <= 0))
00242 continue;
00243
00244 *g_l = (e -> sign () != expression::AUX_GEQ) ? 0. : -COIN_DBL_MAX;
00245 *g_u = (e -> sign () != expression::AUX_LEQ) ? 0. : COIN_DBL_MAX;
00246
00247 ++g_l;
00248 ++g_u;
00249 }
00250
00251 return true;
00252 }
00253
00254
00255
00256
00257
00258
00259 bool CouenneTNLP::get_variables_linearity (Index n, Ipopt::TNLP::LinearityType* var_types) {
00260
00261 CoinFillN (var_types, n, Ipopt::TNLP::LINEAR);
00262
00263 for (std::set <int>:: iterator i = nonLinVars_. begin (); i != nonLinVars_. end (); ++i)
00264 var_types [*i] = Ipopt::TNLP::NON_LINEAR;
00265
00266 return true;
00267 }
00268
00269
00270
00271
00272 bool CouenneTNLP::get_constraints_linearity (Index m, Ipopt::TNLP::LinearityType* const_types) {
00273
00274
00275
00276 for (int i = 0; i < problem_ -> nCons (); i++) {
00277
00278 expression *b = problem_ -> Con (i) -> Body ();
00279
00280 if (b -> Type () == AUX ||
00281 b -> Type () == VAR)
00282 continue;
00283
00284 *const_types++ =
00285 (b -> Linearity () > LINEAR) ?
00286 Ipopt::TNLP::NON_LINEAR :
00287 Ipopt::TNLP::LINEAR;
00288 }
00289
00290
00291
00292 for (int i = 0; i < problem_ -> nVars (); i++) {
00293
00294 exprVar *e = problem_ -> Var (i);
00295
00296 if ((e -> Type () != AUX) ||
00297 (e -> Multiplicity () <= 0))
00298 continue;
00299
00300 *const_types++ =
00301 (e -> Image () -> Linearity () > LINEAR) ?
00302 Ipopt::TNLP::NON_LINEAR :
00303 Ipopt::TNLP::LINEAR;
00304 }
00305
00306 return true;
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316 bool CouenneTNLP::get_starting_point (Index n,
00317 bool init_x, Number* x,
00318 bool init_z, Number* z_L, Number* z_U,
00319 Index m,
00320 bool init_lambda, Number* lambda) {
00321 if (init_x)
00322 CoinCopyN (sol0_, n, x);
00323
00324 assert (!init_z);
00325 assert (!init_lambda);
00326
00327 return true;
00328 }
00329
00330
00331
00332 bool CouenneTNLP::eval_f (Index n, const Number* x, bool new_x,
00333 Number& obj_value) {
00334 if (new_x)
00335 CoinCopyN (x, n, problem_ -> X ());
00336
00337
00338 obj_value = (*(problem_ -> Obj (0) -> Body ())) ();
00339 return true;
00340 }
00341
00342
00343
00344
00345 bool CouenneTNLP::eval_grad_f (Index n, const Number* x, bool new_x,
00346 Number* grad_f) {
00347
00348 #ifdef DEBUG
00349 printf ("eval_grad_f: [");
00350 for (int i=0; i<n; i++)
00351 printf ("%.2g ", x [i]);
00352 printf ("] --> [");
00353 #endif
00354
00355 if (new_x)
00356 CoinCopyN (x, n, problem_ -> X ());
00357
00358
00359 CoinFillN (grad_f, n, 0.);
00360
00361 for (std::vector <std::pair <int, expression *> >::iterator i = gradient_. begin ();
00362 i != gradient_. end (); ++i)
00363 grad_f [i -> first] = (*(i -> second)) ();
00364
00365 #ifdef DEBUG
00366 for (int i=0; i<n; i++)
00367 printf ("%.2g ", grad_f [i]);
00368 printf ("]\n");
00369 #endif
00370
00371 return true;
00372 }
00373
00374
00375
00376 bool CouenneTNLP::eval_g (Index n, const Number* x, bool new_x,
00377 Index m, Number* g) {
00378
00379 if (new_x)
00380 CoinCopyN (x, n, problem_ -> X ());
00381
00382
00383 #ifdef DEBUG
00384 if (x) {
00385 printf ("eval_g: [");
00386 for (int i=0; i<n; i++)
00387 printf ("%.2g ", x [i]);
00388 printf ("] --> [");
00389 }
00390 #endif
00391
00392 int nEntries = 0;
00393
00394 for (int i = 0; i < problem_ -> nCons (); i++) {
00395
00396 expression *b = problem_ -> Con (i) -> Body ();
00397
00398 if (b -> Type () == AUX ||
00399 b -> Type () == VAR)
00400 continue;
00401
00402 nEntries ++;
00403
00404 *g++ = (*b) ();
00405 }
00406
00407
00408
00409 assert (n == problem_ -> nVars ());
00410
00411 for (int i = 0; i < problem_ -> nVars (); i++) {
00412
00413 exprVar *e = problem_ -> Var (i);
00414
00415 if ((e -> Type () != AUX) ||
00416 (e -> Multiplicity () <= 0))
00417 continue;
00418
00419 *g++ = (*(e -> Image ())) () - (*e) ();
00420
00421 nEntries ++;
00422 }
00423
00424 #ifdef DEBUG
00425 if (x) {
00426 for (int i=0; i<nEntries; i++)
00427 printf ("%.2g ", *(g - nEntries + i));
00428 printf ("]\n");
00429 }
00430 #endif
00431
00432 return true;
00433 }
00434
00435
00436
00437
00438
00439
00440
00441 bool CouenneTNLP::eval_jac_g (Index n, const Number* x, bool new_x,
00442 Index m, Index nele_jac, Index* iRow,
00443 Index *jCol, Number* values) {
00444 if (new_x)
00445 CoinCopyN (x, n, problem_ -> X ());
00446
00447
00448 #ifdef DEBUG
00449 if (x) {
00450 printf ("eval_jac_g: ["); fflush (stdout);
00451 for (int i=0; i<n; i++)
00452 {printf ("%.2g ", x [i]); fflush (stdout);}
00453 printf ("] --> ["); fflush (stdout);
00454 }
00455 #endif
00456
00457 if (values == NULL &&
00458 iRow != NULL &&
00459 jCol != NULL) {
00460
00461
00462
00463
00464 CoinCopyN (Jac_.iRow (), nele_jac, iRow);
00465 CoinCopyN (Jac_.jCol (), nele_jac, jCol);
00466
00467 } else {
00468
00469
00470
00471
00472 register expression **e = Jac_. expr ();
00473
00474 for (register int i=nele_jac; i--;)
00475 *values++ = (**(e++)) ();
00476 }
00477
00478 #ifdef DEBUG
00479 if (values) {
00480 for (int i=0; i<nele_jac; i++)
00481 {printf ("%.2g ", *(values - nele_jac + i)); fflush (stdout);}
00482 printf ("]\n");
00483 } else printf ("empty\n");
00484 #endif
00485
00486 return true;
00487 }
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 bool CouenneTNLP::eval_h (Index n, const Number* x, bool new_x, Number obj_factor,
00502 Index m, const Number* lambda, bool new_lambda,
00503 Index nele_hess,
00504 Index* iRow, Index* jCol, Number* values) {
00505
00506 if (new_x)
00507 CoinCopyN (x, n, problem_ -> X ());
00508
00509
00510 #ifdef DEBUG
00511 if (x) {
00512 printf ("eval_h: ["); fflush (stdout);
00513 for (int i=0; i<n; i++)
00514 {printf ("%.2g ", x [i]); fflush (stdout);}
00515 printf ("], lambda: ["); fflush (stdout);
00516 for (int i=0; i<m; i++)
00517 {printf ("%.2g ", lambda [i]); fflush (stdout);}
00518 printf ("] --> ["); fflush (stdout);
00519 }
00520 #endif
00521
00522 if (values == NULL &&
00523 iRow != NULL &&
00524 jCol != NULL) {
00525
00527
00528 CoinCopyN (HLa_ -> iRow (), nele_hess, iRow);
00529 CoinCopyN (HLa_ -> jCol (), nele_hess, jCol);
00530
00531 } else {
00532
00535
00536 CoinZeroN (values, nele_hess);
00537
00538 for (int i=0; i<nele_hess; i++, values++) {
00539
00540 int
00541 numL = HLa_ -> numL () [i],
00542 *lamI = HLa_ -> lamI () [i];
00543
00544 expression
00545 **expr = HLa_ -> expr () [i];
00546
00547 #ifdef DEBUG
00548 printf ("[%d %d] %d lambdas: ", HLa_ -> iRow () [i], HLa_ -> jCol () [i], numL); fflush (stdout);
00549 for (int k=0; k<numL; k++) {
00550 printf ("%d ", lamI [k]);
00551 fflush (stdout);
00552 expr [k] -> print ();
00553 printf ("\n");
00554 }
00555 #endif
00556
00557
00558
00559 if (0 == *lamI) {*values += obj_factor * (*(*expr++)) (); --numL; ++lamI;}
00560 while (numL--) *values += lambda [*lamI++ - 1] * (*(*expr++)) ();
00561 }
00562 }
00563
00564
00565 #ifdef DEBUG
00566 if (values) {
00567 for (int i=0; i<nele_hess; i++)
00568 {printf ("%.2g ", *(values - nele_hess + i)); fflush (stdout);}
00569 printf ("]\n");
00570 } else printf ("empty\n");
00571 #endif
00572
00573 return true;
00574 }
00575
00576
00577
00578 void CouenneTNLP::setObjective (expression *newObj) {
00579
00580 if (HLa_)
00581 delete HLa_;
00582
00583
00584
00585 HLa_ = new ExprHess (problem_);
00586
00587 std::set <int> objDep;
00588
00589
00590
00591 newObj -> DepList (objDep, STOP_AT_AUX);
00592
00593 for (std::vector <std::pair <int, expression *> >::iterator i = gradient_. begin ();
00594 i != gradient_. end (); ++i)
00595 delete (*i). second;
00596
00597 gradient_ . erase (gradient_ . begin (), gradient_ . end ());
00598
00599 for (std::set <int>::iterator i = objDep.begin (); i != objDep. end (); ++i) {
00600
00601 expression *gradcomp = Simplified (newObj -> differentiate (*i));
00602
00603
00604
00605
00606
00607
00608
00609 gradcomp -> realign (problem_);
00610 gradient_ . push_back (std::pair <int, expression *> (*i, gradcomp));
00611 }
00612 }
00613
00614
00615
00616 void CouenneTNLP::finalize_solution (SolverReturn status,
00617 Index n, const Number* x, const Number* z_L, const Number* z_U,
00618 Index m, const Number* g, const Number* lambda,
00619 Number obj_value,
00620 const IpoptData* ip_data,
00621 IpoptCalculatedQuantities* ip_cq) {
00622
00623
00624
00625 bestZ_ = obj_value;
00626
00627 if (sol_) CoinCopyN (x, n, sol_);
00628 else sol_ = CoinCopyOfArray (x, n);
00629
00630
00631
00632
00633 if (!saveOptHessian_)
00634 return;
00635
00636 {
00637 if (!optHessian_)
00638 optHessian_ = new CouenneSparseMatrix;
00639
00640 problem_ -> domain () -> push (n, x, problem_ -> domain () -> current () -> lb (),
00641 problem_ -> domain () -> current () -> ub ());
00642 int nnz = HLa_ -> nnz ();
00643
00644
00645
00646 double *&optHessianVal = optHessian_ -> val ();
00647 int *&optHessianRow = optHessian_ -> row ();
00648 int *&optHessianCol = optHessian_ -> col ();
00649
00650 int &optHessianNum = optHessian_ -> num ();
00651
00652 optHessianVal = (double *) realloc (optHessianVal, nnz * sizeof (double));
00653 optHessianRow = (int *) realloc (optHessianRow, nnz * sizeof (int));
00654 optHessianCol = (int *) realloc (optHessianCol, nnz * sizeof (int));
00655
00656 optHessianNum = 0;
00657
00658 for (int i=0; i < HLa_ -> nnz (); ++i) {
00659
00660 double hessMember = 0.;
00661 expression **elist = HLa_ -> expr () [i];
00662
00663 for (int j=0; j < HLa_ -> numL () [i]; ++j) {
00664
00665 int indLam = HLa_ -> lamI () [i][j];
00666
00667 hessMember += (indLam == 0) ?
00668 (*(elist [j])) () :
00669 (*(elist [j])) () * lambda [indLam-1];
00670 }
00671
00672 if (fabs (hessMember) > COUENNE_EPS) {
00673
00674
00675
00676
00677
00678 optHessianVal [optHessianNum] = hessMember;
00679 optHessianRow [optHessianNum] = HLa_ -> iRow () [i];
00680 optHessianCol [optHessianNum++] = HLa_ -> jCol () [i];
00681 }
00682 }
00683
00684 double *H = new double [n*n];
00685 CoinZeroN (H, n*n);
00686
00687 double *H_PSD = new double [n*n];
00688
00689 for (int i=0; i < optHessianNum; ++i)
00690 H [*optHessianRow++ * n + *optHessianCol++] = *optHessianVal++;
00691
00692 optHessianRow -= optHessianNum;
00693 optHessianCol -= optHessianNum;
00694 optHessianVal -= optHessianNum;
00695
00696
00697
00698 optHessianNum = PSDize (n, H, H_PSD, false);
00699
00700 optHessianVal = (double *) realloc (optHessianVal, optHessianNum * sizeof (double));
00701 optHessianRow = (int *) realloc (optHessianRow, optHessianNum * sizeof (int));
00702 optHessianCol = (int *) realloc (optHessianCol, optHessianNum * sizeof (int));
00703
00704 nnz = 0;
00705 double val;
00706
00707 for (int i=0; i<n; ++i)
00708 for (int j=0; j<n; ++j)
00709 if (fabs (val = *H_PSD++) > COUENNE_EPS) {
00710 *optHessianRow++ = i;
00711 *optHessianCol++ = j;
00712 *optHessianVal++ = val;
00713 ++nnz;
00714 }
00715
00716 H_PSD -= n*n;
00717 optHessianNum = nnz;
00718
00719 optHessianRow -= nnz;
00720 optHessianCol -= nnz;
00721 optHessianVal -= nnz;
00722
00723 problem_ -> domain () -> pop ();
00724
00725 delete [] H;
00726 delete [] H_PSD;
00727 }
00728 }
00729
00730
00731
00732
00733 bool CouenneTNLP::intermediate_callback (AlgorithmMode mode,
00734 Index iter, Number obj_value,
00735 Number inf_pr, Number inf_du,
00736 Number mu, Number d_norm,
00737 Number regularization_size,
00738 Number alpha_du, Number alpha_pr,
00739 Index ls_trials,
00740 const IpoptData* ip_data,
00741 IpoptCalculatedQuantities* ip_cq) {
00742
00743
00744 return true;
00745 }
00746
00747
00748
00749
00750
00751
00752
00753
00754 Index CouenneTNLP::get_number_of_nonlinear_variables ()
00755 {return nonLinVars_. size ();}
00756
00757
00758
00759
00760
00761
00762
00763
00764 bool CouenneTNLP::get_list_of_nonlinear_variables (Index num_nonlin_vars,
00765 Index* pos_nonlin_vars) {
00766
00767 for (std::set <int>:: iterator i = nonLinVars_. begin (); i != nonLinVars_. end (); ++i)
00768 *pos_nonlin_vars++ = *i;
00769
00770 return true;
00771 }