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-2018 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 tightening 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  * Additionally, the propagator analyzes the conflict/clique graph during presolving. It uses Tarjan's algorithm to
68  * search for strongly connected components, for each of which all variables can be aggregated to one. Additionally,
69  * it may detect invalid assignments of binary variables and fix the variable to the only possible value left.
70  */
71 
72 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
73 
74 #include <assert.h>
75 #include <string.h>
76 #include <stdint.h>
77 
78 #include "scip/prop_vbounds.h"
79 
80 /**@name Propagator properties
81  *
82  * @{
83  */
84 
85 #define PROP_NAME "vbounds"
86 #define PROP_DESC "propagates variable upper and lower bounds"
87 #define PROP_TIMING SCIP_PROPTIMING_BEFORELP | SCIP_PROPTIMING_AFTERLPLOOP
88 #define PROP_PRIORITY 3000000 /**< propagator priority */
89 #define PROP_FREQ 1 /**< propagator frequency */
90 #define PROP_DELAY FALSE /**< should propagation method be delayed, if other propagators found reductions? */
91 
92 #define PROP_PRESOL_PRIORITY -90000 /**< priority of the presolving method (>= 0: before, < 0: after constraint handlers); combined with presolvers */
93 #define PROP_PRESOLTIMING SCIP_PRESOLTIMING_MEDIUM | SCIP_PRESOLTIMING_EXHAUSTIVE
94 #define PROP_PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates in (-1: no
95  * limit) */
96 /**@} */
97 
98 /**@name Event handler properties
99  *
100  * @{
101  */
102 
103 #define EVENTHDLR_NAME "vbounds"
104 #define EVENTHDLR_DESC "bound change event handler for for vbounds propagator"
106 /**@} */
107 
108 /**@name Default parameter values
109  *
110  * @{
111  */
112 
113 #define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used to initialize conflict analysis? */
114 #define DEFAULT_USEIMPLICS FALSE /**< should implications be propagated? */
115 #define DEFAULT_USECLIQUES FALSE /**< should cliques be propagated? */
116 #define DEFAULT_USEVBOUNDS TRUE /**< should variable bounds be propagated? */
117 #define DEFAULT_DOTOPOSORT TRUE /**< should the bounds be topologically sorted in advance? */
118 #define DEFAULT_SORTCLIQUES FALSE /**< should cliques be regarded for the topological sort? */
119 #define DEFAULT_DETECTCYCLES FALSE /**< should cycles in the variable bound graph be identified? */
120 #define DEFAULT_MINNEWCLIQUES 0.1 /**< minimum number of new cliques to trigger another clique table analysis */
121 #define DEFAULT_MAXCLIQUESMEDIUM 50.0 /**< maximum number of cliques per variable to run clique table analysis in
122  * medium presolving */
123 #define DEFAULT_MAXCLIQUESEXHAUSTIVE 100.0 /**< maximum number of cliques per variable to run clique table analysis in
124  * exhaustive presolving */
126 /**@} */
127 
128 /**@name Propagator defines
129  *
130  * @{
131  *
132  * The propagator works on indices representing a bound of a variable. This index will be called bound index in the
133  * following. For a given active variable with problem index i (note that active variables have problem indices
134  * between 0 and nactivevariable - 1), the bound index of its lower bound is 2*i, the bound index of its upper
135  * bound is 2*i + 1. The other way around, a given bound index i corresponds to the variable with problem index
136  * i/2 (rounded down), and to the lower bound, if i is even, to the upper bound if i is odd.
137  * The following macros can be used to convert bound index into variable problem index and boundtype and vice versa.
138  */
139 #define getLbIndex(idx) (2*(idx))
140 #define getUbIndex(idx) (2*(idx)+1)
141 #define getVarIndex(idx) ((idx)/2)
142 #define getBoundtype(idx) (((idx) % 2 == 0) ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER)
143 #define isIndexLowerbound(idx) ((idx) % 2 == 0)
144 #define getBoundString(lower) ((lower) ? "lb" : "ub")
145 #define getBoundtypeString(type) ((type) == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper")
146 #define indexGetBoundString(idx) (getBoundString(isIndexLowerbound(idx)))
147 #define getOtherBoundIndex(idx) ((idx) + 1 - 2 * ((idx) % 2))
149 /**@} */
151 /*
152  * Data structures
153  */
154 
155 /** propagator data */
156 struct SCIP_PropData
157 {
158  SCIP_EVENTHDLR* eventhdlr; /**< event handler for catching bound changes */
159  SCIP_VAR** vars; /**< array containing all variable which are considered within the propagator */
160  SCIP_HASHMAP* varhashmap; /**< hashmap mapping from variable to index in the vars array */
161  int* topoorder; /**< array mapping on the bounds of variables in topological order;
162  * or -1, if the bound that should be at that position has no outgoing
163  * implications, cliques, or vbounds;
164  * i.e., for i < j and topoorder[i] != -1 != topoorder[j], the variable
165  * and boundtype represented by index topoorder[i] are earlier in the
166  * topological order than those represented by index topoorder[j]
167  */
168  int** vboundboundedidx; /**< array storing for each bound index the bound indices of all bounds
169  * influenced by this bound through variable bounds */
170  SCIP_Real** vboundcoefs; /**< array storing for each bound index the coefficients in the variable
171  * bounds influencing the corresponding bound index stored in
172  * vboundboundedidx */
173  SCIP_Real** vboundconstants; /**< array storing for each bound index the constants in the variable
174  * bounds influencing the corresponding bound index stored in
175  * vboundboundedidx */
176  int* nvbounds; /**< array storing for each bound index the number of vbounds stored */
177  int* vboundsize; /**< array with sizes of vbound arrays for the nodes */
178  int nbounds; /**< number of bounds of variables regarded (two times number of active variables) */
179  int lastpresolncliques; /**< number of cliques created until the last call to the presolver */
180  SCIP_PQUEUE* propqueue; /**< priority queue to handle the bounds of variables that were changed and have to be propagated */
181  SCIP_Bool* inqueue; /**< boolean array to store whether a bound of a variable is already contained in propqueue */
182  SCIP_Bool initialized; /**< was the data for propagation already initialized? */
183  SCIP_Real minnewcliques; /**< minimum percentage of new cliques to trigger another clique table analysis */
184  SCIP_Real maxcliquesmedium; /**< maximum number of cliques per variable to run clique table analysis in medium presolving */
185  SCIP_Real maxcliquesexhaustive;/**< maximum number of cliques per variable to run clique table analysis in exhaustive presolving */
186  SCIP_Bool usebdwidening; /**< should bound widening be used to initialize conflict analysis? */
187  SCIP_Bool useimplics; /**< should implications be propagated? */
188  SCIP_Bool usecliques; /**< should cliques be propagated? */
189  SCIP_Bool usevbounds; /**< should variable bounds be propagated? */
190  SCIP_Bool dotoposort; /**< should the bounds be topologically sorted in advance? */
191  SCIP_Bool sortcliques; /**< should cliques be regarded for the topological sort? */
192  SCIP_Bool detectcycles; /**< should cycles in the variable bound graph be identified? */
193 };
194 
195 /** inference information */
196 struct InferInfo
197 {
198  union
199  {
200  struct
201  {
202  unsigned int pos:31; /**< position of the variable which forced that propagation */
203  unsigned int boundtype:1; /**< bound type which was the reason (0: lower, 1: upper) */
204  } asbits;
205  int asint; /**< inference information as a single int value */
206  } val;
207 };
208 typedef struct InferInfo INFERINFO;
209 
210 /** converts an integer into an inference information */
211 static
212 INFERINFO intToInferInfo(
213  int i /**< integer to convert */
214  )
215 {
216  INFERINFO inferinfo;
217 
218  inferinfo.val.asint = i;
219 
220  return inferinfo;
221 }
222 
223 /** converts an inference information into an int */
224 static
225 int inferInfoToInt(
226  INFERINFO inferinfo /**< inference information to convert */
227  )
228 {
229  return inferinfo.val.asint;
230 }
231 
232 /** returns the propagation rule stored in the inference information */
233 static
235  INFERINFO inferinfo /**< inference information to convert */
236  )
237 {
238  assert((SCIP_BOUNDTYPE)inferinfo.val.asbits.boundtype == SCIP_BOUNDTYPE_LOWER
239  || (SCIP_BOUNDTYPE)inferinfo.val.asbits.boundtype == SCIP_BOUNDTYPE_UPPER);
240  return (SCIP_BOUNDTYPE)inferinfo.val.asbits.boundtype;
241 }
242 
243 /** returns the position stored in the inference information */
244 static
245 int inferInfoGetPos(
246  INFERINFO inferinfo /**< inference information to convert */
247  )
248 {
249  return (int) inferinfo.val.asbits.pos;
250 }
251 
252 /** constructs an inference information out of a position of a variable and a boundtype */
253 static
254 INFERINFO getInferInfo(
255  int pos, /**< position of the variable which forced that propagation */
256  SCIP_BOUNDTYPE boundtype /**< propagation rule that deduced the value */
257  )
258 {
259  INFERINFO inferinfo;
260 
261  assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER);
262  assert((int)boundtype >= 0 && (int)boundtype <= 1); /*lint !e685 !e568q*/
263  assert(pos >= 0);
264 
265  inferinfo.val.asbits.pos = (unsigned int) pos; /*lint !e732*/
266  inferinfo.val.asbits.boundtype = (unsigned int) boundtype; /*lint !e641*/
267 
268  return inferinfo;
269 }
270 
271 /*
272  * Local methods
273  */
274 
275 /* returns the lower bound index of a variable */
276 static
277 int varGetLbIndex(
278  SCIP_PROPDATA* propdata, /**< propagator data */
279  SCIP_VAR* var /**< variable to get the index for */
280  )
281 {
282  assert(SCIPhashmapExists(propdata->varhashmap, var) == ((size_t)SCIPhashmapGetImage(propdata->varhashmap, var) > 0));
283 
284  return getLbIndex((int)(size_t)SCIPhashmapGetImage(propdata->varhashmap, var) - 1);
285 }
286 
287 /* returns the upper bound index of a variable */
288 static
289 int varGetUbIndex(
290  SCIP_PROPDATA* propdata, /**< propagator data */
291  SCIP_VAR* var /**< variable to get the index for */
292  )
293 {
294  assert(SCIPhashmapExists(propdata->varhashmap, var) == ((size_t)SCIPhashmapGetImage(propdata->varhashmap, var) > 0));
295 
296  return getUbIndex((int)(size_t)SCIPhashmapGetImage(propdata->varhashmap, var) - 1);
297 }
298 
299 /** reset propagation data */
300 static
301 void resetPropdata(
302  SCIP_PROPDATA* propdata /**< propagator data */
303  )
304 {
305  propdata->vars = NULL;
306  propdata->varhashmap = NULL;
307  propdata->topoorder = NULL;
308  propdata->vboundboundedidx = NULL;
309  propdata->vboundcoefs = NULL;
310  propdata->vboundconstants = NULL;
311  propdata->nvbounds = NULL;
312  propdata->vboundsize = NULL;
313  propdata->nbounds = 0;
314  propdata->initialized = FALSE;
315 }
316 
317 /** catches events for variables */
318 static
320  SCIP* scip, /**< SCIP data structure */
321  SCIP_PROPDATA* propdata /**< propagator data */
322  )
323 {
324  SCIP_EVENTHDLR* eventhdlr;
325  SCIP_EVENTTYPE eventtype;
326  SCIP_VAR** vars;
327  SCIP_VAR* var;
328  SCIP_Bool lower;
329  int nbounds;
330  int v;
331  int idx;
332 
333  assert(scip != NULL);
334  assert(propdata != NULL);
335  assert(propdata->vars != NULL);
336  assert(propdata->topoorder != NULL);
337 
338  /* catch variable events according to computed eventtypes */
339  eventhdlr = propdata->eventhdlr;
340  assert(eventhdlr != NULL);
341 
342  vars = propdata->vars;
343  nbounds = propdata->nbounds;
344 
345  /* setup events */
346  for( v = 0; v < nbounds; ++v )
347  {
348  idx = propdata->topoorder[v];
349  assert(idx >= 0 && idx < nbounds);
350 
351  var = vars[getVarIndex(idx)];
352  lower = isIndexLowerbound(idx);
353 
354  /* if the bound does not influence another bound by implications, cliques, or vbounds,
355  * we do not create an event and do not catch changes of the bound;
356  * we mark this by setting the value in topoorder to -1
357  */
358  if( propdata->nvbounds[idx] == 0 && SCIPvarGetNImpls(var, lower) == 0 && SCIPvarGetNCliques(var, lower) == 0 )
359  {
360  propdata->topoorder[v] = -1;
361  continue;
362  }
363 
364  /* determine eventtype that we want to catch depending on boundtype of variable */
365  if( lower )
367  else
369 
370  SCIP_CALL( SCIPcatchVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*) (uintptr_t) v, NULL) ); /*lint !e571*/
371  }
372 
373  return SCIP_OKAY;
374 }
375 
376 /** drops events for variables */
377 static
379  SCIP* scip, /**< SCIP data structure */
380  SCIP_PROPDATA* propdata /**< propagator data */
381  )
382 {
383  SCIP_EVENTHDLR* eventhdlr;
384  SCIP_EVENTTYPE eventtype;
385  SCIP_VAR** vars;
386  SCIP_VAR* var;
387  SCIP_Bool lower;
388  int nbounds;
389  int v;
390  int idx;
391 
392  assert(propdata != NULL);
393 
394  eventhdlr = propdata->eventhdlr;
395  assert(eventhdlr != NULL);
396 
397  vars = propdata->vars;
398  nbounds = propdata->nbounds;
399 
400  for( v = 0; v < nbounds; ++v )
401  {
402  idx = propdata->topoorder[v];
403 
404  if( idx == -1 )
405  continue;
406 
407  assert(idx >= 0 && idx < nbounds);
408 
409  var = vars[getVarIndex(idx)];
410  lower = isIndexLowerbound(idx);
411 
412  /* determine eventtype that we catch and now want to drop depending on boundtype of variable */
413  if( lower )
415  else
417 
418  SCIP_CALL( SCIPdropVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*) (uintptr_t) v, -1) ); /*lint !e571*/
419  }
420 
421  return SCIP_OKAY;
422 }
423 
424 #define INITMEMSIZE 5
425 
426 /* adds a vbound to the propagator data to store it internally and allow forward propagation */
427 static
429  SCIP* scip, /**< SCIP data structure */
430  SCIP_PROPDATA* propdata, /**< propagator data */
431  int startidx, /**< index of bound of variable influencing the other variable */
432  int endidx, /**< index of bound of variable which is influenced */
433  SCIP_Real coef, /**< coefficient in the variable bound */
434  SCIP_Real constant /**< constant in the variable bound */
435  )
436 {
437  int nvbounds;
438 
439  assert(scip != NULL);
440  assert(propdata != NULL);
441 
442  if( propdata->vboundsize[startidx] == 0 )
443  {
444  /* allocate memory for storing vbounds */
445  propdata->vboundsize[startidx] = INITMEMSIZE;
446 
447  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundboundedidx[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
448  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundcoefs[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
449  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundconstants[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
450  }
451  else if( propdata->nvbounds[startidx] >= propdata->vboundsize[startidx] )
452  {
453  /* reallocate memory for storing vbounds */
454  propdata->vboundsize[startidx] = SCIPcalcMemGrowSize(scip, propdata->nvbounds[startidx] + 1);
455  assert(propdata->nvbounds[startidx] < propdata->vboundsize[startidx]);
456 
457  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundboundedidx[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
458  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundcoefs[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
459  SCIP_CALL( SCIPreallocMemoryArray(scip, &propdata->vboundconstants[startidx], propdata->vboundsize[startidx]) ); /*lint !e866*/
460  }
461 
462  nvbounds = propdata->nvbounds[startidx];
463  propdata->vboundboundedidx[startidx][nvbounds] = endidx;
464  propdata->vboundcoefs[startidx][nvbounds] = coef;
465  propdata->vboundconstants[startidx][nvbounds] = constant;
466  (propdata->nvbounds[startidx])++;
467 
468  return SCIP_OKAY;
469 }
470 
471 /** comparison method for two indices in the topoorder array, preferring higher indices because the order is reverse
472  * topological
473  */
474 static
475 SCIP_DECL_SORTPTRCOMP(compVarboundIndices)
476 {
477  int idx1 = (int)(size_t)elem1;
478  int idx2 = (int)(size_t)elem2;
479 
480  return idx2 - idx1;
481 }
482 
483 /* extract bound changes or infeasibility information from a cycle in the variable bound graph detected during
484  * depth-first search
485  */
486 static
488  SCIP* scip, /**< SCIP data structure */
489  SCIP_PROPDATA* propdata, /**< propagator data */
490  int* dfsstack, /**< array of size number of nodes to store the stack;
491  * only needed for performance reasons */
492  int* stacknextedge, /**< array storing the next edge to be visited in dfs for all nodes on the
493  * stack/in the current path; negative numbers represent a clique,
494  * positive numbers an implication (smaller numbers) or a variable bound */
495  int stacksize, /**< current stack size */
496  SCIP_Bool samebound, /**< does the cycle contain the same bound twice or both bounds of the same variable? */
497  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
498 
499  )
500 {
501  SCIP_VAR** vars;
502  SCIP_VAR* currvar;
503  SCIP_Bool currlower;
504 
505  SCIP_Real coef = 1.0;
506  SCIP_Real constant = 0.0;
507  SCIP_Bool islower;
508  SCIP_Real newbound;
509  int cycleidx;
510  int startidx;
511  int ntmpimpls;
512  int j;
513  int k;
514 
515  assert(scip != NULL);
516  assert(propdata != NULL);
517 
518  vars = propdata->vars;
519 
520  /* the last element on the stack is the end-point of the cycle */
521  cycleidx = dfsstack[stacksize - 1];
522 
523  /* the same bound of the variable was visited already earlier on the current path, so the start-point of the cycle
524  * has the same index
525  */
526  if( samebound )
527  startidx = cycleidx;
528  /* the other bound of the variable was visited earlier on the current path, so the start-point of the cycle
529  * has the index of the other bound
530  */
531  else
532  startidx = getOtherBoundIndex(cycleidx);
533 
534  /* search for the start-point of the cycle; since the endpoint is at position stacksize - 1 we start at stacksize - 2
535  * and go backwards
536  */
537  for( j = stacksize - 2; dfsstack[j] != startidx && j >= 0; --j ){};
538  assert(j >= 0);
539 
540  for( ; j < stacksize - 1; ++j )
541  {
542  currvar = vars[getVarIndex(dfsstack[j])];
543  currlower = isIndexLowerbound(dfsstack[j]);
544 
545  /* if we do not use implications, we assume the number of implications to be 0 (as we did before) */
546  ntmpimpls = (propdata->useimplics ? SCIPvarGetNImpls(currvar, currlower) : 0);
547 
548  /* stacknextedge[j] <= 0 --> the last outgoing edge traversed during dfs starting from node dfsstack[j] was given
549  * by a clique
550  */
551  if( stacknextedge[j] <= 0 )
552  {
553  SCIP_Bool nextlower = isIndexLowerbound(dfsstack[j+1]);
554 #if defined(SCIP_DEBUG) || defined(SCIP_MORE_DEBUG)
555  SCIP_CLIQUE** tmpcliques = SCIPvarGetCliques(currvar, currlower);
556  SCIP_VAR** cliquevars;
557  SCIP_Bool* cliquevals;
558  int ntmpcliques = SCIPvarGetNCliques(currvar, currlower);
559  int ncliquevars;
560  int v;
561 #endif
562  /* there are four cases:
563  * a) lb(x) -> ub(y) ==> clique(x,y,...) ==> y <= 1 - x
564  * b) lb(x) -> lb(y) ==> clique(x,~y,...) ==> y >= x
565  * c) ub(x) -> ub(y) ==> clique(~x,y,...) ==> y <= x
566  * d) ub(x) -> lb(y) ==> clique(~x,~y,...) ==> y >= 1 - x
567  *
568  * in cases b) and c), coef=1.0 and constant=0.0; these are the cases where both nodes represent
569  * the same type of bound
570  * in cases a) and d), coef=-1.0 and constant=1.0; both nodes represent different types of bounds
571  *
572  * we do not need to change the overall coef and constant in cases b) and c), but for the others
573  */
574  if( currlower != nextlower )
575  {
576  coef = -coef;
577  constant = -constant + 1.0;
578  }
579 
580  /* since the coefficient and constant only depend on the type of bounds of the two nodes (see below), we do not
581  * need to search for the variable in the clique; however, if debug output is enabled, we want to print the
582  * clique, if more debugging is enabled, we explicitly check that the variable and bound we expect are in the
583  * clique
584  */
585 #if defined(SCIP_DEBUG) || defined(SCIP_MORE_DEBUG)
586  if( stacknextedge[j] == 0 )
587  {
588  k = ntmpcliques - 1;
589  }
590  else
591  {
592  /* we processed at least one edge, so the next one should be -2 or smaller (we have a -1 offset) */
593  assert(stacknextedge[j] <= -2);
594 
595  k = -stacknextedge[j] - 2;
596 
597  assert(k < ntmpcliques);
598  }
599 
600  cliquevars = SCIPcliqueGetVars(tmpcliques[k]);
601  cliquevals = SCIPcliqueGetValues(tmpcliques[k]);
602  ncliquevars = SCIPcliqueGetNVars(tmpcliques[k]);
603 #ifdef SCIP_DEBUG
604  SCIPdebugMsg(scip, "clique: ");
605  for( v = 0; v < ncliquevars; ++v )
606  {
607  SCIPdebugMsg(scip, "%s%s ", cliquevals[v] ? "" : "~", SCIPvarGetName(cliquevars[v]));
608  }
609  SCIPdebugMsg(scip, "(equation:%d)\n", SCIPcliqueIsEquation(tmpcliques[k]));
610 #endif
611 #ifdef SCIP_MORE_DEBUG
612  for( v = 0; v < ncliquevars; ++v )
613  {
614  if( cliquevars[v] == vars[getVarIndex(dfsstack[j+1])] && cliquevals[v] == !nextlower )
615  break;
616  }
617  assert(v < ncliquevars);
618 #endif
619 
620  SCIPdebugMsg(scip, "%s(%s) -- (*%g + %g)[clique(<%s%s>,<%s%s>,...)] --> %s(%s)\n",
621  indexGetBoundString(dfsstack[j]), SCIPvarGetName(currvar),
622  (currlower != nextlower ? -1.0 : 1.0),
623  (currlower != nextlower ? 1.0 : 0.0),
624  (currlower ? "" : "~"), SCIPvarGetName(currvar),
625  (nextlower ? "~" : ""), SCIPvarGetName(vars[getVarIndex(dfsstack[j+1])]),
626  indexGetBoundString(dfsstack[j+1]), SCIPvarGetName(currvar));
627 #endif
628  }
629  /* stacknextedge[j] > 0 --> the last outgoing edge traversed during dfs starting from node dfsstack[j] was given
630  * by an implication or vbound. Implications are looked at first, so if stacknextedge[j] <= ntmpimpls, it comes
631  * from an implication
632  */
633  else if( stacknextedge[j] <= ntmpimpls )
634  {
635 #ifndef NDEBUG
636  SCIP_VAR** implvars = SCIPvarGetImplVars(currvar, currlower);
637 #endif
638  SCIP_BOUNDTYPE* impltypes = SCIPvarGetImplTypes(currvar, currlower);
639  SCIP_Real* implbounds = SCIPvarGetImplBounds(currvar, currlower);
640  SCIP_VAR* nextvar = vars[getVarIndex(dfsstack[j+1])];
641  SCIP_Real newconstant;
642  SCIP_Real newcoef;
643 
644  k = stacknextedge[j] - 1;
645 
646  assert(dfsstack[j+1] == (impltypes[k] == SCIP_BOUNDTYPE_LOWER ?
647  varGetLbIndex(propdata, implvars[k]) : varGetUbIndex(propdata, implvars[k])));
648 
649  if( impltypes[k] == SCIP_BOUNDTYPE_LOWER )
650  {
651  newcoef = implbounds[k] - SCIPvarGetLbLocal(nextvar);
652 
653  if( currlower )
654  {
655  newconstant = SCIPvarGetLbLocal(nextvar);
656  }
657  else
658  {
659  newconstant = implbounds[k];
660  newcoef *= -1.0;
661  }
662  }
663  else
664  {
665  assert(impltypes[k] == SCIP_BOUNDTYPE_UPPER);
666 
667  newcoef = SCIPvarGetUbLocal(nextvar) - implbounds[k];
668 
669  if( currlower )
670  {
671  newconstant = SCIPvarGetUbLocal(nextvar);
672  newcoef *= -1.0;
673  }
674  else
675  {
676  newconstant = implbounds[k];
677  }
678  }
679 
680  coef = coef * newcoef;
681  constant = constant * newcoef + newconstant;
682 
683  SCIPdebugMsg(scip, "%s(%s) -- (*%g + %g) --> %s(%s)\n",
684  indexGetBoundString(dfsstack[j]), SCIPvarGetName(vars[getVarIndex(dfsstack[j])]),
685  newcoef, newconstant,
686  indexGetBoundString(dfsstack[j+1]), SCIPvarGetName(vars[getVarIndex(dfsstack[j+1])]));
687  }
688  /* the edge was given by a variable bound relation */
689  else
690  {
691  assert(stacknextedge[j] > ntmpimpls);
692 
693  k = stacknextedge[j] - ntmpimpls - 1;
694  assert(k < propdata->nvbounds[dfsstack[j]]);
695  assert(propdata->vboundboundedidx[dfsstack[j]][k] == dfsstack[j+1]);
696 
697  SCIPdebugMsg(scip, "%s(%s) -- (*%g + %g) --> %s(%s)\n",
698  indexGetBoundString(dfsstack[j]), SCIPvarGetName(vars[getVarIndex(dfsstack[j])]),
699  propdata->vboundcoefs[dfsstack[j]][k], propdata->vboundconstants[dfsstack[j]][k],
700  indexGetBoundString(dfsstack[j+1]), SCIPvarGetName(vars[getVarIndex(dfsstack[j+1])]));
701 
702  coef = coef * propdata->vboundcoefs[dfsstack[j]][k];
703  constant = constant * propdata->vboundcoefs[dfsstack[j]][k] + propdata->vboundconstants[dfsstack[j]][k];
704  }
705  }
706 
707  SCIPdebugMsg(scip, "==> %s(%s) -- (*%g + %g) --> %s(%s)\n",
708  indexGetBoundString(startidx), SCIPvarGetName(vars[getVarIndex(startidx)]),
709  coef, constant,
710  indexGetBoundString(cycleidx), SCIPvarGetName(vars[getVarIndex(cycleidx)]));
711 
712  islower = isIndexLowerbound(cycleidx);
713 
714  /* we have a relation x <=/>= coef * x + constant now
715  * (the relation depends on islower, i.e., whether the last node in the cycle is a lower or upper bound)
716  * case 1) coef is 1.0 --> x cancels out and we have a statement 0 <=/>= constant.
717  * if we have a >= relation and constant is positive, we have a contradiction 0 >= constant
718  * if we have a <= relation and constant is negative, we have a contradiction 0 <= constant
719  * case 2) coef != 1.0 --> we have a relation x - coef * x <=/>= constant
720  * <=> (1 - coef) * x <=/>= constant
721  * if coef < 1.0 this gives us x >= constant / (1 - coef) (if islower=TRUE)
722  * or x <= constant / (1 - coef) (if islower=FALSE)
723  * if coef > 1.0, the relation signs need to be switched.
724  */
725  if( SCIPisEQ(scip, coef, 1.0) )
726  {
727  if( islower && SCIPisFeasPositive(scip, constant) )
728  {
729  SCIPdebugMsg(scip, "-> infeasible aggregated variable bound relation 0 >= %g\n", constant);
730  *infeasible = TRUE;
731  }
732  else if( !islower && SCIPisFeasNegative(scip, constant) )
733  {
734  SCIPdebugMsg(scip, "-> infeasible aggregated variable bound relation 0 <= %g\n", constant);
735  *infeasible = TRUE;
736  }
737  }
738  else
739  {
740  SCIP_Bool tightened;
741 
742  newbound = constant / (1.0 - coef);
743 
744  if( SCIPisGT(scip, coef, 1.0) )
745  islower = !islower;
746 
747  if( islower )
748  {
749  SCIPdebugMsg(scip, "-> found new lower bound: <%s>[%g,%g] >= %g\n", SCIPvarGetName(vars[getVarIndex(cycleidx)]),
750  SCIPvarGetLbLocal(vars[getVarIndex(cycleidx)]), SCIPvarGetUbLocal(vars[getVarIndex(cycleidx)]), newbound);
751  SCIP_CALL( SCIPtightenVarLb(scip, vars[getVarIndex(cycleidx)], newbound, FALSE, infeasible, &tightened) );
752  }
753  else
754  {
755  SCIPdebugMsg(scip, "-> found new upper bound: <%s>[%g,%g] <= %g\n", SCIPvarGetName(vars[getVarIndex(cycleidx)]),
756  SCIPvarGetLbLocal(vars[getVarIndex(cycleidx)]), SCIPvarGetUbLocal(vars[getVarIndex(cycleidx)]), newbound);
757  SCIP_CALL( SCIPtightenVarUb(scip, vars[getVarIndex(cycleidx)], newbound, FALSE, infeasible, &tightened) );
758  }
759 
760  if( tightened )
761  SCIPdebugMsg(scip, "---> applied new bound\n");
762  }
763 
764  return SCIP_OKAY;
765 }
766 
767 #define VISITED 1
768 #define ACTIVE 2
769 /** performs depth-first-search in the implicitly given directed graph from the given start index */
770 static
772  SCIP* scip, /**< SCIP data structure */
773  SCIP_PROPDATA* propdata, /**< propagator data */
774  int startnode, /**< node to start the depth-first-search */
775  int* visited, /**< array to store for each node, whether it was already visited */
776  int* dfsstack, /**< array of size number of nodes to store the stack;
777  * only needed for performance reasons */
778  int* stacknextedge, /**< array of size number of nodes to store the next edge to be visited in
779  * dfs for all nodes on the stack/in the current path; only needed for
780  * performance reasons */
781  int* dfsnodes, /**< array of nodes that can be reached starting at startnode, in reverse
782  * dfs order */
783  int* ndfsnodes, /**< pointer to store number of nodes that can be reached starting at
784  * startnode */
785  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
786  )
787 {
788  SCIP_VAR** vars;
789  SCIP_VAR* startvar;
790  SCIP_Bool lower;
791  int stacksize;
792  int curridx;
793  int nimpls;
794  int idx;
795  /* for cycle detection, we need to mark currently active nodes, otherwise we just mark them as visited */
796  int visitedflag = (propdata->detectcycles ? ACTIVE : VISITED);
797 
798  assert(startnode >= 0);
799  assert(startnode < propdata->nbounds);
800  assert(visited != NULL);
801  assert(visited[startnode] == 0);
802  assert(dfsstack != NULL);
803  assert(dfsnodes != NULL);
804  assert(ndfsnodes != NULL);
805  assert(infeasible != NULL);
806 
807  *infeasible = FALSE;
808 
809  vars = propdata->vars;
810 
811  /* put start node on the stack */
812  dfsstack[0] = startnode;
813  stacknextedge[0] = 0;
814  stacksize = 1;
815  idx = -1;
816 
817  /* we run until no more bounds indices are on the stack, i.e. all changed bounds were propagated */
818  while( stacksize > 0 )
819  {
820  /* get next node from stack */
821  curridx = dfsstack[stacksize - 1];
822 
823  /* mark current node as visited */
824  assert((visited[curridx] != 0) == (stacknextedge[stacksize - 1] != 0));
825  visited[curridx] = visitedflag;
826 
827  startvar = vars[getVarIndex(curridx)];
828  lower = isIndexLowerbound(curridx);
829 
830  /* if the variable was fixed in the meantime, it is a loose end in the variable bound graph */
831  if( SCIPisFeasGE(scip, SCIPvarGetLbGlobal(startvar), SCIPvarGetUbGlobal(startvar)) )
832  goto REMOVE;
833 
834  nimpls = 0;
835 
836  if( propdata->sortcliques && propdata->usecliques && stacknextedge[stacksize - 1] == 0 )
837  stacknextedge[stacksize - 1] = -1;
838 
839  /* stacknextedge is negative, if the last visited edge from the current node belongs to a clique;
840  * the index of the clique in the variable's clique list equals abs(stacknextedge) - 1
841  */
842  if( propdata->sortcliques && propdata->usecliques && stacknextedge[stacksize - 1] < 0 )
843  {
844  SCIP_CLIQUE** cliques;
845  int ncliques;
846  int j;
847  int i;
848  SCIP_Bool found;
849 
850  ncliques = SCIPvarGetNCliques(startvar, lower);
851  cliques = SCIPvarGetCliques(startvar, lower);
852  found = FALSE;
853 
854  assert(stacknextedge[stacksize - 1] == -1 || -stacknextedge[stacksize - 1] - 1 <= ncliques);
855 
856  /* iterate over all not yet handled cliques and search for an unvisited node */
857  for( j = -stacknextedge[stacksize - 1] - 1; j < ncliques; ++j )
858  {
859  SCIP_VAR** cliquevars;
860  SCIP_Bool* cliquevals;
861  int ncliquevars;
862 
863  cliquevars = SCIPcliqueGetVars(cliques[j]);
864  cliquevals = SCIPcliqueGetValues(cliques[j]);
865  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
866 
867  for( i = 0; i < ncliquevars; ++i )
868  {
869  if( cliquevars[i] == startvar )
870  continue;
871 
872  if( cliquevals[i] )
873  idx = varGetUbIndex(propdata, cliquevars[i]);
874  else
875  idx = varGetLbIndex(propdata, cliquevars[i]);
876 
877  /* we reached a variable that was already visited on the active path, so we have a cycle in the variable
878  * bound graph and try to extract valid bound changes from it or detect infeasibility
879  */
880  if( idx >= 0 && (visited[idx] == ACTIVE || visited[getOtherBoundIndex(idx)] == ACTIVE)
881  && !SCIPisFeasGE(scip, SCIPvarGetLbGlobal(cliquevars[i]), SCIPvarGetUbGlobal(cliquevars[i])) )
882  {
883  SCIPdebugMsg(scip, "found cycle\n");
884 
885  dfsstack[stacksize] = idx;
886  stacknextedge[stacksize - 1] = -j - 2;
887 
888  SCIP_CALL( extractCycle(scip, propdata, dfsstack, stacknextedge, stacksize + 1,
889  visited[idx] == ACTIVE, infeasible) );
890 
891  if( *infeasible )
892  break;
893  }
894 
895  /* break when the first unvisited node is reached */
896  if( idx >= 0 && !visited[idx] )
897  {
898  found = TRUE;
899  break;
900  }
901  }
902  if( found )
903  break;
904  }
905 
906  /* we stopped because we found an unhandled node and not because we reached the end of the list */
907  if( found )
908  {
909  assert(idx >= 0);
910  assert(!visited[idx]);
911  assert(j < ncliques);
912 
913  SCIPdebugMsg(scip, "clique: %s(%s) -> %s(%s)\n", getBoundString(lower), SCIPvarGetName(startvar),
915 
916  /* put the adjacent node onto the stack */
917  dfsstack[stacksize] = idx;
918  stacknextedge[stacksize] = 0;
919  stacknextedge[stacksize - 1] = -j - 2;
920  stacksize++;
921  assert(stacksize <= propdata->nbounds);
922 
923  /* restart while loop, get next index from stack */
924  continue;
925  }
926  else
927  {
928  /* we did not find an edge to an unhandled node given by a clique */
929  stacknextedge[stacksize - 1] = 0;
930  }
931  }
932  assert(stacknextedge[stacksize - 1] >= 0);
933 
934  /* go over edges given by implications */
935  if( propdata->useimplics )
936  {
937  nimpls = SCIPvarGetNImpls(startvar, lower);
938 
939  if( stacknextedge[stacksize - 1] < nimpls )
940  {
941  SCIP_VAR** implvars;
942  SCIP_BOUNDTYPE* impltypes;
943  int* implids;
944  int i;
945 
946  implvars = SCIPvarGetImplVars(startvar, lower);
947  impltypes = SCIPvarGetImplTypes(startvar, lower);
948  implids = SCIPvarGetImplIds(startvar, lower);
949 
950  for( i = stacknextedge[stacksize - 1]; i < nimpls; ++i )
951  {
952  /* it might happen that implications point to inactive variables (normally, those are removed when a
953  * variable becomes inactive, but in some cases, it cannot be done), we have to ignore these variables
954  */
955  if( !SCIPvarIsActive(implvars[i]) )
956  continue;
957 
958  /* implication is just a shortcut, so we dont regard it now, because will later go the long way, anyway;
959  * however, if we do regard cliques for the topological order, we use them to get a better order
960  */
961  if( propdata->usecliques && !propdata->sortcliques && implids[i] < 0 )
962  continue;
963 
964  idx = (impltypes[i] == SCIP_BOUNDTYPE_LOWER ?
965  varGetLbIndex(propdata, implvars[i]) : varGetUbIndex(propdata, implvars[i]));
966 
967  /* we reached a variable that was already visited on the active path, so we have a cycle in the variable
968  * bound graph and try to extract valid bound changes from it or detect infeasibility
969  */
970  if( idx >= 0 && (visited[idx] == ACTIVE || visited[getOtherBoundIndex(idx)] == ACTIVE)
971  && !SCIPisFeasGE(scip, SCIPvarGetLbGlobal(implvars[i]), SCIPvarGetUbGlobal(implvars[i])) )
972  {
973  SCIPdebugMsg(scip, "found cycle\n");
974 
975  dfsstack[stacksize] = idx;
976  stacknextedge[stacksize - 1] = i + 1;
977 
978  SCIP_CALL( extractCycle(scip, propdata, dfsstack, stacknextedge, stacksize + 1,
979  visited[idx] == ACTIVE, infeasible) );
980 
981  if( *infeasible )
982  break;
983  }
984 
985  /* break when the first unvisited node is reached */
986  if( idx >= 0 && !visited[idx] )
987  break;
988  }
989 
990  /* we stopped because we found an unhandled node and not because we reached the end of the list */
991  if( i < nimpls )
992  {
993  assert(!visited[idx]);
994 
995  SCIPdebugMsg(scip, "impl: %s(%s) -> %s(%s)\n", getBoundString(lower), SCIPvarGetName(startvar),
997 
998  /* put the adjacent node onto the stack */
999  dfsstack[stacksize] = idx;
1000  stacknextedge[stacksize] = 0;
1001  stacknextedge[stacksize - 1] = i + 1;
1002  stacksize++;
1003  assert(stacksize <= propdata->nbounds);
1004 
1005  /* restart while loop, get next index from stack */
1006  continue;
1007  }
1008  else
1009  {
1010  stacknextedge[stacksize - 1] = nimpls;
1011  }
1012  }
1013  }
1014  assert(stacknextedge[stacksize - 1] >= nimpls);
1015 
1016  /* go over edges corresponding to varbounds */
1017  if( propdata->usevbounds )
1018  {
1019  int nvbounds;
1020  int* vboundidx;
1021  int i;
1022 
1023  nvbounds = propdata->nvbounds[curridx];
1024  vboundidx = propdata->vboundboundedidx[curridx];
1025 
1026  /* iterate over all vbounds for the given bound */
1027  for( i = stacknextedge[stacksize - 1] - nimpls; i < nvbounds; ++i )
1028  {
1029  idx = vboundidx[i];
1030  assert(idx >= 0);
1031 
1032  if( (visited[idx] == ACTIVE || visited[getOtherBoundIndex(idx)] == ACTIVE)
1033  && !SCIPisFeasGE(scip, SCIPvarGetLbGlobal(vars[getVarIndex(idx)]), SCIPvarGetUbGlobal(vars[getVarIndex(idx)])) )
1034  {
1035  SCIPdebugMsg(scip, "found cycle\n");
1036 
1037  dfsstack[stacksize] = idx;
1038  stacknextedge[stacksize - 1] = nimpls + i + 1;
1039 
1040  /* we reached a variable that was already visited on the active path, so we have a cycle in the variable
1041  * bound graph and try to extract valid bound changes from it or detect infeasibility
1042  */
1043  SCIP_CALL( extractCycle(scip, propdata, dfsstack, stacknextedge, stacksize + 1,
1044  visited[idx] == ACTIVE, infeasible) );
1045 
1046  if( *infeasible )
1047  break;
1048  }
1049 
1050  /* break when the first unvisited node is reached */
1051  if( !visited[idx] )
1052  break;
1053  }
1054 
1055  if( *infeasible )
1056  break;
1057 
1058  /* we stopped because we found an unhandled node and not because we reached the end of the list */
1059  if( i < nvbounds )
1060  {
1061  assert(!visited[idx]);
1062 
1063  SCIPdebugMsg(scip, "vbound: %s(%s) -> %s(%s)\n", getBoundString(lower), SCIPvarGetName(startvar),
1064  indexGetBoundString(idx), SCIPvarGetName(vars[getVarIndex(idx)]));
1065 
1066  /* put the adjacent node onto the stack */
1067  dfsstack[stacksize] = idx;
1068  stacknextedge[stacksize] = 0;
1069  stacknextedge[stacksize - 1] = nimpls + i + 1;
1070  stacksize++;
1071  assert(stacksize <= propdata->nbounds);
1072 
1073  /* restart while loop, get next index from stack */
1074  continue;
1075  }
1076 
1077  }
1078  REMOVE:
1079  /* the current node was completely handled, remove it from stack */
1080  stacksize--;
1081 
1082  SCIPdebugMsg(scip, "topoorder[%d] = %s(%s)\n", *ndfsnodes, getBoundString(lower), SCIPvarGetName(startvar));
1083 
1084  /* store node in the sorted nodes array */
1085  dfsnodes[(*ndfsnodes)] = curridx;
1086  assert(visited[curridx] == visitedflag);
1087  visited[curridx] = VISITED;
1088  (*ndfsnodes)++;
1089  }
1090 
1091  return SCIP_OKAY;
1092 }
1093 
1094 /** sort the bounds of variables topologically */
1095 static
1097  SCIP* scip, /**< SCIP data structure */
1098  SCIP_PROPDATA* propdata, /**< propagator data */
1099  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
1100  )
1101 {
1102  int* dfsstack;
1103  int* stacknextedge;
1104  int* visited;
1105  int nsortednodes;
1106  int nbounds;
1107  int i;
1108 
1109  assert(scip != NULL);
1110  assert(propdata != NULL);
1111  assert(infeasible != NULL);
1112 
1113  nbounds = propdata->nbounds;
1114 
1115  SCIP_CALL( SCIPallocBufferArray(scip, &dfsstack, nbounds) );
1116  SCIP_CALL( SCIPallocBufferArray(scip, &stacknextedge, nbounds) );
1117  SCIP_CALL( SCIPallocClearBufferArray(scip, &visited, nbounds) );
1118 
1119  nsortednodes = 0;
1120 
1121  /* while there are unvisited nodes, run dfs starting from one of these nodes; the dfs orders are stored in the
1122  * topoorder array, later dfs calls are just appended after the stacks of previous dfs calls, which gives us a
1123  * reverse topological order
1124  */
1125  for( i = 0; i < nbounds && !(*infeasible); ++i )
1126  {
1127  if( !visited[i] )
1128  {
1129  SCIP_CALL( dfs(scip, propdata, i, visited, dfsstack, stacknextedge, propdata->topoorder, &nsortednodes, infeasible) );
1130  }
1131  }
1132  assert((nsortednodes == nbounds) || (*infeasible));
1133 
1134  SCIPfreeBufferArray(scip, &visited);
1135  SCIPfreeBufferArray(scip, &stacknextedge);
1136  SCIPfreeBufferArray(scip, &dfsstack);
1137 
1138  return SCIP_OKAY;
1139 }
1140 
1141 /** initializes the internal data for the variable bounds propagator */
1142 static
1144  SCIP* scip, /**< SCIP data structure */
1145  SCIP_PROP* prop, /**< vbounds propagator */
1146  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
1147  )
1148 {
1149  SCIP_PROPDATA* propdata;
1150  SCIP_VAR** vars;
1151  int nvars;
1152  int nbounds;
1153  int startidx;
1154  int v;
1155  int n;
1156 
1157  assert(scip != NULL);
1158  assert(prop != NULL);
1159  assert(infeasible != NULL);
1160 
1161  /* get propagator data */
1162  propdata = SCIPpropGetData(prop);
1163  assert(propdata != NULL);
1164  assert(!propdata->initialized);
1165 
1166  SCIPdebugMsg(scip, "initialize vbounds propagator for problem <%s>\n", SCIPgetProbName(scip));
1167 
1168  vars = SCIPgetVars(scip);
1169  nvars = SCIPgetNVars(scip);
1170  nbounds = 2 * nvars;
1171 
1172  *infeasible = FALSE;
1173 
1174  /* store size of the bounds of variables array */
1175  propdata->nbounds = nbounds;
1176 
1177  if( nbounds == 0 )
1178  return SCIP_OKAY;
1179 
1180  propdata->initialized = TRUE;
1181 
1182  /* prepare priority queue structure */
1183  SCIP_CALL( SCIPpqueueCreate(&propdata->propqueue, nvars, 2.0, compVarboundIndices) );
1184  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->inqueue, nbounds) );
1185  BMSclearMemoryArray(propdata->inqueue, nbounds);
1186 
1187  /* we need to copy the variable since this array is the basis of the propagator and the corresponding variable array
1188  * within SCIP might change during the search
1189  */
1190  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &propdata->vars, vars, nvars) );
1191  SCIP_CALL( SCIPhashmapCreate(&propdata->varhashmap, SCIPblkmem(scip), nvars) );
1192 
1193  for( v = 0; v < nvars; ++v )
1194  {
1195  SCIP_CALL( SCIPhashmapInsert(propdata->varhashmap, propdata->vars[v], (void*)(size_t)(v + 1)) );
1196  }
1197 
1198  /* allocate memory for the arrays of the propdata */
1199  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->topoorder, nbounds) );
1200  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundboundedidx, nbounds) );
1201  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundcoefs, nbounds) );
1202  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundconstants, nbounds) );
1203  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->nvbounds, nbounds) );
1204  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->vboundsize, nbounds) );
1205  BMSclearMemoryArray(propdata->vboundboundedidx, nbounds);
1206  BMSclearMemoryArray(propdata->vboundcoefs, nbounds);
1207  BMSclearMemoryArray(propdata->vboundconstants, nbounds);
1208  BMSclearMemoryArray(propdata->nvbounds, nbounds);
1209  BMSclearMemoryArray(propdata->vboundsize, nbounds);
1210 
1211  for( v = 0; v < nbounds; ++v )
1212  {
1213  propdata->topoorder[v] = v;
1214  propdata->vboundboundedidx[v] = NULL;
1215  propdata->vboundcoefs[v] = NULL;
1216  propdata->vboundconstants[v] = NULL;
1217  propdata->nvbounds[v] = 0;
1218  propdata->vboundsize[v] = 0;
1219  }
1220 
1221  /* collect information about varbounds */
1222  for( v = 0; v < nbounds; ++v )
1223  {
1224  SCIP_VAR** vbvars;
1225  SCIP_VAR* var;
1226  SCIP_Real* coefs;
1227  SCIP_Real* constants;
1228  SCIP_Bool lower;
1229  int nvbvars;
1230 
1231  var = vars[getVarIndex(v)];
1232  lower = isIndexLowerbound(v);
1233 
1234  /* get the variable bound informations for the current variable */
1235  if( lower )
1236  {
1237  vbvars = SCIPvarGetVlbVars(var);
1238  coefs = SCIPvarGetVlbCoefs(var);
1239  constants = SCIPvarGetVlbConstants(var);
1240  nvbvars = SCIPvarGetNVlbs(var);
1241  }
1242  else
1243  {
1244  vbvars = SCIPvarGetVubVars(var);
1245  coefs = SCIPvarGetVubCoefs(var);
1246  constants = SCIPvarGetVubConstants(var);
1247  nvbvars = SCIPvarGetNVubs(var);
1248  }
1249 
1250  /* loop over all variable bounds; a variable lower bound has the form: x >= b*y + d,
1251  * a variable upper bound the form x <= b*y + d */
1252  for( n = 0; n < nvbvars; ++n )
1253  {
1254  SCIP_VAR* vbvar;
1255  SCIP_Real coef;
1256  SCIP_Real constant;
1257 
1258  vbvar = vbvars[n];
1259  coef = coefs[n];
1260  constant = constants[n];
1261  assert(vbvar != NULL);
1262 
1263  /* transform variable bound variable to an active variable, if possible */
1264  SCIP_CALL( SCIPgetProbvarSum(scip, &vbvar, &coef, &constant) );
1265  assert(vbvar != NULL);
1266 
1267  if( !SCIPvarIsActive(vbvar) )
1268  continue;
1269 
1270  /* if the coefficient is positive, the type of bound is the same for the bounded and the bounding variable */
1271  if( SCIPisPositive(scip, coef) )
1272  startidx = (lower ? varGetLbIndex(propdata, vbvar) : varGetUbIndex(propdata, vbvar));
1273  else
1274  startidx = (lower ? varGetUbIndex(propdata, vbvar) : varGetLbIndex(propdata, vbvar));
1275  assert(startidx >= 0);
1276 
1277  /* If the vbvar is binary, the vbound should be stored as an implication already.
1278  * However, it might happen that vbvar was integer when the variable bound was added, but was converted
1279  * to a binary variable later during presolving when its upper bound was changed to 1. In this case,
1280  * the implication might not have been created.
1281  */
1282  if( SCIPvarGetType(vbvar) == SCIP_VARTYPE_BINARY
1283  && SCIPvarHasImplic(vbvar, isIndexLowerbound(startidx), var, getBoundtype(v)) )
1284  {
1285  SCIPdebugMsg(scip, "varbound <%s> %s %g * <%s> + %g not added to propagator data due to reverse implication\n",
1286  SCIPvarGetName(var), (lower ? ">=" : "<="), coef,
1287  SCIPvarGetName(vbvar), constant);
1288  }
1289  else
1290  {
1291  SCIP_CALL( addVbound(scip, propdata, startidx, v, coef, constant) );
1292 
1293  SCIPdebugMsg(scip, "varbound <%s> %s %g * <%s> + %g added to propagator data\n",
1294  SCIPvarGetName(var), (lower ? ">=" : "<="), coef,
1295  SCIPvarGetName(vbvar), constant);
1296 
1297  }
1298  }
1299  }
1300 
1301  /* sort the bounds topologically */
1302  if( propdata->dotoposort )
1303  {
1304  SCIP_CALL( topologicalSort(scip, propdata, infeasible) );
1305  }
1306 
1307  /* catch variable events */
1308  SCIP_CALL( catchEvents(scip, propdata) );
1309 
1310  return SCIP_OKAY;
1311 }
1312 
1313 /** resolves a propagation by adding the variable which implied that bound change */
1314 static
1316  SCIP* scip, /**< SCIP data structure */
1317  SCIP_PROPDATA* propdata, /**< propagator data */
1318  SCIP_VAR* var, /**< variable to be reported */
1319  SCIP_BOUNDTYPE boundtype, /**< bound to be reported */
1320  SCIP_BDCHGIDX* bdchgidx /**< the index of the bound change, representing the point of time where
1321  * the change took place, or NULL for the current local bounds */
1322  )
1323 {
1324  assert(propdata != NULL);
1325  assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER);
1326 
1327  SCIPdebugMsg(scip, " -> add %s bound of variable <%s> as reason\n",
1328  getBoundtypeString(boundtype), SCIPvarGetName(var));
1329 
1330  switch( boundtype )
1331  {
1332  case SCIP_BOUNDTYPE_LOWER:
1333  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
1334  break;
1335  case SCIP_BOUNDTYPE_UPPER:
1336  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
1337  break;
1338  default:
1339  SCIPerrorMessage("invalid bound type <%d>\n", boundtype);
1340  SCIPABORT();
1341  return SCIP_INVALIDDATA; /*lint !e527*/
1342  }
1343 
1344  return SCIP_OKAY;
1345 }
1346 
1347 /** relaxes bound of give variable as long as the given inference bound still leads to a cutoff and add that bound
1348  * change to the conflict set
1349  */
1350 static
1352  SCIP* scip, /**< SCIP data structure */
1353  SCIP_VAR* var, /**< variable for which the upper bound should be relaxed */
1354  SCIP_BOUNDTYPE boundtype, /**< boundtype used for the variable bound variable */
1355  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where
1356  * the change took place, or NULL for the current local bounds */
1357  SCIP_Real relaxedbd /**< relaxed bound */
1358  )
1359 {
1360  if( boundtype == SCIP_BOUNDTYPE_LOWER )
1361  {
1362  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, relaxedbd) );
1363  }
1364  else
1365  {
1366  assert(boundtype == SCIP_BOUNDTYPE_UPPER);
1367  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, relaxedbd) );
1368  }
1369 
1370  return SCIP_OKAY;
1371 }
1372 
1373 /** compute the relaxed bound which is sufficient to propagate the inference lower bound of given variable */
1374 static
1376  SCIP* scip, /**< SCIP data structure */
1377  SCIP_VAR* var, /**< variable which was propagated */
1378  SCIP_Real inferlb, /**< inference lower bound */
1379  SCIP_Real coef, /**< inference variable bound coefficient used */
1380  SCIP_Real constant /**< inference variable bound constant used */
1381  )
1382 {
1383  SCIP_Real relaxedbd;
1384 
1385  if( SCIPvarIsIntegral(var) && inferlb < SCIPgetHugeValue(scip) * SCIPfeastol(scip) )
1386  relaxedbd = (inferlb - 1.0 + 2*SCIPfeastol(scip) - constant) / coef;
1387  else
1388  relaxedbd = (inferlb - constant) / coef;
1389 
1390  /* check the computed relaxed lower/upper bound is a proper reason for the inference bound which has to be explained */
1391  assert(SCIPisEQ(scip, inferlb, SCIPadjustedVarLb(scip, var, relaxedbd * coef + constant)));
1392 
1393  if( coef > 0.0 )
1394  relaxedbd += SCIPfeastol(scip);
1395  else
1396  relaxedbd -= SCIPfeastol(scip);
1397 
1398  return relaxedbd;
1399 }
1400 
1401 /** analyzes an infeasibility which was reached by updating the lower bound of the inference variable above its upper
1402  * bound
1403  */
1404 static
1406  SCIP* scip, /**< SCIP data structure */
1407  SCIP_PROPDATA* propdata, /**< propagator data */
1408  SCIP_VAR* infervar, /**< variable which led to a cutoff */
1409  SCIP_Real inferlb, /**< lower bound which led to infeasibility */
1410  SCIP_VAR* vbdvar, /**< variable which is the reason for the lower bound change */
1411  SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the lower bound change */
1412  SCIP_Real coef, /**< inference variable bound coefficient used */
1413  SCIP_Real constant, /**< inference variable bound constant used */
1414  SCIP_Bool canwide /**< can bound widening be used (for vbounds) or not
1415  * (for implications or cliques) */
1416  )
1417 {
1418  assert(scip != NULL);
1419  assert(propdata != NULL);
1420  assert(infervar != NULL);
1421  assert(SCIPisEQ(scip, SCIPvarGetUbLocal(infervar), SCIPgetVarUbAtIndex(scip, infervar, NULL, FALSE)));
1422  assert(SCIPisEQ(scip, SCIPgetVarUbAtIndex(scip, infervar, NULL, TRUE), SCIPgetVarUbAtIndex(scip, infervar, NULL, FALSE)));
1423  assert(SCIPisGT(scip, inferlb, SCIPvarGetUbLocal(infervar)));
1424  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
1425 
1426  /* check if conflict analysis is applicable */
1428  return SCIP_OKAY;
1429 
1430  if( canwide && propdata->usebdwidening )
1431  {
1432  SCIP_Real relaxedbd;
1433  SCIP_Real relaxedub;
1434 
1435  SCIPdebugMsg(scip, "try to create conflict using bound widening order: inference variable, variable bound variable\n");
1436 
1437  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
1439 
1440  /* adjust lower bound */
1441  inferlb = SCIPadjustedVarLb(scip, infervar, inferlb);
1442 
1443  /* compute a relaxed upper bound which would be sufficient to be still infeasible */
1444  if( SCIPvarIsIntegral(infervar) )
1445  relaxedub = inferlb - 1.0;
1446  else
1447  relaxedub = inferlb - 2*SCIPfeastol(scip);
1448 
1449  /* try to relax inference variable upper bound such that the infeasibility is still given */
1450  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, relaxedub) );
1451 
1452  /* collect the upper bound which is reported to the conflict analysis */
1453  relaxedub = SCIPgetConflictVarUb(scip, infervar);
1454 
1455  /* adjust inference bound with respect to the upper bound reported to the conflict analysis */
1456  if( SCIPvarIsIntegral(infervar) )
1457  relaxedub = relaxedub + 1.0;
1458  else
1459  relaxedub = relaxedub + 2*SCIPfeastol(scip);
1460 
1461  /* compute the relaxed bound which is sufficient to propagate the inference lower bound of given variable */
1462  relaxedbd = computeRelaxedLowerbound(scip, infervar, relaxedub, coef, constant);
1463 
1464  /* try to relax variable bound variable */
1465  SCIP_CALL( relaxVbdvar(scip, vbdvar, boundtype, NULL, relaxedbd) );
1466 
1467  /* analyze the conflict */
1468  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
1469  }
1470  else
1471  {
1472  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
1474 
1475  /* add upper bound of the variable for which we tried to change the lower bound */
1476  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
1477 
1478  /* add (correct) bound of the variable which let to the new lower bound */
1479  SCIP_CALL( resolvePropagation(scip, propdata, vbdvar, boundtype, NULL) );
1480 
1481  /* analyze the conflict */
1482  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
1483  }
1484 
1485  return SCIP_OKAY;
1486 }
1487 
1488 /** compute the relaxed bound which is sufficient to propagate the inference upper bound of given variable */
1489 static
1491  SCIP* scip, /**< SCIP data structure */
1492  SCIP_VAR* var, /**< variable which was propagated */
1493  SCIP_Real inferub, /**< inference upper bound */
1494  SCIP_Real coef, /**< inference variable bound coefficient used */
1495  SCIP_Real constant /**< inference variable bound constant used */
1496  )
1497 {
1498  SCIP_Real relaxedbd;
1499 
1500  if( SCIPvarIsIntegral(var) && inferub < SCIPgetHugeValue(scip) * SCIPfeastol(scip) )
1501  relaxedbd = (inferub + 1.0 - 2*SCIPfeastol(scip) - constant) / coef;
1502  else
1503  relaxedbd = (inferub - constant) / coef;
1504 
1505  /* check the computed relaxed lower/upper bound is a proper reason for the inference bound which has to be explained */
1506  assert(SCIPisEQ(scip, inferub, SCIPadjustedVarUb(scip, var, relaxedbd * coef + constant)));
1507 
1508  if( coef > 0.0 )
1509  relaxedbd -= SCIPfeastol(scip);
1510  else
1511  relaxedbd += SCIPfeastol(scip);
1512 
1513  return relaxedbd;
1514 }
1515 
1516 /** analyzes an infeasibility which was reached by updating the upper bound of the inference variable below its lower
1517  * bound
1518  */
1519 static
1521  SCIP* scip, /**< SCIP data structure */
1522  SCIP_PROPDATA* propdata, /**< propagator data */
1523  SCIP_VAR* infervar, /**< variable which led to a cutoff */
1524  SCIP_Real inferub, /**< upper bound which led to infeasibility */
1525  SCIP_VAR* vbdvar, /**< variable which is the reason for the upper bound change */
1526  SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the upper bound change */
1527  SCIP_Real coef, /**< inference variable bound coefficient used */
1528  SCIP_Real constant, /**< inference variable bound constant used */
1529  SCIP_Bool canwide /**< can bound widening be used (for vbounds) or not (for inplications or cliques) */
1530  )
1531 {
1532  assert(scip != NULL);
1533  assert(propdata != NULL);
1534  assert(infervar != NULL);
1535  assert(SCIPisEQ(scip, SCIPvarGetLbLocal(infervar), SCIPgetVarLbAtIndex(scip, infervar, NULL, FALSE)));
1536  assert(SCIPisEQ(scip, SCIPgetVarLbAtIndex(scip, infervar, NULL, TRUE), SCIPgetVarLbAtIndex(scip, infervar, NULL, FALSE)));
1537  assert(SCIPisLT(scip, inferub, SCIPvarGetLbLocal(infervar)));
1538  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
1539 
1540  /* check if conflict analysis is applicable */
1542  return SCIP_OKAY;
1543 
1544  if( canwide && propdata->usebdwidening )
1545  {
1546  SCIP_Real relaxedbd;
1547  SCIP_Real relaxedlb;
1548 
1549  SCIPdebugMsg(scip, "try to create conflict using bound widening order: inference variable, variable bound variable\n");
1550 
1551  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
1553 
1554  /* adjust upper bound */
1555  inferub = SCIPadjustedVarUb(scip, infervar, inferub);
1556 
1557  /* compute a relaxed lower bound which would be sufficient to be still infeasible */
1558  if( SCIPvarIsIntegral(infervar) )
1559  relaxedlb = inferub + 1.0;
1560  else
1561  relaxedlb = inferub + 2*SCIPfeastol(scip);
1562 
1563  /* try to relax inference variable lower bound such that the infeasibility is still given */
1564  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, relaxedlb) );
1565 
1566  /* collect the lower bound which is reported to the conflict analysis */
1567  relaxedlb = SCIPgetConflictVarLb(scip, infervar);
1568 
1569  /* adjust inference bound with respect to the upper bound reported to the conflict analysis */
1570  if( SCIPvarIsIntegral(infervar) )
1571  relaxedlb = relaxedlb - 1.0;
1572  else
1573  relaxedlb = relaxedlb - 2*SCIPfeastol(scip);
1574 
1575  /* compute the relaxed bound which is sufficient to propagate the inference upper bound of given variable */
1576  relaxedbd = computeRelaxedUpperbound(scip, infervar, relaxedlb, coef, constant);
1577 
1578  /* try to relax variable bound variable */
1579  SCIP_CALL( relaxVbdvar(scip, vbdvar, boundtype, NULL, relaxedbd) );
1580 
1581  /* analyze the conflict */
1582  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
1583  }
1584  else
1585  {
1586  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
1588 
1589  /* add lower bound of the variable for which we tried to change the upper bound */
1590  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
1591 
1592  /* add (correct) bound of the variable which let to the new upper bound */
1593  SCIP_CALL( resolvePropagation(scip, propdata, vbdvar, boundtype, NULL) );
1594 
1595  /* analyze the conflict */
1596  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
1597  }
1598 
1599  return SCIP_OKAY;
1600 }
1601 
1602 /* tries to tighten the (global) lower bound of the given variable to the given new bound */
1603 static
1605  SCIP* scip, /**< SCIP data structure */
1606  SCIP_PROP* prop, /**< vbounds propagator */
1607  SCIP_PROPDATA* propdata, /**< propagator data */
1608  SCIP_VAR* var, /**< variable whose lower bound should be tightened */
1609  SCIP_Real newlb, /**< new lower bound for the variable */
1610  SCIP_Bool global, /**< is the bound globally valid? */
1611  SCIP_VAR* vbdvar, /**< variable which is the reason for the lower bound change */
1612  SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the lower bound change */
1613  SCIP_Bool force, /**< should domain changes for continuous variables be forced */
1614  SCIP_Real coef, /**< coefficient in vbound constraint causing the propagation;
1615  * or 0.0 if propagation is caused by clique or implication */
1616  SCIP_Real constant, /**< constant in vbound constraint causing the propagation;
1617  * or 0.0 if propagation is caused by clique or implication */
1618  SCIP_Bool canwide, /**< can bound widening be used (for vbounds) or not (for inplications or cliques) */
1619  int* nchgbds, /**< pointer to increase, if a bound was changed */
1620  SCIP_RESULT* result /**< pointer to store the result of the propagation */
1621  )
1622 {
1623  INFERINFO inferinfo;
1624  SCIP_Real lb;
1625  SCIP_Bool tightened;
1626  SCIP_Bool infeasible;
1627 
1628  assert(scip != NULL);
1629  assert(prop != NULL);
1630  assert(propdata != NULL);
1631  assert(var != NULL);
1632  assert(nchgbds != NULL);
1633  assert(result != NULL);
1634 
1635  lb = SCIPvarGetLbLocal(var);
1636 
1637  /* check that the new upper bound is better */
1638  if( (SCIPvarIsIntegral(var) && newlb - lb > 0.5) || (force && SCIPisGT(scip, newlb, lb)) )
1639  force = TRUE;
1640  else
1641  force = FALSE;
1642 
1643  /* try to tighten the lower bound */
1644  if( global )
1645  {
1646  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, newlb, force, &infeasible, &tightened) );
1647  }
1648  else
1649  {
1650  inferinfo = getInferInfo(boundtype == SCIP_BOUNDTYPE_LOWER ? varGetLbIndex(propdata, vbdvar) : varGetUbIndex(propdata, vbdvar), boundtype);
1651 
1652  SCIP_CALL( SCIPinferVarLbProp(scip, var, newlb, prop, inferInfoToInt(inferinfo), force, &infeasible, &tightened) );
1653  }
1654 
1655  if( infeasible )
1656  {
1657  /* the infeasible results comes from the fact that the new lower bound lies above the current upper bound */
1658  assert(SCIPisGT(scip, newlb, SCIPvarGetUbLocal(var)));
1659  assert(!global || SCIPisGT(scip, newlb, SCIPvarGetUbGlobal(var)));
1660 
1661  SCIPdebugMsg(scip, "tightening%s lower bound of variable <%s> to %g due the %s bound of variable <%s> led to infeasibility\n",
1662  (global ? " global" : ""), SCIPvarGetName(var), newlb, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
1663 
1664  if( global )
1665  {
1666  /* cutoff the root node */
1667  SCIP_CALL( SCIPcutoffNode(scip, SCIPgetRootNode(scip)) );
1668  }
1669  else
1670  {
1671  /* analyzes a infeasibility via conflict analysis */
1672  SCIP_CALL( analyzeConflictLowerbound(scip, propdata, var, newlb, vbdvar, boundtype, coef, constant, canwide) );
1673  }
1674  *result = SCIP_CUTOFF;
1675  }
1676  else if( tightened )
1677  {
1678  SCIPdebugMsg(scip, "tightened%s lower bound of variable <%s> to %g due the %s bound of variable <%s>\n",
1679  (global ? " global" : ""), SCIPvarGetName(var), newlb, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
1680  (*nchgbds)++;
1681  }
1682 
1683  return SCIP_OKAY;
1684 }
1685 
1686 /* tries to tighten the (global) upper bound of the given variable to the given new bound */
1687 static
1689  SCIP* scip, /**< SCIP data structure */
1690  SCIP_PROP* prop, /**< vbounds propagator */
1691  SCIP_PROPDATA* propdata, /**< propagator data */
1692  SCIP_VAR* var, /**< variable whose upper bound should be tightened */
1693  SCIP_Real newub, /**< new upper bound of the variable */
1694  SCIP_Bool global, /**< is the bound globally valid? */
1695  SCIP_VAR* vbdvar, /**< variable which is the reason for the upper bound change */
1696  SCIP_BOUNDTYPE boundtype, /**< bound which is the reason for the upper bound change */
1697  SCIP_Bool force, /**< should domain changes for continuous variables be forced */
1698  SCIP_Real coef, /**< coefficient in vbound constraint causing the propagation;
1699  * or 0.0 if propagation is caused by clique or implication */
1700  SCIP_Real constant, /**< constant in vbound constraint causing the propagation;
1701  * or 0.0 if propagation is caused by clique or implication */
1702  SCIP_Bool canwide, /**< can bound widening be used (for vbounds) or not (for inplications or cliques) */
1703  int* nchgbds, /**< pointer to increase, if a bound was changed */
1704  SCIP_RESULT* result /**< pointer to store the result of the propagation */
1705  )
1706 {
1707  INFERINFO inferinfo;
1708  SCIP_Real ub;
1709  SCIP_Bool tightened;
1710  SCIP_Bool infeasible;
1711 
1712  assert(scip != NULL);
1713  assert(prop != NULL);
1714  assert(propdata != NULL);
1715  assert(var != NULL);
1716  assert(nchgbds != NULL);
1717  assert(result != NULL);
1718 
1719  ub = SCIPvarGetUbLocal(var);
1720 
1721  /* check that the new upper bound is better */
1722  if( (SCIPvarIsIntegral(var) && ub - newub > 0.5) || (force && SCIPisLT(scip, newub, ub)) )
1723  force = TRUE;
1724  else
1725  force = FALSE;
1726 
1727  /* try to tighten the upper bound */
1728  if( global )
1729  {
1730  SCIP_CALL( SCIPtightenVarUbGlobal(scip, var, newub, force, &infeasible, &tightened) );
1731  }
1732  else
1733  {
1734  inferinfo = getInferInfo(boundtype == SCIP_BOUNDTYPE_LOWER ? varGetLbIndex(propdata, vbdvar) : varGetUbIndex(propdata, vbdvar), boundtype);
1735 
1736  SCIP_CALL( SCIPinferVarUbProp(scip, var, newub, prop, inferInfoToInt(inferinfo), force, &infeasible, &tightened) );
1737  }
1738 
1739  if( infeasible )
1740  {
1741  /* the infeasible results comes from the fact that the new upper bound lies below the current lower bound */
1742  assert(SCIPisLT(scip, newub, SCIPvarGetLbLocal(var)));
1743  assert(!global || SCIPisLT(scip, newub, SCIPvarGetLbGlobal(var)));
1744 
1745  SCIPdebugMsg(scip, "tightening%s upper bound of variable <%s> to %g due the %s bound of variable <%s> led to infeasibility\n",
1746  (global ? " global" : ""), SCIPvarGetName(var), newub, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
1747 
1748  if( global )
1749  {
1750  /* cutoff the root node */
1751  SCIP_CALL( SCIPcutoffNode(scip, SCIPgetRootNode(scip)) );
1752  }
1753  else
1754  {
1755  /* analyzes a infeasibility via conflict analysis */
1756  SCIP_CALL( analyzeConflictUpperbound(scip, propdata, var, newub, vbdvar, boundtype, coef, constant, canwide) );
1757  }
1758  *result = SCIP_CUTOFF;
1759  }
1760  else if( tightened )
1761  {
1762  SCIPdebugMsg(scip, "tightened%s upper bound of variable <%s> to %g due the %s bound of variable <%s>\n",
1763  (global ? " global" : ""), SCIPvarGetName(var), newub, getBoundtypeString(boundtype), SCIPvarGetName(vbdvar));
1764  (*nchgbds)++;
1765  }
1766 
1767  return SCIP_OKAY;
1768 }
1769 
1770 /** performs propagation of variables lower and upper bounds, implications, and cliques */
1771 static
1773  SCIP* scip, /**< SCIP data structure */
1774  SCIP_PROP* prop, /**< vbounds propagator */
1775  SCIP_Bool force, /**< should domain changes for continuous variables be forced */
1776  SCIP_RESULT* result /**< pointer to store the result of the propagation */
1777  )
1778 {
1779  SCIP_PROPDATA* propdata;
1780  SCIP_VAR** vars;
1781  SCIP_VAR* startvar;
1782  SCIP_BOUNDTYPE starttype;
1783  SCIP_Real startbound;
1784  SCIP_Real globalbound;
1785  int startpos;
1786  int topopos;
1787  int v;
1788  int n;
1789  int nchgbds;
1790  int nbounds;
1791  SCIP_Bool lower;
1792  SCIP_Bool global;
1793 
1794  assert(scip != NULL);
1795  assert(prop != NULL);
1796  assert(result != NULL);
1797 
1798  (*result) = SCIP_DIDNOTRUN;
1799 
1800  /* we do not run the propagator in presolving, because we want to avoid doing the expensive creation of the graph twice */
1801  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
1802  return SCIP_OKAY;
1803 
1804  propdata = SCIPpropGetData(prop);
1805  assert(propdata != NULL);
1806 
1807  /* initialize propagator data needed for propagation, if not done yet */
1808  if( !propdata->initialized )
1809  {
1810  SCIP_Bool infeasible;
1811 
1812  SCIP_CALL( initData(scip, prop, &infeasible) );
1813 
1814  if( infeasible )
1815  {
1816  *result = SCIP_CUTOFF;
1817  return SCIP_OKAY;
1818  }
1819  }
1820  assert(propdata->nbounds == 0 || propdata->propqueue != NULL);
1821 
1822  vars = propdata->vars;
1823  nbounds = propdata->nbounds;
1824 
1825  if( nbounds == 0 )
1826  return SCIP_OKAY;
1827 
1828  /* propagate all variables if we are in repropagation */
1829  if( SCIPinRepropagation(scip) )
1830  {
1831  SCIP_VAR* var;
1832  int idx;
1833 
1834  for( v = nbounds - 1; v >= 0; --v )
1835  {
1836  idx = propdata->topoorder[v];
1837  if( idx != -1 && !propdata->inqueue[v] )
1838  {
1839  var = vars[getVarIndex(idx)];
1840  lower = isIndexLowerbound(idx);
1841  if( !SCIPvarIsBinary(var) || (lower && SCIPvarGetLbLocal(var) > 0.5)
1842  || (!lower && SCIPvarGetUbLocal(var) < 0.5) )
1843  {
1844  SCIP_CALL( SCIPpqueueInsert(propdata->propqueue, (void*)(size_t)(v + 1)) ); /*lint !e571 !e776*/
1845  propdata->inqueue[v] = TRUE;
1846  }
1847  }
1848  }
1849  }
1850 
1851  /* return if no bound changes are in the priority queue (no changed bounds to handle since last propagation) */
1852  if( SCIPpqueueNElems(propdata->propqueue) == 0 )
1853  {
1854  (*result) = SCIP_DIDNOTFIND;
1855  return SCIP_OKAY;
1856  }
1857 
1858  nchgbds = 0;
1859 
1860  SCIPdebugMsg(scip, "varbound propagator: %d elements in the propagation queue\n", SCIPpqueueNElems(propdata->propqueue));
1861 
1862  /* get variable bound of highest priority from priority queue and try to deduce bound changes for other variables;
1863  * the priority queue is ordered w.r.t the topological sort of the varbound graph
1864  */
1865  while( SCIPpqueueNElems(propdata->propqueue) > 0 )
1866  {
1867  topopos = ((int)(size_t)SCIPpqueueRemove(propdata->propqueue)) - 1;
1868  assert(propdata->inqueue[topopos]);
1869  startpos = propdata->topoorder[topopos];
1870  assert(startpos >= 0);
1871  propdata->inqueue[topopos] = FALSE;
1872 
1873  startvar = vars[getVarIndex(startpos)];
1874  starttype = getBoundtype(startpos);
1875  lower = (starttype == SCIP_BOUNDTYPE_LOWER);
1876  startbound = ( lower ? SCIPvarGetLbLocal(startvar) : SCIPvarGetUbLocal(startvar) );
1877  globalbound = ( lower ? SCIPvarGetLbGlobal(startvar) : SCIPvarGetUbGlobal(startvar));
1878  global = SCIPisEQ(scip, startbound, globalbound);
1879 
1880  SCIPdebugMsg(scip, "propagate new %s bound of %g of variable <%s>:\n",
1881  getBoundtypeString(starttype), startbound, SCIPvarGetName(startvar));
1882 
1883  /* there should be neither implications nor cliques for non-binary variables */
1884  assert(SCIPvarIsBinary(startvar) || SCIPvarGetNImpls(startvar, lower) == 0);
1885  assert(SCIPvarIsBinary(startvar) || SCIPvarGetNCliques(startvar, lower) == 0);
1886 
1887  if( SCIPvarIsBinary(startvar) )
1888  {
1889  /* we only propagate binary variables if the lower bound changed to 1.0 or the upper bound changed to 0.0 */
1890  if( lower != (startbound > 0.5) )
1891  continue;
1892 
1893  /* propagate implications */
1894  if( propdata->useimplics )
1895  {
1896  int nimplvars;
1897 
1898  /* if the lower bound of the startvar was changed, it was fixed to 1.0, otherwise it was fixed to 0.0;
1899  * get all implications for this varfixing
1900  */
1901  nimplvars = SCIPvarGetNImpls(startvar, lower);
1902 
1903  /* if there are implications for the varfixing, propagate them */
1904  if( nimplvars > 0 )
1905  {
1906  SCIP_VAR** implvars;
1907  SCIP_BOUNDTYPE* impltypes;
1908  SCIP_Real* implbounds;
1909  int* implids;
1910 
1911  implvars = SCIPvarGetImplVars(startvar, lower);
1912  impltypes = SCIPvarGetImplTypes(startvar, lower);
1913  implbounds = SCIPvarGetImplBounds(startvar, lower);
1914  implids = SCIPvarGetImplIds(startvar, lower);
1915 
1916  for( n = 0; n < nimplvars; ++n )
1917  {
1918  /* implication is just a shortcut, so we do not propagate it now,
1919  * because we will propagate the longer way, anyway
1920  */
1921  if( implids[n] < 0 )
1922  continue;
1923 
1924  /* it might happen that implications point to inactive variables (normally, those are removed when a
1925  * variable becomes inactive, but in some cases, it cannot be done), we have to ignore these variables
1926  */
1927  if( !SCIPvarIsActive(implvars[n]) )
1928  continue;
1929 
1930  if( impltypes[n] == SCIP_BOUNDTYPE_LOWER )
1931  {
1932  SCIP_CALL( tightenVarLb(scip, prop, propdata, implvars[n], implbounds[n], global, startvar,
1933  starttype, force, 0.0, 0.0, FALSE, &nchgbds, result) );
1934  }
1935  else
1936  {
1937  SCIP_CALL( tightenVarUb(scip, prop, propdata, implvars[n], implbounds[n], global, startvar,
1938  starttype, force, 0.0, 0.0, FALSE, &nchgbds, result) );
1939  }
1940 
1941  if( *result == SCIP_CUTOFF )
1942  return SCIP_OKAY;
1943  }
1944  }
1945  }
1946 
1947  /* propagate cliques */
1948  if( propdata->usecliques )
1949  {
1950  int ncliques;
1951 
1952  /* if the lower bound of the startvar was changed, it was fixed to 1.0, otherwise it was fixed to 0.0;
1953  * get all cliques for this varfixing
1954  */
1955  ncliques = SCIPvarGetNCliques(startvar, lower);
1956 
1957  /* if there are cliques for the varfixing, propagate them */
1958  if( ncliques > 0 )
1959  {
1960  SCIP_CLIQUE** cliques;
1961  int j;
1962 
1963  cliques = SCIPvarGetCliques(startvar, lower);
1964 
1965  for( j = 0; j < ncliques; ++j )
1966  {
1967  SCIP_VAR** cliquevars;
1968  SCIP_Bool* cliquevals;
1969  int ncliquevars;
1970 
1971  cliquevars = SCIPcliqueGetVars(cliques[j]);
1972  cliquevals = SCIPcliqueGetValues(cliques[j]);
1973  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
1974 
1975  /* fix all variables except for the startvar to the value which is not in the clique */
1976  for( n = 0; n < ncliquevars; ++n )
1977  {
1978  if( cliquevars[n] == startvar )
1979  continue;
1980 
1981  /* try to tighten the bound */
1982  if( cliquevals[n] )
1983  {
1984  /* unnegated variable is in clique, so it has to be fixed to 0.0 */
1985  SCIP_CALL( tightenVarUb(scip, prop, propdata, cliquevars[n], 0.0, global, startvar, starttype,
1986  force, 0.0, 0.0, FALSE, &nchgbds, result) );
1987  }
1988  else
1989  {
1990  /* negated variable is in clique, so it has to be fixed to 1.0 */
1991  SCIP_CALL( tightenVarLb(scip, prop, propdata, cliquevars[n], 1.0, global, startvar, starttype,
1992  force, 0.0, 0.0, FALSE, &nchgbds, result) );
1993  }
1994  if( *result == SCIP_CUTOFF )
1995  return SCIP_OKAY;
1996  }
1997  }
1998  }
1999  }
2000  }
2001 
2002  /* propagate vbounds */
2003  if( propdata->usevbounds )
2004  {
2005  SCIP_VAR* boundedvar;
2006  SCIP_Real newbound;
2007  SCIP_Real coef;
2008  SCIP_Real constant;
2009 
2010  /* iterate over all vbounds for the given bound */
2011  for( n = 0; n < propdata->nvbounds[startpos]; ++n )
2012  {
2013  boundedvar = vars[getVarIndex(propdata->vboundboundedidx[startpos][n])];
2014  coef = propdata->vboundcoefs[startpos][n];
2015  constant = propdata->vboundconstants[startpos][n];
2016 
2017  /* compute new bound */
2018  newbound = startbound * coef + constant;
2019 
2020  /* try to tighten the bound */
2021  if( isIndexLowerbound(propdata->vboundboundedidx[startpos][n]) )
2022  {
2023  SCIP_CALL( tightenVarLb(scip, prop, propdata, boundedvar, newbound, global, startvar, starttype, force,
2024  coef, constant, TRUE, &nchgbds, result) );
2025  }
2026  else
2027  {
2028  SCIP_CALL( tightenVarUb(scip, prop, propdata, boundedvar, newbound, global, startvar, starttype, force,
2029  coef, constant, TRUE, &nchgbds, result) );
2030  }
2031 
2032  if( *result == SCIP_CUTOFF )
2033  return SCIP_OKAY;
2034  }
2035  }
2036  }
2037 
2038  SCIPdebugMsg(scip, "tightened %d variable bounds\n", nchgbds);
2039 
2040  /* set the result depending on whether bound changes were found or not */
2041  if( nchgbds > 0 )
2042  (*result) = SCIP_REDUCEDDOM;
2043  else
2044  (*result) = SCIP_DIDNOTFIND;
2045 
2046  return SCIP_OKAY;
2047 }
2048 
2049 /**@name Callback methods of propagator
2050  *
2051  * @{
2052  */
2053 
2054 /** copy method for propagator plugins (called when SCIP copies plugins) */
2055 static
2056 SCIP_DECL_PROPCOPY(propCopyVbounds)
2057 { /*lint --e{715}*/
2058  assert(scip != NULL);
2059  assert(prop != NULL);
2060  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2061 
2062  /* call inclusion method of propagator */
2064 
2065  return SCIP_OKAY;
2066 }
2067 
2068 /** destructor of propagator to free user data (called when SCIP is exiting) */
2069 static
2070 SCIP_DECL_PROPFREE(propFreeVbounds)
2071 { /*lint --e{715}*/
2072  SCIP_PROPDATA* propdata;
2074  /* free propagator data */
2075  propdata = SCIPpropGetData(prop);
2076 
2077  SCIPfreeBlockMemory(scip, &propdata);
2078  SCIPpropSetData(prop, NULL);
2079 
2080  return SCIP_OKAY;
2081 }
2082 
2083 /** presolving initialization method of propagator (called when presolving is about to begin) */
2084 static
2085 SCIP_DECL_PROPINITPRE(propInitpreVbounds)
2086 { /*lint --e{715}*/
2087  SCIP_PROPDATA* propdata;
2089  propdata = SCIPpropGetData(prop);
2090  assert(propdata != NULL);
2091 
2092  propdata->lastpresolncliques = 0;
2093 
2094  return SCIP_OKAY;
2095 }
2096 
2097 /** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
2098 static
2099 SCIP_DECL_PROPEXITSOL(propExitsolVbounds)
2100 { /*lint --e{715}*/
2101  SCIP_PROPDATA* propdata;
2102  int v;
2103 
2104  propdata = SCIPpropGetData(prop);
2105  assert(propdata != NULL);
2106 
2107  /* free data stored for propagation */
2108  if( propdata->initialized )
2109  {
2110  /* drop all variable events */
2111  SCIP_CALL( dropEvents(scip, propdata) );
2112 
2113  /* release all variables */
2114  for( v = 0; v < propdata->nbounds; ++v )
2115  {
2116  /* free vbound data */
2117  if( propdata->vboundsize[v] > 0 )
2118  {
2119  SCIPfreeMemoryArray(scip, &propdata->vboundboundedidx[v]);
2120  SCIPfreeMemoryArray(scip, &propdata->vboundcoefs[v]);
2121  SCIPfreeMemoryArray(scip, &propdata->vboundconstants[v]);
2122  }
2123  }
2124 
2125  /* free priority queue */
2126  SCIPpqueueFree(&propdata->propqueue);
2127 
2128  /* free arrays */
2129  SCIPfreeBlockMemoryArray(scip, &propdata->vboundsize, propdata->nbounds);
2130  SCIPfreeBlockMemoryArray(scip, &propdata->nvbounds, propdata->nbounds);
2131  SCIPfreeBlockMemoryArray(scip, &propdata->vboundconstants, propdata->nbounds);
2132  SCIPfreeBlockMemoryArray(scip, &propdata->vboundcoefs, propdata->nbounds);
2133  SCIPfreeBlockMemoryArray(scip, &propdata->vboundboundedidx, propdata->nbounds);
2134  SCIPfreeBlockMemoryArray(scip, &propdata->inqueue, propdata->nbounds);
2135  SCIPfreeBlockMemoryArray(scip, &propdata->topoorder, propdata->nbounds);
2136 
2137  /* free variable array and hashmap */
2138  SCIPhashmapFree(&propdata->varhashmap);
2139  SCIPfreeBlockMemoryArray(scip, &propdata->vars, propdata->nbounds / 2);
2140  }
2141 
2142  /* reset propagation data */
2143  resetPropdata(propdata);
2144 
2145  return SCIP_OKAY;
2146 }
2147 
2148 /** performs Tarjan's algorithm for strongly connected components in the implicitly given directed implication graph
2149  * from the given start index; each variable x is represented by two nodes lb(x) = 2*idx(x) and ub(x) = 2*idx(x)+1
2150  * where lb(x) means that the lower bound of x should be changed, i.e., that x is fixed to 1, and vice versa.
2151  *
2152  * The algorithm is an iterative version of Tarjans algorithm
2153  * (see https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm)
2154  * with some additional tweaks.
2155  * Each clique x_1 + ... + x_k <= 1 is represented by k(k-1) arcs (lb(x_i),ub(x_j)), j != i.
2156  * This quadratic number can blow up the running time of Tarjan's algorithm, which is linear in the number of
2157  * nodes and arcs of the graph. However, it suffices to consider only k of these arcs during the course of the algorithm.
2158  * To this end, when we first come to a node lb(x_i) of the clique, traverse all arcs (lb(x_i),ub(x_j)) for this particular i,
2159  * and store that we entered the clique via lb(x_i). Next time we come to any node lb(x_i') of the clique, we know
2160  * that the only arc pointing to an unvisited node is (lb(x_i'),ub(x_i)), all other edges can be disregarded.
2161  * After that, we can disregard the clique for the further search.
2162  * Additionally, we try to identify infeasible fixings for binary variables. Those can be given by a path
2163  * from x=1 to x=0 (or vice versa) or if x=0 (or 1) implies both y=0 and y=1.
2164  */
2165 static
2167  SCIP* scip, /**< SCIP data structure */
2168  int startnode, /**< node to start the depth-first-search */
2169  int* startindex, /**< next index to assign to a processed node */
2170  SCIP_Shortbool* nodeonstack, /**< array to store the whether a each node is on the stack */
2171  int* nodeindex, /**< array to store the dfs index for each node */
2172  int* nodelowlink, /**< array to store the lowlink for each node */
2173  SCIP_Shortbool* nodeinfeasible, /**< array to store whether the fixing of a node was detected to be infeasible */
2174  int* dfsstack, /**< array of size number of nodes to store the stack */
2175  int* predstackidx, /**< for each node on the stack: stack position of its predecessor in the Tarjan search */
2176  int* stacknextclique, /**< array of size number of nodes to store the next clique to be regarded in
2177  * the algorithm for all nodes on the stack */
2178  int* stacknextcliquevar, /**< array of size number of nodes to store the next variable in the next clique to be
2179  * regarded in the algorithm for all nodes on the stack */
2180  int* topoorder, /**< array with reverse (almost) topological ordering of the nodes */
2181  int* nordered, /**< number of ordered nodes (disconnected nodes are disregarded) */
2182  int* cliquefirstentry, /**< node from which a clique was entered for the first time; needed because when
2183  * entering the clique a second time, only the other bound corresponding to this node
2184  * remains to be processed */
2185  int* cliquecurrentexit, /**< for cliques which define an arc on the current path: target node of this arc */
2186  int* sccvars, /**< array with all nontrivial strongly connected components in the graph */
2187  int* sccstarts, /**< start indices of SCCs in sccvars array; one additional entry at the end
2188  * to give length of used part of sccvars array */
2189  int* nsccs, /**< pointer to store number of strongly connected components */
2190  int* infeasnodes, /**< sparse array with node indices of infeasible nodes */
2191  int* ninfeasnodes, /**< pointer to store the number of infeasible nodes */
2192  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
2193  )
2194 {
2195  SCIP_VAR** vars;
2196  SCIP_VAR* startvar;
2197  SCIP_Bool lower;
2198  int label = *startindex;
2199  int stacksize;
2200  int currstackidx;
2201  int curridx;
2202  int idx;
2203 
2204  assert(startnode >= 0);
2205  assert(startnode < 2 * (SCIPgetNVars(scip) - SCIPgetNContVars(scip)));
2206  assert(nodeindex != NULL);
2207  assert(nodeindex[startnode] == 0);
2208  assert(nodelowlink != NULL);
2209  assert(nodelowlink[startnode] == 0);
2210  assert(dfsstack != NULL);
2211  assert(stacknextclique != NULL);
2212  assert(infeasible != NULL);
2213 
2214  *infeasible = FALSE;
2215 
2216  vars = SCIPgetVars(scip);
2217 
2218  /* put start node on the stack */
2219  dfsstack[0] = startnode;
2220  stacknextclique[0] = 0;
2221  stacknextcliquevar[0] = 0;
2222  predstackidx[0] = -1;
2223  stacksize = 1;
2224  idx = -1;
2225  currstackidx = 0;
2226 #ifdef DEBUG_TARJAN
2227  SCIPdebugMsg(scip, "put %s(%s) on stack[%d]\n", indexGetBoundString(dfsstack[stacksize-1]),
2228  SCIPvarGetName(vars[getVarIndex(dfsstack[stacksize-1])]), stacksize-1);
2229 #endif
2230 
2231  /* we run until no more bounds indices are on the stack, i.e., no further nodes are connected to the startnode */
2232  while( stacksize > 0 )
2233  {
2234  SCIP_CLIQUE** cliques;
2235  int ncliques;
2236  SCIP_Bool found;
2237  int clqidx = -1;
2238  int j;
2239  int i;
2240 
2241  /* get next node from stack */
2242  curridx = dfsstack[currstackidx];
2243  assert(nodelowlink[curridx] <= nodeindex[curridx]);
2244 
2245  startvar = vars[getVarIndex(curridx)];
2246  lower = isIndexLowerbound(curridx);
2247 
2248  /* mark current node as on stack, assign index and lowlink */
2249  if( nodeindex[curridx] == 0 )
2250  {
2251  assert(!nodeonstack[curridx]);
2252  assert(stacknextclique[currstackidx] == 0);
2253  assert(stacknextcliquevar[currstackidx] == 0);
2254  nodeonstack[curridx] = 1;
2255  nodeindex[curridx] = label;
2256  nodelowlink[curridx] = label;
2257  ++label;
2258 
2259 #ifdef DEBUG_TARJAN
2260  {
2261  ncliques = SCIPvarGetNCliques(startvar, lower);
2262  cliques = SCIPvarGetCliques(startvar, lower);
2263 
2264  SCIPdebugMsg(scip, "variable %s(%s) has %d cliques\n", indexGetBoundString(curridx), SCIPvarGetName(startvar),
2265  ncliques);
2266  for( j = 0; j < ncliques; ++j )
2267  {
2268  SCIP_VAR** cliquevars;
2269  SCIP_Bool* cliquevals;
2270  int ncliquevars;
2271 
2272  clqidx = SCIPcliqueGetIndex(cliques[j]);
2273  cliquevars = SCIPcliqueGetVars(cliques[j]);
2274  cliquevals = SCIPcliqueGetValues(cliques[j]);
2275  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
2276 
2277  SCIPdebugMsg(scip, "clique %d [%d vars, stacksize: %d]...\n", clqidx, ncliquevars, stacksize);
2278  for( int v = 0; v < ncliquevars; ++v )
2279  SCIPdebugMsgPrint(scip, " %s<%s>", cliquevals[v] ? "" : "~", SCIPvarGetName(cliquevars[v]));
2280  SCIPdebugMsgPrint(scip, "\n");
2281  }
2282  }
2283 #endif
2284  }
2285  /* we just did a backtrack and still need to investigate some outgoing edges of the node;
2286  * however, we should have investigated some of the outgoing edges before
2287  */
2288  else
2289  {
2290  assert(stacknextclique[currstackidx] > 0 || stacknextcliquevar[currstackidx] > 0);
2291  assert(nodeindex[curridx] < label);
2292  }
2293  assert(stacknextclique[currstackidx] >= 0);
2294 
2295  ncliques = SCIPvarGetNCliques(startvar, lower);
2296  cliques = SCIPvarGetCliques(startvar, lower);
2297  found = FALSE;
2298 
2299  /* iterate over all not yet handled cliques and search for an unvisited node */
2300  for( j = stacknextclique[currstackidx]; j < ncliques; ++j )
2301  {
2302  SCIP_VAR** cliquevars;
2303  SCIP_Bool* cliquevals;
2304  int ncliquevars;
2305 
2306  clqidx = SCIPcliqueGetIndex(cliques[j]);
2307  cliquevars = SCIPcliqueGetVars(cliques[j]);
2308  cliquevals = SCIPcliqueGetValues(cliques[j]);
2309  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
2310 
2311  /* we did not look at this clique before from the current node, i.e., we did not backtrack now from another
2312  * node which was reached via this clique
2313  */
2314  if( stacknextcliquevar[currstackidx] == 0 )
2315  {
2316 #ifdef DEBUG_TARJAN
2317  SCIPdebugMsg(scip, "clique %d [%d vars, stacksize: %d]...\n", clqidx, ncliquevars, stacksize);
2318  for( int v = 0; v < ncliquevars; ++v )
2319  SCIPdebugMsgPrint(scip, " %s<%s>", cliquevals[v] ? "" : "~", SCIPvarGetName(cliquevars[v]));
2320  SCIPdebugMsgPrint(scip, "\n");
2321 #endif
2322  /* the clique was not entered before, remember that we first entered it from curridx
2323  * (add 1 to distinguish it from 0 initialization)
2324  */
2325  if( cliquefirstentry[clqidx] == 0 )
2326  {
2327  cliquefirstentry[clqidx] = curridx + 1;
2328  }
2329  else
2330  {
2331  int cliquefirstentryidx = (cliquefirstentry[clqidx] > 0 ? cliquefirstentry[clqidx] : -cliquefirstentry[clqidx]) - 1;
2332  int infeasnode = -1;
2333  assert(cliquefirstentryidx != curridx);
2334 
2335  /* The node by which we entered the clique the first time is still on the stack, so there is a
2336  * way from that node to the node by which we are entering the clique right now.
2337  * Since these two assignments together violate the clique and the second assignment is implied by the first,
2338  * the first one is infeasible
2339  */
2340  if( nodeonstack[cliquefirstentryidx] && !nodeinfeasible[cliquefirstentryidx] )
2341  {
2342  SCIPdebugMsg(scip, "infeasible assignment (1): %s(%s)\n", indexGetBoundString(cliquefirstentryidx),
2343  SCIPvarGetName(vars[getVarIndex(cliquefirstentryidx)]));
2344  infeasnode = cliquefirstentryidx;
2345  }
2346  /* the first entry point of the clique was also implied by the current startnode, so this node implies
2347  * two variables in the clique and is therefore infeasible
2348  */
2349  else if( nodeindex[cliquefirstentryidx] >= *startindex && !nodeinfeasible[startnode] )
2350  {
2351  SCIPdebugMsg(scip, "infeasible assignment (2): %s(%s)\n", indexGetBoundString(startnode),
2352  SCIPvarGetName(vars[getVarIndex(startnode)]));
2353  infeasnode = startnode;
2354  }
2355 
2356  /* we identified an infeasibility */
2357  if( infeasnode >= 0 )
2358  {
2359  /* both values are invalid for the variable, the whole problem is infeasible */
2360  if( nodeinfeasible[getOtherBoundIndex(infeasnode)] )
2361  {
2362  *infeasible = TRUE;
2363  return SCIP_OKAY;
2364  }
2365  infeasnodes[*ninfeasnodes] = infeasnode;
2366  nodeinfeasible[infeasnode] = TRUE;
2367  ++(*ninfeasnodes);
2368 
2369  /* the last node by which the clique was exited is not the negation of the current node and still on
2370  * the stack: update the lowlink of the current node
2371  */
2372  if( cliquecurrentexit[clqidx] > 0
2373  && curridx != getOtherBoundIndex(cliquecurrentexit[clqidx] - 1)
2374  && nodeonstack[cliquecurrentexit[clqidx] - 1]
2375  && nodeindex[cliquecurrentexit[clqidx] - 1] < nodelowlink[curridx] )
2376  {
2377  nodelowlink[curridx] = nodeindex[cliquecurrentexit[clqidx] - 1];
2378  }
2379  }
2380  /* clique is entered for the second time; there is only one edge left to investigate, namely the edge to
2381  * the negation of the first entry point
2382  */
2383  else if( cliquefirstentry[clqidx] > 0 )
2384  {
2385 #ifdef DEBUG_TARJAN
2386  SCIPdebugMsg(scip, "entering clique %d a second time\n", clqidx);
2387 #endif
2388  idx = getOtherBoundIndex(cliquefirstentry[clqidx] - 1);
2389 
2390  /* node was not investigated yet, we found the next node to process */
2391  if( nodeindex[idx] == 0 )
2392  found = TRUE;
2393  /* update lowlink if the node is on the stack */
2394  else if( nodeonstack[idx] && nodeindex[idx] < nodelowlink[curridx] )
2395  nodelowlink[curridx] = nodeindex[idx];
2396 
2397  /* cliquefirstentry[clqidx] < 0 means that we entered the clique at least two times already */
2398  cliquefirstentry[clqidx] = -cliquefirstentry[clqidx];
2399  }
2400  else
2401  {
2402 #ifdef DEBUG_TARJAN
2403  SCIPdebugMsg(scip, "skip clique %d: visited more than twice already!\n", clqidx);
2404 #endif
2405  }
2406  stacknextcliquevar[currstackidx] = ncliquevars;
2407  }
2408  }
2409 
2410  /* iterate over variables in the clique; start where we stopped last time */
2411  for( i = stacknextcliquevar[currstackidx]; i < ncliquevars; ++i )
2412  {
2413  if( cliquevars[i] == startvar )
2414  continue;
2415 
2416  if( !SCIPvarIsActive(cliquevars[i]) )
2417  continue;
2418 
2419  if( cliquevals[i] )
2420  idx = getUbIndex(SCIPvarGetProbindex(cliquevars[i]));
2421  else
2422  idx = getLbIndex(SCIPvarGetProbindex(cliquevars[i]));
2423  assert(idx >= 0);
2424 
2425  /* break when the first unvisited node is reached */
2426  if( nodeindex[idx] == 0 )
2427  {
2428  assert(!nodeonstack[idx]);
2429  stacknextcliquevar[currstackidx] = i + 1;
2430  found = TRUE;
2431  break;
2432  }
2433  else if( nodeonstack[idx] && nodeindex[idx] < nodelowlink[curridx] )
2434  {
2435  nodelowlink[curridx] = nodeindex[idx];
2436  }
2437  }
2438  if( found )
2439  {
2440  if( stacknextcliquevar[currstackidx] < ncliquevars )
2441  stacknextclique[currstackidx] = j;
2442  else
2443  {
2444  stacknextclique[currstackidx] = j + 1;
2445  stacknextcliquevar[currstackidx] = 0;
2446  }
2447  break;
2448  }
2449  else
2450  {
2451  assert(i == ncliquevars);
2452  stacknextclique[currstackidx] = j + 1;
2453  stacknextcliquevar[currstackidx] = 0;
2454  }
2455  }
2456  assert(found || j == ncliques);
2457  assert(found || stacknextclique[currstackidx] == ncliques);
2458 
2459  /* we stopped because we found an unhandled node and not because we reached the end of the list */
2460  if( found )
2461  {
2462  int otheridx = getOtherBoundIndex(idx);
2463  int infeasnode = -1;
2464 
2465  assert(idx >= 0);
2466  assert(!nodeonstack[idx]);
2467  assert(j < ncliques);
2468  assert(clqidx >= 0);
2469 
2470  /* the negated node corresponding to the next node is already on the stack -> the negated assignment is
2471  * infeasible
2472  */
2473  if( nodeonstack[otheridx] && !nodeinfeasible[otheridx] )
2474  {
2475  SCIPdebugMsg(scip, "infeasible assignment (3): %s(%s)\n", indexGetBoundString(otheridx),
2476  SCIPvarGetName(vars[getVarIndex(otheridx)]));
2477  infeasnode = otheridx;
2478  }
2479  /* the negated node corresponding to the next node was reached from the same startnode -> the startnode is
2480  * infeasible
2481  */
2482  else if( nodeindex[otheridx] >= *startindex && !nodeinfeasible[startnode] )
2483  {
2484  SCIPdebugMsg(scip, "infeasible assignment (4): %s(%s)\n", indexGetBoundString(startnode),
2485  SCIPvarGetName(vars[getVarIndex(startnode)]));
2486  infeasnode = startnode;
2487  }
2488  /* treat infeasible case */
2489  if( infeasnode >= 0 )
2490  {
2491  if( nodeinfeasible[getOtherBoundIndex(infeasnode)] )
2492  {
2493  *infeasible = TRUE;
2494  return SCIP_OKAY;
2495  }
2496  infeasnodes[*ninfeasnodes] = infeasnode;
2497  nodeinfeasible[infeasnode] = TRUE;
2498  ++(*ninfeasnodes);
2499  }
2500 
2501  SCIPdebugMsg(scip, "clique: %s(%s) -> %s(%s)\n", getBoundString(lower), SCIPvarGetName(startvar),
2502  indexGetBoundString(idx), SCIPvarGetName(vars[getVarIndex(idx)]));
2503 
2504  /* put the adjacent node onto the stack */
2505  dfsstack[stacksize] = idx;
2506  stacknextclique[stacksize] = 0;
2507  stacknextcliquevar[stacksize] = 0;
2508  cliquecurrentexit[clqidx] = idx + 1;
2509  predstackidx[stacksize] = currstackidx;
2510  currstackidx = stacksize;
2511  stacksize++;
2512  assert(stacksize <= 2 * (SCIPgetNVars(scip) - SCIPgetNContVars(scip)));
2513 
2514 #ifdef DEBUG_TARJAN
2515  SCIPdebugMsg(scip, "put %s(%s) on stack[%d]\n", indexGetBoundString(dfsstack[stacksize-1]), SCIPvarGetName(vars[getVarIndex(dfsstack[stacksize-1])]), stacksize-1);
2516 #endif
2517  /* restart while loop, get next index from stack */
2518  continue;
2519  }
2520  assert(stacknextclique[currstackidx] == ncliques);
2521 
2522  /* no node with a smaller index can be reached from this node -> it is the root of a SCC,
2523  * consisting of all nodes above it on the stack, including the node itself
2524  */
2525  if( nodelowlink[curridx] == nodeindex[curridx] )
2526  {
2527  /* we are only interested in SCCs with more than one node */
2528  if( dfsstack[stacksize-1] != curridx )
2529  {
2530  int sccvarspos = sccstarts[*nsccs];
2531 
2532  SCIPdebugMsg(scip, "SCC:");
2533 
2534  /* store the SCC in sccvars */
2535  do{
2536  stacksize--;
2537  idx = dfsstack[stacksize];
2538  nodeonstack[idx] = 0;
2539  sccvars[sccvarspos] = idx;
2540  ++sccvarspos;
2541  SCIPdebugMsgPrint(scip, " %s(%s)", indexGetBoundString(idx), SCIPvarGetName(vars[getVarIndex(idx)]));
2542 #ifdef DEBUG_TARJAN
2543  SCIPdebugMsg(scip, "remove %s(%s) from stack[%d]\n", indexGetBoundString(dfsstack[stacksize]), SCIPvarGetName(vars[getVarIndex(dfsstack[stacksize])]), stacksize);
2544 #endif
2545 
2546  }
2547  while( idx != curridx );
2548  SCIPdebugMsgPrint(scip, "\n");
2549  ++(*nsccs);
2550  sccstarts[*nsccs] = sccvarspos;
2551  }
2552  /* trivial SCC: remove the single node from the stack, but don't store it as a SCC */
2553  else
2554  {
2555  stacksize--;
2556 #ifdef DEBUG_TARJAN
2557  SCIPdebugMsg(scip, "remove %s(%s) from stack[%d]\n", indexGetBoundString(dfsstack[stacksize]), SCIPvarGetName(vars[getVarIndex(dfsstack[stacksize])]), stacksize);
2558 #endif
2559  idx = dfsstack[stacksize];
2560  nodeonstack[idx] = 0;
2561  assert(nodeindex[idx] > 0);
2562  }
2563  }
2564  /* in a pure dfs, the node would now leave the stack, add it to the array of nodes in reverse topological order */
2565  if( topoorder != NULL && (stacksize > 0 || label > *startindex + 1) )
2566  {
2567  topoorder[*nordered] = curridx;
2568  ++(*nordered);
2569  }
2570 
2571  /* the current node was handled, backtrack */
2572  if( stacksize > 0 )
2573  {
2574  idx = dfsstack[predstackidx[currstackidx]];
2575  nodelowlink[idx] = MIN(nodelowlink[idx], nodelowlink[curridx]);
2576  currstackidx = predstackidx[currstackidx];
2577  }
2578  }
2579 
2580  *startindex = label;
2581 
2582  return SCIP_OKAY;
2583 }
2584 
2585 
2586 /** apply fixings and aggregations found by the clique graph analysis */
2587 static
2589  SCIP* scip, /**< SCIP data structure */
2590  SCIP_VAR** vars, /**< array of active variables */
2591  int* infeasnodes, /**< sparse array with node indices of infeasible nodes */
2592  int ninfeasnodes, /**< pointer to store the number of infeasible nodes */
2593  SCIP_Shortbool* nodeinfeasible, /**< array to store whether the fixing of a node was detected to be infeasible */
2594  int* sccvars, /**< array with all nontrivial strongly connected components in the graph */
2595  int* sccstarts, /**< start indices of SCCs in sccvars array; one additional entry at the end
2596  * to give length of used part of sccvars array */
2597  int nsccs, /**< pointer to store number of strongly connected components */
2598  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
2599  int* nfixedvars, /**< pointer to number of fixed variables, increment when fixing another one */
2600  int* naggrvars, /**< pointer to number of aggregated variables, increment when aggregating another one */
2601  SCIP_RESULT* result /**< pointer to store result of the call */
2602  )
2603 {
2604  int i = 0;
2605 
2606  assert(scip != NULL);
2607  assert(vars != NULL);
2608  assert(infeasible != NULL);
2609 
2610  /* for all infeasible node: fix variable to the other bound */
2611  if( !(*infeasible) && ninfeasnodes > 0 )
2612  {
2613  for( i = 0; i < ninfeasnodes; ++i )
2614  {
2615  SCIP_VAR* var = vars[getVarIndex(infeasnodes[i])];
2616  SCIP_Bool lower = isIndexLowerbound(infeasnodes[i]);
2617  SCIP_Bool fixed;
2618 
2619  assert(nodeinfeasible[infeasnodes[i]]);
2620  nodeinfeasible[infeasnodes[i]] = FALSE;
2621 
2622  SCIP_CALL( SCIPfixVar(scip, var, lower ? 0.0 : 1.0, infeasible, &fixed) );
2623 
2624  SCIPdebugMsg(scip, "fix <%s>[%d] to %g: inf=%d, fixed=%d\n",
2625  SCIPvarGetName(var), infeasnodes[i], lower ? 0.0 : 1.0, *infeasible, fixed);
2626 
2627  /* fixing was infeasible */
2628  if( *infeasible )
2629  break;
2630 
2631  /* increase fixing counter and update result pointer */
2632  if( fixed )
2633  {
2634  *result = SCIP_SUCCESS;
2635  ++(*nfixedvars);
2636  }
2637  }
2638  }
2639  assert((*infeasible) || i == ninfeasnodes);
2640 
2641  /* clear clean buffer array (if we did not enter the block above or stopped early due to an infeasibility) */
2642  for( ; i < ninfeasnodes; ++i )
2643  {
2644  assert(nodeinfeasible[infeasnodes[i]]);
2645  nodeinfeasible[infeasnodes[i]] = FALSE;
2646  }
2647 
2648  if( !(*infeasible) && nsccs > 0 )
2649  {
2650  /* for each strongly connected component: aggregate all variables to the first one */
2651  for( i = 0; i < nsccs; ++i )
2652  {
2653  SCIP_VAR* startvar;
2654  SCIP_Bool lower;
2655  SCIP_Bool aggregated;
2656  SCIP_Bool redundant;
2657  int v;
2658 
2659  assert(sccstarts[i] < sccstarts[i+1] - 1);
2660 
2661  /* get variable and boundtype for first node of the SCC */
2662  startvar = vars[getVarIndex(sccvars[sccstarts[i]])];
2663  lower = isIndexLowerbound(sccvars[sccstarts[i]]);
2664 
2665  for( v = sccstarts[i] + 1; v < sccstarts[i+1]; ++v )
2666  {
2667  /* aggregate variables: if both nodes represent the same bound, we have x=1 <=> y=1,
2668  * and thus aggregate x - y = 0; if both represent different bounds we have
2669  * x=1 <=> y=0, so we aggregate x + y = 1
2670  */
2671  SCIP_CALL( SCIPaggregateVars(scip, startvar, vars[getVarIndex(sccvars[v])], 1.0,
2672  lower == isIndexLowerbound(sccvars[v]) ? -1.0 : 1.0,
2673  lower == isIndexLowerbound(sccvars[v]) ? 0.0 : 1.0,
2674  infeasible, &redundant, &aggregated) );
2675 
2676  SCIPdebugMsg(scip, "aggregate <%s> + %g <%s> = %g: inf=%d, red=%d, aggr=%d\n",
2677  SCIPvarGetName(startvar), lower == isIndexLowerbound(sccvars[v]) ? -1.0 : 1.0,
2678  SCIPvarGetName(vars[getVarIndex(sccvars[v])]), lower == isIndexLowerbound(sccvars[v]) ? 0.0 : 1.0,
2679  *infeasible, redundant, aggregated);
2680 
2681  /* aggregation was infeasible */
2682  if( *infeasible )
2683  break;
2684 
2685  /* increase aggregation counter and update result pointer */
2686  if( aggregated )
2687  {
2688  ++(*naggrvars);
2689  *result = SCIP_SUCCESS;
2690  }
2691  }
2692  }
2693  }
2694 
2695  return SCIP_OKAY;
2696 }
2697 
2698 
2699 
2700 /** presolving method of propagator: search for strongly connected components in the implication graph and
2701  * aggregate all variables within a component; additionally, identifies infeasible variable assignments
2702  * as a side product if a path from x=1 to x=0 (or vice versa) is found or x=1 implies both y=0 and y=1
2703  * The identification of such assignments depends on the order in which variable bounds are processed;
2704  * therefore, we are doing a second run with the bounds processed in (almost) topological order.
2705  */
2706 static
2707 SCIP_DECL_PROPPRESOL(propPresolVbounds)
2708 { /*lint --e{715}*/
2709  SCIP_PROPDATA* propdata;
2710  SCIP_VAR** tmpvars;
2711  SCIP_VAR** vars;
2712  int* dfsstack;
2713  int* stacknextclique;
2714  int* stacknextcliquevar;
2715  int* nodeindex;
2716  int* nodelowlink;
2717  int* predstackidx;
2718  int* cliquefirstentry;
2719  int* cliquecurrentexit;
2720  int* topoorder;
2721  int* sccvars;
2722  int* sccstarts;
2723  int* infeasnodes;
2724  SCIP_Shortbool* nodeonstack;
2725  SCIP_Shortbool* nodeinfeasible;
2726  int ninfeasnodes;
2727  int nsccs;
2728  int nbounds;
2729  int nbinvars;
2730  int ncliques;
2731  int startindex = 1;
2732  int nordered = 0;
2733  int i;
2734  SCIP_Bool infeasible = FALSE;
2735 
2736  assert(scip != NULL);
2737 
2738  propdata = SCIPpropGetData(prop);
2739  assert(propdata != NULL);
2740 
2741  ncliques = SCIPgetNCliques(scip);
2742 
2743  *result = SCIP_DIDNOTRUN;
2744 
2745  if( ncliques < 2 )
2746  return SCIP_OKAY;
2747 
2748  /* too many cliques for medium presolving */
2749  if( presoltiming == SCIP_PRESOLTIMING_MEDIUM && ncliques > propdata->maxcliquesmedium * SCIPgetNBinVars(scip) )
2750  return SCIP_OKAY;
2751 
2752  /* too many cliques for medium presolving */
2753  if( ncliques > propdata->maxcliquesexhaustive * SCIPgetNBinVars(scip) )
2754  return SCIP_OKAY;
2755 
2756  /* only run if enough new cliques were created since the last successful call */
2757  if( SCIPgetNCliquesCreated(scip) < (1.0 + propdata->minnewcliques) * propdata->lastpresolncliques )
2758  return SCIP_OKAY;
2759 
2760  *result = SCIP_DIDNOTFIND;
2761 
2762  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
2763  nbounds = 2 * nbinvars;
2764 
2765  /* cleanup cliques, stop if this proved infeasibility already */
2766  SCIP_CALL( SCIPcleanupCliques(scip, &infeasible) );
2767 
2768  if( infeasible )
2769  {
2770  *result = SCIP_CUTOFF;
2771  return SCIP_OKAY;
2772  }
2773 
2774  tmpvars = SCIPgetVars(scip);
2775 
2776  /* duplicate variable array; needed to get the fixings right later */
2777  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, tmpvars, nbinvars) );
2778 
2779  SCIP_CALL( SCIPallocBufferArray(scip, &dfsstack, nbounds) );
2780  SCIP_CALL( SCIPallocBufferArray(scip, &stacknextclique, nbounds) );
2781  SCIP_CALL( SCIPallocBufferArray(scip, &stacknextcliquevar, nbounds) );
2782  SCIP_CALL( SCIPallocBufferArray(scip, &predstackidx, nbounds) );
2783  SCIP_CALL( SCIPallocBufferArray(scip, &topoorder, nbounds) );
2784  SCIP_CALL( SCIPallocBufferArray(scip, &sccvars, nbounds) );
2785  SCIP_CALL( SCIPallocBufferArray(scip, &sccstarts, nbinvars + 1) );
2786  SCIP_CALL( SCIPallocBufferArray(scip, &infeasnodes, nbounds) );
2787  SCIP_CALL( SCIPallocClearBufferArray(scip, &nodeindex, nbounds) );
2788  SCIP_CALL( SCIPallocClearBufferArray(scip, &nodelowlink, nbounds) );
2789  SCIP_CALL( SCIPallocClearBufferArray(scip, &cliquefirstentry, ncliques) );
2790  SCIP_CALL( SCIPallocClearBufferArray(scip, &cliquecurrentexit, ncliques) );
2791  SCIP_CALL( SCIPallocClearBufferArray(scip, &nodeonstack, nbounds) );
2792  SCIP_CALL( SCIPallocCleanBufferArray(scip, &nodeinfeasible, nbounds) );
2793  sccstarts[0] = 0;
2794  nsccs = 0;
2795  ninfeasnodes = 0;
2796 
2797  /* while there are unvisited nodes, run Tarjan's algorithm starting from one of these nodes */
2798  for( i = 0; i < nbounds && !infeasible; ++i )
2799  {
2800  if( nodeindex[i] == 0 )
2801  {
2802  SCIP_CALL( tarjan(scip, i, &startindex, nodeonstack, nodeindex, nodelowlink, nodeinfeasible,
2803  dfsstack, predstackidx, stacknextclique, stacknextcliquevar, topoorder, &nordered,
2804  cliquefirstentry, cliquecurrentexit, sccvars, sccstarts, &nsccs,
2805  infeasnodes, &ninfeasnodes, &infeasible) );
2806  }
2807  }
2808  assert(nordered <= nbounds);
2809 
2810  /* aggregate all variables within a SCC and fix all variables for which one bounds was proven infeasible */
2811  if( ninfeasnodes > 0 || nsccs > 0 )
2812  {
2813  SCIP_CALL( applyFixingsAndAggregations(scip, vars, infeasnodes, ninfeasnodes, nodeinfeasible,
2814  sccvars, sccstarts, nsccs, &infeasible, nfixedvars, naggrvars, result) );
2815  }
2816 
2817  /* second round, now with topological order! */
2818  if( !infeasible && nordered > 0 )
2819  {
2820  SCIP_VAR** vars2;
2821  int nbounds2;
2822 
2823  assert(nordered > 1);
2824 
2825  /* we already fixed or aggregated some variables in the first run, so we better clean up the cliques */
2826  if( *result == SCIP_SUCCESS )
2827  {
2828  SCIP_CALL( SCIPcleanupCliques(scip, &infeasible) );
2829 
2830  if( infeasible )
2831  goto TERMINATE;
2832  }
2833 
2834  nbounds2 = 2 * (SCIPgetNVars(scip) - SCIPgetNContVars(scip));
2835  ncliques = SCIPgetNCliques(scip);
2836 
2837  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars2, tmpvars, nbounds2/2) );
2838 
2839  /* clear arrays that should be initialized to 0 */
2840  BMSclearMemoryArray(nodeonstack, nbounds2);
2841  BMSclearMemoryArray(nodeindex, nbounds2);
2842  BMSclearMemoryArray(nodelowlink, nbounds2);
2843  BMSclearMemoryArray(cliquefirstentry, ncliques);
2844  BMSclearMemoryArray(cliquecurrentexit, ncliques);
2845  sccstarts[0] = 0;
2846  nsccs = 0;
2847  ninfeasnodes = 0;
2848  startindex = 1;
2849 
2850  /* while there are unvisited nodes, run Tarjan's algorithm starting from one of these nodes */
2851  for( i = nordered - 1; i >= 0 && !infeasible; --i )
2852  {
2853  int varindex;
2854  int startpos;
2855  assert(topoorder[i] < nbounds);
2856 
2857  /* variable of next node in topological order */
2858  varindex = SCIPvarGetProbindex(vars[getVarIndex(topoorder[i])]);
2859 
2860  /* variable was not fixed after the first run */
2861  if( varindex >= 0 )
2862  {
2863  startpos = isIndexLowerbound(topoorder[i]) ? getLbIndex(varindex) : getUbIndex(varindex);
2864  if( nodeindex[startpos] == 0 )
2865  {
2866  SCIP_CALL( tarjan(scip, startpos, &startindex, nodeonstack, nodeindex, nodelowlink, nodeinfeasible,
2867  dfsstack, predstackidx, stacknextclique, stacknextcliquevar, NULL, NULL,
2868  cliquefirstentry, cliquecurrentexit, sccvars, sccstarts, &nsccs,
2869  infeasnodes, &ninfeasnodes, &infeasible) );
2870  }
2871  }
2872  }
2873 
2874  /* aggregate all variables within a SCC and fix all variables for which one bounds was proven infeasible */
2875  if( ninfeasnodes > 0 || nsccs > 0 )
2876  {
2877  SCIP_CALL( applyFixingsAndAggregations(scip, vars2, infeasnodes, ninfeasnodes, nodeinfeasible,
2878  sccvars, sccstarts, nsccs, &infeasible, nfixedvars, naggrvars, result) );
2879  }
2880 
2881  SCIPfreeBufferArray(scip, &vars2);
2882  }
2883 
2884  TERMINATE:
2885  if( infeasible )
2886  *result = SCIP_CUTOFF;
2887 #ifndef NDEBUG
2888  for( i = 0; i < nbounds; ++i )
2889  {
2890  assert(nodeinfeasible[i] == FALSE);
2891  }
2892 #endif
2893  SCIPfreeCleanBufferArray(scip, &nodeinfeasible);
2894 
2895  SCIPfreeBufferArray(scip, &cliquecurrentexit);
2896  SCIPfreeBufferArray(scip, &cliquefirstentry);
2897 
2898  SCIPfreeBufferArray(scip, &nodelowlink);
2899  SCIPfreeBufferArray(scip, &nodeindex);
2900  SCIPfreeBufferArray(scip, &nodeonstack);
2901  SCIPfreeBufferArray(scip, &infeasnodes);
2902  SCIPfreeBufferArray(scip, &sccstarts);
2903  SCIPfreeBufferArray(scip, &sccvars);
2904  SCIPfreeBufferArray(scip, &topoorder);
2905  SCIPfreeBufferArray(scip, &predstackidx);
2906  SCIPfreeBufferArray(scip, &stacknextcliquevar);
2907  SCIPfreeBufferArray(scip, &stacknextclique);
2908  SCIPfreeBufferArray(scip, &dfsstack);
2909  SCIPfreeBufferArray(scip, &vars);
2910 
2911  propdata->lastpresolncliques = SCIPgetNCliquesCreated(scip);
2912 
2913  return SCIP_OKAY;
2914 }
2915 
2916 
2917 
2918 /** execution method of propagator */
2919 static
2920 SCIP_DECL_PROPEXEC(propExecVbounds)
2921 { /*lint --e{715}*/
2922 
2923  *result = SCIP_DIDNOTRUN;
2924 
2925  /* perform variable lower and upper bound propagation */
2926  SCIP_CALL( propagateVbounds(scip, prop, FALSE, result) );
2927 
2928  assert((*result) == SCIP_CUTOFF || (*result) == SCIP_DIDNOTRUN
2929  || (*result) == SCIP_DIDNOTFIND || (*result) == SCIP_REDUCEDDOM);
2930 
2931  return SCIP_OKAY;
2932 }
2933 
2934 /** propagation conflict resolving method of propagator */
2935 static
2936 SCIP_DECL_PROPRESPROP(propRespropVbounds)
2937 { /*lint --e{715}*/
2938  SCIP_PROPDATA* propdata;
2939  SCIP_VAR** vars;
2940  SCIP_VAR* startvar;
2941  SCIP_BOUNDTYPE starttype;
2942  int pos;
2943 
2944  propdata = SCIPpropGetData(prop);
2945  assert(propdata != NULL);
2946 
2947  starttype = inferInfoGetBoundtype(intToInferInfo(inferinfo));
2948  pos = inferInfoGetPos(intToInferInfo(inferinfo));
2949  assert(pos >= 0);
2950  assert(pos < propdata->nbounds);
2951 
2952  vars = propdata->vars;
2953  assert(vars != NULL);
2954  startvar = vars[getVarIndex(pos)];
2955  assert(startvar != NULL);
2956  assert(startvar != infervar);
2957 
2958  SCIPdebugMsg(scip, "explain %s bound change of variable <%s>\n",
2959  getBoundtypeString(boundtype), SCIPvarGetName(infervar));
2960 
2961  if( !SCIPvarIsBinary(startvar) && propdata->usebdwidening )
2962  {
2963  int* vboundboundedidx;
2964  SCIP_Real constant;
2965  SCIP_Real coef;
2966  int inferidx;
2967  int nvbounds;
2968  int b;
2969 
2970  nvbounds = propdata->nvbounds[pos];
2971  vboundboundedidx = propdata->vboundboundedidx[pos];
2972 
2973  inferidx = boundtype == SCIP_BOUNDTYPE_LOWER ? varGetLbIndex(propdata, infervar) : varGetUbIndex(propdata, infervar);
2974  assert(inferidx >= 0);
2975 
2976  for( b = 0; b < nvbounds; ++b )
2977  {
2978  if( vboundboundedidx[b] == inferidx )
2979  break;
2980  }
2981  assert(b < nvbounds);
2982 
2983  coef = propdata->vboundcoefs[pos][b];
2984  constant = propdata->vboundconstants[pos][b];
2985  assert(!SCIPisZero(scip, coef));
2986 
2987  /* compute the relaxed bound which is sufficient to propagate the inference bound of given variable */
2988  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2989  relaxedbd = computeRelaxedLowerbound(scip, infervar, relaxedbd, coef, constant);
2990  else
2991  relaxedbd = computeRelaxedUpperbound(scip, infervar, relaxedbd, coef, constant);
2992 
2993  /* try to relax variable bound variable */
2994  SCIP_CALL( relaxVbdvar(scip, startvar, starttype, bdchgidx, relaxedbd) );
2995  }
2996  else
2997  {
2998  SCIP_CALL( resolvePropagation(scip, propdata, startvar, starttype, bdchgidx) );
2999  }
3000 
3001  (*result) = SCIP_SUCCESS;
3002 
3003  return SCIP_OKAY;
3004 }
3005 
3006 /**@} */
3007 
3008 /**@name Callback methods of event handler
3009  *
3010  * @{
3011  */
3012 
3013 /** execution method of bound change event handler */
3014 static
3015 SCIP_DECL_EVENTEXEC(eventExecVbound)
3016 { /*lint --e{715}*/
3017  SCIP_PROPDATA* propdata;
3018  int idx;
3019 
3020  assert(eventhdlr != NULL);
3021 
3022  propdata = (SCIP_PROPDATA*)SCIPeventhdlrGetData(eventhdlr);
3023  assert(propdata != NULL);
3024 
3025  idx = (int) (size_t) eventdata;
3026  assert(idx >= 0);
3027 
3028  SCIPdebugMsg(scip, "eventexec (type=%llu): try to add sort index %d: %s(%s) to priority queue\n", SCIPeventGetType(event),
3029  idx, indexGetBoundString(propdata->topoorder[idx]),
3030  SCIPvarGetName(propdata->vars[getVarIndex(propdata->topoorder[idx])]));
3031 
3033  && SCIPeventGetNewbound(event) > 0.5 )
3034  return SCIP_OKAY;
3035 
3037  && SCIPeventGetNewbound(event) < 0.5 )
3038  return SCIP_OKAY;
3039 
3040  assert(getVarIndex(propdata->topoorder[idx]) < SCIPgetNVars(scip));
3041  assert(SCIPvarGetType(propdata->vars[getVarIndex(propdata->topoorder[idx])]) != SCIP_VARTYPE_BINARY
3042  || (isIndexLowerbound(propdata->topoorder[idx]) == (SCIPeventGetNewbound(event) > 0.5)));
3043 
3044  /* add the bound change to the propagation queue, if it is not already contained */
3045  if( !propdata->inqueue[idx] )
3046  {
3047  SCIP_CALL( SCIPpqueueInsert(propdata->propqueue, (void*)(size_t)(idx + 1)) ); /*lint !e571 !e776*/
3048  propdata->inqueue[idx] = TRUE;
3049  }
3050  assert(SCIPpqueueNElems(propdata->propqueue) > 0);
3051 
3052  return SCIP_OKAY;
3053 }
3054 
3055 /**@} */
3056 
3057 /**@name Interface methods
3058  *
3059  * @{
3060  */
3061 
3062 /** creates the vbounds propagator and includes it in SCIP */
3064  SCIP* scip /**< SCIP data structure */
3065  )
3067  SCIP_PROPDATA* propdata;
3068  SCIP_PROP* prop;
3069 
3070  /* create vbounds propagator data */
3071  SCIP_CALL( SCIPallocBlockMemory(scip, &propdata) );
3072 
3073  /* reset propagation data */
3074  resetPropdata(propdata);
3075 
3076  /* include propagator */
3078  propExecVbounds, propdata) );
3079  assert(prop != NULL);
3080 
3081  /* set optional callbacks via setter functions */
3082  SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyVbounds) );
3083  SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeVbounds) );
3084  SCIP_CALL( SCIPsetPropInitpre(scip, prop, propInitpreVbounds) );
3085  SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolVbounds) );
3086  SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropVbounds) );
3087  SCIP_CALL( SCIPsetPropPresol(scip, prop, propPresolVbounds, PROP_PRESOL_PRIORITY, PROP_PRESOL_MAXROUNDS,
3088  PROP_PRESOLTIMING) );
3089 
3090  /* include event handler for bound change events */
3091  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &propdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC,
3092  eventExecVbound, (SCIP_EVENTHDLRDATA*)propdata) );
3093 
3095  "propagating/" PROP_NAME "/usebdwidening", "should bound widening be used to initialize conflict analysis?",
3096  &propdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
3098  "propagating/" PROP_NAME "/useimplics", "should implications be propagated?",
3099  &propdata->useimplics, TRUE, DEFAULT_USEIMPLICS, NULL, NULL) );
3101  "propagating/" PROP_NAME "/usecliques", "should cliques be propagated?",
3102  &propdata->usecliques, TRUE, DEFAULT_USECLIQUES, NULL, NULL) );
3104  "propagating/" PROP_NAME "/usevbounds", "should vbounds be propagated?",
3105  &propdata->usevbounds, TRUE, DEFAULT_USEVBOUNDS, NULL, NULL) );
3107  "propagating/" PROP_NAME "/dotoposort", "should the bounds be topologically sorted in advance?",
3108  &propdata->dotoposort, FALSE, DEFAULT_DOTOPOSORT, NULL, NULL) );
3110  "propagating/" PROP_NAME "/sortcliques", "should cliques be regarded for the topological sort?",
3111  &propdata->sortcliques, TRUE, DEFAULT_SORTCLIQUES, NULL, NULL) );
3113  "propagating/" PROP_NAME "/detectcycles", "should cycles in the variable bound graph be identified?",
3114  &propdata->detectcycles, FALSE, DEFAULT_DETECTCYCLES, NULL, NULL) );
3116  "propagating/" PROP_NAME "/minnewcliques", "minimum percentage of new cliques to trigger another clique table analysis",
3117  &propdata->minnewcliques, FALSE, DEFAULT_MINNEWCLIQUES, 0.0, 1.0, NULL, NULL) );
3118  SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/maxcliquesmedium",
3119  "maximum number of cliques per variable to run clique table analysis in medium presolving",
3120  &propdata->maxcliquesmedium, FALSE, DEFAULT_MAXCLIQUESMEDIUM, 0.0, SCIP_REAL_MAX, NULL, NULL) );
3121  SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/maxcliquesexhaustive",
3122  "maximum number of cliques per variable to run clique table analysis in exhaustive presolving",
3123  &propdata->maxcliquesexhaustive, FALSE, DEFAULT_MAXCLIQUESEXHAUSTIVE, 0.0, SCIP_REAL_MAX, NULL, NULL) );
3124 
3125  return SCIP_OKAY;
3126 }
3127 
3128 /** returns TRUE if the propagator has the status that all variable lower and upper bounds are propgated */
3130  SCIP* scip /**< SCIP data structure */
3131  )
3133  SCIP_PROP* prop;
3134  SCIP_PROPDATA* propdata;
3135 
3136  prop = SCIPfindProp(scip, PROP_NAME);
3137  assert(prop != NULL);
3138 
3139  propdata = SCIPpropGetData(prop);
3140  assert(propdata != NULL);
3141 
3142  return (SCIPpqueueNElems(propdata->propqueue) == 0);
3143 }
3144 
3145 /** performs propagation of variables lower and upper bounds */
3147  SCIP* scip, /**< SCIP data structure */
3148  SCIP_Bool force, /**< should domain changes for continuous variables be forced */
3149  SCIP_RESULT* result /**< pointer to store result */
3150  )
3151 {
3152  SCIP_PROP* prop;
3153 
3154  prop = SCIPfindProp(scip, PROP_NAME);
3155  assert(prop != NULL);
3156 
3157  /* perform variable lower and upper bound propagation */
3158  SCIP_CALL( propagateVbounds(scip, prop, force, result) );
3159 
3160  assert((*result) == SCIP_CUTOFF || (*result) == SCIP_DIDNOTRUN
3161  || (*result) == SCIP_DIDNOTFIND || (*result) == SCIP_REDUCEDDOM);
3162 
3163  return SCIP_OKAY;
3164 }
3165 
3166 /**@} */
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
#define PROP_PRESOL_MAXROUNDS
Definition: prop_vbounds.c:94
SCIP_RETCODE SCIPsetPropPresol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPPRESOL((*proppresol)), int presolpriority, int presolmaxrounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:7823
static void resetPropdata(SCIP_PROPDATA *propdata)
Definition: prop_vbounds.c:304
#define DEFAULT_MAXCLIQUESEXHAUSTIVE
Definition: prop_vbounds.c:125
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22604
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
int SCIPpqueueNElems(SCIP_PQUEUE *pqueue)
Definition: misc.c:1263
#define PROP_PRESOL_PRIORITY
Definition: prop_vbounds.c:92
#define PROP_FREQ
Definition: prop_vbounds.c:89
static SCIP_RETCODE addVbound(SCIP *scip, SCIP_PROPDATA *propdata, int startidx, int endidx, SCIP_Real coef, SCIP_Real constant)
Definition: prop_vbounds.c:431
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip.c:41459
#define getVarIndex(idx)
Definition: prop_vbounds.c:144
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17490
#define DEFAULT_USEBDWIDENING
Definition: prop_vbounds.c:114
static SCIP_RETCODE resolvePropagation(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx)
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:46443
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3353
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22587
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22523
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip.c:19649
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:821
static SCIP_Real computeRelaxedLowerbound(SCIP *scip, SCIP_VAR *var, SCIP_Real inferlb, SCIP_Real coef, SCIP_Real constant)
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip.c:19509
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_PROPDATA *propdata)
Definition: prop_vbounds.c:381
#define DEFAULT_USECLIQUES
Definition: prop_vbounds.c:116
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_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:41226
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17468
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip.h:22622
SCIP_PROP * SCIPfindProp(SCIP *scip, const char *name)
Definition: scip.c:7873
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17276
#define PROP_PRESOLTIMING
Definition: prop_vbounds.c:93
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:46813
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:47088
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17332
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17639
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:23211
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:8611
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16842
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:138
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:47387
#define getLbIndex(idx)
Definition: prop_vbounds.c:142
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47350
int SCIPcliqueGetIndex(SCIP_CLIQUE *clique)
Definition: implics.c:3389
#define FALSE
Definition: def.h:64
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip.c:21985
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2793
#define DEFAULT_SORTCLIQUES
Definition: prop_vbounds.c:119
#define DEFAULT_MAXCLIQUESMEDIUM
Definition: prop_vbounds.c:122
SCIP_RETCODE SCIPcutoffNode(SCIP *scip, SCIP_NODE *node)
Definition: scip.c:41747
#define TRUE
Definition: def.h:63
SCIP_Bool SCIPvarHasImplic(SCIP_VAR *var, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype)
Definition: var.c:10560
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:27474
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_Bool SCIPcliqueIsEquation(SCIP_CLIQUE *clique)
Definition: implics.c:3409
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:27251
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17510
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:16969
#define SCIP_EVENTTYPE_GLBCHANGED
Definition: type_event.h:61
static SCIP_DECL_PROPINITPRE(propInitpreVbounds)
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
Definition: scip.c:27218
static SCIP_DECL_PROPCOPY(propCopyVbounds)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
Definition: scip.c:27155
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22639
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:22602
void SCIPpqueueFree(SCIP_PQUEUE **pqueue)
Definition: misc.c:1160
static SCIP_BOUNDTYPE inferInfoGetBoundtype(INFERINFO inferinfo)
Definition: prop_vbounds.c:237
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17480
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip.h:22628
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:2931
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46963
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:22632
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip.c:21953
#define isIndexLowerbound(idx)
Definition: prop_vbounds.c:146
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:22585
SCIP_NODE * SCIPgetRootNode(SCIP *scip)
Definition: scip.c:41423
static int inferInfoToInt(INFERINFO inferinfo)
Definition: prop_vbounds.c:228
#define SCIPdebugMsgPrint
Definition: scip.h:456
#define SCIPdebugMsg
Definition: scip.h:455
#define VISITED
Definition: prop_vbounds.c:770
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17628
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:11992
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:27184
SCIP_RETCODE SCIPincludePropVbounds(SCIP *scip)
int * SCIPvarGetImplIds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17616
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:115
const char * SCIPgetProbName(SCIP *scip)
Definition: scip.c:10891
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3025
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
Definition: scip.c:27133
static SCIP_Real computeRelaxedUpperbound(SCIP *scip, SCIP_VAR *var, SCIP_Real inferub, SCIP_Real coef, SCIP_Real constant)
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition: scip.h:22638
variable upper and lower bound propagator
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17286
#define PROP_DESC
Definition: prop_vbounds.c:86
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:22599
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1162
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
#define SCIPerrorMessage
Definition: pub_message.h:45
static SCIP_DECL_EVENTEXEC(eventExecVbound)
#define indexGetBoundString(idx)
Definition: prop_vbounds.c:149
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46976
SCIP_RETCODE SCIPexecPropVbounds(SCIP *scip, SCIP_Bool force, SCIP_RESULT *result)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:19311
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:46731
#define INITMEMSIZE
Definition: prop_vbounds.c:427
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:27450
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17542
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16662
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2826
SCIP_RETCODE SCIPtightenVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:23542
#define SCIP_Shortbool
Definition: def.h:69
static int varGetUbIndex(SCIP_PROPDATA *propdata, SCIP_VAR *var)
Definition: prop_vbounds.c:292
#define PROP_NAME
Definition: prop_vbounds.c:85
#define SCIP_CALL(x)
Definition: def.h:350
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:63
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17500
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:23325
static INFERINFO intToInferInfo(int i)
Definition: prop_vbounds.c:215
#define DEFAULT_DOTOPOSORT
Definition: prop_vbounds.c:118
#define PROP_TIMING
Definition: prop_vbounds.c:87
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17532
static SCIP_DECL_PROPEXEC(propExecVbounds)
void * SCIPpqueueRemove(SCIP_PQUEUE *pqueue)
Definition: misc.c:1208
static SCIP_DECL_PROPEXITSOL(propExitsolVbounds)
static SCIP_RETCODE initData(SCIP *scip, SCIP_PROP *prop, SCIP_Bool *infeasible)
static int inferInfoGetPos(INFERINFO inferinfo)
Definition: prop_vbounds.c:248
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:22620
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17586
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:982
#define SCIP_Bool
Definition: def.h:61
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:959
int SCIPgetNCliquesCreated(SCIP *scip)
Definition: scip.c:24906
#define EVENTHDLR_NAME
Definition: prop_vbounds.c:104
#define getBoundtype(idx)
Definition: prop_vbounds.c:145
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17554
static SCIP_RETCODE applyFixingsAndAggregations(SCIP *scip, SCIP_VAR **vars, int *infeasnodes, int ninfeasnodes, SCIP_Shortbool *nodeinfeasible, int *sccvars, int *sccstarts, int nsccs, SCIP_Bool *infeasible, int *nfixedvars, int *naggrvars, SCIP_RESULT *result)
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
Definition: scip.c:27286
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3365
#define EVENTHDLR_DESC
Definition: prop_vbounds.c:105
static SCIP_RETCODE dfs(SCIP *scip, SCIP_PROPDATA *propdata, int startnode, int *visited, int *dfsstack, int *stacknextedge, int *dfsnodes, int *ndfsnodes, SCIP_Bool *infeasible)
Definition: prop_vbounds.c:774
SCIP_RETCODE SCIPsetPropCopy(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPCOPY((*propcopy)))
Definition: scip.c:7695
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:41272
static SCIP_RETCODE extractCycle(SCIP *scip, SCIP_PROPDATA *propdata, int *dfsstack, int *stacknextedge, int stacksize, SCIP_Bool samebound, SCIP_Bool *infeasible)
Definition: prop_vbounds.c:490
#define SCIPfreeMemoryArray(scip, ptr)
Definition: scip.h:22569
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip.c:25575
#define SCIPreallocMemoryArray(scip, ptr, newnum)
Definition: scip.h:22559
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:65
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17600
SCIP_RETCODE SCIPsetPropExitsol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPEXITSOL((*propexitsol)))
Definition: scip.c:7775
int SCIPgetNBinVars(SCIP *scip)
Definition: scip.c:11857
const char * SCIPpropGetName(SCIP_PROP *prop)
Definition: prop.c:887
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:11812
#define SCIP_REAL_MAX
Definition: def.h:150
static SCIP_RETCODE relaxVbdvar(SCIP *scip, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd)
#define getBoundString(lower)
Definition: prop_vbounds.c:147
#define PROP_DELAY
Definition: prop_vbounds.c:90
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17571
static int varGetLbIndex(SCIP_PROPDATA *propdata, SCIP_VAR *var)
Definition: prop_vbounds.c:280
#define DEFAULT_MINNEWCLIQUES
Definition: prop_vbounds.c:121
static SCIP_RETCODE tarjan(SCIP *scip, int startnode, int *startindex, SCIP_Shortbool *nodeonstack, int *nodeindex, int *nodelowlink, SCIP_Shortbool *nodeinfeasible, int *dfsstack, int *predstackidx, int *stacknextclique, int *stacknextcliquevar, int *topoorder, int *nordered, int *cliquefirstentry, int *cliquecurrentexit, int *sccvars, int *sccstarts, int *nsccs, int *infeasnodes, int *ninfeasnodes, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPsetPropResprop(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPRESPROP((*propresprop)))
Definition: scip.c:7856
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47002
#define ACTIVE
Definition: prop_vbounds.c:771
static INFERINFO getInferInfo(int pos, SCIP_BOUNDTYPE boundtype)
Definition: prop_vbounds.c:257
SCIP_RETCODE SCIPpqueueInsert(SCIP_PQUEUE *pqueue, void *elem)
Definition: misc.c:1181
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:322
SCIP_RETCODE SCIPpqueueCreate(SCIP_PQUEUE **pqueue, int initsize, SCIP_Real sizefac, SCIP_DECL_SORTPTRCOMP((*ptrcomp)))
Definition: misc.c:1135
SCIP_Real SCIPgetHugeValue(SCIP *scip)
Definition: scip.c:47065
#define PROP_PRIORITY
Definition: prop_vbounds.c:88
#define getOtherBoundIndex(idx)
Definition: prop_vbounds.c:150
int SCIPgetNCliques(SCIP *scip)
Definition: scip.c:24879
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:47375
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:11767
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip.c:25684
#define SCIP_Real
Definition: def.h:149
#define getBoundtypeString(type)
Definition: prop_vbounds.c:148
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition: scip.h:22642
static SCIP_DECL_PROPPRESOL(propPresolVbounds)
struct SCIP_PropData SCIP_PROPDATA
Definition: type_prop.h:38
#define DEFAULT_USEVBOUNDS
Definition: prop_vbounds.c:117
SCIP_RETCODE SCIPsetPropFree(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPFREE((*propfree)))
Definition: scip.c:7711
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17522
SCIP_PROPDATA * SCIPpropGetData(SCIP_PROP *prop)
Definition: prop.c:735
void SCIPpropSetData(SCIP_PROP *prop, SCIP_PROPDATA *propdata)
Definition: prop.c:745
static SCIP_RETCODE propagateVbounds(SCIP *scip, SCIP_PROP *prop, SCIP_Bool force, SCIP_RESULT *result)
#define DEFAULT_DETECTCYCLES
Definition: prop_vbounds.c:120
static SCIP_DECL_SORTPTRCOMP(compVarboundIndices)
Definition: prop_vbounds.c:478
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16827
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:47076
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17342
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3343
SCIP_RETCODE SCIPtightenVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:23662
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2874
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:112
static SCIP_DECL_PROPRESPROP(propRespropVbounds)
#define SCIP_EVENTTYPE_GUBCHANGED
Definition: type_event.h:62
SCIP_EVENTHDLRDATA * SCIPeventhdlrGetData(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:288
SCIP_RETCODE SCIPsetPropInitpre(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPINITPRE((*propinitpre)))
Definition: scip.c:7791
SCIP_RETCODE SCIPcleanupCliques(SCIP *scip, SCIP_Bool *infeasible)
Definition: scip.c:24836
#define SCIPABORT()
Definition: def.h:322
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16853
SCIP_Bool SCIPisPropagatedVbounds(SCIP *scip)
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4321
SCIP_RETCODE SCIPanalyzeConflict(SCIP *scip, int validdepth, SCIP_Bool *success)
Definition: scip.c:27504
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:4239
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16949
static SCIP_RETCODE topologicalSort(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Bool *infeasible)
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:134
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:7658
#define getUbIndex(idx)
Definition: prop_vbounds.c:143
static SCIP_DECL_PROPFREE(propFreeVbounds)