CouenneVarObject.cpp
Go to the documentation of this file.
1 /* $Id: CouenneVarObject.cpp 792 2012-01-24 17:24:15Z pbelotti $
2  *
3  * Name: CouenneVarObject.cpp
4  * Authors: Pietro Belotti, Carnegie Mellon University
5  * Purpose: Base object for variables (to be used in branching)
6  *
7  * (C) Carnegie-Mellon University, 2008-11.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "CoinHelperFunctions.hpp"
12 
13 #include "BonBabSetupBase.hpp"
14 
15 #include "CouenneProblem.hpp"
16 #include "CouenneVarObject.hpp"
18 #include "CouenneComplObject.hpp"
19 #include "CouenneProblemElem.hpp"
20 
21 using namespace Ipopt;
22 using namespace Couenne;
23 
25 CouenneVarObject::CouenneVarObject (CouenneCutGenerator *c,
26  CouenneProblem *p,
27  exprVar *ref,
28  Bonmin::BabSetupBase *base,
29  JnlstPtr jnlst,
30  int varSelection):
31 
32  // Do not set variable (expression).
33  // This way, no expression-dependent strategy is chosen
34  CouenneObject (c, p, ref, base, jnlst),
35  varSelection_ (varSelection) {
36 
37  if (jnlst_ -> ProduceOutput (J_SUMMARY, J_BRANCHING)) {
38  printf ("created Variable Object: ");
39  reference_ -> print ();
40  printf (" with %s strategy [clamp=%g, alpha=%g]\n",
41  (strategy_ == LP_CLAMPED) ? "lp-clamped" :
42  (strategy_ == LP_CENTRAL) ? "lp-central" :
43  (strategy_ == BALANCED) ? "balanced" :
44  (strategy_ == MIN_AREA) ? "min-area" :
45  (strategy_ == MID_INTERVAL) ? "mid-point" :
46  (strategy_ == NO_BRANCH) ? "no-branching (null infeasibility)" :
47  "no strategy",
48  lp_clamp_, alpha_);
49  }
50 }
51 
52 
54 OsiBranchingObject *CouenneVarObject::createBranch (OsiSolverInterface *si,
55  const OsiBranchingInformation *info,
56  int way) const {
57 
58  // Before anything, use the LP point if so instructed
59 
60  problem_ -> domain () -> push
61  (problem_ -> nVars (),
62  info -> solution_,
63  info -> lower_,
64  info -> upper_, false); // don't have to alloc+copy
65 
66  OsiBranchingObject *obj = NULL;
67 
68  // For some obscure reason, this only seems to work if
69  // strong/reliability branching is not used. I suppose it has to do
70  // with omitted pseudocost multiplier update, or some other hidden
71  // part of the code.
72 
77 
78  int indVar = reference_ -> Index ();
79 
80  CouNumber
81  brpt = info -> solution_ [indVar],
82  l = info -> lower_ [indVar],
83  u = info -> upper_ [indVar];
84 
85  // these vanilla assignments would drive Couenne crazy. If any of
86  // the bounds is (in absolute value) above 1e20, branching values
87  // can be detrimental for bound tightening and convexification
88  // cuts, for instance.
89 
90  // Actually, even smaller values (such as 1e10) can trigger bad BB
91  // tree development (see wall in test files, not globallib/wall)
92 
93 #define LARGE_VALUE 1e8
94 
95  if ((l < - LARGE_VALUE) &&
96  (u > LARGE_VALUE) &&
97  (fabs (brpt) > LARGE_VALUE / 10))
98  brpt = 0.;
99 
100  if (l < - COUENNE_INFINITY) l = -1. - 2 * fabs (brpt);
101  if (u > COUENNE_INFINITY) u = +1. + 2 * fabs (brpt);
102 
103  CouNumber width = lp_clamp_ * (u-l);
104 
105  switch (strategy_) {
106 
107  case CouenneObject::LP_CLAMPED: brpt = CoinMax (l + width, CoinMin (brpt, u - width)); break;
108  case CouenneObject::LP_CENTRAL: if ((brpt < l + width) ||
109  (brpt > u - width)) brpt = .5 * (l+u); break;
110  case CouenneObject::MID_INTERVAL: brpt = midInterval (brpt,
111  info -> lower_ [indVar],
112  info -> upper_ [indVar], info); break;
113  default: assert (false); // this will never be used
114  }
115 
116  obj = new CouenneBranchingObject (si, this, jnlst_, cutGen_, problem_, reference_,
117  TWO_LEFT, brpt, doFBBT_, doConvCuts_);
118  } else {
119 
120  // now deal with the more complicated branching selections
121 
122  // The infeasibility on an (independent) variable x_i is given by
123  // something more elaborate than |w-f(x)|, that is, a function of
124  // all infeasibilities of all expressions which depend on x_i.
125 
126  int bestWay;
127  const CouenneObject *criticalObject = NULL; // should create the branchingObject
128 
129  CouNumber bestPt = computeBranchingPoint (info, bestWay, criticalObject);
130 
132 
133  int indVar = reference_ -> Index ();
134 
135  jnlst_ -> Printf (J_ITERSUMMARY, J_BRANCHING, ":::: creating branching on x_%d @%g [%g,%g]\n",
136  indVar,
137  info -> solution_ [indVar],
138  info -> lower_ [indVar],
139  info -> upper_ [indVar]);
140 
141  obj = criticalObject ?
142  criticalObject -> createBranch (si, info, way) :
144  way, bestPt, doFBBT_, doConvCuts_);
145  }
146 
147  problem_ -> domain () -> pop ();
148 
149  return obj;
150 }
151 
152 
155  int& bestWay,
156  const CouenneObject *&criticalObject) const {
157  criticalObject = NULL;
158 
159  if (jnlst_ -> ProduceOutput (J_DETAILED, J_BRANCHING)) {
160  printf ( "---------- computeBRPT for ");
161  reference_ -> print ();
162  printf (" [%g,%g]\n",
163  info -> lower_ [reference_ -> Index ()],
164  info -> upper_ [reference_ -> Index ()]);
165  }
166 
167  expression *brVar = NULL; // branching variable
168 
169  CouNumber
170  brdistDn = 0.,
171  brdistUp = 0.,
172  bestPt = 0.,
173  *brPts = NULL, // branching point(s)
174  *brDist = NULL, // distances from LP point to each new convexification
175  maxdist = - COIN_DBL_MAX;
176 
177  bool chosen = false;
178 
179  bestWay = TWO_LEFT;
180 
181  int
182  whichWay = TWO_LEFT,
183  index = reference_ -> Index ();
184 
185  std::set <int> deplist = problem_ -> Dependence () [index];
186 
187  for (std::set <int>::iterator i = deplist.begin (); i != deplist.end (); ++i) {
188 
189  const CouenneObject *obj = problem_ -> Objects () [*i];
190 
191  CouNumber improv = 0.;
192 
193  assert (obj -> Reference ());
194 
195  if (jnlst_ -> ProduceOutput (J_MATRIX, J_BRANCHING)) {
196  printf (" dependence: ");
197  obj -> Reference () -> print ();
198  if (reference_ -> Image ()) {printf (" := "); obj -> Reference () -> Image () -> print ();}
199  printf ("\n");
200  }
201 
202  if (obj -> Reference ()) {
203  if (obj -> Reference () -> Image ())
204 
205  improv = obj -> Reference () -> Image ()
206  -> selectBranch (obj, info, // input parameters
207  brVar, brPts, brDist, whichWay); // result: who, where, distances, direction
208  else {
209 
210  brVar = obj -> Reference ();
211  brPts = (double *) realloc (brPts, sizeof (double));
212  brDist = (double *) realloc (brDist, 2 * sizeof (double));
213 
214  double point = info -> solution_ [obj -> Reference () -> Index ()];
215 
216  *brPts = point;
217  improv = 0.;
218 
219  if (point > floor (point)) {improv = brDist [0] = point - floor (point);}
220  if (point < ceil (point)) {improv = CoinMin (improv, brDist [1] = ceil (point) - point);}
221 
222  point -= floor (point);
223  whichWay = (point < 0.45) ? TWO_LEFT : (point > 0.55) ? TWO_RIGHT : TWO_RAND;
224  }
225  }
226 
227  if (jnlst_ -> ProduceOutput (J_MATRIX, J_BRANCHING)) {
228  printf (" --> Branching on ");
229  if (brVar) {
230  brVar -> print ();
231  if (brPts)
232  printf (" at %g, improv %g <%g>, indices = %d,%d\n",
233  *brPts, improv, maxdist, index, brVar -> Index ());
234  }
235  }
236 
237  if (brVar &&
238  (brVar -> Index () == index) && // it's us!
239  (fabs (improv) > maxdist) && // this branching seems to induce a higher improvement
240  (fabs (*brPts) < COU_MAX_COEFF)) { // and branching pt is limited
241 
242  criticalObject = (problem_ -> Objects () [*i]); // set this object as the branch creator
243 
244  brdistDn = brDist [0];
245  brdistUp = brDist [1];
246  chosen = true;
247  bestPt = *brPts;
248  maxdist = improv;
249  bestWay = whichWay;
250  }
251  }
252 
253  // no hits on this VarObject's variable, that is, this variable was
254  // never chosen
255 
256  if (!chosen) {
257 
258  bestPt = info -> solution_ [index];
259  brVar = reference_;
260 
261  CouNumber
262  l = info -> lower_ [index],
263  u = info -> upper_ [index],
264  width = lp_clamp_ * (u-l);
265 
266  switch (strategy_) {
267 
269  bestPt = CoinMax (l + width, CoinMin (bestPt, u - width));
270  break;
271 
273  if ((bestPt < l + width) || (bestPt > u - width))
274  bestPt = (l+u)/2;
275  break;
276 
278 
279  default:
280  // all other cases (balanced, min-area)
281  bestPt = midInterval (bestPt, l, u, info);
282 
283  if (jnlst_ -> ProduceOutput (J_MATRIX, J_BRANCHING)) {
284  if (CoinMin (fabs (bestPt - l), fabs (bestPt - u)) < 1e-3) {
285  printf ("computed failsafe %g [%g,%g] for ", bestPt, l,u);
286  reference_ -> print (); printf ("\n");
287  }
288  }
289 
290  break;
291  }
292 
293  if ((l < - large_bound) &&
294  (u > large_bound) &&
295  (fabs (bestPt) > large_bound))
296  bestPt = 0.;
297 
298  brPts = (double *) realloc (brPts, sizeof (double));
299  *brPts = bestPt;
300 
301  if (jnlst_ -> ProduceOutput (J_MATRIX, J_BRANCHING)) {
302  printf (" ::: failsafe: %g [%g,%g] for ",
303  bestPt, info -> lower_ [index], info -> upper_ [index]);
304  reference_ -> print ();
305  printf ("\n");
306  }
307 
308  } else {
309 
310  if (jnlst_ -> ProduceOutput (J_MATRIX, J_BRANCHING)) {
311  if (CoinMin (fabs (bestPt - info -> lower_ [index]),
312  fabs (bestPt - info -> upper_ [index])) < 1e-3) {
313  printf (" computed %g [%g,%g] for ",
314  bestPt, info -> lower_ [index], info -> upper_ [index]);
315  reference_ -> print ();
316  printf ("\n");
317  }
318  }
319  }
320 
321  if (pseudoMultType_ == PROJECTDIST) {
322 
323  if (chosen) {
324  downEstimate_ = brdistDn;
325  upEstimate_ = brdistUp;
326  }
327  else downEstimate_ = upEstimate_ = 1.;
328  }
329 
330  if (brPts) free (brPts);
331  if (brDist) free (brDist);
332 
333  return bestPt;
334 }
335 
336 
337 #define TOL 0.
338 
340 double CouenneVarObject::feasibleRegion (OsiSolverInterface *solver,
341  const OsiBranchingInformation *info) const {
342  int index = reference_ -> Index ();
343 
344  assert (index >= 0);
345 
346  double val = info -> solution_ [index];
347 
348  // fix that variable to its current value
349  solver -> setColLower (index, val-TOL);
350  solver -> setColUpper (index, val+TOL);
351 
352  return 0.;
353 }
354 
355 
358 
359  const std::set <int> &deplist = problem_ -> Dependence () [reference_ -> Index ()];
360  const std::vector <CouenneObject *> &objects = problem_ -> Objects ();
361 
362  for (std::set <int>::const_iterator depvar = deplist. begin ();
363  depvar != deplist. end (); ++depvar)
364  if (!(objects [*depvar] -> isCuttable ()))
365  return false;
366 
367  return (!(reference_ -> isInteger ()));
368 }
369 
Cut Generator for linear convexifications.
const double large_bound
if |branching point| &gt; this, change it
virtual bool isCuttable() const
are we on the bad or good side of the expression?
virtual OsiBranchingObject * createBranch(OsiSolverInterface *, const OsiBranchingInformation *, int) const
create CouenneBranchingObject or CouenneThreeWayBranchObj based on this object
void fint fint fint real fint real real real real real real real real real fint real fint fint fint real fint fint fint fint * info
OsiObject for auxiliary variables $w=f(x)$.
virtual double feasibleRegion(OsiSolverInterface *, const OsiBranchingInformation *) const
fix nonlinear coordinates of current integer-nonlinear feasible solution
CouNumber alpha_
Combination parameter for the mid-point branching point selection strategy.
#define LARGE_VALUE
exprVar * reference_
The (auxiliary) variable this branching object refers to.
&quot;Spatial&quot; branching object.
enum brSelStrat strategy_
Branching point selection strategy.
const Ipopt::EJournalCategory J_BRANCHING(Ipopt::J_USER1)
bool doFBBT_
shall we do Feasibility based Bound Tightening (FBBT) at branching?
CouNumber computeBranchingPoint(const OsiBranchingInformation *info, int &bestWay, const CouenneObject *&criticalObject) const
Method computing the branching point.
double downEstimate_
down estimate (to be used in pseudocost)
CouenneProblem * problem_
pointer to Couenne problem
void fint fint fint real fint real real real real real real real real real * e
A class to have all elements necessary to setup a branch-and-bound.
fint end
int varSelection_
branching scheme used.
bool doConvCuts_
shall we add convexification cuts at branching?
Class for MINLP problems with symbolic information.
#define COU_MAX_COEFF
double CouNumber
main number type in Couenne
#define TOL
enum pseudocostMult pseudoMultType_
multiplier type for pseudocost
double upEstimate_
up estimate (to be used in pseudocost)
CouNumber midInterval(CouNumber x, CouNumber l, CouNumber u, const OsiBranchingInformation *info=NULL) const
returns a point &quot;inside enough&quot; a given interval, or x if it already is.
#define COUENNE_INFINITY
exprVar * Reference() const
return reference auxiliary variable
variable-type operator
CouenneCutGenerator * cutGen_
pointer to cut generator (not necessary, can be NULL)
CouNumber lp_clamp_
Defines safe interval percentage for using LP point as a branching point.
Expression base class.
JnlstPtr jnlst_
SmartPointer to the Journalist.
real c
bool isInteger(CouNumber x)
is this number integer?