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