00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "CbcModel.hpp"
00012
00013 #include "IpLapack.hpp"
00014
00015 #include "CouenneSparseMatrix.hpp"
00016 #include "CouenneTNLP.hpp"
00017 #include "CouenneFeasPump.hpp"
00018 #include "CouenneProblem.hpp"
00019 #include "CouenneProblemElem.hpp"
00020 #include "CouenneExprVar.hpp"
00021
00022 #define COUENNE_EIG_RATIO .1 // how much smaller than the largest eigenvalue should the minimum be set at?
00023
00024 using namespace Couenne;
00025
00027 void ComputeSquareRoot (const CouenneFeasPump *fp, CouenneSparseMatrix *hessian, CoinPackedVector *P);
00028
00032 int PSDize (int n, double *A, double *B, bool doSqrRoot);
00033
00035 OsiSolverInterface *createCloneMILP (const CouenneFeasPump *fp, CbcModel *model, bool isMILP, int *match) {
00036
00037 OsiSolverInterface *lp = model -> solver () -> clone ();
00038
00039
00040
00041
00042
00043
00044 CoinPackedVector vec;
00045
00046 for (int i = fp -> Problem () -> nVars (), j = 0; i--; ++j) {
00047
00048
00049
00050
00051
00052
00053
00054
00055 if (fp -> Problem () -> Var (j) -> Multiplicity () <= 0)
00056 continue;
00057
00058 bool intVar = lp -> isInteger (j);
00059
00060 if ((isMILP && (intVar || (fp -> compDistInt () == CouenneFeasPump::FP_DIST_ALL)))
00061 ||
00062 (!isMILP && !intVar)) {
00063
00064
00065 lp -> addCol (vec, 0., COIN_DBL_MAX, 1.);
00066
00067 if (match)
00068 match [j] = lp -> getNumCols () - 1;
00069 }
00070 }
00071
00072
00073
00074
00075
00076
00077 int objInd = fp -> Problem () -> Obj (0) -> Body () -> Index ();
00078
00079 if (objInd >= 0)
00080 lp -> setObjCoeff (objInd, 0.);
00081
00082 return lp;
00083 }
00084
00086 void addDistanceConstraints (const CouenneFeasPump *fp, OsiSolverInterface *lp, double *sol, bool isMILP, int *match) {
00087
00088
00089
00090
00091
00092 int n = fp -> Problem () -> nVars ();
00093
00094 CoinPackedVector *P = new CoinPackedVector [n];
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 CoinPackedVector x0 (n, sol);
00118
00119
00120
00121 if (isMILP && (fp -> multObjFMILP () > 0.)) {
00122
00123 int objInd = fp -> Problem () -> Obj (0) -> Body () -> Index ();
00124
00125 if (objInd >= 0)
00126 lp -> setObjCoeff (objInd, fp -> multObjFMILP ());
00127 }
00128
00129 if (isMILP &&
00130 (fp -> multHessMILP () > 0.) &&
00131 (fp -> nlp () -> optHessian ())) {
00132
00133
00134
00135
00136
00137
00138 CouenneSparseMatrix *hessian = fp -> nlp () -> optHessian ();
00139
00140 ComputeSquareRoot (fp, hessian, P);
00141
00142 } else {
00143
00144
00145
00146 for (int i=0; i<n; i++)
00147 if (fp -> Problem () -> Var (i) -> Multiplicity () > 0)
00148 P[i].insert (i, 1. / sqrt ((double) n));
00149 }
00150
00151
00152
00153 for (int i = 0, j = n, k = n; k--; ++i) {
00154
00155 if (match && match [i] < 0)
00156 continue;
00157
00158 if (fp -> Problem () -> Var (i) -> Multiplicity () <= 0)
00159 continue;
00160
00161
00162
00163
00164
00165
00166 bool intVar = lp -> isInteger (i);
00167
00168 if ((isMILP && (intVar || (fp -> compDistInt () == CouenneFeasPump::FP_DIST_ALL)))
00169 ||
00170 (!isMILP && !intVar)) {
00171
00172
00173 CoinPackedVector &vec = P [i];
00174
00175 if (vec.getNumElements () == 0)
00176 continue;
00177
00178
00179 double PiX0 = sparseDotProduct (vec, x0);
00180
00181 assert (!match || match [i] >= 0);
00182
00183
00184
00185
00186
00187 vec.insert (j, -1.); lp -> addRow (vec, -COIN_DBL_MAX, PiX0);
00188 vec.setElement (vec.getNumElements () - 1, +1.); lp -> addRow (vec, PiX0, COIN_DBL_MAX);
00189
00190 ++j;
00191
00192 } else if (intVar) {
00193
00194
00195
00196 #define INT_LP_BRACKET 0
00197
00198 lp -> setColLower (i, sol [i] - INT_LP_BRACKET);
00199 lp -> setColUpper (i, sol [i] + INT_LP_BRACKET);
00200 }
00201 }
00202
00203 delete [] P;
00204 }
00205
00206
00207 #define GRADIENT_WEIGHT 1
00208
00209 void ComputeSquareRoot (const CouenneFeasPump *fp,
00210 CouenneSparseMatrix *hessian,
00211 CoinPackedVector *P) {
00212
00213 int
00214 objInd = fp -> Problem () -> Obj (0) -> Body () -> Index (),
00215 n = fp -> Problem () -> nVars ();
00216
00217
00218
00219 double *val = hessian -> val ();
00220 int *row = hessian -> row ();
00221 int *col = hessian -> col ();
00222 int num = hessian -> num ();
00223
00224
00225
00226
00227
00228
00229
00230 double maxElem = 0.;
00231
00232 for (int i=num; i--; ++row, ++col, ++val) {
00233
00234
00235
00236 if ((*row == objInd) ||
00237 (*col == objInd))
00238
00239 *val = 0;
00240
00241 else if (fabs (*val) > maxElem)
00242 maxElem = fabs (*val);
00243 }
00244
00245 val -= num;
00246 row -= num;
00247 col -= num;
00248
00249
00250
00251 double *A = (double *) malloc (n*n * sizeof (double));
00252 double *B = (double *) malloc (n*n * sizeof (double));
00253
00254 CoinZeroN (A, n*n);
00255
00256 double sqrt_trace = 0;
00257
00258
00259 for (int i=0; i<num; ++i, ++row, ++col, ++val)
00260 if (*col <= *row) {
00261 A [*col * n + *row] = fp -> multHessMILP () * *val;
00262 if (*col == *row)
00263 sqrt_trace += *val * *val;
00264 }
00265
00266 val -= num;
00267 row -= num;
00268 col -= num;
00269
00270 sqrt_trace = sqrt (sqrt_trace);
00271
00272
00273 if (sqrt_trace > COUENNE_EPS)
00274 for (int i=0; i<num; ++i, ++row, ++col)
00275 A [*col * n + *row] /= sqrt_trace;
00276
00277 row -= num;
00278 col -= num;
00279
00280
00281 for (int i=0; i<n; ++i)
00282 if (fp -> Problem () -> Var (i) -> Multiplicity () > 0)
00283 A [i * (n+1)] += fp -> multDistMILP () / sqrt (static_cast<double>(n));
00284
00285
00286
00287
00288
00289 if (objInd >= 0)
00290 A [objInd * (n+1)] = maxElem * GRADIENT_WEIGHT * n;
00291
00292 PSDize (n, A, B, true);
00293
00294 double *eigenvec = A;
00295
00296 for (int i=0; i<n; ++i)
00297 for (int j=0; j<n; ++j) {
00298
00299
00300
00301 double elem = 0.;
00302
00303 for (int k=0; k<n; ++k)
00304 elem += B [i + k * n] * eigenvec [j * n + k];
00305
00306 if (fabs (elem) > COUENNE_EPS)
00307 P [i]. insert (j, elem);
00308 }
00309
00310
00311
00312
00313
00314
00315 free (A);
00316 free (B);
00317 }
00318
00319
00324
00325
00326 int PSDize (int n, double *A, double *B, bool doSqrRoot) {
00327
00328
00329 double *eigenval = (double *) malloc (n * sizeof (double));
00330 int status;
00331
00332
00333 Ipopt::IpLapackDsyev (true, n, A, n, eigenval, status);
00334
00335 if (status < 0) printf ("Couenne: warning, argument %d illegal\n", -status);
00336 else if (status > 0) printf ("Couenne: warning, dsyev did not converge (error code: %d)\n", status);
00337
00338
00339
00340
00341
00342
00343
00344
00345 double *eigenvec = A;
00346
00347
00348
00349
00350
00351
00352
00353
00354 double
00355 MinEigVal = eigenval [0],
00356 MaxEigVal = eigenval [n-1];
00357
00358 for (int j=1; j<n; j++)
00359 assert (eigenval [j-1] <= eigenval [j]);
00360
00361 if (MaxEigVal <= 0.)
00362
00363
00364
00365
00366
00367
00368 for (int j=0; j<n; j++)
00369 eigenval [j] = 1. / (.1 - eigenval [j]);
00370
00371 else {
00372
00373
00374
00375
00376 MinEigVal = MaxEigVal * COUENNE_EIG_RATIO;
00377
00378 if (eigenval [0] <= MinEigVal)
00379 for (int j=0; eigenval [j] <= MinEigVal; j++)
00380 eigenval [j] = MinEigVal;
00381 }
00382
00383
00384
00385 int nnz = 0;
00386
00387 for (int j=0; j<n; ++j) {
00388
00389 register double multEig = doSqrRoot ? sqrt (eigenval [j]) :
00390 eigenval [j];
00391
00392 for (int i=0; i<n; ++i)
00393 if (fabs (*B++ = multEig * eigenvec [i*n+j]) > COUENNE_EPS)
00394 ++nnz;
00395 }
00396
00397 B -= n*n;
00398
00399
00400
00401
00402
00403
00404
00405
00406 free (eigenval);
00407
00408 return nnz;
00409 }