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