00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <set>
00012 #include <stdlib.h>
00013
00014 #include "BonCbc.hpp"
00015 #include "BonBabInfos.hpp"
00016 #include "CoinHelperFunctions.hpp"
00017 #include "CoinPackedMatrix.hpp"
00018 #include "CglCutGenerator.hpp"
00019 #include "CoinTime.hpp"
00020
00021 #include "CouenneTypes.hpp"
00022 #include "CouenneProblemElem.hpp"
00023 #include "CouenneTwoImplied.hpp"
00024 #include "CouenneExprVar.hpp"
00025 #include "CouennePrecisions.hpp"
00026 #include "CouenneProblem.hpp"
00027 #include "CouenneInfeasCut.hpp"
00028 #include "CouenneJournalist.hpp"
00029
00030 using namespace Ipopt;
00031
00032
00033 namespace Couenne {
00034
00036 void updateBranchInfo (const OsiSolverInterface &si, CouenneProblem *p,
00037 t_chg_bounds *chg, const CglTreeInfo &info);
00038
00039
00040
00041 int combine (CouenneProblem *p,
00042 int n1, int n2,
00043 const int *ind1,
00044 const int *ind2,
00045 double *sa1,
00046 double *sa2,
00047 const double *a1,
00048 const double *a2,
00049 double *clb,
00050 double *cub,
00051 double l1,
00052 double l2,
00053 double u1,
00054 double u2,
00055 bool *isInteger,
00056 int sign);
00057
00059 void CouenneTwoImplied::generateCuts (const OsiSolverInterface &si,
00060 OsiCuts &cs,
00061 const CglTreeInfo info) const {
00062
00063
00064
00065
00066
00067 if (isWiped (cs))
00068 return;
00069
00070 double now = CoinCpuTime ();
00071
00072
00073
00074 if ((depthStopSeparate_ >= 0 &&
00075 info.level > depthStopSeparate_)
00076 ||
00077 (depthLevelling_ >= 0 &&
00078 info.level >= depthLevelling_ &&
00079 CoinDrand48 () > 1. / (2. + info.level - depthLevelling_)))
00080 return;
00081
00082 if (info.level <= 0)
00083 jnlst_ -> Printf (J_ERROR, J_COUENNE, "TwoImpl-BT: "); fflush (stdout);
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 problem_ -> domain () -> push (&si, &cs);
00095
00096 static int nBadColMatWarnings = 0;
00097
00098 std::set <std::pair <int, int> > pairs;
00099
00106
00109
00110 #define USE_ROW
00111
00112 #ifdef USE_ROW
00113
00114 const CoinPackedMatrix *mat = si. getMatrixByRow ();
00115
00116 int
00117 m = mat -> getMajorDim (),
00118 n = mat -> getMinorDim ();
00119
00120 #else
00121
00122 const CoinPackedMatrix *mat = si. getMatrixByCol ();
00123
00124 int
00125 n = mat -> getMajorDim (),
00126 m = mat -> getMinorDim ();
00127
00128 #endif
00129
00130 const double
00131 *rlb = si.getRowLower (),
00132 *rub = si.getRowUpper ();
00133
00134 #ifdef USE_ROW
00135
00137
00138 int
00139 nnz = mat -> getNumElements (),
00140 nnzC = 0,
00141 *sta = new int [n+1],
00142 nCuts = cs.sizeRowCuts ();
00143
00144
00145
00146 for (int i=0, ii = cs. sizeRowCuts (); ii--; i++) {
00147
00148 const OsiRowCut *cut = cs. rowCutPtr (i);
00149 const CoinPackedVector &rowCoe = cut -> row ();
00150
00151 nnzC += rowCoe.getNumElements ();
00152 }
00153
00154 int *ind = new int [nnz + nnzC];
00155 double *A = new double [nnz + nnzC];
00156
00158 {
00159 const double
00160 *rA = mat -> getElements ();
00161
00162 const int
00163 *rInd = mat -> getIndices (),
00164 *rSta = mat -> getVectorStarts ();
00165
00166
00167
00168 CoinZeroN (sta, n+1);
00169
00171
00172
00173
00174 for (int i=nnz; i--;)
00175 ++ (sta [1 + *rInd++]);
00176
00177
00178
00179 for (int i=0, ii = cs. sizeRowCuts (); ii--; i++) {
00180
00181 const OsiRowCut *cut = cs. rowCutPtr (i);
00182 const CoinPackedVector &rowCoe = cut -> row ();
00183 const int *indices = rowCoe.getIndices ();
00184 int nnz = rowCoe.getNumElements ();
00185
00186
00187 for (int i=nnz; i--;)
00188 ++ (sta [1 + *indices++]);
00189 }
00190
00191 rInd -= nnz;
00192
00194
00195
00196
00197 for (int i=1; i<=n; i++)
00198 sta [i] += sta [i-1];
00199
00200
00201
00202
00203 for (int i=0; i<m; i++) {
00204
00205
00206
00207 int rowStart = rSta [i];
00208
00209 for (int j = rowStart, jj = rSta [i+1] - rowStart; jj--; j++) {
00210
00211 int &curSta = sta [rInd [j]];
00212
00213 ind [curSta] = i;
00214 A [curSta++] = rA [j];
00215 }
00216
00217
00218 }
00219
00220
00221
00222 for (int i=0, ii = cs. sizeRowCuts (); ii--; i++) {
00223
00224 const OsiRowCut *cut = cs. rowCutPtr (i);
00225
00226
00227 const CoinPackedVector &rowCoe = cut -> row ();
00228 const int *indices = rowCoe.getIndices ();
00229 const double *elements = rowCoe.getElements ();
00230 int nnz = rowCoe.getNumElements ();
00231
00232
00233 for (int j=nnz; j--;) {
00234
00235
00236
00237 int &curSta = sta [*indices++];
00238
00239 ind [curSta] = m+i;
00240 A [curSta++] = *elements++;
00241 }
00242
00243 }
00244
00245 for (int i=n; --i;)
00246 sta [i] = sta [i-1];
00247
00248 sta [0] = 0;
00249
00250
00251 }
00252
00253 #else
00254
00255 const double
00256 *A = mat -> getElements ();
00257
00258 const int
00259 *ind = mat -> getIndices (),
00260 *sta = mat -> getVectorStarts ();
00261
00262 #endif
00263
00266
00267 bool *isInteger = new bool [n];
00268 for (int i=0, ii=n; ii--; i++)
00269 *isInteger++ = problem_ -> Var (i) -> isInteger ();
00270 isInteger -= n;
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 double
00295 *sa1 = new double [n],
00296 *sa2 = new double [n];
00297
00298 CoinFillN (sa1, n, 0.);
00299 CoinFillN (sa2, n, 0.);
00300
00301 for (int i=0; i<n; i++, sta++) {
00302
00303
00304
00305 for (int jj = *(sta+1) - *sta, j = *sta; jj--; j++)
00306 for (int kk = jj, k = j+1; kk--; k++) {
00307
00308 if (CoinCpuTime () > problem_ -> getMaxCpuTime ())
00309 break;
00310
00311 register int
00312 indj = ind [j],
00313 indk = ind [k];
00314
00315
00316
00317
00318 if ((indj >= m + nCuts) || (indj < 0) ||
00319 (indk >= m + nCuts) || (indk < 0)) {
00320
00321 if (nBadColMatWarnings++ < 1)
00322
00323 printf ("\
00324 Couenne: warning, matrix by row has nonsense indices.\n\
00325 This separator will now return without (column) cuts.\n\
00326 NOTE: further such inconsistencies won't be reported.\n");
00327
00328 delete [] sa1;
00329 delete [] sa2;
00330
00331 delete [] sta;
00332 delete [] ind;
00333 delete [] A;
00334
00335 delete [] isInteger;
00336
00337 problem_ -> domain () -> pop ();
00338
00339 totalTime_ += CoinCpuTime () - now;
00340 totalInitTime_ += CoinCpuTime () - now;
00341
00342 return;
00343 }
00344
00345 double
00346 prod = A [j] * A [k],
00347 rlbj, rubj, rlbk, rubk;
00348
00349 if (indj>=m) {
00350 OsiRowCut *cut = cs.rowCutPtr (indj-m);
00351 rlbj = cut -> lb ();
00352 rubj = cut -> ub ();
00353 } else {
00354 rlbj = rlb [indj];
00355 rubj = rub [indj];
00356 }
00357
00358 if (indk>=m) {
00359 OsiRowCut *cut = cs.rowCutPtr (indk-m);
00360 rlbk = cut -> lb ();
00361 rubk = cut -> ub ();
00362 } else {
00363 rlbk = rlb [indk];
00364 rubk = rub [indk];
00365 }
00366
00367 if (prod > 0.) {
00368
00369
00370
00371
00372 if (!(((rlbj > -COUENNE_INFINITY/10) && (rubk < COUENNE_INFINITY/10)) ||
00373 ((rubj < COUENNE_INFINITY/10) && (rlbk > -COUENNE_INFINITY/10))))
00374
00375 continue;
00376
00377 } else
00378
00379 if ((prod < 0.) &&
00380
00381 !(((rlbj > -COUENNE_INFINITY/10) && (rlbk > -COUENNE_INFINITY/10)) ||
00382 ((rubj < COUENNE_INFINITY/10) && (rubk < COUENNE_INFINITY/10))))
00383
00384 continue;
00385
00386 pairs.insert (std::pair <int, int> (indj, indk));
00387 }
00388 }
00389
00390
00391
00392 #ifdef USE_ROW
00393 const CoinPackedMatrix *rowA = mat;
00394 #else
00395 const CoinPackedMatrix *rowA = si. getMatrixByRow ();
00396 #endif
00397
00398 const double
00399 *rA = rowA -> getElements ();
00400
00401
00402
00403 double
00404 *clb = CoinCopyOfArray (problem_ -> Lb (), n),
00405 *cub = CoinCopyOfArray (problem_ -> Ub (), n),
00406 *oldLB = CoinCopyOfArray (problem_ -> Lb (), n),
00407 *oldUB = CoinCopyOfArray (problem_ -> Ub (), n);
00408
00409 const int
00410 *rInd = rowA -> getIndices (),
00411 *rSta = rowA -> getVectorStarts ();
00412
00413 int
00414 ntightened = 0,
00415 ntrials = 0,
00416 nCurTightened;
00417
00418
00419
00420 Bonmin::BabInfo * babInfo = dynamic_cast <Bonmin::BabInfo *> (si.getAuxiliaryInfo ());
00421
00422 int result = 0;
00423
00424
00425
00426 t_chg_bounds *chg_bds = new t_chg_bounds [n];
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436 updateBranchInfo (si, problem_, chg_bds, info);
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449 do {
00450
00451 nCurTightened = 0;
00452
00453
00454
00455
00456 for (std::set <std::pair <int, int> >:: iterator p = pairs.begin (); p != pairs.end (); ++p) {
00457
00458 if (CoinCpuTime () > problem_ -> getMaxCpuTime ())
00459 break;
00460
00461
00462
00463 int
00464 h = p -> first,
00465 k = p -> second,
00466 n1, n2;
00467
00468 double l1, u1, l2, u2;
00469
00470 const double *a1, *a2;
00471
00472 const int *ind1, *ind2;
00473
00474
00475
00476
00477 if (h>=m) {
00478
00479 const OsiRowCut *cut = cs.rowCutPtr (h-m);
00480 const CoinPackedVector &rowCoe = cut -> row ();
00481
00482 l1 = cut -> lb ();
00483 u1 = cut -> ub ();
00484 n1 = rowCoe. getNumElements ();
00485 ind1 = rowCoe. getIndices ();
00486 a1 = rowCoe. getElements ();
00487
00488 } else {
00489
00490 l1 = rlb [h];
00491 u1 = rub [h];
00492 n1 = rSta [h+1] - rSta [h];
00493 ind1 = rInd + rSta [h];
00494 a1 = rA + rSta [h];
00495 }
00496
00498
00499 if (k>=m) {
00500
00501 OsiRowCut *cut = cs.rowCutPtr (k-m);
00502 const CoinPackedVector &rowCoe = cut -> row ();
00503
00504 l2 = cut -> lb ();
00505 u2 = cut -> ub ();
00506 n2 = rowCoe. getNumElements ();
00507 ind2 = rowCoe. getIndices ();
00508 a2 = rowCoe. getElements ();
00509
00510 } else {
00511
00512 l2 = rlb [k];
00513 u2 = rub [k];
00514 n2 = rSta [k+1] - rSta [k];
00515 ind2 = rInd + rSta [k];
00516 a2 = rA + rSta [k];
00517 }
00518
00519
00520
00521
00522
00523 if ((h < m) && (k < m) && !firstCall_) {
00524
00525 bool new_bound = false;
00526
00527 for (int i=n1; i--;) {
00528
00529 t_chg_bounds &chg = chg_bds [ind1 [i]];
00530
00531 if ((chg. lower () != t_chg_bounds::UNCHANGED) ||
00532 (chg. upper () != t_chg_bounds::UNCHANGED))
00533
00534 new_bound = true;
00535 }
00536
00537 if (!new_bound)
00538 for (int i=n2; i--;) {
00539
00540 t_chg_bounds &chg = chg_bds [ind2 [i]];
00541
00542 if ((chg. lower () != t_chg_bounds::UNCHANGED) ||
00543 (chg. upper () != t_chg_bounds::UNCHANGED))
00544
00545 new_bound = true;
00546 }
00547
00548 if (!new_bound) continue;
00549 }
00550
00551
00552
00553 for (int i=n1; i--;) sa1 [ind1 [i]] = a1 [i];
00554 for (int i=n2; i--;) sa2 [ind2 [i]] = a2 [i];
00555
00556
00557
00558
00559
00560
00561
00562 if ((u1 < COUENNE_INFINITY && u2 < COUENNE_INFINITY) ||
00563 (l1 > - COUENNE_INFINITY && l2 > - COUENNE_INFINITY))
00564
00565 result = combine (problem_, n1, n2, ind1, ind2, sa1, sa2, a1, a2, clb, cub, l1, l2, u1, u2, isInteger, 1);
00566
00567 if (result < 0)
00568 break;
00569
00570 nCurTightened += result;
00571 result = 0;
00572
00573
00574 for (int i=n2; i--;)
00575 sa2 [ind2 [i]] = - a2 [i];
00576
00577 if ((u1 < COUENNE_INFINITY && l2 > - COUENNE_INFINITY) ||
00578 (l1 > - COUENNE_INFINITY && u2 < COUENNE_INFINITY))
00579
00580
00581 result = combine (problem_, n1, n2, ind1, ind2, sa1, sa2, a1, a2, clb, cub, l1, l2, u1, u2, isInteger, -1);
00582
00583 if (result < 0)
00584 break;
00585
00586 nCurTightened += result;
00587
00588
00589
00590 for (int i=n1; i--;) sa1 [ind1 [i]] = 0.;
00591 for (int i=n2; i--;) sa2 [ind2 [i]] = 0.;
00592 }
00593
00594 if (result < 0)
00595 break;
00596
00597 int objInd = problem_ -> Obj (0) -> Body () -> Index ();
00598
00599 if (nCurTightened &&
00600 (objInd >= 0) &&
00601 babInfo &&
00602 babInfo -> babPtr ()) {
00603
00604 #ifdef DEBUG
00605 printf ("FBBT\n");
00606 #endif
00607
00608 CouNumber
00609 UB = babInfo -> babPtr () -> model (). getObjValue(),
00610 LB = babInfo -> babPtr () -> model (). getBestPossibleObjValue (),
00611 primal0 = problem_ -> Ub (objInd),
00612 dual0 = problem_ -> Lb (objInd);
00613
00614
00615
00616 if ((UB < COUENNE_INFINITY) &&
00617 (UB < primal0 - COUENNE_EPS)) {
00618
00619 problem_ -> Ub (objInd) = UB;
00620 chg_bds [objInd].setUpper (t_chg_bounds::CHANGED);
00621 }
00622
00623 if ((LB > - COUENNE_INFINITY) &&
00624 (LB > dual0 + COUENNE_EPS)) {
00625 problem_ -> Lb (objInd) = LB;
00626 chg_bds [objInd].setLower (t_chg_bounds::CHANGED);
00627 }
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653 if (!(problem_ -> btCore (chg_bds))) {
00654
00655
00656
00657 result = -1;
00658 break;
00659
00660 } else {
00661
00662
00663
00664 for (int i=0; i<n; i++) {
00665
00666 if (problem_ -> Lb (i) > clb [i] + COUENNE_EPS) clb [i] = problem_ -> Lb (i);
00667 if (problem_ -> Ub (i) < cub [i] - COUENNE_EPS) cub [i] = problem_ -> Ub (i);
00668 }
00669 }
00670 }
00671
00672 ntightened += nCurTightened;
00673
00674 } while (++ntrials < nMaxTrials_ && nCurTightened);
00675
00676 totalInitTime_ += CoinCpuTime () - now;
00677
00678
00679
00680 if (result >= 0 && ntightened) {
00681
00682
00683
00684 int
00685 *indLB = new int [n],
00686 *indUB = new int [n],
00687 ntightenedL = 0,
00688 ntightenedU = 0;
00689
00690 double
00691 *valLB = new double [n],
00692 *valUB = new double [n];
00693
00694 for (int i=0; i<n; i++) {
00695
00696 if (clb [i] > oldLB [i]) {
00697
00698 if (problem_ -> bestSol () &&
00699 problem_ -> bestSol () [i] > oldLB [i] &&
00700 problem_ -> bestSol () [i] < clb [i] - 1e-12) {
00701
00702 jnlst_ -> Printf (J_ERROR, J_COUENNE,
00703 "Warning, twoImplBounds new LB cuts optimal solution: LB x_%d = %g --> %g, opt %g (diff: %g)\n",
00704 i, oldLB [i], clb [i], problem_ -> bestSol () [i], clb [i] - problem_ -> bestSol () [i]);
00705
00706 }
00707
00708
00709 indLB [ntightenedL] = i;
00710 valLB [ntightenedL++] = clb [i];
00711 }
00712
00713 if (cub [i] < oldUB [i]) {
00714
00715 if (problem_ -> bestSol () &&
00716 problem_ -> bestSol () [i] < oldUB [i] &&
00717 problem_ -> bestSol () [i] > cub [i] + 1e-12) {
00718
00719 jnlst_ -> Printf (J_ERROR, J_COUENNE,
00720 "Warning, twoImplBounds new UB cuts optimal solution: UB x_%d = %g --> %g, opt %g (diff: %g)\n",
00721 i, oldUB [i], cub [i], problem_ -> bestSol () [i], problem_ -> bestSol () [i] - cub [i]);
00722
00723 }
00724
00725
00726 indUB [ntightenedU] = i;
00727 valUB [ntightenedU++] = cub [i];
00728 }
00729 }
00730
00731 if (ntightenedL || ntightenedU) {
00732
00733 OsiColCut newBound;
00734
00735 newBound.setLbs (ntightenedL, indLB, valLB);
00736 newBound.setUbs (ntightenedU, indUB, valUB);
00737
00738
00739
00740 cs.insert (newBound);
00741 }
00742
00743 delete [] indLB;
00744 delete [] indUB;
00745 delete [] valLB;
00746 delete [] valUB;
00747
00748 ntightened = ntightenedL + ntightenedU;
00749 }
00750
00751 else
00752
00753 if (result < 0)
00754 WipeMakeInfeas (cs);
00755
00756 delete [] clb;
00757 delete [] cub;
00758 delete [] oldLB;
00759 delete [] oldUB;
00760 delete [] sa1;
00761 delete [] sa2;
00762 delete [] chg_bds;
00763
00764 delete [] isInteger;
00765
00766 problem_ -> domain () -> pop ();
00767
00768 #ifdef USE_ROW
00769 delete [] A;
00770 delete [] ind;
00771 delete [] (sta-n);
00772 #endif
00773
00774 if (firstCall_)
00775 firstCall_ = false;
00776
00777 totalTime_ += CoinCpuTime () - now;
00778
00779 if (info.level <= 0)
00780 jnlst_ -> Printf (J_ERROR, J_COUENNE, "%d improved bounds\n", ntightened);
00781 }
00782 }