1 /* $Id$
2 *
3 * Name: generateCuts.cpp
4 * Author: Pietro Belotti
5 * Purpose: the generateCuts() method of the convexification class CouenneCutGenerator
6 *
7 * (C) Carnegie-Mellon University, 2006-11.
8 * This file is licensed under the Eclipse Public License (EPL)
9 */
10
11 #include "BonCbc.hpp"
12 #include "BonBabInfos.hpp"
13 #include "CglCutGenerator.hpp"
14
15 #include "CouenneCutGenerator.hpp"
16 #include "CouenneProblem.hpp"
17 #include "CouenneProblemElem.hpp"
18 #include "CouenneExprVar.hpp"
19 #include "CouenneInfeasCut.hpp"
20
21 #include "CouenneRecordBestSol.hpp"
22
23 //#define FM_PRINT_INFO
24
25 #ifdef COIN_HAS_NTY
26 #include "Nauty.h"
27 #endif
28
29 using namespace Ipopt;
30
31 namespace Couenne {
32
33 #define Couenne_large_bound2 9.99e12
34
35 // checks bad cuts against known optimum
36 bool isOptimumCut (const CouNumber *opt, OsiCuts &cs, CouenneProblem *p);
37
38 // set and lift bound for auxiliary variable associated with objective
39 // function
fictitiousBound(OsiCuts & cs,CouenneProblem * p,bool action)40 void fictitiousBound (OsiCuts &cs,
41 CouenneProblem *p,
42 bool action) { // true before convexifying, false afterwards
43
44 // fictitious bound for initial unbounded lp relaxations
45 const CouNumber large_tol = (Couenne_large_bound2 / 1e6);
46
47 // set trivial dual bound to objective function, if there is none
48
49 int ind_obj = p -> Obj (0) -> Body () -> Index ();
50
51 if (ind_obj < 0) return;
52
53 // we have a single variable objective function
54
55 //int sense = -1; //(p -> Obj (0) -> Sense () == MINIMIZE) ? -1 : 1;
56
57 if (action)
58 //if (sense<0)
59 {if (p -> Lb (ind_obj) < - Couenne_large_bound2) p -> Lb (ind_obj) = - Couenne_large_bound2;}
60 //else {if (p -> Ub (ind_obj) > large_bound2) p -> Ub (ind_obj) = large_bound2;}
61 else
62 //if (sense>0) {if (fabs (p->Ub(ind_obj)-large_bound2)<large_tol) p->Ub(ind_obj)=COUENNE_INFINITY;}
63 //else
64 {if (fabs (p->Lb(ind_obj)+Couenne_large_bound2)<large_tol) p->Lb(ind_obj) =-COUENNE_INFINITY;}
65 }
66
67
68 // translate changed bound sparse array into a dense one
sparse2dense(int ncols,t_chg_bounds * chg_bds,int * & changed,int & nchanged)69 void sparse2dense (int ncols, t_chg_bounds *chg_bds, int *&changed, int &nchanged) {
70
71 // convert sparse chg_bds in something handier
72
73 changed = (int *) realloc (changed, ncols * sizeof (int));
74 nchanged = 0;
75
76 for (register int i=ncols, j=0; i--; j++, chg_bds++)
77 if (chg_bds -> lower() != t_chg_bounds::UNCHANGED ||
78 chg_bds -> upper() != t_chg_bounds::UNCHANGED ) {
79 *changed++ = j;
80 nchanged++;
81 }
82
83 changed -= nchanged;
84 //changed = (int *) realloc (changed, nchanged * sizeof (int));
85 }
86
87
88 /// get new bounds from parents' bounds + branching rules
89 void updateBranchInfo (const OsiSolverInterface &si, CouenneProblem *p,
90 t_chg_bounds *chg, const CglTreeInfo &info);
91
92 /// a convexifier cut generator
93
generateCuts(const OsiSolverInterface & si,OsiCuts & cs,const CglTreeInfo info) const94 void CouenneCutGenerator::generateCuts (const OsiSolverInterface &si,
95 OsiCuts &cs,
96 const CglTreeInfo info)
97 #if CGL_VERSION_MAJOR == 0 && CGL_VERSION_MINOR <= 57
98 const
99 #endif
100 {
101
102 // if si.lb(objInd) > cutoff,
103 // return infeasCut
104
105 int indObj = problem_ -> Obj (0) -> Body () -> Index ();
106
107 if ((indObj >= 0) &&
108 (si.getColLower () [indObj] > problem_ -> getCutOff () + COUENNE_EPS)) {
109
110 WipeMakeInfeas (cs);
111 return;
112 }
113
114 // check if out of time or if an infeasibility cut (iis of type 0)
115 // was added as a result of, e.g., pruning on BT. If so, no need to
116 // run this.
117
118 if (isWiped (cs) ||
119 (CoinCpuTime () > problem_ -> getMaxCpuTime ()))
120 return;
121
122 #ifdef FM_TRACE_OPTSOL
123 double currCutOff = problem_->getCutOff();
124 double bestVal = 1e50;
125 CouenneRecordBestSol *rs = problem_->getRecordBestSol();
126 if(rs->getHasSol()) {
127 bestVal = rs->getVal();
128 }
129 if(currCutOff > bestVal) {
130 //problem_ -> setCutOff (bestVal - 1e-6); // FIXME: don't add numerical constants
131 problem_ -> setCutOff (bestVal);
132
133 if ((indObj >= 0) && (si. getColUpper () [indObj] > bestVal)) {
134 OsiColCut *objCut = new OsiColCut;
135 objCut->setUbs(1, &indObj, &bestVal);
136 cs.insert(objCut);
137 delete objCut;
138 }
139 }
140 #endif
141
142 #ifdef FM_PRINT_INFO
143 if((BabPtr_ != NULL) && (info.level >= 0) && (info.pass == 0) &&
144 (BabPtr_->model().getNodeCount() > lastPrintLine)) {
145 printLineInfo();
146 lastPrintLine += 1;
147 }
148 #endif
149
150 const int infeasible = 1;
151
152 int nInitCuts = cs.sizeRowCuts ();
153
154 CouNumber
155 *&realOpt = problem_ -> bestSol (),
156 *saveOptimum = realOpt;
157
158 if (!firstcall_ && realOpt) {
159
160 // have a debug optimal solution. Check if current bounds
161 // contain it, otherwise pretend it does not exist
162
163 CouNumber *opt = realOpt;
164
165 const CouNumber
166 *sol = si.getColSolution (),
167 *lb = si.getColLower (),
168 *ub = si.getColUpper ();
169
170 int objind = problem_ -> Obj (0) -> Body () -> Index ();
171
172 for (int j=0, i=problem_ -> nVars (); i--; j++, opt++, lb++, ub++)
173 if ((j != objind) &&
174 ((*opt < *lb - COUENNE_EPS * (1 + CoinMin (fabs (*opt), fabs (*lb)))) ||
175 (*opt > *ub + COUENNE_EPS * (1 + CoinMin (fabs (*opt), fabs (*ub)))))) {
176
177 jnlst_ -> Printf (J_VECTOR, J_CONVEXIFYING,
178 "out of bounds, ignore x%d = %g [%g,%g] opt = %g\n",
179 problem_ -> nVars () - i - 1, *sol, *lb, *ub, *opt);
180
181 // optimal point is not in current bounding box,
182 // pretend realOpt is NULL until we return from this procedure
183 realOpt = NULL;
184 break;
185 }
186 }
187
188 /*static int count = 0;
189 char fname [20];
190 sprintf (fname, "relax_%d", count++);
191 si.writeLp (fname);
192 printf ("writing %s\n", fname);*/
193
194 jnlst_ -> Printf (J_DETAILED, J_CONVEXIFYING,
195 "generateCuts: level = %d, pass = %d, intree = %d\n",
196 info.level, info.pass, info.inTree);
197
198 Bonmin::BabInfo * babInfo = dynamic_cast <Bonmin::BabInfo *> (si.getAuxiliaryInfo ());
199
200 if (babInfo)
201 babInfo -> setFeasibleNode ();
202
203 double now = CoinCpuTime ();
204 int ncols = problem_ -> nVars ();
205
206 // This vector contains variables whose bounds have changed due to
207 // branching, reduced cost fixing, or bound tightening below. To be
208 // used with malloc/realloc/free
209
210 t_chg_bounds *chg_bds = new t_chg_bounds [ncols];
211
212 /*for (int i=0; i < ncols; i++)
213 if (problem_ -> Var (i) -> Multiplicity () <= 0) {
214 chg_bds [i].setLower (t_chg_bounds::UNCHANGED);
215 chg_bds [i].setUpper (t_chg_bounds::UNCHANGED);
216 }*/
217
218 problem_ -> installCutOff (); // install upper bound
219
220 if (firstcall_) {
221
222 // First convexification //////////////////////////////////////
223
224 // OsiSolverInterface is empty yet, no information can be obtained
225 // on variables or bounds -- and none is needed since our
226 // constructor populated *problem_ with variables and bounds. We
227 // only need to update the auxiliary variables and bounds with
228 // their current value.
229
230 for (int i=0; i < ncols; i++)
231 if (problem_ -> Var (i) -> Multiplicity () > 0) {
232 chg_bds [i].setLower (t_chg_bounds::CHANGED);
233 chg_bds [i].setUpper (t_chg_bounds::CHANGED);
234 }
235
236 // start with FBBT, should take advantage of cutoff found by NLP
237 // run AFTER initial FBBT...
238 if (problem_ -> doFBBT () &&
239 (! (problem_ -> boundTightening (chg_bds, info, babInfo))))
240 jnlst_ -> Printf (J_STRONGWARNING, J_CONVEXIFYING,
241 "Couenne: WARNING, first convexification is infeasible\n");
242
243 // For each auxiliary variable replacing the original (nonlinear)
244 // constraints, check if corresponding bounds are violated, and
245 // add cut to cs
246
247 int nnlc = problem_ -> nCons ();
248
249 for (int i=0; i<nnlc; i++) {
250
251 if (CoinCpuTime () > problem_ -> getMaxCpuTime ())
252 break;
253
254 // for each constraint
255 CouenneConstraint *con = problem_ -> Con (i);
256
257 // (which has an aux as its body)
258 int objindex = con -> Body () -> Index ();
259
260 if ((objindex >= 0) &&
261 ((con -> Body () -> Type () == AUX) ||
262 (con -> Body () -> Type () == VAR))) {
263
264 // get the auxiliary that is at the lhs
265 exprVar *conaux = problem_ -> Var (objindex);
266
267 if (conaux &&
268 (conaux -> Type () == AUX) &&
269 (conaux -> Image ()) &&
270 (conaux -> Image () -> Linearity () <= LINEAR)) {
271
272 // reduce density of problem by adding w >= l rather than
273 // ax + b >= l for any linear auxiliary defined as w := ax+b
274
275 double
276 lb = (*(con -> Lb ())) (),
277 ub = (*(con -> Ub ())) ();
278
279 OsiColCut newBound;
280 if (lb > -COUENNE_INFINITY) newBound.setLbs (1, &objindex, &lb);
281 if (ub < COUENNE_INFINITY) newBound.setUbs (1, &objindex, &ub);
282
283 cs.insert (newBound);
284
285 // the auxiliary w of constraint w <= b is associated with a
286 // linear expression w = ax: add constraint ax <= b
287 /*conaux -> Image () -> generateCuts (conaux, si, cs, this, chg_bds,
288 conaux -> Index (),
289 (*(con -> Lb ())) (),
290 (*(con -> Ub ())) ());*/
291
292 // take it from the list of the variables to be linearized
293 //
294 // DO NOT decrease multiplicity. Even if it is a linear
295 // term, its bounds can still be used in implied bounds
296 //
297 // Are we sure? That will happen only if its multiplicity is
298 // nonzero, for otherwise this aux is only used here, and is
299 // useless elsewhere
300 //
301 //conaux -> decreaseMult (); // !!!
302 }
303
304 // also, add constraint w <= b
305
306 // not now, do it later
307
308 // // if there exists violation, add constraint
309 // CouNumber l = con -> Lb () -> Value (),
310 // u = con -> Ub () -> Value ();
311
312 // // tighten bounds in Couenne's problem representation
313 // problem_ -> Lb (index) = CoinMax (l, problem_ -> Lb (index));
314 // problem_ -> Ub (index) = CoinMin (u, problem_ -> Ub (index));
315
316 } else { // body is more than just a variable, but it should be
317 // linear. If so, generate equivalent linear cut
318
319 assert (false); // TODO
320 }
321 }
322
323 if (jnlst_ -> ProduceOutput (J_ITERSUMMARY, J_CONVEXIFYING)) {
324 if (cs.sizeRowCuts ()) {
325 jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne: %d constraint row cuts\n",
326 cs.sizeRowCuts ());
327 for (int i=0; i<cs.sizeRowCuts (); i++)
328 cs.rowCutPtr (i) -> print ();
329 }
330 if (cs.sizeColCuts ()) {
331 jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne: %d constraint col cuts\n",
332 cs.sizeColCuts ());
333 for (int i=0; i<cs.sizeColCuts (); i++)
334 cs.colCutPtr (i) -> print ();
335 }
336 }
337 } else {
338
339 // use new optimum as lower bound for variable associated w/objective
340
341 // transmit solution from OsiSolverInterface to problem
342 problem_ -> domain () -> push (&si, &cs);
343
344 if (indObj >= 0) {
345
346 // Use current value of objvalue's x as a lower bound for bound
347 // tightening
348 double lp_bound = problem_ -> domain () -> x (indObj);
349
350 //if (problem_ -> Obj (0) -> Sense () == MINIMIZE)
351 {if (lp_bound > problem_ -> Lb (indObj)) problem_ -> Lb (indObj) = lp_bound;}
352 //else {if (lp_bound < problem_ -> Ub (indObj)) problem_ -> Ub (indObj) = lp_bound;}
353 }
354
355 updateBranchInfo (si, problem_, chg_bds, info); // info.depth >= 0 || info.pass >= 0
356 }
357
358 // restore constraint bounds before tightening and cut generation
359 for (int i = problem_ -> nCons (); i--;) {
360
361 // for each constraint
362 CouenneConstraint *con = problem_ -> Con (i);
363
364 // (which has an aux as its body)
365 int objindex = con -> Body () -> Index ();
366
367 if ((objindex >= 0) &&
368 ((con -> Body () -> Type () == AUX) ||
369 (con -> Body () -> Type () == VAR))) {
370
371 // if there exists violation, add constraint
372 CouNumber
373 l = con -> Lb () -> Value (),
374 u = con -> Ub () -> Value ();
375
376 // tighten bounds in Couenne's problem representation
377 problem_ -> Lb (objindex) = CoinMax (l, problem_ -> Lb (objindex));
378 problem_ -> Ub (objindex) = CoinMin (u, problem_ -> Ub (objindex));
379 }
380 }
381
382 problem_ -> installCutOff (); // install upper bound
383
384 fictitiousBound (cs, problem_, false); // install finite lower bound, if currently -inf
385
386 int *changed = NULL, nchanged;
387
388 // Bound tightening ///////////////////////////////////////////
389
390 // do bound tightening only at first pass of cutting plane in a node
391 // of BB tree (info.pass == 0) or if first call (creation of RLT,
392 // info.pass == -1)
393
394 try {
395
396 // Before bound tightening, compute symmetry group. After bound
397 // tightening is done, we can apply further tightening using orbit
398 // information.
399
400 // #ifdef COIN_HAS_NTY
401 // // ChangeBounds (psi -> getColLower (),
402 // // psi -> getColUpper (),
403 // // psi -> getNumCols ());
404
405 // if (problem_ -> orbitalBranching ()){
406
407 // problem_ -> ChangeBounds (problem_ -> Lb (),
408 // problem_ -> Ub (),
409 // problem_ -> nVars ());
410
411 // problem_ -> Compute_Symmetry ();
412 // }
413 // #endif
414
415 // Bound tightening ////////////////////////////////////
416
417 //bool is_feas = p -> btCore (chg_bds);
418
419 // Reduced Cost BT -- to be done first to use rcost correctly
420 if (!firstcall_ && // have a linearization already
421 problem_ -> doRCBT () && // authorized to do reduced cost tightening
422 problem_ -> redCostBT (&si, chg_bds) && // some variables were tightened with reduced cost
423 !(problem_ -> btCore (chg_bds))) // in this case, do another round of FBBT
424 throw infeasible;
425
426 // FBBT
427 if (problem_ -> doFBBT () &&
428 //(info.pass <= 0) && // do it in subsequent rounds too
429 (! (problem_ -> boundTightening (chg_bds, info, babInfo))))
430 throw infeasible;
431
432 // OBBT
433 if (!firstcall_ && // no obbt if first call (there is no LP to work with)
434 problem_ -> obbt (this, si, cs, info, babInfo, chg_bds) < 0)
435 throw infeasible;
436
437 // Bound tightening done /////////////////////////////
438
439 if ((problem_ -> doFBBT () ||
440 problem_ -> doOBBT () ||
441 problem_ -> doABT ()) &&
442 (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING))) {
443
444 jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== after bt =============\n");
445 for (int i = 0; i < problem_ -> nVars (); i++)
446 if (problem_ -> Var (i) -> Multiplicity () > 0)
447 jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i,
448 problem_ -> X (i), problem_ -> Lb (i), problem_ -> Ub (i));
449 jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n");
450 }
451
452 // Use orbit info to tighten bounds
453
454 #ifdef COIN_HAS_NTY
455
456 // TODO: when independent bound tightener, can get original bounds
457 // through si.getCol{Low,Upp}er()
458
459 if (problem_ -> orbitalBranching () && !firstcall_) {
460
461 CouNumber
462 *lb = problem_ -> Lb (),
463 *ub = problem_ -> Ub ();
464
465 std::vector<std::vector<int> > *new_orbits = problem_ -> getNtyInfo () -> getOrbits();
466
467 for (int i=0, ii = problem_ -> getNtyInfo () -> getNumOrbits (); ii--; i++){
468
469 CouNumber
470 ll = -COUENNE_INFINITY,
471 uu = COUENNE_INFINITY;
472
473 std::vector <int> orbit = (*new_orbits)[i];
474
475 if (orbit.size () <= 1)
476 continue; // not much to do when only one variable in this orbit
477
478 if (jnlst_ -> ProduceOutput (J_VECTOR, J_BOUNDTIGHTENING)) {
479 printf ("orbit bounds: "); fflush (stdout);
480 for(int j = 0; j < orbit.size (); j++) {
481 printf ("x_%d [%g,%g] ", orbit[j], lb [orbit [j]], ub [orbit [j]]);
482 fflush (stdout);
483 }
484 }
485
486 for (int j = 0; j < orbit.size (); j++) {
487
488 int indOrb = orbit [j];
489
490 if (indOrb < problem_ -> nVars ()) {
491
492 if (lb [indOrb] > ll) ll = lb [indOrb];
493 if (ub [indOrb] < uu) uu = ub [indOrb];
494 }
495 }
496
497 jnlst_ -> Printf (J_VECTOR, J_BOUNDTIGHTENING,
498 " --> new common bounds: [%g,%g]\n", ll, uu);
499
500 for(int j = 0; j < orbit.size (); j++) {
501
502 int indOrb = orbit [j];
503
504 if (indOrb < problem_ -> nVars ()){
505
506 lb [indOrb] = ll;
507 ub [indOrb] = uu;
508 }
509 }
510 }
511
512 delete new_orbits;
513 }
514
515 #endif
516
517 // Generate convexification cuts //////////////////////////////
518
519 sparse2dense (ncols, chg_bds, changed, nchanged);
520
521 double *nlpSol = NULL;
522
523 //--------------------------------------------
524
525 if (true) {
526
527 if (babInfo)
528 nlpSol = const_cast <double *> (babInfo -> nlpSolution ());
529
530 // Aggressive Bound Tightening ////////////////////////////////
531
532 int logAbtLev = problem_ -> logAbtLev ();
533
534 if (problem_ -> doABT () && // flag is checked, AND
535 ((logAbtLev != 0) || // (parameter is nonzero OR
536 (info.level == 0)) && // we are at root node), AND
537 (info.pass == 0) && // at first round of cuts, AND
538 ((logAbtLev < 0) || // (logAbtLev = -1, OR
539 (info.level <= logAbtLev) || // depth is lower than COU_OBBT_CUTOFF_LEVEL, OR
540 (CoinDrand48 () < // probability inversely proportional to the level)
541 pow (2., (double) logAbtLev - (info.level + 1))))) {
542
543 jnlst_ -> Printf(J_VECTOR, J_BOUNDTIGHTENING," performing ABT\n");
544 if (! (problem_ -> aggressiveBT (nlp_, chg_bds, info, babInfo)))
545 throw infeasible;
546
547 sparse2dense (ncols, chg_bds, changed, nchanged);
548 }
549
550 // obtain solution just found by nlp solver
551
552 // Auxiliaries should be correct. solution should be the one found
553 // at the node even if not as good as the best known.
554
555 // save violation flag and disregard it while adding cut at NLP
556 // point (which are not violated by the current, NLP, solution)
557 bool save_av = addviolated_;
558 addviolated_ = false;
559
560 // save values
561 problem_ -> domain () -> push
562 (problem_ -> nVars (),
563 problem_ -> domain () -> x (),
564 problem_ -> domain () -> lb (),
565 problem_ -> domain () -> ub (), false);
566
567 // fill originals with nlp values
568 if (nlpSol) {
569 CoinCopyN (nlpSol, problem_ -> nOrigVars (), problem_ -> domain () -> x ());
570 //problem_ -> initAuxs ();
571
572 problem_ -> getAuxs (problem_ -> domain () -> x ());
573 }
574
575 if (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING)) {
576 jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== genrowcuts on NLP =============\n");
577 for (int i = 0; i < problem_ -> nVars (); i++)
578 if (problem_ -> Var (i) -> Multiplicity () > 0)
579 jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i,
580 problem_ -> X (i),
581 problem_ -> Lb (i),
582 problem_ -> Ub (i));
583 jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n");
584 }
585
586 problem_ -> domain () -> current () -> isNlp () = true;
587 genRowCuts (si, cs, nchanged, changed, chg_bds); // add cuts
588
589 problem_ -> domain () -> pop (); // restore point
590
591 addviolated_ = save_av; // restore previous value
592
593 // if (!firstcall_) // keep solution if called from extractLinearRelaxation()
594 if (babInfo)
595 babInfo -> setHasNlpSolution (false); // reset it after use //AW HERE
596
597 } else {
598
599 if (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING)) {
600 jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== genrowcuts on LP =============\n");
601 for (int i = 0; i < problem_ -> nVars (); i++)
602 if (problem_ -> Var (i) -> Multiplicity () > 0)
603 jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i,
604 problem_ -> X (i),
605 problem_ -> Lb (i),
606 problem_ -> Ub (i));
607 jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n");
608 }
609
610 genRowCuts (si, cs, nchanged, changed, chg_bds);
611 }
612
613 // change tightened bounds through OsiCuts
614 if (nchanged)
615 genColCuts (si, cs, nchanged, changed);
616
617 if (firstcall_ && (cs.sizeRowCuts () >= 1))
618 jnlst_->Printf(J_ITERSUMMARY, J_CONVEXIFYING,
619 "Couenne: %d initial row cuts\n", cs.sizeRowCuts ());
620
621 if (realOpt && // this is a good time to check if we have cut the optimal solution
622 isOptimumCut (realOpt, cs, problem_))
623 jnlst_->Printf(J_ITERSUMMARY, J_CONVEXIFYING,
624 "Warning: Optimal solution was cut\n");
625 }
626
627 catch (int exception) {
628
629 if ((exception == infeasible) && (!firstcall_)) {
630
631 jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,
632 "Couenne: Infeasible node\n");
633
634 WipeMakeInfeas (cs);
635 }
636
637 if (babInfo) // set infeasibility to true in order to skip NLP heuristic
638 babInfo -> setInfeasibleNode ();
639 }
640
641 delete [] chg_bds;
642
643 if (changed)
644 free (changed);
645
646 if (firstcall_) {
647
648 jnlst_ -> Printf (J_SUMMARY, J_CONVEXIFYING,
649 "Couenne: %d cuts (%d row, %d col) for linearization\n",
650 cs.sizeRowCuts () + cs.sizeColCuts (),
651 cs.sizeRowCuts (), cs.sizeColCuts ());
652
653 fictitiousBound (cs, problem_, true);
654 firstcall_ = false;
655 ntotalcuts_ = nrootcuts_ = cs.sizeRowCuts ();
656
657 } else {
658
659 problem_ -> domain () -> pop ();
660
661 ntotalcuts_ += (cs.sizeRowCuts () - nInitCuts);
662
663 if (saveOptimum)
664 realOpt = saveOptimum; // restore debug optimum
665 }
666
667 septime_ += CoinCpuTime () - now;
668
669 if (jnlst_ -> ProduceOutput (J_ITERSUMMARY, J_CONVEXIFYING)) {
670
671 if (cs.sizeColCuts ()) {
672 jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne col cuts:\n");
673 for (int i=0; i<cs.sizeColCuts (); i++)
674 cs.colCutPtr (i) -> print ();
675 }
676 }
677
678 if (!(info.inTree))
679 rootTime_ = CoinCpuTime ();
680 }
681
682 }
683