BM_lp_branch.cpp
Go to the documentation of this file.
1 // (C) Copyright International Business Machines Corporation 2006, 2007
2 // All Rights Reserved.
3 // This code is published under the Eclipse Public License.
4 //
5 // Authors :
6 // Laszlo Ladanyi, International Business Machines Corporation
7 // Pierre Bonami, Carnegie Mellon University
8 
9 #include "CoinHelperFunctions.hpp"
10 #include "BCP_lp_node.hpp"
11 #include "BCP_lp.hpp"
12 #include "BCP_lp_functions.hpp"
13 #include "BM.hpp"
14 #include "BonChooseVariable.hpp"
16 #include "BonQpBranchingSolver.hpp"
17 #include "BonLpBranchingSolver.hpp"
19 #include "BonIpoptWarmStart.hpp"
20 
21 #ifndef BM_DEBUG_PRINT
22 #define BM_DEBUG_PRINT 0
23 #endif
24 
25 static bool ifprint = true;
26 static bool ifprint2 = false;
27 
28 //#############################################################################
29 
32  const BCP_vec<BCP_var*>& vars,
33  const BCP_vec<BCP_cut*>& cuts,
34  const BCP_lp_var_pool& local_var_pool,
35  const BCP_lp_cut_pool& local_cut_pool,
37  bool force_branch)
38 {
39  /* FIXME: this is good only for BB and using NLP to solve a node */
41 
44  // If we are doing pure B&B then we have an nlp, and then we check for
45  // consecutive failures.
46  if (nlp) {
47  if (lpres.termcode() & BCP_Abandoned) {
48  if (nlp->isIterationLimitReached()) {
49  print(ifprint, "\
50 BM_lp: At node %i : WARNING: nlp reached iter limit. Will force branching\n",
51  current_index());
52  } else {
53  print(ifprint, "\
54 BM_lp: At node %i : WARNING: nlp is abandoned. Will force branching\n",
55  current_index());
56  }
57  // nlp failed
58  nlp->forceBranchable();
59  numNlpFailed_++;
61  print(ifprint, "WARNING! Too many (%i) NLP failures in a row. Abandoning node.",
64  }
65  } else {
66  numNlpFailed_ = 0;
67  }
68  }
69 
70  OsiBranchingInformation brInfo(nlp, false, true);
71  brInfo.cutoff_ = upper_bound() + get_param(BCP_lp_par::Granularity);
72  brInfo.objectiveValue_ = lpres.objval();
73  brInfo.integerTolerance_ = integerTolerance_;
74  brInfo.timeRemaining_ = get_param(BCP_lp_par::MaxRunTime) - CoinCpuTime();
75  brInfo.numberSolutions_ = 0; /*FIXME*/
76  brInfo.numberBranchingSolutions_ = 0; /*FIXME numBranchingSolutions_;*/
77  brInfo.depth_ = current_level();
78 
79  BCP_branching_decision brDecision;
80  if (bonmin_.getAlgorithm() == 0) {
81  /* if pure B&B */
82  brDecision = bbBranch(brInfo, cands);
83  } else {
84  brDecision = hybridBranch();
85  }
86 
87  return brDecision;
88 }
89 
90 //-----------------------------------------------------------------------------
91 
94 {
95  // FIXME: most of the pureBB stuff should work here.
96  throw BCP_fatal_error("BM_lp: FIXME: make hybrid work...");
97 }
98 
99 /*****************************************************************************/
100 
101 void
103 {
104  Bonmin::BonChooseVariable* choose =
106  OsiPseudoCosts& pseudoCosts = choose->pseudoCosts();
107  int numObj = pseudoCosts.numberObjects();
108  double* upTotalChange = pseudoCosts.upTotalChange();
109  int* upNumber = pseudoCosts.upNumber();
110  double* downTotalChange = pseudoCosts.downTotalChange();
111  int* downNumber = pseudoCosts.downNumber();
112 
113  buf.unpack(upTotalChange, numObj, false);
114  buf.unpack(upNumber, numObj, false);
115  buf.unpack(downTotalChange, numObj, false);
116  buf.unpack(downNumber, numObj, false);
117 }
118 
119 
120 //-----------------------------------------------------------------------------
121 
122 void
123 BM_lp::send_pseudo_cost_update(OsiBranchingInformation& branchInfo)
124 {
125  bm_buf.clear();
126  int itmp;
127  double objchange;
128  itmp = BM_PseudoCostUpdate;
129  bm_buf.pack(itmp);
130  for (int i = 0; i < objNum_; ++i) {
131  const BM_SB_result& sbres = sbResult_[i];
132  if ((sbres.branchEval & 1) != 0 && sbres.status[0] != BCP_Abandoned) {
133  bm_buf.pack(sbres.objInd);
134  itmp = 0;
135  bm_buf.pack(itmp);
136  if (sbres.status[0] == BCP_ProvenOptimal) {
137  objchange = sbres.objval[0] - branchInfo.objectiveValue_;
138  } else { // Must be BCP_ProvenPrimalInf
139  if (branchInfo.cutoff_ < 1e50) {
140  objchange = 2*(branchInfo.cutoff_-branchInfo.objectiveValue_);
141  } else {
142  objchange = 2*fabs(branchInfo.objectiveValue_);
143  }
144  }
145  bm_buf.pack(objchange/sbres.varChange[0]);
146  }
147  if ((sbres.branchEval & 2) != 0 && sbres.status[1] != BCP_Abandoned) {
148  bm_buf.pack(sbres.objInd);
149  itmp = 1;
150  bm_buf.pack(itmp);
151  if (sbres.status[1] == BCP_ProvenOptimal) {
152  objchange = sbres.objval[1] - branchInfo.objectiveValue_;
153  } else { // Must be BCP_ProvenPrimalInf
154  if (branchInfo.cutoff_ < 1e50) {
155  objchange = 2*(branchInfo.cutoff_-branchInfo.objectiveValue_);
156  } else {
157  objchange = 2*fabs(branchInfo.objectiveValue_);
158  }
159  }
160  bm_buf.pack(objchange/sbres.varChange[1]);
161  }
162  }
163  itmp = -1;
164  bm_buf.pack(itmp);
166 }
167 
168 //-----------------------------------------------------------------------------
169 
170 int
171 BM_lp::sort_objects(OsiBranchingInformation& branchInfo,
172  Bonmin::BonChooseVariable* choose, int& branchNum)
173 {
174  const OsiObject* const * objects = branchInfo.solver_->objects();
175  double upMult, downMult;
176  choose->computeMultipliers(upMult, downMult);
177  const double MAXMIN = choose->maxminCrit(&branchInfo);
178 
179  /* Order all objects that can be branched on */
180  int lastPriority = objects[objInd_[0]]->priority();
181  int infBlockStart = 0;
182  int feasBlockStart = 0;
183  branchNum = 0;
184  infNum_ = 0;
185  feasNum_ = 0;
186 
187  const bool isRoot = (current_index() == 0);
188  int way;
189 
190  const bool disregardPriorities = par.entry(BM_par::DisregardPriorities);
191  const bool usePseudoCosts = par.entry(BM_par::UsePseudoCosts);
192 
193  for (int i = 0; i < objNum_; ++i) {
194  const int ind = objInd_[i];
195  const OsiObject* object = objects[ind];
196  double value = object->infeasibility(&branchInfo, way);
197  if (value > 0.0) {
198  if (value >= 1e50) { // infeasible
199  return -1;
200  }
201  if (! disregardPriorities) {
202  int priorityLevel = object->priority();
203  if (lastPriority < priorityLevel) {
204  // sort the entries based on their usefulness
205  if (infBlockStart < infNum_) {
207  CoinSort_2(infUseful_ + infBlockStart, infUseful_ + infNum_,
208  infInd_ + infBlockStart,
209  CoinFirstGreater_2<double,int>());
210  } else {
211  CoinSort_2(infUseful_ + infBlockStart, infUseful_ + infNum_,
212  infInd_ + infBlockStart);
213  }
214  infBlockStart = infNum_;
215  }
216  lastPriority = priorityLevel;
217  }
218  }
219  double dummy;
220  infInd_[infNum_] = ind;
221  if (usePseudoCosts) {
222  infUseful_[infNum_] = isRoot ?
223  value : choose->computeUsefulness(MAXMIN, upMult, downMult, value,
224  object, ind, dummy);
225  } else {
226  infUseful_[infNum_] = value;
227  }
228 
229  ++infNum_;
230  branchNum += 2;
231 
232  } else { /* value == 0.0 */
233  const OsiSOS* sos = dynamic_cast<const OsiSOS*>(object);
234  if (sos) {
235  // if an sos is feasible thne we don't do strong branching on it
236  continue;
237  }
238  const int iCol = object->columnNumber();
239  const double lb = branchInfo.lower_[iCol];
240  const double ub = branchInfo.upper_[iCol];
241  if (fabs(ub - lb) < 0.1) {
242  continue;
243  }
244  value = branchInfo.solution_[iCol];
245  ++branchNum;
246  if (floor(value+0.5) > lb && ceil(value-0.5) < ub) {
247  // The variable is integer, but neither at its lower nor at its upper
248  // bound (the test accounts for tolerances)
249  ++branchNum;
250  }
251  if (! disregardPriorities) {
252  int priorityLevel = object->priority();
253  if (lastPriority < priorityLevel) {
254  // sort the entries based on their usefulness
255  if (feasBlockStart < feasNum_) {
257  CoinSort_2(feasUseful_ + feasBlockStart, feasUseful_ + feasNum_,
258  feasInd_ + feasBlockStart,
259  CoinFirstGreater_2<double,int>());
260  } else {
261  CoinSort_2(feasUseful_ + feasBlockStart, feasUseful_ + feasNum_,
262  feasInd_ + feasBlockStart);
263  }
264  }
265  lastPriority = priorityLevel;
266  }
267  }
268  double dummy;
269  feasInd_[feasNum_] = ind;
270  feasUseful_[feasNum_] = choose->computeUsefulness(MAXMIN,
271  upMult, downMult, value,
272  object, ind, dummy);
273  ++feasNum_;
274  }
275  }
276  if (infBlockStart < infNum_) {
278  CoinSort_2(infUseful_ + infBlockStart, infUseful_ + infNum_,
279  infInd_ + infBlockStart,
280  CoinFirstGreater_2<double,int>());
281  } else {
282  CoinSort_2(infUseful_ + infBlockStart, infUseful_ + infNum_,
283  infInd_ + infBlockStart);
284  }
285  }
286  if (feasBlockStart < feasNum_) {
288  CoinSort_2(feasUseful_ + feasBlockStart, feasUseful_ + feasNum_,
289  feasInd_ + feasBlockStart,
290  CoinFirstGreater_2<double,int>());
291  } else {
292  CoinSort_2(feasUseful_ + feasBlockStart, feasUseful_ + feasNum_,
293  feasInd_ + feasBlockStart);
294  }
295  }
296 
297 #if (BM_DEBUG_PRINT != 0)
298  const double t = CoinWallclockTime();
299  printf("LP %.3f: node: %i depth: %i obj: %f infNum: %i feasNum: %i soltime: %.3f\n",
301  branchInfo.objectiveValue_,
303  node_start_time = t;
304 #endif
305 
306  return infNum_;
307 }
308 
309 //-----------------------------------------------------------------------------
310 
311 void
313 {
314  for (int i = 0; i < objNum_; ++i) {
315  sbResult_[i].branchEval = 0;
316  }
317  bestSbResult_ = NULL;
318 }
319 
320 //-----------------------------------------------------------------------------
321 
322 void
323 BM_lp::collect_branch_data(OsiBranchingInformation& branchInfo,
324  OsiSolverInterface* solver,
325  const int branchNum,
326  BM_BranchData* branchData)
327 {
328  int i;
329  int b = 0;
330  for (i = 0; i < infNum_; ++i) {
331  /* FIXME: think about SOS */
332  const int objInd = infInd_[i];
333  const int colInd = solver->object(objInd)->columnNumber();
334  const double val = branchInfo.solution_[colInd];
335  branchData[b].changeType = BM_Var_DownBranch;
336  branchData[b].objInd = objInd;
337  branchData[b].colInd = colInd;
338  branchData[b].solval = val;
339  branchData[b].bd = floor(val);
340  BM_SB_result& sbres = sbResult_[objInd];
341  sbres.objInd = objInd;
342  sbres.varChange[0] = val - floor(val);
343  ++b;
344  if (b == branchNum) {
345  return;
346  }
347  branchData[b].changeType = BM_Var_UpBranch;
348  branchData[b].objInd = objInd;
349  branchData[b].colInd = colInd;
350  branchData[b].solval = val;
351  branchData[b].bd = ceil(val);
352  sbres.varChange[1] = ceil(val) - val;
353  ++b;
354  if (b == branchNum) {
355  return;
356  }
357  }
358  for (i = 0; i < feasNum_; ++i) {
359  const int objInd = feasInd_[i];
360  const int colInd = solver->object(objInd)->columnNumber();
361  const double val = branchInfo.solution_[colInd];
362  const double lb = branchInfo.lower_[colInd];
363  const double ub = branchInfo.upper_[colInd];
364  if (floor(val+0.5) > lb) { // not at its lb
365  branchData[b].changeType = BM_Var_DownBranch;
366  branchData[b].objInd = objInd;
367  branchData[b].colInd = colInd;
368  branchData[b].solval = val;
369  branchData[b].bd = floor(val - 0.5);
370  ++b;
371  if (b == branchNum) {
372  return;
373  }
374  }
375  if (ceil(val-0.5) < ub) { // not at its ub
376  branchData[b].changeType = BM_Var_UpBranch;
377  branchData[b].objInd = objInd;
378  branchData[b].colInd = colInd;
379  branchData[b].solval = val;
380  branchData[b].bd = ceil(val + 0.5);
381  ++b;
382  if (b == branchNum) {
383  return;
384  }
385  }
386  }
387 }
388 
389 //-----------------------------------------------------------------------------
390 
391 void
392 BM_solve_branches(OsiSolverInterface* solver, const CoinWarmStart* cws,
393  const int numBranch, BM_BranchData* bD)
394 {
395  for (int i = 0; i < numBranch; ++i) {
396  double t = CoinWallclockTime();
397  const int ind = bD[i].colInd;
398  const int field = bD[i].changeType == BM_Var_UpBranch ? 1 : 0;
399  const double old_lb = solver->getColLower()[ind];
400  const double old_ub = solver->getColUpper()[ind];
401  if (field == 0) {
402  solver->setColUpper(ind, bD[i].bd);
403  } else {
404  solver->setColLower(ind, bD[i].bd);
405  }
406  if (cws) {
407  solver->setWarmStart(cws);
408  solver->resolve();
409  } else {
410  solver->initialSolve();
411  }
412  bD[i].status =
413  (solver->isAbandoned() ? BCP_Abandoned : 0) |
414  (solver->isProvenOptimal() ? BCP_ProvenOptimal : 0) |
415  (solver->isProvenPrimalInfeasible() ? BCP_ProvenPrimalInf : 0);
416  bD[i].objval =
417  (bD[i].status & BCP_ProvenOptimal) != 0 ? solver->getObjValue() : 0.0;
418  bD[i].iter = solver->getIterationCount();
419  solver->setColBounds(ind, old_lb, old_ub);
420  bD[i].time = CoinWallclockTime() - t;
421  }
422 }
423 
424 //-----------------------------------------------------------------------------
425 
426 void
427 BM_register_branch_results(const int numBranch, const BM_BranchData* bD,
428  BM_SB_result* sbResults)
429 {
430  for (int i = 0; i < numBranch; ++i) {
431  const int field = bD[i].changeType == BM_Var_UpBranch ? 1 : 0;
432  BM_SB_result& sbres = sbResults[bD[i].objInd];
433  sbres.objInd = bD[i].objInd;
434  sbres.branchEval |= field == 0 ? 1 : 2;
435  sbres.status[field] = bD[i].status;
436  sbres.objval[field] = bD[i].objval;
437  sbres.iter[field] = bD[i].iter;
438  sbres.varChange[field] = fabs(bD[i].solval - bD[i].bd);
439  }
440 }
441 
442 //-----------------------------------------------------------------------------
443 
444 void
445 BM_lp::do_distributed_SB(OsiBranchingInformation& branchInfo,
446  OsiSolverInterface* solver,
447  const CoinWarmStart* cws,
448  const int branchNum,
449  const int* pids, const int pidNum)
450 {
451  const double * clb = solver->getColLower();
452  const double * cub = solver->getColUpper();
453  const int numCols = solver->getNumCols();
454  bm_buf.clear();
455  int tag = BM_StrongBranchRequest;
456  bm_buf.pack(tag);
457  bm_buf.pack(clb, numCols);
458  bm_buf.pack(cub, numCols);
459  bm_buf.pack(branchInfo.objectiveValue_);
460  bm_buf.pack(branchInfo.cutoff_);
461  bool has_ws = cws != NULL;
462  bm_buf.pack(has_ws);
463  if (has_ws) {
465  CoinWarmStart* cws_tmp = cws->clone(); // the next call destroys it
466  BCP_warmstart* ws = cws ? BCP_lp_convert_CoinWarmStart(*p, cws_tmp) : NULL;
468  delete ws;
469  }
470 
471  const int fixed_size = bm_buf.size();
472 
473  // collect what we'll need to send off data
474  BM_BranchData* branchData = new BM_BranchData[branchNum];
475  collect_branch_data(branchInfo, solver, branchNum, branchData);
476 
477  // We have branchNum branches to process on pidNum+1 (the last is the local
478  // process) processes.
479  int branchLeft = branchNum;
480  BM_BranchData* bD = branchData;
481  for (int pidLeft = pidNum; pidLeft > 0; --pidLeft) {
482  int numSend = branchLeft / pidLeft;
483  if (numSend * pidLeft < branchLeft) {
484  ++numSend;
485  }
486  bm_buf.set_size(fixed_size);
487  // Now pack where we are in branchData and pack numSend branches
488  int location = bD - branchData;
489  bm_buf.pack(location);
490  bm_buf.pack(numSend);
491  for (int s = 0; s < numSend; ++s) {
492  bm_buf.pack(bD[s].changeType);
493  bm_buf.pack(bD[s].objInd);
494  bm_buf.pack(bD[s].colInd);
495  bm_buf.pack(bD[s].solval);
496  bm_buf.pack(bD[s].bd);
497  }
498  send_message(pids[pidLeft-1], bm_buf);
499  bD += numSend;
500  branchLeft -= numSend;
501  }
502  assert(branchNum/(pidNum+1) == branchLeft);
503 
504  // Process the leftover branches locally
505  /* FIXME: this assumes that the solver is the NLP solver. Maybe we should use
506  the nlp solver in BM_lp */
507  BM_solve_branches(solver, cws, branchLeft, bD);
508  bm_stats.incNumberSbSolves(branchLeft);
509  BM_register_branch_results(branchLeft, bD, sbResult_);
510 
511  // Receive the results from the other processes
512  int numResults = branchLeft;
513  while (numResults < branchNum) {
514  bm_buf.clear();
516  bm_buf.unpack(tag);
517  assert(tag == BM_StrongBranchResult);
518  int location;
519  int numRes;
520  bm_buf.unpack(location);
521  bm_buf.unpack(numRes);
522  BM_BranchData* bD = branchData + location;
523  for (int i = 0; i < numRes; ++i) {
524  bm_buf.unpack(bD[i].status);
525  bm_buf.unpack(bD[i].objval);
526  bm_buf.unpack(bD[i].iter);
527  bm_buf.unpack(bD[i].time);
528  }
530  numResults += numRes;
531  }
532 }
533 
534 //-----------------------------------------------------------------------------
535 
536 bool
537 BM_lp::isBranchFathomable(int status, double obj)
538 {
539  return ( (status & BCP_ProvenPrimalInf) ||
540  ((status & BCP_ProvenOptimal) && over_ub(obj)) );
541 }
542 
543 //-----------------------------------------------------------------------------
544 
545 int
546 BM_lp::process_SB_results(OsiBranchingInformation& branchInfo,
547  OsiSolverInterface* solver,
549  OsiBranchingObject*& branchObject)
550 {
551  int evaluated = 0;
552  int i;
553 #if defined(DEBUG_PRINT)
554  const double t = CoinWallclockTime()-start_time();
555 #endif
556 
557 #if 0 // defined(DEBUG_PRINT)
558  const double t = CoinWallclockTime()-start_time();
559  for (i = 0; i < infNum_; ++i) {
560  const BM_SB_result& sbres = sbResult_[infInd_[i]];
561  if (sbres.branchEval == 0) {
562  continue;
563  }
564  printf("LP %.3f: SB: node: %i inf col: %i stati: %i %i, obj: %f %f time: %.3f %.3f\n",
565  t, current_index(), sbres.colInd,
566  sbres.status[0], sbres.status[1],
567  sbres.objval[0], sbres.objval[1], sbres.time[0], sbres.time[1]);
568  }
569  for (i = 0; i < feasNum_; ++i) {
570  const BM_SB_result& sbres = sbResult_[feasInd_[i]];
571  if (sbres.branchEval == 0) {
572  continue;
573  }
574  printf("LP %.3f: SB: node: %i feas col: %i stati: %i %i, obj: %f %f time: %.3f %.3f\n",
575  t, current_index(), sbres.colInd,
576  sbres.status[0], sbres.status[1],
577  sbres.objval[0], sbres.objval[1], sbres.time[0], sbres.time[1]);
578  }
579 #endif
580  // First check if we can fathom the node
581  int listLen=0; // we want this for the bm_stats
582  for (i = 0; i < infNum_; ++i) {
583  const BM_SB_result& sbres = sbResult_[infInd_[i]];
584  if (sbres.branchEval == 0) {
585  continue;
586  }
587  assert(sbres.branchEval == 3);
588  if (isBranchFathomable(sbres.status[0], sbres.objval[0]) &&
589  isBranchFathomable(sbres.status[1], sbres.objval[1])) {
590 #if (BM_DEBUG_PRINT != 0)
591  const double wallclock = CoinWallclockTime();
592 #if 0
593  printf("LP %.3f: SBres: node: %i FATHOM inf/eval/cand: time: %.3f\n",
594  wallclock-start_time(), current_index(),
595  infNum_,
596  wallclock-node_start_time);
597 #else
598  printf("LP %.3f: SBres: node: %i FATHOM time: %.3f\n",
599  wallclock-start_time(), current_index(),
600  wallclock-node_start_time);
601 #endif
602 #endif
603  return -2;
604  }
605  ++listLen;
606  }
607 
608  // Nope. Let's see if we can fix anything.
609  // 0: nothing fixed bit 0: fixed but stayd feas bit 1: fixed and lost feas
610  int fixedStat = 0;
611  for (i = 0; i < infNum_; ++i) {
612  const BM_SB_result& sbres = sbResult_[infInd_[i]];
613  if (sbres.branchEval == 0) {
614  continue;
615  }
616  ++evaluated;
617  if (isBranchFathomable(sbres.status[0], sbres.objval[0])) {
618  const int colInd = sbres.colInd;
619  solver->setColLower(colInd, ceil(branchInfo.solution_[colInd]));
620  fixedStat |= 2;
622  }
623  if (isBranchFathomable(sbres.status[1], sbres.objval[1])) {
624  const int colInd = sbres.colInd;
625  solver->setColUpper(colInd, floor(branchInfo.solution_[colInd]));
626  fixedStat |= 2;
628  }
629  }
630  for (i = 0; i < feasNum_; ++i) {
631  const BM_SB_result& sbres = sbResult_[feasInd_[i]];
632  if (sbres.branchEval == 0) {
633  continue;
634  }
635  ++evaluated;
636  if ( (sbres.branchEval & 1) &&
637  isBranchFathomable(sbres.status[0], sbres.objval[0]) ) {
638  // Down branch evaluated and fathomable
639  const int colInd = sbres.colInd;
640  solver->setColLower(colInd, ceil(branchInfo.solution_[colInd] - 0.5));
641  fixedStat |= 1;
643  }
644  if ( (sbres.branchEval & 2) &&
645  isBranchFathomable(sbres.status[1], sbres.objval[1]) ) {
646  // Up branch evaluated and fathomable
647  const int colInd = sbres.colInd;
648  solver->setColUpper(colInd, floor(branchInfo.solution_[colInd] + 0.5));
649  fixedStat |= 1;
651  }
652  }
653  if ((fixedStat & 2) != 0) {
654 #if (BM_DEBUG_PRINT != 0)
655  printf("LP %.3f: SBres: node: %i RESOLVE time: %.3f\n",
657  node_start_time = t;
658 #endif
659  return -1;
660  }
661 
662  // OK, we may have fixed some, but we got to branch, nevertheless.
663  // Try to choose something where both sides have finished properly.
664  // Note: at this point all stati of the inf pieces is either abandoned,
665  // optimal (if primal infeas then we fixed and lost feasibility)
666  const bool preferHigh = par.entry(BM_par::PreferHighCombinationInBranching);
667  int best = -1;
668  int bestWhichWay = 1;
669  double bestTrusted = preferHigh ? -COIN_DBL_MAX : COIN_DBL_MAX;
670  const double MAXMIN = choose->maxminCrit(&branchInfo);
671 
672  for (i = 0; i < infNum_; ++i) {
673  const int objInd = infInd_[i];
674  const BM_SB_result& sbres = sbResult_[objInd];
675  if (sbres.branchEval == 0) {
676  // FIXME: Check the pseudocost
677  continue;
678  }
679  if ((sbres.status[0]&BCP_Abandoned) || (sbres.status[1]&BCP_Abandoned)){
680  continue;
681  }
682  double upEst = sbres.objval[1] - branchInfo.objectiveValue_;
683  double downEst = sbres.objval[0] - branchInfo.objectiveValue_;
684  double value =
685  MAXMIN*CoinMin(upEst,downEst) + (1.0-MAXMIN)*CoinMax(upEst,downEst);
686  const bool better = ( ( preferHigh && (value > bestTrusted)) ||
687  ( !preferHigh && (value < bestTrusted)) );
688  if (better) {
689  bestTrusted = value;
690  best = i;
691  bestWhichWay = upEst > downEst ? 0 : 1;
692  // override if there is a preferred way
693  const OsiObject* object = solver->object(objInd);
694  if (object->preferredWay() >= 0 && object->infeasibility()) {
695  bestWhichWay = object->preferredWay();
696  }
697  }
698  }
699  if (best == -1) {
700  // OMG... In *ALL* evaluated candidates at least one side was abandoned...
701  // Oh well, pick the first one not evaluated, or if no such thing then the
702  // first where only one side failed, or if no such thing then anything...
703  // FIXME: this loop will not be needed when pseudocosts are used
704  for (i = 0; i < infNum_; ++i) {
705  const BM_SB_result& sbres = sbResult_[infInd_[i]];
706  if (sbres.branchEval == 0) {
707  best = i;
708  break;
709  }
710  }
711  if (best == -1) {
712  for (i = 0; i < infNum_; ++i) {
713  const BM_SB_result& sbres = sbResult_[infInd_[i]];
714  if ((sbres.status[0] & BCP_Abandoned) == 0 ||
715  (sbres.status[1] & BCP_Abandoned) == 0) {
716  // prefer something where at least one side was not abandoned...
717  best = i;
718  break;
719  }
720  best = i;
721  }
722  }
723  }
724 
725  bm_stats.updateStrongBrachingInfo(best, listLen);
726 
727  // At this point best is not -1, create the branching object
728  const OsiObject * object = solver->object(infInd_[best]);
729  branchObject = object->createBranch(solver, &branchInfo, bestWhichWay);
730  bestSbResult_ = sbResult_ + infInd_[best];
731 #if (BM_DEBUG_PRINT != 0)
732  const int ind = object->columnNumber();
733  printf("LP %.3f: SBres: node: %i depth: %i BRANCH time: %.3f evaluated: %i bvar: %i val: %f obj0: %f obj1: %f way: %i\n",
735  evaluated, ind, branchInfo.solution_[ind],
736  bestSbResult_->objval[0], bestSbResult_->objval[1], bestWhichWay);
737  node_start_time = t;
738 #endif
739 
740  return (fixedStat & 1) != 0 ? -1 : 0;
741 }
742 
743 //-----------------------------------------------------------------------------
744 
745 int
746 BM_lp::try_to_branch(OsiBranchingInformation& branchInfo,
747  OsiSolverInterface* solver,
749  OsiBranchingObject*& branchObject,
750  bool allowVarFix)
751 {
752  int returnStatus = 0;
753 
754  int branchNum;
755  sort_objects(branchInfo, choose, branchNum);
756 
757  if (infNum_ == 0) {
758  return 0;
759  }
760 
761  const bool do_distributed_branching = true;
762 
763  if (do_distributed_branching) {
764 
765  bm_buf.clear();
766  bm_buf.pack(branchNum-1);
768  bm_buf.clear();
770  int* pids = NULL;
771  int pidNum;
772  bm_buf.unpack(pids, pidNum);
773 
775 
776  // Get the warmstart information
777  CoinWarmStart* cws = solver->getWarmStart();
778  Bonmin::IpoptWarmStart* iws = dynamic_cast<Bonmin::IpoptWarmStart*>(cws);
779  if (iws && iws->empty()) {
780  delete cws;
781  cws = NULL;
782  }
783 
784  const int nodeIndex = current_index();
785  if (nodeIndex == 0) {
786  // we are in the root. We want to process all possible branches upto the
787  // parameter value.
788  branchNum = CoinMin(branchNum, par.entry(BM_par::SBNumBranchesInRoot));
789  } else {
790  if (nodeIndex < par.entry(BM_par::SBMaxLevel)) {
791  branchNum = CoinMin(branchNum,
792  CoinMax(pidNum + 1,
794  } else {
795  branchNum = pidNum > 0 ? pidNum + 1 : 0;
796  }
797  }
798 
799  if (branchNum > 0) {
800  do_distributed_SB(branchInfo, solver, cws, branchNum, pids, pidNum);
801  returnStatus = process_SB_results(branchInfo, solver, choose,
802  branchObject);
803  send_pseudo_cost_update(branchInfo);
804  } else {
805  // We are too deep in the tree, just do something locally (like
806  // pseudocosts...)
807  returnStatus = BCP_lp_user::try_to_branch(branchInfo, solver, choose,
808  branchObject, allowVarFix);
809  }
810 
811  delete[] pids;
812  delete cws;
813 
814  } else { /* ! do_distributed_branching ===> Do something locally */
815 
816  }
817 
818  return returnStatus;
819 }
820 
821 //-----------------------------------------------------------------------------
822 
824 BM_lp::bbBranch(OsiBranchingInformation& brInfo,
826 {
828  OsiSolverInterface* osi = p->lp_solver;
830  dynamic_cast<Bonmin::OsiTMINLPInterface*>(osi);
831  assert(nlp);
832 
833  nlp->getDblParam(OsiPrimalTolerance, brInfo.integerTolerance_);
834 
835  BCP_branching_decision retCode;
836  OsiBranchingObject* brObj = NULL;
837 
838  const int numCols = nlp->getNumCols();
839  double* clb_old = new double[numCols];
840  double* cub_old = new double[numCols];
841  CoinDisjointCopyN(nlp->getColLower(), numCols, clb_old);
842  CoinDisjointCopyN(nlp->getColUpper(), numCols, cub_old);
843 
845  int numSB = 0;
846  //const bool sbIsSet =
847  options->GetIntegerValue("number_strong_branch",numSB,"bonmin.");
848  int numSBroot = 0;
849  const bool sbRootIsSet =
850  options->GetIntegerValue("number_strong_branch_root",numSBroot,"bonmin.");
851 
852  if (sbRootIsSet && brInfo.depth_ == 0) {
853  bonmin_.branchingMethod()->setNumberStrong(numSBroot);
854  } else {
855  bonmin_.branchingMethod()->setNumberStrong(numSB);
856  }
857 
858  Bonmin::BonChooseVariable* choose =
860  const int brResult = BM_lp::try_to_branch(brInfo, nlp, choose, brObj, true);
861 
862 #if 0
863  if (choose->goodSolution()) {
864  /* yipee! a feasible solution! Check that it's really */
865  const double* sol = choose->goodSolution();
866  BM_solution* bmsol = new BM_solution;
867  //Just copy the solution stored in solver to sol
868  double ptol = integerTolerance_;
869  for (int i = 0 ; i < numCols ; i++) {
870  if (fabs(sol[i]) > ptol)
871  bmsol->add_entry(i, sol[i]);
872  }
873  bmsol->setObjective(choose->goodObjectiveValue());
874  choose->clearGoodSolution();
875  send_feasible_solution(bmsol);
876  delete bmsol;
877  }
878 #endif
879 
880  switch (brResult) {
881  case -2:
882  // when doing strong branching a candidate has proved that the
883  // problem is infeasible
884  retCode = BCP_DoNotBranch_Fathomed;
885  break;
886  case -1:
887  // OsiChooseVariable::chooseVariable() returned 2, 3, or 4
888  if (!brObj) {
889  // just go back and resolve
890  retCode = BCP_DoNotBranch;
891  } else {
892  // otherwise might as well branch. The forced variable is
893  // unlikely to jump up one more (though who knows...)
894  retCode = BCP_DoBranch;
895  }
896  break;
897  case 0:
898  if (!brObj) {
899  // nothing got fixed, yet couldn't find something to branch on
900  throw BCP_fatal_error("BM: Couldn't branch!\n");
901  }
902  // we've got a branching object
903  retCode = BCP_DoBranch;
904  break;
905  default:
906  throw BCP_fatal_error("\
907 BM: BCP_lp_user::try_to_branch returned with unknown return code.\n");
908  }
909 
910  if (brResult < 0) {
911  // If there were some fixings (brResult < 0) then propagate them
912  // where needed
913 
914  // FIXME: This is not nice. Meddling w/ BCP internal data. The BCP
915  // user interface should provide a way to change bounds regardless
916  // whether branching is asked for or not.
917  const double* clb = nlp->getColLower();
918  const double* cub = nlp->getColUpper();
919 
921  for (int i = 0; i < numCols; ++i) {
922  if (clb_old[i] != clb[i] || cub_old[i] != cub[i]) {
923  vars[i]->change_bounds(clb[i], cub[i]);
924  nlp->setColBounds(i, clb[i], cub[i]);
925  }
926  }
927  }
928 
929  if (retCode == BCP_DoBranch) {
930  // all possibilities are 2-way branches
931  int order[2] = {0, 1};
932  // Now interpret the result (at this point we must have a brObj
933  OsiIntegerBranchingObject* intBrObj =
934  dynamic_cast<OsiIntegerBranchingObject*>(brObj);
935  if (intBrObj) {
936  if (intBrObj->firstBranch() == 1) {
937  order[0] = 1;
938  order[1] = 0;
939  }
941  cands.push_back(new BCP_lp_branching_object(o, order));
942  if (bestSbResult_) {
943  BCP_vec<double> lb(2, 0.0);
944  lb[0] = bestSbResult_->objval[order[0]];
945  lb[1] = bestSbResult_->objval[order[1]];
946  BCP_vec<int> tc(2, 0);
947  tc[0] = bestSbResult_->status[order[0]];
948  tc[1] = bestSbResult_->status[order[1]];
949  cands.back()->set_presolve_result(lb, tc);
950  }
952  print(ifprint2, "BM_lp: branching on variable %i value: %f\n",
953  intBrObj->originalObject()->columnNumber(),
954  intBrObj->value());
955  }
956  }
957  OsiSOSBranchingObject* sosBrObj =
958  dynamic_cast<OsiSOSBranchingObject*>(brObj);
959  if (sosBrObj) {
960  if (sosBrObj->firstBranch() == 1) {
961  order[0] = 1;
962  order[1] = 0;
963  }
964  BCP_lp_sos_branching_object o(sosBrObj);
965  cands.push_back(new BCP_lp_branching_object(nlp, o, order));
966  if (bestSbResult_) {
967  BCP_vec<double> lb(2, 0.0);
968  lb[0] = bestSbResult_->objval[order[0]];
969  lb[1] = bestSbResult_->objval[order[1]];
970  BCP_vec<int> tc(2, 0);
971  tc[0] = bestSbResult_->status[order[0]];
972  tc[1] = bestSbResult_->status[order[1]];
973  cands.back()->set_presolve_result(lb, tc);
974  }
976  print(ifprint2, "BM_lp: branching on SOS %i value: %f\n",
977  sosBrObj->originalObject()->columnNumber(),
978  sosBrObj->value());
979  }
980  }
981  }
982 
983  delete brObj;
984  delete[] clb_old;
985  delete[] cub_old;
986 
987  return retCode;
988 }
989 
990 /****************************************************************************/
991 
992 void
994  const int selected)
995 {
996  BM_node* data = NULL;
997  data = new BM_node;
999  best->user_data()[0] = data;
1000  data = new BM_node;
1001  data->numNlpFailed_ = numNlpFailed_;
1002  best->user_data()[1] = data;
1003 }
1004 
1005 //#############################################################################
1006 
1007 void
1009 {
1010  int msgtag;
1011  buf.unpack(msgtag);
1012  assert(msgtag == BM_StrongBranchRequest);
1013 
1015 
1016  int numCols;
1017  double* clb;
1018  double* cub;
1019  double objvalOrig;
1020  double cutoff;
1021  buf.unpack(clb, numCols);
1022  assert(numCols == nlp->getNumCols());
1023  buf.unpack(cub, numCols);
1024  assert(numCols == nlp->getNumCols());
1025  buf.unpack(objvalOrig);
1026  buf.unpack(cutoff);
1027  bool has_ws;
1028  buf.unpack(has_ws);
1029  BCP_warmstart* ws = has_ws ? BCP_unpack_warmstart(buf) : NULL;
1030  CoinWarmStart* cws = ws ? ws->convert_to_CoinWarmStart() : NULL;
1031  int location; // just a marker that we'll send back
1032  int numBranch;
1033  buf.unpack(location);
1034  buf.unpack(numBranch);
1035 
1036  int i;
1037  BM_BranchData* branchData = new BM_BranchData[numBranch];
1038  for (i = 0; i < numBranch; ++i) {
1039  buf.unpack(branchData[i].changeType);
1040  buf.unpack(branchData[i].objInd);
1041  buf.unpack(branchData[i].colInd);
1042  buf.unpack(branchData[i].solval);
1043  buf.unpack(branchData[i].bd);
1044  }
1045 
1046  nlp->setColLower(clb);
1047  nlp->setColUpper(cub);
1048  BM_solve_branches(nlp, cws, numBranch, branchData);
1049 
1050  bm_buf.clear();
1051  msgtag = BM_StrongBranchResult;
1052  bm_buf.pack(msgtag);
1053  bm_buf.pack(location);
1054  bm_buf.pack(numBranch);
1055  for (i = 0; i < numBranch; ++i) {
1056  const BM_BranchData& bD = branchData[i];
1057  bm_buf.pack(bD.status);
1058  bm_buf.pack(bD.objval);
1059  bm_buf.pack(bD.iter);
1060  bm_buf.pack(bD.time);
1061  }
1063 
1064  bm_buf.clear();
1066 
1067  delete[] branchData;
1068  delete cws;
1069  delete ws;
1070  delete[] clb;
1071  delete[] cub;
1072 
1073  bm_stats.incNumberSbSolves(numBranch);
1074 }
BM_SB_result * bestSbResult_
A pointer to the entry that got selected.
Definition: BM.hpp:324
char get_param(const BCP_lp_par::chr_params key) const
Definition: BCP_lp_user.cpp:51
int feasNum_
Definition: BM.hpp:318
double time[2]
Definition: BM.hpp:253
double time
Definition: BM.hpp:165
BCP_branching_decision bbBranch(OsiBranchingInformation &brInfo, BCP_vec< BCP_lp_branching_object * > &cands)
double * feasUseful_
Definition: BM.hpp:317
BCP_buffer & pack(const T &value)
Pack a single object of type T.
Definition: BCP_buffer.hpp:177
double objval
Definition: BM.hpp:163
Definition: BM.hpp:26
virtual void set_user_data_for_children(BCP_presolved_lp_brobj *best, const int selected)
For each child create a user data object and put it into the appropriate entry in best-&gt;user_data()...
BCP_lp_node * node
Description he current search tree node.
Definition: BCP_lp.hpp:168
The minimum difference between the objective value of any two feasible solution (with different objec...
void print(const bool ifprint, const char *format,...) const
A method to print a message with the process id.
Definition: BCP_lp_user.cpp:38
int iter[2]
Definition: BM.hpp:250
BCP_buffer & unpack(T &value)
Unpack a single object of type T.
Definition: BCP_buffer.hpp:186
int parent() const
the process id of the parent
virtual const double * getColLower() const
Get pointer to array[getNumCols()] of column lower bounds.
int iter
Definition: BM.hpp:164
This class chooses a variable to branch on.
void BCP_pack_warmstart(const BCP_warmstart *ws, BCP_buffer &buf)
static bool ifprint2
Class for storing warm start informations for Ipopt.
void BM_register_branch_results(const int numBranch, const BM_BranchData *bD, BM_SB_result *sbResults)
const int BCP_AnyProcess
Definition: BCP_message.hpp:21
BCP_var_set vars
Request a list of process ids the LP can use to do distributed strong branching.
void updateStrongBrachingInfo(int chosenIndex, int listLength)
Definition: BM.hpp:129
This is class provides an Osi interface for a Mixed Integer Linear Program expressed as a TMINLP (so ...
int branchEval
0: Not done 1: Only down 2: only up 3: both ways
Definition: BM.hpp:246
double computeUsefulness(const double MAXMIN_CRITERION, const double upMult, const double dowMult, const double value, const OsiObject *object, int i, double &value2) const
void forceBranchable()
Force current solution to be branched on (make it fractionnal with small objective) ...
This class exist only so that we can extract information from OsiIntegerBranchingObject.
void collect_branch_data(OsiBranchingInformation &branchInfo, OsiSolverInterface *solver, const int branchNum, BM_BranchData *branchData)
double maxminCrit(const OsiBranchingInformation *info) const
Helper functions for setupList and chooseVariable.
char entry(const chr_params key) const
Maximum allowed running time.
double varChange[2]
Definition: BM.hpp:252
int process_SB_results(OsiBranchingInformation &branchInfo, OsiSolverInterface *solver, Bonmin::BonChooseVariable *choose, OsiBranchingObject *&branchObject)
double node_start_time
The time when we started to process the node.
Definition: BM.hpp:327
int current_level() const
Return the level of the search tree node being processed.
Definition: BCP_lp_user.cpp:32
int sender() const
Return a const pointer to the process id of the sender of the message in the buffer.
Definition: BCP_buffer.hpp:93
double objval[2]
Definition: BM.hpp:251
double bd
Definition: BM.hpp:160
int current_index() const
Return the internal index of the search tree node being processed.
Definition: BCP_lp_user.cpp:33
BCP should continue to work on this node.
double start_time() const
Return when the LP process started.
Definition: BCP_lp_user.cpp:35
BCP_warmstart * BCP_lp_convert_CoinWarmStart(BCP_lp_prob &p, CoinWarmStart *&ws)
void BM_solve_branches(OsiSolverInterface *solver, const CoinWarmStart *cws, const int numBranch, BM_BranchData *bD)
NO OLD DOC.
Definition: BCP_lp.hpp:102
void do_distributed_SB(OsiBranchingInformation &branchInfo, OsiSolverInterface *solver, const CoinWarmStart *cws, const int branchNum, const int *pids, const int pidNum)
reference back()
Return a reference to the last entry.
Definition: BCP_vector.hpp:133
virtual int getNumCols() const
Get number of columns.
Warmstarting information for the LP solver.
void push_back(const_reference x)
Append x to the end of the vector.
BCP_branching_decision hybridBranch()
BM_stats bm_stats
Class for collecting statistics.
Definition: BM.hpp:330
int objNum_
Definition: BM.hpp:303
int * feasInd_
Definition: BM.hpp:316
void send_message(const int target, const BCP_buffer &buf, BCP_message_tag tag=BCP_Msg_User)
Send a message to a particular process.
void unpack_pseudo_costs(BCP_buffer &buf)
int numNlpFailed_
A counter for how many times in a row did the NLP code fail.
Definition: BM.hpp:295
const OsiPseudoCosts & pseudoCosts() const
Access to pseudo costs storage.
int infNum_
Definition: BM.hpp:315
virtual void setColUpper(int elementIndex, double elementValue)
Set a single column upper bound.
Bonmin::Algorithm getAlgorithm()
Get the algorithm used.
double integerTolerance_
Definition: BM.hpp:289
Bonmin::BonminAmplSetup bonmin_
This contains the setup for running Bonmin in particular nlp solver, continuous solver, cut generators,...
Definition: BM.hpp:287
virtual void process_message(BCP_buffer &buf)
Process a message that has been sent by another process&#39; user part to this process&#39; user part...
int * infInd_
Every time when branching decisions are to be made, we create 6 arrays, 3 for those objects that are ...
Definition: BM.hpp:313
int numNlpFailed_
A counter for how many times in a row did the NLP code fail.
Definition: BM.hpp:32
int colInd
Definition: BM.hpp:248
BCP_vec< BCP_user_data * > & user_data()
Return a reference to the user data vector.
BCP_lp_prob * getLpProblemPointer()
Get the pointer.
Definition: BCP_lp_user.hpp:95
void clear_SB_results()
int objInd
Definition: BM.hpp:247
An LP process (that is used as a strong branching node) indicates that it&#39;s finished.
OsiSolverInterface * lp_solver
A class that holds the methods about how to pack things.
Definition: BCP_lp.hpp:137
void set_presolve_result(const BCP_vec< double > &objval, const BCP_vec< int > &termcode)
The constructor makes a copy of each vector passed to it.
OsiChooseVariable * branchingMethod()
branching method to use.
virtual BCP_branching_decision select_branching_candidates(const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, const BCP_lp_var_pool &local_var_pool, const BCP_lp_cut_pool &local_cut_pool, BCP_vec< BCP_lp_branching_object * > &cans, bool force_branch=false)
Decide whether to branch or not and select a set of branching candidates if branching is decided upon...
double objval() const
double solval
Definition: BM.hpp:159
This class describes a generic branching object.
void fint fint fint fint fint fint fint fint fint fint real real real real real real real real * s
virtual CoinWarmStart * convert_to_CoinWarmStart() const =0
Return an OsiWarmStart object that can be fed to the LP engine.
int changeType
Definition: BM.hpp:156
virtual bool isIterationLimitReached() const
Iteration limit reached?
BCP_branching_decision
This enumerative constant is the return value of the select_branching_candidates() method in [BCP_lp_...
void clear()
Completely clear the buffer.
Definition: BCP_buffer.hpp:168
void fint fint fint real fint real real real real real real real real real fint real fint fint fint real * ws
void computeMultipliers(double &upMult, double &downMult) const
int objInd
Definition: BM.hpp:157
void send_pseudo_cost_update(OsiBranchingInformation &branchInfo)
Methods invoked from bbBranch()
static bool ifprint
void set_size(const int s)
Cut off the end of the buffer.
Definition: BCP_buffer.hpp:110
int * objInd_
These are the indices of the integral (i.e., things that can be branched on) objects in the solver...
Definition: BM.hpp:302
double upper_bound() const
Return what is the best known upper bound (might be BCP_DBL_MAX)
Definition: BCP_lp_user.cpp:29
Currently there isn&#39;t any error handling in BCP.
Definition: BCP_error.hpp:20
double * infUseful_
Definition: BM.hpp:314
int colInd
Definition: BM.hpp:158
The node should be fathomed without even trying to branch.
A presolved branching object candidate.
BCP_buffer bm_buf
Definition: BM.hpp:283
virtual int try_to_branch(OsiBranchingInformation &branchInfo, OsiSolverInterface *solver, OsiChooseVariable *choose, OsiBranchingObject *&branchObject, bool allowVarFix)
Select the &quot;close-to-half&quot; variables for strong branching.
void receive_message(const int sender, BCP_buffer &buf, BCP_message_tag tag=BCP_Msg_User)
Wait for a message and receive it.
void incNumberSbSolves(int cnt)
Definition: BM.hpp:123
int try_to_branch(OsiBranchingInformation &branchInfo, OsiSolverInterface *solver, Bonmin::BonChooseVariable *choose, OsiBranchingObject *&branchObject, bool allowVarFix)
BCP_parameter_set< BM_par > par
Definition: BM.hpp:282
This class describes the message buffer used for all processes of BCP.
Definition: BCP_buffer.hpp:39
BCP_warmstart * BCP_unpack_warmstart(BCP_buffer &buf)
virtual const double * getColUpper() const
Get pointer to array[getNumCols()] of column upper bounds.
OsiTMINLPInterface * nonlinearSolver()
Pointer to the non-linear solver used.
Ipopt::SmartPtr< Ipopt::OptionsList > options()
Acces list of Options.
int termcode() const
Used by the user to send a message to the user portion of the other process.
BM_SB_result * sbResult_
This is where we keep the results in case of distributed strong branching.
Definition: BM.hpp:322
This class exist only so that we can extract information from OsiIntegerBranchingObject.
void incNumberNodeSolves()
Definition: BM.hpp:120
BCP_lp_prob * p
Definition: BCP_lp_user.hpp:82
This class holds the results after solving an LP relaxation.
Branching must be done.
bool empty() const
Is this an empty warm start?
bool over_ub(double lb) const
Return true / false depending on whether the lb argument is over the current upper bound or not...
Definition: BCP_lp_user.cpp:30
Send a list of process ids the LP can use to do distributed strong branching.
virtual void setColLower(int elementIndex, double elementValue)
Set a single column lower bound.
int status
Definition: BM.hpp:162
bool isBranchFathomable(int status, double obj)
static char * t
Definition: OSdtoa.cpp:3645
void send_feasible_solution(const BCP_solution *sol)
Definition: BCP_lp_user.cpp:77
int sort_objects(OsiBranchingInformation &branchInfo, Bonmin::BonChooseVariable *choose, int &branchNum)
return b
Definition: OSdtoa.cpp:1719
void incNumberFixed()
Definition: BM.hpp:126
bool getDblParam(OsiDblParam key, double &value) const
int size() const
Return the size of the current message in the buffer.
Definition: BCP_buffer.hpp:95
int status[2]
Definition: BM.hpp:249