source: trunk/Couenne/src/bound_tightening/twoImpliedBT/TwoImpliedGenCuts.cpp @ 939

Last change on this file since 939 was 939, checked in by pbelotti, 8 years ago

cosmetic changes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.3 KB
Line 
1/* $Id: TwoImpliedGenCuts.cpp 939 2013-01-12 19:53:30Z pbelotti $
2 *
3 * Name:    TwoImpliedGenCuts.cpp
4 * Author:  Pietro Belotti
5 * Purpose: bound reduction using two inequalities from the LP relaxation
6 *
7 * (C) Pietro Belotti, 2010.
8 * This file is licensed under the Eclipse Public License (EPL)
9 */
10
11#include <set>
12#include <stdlib.h>
13
14#include "BonCbc.hpp"
15#include "BonBabInfos.hpp"
16#include "CoinHelperFunctions.hpp"
17#include "CoinPackedMatrix.hpp"
18#include "CglCutGenerator.hpp"
19#include "CoinTime.hpp"
20
21#include "CouenneTypes.hpp"
22#include "CouenneProblemElem.hpp"
23#include "CouenneTwoImplied.hpp"
24#include "CouenneExprVar.hpp"
25#include "CouennePrecisions.hpp"
26#include "CouenneProblem.hpp"
27#include "CouenneInfeasCut.hpp"
28#include "CouenneJournalist.hpp"
29
30using namespace Ipopt;
31
32// necessary to make updateBranchInfo visible
33namespace Couenne {
34
35/// get new bounds from parents' bounds + branching rules
36void updateBranchInfo (const OsiSolverInterface &si, CouenneProblem *p, 
37                       t_chg_bounds *chg, const CglTreeInfo &info);
38
39// do single pair of inequalities. Return < 0 if infeasible
40
41int combine (CouenneProblem *p,
42             int n1, int n2, 
43             const int *ind1, // indices
44             const int *ind2, 
45             double *sa1, // coeff (sparse array)
46             double *sa2,
47             const double *a1,  // coeff
48             const double *a2, 
49             double *clb, // variable bounds
50             double *cub,
51             double l1, // constraint bounds
52             double l2, 
53             double u1, 
54             double u2, 
55             bool *isInteger,
56             int sign); // invert second constraint? -1: yes, +1: no
57
58/// the main CglCutGenerator
59void CouenneTwoImplied::generateCuts (const OsiSolverInterface &si, 
60                                      OsiCuts &cs, 
61                                      const CglTreeInfo info) const {
62
63  // don't perform this is cs has been added an infeasible cut (a
64  // result of some bound tightening procedure discovering an
65  // infeasible node)
66
67  if (isWiped (cs))
68    return;
69
70  double now = CoinCpuTime ();
71
72  // a more elaborate scheme to avoid heavy use of this heavy procedure
73
74  if ((depthStopSeparate_ >= 0 &&           // if -1, there is no limit on depth
75       info.level > depthStopSeparate_)     // otherwise, check if too deep for adding these cuts
76      ||
77      (depthLevelling_ >= 0 &&              // chance to run this procedure
78       info.level >= depthLevelling_ &&
79       CoinDrand48 () > 1. / (2. + info.level - depthLevelling_)))
80    return;
81
82  if (info.level <= 0)
83    jnlst_ -> Printf (J_ERROR, J_COUENNE, "TwoImpl-BT: "); fflush (stdout);
84
85  // printf ("probexecute = %g. Level = %d, depthlevelling = %d, depthStop = %d, cond = %d\n",
86  //      1. / (2. + info.level - depthLevelling_),
87  //      info.level,
88  //      depthLevelling_,
89  //      depthStopSeparate_,
90  //      (depthLevelling_ < 0 || info.level < depthLevelling_));
91
92  // Update CouenneProblem's bounds using si's getCol{Low,Upp}er() and
93  // cs's OsiColCuts
94  problem_ -> domain () -> push (&si, &cs);
95
96  static int nBadColMatWarnings = 0;
97
98  std::set <std::pair <int, int> > pairs;
99
100  /// In principle, "si. getMatrixByCol ()" should be sufficient.
101  /// However, there seems to be a bug (not sure where... Osi? Clp?
102  /// Or, most probably, Couenne?) that doesn't return good values
103  /// from A (and triggers Valgrind errors and segfaults on ex3_1_1
104  /// and others). While waiting for a fix, we'll use the row
105  /// representation.
106
107  /// Update: we should probably stick to #defining USE_ROW even when
108  /// this is solved, as cuts from cs should also be added.
109
110#define USE_ROW
111
112#ifdef USE_ROW
113
114  const CoinPackedMatrix *mat = si. getMatrixByRow ();
115
116  int 
117    m = mat -> getMajorDim (), // # rows
118    n = mat -> getMinorDim (); // # cols
119
120#else
121
122  const CoinPackedMatrix *mat = si. getMatrixByCol ();
123
124  int 
125    n = mat -> getMajorDim (), // # cols
126    m = mat -> getMinorDim (); // # rows
127
128#endif
129
130  const double
131    *rlb = si.getRowLower (),
132    *rub = si.getRowUpper ();
133
134#ifdef USE_ROW
135
136  /// These will be used
137
138  int 
139     nnz   = mat -> getNumElements (), // # nonzeros
140     nnzC  = 0,
141    *sta   = new int [n+1],
142     nCuts = cs.sizeRowCuts ();
143
144  // Count nonzeros in cs
145
146  for (int i=0, ii = cs. sizeRowCuts (); ii--; i++) {
147
148    const OsiRowCut        *cut     = cs. rowCutPtr (i);
149    const CoinPackedVector &rowCoe  = cut -> row ();
150
151    nnzC += rowCoe.getNumElements ();
152  }
153
154  int    *ind = new int    [nnz + nnzC];
155  double *A   = new double [nnz + nnzC];
156
157  /// these are the row-format originals
158  {
159    const double
160      *rA   = mat -> getElements ();
161
162    const int
163      *rInd = mat -> getIndices      (),
164      *rSta = mat -> getVectorStarts ();
165
166    // copy rA, rInd, rSta into A, ind, sta
167
168    CoinZeroN (sta, n+1);
169
170    /////////////////////////////////////////////////////////
171
172    // pre-fill starting positions with cardinalities of each column
173
174    for (int i=nnz; i--;)
175      ++ (sta [1 + *rInd++]);
176
177    // fill sta with nonzeros from cs's OsiRowCuts
178
179    for (int i=0, ii = cs. sizeRowCuts (); ii--; i++) {
180
181      const OsiRowCut        *cut     = cs. rowCutPtr (i);
182      const CoinPackedVector &rowCoe  = cut -> row ();
183      const int              *indices = rowCoe.getIndices     ();
184      int                     nnz     = rowCoe.getNumElements ();
185      // Note: nnz redeclared here (no scoping problems)
186
187      for (int i=nnz; i--;)
188        ++ (sta [1 + *indices++]);
189    }
190
191    rInd -= nnz;
192
193    ////////////////////////////////////////////////////////
194
195    // make sta cumulative
196
197    for (int i=1; i<=n; i++)
198      sta [i] += sta [i-1];
199
200    // use space marked by sta to fill appropriate
201    // indices/coefficients
202
203    for (int i=0; i<m; i++) {
204
205      // filling indices of row i
206
207      int rowStart = rSta [i];
208
209      for (int j = rowStart, jj = rSta [i+1] - rowStart; jj--; j++) {
210
211        int &curSta = sta [rInd [j]];
212
213        ind [curSta]   = i;
214        A   [curSta++] = rA [j];
215      }
216     
217      //printf ("\n");
218    }
219
220    // Add rowCuts from cs as well.
221
222    for (int i=0, ii = cs. sizeRowCuts (); ii--; i++) {
223
224      const OsiRowCut        *cut      = cs. rowCutPtr (i);
225      //printf ("[cut] %4d [%g,%g]: ", m+i, cut -> lb (), cut -> ub ());
226
227      const CoinPackedVector &rowCoe   = cut -> row ();
228      const int              *indices  = rowCoe.getIndices  ();
229      const double           *elements = rowCoe.getElements ();
230      int                     nnz      = rowCoe.getNumElements ();
231      // Note: nnz redeclared here (no scoping problems)
232
233      for (int j=nnz; j--;) {
234
235        //printf ("%+g x%d ", *elements, *indices);
236
237        int &curSta = sta [*indices++];
238
239        ind [curSta]   = m+i;
240        A   [curSta++] = *elements++;
241      }
242      //printf ("\n");
243    }
244
245    for (int i=n; --i;)
246      sta [i] = sta [i-1];
247
248    sta [0] = 0;
249
250    //printf ("%d + %d = %d nonzeros\n", nnz, nnzC, nnz + nnzC);
251  }
252
253#else
254
255  const double
256    *A   = mat -> getElements ();
257
258  const int
259    *ind = mat -> getIndices      (),
260    *sta = mat -> getVectorStarts ();
261
262#endif
263
264  /// Prepare vector for integrality test. Since many checks are done
265  /// within combine(), it is worth to prepare one here
266
267  bool *isInteger = new bool [n];
268  for (int i=0, ii=n; ii--; i++)
269    *isInteger++ = problem_ -> Var (i) -> isInteger ();
270  isInteger -= n;
271
272  // print out
273
274  // for (int i=0; i<n; i++) {
275
276  //   printf ("x%04d - %5d -> %5d, %5d elements:", i, sta [i], sta [i+1], sta [i+1] - sta [i]);
277  //   fflush (stdout);
278
279  //   for (int j=0; j<sta [i+1] - sta [i]; j++) {
280  //     printf ("(%d,%g) ", ind [sta [i] + j], A [sta [i] + j]);
281  //     fflush (stdout);
282  //   }
283  //   printf ("\n");
284  // }
285
286  // For every column i, compare pairs of rows j and k with nonzero
287  // coefficients.
288  //
289  // If the coefficients have the same sign and the inequalities are
290  // both >= or both <=, skip this pair -- no tightening can come from
291  // this pair (this doesn't mean that for another variable the
292  // opposite may happen).
293
294  double 
295    *sa1 = new double [n], // contains dense representation of a1 i.e. lots of zeros
296    *sa2 = new double [n]; //                                  a2
297
298  CoinFillN (sa1, n, 0.);
299  CoinFillN (sa2, n, 0.);
300
301  for (int i=0; i<n; i++, sta++) {
302
303    //printf ("x%d:\n", i);
304
305    for   (int jj = *(sta+1) - *sta, j = *sta; jj--; j++)
306      for (int kk = jj,              k = j+1;  kk--; k++) {
307
308        if (CoinCpuTime () > problem_ -> getMaxCpuTime ())
309          break;
310
311        register int 
312          indj = ind [j],
313          indk = ind [k];
314
315        //printf ("  checking pair %d, %d\n", indj, indk);
316
317        // should never happen, but if it does, just bail out
318        if ((indj >= m + nCuts) || (indj < 0) ||
319            (indk >= m + nCuts) || (indk < 0)) {
320
321          if (nBadColMatWarnings++ < 1)
322            //      jnlst_ -> Printf (J_STRONGWARNING, J_BOUNDTIGHTENING, "
323            printf ("\
324  Couenne: warning, matrix by row has nonsense indices.\n\
325  This separator will now return without (column) cuts.\n\
326  NOTE: further such inconsistencies won't be reported.\n");
327
328          delete [] sa1;
329          delete [] sa2;
330
331          delete [] sta;
332          delete [] ind;
333          delete [] A;
334
335          delete [] isInteger;
336
337          problem_ -> domain () -> pop ();
338
339          totalTime_     += CoinCpuTime () - now;
340          totalInitTime_ += CoinCpuTime () - now;
341
342          return; 
343        }
344
345        double 
346          prod = A [j] * A [k],
347          rlbj, rubj, rlbk, rubk;
348
349        if (indj>=m) {
350          OsiRowCut *cut = cs.rowCutPtr (indj-m);
351          rlbj = cut -> lb ();
352          rubj = cut -> ub ();
353        } else {
354          rlbj = rlb [indj];
355          rubj = rub [indj];
356        }
357
358        if (indk>=m) {
359          OsiRowCut *cut = cs.rowCutPtr (indk-m);
360          rlbk = cut -> lb ();
361          rubk = cut -> ub ();
362        } else {
363          rlbk = rlb [indk];
364          rubk = rub [indk];
365        }
366
367        if (prod > 0.) { // same sign -- skip unless finite lb1/ub2 OR
368                         // finite ub1/lb2. This is to avoid a situation
369                         // in which all coefficients in this pair
370                         // have the same sign
371
372          if (!(((rlbj > -COUENNE_INFINITY/10) && (rubk <  COUENNE_INFINITY/10)) || 
373                ((rubj <  COUENNE_INFINITY/10) && (rlbk > -COUENNE_INFINITY/10))))
374
375            continue;
376
377        } else
378
379        if ((prod < 0.) && // opposite sign -- multiply second
380                           // inequality by -1 and repeat
381            !(((rlbj > -COUENNE_INFINITY/10) && (rlbk > -COUENNE_INFINITY/10)) || 
382              ((rubj <  COUENNE_INFINITY/10) && (rubk <  COUENNE_INFINITY/10))))
383
384          continue;
385
386        pairs.insert (std::pair <int, int> (indj, indk));
387      }
388  }
389
390  // pairs (h,k) are done. Now for each pair set new bounds, if possible ///////////////////////////
391
392#ifdef USE_ROW
393  const CoinPackedMatrix *rowA = mat;
394#else
395  const CoinPackedMatrix *rowA = si. getMatrixByRow ();
396#endif
397
398  const double
399    *rA  = rowA -> getElements ();
400
401  // TODO: no need for copy, though we need it to compare to old problem's bounds
402
403  double
404    *clb   = CoinCopyOfArray (problem_ -> Lb (), n),
405    *cub   = CoinCopyOfArray (problem_ -> Ub (), n),
406    *oldLB = CoinCopyOfArray (problem_ -> Lb (), n),
407    *oldUB = CoinCopyOfArray (problem_ -> Ub (), n);
408
409  const int
410    *rInd = rowA -> getIndices      (),
411    *rSta = rowA -> getVectorStarts ();
412
413  int 
414    ntightened = 0,
415    ntrials    = 0,
416    nCurTightened;
417
418  // info about LP problem: upper bound, dual bound
419
420  Bonmin::BabInfo * babInfo = dynamic_cast <Bonmin::BabInfo *> (si.getAuxiliaryInfo ());
421
422  int result = 0;
423
424  // data structure for FBBT
425
426  t_chg_bounds *chg_bds = new t_chg_bounds [n];
427
428  // for (int i=0; i<n; i++)
429  //   if (problem_ -> Var (i) -> Multiplicity () <= 0) {
430  //     chg_bds [i].setLower (t_chg_bounds::UNCHANGED);
431  //     chg_bds [i].setUpper (t_chg_bounds::UNCHANGED);
432  //   }
433
434  // fills in chg_bds with changed bounds from previous BB node
435
436  updateBranchInfo (si, problem_, chg_bds, info);
437
438  // Comparing all pairs of inequalities is overkill if the comparison
439  // has been done in a previous iteration: a pair of inequalities of
440  // the old LP relaxation should be skipped unless some bounds have
441  // been changed in at least one of the variables (of either
442  // inequality). Moreover, all pairs of inequalities should be
443  // considered where the first is from the LP relaxation and the
444  // second is from the cuts added so far.
445
446  // Repeat the scan as long as there is tightening and the bounding
447  // box is nonempty.
448
449  do {
450
451    nCurTightened = 0;
452
453    // scan all pairs. All are potential pairs of inequalities that
454    // can give a better (combined) implied bound
455
456    for (std::set <std::pair <int, int> >:: iterator p = pairs.begin (); p != pairs.end (); ++p) {
457
458      if (CoinCpuTime () > problem_ -> getMaxCpuTime ())
459        break;
460
461      // indices of the two inequalities
462
463      int 
464        h = p -> first,
465        k = p -> second,
466        n1, n2;
467
468      double l1, u1, l2, u2;
469
470      const double *a1, *a2;
471
472      const int *ind1, *ind2;
473
474      // set indices/counters depending on whether h or k are cuts or
475      // inequalities
476
477      if (h>=m) {
478
479        const OsiRowCut *cut = cs.rowCutPtr (h-m);
480        const CoinPackedVector &rowCoe  = cut -> row ();
481
482        l1 = cut -> lb ();
483        u1 = cut -> ub ();
484        n1   = rowCoe. getNumElements ();
485        ind1 = rowCoe. getIndices     ();
486        a1   = rowCoe. getElements    ();
487
488      } else {
489
490        l1 = rlb [h];
491        u1 = rub [h];
492        n1 = rSta [h+1] - rSta [h];
493        ind1 = rInd + rSta [h];
494        a1 = rA + rSta [h];
495      }
496
497      ////////////////////////////////////////////////////////////////
498
499      if (k>=m) {
500
501        OsiRowCut *cut = cs.rowCutPtr (k-m);
502        const CoinPackedVector &rowCoe  = cut -> row ();
503
504        l2 = cut -> lb ();
505        u2 = cut -> ub ();
506        n2   = rowCoe. getNumElements ();
507        ind2 = rowCoe. getIndices     ();
508        a2   = rowCoe. getElements    ();
509
510      } else {
511
512        l2 = rlb [k];
513        u2 = rub [k];
514        n2 = rSta [k+1] - rSta [k];
515        ind2 = rInd + rSta [k];
516        a2 = rA + rSta [k];
517      }
518
519      // If both indices are from the LP relaxation, only check if
520      // there is at least one changed bound in the variables of one
521      // (or both) of them
522
523      if ((h < m) && (k < m) && !firstCall_) {
524
525        bool new_bound = false;
526
527        for (int i=n1; i--;) {
528
529          t_chg_bounds &chg = chg_bds [ind1 [i]];
530
531          if ((chg. lower () != t_chg_bounds::UNCHANGED) ||
532              (chg. upper () != t_chg_bounds::UNCHANGED))
533
534            new_bound = true;
535        }
536
537        if (!new_bound) 
538          for (int i=n2; i--;) {
539
540            t_chg_bounds &chg = chg_bds [ind2 [i]];
541
542            if ((chg. lower () != t_chg_bounds::UNCHANGED) ||
543                (chg. upper () != t_chg_bounds::UNCHANGED))
544
545              new_bound = true;
546          }
547
548        if (!new_bound) continue;
549      }
550
551      // fill in sa1 and sa2
552
553      for (int i=n1; i--;) sa1 [ind1 [i]] = a1 [i];
554      for (int i=n2; i--;) sa2 [ind2 [i]] = a2 [i];
555
556      // A few cases here on the inequalities' bounds, which may
557      // determine a change of sign in the second when combining the
558      // two: for example, if we have -inf < ax < b and c < dx < +inf,
559      // it makes sense to combine -inf < ax < b and -inf < - dx < -c
560      // as the upper bound will create a finite convex combination.
561
562      if ((u1 <   COUENNE_INFINITY && u2 <   COUENNE_INFINITY) ||
563          (l1 > - COUENNE_INFINITY && l2 > - COUENNE_INFINITY))
564
565        result = combine (problem_, n1, n2, ind1, ind2, sa1, sa2, a1, a2, clb, cub, l1, l2, u1, u2, isInteger, 1);
566
567      if (result < 0)
568        break;
569
570      nCurTightened += result;
571      result = 0;
572
573      // fill in sa2 with opposite values
574      for (int i=n2; i--;) 
575        sa2 [ind2 [i]] = - a2 [i];
576
577      if ((u1 <   COUENNE_INFINITY && l2 > - COUENNE_INFINITY) ||
578          (l1 > - COUENNE_INFINITY && u2 <   COUENNE_INFINITY))
579
580        // do NOT invert l2 and u2, this is done in combine
581        result = combine (problem_, n1, n2, ind1, ind2, sa1, sa2, a1, a2, clb, cub, l1, l2, u1, u2, isInteger, -1);
582
583      if (result < 0)
584        break;
585
586      nCurTightened += result;
587
588      // clean sa1 and sa2
589
590      for (int i=n1; i--;) sa1 [ind1 [i]] = 0.;
591      for (int i=n2; i--;) sa2 [ind2 [i]] = 0.;
592    }
593
594    if (result < 0) 
595      break;
596
597    int objInd = problem_ -> Obj (0) -> Body () -> Index ();
598
599    if (nCurTightened &&
600        (objInd >= 0) && 
601        babInfo && 
602        babInfo -> babPtr ()) {
603
604      CouNumber
605        UB      = babInfo -> babPtr () -> model (). getObjValue(),
606        LB      = babInfo -> babPtr () -> model (). getBestPossibleObjValue (),
607        primal0 = problem_ -> Ub (objInd), 
608        dual0   = problem_ -> Lb (objInd);
609
610      // Do one round of BT
611
612      if ((UB < COUENNE_INFINITY) && 
613          (UB < primal0 - COUENNE_EPS)) { // update primal bound (MIP)
614
615        problem_ -> Ub (objInd) = UB;
616        chg_bds [objInd].setUpper (t_chg_bounds::CHANGED);
617      }
618
619      if ((LB > - COUENNE_INFINITY) && 
620          (LB > dual0 + COUENNE_EPS)) { // update dual bound
621        problem_ -> Lb (objInd) = LB;
622        chg_bds [objInd].setLower (t_chg_bounds::CHANGED);
623      }
624
625      // change chg_bds for all new bounds stored in cs
626
627      /*for (int i = cs. sizeColCuts (); i--;) {
628
629        const CoinPackedVector
630          &lbs = cs. colCutPtr (i) -> lbs (),
631          &ubs = cs. colCutPtr (i) -> ubs ();
632
633        // copy lbs
634
635        const int *indices = lbs. getIndices ();
636
637        for (int j = lbs. getNumElements (); j--; indices++)
638          chg_bds [*indices].setLower (t_chg_bounds::CHANGED);
639
640        // copy ubs
641
642        indices = ubs. getIndices ();
643
644        for (int j = ubs. getNumElements (); j--; indices++)
645          chg_bds [*indices].setUpper (t_chg_bounds::CHANGED);
646      }
647      */
648
649      if (!(problem_ -> btCore (chg_bds))) {
650
651        //problem infeasible, add IIS of size 2
652
653        result = -1;
654        break;
655
656      } else {
657
658        // update tightened bounds from problem to clb
659
660        for (int i=0; i<n; i++) {
661
662          if (problem_ -> Lb (i) > clb [i] + COUENNE_EPS) clb [i] = problem_ -> Lb (i);
663          if (problem_ -> Ub (i) < cub [i] - COUENNE_EPS) cub [i] = problem_ -> Ub (i);
664        }
665      }
666    }
667
668    ntightened += nCurTightened;
669
670  } while (++ntrials < nMaxTrials_ && nCurTightened);
671
672  totalInitTime_ += CoinCpuTime () - now;
673
674  // check if bounds improved, in that case create OsiColCuts
675
676  if (result >= 0 && ntightened) {
677
678    // check old and new bounds
679
680    int 
681      *indLB = new int [n],
682      *indUB = new int [n],
683      ntightenedL = 0,
684      ntightenedU = 0;
685
686    double 
687      *valLB = new double [n],
688      *valUB = new double [n];
689
690    for (int i=0; i<n; i++) {
691
692      if (clb [i] > oldLB [i]) {
693
694        if (problem_ -> bestSol () &&
695            problem_ -> bestSol () [i] > oldLB [i] &&
696            problem_ -> bestSol () [i] < clb   [i] - 1e-12) {
697
698          jnlst_ -> Printf (J_ERROR, J_COUENNE, 
699                            "Warning, twoImplBounds new LB cuts optimal solution: LB x_%d = %g --> %g, opt %g (diff: %g)\n",
700                            i, oldLB [i], clb [i], problem_ -> bestSol () [i], clb [i] - problem_ -> bestSol () [i]);
701
702        }
703
704        //printf ("L %4d: %g -> %g\n", i, oldLB [i], clb [i]);
705        indLB [ntightenedL]   = i;
706        valLB [ntightenedL++] = clb [i];
707      }
708
709      if (cub [i] < oldUB [i]) {
710
711        if (problem_ -> bestSol () &&
712            problem_ -> bestSol () [i] < oldUB [i] &&
713            problem_ -> bestSol () [i] > cub   [i] + 1e-12) {
714
715          jnlst_ -> Printf (J_ERROR, J_COUENNE, 
716                            "Warning, twoImplBounds new UB cuts optimal solution: UB x_%d = %g --> %g, opt %g (diff: %g)\n",
717                            i, oldUB [i], cub [i], problem_ -> bestSol () [i], problem_ -> bestSol () [i] - cub [i]);
718
719        }
720
721        //printf ("U %4d: %g -> %g\n", i, oldUB [i], cub [i]);
722        indUB [ntightenedU]   = i;
723        valUB [ntightenedU++] = cub [i];
724      }
725    }
726
727    if (ntightenedL || ntightenedU) {
728
729      OsiColCut newBound;
730
731      newBound.setLbs (ntightenedL, indLB, valLB);
732      newBound.setUbs (ntightenedU, indUB, valUB);
733
734      //newBound.print ();
735
736      cs.insert (newBound);
737    }
738
739    delete [] indLB;
740    delete [] indUB;
741    delete [] valLB;
742    delete [] valUB;
743
744    ntightened = ntightenedL + ntightenedU;
745  }
746
747  else 
748
749    if (result < 0)
750      WipeMakeInfeas (cs);
751
752  delete [] clb;
753  delete [] cub;
754  delete [] oldLB;
755  delete [] oldUB;
756  delete [] sa1;
757  delete [] sa2; 
758  delete [] chg_bds;
759
760  delete [] isInteger;
761
762  problem_ -> domain () -> pop ();
763
764#ifdef USE_ROW
765  delete [] A;
766  delete [] ind;
767  delete [] (sta-n);
768#endif
769
770  if (firstCall_)
771    firstCall_ = false;
772
773  totalTime_ += CoinCpuTime () - now;
774
775  if (info.level <= 0)
776    jnlst_ -> Printf (J_ERROR, J_COUENNE, "%d improved bounds\n", ntightened);
777}
778}
Note: See TracBrowser for help on using the repository browser.