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-2018 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file prop_genvbounds.c
17  * @ingroup PROPAGATORS
18  * @brief generalized variable bounds propagator
19  * @author Stefan Weltge
20  * @author Ambros Gleixner
21  * @author Benjamin Mueller
22  */
23 
24 /**@todo should we only discard events catched from nodes that are not the current node's ancestors? */
25 /**@todo improve computation of minactivity */
26 /**@todo for multaggr vars on left-hand side, create a linear constraint, probably in exitpre */
27 
28 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
29 
30 #include <assert.h>
31 #include <string.h>
32 
33 #include "scip/prop_genvbounds.h"
34 #include "scip/debug.h"
35 #include "scip/cons_linear.h"
36 
37 #define PROP_NAME "genvbounds"
38 #define PROP_DESC "generalized variable bounds propagator"
39 #define PROP_TIMING SCIP_PROPTIMING_ALWAYS
40 #define PROP_PRIORITY 3000000 /**< propagator priority */
41 #define PROP_FREQ 1 /**< propagator frequency */
42 #define PROP_DELAY FALSE /**< should propagation method be delayed, if other propagators
43  * found reductions? */
44 #define PROP_PRESOL_PRIORITY -2000000 /**< priority of the presolving method (>= 0: before, < 0: after
45  * constraint handlers); combined with presolvers */
46 #define PROP_PRESOLTIMING SCIP_PRESOLTIMING_FAST /* timing of the presolving method (fast, medium, or exhaustive) */
47 #define PROP_PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates
48  * in (-1: no limit) */
49 #define DEFAULT_GLOBAL_PROPAGATION TRUE /**< apply global propagation? */
50 #define DEFAULT_PROPAGATE_IN_ROOT_NODE TRUE /**< apply genvbounds in root node if no new incumbent was found? */
51 #define DEFAULT_SORT TRUE /**< sort genvbounds and wait for bound change events? (otherwise all
52  * genvbounds are applied in each node) */
53 #define DEFAULT_PROPASCONSS FALSE /**< should genvbounds be transformed to (linear) constraints? */
54 
55 #define EVENTHDLR_NAME "genvbounds"
56 #define EVENTHDLR_DESC "event handler for generalized variable bounds propagator"
57 
58 
59 /*
60  * Data structures
61  */
62 
63 /** GenVBound data */
64 struct GenVBound
65 {
66  SCIP_VAR** vars; /**< pointers to variables x_j occuring in this generalized variable
67  * bound */
68  SCIP_VAR* var; /**< pointer to variable x_i */
69  SCIP_Real* coefs; /**< coefficients a_j of the variables listed in vars */
70  SCIP_Real constant; /**< constant term in generalized variable bound */
71  SCIP_Real cutoffcoef; /**< cutoff bound's coefficient */
72  int coefssize; /**< size of coefs array */
73  int index; /**< index of this genvbound in genvboundstore array */
74  int ncoefs; /**< number of nonzero coefficients a_j */
75  SCIP_BOUNDTYPE boundtype; /**< type of bound provided by the genvbound, SCIP_BOUNDTYPE_LOWER/UPPER
76  * if +/- x_i on left-hand side */
77 };
78 typedef struct GenVBound GENVBOUND;
79 
80 /** starting indices data structure */
81 struct SCIP_EventData
82 {
83  SCIP_PROP* prop; /**< pointer to genvbounds propagator */
84  SCIP_VAR* var; /**< variable */
85  int* startindices; /**< array to store the first indices of genvbounds in components that are
86  * impacted by a change of this bound */
87  int* startcomponents; /**< array to store the components corresponding to startindices array */
88  int nstarts; /**< number of indices stored in startindices array */
89  int startindicessize; /**< size of the startindices and startcomponents arrays */
90 };
91 
92 /** propagator data */
93 struct SCIP_PropData
94 {
95  GENVBOUND** genvboundstore; /**< array to store genvbounds; fast access is provided by hashmaps
96  * lbgenvbounds and ubgenvbounds */
97  SCIP_EVENTDATA** lbevents; /**< array of lower bound event data */
98  SCIP_EVENTDATA** ubevents; /**< array of upper bound event data */
99  SCIP_EVENTHDLR* eventhdlr; /**< genvbounds propagator event handler */
100  SCIP_HASHMAP* lbgenvbounds; /**< hashmap to provide fast access to lower bound genvbounds in
101  * genvboundstore array */
102  SCIP_HASHMAP* ubgenvbounds; /**< hashmap to provide fast access to upper bound genvbounds in
103  * genvboundstore array */
104  SCIP_HASHMAP* lbeventsmap; /**< hashmap to provide fast access to lbevents array */
105  SCIP_HASHMAP* ubeventsmap; /**< hashmap to provide fast access to ubevents array */
106  SCIP_HASHMAP* startmap; /**< hashmap to provide fast access to startindices array */
107  SCIP_PROP* prop; /**< pointer to genvbounds propagator */
108  SCIP_NODE* lastnodecaught; /**< last node where events for starting indices were caught */
109  SCIP_VAR* cutoffboundvar; /**< artificial variable representing primal cutoff bound */
110  int* componentsstart; /**< stores the components starting indices in genvboundstore array; the
111  * entry componentsstart[ncomponents] is equal to ngenvbounds, which
112  * makes it easier to iterate over all components */
113  int componentsstartsize;/**< size of componentsstart array */
114  int* startindices; /**< storing indices of components where local propagation should start */
115  int* startcomponents; /**< components corresponding to indices stored in startindices array */
116  int startindicessize; /**< size of startindices and startcomponents arrays */
117  int* gstartindices; /**< storing indices of components where global propagation, i.e.,
118  * propagation of an improved primal bound, should start */
119  int* gstartcomponents; /**< components corresponding to indices stored in gstartindices array */
120  int gstartindicessize; /**< size of gstartindices and gstartcomponents arrays */
121  SCIP_Real lastcutoff; /**< cutoff bound's value last time genvbounds propagator was called */
122  int genvboundstoresize; /**< size of genvboundstore array */
123  int ngenvbounds; /**< number of genvbounds stored in genvboundstore array */
124  int ncomponents; /**< number of components in genvboundstore array */
125  int nindices; /**< number of indices stored in startindices array */
126  int ngindices; /**< number of indices stored in gstartindices array */
127  int nlbevents; /**< number of data entries in lbevents array */
128  int nubevents; /**< number of data entries in ubevents array */
129  SCIP_Bool issorted; /**< stores wether array genvboundstore is topologically sorted */
130  SCIP_Bool global; /**< apply global propagation? */
131  SCIP_Bool propinrootnode; /**< apply genvbounds in root node if no new incumbent was found? */
132  SCIP_Bool sort; /**< sort genvbounds and wait for bound change events? (otherwise all
133  * genvbounds are applied in each node) */
134  SCIP_Bool propasconss; /**< should genvbounds be transformed to (linear) constraints? */
135 };
136 
137 
138 /*
139  * Local methods
140  */
141 
142 /** returns correct cutoff bound value */
143 static
145  SCIP* scip /**< SCIP data structure */
146  )
147 {
148  assert(scip != NULL);
149 
150  SCIPdebugMsg(scip, "cutoff = %.9g (%.9g + %.9g * %.9g)\n",
153 
154  /* the cutoff bound is valid w.r.t. the current objective function in the transformed problem; during presolving,
155  * however, the objective function can change (e.g., when a variable is fixed, its contribution in the objective is
156  * subtracted from the cutoff bound and added to the objective offset); we solve this by transforming the
157  * contribution of the cutoff bound in the generalized variable bound to the original problem as described in
158  * function SCIPgenVBoundAdd()
159  */
160  return (SCIPgetCutoffbound(scip) + SCIPgetTransObjoffset(scip)) * SCIPgetTransObjscale(scip);
161 }
162 
163 /** returns corresponding genvbound in genvboundstore if there is one, NULL otherwise */
164 static
166  SCIP* scip, /**< SCIP data structure */
167  SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
168  SCIP_VAR* var, /**< bounds variable */
169  SCIP_BOUNDTYPE boundtype /**< bounds type */
170  )
171 {
172  SCIP_HASHMAP* hashmap;
173 
174  assert(scip != NULL);
175  assert(propdata != NULL);
176  assert(var != NULL);
177 
178  hashmap = boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds;
179 
180  return (GENVBOUND*) SCIPhashmapGetImage(hashmap, var);
181 }
182 
183 #ifdef SCIP_DEBUG
184 /** prints a genvbound as debug message */
185 static
186 void printGenVBound(
187  SCIP* scip, /**< SCIP data structure */
188  GENVBOUND* genvbound /**< genvbound to be printed */
189  )
190 {
191  SCIP_Bool first;
192  int i;
193 
194  assert(genvbound != NULL);
195 
196  if( genvbound->boundtype == SCIP_BOUNDTYPE_UPPER )
197  {
198  SCIPdebugMsgPrint(scip, "- ");
199  }
200 
201  SCIPdebugMsgPrint(scip, "<%s> >= ", SCIPvarGetName(genvbound->var));
202 
203  first = TRUE;
204  for( i = 0; i < genvbound->ncoefs; i++ )
205  {
206  if( !first )
207  {
208  SCIPdebugMsgPrint(scip, " + ");
209  }
210 
211  SCIPdebugMsgPrint(scip, "%g * <%s>", genvbound->coefs[i], SCIPvarGetName(genvbound->vars[i]));
212 
213  first = FALSE;
214  }
215 
216  if( !SCIPisZero(scip, genvbound->cutoffcoef) )
217  {
218  SCIPdebugMsgPrint(scip, " + %g * cutoff_bound", genvbound->cutoffcoef);
219  }
220 
221  if( !SCIPisZero(scip, genvbound->constant) )
222  {
223  SCIPdebugMsgPrint(scip, " + %g", genvbound->constant);
224  }
225 
226  SCIPdebugMsgPrint(scip, "\n");
227 }
228 #endif
229 
230 /** calculates the minactivity of a linear combination of variables stored in an array */
231 static
233  SCIP* scip, /**< SCIP data structure */
234  SCIP_VAR** vars, /**< array of variables */
235  SCIP_Real* coefs, /**< array of coefficients */
236  int nvars, /**< number of variables */
237  SCIP_Bool global /**< use global variable bounds? */
238  )
239 {
240  SCIP_Real minval;
241  int i;
242 
243  assert(scip != NULL);
244  assert(vars != NULL);
245  assert(coefs != NULL);
246  assert(nvars >= 0);
247 
248  minval = 0.0;
249 
250  for( i = 0; i < nvars; i++ )
251  {
253 
254  /* get global or local bound */
255  if( global )
256  bound = coefs[i] > 0.0 ? SCIPvarGetLbGlobal(vars[i]) : SCIPvarGetUbGlobal(vars[i]);
257  else
258  bound = coefs[i] > 0.0 ? SCIPvarGetLbLocal(vars[i]) : SCIPvarGetUbLocal(vars[i]);
259 
260  /* with infinite bounds we cannot compute a valid minactivity and return minus infinity */
261  if( SCIPisInfinity(scip, bound) || SCIPisInfinity(scip, -bound) )
262  return -SCIPinfinity(scip);
263 
264  /* add contribution to minactivity */
265  minval += coefs[i] * bound;
266  }
267 
268  return minval;
269 }
270 
271 /** calculates the minactivity of a linear combination of variables stored in the current conflict set */
272 static
274  SCIP* scip, /**< SCIP data structure */
275  SCIP_VAR** vars, /**< array of variables */
276  SCIP_Real* coefs, /**< array of coefficients */
277  int nvars, /**< number of variables */
278  SCIP_BDCHGIDX* bdchgidx /**< bound change at which minactivity should be computed; if NULL use local bounds */
279  )
280 {
281  SCIP_Real minval;
282  int i;
283 
284  assert(scip != NULL);
285  assert(vars != NULL);
286  assert(coefs != NULL);
287  assert(nvars >= 0);
288 
289  minval = 0.0;
290 
291  for( i = 0; i < nvars; i++ )
292  {
294 
295  if( coefs[i] > 0.0 )
296  {
297  /* get bound at current bound change */
298  bound = SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, TRUE);
299 
300  /* if bdchgidx is NULL, assert that we use local bounds */
301  assert(bdchgidx != NULL || SCIPisEQ(scip, bound, SCIPvarGetLbLocal(vars[i])));
302 
303  /* if bdchgidx is not NULL, use the possibly tighter bound already in the current conflict set */
304  if( bdchgidx != NULL && SCIPgetConflictVarLb(scip, vars[i]) > bound )
305  bound = SCIPgetConflictVarLb(scip, vars[i]);
306  }
307  else
308  {
309  /* get bound at current bound change */
310  bound = SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, TRUE);
311 
312  /* if bdchgidx is NULL, assert that we use local bounds */
313  assert(bdchgidx != NULL || SCIPisEQ(scip, bound, SCIPvarGetUbLocal(vars[i])));
314 
315  /* if bdchgidx is not NULL, use the possibly tighter bound already in the current conflict set */
316  if( bdchgidx != NULL && SCIPgetConflictVarUb(scip, vars[i]) < bound )
317  bound = SCIPgetConflictVarUb(scip, vars[i]);
318  }
319 
320  /* with infinite bounds we cannot compute a valid minactivity and return minus infinity */
321  if( SCIPisInfinity(scip, bound) || SCIPisInfinity(scip, -bound) )
322  return -SCIPinfinity(scip);
323 
324  /* add contribution to minactivity */
325  minval += coefs[i] * bound;
326  }
327 
328  return minval;
329 }
330 
331 /** returns a valid bound given by a generalized variable bound */
332 static
334  SCIP* scip, /**< SCIP data structure */
335  GENVBOUND* genvbound, /**< generalized variable bound */
336  SCIP_Bool global /**< use global variable bounds? */
337  )
338 {
339  SCIP_Real boundval;
340 
341  assert(scip != NULL);
342  assert(genvbound != NULL);
343 
344  boundval = getGenVBoundsMinActivity(scip, genvbound->vars, genvbound->coefs, genvbound->ncoefs, global);
345 
346  if( SCIPisInfinity(scip, -boundval) )
347  return (genvbound->boundtype == SCIP_BOUNDTYPE_LOWER) ? -SCIPinfinity(scip) : SCIPinfinity(scip);
348 
349  if( genvbound->cutoffcoef != 0.0 )
350  boundval += genvbound->cutoffcoef * getCutoffboundGenVBound(scip);
351 
352  boundval += genvbound->constant;
353 
354  if( genvbound->boundtype == SCIP_BOUNDTYPE_UPPER )
355  boundval *= -1.0;
356 
357  return boundval;
358 }
359 
360 #ifdef WITH_DEBUG_SOLUTION
361 /** checks whether a generalized variable bound violates the debug solution */
362 static
363 SCIP_RETCODE checkDebugSolutionGenVBound(
364  SCIP* scip, /**< SCIP data structure */
365  GENVBOUND* genvbound /**< generalized variable bound */
366  )
367 {
368  SCIP_SOL* debugsol;
369  SCIP_Real activity;
370  SCIP_Real solval;
371  int i;
372 
373  assert(scip != NULL);
374  assert(genvbound != NULL);
375 
376  if( !SCIPdebugIsMainscip(scip) )
377  return SCIP_OKAY;
378 
379  /* the genvbound must be valid for all cutoff bounds greater equal the objective value of the debug solution */
380  SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
381 
382  /* check whether a debug solution is available */
383  if( debugsol == NULL )
384  return SCIP_OKAY;
385 
386  activity = 0.0;
387  for( i = 0; i < genvbound->ncoefs; i++ )
388  {
389  SCIP_CALL( SCIPdebugGetSolVal(scip, genvbound->vars[i], &solval) );
390  if( solval != SCIP_UNKNOWN || solval != SCIP_INVALID )
391  activity += genvbound->coefs[i] * solval;
392  else
393  printf("***** debug: ignoring variable with %s value in debug solution\n",
394  solval == SCIP_UNKNOWN ? "unknown" : "invalid");
395  }
396 
397  activity += genvbound->cutoffcoef *
398  (SCIPgetSolTransObj(scip, debugsol) + SCIPgetTransObjoffset(scip)) * SCIPgetTransObjscale(scip);
399  activity += genvbound->constant;
400 
401  SCIP_CALL( SCIPdebugGetSolVal(scip, genvbound->var, &solval) );
402  if( solval != SCIP_UNKNOWN || solval != SCIP_INVALID )
403  {
404  if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
405  {
406  SCIP_CALL( SCIPdebugCheckLbGlobal(scip, genvbound->var, activity) );
407  }
408  else if( genvbound->boundtype == SCIP_BOUNDTYPE_UPPER )
409  {
410  SCIP_CALL( SCIPdebugCheckUbGlobal(scip, genvbound->var, -activity) );
411  }
412  }
413 
414  return SCIP_OKAY;
415 }
416 #endif
417 
418 /** allocate local and global startindices, startcomponents and startmap */
419 static
421  SCIP* scip, /**< SCIP data structure */
422  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
423  )
424 {
425  assert(scip != NULL);
426  assert(propdata != NULL);
427 
428  assert(propdata->startcomponents == NULL);
429  assert(propdata->startindices == NULL);
430  assert(propdata->startmap == NULL);
431  assert(propdata->nindices == -1);
432 
433  assert(propdata->gstartindices == NULL);
434  assert(propdata->gstartcomponents == NULL);
435  assert(propdata->ngindices == -1);
436 
437  assert(propdata->ngenvbounds >= 1);
438  assert(propdata->ncomponents >= 1);
439 
440  SCIPdebugMsg(scip, "create starting data\n");
441 
442  /* allocate memory for arrays */
443  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->startindices), propdata->ncomponents) );
444  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->startcomponents), propdata->ncomponents) );
445  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->gstartindices), propdata->ncomponents) );
446  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->gstartcomponents), propdata->ncomponents) );
447  propdata->startindicessize = propdata->ncomponents;
448  propdata->gstartindicessize = propdata->ncomponents;
449 
450  /* create hashmap */
451  SCIP_CALL( SCIPhashmapCreate(&(propdata->startmap), SCIPblkmem(scip), propdata->ncomponents) );
452 
453  propdata->nindices = 0;
454  propdata->ngindices = 0;
455 
456  return SCIP_OKAY;
457 }
458 
459 /** free local and global startindices, startcomponents and startmap */
460 static
462  SCIP* scip, /**< SCIP data structure */
463  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
464  )
465 {
466  assert(scip != NULL);
467  assert(propdata != NULL);
468 
469  SCIPdebugMsg(scip, "free starting data\n");
470 
471  if( propdata->startcomponents != NULL )
472  {
473  assert(propdata->startindices != NULL);
474  assert(propdata->startmap != NULL);
475  assert(propdata->nindices >= 0);
476 
477  SCIPfreeBlockMemoryArray(scip, &(propdata->startindices), propdata->startindicessize);
478  SCIPfreeBlockMemoryArray(scip, &(propdata->startcomponents), propdata->startindicessize);
479  propdata->startindicessize = 0;
480  SCIPhashmapFree(&(propdata->startmap));
481  propdata->nindices = -1;
482 
483  assert(propdata->gstartindices != NULL);
484  assert(propdata->gstartcomponents != NULL);
485  assert(propdata->ngindices >= 0);
486 
487  SCIPfreeBlockMemoryArray(scip, &(propdata->gstartindices), propdata->gstartindicessize);
488  SCIPfreeBlockMemoryArray(scip, &(propdata->gstartcomponents), propdata->gstartindicessize);
489  propdata->gstartindicessize = 0;
490  propdata->ngindices = -1;
491  }
492 
493  assert(propdata->startcomponents == NULL);
494  assert(propdata->startindices == NULL);
495  assert(propdata->startmap == NULL);
496  assert(propdata->nindices == -1);
497 
498  assert(propdata->gstartindices == NULL);
499  assert(propdata->gstartcomponents == NULL);
500  assert(propdata->ngindices == -1);
501 
502  return SCIP_OKAY;
503 }
504 
505 static
507  SCIP* scip, /**< SCIP data structure */
508  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
509  )
510 {
511  int i;
512 
513  assert(scip != NULL);
514  assert(propdata != NULL);
515 
516  assert(propdata->gstartindices != NULL);
517  assert(propdata->gstartcomponents != NULL);
518  assert(propdata->ngindices == 0);
519 
520  SCIPdebugMsg(scip, "fill global starting data\n");
521 
522  for( i = 0; i < propdata->ncomponents; i++ )
523  {
524  int j;
525 
526  for( j = propdata->componentsstart[i]; j < propdata->componentsstart[i+1]; j++ ) /*lint !e679*/
527  {
528  assert(j < propdata->ngenvbounds);
529 
530  if( !SCIPisZero(scip, propdata->genvboundstore[j]->cutoffcoef) )
531  {
532  assert(SCIPisNegative(scip, propdata->genvboundstore[j]->cutoffcoef));
533 
534  propdata->gstartcomponents[propdata->ngindices] = i;
535  propdata->gstartindices[propdata->ngindices] = j;
536 
537  /* go to next component */
538  propdata->ngindices++;
539  break;
540  }
541  }
542  }
543 
544  /* resize arrays */
545  if( propdata->gstartindicessize != propdata->ngindices )
546  {
547  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(propdata->gstartindices), propdata->gstartindicessize, \
548  propdata->ngindices) );
549  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(propdata->gstartcomponents), propdata->gstartindicessize, \
550  propdata->ngindices) );
551  propdata->gstartindicessize = propdata->ngindices;
552  }
553 
554  return SCIP_OKAY;
555 }
556 
557 
558 /** resets local starting 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  assert(propdata->startcomponents != NULL);
568  assert(propdata->startindices != NULL);
569  assert(propdata->startmap != NULL);
570  assert(propdata->nindices >= 0);
571 
572  SCIP_CALL( SCIPhashmapRemoveAll(propdata->startmap) );
573  propdata->nindices = 0;
574 
575  return SCIP_OKAY;
576 }
577 
578 /** frees sorted components data */
579 static
581  SCIP* scip, /**< SCIP data structure */
582  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
583  )
584 {
585  assert(scip != NULL);
586  assert(propdata != NULL);
587 
588  SCIPdebugMsg(scip, "free components data\n");
589 
590  if( propdata->componentsstart != NULL )
591  {
592  assert(propdata->ncomponents > 0);
593 
594  SCIPfreeBlockMemoryArray(scip, &(propdata->componentsstart), propdata->componentsstartsize);
595  propdata->componentsstartsize = 0;
596  propdata->ncomponents = -1;
597  }
598 
599  assert(propdata->componentsstart == NULL);
600  assert(propdata->ncomponents == -1);
601 
602  return SCIP_OKAY;
603 }
604 
605 /** frees memory allocated for a generalized variable bound */
606 static
608  SCIP* scip,
609  GENVBOUND* genvbound
610  )
611 {
612  int i;
613 
614  assert(scip != NULL);
615  assert(genvbound != NULL);
616  assert(genvbound->coefs != NULL);
617  assert(genvbound->vars != NULL);
618  assert(genvbound->var != NULL);
619 
620  /* release variables */
621  for( i = 0; i < genvbound->ncoefs; ++i )
622  {
623  assert(genvbound->vars[i] != NULL);
624  SCIP_CALL( SCIPreleaseVar(scip, &(genvbound->vars[i])) );
625  }
626  SCIP_CALL( SCIPreleaseVar(scip, &genvbound->var) );
627 
628  /* free memory */
629  SCIPfreeBlockMemoryArray(scip, &(genvbound->coefs), genvbound->coefssize);
630  SCIPfreeBlockMemoryArray(scip, &(genvbound->vars), genvbound->coefssize);
631  SCIPfreeBlockMemory(scip, &genvbound);
632 
633  return SCIP_OKAY;
634 }
635 
636 /** helper function to release all genvbounds */
637 static
639  SCIP* scip,
640  SCIP_PROPDATA* propdata
641  )
642 {
643  int i;
644 
645  assert(scip != NULL);
646  assert(propdata != NULL);
647 
648  if( propdata->genvboundstore != NULL )
649  {
650  /* free genvbounds */
651  for( i = propdata->ngenvbounds - 1; i >= 0; i-- )
652  {
653  SCIP_CALL( freeGenVBound(scip, propdata->genvboundstore[i]) );
654  }
655 
656  /* free genvboundstore hashmaps */
657  SCIPhashmapFree(&(propdata->lbgenvbounds));
658  SCIPhashmapFree(&(propdata->ubgenvbounds));
659 
660  /* free genvboundstore array */
661  SCIPfreeBlockMemoryArray(scip, &(propdata->genvboundstore), propdata->genvboundstoresize);
662 
663  /* set the number of genvbounds to zero */
664  propdata->ngenvbounds = 0;
665 
666  /* free componentsstart array */
667  SCIP_CALL( freeComponentsData(scip, propdata) );
668 
669  /* free starting indices data */
670  SCIP_CALL( freeStartingData(scip, propdata) );
671 
672  /* release the cutoffboundvar and undo the locks */
673  if( propdata->cutoffboundvar != NULL )
674  {
675  SCIP_CALL( SCIPaddVarLocks(scip, propdata->cutoffboundvar, -1, -1) );
676  SCIP_CALL( SCIPreleaseVar(scip, &(propdata->cutoffboundvar)) );
677  propdata->cutoffboundvar = NULL;
678  SCIPdebugMsg(scip, "release cutoffboundvar!\n");
679  }
680  }
681 
682  return SCIP_OKAY;
683 }
684 
685 /** resolves propagation of lower bound on +/- left-hand side variable of a generalized variable bound */
686 static
688  SCIP* scip, /**< SCIP data structure */
689  GENVBOUND* genvbound, /**< genvbound data structure */
690  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
691  SCIP_Real* boundval, /**< pointer to lower bound value on +/- left-hand side variable */
692  SCIP_Bool* success /**< was the explanation succesful? */
693  )
694 {
695  SCIP_VAR* lhsvar;
696  SCIP_VAR** vars;
697  SCIP_Real minactivity;
698  SCIP_Real tmpboundval;
699  SCIP_Real slack;
700  int nvars;
701  int i;
702 
703  assert(scip != NULL);
704  assert(genvbound != NULL);
705  assert(boundval != NULL);
706  assert(success != NULL);
707 
708  *success = FALSE;
709 
710  /* get left-hand side variable */
711  lhsvar = genvbound->var;
712  assert(lhsvar != NULL);
713 
714  /* get right-hand side variables */
715  vars = genvbound->vars;
716  nvars = genvbound->ncoefs;
717  assert(vars != NULL);
718 
719  /* if only the primal bound participates in the propagation, it is globally valid and should not be analyzed */
720  assert(nvars > 0);
721 
722  /* when resolving a propagation, bdchgidx is not NULL and boundval should be the bound change performed for the
723  * left-hand side variable
724  */
725  assert(bdchgidx == NULL || genvbound->boundtype != SCIP_BOUNDTYPE_LOWER || SCIPisEQ(scip,
726  SCIPvarIsIntegral(genvbound->var) ? SCIPfeasCeil(scip, *boundval) : *boundval, SCIPgetVarLbAtIndex(scip, lhsvar, bdchgidx, TRUE)));
727  assert(bdchgidx == NULL || genvbound->boundtype != SCIP_BOUNDTYPE_UPPER || SCIPisEQ(scip,
728  SCIPvarIsIntegral(genvbound->var) ? SCIPfeasCeil(scip, *boundval) : *boundval, -SCIPgetVarUbAtIndex(scip, lhsvar, bdchgidx, TRUE)));
729 
730  /* when creating an initial conflict, bdchgidx is NULL and +/-boundval must exceed the upper/lower bound of the
731  * left-hand side variable
732  */
733  assert(bdchgidx != NULL || genvbound->boundtype != SCIP_BOUNDTYPE_LOWER
734  || SCIPisGT(scip, *boundval, SCIPvarGetUbLocal(lhsvar)));
735  assert(bdchgidx != NULL || genvbound->boundtype != SCIP_BOUNDTYPE_UPPER
736  || SCIPisGT(scip, *boundval, -SCIPvarGetLbLocal(lhsvar)));
737 
738  SCIPdebugMsg(scip, "resolving genvbound propagation: lhs=%s<%s> >= boundval=%.15g\n",
739  genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? "+" : "-", SCIPvarGetName(lhsvar), *boundval);
740 
741  /* subtract constant terms from bound value */
742  tmpboundval = *boundval;
743  tmpboundval -= genvbound->cutoffcoef * getCutoffboundGenVBound(scip);
744  tmpboundval -= genvbound->constant;
745 
746  SCIPdebugMsg(scip, "subtracting constant terms gives boundval=%.15g\n", tmpboundval);
747 
748  /* compute minimal activity; if bdchgidx is NULL, we create the initial conflict and use local bounds */
749  minactivity = getGenVBoundsMinActivityConflict(scip, genvbound->vars, genvbound->coefs, genvbound->ncoefs, bdchgidx);
750 
751  SCIPdebugMsg(scip, "minactivity of right-hand side is minactivity=%.15g\n", minactivity);
752 
753  /* a genvbound might have been replaced since the propagation took place, hence we have to check that the current
754  * genvbound can explain the propagation at the given bound change index; note that by now, with smaller cutoff
755  * bound, we might even perform a stronger propagation
756  */
757  if( SCIPisLT(scip, minactivity, tmpboundval) )
758  {
759  SCIPdebugMsg(scip, "minactivity is too small to explain propagation; was genvbound replaced?\n");
760  return SCIP_OKAY;
761  }
762 
763  /* if bdchgidx is NULL, i.e., we create the initial conflict, we should be able to explain the bound change */
764  assert(SCIPisGE(scip, minactivity, tmpboundval));
765 
766  slack = MAX(minactivity - tmpboundval, 0.0);
767 
768  SCIPdebugMsg(scip, "slack=%.15g\n", slack);
769 
770  /* add variables on the right-hand side as reasons for propagation */
771  for( i = 0; i < nvars; i++ )
772  {
773  assert(vars[i] != NULL);
774  assert(SCIPisEQ(scip, SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, FALSE)));
775  assert(SCIPisEQ(scip, SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, FALSE)));
776 
777  /* coefficient is positive */
778  if( genvbound->coefs[i] > 0.0 )
779  {
780  SCIP_Real lbatindex;
781  SCIP_Real conflictlb;
782 
783  /* get bound at current bound change */
784  lbatindex = SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, TRUE);
785 
786  /* get bound already enforced by conflict set */
787  conflictlb = SCIPgetConflictVarLb(scip, genvbound->vars[i]);
788  assert(SCIPisGE(scip, conflictlb, SCIPvarGetLbGlobal(genvbound->vars[i])));
789 
790  SCIPdebugMsg(scip, "lower bound of variable <%s> (genvbound->vars[%d]) in conflict set / at index is %.15g / %.15g\n",
791  SCIPvarGetName(genvbound->vars[i]), i, conflictlb, lbatindex);
792 
793  /* if bound is already enforced by conflict set we do not need to add the bound change; since we used the
794  * tighest bound already when computing the initial minactivity, the slack is already correct
795  */
796  if( SCIPisLE(scip, lbatindex, conflictlb) )
797  {
798  SCIPdebugMsg(scip, "skipping lower bound of variable <%s> (genvbound->vars[%d]) already enforced in conflict set\n",
799  SCIPvarGetName(genvbound->vars[i]), i);
800  }
801  else
802  {
803  SCIP_Real relaxedlb;
804 
805  /* compute relaxed bound that would suffice to explain the bound change */
806  relaxedlb = lbatindex - (slack / genvbound->coefs[i]);
807  assert(relaxedlb <= lbatindex);
808 
809  /* add variable to conflict set */
810  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, genvbound->vars[i], bdchgidx, relaxedlb ) );
811 
812  /* get new bound of variable in conflict set; after possible bound widening in SCIPaddConflictLbRelaxed(),
813  * it should be between conflictlb and lbatindex
814  */
815  relaxedlb = SCIPgetConflictVarLb(scip, genvbound->vars[i]);
816  assert(SCIPisGE(scip, relaxedlb, conflictlb));
817  assert(SCIPisLE(scip, relaxedlb, lbatindex));
818 
819  /* update slack and ensure that its nonegative */
820  slack -= genvbound->coefs[i] * (lbatindex - relaxedlb);
821  slack = MAX(slack, 0.0);
822 
823  SCIPdebugMsg(scip, "added lower bound of variable <%s> (genvbound->vars[%d]); new slack=%.15g\n",
824  SCIPvarGetName(genvbound->vars[i]), i, slack);
825  }
826  }
827  /* coefficient is negative */
828  else
829  {
830  SCIP_Real ubatindex;
831  SCIP_Real conflictub;
832 
833  /* get bound at current bound change */
834  ubatindex = SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, TRUE);
835 
836  /* get bound already enforced by conflict set */
837  conflictub = SCIPgetConflictVarUb(scip, genvbound->vars[i]);
838  assert(SCIPisLE(scip, conflictub, SCIPvarGetUbGlobal(genvbound->vars[i])));
839 
840  SCIPdebugMsg(scip, "upper bound of variable <%s> (genvbound->vars[%d]) in conflict set / at index is %.15g / %.15g\n",
841  SCIPvarGetName(genvbound->vars[i]), i, conflictub, ubatindex);
842 
843  /* if bound is already enforced by conflict set we do not need to add the bound change; since we used the
844  * tighest bound already when computing the initial minactivity, the slack is already correct
845  */
846  if( SCIPisGE(scip, ubatindex, conflictub) )
847  {
848  SCIPdebugMsg(scip, "skipping upper bound of variable <%s> (genvbound->vars[%d]) already enforced in conflict set\n",
849  SCIPvarGetName(genvbound->vars[i]), i);
850  }
851  else
852  {
853  SCIP_Real relaxedub;
854 
855  /* compute relaxed bound that would suffice to explain the bound change */
856  relaxedub = ubatindex - (slack / genvbound->coefs[i]);
857  assert(relaxedub >= ubatindex);
858 
859  /* add variable to conflict set */
860  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, genvbound->vars[i], bdchgidx, relaxedub ) );
861 
862  /* get new bound of variable in conflict set; after possible bound widening in SCIPaddConflictUbRelaxed(),
863  * it should be between conflictub and ubatindex
864  */
865  relaxedub = SCIPgetConflictVarUb(scip, genvbound->vars[i]);
866  assert(SCIPisLE(scip, relaxedub, conflictub));
867  assert(SCIPisGE(scip, relaxedub, ubatindex));
868 
869  /* update slack and ensure that its nonegative */
870  slack -= genvbound->coefs[i] * (ubatindex - relaxedub);
871  slack = MAX(slack, 0.0);
872 
873  SCIPdebugMsg(scip, "added upper bound of variable <%s> (genvbound->vars[%d]); new slack=%.15g\n",
874  SCIPvarGetName(genvbound->vars[i]), i, slack);
875  }
876  }
877  }
878 
879  /* if slack is positive, return increased boundval */
880  if( SCIPisPositive(scip, slack) )
881  tmpboundval += slack;
882 
883  /* add constant terms again */
884  tmpboundval += genvbound->cutoffcoef * getCutoffboundGenVBound(scip);
885  tmpboundval += genvbound->constant;
886 
887  /* boundval should not have been decreased; if this happened nevertheless, maybe due to numerical errors, we quit
888  * without success
889  */
890  if( SCIPisLT(scip, tmpboundval, *boundval) )
891  {
892  SCIPdebugMsg(scip, "boundval was reduced from %.15g to %.15g; propagation not resolved\n", *boundval, tmpboundval);
893  return SCIP_OKAY;
894  }
895 
896  /* return widened boundval */
897  *boundval = tmpboundval;
898  *success = TRUE;
899 
900  return SCIP_OKAY;
901 }
902 
903 /** create initial conflict */
904 static
906  SCIP* scip, /**< SCIP data structure */
907  GENVBOUND* genvbound /**< genvbound data structure */
908  )
909 {
910  SCIP_Bool success;
911 
912  assert(scip != NULL);
913  assert(genvbound != NULL);
914 
915  /* check if conflict analysis is applicable */
917  return SCIP_OKAY;
918 
919  /* initialize conflict analysis */
921 
922  /* left-hand side variable >= ... */
923  if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
924  {
925  SCIP_Real infeasthreshold;
927 
928  /* get minimal right-hand side bound that leads to infeasibility; first try with a factor of 2 for robustness */
929  bound = REALABS(SCIPvarGetUbLocal(genvbound->var));
930  infeasthreshold = MAX(bound, 1.0) * 2 * SCIPfeastol(scip);
931  bound = SCIPvarGetUbLocal(genvbound->var) + infeasthreshold;
932 
933  /* add right-hand side variables that force the lower bound of the left-hand side variable above its upper bound
934  * to conflict set
935  */
936  SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
937  assert(!success || SCIPisFeasGT(scip, bound, SCIPvarGetUbLocal(genvbound->var)));
938 
939  /* if infeasibility cannot be proven with the tighter bound, try with actual bound */
940  if( !success )
941  {
942  bound = REALABS(SCIPvarGetUbLocal(genvbound->var));
943  infeasthreshold = MAX(bound, 1.0) * SCIPfeastol(scip);
944  bound = SCIPvarGetUbLocal(genvbound->var) + infeasthreshold;
945 
946  SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
947  success = success && SCIPisFeasGT(scip, bound, SCIPvarGetUbLocal(genvbound->var));
948  }
949 
950  /* compute upper bound on left-hand side variable that leads to infeasibility */
951  bound -= infeasthreshold;
952  success = success && SCIPisGE(scip, bound, SCIPvarGetUbLocal(genvbound->var));
953 
954  /* initial reason could not be constructed, maybe due to numerics; do not apply conflict analysis */
955  if( !success )
956  {
957  SCIPdebugMsg(scip, "strange: could not create initial reason to start conflict analysis\n");
958  return SCIP_OKAY;
959  }
960 
961  /* if bound is already enforced by conflict set we do not have to add it */
962  if( SCIPisGE(scip, bound, SCIPgetConflictVarUb(scip, genvbound->var)) )
963  {
964  SCIPdebugMsg(scip, "skipping upper bound of left-hand side variable <%s> already enforced in conflict set\n",
965  SCIPvarGetName(genvbound->var));
966  }
967  else
968  {
969  SCIPdebugMsg(scip, "adding upper bound of left-hand side variable <%s>\n", SCIPvarGetName(genvbound->var));
970 
971  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, genvbound->var, NULL, bound) );
972  }
973  }
974  /* left-hand side variable <= ..., i.e., - left-hand side variable >= ... */
975  else
976  {
977  SCIP_Real infeasthreshold;
979 
980  /* get minimal right-hand side bound that leads to infeasibility; try with a factor of 2 first for robustness */
981  bound = REALABS(SCIPvarGetLbLocal(genvbound->var));
982  infeasthreshold = MAX(bound, 1.0) * 2 * SCIPfeastol(scip);
983  bound = -SCIPvarGetLbLocal(genvbound->var) + infeasthreshold;
984 
985  /* add right-hand side variables that force the upper bound of the left-hand side variable below its lower bound
986  * to conflict set
987  */
988  SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
989  assert(!success || SCIPisFeasLT(scip, -bound, SCIPvarGetLbLocal(genvbound->var)));
990 
991  /* if infeasibility cannot be proven with the tighter bound, try with actual bound */
992  if( !success )
993  {
994  bound = REALABS(SCIPvarGetLbLocal(genvbound->var));
995  infeasthreshold = MAX(bound, 1.0) * SCIPfeastol(scip);
996  bound = -SCIPvarGetLbLocal(genvbound->var) + infeasthreshold;
997 
998  SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
999  success = success && SCIPisFeasLT(scip, -bound, SCIPvarGetLbLocal(genvbound->var));
1000  }
1001 
1002  /* compute lower bound on left-hand side variable that leads to infeasibility */
1003  bound = -bound + infeasthreshold;
1004  success = success && SCIPisLE(scip, bound, SCIPvarGetLbLocal(genvbound->var));
1005 
1006  /* initial reason could not be constructed, maybe due to numerics; do not apply conflict analysis */
1007  if( !success )
1008  {
1009  SCIPdebugMsg(scip, "strange: could not create initial reason to start conflict analysis\n");
1010  return SCIP_OKAY;
1011  }
1012 
1013  /* if bound is already enforced by conflict set we do not have to add it */
1014  if( SCIPisLE(scip, bound, SCIPgetConflictVarLb(scip, genvbound->var)) )
1015  {
1016  SCIPdebugMsg(scip, "skipping lower bound of left-hand side variable <%s> already enforced in conflict set\n",
1017  SCIPvarGetName(genvbound->var));
1018  }
1019  else
1020  {
1021  SCIPdebugMsg(scip, "adding lower bound of left-hand side variable <%s>\n", SCIPvarGetName(genvbound->var));
1022 
1023  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, genvbound->var, NULL, bound) );
1024  }
1025  }
1026 
1027  /* analyze the conflict */
1028  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
1029 
1030  return SCIP_OKAY;
1031 }
1032 
1033 /** apply propagation for one generalized variable bound; also if the left-hand side variable is locally fixed, we
1034  * compute the right-hand side minactivity to possibly detect infeasibility
1035  */
1036 static
1038  SCIP* scip, /**< SCIP data structure */
1039  SCIP_PROP* prop, /**< genvbounds propagator */
1040  GENVBOUND* genvbound, /**< genvbound data structure */
1041  SCIP_Bool global, /**< apply global bound changes? (global: true, local: false)*/
1042  SCIP_RESULT* result, /**< result pointer */
1043  int* nchgbds /**< counter to increment if bound was tightened */
1044  )
1045 {
1046  SCIP_Real boundval;
1047  SCIP_Bool infeas;
1048  SCIP_Bool tightened;
1049 
1050  assert(scip != NULL);
1051  assert(genvbound != NULL);
1052  assert(genvbound->var != NULL);
1053  assert(SCIPvarGetStatus(genvbound->var) != SCIP_VARSTATUS_MULTAGGR);
1054  assert(result != NULL);
1055  assert(*result != SCIP_DIDNOTRUN);
1056 
1057  /* get bound value provided by genvbound */
1058  boundval = getGenVBoundsBound(scip, genvbound, global);
1059 
1060  if( SCIPisInfinity(scip, REALABS(boundval)) )
1061  return SCIP_OKAY;
1062 
1063 #ifdef SCIP_DEBUG
1064  {
1065  SCIP_Real lb;
1066  SCIP_Real ub;
1067  SCIP_Real new_lb;
1068  SCIP_Real new_ub;
1069 
1070  lb = global ? SCIPvarGetLbGlobal(genvbound->var) : SCIPvarGetLbLocal(genvbound->var);
1071  ub = global ? SCIPvarGetUbGlobal(genvbound->var) : SCIPvarGetUbLocal(genvbound->var);
1072  new_lb = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? boundval : lb;
1073  new_ub = genvbound->boundtype == SCIP_BOUNDTYPE_UPPER ? boundval : ub;
1074 
1075  SCIPdebugMsg(scip, " %s genvbound propagation for <%s>\n", global ?
1076  "global" : "local", SCIPvarGetName(genvbound->var));
1077  SCIPdebugMsg(scip, " genvbound: ");
1078  printGenVBound(scip, genvbound);
1079  SCIPdebugMsg(scip, " [%.15g,%.15g] -> [%.15g,%.15g]\n", lb, ub, new_lb, new_ub);
1080  }
1081 #endif
1082 
1083  /* tighten bound globally */
1084  if( global || genvbound->ncoefs <= 0 )
1085  {
1086  if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
1087  {
1088  SCIP_CALL( SCIPtightenVarLbGlobal(scip, genvbound->var, boundval, FALSE, &infeas, &tightened) );
1089  }
1090  else
1091  {
1092  SCIP_CALL( SCIPtightenVarUbGlobal(scip, genvbound->var, boundval, FALSE, &infeas, &tightened) );
1093  }
1094  }
1095  /* tighten bound locally and start conflict analysis in case of infeasibility; as inferinfo we pass the index of the
1096  * genvbound that was used for propagation
1097  */
1098  else
1099  {
1100  if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
1101  {
1102  SCIP_CALL( SCIPinferVarLbProp(scip, genvbound->var, boundval, prop, genvbound->index, FALSE, &infeas, &tightened) );
1103 
1104  /* initialize conflict analysis if infeasible */
1105  if( infeas )
1106  {
1107  SCIPdebugMsg(scip, " -> lower bound tightening on variable <%s> led to infeasibility\n",
1108  SCIPvarGetName(genvbound->var));
1109 
1110  SCIP_CALL( analyzeGenVBoundConflict(scip, genvbound) );
1111  }
1112  }
1113  else
1114  {
1115  SCIP_CALL( SCIPinferVarUbProp(scip, genvbound->var, boundval, prop, genvbound->index, FALSE, &infeas, &tightened) );
1116 
1117  /* initialize conflict analysis if infeasible */
1118  if( infeas )
1119  {
1120  SCIPdebugMsg(scip, " -> upper bound tightening on variable <%s> led to infeasibility\n",
1121  SCIPvarGetName(genvbound->var));
1122 
1123  SCIP_CALL( analyzeGenVBoundConflict(scip, genvbound) );
1124  }
1125  }
1126  }
1127 
1128  /* handle result */
1129  if( infeas )
1130  {
1131  *result = SCIP_CUTOFF;
1132  SCIPdebugMsg(scip, " cutoff!\n");
1133  }
1134  else if( tightened )
1135  {
1137  if( nchgbds != NULL )
1138  ++(*nchgbds);
1139  SCIPdebugMsg(scip, " tightened!\n");
1140  }
1141 
1142  return SCIP_OKAY;
1143 }
1144 
1145 #ifdef SCIP_DEBUG
1146 /** prints event data as debug message */
1147 static
1148 void printEventData(
1149  SCIP_EVENTDATA* eventdata,
1151  )
1152 {
1153  int i;
1154 
1155  SCIPdebugMessage("event data: %s bound of <%s> tightened ==> start propagating at ",
1156  boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", SCIPvarGetName(eventdata->var));
1157 
1158  /* if there is eventdata it should contain at least one starting index */
1159  assert(eventdata->nstarts > 0);
1160 
1161  for( i = 0; i < eventdata->nstarts; i++ )
1162  {
1163  SCIPdebugPrintf("(component %d, index %d) ", eventdata->startcomponents[i], eventdata->startindices[i]);
1164  }
1165  SCIPdebugPrintf("\n");
1166 }
1167 #endif
1168 
1169 /** frees event data */
1170 static
1172  SCIP* scip, /**< SCIP data structure */
1173  SCIP_EVENTDATA** eventdata /**< event data to be freed */
1174  )
1176  assert(scip != NULL);
1177  assert(eventdata != NULL);
1178  assert(*eventdata != NULL);
1179 
1180  SCIPfreeBlockMemoryArray(scip, &((*eventdata)->startcomponents), (*eventdata)->startindicessize);
1181  SCIPfreeBlockMemoryArray(scip, &((*eventdata)->startindices), (*eventdata)->startindicessize);
1182 
1183  (*eventdata)->startindicessize = 0;
1184  (*eventdata)->nstarts = -1;
1185  (*eventdata)->var = NULL;
1186  (*eventdata)->prop = NULL;
1187 
1188  SCIPfreeBlockMemory(scip, eventdata);
1189 
1190  return SCIP_OKAY;
1191 }
1192 
1193 /** frees all eventdata stored */
1194 static
1196  SCIP* scip, /**< SCIP data structure */
1197  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1198  )
1200  int i;
1201 
1202  assert(scip != NULL);
1203  assert(propdata != NULL);
1204 
1205  if( propdata->lbevents != NULL )
1206  {
1207  assert(propdata->ubevents != NULL);
1208  assert(propdata->lbeventsmap != NULL);
1209  assert(propdata->ubeventsmap != NULL);
1210 
1211  SCIPhashmapFree(&(propdata->lbeventsmap));
1212  SCIPhashmapFree(&(propdata->ubeventsmap));
1213 
1214  for( i = propdata->nlbevents - 1; i >= 0; i-- )
1215  {
1216  SCIP_CALL( freeEventData(scip, &(propdata->lbevents[i])) );
1217  }
1218 
1219  for( i = propdata->nubevents - 1; i >= 0; i-- )
1220  {
1221  SCIP_CALL( freeEventData(scip, &(propdata->ubevents[i])) );
1222  }
1223 
1224  SCIPfreeBlockMemoryArray(scip, &(propdata->ubevents), propdata->nubevents);
1225  SCIPfreeBlockMemoryArray(scip, &(propdata->lbevents), propdata->nlbevents);
1226  propdata->nlbevents = -1;
1227  propdata->nubevents = -1;
1228  }
1229 
1230  assert(propdata->lbevents == NULL);
1231  assert(propdata->ubevents == NULL);
1232  assert(propdata->lbeventsmap == NULL);
1233  assert(propdata->ubeventsmap == NULL);
1234  assert(propdata->nlbevents == -1);
1235  assert(propdata->nubevents == -1);
1236 
1237  return SCIP_OKAY;
1238 }
1239 
1240 /** drops all events caught by genvbounds propagator and frees their data */
1241 static
1243  SCIP* scip, /**< SCIP data structure */
1244  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1245  )
1247  int i;
1248 
1249  SCIPdebugMsg(scip, "drop and free events\n");
1250 
1251  assert(scip != NULL);
1252  assert(propdata != NULL);
1253  assert(propdata->eventhdlr != NULL);
1254 
1255  if( propdata->lbevents != NULL )
1256  {
1257  assert(propdata->ubevents != NULL);
1258  assert(propdata->nlbevents >= 0);
1259  assert(propdata->nubevents >= 0);
1260 
1261  for( i = propdata->nlbevents - 1; i >= 0; i-- )
1262  {
1263  /* drop event */
1264  SCIP_CALL( SCIPdropVarEvent(scip, propdata->lbevents[i]->var, SCIP_EVENTTYPE_LBTIGHTENED, propdata->eventhdlr,
1265  propdata->lbevents[i], -1) );
1266  }
1267 
1268  for( i = propdata->nubevents - 1; i >= 0; i-- )
1269  {
1270  /* drop event */
1271  SCIP_CALL( SCIPdropVarEvent(scip, propdata->ubevents[i]->var, SCIP_EVENTTYPE_UBTIGHTENED, propdata->eventhdlr,
1272  propdata->ubevents[i], -1) );
1273  }
1274 
1275  /* free event data */
1276  SCIP_CALL( freeAllEventData(scip, propdata) );
1277  }
1278 
1279  assert(propdata->lbevents == NULL);
1280  assert(propdata->ubevents == NULL);
1281  assert(propdata->nlbevents == -1);
1282  assert(propdata->nubevents == -1);
1283 
1284  return SCIP_OKAY;
1285 }
1286 
1287 /** returns the corresponding event data entry in the corresponding array, if there is one; if not: allocates a new
1288  * event data entry, stores it in the array and returns its adress
1289  */
1290 static
1292  SCIP* scip, /**< SCIP data structure */
1293  SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1294  SCIP_VAR* var, /**< variable */
1295  SCIP_BOUNDTYPE boundtype, /**< type of bound */
1296  SCIP_EVENTDATA** eventdata /**< event data to return */
1297  )
1298 {
1299  SCIP_HASHMAP* hashmap;
1300 
1301  assert(scip != NULL);
1302  assert(propdata != NULL);
1303  assert(var != NULL);
1304 
1305  hashmap = boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbeventsmap : propdata->ubeventsmap;
1306 
1307  if( SCIPhashmapExists(hashmap, var) )
1308  *eventdata = (SCIP_EVENTDATA*) SCIPhashmapGetImage(hashmap, var);
1309  else
1310  {
1311  /* set up new eventdata entry */
1312  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
1313  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &((*eventdata)->startcomponents), propdata->ncomponents) );
1314  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &((*eventdata)->startindices), propdata->ncomponents) );
1315  (*eventdata)->startindicessize = propdata->ncomponents;
1316  (*eventdata)->nstarts = 0;
1317  (*eventdata)->var = var;
1318  (*eventdata)->prop = propdata->prop;
1319 
1320  /* store event data in eventarray */
1321  if( boundtype == SCIP_BOUNDTYPE_LOWER )
1322  {
1323  propdata->lbevents[propdata->nlbevents] = *eventdata;
1324  propdata->nlbevents++;
1325  }
1326  else
1327  {
1328  propdata->ubevents[propdata->nubevents] = *eventdata;
1329  propdata->nubevents++;
1330  }
1331 
1332  /* store hashmap entry */
1333  SCIP_CALL( SCIPhashmapInsert(hashmap, var, (*eventdata)) );
1334  }
1335 
1336  return SCIP_OKAY;
1337 }
1338 
1339 /** adds an event to the event array lbevents (if boundtype == SCIP_BOUNDTYPE_LOWER) or ubevents (if boundtype ==
1340  * SCIP_BOUNDTYPE_UPPER)
1341  */
1342 static
1344  SCIP* scip, /**< SCIP data structure */
1345  SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1346  SCIP_VAR* var, /**< variable thats event to be added */
1347  int startindex, /**< starting index */
1348  int startcomponent, /**< starting components index */
1349  SCIP_BOUNDTYPE boundtype /**< type of bound */
1350  )
1351 {
1352  SCIP_EVENTDATA* eventdata;
1353 
1354  assert(scip != NULL);
1355  assert(propdata != NULL);
1356  assert(var != NULL);
1357  assert(startindex >= 0);
1358  assert(startcomponent >= 0);
1359 
1360  /* get eventdata entry */
1361  SCIP_CALL( getEventData(scip, propdata, var, boundtype, &eventdata) );
1362  assert(eventdata != NULL);
1363 
1364  if( eventdata->nstarts > 0 && eventdata->startcomponents[eventdata->nstarts - 1] == startcomponent )
1365  {
1366  /* if there is already a starting index for startcomponent stored at the last entry of eventdata->startindices,
1367  * it should be smaller; this relies on the implementation of setUpEvents(), calling addEventData() in
1368  * topological order
1369  */
1370  assert(eventdata->startindices[eventdata->nstarts - 1] < startindex);
1371  }
1372  else
1373  {
1374  /* append starting information */
1375  eventdata->startcomponents[eventdata->nstarts] = startcomponent;
1376  eventdata->startindices[eventdata->nstarts] = startindex;
1377 
1378  /* increase counter */
1379  eventdata->nstarts++;
1380  }
1381 
1382  return SCIP_OKAY;
1383 }
1384 
1385 static
1387  SCIP* scip, /**< SCIP data structure */
1388  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1389  )
1391  int nprobvars;
1392  int i;
1393 
1394  assert(scip != NULL);
1395  assert(propdata != NULL);
1396  assert(propdata->eventhdlr != NULL);
1397  assert(propdata->lbevents == NULL);
1398  assert(propdata->ubevents == NULL);
1399  assert(propdata->issorted);
1400  assert(propdata->nlbevents == -1);
1401  assert(propdata->nubevents == -1);
1402 
1403  SCIPdebugMsg(scip, "set up events\n");
1404 
1405  /* allocate lbevents, ubevents, and their hashmaps */
1406  nprobvars = SCIPgetNVars(scip) + SCIPgetNFixedVars(scip);
1407  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->lbevents), nprobvars) );
1408  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->ubevents), nprobvars) );
1409  SCIP_CALL( SCIPhashmapCreate(&(propdata->lbeventsmap), SCIPblkmem(scip), nprobvars) );
1410  SCIP_CALL( SCIPhashmapCreate(&(propdata->ubeventsmap), SCIPblkmem(scip), nprobvars) );
1411  propdata->nlbevents = 0;
1412  propdata->nubevents = 0;
1413 
1414  /* loop over all components of genvboundstore */
1415  for( i = 0; i < propdata->ncomponents; i++ )
1416  {
1417  int j;
1418 
1419  /* loop over all genvbounds in this component */
1420  for( j = propdata->componentsstart[i]; j < propdata->componentsstart[i+1]; j++ ) /*lint !e679*/
1421  {
1422  GENVBOUND* genvbound;
1423  int k;
1424 
1425  assert(j < propdata->ngenvbounds);
1426 
1427  genvbound = propdata->genvboundstore[j];
1428  assert(genvbound != NULL);
1429 
1430  /* loop over all coefficients in this genvbound */
1431  for( k = 0; k < genvbound->ncoefs; k++ )
1432  {
1433  if( SCIPisPositive(scip, genvbound->coefs[k]) )
1434  {
1435  SCIP_CALL( addEventData(scip, propdata, genvbound->vars[k], j, i, SCIP_BOUNDTYPE_LOWER) );
1436  }
1437  else
1438  {
1439  SCIP_CALL( addEventData(scip, propdata, genvbound->vars[k], j, i, SCIP_BOUNDTYPE_UPPER) );
1440  }
1441  }
1442  }
1443  }
1444 
1445  /* resize lbevents and ubevents array */
1446  assert(propdata->nlbevents <= nprobvars);
1447  assert(propdata->nubevents <= nprobvars);
1448  if( propdata->nlbevents < nprobvars )
1449  {
1450  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(propdata->lbevents), nprobvars, propdata->nlbevents) );
1451  }
1452  if( propdata->nubevents < nprobvars )
1453  {
1454  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(propdata->ubevents), nprobvars, propdata->nubevents) );
1455  }
1456 
1457  /* resize and register lower bound events */
1458  for( i = 0; i < propdata->nlbevents; i++ )
1459  {
1460  SCIP_EVENTDATA* eventdata = propdata->lbevents[i];
1461 
1462  assert(eventdata != NULL);
1463  assert(eventdata->nstarts > 0);
1464  assert(eventdata->startcomponents != NULL);
1465  assert(eventdata->startindices != NULL);
1466 
1467  /* resize arrays stored in eventdata */
1468  if( eventdata->startindicessize != eventdata->nstarts )
1469  {
1470  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(eventdata->startcomponents), eventdata->startindicessize, \
1471  eventdata->nstarts) );
1472  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(eventdata->startindices), eventdata->startindicessize, \
1473  eventdata->nstarts) );
1474  eventdata->startindicessize = eventdata->nstarts;
1475  }
1476 
1477  /* register event */
1478  SCIP_CALL( SCIPcatchVarEvent(scip, eventdata->var, SCIP_EVENTTYPE_LBTIGHTENED, propdata->eventhdlr, eventdata, \
1479  NULL) );
1480  }
1481 
1482  /* resize and register upper bound events */
1483  for( i = 0; i < propdata->nubevents; i++ )
1484  {
1485  SCIP_EVENTDATA* eventdata = propdata->ubevents[i];
1486 
1487  assert(eventdata != NULL);
1488  assert(eventdata->nstarts > 0);
1489  assert(eventdata->startcomponents != NULL);
1490  assert(eventdata->startindices != NULL);
1491 
1492  /* resize arrays stored in eventdata */
1493  if( eventdata->startindicessize != eventdata->nstarts )
1494  {
1495  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(eventdata->startcomponents), eventdata->startindicessize, \
1496  eventdata->nstarts) );
1497  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(eventdata->startindices), eventdata->startindicessize, \
1498  eventdata->nstarts) );
1499  eventdata->startindicessize = eventdata->nstarts;
1500  }
1501  /* register event */
1502  SCIP_CALL( SCIPcatchVarEvent(scip, eventdata->var, SCIP_EVENTTYPE_UBTIGHTENED, propdata->eventhdlr, eventdata,
1503  NULL) );
1504  }
1505 
1506  return SCIP_OKAY;
1507 }
1508 
1509 /** performs a topological sort on genvboundstore array
1510  *
1511  * The genvbounds graph is defined as follows: Given two genvbounds
1512  *
1513  * (genvbound1) c1 * x_i1 >= RHS1
1514  *
1515  * and
1516  *
1517  * (genvbound2) c2 * x_i2 >= RHS2,
1518  *
1519  * there is an arc from genvbound1 to genvbound2 iff c1 = +1 and x_i1 appears with positive coefficient in RHS2 or
1520  * c1 = -1 and x_i1 appears with negative coefficient in RHS2; in this case, a bound change of x_i1 deduced from
1521  * genvbound1 improves genvbound2's minactivity in RHS2.
1522  *
1523  * The method computes the strongly connected components and sorts them topologically. The order of the nodes in an
1524  * strongly connected component is arbitrary.
1525  */
1526 static
1528  SCIP* scip, /**< SCIP data structure */
1529  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1530  )
1532  GENVBOUND** genvboundssorted; /* array to store the sorted genvbounds */
1533  SCIP_DIGRAPH* graph;
1534  int* strongcomponents;
1535  int* strongcompstartidx;
1536  int sortedindex;
1537  int i;
1538 
1539  assert(scip != NULL);
1540  assert(propdata != NULL);
1541  assert(propdata->componentsstart == NULL);
1542 
1543  SCIPdebugMsg(scip, "(re-)sort genvbounds topologically\n");
1544 
1545  /* create digraph */
1546  SCIP_CALL( SCIPcreateDigraph(scip, &graph, propdata->ngenvbounds) );
1547 
1548  /* add outgoing arcs for each genvbound */
1549  for( i = 0; i < propdata->ngenvbounds; i++ )
1550  {
1551  GENVBOUND* genvbound;
1552  int j;
1553 
1554  assert(i < propdata->ngenvbounds);
1555 
1556  genvbound = propdata->genvboundstore[i];
1557 
1558  for( j = 0; j < genvbound->ncoefs; j++ )
1559  {
1560  if( SCIPisPositive(scip, genvbound->coefs[j]) &&
1561  SCIPhashmapExists(propdata->lbgenvbounds, genvbound->vars[j]) )
1562  {
1563  int from = ((GENVBOUND*) SCIPhashmapGetImage(propdata->lbgenvbounds, genvbound->vars[j]))->index;
1564  SCIP_CALL( SCIPdigraphAddArc(graph, from, i, NULL) );
1565  }
1566  else if( SCIPisNegative(scip, genvbound->coefs[j]) &&
1567  SCIPhashmapExists(propdata->ubgenvbounds, genvbound->vars[j]) )
1568  {
1569  int from = ((GENVBOUND*) SCIPhashmapGetImage(propdata->ubgenvbounds, genvbound->vars[j]))->index;
1570  SCIP_CALL( SCIPdigraphAddArc(graph, from, i, NULL) );
1571  }
1572  }
1573  }
1574 
1575  /* perform the topological sort */
1576  SCIP_CALL( SCIPdigraphComputeUndirectedComponents(graph, 1, NULL, &(propdata->ncomponents)) );
1578  assert(SCIPdigraphGetNComponents(graph) == propdata->ncomponents);
1579 
1580  /* allocate memory for genvboundssorted and componentsstart array */
1581  SCIP_CALL( SCIPallocBufferArray(scip, &genvboundssorted, propdata->ngenvbounds) );
1582  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->componentsstart), propdata->ncomponents + 1) );
1583  propdata->componentsstartsize = propdata->ncomponents + 1;
1584 
1585  /* allocate memory for strong component arrays */
1586  SCIP_CALL( SCIPallocBufferArray(scip, &strongcomponents, SCIPdigraphGetNNodes(graph)) ); /*lint !e666*/
1587  SCIP_CALL( SCIPallocBufferArray(scip, &strongcompstartidx, SCIPdigraphGetNNodes(graph) + 1) ); /*lint !e666*/
1588 
1589  /* compute sorted genvbounds array, fill componentsstart array */
1590  sortedindex = 0;
1591  propdata->componentsstart[propdata->ncomponents] = propdata->ngenvbounds;
1592  for( i = 0; i < propdata->ncomponents; i++ )
1593  {
1594  int j;
1595  int *nodes;
1596  int nnodes;
1597  int nstrongcomponents;
1598 
1599  SCIPdigraphGetComponent(graph, i, &nodes, &nnodes);
1600  propdata->componentsstart[i] = sortedindex;
1601 
1602  /* compute the strong components of the i-th undirected component */
1603  if( nnodes > 2 )
1604  {
1605  SCIP_CALL( SCIPdigraphComputeDirectedComponents(graph, i, strongcomponents, strongcompstartidx,
1606  &nstrongcomponents) );
1607 
1608  for( j = 0; j < nnodes; ++j )
1609  {
1610  int node;
1611 
1612  /* take the nodes at the end of the strong components array first to respect the topological
1613  * order of the different strong components
1614  */
1615  node = strongcomponents[nnodes - j - 1];
1616 
1617  assert(node < propdata->ngenvbounds);
1618  genvboundssorted[sortedindex] = propdata->genvboundstore[node];
1619  sortedindex++;
1620  }
1621  }
1622  else
1623  {
1624  for( j = 0; j < nnodes; j++ )
1625  {
1626  assert(nodes[j] < propdata->ngenvbounds);
1627  genvboundssorted[sortedindex] = propdata->genvboundstore[nodes[j]];
1628  sortedindex++;
1629  }
1630  }
1631  }
1632  assert(sortedindex == propdata->ngenvbounds);
1633 
1634  /* copy sorted genvbounds into genvboundstore */
1635  for( i = 0; i < propdata->ngenvbounds; i++ )
1636  {
1637  assert(genvboundssorted[i] != NULL);
1638 
1639  propdata->genvboundstore[i] = genvboundssorted[i];
1640  propdata->genvboundstore[i]->index = i;
1641  }
1642  SCIPfreeBufferArray(scip, &(genvboundssorted));
1643 
1644  /* free strong component arrays */
1645  SCIPfreeBufferArray(scip, &strongcompstartidx);
1646  SCIPfreeBufferArray(scip, &strongcomponents);
1647 
1648  /* free digraph */
1649  SCIPdigraphFree(&graph);
1650 
1651  /* remember genvboundstore as sorted */
1652  propdata->issorted = TRUE;
1653 
1654 #ifdef SCIP_DEBUG
1655  SCIPdebugMsg(scip, "genvbounds got: %d\n", propdata->ngenvbounds);
1656  for( i = 0; i < propdata->ncomponents; i++ )
1657  {
1658  int j;
1659 
1660  SCIPdebugMsg(scip, "{\n");
1661 
1662  for( j = propdata->componentsstart[i]; j < propdata->componentsstart[i+1]; j++ )
1663  {
1664  SCIPdebugMsg(scip, " [%d] ", j);
1665  printGenVBound(scip, propdata->genvboundstore[j]);
1666  }
1667 
1668  SCIPdebugMsg(scip, "}\n");
1669  }
1670 #endif
1671 
1672  return SCIP_OKAY;
1673 }
1674 
1675 /** apply propagation of generalized variable bounds */
1676 static
1678  SCIP* scip, /**< SCIP data structure */
1679  SCIP_PROP* prop, /**< genvbounds propagator */
1680  SCIP_Bool global, /**< use global variable bounds for propagation? */
1681  SCIP_RESULT* result, /**< result pointer */
1682  int* nchgbds /**< counter to increase by the number of changed bounds */
1683  )
1684 {
1685  SCIP_PROPDATA* propdata;
1686  int* startingcomponents;
1687  int* startingindices;
1688  int nindices;
1689  int i;
1690 
1691  SCIPdebugMsg(scip, "applying %s genvbound propagation in depth %d\n", global ?
1692  "global" : "local", SCIPgetDepth(scip));
1693 
1694  assert(scip != NULL);
1695  assert(prop != NULL);
1696  assert(result != NULL);
1697 
1698  propdata = SCIPpropGetData(prop);
1699  assert(propdata != NULL);
1700  assert(propdata->genvboundstore != NULL);
1701 
1702  if( *result == SCIP_DIDNOTRUN )
1703  *result = SCIP_DIDNOTFIND;
1704 
1705  /* if the genvbounds are not sorted, i.e. if root node processing has not been finished, yet, we just propagate in
1706  * the order in which they have been added to genvboundstore
1707  */
1708  if( !propdata->issorted )
1709  {
1710  int j;
1711 
1712  assert(!propdata->sort || SCIPinProbing(scip) || SCIPgetDepth(scip) == 0);
1713 
1714  for( j = 0; j < propdata->ngenvbounds && *result != SCIP_CUTOFF; j++ )
1715  {
1716  if( ! SCIPvarIsActive(propdata->genvboundstore[j]->var) )
1717  {
1718  /**@todo resolve multiaggregation in exitpre */
1719  }
1720  else
1721  {
1722  SCIPdebugMsg(scip, "applying genvbound with index %d (unsorted mode)\n", j);
1723  SCIP_CALL( applyGenVBound(scip, prop, propdata->genvboundstore[j], global, result, nchgbds) );
1724  }
1725  }
1726 
1727  return SCIP_OKAY;
1728  }
1729 
1730  /* otherwise, we propagate only components affected by the latest bound changes */
1731  startingcomponents = global ? propdata->gstartcomponents : propdata->startcomponents;
1732  startingindices = global ? propdata->gstartindices : propdata->startindices;
1733  nindices = global ? propdata->ngindices : propdata->nindices;
1734 
1735  for( i = 0; i < nindices && *result != SCIP_CUTOFF; i++ )
1736  {
1737  int j;
1738 
1739  SCIPdebugMsg(scip, "starting in component %d at index %d\n", startingcomponents[i], startingindices[i]);
1740  for( j = startingindices[i]; j < propdata->componentsstart[startingcomponents[i] + 1] &&
1741  *result != SCIP_CUTOFF; j++ ) /*lint !e679*/
1742  {
1743  assert(j < propdata->ngenvbounds);
1744 
1745  if( ! SCIPvarIsActive(propdata->genvboundstore[j]->var) )
1746  {
1747  /**@todo resolve multiaggregation in exitpre */
1748  }
1749  else
1750  {
1751  SCIPdebugMsg(scip, "applying genvbound with index %d, component %d\n", j, startingcomponents[i]);
1752  SCIP_CALL( applyGenVBound(scip, prop, propdata->genvboundstore[j], global, result, nchgbds) );
1753  }
1754  }
1755  }
1756 
1757  /* we dont want to run again caused by this starting data */
1758  if( !global )
1759  {
1760  SCIP_CALL( resetLocalStartingData(scip, propdata) );
1761  }
1762 
1763  return SCIP_OKAY;
1764 }
1765 
1766 /** initialize propagator data */
1767 static
1769  SCIP* scip, /**< SCIP data structure */
1770  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1771  )
1773  int nprobvars;
1774 
1775  assert(scip != NULL);
1776  assert(propdata != NULL);
1777  assert(propdata->eventhdlr != NULL);
1778 
1779  SCIPdebugMsg(scip, "init propdata\n");
1780 
1781  nprobvars = SCIPgetNVars(scip);
1782 
1783  /* init genvboundstore */
1784  propdata->genvboundstoresize = 2 * nprobvars;
1785  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->genvboundstore), propdata->genvboundstoresize) );
1786  BMSclearMemoryArray(propdata->genvboundstore, propdata->genvboundstoresize);
1787  propdata->ngenvbounds = 0;
1788 
1789  /* init genvboundstore hashmaps */
1790  SCIP_CALL( SCIPhashmapCreate(&(propdata->lbgenvbounds), SCIPblkmem(scip), nprobvars) );
1791  SCIP_CALL( SCIPhashmapCreate(&(propdata->ubgenvbounds), SCIPblkmem(scip), nprobvars) );
1792 
1793  return SCIP_OKAY;
1794 }
1795 
1796 /** adds a new genvbound to genvboundstore array and sets a hashmap entry */
1797 static
1799  SCIP* scip, /**< SCIP data structure */
1800  SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1801  GENVBOUND* genvbound /**< genvbound to be added */
1802  )
1803 {
1804  SCIP_HASHMAP* hashmap;
1805 
1806  assert(scip != NULL);
1807  assert(propdata != NULL);
1808  assert(genvbound != NULL);
1809  assert(getGenVBound(scip, propdata, genvbound->var, genvbound->boundtype) == NULL);
1810 
1811  hashmap = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds;
1812 
1813  /* e.g., during presolving after a restart, new variables might have been created; in this case, we need to extend
1814  * the genvboundstore; the new size may even exceed 2*SCIPgetNVars() if we have genvbounds with nonactive left-hand
1815  * side variables
1816  */
1817  assert(propdata->ngenvbounds <= propdata->genvboundstoresize);
1818  if( propdata->ngenvbounds == propdata->genvboundstoresize )
1819  {
1820  int oldsize = propdata->genvboundstoresize;
1821  propdata->genvboundstoresize = 2*propdata->genvboundstoresize + 1;
1822  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(propdata->genvboundstore), oldsize, propdata->genvboundstoresize) );
1823  }
1824 
1825  /* new index is propdata->ngenvbounds */
1826  SCIP_CALL( SCIPhashmapInsert(hashmap, genvbound->var, genvbound) );
1827  propdata->genvboundstore[propdata->ngenvbounds] = genvbound;
1828  genvbound->index = propdata->ngenvbounds;
1829  propdata->ngenvbounds++;
1830 
1831  assert(propdata->ngenvbounds <= propdata->genvboundstoresize);
1832 
1833  return SCIP_OKAY;
1834 }
1835 
1836 /** runs propagation routine */
1837 static
1839  SCIP* scip, /**< SCIP data structure */
1840  SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1841  SCIP_RESULT* result, /**< result pointer */
1842  SCIP_Bool local, /**< should local propagation be applied? */
1843  int* nchgbds /**< counter to increase by the number of changed bounds */
1844  )
1845 {
1846  assert(scip != NULL);
1847  assert(propdata != NULL);
1848  assert(propdata->prop != NULL);
1849  assert(result != NULL);
1850 
1851  /* we only sort after the root node is finished; this avoids having to sort again after adding more genvbounds; if
1852  * the genvbounds are not sorted, we will simply propagate all of them in the order given
1853  */
1854  if( propdata->sort && !SCIPinProbing(scip) && SCIPgetDepth(scip) > 0 )
1855  {
1856  if( !propdata->issorted )
1857  {
1858  *result = SCIP_DIDNOTFIND;
1859 
1860  SCIPdebugMsg(scip, "genvbounds are not sorted\n");
1861 
1862  /* drop and free old events */
1863  SCIP_CALL( dropAndFreeEvents(scip, propdata) );
1864 
1865  /* free old starting data */
1866  SCIP_CALL( freeStartingData(scip, propdata) );
1867 
1868  /* free sorted components data */
1869  SCIP_CALL( freeComponentsData(scip, propdata) );
1870 
1871  /* sort genvbounds */
1872  SCIP_CALL( sortGenVBounds(scip, propdata) );
1873 
1874  /* create starting data */
1875  SCIP_CALL( createStartingData(scip, propdata) );
1876 
1877  /* fill global starting data */
1878  SCIP_CALL( fillGlobalStartingData(scip, propdata) );
1879  }
1880 
1881  /* set up new events to catch (if not done so far) */
1882  if( propdata->lbevents == NULL )
1883  {
1884  SCIP_CALL( setUpEvents(scip, propdata) );
1885  }
1886  }
1887 
1888  /* apply global propagation if primal bound has improved */
1889  if( propdata->global && SCIPgetDepth(scip) > 0 && SCIPisFeasLT(scip, SCIPgetCutoffbound(scip), propdata->lastcutoff) )
1890  {
1891  if( propdata->ngindices > 0 )
1892  {
1893  SCIP_CALL( applyGenVBounds(scip, propdata->prop, TRUE, result, nchgbds) );
1894  assert(*result != SCIP_DIDNOTRUN);
1895  }
1896 
1897  /* within the tree, the objective function should not change anymore, hence the cutoff bound should be a stable
1898  * point of reference
1899  */
1900  propdata->lastcutoff = SCIPgetCutoffbound(scip);
1901  }
1902 
1903  /* apply local propagation if allowed */
1904  if( local && *result != SCIP_CUTOFF )
1905  {
1906  /* check if local propagation in root node is allowed */
1907  if( SCIPgetDepth(scip) > 0 || propdata->propinrootnode )
1908  {
1909  /* if genvbounds are already sorted, check if bound change events were caught; otherwise apply all genvbounds */
1910  if( !propdata->issorted || ( SCIPgetCurrentNode(scip) == propdata->lastnodecaught && propdata->nindices > 0 ) )
1911  {
1912  SCIP_CALL( applyGenVBounds(scip, propdata->prop, FALSE, result, nchgbds) );
1913  assert(*result != SCIP_DIDNOTRUN);
1914  }
1915  }
1916  }
1917 
1918  return SCIP_OKAY;
1919 }
1920 
1921 /* adds all genvbounds in the genvboundstore as constraints to the problem; afterwards clears the genvboundstore */
1922 static
1924  SCIP* scip, /**< SCIP data structure */
1925  SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1926  )
1928  int i;
1929 
1930  assert(scip != NULL);
1931  assert(propdata != NULL);
1932  assert(propdata->propasconss);
1933 
1934  /* ensure that the cutoffboundvar is available */
1935  if( propdata->cutoffboundvar == NULL )
1936  {
1937  SCIP_Real ub;
1938  char name[16];
1939 
1940  /* set the upper bound to the best primal value in the original problem */
1941  ub = getCutoffboundGenVBound(scip);
1942 
1943  SCIPdebugMsg(scip, "initialize cutoffboundvar with UB = %e\n", ub);
1944 
1945  (void) SCIPsnprintf(name, 16, "cutoffboundvar");
1946  SCIP_CALL( SCIPcreateVarBasic(scip, &propdata->cutoffboundvar, name, -SCIPinfinity(scip), ub, 0.0, SCIP_VARTYPE_CONTINUOUS) );
1947  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, propdata->cutoffboundvar) );
1948 
1949  SCIP_CALL( SCIPaddVar(scip, propdata->cutoffboundvar) );
1950 
1951  /* lock the variable because it should not be subject to dual presolving reductions; because we create the
1952  * linear constraints as non-check constraints, the cutoffboundvar will not be locked by the linear constraint
1953  * handler
1954  */
1955  SCIP_CALL( SCIPaddVarLocks(scip, propdata->cutoffboundvar, 1, 1) );
1956  }
1957 
1958  assert(propdata->cutoffboundvar != NULL);
1959 
1960  /* now iterate over all genvbounds in the store and construct a linear constraint for each of them */
1961  for( i = 0; i < propdata->ngenvbounds; ++i )
1962  {
1963  GENVBOUND* genvbound;
1964  SCIP_CONS* cons;
1965  SCIP_VAR** vars;
1966  SCIP_Real* vals;
1967  char name[SCIP_MAXSTRLEN];
1968  int nvars;
1969  int j;
1970 
1971  genvbound = propdata->genvboundstore[i];
1972  assert(genvbound != NULL);
1973 
1974  nvars = genvbound->ncoefs + 2;
1975  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
1976  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) );
1977 
1978  SCIPdebugMsgPrint(scip, "add cons: ");
1979 
1980  /* copy the coefs/vars array */
1981  for( j = 0; j < genvbound->ncoefs; j++ )
1982  {
1983  vars[j] = genvbound->vars[j];
1984  vals[j] = genvbound->coefs[j];
1985  SCIPdebugMsgPrint(scip, "%e%s + ", vals[j], SCIPvarGetName(vars[j]));
1986  }
1987 
1988  /* add the variable and the coefficient of the genvbound */
1989  vars[genvbound->ncoefs] = genvbound->var;
1990  vals[genvbound->ncoefs] = (genvbound->boundtype == SCIP_BOUNDTYPE_LOWER) ? -1.0 : 1.0;
1991 
1992  SCIPdebugMsgPrint(scip, "%e%s + ", vals[genvbound->ncoefs], SCIPvarGetName(vars[genvbound->ncoefs]));
1993 
1994  /* add cutoffcoef * cutoffboundvar */
1995  vars[genvbound->ncoefs + 1] = propdata->cutoffboundvar;
1996  vals[genvbound->ncoefs + 1] = genvbound->cutoffcoef;
1997 
1998  SCIPdebugMsgPrint(scip, "%e%s <= %e\n", vals[genvbound->ncoefs + 1], SCIPvarGetName(vars[genvbound->ncoefs + 1]), -1.0*genvbound->constant);
1999 
2000  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "genvbound_cons%d", genvbound->index);
2001 
2002  /* create linear constraint with only propagate flag as TRUE */
2003  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nvars, vars, vals, -SCIPinfinity(scip), -genvbound->constant,
2005 
2006  SCIP_CALL( SCIPaddCons(scip, cons) );
2007  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2008 
2009  /* free memory */
2010  SCIPfreeBufferArray(scip, &vars);
2011  SCIPfreeBufferArray(scip, &vals);
2012  }
2013 
2014  /* now delete all genvbounds in the genvboundstore */
2015  if( propdata->ngenvbounds > 0 )
2016  {
2017  assert(propdata->genvboundstore != NULL);
2018 
2019  for( i = propdata->ngenvbounds - 1; i >= 0; i-- )
2020  {
2021  SCIP_CALL( freeGenVBound(scip, propdata->genvboundstore[i]) );
2022  }
2023 
2024  /* free genvboundstore hashmaps */
2025  SCIPhashmapFree(&(propdata->lbgenvbounds));
2026  SCIPhashmapFree(&(propdata->ubgenvbounds));
2027 
2028  /* drop and free all events */
2029  SCIP_CALL( dropAndFreeEvents(scip, propdata) );
2030 
2031  /* free componentsstart array */
2032  SCIP_CALL( freeComponentsData(scip, propdata) );
2033 
2034  /* free starting indices data */
2035  SCIP_CALL( freeStartingData(scip, propdata) );
2036 
2037  SCIPfreeBlockMemoryArray(scip, &(propdata->genvboundstore), propdata->genvboundstoresize);
2038  propdata->genvboundstore = NULL;
2039  propdata->genvboundstoresize = 0;
2040  propdata->ngenvbounds = 0;
2041  }
2042 
2043  return SCIP_OKAY;
2044 }
2045 
2046 
2047 
2048 /*
2049  * Public methods
2050  */
2051 
2052 /** adds a generalized variable bound to the genvbounds propagator; if there is already a genvbound for the bound
2053  * "boundtype" of variable "var", it will be replaced
2054  */
2056  SCIP* scip, /**< SCIP data structure */
2057  SCIP_PROP* genvboundprop, /**< genvbound propagator */
2058  SCIP_VAR** vars, /**< array of RHSs variables */
2059  SCIP_VAR* var, /**< LHSs variable */
2060  SCIP_Real* coefs, /**< array of coefficients for the RHSs variables */
2061  int ncoefs, /**< size of coefs array */
2062  SCIP_Real coefcutoffbound, /**< nonpositive value of the cutoff bounds multiplier */
2063  SCIP_Real constant, /**< constant term */
2064  SCIP_BOUNDTYPE boundtype /**< type of bound provided by the genvbound */
2065  )
2066 {
2067  /**@todo in debug mode: check if genvbound is nontrivial */
2068 
2069  SCIP_PROPDATA* propdata;
2070  GENVBOUND* genvbound;
2071  SCIP_Bool newgenvbound;
2072  int i;
2073 
2074  assert(scip != NULL);
2075  assert(genvboundprop != NULL);
2076  assert(strcmp(SCIPpropGetName(genvboundprop), PROP_NAME) == 0);
2077  assert(vars != NULL);
2078  assert(var != NULL);
2079  assert(coefs != NULL);
2080  assert(ncoefs >= 0);
2081  assert(coefcutoffbound <= 0.0);
2082  assert(!SCIPisInfinity(scip, -constant));
2083 
2084  if( ncoefs < 0 || coefcutoffbound > 0.0 || SCIPisInfinity(scip, -constant) )
2085  {
2086  SCIPerrorMessage("cannot create generalized variable bound from invalid data\n");
2087  return SCIP_INVALIDDATA;
2088  }
2089 
2090  propdata = SCIPpropGetData(genvboundprop);
2091  assert(propdata != NULL);
2092 
2093  /* initialize propdata if not done yet */
2094  if( propdata->genvboundstore == NULL )
2095  {
2096  SCIP_CALL( initPropdata(scip, propdata) );
2097  }
2098 
2099  genvbound = getGenVBound(scip, propdata, var, boundtype);
2100  newgenvbound = (genvbound == NULL);
2101 
2102  /* release previous variables */
2103  if( !newgenvbound )
2104  {
2105  for( i = 0; i < genvbound->ncoefs; ++i )
2106  {
2107  assert(genvbound->vars[i] != NULL);
2108  SCIP_CALL( SCIPreleaseVar(scip, &(genvbound->vars[i])) );
2109  }
2110  }
2111 
2112  /* check if there already is a genvbound corresponding to this bound, freeing its data and overwriting it */
2113  if( !newgenvbound && genvbound->ncoefs < ncoefs )
2114  {
2115  /* do not realloc since we do not want to keep and possibly copy the old entries */
2116  SCIPfreeBlockMemoryArray(scip, &(genvbound->coefs), genvbound->coefssize);
2117  SCIPfreeBlockMemoryArray(scip, &(genvbound->vars), genvbound->coefssize);
2118 
2119  /* allocate and copy arrays in genvbound */
2120  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(genvbound->coefs), coefs, ncoefs) );
2121  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(genvbound->vars), vars, ncoefs) );
2122  genvbound->coefssize = ncoefs;
2123  }
2124  else if( !newgenvbound && genvbound->ncoefs == ncoefs )
2125  {
2126  /* just update entries */
2127  for( i = 0; i < ncoefs; i++ )
2128  {
2129  genvbound->coefs[i] = coefs[i];
2130  genvbound->vars[i] = vars[i];
2131  }
2132  }
2133  else if( !newgenvbound && genvbound->ncoefs > ncoefs )
2134  {
2135  /* reallocate memory for arrays in genvbound to free unused memory */
2136  if( genvbound->coefssize < ncoefs )
2137  {
2138  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(genvbound->coefs), genvbound->coefssize, ncoefs) );
2139  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(genvbound->vars), genvbound->coefssize, ncoefs) );
2140  genvbound->coefssize = ncoefs;
2141  }
2142 
2143  /* update entries */
2144  for( i = 0; i < ncoefs; i++ )
2145  {
2146  genvbound->coefs[i] = coefs[i];
2147  genvbound->vars[i] = vars[i];
2148  }
2149  }
2150  else if( newgenvbound )
2151  {
2152  /* allocate memory for genvbound data */
2153  SCIP_CALL( SCIPallocBlockMemory(scip, &genvbound) );
2154 
2155  /* allocate and copy arrays in genvbound */
2156  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(genvbound->coefs), coefs, ncoefs) );
2157  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(genvbound->vars), vars, ncoefs) );
2158  genvbound->coefssize = ncoefs;
2159  }
2160 
2161  /* set up data for genvbound */
2162  genvbound->boundtype = boundtype;
2163  genvbound->var = var;
2164  genvbound->ncoefs = ncoefs;
2165  genvbound->constant = constant;
2166 
2167  /* capture variables */
2168  for( i = 0; i < genvbound->ncoefs; ++i )
2169  {
2170  assert(genvbound->vars[i] != NULL);
2171  SCIP_CALL( SCIPcaptureVar(scip, genvbound->vars[i]) );
2172  }
2173  if( newgenvbound )
2174  {
2175  assert(genvbound->var != NULL);
2176  SCIP_CALL( SCIPcaptureVar(scip, genvbound->var) );
2177  }
2178 
2179  /* the cutoff bound is valid w.r.t. the current objective function in the transformed problem; during presolving,
2180  * however, the objective function can change (e.g., when a variable is fixed, its contribution in the objective
2181  * is subtracted from the cutoff bound and added to the objective offset); we solve this by transforming the
2182  * contribution of the cutoff bound in the generalized variable bound to the original problem as follows:
2183  *
2184  * +/- var >= ... + z * SCIPgetCutoffbound() + constant
2185  *
2186  * becomes
2187  *
2188  * +/- var >= ... + (z / SCIPgetTransObjscale()) * origcutoffbound + (constant - z * SCIPgetTransObjoffset())
2189  *
2190  * with SCIPgetCutoffbound() = origcutoffbound / SCIPgetTransObjscale() - SCIPgetTransObjoffset(); in the
2191  * propagation later, we will use (SCIPgetCutoffbound() + SCIPgetTransObjoffset()) * SCIPgetTransObjscale(), see
2192  * function getCutoffboundGenVBound()
2193  */
2194  if( SCIPisNegative(scip, coefcutoffbound) )
2195  {
2196  assert(SCIPisPositive(scip, SCIPgetTransObjscale(scip)));
2197  genvbound->cutoffcoef = coefcutoffbound / SCIPgetTransObjscale(scip);
2198  genvbound->constant -= (coefcutoffbound * SCIPgetTransObjoffset(scip));
2199  }
2200  else
2201  genvbound->cutoffcoef = 0.0;
2202 
2203  /* if genvbound is not overwritten, create a new entry in genvboundstore */
2204  if( newgenvbound )
2205  {
2206  SCIP_CALL( addNewGenVBound(scip, propdata, genvbound) );
2207  }
2208 
2209  /* mark genvbounds array to be resorted */
2210  propdata->issorted = FALSE;
2211 
2212  /* debug message */
2213  SCIPdebugMsg(scip, "added genvbound ");
2214  SCIPdebug( printGenVBound(scip, genvbound) );
2215 #ifdef WITH_DEBUG_SOLUTION
2216  SCIP_CALL( checkDebugSolutionGenVBound(scip, genvbound) );
2217 #endif
2218 
2219  return SCIP_OKAY;
2220 }
2221 
2222 
2223 /*
2224  * Callback methods of propagator
2225  */
2226 
2227 /** copy method for propagator plugins (called when SCIP copies plugins)
2228  *
2229  * @note The UG framework assumes that all default plug-ins of SCIP implement a copy callback.
2230  */
2231 static
2232 SCIP_DECL_PROPCOPY(propCopyGenvbounds)
2233 { /*lint --e{715}*/
2234  assert(scip != NULL);
2235  assert(prop != NULL);
2236  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2237 
2238  /* call inclusion method of constraint handler */
2240 
2241  return SCIP_OKAY;
2242 }
2243 
2244 /** initialization method of propagator (called after problem was transformed) */
2245 static
2246 SCIP_DECL_PROPINIT(propInitGenvbounds)
2247 { /*lint --e{715}*/
2248  SCIP_PROPDATA* propdata;
2249 
2250  assert(scip != NULL);
2251  assert(prop != NULL);
2252  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2253 
2254  /* get propagator data */
2255  propdata = SCIPpropGetData(prop);
2256  assert(propdata != NULL);
2257 
2258  propdata->genvboundstore = NULL;
2259  propdata->genvboundstoresize = 0;
2260  propdata->lbevents = NULL;
2261  propdata->ubevents = NULL;
2262  propdata->lbgenvbounds = NULL;
2263  propdata->ubgenvbounds = NULL;
2264  propdata->lbeventsmap = NULL;
2265  propdata->ubeventsmap = NULL;
2266  propdata->startmap = NULL;
2267  propdata->componentsstart = NULL;
2268  propdata->startindices = NULL;
2269  propdata->startcomponents = NULL;
2270  propdata->gstartindices = NULL;
2271  propdata->gstartcomponents = NULL;
2272  propdata->lastcutoff = SCIPinfinity(scip);
2273  propdata->lastnodecaught = NULL;
2274  propdata->cutoffboundvar = NULL;
2275  propdata->ngenvbounds = -1;
2276  propdata->ncomponents = -1;
2277  propdata->nindices = -1;
2278  propdata->ngindices = -1;
2279  propdata->nlbevents = -1;
2280  propdata->nubevents = -1;
2281  propdata->issorted = FALSE;
2282 
2283  propdata->prop = prop;
2284 
2285  return SCIP_OKAY;
2286 }
2287 
2288 
2289 /** presolving method of propagator */
2290 static
2291 SCIP_DECL_PROPPRESOL(propPresolGenvbounds)
2292 { /*lint --e{715}*/
2293  SCIP_PROPDATA* propdata;
2294 
2295  assert(scip != NULL);
2296  assert(prop != NULL);
2297  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2298 
2299  *result = SCIP_DIDNOTRUN;
2300 
2301  if( !SCIPallowDualReds(scip) )
2302  return SCIP_OKAY;
2303 
2304  /* get propagator data */
2305  propdata = SCIPpropGetData(prop);
2306  assert(propdata != NULL);
2307 
2308  SCIPdebugMsg(scip, "proppresol in problem <%s>\n", SCIPgetProbName(scip));
2309 
2310  /* do not run if no genvbounds were added yet */
2311  if( propdata->ngenvbounds < 1 )
2312  {
2313  SCIPdebugMsg(scip, "no bounds were added yet\n");
2314  return SCIP_OKAY;
2315  }
2316 
2317  /* propagate */
2318  SCIP_CALL( execGenVBounds(scip, propdata, result, TRUE, nchgbds) );
2319 
2320  return SCIP_OKAY;
2321 }
2322 
2323 
2324 /** presolving initialization method of propagator (called when presolving is about to begin) */
2325 static
2326 SCIP_DECL_PROPINITPRE(propInitpreGenvbounds)
2327 { /*lint --e{715}*/
2328  SCIP_PROPDATA* propdata;
2329 
2330  assert(scip != NULL);
2331  assert(prop != NULL);
2332  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2333 
2334  /* get propagator data */
2335  propdata = SCIPpropGetData(prop);
2336  assert(propdata != NULL);
2337 
2338  /* lock the variable because it should not be deleted after a restart */
2339  if( propdata->cutoffboundvar != NULL )
2340  {
2341  SCIPdebugMsg(scip, "propinitpre in problem <%s>: locking cutoffboundvar (current downlocks=%d, uplocks=%d)\n",
2342  SCIPgetProbName(scip), SCIPvarGetNLocksDown(propdata->cutoffboundvar),
2343  SCIPvarGetNLocksUp(propdata->cutoffboundvar));
2344 
2345  SCIP_CALL( SCIPaddVarLocks(scip, propdata->cutoffboundvar, 1, 1) );
2346  }
2347 
2348  return SCIP_OKAY;
2349 }
2350 
2351 
2352 /** presolving deinitialization method of propagator (called after presolving has been finished) */
2353 static
2354 SCIP_DECL_PROPEXITPRE(propExitpreGenvbounds)
2355 { /*lint --e{715}*/
2356  SCIP_VAR** vars;
2357  SCIP_PROPDATA* propdata;
2358  int i;
2359 
2360  assert(scip != NULL);
2361  assert(prop != NULL);
2362  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2363 
2364  SCIPdebugMsg(scip, "propexitpre in problem <%s>: removing fixed, aggregated, negated, and multi-aggregated variables from right-hand side\n",
2365  SCIPgetProbName(scip));
2366 
2367  /* get propagator data */
2368  propdata = SCIPpropGetData(prop);
2369  assert(propdata != NULL);
2370 
2371  /* there should be no events on the right-hand side variables */
2372  assert(propdata->lbevents == NULL);
2373  assert(propdata->ubevents == NULL);
2374 
2375  /* allocate memory to store new variables */
2376  SCIP_CALL( SCIPallocBufferArray(scip, &vars, SCIPgetNTotalVars(scip)) );
2377 
2378  for( i = 0; i < propdata->ngenvbounds; )
2379  {
2380  GENVBOUND* genvbound;
2381  int requiredsize;
2382  int nvars;
2383  int j;
2384 
2385  genvbound = propdata->genvboundstore[i];
2386  assert(genvbound != NULL);
2387 
2388  /* store variables of the genvbound to release them properly */
2389  assert(genvbound->ncoefs <= SCIPgetNTotalVars(scip));
2390  BMScopyMemoryArray(vars, genvbound->vars, genvbound->ncoefs);
2391  nvars = genvbound->ncoefs;
2392 
2393  /* replace non-active by active variables and update constant; note that this may result in coefficients where
2394  * SCIPisZero() is true; this should not create any problems
2395  */
2396  SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, genvbound->ncoefs, &genvbound->constant, &requiredsize, TRUE) );
2397 
2398  /* if space was not enough we need to resize the buffers */
2399  if( requiredsize > genvbound->ncoefs )
2400  {
2401  /* reallocate memory for arrays in genvbound to free unused memory */
2402  if( genvbound->coefssize < requiredsize )
2403  {
2404  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(genvbound->coefs), genvbound->coefssize, requiredsize) );
2405  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(genvbound->vars), genvbound->coefssize, requiredsize) );
2406  genvbound->coefssize = requiredsize;
2407  }
2408 
2409  SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, requiredsize, &genvbound->constant, &requiredsize, TRUE) );
2410  assert(requiredsize <= genvbound->ncoefs);
2411  }
2412 
2413  /* capture new and release old variables */
2414  for( j = 0; j < genvbound->ncoefs; ++j )
2415  {
2416  assert(genvbound->vars[j] != NULL);
2417  SCIP_CALL( SCIPcaptureVar(scip, genvbound->vars[j]) );
2418  }
2419  for( j = 0; j < nvars; ++j )
2420  {
2421  assert(vars[j] != NULL);
2422  SCIP_CALL( SCIPreleaseVar(scip, &vars[j]) );
2423  }
2424 
2425  /* if the resulting genvbound is trivial, remove it */
2426  /* we remove all genvbounds with an aggregated or multi-aggregated genvbound->var; tightening aggregated variables
2427  * might lead to some asserts in tree.c if the active variable has been already tightened (see !398);
2428  *
2429  * @todo replace aggregated variable by their active part
2430  */
2431  if( (genvbound->ncoefs == 0 && SCIPisZero(scip, genvbound->cutoffcoef))
2432  || SCIPvarGetStatus(genvbound->var) == SCIP_VARSTATUS_MULTAGGR
2433  || SCIPvarGetStatus(genvbound->var) == SCIP_VARSTATUS_AGGREGATED )
2434  {
2435  SCIP_HASHMAP* hashmap;
2436 
2437  hashmap = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds;
2438 
2439  /* remove genvbound from hashmap */
2440  assert(SCIPhashmapExists(hashmap, genvbound->var));
2441  SCIP_CALL( SCIPhashmapRemove(hashmap, genvbound->var) );
2442 
2443  /* free genvbound and fill gap */
2444  SCIP_CALL( freeGenVBound(scip, propdata->genvboundstore[i]) );
2445  --(propdata->ngenvbounds);
2446 
2447  /* move the last genvbound to the i-th position */
2448  if( i < propdata->ngenvbounds )
2449  {
2450  propdata->genvboundstore[i] = propdata->genvboundstore[propdata->ngenvbounds];
2451  propdata->genvboundstore[i]->index = i;
2452 
2453  /* mark genvbounds array to be resorted */
2454  propdata->issorted = FALSE;
2455  }
2456  }
2457  else
2458  ++i;
2459  }
2460 
2461  SCIPfreeBufferArray(scip, &vars);
2462 
2463  return SCIP_OKAY;
2464 }
2465 
2466 /** deinitialization method of propagator (called before transformed problem is freed) */
2467 static
2468 SCIP_DECL_PROPEXIT(propExitGenvbounds)
2469 {
2470  SCIP_PROPDATA* propdata;
2471 
2472  assert(scip != NULL);
2473  assert(prop != NULL);
2474  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2475 
2476  /* get propagator data */
2477  propdata = SCIPpropGetData(prop);
2478  assert(propdata != NULL);
2479 
2480  /* free remaining genvbounds */
2481  SCIP_CALL( freeGenVBounds(scip, propdata) );
2482 
2483  return SCIP_OKAY;
2484 }
2485 
2486 /** execution method of propagator */
2487 static
2488 SCIP_DECL_PROPEXEC(propExecGenvbounds)
2489 { /*lint --e{715}*/
2490  SCIP_PROPDATA* propdata;
2491 
2492  assert(scip != NULL);
2493  assert(prop != NULL);
2494  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2495 
2496  *result = SCIP_DIDNOTRUN;
2497 
2498  /* do not run if propagation w.r.t. current objective is not allowed */
2499  if( !SCIPallowObjProp(scip) )
2500  return SCIP_OKAY;
2501 
2502  /* get propagator data */
2503  propdata = SCIPpropGetData(prop);
2504  assert(propdata != NULL);
2505 
2506  /* update upper bound of the cutoffboundvar */
2507  if( propdata->cutoffboundvar != NULL )
2508  {
2509  SCIP_Real newub;
2510  SCIP_Real oldub;
2511  SCIP_Bool infeasible;
2512  SCIP_Bool tightened;
2513 
2514  assert(propdata->propasconss);
2515 
2516  /* compute the primal bound in the original problem */
2517  newub = getCutoffboundGenVBound(scip);
2518  oldub = SCIPvarGetUbLocal(propdata->cutoffboundvar);
2519 
2520  if( SCIPisInfinity(scip, newub) == FALSE && SCIPisFeasLT(scip, newub, oldub) )
2521  {
2522  SCIP_CALL( SCIPtightenVarUbGlobal(scip, propdata->cutoffboundvar, newub, FALSE, &infeasible, &tightened) );
2523 
2524  if( tightened )
2525  {
2526  SCIPdebugMsg(scip, "tightened UB of cutoffboundvar to %e (old: %e, infeas: %u, tightened: %u)\n",
2527  newub, oldub, infeasible, tightened);
2528  }
2529 
2530  assert(infeasible == FALSE);
2531  }
2532  }
2533 
2534  SCIPdebugMsg(scip, "propexec in problem <%s> at depth %d%s\n", SCIPgetProbName(scip), SCIPgetDepth(scip),
2535  SCIPinProbing(scip) ? " in probing" : "");
2536 
2537  /* do not run if no genvbounds were added yet */
2538  if( propdata->ngenvbounds < 1 )
2539  {
2540  /**@todo is it really no performance issue to be called each time when there are no genvbounds, e.g., for MIPs? */
2541  SCIPdebugMsg(scip, "no bounds were added yet\n");
2542  return SCIP_OKAY;
2543  }
2544 
2545  /* add the genvbounds in the genvboundstore as constraints to the problem; afterwards clear the genvboundstore */
2546  if( propdata->propasconss )
2547  {
2548  SCIP_CALL( createConstraints(scip, propdata) );
2549  return SCIP_OKAY;
2550  }
2551 
2552  /* propagate locally and globally */
2553  SCIP_CALL( execGenVBounds(scip, propdata, result, !SCIPinProbing(scip), NULL) );
2554 
2555  /* when called in presolving stage the result is set to SCIP_SUCCESS instead of SCIP_REDUCEDDOM, this is corrected
2556  * here
2557  */
2558  if( *result == SCIP_SUCCESS )
2559  *result = SCIP_REDUCEDDOM;
2560 
2561  SCIPdebugMsg(scip, "end of exec\n");
2562 
2563  return SCIP_OKAY;
2564 }
2565 
2566 /** propagation conflict resolving method of propagator */
2567 static
2568 SCIP_DECL_PROPRESPROP(propRespropGenvbounds)
2569 { /*lint --e{715}*/
2570  SCIP_PROPDATA* propdata;
2571  GENVBOUND* genvbound;
2572  SCIP_Real boundval;
2573  SCIP_Bool success;
2574 
2575  SCIPdebugMsg(scip, "explain %s bound change of variable <%s>\n",
2576  boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", SCIPvarGetName(infervar));
2577 
2578  /* get propagator data */
2579  propdata = SCIPpropGetData(prop);
2580  assert(propdata != NULL);
2581  assert(propdata->genvboundstore != NULL);
2582 
2583  /* as inferinfo we passed the index of the genvbound that was used for propagation; the genvbound might have been
2584  * replaced, but also the new genvbound at this position has the same variable on the left-hand side
2585  */
2586  assert(inferinfo >= 0);
2587  assert(inferinfo < propdata->ngenvbounds);
2588 
2589  *result = SCIP_DIDNOTFIND;
2590 
2591  /* check also in optimized mode that inferinfo is correct */
2592  if( inferinfo >= propdata->ngenvbounds)
2593  {
2594  SCIPerrorMessage("generalized variable bounds propagator received inferinfo out of range; propagation not resolved, safe to continue\n");
2595  return SCIP_OKAY;
2596  }
2597 
2598  /* get genvbound responsible for the bound change */
2599  genvbound = propdata->genvboundstore[inferinfo];
2600  assert(genvbound != NULL);
2601  assert(genvbound->var == infervar);
2602 
2603  /* check also in optimized mode that inferinfo is correct */
2604  if( genvbound->var != infervar )
2605  {
2606  SCIPerrorMessage("generalized variable bounds propagator received incorrect inferinfo; propagation not resolved, but it's safe to continue\n");
2607  return SCIP_OKAY;
2608  }
2609 
2610  /* get value of bound change on left-hand side */
2611  boundval = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER
2612  ? SCIPgetVarLbAtIndex(scip, genvbound->var, bdchgidx, TRUE)
2613  : -SCIPgetVarUbAtIndex(scip, genvbound->var, bdchgidx, TRUE);
2614 
2615  /* if left-hand side variable is integral, it suffices to explain a bound change greater than boundval - 1 */
2616  if( SCIPvarIsIntegral(genvbound->var) )
2617  {
2618  SCIP_Real roundedboundval;
2619 
2620  assert(SCIPisIntegral(scip, boundval));
2621 
2622  roundedboundval = SCIPfeasCeil(scip, boundval - 1.0) + 2 * SCIPfeastol(scip);
2623  boundval = MIN(boundval, roundedboundval);
2624  }
2625 
2626  /* resolve propagation */
2627  SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, bdchgidx, &boundval, &success) );
2628 
2629  if( success )
2630  *result = SCIP_SUCCESS;
2631 
2632  return SCIP_OKAY;
2633 }
2634 
2635 /** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
2636 static
2637 SCIP_DECL_PROPEXITSOL(propExitsolGenvbounds)
2638 { /*lint --e{715}*/
2639  SCIP_PROPDATA* propdata;
2640 
2641  assert(scip != NULL);
2642  assert(prop != NULL);
2643  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2644 
2645  SCIPdebugMsg(scip, "propexitsol in problem <%s>\n", SCIPgetProbName(scip));
2646 
2647  /* get propagator data */
2648  propdata = SCIPpropGetData(prop);
2649  assert(propdata != NULL);
2650 
2651  /* free all genvbounds if we are not in a restart */
2652  if( !SCIPisInRestart(scip) )
2653  {
2654  SCIP_CALL( freeGenVBounds(scip, propdata) );
2655  }
2656 
2657  /* drop and free all events */
2658  SCIP_CALL( dropAndFreeEvents(scip, propdata) );
2659 
2660  return SCIP_OKAY;
2661 }
2662 
2663 /** destructor of propagator to free user data (called when SCIP is exiting) */
2664 static
2665 SCIP_DECL_PROPFREE(propFreeGenvbounds)
2666 { /*lint --e{715}*/
2667  SCIP_PROPDATA* propdata;
2668 
2669  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
2670 
2671  /* free propagator data */
2672  propdata = SCIPpropGetData(prop);
2673  assert(propdata != NULL);
2674 
2675  SCIPfreeBlockMemory(scip, &propdata);
2676 
2677  SCIPpropSetData(prop, NULL);
2678 
2679  return SCIP_OKAY;
2680 }
2681 
2682 
2683 /*
2684  * Callback methods of event handler
2685  */
2686 
2687 static
2688 SCIP_DECL_EVENTEXEC(eventExecGenvbounds)
2689 { /*lint --e{715}*/
2690  SCIP_PROPDATA* propdata;
2691  int i;
2693  assert(scip != NULL);
2694  assert(eventdata != NULL);
2695 
2696  assert(SCIPeventGetType(event) == SCIP_EVENTTYPE_LBTIGHTENED || SCIPeventGetType(event) ==
2698 
2699  assert(eventdata->startcomponents != NULL);
2700  assert(eventdata->startindices != NULL);
2701  assert(eventdata->nstarts > 0);
2702  assert(eventdata->prop != NULL);
2703 
2704  propdata = SCIPpropGetData(eventdata->prop);
2705  assert(propdata != NULL);
2706 
2707  assert(propdata->startcomponents != NULL);
2708  assert(propdata->startmap != NULL);
2709  assert(propdata->startindices != NULL);
2710 
2711  SCIPdebugMsg(scip, "catching eventdata:\n");
2712  SCIPdebug( printEventData(eventdata, SCIPeventGetType(event) == SCIP_EVENTTYPE_LBTIGHTENED ?
2714 
2715  /* check if we need to reset old local starting indices data */
2716  if( SCIPgetCurrentNode(scip) != propdata->lastnodecaught )
2717  {
2718  SCIP_CALL( resetLocalStartingData(scip, propdata) );
2719  propdata->lastnodecaught = SCIPgetCurrentNode(scip);
2720  }
2721 
2722  for( i = 0; i < eventdata->nstarts; i++ )
2723  {
2724  int component;
2725  int startidx;
2726 
2727  component = eventdata->startcomponents[i];
2728  assert(component >= 0);
2729  startidx = eventdata->startindices[i];
2730 
2731  /* there is already an entry for this component */
2732  if( SCIPhashmapExists(propdata->startmap, (void*)(size_t) (component + 1)) )
2733  {
2734  int componentidx;
2735 
2736  /* get its index */
2737  componentidx = ((int)(size_t) SCIPhashmapGetImage(propdata->startmap, (void*)(size_t) (component + 1))) - 1; /*lint !e776*/
2738  assert(componentidx >= 0);
2739  assert(propdata->startcomponents[componentidx] == component);
2740 
2741  if( propdata->startindices[componentidx] > startidx )
2742  propdata->startindices[componentidx] = startidx;
2743  }
2744  else
2745  {
2746  /* get a new entry */
2747  int componentidx;
2748  componentidx = propdata->nindices;
2749 
2750  /* store index */
2751  propdata->startcomponents[componentidx] = component;
2752  propdata->startindices[componentidx] = startidx;
2753 
2754  /* store component in hashmap */
2755  SCIP_CALL( SCIPhashmapInsert(propdata->startmap, (void*)(size_t) (component + 1),
2756  (void*)(size_t) (componentidx + 1)) );
2757 
2758  /* increase number of starting indices */
2759  propdata->nindices++;
2760  }
2761  }
2762 
2763  return SCIP_OKAY;
2764 }
2765 
2766 /*
2767  * propagator specific interface methods
2768  */
2769 
2770 /** creates the genvbounds propagator and includes it in SCIP */
2772  SCIP* scip /**< SCIP data structure */
2773  )
2774 {
2775  SCIP_PROPDATA* propdata;
2776  SCIP_PROP* prop;
2777 
2778  /* create genvbounds propagator data */
2779  SCIP_CALL( SCIPallocBlockMemory(scip, &propdata) );
2780 
2781  /* include propagator */
2783  propExecGenvbounds, propdata) );
2784 
2785  SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyGenvbounds) );
2786  SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeGenvbounds) );
2787  SCIP_CALL( SCIPsetPropInit(scip, prop, propInitGenvbounds) );
2788  SCIP_CALL( SCIPsetPropInitpre(scip, prop, propInitpreGenvbounds) );
2789  SCIP_CALL( SCIPsetPropExitpre(scip, prop, propExitpreGenvbounds) );
2790  SCIP_CALL( SCIPsetPropExit(scip, prop, propExitGenvbounds) );
2791  SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolGenvbounds) );
2792  SCIP_CALL( SCIPsetPropPresol(scip, prop, propPresolGenvbounds, PROP_PRESOL_PRIORITY,
2794  SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropGenvbounds) );
2795 
2796  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/global",
2797  "apply global propagation?",
2798  &propdata->global, TRUE, DEFAULT_GLOBAL_PROPAGATION, NULL, NULL) );
2799 
2800  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/propinrootnode",
2801  "apply genvbounds in root node if no new incumbent was found?",
2802  &propdata->propinrootnode, TRUE, DEFAULT_PROPAGATE_IN_ROOT_NODE, NULL, NULL) );
2803 
2804  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/sort",
2805  "sort genvbounds and wait for bound change events?",
2806  &propdata->sort, TRUE, DEFAULT_SORT, NULL, NULL) );
2807 
2808  SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/propasconss",
2809  "should genvbounds be transformed to (linear) constraints?",
2810  &propdata->propasconss, TRUE, DEFAULT_PROPASCONSS, NULL, NULL) );
2811 
2812  /* include event handler */
2813  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &propdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecGenvbounds, NULL) );
2814 
2815  return SCIP_OKAY;
2816 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
SCIP_RETCODE SCIPsetPropPresol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPPRESOL((*proppresol)), int presolpriority, int presolmaxrounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:7823
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22604
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:22593
static SCIP_RETCODE applyGenVBound(SCIP *scip, SCIP_PROP *prop, GENVBOUND *genvbound, SCIP_Bool global, SCIP_RESULT *result, int *nchgbds)
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:46443
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22587
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip.c:19649
static SCIP_RETCODE freeComponentsData(SCIP *scip, SCIP_PROPDATA *propdata)
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip.c:41404
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:821
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47311
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip.c:19509
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)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:41226
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
Definition: scip.c:43453
static SCIP_RETCODE initPropdata(SCIP *scip, SCIP_PROPDATA *propdata)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17276
static SCIP_RETCODE applyGenVBounds(SCIP *scip, SCIP_PROP *prop, SCIP_Bool global, SCIP_RESULT *result, int *nchgbds)
#define SCIP_MAXSTRLEN
Definition: def.h:259
static SCIP_RETCODE dropAndFreeEvents(SCIP *scip, SCIP_PROPDATA *propdata)
SCIP_RETCODE SCIPdigraphComputeUndirectedComponents(SCIP_DIGRAPH *digraph, int minsize, int *components, int *ncomponents)
Definition: misc.c:7417
static long bound
#define PROP_PRESOL_MAXROUNDS
#define PROP_DESC
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:47088
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17332
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47015
SCIP_RETCODE SCIPinferVarLbProp(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_PROP *inferprop, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:23211
static SCIP_DECL_PROPEXEC(propExecGenvbounds)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:8611
static SCIP_RETCODE freeAllEventData(SCIP *scip, SCIP_PROPDATA *propdata)
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:18766
static SCIP_RETCODE analyzeGenVBoundConflict(SCIP *scip, GENVBOUND *genvbound)
static SCIP_RETCODE freeEventData(SCIP *scip, SCIP_EVENTDATA **eventdata)
#define PROP_NAME
#define PROP_FREQ
SCIP_VAR * var
#define FALSE
Definition: def.h:64
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2793
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:47028
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10011
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:47100
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:27474
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:21660
static SCIP_DECL_PROPEXITSOL(propExitsolGenvbounds)
static GENVBOUND * getGenVBound(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype)
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip.c:17699
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
Definition: scip.c:27218
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
Definition: scip.c:27155
int SCIPdigraphGetNComponents(SCIP_DIGRAPH *digraph)
Definition: misc.c:7612
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:22602
#define SCIPdebugMessage
Definition: pub_message.h:77
static SCIP_RETCODE resetLocalStartingData(SCIP *scip, SCIP_PROPDATA *propdata)
#define PROP_PRESOLTIMING
void SCIPdigraphGetComponent(SCIP_DIGRAPH *digraph, int compidx, int **nodes, int *nnodes)
Definition: misc.c:7625
static SCIP_Real getGenVBoundsMinActivity(SCIP *scip, SCIP_VAR **vars, SCIP_Real *coefs, int nvars, SCIP_Bool global)
#define DEFAULT_PROPASCONSS
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2931
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46963
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:22632
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:22585
static SCIP_RETCODE fillGlobalStartingData(SCIP *scip, SCIP_PROPDATA *propdata)
#define SCIPdebugMsgPrint
Definition: scip.h:456
#define SCIPdebugMsg
Definition: scip.h:455
SCIP_RETCODE SCIPdigraphTopoSortComponents(SCIP_DIGRAPH *digraph)
Definition: misc.c:7546
SCIP_RETCODE SCIPcreateDigraph(SCIP *scip, SCIP_DIGRAPH **digraph, int nnodes)
Definition: scip.c:48568
static SCIP_DECL_PROPEXITPRE(propExitpreGenvbounds)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
Definition: scip.c:47435
static SCIP_RETCODE addEventData(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, int startindex, int startcomponent, SCIP_BOUNDTYPE boundtype)
const char * SCIPgetProbName(SCIP *scip)
Definition: scip.c:10891
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3025
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
Definition: scip.c:27133
#define PROP_TIMING
int SCIPdigraphGetNNodes(SCIP_DIGRAPH *digraph)
Definition: misc.c:7232
int SCIPgetNFixedVars(SCIP *scip)
Definition: scip.c:12129
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17286
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:22599
SCIP_RETCODE SCIPsetPropExitpre(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPEXITPRE((*propexitpre)))
Definition: scip.c:7807
static SCIP_RETCODE addNewGenVBound(SCIP *scip, SCIP_PROPDATA *propdata, GENVBOUND *genvbound)
#define SCIPerrorMessage
Definition: pub_message.h:45
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12591
#define SCIPdebugPrintf
Definition: pub_message.h:80
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46976
static SCIP_Real getGenVBoundsBound(SCIP *scip, GENVBOUND *genvbound, SCIP_Bool global)
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_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)
#define DEFAULT_PROPAGATE_IN_ROOT_NODE
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:46731
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:27450
static SCIP_DECL_PROPEXIT(propExitGenvbounds)
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:25932
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:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16662
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2826
SCIP_RETCODE SCIPtightenVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:23542
SCIP_Real * coefs
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:39041
#define REALABS(x)
Definition: def.h:173
#define SCIP_CALL(x)
Definition: def.h:350
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:63
int SCIPgetNTotalVars(SCIP *scip)
Definition: scip.c:12389
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47337
SCIP_RETCODE SCIPinferVarUbProp(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_PROP *inferprop, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:23325
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:19255
SCIP_RETCODE SCIPdigraphAddArc(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
Definition: misc.c:7154
#define SCIPdebugCheckLbGlobal(scip, var, lb)
Definition: debug.h:251
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:262
static SCIP_RETCODE freeGenVBounds(SCIP *scip, SCIP_PROPDATA *propdata)
#define SCIPdebugCheckUbGlobal(scip, var, ub)
Definition: debug.h:252
#define PROP_PRESOL_PRIORITY
static SCIP_RETCODE createConstraints(SCIP *scip, SCIP_PROPDATA *propdata)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:22620
#define SCIP_UNKNOWN
Definition: def.h:170
SCIP_RETCODE SCIPsetPropInit(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPINIT((*propinit)))
Definition: scip.c:7727
static SCIP_RETCODE setUpEvents(SCIP *scip, SCIP_PROPDATA *propdata)
#define SCIP_Bool
Definition: def.h:61
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:959
SCIP_BOUNDTYPE boundtype
SCIP_RETCODE SCIPhashmapRemoveAll(SCIP_HASHMAP *hashmap)
Definition: misc.c:3214
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:43045
SCIP_VAR ** vars
#define EVENTHDLR_NAME
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3217
#define MAX(x, y)
Definition: tclique_def.h:75
methods for debugging
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
Definition: scip.c:27286
static SCIP_Real getCutoffboundGenVBound(SCIP *scip)
#define DEFAULT_SORT
SCIP_RETCODE SCIPsetPropCopy(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPCOPY((*propcopy)))
Definition: scip.c:7695
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:41272
SCIP_RETCODE SCIPdigraphComputeDirectedComponents(SCIP_DIGRAPH *digraph, int compidx, int *strongcomponents, int *strongcompstartidx, int *nstrongcomponents)
Definition: misc.c:7757
SCIP_Real cutoffcoef
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:116
static SCIP_DECL_PROPFREE(propFreeGenvbounds)
static SCIP_DECL_PROPINITPRE(propInitpreGenvbounds)
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:65
Constraint handler for linear constraints in their most general form, .
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:47039
SCIP_Real SCIPgetTransObjscale(SCIP *scip)
Definition: scip.c:11214
SCIP_RETCODE SCIPsetPropExitsol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPEXITSOL((*propexitsol)))
Definition: scip.c:7775
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:35836
const char * SCIPpropGetName(SCIP_PROP *prop)
Definition: prop.c:887
#define EVENTHDLR_DESC
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:11812
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Real SCIPgetTransObjoffset(SCIP *scip)
Definition: scip.c:11191
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3041
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3162
SCIP_RETCODE SCIPsetPropResprop(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPRESPROP((*propresprop)))
Definition: scip.c:7856
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47002
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:47112
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:11492
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:27761
SCIP_Real constant
SCIP_Bool SCIPallowDualReds(SCIP *scip)
Definition: scip.c:25885
static SCIP_RETCODE createStartingData(SCIP *scip, SCIP_PROPDATA *propdata)
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16781
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:18732
#define SCIP_Real
Definition: def.h:149
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
static SCIP_RETCODE sortGenVBounds(SCIP *scip, SCIP_PROPDATA *propdata)
#define SCIP_INVALID
Definition: def.h:169
SCIP_RETCODE SCIPsetPropFree(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPFREE((*propfree)))
Definition: scip.c:7711
SCIP_PROPDATA * SCIPpropGetData(SCIP_PROP *prop)
Definition: prop.c:735
void SCIPpropSetData(SCIP_PROP *prop, SCIP_PROPDATA *propdata)
Definition: prop.c:745
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:47076
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46989
#define PROP_DELAY
#define DEFAULT_GLOBAL_PROPAGATION
#define nnodes
Definition: gastrans.c:65
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17342
static SCIP_DECL_PROPCOPY(propCopyGenvbounds)
SCIP_RETCODE SCIPtightenVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:23662
SCIP_RETCODE SCIPincludePropGenvbounds(SCIP *scip)
static SCIP_DECL_PROPRESPROP(propRespropGenvbounds)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2874
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:112
SCIP_RETCODE SCIPsetPropInitpre(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPINITPRE((*propinitpre)))
Definition: scip.c:7791
void SCIPdigraphFree(SCIP_DIGRAPH **digraph)
Definition: misc.c:7064
SCIP_RETCODE SCIPsetPropExit(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPEXIT((*propexit)))
Definition: scip.c:7743
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16853
static SCIP_RETCODE freeStartingData(SCIP *scip, SCIP_PROPDATA *propdata)
SCIP_Bool SCIPisInRestart(SCIP *scip)
Definition: scip.c:17582
static SCIP_DECL_PROPPRESOL(propPresolGenvbounds)
SCIP_RETCODE SCIPanalyzeConflict(SCIP *scip, int validdepth, SCIP_Bool *success)
Definition: scip.c:27504
SCIP_Bool SCIPallowObjProp(SCIP *scip)
Definition: scip.c:25895
static SCIP_DECL_PROPINIT(propInitGenvbounds)
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4239
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16949
generalized variable bounds propagator
SCIP_RETCODE SCIPincludePropBasic(SCIP *scip, SCIP_PROP **propptr, const char *name, const char *desc, int priority, int freq, SCIP_Bool delay, SCIP_PROPTIMING timingmask, SCIP_DECL_PROPEXEC((*propexec)), SCIP_PROPDATA *propdata)
Definition: scip.c:7658