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-2015 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_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates in (-1: no
45  * limit) */
46 #define PROP_PRESOLTIMING SCIP_PRESOLTIMING_FAST /* timing of the presolving method (fast, medium, or exhaustive) */
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 */
72 struct SCIP_ObjImplics
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
236 SCIP_DECL_SORTPTRCOMP(varCompObj)
237 {
238  SCIP_VAR* var1;
239  SCIP_VAR* var2;
240  int locks1;
241  int locks2;
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 }
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;
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
661 void propdataReset(
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;
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_Bool* values;
831  SCIP_Bool varfixing;
832  int nbinvars;
833  int ncliques;
834  int c;
835  int v;
836 
837  assert(SCIPvarIsBinary(var));
838  assert(SCIPvarGetLbGlobal(var) < 0.5);
839  assert(SCIPvarGetUbGlobal(var) > 0.5);
840  assert(bound == SCIP_BOUNDTYPE_LOWER || bound == SCIP_BOUNDTYPE_UPPER);
841  assert(objchg != NULL);
842  assert(contributors != NULL);
843  assert(ncontributors != NULL);
844  assert(*ncontributors == 0);
845 
847  assert((SCIP_Bool)SCIP_BOUNDTYPE_UPPER == TRUE);
848  varfixing = (SCIP_Bool)bound;
849 
850  cliques = SCIPvarGetCliques(var, varfixing);
851  ncliques = SCIPvarGetNCliques(var, varfixing);
852 
853 #ifndef NDEBUG
854  /* check that the marker array is reset */
855  for( c = 0; c < nbinobjvars; ++c )
856  assert(collectedvars[c] == FALSE);
857 #endif
858 
859  /* collect all implication which are given via cliques */
860  for( c = 0; c < ncliques; ++c )
861  {
862  SCIP_Bool useless;
863 
864  assert(uselesscliques != NULL);
865 
866  clique = cliques[c];
867  assert(clique != NULL);
868 
869  /* check if the clique was previously detected to be useless with respect to minimum activity */
870  if( SCIPhashtableExists(uselesscliques, (void*)clique) )
871  continue;
872 
873  nbinvars = SCIPcliqueGetNVars(clique);
874 
875  if( nbinvars > MAX_CLIQUELENGTH )
876  {
877  SCIP_CALL( SCIPhashtableInsert(uselesscliques, (void*)clique) );
878  continue;
879  }
880 
881  vars = SCIPcliqueGetVars(clique);
882  values = SCIPcliqueGetValues(clique);
883  useless = TRUE;
884 
885  for( v = 0; v < nbinvars; ++v )
886  {
887  implvar = vars[v];
888  assert(implvar != NULL);
889 
890  if( implvar == var )
891  {
892  /* check if the clique is useful at all */
893  if( useless )
894  {
895  SCIP_Real objval;
896 
897  objval = SCIPvarGetObj(var);
898 
899  if( varfixing == (SCIP_Bool)SCIPvarGetBestBoundType(var) && !SCIPisZero(scip, objval) )
900  useless = FALSE;
901  }
902  }
903  else if( values[v] == (SCIP_Bool)SCIPvarGetBestBoundType(implvar) )
904  {
905  useless = FALSE;
906  (*objchg) += collectMinactImplicVar(scip, implvar, binobjvarmap, collectedvars, nbinobjvars, contributors, ncontributors);
907  }
908  }
909 
910  /* if the clique is useless store it in the hash table to skip it later */
911  if( useless )
912  {
913  assert(!SCIPhashtableExists(uselesscliques, (void*)clique));
914  SCIP_CALL( SCIPhashtableInsert(uselesscliques, (void*)clique) );
915  }
916  }
917 
918  return SCIP_OKAY;
919 }
920 
921 /** returns the objective change provided by the implications of the given variable by fixing it to the given bound
922  * w.r.t. minimum activity of the objective function
923  *
924  * Let I(0) and I(1) be all implications of the given variable which follow by fixing it to given bound and evaluate to
925  * fixing the implication variable to zero (I(0)) or one (I(1)), respectively. The objective change provided by the
926  * implications are:
927  *
928  * \f[
929  * \displaystyle
930  * 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)
931  * =
932  * sum_{x\in I(0) \cup I(1)} (\mbox{impliedbound}(x) - \mbox{bestbound}(x)) \cdot \mbox{objval}(x)
933  * \f]
934  *
935  * This can be done w.r.t. global variable bounds (local == FALSE), w.r.t. local variable bounds (local == TRUE &&
936  * bdchgidx == NULL), and w.r.t. given time stamp (local == TRUE && bdchgidx != NULL)
937  */
938 static
940  SCIP* scip, /**< SCIP data structure */
941  SCIP_VAR* var, /**< variable to computes the objective contribution */
942  SCIP_OBJIMPLICS* objimplics, /**< objective implication data for the given variable */
943  SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node, or NULL */
944  SCIP_BOUNDTYPE bound, /**< bound to check for */
945  SCIP_Bool local, /**< propagate local bounds, otherwise global bounds */
946  SCIP_Real* objchg /**< pointer to store the objective change */
947  )
948 {
949  SCIP_VAR* implvar;
950  SCIP_Bool lb;
951  SCIP_Bool ub;
952  int nbinvars;
953  int v;
954 
955  assert(SCIPvarIsBinary(var));
956  assert(!local || SCIPvarGetLbAtIndex(var, bdchgidx, FALSE) < 0.5);
957  assert(!local || SCIPvarGetUbAtIndex(var, bdchgidx, FALSE) > 0.5);
958  assert(SCIPvarGetLbGlobal(var) < 0.5);
959  assert(SCIPvarGetUbGlobal(var) > 0.5);
960  assert(bound == SCIP_BOUNDTYPE_LOWER || bound == SCIP_BOUNDTYPE_UPPER);
961 
962  if( bound == SCIP_BOUNDTYPE_LOWER )
963  {
964  v = 0;
965  nbinvars = objimplics->nlbimpls;
966  }
967  else
968  {
969  assert(bound == SCIP_BOUNDTYPE_UPPER);
970  v = objimplics->nlbimpls;
971  nbinvars = objimplics->nlbimpls + objimplics->nubimpls;
972  }
973 
974  /* loop over all implications */
975  while( v < nbinvars )
976  {
977  implvar = objimplics->objvars[v];
978  assert(implvar != NULL);
979  assert(!SCIPisZero(scip, SCIPvarGetObj(implvar)));
980 
981  if( local )
982  {
983  lb = SCIPvarGetLbAtIndex(implvar, bdchgidx, FALSE) > 0.5;
984  ub = SCIPvarGetUbAtIndex(implvar, bdchgidx, FALSE) > 0.5;
985 
986  /* check if variable is fixed */
987  if( lb == TRUE || ub == FALSE )
988  {
989  v++;
990  continue;
991  }
992  }
993  else
994  {
995  lb = SCIPvarGetLbGlobal(implvar) > 0.5;
996  ub = SCIPvarGetUbGlobal(implvar) > 0.5;
997 
998  /* check if variable is global fixed; if so remove it from the objective implication data structure and
999  * continue with the next candidate
1000  */
1001  if( lb == TRUE || ub == FALSE )
1002  {
1003  SCIP_CALL( objimplicsDelPos(scip, objimplics, v) );
1004  nbinvars--;
1005  continue;
1006  }
1007  }
1008 
1009  assert(SCIPvarGetObj(implvar) > 0.0 || SCIPvarsHaveCommonClique(var, (SCIP_Bool) bound, implvar, TRUE, TRUE));
1010  assert(SCIPvarGetObj(implvar) < 0.0 || SCIPvarsHaveCommonClique(var, (SCIP_Bool) bound, implvar, FALSE, TRUE));
1011 
1012  /* add objective change */
1013  (*objchg) += REALABS(SCIPvarGetObj(implvar));
1014  v++;
1015  }
1016 
1017  return SCIP_OKAY;
1018 }
1019 
1020 /** computes for the given binary variable the objective contribution by fixing it to given bound w.r.t. minimum
1021  * activity of the objective function; additionally it collects all contributors for that objective change;
1022  */
1023 static
1025  SCIP* scip, /**< SCIP data structure */
1026  SCIP_VAR* var, /**< variable to computes the objective contribution */
1027  SCIP_BOUNDTYPE bound, /**< bound to check for */
1028  SCIP_HASHMAP* binobjvarmap, /**< hash map mapping binary variables with none-zero objective to position in collected variables arrays */
1029  SCIP_Bool* collectedvars, /**< temporary buffer to mark collected variables */
1030  int nbinobjvars, /**< number of binary variables with non-zero objective coefficient */
1031  SCIP_VAR** contributors, /**< array to store the contriboters */
1032  SCIP_HASHTABLE* uselesscliques, /**< hash table to store useless cliques, or NULL */
1033  int* ncontributors, /**< pointer to store number of contributor to the objective contribution */
1034  SCIP_Real* objchg /**< pointer to store the objective change */
1035  )
1036 {
1037  assert(SCIPvarIsBinary(var));
1038  assert(contributors != NULL);
1039  assert(ncontributors != NULL);
1040 
1041  /* collects the contribution of the variable itself w.r.t. the best bound */
1042  (*objchg) = getVarObjchg(var, SCIPvarGetBestBoundType(var), bound);
1043 
1044  (*ncontributors) = 0;
1045 
1046  /* add the objective contribution from the implication variable */
1047  SCIP_CALL( collectMinactImplicVars(scip, var, bound, binobjvarmap, collectedvars, nbinobjvars, contributors, uselesscliques, ncontributors, objchg) );
1048 
1049  return SCIP_OKAY;
1050 }
1051 
1052 /** computes for the given binary variable the objective contribution by fixing it to given bound w.r.t. minimum
1053  * activity of the objective function; this can be done w.r.t. global variable bounds (local == FALSE), w.r.t. local
1054  * variable bounds (local == TRUE && bdchgidx == NULL), and w.r.t. given time stamp (local == TRUE && bdchgidx != NULL)
1055  */
1056 static
1058  SCIP* scip, /**< SCIP data structure */
1059  SCIP_VAR* var, /**< variable to computes the objective contribution */
1060  SCIP_OBJIMPLICS* objimplics, /**< objective implication data for the given variable */
1061  SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node, or NULL */
1062  SCIP_BOUNDTYPE bound, /**< bound to check for */
1063  SCIP_Bool local, /**< propagate local bounds, otherwise global bounds */
1064  SCIP_Real* objchg /**< pointer to store the objective change */
1065  )
1066 {
1067  assert(SCIPvarIsBinary(var));
1068 
1069  /* collects the contribution of the variable itself w.r.t. the best bound */
1070  (*objchg) = getVarObjchg(var, SCIPvarGetBestBoundType(var), bound);
1071 
1072  /* add the objective contribution from the implication variable */
1073  SCIP_CALL( getMinactImplicObjchg(scip, var, objimplics, bdchgidx, bound, local, objchg) );
1074 
1075  return SCIP_OKAY;
1076 }
1077 
1078 /** returns the global (that means w.r.t. global bounds of the variables) objective change provided by all cliques of
1079  * the given variable by fixing it to the given bound w.r.t. maximum activity of the objective function
1080  *
1081  * Let I(0) and I(1) be all implications of the given variable which follow by fixing it to given bound and evaluate to
1082  * fixing the implication variable to zero (I(0)) or one (I(1)), respectively. The objective change provided by these
1083  * implications are:
1084  *
1085  * \f[
1086  * \displaystyle
1087  * 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)
1088  * =
1089  * sum_{x\in I(0) \cup I(1)} (\mbox{impliedbound}(x) - \mbox{worstbound}(x)) \cdot \mbox{objval}(x)
1090  * \f]
1091  */
1092 static
1094  SCIP* scip, /**< SCIP data structure */
1095  SCIP_VAR* var, /**< variable to computes the objective contribution */
1096  SCIP_BOUNDTYPE bound, /**< bound to check for */
1097  SCIP_Real* objchg /**< pointer to store the objective change */
1098  )
1100  SCIP_Bool varfixing;
1101  int ncliques;
1102  int nvars;
1103 
1104  assert(scip != NULL);
1105  assert(SCIPvarIsBinary(var));
1106  assert(SCIPvarGetLbGlobal(var) < 0.5);
1107  assert(SCIPvarGetUbGlobal(var) > 0.5);
1108  assert(bound == SCIP_BOUNDTYPE_LOWER || bound == SCIP_BOUNDTYPE_UPPER);
1109  assert(objchg != NULL);
1110 
1111  varfixing = (SCIP_Bool)bound;
1112  assert((SCIP_Bool)SCIP_BOUNDTYPE_LOWER == FALSE);
1113  assert((SCIP_Bool)SCIP_BOUNDTYPE_UPPER == TRUE);
1114 
1115  *objchg = 0.0;
1116  ncliques = SCIPvarGetNCliques(var, varfixing);
1117 
1118  if( ncliques > 0 )
1119  {
1120  SCIP_CLIQUE** cliques;
1121  SCIP_CLIQUE* clique;
1122  SCIP_VAR** clqvars;
1123  SCIP_VAR** probvars;
1124  SCIP_VAR* clqvar;
1125  SCIP_Bool* clqvalues;
1126  int* entries;
1127  int* ids;
1128  SCIP_Real obj;
1129  int nclqvars;
1130  int nentries;
1131  int objmult;
1132  int nids;
1133  int id;
1134  int c;
1135  int v;
1136 
1137  assert(SCIPisTransformed(scip));
1138 
1139  nentries = SCIPgetNVars(scip) - SCIPgetNContVars(scip) + 1;
1140 
1141  SCIP_CALL( SCIPallocBufferArray(scip, &ids, 2*nentries) );
1142  nids = 0;
1143  /* @todo move this memory allocation to SCIP_SET and add a memory list there, to decrease the number of
1144  * allocations and clear ups
1145  */
1146  SCIP_CALL( SCIPallocBufferArray(scip, &entries, nentries) );
1147  BMSclearMemoryArray(entries, nentries);
1148 
1149  cliques = SCIPvarGetCliques(var, varfixing);
1150  assert(cliques != NULL);
1151 
1152  /* iterate over all cliques and determine all importantimplications */
1153  for( c = ncliques - 1; c >= 0; --c )
1154  {
1155  clique = cliques[c];
1156  clqvars = SCIPcliqueGetVars(clique);
1157  clqvalues = SCIPcliqueGetValues(clique);
1158  nclqvars = SCIPcliqueGetNVars(clique);
1159  assert(nclqvars > 0);
1160  assert(clqvars != NULL);
1161  assert(clqvalues != NULL);
1162 
1163  if( nclqvars > MAX_CLIQUELENGTH )
1164  continue;
1165 
1166  /* iterate over all clique variables */
1167  for( v = nclqvars - 1; v >= 0; --v )
1168  {
1169  clqvar = clqvars[v];
1170  assert(clqvar != NULL);
1171 
1172  objmult = (int)!clqvalues[v] - (int)SCIPvarGetWorstBoundType(clqvar);
1173  assert(-1 <= objmult && objmult <= 1);
1174 
1175  /* ignore binary variable which are either fixed and were the objective contribution will not be zero */
1176  if( clqvar != var && objmult != 0 && SCIPvarIsActive(clqvar) &&
1177  (SCIPvarGetLbGlobal(clqvar) < 0.5 && SCIPvarGetUbGlobal(clqvar) > 0.5) && !SCIPisZero(scip, SCIPvarGetObj(clqvar)) )
1178  {
1179  int probindex = SCIPvarGetProbindex(clqvar) + 1;
1180  assert(0 < probindex && probindex < nentries);
1181 
1182  /* check that the variable was not yet visited */
1183  assert(entries[probindex] == 0 || entries[probindex] == objmult);
1184  if( entries[probindex] == 0 )
1185  {
1186  /* memorize probindex */
1187  ids[nids] = probindex;
1188  ++nids;
1189 
1190  assert(ABS(objmult) == 1);
1191 
1192  /* mark variable as visited */
1193  entries[probindex] = objmult;
1194  }
1195  }
1196  }
1197  }
1198 
1199  probvars = SCIPgetVars(scip);
1200  assert(probvars != NULL);
1201 
1202  /* add all implied objective values */
1203  for( v = nids - 1; v >= 0; --v )
1204  {
1205  id = ids[v];
1206  assert(0 < id && id < nentries);
1207  assert(entries[id] != 0);
1208 
1209  clqvar = probvars[id - 1];
1210  assert(clqvar != NULL);
1211  assert(SCIPvarIsBinary(clqvar));
1212  assert(SCIPvarIsActive(clqvar));
1213  assert(SCIPvarGetLbGlobal(clqvar) < 0.5);
1214  assert(SCIPvarGetUbGlobal(clqvar) > 0.5);
1215 
1216  obj = SCIPvarGetObj(clqvar);
1217  assert(!SCIPisZero(scip, obj));
1218 
1219  *objchg += entries[id] * obj;
1220  }
1221 
1222  /* free temporary memory */
1223  SCIPfreeBufferArray(scip, &entries);
1224  SCIPfreeBufferArray(scip, &ids);
1225  }
1226 
1227 #ifdef SCIP_MORE_DEBUG
1228  SCIPdebugMessage("objective contribution when variable <%s> fixed to %u using cliques is %g\n", SCIPvarGetName(var),
1229  varfixing, *objchg);
1230 #endif
1231 
1232  /* collect non-binary implication information */
1233  nvars = SCIPvarGetNImpls(var, varfixing);
1234 
1235  if( nvars > 0 )
1236  {
1237  SCIP_VAR** vars;
1238  SCIP_VAR* implvar;
1239  SCIP_Real* bounds;
1240  SCIP_BOUNDTYPE* boundtypes;
1241  SCIP_Real obj;
1242  SCIP_Real lb;
1243  SCIP_Real ub;
1244  int v;
1245 
1246  vars = SCIPvarGetImplVars(var, varfixing);
1247  boundtypes = SCIPvarGetImplTypes(var, varfixing);
1248  bounds = SCIPvarGetImplBounds(var, varfixing);
1249 
1250  for( v = nvars - 1; v >= 0; --v )
1251  {
1252  implvar = vars[v];
1253  assert(implvar != NULL);
1254 
1255  lb = SCIPvarGetLbLocal(implvar);
1256  ub = SCIPvarGetUbLocal(implvar);
1257  obj = SCIPvarGetObj(implvar);
1258 
1259  /* ignore binary variable which are fixed or not of column status */
1260  if( SCIPisZero(scip, obj) )
1261  continue;
1262 
1263  /* add up objective change if applicable */
1264  if( boundtypes[v] == SCIP_BOUNDTYPE_LOWER && SCIPvarGetWorstBoundType(implvar) == SCIP_BOUNDTYPE_LOWER && SCIPisFeasGT(scip, bounds[v], lb) )
1265  *objchg += (bounds[v] - lb)*obj;
1266  else if( boundtypes[v] == SCIP_BOUNDTYPE_UPPER && SCIPvarGetWorstBoundType(implvar) == SCIP_BOUNDTYPE_UPPER && SCIPisFeasLT(scip, bounds[v], ub) )
1267  *objchg += (bounds[v] - ub)*obj;
1268  }
1269  }
1270 
1271 #ifdef SCIP_MORE_DEBUG
1272  SCIPdebugMessage("objective contribution when variable <%s> fixed to %u using cliques and implications is %g\n", SCIPvarGetName(var),
1273  varfixing, *objchg);
1274 #endif
1275 
1276  return SCIP_OKAY;
1277 }
1278 
1279 /** computes for the given binary variable the gloabl (that means w.r.t. global bounds of the variables) objective
1280  * contribution by fixing it to given bound w.r.t. maximum activity of the objective function
1281  */
1282 static
1284  SCIP* scip, /**< SCIP data structure */
1285  SCIP_VAR* var, /**< variable to computes the objective contribution */
1286  SCIP_BOUNDTYPE bound, /**< bound to check for */
1287  SCIP_Bool useimplics, /**< should implications be used */
1288  SCIP_Real* objchg /**< pointer to store the objective change */
1289  )
1290 {
1291  assert(scip != NULL);
1292  assert(SCIPvarIsBinary(var));
1293  assert(objchg != NULL);
1294 
1295  *objchg = 0;
1296 
1297  /* check if the implications should be used to increase the objective contribution for given variable */
1298  if( useimplics )
1299  {
1300  /* using cliques and @todo other implications */
1301  SCIP_CALL( getMaxactImplicObjchg(scip, var, bound, objchg) );
1302  }
1303 
1304  /* collects the contribution of the variable itself w.r.t. the worst bound */
1305  *objchg += getVarObjchg(var, SCIPvarGetWorstBoundType(var), bound);
1306 
1307  return SCIP_OKAY;
1308 }
1309 
1310 /** reset variables array which marks variables which are collected */
1311 static
1312 void resetContributors(
1313  SCIP_HASHMAP* binobjvarmap, /**< hash map mapping binary variables with none-zero objective to position in collected variables arrays */
1314  SCIP_Bool* collectedvars, /**< temporary buffer to mark collected variables which should be reset */
1315  SCIP_VAR** contributors, /**< temporary buffer to use for collecting contributors */
1316  int ncontributors /**< number of contributors */
1317  )
1319  SCIP_VAR* var;
1320  int pos;
1321  int c;
1322 
1323  for( c = 0; c < ncontributors; ++c )
1324  {
1325  var = contributors[c];
1326  assert(var != NULL);
1327 
1328  assert(SCIPhashmapExists(binobjvarmap, var));
1329  pos = (int)(size_t)SCIPhashmapGetImage(binobjvarmap, var);
1330  assert(pos > 0);
1331  collectedvars[pos] = FALSE;
1332  }
1333 }
1334 
1335 /** check if the given variable should be collected for the minimum activity propagation */
1336 static
1338  SCIP* scip, /**< SCIP data structure */
1339  SCIP_VAR* var, /**< variable to check */
1340  SCIP_OBJIMPLICS** objimplics, /**< pointer to store the objective implication data structure w.r.t. minimum activity */
1341  SCIP_Bool useimplics, /**< should implications be used */
1342  SCIP_HASHMAP* binobjvarmap, /**< hash map mapping binary variables with none-zero objective to position in collected variables arrays */
1343  SCIP_Bool* collectedlbvars, /**< temporary buffer to mark collected variables for lower bound fixing */
1344  SCIP_Bool* collectedubvars, /**< temporary buffer to mark collected variables for upper bound fixing */
1345  int nbinobjvars, /**< number of binary variables with non-zero objective coefficient */
1346  SCIP_VAR** contributors, /**< temporary buffer to use for collecting contributors */
1347  SCIP_HASHTABLE* uselesscliques, /**< hash table to store useless cliques, or NULL */
1348  SCIP_Bool* collect /**< pointer to store if the variable should be stored */
1349  )
1350 {
1351  SCIP_Real lbobjchg;
1352  SCIP_Real ubobjchg;
1353  SCIP_Real objval;
1354  int nlbcliques;
1355  int nubcliques;
1356 
1357  assert(objimplics != NULL);
1358 
1359  objval = SCIPvarGetObj(var);
1360  (*objimplics) = NULL;
1361 
1362  if( SCIPisZero(scip, objval) )
1363  (*collect) = FALSE;
1364  else
1365  (*collect) = TRUE;
1366 
1367  nlbcliques = SCIPvarGetNCliques(var, FALSE);
1368  nubcliques = SCIPvarGetNCliques(var, TRUE);
1369 
1370  /* check if implications should be used and if implications are existing */
1371  if( useimplics && nlbcliques + nubcliques > 0 )
1372  {
1373  int nlbcontributors;
1374  int nubcontributors;
1375 
1376  assert((SCIP_Bool)SCIP_BOUNDTYPE_LOWER == FALSE);
1377  assert((SCIP_Bool)SCIP_BOUNDTYPE_UPPER == TRUE);
1378 
1379  /* get contribution of variable by fixing it to its lower bound w.r.t. minimum activity of the objective function */
1380  SCIP_CALL( collectMinactObjchg(scip, var, SCIP_BOUNDTYPE_LOWER, binobjvarmap, collectedlbvars, nbinobjvars,
1381  contributors, uselesscliques, &nlbcontributors, &lbobjchg) );
1382  assert(!SCIPisNegative(scip, lbobjchg));
1383 
1384  SCIPdebugMessage("variable <%s> fixed to bound=%d implies %d(%d)\n", SCIPvarGetName(var),
1385  SCIP_BOUNDTYPE_LOWER, 0, nlbcontributors);
1386 
1387  /* ignore implications if the variable has a zero objective coefficient and implications only one variable, since
1388  * this covered by that implied variable
1389  */
1390  if( !(*collect) && nlbcontributors == 1 )
1391  {
1392  /* reset lower bound contributors */
1393  resetContributors(binobjvarmap, collectedlbvars, contributors, nlbcontributors);
1394 
1395  assert(SCIPisZero(scip, objval));
1396  nlbcontributors = 0;
1397  }
1398 
1399  /* get contribution of variable by fixing it to its upper bound w.r.t. minimum activity of the objective function */
1400  SCIP_CALL( collectMinactObjchg(scip, var, SCIP_BOUNDTYPE_UPPER, binobjvarmap, collectedubvars, nbinobjvars,
1401  &contributors[nlbcontributors], uselesscliques, &nubcontributors, &ubobjchg) );
1402  assert(!SCIPisNegative(scip, ubobjchg));
1403 
1404  SCIPdebugMessage("variable <%s> fixed to bound=%d implies %d(%d)\n", SCIPvarGetName(var),
1405  SCIP_BOUNDTYPE_UPPER, 0, nubcontributors);
1406 
1407  /* ignore implications if the variable has a zero objective coefficient and implications only one variable, since
1408  * this covered by that implied variable
1409  */
1410  if( !(*collect) && nubcontributors == 1 )
1411  {
1412  /* reset upper bound contributors */
1413  resetContributors(binobjvarmap, collectedubvars, &contributors[nlbcontributors], nubcontributors);
1414 
1415  assert(SCIPisZero(scip, objval));
1416  nubcontributors = 0;
1417  }
1418 
1419  if( (*collect) || nlbcontributors > 1 || nubcontributors > 1 )
1420  {
1421  /* creates an objective implication data structure, fixes (globally) variables which are implied by lower and upper
1422  * bound fixing, and clears the collected arrays for lower and upper bound
1423  */
1424  SCIP_CALL( objimplicsCreate(scip, objimplics, contributors, binobjvarmap, collectedlbvars, collectedubvars, lbobjchg, ubobjchg, nlbcontributors, nubcontributors) );
1425  (*collect) = TRUE;
1426  }
1427  else
1428  {
1429  /* reset lower bound contributors */
1430  resetContributors(binobjvarmap, collectedlbvars, contributors, nlbcontributors);
1431 
1432  /* reset upper bound contributors */
1433  resetContributors(binobjvarmap, collectedubvars, &contributors[nlbcontributors], nubcontributors);
1434  }
1435  }
1436  else if( (*collect) )
1437  {
1440  assert(!SCIPisZero(scip, lbobjchg) || !SCIPisZero(scip, ubobjchg));
1441  assert(!SCIPisNegative(scip, lbobjchg));
1442  assert(!SCIPisNegative(scip, ubobjchg));
1443 
1444  /* creates an "empty" objective implication data structure */
1445  SCIP_CALL( objimplicsCreate(scip, objimplics, NULL, NULL, NULL, NULL, lbobjchg, ubobjchg, 0, 0) );
1446  }
1447 
1448  return SCIP_OKAY;
1449 }
1450 
1451 /** check if the given variable should be collected for the maximum activity propagation */
1452 static
1454  SCIP* scip, /**< SCIP data structure */
1455  SCIP_VAR* var, /**< variable to check */
1456  SCIP_Bool useimplics, /**< should implications be used */
1457  SCIP_Real* objchg, /**< pointer to store the objective change w.r.t. maximum activity */
1458  SCIP_Bool* isnotzero /**< pointer to store if the objective change is unequal to zero or not */
1459  )
1460 {
1461  SCIP_Real lbobjchg;
1462  SCIP_Real ubobjchg;
1463 
1464  assert(scip != NULL);
1465  assert(SCIPvarIsBinary(var));
1466  assert(objchg != NULL);
1467  assert(isnotzero != NULL);
1468 
1469  /* get contribution of variable by fixing it to its lower bound w.r.t. maximum activity of the objective function */
1470  SCIP_CALL( getMaxactObjchg(scip, var, SCIP_BOUNDTYPE_LOWER, useimplics, &lbobjchg) );
1471  assert(!SCIPisPositive(scip, lbobjchg));
1472 
1473  /* get contribution of variable by fixing it to its upper bound w.r.t. maximum activity of the objective function */
1474  SCIP_CALL( getMaxactObjchg(scip, var, SCIP_BOUNDTYPE_UPPER, useimplics, &ubobjchg) );
1475  assert(!SCIPisPositive(scip, ubobjchg));
1476 
1477  (*objchg) = MIN(lbobjchg, ubobjchg);
1478 
1479  /* only consider variables with non-zero objective contribution */
1480  if( SCIPisZero(scip, (*objchg)) )
1481  *isnotzero = FALSE;
1482  else
1483  *isnotzero = TRUE;
1484 
1485  return SCIP_OKAY;
1486 }
1487 
1488 /** initializate the propagator */
1489 static
1491  SCIP* scip, /**< SCIP data structure */
1492  SCIP_PROPDATA* propdata /**< propagator data */
1493  )
1494 {
1495  SCIP_VAR** vars;
1496  SCIP_VAR* var;
1497  SCIP_HASHMAP* binobjvarmap;
1498  int nvars;
1499  int nbinvars;
1500  int nintvars;
1501  int nminactvars;
1502  int nmaxactvars;
1503  int nobjintvars;
1504  int nobjcontvars;
1505  int nobjvars;
1506  int nbinobjvars;
1507  int v;
1508 
1509  assert(scip != NULL);
1510  assert(propdata != NULL);
1511 
1512  /* get problem variables */
1513  vars = SCIPgetVars(scip);
1514  nvars = SCIPgetNVars(scip);
1515  nintvars = nvars - SCIPgetNContVars(scip);
1516 
1517  nbinvars = 0;
1518  nobjvars = 0;
1519  nbinobjvars = 0;
1520 
1521  SCIP_CALL( SCIPhashmapCreate(&binobjvarmap, SCIPblkmem(scip), SCIPcalcHashtableSize(SCIPgetNObjVars(scip) * 5)) );
1522 
1523  /* count and collect variable problem indices of variables with non-zero objective coefficient */
1524  for( v = 0; v < nvars; ++v )
1525  {
1526  var = vars[v];
1527  assert(var != NULL);
1528 
1529  if( !SCIPisZero(scip, SCIPvarGetObj(var)) )
1530  {
1531  nobjvars++;
1532 
1533  if( SCIPvarIsBinary(var) )
1534  {
1535  SCIP_CALL( SCIPhashmapInsert(binobjvarmap, (void*)var, (void*)(size_t)(nbinobjvars + 1)) );
1536  nbinobjvars++;
1537  }
1538  }
1539 
1540  if( SCIPvarIsBinary(var) )
1541  nbinvars++;
1542  }
1543 
1544  nminactvars = 0;
1545  nmaxactvars = 0;
1546  nobjintvars = 0;
1547  nobjcontvars = 0;
1548 
1549  if( nobjvars > 0 )
1550  {
1551  SCIP_EVENTHDLR* eventhdlr;
1552  SCIP_OBJIMPLICS* objimplics;
1553  SCIP_HASHTABLE* uselesscliques;
1554  SCIP_VAR** contributors;
1555  SCIP_Bool* collectedlbvars;
1556  SCIP_Bool* collectedubvars;
1557  SCIP_Bool collect;
1558  SCIP_Bool useimplics;
1559  SCIP_Real objval;
1560  SCIP_Real objchg;
1561 
1562  eventhdlr = propdata->eventhdlr;
1563  assert(eventhdlr != NULL);
1564 
1565  useimplics = (propdata->propuseimplics && nbinobjvars < propdata->maximplvars);
1566 
1567  /* allocate memory for all arrays */
1568  SCIP_CALL( SCIPallocMemoryArray(scip, &propdata->minactvars, nbinvars) );
1569  SCIP_CALL( SCIPallocMemoryArray(scip, &propdata->minactimpls, nbinvars) );
1570  SCIP_CALL( SCIPallocMemoryArray(scip, &propdata->maxactvars, nbinvars) );
1571  SCIP_CALL( SCIPallocMemoryArray(scip, &propdata->maxactchgs, nbinvars) );
1572  SCIP_CALL( SCIPallocMemoryArray(scip, &propdata->objintvars, nobjvars - nbinobjvars) );
1573 
1574  if( useimplics )
1575  {
1576  int ncliques;
1577 
1578  /* create temporary buffer */
1579  SCIP_CALL( SCIPallocBufferArray(scip, &contributors, nbinobjvars) );
1580  SCIP_CALL( SCIPallocBufferArray(scip, &collectedlbvars, nbinobjvars+1) );
1581  BMSclearMemoryArray(collectedlbvars, nbinobjvars+1);
1582  SCIP_CALL( SCIPallocBufferArray(scip, &collectedubvars, nbinobjvars+1) );
1583  BMSclearMemoryArray(collectedubvars, nbinobjvars+1);
1584 
1585  ncliques = SCIPgetNCliques(scip);
1586 
1587  if( ncliques > 0 )
1588  {
1589  SCIP_CALL( SCIPhashtableCreate(&uselesscliques, SCIPblkmem(scip), SCIPcalcHashtableSize(ncliques),
1590  cliqueGetHashkey, cliqueIsHashkeyEq, cliqueGetHashkeyVal, NULL) );
1591  }
1592  else
1593  uselesscliques = NULL;
1594  }
1595  else
1596  {
1597  contributors = NULL;
1598  collectedlbvars = NULL;
1599  collectedubvars = NULL;
1600  uselesscliques = NULL;
1601  }
1602 
1603  /* collect the variables with non-zero objective contribution and catch global bound tighten events that decrease the
1604  * maximal pseudo objective activity
1605  */
1606  for( v = 0; v < nvars && (nobjintvars == 0 || nobjintvars < nobjvars - nbinobjvars); ++v )
1607  {
1608  var = vars[v];
1609  assert(var != NULL);
1610 
1611  objval = SCIPvarGetObj(var);
1612 
1613  if( SCIPvarIsBinary(var) )
1614  {
1615  /* ignore variables which are globally fixed */
1616  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
1617  {
1618 #ifndef NDEBUG
1619  /* check that the binary implications are applied for binary variables which are globally fixed */
1620  checkImplicsApplied(scip, var);
1621 #endif
1622  continue;
1623  }
1624 
1625  /* check if the variable should be collected for the minimum activity propagation */
1626  SCIP_CALL( collectMinactVar(scip, var, &objimplics, useimplics, binobjvarmap, collectedlbvars, collectedubvars,
1627  nbinobjvars, contributors, uselesscliques, &collect) );
1628 
1629  if( collect )
1630  {
1631  assert(nminactvars < nbinvars);
1632  assert(objimplics != NULL);
1633  assert(objimplics->nlbimpls + objimplics->nubimpls <= nbinobjvars);
1634 
1635  /* collect the binary variable with non-zero objective contribution */
1636  propdata->minactvars[nminactvars] = var;
1637  propdata->minactimpls[nminactvars] = objimplics;
1638  nminactvars++;
1639 
1640  /* catch bound relax event for the binary variable to handel the firstnonfixed index correctly */
1641  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDRELAXED, eventhdlr, (SCIP_EVENTDATA*)propdata, NULL) );
1642 
1643  SCIPdebugMessage("variable <%s>[obj: <%g>] implicit objective change %g\n",
1644  SCIPvarGetName(var), objval, objimplics->maxobjchg);
1645 
1646  /* captures the variable */
1647  SCIP_CALL( SCIPcaptureVar(scip, var) ) ;
1648  }
1649  /* check if the variable should be collected for the maximum activity propagation */
1650  SCIP_CALL( collectMaxactVar(scip, var, useimplics, &objchg, &collect) );
1651 
1652  if( collect )
1653  {
1654  assert(nmaxactvars < nbinvars);
1655 
1656  /* collect the binary variable with non-zero objective contribution */
1657  propdata->maxactvars[nmaxactvars] = var;
1658  propdata->maxactchgs[nmaxactvars] = -objchg;
1659  nmaxactvars++;
1660 
1661  /* catch bound change events if the variable has a non-zero objective coefficient to check if the maximum
1662  * activity of the objective function changed
1663  */
1664  SCIP_CALL( catchObjEvent(scip, propdata, eventhdlr, var) );
1665 
1666  /* captures the variable */
1667  SCIP_CALL( SCIPcaptureVar(scip, var) ) ;
1668  }
1669  }
1670  else
1671  {
1672  /* only consider none binary variables with a non-zero objective */
1673  if( SCIPisZero(scip, objval) )
1674  continue;
1675 
1676  assert(nobjintvars < nobjvars - nbinobjvars);
1677 
1678  propdata->objintvars[nobjintvars] = var;
1679  nobjintvars++;
1680 
1681  if( v >= nintvars )
1682  nobjcontvars++;
1683 
1684  /* catch bound change events if the variable has a non-zero objective coefficient to check if the maximum
1685  * activity of the objective function changed
1686  */
1687  SCIP_CALL( catchObjEvent(scip, propdata, eventhdlr, var) );
1688 
1689  /* captures the variable */
1690  SCIP_CALL( SCIPcaptureVar(scip, var) );
1691  }
1692  }
1693 
1694  if( useimplics )
1695  {
1696  if( uselesscliques != NULL )
1697  SCIPhashtableFree(&uselesscliques);
1698 
1699  SCIPfreeBufferArray(scip, &collectedubvars);
1700  SCIPfreeBufferArray(scip, &collectedlbvars);
1701  SCIPfreeBufferArray(scip, &contributors);
1702  }
1703 
1704  if( nminactvars == 0 )
1705  {
1706  SCIPfreeMemoryArray(scip, &propdata->minactvars);
1707  SCIPfreeMemoryArray(scip, &propdata->minactimpls);
1708  propdata->minactvars = NULL;
1709  propdata->minactimpls = NULL;
1710  }
1711  else
1712  {
1713  /* sort binary variables with respect to the absolute value of their maximal potential objective contribution for
1714  * the minimum activity of the objective function
1715  */
1716  SCIPsortDownPtrPtr((void**)propdata->minactimpls, (void**)propdata->minactvars, objimplicsComp, nminactvars);
1717 
1718  SCIPdebugMessage("%d binary variables with non-zero objective contribution w.r.t. the minimum activity of the objective function\n", nminactvars);
1719  }
1720 
1721  if( nmaxactvars == 0 )
1722  {
1723  SCIPfreeMemoryArray(scip, &propdata->maxactvars);
1724  SCIPfreeMemoryArray(scip, &propdata->maxactchgs);
1725  propdata->maxactvars = NULL;
1726  propdata->maxactchgs = NULL;
1727  }
1728  else
1729  {
1730  /* sort binary variables with respect to the absolute value of their maximal potential objective contribution for
1731  * the maximum activity of the objective function
1732  */
1733  SCIPsortDownRealPtr(propdata->maxactchgs, (void**)propdata->maxactvars, nmaxactvars);
1734 
1735  SCIPdebugMessage("%d binary variables with non-zero objective contribution w.r.t. the maximum activity of the objective function\n", nmaxactvars);
1736  }
1737 
1738  if( nobjintvars == 0 )
1739  {
1740  SCIPfreeMemoryArray(scip, &propdata->objintvars);
1741  propdata->objintvars = NULL;
1742  }
1743  else
1744  {
1745  /* sort integer variables with respect to the absolute value of their objective coefficient */
1746  SCIPsortDownPtr((void**)propdata->objintvars, varCompObj, nobjintvars - nobjcontvars);
1747 
1748  /* sort continuous variables with respect to the absolute value of their objective coefficient */
1749  SCIPsortDownPtr((void**)(&propdata->objintvars[nobjintvars - nobjcontvars]), varCompObj, nobjcontvars);
1750 
1751  SCIPdebugMessage("%d integer variables and %d continuous variables with non-zero objective contribution\n",
1752  nobjintvars - nobjcontvars, nobjcontvars);
1753  }
1754  }
1755 
1756  SCIPhashmapFree(&binobjvarmap);
1757 
1758  propdata->nminactvars = nminactvars;
1759  propdata->nmaxactvars = nmaxactvars;
1760  propdata->nobjintvars = nobjintvars;
1761  propdata->maxpseudoobjact = SCIP_INVALID;
1762  propdata->maxpseudoobjactinf = 0;
1763  propdata->lastvarnum = -1;
1764  propdata->glbfirstnonfixed = 0;
1765  propdata->maxactfirstnonfixed = 0;
1766  propdata->firstnonfixed = 0;
1767  propdata->nnewvars = 0;
1768  propdata->cutoffbound = SCIPinfinity(scip);
1769  propdata->lastlowerbound = -SCIPinfinity(scip);
1770  propdata->glbpseudoobjval = -SCIPinfinity(scip);
1771 
1772  propdata->initialized = TRUE;
1773 
1774  /* due to scaling after presolving we need to update the global pseudoactivity and the cutoffbound */
1775  propdata->glbpropagated = FALSE;
1776  propdata->glbpseudoobjval = SCIPgetGlobalPseudoObjval(scip);
1777  propdata->cutoffbound = SCIPgetCutoffbound(scip);
1778  assert(SCIPgetDepth(scip) > 0 || SCIPisFeasEQ(scip, propdata->glbpseudoobjval, SCIPgetPseudoObjval(scip)));
1779 
1780  /* create hash table which is used for resolving bound changes */
1781  if( nminactvars > 0 )
1782  {
1783  SCIP_CALL( SCIPhashtableCreate(&propdata->addedvars, SCIPblkmem(scip), SCIPcalcHashtableSize(5*nvars),
1784  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
1785  }
1786  else
1787  propdata->addedvars = NULL;
1788 
1789 
1790  return SCIP_OKAY;
1791 }
1792 
1793 /** adds for the given none binary variable a conflict bound depending on its objective contribution */
1794 static
1796  SCIP* scip, /**< SCIP data structure */
1797  SCIP_VAR* var, /**< variable to check for objective contribution */
1798  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
1799  SCIP_Real* reqpseudoobjval /**< pointer to store the remaining minimum activity which has to be proven */
1800  )
1802  SCIP_Real objval;
1803 
1804  objval = SCIPvarGetObj(var);
1805  assert(!SCIPisZero(scip, objval));
1806 
1807  if( objval > 0.0 )
1808  {
1809  SCIP_Real loclb;
1810  SCIP_Real glblb;
1811 
1812  glblb = SCIPvarGetLbGlobal(var);
1813  loclb = SCIPvarGetLbAtIndex(var, bdchgidx, FALSE);
1814  assert(SCIPisFeasGE(scip, loclb, glblb));
1815 
1816  /* check if the local lower bound (at time stamp bdchgidx) is larger than the global lower bound */
1817  if( SCIPisGT(scip, loclb, glblb) )
1818  {
1819  SCIPdebugMessage(" add bound change <%s>[%g] >= <%g>\n", SCIPvarGetName(var), objval, loclb);
1820  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
1821 
1822  assert(SCIPisPositive(scip, (loclb - glblb) * objval));
1823  (*reqpseudoobjval) -= (loclb - glblb) * objval;
1824  }
1825  }
1826  else
1827  {
1828  SCIP_Real locub;
1829  SCIP_Real glbub;
1830 
1831  glbub = SCIPvarGetUbGlobal(var);
1832  locub = SCIPvarGetUbAtIndex(var, bdchgidx, FALSE);
1833  assert(SCIPisFeasLE(scip, locub, glbub));
1834 
1835  /* check if the local upper bound (at time stamp bdchgidx) is smaller than the global upper bound */
1836  if( SCIPisLT(scip, locub, glbub) )
1837  {
1838  SCIPdebugMessage(" add bound change <%s>[%g] <= <%g>\n", SCIPvarGetName(var), objval, locub);
1839  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
1840 
1841  assert(SCIPisPositive(scip, (locub - glbub) * objval));
1842  (*reqpseudoobjval) -= (locub - glbub) * objval;
1843  }
1844  }
1845 
1846  return SCIP_OKAY;
1847 }
1848 
1849 /** check for the given implication variables of they also contribute to the required minimum activity */
1850 static
1852  SCIP* scip, /**< SCIP data structure */
1853  SCIP_VAR** vars, /**< variable to check for objective contribution */
1854  int start, /**< start index */
1855  int end, /**< end index */
1856  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
1857  SCIP_HASHTABLE* addedvars, /**< hash table containing variables which are already add directly or implicitly due to implications */
1858  SCIP_Real* reqpseudoobjval, /**< pointer to store the remaining minimum activity which has to be proven */
1859  SCIP_Bool* foundimplics /**< pointer to store if an implication is found */
1860  )
1861 {
1862  SCIP_VAR* var;
1863  SCIP_Real lb;
1864  SCIP_Real ub;
1865  int v;
1866 
1867  assert(foundimplics != NULL);
1868  assert(*foundimplics == FALSE);
1869 
1870  for( v = start; v < end; ++v )
1871  {
1872  var = vars[v];
1873  assert(var != NULL);
1874  assert(SCIPvarIsBinary(var));
1875 
1876  lb = SCIPvarGetLbAtIndex(var, bdchgidx, FALSE);
1877  ub = SCIPvarGetUbAtIndex(var, bdchgidx, FALSE);
1878 
1879  if( lb < 0.5 && ub > 0.5 && !SCIPhashtableExists(addedvars, (void*)var) )
1880  {
1881  (*reqpseudoobjval) -= REALABS(SCIPvarGetObj(var));
1882  SCIPdebugMessage(" implicated variables <%s>[%g] bdchgidx [%g,%g] -> remaining <%g>\n", SCIPvarGetName(var), SCIPvarGetObj(var), lb, ub, *reqpseudoobjval);
1883 
1884  SCIP_CALL( SCIPhashtableInsert(addedvars, (void*)var) );
1885  assert(SCIPhashtableExists(addedvars, (void*)var));
1886  (*foundimplics) = TRUE;
1887  }
1888  }
1889 
1890  return SCIP_OKAY;
1891 }
1892 
1893 /** adds for the given binary variable a conflict bound depending on its objective contribution */
1894 static
1896  SCIP* scip, /**< SCIP data structure */
1897  SCIP_VAR* var, /**< variable to check for objective contribution */
1898  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
1899  SCIP_OBJIMPLICS* objimplics, /**< objective implication data for the given variable */
1900  SCIP_HASHTABLE* addedvars, /**< hash table containing variables which are already add directly or implicitly due to implications */
1901  SCIP_Bool respropuseimplics, /**< should implications be used */
1902  SCIP_Real* reqpseudoobjval /**< pointer to store the remaining minimum activity which has to be proven */
1903  )
1904 {
1905  SCIP_Real objval;
1906  SCIP_Real lb;
1907  SCIP_Real ub;
1908  SCIP_Bool foundimplics;
1909 
1910  assert(SCIPvarIsBinary(var));
1911 
1912  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
1913  return SCIP_OKAY;
1914 
1915  lb = SCIPvarGetLbAtIndex(var, bdchgidx, FALSE);
1916  ub = SCIPvarGetUbAtIndex(var, bdchgidx, FALSE);
1917 
1918  objval = SCIPvarGetObj(var);
1919  foundimplics = FALSE;
1920 
1921  /* only consider variables which are fixed */
1922  if( lb > 0.5 )
1923  {
1924  if( respropuseimplics )
1925  {
1926  SCIP_CALL( getConflictImplics(scip, objimplics->objvars, objimplics->nlbimpls, objimplics->nlbimpls + objimplics->nubimpls,
1927  bdchgidx, addedvars, reqpseudoobjval, &foundimplics) );
1928  }
1929 
1930  /* check if the binary variable has a positive contribution (positive objective coefficient since it is fixed to
1931  * one) or is needed due a positive contribution of an implied variable
1932  */
1933  if( foundimplics || SCIPisPositive(scip, objval) )
1934  {
1935  SCIPdebugMessage(" add bound change <%s>[%g] >= <%g> bdchgidx [%g,%g]\n", SCIPvarGetName(var), objval, lb, lb, ub);
1936  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
1937 
1938  (*reqpseudoobjval) -= MAX(0.0, objval);
1939 
1940  if( addedvars != NULL )
1941  {
1942  assert(!SCIPhashtableExists(addedvars, (void*)var));
1943  SCIP_CALL( SCIPhashtableInsert(addedvars, (void*)var) );
1944  }
1945  }
1946  }
1947  else if( ub < 0.5 )
1948  {
1949  if( respropuseimplics )
1950  {
1951  SCIP_CALL( getConflictImplics(scip, objimplics->objvars, 0, objimplics->nlbimpls,
1952  bdchgidx, addedvars, reqpseudoobjval, &foundimplics) );
1953  }
1954 
1955  /* check if the binary variable has a positive contribution (negative objective coefficient since it is fixed to
1956  * zero) or is needed due a positive contribution of an implied variable
1957  */
1958  if( foundimplics || SCIPisNegative(scip, objval) )
1959  {
1960  SCIPdebugMessage(" add bound change <%s>[%g] <= <%g> bdchgidx=[%g,%g]\n", SCIPvarGetName(var), objval, ub, lb, ub);
1961  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
1962 
1963  (*reqpseudoobjval) += MIN(0.0, objval);
1964 
1965  if( addedvars != NULL )
1966  {
1967  assert(!SCIPhashtableExists(addedvars, (void*)var));
1968  SCIP_CALL( SCIPhashtableInsert(addedvars, (void*)var) );
1969  }
1970  }
1971  }
1972 
1973  return SCIP_OKAY;
1974 }
1975 
1976 
1977 /** resolves a propagation by supplying the variables whose bound changes increased the pseudo objective value above the
1978  * cutoff bound
1979  */
1980 static
1982  SCIP* scip, /**< SCIP data structure */
1983  SCIP_PROPDATA* propdata, /**< propagator data */
1984  SCIP_VAR* var, /**< variable that was deduced */
1985  int inferinfo, /**< inference information */
1986  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
1987  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
1988  SCIP_HASHTABLE* addedvars, /**< hash table which contains variable which are already added or implict given as reason for the resolve, or NULL */
1989  SCIP_Real* cutoffbound /**< pointer to store the adjusted cutoff bound */
1990  )
1991 {
1992  if( inferinfo != -1 )
1993  {
1994  SCIP_OBJIMPLICS* objimplics;
1995  SCIP_Bool foundimplics;
1996  int start;
1997  int end;
1998 
1999  assert(var != NULL);
2000  assert(SCIPvarIsBinary(var));
2001  assert(bdchgidx != NULL);
2002  assert(SCIPisEQ(scip, SCIPvarGetLbAtIndex(var, bdchgidx, TRUE), SCIPvarGetUbAtIndex(var, bdchgidx, TRUE)));
2003  assert(inferinfo >= 0);
2004  assert(inferinfo < propdata->nminactvars);
2005  assert((SCIP_Bool)SCIP_BOUNDTYPE_LOWER == FALSE);
2006  assert((SCIP_Bool)SCIP_BOUNDTYPE_UPPER == TRUE);
2007 
2008  objimplics = propdata->minactimpls[inferinfo];
2009  assert(objimplics != NULL);
2010 
2011  /* get the objective contribution if we would fix the binray inference variable to its other bound */
2012  (*cutoffbound) -= getVarObjchg(var, SCIPvarGetBestBoundType(var), boundtype);
2013  foundimplics = FALSE;
2014 
2015  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2016  {
2017  start = 0;
2018  end = objimplics->nlbimpls;
2019  }
2020  else
2021  {
2022  start = objimplics->nlbimpls;
2023  end = objimplics->nlbimpls + objimplics->nubimpls;
2024  }
2025 
2026  SCIP_CALL( getConflictImplics(scip, objimplics->objvars, start, end, bdchgidx, addedvars, cutoffbound, &foundimplics) );
2027  }
2028  else
2029  {
2030  SCIP_Real glbbound;
2031  SCIP_Real newbound;
2032  SCIP_Real objval;
2033 
2034  objval = SCIPvarGetObj(var);
2035 
2036  assert(!SCIPisZero(scip, objval));
2037 
2038  if( objval > 0.0 )
2039  {
2040  newbound = SCIPvarGetUbAtIndex(var, bdchgidx, TRUE);
2041  glbbound = SCIPvarGetLbGlobal(var);
2042  }
2043  else
2044  {
2045  newbound = SCIPvarGetLbAtIndex(var, bdchgidx, TRUE);
2046  glbbound = SCIPvarGetUbGlobal(var);
2047  }
2048 
2049  /* in case the variable is integral we just need to prove the newbound plus/minus (1 - epsilon) since the this bound
2050  * would be rounded to newbound due to integrability which is global information
2051  */
2052  if( SCIPvarIsIntegral(var) )
2053  {
2054  if( objval > 0.0 )
2055  newbound += 1 - 10 * SCIPfeastol(scip);
2056  else
2057  newbound -= 1 - 10 * SCIPfeastol(scip);
2058  }
2059 
2060  /* adjust the cutoff bound by the portion the inference variable contributes to the presudo objective activitiy
2061  * (minactivity)
2062  */
2063  assert(!SCIPisNegative(scip, objval * (newbound - glbbound)));
2064  (*cutoffbound) -= objval * (newbound - glbbound);
2065  }
2066 
2067  return SCIP_OKAY;
2068 }
2069 
2070 
2071 /** resolves a propagation by supplying the variables whose bound changes increased the pseudo objective value above the
2072  * cutoff bound
2073  */
2074 static
2076  SCIP* scip, /**< SCIP data structure */
2077  SCIP_PROPDATA* propdata, /**< propagator data */
2078  SCIP_Real cutoffbound, /**< the global cutoff */
2079  SCIP_VAR* infervar, /**< variable that was deduced, or NULL for conflict analysis initialization */
2080  int inferinfo, /**< inference information */
2081  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2082  SCIP_BDCHGIDX* bdchgidx /**< bound change index (time stamp of bound change), or NULL for current time */
2083  )
2084 {
2085  SCIP_HASHTABLE* addedvars;
2086  SCIP_VAR** vars;
2087  SCIP_VAR* var;
2088  SCIP_Real glbpseudoobjval;
2089  SCIP_Real reqpseudoobjval;
2090  SCIP_Bool infinity;
2091  int nvars;
2092  int v;
2093 
2094  infinity = FALSE;
2095  addedvars = NULL;
2096  nvars = propdata->nminactvars;
2097 
2098  /* the global pseudo value gives us a global valid minimal activity
2099  *
2100  * @note The global pseudo objective activity can be minus infinity. In that case all variable are part of the
2101  * reason/explanation
2102  *
2103  * @note If the global pseudo objective activity is greater than the required minactivity, the local bound change
2104  * which has to explained is actually (now) a global one. That means, the reason/explanation is empty
2105  */
2106  glbpseudoobjval = SCIPgetGlobalPseudoObjval(scip);
2107 
2108  if( SCIPisInfinity(scip, -glbpseudoobjval) )
2109  {
2110  infinity = TRUE;
2111  reqpseudoobjval = cutoffbound;
2112  }
2113  else
2114  {
2115  /* clear hash table for storing variables which are not needed to add the reason due to global implications or
2116  * already added
2117  */
2118  if( nvars > 0 )
2119  {
2120  addedvars = propdata->addedvars;
2121  SCIPhashtableRemoveAll(addedvars);
2122  }
2123 
2124  if( infervar != NULL )
2125  {
2126  SCIP_CALL( adjustCutoffbound(scip, propdata, infervar, inferinfo, boundtype, bdchgidx, addedvars, &cutoffbound) );
2127  }
2128 
2129  reqpseudoobjval = cutoffbound - glbpseudoobjval;
2130  }
2131 
2132  SCIPdebugMessage("resolve propagation global pseudo objective <%g>, cutoff bounda <%g>, required minactivity <%g>\n",
2133  glbpseudoobjval, cutoffbound, reqpseudoobjval);
2134 
2135  /* the variables responsible for the propagation are the ones with
2136  * - obj > 0 and local lb > global lb
2137  * - obj < 0 and local ub < global ub
2138  *
2139  * collect all variables which contribute positively to the pseudo objective value (minimum activity) until we
2140  * reached the (adjusted) required minimum activity for the inference bound chnage
2141  */
2142 
2143  /* first consider the binary variables */
2144  if( nvars > 0 )
2145  {
2146  SCIP_OBJIMPLICS** minactimpls;
2147 
2148  vars = propdata->minactvars;
2149  assert(vars != NULL);
2150 
2151  minactimpls = propdata->minactimpls;
2152  assert(minactimpls != NULL);
2153 
2154 #ifndef NDEBUG
2155  checkGlbfirstnonfixed(scip, propdata);
2156 #endif
2157 
2158  if( infinity )
2159  {
2160  /* if the required minimum activity is minus infinity, we have to add all variables which contribute the local
2161  * prseudo objective activity
2162  */
2163 
2164  for( v = propdata->glbfirstnonfixed; v < nvars; ++v )
2165  {
2166  var = vars[v];
2167  assert(var != NULL);
2168 
2169  /* @note binary variables can have a zero objective value */
2170 
2171  if( var == infervar )
2172  continue;
2173 
2174  SCIP_CALL( addConflictBinvar(scip, var, bdchgidx, NULL, NULL, FALSE, &reqpseudoobjval) );
2175  }
2176  }
2177  else
2178  {
2179  assert(addedvars != NULL);
2180 
2181  for( v = propdata->glbfirstnonfixed; v < nvars && SCIPisPositive(scip, reqpseudoobjval); ++v )
2182  {
2183  var = vars[v];
2184  assert(var != NULL);
2185 
2186  /* @note binary variables can have a zero objective value */
2187 
2188  if( var == infervar )
2189  continue;
2190 
2191  if( SCIPhashtableExists(addedvars, (void*)var) )
2192  continue;
2193 
2194  SCIP_CALL( addConflictBinvar(scip, var, bdchgidx, minactimpls[v], addedvars, propdata->respropuseimplics, &reqpseudoobjval) );
2195  }
2196  }
2197  }
2198 
2199  vars = propdata->objintvars;
2200  nvars = propdata->nobjintvars;
2201  assert(nvars == 0 || vars != NULL);
2202 
2203  /* second consider the none binary variables */
2204  for( v = 0; v < nvars && (infinity || SCIPisPositive(scip, reqpseudoobjval)); ++v )
2205  {
2206  var = vars[v];
2207  assert(var != NULL);
2208  assert(!SCIPisZero(scip, SCIPvarGetObj(var)));
2209 
2210  if( var == infervar )
2211  continue;
2212 
2213  SCIP_CALL( addConflictBounds(scip, var, bdchgidx, &reqpseudoobjval) );
2214  }
2215 
2216  return SCIP_OKAY;
2217 }
2218 
2219 /** propagates the given variable against the cutoff bound */
2220 static
2222  SCIP* scip, /**< SCIP data structure */
2223  SCIP_PROP* prop, /**< propagator, or NULL */
2224  SCIP_VAR* var, /**< variable to propagate */
2225  int inferinfo, /**< inference information to store with the bound change */
2226  SCIP_Real objchg, /**< objective change */
2227  SCIP_Real cutoffbound, /**< cutoff bound to use */
2228  SCIP_Real pseudoobjval, /**< pseudo objective value to use */
2229  SCIP_Bool local, /**< local or global propagation */
2230  SCIP_Bool* tightened /**< pointer to store if the variable domain was tightened */
2231  )
2232 {
2233  SCIP_Real lb;
2234  SCIP_Real ub;
2235  SCIP_Real newbd;
2236  SCIP_Bool infeasible;
2237 
2238  assert(!SCIPisZero(scip, objchg));
2239  assert(!SCIPisInfinity(scip, -pseudoobjval));
2240  assert(!SCIPisInfinity(scip, cutoffbound));
2241  assert(SCIPisLT(scip, pseudoobjval, cutoffbound) );
2242  assert(tightened != NULL);
2243 
2244  *tightened = FALSE;
2245 
2246  /* collect bounds of the variable */
2247  if( local )
2248  {
2249  assert(prop != NULL);
2250  lb = SCIPvarGetLbLocal(var);
2251  ub = SCIPvarGetUbLocal(var);
2252  }
2253  else
2254  {
2255  lb = SCIPvarGetLbGlobal(var);
2256  ub = SCIPvarGetUbGlobal(var);
2257  }
2258 
2259  if( SCIPisFeasEQ(scip, lb, ub) )
2260  return SCIP_OKAY;
2261 
2262  /* depending on the objective contribution we can try to tighten the lower or upper bound of the variable */
2263  if( objchg > 0.0 )
2264  {
2265  newbd = lb + (cutoffbound - pseudoobjval) / objchg;
2266 
2267  if( local )
2268  {
2269  SCIP_CALL( SCIPinferVarUbProp(scip, var, newbd, prop, inferinfo, FALSE, &infeasible, tightened) );
2270  assert(!infeasible);
2271 
2272  if( *tightened ) /* might not be tightened due to numerical reasons */
2273  {
2274  SCIPdebugMessage(" -> new (local) upper bound of variable <%s>[%g,%g]: %g, objective change <%g>, pseudo objective <%g>, cutoff bound <%g>\n",
2275  SCIPvarGetName(var), lb, ub, newbd, objchg, pseudoobjval, cutoffbound);
2276  }
2277  }
2278  else
2279  {
2280  SCIP_CALL( SCIPtightenVarUbGlobal(scip, var, newbd, FALSE, &infeasible, tightened) );
2281  assert(!infeasible);
2282 
2283  if( *tightened )
2284  {
2285  SCIPdebugMessage(" -> new (global) upper bound of variable <%s>[%g,%g]: %g, objective change <%g>, pseudo objective <%g>, cutoff bound <%g>\n",
2286  SCIPvarGetName(var), lb, ub, newbd, objchg, pseudoobjval, cutoffbound);
2287  }
2288  }
2289  }
2290  else
2291  {
2292  newbd = ub + (cutoffbound - pseudoobjval) / objchg;
2293 
2294  if( local )
2295  {
2296  SCIP_CALL( SCIPinferVarLbProp(scip, var, newbd, prop, inferinfo, FALSE, &infeasible, tightened) );
2297  assert(!infeasible);
2298 
2299  if( *tightened ) /* might not be tightened due to numerical reasons */
2300  {
2301  SCIPdebugMessage(" -> new (local) lower bound of variable <%s>[%g,%g]: %g, objective change <%g>, pseudo objective <%g>, cutoff bound <%g>\n",
2302  SCIPvarGetName(var), lb, ub, newbd, objchg, pseudoobjval, cutoffbound);
2303  }
2304  }
2305  else
2306  {
2307  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, newbd, FALSE, &infeasible, tightened) );
2308  assert(!infeasible);
2309 
2310  if( *tightened )
2311  {
2312  SCIPdebugMessage(" -> new (global) lower bound of variable <%s>[%g,%g]: %g, objective change <%g>, pseudo objective <%g>, cutoff bound <%g>\n",
2313  SCIPvarGetName(var), lb, ub, newbd, objchg, pseudoobjval, cutoffbound);
2314  }
2315  }
2316  }
2317 
2318  return SCIP_OKAY;
2319 }
2320 
2321 /** propagates the given binary variable against the cutoff bound */
2322 static
2324  SCIP* scip, /**< SCIP data structure */
2325  SCIP_PROP* prop, /**< propagator, or NULL */
2326  SCIP_VAR* var, /**< variable to propagate */
2327  int pos, /**< position of the variable in the corresponding propdata variable array */
2328  SCIP_Real cutoffbound, /**< cutoff bound to use */
2329  SCIP_Real pseudoobjval, /**< pseudo objective value to use */
2330  SCIP_Bool* tightened, /**< pointer to store if the variable domain was tightened */
2331  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
2332  SCIP_Bool local /**< propagate local bounds, otherwise global bounds */
2333  )
2334 {
2335  SCIP_PROPDATA* propdata;
2336  SCIP_OBJIMPLICS* objimplics;
2337  SCIP_Real lbobjchg;
2338  SCIP_Real ubobjchg;
2339  SCIP_Real objchg;
2340 
2341  assert(SCIPvarIsBinary(var));
2342 
2343  propdata = SCIPpropGetData(prop);
2344  assert(propdata != NULL);
2345 
2346  objimplics = propdata->minactimpls[pos];
2347  assert(objimplics != NULL);
2348 
2349  /* get objective change in case of fixing the variable to its lower bound (that is zero) */
2350  SCIP_CALL( getMinactObjchg(scip, var, objimplics, NULL, SCIP_BOUNDTYPE_LOWER, local, &lbobjchg) );
2351  assert(!SCIPisNegative(scip, lbobjchg));
2352 
2353  /* get objective change in case of fixing the variable to its upper bound (that is one) */
2354  SCIP_CALL( getMinactObjchg(scip, var, objimplics, NULL, SCIP_BOUNDTYPE_UPPER, local, &ubobjchg) );
2355  assert(!SCIPisNegative(scip, ubobjchg));
2356 
2357  (*tightened) = FALSE;
2358 
2359  /* nothing can be done if the objective contribution is zero independently of the bound */
2360  if( SCIPisZero(scip, lbobjchg) && SCIPisZero(scip, ubobjchg) )
2361  return SCIP_OKAY;
2362 
2363  /* if the lbobjchg and ubobjchg are both able to fix the variable to its upper (1.0) or lower (0.0) bound,
2364  * respectively, we detected an cutoff
2365  *
2366  * @note There is no need to use SCIPisFeasLT() in case the objective is integral since the cutoff bound in that case
2367  * is the upper bound minus 1 plus the SCIPcutoffbounddelta() (which is MIN(100.0 * feastol, 0.0001)). However,
2368  * if the objective is not integral we have to check w.r.t. an epsilon to avoid numerical problems.
2369  */
2370  if( SCIPisFeasLT(scip, cutoffbound, pseudoobjval + ubobjchg) && SCIPisFeasLT(scip, cutoffbound, pseudoobjval + lbobjchg) )
2371  {
2372  /* check if conflict analysis is applicable */
2373  if( local && SCIPisConflictAnalysisApplicable(scip) )
2374  {
2375  assert(SCIPgetDepth(scip) > 0);
2376 
2377  /* initialize conflict analysis */
2379 
2380  /* add all variable whose best bound changes increased the pseudo objective value above to cutoff bound */
2381  SCIP_CALL( resolvePropagation(scip, propdata, pseudoobjval, NULL, -1, SCIP_BOUNDTYPE_UPPER, NULL) );
2382 
2383  /* analyze the conflict */
2384  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
2385  }
2386 
2387  (*cutoff) = TRUE;
2388  }
2389  else
2390  {
2391  /* try to tighten the variable bound use the larger objective contribution */
2392  if( lbobjchg > ubobjchg )
2393  objchg = -lbobjchg;
2394  else
2395  objchg = ubobjchg;
2396 
2397  SCIP_CALL( propagateCutoffboundVar(scip, prop, var, pos, objchg, cutoffbound, pseudoobjval, local, tightened) );
2398  }
2399 
2400  return SCIP_OKAY;
2401 }
2402 
2403 /** globally propagates if a new cutoff bound or global pseudo objective value (minimum activity of the objective
2404  * function) is available
2405  */
2406 static
2408  SCIP* scip, /**< SCIP data structure */
2409  SCIP_PROP* prop, /**< propagator */
2410  int* nchgbds, /**< pointer to store the number of bound changes */
2411  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
2412  )
2414  SCIP_PROPDATA* propdata;
2415  SCIP_VAR** minactvars;
2416  SCIP_VAR** objintvars;
2417  SCIP_VAR* var;
2418  SCIP_Bool tightened;
2419  SCIP_Real pseudoobjval;
2420  SCIP_Real cutoffbound;
2421  int nminactvars;
2422  int nobjintvars;
2423  int v;
2424 
2425  /* this method should not be called in the root node of the search tree since the standard propagation already does
2426  * the job
2427  */
2428  assert(SCIPgetDepth(scip) > 0);
2429 
2430  propdata = SCIPpropGetData(prop);
2431  assert(propdata != NULL);
2432 
2433  pseudoobjval = SCIPgetGlobalPseudoObjval(scip);
2434  cutoffbound = propdata->cutoffbound;
2435 
2436  /* nothing can be done if the global pseudo objective is minus infinity */
2437  if( SCIPisInfinity(scip, -pseudoobjval) )
2438  return SCIP_OKAY;
2439 
2440  /* check if the global pseudo objective value (minimum activity of the objective function) is greater or equal to
2441  * the cutoff bound
2442  */
2443  if( SCIPisGE(scip, pseudoobjval, cutoffbound) )
2444  {
2445  *cutoff = TRUE;
2446  return SCIP_OKAY;
2447  }
2448 
2449  minactvars = propdata->minactvars;
2450  objintvars = propdata->objintvars;
2451  nminactvars = propdata->nminactvars;
2452  nobjintvars = propdata->nobjintvars;
2453 
2454 #ifndef NDEBUG
2455  checkGlbfirstnonfixed(scip, propdata);
2456 #endif
2457 
2458  *cutoff = FALSE;
2459 
2460  /* always propagate the binary variables completely */
2461  for( v = propdata->glbfirstnonfixed; v < nminactvars; ++v )
2462  {
2463  var = minactvars[v];
2464  assert(var != NULL);
2465 
2466  /* check if the variables is already globally fixed; if so continue with the potential candidate */
2467  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
2468  continue;
2469 
2470  /* propagates the cutoff bound for the given binary variable */
2471  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, FALSE) );
2472 
2473  /* the binary variables are sorted in non-increasing manner w.r.t. the absolute value of their objective
2474  * contribution w.r.t. minimum activity (pseudo objective value) of the objective function; these values are the
2475  * increase in the pseudo objective activity we would get if we fix the variable to its worse bound; hence, we can
2476  * stop if for a variable this potential increase is not enough too exceed the cutoff bound;
2477  */
2478  if( !tightened )
2479  {
2480  SCIPdebugMessage("interrupt global pseudo objective propagation w.r.t. cutoff bound <%.15g> for binary variables after %d from %d binary variables\n",
2481  cutoffbound, v, nminactvars);
2482  break;
2483  }
2484 
2485  if( *cutoff )
2486  return SCIP_OKAY;
2487 
2488  /* @note The variable might not be globally fixed right away since this would destroy the local internal
2489  * data structure of a search node; the bound change is in that case pending; hence we cannot assert
2490  * that the variable is globally fixed
2491  */
2492  (*nchgbds)++;
2493  }
2494  propdata->glbfirstnonfixed = v;
2495  propdata->firstnonfixed = MAX(propdata->firstnonfixed, v);
2496 
2497  /* check all binary variables which could potentially be fixed */
2498  for( ; v < nminactvars && cutoffbound - pseudoobjval < propdata->minactimpls[v]->maxobjchg; ++v )
2499  {
2500  var = minactvars[v];
2501  assert(var != NULL);
2502 
2503  /* check if the variables is already globally fixed; if so continue with the potential candidate */
2504  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
2505  continue;
2506 
2507  /* propagates the cutoff bound for the given binary variable */
2508  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, FALSE) );
2509 
2510  /* check if the domain of the variable was reduced */
2511  if( tightened )
2512  (*nchgbds)++;
2513 
2514  if( *cutoff )
2515  return SCIP_OKAY;
2516  }
2517 
2518 #if 0 /* might fail, but is not a real error, still need to investigate */
2519 #ifndef NDEBUG
2520  /* check that the abort criteria for the binary variables works */
2521  for( ; v < nminactvars; ++v )
2522  {
2523  assert(cutoffbound - pseudoobjval >= propdata->minactimpls[v]->maxobjchg);
2524 
2525  var = minactvars[v];
2526  assert(var != NULL);
2527 
2528  /* check if the variable is already locally fixed; in that case we just continue with the next potential
2529  * candidate
2530  */
2531  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
2532  continue;
2533 
2534  /* propagates the cutoff bound for the given binary variable */
2535  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, FALSE) );
2536  assert(!tightened);
2537  assert(!(*cutoff));
2538  }
2539 #endif
2540 #endif
2541 
2542  /* propagate the none binary variables completely */
2543  for( v = 0; v < nobjintvars; ++v )
2544  {
2545  var = objintvars[v];
2546  assert(var != NULL);
2547  assert(!SCIPisZero(scip, SCIPvarGetObj(var)));
2548 
2549  /* try to tighten the bound of the variable */
2550  SCIP_CALL( propagateCutoffboundVar(scip, NULL, var, -1, SCIPvarGetObj(var), cutoffbound, pseudoobjval, FALSE, &tightened) );
2551 
2552  /* check if the domain of the variable was reduced */
2553  if( tightened )
2554  (*nchgbds)++;
2555  }
2556 
2557  propdata->glbpropagated = TRUE;
2558 
2559  return SCIP_OKAY;
2560 }
2561 
2562 /** propagates the cutoff bound for binary variables (c*x <= cutoff) */
2563 static
2565  SCIP* scip, /**< SCIP data structure */
2566  SCIP_PROP* prop, /**< propagator */
2567  SCIP_Real cutoffbound, /**< cutoff bound to use */
2568  SCIP_Real pseudoobjval, /**< pseudo objective value to use */
2569  int* nfixedvars, /**< pointer to store the number of fixed variables */
2570  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
2571  )
2572 {
2573  SCIP_PROPDATA* propdata;
2574  SCIP_VAR** minactvars;
2575  SCIP_VAR* var;
2576  SCIP_Bool tightened;
2577  int nminactvars;
2578  int v;
2579 
2580  propdata = SCIPpropGetData(prop);
2581  assert(propdata != NULL);
2582 
2583  minactvars = propdata->minactvars;
2584  nminactvars = propdata->nminactvars;
2585  assert(nminactvars == 0 || minactvars != NULL);
2586 
2587  /* always propagate the binary variables completely; note that the variables before the firstnonfixed indexed are
2588  * already locally fixed and those before glbfirstnonfixed are already globally fixed
2589  */
2590 
2591 #ifndef NDEBUG
2592  /* check that the variables before glbfirstnonfixed are globally fixed */
2593  checkGlbfirstnonfixed(scip, propdata);
2594 
2595  /* check that the variables before firstnonfixed are locally fixed */
2596  for( v = propdata->glbfirstnonfixed; v < propdata->firstnonfixed; ++v )
2597  {
2598  var = minactvars[v];
2599  assert(var != NULL);
2600 
2601  assert(SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5);
2602  }
2603 #endif
2604 
2605  (*cutoff) = FALSE;
2606 
2607  for( v = propdata->firstnonfixed; v < nminactvars; ++v )
2608  {
2609  var = minactvars[v];
2610  assert(var != NULL);
2611 
2612  /* check if the variable is already locally fixed; in that case we just continue with the next potential
2613  * candidate
2614  */
2615  if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5)
2616  continue;
2617 
2618  /* propagates the cutoff bound for the given binary variable */
2619  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, TRUE) );
2620 
2621  /* the binary variables are sorted in non-increasing manner w.r.t. the absolute value of their objective
2622  * contribution w.r.t. minimum activity of the objective function; These values are the increase in the pseudo
2623  * objective activity (minimum activity of the objective function) we would get if we fix the variable to its
2624  * worse bound; hence, we can stop if for a variable this potential increase is not enough too exceed the cutoff
2625  * bound;
2626  */
2627  if( !tightened )
2628  {
2629  SCIPdebugMessage("interrupt local pseudo objective propagation w.r.t. cutoff bound <%.15g> for binary variables after %d from %d binary variables\n",
2630  cutoffbound, v, nminactvars);
2631  break;
2632  }
2633 
2634  if( *cutoff )
2635  return SCIP_OKAY;
2636 
2637  /* check that the binary variable is locally fixed */
2638  assert(SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5);
2639  (*nfixedvars)++;
2640  }
2641  propdata->firstnonfixed = v;
2642 
2643  /* check all binary variables which could potentially be fixed */
2644  for( ; v < nminactvars && cutoffbound - pseudoobjval < propdata->minactimpls[v]->maxobjchg; ++v )
2645  {
2646  var = minactvars[v];
2647  assert(var != NULL);
2648 
2649  /* check if the variable is already locally fixed; in that case we just continue with the next potential
2650  * candidate
2651  */
2652  if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5)
2653  continue;
2654 
2655  /* propagates the cutoff bound for the given binary variable */
2656  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, TRUE) );
2657 
2658  if( tightened )
2659  {
2660  assert(SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5);
2661  (*nfixedvars)++;
2662  }
2663 
2664  if( *cutoff )
2665  return SCIP_OKAY;
2666  }
2667 
2668 #if 0 /* might fail, but is not a real error, still need to investigate */
2669 #ifndef NDEBUG
2670  /* check that the abort criteria for the binary variables works */
2671  for( ; v < nminactvars; ++v )
2672  {
2673  var = minactvars[v];
2674  assert(var != NULL);
2675 
2676  assert(cutoffbound - pseudoobjval >= propdata->minactimpls[v]->maxobjchg);
2677 
2678  /* check if the variable is already locally fixed; in that case we just continue with the next potential
2679  * candidate
2680  */
2681  if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5)
2682  continue;
2683 
2684  /* propagates the cutoff bound for the given binary variable */
2685  SCIP_CALL( propagateCutoffboundBinvar(scip, prop, var, v, cutoffbound, pseudoobjval, &tightened, cutoff, TRUE) );
2686  assert(!tightened);
2687  assert(!(*cutoff));
2688  }
2689 #endif
2690 #endif
2691 
2692  return SCIP_OKAY;
2693 }
2694 
2695 /** propagates the cutoff bound c*x <= cutoff */
2696 static
2698  SCIP* scip, /**< SCIP data structure */
2699  SCIP_PROP* prop, /**< propagator */
2700  SCIP_RESULT* result /**< pointer to store the result of the callback method */
2701  )
2702 {
2703  SCIP_PROPDATA* propdata;
2704  SCIP_Real pseudoobjval;
2705  SCIP_Real cutoffbound;
2706  SCIP_Bool cutoff;
2707  SCIP_Bool tightened;
2708  int nchgbds;
2709 
2710  assert(result != NULL);
2711 
2712  (*result) = SCIP_DIDNOTRUN;
2713 
2714  propdata = SCIPpropGetData(prop);
2715  assert(propdata != NULL);
2716 
2717  /* get current pseudo objective value (minimum activity of the objective function) and cutoff bound */
2718  pseudoobjval = SCIPgetPseudoObjval(scip);
2719  if( SCIPisInfinity(scip, -pseudoobjval) )
2720  return SCIP_OKAY;
2721  cutoffbound = SCIPgetCutoffbound(scip);
2722  if( SCIPisInfinity(scip, cutoffbound) )
2723  return SCIP_OKAY;
2724 
2725  /* @note A new global pseudo objective value could be used to retrive global fixings. There is, however, no need to
2726  * check if a new global pseudo objective value is available. This is the case since a new (better) global
2727  * pseudo activity implicis that a global bound change was performed. That causes that the root node of the
2728  * search tree get marked for repropagation. That will result in propagation call of the pseudo objective
2729  * propagator.
2730  */
2731 
2732  /* check current cutoff bound */
2733  if( cutoffbound < propdata->cutoffbound )
2734  {
2735  propdata->glbpropagated = FALSE;
2736  propdata->cutoffbound = cutoffbound;
2737  }
2738 
2739  nchgbds = 0;
2740  cutoff = FALSE;
2741  (*result) = SCIP_DIDNOTFIND;
2742 
2743  /* check if we have a new cutoff bound; in that case we globally propagate this new bound
2744  *
2745  * @note there is no need to propagate the cutoff bound if we are in the root node since this will be done by the
2746  * standard local propagation
2747  */
2748  if( propdata->propcutoffbound && !propdata->glbpropagated && SCIPgetDepth(scip) > 0 )
2749  {
2750  /* first globally propagate new cutoff bound or pseudo objective activity */
2751  SCIP_CALL( propagateCutoffboundGlobally(scip, prop, &nchgbds, &cutoff) );
2752 
2753  if( cutoff )
2754  {
2755  /* we are done with solving since a global pseudo activity is greater or equal to the cutoff bound */
2756  SCIP_CALL( SCIPcutoffNode(scip, SCIPgetRootNode(scip)) );
2757 
2758  (*result) = SCIP_CUTOFF;
2759  return SCIP_OKAY;
2760  }
2761 
2762  /* check if the global propagation cut off the active/current node */
2763  if( SCIPgetCutoffdepth(scip) <= SCIPgetDepth(scip) )
2764  {
2765  (*result) = SCIP_CUTOFF;
2766  return SCIP_OKAY;
2767  }
2768  }
2769 
2770  /* check if the pseudo objective value (minimum activity of the objective function) is greater or equal to the cutoff
2771  * bound
2772  */
2773  if( SCIPisGE(scip, pseudoobjval, cutoffbound) )
2774  {
2775  SCIPdebugMessage("pseudo objective value <%g> exceeds cutoff bound <%g>\n", pseudoobjval, cutoffbound);
2776 
2777  /* check if conflict analysis is applicable */
2779  {
2780  assert(SCIPgetDepth(scip) > 0);
2781 
2782  /* initialize conflict analysis */
2784 
2785  /* add all variable whose best bound changes increased the pseudo objective value above to cutoff bound */
2786  SCIP_CALL( resolvePropagation(scip, propdata, cutoffbound, NULL, -1, SCIP_BOUNDTYPE_UPPER, NULL) );
2787 
2788  /* analyze the conflict */
2789  SCIP_CALL( SCIPanalyzeConflict(scip, 0, NULL) );
2790  }
2791  (*result) = SCIP_CUTOFF;
2792 
2793  return SCIP_OKAY;
2794  }
2795 
2796  SCIPdebugMessage("propagating pseudo objective function (pseudoobj: %g, cutoffbound: %g)\n", pseudoobjval, cutoffbound);
2797 
2798  /* propagate binary variables */
2799  SCIP_CALL( propagateCutoffboundBinvars(scip, prop, cutoffbound, pseudoobjval, &nchgbds, &cutoff) );
2800 
2801  if( cutoff )
2802  {
2803  (*result) = SCIP_CUTOFF;
2804  return SCIP_OKAY;
2805  }
2806 
2807  /* tighten domains of none binary variables, if they would increase the pseudo objective value above the cutoff
2808  * bound
2809  */
2810  if( propdata->propfullinroot && SCIPgetDepth(scip) == 0 )
2811  {
2812  SCIP_VAR** objintvars;
2813  SCIP_VAR* var;
2814  SCIP_Real objval;
2815  int nobjintvars;
2816  int v;
2817 
2818  objintvars = propdata->objintvars;
2819  nobjintvars = propdata->nobjintvars;
2820  assert(nobjintvars == 0 || objintvars != NULL);
2821 
2822  /* propagate all none binary variables */
2823  for( v = 0; v < nobjintvars; ++v )
2824  {
2825  var = objintvars[v];
2826  assert(var != NULL);
2827 
2828  objval = SCIPvarGetObj(var);
2829  assert(!SCIPisZero(scip, objval));
2830 
2831  /* try to tighten the bound of the variable */
2832  SCIP_CALL( propagateCutoffboundVar(scip, NULL, var, -1, objval, cutoffbound, pseudoobjval, FALSE, &tightened) );
2833 
2834  /* check if the domain of the variable was reduced */
2835  if( tightened )
2836  nchgbds++;
2837  }
2838  }
2839  else
2840  {
2841  SCIP_VAR** objintvars;
2842  SCIP_VAR* var;
2843  SCIP_Real objval;
2844  int nobjintvars;
2845  int nmaxuseless;
2846  int nuseless;
2847  int c;
2848  int v;
2849 
2850  objintvars = propdata->objintvars;
2851  nobjintvars = propdata->nobjintvars;
2852  assert(nobjintvars == 0 || objintvars != NULL);
2853 
2854  /* compute maximum number of useless propagations before aborting */
2855  nmaxuseless = MAX(propdata->minuseless, (int)propdata->maxvarsfrac*(nobjintvars));
2856 
2857  nuseless = 0;
2858  v = propdata->lastvarnum;
2859 
2860  for( c = 0; c < nobjintvars && nuseless < nmaxuseless; ++c )
2861  {
2862  v++;
2863  if( v >= nobjintvars )
2864  v = 0;
2865 
2866  var = objintvars[v];
2867  assert(var != NULL);
2868 
2869  objval = SCIPvarGetObj(var);
2870  assert(!SCIPisZero(scip, objval));
2871 
2872  /* try to tighten the bound of the variable */
2873  SCIP_CALL( propagateCutoffboundVar(scip, prop, var, -1, objval, cutoffbound, pseudoobjval, TRUE, &tightened) );
2874 
2875  /* check if the domain of the variable was reduced */
2876  if( tightened )
2877  nchgbds++;
2878  else
2879  nuseless++;
2880  }
2881  propdata->lastvarnum = v;
2882  }
2883 
2884  /* check if we chanced bounds */
2885  if( nchgbds > 0 )
2886  (*result) = SCIP_REDUCEDDOM;
2887 
2888  return SCIP_OKAY;
2889 }
2890 
2891 /** recalculates the maximum objective pseudoactivity */
2892 static
2894  SCIP* scip, /**< SCIP data structure */
2895  SCIP_PROPDATA* propdata /**< propagator data */
2896  )
2897 {
2898  SCIP_VAR** vars;
2899  SCIP_Real objval;
2900  SCIP_Real contrib;
2901  int nvars;
2902  int v;
2903 
2904  assert(propdata != NULL);
2905 
2906  /* get problem variables */
2907  vars = SCIPgetVars(scip);
2908  nvars = SCIPgetNVars(scip);
2909 
2910  /* calculate current max pseudo activity and largest contribution */
2911  propdata->maxpseudoobjact = 0.0;
2912  propdata->maxpseudoobjactinf = 0;
2913 
2914  for( v = 0; v < nvars; ++v )
2915  {
2916  objval = SCIPvarGetObj(vars[v]);
2917  if( SCIPisPositive(scip, objval) )
2918  {
2919  contrib = SCIPvarGetUbGlobal(vars[v]);
2920  if( !SCIPisInfinity(scip, contrib) )
2921  contrib *= objval;
2922  }
2923  else if( SCIPisNegative(scip, objval) )
2924  {
2925  contrib = SCIPvarGetLbGlobal(vars[v]);
2926  if( !SCIPisInfinity(scip, -contrib) )
2927  contrib *= objval;
2928  else
2929  contrib *= -1.0;
2930  }
2931  else
2932  continue;
2933 
2934  if( SCIPisInfinity(scip, contrib) )
2935  propdata->maxpseudoobjactinf++;
2936  else
2937  propdata->maxpseudoobjact += contrib;
2938  }
2939 }
2940 
2941 /** updates the pseudo objective activity if necessary */
2942 static
2944  SCIP* scip, /**< SCIP data structure */
2945  SCIP_PROPDATA* propdata /**< propagator data */
2946  )
2947 {
2948  assert(propdata != NULL);
2950  /* if necessary, calculate the maximum pseudo objective activity */
2951  if( propdata->maxpseudoobjact == SCIP_INVALID ) /*lint !e777*/
2952  calcMaxObjPseudoactivity(scip, propdata);
2953  assert(propdata->maxpseudoobjact != SCIP_INVALID); /*lint !e777*/
2954 }
2955 
2956 /** returns the residual pseudo objective activity without the given value */
2957 static
2959  SCIP* scip, /**< SCIP data structure */
2960  SCIP_PROPDATA* propdata, /**< propagator data */
2961  SCIP_Real contrib /**< value to eliminate from pseudo objective activity */
2962  )
2963 {
2964  SCIP_Real residual;
2965 
2966  assert(propdata != NULL);
2967 
2968  /* if necessary, calculate the maximum pseudo objective activity */
2969  if( propdata->maxpseudoobjact == SCIP_INVALID ) /*lint !e777*/
2970  calcMaxObjPseudoactivity(scip, propdata);
2971  assert(propdata->maxpseudoobjact != SCIP_INVALID); /*lint !e777*/
2972 
2973  if( SCIPisInfinity(scip, contrib) )
2974  {
2975  assert(propdata->maxpseudoobjactinf >= 1);
2976  /* check if this variable yields the only infinite contribution */
2977  if( propdata->maxpseudoobjactinf == 1 )
2978  residual = propdata->maxpseudoobjact;
2979  else
2980  residual = SCIPinfinity(scip);
2981  }
2982  else
2983  {
2984  /* check if there is an infinite contribution */
2985  if( propdata->maxpseudoobjactinf >= 1 )
2986  residual = SCIPinfinity(scip);
2987  else
2988  residual = propdata->maxpseudoobjact - contrib;
2989  }
2990 
2991  return residual;
2992 }
2993 
2994 /** returns the residual pseudo objective activity */
2995 static
2997  SCIP* scip, /**< SCIP data structure */
2998  SCIP_PROPDATA* propdata, /**< propagator data */
2999  SCIP_VAR* var /**< variable to get residual activity for */
3000  )
3001 {
3002  SCIP_Real objval;
3003  SCIP_Real contrib;
3004 
3005  assert(propdata != NULL);
3006 
3007  contrib = 0.0;
3008  objval = SCIPvarGetObj(var);
3010  {
3011  contrib = SCIPvarGetUbGlobal(var);
3012  if( !SCIPisInfinity(scip, contrib) )
3013  contrib *= objval;
3014  }
3015  else
3016  {
3018  contrib = SCIPvarGetLbGlobal(var);
3019  if( !SCIPisInfinity(scip, -contrib) )
3020  contrib *= objval;
3021  else
3022  contrib *= -1.0;
3023  }
3024 
3025  return getMaxObjPseudoactivityResidualValue(scip, propdata, contrib);
3026 }
3027 
3028 /** returns the maximum pseudo objective activity of the objective function */
3029 static
3031  SCIP* scip, /**< SCIP data structure */
3032  SCIP_PROPDATA* propdata /**< propagator data */
3033  )
3034 {
3035  return getMaxObjPseudoactivityResidualValue(scip, propdata, 0.0);
3037 
3038 /** propagates the global domain of the given binary variable against the lower bound (c*x >= lowerbound) */
3039 static
3041  SCIP* scip, /**< SCIP data structure */
3042  SCIP_VAR* var, /**< variable to propagate */
3043  SCIP_Real lowerbound, /**< lower bound to use */
3044  SCIP_Real maxpseudoobjact, /**< maximum pseudo objective activity */
3045  SCIP_Bool useimplics, /**< should implications be used */
3046  SCIP_Bool* infeasible, /**< pointer to store if the variable domain got empty, infeasible */
3047  SCIP_Bool* tightened /**< pointer to store if the variable domain was tightened */
3048  )
3049 {
3050  SCIP_Real lbobjchg;
3051  SCIP_Real ubobjchg;
3052 
3053  assert(SCIPvarIsBinary(var));
3054  assert(SCIPisLE(scip, lowerbound, maxpseudoobjact));
3055  assert(!SCIPisInfinity(scip, maxpseudoobjact));
3056 
3057  /*@todo Instead of running always over all implications use SCIP_OBJIMPLICS in the same way as for the propagation of
3058  * the minimum activity against the cutoff bound. If so we could use the cliques as well.
3059  */
3060 
3061  /* get contribution of variable by fixing it to its lower bound w.r.t. maximum activity of the objective function */
3062  SCIP_CALL( getMaxactObjchg(scip, var, SCIP_BOUNDTYPE_LOWER, useimplics, &lbobjchg) );
3063  assert(!SCIPisPositive(scip, lbobjchg));
3064 
3065  /* get contribution of variable by fixing it to its upper bound w.r.t. maximum activity of the objective function */
3066  SCIP_CALL( getMaxactObjchg(scip, var, SCIP_BOUNDTYPE_UPPER, useimplics, &ubobjchg) );
3067  assert(!SCIPisPositive(scip, ubobjchg));
3068 
3069  (*infeasible) = FALSE;
3070  (*tightened) = FALSE;
3071 
3072  /* if the maximum activity of the objective function without the contribution of the given variable shrinks below the
3073  * global lower bound, the contribution of the variable is need; hence, we can fix it to corresponding bound globally
3074  */
3075  if( SCIPisFeasLT(scip, maxpseudoobjact + lbobjchg, lowerbound) && SCIPisFeasLT(scip, maxpseudoobjact + ubobjchg, lowerbound) )
3076  {
3077  /* fixing the variable to zero or one leads to decreases of the maximum activity below the lower bound, hence, we
3078  * detected an cutoff
3079  */
3080  (*infeasible) = TRUE;
3081  }
3082  else if( SCIPisFeasLT(scip, maxpseudoobjact + lbobjchg, lowerbound) )
3083  {
3084  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, 1.0, FALSE, infeasible, tightened) );
3085  }
3086  else if( SCIPisFeasLT(scip, maxpseudoobjact + ubobjchg, lowerbound) )
3087  {
3088  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, 0.0, FALSE, infeasible, tightened) );
3089  }
3090 
3091  return SCIP_OKAY;
3092 }
3093 
3094 /** propagates the global domains of the given variable with non-zero objective coefficient against the lower bound
3095  * (c*x >= lowerbound)
3096  */
3097 static
3099  SCIP* scip, /**< SCIP data structure */
3100  SCIP_PROPDATA* propdata, /**< propagator data */
3101  SCIP_VAR* var, /**< variable to propagate */
3102  SCIP_Real lowerbound, /**< lower bound to use */
3103  SCIP_Bool* infeasible, /**< pointer to store if the variable domain got empty, infeasible */
3104  SCIP_Bool* tightened /**< pointer to store if the variable domain was tightened */
3105  )
3106 {
3107  SCIP_Real residual;
3108  SCIP_Real newbd;
3109  SCIP_Real objval;
3110 
3111  objval = SCIPvarGetObj(var);
3112  assert(!SCIPisZero(scip, objval));
3113 
3114  (*tightened) = FALSE;
3115 
3116  /* get residual pseudo objective activity, that is the pseudo objective activity without the given variable */
3117  residual = getMaxObjPseudoactivityResidual(scip, propdata, var);
3118 
3119  if( SCIPisInfinity(scip, residual) )
3120  return SCIP_OKAY;
3121 
3122  /* compute potential mew bound */
3123  newbd = (lowerbound - residual) / objval;
3124 
3125  /**@note In case the variable is integral we force the update of the new bound */
3126 
3127  if( objval > 0.0 )
3128  {
3129  SCIP_Real lb;
3130 
3131  lb = SCIPvarGetLbGlobal(var);
3132 
3133  if( !SCIPvarIsIntegral(var) )
3134  {
3135  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, newbd, FALSE, infeasible, tightened) );
3136  }
3137  else if( SCIPisFeasGT(scip, newbd, lb) )
3138  {
3139  SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, newbd, TRUE, infeasible, tightened) );
3140  }
3141  }
3142  else
3143  {
3144  SCIP_Real ub;
3145 
3146  ub = SCIPvarGetUbGlobal(var);
3147 
3148  if( !SCIPvarIsIntegral(var) )
3149  {
3150  SCIP_CALL( SCIPtightenVarUbGlobal(scip, var, newbd, FALSE, infeasible, tightened) );
3151  }
3152  else if( SCIPisFeasLT(scip, newbd, ub) )
3153  {
3154  SCIP_CALL( SCIPtightenVarUbGlobal(scip, var, newbd, TRUE, infeasible, tightened) );
3155  }
3156  }
3157 
3158  return SCIP_OKAY;
3159 }
3160 
3161 /** propagates the global lower (dual) bound c*x >= lowerbound */
3162 static
3164  SCIP* scip, /**< SCIP data structure */
3165  SCIP_PROP* prop, /**< propagator */
3166  SCIP_RESULT* result /**< pointer to store the result of the callback method */
3167  )
3168 { /*lint --e{715}*/
3169  SCIP_PROPDATA* propdata;
3170  SCIP_Real lowerbound;
3171  SCIP_Real maxpseudoobjact;
3172  SCIP_Bool cutoff;
3173  int nchgbds;
3174 
3175  assert(result != NULL);
3176 
3177  (*result) = SCIP_DIDNOTRUN;
3178  cutoff = FALSE;
3179  nchgbds = 0;
3180 
3181  propdata = SCIPpropGetData(prop);
3182  assert(propdata != NULL);
3183  assert(propdata->nminactvars > 0 || propdata->nobjintvars > 0);
3184 
3185  /* check if there is a chance to find a reduction */
3186  lowerbound = SCIPgetLowerbound(scip);
3187 
3188  if( SCIPisInfinity(scip, -lowerbound) )
3189  return SCIP_OKAY;
3190 
3191  /* if the lower bound did not change since the last propagation as well as the global bounds of the variables with a
3192  * non-zero objective coefficient we do nothing since there is no new information available
3193  */
3194  if( SCIPisLE(scip, lowerbound, propdata->lastlowerbound) && propdata->maxpseudoobjact < SCIP_INVALID )
3195  return SCIP_OKAY;
3196 
3197  /* updates the pseudo objective activity if necessary */
3198  updateMaxObjPseudoactivity(scip, propdata);
3199 
3200  /* if more than one variable contributes an infinity to the maximal pseudo activity we can do nothing */
3201  assert(propdata->maxpseudoobjact < SCIP_INVALID);
3202  if( propdata->maxpseudoobjactinf > 1 )
3203  return SCIP_OKAY;
3204 
3205  maxpseudoobjact = getMaxObjPseudoactivity(scip, propdata);
3206  assert(!SCIPisInfinity(scip, maxpseudoobjact) || !SCIPisInfinity(scip, lowerbound));
3207 
3208 #ifndef NDEBUG
3209  /* check that the global indices are correct */
3210  checkGlbfirstnonfixed(scip, propdata);
3211 #endif
3212 
3213  /* if the maximum pseudo objective activity is smaller than the lower bound the problem is infeasible */
3214  if( SCIPisLT(scip, maxpseudoobjact, lowerbound) )
3215  cutoff = TRUE;
3216  else
3217  {
3218  SCIP_VAR** objintvars;
3219  SCIP_VAR* var;
3220  SCIP_Bool tightened;
3221  int nobjintvars;
3222  int v;
3223 
3224  if( propdata->maxpseudoobjactinf == 0 && !SCIPisInfinity(scip, maxpseudoobjact) )
3225  {
3226  SCIP_VAR** maxactvars;
3227  int nmaxactvars;
3228 
3229  maxactvars = propdata->maxactvars;
3230  nmaxactvars = propdata->nmaxactvars;
3231  assert(nmaxactvars == 0 || maxactvars != NULL);
3232 
3233  for( v = propdata->maxactfirstnonfixed; v < nmaxactvars; ++v )
3234  {
3235  var = maxactvars[v];
3236  assert(var != NULL);
3237  assert(SCIPvarIsBinary(var));
3238 
3239  /* check if the variables is already globally fixed; if so continue with the next potential candidate */
3240  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
3241  continue;
3242 
3243  /* try to propagate variable domain globally */
3244  SCIP_CALL( propagateLowerboundBinvar(scip, var, lowerbound, maxpseudoobjact, propdata->propuseimplics, &cutoff, &tightened) );
3245 
3246  /* the binary variables are sorted in non-increasing manner w.r.t. the absolute value of their objective
3247  * contribution w.r.t. maximum activity of the objective function; These values are the decrease we would
3248  * get with the maximum pseudo objective activity if we fix the variable to its best bound; hence, we can
3249  * stop if for a variable this potential decrease is not enough anymore too fall below the lower bound.
3250  *
3251  * @note In case a fixing was performed. The variable might not be globally fixed right away since this would
3252  * destroy the local internal data structure of a search node; the bound change is in that case pending;
3253  * hence we cannot assert that the variable is globally fixed
3254  */
3255  if( !tightened )
3256  {
3257  assert(!SCIPisInfinity(scip, propdata->maxpseudoobjact));
3258  SCIPdebugMessage("interrupt pseudo objective propagation w.r.t. lower bound <%.15g> for binary variables after %d from %d binary variables\n",
3259  lowerbound, v, nmaxactvars);
3260  break;
3261  }
3262 
3263  if( cutoff )
3264  break;
3265 
3266  /* update maximum pseudo activity since the previous global bound change might invalidated the maximum
3267  * pseudo activity
3268  */
3269  maxpseudoobjact = getMaxObjPseudoactivity(scip, propdata);
3270  nchgbds++;
3271  }
3272 
3273  /* update globally fixed index if abort criteria was applied */
3274  propdata->maxactfirstnonfixed = v;
3275 
3276  /* check all binary variables which could potentially be fixed */
3277  for( ; v < nmaxactvars && maxpseudoobjact - lowerbound < propdata->maxactchgs[v] && !cutoff; ++v )
3278  {
3279  var = maxactvars[v];
3280  assert(var != NULL);
3281  assert(SCIPvarIsBinary(var));
3282 
3283  /* check if the variables is already globally fixed; if so continue with the potential candidate */
3284  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
3285  continue;
3286 
3287  /* propagates the cutoff bound for the given binary variable */
3288  SCIP_CALL( propagateLowerboundBinvar(scip, var, lowerbound, maxpseudoobjact, propdata->propuseimplics, &cutoff, &tightened) );
3289 
3290  if( tightened )
3291  {
3292  /* update maximum pseudo activity since the previous global bound change might invalidated the maximum
3293  * pseudo activity
3294  */
3295  maxpseudoobjact = getMaxObjPseudoactivity(scip, propdata);
3296  nchgbds++;
3297  }
3298  }
3299 
3300 #if 0 /* might fail, but is not a real error, still need to investigate */
3301 #ifndef NDEBUG
3302  /* check that the abort criteria for the binary variables works */
3303  for( ; v < nmaxactvars && !cutoff; ++v )
3304  {
3305  var = maxactvars[v];
3306  assert(var != NULL);
3307  assert(SCIPvarIsBinary(var));
3308 
3309  /* check if the variables is already globally fixed; if so continue with the next potential candidate */
3310  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5)
3311  continue;
3312 
3313  /* try to propagate variable domain globally */
3314  SCIP_CALL( propagateLowerboundBinvar(scip, var, lowerbound, maxpseudoobjact, propdata->propuseimplics, &cutoff, &tightened) );
3315  assert(!tightened);
3316  assert(!cutoff);
3317  }
3318 #endif
3319 #endif
3320  }
3321 
3322  objintvars = propdata->objintvars;
3323  nobjintvars = propdata->nobjintvars;
3324  assert(nobjintvars == 0 || objintvars != NULL);
3325 
3326  /* propagate c*x >= lowerbound for non-binary variables */
3327  for( v = 0; v < nobjintvars && !cutoff; ++v )
3328  {
3329  var = objintvars[v];
3330  assert(var != NULL);
3331  assert(!SCIPisZero(scip, SCIPvarGetObj(var)));
3332 
3333  /* try to propagate variable domain globally */
3334  SCIP_CALL( propagateLowerboundVar(scip, propdata, var, lowerbound, &cutoff, &tightened) );
3335 
3336  if( tightened )
3337  nchgbds++;
3338  }
3339  }
3340 
3341  /* evaluate propagation results */
3342  if( cutoff )
3343  {
3344  /* we are done with solving since a global bound change is infeasible: cutoff root node */
3345  SCIP_CALL( SCIPcutoffNode(scip, SCIPgetRootNode(scip)) );
3346  (*result) = SCIP_CUTOFF;
3347  }
3348  else if( nchgbds > 0 )
3349  (*result) = SCIP_REDUCEDDOM;
3350 
3351  /* remember the lower bound which we already propagated */
3352  propdata->lastlowerbound = lowerbound;
3353 
3354  return SCIP_OKAY;
3355 }
3356 
3357 
3358 /*
3359  * Callback methods of propagator
3360  */
3361 
3362 /** copy method for propagator plugins (called when SCIP copies plugins) */
3363 static
3364 SCIP_DECL_PROPCOPY(propCopyPseudoobj)
3365 { /*lint --e{715}*/
3366  assert(scip != NULL);
3367  assert(prop != NULL);
3368  assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
3369 
3370  /* call inclusion method of propagator */
3372 
3373  return SCIP_OKAY;
3374 }
3375 
3376 /** destructor of propagator to free user data (called when SCIP is exiting) */
3377 static
3378 SCIP_DECL_PROPFREE(propFreePseudoobj)
3379 { /*lint --e{715}*/
3380  SCIP_PROPDATA* propdata;
3381 
3382  /* free propagator data */
3383  propdata = SCIPpropGetData(prop);
3384  SCIPfreeMemory(scip, &propdata);
3385  SCIPpropSetData(prop, NULL);
3386 
3387  return SCIP_OKAY;
3388 }
3389 
3390 
3391 /** solving process initialization method of propagator (called when branch and bound process is about to begin) */
3392 static
3393 SCIP_DECL_PROPINITSOL(propInitsolPseudoobj)
3394 {
3395  SCIP_PROPDATA* propdata;
3396 
3397  propdata = SCIPpropGetData(prop);
3398  assert(propdata != NULL);
3400  /* do nothing if active pricer are present and force flag is not TRUE */
3401  if( !propdata->force && SCIPgetNActivePricers(scip) > 0 )
3402  return SCIP_OKAY;
3403 
3404  /* if active pricer are present we want to catch the variable added event */
3405  if( SCIPgetNActivePricers(scip) > 0 )
3406  {
3407  assert(!propdata->catchvaradded);
3408  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_VARADDED, propdata->eventhdlr, (SCIP_EVENTDATA*)propdata, NULL) );
3409  propdata->catchvaradded = TRUE;
3410  }
3411 
3412  return SCIP_OKAY;
3413 }
3414 
3415 /** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
3416 static
3417 SCIP_DECL_PROPEXITSOL(propExitsolPseudoobj)
3418 { /*lint --e{715}*/
3419  SCIP_PROPDATA* propdata;
3420 
3421  propdata = SCIPpropGetData(prop);
3422  assert(propdata != NULL);
3424  if( propdata->catchvaradded )
3425  {
3426  /* drop the variable added event */
3427  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_VARADDED, propdata->eventhdlr, (SCIP_EVENTDATA*)propdata, -1) );
3428  propdata->catchvaradded = FALSE;
3429  }
3430 
3431  /* free propagator data */
3432  SCIP_CALL( propdataExit(scip, propdata) );
3433 
3434  return SCIP_OKAY;
3435 }
3436 
3437 
3438 /** presolving method of propagator */
3439 static
3440 SCIP_DECL_PROPPRESOL(propPresolPseudoobj)
3441 { /*lint --e{715}*/
3442 
3443  SCIP_PROPDATA* propdata;
3444  SCIP_VAR** vars;
3445  SCIP_Real cutoffbound;
3446  SCIP_Real pseudoobjval;
3447  int oldnchgbds;
3448  int nvars;
3449  int v;
3450 
3451  assert(result != NULL);
3452 
3453  propdata = SCIPpropGetData(prop);
3454  assert(propdata != NULL);
3455 
3456  (*result) = SCIP_DIDNOTRUN;
3457 
3458  /* do nothing if active pricer are present and force flag is not TRUE */
3459  if( !propdata->force && SCIPgetNActivePricers(scip) > 0 )
3460  return SCIP_OKAY;
3461 
3462  /* do nothing if objective propagation is not allowed */
3463  if( !SCIPallowObjProp(scip) )
3464  return SCIP_OKAY;
3465 
3466  pseudoobjval = SCIPgetGlobalPseudoObjval(scip);
3467  if( SCIPisInfinity(scip, -pseudoobjval) )
3468  return SCIP_OKAY;
3469 
3470  cutoffbound = SCIPgetCutoffbound(scip);
3471  if( SCIPisInfinity(scip, cutoffbound) )
3472  return SCIP_OKAY;
3473 
3474  if( SCIPisGE(scip, pseudoobjval, cutoffbound) )
3475  {
3476  (*result) = SCIP_CUTOFF;
3477  return SCIP_OKAY;
3478  }
3479 
3480  /* only propagate if a new cutoff bound or global pseudo objective value is available */
3481  if( cutoffbound < propdata->cutoffbound || pseudoobjval > propdata->glbpseudoobjval )
3482  {
3483  SCIP_Real objval;
3484  SCIP_Bool tightened;
3485 
3486  (*result) = SCIP_DIDNOTFIND;
3487  oldnchgbds = *nchgbds;
3488 
3489  /* get the problem variables */
3490  vars = SCIPgetVars(scip);
3491  nvars = SCIPgetNVars(scip);
3492 
3493  /* scan the variables for pseudoobj bound reductions
3494  * (loop backwards, since a variable fixing can change the current and the subsequent slots in the vars array)
3495  */
3496  for( v = nvars - 1; v >= 0; --v )
3497  {
3498  objval = SCIPvarGetObj(vars[v]);
3499 
3500  if( SCIPisZero(scip, objval) )
3501  continue;
3502 
3503  SCIP_CALL( propagateCutoffboundVar(scip, NULL, vars[v], -1, objval, cutoffbound, pseudoobjval, FALSE, &tightened) );
3504 
3505  if( tightened )
3506  (*nchgbds)++;
3507  }
3508 
3509  /* evaluate if bound change was detected */
3510  if( *nchgbds > oldnchgbds )
3511  (*result) = SCIP_SUCCESS;
3512 
3513  /* store the old values */
3514  propdata->cutoffbound = cutoffbound;
3515  propdata->glbpseudoobjval = pseudoobjval;
3516  propdata->glbpropagated = TRUE;
3517  }
3518 
3519  return SCIP_OKAY;
3520 }
3521 
3522 /** execution method of propagator */
3523 static
3524 SCIP_DECL_PROPEXEC(propExecPseudoobj)
3525 { /*lint --e{715}*/
3526  SCIP_PROPDATA* propdata;
3527 
3528  propdata = SCIPpropGetData(prop);
3529  assert(propdata != NULL);
3531  (*result) = SCIP_DIDNOTRUN;
3532 
3533  if( SCIPinProbing(scip) )
3534  return SCIP_OKAY;
3535 
3536  if( proptiming == SCIP_PROPTIMING_DURINGLPLOOP && SCIPgetDepth(scip) != 0 )
3537  return SCIP_OKAY;
3538 
3539  /* do nothing if active pricer are present and force flag is not TRUE */
3540  if( !propdata->force && SCIPgetNActivePricers(scip) > 0 )
3541  return SCIP_OKAY;
3542 
3543  /* do not run if propagation w.r.t. objective is not allowed */
3544  if( !SCIPallowObjProp(scip) )
3545  return SCIP_OKAY;
3546 
3547  /* check if enough new variable are added (due to column generatition to reinitialized the propgator data) */
3548  if( !propdata->initialized || propdata->nnewvars > propdata->maxnewvars )
3549  {
3550  /* free current propdata data */
3551  SCIP_CALL( propdataExit(scip, propdata) );
3552 
3553  /* initialize propdata data from scratch */
3554  SCIP_CALL( propdataInit(scip, propdata) );
3555  }
3556 
3557  /* nothing to do for zero objective */
3558  if( propdata->nminactvars == 0 && propdata->nmaxactvars == 0 && propdata->nobjintvars == 0 )
3559  return SCIP_OKAY;
3560 
3561  /* propagate c*x <= cutoff */
3562  SCIP_CALL( propagateCutoffbound(scip, prop, result) );
3563 
3564  if( (*result) != SCIP_CUTOFF && (propdata->nmaxactvars > 0 || propdata->nobjintvars > 0) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3565  {
3566  SCIP_RESULT dualresult;
3567 
3568  /* propagates the global lower (dual) bound c*x >= lowerbound */
3569  SCIP_CALL( propagateLowerbound(scip, prop, &dualresult) );
3570 
3571  if( dualresult == SCIP_REDUCEDDOM || dualresult == SCIP_CUTOFF )
3572  (*result) = dualresult;
3573  }
3574 
3575  return SCIP_OKAY;
3576 }
3577 
3578 /** propagation conflict resolving method of propagator */
3579 static
3580 SCIP_DECL_PROPRESPROP(propRespropPseudoobj)
3581 { /*lint --e{715}*/
3582  SCIP_PROPDATA* propdata;
3583  SCIP_Real cutoffbound;
3584 
3585  assert(!SCIPisEQ(scip, SCIPvarGetLbGlobal(infervar), SCIPvarGetUbGlobal(infervar)));
3587  propdata = SCIPpropGetData(prop);
3588  assert(propdata != NULL);
3589 
3590  cutoffbound = SCIPgetCutoffbound(scip);
3591  assert(!SCIPisInfinity(scip, cutoffbound));
3592  assert(infervar != NULL);
3593 
3594  SCIPdebugMessage("resolve bound change <%s> %s <%g>(%g), cutoff bound <%g>\n", SCIPvarGetName(infervar),
3595  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", SCIPvarGetLbAtIndex(infervar, bdchgidx, TRUE),
3596  SCIPvarGetLbAtIndex(infervar, bdchgidx, FALSE), cutoffbound);
3597 
3598  /* resolve the propagation of the inference variable w.r.t. required minactivity */
3599  SCIP_CALL( resolvePropagation(scip, propdata, cutoffbound, infervar, inferinfo, boundtype, bdchgidx) );
3600 
3601  (*result) = SCIP_SUCCESS;
3602 
3603  return SCIP_OKAY;
3604 }
3605 
3606 
3607 /*
3608  * Event handler
3609  */
3610 
3611 /** execution method of bound change event handler */
3612 static
3613 SCIP_DECL_EVENTEXEC(eventExecPseudoobj)
3614 { /*lint --e{715}*/
3615  SCIP_PROPDATA* propdata;
3616  SCIP_EVENTTYPE eventtype;
3617 
3618  propdata = (SCIP_PROPDATA*)eventdata;
3619  assert(propdata != NULL);
3620 
3621  assert(eventhdlr != NULL);
3622  assert(eventdata != NULL);
3623  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
3624  assert(event != NULL);
3625 
3626  eventtype = SCIPeventGetType(event);
3627 
3628  switch( eventtype )
3629  {
3632  /* if bound got relaxed we need to start up front for trial of bound tightening */
3633  propdata->firstnonfixed = 0;
3634  break;
3636  propdata->nnewvars++;
3637  break;
3638  default:
3639  assert(eventtype == SCIP_EVENTTYPE_GLBCHANGED || eventtype == SCIP_EVENTTYPE_GUBCHANGED);
3640 
3641  /* invalidate the maximum pseudo objective activity */
3642  propdata->maxpseudoobjact = SCIP_INVALID;
3643  propdata->maxpseudoobjactinf = 0;
3644  }
3645 
3646  return SCIP_OKAY;
3647 }
3648 
3649 
3650 /*
3651  * propagator specific interface methods
3652  */
3653 
3654 /** creates the pseudo objective function propagator and includes it in SCIP */
3656  SCIP* scip /**< SCIP data structure */
3657  )
3658 {
3659  SCIP_PROPDATA* propdata;
3660  SCIP_PROP* prop;
3662 
3663  /* create pseudoobj propagator data */
3664  SCIP_CALL( SCIPallocMemory(scip, &propdata) );
3665 
3666  /* reset propagator data structure */
3667  propdataReset(scip, propdata);
3668 
3669  propdata->eventhdlr = NULL;
3670  /* include event handler for gloabl bound change events and variable added event (in case of pricing) */
3671  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &propdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC,
3672  eventExecPseudoobj, NULL) );
3673 
3674  if( propdata->eventhdlr == NULL )
3675  {
3676  SCIPerrorMessage("event handler for pseudo objective propagator not found\n");
3677  return SCIP_PLUGINNOTFOUND;
3678  }
3679 
3680  /* include propagator */
3682  propExecPseudoobj,
3683  propdata) );
3684  assert(prop != NULL);
3685 
3686  /* set optional callbacks via setter functions */
3687  SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyPseudoobj) );
3688  SCIP_CALL( SCIPsetPropFree(scip, prop, propFreePseudoobj) );
3689  SCIP_CALL( SCIPsetPropInitsol(scip, prop, propInitsolPseudoobj) );
3690  SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolPseudoobj) );
3692  SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropPseudoobj) );
3693 
3694  /* add pseudoobj propagator parameters */
3695  SCIP_CALL( SCIPaddIntParam(scip,
3696  "propagating/" PROP_NAME "/minuseless",
3697  "minimal number of successive none binary variable propagator whithout a bound reduction before aborted",
3698  &propdata->minuseless, TRUE, DEFAULT_MINUSELESS, 0, INT_MAX, NULL, NULL) );
3699 
3701  "propagating/" PROP_NAME "/maxvarsfrac",
3702  "maximal fraction of none binary variables with non-zero objective without a bound reduction before aborted",
3703  &propdata->maxvarsfrac, TRUE, DEFAULT_MAXVARSFRAC, 0.0, 1.0, NULL, NULL) );
3704 
3706  "propagating/" PROP_NAME "/propfullinroot",
3707  "do we want to propagate all none binary variables if we are propagating the root node",
3708  &propdata->propfullinroot, TRUE, DEFAULT_PROPFULLINROOT, NULL, NULL) );
3709 
3711  "propagating/" PROP_NAME "/propcutoffbound",
3712  "propagate new cutoff bound directly globally",
3713  &propdata->propcutoffbound, TRUE, DEFAULT_PROPCUTOFFBOUND, NULL, NULL) );
3714 
3716  "propagating/" PROP_NAME "/force",
3717  "should the propagator be forced even active pricer are present?",
3718  &propdata->force, TRUE, DEFAULT_FORCE, NULL, NULL) );
3719 
3720  SCIP_CALL( SCIPaddIntParam(scip,
3721  "propagating/" PROP_NAME "/maxnewvars",
3722  "number of variable added after the propgatore is reinitialized?",
3723  &propdata->maxnewvars, TRUE, DEFAULT_MAXNEWVARS, 0, INT_MAX, NULL, NULL) );
3724 
3726  "propagating/" PROP_NAME "/propuseimplics",
3727  "use implications to strengthen the propagation of binary variable (increasing the objective change)?",
3728  &propdata->propuseimplics, TRUE, DEFAULT_PROPUSEIMPLICS, NULL, NULL) );
3729 
3731  "propagating/" PROP_NAME "/respropuseimplics",
3732  "use implications to strengthen the resolve propagation of binary variable (increasing the objective change)?",
3733  &propdata->respropuseimplics, TRUE, DEFAULT_RESPROPUSEIMPLICS, NULL, NULL) );
3734 
3735  SCIP_CALL( SCIPaddIntParam(scip,
3736  "propagating/" PROP_NAME "/maximplvars",
3737  "maximum number of binary variables the implications are used if turned on (-1: unlimited)?",
3738  &propdata->maximplvars, TRUE, DEFAULT_MAXIMPLVARS, -1, INT_MAX, NULL, NULL) );
3739 
3740  return SCIP_OKAY;
3741 }
3742 
3743 /** propagates the cutoff bound for the given variables */
3745  SCIP* scip, /**< SCIP data structure */
3746  SCIP_PROP* prop, /**< propagator, or NULL */
3747  SCIP_VAR* var, /**< variables to propagate */
3748  SCIP_Real cutoffbound, /**< cutoff bound to use */
3749  SCIP_Real pseudoobjval, /**< pseudo objective value to use */
3750  SCIP_Bool* tightened /**< pointer to if the domain was tightened */
3751  )
3752 {
3753  SCIP_Real objval;
3754 
3755  objval = SCIPvarGetObj(var);
3756 
3757  SCIP_CALL( propagateCutoffboundVar(scip, prop, var, -1, objval, cutoffbound, pseudoobjval, TRUE, tightened) );
3758 
3759  return SCIP_OKAY;
3760 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:51
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17250
SCIP_RETCODE SCIPsetPropExitsol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPEXITSOL((*propexitsol)))
Definition: scip.c:6994
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41180
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
static SCIP_RETCODE adjustCutoffbound(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, int inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_HASHTABLE *addedvars, SCIP_Real *cutoffbound)
static SCIP_RETCODE getMinactImplicObjchg(SCIP *scip, SCIP_VAR *var, SCIP_OBJIMPLICS *objimplics, SCIP_BDCHGIDX *bdchgidx, SCIP_BOUNDTYPE bound, SCIP_Bool local, SCIP_Real *objchg)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41293
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:10735
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3105
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16341
#define PROP_FREQ
SCIP_VAR ** objvars
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:41256
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1562
#define PROP_PRIORITY
Pseudo objective propagator.
static SCIP_RETCODE propagateLowerbound(SCIP *scip, SCIP_PROP *prop, SCIP_RESULT *result)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16521
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41528
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:10690
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17318
static SCIP_RETCODE propdataExit(SCIP *scip, SCIP_PROPDATA *propdata)
#define NULL
Definition: lpi_spx.cpp:130
static SCIP_RETCODE collectMinactVar(SCIP *scip, SCIP_VAR *var, SCIP_OBJIMPLICS **objimplics, SCIP_Bool useimplics, SCIP_HASHMAP *binobjvarmap, SCIP_Bool *collectedlbvars, SCIP_Bool *collectedubvars, int nbinobjvars, SCIP_VAR **contributors, SCIP_HASHTABLE *uselesscliques, SCIP_Bool *collect)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17011
static SCIP_DECL_PROPINITSOL(propInitsolPseudoobj)
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:16965
#define DEFAULT_MAXNEWVARS
void SCIPsortDownRealPtr(SCIP_Real *realarray, void **ptrarray, int len)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
Definition: scip.c:24307
#define DEFAULT_PROPCUTOFFBOUND
static void updateMaxObjPseudoactivity(SCIP *scip, SCIP_PROPDATA *propdata)
#define SCIP_PROPTIMING_DURINGLPLOOP
Definition: type_timing.h:55
#define FALSE
Definition: def.h:53
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2052
#define DEFAULT_MINUSELESS
SCIP_BOUNDTYPE SCIPvarGetBestBoundType(SCIP_VAR *var)
Definition: var.c:17067
static SCIP_DECL_SORTPTRCOMP(objimplicsComp)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:7747
#define TRUE
Definition: def.h:52
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static SCIP_RETCODE addConflictBinvar(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_OBJIMPLICS *objimplics, SCIP_HASHTABLE *addedvars, SCIP_Bool respropuseimplics, SCIP_Real *reqpseudoobjval)
SCIP_RETCODE SCIPsetPropCopy(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPCOPY((*propcopy)))
Definition: scip.c:6914
static SCIP_RETCODE getMaxactObjchg(SCIP *scip, SCIP_VAR *var, SCIP_BOUNDTYPE bound, SCIP_Bool useimplics, SCIP_Real *objchg)
#define SCIP_EVENTTYPE_GLBCHANGED
Definition: type_event.h:53
int SCIPgetNActivePricers(SCIP *scip)
Definition: scip.c:4986
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
Definition: scip.c:38147
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20385
SCIP_Real SCIPvarGetLbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15695
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_RETCODE SCIPinferVarLbProp(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_PROP *inferprop, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20907
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:20414
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:16803
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2111
SCIP_RETCODE SCIPcutoffNode(SCIP *scip, SCIP_NODE *node)
Definition: scip.c:36726
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:10915
static SCIP_RETCODE propagateCutoffbound(SCIP *scip, SCIP_PROP *prop, SCIP_RESULT *result)
#define PROP_DELAY
static void resetContributors(SCIP_HASHMAP *binobjvarmap, SCIP_Bool *collectedvars, SCIP_VAR **contributors, int ncontributors)
#define DEFAULT_FORCE
static SCIP_Real getMaxObjPseudoactivityResidual(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var)
#define EVENTHDLR_DESC
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11206
SCIP_RETCODE SCIPincludePropPseudoobj(SCIP *scip)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
Definition: scip.c:37979
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:1475
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3516
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2154
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3542
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:56
#define PROP_PRESOLTIMING
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16532
static SCIP_RETCODE addConflictBounds(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real *reqpseudoobjval)
SCIP_RETCODE SCIPanalyzeConflict(SCIP *scip, int validdepth, SCIP_Bool *success)
Definition: scip.c:24676
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:36232
static SCIP_RETCODE collectMinactObjchg(SCIP *scip, SCIP_VAR *var, SCIP_BOUNDTYPE bound, SCIP_HASHMAP *binobjvarmap, SCIP_Bool *collectedvars, int nbinobjvars, SCIP_VAR **contributors, SCIP_HASHTABLE *uselesscliques, int *ncontributors, SCIP_Real *objchg)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip)
Definition: scip.c:24329
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41193
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:20383
static SCIP_RETCODE objimplicsDelPos(SCIP *scip, SCIP_OBJIMPLICS *objimplics, int pos)
SCIP_NODE * SCIPgetRootNode(SCIP *scip)
Definition: scip.c:36408
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:41317
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:20355
SCIP_PROPDATA * SCIPpropGetData(SCIP_PROP *prop)
Definition: prop.c:735
#define SCIPerrorMessage
Definition: pub_message.h:45
static SCIP_RETCODE propagateCutoffboundBinvar(SCIP *scip, SCIP_PROP *prop, SCIP_VAR *var, int pos, SCIP_Real cutoffbound, SCIP_Real pseudoobjval, SCIP_Bool *tightened, SCIP_Bool *cutoff, SCIP_Bool local)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:20426
#define SCIPdebugPrintf
Definition: pub_message.h:80
static SCIP_RETCODE getMaxactImplicObjchg(SCIP *scip, SCIP_VAR *var, SCIP_BOUNDTYPE bound, SCIP_Real *objchg)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:20403
SCIP_Real maxobjchg
void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
int SCIPcalcHashtableSize(int minsize)
Definition: misc.c:1152
SCIP_Real SCIPvarGetUbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15787
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41206
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:40927
static SCIP_RETCODE collectMinactImplicVars(SCIP *scip, SCIP_VAR *var, SCIP_BOUNDTYPE bound, SCIP_HASHMAP *binobjvarmap, SCIP_Bool *collectedvars, int nbinobjvars, SCIP_VAR **contributors, SCIP_HASHTABLE *uselesscliques, int *ncontributors, SCIP_Real *objchg)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41515
#define MAX_CLIQUELENGTH
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:146
static SCIP_DECL_PROPPRESOL(propPresolPseudoobj)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2070
#define PROP_DESC
#define PROP_PRESOL_MAXROUNDS
void SCIPsortDownPtrPtr(void **ptrarray1, void **ptrarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17265
#define REALABS(x)
Definition: def.h:148
#define SCIP_EVENTTYPE_UBRELAXED
Definition: type_event.h:58
#define DEFAULT_PROPUSEIMPLICS
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3204
static SCIP_RETCODE resolvePropagation(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Real cutoffbound, SCIP_VAR *infervar, int inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx)
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:41245
SCIP_Real SCIPgetGlobalPseudoObjval(SCIP *scip)
Definition: scip.c:26530
static SCIP_RETCODE dropObjEvent(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_EVENTHDLR *eventhdlr, SCIP_VAR *var)
#define SCIP_CALL(x)
Definition: def.h:263
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: var.c:10742
static SCIP_DECL_PROPCOPY(propCopyPseudoobj)
void SCIPhashtableRemoveAll(SCIP_HASHTABLE *hashtable)
Definition: misc.c:1748
SCIP_RETCODE SCIPsetPropPresol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPPRESOL((*proppresol)), int presolpriority, int presolmaxrounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:7042
static SCIP_RETCODE objimplicsFree(SCIP *scip, SCIP_OBJIMPLICS **objimplics)
SCIP_RETCODE SCIPinferVarUbProp(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_PROP *inferprop, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:21010
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:31741
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41554
void SCIPpropSetData(SCIP_PROP *prop, SCIP_PROPDATA *propdata)
Definition: prop.c:745
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:16968
static SCIP_DECL_PROPFREE(propFreePseudoobj)
SCIP_RETCODE SCIPtightenVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:21216
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41219
static SCIP_RETCODE propagateCutoffboundGlobally(SCIP *scip, SCIP_PROP *prop, int *nchgbds, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:16934
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17021
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip.c:997
unsigned int SCIP_EVENTTYPE
Definition: type_event.h:125
SCIP_RETCODE SCIPsetPropResprop(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPRESPROP((*propresprop)))
Definition: scip.c:7075
static SCIP_DECL_PROPEXITSOL(propExitsolPseudoobj)
#define SCIP_Bool
Definition: def.h:50
SCIP_RETCODE SCIPsetPropFree(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPFREE((*propfree)))
Definition: scip.c:6930
static SCIP_DECL_PROPRESPROP(propRespropPseudoobj)
static SCIP_RETCODE getMinactObjchg(SCIP *scip, SCIP_VAR *var, SCIP_OBJIMPLICS *objimplics, SCIP_BDCHGIDX *bdchgidx, SCIP_BOUNDTYPE bound, SCIP_Bool local, SCIP_Real *objchg)
static SCIP_Real getMaxObjPseudoactivityResidualValue(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Real contrib)
#define DEFAULT_PROPFULLINROOT
static void calcMaxObjPseudoactivity(SCIP *scip, SCIP_PROPDATA *propdata)
SCIP_RETCODE SCIPpropagateCutoffboundVar(SCIP *scip, SCIP_PROP *prop, SCIP_VAR *var, SCIP_Real cutoffbound, SCIP_Real pseudoobjval, SCIP_Bool *tightened)
SCIP_RETCODE SCIPincludePropBasic(SCIP *scip, SCIP_PROP **propptr, const char *name, const char *desc, int priority, int freq, SCIP_Bool delay, SCIP_PROPTIMING timingmask, SCIP_DECL_PROPEXEC((*propexec)), SCIP_PROPDATA *propdata)
Definition: scip.c:6877
static SCIP_RETCODE propdataInit(SCIP *scip, SCIP_PROPDATA *propdata)
static SCIP_RETCODE collectMaxactVar(SCIP *scip, SCIP_VAR *var, SCIP_Bool useimplics, SCIP_Real *objchg, SCIP_Bool *isnotzero)
static SCIP_RETCODE objimplicsCreate(SCIP *scip, SCIP_OBJIMPLICS **objimplics, SCIP_VAR **objvars, SCIP_HASHMAP *binobjvarmap, SCIP_Bool *collectedlbvars, SCIP_Bool *collectedubvars, SCIP_Real maxlbobjchg, SCIP_Real maxubobjchg, int nlbimpls, int nubimpls)
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17233
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:801
static SCIP_RETCODE propagateCutoffboundBinvars(SCIP *scip, SCIP_PROP *prop, SCIP_Real cutoffbound, SCIP_Real pseudoobjval, int *nfixedvars, SCIP_Bool *cutoff)
SCIP_Real SCIPgetPseudoObjval(SCIP *scip)
Definition: scip.c:26555
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:24356
static SCIP_Real getVarObjchg(SCIP_VAR *var, SCIP_BOUNDTYPE boundtype, SCIP_BOUNDTYPE bound)
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3117
SCIP_Bool SCIPallowObjProp(SCIP *scip)
Definition: scip.c:23080
static SCIP_DECL_HASHKEYEQ(cliqueIsHashkeyEq)
int SCIPgetNCliques(SCIP *scip)
Definition: scip.c:22095
#define SCIPfreeMemoryArray(scip, ptr)
Definition: scip.h:20373
#define SCIPallocMemoryArray(scip, ptr, num)
Definition: scip.h:20357
SCIP_BOUNDTYPE SCIPvarGetWorstBoundType(SCIP_VAR *var)
Definition: var.c:17080
static SCIP_RETCODE getConflictImplics(SCIP *scip, SCIP_VAR **vars, int start, int end, SCIP_BDCHGIDX *bdchgidx, SCIP_HASHTABLE *addedvars, SCIP_Real *reqpseudoobjval, SCIP_Bool *foundimplics)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:20400
static void checkImplicsApplied(SCIP *scip, SCIP_VAR *var)
static SCIP_RETCODE catchObjEvent(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_EVENTHDLR *eventhdlr, SCIP_VAR *var)
SCIP_RETCODE SCIPsetPropInitsol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPINITSOL((*propinitsol)))
Definition: scip.c:6978
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:37750
#define DEFAULT_RESPROPUSEIMPLICS
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41232
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:1505
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:36278
static SCIP_Real collectMinactImplicVar(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *binobjvarmap, SCIP_Bool *collectedvars, int nbinobjvars, SCIP_VAR **contributors, int *ncontributors)
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:20371
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:16955
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:36198
#define DEFAULT_MAXVARSFRAC
#define PROP_PRESOL_PRIORITY
#define EVENTHDLR_NAME
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:278
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41541
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:16648
static SCIP_DECL_HASHKEYVAL(cliqueGetHashkeyVal)
static void propdataReset(SCIP *scip, SCIP_PROPDATA *propdata)
SCIP_RETCODE SCIPtightenVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:21326
#define SCIP_Real
Definition: def.h:124
struct SCIP_PropData SCIP_PROPDATA
Definition: type_prop.h:38
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17307
#define MIN(x, y)
Definition: memory.c:63
static SCIP_RETCODE propagateLowerboundVar(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_Real lowerbound, SCIP_Bool *infeasible, SCIP_Bool *tightened)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41567
static SCIP_DECL_HASHGETKEY(cliqueGetHashkey)
#define SCIP_INVALID
Definition: def.h:144
static SCIP_RETCODE propagateCutoffboundVar(SCIP *scip, SCIP_PROP *prop, SCIP_VAR *var, int inferinfo, SCIP_Real objchg, SCIP_Real cutoffbound, SCIP_Real pseudoobjval, SCIP_Bool local, SCIP_Bool *tightened)
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:40720
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:917
#define PROP_NAME
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1687
static SCIP_DECL_EVENTEXEC(eventExecPseudoobj)
static void checkGlbfirstnonfixed(SCIP *scip, SCIP_PROPDATA *propdata)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16628
int SCIPgetNObjVars(SCIP *scip)
Definition: scip.c:10963
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3095
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17279
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_PROPDATA *propdata)
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:24423
int SCIPgetCutoffdepth(SCIP *scip)
Definition: scip.c:36765
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2089
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
#define SCIP_EVENTTYPE_GUBCHANGED
Definition: type_event.h:54
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41305
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3598
#define SCIPfreeMemoryArrayNull(scip, ptr)
Definition: scip.h:20374
static SCIP_DECL_PROPEXEC(propExecPseudoobj)
#define SCIP_EVENTTYPE_VARADDED
Definition: type_event.h:46
#define DEFAULT_MAXIMPLVARS
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3149
const char * SCIPpropGetName(SCIP_PROP *prop)
Definition: prop.c:887
static SCIP_Real getMaxObjPseudoactivity(SCIP *scip, SCIP_PROPDATA *propdata)
static SCIP_RETCODE propagateLowerboundBinvar(SCIP *scip, SCIP_VAR *var, SCIP_Real lowerbound, SCIP_Real maxpseudoobjact, SCIP_Bool useimplics, SCIP_Bool *infeasible, SCIP_Bool *tightened)
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:36164
int SCIPcliqueGetId(SCIP_CLIQUE *clique)
Definition: implics.c:3127
#define PROP_TIMING
#define SCIP_EVENTTYPE_BOUNDRELAXED
Definition: type_event.h:98