Scippy

SCIP

Solving Constraint Integer Programs

prop_genvbounds.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-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file prop_genvbounds.c
17  * @ingroup PROPAGATORS
18  * @brief generalized variable bounds propagator
19  * @author Stefan Weltge
20  * @author Ambros Gleixner
21  */
22 
23 /**@todo should we only discard events catched from nodes that are not the current node's ancestors? */
24 /**@todo improve computation of minactivity */
25 /**@todo for multaggr vars on left-hand side, create a linear constraint, probably in exitpre */
26 
27 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
28 
29 #include <assert.h>
30 #include <string.h>
31 
32 #include "scip/prop_genvbounds.h"
33 #include "scip/debug.h"
34 
35 #define PROP_NAME "genvbounds"
36 #define PROP_DESC "generalized variable bounds propagator"
37 #define PROP_TIMING SCIP_PROPTIMING_ALWAYS
38 #define PROP_PRIORITY 3000000 /**< propagator priority */
39 #define PROP_FREQ 1 /**< propagator frequency */
40 #define PROP_DELAY FALSE /**< should propagation method be delayed, if other propagators
41  * found reductions? */
42 #define PROP_PRESOL_PRIORITY -2000000 /**< priority of the presolving method (>= 0: before, < 0: after
43  * constraint handlers); combined with presolvers */
44 #define PROP_PRESOL_DELAY FALSE /**< should presolving be delay, if other presolvers found
45  * reductions? */
46 #define PROP_PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates
47  * in (-1: no limit) */
48 #define DEFAULT_GLOBAL_PROPAGATION TRUE /**< apply global propagation? */
49 #define DEFAULT_PROPAGATE_IN_ROOT_NODE TRUE /**< apply genvbounds in root node if no new incumbent was found? */
50 #define DEFAULT_SORT TRUE /**< sort genvbounds and wait for bound change events? (otherwise all
51  * genvbounds are applied in each node) */
52 
53 #define EVENTHDLR_NAME "genvbounds"
54 #define EVENTHDLR_DESC "event handler for generalized variable bounds propagator"
55 
56 
57 /*
58  * Data structures
59  */
60 
61 /** GenVBound data */
62 struct GenVBound
63 {
64  SCIP_VAR** vars; /**< pointers to variables x_j occuring in this generalized variable
65  * bound */
66  SCIP_VAR* var; /**< pointer to variable x_i */
67  SCIP_Real* coefs; /**< coefficients a_j of the variables listed in vars */
68  SCIP_Real constant; /**< constant term in generalized variable bound */
69  SCIP_Real cutoffcoef; /**< cutoff bound's coefficient */
70  int index; /**< index of this genvbound in genvboundstore array */
71  int ncoefs; /**< number of nonzero coefficients a_j */
72  SCIP_BOUNDTYPE boundtype; /**< type of bound provided by the genvbound, SCIP_BOUNDTYPE_LOWER/UPPER
73  * if +/- x_i on left-hand side */
74 };
75 typedef struct GenVBound GENVBOUND;
76 
77 /** starting indices data structure */
78 struct SCIP_EventData
79 {
80  SCIP_PROP* prop; /**< pointer to genvbounds propagator */
81  SCIP_VAR* var; /**< variable */
82  int* startindices; /**< array to store the first indices of genvbounds in components that are
83  * impacted by a change of this bound */
84  int* startcomponents; /**< array to store the components corresponding to startindices array */
85  int nstarts; /**< number of indices stored in startindices array */
86 };
87 
88 /** propagator data */
89 struct SCIP_PropData
90 {
91  GENVBOUND** genvboundstore; /**< array to store genvbounds; fast access is provided by hashmaps
92  * lbgenvbounds and ubgenvbounds */
93  SCIP_EVENTDATA** lbevents; /**< array of lower bound event data */
94  SCIP_EVENTDATA** ubevents; /**< array of upper bound event data */
95  SCIP_EVENTHDLR* eventhdlr; /**< genvbounds propagator event handler */
96  SCIP_HASHMAP* lbgenvbounds; /**< hashmap to provide fast access to lower bound genvbounds in
97  * genvboundstore array */
98  SCIP_HASHMAP* ubgenvbounds; /**< hashmap to provide fast access to upper bound genvbounds in
99  * genvboundstore array */
100  SCIP_HASHMAP* lbeventsmap; /**< hashmap to provide fast access to lbevents array */
101  SCIP_HASHMAP* ubeventsmap; /**< hashmap to provide fast access to ubevents array */
102  SCIP_HASHMAP* startmap; /**< hashmap to provide fast access to startindices array */
103  SCIP_PROP* prop; /**< pointer to genvbounds propagator */
104  SCIP_NODE* lastnodecaught; /**< last node where events for starting indices were caught */
105  int* componentsstart; /**< stores the components starting indices in genvboundstore array; the
106  * entry componentsstart[ncomponents] is equal to ngenvbounds, which
107  * makes it easier to iterate over all components */
108  int* startindices; /**< storing indices of components where local propagation should start */
109  int* startcomponents; /**< components corresponding to indices stored in startindices array */
110  int* gstartindices; /**< storing indices of components where global propagation, i.e.,
111  * propagation of an improved primal bound, should start */
112  int* gstartcomponents; /**< components corresponding to indices stored in gstartindices array */
113  SCIP_Real lastcutoff; /**< cutoff bound's value last time genvbounds propagator was called */
114  int genvboundstoresize; /**< size of genvboundstore array */
115  int ngenvbounds; /**< number of genvbounds stored in genvboundstore array */
116  int ncomponents; /**< number of components in genvboundstore array */
117  int nindices; /**< number of indices stored in startindices array */
118  int ngindices; /**< number of indices stored in gstartindices array */
119  int nlbevents; /**< number of data entries in lbevents array */
120  int nubevents; /**< number of data entries in ubevents array */
121  SCIP_Bool issorted; /**< stores wether array genvboundstore is topologically sorted */
122  SCIP_Bool global; /**< apply global propagation? */
123  SCIP_Bool propinrootnode; /**< apply genvbounds in root node if no new incumbent was found? */
124  SCIP_Bool sort; /**< sort genvbounds and wait for bound change events? (otherwise all
125  * genvbounds are applied in each node) */
126 };
127 
128 
129 /*
130  * Local methods
131  */
132 
133 /** returns correct cutoff bound value */
134 static
136  SCIP* scip, /**< SCIP data structure */
137  GENVBOUND* genvbound /**< genvbound */
138  )
139 {
140  assert(scip != NULL);
141  assert(genvbound != NULL);
142 
143  SCIPdebugMessage("cutoff = %.9g (%.9g + %.9g * %.9g)\n",
146 
147  /* the cutoff bound is valid w.r.t. the current objective function in the transformed problem; during presolving,
148  * however, the objective function can change (e.g., when a variable is fixed, its contribution in the objective is
149  * subtracted from the cutoff bound and added to the objective offset); we solve this by transforming the
150  * contribution of the cutoff bound in the generalized variable bound to the original problem as described in
151  * function SCIPgenVBoundAdd()
152  */
153  return (SCIPgetCutoffbound(scip) + SCIPgetTransObjoffset(scip)) * SCIPgetTransObjscale(scip);
154 }
155 
156 /** returns corresponding genvbound in genvboundstore if there is one, NULL otherwise */
157 static
159  SCIP* scip, /**< SCIP data structure */
160  SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
161  SCIP_VAR* var, /**< bounds variable */
162  SCIP_BOUNDTYPE boundtype /**< bounds type */
163  )
164 {
165  SCIP_HASHMAP* hashmap;
166 
167  assert(scip != NULL);
168  assert(propdata != NULL);
169  assert(var != NULL);
170 
171  hashmap = boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds;
172 
173  return (GENVBOUND*) SCIPhashmapGetImage(hashmap, var);
174 }
175 
176 #ifdef SCIP_DEBUG
177 /** prints a genvbound as debug message */
178 static
179 void printGenVBound(
180  SCIP* scip, /**< SCIP data structure */
181  GENVBOUND* genvbound /**< genvbound to be printed */
182  )
183 {
184  SCIP_Bool first;
185  int i;
186 
187  assert(genvbound != NULL);
188 
189  if( genvbound->boundtype == SCIP_BOUNDTYPE_UPPER )
190  {
191  SCIPdebugPrintf("- ");
192  }
193 
194  SCIPdebugPrintf("<%s> >= ", SCIPvarGetName(genvbound->var));
195 
196  first = TRUE;
197  for( i = 0; i < genvbound->ncoefs; i++ )
198  {
199  if( !first )
200  {
201  SCIPdebugPrintf(" + ");
202  }
203 
204  SCIPdebugPrintf("%g * <%s>", genvbound->coefs[i], SCIPvarGetName(genvbound->vars[i]));
205 
206  first = FALSE;
207  }
208 
209  if( !SCIPisZero(scip, genvbound->cutoffcoef) )
210  {
211  SCIPdebugPrintf(" + %g * cutoff_bound", genvbound->cutoffcoef);
212  }
213 
214  if( !SCIPisZero(scip, genvbound->constant) )
215  {
216  SCIPdebugPrintf(" + %g", genvbound->constant);
217  }
218 
219  SCIPdebugPrintf("\n");
220 }
221 #endif
222 
223 /** calculates the minactivity of a linear combination of variables stored in an array */
224 static
226  SCIP* scip, /**< SCIP data structure */
227  SCIP_VAR** vars, /**< array of variables */
228  SCIP_Real* coefs, /**< array of coefficients */
229  int nvars, /**< number of variables */
230  SCIP_Bool global /**< use global variable bounds? */
231  )
232 {
233  SCIP_Real minval;
234  int i;
235 
236  assert(scip != NULL);
237  assert(vars != NULL);
238  assert(coefs != NULL);
239  assert(nvars >= 0);
240 
241  minval = 0.0;
242 
243  for( i = 0; i < nvars; i++ )
244  {
245  SCIP_Real bound;
246 
247  assert(!SCIPisZero(scip, coefs[i]));
248 
249  /* get global or local bound */
250  if( global )
251  bound = coefs[i] > 0.0 ? SCIPvarGetLbGlobal(vars[i]) : SCIPvarGetUbGlobal(vars[i]);
252  else
253  bound = coefs[i] > 0.0 ? SCIPvarGetLbLocal(vars[i]) : SCIPvarGetUbLocal(vars[i]);
254 
255  /* with infinite bounds we cannot compute a valid minactivity and return minus infinity */
256  if( SCIPisInfinity(scip, bound) || SCIPisInfinity(scip, -bound) )
257  return -SCIPinfinity(scip);
258 
259  /* add contribution to minactivity */
260  minval += coefs[i] * bound;
261  }
262 
263  return minval;
264 }
265 
266 /** calculates the minactivity of a linear combination of variables stored in the current conflict set */
267 static
269  SCIP* scip, /**< SCIP data structure */
270  SCIP_VAR** vars, /**< array of variables */
271  SCIP_Real* coefs, /**< array of coefficients */
272  int nvars, /**< number of variables */
273  SCIP_BDCHGIDX* bdchgidx /**< bound change at which minactivity should be computed; if NULL use local bounds */
274  )
275 {
276  SCIP_Real minval;
277  int i;
278 
279  assert(scip != NULL);
280  assert(vars != NULL);
281  assert(coefs != NULL);
282  assert(nvars >= 0);
283 
284  minval = 0.0;
285 
286  for( i = 0; i < nvars; i++ )
287  {
288  SCIP_Real bound;
289 
290  assert(!SCIPisZero(scip, coefs[i]));
291 
292  if( coefs[i] > 0.0 )
293  {
294  /* get bound at current bound change */
295  bound = SCIPvarGetLbAtIndex(vars[i], bdchgidx, TRUE);
296 
297  /* if bdchgidx is NULL, assert that we use local bounds */
298  assert(bdchgidx != NULL || SCIPisEQ(scip, bound, SCIPvarGetLbLocal(vars[i])));
299 
300  /* if bdchgidx is not NULL, use the possibly tighter bound already in the current conflict set */
301  if( bdchgidx != NULL && SCIPgetConflictVarLb(scip, vars[i]) > bound )
302  bound = SCIPgetConflictVarLb(scip, vars[i]);
303  }
304  else
305  {
306  /* get bound at current bound change */
307  bound = SCIPvarGetUbAtIndex(vars[i], bdchgidx, TRUE);
308 
309  /* if bdchgidx is NULL, assert that we use local bounds */
310  assert(bdchgidx != NULL || SCIPisEQ(scip, bound, SCIPvarGetUbLocal(vars[i])));
311 
312  /* if bdchgidx is not NULL, use the possibly tighter bound already in the current conflict set */
313  if( bdchgidx != NULL && SCIPgetConflictVarUb(scip, vars[i]) < bound )
314  bound = SCIPgetConflictVarUb(scip, vars[i]);
315  }
316 
317  /* with infinite bounds we cannot compute a valid minactivity and return minus infinity */
318  if( SCIPisInfinity(scip, bound) || SCIPisInfinity(scip, -bound) )
319  return -SCIPinfinity(scip);
320 
321  /* add contribution to minactivity */
322  minval += coefs[i] * bound;
323  }
324 
325  return minval;
326 }
327 
328 /** returns a valid bound given by a generalized variable bound */
329 static
331  SCIP* scip, /**< SCIP data structure */
332  GENVBOUND* genvbound, /**< generalized variable bound */
333  SCIP_Bool global /**< use global variable bounds? */
334  )
335 {
336  SCIP_Real boundval;
337 
338  assert(scip != NULL);
339  assert(genvbound != NULL);
340 
341  boundval = getGenVBoundsMinActivity(scip, genvbound->vars, genvbound->coefs, genvbound->ncoefs, global);
342 
343  if( SCIPisInfinity(scip, -boundval) )
344  return (genvbound->boundtype == SCIP_BOUNDTYPE_LOWER) ? -SCIPinfinity(scip) : SCIPinfinity(scip);
345 
346  if( genvbound->cutoffcoef != 0.0 )
347  boundval += genvbound->cutoffcoef * getCutoffboundGenVBound(scip, genvbound);
348 
349  boundval += genvbound->constant;
350 
351  if( genvbound->boundtype == SCIP_BOUNDTYPE_UPPER )
352  boundval *= -1.0;
353 
354  return boundval;
355 }
356 
357 #ifdef SCIP_DEBUG_SOLUTION
358 /** checks whether a generalized variable bound violates the debug solution */
359 static
360 SCIP_RETCODE checkDebugSolutionGenVBound(
361  SCIP* scip, /**< SCIP data structure */
362  GENVBOUND* genvbound /**< generalized variable bound */
363  )
364 {
365  SCIP_SOL* debugsol;
366  SCIP_Real activity;
367  SCIP_Real solval;
368  int i;
369 
370  assert(scip != NULL);
371  assert(genvbound != NULL);
372 
373  if( !SCIPdebugIsMainscip(scip) )
374  return SCIP_OKAY;
375 
376  activity = 0.0;
377  for( i = 0; i < genvbound->ncoefs; i++ )
378  {
379  SCIP_CALL( SCIPdebugGetSolVal(scip, genvbound->vars[i], &solval) );
380  if( solval != SCIP_UNKNOWN || solval != SCIP_INVALID )
381  activity += genvbound->coefs[i] * solval;
382  else
383  printf("***** debug: ignoring variable with %s value in debug solution\n",
384  solval == SCIP_UNKNOWN ? "unknown" : "invalid");
385  }
386 
387  /* the genvbound must be valid for all cutoff bounds greater equal the objective value of the debug solution */
388  SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
389  activity += genvbound->cutoffcoef *
390  (SCIPgetSolTransObj(scip, debugsol) + SCIPgetTransObjoffset(scip)) * SCIPgetTransObjscale(scip);
391  activity += genvbound->constant;
392 
393  SCIP_CALL( SCIPdebugGetSolVal(scip, genvbound->var, &solval) );
394  if( solval != SCIP_UNKNOWN || solval != SCIP_INVALID )
395  {
396  if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
397  {
398  SCIP_CALL( SCIPdebugCheckLbGlobal(scip, genvbound->var, activity) );
399  }
400  else if( genvbound->boundtype == SCIP_BOUNDTYPE_UPPER )
401  {
402  SCIP_CALL( SCIPdebugCheckUbGlobal(scip, genvbound->var, -activity) );
403  }
404  }
405 
406  return SCIP_OKAY;
407 }
408 #endif
409 
410 /** allocate local and global startindices, startcomponents and startmap */
411 static
413  SCIP* scip, /**< SCIP data structure */
414  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
415  )
416 {
417  assert(scip != NULL);
418  assert(propdata != NULL);
419 
420  assert(propdata->startcomponents == NULL);
421  assert(propdata->startindices == NULL);
422  assert(propdata->startmap == NULL);
423  assert(propdata->nindices == -1);
424 
425  assert(propdata->gstartindices == NULL);
426  assert(propdata->gstartcomponents == NULL);
427  assert(propdata->ngindices == -1);
428 
429  assert(propdata->ngenvbounds >= 1);
430  assert(propdata->ncomponents >= 1);
431 
432  SCIPdebugMessage("create starting data\n");
433 
434  /* allocate memory for arrays */
435  SCIP_CALL( SCIPallocMemoryArray(scip, &(propdata->startindices), propdata->ncomponents) );
436  SCIP_CALL( SCIPallocMemoryArray(scip, &(propdata->startcomponents), propdata->ncomponents) );
437  SCIP_CALL( SCIPallocMemoryArray(scip, &(propdata->gstartindices), propdata->ncomponents) );
438  SCIP_CALL( SCIPallocMemoryArray(scip, &(propdata->gstartcomponents), propdata->ncomponents) );
439 
440  /* create hashmap */
441  SCIP_CALL( SCIPhashmapCreate(&(propdata->startmap), SCIPblkmem(scip), SCIPcalcHashtableSize(propdata->ncomponents)) );
442 
443  propdata->nindices = 0;
444  propdata->ngindices = 0;
445 
446  return SCIP_OKAY;
447 }
448 
449 /** free local and global startindices, startcomponents and startmap */
450 static
452  SCIP* scip, /**< SCIP data structure */
453  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
454  )
455 {
456  assert(scip != NULL);
457  assert(propdata != NULL);
458 
459  SCIPdebugMessage("free starting data\n");
460 
461  if( propdata->startcomponents != NULL )
462  {
463  assert(propdata->startindices != NULL);
464  assert(propdata->startmap != NULL);
465  assert(propdata->nindices >= 0);
466 
467  SCIPfreeMemoryArray(scip, &(propdata->startindices));
468  SCIPfreeMemoryArray(scip, &(propdata->startcomponents));
469  SCIPhashmapFree(&(propdata->startmap));
470  propdata->nindices = -1;
471 
472  assert(propdata->gstartindices != NULL);
473  assert(propdata->gstartcomponents != NULL);
474  assert(propdata->ngindices >= 0);
475 
476  SCIPfreeMemoryArray(scip, &(propdata->gstartindices));
477  SCIPfreeMemoryArray(scip, &(propdata->gstartcomponents));
478  propdata->ngindices = -1;
479  }
480 
481  assert(propdata->startcomponents == NULL);
482  assert(propdata->startindices == NULL);
483  assert(propdata->startmap == NULL);
484  assert(propdata->nindices == -1);
485 
486  assert(propdata->gstartindices == NULL);
487  assert(propdata->gstartcomponents == NULL);
488  assert(propdata->ngindices == -1);
489 
490  return SCIP_OKAY;
491 }
492 
493 static
495  SCIP* scip, /**< SCIP data structure */
496  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
497  )
498 {
499  int i;
500 
501  assert(scip != NULL);
502  assert(propdata != NULL);
503 
504  assert(propdata->gstartindices != NULL);
505  assert(propdata->gstartcomponents != NULL);
506  assert(propdata->ngindices == 0);
507 
508  SCIPdebugMessage("fill global starting data\n");
509 
510  for( i = 0; i < propdata->ncomponents; i++ )
511  {
512  int j;
513 
514  for( j = propdata->componentsstart[i]; j < propdata->componentsstart[i+1]; j++ )
515  {
516  assert(j < propdata->ngenvbounds);
517 
518  if( !SCIPisZero(scip, propdata->genvboundstore[j]->cutoffcoef) )
519  {
520  assert(SCIPisNegative(scip, propdata->genvboundstore[j]->cutoffcoef));
521 
522  propdata->gstartcomponents[propdata->ngindices] = i;
523  propdata->gstartindices[propdata->ngindices] = j;
524 
525  /* go to next component */
526  propdata->ngindices++;
527  break;
528  }
529  }
530  }
531 
532  /* resize arrays */
533  SCIP_CALL( SCIPreallocMemoryArray(scip, &(propdata->gstartindices), propdata->ngindices) );
534  SCIP_CALL( SCIPreallocMemoryArray(scip, &(propdata->gstartcomponents), propdata->ngindices) );
535 
536  return SCIP_OKAY;
537 }
538 
539 
540 /** resets local starting data */
541 static
543  SCIP* scip, /**< SCIP data structure */
544  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
545  )
546 {
547  assert(scip != NULL);
548  assert(propdata != NULL);
549  assert(propdata->startcomponents != NULL);
550  assert(propdata->startindices != NULL);
551  assert(propdata->startmap != NULL);
552  assert(propdata->nindices >= 0);
553 
554  SCIP_CALL( SCIPhashmapRemoveAll(propdata->startmap) );
555  propdata->nindices = 0;
556 
557  return SCIP_OKAY;
558 }
559 
560 /** frees sorted components data */
561 static
563  SCIP* scip, /**< SCIP data structure */
564  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
565  )
566 {
567  assert(scip != NULL);
568  assert(propdata != NULL);
569 
570  SCIPdebugMessage("free components data\n");
571 
572  if( propdata->componentsstart != NULL )
573  {
574  assert(propdata->ncomponents > 0);
575 
576  SCIPfreeMemoryArray(scip, &(propdata->componentsstart));
577  propdata->ncomponents = -1;
578  }
579 
580  assert(propdata->componentsstart == NULL);
581  assert(propdata->ncomponents == -1);
582 
583  return SCIP_OKAY;
584 }
585 
586 /** frees memory allocated for a generalized variable bound */
587 static
589  SCIP* scip,
590  GENVBOUND* genvbound
591  )
592 {
593  assert(scip != NULL);
594  assert(genvbound != NULL);
595  assert(genvbound->coefs != NULL);
596  assert(genvbound->vars != NULL);
597 
598  SCIPfreeMemoryArray(scip, &(genvbound->coefs));
599  SCIPfreeMemoryArray(scip, &(genvbound->vars));
600 
601  SCIPfreeMemory(scip, &genvbound);
602 
603  return SCIP_OKAY;
604 }
605 
606 /** resolves propagation of lower bound on +/- left-hand side variable of a generalized variable bound */
607 static
609  SCIP* scip, /**< SCIP data structure */
610  GENVBOUND* genvbound, /**< genvbound data structure */
611  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
612  SCIP_Real* boundval, /**< pointer to lower bound value on +/- left-hand side variable */
613  SCIP_Bool* success /**< was the explanation succesful? */
614  )
615 {
616  SCIP_VAR* lhsvar;
617  SCIP_VAR** vars;
618  SCIP_Real minactivity;
619  SCIP_Real tmpboundval;
620  SCIP_Real slack;
621  int nvars;
622  int i;
623 
624  assert(scip != NULL);
625  assert(genvbound != NULL);
626  assert(boundval != NULL);
627  assert(success != NULL);
628 
629  *success = FALSE;
630 
631  /* get left-hand side variable */
632  lhsvar = genvbound->var;
633  assert(lhsvar != NULL);
634 
635  /* get right-hand side variables */
636  vars = genvbound->vars;
637  nvars = genvbound->ncoefs;
638  assert(vars != NULL);
639 
640  /* if only the primal bound participates in the propagation, it is globally valid and should not be analyzed */
641  assert(nvars > 0);
642 
643  /* when resolving a propagation, bdchgidx is not NULL and boundval should be the bound change performed for the
644  * left-hand side variable
645  */
646  assert(bdchgidx == NULL || genvbound->boundtype != SCIP_BOUNDTYPE_LOWER || SCIPisEQ(scip,
647  SCIPvarIsIntegral(genvbound->var) ? SCIPfeasCeil(scip, *boundval) : *boundval, SCIPvarGetLbAtIndex(lhsvar, bdchgidx, TRUE)));
648  assert(bdchgidx == NULL || genvbound->boundtype != SCIP_BOUNDTYPE_UPPER || SCIPisEQ(scip,
649  SCIPvarIsIntegral(genvbound->var) ? SCIPfeasCeil(scip, *boundval) : *boundval, -SCIPvarGetUbAtIndex(lhsvar, bdchgidx, TRUE)));
650 
651  /* when creating an initial conflict, bdchgidx is NULL and +/-boundval must exceed the upper/lower bound of the
652  * left-hand side variable
653  */
654  assert(bdchgidx != NULL || genvbound->boundtype != SCIP_BOUNDTYPE_LOWER
655  || SCIPisGT(scip, *boundval, SCIPvarGetUbLocal(lhsvar)));
656  assert(bdchgidx != NULL || genvbound->boundtype != SCIP_BOUNDTYPE_UPPER
657  || SCIPisGT(scip, *boundval, -SCIPvarGetLbLocal(lhsvar)));
658 
659  SCIPdebugMessage("resolving genvbound propagation: lhs=%s<%s> >= boundval=%.15g\n",
660  genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? "+" : "-", SCIPvarGetName(lhsvar), *boundval);
661 
662  /* subtract constant terms from bound value */
663  tmpboundval = *boundval;
664  tmpboundval -= genvbound->cutoffcoef * getCutoffboundGenVBound(scip, genvbound);
665  tmpboundval -= genvbound->constant;
666 
667  SCIPdebugMessage("subtracting constant terms gives boundval=%.15g\n", tmpboundval);
668 
669  /* compute minimal activity; if bdchgidx is NULL, we create the initial conflict and use local bounds */
670  minactivity = getGenVBoundsMinActivityConflict(scip, genvbound->vars, genvbound->coefs, genvbound->ncoefs, bdchgidx);
671 
672  SCIPdebugMessage("minactivity of right-hand side is minactivity=%.15g\n", minactivity);
673 
674  /* a genvbound might have been replaced since the propagation took place, hence we have to check that the current
675  * genvbound can explain the propagation at the given bound change index; note that by now, with smaller cutoff
676  * bound, we might even perform a stronger propagation
677  */
678  if( SCIPisLT(scip, minactivity, tmpboundval) )
679  {
680  SCIPdebugMessage("minactivity is too small to explain propagation; was genvbound replaced?\n");
681  return SCIP_OKAY;
682  }
683 
684  /* if bdchgidx is NULL, i.e., we create the initial conflict, we should be able to explain the bound change */
685  assert(SCIPisGE(scip, minactivity, tmpboundval));
686 
687  slack = MAX(minactivity - tmpboundval, 0.0);
688 
689  SCIPdebugMessage("slack=%.15g\n", slack);
690 
691  /* add variables on the right-hand side as reasons for propagation */
692  for( i = 0; i < nvars; i++ )
693  {
694  assert(vars[i] != NULL);
695  assert(!SCIPisZero(scip, genvbound->coefs[i]));
696  assert(SCIPisEQ(scip, SCIPvarGetLbAtIndex(vars[i], bdchgidx, TRUE), SCIPvarGetLbAtIndex(vars[i], bdchgidx, FALSE)));
697  assert(SCIPisEQ(scip, SCIPvarGetUbAtIndex(vars[i], bdchgidx, TRUE), SCIPvarGetUbAtIndex(vars[i], bdchgidx, FALSE)));
698 
699  /* coefficient is positive */
700  if( genvbound->coefs[i] > 0.0 )
701  {
702  SCIP_Real lbatindex;
703  SCIP_Real conflictlb;
704 
705  /* get bound at current bound change */
706  lbatindex = SCIPvarGetLbAtIndex(vars[i], bdchgidx, TRUE);
707 
708  /* get bound already enforced by conflict set */
709  conflictlb = SCIPgetConflictVarLb(scip, genvbound->vars[i]);
710  assert(SCIPisGE(scip, conflictlb, SCIPvarGetLbGlobal(genvbound->vars[i])));
711 
712  SCIPdebugMessage("lower bound of variable <%s> (genvbound->vars[%d]) in conflict set / at index is %.15g / %.15g\n",
713  SCIPvarGetName(genvbound->vars[i]), i, conflictlb, lbatindex);
714 
715  /* if bound is already enforced by conflict set we do not need to add the bound change; since we used the
716  * tighest bound already when computing the initial minactivity, the slack is already correct
717  */
718  if( SCIPisLE(scip, lbatindex, conflictlb) )
719  {
720  SCIPdebugMessage("skipping lower bound of variable <%s> (genvbound->vars[%d]) already enforced in conflict set\n",
721  SCIPvarGetName(genvbound->vars[i]), i);
722  }
723  else
724  {
725  SCIP_Real relaxedlb;
726 
727  /* compute relaxed bound that would suffice to explain the bound change */
728  relaxedlb = lbatindex - (slack / genvbound->coefs[i]);
729  assert(relaxedlb <= lbatindex);
730 
731  /* add variable to conflict set */
732  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, genvbound->vars[i], bdchgidx, relaxedlb ) );
733 
734  /* get new bound of variable in conflict set; after possible bound widening in SCIPaddConflictLbRelaxed(),
735  * it should be between conflictlb and lbatindex
736  */
737  relaxedlb = SCIPgetConflictVarLb(scip, genvbound->vars[i]);
738  assert(SCIPisGE(scip, relaxedlb, conflictlb));
739  assert(SCIPisLE(scip, relaxedlb, lbatindex));
740 
741  /* update slack and ensure that its nonegative */
742  slack -= genvbound->coefs[i] * (lbatindex - relaxedlb);
743  slack = MAX(slack, 0.0);
744 
745  SCIPdebugMessage("added lower bound of variable <%s> (genvbound->vars[%d]); new slack=%.15g\n",
746  SCIPvarGetName(genvbound->vars[i]), i, slack);
747  }
748  }
749  /* coefficient is negative */
750  else
751  {
752  SCIP_Real ubatindex;
753  SCIP_Real conflictub;
754 
755  /* get bound at current bound change */
756  ubatindex = SCIPvarGetUbAtIndex(vars[i], bdchgidx, TRUE);
757 
758  /* get bound already enforced by conflict set */
759  conflictub = SCIPgetConflictVarUb(scip, genvbound->vars[i]);
760  assert(SCIPisLE(scip, conflictub, SCIPvarGetUbGlobal(genvbound->vars[i])));
761 
762  SCIPdebugMessage("upper bound of variable <%s> (genvbound->vars[%d]) in conflict set / at index is %.15g / %.15g\n",
763  SCIPvarGetName(genvbound->vars[i]), i, conflictub, ubatindex);
764 
765  /* if bound is already enforced by conflict set we do not need to add the bound change; since we used the
766  * tighest bound already when computing the initial minactivity, the slack is already correct
767  */
768  if( SCIPisGE(scip, ubatindex, conflictub) )
769  {
770  SCIPdebugMessage("skipping upper bound of variable <%s> (genvbound->vars[%d]) already enforced in conflict set\n",
771  SCIPvarGetName(genvbound->vars[i]), i);
772  }
773  else
774  {
775  SCIP_Real relaxedub;
776 
777  /* compute relaxed bound that would suffice to explain the bound change */
778  relaxedub = ubatindex - (slack / genvbound->coefs[i]);
779  assert(relaxedub >= ubatindex);
780 
781  /* add variable to conflict set */
782  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, genvbound->vars[i], bdchgidx, relaxedub ) );
783 
784  /* get new bound of variable in conflict set; after possible bound widening in SCIPaddConflictUbRelaxed(),
785  * it should be between conflictub and ubatindex
786  */
787  relaxedub = SCIPgetConflictVarUb(scip, genvbound->vars[i]);
788  assert(SCIPisLE(scip, relaxedub, conflictub));
789  assert(SCIPisGE(scip, relaxedub, ubatindex));
790 
791  /* update slack and ensure that its nonegative */
792  slack -= genvbound->coefs[i] * (ubatindex - relaxedub);
793  slack = MAX(slack, 0.0);
794 
795  SCIPdebugMessage("added upper bound of variable <%s> (genvbound->vars[%d]); new slack=%.15g\n",
796  SCIPvarGetName(genvbound->vars[i]), i, slack);
797  }
798  }
799  }
800 
801  /* if slack is positive, return increased boundval */
802  if( SCIPisPositive(scip, slack) )
803  tmpboundval += slack;
804 
805  /* add constant terms again */
806  tmpboundval += genvbound->cutoffcoef * getCutoffboundGenVBound(scip, genvbound);
807  tmpboundval += genvbound->constant;
808 
809  /* boundval should not have been decreased; if this happened nevertheless, maybe due to numerical errors, we quit
810  * without success
811  */
812  if( SCIPisLT(scip, tmpboundval, *boundval) )
813  {
814  SCIPdebugMessage("boundval was reduced from %.15g to %.15g; propagation not resolved\n", *boundval, tmpboundval);
815  return SCIP_OKAY;
816  }
817 
818  /* return widened boundval */
819  *boundval = tmpboundval;
820  *success = TRUE;
821 
822  return SCIP_OKAY;
823 }
824 
825 /** create initial conflict */
826 static
828  SCIP* scip, /**< SCIP data structure */
829  GENVBOUND* genvbound /**< genvbound data structure */
830  )
831 {
832  SCIP_Bool success;
833 
834  assert(scip != NULL);
835  assert(genvbound != NULL);
836 
837  /* check if conflict analysis is applicable */
839  return SCIP_OKAY;
840 
841  /* initialize conflict analysis */
843 
844  /* left-hand side variable >= ... */
845  if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
846  {
847  SCIP_Real infeasthreshold;
848  SCIP_Real bound;
849 
850  /* get minimal right-hand side bound that leads to infeasibility; first try with a factor of 2 for robustness */
851  bound = REALABS(SCIPvarGetUbLocal(genvbound->var));
852  infeasthreshold = MAX(bound, 1.0) * 2 * SCIPfeastol(scip);
853  bound = SCIPvarGetUbLocal(genvbound->var) + infeasthreshold;
854 
855  /* add right-hand side variables that force the lower bound of the left-hand side variable above its upper bound
856  * to conflict set
857  */
858  SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
859  assert(!success || SCIPisFeasGT(scip, bound, SCIPvarGetUbLocal(genvbound->var)));
860 
861  /* if infeasibility cannot be proven with the tighter bound, try with actual bound */
862  if( !success )
863  {
864  bound = REALABS(SCIPvarGetUbLocal(genvbound->var));
865  infeasthreshold = MAX(bound, 1.0) * SCIPfeastol(scip);
866  bound = SCIPvarGetUbLocal(genvbound->var) + infeasthreshold;
867 
868  SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
869  success = success && SCIPisFeasGT(scip, bound, SCIPvarGetUbLocal(genvbound->var));
870  }
871 
872  /* compute upper bound on left-hand side variable that leads to infeasibility */
873  bound -= infeasthreshold;
874  success = success && SCIPisGE(scip, bound, SCIPvarGetUbLocal(genvbound->var));
875 
876  /* initial reason could not be constructed, maybe due to numerics; do not apply conflict analysis */
877  if( !success )
878  {
879  SCIPdebugMessage("strange: could not create initial reason to start conflict analysis\n");
880  return SCIP_OKAY;
881  }
882 
883  /* if bound is already enforced by conflict set we do not have to add it */
884  if( SCIPisGE(scip, bound, SCIPgetConflictVarUb(scip, genvbound->var)) )
885  {
886  SCIPdebugMessage("skipping upper bound of left-hand side variable <%s> already enforced in conflict set\n",
887  SCIPvarGetName(genvbound->var));
888  }
889  else
890  {
891  SCIPdebugMessage("adding upper bound of left-hand side variable <%s>\n", SCIPvarGetName(genvbound->var));
892 
893  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, genvbound->var, NULL, bound) );
894  }
895  }
896  /* left-hand side variable <= ..., i.e., - left-hand side variable >= ... */
897  else
898  {
899  SCIP_Real infeasthreshold;
900  SCIP_Real bound;
901 
902  /* get minimal right-hand side bound that leads to infeasibility; try with a factor of 2 first for robustness */
903  bound = REALABS(SCIPvarGetLbLocal(genvbound->var));
904  infeasthreshold = MAX(bound, 1.0) * 2 * SCIPfeastol(scip);
905  bound = -SCIPvarGetLbLocal(genvbound->var) + infeasthreshold;
906 
907  /* add right-hand side variables that force the upper bound of the left-hand side variable below its lower bound
908  * to conflict set
909  */
910  SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
911  assert(!success || SCIPisFeasLT(scip, -bound, SCIPvarGetLbLocal(genvbound->var)));
912 
913  /* if infeasibility cannot be proven with the tighter bound, try with actual bound */
914  if( !success )
915  {
916  bound = REALABS(SCIPvarGetLbLocal(genvbound->var));
917  infeasthreshold = MAX(bound, 1.0) * SCIPfeastol(scip);
918  bound = -SCIPvarGetLbLocal(genvbound->var) + infeasthreshold;
919 
920  SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
921  success = success && SCIPisFeasLT(scip, -bound, SCIPvarGetLbLocal(genvbound->var));
922  }
923 
924  /* compute lower bound on left-hand side variable that leads to infeasibility */
925  bound = -bound + infeasthreshold;
926  success = success && SCIPisLE(scip, bound, SCIPvarGetLbLocal(genvbound->var));
927 
928  /* initial reason could not be constructed, maybe due to numerics; do not apply conflict analysis */
929  if( !success )
930  {
931  SCIPdebugMessage("strange: could not create initial reason to start conflict analysis\n");
932  return SCIP_OKAY;
933  }
934 
935  /* if bound is already enforced by conflict set we do not have to add it */
936  if( SCIPisLE(scip, bound, SCIPgetConflictVarLb(scip, genvbound->var)) )
937  {
938  SCIPdebugMessage("skipping lower bound of left-hand side variable <%s> already enforced in conflict set\n",
939  SCIPvarGetName(genvbound->var));
940  }
941  else
942  {
943  SCIPdebugMessage("adding lower bound of left-hand side variable <%s>\n", SCIPvarGetName(genvbound->var));
944 
945  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, genvbound->var, NULL, bound) );
946  }
947  }
948 
949  /* analyze the conflict */
950  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
951 
952  return SCIP_OKAY;
953 }
954 
955 /** apply propagation for one generalized variable bound; also if the left-hand side variable is locally fixed, we
956  * compute the right-hand side minactivity to possibly detect infeasibility
957  */
958 static
960  SCIP* scip, /**< SCIP data structure */
961  SCIP_PROP* prop, /**< genvbounds propagator */
962  GENVBOUND* genvbound, /**< genvbound data structure */
963  SCIP_Bool global, /**< apply global bound changes? (global: true, local: false)*/
964  SCIP_RESULT* result, /**< result pointer */
965  int* nchgbds /**< counter to increment if bound was tightened */
966  )
967 {
968  SCIP_Real boundval;
969  SCIP_Bool infeas;
970  SCIP_Bool tightened;
971 
972  assert(scip != NULL);
973  assert(genvbound != NULL);
974  assert(genvbound->var != NULL);
975  assert(SCIPvarGetStatus(genvbound->var) != SCIP_VARSTATUS_MULTAGGR);
976  assert(result != NULL);
977  assert(*result != SCIP_DIDNOTRUN);
978 
979  /* get bound value provided by genvbound */
980  boundval = getGenVBoundsBound(scip, genvbound, global);
981 
982 #ifdef SCIP_DEBUG
983  {
984  SCIP_Real lb;
985  SCIP_Real ub;
986  SCIP_Real new_lb;
987  SCIP_Real new_ub;
988 
989  lb = global ? SCIPvarGetLbGlobal(genvbound->var) : SCIPvarGetLbLocal(genvbound->var);
990  ub = global ? SCIPvarGetUbGlobal(genvbound->var) : SCIPvarGetUbLocal(genvbound->var);
991  new_lb = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? boundval : lb;
992  new_ub = genvbound->boundtype == SCIP_BOUNDTYPE_UPPER ? boundval : ub;
993 
994  SCIPdebugMessage(" %s genvbound propagation for <%s>\n", global ?
995  "global" : "local", SCIPvarGetName(genvbound->var));
996  SCIPdebugMessage(" genvbound: ");
997  printGenVBound(scip, genvbound);
998  SCIPdebugMessage(" [%.15g,%.15g] -> [%.15g,%.15g]\n", lb, ub, new_lb, new_ub);
999  }
1000 #endif
1001 
1002  /* tighten bound globally */
1003  if( global )
1004  {
1005  if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
1006  {
1007  SCIP_CALL( SCIPtightenVarLbGlobal(scip, genvbound->var, boundval, FALSE, &infeas, &tightened) );
1008  }
1009  else
1010  {
1011  SCIP_CALL( SCIPtightenVarUbGlobal(scip, genvbound->var, boundval, FALSE, &infeas, &tightened) );
1012  }
1013  }
1014  /* tighten bound locally and start conflict analysis in case of infeasibility; as inferinfo we pass the index of the
1015  * genvbound that was used for propagation
1016  */
1017  else
1018  {
1019  if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
1020  {
1021  SCIP_CALL( SCIPinferVarLbProp(scip, genvbound->var, boundval, prop, genvbound->index, FALSE, &infeas, &tightened) );
1022 
1023  /* initialize conflict analysis if infeasible */
1024  if( infeas )
1025  {
1026  SCIPdebugMessage(" -> lower bound tightening on variable <%s> led to infeasibility\n",
1027  SCIPvarGetName(genvbound->var));
1028 
1029  SCIP_CALL( analyzeGenVBoundConflict(scip, genvbound) );
1030  }
1031  }
1032  else
1033  {
1034  SCIP_CALL( SCIPinferVarUbProp(scip, genvbound->var, boundval, prop, genvbound->index, FALSE, &infeas, &tightened) );
1035 
1036  /* initialize conflict analysis if infeasible */
1037  if( infeas )
1038  {
1039  SCIPdebugMessage(" -> upper bound tightening on variable <%s> led to infeasibility\n",
1040  SCIPvarGetName(genvbound->var));
1041 
1042  SCIP_CALL( analyzeGenVBoundConflict(scip, genvbound) );
1043  }
1044  }
1045  }
1046 
1047  /* handle result */
1048  if( infeas )
1049  {
1050  *result = SCIP_CUTOFF;
1051  SCIPdebugMessage(" cutoff!\n");
1052  }
1053  else if( tightened )
1054  {
1056  if( nchgbds != NULL )
1057  ++(*nchgbds);
1058  SCIPdebugMessage(" tightened!\n");
1059  }
1060 
1061  return SCIP_OKAY;
1062 }
1063 
1064 #ifdef SCIP_DEBUG
1065 /** prints event data as debug message */
1066 static
1067 void printEventData(
1068  SCIP_EVENTDATA* eventdata,
1069  SCIP_BOUNDTYPE boundtype
1070  )
1071 {
1072  int i;
1073  SCIPdebugMessage("event data: %s bound of <%s> tightened ==> start propagating at ",
1074  boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", SCIPvarGetName(eventdata->var));
1075 
1076  /* if there is eventdata it should contain at least one starting index */
1077  assert(eventdata->nstarts > 0);
1078 
1079  for( i = 0; i < eventdata->nstarts; i++ )
1080  {
1081  SCIPdebugPrintf("(component %d, index %d) ", eventdata->startcomponents[i], eventdata->startindices[i]);
1082  }
1083 
1084  SCIPdebugPrintf("\n");
1085 }
1086 #endif
1087 
1088 /** frees event data */
1089 static
1091  SCIP* scip, /**< SCIP data structure */
1092  SCIP_EVENTDATA** eventdata /**< event data to be freed */
1093  )
1094 {
1095  assert(scip != NULL);
1096  assert(eventdata != NULL);
1097  assert(*eventdata != NULL);
1098 
1099  SCIPfreeMemoryArray(scip, &((*eventdata)->startcomponents));
1100  SCIPfreeMemoryArray(scip, &((*eventdata)->startindices));
1101 
1102  (*eventdata)->nstarts = -1;
1103  (*eventdata)->var = NULL;
1104  (*eventdata)->prop = NULL;
1105 
1106  SCIPfreeMemory(scip, eventdata);
1107 
1108  return SCIP_OKAY;
1109 }
1110 
1111 /** frees all eventdata stored */
1112 static
1114  SCIP* scip, /**< SCIP data structure */
1115  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1116  )
1117 {
1118  int i;
1119 
1120  assert(scip != NULL);
1121  assert(propdata != NULL);
1122 
1123  if( propdata->lbevents != NULL )
1124  {
1125  assert(propdata->ubevents != NULL);
1126  assert(propdata->lbeventsmap != NULL);
1127  assert(propdata->ubeventsmap != NULL);
1128 
1129  SCIPhashmapFree(&(propdata->lbeventsmap));
1130  SCIPhashmapFree(&(propdata->ubeventsmap));
1131 
1132  for( i = propdata->nlbevents - 1; i >= 0; i-- )
1133  {
1134  SCIP_CALL( freeEventData(scip, &(propdata->lbevents[i])) );
1135  }
1136 
1137  for( i = propdata->nubevents - 1; i >= 0; i-- )
1138  {
1139  SCIP_CALL( freeEventData(scip, &(propdata->ubevents[i])) );
1140  }
1141 
1142  SCIPfreeMemoryArray(scip, &(propdata->ubevents));
1143  SCIPfreeMemoryArray(scip, &(propdata->lbevents));
1144  propdata->nlbevents = -1;
1145  propdata->nubevents = -1;
1146  }
1147 
1148  assert(propdata->lbevents == NULL);
1149  assert(propdata->ubevents == NULL);
1150  assert(propdata->lbeventsmap == NULL);
1151  assert(propdata->ubeventsmap == NULL);
1152  assert(propdata->nlbevents == -1);
1153  assert(propdata->nubevents == -1);
1154 
1155  return SCIP_OKAY;
1156 }
1157 
1158 /** drops all events caught by genvbounds propagator and frees their data */
1159 static
1161  SCIP* scip, /**< SCIP data structure */
1162  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1163  )
1164 {
1165  int i;
1166 
1167  SCIPdebugMessage("drop and free events\n");
1168 
1169  assert(scip != NULL);
1170  assert(propdata != NULL);
1171  assert(propdata->eventhdlr != NULL);
1172 
1173  if( propdata->lbevents != NULL )
1174  {
1175  assert(propdata->ubevents != NULL);
1176  assert(propdata->nlbevents >= 0);
1177  assert(propdata->nubevents >= 0);
1178 
1179  for( i = propdata->nlbevents - 1; i >= 0; i-- )
1180  {
1181  /* drop event */
1182  SCIP_CALL( SCIPdropVarEvent(scip, propdata->lbevents[i]->var, SCIP_EVENTTYPE_LBTIGHTENED, propdata->eventhdlr,
1183  propdata->lbevents[i], -1) );
1184  }
1185 
1186  for( i = propdata->nubevents - 1; i >= 0; i-- )
1187  {
1188  /* drop event */
1189  SCIP_CALL( SCIPdropVarEvent(scip, propdata->ubevents[i]->var, SCIP_EVENTTYPE_UBTIGHTENED, propdata->eventhdlr,
1190  propdata->ubevents[i], -1) );
1191  }
1192 
1193  /* free event data */
1194  SCIP_CALL( freeAllEventData(scip, propdata) );
1195  }
1196 
1197  assert(propdata->lbevents == NULL);
1198  assert(propdata->ubevents == NULL);
1199  assert(propdata->nlbevents == -1);
1200  assert(propdata->nubevents == -1);
1201 
1202  return SCIP_OKAY;
1203 }
1204 
1205 /** returns the corresponding event data entry in the corresponding array, if there is one; if not: allocates a new
1206  * event data entry, stores it in the array and returns its adress
1207  */
1208 static
1210  SCIP* scip, /**< SCIP data structure */
1211  SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1212  SCIP_VAR* var, /**< variable */
1213  SCIP_BOUNDTYPE boundtype, /**< type of bound */
1214  SCIP_EVENTDATA** eventdata /**< event data to return */
1215  )
1216 {
1217  SCIP_HASHMAP* hashmap;
1218 
1219  assert(scip != NULL);
1220  assert(propdata != NULL);
1221  assert(var != NULL);
1222 
1223  hashmap = boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbeventsmap : propdata->ubeventsmap;
1224 
1225  if( SCIPhashmapExists(hashmap, var) )
1226  *eventdata = (SCIP_EVENTDATA*) SCIPhashmapGetImage(hashmap, var);
1227  else
1228  {
1229  /* set up new eventdata entry */
1230  SCIP_CALL( SCIPallocMemory(scip, eventdata) );
1231  SCIP_CALL( SCIPallocMemoryArray(scip, &((*eventdata)->startcomponents), propdata->ncomponents) );
1232  SCIP_CALL( SCIPallocMemoryArray(scip, &((*eventdata)->startindices), propdata->ncomponents) );
1233  (*eventdata)->nstarts = 0;
1234  (*eventdata)->var = var;
1235  (*eventdata)->prop = propdata->prop;
1236 
1237  /* store event data in eventarray */
1238  if( boundtype == SCIP_BOUNDTYPE_LOWER )
1239  {
1240  propdata->lbevents[propdata->nlbevents] = *eventdata;
1241  propdata->nlbevents++;
1242  }
1243  else
1244  {
1245  propdata->ubevents[propdata->nubevents] = *eventdata;
1246  propdata->nubevents++;
1247  }
1248 
1249  /* store hashmap entry */
1250  SCIP_CALL( SCIPhashmapInsert(hashmap, var, (*eventdata)) );
1251  }
1252 
1253  return SCIP_OKAY;
1254 }
1255 
1256 /** adds an event to the event array lbevents (if boundtype == SCIP_BOUNDTYPE_LOWER) or ubevents (if boundtype ==
1257  * SCIP_BOUNDTYPE_UPPER)
1258  */
1259 static
1261  SCIP* scip, /**< SCIP data structure */
1262  SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1263  SCIP_VAR* var, /**< variable thats event to be added */
1264  int startindex, /**< starting index */
1265  int startcomponent, /**< starting components index */
1266  SCIP_BOUNDTYPE boundtype /**< type of bound */
1267  )
1268 {
1269  SCIP_EVENTDATA* eventdata;
1270 
1271  assert(scip != NULL);
1272  assert(propdata != NULL);
1273  assert(var != NULL);
1274  assert(startindex >= 0);
1275  assert(startcomponent >= 0);
1276 
1277  /* get eventdata entry */
1278  SCIP_CALL( getEventData(scip, propdata, var, boundtype, &eventdata) );
1279  assert(eventdata != NULL);
1280 
1281  if( eventdata->nstarts > 0 && eventdata->startcomponents[eventdata->nstarts - 1] == startcomponent )
1282  {
1283  /* if there is already a starting index for startcomponent stored at the last entry of eventdata->startindices,
1284  * it should be smaller; this relies on the implementation of setUpEvents(), calling addEventData() in
1285  * topological order
1286  */
1287  assert(eventdata->startindices[eventdata->nstarts - 1] < startindex);
1288  }
1289  else
1290  {
1291  /* append starting information */
1292  eventdata->startcomponents[eventdata->nstarts] = startcomponent;
1293  eventdata->startindices[eventdata->nstarts] = startindex;
1294 
1295  /* increase counter */
1296  eventdata->nstarts++;
1297  }
1298 
1299  return SCIP_OKAY;
1300 }
1301 
1302 static
1304  SCIP* scip, /**< SCIP data structure */
1305  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1306  )
1307 {
1308  int nprobvars;
1309  int i;
1310 
1311  assert(scip != NULL);
1312  assert(propdata != NULL);
1313  assert(propdata->eventhdlr != NULL);
1314  assert(propdata->lbevents == NULL);
1315  assert(propdata->ubevents == NULL);
1316  assert(propdata->issorted);
1317  assert(propdata->nlbevents == -1);
1318  assert(propdata->nubevents == -1);
1319 
1320  SCIPdebugMessage("set up events\n");
1321 
1322  /* allocate lbevents, ubevents, and their hashmaps */
1323  nprobvars = SCIPgetNVars(scip) + SCIPgetNFixedVars(scip);
1324  SCIP_CALL( SCIPallocMemoryArray(scip, &(propdata->lbevents), nprobvars) );
1325  SCIP_CALL( SCIPallocMemoryArray(scip, &(propdata->ubevents), nprobvars) );
1326  SCIP_CALL( SCIPhashmapCreate(&(propdata->lbeventsmap), SCIPblkmem(scip), SCIPcalcHashtableSize(nprobvars)) );
1327  SCIP_CALL( SCIPhashmapCreate(&(propdata->ubeventsmap), SCIPblkmem(scip), SCIPcalcHashtableSize(nprobvars)) );
1328  propdata->nlbevents = 0;
1329  propdata->nubevents = 0;
1330 
1331  /* loop over all components of genvboundstore */
1332  for( i = 0; i < propdata->ncomponents; i++ )
1333  {
1334  int j;
1335 
1336  /* loop over all genvbounds in this component */
1337  for( j = propdata->componentsstart[i]; j < propdata->componentsstart[i+1]; j++ )
1338  {
1339  GENVBOUND* genvbound;
1340  int k;
1341 
1342  assert(j < propdata->ngenvbounds);
1343 
1344  genvbound = propdata->genvboundstore[j];
1345  assert(genvbound != NULL);
1346 
1347  /* loop over all coefficients in this genvbound */
1348  for( k = 0; k < genvbound->ncoefs; k++ )
1349  {
1350  assert(!SCIPisZero(scip, genvbound->coefs[k]));
1351 
1352  if( SCIPisPositive(scip, genvbound->coefs[k]) )
1353  {
1354  SCIP_CALL( addEventData(scip, propdata, genvbound->vars[k], j, i, SCIP_BOUNDTYPE_LOWER) );
1355  }
1356  else
1357  {
1358  SCIP_CALL( addEventData(scip, propdata, genvbound->vars[k], j, i, SCIP_BOUNDTYPE_UPPER) );
1359  }
1360  }
1361  }
1362  }
1363 
1364  /* resize lbevents and ubevents array */
1365  assert(propdata->nlbevents <= nprobvars);
1366  assert(propdata->nubevents <= nprobvars);
1367  SCIP_CALL( SCIPreallocMemoryArray(scip, &(propdata->lbevents), propdata->nlbevents) );
1368  SCIP_CALL( SCIPreallocMemoryArray(scip, &(propdata->ubevents), propdata->nubevents) );
1369 
1370  /* resize and register lower bound events */
1371  for( i = 0; i < propdata->nlbevents; i++ )
1372  {
1373  SCIP_EVENTDATA* eventdata = propdata->lbevents[i];
1374 
1375  assert(eventdata != NULL);
1376  assert(eventdata->nstarts > 0);
1377  assert(eventdata->startcomponents != NULL);
1378  assert(eventdata->startindices != NULL);
1379 
1380  /* resize arrays stored in eventdata */
1381  SCIP_CALL( SCIPreallocMemoryArray(scip, &(eventdata->startcomponents), eventdata->nstarts) );
1382  SCIP_CALL( SCIPreallocMemoryArray(scip, &(eventdata->startindices), eventdata->nstarts) );
1383 
1384  /* register event */
1385  SCIP_CALL( SCIPcatchVarEvent(scip, eventdata->var, SCIP_EVENTTYPE_LBTIGHTENED, propdata->eventhdlr, eventdata,
1386  NULL) );
1387  }
1388 
1389  /* resize and register upper bound events */
1390  for( i = 0; i < propdata->nubevents; i++ )
1391  {
1392  SCIP_EVENTDATA* eventdata = propdata->ubevents[i];
1393 
1394  assert(eventdata != NULL);
1395  assert(eventdata->nstarts > 0);
1396  assert(eventdata->startcomponents != NULL);
1397  assert(eventdata->startindices != NULL);
1398 
1399  /* resize arrays stored in eventdata */
1400  SCIP_CALL( SCIPreallocMemoryArray(scip, &(eventdata->startcomponents), eventdata->nstarts) );
1401  SCIP_CALL( SCIPreallocMemoryArray(scip, &(eventdata->startindices), eventdata->nstarts) );
1402 
1403  /* register event */
1404  SCIP_CALL( SCIPcatchVarEvent(scip, eventdata->var, SCIP_EVENTTYPE_UBTIGHTENED, propdata->eventhdlr, eventdata,
1405  NULL) );
1406  }
1407 
1408  return SCIP_OKAY;
1409 }
1410 
1411 /** performs a topological sort on genvboundstore array
1412  *
1413  * The genvbounds graph is defined as follows: Given two genvbounds
1414  *
1415  * (genvbound1) c1 * x_i1 >= RHS1
1416  *
1417  * and
1418  *
1419  * (genvbound2) c2 * x_i2 >= RHS2,
1420  *
1421  * there is an arc from genvbound1 to genvbound2 iff c1 = +1 and x_i1 appears with positive coefficient in RHS2 or
1422  * c1 = -1 and x_i1 appears with negative coefficient in RHS2; in this case, a bound change of x_i1 deduced from
1423  * genvbound1 improves genvbound2's minactivity in RHS2.
1424  */
1425 static
1427  SCIP* scip, /**< SCIP data structure */
1428  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1429  )
1430 {
1431  GENVBOUND** genvboundssorted; /* array to store the sorted genvbounds */
1432  SCIP_DIGRAPH* graph;
1433  int sortedindex;
1434  int i;
1435 
1436  assert(scip != NULL);
1437  assert(propdata != NULL);
1438  assert(propdata->componentsstart == NULL);
1439 
1440  SCIPdebugMessage("(re-)sort genvbounds topologically\n");
1441 
1442  /* create digraph */
1443  SCIP_CALL( SCIPdigraphCreate(&graph, propdata->ngenvbounds) );
1444 
1445  /* add outgoing arcs for each genvbound */
1446  for( i = 0; i < propdata->ngenvbounds; i++ )
1447  {
1448  GENVBOUND* genvbound;
1449  int j;
1450 
1451  assert(i < propdata->ngenvbounds);
1452 
1453  genvbound = propdata->genvboundstore[i];
1454 
1455  for( j = 0; j < genvbound->ncoefs; j++ )
1456  {
1457  if( SCIPisPositive(scip, genvbound->coefs[j]) &&
1458  SCIPhashmapExists(propdata->lbgenvbounds, genvbound->vars[j]) )
1459  {
1460  int from = ((GENVBOUND*) SCIPhashmapGetImage(propdata->lbgenvbounds, genvbound->vars[j]))->index;
1461  SCIP_CALL( SCIPdigraphAddArc(graph, from, i, NULL) );
1462  }
1463  else if( SCIPisNegative(scip, genvbound->coefs[j]) &&
1464  SCIPhashmapExists(propdata->ubgenvbounds, genvbound->vars[j]) )
1465  {
1466  int from = ((GENVBOUND*) SCIPhashmapGetImage(propdata->ubgenvbounds, genvbound->vars[j]))->index;
1467  SCIP_CALL( SCIPdigraphAddArc(graph, from, i, NULL) );
1468  }
1469  }
1470  }
1471 
1472  /* perform the topological sort */
1473  SCIP_CALL( SCIPdigraphComputeUndirectedComponents(graph, 1, NULL, &(propdata->ncomponents)) );
1475  assert(SCIPdigraphGetNComponents(graph) == propdata->ncomponents);
1476 
1477  /* allocate memory for genvboundssorted and componentsstart array */
1478  SCIP_CALL( SCIPallocMemoryArray(scip, &genvboundssorted, propdata->ngenvbounds) );
1479  SCIP_CALL( SCIPallocMemoryArray(scip, &(propdata->componentsstart), propdata->ncomponents + 1) );
1480 
1481  /* compute sorted genvbounds array, fill componentsstart array */
1482  sortedindex = 0;
1483  propdata->componentsstart[propdata->ncomponents] = propdata->ngenvbounds;
1484  for( i = 0; i < propdata->ncomponents; i++ )
1485  {
1486  int j;
1487  int *nodes;
1488  int nnodes;
1489 
1490  SCIPdigraphGetComponent(graph, i, &nodes, &nnodes);
1491  propdata->componentsstart[i] = sortedindex;
1492 
1493  for( j = 0; j < nnodes; j++ )
1494  {
1495  assert(nodes[j] < propdata->ngenvbounds);
1496  genvboundssorted[sortedindex] = propdata->genvboundstore[nodes[j]];
1497  sortedindex++;
1498  }
1499  }
1500  assert(sortedindex == propdata->ngenvbounds);
1501 
1502  /* free digraph */
1503  SCIPdigraphFree(&graph);
1504 
1505  /* copy sorted genvbounds into genvboundstore */
1506  for( i = 0; i < propdata->ngenvbounds; i++ )
1507  {
1508  assert(genvboundssorted[i] != NULL);
1509 
1510  propdata->genvboundstore[i] = genvboundssorted[i];
1511  propdata->genvboundstore[i]->index = i;
1512  }
1513  SCIPfreeMemoryArray(scip, &(genvboundssorted));
1514 
1515  /* remember genvboundstore as sorted */
1516  propdata->issorted = TRUE;
1517 
1518 #ifdef SCIP_DEBUG
1519  SCIPdebugMessage("genvbounds got: %d\n", propdata->ngenvbounds);
1520  for( i = 0; i < propdata->ncomponents; i++ )
1521  {
1522  int j;
1523 
1524  SCIPdebugMessage("{\n");
1525 
1526  for( j = propdata->componentsstart[i]; j < propdata->componentsstart[i+1]; j++ )
1527  {
1528  SCIPdebugMessage(" [%d] ", j);
1529  printGenVBound(scip, propdata->genvboundstore[j]);
1530  }
1531 
1532  SCIPdebugMessage("}\n");
1533  }
1534 #endif
1535 
1536  return SCIP_OKAY;
1537 }
1538 
1539 /** apply propagation of generalized variable bounds */
1540 static
1542  SCIP* scip, /**< SCIP data structure */
1543  SCIP_PROP* prop, /**< genvbounds propagator */
1544  SCIP_Bool global, /**< use global variable bounds for propagation? */
1545  SCIP_RESULT* result, /**< result pointer */
1546  int* nchgbds /**< counter to increase by the number of changed bounds */
1547  )
1548 {
1549  SCIP_PROPDATA* propdata;
1550  int* startingcomponents;
1551  int* startingindices;
1552  int nindices;
1553  int i;
1554 
1555  SCIPdebugMessage("applying %s genvbound propagation in depth %d\n", global ?
1556  "global" : "local", SCIPgetDepth(scip));
1557 
1558  assert(scip != NULL);
1559  assert(prop != NULL);
1560  assert(result != NULL);
1561 
1562  propdata = SCIPpropGetData(prop);
1563  assert(propdata != NULL);
1564  assert(propdata->genvboundstore != NULL);
1565 
1566  if( *result == SCIP_DIDNOTRUN )
1567  *result = SCIP_DIDNOTFIND;
1568 
1569  /* if the genvbounds are not sorted, i.e. if root node processing has not been finished, yet, we just propagate in
1570  * the order in which they have been added to genvboundstore
1571  */
1572  if( !propdata->issorted )
1573  {
1574  int j;
1575 
1576  assert(!propdata->sort || SCIPinProbing(scip) || SCIPgetDepth(scip) == 0);
1577 
1578  for( j = 0; j < propdata->ngenvbounds && *result != SCIP_CUTOFF; j++ )
1579  {
1580  if( SCIPvarGetStatus(propdata->genvboundstore[j]->var) == SCIP_VARSTATUS_MULTAGGR )
1581  {
1582  /**@todo resolve multiaggregation in exitpre */
1583  }
1584  else
1585  {
1586  SCIPdebugMessage("applying genvbound with index %d (unsorted mode)\n", j);
1587  SCIP_CALL( applyGenVBound(scip, prop, propdata->genvboundstore[j], global, result, nchgbds) );
1588  }
1589  }
1590 
1591  return SCIP_OKAY;
1592  }
1593 
1594  /* otherwise, we propagate only components affected by the latest bound changes */
1595  startingcomponents = global ? propdata->gstartcomponents : propdata->startcomponents;
1596  startingindices = global ? propdata->gstartindices : propdata->startindices;
1597  nindices = global ? propdata->ngindices : propdata->nindices;
1598 
1599  for( i = 0; i < nindices && *result != SCIP_CUTOFF; i++ )
1600  {
1601  int j;
1602 
1603  SCIPdebugMessage("starting in component %d at index %d\n", startingcomponents[i], startingindices[i]);
1604  for( j = startingindices[i]; j < propdata->componentsstart[startingcomponents[i] + 1] &&
1605  *result != SCIP_CUTOFF; j++ )
1606  {
1607  assert(j < propdata->ngenvbounds);
1608 
1609  if( SCIPvarGetStatus(propdata->genvboundstore[j]->var) == SCIP_VARSTATUS_MULTAGGR )
1610  {
1611  /**@todo resolve multiaggregation in exitpre */
1612  }
1613  else
1614  {
1615  SCIPdebugMessage("applying genvbound with index %d, component %d\n", j, startingcomponents[i]);
1616  SCIP_CALL( applyGenVBound(scip, prop, propdata->genvboundstore[j], global, result, nchgbds) );
1617  }
1618  }
1619  }
1620 
1621  /* we dont want to run again caused by this starting data */
1622  if( !global )
1623  {
1624  SCIP_CALL( resetLocalStartingData(scip, propdata) );
1625  }
1626 
1627  return SCIP_OKAY;
1628 }
1629 
1630 /** initialize propagator data */
1631 static
1633  SCIP* scip, /**< SCIP data structure */
1634  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1635  )
1636 {
1637  int nprobvars;
1638 
1639  assert(scip != NULL);
1640  assert(propdata != NULL);
1641  assert(propdata->eventhdlr != NULL);
1642 
1643  SCIPdebugMessage("init propdata\n");
1644 
1645  nprobvars = SCIPgetNVars(scip);
1646 
1647  /* init genvboundstore */
1648  SCIP_CALL( SCIPallocMemoryArray(scip, &(propdata->genvboundstore), 2 * nprobvars) );
1649  BMSclearMemoryArray(propdata->genvboundstore, 2 * nprobvars);
1650  propdata->ngenvbounds = 0;
1651 
1652  /* init genvboundstore hashmaps */
1653  SCIP_CALL( SCIPhashmapCreate(&(propdata->lbgenvbounds), SCIPblkmem(scip), SCIPcalcHashtableSize(nprobvars)) );
1654  SCIP_CALL( SCIPhashmapCreate(&(propdata->ubgenvbounds), SCIPblkmem(scip), SCIPcalcHashtableSize(nprobvars)) );
1655 
1656  return SCIP_OKAY;
1657 }
1658 
1659 /** adds a new genvbound to genvboundstore array and sets a hashmap entry */
1660 static
1662  SCIP* scip, /**< SCIP data structure */
1663  SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1664  GENVBOUND* genvbound /**< genvbound to be added */
1665  )
1666 {
1667  SCIP_HASHMAP* hashmap;
1668 
1669  assert(scip != NULL);
1670  assert(propdata != NULL);
1671  assert(genvbound != NULL);
1672  assert(getGenVBound(scip, propdata, genvbound->var, genvbound->boundtype) == NULL);
1673 
1674  hashmap = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds;
1675 
1676  /* e.g., during presolving after a restart, new variables might have been created; in this case, we need to extend
1677  * the genvboundstore; the new size may even exceed 2*SCIPgetNVars() if we have genvbounds with nonactive left-hand
1678  * side variables
1679  */
1680  assert(propdata->ngenvbounds <= propdata->genvboundstoresize);
1681  if( propdata->ngenvbounds == propdata->genvboundstoresize )
1682  {
1683  propdata->genvboundstoresize = 2*propdata->genvboundstoresize + 1;
1684  SCIP_CALL( SCIPreallocMemoryArray(scip, &(propdata->genvboundstore), propdata->genvboundstoresize) );
1685  }
1686 
1687  /* new index is propdata->ngenvbounds */
1688  SCIP_CALL( SCIPhashmapInsert(hashmap, genvbound->var, genvbound) );
1689  propdata->genvboundstore[propdata->ngenvbounds] = genvbound;
1690  genvbound->index = propdata->ngenvbounds;
1691  propdata->ngenvbounds++;
1692 
1693  assert(propdata->ngenvbounds <= propdata->genvboundstoresize);
1694 
1695  return SCIP_OKAY;
1696 }
1697 
1698 /** runs propagation routine */
1699 static
1701  SCIP* scip, /**< SCIP data structure */
1702  SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1703  SCIP_RESULT* result, /**< result pointer */
1704  SCIP_Bool local, /**< should local propagation be applied? */
1705  int* nchgbds /**< counter to increase by the number of changed bounds */
1706  )
1707 {
1708  assert(scip != NULL);
1709  assert(propdata != NULL);
1710  assert(propdata->prop != NULL);
1711  assert(result != NULL);
1712 
1713  /* we only sort after the root node is finished; this avoids having to sort again after adding more genvbounds; if
1714  * the genvbounds are not sorted, we will simply propagate all of them in the order given
1715  */
1716  if( propdata->sort && !propdata->issorted && !SCIPinProbing(scip) && SCIPgetDepth(scip) > 0 )
1717  {
1718  *result = SCIP_DIDNOTFIND;
1719 
1720  SCIPdebugMessage("genvbounds are not sorted\n");
1721 
1722  /* drop and free old events */
1723  SCIP_CALL( dropAndFreeEvents(scip, propdata) );
1724 
1725  /* free old starting data */
1726  SCIP_CALL( freeStartingData(scip, propdata) );
1727 
1728  /* free sorted components data */
1729  SCIP_CALL( freeComponentsData(scip, propdata) );
1730 
1731  /* sort genvbounds */
1732  SCIP_CALL( sortGenVBounds(scip, propdata) );
1733 
1734  /* create starting data */
1735  SCIP_CALL( createStartingData(scip, propdata) );
1736 
1737  /* fill global starting data */
1738  SCIP_CALL( fillGlobalStartingData(scip, propdata) );
1739 
1740  /* set up new events to catch */
1741  SCIP_CALL( setUpEvents(scip, propdata) );
1742  }
1743 
1744  /* apply global propagation if primal bound has improved */
1745  if( propdata->global && SCIPgetDepth(scip) > 0 && SCIPisFeasLT(scip, SCIPgetCutoffbound(scip), propdata->lastcutoff) )
1746  {
1747  if( propdata->ngindices > 0 )
1748  {
1749  SCIP_CALL( applyGenVBounds(scip, propdata->prop, TRUE, result, nchgbds) );
1750  assert(*result != SCIP_DIDNOTRUN);
1751  }
1752 
1753  /* within the tree, the objective function should not change anymore, hence the cutoff bound should be a stable
1754  * point of reference
1755  */
1756  propdata->lastcutoff = SCIPgetCutoffbound(scip);
1757  }
1758 
1759  /* apply local propagation if allowed */
1760  if( local && *result != SCIP_CUTOFF )
1761  {
1762  /* check if local propagation in root node is allowed */
1763  if( SCIPgetDepth(scip) > 0 || propdata->propinrootnode )
1764  {
1765  /* if genvbounds are already sorted, check if bound change events were caught; otherwise apply all genvbounds */
1766  if( !propdata->issorted || ( SCIPgetCurrentNode(scip) == propdata->lastnodecaught && propdata->nindices > 0 ) )
1767  {
1768  SCIP_CALL( applyGenVBounds(scip, propdata->prop, FALSE, result, nchgbds) );
1769  assert(*result != SCIP_DIDNOTRUN);
1770  }
1771  }
1772  }
1773 
1774  return SCIP_OKAY;
1775 }
1776 
1777 
1778 /*
1779  * Public methods
1780  */
1781 
1782 /** adds a generalized variable bound to the genvbounds propagator; if there is already a genvbound for the bound
1783  * "boundtype" of variable "var", it will be replaced
1784  */
1786  SCIP* scip, /**< SCIP data structure */
1787  SCIP_PROP* genvboundprop, /**< genvbound propagator */
1788  SCIP_VAR** vars, /**< array of RHSs variables */
1789  SCIP_VAR* var, /**< LHSs variable */
1790  SCIP_Real* coefs, /**< array of coefficients for the RHSs variables */
1791  int ncoefs, /**< size of coefs array */
1792  SCIP_Real coefcutoffbound, /**< nonpositive value of the cutoff bounds multiplier */
1793  SCIP_Real constant, /**< constant term */
1794  SCIP_BOUNDTYPE boundtype /**< type of bound provided by the genvbound */
1795  )
1796 {
1797  /**@todo in debug mode: check if genvbound is nontrivial */
1798 
1799  SCIP_PROPDATA* propdata;
1800  GENVBOUND* genvbound;
1801 
1802  SCIP_Bool newgenvbound;
1803 
1804  assert(scip != NULL);
1805  assert(genvboundprop != NULL);
1806  assert(strcmp(SCIPpropGetName(genvboundprop), PROP_NAME) == 0);
1807  assert(vars != NULL);
1808  assert(var != NULL);
1809  assert(coefs != NULL);
1810  assert(ncoefs >= 0);
1811  assert(coefcutoffbound <= 0.0);
1812 
1813  propdata = SCIPpropGetData(genvboundprop);
1814  assert(propdata != NULL);
1815 
1816  /* initialize propdata if not done yet */
1817  if( propdata->genvboundstore == NULL )
1818  {
1819  SCIP_CALL( initPropdata(scip, propdata) );
1820  }
1821 
1822  genvbound = getGenVBound(scip, propdata, var, boundtype);
1823  newgenvbound = (genvbound == NULL);
1824 
1825  /* check if there already is a genvbound corresponding to this bound, freeing its data and overwriting it */
1826  if( !newgenvbound && genvbound->ncoefs < ncoefs )
1827  {
1828  /* do not realloc since we do not want to keep and possibly copy the old entries */
1829  SCIPfreeMemoryArray(scip, &(genvbound->coefs));
1830  SCIPfreeMemoryArray(scip, &(genvbound->vars));
1831 
1832  /* allocate and copy arrays in genvbound */
1833  SCIP_CALL( SCIPduplicateMemoryArray(scip, &(genvbound->coefs), coefs, ncoefs) );
1834  SCIP_CALL( SCIPduplicateMemoryArray(scip, &(genvbound->vars), vars, ncoefs) );
1835  }
1836  else if( !newgenvbound && genvbound->ncoefs == ncoefs )
1837  {
1838  int i;
1839 
1840  /* just update entries */
1841  for( i = 0; i < ncoefs; i++ )
1842  {
1843  genvbound->coefs[i] = coefs[i];
1844  genvbound->vars[i] = vars[i];
1845  }
1846  }
1847  else if( !newgenvbound && genvbound->ncoefs > ncoefs )
1848  {
1849  int i;
1850 
1851  /* reallocate memory for arrays in genvbound to free unused memory */
1852  SCIP_CALL( SCIPreallocMemoryArray(scip, &(genvbound->coefs), ncoefs) );
1853  SCIP_CALL( SCIPreallocMemoryArray(scip, &(genvbound->vars), ncoefs) );
1854 
1855  /* update entries */
1856  for( i = 0; i < ncoefs; i++ )
1857  {
1858  genvbound->coefs[i] = coefs[i];
1859  genvbound->vars[i] = vars[i];
1860  }
1861  }
1862  else if( newgenvbound )
1863  {
1864  /* allocate memory for genvbound data */
1865  SCIP_CALL( SCIPallocMemory(scip, &genvbound) );
1866 
1867  /* allocate and copy arrays in genvbound */
1868  SCIP_CALL( SCIPduplicateMemoryArray(scip, &(genvbound->coefs), coefs, ncoefs) );
1869  SCIP_CALL( SCIPduplicateMemoryArray(scip, &(genvbound->vars), vars, ncoefs) );
1870  }
1871 
1872  /* set up data for genvbound */
1873  genvbound->boundtype = boundtype;
1874  genvbound->var = var;
1875  genvbound->ncoefs = ncoefs;
1876  genvbound->constant = constant;
1877 
1878  /* the cutoff bound is valid w.r.t. the current objective function in the transformed problem; during presolving,
1879  * however, the objective function can change (e.g., when a variable is fixed, its contribution in the objective
1880  * is subtracted from the cutoff bound and added to the objective offset); we solve this by transforming the
1881  * contribution of the cutoff bound in the generalized variable bound to the original problem as follows:
1882  *
1883  * +/- var >= ... + z * SCIPgetCutoffbound() + constant
1884  *
1885  * becomes
1886  *
1887  * +/- var >= ... + (z / SCIPgetTransObjscale()) * origcutoffbound + (constant - z * SCIPgetTransObjoffset())
1888  *
1889  * with SCIPgetCutoffbound() = origcutoffbound / SCIPgetTransObjscale() - SCIPgetTransObjoffset(); in the
1890  * propagation later, we will use (SCIPgetCutoffbound() + SCIPgetTransObjoffset()) * SCIPgetTransObjscale(), see
1891  * function getCutoffboundGenVBound()
1892  */
1893  if( SCIPisNegative(scip, coefcutoffbound) )
1894  {
1895  assert(SCIPisPositive(scip, SCIPgetTransObjscale(scip)));
1896  genvbound->cutoffcoef = coefcutoffbound / SCIPgetTransObjscale(scip);
1897  genvbound->constant -= (coefcutoffbound * SCIPgetTransObjoffset(scip));
1898  }
1899  else
1900  genvbound->cutoffcoef = 0.0;
1901 
1902  /* if genvbound is not overwritten, create a new entry in genvboundstore */
1903  if( newgenvbound )
1904  {
1905  SCIP_CALL( addNewGenVBound(scip, propdata, genvbound) );
1906  }
1907 
1908  /* mark genvbounds array to be resorted */
1909  propdata->issorted = FALSE;
1910 
1911  /* debug message */
1912  SCIPdebugMessage("added genvbound ");
1913  SCIPdebug( printGenVBound(scip, genvbound) );
1914 #ifdef SCIP_DEBUG_SOLUTION
1915  SCIP_CALL( checkDebugSolutionGenVBound(scip, genvbound) );
1916 #endif
1917 
1918  return SCIP_OKAY;
1919 }
1920 
1921 
1922 /*
1923  * Callback methods of propagator
1924  */
1925 
1926 
1927 /** initialization method of propagator (called after problem was transformed) */
1928 static
1929 SCIP_DECL_PROPINIT(propInitGenvbounds)
1930 { /*lint --e{715}*/
1931  SCIP_PROPDATA* propdata;
1932 
1933  assert(scip != NULL);
1934  assert(prop != NULL);
1935  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
1936 
1937  /* get propagator data */
1938  propdata = SCIPpropGetData(prop);
1939  assert(propdata != NULL);
1940 
1941  propdata->genvboundstore = NULL;
1942  propdata->genvboundstoresize = 0;
1943  propdata->lbevents = NULL;
1944  propdata->ubevents = NULL;
1945  propdata->lbgenvbounds = NULL;
1946  propdata->ubgenvbounds = NULL;
1947  propdata->lbeventsmap = NULL;
1948  propdata->ubeventsmap = NULL;
1949  propdata->startmap = NULL;
1950  propdata->componentsstart = NULL;
1951  propdata->startindices = NULL;
1952  propdata->startcomponents = NULL;
1953  propdata->gstartindices = NULL;
1954  propdata->gstartcomponents = NULL;
1955  propdata->lastcutoff = SCIPinfinity(scip);
1956  propdata->lastnodecaught = NULL;
1957  propdata->ngenvbounds = -1;
1958  propdata->ncomponents = -1;
1959  propdata->nindices = -1;
1960  propdata->ngindices = -1;
1961  propdata->nlbevents = -1;
1962  propdata->nubevents = -1;
1963  propdata->issorted = FALSE;
1964 
1965  propdata->prop = prop;
1966 
1967  return SCIP_OKAY;
1968 }
1969 
1970 
1971 /** presolving method of propagator */
1972 static
1973 SCIP_DECL_PROPPRESOL(propPresolGenvbounds)
1974 { /*lint --e{715}*/
1975  SCIP_PROPDATA* propdata;
1976 
1977  assert(scip != NULL);
1978  assert(prop != NULL);
1979  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
1980 
1981  *result = SCIP_DIDNOTRUN;
1982 
1983  /* get propagator data */
1984  propdata = SCIPpropGetData(prop);
1985  assert(propdata != NULL);
1986 
1987  SCIPdebugMessage("proppresol in problem <%s>\n", SCIPgetProbName(scip));
1988 
1989  /* do not run if no genvbounds were added yet */
1990  if( propdata->ngenvbounds < 1 )
1991  {
1992  SCIPdebugMessage("no bounds were added yet\n");
1993  return SCIP_OKAY;
1994  }
1995 
1996  /* propagate */
1997  SCIP_CALL( execGenVBounds(scip, propdata, result, TRUE, nchgbds) );
1998 
1999  return SCIP_OKAY;
2000 }
2001 
2002 
2003 /** presolving deinitialization method of propagator (called after presolving has been finished) */
2004 static
2005 SCIP_DECL_PROPEXITPRE(propExitpreGenvbounds)
2006 { /*lint --e{715}*/
2007  SCIP_PROPDATA* propdata;
2008  int i;
2009 
2010  assert(scip != NULL);
2011  assert(prop != NULL);
2012  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2013 
2014  SCIPdebugMessage("propexitpre in problem <%s>: removing fixed, aggregated, negated, and multi-aggregated variables from right-hand side\n",
2015  SCIPgetProbName(scip));
2016 
2017  /* get propagator data */
2018  propdata = SCIPpropGetData(prop);
2019  assert(propdata != NULL);
2020 
2021  /* there should be no events on the right-hand side variables */
2022  assert(propdata->lbevents == NULL);
2023  assert(propdata->ubevents == NULL);
2024 
2025  for( i = 0; i < propdata->ngenvbounds; )
2026  {
2027  GENVBOUND* genvbound;
2028  int requiredsize;
2029 
2030  genvbound = propdata->genvboundstore[i];
2031  assert(genvbound != NULL);
2032 
2033  /* replace non-active by active variables and update constant */
2034  SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, genvbound->ncoefs, &genvbound->constant, &requiredsize, TRUE) );
2035 
2036  /* if space was not enough we need to resize the buffers */
2037  if( requiredsize > genvbound->ncoefs )
2038  {
2039  /* reallocate memory for arrays in genvbound to free unused memory */
2040  SCIP_CALL( SCIPreallocMemoryArray(scip, &(genvbound->coefs), requiredsize) );
2041  SCIP_CALL( SCIPreallocMemoryArray(scip, &(genvbound->vars), requiredsize) );
2042 
2043  SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, requiredsize, &genvbound->constant, &requiredsize, TRUE) );
2044  assert(requiredsize <= genvbound->ncoefs);
2045  }
2046 
2047  /* if the resulting genvbound is trivial, remove it */
2048  if( genvbound->ncoefs == 0 && SCIPisZero(scip, genvbound->cutoffcoef) )
2049  {
2050  SCIP_HASHMAP* hashmap;
2051 
2052  hashmap = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds;
2053 
2054  /* remove genvbound from hashmap */
2055  assert(SCIPhashmapExists(hashmap, genvbound->var));
2056  SCIP_CALL( SCIPhashmapRemove(hashmap, genvbound->var) );
2057 
2058  /* free genvbound and fill gap */
2059  SCIP_CALL( freeGenVBound(scip, propdata->genvboundstore[i]) );
2060  --(propdata->ngenvbounds);
2061  propdata->genvboundstore[i] = propdata->genvboundstore[propdata->ngenvbounds];
2062  propdata->genvboundstore[i]->index = i;
2063 
2064  /* mark genvbounds array to be resorted */
2065  propdata->issorted = FALSE;
2066  }
2067  else
2068  ++i;
2069  }
2070 
2071  return SCIP_OKAY;
2072 }
2073 
2074 
2075 /** execution method of propagator */
2076 static
2077 SCIP_DECL_PROPEXEC(propExecGenvbounds)
2078 { /*lint --e{715}*/
2079  SCIP_PROPDATA* propdata;
2080 
2081  assert(scip != NULL);
2082  assert(prop != NULL);
2083  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2084 
2085  *result = SCIP_DIDNOTRUN;
2086 
2087  /* get propagator data */
2088  propdata = SCIPpropGetData(prop);
2089  assert(propdata != NULL);
2090 
2091  SCIPdebugMessage("propexec in problem <%s> at depth %d%s\n", SCIPgetProbName(scip), SCIPgetDepth(scip),
2092  SCIPinProbing(scip) ? " in probing" : "");
2093 
2094  /* do not run if no genvbounds were added yet */
2095  if( propdata->ngenvbounds < 1 )
2096  {
2097  /**@todo is it really no performance issue to be called each time when there are no genvbounds, e.g., for MIPs? */
2098  SCIPdebugMessage("no bounds were added yet\n");
2099  return SCIP_OKAY;
2100  }
2101 
2102  /* propagate locally and globally */
2103  SCIP_CALL( execGenVBounds(scip, propdata, result, TRUE, NULL) );
2104 
2105  /* when called in presolving stage the result is set to SCIP_SUCCESS instead of SCIP_REDUCEDDOM, this is corrected
2106  * here
2107  */
2108  if( *result == SCIP_SUCCESS )
2109  *result = SCIP_REDUCEDDOM;
2110 
2111  return SCIP_OKAY;
2112 }
2113 
2114 /** propagation conflict resolving method of propagator */
2115 static
2116 SCIP_DECL_PROPRESPROP(propRespropGenvbounds)
2117 { /*lint --e{715}*/
2118  SCIP_PROPDATA* propdata;
2119  GENVBOUND* genvbound;
2120  SCIP_Real boundval;
2121  SCIP_Bool success;
2122 
2123  SCIPdebugMessage("explain %s bound change of variable <%s>\n",
2124  boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", SCIPvarGetName(infervar));
2125 
2126  /* get propagator data */
2127  propdata = SCIPpropGetData(prop);
2128  assert(propdata != NULL);
2129  assert(propdata->genvboundstore != NULL);
2130 
2131  /* as inferinfo we passed the index of the genvbound that was used for propagation; the genvbound might have been
2132  * replaced, but also the new genvbound at this position has the same variable on the left-hand side
2133  */
2134  assert(inferinfo >= 0);
2135  assert(inferinfo < propdata->ngenvbounds);
2136 
2137  *result = SCIP_DIDNOTFIND;
2138 
2139  /* check also in optimized mode that inferinfo is correct */
2140  if( inferinfo >= propdata->ngenvbounds)
2141  {
2142  SCIPerrorMessage("generalized variable bounds propagator received inferinfo out of range; propagation not resolved, safe to continue\n");
2143  return SCIP_OKAY;
2144  }
2145 
2146  /* get genvbound responsible for the bound change */
2147  genvbound = propdata->genvboundstore[inferinfo];
2148  assert(genvbound != NULL);
2149  assert(genvbound->var == infervar);
2150 
2151  /* check also in optimized mode that inferinfo is correct */
2152  if( genvbound->var != infervar )
2153  {
2154  SCIPerrorMessage("generalized variable bounds propagator received incorrect inferinfo; propagation not resolved, but it's safe to continue\n");
2155  return SCIP_OKAY;
2156  }
2157 
2158  /* get value of bound change on left-hand side */
2159  boundval = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER
2160  ? SCIPvarGetLbAtIndex(genvbound->var, bdchgidx, TRUE)
2161  : -SCIPvarGetUbAtIndex(genvbound->var, bdchgidx, TRUE);
2162 
2163  /* if left-hand side variable is integral, it suffices to explain a bound change greater than boundval - 1 */
2164  if( SCIPvarIsIntegral(genvbound->var) )
2165  {
2166  SCIP_Real roundedboundval;
2167 
2168  assert(SCIPisIntegral(scip, boundval));
2169 
2170  roundedboundval = SCIPfeasCeil(scip, boundval - 1.0) + 2 * SCIPfeastol(scip);
2171  boundval = MIN(boundval, roundedboundval);
2172  }
2173 
2174  /* resolve propagation */
2175  SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, bdchgidx, &boundval, &success) );
2176 
2177  if( success )
2178  *result = SCIP_SUCCESS;
2179 
2180  return SCIP_OKAY;
2181 }
2182 
2183 /** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
2184 static
2185 SCIP_DECL_PROPEXITSOL(propExitsolGenvbounds)
2186 { /*lint --e{715}*/
2187  SCIP_PROPDATA* propdata;
2188  int i;
2189 
2190  assert(scip != NULL);
2191  assert(prop != NULL);
2192  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2193 
2194  SCIPdebugMessage("propexitsol in problem <%s>\n", SCIPgetProbName(scip));
2195 
2196  /* get propagator data */
2197  propdata = SCIPpropGetData(prop);
2198  assert(propdata != NULL);
2199 
2200  if( !SCIPisInRestart(scip) && propdata->genvboundstore != NULL )
2201  {
2202  /* free genvbounds */
2203  for( i = propdata->ngenvbounds - 1; i >= 0; i-- )
2204  {
2205  SCIP_CALL( freeGenVBound(scip, propdata->genvboundstore[i]) );
2206  }
2207 
2208  /* free genvboundstore hashmaps */
2209  SCIPhashmapFree(&(propdata->lbgenvbounds));
2210  SCIPhashmapFree(&(propdata->ubgenvbounds));
2211 
2212  /* free genvboundstore array */
2213  SCIPfreeMemoryArray(scip, &(propdata->genvboundstore));
2214 
2215  /* drop and free all events */
2216  SCIP_CALL( dropAndFreeEvents(scip, propdata) );
2217 
2218  /* free componentsstart array */
2219  SCIP_CALL( freeComponentsData(scip, propdata) );
2220 
2221  /* free starting indices data */
2222  SCIP_CALL( freeStartingData(scip, propdata) );
2223  }
2224 
2225  return SCIP_OKAY;
2226 }
2227 
2228 /** destructor of propagator to free user data (called when SCIP is exiting) */
2229 static
2230 SCIP_DECL_PROPFREE(propFreeGenvbounds)
2231 { /*lint --e{715}*/
2232  SCIP_PROPDATA* propdata;
2233 
2234  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2235 
2236  /* free propagator data */
2237  propdata = SCIPpropGetData(prop);
2238  assert(propdata != NULL);
2239 
2240  SCIPfreeMemory(scip, &propdata);
2241 
2242  SCIPpropSetData(prop, NULL);
2243 
2244  return SCIP_OKAY;
2245 }
2246 
2247 
2248 /*
2249  * Callback methods of event handler
2250  */
2251 
2252 static
2253 SCIP_DECL_EVENTEXEC(eventExecGenvbounds)
2254 { /*lint --e{715}*/
2255  SCIP_PROPDATA* propdata;
2256  int i;
2257 
2258  assert(scip != NULL);
2259  assert(eventdata != NULL);
2260  assert(SCIPeventGetType(event) == SCIP_EVENTTYPE_LBTIGHTENED || SCIPeventGetType(event) ==
2262 
2263  assert(eventdata->startcomponents != NULL);
2264  assert(eventdata->startindices != NULL);
2265  assert(eventdata->nstarts > 0);
2266  assert(eventdata->prop != NULL);
2267 
2268  propdata = SCIPpropGetData(eventdata->prop);
2269  assert(propdata != NULL);
2270 
2271  assert(propdata->startcomponents != NULL);
2272  assert(propdata->startmap != NULL);
2273  assert(propdata->startindices != NULL);
2274 
2275  SCIPdebugMessage("catching eventdata:\n");
2276  SCIPdebug( printEventData(eventdata, SCIPeventGetType(event) == SCIP_EVENTTYPE_LBTIGHTENED ?
2278 
2279  /* check if we need to reset old local starting indices data */
2280  if( SCIPgetCurrentNode(scip) != propdata->lastnodecaught )
2281  {
2282  SCIP_CALL( resetLocalStartingData(scip, propdata) );
2283  propdata->lastnodecaught = SCIPgetCurrentNode(scip);
2284  }
2285 
2286  for( i = 0; i < eventdata->nstarts; i++ )
2287  {
2288  int component;
2289  int startidx;
2290 
2291  component = eventdata->startcomponents[i];
2292  startidx = eventdata->startindices[i];
2293 
2294  /* there is already an entry for this component */
2295  if( SCIPhashmapExists(propdata->startmap, (void*)(size_t) (component + 1)) )
2296  {
2297  int componentidx;
2298 
2299  /* get its index */
2300  componentidx = (int)(size_t) SCIPhashmapGetImage(propdata->startmap, (void*)(size_t) (component + 1)) - 1;
2301  assert(propdata->startcomponents[componentidx] == component);
2302 
2303  if( propdata->startindices[componentidx] > startidx )
2304  propdata->startindices[componentidx] = startidx;
2305  }
2306  else
2307  {
2308  /* get a new entry */
2309  int componentidx;
2310  componentidx = propdata->nindices;
2311 
2312  /* store index */
2313  propdata->startcomponents[componentidx] = component;
2314  propdata->startindices[componentidx] = startidx;
2315 
2316  /* store component in hashmap */
2317  SCIP_CALL( SCIPhashmapInsert(propdata->startmap, (void*)(size_t) (component + 1),
2318  (void*)(size_t) (componentidx + 1)) );
2319 
2320  /* increase number of starting indices */
2321  propdata->nindices++;
2322  }
2323  }
2324 
2325  return SCIP_OKAY;
2326 }
2327 
2328 /*
2329  * propagator specific interface methods
2330  */
2331 
2332 /** creates the genvbounds propagator and includes it in SCIP */
2334  SCIP* scip /**< SCIP data structure */
2335  )
2336 {
2337  SCIP_PROPDATA* propdata;
2338  SCIP_PROP* prop;
2339 
2340  /* create genvbounds propagator data */
2341  SCIP_CALL( SCIPallocMemory(scip, &propdata) );
2342 
2343  /* include propagator */
2345  propExecGenvbounds, propdata) );
2346 
2347  SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeGenvbounds) );
2348  SCIP_CALL( SCIPsetPropInit(scip, prop, propInitGenvbounds) );
2349  SCIP_CALL( SCIPsetPropExitpre(scip, prop, propExitpreGenvbounds) );
2350  SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolGenvbounds) );
2351  SCIP_CALL( SCIPsetPropPresol(scip, prop, propPresolGenvbounds, PROP_PRESOL_PRIORITY,
2353  SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropGenvbounds) );
2354 
2355 
2356  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/"PROP_NAME"/global",
2357  "apply global propagation?",
2358  &propdata->global, TRUE, DEFAULT_GLOBAL_PROPAGATION, NULL, NULL) );
2359 
2360  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/"PROP_NAME"/propinrootnode",
2361  "apply genvbounds in root node if no new incumbent was found?",
2362  &propdata->propinrootnode, TRUE, DEFAULT_PROPAGATE_IN_ROOT_NODE, NULL, NULL) );
2363 
2364  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/"PROP_NAME"/sort",
2365  "sort genvbounds and wait for bound change events?",
2366  &propdata->sort, TRUE, DEFAULT_SORT, NULL, NULL) );
2367 
2368  /* include event handler */
2369  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &propdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecGenvbounds, NULL) );
2370 
2371  return SCIP_OKAY;
2372 }
2373