00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "stdlib.h"
00012 #include "stdio.h"
00013 #include "math.h"
00014
00015 #include "CoinTime.hpp"
00016 #include "CoinHelperFunctions.hpp"
00017
00018 #include "CouenneExprVar.hpp"
00019 #include "CouenneExprClone.hpp"
00020 #include "operators/CouenneExprMul.hpp"
00021 #include "CouenneProblem.hpp"
00022 #include "CouenneMatrix.hpp"
00023 #include "CouenneSdpCuts.hpp"
00024
00025 #include "dsyevx_wrapper.hpp"
00026
00027
00028
00029 const bool WISE_SPARSIFY = true;
00030
00031 #define SPARSIFY_MAX_CARD 10000
00032 #define SPARSIFY_NEW_NZ_THRESHOLD 0.70
00033
00034 #define EV_TOL 1e-13
00035
00036 using namespace Couenne;
00037
00038
00039
00040 void CouenneSdpCuts::generateCuts (const OsiSolverInterface &si, OsiCuts &cs,
00041 const CglTreeInfo info)
00042 #if CGL_VERSION_MAJOR == 0 && CGL_VERSION_MINOR <= 57
00043 const
00044 #endif
00045 {
00046
00047
00048
00049 if ((info . level + info . pass > 4)) return;
00050
00051 problem_ -> domain () -> push (&si, &cs);
00052
00053 for (std::vector <CouenneExprMatrix *>::const_iterator
00054 minor = minors_. begin ();
00055 minor != minors_. end (); ++minor)
00056
00057 genCutSingle (*minor, si, cs, info);
00058
00059 problem_ -> domain () -> pop ();
00060 }
00061
00062
00063
00064 void CouenneSdpCuts::genCutSingle (CouenneExprMatrix * const & minor,
00065 const OsiSolverInterface &si,
00066 OsiCuts &cs,
00067 const CglTreeInfo info) const {
00068 #ifdef DEBUG
00069 printf ("Generating cut on minor -> ");
00070 minor -> print ();
00071 #endif
00072
00073 std::vector <expression *> &varInd = minor -> varIndices ();
00074
00075 int
00076 n = (int) (minor -> size ()),
00077 m,
00078 nVecs = (numEigVec_ < 0) ? n : numEigVec_,
00079
00080 **indA = new int * [n],
00081 *indMap = new int [problem_ -> nVars ()],
00082
00083 compressed_index = 0;
00084
00085 double
00086 *A = new double [n * n];
00087
00088
00089 for (std::vector <expression *>::const_iterator
00090 i = varInd . begin ();
00091 i != varInd . end (); ++i)
00092 indMap [(*i) -> Index ()] = compressed_index++;
00093
00094
00095
00096 for (int i=0; i<n; ++i)
00097 CoinFillN (indA [i] = new int [n], n, -2);
00098
00099
00100
00101
00102
00103 CoinFillN (A, n * n, 0.);
00104
00105 #ifdef DEBUG
00106 printf ("Components\n\n");
00107 #endif
00108
00109 int indI = 0;
00110
00111 for (std::set <std::pair <int, CouenneSparseVector *>, CouenneExprMatrix::compare_pair_ind>::const_iterator
00112 i = minor -> getRows () . begin ();
00113 i != minor -> getRows () . end (); ++i, ++indI) {
00114
00115 #ifdef DEBUG
00116 printf ("row %d [var %d]: ", indI, i -> first); fflush (stdout);
00117 #endif
00118
00119 int
00120 majInd = (i -> first == problem_ -> nVars ()) ? n-1 : indMap [i -> first],
00121 indJ = 0;
00122
00123 for (std::set <CouenneScalar *, CouenneSparseVector::compare_scalars>::const_iterator
00124 j = i -> second -> getElements () . begin ();
00125 j != i -> second -> getElements () . end (); ++j, ++indJ) {
00126
00127 #ifdef DEBUG
00128 printf ("[r%d,v%d,%d,%g,", indJ,
00129 (*j) -> getIndex (),
00130 (*j) -> getElem () -> Index (),
00131 (*((*j) -> getElem ())) ());
00132 (*j) -> getElem () -> print (); printf ("] ");
00133 fflush (stdout);
00134 #endif
00135
00136 int minInd = ((*j) -> getIndex () == problem_ -> nVars ()) ? (n-1) : (indMap [(*j) -> getIndex ()]);
00137
00138 expression *Elem = (*j) -> getElem ();
00139
00140 A [majInd * n + minInd] = (*Elem) ();
00141
00142
00143 indA [majInd] [minInd] = Elem -> Index ();
00144
00145 }
00146
00147 #ifdef DEBUG
00148 printf ("\n");
00149 #endif
00150 }
00151
00152 delete [] indMap;
00153
00154
00155
00156 for (int i=0; i<n-1; ++i)
00157 for (int j=i; j<n-1; ++j)
00158 if (indA [i] [j] == -2)
00159 A [i * n + j] =
00160 A [j * n + i] =
00161 (*(varInd [i])) () *
00162 (*(varInd [j])) ();
00163
00164 #ifdef DEBUG
00165 for (int i=0; i<n; ++i) {
00166 for (int j=0; j<n; ++j)
00167 printf ("[%4d,%7.2g] ", indA [i][j], A [i * n + j]);
00168 printf ("\n");
00169 }
00170 #endif
00171
00172 double
00173 *Acopy = useSparsity_ ? CoinCopyOfArray (A, n * n) : NULL,
00174 *w = NULL,
00175 *z = NULL;
00176
00177
00178
00179
00180 dsyevx_interface (n, A, m, w, z, EV_TOL,
00181 -COIN_DBL_MAX, onlyNegEV_ ? 0. : COIN_DBL_MAX,
00182 1, numEigVec_ < 0 ? n : numEigVec_);
00183
00184
00185 if (m < nVecs)
00186 nVecs = m;
00187
00188 double
00189 **work_ev = new double * [m];
00190
00191 for (int i=0; i < nVecs; i++) {
00192
00193 if (w [i] >= 0) {
00194 nVecs = i;
00195 break;
00196 }
00197
00198 work_ev [i] = z + (i*n);
00199
00200 #ifdef SCALE_EIGENV
00201 double scaling_factor = sqrt (n);
00202
00203 for (int j=0; j<n; j++)
00204 work_ev [i] [j] *= scaling_factor;
00205 #endif
00206 }
00207
00208
00209
00210 for (int i=0; i<nVecs; i++)
00211 genSDPcut (si, cs, minor, work_ev [i], work_ev [i], indA);
00212
00213 int
00214 wise_evdec_num = 0,
00215 card_sparse_v_mat = 0,
00216 min_nz;
00217
00218 double **sparse_v_mat = NULL;
00219
00220 if (useSparsity_) {
00221
00222 sparse_v_mat = new double*[SPARSIFY_MAX_CARD];
00223 for (int i=0; i<SPARSIFY_MAX_CARD; i++)
00224 sparse_v_mat[i] = new double [n];
00225
00226 min_nz = ceil (n * SPARSIFY_NEW_NZ_THRESHOLD);
00227 card_sparse_v_mat = 0;
00228
00229 sparsify2 (n, A, sparse_v_mat, &card_sparse_v_mat, min_nz, &wise_evdec_num);
00230
00231 for (int k=0; k < card_sparse_v_mat; k++)
00232 genSDPcut (si, cs, minor, sparse_v_mat [k], sparse_v_mat [k], indA);
00233
00235
00236 for (int i=0; i<nVecs; ++i) {
00237
00238 card_sparse_v_mat = 0;
00239 double *v = work_ev[i];
00240
00241 sparsify (WISE_SPARSIFY, i, w [i], v, n, Acopy, sparse_v_mat, &card_sparse_v_mat, &wise_evdec_num);
00242
00243 for (int k=0; k < card_sparse_v_mat; k++) {
00244
00245 genSDPcut (si, cs, minor, sparse_v_mat [k], sparse_v_mat [k], indA);
00246
00247 if (useSparsity_)
00248 additionalSDPcuts (si, cs, minor, n, Acopy, sparse_v_mat[k], indA);
00249 }
00250 }
00251 }
00252
00253 for (int i=0; i<n; ++i)
00254 delete [] indA [i];
00255 delete [] indA;
00256
00257 if (useSparsity_) {
00258
00259 for (int i=0; i < SPARSIFY_MAX_CARD; i++)
00260 delete [] sparse_v_mat[i];
00261
00262 delete [] sparse_v_mat;
00263 delete [] Acopy;
00264 }
00265
00266 delete [] z;
00267 delete [] w;
00268 delete [] A;
00269 delete [] work_ev;
00270 }
00271
00272
00273
00274 void CouenneSdpCuts::genSDPcut (const OsiSolverInterface &si,
00275 OsiCuts &cs,
00276 CouenneExprMatrix *XX,
00277 double *v1, double *v2,
00278 int **indA) const {
00279 int
00280 nterms = 0,
00281 n = (int) (XX -> size ()),
00282 nvars = problem_ -> nVars (),
00283 N = n * n,
00284 *ind = new int [N],
00285 *inverse = new int [nvars];
00286
00287 double
00288 *coeff = new double [N],
00289 *xtraC = new double [nvars],
00290 rhs = 0.;
00291
00292 std::vector <expression *> &varIndices = XX -> varIndices ();
00293
00294 CoinFillN (xtraC, nvars, 0.);
00295 CoinFillN (inverse, nvars, -1);
00296
00297
00298
00299
00300
00301
00302 #ifdef DEBUG
00303 printf ("Solution: (");
00304 for (int i=0; i<n; i++) {
00305 if (i) printf (",");
00306 printf ("%g", v1 [i]);
00307 }
00308 printf (")\n");
00309 #endif
00310
00311
00312
00313 bool numerics_flag = false;
00314
00315
00316 for (int i=0; (i<n) && !numerics_flag; i++)
00317
00318 for (int j=i; j<n; j++) {
00319
00320 double coeff0 = v1 [i] * v2 [j] + v1 [j] * v2 [i];
00321
00322 if (fabs (coeff0) < 1e-21) continue;
00323
00324 int index = indA [i] [j];
00325
00326 #ifdef DEBUG
00327 printf ("{%d,%g} ", index, coeff0);
00328 #endif
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 #ifdef DEBUG
00341 if (index == -1) printf ("found constant: %g\n", (i==j) ? coeff0 / 2 : coeff0);
00342 #endif
00343 if (index == -1)
00344
00345 rhs -= ((i==j) ? coeff0 / 2 : coeff0);
00346
00347 else if (index < -1) {
00348
00349 expression
00350 *Xi = XX -> varIndices () [i],
00351 *Xj = XX -> varIndices () [j];
00352
00353 double
00354 valXi = (*Xi) (),
00355 valXj = (*Xj) (),
00356 li, lj,
00357 ui, uj,
00358 L, U;
00359
00360 Xi -> getBounds (li, ui);
00361 Xj -> getBounds (lj, uj);
00362
00363 #ifdef DEBUG
00364 printf ("expression: x%d [%g,%g] * x%d [%g,%g]\n",
00365 Xi -> Index (), li, ui,
00366 Xj -> Index (), lj, uj);
00367 #endif
00368
00369 if (i==j) {
00370
00371
00372
00373
00374
00375
00376 if ((fabs (li) > COUENNE_INFINITY) ||
00377 (fabs (ui) > COUENNE_INFINITY)) {
00378
00379
00380
00381
00382 numerics_flag = true;
00383 break;
00384 }
00385
00386 xtraC [varIndices [i] -> Index ()] += coeff0 / 2 * (li + ui);
00387 #ifdef DEBUG
00388 printf ("adding %g=%g*(%g+%g) (sq) to xtrac[%d=varInd[%d]]\n",
00389 coeff0 / 2 * (li + ui), coeff0, li, ui, varIndices [i] -> Index (), i);
00390 #endif
00391 rhs += coeff0 / 2 * (li * ui);
00392
00393 } else {
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408 exprMul Xij (new exprClone (Xi),
00409 new exprClone (Xj));
00410
00411 Xij . getBounds (L, U);
00412
00413 double
00414 rhsMll = lj * valXi + li * valXj - lj * li,
00415 rhsMuu = uj * valXi + ui * valXj - uj * ui;
00416
00417 if (coeff0 < 0) {
00418
00419 if (L >= CoinMax (rhsMll, rhsMuu))
00420
00421 rhs -= coeff0 * L;
00422
00423 else if (rhsMuu > rhsMll) {
00424
00425 if ((fabs (ui) > COUENNE_INFINITY) ||
00426 (fabs (uj) > COUENNE_INFINITY)) {
00427 numerics_flag = true;
00428 break;
00429 }
00430
00431 xtraC [varIndices [i] -> Index ()] += coeff0 * uj;
00432 xtraC [varIndices [j] -> Index ()] += coeff0 * ui;
00433 rhs += coeff0 * uj * ui;
00434
00435 #ifdef DEBUG
00436 printf ("adding (%g,%g) = %g*(%g,%g) (rhsMuu) to xtrac[%d=varInd[%d]] and xtrac[%d=varInd[%d]]\n",
00437 coeff0 * uj, coeff0 * ui, coeff0, uj, ui, varIndices [i] -> Index (), i, varIndices [j] -> Index (), j);
00438 #endif
00439 } else {
00440
00441 if ((fabs (li) > COUENNE_INFINITY) ||
00442 (fabs (lj) > COUENNE_INFINITY)) {
00443
00444 numerics_flag = true;
00445 break;
00446 }
00447
00448 xtraC [varIndices [i] -> Index ()] += coeff0 * lj;
00449 xtraC [varIndices [j] -> Index ()] += coeff0 * li;
00450 rhs += coeff0 * lj * li;
00451
00452 #ifdef DEBUG
00453 printf ("adding (%g,%g) = %g*(%g,%g) (rhsMll) to xtrac[%d=varInd[%d]] and xtrac[%d=varInd[%d]]\n",
00454 coeff0 * lj, coeff0 * li, coeff0, lj, li, varIndices [i] -> Index (), i, varIndices [j] -> Index (), j);
00455 #endif
00456 }
00457
00458 } else {
00459
00460 double
00461 rhsMlu = lj * valXi + ui * valXj - lj * ui,
00462 rhsMul = uj * valXi + li * valXj - uj * li;
00463
00464 if (U <= CoinMin (rhsMlu, rhsMul))
00465
00466 rhs -= coeff0 * U;
00467
00468 else if (rhsMul < rhsMlu) {
00469
00470 if ((fabs (li) > COUENNE_INFINITY) ||
00471 (fabs (uj) > COUENNE_INFINITY)) {
00472
00473 numerics_flag = true;
00474 break;
00475 }
00476
00477 xtraC [varIndices [i] -> Index ()] += coeff0 * uj;
00478 xtraC [varIndices [j] -> Index ()] += coeff0 * li;
00479 rhs += coeff0 * uj * li;
00480
00481 #ifdef DEBUG
00482 printf ("adding (%g,%g) = %g*(%g,%g) (rhsMul) to xtrac[%d=varInd[%d]] and xtrac[%d=varInd[%d]]\n",
00483 coeff0 * uj, coeff0 * li, coeff0, uj, li, varIndices [i] -> Index (), i, varIndices [j] -> Index (), j);
00484 #endif
00485
00486 } else {
00487
00488 if ((fabs (ui) > COUENNE_INFINITY) ||
00489 (fabs (lj) > COUENNE_INFINITY)) {
00490
00491 numerics_flag = true;
00492 break;
00493 }
00494
00495 xtraC [varIndices [i] -> Index ()] += coeff0 * lj;
00496 xtraC [varIndices [j] -> Index ()] += coeff0 * ui;
00497 rhs += coeff0 * lj * ui;
00498
00499 #ifdef DEBUG
00500 printf ("adding (%g,%g) = %g*(%g,%g) (rhsMlu) to xtrac[%d=varInd[%d]] and xtrac[%d=varInd[%d]]\n",
00501 coeff0 * lj, coeff0 * ui, coeff0, lj, ui, varIndices [i] -> Index (), i, varIndices [j] -> Index (), j);
00502 #endif
00503 }
00504 }
00505 }
00506
00508
00509 } else {
00510
00511 #ifdef DEBUG
00512 printf ("normal term: %g x_%d [terms:%d]\n", (i==j) ? (0.5 * coeff0) : (coeff0), index, nterms);
00513 #endif
00514
00515 if (inverse [index] >= 0)
00516 coeff [inverse [index]] += (i==j) ? (0.5 * coeff0) : (coeff0);
00517 else {
00518
00519 coeff [nterms] = (i==j) ? (0.5 * coeff0) : (coeff0);
00520
00521
00522
00523 inverse [index] = nterms;
00524 ind [nterms++] = index;
00525 }
00526 }
00527 #ifdef DEBUG
00528 printf ("%d terms so far\n", nterms);
00529 #endif
00530 }
00531
00532 if (!numerics_flag)
00533 for (std::vector <expression *>::iterator
00534 i = varIndices . begin ();
00535 i != varIndices . end (); ++i) {
00536
00537 int varInd = (*i) -> Index ();
00538
00539 if ((inverse [varInd] >= 0) &&
00540 (fabs (xtraC [varInd]) > 1e-15)) {
00541 #ifdef DEBUG
00542 printf ("now adding %g to coeff [inv [%d] = %d]\n", xtraC [varInd], varInd, inverse [varInd]);
00543 #endif
00544 coeff [inverse [varInd]] += xtraC [varInd];
00545 } else if (fabs (xtraC [varInd]) > COUENNE_EPS) {
00546
00547 coeff [nterms] = xtraC [varInd];
00548 inverse [varInd] = nterms;
00549 ind [nterms++] = varInd;
00550 }
00551 }
00552
00553 delete [] inverse;
00554 delete [] xtraC;
00555
00556 if (!numerics_flag) {
00557
00558 OsiRowCut *cut = new OsiRowCut;
00559 cut -> setRow (nterms, ind, coeff);
00560 cut -> setLb (rhs);
00561
00562 if (nterms > 0) {
00563
00564 #ifdef DEBUG
00565 printf ("SDP: separating ");
00566 cut -> print ();
00567 #endif
00568
00569 CoinAbsFltEq treatAsSame (COUENNE_EPS);
00570 cs.insertIfNotDuplicate (*cut, treatAsSame);
00571
00572 double violation = 0.;
00573
00574 if (problem_ -> bestSol () && ((violation = cut -> violated (problem_ -> bestSol ())) > 0.)) {
00575
00576 printf ("Cut violates optimal solution by %g\n", violation);
00577 cut -> print ();
00578 }
00579 }
00580
00581 delete cut;
00582 }
00583
00584 delete [] ind;
00585 delete [] coeff;
00586 }