source: stable/0.4/Couenne/src/bound_tightening/twoImpliedBT/TwoImpliedGenCuts.cpp @ 946

Last change on this file since 946 was 946, checked in by stefan, 8 years ago

merge r945 from trunk: allow compiling against Cgl 0.58

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