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