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
00021 #define COUENNE_EIG_RATIO .1 // how much smaller than the largest eigenvalue should the minimum be set at?
00022
00023 using namespace Couenne;
00024
00026 void ComputeSquareRoot (const CouenneFeasPump *fp, CouenneSparseMatrix *hessian, CoinPackedVector *P);
00027
00029 OsiSolverInterface *createCloneMILP (const CouenneFeasPump *fp, CbcModel *model, bool isMILP) {
00030
00031 OsiSolverInterface *lp = model -> solver () -> clone ();
00032
00033
00034
00035
00036
00037
00038 CoinPackedVector vec;
00039
00040 for (int i = fp -> Problem () -> nVars (), j = 0; i--; ++j) {
00041
00042
00043
00044
00045
00046
00047 bool intVar = lp -> isInteger (j);
00048
00049 if ((isMILP && (intVar || (fp -> compDistInt () == CouenneFeasPump::FP_DIST_ALL)))
00050 ||
00051 (!isMILP && !intVar))
00052
00053 lp -> addCol (vec, 0., COIN_DBL_MAX, 1.);
00054 }
00055
00056
00057
00058
00059
00060
00061 int objInd = fp -> Problem () -> Obj (0) -> Body () -> Index ();
00062
00063 if (objInd >= 0)
00064 lp -> setObjCoeff (objInd, 0.);
00065
00066 return lp;
00067 }
00068
00069
00071 void addDistanceConstraints (const CouenneFeasPump *fp, OsiSolverInterface *lp, double *sol, bool isMILP) {
00072
00073
00074
00075
00076
00077 int n = fp -> Problem () -> nVars ();
00078
00079 CoinPackedVector *P = new CoinPackedVector [n];
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 CoinPackedVector x0 (n, sol);
00103
00104
00105
00106 if (isMILP && (fp -> multObjFMILP () > 0.)) {
00107
00108 int objInd = fp -> Problem () -> Obj (0) -> Body () -> Index ();
00109
00110 if (objInd >= 0)
00111 lp -> setObjCoeff (objInd, fp -> multObjFMILP ());
00112 }
00113
00114 if (isMILP &&
00115 (fp -> multHessMILP () > 0.) &&
00116 (fp -> nlp () -> optHessian ())) {
00117
00118
00119
00120
00121
00122
00123 CouenneSparseMatrix *hessian = fp -> nlp () -> optHessian ();
00124
00125 ComputeSquareRoot (fp, hessian, P);
00126
00127 } else {
00128
00129
00130
00131 for (int i=0; i<n; i++)
00132 P[i].insert (i, 1.);
00133 }
00134
00135
00136
00137 for (int i = 0, j = n, k = j; k--; ++i) {
00138
00139
00140
00141
00142
00143
00144 bool intVar = lp -> isInteger (i);
00145
00146 if ((isMILP && (intVar || (fp -> compDistInt () == CouenneFeasPump::FP_DIST_ALL)))
00147 ||
00148 (!isMILP && !intVar)) {
00149
00150
00151 CoinPackedVector &vec = P [i];
00152
00153 if (vec.getNumElements () == 0)
00154 continue;
00155
00156
00157 double PiX0 = sparseDotProduct (vec, x0);
00158
00159
00160
00161 vec.insert (j, -1.); lp -> addRow (vec, -COIN_DBL_MAX, PiX0);
00162 vec.setElement (vec.getNumElements () - 1, +1.); lp -> addRow (vec, PiX0, COIN_DBL_MAX);
00163
00164 ++j;
00165
00166 } else if (intVar) {
00167
00168
00169
00170 #define INT_LP_BRACKET 0
00171
00172 lp -> setColLower (i, sol [i] - INT_LP_BRACKET);
00173 lp -> setColUpper (i, sol [i] + INT_LP_BRACKET);
00174 }
00175 }
00176
00177 delete [] P;
00178 }
00179
00180
00181 #define GRADIENT_WEIGHT 1
00182
00183 void ComputeSquareRoot (const CouenneFeasPump *fp,
00184 CouenneSparseMatrix *hessian,
00185 CoinPackedVector *P) {
00186 int
00187 objInd = fp -> Problem () -> Obj (0) -> Body () -> Index (),
00188 n = fp -> Problem () -> nVars ();
00189
00190
00191
00192 double *val = hessian -> val ();
00193 int *row = hessian -> row ();
00194 int *col = hessian -> col ();
00195 int num = hessian -> num ();
00196
00197
00198
00199
00200
00201
00202
00203 double maxElem = 0.;
00204
00205 for (int i=num; i--; ++row, ++col, ++val) {
00206
00207
00208
00209 if ((*row == objInd) ||
00210 (*col == objInd))
00211
00212 *val = 0;
00213
00214 else if (fabs (*val) > maxElem)
00215 maxElem = fabs (*val);
00216 }
00217
00218 val -= num;
00219 row -= num;
00220 col -= num;
00221
00222
00223
00224 double *A = (double *) malloc (n*n * sizeof (double));
00225
00226 CoinZeroN (A, n*n);
00227
00228
00229 for (int i=0; i<num; ++i, ++row, ++col, ++val)
00230 if (*col <= *row)
00231 A [*col * n + *row] = fp -> multHessMILP () * *val;
00232
00233
00234 for (int i=0; i<n; ++i)
00235 A [i * (n+1)] += fp -> multDistMILP ();
00236
00237
00238
00239
00240
00241 if (objInd >= 0)
00242 A [objInd * (n+1)] = maxElem * GRADIENT_WEIGHT * n;
00243
00244
00245 double *eigenval = (double *) malloc (n * sizeof (double));
00246 int status;
00247
00248
00249 Ipopt::IpLapackDsyev (true, n, A, n, eigenval, status);
00250
00251 if (status < 0) printf ("Couenne: warning, argument %d illegal\n", -status);
00252 else if (status > 0) printf ("Couenne: warning, dsyev did not converge (error code: %d)\n", status);
00253
00254
00255
00256
00257
00258
00259
00260
00261 double *B = (double *) malloc (n*n * sizeof(double));
00262
00263 double *eigenvec = A;
00264
00265
00266
00267
00268
00269
00270
00271
00272 double
00273 MinEigVal = eigenval [0],
00274 MaxEigVal = eigenval [n-1];
00275
00276 for (int j=1; j<n; j++)
00277 assert (eigenval [j-1] <= eigenval [j]);
00278
00279 if (MaxEigVal <= 0.)
00280
00281
00282
00283
00284
00285 for (int j=0; j<n; j++)
00286 eigenval [j] = 1. / (.1 - eigenval [j]);
00287
00288 else {
00289
00290
00291
00292
00293 MinEigVal = MaxEigVal * COUENNE_EIG_RATIO;
00294
00295 if (eigenval [0] <= MinEigVal)
00296 for (int j=0; eigenval [j] <= MinEigVal; j++)
00297 eigenval [j] = MinEigVal;
00298 }
00299
00300
00301
00302 for (int j=0; j<n; ++j) {
00303
00304 register double sqrtEig = sqrt (eigenval [j]);
00305
00306 for (int i=n; i--;)
00307 *B++ = sqrtEig * eigenvec [i*n+j];
00308 }
00309
00310 B -= n*n;
00311
00312
00313
00314
00315
00316
00317
00318
00319 for (int i=0; i<n; ++i)
00320 for (int j=0; j<n; ++j) {
00321
00322
00323
00324 double elem = 0.;
00325
00326 for (int k=0; k<n; ++k)
00327 elem += B [i + k * n] * eigenvec [j * n + k];
00328
00329 if (fabs (elem) > COUENNE_EPS)
00330 P [i]. insert (j, elem);
00331 }
00332
00333 if (fp -> Problem () -> Jnlst () -> ProduceOutput (Ipopt::J_STRONGWARNING, J_NLPHEURISTIC)) {
00334
00335 printf ("P:\n");
00336
00337
00338 printf ("P^{1/2}:\n");
00339
00340 }
00341
00342 free (eigenval);
00343 free (A);
00344 free (B);
00345 }