Scippy

SCIP

Solving Constraint Integer Programs

prop_vbounds.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2016 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file prop_vbounds.c
17  * @brief variable upper and lower bound propagator
18  * @author Stefan Heinz
19  * @author Jens Schulz
20  * @author Gerald Gamrath
21  *
22  * This propagator uses global bound information provided by SCIP to deduce global and local bound changes.
23  * It can take into account
24  * - implications (bound change following from specific value of a binary variable)
25  * - cliques (set of binary variables, each with a corresponding value, of which at most one variable can get the value)
26  * - variable lower/upper bounds (bounds of arbitrary variables that depend linearly on the value of another variable)
27  *
28  * The propagator does not look at a variable in whole, but at one point in time only handles one specific bound (lower
29  * or upper) of a variable and deduces changes for lower or upper bounds of other variables. The concept is as follows:
30  *
31  * 1) Extract variable bound data
32  *
33  * Implications and cliques are stored in a way such that given a variable and its new value, we can access all bound
34  * changes that can be deduced from setting the variable to that value. However, for variable bounds, this currently
35  * does not hold, they are only stored in the other direction, i.e. for a bound of a given variable, we have a list
36  * of all other bounds of variables that directly influence the bound of the given variable and a linear function
37  * describing how they do this.
38  * For the propagation, we need the other direction, thus we store it in the propagator data when the branch-and-bound
39  * solving process is about to begin.
40  *
41  * 2) Topological sorting of bounds of variable
42  *
43  * We compute a topological order of the bounds of variables. This is needed to define an order in which we will
44  * regard bounds of variables in the propagation process in order to avoid unneccessarily regarding the same variable
45  * bound multiple times because it was changed in the meantime when propagating another bound of a variable.
46  * Therefore, we implictly regard a directed graph, in which each node corresponds to a bound of a variable and there
47  * exists a directed edge from one node to another, if the bound corresponding to the former node influences the
48  * bound corresponding to the latter node. This is done by iteratively running a DFS until all nodes were visited.
49  * Note that there might be cycles in the graph, which are randomly broken, so the order is only almost topological.
50  *
51  * 3) Collecting bound changes
52  *
53  * For each bound of a variable, which can trigger bound changes of other variables, the propagator catches all
54  * events informing about a global change of the bound or a local toghtening of the bound. The event handler
55  * then adds the bound of the variable to a priority queue, with the key in the priority queue corresponding
56  * to the position of the bound in the topological sort.
57  *
58  * 4) Propagating Bounds
59  *
60  * As long as there are bounds contained in the priority queue, the propagator pops one bound from the queue, which
61  * is the one most at the beginning of the topological sort, so it should not be influenced by propagating other
62  * bounds currently contained in the queue. Starting at this bound, all implication, clique, and variable bound
63  * information is used to deduce tigther bounds for other variables and change the bounds, if a tighter one is found.
64  * These bound changes trigger an event that will lead to adding the corresponding bound to the priority queue,
65  * if it is not contained, yet. The process is iterated until the priority queue contains no more bounds.
66  */
67 
68 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
69 
70 #include <assert.h>
71 #include <string.h>
72 
73 #include "scip/prop_vbounds.h"
74 
75 /**@name Propagator properties
76  *
77  * @{
78  */
79 
80 #define PROP_NAME "vbounds"
81 #define PROP_DESC "propagates variable upper and lower bounds"
82 #define PROP_TIMING SCIP_PROPTIMING_BEFORELP | SCIP_PROPTIMING_AFTERLPLOOP
83 #define PROP_PRIORITY 3000000 /**< propagator priority */
84 #define PROP_FREQ 1 /**< propagator frequency */
85 #define PROP_DELAY FALSE /**< should propagation method be delayed, if other propagators found reductions? */
86 
87 /**@} */
88 
89 /**@name Event handler properties
90  *
91  * @{
92  */
93 
94 #define EVENTHDLR_NAME "vbounds"
95 #define EVENTHDLR_DESC "bound change event handler for for vbounds propagator"
96 
97 /**@} */
98 
99 /**@name Default parameter values
100  *
101  * @{
102  */
103 
104 #define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used to initialize conflict analysis? */
105 #define DEFAULT_USEIMPLICS FALSE /**< should implications be propagated? */
106 #define DEFAULT_USECLIQUES FALSE /**< should cliques be propagated? */
107 #define DEFAULT_USEVBOUNDS TRUE /**< should variable bounds be propagated? */
108 #define DEFAULT_DOTOPOSORT TRUE /**< should the bounds be topologically sorted in advance? */
109 #define DEFAULT_SORTCLIQUES FALSE /**< should cliques be regarded for the topological sort? */
110 
111 /**@} */
112 
113 /**@name Propagator defines
114  *
115  * @{
116  *
117  * The propagator works on indices representing a bound of a variable. This index will be called bound index in the
118  * following. For a given active variable with problem index i (note that active variables have problem indices
119  * between 0 and nactivevariable - 1), the bound index of its lower bound is 2*i, the bound index of its upper
120  * bound is 2*i + 1. The other way around, a given bound index i corresponds to the variable with problem index
121  * i/2 (rounded down), and to the lower bound, if i is even, to the upper bound if i is odd.
122  * The following macros can be used to convert bound index into variable problem index and boundtype and vice versa.
123  */
124 #define getLbIndex(idx) (2*(idx))
125 #define getUbIndex(idx) (2*(idx)+1)
126 #define getVarIndex(idx) ((idx)/2)
127 #define getBoundtype(idx) (((idx) % 2 == 0) ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER)
128 #define isIndexLowerbound(idx) ((idx) % 2 == 0)
129 #define getBoundString(lower) ((lower) ? "lb" : "ub")
130 #define getBoundtypeString(type) ((type) == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper")
131 #define indexGetBoundString(idx) (getBoundString(isIndexLowerbound(idx)))
132 
133 /**@} */
134 
135 /*
136  * Data structures
137  */
138 
139 /** propagator data */
140 struct SCIP_PropData
141 {
142  SCIP_EVENTHDLR* eventhdlr; /**< event handler for catching bound changes */
143  SCIP_VAR** vars; /**< array containing all variable which are considered within the propagator */
144  SCIP_HASHMAP* varhashmap; /**< hashmap mapping from variable to index in the vars array */
145  int* topoorder; /**< array mapping on the bounds of variables in topological order;
146  * or -1, if the bound that should be at that position has no outgoing
147  * implications, cliques, or vbounds;
148  * i.e., for i < j and topoorder[i] != -1 != topoorder[j], the variable
149  * and boundtype represented by index topoorder[i] are earlier in the
150  * topological order than those represented by index topoorder[j]
151  */
152  int** vboundboundedidx; /**< array storing for each bound index the bound indices of all bounds
153  * influenced by this bound through variable bounds */
154  SCIP_Real** vboundcoefs; /**< array storing for each bound index the coefficients in the variable
155  * bounds influencing the corresponding bound index stored in
156  * vboundboundedidx */
157  SCIP_Real** vboundconstants; /**< array storing for each bound index the constants in the variable
158  * bounds influencing the corresponding bound index stored in
159  * vboundboundedidx */
160  int* nvbounds; /**< array storing for each bound index the number of vbounds stored */
161  int* vboundsize; /**< array with sizes of vbound arrays for the nodes */
162  int nbounds; /**< number of bounds of variables regarded (two times number of active variables) */
163  SCIP_PQUEUE* propqueue; /**< priority queue to handle the bounds of variables that were changed and have to be propagated */
164  SCIP_Bool* inqueue; /**< boolean array to store whether a bound of a variable is already contained in propqueue */
165  SCIP_Bool initialized; /**< was the data for propagation already initialized? */
166  SCIP_Bool usebdwidening; /**< should bound widening be used to initialize conflict analysis? */
167  SCIP_Bool useimplics; /**< should implications be propagated? */
168  SCIP_Bool usecliques; /**< should cliques be propagated? */
169  SCIP_Bool usevbounds; /**< should variable bounds be propagated? */
170  SCIP_Bool dotoposort; /**< should the bounds be topologically sorted in advance? */
171  SCIP_Bool sortcliques; /**< should cliques be regarded for the topological sort? */
172 };
173 
174 /** inference information */
175 struct InferInfo
176 {
177  union
178  {
179  struct
180  {
181  unsigned int pos:31; /**< position of the variable which forced that propagation */
182  unsigned int boundtype:1; /**< bound type which was the reason (0: lower, 1: upper) */
183  } asbits;
184  int asint; /**< inference information as a single int value */
185  } val;
186 };
187 typedef struct InferInfo INFERINFO;
188 
189 /** converts an integer into an inference information */
190 static
192  int i /**< integer to convert */
193  )
194 {
195  INFERINFO inferinfo;
196 
197  inferinfo.val.asint = i;
198 
199  return inferinfo;
200 }
201 
202 /** converts an inference information into an int */
203 static
205  INFERINFO inferinfo /**< inference information to convert */
206  )
207 {
208  return inferinfo.val.asint;
209 }
210 
211 /** returns the propagation rule stored in the inference information */
212 static
214  INFERINFO inferinfo /**< inference information to convert */
215  )
216 {
217  assert((SCIP_BOUNDTYPE)inferinfo.val.asbits.boundtype == SCIP_BOUNDTYPE_LOWER
218  || (SCIP_BOUNDTYPE)inferinfo.val.asbits.boundtype == SCIP_BOUNDTYPE_UPPER);
219  return (SCIP_BOUNDTYPE)inferinfo.val.asbits.boundtype;
220 }
221 
222 /** returns the position stored in the inference information */
223 static
225  INFERINFO inferinfo /**< inference information to convert */
226  )
227 {
228  return (int) inferinfo.val.asbits.pos;
229 }
230 
231 /** constructs an inference information out of a position of a variable and a boundtype */
232 static
234  int pos, /**< position of the variable which forced that propagation */
235  SCIP_BOUNDTYPE boundtype /**< propagation rule that deduced the value */
236  )
237 {
238  INFERINFO inferinfo;
239 
240  assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER);
241  assert((int)boundtype >= 0 && (int)boundtype <= 1); /*lint !e685 !e568q*/
242  assert(pos >= 0);
243 
244  inferinfo.val.asbits.pos = (unsigned int) pos; /*lint !e732*/
245  inferinfo.val.asbits.boundtype = (unsigned int) boundtype; /*lint !e641*/
246 
247  return inferinfo;
248 }
249 
250 /*
251  * Local methods
252  */
253 
254 /* returns the lower bound index of a variable */
255 static
257  SCIP_PROPDATA* propdata, /**< propagator data */
258  SCIP_VAR* var /**< variable to get the index for */
259  )
260 {
261  assert(SCIPhashmapExists(propdata->varhashmap, var) == ((size_t)SCIPhashmapGetImage(propdata->varhashmap, var) > 0));
262 
263  return getLbIndex((int)(size_t)SCIPhashmapGetImage(propdata->varhashmap, var) - 1);
264 }
265 
266 /* returns the upper bound index of a variable */
267 static
269  SCIP_PROPDATA* propdata, /**< propagator data */
270  SCIP_VAR* var /**< variable to get the index for */
271  )
272 {
273  assert(SCIPhashmapExists(propdata->varhashmap, var) == ((size_t)SCIPhashmapGetImage(propdata->varhashmap, var) > 0));
274 
275  return getUbIndex((int)(size_t)SCIPhashmapGetImage(propdata->varhashmap, var) - 1);
276 }
277 
278 /** reset propagation data */
279 static
281  SCIP_PROPDATA* propdata /**< propagator data */
282  )
283 {
284  propdata->vars = NULL;
285  propdata->varhashmap = NULL;
286  propdata->topoorder = NULL;
287  propdata->vboundboundedidx = NULL;
288  propdata->vboundcoefs = NULL;
289  propdata->vboundconstants = NULL;
290  propdata->nvbounds = NULL;
291  propdata->vboundsize = NULL;
292  propdata->nbounds = 0;
293  propdata->initialized = FALSE;
294 }
295 
296 /** catches events for variables */
297 static
299  SCIP* scip, /**< SCIP data structure */
300  SCIP_PROPDATA* propdata /**< propagator data */
301  )
302 {
303  SCIP_EVENTHDLR* eventhdlr;
304  SCIP_EVENTTYPE eventtype;
305  SCIP_VAR** vars;
306  SCIP_VAR* var;
307  SCIP_Bool lower;
308  int nbounds;
309  int v;
310  int idx;
311 
312  assert(scip != NULL);
313  assert(propdata != NULL);
314  assert(propdata->vars != NULL);
315  assert(propdata->topoorder != NULL);
316 
317  /* catch variable events according to computed eventtypes */
318  eventhdlr = propdata->eventhdlr;
319  assert(eventhdlr != NULL);
320 
321  vars = propdata->vars;
322  nbounds = propdata->nbounds;
323 
324  /* setup events */
325  for( v = 0; v < nbounds; ++v )
326  {
327  idx = propdata->topoorder[v];
328  assert(idx >= 0 && idx < nbounds);
329 
330  var = vars[getVarIndex(idx)];
331  lower = isIndexLowerbound(idx);
332 
333  /* if the bound does not influence another bound by implications, cliques, or vbounds,
334  * we do not create an event and do not catch changes of the bound;
335  * we mark this by setting the value in topoorder to -1
336  */
337  if( propdata->nvbounds[idx] == 0 && SCIPvarGetNImpls(var, lower) == 0 && SCIPvarGetNCliques(var, lower) == 0 )
338  {
339  propdata->topoorder[v] = -1;
340  continue;
341  }
342 
343  /* determine eventtype that we want to catch depending on boundtype of variable */
344  if( lower )
346  else
348 
349  SCIP_CALL( SCIPcatchVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*) (size_t) v, NULL) ); /*lint !e571*/
350  }
351 
352  return SCIP_OKAY;
353 }
354 
355 
356 /** drops events for variables */
357 static
359  SCIP* scip, /**< SCIP data structure */
360  SCIP_PROPDATA* propdata /**< propagator data */
361  )
362 {
363  SCIP_EVENTHDLR* eventhdlr;
364  SCIP_EVENTTYPE eventtype;
365  SCIP_VAR** vars;
366  SCIP_VAR* var;
367  SCIP_Bool lower;
368  int nbounds;
369  int v;
370  int idx;
371 
372  assert(propdata != NULL);
373 
374  eventhdlr = propdata->eventhdlr;
375  assert(eventhdlr != NULL);
376 
377  vars = propdata->vars;
378  nbounds = propdata->nbounds;
379 
380  for( v = 0; v < nbounds; ++v )
381  {
382  idx = propdata->topoorder[v];
383 
384  if( idx == -1 )
385  continue;
386 
387  assert(idx >= 0 && idx < nbounds);
388 
389  var = vars[getVarIndex(idx)];
390  lower = isIndexLowerbound(idx);
391 
392  /* determine eventtype that we catch and now want to drop depending on boundtype of variable */
393  if( lower )
395  else
397 
398  SCIP_CALL( SCIPdropVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*) (size_t) v, -1) ); /*lint !e571*/
399  }
400 
401  return SCIP_OKAY;
402 }
403 
404 #define INITMEMSIZE 5
405 
406 /* adds a vbound to the propagator data to store it internally and allow forward propagation */
407 static
409  SCIP* scip, /**< SCIP data structure */
410  SCIP_PROPDATA* propdata, /**< propagator data */
411  int startidx, /**< index of bound of variable influencing the other variable */
412  int endidx, /**< index of bound of variable which is influenced */
413  SCIP_Real coef, /**< coefficient in the variable bound */
414  SCIP_Real constant /**< constant in the variable bound */
415  )
416 {
417  int nvbounds;
418 
419  assert(scip != NULL);
420  assert(propdata != NULL);
421 
422  if( propdata->vboundsize[startidx] == 0 )
423  {
424  /* allocate memory for storing vbounds */
425  propdata->vboundsize[startidx] = INITMEMSIZE;
426 
427  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundboundedidx[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
428  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundcoefs[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
429  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundconstants[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
430  }
431  else if( propdata->nvbounds[startidx] >= propdata->vboundsize[startidx] )
432  {
433  /* reallocate memory for storing vbounds */
434  propdata->vboundsize[startidx] = SCIPcalcMemGrowSize(scip, propdata->nvbounds[startidx] + 1);
435  assert(propdata->nvbounds[startidx] < propdata->vboundsize[startidx]);
436 
437  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundboundedidx[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
438  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundcoefs[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
439  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundconstants[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
440  }
441 
442  nvbounds = propdata->nvbounds[startidx];
443  propdata->vboundboundedidx[startidx][nvbounds] = endidx;
444  propdata->vboundcoefs[startidx][nvbounds] = coef;
445  propdata->vboundconstants[startidx][nvbounds] = constant;
446  (propdata->nvbounds[startidx])++;
447 
448  return SCIP_OKAY;
449 }
450 
451 
452 /** comparison method for two indices in the topoorder array, preferring higher indices because the order is reverse
453  * topological
454  */
455 static
456 SCIP_DECL_SORTPTRCOMP(compVarboundIndices)
457 {
458  int idx1 = (int)(size_t)elem1;
459  int idx2 = (int)(size_t)elem2;
460 
461  return idx2 - idx1;
462 }
463 
464 /** performs depth-first-search in the implicitly given directed graph from the given start index */
465 static
467  SCIP* scip, /**< SCIP data structure */
468  SCIP_PROPDATA* propdata, /**< propagator data */
469  int startnode, /**< node to start the depth-first-search */
470  SCIP_Bool* visited, /**< array to store for each node, whether it was already visited */
471  int* dfsstack, /**< array of size number of nodes to store the stack;
472  * only needed for performance reasons */
473  int* stacknextedge, /**< array of size number of nodes to store the number of adjacent nodes
474  * already visited for each node on the stack; only needed for
475  * performance reasons */
476  int* dfsnodes, /**< array of nodes that can be reached starting at startnode, in reverse
477  * dfs order */
478  int* ndfsnodes /**< pointer to store number of nodes that can be reached starting at
479  * startnode */
480  )
481 {
482  SCIP_VAR** vars;
483  SCIP_VAR* startvar;
484  SCIP_Bool lower;
485  int stacksize;
486  int curridx;
487  int nimpls;
488  int idx;
489 
490  assert(startnode >= 0);
491  assert(startnode < propdata->nbounds);
492  assert(visited != NULL);
493  assert(visited[startnode] == FALSE);
494  assert(dfsstack != NULL);
495  assert(dfsnodes != NULL);
496  assert(ndfsnodes != NULL);
497 
498  vars = propdata->vars;
499 
500  /* put start node on the stack */
501  dfsstack[0] = startnode;
502  stacknextedge[0] = 0;
503  stacksize = 1;
504  idx = -1;
505 
506  /* we run until no more bounds indices are on the stack, i.e. all changed bounds were propagated */
507  while( stacksize > 0 )
508  {
509  /* get next node from stack */
510  curridx = dfsstack[stacksize - 1];
511 
512  /* mark current node as visited */
513  assert(visited[curridx] == (stacknextedge[stacksize - 1] != 0));
514  visited[curridx] = TRUE;
515 
516  startvar = vars[getVarIndex(curridx)];
517  lower = isIndexLowerbound(curridx);
518 
519  nimpls = 0;
520 
521  if( propdata->sortcliques && propdata->usecliques && stacknextedge[stacksize - 1] == 0 )
522  stacknextedge[stacksize - 1] = -1;
523 
524  /* stacknextedge is negative, if the last visited edge from the current node belongs to a clique;
525  * the index of the clique in the variable's clique list equals abs(stacknextedge) - 1
526  */
527  if( propdata->sortcliques && propdata->usecliques && stacknextedge[stacksize - 1] < 0 )
528  {
529  SCIP_CLIQUE** cliques;
530  int ncliques;
531  int j;
532  int i;
533  SCIP_Bool found;
534 
535  ncliques = SCIPvarGetNCliques(startvar, lower);
536  cliques = SCIPvarGetCliques(startvar, lower);
537  found = FALSE;
538 
539  assert(stacknextedge[stacksize - 1] == -1 || -stacknextedge[stacksize - 1] - 1 < ncliques);
540 
541  /* iterate over all not yet handled cliques and search for an unvisited node */
542  for( j = -stacknextedge[stacksize - 1] - 1; j < ncliques; ++j )
543  {
544  SCIP_VAR** cliquevars;
545  SCIP_Bool* cliquevals;
546  int ncliquevars;
547 
548  cliquevars = SCIPcliqueGetVars(cliques[j]);
549  cliquevals = SCIPcliqueGetValues(cliques[j]);
550  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
551 
552  for( i = 0; i < ncliquevars; ++i )
553  {
554  if( cliquevars[i] == startvar )
555  continue;
556 
557  if( cliquevals[i] )
558  idx = varGetUbIndex(propdata, cliquevars[i]);
559  else
560  idx = varGetLbIndex(propdata, cliquevars[i]);
561 
562  /* break when the first unvisited node is reached */
563  if( idx >= 0 && !visited[idx] )
564  {
565  found = TRUE;
566  break;
567  }
568  }
569  if( found )
570  break;
571  }
572 
573  /* we stopped because we found an unhandled node and not because we reached the end of the list */
574  if( found )
575  {
576  assert(idx >= 0);
577  assert(!visited[idx]);
578  assert(j < ncliques);
579 
580  SCIPdebugMessage("clique: %s(%s) -> %s(%s)\n", getBoundString(lower), SCIPvarGetName(startvar),
582 
583  /* put the adjacent node onto the stack */
584  dfsstack[stacksize] = idx;
585  stacknextedge[stacksize] = 0;
586  stacknextedge[stacksize - 1] = -j - 1;
587  stacksize++;
588  assert(stacksize <= propdata->nbounds);
589 
590  /* restart while loop, get next index from stack */
591  continue;
592  }
593  else
594  {
595  /* we did not find an edge to an unhandled node given by a clique */
596  stacknextedge[stacksize - 1] = 0;
597  }
598  }
599  assert(stacknextedge[stacksize - 1] >= 0);
600 
601  /* go over edges given by implications */
602  if( propdata->useimplics )
603  {
604  nimpls = SCIPvarGetNImpls(startvar, lower);
605 
606  if( stacknextedge[stacksize - 1] < nimpls )
607  {
608  SCIP_VAR** implvars;
609  SCIP_BOUNDTYPE* impltypes;
610  int* implids;
611  int i;
612 
613  implvars = SCIPvarGetImplVars(startvar, lower);
614  impltypes = SCIPvarGetImplTypes(startvar, lower);
615  implids = SCIPvarGetImplIds(startvar, lower);
616 
617  for( i = stacknextedge[stacksize - 1]; i < nimpls; ++i )
618  {
619  /* it might happen that implications point to inactive variables (normally, those are removed when a
620  * variable becomes inactive, but in some cases, it cannot be done), we have to ignore these variables
621  */
622  if( !SCIPvarIsActive(implvars[i]) )
623  continue;
624 
625  /* implication is just a shortcut, so we dont regard it now, because will later go the long way, anyway;
626  * however, if we do regard cliques for the topological order, we use them to get a better order
627  */
628  if( propdata->usecliques && !propdata->sortcliques && implids[i] < 0 )
629  continue;
630 
631  idx = (impltypes[i] == SCIP_BOUNDTYPE_LOWER ? varGetLbIndex(propdata, implvars[i]) : varGetUbIndex(propdata, implvars[i]));
632 
633  /* break when the first unvisited node is reached */
634  if( idx >= 0 && !visited[idx] )
635  break;
636  }
637 
638  /* we stopped because we found an unhandled node and not because we reached the end of the list */
639  if( i < nimpls )
640  {
641  assert(!visited[idx]);
642 
643  SCIPdebugMessage("impl: %s(%s) -> %s(%s)\n", getBoundString(lower), SCIPvarGetName(startvar),
645 
646 
647  /* put the adjacent node onto the stack */
648  dfsstack[stacksize] = idx;
649  stacknextedge[stacksize] = 0;
650  stacknextedge[stacksize - 1] = i + 1;
651  stacksize++;
652  assert(stacksize <= propdata->nbounds);
653 
654  /* restart while loop, get next index from stack */
655  continue;
656  }
657  else
658  {
659  stacknextedge[stacksize - 1] = nimpls;
660  }
661  }
662  }
663  assert(stacknextedge[stacksize - 1] >= nimpls);
664 
665  /* go over edges corresponding by varbounds */
666  if( propdata->usevbounds )
667  {
668  int nvbounds;
669  int* vboundidx;
670  int i;
671 
672  nvbounds = propdata->nvbounds[curridx];
673  vboundidx = propdata->vboundboundedidx[curridx];
674 
675  /* iterate over all vbounds for the given bound */
676  for( i = 0; i < nvbounds; ++i )
677  {
678  idx = vboundidx[i];
679  assert(idx >= 0);
680 
681  /* break when the first unvisited node is reached */
682  if( !visited[idx] )
683  break;
684  }
685 
686  /* we stopped because we found an unhandled node and not because we reached the end of the list */
687  if( i < nvbounds )
688  {
689  assert(!visited[idx]);
690 
691  SCIPdebugMessage("vbound: %s(%s) -> %s(%s)\n", getBoundString(lower), SCIPvarGetName(startvar),
693 
694  /* put the adjacent node onto the stack */
695  dfsstack[stacksize] = idx;
696  stacknextedge[stacksize] = 0;
697  stacknextedge[stacksize - 1] = nimpls + i + 1;
698  stacksize++;
699  assert(stacksize <= propdata->nbounds);
700 
701  /* restart while loop, get next index from stack */
702  continue;
703  }
704 
705  }
706 
707  /* the current node was completely handled, remove it from stack */
708  stacksize--;
709 
710  SCIPdebugMessage("topoorder[%d] = %s(%s)\n", *ndfsnodes, getBoundString(lower), SCIPvarGetName(startvar));
711 
712  /* store node in the sorted nodes array */
713  dfsnodes[(*ndfsnodes)] = curridx;
714  (*ndfsnodes)++;
715  }
716 
717  return SCIP_OKAY;
718 }
719 
720 
721 /** sort the bounds of variables topologically */
722 static
724  SCIP* scip, /**< SCIP data structure */
725  SCIP_PROPDATA* propdata /**< propagator data */
726  )
727 {
728  int* dfsstack;
729  int* stacknextedge;
730  int nsortednodes;
731  int nbounds;
732  int i;
733 
734  assert(scip != NULL);
735  assert(propdata != NULL);
736 
737  nbounds = propdata->nbounds;
738 
739  SCIP_CALL( SCIPallocBufferArray(scip, &dfsstack, nbounds) );
740  SCIP_CALL( SCIPallocBufferArray(scip, &stacknextedge, nbounds) );
741 
742  nsortednodes = 0;
743 
744 #ifndef NDEBUG
745  for( i = 0; i < nbounds; ++i )
746  assert(!propdata->inqueue[i]);
747 #endif
748 
749  /* while there are unvisited nodes, run dfs starting from one of these nodes; the dfs orders are stored in the
750  * topoorder array, later dfs calls are just appended after the stacks of previous dfs calls, which gives us a
751  * reverse topological order
752  */
753  for( i = 0; i < nbounds; ++i )
754  {
755  if( !propdata->inqueue[i] )
756  {
757  SCIP_CALL( dfs(scip, propdata, i, propdata->inqueue, dfsstack, stacknextedge, propdata->topoorder, &nsortednodes) );
758  }
759  }
760  assert(nsortednodes == nbounds);
761 
762  BMSclearMemoryArray(propdata->inqueue, nbounds);
763 
764  SCIPfreeBufferArray(scip, &stacknextedge);
765  SCIPfreeBufferArray(scip, &dfsstack);
766 
767  return SCIP_OKAY;
768 }
769 
770 /** initializes the internal data for the variable bounds propagator */
771 static
773  SCIP* scip, /**< SCIP data structure */
774  SCIP_PROP* prop /**< vbounds propagator */
775  )
776 {
777  SCIP_PROPDATA* propdata;
778  SCIP_VAR** vars;
779  int nvars;
780  int nbounds;
781  int startidx;
782  int v;
783  int n;
784 
785  assert(scip != NULL);
786  assert(prop != NULL);
787 
788  /* get propagator data */
789  propdata = SCIPpropGetData(prop);
790  assert(propdata != NULL);
791  assert(!propdata->initialized);
792 
793  SCIPdebugMessage("initialize vbounds propagator for problem <%s>\n", SCIPgetProbName(scip));
794 
795  vars = SCIPgetVars(scip);
796  nvars = SCIPgetNVars(scip);
797  nbounds = 2 * nvars;
798 
799  /* store size of the bounds of variables array */
800  propdata->nbounds = nbounds;
801 
802  if( nbounds == 0 )
803  return SCIP_OKAY;
804 
805  propdata->initialized = TRUE;
806 
807  /* prepare priority queue structure */
808  SCIP_CALL( SCIPpqueueCreate(&propdata->propqueue, nvars, 2.0, compVarboundIndices) );
809  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->inqueue, nbounds) );
810  BMSclearMemoryArray(propdata->inqueue, nbounds);
811 
812  /* we need to copy the variable since this array is the basis of the propagator and the corresponding variable array
813  * within SCIP might change during the search
814  */
815  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &propdata->vars, vars, nvars) );
816  SCIP_CALL( SCIPhashmapCreate(&propdata->varhashmap, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * nvars)) );
817 
818  for( v = 0; v < nvars; ++v )
819  {
820  SCIP_CALL( SCIPhashmapInsert(propdata->varhashmap, propdata->vars[v], (void*)(size_t)(v + 1)) );
821  }
822 
823  /* allocate memory for the arrays of the propdata */
824  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->topoorder, nbounds) );
825  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundboundedidx, nbounds) );
826  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundcoefs, nbounds) );
827  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundconstants, nbounds) );
828  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->nvbounds, nbounds) );
829  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundsize, nbounds) );
830  BMSclearMemoryArray(propdata->vboundboundedidx, nbounds);
831  BMSclearMemoryArray(propdata->vboundcoefs, nbounds);
832  BMSclearMemoryArray(propdata->vboundconstants, nbounds);
833  BMSclearMemoryArray(propdata->nvbounds, nbounds);
834  BMSclearMemoryArray(propdata->vboundsize, nbounds);
835 
836  for( v = 0; v < nbounds; ++v )
837  {
838  propdata->topoorder[v] = v;
839  propdata->vboundboundedidx[v] = NULL;
840  propdata->vboundcoefs[v] = NULL;
841  propdata->vboundconstants[v] = NULL;
842  propdata->nvbounds[v] = 0;
843  propdata->vboundsize[v] = 0;
844  }
845 
846  /* collect information about varbounds */
847  for( v = 0; v < nbounds; ++v )
848  {
849  SCIP_VAR** vbvars;
850  SCIP_VAR* var;
851  SCIP_Real* coefs;
852  SCIP_Real* constants;
853  SCIP_Bool lower;
854  int nvbvars;
855 
856  var = vars[getVarIndex(v)];
857  lower = isIndexLowerbound(v);
858 
859  /* get the variable bound informations for the current variable */
860  if( lower )
861  {
862  vbvars = SCIPvarGetVlbVars(var);
863  coefs = SCIPvarGetVlbCoefs(var);
864  constants = SCIPvarGetVlbConstants(var);
865  nvbvars = SCIPvarGetNVlbs(var);
866  }
867  else
868  {
869  vbvars = SCIPvarGetVubVars(var);
870  coefs = SCIPvarGetVubCoefs(var);
871  constants = SCIPvarGetVubConstants(var);
872  nvbvars = SCIPvarGetNVubs(var);
873  }
874 
875  /* loop over all variable lower bounds; a variable lower bound has the form: x >= b*y + d,
876  * a variable upper bound the form x <= b*y + d */
877  for( n = 0; n < nvbvars; ++n )
878  {
879  SCIP_VAR* vbvar;
880  SCIP_Real coef;
881  SCIP_Real constant;
882 
883  vbvar = vbvars[n];
884  coef = coefs[n];
885  constant = constants[n];
886  assert(vbvar != NULL);
887 
888  /* transform variable bound variable to an active variable, if possible */
889  SCIP_CALL( SCIPgetProbvarSum(scip, &vbvar, &coef, &constant) );
890  assert(vbvar != NULL);
891 
892  if( !SCIPvarIsActive(vbvar) )
893  continue;
894 
895  /* if the coefficient is positive, the type of bound is the same for the bounded and the bounding variable */
896  if( SCIPisPositive(scip, coef) )
897  startidx = (lower ? varGetLbIndex(propdata, vbvar) : varGetUbIndex(propdata, vbvar));
898  else
899  startidx = (lower ? varGetUbIndex(propdata, vbvar) : varGetLbIndex(propdata, vbvar));
900  assert(startidx >= 0);
901 
902  /* If the vbvar is binary, the vbound should be stored as an implication already.
903  * However, it might happen that vbvar was integer when the variable bound was added, but was converted
904  * to a binary variable later during presolving when its upper bound was changed to 1. In this case,
905  * the implication might not have been created.
906  */
907  if( SCIPvarGetType(vbvar) == SCIP_VARTYPE_BINARY
908  && SCIPvarHasImplic(vbvar, isIndexLowerbound(startidx), var, getBoundtype(v)) )
909  {
910  SCIPdebugMessage("varbound <%s> %s %g * <%s> + %g not added to propagator data due to reverse implication\n",
911  SCIPvarGetName(var), (lower ? ">=" : "<="), coef,
912  SCIPvarGetName(vbvar), constant);
913  }
914  else
915  {
916  SCIP_CALL( addVbound(scip, propdata, startidx, v, coef, constant) );
917 
918  SCIPdebugMessage("varbound <%s> %s %g * <%s> + %g added to propagator data\n",
919  SCIPvarGetName(var), (lower ? ">=" : "<="), coef,
920  SCIPvarGetName(vbvar), constant);
921 
922  }
923  }
924  }
925 
926  /* sort the bounds topologically */
927  if( propdata->dotoposort )
928  {
929  SCIP_CALL( topologicalSort(scip, propdata) );
930  }
931 
932  /* catch variable events */
933  SCIP_CALL( catchEvents(scip, propdata) );
934 
935  return SCIP_OKAY;
936 }
937 
938 
939 /** resolves a propagation by adding the variable which implied that bound change */
940 static
942  SCIP* scip, /**< SCIP data structure */
943  SCIP_PROPDATA* propdata, /**< propagator data */
944  SCIP_VAR* var, /**< variable to be reported */
945  SCIP_BOUNDTYPE boundtype, /**< bound to be reported */
946  SCIP_BDCHGIDX* bdchgidx /**< the index of the bound change, representing the point of time where the change took place, or NULL for the current local bounds */
947  )
948 {
949  assert(propdata != NULL);
950  assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER);
951 
952  SCIPdebugMessage(" -> add %s bound of variable <%s> as reason\n",
953  getBoundtypeString(boundtype), SCIPvarGetName(var));
954 
955  switch( boundtype )
956  {
958  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
959  break;
961  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
962  break;
963  default:
964  SCIPerrorMessage("invalid bound type <%d>\n", boundtype);
965  SCIPABORT();
966  return SCIP_INVALIDDATA; /*lint !e527*/
967  }
968 
969  return SCIP_OKAY;
970 }
971 
972 /** relaxes bound of give variable as long as the given inference bound still leads to a cutoff and add that bound
973  * change to the conflict set
974  */
975 static
977  SCIP* scip, /**< SCIP data structure */
978  SCIP_VAR* var, /**< variable for which the upper bound should be relaxed */
979  SCIP_BOUNDTYPE boundtype, /**< boundtype used for the variable bound variable */
980  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place, or NULL for the current local bounds */
981  SCIP_Real relaxedbd /**< relaxed bound */
982  )
983 {
984  if( boundtype == SCIP_BOUNDTYPE_LOWER )
985  {
986  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, relaxedbd) );
987  }
988  else
989  {
990  assert(boundtype == SCIP_BOUNDTYPE_UPPER);
991  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, relaxedbd) );
992  }
993 
994  return SCIP_OKAY;
995 }
996 
997 /** compute the relaxed bound which is sufficient to propagate the inference lower bound of given variable */
998 static
1000  SCIP* scip, /**< SCIP data structure */
1001  SCIP_VAR* var, /**< variable which was propagated */
1002  SCIP_Real inferlb, /**< inference lower bound */
1003  SCIP_Real coef, /**< inference variable bound coefficient used */
1004  SCIP_Real constant /**< inference variable bound constant used */
1005  )
1006 {
1007  SCIP_Real relaxedbd;
1008 
1009  if( SCIPvarIsIntegral(var) )
1010  relaxedbd = (inferlb - 1.0 + 2*SCIPfeastol(scip) - constant) / coef;
1011  else
1012  relaxedbd = (inferlb - constant) / coef;
1013 
1014  /* check the computed relaxed lower/upper bound is a proper reason for the inference bound which has to be explained */
1015  assert(SCIPisEQ(scip, inferlb, SCIPadjustedVarLb(scip, var, relaxedbd * coef + constant)));
1016 
1017  return relaxedbd;
1018 }
1019 
1020 
1021 /** analyzes an infeasibility which was reached by updating the lower bound of the inference variable above its upper
1022  * bound
1023  */
1024 static
1026  SCIP* scip, /**< SCIP data structure */
1027  SCIP_PROPDATA* propdata, /**< propagator data */
1028  SCIP_VAR* infervar, /**< variable which led to a cutoff */
1029  SCIP_Real inferlb, /**< lower bound which led to infeasibility */
1030  SCIP_VAR* vbdvar, /**< variable which is the reason for the lower bound change */
1031  SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the lower bound change */
1032  SCIP_Real coef, /**< inference variable bound coefficient used */
1033  SCIP_Real constant, /**< inference variable bound constant used */
1034  SCIP_Bool canwide /**< can bound widening be used (for vbounds) or not (for inplications or cliques) */
1035  )
1036 {
1037  assert(scip != NULL);
1038  assert(propdata != NULL);
1039  assert(infervar != NULL);
1040  assert(SCIPisEQ(scip, SCIPvarGetUbLocal(infervar), SCIPvarGetUbAtIndex(infervar, NULL, FALSE)));
1041  assert(SCIPisEQ(scip, SCIPvarGetUbAtIndex(infervar, NULL, TRUE), SCIPvarGetUbAtIndex(infervar, NULL, FALSE)));
1042  assert(SCIPisGT(scip, inferlb, SCIPvarGetUbLocal(infervar)));
1043  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
1044 
1045  /* check if conflict analysis is applicable */
1047  return SCIP_OKAY;
1048 
1049  if( canwide && propdata->usebdwidening )
1050  {
1051  SCIP_Real relaxedbd;
1052  SCIP_Real relaxedub;
1053 
1054  SCIPdebugMessage("try to create conflict using bound widening order: inference variable, variable bound variable\n");
1055 
1056  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
1058 
1059  /* adjust lower bound */
1060  inferlb = SCIPadjustedVarLb(scip, infervar, inferlb);
1061 
1062  /* compute a relaxed upper bound which would be sufficient to be still infeasible */
1063  if( SCIPvarIsIntegral(infervar) )
1064  relaxedub = inferlb - 1.0;
1065  else
1066  relaxedub = inferlb - 2*SCIPfeastol(scip);
1067 
1068  /* try to relax inference variable upper bound such that the infeasibility is still given */
1069  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, relaxedub) );
1070 
1071  /* collect the upper bound which is reported to the conflict analysis */
1072  relaxedub = SCIPgetConflictVarUb(scip, infervar);
1073 
1074  /* adjust inference bound with respect to the upper bound reported to the conflict analysis */
1075  if( SCIPvarIsIntegral(infervar) )
1076  relaxedub = relaxedub + 1.0;
1077  else
1078  relaxedub = relaxedub + 2*SCIPfeastol(scip);
1079 
1080  /* compute the relaxed bound which is sufficient to propagate the inference lower bound of given variable */
1081  relaxedbd = computeRelaxedLowerbound(scip, infervar, relaxedub, coef, constant);
1082 
1083  /* try to relax variable bound variable */
1084  SCIP_CALL( relaxVbdvar(scip, vbdvar, boundtype, NULL, relaxedbd) );
1085 
1086  /* analyze the conflict */
1087  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
1088  }
1089  else
1090  {
1091  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
1093 
1094  /* add upper bound of the variable for which we tried to change the lower bound */
1095  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
1096 
1097  /* add (correct) bound of the variable which let to the new lower bound */
1098  SCIP_CALL( resolvePropagation(scip, propdata, vbdvar, boundtype, NULL) );
1099 
1100  /* analyze the conflict */
1101  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
1102  }
1103 
1104  return SCIP_OKAY;
1105 }
1106 
1107 /** compute the relaxed bound which is sufficient to propagate the inference upper bound of given variable */
1108 static
1110  SCIP* scip, /**< SCIP data structure */
1111  SCIP_VAR* var, /**< variable which was propagated */
1112  SCIP_Real inferub, /**< inference upper bound */
1113  SCIP_Real coef, /**< inference variable bound coefficient used */
1114  SCIP_Real constant /**< inference variable bound constant used */
1115  )
1116 {
1117  SCIP_Real relaxedbd;
1118 
1119  if( SCIPvarIsIntegral(var) )
1120  relaxedbd = (inferub + 1.0 - 2*SCIPfeastol(scip) - constant) / coef;
1121  else
1122  relaxedbd = (inferub - constant) / coef;
1123 
1124  /* check the computed relaxed lower/upper bound is a proper reason for the inference bound which has to be explained */
1125  assert(SCIPisEQ(scip, inferub, SCIPadjustedVarUb(scip, var, relaxedbd * coef + constant)));
1126 
1127  return relaxedbd;
1128 }
1129 
1130 /** analyzes an infeasibility which was reached by updating the upper bound of the inference variable below its lower
1131  * bound
1132  */
1133 static
1135  SCIP* scip, /**< SCIP data structure */
1136  SCIP_PROPDATA* propdata, /**< propagator data */
1137  SCIP_VAR* infervar, /**< variable which led to a cutoff */
1138  SCIP_Real inferub, /**< upper bound which led to infeasibility */
1139  SCIP_VAR* vbdvar, /**< variable which is the reason for the upper bound change */
1140  SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the upper bound change */
1141  SCIP_Real coef, /**< inference variable bound coefficient used */
1142  SCIP_Real constant, /**< inference variable bound constant used */
1143  SCIP_Bool canwide /**< can bound widening be used (for vbounds) or not (for inplications or cliques) */
1144  )
1145 {
1146  assert(scip != NULL);
1147  assert(propdata != NULL);
1148  assert(infervar != NULL);
1149  assert(SCIPisEQ(scip, SCIPvarGetLbLocal(infervar), SCIPvarGetLbAtIndex(infervar, NULL, FALSE)));
1150  assert(SCIPisEQ(scip, SCIPvarGetLbAtIndex(infervar, NULL, TRUE), SCIPvarGetLbAtIndex(infervar, NULL, FALSE)));
1151  assert(SCIPisLT(scip, inferub, SCIPvarGetLbLocal(infervar)));
1152  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
1153 
1154  /* check if conflict analysis is applicable */
1156  return SCIP_OKAY;
1157 
1158  if( canwide && propdata->usebdwidening )
1159  {
1160  SCIP_Real relaxedbd;
1161  SCIP_Real relaxedlb;
1162 
1163  SCIPdebugMessage("try to create conflict using bound widening order: inference variable, variable bound variable\n");
1164 
1165  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
1167 
1168  /* adjust upper bound */
1169  inferub = SCIPadjustedVarUb(scip, infervar, inferub);
1170 
1171  /* compute a relaxed lower bound which would be sufficient to be still infeasible */
1172  if( SCIPvarIsIntegral(infervar) )
1173  relaxedlb = inferub + 1.0;
1174  else
1175  relaxedlb = inferub + 2*SCIPfeastol(scip);
1176 
1177  /* try to relax inference variable lower bound such that the infeasibility is still given */
1178  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, relaxedlb) );
1179 
1180  /* collect the lower bound which is reported to the conflict analysis */
1181  relaxedlb = SCIPgetConflictVarLb(scip, infervar);
1182 
1183  /* adjust inference bound with respect to the upper bound reported to the conflict analysis */
1184  if( SCIPvarIsIntegral(infervar) )
1185  relaxedlb = relaxedlb - 1.0;
1186  else
1187  relaxedlb = relaxedlb - 2*SCIPfeastol(scip);
1188 
1189  /* compute the relaxed bound which is sufficient to propagate the inference upper bound of given variable */
1190  relaxedbd = computeRelaxedUpperbound(scip, infervar, relaxedlb, coef, constant);
1191 
1192  /* try to relax variable bound variable */
1193  SCIP_CALL( relaxVbdvar(scip, vbdvar, boundtype, NULL, relaxedbd) );
1194 
1195  /* analyze the conflict */
1196  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
1197  }
1198  else
1199  {
1200  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
1202 
1203  /* add lower bound of the variable for which we tried to change the upper bound */
1204  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
1205 
1206  /* add (correct) bound of the variable which let to the new upper bound */
1207  SCIP_CALL( resolvePropagation(scip, propdata, vbdvar, boundtype, NULL) );
1208 
1209  /* analyze the conflict */
1210  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
1211  }
1212 
1213  return SCIP_OKAY;
1214 }
1215 
1216 
1217 /* tries to tighten the (global) lower bound of the given variable to the given new bound */
1218 static
1220  SCIP* scip, /**< SCIP data structure */
1221  SCIP_PROP* prop, /**< vbounds propagator */
1222  SCIP_PROPDATA* propdata, /**< propagator data */
1223  SCIP_VAR* var, /**< variable whose lower bound should be tightened */
1224  SCIP_Real newlb, /**< new lower bound for the variable */
1225  SCIP_Bool global, /**< is the bound globally valid? */
1226  SCIP_VAR* vbdvar, /**< variable which is the reason for the lower bound change */
1227  SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the lower bound change */
1228  SCIP_Bool force, /**< should domain changes for continuous variables be forced */
1229  SCIP_Real coef, /**< coefficient in vbound constraint causing the propagation;
1230  * or 0.0 if propagation is caused by clique or implication */
1231  SCIP_Real constant, /**< constant in vbound constraint causing the propagation;
1232  * or 0.0 if propagation is caused by clique or implication */
1233  SCIP_Bool canwide, /**< can bound widening be used (for vbounds) or not (for inplications or cliques) */
1234  int* nchgbds, /**< pointer to increase, if a bound was changed */
1235  SCIP_RESULT* result /**< pointer to store the result of the propagation */
1236  )
1237 {
1238  INFERINFO inferinfo;
1239  SCIP_Real lb;
1240  SCIP_Bool tightened;
1241  SCIP_Bool infeasible;
1242 
1243  assert(scip != NULL);
1244  assert(prop != NULL);
1245  assert(propdata != NULL);
1246  assert(var != NULL);
1247  assert(nchgbds != NULL);
1248  assert(result != NULL);
1249 
1250  lb = SCIPvarGetLbLocal(var);
1251 
1252  /* check that the new upper bound is better */
1253  if( (SCIPvarIsIntegral(var) && newlb - lb > 0.5) || (force && SCIPisGT(scip, newlb, lb)) )
1254  force = TRUE;
1255  else
1256  force = FALSE;
1257 
1258  /* try to tighten the lower bound */
1259  if( global )
1260  {
1261  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, newlb, force, &infeasible, &tightened) );
1262  }
1263  else
1264  {
1265  inferinfo = getInferInfo(boundtype == SCIP_BOUNDTYPE_LOWER ? varGetLbIndex(propdata, vbdvar) : varGetUbIndex(propdata, vbdvar), boundtype);
1266 
1267  SCIP_CALL( SCIPinferVarLbProp(scip, var, newlb, prop, inferInfoToInt(inferinfo), force, &infeasible, &tightened) );
1268  }
1269 
1270  if( infeasible )
1271  {
1272  /* the infeasible results comes from the fact that the new lower bound lies above the current upper bound */
1273  assert(SCIPisGT(scip, newlb, SCIPvarGetUbLocal(var)));
1274  assert(!global || SCIPisGT(scip, newlb, SCIPvarGetUbGlobal(var)));
1275 
1276  SCIPdebugMessage("tightening%s lower bound of variable <%s> to %g due the %s bound of variable <%s> led to infeasibility\n",
1277  (global ? " global" : ""), SCIPvarGetName(var), newlb, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
1278 
1279  if( global )
1280  {
1281  /* cutoff the root node */
1282  SCIP_CALL( SCIPcutoffNode(scip, SCIPgetRootNode(scip)) );
1283  }
1284  else
1285  {
1286  /* analyzes a infeasibility via conflict analysis */
1287  SCIP_CALL( analyzeConflictLowerbound(scip, propdata, var, newlb, vbdvar, boundtype, coef, constant, canwide) );
1288  }
1289  *result = SCIP_CUTOFF;
1290  }
1291  else if( tightened )
1292  {
1293  SCIPdebugMessage("tightened%s lower bound of variable <%s> to %g due the %s bound of variable <%s>\n",
1294  (global ? " global" : ""), SCIPvarGetName(var), newlb, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
1295  (*nchgbds)++;
1296  }
1297 
1298  return SCIP_OKAY;
1299 }
1300 
1301 /* tries to tighten the (global) upper bound of the given variable to the given new bound */
1302 static
1304  SCIP* scip, /**< SCIP data structure */
1305  SCIP_PROP* prop, /**< vbounds propagator */
1306  SCIP_PROPDATA* propdata, /**< propagator data */
1307  SCIP_VAR* var, /**< variable whose upper bound should be tightened */
1308  SCIP_Real newub, /**< new upper bound of the variable */
1309  SCIP_Bool global, /**< is the bound globally valid? */
1310  SCIP_VAR* vbdvar, /**< variable which is the reason for the upper bound change */
1311  SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the upper bound change */
1312  SCIP_Bool force, /**< should domain changes for continuous variables be forced */
1313  SCIP_Real coef, /**< coefficient in vbound constraint causing the propagation;
1314  * or 0.0 if propagation is caused by clique or implication */
1315  SCIP_Real constant, /**< constant in vbound constraint causing the propagation;
1316  * or 0.0 if propagation is caused by clique or implication */
1317  SCIP_Bool canwide, /**< can bound widening be used (for vbounds) or not (for inplications or cliques) */
1318  int* nchgbds, /**< pointer to increase, if a bound was changed */
1319  SCIP_RESULT* result /**< pointer to store the result of the propagation */
1320  )
1321 {
1322  INFERINFO inferinfo;
1323  SCIP_Real ub;
1324  SCIP_Bool tightened;
1325  SCIP_Bool infeasible;
1326 
1327  assert(scip != NULL);
1328  assert(prop != NULL);
1329  assert(propdata != NULL);
1330  assert(var != NULL);
1331  assert(nchgbds != NULL);
1332  assert(result != NULL);
1333 
1334  ub = SCIPvarGetUbLocal(var);
1335 
1336  /* check that the new upper bound is better */
1337  if( (SCIPvarIsIntegral(var) && ub - newub > 0.5) || (force && SCIPisLT(scip, newub, ub)) )
1338  force = TRUE;
1339  else
1340  force = FALSE;
1341 
1342  /* try to tighten the upper bound */
1343  if( global )
1344  {
1345  SCIP_CALL( SCIPtightenVarUbGlobal(scip, var, newub, force, &infeasible, &tightened) );
1346  }
1347  else
1348  {
1349  inferinfo = getInferInfo(boundtype == SCIP_BOUNDTYPE_LOWER ? varGetLbIndex(propdata, vbdvar) : varGetUbIndex(propdata, vbdvar), boundtype);
1350 
1351  SCIP_CALL( SCIPinferVarUbProp(scip, var, newub, prop, inferInfoToInt(inferinfo), force, &infeasible, &tightened) );
1352  }
1353 
1354  if( infeasible )
1355  {
1356  /* the infeasible results comes from the fact that the new upper bound lies below the current lower bound */
1357  assert(SCIPisLT(scip, newub, SCIPvarGetLbLocal(var)));
1358  assert(!global || SCIPisLT(scip, newub, SCIPvarGetLbGlobal(var)));
1359 
1360  SCIPdebugMessage("tightening%s upper bound of variable <%s> to %g due the %s bound of variable <%s> led to infeasibility\n",
1361  (global ? " global" : ""), SCIPvarGetName(var), newub, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
1362 
1363  if( global )
1364  {
1365  /* cutoff the root node */
1366  SCIP_CALL( SCIPcutoffNode(scip, SCIPgetRootNode(scip)) );
1367  }
1368  else
1369  {
1370  /* analyzes a infeasibility via conflict analysis */
1371  SCIP_CALL( analyzeConflictUpperbound(scip, propdata, var, newub, vbdvar, boundtype, coef, constant, canwide) );
1372  }
1373  *result = SCIP_CUTOFF;
1374  }
1375  else if( tightened )
1376  {
1377  SCIPdebugMessage("tightened%s upper bound of variable <%s> to %g due the %s bound of variable <%s>\n",
1378  (global ? " global" : ""), SCIPvarGetName(var), newub, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
1379  (*nchgbds)++;
1380  }
1381 
1382  return SCIP_OKAY;
1383 }
1384 
1385 /** performs propagation of variables lower and upper bounds, implications, and cliques */
1386 static
1388  SCIP* scip, /**< SCIP data structure */
1389  SCIP_PROP* prop, /**< vbounds propagator */
1390  SCIP_Bool force, /**< should domain changes for continuous variables be forced */
1391  SCIP_RESULT* result /**< pointer to store the result of the propagation */
1392  )
1393 {
1394  SCIP_PROPDATA* propdata;
1395  SCIP_VAR** vars;
1396  SCIP_VAR* startvar;
1397  SCIP_BOUNDTYPE starttype;
1398  SCIP_Real startbound;
1399  SCIP_Real globalbound;
1400  int startpos;
1401  int topopos;
1402  int v;
1403  int n;
1404  int nchgbds;
1405  int nbounds;
1406  SCIP_Bool lower;
1407  SCIP_Bool global;
1408 
1409  assert(scip != NULL);
1410  assert(prop != NULL);
1411  assert(result != NULL);
1412 
1413  (*result) = SCIP_DIDNOTRUN;
1414 
1415  /* we do not run the propagator in presolving, because we want to avoid doing the expensive creation of the graph twice */
1416  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
1417  return SCIP_OKAY;
1418 
1419  propdata = SCIPpropGetData(prop);
1420  assert(propdata != NULL);
1421 
1422  /* initialize propagator data needed for propagation, if not done yet */
1423  if( !propdata->initialized )
1424  {
1425  SCIP_CALL( initData(scip, prop) );
1426  }
1427  assert(propdata->nbounds == 0 || propdata->propqueue != NULL);
1428 
1429  vars = propdata->vars;
1430  nbounds = propdata->nbounds;
1431 
1432  if( nbounds == 0 )
1433  return SCIP_OKAY;
1434 
1435  /* propagate all variables if we are in repropagation */
1436  if( SCIPinRepropagation(scip) )
1437  {
1438  SCIP_VAR* var;
1439  int idx;
1440 
1441  for( v = nbounds - 1; v >= 0; --v )
1442  {
1443  idx = propdata->topoorder[v];
1444  if( idx != -1 && !propdata->inqueue[v] )
1445  {
1446  var = vars[getVarIndex(idx)];
1447  lower = isIndexLowerbound(idx);
1448  if( !SCIPvarIsBinary(var) || (lower && SCIPvarGetLbLocal(var) > 0.5)
1449  || (!lower && SCIPvarGetUbLocal(var) < 0.5) )
1450  {
1451  SCIP_CALL( SCIPpqueueInsert(propdata->propqueue, (void*)(size_t)(v + 1)) ); /*lint !e571 !e776*/
1452  propdata->inqueue[v] = TRUE;
1453  }
1454  }
1455  }
1456  }
1457 
1458  /* return if no bound changes are in the priority queue (no changed bounds to handle since last propagation) */
1459  if( SCIPpqueueNElems(propdata->propqueue) == 0 )
1460  {
1461  (*result) = SCIP_DIDNOTFIND;
1462  return SCIP_OKAY;
1463  }
1464 
1465  nchgbds = 0;
1466 
1467  SCIPdebugMessage("varbound propagator: %d elements in the propagation queue\n", SCIPpqueueNElems(propdata->propqueue));
1468 
1469  /* get variable bound of highest priority from priority queue and try to deduce bound changes for other variables;
1470  * the priority queue is ordered w.r.t the topological sort of the varbound graph
1471  */
1472  while( SCIPpqueueNElems(propdata->propqueue) > 0 )
1473  {
1474  topopos = ((int)(size_t)SCIPpqueueRemove(propdata->propqueue)) - 1;
1475  assert(propdata->inqueue[topopos]);
1476  startpos = propdata->topoorder[topopos];
1477  assert(startpos >= 0);
1478  propdata->inqueue[topopos] = FALSE;
1479 
1480  startvar = vars[getVarIndex(startpos)];
1481  starttype = getBoundtype(startpos);
1482  lower = (starttype == SCIP_BOUNDTYPE_LOWER);
1483  startbound = ( lower ? SCIPvarGetLbLocal(startvar) : SCIPvarGetUbLocal(startvar) );
1484  globalbound = ( lower ? SCIPvarGetLbGlobal(startvar) : SCIPvarGetUbGlobal(startvar));
1485  global = SCIPisEQ(scip, startbound, globalbound);
1486 
1487  SCIPdebugMessage("propagate new %s bound of %g of variable <%s>:\n",
1488  getBoundtypeString(starttype), startbound, SCIPvarGetName(startvar));
1489 
1490  /* there should be neither implications nor cliques for non-binary variables */
1491  assert(SCIPvarIsBinary(startvar) || SCIPvarGetNImpls(startvar, lower) == 0);
1492  assert(SCIPvarIsBinary(startvar) || SCIPvarGetNCliques(startvar, lower) == 0);
1493 
1494  if( SCIPvarIsBinary(startvar) )
1495  {
1496  /* we only propagate binary variables if the lower bound changed to 1.0 or the upper bound changed to 0.0 */
1497  if( lower != (startbound > 0.5) )
1498  continue;
1499 
1500  /* propagate implications */
1501  if( propdata->useimplics )
1502  {
1503  int nimplvars;
1504 
1505  /* if the lower bound of the startvar was changed, it was fixed to 1.0, otherwise it was fixed to 0.0;
1506  * get all implications for this varfixing
1507  */
1508  nimplvars = SCIPvarGetNImpls(startvar, lower);
1509 
1510  /* if there are implications for the varfixing, propagate them */
1511  if( nimplvars > 0 )
1512  {
1513  SCIP_VAR** implvars;
1514  SCIP_BOUNDTYPE* impltypes;
1515  SCIP_Real* implbounds;
1516  int* implids;
1517 
1518  implvars = SCIPvarGetImplVars(startvar, lower);
1519  impltypes = SCIPvarGetImplTypes(startvar, lower);
1520  implbounds = SCIPvarGetImplBounds(startvar, lower);
1521  implids = SCIPvarGetImplIds(startvar, lower);
1522 
1523  for( n = 0; n < nimplvars; ++n )
1524  {
1525  /* implication is just a shortcut, so we do not propagate it now,
1526  * because we will propagate the longer way, anyway
1527  */
1528  if( implids[n] < 0 )
1529  continue;
1530 
1531  /* it might happen that implications point to inactive variables (normally, those are removed when a
1532  * variable becomes inactive, but in some cases, it cannot be done), we have to ignore these variables
1533  */
1534  if( !SCIPvarIsActive(implvars[n]) )
1535  continue;
1536 
1537  if( impltypes[n] == SCIP_BOUNDTYPE_LOWER )
1538  {
1539  SCIP_CALL( tightenVarLb(scip, prop, propdata, implvars[n], implbounds[n], global, startvar,
1540  starttype, force, 0.0, 0.0, FALSE, &nchgbds, result) );
1541  }
1542  else
1543  {
1544  SCIP_CALL( tightenVarUb(scip, prop, propdata, implvars[n], implbounds[n], global, startvar,
1545  starttype, force, 0.0, 0.0, FALSE, &nchgbds, result) );
1546  }
1547 
1548  if( *result == SCIP_CUTOFF )
1549  return SCIP_OKAY;
1550  }
1551  }
1552  }
1553 
1554  /* propagate cliques */
1555  if( propdata->usecliques )
1556  {
1557  int ncliques;
1558 
1559  /* if the lower bound of the startvar was changed, it was fixed to 1.0, otherwise it was fixed to 0.0;
1560  * get all cliques for this varfixing
1561  */
1562  ncliques = SCIPvarGetNCliques(startvar, lower);
1563 
1564  /* if there are cliques for the varfixing, propagate them */
1565  if( ncliques > 0 )
1566  {
1567  SCIP_CLIQUE** cliques;
1568  int j;
1569 
1570  cliques = SCIPvarGetCliques(startvar, lower);
1571 
1572  for( j = 0; j < ncliques; ++j )
1573  {
1574  SCIP_VAR** cliquevars;
1575  SCIP_Bool* cliquevals;
1576  int ncliquevars;
1577 
1578  cliquevars = SCIPcliqueGetVars(cliques[j]);
1579  cliquevals = SCIPcliqueGetValues(cliques[j]);
1580  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
1581 
1582  /* fix all variables except for the startvar to the value which is not in the clique */
1583  for( n = 0; n < ncliquevars; ++n )
1584  {
1585  if( cliquevars[n] == startvar )
1586  continue;
1587 
1588  /* try to tighten the bound */
1589  if( cliquevals[n] )
1590  {
1591  /* unnegated variable is in clique, so it has to be fixed to 0.0 */
1592  SCIP_CALL( tightenVarUb(scip, prop, propdata, cliquevars[n], 0.0, global, startvar, starttype,
1593  force, 0.0, 0.0, FALSE, &nchgbds, result) );
1594  }
1595  else
1596  {
1597  /* negated variable is in clique, so it has to be fixed to 1.0 */
1598  SCIP_CALL( tightenVarLb(scip, prop, propdata, cliquevars[n], 1.0, global, startvar, starttype,
1599  force, 0.0, 0.0, FALSE, &nchgbds, result) );
1600  }
1601  if( *result == SCIP_CUTOFF )
1602  return SCIP_OKAY;
1603  }
1604  }
1605  }
1606  }
1607  }
1608 
1609  /* propagate vbounds */
1610  if( propdata->usevbounds )
1611  {
1612  SCIP_VAR* boundedvar;
1613  SCIP_Real newbound;
1614  SCIP_Real coef;
1615  SCIP_Real constant;
1616 
1617  /* iterate over all vbounds for the given bound */
1618  for( n = 0; n < propdata->nvbounds[startpos]; ++n )
1619  {
1620  boundedvar = vars[getVarIndex(propdata->vboundboundedidx[startpos][n])];
1621  coef = propdata->vboundcoefs[startpos][n];
1622  constant = propdata->vboundconstants[startpos][n];
1623 
1624  /* compute new bound */
1625  newbound = startbound * coef + constant;
1626 
1627  /* try to tighten the bound */
1628  if( isIndexLowerbound(propdata->vboundboundedidx[startpos][n]) )
1629  {
1630  SCIP_CALL( tightenVarLb(scip, prop, propdata, boundedvar, newbound, global, startvar, starttype, force,
1631  coef, constant, TRUE, &nchgbds, result) );
1632  }
1633  else
1634  {
1635  SCIP_CALL( tightenVarUb(scip, prop, propdata, boundedvar, newbound, global, startvar, starttype, force,
1636  coef, constant, TRUE, &nchgbds, result) );
1637  }
1638 
1639  if( *result == SCIP_CUTOFF )
1640  return SCIP_OKAY;
1641  }
1642  }
1643  }
1644 
1645  SCIPdebugMessage("tightened %d variable bounds\n", nchgbds);
1646 
1647  /* set the result depending on whether bound changes were found or not */
1648  if( nchgbds > 0 )
1649  (*result) = SCIP_REDUCEDDOM;
1650  else
1651  (*result) = SCIP_DIDNOTFIND;
1652 
1653  return SCIP_OKAY;
1654 }
1655 
1656 /**@name Callback methods of propagator
1657  *
1658  * @{
1659  */
1660 
1661 /** copy method for propagator plugins (called when SCIP copies plugins) */
1662 static
1663 SCIP_DECL_PROPCOPY(propCopyVbounds)
1664 { /*lint --e{715}*/
1665  assert(scip != NULL);
1666  assert(prop != NULL);
1667  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
1668 
1669  /* call inclusion method of propagator */
1671 
1672  return SCIP_OKAY;
1673 }
1674 
1675 /** destructor of propagator to free user data (called when SCIP is exiting) */
1676 static
1677 SCIP_DECL_PROPFREE(propFreeVbounds)
1678 { /*lint --e{715}*/
1679  SCIP_PROPDATA* propdata;
1680 
1681  /* free propagator data */
1682  propdata = SCIPpropGetData(prop);
1683 
1684  SCIPfreeMemory(scip, &propdata);
1685  SCIPpropSetData(prop, NULL);
1686 
1687  return SCIP_OKAY;
1688 }
1689 
1690 /** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
1691 static
1692 SCIP_DECL_PROPEXITSOL(propExitsolVbounds)
1693 { /*lint --e{715}*/
1694  SCIP_PROPDATA* propdata;
1695  int v;
1696 
1697  propdata = SCIPpropGetData(prop);
1698  assert(propdata != NULL);
1699 
1700  /* free data stored for propagation */
1701  if( propdata->initialized )
1702  {
1703  /* drop all variable events */
1704  SCIP_CALL( dropEvents(scip, propdata) );
1705 
1706  /* release all variables */
1707  for( v = 0; v < propdata->nbounds; ++v )
1708  {
1709  /* free vbound data */
1710  if( propdata->vboundsize[v] > 0 )
1711  {
1712  SCIPfreeMemoryArray(scip, &propdata->vboundboundedidx[v]);
1713  SCIPfreeMemoryArray(scip, &propdata->vboundcoefs[v]);
1714  SCIPfreeMemoryArray(scip, &propdata->vboundconstants[v]);
1715  }
1716  }
1717 
1718  /* free priority queue */
1719  SCIPpqueueFree(&propdata->propqueue);
1720 
1721  /* free arrays */
1722  SCIPfreeBlockMemoryArray(scip, &propdata->vboundsize, propdata->nbounds);
1723  SCIPfreeBlockMemoryArray(scip, &propdata->nvbounds, propdata->nbounds);
1724  SCIPfreeBlockMemoryArray(scip, &propdata->vboundconstants, propdata->nbounds);
1725  SCIPfreeBlockMemoryArray(scip, &propdata->vboundcoefs, propdata->nbounds);
1726  SCIPfreeBlockMemoryArray(scip, &propdata->vboundboundedidx, propdata->nbounds);
1727  SCIPfreeBlockMemoryArray(scip, &propdata->inqueue, propdata->nbounds);
1728  SCIPfreeBlockMemoryArray(scip, &propdata->topoorder, propdata->nbounds);
1729 
1730  /* free variable array and hashmap */
1731  SCIPhashmapFree(&propdata->varhashmap);
1732  SCIPfreeBlockMemoryArray(scip, &propdata->vars, propdata->nbounds / 2);
1733  }
1734 
1735  /* reset propagation data */
1736  resetPropdata(propdata);
1737 
1738  return SCIP_OKAY;
1739 }
1740 
1741 /** execution method of propagator */
1742 static
1743 SCIP_DECL_PROPEXEC(propExecVbounds)
1744 { /*lint --e{715}*/
1745 
1746  *result = SCIP_DIDNOTRUN;
1747 
1748  /* perform variable lower and upper bound propagation */
1749  SCIP_CALL( propagateVbounds(scip, prop, FALSE, result) );
1750 
1751  assert((*result) == SCIP_CUTOFF || (*result) == SCIP_DIDNOTRUN
1752  || (*result) == SCIP_DIDNOTFIND || (*result) == SCIP_REDUCEDDOM);
1753 
1754  return SCIP_OKAY;
1755 }
1756 
1757 
1758 /** propagation conflict resolving method of propagator */
1759 static
1760 SCIP_DECL_PROPRESPROP(propRespropVbounds)
1761 { /*lint --e{715}*/
1762  SCIP_PROPDATA* propdata;
1763  SCIP_VAR** vars;
1764  SCIP_VAR* startvar;
1765  SCIP_BOUNDTYPE starttype;
1766  int pos;
1767 
1768  propdata = SCIPpropGetData(prop);
1769  assert(propdata != NULL);
1770 
1771  starttype = inferInfoGetBoundtype(intToInferInfo(inferinfo));
1772  pos = inferInfoGetPos(intToInferInfo(inferinfo));
1773  assert(pos >= 0);
1774  assert(pos < propdata->nbounds);
1775 
1776  vars = propdata->vars;
1777  assert(vars != NULL);
1778  startvar = vars[getVarIndex(pos)];
1779  assert(startvar != NULL);
1780  assert(startvar != infervar);
1781 
1782  SCIPdebugMessage("explain %s bound change of variable <%s>\n",
1783  getBoundtypeString(boundtype), SCIPvarGetName(infervar));
1784 
1785  if( !SCIPvarIsBinary(startvar) && propdata->usebdwidening )
1786  {
1787  int* vboundboundedidx;
1788  SCIP_Real constant;
1789  SCIP_Real coef;
1790  int inferidx;
1791  int nvbounds;
1792  int b;
1793 
1794  nvbounds = propdata->nvbounds[pos];
1795  vboundboundedidx = propdata->vboundboundedidx[pos];
1796 
1797  inferidx = boundtype == SCIP_BOUNDTYPE_LOWER ? varGetLbIndex(propdata, infervar) : varGetUbIndex(propdata, infervar);
1798  assert(inferidx >= 0);
1799 
1800  for( b = 0; b < nvbounds; ++b )
1801  {
1802  if( vboundboundedidx[b] == inferidx )
1803  break;
1804  }
1805  assert(b < nvbounds);
1806 
1807  coef = propdata->vboundcoefs[pos][b];
1808  constant = propdata->vboundconstants[pos][b];
1809  assert(!SCIPisZero(scip, coef));
1810 
1811  /* compute the relaxed bound which is sufficient to propagate the inference bound of given variable */
1812  if( boundtype == SCIP_BOUNDTYPE_LOWER )
1813  relaxedbd = computeRelaxedLowerbound(scip, infervar, relaxedbd, coef, constant);
1814  else
1815  relaxedbd = computeRelaxedUpperbound(scip, infervar, relaxedbd, coef, constant);
1816 
1817  /* try to relax variable bound variable */
1818  SCIP_CALL( relaxVbdvar(scip, startvar, starttype, bdchgidx, relaxedbd) );
1819  }
1820  else
1821  {
1822  SCIP_CALL( resolvePropagation(scip, propdata, startvar, starttype, bdchgidx) );
1823  }
1824 
1825  (*result) = SCIP_SUCCESS;
1826 
1827  return SCIP_OKAY;
1828 }
1829 
1830 /**@} */
1831 
1832 /**@name Callback methods of event handler
1833  *
1834  * @{
1835  */
1836 
1837 /** execution method of bound change event handler */
1838 static
1839 SCIP_DECL_EVENTEXEC(eventExecVbound)
1840 { /*lint --e{715}*/
1841  SCIP_PROPDATA* propdata;
1842  int idx;
1843 
1844  assert(eventhdlr != NULL);
1845 
1846  propdata = (SCIP_PROPDATA*)SCIPeventhdlrGetData(eventhdlr);
1847  assert(propdata != NULL);
1848 
1849  idx = (int) (size_t) eventdata;
1850  assert(idx >= 0);
1851 
1852  SCIPdebugMessage("eventexec (type=%u): try to add sort index %d: %s(%s) to priority queue\n", SCIPeventGetType(event),
1853  idx, indexGetBoundString(propdata->topoorder[idx]),
1854  SCIPvarGetName(propdata->vars[getVarIndex(propdata->topoorder[idx])]));
1855 
1857  && SCIPeventGetNewbound(event) > 0.5 )
1858  return SCIP_OKAY;
1859 
1861  && SCIPeventGetNewbound(event) < 0.5 )
1862  return SCIP_OKAY;
1863 
1864  assert(getVarIndex(propdata->topoorder[idx]) < SCIPgetNVars(scip));
1865  assert(SCIPvarGetType(propdata->vars[getVarIndex(propdata->topoorder[idx])]) != SCIP_VARTYPE_BINARY
1866  || (isIndexLowerbound(propdata->topoorder[idx]) == (SCIPeventGetNewbound(event) > 0.5)));
1867 
1868  /* add the bound change to the propagation queue, if it is not already contained */
1869  if( !propdata->inqueue[idx] )
1870  {
1871  SCIP_CALL( SCIPpqueueInsert(propdata->propqueue, (void*)(size_t)(idx + 1)) ); /*lint !e571 !e776*/
1872  propdata->inqueue[idx] = TRUE;
1873  }
1874  assert(SCIPpqueueNElems(propdata->propqueue) > 0);
1875 
1876  return SCIP_OKAY;
1877 }
1878 
1879 /**@} */
1880 
1881 /**@name Interface methods
1882  *
1883  * @{
1884  */
1885 
1886 /** creates the vbounds propagator and includes it in SCIP */
1888  SCIP* scip /**< SCIP data structure */
1889  )
1890 {
1891  SCIP_PROPDATA* propdata;
1892  SCIP_PROP* prop;
1893 
1894  /* create vbounds propagator data */
1895  SCIP_CALL( SCIPallocMemory(scip, &propdata) );
1896 
1897  /* reset propagation data */
1898  resetPropdata(propdata);
1899 
1900  /* include propagator */
1902  propExecVbounds, propdata) );
1903  assert(prop != NULL);
1904 
1905  /* set optional callbacks via setter functions */
1906  SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyVbounds) );
1907  SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeVbounds) );
1908  SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolVbounds) );
1909  SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropVbounds) );
1910 
1911  /* include event handler for bound change events */
1912  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &propdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC,
1913  eventExecVbound, (SCIP_EVENTHDLRDATA*)propdata) );
1914 
1916  "propagating/" PROP_NAME "/usebdwidening", "should bound widening be used to initialize conflict analysis?",
1917  &propdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
1919  "propagating/" PROP_NAME "/useimplics", "should implications be propagated?",
1920  &propdata->useimplics, FALSE, DEFAULT_USEIMPLICS, NULL, NULL) );
1922  "propagating/" PROP_NAME "/usecliques", "should cliques be propagated?",
1923  &propdata->usecliques, FALSE, DEFAULT_USECLIQUES, NULL, NULL) );
1925  "propagating/" PROP_NAME "/usevbounds", "should vbounds be propagated?",
1926  &propdata->usevbounds, FALSE, DEFAULT_USEVBOUNDS, NULL, NULL) );
1928  "propagating/" PROP_NAME "/dotoposort", "should the bounds be topologically sorted in advance?",
1929  &propdata->dotoposort, FALSE, DEFAULT_DOTOPOSORT, NULL, NULL) );
1931  "propagating/" PROP_NAME "/sortcliques", "should cliques be regarded for the topological sort?",
1932  &propdata->sortcliques, FALSE, DEFAULT_SORTCLIQUES, NULL, NULL) );
1933 
1934  return SCIP_OKAY;
1935 }
1936 
1937 /** returns TRUE if the propagator has the status that all variable lower and upper bounds are propgated */
1939  SCIP* scip /**< SCIP data structure */
1940  )
1941 {
1942  SCIP_PROP* prop;
1943  SCIP_PROPDATA* propdata;
1944 
1945  prop = SCIPfindProp(scip, PROP_NAME);
1946  assert(prop != NULL);
1947 
1948  propdata = SCIPpropGetData(prop);
1949  assert(propdata != NULL);
1950 
1951  return (SCIPpqueueNElems(propdata->propqueue) == 0);
1952 }
1953 
1954 /** performs propagation of variables lower and upper bounds */
1956  SCIP* scip, /**< SCIP data structure */
1957  SCIP_Bool force, /**< should domain changes for continuous variables be forced */
1958  SCIP_RESULT* result /**< pointer to store result */
1959  )
1960 {
1961  SCIP_PROP* prop;
1962 
1963  prop = SCIPfindProp(scip, PROP_NAME);
1964  assert(prop != NULL);
1965 
1966  /* perform variable lower and upper bound propagation */
1967  SCIP_CALL( propagateVbounds(scip, prop, force, result) );
1968 
1969  assert((*result) == SCIP_CUTOFF || (*result) == SCIP_DIDNOTRUN
1970  || (*result) == SCIP_DIDNOTFIND || (*result) == SCIP_REDUCEDDOM);
1971 
1972  return SCIP_OKAY;
1973 }
1974 
1975 /**@} */
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:51
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17352
static void resetPropdata(SCIP_PROPDATA *propdata)
Definition: prop_vbounds.c:280
SCIP_RETCODE SCIPsetPropExitsol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPEXITSOL((*propexitsol)))
Definition: scip.c:7025
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41572
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
int SCIPpqueueNElems(SCIP_PQUEUE *pqueue)
Definition: misc.c:1073
struct InferInfo INFERINFO
#define PROP_FREQ
Definition: prop_vbounds.c:84
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41685
static SCIP_RETCODE addVbound(SCIP *scip, SCIP_PROPDATA *propdata, int startidx, int endidx, SCIP_Real coef, SCIP_Real constant)
Definition: prop_vbounds.c:408
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:10698
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:20526
#define getVarIndex(idx)
Definition: prop_vbounds.c:126
#define DEFAULT_USEBDWIDENING
Definition: prop_vbounds.c:104
static SCIP_RETCODE resolvePropagation(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx)
Definition: prop_vbounds.c:941
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3111
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16443
static SCIP_Real computeRelaxedLowerbound(SCIP *scip, SCIP_VAR *var, SCIP_Real inferlb, SCIP_Real coef, SCIP_Real constant)
Definition: prop_vbounds.c:999
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_PROPDATA *propdata)
Definition: prop_vbounds.c:358
#define DEFAULT_USECLIQUES
Definition: prop_vbounds.c:106
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20573
static SCIP_RETCODE analyzeConflictUpperbound(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *infervar, SCIP_Real inferub, SCIP_VAR *vbdvar, SCIP_BOUNDTYPE boundtype, SCIP_Real coef, SCIP_Real constant, SCIP_Bool canwide)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16623
SCIP_Bool SCIPisPropagatedVbounds(SCIP *scip)
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:10653
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17420
#define NULL
Definition: lpi_spx.cpp:130
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17113
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:940
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17323
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17261
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17067
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:129
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17291
#define SCIPfreeMemoryArray(scip, ptr)
Definition: scip.h:20544
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
Definition: scip.c:24320
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:17429
#define getLbIndex(idx)
Definition: prop_vbounds.c:124
#define FALSE
Definition: def.h:56
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2057
#define DEFAULT_SORTCLIQUES
Definition: prop_vbounds.c:109
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:7778
#define TRUE
Definition: def.h:55
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPsetPropCopy(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPCOPY((*propcopy)))
Definition: scip.c:6945
#define SCIP_CALL(x)
Definition: def.h:266
#define SCIP_EVENTTYPE_GLBCHANGED
Definition: type_event.h:53
SCIP_Bool SCIPvarHasImplic(SCIP_VAR *var, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype)
Definition: var.c:10413
static SCIP_DECL_PROPCOPY(propCopyVbounds)
SCIP_PROP * SCIPfindProp(SCIP *scip, const char *name)
Definition: scip.c:7123
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20556
SCIP_Real SCIPvarGetLbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15737
void SCIPpqueueFree(SCIP_PQUEUE **pqueue)
Definition: misc.c:970
#define SCIPdebugMessage
Definition: pub_message.h:77
static SCIP_BOUNDTYPE inferInfoGetBoundtype(INFERINFO inferinfo)
Definition: prop_vbounds.c:213
SCIP_RETCODE SCIPinferVarLbProp(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_PROP *inferprop, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20841
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
static SCIP_RETCODE analyzeConflictLowerbound(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *infervar, SCIP_Real inferlb, SCIP_VAR *vbdvar, SCIP_BOUNDTYPE boundtype, SCIP_Real coef, SCIP_Real constant, SCIP_Bool canwide)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2116
SCIP_RETCODE SCIPcutoffNode(SCIP *scip, SCIP_NODE *node)
Definition: scip.c:37116
#define isIndexLowerbound(idx)
Definition: prop_vbounds.c:128
static int inferInfoToInt(INFERINFO inferinfo)
Definition: prop_vbounds.c:204
static SCIP_RETCODE dfs(SCIP *scip, SCIP_PROPDATA *propdata, int startnode, SCIP_Bool *visited, int *dfsstack, int *stacknextedge, int *dfsnodes, int *ndfsnodes)
Definition: prop_vbounds.c:466
static SCIP_RETCODE tightenVarLb(SCIP *scip, SCIP_PROP *prop, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_Real newlb, SCIP_Bool global, SCIP_VAR *vbdvar, SCIP_BOUNDTYPE boundtype, SCIP_Bool force, SCIP_Real coef, SCIP_Real constant, SCIP_Bool canwide, int *nchgbds, SCIP_RESULT *result)
#define DEFAULT_USEIMPLICS
Definition: prop_vbounds.c:105
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3547
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2159
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16634
static SCIP_Real computeRelaxedUpperbound(SCIP *scip, SCIP_VAR *var, SCIP_Real inferub, SCIP_Real coef, SCIP_Real constant)
SCIP_RETCODE SCIPanalyzeConflict(SCIP *scip, int validdepth, SCIP_Bool *success)
Definition: scip.c:24689
variable upper and lower bound propagator
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:36622
#define PROP_DESC
Definition: prop_vbounds.c:81
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:20542
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip)
Definition: scip.c:24342
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41585
SCIP_RETCODE SCIPincludePropVbounds(SCIP *scip)
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17303
SCIP_NODE * SCIPgetRootNode(SCIP *scip)
Definition: scip.c:36798
SCIP_PROPDATA * SCIPpropGetData(SCIP_PROP *prop)
Definition: prop.c:735
#define SCIPerrorMessage
Definition: pub_message.h:45
static SCIP_DECL_EVENTEXEC(eventExecVbound)
#define indexGetBoundString(idx)
Definition: prop_vbounds.c:131
int SCIPcalcHashtableSize(int minsize)
Definition: misc.c:1157
SCIP_Real SCIPvarGetUbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15859
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip.c:19717
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:41353
#define INITMEMSIZE
Definition: prop_vbounds.c:404
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:146
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2075
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17367
static int varGetUbIndex(SCIP_PROPDATA *propdata, SCIP_VAR *var)
Definition: prop_vbounds.c:268
#define PROP_NAME
Definition: prop_vbounds.c:80
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:55
SCIP_EVENTHDLRDATA * SCIPeventhdlrGetData(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:288
static INFERINFO intToInferInfo(int i)
Definition: prop_vbounds.c:191
#define DEFAULT_DOTOPOSORT
Definition: prop_vbounds.c:108
#define PROP_TIMING
Definition: prop_vbounds.c:82
SCIP_RETCODE SCIPinferVarUbProp(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_PROP *inferprop, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20944
static SCIP_DECL_PROPEXEC(propExecVbounds)
void * SCIPpqueueRemove(SCIP_PQUEUE *pqueue)
Definition: misc.c:1018
void SCIPpropSetData(SCIP_PROP *prop, SCIP_PROPDATA *propdata)
Definition: prop.c:745
static SCIP_DECL_PROPEXITSOL(propExitsolVbounds)
SCIP_RETCODE SCIPtightenVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:21150
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41611
static int inferInfoGetPos(INFERINFO inferinfo)
Definition: prop_vbounds.c:224
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17123
unsigned int SCIP_EVENTTYPE
Definition: type_event.h:125
SCIP_RETCODE SCIPsetPropResprop(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPRESPROP((*propresprop)))
Definition: scip.c:7106
#define SCIP_Bool
Definition: def.h:53
SCIP_RETCODE SCIPsetPropFree(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPFREE((*propfree)))
Definition: scip.c:6961
SCIP_RETCODE SCIPincludePropBasic(SCIP *scip, SCIP_PROP **propptr, const char *name, const char *desc, int priority, int freq, SCIP_Bool delay, SCIP_PROPTIMING timingmask, SCIP_DECL_PROPEXEC((*propexec)), SCIP_PROPDATA *propdata)
Definition: scip.c:6908
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17335
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17313
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:801
#define EVENTHDLR_NAME
Definition: prop_vbounds.c:94
#define getBoundtype(idx)
Definition: prop_vbounds.c:127
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:24369
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17281
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3123
#define EVENTHDLR_DESC
Definition: prop_vbounds.c:95
int * SCIPvarGetImplIds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17397
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
Definition: scip.c:24403
#define SCIPreallocMemoryArray(scip, ptr, newnum)
Definition: scip.h:20534
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17249
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:57
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:36668
static SCIP_RETCODE relaxVbdvar(SCIP *scip, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd)
Definition: prop_vbounds.c:976
#define getBoundString(lower)
Definition: prop_vbounds.c:129
#define PROP_DELAY
Definition: prop_vbounds.c:85
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16608
static int varGetLbIndex(SCIP_PROPDATA *propdata, SCIP_VAR *var)
Definition: prop_vbounds.c:256
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17271
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:20585
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17057
static SCIP_RETCODE topologicalSort(SCIP *scip, SCIP_PROPDATA *propdata)
Definition: prop_vbounds.c:723
static INFERINFO getInferInfo(int pos, SCIP_BOUNDTYPE boundtype)
Definition: prop_vbounds.c:233
SCIP_RETCODE SCIPpqueueInsert(SCIP_PQUEUE *pqueue, void *elem)
Definition: misc.c:991
static SCIP_RETCODE tightenVarUb(SCIP *scip, SCIP_PROP *prop, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_Real newub, SCIP_Bool global, SCIP_VAR *vbdvar, SCIP_BOUNDTYPE boundtype, SCIP_Bool force, SCIP_Real coef, SCIP_Real constant, SCIP_Bool canwide, int *nchgbds, SCIP_RESULT *result)
static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_PROPDATA *propdata)
Definition: prop_vbounds.c:298
SCIP_RETCODE SCIPpqueueCreate(SCIP_PQUEUE **pqueue, int initsize, SCIP_Real sizefac, SCIP_DECL_SORTPTRCOMP((*ptrcomp)))
Definition: misc.c:945
#define PROP_PRIORITY
Definition: prop_vbounds.c:83
SCIP_RETCODE SCIPtightenVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:21260
#define SCIP_Real
Definition: def.h:127
#define getBoundtypeString(type)
Definition: prop_vbounds.c:130
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:24635
struct SCIP_PropData SCIP_PROPDATA
Definition: type_prop.h:38
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17409
#define DEFAULT_USEVBOUNDS
Definition: prop_vbounds.c:107
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:20568
SCIP_RETCODE SCIPexecPropVbounds(SCIP *scip, SCIP_Bool force, SCIP_RESULT *result)
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:41146
const char * SCIPgetProbName(SCIP *scip)
Definition: scip.c:9941
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
Definition: scip.c:24471
static SCIP_RETCODE propagateVbounds(SCIP *scip, SCIP_PROP *prop, SCIP_Bool force, SCIP_RESULT *result)
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip.c:19685
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:917
static SCIP_DECL_SORTPTRCOMP(compVarboundIndices)
Definition: prop_vbounds.c:456
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:20597
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16730
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3101
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17381
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:24436
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:41422
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2094
static SCIP_DECL_PROPRESPROP(propRespropVbounds)
#define SCIP_EVENTTYPE_GUBCHANGED
Definition: type_event.h:54
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:24659
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41697
static SCIP_RETCODE initData(SCIP *scip, SCIP_PROP *prop)
Definition: prop_vbounds.c:772
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1120
#define SCIPABORT()
Definition: def.h:238
const char * SCIPpropGetName(SCIP_PROP *prop)
Definition: prop.c:887
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip.c:36834
#define getUbIndex(idx)
Definition: prop_vbounds.c:125
static SCIP_DECL_PROPFREE(propFreeVbounds)