Scippy

SCIP

Solving Constraint Integer Programs

prop_pseudoobj.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file prop_pseudoobj.c
17  * @brief Pseudo objective propagator
18  * @author Tobias Achterberg
19  * @author Stefan Heinz
20  *
21  * This propagator propagates the objective function using the cutoff bound and the pseudo objective value. The pseudo
22  * objective value can be seen as minimum activity of the linear objective function. Using this, this propagator checks
23  * if variables with non-zero objective coefficients can exceed the cutoff bound. If this is the case the corresponding
24  * bound can be tightened.
25  *
26  * @todo use the complete implication to initialize the objective implication data structure
27  */
28 
29 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
30 
31 #include <assert.h>
32 #include <string.h>
33 
34 #include "scip/prop_pseudoobj.h"
35 
36 
37 #define PROP_NAME "pseudoobj"
38 #define PROP_DESC "pseudo objective function propagator"
39 #define PROP_TIMING SCIP_PROPTIMING_BEFORELP | SCIP_PROPTIMING_AFTERLPLOOP | SCIP_PROPTIMING_DURINGLPLOOP
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 found reductions? */
43 #define PROP_PRESOL_PRIORITY +6000000 /**< priority of the presolving method (>= 0: before, < 0: after constraint handlers); combined with presolvers */
44 #define PROP_PRESOL_DELAY FALSE /**< should presolving be delay, if other presolvers found reductions? */
45 #define PROP_PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates in (-1: no
46  * limit) */
47 
48 #define EVENTHDLR_NAME "pseudoobj"
49 #define EVENTHDLR_DESC "bound change event handler for pseudo objective function propagator"
50 
51 #define DEFAULT_MINUSELESS 100 /**< minimal number of successive none binary variable propagator whithout a
52  * bound reduction before aborted */
53 #define DEFAULT_MAXVARSFRAC 0.1 /**< maximal fraction of none binary variables with non-zero objective
54  * without a bound reduction before aborted */
55 #define DEFAULT_PROPFULLINROOT TRUE /**< do we want to propagate all non-binary variables if we are propagating the root node? */
56 #define DEFAULT_PROPCUTOFFBOUND TRUE /**< propagate new cutoff bound directly globally */
57 #define DEFAULT_FORCE FALSE /**< should the propagator be forced even active pricer are present? Note that
58  * can be done if it is known that the pseudo objective activity is given by
59  * the zero bound for all variables which are currently not present in the
60  * problem */
61 #define DEFAULT_MAXNEWVARS 1000 /**< number of variable added after the propagator is reinitialized? */
62 #define DEFAULT_PROPUSEIMPLICS TRUE /**< use implications to strengthen the propagation of binary variable (increasing the objective change)? */
63 #define DEFAULT_RESPROPUSEIMPLICS TRUE /**< use implications to strengthen the resolve propagation of binary variable (increasing the objective change)? */
64 #define DEFAULT_MAXIMPLVARS 50000 /**< maximum number of binary variables the implications are used if turned on (-1: unlimited)? */
65 
66 
67 /*
68  * Data structures
69  */
70 
71 /** implication data structure for objective contributions of a binary variable */
73 {
74  SCIP_VAR** objvars; /**< variables y in implications y == 0 or y == 1, first we store the
75  * implications by x == 0 and second the implications x == 1 */
76  SCIP_Real maxobjchg; /**< maximum objective contribution if variables x is fixed to zero or one */
77  int nlbimpls; /**< number of all implications result through for x == 0 */
78  int nubimpls; /**< number of all implications result through for x == 1 */
79  int size; /**< size of the objvars array */
80 };
81 typedef struct SCIP_ObjImplics SCIP_OBJIMPLICS; /**< implications in the form x == 0 or x == 1 ==> y == 0 or y == 1 for (x and y binary) */
82 
83 
84 /** propagator data */
85 struct SCIP_PropData
86 {
87  SCIP_EVENTHDLR* eventhdlr; /**< event handler for global bound change events */
88  SCIP_VAR** minactvars; /**< binary variables with non-zero objective contribution w.r.t. minimum activity of the objective function */
89  SCIP_OBJIMPLICS** minactimpls; /**< implication data structure for the binary variables w.r.t. minimum activity */
90  SCIP_VAR** maxactvars; /**< binary variables with non-zero objective contribution w.r.t. maximum activity of the objective function */
91  SCIP_Real* maxactchgs; /**< the maximal potential change of the objective if the binary variable
92  * is fixed to its best bound w.r.t. maximum activity of the objective function */
93  SCIP_VAR** objintvars; /**< none binary variable with non-zero objective coefficient */
94  SCIP_HASHTABLE* addedvars; /**< hash table used during resolving of a bound change (conflict analysis) */
95  SCIP_Real lastlowerbound; /**< last lower bound which was propagated */
96  SCIP_Real cutoffbound; /**< last cutoff bound used for propagation */
97  SCIP_Real glbpseudoobjval; /**< last global pseudo objective used in presolving */
98  SCIP_Real maxvarsfrac; /**< maximal fraction of none binary variables with non-zero objective
99  * without a bound reduction before aborted */
100  SCIP_Real maxpseudoobjact; /**< maximal global pseudo objective activity */
101  int maxpseudoobjactinf; /**< number of coefficients contributing with infinite value to maxpseudoobjact */
102  int nminactvars; /**< number of binary variables with non-zero objective contribution w.r.t. minimum activity of the objective function */
103  int nmaxactvars; /**< number of binary variables with non-zero objective contribution w.r.t. maximum activity of the objective function */
104  int nobjintvars; /**< number of none binary variables with non-zero objective */
105  int minuseless; /**< minimal number of successive none binary variable propagator whithout
106  * a bound reduction before aborted */
107  int lastvarnum; /**< last none binary variable number that was looked at */
108  int glbfirstnonfixed; /**< index of first globally non-fixed binary variable in minactvars array */
109  int maxactfirstnonfixed;/**< index of first globally non-fixed binary variable in maxctvars array */
110  int firstnonfixed; /**< index of first locally non-fixed binary variable in minactvars array */
111  int nnewvars; /**< counter for counting number of new variables added */
112  int maxnewvars; /**< number of variable added after the propagator is reinitialized? */
113  int maximplvars; /**< maximum number of binary variables the implications are used if turned on (-1: unlimited)? */
114  SCIP_Bool glbpropagated; /**< are global domains propagated */
115  SCIP_Bool propfullinroot; /**< do we want to propagate all non-binary variables if we are propagating the root node */
116  SCIP_Bool propcutoffbound; /**< propagate new cutoff bound directly globally */
117  SCIP_Bool force; /**< should the propagator be forced even if active pricer are present? */
118  SCIP_Bool catchvaradded; /**< do we catch the variable added event? */
119  SCIP_Bool propuseimplics; /**< use implications to strengthen the propagation of binary variable (increasing the objective change)? */
120  SCIP_Bool respropuseimplics; /**< use implications to strengthen the resolve propagation of binary variable (increasing the objective change)? */
121  SCIP_Bool initialized; /**< is propagator data structure initialized */
122 };
123 
124 /*
125  * Debug methods
126  */
127 
128 #ifndef NDEBUG
129 /** check that the implications are applied for a globally fixed variable */
130 static
132  SCIP* scip, /**< SCIP data structure */
133  SCIP_VAR* var /**< variable to check the implications */
134  )
135 {
136  SCIP_VAR** vars;
137  SCIP_Real* bounds;
138  SCIP_BOUNDTYPE* boundtypes;
139  SCIP_Bool varfixing;
140  int nvars;
141  int v;
142 
143  /* check that the given variable is locally or globally fixed */
144  assert(SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5);
145 
146  /* get fixed value */
147  varfixing = SCIPvarGetLbGlobal(var) > 0.5;
148 
149  vars = SCIPvarGetImplVars(var, varfixing);
150  nvars = SCIPvarGetNImpls(var, varfixing);
151  bounds = SCIPvarGetImplBounds(var, varfixing);
152  boundtypes = SCIPvarGetImplTypes(var, varfixing);
153 
154  /* check that each implication was applied */
155  for( v = 0; v < nvars; ++v )
156  {
157  if( boundtypes[v] == SCIP_BOUNDTYPE_LOWER )
158  {
159  SCIP_Real lb;
160 
161  lb = SCIPvarGetLbGlobal(vars[v]);
162  assert(SCIPisLE(scip, lb, bounds[v]));
163  }
164  else
165  {
166  SCIP_Real ub;
167 
168  assert(boundtypes[v] == SCIP_BOUNDTYPE_UPPER);
169 
170  ub = SCIPvarGetLbGlobal(vars[v]);
171  assert(SCIPisGE(scip, ub, bounds[v]));
172  }
173  }
174 }
175 
176 /** check if the global fixed indices are correct */
177 static
179  SCIP* scip, /**< SCIP data structure */
180  SCIP_PROPDATA* propdata /**< propagator data */
181  )
182 {
183  SCIP_VAR* var;
184  int v;
185 
186  for( v = 0; v < propdata->glbfirstnonfixed; ++v )
187  {
188  var = propdata->minactvars[v];
189  assert(var != NULL);
190 
191  assert(SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5);
192  }
193 
194  for( v = 0; v < propdata->maxactfirstnonfixed; ++v )
195  {
196  var = propdata->maxactvars[v];
197  assert(var != NULL);
198 
199  assert(SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5);
200  }
201 }
202 #endif /* end of debug methods */
203 
204 /*
205  * Comparer
206  */
207 
208 /** compares objective implications w.r.t. their maximum contribution */
209 static
210 SCIP_DECL_SORTPTRCOMP(objimplicsComp)
211 {
212  SCIP_OBJIMPLICS* objimplics1;
213  SCIP_OBJIMPLICS* objimplics2;
214 
215  objimplics1 = (SCIP_OBJIMPLICS*)elem1;
216  objimplics2 = (SCIP_OBJIMPLICS*)elem2;
217 
218  if( objimplics1->maxobjchg > objimplics2->maxobjchg )
219  return +1;
220 
221  if( objimplics1->maxobjchg < objimplics2->maxobjchg )
222  return -1;
223 
224  return 0;
225 }
226 
227 /** compare variables w.r.t.
228  * (i) the absolute value the objective coefficient;
229  * (ii) the locks which indicate most effect -- for the variables with a positive (negative) objective coefficient the
230  * down (up) lock is used since this lock indicates that tightened of the upper (lower) bound will triegger
231  * further domain propagations;
232  * (iii) the other locks;
233  * (iv) variable problem index;
234  */
235 static
237 {
238  SCIP_VAR* var1;
239  SCIP_VAR* var2;
240  int locks1;
241  int locks2;
242 
243  var1 = (SCIP_VAR*)elem1;
244  var2 = (SCIP_VAR*)elem2;
245 
246  assert(SCIPvarGetObj(var1) != 0.0);
247  assert(SCIPvarGetObj(var2) != 0.0);
248 
249  /* first criteria is the absolute value of objective coefficient */
250  if( REALABS(SCIPvarGetObj(var1)) < REALABS(SCIPvarGetObj(var2)) )
251  return -1;
252  else if( REALABS(SCIPvarGetObj(var1)) > REALABS(SCIPvarGetObj(var2)) )
253  return +1;
254 
255  /* second criteria the locks which indicate most effect */
256  if( SCIPvarGetObj(var1) > 0.0 )
257  locks1 = SCIPvarGetNLocksDown(var1);
258  else
259  locks1 = SCIPvarGetNLocksUp(var1);
260 
261  if( SCIPvarGetObj(var2) > 0.0 )
262  locks2 = SCIPvarGetNLocksDown(var2);
263  else
264  locks2 = SCIPvarGetNLocksUp(var2);
265 
266  if( locks1 < locks2 )
267  return -1;
268  if( locks1 > locks2 )
269  return 1;
270 
271  /* third criteria the other locks */
272  if( SCIPvarGetObj(var1) > 0.0 )
273  locks1 = SCIPvarGetNLocksUp(var1);
274  else
275  locks1 = SCIPvarGetNLocksDown(var1);
276 
277  if( SCIPvarGetObj(var2) > 0.0 )
278  locks2 = SCIPvarGetNLocksUp(var2);
279  else
280  locks2 = SCIPvarGetNLocksDown(var2);
281 
282  if( locks1 < locks2 )
283  return -1;
284  if( locks1 > locks2 )
285  return 1;
286 
287  /* forth criteria use the problem index */
288  return SCIPvarCompare(var1, var2);
289 }
290 
291 /** hash key retrieval function for cliques*/
292 static
293 SCIP_DECL_HASHGETKEY(cliqueGetHashkey)
294 { /*lint --e{715}*/
295  return elem;
296 }
297 
298 /** returns TRUE iff the cliques are equal */
299 static
300 SCIP_DECL_HASHKEYEQ(cliqueIsHashkeyEq)
301 { /*lint --e{715}*/
302  if( key1 == key2 )
303  return TRUE;
304  return FALSE;
305 }
306 
307 /** returns the hash value of the key */
308 static
309 SCIP_DECL_HASHKEYVAL(cliqueGetHashkeyVal)
310 { /*lint --e{715}*/
311  assert( SCIPcliqueGetId((SCIP_CLIQUE*) key) >= 0 );
312  return (unsigned int) SCIPcliqueGetId((SCIP_CLIQUE*) key);
313 }
314 
315 /*
316  * methods for SCIP_OBJIMPLICS data structure
317  */
318 
319 /** creates an objective implication data structure, fixes (globally) variables which are implied by lower and upper
320  * bound fixing, and clears the collected arrays for lower and upper bound
321  */
322 static
324  SCIP* scip, /**< SCIP data structure */
325  SCIP_OBJIMPLICS** objimplics, /**< pointer to objective implication data structure */
326  SCIP_VAR** objvars, /**< objective contributor variables, or NULL */
327  SCIP_HASHMAP* binobjvarmap, /**< hash map mapping binary variables with none-zero objective to position in collected variables arrays, or NULL */
328  SCIP_Bool* collectedlbvars, /**< temporary buffer to mark collected variables for lower bound fixing, or NULL */
329  SCIP_Bool* collectedubvars, /**< temporary buffer to mark collected variables for upper bound fixing, or NULL */
330  SCIP_Real maxlbobjchg, /**< maximum objective contributor if variables id fixed to zero */
331  SCIP_Real maxubobjchg, /**< maximum objective contributor if variables id fixed to one */
332  int nlbimpls, /**< number of variables contributing to to lower bound fix */
333  int nubimpls /**< number of variables contributing to to upper bound fix */
334  )
335 
336 {
337  assert(scip != NULL);
338  assert(objimplics != NULL);
339  assert(!SCIPisNegative(scip, maxlbobjchg));
340  assert(!SCIPisNegative(scip, maxubobjchg));
341 
342  /* allocate block memory for the implication data structure */
343  SCIP_CALL( SCIPallocBlockMemory(scip, objimplics) );
344 
345  if( nlbimpls + nubimpls == 0 )
346  {
347  assert(nlbimpls == 0);
348  assert(nubimpls == 0);
349  (*objimplics)->objvars = NULL;
350  (*objimplics)->maxobjchg = 0.0;
351  (*objimplics)->nlbimpls = 0;
352  (*objimplics)->nubimpls = 0;
353  (*objimplics)->size = 0;
354  }
355  else
356  {
357  SCIP_VAR* var;
358  int nvars;
359  int pos;
360  int v;
361 
362  assert(objvars != NULL);
363  assert(binobjvarmap != NULL);
364  assert(collectedlbvars != NULL);
365  assert(collectedubvars != NULL);
366 
367  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*objimplics)->objvars, nlbimpls + nubimpls) );
368  (*objimplics)->size = nlbimpls + nubimpls;
369 
370  nvars = 0;
371 
372  for( v = 0; v < nlbimpls; ++v )
373  {
374  var = objvars[v];
375  assert(var != NULL);
376  assert(!SCIPisZero(scip, SCIPvarGetObj(var)));
377 
378  assert(SCIPhashmapExists(binobjvarmap, var));
379  pos = (int)(size_t)SCIPhashmapGetImage(binobjvarmap, (void*)var);
380  assert(pos > 0);
381  assert(collectedlbvars[pos]);
382 
383  if( collectedubvars[pos] )
384  {
385  SCIP_Bool infeasible;
386  SCIP_Bool tightened;
387 
389  {
390  SCIPdebugMessage("fix variables <%s> to 1.0 due to implications\n", SCIPvarGetName(var));
391 
392  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, 1.0, FALSE, &infeasible, &tightened) );
393  maxlbobjchg -= SCIPvarGetObj(var);
394  }
395  else
396  {
397  SCIPdebugMessage("fix variables <%s> to 0.0 due to implications\n", SCIPvarGetName(var));
398 
399  SCIP_CALL( SCIPtightenVarUbGlobal(scip, var, 0.0, FALSE, &infeasible, &tightened) );
400  maxlbobjchg += SCIPvarGetObj(var);
401  }
402  assert(!infeasible);
403  assert(tightened);
404  }
405  else
406  {
407  (*objimplics)->objvars[nvars] = var;
408  nvars++;
409  }
410  collectedlbvars[pos] = FALSE;
411  }
412  (*objimplics)->nlbimpls = nvars;
413 
414  for( v = 0; v < nubimpls; ++v )
415  {
416  var = objvars[nlbimpls + v];
417  assert(var != NULL);
418  assert(!SCIPisZero(scip, SCIPvarGetObj(var)));
419 
420  assert(SCIPhashmapExists(binobjvarmap, var));
421  pos = (int)(size_t)SCIPhashmapGetImage(binobjvarmap, (void*)var);
422  assert(pos > 0);
423  assert(collectedubvars[pos]);
424 
425  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
426  {
428  maxubobjchg -= SCIPvarGetObj(var);
429  else
430  maxubobjchg += SCIPvarGetObj(var);
431  }
432  else
433  {
434  (*objimplics)->objvars[nvars] = var;
435  nvars++;
436  }
437  collectedubvars[pos] = FALSE;
438  }
439  (*objimplics)->nubimpls = nvars - (*objimplics)->nlbimpls;
440 
441  /* capture the variables */
442  for( v = 0; v < nvars; ++v )
443  {
444  assert(SCIPvarIsBinary((*objimplics)->objvars[v]));
445  assert(!SCIPisZero(scip, SCIPvarGetObj((*objimplics)->objvars[v])));
446  SCIP_CALL( SCIPcaptureVar(scip, (*objimplics)->objvars[v]) );
447  }
448  }
449 
450  (*objimplics)->maxobjchg = MAX(maxlbobjchg, maxubobjchg);
451 
452  return SCIP_OKAY;
453 }
454 
455 /** frees an objective implication data structure */
456 static
458  SCIP* scip, /**< SCIP data structure */
459  SCIP_OBJIMPLICS** objimplics /**< pointer to objective implication data structure */
460  )
461 {
462  int v;
463 
464  assert(scip != NULL);
465  assert(objimplics != NULL);
466  assert(*objimplics != NULL);
467 
468  /* release all variables */
469  for( v = 0; v < (*objimplics)->nlbimpls + (*objimplics)->nubimpls; ++v )
470  {
471  SCIP_CALL( SCIPreleaseVar(scip, &(*objimplics)->objvars[v]) );
472  }
473 
474  /* free objective variable array */
475  SCIPfreeBlockMemoryArrayNull(scip, &(*objimplics)->objvars, (*objimplics)->size);
476 
477  /* frees block memory for the implication data structure */
478  SCIPfreeBlockMemory(scip, objimplics);
479 
480  return SCIP_OKAY;
481 }
482 
483 /** remove the given variable at the given pos from the objective implication data structure */
484 static
486  SCIP* scip, /**< SCIP data structure */
487  SCIP_OBJIMPLICS* objimplics, /**< objective implication data structure */
488  int pos /**< position */
489  )
490 {
491  assert(0 <= pos);
492  assert(pos < objimplics->nlbimpls + objimplics->nubimpls);
493 
494  SCIPdebugMessage("variable <%s> ", SCIPvarGetName(objimplics->objvars[pos]));
495 
496  /* release variable */
497  SCIP_CALL( SCIPreleaseVar(scip, &objimplics->objvars[pos]) );
498 
499  /* copy last lower bound variable to that position */
500  if( pos < objimplics->nlbimpls )
501  {
502  objimplics->nlbimpls--;
503  assert(objimplics->nlbimpls >= 0);
504 
505  /* copy last lower bound variable to that position */
506  objimplics->objvars[pos] = objimplics->objvars[objimplics->nlbimpls];
507 
508  /* copy last upper bound variable to open slot */
509  objimplics->objvars[objimplics->nlbimpls] = objimplics->objvars[objimplics->nlbimpls + objimplics->nubimpls];
510 
511  SCIPdebugPrintf("remove lower bound implication\n");
512  }
513  else
514  {
515  objimplics->nubimpls--;
516  assert(objimplics->nubimpls >= 0);
517 
518  /* copy last upper bound variable to that position */
519  objimplics->objvars[pos] = objimplics->objvars[objimplics->nlbimpls + objimplics->nubimpls];
520 
521  SCIPdebugPrintf("remove upper bound implication\n");
522  }
523 
524  return SCIP_OKAY;
525 }
526 
527 /*
528  * Local methods
529  */
530 
531 
532 /** catch bound change events if the variable has a non-zero objective coefficient to check if the maximum activity of
533  * the objective function changed
534  */
535 static
537  SCIP* scip, /**< SCIP data structure */
538  SCIP_PROPDATA* propdata, /**< propagator data */
539  SCIP_EVENTHDLR* eventhdlr, /**< event handler for global bound change events */
540  SCIP_VAR* var /**< variable for which the event should be dropped */
541  )
542 {
543  SCIP_Real objval;
544 
545  assert(propdata != NULL);
546  assert(eventhdlr != NULL);
547 
548  objval = SCIPvarGetObj(var);
549 
550  if( !SCIPisZero(scip, objval) )
551  {
552  if( objval > 0.0 )
553  {
554  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GUBCHANGED, eventhdlr, (SCIP_EVENTDATA*)propdata, NULL) );
555  }
556  else
557  {
558  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GLBCHANGED, eventhdlr, (SCIP_EVENTDATA*)propdata, NULL) );
559  }
560  }
561 
562  return SCIP_OKAY;
563 }
564 
565 /** drop variable event w.r.t. objective coefficient */
566 static
568  SCIP* scip, /**< SCIP data structure */
569  SCIP_PROPDATA* propdata, /**< propagator data */
570  SCIP_EVENTHDLR* eventhdlr, /**< event handler for global bound change events */
571  SCIP_VAR* var /**< variable for which the event should be dropped */
572  )
573 {
574  SCIP_Real objval;
575 
576  assert(propdata != NULL);
577  assert(eventhdlr != NULL);
578 
579  objval = SCIPvarGetObj(var);
580 
581  /* drop bound change event */
582  if( !SCIPisZero(scip, objval) )
583  {
584  if( objval > 0.0 )
585  {
586  SCIP_CALL( SCIPdropVarEvent(scip, var, SCIP_EVENTTYPE_GUBCHANGED, eventhdlr, (SCIP_EVENTDATA*)propdata, -1) );
587  }
588  else
589  {
590  SCIP_CALL( SCIPdropVarEvent(scip, var, SCIP_EVENTTYPE_GLBCHANGED, eventhdlr, (SCIP_EVENTDATA*)propdata, -1) );
591  }
592  }
593  return SCIP_OKAY;
594 }
595 
596 /** drop all variable events */
597 static
599  SCIP* scip, /**< SCIP data structure */
600  SCIP_PROPDATA* propdata /**< propagator data */
601  )
602 {
603  SCIP_EVENTHDLR* eventhdlr;
604  SCIP_VAR* var;
605  int k;
606 
607  assert(scip != NULL);
608  assert(propdata != NULL);
609 
610  eventhdlr = propdata->eventhdlr;
611  assert(eventhdlr != NULL);
612 
613  /* drop all events and release variables */
614  for( k = 0; k < propdata->nminactvars; ++k )
615  {
616  var = propdata->minactvars[k];
617  assert(var != NULL);
618  assert(SCIPvarIsBinary(var));
619 
620  /* drop bound relax event which is caught for all binary variables which are used for propagation the objective
621  * function via the minimum activity of the objective function
622  */
623  SCIP_CALL( SCIPdropVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDRELAXED, eventhdlr, (SCIP_EVENTDATA*)propdata, -1) );
624 
625  /* release variable */
626  SCIP_CALL( SCIPreleaseVar(scip, &var) );
627  }
628 
629  /* release variables */
630  for( k = 0; k < propdata->nmaxactvars; ++k )
631  {
632  var = propdata->maxactvars[k];
633  assert(var != NULL);
634  assert(SCIPvarIsBinary(var));
635 
636  /* drop events which are needed for evaluating the maximum activity of the objective function */
637  SCIP_CALL( dropObjEvent(scip, propdata, eventhdlr, var) );
638 
639  /* release variable */
640  SCIP_CALL( SCIPreleaseVar(scip, &var) );
641  }
642 
643  /* drop all events and release variables */
644  for( k = 0; k < propdata->nobjintvars; ++k )
645  {
646  var = propdata->objintvars[k];
647  assert(var != NULL);
648 
649  /* drop events which are needed for evaluating the maximum activity of the objective function */
650  SCIP_CALL( dropObjEvent(scip, propdata, eventhdlr, var) );
651 
652  /* release variable */
653  SCIP_CALL( SCIPreleaseVar(scip, &var) );
654  }
655 
656  return SCIP_OKAY;
657 }
658 
659 /** reset propagatore data structure */
660 static
662  SCIP* scip, /**< SCIP data structure */
663  SCIP_PROPDATA* propdata /**< propagator data */
664  )
665 {
666  propdata->minactvars = NULL;
667  propdata->minactimpls = NULL;
668  propdata->maxactvars = NULL;
669  propdata->maxactchgs = NULL;
670  propdata->objintvars = NULL;
671  propdata->nminactvars = 0;
672  propdata->nmaxactvars = 0;
673  propdata->nobjintvars = 0;
674  propdata->maxpseudoobjact = SCIP_INVALID;
675  propdata->maxpseudoobjactinf = 0;
676  propdata->lastvarnum = -1;
677  propdata->glbpropagated = FALSE;
678  propdata->cutoffbound = SCIP_INVALID;
679  propdata->lastlowerbound = -SCIP_INVALID;
680  propdata->glbpseudoobjval = -SCIP_INVALID;
681  propdata->glbfirstnonfixed = 0;
682  propdata->maxactfirstnonfixed = 0;
683  propdata->firstnonfixed = 0;
684  propdata->nnewvars = 0;
685  propdata->catchvaradded = FALSE;
686  propdata->initialized = FALSE;
687 }
688 
689 /** free propagator data */
690 static
692  SCIP* scip, /**< SCIP data structure */
693  SCIP_PROPDATA* propdata /**< propagator data */
694  )
695 {
696  int v;
697 
698  if( !propdata->initialized )
699  return SCIP_OKAY;
700 
701  if( propdata->addedvars != NULL )
702  SCIPhashtableFree(&propdata->addedvars);
703 
704  /* drop events for the variables */
705  SCIP_CALL( dropVarEvents(scip, propdata) );
706 
707  for( v = 0; v < propdata->nminactvars; ++v )
708  {
709  SCIP_CALL( objimplicsFree(scip, &(propdata->minactimpls[v])) );
710  }
711 
712  /* free memory for non-zero objective variables */
713  SCIPfreeMemoryArrayNull(scip, &propdata->minactvars);
714  SCIPfreeMemoryArrayNull(scip, &propdata->minactimpls);
715  SCIPfreeMemoryArrayNull(scip, &propdata->maxactvars);
716  SCIPfreeMemoryArrayNull(scip, &propdata->maxactchgs);
717  SCIPfreeMemoryArrayNull(scip, &propdata->objintvars);
718 
719  /* reset propagator data structure */
720  propdataReset(scip, propdata);
721 
722  return SCIP_OKAY;
723 }
724 
725 /** returns the objective change for the given binary variable */
726 static
728  SCIP_VAR* var, /**< variable to get objective change for */
729  SCIP_BOUNDTYPE boundtype, /**< bound type to consider */
730  SCIP_BOUNDTYPE bound /**< fixing bound */
731  )
732 {
733  assert(SCIPvarIsBinary(var));
734  assert((int)SCIP_BOUNDTYPE_LOWER == 0);
735  assert((int)SCIP_BOUNDTYPE_UPPER == 1);
736 
737  /* collect contribution of variable itself */
738  return (SCIP_Real)((int)bound - (int)(boundtype == SCIP_BOUNDTYPE_UPPER)) * SCIPvarGetObj(var);
739 }
740 
741 /** returns the objective change provided by the implication variable by fixing it to the given bound
742  * w.r.t. minimum activity of the objective function; additionally it collects all contributors for that objective
743  * change;
744  */
745 static
747  SCIP* scip, /**< SCIP data structure */
748  SCIP_VAR* var, /**< variable to computes the objective contribution */
749  SCIP_HASHMAP* binobjvarmap, /**< hash map mapping binary variables with none-zero objective to position in collected variables arrays */
750  SCIP_Bool* collectedvars, /**< temporary buffer to mark collected variables */
751  int nbinobjvars, /**< number of binary variables with non-zero objective coefficient */
752  SCIP_VAR** contributors, /**< array to store the contributors */
753  int* ncontributors /**< pointer to store number of contributor to the objective contribution */
754  )
755 {
756  SCIP_Real objval;
757  int pos;
758 
759  assert(scip != NULL);
760  assert(var != NULL);
761  assert(binobjvarmap != NULL);
762  assert(collectedvars != NULL);
763  assert(contributors != NULL);
764  assert(ncontributors != NULL);
765 
766  /* ignore global fixed variables */
767  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
768  return 0.0;
769 
770  objval = SCIPvarGetObj(var);
771 
772  /* ignore variables with zero objective coefficient */
773  if( SCIPisZero(scip, objval) )
774  return 0.0;
775 
776  assert(SCIPhashmapExists(binobjvarmap, var));
777  pos = (int)(size_t)SCIPhashmapGetImage(binobjvarmap, var);
778  assert(pos > 0);
779 
780  /* check if the variables was already collected through other cliques */
781  if( collectedvars[pos] )
782  return 0.0;
783 
784  /* collect variable */
785  assert(*ncontributors < nbinobjvars);
786  contributors[*ncontributors] = var;
787  (*ncontributors)++;
788 
789  /* mark variable to be collected */
790  collectedvars[pos] = TRUE;
791 
792  /* return the absolute value of the objective coefficient as constriction */
793  return REALABS(objval);
794 }
795 
796 #define MAX_CLIQUELENGTH 50
797 /** returns the objective change provided by the implications of the given variable by fixing it to the given bound
798  * w.r.t. minimum activity of the objective function; additionally it collects all contributors for that objective
799  * change;
800  *
801  * Let I(0) and I(1) be all implications of the given variable which follow by fixing it to given bound and evaluate to
802  * fixing the implication variable to zero (I(0)) or one (I(1)), respectively. The objective change provided by the
803  * implications are:
804  *
805  * \f[
806  * \displaystyle
807  * sum_{x\in I(1)} (1 - \mbox{bestbound}(x)) \cdot \mbox{objval}(x) - sum_{x\in I(1)} \mbox{bestbound}(x) \cdot \mbox{objval}(x)
808  * =
809  * sum_{x\in I(0) \cup I(1)} (\mbox{impliedbound}(x) - \mbox{bestbound}(x)) \cdot \mbox{objval}(x)
810  * \f]
811  */
812 static
814  SCIP* scip, /**< SCIP data structure */
815  SCIP_VAR* var, /**< variable to computes the objective contribution */
816  SCIP_BOUNDTYPE bound, /**< bound to check for */
817  SCIP_HASHMAP* binobjvarmap, /**< hash map mapping binary variables with none-zero objective to position in collected variables arrays */
818  SCIP_Bool* collectedvars, /**< temporary buffer to mark collected variables */
819  int nbinobjvars, /**< number of binary variables with non-zero objective coefficient */
820  SCIP_VAR** contributors, /**< array to store the contributors */
821  SCIP_HASHTABLE* uselesscliques, /**< hash table to store useless cliques, or NULL */
822  int* ncontributors, /**< pointer to store number of contributor to the objective contribution */
823  SCIP_Real* objchg /**< pointer to store the objective change */
824  )
825 {
826  SCIP_CLIQUE** cliques;
827  SCIP_CLIQUE* clique;
828  SCIP_VAR** vars;
829  SCIP_VAR* implvar;
830  SCIP_BOUNDTYPE* boundtypes;
831  SCIP_Bool* values;
832  SCIP_Bool varfixing;
833  int nbinvars;
834  int ncliques;
835  int c;
836  int v;
837 
838  assert(SCIPvarIsBinary(var));
839  assert(SCIPvarGetLbGlobal(var) < 0.5);
840  assert(SCIPvarGetUbGlobal(var) > 0.5);
841  assert(bound == SCIP_BOUNDTYPE_LOWER || bound == SCIP_BOUNDTYPE_UPPER);
842  assert(objchg != NULL);
843  assert(contributors != NULL);
844  assert(ncontributors != NULL);
845  assert(*ncontributors == 0);
846 
848  assert((SCIP_Bool)SCIP_BOUNDTYPE_UPPER == TRUE);
849  varfixing = (SCIP_Bool)bound;
850 
851  cliques = SCIPvarGetCliques(var, varfixing);
852  ncliques = SCIPvarGetNCliques(var, varfixing);
853 
854 #ifndef NDEBUG
855  /* check that the marker array is reset */
856  for( c = 0; c < nbinobjvars; ++c )
857  assert(collectedvars[c] == FALSE);
858 #endif
859 
860  /* collect all implication which are given via cliques */
861  for( c = 0; c < ncliques; ++c )
862  {
863  SCIP_Bool useless;
864 
865  assert(uselesscliques != NULL);
866 
867  clique = cliques[c];
868  assert(clique != NULL);
869 
870  /* check if the clique was previously detected to be useless with respect to minimum activity */
871  if( SCIPhashtableExists(uselesscliques, (void*)clique) )
872  continue;
873 
874  nbinvars = SCIPcliqueGetNVars(clique);
875 
876  if( nbinvars > MAX_CLIQUELENGTH )
877  {
878  SCIP_CALL( SCIPhashtableInsert(uselesscliques, (void*)clique) );
879  continue;
880  }
881 
882  vars = SCIPcliqueGetVars(clique);
883  values = SCIPcliqueGetValues(clique);
884  useless = TRUE;
885 
886  for( v = 0; v < nbinvars; ++v )
887  {
888  implvar = vars[v];
889  assert(implvar != NULL);
890 
891  if( implvar == var )
892  {
893  /* check if the clique is useful at all */
894  if( useless )
895  {
896  SCIP_Real objval;
897 
898  objval = SCIPvarGetObj(var);
899 
900  if( varfixing == (SCIP_Bool)SCIPvarGetBestBoundType(var) && !SCIPisZero(scip, objval) )
901  useless = FALSE;
902  }
903  }
904  else if( values[v] == (SCIP_Bool)SCIPvarGetBestBoundType(implvar) )
905  {
906  useless = FALSE;
907  (*objchg) += collectMinactImplicVar(scip, implvar, binobjvarmap, collectedvars, nbinobjvars, contributors, ncontributors);
908  }
909  }
910 
911  /* if the clique is useless store it in the hash table to skip it later */
912  if( useless )
913  {
914  assert(!SCIPhashtableExists(uselesscliques, (void*)clique));
915  SCIP_CALL( SCIPhashtableInsert(uselesscliques, (void*)clique) );
916  }
917  }
918 
919  /* collect implications */
920  vars = SCIPvarGetImplVars(var, varfixing);
921  nbinvars = SCIPvarGetNBinImpls(var, varfixing);
922  boundtypes = SCIPvarGetImplTypes(var, varfixing);
923 
924  /* loop over all implications */
925  for( v = 0; v < nbinvars; ++v )
926  {
927  assert(vars[v] != NULL);
928 
929  if( boundtypes[v] == SCIPvarGetBestBoundType(vars[v]) )
930  {
931  (*objchg) += collectMinactImplicVar(scip, vars[v], binobjvarmap, collectedvars, nbinobjvars, contributors, ncontributors);
932  }
933  }
934 
935  return SCIP_OKAY;
936 }
937 
938 /** returns the objective change provided by the implications of the given variable by fixing it to the given bound
939  * w.r.t. minimum activity of the objective function
940  *
941  * Let I(0) and I(1) be all implications of the given variable which follow by fixing it to given bound and evaluate to
942  * fixing the implication variable to zero (I(0)) or one (I(1)), respectively. The objective change provided by the
943  * implications are:
944  *
945  * \f[
946  * \displaystyle
947  * sum_{x\in I(1)} (1 - \mbox{bestbound}(x)) \cdot \mbox{objval}(x) - sum_{x\in I(1)} \mbox{bestbound}(x) \cdot \mbox{objval}(x)
948  * =
949  * sum_{x\in I(0) \cup I(1)} (\mbox{impliedbound}(x) - \mbox{bestbound}(x)) \cdot \mbox{objval}(x)
950  * \f]
951  *
952  * This can be done w.r.t. global variable bounds (local == FALSE), w.r.t. local variable bounds (local == TRUE &&
953  * bdchgidx == NULL), and w.r.t. given time stamp (local == TRUE && bdchgidx != NULL)
954  */
955 static
957  SCIP* scip, /**< SCIP data structure */
958  SCIP_VAR* var, /**< variable to computes the objective contribution */
959  SCIP_OBJIMPLICS* objimplics, /**< objective implication data for the given variable */
960  SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node, or NULL */
961  SCIP_BOUNDTYPE bound, /**< bound to check for */
962  SCIP_Bool local, /**< propagate local bounds, otherwise global bounds */
963  SCIP_Real* objchg /**< pointer to store the objective change */
964  )
965 {
966  SCIP_VAR* implvar;
967  SCIP_Bool lb;
968  SCIP_Bool ub;
969  int nbinvars;
970  int v;
971 
972  assert(SCIPvarIsBinary(var));
973  assert(!local || SCIPvarGetLbAtIndex(var, bdchgidx, FALSE) < 0.5);
974  assert(!local || SCIPvarGetUbAtIndex(var, bdchgidx, FALSE) > 0.5);
975  assert(SCIPvarGetLbGlobal(var) < 0.5);
976  assert(SCIPvarGetUbGlobal(var) > 0.5);
977  assert(bound == SCIP_BOUNDTYPE_LOWER || bound == SCIP_BOUNDTYPE_UPPER);
978 
979  if( bound == SCIP_BOUNDTYPE_LOWER )
980  {
981  v = 0;
982  nbinvars = objimplics->nlbimpls;
983  }
984  else
985  {
986  assert(bound == SCIP_BOUNDTYPE_UPPER);
987  v = objimplics->nlbimpls;
988  nbinvars = objimplics->nlbimpls + objimplics->nubimpls;
989  }
990 
991  /* loop over all implications */
992  while( v < nbinvars )
993  {
994  implvar = objimplics->objvars[v];
995  assert(implvar != NULL);
996  assert(!SCIPisZero(scip, SCIPvarGetObj(implvar)));
997 
998  if( local )
999  {
1000  lb = SCIPvarGetLbAtIndex(implvar, bdchgidx, FALSE) > 0.5;
1001  ub = SCIPvarGetUbAtIndex(implvar, bdchgidx, FALSE) > 0.5;
1002 
1003  /* check if variable is fixed */
1004  if( lb == TRUE || ub == FALSE )
1005  {
1006  v++;
1007  continue;
1008  }
1009  }
1010  else
1011  {
1012  lb = SCIPvarGetLbGlobal(implvar) > 0.5;
1013  ub = SCIPvarGetUbGlobal(implvar) > 0.5;
1014 
1015  /* check if variable is global fixed; if so remove it from the objective implication data structure and
1016  * continue with the next candidate
1017  */
1018  if( lb == TRUE || ub == FALSE )
1019  {
1020  SCIP_CALL( objimplicsDelPos(scip, objimplics, v) );
1021  nbinvars--;
1022  continue;
1023  }
1024  }
1025 
1026  assert(SCIPvarGetObj(implvar) > 0.0 || SCIPvarsHaveCommonClique(var, (SCIP_Bool) bound, implvar, TRUE, TRUE));
1027  assert(SCIPvarGetObj(implvar) < 0.0 || SCIPvarsHaveCommonClique(var, (SCIP_Bool) bound, implvar, FALSE, TRUE));
1028 
1029  /* add objective change */
1030  (*objchg) += REALABS(SCIPvarGetObj(implvar));
1031  v++;
1032  }
1033 
1034  return SCIP_OKAY;
1035 }
1036 
1037 /** computes for the given binary variable the objective contribution by fixing it to given bound w.r.t. minimum
1038  * activity of the objective function; additionally it collects all contributors for that objective change;
1039  */
1040 static
1042  SCIP* scip, /**< SCIP data structure */
1043  SCIP_VAR* var, /**< variable to computes the objective contribution */
1044  SCIP_BOUNDTYPE bound, /**< bound to check for */
1045  SCIP_HASHMAP* binobjvarmap, /**< hash map mapping binary variables with none-zero objective to position in collected variables arrays */
1046  SCIP_Bool* collectedvars, /**< temporary buffer to mark collected variables */
1047  int nbinobjvars, /**< number of binary variables with non-zero objective coefficient */
1048  SCIP_VAR** contributors, /**< array to store the contriboters */
1049  SCIP_HASHTABLE* uselesscliques, /**< hash table to store useless cliques, or NULL */
1050  int* ncontributors, /**< pointer to store number of contributor to the objective contribution */
1051  SCIP_Real* objchg /**< pointer to store the objective change */
1052  )
1053 {
1054  assert(SCIPvarIsBinary(var));
1055  assert(contributors != NULL);
1056  assert(ncontributors != NULL);
1057 
1058  /* collects the contribution of the variable itself w.r.t. the best bound */
1059  (*objchg) = getVarObjchg(var, SCIPvarGetBestBoundType(var), bound);
1060 
1061  (*ncontributors) = 0;
1062 
1063  /* add the objective contribution from the implication variable */
1064  SCIP_CALL( collectMinactImplicVars(scip, var, bound, binobjvarmap, collectedvars, nbinobjvars, contributors, uselesscliques, ncontributors, objchg) );
1065 
1066  return SCIP_OKAY;
1067 }
1068 
1069 /** computes for the given binary variable the objective contribution by fixing it to given bound w.r.t. minimum
1070  * activity of the objective function; this can be done w.r.t. global variable bounds (local == FALSE), w.r.t. local
1071  * variable bounds (local == TRUE && bdchgidx == NULL), and w.r.t. given time stamp (local == TRUE && bdchgidx != NULL)
1072  */
1073 static
1075  SCIP* scip, /**< SCIP data structure */
1076  SCIP_VAR* var, /**< variable to computes the objective contribution */
1077  SCIP_OBJIMPLICS* objimplics, /**< objective implication data for the given variable */
1078  SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node, or NULL */
1079  SCIP_BOUNDTYPE bound, /**< bound to check for */
1080  SCIP_Bool local, /**< propagate local bounds, otherwise global bounds */
1081  SCIP_Real* objchg /**< pointer to store the objective change */
1082  )
1083 {
1084  assert(SCIPvarIsBinary(var));
1085 
1086  /* collects the contribution of the variable itself w.r.t. the best bound */
1087  (*objchg) = getVarObjchg(var, SCIPvarGetBestBoundType(var), bound);
1088 
1089  /* add the objective contribution from the implication variable */
1090  SCIP_CALL( getMinactImplicObjchg(scip, var, objimplics, bdchgidx, bound, local, objchg) );
1091 
1092  return SCIP_OKAY;
1093 }
1094 
1095 /** returns the global (that means w.r.t. global bounds of the variables) objective change provided by the implication of
1096  * the given variable by fixing it to the given bound w.r.t. maximum activity of the objective function
1097  *
1098  * Let I(0) and I(1) be all implications of the given variable which follow by fixing it to given bound and evaluate to
1099  * fixing the implication variable to zero (I(0)) or one (I(1)), respectively. The objective change provided by the
1100  * implications are:
1101  *
1102  * \f[
1103  * \displaystyle
1104  * sum_{x\in I(1)} (1 - \mbox{worstbound}(x)) \cdot \mbox{objval}(x) - sum_{x\in I(1)} \mbox{worst}(x) \cdot \mbox{objval}(x)
1105  * =
1106  * sum_{x\in I(0) \cup I(1)} (\mbox{impliedbound}(x) - \mbox{worstbound}(x)) \cdot \mbox{objval}(x)
1107  * \f]
1108  */
1109 static
1111  SCIP_VAR* var, /**< variable to computes the objective contribution */
1112  SCIP_BOUNDTYPE bound /**< bound to check for */
1113  )
1114 {
1115  SCIP_VAR** vars;
1116  SCIP_VAR* implvar;
1117  SCIP_Real* bounds;
1118  SCIP_Real objchg;
1119  SCIP_Bool varfixing;
1120  int nbinvars;
1121  int v;
1122 
1123  assert(SCIPvarIsBinary(var));
1124  assert(SCIPvarGetLbGlobal(var) < 0.5);
1125  assert(SCIPvarGetUbGlobal(var) > 0.5);
1126  assert(bound == SCIP_BOUNDTYPE_LOWER || bound == SCIP_BOUNDTYPE_UPPER);
1127 
1128  varfixing = (SCIP_Bool)bound;
1129  assert((SCIP_Bool)SCIP_BOUNDTYPE_LOWER == FALSE);
1130  assert((SCIP_Bool)SCIP_BOUNDTYPE_UPPER == TRUE);
1131 
1132  vars = SCIPvarGetImplVars(var, varfixing);
1133  nbinvars = SCIPvarGetNBinImpls(var, varfixing);
1134  bounds = SCIPvarGetImplBounds(var, varfixing);
1135 
1136  objchg = 0.0;
1137 
1138  /* loop over all implications */
1139  for( v = 0; v < nbinvars; ++v )
1140  {
1141  implvar = vars[v];
1142  assert(implvar != NULL);
1143 
1144  /* ignore globally fixed variables */
1145  if( SCIPvarGetLbGlobal(implvar) < 0.5 && SCIPvarGetUbGlobal(implvar) > 0.5 )
1146  objchg += (bounds[v] - SCIPvarGetWorstBoundGlobal(implvar)) * SCIPvarGetObj(implvar);
1147  }
1148 
1149  return objchg;
1150 }
1151 
1152 /** computes for the given binary variable the gloabl (that means w.r.t. global bounds of the variables) objective
1153  * contribution by fixing it to given bound w.r.t. maximum activity of the objective function
1154  */
1155 static
1157  SCIP_VAR* var, /**< variable to computes the objective contribution */
1158  SCIP_BOUNDTYPE bound, /**< bound to check for */
1159  SCIP_Bool useimplics /**< should implications be used */
1160  )
1161 {
1162  SCIP_Real objchg;
1163 
1164  assert(SCIPvarIsBinary(var));
1165 
1166  /* collects the contribution of the variable itself w.r.t. the worst bound */
1167  objchg = getVarObjchg(var, SCIPvarGetWorstBoundType(var), bound);
1168 
1169  /* check if the implications should be used to increase the objective contribution for given variable */
1170  if( useimplics )
1171  {
1172  /* add the objective contribution from the implication variable */
1173  objchg += getMaxactImplicObjchg(var, bound);
1174  }
1175 
1176  return objchg;
1177 }
1178 
1179 /** reset variables array which marks variables which are collected */
1180 static
1182  SCIP_HASHMAP* binobjvarmap, /**< hash map mapping binary variables with none-zero objective to position in collected variables arrays */
1183  SCIP_Bool* collectedvars, /**< temporary buffer to mark collected variables which should be reset */
1184  SCIP_VAR** contributors, /**< temporary buffer to use for collecting contributors */
1185  int ncontributors /**< number of contributors */
1186  )
1187 {
1188  SCIP_VAR* var;
1189  int pos;
1190  int c;
1191 
1192  for( c = 0; c < ncontributors; ++c )
1193  {
1194  var = contributors[c];
1195  assert(var != NULL);
1196 
1197  assert(SCIPhashmapExists(binobjvarmap, var));
1198  pos = (int)(size_t)SCIPhashmapGetImage(binobjvarmap, var);
1199  assert(pos > 0);
1200  collectedvars[pos] = FALSE;
1201  }
1202 }
1203 
1204 /** check if the given variable should be collected for the minimum activity propagation */
1205 static
1207  SCIP* scip, /**< SCIP data structure */
1208  SCIP_VAR* var, /**< variable to check */
1209  SCIP_OBJIMPLICS** objimplics, /**< pointer to store the objective implication data structure w.r.t. minimum activity */
1210  SCIP_Bool useimplics, /**< should implications be used */
1211  SCIP_HASHMAP* binobjvarmap, /**< hash map mapping binary variables with none-zero objective to position in collected variables arrays */
1212  SCIP_Bool* collectedlbvars, /**< temporary buffer to mark collected variables for lower bound fixing */
1213  SCIP_Bool* collectedubvars, /**< temporary buffer to mark collected variables for upper bound fixing */
1214  int nbinobjvars, /**< number of binary variables with non-zero objective coefficient */
1215  SCIP_VAR** contributors, /**< temporary buffer to use for collecting contributors */
1216  SCIP_HASHTABLE* uselesscliques, /**< hash table to store useless cliques, or NULL */
1217  SCIP_Bool* collect /**< pointer to store if the variable should be stored */
1218  )
1219 {
1220  SCIP_Real lbobjchg;
1221  SCIP_Real ubobjchg;
1222  SCIP_Real objval;
1223  int nlbimplics;
1224  int nubimplics;
1225  int nlbcliques;
1226  int nubcliques;
1227 
1228  assert(objimplics != NULL);
1229 
1230  objval = SCIPvarGetObj(var);
1231  (*objimplics) = NULL;
1232 
1233  if( SCIPisZero(scip, objval) )
1234  (*collect) = FALSE;
1235  else
1236  (*collect) = TRUE;
1237 
1238  nlbimplics = SCIPvarGetNBinImpls(var, FALSE);
1239  nubimplics = SCIPvarGetNBinImpls(var, TRUE);
1240 
1241  nlbcliques = SCIPvarGetNCliques(var, FALSE);
1242  nubcliques = SCIPvarGetNCliques(var, TRUE);
1243 
1244  /* check if implications should be used and if implications are existing */
1245  if( useimplics && nlbimplics + nubimplics + nlbcliques + nubcliques > 0 )
1246  {
1247  int nlbcontributors;
1248  int nubcontributors;
1249 
1250  assert((SCIP_Bool)SCIP_BOUNDTYPE_LOWER == FALSE);
1251  assert((SCIP_Bool)SCIP_BOUNDTYPE_UPPER == TRUE);
1252 
1253  /* get contribution of variable by fixing it to its lower bound w.r.t. minimum activity of the objective function */
1254  SCIP_CALL( collectMinactObjchg(scip, var, SCIP_BOUNDTYPE_LOWER, binobjvarmap, collectedlbvars, nbinobjvars,
1255  contributors, uselesscliques, &nlbcontributors, &lbobjchg) );
1256  assert(!SCIPisNegative(scip, lbobjchg));
1257 
1258  SCIPdebugMessage("variable <%s> fixed to bound=%d implies %d(%d)\n", SCIPvarGetName(var),
1260 
1261  /* ignore implications if the variable has a zero objective coefficient and implications only one variable, since
1262  * this covered by that implied variable
1263  */
1264  if( !(*collect) && nlbcontributors == 1 )
1265  {
1266  /* reset lower bound contributors */
1267  resetContributors(binobjvarmap, collectedlbvars, contributors, nlbcontributors);
1268 
1269  assert(SCIPisZero(scip, objval));
1270  nlbcontributors = 0;
1271  }
1272 
1273  /* get contribution of variable by fixing it to its upper bound w.r.t. minimum activity of the objective function */
1274  SCIP_CALL( collectMinactObjchg(scip, var, SCIP_BOUNDTYPE_UPPER, binobjvarmap, collectedubvars, nbinobjvars,
1275  &contributors[nlbcontributors], uselesscliques, &nubcontributors, &ubobjchg) );
1276  assert(!SCIPisNegative(scip, ubobjchg));
1277 
1278  SCIPdebugMessage("variable <%s> fixed to bound=%d implies %d(%d)\n", SCIPvarGetName(var),
1280 
1281  /* ignore implications if the variable has a zero objective coefficient and implications only one variable, since
1282  * this covered by that implied variable
1283  */
1284  if( !(*collect) && nubcontributors == 1 )
1285  {
1286  /* reset upper bound contributors */
1287  resetContributors(binobjvarmap, collectedubvars, &contributors[nlbcontributors], nubcontributors);
1288 
1289  assert(SCIPisZero(scip, objval));
1290  nubcontributors = 0;
1291  }
1292 
1293  if( (*collect) || nlbcontributors > 1 || nubcontributors > 1 )
1294  {
1295  /* creates an objective implication data structure, fixes (globally) variables which are implied by lower and upper
1296  * bound fixing, and clears the collected arrays for lower and upper bound
1297  */
1298  SCIP_CALL( objimplicsCreate(scip, objimplics, contributors, binobjvarmap, collectedlbvars, collectedubvars, lbobjchg, ubobjchg, nlbcontributors, nubcontributors) );
1299  (*collect) = TRUE;
1300  }
1301  else
1302  {
1303  /* reset lower bound contributors */
1304  resetContributors(binobjvarmap, collectedlbvars, contributors, nlbcontributors);
1305 
1306  /* reset upper bound contributors */
1307  resetContributors(binobjvarmap, collectedubvars, &contributors[nlbcontributors], nubcontributors);
1308  }
1309  }
1310  else if( (*collect) )
1311  {
1314  assert(!SCIPisZero(scip, lbobjchg) || !SCIPisZero(scip, ubobjchg));
1315  assert(!SCIPisNegative(scip, lbobjchg));
1316  assert(!SCIPisNegative(scip, ubobjchg));
1317 
1318  /* creates an "empty" objective implication data structure */
1319  SCIP_CALL( objimplicsCreate(scip, objimplics, NULL, NULL, NULL, NULL, lbobjchg, ubobjchg, 0, 0) );
1320  }
1321 
1322  return SCIP_OKAY;
1323 }
1324 
1325 /** check if the given variable should be collected for the maximum activity propagation */
1326 static
1328  SCIP* scip, /**< SCIP data structure */
1329  SCIP_VAR* var, /**< variable to check */
1330  SCIP_Bool useimplics, /**< should implications be used */
1331  SCIP_Real* objchg /**< pointer to store the objective change w.r.t. maximum activity */
1332  )
1333 {
1334  SCIP_Real lbobjchg;
1335  SCIP_Real ubobjchg;
1336 
1337  /* get contribution of variable by fixing it to its lower bound w.r.t. maximum activity of the objective function */
1338  lbobjchg = getMaxactObjchg(var, SCIP_BOUNDTYPE_LOWER, useimplics);
1339  assert(!SCIPisPositive(scip, lbobjchg));
1340 
1341  /* get contribution of variable by fixing it to its upper bound w.r.t. maximum activity of the objective function */
1342  ubobjchg = getMaxactObjchg(var, SCIP_BOUNDTYPE_UPPER, useimplics);
1343  assert(!SCIPisPositive(scip, ubobjchg));
1344 
1345  (*objchg) = MIN(lbobjchg, ubobjchg);
1346 
1347  /* only consider variables with non-zero objective contribution */
1348  if( SCIPisZero(scip, (*objchg)) )
1349  return FALSE;
1350 
1351  return TRUE;
1352 }
1353 
1354 /** initializate the propagator */
1355 static
1357  SCIP* scip, /**< SCIP data structure */
1358  SCIP_PROPDATA* propdata /**< propagator data */
1359  )
1360 {
1361  SCIP_VAR** vars;
1362  SCIP_VAR* var;
1363  SCIP_HASHMAP* binobjvarmap;
1364  int nvars;
1365  int nbinvars;
1366  int nintvars;
1367  int nminactvars;
1368  int nmaxactvars;
1369  int nobjintvars;
1370  int nobjcontvars;
1371  int nobjvars;
1372  int nbinobjvars;
1373  int v;
1374 
1375  assert(scip != NULL);
1376  assert(propdata != NULL);
1377 
1378  /* get problem variables */
1379  vars = SCIPgetVars(scip);
1380  nvars = SCIPgetNVars(scip);
1381  nintvars = nvars - SCIPgetNContVars(scip);
1382 
1383  nbinvars = 0;
1384  nobjvars = 0;
1385  nbinobjvars = 0;
1386 
1387  SCIP_CALL( SCIPhashmapCreate(&binobjvarmap, SCIPblkmem(scip), SCIPcalcHashtableSize(SCIPgetNObjVars(scip) * 5)) );
1388 
1389  /* count and collect variable problem indices of variables with non-zero objective coefficient */
1390  for( v = 0; v < nvars; ++v )
1391  {
1392  var = vars[v];
1393  assert(var != NULL);
1394 
1395  if( !SCIPisZero(scip, SCIPvarGetObj(var)) )
1396  {
1397  nobjvars++;
1398 
1399  if( SCIPvarIsBinary(var) )
1400  {
1401  SCIP_CALL( SCIPhashmapInsert(binobjvarmap, (void*)var, (void*)(size_t)(nbinobjvars + 1)) );
1402  nbinobjvars++;
1403  }
1404  }
1405 
1406  if( SCIPvarIsBinary(var) )
1407  nbinvars++;
1408  }
1409 
1410  nminactvars = 0;
1411  nmaxactvars = 0;
1412  nobjintvars = 0;
1413  nobjcontvars = 0;
1414 
1415  if( nobjvars > 0 )
1416  {
1417  SCIP_EVENTHDLR* eventhdlr;
1418  SCIP_OBJIMPLICS* objimplics;
1419  SCIP_HASHTABLE* uselesscliques;
1420  SCIP_VAR** contributors;
1421  SCIP_Bool* collectedlbvars;
1422  SCIP_Bool* collectedubvars;
1423  SCIP_Bool collect;
1424  SCIP_Bool useimplics;
1425  SCIP_Real objval;
1426  SCIP_Real objchg;
1427 
1428  eventhdlr = propdata->eventhdlr;
1429  assert(eventhdlr != NULL);
1430 
1431  useimplics = (propdata->propuseimplics && nbinobjvars < propdata->maximplvars);
1432 
1433  /* allocate memory for all arrays */
1434  SCIP_CALL( SCIPallocMemoryArray(scip, &propdata->minactvars, nbinvars) );
1435  SCIP_CALL( SCIPallocMemoryArray(scip, &propdata->minactimpls, nbinvars) );
1436  SCIP_CALL( SCIPallocMemoryArray(scip, &propdata->maxactvars, nbinvars) );
1437  SCIP_CALL( SCIPallocMemoryArray(scip, &propdata->maxactchgs, nbinvars) );
1438  SCIP_CALL( SCIPallocMemoryArray(scip, &propdata->objintvars, nobjvars - nbinobjvars) );
1439 
1440  if( useimplics )
1441  {
1442  int ncliques;
1443 
1444  /* create temporary buffer */
1445  SCIP_CALL( SCIPallocBufferArray(scip, &contributors, nbinobjvars) );
1446  SCIP_CALL( SCIPallocBufferArray(scip, &collectedlbvars, nbinobjvars+1) );
1447  BMSclearMemoryArray(collectedlbvars, nbinobjvars+1);
1448  SCIP_CALL( SCIPallocBufferArray(scip, &collectedubvars, nbinobjvars+1) );
1449  BMSclearMemoryArray(collectedubvars, nbinobjvars+1);
1450 
1451  ncliques = SCIPgetNCliques(scip);
1452 
1453  if( ncliques > 0 )
1454  {
1455  SCIP_CALL( SCIPhashtableCreate(&uselesscliques, SCIPblkmem(scip), SCIPcalcHashtableSize(ncliques),
1456  cliqueGetHashkey, cliqueIsHashkeyEq, cliqueGetHashkeyVal, NULL) );
1457  }
1458  else
1459  uselesscliques = NULL;
1460  }
1461  else
1462  {
1463  contributors = NULL;
1464  collectedlbvars = NULL;
1465  collectedubvars = NULL;
1466  uselesscliques = NULL;
1467  }
1468 
1469  /* collect the variables with non-zero objective contribution and catch global bound tighten events that decrease the
1470  * maximal pseudo objective activity
1471  */
1472  for( v = 0; v < nvars && (nobjintvars == 0 || nobjintvars < nobjvars - nbinobjvars); ++v )
1473  {
1474  var = vars[v];
1475  assert(var != NULL);
1476 
1477  objval = SCIPvarGetObj(var);
1478 
1479  if( SCIPvarIsBinary(var) )
1480  {
1481  /* ignore variables which are globally fixed */
1482  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
1483  {
1484 #ifndef NDEBUG
1485  /* check that the binary implications are applied for binary variables which are globally fixed */
1486  checkImplicsApplied(scip, var);
1487 #endif
1488  continue;
1489  }
1490 
1491  /* check if the variable should be collected for the minimum activity propagation */
1492  SCIP_CALL( collectMinactVar(scip, var, &objimplics, useimplics, binobjvarmap, collectedlbvars, collectedubvars,
1493  nbinobjvars, contributors, uselesscliques, &collect) );
1494 
1495  if( collect )
1496  {
1497  assert(nminactvars < nbinvars);
1498  assert(objimplics != NULL);
1499  assert(objimplics->nlbimpls + objimplics->nubimpls <= nbinobjvars);
1500 
1501  /* collect the binary variable with non-zero objective contribution */
1502  propdata->minactvars[nminactvars] = var;
1503  propdata->minactimpls[nminactvars] = objimplics;
1504  nminactvars++;
1505 
1506  /* catch bound relax event for the binary variable to handel the firstnonfixed index correctly */
1507  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDRELAXED, eventhdlr, (SCIP_EVENTDATA*)propdata, NULL) );
1508 
1509  SCIPdebugMessage("variable <%s>[obj: <%g>] implicit objective change %g\n",
1510  SCIPvarGetName(var), objval, objimplics->maxobjchg);
1511 
1512  /* captures the variable */
1513  SCIP_CALL( SCIPcaptureVar(scip, var) ) ;
1514  }
1515 
1516  /* check if the variable should be collected for the maximum activity propagation */
1517  collect = collectMaxactVar(scip, var, useimplics, &objchg);
1518 
1519  if( collect )
1520  {
1521  assert(nmaxactvars < nbinvars);
1522 
1523  /* collect the binary variable with non-zero objective contribution */
1524  propdata->maxactvars[nmaxactvars] = var;
1525  propdata->maxactchgs[nmaxactvars] = -objchg;
1526  nmaxactvars++;
1527 
1528  /* catch bound change events if the variable has a non-zero objective coefficient to check if the maximum
1529  * activity of the objective function changed
1530  */
1531  SCIP_CALL( catchObjEvent(scip, propdata, eventhdlr, var) );
1532 
1533  /* captures the variable */
1534  SCIP_CALL( SCIPcaptureVar(scip, var) ) ;
1535  }
1536  }
1537  else
1538  {
1539  /* only consider none binary variables with a non-zero objective */
1540  if( SCIPisZero(scip, objval) )
1541  continue;
1542 
1543  assert(nobjintvars < nobjvars - nbinobjvars);
1544 
1545  propdata->objintvars[nobjintvars] = var;
1546  nobjintvars++;
1547 
1548  if( v >= nintvars )
1549  nobjcontvars++;
1550 
1551  /* catch bound change events if the variable has a non-zero objective coefficient to check if the maximum
1552  * activity of the objective function changed
1553  */
1554  SCIP_CALL( catchObjEvent(scip, propdata, eventhdlr, var) );
1555 
1556  /* captures the variable */
1557  SCIP_CALL( SCIPcaptureVar(scip, var) );
1558  }
1559  }
1560 
1561  if( useimplics )
1562  {
1563  if( uselesscliques != NULL )
1564  SCIPhashtableFree(&uselesscliques);
1565 
1566  SCIPfreeBufferArray(scip, &collectedubvars);
1567  SCIPfreeBufferArray(scip, &collectedlbvars);
1568  SCIPfreeBufferArray(scip, &contributors);
1569  }
1570 
1571  if( nminactvars == 0 )
1572  {
1573  SCIPfreeMemoryArray(scip, &propdata->minactvars);
1574  SCIPfreeMemoryArray(scip, &propdata->minactimpls);
1575  propdata->minactvars = NULL;
1576  propdata->minactimpls = NULL;
1577  }
1578  else
1579  {
1580  /* sort binary variables with respect to the absolute value of their maximal potential objective contribution for
1581  * the minimum activity of the objective function
1582  */
1583  SCIPsortDownPtrPtr((void**)propdata->minactimpls, (void**)propdata->minactvars, objimplicsComp, nminactvars);
1584 
1585  SCIPdebugMessage("%d binary variables with non-zero objective contribution w.r.t. the minimum activity of the objective function\n", nminactvars);
1586  }
1587 
1588  if( nmaxactvars == 0 )
1589  {
1590  SCIPfreeMemoryArray(scip, &propdata->maxactvars);
1591  SCIPfreeMemoryArray(scip, &propdata->maxactchgs);
1592  propdata->maxactvars = NULL;
1593  propdata->maxactchgs = NULL;
1594  }
1595  else
1596  {
1597  /* sort binary variables with respect to the absolute value of their maximal potential objective contribution for
1598  * the maximum activity of the objective function
1599  */
1600  SCIPsortDownRealPtr(propdata->maxactchgs, (void**)propdata->maxactvars, nmaxactvars);
1601 
1602  SCIPdebugMessage("%d binary variables with non-zero objective contribution w.r.t. the maximum activity of the objective function\n", nmaxactvars);
1603  }
1604 
1605  if( nobjintvars == 0 )
1606  {
1607  SCIPfreeMemoryArray(scip, &propdata->objintvars);
1608  propdata->objintvars = NULL;
1609  }
1610  else
1611  {
1612  /* sort integer variables with respect to the absolute value of their objective coefficient */
1613  SCIPsortDownPtr((void**)propdata->objintvars, varCompObj, nobjintvars - nobjcontvars);
1614 
1615  /* sort continuous variables with respect to the absolute value of their objective coefficient */
1616  SCIPsortDownPtr((void**)(&propdata->objintvars[nobjintvars - nobjcontvars]), varCompObj, nobjcontvars);
1617 
1618  SCIPdebugMessage("%d integer variables and %d continuous variables with non-zero objective contribution\n",
1619  nobjintvars - nobjcontvars, nobjcontvars);
1620  }
1621  }
1622 
1623  SCIPhashmapFree(&binobjvarmap);
1624 
1625  propdata->nminactvars = nminactvars;
1626  propdata->nmaxactvars = nmaxactvars;
1627  propdata->nobjintvars = nobjintvars;
1628  propdata->maxpseudoobjact = SCIP_INVALID;
1629  propdata->maxpseudoobjactinf = 0;
1630  propdata->lastvarnum = -1;
1631  propdata->glbfirstnonfixed = 0;
1632  propdata->maxactfirstnonfixed = 0;
1633  propdata->firstnonfixed = 0;
1634  propdata->nnewvars = 0;
1635  propdata->cutoffbound = SCIPinfinity(scip);
1636  propdata->lastlowerbound = -SCIPinfinity(scip);
1637  propdata->glbpseudoobjval = -SCIPinfinity(scip);
1638 
1639  propdata->initialized = TRUE;
1640 
1641  /* due to scaling after presolving we need to update the global pseudoactivity and the cutoffbound */
1642  propdata->glbpropagated = FALSE;
1643  propdata->glbpseudoobjval = SCIPgetGlobalPseudoObjval(scip);
1644  propdata->cutoffbound = SCIPgetCutoffbound(scip);
1645  assert(SCIPgetDepth(scip) > 0 || SCIPisFeasEQ(scip, propdata->glbpseudoobjval, SCIPgetPseudoObjval(scip)));
1646 
1647  /* create hash table which is used for resolving bound changes */
1648  if( nminactvars > 0 )
1649  {
1650  SCIP_CALL( SCIPhashtableCreate(&propdata->addedvars, SCIPblkmem(scip), SCIPcalcHashtableSize(5*nvars),
1651  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
1652  }
1653  else
1654  propdata->addedvars = NULL;
1655 
1656 
1657  return SCIP_OKAY;
1658 }
1659 
1660 /** adds for the given none binary variable a conflict bound depending on its objective contribution */
1661 static
1663  SCIP* scip, /**< SCIP data structure */
1664  SCIP_VAR* var, /**< variable to check for objective contribution */
1665  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
1666  SCIP_Real* reqpseudoobjval /**< pointer to store the remaining minimum activity which has to be proven */
1667  )
1668 {
1669  SCIP_Real objval;
1670 
1671  objval = SCIPvarGetObj(var);
1672  assert(!SCIPisZero(scip, objval));
1673 
1674  if( objval > 0.0 )
1675  {
1676  SCIP_Real loclb;
1677  SCIP_Real glblb;
1678 
1679  glblb = SCIPvarGetLbGlobal(var);
1680  loclb = SCIPvarGetLbAtIndex(var, bdchgidx, FALSE);
1681  assert(SCIPisFeasGE(scip, loclb, glblb));
1682 
1683  /* check if the local lower bound (at time stamp bdchgidx) is larger than the global lower bound */
1684  if( SCIPisGT(scip, loclb, glblb) )
1685  {
1686  SCIPdebugMessage(" add bound change <%s>[%g] >= <%g>\n", SCIPvarGetName(var), objval, loclb);
1687  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
1688 
1689  assert(SCIPisPositive(scip, (loclb - glblb) * objval));
1690  (*reqpseudoobjval) -= (loclb - glblb) * objval;
1691  }
1692  }
1693  else
1694  {
1695  SCIP_Real locub;
1696  SCIP_Real glbub;
1697 
1698  glbub = SCIPvarGetUbGlobal(var);
1699  locub = SCIPvarGetUbAtIndex(var, bdchgidx, FALSE);
1700  assert(SCIPisFeasLE(scip, locub, glbub));
1701 
1702  /* check if the local upper bound (at time stamp bdchgidx) is smaller than the global upper bound */
1703  if( SCIPisLT(scip, locub, glbub) )
1704  {
1705  SCIPdebugMessage(" add bound change <%s>[%g] <= <%g>\n", SCIPvarGetName(var), objval, locub);
1706  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
1707 
1708  assert(SCIPisPositive(scip, (locub - glbub) * objval));
1709  (*reqpseudoobjval) -= (locub - glbub) * objval;
1710  }
1711  }
1712 
1713  return SCIP_OKAY;
1714 }
1715 
1716 /** check for the given implication variables of they also contribute to the required minimum activity */
1717 static
1719  SCIP* scip, /**< SCIP data structure */
1720  SCIP_VAR** vars, /**< variable to check for objective contribution */
1721  int start, /**< start index */
1722  int end, /**< end index */
1723  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
1724  SCIP_HASHTABLE* addedvars, /**< hash table containing variables which are already add directly or implicitly due to implications */
1725  SCIP_Real* reqpseudoobjval, /**< pointer to store the remaining minimum activity which has to be proven */
1726  SCIP_Bool* foundimplics /**< pointer to store if an implication is found */
1727  )
1728 {
1729  SCIP_VAR* var;
1730  SCIP_Real lb;
1731  SCIP_Real ub;
1732  int v;
1733 
1734  assert(foundimplics != NULL);
1735  assert(*foundimplics == FALSE);
1736 
1737  for( v = start; v < end; ++v )
1738  {
1739  var = vars[v];
1740  assert(var != NULL);
1741  assert(SCIPvarIsBinary(var));
1742 
1743  lb = SCIPvarGetLbAtIndex(var, bdchgidx, FALSE);
1744  ub = SCIPvarGetUbAtIndex(var, bdchgidx, FALSE);
1745 
1746  if( lb < 0.5 && ub > 0.5 && !SCIPhashtableExists(addedvars, (void*)var) )
1747  {
1748  (*reqpseudoobjval) -= REALABS(SCIPvarGetObj(var));
1749  SCIPdebugMessage(" implicated variables <%s>[%g] bdchgidx [%g,%g] -> remaining <%g>\n", SCIPvarGetName(var), SCIPvarGetObj(var), lb, ub, *reqpseudoobjval);
1750 
1751  SCIP_CALL( SCIPhashtableInsert(addedvars, (void*)var) );
1752  assert(SCIPhashtableExists(addedvars, (void*)var));
1753  (*foundimplics) = TRUE;
1754  }
1755  }
1756 
1757  return SCIP_OKAY;
1758 }
1759 
1760 /** adds for the given binary variable a conflict bound depending on its objective contribution */
1761 static
1763  SCIP* scip, /**< SCIP data structure */
1764  SCIP_VAR* var, /**< variable to check for objective contribution */
1765  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
1766  SCIP_OBJIMPLICS* objimplics, /**< objective implication data for the given variable */
1767  SCIP_HASHTABLE* addedvars, /**< hash table containing variables which are already add directly or implicitly due to implications */
1768  SCIP_Bool respropuseimplics, /**< should implications be used */
1769  SCIP_Real* reqpseudoobjval /**< pointer to store the remaining minimum activity which has to be proven */
1770  )
1771 {
1772  SCIP_Real objval;
1773  SCIP_Real lb;
1774  SCIP_Real ub;
1775  SCIP_Bool foundimplics;
1776 
1777  assert(SCIPvarIsBinary(var));
1778 
1779  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
1780  return SCIP_OKAY;
1781 
1782  lb = SCIPvarGetLbAtIndex(var, bdchgidx, FALSE);
1783  ub = SCIPvarGetUbAtIndex(var, bdchgidx, FALSE);
1784 
1785  objval = SCIPvarGetObj(var);
1786  foundimplics = FALSE;
1787 
1788  /* only consider variables which are fixed */
1789  if( lb > 0.5 )
1790  {
1791  if( respropuseimplics )
1792  {
1793  SCIP_CALL( getConflictImplics(scip, objimplics->objvars, objimplics->nlbimpls, objimplics->nlbimpls + objimplics->nubimpls,
1794  bdchgidx, addedvars, reqpseudoobjval, &foundimplics) );
1795  }
1796 
1797  /* check if the binary variable has a positive contribution (positive objective coefficient since it is fixed to
1798  * one) or is needed due a positive contribution of an implied variable
1799  */
1800  if( foundimplics || SCIPisPositive(scip, objval) )
1801  {
1802  SCIPdebugMessage(" add bound change <%s>[%g] >= <%g> bdchgidx [%g,%g]\n", SCIPvarGetName(var), objval, lb, lb, ub);
1803  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
1804 
1805  (*reqpseudoobjval) -= MAX(0.0, objval);
1806 
1807  if( addedvars != NULL )
1808  {
1809  assert(!SCIPhashtableExists(addedvars, (void*)var));
1810  SCIP_CALL( SCIPhashtableInsert(addedvars, (void*)var) );
1811  }
1812  }
1813  }
1814  else if( ub < 0.5 )
1815  {
1816  if( respropuseimplics )
1817  {
1818  SCIP_CALL( getConflictImplics(scip, objimplics->objvars, 0, objimplics->nlbimpls,
1819  bdchgidx, addedvars, reqpseudoobjval, &foundimplics) );
1820  }
1821 
1822  /* check if the binary variable has a positive contribution (negative objective coefficient since it is fixed to
1823  * zero) or is needed due a positive contribution of an implied variable
1824  */
1825  if( foundimplics || SCIPisNegative(scip, objval) )
1826  {
1827  SCIPdebugMessage(" add bound change <%s>[%g] <= <%g> bdchgidx=[%g,%g]\n", SCIPvarGetName(var), objval, ub, lb, ub);
1828  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
1829 
1830  (*reqpseudoobjval) += MIN(0.0, objval);
1831 
1832  if( addedvars != NULL )
1833  {
1834  assert(!SCIPhashtableExists(addedvars, (void*)var));
1835  SCIP_CALL( SCIPhashtableInsert(addedvars, (void*)var) );
1836  }
1837  }
1838  }
1839 
1840  return SCIP_OKAY;
1841 }
1842 
1843 
1844 /** resolves a propagation by supplying the variables whose bound changes increased the pseudo objective value above the
1845  * cutoff bound
1846  */
1847 static
1849  SCIP* scip, /**< SCIP data structure */
1850  SCIP_PROPDATA* propdata, /**< propagator data */
1851  SCIP_VAR* var, /**< variable that was deduced */
1852  int inferinfo, /**< inference information */
1853  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
1854  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
1855  SCIP_HASHTABLE* addedvars, /**< hash table which contains variable which are already added or implict given as reason for the resolve, or NULL */
1856  SCIP_Real* cutoffbound /**< pointer to store the adjusted cutoff bound */
1857  )
1858 {
1859  if( inferinfo != -1 )
1860  {
1861  SCIP_OBJIMPLICS* objimplics;
1862  SCIP_Bool foundimplics;
1863  int start;
1864  int end;
1865 
1866  assert(var != NULL);
1867  assert(SCIPvarIsBinary(var));
1868  assert(bdchgidx != NULL);
1869  assert(SCIPisEQ(scip, SCIPvarGetLbAtIndex(var, bdchgidx, TRUE), SCIPvarGetUbAtIndex(var, bdchgidx, TRUE)));
1870  assert(inferinfo >= 0);
1871  assert(inferinfo < propdata->nminactvars);
1872  assert((SCIP_Bool)SCIP_BOUNDTYPE_LOWER == FALSE);
1873  assert((SCIP_Bool)SCIP_BOUNDTYPE_UPPER == TRUE);
1874 
1875  objimplics = propdata->minactimpls[inferinfo];
1876  assert(objimplics != NULL);
1877 
1878  /* get the objective contribution if we would fix the binray inference variable to its other bound */
1879  (*cutoffbound) -= getVarObjchg(var, SCIPvarGetBestBoundType(var), boundtype);
1880  foundimplics = FALSE;
1881 
1882  if( boundtype == SCIP_BOUNDTYPE_LOWER )
1883  {
1884  start = 0;
1885  end = objimplics->nlbimpls;
1886  }
1887  else
1888  {
1889  start = objimplics->nlbimpls;
1890  end = objimplics->nlbimpls + objimplics->nubimpls;
1891  }
1892 
1893  SCIP_CALL( getConflictImplics(scip, objimplics->objvars, start, end, bdchgidx, addedvars, cutoffbound, &foundimplics) );
1894  }
1895  else
1896  {
1897  SCIP_Real glbbound;
1898  SCIP_Real newbound;
1899  SCIP_Real objval;
1900 
1901  objval = SCIPvarGetObj(var);
1902 
1903  assert(!SCIPisZero(scip, objval));
1904 
1905  if( objval > 0.0 )
1906  {
1907  newbound = SCIPvarGetUbAtIndex(var, bdchgidx, TRUE);
1908  glbbound = SCIPvarGetLbGlobal(var);
1909  }
1910  else
1911  {
1912  newbound = SCIPvarGetLbAtIndex(var, bdchgidx, TRUE);
1913  glbbound = SCIPvarGetUbGlobal(var);
1914  }
1915 
1916  /* in case the variable is integral we just need to prove the newbound plus/minus (1 - epsilon) since the this bound
1917  * would be rounded to newbound due to integrability which is global information
1918  */
1919  if( SCIPvarIsIntegral(var) )
1920  {
1921  if( objval > 0.0 )
1922  newbound += 1 - 10 * SCIPfeastol(scip);
1923  else
1924  newbound -= 1 - 10 * SCIPfeastol(scip);
1925  }
1926 
1927  /* adjust the cutoff bound by the portion the inference variable contributes to the presudo objective activitiy
1928  * (minactivity)
1929  */
1930  assert(!SCIPisNegative(scip, objval * (newbound - glbbound)));
1931  (*cutoffbound) -= objval * (newbound - glbbound);
1932  }
1933 
1934  return SCIP_OKAY;
1935 }
1936 
1937 
1938 /** resolves a propagation by supplying the variables whose bound changes increased the pseudo objective value above the
1939  * cutoff bound
1940  */
1941 static
1943  SCIP* scip, /**< SCIP data structure */
1944  SCIP_PROPDATA* propdata, /**< propagator data */
1945  SCIP_Real cutoffbound, /**< the global cutoff */
1946  SCIP_VAR* infervar, /**< variable that was deduced, or NULL for conflict analysis initialization */
1947  int inferinfo, /**< inference information */
1948  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
1949  SCIP_BDCHGIDX* bdchgidx /**< bound change index (time stamp of bound change), or NULL for current time */
1950  )
1951 {
1952  SCIP_HASHTABLE* addedvars;
1953  SCIP_VAR** vars;
1954  SCIP_VAR* var;
1955  SCIP_Real glbpseudoobjval;
1956  SCIP_Real reqpseudoobjval;
1957  SCIP_Bool infinity;
1958  int nvars;
1959  int v;
1960 
1961  infinity = FALSE;
1962  addedvars = NULL;
1963  nvars = propdata->nminactvars;
1964 
1965  /* the global pseudo value gives us a global valid minimal activity
1966  *
1967  * @note The global pseudo objective activity can be minus infinity. In that case all variable are part of the
1968  * reason/explanation
1969  *
1970  * @note If the global pseudo objective activity is greater than the required minactivity, the local bound change
1971  * which has to explained is actually (now) a global one. That means, the reason/explanation is empty
1972  */
1973  glbpseudoobjval = SCIPgetGlobalPseudoObjval(scip);
1974 
1975  if( SCIPisInfinity(scip, -glbpseudoobjval) )
1976  {
1977  infinity = TRUE;
1978  reqpseudoobjval = cutoffbound;
1979  }
1980  else
1981  {
1982  /* clear hash table for storing variables which are not needed to add the reason due to global implications or
1983  * already added
1984  */
1985  if( nvars > 0 )
1986  {
1987  addedvars = propdata->addedvars;
1988  SCIPhashtableRemoveAll(addedvars);
1989  }
1990 
1991  if( infervar != NULL )
1992  {
1993  SCIP_CALL( adjustCutoffbound(scip, propdata, infervar, inferinfo, boundtype, bdchgidx, addedvars, &cutoffbound) );
1994  }
1995 
1996  reqpseudoobjval = cutoffbound - glbpseudoobjval;
1997  }
1998 
1999  SCIPdebugMessage("resolve propagation global pseudo objective <%g>, cutoff bounda <%g>, required minactivity <%g>\n",
2000  glbpseudoobjval, cutoffbound, reqpseudoobjval);
2001 
2002  /* the variables responsible for the propagation are the ones with
2003  * - obj > 0 and local lb > global lb
2004  * - obj < 0 and local ub < global ub
2005  *
2006  * collect all variables which contribute positively to the pseudo objective value (minimum activity) until we
2007  * reached the (adjusted) required minimum activity for the inference bound chnage
2008  */
2009 
2010  /* first consider the binary variables */
2011  if( nvars > 0 )
2012  {
2013  SCIP_OBJIMPLICS** minactimpls;
2014 
2015  vars = propdata->minactvars;
2016  assert(vars != NULL);
2017 
2018  minactimpls = propdata->minactimpls;
2019  assert(minactimpls != NULL);
2020 
2021 #ifndef NDEBUG
2022  checkGlbfirstnonfixed(scip, propdata);
2023 #endif
2024 
2025  if( infinity )
2026  {
2027  /* if the required minimum activity is minus infinity, we have to add all variables which contribute the local
2028  * prseudo objective activity
2029  */
2030 
2031  for( v = propdata->glbfirstnonfixed; v < nvars; ++v )
2032  {
2033  var = vars[v];
2034  assert(var != NULL);
2035 
2036  /* @note binary variables can have a zero objective value */
2037 
2038  if( var == infervar )
2039  continue;
2040 
2041  SCIP_CALL( addConflictBinvar(scip, var, bdchgidx, NULL, NULL, FALSE, &reqpseudoobjval) );
2042  }
2043  }
2044  else
2045  {
2046  assert(addedvars != NULL);
2047 
2048  for( v = propdata->glbfirstnonfixed; v < nvars && SCIPisPositive(scip, reqpseudoobjval); ++v )
2049  {
2050  var = vars[v];
2051  assert(var != NULL);
2052 
2053  /* @note binary variables can have a zero objective value */
2054 
2055  if( var == infervar )
2056  continue;
2057 
2058  if( SCIPhashtableExists(addedvars, (void*)var) )
2059  continue;
2060 
2061  SCIP_CALL( addConflictBinvar(scip, var, bdchgidx, minactimpls[v], addedvars, propdata->respropuseimplics, &reqpseudoobjval) );
2062  }
2063  }
2064  }
2065 
2066  vars = propdata->objintvars;
2067  nvars = propdata->nobjintvars;
2068  assert(nvars == 0 || vars != NULL);
2069 
2070  /* second consider the none binary variables */
2071  for( v = 0; v < nvars && (infinity || SCIPisPositive(scip, reqpseudoobjval)); ++v )
2072  {
2073  var = vars[v];
2074  assert(var != NULL);
2075  assert(!SCIPisZero(scip, SCIPvarGetObj(var)));
2076 
2077  if( var == infervar )
2078  continue;
2079 
2080  SCIP_CALL( addConflictBounds(scip, var, bdchgidx, &reqpseudoobjval) );
2081  }
2082 
2083  return SCIP_OKAY;
2084 }
2085 
2086 /** propagates the given variable against the cutoff bound */
2087 static
2089  SCIP* scip, /**< SCIP data structure */
2090  SCIP_PROP* prop, /**< propagator, or NULL */
2091  SCIP_VAR* var, /**< variable to propagate */
2092  int inferinfo, /**< inference information to store with the bound change */
2093  SCIP_Real objchg, /**< objective change */
2094  SCIP_Real cutoffbound, /**< cutoff bound to use */
2095  SCIP_Real pseudoobjval, /**< pseudo objective value to use */
2096  SCIP_Bool local, /**< local or global propagation */
2097  SCIP_Bool* tightened /**< pointer to store if the variable domain was tightened */
2098  )
2099 {
2100  SCIP_Real lb;
2101  SCIP_Real ub;
2102  SCIP_Real newbd;
2103  SCIP_Bool infeasible;
2104 
2105  assert(!SCIPisZero(scip, objchg));
2106  assert(!SCIPisInfinity(scip, -pseudoobjval));
2107  assert(!SCIPisInfinity(scip, cutoffbound));
2108  assert(SCIPisLT(scip, pseudoobjval, cutoffbound) );
2109  assert(tightened != NULL);
2110 
2111  *tightened = FALSE;
2112 
2113  /* collect bounds of the variable */
2114  if( local )
2115  {
2116  assert(prop != NULL);
2117  lb = SCIPvarGetLbLocal(var);
2118  ub = SCIPvarGetUbLocal(var);
2119  }
2120  else
2121  {
2122  lb = SCIPvarGetLbGlobal(var);
2123  ub = SCIPvarGetUbGlobal(var);
2124  }
2125 
2126  if( SCIPisFeasEQ(scip, lb, ub) )
2127  return SCIP_OKAY;
2128 
2129  /* depending on the objective contribution we can try to tighten the lower or upper bound of the variable */
2130  if( objchg > 0.0 )
2131  {
2132  newbd = lb + (cutoffbound - pseudoobjval) / objchg;
2133 
2134  if( local )
2135  {
2136  SCIP_CALL( SCIPinferVarUbProp(scip, var, newbd, prop, inferinfo, FALSE, &infeasible, tightened) );
2137  assert(!infeasible);
2138 
2139  if( *tightened ) /* might not be tightened due to numerical reasons */
2140  {
2141  SCIPdebugMessage(" -> new (local) upper bound of variable <%s>[%g,%g]: %g, objective change <%g>, pseudo objective <%g>, cutoff bound <%g>\n",
2142  SCIPvarGetName(var), lb, ub, newbd, objchg, pseudoobjval, cutoffbound);
2143  }
2144  }
2145  else
2146  {
2147  SCIP_CALL( SCIPtightenVarUbGlobal(scip, var, newbd, FALSE, &infeasible, tightened) );
2148  assert(!infeasible);
2149 
2150  if( *tightened )
2151  {
2152  SCIPdebugMessage(" -> new (global) upper bound of variable <%s>[%g,%g]: %g, objective change <%g>, pseudo objective <%g>, cutoff bound <%g>\n",
2153  SCIPvarGetName(var), lb, ub, newbd, objchg, pseudoobjval, cutoffbound);
2154  }
2155  }
2156  }
2157  else
2158  {
2159  newbd = ub + (cutoffbound - pseudoobjval) / objchg;
2160 
2161  if( local )
2162  {
2163  SCIP_CALL( SCIPinferVarLbProp(scip, var, newbd, prop, inferinfo, FALSE, &infeasible, tightened) );
2164  assert(!infeasible);
2165 
2166  if( *tightened ) /* might not be tightened due to numerical reasons */
2167  {
2168  SCIPdebugMessage(" -> new (local) lower bound of variable <%s>[%g,%g]: %g, objective change <%g>, pseudo objective <%g>, cutoff bound <%g>\n",
2169  SCIPvarGetName(var), lb, ub, newbd, objchg, pseudoobjval, cutoffbound);
2170  }
2171  }
2172  else
2173  {
2174  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, newbd, FALSE, &infeasible, tightened) );
2175  assert(!infeasible);
2176 
2177  if( *tightened )
2178  {
2179  SCIPdebugMessage(" -> new (global) lower bound of variable <%s>[%g,%g]: %g, objective change <%g>, pseudo objective <%g>, cutoff bound <%g>\n",
2180  SCIPvarGetName(var), lb, ub, newbd, objchg, pseudoobjval, cutoffbound);
2181  }
2182  }
2183  }
2184 
2185  return SCIP_OKAY;
2186 }
2187 
2188 /** propagates the given binary variable against the cutoff bound */
2189 static
2191  SCIP* scip, /**< SCIP data structure */
2192  SCIP_PROP* prop, /**< propagator, or NULL */
2193  SCIP_VAR* var, /**< variable to propagate */
2194  int pos, /**< position of the variable in the corresponding propdata variable array */
2195  SCIP_Real cutoffbound, /**< cutoff bound to use */
2196  SCIP_Real pseudoobjval, /**< pseudo objective value to use */
2197  SCIP_Bool* tightened, /**< pointer to store if the variable domain was tightened */
2198  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
2199  SCIP_Bool local /**< propagate local bounds, otherwise global bounds */
2200  )
2201 {
2202  SCIP_PROPDATA* propdata;
2203  SCIP_OBJIMPLICS* objimplics;
2204  SCIP_Real lbobjchg;
2205  SCIP_Real ubobjchg;
2206  SCIP_Real objchg;
2207 
2208  assert(SCIPvarIsBinary(var));
2209 
2210  propdata = SCIPpropGetData(prop);
2211  assert(propdata != NULL);
2212 
2213  objimplics = propdata->minactimpls[pos];
2214  assert(objimplics != NULL);
2215 
2216  /* get objective change in case of fixing the variable to its lower bound (that is zero) */
2217  SCIP_CALL( getMinactObjchg(scip, var, objimplics, NULL, SCIP_BOUNDTYPE_LOWER, local, &lbobjchg) );
2218  assert(!SCIPisNegative(scip, lbobjchg));
2219 
2220  /* get objective change in case of fixing the variable to its upper bound (that is one) */
2221  SCIP_CALL( getMinactObjchg(scip, var, objimplics, NULL, SCIP_BOUNDTYPE_UPPER, local, &ubobjchg) );
2222  assert(!SCIPisNegative(scip, ubobjchg));
2223 
2224  (*tightened) = FALSE;
2225 
2226  /* nothing can be done if the objective contribution is zero independently of the bound */
2227  if( SCIPisZero(scip, lbobjchg) && SCIPisZero(scip, ubobjchg) )
2228  return SCIP_OKAY;
2229 
2230  /* if the lbobjchg and ubobjchg are both able to fix the variable to its upper (1.0) or lower (0.0) bound,
2231  * respectively, we detected an cutoff
2232  *
2233  * @note There is no need to use SCIPisFeasLT() in case the objective is integral since the cutoff bound in that case
2234  * is the upper bound minus 1 plus the SCIPcutoffbounddelta() (which is MIN(100.0 * feastol, 0.0001)). However,
2235  * if the objective is not integral we have to check w.r.t. an epsilon to avoid numerical problems.
2236  */
2237  if( SCIPisFeasLT(scip, cutoffbound, pseudoobjval + ubobjchg) && SCIPisFeasLT(scip, cutoffbound, pseudoobjval + lbobjchg) )
2238  {
2239  /* check if conflict analysis is applicable */
2240  if( local && SCIPisConflictAnalysisApplicable(scip) )
2241  {
2242  assert(SCIPgetDepth(scip) > 0);
2243 
2244  /* initialize conflict analysis */
2246 
2247  /* add all variable whose best bound changes increased the pseudo objective value above to cutoff bound */
2248  SCIP_CALL( resolvePropagation(scip, propdata, pseudoobjval, NULL, -1, SCIP_BOUNDTYPE_UPPER, NULL) );
2249 
2250  /* analyze the conflict */
2251  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
2252  }
2253 
2254  (*cutoff) = TRUE;
2255  }
2256  else
2257  {
2258  /* try to tighten the variable bound use the larger objective contribution */
2259  if( lbobjchg > ubobjchg )
2260  objchg = -lbobjchg;
2261  else
2262  objchg = ubobjchg;
2263 
2264  SCIP_CALL( propagateCutoffboundVar(scip, prop, var, pos, objchg, cutoffbound, pseudoobjval, local, tightened) );
2265  }
2266 
2267  return SCIP_OKAY;
2268 }
2269 
2270 /** globally propagates if a new cutoff bound or global pseudo objective value (minimum activity of the objective
2271  * function) is available
2272  */
2273 static
2275  SCIP* scip, /**< SCIP data structure */
2276  SCIP_PROP* prop, /**< propagator */
2277  int* nchgbds, /**< pointer to store the number of bound changes */
2278  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
2279  )
2280 {
2281  SCIP_PROPDATA* propdata;
2282  SCIP_VAR** minactvars;
2283  SCIP_VAR** objintvars;
2284  SCIP_VAR* var;
2285  SCIP_Bool tightened;
2286  SCIP_Real pseudoobjval;
2287  SCIP_Real cutoffbound;
2288  int nminactvars;
2289  int nobjintvars;
2290  int v;
2291 
2292  /* this method should not be called in the root node of the search tree since the standard propagation already does
2293  * the job
2294  */
2295  assert(SCIPgetDepth(scip) > 0);
2296 
2297  propdata = SCIPpropGetData(prop);
2298  assert(propdata != NULL);
2299 
2300  pseudoobjval = SCIPgetGlobalPseudoObjval(scip);
2301  cutoffbound = propdata->cutoffbound;
2302 
2303  /* nothing can be done if the global pseudo objective is minus infinity */
2304  if( SCIPisInfinity(scip, -pseudoobjval) )
2305  return SCIP_OKAY;
2306 
2307  /* check if the global pseudo objective value (minimum activity of the objective function) is greater or equal to
2308  * the cutoff bound
2309  */
2310  if( SCIPisGE(scip, pseudoobjval, cutoffbound) )
2311  {
2312  *cutoff = TRUE;
2313  return SCIP_OKAY;
2314  }
2315 
2316  minactvars = propdata->minactvars;
2317  objintvars = propdata->objintvars;
2318  nminactvars = propdata->nminactvars;
2319  nobjintvars = propdata->nobjintvars;
2320 
2321 #ifndef NDEBUG
2322  checkGlbfirstnonfixed(scip, propdata);
2323 #endif
2324 
2325  *cutoff = FALSE;
2326 
2327  /* always propagate the binary variables completely */
2328  for( v = propdata->glbfirstnonfixed; v < nminactvars; ++v )
2329  {
2330  var = minactvars[v];
2331  assert(var != NULL);
2332 
2333  /* check if the variables is already globally fixed; if so continue with the potential candidate */
2334  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
2335  continue;
2336 
2337  /* propagates the cutoff bound for the given binary variable */
2338  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, FALSE) );
2339 
2340  /* the binary variables are sorted in non-increasing manner w.r.t. the absolute value of their objective
2341  * contribution w.r.t. minimum activity (pseudo objective value) of the objective function; these values are the
2342  * increase in the pseudo objective activity we would get if we fix the variable to its worse bound; hence, we can
2343  * stop if for a variable this potential increase is not enough too exceed the cutoff bound;
2344  */
2345  if( !tightened )
2346  {
2347  SCIPdebugMessage("interrupt global pseudo objective propagation w.r.t. cutoff bound <%.15g> for binary variables after %d from %d binary variables\n",
2348  cutoffbound, v, nminactvars);
2349  break;
2350  }
2351 
2352  if( *cutoff )
2353  return SCIP_OKAY;
2354 
2355  /* @note The variable might not be globally fixed right away since this would destroy the local internal
2356  * data structure of a search node; the bound change is in that case pending; hence we cannot assert
2357  * that the variable is globally fixed
2358  */
2359  (*nchgbds)++;
2360  }
2361  propdata->glbfirstnonfixed = v;
2362  propdata->firstnonfixed = MAX(propdata->firstnonfixed, v);
2363 
2364  /* check all binary variables which could potentially be fixed */
2365  for( ; v < nminactvars && cutoffbound - pseudoobjval < propdata->minactimpls[v]->maxobjchg; ++v )
2366  {
2367  var = minactvars[v];
2368  assert(var != NULL);
2369 
2370  /* check if the variables is already globally fixed; if so continue with the potential candidate */
2371  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
2372  continue;
2373 
2374  /* propagates the cutoff bound for the given binary variable */
2375  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, FALSE) );
2376 
2377  /* check if the domain of the variable was reduced */
2378  if( tightened )
2379  (*nchgbds)++;
2380 
2381  if( *cutoff )
2382  return SCIP_OKAY;
2383  }
2384 
2385 #if 0 /* might fail, but is not a real error, still need to investigate */
2386 #ifndef NDEBUG
2387  /* check that the abort criteria for the binary variables works */
2388  for( ; v < nminactvars; ++v )
2389  {
2390  assert(cutoffbound - pseudoobjval >= propdata->minactimpls[v]->maxobjchg);
2391 
2392  var = minactvars[v];
2393  assert(var != NULL);
2394 
2395  /* check if the variable is already locally fixed; in that case we just continue with the next potential
2396  * candidate
2397  */
2398  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
2399  continue;
2400 
2401  /* propagates the cutoff bound for the given binary variable */
2402  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, FALSE) );
2403  assert(!tightened);
2404  assert(!(*cutoff));
2405  }
2406 #endif
2407 #endif
2408 
2409  /* propagate the none binary variables completely */
2410  for( v = 0; v < nobjintvars; ++v )
2411  {
2412  var = objintvars[v];
2413  assert(var != NULL);
2414  assert(!SCIPisZero(scip, SCIPvarGetObj(var)));
2415 
2416  /* try to tighten the bound of the variable */
2417  SCIP_CALL( propagateCutoffboundVar(scip, NULL, var, -1, SCIPvarGetObj(var), cutoffbound, pseudoobjval, FALSE, &tightened) );
2418 
2419  /* check if the domain of the variable was reduced */
2420  if( tightened )
2421  (*nchgbds)++;
2422  }
2423 
2424  propdata->glbpropagated = TRUE;
2425 
2426  return SCIP_OKAY;
2427 }
2428 
2429 /** propagates the cutoff bound for binary variables (c*x <= cutoff) */
2430 static
2432  SCIP* scip, /**< SCIP data structure */
2433  SCIP_PROP* prop, /**< propagator */
2434  SCIP_Real cutoffbound, /**< cutoff bound to use */
2435  SCIP_Real pseudoobjval, /**< pseudo objective value to use */
2436  int* nfixedvars, /**< pointer to store the number of fixed variables */
2437  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
2438  )
2439 {
2440  SCIP_PROPDATA* propdata;
2441  SCIP_VAR** minactvars;
2442  SCIP_VAR* var;
2443  SCIP_Bool tightened;
2444  int nminactvars;
2445  int v;
2446 
2447  propdata = SCIPpropGetData(prop);
2448  assert(propdata != NULL);
2449 
2450  minactvars = propdata->minactvars;
2451  nminactvars = propdata->nminactvars;
2452  assert(nminactvars == 0 || minactvars != NULL);
2453 
2454  /* always propagate the binary variables completely; note that the variables before the firstnonfixed indexed are
2455  * already locally fixed and those before glbfirstnonfixed are already globally fixed
2456  */
2457 
2458 #ifndef NDEBUG
2459  /* check that the variables before glbfirstnonfixed are globally fixed */
2460  checkGlbfirstnonfixed(scip, propdata);
2461 
2462  /* check that the variables before firstnonfixed are locally fixed */
2463  for( v = propdata->glbfirstnonfixed; v < propdata->firstnonfixed; ++v )
2464  {
2465  var = minactvars[v];
2466  assert(var != NULL);
2467 
2468  assert(SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5);
2469  }
2470 #endif
2471 
2472  (*cutoff) = FALSE;
2473 
2474  for( v = propdata->firstnonfixed; v < nminactvars; ++v )
2475  {
2476  var = minactvars[v];
2477  assert(var != NULL);
2478 
2479  /* check if the variable is already locally fixed; in that case we just continue with the next potential
2480  * candidate
2481  */
2482  if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5)
2483  continue;
2484 
2485  /* propagates the cutoff bound for the given binary variable */
2486  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, TRUE) );
2487 
2488  /* the binary variables are sorted in non-increasing manner w.r.t. the absolute value of their objective
2489  * contribution w.r.t. minimum activity of the objective function; These values are the increase in the pseudo
2490  * objective activity (minimum activity of the objective function) we would get if we fix the variable to its
2491  * worse bound; hence, we can stop if for a variable this potential increase is not enough too exceed the cutoff
2492  * bound;
2493  */
2494  if( !tightened )
2495  {
2496  SCIPdebugMessage("interrupt local pseudo objective propagation w.r.t. cutoff bound <%.15g> for binary variables after %d from %d binary variables\n",
2497  cutoffbound, v, nminactvars);
2498  break;
2499  }
2500 
2501  if( *cutoff )
2502  return SCIP_OKAY;
2503 
2504  /* check that the binary variable is locally fixed */
2505  assert(SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5);
2506  (*nfixedvars)++;
2507  }
2508  propdata->firstnonfixed = v;
2509 
2510  /* check all binary variables which could potentially be fixed */
2511  for( ; v < nminactvars && cutoffbound - pseudoobjval < propdata->minactimpls[v]->maxobjchg; ++v )
2512  {
2513  var = minactvars[v];
2514  assert(var != NULL);
2515 
2516  /* check if the variable is already locally fixed; in that case we just continue with the next potential
2517  * candidate
2518  */
2519  if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5)
2520  continue;
2521 
2522  /* propagates the cutoff bound for the given binary variable */
2523  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, TRUE) );
2524 
2525  if( tightened )
2526  {
2527  assert(SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5);
2528  (*nfixedvars)++;
2529  }
2530 
2531  if( *cutoff )
2532  return SCIP_OKAY;
2533  }
2534 
2535 #if 0 /* might fail, but is not a real error, still need to investigate */
2536 #ifndef NDEBUG
2537  /* check that the abort criteria for the binary variables works */
2538  for( ; v < nminactvars; ++v )
2539  {
2540  var = minactvars[v];
2541  assert(var != NULL);
2542 
2543  assert(cutoffbound - pseudoobjval >= propdata->minactimpls[v]->maxobjchg);
2544 
2545  /* check if the variable is already locally fixed; in that case we just continue with the next potential
2546  * candidate
2547  */
2548  if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5)
2549  continue;
2550 
2551  /* propagates the cutoff bound for the given binary variable */
2552  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, TRUE) );
2553  assert(!tightened);
2554  assert(!(*cutoff));
2555  }
2556 #endif
2557 #endif
2558 
2559  return SCIP_OKAY;
2560 }
2561 
2562 /** propagates the cutoff bound c*x <= cutoff */
2563 static
2565  SCIP* scip, /**< SCIP data structure */
2566  SCIP_PROP* prop, /**< propagator */
2567  SCIP_RESULT* result /**< pointer to store the result of the callback method */
2568  )
2569 {
2570  SCIP_PROPDATA* propdata;
2571  SCIP_Real pseudoobjval;
2572  SCIP_Real cutoffbound;
2573  SCIP_Bool cutoff;
2574  SCIP_Bool tightened;
2575  int nchgbds;
2576 
2577  assert(result != NULL);
2578 
2579  (*result) = SCIP_DIDNOTRUN;
2580 
2581  propdata = SCIPpropGetData(prop);
2582  assert(propdata != NULL);
2583 
2584  /* get current pseudo objective value (minimum activity of the objective function) and cutoff bound */
2585  pseudoobjval = SCIPgetPseudoObjval(scip);
2586  if( SCIPisInfinity(scip, -pseudoobjval) )
2587  return SCIP_OKAY;
2588  cutoffbound = SCIPgetCutoffbound(scip);
2589  if( SCIPisInfinity(scip, cutoffbound) )
2590  return SCIP_OKAY;
2591 
2592  /* @note A new global pseudo objective value could be used to retrive global fixings. There is, however, no need to
2593  * check if a new global pseudo objective value is available. This is the case since a new (better) global
2594  * pseudo activity implicis that a global bound change was performed. That causes that the root node of the
2595  * search tree get marked for repropagation. That will result in propagation call of the pseudo objective
2596  * propagator.
2597  */
2598 
2599  /* check current cutoff bound */
2600  if( cutoffbound < propdata->cutoffbound )
2601  {
2602  propdata->glbpropagated = FALSE;
2603  propdata->cutoffbound = cutoffbound;
2604  }
2605 
2606  nchgbds = 0;
2607  cutoff = FALSE;
2608  (*result) = SCIP_DIDNOTFIND;
2609 
2610  /* check if we have a new cutoff bound; in that case we globally propagate this new bound
2611  *
2612  * @note there is no need to propagate the cutoff bound if we are in the root node since this will be done by the
2613  * standard local propagation
2614  */
2615  if( propdata->propcutoffbound && !propdata->glbpropagated && SCIPgetDepth(scip) > 0 )
2616  {
2617  /* first globally propagate new cutoff bound or pseudo objective activity */
2618  SCIP_CALL( propagateCutoffboundGlobally(scip, prop, &nchgbds, &cutoff) );
2619 
2620  if( cutoff )
2621  {
2622  /* we are done with solving since a global pseudo activity is greater or equal to the cutoff bound */
2623  SCIP_CALL( SCIPcutoffNode(scip, SCIPgetRootNode(scip)) );
2624 
2625  (*result) = SCIP_CUTOFF;
2626  return SCIP_OKAY;
2627  }
2628 
2629  /* check if the global propagation cut off the active/current node */
2630  if( SCIPgetCutoffdepth(scip) <= SCIPgetDepth(scip) )
2631  {
2632  (*result) = SCIP_CUTOFF;
2633  return SCIP_OKAY;
2634  }
2635  }
2636 
2637  /* check if the pseudo objective value (minimum activity of the objective function) is greater or equal to the cutoff
2638  * bound
2639  */
2640  if( SCIPisGE(scip, pseudoobjval, cutoffbound) )
2641  {
2642  SCIPdebugMessage("pseudo objective value <%g> exceeds cutoff bound <%g>\n", pseudoobjval, cutoffbound);
2643 
2644  /* check if conflict analysis is applicable */
2646  {
2647  assert(SCIPgetDepth(scip) > 0);
2648 
2649  /* initialize conflict analysis */
2651 
2652  /* add all variable whose best bound changes increased the pseudo objective value above to cutoff bound */
2653  SCIP_CALL( resolvePropagation(scip, propdata, cutoffbound, NULL, -1, SCIP_BOUNDTYPE_UPPER, NULL) );
2654 
2655  /* analyze the conflict */
2656  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
2657  }
2658  (*result) = SCIP_CUTOFF;
2659 
2660  return SCIP_OKAY;
2661  }
2662 
2663  SCIPdebugMessage("propagating pseudo objective function (pseudoobj: %g, cutoffbound: %g)\n", pseudoobjval, cutoffbound);
2664 
2665  /* propagate binary variables */
2666  SCIP_CALL( propagateCutoffboundBinvars(scip, prop, cutoffbound, pseudoobjval, &nchgbds, &cutoff) );
2667 
2668  if( cutoff )
2669  {
2670  (*result) = SCIP_CUTOFF;
2671  return SCIP_OKAY;
2672  }
2673 
2674  /* tighten domains of none binary variables, if they would increase the pseudo objective value above the cutoff
2675  * bound
2676  */
2677  if( propdata->propfullinroot && SCIPgetDepth(scip) == 0 )
2678  {
2679  SCIP_VAR** objintvars;
2680  SCIP_VAR* var;
2681  SCIP_Real objval;
2682  int nobjintvars;
2683  int v;
2684 
2685  objintvars = propdata->objintvars;
2686  nobjintvars = propdata->nobjintvars;
2687  assert(nobjintvars == 0 || objintvars != NULL);
2688 
2689  /* propagate all none binary variables */
2690  for( v = 0; v < nobjintvars; ++v )
2691  {
2692  var = objintvars[v];
2693  assert(var != NULL);
2694 
2695  objval = SCIPvarGetObj(var);
2696  assert(!SCIPisZero(scip, objval));
2697 
2698  /* try to tighten the bound of the variable */
2699  SCIP_CALL( propagateCutoffboundVar(scip, NULL, var, -1, objval, cutoffbound, pseudoobjval, FALSE, &tightened) );
2700 
2701  /* check if the domain of the variable was reduced */
2702  if( tightened )
2703  nchgbds++;
2704  }
2705  }
2706  else
2707  {
2708  SCIP_VAR** objintvars;
2709  SCIP_VAR* var;
2710  SCIP_Real objval;
2711  int nobjintvars;
2712  int nmaxuseless;
2713  int nuseless;
2714  int c;
2715  int v;
2716 
2717  objintvars = propdata->objintvars;
2718  nobjintvars = propdata->nobjintvars;
2719  assert(nobjintvars == 0 || objintvars != NULL);
2720 
2721  /* compute maximum number of useless propagations before aborting */
2722  nmaxuseless = MAX(propdata->minuseless, (int)propdata->maxvarsfrac*(nobjintvars));
2723 
2724  nuseless = 0;
2725  v = propdata->lastvarnum;
2726 
2727  for( c = 0; c < nobjintvars && nuseless < nmaxuseless; ++c )
2728  {
2729  v++;
2730  if( v >= nobjintvars )
2731  v = 0;
2732 
2733  var = objintvars[v];
2734  assert(var != NULL);
2735 
2736  objval = SCIPvarGetObj(var);
2737  assert(!SCIPisZero(scip, objval));
2738 
2739  /* try to tighten the bound of the variable */
2740  SCIP_CALL( propagateCutoffboundVar(scip, prop, var, -1, objval, cutoffbound, pseudoobjval, TRUE, &tightened) );
2741 
2742  /* check if the domain of the variable was reduced */
2743  if( tightened )
2744  nchgbds++;
2745  else
2746  nuseless++;
2747  }
2748  propdata->lastvarnum = v;
2749  }
2750 
2751  /* check if we chanced bounds */
2752  if( nchgbds > 0 )
2753  (*result) = SCIP_REDUCEDDOM;
2754 
2755  return SCIP_OKAY;
2756 }
2757 
2758 /** recalculates the maximum objective pseudoactivity */
2759 static
2761  SCIP* scip, /**< SCIP data structure */
2762  SCIP_PROPDATA* propdata /**< propagator data */
2763  )
2764 {
2765  SCIP_VAR** vars;
2766  SCIP_Real objval;
2767  SCIP_Real contrib;
2768  int nvars;
2769  int v;
2770 
2771  assert(propdata != NULL);
2772 
2773  /* get problem variables */
2774  vars = SCIPgetVars(scip);
2775  nvars = SCIPgetNVars(scip);
2776 
2777  /* calculate current max pseudo activity and largest contribution */
2778  propdata->maxpseudoobjact = 0.0;
2779  propdata->maxpseudoobjactinf = 0;
2780 
2781  for( v = 0; v < nvars; ++v )
2782  {
2783  objval = SCIPvarGetObj(vars[v]);
2784  if( SCIPisPositive(scip, objval) )
2785  {
2786  contrib = SCIPvarGetUbGlobal(vars[v]);
2787  if( !SCIPisInfinity(scip, contrib) )
2788  contrib *= objval;
2789  }
2790  else if( SCIPisNegative(scip, objval) )
2791  {
2792  contrib = SCIPvarGetLbGlobal(vars[v]);
2793  if( !SCIPisInfinity(scip, -contrib) )
2794  contrib *= objval;
2795  else
2796  contrib *= -1.0;
2797  }
2798  else
2799  continue;
2800 
2801  if( SCIPisInfinity(scip, contrib) )
2802  propdata->maxpseudoobjactinf++;
2803  else
2804  propdata->maxpseudoobjact += contrib;
2805  }
2806 }
2807 
2808 /** updates the pseudo objective activity if necessary */
2809 static
2811  SCIP* scip, /**< SCIP data structure */
2812  SCIP_PROPDATA* propdata /**< propagator data */
2813  )
2814 {
2815  assert(propdata != NULL);
2816 
2817  /* if necessary, calculate the maximum pseudo objective activity */
2818  if( propdata->maxpseudoobjact == SCIP_INVALID ) /*lint !e777*/
2819  calcMaxObjPseudoactivity(scip, propdata);
2820  assert(propdata->maxpseudoobjact != SCIP_INVALID); /*lint !e777*/
2821 }
2822 
2823 /** returns the residual pseudo objective activity without the given value */
2824 static
2826  SCIP* scip, /**< SCIP data structure */
2827  SCIP_PROPDATA* propdata, /**< propagator data */
2828  SCIP_Real contrib /**< value to eliminate from pseudo objective activity */
2829  )
2830 {
2831  SCIP_Real residual;
2832 
2833  assert(propdata != NULL);
2834 
2835  /* if necessary, calculate the maximum pseudo objective activity */
2836  if( propdata->maxpseudoobjact == SCIP_INVALID ) /*lint !e777*/
2837  calcMaxObjPseudoactivity(scip, propdata);
2838  assert(propdata->maxpseudoobjact != SCIP_INVALID); /*lint !e777*/
2839 
2840  if( SCIPisInfinity(scip, contrib) )
2841  {
2842  assert(propdata->maxpseudoobjactinf >= 1);
2843  /* check if this variable yields the only infinite contribution */
2844  if( propdata->maxpseudoobjactinf == 1 )
2845  residual = propdata->maxpseudoobjact;
2846  else
2847  residual = SCIPinfinity(scip);
2848  }
2849  else
2850  {
2851  /* check if there is an infinite contribution */
2852  if( propdata->maxpseudoobjactinf >= 1 )
2853  residual = SCIPinfinity(scip);
2854  else
2855  residual = propdata->maxpseudoobjact - contrib;
2856  }
2857 
2858  return residual;
2859 }
2860 
2861 /** returns the residual pseudo objective activity */
2862 static
2864  SCIP* scip, /**< SCIP data structure */
2865  SCIP_PROPDATA* propdata, /**< propagator data */
2866  SCIP_VAR* var /**< variable to get residual activity for */
2867  )
2868 {
2869  SCIP_Real objval;
2870  SCIP_Real contrib;
2871 
2872  assert(propdata != NULL);
2873 
2874  contrib = 0.0;
2875  objval = SCIPvarGetObj(var);
2877  {
2878  contrib = SCIPvarGetUbGlobal(var);
2879  if( !SCIPisInfinity(scip, contrib) )
2880  contrib *= objval;
2881  }
2882  else
2883  {
2885  contrib = SCIPvarGetLbGlobal(var);
2886  if( !SCIPisInfinity(scip, -contrib) )
2887  contrib *= objval;
2888  else
2889  contrib *= -1.0;
2890  }
2891 
2892  return getMaxObjPseudoactivityResidualValue(scip, propdata, contrib);
2893 }
2894 
2895 /** returns the maximum pseudo objective activity of the objective function */
2896 static
2898  SCIP* scip, /**< SCIP data structure */
2899  SCIP_PROPDATA* propdata /**< propagator data */
2900  )
2901 {
2902  return getMaxObjPseudoactivityResidualValue(scip, propdata, 0.0);
2903 }
2904 
2905 /** propagates the global domain of the given binary variable against the lower bound (c*x >= lowerbound) */
2906 static
2908  SCIP* scip, /**< SCIP data structure */
2909  SCIP_VAR* var, /**< variable to propagate */
2910  SCIP_Real lowerbound, /**< lower bound to use */
2911  SCIP_Real maxpseudoobjact, /**< maximum pseudo objective activity */
2912  SCIP_Bool useimplics, /**< should implications be used */
2913  SCIP_Bool* infeasible, /**< pointer to store if the variable domain got empty, infeasible */
2914  SCIP_Bool* tightened /**< pointer to store if the variable domain was tightened */
2915  )
2916 {
2917  SCIP_Real lbobjchg;
2918  SCIP_Real ubobjchg;
2919 
2920  assert(SCIPvarIsBinary(var));
2921  assert(SCIPisLE(scip, lowerbound, maxpseudoobjact));
2922  assert(!SCIPisInfinity(scip, maxpseudoobjact));
2923 
2924  /*@todo Instead of running always over all implications use SCIP_OBJIMPLICS in the same way as for the propagation of
2925  * the minimum activity against the cutoff bound. If so we could use the cliques as well.
2926  */
2927 
2928  /* get contribution of variable by fixing it to its lower bound w.r.t. maximum activity of the objective function */
2929  lbobjchg = getMaxactObjchg(var, SCIP_BOUNDTYPE_LOWER, useimplics);
2930  assert(!SCIPisPositive(scip, lbobjchg));
2931 
2932  /* get contribution of variable by fixing it to its upper bound w.r.t. maximum activity of the objective function */
2933  ubobjchg = getMaxactObjchg(var, SCIP_BOUNDTYPE_UPPER, useimplics);
2934  assert(!SCIPisPositive(scip, ubobjchg));
2935 
2936  (*infeasible) = FALSE;
2937  (*tightened) = FALSE;
2938 
2939  /* if the maximum activity of the objective function without the contribution of the given variable shrinks below the
2940  * global lower bound, the contribution of the variable is need; hence, we can fix it to corresponding bound globally
2941  */
2942  if( SCIPisFeasLT(scip, maxpseudoobjact + lbobjchg, lowerbound) && SCIPisFeasLT(scip, maxpseudoobjact + ubobjchg, lowerbound) )
2943  {
2944  /* fixing the variable to zero or one leads to decreases of the maximum activity below the lower bound, hence, we
2945  * detected an cutoff
2946  */
2947  (*infeasible) = TRUE;
2948  }
2949  else if( SCIPisFeasLT(scip, maxpseudoobjact + lbobjchg, lowerbound) )
2950  {
2951  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, 1.0, FALSE, infeasible, tightened) );
2952  }
2953  else if( SCIPisFeasLT(scip, maxpseudoobjact + ubobjchg, lowerbound) )
2954  {
2955  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, 0.0, FALSE, infeasible, tightened) );
2956  }
2957 
2958  return SCIP_OKAY;
2959 }
2960 
2961 /** propagates the global domains of the given variable with non-zero objective coefficient against the lower bound
2962  * (c*x >= lowerbound)
2963  */
2964 static
2966  SCIP* scip, /**< SCIP data structure */
2967  SCIP_PROPDATA* propdata, /**< propagator data */
2968  SCIP_VAR* var, /**< variable to propagate */
2969  SCIP_Real lowerbound, /**< lower bound to use */
2970  SCIP_Bool* infeasible, /**< pointer to store if the variable domain got empty, infeasible */
2971  SCIP_Bool* tightened /**< pointer to store if the variable domain was tightened */
2972  )
2973 {
2974  SCIP_Real residual;
2975  SCIP_Real newbd;
2976  SCIP_Real objval;
2977 
2978  objval = SCIPvarGetObj(var);
2979  assert(!SCIPisZero(scip, objval));
2980 
2981  (*tightened) = FALSE;
2982 
2983  /* get residual pseudo objective activity, that is the pseudo objective activity without the given variable */
2984  residual = getMaxObjPseudoactivityResidual(scip, propdata, var);
2985 
2986  if( SCIPisInfinity(scip, residual) )
2987  return SCIP_OKAY;
2988 
2989  /* compute potential mew bound */
2990  newbd = (lowerbound - residual) / objval;
2991 
2992  /**@note In case the variable is integral we force the update of the new bound */
2993 
2994  if( objval > 0.0 )
2995  {
2996  SCIP_Real lb;
2997 
2998  lb = SCIPvarGetLbGlobal(var);
2999 
3000  if( !SCIPvarIsIntegral(var) )
3001  {
3002  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, newbd, FALSE, infeasible, tightened) );
3003  }
3004  else if( SCIPisFeasGT(scip, newbd, lb) )
3005  {
3006  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, newbd, TRUE, infeasible, tightened) );
3007  }
3008  }
3009  else
3010  {
3011  SCIP_Real ub;
3012 
3013  ub = SCIPvarGetUbGlobal(var);
3014 
3015  if( !SCIPvarIsIntegral(var) )
3016  {
3017  SCIP_CALL( SCIPtightenVarUbGlobal(scip, var, newbd, FALSE, infeasible, tightened) );
3018  }
3019  else if( SCIPisFeasLT(scip, newbd, ub) )
3020  {
3021  SCIP_CALL( SCIPtightenVarUbGlobal(scip, var, newbd, TRUE, infeasible, tightened) );
3022  }
3023  }
3024 
3025  return SCIP_OKAY;
3026 }
3027 
3028 /** propagates the global lower (dual) bound c*x >= lowerbound */
3029 static
3031  SCIP* scip, /**< SCIP data structure */
3032  SCIP_PROP* prop, /**< propagator */
3033  SCIP_RESULT* result /**< pointer to store the result of the callback method */
3034  )
3035 { /*lint --e{715}*/
3036  SCIP_PROPDATA* propdata;
3037  SCIP_Real lowerbound;
3038  SCIP_Real maxpseudoobjact;
3039  SCIP_Bool cutoff;
3040  int nchgbds;
3041 
3042  assert(result != NULL);
3043 
3044  (*result) = SCIP_DIDNOTRUN;
3045  cutoff = FALSE;
3046  nchgbds = 0;
3047 
3048  propdata = SCIPpropGetData(prop);
3049  assert(propdata != NULL);
3050  assert(propdata->nminactvars > 0 || propdata->nobjintvars > 0);
3051 
3052  /* check if there is a chance to find a reduction */
3053  lowerbound = SCIPgetLowerbound(scip);
3054 
3055  if( SCIPisInfinity(scip, -lowerbound) )
3056  return SCIP_OKAY;
3057 
3058  /* if the lower bound did not change since the last propagation as well as the global bounds of the variables with a
3059  * non-zero objective coefficient we do nothing since there is no new information available
3060  */
3061  if( SCIPisLE(scip, lowerbound, propdata->lastlowerbound) && propdata->maxpseudoobjact < SCIP_INVALID )
3062  return SCIP_OKAY;
3063 
3064  /* updates the pseudo objective activity if necessary */
3065  updateMaxObjPseudoactivity(scip, propdata);
3066 
3067  /* if more than one variable contributes an infinity to the maximal pseudo activity we can do nothing */
3068  assert(propdata->maxpseudoobjact < SCIP_INVALID);
3069  if( propdata->maxpseudoobjactinf > 1 )
3070  return SCIP_OKAY;
3071 
3072  maxpseudoobjact = getMaxObjPseudoactivity(scip, propdata);
3073  assert(!SCIPisInfinity(scip, maxpseudoobjact) || !SCIPisInfinity(scip, lowerbound));
3074 
3075 #ifndef NDEBUG
3076  /* check that the global indices are correct */
3077  checkGlbfirstnonfixed(scip, propdata);
3078 #endif
3079 
3080  /* if the maximum pseudo objective activity is smaller than the lower bound the problem is infeasible */
3081  if( SCIPisLT(scip, maxpseudoobjact, lowerbound) )
3082  cutoff = TRUE;
3083  else
3084  {
3085  SCIP_VAR** objintvars;
3086  SCIP_VAR* var;
3087  SCIP_Bool tightened;
3088  int nobjintvars;
3089  int v;
3090 
3091  if( propdata->maxpseudoobjactinf == 0 && !SCIPisInfinity(scip, maxpseudoobjact) )
3092  {
3093  SCIP_VAR** maxactvars;
3094  int nmaxactvars;
3095 
3096  maxactvars = propdata->maxactvars;
3097  nmaxactvars = propdata->nmaxactvars;
3098  assert(nmaxactvars == 0 || maxactvars != NULL);
3099 
3100  for( v = propdata->maxactfirstnonfixed; v < nmaxactvars; ++v )
3101  {
3102  var = maxactvars[v];
3103  assert(var != NULL);
3104  assert(SCIPvarIsBinary(var));
3105 
3106  /* check if the variables is already globally fixed; if so continue with the next potential candidate */
3107  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
3108  continue;
3109 
3110  /* try to propagate variable domain globally */
3111  SCIP_CALL( propagateLowerboundBinvar(scip, var, lowerbound, maxpseudoobjact, propdata->propuseimplics, &cutoff, &tightened) );
3112 
3113  /* the binary variables are sorted in non-increasing manner w.r.t. the absolute value of their objective
3114  * contribution w.r.t. maximum activity of the objective function; These values are the decrease we would
3115  * get with the maximum pseudo objective activity if we fix the variable to its best bound; hence, we can
3116  * stop if for a variable this potential decrease is not enough anymore too fall below the lower bound.
3117  *
3118  * @note In case a fixing was performed. The variable might not be globally fixed right away since this would
3119  * destroy the local internal data structure of a search node; the bound change is in that case pending;
3120  * hence we cannot assert that the variable is globally fixed
3121  */
3122  if( !tightened )
3123  {
3124  assert(!SCIPisInfinity(scip, propdata->maxpseudoobjact));
3125  SCIPdebugMessage("interrupt pseudo objective propagation w.r.t. lower bound <%.15g> for binary variables after %d from %d binary variables\n",
3126  lowerbound, v, nmaxactvars);
3127  break;
3128  }
3129 
3130  if( cutoff )
3131  break;
3132 
3133  /* update maximum pseudo activity since the previous global bound change might invalidated the maximum
3134  * pseudo activity
3135  */
3136  maxpseudoobjact = getMaxObjPseudoactivity(scip, propdata);
3137  nchgbds++;
3138  }
3139 
3140  /* update globally fixed index if abort criteria was applied */
3141  propdata->maxactfirstnonfixed = v;
3142 
3143  /* check all binary variables which could potentially be fixed */
3144  for( ; v < nmaxactvars && maxpseudoobjact - lowerbound < propdata->maxactchgs[v] && !cutoff; ++v )
3145  {
3146  var = maxactvars[v];
3147  assert(var != NULL);
3148  assert(SCIPvarIsBinary(var));
3149 
3150  /* check if the variables is already globally fixed; if so continue with the potential candidate */
3151  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
3152  continue;
3153 
3154  /* propagates the cutoff bound for the given binary variable */
3155  SCIP_CALL( propagateLowerboundBinvar(scip, var, lowerbound, maxpseudoobjact, propdata->propuseimplics, &cutoff, &tightened) );
3156 
3157  if( tightened )
3158  {
3159  /* update maximum pseudo activity since the previous global bound change might invalidated the maximum
3160  * pseudo activity
3161  */
3162  maxpseudoobjact = getMaxObjPseudoactivity(scip, propdata);
3163  nchgbds++;
3164  }
3165  }
3166 
3167 #if 0 /* might fail, but is not a real error, still need to investigate */
3168 #ifndef NDEBUG
3169  /* check that the abort criteria for the binary variables works */
3170  for( ; v < nmaxactvars && !cutoff; ++v )
3171  {
3172  var = maxactvars[v];
3173  assert(var != NULL);
3174  assert(SCIPvarIsBinary(var));
3175 
3176  /* check if the variables is already globally fixed; if so continue with the next potential candidate */
3177  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
3178  continue;
3179 
3180  /* try to propagate variable domain globally */
3181  SCIP_CALL( propagateLowerboundBinvar(scip, var, lowerbound, maxpseudoobjact, propdata->propuseimplics, &cutoff, &tightened) );
3182  assert(!tightened);
3183  assert(!cutoff);
3184  }
3185 #endif
3186 #endif
3187  }
3188 
3189  objintvars = propdata->objintvars;
3190  nobjintvars = propdata->nobjintvars;
3191  assert(nobjintvars == 0 || objintvars != NULL);
3192 
3193  /* propagate c*x >= lowerbound for non-binary variables */
3194  for( v = 0; v < nobjintvars && !cutoff; ++v )
3195  {
3196  var = objintvars[v];
3197  assert(var != NULL);
3198  assert(!SCIPisZero(scip, SCIPvarGetObj(var)));
3199 
3200  /* try to propagate variable domain globally */
3201  SCIP_CALL( propagateLowerboundVar(scip, propdata, var, lowerbound, &cutoff, &tightened) );
3202 
3203  if( tightened )
3204  nchgbds++;
3205  }
3206  }
3207 
3208  /* evaluate propagation results */
3209  if( cutoff )
3210  {
3211  /* we are done with solving since a global bound change is infeasible: cutoff root node */
3212  SCIP_CALL( SCIPcutoffNode(scip, SCIPgetRootNode(scip)) );
3213  (*result) = SCIP_CUTOFF;
3214  }
3215  else if( nchgbds > 0 )
3216  (*result) = SCIP_REDUCEDDOM;
3217 
3218  /* remember the lower bound which we already propagated */
3219  propdata->lastlowerbound = lowerbound;
3220 
3221  return SCIP_OKAY;
3222 }
3223 
3224 
3225 /*
3226  * Callback methods of propagator
3227  */
3228 
3229 /** copy method for propagator plugins (called when SCIP copies plugins) */
3230 static
3231 SCIP_DECL_PROPCOPY(propCopyPseudoobj)
3232 { /*lint --e{715}*/
3233  assert(scip != NULL);
3234  assert(prop != NULL);
3235  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
3236 
3237  /* call inclusion method of propagator */
3239 
3240  return SCIP_OKAY;
3241 }
3242 
3243 /** destructor of propagator to free user data (called when SCIP is exiting) */
3244 static
3245 SCIP_DECL_PROPFREE(propFreePseudoobj)
3246 { /*lint --e{715}*/
3247  SCIP_PROPDATA* propdata;
3248 
3249  /* free propagator data */
3250  propdata = SCIPpropGetData(prop);
3251  SCIPfreeMemory(scip, &propdata);
3252  SCIPpropSetData(prop, NULL);
3253 
3254  return SCIP_OKAY;
3255 }
3256 
3257 
3258 /** solving process initialization method of propagator (called when branch and bound process is about to begin) */
3259 static
3260 SCIP_DECL_PROPINITSOL(propInitsolPseudoobj)
3261 {
3262  SCIP_PROPDATA* propdata;
3263 
3264  propdata = SCIPpropGetData(prop);
3265  assert(propdata != NULL);
3266 
3267  /* do nothing if active pricer are present and force flag is not TRUE */
3268  if( !propdata->force && SCIPgetNActivePricers(scip) > 0 )
3269  return SCIP_OKAY;
3270 
3271  /* if active pricer are present we want to catch the variable added event */
3272  if( SCIPgetNActivePricers(scip) > 0 )
3273  {
3274  assert(!propdata->catchvaradded);
3275  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_VARADDED, propdata->eventhdlr, (SCIP_EVENTDATA*)propdata, NULL) );
3276  propdata->catchvaradded = TRUE;
3277  }
3278 
3279  return SCIP_OKAY;
3280 }
3281 
3282 /** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
3283 static
3284 SCIP_DECL_PROPEXITSOL(propExitsolPseudoobj)
3285 { /*lint --e{715}*/
3286  SCIP_PROPDATA* propdata;
3287 
3288  propdata = SCIPpropGetData(prop);
3289  assert(propdata != NULL);
3290 
3291  if( propdata->catchvaradded )
3292  {
3293  /* drop the variable added event */
3294  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_VARADDED, propdata->eventhdlr, (SCIP_EVENTDATA*)propdata, -1) );
3295  propdata->catchvaradded = FALSE;
3296  }
3297 
3298  /* free propagator data */
3299  SCIP_CALL( propdataExit(scip, propdata) );
3300 
3301  return SCIP_OKAY;
3302 }
3303 
3304 
3305 /** presolving method of propagator */
3306 static
3307 SCIP_DECL_PROPPRESOL(propPresolPseudoobj)
3308 { /*lint --e{715}*/
3309 
3310  SCIP_PROPDATA* propdata;
3311  SCIP_VAR** vars;
3312  SCIP_Real cutoffbound;
3313  SCIP_Real pseudoobjval;
3314  int oldnchgbds;
3315  int nvars;
3316  int v;
3317 
3318  assert(result != NULL);
3319 
3320  propdata = SCIPpropGetData(prop);
3321  assert(propdata != NULL);
3322 
3323  (*result) = SCIP_DIDNOTRUN;
3324 
3325  /* do nothing if active pricer are present and force flag is not TRUE */
3326  if( !propdata->force && SCIPgetNActivePricers(scip) > 0 )
3327  return SCIP_OKAY;
3328 
3329  pseudoobjval = SCIPgetGlobalPseudoObjval(scip);
3330  if( SCIPisInfinity(scip, -pseudoobjval) )
3331  return SCIP_OKAY;
3332 
3333  cutoffbound = SCIPgetCutoffbound(scip);
3334  if( SCIPisInfinity(scip, cutoffbound) )
3335  return SCIP_OKAY;
3336 
3337  if( SCIPisGE(scip, pseudoobjval, cutoffbound) )
3338  {
3339  (*result) = SCIP_CUTOFF;
3340  return SCIP_OKAY;
3341  }
3342 
3343  /* only propagate if a new cutoff bound or global pseudo objective value is available */
3344  if( cutoffbound < propdata->cutoffbound || pseudoobjval > propdata->glbpseudoobjval )
3345  {
3346  SCIP_Real objval;
3347  SCIP_Bool tightened;
3348 
3349  (*result) = SCIP_DIDNOTFIND;
3350  oldnchgbds = *nchgbds;
3351 
3352  /* get the problem variables */
3353  vars = SCIPgetVars(scip);
3354  nvars = SCIPgetNVars(scip);
3355 
3356  /* scan the variables for pseudoobj bound reductions
3357  * (loop backwards, since a variable fixing can change the current and the subsequent slots in the vars array)
3358  */
3359  for( v = nvars - 1; v >= 0; --v )
3360  {
3361  objval = SCIPvarGetObj(vars[v]);
3362 
3363  if( SCIPisZero(scip, objval) )
3364  continue;
3365 
3366  SCIP_CALL( propagateCutoffboundVar(scip, NULL, vars[v], -1, objval, cutoffbound, pseudoobjval, FALSE, &tightened) );
3367 
3368  if( tightened )
3369  (*nchgbds)++;
3370  }
3371 
3372  /* evaluate if bound change was detected */
3373  if( *nchgbds > oldnchgbds )
3374  (*result) = SCIP_SUCCESS;
3375 
3376  /* store the old values */
3377  propdata->cutoffbound = cutoffbound;
3378  propdata->glbpseudoobjval = pseudoobjval;
3379  propdata->glbpropagated = TRUE;
3380  }
3381 
3382  return SCIP_OKAY;
3383 }
3384 
3385 /** execution method of propagator */
3386 static
3387 SCIP_DECL_PROPEXEC(propExecPseudoobj)
3388 { /*lint --e{715}*/
3389  SCIP_PROPDATA* propdata;
3390 
3391  propdata = SCIPpropGetData(prop);
3392  assert(propdata != NULL);
3393 
3394  (*result) = SCIP_DIDNOTRUN;
3395 
3396  if( SCIPinProbing(scip) )
3397  return SCIP_OKAY;
3398 
3399  if( proptiming == SCIP_PROPTIMING_DURINGLPLOOP && SCIPgetDepth(scip) != 0 )
3400  return SCIP_OKAY;
3401 
3402  /* do nothing if active pricer are present and force flag is not TRUE */
3403  if( !propdata->force && SCIPgetNActivePricers(scip) > 0 )
3404  return SCIP_OKAY;
3405 
3406  /* check if enough new variable are added (due to column generatition to reinitialized the propgator data) */
3407  if( !propdata->initialized || propdata->nnewvars > propdata->maxnewvars )
3408  {
3409  /* free current propdata data */
3410  SCIP_CALL( propdataExit(scip, propdata) );
3411 
3412  /* initialize propdata data from scratch */
3413  SCIP_CALL( propdataInit(scip, propdata) );
3414  }
3415 
3416  /* nothing to do for zero objective */
3417  if( propdata->nminactvars == 0 && propdata->nmaxactvars == 0 && propdata->nobjintvars == 0 )
3418  return SCIP_OKAY;
3419 
3420  /* propagate c*x <= cutoff */
3421  SCIP_CALL( propagateCutoffbound(scip, prop, result) );
3422 
3423  if( (*result) != SCIP_CUTOFF && (propdata->nmaxactvars > 0 || propdata->nobjintvars > 0) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3424  {
3425  SCIP_RESULT dualresult;
3426 
3427  /* propagates the global lower (dual) bound c*x >= lowerbound */
3428  SCIP_CALL( propagateLowerbound(scip, prop, &dualresult) );
3429 
3430  if( dualresult == SCIP_REDUCEDDOM || dualresult == SCIP_CUTOFF )
3431  (*result) = dualresult;
3432  }
3433 
3434  return SCIP_OKAY;
3435 }
3436 
3437 /** propagation conflict resolving method of propagator */
3438 static
3439 SCIP_DECL_PROPRESPROP(propRespropPseudoobj)
3440 { /*lint --e{715}*/
3441  SCIP_PROPDATA* propdata;
3442  SCIP_Real cutoffbound;
3443 
3444  assert(!SCIPisEQ(scip, SCIPvarGetLbGlobal(infervar), SCIPvarGetUbGlobal(infervar)));
3445 
3446  propdata = SCIPpropGetData(prop);
3447  assert(propdata != NULL);
3448 
3449  cutoffbound = SCIPgetCutoffbound(scip);
3450  assert(!SCIPisInfinity(scip, cutoffbound));
3451  assert(infervar != NULL);
3452 
3453  SCIPdebugMessage("resolve bound change <%s> %s <%g>(%g), cutoff bound <%g>\n", SCIPvarGetName(infervar),
3454  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", SCIPvarGetLbAtIndex(infervar, bdchgidx, TRUE),
3455  SCIPvarGetLbAtIndex(infervar, bdchgidx, FALSE), cutoffbound);
3456 
3457  /* resolve the propagation of the inference variable w.r.t. required minactivity */
3458  SCIP_CALL( resolvePropagation(scip, propdata, cutoffbound, infervar, inferinfo, boundtype, bdchgidx) );
3459 
3460  (*result) = SCIP_SUCCESS;
3461 
3462  return SCIP_OKAY;
3463 }
3464 
3465 
3466 /*
3467  * Event handler
3468  */
3469 
3470 /** execution method of bound change event handler */
3471 static
3472 SCIP_DECL_EVENTEXEC(eventExecPseudoobj)
3473 { /*lint --e{715}*/
3474  SCIP_PROPDATA* propdata;
3475  SCIP_EVENTTYPE eventtype;
3476 
3477  propdata = (SCIP_PROPDATA*)eventdata;
3478  assert(propdata != NULL);
3479 
3480  assert(eventhdlr != NULL);
3481  assert(eventdata != NULL);
3482  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
3483  assert(event != NULL);
3484 
3485  eventtype = SCIPeventGetType(event);
3486 
3487  switch( eventtype )
3488  {
3491  /* if bound got relaxed we need to start up front for trial of bound tightening */
3492  propdata->firstnonfixed = 0;
3493  break;
3495  propdata->nnewvars++;
3496  break;
3497  default:
3498  assert(eventtype == SCIP_EVENTTYPE_GLBCHANGED || eventtype == SCIP_EVENTTYPE_GUBCHANGED);
3499 
3500  /* invalidate the maximum pseudo objective activity */
3501  propdata->maxpseudoobjact = SCIP_INVALID;
3502  propdata->maxpseudoobjactinf = 0;
3503  }
3504 
3505  return SCIP_OKAY;
3506 }
3507 
3508 
3509 /*
3510  * propagator specific interface methods
3511  */
3512 
3513 /** creates the pseudo objective function propagator and includes it in SCIP */
3515  SCIP* scip /**< SCIP data structure */
3516  )
3517 {
3518  SCIP_PROPDATA* propdata;
3519  SCIP_PROP* prop;
3520 
3521 
3522  /* create pseudoobj propagator data */
3523  SCIP_CALL( SCIPallocMemory(scip, &propdata) );
3524 
3525  /* reset propagator data structure */
3526  propdataReset(scip, propdata);
3527 
3528  propdata->eventhdlr = NULL;
3529  /* include event handler for gloabl bound change events and variable added event (in case of pricing) */
3530  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &propdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC,
3531  eventExecPseudoobj, NULL) );
3532 
3533  if( propdata->eventhdlr == NULL )
3534  {
3535  SCIPerrorMessage("event handler for pseudo objective propagator not found\n");
3536  return SCIP_PLUGINNOTFOUND;
3537  }
3538 
3539  /* include propagator */
3541  propExecPseudoobj,
3542  propdata) );
3543  assert(prop != NULL);
3544 
3545  /* set optional callbacks via setter functions */
3546  SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyPseudoobj) );
3547  SCIP_CALL( SCIPsetPropFree(scip, prop, propFreePseudoobj) );
3548  SCIP_CALL( SCIPsetPropInitsol(scip, prop, propInitsolPseudoobj) );
3549  SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolPseudoobj) );
3551  SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropPseudoobj) );
3552 
3553  /* add pseudoobj propagator parameters */
3554  SCIP_CALL( SCIPaddIntParam(scip,
3555  "propagating/"PROP_NAME"/minuseless",
3556  "minimal number of successive none binary variable propagator whithout a bound reduction before aborted",
3557  &propdata->minuseless, TRUE, DEFAULT_MINUSELESS, 0, INT_MAX, NULL, NULL) );
3558 
3560  "propagating/"PROP_NAME"/maxvarsfrac",
3561  "maximal fraction of none binary variables with non-zero objective without a bound reduction before aborted",
3562  &propdata->maxvarsfrac, TRUE, DEFAULT_MAXVARSFRAC, 0.0, 1.0, NULL, NULL) );
3563 
3565  "propagating/"PROP_NAME"/propfullinroot",
3566  "do we want to propagate all none binary variables if we are propagating the root node",
3567  &propdata->propfullinroot, TRUE, DEFAULT_PROPFULLINROOT, NULL, NULL) );
3568 
3570  "propagating/"PROP_NAME"/propcutoffbound",
3571  "propagate new cutoff bound directly globally",
3572  &propdata->propcutoffbound, TRUE, DEFAULT_PROPCUTOFFBOUND, NULL, NULL) );
3573 
3575  "propagating/"PROP_NAME"/force",
3576  "should the propagator be forced even active pricer are present?",
3577  &propdata->force, TRUE, DEFAULT_FORCE, NULL, NULL) );
3578 
3579  SCIP_CALL( SCIPaddIntParam(scip,
3580  "propagating/"PROP_NAME"/maxnewvars",
3581  "number of variable added after the propgatore is reinitialized?",
3582  &propdata->maxnewvars, TRUE, DEFAULT_MAXNEWVARS, 0, INT_MAX, NULL, NULL) );
3583 
3585  "propagating/"PROP_NAME"/propuseimplics",
3586  "use implications to strengthen the propagation of binary variable (increasing the objective change)?",
3587  &propdata->propuseimplics, TRUE, DEFAULT_PROPUSEIMPLICS, NULL, NULL) );
3588 
3590  "propagating/"PROP_NAME"/respropuseimplics",
3591  "use implications to strengthen the resolve propagation of binary variable (increasing the objective change)?",
3592  &propdata->respropuseimplics, TRUE, DEFAULT_RESPROPUSEIMPLICS, NULL, NULL) );
3593 
3594  SCIP_CALL( SCIPaddIntParam(scip,
3595  "propagating/"PROP_NAME"/maximplvars",
3596  "maximum number of binary variables the implications are used if turned on (-1: unlimited)?",
3597  &propdata->maximplvars, TRUE, DEFAULT_MAXIMPLVARS, -1, INT_MAX, NULL, NULL) );
3598 
3599  return SCIP_OKAY;
3600 }
3601 
3602 /** propagates the cutoff bound for the given variables */
3604  SCIP* scip, /**< SCIP data structure */
3605  SCIP_PROP* prop, /**< propagator, or NULL */
3606  SCIP_VAR* var, /**< variables to propagate */
3607  SCIP_Real cutoffbound, /**< cutoff bound to use */
3608  SCIP_Real pseudoobjval, /**< pseudo objective value to use */
3609  SCIP_Bool* tightened /**< pointer to if the domain was tightened */
3610  )
3611 {
3612  SCIP_Real objval;
3613 
3614  objval = SCIPvarGetObj(var);
3615 
3616  SCIP_CALL( propagateCutoffboundVar(scip, prop, var, -1, objval, cutoffbound, pseudoobjval, TRUE, tightened) );
3617 
3618  return SCIP_OKAY;
3619 }
3620