Scippy

SCIP

Solving Constraint Integer Programs

var.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file var.c
17  * @brief methods for problem variables
18  * @author Tobias Achterberg
19  * @author Timo Berthold
20  * @author Gerald Gamrath
21  * @author Stefan Heinz
22  * @author Marc Pfetsch
23  * @author Michael Winkler
24  * @author Kati Wolter
25  * @author Stefan Vigerske
26  *
27  * @todo Possibly implement the access of bounds of multi-aggregated variables by accessing the
28  * corresponding linear constraint if it exists. This seems to require some work, since the linear
29  * constraint has to be stored. Moreover, it has even to be created in case the original constraint
30  * was deleted after multi-aggregation, but the bounds of the multi-aggregated variable should be
31  * changed. This has to be done with care in order to not loose the performance gains of
32  * multi-aggregation.
33  */
34 
35 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
36 
37 #include <stdlib.h>
38 #include <assert.h>
39 #include <string.h>
40 
41 #include "scip/def.h"
42 #include "scip/prop.h"
43 #include "scip/relax.h"
44 #include "scip/var.h"
45 #include "scip/cons.h"
46 #include "scip/event.h"
47 #include "scip/history.h"
48 #include "scip/implics.h"
49 #include "scip/lp.h"
50 #include "scip/primal.h"
51 #include "scip/prob.h"
52 #include "scip/set.h"
53 #include "scip/sol.h"
54 #include "scip/stat.h"
55 #include "scip/tree.h"
56 
57 #include "scip/debug.h"
58 
59 #include "scip/pub_message.h"
60 #include "scip/pub_history.h"
61 
62 #define MAXIMPLSCLOSURE 100 /**< maximal number of descendants of implied variable for building closure
63  * in implication graph */
64 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds added due to implications */
65 
66 /*
67  * hole, holelist, and domain methods
68  */
69 
70 /** creates a new holelist element */
71 static
73  SCIP_HOLELIST** holelist, /**< pointer to holelist to create */
74  BMS_BLKMEM* blkmem, /**< block memory for target holelist */
75  SCIP_SET* set, /**< global SCIP settings */
76  SCIP_Real left, /**< left bound of open interval in new hole */
77  SCIP_Real right /**< right bound of open interval in new hole */
78  )
79 {
80  assert(holelist != NULL);
81  assert(blkmem != NULL);
82  assert(SCIPsetIsLT(set, left, right));
83 
84  SCIPdebugMessage("create hole list element (%.15g,%.15g) in blkmem %p\n", left, right, (void*)blkmem);
85 
86  SCIP_ALLOC( BMSallocBlockMemory(blkmem, holelist) );
87  (*holelist)->hole.left = left;
88  (*holelist)->hole.right = right;
89  (*holelist)->next = NULL;
90 
91  return SCIP_OKAY;
92 }
93 
94 /** frees all elements in the holelist */
95 static
97  SCIP_HOLELIST** holelist, /**< pointer to holelist to free */
98  BMS_BLKMEM* blkmem /**< block memory for target holelist */
99  )
100 {
101  assert(holelist != NULL);
102  assert(blkmem != NULL);
103 
104  while( *holelist != NULL )
105  {
106  SCIP_HOLELIST* next;
107 
108  SCIPdebugMessage("free hole list element (%.15g,%.15g) in blkmem %p\n",
109  (*holelist)->hole.left, (*holelist)->hole.right, (void*)blkmem);
110 
111  next = (*holelist)->next;
112  BMSfreeBlockMemory(blkmem, holelist);
113  assert(*holelist == NULL);
114 
115  *holelist = next;
116  }
117  assert(*holelist == NULL);
118 }
119 
120 /** duplicates a list of holes */
121 static
123  SCIP_HOLELIST** target, /**< pointer to target holelist */
124  BMS_BLKMEM* blkmem, /**< block memory for target holelist */
125  SCIP_SET* set, /**< global SCIP settings */
126  SCIP_HOLELIST* source /**< holelist to duplicate */
127  )
128 {
129  assert(target != NULL);
130 
131  while( source != NULL )
132  {
133  assert(source->next == NULL || SCIPsetIsGE(set, source->next->hole.left, source->hole.right));
134  SCIP_CALL( holelistCreate(target, blkmem, set, source->hole.left, source->hole.right) );
135  source = source->next;
136  target = &(*target)->next;
137  }
138 
139  return SCIP_OKAY;
140 }
141 
142 /** adds a hole to the domain */
143 static
145  SCIP_DOM* dom, /**< domain to add hole to */
146  BMS_BLKMEM* blkmem, /**< block memory */
147  SCIP_SET* set, /**< global SCIP settings */
148  SCIP_Real left, /**< left bound of open interval in new hole */
149  SCIP_Real right, /**< right bound of open interval in new hole */
150  SCIP_Bool* added /**< pointer to store whether the hole was added (variable didn't had that hole before), or NULL */
151  )
152 {
153  SCIP_HOLELIST** insertpos;
154  SCIP_HOLELIST* next;
155 
156  assert(dom != NULL);
157  assert(added != NULL);
158 
159  /* search for the position of the new hole */
160  insertpos = &dom->holelist;
161  while( *insertpos != NULL && (*insertpos)->hole.left < left )
162  insertpos = &(*insertpos)->next;
163 
164  /* check if new hole already exists in the hole list or is a sub hole of an existing one */
165  if( *insertpos != NULL && (*insertpos)->hole.left == left && (*insertpos)->hole.right >= right ) /*lint !e777 */
166  {
167  SCIPdebugMessage("new hole (%.15g,%.15g) is redundant through known hole (%.15g,%.15g)\n",
168  left, right, (*insertpos)->hole.left, (*insertpos)->hole.right);
169  *added = FALSE;
170  return SCIP_OKAY;
171  }
172 
173  /* add hole */
174  *added = TRUE;
175 
176  next = *insertpos;
177  SCIP_CALL( holelistCreate(insertpos, blkmem, set, left, right) );
178  (*insertpos)->next = next;
179 
180  return SCIP_OKAY;
181 }
182 
183 /** merges overlapping holes into single holes, computes and moves lower and upper bound, respectively */
184 /**@todo the domMerge() method is currently called if a lower or an upper bound locally or globally changed; this could
185  * be more efficient if performed with the knowledge if it was a lower or an upper bound which triggered this
186  * merge */
187 static
188 void domMerge(
189  SCIP_DOM* dom, /**< domain to merge */
190  BMS_BLKMEM* blkmem, /**< block memory */
191  SCIP_SET* set, /**< global SCIP settings */
192  SCIP_Real* newlb, /**< pointer to store new lower bound */
193  SCIP_Real* newub /**< pointer to store new upper bound */
194  )
195 {
196  SCIP_HOLELIST** holelistptr;
197  SCIP_HOLELIST** lastnextptr;
198  SCIP_Real* lastrightptr;
199 
200  assert(dom != NULL);
201  assert(SCIPsetIsLE(set, dom->lb, dom->ub));
202 
203 #ifndef NDEBUG
204  {
205  /* check if the holelist is sorted w.r.t. to the left interval bounds */
206  SCIP_Real lastleft;
207 
208  holelistptr = &dom->holelist;
209 
210  lastleft = -SCIPsetInfinity(set);
211 
212  while( *holelistptr != NULL )
213  {
214  if( (*holelistptr)->next != NULL )
215  {
216  assert( SCIPsetIsLE(set, lastleft, (*holelistptr)->hole.left) );
217  lastleft = (*holelistptr)->hole.left;
218  }
219 
220  holelistptr = &(*holelistptr)->next;
221  }
222  }
223 #endif
224 
225  SCIPdebugMessage("merge hole list\n");
226 
227  holelistptr = &dom->holelist;
228  lastrightptr = &dom->lb; /* lower bound is the right bound of the hole (-infinity,lb) */
229  lastnextptr = holelistptr;
230 
231  while( *holelistptr != NULL )
232  {
233  SCIPdebugMessage("check hole (%.15g,%.15g) last right interval was <%.15g>\n",
234  (*holelistptr)->hole.left, (*holelistptr)->hole.right, *lastrightptr);
235 
236  /* check that the hole is not empty */
237  assert(SCIPsetIsLT(set, (*holelistptr)->hole.left, (*holelistptr)->hole.right));
238 
239  if( SCIPsetIsGE(set, (*holelistptr)->hole.left, dom->ub) )
240  {
241  /* the remaining holes start behind the upper bound: remove them */
242  SCIPdebugMessage("remove remaining hole since upper bound <%.15g> is less then the left hand side of the current hole\n", dom->ub);
243  holelistFree(holelistptr, blkmem);
244  assert(*holelistptr == NULL);
245 
246  /* unlink this hole from the previous hole */
247  *lastnextptr = NULL;
248  }
249  else if( SCIPsetIsGT(set, (*holelistptr)->hole.right, dom->ub) )
250  {
251  /* the hole overlaps the upper bound: decrease upper bound, remove this hole and all remaining holes */
252  SCIPdebugMessage("upper bound <%.15g> lays in current hole; store new upper bound and remove this and all remaining holes\n", dom->ub);
253 
254  assert(SCIPsetIsLT(set, (*holelistptr)->hole.left, dom->ub));
255 
256  /* adjust upper bound */
257  dom->ub = (*holelistptr)->hole.left;
258 
259  if(newub != NULL )
260  *newub = (*holelistptr)->hole.left;
261 
262  /* remove remaining hole list */
263  holelistFree(holelistptr, blkmem);
264  assert(*holelistptr == NULL);
265 
266  /* unlink this hole from the previous hole */
267  *lastnextptr = NULL;
268  }
269  else if( SCIPsetIsGT(set, *lastrightptr, (*holelistptr)->hole.left) )
270  {
271  /* the right bound of the last hole is greater than the left bound of this hole: increase the right bound of
272  * the last hole, delete this hole */
273  SCIP_HOLELIST* nextholelist;
274 
275  if( SCIPsetIsEQ(set, *lastrightptr, dom->lb ) )
276  {
277  /* the reason for the overlap results from the lower bound hole (-infinity,lb); therefore, we can increase
278  * the lower bound */
279  SCIPdebugMessage("lower bound <%.15g> lays in current hole; store new lower bound and remove hole\n", dom->lb);
280  *lastrightptr = MAX(*lastrightptr, (*holelistptr)->hole.right);
281 
282  /* adjust lower bound */
283  dom->lb = *lastrightptr;
284 
285  if(newlb != NULL )
286  *newlb = *lastrightptr;
287  }
288  else
289  {
290  SCIPdebugMessage("current hole overlaps with the previous one (...,%.15g); merge to (...,%.15g)\n",
291  *lastrightptr, MAX(*lastrightptr, (*holelistptr)->hole.right) );
292  *lastrightptr = MAX(*lastrightptr, (*holelistptr)->hole.right);
293  }
294  nextholelist = (*holelistptr)->next;
295  (*holelistptr)->next = NULL;
296  holelistFree(holelistptr, blkmem);
297 
298  /* connect the linked list after removing the hole */
299  *lastnextptr = nextholelist;
300 
301  /* get next hole */
302  *holelistptr = nextholelist;
303  }
304  else
305  {
306  /* the holes do not overlap: update lastholelist and lastrightptr */
307  lastrightptr = &(*holelistptr)->hole.right;
308  lastnextptr = &(*holelistptr)->next;
309 
310  /* get next hole */
311  holelistptr = &(*holelistptr)->next;
312  }
313  }
314 
315 #ifndef NDEBUG
316  {
317  /* check that holes are merged */
318  SCIP_Real lastright;
319 
320  lastright = dom->lb; /* lower bound is the right bound of the hole (-infinity,lb) */
321  holelistptr = &dom->holelist;
322 
323  while( *holelistptr != NULL )
324  {
325  /* check the the last right interval is smaller or equal to the current left interval (none overlapping) */
326  assert( SCIPsetIsLE(set, lastright, (*holelistptr)->hole.left) );
327 
328  /* check the hole property (check that the hole is not empty) */
329  assert( SCIPsetIsLT(set, (*holelistptr)->hole.left, (*holelistptr)->hole.right) );
330  lastright = (*holelistptr)->hole.right;
331 
332  /* get next hole */
333  holelistptr = &(*holelistptr)->next;
334  }
335 
336  /* check the the last right interval is smaller or equal to the upper bound (none overlapping) */
337  assert( SCIPsetIsLE(set, lastright, dom->ub) );
338  }
339 #endif
340 }
341 
342 /*
343  * domain change methods
344  */
345 
346 /** ensures, that bound change info array for lower bound changes can store at least num entries */
347 static
349  SCIP_VAR* var, /**< problem variable */
350  BMS_BLKMEM* blkmem, /**< block memory */
351  SCIP_SET* set, /**< global SCIP settings */
352  int num /**< minimum number of entries to store */
353  )
354 {
355  assert(var != NULL);
356  assert(var->nlbchginfos <= var->lbchginfossize);
357  assert(SCIPvarIsTransformed(var));
358 
359  if( num > var->lbchginfossize )
360  {
361  int newsize;
362 
363  newsize = SCIPsetCalcMemGrowSize(set, num);
364  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->lbchginfos, var->lbchginfossize, newsize) );
365  var->lbchginfossize = newsize;
366  }
367  assert(num <= var->lbchginfossize);
368 
369  return SCIP_OKAY;
370 }
371 
372 /** ensures, that bound change info array for upper bound changes can store at least num entries */
373 static
375  SCIP_VAR* var, /**< problem variable */
376  BMS_BLKMEM* blkmem, /**< block memory */
377  SCIP_SET* set, /**< global SCIP settings */
378  int num /**< minimum number of entries to store */
379  )
380 {
381  assert(var != NULL);
382  assert(var->nubchginfos <= var->ubchginfossize);
383  assert(SCIPvarIsTransformed(var));
384 
385  if( num > var->ubchginfossize )
386  {
387  int newsize;
388 
389  newsize = SCIPsetCalcMemGrowSize(set, num);
390  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->ubchginfos, var->ubchginfossize, newsize) );
391  var->ubchginfossize = newsize;
392  }
393  assert(num <= var->ubchginfossize);
394 
395  return SCIP_OKAY;
396 }
397 
398 /** adds domain change info to the variable's lower bound change info array */
399 static
401  SCIP_VAR* var, /**< problem variable */
402  BMS_BLKMEM* blkmem, /**< block memory */
403  SCIP_SET* set, /**< global SCIP settings */
404  SCIP_Real oldbound, /**< old value for bound */
405  SCIP_Real newbound, /**< new value for bound */
406  int depth, /**< depth in the tree, where the bound change takes place */
407  int pos, /**< position of the bound change in its bound change array */
408  SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself) */
409  SCIP_CONS* infercons, /**< constraint that infered this bound change, or NULL */
410  SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
411  int inferinfo, /**< user information for inference to help resolving the conflict */
412  SCIP_BOUNDTYPE inferboundtype, /**< type of bound for inference var: lower or upper bound */
413  SCIP_BOUNDCHGTYPE boundchgtype /**< bound change type: branching decision or infered bound change */
414  )
415 {
416  assert(var != NULL);
417  assert(SCIPsetIsLT(set, oldbound, newbound));
418  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, oldbound));
419  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
420  assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, oldbound, 0.0));
421  assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, 1.0));
422  assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
423  assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
424  assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
425 
426  SCIPdebugMessage("adding lower bound change info to var <%s>[%g,%g]: depth=%d, pos=%d, infer%s=<%s>, inferinfo=%d, %g -> %g\n",
427  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, depth, pos,
428  infercons != NULL ? "cons" : "prop",
429  infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo,
430  oldbound, newbound);
431 
432  SCIP_CALL( varEnsureLbchginfosSize(var, blkmem, set, var->nlbchginfos+1) );
433  var->lbchginfos[var->nlbchginfos].oldbound = oldbound;
434  var->lbchginfos[var->nlbchginfos].newbound = newbound;
435  var->lbchginfos[var->nlbchginfos].var = var;
436  var->lbchginfos[var->nlbchginfos].bdchgidx.depth = depth;
437  var->lbchginfos[var->nlbchginfos].bdchgidx.pos = pos;
438  var->lbchginfos[var->nlbchginfos].pos = var->nlbchginfos; /*lint !e732*/
439  var->lbchginfos[var->nlbchginfos].boundchgtype = boundchgtype; /*lint !e641*/
440  var->lbchginfos[var->nlbchginfos].boundtype = SCIP_BOUNDTYPE_LOWER; /*lint !e641*/
441  var->lbchginfos[var->nlbchginfos].redundant = FALSE;
442  var->lbchginfos[var->nlbchginfos].inferboundtype = inferboundtype; /*lint !e641*/
443  var->lbchginfos[var->nlbchginfos].inferencedata.var = infervar;
444  var->lbchginfos[var->nlbchginfos].inferencedata.info = inferinfo;
445 
446  /**@note The "pos" data member of the bound change info has a size of 27 bits */
447  assert(var->nlbchginfos < 1 << 27);
448 
449  switch( boundchgtype )
450  {
452  break;
454  assert(infercons != NULL);
455  var->lbchginfos[var->nlbchginfos].inferencedata.reason.cons = infercons;
456  break;
458  var->lbchginfos[var->nlbchginfos].inferencedata.reason.prop = inferprop;
459  break;
460  default:
461  SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
462  return SCIP_INVALIDDATA;
463  }
464 
465  var->nlbchginfos++;
466 
467  assert(var->nlbchginfos < 2
469  &var->lbchginfos[var->nlbchginfos-1].bdchgidx));
470 
471  return SCIP_OKAY;
472 }
473 
474 /** adds domain change info to the variable's upper bound change info array */
475 static
477  SCIP_VAR* var, /**< problem variable */
478  BMS_BLKMEM* blkmem, /**< block memory */
479  SCIP_SET* set, /**< global SCIP settings */
480  SCIP_Real oldbound, /**< old value for bound */
481  SCIP_Real newbound, /**< new value for bound */
482  int depth, /**< depth in the tree, where the bound change takes place */
483  int pos, /**< position of the bound change in its bound change array */
484  SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself) */
485  SCIP_CONS* infercons, /**< constraint that infered this bound change, or NULL */
486  SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
487  int inferinfo, /**< user information for inference to help resolving the conflict */
488  SCIP_BOUNDTYPE inferboundtype, /**< type of bound for inference var: lower or upper bound */
489  SCIP_BOUNDCHGTYPE boundchgtype /**< bound change type: branching decision or infered bound change */
490  )
491 {
492  assert(var != NULL);
493  assert(SCIPsetIsGT(set, oldbound, newbound));
494  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, oldbound));
495  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
496  assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, oldbound, 1.0));
497  assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, 0.0));
498  assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
499  assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
500  assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
501 
502  SCIPdebugMessage("adding upper bound change info to var <%s>[%g,%g]: depth=%d, pos=%d, infer%s=<%s>, inferinfo=%d, %g -> %g\n",
503  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, depth, pos,
504  infercons != NULL ? "cons" : "prop",
505  infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo,
506  oldbound, newbound);
507 
508  SCIP_CALL( varEnsureUbchginfosSize(var, blkmem, set, var->nubchginfos+1) );
509  var->ubchginfos[var->nubchginfos].oldbound = oldbound;
510  var->ubchginfos[var->nubchginfos].newbound = newbound;
511  var->ubchginfos[var->nubchginfos].var = var;
512  var->ubchginfos[var->nubchginfos].bdchgidx.depth = depth;
513  var->ubchginfos[var->nubchginfos].bdchgidx.pos = pos;
514  var->ubchginfos[var->nubchginfos].pos = var->nubchginfos; /*lint !e732*/
515  var->ubchginfos[var->nubchginfos].boundchgtype = boundchgtype; /*lint !e641*/
516  var->ubchginfos[var->nubchginfos].boundtype = SCIP_BOUNDTYPE_UPPER; /*lint !e641*/
517  var->ubchginfos[var->nubchginfos].redundant = FALSE;
518  var->ubchginfos[var->nubchginfos].inferboundtype = inferboundtype; /*lint !e641*/
519  var->ubchginfos[var->nubchginfos].inferencedata.var = infervar;
520  var->ubchginfos[var->nubchginfos].inferencedata.info = inferinfo;
521 
522  /**@note The "pos" data member of the bound change info has a size of 27 bits */
523  assert(var->nubchginfos < 1 << 27);
524 
525  switch( boundchgtype )
526  {
528  break;
530  assert(infercons != NULL);
531  var->ubchginfos[var->nubchginfos].inferencedata.reason.cons = infercons;
532  break;
534  var->ubchginfos[var->nubchginfos].inferencedata.reason.prop = inferprop;
535  break;
536  default:
537  SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
538  return SCIP_INVALIDDATA;
539  }
540 
541  var->nubchginfos++;
542 
543  assert(var->nubchginfos < 2
545  &var->ubchginfos[var->nubchginfos-1].bdchgidx));
546 
547  return SCIP_OKAY;
548 }
549 
550 /** applies single bound change */
552  SCIP_BOUNDCHG* boundchg, /**< bound change to apply */
553  BMS_BLKMEM* blkmem, /**< block memory */
554  SCIP_SET* set, /**< global SCIP settings */
555  SCIP_STAT* stat, /**< problem statistics */
556  SCIP_LP* lp, /**< current LP data */
557  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
558  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
559  int depth, /**< depth in the tree, where the bound change takes place */
560  int pos, /**< position of the bound change in its bound change array */
561  SCIP_Bool* cutoff /**< pointer to store whether an infeasible bound change was detected */
562  )
563 {
564  SCIP_VAR* var;
565 
566  assert(boundchg != NULL);
567  assert(stat != NULL);
568  assert(depth > 0);
569  assert(pos >= 0);
570  assert(cutoff != NULL);
571 
572  *cutoff = FALSE;
573 
574  /* ignore redundant bound changes */
575  if( boundchg->redundant )
576  return SCIP_OKAY;
577 
578  var = boundchg->var;
579  assert(var != NULL);
581  assert(!SCIPvarIsIntegral(var) || SCIPsetIsIntegral(set, boundchg->newbound));
582 
583  /* apply bound change */
584  switch( boundchg->boundtype )
585  {
587  /* check, if the bound change is still active (could be replaced by inference due to repropagation of higher node) */
588  if( SCIPsetIsGT(set, boundchg->newbound, var->locdom.lb) )
589  {
590  if( SCIPsetIsLE(set, boundchg->newbound, var->locdom.ub) )
591  {
592  /* add the bound change info to the variable's bound change info array */
593  switch( boundchg->boundchgtype )
594  {
596  SCIPdebugMessage(" -> branching: new lower bound of <%s>[%g,%g]: %g\n",
597  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
598  SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
600  stat->lastbranchvar = var;
602  stat->lastbranchvalue = boundchg->newbound;
603  break;
604 
606  assert(boundchg->data.inferencedata.reason.cons != NULL);
607  SCIPdebugMessage(" -> constraint <%s> inference: new lower bound of <%s>[%g,%g]: %g\n",
608  SCIPconsGetName(boundchg->data.inferencedata.reason.cons),
609  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
610  SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
611  boundchg->data.inferencedata.var, boundchg->data.inferencedata.reason.cons, NULL,
612  boundchg->data.inferencedata.info,
614  break;
615 
617  SCIPdebugMessage(" -> propagator <%s> inference: new lower bound of <%s>[%g,%g]: %g\n",
618  boundchg->data.inferencedata.reason.prop != NULL
619  ? SCIPpropGetName(boundchg->data.inferencedata.reason.prop) : "-",
620  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
621  SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
622  boundchg->data.inferencedata.var, NULL, boundchg->data.inferencedata.reason.prop,
623  boundchg->data.inferencedata.info,
625  break;
626 
627  default:
628  SCIPerrorMessage("invalid bound change type %d\n", boundchg->boundchgtype);
629  return SCIP_INVALIDDATA;
630  }
631 
632  /* change local bound of variable */
633  SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, boundchg->newbound) );
634  }
635  else
636  {
637  SCIPdebugMessage(" -> cutoff: new lower bound of <%s>[%g,%g]: %g\n",
638  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
639  *cutoff = TRUE;
640  boundchg->redundant = TRUE; /* bound change has not entered the lbchginfos array of the variable! */
641  }
642  }
643  else
644  {
645  /* mark bound change to be inactive */
646  SCIPdebugMessage(" -> inactive %s: new lower bound of <%s>[%g,%g]: %g\n",
647  (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
648  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
649  boundchg->redundant = TRUE;
650  }
651  break;
652 
654  /* check, if the bound change is still active (could be replaced by inference due to repropagation of higher node) */
655  if( SCIPsetIsLT(set, boundchg->newbound, var->locdom.ub) )
656  {
657  if( SCIPsetIsGE(set, boundchg->newbound, var->locdom.lb) )
658  {
659  /* add the bound change info to the variable's bound change info array */
660  switch( boundchg->boundchgtype )
661  {
663  SCIPdebugMessage(" -> branching: new upper bound of <%s>[%g,%g]: %g\n",
664  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
665  SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
667  stat->lastbranchvar = var;
669  stat->lastbranchvalue = boundchg->newbound;
670  break;
671 
673  assert(boundchg->data.inferencedata.reason.cons != NULL);
674  SCIPdebugMessage(" -> constraint <%s> inference: new upper bound of <%s>[%g,%g]: %g\n",
675  SCIPconsGetName(boundchg->data.inferencedata.reason.cons),
676  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
677  SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
678  boundchg->data.inferencedata.var, boundchg->data.inferencedata.reason.cons, NULL,
679  boundchg->data.inferencedata.info,
681  break;
682 
684  SCIPdebugMessage(" -> propagator <%s> inference: new upper bound of <%s>[%g,%g]: %g\n",
685  boundchg->data.inferencedata.reason.prop != NULL
686  ? SCIPpropGetName(boundchg->data.inferencedata.reason.prop) : "-",
687  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
688  SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
689  boundchg->data.inferencedata.var, NULL, boundchg->data.inferencedata.reason.prop,
690  boundchg->data.inferencedata.info,
692  break;
693 
694  default:
695  SCIPerrorMessage("invalid bound change type %d\n", boundchg->boundchgtype);
696  return SCIP_INVALIDDATA;
697  }
698 
699  /* change local bound of variable */
700  SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, boundchg->newbound) );
701  }
702  else
703  {
704  SCIPdebugMessage(" -> cutoff: new upper bound of <%s>[%g,%g]: %g\n",
705  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
706  *cutoff = TRUE;
707  boundchg->redundant = TRUE; /* bound change has not entered the ubchginfos array of the variable! */
708  }
709  }
710  else
711  {
712  /* mark bound change to be inactive */
713  SCIPdebugMessage(" -> inactive %s: new upper bound of <%s>[%g,%g]: %g\n",
714  (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
715  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
716  boundchg->redundant = TRUE;
717  }
718  break;
719 
720  default:
721  SCIPerrorMessage("unknown bound type\n");
722  return SCIP_INVALIDDATA;
723  }
724 
725  /* update the branching and inference history */
726  if( !boundchg->applied && !boundchg->redundant )
727  {
728  assert(var == boundchg->var);
729 
731  {
732  SCIP_CALL( SCIPvarIncNBranchings(var, blkmem, set, stat,
735  }
736  else if( stat->lastbranchvar != NULL )
737  {
738  /**@todo if last branching variable is unknown, retrieve it from the nodes' boundchg arrays */
739  SCIP_CALL( SCIPvarIncInferenceSum(stat->lastbranchvar, blkmem, set, stat, stat->lastbranchdir, stat->lastbranchvalue, 1.0) );
740  }
741  boundchg->applied = TRUE;
742  }
743 
744  return SCIP_OKAY;
745 }
746 
747 /** undoes single bound change */
749  SCIP_BOUNDCHG* boundchg, /**< bound change to remove */
750  BMS_BLKMEM* blkmem, /**< block memory */
751  SCIP_SET* set, /**< global SCIP settings */
752  SCIP_STAT* stat, /**< problem statistics */
753  SCIP_LP* lp, /**< current LP data */
754  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
755  SCIP_EVENTQUEUE* eventqueue /**< event queue */
756  )
757 {
758  SCIP_VAR* var;
759 
760  assert(boundchg != NULL);
761  assert(stat != NULL);
762 
763  /* ignore redundant bound changes */
764  if( boundchg->redundant )
765  return SCIP_OKAY;
766 
767  var = boundchg->var;
768  assert(var != NULL);
770 
771  /* undo bound change: apply the previous bound change of variable */
772  switch( boundchg->boundtype )
773  {
775  var->nlbchginfos--;
776  assert(var->nlbchginfos >= 0);
777  assert(var->lbchginfos != NULL);
778  assert( SCIPsetIsFeasEQ(set, var->lbchginfos[var->nlbchginfos].newbound, var->locdom.lb) ); /*lint !e777*/
779  assert( SCIPsetIsFeasLE(set, boundchg->newbound, var->locdom.lb) ); /* current lb might be larger to intermediate global bound change */
780 
781  SCIPdebugMessage("removed lower bound change info of var <%s>[%g,%g]: depth=%d, pos=%d, %g -> %g\n",
782  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub,
785 
786  /* reinstall the previous local bound */
787  SCIP_CALL( SCIPvarChgLbLocal(boundchg->var, blkmem, set, stat, lp, branchcand, eventqueue,
788  var->lbchginfos[var->nlbchginfos].oldbound) );
789 
790  /* in case all bound changes are removed the local bound should match the global bound */
791  assert(var->nlbchginfos > 0 || SCIPsetIsFeasEQ(set, var->locdom.lb, var->glbdom.lb));
792 
793  break;
794 
796  var->nubchginfos--;
797  assert(var->nubchginfos >= 0);
798  assert(var->ubchginfos != NULL);
799  assert( SCIPsetIsFeasEQ(set, var->ubchginfos[var->nubchginfos].newbound, var->locdom.ub) ); /*lint !e777*/
800  assert( SCIPsetIsFeasGE(set, boundchg->newbound, var->locdom.ub) ); /* current ub might be smaller to intermediate global bound change */
801 
802  SCIPdebugMessage("removed upper bound change info of var <%s>[%g,%g]: depth=%d, pos=%d, %g -> %g\n",
803  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub,
806 
807  /* reinstall the previous local bound */
808  SCIP_CALL( SCIPvarChgUbLocal(boundchg->var, blkmem, set, stat, lp, branchcand, eventqueue,
809  var->ubchginfos[var->nubchginfos].oldbound) );
810 
811  /* in case all bound changes are removed the local bound should match the global bound */
812  assert(var->nubchginfos > 0 || SCIPsetIsFeasEQ(set, var->locdom.ub, var->glbdom.ub));
813 
814  break;
815 
816  default:
817  SCIPerrorMessage("unknown bound type\n");
818  return SCIP_INVALIDDATA;
819  }
820 
821  /* update last branching variable */
823  {
824  stat->lastbranchvar = NULL;
826  }
827 
828  return SCIP_OKAY;
829 }
830 
831 /** applies single bound change to the global problem by changing the global bound of the corresponding variable */
832 static
834  SCIP_BOUNDCHG* boundchg, /**< bound change to apply */
835  BMS_BLKMEM* blkmem, /**< block memory */
836  SCIP_SET* set, /**< global SCIP settings */
837  SCIP_STAT* stat, /**< problem statistics */
838  SCIP_LP* lp, /**< current LP data */
839  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
840  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
841  SCIP_Bool* cutoff /**< pointer to store whether an infeasible bound change was detected */
842  )
843 {
844  SCIP_VAR* var;
845  SCIP_Real newbound;
846  SCIP_BOUNDTYPE boundtype;
847 
848  assert(boundchg != NULL);
849  assert(cutoff != NULL);
850 
851  *cutoff = FALSE;
852 
853  /* ignore redundant bound changes */
854  if( boundchg->redundant )
855  return SCIP_OKAY;
856 
857  var = SCIPboundchgGetVar(boundchg);
858  newbound = SCIPboundchgGetNewbound(boundchg);
859  boundtype = SCIPboundchgGetBoundtype(boundchg);
860 
861  /* check if the bound change is redundant which can happen due to a (better) global bound change which was perforemed
862  * after that bound change was applied
863  *
864  * @note a global bound change is not captured by the redundant member of the bound change data structure
865  */
866  if( (boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasLE(set, newbound, SCIPvarGetLbGlobal(var)))
867  || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasGE(set, newbound, SCIPvarGetUbGlobal(var))) )
868  {
869  return SCIP_OKAY;
870  }
871 
872  SCIPdebugMessage("applying global bound change: <%s>[%g,%g] %s %g\n",
874  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", newbound);
875 
876  /* check for cutoff */
877  if( (boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGT(set, newbound, SCIPvarGetUbGlobal(var)))
878  || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLT(set, newbound, SCIPvarGetLbGlobal(var))) )
879  {
880  *cutoff = TRUE;
881  return SCIP_OKAY;
882  }
883 
884  /* apply bound change */
885  SCIP_CALL( SCIPvarChgBdGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound, boundtype) );
886 
887  return SCIP_OKAY;
888 }
889 
890 /** captures branching and inference data of bound change */
891 static
893  SCIP_BOUNDCHG* boundchg /**< bound change to remove */
894  )
895 {
896  assert(boundchg != NULL);
897 
898  /* capture variable associated with the bound change */
899  assert(boundchg->var != NULL);
900  SCIPvarCapture(boundchg->var);
901 
902  switch( boundchg->boundchgtype )
903  {
906  break;
907 
909  assert(boundchg->data.inferencedata.var != NULL);
910  assert(boundchg->data.inferencedata.reason.cons != NULL);
911  SCIPconsCapture(boundchg->data.inferencedata.reason.cons);
912  break;
913 
914  default:
915  SCIPerrorMessage("invalid bound change type\n");
916  return SCIP_INVALIDDATA;
917  }
918 
919  return SCIP_OKAY;
920 }
921 
922 /** releases branching and inference data of bound change */
923 static
925  SCIP_BOUNDCHG* boundchg, /**< bound change to remove */
926  BMS_BLKMEM* blkmem, /**< block memory */
927  SCIP_SET* set, /**< global SCIP settings */
928  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
929  SCIP_LP* lp /**< current LP data */
930 
931  )
932 {
933  assert(boundchg != NULL);
934 
935  switch( boundchg->boundchgtype )
936  {
939  break;
940 
942  assert(boundchg->data.inferencedata.var != NULL);
943  assert(boundchg->data.inferencedata.reason.cons != NULL);
944  SCIP_CALL( SCIPconsRelease(&boundchg->data.inferencedata.reason.cons, blkmem, set) );
945  break;
946 
947  default:
948  SCIPerrorMessage("invalid bound change type\n");
949  return SCIP_INVALIDDATA;
950  }
951 
952  /* release variable */
953  assert(boundchg->var != NULL);
954  SCIP_CALL( SCIPvarRelease(&boundchg->var, blkmem, set, eventqueue, lp) );
955 
956 
957  return SCIP_OKAY;
958 }
959 
960 /** creates empty domain change data with dynamic arrays */
961 static
963  SCIP_DOMCHG** domchg, /**< pointer to domain change data */
964  BMS_BLKMEM* blkmem /**< block memory */
965  )
966 {
967  assert(domchg != NULL);
968  assert(blkmem != NULL);
969 
970  SCIP_ALLOC( BMSallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN)) );
971  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
972  (*domchg)->domchgdyn.nboundchgs = 0;
973  (*domchg)->domchgdyn.boundchgs = NULL;
974  (*domchg)->domchgdyn.nholechgs = 0;
975  (*domchg)->domchgdyn.holechgs = NULL;
976  (*domchg)->domchgdyn.boundchgssize = 0;
977  (*domchg)->domchgdyn.holechgssize = 0;
978 
979  return SCIP_OKAY;
980 }
981 
982 /** frees domain change data */
984  SCIP_DOMCHG** domchg, /**< pointer to domain change */
985  BMS_BLKMEM* blkmem, /**< block memory */
986  SCIP_SET* set, /**< global SCIP settings */
987  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
988  SCIP_LP* lp /**< current LP data */
989  )
990 {
991  assert(domchg != NULL);
992  assert(blkmem != NULL);
993 
994  if( *domchg != NULL )
995  {
996  int i;
997 
998  /* release variables, branching and inference data associated with the bound changes */
999  for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1000  {
1001  SCIP_CALL( boundchgReleaseData(&(*domchg)->domchgbound.boundchgs[i], blkmem, set, eventqueue, lp) );
1002  }
1003 
1004  /* free memory for bound and hole changes */
1005  switch( (*domchg)->domchgdyn.domchgtype )
1006  {
1007  case SCIP_DOMCHGTYPE_BOUND:
1008  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgbound.boundchgs, (*domchg)->domchgbound.nboundchgs);
1009  BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOUND));
1010  break;
1011  case SCIP_DOMCHGTYPE_BOTH:
1012  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgboth.boundchgs, (*domchg)->domchgboth.nboundchgs);
1013  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgboth.holechgs, (*domchg)->domchgboth.nholechgs);
1014  BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH));
1015  break;
1017  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.boundchgs, (*domchg)->domchgdyn.boundchgssize);
1018  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.holechgs, (*domchg)->domchgdyn.holechgssize);
1019  BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN));
1020  break;
1021  default:
1022  SCIPerrorMessage("invalid domain change type\n");
1023  return SCIP_INVALIDDATA;
1024  }
1025  }
1026 
1027  return SCIP_OKAY;
1028 }
1029 
1030 /** converts a static domain change data into a dynamic one */
1031 static
1033  SCIP_DOMCHG** domchg, /**< pointer to domain change data */
1034  BMS_BLKMEM* blkmem /**< block memory */
1035  )
1036 {
1037  assert(domchg != NULL);
1038  assert(blkmem != NULL);
1039 
1040  SCIPdebugMessage("making domain change data %p pointing to %p dynamic\n", (void*)domchg, (void*)*domchg);
1041 
1042  if( *domchg == NULL )
1043  {
1044  SCIP_CALL( domchgCreate(domchg, blkmem) );
1045  }
1046  else
1047  {
1048  switch( (*domchg)->domchgdyn.domchgtype )
1049  {
1050  case SCIP_DOMCHGTYPE_BOUND:
1051  SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOUND), sizeof(SCIP_DOMCHGDYN)) );
1052  (*domchg)->domchgdyn.nholechgs = 0;
1053  (*domchg)->domchgdyn.holechgs = NULL;
1054  (*domchg)->domchgdyn.boundchgssize = (*domchg)->domchgdyn.nboundchgs;
1055  (*domchg)->domchgdyn.holechgssize = 0;
1056  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
1057  break;
1058  case SCIP_DOMCHGTYPE_BOTH:
1059  SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH), sizeof(SCIP_DOMCHGDYN)) );
1060  (*domchg)->domchgdyn.boundchgssize = (*domchg)->domchgdyn.nboundchgs;
1061  (*domchg)->domchgdyn.holechgssize = (*domchg)->domchgdyn.nholechgs;
1062  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
1063  break;
1065  break;
1066  default:
1067  SCIPerrorMessage("invalid domain change type\n");
1068  return SCIP_INVALIDDATA;
1069  }
1070  }
1071 #ifndef NDEBUG
1072  {
1073  int i;
1074  for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1075  assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1076  || EPSISINT((*domchg)->domchgbound.boundchgs[i].newbound, 1e-06));
1077  }
1078 #endif
1079 
1080  return SCIP_OKAY;
1081 }
1082 
1083 /** converts a dynamic domain change data into a static one, using less memory than for a dynamic one */
1085  SCIP_DOMCHG** domchg, /**< pointer to domain change data */
1086  BMS_BLKMEM* blkmem, /**< block memory */
1087  SCIP_SET* set, /**< global SCIP settings */
1088  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1089  SCIP_LP* lp /**< current LP data */
1090  )
1091 {
1092  assert(domchg != NULL);
1093  assert(blkmem != NULL);
1094 
1095  SCIPdebugMessage("making domain change data %p pointing to %p static\n", (void*)domchg, (void*)*domchg);
1096 
1097  if( *domchg != NULL )
1098  {
1099  switch( (*domchg)->domchgdyn.domchgtype )
1100  {
1101  case SCIP_DOMCHGTYPE_BOUND:
1102  if( (*domchg)->domchgbound.nboundchgs == 0 )
1103  {
1104  SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1105  }
1106  break;
1107  case SCIP_DOMCHGTYPE_BOTH:
1108  if( (*domchg)->domchgboth.nholechgs == 0 )
1109  {
1110  if( (*domchg)->domchgbound.nboundchgs == 0 )
1111  {
1112  SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1113  }
1114  else
1115  {
1116  SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH), sizeof(SCIP_DOMCHGBOUND)) );
1117  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOUND; /*lint !e641*/
1118  }
1119  }
1120  break;
1122  if( (*domchg)->domchgboth.nholechgs == 0 )
1123  {
1124  if( (*domchg)->domchgbound.nboundchgs == 0 )
1125  {
1126  SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1127  }
1128  else
1129  {
1130  /* shrink dynamic size arrays to their minimal sizes */
1131  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.boundchgs,
1132  (*domchg)->domchgdyn.boundchgssize, (*domchg)->domchgdyn.nboundchgs) ); /*lint !e571*/
1133  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.holechgs, (*domchg)->domchgdyn.holechgssize);
1134 
1135  /* convert into static domain change */
1136  SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN), sizeof(SCIP_DOMCHGBOUND)) );
1137  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOUND; /*lint !e641*/
1138  }
1139  }
1140  else
1141  {
1142  /* shrink dynamic size arrays to their minimal sizes */
1143  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.boundchgs,
1144  (*domchg)->domchgdyn.boundchgssize, (*domchg)->domchgdyn.nboundchgs) ); /*lint !e571*/
1145  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.holechgs,
1146  (*domchg)->domchgdyn.holechgssize, (*domchg)->domchgdyn.nholechgs) );
1147 
1148  /* convert into static domain change */
1149  SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN), sizeof(SCIP_DOMCHGBOTH)) );
1150  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOTH; /*lint !e641*/
1151  }
1152  break;
1153  default:
1154  SCIPerrorMessage("invalid domain change type\n");
1155  return SCIP_INVALIDDATA;
1156  }
1157 #ifndef NDEBUG
1158  if( *domchg != NULL )
1159  {
1160  int i;
1161  for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1162  assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1163  || SCIPsetIsFeasIntegral(set, (*domchg)->domchgbound.boundchgs[i].newbound));
1164  }
1165 #endif
1166  }
1167 
1168  return SCIP_OKAY;
1169 }
1170 
1171 /** ensures, that boundchgs array can store at least num entries */
1172 static
1174  SCIP_DOMCHG* domchg, /**< domain change data structure */
1175  BMS_BLKMEM* blkmem, /**< block memory */
1176  SCIP_SET* set, /**< global SCIP settings */
1177  int num /**< minimum number of entries to store */
1178  )
1179 {
1180  assert(domchg != NULL);
1181  assert(domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1182 
1183  if( num > domchg->domchgdyn.boundchgssize )
1184  {
1185  int newsize;
1186 
1187  newsize = SCIPsetCalcMemGrowSize(set, num);
1188  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &domchg->domchgdyn.boundchgs, domchg->domchgdyn.boundchgssize, newsize) );
1189  domchg->domchgdyn.boundchgssize = newsize;
1190  }
1191  assert(num <= domchg->domchgdyn.boundchgssize);
1192 
1193  return SCIP_OKAY;
1194 }
1195 
1196 /** ensures, that holechgs array can store at least num additional entries */
1197 static
1199  SCIP_DOMCHG* domchg, /**< domain change data structure */
1200  BMS_BLKMEM* blkmem, /**< block memory */
1201  SCIP_SET* set, /**< global SCIP settings */
1202  int num /**< minimum number of additional entries to store */
1203  )
1204 {
1205  assert(domchg != NULL);
1206  assert(domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1207 
1208  if( num > domchg->domchgdyn.holechgssize )
1209  {
1210  int newsize;
1211 
1212  newsize = SCIPsetCalcMemGrowSize(set, num);
1213  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &domchg->domchgdyn.holechgs, domchg->domchgdyn.holechgssize, newsize) );
1214  domchg->domchgdyn.holechgssize = newsize;
1215  }
1216  assert(num <= domchg->domchgdyn.holechgssize);
1217 
1218  return SCIP_OKAY;
1219 }
1220 
1221 /** applies domain change */
1223  SCIP_DOMCHG* domchg, /**< domain change to apply */
1224  BMS_BLKMEM* blkmem, /**< block memory */
1225  SCIP_SET* set, /**< global SCIP settings */
1226  SCIP_STAT* stat, /**< problem statistics */
1227  SCIP_LP* lp, /**< current LP data */
1228  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1229  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1230  int depth, /**< depth in the tree, where the domain change takes place */
1231  SCIP_Bool* cutoff /**< pointer to store whether an infeasible domain change was detected */
1232  )
1233 {
1234  int i;
1235 
1236  assert(cutoff != NULL);
1237 
1238  *cutoff = FALSE;
1239 
1240  SCIPdebugMessage("applying domain changes at %p in depth %d\n", (void*)domchg, depth);
1241 
1242  if( domchg == NULL )
1243  return SCIP_OKAY;
1244 
1245  /* apply bound changes */
1246  for( i = 0; i < (int)domchg->domchgbound.nboundchgs; ++i )
1247  {
1248  SCIP_CALL( SCIPboundchgApply(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp,
1249  branchcand, eventqueue, depth, i, cutoff) );
1250  if( *cutoff )
1251  break;
1252  }
1253  SCIPdebugMessage(" -> %u bound changes (cutoff %u)\n", domchg->domchgbound.nboundchgs, *cutoff);
1254 
1255  /* mark all bound changes after a cutoff redundant */
1256  for( ; i < (int)domchg->domchgbound.nboundchgs; ++i )
1257  domchg->domchgbound.boundchgs[i].redundant = TRUE;
1258 
1259  /* apply holelist changes */
1260  if( domchg->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_BOUND ) /*lint !e641*/
1261  {
1262  for( i = 0; i < domchg->domchgboth.nholechgs; ++i )
1263  *(domchg->domchgboth.holechgs[i].ptr) = domchg->domchgboth.holechgs[i].newlist;
1264  SCIPdebugMessage(" -> %d hole changes\n", domchg->domchgboth.nholechgs);
1265  }
1266 
1267  return SCIP_OKAY;
1268 }
1269 
1270 /** undoes domain change */
1272  SCIP_DOMCHG* domchg, /**< domain change to remove */
1273  BMS_BLKMEM* blkmem, /**< block memory */
1274  SCIP_SET* set, /**< global SCIP settings */
1275  SCIP_STAT* stat, /**< problem statistics */
1276  SCIP_LP* lp, /**< current LP data */
1277  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1278  SCIP_EVENTQUEUE* eventqueue /**< event queue */
1279  )
1280 {
1281  int i;
1282 
1283  SCIPdebugMessage("undoing domain changes at %p\n", (void*)domchg);
1284  if( domchg == NULL )
1285  return SCIP_OKAY;
1286 
1287  /* undo holelist changes */
1288  if( domchg->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_BOUND ) /*lint !e641*/
1289  {
1290  for( i = domchg->domchgboth.nholechgs-1; i >= 0; --i )
1291  *(domchg->domchgboth.holechgs[i].ptr) = domchg->domchgboth.holechgs[i].oldlist;
1292  SCIPdebugMessage(" -> %d hole changes\n", domchg->domchgboth.nholechgs);
1293  }
1294 
1295  /* undo bound changes */
1296  for( i = domchg->domchgbound.nboundchgs-1; i >= 0; --i )
1297  {
1298  SCIP_CALL( SCIPboundchgUndo(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp, branchcand, eventqueue) );
1299  }
1300  SCIPdebugMessage(" -> %u bound changes\n", domchg->domchgbound.nboundchgs);
1301 
1302  return SCIP_OKAY;
1303 }
1304 
1305 /** applies domain change to the global problem */
1307  SCIP_DOMCHG* domchg, /**< domain change to apply */
1308  BMS_BLKMEM* blkmem, /**< block memory */
1309  SCIP_SET* set, /**< global SCIP settings */
1310  SCIP_STAT* stat, /**< problem statistics */
1311  SCIP_LP* lp, /**< current LP data */
1312  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1313  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1314  SCIP_Bool* cutoff /**< pointer to store whether an infeasible domain change was detected */
1315  )
1316 {
1317  int i;
1318 
1319  assert(cutoff != NULL);
1320 
1321  *cutoff = FALSE;
1322 
1323  if( domchg == NULL )
1324  return SCIP_OKAY;
1325 
1326  SCIPdebugMessage("applying domain changes at %p to the global problem\n", (void*)domchg);
1327 
1328  /* apply bound changes */
1329  for( i = 0; i < (int)domchg->domchgbound.nboundchgs; ++i )
1330  {
1331  SCIP_CALL( boundchgApplyGlobal(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp,
1332  branchcand, eventqueue, cutoff) );
1333  if( *cutoff )
1334  break;
1335  }
1336  SCIPdebugMessage(" -> %u global bound changes\n", domchg->domchgbound.nboundchgs);
1337 
1338  /**@todo globally apply holelist changes - how can this be done without confusing pointer updates? */
1339 
1340  return SCIP_OKAY;
1341 }
1342 
1343 /** adds bound change to domain changes */
1345  SCIP_DOMCHG** domchg, /**< pointer to domain change data structure */
1346  BMS_BLKMEM* blkmem, /**< block memory */
1347  SCIP_SET* set, /**< global SCIP settings */
1348  SCIP_VAR* var, /**< variable to change the bounds for */
1349  SCIP_Real newbound, /**< new value for bound */
1350  SCIP_BOUNDTYPE boundtype, /**< type of bound for var: lower or upper bound */
1351  SCIP_BOUNDCHGTYPE boundchgtype, /**< type of bound change: branching decision or inference */
1352  SCIP_Real lpsolval, /**< solval of variable in last LP on path to node, or SCIP_INVALID if unknown */
1353  SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself), or NULL */
1354  SCIP_CONS* infercons, /**< constraint that deduced the bound change, or NULL */
1355  SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
1356  int inferinfo, /**< user information for inference to help resolving the conflict */
1357  SCIP_BOUNDTYPE inferboundtype /**< type of bound for inference var: lower or upper bound */
1358  )
1359 {
1360  SCIP_BOUNDCHG* boundchg;
1361 
1362  assert(domchg != NULL);
1363  assert(var != NULL);
1365  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
1366  assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, boundtype == SCIP_BOUNDTYPE_LOWER ? 1.0 : 0.0));
1367  assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
1368  assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
1369  assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
1370 
1371  SCIPdebugMessage("adding %s bound change <%s: %g> of variable <%s> to domain change at %p pointing to %p\n",
1372  boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper",
1373  boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
1374  newbound, var->name, (void*)domchg, (void*)*domchg);
1375 
1376  /* if domain change data doesn't exist, create it;
1377  * if domain change is static, convert it into dynamic change
1378  */
1379  if( *domchg == NULL )
1380  {
1381  SCIP_CALL( domchgCreate(domchg, blkmem) );
1382  }
1383  else if( (*domchg)->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_DYNAMIC ) /*lint !e641*/
1384  {
1385  SCIP_CALL( domchgMakeDynamic(domchg, blkmem) );
1386  }
1387  assert(*domchg != NULL && (*domchg)->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1388 
1389  /* get memory for additional bound change */
1390  SCIP_CALL( domchgEnsureBoundchgsSize(*domchg, blkmem, set, (*domchg)->domchgdyn.nboundchgs+1) );
1391 
1392  /* fill in the bound change data */
1393  boundchg = &(*domchg)->domchgdyn.boundchgs[(*domchg)->domchgdyn.nboundchgs];
1394  boundchg->var = var;
1395  switch( boundchgtype )
1396  {
1398  boundchg->data.branchingdata.lpsolval = lpsolval;
1399  break;
1401  assert(infercons != NULL);
1402  boundchg->data.inferencedata.var = infervar;
1403  boundchg->data.inferencedata.reason.cons = infercons;
1404  boundchg->data.inferencedata.info = inferinfo;
1405  break;
1407  boundchg->data.inferencedata.var = infervar;
1408  boundchg->data.inferencedata.reason.prop = inferprop;
1409  boundchg->data.inferencedata.info = inferinfo;
1410  break;
1411  default:
1412  SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
1413  return SCIP_INVALIDDATA;
1414  }
1415 
1416  boundchg->newbound = newbound;
1417  boundchg->boundchgtype = boundchgtype; /*lint !e641*/
1418  boundchg->boundtype = boundtype; /*lint !e641*/
1419  boundchg->inferboundtype = inferboundtype; /*lint !e641*/
1420  boundchg->applied = FALSE;
1421  boundchg->redundant = FALSE;
1422  (*domchg)->domchgdyn.nboundchgs++;
1423 
1424  /* capture branching and inference data associated with the bound changes */
1425  SCIP_CALL( boundchgCaptureData(boundchg) );
1426 
1427 #if 0
1428 #ifndef NDEBUG
1429  {
1430  int i;
1431  for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1432  assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1433  || SCIPsetIsFeasIntegral(set, (*domchg)->domchgbound.boundchgs[i].newbound));
1434  }
1435 #endif
1436 #endif
1437 
1438  return SCIP_OKAY;
1439 }
1440 
1441 /** adds hole change to domain changes */
1443  SCIP_DOMCHG** domchg, /**< pointer to domain change data structure */
1444  BMS_BLKMEM* blkmem, /**< block memory */
1445  SCIP_SET* set, /**< global SCIP settings */
1446  SCIP_HOLELIST** ptr, /**< changed list pointer */
1447  SCIP_HOLELIST* newlist, /**< new value of list pointer */
1448  SCIP_HOLELIST* oldlist /**< old value of list pointer */
1449  )
1450 {
1451  SCIP_HOLECHG* holechg;
1452 
1453  assert(domchg != NULL);
1454  assert(ptr != NULL);
1455 
1456  /* if domain change data doesn't exist, create it;
1457  * if domain change is static, convert it into dynamic change
1458  */
1459  if( *domchg == NULL )
1460  {
1461  SCIP_CALL( domchgCreate(domchg, blkmem) );
1462  }
1463  else if( (*domchg)->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_DYNAMIC ) /*lint !e641*/
1464  {
1465  SCIP_CALL( domchgMakeDynamic(domchg, blkmem) );
1466  }
1467  assert(*domchg != NULL && (*domchg)->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1468 
1469  /* get memory for additional hole change */
1470  SCIP_CALL( domchgEnsureHolechgsSize(*domchg, blkmem, set, (*domchg)->domchgdyn.nholechgs+1) );
1471 
1472  /* fill in the hole change data */
1473  holechg = &(*domchg)->domchgdyn.holechgs[(*domchg)->domchgdyn.nholechgs];
1474  holechg->ptr = ptr;
1475  holechg->newlist = newlist;
1476  holechg->oldlist = oldlist;
1477  (*domchg)->domchgdyn.nholechgs++;
1478 
1479  return SCIP_OKAY;
1480 }
1481 
1482 
1483 
1484 
1485 /*
1486  * methods for variables
1487  */
1488 
1489 /** returns adjusted lower bound value, which is rounded for integral variable types */
1490 static
1492  SCIP_SET* set, /**< global SCIP settings */
1493  SCIP_VARTYPE vartype, /**< type of variable */
1494  SCIP_Real lb /**< lower bound to adjust */
1495  )
1496 {
1497  if( lb < 0 && SCIPsetIsInfinity(set, -lb) )
1498  return -SCIPsetInfinity(set);
1499  else if( lb > 0 && SCIPsetIsInfinity(set, lb) )
1500  return SCIPsetInfinity(set);
1501  else if( vartype != SCIP_VARTYPE_CONTINUOUS )
1502  return SCIPsetFeasCeil(set, lb);
1503  else if( SCIPsetIsZero(set, lb) )
1504  return 0.0;
1505  else
1506  return lb;
1507 }
1508 
1509 /** returns adjusted upper bound value, which is rounded for integral variable types */
1510 static
1512  SCIP_SET* set, /**< global SCIP settings */
1513  SCIP_VARTYPE vartype, /**< type of variable */
1514  SCIP_Real ub /**< upper bound to adjust */
1515  )
1516 {
1517  if( ub > 0 && SCIPsetIsInfinity(set, ub) )
1518  return SCIPsetInfinity(set);
1519  else if( ub < 0 && SCIPsetIsInfinity(set, -ub) )
1520  return -SCIPsetInfinity(set);
1521  else if( vartype != SCIP_VARTYPE_CONTINUOUS )
1522  return SCIPsetFeasFloor(set, ub);
1523  else if( SCIPsetIsZero(set, ub) )
1524  return 0.0;
1525  else
1526  return ub;
1527 }
1528 
1529 /* removes (redundant) implications and variable bounds of variable from all other variables' implications and variable
1530  * bounds arrays, and optionally removes them also from the variable itself
1531  */
1532 static
1534  SCIP_VAR* var, /**< problem variable */
1535  BMS_BLKMEM* blkmem, /**< block memory */
1536  SCIP_SET* set, /**< global SCIP settings */
1537  SCIP_Bool onlyredundant, /**< should only the redundant implications and variable bounds be removed? */
1538  SCIP_Bool removefromvar /**< should the implications and variable bounds be removed from the var itself? */
1539  )
1540 {
1541  SCIP_Real lb;
1542  SCIP_Real ub;
1543 
1544  assert(var != NULL);
1546  assert(SCIPvarIsActive(var) || SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
1547 
1548  lb = SCIPvarGetLbGlobal(var);
1549  ub = SCIPvarGetUbGlobal(var);
1550 
1551  SCIPdebugMessage("removing %s implications and vbounds of <%s>[%g,%g]\n",
1552  onlyredundant ? "redundant" : "all", SCIPvarGetName(var), lb, ub);
1553 
1554  /* remove implications of (fixed) binary variable */
1555  if( var->implics != NULL && (!onlyredundant || lb > 0.5 || ub < 0.5) )
1556  {
1557  SCIP_Bool varfixing;
1558 
1559  assert(SCIPvarIsBinary(var));
1560 
1561  varfixing = FALSE;
1562  do
1563  {
1564  int nimpls;
1565  int nbinimpls;
1566  SCIP_VAR** implvars;
1567  SCIP_BOUNDTYPE* impltypes;
1568  int i;
1569 
1570  nimpls = SCIPimplicsGetNImpls(var->implics, varfixing);
1571  nbinimpls = SCIPimplicsGetNBinImpls(var->implics, varfixing);
1572  implvars = SCIPimplicsGetVars(var->implics, varfixing);
1573  impltypes = SCIPimplicsGetTypes(var->implics, varfixing);
1574 
1575  /* process the implications on binary variables */
1576  for( i = 0; i < nbinimpls; i++ )
1577  {
1578  SCIP_VAR* implvar;
1579  SCIP_BOUNDTYPE impltype;
1580 
1581  implvar = implvars[i];
1582  impltype = impltypes[i];
1583  assert(implvar != var);
1584  assert(SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY);
1585 
1586  /* remove for all implications z == 0 / 1 ==> x <= 0 / x >= 1 (x binary)
1587  * the following implication from x's implications
1588  * x == 1 ==> z <= 0 , for z == 1 ==> x <= 0
1589  * x == 0 ==> z <= 0 , for z == 1 ==> x >= 1
1590  *
1591  * x == 1 ==> z >= 1 , for z == 0 ==> x <= 0
1592  * x == 0 ==> z >= 1 , for z == 0 ==> x >= 1
1593  */
1594  if( implvar->implics != NULL ) /* implvar may have been aggregated in the mean time */
1595  {
1596  SCIPdebugMessage("deleting implication: <%s> == %d ==> <%s> %s\n",
1597  SCIPvarGetName(implvar), (impltype == SCIP_BOUNDTYPE_UPPER),
1598  SCIPvarGetName(var), varfixing ? "<= 0 " : ">= 1");
1599  SCIP_CALL( SCIPimplicsDel(&implvar->implics, blkmem, set, (impltype == SCIP_BOUNDTYPE_UPPER), var,
1600  varfixing ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER) );
1601  }
1602  }
1603 
1604  /* process the implications on non-binary variables */
1605  for( i = nbinimpls; i < nimpls; i++ )
1606  {
1607  SCIP_VAR* implvar;
1608  SCIP_BOUNDTYPE impltype;
1609 
1610  implvar = implvars[i];
1611  impltype = impltypes[i];
1612  assert(implvar != var);
1613  assert(SCIPvarGetType(implvar) != SCIP_VARTYPE_BINARY);
1614 
1615  /* remove for all implications z == 0 / 1 ==> x <= p / x >= p (x not binary)
1616  * the following variable bound from x's variable bounds
1617  * x <= b*z+d (z in vubs of x) , for z == 0 / 1 ==> x <= p
1618  * x >= b*z+d (z in vlbs of x) , for z == 0 / 1 ==> x >= p
1619  */
1620  if( impltype == SCIP_BOUNDTYPE_UPPER )
1621  {
1622  if( implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1623  {
1624  SCIPdebugMessage("deleting variable bound: <%s> == %u ==> <%s> <= %g\n",
1625  SCIPvarGetName(var), varfixing, SCIPvarGetName(implvar),
1626  SCIPimplicsGetBounds(var->implics, varfixing)[i]);
1627  SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, varfixing) );
1628  implvar->closestvblpcount = -1;
1629  var->closestvblpcount = -1;
1630  }
1631  }
1632  else
1633  {
1634  if( implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1635  {
1636  SCIPdebugMessage("deleting variable bound: <%s> == %u ==> <%s> >= %g\n",
1637  SCIPvarGetName(var), varfixing, SCIPvarGetName(implvar),
1638  SCIPimplicsGetBounds(var->implics, varfixing)[i]);
1639  SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, !varfixing) );
1640  implvar->closestvblpcount = -1;
1641  var->closestvblpcount = -1;
1642  }
1643  }
1644  }
1645  varfixing = !varfixing;
1646  }
1647  while( varfixing == TRUE );
1648 
1649  if( removefromvar )
1650  {
1651  /* free the implications data structures */
1652  SCIPimplicsFree(&var->implics, blkmem);
1653  }
1654  }
1655 
1656  /* remove the (redundant) variable lower bounds */
1657  if( var->vlbs != NULL )
1658  {
1659  SCIP_VAR** vars;
1660  SCIP_Real* coefs;
1661  SCIP_Real* constants;
1662  int nvbds;
1663  int newnvbds;
1664  int i;
1665 
1666  nvbds = SCIPvboundsGetNVbds(var->vlbs);
1667  vars = SCIPvboundsGetVars(var->vlbs);
1668  coefs = SCIPvboundsGetCoefs(var->vlbs);
1669  constants = SCIPvboundsGetConstants(var->vlbs);
1670 
1671  /* remove for all variable bounds x >= b*z+d the following implication from z's implications
1672  * z == ub ==> x >= b*ub + d , if b > 0
1673  * z == lb ==> x >= b*lb + d , if b < 0
1674  */
1675  newnvbds = 0;
1676  for( i = 0; i < nvbds; i++ )
1677  {
1678  SCIP_VAR* implvar;
1679  SCIP_Real coef;
1680 
1681  assert(newnvbds <= i);
1682 
1683  implvar = vars[i];
1684  assert(implvar != NULL);
1685 
1686  coef = coefs[i];
1687  assert(!SCIPsetIsZero(set, coef));
1688 
1689  /* check, if we want to remove the variable bound */
1690  if( onlyredundant )
1691  {
1692  SCIP_Real vbound;
1693 
1694  vbound = MAX(coef * SCIPvarGetUbGlobal(implvar), coef * SCIPvarGetLbGlobal(implvar)) + constants[i]; /*lint !e666*/
1695  if( SCIPsetIsFeasGT(set, vbound, lb) )
1696  {
1697  /* the variable bound is not redundant: keep it */
1698  if( removefromvar )
1699  {
1700  if( newnvbds < i )
1701  {
1702  vars[newnvbds] = implvar;
1703  coefs[newnvbds] = coef;
1704  constants[newnvbds] = constants[i];
1705  }
1706  newnvbds++;
1707  }
1708  continue;
1709  }
1710  }
1711 
1712  /* remove the corresponding implication */
1713  if( implvar->implics != NULL ) /* variable may have been aggregated in the mean time */
1714  {
1715  SCIPdebugMessage("deleting implication: <%s> == %d ==> <%s> >= %g\n",
1716  SCIPvarGetName(implvar), (coef > 0.0), SCIPvarGetName(var), MAX(coef, 0.0) + constants[i]);
1717  SCIP_CALL( SCIPimplicsDel(&implvar->implics, blkmem, set, (coef > 0.0), var, SCIP_BOUNDTYPE_LOWER) );
1718  }
1719  if( coef > 0.0 && implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1720  {
1721  SCIPdebugMessage("deleting variable upper bound from <%s> involving variable %s\n",
1722  SCIPvarGetName(implvar), SCIPvarGetName(var));
1723  SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, FALSE) );
1724  implvar->closestvblpcount = -1;
1725  var->closestvblpcount = -1;
1726  }
1727  else if( coef < 0.0 && implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1728  {
1729  SCIPdebugMessage("deleting variable lower bound from <%s> involving variable %s\n",
1730  SCIPvarGetName(implvar), SCIPvarGetName(var));
1731  SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, TRUE) );
1732  implvar->closestvblpcount = -1;
1733  var->closestvblpcount = -1;
1734  }
1735  }
1736 
1737  if( removefromvar )
1738  {
1739  /* update the number of variable bounds */
1740  SCIPvboundsShrink(&var->vlbs, blkmem, newnvbds);
1741  var->closestvblpcount = -1;
1742  }
1743  }
1744 
1745  /**@todo in general, variable bounds like x >= b*z + d corresponding to an implication like z = ub ==> x >= b*ub + d
1746  * might be missing because we only add variable bounds with reasonably small value of b. thus, we currently
1747  * cannot remove such variables x from z's implications.
1748  */
1749 
1750  /* remove the (redundant) variable upper bounds */
1751  if( var->vubs != NULL )
1752  {
1753  SCIP_VAR** vars;
1754  SCIP_Real* coefs;
1755  SCIP_Real* constants;
1756  int nvbds;
1757  int newnvbds;
1758  int i;
1759 
1760  nvbds = SCIPvboundsGetNVbds(var->vubs);
1761  vars = SCIPvboundsGetVars(var->vubs);
1762  coefs = SCIPvboundsGetCoefs(var->vubs);
1763  constants = SCIPvboundsGetConstants(var->vubs);
1764 
1765  /* remove for all variable bounds x <= b*z+d the following implication from z's implications
1766  * z == lb ==> x <= b*lb + d , if b > 0
1767  * z == ub ==> x <= b*ub + d , if b < 0
1768  */
1769  newnvbds = 0;
1770  for( i = 0; i < nvbds; i++ )
1771  {
1772  SCIP_VAR* implvar;
1773  SCIP_Real coef;
1774 
1775  assert(newnvbds <= i);
1776 
1777  implvar = vars[i];
1778  assert(implvar != NULL);
1779 
1780  coef = coefs[i];
1781  assert(!SCIPsetIsZero(set, coef));
1782 
1783  /* check, if we want to remove the variable bound */
1784  if( onlyredundant )
1785  {
1786  SCIP_Real vbound;
1787 
1788  vbound = MIN(coef * SCIPvarGetUbGlobal(implvar), coef * SCIPvarGetLbGlobal(implvar)) + constants[i]; /*lint !e666*/
1789  if( SCIPsetIsFeasLT(set, vbound, ub) )
1790  {
1791  /* the variable bound is not redundant: keep it */
1792  if( removefromvar )
1793  {
1794  if( newnvbds < i )
1795  {
1796  vars[newnvbds] = implvar;
1797  coefs[newnvbds] = coefs[i];
1798  constants[newnvbds] = constants[i];
1799  }
1800  newnvbds++;
1801  }
1802  continue;
1803  }
1804  }
1805 
1806  /* remove the corresponding implication */
1807  if( implvar->implics != NULL ) /* variable may have been aggregated in the mean time */
1808  {
1809  SCIPdebugMessage("deleting implication: <%s> == %d ==> <%s> <= %g\n",
1810  SCIPvarGetName(implvar), (coef < 0.0), SCIPvarGetName(var), MIN(coef, 0.0) + constants[i]);
1811  SCIP_CALL( SCIPimplicsDel(&implvar->implics, blkmem, set, (coef < 0.0), var, SCIP_BOUNDTYPE_UPPER) );
1812  }
1813  if( coef < 0.0 && implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1814  {
1815  SCIPdebugMessage("deleting variable upper bound from <%s> involving variable %s\n",
1816  SCIPvarGetName(implvar), SCIPvarGetName(var));
1817  SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, TRUE) );
1818  implvar->closestvblpcount = -1;
1819  var->closestvblpcount = -1;
1820  }
1821  else if( coef > 0.0 && implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1822  {
1823  SCIPdebugMessage("deleting variable lower bound from <%s> involving variable %s\n",
1824  SCIPvarGetName(implvar), SCIPvarGetName(var));
1825  SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, FALSE) );
1826  implvar->closestvblpcount = -1;
1827  var->closestvblpcount = -1;
1828  }
1829  }
1830 
1831  if( removefromvar )
1832  {
1833  /* update the number of variable bounds */
1834  SCIPvboundsShrink(&var->vubs, blkmem, newnvbds);
1835  var->closestvblpcount = -1;
1836  }
1837  }
1838 
1839  /**@todo variable bounds like x <= b*z + d with z general integer are not removed from x's vbd arrays, because
1840  * z has no link (like in the binary case) to x
1841  */
1842 
1843  return SCIP_OKAY;
1844 }
1845 
1846 /** sets the variable name */
1847 static
1849  SCIP_VAR* var, /**< problem variable */
1850  BMS_BLKMEM* blkmem, /**< block memory */
1851  SCIP_STAT* stat, /**< problem statistics, or NULL */
1852  const char* name /**< name of variable, or NULL for automatic name creation */
1853  )
1854 {
1855  assert(blkmem != NULL);
1856  assert(var != NULL);
1857 
1858  if( name == NULL )
1859  {
1860  char s[SCIP_MAXSTRLEN];
1861 
1862  assert(stat != NULL);
1863 
1864  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "_var%d_", stat->nvaridx);
1865  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->name, s, strlen(s)+1) );
1866  }
1867  else
1868  {
1869  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->name, name, strlen(name)+1) );
1870  }
1871 
1872  return SCIP_OKAY;
1873 }
1874 
1875 
1876 /** creates variable; if variable is of integral type, fractional bounds are automatically rounded; an integer variable
1877  * with bounds zero and one is automatically converted into a binary variable
1878  */
1879 static
1881  SCIP_VAR** var, /**< pointer to variable data */
1882  BMS_BLKMEM* blkmem, /**< block memory */
1883  SCIP_SET* set, /**< global SCIP settings */
1884  SCIP_STAT* stat, /**< problem statistics */
1885  const char* name, /**< name of variable, or NULL for automatic name creation */
1886  SCIP_Real lb, /**< lower bound of variable */
1887  SCIP_Real ub, /**< upper bound of variable */
1888  SCIP_Real obj, /**< objective function value */
1889  SCIP_VARTYPE vartype, /**< type of variable */
1890  SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
1891  SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
1892  SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
1893  SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */
1894  SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */
1895  SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */
1896  SCIP_VARDATA* vardata /**< user data for this specific variable */
1897  )
1898 {
1899  assert(var != NULL);
1900  assert(blkmem != NULL);
1901  assert(stat != NULL);
1902 
1903  /* adjust bounds of variable */
1904  lb = adjustedLb(set, vartype, lb);
1905  ub = adjustedUb(set, vartype, ub);
1906 
1907  /* convert [0,1]-integers into binary variables and check that binary variables have correct bounds */
1908  if( (SCIPsetIsEQ(set, lb, 0.0) || SCIPsetIsEQ(set, lb, 1.0))
1909  && (SCIPsetIsEQ(set, ub, 0.0) || SCIPsetIsEQ(set, ub, 1.0)) )
1910  {
1911  if( vartype == SCIP_VARTYPE_INTEGER )
1912  vartype = SCIP_VARTYPE_BINARY;
1913  }
1914  else
1915  {
1916  if( vartype == SCIP_VARTYPE_BINARY )
1917  {
1918  SCIPerrorMessage("invalid bounds [%.2g,%.2g] for binary variable <%s>\n", lb, ub, name);
1919  return SCIP_INVALIDDATA;
1920  }
1921  }
1922 
1923  assert(vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, lb, 0.0) || SCIPsetIsEQ(set, lb, 1.0));
1924  assert(vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, ub, 0.0) || SCIPsetIsEQ(set, ub, 1.0));
1925 
1926  SCIP_ALLOC( BMSallocBlockMemory(blkmem, var) );
1927 
1928  /* set variable's name */
1929  SCIP_CALL( varSetName(*var, blkmem, stat, name) );
1930 
1931 #ifndef NDEBUG
1932  (*var)->scip = set->scip;
1933 #endif
1934  (*var)->obj = obj;
1935  (*var)->branchfactor = 1.0;
1936  (*var)->rootsol = 0.0;
1937  (*var)->bestrootsol = 0.0;
1938  (*var)->bestrootredcost = 0.0;
1939  (*var)->bestrootlpobjval = SCIP_INVALID;
1940  (*var)->relaxsol = 0.0;
1941  (*var)->nlpsol = 0.0;
1942  (*var)->primsolavg = 0.5 * (lb + ub);
1943  (*var)->conflictlb = SCIP_REAL_MIN;
1944  (*var)->conflictub = SCIP_REAL_MAX;
1945  (*var)->conflictrelaxedlb = (*var)->conflictlb;
1946  (*var)->conflictrelaxedub = (*var)->conflictub;
1947  (*var)->lazylb = -SCIPsetInfinity(set);
1948  (*var)->lazyub = SCIPsetInfinity(set);
1949  (*var)->glbdom.holelist = NULL;
1950  (*var)->glbdom.lb = lb;
1951  (*var)->glbdom.ub = ub;
1952  (*var)->locdom.holelist = NULL;
1953  (*var)->locdom.lb = lb;
1954  (*var)->locdom.ub = ub;
1955  (*var)->varcopy = varcopy;
1956  (*var)->vardelorig = vardelorig;
1957  (*var)->vartrans = vartrans;
1958  (*var)->vardeltrans = vardeltrans;
1959  (*var)->vardata = vardata;
1960  (*var)->parentvars = NULL;
1961  (*var)->negatedvar = NULL;
1962  (*var)->vlbs = NULL;
1963  (*var)->vubs = NULL;
1964  (*var)->implics = NULL;
1965  (*var)->cliquelist = NULL;
1966  (*var)->eventfilter = NULL;
1967  (*var)->lbchginfos = NULL;
1968  (*var)->ubchginfos = NULL;
1969  (*var)->index = stat->nvaridx;
1970  (*var)->probindex = -1;
1971  (*var)->pseudocandindex = -1;
1972  (*var)->eventqueueindexobj = -1;
1973  (*var)->eventqueueindexlb = -1;
1974  (*var)->eventqueueindexub = -1;
1975  (*var)->parentvarssize = 0;
1976  (*var)->nparentvars = 0;
1977  (*var)->nuses = 0;
1978  (*var)->nlocksdown = 0;
1979  (*var)->nlocksup = 0;
1980  (*var)->branchpriority = 0;
1981  (*var)->branchdirection = SCIP_BRANCHDIR_AUTO; /*lint !e641*/
1982  (*var)->lbchginfossize = 0;
1983  (*var)->nlbchginfos = 0;
1984  (*var)->ubchginfossize = 0;
1985  (*var)->nubchginfos = 0;
1986  (*var)->conflictlbcount = 0;
1987  (*var)->conflictubcount = 0;
1988  (*var)->closestvlbidx = -1;
1989  (*var)->closestvubidx = -1;
1990  (*var)->closestvblpcount = -1;
1991  (*var)->initial = initial;
1992  (*var)->removable = removable;
1993  (*var)->deleted = FALSE;
1994  (*var)->donotmultaggr = FALSE;
1995  (*var)->vartype = vartype; /*lint !e641*/
1996  (*var)->pseudocostflag = FALSE;
1997  (*var)->eventqueueimpl = FALSE;
1998  (*var)->deletable = FALSE;
1999  stat->nvaridx++;
2000 
2001  /* create branching and inference history entries */
2002  SCIP_CALL( SCIPhistoryCreate(&(*var)->history, blkmem) );
2003  SCIP_CALL( SCIPhistoryCreate(&(*var)->historycrun, blkmem) );
2004 
2005  /* the value based history is only created on demand */
2006  (*var)->valuehistory = NULL;
2007 
2008  return SCIP_OKAY;
2009 }
2010 
2011 /** creates and captures an original problem variable; an integer variable with bounds
2012  * zero and one is automatically converted into a binary variable
2013  */
2015  SCIP_VAR** var, /**< pointer to variable data */
2016  BMS_BLKMEM* blkmem, /**< block memory */
2017  SCIP_SET* set, /**< global SCIP settings */
2018  SCIP_STAT* stat, /**< problem statistics */
2019  const char* name, /**< name of variable, or NULL for automatic name creation */
2020  SCIP_Real lb, /**< lower bound of variable */
2021  SCIP_Real ub, /**< upper bound of variable */
2022  SCIP_Real obj, /**< objective function value */
2023  SCIP_VARTYPE vartype, /**< type of variable */
2024  SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2025  SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2026  SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */
2027  SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */
2028  SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */
2029  SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2030  SCIP_VARDATA* vardata /**< user data for this specific variable */
2031  )
2032 {
2033  assert(var != NULL);
2034  assert(blkmem != NULL);
2035  assert(stat != NULL);
2036 
2037  /* create variable */
2038  SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2039  varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2040 
2041  /* set variable status and data */
2042  (*var)->varstatus = SCIP_VARSTATUS_ORIGINAL; /*lint !e641*/
2043  (*var)->data.original.origdom.holelist = NULL;
2044  (*var)->data.original.origdom.lb = lb;
2045  (*var)->data.original.origdom.ub = ub;
2046  (*var)->data.original.transvar = NULL;
2047 
2048  /* capture variable */
2049  SCIPvarCapture(*var);
2050 
2051  return SCIP_OKAY;
2052 }
2053 
2054 /** creates and captures a loose variable belonging to the transformed problem; an integer variable with bounds
2055  * zero and one is automatically converted into a binary variable
2056  */
2058  SCIP_VAR** var, /**< pointer to variable data */
2059  BMS_BLKMEM* blkmem, /**< block memory */
2060  SCIP_SET* set, /**< global SCIP settings */
2061  SCIP_STAT* stat, /**< problem statistics */
2062  const char* name, /**< name of variable, or NULL for automatic name creation */
2063  SCIP_Real lb, /**< lower bound of variable */
2064  SCIP_Real ub, /**< upper bound of variable */
2065  SCIP_Real obj, /**< objective function value */
2066  SCIP_VARTYPE vartype, /**< type of variable */
2067  SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2068  SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2069  SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */
2070  SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */
2071  SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */
2072  SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2073  SCIP_VARDATA* vardata /**< user data for this specific variable */
2074  )
2075 {
2076  assert(var != NULL);
2077  assert(blkmem != NULL);
2078 
2079  /* create variable */
2080  SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2081  varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2082 
2083  /* create event filter for transformed variable */
2084  SCIP_CALL( SCIPeventfilterCreate(&(*var)->eventfilter, blkmem) );
2085 
2086  /* set variable status and data */
2087  (*var)->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
2088 
2089  /* capture variable */
2090  SCIPvarCapture(*var);
2091 
2092  return SCIP_OKAY;
2093 }
2094 
2095 /** copies and captures a variable from source to target SCIP; an integer variable with bounds zero and one is
2096  * automatically converted into a binary variable; in case the variable data cannot be copied the variable is not
2097  * copied at all
2098  */
2100  SCIP_VAR** var, /**< pointer to store the target variable */
2101  BMS_BLKMEM* blkmem, /**< block memory */
2102  SCIP_SET* set, /**< global SCIP settings */
2103  SCIP_STAT* stat, /**< problem statistics */
2104  SCIP* sourcescip, /**< source SCIP data structure */
2105  SCIP_VAR* sourcevar, /**< source variable */
2106  SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of source variables corresponding
2107  * target variables */
2108  SCIP_HASHMAP* consmap, /**< a hashmap to store the mapping of source constraints to the corresponding
2109  * target constraints */
2110  SCIP_Bool global /**< should global or local bounds be used? */
2111  )
2112 {
2113  SCIP_VARDATA* targetdata;
2114  SCIP_RESULT result;
2115  SCIP_Real lb;
2116  SCIP_Real ub;
2117 
2118  assert(set != NULL);
2119  assert(blkmem != NULL);
2120  assert(stat != NULL);
2121  assert(sourcescip != NULL);
2122  assert(sourcevar != NULL);
2123  assert(var != NULL);
2124  assert(set->stage == SCIP_STAGE_PROBLEM);
2125  assert(varmap != NULL);
2126  assert(consmap != NULL);
2127 
2128  /** @todo copy hole lists */
2129  assert(global || SCIPvarGetHolelistLocal(sourcevar) == NULL);
2130  assert(!global || SCIPvarGetHolelistGlobal(sourcevar) == NULL);
2131 
2132  result = SCIP_DIDNOTRUN;
2133  targetdata = NULL;
2134 
2135  if( SCIPvarGetStatus(sourcevar) == SCIP_VARSTATUS_ORIGINAL )
2136  {
2137  lb = SCIPvarGetLbOriginal(sourcevar);
2138  ub = SCIPvarGetUbOriginal(sourcevar);
2139  }
2140  else
2141  {
2142  lb = global ? SCIPvarGetLbGlobal(sourcevar) : SCIPvarGetLbLocal(sourcevar);
2143  ub = global ? SCIPvarGetUbGlobal(sourcevar) : SCIPvarGetUbLocal(sourcevar);
2144  }
2145 
2146  /* creates and captures the variable in the target SCIP and initialize callback methods and variable data to NULL */
2147  SCIP_CALL( SCIPvarCreateOriginal(var, blkmem, set, stat, SCIPvarGetName(sourcevar),
2148  lb, ub, SCIPvarGetObj(sourcevar), SCIPvarGetType(sourcevar),
2149  SCIPvarIsInitial(sourcevar), SCIPvarIsRemovable(sourcevar),
2150  NULL, NULL, NULL, NULL, NULL) );
2151  assert(*var != NULL);
2152 
2153  /* insert variable into mapping between source SCIP and the target SCIP */
2154  assert(!SCIPhashmapExists(varmap, sourcevar));
2155  SCIP_CALL( SCIPhashmapInsert(varmap, sourcevar, *var) );
2156 
2157  /* in case there exists variable data and the variable data copy callback, try to copy variable data */
2158  if( sourcevar->vardata != NULL && sourcevar->varcopy != NULL )
2159  {
2160  SCIP_CALL( sourcevar->varcopy(set->scip, sourcescip, sourcevar, sourcevar->vardata,
2161  varmap, consmap, (*var), &targetdata, &result) );
2162 
2163  /* evaluate result */
2164  if( result != SCIP_DIDNOTRUN && result != SCIP_SUCCESS )
2165  {
2166  SCIPerrorMessage("variable data copying method returned invalid result <%d>\n", result);
2167  return SCIP_INVALIDRESULT;
2168  }
2169 
2170  assert(targetdata == NULL || result == SCIP_SUCCESS);
2171  }
2172 
2173  /* in case the copying was successfully, add the created variable data to the variable as well as all callback
2174  * methods
2175  */
2176  if( result == SCIP_SUCCESS )
2177  {
2178  (*var)->varcopy = sourcevar->varcopy;
2179  (*var)->vardelorig = sourcevar->vardelorig;
2180  (*var)->vartrans = sourcevar->vartrans;
2181  (*var)->vardeltrans = sourcevar->vardeltrans;
2182  (*var)->vardata = targetdata;
2183  }
2184 
2185  SCIPdebugMessage("created copy <%s> of variable <%s>\n", SCIPvarGetName(*var), SCIPvarGetName(sourcevar));
2186 
2187  return SCIP_OKAY;
2188 }
2189 
2190 /** parse given string for a SCIP_Real bound */
2191 static
2193  SCIP_SET* set, /**< global SCIP settings */
2194  const char* str, /**< string to parse */
2195  SCIP_Real* value, /**< pointer to store the parsed value */
2196  char** endptr /**< pointer to store the final string position if successfully parsed */
2197  )
2198 {
2199  /* first check for infinity value */
2200  if( strncmp(str, "+inf", 4) == 0 )
2201  {
2202  *value = SCIPsetInfinity(set);
2203  (*endptr) = (char*)str + 4;
2204  }
2205  else if( strncmp(str, "-inf", 4) == 0 )
2206  {
2207  *value = -SCIPsetInfinity(set);
2208  (*endptr) = (char*)str + 4;
2209  }
2210  else
2211  {
2212  if( !SCIPstrToRealValue(str, value, endptr) )
2213  return SCIP_READERROR;
2214  }
2215 
2216  return SCIP_OKAY;
2217 }
2218 
2219 /** parse the characters as bounds */
2220 static
2222  SCIP_SET* set, /**< global SCIP settings */
2223  const char* str, /**< string to parse */
2224  char* type, /**< bound type (global, local, or lazy) */
2225  SCIP_Real* lb, /**< pointer to store the lower bound */
2226  SCIP_Real* ub, /**< pointer to store the upper bound */
2227  char** endptr /**< pointer to store the final string position if successfully parsed (or NULL if an error occured) */
2228  )
2229 {
2230  char token[SCIP_MAXSTRLEN];
2231 
2232  SCIPdebugMessage("parsing bounds: '%s'\n", str);
2233 
2234  /* get bound type */
2235  SCIPstrCopySection(str, ' ', ' ', type, SCIP_MAXSTRLEN, endptr);
2236  if ( strncmp(type, "original", 8) != 0 && strncmp(type, "global", 6) != 0 && strncmp(type, "local", 5) != 0 && strncmp(type, "lazy", 4) != 0 )
2237  {
2238  SCIPdebugMessage("unkown bound type <%s>\n", type);
2239  *endptr = NULL;
2240  return SCIP_OKAY;
2241  }
2242 
2243  SCIPdebugMessage("parsed bound type <%s>\n", type);
2244 
2245  /* get lower bound */
2246  SCIPstrCopySection(str, '[', ',', token, SCIP_MAXSTRLEN, endptr);
2247  str = *endptr;
2248  SCIP_CALL( parseValue(set, token, lb, endptr) );
2249 
2250  /* get upper bound */
2251  SCIP_CALL( parseValue(set, str, ub, endptr) );
2252 
2253  SCIPdebugMessage("parsed bounds: [%g,%g]\n", *lb, *ub);
2254 
2255  /* skip end of bounds */
2256  while ( **endptr != '\0' && (**endptr == ']' || **endptr == ',') )
2257  ++(*endptr);
2258 
2259  return SCIP_OKAY;
2260 }
2261 
2262 /** parses a given string for a variable informations */
2263 static
2265  SCIP_SET* set, /**< global SCIP settings */
2266  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2267  const char* str, /**< string to parse */
2268  char* name, /**< pointer to store the variable name */
2269  SCIP_Real* lb, /**< pointer to store the lower bound */
2270  SCIP_Real* ub, /**< pointer to store the upper bound */
2271  SCIP_Real* obj, /**< pointer to store the objective coefficient */
2272  SCIP_VARTYPE* vartype, /**< pointer to store the variable type */
2273  SCIP_Real* lazylb, /**< pointer to store if the lower bound is lazy */
2274  SCIP_Real* lazyub, /**< pointer to store if the upper bound is lazy */
2275  SCIP_Bool local, /**< should the local bound be applied */
2276  char** endptr, /**< pointer to store the final string position if successfully */
2277  SCIP_Bool* success /**< pointer store if the paring process was successful */
2278  )
2279 {
2280  SCIP_Real parsedlb;
2281  SCIP_Real parsedub;
2282  char token[SCIP_MAXSTRLEN];
2283  char* strptr;
2284  int i;
2285 
2286  assert(lb != NULL);
2287  assert(ub != NULL);
2288  assert(obj != NULL);
2289  assert(vartype != NULL);
2290  assert(lazylb != NULL);
2291  assert(lazyub != NULL);
2292  assert(endptr != NULL);
2293  assert(success != NULL);
2294 
2295  (*success) = TRUE;
2296 
2297  /* copy variable type */
2298  SCIPstrCopySection(str, '[', ']', token, SCIP_MAXSTRLEN, endptr);
2299  assert(str != *endptr);
2300  SCIPdebugMessage("parsed variable type <%s>\n", token);
2301 
2302  /* get variable type */
2303  if( strncmp(token, "binary", 3) == 0 )
2304  (*vartype) = SCIP_VARTYPE_BINARY;
2305  else if( strncmp(token, "integer", 3) == 0 )
2306  (*vartype) = SCIP_VARTYPE_INTEGER;
2307  else if( strncmp(token, "implicit", 3) == 0 )
2308  (*vartype) = SCIP_VARTYPE_IMPLINT;
2309  else if( strncmp(token, "continuous", 3) == 0 )
2310  (*vartype) = SCIP_VARTYPE_CONTINUOUS;
2311  else
2312  {
2313  SCIPmessagePrintWarning(messagehdlr, "unknown variable type\n");
2314  (*success) = FALSE;
2315  return SCIP_OKAY;
2316  }
2317 
2318  /* move string pointer behind variable type */
2319  str = *endptr;
2320 
2321  /* get variable name */
2322  SCIPstrCopySection(str, '<', '>', name, SCIP_MAXSTRLEN, endptr);
2323  assert(endptr != NULL);
2324  SCIPdebugMessage("parsed variable name <%s>\n", name);
2325 
2326  /* move string pointer behind variable name */
2327  str = *endptr;
2328 
2329  /* cut out objective coefficient */
2330  SCIPstrCopySection(str, '=', ',', token, SCIP_MAXSTRLEN, endptr);
2331 
2332  /* move string pointer behind objective coefficient */
2333  str = *endptr;
2334 
2335  /* get objective coefficient */
2336  if( !SCIPstrToRealValue(token, obj, endptr) )
2337  return SCIP_READERROR;
2338 
2339  SCIPdebugMessage("parsed objective coefficient <%g>\n", *obj);
2340 
2341  /* parse global/original bounds */
2342  SCIP_CALL( parseBounds(set, str, token, lb, ub, endptr) );
2343  assert(strncmp(token, "global", 6) == 0 || strncmp(token, "original", 8) == 0);
2344 
2345  /* initialize the lazy bound */
2346  *lazylb = -SCIPsetInfinity(set);
2347  *lazyub = SCIPsetInfinity(set);
2348 
2349  /* store pointer */
2350  strptr = *endptr;
2351 
2352  /* possibly parse optional local and lazy bounds */
2353  for( i = 0; i < 2 && *endptr != NULL && **endptr != '\0'; ++i )
2354  {
2355  /* start after previous bounds */
2356  strptr = *endptr;
2357 
2358  /* parse global bounds */
2359  SCIP_CALL( parseBounds(set, strptr, token, &parsedlb, &parsedub, endptr) );
2360 
2361  if( strncmp(token, "local", 5) == 0 && local )
2362  {
2363  *lb = parsedlb;
2364  *ub = parsedub;
2365  }
2366  else if( strncmp(token, "lazy", 4) == 0 )
2367  {
2368  *lazylb = parsedlb;
2369  *lazyub = parsedub;
2370  }
2371  }
2372 
2373  /* restore pointer */
2374  if ( *endptr == NULL )
2375  *endptr = strptr;
2376 
2377  /* check bounds for binary variables */
2378  if ( (*vartype) == SCIP_VARTYPE_BINARY )
2379  {
2380  if ( SCIPsetIsLT(set, *lb, 0.0) || SCIPsetIsGT(set, *ub, 1.0) )
2381  {
2382  SCIPerrorMessage("Parsed invalid bounds for binary variable <%s>: [%f, %f].\n", name, *lb, *ub);
2383  return SCIP_READERROR;
2384  }
2385  if ( !SCIPsetIsInfinity(set, -(*lazylb)) && !SCIPsetIsInfinity(set, *lazyub) &&
2386  ( SCIPsetIsLT(set, *lazylb, 0.0) || SCIPsetIsGT(set, *lazyub, 1.0) ) )
2387  {
2388  SCIPerrorMessage("Parsed invalid lazy bounds for binary variable <%s>: [%f, %f].\n", name, *lazylb, *lazyub);
2389  return SCIP_READERROR;
2390  }
2391  }
2392 
2393  return SCIP_OKAY;
2394 }
2395 
2396 /** parses variable information (in cip format) out of a string; if the parsing process was successful an original
2397  * variable is created and captured; if variable is of integral type, fractional bounds are automatically rounded; an
2398  * integer variable with bounds zero and one is automatically converted into a binary variable
2399  */
2401  SCIP_VAR** var, /**< pointer to variable data */
2402  BMS_BLKMEM* blkmem, /**< block memory */
2403  SCIP_SET* set, /**< global SCIP settings */
2404  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2405  SCIP_STAT* stat, /**< problem statistics */
2406  const char* str, /**< string to parse */
2407  SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2408  SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2409  SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2410  SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable */
2411  SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data */
2412  SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable */
2413  SCIP_VARDATA* vardata, /**< user data for this specific variable */
2414  char** endptr, /**< pointer to store the final string position if successfully */
2415  SCIP_Bool* success /**< pointer store if the paring process was successful */
2416  )
2417 {
2418  char name[SCIP_MAXSTRLEN];
2419  SCIP_Real lb;
2420  SCIP_Real ub;
2421  SCIP_Real obj;
2422  SCIP_VARTYPE vartype;
2423  SCIP_Real lazylb;
2424  SCIP_Real lazyub;
2425 
2426  assert(var != NULL);
2427  assert(blkmem != NULL);
2428  assert(stat != NULL);
2429  assert(endptr != NULL);
2430  assert(success != NULL);
2431 
2432  /* parse string in cip format for variable information */
2433  SCIP_CALL( varParse(set, messagehdlr, str, name, &lb, &ub, &obj, &vartype, &lazylb, &lazyub, FALSE, endptr, success) );
2434 
2435  if( *success )
2436  {
2437  /* create variable */
2438  SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2439  varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2440 
2441  /* set variable status and data */
2442  (*var)->varstatus = SCIP_VARSTATUS_ORIGINAL; /*lint !e641*/
2443  (*var)->data.original.origdom.holelist = NULL;
2444  (*var)->data.original.origdom.lb = lb;
2445  (*var)->data.original.origdom.ub = ub;
2446  (*var)->data.original.transvar = NULL;
2447 
2448  /* set lazy status of variable bounds */
2449  (*var)->lazylb = lazylb;
2450  (*var)->lazyub = lazyub;
2451 
2452  /* capture variable */
2453  SCIPvarCapture(*var);
2454  }
2455 
2456  return SCIP_OKAY;
2457 }
2458 
2459 /** parses variable information (in cip format) out of a string; if the parsing process was successful a loose variable
2460  * belonging to the transformed problem is created and captured; if variable is of integral type, fractional bounds are
2461  * automatically rounded; an integer variable with bounds zero and one is automatically converted into a binary
2462  * variable
2463  */
2465  SCIP_VAR** var, /**< pointer to variable data */
2466  BMS_BLKMEM* blkmem, /**< block memory */
2467  SCIP_SET* set, /**< global SCIP settings */
2468  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2469  SCIP_STAT* stat, /**< problem statistics */
2470  const char* str, /**< string to parse */
2471  SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2472  SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2473  SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2474  SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable */
2475  SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data */
2476  SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable */
2477  SCIP_VARDATA* vardata, /**< user data for this specific variable */
2478  char** endptr, /**< pointer to store the final string position if successfully */
2479  SCIP_Bool* success /**< pointer store if the paring process was successful */
2480  )
2481 {
2482  char name[SCIP_MAXSTRLEN];
2483  SCIP_Real lb;
2484  SCIP_Real ub;
2485  SCIP_Real obj;
2486  SCIP_VARTYPE vartype;
2487  SCIP_Real lazylb;
2488  SCIP_Real lazyub;
2489 
2490  assert(var != NULL);
2491  assert(blkmem != NULL);
2492  assert(endptr != NULL);
2493  assert(success != NULL);
2494 
2495  /* parse string in cip format for variable information */
2496  SCIP_CALL( varParse(set, messagehdlr, str, name, &lb, &ub, &obj, &vartype, &lazylb, &lazyub, TRUE, endptr, success) );
2497 
2498  if( *success )
2499  {
2500  /* create variable */
2501  SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2502  varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2503 
2504  /* create event filter for transformed variable */
2505  SCIP_CALL( SCIPeventfilterCreate(&(*var)->eventfilter, blkmem) );
2506 
2507  /* set variable status and data */
2508  (*var)->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
2509 
2510  /* set lazy status of variable bounds */
2511  (*var)->lazylb = lazylb;
2512  (*var)->lazyub = lazyub;
2513 
2514  /* capture variable */
2515  SCIPvarCapture(*var);
2516  }
2517 
2518  return SCIP_OKAY;
2519 }
2520 
2521 /** ensures, that parentvars array of var can store at least num entries */
2522 static
2524  SCIP_VAR* var, /**< problem variable */
2525  BMS_BLKMEM* blkmem, /**< block memory */
2526  SCIP_SET* set, /**< global SCIP settings */
2527  int num /**< minimum number of entries to store */
2528  )
2529 {
2530  assert(var->nparentvars <= var->parentvarssize);
2531 
2532  if( num > var->parentvarssize )
2533  {
2534  int newsize;
2535 
2536  newsize = SCIPsetCalcMemGrowSize(set, num);
2537  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->parentvars, var->parentvarssize, newsize) );
2538  var->parentvarssize = newsize;
2539  }
2540  assert(num <= var->parentvarssize);
2541 
2542  return SCIP_OKAY;
2543 }
2544 
2545 /** adds variable to parent list of a variable and captures parent variable */
2546 static
2548  SCIP_VAR* var, /**< variable to add parent to */
2549  BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
2550  SCIP_SET* set, /**< global SCIP settings */
2551  SCIP_VAR* parentvar /**< parent variable to add */
2552  )
2553 {
2554  assert(var != NULL);
2555  assert(parentvar != NULL);
2556 
2557  /* the direct original counterpart must be stored as first parent */
2558  assert(var->nparentvars == 0 || SCIPvarGetStatus(parentvar) != SCIP_VARSTATUS_ORIGINAL);
2559 
2560  SCIPdebugMessage("adding parent <%s>[%p] to variable <%s>[%p] in slot %d\n",
2561  parentvar->name, (void*)parentvar, var->name, (void*)var, var->nparentvars);
2562 
2563  SCIP_CALL( varEnsureParentvarsSize(var, blkmem, set, var->nparentvars+1) );
2564 
2565  var->parentvars[var->nparentvars] = parentvar;
2566  var->nparentvars++;
2567 
2568  SCIPvarCapture(parentvar);
2569 
2570  return SCIP_OKAY;
2571 }
2572 
2573 /** deletes and releases all variables from the parent list of a variable, frees the memory of parents array */
2574 static
2576  SCIP_VAR** var, /**< pointer to variable */
2577  BMS_BLKMEM* blkmem, /**< block memory */
2578  SCIP_SET* set, /**< global SCIP settings */
2579  SCIP_EVENTQUEUE* eventqueue, /**< event queue (or NULL, if it's an original variable) */
2580  SCIP_LP* lp /**< current LP data (or NULL, if it's an original variable) */
2581  )
2582 {
2583  SCIP_VAR* parentvar;
2584  int i;
2585 
2586  SCIPdebugMessage("free parents of <%s>\n", (*var)->name);
2587 
2588  /* release the parent variables and remove the link from the parent variable to the child */
2589  for( i = 0; i < (*var)->nparentvars; ++i )
2590  {
2591  assert((*var)->parentvars != NULL);
2592  parentvar = (*var)->parentvars[i];
2593  assert(parentvar != NULL);
2594 
2595  switch( SCIPvarGetStatus(parentvar) )
2596  {
2598  assert(parentvar->data.original.transvar == *var);
2599  assert(&parentvar->data.original.transvar != var);
2600  parentvar->data.original.transvar = NULL;
2601  break;
2602 
2604  assert(parentvar->data.aggregate.var == *var);
2605  assert(&parentvar->data.aggregate.var != var);
2606  parentvar->data.aggregate.var = NULL;
2607  break;
2608 
2609 #if 0
2610  /* The following code is unclear: should the current variable be removed from its parents? */
2612  assert(parentvar->data.multaggr.vars != NULL);
2613  for( v = 0; v < parentvar->data.multaggr.nvars && parentvar->data.multaggr.vars[v] != *var; ++v )
2614  {}
2615  assert(v < parentvar->data.multaggr.nvars && parentvar->data.multaggr.vars[v] == *var);
2616  if( v < parentvar->data.multaggr.nvars-1 )
2617  {
2618  parentvar->data.multaggr.vars[v] = parentvar->data.multaggr.vars[parentvar->data.multaggr.nvars-1];
2619  parentvar->data.multaggr.scalars[v] = parentvar->data.multaggr.scalars[parentvar->data.multaggr.nvars-1];
2620  }
2621  parentvar->data.multaggr.nvars--;
2622  break;
2623 #endif
2624 
2626  assert(parentvar->negatedvar == *var);
2627  assert((*var)->negatedvar == parentvar);
2628  parentvar->negatedvar = NULL;
2629  (*var)->negatedvar = NULL;
2630  break;
2631 
2632  default:
2633  SCIPerrorMessage("parent variable is neither ORIGINAL, AGGREGATED nor NEGATED\n");
2634  return SCIP_INVALIDDATA;
2635  } /*lint !e788*/
2636 
2637  SCIP_CALL( SCIPvarRelease(&(*var)->parentvars[i], blkmem, set, eventqueue, lp) );
2638  }
2639 
2640  /* free parentvars array */
2641  BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->parentvars, (*var)->parentvarssize);
2642 
2643  return SCIP_OKAY;
2644 }
2645 
2646 /** frees a variable */
2647 static
2649  SCIP_VAR** var, /**< pointer to variable */
2650  BMS_BLKMEM* blkmem, /**< block memory */
2651  SCIP_SET* set, /**< global SCIP settings */
2652  SCIP_EVENTQUEUE* eventqueue, /**< event queue (may be NULL, if it's not a column variable) */
2653  SCIP_LP* lp /**< current LP data (may be NULL, if it's not a column variable) */
2654  )
2655 {
2656  assert(var != NULL);
2657  assert(*var != NULL);
2658  assert(SCIPvarGetStatus(*var) != SCIP_VARSTATUS_COLUMN || &(*var)->data.col->var != var);
2659  assert((*var)->nuses == 0);
2660  assert((*var)->probindex == -1);
2661 
2662  SCIPdebugMessage("free variable <%s> with status=%d\n", (*var)->name, SCIPvarGetStatus(*var));
2663 
2664  switch( SCIPvarGetStatus(*var) )
2665  {
2667  assert((*var)->data.original.transvar == NULL); /* cannot free variable, if transformed variable is still existing */
2668  holelistFree(&(*var)->data.original.origdom.holelist, blkmem);
2669  assert((*var)->data.original.origdom.holelist == NULL);
2670  break;
2671  case SCIP_VARSTATUS_LOOSE:
2672  break;
2673  case SCIP_VARSTATUS_COLUMN:
2674  SCIP_CALL( SCIPcolFree(&(*var)->data.col, blkmem, set, eventqueue, lp) ); /* free corresponding LP column */
2675  break;
2676  case SCIP_VARSTATUS_FIXED:
2678  break;
2680  BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.vars, (*var)->data.multaggr.varssize);
2681  BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.scalars, (*var)->data.multaggr.varssize);
2682  break;
2684  break;
2685  default:
2686  SCIPerrorMessage("unknown variable status\n");
2687  return SCIP_INVALIDDATA;
2688  }
2689 
2690  /* release all parent variables and free the parentvars array */
2691  SCIP_CALL( varFreeParents(var, blkmem, set, eventqueue, lp) );
2692 
2693  /* free user data */
2695  {
2696  if( (*var)->vardelorig != NULL )
2697  {
2698  SCIP_CALL( (*var)->vardelorig(set->scip, *var, &(*var)->vardata) );
2699  }
2700  }
2701  else
2702  {
2703  if( (*var)->vardeltrans != NULL )
2704  {
2705  SCIP_CALL( (*var)->vardeltrans(set->scip, *var, &(*var)->vardata) );
2706  }
2707  }
2708 
2709  /* free event filter */
2710  if( (*var)->eventfilter != NULL )
2711  {
2712  SCIP_CALL( SCIPeventfilterFree(&(*var)->eventfilter, blkmem, set) );
2713  }
2714  assert((*var)->eventfilter == NULL);
2715 
2716  /* free hole lists */
2717  holelistFree(&(*var)->glbdom.holelist, blkmem);
2718  holelistFree(&(*var)->locdom.holelist, blkmem);
2719  assert((*var)->glbdom.holelist == NULL);
2720  assert((*var)->locdom.holelist == NULL);
2721 
2722  /* free variable bounds data structures */
2723  SCIPvboundsFree(&(*var)->vlbs, blkmem);
2724  SCIPvboundsFree(&(*var)->vubs, blkmem);
2725 
2726  /* free implications data structures */
2727  SCIPimplicsFree(&(*var)->implics, blkmem);
2728 
2729  /* free clique list data structures */
2730  SCIPcliquelistFree(&(*var)->cliquelist, blkmem);
2731 
2732  /* free bound change information arrays */
2733  BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->lbchginfos, (*var)->lbchginfossize);
2734  BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->ubchginfos, (*var)->ubchginfossize);
2735 
2736  /* free branching and inference history entries */
2737  SCIPhistoryFree(&(*var)->history, blkmem);
2738  SCIPhistoryFree(&(*var)->historycrun, blkmem);
2739  SCIPvaluehistoryFree(&(*var)->valuehistory, blkmem);
2740 
2741  /* free variable data structure */
2742  BMSfreeBlockMemoryArray(blkmem, &(*var)->name, strlen((*var)->name)+1);
2743  BMSfreeBlockMemory(blkmem, var);
2744 
2745  return SCIP_OKAY;
2746 }
2747 
2748 /** increases usage counter of variable */
2750  SCIP_VAR* var /**< variable */
2751  )
2752 {
2753  assert(var != NULL);
2754  assert(var->nuses >= 0);
2755 
2756  SCIPdebugMessage("capture variable <%s> with nuses=%d\n", var->name, var->nuses);
2757  var->nuses++;
2758 }
2759 
2760 /** decreases usage counter of variable, and frees memory if necessary */
2762  SCIP_VAR** var, /**< pointer to variable */
2763  BMS_BLKMEM* blkmem, /**< block memory */
2764  SCIP_SET* set, /**< global SCIP settings */
2765  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2766  SCIP_LP* lp /**< current LP data (or NULL, if it's an original variable) */
2767  )
2768 {
2769  assert(var != NULL);
2770  assert(*var != NULL);
2771  assert((*var)->nuses >= 1);
2772  assert(blkmem != NULL);
2773  assert((*var)->scip == set->scip);
2774 
2775  SCIPdebugMessage("release variable <%s> with nuses=%d\n", (*var)->name, (*var)->nuses);
2776  (*var)->nuses--;
2777  if( (*var)->nuses == 0 )
2778  {
2779  SCIP_CALL( varFree(var, blkmem, set, eventqueue, lp) );
2780  }
2781 
2782  *var = NULL;
2783 
2784  return SCIP_OKAY;
2785 }
2786 
2787 /** change variable name */
2789  SCIP_VAR* var, /**< problem variable */
2790  BMS_BLKMEM* blkmem, /**< block memory */
2791  const char* name /**< name of variable */
2792  )
2793 {
2794  assert(name != NULL);
2795 
2796  /* remove old variable name */
2797  BMSfreeBlockMemoryArray(blkmem, &var->name, strlen(var->name)+1);
2798 
2799  /* set new variable name */
2800  SCIP_CALL( varSetName(var, blkmem, NULL, name) );
2801 
2802  return SCIP_OKAY;
2803 }
2804 
2805 /** initializes variable data structure for solving */
2807  SCIP_VAR* var /**< problem variable */
2808  )
2809 {
2810  assert(var != NULL);
2811 
2813  var->conflictlbcount = 0;
2814  var->conflictubcount = 0;
2815 }
2816 
2817 /** outputs the given bounds into the file stream */
2818 static
2820  SCIP_SET* set, /**< global SCIP settings */
2821  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2822  FILE* file, /**< output file (or NULL for standard output) */
2823  SCIP_Real lb, /**< lower bound */
2824  SCIP_Real ub, /**< upper bound */
2825  const char* name /**< bound type name */
2826  )
2827 {
2828  assert(set != NULL);
2829 
2830  SCIPmessageFPrintInfo(messagehdlr, file, ", %s=", name);
2831  if( SCIPsetIsInfinity(set, lb) )
2832  SCIPmessageFPrintInfo(messagehdlr, file, "[+inf,");
2833  else if( SCIPsetIsInfinity(set, -lb) )
2834  SCIPmessageFPrintInfo(messagehdlr, file, "[-inf,");
2835  else
2836  SCIPmessageFPrintInfo(messagehdlr, file, "[%.15g,", lb);
2837  if( SCIPsetIsInfinity(set, ub) )
2838  SCIPmessageFPrintInfo(messagehdlr, file, "+inf]");
2839  else if( SCIPsetIsInfinity(set, -ub) )
2840  SCIPmessageFPrintInfo(messagehdlr, file, "-inf]");
2841  else
2842  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g]", ub);
2843 }
2844 
2845 /** prints hole list to file stream */
2846 static
2848  SCIP_SET* set, /**< global SCIP settings */
2849  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2850  FILE* file, /**< output file (or NULL for standard output) */
2851  SCIP_HOLELIST* holelist, /**< hole list pointer to hole of interest */
2852  const char* name /**< hole type name */
2853  )
2854 { /*lint --e{715}*/
2855  SCIP_Real left;
2856  SCIP_Real right;
2857 
2858  if( holelist == NULL )
2859  return;
2860 
2861  left = SCIPholelistGetLeft(holelist);
2862  right = SCIPholelistGetRight(holelist);
2863 
2864  /* display first hole */
2865  SCIPmessageFPrintInfo(messagehdlr, file, ", %s=(%g,%g)", name, left, right);
2866  holelist = SCIPholelistGetNext(holelist);
2867 
2868  while(holelist != NULL )
2869  {
2870  left = SCIPholelistGetLeft(holelist);
2871  right = SCIPholelistGetRight(holelist);
2872 
2873  /* display hole */
2874  SCIPmessageFPrintInfo(messagehdlr, file, "(%g,%g)", left, right);
2875 
2876  /* get next hole */
2877  holelist = SCIPholelistGetNext(holelist);
2878  }
2879 }
2880 
2881 /** outputs variable information into file stream */
2883  SCIP_VAR* var, /**< problem variable */
2884  SCIP_SET* set, /**< global SCIP settings */
2885  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2886  FILE* file /**< output file (or NULL for standard output) */
2887  )
2888 {
2889  SCIP_HOLELIST* holelist;
2890  SCIP_Real lb;
2891  SCIP_Real ub;
2892  int i;
2893 
2894  assert(var != NULL);
2895  assert(var->scip == set->scip);
2896 
2897  /* type of variable */
2898  switch( SCIPvarGetType(var) )
2899  {
2900  case SCIP_VARTYPE_BINARY:
2901  SCIPmessageFPrintInfo(messagehdlr, file, " [binary]");
2902  break;
2903  case SCIP_VARTYPE_INTEGER:
2904  SCIPmessageFPrintInfo(messagehdlr, file, " [integer]");
2905  break;
2906  case SCIP_VARTYPE_IMPLINT:
2907  SCIPmessageFPrintInfo(messagehdlr, file, " [implicit]");
2908  break;
2910  SCIPmessageFPrintInfo(messagehdlr, file, " [continuous]");
2911  break;
2912  default:
2913  SCIPerrorMessage("unknown variable type\n");
2914  SCIPABORT();
2915  return SCIP_ERROR; /*lint !e527*/
2916  }
2917 
2918  /* name */
2919  SCIPmessageFPrintInfo(messagehdlr, file, " <%s>:", var->name);
2920 
2921  /* objective value */
2922  SCIPmessageFPrintInfo(messagehdlr, file, " obj=%.15g", var->obj);
2923 
2924  /* bounds (global bounds for transformed variables, original bounds for original variables) */
2925  if( !SCIPvarIsTransformed(var) )
2926  {
2927  /* output original bound */
2928  lb = SCIPvarGetLbOriginal(var);
2929  ub = SCIPvarGetUbOriginal(var);
2930  printBounds(set, messagehdlr, file, lb, ub, "original bounds");
2931 
2932  /* output lazy bound */
2933  lb = SCIPvarGetLbLazy(var);
2934  ub = SCIPvarGetUbLazy(var);
2935 
2936  /* only display the lazy bounds if they are different from [-infinity,infinity] */
2937  if( !SCIPsetIsInfinity(set, -lb) || !SCIPsetIsInfinity(set, ub) )
2938  printBounds(set, messagehdlr, file, lb, ub, "lazy bounds");
2939 
2940  holelist = SCIPvarGetHolelistOriginal(var);
2941  printHolelist(set, messagehdlr, file, holelist, "original holes");
2942  }
2943  else
2944  {
2945  /* output global bound */
2946  lb = SCIPvarGetLbGlobal(var);
2947  ub = SCIPvarGetUbGlobal(var);
2948  printBounds(set, messagehdlr, file, lb, ub, "global bounds");
2949 
2950  /* output local bound */
2951  lb = SCIPvarGetLbLocal(var);
2952  ub = SCIPvarGetUbLocal(var);
2953  printBounds(set, messagehdlr, file, lb, ub, "local bounds");
2954 
2955  /* output lazy bound */
2956  lb = SCIPvarGetLbLazy(var);
2957  ub = SCIPvarGetUbLazy(var);
2958 
2959  /* only display the lazy bounds if they are different from [-infinity,infinity] */
2960  if( !SCIPsetIsInfinity(set, -lb) || !SCIPsetIsInfinity(set, ub) )
2961  printBounds(set, messagehdlr, file, lb, ub, "lazy bounds");
2962 
2963  /* global hole list */
2964  holelist = SCIPvarGetHolelistGlobal(var);
2965  printHolelist(set, messagehdlr, file, holelist, "global holes");
2966 
2967  /* local hole list */
2968  holelist = SCIPvarGetHolelistLocal(var);
2969  printHolelist(set, messagehdlr, file, holelist, "local holes");
2970  }
2971 
2972  /* fixings and aggregations */
2973  switch( SCIPvarGetStatus(var) )
2974  {
2976  case SCIP_VARSTATUS_LOOSE:
2977  case SCIP_VARSTATUS_COLUMN:
2978  break;
2979 
2980  case SCIP_VARSTATUS_FIXED:
2981  SCIPmessageFPrintInfo(messagehdlr, file, ", fixed:");
2982  if( SCIPsetIsInfinity(set, var->glbdom.lb) )
2983  SCIPmessageFPrintInfo(messagehdlr, file, "+inf");
2984  else if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
2985  SCIPmessageFPrintInfo(messagehdlr, file, "-inf");
2986  else
2987  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", var->glbdom.lb);
2988  break;
2989 
2991  SCIPmessageFPrintInfo(messagehdlr, file, ", aggregated:");
2992  if( !SCIPsetIsZero(set, var->data.aggregate.constant) )
2993  SCIPmessageFPrintInfo(messagehdlr, file, " %.15g", var->data.aggregate.constant);
2994  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g<%s>", var->data.aggregate.scalar, SCIPvarGetName(var->data.aggregate.var));
2995  break;
2996 
2998  SCIPmessageFPrintInfo(messagehdlr, file, ", aggregated:");
2999  if( var->data.multaggr.nvars == 0 || !SCIPsetIsZero(set, var->data.multaggr.constant) )
3000  SCIPmessageFPrintInfo(messagehdlr, file, " %.15g", var->data.multaggr.constant);
3001  for( i = 0; i < var->data.multaggr.nvars; ++i )
3002  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g<%s>", var->data.multaggr.scalars[i], SCIPvarGetName(var->data.multaggr.vars[i]));
3003  break;
3004 
3006  SCIPmessageFPrintInfo(messagehdlr, file, ", negated: %.15g - <%s>", var->data.negate.constant, SCIPvarGetName(var->negatedvar));
3007  break;
3008 
3009  default:
3010  SCIPerrorMessage("unknown variable status\n");
3011  SCIPABORT();
3012  return SCIP_ERROR; /*lint !e527*/
3013  }
3014 
3015  SCIPmessageFPrintInfo(messagehdlr, file, "\n");
3016 
3017  return SCIP_OKAY;
3018 }
3019 
3020 /** issues a VARUNLOCKED event on the given variable */
3021 static
3023  SCIP_VAR* var, /**< problem variable to change */
3024  BMS_BLKMEM* blkmem, /**< block memory */
3025  SCIP_SET* set, /**< global SCIP settings */
3026  SCIP_EVENTQUEUE* eventqueue /**< event queue */
3027  )
3028 {
3029  SCIP_EVENT* event;
3030 
3031  assert(var != NULL);
3032  assert(var->nlocksdown <= 1 && var->nlocksup <= 1);
3033  assert(var->scip == set->scip);
3034 
3035  /* issue VARUNLOCKED event on variable */
3036  SCIP_CALL( SCIPeventCreateVarUnlocked(&event, blkmem, var) );
3037  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
3038 
3039  return SCIP_OKAY;
3040 }
3041 
3042 /** modifies lock numbers for rounding */
3044  SCIP_VAR* var, /**< problem variable */
3045  BMS_BLKMEM* blkmem, /**< block memory */
3046  SCIP_SET* set, /**< global SCIP settings */
3047  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3048  int addnlocksdown, /**< increase in number of rounding down locks */
3049  int addnlocksup /**< increase in number of rounding up locks */
3050  )
3051 {
3052  SCIP_VAR* lockvar;
3053 
3054  assert(var != NULL);
3055  assert(var->nlocksup >= 0);
3056  assert(var->nlocksdown >= 0);
3057  assert(var->scip == set->scip);
3058 
3059  if( addnlocksdown == 0 && addnlocksup == 0 )
3060  return SCIP_OKAY;
3061 
3062  SCIPdebugMessage("add rounding locks %d/%d to variable <%s> (locks=%d/%d)\n",
3063  addnlocksdown, addnlocksup, var->name, var->nlocksdown, var->nlocksup);
3064 
3065  lockvar = var;
3066 
3067  while( TRUE ) /*lint !e716 */
3068  {
3069  assert(lockvar != NULL);
3070 
3071  switch( SCIPvarGetStatus(lockvar) )
3072  {
3074  if( lockvar->data.original.transvar != NULL )
3075  {
3076  lockvar = lockvar->data.original.transvar;
3077  break;
3078  }
3079  else
3080  {
3081  lockvar->nlocksdown += addnlocksdown;
3082  lockvar->nlocksup += addnlocksup;
3083 
3084  assert(lockvar->nlocksdown >= 0);
3085  assert(lockvar->nlocksup >= 0);
3086 
3087  return SCIP_OKAY;
3088  }
3089  case SCIP_VARSTATUS_LOOSE:
3090  case SCIP_VARSTATUS_COLUMN:
3091  case SCIP_VARSTATUS_FIXED:
3092  lockvar->nlocksdown += addnlocksdown;
3093  lockvar->nlocksup += addnlocksup;
3094 
3095  assert(lockvar->nlocksdown >= 0);
3096  assert(lockvar->nlocksup >= 0);
3097 
3098  if( lockvar->nlocksdown <= 1 && lockvar->nlocksup <= 1 )
3099  {
3100  SCIP_CALL( varEventVarUnlocked(lockvar, blkmem, set, eventqueue) );
3101  }
3102 
3103  return SCIP_OKAY;
3105  if( lockvar->data.aggregate.scalar < 0.0 )
3106  {
3107  int tmp = addnlocksup;
3108 
3109  addnlocksup = addnlocksdown;
3110  addnlocksdown = tmp;
3111  }
3112 
3113  lockvar = lockvar->data.aggregate.var;
3114  break;
3116  {
3117  int v;
3118 
3119  assert(!lockvar->donotmultaggr);
3120 
3121  for( v = lockvar->data.multaggr.nvars - 1; v >= 0; --v )
3122  {
3123  if( lockvar->data.multaggr.scalars[v] > 0.0 )
3124  {
3125  SCIP_CALL( SCIPvarAddLocks(lockvar->data.multaggr.vars[v], blkmem, set, eventqueue,
3126  addnlocksdown, addnlocksup) );
3127  }
3128  else
3129  {
3130  SCIP_CALL( SCIPvarAddLocks(lockvar->data.multaggr.vars[v], blkmem, set, eventqueue,
3131  addnlocksup, addnlocksdown) );
3132  }
3133  }
3134  return SCIP_OKAY;
3135  }
3137  {
3138  int tmp = addnlocksup;
3139 
3140  assert(lockvar->negatedvar != NULL);
3141  assert(SCIPvarGetStatus(lockvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
3142  assert(lockvar->negatedvar->negatedvar == lockvar);
3143 
3144  addnlocksup = addnlocksdown;
3145  addnlocksdown = tmp;
3146 
3147  lockvar = lockvar->negatedvar;
3148  break;
3149  }
3150  default:
3151  SCIPerrorMessage("unknown variable status\n");
3152  return SCIP_INVALIDDATA;
3153  }
3154  }
3155 }
3156 
3157 /** gets number of locks for rounding down */
3159  SCIP_VAR* var /**< problem variable */
3160  )
3161 {
3162  int nlocks;
3163  int i;
3164 
3165  assert(var != NULL);
3166  assert(var->nlocksdown >= 0);
3167 
3168  switch( SCIPvarGetStatus(var) )
3169  {
3171  if( var->data.original.transvar != NULL )
3173  else
3174  return var->nlocksdown;
3175 
3176  case SCIP_VARSTATUS_LOOSE:
3177  case SCIP_VARSTATUS_COLUMN:
3178  case SCIP_VARSTATUS_FIXED:
3179  return var->nlocksdown;
3180 
3182  if( var->data.aggregate.scalar > 0.0 )
3183  return SCIPvarGetNLocksDown(var->data.aggregate.var);
3184  else
3185  return SCIPvarGetNLocksUp(var->data.aggregate.var);
3186 
3188  assert(!var->donotmultaggr);
3189  nlocks = 0;
3190  for( i = 0; i < var->data.multaggr.nvars; ++i )
3191  {
3192  if( var->data.multaggr.scalars[i] > 0.0 )
3193  nlocks += SCIPvarGetNLocksDown(var->data.multaggr.vars[i]);
3194  else
3195  nlocks += SCIPvarGetNLocksUp(var->data.multaggr.vars[i]);
3196  }
3197  return nlocks;
3198 
3200  assert(var->negatedvar != NULL);
3202  assert(var->negatedvar->negatedvar == var);
3203  return SCIPvarGetNLocksUp(var->negatedvar);
3204 
3205  default:
3206  SCIPerrorMessage("unknown variable status\n");
3207  SCIPABORT();
3208  return INT_MAX; /*lint !e527*/
3209  }
3210 }
3211 
3212 /** gets number of locks for rounding up */
3214  SCIP_VAR* var /**< problem variable */
3215  )
3216 {
3217  int nlocks;
3218  int i;
3219 
3220  assert(var != NULL);
3221  assert(var->nlocksup >= 0);
3222 
3223  switch( SCIPvarGetStatus(var) )
3224  {
3226  if( var->data.original.transvar != NULL )
3228  else
3229  return var->nlocksup;
3230 
3231  case SCIP_VARSTATUS_LOOSE:
3232  case SCIP_VARSTATUS_COLUMN:
3233  case SCIP_VARSTATUS_FIXED:
3234  return var->nlocksup;
3235 
3237  if( var->data.aggregate.scalar > 0.0 )
3238  return SCIPvarGetNLocksUp(var->data.aggregate.var);
3239  else
3240  return SCIPvarGetNLocksDown(var->data.aggregate.var);
3241 
3243  assert(!var->donotmultaggr);
3244  nlocks = 0;
3245  for( i = 0; i < var->data.multaggr.nvars; ++i )
3246  {
3247  if( var->data.multaggr.scalars[i] > 0.0 )
3248  nlocks += SCIPvarGetNLocksUp(var->data.multaggr.vars[i]);
3249  else
3250  nlocks += SCIPvarGetNLocksDown(var->data.multaggr.vars[i]);
3251  }
3252  return nlocks;
3253 
3255  assert(var->negatedvar != NULL);
3257  assert(var->negatedvar->negatedvar == var);
3258  return SCIPvarGetNLocksDown(var->negatedvar);
3259 
3260  default:
3261  SCIPerrorMessage("unknown variable status\n");
3262  SCIPABORT();
3263  return INT_MAX; /*lint !e527*/
3264  }
3265 }
3266 
3267 /** is it possible, to round variable down and stay feasible? */
3269  SCIP_VAR* var /**< problem variable */
3270  )
3271 {
3272  return (SCIPvarGetNLocksDown(var) == 0);
3273 }
3274 
3275 /** is it possible, to round variable up and stay feasible? */
3277  SCIP_VAR* var /**< problem variable */
3278  )
3279 {
3280  return (SCIPvarGetNLocksUp(var) == 0);
3281 }
3282 
3283 /** gets and captures transformed variable of a given variable; if the variable is not yet transformed,
3284  * a new transformed variable for this variable is created
3285  */
3287  SCIP_VAR* origvar, /**< original problem variable */
3288  BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
3289  SCIP_SET* set, /**< global SCIP settings */
3290  SCIP_STAT* stat, /**< problem statistics */
3291  SCIP_OBJSENSE objsense, /**< objective sense of original problem; transformed is always MINIMIZE */
3292  SCIP_VAR** transvar /**< pointer to store the transformed variable */
3293  )
3294 {
3295  char name[SCIP_MAXSTRLEN];
3296 
3297  assert(origvar != NULL);
3298  assert(origvar->scip == set->scip);
3299  assert(SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_ORIGINAL);
3300  assert(SCIPsetIsEQ(set, origvar->glbdom.lb, origvar->locdom.lb));
3301  assert(SCIPsetIsEQ(set, origvar->glbdom.ub, origvar->locdom.ub));
3302  assert(origvar->vlbs == NULL);
3303  assert(origvar->vubs == NULL);
3304  assert(transvar != NULL);
3305 
3306  /* check if variable is already transformed */
3307  if( origvar->data.original.transvar != NULL )
3308  {
3309  *transvar = origvar->data.original.transvar;
3310  SCIPvarCapture(*transvar);
3311  }
3312  else
3313  {
3314  /* create transformed variable */
3315  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "t_%s", origvar->name);
3316  SCIP_CALL( SCIPvarCreateTransformed(transvar, blkmem, set, stat, name,
3317  origvar->glbdom.lb, origvar->glbdom.ub, (SCIP_Real)objsense * origvar->obj,
3318  SCIPvarGetType(origvar), origvar->initial, origvar->removable,
3319  origvar->vardelorig, origvar->vartrans, origvar->vardeltrans, origvar->varcopy, NULL) );
3320 
3321  /* copy the branch factor and priority */
3322  (*transvar)->branchfactor = origvar->branchfactor;
3323  (*transvar)->branchpriority = origvar->branchpriority;
3324  (*transvar)->branchdirection = origvar->branchdirection; /*lint !e732*/
3325 
3326  /* duplicate hole lists */
3327  SCIP_CALL( holelistDuplicate(&(*transvar)->glbdom.holelist, blkmem, set, origvar->glbdom.holelist) );
3328  SCIP_CALL( holelistDuplicate(&(*transvar)->locdom.holelist, blkmem, set, origvar->locdom.holelist) );
3329 
3330  /* link original and transformed variable */
3331  origvar->data.original.transvar = *transvar;
3332  SCIP_CALL( varAddParent(*transvar, blkmem, set, origvar) );
3333 
3334  /* copy rounding locks */
3335  (*transvar)->nlocksdown = origvar->nlocksdown;
3336  (*transvar)->nlocksup = origvar->nlocksup;
3337  assert((*transvar)->nlocksdown >= 0);
3338  assert((*transvar)->nlocksup >= 0);
3339 
3340  /* copy doNotMultiaggr status */
3341  (*transvar)->donotmultaggr = origvar->donotmultaggr;
3342 
3343  /* copy lazy bounds */
3344  (*transvar)->lazylb = origvar->lazylb;
3345  (*transvar)->lazyub = origvar->lazyub;
3346 
3347  /* transform user data */
3348  if( origvar->vartrans != NULL )
3349  {
3350  SCIP_CALL( origvar->vartrans(set->scip, origvar, origvar->vardata, *transvar, &(*transvar)->vardata) );
3351  }
3352  else
3353  (*transvar)->vardata = origvar->vardata;
3354  }
3355 
3356  SCIPdebugMessage("transformed variable: <%s>[%p] -> <%s>[%p]\n", origvar->name, (void*)origvar, (*transvar)->name, (void*)*transvar);
3357 
3358  return SCIP_OKAY;
3359 }
3360 
3361 /** gets corresponding transformed variable of an original or negated original variable */
3363  SCIP_VAR* origvar, /**< original problem variable */
3364  BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
3365  SCIP_SET* set, /**< global SCIP settings */
3366  SCIP_STAT* stat, /**< problem statistics */
3367  SCIP_VAR** transvar /**< pointer to store the transformed variable, or NULL if not existing yet */
3368  )
3369 {
3370  assert(origvar != NULL);
3372  assert(origvar->scip == set->scip);
3373 
3374  if( SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_NEGATED )
3375  {
3376  assert(origvar->negatedvar != NULL);
3378 
3379  if( origvar->negatedvar->data.original.transvar == NULL )
3380  *transvar = NULL;
3381  else
3382  {
3383  SCIP_CALL( SCIPvarNegate(origvar->negatedvar->data.original.transvar, blkmem, set, stat, transvar) );
3384  }
3385  }
3386  else
3387  *transvar = origvar->data.original.transvar;
3388 
3389  return SCIP_OKAY;
3390 }
3391 
3392 /** converts loose transformed variable into column variable, creates LP column */
3394  SCIP_VAR* var, /**< problem variable */
3395  BMS_BLKMEM* blkmem, /**< block memory */
3396  SCIP_SET* set, /**< global SCIP settings */
3397  SCIP_STAT* stat, /**< problem statistics */
3398  SCIP_PROB* prob, /**< problem data */
3399  SCIP_LP* lp /**< current LP data */
3400  )
3401 {
3402  assert(var != NULL);
3403  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
3404  assert(var->scip == set->scip);
3405 
3406  SCIPdebugMessage("creating column for variable <%s>\n", var->name);
3407 
3408  /* switch variable status */
3409  var->varstatus = SCIP_VARSTATUS_COLUMN; /*lint !e641*/
3410 
3411  /* create column of variable */
3412  SCIP_CALL( SCIPcolCreate(&var->data.col, blkmem, set, stat, var, 0, NULL, NULL, var->removable) );
3413 
3414  if( var->probindex != -1 )
3415  {
3416  /* inform problem about the variable's status change */
3417  SCIP_CALL( SCIPprobVarChangedStatus(prob, blkmem, set, NULL, var) );
3418 
3419  /* inform LP, that problem variable is now a column variable and no longer loose */
3420  SCIP_CALL( SCIPlpUpdateVarColumn(lp, set, var) );
3421  }
3422 
3423  return SCIP_OKAY;
3424 }
3425 
3426 /** converts column transformed variable back into loose variable, frees LP column */
3428  SCIP_VAR* var, /**< problem variable */
3429  BMS_BLKMEM* blkmem, /**< block memory */
3430  SCIP_SET* set, /**< global SCIP settings */
3431  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3432  SCIP_PROB* prob, /**< problem data */
3433  SCIP_LP* lp /**< current LP data */
3434  )
3435 {
3436  assert(var != NULL);
3437  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
3438  assert(var->scip == set->scip);
3439  assert(var->data.col != NULL);
3440  assert(var->data.col->lppos == -1);
3441  assert(var->data.col->lpipos == -1);
3442 
3443  SCIPdebugMessage("deleting column for variable <%s>\n", var->name);
3444 
3445  /* free column of variable */
3446  SCIP_CALL( SCIPcolFree(&var->data.col, blkmem, set, eventqueue, lp) );
3447 
3448  /* switch variable status */
3449  var->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
3450 
3451  if( var->probindex != -1 )
3452  {
3453  /* inform problem about the variable's status change */
3454  SCIP_CALL( SCIPprobVarChangedStatus(prob, blkmem, set, NULL, var) );
3455 
3456  /* inform LP, that problem variable is now a loose variable and no longer a column */
3457  SCIP_CALL( SCIPlpUpdateVarLoose(lp, set, var) );
3458  }
3459 
3460  return SCIP_OKAY;
3461 }
3462 
3463 /** issues a VARFIXED event on the given variable and all its parents (except ORIGINAL parents);
3464  * the event issuing on the parents is necessary, because unlike with bound changes, the parent variables
3465  * are not informed about a fixing of an active variable they are pointing to
3466  */
3467 static
3469  SCIP_VAR* var, /**< problem variable to change */
3470  BMS_BLKMEM* blkmem, /**< block memory */
3471  SCIP_SET* set, /**< global SCIP settings */
3472  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3473  int fixeventtype /**< is this event a fixation(0), an aggregation(1), or a
3474  * multi-aggregation(2)
3475  */
3476  )
3477 {
3478  SCIP_EVENT* event;
3479  SCIP_VARSTATUS varstatus;
3480  int i;
3481 
3482  assert(var != NULL);
3483  assert(var->scip == set->scip);
3484  assert(0 <= fixeventtype && fixeventtype <= 2);
3485 
3486  /* issue VARFIXED event on variable */
3487  SCIP_CALL( SCIPeventCreateVarFixed(&event, blkmem, var) );
3488  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
3489 
3490 #ifndef NDEBUG
3491  for( i = var->nparentvars -1; i >= 0; --i )
3492  {
3494  }
3495 #endif
3496 
3497  switch( fixeventtype )
3498  {
3499  case 0:
3500  /* process all parents of a fixed variable */
3501  for( i = var->nparentvars - 1; i >= 0; --i )
3502  {
3503  varstatus = SCIPvarGetStatus(var->parentvars[i]);
3504 
3505  assert(varstatus != SCIP_VARSTATUS_FIXED);
3506 
3507  /* issue event on all not yet fixed parent variables, (that should already issued this event) except the original
3508  * one
3509  */
3510  if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3511  {
3512  SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3513  }
3514  }
3515  break;
3516  case 1:
3517  /* process all parents of a aggregated variable */
3518  for( i = var->nparentvars - 1; i >= 0; --i )
3519  {
3520  varstatus = SCIPvarGetStatus(var->parentvars[i]);
3521 
3522  assert(varstatus != SCIP_VARSTATUS_FIXED);
3523 
3524  /* issue event for not aggregated parent variable, because for these and its parents the var event was already
3525  * issued(, except the original one)
3526  *
3527  * @note that even before an aggregated parent variable, there might be variables, for which the vent was not
3528  * yet issued
3529  */
3530  if( varstatus == SCIP_VARSTATUS_AGGREGATED )
3531  continue;
3532 
3533  if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3534  {
3535  SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3536  }
3537  }
3538  break;
3539  case 2:
3540  /* process all parents of a aggregated variable */
3541  for( i = var->nparentvars - 1; i >= 0; --i )
3542  {
3543  varstatus = SCIPvarGetStatus(var->parentvars[i]);
3544 
3545  assert(varstatus != SCIP_VARSTATUS_FIXED);
3546 
3547  /* issue event on all parent variables except the original one */
3548  if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3549  {
3550  SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3551  }
3552  }
3553  break;
3554  default:
3555  SCIPerrorMessage("unknown variable fixation event origin\n");
3556  return SCIP_INVALIDDATA;
3557  }
3558 
3559  return SCIP_OKAY;
3560 }
3561 
3562 /** converts variable into fixed variable */
3564  SCIP_VAR* var, /**< problem variable */
3565  BMS_BLKMEM* blkmem, /**< block memory */
3566  SCIP_SET* set, /**< global SCIP settings */
3567  SCIP_STAT* stat, /**< problem statistics */
3568  SCIP_PROB* transprob, /**< tranformed problem data */
3569  SCIP_PROB* origprob, /**< original problem data */
3570  SCIP_PRIMAL* primal, /**< primal data */
3571  SCIP_TREE* tree, /**< branch and bound tree */
3572  SCIP_LP* lp, /**< current LP data */
3573  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
3574  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3575  SCIP_Real fixedval, /**< value to fix variable at */
3576  SCIP_Bool* infeasible, /**< pointer to store whether the fixing is infeasible */
3577  SCIP_Bool* fixed /**< pointer to store whether the fixing was performed (variable was unfixed) */
3578  )
3579 {
3580  SCIP_Real obj;
3581  SCIP_Real childfixedval;
3582 
3583  assert(var != NULL);
3584  assert(var->scip == set->scip);
3585  assert(SCIPsetIsEQ(set, var->glbdom.lb, var->locdom.lb));
3586  assert(SCIPsetIsEQ(set, var->glbdom.ub, var->locdom.ub));
3587  assert(infeasible != NULL);
3588  assert(fixed != NULL);
3589 
3590  SCIPdebugMessage("fix variable <%s>[%g,%g] to %g\n", var->name, var->glbdom.lb, var->glbdom.ub, fixedval);
3591 
3592  *infeasible = FALSE;
3593  *fixed = FALSE;
3594 
3596  {
3597  *infeasible = !SCIPsetIsFeasEQ(set, fixedval, var->locdom.lb);
3598  SCIPdebugMessage(" -> variable already fixed to %g (fixedval=%g): infeasible=%u\n",
3599  var->locdom.lb, fixedval, *infeasible);
3600  return SCIP_OKAY;
3601  }
3602  else if( (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && !SCIPsetIsFeasIntegral(set, fixedval))
3603  || SCIPsetIsFeasLT(set, fixedval, var->locdom.lb)
3604  || SCIPsetIsFeasGT(set, fixedval, var->locdom.ub) )
3605  {
3606  SCIPdebugMessage(" -> fixing infeasible: locdom=[%g,%g], fixedval=%g\n", var->locdom.lb, var->locdom.ub, fixedval);
3607  *infeasible = TRUE;
3608  return SCIP_OKAY;
3609  }
3610 
3611  switch( SCIPvarGetStatus(var) )
3612  {
3614  if( var->data.original.transvar == NULL )
3615  {
3616  SCIPerrorMessage("cannot fix an untransformed original variable\n");
3617  return SCIP_INVALIDDATA;
3618  }
3619  SCIP_CALL( SCIPvarFix(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue,
3620  fixedval, infeasible, fixed) );
3621  break;
3622 
3623  case SCIP_VARSTATUS_LOOSE:
3624  assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
3625 
3626  /* set the fixed variable's objective value to 0.0 */
3627  obj = var->obj;
3628  SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
3629 
3630  /* since we change the variable type form loose to fixed, we have to adjust the number of loose
3631  * variables in the LP data structure; the loose objective value (looseobjval) in the LP data structure, however,
3632  * gets adjusted automatically, due to the event SCIP_EVENTTYPE_OBJCHANGED which dropped in the moment where the
3633  * objective of this variable is set to zero
3634  */
3635  SCIPlpDecNLoosevars(lp);
3636 
3637  /* change variable's bounds to fixed value (thereby removing redundant implications and variable bounds) */
3638  holelistFree(&var->glbdom.holelist, blkmem);
3639  holelistFree(&var->locdom.holelist, blkmem);
3640  SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, fixedval) );
3641  SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, fixedval) );
3642 
3643  /* explicitly set variable's bounds, even if the fixed value is in epsilon range of the old bound */
3644  var->glbdom.lb = fixedval;
3645  var->glbdom.ub = fixedval;
3646  var->locdom.lb = fixedval;
3647  var->locdom.ub = fixedval;
3648 
3649  /* delete implications and variable bounds information */
3650  SCIP_CALL( varRemoveImplicsVbs(var, blkmem, set, FALSE, TRUE) );
3651  assert(var->vlbs == NULL);
3652  assert(var->vubs == NULL);
3653  assert(var->implics == NULL);
3654 
3655  /* remove the variable from all cliques */
3656  if( SCIPvarIsBinary(var) )
3657  {
3659  SCIPcliquelistFree(&var->cliquelist, blkmem);
3660  }
3661  assert(var->cliquelist == NULL);
3662 
3663  /* clear the history of the variable */
3664  SCIPhistoryReset(var->history);
3666 
3667  /* convert variable into fixed variable */
3668  var->varstatus = SCIP_VARSTATUS_FIXED; /*lint !e641*/
3669 
3670  /* inform problem about the variable's status change */
3671  if( var->probindex != -1 )
3672  {
3673  SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, var) );
3674  }
3675 
3676  /* reset the objective value of the fixed variable, thus adjusting the problem's objective offset */
3677  SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, lp, eventqueue, obj) );
3678 
3679  /* issue VARFIXED event */
3680  SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 0) );
3681 
3682  *fixed = TRUE;
3683  break;
3684 
3685  case SCIP_VARSTATUS_COLUMN:
3686  SCIPerrorMessage("cannot fix a column variable\n");
3687  return SCIP_INVALIDDATA;
3688 
3689  case SCIP_VARSTATUS_FIXED:
3690  SCIPerrorMessage("cannot fix a fixed variable again\n"); /*lint !e527*/
3691  SCIPABORT(); /* case is already handled in earlier if condition */
3692  return SCIP_INVALIDDATA; /*lint !e527*/
3693 
3695  /* fix aggregation variable y in x = a*y + c, instead of fixing x directly */
3696  assert(SCIPsetIsZero(set, var->obj));
3697  assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
3698  if( SCIPsetIsInfinity(set, fixedval) || SCIPsetIsInfinity(set, -fixedval) )
3699  childfixedval = (var->data.aggregate.scalar < 0.0 ? -fixedval : fixedval);
3700  else
3701  childfixedval = (fixedval - var->data.aggregate.constant)/var->data.aggregate.scalar;
3702  SCIP_CALL( SCIPvarFix(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue,
3703  childfixedval, infeasible, fixed) );
3704  break;
3705 
3707  SCIPerrorMessage("cannot fix a multiple aggregated variable\n");
3708  SCIPABORT();
3709  return SCIP_INVALIDDATA; /*lint !e527*/
3710 
3712  /* fix negation variable x in x' = offset - x, instead of fixing x' directly */
3713  assert(SCIPsetIsZero(set, var->obj));
3714  assert(var->negatedvar != NULL);
3716  assert(var->negatedvar->negatedvar == var);
3717  SCIP_CALL( SCIPvarFix(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue,
3718  var->data.negate.constant - fixedval, infeasible, fixed) );
3719  break;
3720 
3721  default:
3722  SCIPerrorMessage("unknown variable status\n");
3723  return SCIP_INVALIDDATA;
3724  }
3725 
3726  return SCIP_OKAY;
3727 }
3728 
3729 /** transforms given variables, scalars and constant to the corresponding active variables, scalars and constant
3730  *
3731  * If the number of needed active variables is greater than the available slots in the variable array, nothing happens except
3732  * that the required size is stored in the corresponding variable; hence, if afterwards the required size is greater than the
3733  * available slots (varssize), nothing happens; otherwise, the active variable representation is stored in the arrays.
3734  *
3735  * The reason for this approach is that we cannot reallocate memory, since we do not know how the
3736  * memory has been allocated (e.g., by a C++ 'new' or SCIP functions).
3737  */
3739  SCIP_SET* set, /**< global SCIP settings */
3740  SCIP_VAR** vars, /**< variable array to get active variables */
3741  SCIP_Real* scalars, /**< scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
3742  int* nvars, /**< pointer to number of variables and values in vars and scalars array */
3743  int varssize, /**< available slots in vars and scalars array */
3744  SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */
3745  int* requiredsize, /**< pointer to store the required array size for the active variables */
3746  SCIP_Bool mergemultiples /**< should multiple occurrences of a var be replaced by a single coeff? */
3747  )
3748 {
3749  SCIP_VAR** activevars;
3750  SCIP_Real* activescalars;
3751  int nactivevars;
3752  SCIP_Real activeconstant;
3753  SCIP_Bool activeconstantinf;
3754  int activevarssize;
3755 
3756  SCIP_VAR* var;
3757  SCIP_Real scalar;
3758  int v;
3759 
3760  SCIP_VAR** tmpvars;
3761  SCIP_VAR** multvars;
3762  SCIP_Real* tmpscalars;
3763  SCIP_Real* multscalars;
3764  int tmpvarssize;
3765  int ntmpvars;
3766  int nmultvars;
3767 
3768  SCIP_VAR* multvar;
3769  SCIP_Real multscalar;
3770  SCIP_Real multconstant;
3771  int pos;
3772 
3773  int noldtmpvars;
3774 
3775  SCIP_VAR** tmpvars2;
3776  SCIP_Real* tmpscalars2;
3777  int tmpvarssize2;
3778  int ntmpvars2;
3779 
3780  assert(set != NULL);
3781  assert(nvars != NULL);
3782  assert(vars != NULL || *nvars == 0);
3783  assert(scalars != NULL || *nvars == 0);
3784  assert(constant != NULL);
3785  assert(requiredsize != NULL);
3786  assert(*nvars <= varssize);
3787 
3788  *requiredsize = 0;
3789 
3790  if( *nvars == 0 )
3791  return SCIP_OKAY;
3792 
3793  assert(vars != NULL);
3794 
3795  /* handle the "easy" case of just one variable and avoid memory allocation if the variable is already active */
3796  if( *nvars == 1 && (vars[0]->varstatus == ((int) SCIP_VARSTATUS_COLUMN) || vars[0]->varstatus == ((int) SCIP_VARSTATUS_LOOSE)) )
3797  {
3798  *requiredsize = 1;
3799 
3800  return SCIP_OKAY;
3801  }
3802 
3803  nactivevars = 0;
3804  activeconstant = 0.0;
3805  activeconstantinf = FALSE;
3806  activevarssize = (*nvars) * 2;
3807  ntmpvars = *nvars;
3808  tmpvarssize = *nvars;
3809 
3810  tmpvarssize2 = 1;
3811  ntmpvars2 = 0;
3812 
3813  /* allocate temporary memory */
3814  SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpvars2, tmpvarssize2) );
3815  SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpscalars2, tmpvarssize2) );
3816  SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) );
3817  SCIP_CALL( SCIPsetAllocBufferArray(set, &activescalars, activevarssize) );
3818  SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpvars, vars, ntmpvars) );
3819  SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpscalars, scalars, ntmpvars) );
3820 
3821  /* to avoid unnecessary expanding of variable arrays while disaggregating several variables multiple times combine same variables
3822  * first, first get all corresponding variables with status loose, column, multaggr or fixed
3823  */
3824  for( v = ntmpvars - 1; v >= 0; --v )
3825  {
3826  var = tmpvars[v];
3827  scalar = tmpscalars[v];
3828 
3829  assert(var != NULL);
3830  /* transforms given variable, scalar and constant to the corresponding active, fixed, or
3831  * multi-aggregated variable, scalar and constant; if the variable resolves to a fixed
3832  * variable, "scalar" will be 0.0 and the value of the sum will be stored in "constant".
3833  */
3834  SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &scalar, &activeconstant) );
3835  assert(var != NULL);
3836 
3837  assert(SCIPsetIsInfinity(set, activeconstant) == (activeconstant == SCIPsetInfinity(set))); /*lint !e777*/
3838  assert(SCIPsetIsInfinity(set, -activeconstant) == (activeconstant == -SCIPsetInfinity(set))); /*lint !e777*/
3839 
3840  activeconstantinf = SCIPsetIsInfinity(set, activeconstant) || SCIPsetIsInfinity(set, -activeconstant);
3841 
3842  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
3843  || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
3846 
3847  tmpvars[v] = var;
3848  tmpscalars[v] = scalar;
3849  }
3850  noldtmpvars = ntmpvars;
3851 
3852  /* sort all variables to combine equal variables easily */
3853  SCIPsortPtrReal((void**)tmpvars, tmpscalars, SCIPvarComp, ntmpvars);
3854  for( v = ntmpvars - 1; v > 0; --v )
3855  {
3856  /* combine same variables */
3857  if( SCIPvarCompare(tmpvars[v], tmpvars[v - 1]) == 0 )
3858  {
3859  tmpscalars[v - 1] += tmpscalars[v];
3860  --ntmpvars;
3861  tmpvars[v] = tmpvars[ntmpvars];
3862  tmpscalars[v] = tmpscalars[ntmpvars];
3863  }
3864  }
3865  /* sort all variables again to combine equal variables later on */
3866  if( noldtmpvars > ntmpvars )
3867  SCIPsortPtrReal((void**)tmpvars, tmpscalars, SCIPvarComp, ntmpvars);
3868 
3869  /* collect for each variable the representation in active variables */
3870  while( ntmpvars >= 1 )
3871  {
3872  --ntmpvars;
3873  ntmpvars2 = 0;
3874  var = tmpvars[ntmpvars];
3875  scalar = tmpscalars[ntmpvars];
3876 
3877  assert(var != NULL);
3878 
3879  if( scalar == 0.0 )
3880  continue;
3881 
3882  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
3883  || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
3886 
3887  switch( SCIPvarGetStatus(var) )
3888  {
3889  case SCIP_VARSTATUS_LOOSE:
3890  case SCIP_VARSTATUS_COLUMN:
3891  /* x = a*y + c */
3892  if( nactivevars >= activevarssize )
3893  {
3894  activevarssize *= 2;
3895  SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) );
3896  SCIP_CALL( SCIPsetReallocBufferArray(set, &activescalars, activevarssize) );
3897  assert(nactivevars < activevarssize);
3898  }
3899  activevars[nactivevars] = var;
3900  activescalars[nactivevars] = scalar;
3901  nactivevars++;
3902  break;
3903 
3905  /* x = a_1*y_1 + ... + a_n*y_n + c */
3906  nmultvars = var->data.multaggr.nvars;
3907  multvars = var->data.multaggr.vars;
3908  multscalars = var->data.multaggr.scalars;
3909 
3910  if( nmultvars + ntmpvars > tmpvarssize )
3911  {
3912  while( nmultvars + ntmpvars > tmpvarssize )
3913  tmpvarssize *= 2;
3914  SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) );
3915  SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars, tmpvarssize) );
3916  assert(nmultvars + ntmpvars <= tmpvarssize);
3917  }
3918 
3919  if( nmultvars > tmpvarssize2 )
3920  {
3921  while( nmultvars > tmpvarssize2 )
3922  tmpvarssize2 *= 2;
3923  SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars2, tmpvarssize2) );
3924  SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars2, tmpvarssize2) );
3925  assert(nmultvars <= tmpvarssize2);
3926  }
3927 
3928  --nmultvars;
3929 
3930  for( ; nmultvars >= 0; --nmultvars )
3931  {
3932  multvar = multvars[nmultvars];
3933  multscalar = multscalars[nmultvars];
3934  multconstant = 0;
3935 
3936  assert(multvar != NULL);
3937  SCIP_CALL( SCIPvarGetProbvarSum(&multvar, set, &multscalar, &multconstant) );
3938  assert(multvar != NULL);
3939 
3940  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
3941  || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
3944 
3945  if( !activeconstantinf )
3946  {
3947  assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar));
3948 
3949  if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) )
3950  {
3951  assert(scalar != 0.0);
3952  if( scalar * multconstant > 0.0 )
3953  {
3954  activeconstant = SCIPsetInfinity(set);
3955  activeconstantinf = TRUE;
3956  }
3957  else
3958  {
3959  activeconstant = -SCIPsetInfinity(set);
3960  activeconstantinf = TRUE;
3961  }
3962  }
3963  else
3964  activeconstant += scalar * multconstant;
3965  }
3966 #ifndef NDEBUG
3967  else
3968  {
3969  assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 &&
3970  (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
3971  assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 &&
3972  (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
3973  }
3974 #endif
3975 
3976  if( SCIPsortedvecFindPtr((void**)tmpvars, SCIPvarComp, multvar, ntmpvars, &pos) )
3977  {
3978  assert(SCIPvarCompare(tmpvars[pos], multvar) == 0);
3979  tmpscalars[pos] += scalar * multscalar;
3980  }
3981  else
3982  {
3983  tmpvars2[ntmpvars2] = multvar;
3984  tmpscalars2[ntmpvars2] = scalar * multscalar;
3985  ++(ntmpvars2);
3986  assert(ntmpvars2 <= tmpvarssize2);
3987  }
3988  }
3989 
3990  /* sort all variables to combine equal variables easily */
3991  SCIPsortPtrReal((void**)tmpvars2, tmpscalars2, SCIPvarComp, ntmpvars2);
3992  for( v = ntmpvars2 - 1; v > 0; --v )
3993  {
3994  /* combine same variables */
3995  if( SCIPvarCompare(tmpvars2[v], tmpvars2[v - 1]) == 0 )
3996  {
3997  tmpscalars2[v - 1] += tmpscalars2[v];
3998  --ntmpvars2;
3999  tmpvars2[v] = tmpvars2[ntmpvars2];
4000  tmpscalars2[v] = tmpscalars2[ntmpvars2];
4001  }
4002  }
4003 
4004  for( v = 0; v < ntmpvars2; ++v )
4005  {
4006  tmpvars[ntmpvars] = tmpvars2[v];
4007  tmpscalars[ntmpvars] = tmpscalars2[v];
4008  ++(ntmpvars);
4009  assert(ntmpvars <= tmpvarssize);
4010  }
4011  SCIPsortPtrReal((void**)tmpvars, tmpscalars, SCIPvarComp, ntmpvars);
4012 
4013  if( !activeconstantinf )
4014  {
4015  assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar));
4016 
4017  multconstant = SCIPvarGetMultaggrConstant(var);
4018 
4019  if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) )
4020  {
4021  assert(scalar != 0.0);
4022  if( scalar * multconstant > 0.0 )
4023  {
4024  activeconstant = SCIPsetInfinity(set);
4025  activeconstantinf = TRUE;
4026  }
4027  else
4028  {
4029  activeconstant = -SCIPsetInfinity(set);
4030  activeconstantinf = TRUE;
4031  }
4032  }
4033  else
4034  activeconstant += scalar * multconstant;
4035  }
4036 #ifndef NDEBUG
4037  else
4038  {
4039  multconstant = SCIPvarGetMultaggrConstant(var);
4040  assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 &&
4041  (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4042  assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 &&
4043  (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4044  }
4045 #endif
4046  break;
4047 
4048  case SCIP_VARSTATUS_FIXED:
4052  default:
4053  /* case x = c, but actually we should not be here, since SCIPvarGetProbvarSum() returns a scalar of 0.0 for
4054  * fixed variables and is handled already
4055  */
4056  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
4057  assert(SCIPsetIsZero(set, var->glbdom.lb) && SCIPsetIsEQ(set, var->glbdom.lb, var->glbdom.ub));
4058  }
4059  }
4060 
4061  if( mergemultiples )
4062  {
4063  /* sort variable and scalar array by variable index */
4064  SCIPsortPtrReal((void**)activevars, activescalars, SCIPvarComp, nactivevars);
4065 
4066  /* eliminate duplicates and count required size */
4067  v = nactivevars - 1;
4068  while( v > 0 )
4069  {
4070  /* combine both variable since they are the same */
4071  if( SCIPvarCompare(activevars[v - 1], activevars[v]) == 0 )
4072  {
4073  if( activescalars[v - 1] + activescalars[v] != 0.0 )
4074  {
4075  activescalars[v - 1] += activescalars[v];
4076  --nactivevars;
4077  activevars[v] = activevars[nactivevars];
4078  activescalars[v] = activescalars[nactivevars];
4079  }
4080  else
4081  {
4082  --nactivevars;
4083  activevars[v] = activevars[nactivevars];
4084  activescalars[v] = activescalars[nactivevars];
4085  --nactivevars;
4086  --v;
4087  activevars[v] = activevars[nactivevars];
4088  activescalars[v] = activescalars[nactivevars];
4089  }
4090  }
4091  --v;
4092  }
4093  }
4094  *requiredsize = nactivevars;
4095 
4096  if( varssize >= *requiredsize )
4097  {
4098  assert(vars != NULL);
4099 
4100  *nvars = *requiredsize;
4101 
4102  if( !SCIPsetIsInfinity(set, *constant) && !SCIPsetIsInfinity(set, -(*constant)) )
4103  {
4104  /* if the activeconstant is infinite, the constant pointer gets the same value, otherwise add the value */
4105  if( activeconstantinf )
4106  (*constant) = activeconstant;
4107  else
4108  (*constant) += activeconstant;
4109  }
4110 #ifndef NDEBUG
4111  else
4112  {
4113  assert(!SCIPsetIsInfinity(set, (*constant)) || !SCIPsetIsInfinity(set, -activeconstant));
4114  assert(!SCIPsetIsInfinity(set, -(*constant)) || !SCIPsetIsInfinity(set, activeconstant));
4115  }
4116 #endif
4117 
4118  /* copy active variable and scalar array to the given arrays */
4119  for( v = 0; v < *nvars; ++v )
4120  {
4121  vars[v] = activevars[v];
4122  scalars[v] = activescalars[v]; /*lint !e613*/
4123  }
4124  }
4125 
4126  assert(SCIPsetIsInfinity(set, *constant) == ((*constant) == SCIPsetInfinity(set))); /*lint !e777*/
4127  assert(SCIPsetIsInfinity(set, -(*constant)) == ((*constant) == -SCIPsetInfinity(set))); /*lint !e777*/
4128 
4129  SCIPsetFreeBufferArray(set, &tmpvars2);
4130  SCIPsetFreeBufferArray(set, &tmpscalars2);
4131  SCIPsetFreeBufferArray(set, &tmpvars);
4132  SCIPsetFreeBufferArray(set, &tmpscalars);
4133  SCIPsetFreeBufferArray(set, &activevars);
4134  SCIPsetFreeBufferArray(set, &activescalars);
4135 
4136  return SCIP_OKAY;
4137 }
4138 
4139 
4140 /** flattens aggregation graph of multi-aggregated variable in order to avoid exponential recursion later on */
4142  SCIP_VAR* var, /**< problem variable */
4143  BMS_BLKMEM* blkmem, /**< block memory */
4144  SCIP_SET* set /**< global SCIP settings */
4145  )
4146 {
4147  SCIP_Real multconstant;
4148  int multvarssize;
4149  int nmultvars;
4150  int multrequiredsize;
4151 
4152  assert( var != NULL );
4153  assert( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR );
4154  assert(var->scip == set->scip);
4155 
4156  multconstant = var->data.multaggr.constant;
4157  nmultvars = var->data.multaggr.nvars;
4158  multvarssize = var->data.multaggr.varssize;
4159 
4160  SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) );
4161 
4162  if( multrequiredsize > multvarssize )
4163  {
4164  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.vars), multvarssize, multrequiredsize) );
4165  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.scalars), multvarssize, multrequiredsize) );
4166  multvarssize = multrequiredsize;
4167  SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) );
4168  assert( multrequiredsize <= multvarssize );
4169  }
4170  /**@note After the flattening the multi aggregation might resolve to be in fact an aggregation (or even a fixing?).
4171  * This issue is not resolved right now, since var->data.multaggr.nvars < 2 should not cause troubles. However, one
4172  * may loose performance hereby, since aggregated variables are easier to handle.
4173  *
4174  * Note, that there are two cases where SCIPvarFlattenAggregationGraph() is called: The easier one is that it is
4175  * called while installing the multi-aggregation. in principle, the described issue could be handled straightforward
4176  * in this case by aggregating or fixing the variable instead. The more complicated case is the one, when the
4177  * multi-aggregation is used, e.g., in linear presolving (and the variable is already declared to be multi-aggregated).
4178  *
4179  * By now, it is not allowed to fix or aggregate multi-aggregated variables which would be necessary in this case.
4180  *
4181  * The same issue appears in the SCIPvarGetProbvar...() methods.
4182  */
4183 
4184  var->data.multaggr.constant = multconstant;
4185  var->data.multaggr.nvars = nmultvars;
4186  var->data.multaggr.varssize = multvarssize;
4187 
4188  return SCIP_OKAY;
4189 }
4190 
4191 
4192 /** tightens the bounds of both variables in aggregation x = a*y + c */
4193 static
4195  SCIP_VAR* var, /**< problem variable */
4196  BMS_BLKMEM* blkmem, /**< block memory */
4197  SCIP_SET* set, /**< global SCIP settings */
4198  SCIP_STAT* stat, /**< problem statistics */
4199  SCIP_PROB* transprob, /**< tranformed problem data */
4200  SCIP_PROB* origprob, /**< original problem data */
4201  SCIP_PRIMAL* primal, /**< primal data */
4202  SCIP_TREE* tree, /**< branch and bound tree */
4203  SCIP_LP* lp, /**< current LP data */
4204  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4205  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4206  SCIP_VAR* aggvar, /**< variable y in aggregation x = a*y + c */
4207  SCIP_Real scalar, /**< multiplier a in aggregation x = a*y + c */
4208  SCIP_Real constant, /**< constant shift c in aggregation x = a*y + c */
4209  SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
4210  SCIP_Bool* fixed /**< pointer to store whether the variables were fixed */
4211  )
4212 {
4213  SCIP_Real varlb;
4214  SCIP_Real varub;
4215  SCIP_Real aggvarlb;
4216  SCIP_Real aggvarub;
4217  SCIP_Bool aggvarbdschanged;
4218 
4219  assert(var != NULL);
4220  assert(var->scip == set->scip);
4221  assert(aggvar != NULL);
4222  assert(!SCIPsetIsZero(set, scalar));
4223  assert(infeasible != NULL);
4224  assert(fixed != NULL);
4225 
4226  *infeasible = FALSE;
4227  *fixed = FALSE;
4228 
4229  SCIPdebugMessage("updating bounds of variables in aggregation <%s> == %g*<%s> %+g\n",
4230  var->name, scalar, aggvar->name, constant);
4231  SCIPdebugMessage(" old bounds: <%s> [%g,%g] <%s> [%g,%g]\n",
4232  var->name, var->glbdom.lb, var->glbdom.ub, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub);
4233 
4234  /* loop as long additional changes may be found */
4235  do
4236  {
4237  aggvarbdschanged = FALSE;
4238 
4239  /* update the bounds of the aggregated variable x in x = a*y + c */
4240  if( scalar > 0.0 )
4241  {
4242  if( SCIPsetIsInfinity(set, -aggvar->glbdom.lb) )
4243  varlb = -SCIPsetInfinity(set);
4244  else
4245  varlb = aggvar->glbdom.lb * scalar + constant;
4246  if( SCIPsetIsInfinity(set, aggvar->glbdom.ub) )
4247  varub = SCIPsetInfinity(set);
4248  else
4249  varub = aggvar->glbdom.ub * scalar + constant;
4250  }
4251  else
4252  {
4253  if( SCIPsetIsInfinity(set, -aggvar->glbdom.lb) )
4254  varub = SCIPsetInfinity(set);
4255  else
4256  varub = aggvar->glbdom.lb * scalar + constant;
4257  if( SCIPsetIsInfinity(set, aggvar->glbdom.ub) )
4258  varlb = -SCIPsetInfinity(set);
4259  else
4260  varlb = aggvar->glbdom.ub * scalar + constant;
4261  }
4262  varlb = MAX(varlb, var->glbdom.lb);
4263  varub = MIN(varub, var->glbdom.ub);
4264  SCIPvarAdjustLb(var, set, &varlb);
4265  SCIPvarAdjustUb(var, set, &varub);
4266 
4267  /* check the new bounds */
4268  if( SCIPsetIsGT(set, varlb, varub) )
4269  {
4270  /* the aggregation is infeasible */
4271  *infeasible = TRUE;
4272  return SCIP_OKAY;
4273  }
4274  else if( SCIPsetIsEQ(set, varlb, varub) )
4275  {
4276  /* the aggregated variable is fixed -> fix both variables */
4277  SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue,
4278  varlb, infeasible, fixed) );
4279  if( !(*infeasible) )
4280  {
4281  SCIP_Bool aggfixed;
4282 
4283  SCIP_CALL( SCIPvarFix(aggvar, blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue,
4284  (varlb-constant)/scalar, infeasible, &aggfixed) );
4285  assert(*fixed == aggfixed);
4286  }
4287  return SCIP_OKAY;
4288  }
4289  else
4290  {
4291  if( SCIPsetIsGT(set, varlb, var->glbdom.lb) )
4292  {
4293  SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, varlb) );
4294  }
4295  if( SCIPsetIsLT(set, varub, var->glbdom.ub) )
4296  {
4297  SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, varub) );
4298  }
4299 
4300  /* update the hole list of the aggregation variable */
4301  /**@todo update hole list of aggregation variable */
4302  }
4303 
4304  /* update the bounds of the aggregation variable y in x = a*y + c -> y = (x-c)/a */
4305  if( scalar > 0.0 )
4306  {
4307  if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
4308  aggvarlb = -SCIPsetInfinity(set);
4309  else
4310  aggvarlb = (var->glbdom.lb - constant) / scalar;
4311  if( SCIPsetIsInfinity(set, var->glbdom.ub) )
4312  aggvarub = SCIPsetInfinity(set);
4313  else
4314  aggvarub = (var->glbdom.ub - constant) / scalar;
4315  }
4316  else
4317  {
4318  if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
4319  aggvarub = SCIPsetInfinity(set);
4320  else
4321  aggvarub = (var->glbdom.lb - constant) / scalar;
4322  if( SCIPsetIsInfinity(set, var->glbdom.ub) )
4323  aggvarlb = -SCIPsetInfinity(set);
4324  else
4325  aggvarlb = (var->glbdom.ub - constant) / scalar;
4326  }
4327  aggvarlb = MAX(aggvarlb, aggvar->glbdom.lb);
4328  aggvarub = MIN(aggvarub, aggvar->glbdom.ub);
4329  SCIPvarAdjustLb(aggvar, set, &aggvarlb);
4330  SCIPvarAdjustUb(aggvar, set, &aggvarub);
4331 
4332  /* check the new bounds */
4333  if( SCIPsetIsGT(set, aggvarlb, aggvarub) )
4334  {
4335  /* the aggregation is infeasible */
4336  *infeasible = TRUE;
4337  return SCIP_OKAY;
4338  }
4339  else if( SCIPsetIsEQ(set, aggvarlb, aggvarub) )
4340  {
4341  /* the aggregation variable is fixed -> fix both variables */
4342  SCIP_CALL( SCIPvarFix(aggvar, blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue, aggvarlb,
4343  infeasible, fixed) );
4344  if( !(*infeasible) )
4345  {
4346  SCIP_Bool varfixed;
4347 
4348  SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue,
4349  aggvarlb * scalar + constant, infeasible, &varfixed) );
4350  assert(*fixed == varfixed);
4351  }
4352  return SCIP_OKAY;
4353  }
4354  else
4355  {
4356  SCIP_Real oldbd;
4357  if( SCIPsetIsGT(set, aggvarlb, aggvar->glbdom.lb) )
4358  {
4359  oldbd = aggvar->glbdom.lb;
4360  SCIP_CALL( SCIPvarChgLbGlobal(aggvar, blkmem, set, stat, lp, branchcand, eventqueue, aggvarlb) );
4361  aggvarbdschanged = !SCIPsetIsEQ(set, oldbd, aggvar->glbdom.lb);
4362  }
4363  if( SCIPsetIsLT(set, aggvarub, aggvar->glbdom.ub) )
4364  {
4365  oldbd = aggvar->glbdom.ub;
4366  SCIP_CALL( SCIPvarChgUbGlobal(aggvar, blkmem, set, stat, lp, branchcand, eventqueue, aggvarub) );
4367  aggvarbdschanged = aggvarbdschanged || !SCIPsetIsEQ(set, oldbd, aggvar->glbdom.ub);
4368  }
4369 
4370  /* update the hole list of the aggregation variable */
4371  /**@todo update hole list of aggregation variable */
4372  }
4373  }
4374  while( aggvarbdschanged );
4375 
4376  SCIPdebugMessage(" new bounds: <%s> [%g,%g] <%s> [%g,%g]\n",
4377  var->name, var->glbdom.lb, var->glbdom.ub, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub);
4378 
4379  return SCIP_OKAY;
4380 }
4381 
4382 /** converts loose variable into aggregated variable */
4384  SCIP_VAR* var, /**< loose problem variable */
4385  BMS_BLKMEM* blkmem, /**< block memory */
4386  SCIP_SET* set, /**< global SCIP settings */
4387  SCIP_STAT* stat, /**< problem statistics */
4388  SCIP_PROB* transprob, /**< tranformed problem data */
4389  SCIP_PROB* origprob, /**< original problem data */
4390  SCIP_PRIMAL* primal, /**< primal data */
4391  SCIP_TREE* tree, /**< branch and bound tree */
4392  SCIP_LP* lp, /**< current LP data */
4393  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
4394  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4395  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4396  SCIP_VAR* aggvar, /**< loose variable y in aggregation x = a*y + c */
4397  SCIP_Real scalar, /**< multiplier a in aggregation x = a*y + c */
4398  SCIP_Real constant, /**< constant shift c in aggregation x = a*y + c */
4399  SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
4400  SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
4401  )
4402 {
4403  SCIP_VAR** vars;
4404  SCIP_Real* coefs;
4405  SCIP_Real* constants;
4406  SCIP_Real obj;
4407  SCIP_Real branchfactor;
4408  SCIP_Bool fixed;
4409  int branchpriority;
4410  int nlocksdown;
4411  int nlocksup;
4412  int nvbds;
4413  int i;
4414  int j;
4415 
4416  assert(var != NULL);
4417  assert(var->scip == set->scip);
4418  assert(var->glbdom.lb == var->locdom.lb); /*lint !e777*/
4419  assert(var->glbdom.ub == var->locdom.ub); /*lint !e777*/
4420  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
4421  assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
4422  assert(infeasible != NULL);
4423  assert(aggregated != NULL);
4424 
4425  *infeasible = FALSE;
4426  *aggregated = FALSE;
4427 
4428  /* get active problem variable of aggregation variable */
4429  SCIP_CALL( SCIPvarGetProbvarSum(&aggvar, set, &scalar, &constant) );
4430 
4431  /* aggregation is a fixing, if the scalar is zero */
4432  if( SCIPsetIsZero(set, scalar) )
4433  {
4434  SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue, constant,
4435  infeasible, aggregated) );
4436  return SCIP_OKAY;
4437  }
4438 
4439  /* don't perform the aggregation if the aggregation variable is multi-aggregated itself */
4440  if( SCIPvarGetStatus(aggvar) == SCIP_VARSTATUS_MULTAGGR )
4441  return SCIP_OKAY;
4442 
4443  /**@todo currently we don't perform the aggregation if the aggregation variable has a non-empty hole list; this
4444  * should be changed in the future
4445  */
4446  if( SCIPvarGetHolelistGlobal(var) != NULL )
4447  return SCIP_OKAY;
4448 
4449  assert(aggvar != NULL);
4450  assert(aggvar->glbdom.lb == aggvar->locdom.lb); /*lint !e777*/
4451  assert(aggvar->glbdom.ub == aggvar->locdom.ub); /*lint !e777*/
4452  assert(SCIPvarGetStatus(aggvar) == SCIP_VARSTATUS_LOOSE);
4453 
4454  SCIPdebugMessage("aggregate variable <%s>[%g,%g] == %g*<%s>[%g,%g] %+g\n", var->name, var->glbdom.lb, var->glbdom.ub,
4455  scalar, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub, constant);
4456 
4457  /* if variable and aggregation variable are equal, the variable can be fixed: x == a*x + c => x == c/(1-a) */
4458  if( var == aggvar )
4459  {
4460  if( SCIPsetIsEQ(set, scalar, 1.0) )
4461  *infeasible = !SCIPsetIsZero(set, constant);
4462  else
4463  {
4464  SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue,
4465  constant/(1.0-scalar), infeasible, aggregated) );
4466  }
4467  return SCIP_OKAY;
4468  }
4469 
4470  /* tighten the bounds of aggregated and aggregation variable */
4471  SCIP_CALL( varUpdateAggregationBounds(var, blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue,
4472  aggvar, scalar, constant, infeasible, &fixed) );
4473  if( *infeasible || fixed )
4474  {
4475  *aggregated = fixed;
4476  return SCIP_OKAY;
4477  }
4478 
4479  /* delete implications and variable bounds of the aggregated variable from other variables, but keep them in the
4480  * aggregated variable
4481  */
4482  SCIP_CALL( varRemoveImplicsVbs(var, blkmem, set, FALSE, FALSE) );
4483 
4484  /* set the aggregated variable's objective value to 0.0 */
4485  obj = var->obj;
4486  SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
4487 
4488  /* unlock all rounding locks */
4489  nlocksdown = var->nlocksdown;
4490  nlocksup = var->nlocksup;
4491  var->nlocksdown = 0;
4492  var->nlocksup = 0;
4493 
4494  /* check, if variable should be used as NEGATED variable of the aggregation variable */
4495  if( SCIPvarIsBinary(var) && SCIPvarIsBinary(aggvar)
4496  && var->negatedvar == NULL && aggvar->negatedvar == NULL
4497  && SCIPsetIsEQ(set, scalar, -1.0) && SCIPsetIsEQ(set, constant, 1.0) )
4498  {
4499  /* link both variables as negation pair */
4500  var->varstatus = SCIP_VARSTATUS_NEGATED; /*lint !e641*/
4501  var->data.negate.constant = 1.0;
4502  var->negatedvar = aggvar;
4503  aggvar->negatedvar = var;
4504 
4505  /* copy doNotMultiaggr status */
4506  aggvar->donotmultaggr |= var->donotmultaggr;
4507 
4508  /* mark both variables to be non-deletable */
4510  SCIPvarMarkNotDeletable(aggvar);
4511  }
4512  else
4513  {
4514  /* convert variable into aggregated variable */
4515  var->varstatus = SCIP_VARSTATUS_AGGREGATED; /*lint !e641*/
4516  var->data.aggregate.var = aggvar;
4517  var->data.aggregate.scalar = scalar;
4518  var->data.aggregate.constant = constant;
4519 
4520  /* copy doNotMultiaggr status */
4521  aggvar->donotmultaggr |= var->donotmultaggr;
4522 
4523  /* mark both variables to be non-deletable */
4525  SCIPvarMarkNotDeletable(aggvar);
4526  }
4527 
4528  /* make aggregated variable a parent of the aggregation variable */
4529  SCIP_CALL( varAddParent(aggvar, blkmem, set, var) );
4530 
4531  /* relock the rounding locks of the variable, thus increasing the locks of the aggregation variable */
4532  SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, nlocksdown, nlocksup) );
4533 
4534  /* move the variable bounds to the aggregation variable:
4535  * - add all variable bounds again to the variable, thus adding it to the aggregation variable
4536  * - free the variable bounds data structures
4537  */
4538  if( var->vlbs != NULL )
4539  {
4540  nvbds = SCIPvboundsGetNVbds(var->vlbs);
4541  vars = SCIPvboundsGetVars(var->vlbs);
4542  coefs = SCIPvboundsGetCoefs(var->vlbs);
4543  constants = SCIPvboundsGetConstants(var->vlbs);
4544  for( i = 0; i < nvbds && !(*infeasible); ++i )
4545  {
4546  SCIP_CALL( SCIPvarAddVlb(var, blkmem, set, stat, transprob, origprob, tree, lp, cliquetable, branchcand,
4547  eventqueue, vars[i], coefs[i], constants[i], FALSE, infeasible, NULL) );
4548  }
4549  }
4550  if( var->vubs != NULL )
4551  {
4552  nvbds = SCIPvboundsGetNVbds(var->vubs);
4553  vars = SCIPvboundsGetVars(var->vubs);
4554  coefs = SCIPvboundsGetCoefs(var->vubs);
4555  constants = SCIPvboundsGetConstants(var->vubs);
4556  for( i = 0; i < nvbds && !(*infeasible); ++i )
4557  {
4558  SCIP_CALL( SCIPvarAddVub(var, blkmem, set, stat, transprob, origprob, tree, lp, cliquetable, branchcand,
4559  eventqueue, vars[i], coefs[i], constants[i], FALSE, infeasible, NULL) );
4560  }
4561  }
4562  SCIPvboundsFree(&var->vlbs, blkmem);
4563  SCIPvboundsFree(&var->vubs, blkmem);
4564 
4565  /* move the implications to the aggregation variable:
4566  * - add all implications again to the variable, thus adding it to the aggregation variable
4567  * - free the implications data structures
4568  */
4569  if( var->implics != NULL && SCIPvarGetType(aggvar) == SCIP_VARTYPE_BINARY )
4570  {
4571  assert(SCIPvarIsBinary(var));
4572  for( i = 0; i < 2; ++i )
4573  {
4574  SCIP_VAR** implvars;
4575  SCIP_BOUNDTYPE* impltypes;
4576  SCIP_Real* implbounds;
4577  int nimpls;
4578 
4579  nimpls = SCIPimplicsGetNImpls(var->implics, (SCIP_Bool)i);
4580  implvars = SCIPimplicsGetVars(var->implics, (SCIP_Bool)i);
4581  impltypes = SCIPimplicsGetTypes(var->implics, (SCIP_Bool)i);
4582  implbounds = SCIPimplicsGetBounds(var->implics, (SCIP_Bool)i);
4583 
4584  for( j = 0; j < nimpls && !(*infeasible); ++j )
4585  {
4586  /* @todo can't we omit transitive closure, because it should already have been done when adding the
4587  * implication to the aggregated variable?
4588  */
4589  SCIP_CALL( SCIPvarAddImplic(var, blkmem, set, stat, transprob, origprob, tree, lp, cliquetable, branchcand,
4590  eventqueue, (SCIP_Bool)i, implvars[j], impltypes[j], implbounds[j], FALSE, infeasible, NULL) );
4591  assert(nimpls == SCIPimplicsGetNImpls(var->implics, (SCIP_Bool)i));
4592  }
4593  }
4594  }
4595  SCIPimplicsFree(&var->implics, blkmem);
4596 
4597  /* move the cliques to the aggregation variable:
4598  * - remove the variable from all cliques it is contained in
4599  * - add all cliques again to the variable, thus adding it to the aggregated variable
4600  * - free the cliquelist data structures
4601  */
4602  if( SCIPvarIsBinary(var) )
4603  {
4605  if( var->cliquelist != NULL && SCIPvarIsBinary(aggvar) )
4606  {
4607  for( i = 0; i < 2; ++i )
4608  {
4609  SCIP_CLIQUE** cliques;
4610  int ncliques;
4611 
4612  ncliques = SCIPcliquelistGetNCliques(var->cliquelist, (SCIP_Bool)i);
4613  cliques = SCIPcliquelistGetCliques(var->cliquelist, (SCIP_Bool)i);
4614  for( j = 0; j < ncliques && !(*infeasible); ++j )
4615  {
4616  SCIP_CALL( SCIPvarAddClique(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue,
4617  (SCIP_Bool)i, cliques[j], infeasible, NULL) );
4618  assert(ncliques == SCIPcliquelistGetNCliques(var->cliquelist, (SCIP_Bool)i));
4619  }
4620  }
4621  }
4622  SCIPcliquelistFree(&var->cliquelist, blkmem);
4623  }
4624  assert(var->cliquelist == NULL);
4625 
4626  /* add the history entries to the aggregation variable and clear the history of the aggregated variable */
4627  SCIPhistoryUnite(aggvar->history, var->history, scalar < 0.0);
4628  SCIPhistoryUnite(aggvar->historycrun, var->historycrun, scalar < 0.0);
4629  SCIPhistoryReset(var->history);
4631 
4632  /* update flags of aggregation variable */
4633  aggvar->removable &= var->removable;
4634 
4635  /* update branching factors and priorities of both variables to be the maximum of both variables */
4636  branchfactor = MAX(aggvar->branchfactor, var->branchfactor);
4637  branchpriority = MAX(aggvar->branchpriority, var->branchpriority);
4638  SCIP_CALL( SCIPvarChgBranchFactor(aggvar, set, branchfactor) );
4639  SCIP_CALL( SCIPvarChgBranchPriority(aggvar, branchpriority) );
4640  SCIP_CALL( SCIPvarChgBranchFactor(var, set, branchfactor) );
4641  SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) );
4642 
4643  /* update branching direction of both variables to agree to a single direction */
4644  if( scalar >= 0.0 )
4645  {
4647  {
4649  }
4650  else if( (SCIP_BRANCHDIR)aggvar->branchdirection == SCIP_BRANCHDIR_AUTO )
4651  {
4653  }
4654  else if( var->branchdirection != aggvar->branchdirection )
4655  {
4657  }
4658  }
4659  else
4660  {
4662  {
4664  }
4665  else if( (SCIP_BRANCHDIR)aggvar->branchdirection == SCIP_BRANCHDIR_AUTO )
4666  {
4668  }
4669  else if( var->branchdirection != aggvar->branchdirection )
4670  {
4672  }
4673  }
4674 
4675  if( var->probindex != -1 )
4676  {
4677  /* inform problem about the variable's status change */
4678  SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, var) );
4679  }
4680 
4681  /* reset the objective value of the aggregated variable, thus adjusting the objective value of the aggregation
4682  * variable and the problem's objective offset
4683  */
4684  SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, lp, eventqueue, obj) );
4685 
4686  /* issue VARFIXED event */
4687  SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 1) );
4688 
4689  *aggregated = TRUE;
4690 
4691  return SCIP_OKAY;
4692 }
4693 
4694 /** Tries to aggregate an equality a*x + b*y == c consisting of two (implicit) integral active problem variables x and
4695  * y. An integer aggregation (i.e. integral coefficients a' and b', such that a'*x + b'*y == c') is searched.
4696  *
4697  * This can lead to the detection of infeasibility (e.g. if c' is fractional), or to a rejection of the aggregation
4698  * (denoted by aggregated == FALSE), if the resulting integer coefficients are too large and thus numerically instable.
4699  */
4700 static
4702  SCIP_SET* set, /**< global SCIP settings */
4703  BMS_BLKMEM* blkmem, /**< block memory */
4704  SCIP_STAT* stat, /**< problem statistics */
4705  SCIP_PROB* transprob, /**< tranformed problem data */
4706  SCIP_PROB* origprob, /**< original problem data */
4707  SCIP_PRIMAL* primal, /**< primal data */
4708  SCIP_TREE* tree, /**< branch and bound tree */
4709  SCIP_LP* lp, /**< current LP data */
4710  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
4711  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4712  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
4713  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4714  SCIP_VAR* varx, /**< integral variable x in equality a*x + b*y == c */
4715  SCIP_VAR* vary, /**< integral variable y in equality a*x + b*y == c */
4716  SCIP_Real scalarx, /**< multiplier a in equality a*x + b*y == c */
4717  SCIP_Real scalary, /**< multiplier b in equality a*x + b*y == c */
4718  SCIP_Real rhs, /**< right hand side c in equality a*x + b*y == c */
4719  SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
4720  SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
4721  )
4722 {
4723  SCIP_VAR* aggvar;
4724  char aggvarname[SCIP_MAXSTRLEN];
4725  SCIP_Longint scalarxn = 0;
4726  SCIP_Longint scalarxd = 0;
4727  SCIP_Longint scalaryn = 0;
4728  SCIP_Longint scalaryd = 0;
4729  SCIP_Longint a;
4730  SCIP_Longint b;
4731  SCIP_Longint c;
4732  SCIP_Longint scm;
4733  SCIP_Longint gcd;
4734  SCIP_Longint currentclass;
4735  SCIP_Longint classstep;
4736  SCIP_Longint xsol;
4737  SCIP_Longint ysol;
4738  SCIP_Bool success;
4739  SCIP_VARTYPE vartype;
4740 
4741 #define MAXDNOM 1000000LL
4742 
4743  assert(set != NULL);
4744  assert(blkmem != NULL);
4745  assert(stat != NULL);
4746  assert(transprob != NULL);
4747  assert(origprob != NULL);
4748  assert(tree != NULL);
4749  assert(lp != NULL);
4750  assert(cliquetable != NULL);
4751  assert(branchcand != NULL);
4752  assert(eventqueue != NULL);
4753  assert(varx != NULL);
4754  assert(vary != NULL);
4755  assert(varx != vary);
4756  assert(infeasible != NULL);
4757  assert(aggregated != NULL);
4758  assert(SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING);
4759  assert(SCIPvarGetStatus(varx) == SCIP_VARSTATUS_LOOSE);
4761  assert(SCIPvarGetStatus(vary) == SCIP_VARSTATUS_LOOSE);
4763  assert(!SCIPsetIsZero(set, scalarx));
4764  assert(!SCIPsetIsZero(set, scalary));
4765 
4766  *infeasible = FALSE;
4767  *aggregated = FALSE;
4768 
4769  /* get rational representation of coefficients */
4770  success = SCIPrealToRational(scalarx, -SCIPsetEpsilon(set), SCIPsetEpsilon(set), MAXDNOM, &scalarxn, &scalarxd);
4771  if( success )
4772  success = SCIPrealToRational(scalary, -SCIPsetEpsilon(set), SCIPsetEpsilon(set), MAXDNOM, &scalaryn, &scalaryd);
4773  if( !success )
4774  return SCIP_OKAY;
4775  assert(scalarxd >= 1);
4776  assert(scalaryd >= 1);
4777 
4778  /* multiply equality with smallest common denominator */
4779  scm = SCIPcalcSmaComMul(scalarxd, scalaryd);
4780  a = (scm/scalarxd)*scalarxn;
4781  b = (scm/scalaryd)*scalaryn;
4782  rhs *= scm;
4783 
4784  /* divide equality by the greatest common divisor of a and b */
4785  gcd = SCIPcalcGreComDiv(ABS(a), ABS(b));
4786  a /= gcd;
4787  b /= gcd;
4788  rhs /= gcd;
4789  assert(a != 0);
4790  assert(b != 0);
4791 
4792  /* check, if right hand side is integral */
4793  if( !SCIPsetIsFeasIntegral(set, rhs) )
4794  {
4795  *infeasible = TRUE;
4796  return SCIP_OKAY;
4797  }
4798  c = (SCIP_Longint)(SCIPsetFeasFloor(set, rhs));
4799 
4800  /* check, if we are in an easy case with either |a| = 1 or |b| = 1 */
4801  if( (a == 1 || a == -1) && SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER )
4802  {
4803  /* aggregate x = - b/a*y + c/a */
4804  /*lint --e{653}*/
4805  SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, lp, cliquetable, branchcand, eventqueue,
4806  vary, (SCIP_Real)(-b/a), (SCIP_Real)(c/a), infeasible, aggregated) );
4807  assert(*aggregated);
4808  return SCIP_OKAY;
4809  }
4810  if( (b == 1 || b == -1) && SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER )
4811  {
4812  /* aggregate y = - a/b*x + c/b */
4813  /*lint --e{653}*/
4814  SCIP_CALL( SCIPvarAggregate(vary, blkmem, set, stat, transprob, origprob, primal, tree, lp, cliquetable, branchcand, eventqueue,
4815  varx, (SCIP_Real)(-a/b), (SCIP_Real)(c/b), infeasible, aggregated) );
4816  assert(*aggregated);
4817  return SCIP_OKAY;
4818  }
4819 
4820  /* Both variables are integers, their coefficients are not multiples of each other, and they don't have any
4821  * common divisor. Let (x',y') be a solution of the equality
4822  * a*x + b*y == c -> a*x == c - b*y
4823  * Then x = -b*z + x', y = a*z + y' with z integral gives all solutions to the equality.
4824  */
4825 
4826  /* find initial solution (x',y'):
4827  * - find y' such that c - b*y' is a multiple of a
4828  * - start in equivalence class c%a
4829  * - step through classes, where each step increases class number by (-b)%a, until class 0 is visited
4830  * - if equivalence class 0 is visited, we are done: y' equals the number of steps taken
4831  * - because a and b don't have a common divisor, each class is visited at most once, and at most a-1 steps are needed
4832  * - calculate x' with x' = (c - b*y')/a (which must be integral)
4833  *
4834  * Algorithm works for a > 0 only.
4835  */
4836  if( a < 0 )
4837  {
4838  a = -a;
4839  b = -b;
4840  c = -c;
4841  }
4842  assert(0 <= a);
4843 
4844  /* search upwards from ysol = 0 */
4845  ysol = 0;
4846  currentclass = c%a;
4847  if( currentclass < 0 )
4848  currentclass += a;
4849  assert(0 <= currentclass && currentclass < a);
4850 
4851  classstep = (-b)%a;
4852 
4853  if( classstep < 0 )
4854  classstep += a;
4855  assert(0 <= classstep && classstep < a);
4856 
4857  while( currentclass != 0 )
4858  {
4859  assert(0 <= currentclass && currentclass < a);
4860  currentclass += classstep;
4861  if( currentclass >= a )
4862  currentclass -= a;
4863  ysol++;
4864  }
4865  assert(ysol < a);
4866  assert(((c - b*ysol)%a) == 0);
4867 
4868  xsol = (c - b*ysol)/a;
4869 
4870  /* determine variable type for new artificial variable:
4871  *
4872  * if both variables are implicit integer the new variable can be implicit too, because the integer implication on
4873  * these both variables should be enforced by some other variables, otherwise the new variable needs to be of
4874  * integral type
4875  */
4878 
4879  /* feasible solutions are (x,y) = (x',y') + z*(-b,a)
4880  * - create new integer variable z with infinite bounds
4881  * - aggregate variable x = -b*z + x'
4882  * - aggregate variable y = a*z + y'
4883  * - the bounds of z are calculated automatically during aggregation
4884  */
4885  (void) SCIPsnprintf(aggvarname, SCIP_MAXSTRLEN, "agg%d", stat->nvaridx);
4886  SCIP_CALL( SCIPvarCreateTransformed(&aggvar, blkmem, set, stat,
4887  aggvarname, -SCIPsetInfinity(set), SCIPsetInfinity(set), 0.0, vartype,
4889  NULL, NULL, NULL, NULL, NULL) );
4890 
4891  SCIP_CALL( SCIPprobAddVar(transprob, blkmem, set, lp, branchcand, eventfilter, eventqueue, aggvar) );
4892 
4893  SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, lp, cliquetable, branchcand, eventqueue,
4894  aggvar, (SCIP_Real)(-b), (SCIP_Real)xsol, infeasible, aggregated) );
4895  assert(*aggregated || *infeasible);
4896 
4897  if( !(*infeasible) )
4898  {
4899  SCIP_CALL( SCIPvarAggregate(vary, blkmem, set, stat, transprob, origprob, primal, tree, lp, cliquetable, branchcand, eventqueue,
4900  aggvar, (SCIP_Real)a, (SCIP_Real)ysol, infeasible, aggregated) );
4901  assert(*aggregated || *infeasible);
4902  }
4903 
4904  /* release z */
4905  SCIP_CALL( SCIPvarRelease(&aggvar, blkmem, set, eventqueue, lp) );
4906 
4907  return SCIP_OKAY;
4908 }
4909 
4910 /** performs second step of SCIPaggregateVars():
4911  * the variable to be aggregated is chosen among active problem variables x' and y', preferring a less strict variable
4912  * type as aggregation variable (i.e. continuous variables are preferred over implicit integers, implicit integers
4913  * or integers over binaries). If none of the variables is continuous, it is tried to find an integer
4914  * aggregation (i.e. integral coefficients a'' and b'', such that a''*x' + b''*y' == c''). This can lead to
4915  * the detection of infeasibility (e.g. if c'' is fractional), or to a rejection of the aggregation (denoted by
4916  * aggregated == FALSE), if the resulting integer coefficients are too large and thus numerically instable.
4917  */
4919  SCIP_SET* set, /**< global SCIP settings */
4920  BMS_BLKMEM* blkmem, /**< block memory */
4921  SCIP_STAT* stat, /**< problem statistics */
4922  SCIP_PROB* transprob, /**< tranformed problem data */
4923  SCIP_PROB* origprob, /**< original problem data */
4924  SCIP_PRIMAL* primal, /**< primal data */
4925  SCIP_TREE* tree, /**< branch and bound tree */
4926  SCIP_LP* lp, /**< current LP data */
4927  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
4928  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4929  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
4930  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4931  SCIP_VAR* varx, /**< variable x in equality a*x + b*y == c */
4932  SCIP_VAR* vary, /**< variable y in equality a*x + b*y == c */
4933  SCIP_Real scalarx, /**< multiplier a in equality a*x + b*y == c */
4934  SCIP_Real scalary, /**< multiplier b in equality a*x + b*y == c */
4935  SCIP_Real rhs, /**< right hand side c in equality a*x + b*y == c */
4936  SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
4937  SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
4938  )
4939 {
4940  SCIP_Bool easyaggr;
4941 
4942  assert(set != NULL);
4943  assert(blkmem != NULL);
4944  assert(stat != NULL);
4945  assert(transprob != NULL);
4946  assert(origprob != NULL);
4947  assert(tree != NULL);
4948  assert(lp != NULL);
4949  assert(cliquetable != NULL);
4950  assert(branchcand != NULL);
4951  assert(eventqueue != NULL);
4952  assert(varx != NULL);
4953  assert(vary != NULL);
4954  assert(varx != vary);
4955  assert(infeasible != NULL);
4956  assert(aggregated != NULL);
4957  assert(SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING);
4958  assert(SCIPvarGetStatus(varx) == SCIP_VARSTATUS_LOOSE);
4959  assert(SCIPvarGetStatus(vary) == SCIP_VARSTATUS_LOOSE);
4960  assert(!SCIPsetIsZero(set, scalarx));
4961  assert(!SCIPsetIsZero(set, scalary));
4962 
4963  *infeasible = FALSE;
4964  *aggregated = FALSE;
4965 
4966  /* prefer aggregating the variable of more general type (preferred aggregation variable is varx) */
4967  if( SCIPvarGetType(vary) > SCIPvarGetType(varx) )
4968  {
4969  SCIP_VAR* var;
4970  SCIP_Real scalar;
4971 
4972  /* switch the variables, such that varx is the variable of more general type (cont > implint > int > bin) */
4973  var = vary;
4974  vary = varx;
4975  varx = var;
4976  scalar = scalary;
4977  scalary = scalarx;
4978  scalarx = scalar;
4979  }
4980  assert(SCIPvarGetType(varx) >= SCIPvarGetType(vary));
4981 
4982  /* figure out, which variable should be aggregated */
4983  easyaggr = FALSE;
4984 
4985  /* check if it is an easy aggregation that means:
4986  *
4987  * a*x + b*y == c -> x == -b/a * y + c/a iff b/a != 0 and abs(b/a) < infinity
4988  */
4989  if( !SCIPsetIsZero(set, scalary/scalarx) && !SCIPsetIsInfinity(set, REALABS(scalary/scalarx)) )
4990  {
4992  easyaggr = TRUE;
4993  else if( SCIPsetIsFeasIntegral(set, scalary/scalarx) )
4994  easyaggr = TRUE;
4995  }
4996 
4997  /* check if we have easy aggregation if we flip the variables x and y that means:
4998  *
4999  * a*x + b*y == c -> y == -a/b * x + c/b iff a/b != 0 and abs(a/b) < infinity
5000  */
5001  if( !easyaggr && !SCIPsetIsZero(set, scalarx/scalary) && !SCIPsetIsInfinity(set, REALABS(scalarx/scalary))
5002  && SCIPsetIsFeasIntegral(set, scalarx/scalary) && SCIPvarGetType(vary) == SCIPvarGetType(varx))
5003  {
5004  SCIP_VAR* var;
5005  SCIP_Real scalar;
5006 
5007  /* switch the variables, such that varx is the aggregated variable */
5008  var = vary;
5009  vary = varx;
5010  varx = var;
5011  scalar = scalary;
5012  scalary = scalarx;
5013  scalarx = scalar;
5014  easyaggr = TRUE;
5015  }
5016 
5017  /* if we did not find an easy aggregation so far, the aggregation is still easy if both variables are continuous
5018  *
5019  * a*x + b*y == c -> x == -b/a * y + c/a iff b/a != 0 and abs(b/a) < infinty
5020  */
5021  if( !easyaggr && !SCIPsetIsZero(set, scalary/scalarx) && !SCIPsetIsInfinity(set, REALABS(scalary/scalarx))
5023  {
5024  assert(SCIPvarGetType(vary) == SCIP_VARTYPE_CONTINUOUS);
5025  easyaggr = TRUE;
5026  }
5027 
5028  /* did we find an "easy" aggregation? */
5029  if( easyaggr )
5030  {
5031  SCIP_Real scalar;
5032  SCIP_Real constant;
5033 
5034  assert(SCIPvarGetType(varx) >= SCIPvarGetType(vary));
5035 
5036  /* calculate aggregation scalar and constant: a*x + b*y == c => x == -b/a * y + c/a */
5037  scalar = -scalary/scalarx;
5038  constant = rhs/scalarx;
5039 
5040  /* check aggregation for integer feasibility */
5043  && SCIPsetIsFeasIntegral(set, scalar) && !SCIPsetIsFeasIntegral(set, constant) )
5044  {
5045  *infeasible = TRUE;
5046  return SCIP_OKAY;
5047  }
5048 
5049 #if 0
5050  /* if the aggregation scalar is fractional, we cannot (for technical reasons) and do not want to aggregate implicit integer variables,
5051  * since then we would loose the corresponding divisibility property
5052  * @todo analyze the possible values of x and y and try to derive fixings, infeasibility, bound changes or domain holes
5053  */
5054  if( SCIPvarGetType(varx) == SCIP_VARTYPE_IMPLINT && !SCIPsetIsFeasIntegral(set, scalar) )
5055  {
5056  return SCIP_OKAY;
5057  }
5058 #else
5059  assert(SCIPvarGetType(varx) != SCIP_VARTYPE_IMPLINT || SCIPsetIsFeasIntegral(set, scalar));
5060 #endif
5061 
5062  /* aggregate the variable */
5063  SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, lp, cliquetable, branchcand, eventqueue,
5064  vary, scalar, constant, infeasible, aggregated) );
5065  assert(*aggregated || *infeasible);
5066  }
5069  {
5070  /* the variables are both integral: we have to try to find an integer aggregation */
5071  SCIP_CALL( tryAggregateIntVars(set, blkmem, stat, transprob, origprob, primal, tree, lp, cliquetable, branchcand, eventfilter, eventqueue,
5072  varx, vary, scalarx, scalary, rhs, infeasible, aggregated) );
5073  }
5074 #if 0
5075  else
5076  {
5077  /* @todo check for fixings or infeasibility when having one binary variable and another integer/implicit/binary
5078  * variable
5079  */
5080  }
5081 #endif
5082 
5083  return SCIP_OKAY;
5084 }
5085 
5086 /** converts variable into multi-aggregated variable */
5088  SCIP_VAR* var, /**< problem variable */
5089  BMS_BLKMEM* blkmem, /**< block memory */
5090  SCIP_SET* set, /**< global SCIP settings */
5091  SCIP_STAT* stat, /**< problem statistics */
5092  SCIP_PROB* transprob, /**< tranformed problem data */
5093  SCIP_PROB* origprob, /**< original problem data */
5094  SCIP_PRIMAL* primal, /**< primal data */
5095  SCIP_TREE* tree, /**< branch and bound tree */
5096  SCIP_LP* lp, /**< current LP data */
5097  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
5098  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
5099  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
5100  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5101  int naggvars, /**< number n of variables in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5102  SCIP_VAR** aggvars, /**< variables y_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5103  SCIP_Real* scalars, /**< multipliers a_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5104  SCIP_Real constant, /**< constant shift c in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5105  SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
5106  SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
5107  )
5108 {
5109  SCIP_VAR** tmpvars;
5110  SCIP_Real* tmpscalars;
5111  SCIP_Real obj;
5112  SCIP_Real branchfactor;
5113  int branchpriority;
5114  SCIP_BRANCHDIR branchdirection;
5115  int nlocksdown;
5116  int nlocksup;
5117  int v;
5118  SCIP_Real tmpconstant;
5119  SCIP_Real tmpscalar;
5120  int ntmpvars;
5121  int tmpvarssize;
5122  int tmprequiredsize;
5123 
5124  assert(var != NULL);
5125  assert(var->scip == set->scip);
5126  assert(var->glbdom.lb == var->locdom.lb); /*lint !e777*/
5127  assert(var->glbdom.ub == var->locdom.ub); /*lint !e777*/
5128  assert(naggvars == 0 || aggvars != NULL);
5129  assert(naggvars == 0 || scalars != NULL);
5130  assert(infeasible != NULL);
5131  assert(aggregated != NULL);
5132 
5133  SCIPdebugMessage("trying multi-aggregating variable <%s> == ...%d vars... %+g\n", var->name, naggvars, constant);
5134 
5135  *infeasible = FALSE;
5136  *aggregated = FALSE;
5137 
5138  switch( SCIPvarGetStatus(var) )
5139  {
5141  if( var->data.original.transvar == NULL )
5142  {
5143  SCIPerrorMessage("cannot multi-aggregate an untransformed original variable\n");
5144  return SCIP_INVALIDDATA;
5145  }
5146  SCIP_CALL( SCIPvarMultiaggregate(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree, lp,
5147  cliquetable, branchcand, eventfilter, eventqueue, naggvars, aggvars, scalars, constant, infeasible, aggregated) );
5148  break;
5149 
5150  case SCIP_VARSTATUS_LOOSE:
5151  assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
5152 
5153  /* check if we would create a self-reference */
5154  ntmpvars = naggvars;
5155  tmpvarssize = naggvars;
5156  tmpconstant = constant;
5157  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &tmpvars, aggvars, ntmpvars) );
5158  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &tmpscalars, scalars, ntmpvars) );
5159 
5160  /* get all active variables for multi-aggregation */
5161  SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) );
5162  if( tmprequiredsize > tmpvarssize )
5163  {
5164  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpvars, tmpvarssize, tmprequiredsize) );
5165  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpscalars, tmpvarssize, tmprequiredsize) );
5166  tmpvarssize = tmprequiredsize;
5167  SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) );
5168  assert( tmprequiredsize <= tmpvarssize );
5169  }
5170 
5171  tmpscalar = 0.0;
5172 
5173  /* iterate over all active variables of the multi-aggregation and filter all variables which are equal to the
5174  * possible multi-aggregated variable
5175  */
5176  for( v = ntmpvars - 1; v >= 0; --v )
5177  {
5178  assert(tmpvars[v] != NULL);
5179  assert(SCIPvarGetStatus(tmpvars[v]) == SCIP_VARSTATUS_LOOSE);
5180 
5181  if( tmpvars[v]->index == var->index )
5182  {
5183  tmpscalar += tmpscalars[v];
5184  tmpvars[v] = tmpvars[ntmpvars - 1];
5185  tmpscalars[v] = tmpscalars[ntmpvars - 1];
5186  --ntmpvars;
5187  }
5188  }
5189 
5190  /* this means that x = x + a_1*y_1 + ... + a_n*y_n + c */
5191  if( SCIPsetIsEQ(set, tmpscalar, 1.0) )
5192  {
5193  if( ntmpvars == 0 )
5194  {
5195  if( SCIPsetIsZero(set, tmpconstant) ) /* x = x */
5196  {
5197  SCIPdebugMessage("Possible multi-aggregation was completely resolved and detected to be redundant.\n");
5198  goto TERMINATE;
5199  }
5200  else /* 0 = c and c != 0 */
5201  {
5202  SCIPdebugMessage("Multi-aggregation was completely resolved and led to infeasibility.\n");
5203  *infeasible = TRUE;
5204  goto TERMINATE;
5205  }
5206  }
5207  else if( ntmpvars == 1 ) /* 0 = a*y + c => y = -c/a */
5208  {
5209  assert(tmpscalars[0] != 0.0);
5210  assert(tmpvars[0] != NULL);
5211 
5212  SCIPdebugMessage("Possible multi-aggregation led to fixing of variable <%s> to %g.\n", SCIPvarGetName(tmpvars[0]), -constant/tmpscalars[0]);
5213  SCIP_CALL( SCIPvarFix(tmpvars[0], blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue, -constant/tmpscalars[0],
5214  infeasible, aggregated) );
5215  goto TERMINATE;
5216  }
5217  else if( ntmpvars == 2 ) /* 0 = a_1*y_1 + a_2*y_2 + c => y_1 = -a_2/a_1 * y_2 - c/a_1 */
5218  {
5219  /* both variables are different active problem variables, and both scalars are non-zero: try to aggregate them */
5220 
5221  SCIPdebugMessage("Possible multi-aggregation led to aggregation of variables <%s> and <%s> with scalars %g and %g and constant %g.\n", SCIPvarGetName(tmpvars[0]), SCIPvarGetName(tmpvars[1]), tmpscalars[0], tmpscalars[1], -tmpconstant);
5222 
5223  SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal, tree, lp, cliquetable, branchcand, eventfilter, eventqueue,
5224  tmpvars[0], tmpvars[1], tmpscalars[0], tmpscalars[1], -tmpconstant, infeasible, aggregated) );
5225 
5226  goto TERMINATE;
5227  }
5228  else
5229  /* @todo: it is possible to multi-aggregate another variable, does it make sense?,
5230  * rest looks like 0 = a_1*y_1 + ... + a_n*y_n + c and has at least three variables
5231  */
5232  goto TERMINATE;
5233  }
5234  /* this means that x = b*x + a_1*y_1 + ... + a_n*y_n + c */
5235  else if( !SCIPsetIsZero(set, tmpscalar) )
5236  {
5237  tmpscalar = 1 - tmpscalar;
5238  tmpconstant /= tmpscalar;
5239  for( v = ntmpvars - 1; v >= 0; --v )
5240  tmpscalars[v] /= tmpscalar;
5241  }
5242 
5243  /* check, if we are in one of the simple cases */
5244  if( ntmpvars == 0 )
5245  {
5246  SCIPdebugMessage("Possible multi-aggregation led to fixing of variable <%s> to %g.\n", SCIPvarGetName(var), tmpconstant);
5247  SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, lp, branchcand, eventqueue, tmpconstant,
5248  infeasible, aggregated) );
5249  goto TERMINATE;
5250  }
5251 
5252  /* if only one aggregation variable is left, we perform a normal aggregation instead of a multi-aggregation */
5253  if( ntmpvars == 1 )
5254  {
5255  SCIPdebugMessage("Possible multi-aggregation led to aggregation of variables <%s> and <%s> with scalars %g and %g and constant %g.\n", SCIPvarGetName(var), SCIPvarGetName(tmpvars[0]), 1.0, -tmpscalars[0], tmpconstant);
5256 
5257  SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal, tree, lp, cliquetable, branchcand, eventfilter, eventqueue,
5258  var, tmpvars[0], 1.0, -tmpscalars[0], tmpconstant, infeasible, aggregated) );
5259 
5260  goto TERMINATE;
5261  }
5262 
5263  /**@todo currently we don't perform the multi aggregation if the multi aggregation variable has a non
5264  * empty hole list; this should be changed in the future */
5265  if( SCIPvarGetHolelistGlobal(var) != NULL )
5266  goto TERMINATE;
5267 
5268  /* if the variable is not allowed to be multi-aggregated */
5269  if( SCIPvarDoNotMultaggr(var) )
5270  {
5271  SCIPdebugMessage("variable is not allowed to be multi-aggregated.\n");
5272  goto TERMINATE;
5273  }
5274 
5275  /* if the variable to be multi-aggregated has implications or variable bounds (i.e. is the implied variable or
5276  * variable bound variable of another variable), we have to remove it from the other variables implications or
5277  * variable bounds
5278  */
5279  SCIP_CALL( varRemoveImplicsVbs(var, blkmem, set, FALSE, TRUE) );
5280  assert(var->vlbs == NULL);
5281  assert(var->vubs == NULL);
5282  assert(var->implics == NULL);
5283 
5284  /* the variable also has to be removed from all cliques */
5285  if( SCIPvarIsBinary(var) )
5286  {
5288  SCIPcliquelistFree(&var->cliquelist, blkmem);
5289  }
5290  assert(var->cliquelist == NULL);
5291 
5292  /* set the aggregated variable's objective value to 0.0 */
5293  obj = var->obj;
5294  SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
5295 
5296  /* since we change the variable type form loose to multi aggregated, we have to adjust the number of loose
5297  * variables in the LP data structure; the loose objective value (looseobjval) in the LP data structure, however,
5298  * gets adjusted automatically, due to the event SCIP_EVENTTYPE_OBJCHANGED which dropped in the moment where the
5299  * objective of this variable is set to zero
5300  */
5301  SCIPlpDecNLoosevars(lp);
5302 
5303  /* unlock all rounding locks */
5304  nlocksdown = var->nlocksdown;
5305  nlocksup = var->nlocksup;
5306  var->nlocksdown = 0;
5307  var->nlocksup = 0;
5308 
5309  /* convert variable into multi-aggregated variable */
5310  var->varstatus = SCIP_VARSTATUS_MULTAGGR; /*lint !e641*/
5311  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->data.multaggr.vars, tmpvars, ntmpvars) );
5312  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->data.multaggr.scalars, tmpscalars, ntmpvars) );
5313  var->data.multaggr.constant = tmpconstant;
5314  var->data.multaggr.nvars = ntmpvars;
5315  var->data.multaggr.varssize = ntmpvars;
5316 
5317  /* mark variable to be non-deletable */
5319 
5320  /* relock the rounding locks of the variable, thus increasing the locks of the aggregation variables */
5321  SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, nlocksdown, nlocksup) );
5322 
5323  /* update flags and branching factors and priorities of aggregation variables;
5324  * update preferred branching direction of all aggregation variables that don't have a preferred direction yet
5325  */
5326  branchfactor = var->branchfactor;
5327  branchpriority = var->branchpriority;
5328  branchdirection = (SCIP_BRANCHDIR)var->branchdirection;
5329 
5330  for( v = 0; v < ntmpvars; ++v )
5331  {
5332  assert(tmpvars[v] != NULL);
5333  tmpvars[v]->removable &= var->removable;
5334  branchfactor = MAX(tmpvars[v]->branchfactor, branchfactor);
5335  branchpriority = MAX(tmpvars[v]->branchpriority, branchpriority);
5336 
5337  /* mark variable to be non-deletable */
5338  SCIPvarMarkNotDeletable(tmpvars[v]);
5339  }
5340  for( v = 0; v < ntmpvars; ++v )
5341  {
5342  SCIP_CALL( SCIPvarChgBranchFactor(tmpvars[v], set, branchfactor) );
5343  SCIP_CALL( SCIPvarChgBranchPriority(tmpvars[v], branchpriority) );
5344  if( (SCIP_BRANCHDIR)tmpvars[v]->branchdirection == SCIP_BRANCHDIR_AUTO )
5345  {
5346  if( tmpscalars[v] >= 0.0 )
5347  {
5348  SCIP_CALL( SCIPvarChgBranchDirection(tmpvars[v], branchdirection) );
5349  }
5350  else
5351  {
5352  SCIP_CALL( SCIPvarChgBranchDirection(tmpvars[v], SCIPbranchdirOpposite(branchdirection)) );
5353  }
5354  }
5355  }
5356  SCIP_CALL( SCIPvarChgBranchFactor(var, set, branchfactor) );
5357  SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) );
5358 
5359  if( var->probindex != -1 )
5360  {
5361  /* inform problem about the variable's status change */
5362  SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, var) );
5363  }
5364 
5365  /* issue VARFIXED event */
5366  SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 2) );
5367 
5368  /* reset the objective value of the aggregated variable, thus adjusting the objective value of the aggregation
5369  * variables and the problem's objective offset
5370  */
5371  SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, lp, eventqueue, obj) );
5372 
5373  *aggregated = TRUE;
5374 
5375  TERMINATE:
5376  BMSfreeBlockMemoryArray(blkmem, &tmpscalars, tmpvarssize);
5377  BMSfreeBlockMemoryArray(blkmem, &tmpvars, tmpvarssize);
5378 
5379  break;
5380 
5381  case SCIP_VARSTATUS_COLUMN:
5382  SCIPerrorMessage("cannot multi-aggregate a column variable\n");
5383  return SCIP_INVALIDDATA;
5384 
5385  case SCIP_VARSTATUS_FIXED:
5386  SCIPerrorMessage("cannot multi-aggregate a fixed variable\n");
5387  return SCIP_INVALIDDATA;
5388 
5390  SCIPerrorMessage("cannot multi-aggregate an aggregated variable\n");
5391  return SCIP_INVALIDDATA;
5392 
5394  SCIPerrorMessage("cannot multi-aggregate a multiple aggregated variable again\n");
5395  return SCIP_INVALIDDATA;
5396 
5398  /* aggregate negation variable x in x' = offset - x, instead of aggregating x' directly:
5399  * x' = a_1*y_1 + ... + a_n*y_n + c -> x = offset - x' = offset - a_1*y_1 - ... - a_n*y_n - c
5400  */
5401  assert(SCIPsetIsZero(set, var->obj));
5402  assert(var->negatedvar != NULL);
5404  assert(var->negatedvar->negatedvar == var);
5405 
5406  /* switch the signs of the aggregation scalars */
5407  for( v = 0; v < naggvars; ++v )
5408  scalars[v] *= -1.0;
5409 
5410  /* perform the multi aggregation on the negation variable */
5411  SCIP_CALL( SCIPvarMultiaggregate(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, lp,
5412  cliquetable, branchcand, eventfilter, eventqueue, naggvars, aggvars, scalars,
5413  var->data.negate.constant - constant, infeasible, aggregated) );
5414 
5415  /* switch the signs of the aggregation scalars again, to reset them to their original values */
5416  for( v = 0; v < naggvars; ++v )
5417  scalars[v] *= -1.0;
5418  break;
5419 
5420  default:
5421  SCIPerrorMessage("unknown variable status\n");
5422  return SCIP_INVALIDDATA;
5423  }
5424 
5425  return SCIP_OKAY;
5426 }
5427 
5428 /** transformed variables are resolved to their active, fixed, or multi-aggregated problem variable of a variable,
5429  * or for original variables the same variable is returned
5430  */
5431 static
5433  SCIP_VAR* var /**< problem variable */
5434  )
5435 {
5436  SCIP_VAR* retvar;
5437 
5438  assert(var != NULL);
5439 
5440  retvar = var;
5441 
5442  SCIPdebugMessage("get active variable of <%s>\n", var->name);
5443 
5444  while( TRUE ) /*lint !e716 */
5445  {
5446  assert(retvar != NULL);
5447 
5448  switch( SCIPvarGetStatus(retvar) )
5449  {
5451  case SCIP_VARSTATUS_LOOSE:
5452  case SCIP_VARSTATUS_COLUMN:
5453  case SCIP_VARSTATUS_FIXED:
5454  return retvar;
5455 
5457  /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
5458  if ( retvar->data.multaggr.nvars == 1 )
5459  retvar = retvar->data.multaggr.vars[0];
5460  else
5461  return retvar;
5462  break;
5463 
5465  retvar = retvar->data.aggregate.var;
5466  break;
5467 
5469  retvar = retvar->negatedvar;
5470  break;
5471 
5472  default:
5473  SCIPerrorMessage("unknown variable status\n");
5474  SCIPABORT();
5475  return NULL; /*lint !e527*/
5476  }
5477  }
5478 }
5479 
5480 /** returns whether variable is not allowed to be multi-aggregated */
5482  SCIP_VAR* var /**< problem variable */
5483  )
5484 {
5485  SCIP_VAR* retvar;
5486 
5487  assert(var != NULL);
5488 
5489  retvar = varGetActiveVar(var);
5490  assert(retvar != NULL);
5491 
5492  switch( SCIPvarGetStatus(retvar) )
5493  {
5495  case SCIP_VARSTATUS_LOOSE:
5496  case SCIP_VARSTATUS_COLUMN:
5497  case SCIP_VARSTATUS_FIXED:
5498  return retvar->donotmultaggr;
5499 
5501  return FALSE;
5502 
5505  default:
5506  SCIPerrorMessage("wrong variable status\n");
5507  SCIPABORT();
5508  return FALSE; /*lint !e527 */
5509  }
5510 }
5511 
5512 /** gets negated variable x' = offset - x of problem variable x; the negated variable is created if not yet existing;
5513  * the negation offset of binary variables is always 1, the offset of other variables is fixed to lb + ub when the
5514  * negated variable is created
5515  */
5517  SCIP_VAR* var, /**< problem variable to negate */
5518  BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
5519  SCIP_SET* set, /**< global SCIP settings */
5520  SCIP_STAT* stat, /**< problem statistics */
5521  SCIP_VAR** negvar /**< pointer to store the negated variable */
5522  )
5523 {
5524  assert(var != NULL);
5525  assert(var->scip == set->scip);
5526  assert(negvar != NULL);
5527 
5528  /* check, if we already created the negated variable */
5529  if( var->negatedvar == NULL )
5530  {
5531  char negvarname[SCIP_MAXSTRLEN];
5532 
5533  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED);
5534 
5535  SCIPdebugMessage("creating negated variable of <%s>\n", var->name);
5536 
5537  /* negation is only possible for bounded variables */
5538  if( SCIPsetIsInfinity(set, -var->glbdom.lb) || SCIPsetIsInfinity(set, var->glbdom.ub) )
5539  {
5540  SCIPerrorMessage("cannot negate unbounded variable\n");
5541  return SCIP_INVALIDDATA;
5542  }
5543 
5544  (void) SCIPsnprintf(negvarname, SCIP_MAXSTRLEN, "%s_neg", var->name);
5545 
5546  /* create negated variable */
5547  SCIP_CALL( varCreate(negvar, blkmem, set, stat, negvarname, var->glbdom.lb, var->glbdom.ub, 0.0,
5548  SCIPvarGetType(var), var->initial, var->removable, NULL, NULL, NULL, NULL, NULL) );
5549  (*negvar)->varstatus = SCIP_VARSTATUS_NEGATED; /*lint !e641*/
5550  if( SCIPvarIsBinary(var) )
5551  (*negvar)->data.negate.constant = 1.0;
5552  else
5553  (*negvar)->data.negate.constant = var->glbdom.lb + var->glbdom.ub;
5554 
5555  /* create event filter for transformed variable */
5556  if( SCIPvarIsTransformed(var) )
5557  {
5558  SCIP_CALL( SCIPeventfilterCreate(&(*negvar)->eventfilter, blkmem) );
5559  }
5560 
5561  /* set the bounds corresponding to the negation variable */
5562  (*negvar)->glbdom.lb = (*negvar)->data.negate.constant - var->glbdom.ub;
5563  (*negvar)->glbdom.ub = (*negvar)->data.negate.constant - var->glbdom.lb;
5564  (*negvar)->locdom.lb = (*negvar)->data.negate.constant - var->locdom.ub;
5565  (*negvar)->locdom.ub = (*negvar)->data.negate.constant - var->locdom.lb;
5566  /**@todo create holes in the negated variable corresponding to the holes of the negation variable */
5567 
5568  /* link the variables together */
5569  var->negatedvar = *negvar;
5570  (*negvar)->negatedvar = var;
5571 
5572  /* mark both variables to be non-deletable */
5574  SCIPvarMarkNotDeletable(*negvar);
5575 
5576  /* copy the branch factor and priority, and use the negative preferred branching direction */
5577  (*negvar)->branchfactor = var->branchfactor;
5578  (*negvar)->branchpriority = var->branchpriority;
5579  (*negvar)->branchdirection = SCIPbranchdirOpposite((SCIP_BRANCHDIR)var->branchdirection); /*lint !e641*/
5580 
5581  /* copy doNotMultiaggr status */
5582  (*negvar)->donotmultaggr = var->donotmultaggr;
5583 
5584  /* copy lazy bounds (they have to be flipped) */
5585  (*negvar)->lazylb = (*negvar)->data.negate.constant - var->lazyub;
5586  (*negvar)->lazyub = (*negvar)->data.negate.constant - var->lazylb;
5587 
5588  /* make negated variable a parent of the negation variable (negated variable is captured as a parent) */
5589  SCIP_CALL( varAddParent(var, blkmem, set, *negvar) );
5590  assert((*negvar)->nuses == 1);
5591  }
5592  assert(var->negatedvar != NULL);
5593 
5594  /* return the negated variable */
5595  *negvar = var->negatedvar;
5596 
5597  /* exactly one variable of the negation pair has to be marked as negated variable */
5599 
5600  return SCIP_OKAY;
5601 }
5602 
5603 /** informs variable that its position in problem's vars array changed */
5604 static
5606  SCIP_VAR* var, /**< problem variable */
5607  int probindex /**< new problem index of variable (-1 for removal) */
5608  )
5609 {
5610  assert(var != NULL);
5611  assert(probindex >= 0 || var->vlbs == NULL);
5612  assert(probindex >= 0 || var->vubs == NULL);
5613  assert(probindex >= 0 || var->implics == NULL);
5614 
5615  var->probindex = probindex;
5617  {
5618  assert(var->data.col != NULL);
5619  var->data.col->var_probindex = probindex;
5620  }
5621 }
5622 
5623 /** informs variable that its position in problem's vars array changed */
5625  SCIP_VAR* var, /**< problem variable */
5626  int probindex /**< new problem index of variable */
5627  )
5628 {
5629  assert(var != NULL);
5630  assert(probindex >= 0);
5631 
5632  varSetProbindex(var, probindex);
5633 }
5634 
5635 /** gives the variable a new name
5636  *
5637  * @note the old pointer is overwritten, which might result in a memory leakage
5638  */
5640  SCIP_VAR* var, /**< problem variable */
5641  const char* name /**< new name of variable */
5642  )
5643 {
5644  assert(var != NULL);
5645  assert(name != NULL);
5646 
5647  var->name = (char*)name;
5648 }
5649 
5650 /** informs variable that it will be removed from the problem; adjusts probindex and removes variable from the
5651  * implication graph;
5652  * If 'final' is TRUE, the thorough implication graph removal is not performed. Instead, only the
5653  * variable bounds and implication data structures of the variable are freed. Since in the final removal
5654  * of all variables from the transformed problem, this deletes the implication graph completely and is faster
5655  * than removing the variables one by one, each time updating all lists of the other variables.
5656  */
5658  SCIP_VAR* var, /**< problem variable */
5659  BMS_BLKMEM* blkmem, /**< block memory buffer */
5660  SCIP_SET* set, /**< global SCIP settings */
5661  SCIP_Bool final /**< is this the final removal of all problem variables? */
5662  )
5663 {
5664  assert(SCIPvarGetProbindex(var) >= 0);
5665  assert(var->scip == set->scip);
5666 
5667  /* if the variable is active in the transformed problem, remove it from the implication graph */
5668  if( SCIPvarIsTransformed(var)
5670  {
5671  if( final )
5672  {
5673  /* just destroy the data structures */
5674  SCIPvboundsFree(&var->vlbs, blkmem);
5675  SCIPvboundsFree(&var->vubs, blkmem);
5676  SCIPimplicsFree(&var->implics, blkmem);
5677  }
5678  else
5679  {
5680  /* unlink the variable from all other variables' lists and free the data structures */
5681  SCIP_CALL( varRemoveImplicsVbs(var, blkmem, set, FALSE, TRUE) );
5682  }
5683  }
5684 
5685  /* mark the variable to be no longer a member of the problem */
5686  varSetProbindex(var, -1);
5687 
5688  return SCIP_OKAY;
5689 }
5690 
5691 /** marks the variable to be deleted from the problem */
5693  SCIP_VAR* var /**< problem variable */
5694  )
5695 {
5696  assert(var != NULL);
5697  assert(var->probindex != -1);
5698 
5699  var->deleted = TRUE;
5700 }
5701 
5702 /** marks the variable to not to be multi-aggregated */
5704  SCIP_VAR* var /**< problem variable */
5705  )
5706 {
5707  SCIP_VAR* retvar;
5708 
5709  assert(var != NULL);
5710 
5711  retvar = varGetActiveVar(var);
5712  assert(retvar != NULL);
5713 
5714  switch( SCIPvarGetStatus(retvar) )
5715  {
5717  case SCIP_VARSTATUS_LOOSE:
5718  case SCIP_VARSTATUS_COLUMN:
5719  case SCIP_VARSTATUS_FIXED:
5720  retvar->donotmultaggr = TRUE;
5721  break;
5722 
5724  SCIPerrorMessage("cannot mark a multi-aggregated variable to not be multi-aggregated.\n");
5725  return SCIP_INVALIDDATA;
5726 
5729  default:
5730  SCIPerrorMessage("wrong variable status\n");
5731  return SCIP_INVALIDDATA;
5732  }
5733 
5734  return SCIP_OKAY;
5735 }
5736 
5737 /** changes type of variable; cannot be called, if var belongs to a problem */
5739  SCIP_VAR* var, /**< problem variable to change */
5740  SCIP_VARTYPE vartype /**< new type of variable */
5741  )
5742 {
5743  assert(var != NULL);
5744 
5745  SCIPdebugMessage("change type of <%s> from %d to %d\n", var->name, SCIPvarGetType(var), vartype);
5746 
5747  if( var->probindex >= 0 )
5748  {
5749  SCIPerrorMessage("cannot change type of variable already in the problem\n");
5750  return SCIP_INVALIDDATA;
5751  }
5752 
5753  var->vartype = vartype; /*lint !e641*/
5754  if( var->negatedvar != NULL )
5755  var->negatedvar->vartype = vartype; /*lint !e641*/
5756 
5757  return SCIP_OKAY;
5758 }
5759 
5760 /** appends OBJCHANGED event to the event queue */
5761 static
5763  SCIP_VAR* var, /**< problem variable to change */
5764  BMS_BLKMEM* blkmem, /**< block memory */
5765  SCIP_SET* set, /**< global SCIP settings */
5766  SCIP_PRIMAL* primal, /**< primal data */
5767  SCIP_LP* lp, /**< current LP data */
5768  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5769  SCIP_Real oldobj, /**< old objective value for variable */
5770  SCIP_Real newobj /**< new objective value for variable */
5771  )
5772 {
5773  SCIP_EVENT* event;
5774 
5775  assert(var != NULL);
5776  assert(var->scip == set->scip);
5777  assert(var->eventfilter != NULL);
5779  assert(SCIPvarIsTransformed(var));
5780  assert(!SCIPsetIsEQ(set, oldobj, newobj));
5781 
5782  SCIP_CALL( SCIPeventCreateObjChanged(&event, blkmem, var, oldobj, newobj) );
5783  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) );
5784 
5785  return SCIP_OKAY;
5786 }
5787 
5788 /** changes objective value of variable */
5790  SCIP_VAR* var, /**< variable to change */
5791  BMS_BLKMEM* blkmem, /**< block memory */
5792  SCIP_SET* set, /**< global SCIP settings */
5793  SCIP_PROB* prob, /**< problem data */
5794  SCIP_PRIMAL* primal, /**< primal data */
5795  SCIP_LP* lp, /**< current LP data */
5796  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5797  SCIP_Real newobj /**< new objective value for variable */
5798  )
5799 {
5800  SCIP_Real oldobj;
5801 
5802  assert(var != NULL);
5803  assert(set != NULL);
5804  assert(var->scip == set->scip);
5805 
5806  SCIPdebugMessage("changing objective value of <%s> from %g to %g\n", var->name, var->obj, newobj);
5807 
5808  if( !SCIPsetIsEQ(set, var->obj, newobj) )
5809  {
5810  switch( SCIPvarGetStatus(var) )
5811  {
5813  if( var->data.original.transvar != NULL )
5814  {
5815  SCIP_CALL( SCIPvarChgObj(var->data.original.transvar, blkmem, set, prob, primal, lp, eventqueue, newobj) );
5816  }
5817  else
5818  {
5819  assert(set->stage == SCIP_STAGE_PROBLEM);
5820  var->obj = newobj;
5821  }
5822  break;
5823 
5824  case SCIP_VARSTATUS_LOOSE:
5825  case SCIP_VARSTATUS_COLUMN:
5826  oldobj = var->obj;
5827  var->obj = newobj;
5828 
5829  /* update the number of variables with non-zero objective coefficient;
5830  * we only want to do the update, if the variable is added to the problem;
5831  * since the objective of inactive variables cannot be changed, this corresponds to probindex != -1
5832  */
5833  if( SCIPvarIsActive(var) )
5834  SCIPprobUpdateNObjVars(prob, set, oldobj, var->obj);
5835 
5836  SCIP_CALL( varEventObjChanged(var, blkmem, set, primal, lp, eventqueue, oldobj, var->obj) );
5837  break;
5838 
5839  case SCIP_VARSTATUS_FIXED:
5843  SCIPerrorMessage("cannot change objective value of a fixed, aggregated, multi-aggregated, or negated variable\n");
5844  return SCIP_INVALIDDATA;
5845 
5846  default:
5847  SCIPerrorMessage("unknown variable status\n");
5848  return SCIP_INVALIDDATA;
5849  }
5850  }
5851 
5852  return SCIP_OKAY;
5853 }
5854 
5855 /** adds value to objective value of variable */
5857  SCIP_VAR* var, /**< variable to change */
5858  BMS_BLKMEM* blkmem, /**< block memory */
5859  SCIP_SET* set, /**< global SCIP settings */
5860  SCIP_STAT* stat, /**< problem statistics */
5861  SCIP_PROB* transprob, /**< tranformed problem data */
5862  SCIP_PROB* origprob, /**< original problem data */
5863  SCIP_PRIMAL* primal, /**< primal data */
5864  SCIP_TREE* tree, /**< branch and bound tree */
5865  SCIP_LP* lp, /**< current LP data */
5866  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5867  SCIP_Real addobj /**< additional objective value for variable */
5868  )
5869 {
5870  assert(var != NULL);
5871  assert(set != NULL);
5872  assert(var->scip == set->scip);
5873  assert(set->stage < SCIP_STAGE_INITSOLVE);
5874 
5875  SCIPdebugMessage("adding %g to objective value %g of <%s>\n", addobj, var->obj, var->name);
5876 
5877  if( !SCIPsetIsZero(set, addobj) )
5878  {
5879  SCIP_Real oldobj;
5880  int i;
5881 
5882  switch( SCIPvarGetStatus(var) )
5883  {
5885  if( var->data.original.transvar != NULL )
5886  {
5887  SCIP_CALL( SCIPvarAddObj(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree, lp, eventqueue, addobj) );
5888  }
5889  else
5890  {
5891  assert(set->stage == SCIP_STAGE_PROBLEM);
5892  var->obj += addobj;
5893  }
5894  break;
5895 
5896  case SCIP_VARSTATUS_LOOSE:
5897  case SCIP_VARSTATUS_COLUMN:
5898  oldobj = var->obj;
5899  var->obj += addobj;
5900 
5901  /* update the number of variables with non-zero objective coefficient;
5902  * we only want to do the update, if the variable is added to the problem;
5903  * since the objective of inactive variables cannot be changed, this corresponds to probindex != -1
5904  */
5905  if( SCIPvarIsActive(var) )
5906  SCIPprobUpdateNObjVars(transprob, set, oldobj, var->obj);
5907 
5908  SCIP_CALL( varEventObjChanged(var, blkmem, set, primal, lp, eventqueue, oldobj, var->obj) );
5909  break;
5910 
5911  case SCIP_VARSTATUS_FIXED:
5912  assert(SCIPsetIsEQ(set, var->locdom.lb, var->locdom.ub));
5913  SCIPprobAddObjoffset(transprob, var->locdom.lb * addobj);
5914  SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventqueue, transprob, origprob, tree, lp) );
5915  break;
5916 
5918  /* x = a*y + c -> add a*addobj to obj. val. of y, and c*addobj to obj. offset of problem */
5919  SCIPprobAddObjoffset(transprob, var->data.aggregate.constant * addobj);
5920  SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventqueue, transprob, origprob, tree, lp) );
5921  SCIP_CALL( SCIPvarAddObj(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, primal, tree, lp, eventqueue,
5922  var->data.aggregate.scalar * addobj) );
5923  break;
5924 
5926  assert(!var->donotmultaggr);
5927  /* x = a_1*y_1 + ... + a_n*y_n + c -> add a_i*addobj to obj. val. of y_i, and c*addobj to obj. offset */
5928  SCIPprobAddObjoffset(transprob, var->data.multaggr.constant * addobj);
5929  SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventqueue, transprob, origprob, tree, lp) );
5930  for( i = 0; i < var->data.multaggr.nvars; ++i )
5931  {
5932  SCIP_CALL( SCIPvarAddObj(var->data.multaggr.vars[i], blkmem, set, stat, transprob, origprob, primal, tree, lp,
5933  eventqueue, var->data.multaggr.scalars[i] * addobj) );
5934  }
5935  break;
5936 
5938  /* x' = offset - x -> add -addobj to obj. val. of x and offset*addobj to obj. offset of problem */
5939  assert(var->negatedvar != NULL);
5941  assert(var->negatedvar->negatedvar == var);
5942  SCIPprobAddObjoffset(transprob, var->data.negate.constant * addobj);
5943  SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventqueue, transprob, origprob, tree, lp) );
5944  SCIP_CALL( SCIPvarAddObj(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, lp, eventqueue, -addobj) );
5945  break;
5946 
5947  default:
5948  SCIPerrorMessage("unknown variable status\n");
5949  return SCIP_INVALIDDATA;
5950  }
5951  }
5952 
5953  return SCIP_OKAY;
5954 }
5955 
5956 /** changes objective value of variable in current dive */
5958  SCIP_VAR* var, /**< problem variable to change */
5959  SCIP_SET* set, /**< global SCIP settings */
5960  SCIP_LP* lp, /**< current LP data */
5961  SCIP_Real newobj /**< new objective value for variable */
5962  )
5963 {
5964  assert(var != NULL);
5965  assert(set != NULL);
5966  assert(var->scip == set->scip);
5967  assert(lp != NULL);
5968 
5969  SCIPdebugMessage("changing objective of <%s> to %g in current dive\n", var->name, newobj);
5970 
5971  if( SCIPsetIsZero(set, newobj) )
5972  newobj = 0.0;
5973 
5974  /* change objective value of attached variables */
5975  switch( SCIPvarGetStatus(var) )
5976  {
5978  assert(var->data.original.transvar != NULL);
5979  SCIP_CALL( SCIPvarChgObjDive(var->data.original.transvar, set, lp, newobj) );
5980  break;
5981 
5982  case SCIP_VARSTATUS_COLUMN:
5983  assert(var->data.col != NULL);
5984  SCIP_CALL( SCIPcolChgObj(var->data.col, set, lp, newobj) );
5985  break;
5986 
5987  case SCIP_VARSTATUS_LOOSE:
5988  case SCIP_VARSTATUS_FIXED:
5989  /* nothing to do here: only the constant shift in objective function would change */
5990  break;
5991 
5992  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
5993  assert(var->data.aggregate.var != NULL);
5994  assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
5995  SCIP_CALL( SCIPvarChgObjDive(var->data.aggregate.var, set, lp, newobj / var->data.aggregate.scalar) );
5996  /* the constant can be ignored, because it would only affect the objective shift */
5997  break;
5998 
6000  SCIPerrorMessage("cannot change diving objective value of a multi-aggregated variable\n");
6001  return SCIP_INVALIDDATA;
6002 
6003  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
6004  assert(var->negatedvar != NULL);
6006  assert(var->negatedvar->negatedvar == var);
6007  SCIP_CALL( SCIPvarChgObjDive(var->negatedvar, set, lp, -newobj) );
6008  /* the offset can be ignored, because it would only affect the objective shift */
6009  break;
6010 
6011  default:
6012  SCIPerrorMessage("unknown variable status\n");
6013  return SCIP_INVALIDDATA;
6014  }
6015 
6016  return SCIP_OKAY;
6017 }
6018 
6019 /** adjust lower bound to integral value, if variable is integral */
6021  SCIP_VAR* var, /**< problem variable */
6022  SCIP_SET* set, /**< global SCIP settings */
6023  SCIP_Real* lb /**< pointer to lower bound to adjust */
6024  )
6025 {
6026  assert(var != NULL);
6027  assert(set != NULL);
6028  assert(var->scip == set->scip);
6029  assert(lb != NULL);
6030 
6031  SCIPdebugMessage("adjust lower bound %g of <%s>\n", *lb, var->name);
6032 
6033  *lb = adjustedLb(set, SCIPvarGetType(var), *lb);
6034 }
6035 
6036 /** adjust upper bound to integral value, if variable is integral */
6038  SCIP_VAR* var, /**< problem variable */
6039  SCIP_SET* set, /**< global SCIP settings */
6040  SCIP_Real* ub /**< pointer to upper bound to adjust */
6041  )
6042 {
6043  assert(var != NULL);
6044  assert(set != NULL);
6045  assert(var->scip == set->scip);
6046  assert(ub != NULL);
6047 
6048  SCIPdebugMessage("adjust upper bound %g of <%s>\n", *ub, var->name);
6049 
6050  *ub = adjustedUb(set, SCIPvarGetType(var), *ub);
6051 }
6052 
6053 /** adjust lower or upper bound to integral value, if variable is integral */
6055  SCIP_VAR* var, /**< problem variable */
6056  SCIP_SET* set, /**< global SCIP settings */
6057  SCIP_BOUNDTYPE boundtype, /**< type of bound to adjust */
6058  SCIP_Real* bd /**< pointer to bound to adjust */
6059  )
6060 {
6061  assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER);
6062 
6063  if( boundtype == SCIP_BOUNDTYPE_LOWER )
6064  SCIPvarAdjustLb(var, set, bd);
6065  else
6066  SCIPvarAdjustUb(var, set, bd);
6067 }
6068 
6069 /** changes lower bound of original variable in original problem */
6071  SCIP_VAR* var, /**< problem variable to change */
6072  SCIP_SET* set, /**< global SCIP settings */
6073  SCIP_Real newbound /**< new bound for variable */
6074  )
6075 {
6076  int i;
6077 
6078  assert(var != NULL);
6079  assert(!SCIPvarIsTransformed(var));
6081  assert(set != NULL);
6082  assert(var->scip == set->scip);
6083  assert(set->stage == SCIP_STAGE_PROBLEM);
6084 
6085  /* check that the bound is feasible */
6086  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsLE(set, newbound, SCIPvarGetUbOriginal(var)));
6087  /* adjust bound to integral value if variable is of integral type */
6088  newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
6089 
6090  if( SCIPsetIsZero(set, newbound) )
6091  newbound = 0.0;
6092 
6093  /* original domains are only stored for ORIGINAL variables, not for NEGATED */
6095  {
6096  SCIPdebugMessage("changing original lower bound of <%s> from %g to %g\n",
6097  var->name, var->data.original.origdom.lb, newbound);
6098 
6099  if( SCIPsetIsEQ(set, var->data.original.origdom.lb, newbound) )
6100  return SCIP_OKAY;
6101 
6102  /* change the bound */
6103  var->data.original.origdom.lb = newbound;
6104  }
6105  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED )
6106  {
6107  assert( var->negatedvar != NULL );
6108  SCIP_CALL( SCIPvarChgUbOriginal(var->negatedvar, set, var->data.negate.constant - newbound) );
6109  }
6110 
6111  /* process parent variables */
6112  for( i = 0; i < var->nparentvars; ++i )
6113  {
6114  SCIP_VAR* parentvar;
6115 
6116  parentvar = var->parentvars[i];
6117  assert(parentvar != NULL);
6118  assert(SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_NEGATED);
6119  assert(parentvar->negatedvar == var);
6120  assert(var->negatedvar == parentvar);
6121 
6122  SCIP_CALL( SCIPvarChgUbOriginal(parentvar, set, parentvar->data.negate.constant - newbound) );
6123  }
6124 
6125  return SCIP_OKAY;
6126 }
6127 
6128 /** changes upper bound of original variable in original problem */
6130  SCIP_VAR* var, /**< problem variable to change */
6131  SCIP_SET* set, /**< global SCIP settings */
6132  SCIP_Real newbound /**< new bound for variable */
6133  )
6134 {
6135  int i;
6136 
6137  assert(var != NULL);
6138  assert(!SCIPvarIsTransformed(var));
6140  assert(set != NULL);
6141  assert(var->scip == set->scip);
6142  assert(set->stage == SCIP_STAGE_PROBLEM);
6143 
6144  /* check that the bound is feasible */
6145  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsGE(set, newbound, SCIPvarGetLbOriginal(var)));
6146  /* adjust bound to integral value if variable is of integral type */
6147  newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
6148 
6149  if( SCIPsetIsZero(set, newbound) )
6150  newbound = 0.0;
6151 
6152  /* original domains are only stored for ORIGINAL variables, not for NEGATED */
6154  {
6155  SCIPdebugMessage("changing original upper bound of <%s> from %g to %g\n",
6156  var->name, var->data.original.origdom.ub, newbound);
6157 
6158  if( SCIPsetIsEQ(set, var->data.original.origdom.ub, newbound) )
6159  return SCIP_OKAY;
6160 
6161  /* change the bound */
6162  var->data.original.origdom.ub = newbound;
6163  }
6164  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED )
6165  {
6166  assert( var->negatedvar != NULL );
6167  SCIP_CALL( SCIPvarChgLbOriginal(var->negatedvar, set, var->data.negate.constant - newbound) );
6168  }
6169 
6170  /* process parent variables */
6171  for( i = 0; i < var->nparentvars; ++i )
6172  {
6173  SCIP_VAR* parentvar;
6174 
6175  parentvar = var->parentvars[i];
6176  assert(parentvar != NULL);
6177  assert(SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_NEGATED);
6178  assert(parentvar->negatedvar == var);
6179  assert(var->negatedvar == parentvar);
6180 
6181  SCIP_CALL( SCIPvarChgLbOriginal(parentvar, set, parentvar->data.negate.constant - newbound) );
6182  }
6183 
6184  return SCIP_OKAY;
6185 }
6186 
6187 /** appends GLBCHANGED event to the event queue */
6188 static
6190  SCIP_VAR* var, /**< problem variable to change */
6191  BMS_BLKMEM* blkmem, /**< block memory */
6192  SCIP_SET* set, /**< global SCIP settings */
6193  SCIP_LP* lp, /**< current LP data */
6194  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
6195  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6196  SCIP_Real oldbound, /**< old lower bound for variable */
6197  SCIP_Real newbound /**< new lower bound for variable */
6198  )
6199 {
6200  assert(var != NULL);
6201  assert(var->eventfilter != NULL);
6202  assert(SCIPvarIsTransformed(var));
6203  assert(!SCIPsetIsEQ(set, oldbound, newbound));
6204  assert(set != NULL);
6205  assert(var->scip == set->scip);
6206 
6207  /* check, if the variable is being tracked for bound changes
6208  * COLUMN and LOOSE variables are tracked always, because global/root pseudo objective value has to be updated
6209  */
6210  if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GLBCHANGED) != 0)
6213  {
6214  SCIP_EVENT* event;
6215 
6216  SCIPdebugMessage("issue GLBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
6217 
6218  SCIP_CALL( SCIPeventCreateGlbChanged(&event, blkmem, var, oldbound, newbound) );
6219  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
6220  }
6221 
6222  return SCIP_OKAY;
6223 }
6224 
6225 /** appends GUBCHANGED event to the event queue */
6226 static
6228  SCIP_VAR* var, /**< problem variable to change */
6229  BMS_BLKMEM* blkmem, /**< block memory */
6230  SCIP_SET* set, /**< global SCIP settings */
6231  SCIP_LP* lp, /**< current LP data */
6232  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
6233  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6234  SCIP_Real oldbound, /**< old lower bound for variable */
6235  SCIP_Real newbound /**< new lower bound for variable */
6236  )
6237 {
6238  assert(var != NULL);
6239  assert(var->eventfilter != NULL);
6240  assert(SCIPvarIsTransformed(var));
6241  assert(!SCIPsetIsEQ(set, oldbound, newbound));
6242  assert(set != NULL);
6243  assert(var->scip == set->scip);
6244 
6245  /* check, if the variable is being tracked for bound changes
6246  * COLUMN and LOOSE variables are tracked always, because global/root pseudo objective value has to be updated
6247  */
6248  if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GUBCHANGED) != 0)
6251  {
6252  SCIP_EVENT* event;
6253 
6254  SCIPdebugMessage("issue GUBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
6255 
6256  SCIP_CALL( SCIPeventCreateGubChanged(&event, blkmem, var, oldbound, newbound) );
6257  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
6258  }
6259 
6260  return SCIP_OKAY;
6261 }
6262 
6263 /** appends GHOLEADDED event to the event queue */
6264 static
6266  SCIP_VAR* var, /**< problem variable to change */
6267  BMS_BLKMEM* blkmem, /**< block memory */
6268  SCIP_SET* set, /**< global SCIP settings */
6269  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6270  SCIP_Real left, /**< left bound of open interval in new hole */
6271  SCIP_Real right /**< right bound of open interval in new hole */
6272  )
6273 {
6274  assert(var != NULL);
6275  assert(var->eventfilter != NULL);
6276  assert(SCIPvarIsTransformed(var));
6277  assert(set != NULL);
6278  assert(var->scip == set->scip);
6279  assert(SCIPsetIsLT(set, left, right));
6280 
6281  /* check, if the variable is being tracked for bound changes */
6282  if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GHOLEADDED) != 0) )
6283  {
6284  SCIP_EVENT* event;
6285 
6286  SCIPdebugMessage("issue GHOLEADDED event for variable <%s>: (%.15g,%.15g)\n", var->name, left, right);
6287 
6288  SCIP_CALL( SCIPeventCreateGholeAdded(&event, blkmem, var, left, right) );
6289  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
6290  }
6291 
6292  return SCIP_OKAY;
6293 }
6294 
6295 /** increases root bound change statistics after a global bound change */
6296 static
6298  SCIP_VAR* var, /**< problem variable to change */
6299  SCIP_SET* set, /**< global SCIP settings */
6300  SCIP_STAT* stat /**< problem statistics */
6301  )
6302 {
6303  assert(var != NULL);
6304  assert(set != NULL);
6305  assert(var->scip == set->scip);
6306  assert(stat != NULL);
6307 
6308  if( SCIPvarIsActive(var) && SCIPvarIsTransformed(var) && set->stage == SCIP_STAGE_SOLVING )
6309  {
6310  stat->nrootboundchgs++;
6311  stat->nrootboundchgsrun++;
6312  if( SCIPvarIsIntegral(var) && SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
6313  {
6314  stat->nrootintfixings++;
6315  stat->nrootintfixingsrun++;
6316  }
6317  }
6318 }
6319 
6320 /* forward declaration, because both methods call each other recursively */
6321 
6322 /* performs the current change in upper bound, changes all parents accordingly */
6323 static
6325  SCIP_VAR* var, /**< problem variable to change */
6326  BMS_BLKMEM* blkmem, /**< block memory */
6327  SCIP_SET* set, /**< global SCIP settings */
6328  SCIP_STAT* stat, /**< problem statistics */
6329  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
6330  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
6331  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
6332  SCIP_Real newbound /**< new bound for variable */
6333  );
6334 
6335 /** performs the current change in lower bound, changes all parents accordingly */
6336 static
6338  SCIP_VAR* var, /**< problem variable to change */
6339  BMS_BLKMEM* blkmem, /**< block memory */
6340  SCIP_SET* set, /**< global SCIP settings */
6341  SCIP_STAT* stat, /**< problem statistics */
6342  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
6343  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
6344  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
6345  SCIP_Real newbound /**< new bound for variable */
6346  )
6347 {
6348  SCIP_VAR* parentvar;
6349  SCIP_Real oldbound;
6350  int i;
6351 
6352  assert(var != NULL);
6353  /* local domains can violate global bounds but not more than feasibility epsilon */
6354  assert(SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb));
6355  assert(SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub));
6356  assert(blkmem != NULL);
6357  assert(set != NULL);
6358  assert(var->scip == set->scip);
6359  assert(stat != NULL);
6360 
6361  /* adjust bound to integral value if variable is of integral type */
6362  newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
6363 
6364  /* check that the bound is feasible */
6365  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM && newbound > var->glbdom.ub )
6366  {
6367  /* due to numerics we only want to be feasible in feasibility tolerance */
6368  assert(SCIPsetIsFeasLE(set, newbound, var->glbdom.ub));
6369  newbound = var->glbdom.ub;
6370  }
6371  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
6372 
6373  assert(var->vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, newbound, 0.0) || SCIPsetIsEQ(set, newbound, 1.0)); /*lint !e641*/
6374 
6375  SCIPdebugMessage("process changing global lower bound of <%s> from %f to %f\n", var->name, var->glbdom.lb, newbound);
6376 
6377  if( SCIPsetIsEQ(set, newbound, var->glbdom.lb) )
6378  return SCIP_OKAY;
6379 
6380  /* check bound on debugging solution */
6381  SCIP_CALL( SCIPdebugCheckLbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
6382 
6383  /* change the bound */
6384  oldbound = var->glbdom.lb;
6385  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasLE(set, newbound, var->glbdom.ub));
6386  var->glbdom.lb = newbound;
6387  assert( SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb) );
6388  assert( SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub) );
6389 
6390  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
6391  {
6392  /* merges overlapping holes into single holes, moves bounds respectively */
6393  domMerge(&var->glbdom, blkmem, set, &newbound, NULL);
6394  }
6395 
6396  /* update the root bound changes counters */
6397  varIncRootboundchgs(var, set, stat);
6398 
6399  /* update the lbchginfos array by replacing worse local bounds with the new global bound and changing the
6400  * redundant bound changes to be branching decisions
6401  */
6402  for( i = 0; i < var->nlbchginfos; ++i )
6403  {
6404  assert(var->lbchginfos[i].var == var);
6405 
6406  if( var->lbchginfos[i].oldbound < var->glbdom.lb )
6407  {
6408  SCIPdebugMessage(" -> adjust lower bound change <%s>: %g -> %g due to new global lower bound %g\n",
6409  SCIPvarGetName(var), var->lbchginfos[i].oldbound, var->lbchginfos[i].newbound, var->glbdom.lb);
6410  var->lbchginfos[i].oldbound = var->glbdom.lb;
6411  if( SCIPsetIsLE(set, var->lbchginfos[i].newbound, var->glbdom.lb) )
6412  {
6413  /* this bound change is redundant due to the new global bound */
6414  var->lbchginfos[i].newbound = var->glbdom.lb;
6415  var->lbchginfos[i].boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
6416  var->lbchginfos[i].redundant = TRUE;
6417  }
6418  else
6419  break; /* from now on, the remaining local bound changes are not redundant */
6420  }
6421  else
6422  break; /* from now on, the remaining local bound changes are not redundant */
6423  }
6424 
6425  /* remove redundant implications and variable bounds */
6427  {
6428  SCIP_CALL( varRemoveImplicsVbs(var, blkmem, set, TRUE, TRUE) );
6429  }
6430 
6431  /* issue bound change event */
6432  assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
6433  if( var->eventfilter != NULL )
6434  {
6435  SCIP_CALL( varEventGlbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
6436  }
6437 
6438  /* process parent variables */
6439  for( i = 0; i < var->nparentvars; ++i )
6440  {
6441  parentvar = var->parentvars[i];
6442  assert(parentvar != NULL);
6443 
6444  switch( SCIPvarGetStatus(parentvar) )
6445  {
6447  SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
6448  break;
6449 
6450  case SCIP_VARSTATUS_COLUMN:
6451  case SCIP_VARSTATUS_LOOSE:
6452  case SCIP_VARSTATUS_FIXED:
6454  SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
6455  return SCIP_INVALIDDATA;
6456 
6457  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
6458  assert(parentvar->data.aggregate.var == var);
6459  if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
6460  {
6461  SCIP_Real parentnewbound;
6462 
6463  /* a > 0 -> change lower bound of y */
6464  assert((SCIPsetIsInfinity(set, -parentvar->glbdom.lb) && SCIPsetIsInfinity(set, -oldbound))
6465  || SCIPsetIsFeasEQ(set, parentvar->glbdom.lb, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
6466  || (SCIPsetIsZero(set, parentvar->glbdom.lb / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
6467 
6468  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6469  parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6470  else
6471  parentnewbound = newbound;
6472  SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, parentnewbound) );
6473  }
6474  else
6475  {
6476  SCIP_Real parentnewbound;
6477 
6478  /* a < 0 -> change upper bound of y */
6479  assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
6480  assert((SCIPsetIsInfinity(set, parentvar->glbdom.ub) && SCIPsetIsInfinity(set, -oldbound))
6481  || SCIPsetIsFeasEQ(set, parentvar->glbdom.ub, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
6482  || (SCIPsetIsZero(set, parentvar->glbdom.ub / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
6483 
6484  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6485  parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6486  else
6487  parentnewbound = -newbound;
6488  SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, parentnewbound) );
6489  }
6490  break;
6491 
6492  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
6493  assert(parentvar->negatedvar != NULL);
6494  assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
6495  assert(parentvar->negatedvar->negatedvar == parentvar);
6496  SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue,
6497  parentvar->data.negate.constant - newbound) );
6498  break;
6499 
6500  default:
6501  SCIPerrorMessage("unknown variable status\n");
6502  return SCIP_INVALIDDATA;
6503  }
6504  }
6505 
6506  return SCIP_OKAY;
6507 }
6508 
6509 /** performs the current change in upper bound, changes all parents accordingly */
6510 static
6512  SCIP_VAR* var, /**< problem variable to change */
6513  BMS_BLKMEM* blkmem, /**< block memory */
6514  SCIP_SET* set, /**< global SCIP settings */
6515  SCIP_STAT* stat, /**< problem statistics */
6516  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
6517  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
6518  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
6519  SCIP_Real newbound /**< new bound for variable */
6520  )
6521 {
6522  SCIP_VAR* parentvar;
6523  SCIP_Real oldbound;
6524  int i;
6525 
6526  assert(var != NULL);
6527  /* local domains can violate global bounds but not more than feasibility epsilon */
6528  assert(SCIPsetIsFeasLE(set, var->glbdom.lb , var->locdom.lb));
6529  assert(SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub));
6530  assert(blkmem != NULL);
6531  assert(set != NULL);
6532  assert(var->scip == set->scip);
6533  assert(stat != NULL);
6534 
6535  /* adjust bound to integral value if variable is of integral type */
6536  newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
6537 
6538  /* check that the bound is feasible */
6539  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM && newbound < var->glbdom.lb )
6540  {
6541  /* due to numerics we only want to be feasible in feasibility tolerance */
6542  assert(SCIPsetIsFeasGE(set, newbound, var->glbdom.lb));
6543  newbound = var->glbdom.lb;
6544  }
6545  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
6546 
6547  assert(var->vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, newbound, 0.0) || SCIPsetIsEQ(set, newbound, 1.0)); /*lint !e641*/
6548 
6549  SCIPdebugMessage("process changing global upper bound of <%s> from %f to %f\n", var->name, var->glbdom.ub, newbound);
6550 
6551  if( SCIPsetIsEQ(set, newbound, var->glbdom.ub) )
6552  return SCIP_OKAY;
6553 
6554  /* check bound on debugging solution */
6555  SCIP_CALL( SCIPdebugCheckUbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
6556 
6557  /* change the bound */
6558  oldbound = var->glbdom.ub;
6559  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasGE(set, newbound, var->glbdom.lb));
6560  var->glbdom.ub = newbound;
6561  assert( SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb) );
6562  assert( SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub) );
6563 
6564  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
6565  {
6566  /* merges overlapping holes into single holes, moves bounds respectively */
6567  domMerge(&var->glbdom, blkmem, set, NULL, &newbound);
6568  }
6569 
6570  /* update the root bound changes counters */
6571  varIncRootboundchgs(var, set, stat);
6572 
6573  /* update the ubchginfos array by replacing worse local bounds with the new global bound and changing the
6574  * redundant bound changes to be branching decisions
6575  */
6576  for( i = 0; i < var->nubchginfos; ++i )
6577  {
6578  assert(var->ubchginfos[i].var == var);
6579  if( var->ubchginfos[i].oldbound > var->glbdom.ub )
6580  {
6581  SCIPdebugMessage(" -> adjust upper bound change <%s>: %g -> %g due to new global upper bound %g\n",
6582  SCIPvarGetName(var), var->ubchginfos[i].oldbound, var->ubchginfos[i].newbound, var->glbdom.ub);
6583  var->ubchginfos[i].oldbound = var->glbdom.ub;
6584  if( SCIPsetIsGE(set, var->ubchginfos[i].newbound, var->glbdom.ub) )
6585  {
6586  /* this bound change is redundant due to the new global bound */
6587  var->ubchginfos[i].newbound = var->glbdom.ub;
6588  var->ubchginfos[i].boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
6589  var->ubchginfos[i].redundant = TRUE;
6590  }
6591  else
6592  break; /* from now on, the remaining local bound changes are not redundant */
6593  }
6594  else
6595  break; /* from now on, the remaining local bound changes are not redundant */
6596  }
6597 
6598  /* remove redundant implications and variable bounds */
6600  {
6601  SCIP_CALL( varRemoveImplicsVbs(var, blkmem, set, TRUE, TRUE) );
6602  }
6603 
6604  /* issue bound change event */
6605  assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
6606  if( var->eventfilter != NULL )
6607  {
6608  SCIP_CALL( varEventGubChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
6609  }
6610 
6611  /* process parent variables */
6612  for( i = 0; i < var->nparentvars; ++i )
6613  {
6614  parentvar = var->parentvars[i];
6615  assert(parentvar != NULL);
6616 
6617  switch( SCIPvarGetStatus(parentvar) )
6618  {
6620  SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
6621  break;
6622 
6623  case SCIP_VARSTATUS_COLUMN:
6624  case SCIP_VARSTATUS_LOOSE:
6625  case SCIP_VARSTATUS_FIXED:
6627  SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
6628  return SCIP_INVALIDDATA;
6629 
6630  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
6631  assert(parentvar->data.aggregate.var == var);
6632  if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
6633  {
6634  SCIP_Real parentnewbound;
6635 
6636  /* a > 0 -> change upper bound of y */
6637  assert((SCIPsetIsInfinity(set, parentvar->glbdom.ub) && SCIPsetIsInfinity(set, oldbound))
6638  || SCIPsetIsFeasEQ(set, parentvar->glbdom.ub,
6639  oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
6640  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6641  parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6642  else
6643  parentnewbound = newbound;
6644  SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, parentnewbound) );
6645  }
6646  else
6647  {
6648  SCIP_Real parentnewbound;
6649 
6650  /* a < 0 -> change lower bound of y */
6651  assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
6652  assert((SCIPsetIsInfinity(set, -parentvar->glbdom.lb) && SCIPsetIsInfinity(set, oldbound))
6653  || SCIPsetIsFeasEQ(set, parentvar->glbdom.lb,
6654  oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
6655  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6656  parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6657  else
6658  parentnewbound = -newbound;
6659  SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, parentnewbound) );
6660  }
6661  break;
6662 
6663  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
6664  assert(parentvar->negatedvar != NULL);
6665  assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
6666  assert(parentvar->negatedvar->negatedvar == parentvar);
6667  SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue,
6668  parentvar->data.negate.constant - newbound) );
6669  break;
6670 
6671  default:
6672  SCIPerrorMessage("unknown variable status\n");
6673  return SCIP_INVALIDDATA;
6674  }
6675  }
6676 
6677  return SCIP_OKAY;
6678 }
6679 
6680 /** changes global lower bound of variable; if possible, adjusts bound to integral value;
6681  * updates local lower bound if the global bound is tighter
6682  */
6684  SCIP_VAR* var, /**< problem variable to change */
6685  BMS_BLKMEM* blkmem, /**< block memory */
6686  SCIP_SET* set, /**< global SCIP settings */
6687  SCIP_STAT* stat, /**< problem statistics */
6688  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
6689  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
6690  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
6691  SCIP_Real newbound /**< new bound for variable */
6692  )
6693 {
6694  assert(var != NULL);
6695  assert(blkmem != NULL);
6696  assert(set != NULL);
6697  assert(var->scip == set->scip);
6698 
6699  /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
6700  * of the domain within feastol
6701  */
6702  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->glbdom.ub));
6703 
6704  /* adjust bound to integral value if variable is of integral type */
6705  newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
6706 
6707  /* check that the adjusted bound is feasible
6708  * @todo this does not have to be the case if the original problem was infeasible due to bounds and we are called
6709  * here because we reset bounds to their original value!
6710  */
6711  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->glbdom.ub));
6712 
6713  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
6714  {
6715  /* we do not want to exceed the upperbound, which could have happened due to numerics */
6716  newbound = MIN(newbound, var->glbdom.ub);
6717  }
6718  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
6719 
6720  /* the new global bound has to be tighter except we are in the original problem; this must be w.r.t. feastol because
6721  * SCIPvarFix() allows fixings that are outside of the domain within feastol
6722  */
6723  assert(lp == NULL || SCIPsetIsFeasLE(set, var->glbdom.lb, newbound));
6724 
6725  SCIPdebugMessage("changing global lower bound of <%s> from %g to %g\n", var->name, var->glbdom.lb, newbound);
6726 
6727  if( SCIPsetIsEQ(set, var->glbdom.lb, newbound) )
6728  return SCIP_OKAY;
6729 
6730  /* change bounds of attached variables */
6731  switch( SCIPvarGetStatus(var) )
6732  {
6734  if( var->data.original.transvar != NULL )
6735  {
6736  SCIP_CALL( SCIPvarChgLbGlobal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue,
6737  newbound) );
6738  }
6739  else
6740  {
6741  assert(set->stage == SCIP_STAGE_PROBLEM);
6742  if( newbound > SCIPvarGetLbLocal(var) )
6743  {
6744  SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
6745  }
6746  SCIP_CALL( varProcessChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
6747  }
6748  break;
6749 
6750  case SCIP_VARSTATUS_COLUMN:
6751  case SCIP_VARSTATUS_LOOSE:
6752  if( newbound > SCIPvarGetLbLocal(var) )
6753  {
6754  SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
6755  }
6756  SCIP_CALL( varProcessChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
6757  break;
6758 
6759  case SCIP_VARSTATUS_FIXED:
6760  SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
6761  return SCIP_INVALIDDATA;
6762 
6763  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
6764  assert(var->data.aggregate.var != NULL);
6765  if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
6766  {
6767  SCIP_Real childnewbound;
6768 
6769  /* a > 0 -> change lower bound of y */
6770  assert((SCIPsetIsInfinity(set, -var->glbdom.lb) && SCIPsetIsInfinity(set, -var->data.aggregate.var->glbdom.lb))
6771  || SCIPsetIsFeasEQ(set, var->glbdom.lb,
6773  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6774  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
6775  else
6776  childnewbound = newbound;
6777  SCIP_CALL( SCIPvarChgLbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
6778  childnewbound) );
6779  }
6780  else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
6781  {
6782  SCIP_Real childnewbound;
6783 
6784  /* a < 0 -> change upper bound of y */
6785  assert((SCIPsetIsInfinity(set, -var->glbdom.lb) && SCIPsetIsInfinity(set, var->data.aggregate.var->glbdom.ub))
6786  || SCIPsetIsFeasEQ(set, var->glbdom.lb,
6788  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6789  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
6790  else
6791  childnewbound = -newbound;
6792  SCIP_CALL( SCIPvarChgUbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
6793  childnewbound) );
6794  }
6795  else
6796  {
6797  SCIPerrorMessage("scalar is zero in aggregation\n");
6798  return SCIP_INVALIDDATA;
6799  }
6800  break;
6801 
6803  SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
6804  return SCIP_INVALIDDATA;
6805 
6806  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
6807  assert(var->negatedvar != NULL);
6809  assert(var->negatedvar->negatedvar == var);
6810  SCIP_CALL( SCIPvarChgUbGlobal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue,
6811  var->data.negate.constant - newbound) );
6812  break;
6813 
6814  default:
6815  SCIPerrorMessage("unknown variable status\n");
6816  return SCIP_INVALIDDATA;
6817  }
6818 
6819  return SCIP_OKAY;
6820 }
6821 
6822 /** changes global upper bound of variable; if possible, adjusts bound to integral value;
6823  * updates local upper bound if the global bound is tighter
6824  */
6826  SCIP_VAR* var, /**< problem variable to change */
6827  BMS_BLKMEM* blkmem, /**< block memory */
6828  SCIP_SET* set, /**< global SCIP settings */
6829  SCIP_STAT* stat, /**< problem statistics */
6830  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
6831  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
6832  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
6833  SCIP_Real newbound /**< new bound for variable */
6834  )
6835 {
6836  assert(var != NULL);
6837  assert(blkmem != NULL);
6838  assert(set != NULL);
6839  assert(var->scip == set->scip);
6840 
6841  /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
6842  * of the domain within feastol
6843  */
6844  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->glbdom.lb));
6845 
6846  /* adjust bound to integral value if variable is of integral type */
6847  newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
6848 
6849  /* check that the adjusted bound is feasible
6850  * @todo this does not have to be the case if the original problem was infeasible due to bounds and we are called
6851  * here because we reset bounds to their original value!
6852  */
6853  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->glbdom.lb));
6854 
6855  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
6856  {
6857  /* we do not want to undercut the lowerbound, which could have happened due to numerics */
6858  newbound = MAX(newbound, var->glbdom.lb);
6859  }
6860  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
6861 
6862  /* the new global bound has to be tighter except we are in the original problem; this must be w.r.t. feastol because
6863  * SCIPvarFix() allows fixings that are outside of the domain within feastol
6864  */
6865  assert(lp == NULL || SCIPsetIsFeasGE(set, var->glbdom.ub, newbound));
6866 
6867  SCIPdebugMessage("changing global upper bound of <%s> from %g to %g\n", var->name, var->glbdom.ub, newbound);
6868 
6869  if( SCIPsetIsEQ(set, var->glbdom.ub, newbound) )
6870  return SCIP_OKAY;
6871 
6872  /* change bounds of attached variables */
6873  switch( SCIPvarGetStatus(var) )
6874  {
6876  if( var->data.original.transvar != NULL )
6877  {
6878  SCIP_CALL( SCIPvarChgUbGlobal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue,
6879  newbound) );
6880  }
6881  else
6882  {
6883  assert(set->stage == SCIP_STAGE_PROBLEM);
6884  if( newbound < SCIPvarGetUbLocal(var) )
6885  {
6886  SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
6887  }
6888  SCIP_CALL( varProcessChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
6889  }
6890  break;
6891 
6892  case SCIP_VARSTATUS_COLUMN:
6893  case SCIP_VARSTATUS_LOOSE:
6894  if( newbound < SCIPvarGetUbLocal(var) )
6895  {
6896  SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
6897  }
6898  SCIP_CALL( varProcessChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
6899  break;
6900 
6901  case SCIP_VARSTATUS_FIXED:
6902  SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
6903  return SCIP_INVALIDDATA;
6904 
6905  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
6906  assert(var->data.aggregate.var != NULL);
6907  if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
6908  {
6909  SCIP_Real childnewbound;
6910 
6911  /* a > 0 -> change lower bound of y */
6912  assert((SCIPsetIsInfinity(set, var->glbdom.ub) && SCIPsetIsInfinity(set, var->data.aggregate.var->glbdom.ub))
6913  || SCIPsetIsFeasEQ(set, var->glbdom.ub,
6915  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6916  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
6917  else
6918  childnewbound = newbound;
6919  SCIP_CALL( SCIPvarChgUbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
6920  childnewbound) );
6921  }
6922  else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
6923  {
6924  SCIP_Real childnewbound;
6925 
6926  /* a < 0 -> change upper bound of y */
6927  assert((SCIPsetIsInfinity(set, var->glbdom.ub) && SCIPsetIsInfinity(set, -var->data.aggregate.var->glbdom.lb))
6928  || SCIPsetIsFeasEQ(set, var->glbdom.ub,
6930  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6931  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
6932  else
6933  childnewbound = -newbound;
6934  SCIP_CALL( SCIPvarChgLbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
6935  childnewbound) );
6936  }
6937  else
6938  {
6939  SCIPerrorMessage("scalar is zero in aggregation\n");
6940  return SCIP_INVALIDDATA;
6941  }
6942  break;
6943 
6945  SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
6946  return SCIP_INVALIDDATA;
6947 
6948  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
6949  assert(var->negatedvar != NULL);
6951  assert(var->negatedvar->negatedvar == var);
6952  SCIP_CALL( SCIPvarChgLbGlobal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue,
6953  var->data.negate.constant - newbound) );
6954  break;
6955 
6956  default:
6957  SCIPerrorMessage("unknown variable status\n");
6958  return SCIP_INVALIDDATA;
6959  }
6960 
6961  return SCIP_OKAY;
6962 }
6963 
6964 /** changes lazy lower bound of the variable, this is only possible if the variable is not in the LP yet */
6966  SCIP_VAR* var, /**< problem variable */
6967  SCIP_SET* set, /**< global SCIP settings */
6968  SCIP_Real lazylb /**< the lazy lower bound to be set */
6969  )
6970 {
6971  assert(var != NULL);
6972  assert(var->probindex != -1);
6973  assert(SCIPsetIsFeasGE(set, var->glbdom.ub, lazylb));
6974  assert(SCIPsetIsFeasGE(set, var->lazyub, lazylb));
6975  assert(set != NULL);
6976  assert(var->scip == set->scip);
6977 
6978  /* variable should not be in the LP */
6980  return SCIP_INVALIDCALL;
6981 
6982  var->lazylb = lazylb;
6983 
6984  return SCIP_OKAY;
6985 }
6986 
6987 /** changes lazy upper bound of the variable, this is only possible if the variable is not in the LP yet */
6989  SCIP_VAR* var, /**< problem variable */
6990  SCIP_SET* set, /**< global SCIP settings */
6991  SCIP_Real lazyub /**< the lazy lower bound to be set */
6992  )
6993 {
6994  assert(var != NULL);
6995  assert(var->probindex != -1);
6996  assert(SCIPsetIsFeasGE(set, lazyub, var->glbdom.lb));
6997  assert(SCIPsetIsFeasGE(set, lazyub, var->lazylb));
6998  assert(set != NULL);
6999  assert(var->scip == set->scip);
7000 
7001  /* variable should not be in the LP */
7003  return SCIP_INVALIDCALL;
7004 
7005  var->lazyub = lazyub;
7006 
7007  return SCIP_OKAY;
7008 }
7009 
7010 
7011 /** changes global bound of variable; if possible, adjusts bound to integral value;
7012  * updates local bound if the global bound is tighter
7013  */
7015  SCIP_VAR* var, /**< problem variable to change */
7016  BMS_BLKMEM* blkmem, /**< block memory */
7017  SCIP_SET* set, /**< global SCIP settings */
7018  SCIP_STAT* stat, /**< problem statistics */
7019  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7020  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7021  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7022  SCIP_Real newbound, /**< new bound for variable */
7023  SCIP_BOUNDTYPE boundtype /**< type of bound: lower or upper bound */
7024  )
7025 {
7026  /* apply bound change to the LP data */
7027  switch( boundtype )
7028  {
7029  case SCIP_BOUNDTYPE_LOWER:
7030  return SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound);
7031  case SCIP_BOUNDTYPE_UPPER:
7032  return SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound);
7033  default:
7034  SCIPerrorMessage("unknown bound type\n");
7035  return SCIP_INVALIDDATA;
7036  }
7037 }
7038 
7039 /** appends LBTIGHTENED or LBRELAXED event to the event queue */
7040 static
7042  SCIP_VAR* var, /**< problem variable to change */
7043  BMS_BLKMEM* blkmem, /**< block memory */
7044  SCIP_SET* set, /**< global SCIP settings */
7045  SCIP_LP* lp, /**< current LP data */
7046  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
7047  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
7048  SCIP_Real oldbound, /**< old lower bound for variable */
7049  SCIP_Real newbound /**< new lower bound for variable */
7050  )
7051 {
7052  assert(var != NULL);
7053  assert(var->eventfilter != NULL);
7054  assert(SCIPvarIsTransformed(var));
7055  assert(!SCIPsetIsEQ(set, oldbound, newbound));
7056  assert(set != NULL);
7057  assert(var->scip == set->scip);
7058 
7059  /* check, if the variable is being tracked for bound changes
7060  * COLUMN and LOOSE variables are tracked always, because row activities and LP changes have to be updated
7061  */
7062  if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_LBCHANGED) != 0)
7065  {
7066  SCIP_EVENT* event;
7067 
7068  SCIPdebugMessage("issue LBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
7069 
7070  SCIP_CALL( SCIPeventCreateLbChanged(&event, blkmem, var, oldbound, newbound) );
7071  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
7072  }
7073 
7074  return SCIP_OKAY;
7075 }
7076 
7077 /** appends UBTIGHTENED or UBRELAXED event to the event queue */
7078 static
7080  SCIP_VAR* var, /**< problem variable to change */
7081  BMS_BLKMEM* blkmem, /**< block memory */
7082  SCIP_SET* set, /**< global SCIP settings */
7083  SCIP_LP* lp, /**< current LP data */
7084  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
7085  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
7086  SCIP_Real oldbound, /**< old upper bound for variable */
7087  SCIP_Real newbound /**< new upper bound for variable */
7088  )
7089 {
7090  assert(var != NULL);
7091  assert(var->eventfilter != NULL);
7092  assert(SCIPvarIsTransformed(var));
7093  assert(!SCIPsetIsEQ(set, oldbound, newbound));
7094  assert(set != NULL);
7095  assert(var->scip == set->scip);
7096 
7097  /* check, if the variable is being tracked for bound changes
7098  * COLUMN and LOOSE variables are tracked always, because row activities and LP changes have to be updated
7099  */
7100  if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_UBCHANGED) != 0)
7103  {
7104  SCIP_EVENT* event;
7105 
7106  SCIPdebugMessage("issue UBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
7107 
7108  SCIP_CALL( SCIPeventCreateUbChanged(&event, blkmem, var, oldbound, newbound) );
7109  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
7110  }
7111 
7112  return SCIP_OKAY;
7113 }
7114 
7115 /* forward declaration, because both methods call each other recursively */
7116 
7117 /* performs the current change in upper bound, changes all parents accordingly */
7118 static
7120  SCIP_VAR* var, /**< problem variable to change */
7121  BMS_BLKMEM* blkmem, /**< block memory */
7122  SCIP_SET* set, /**< global SCIP settings */
7123  SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7124  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7125  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7126  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7127  SCIP_Real newbound /**< new bound for variable */
7128  );
7129 
7130 /** performs the current change in lower bound, changes all parents accordingly */
7131 static
7133  SCIP_VAR* var, /**< problem variable to change */
7134  BMS_BLKMEM* blkmem, /**< block memory */
7135  SCIP_SET* set, /**< global SCIP settings */
7136  SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7137  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7138  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7139  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7140  SCIP_Real newbound /**< new bound for variable */
7141  )
7142 {
7143  SCIP_VAR* parentvar;
7144  SCIP_Real oldbound;
7145  int i;
7146 
7147  assert(var != NULL);
7148  assert(set != NULL);
7149  assert(var->scip == set->scip);
7150  assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && (SCIPsetIsZero(set, newbound) || SCIPsetIsEQ(set, newbound, 1.0)))
7151  || (SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS && SCIPsetIsIntegral(set, newbound))
7153 
7154  /* check that the bound is feasible */
7155  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsLE(set, newbound, var->glbdom.ub));
7156  /* adjust bound to integral value if variable is of integral type */
7157  newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
7158 
7159  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7160  {
7161  /* we do not want to exceed the upperbound, which could have happened due to numerics */
7162  newbound = MIN(newbound, var->locdom.ub);
7163  }
7164  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7165 
7166  SCIPdebugMessage("process changing lower bound of <%s> from %g to %g\n", var->name, var->locdom.lb, newbound);
7167 
7168  if( SCIPsetIsEQ(set, newbound, var->locdom.lb) )
7169  return SCIP_OKAY;
7170  if( SCIPsetIsEQ(set, newbound, var->glbdom.lb) )
7171  newbound = var->glbdom.lb;
7172 
7173  /* change the bound */
7174  oldbound = var->locdom.lb;
7175  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasLE(set, newbound, var->locdom.ub));
7176  var->locdom.lb = newbound;
7177 
7178  /* update statistic; during the update steps of the parent variable we pass a NULL pointer to ensure that we only
7179  * once update the statistic
7180  */
7181  if( stat != NULL )
7182  stat->domchgcount++;
7183 
7184  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7185  {
7186  /* merges overlapping holes into single holes, moves bounds respectively */
7187  domMerge(&var->locdom, blkmem, set, &newbound, NULL);
7188  }
7189 
7190  /* issue bound change event */
7191  assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
7192  if( var->eventfilter != NULL )
7193  {
7194  SCIP_CALL( varEventLbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
7195  }
7196 
7197  /* process parent variables */
7198  for( i = 0; i < var->nparentvars; ++i )
7199  {
7200  parentvar = var->parentvars[i];
7201  assert(parentvar != NULL);
7202 
7203  switch( SCIPvarGetStatus(parentvar) )
7204  {
7206  SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, newbound) );
7207  break;
7208 
7209  case SCIP_VARSTATUS_COLUMN:
7210  case SCIP_VARSTATUS_LOOSE:
7211  case SCIP_VARSTATUS_FIXED:
7213  SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
7214  return SCIP_INVALIDDATA;
7215 
7216  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7217  assert(parentvar->data.aggregate.var == var);
7218  if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
7219  {
7220  SCIP_Real parentnewbound;
7221 
7222  /* a > 0 -> change lower bound of y */
7223  assert((SCIPsetIsInfinity(set, -parentvar->locdom.lb) && SCIPsetIsInfinity(set, -oldbound))
7224  || SCIPsetIsFeasEQ(set, parentvar->locdom.lb, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
7225  || (SCIPsetIsZero(set, parentvar->locdom.lb / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
7226 
7227  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7228  {
7229  parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7230  /* if parent's new lower bound exceeds its upper bound, then this could be due to numerical difficulties, e.g., if numbers are large
7231  * thus, at least a relative comparision of the new lower bound and the current upper bound should proof consistency
7232  * as a result, the parent's lower bound is set to it's upper bound, and not above
7233  */
7234  if( parentnewbound > parentvar->glbdom.ub )
7235  {
7236  /* due to numerics we only want to be feasible in feasibility tolerance */
7237  assert(SCIPsetIsFeasLE(set, parentnewbound, parentvar->glbdom.ub));
7238  parentnewbound = parentvar->glbdom.ub;
7239  }
7240  }
7241  else
7242  parentnewbound = newbound;
7243  SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7244  }
7245  else
7246  {
7247  SCIP_Real parentnewbound;
7248 
7249  /* a < 0 -> change upper bound of y */
7250  assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
7251  assert((SCIPsetIsInfinity(set, parentvar->locdom.ub) && SCIPsetIsInfinity(set, -oldbound))
7252  || SCIPsetIsFeasEQ(set, parentvar->locdom.ub, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
7253  || (SCIPsetIsZero(set, parentvar->locdom.ub / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
7254 
7255  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7256  {
7257  parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7258  /* if parent's new upper bound is below its lower bound, then this could be due to numerical difficulties, e.g., if numbers are large
7259  * thus, at least a relative comparision of the new upper bound and the current lower bound should proof consistency
7260  * as a result, the parent's upper bound is set to it's lower bound, and not below
7261  */
7262  if( parentnewbound < parentvar->glbdom.lb )
7263  {
7264  /* due to numerics we only want to be feasible in feasibility tolerance */
7265  assert(SCIPsetIsFeasGE(set, parentnewbound, parentvar->glbdom.lb));
7266  parentnewbound = parentvar->glbdom.lb;
7267  }
7268  }
7269  else
7270  parentnewbound = -newbound;
7271  SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7272  }
7273  break;
7274 
7275  case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
7276  assert(parentvar->negatedvar != NULL);
7277  assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
7278  assert(parentvar->negatedvar->negatedvar == parentvar);
7279  SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue,
7280  parentvar->data.negate.constant - newbound) );
7281  break;
7282 
7283  default:
7284  SCIPerrorMessage("unknown variable status\n");
7285  return SCIP_INVALIDDATA;
7286  }
7287  }
7288 
7289  return SCIP_OKAY;
7290 }
7291 
7292 /** performs the current change in upper bound, changes all parents accordingly */
7293 static
7295  SCIP_VAR* var, /**< problem variable to change */
7296  BMS_BLKMEM* blkmem, /**< block memory */
7297  SCIP_SET* set, /**< global SCIP settings */
7298  SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7299  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7300  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7301  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7302  SCIP_Real newbound /**< new bound for variable */
7303  )
7304 {
7305  SCIP_VAR* parentvar;
7306  SCIP_Real oldbound;
7307  int i;
7308 
7309  assert(var != NULL);
7310  assert(set != NULL);
7311  assert(var->scip == set->scip);
7312  assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && (SCIPsetIsZero(set, newbound) || SCIPsetIsEQ(set, newbound, 1.0)))
7313  || (SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS && SCIPsetIsIntegral(set, newbound))
7315 
7316  /* check that the bound is feasible */
7317  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsGE(set, newbound, var->glbdom.lb));
7318  /* adjust bound to integral value if variable is of integral type */
7319  newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
7320 
7321  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7322  {
7323  /* we do not want to undercut the lowerbound, which could have happened due to numerics */
7324  newbound = MAX(newbound, var->locdom.lb);
7325  }
7326  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7327 
7328  SCIPdebugMessage("process changing upper bound of <%s> from %g to %g\n", var->name, var->locdom.ub, newbound);
7329 
7330  if( SCIPsetIsEQ(set, newbound, var->locdom.ub) )
7331  return SCIP_OKAY;
7332  if( SCIPsetIsEQ(set, newbound, var->glbdom.ub) )
7333  newbound = var->glbdom.ub;
7334 
7335  /* change the bound */
7336  oldbound = var->locdom.ub;
7337  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasGE(set, newbound, var->locdom.lb));
7338  var->locdom.ub = newbound;
7339 
7340  /* update statistic; during the update steps of the parent variable we pass a NULL pointer to ensure that we only
7341  * once update the statistic
7342  */
7343  if( stat != NULL )
7344  stat->domchgcount++;
7345 
7346  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7347  {
7348  /* merges overlapping holes into single holes, moves bounds respectively */
7349  domMerge(&var->locdom, blkmem, set, NULL, &newbound);
7350  }
7351 
7352  /* issue bound change event */
7353  assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
7354  if( var->eventfilter != NULL )
7355  {
7356  SCIP_CALL( varEventUbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
7357  }
7358 
7359  /* process parent variables */
7360  for( i = 0; i < var->nparentvars; ++i )
7361  {
7362  parentvar = var->parentvars[i];
7363  assert(parentvar != NULL);
7364 
7365  switch( SCIPvarGetStatus(parentvar) )
7366  {
7368  SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, newbound) );
7369  break;
7370 
7371  case SCIP_VARSTATUS_COLUMN:
7372  case SCIP_VARSTATUS_LOOSE:
7373  case SCIP_VARSTATUS_FIXED:
7375  SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
7376  return SCIP_INVALIDDATA;
7377 
7378  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7379  assert(parentvar->data.aggregate.var == var);
7380  if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
7381  {
7382  SCIP_Real parentnewbound;
7383 
7384  /* a > 0 -> change upper bound of x */
7385  assert((SCIPsetIsInfinity(set, parentvar->locdom.ub) && SCIPsetIsInfinity(set, oldbound))
7386  || SCIPsetIsFeasEQ(set, parentvar->locdom.ub,
7387  oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7388  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7389  {
7390  parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7391  /* if parent's new upper bound is below its lower bound, then this could be due to numerical difficulties, e.g., if numbers are large
7392  * thus, at least a relative comparision of the new upper bound and the current lower bound should proof consistency
7393  * as a result, the parent's upper bound is set to it's lower bound, and not below
7394  */
7395  if( parentnewbound < parentvar->glbdom.lb )
7396  {
7397  /* due to numerics we only want to be feasible in feasibility tolerance */
7398  assert(SCIPsetIsFeasGE(set, parentnewbound, parentvar->glbdom.lb));
7399  parentnewbound = parentvar->glbdom.lb;
7400  }
7401  }
7402  else
7403  parentnewbound = newbound;
7404  SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7405  }
7406  else
7407  {
7408  SCIP_Real parentnewbound;
7409 
7410  /* a < 0 -> change lower bound of x */
7411  assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
7412  assert((SCIPsetIsInfinity(set, -parentvar->locdom.lb) && SCIPsetIsInfinity(set, oldbound))
7413  || SCIPsetIsFeasEQ(set, parentvar->locdom.lb,
7414  oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7415  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7416  {
7417  parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7418  /* if parent's new lower bound exceeds its upper bound, then this could be due to numerical difficulties, e.g., if numbers are large
7419  * thus, at least a relative comparision of the new lower bound and the current upper bound should proof consistency
7420  * as a result, the parent's lower bound is set to it's upper bound, and not above
7421  */
7422  if( parentnewbound > parentvar->glbdom.ub )
7423  {
7424  /* due to numerics we only want to be feasible in feasibility tolerance */
7425  assert(SCIPsetIsFeasLE(set, parentnewbound, parentvar->glbdom.ub));
7426  parentnewbound = parentvar->glbdom.ub;
7427  }
7428  }
7429  else
7430  parentnewbound = -newbound;
7431  SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7432  }
7433  break;
7434 
7435  case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
7436  assert(parentvar->negatedvar != NULL);
7437  assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
7438  assert(parentvar->negatedvar->negatedvar == parentvar);
7439  SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue,
7440  parentvar->data.negate.constant - newbound) );
7441  break;
7442 
7443  default:
7444  SCIPerrorMessage("unknown variable status\n");
7445  return SCIP_INVALIDDATA;
7446  }
7447  }
7448 
7449  return SCIP_OKAY;
7450 }
7451 
7452 /** changes current local lower bound of variable; if possible, adjusts bound to integral value; stores inference
7453  * information in variable
7454  */
7456  SCIP_VAR* var, /**< problem variable to change */
7457  BMS_BLKMEM* blkmem, /**< block memory */
7458  SCIP_SET* set, /**< global SCIP settings */
7459  SCIP_STAT* stat, /**< problem statistics */
7460  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7461  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7462  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7463  SCIP_Real newbound /**< new bound for variable */
7464  )
7465 {
7466  assert(var != NULL);
7467  assert(blkmem != NULL);
7468  assert(set != NULL);
7469  assert(var->scip == set->scip);
7470 
7471  /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7472  * of the domain within feastol
7473  */
7474  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->locdom.ub));
7475 
7476  /* adjust bound to integral value if variable is of integral type */
7477  newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
7478 
7479  /* check that the adjusted bound is feasible */
7480  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->locdom.ub));
7481 
7482  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7483  {
7484  /* we do not want to exceed the upperbound, which could have happened due to numerics */
7485  newbound = MIN(newbound, var->locdom.ub);
7486  }
7487  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7488 
7489  SCIPdebugMessage("changing lower bound of <%s>[%g,%g] to %g\n", var->name, var->locdom.lb, var->locdom.ub, newbound);
7490 
7491  if( SCIPsetIsEQ(set, var->locdom.lb, newbound) )
7492  return SCIP_OKAY;
7493 
7494  /* change bounds of attached variables */
7495  switch( SCIPvarGetStatus(var) )
7496  {
7498  if( var->data.original.transvar != NULL )
7499  {
7500  SCIP_CALL( SCIPvarChgLbLocal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue,
7501  newbound) );
7502  }
7503  else
7504  {
7505  assert(set->stage == SCIP_STAGE_PROBLEM);
7506  SCIP_CALL( varProcessChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7507  }
7508  break;
7509 
7510  case SCIP_VARSTATUS_COLUMN:
7511  case SCIP_VARSTATUS_LOOSE:
7512  SCIP_CALL( varProcessChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7513  break;
7514 
7515  case SCIP_VARSTATUS_FIXED:
7516  SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7517  return SCIP_INVALIDDATA;
7518 
7519  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7520  assert(var->data.aggregate.var != NULL);
7521  if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
7522  {
7523  SCIP_Real childnewbound;
7524 
7525  /* a > 0 -> change lower bound of y */
7526  assert((SCIPsetIsInfinity(set, -var->locdom.lb) && SCIPsetIsInfinity(set, -var->data.aggregate.var->locdom.lb))
7527  || SCIPsetIsFeasEQ(set, var->locdom.lb,
7529  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7530  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7531  else
7532  childnewbound = newbound;
7533  SCIP_CALL( SCIPvarChgLbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
7534  childnewbound) );
7535  }
7536  else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7537  {
7538  SCIP_Real childnewbound;
7539 
7540  /* a < 0 -> change upper bound of y */
7541  assert((SCIPsetIsInfinity(set, -var->locdom.lb) && SCIPsetIsInfinity(set, var->data.aggregate.var->locdom.ub))
7542  || SCIPsetIsFeasEQ(set, var->locdom.lb,
7544  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7545  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7546  else
7547  childnewbound = -newbound;
7548  SCIP_CALL( SCIPvarChgUbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
7549  childnewbound) );
7550  }
7551  else
7552  {
7553  SCIPerrorMessage("scalar is zero in aggregation\n");
7554  return SCIP_INVALIDDATA;
7555  }
7556  break;
7557 
7559  SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
7560  return SCIP_INVALIDDATA;
7561 
7562  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
7563  assert(var->negatedvar != NULL);
7565  assert(var->negatedvar->negatedvar == var);
7566  SCIP_CALL( SCIPvarChgUbLocal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue,
7567  var->data.negate.constant - newbound) );
7568  break;
7569 
7570  default:
7571  SCIPerrorMessage("unknown variable status\n");
7572  return SCIP_INVALIDDATA;
7573  }
7574 
7575  return SCIP_OKAY;
7576 }
7577 
7578 /** changes current local upper bound of variable; if possible, adjusts bound to integral value; stores inference
7579  * information in variable
7580  */
7582  SCIP_VAR* var, /**< problem variable to change */
7583  BMS_BLKMEM* blkmem, /**< block memory */
7584  SCIP_SET* set, /**< global SCIP settings */
7585  SCIP_STAT* stat, /**< problem statistics */
7586  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7587  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7588  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7589  SCIP_Real newbound /**< new bound for variable */
7590  )
7591 {
7592  assert(var != NULL);
7593  assert(blkmem != NULL);
7594  assert(set != NULL);
7595  assert(var->scip == set->scip);
7596 
7597  /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7598  * of the domain within feastol
7599  */
7600  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->locdom.lb));
7601 
7602  /* adjust bound to integral value if variable is of integral type */
7603  newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
7604 
7605  /* check that the adjusted bound is feasible */
7606  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->locdom.lb));
7607 
7608  if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7609  {
7610  /* we do not want to undercut the lowerbound, which could have happened due to numerics */
7611  newbound = MAX(newbound, var->locdom.lb);
7612  }
7613  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7614 
7615  SCIPdebugMessage("changing upper bound of <%s>[%g,%g] to %g\n", var->name, var->locdom.lb, var->locdom.ub, newbound);
7616 
7617  if( SCIPsetIsEQ(set, var->locdom.ub, newbound) )
7618  return SCIP_OKAY;
7619 
7620  /* change bounds of attached variables */
7621  switch( SCIPvarGetStatus(var) )
7622  {
7624  if( var->data.original.transvar != NULL )
7625  {
7626  SCIP_CALL( SCIPvarChgUbLocal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7627  }
7628  else
7629  {
7630  assert(set->stage == SCIP_STAGE_PROBLEM);
7631  SCIP_CALL( varProcessChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7632  }
7633  break;
7634 
7635  case SCIP_VARSTATUS_COLUMN:
7636  case SCIP_VARSTATUS_LOOSE:
7637  SCIP_CALL( varProcessChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7638  break;
7639 
7640  case SCIP_VARSTATUS_FIXED:
7641  SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7642  return SCIP_INVALIDDATA;
7643 
7644  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7645  assert(var->data.aggregate.var != NULL);
7646  if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
7647  {
7648  SCIP_Real childnewbound;
7649 
7650  /* a > 0 -> change upper bound of y */
7651  assert((SCIPsetIsInfinity(set, var->locdom.ub) && SCIPsetIsInfinity(set, var->data.aggregate.var->locdom.ub))
7652  || SCIPsetIsFeasEQ(set, var->locdom.ub,
7654  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7655  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7656  else
7657  childnewbound = newbound;
7658  SCIP_CALL( SCIPvarChgUbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
7659  childnewbound) );
7660  }
7661  else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7662  {
7663  SCIP_Real childnewbound;
7664 
7665  /* a < 0 -> change lower bound of y */
7666  assert((SCIPsetIsInfinity(set, var->locdom.ub) && SCIPsetIsInfinity(set, -var->data.aggregate.var->locdom.lb))
7667  || SCIPsetIsFeasEQ(set, var->locdom.ub,
7669  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7670  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7671  else
7672  childnewbound = -newbound;
7673  SCIP_CALL( SCIPvarChgLbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
7674  childnewbound) );
7675  }
7676  else
7677  {
7678  SCIPerrorMessage("scalar is zero in aggregation\n");
7679  return SCIP_INVALIDDATA;
7680  }
7681  break;
7682 
7684  SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
7685  return SCIP_INVALIDDATA;
7686 
7687  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
7688  assert(var->negatedvar != NULL);
7690  assert(var->negatedvar->negatedvar == var);
7691  SCIP_CALL( SCIPvarChgLbLocal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue,
7692  var->data.negate.constant - newbound) );
7693  break;
7694 
7695  default:
7696  SCIPerrorMessage("unknown variable status\n");
7697  return SCIP_INVALIDDATA;
7698  }
7699 
7700  return SCIP_OKAY;
7701 }
7702 
7703 /** changes current local bound of variable; if possible, adjusts bound to integral value; stores inference
7704  * information in variable
7705  */
7707  SCIP_VAR* var, /**< problem variable to change */
7708  BMS_BLKMEM* blkmem, /**< block memory */
7709  SCIP_SET* set, /**< global SCIP settings */
7710  SCIP_STAT* stat, /**< problem statistics */
7711  SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7712  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7713  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7714  SCIP_Real newbound, /**< new bound for variable */
7715  SCIP_BOUNDTYPE boundtype /**< type of bound: lower or upper bound */
7716  )
7717 {
7718  /* apply bound change to the LP data */
7719  switch( boundtype )
7720  {
7721  case SCIP_BOUNDTYPE_LOWER:
7722  return SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound);
7723  case SCIP_BOUNDTYPE_UPPER:
7724  return SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound);
7725  default:
7726  SCIPerrorMessage("unknown bound type\n");
7727  return SCIP_INVALIDDATA;
7728  }
7729 }
7730 
7731 /** changes lower bound of variable in current dive; if possible, adjusts bound to integral value */
7733  SCIP_VAR* var, /**< problem variable to change */
7734  SCIP_SET* set, /**< global SCIP settings */
7735  SCIP_LP* lp, /**< current LP data */
7736  SCIP_Real newbound /**< new bound for variable */
7737  )
7738 {
7739  assert(var != NULL);
7740  assert(set != NULL);
7741  assert(var->scip == set->scip);
7742  assert(lp != NULL);
7743  assert(SCIPlpDiving(lp));
7744 
7745  /* adjust bound for integral variables */
7746  SCIPvarAdjustLb(var, set, &newbound);
7747 
7748  SCIPdebugMessage("changing lower bound of <%s> to %g in current dive\n", var->name, newbound);
7749 
7750  /* change bounds of attached variables */
7751  switch( SCIPvarGetStatus(var) )
7752  {
7754  assert(var->data.original.transvar != NULL);
7755  SCIP_CALL( SCIPvarChgLbDive(var->data.original.transvar, set, lp, newbound) );
7756  break;
7757 
7758  case SCIP_VARSTATUS_COLUMN:
7759  assert(var->data.col != NULL);
7760  SCIP_CALL( SCIPcolChgLb(var->data.col, set, lp, newbound) );
7761  break;
7762 
7763  case SCIP_VARSTATUS_LOOSE:
7764  SCIPerrorMessage("cannot change variable's bounds in dive for LOOSE variables\n");
7765  return SCIP_INVALIDDATA;
7766 
7767  case SCIP_VARSTATUS_FIXED:
7768  SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7769  return SCIP_INVALIDDATA;
7770 
7771  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7772  assert(var->data.aggregate.var != NULL);
7773  if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
7774  {
7775  SCIP_Real childnewbound;
7776 
7777  /* a > 0 -> change lower bound of y */
7778  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7779  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7780  else
7781  childnewbound = newbound;
7782  SCIP_CALL( SCIPvarChgLbDive(var->data.aggregate.var, set, lp, childnewbound) );
7783  }
7784  else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7785  {
7786  SCIP_Real childnewbound;
7787 
7788  /* a < 0 -> change upper bound of y */
7789  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7790  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7791  else
7792  childnewbound = -newbound;
7793  SCIP_CALL( SCIPvarChgUbDive(var->data.aggregate.var, set, lp, childnewbound) );
7794  }
7795  else
7796  {
7797  SCIPerrorMessage("scalar is zero in aggregation\n");
7798  return SCIP_INVALIDDATA;
7799  }
7800  break;
7801 
7803  SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
7804  return SCIP_INVALIDDATA;
7805 
7806  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
7807  assert(var->negatedvar != NULL);
7809  assert(var->negatedvar->negatedvar == var);
7810  SCIP_CALL( SCIPvarChgUbDive(var->negatedvar, set, lp, var->data.negate.constant - newbound) );
7811  break;
7812 
7813  default:
7814  SCIPerrorMessage("unknown variable status\n");
7815  return SCIP_INVALIDDATA;
7816  }
7817 
7818  return SCIP_OKAY;
7819 }
7820 
7821 /** changes upper bound of variable in current dive; if possible, adjusts bound to integral value */
7823  SCIP_VAR* var, /**< problem variable to change */
7824  SCIP_SET* set, /**< global SCIP settings */
7825  SCIP_LP* lp, /**< current LP data */
7826  SCIP_Real newbound /**< new bound for variable */
7827  )
7828 {
7829  assert(var != NULL);
7830  assert(set != NULL);
7831  assert(var->scip == set->scip);
7832  assert(lp != NULL);
7833  assert(SCIPlpDiving(lp));
7834 
7835  /* adjust bound for integral variables */
7836  SCIPvarAdjustUb(var, set, &newbound);
7837 
7838  SCIPdebugMessage("changing upper bound of <%s> to %g in current dive\n", var->name, newbound);
7839 
7840  /* change bounds of attached variables */
7841  switch( SCIPvarGetStatus(var) )
7842  {
7844  assert(var->data.original.transvar != NULL);
7845  SCIP_CALL( SCIPvarChgUbDive(var->data.original.transvar, set, lp, newbound) );
7846  break;
7847 
7848  case SCIP_VARSTATUS_COLUMN:
7849  assert(var->data.col != NULL);
7850  SCIP_CALL( SCIPcolChgUb(var->data.col, set, lp, newbound) );
7851  break;
7852 
7853  case SCIP_VARSTATUS_LOOSE:
7854  SCIPerrorMessage("cannot change variable's bounds in dive for LOOSE variables\n");
7855  return SCIP_INVALIDDATA;
7856 
7857  case SCIP_VARSTATUS_FIXED:
7858  SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7859  return SCIP_INVALIDDATA;
7860 
7861  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7862  assert(var->data.aggregate.var != NULL);
7863  if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
7864  {
7865  SCIP_Real childnewbound;
7866 
7867  /* a > 0 -> change upper bound of y */
7868  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7869  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7870  else
7871  childnewbound = newbound;
7872  SCIP_CALL( SCIPvarChgUbDive(var->data.aggregate.var, set, lp, childnewbound) );
7873  }
7874  else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7875  {
7876  SCIP_Real childnewbound;
7877 
7878  /* a < 0 -> change lower bound of y */
7879  if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7880  childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7881  else
7882  childnewbound = -newbound;
7883  SCIP_CALL( SCIPvarChgLbDive(var->data.aggregate.var, set, lp, childnewbound) );
7884  }
7885  else
7886  {
7887  SCIPerrorMessage("scalar is zero in aggregation\n");
7888  return SCIP_INVALIDDATA;
7889  }
7890  break;
7891 
7893  SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
7894  return SCIP_INVALIDDATA;
7895 
7896  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
7897  assert(var->negatedvar != NULL);
7899  assert(var->negatedvar->negatedvar == var);
7900  SCIP_CALL( SCIPvarChgLbDive(var->negatedvar, set, lp, var->data.negate.constant - newbound) );
7901  break;
7902 
7903  default:
7904  SCIPerrorMessage("unknown variable status\n");
7905  return SCIP_INVALIDDATA;
7906  }
7907 
7908  return SCIP_OKAY;
7909 }
7910 
7911 /** for a multi-aggregated variable, gives the local lower bound computed by adding the local bounds from all
7912  * aggregation variables, this lower bound may be tighter than the one given by SCIPvarGetLbLocal, since the latter is
7913  * not updated if bounds of aggregation variables are changing
7914  *
7915  * calling this function for a non-multi-aggregated variable is not allowed
7916  */
7918  SCIP_VAR* var, /**< problem variable */
7919  SCIP_SET* set /**< global SCIP settings */
7920  )
7921 {
7922  int i;
7923  SCIP_Real lb;
7924  SCIP_Real bnd;
7925  SCIP_VAR* aggrvar;
7926  SCIP_Bool posinf;
7927  SCIP_Bool neginf;
7928 
7929  assert(var != NULL);
7930  assert(set != NULL);
7931  assert(var->scip == set->scip);
7933 
7934  posinf = FALSE;
7935  neginf = FALSE;
7936  lb = var->data.multaggr.constant;
7937  for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
7938  {
7939  aggrvar = var->data.multaggr.vars[i];
7940  if( var->data.multaggr.scalars[i] > 0.0 )
7941  {
7942  bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbLocal(aggrvar, set) : SCIPvarGetLbLocal(aggrvar);
7943 
7944  if( SCIPsetIsInfinity(set, bnd) )
7945  posinf = TRUE;
7946  else if( SCIPsetIsInfinity(set, -bnd) )
7947  neginf = TRUE;
7948  else
7949  lb += var->data.multaggr.scalars[i] * bnd;
7950  }
7951  else
7952  {
7953  bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbLocal(aggrvar, set) : SCIPvarGetUbLocal(aggrvar);
7954 
7955  if( SCIPsetIsInfinity(set, -bnd) )
7956  posinf = TRUE;
7957  else if( SCIPsetIsInfinity(set, bnd) )
7958  neginf = TRUE;
7959  else
7960  lb += var->data.multaggr.scalars[i] * bnd;
7961  }
7962 
7963  /* stop if two diffrent infinities (or a -infinity) were found and return local lower bound of multi aggregated
7964  * variable
7965  */
7966  if( neginf )
7967  return SCIPvarGetLbLocal(var);
7968  }
7969 
7970  /* if positive infinity flag was set to true return infinity */
7971  if( posinf )
7972  return SCIPsetInfinity(set);
7973 
7974  return (MAX(lb, SCIPvarGetLbLocal(var))); /*lint !e666*/
7975 }
7976 
7977 /** for a multi-aggregated variable, gives the local upper bound computed by adding the local bounds from all
7978  * aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbLocal, since the latter is
7979  * not updated if bounds of aggregation variables are changing
7980  *
7981  * calling this function for a non-multi-aggregated variable is not allowed
7982  */
7984  SCIP_VAR* var, /**< problem variable */
7985  SCIP_SET* set /**< global SCIP settings */
7986  )
7987 {
7988  int i;
7989  SCIP_Real ub;
7990  SCIP_Real bnd;
7991  SCIP_VAR* aggrvar;
7992  SCIP_Bool posinf;
7993  SCIP_Bool neginf;
7994 
7995  assert(var != NULL);
7996  assert(set != NULL);
7997  assert(var->scip == set->scip);
7999 
8000  posinf = FALSE;
8001  neginf = FALSE;
8002  ub = var->data.multaggr.constant;
8003  for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8004  {
8005  aggrvar = var->data.multaggr.vars[i];
8006  if( var->data.multaggr.scalars[i] > 0.0 )
8007  {
8008  bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbLocal(aggrvar, set) : SCIPvarGetUbLocal(aggrvar);
8009 
8010  if( SCIPsetIsInfinity(set, bnd) )
8011  posinf = TRUE;
8012  else if( SCIPsetIsInfinity(set, -bnd) )
8013  neginf = TRUE;
8014  else
8015  ub += var->data.multaggr.scalars[i] * bnd;
8016  }
8017  else
8018  {
8019  bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbLocal(aggrvar, set) : SCIPvarGetLbLocal(aggrvar);
8020 
8021  if( SCIPsetIsInfinity(set, -bnd) )
8022  posinf = TRUE;
8023  else if( SCIPsetIsInfinity(set, bnd) )
8024  neginf = TRUE;
8025  else
8026  ub += var->data.multaggr.scalars[i] * bnd;
8027  }
8028 
8029  /* stop if two diffrent infinities (or a -infinity) were found and return local upper bound of multi aggregated
8030  * variable
8031  */
8032  if( posinf )
8033  return SCIPvarGetUbLocal(var);
8034  }
8035 
8036  /* if negative infinity flag was set to true return -infinity */
8037  if( neginf )
8038  return -SCIPsetInfinity(set);
8039 
8040  return (MIN(ub, SCIPvarGetUbLocal(var))); /*lint !e666*/
8041 }
8042 
8043 /** for a multi-aggregated variable, gives the global lower bound computed by adding the global bounds from all
8044  * aggregation variables, this global bound may be tighter than the one given by SCIPvarGetLbGlobal, since the latter is
8045  * not updated if bounds of aggregation variables are changing
8046  *
8047  * calling this function for a non-multi-aggregated variable is not allowed
8048  */
8050  SCIP_VAR* var, /**< problem variable */
8051  SCIP_SET* set /**< global SCIP settings */
8052  )
8053 {
8054  int i;
8055  SCIP_Real lb;
8056  SCIP_Real bnd;
8057  SCIP_VAR* aggrvar;
8058  SCIP_Bool posinf;
8059  SCIP_Bool neginf;
8060 
8061  assert(var != NULL);
8062  assert(set != NULL);
8063  assert(var->scip == set->scip);
8065 
8066  posinf = FALSE;
8067  neginf = FALSE;
8068  lb = var->data.multaggr.constant;
8069  for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8070  {
8071  aggrvar = var->data.multaggr.vars[i];
8072  if( var->data.multaggr.scalars[i] > 0.0 )
8073  {
8074  bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbGlobal(aggrvar, set) : SCIPvarGetLbGlobal(aggrvar);
8075 
8076  if( SCIPsetIsInfinity(set, bnd) )
8077  posinf = TRUE;
8078  else if( SCIPsetIsInfinity(set, -bnd) )
8079  neginf = TRUE;
8080  else
8081  lb += var->data.multaggr.scalars[i] * bnd;
8082  }
8083  else
8084  {
8085  bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbGlobal(aggrvar, set) : SCIPvarGetUbGlobal(aggrvar);
8086 
8087  if( SCIPsetIsInfinity(set, -bnd) )
8088  posinf = TRUE;
8089  else if( SCIPsetIsInfinity(set, bnd) )
8090  neginf = TRUE;
8091  else
8092  lb += var->data.multaggr.scalars[i] * bnd;
8093  }
8094 
8095  /* stop if two diffrent infinities (or a -infinity) were found and return global lower bound of multi aggregated
8096  * variable
8097  */
8098  if( neginf )
8099  return SCIPvarGetLbGlobal(var);
8100  }
8101 
8102  /* if positive infinity flag was set to true return infinity */
8103  if( posinf )
8104  return SCIPsetInfinity(set);
8105 
8106  return (MAX(lb, SCIPvarGetLbGlobal(var))); /*lint !e666*/
8107 }
8108 
8109 /** for a multi-aggregated variable, gives the global upper bound computed by adding the global bounds from all
8110  * aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbGlobal, since the latter is
8111  * not updated if bounds of aggregation variables are changing
8112  *
8113  * calling this function for a non-multi-aggregated variable is not allowed
8114  */
8116  SCIP_VAR* var, /**< problem variable */
8117  SCIP_SET* set /**< global SCIP settings */
8118  )
8119 {
8120  int i;
8121  SCIP_Real ub;
8122  SCIP_Real bnd;
8123  SCIP_VAR* aggrvar;
8124  SCIP_Bool posinf;
8125  SCIP_Bool neginf;
8126 
8127  assert(var != NULL);
8128  assert(set != NULL);
8129  assert(var->scip == set->scip);
8131 
8132  posinf = FALSE;
8133  neginf = FALSE;
8134  ub = var->data.multaggr.constant;
8135  for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8136  {
8137  aggrvar = var->data.multaggr.vars[i];
8138  if( var->data.multaggr.scalars[i] > 0.0 )
8139  {
8140  bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbGlobal(aggrvar, set) : SCIPvarGetUbGlobal(aggrvar);
8141 
8142  if( SCIPsetIsInfinity(set, bnd) )
8143  posinf = TRUE;
8144  else if( SCIPsetIsInfinity(set, -bnd) )
8145  neginf = TRUE;
8146  else
8147  ub += var->data.multaggr.scalars[i] * bnd;
8148  }
8149  else
8150  {
8151  bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbGlobal(aggrvar, set) : SCIPvarGetLbGlobal(aggrvar);
8152 
8153  if( SCIPsetIsInfinity(set, -bnd) )
8154  posinf = TRUE;
8155  else if( SCIPsetIsInfinity(set, bnd) )
8156  neginf = TRUE;
8157  else
8158  ub += var->data.multaggr.scalars[i] * bnd;
8159  }
8160 
8161  /* stop if two diffrent infinities (or a -infinity) were found and return local upper bound of multi aggregated
8162  * variable
8163  */
8164  if( posinf )
8165  return SCIPvarGetUbGlobal(var);
8166  }
8167 
8168  /* if negative infinity flag was set to true return -infinity */
8169  if( neginf )
8170  return -SCIPsetInfinity(set);
8171 
8172  return (MIN(ub, SCIPvarGetUbGlobal(var))); /*lint !e666*/
8173 }
8174 
8175 /** adds a hole to the original domain of the variable */
8177  SCIP_VAR* var, /**< problem variable */
8178  BMS_BLKMEM* blkmem, /**< block memory */
8179  SCIP_SET* set, /**< global SCIP settings */
8180  SCIP_Real left, /**< left bound of open interval in new hole */
8181  SCIP_Real right /**< right bound of open interval in new hole */
8182  )
8183 {
8184  SCIP_Bool added;
8185 
8186  assert(var != NULL);
8187  assert(!SCIPvarIsTransformed(var));
8189  assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
8190  assert(set != NULL);
8191  assert(var->scip == set->scip);
8192  assert(set->stage == SCIP_STAGE_PROBLEM);
8193 
8194  SCIPdebugMessage("adding original hole (%g,%g) to <%s>\n", left, right, var->name);
8195 
8196  if( SCIPsetIsEQ(set, left, right) )
8197  return SCIP_OKAY;
8198 
8199  /* the interval should not be empty */
8200  assert(SCIPsetIsLT(set, left, right));
8201 
8202  /* the the interval bound should already be adjusted */
8203  assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8204  assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8205 
8206  /* the the interval should lay between the lower and upper bound */
8207  assert(SCIPsetIsGE(set, left, SCIPvarGetLbOriginal(var)));
8208  assert(SCIPsetIsLE(set, right, SCIPvarGetUbOriginal(var)));
8209 
8210  /* add domain hole */
8211  SCIP_CALL( domAddHole(&var->data.original.origdom, blkmem, set, left, right, &added) );
8212 
8213  /* merges overlapping holes into single holes, moves bounds respectively if hole was added */
8214  if( added )
8215  {
8216  domMerge(&var->data.original.origdom, blkmem, set, NULL, NULL);
8217  }
8218 
8219  /**@todo add hole in parent and child variables (just like with bound changes);
8220  * warning! original vars' holes are in original blkmem, transformed vars' holes in transformed blkmem
8221  */
8222 
8223  return SCIP_OKAY;
8224 }
8225 
8226 /** performs the current add of domain, changes all parents accordingly */
8227 static
8229  SCIP_VAR* var, /**< problem variable */
8230  BMS_BLKMEM* blkmem, /**< block memory */
8231  SCIP_SET* set, /**< global SCIP settings */
8232  SCIP_STAT* stat, /**< problem statistics */
8233  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8234  SCIP_Real left, /**< left bound of open interval in new hole */
8235  SCIP_Real right, /**< right bound of open interval in new hole */
8236  SCIP_Bool* added /**< pointer to store whether the hole was added */
8237  )
8238 {
8239  SCIP_VAR* parentvar;
8240  SCIP_Real newlb;
8241  SCIP_Real newub;
8242  int i;
8243 
8244  assert(var != NULL);
8245  assert(added != NULL);
8246  assert(blkmem != NULL);
8247 
8248  /* the interval should not be empty */
8249  assert(SCIPsetIsLT(set, left, right));
8250 
8251  /* the interval bound should already be adjusted */
8252  assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8253  assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8254 
8255  /* the interval should lay between the lower and upper bound */
8256  assert(SCIPsetIsGE(set, left, SCIPvarGetLbGlobal(var)));
8257  assert(SCIPsetIsLE(set, right, SCIPvarGetUbGlobal(var)));
8258 
8259  /* @todo add debugging mechanism for holes when using a debugging solution */
8260 
8261  /* add hole to hole list */
8262  SCIP_CALL( domAddHole(&var->glbdom, blkmem, set, left, right, added) );
8263 
8264  /* check if the hole is redundant */
8265  if( !(*added) )
8266  return SCIP_OKAY;
8267 
8268  /* current bounds */
8269  newlb = var->glbdom.lb;
8270  newub = var->glbdom.ub;
8271 
8272  /* merge domain holes */
8273  domMerge(&var->glbdom, blkmem, set, &newlb, &newub);
8274 
8275  /* the bound should not be changed */
8276  assert(SCIPsetIsEQ(set, newlb, var->glbdom.lb));
8277  assert(SCIPsetIsEQ(set, newub, var->glbdom.ub));
8278 
8279  /* issue bound change event */
8280  assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
8281  if( var->eventfilter != NULL )
8282  {
8283  SCIP_CALL( varEventGholeAdded(var, blkmem, set, eventqueue, left, right) );
8284  }
8285 
8286  /* process parent variables */
8287  for( i = 0; i < var->nparentvars; ++i )
8288  {
8289  SCIP_Real parentnewleft;
8290  SCIP_Real parentnewright;
8291  SCIP_Bool localadded;
8292 
8293  parentvar = var->parentvars[i];
8294  assert(parentvar != NULL);
8295 
8296  switch( SCIPvarGetStatus(parentvar) )
8297  {
8299  parentnewleft = left;
8300  parentnewright = right;
8301  break;
8302 
8303  case SCIP_VARSTATUS_COLUMN:
8304  case SCIP_VARSTATUS_LOOSE:
8305  case SCIP_VARSTATUS_FIXED:
8307  SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
8308  return SCIP_INVALIDDATA;
8309 
8310  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8311  assert(parentvar->data.aggregate.var == var);
8312 
8313  if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
8314  {
8315  /* a > 0 -> change upper bound of x */
8316  parentnewleft = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8317  parentnewright = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8318  }
8319  else
8320  {
8321  /* a < 0 -> change lower bound of x */
8322  assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
8323 
8324  parentnewright = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8325  parentnewleft = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8326  }
8327  break;
8328 
8329  case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
8330  assert(parentvar->negatedvar != NULL);
8331  assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
8332  assert(parentvar->negatedvar->negatedvar == parentvar);
8333 
8334  parentnewright = -left + parentvar->data.negate.constant;
8335  parentnewleft = -right + parentvar->data.negate.constant;
8336  break;
8337 
8338  default:
8339  SCIPerrorMessage("unknown variable status\n");
8340  return SCIP_INVALIDDATA;
8341  }
8342 
8343  SCIPdebugMessage("add global hole (%g,%g) to parent variable <%s>\n", parentnewleft, parentnewright, SCIPvarGetName(parentvar));
8344 
8345  /* perform hole added for parent variable */
8346  assert(blkmem != NULL);
8347  assert(SCIPsetIsLT(set, parentnewleft, parentnewright));
8348  SCIP_CALL( varProcessAddHoleGlobal(parentvar, blkmem, set, stat, eventqueue,
8349  parentnewleft, parentnewright, &localadded) );
8350  assert(localadded);
8351  }
8352 
8353  return SCIP_OKAY;
8354 }
8355 
8356 /** adds a hole to the variable's global and local domain */
8358  SCIP_VAR* var, /**< problem variable */
8359  BMS_BLKMEM* blkmem, /**< block memory */
8360  SCIP_SET* set, /**< global SCIP settings */
8361  SCIP_STAT* stat, /**< problem statistics */
8362  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8363  SCIP_Real left, /**< left bound of open interval in new hole */
8364  SCIP_Real right, /**< right bound of open interval in new hole */
8365  SCIP_Bool* added /**< pointer to store whether the hole was added */
8366  )
8367 {
8368  SCIP_Real childnewleft;
8369  SCIP_Real childnewright;
8370 
8371  assert(var != NULL);
8372  assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
8373  assert(blkmem != NULL);
8374  assert(added != NULL);
8375 
8376  SCIPdebugMessage("adding global hole (%g,%g) to <%s>\n", left, right, var->name);
8377 
8378  /* the interval should not be empty */
8379  assert(SCIPsetIsLT(set, left, right));
8380 
8381  /* the the interval bound should already be adjusted */
8382  assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8383  assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8384 
8385  /* the the interval should lay between the lower and upper bound */
8386  assert(SCIPsetIsGE(set, left, SCIPvarGetLbGlobal(var)));
8387  assert(SCIPsetIsLE(set, right, SCIPvarGetUbGlobal(var)));
8388 
8389  /* change bounds of attached variables */
8390  switch( SCIPvarGetStatus(var) )
8391  {
8393  if( var->data.original.transvar != NULL )
8394  {
8395  SCIP_CALL( SCIPvarAddHoleGlobal(var->data.original.transvar, blkmem, set, stat, eventqueue,
8396  left, right, added) );
8397  }
8398  else
8399  {
8400  assert(set->stage == SCIP_STAGE_PROBLEM);
8401 
8402  SCIP_CALL( varProcessAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) );
8403  if( *added )
8404  {
8405  SCIP_Bool localadded;
8406 
8407  SCIP_CALL( SCIPvarAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, &localadded) );
8408  }
8409  }
8410  break;
8411 
8412  case SCIP_VARSTATUS_COLUMN:
8413  case SCIP_VARSTATUS_LOOSE:
8414  SCIP_CALL( varProcessAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) );
8415  if( *added )
8416  {
8417  SCIP_Bool localadded;
8418 
8419  SCIP_CALL( SCIPvarAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, &localadded) );
8420  }
8421  break;
8422 
8423  case SCIP_VARSTATUS_FIXED:
8424  SCIPerrorMessage("cannot add hole of a fixed variable\n");
8425  return SCIP_INVALIDDATA;
8426 
8427  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8428  assert(var->data.aggregate.var != NULL);
8429 
8430  if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
8431  {
8432  /* a > 0 -> change lower bound of y */
8433  childnewleft = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
8434  childnewright = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
8435  }
8436  else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8437  {
8438  childnewright = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
8439  childnewleft = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
8440  }
8441  else
8442  {
8443  SCIPerrorMessage("scalar is zero in aggregation\n");
8444  return SCIP_INVALIDDATA;
8445  }
8446  SCIP_CALL( SCIPvarAddHoleGlobal(var->data.aggregate.var, blkmem, set, stat, eventqueue,
8447  childnewleft, childnewright, added) );
8448  break;
8449 
8451  SCIPerrorMessage("cannot add a hole of a multi-aggregated variable.\n");
8452  return SCIP_INVALIDDATA;
8453 
8454  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8455  assert(var->negatedvar != NULL);
8457  assert(var->negatedvar->negatedvar == var);
8458 
8459  childnewright = -left + var->data.negate.constant;
8460  childnewleft = -right + var->data.negate.constant;
8461 
8462  SCIP_CALL( SCIPvarAddHoleGlobal(var->negatedvar, blkmem, set, stat, eventqueue,
8463  childnewleft, childnewright, added) );
8464  break;
8465 
8466  default:
8467  SCIPerrorMessage("unknown variable status\n");
8468  return SCIP_INVALIDDATA;
8469  }
8470 
8471  return SCIP_OKAY;
8472 }
8473 
8474 /** performs the current add of domain, changes all parents accordingly */
8475 static
8477  SCIP_VAR* var, /**< problem variable */
8478  BMS_BLKMEM* blkmem, /**< block memory */
8479  SCIP_SET* set, /**< global SCIP settings */
8480  SCIP_STAT* stat, /**< problem statistics */
8481  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8482  SCIP_Real left, /**< left bound of open interval in new hole */
8483  SCIP_Real right, /**< right bound of open interval in new hole */
8484  SCIP_Bool* added /**< pointer to store whether the hole was added, or NULL */
8485  )
8486 {
8487  SCIP_VAR* parentvar;
8488  SCIP_Real newlb;
8489  SCIP_Real newub;
8490  int i;
8491 
8492  assert(var != NULL);
8493  assert(added != NULL);
8494  assert(blkmem != NULL);
8495 
8496  /* the interval should not be empty */
8497  assert(SCIPsetIsLT(set, left, right));
8498 
8499  /* the the interval bound should already be adjusted */
8500  assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8501  assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8502 
8503  /* the the interval should lay between the lower and upper bound */
8504  assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
8505  assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
8506 
8507  /* add hole to hole list */
8508  SCIP_CALL( domAddHole(&var->locdom, blkmem, set, left, right, added) );
8509 
8510  /* check if the hole is redundant */
8511  if( !(*added) )
8512  return SCIP_OKAY;
8513 
8514  /* current bounds */
8515  newlb = var->locdom.lb;
8516  newub = var->locdom.ub;
8517 
8518  /* merge domain holes */
8519  domMerge(&var->locdom, blkmem, set, &newlb, &newub);
8520 
8521  /* the bound should not be changed */
8522  assert(SCIPsetIsEQ(set, newlb, var->locdom.lb));
8523  assert(SCIPsetIsEQ(set, newub, var->locdom.ub));
8524 
8525 #if 0
8526  /* issue bound change event */
8527  assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
8528  if( var->eventfilter != NULL )
8529  {
8530  SCIP_CALL( varEventLholeAdded(var, blkmem, set, lp, branchcand, eventqueue, left, right) );
8531  }
8532 #endif
8533 
8534  /* process parent variables */
8535  for( i = 0; i < var->nparentvars; ++i )
8536  {
8537  SCIP_Real parentnewleft;
8538  SCIP_Real parentnewright;
8539  SCIP_Bool localadded;
8540 
8541  parentvar = var->parentvars[i];
8542  assert(parentvar != NULL);
8543 
8544  switch( SCIPvarGetStatus(parentvar) )
8545  {
8547  parentnewleft = left;
8548  parentnewright = right;
8549  break;
8550 
8551  case SCIP_VARSTATUS_COLUMN:
8552  case SCIP_VARSTATUS_LOOSE:
8553  case SCIP_VARSTATUS_FIXED:
8555  SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
8556  return SCIP_INVALIDDATA;
8557 
8558  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8559  assert(parentvar->data.aggregate.var == var);
8560 
8561  if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
8562  {
8563  /* a > 0 -> change upper bound of x */
8564  parentnewleft = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8565  parentnewright = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8566  }
8567  else
8568  {
8569  /* a < 0 -> change lower bound of x */
8570  assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
8571 
8572  parentnewright = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8573  parentnewleft = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8574  }
8575  break;
8576 
8577  case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
8578  assert(parentvar->negatedvar != NULL);
8579  assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
8580  assert(parentvar->negatedvar->negatedvar == parentvar);
8581 
8582  parentnewright = -left + parentvar->data.negate.constant;
8583  parentnewleft = -right + parentvar->data.negate.constant;
8584  break;
8585 
8586  default:
8587  SCIPerrorMessage("unknown variable status\n");
8588  return SCIP_INVALIDDATA;
8589  }
8590 
8591  SCIPdebugMessage("add local hole (%g,%g) to parent variable <%s>\n", parentnewleft, parentnewright, SCIPvarGetName(parentvar));
8592 
8593  /* perform hole added for parent variable */
8594  assert(blkmem != NULL);
8595  assert(SCIPsetIsLT(set, parentnewleft, parentnewright));
8596  SCIP_CALL( varProcessAddHoleLocal(parentvar, blkmem, set, stat, eventqueue,
8597  parentnewleft, parentnewright, &localadded) );
8598  assert(localadded);
8599  }
8600 
8601  return SCIP_OKAY;
8602 }
8603 
8604 /** adds a hole to the variable's current local domain */
8606  SCIP_VAR* var, /**< problem variable */
8607  BMS_BLKMEM* blkmem, /**< block memory */
8608  SCIP_SET* set, /**< global SCIP settings */
8609  SCIP_STAT* stat, /**< problem statistics */
8610  SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8611  SCIP_Real left, /**< left bound of open interval in new hole */
8612  SCIP_Real right, /**< right bound of open interval in new hole */
8613  SCIP_Bool* added /**< pointer to store whether the hole was added */
8614  )
8615 {
8616  SCIP_Real childnewleft;
8617  SCIP_Real childnewright;
8618 
8619  SCIPdebugMessage("adding local hole (%g,%g) to <%s>\n", left, right, var->name);
8620 
8621  assert(var != NULL);
8622  assert(set != NULL);
8623  assert(var->scip == set->scip);
8624  assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
8625  assert(blkmem != NULL);
8626  assert(added != NULL);
8627 
8628  /* the interval should not be empty */
8629  assert(SCIPsetIsLT(set, left, right));
8630 
8631  /* the the interval bound should already be adjusted */
8632  assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8633  assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8634 
8635  /* the the interval should lay between the lower and upper bound */
8636  assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
8637  assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
8638 
8639  /* change bounds of attached variables */
8640  switch( SCIPvarGetStatus(var) )
8641  {
8643  if( var->data.original.transvar != NULL )
8644  {
8645  SCIP_CALL( SCIPvarAddHoleLocal(var->data.original.transvar, blkmem, set, stat, eventqueue,
8646  left, right, added) );
8647  }
8648  else
8649  {
8650  assert(set->stage == SCIP_STAGE_PROBLEM);
8651 
8652  stat->domchgcount++;
8653  SCIP_CALL( varProcessAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, added) );
8654  }
8655  break;
8656 
8657  case SCIP_VARSTATUS_COLUMN:
8658  case SCIP_VARSTATUS_LOOSE:
8659  stat->domchgcount++;
8660  SCIP_CALL( varProcessAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, added) );
8661  break;
8662 
8663  case SCIP_VARSTATUS_FIXED:
8664  SCIPerrorMessage("cannot add domain hole to a fixed variable\n");
8665  return SCIP_INVALIDDATA;
8666 
8667  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8668  assert(var->data.aggregate.var != NULL);
8669 
8670  if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
8671  {
8672  /* a > 0 -> change lower bound of y */
8673  childnewleft = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
8674  childnewright = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
8675  }
8676  else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8677  {
8678  childnewright = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
8679  childnewleft = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
8680  }
8681  else
8682  {
8683  SCIPerrorMessage("scalar is zero in aggregation\n");
8684  return SCIP_INVALIDDATA;
8685  }
8686  SCIP_CALL( SCIPvarAddHoleLocal(var->data.aggregate.var, blkmem, set, stat, eventqueue,
8687  childnewleft, childnewright, added) );
8688  break;
8689 
8691  SCIPerrorMessage("cannot add domain hole to a multi-aggregated variable.\n");
8692  return SCIP_INVALIDDATA;
8693 
8694  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8695  assert(var->negatedvar != NULL);
8697  assert(var->negatedvar->negatedvar == var);
8698 
8699  childnewright = -left + var->data.negate.constant;
8700  childnewleft = -right + var->data.negate.constant;
8701 
8702  SCIP_CALL( SCIPvarAddHoleLocal(var->negatedvar, blkmem, set, stat, eventqueue, childnewleft, childnewright, added) );
8703  break;
8704 
8705  default:
8706  SCIPerrorMessage("unknown variable status\n");
8707  return SCIP_INVALIDDATA;
8708  }
8709 
8710  return SCIP_OKAY;
8711 }
8712 
8713 /** resets the global and local bounds of original variable to their original values */
8715  SCIP_VAR* var, /**< problem variable */
8716  BMS_BLKMEM* blkmem, /**< block memory */
8717  SCIP_SET* set, /**< global SCIP settings */
8718  SCIP_STAT* stat /**< problem statistics */
8719  )
8720 {
8721  assert(var != NULL);
8722  assert(set != NULL);
8723  assert(var->scip == set->scip);
8724  assert(SCIPvarIsOriginal(var));
8725  /* resetting of bounds on original variables which have a transformed counterpart easily fails if, e.g.,
8726  * the transformed variable has been fixed */
8727  assert(SCIPvarGetTransVar(var) == NULL);
8728 
8729  /* copy the original bounds back to the global and local bounds */
8730  SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.lb) );
8731  SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.ub) );
8732  SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.lb) );
8733  SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.ub) );
8734 
8735  /* free the global and local holelists and duplicate the original ones */
8736  /**@todo this has also to be called recursively with methods similar to SCIPvarChgLbGlobal() */
8737  holelistFree(&var->glbdom.holelist, blkmem);
8738  holelistFree(&var->locdom.holelist, blkmem);
8739  SCIP_CALL( holelistDuplicate(&var->glbdom.holelist, blkmem, set, var->data.original.origdom.holelist) );
8740  SCIP_CALL( holelistDuplicate(&var->locdom.holelist, blkmem, set, var->data.original.origdom.holelist) );
8741 
8742  return SCIP_OKAY;
8743 }
8744 
8745 /** issues a IMPLADDED event on the given variable */
8746 static
8748  SCIP_VAR* var, /**< problem variable to change */
8749  BMS_BLKMEM* blkmem, /**< block memory */
8750  SCIP_SET* set, /**< global SCIP settings */
8751  SCIP_EVENTQUEUE* eventqueue /**< event queue */
8752  )
8753 {
8754  SCIP_EVENT* event;
8755 
8756  assert(var != NULL);
8757 
8758  /* issue IMPLADDED event on variable */
8759  SCIP_CALL( SCIPeventCreateImplAdded(&event, blkmem, var) );
8760  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
8761 
8762  return SCIP_OKAY;
8763 }
8764 
8765 /** actually performs the addition of a variable bound to the variable's vbound arrays */
8766 static
8768  SCIP_VAR* var, /**< problem variable x in x <= b*z + d or x >= b*z + d */
8769  BMS_BLKMEM* blkmem, /**< block memory */
8770  SCIP_SET* set, /**< global SCIP settings */
8771  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
8772  SCIP_BOUNDTYPE vbtype, /**< type of variable bound (LOWER or UPPER) */
8773  SCIP_VAR* vbvar, /**< variable z in x <= b*z + d or x >= b*z + d */
8774  SCIP_Real vbcoef, /**< coefficient b in x <= b*z + d or x >= b*z + d */
8775  SCIP_Real vbconstant /**< constant d in x <= b*z + d or x >= b*z + d */
8776  )
8777 {
8778  SCIP_Bool added;
8779 
8780  /* It can happen that the variable "var" and the variable "vbvar" are the same variable. For example if a variable
8781  * gets aggregated, the variable bounds (vbound) of that variable are copied to the other variable. A variable bound
8782  * variable of the aggregated variable might be the same as the one its gets aggregated too.
8783  *
8784  * If the variable "var" and the variable "vbvar" are the same, the variable bound which should be added here has to
8785  * be redundant. This is the case since an infeasibility should have be detected in the previous methods. As well as
8786  * the bounds of the variable which should be also already be tightened in the previous methods. Therefore, the
8787  * variable bound can be ignored.
8788  *
8789  * From the way the the variable bound system is implemented (detecting infeasibility, tighten bounds), the
8790  * equivalence of the variables should be checked here.
8791  */
8792  if( var == vbvar )
8793  {
8794  /* in this case the variable bound has to be redundant, this means for possible assignments to this variable; this
8795  * can be checked via the global bounds of the variable */
8796 #ifndef NDEBUG
8797  SCIP_Real lb;
8798  SCIP_Real ub;
8799 
8800  lb = SCIPvarGetLbGlobal(var);
8801  ub = SCIPvarGetUbGlobal(var);
8802 
8803  if(vbtype == SCIP_BOUNDTYPE_LOWER)
8804  {
8805  if( vbcoef > 0.0 )
8806  {
8807  assert(SCIPsetIsGE(set, lb, lb * vbcoef + vbconstant) );
8808  assert(SCIPsetIsGE(set, ub, ub * vbcoef + vbconstant) );
8809  }
8810  else
8811  {
8812  assert(SCIPsetIsGE(set, lb, ub * vbcoef + vbconstant) );
8813  assert(SCIPsetIsGE(set, ub, lb * vbcoef + vbconstant) );
8814  }
8815  }
8816  else
8817  {
8818  assert(vbtype == SCIP_BOUNDTYPE_UPPER);
8819  if( vbcoef > 0.0 )
8820  {
8821  assert(SCIPsetIsLE(set, lb, lb * vbcoef + vbconstant) );
8822  assert(SCIPsetIsLE(set, ub, ub * vbcoef + vbconstant) );
8823  }
8824  else
8825  {
8826  assert(SCIPsetIsLE(set, lb, ub * vbcoef + vbconstant) );
8827  assert(SCIPsetIsLE(set, ub, lb * vbcoef + vbconstant) );
8828  }
8829  }
8830 #endif
8831  SCIPdebugMessage("redundant variable bound: <%s> %s %g<%s> %+g\n",
8832  SCIPvarGetName(var), vbtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", vbcoef, SCIPvarGetName(vbvar), vbconstant);
8833 
8834  return SCIP_OKAY;
8835  }
8836 
8837  SCIPdebugMessage("adding variable bound: <%s> %s %g<%s> %+g\n",
8838  SCIPvarGetName(var), vbtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", vbcoef, SCIPvarGetName(vbvar), vbconstant);
8839 
8840  /* check variable bound on debugging solution */
8841  SCIP_CALL( SCIPdebugCheckVbound(set, var, vbtype, vbvar, vbcoef, vbconstant) ); /*lint !e506 !e774*/
8842 
8843  /* perform the addition */
8844  if( vbtype == SCIP_BOUNDTYPE_LOWER )
8845  {
8846  SCIP_CALL( SCIPvboundsAdd(&var->vlbs, blkmem, set, vbtype, vbvar, vbcoef, vbconstant, &added) );
8847  }
8848  else
8849  {
8850  SCIP_CALL( SCIPvboundsAdd(&var->vubs, blkmem, set, vbtype, vbvar, vbcoef, vbconstant, &added) );
8851  }
8852  var->closestvblpcount = -1;
8853 
8854  if( added )
8855  {
8856  /* issue IMPLADDED event */
8857  SCIP_CALL( varEventImplAdded(var, blkmem, set, eventqueue) );
8858  }
8859 
8860  return SCIP_OKAY;
8861 }
8862 
8863 /** checks whether the given implication is redundant or infeasible w.r.t. the implied variables global bounds */
8864 static
8866  SCIP_SET* set, /**< global SCIP settings */
8867  SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
8868  SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
8869  SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
8870  SCIP_Bool* redundant, /**< pointer to store whether the implication is redundant */
8871  SCIP_Bool* infeasible /**< pointer to store whether the implication is infeasible */
8872  )
8873 {
8874  SCIP_Real impllb;
8875  SCIP_Real implub;
8876 
8877  assert(redundant != NULL);
8878  assert(infeasible != NULL);
8879 
8880  impllb = SCIPvarGetLbGlobal(implvar);
8881  implub = SCIPvarGetUbGlobal(implvar);
8882  if( impltype == SCIP_BOUNDTYPE_LOWER )
8883  {
8884  *infeasible = SCIPsetIsFeasGT(set, implbound, implub);
8885  *redundant = SCIPsetIsFeasLE(set, implbound, impllb);
8886  }
8887  else
8888  {
8889  *infeasible = SCIPsetIsFeasLT(set, implbound, impllb);
8890  *redundant = SCIPsetIsFeasGE(set, implbound, implub);
8891  }
8892 }
8893 
8894 /** applies the given implication, if it is not redundant */
8895 static
8897  BMS_BLKMEM* blkmem, /**< block memory */
8898  SCIP_SET* set, /**< global SCIP settings */
8899  SCIP_STAT* stat, /**< problem statistics */
8900  SCIP_PROB* transprob, /**< transformed problem */
8901  SCIP_PROB* origprob, /**< original problem */
8902  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
8903  SCIP_LP* lp, /**< current LP data */
8904  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
8905  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
8906  SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
8907  SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
8908  SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
8909  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
8910  int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
8911  )
8912 {
8913  SCIP_Real implub;
8914  SCIP_Real impllb;
8915 
8916  assert(infeasible != NULL);
8917 
8918  *infeasible = FALSE;
8919 
8920  implub = SCIPvarGetUbGlobal(implvar);
8921  impllb = SCIPvarGetLbGlobal(implvar);
8922  if( impltype == SCIP_BOUNDTYPE_LOWER )
8923  {
8924  if( SCIPsetIsFeasGT(set, implbound, implub) )
8925  {
8926  /* the implication produces a conflict: the problem is infeasible */
8927  *infeasible = TRUE;
8928  }
8929  else if( SCIPsetIsFeasGT(set, implbound, impllb) )
8930  {
8931  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
8932  * with the local bound, in this case we need to store the bound change as pending bound change
8933  */
8934  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
8935  {
8936  assert(tree != NULL);
8937  assert(transprob != NULL);
8938  assert(SCIPprobIsTransformed(transprob));
8939 
8940  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
8941  tree, lp, branchcand, eventqueue, implvar, implbound, SCIP_BOUNDTYPE_LOWER, FALSE) );
8942  }
8943  else
8944  {
8945  SCIP_CALL( SCIPvarChgLbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, implbound) );
8946  }
8947 
8948  if( nbdchgs != NULL )
8949  (*nbdchgs)++;
8950  }
8951  }
8952  else
8953  {
8954  if( SCIPsetIsFeasLT(set, implbound, impllb) )
8955  {
8956  /* the implication produces a conflict: the problem is infeasible */
8957  *infeasible = TRUE;
8958  }
8959  else if( SCIPsetIsFeasLT(set, implbound, implub) )
8960  {
8961  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
8962  * with the local bound, in this case we need to store the bound change as pending bound change
8963  */
8964  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
8965  {
8966  assert(tree != NULL);
8967  assert(transprob != NULL);
8968  assert(SCIPprobIsTransformed(transprob));
8969 
8970  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
8971  tree, lp, branchcand, eventqueue, implvar, implbound, SCIP_BOUNDTYPE_UPPER, FALSE) );
8972  }
8973  else
8974  {
8975  SCIP_CALL( SCIPvarChgUbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, implbound) );
8976  }
8977 
8978  if( nbdchgs != NULL )
8979  (*nbdchgs)++;
8980  }
8981  }
8982 
8983  return SCIP_OKAY;
8984 }
8985 
8986 /** actually performs the addition of an implication to the variable's implication arrays,
8987  * and adds the corresponding implication or variable bound to the implied variable;
8988  * if the implication is conflicting, the variable is fixed to the opposite value;
8989  * if the variable is already fixed to the given value, the implication is performed immediately;
8990  * if the implication is redundant with respect to the variables' global bounds, it is ignored
8991  */
8992 static
8994  SCIP_VAR* var, /**< problem variable */
8995  BMS_BLKMEM* blkmem, /**< block memory */
8996  SCIP_SET* set, /**< global SCIP settings */
8997  SCIP_STAT* stat, /**< problem statistics */
8998  SCIP_PROB* transprob, /**< transformed problem */
8999  SCIP_PROB* origprob, /**< original problem */
9000  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9001  SCIP_LP* lp, /**< current LP data */
9002  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9003  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9004  SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9005  SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9006  SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9007  SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
9008  SCIP_Bool isshortcut, /**< is the implication a shortcut, i.e., added as part of the transitive closure of another implication? */
9009  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9010  int* nbdchgs, /**< pointer to count the number of performed bound changes, or NULL */
9011  SCIP_Bool* added /**< pointer to store whether an implication was added */
9012  )
9013 {
9014  SCIP_Bool redundant;
9015  SCIP_Bool conflict;
9016 
9017  assert(var != NULL);
9018  assert(SCIPvarIsActive(var));
9020  assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
9021  assert(SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED);
9022  assert(infeasible != NULL);
9023  assert(added != NULL);
9024 
9025  /* check implication on debugging solution */
9026  SCIP_CALL( SCIPdebugCheckImplic(set, var, varfixing, implvar, impltype, implbound) ); /*lint !e506 !e774*/
9027 
9028  *infeasible = FALSE;
9029  *added = FALSE;
9030 
9031  /* check, if the implication is redundant or infeasible */
9032  checkImplic(set, implvar, impltype, implbound, &redundant, &conflict);
9033  assert(!redundant || !conflict);
9034  if( redundant )
9035  return SCIP_OKAY;
9036 
9037  if( var == implvar )
9038  {
9039  /* variable implies itself: x == varfixing => x == (impltype == SCIP_BOUNDTYPE_LOWER) */
9040  assert(SCIPsetIsEQ(set, implbound, 0.0) || SCIPsetIsEQ(set, implbound, 1.0));
9041  assert(SCIPsetIsEQ(set, implbound, 0.0) == (impltype == SCIP_BOUNDTYPE_UPPER));
9042  assert(SCIPsetIsEQ(set, implbound, 1.0) == (impltype == SCIP_BOUNDTYPE_LOWER));
9043  conflict = conflict || ((varfixing == TRUE) == (impltype == SCIP_BOUNDTYPE_UPPER));
9044  if( !conflict )
9045  return SCIP_OKAY;
9046  }
9047 
9048  /* check, if the variable is already fixed */
9049  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
9050  {
9051  /* if the variable is fixed to the given value, perform the implication; otherwise, ignore the implication */
9052  if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
9053  {
9054  SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue,
9055  implvar, impltype, implbound, infeasible, nbdchgs) );
9056  }
9057  return SCIP_OKAY;
9058  }
9059 
9060  assert((impltype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, implbound, SCIPvarGetLbGlobal(implvar)))
9061  || (impltype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, implbound, SCIPvarGetUbGlobal(implvar))));
9062 
9063  if( !conflict )
9064  {
9065  assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9066 
9067  /* add implication x == 0/1 -> y <= b / y >= b to the implications list of x */
9068  SCIPdebugMessage("adding implication: <%s> == %u ==> <%s> %s %g\n",
9069  SCIPvarGetName(var), varfixing,
9070  SCIPvarGetName(implvar), impltype == SCIP_BOUNDTYPE_UPPER ? "<=" : ">=", implbound);
9071  SCIP_CALL( SCIPimplicsAdd(&var->implics, blkmem, set, stat, varfixing, implvar, impltype, implbound,
9072  isshortcut, &conflict, added) );
9073  }
9074  assert(!conflict || !(*added));
9075 
9076  /* on conflict, fix the variable to the opposite value */
9077  if( conflict )
9078  {
9079  SCIPdebugMessage(" -> implication yields a conflict: fix <%s> == %d\n", SCIPvarGetName(var), !varfixing);
9080 
9081  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9082  * with the local bound, in this case we need to store the bound change as pending bound change
9083  */
9084  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9085  {
9086  assert(tree != NULL);
9087  assert(transprob != NULL);
9088  assert(SCIPprobIsTransformed(transprob));
9089 
9090  if( varfixing )
9091  {
9092  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9093  tree, lp, branchcand, eventqueue, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) );
9094  }
9095  else
9096  {
9097  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9098  tree, lp, branchcand, eventqueue, var, 1.0, SCIP_BOUNDTYPE_LOWER, FALSE) );
9099  }
9100  }
9101  else
9102  {
9103  if( varfixing )
9104  {
9105  SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, 0.0) );
9106  }
9107  else
9108  {
9109  SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, 1.0) );
9110  }
9111  }
9112  if( nbdchgs != NULL )
9113  (*nbdchgs)++;
9114 
9115  return SCIP_OKAY;
9116  }
9117  else if( *added )
9118  {
9119  /* issue IMPLADDED event */
9120  SCIP_CALL( varEventImplAdded(var, blkmem, set, eventqueue) );
9121  }
9122  else
9123  {
9124  /* the implication was redundant: the inverse is also redundant */
9125  return SCIP_OKAY;
9126  }
9127 
9128  assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9129 
9130  /* check, whether implied variable is binary */
9131  if( SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY )
9132  {
9133  SCIP_Bool inverseadded;
9134 
9135  assert(SCIPsetIsEQ(set, implbound, 0.0) == (impltype == SCIP_BOUNDTYPE_UPPER));
9136  assert(SCIPsetIsEQ(set, implbound, 1.0) == (impltype == SCIP_BOUNDTYPE_LOWER));
9137 
9138  /* add inverse implication y == 0/1 -> x == 0/1 to the implications list of y:
9139  * x == 0 -> y == 0 <-> y == 1 -> x == 1
9140  * x == 1 -> y == 0 <-> y == 1 -> x == 0
9141  * x == 0 -> y == 1 <-> y == 0 -> x == 1
9142  * x == 1 -> y == 1 <-> y == 0 -> x == 0
9143  */
9144  SCIPdebugMessage("adding inverse implication: <%s> == %d ==> <%s> == %d\n",
9145  SCIPvarGetName(implvar), (impltype == SCIP_BOUNDTYPE_UPPER), SCIPvarGetName(var), !varfixing);
9146  SCIP_CALL( SCIPimplicsAdd(&implvar->implics, blkmem, set, stat,
9147  (impltype == SCIP_BOUNDTYPE_UPPER), var, varfixing ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER,
9148  varfixing ? 0.0 : 1.0, isshortcut, &conflict, &inverseadded) );
9149  assert(inverseadded == !conflict); /* if there is no conflict, the implication must not be redundant */
9150 
9151  /* on conflict, fix the variable to the opposite value */
9152  if( conflict )
9153  {
9154  SCIPdebugMessage(" -> implication yields a conflict: fix <%s> == %d\n",
9155  SCIPvarGetName(implvar), impltype == SCIP_BOUNDTYPE_LOWER);
9156 
9157  /* remove the original implication (which is now redundant due to the fixing of the implvar) */
9158  SCIPdebugMessage(" -> deleting implication: <%s> == %u ==> <%s> %s %g\n",
9159  SCIPvarGetName(var), varfixing, SCIPvarGetName(implvar), impltype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
9160  implbound);
9161  SCIP_CALL( SCIPimplicsDel(&var->implics, blkmem, set, varfixing, implvar, impltype) );
9162 
9163  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9164  * with the local bound, in this case we need to store the bound change as pending bound change
9165  */
9166  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9167  {
9168  assert(tree != NULL);
9169  assert(transprob != NULL);
9170  assert(SCIPprobIsTransformed(transprob));
9171 
9172  /* fix implvar */
9173  if( impltype == SCIP_BOUNDTYPE_UPPER )
9174  {
9175  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9176  tree, lp, branchcand, eventqueue, implvar, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) );
9177  }
9178  else
9179  {
9180  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9181  tree, lp, branchcand, eventqueue, implvar, 1.0, SCIP_BOUNDTYPE_LOWER, FALSE) );
9182  }
9183  }
9184  else
9185  {
9186  /* fix implvar */
9187  if( impltype == SCIP_BOUNDTYPE_UPPER )
9188  {
9189  SCIP_CALL( SCIPvarChgUbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, 0.0) );
9190  }
9191  else
9192  {
9193  SCIP_CALL( SCIPvarChgLbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, 1.0) );
9194  }
9195  }
9196 
9197  if( nbdchgs != NULL )
9198  (*nbdchgs)++;
9199  }
9200  else if( inverseadded )
9201  {
9202  /* issue IMPLADDED event */
9203  SCIP_CALL( varEventImplAdded(implvar, blkmem, set, eventqueue) );
9204  }
9205  }
9206  else
9207  {
9208  SCIP_Real lb;
9209  SCIP_Real ub;
9210 
9211  /* add inverse variable bound to the variable bounds of y with global bounds y \in [lb,ub]:
9212  * x == 0 -> y <= b <-> y <= (ub - b)*x + b
9213  * x == 1 -> y <= b <-> y <= (b - ub)*x + ub
9214  * x == 0 -> y >= b <-> y >= (lb - b)*x + b
9215  * x == 1 -> y >= b <-> y >= (b - lb)*x + lb
9216  * for numerical reasons, ignore variable bounds with large absolute coefficient
9217  */
9218  lb = SCIPvarGetLbGlobal(implvar);
9219  ub = SCIPvarGetUbGlobal(implvar);
9220  if( impltype == SCIP_BOUNDTYPE_UPPER )
9221  {
9222  if( REALABS(implbound - ub) <= MAXABSVBCOEF )
9223  {
9224  SCIP_CALL( varAddVbound(implvar, blkmem, set, eventqueue, SCIP_BOUNDTYPE_UPPER, var,
9225  varfixing ? implbound - ub : ub - implbound, varfixing ? ub : implbound) );
9226  }
9227  }
9228  else
9229  {
9230  if( REALABS(implbound - lb) <= MAXABSVBCOEF )
9231  {
9232  SCIP_CALL( varAddVbound(implvar, blkmem, set, eventqueue, SCIP_BOUNDTYPE_LOWER, var,
9233  varfixing ? implbound - lb : lb - implbound, varfixing ? lb : implbound) );
9234  }
9235  }
9236  }
9237 
9238  return SCIP_OKAY;
9239 }
9240 
9241 /** adds transitive closure for binary implication x = a -> y = b */
9242 static
9244  SCIP_VAR* var, /**< problem variable */
9245  BMS_BLKMEM* blkmem, /**< block memory */
9246  SCIP_SET* set, /**< global SCIP settings */
9247  SCIP_STAT* stat, /**< problem statistics */
9248  SCIP_PROB* transprob, /**< transformed problem */
9249  SCIP_PROB* origprob, /**< original problem */
9250  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9251  SCIP_LP* lp, /**< current LP data */
9252  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9253  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9254  SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9255  SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9256  SCIP_Bool implvarfixing, /**< fixing b in implication */
9257  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9258  int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
9259  )
9260 {
9261  SCIP_VAR** implvars;
9262  SCIP_BOUNDTYPE* impltypes;
9263  SCIP_Real* implbounds;
9264  int nimpls;
9265  int i;
9266 
9267  *infeasible = FALSE;
9268 
9269  /* binary variable: implications of implvar */
9270  nimpls = SCIPimplicsGetNImpls(implvar->implics, implvarfixing);
9271  implvars = SCIPimplicsGetVars(implvar->implics, implvarfixing);
9272  impltypes = SCIPimplicsGetTypes(implvar->implics, implvarfixing);
9273  implbounds = SCIPimplicsGetBounds(implvar->implics, implvarfixing);
9274 
9275  /* if variable has too many implications, the implication graph may become too dense */
9276  if( nimpls > MAXIMPLSCLOSURE )
9277  return SCIP_OKAY;
9278 
9279  /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9280  * implvars[i] is fixed, s.t. the implication y == varfixing -> z <= b / z >= b is deleted; this affects the
9281  * array over which we currently iterate; the only thing that can happen, is that elements of the array are
9282  * deleted; in this case, the subsequent elements are moved to the front; if we iterate from back to front, the
9283  * only thing that can happen is that we add the same implication twice - this does no harm
9284  */
9285  i = nimpls-1;
9286  while ( i >= 0 && !(*infeasible) )
9287  {
9288  SCIP_Bool added;
9289 
9290  assert(implvars[i] != implvar);
9291 
9292  /* we have x == varfixing -> y == implvarfixing -> z <= b / z >= b:
9293  * add implication x == varfixing -> z <= b / z >= b to the implications list of x
9294  */
9295  if( SCIPvarIsActive(implvars[i]) )
9296  {
9297  SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue,
9298  varfixing, implvars[i], impltypes[i], implbounds[i], TRUE, infeasible, nbdchgs, &added) );
9299  assert(SCIPimplicsGetNImpls(implvar->implics, implvarfixing) <= nimpls);
9300  nimpls = SCIPimplicsGetNImpls(implvar->implics, implvarfixing);
9301  i = MIN(i, nimpls); /* some elements from the array could have been removed */
9302  }
9303  --i;
9304  }
9305 
9306  return SCIP_OKAY;
9307 }
9308 
9309 /** adds given implication to the variable's implication list, and adds all implications directly implied by this
9310  * implication to the variable's implication list;
9311  * if the implication is conflicting, the variable is fixed to the opposite value;
9312  * if the variable is already fixed to the given value, the implication is performed immediately;
9313  * if the implication is redundant with respect to the variables' global bounds, it is ignored
9314  */
9315 static
9317  SCIP_VAR* var, /**< problem variable */
9318  BMS_BLKMEM* blkmem, /**< block memory */
9319  SCIP_SET* set, /**< global SCIP settings */
9320  SCIP_STAT* stat, /**< problem statistics */
9321  SCIP_PROB* transprob, /**< transformed problem */
9322  SCIP_PROB* origprob, /**< original problem */
9323  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9324  SCIP_LP* lp, /**< current LP data */
9325  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9326  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9327  SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9328  SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9329  SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9330  SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
9331  SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
9332  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9333  int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
9334  )
9335 {
9336  SCIP_Bool added;
9337 
9338  assert(var != NULL);
9339  assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
9340  assert(SCIPvarIsActive(var));
9341  assert(implvar != NULL);
9342  assert(SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED);
9343  assert(infeasible != NULL);
9344 
9345  /* add implication x == varfixing -> y <= b / y >= b to the implications list of x */
9346  SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue,
9347  varfixing, implvar, impltype, implbound, FALSE, infeasible, nbdchgs, &added) );
9348  if( *infeasible || var == implvar || !transitive || !added )
9349  return SCIP_OKAY;
9350 
9351  assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9352 
9353  /* add transitive closure */
9354  if( SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY )
9355  {
9356  SCIP_Bool implvarfixing;
9357 
9358  implvarfixing = (impltype == SCIP_BOUNDTYPE_LOWER);
9359 
9360  /* binary variable: implications of implvar */
9361  SCIP_CALL( varAddTransitiveBinaryClosureImplic(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand,
9362  eventqueue, varfixing, implvar, implvarfixing, infeasible, nbdchgs) );
9363 
9364  /* inverse implication */
9365  if( !(*infeasible) )
9366  {
9367  SCIP_CALL( varAddTransitiveBinaryClosureImplic(implvar, blkmem, set, stat, transprob, origprob, tree, lp,
9368  branchcand, eventqueue, !implvarfixing, var, !varfixing, infeasible, nbdchgs) );
9369  }
9370  }
9371  else
9372  {
9373  /* non-binary variable: variable lower bounds of implvar */
9374  if( impltype == SCIP_BOUNDTYPE_UPPER && implvar->vlbs != NULL )
9375  {
9376  SCIP_VAR** vlbvars;
9377  SCIP_Real* vlbcoefs;
9378  SCIP_Real* vlbconstants;
9379  int nvlbvars;
9380  int i;
9381 
9382  nvlbvars = SCIPvboundsGetNVbds(implvar->vlbs);
9383  vlbvars = SCIPvboundsGetVars(implvar->vlbs);
9384  vlbcoefs = SCIPvboundsGetCoefs(implvar->vlbs);
9385  vlbconstants = SCIPvboundsGetConstants(implvar->vlbs);
9386 
9387  /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9388  * vlbvars[i] is fixed, s.t. the variable bound is deleted; this affects the array over which we currently
9389  * iterate; the only thing that can happen, is that elements of the array are deleted; in this case, the
9390  * subsequent elements are moved to the front; if we iterate from back to front, the only thing that can happen
9391  * is that we add the same implication twice - this does no harm
9392  */
9393  i = nvlbvars-1;
9394  while ( i >= 0 && !(*infeasible) )
9395  {
9396  assert(vlbvars[i] != implvar);
9397  assert(!SCIPsetIsZero(set, vlbcoefs[i]));
9398 
9399  /* we have x == varfixing -> y <= b and y >= c*z + d:
9400  * c > 0: add implication x == varfixing -> z <= (b-d)/c to the implications list of x
9401  * c < 0: add implication x == varfixing -> z >= (b-d)/c to the implications list of x
9402  *
9403  * @note during an aggregation the aggregated variable "aggrvar" (the one which will have the status
9404  * SCIP_VARSTATUS_AGGREGATED afterwards) copies its variable lower and uppers bounds to the
9405  * aggregation variable (the one which will stay active);
9406  *
9407  * W.l.o.g. we consider the variable upper bounds for now. Let "vubvar" be a variable upper bound of
9408  * the aggregated variable "aggvar"; During that copying of that variable upper bound variable
9409  * "vubvar" the variable lower and upper bounds of this variable "vubvar" are also considered; note
9410  * that the "aggvar" can be a variable lower bound variable of the variable "vubvar"; Due to that
9411  * situation it can happen that we reach that code place where "vlbvars[i] == aggvar". In particular
9412  * the "aggvar" has already the variable status SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED
9413  * but is still active since the aggregation is not finished yet (in SCIPvarAggregate()); therefore we
9414  * have to explicitly check that the active variable has not a variable status
9415  * SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED;
9416  */
9417  if( SCIPvarIsActive(vlbvars[i]) && SCIPvarGetStatus(vlbvars[i]) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(vlbvars[i]) != SCIP_VARSTATUS_NEGATED )
9418  {
9419  SCIP_Real vbimplbound;
9420 
9421  vbimplbound = (implbound - vlbconstants[i])/vlbcoefs[i];
9422  if( vlbcoefs[i] >= 0.0 )
9423  {
9424  vbimplbound = adjustedUb(set, SCIPvarGetType(vlbvars[i]), vbimplbound);
9425  SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue,
9426  varfixing, vlbvars[i], SCIP_BOUNDTYPE_UPPER, vbimplbound, TRUE, infeasible, nbdchgs, &added) );
9427  }
9428  else
9429  {
9430  vbimplbound = adjustedLb(set, SCIPvarGetType(vlbvars[i]), vbimplbound);
9431  SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue,
9432  varfixing, vlbvars[i], SCIP_BOUNDTYPE_LOWER, vbimplbound, TRUE, infeasible, nbdchgs, &added) );
9433  }
9434  nvlbvars = SCIPvboundsGetNVbds(implvar->vlbs);
9435  i = MIN(i, nvlbvars); /* some elements from the array could have been removed */
9436  }
9437  --i;
9438  }
9439  }
9440 
9441  /* non-binary variable: variable upper bounds of implvar */
9442  if( impltype == SCIP_BOUNDTYPE_LOWER && implvar->vubs != NULL )
9443  {
9444  SCIP_VAR** vubvars;
9445  SCIP_Real* vubcoefs;
9446  SCIP_Real* vubconstants;
9447  int nvubvars;
9448  int i;
9449 
9450  nvubvars = SCIPvboundsGetNVbds(implvar->vubs);
9451  vubvars = SCIPvboundsGetVars(implvar->vubs);
9452  vubcoefs = SCIPvboundsGetCoefs(implvar->vubs);
9453  vubconstants = SCIPvboundsGetConstants(implvar->vubs);
9454 
9455  /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9456  * vubvars[i] is fixed, s.t. the variable bound is deleted; this affects the array over which we currently
9457  * iterate; the only thing that can happen, is that elements of the array are deleted; in this case, the
9458  * subsequent elements are moved to the front; if we iterate from back to front, the only thing that can happen
9459  * is that we add the same implication twice - this does no harm
9460  */
9461  i = nvubvars-1;
9462  while ( i >= 0 && !(*infeasible) )
9463  {
9464  assert(vubvars[i] != implvar);
9465  assert(!SCIPsetIsZero(set, vubcoefs[i]));
9466 
9467  /* we have x == varfixing -> y >= b and y <= c*z + d:
9468  * c > 0: add implication x == varfixing -> z >= (b-d)/c to the implications list of x
9469  * c < 0: add implication x == varfixing -> z <= (b-d)/c to the implications list of x
9470  *
9471  * @note during an aggregation the aggregated variable "aggrvar" (the one which will have the status
9472  * SCIP_VARSTATUS_AGGREGATED afterwards) copies its variable lower and uppers bounds to the
9473  * aggregation variable (the one which will stay active);
9474  *
9475  * W.l.o.g. we consider the variable lower bounds for now. Let "vlbvar" be a variable lower bound of
9476  * the aggregated variable "aggvar"; During that copying of that variable lower bound variable
9477  * "vlbvar" the variable lower and upper bounds of this variable "vlbvar" are also considered; note
9478  * that the "aggvar" can be a variable upper bound variable of the variable "vlbvar"; Due to that
9479  * situation it can happen that we reach that code place where "vubvars[i] == aggvar". In particular
9480  * the "aggvar" has already the variable status SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED
9481  * but is still active since the aggregation is not finished yet (in SCIPvarAggregate()); therefore we
9482  * have to explicitly check that the active variable has not a variable status
9483  * SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED;
9484  */
9485  if( SCIPvarIsActive(vubvars[i]) && SCIPvarGetStatus(vubvars[i]) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(vubvars[i]) != SCIP_VARSTATUS_NEGATED )
9486  {
9487  SCIP_Real vbimplbound;
9488 
9489  vbimplbound = (implbound - vubconstants[i])/vubcoefs[i];
9490  if( vubcoefs[i] >= 0.0 )
9491  {
9492  vbimplbound = adjustedLb(set, SCIPvarGetType(vubvars[i]), vbimplbound);
9493  SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue,
9494  varfixing, vubvars[i], SCIP_BOUNDTYPE_LOWER, vbimplbound, TRUE, infeasible, nbdchgs, &added) );
9495  }
9496  else
9497  {
9498  vbimplbound = adjustedUb(set, SCIPvarGetType(vubvars[i]), vbimplbound);
9499  SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue,
9500  varfixing, vubvars[i], SCIP_BOUNDTYPE_UPPER, vbimplbound, TRUE, infeasible, nbdchgs, &added) );
9501  }
9502  nvubvars = SCIPvboundsGetNVbds(implvar->vubs);
9503  i = MIN(i, nvubvars); /* some elements from the array could have been removed */
9504  }
9505  --i;
9506  }
9507  }
9508  }
9509 
9510  return SCIP_OKAY;
9511 }
9512 
9513 /** informs variable x about a globally valid variable lower bound x >= b*z + d with integer variable z;
9514  * if z is binary, the corresponding valid implication for z is also added;
9515  * improves the global bounds of the variable and the vlb variable if possible
9516  */
9518  SCIP_VAR* var, /**< problem variable */
9519  BMS_BLKMEM* blkmem, /**< block memory */
9520  SCIP_SET* set, /**< global SCIP settings */
9521  SCIP_STAT* stat, /**< problem statistics */
9522  SCIP_PROB* transprob, /**< transformed problem */
9523  SCIP_PROB* origprob, /**< original problem */
9524  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9525  SCIP_LP* lp, /**< current LP data */
9526  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
9527  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9528  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9529  SCIP_VAR* vlbvar, /**< variable z in x >= b*z + d */
9530  SCIP_Real vlbcoef, /**< coefficient b in x >= b*z + d */
9531  SCIP_Real vlbconstant, /**< constant d in x >= b*z + d */
9532  SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
9533  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9534  int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
9535  )
9536 {
9537  assert(var != NULL);
9538  assert(set != NULL);
9539  assert(var->scip == set->scip);
9540  assert(SCIPvarGetType(vlbvar) != SCIP_VARTYPE_CONTINUOUS);
9541  assert(infeasible != NULL);
9542 
9543  SCIPdebugMessage("adding variable lower bound <%s> >= %g<%s> + %g\n",
9544  SCIPvarGetName(var), vlbcoef, SCIPvarGetName(vlbvar), vlbconstant);
9545 
9546  *infeasible = FALSE;
9547  if( nbdchgs != NULL )
9548  *nbdchgs = 0;
9549 
9550  switch( SCIPvarGetStatus(var) )
9551  {
9553  assert(var->data.original.transvar != NULL);
9554  SCIP_CALL( SCIPvarAddVlb(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, lp,
9555  cliquetable, branchcand, eventqueue, vlbvar, vlbcoef, vlbconstant, transitive, infeasible, nbdchgs) );
9556  break;
9557 
9558  case SCIP_VARSTATUS_COLUMN:
9559  case SCIP_VARSTATUS_LOOSE:
9560  case SCIP_VARSTATUS_FIXED:
9561  /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */
9562  SCIP_CALL( SCIPvarGetProbvarSum(&vlbvar, set, &vlbcoef, &vlbconstant) );
9563  SCIPdebugMessage(" -> transformed to variable lower bound <%s> >= %g<%s> + %g\n",
9564  SCIPvarGetName(var), vlbcoef, SCIPvarGetName(vlbvar), vlbconstant);
9565 
9566  /* if the vlb coefficient is zero, just update the lower bound of the variable */
9567  if( SCIPsetIsZero(set, vlbcoef) )
9568  {
9569  if( SCIPsetIsFeasGT(set, vlbconstant, SCIPvarGetUbGlobal(var)) )
9570  *infeasible = TRUE;
9571  else if( SCIPsetIsFeasGT(set, vlbconstant, SCIPvarGetLbGlobal(var)) )
9572  {
9573  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9574  * with the local bound, in this case we need to store the bound change as pending bound change
9575  */
9576  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9577  {
9578  assert(tree != NULL);
9579  assert(transprob != NULL);
9580  assert(SCIPprobIsTransformed(transprob));
9581 
9582  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9583  tree, lp, branchcand, eventqueue, var, vlbconstant, SCIP_BOUNDTYPE_LOWER, FALSE) );
9584  }
9585  else
9586  {
9587  SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, vlbconstant) );
9588  }
9589 
9590  if( nbdchgs != NULL )
9591  (*nbdchgs)++;
9592  }
9593  }
9594  else if( SCIPvarIsActive(vlbvar) )
9595  {
9596  SCIP_Real xlb;
9597  SCIP_Real xub;
9598  SCIP_Real zlb;
9599  SCIP_Real zub;
9600  SCIP_Real minvlb;
9601  SCIP_Real maxvlb;
9602 
9604  assert(vlbcoef != 0.0);
9605 
9606  minvlb = -SCIPsetInfinity(set);
9607  maxvlb = -SCIPsetInfinity(set);
9608 
9609  xlb = SCIPvarGetLbGlobal(var);
9610  xub = SCIPvarGetUbGlobal(var);
9611  zlb = SCIPvarGetLbGlobal(vlbvar);
9612  zub = SCIPvarGetUbGlobal(vlbvar);
9613 
9614  /* improve global bounds of vlb variable, and calculate minimal and maximal value of variable bound */
9615  if( vlbcoef >= 0.0 )
9616  {
9617  SCIP_Real newzub;
9618 
9619  if( !SCIPsetIsInfinity(set, xub) )
9620  {
9621  /* x >= b*z + d -> z <= (x-d)/b */
9622  newzub = (xub - vlbconstant)/vlbcoef;
9623  if( SCIPsetIsFeasLT(set, newzub, zlb) )
9624  {
9625  *infeasible = TRUE;
9626  return SCIP_OKAY;
9627  }
9628  if( SCIPsetIsFeasLT(set, newzub, zub) )
9629  {
9630  /* bound might be adjusted due to integrality condition */
9631  newzub = adjustedUb(set, SCIPvarGetType(vlbvar), newzub);
9632 
9633  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9634  * with the local bound, in this case we need to store the bound change as pending bound change
9635  */
9636  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9637  {
9638  assert(tree != NULL);
9639  assert(transprob != NULL);
9640  assert(SCIPprobIsTransformed(transprob));
9641 
9642  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9643  tree, lp, branchcand, eventqueue, vlbvar, newzub, SCIP_BOUNDTYPE_UPPER, FALSE) );
9644  }
9645  else
9646  {
9647  SCIP_CALL( SCIPvarChgUbGlobal(vlbvar, blkmem, set, stat, lp, branchcand, eventqueue, newzub) );
9648  }
9649  zub = newzub;
9650 
9651  if( nbdchgs != NULL )
9652  (*nbdchgs)++;
9653  }
9654  maxvlb = vlbcoef * zub + vlbconstant;
9655  if( !SCIPsetIsInfinity(set, -zlb) )
9656  minvlb = vlbcoef * zlb + vlbconstant;
9657  }
9658  else
9659  {
9660  if( !SCIPsetIsInfinity(set, zub) )
9661  maxvlb = vlbcoef * zub + vlbconstant;
9662  if( !SCIPsetIsInfinity(set, -zlb) )
9663  minvlb = vlbcoef * zlb + vlbconstant;
9664  }
9665  }
9666  else
9667  {
9668  SCIP_Real newzlb;
9669 
9670  if( !SCIPsetIsInfinity(set, xub) )
9671  {
9672  /* x >= b*z + d -> z >= (x-d)/b */
9673  newzlb = (xub - vlbconstant)/vlbcoef;
9674  if( SCIPsetIsFeasGT(set, newzlb, zub) )
9675  {
9676  *infeasible = TRUE;
9677  return SCIP_OKAY;
9678  }
9679  if( SCIPsetIsFeasGT(set, newzlb, zlb) )
9680  {
9681  /* bound might be adjusted due to integrality condition */
9682  newzlb = adjustedLb(set, SCIPvarGetType(vlbvar), newzlb);
9683 
9684  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9685  * with the local bound, in this case we need to store the bound change as pending bound change
9686  */
9687  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9688  {
9689  assert(tree != NULL);
9690  assert(transprob != NULL);
9691  assert(SCIPprobIsTransformed(transprob));
9692 
9693  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9694  tree, lp, branchcand, eventqueue, vlbvar, newzlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
9695  }
9696  else
9697  {
9698  SCIP_CALL( SCIPvarChgLbGlobal(vlbvar, blkmem, set, stat, lp, branchcand, eventqueue, newzlb) );
9699  }
9700  zlb = newzlb;
9701 
9702  if( nbdchgs != NULL )
9703  (*nbdchgs)++;
9704  }
9705  maxvlb = vlbcoef * zlb + vlbconstant;
9706  if( !SCIPsetIsInfinity(set, zub) )
9707  minvlb = vlbcoef * zub + vlbconstant;
9708  }
9709  else
9710  {
9711  if( !SCIPsetIsInfinity(set, -zlb) )
9712  maxvlb = vlbcoef * zlb + vlbconstant;
9713  if( !SCIPsetIsInfinity(set, zub) )
9714  minvlb = vlbcoef * zub + vlbconstant;
9715  }
9716  }
9717  if( maxvlb < minvlb )
9718  maxvlb = minvlb;
9719 
9720  /* adjust bounds due to integrality of variable */
9721  minvlb = adjustedLb(set, SCIPvarGetType(var), minvlb);
9722  maxvlb = adjustedLb(set, SCIPvarGetType(var), maxvlb);
9723 
9724  /* check bounds for feasibility */
9725  if( SCIPsetIsFeasGT(set, minvlb, xub) || (var == vlbvar && SCIPsetIsEQ(set, vlbcoef, 1.0) && !SCIPsetIsZero(set, vlbconstant)) )
9726  {
9727  *infeasible = TRUE;
9728  return SCIP_OKAY;
9729  }
9730  /* improve global lower bound of variable */
9731  if( SCIPsetIsFeasGT(set, minvlb, xlb) )
9732  {
9733  /* bound might be adjusted due to integrality condition */
9734  minvlb = adjustedLb(set, SCIPvarGetType(var), minvlb);
9735 
9736  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9737  * with the local bound, in this case we need to store the bound change as pending bound change
9738  */
9739  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9740  {
9741  assert(tree != NULL);
9742  assert(transprob != NULL);
9743  assert(SCIPprobIsTransformed(transprob));
9744 
9745  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9746  tree, lp, branchcand, eventqueue, var, minvlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
9747  }
9748  else
9749  {
9750  SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, minvlb) );
9751  }
9752  xlb = minvlb;
9753 
9754  if( nbdchgs != NULL )
9755  (*nbdchgs)++;
9756  }
9757  minvlb = xlb;
9758 
9759  /* improve variable bound for binary z by moving the variable's global bound to the vlb constant */
9760  if( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY )
9761  {
9762  /* b > 0: x >= (maxvlb - minvlb) * z + minvlb
9763  * b < 0: x >= (minvlb - maxvlb) * z + maxvlb
9764  */
9765 
9766  assert(!SCIPsetIsInfinity(set, -maxvlb) && !SCIPsetIsInfinity(set, -minvlb));
9767 
9768  if( vlbcoef >= 0.0 )
9769  {
9770  vlbcoef = maxvlb - minvlb;
9771  vlbconstant = minvlb;
9772  }
9773  else
9774  {
9775  vlbcoef = minvlb - maxvlb;
9776  vlbconstant = maxvlb;
9777  }
9778  }
9779 
9780  /* add variable bound to the variable bounds list */
9781  if( SCIPsetIsFeasGT(set, maxvlb, xlb) )
9782  {
9783  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED);
9784  assert(!SCIPsetIsZero(set, vlbcoef));
9785 
9786  /* if one of the variables is binary, add the corresponding implication to the variable's implication
9787  * list, thereby also adding the variable bound (or implication) to the other variable
9788  */
9789  if( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY )
9790  {
9791  /* add corresponding implication:
9792  * b > 0, x >= b*z + d <-> z == 1 -> x >= b+d
9793  * b < 0, x >= b*z + d <-> z == 0 -> x >= d
9794  */
9795  SCIP_CALL( varAddTransitiveImplic(vlbvar, blkmem, set, stat, transprob, origprob, tree, lp, branchcand,
9796  eventqueue, (vlbcoef >= 0.0), var, SCIP_BOUNDTYPE_LOWER, maxvlb, transitive, infeasible, nbdchgs) );
9797  }
9798  else if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
9799  {
9800  /* add corresponding implication:
9801  * b > 0, x >= b*z + d <-> x == 0 -> z <= -d/b
9802  * b < 0, x >= b*z + d <-> x == 0 -> z >= -d/b
9803  */
9804  SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand,
9805  eventqueue, FALSE, vlbvar, (vlbcoef >= 0.0 ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER),
9806  -vlbconstant/vlbcoef, transitive, infeasible, nbdchgs) );
9807  }
9808  else
9809  {
9810  SCIP_CALL( varAddVbound(var, blkmem, set, eventqueue, SCIP_BOUNDTYPE_LOWER, vlbvar, vlbcoef, vlbconstant) );
9811  }
9812  }
9813  }
9814  break;
9815 
9817  /* x = a*y + c: x >= b*z + d <=> a*y + c >= b*z + d <=> y >= b/a * z + (d-c)/a, if a > 0
9818  * y <= b/a * z + (d-c)/a, if a < 0
9819  */
9820  assert(var->data.aggregate.var != NULL);
9821  if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
9822  {
9823  /* a > 0 -> add variable lower bound */
9824  SCIP_CALL( SCIPvarAddVlb(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, lp,
9825  cliquetable, branchcand, eventqueue, vlbvar, vlbcoef/var->data.aggregate.scalar,
9826  (vlbconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
9827  }
9828  else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
9829  {
9830  /* a < 0 -> add variable upper bound */
9831  SCIP_CALL( SCIPvarAddVub(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, lp,
9832  cliquetable, branchcand, eventqueue, vlbvar, vlbcoef/var->data.aggregate.scalar,
9833  (vlbconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
9834  }
9835  else
9836  {
9837  SCIPerrorMessage("scalar is zero in aggregation\n");
9838  return SCIP_INVALIDDATA;
9839  }
9840  break;
9841 
9843  /* nothing to do here */
9844  break;
9845 
9847  /* x = offset - x': x >= b*z + d <=> offset - x' >= b*z + d <=> x' <= -b*z + (offset-d) */
9848  assert(var->negatedvar != NULL);
9850  assert(var->negatedvar->negatedvar == var);
9851  SCIP_CALL( SCIPvarAddVub(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, lp, cliquetable,
9852  branchcand, eventqueue, vlbvar, -vlbcoef, var->data.negate.constant - vlbconstant, transitive, infeasible,
9853  nbdchgs) );
9854  break;
9855 
9856  default:
9857  SCIPerrorMessage("unknown variable status\n");
9858  return SCIP_INVALIDDATA;
9859  }
9860 
9861  return SCIP_OKAY;
9862 }
9863 
9864 /** informs variable x about a globally valid variable upper bound x <= b*z + d with integer variable z;
9865  * if z is binary, the corresponding valid implication for z is also added;
9866  * updates the global bounds of the variable and the vub variable correspondingly
9867  */
9869  SCIP_VAR* var, /**< problem variable */
9870  BMS_BLKMEM* blkmem, /**< block memory */
9871  SCIP_SET* set, /**< global SCIP settings */
9872  SCIP_STAT* stat, /**< problem statistics */
9873  SCIP_PROB* transprob, /**< transformed problem */
9874  SCIP_PROB* origprob, /**< original problem */
9875  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9876  SCIP_LP* lp, /**< current LP data */
9877  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
9878  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9879  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9880  SCIP_VAR* vubvar, /**< variable z in x <= b*z + d */
9881  SCIP_Real vubcoef, /**< coefficient b in x <= b*z + d */
9882  SCIP_Real vubconstant, /**< constant d in x <= b*z + d */
9883  SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
9884  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9885  int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
9886  )
9887 {
9888  assert(var != NULL);
9889  assert(set != NULL);
9890  assert(var->scip == set->scip);
9891  assert(SCIPvarGetType(vubvar) != SCIP_VARTYPE_CONTINUOUS);
9892  assert(infeasible != NULL);
9893 
9894  SCIPdebugMessage("adding variable upper bound <%s> <= %g<%s> + %g\n",
9895  SCIPvarGetName(var), vubcoef, SCIPvarGetName(vubvar), vubconstant);
9896 
9897  *infeasible = FALSE;
9898  if( nbdchgs != NULL )
9899  *nbdchgs = 0;
9900 
9901  switch( SCIPvarGetStatus(var) )
9902  {
9904  assert(var->data.original.transvar != NULL);
9905  SCIP_CALL( SCIPvarAddVub(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, lp,
9906  cliquetable, branchcand, eventqueue, vubvar, vubcoef, vubconstant, transitive, infeasible, nbdchgs) );
9907  break;
9908 
9909  case SCIP_VARSTATUS_COLUMN:
9910  case SCIP_VARSTATUS_LOOSE:
9911  case SCIP_VARSTATUS_FIXED:
9912  /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */
9913  SCIP_CALL( SCIPvarGetProbvarSum(&vubvar, set, &vubcoef, &vubconstant) );
9914  SCIPdebugMessage(" -> transformed to variable upper bound <%s> <= %g<%s> + %g\n",
9915  SCIPvarGetName(var), vubcoef, SCIPvarGetName(vubvar), vubconstant);
9916 
9917  /* if the vub coefficient is zero, just update the upper bound of the variable */
9918  if( SCIPsetIsZero(set, vubcoef) )
9919  {
9920  if( SCIPsetIsFeasLT(set, vubconstant, SCIPvarGetLbGlobal(var)) )
9921  *infeasible = TRUE;
9922  else if( SCIPsetIsFeasLT(set, vubconstant, SCIPvarGetUbGlobal(var)) )
9923  {
9924  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9925  * with the local bound, in this case we need to store the bound change as pending bound change
9926  */
9927  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9928  {
9929  assert(tree != NULL);
9930  assert(transprob != NULL);
9931  assert(SCIPprobIsTransformed(transprob));
9932 
9933  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9934  tree, lp, branchcand, eventqueue, var, vubconstant, SCIP_BOUNDTYPE_UPPER, FALSE) );
9935  }
9936  else
9937  {
9938  SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, vubconstant) );
9939  }
9940 
9941  if( nbdchgs != NULL )
9942  (*nbdchgs)++;
9943  }
9944  }
9945  else if( SCIPvarIsActive(vubvar) )
9946  {
9947  SCIP_Real xlb;
9948  SCIP_Real xub;
9949  SCIP_Real zlb;
9950  SCIP_Real zub;
9951  SCIP_Real minvub;
9952  SCIP_Real maxvub;
9953 
9955  assert(vubcoef != 0.0);
9956 
9957  minvub = SCIPsetInfinity(set);
9958  maxvub = SCIPsetInfinity(set);
9959 
9960  xlb = SCIPvarGetLbGlobal(var);
9961  xub = SCIPvarGetUbGlobal(var);
9962  zlb = SCIPvarGetLbGlobal(vubvar);
9963  zub = SCIPvarGetUbGlobal(vubvar);
9964 
9965  /* improve global bounds of vub variable, and calculate minimal and maximal value of variable bound */
9966  if( vubcoef >= 0.0 )
9967  {
9968  SCIP_Real newzlb;
9969 
9970  if( !SCIPsetIsInfinity(set, -xlb) )
9971  {
9972  /* x <= b*z + d -> z >= (x-d)/b */
9973  newzlb = (xlb - vubconstant)/vubcoef;
9974  if( SCIPsetIsFeasGT(set, newzlb, zub) )
9975  {
9976  *infeasible = TRUE;
9977  return SCIP_OKAY;
9978  }
9979  if( SCIPsetIsFeasGT(set, newzlb, zlb) )
9980  {
9981  /* bound might be adjusted due to integrality condition */
9982  newzlb = adjustedLb(set, SCIPvarGetType(vubvar), newzlb);
9983 
9984  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9985  * with the local bound, in this case we need to store the bound change as pending bound change
9986  */
9987  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9988  {
9989  assert(tree != NULL);
9990  assert(transprob != NULL);
9991  assert(SCIPprobIsTransformed(transprob));
9992 
9993  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9994  tree, lp, branchcand, eventqueue, vubvar, newzlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
9995  }
9996  else
9997  {
9998  SCIP_CALL( SCIPvarChgLbGlobal(vubvar, blkmem, set, stat, lp, branchcand, eventqueue, newzlb) );
9999  }
10000  zlb = newzlb;
10001 
10002  if( nbdchgs != NULL )
10003  (*nbdchgs)++;
10004  }
10005  minvub = vubcoef * zlb + vubconstant;
10006  if( !SCIPsetIsInfinity(set, zub) )
10007  maxvub = vubcoef * zub + vubconstant;
10008  }
10009  else
10010  {
10011  if( !SCIPsetIsInfinity(set, zub) )
10012  maxvub = vubcoef * zub + vubconstant;
10013  if( !SCIPsetIsInfinity(set, -zlb) )
10014  minvub = vubcoef * zlb + vubconstant;
10015  }
10016  }
10017  else
10018  {
10019  SCIP_Real newzub;
10020 
10021  if( !SCIPsetIsInfinity(set, -xlb) )
10022  {
10023  /* x <= b*z + d -> z <= (x-d)/b */
10024  newzub = (xlb - vubconstant)/vubcoef;
10025  if( SCIPsetIsFeasLT(set, newzub, zlb) )
10026  {
10027  *infeasible = TRUE;
10028  return SCIP_OKAY;
10029  }
10030  if( SCIPsetIsFeasLT(set, newzub, zub) )
10031  {
10032  /* bound might be adjusted due to integrality condition */
10033  newzub = adjustedUb(set, SCIPvarGetType(vubvar), newzub);
10034 
10035  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10036  * with the local bound, in this case we need to store the bound change as pending bound change
10037  */
10038  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10039  {
10040  assert(tree != NULL);
10041  assert(transprob != NULL);
10042  assert(SCIPprobIsTransformed(transprob));
10043 
10044  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10045  tree, lp, branchcand, eventqueue, vubvar, newzub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10046  }
10047  else
10048  {
10049  SCIP_CALL( SCIPvarChgUbGlobal(vubvar, blkmem, set, stat, lp, branchcand, eventqueue, newzub) );
10050  }
10051  zub = newzub;
10052 
10053  if( nbdchgs != NULL )
10054  (*nbdchgs)++;
10055  }
10056  minvub = vubcoef * zub + vubconstant;
10057  if( !SCIPsetIsInfinity(set, -zlb) )
10058  maxvub = vubcoef * zlb + vubconstant;
10059  }
10060  else
10061  {
10062  if( !SCIPsetIsInfinity(set, zub) )
10063  minvub = vubcoef * zub + vubconstant;
10064  if( !SCIPsetIsInfinity(set, -zlb) )
10065  maxvub = vubcoef * zlb + vubconstant;
10066  }
10067 
10068  }
10069  if( minvub > maxvub )
10070  minvub = maxvub;
10071 
10072  /* adjust bounds due to integrality of vub variable */
10073  minvub = adjustedUb(set, SCIPvarGetType(var), minvub);
10074  maxvub = adjustedUb(set, SCIPvarGetType(var), maxvub);
10075 
10076  /* check bounds for feasibility */
10077  if( SCIPsetIsFeasLT(set, maxvub, xlb) || (var == vubvar && SCIPsetIsEQ(set, vubcoef, 1.0) && !SCIPsetIsZero(set, vubconstant)) )
10078  {
10079  *infeasible = TRUE;
10080  return SCIP_OKAY;
10081  }
10082  /* improve global upper bound of variable */
10083  if( SCIPsetIsFeasLT(set, maxvub, xub) )
10084  {
10085  /* bound might be adjusted due to integrality condition */
10086  maxvub = adjustedUb(set, SCIPvarGetType(var), maxvub);
10087 
10088  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10089  * with the local bound, in this case we need to store the bound change as pending bound change
10090  */
10091  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10092  {
10093  assert(tree != NULL);
10094  assert(transprob != NULL);
10095  assert(SCIPprobIsTransformed(transprob));
10096 
10097  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10098  tree, lp, branchcand, eventqueue, var, maxvub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10099  }
10100  else
10101  {
10102  SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, maxvub) );
10103  }
10104  xub = maxvub;
10105 
10106  if( nbdchgs != NULL )
10107  (*nbdchgs)++;
10108  }
10109  maxvub = xub;
10110 
10111  /* improve variable bound for binary z by moving the variable's global bound to the vub constant */
10112  if( SCIPvarIsBinary(vubvar) )
10113  {
10114  /* b > 0: x <= (maxvub - minvub) * z + minvub
10115  * b < 0: x <= (minvub - maxvub) * z + maxvub
10116  */
10117 
10118  assert(!SCIPsetIsInfinity(set, maxvub) && !SCIPsetIsInfinity(set, minvub));
10119 
10120  if( vubcoef >= 0.0 )
10121  {
10122  vubcoef = maxvub - minvub;
10123  vubconstant = minvub;
10124  }
10125  else
10126  {
10127  vubcoef = minvub - maxvub;
10128  vubconstant = maxvub;
10129  }
10130  }
10131 
10132  /* add variable bound to the variable bounds list */
10133  if( SCIPsetIsFeasLT(set, minvub, xub) )
10134  {
10135  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED);
10136  assert(!SCIPsetIsZero(set, vubcoef));
10137 
10138  /* if one of the variables is binary, add the corresponding implication to the variable's implication
10139  * list, thereby also adding the variable bound (or implication) to the other variable
10140  */
10141  if( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY )
10142  {
10143  /* add corresponding implication:
10144  * b > 0, x <= b*z + d <-> z == 0 -> x <= d
10145  * b < 0, x <= b*z + d <-> z == 1 -> x <= b+d
10146  */
10147  SCIP_CALL( varAddTransitiveImplic(vubvar, blkmem, set, stat, transprob, origprob, tree, lp, branchcand,
10148  eventqueue, (vubcoef < 0.0), var, SCIP_BOUNDTYPE_UPPER, minvub, transitive, infeasible, nbdchgs) );
10149  }
10150  else if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
10151  {
10152  /* add corresponding implication:
10153  * b > 0, x <= b*z + d <-> x == 1 -> z >= (1-d)/b
10154  * b < 0, x <= b*z + d <-> x == 1 -> z <= (1-d)/b
10155  */
10156  SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand,
10157  eventqueue, TRUE, vubvar, (vubcoef >= 0.0 ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER),
10158  (1.0-vubconstant)/vubcoef, transitive, infeasible, nbdchgs) );
10159  }
10160  else
10161  {
10162  SCIP_CALL( varAddVbound(var, blkmem, set, eventqueue, SCIP_BOUNDTYPE_UPPER, vubvar, vubcoef, vubconstant) );
10163  }
10164  }
10165  }
10166  break;
10167 
10169  /* x = a*y + c: x <= b*z + d <=> a*y + c <= b*z + d <=> y <= b/a * z + (d-c)/a, if a > 0
10170  * y >= b/a * z + (d-c)/a, if a < 0
10171  */
10172  assert(var->data.aggregate.var != NULL);
10173  if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
10174  {
10175  /* a > 0 -> add variable upper bound */
10176  SCIP_CALL( SCIPvarAddVub(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, lp,
10177  cliquetable, branchcand, eventqueue, vubvar, vubcoef/var->data.aggregate.scalar,
10178  (vubconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10179  }
10180  else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
10181  {
10182  /* a < 0 -> add variable lower bound */
10183  SCIP_CALL( SCIPvarAddVlb(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, lp,
10184  cliquetable, branchcand, eventqueue, vubvar, vubcoef/var->data.aggregate.scalar,
10185  (vubconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10186  }
10187  else
10188  {
10189  SCIPerrorMessage("scalar is zero in aggregation\n");
10190  return SCIP_INVALIDDATA;
10191  }
10192  break;
10193 
10195  /* nothing to do here */
10196  break;
10197 
10199  /* x = offset - x': x <= b*z + d <=> offset - x' <= b*z + d <=> x' >= -b*z + (offset-d) */
10200  assert(var->negatedvar != NULL);
10202  assert(var->negatedvar->negatedvar == var);
10203  SCIP_CALL( SCIPvarAddVlb(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, lp, cliquetable,
10204  branchcand, eventqueue, vubvar, -vubcoef, var->data.negate.constant - vubconstant, transitive, infeasible,
10205  nbdchgs) );
10206  break;
10207 
10208  default:
10209  SCIPerrorMessage("unknown variable status\n");
10210  return SCIP_INVALIDDATA;
10211  }
10212 
10213  return SCIP_OKAY;
10214 }
10215 
10216 /** informs binary variable x about a globally valid implication: x == 0 or x == 1 ==> y <= b or y >= b;
10217  * also adds the corresponding implication or variable bound to the implied variable;
10218  * if the implication is conflicting, the variable is fixed to the opposite value;
10219  * if the variable is already fixed to the given value, the implication is performed immediately;
10220  * if the implication is redundant with respect to the variables' global bounds, it is ignored
10221  */
10223  SCIP_VAR* var, /**< problem variable */
10224  BMS_BLKMEM* blkmem, /**< block memory */
10225  SCIP_SET* set, /**< global SCIP settings */
10226  SCIP_STAT* stat, /**< problem statistics */
10227  SCIP_PROB* transprob, /**< transformed problem */
10228  SCIP_PROB* origprob, /**< original problem */
10229  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
10230  SCIP_LP* lp, /**< current LP data */
10231  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
10232  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
10233  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
10234  SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
10235  SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
10236  SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
10237  SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
10238  SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
10239  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
10240  int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
10241  )
10242 {
10243  assert(var != NULL);
10244  assert(set != NULL);
10245  assert(var->scip == set->scip);
10246  assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
10247  assert(infeasible != NULL);
10248 
10249  *infeasible = FALSE;
10250  if( nbdchgs != NULL )
10251  *nbdchgs = 0;
10252 
10253  switch( SCIPvarGetStatus(var) )
10254  {
10256  assert(var->data.original.transvar != NULL);
10257  SCIP_CALL( SCIPvarAddImplic(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, lp,
10258  cliquetable, branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible,
10259  nbdchgs) );
10260  break;
10261 
10262  case SCIP_VARSTATUS_COLUMN:
10263  case SCIP_VARSTATUS_LOOSE:
10264  /* if the variable is fixed (although it has no FIXED status), and varfixing corresponds to the fixed value of
10265  * the variable, the implication can be applied directly;
10266  * otherwise, add implication to the implications list (and add inverse of implication to the implied variable)
10267  */
10268  if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
10269  {
10270  if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
10271  {
10272  SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue,
10273  implvar, impltype, implbound, infeasible, nbdchgs) );
10274  }
10275  }
10276  else
10277  {
10278  SCIP_CALL( SCIPvarGetProbvarBound(&implvar, &implbound, &impltype) );
10279  SCIPvarAdjustBd(implvar, set, impltype, &implbound);
10280  if( SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED )
10281  {
10282  SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand,
10283  eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible, nbdchgs) );
10284  }
10285  }
10286  break;
10287 
10288  case SCIP_VARSTATUS_FIXED:
10289  /* if varfixing corresponds to the fixed value of the variable, the implication can be applied directly */
10290  if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
10291  {
10292  SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue,
10293  implvar, impltype, implbound, infeasible, nbdchgs) );
10294  }
10295  break;
10296 
10298  /* implication added for x == 1:
10299  * x == 1 && x = 1*z + 0 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b
10300  * x == 1 && x = -1*z + 1 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b
10301  * implication added for x == 0:
10302  * x == 0 && x = 1*z + 0 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b
10303  * x == 0 && x = -1*z + 1 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b
10304  *
10305  * use only binary variables z
10306  */
10307  assert(var->data.aggregate.var != NULL);
10308  if( SCIPvarIsBinary(var->data.aggregate.var) )
10309  {
10310  assert( (SCIPsetIsEQ(set, var->data.aggregate.scalar, 1.0) && SCIPsetIsZero(set, var->data.aggregate.constant))
10311  || (SCIPsetIsEQ(set, var->data.aggregate.scalar, -1.0) && SCIPsetIsEQ(set, var->data.aggregate.constant, 1.0)) );
10312 
10313  if( var->data.aggregate.scalar > 0 )
10314  {
10315  SCIP_CALL( SCIPvarAddImplic(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, lp,
10316  cliquetable, branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible,
10317  nbdchgs) );
10318  }
10319  else
10320  {
10321  SCIP_CALL( SCIPvarAddImplic(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, lp,
10322  cliquetable, branchcand, eventqueue, !varfixing, implvar, impltype, implbound, transitive, infeasible,
10323  nbdchgs) );
10324  }
10325  }
10326  break;
10327 
10329  /* nothing to do here */
10330  break;
10331 
10333  /* implication added for x == 1:
10334  * x == 1 && x = -1*z + 1 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b
10335  * implication added for x == 0:
10336  * x == 0 && x = -1*z + 1 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b
10337  */
10338  assert(var->negatedvar != NULL);
10340  assert(var->negatedvar->negatedvar == var);
10341  assert(SCIPvarIsBinary(var->negatedvar));
10342 
10344  {
10345  SCIP_CALL( SCIPvarAddImplic(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, lp, cliquetable,
10346  branchcand, eventqueue, !varfixing, implvar, impltype, implbound, transitive, infeasible, nbdchgs) );
10347  }
10348  /* in case one both variables are not of binary type we have to add the implication as variable bounds */
10349  else
10350  {
10351  /* if the implied variable is of binary type exchange the variables */
10352  if( SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY )
10353  {
10354  SCIP_CALL( SCIPvarAddImplic(implvar, blkmem, set, stat, transprob, origprob, tree, lp, cliquetable,
10355  branchcand, eventqueue, (impltype == SCIP_BOUNDTYPE_UPPER) ? TRUE : FALSE, var->negatedvar,
10356  varfixing ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER, varfixing ? 1.0 : 0.0, transitive,
10357  infeasible, nbdchgs) );
10358  }
10359  else
10360  {
10361  /* both variables are not of binary type but are implicit binary; in that case we can only add this
10362  * implication as variable bounds
10363  */
10364 
10365  /* add variable lower bound on the negation of var */
10366  if( varfixing )
10367  {
10368  /* (x = 1 => i) z = 0 ii) z = 1) <=> ( i) z = 1 ii) z = 0 => ~x = 1), this is done by adding ~x >= b*z + d
10369  * as variable lower bound
10370  */
10371  SCIP_CALL( SCIPvarAddVlb(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, lp, cliquetable,
10372  branchcand, eventqueue, implvar, (impltype == SCIP_BOUNDTYPE_UPPER) ? 1.0 : -1.0,
10373  (impltype == SCIP_BOUNDTYPE_UPPER) ? 0.0 : 1.0, transitive, infeasible, nbdchgs) );
10374  }
10375  else
10376  {
10377  /* (x = 0 => i) z = 0 ii) z = 1) <=> ( i) z = 1 ii) z = 0 => ~x = 0), this is done by adding ~x <= b*z + d
10378  * as variable upper bound
10379  */
10380  SCIP_CALL( SCIPvarAddVub(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, lp, cliquetable,
10381  branchcand, eventqueue, implvar, (impltype == SCIP_BOUNDTYPE_UPPER) ? -1.0 : 1.0,
10382  (impltype == SCIP_BOUNDTYPE_UPPER) ? 1.0 : 0.0, transitive, infeasible, nbdchgs) );
10383  }
10384 
10385  /* add variable bound on implvar */
10386  if( impltype == SCIP_BOUNDTYPE_UPPER )
10387  {
10388  /* (z = 1 => i) x = 0 ii) x = 1) <=> ( i) ~x = 0 ii) ~x = 1 => z = 0), this is done by adding z <= b*~x + d
10389  * as variable upper bound
10390  */
10391  SCIP_CALL( SCIPvarAddVub(implvar, blkmem, set, stat, transprob, origprob, tree, lp, cliquetable,
10392  branchcand, eventqueue, var->negatedvar, (varfixing) ? 1.0 : -1.0,
10393  (varfixing) ? 0.0 : 1.0, transitive, infeasible, nbdchgs) );
10394  }
10395  else
10396  {
10397  /* (z = 0 => i) x = 0 ii) x = 1) <=> ( i) ~x = 0 ii) ~x = 1 => z = 1), this is done by adding z >= b*~x + d
10398  * as variable upper bound
10399  */
10400  SCIP_CALL( SCIPvarAddVlb(implvar, blkmem, set, stat, transprob, origprob, tree, lp, cliquetable,
10401  branchcand, eventqueue, var->negatedvar, (varfixing) ? -1.0 : 1.0, (varfixing) ? 1.0 : 0.0,
10402  transitive, infeasible, nbdchgs) );
10403  }
10404  }
10405  }
10406  break;
10407 
10408  default:
10409  SCIPerrorMessage("unknown variable status\n");
10410  return SCIP_INVALIDDATA;
10411  }
10412 
10413  return SCIP_OKAY;
10414 }
10415 
10416 /** returns whether there is an implication x == varfixing -> y <= b or y >= b in the implication graph;
10417  * implications that are represented as cliques in the clique table are not regarded (use SCIPvarsHaveCommonClique());
10418  * both variables must be active, variable x must be binary
10419  */
10421  SCIP_VAR* var, /**< problem variable x */
10422  SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
10423  SCIP_VAR* implvar, /**< variable y to search for */
10424  SCIP_BOUNDTYPE impltype /**< type of implication y <=/>= b to search for */
10425  )
10426 {
10427  assert(var != NULL);
10428  assert(implvar != NULL);
10429  assert(SCIPvarIsActive(var));
10430  assert(SCIPvarIsActive(implvar));
10431  assert(SCIPvarIsBinary(var));
10432 
10433  return var->implics != NULL && SCIPimplicsContainsImpl(var->implics, varfixing, implvar, impltype);
10434 }
10435 
10436 /** returns whether there is an implication x == varfixing -> y == implvarfixing in the implication graph;
10437  * implications that are represented as cliques in the clique table are not regarded (use SCIPvarsHaveCommonClique());
10438  * both variables must be active binary variables
10439  */
10441  SCIP_VAR* var, /**< problem variable x */
10442  SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
10443  SCIP_VAR* implvar, /**< variable y to search for */
10444  SCIP_Bool implvarfixing /**< value of the implied variable to search for */
10445  )
10446 {
10447  assert(SCIPvarIsBinary(implvar));
10448 
10449  return SCIPvarHasImplic(var, varfixing, implvar, implvarfixing ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER);
10450 }
10451 
10452 /** fixes the bounds of a binary variable to the given value, counting bound changes and detecting infeasibility */
10454  SCIP_VAR* var, /**< problem variable */
10455  BMS_BLKMEM* blkmem, /**< block memory */
10456  SCIP_SET* set, /**< global SCIP settings */
10457  SCIP_STAT* stat, /**< problem statistics */
10458  SCIP_PROB* transprob, /**< transformed problem */
10459  SCIP_PROB* origprob, /**< original problem */
10460  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
10461  SCIP_LP* lp, /**< current LP data */
10462  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
10463  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
10464  SCIP_Bool value, /**< value to fix variable to */
10465  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
10466  int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
10467  )
10468 {
10469  assert(var != NULL);
10470  assert(set != NULL);
10471  assert(var->scip == set->scip);
10472  assert(infeasible != NULL);
10473 
10474  *infeasible = FALSE;
10475 
10476  if( value == FALSE )
10477  {
10478  if( var->glbdom.lb > 0.5 )
10479  *infeasible = TRUE;
10480  else if( var->glbdom.ub > 0.5 )
10481  {
10482  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10483  * with the local bound, in this case we need to store the bound change as pending bound change
10484  */
10485  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10486  {
10487  assert(tree != NULL);
10488  assert(transprob != NULL);
10489  assert(SCIPprobIsTransformed(transprob));
10490 
10491  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10492  tree, lp, branchcand, eventqueue, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) );
10493  }
10494  else
10495  {
10496  SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, 0.0) );
10497  }
10498 
10499  if( nbdchgs != NULL )
10500  (*nbdchgs)++;
10501  }
10502  }
10503  else
10504  {
10505  if( var->glbdom.ub < 0.5 )
10506  *infeasible = TRUE;
10507  else if( var->glbdom.lb < 0.5 )
10508  {
10509  /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10510  * with the local bound, in this case we need to store the bound change as pending bound change
10511  */
10512  if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10513  {
10514  assert(tree != NULL);
10515  assert(transprob != NULL);
10516  assert(SCIPprobIsTransformed(transprob));
10517 
10518  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10519  tree, lp, branchcand, eventqueue, var, 1.0, SCIP_BOUNDTYPE_LOWER, FALSE) );
10520  }
10521  else
10522  {
10523  SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, 1.0) );
10524  }
10525 
10526  if( nbdchgs != NULL )
10527  (*nbdchgs)++;
10528  }
10529  }
10530 
10531  return SCIP_OKAY;
10532 }
10533 
10534 /** adds the variable to the given clique and updates the list of cliques the binary variable is member of;
10535  * if the variable now appears twice in the clique with the same value, it is fixed to the opposite value;
10536  * if the variable now appears twice in the clique with opposite values, all other variables are fixed to
10537  * the opposite of the value they take in the clique
10538  */
10540  SCIP_VAR* var, /**< problem variable */
10541  BMS_BLKMEM* blkmem, /**< block memory */
10542  SCIP_SET* set, /**< global SCIP settings */
10543  SCIP_STAT* stat, /**< problem statistics */
10544  SCIP_PROB* transprob, /**< transformed problem */
10545  SCIP_PROB* origprob, /**< original problem */
10546  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
10547  SCIP_LP* lp, /**< current LP data */
10548  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
10549  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
10550  SCIP_Bool value, /**< value of the variable in the clique */
10551  SCIP_CLIQUE* clique, /**< clique the variable should be added to */
10552  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
10553  int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
10554  )
10555 {
10556  assert(var != NULL);
10557  assert(set != NULL);
10558  assert(var->scip == set->scip);
10559  assert(SCIPvarIsBinary(var));
10560  assert(infeasible != NULL);
10561 
10562  *infeasible = FALSE;
10563 
10564  /* get corresponding active problem variable */
10565  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
10570  assert(SCIPvarIsBinary(var));
10571 
10572  /* only column and loose variables may be member of a clique */
10574  {
10575  SCIP_Bool doubleentry;
10576  SCIP_Bool oppositeentry;
10577 
10578  /* add variable to clique */
10579  SCIP_CALL( SCIPcliqueAddVar(clique, blkmem, set, var, value, &doubleentry, &oppositeentry) );
10580 
10581  /* add clique to variable's clique list */
10582  SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, value, clique) );
10583 
10584  /* check consistency of cliquelist */
10585  SCIPcliquelistCheck(var->cliquelist, var);
10586 
10587  /* if the variable now appears twice with the same value in the clique, it can be fixed to the opposite value */
10588  if( doubleentry )
10589  {
10590  SCIP_CALL( SCIPvarFixBinary(var, blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue, !value,
10591  infeasible, nbdchgs) );
10592  }
10593 
10594  /* if the variable appears with both values in the clique, all other variables of the clique can be fixed
10595  * to the opposite of the value they take in the clique
10596  */
10597  if( oppositeentry )
10598  {
10599  SCIP_VAR** vars;
10600  SCIP_Bool* values;
10601  int nvars;
10602  int i;
10603 
10604  nvars = SCIPcliqueGetNVars(clique);
10605  vars = SCIPcliqueGetVars(clique);
10606  values = SCIPcliqueGetValues(clique);
10607  for( i = 0; i < nvars && !(*infeasible); ++i )
10608  {
10609  if( vars[i] == var )
10610  continue;
10611 
10612  SCIP_CALL( SCIPvarFixBinary(vars[i], blkmem, set, stat, transprob, origprob, tree, lp, branchcand, eventqueue,
10613  !values[i], infeasible, nbdchgs) );
10614  }
10615  }
10616  }
10617 
10618  return SCIP_OKAY;
10619 }
10620 
10621 /** adds a filled clique to the cliquelists of all corresponding variables */
10623  SCIP_VAR** vars, /**< problem variables */
10624  SCIP_Bool* values, /**< values of the variables in the clique */
10625  int nvars, /**< number of problem variables */
10626  BMS_BLKMEM* blkmem, /**< block memory */
10627  SCIP_SET* set, /**< global SCIP settings */
10628  SCIP_CLIQUE* clique /**< clique that contains all given variables and values */
10629  )
10630 {
10631  SCIP_VAR* var;
10632  int v;
10633 
10634  assert(vars != NULL);
10635  assert(values != NULL);
10636  assert(nvars > 0);
10637  assert(set != NULL);
10638  assert(blkmem != NULL);
10639  assert(clique != NULL);
10640 
10641  for( v = nvars - 1; v >= 0; --v )
10642  {
10643  var = vars[v];
10644  assert(SCIPvarIsBinary(var));
10646 
10647  /* add clique to variable's clique list */
10648  SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, values[v], clique) );
10649 
10650  /* check consistency of cliquelist */
10651  SCIPcliquelistCheck(var->cliquelist, var);
10652  }
10653 
10654  return SCIP_OKAY;
10655 }
10656 
10657 /** deletes a clique from the list of cliques the binary variable is member of, but does not change the clique
10658  * itself
10659  */
10661  SCIP_VAR* var, /**< problem variable */
10662  BMS_BLKMEM* blkmem, /**< block memory */
10663  SCIP_Bool value, /**< value of the variable in the clique */
10664  SCIP_CLIQUE* clique /**< clique that should be removed from the variable's clique list */
10665  )
10666 {
10667  assert(var != NULL);
10668  assert(SCIPvarIsBinary(var));
10670 
10671  /* delete clique from variable's clique list */
10672  SCIP_CALL( SCIPcliquelistDel(&var->cliquelist, blkmem, value, clique) );
10673 
10674  return SCIP_OKAY;
10675 }
10676 
10677 /** deletes the variable from the given clique and updates the list of cliques the binary variable is member of */
10679  SCIP_VAR* var, /**< problem variable */
10680  BMS_BLKMEM* blkmem, /**< block memory */
10681  SCIP_Bool value, /**< value of the variable in the clique */
10682  SCIP_CLIQUE* clique /**< clique the variable should be removed from */
10683  )
10684 {
10685  assert(var != NULL);
10686  assert(SCIPvarIsBinary(var));
10687 
10688  /* get corresponding active problem variable */
10689  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
10694  assert(SCIPvarIsBinary(var));
10695 
10696  /* only column and loose variables may be member of a clique */
10698  {
10699  /* delete clique from variable's clique list */
10700  SCIP_CALL( SCIPcliquelistDel(&var->cliquelist, blkmem, value, clique) );
10701 
10702  /* delete variable from clique */
10703  SCIP_CALL( SCIPcliqueDelVar(clique, var, value) );
10704 
10705  /* check consistency of cliquelist */
10706  SCIPcliquelistCheck(var->cliquelist, var);
10707  }
10708 
10709  return SCIP_OKAY;
10710 }
10711 
10712 /** returns whether there is a clique that contains both given variable/value pairs;
10713  * the variables must be active binary variables;
10714  * if regardimplics is FALSE, only the cliques in the clique table are looked at;
10715  * if regardimplics is TRUE, both the cliques and the implications of the implication graph are regarded
10716  *
10717  * @note a variable with it's negated variable are NOT! in a clique
10718  * @note a variable with itself are in a clique
10719  */
10721  SCIP_VAR* var1, /**< first variable */
10722  SCIP_Bool value1, /**< value of first variable */
10723  SCIP_VAR* var2, /**< second variable */
10724  SCIP_Bool value2, /**< value of second variable */
10725  SCIP_Bool regardimplics /**< should the implication graph also be searched for a clique? */
10726  )
10727 {
10728  assert(var1 != NULL);
10729  assert(var2 != NULL);
10730  assert(SCIPvarIsActive(var1));
10731  assert(SCIPvarIsActive(var2));
10732  assert(SCIPvarIsBinary(var1));
10733  assert(SCIPvarIsBinary(var2));
10734 
10735  return (SCIPcliquelistsHaveCommonClique(var1->cliquelist, value1, var2->cliquelist, value2)
10736  || (regardimplics && SCIPvarHasImplic(var1, value1, var2, value2 ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER)));
10737 }
10738 
10739 /** actually changes the branch factor of the variable and of all parent variables */
10740 static
10742  SCIP_VAR* var, /**< problem variable */
10743  SCIP_SET* set, /**< global SCIP settings */
10744  SCIP_Real branchfactor /**< factor to weigh variable's branching score with */
10745  )
10746 {
10747  SCIP_VAR* parentvar;
10748  SCIP_Real eps;
10749  int i;
10750 
10751  assert(var != NULL);
10752  assert(set != NULL);
10753  assert(var->scip == set->scip);
10754 
10755  /* only use positive values */
10756  eps = SCIPsetEpsilon(set);
10757  branchfactor = MAX(branchfactor, eps);
10758 
10759  SCIPdebugMessage("process changing branch factor of <%s> from %f to %f\n", var->name, var->branchfactor, branchfactor);
10760 
10761  if( SCIPsetIsEQ(set, branchfactor, var->branchfactor) )
10762  return SCIP_OKAY;
10763 
10764  /* change the branch factor */
10765  var->branchfactor = branchfactor;
10766 
10767  /* process parent variables */
10768  for( i = 0; i < var->nparentvars; ++i )
10769  {
10770  parentvar = var->parentvars[i];
10771  assert(parentvar != NULL);
10772 
10773  switch( SCIPvarGetStatus(parentvar) )
10774  {
10776  /* do not change priorities across the border between transformed and original problem */
10777  break;
10778 
10779  case SCIP_VARSTATUS_COLUMN:
10780  case SCIP_VARSTATUS_LOOSE:
10781  case SCIP_VARSTATUS_FIXED:
10783  SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
10784  SCIPABORT();
10785  return SCIP_INVALIDDATA; /*lint !e527*/
10786 
10789  SCIP_CALL( varProcessChgBranchFactor(parentvar, set, branchfactor) );
10790  break;
10791 
10792  default:
10793  SCIPerrorMessage("unknown variable status\n");
10794  SCIPABORT();
10795  return SCIP_ERROR; /*lint !e527*/
10796  }
10797  }
10798 
10799  return SCIP_OKAY;
10800 }
10801 
10802 /** sets the branch factor of the variable; this value can be used in the branching methods to scale the score
10803  * values of the variables; higher factor leads to a higher probability that this variable is chosen for branching
10804  */
10806  SCIP_VAR* var, /**< problem variable */
10807  SCIP_SET* set, /**< global SCIP settings */
10808  SCIP_Real branchfactor /**< factor to weigh variable's branching score with */
10809  )
10810 {
10811  int v;
10812 
10813  assert(var != NULL);
10814  assert(set != NULL);
10815  assert(var->scip == set->scip);
10816  assert(branchfactor >= 0.0);
10817 
10818  SCIPdebugMessage("changing branch factor of <%s> from %g to %g\n", var->name, var->branchfactor, branchfactor);
10819 
10820  if( SCIPsetIsEQ(set, var->branchfactor, branchfactor) )
10821  return SCIP_OKAY;
10822 
10823  /* change priorities of attached variables */
10824  switch( SCIPvarGetStatus(var) )
10825  {
10827  if( var->data.original.transvar != NULL )
10828  {
10829  SCIP_CALL( SCIPvarChgBranchFactor(var->data.original.transvar, set, branchfactor) );
10830  }
10831  else
10832  {
10833  assert(set->stage == SCIP_STAGE_PROBLEM);
10834  var->branchfactor = branchfactor;
10835  }
10836  break;
10837 
10838  case SCIP_VARSTATUS_COLUMN:
10839  case SCIP_VARSTATUS_LOOSE:
10840  case SCIP_VARSTATUS_FIXED:
10841  SCIP_CALL( varProcessChgBranchFactor(var, set, branchfactor) );
10842  break;
10843 
10845  assert(var->data.aggregate.var != NULL);
10846  SCIP_CALL( SCIPvarChgBranchFactor(var->data.aggregate.var, set, branchfactor) );
10847  break;
10848 
10850  assert(!var->donotmultaggr);
10851  for( v = 0; v < var->data.multaggr.nvars; ++v )
10852  {
10853  SCIP_CALL( SCIPvarChgBranchFactor(var->data.multaggr.vars[v], set, branchfactor) );
10854  }
10855  break;
10856 
10858  assert(var->negatedvar != NULL);
10860  assert(var->negatedvar->negatedvar == var);
10861  SCIP_CALL( SCIPvarChgBranchFactor(var->negatedvar, set, branchfactor) );
10862  break;
10863 
10864  default:
10865  SCIPerrorMessage("unknown variable status\n");
10866  SCIPABORT();
10867  return SCIP_ERROR; /*lint !e527*/
10868  }
10869 
10870  return SCIP_OKAY;
10871 }
10872 
10873 /** actually changes the branch priority of the variable and of all parent variables */
10874 static
10876  SCIP_VAR* var, /**< problem variable */
10877  int branchpriority /**< branching priority of the variable */
10878  )
10879 {
10880  SCIP_VAR* parentvar;
10881  int i;
10882 
10883  assert(var != NULL);
10884 
10885  SCIPdebugMessage("process changing branch priority of <%s> from %d to %d\n",
10886  var->name, var->branchpriority, branchpriority);
10887 
10888  if( branchpriority == var->branchpriority )
10889  return SCIP_OKAY;
10890 
10891  /* change the branch priority */
10892  var->branchpriority = branchpriority;
10893 
10894  /* process parent variables */
10895  for( i = 0; i < var->nparentvars; ++i )
10896  {
10897  parentvar = var->parentvars[i];
10898  assert(parentvar != NULL);
10899 
10900  switch( SCIPvarGetStatus(parentvar) )
10901  {
10903  /* do not change priorities across the border between transformed and original problem */
10904  break;
10905 
10906  case SCIP_VARSTATUS_COLUMN:
10907  case SCIP_VARSTATUS_LOOSE:
10908  case SCIP_VARSTATUS_FIXED:
10910  SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
10911  SCIPABORT();
10912  return SCIP_INVALIDDATA; /*lint !e527*/
10913 
10916  SCIP_CALL( varProcessChgBranchPriority(parentvar, branchpriority) );
10917  break;
10918 
10919  default:
10920  SCIPerrorMessage("unknown variable status\n");
10921  return SCIP_ERROR;
10922  }
10923  }
10924 
10925  return SCIP_OKAY;
10926 }
10927 
10928 /** sets the branch priority of the variable; variables with higher branch priority are always preferred to variables
10929  * with lower priority in selection of branching variable
10930  */
10932  SCIP_VAR* var, /**< problem variable */
10933  int branchpriority /**< branching priority of the variable */
10934  )
10935 {
10936  int v;
10937 
10938  assert(var != NULL);
10939 
10940  SCIPdebugMessage("changing branch priority of <%s> from %d to %d\n", var->name, var->branchpriority, branchpriority);
10941 
10942  if( var->branchpriority == branchpriority )
10943  return SCIP_OKAY;
10944 
10945  /* change priorities of attached variables */
10946  switch( SCIPvarGetStatus(var) )
10947  {
10949  if( var->data.original.transvar != NULL )
10950  {
10951  SCIP_CALL( SCIPvarChgBranchPriority(var->data.original.transvar, branchpriority) );
10952  }
10953  else
10954  var->branchpriority = branchpriority;
10955  break;
10956 
10957  case SCIP_VARSTATUS_COLUMN:
10958  case SCIP_VARSTATUS_LOOSE:
10959  case SCIP_VARSTATUS_FIXED:
10960  SCIP_CALL( varProcessChgBranchPriority(var, branchpriority) );
10961  break;
10962 
10964  assert(var->data.aggregate.var != NULL);
10965  SCIP_CALL( SCIPvarChgBranchPriority(var->data.aggregate.var, branchpriority) );
10966  break;
10967 
10969  assert(!var->donotmultaggr);
10970  for( v = 0; v < var->data.multaggr.nvars; ++v )
10971  {
10972  SCIP_CALL( SCIPvarChgBranchPriority(var->data.multaggr.vars[v], branchpriority) );
10973  }
10974  break;
10975 
10977  assert(var->negatedvar != NULL);
10979  assert(var->negatedvar->negatedvar == var);
10980  SCIP_CALL( SCIPvarChgBranchPriority(var->negatedvar, branchpriority) );
10981  break;
10982 
10983  default:
10984  SCIPerrorMessage("unknown variable status\n");
10985  SCIPABORT();
10986  return SCIP_ERROR; /*lint !e527*/
10987  }
10988 
10989  return SCIP_OKAY;
10990 }
10991 
10992 /** actually changes the branch direction of the variable and of all parent variables */
10993 static
10995  SCIP_VAR* var, /**< problem variable */
10996  SCIP_BRANCHDIR branchdirection /**< preferred branch direction of the variable (downwards, upwards, auto) */
10997  )
10998 {
10999  SCIP_VAR* parentvar;
11000  int i;
11001 
11002  assert(var != NULL);
11003 
11004  SCIPdebugMessage("process changing branch direction of <%s> from %u to %d\n",
11005  var->name, var->branchdirection, branchdirection);
11006 
11007  if( branchdirection == (SCIP_BRANCHDIR)var->branchdirection )
11008  return SCIP_OKAY;
11009 
11010  /* change the branch direction */
11011  var->branchdirection = branchdirection; /*lint !e641*/
11012 
11013  /* process parent variables */
11014  for( i = 0; i < var->nparentvars; ++i )
11015  {
11016  parentvar = var->parentvars[i];
11017  assert(parentvar != NULL);
11018 
11019  switch( SCIPvarGetStatus(parentvar) )
11020  {
11022  /* do not change directions across the border between transformed and original problem */
11023  break;
11024 
11025  case SCIP_VARSTATUS_COLUMN:
11026  case SCIP_VARSTATUS_LOOSE:
11027  case SCIP_VARSTATUS_FIXED:
11029  SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
11030  SCIPABORT();
11031  return SCIP_INVALIDDATA; /*lint !e527*/
11032 
11034  if( parentvar->data.aggregate.scalar > 0.0 )
11035  {
11036  SCIP_CALL( varProcessChgBranchDirection(parentvar, branchdirection) );
11037  }
11038  else
11039  {
11040  SCIP_CALL( varProcessChgBranchDirection(parentvar, SCIPbranchdirOpposite(branchdirection)) );
11041  }
11042  break;
11043 
11045  SCIP_CALL( varProcessChgBranchDirection(parentvar, SCIPbranchdirOpposite(branchdirection)) );
11046  break;
11047 
11048  default:
11049  SCIPerrorMessage("unknown variable status\n");
11050  SCIPABORT();
11051  return SCIP_ERROR; /*lint !e527*/
11052  }
11053  }
11054 
11055  return SCIP_OKAY;
11056 }
11057 
11058 /** sets the branch direction of the variable; variables with higher branch direction are always preferred to variables
11059  * with lower direction in selection of branching variable
11060  */
11062  SCIP_VAR* var, /**< problem variable */
11063  SCIP_BRANCHDIR branchdirection /**< preferred branch direction of the variable (downwards, upwards, auto) */
11064  )
11065 {
11066  int v;
11067 
11068  assert(var != NULL);
11069 
11070  SCIPdebugMessage("changing branch direction of <%s> from %u to %d\n", var->name, var->branchdirection, branchdirection);
11071 
11072  if( (SCIP_BRANCHDIR)var->branchdirection == branchdirection )
11073  return SCIP_OKAY;
11074 
11075  /* change directions of attached variables */
11076  switch( SCIPvarGetStatus(var) )
11077  {
11079  if( var->data.original.transvar != NULL )
11080  {
11081  SCIP_CALL( SCIPvarChgBranchDirection(var->data.original.transvar, branchdirection) );
11082  }
11083  else
11084  var->branchdirection = branchdirection; /*lint !e641*/
11085  break;
11086 
11087  case SCIP_VARSTATUS_COLUMN:
11088  case SCIP_VARSTATUS_LOOSE:
11089  case SCIP_VARSTATUS_FIXED:
11090  SCIP_CALL( varProcessChgBranchDirection(var, branchdirection) );
11091  break;
11092 
11094  assert(var->data.aggregate.var != NULL);
11095  if( var->data.aggregate.scalar > 0.0 )
11096  {
11097  SCIP_CALL( SCIPvarChgBranchDirection(var->data.aggregate.var, branchdirection) );
11098  }
11099  else
11100  {
11102  }
11103  break;
11104 
11106  assert(!var->donotmultaggr);
11107  for( v = 0; v < var->data.multaggr.nvars; ++v )
11108  {
11109  /* only update branching direction of aggregation variables, if they don't have a preferred direction yet */
11110  assert(var->data.multaggr.vars[v] != NULL);
11112  {
11113  if( var->data.multaggr.scalars[v] > 0.0 )
11114  {
11115  SCIP_CALL( SCIPvarChgBranchDirection(var->data.multaggr.vars[v], branchdirection) );
11116  }
11117  else
11118  {
11120  }
11121  }
11122  }
11123  break;
11124 
11126  assert(var->negatedvar != NULL);
11128  assert(var->negatedvar->negatedvar == var);
11130  break;
11131 
11132  default:
11133  SCIPerrorMessage("unknown variable status\n");
11134  SCIPABORT();
11135  return SCIP_ERROR; /*lint !e527*/
11136  }
11137 
11138  return SCIP_OKAY;
11139 }
11140 
11141 /** compares the index of two variables, only active, fixed or negated variables are allowed, if a variable
11142  * is negated then the index of the corresponding active variable is taken, returns -1 if first is
11143  * smaller than, and +1 if first is greater than second variable index; returns 0 if both indices
11144  * are equal, which means both variables are equal
11145  */
11147  SCIP_VAR* var1, /**< first problem variable */
11148  SCIP_VAR* var2 /**< second problem variable */
11149  )
11150 {
11151  assert(var1 != NULL);
11152  assert(var2 != NULL);
11155 
11157  var1 = SCIPvarGetNegatedVar(var1);
11159  var2 = SCIPvarGetNegatedVar(var2);
11160 
11161  assert(var1 != NULL);
11162  assert(var2 != NULL);
11163 
11164  if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
11165  return -1;
11166  else if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
11167  return +1;
11168 
11169  assert(var1 == var2);
11170  return 0;
11171 }
11172 
11173 /** comparison method for sorting active and negated variables by non-decreasing index, active and negated
11174  * variables are handled as the same variables
11175  */
11176 SCIP_DECL_SORTPTRCOMP(SCIPvarCompActiveAndNegated)
11177 {
11178  return SCIPvarCompareActiveAndNegated((SCIP_VAR*)elem1, (SCIP_VAR*)elem2);
11179 }
11180 
11181 /** compares the index of two variables, returns -1 if first is smaller than, and +1 if first is greater than second
11182  * variable index; returns 0 if both indices are equal, which means both variables are equal
11183  */
11185  SCIP_VAR* var1, /**< first problem variable */
11186  SCIP_VAR* var2 /**< second problem variable */
11187  )
11188 {
11189  assert(var1 != NULL);
11190  assert(var2 != NULL);
11191 
11192  if( var1->index < var2->index )
11193  return -1;
11194  else if( var1->index > var2->index )
11195  return +1;
11196  else
11197  {
11198  assert(var1 == var2);
11199  return 0;
11200  }
11201 }
11202 
11203 /** comparison method for sorting variables by non-decreasing index */
11205 {
11206  return SCIPvarCompare((SCIP_VAR*)elem1, (SCIP_VAR*)elem2);
11207 }
11208 
11209 /** comparison method for sorting variables by non-decreasing objective coefficient */
11210 SCIP_DECL_SORTPTRCOMP(SCIPvarCompObj)
11211 {
11212  SCIP_Real obj1;
11213  SCIP_Real obj2;
11214 
11215  obj1 = SCIPvarGetObj((SCIP_VAR*)elem1);
11216  obj2 = SCIPvarGetObj((SCIP_VAR*)elem2);
11217 
11218  if( obj1 < obj2 )
11219  return -1;
11220  else if( obj1 > obj2 )
11221  return +1;
11222  else
11223  return 0;
11224 }
11225 
11226 /** hash key retrieval function for variables */
11227 SCIP_DECL_HASHGETKEY(SCIPvarGetHashkey)
11228 { /*lint --e{715}*/
11229  return elem;
11230 }
11231 
11232 /** returns TRUE iff the indices of both variables are equal */
11233 SCIP_DECL_HASHKEYEQ(SCIPvarIsHashkeyEq)
11234 { /*lint --e{715}*/
11235  if( key1 == key2 )
11236  return TRUE;
11237  return FALSE;
11238 }
11239 
11240 /** returns the hash value of the key */
11241 SCIP_DECL_HASHKEYVAL(SCIPvarGetHashkeyVal)
11242 { /*lint --e{715}*/
11243  assert( SCIPvarGetIndex((SCIP_VAR*) key) >= 0 );
11244  return (unsigned int) SCIPvarGetIndex((SCIP_VAR*) key);
11245 }
11246 
11247 /** return for given variables all their active counterparts; all active variables will be pairwise different */
11249  SCIP_SET* set, /**< global SCIP settings */
11250  SCIP_VAR** vars, /**< variable array with given variables and as output all active
11251  * variables, if enough slots exist
11252  */
11253  int* nvars, /**< number of given variables, and as output number of active variables,
11254  * if enough slots exist
11255  */
11256  int varssize, /**< available slots in vars array */
11257  int* requiredsize /**< pointer to store the required array size for the active variables */
11258  )
11259 {
11260  SCIP_VAR** activevars;
11261  int nactivevars;
11262  int activevarssize;
11263 
11264  SCIP_VAR* var;
11265  int v;
11266 
11267  SCIP_VAR** tmpvars;
11268  SCIP_VAR** multvars;
11269  int tmpvarssize;
11270  int ntmpvars;
11271  int noldtmpvars;
11272  int nmultvars;
11273 
11274  assert(set != NULL);
11275  assert(nvars != NULL);
11276  assert(vars != NULL || *nvars == 0);
11277  assert(varssize >= *nvars);
11278  assert(requiredsize != NULL);
11279 
11280  *requiredsize = 0;
11281 
11282  if( *nvars == 0 )
11283  return SCIP_OKAY;
11284 
11285  nactivevars = 0;
11286  activevarssize = *nvars;
11287  ntmpvars = *nvars;
11288  tmpvarssize = *nvars;
11289 
11290  /* temporary memory */
11291  SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) );
11292  SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpvars, vars, ntmpvars) );
11293 
11294  noldtmpvars = ntmpvars;
11295 
11296  /* sort all variables to combine equal variables easily */
11297  SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
11298  for( v = ntmpvars - 1; v > 0; --v )
11299  {
11300  /* combine same variables */
11301  if( SCIPvarCompare(tmpvars[v], tmpvars[v - 1]) == 0 )
11302  {
11303  --ntmpvars;
11304  tmpvars[v] = tmpvars[ntmpvars];
11305  }
11306  }
11307  /* sort all variables again to combine equal variables later on */
11308  if( noldtmpvars > ntmpvars )
11309  SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
11310 
11311  /* collect for each variable the representation in active variables */
11312  while( ntmpvars >= 1 )
11313  {
11314  --ntmpvars;
11315  var = tmpvars[ntmpvars];
11316  assert( var != NULL );
11317 
11318  switch( SCIPvarGetStatus(var) )
11319  {
11321  if( var->data.original.transvar == NULL )
11322  {
11323  SCIPerrorMessage("original variable has no transformed variable attached\n");
11324  SCIPABORT();
11325  return SCIP_INVALIDDATA; /*lint !e527*/
11326  }
11327  tmpvars[ntmpvars] = var->data.original.transvar;
11328  ++ntmpvars;
11329  break;
11330 
11332  tmpvars[ntmpvars] = var->data.aggregate.var;
11333  ++ntmpvars;
11334  break;
11335 
11337  tmpvars[ntmpvars] = var->negatedvar;
11338  ++ntmpvars;
11339  break;
11340 
11341  case SCIP_VARSTATUS_LOOSE:
11342  case SCIP_VARSTATUS_COLUMN:
11343  /* check for space in temporary memory */
11344  if( nactivevars >= activevarssize )
11345  {
11346  activevarssize *= 2;
11347  SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) );
11348  assert(nactivevars < activevarssize);
11349  }
11350  activevars[nactivevars] = var;
11351  nactivevars++;
11352  break;
11353 
11355  /* x = a_1*y_1 + ... + a_n*y_n + c */
11356  nmultvars = var->data.multaggr.nvars;
11357  multvars = var->data.multaggr.vars;
11358 
11359  /* check for space in temporary memory */
11360  if( nmultvars + ntmpvars > tmpvarssize )
11361  {
11362  while( nmultvars + ntmpvars > tmpvarssize )
11363  tmpvarssize *= 2;
11364  SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) );
11365  assert(nmultvars + ntmpvars <= tmpvarssize);
11366  }
11367 
11368  /* copy all multi-aggregation variables into our working array */
11369  BMScopyMemoryArray(&tmpvars[ntmpvars], multvars, nmultvars); /*lint !e866*/
11370 
11371  /* get active, fixed or multi-aggregated corresponding variables for all new ones */
11372  SCIPvarsGetProbvar(&tmpvars[ntmpvars], nmultvars);
11373 
11374  ntmpvars += nmultvars;
11375  noldtmpvars = ntmpvars;
11376 
11377  /* sort all variables to combine equal variables easily */
11378  SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
11379  for( v = ntmpvars - 1; v > 0; --v )
11380  {
11381  /* combine same variables */
11382  if( SCIPvarCompare(tmpvars[v], tmpvars[v - 1]) == 0 )
11383  {
11384  --ntmpvars;
11385  tmpvars[v] = tmpvars[ntmpvars];
11386  }
11387  }
11388  /* sort all variables again to combine equal variables later on */
11389  if( noldtmpvars > ntmpvars )
11390  SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
11391 
11392  break;
11393 
11394  case SCIP_VARSTATUS_FIXED:
11395  /* no need for memorizing fixed variables */
11396  break;
11397 
11398  default:
11399  SCIPerrorMessage("unknown variable status\n");
11400  SCIPABORT();
11401  return SCIP_INVALIDDATA; /*lint !e527*/
11402  }
11403  }
11404 
11405  /* sort variable array by variable index */
11406  SCIPsortPtr((void**)activevars, SCIPvarComp, nactivevars);
11407 
11408  /* eliminate duplicates and count required size */
11409  v = nactivevars - 1;
11410  while( v > 0 )
11411  {
11412  /* combine both variable since they are the same */
11413  if( SCIPvarCompare(activevars[v - 1], activevars[v]) == 0 )
11414  {
11415  --nactivevars;
11416  activevars[v] = activevars[nactivevars];
11417  }
11418  --v;
11419  }
11420  *requiredsize = nactivevars;
11421 
11422  if( varssize >= *requiredsize )
11423  {
11424  assert(vars != NULL);
11425 
11426  *nvars = *requiredsize;
11427  BMScopyMemoryArray(vars, activevars, nactivevars);
11428  }
11429 
11430  SCIPsetFreeBufferArray(set, &tmpvars);
11431  SCIPsetFreeBufferArray(set, &activevars);
11432 
11433  return SCIP_OKAY;
11434 }
11435 
11436 /** gets corresponding active, fixed, or multi-aggregated problem variables of given variables,
11437  * @note the content of the given array will/might change
11438  */
11440  SCIP_VAR** vars, /**< array of problem variables */
11441  int nvars /**< number of variables */
11442  )
11443 {
11444  int v;
11445 
11446  assert(vars != NULL || nvars == 0);
11447 
11448  for( v = nvars - 1; v >= 0; --v )
11449  {
11450  assert(vars != NULL);
11451  assert(vars[v] != NULL);
11452 
11453  vars[v] = SCIPvarGetProbvar(vars[v]);
11454  assert(vars[v] != NULL);
11455  }
11456 }
11457 
11458 /** gets corresponding active, fixed, or multi-aggregated problem variable of a variable */
11460  SCIP_VAR* var /**< problem variable */
11461  )
11462 {
11463  SCIP_VAR* retvar;
11464 
11465  assert(var != NULL);
11466 
11467  retvar = var;
11468 
11469  SCIPdebugMessage("get problem variable of <%s>\n", var->name);
11470 
11471  while( TRUE ) /*lint !e716 */
11472  {
11473  assert(retvar != NULL);
11474 
11475  switch( SCIPvarGetStatus(retvar) )
11476  {
11478  if( retvar->data.original.transvar == NULL )
11479  {
11480  SCIPerrorMessage("original variable has no transformed variable attached\n");
11481  SCIPABORT();
11482  return NULL; /*lint !e527 */
11483  }
11484  retvar = retvar->data.original.transvar;
11485  break;
11486 
11487  case SCIP_VARSTATUS_LOOSE:
11488  case SCIP_VARSTATUS_COLUMN:
11489  case SCIP_VARSTATUS_FIXED:
11490  return retvar;
11491 
11493  /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
11494  if ( retvar->data.multaggr.nvars == 1 )
11495  retvar = retvar->data.multaggr.vars[0];
11496  else
11497  return retvar;
11498  break;
11499 
11501  retvar = retvar->data.aggregate.var;
11502  break;
11503 
11505  retvar = retvar->negatedvar;
11506  break;
11507 
11508  default:
11509  SCIPerrorMessage("unknown variable status\n");
11510  SCIPABORT();
11511  return NULL; /*lint !e527*/
11512  }
11513  }
11514 }
11515 
11516 /** gets corresponding active, fixed, or multi-aggregated problem variables of binary variables and updates the given
11517  * negation status of each variable
11518  */
11520  SCIP_VAR*** vars, /**< pointer to binary problem variables */
11521  SCIP_Bool** negatedarr, /**< pointer to corresponding array to update the negation status */
11522  int nvars /**< number of variables and values in vars and negated array */
11523  )
11524 {
11525  SCIP_VAR** var;
11526  SCIP_Bool* negated;
11527  int v;
11528 
11529  assert(vars != NULL);
11530  assert(*vars != NULL || nvars == 0);
11531  assert(negatedarr != NULL);
11532  assert(*negatedarr != NULL || nvars == 0);
11533 
11534  for( v = nvars - 1; v >= 0; --v )
11535  {
11536  var = &((*vars)[v]);
11537  negated = &((*negatedarr)[v]);
11538 
11539  /* get problem variable */
11540  SCIP_CALL( SCIPvarGetProbvarBinary(var, negated) );
11541  }
11542 
11543  return SCIP_OKAY;
11544 }
11545 
11546 
11547 /** gets corresponding active, fixed, or multi-aggregated problem variable of a binary variable and updates the given
11548  * negation status (this means you have to assign a value to SCIP_Bool negated before calling this method, usually
11549  * FALSE is used)
11550  */
11552  SCIP_VAR** var, /**< pointer to binary problem variable */
11553  SCIP_Bool* negated /**< pointer to update the negation status */
11554  )
11555 {
11556  assert(var != NULL);
11557  assert(*var != NULL);
11558  assert(negated != NULL);
11559 
11560  while( *var != NULL )
11561  {
11562  assert(SCIPvarIsBinary(*var));
11563 
11564  switch( SCIPvarGetStatus(*var) )
11565  {
11567  if( (*var)->data.original.transvar == NULL )
11568  return SCIP_OKAY;
11569  *var = (*var)->data.original.transvar;
11570  break;
11571 
11572  case SCIP_VARSTATUS_LOOSE:
11573  case SCIP_VARSTATUS_COLUMN:
11574  case SCIP_VARSTATUS_FIXED:
11575  return SCIP_OKAY;
11576 
11578  /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
11579  if ( (*var)->data.multaggr.nvars == 1 )
11580  {
11581  assert( (*var)->data.multaggr.vars != NULL );
11582  assert( (*var)->data.multaggr.scalars != NULL );
11583  assert( SCIPvarIsBinary((*var)->data.multaggr.vars[0]) );
11584  assert(!EPSZ((*var)->data.multaggr.scalars[0], 1e-06));
11585 
11586  /* if not all variables were fully propagated, it might happen that a variable is multi-aggregated to
11587  * another variable which needs to be fixed
11588  *
11589  * e.g. x = y - 1 => (x = 0 && y = 1)
11590  * e.g. x = y + 1 => (x = 1 && y = 0)
11591  *
11592  * is this special case we need to return the muti-aggregation
11593  */
11594  if( EPSEQ((*var)->data.multaggr.constant, -1.0, 1e-06) || (EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06) && EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06)) )
11595  {
11596  assert(EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06));
11597  }
11598  else
11599  {
11600  /* @note due to fixations, a multi-aggregation can have a constant of zero and a negative scalar or even
11601  * a scalar in absolute value unequal to one, in this case this aggregation variable needs to be
11602  * fixed to zero, but should be done by another enforcement; so not depending on the scalar, we
11603  * will return the aggregation variable
11604  */
11605  if( !EPSEQ(REALABS((*var)->data.multaggr.scalars[0]), 1.0, 1e-06) )
11606  return SCIP_OKAY;
11607 
11608  assert( EPSZ((*var)->data.multaggr.constant, 1e-06) || EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06) );
11609  assert( EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06) || EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06));
11610 
11611  if( EPSZ((*var)->data.multaggr.constant, 1e-06) )
11612  {
11613  /* if the scalar is negative, either the aggregation variable is already fixed to zero or has at
11614  * least one uplock (that hopefully will enforce this fixation to zero); can it happen that this
11615  * variable itself is multi-aggregated again?
11616  */
11617  assert(EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06) ?
11618  ((SCIPvarGetUbGlobal((*var)->data.multaggr.vars[0]) < 0.5) ||
11619  SCIPvarGetNLocksUp((*var)->data.multaggr.vars[0]) > 0) : TRUE);
11620  }
11621  else
11622  {
11623  assert(EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06));
11624 
11625  *negated = !(*negated);
11626  }
11627  *var = (*var)->data.multaggr.vars[0];
11628  break;
11629  }
11630  }
11631  return SCIP_OKAY;
11632 
11633  case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */
11634  assert((*var)->data.aggregate.var != NULL);
11635  assert(SCIPvarIsBinary((*var)->data.aggregate.var));
11636  assert(EPSZ((*var)->data.aggregate.constant, 1e-06) || EPSEQ((*var)->data.aggregate.constant, 1.0, 1e-06));
11637  assert(EPSEQ((*var)->data.aggregate.scalar, 1.0, 1e-06) || EPSEQ((*var)->data.aggregate.scalar, -1.0, 1e-06));
11638  assert(EPSZ((*var)->data.aggregate.constant, 1e-06) == EPSEQ((*var)->data.aggregate.scalar, 1.0, 1e-06));
11639 
11640  *negated = (*negated != ((*var)->data.aggregate.scalar < 0.0));
11641  *var = (*var)->data.aggregate.var;
11642  break;
11643 
11644  case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */
11645  assert((*var)->negatedvar != NULL);
11646 
11647  *negated = !(*negated);
11648  *var = (*var)->negatedvar;
11649  break;
11650 
11651  default:
11652  SCIPerrorMessage("unknown variable status\n");
11653  return SCIP_INVALIDDATA;
11654  }
11655  }
11656 
11657  SCIPerrorMessage("active variable path leads to NULL pointer\n");
11658  return SCIP_INVALIDDATA;
11659 }
11660 
11661 /** transforms given variable, boundtype and bound to the corresponding active, fixed, or multi-aggregated variable
11662  * values
11663  */
11665  SCIP_VAR** var, /**< pointer to problem variable */
11666  SCIP_Real* bound, /**< pointer to bound value to transform */
11667  SCIP_BOUNDTYPE* boundtype /**< pointer to type of bound: lower or upper bound */
11668  )
11669 {
11670  assert(var != NULL);
11671  assert(*var != NULL);
11672  assert(bound != NULL);
11673  assert(boundtype != NULL);
11674 
11675  SCIPdebugMessage("get probvar bound %g of type %d of variable <%s>\n", *bound, *boundtype, (*var)->name);
11676 
11677  switch( SCIPvarGetStatus(*var) )
11678  {
11680  if( (*var)->data.original.transvar == NULL )
11681  {
11682  SCIPerrorMessage("original variable has no transformed variable attached\n");
11683  return SCIP_INVALIDDATA;
11684  }
11685  *var = (*var)->data.original.transvar;
11686  SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
11687  break;
11688 
11689  case SCIP_VARSTATUS_LOOSE:
11690  case SCIP_VARSTATUS_COLUMN:
11691  case SCIP_VARSTATUS_FIXED:
11692  break;
11693 
11695  /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
11696  if ( (*var)->data.multaggr.nvars == 1 )
11697  {
11698  assert( (*var)->data.multaggr.vars != NULL );
11699  assert( (*var)->data.multaggr.scalars != NULL );
11700  assert( (*var)->data.multaggr.scalars[0] != 0.0 );
11701 
11702  (*bound) /= (*var)->data.multaggr.scalars[0];
11703  (*bound) -= (*var)->data.multaggr.constant/(*var)->data.multaggr.scalars[0];
11704  if ( (*var)->data.multaggr.scalars[0] < 0.0 )
11705  {
11706  if ( *boundtype == SCIP_BOUNDTYPE_LOWER )
11707  *boundtype = SCIP_BOUNDTYPE_UPPER;
11708  else
11709  *boundtype = SCIP_BOUNDTYPE_LOWER;
11710  }
11711  *var = (*var)->data.multaggr.vars[0];
11712  SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
11713  }
11714  break;
11715 
11716  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = x/a - c/a */
11717  assert((*var)->data.aggregate.var != NULL);
11718  assert((*var)->data.aggregate.scalar != 0.0);
11719 
11720  (*bound) /= (*var)->data.aggregate.scalar;
11721  (*bound) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
11722  if( (*var)->data.aggregate.scalar < 0.0 )
11723  {
11724  if( *boundtype == SCIP_BOUNDTYPE_LOWER )
11725  *boundtype = SCIP_BOUNDTYPE_UPPER;
11726  else
11727  *boundtype = SCIP_BOUNDTYPE_LOWER;
11728  }
11729  *var = (*var)->data.aggregate.var;
11730  SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
11731  break;
11732 
11733  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
11734  assert((*var)->negatedvar != NULL);
11735  assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
11736  assert((*var)->negatedvar->negatedvar == *var);
11737  (*bound) = (*var)->data.negate.constant - *bound;
11738  if( *boundtype == SCIP_BOUNDTYPE_LOWER )
11739  *boundtype = SCIP_BOUNDTYPE_UPPER;
11740  else
11741  *boundtype = SCIP_BOUNDTYPE_LOWER;
11742  *var = (*var)->negatedvar;
11743  SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
11744  break;
11745 
11746  default:
11747  SCIPerrorMessage("unknown variable status\n");
11748  return SCIP_INVALIDDATA;
11749  }
11750 
11751  return SCIP_OKAY;
11752 }
11753 
11754 /** transforms given variable and domain hole to the corresponding active, fixed, or multi-aggregated variable
11755  * values
11756  */
11758  SCIP_VAR** var, /**< pointer to problem variable */
11759  SCIP_Real* left, /**< pointer to left bound of open interval in hole to transform */
11760  SCIP_Real* right /**< pointer to right bound of open interval in hole to transform */
11761  )
11762 {
11763  assert(var != NULL);
11764  assert(*var != NULL);
11765  assert(left != NULL);
11766  assert(right != NULL);
11767 
11768  SCIPdebugMessage("get probvar hole (%g,%g) of variable <%s>\n", *left, *right, (*var)->name);
11769 
11770  switch( SCIPvarGetStatus(*var) )
11771  {
11773  if( (*var)->data.original.transvar == NULL )
11774  {
11775  SCIPerrorMessage("original variable has no transformed variable attached\n");
11776  return SCIP_INVALIDDATA;
11777  }
11778  *var = (*var)->data.original.transvar;
11779  SCIP_CALL( SCIPvarGetProbvarHole(var, left, right) );
11780  break;
11781 
11782  case SCIP_VARSTATUS_LOOSE:
11783  case SCIP_VARSTATUS_COLUMN:
11784  case SCIP_VARSTATUS_FIXED:
11786  break;
11787 
11788  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = x/a - c/a */
11789  assert((*var)->data.aggregate.var != NULL);
11790  assert((*var)->data.aggregate.scalar != 0.0);
11791 
11792  /* scale back */
11793  (*left) /= (*var)->data.aggregate.scalar;
11794  (*right) /= (*var)->data.aggregate.scalar;
11795 
11796  /* shift back */
11797  (*left) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
11798  (*right) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
11799 
11800  *var = (*var)->data.aggregate.var;
11801 
11802  /* check if the interval bounds have to swapped */
11803  if( (*var)->data.aggregate.scalar < 0.0 )
11804  {
11805  SCIP_CALL( SCIPvarGetProbvarHole(var, right, left) );
11806  }
11807  else
11808  {
11809  SCIP_CALL( SCIPvarGetProbvarHole(var, left, right) );
11810  }
11811  break;
11812 
11813  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
11814  assert((*var)->negatedvar != NULL);
11815  assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
11816  assert((*var)->negatedvar->negatedvar == *var);
11817 
11818  /* shift and scale back */
11819  (*left) = (*var)->data.negate.constant - (*left);
11820  (*right) = (*var)->data.negate.constant - (*right);
11821 
11822  *var = (*var)->negatedvar;
11823 
11824  /* through the negated variable the left and right interval bound have to swapped */
11825  SCIP_CALL( SCIPvarGetProbvarHole(var, right, left) );
11826  break;
11827 
11828  default:
11829  SCIPerrorMessage("unknown variable status\n");
11830  return SCIP_INVALIDDATA;
11831  }
11832 
11833  return SCIP_OKAY;
11834 }
11835 
11836 /** transforms given variable, scalar and constant to the corresponding active, fixed, or
11837  * multi-aggregated variable, scalar and constant; if the variable resolves to a fixed variable,
11838  * "scalar" will be 0.0 and the value of the sum will be stored in "constant"; a multi-aggregation
11839  * with only one active variable (this can happen due to fixings after the multi-aggregation),
11840  * is treated like an aggregation; if the multi-aggregation constant is infinite, "scalar" will be 0.0
11841  */
11843  SCIP_VAR** var, /**< pointer to problem variable x in sum a*x + c */
11844  SCIP_SET* set, /**< global SCIP settings */
11845  SCIP_Real* scalar, /**< pointer to scalar a in sum a*x + c */
11846  SCIP_Real* constant /**< pointer to constant c in sum a*x + c */
11847  )
11848 {
11849  assert(var != NULL);
11850  assert(scalar != NULL);
11851  assert(constant != NULL);
11852 
11853  while( *var != NULL )
11854  {
11855  switch( SCIPvarGetStatus(*var) )
11856  {
11858  if( (*var)->data.original.transvar == NULL )
11859  {
11860  SCIPerrorMessage("original variable has no transformed variable attached\n");
11861  return SCIP_INVALIDDATA;
11862  }
11863  *var = (*var)->data.original.transvar;
11864  break;
11865 
11866  case SCIP_VARSTATUS_LOOSE:
11867  case SCIP_VARSTATUS_COLUMN:
11868  return SCIP_OKAY;
11869 
11870  case SCIP_VARSTATUS_FIXED: /* x = c' => a*x + c == (a*c' + c) */
11871  if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
11872  {
11873  if( SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)) )
11874  {
11875  assert(*scalar != 0.0);
11876  if( (*scalar) * (*var)->glbdom.lb > 0.0 )
11877  (*constant) = SCIPsetInfinity(set);
11878  else
11879  (*constant) = -SCIPsetInfinity(set);
11880  }
11881  else
11882  (*constant) += *scalar * (*var)->glbdom.lb;
11883  }
11884 #ifndef NDEBUG
11885  else
11886  {
11887  assert(!SCIPsetIsInfinity(set, (*constant)) || !((*scalar) * (*var)->glbdom.lb < 0.0 &&
11888  (SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)))));
11889  assert(!SCIPsetIsInfinity(set, -(*constant)) || !((*scalar) * (*var)->glbdom.lb > 0.0 &&
11890  (SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)))));
11891  }
11892 #endif
11893  *scalar = 0.0;
11894  return SCIP_OKAY;
11895 
11897  /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
11898  if ( (*var)->data.multaggr.nvars == 1 )
11899  {
11900  assert((*var)->data.multaggr.vars != NULL);
11901  assert((*var)->data.multaggr.scalars != NULL);
11902  assert((*var)->data.multaggr.vars[0] != NULL);
11903  if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
11904  {
11905  /* the multi-aggregation constant can be infinite, if one of the multi-aggregation variables
11906  * was fixed to +/-infinity; ensure that the constant is set to +/-infinity, too, and the scalar
11907  * is set to 0.0, because the multi-aggregated variable can be seen as fixed, too
11908  */
11909  if( SCIPsetIsInfinity(set, (*var)->data.multaggr.constant)
11910  || SCIPsetIsInfinity(set, -((*var)->data.multaggr.constant)) )
11911  {
11912  if( (*scalar) * (*var)->data.multaggr.constant > 0 )
11913  {
11914  assert(!SCIPsetIsInfinity(set, -(*constant)));
11915  (*constant) = SCIPsetInfinity(set);
11916  }
11917  else
11918  {
11919  assert(!SCIPsetIsInfinity(set, *constant));
11920  (*constant) = -SCIPsetInfinity(set);
11921  }
11922  (*scalar) = 0.0;
11923  }
11924  else
11925  (*constant) += *scalar * (*var)->data.multaggr.constant;
11926  }
11927  (*scalar) *= (*var)->data.multaggr.scalars[0];
11928  *var = (*var)->data.multaggr.vars[0];
11929  break;
11930  }
11931  return SCIP_OKAY;
11932 
11933  case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */
11934  assert((*var)->data.aggregate.var != NULL);
11935  assert(!SCIPsetIsInfinity(set, (*var)->data.aggregate.constant)
11936  && !SCIPsetIsInfinity(set, (*var)->data.aggregate.constant));
11937  if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
11938  (*constant) += *scalar * (*var)->data.aggregate.constant;
11939  (*scalar) *= (*var)->data.aggregate.scalar;
11940  *var = (*var)->data.aggregate.var;
11941  break;
11942 
11943  case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */
11944  assert((*var)->negatedvar != NULL);
11945  assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
11946  assert((*var)->negatedvar->negatedvar == *var);
11947  assert(!SCIPsetIsInfinity(set, (*var)->data.negate.constant)
11948  && !SCIPsetIsInfinity(set, (*var)->data.negate.constant));
11949  if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
11950  (*constant) += *scalar * (*var)->data.negate.constant;
11951  (*scalar) *= -1.0;
11952  *var = (*var)->negatedvar;
11953  break;
11954 
11955  default:
11956  SCIPerrorMessage("unknown variable status\n");
11957  SCIPABORT();
11958  return SCIP_INVALIDDATA; /*lint !e527*/
11959  }
11960  }
11961  *scalar = 0.0;
11962 
11963  return SCIP_OKAY;
11964 }
11965 
11966 /** retransforms given variable, scalar and constant to the corresponding original variable, scalar
11967  * and constant, if possible; if the retransformation is impossible, NULL is returned as variable
11968  */
11970  SCIP_VAR** var, /**< pointer to problem variable x in sum a*x + c */
11971  SCIP_Real* scalar, /**< pointer to scalar a in sum a*x + c */
11972  SCIP_Real* constant /**< pointer to constant c in sum a*x + c */
11973  )
11974 {
11975  SCIP_VAR* parentvar;
11976 
11977  assert(var != NULL);
11978  assert(*var != NULL);
11979  assert(scalar != NULL);
11980  assert(constant != NULL);
11981 
11982  while( SCIPvarGetStatus(*var) != SCIP_VARSTATUS_ORIGINAL )
11983  {
11984  /* if the variable has no parent variables, it was generated during solving and has no corresponding original
11985  * var
11986  */
11987  if( (*var)->nparentvars == 0 )
11988  {
11989  /* negated variables do not need to have a parent variables, and negated variables can exist in original
11990  * space
11991  */
11993  {
11994  *scalar *= -1.0;
11995  *constant -= (*var)->data.negate.constant * (*scalar);
11996  *var = (*var)->negatedvar;
11997 
11998  continue;
11999  }
12000  /* if the variables does not have any parent the variables was created during solving and has no original
12001  * counterpart
12002  */
12003  else
12004  {
12005  *var = NULL;
12006 
12007  return SCIP_OKAY;
12008  }
12009  }
12010 
12011  /* follow the link to the first parent variable */
12012  parentvar = (*var)->parentvars[0];
12013  assert(parentvar != NULL);
12014 
12015  switch( SCIPvarGetStatus(parentvar) )
12016  {
12018  break;
12019 
12020  case SCIP_VARSTATUS_COLUMN:
12021  case SCIP_VARSTATUS_LOOSE:
12022  case SCIP_VARSTATUS_FIXED:
12024  SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
12025  return SCIP_INVALIDDATA;
12026 
12027  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + b -> y = (x-b)/a, s*y + c = (s/a)*x + c-b*s/a */
12028  assert(parentvar->data.aggregate.var == *var);
12029  assert(parentvar->data.aggregate.scalar != 0.0);
12030  *scalar /= parentvar->data.aggregate.scalar;
12031  *constant -= parentvar->data.aggregate.constant * (*scalar);
12032  break;
12033 
12034  case SCIP_VARSTATUS_NEGATED: /* x = b - y -> y = b - x, s*y + c = -s*x + c+b*s */
12035  assert(parentvar->negatedvar != NULL);
12036  assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
12037  assert(parentvar->negatedvar->negatedvar == parentvar);
12038  *scalar *= -1.0;
12039  *constant -= parentvar->data.negate.constant * (*scalar);
12040  break;
12041 
12042  default:
12043  SCIPerrorMessage("unknown variable status\n");
12044  return SCIP_INVALIDDATA;
12045  }
12046 
12047  assert( parentvar != NULL );
12048  *var = parentvar;
12049  }
12050 
12051  return SCIP_OKAY;
12052 }
12053 
12054 /** returns whether the given variable is the direct counterpart of an original problem variable */
12056  SCIP_VAR* var /**< problem variable */
12057  )
12058 {
12059  SCIP_VAR* parentvar;
12060  assert(var != NULL);
12061 
12062  if( !SCIPvarIsTransformed(var) || var->nparentvars < 1 )
12063  return FALSE;
12064 
12065  assert(var->parentvars != NULL);
12066  parentvar = var->parentvars[0];
12067  assert(parentvar != NULL);
12068 
12069  /* we follow the aggregation tree to the root unless an original variable has been found - the first entries in the parentlist are candidates */
12070  while( parentvar->nparentvars >= 1 && SCIPvarGetStatus(parentvar) != SCIP_VARSTATUS_ORIGINAL )
12071  parentvar = parentvar->parentvars[0];
12072  assert( parentvar != NULL );
12073 
12074  return ( SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_ORIGINAL );
12075 }
12076 
12077 /** gets objective value of variable in current SCIP_LP; the value can be different from the bound stored in the variable's own
12078  * data due to diving, that operate only on the LP without updating the variables
12079  */
12081  SCIP_VAR* var /**< problem variable */
12082  )
12083 {
12084  assert(var != NULL);
12085 
12086  /* get bounds of attached variables */
12087  switch( SCIPvarGetStatus(var) )
12088  {
12090  assert(var->data.original.transvar != NULL);
12091  return SCIPvarGetObjLP(var->data.original.transvar);
12092 
12093  case SCIP_VARSTATUS_COLUMN:
12094  assert(var->data.col != NULL);
12095  return SCIPcolGetObj(var->data.col);
12096 
12097  case SCIP_VARSTATUS_LOOSE:
12098  case SCIP_VARSTATUS_FIXED:
12099  return var->obj;
12100 
12101  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
12102  assert(var->data.aggregate.var != NULL);
12103  return var->data.aggregate.scalar * SCIPvarGetObjLP(var->data.aggregate.var);
12104 
12106  SCIPerrorMessage("cannot get the objective value of a multiple aggregated variable\n");
12107  SCIPABORT();
12108  return 0.0; /*lint !e527*/
12109 
12110  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12111  assert(var->negatedvar != NULL);
12113  assert(var->negatedvar->negatedvar == var);
12114  return -SCIPvarGetObjLP(var->negatedvar);
12115 
12116  default:
12117  SCIPerrorMessage("unknown variable status\n");
12118  SCIPABORT();
12119  return 0.0; /*lint !e527*/
12120  }
12121 }
12122 
12123 /** gets lower bound of variable in current SCIP_LP; the bound can be different from the bound stored in the variable's own
12124  * data due to diving or conflict analysis, that operate only on the LP without updating the variables
12125  */
12127  SCIP_VAR* var, /**< problem variable */
12128  SCIP_SET* set /**< global SCIP settings */
12129  )
12130 {
12131  assert(var != NULL);
12132  assert(set != NULL);
12133  assert(var->scip == set->scip);
12134 
12135  /* get bounds of attached variables */
12136  switch( SCIPvarGetStatus(var) )
12137  {
12139  assert(var->data.original.transvar != NULL);
12140  return SCIPvarGetLbLP(var->data.original.transvar, set);
12141 
12142  case SCIP_VARSTATUS_COLUMN:
12143  assert(var->data.col != NULL);
12144  return SCIPcolGetLb(var->data.col);
12145 
12146  case SCIP_VARSTATUS_LOOSE:
12147  case SCIP_VARSTATUS_FIXED:
12148  return var->locdom.lb;
12149 
12150  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
12151  assert(var->data.aggregate.var != NULL);
12152  if( (var->data.aggregate.scalar > 0.0 && SCIPsetIsInfinity(set, -SCIPvarGetLbLP(var->data.aggregate.var, set)))
12153  || (var->data.aggregate.scalar < 0.0 && SCIPsetIsInfinity(set, SCIPvarGetUbLP(var->data.aggregate.var, set))) )
12154  {
12155  return -SCIPsetInfinity(set);
12156  }
12157  else if( var->data.aggregate.scalar > 0.0 )
12158  {
12159  /* a > 0 -> get lower bound of y */
12160  return var->data.aggregate.scalar * SCIPvarGetLbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
12161  }
12162  else if( var->data.aggregate.scalar < 0.0 )
12163  {
12164  /* a < 0 -> get upper bound of y */
12165  return var->data.aggregate.scalar * SCIPvarGetUbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
12166  }
12167  else
12168  {
12169  SCIPerrorMessage("scalar is zero in aggregation\n");
12170  SCIPABORT();
12171  return SCIP_INVALID; /*lint !e527*/
12172  }
12173 
12175  /**@todo get the sides of the corresponding linear constraint */
12176  SCIPerrorMessage("getting the bounds of a multiple aggregated variable is not implemented yet\n");
12177  SCIPABORT();
12178  return SCIP_INVALID; /*lint !e527*/
12179 
12180  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12181  assert(var->negatedvar != NULL);
12183  assert(var->negatedvar->negatedvar == var);
12184  return var->data.negate.constant - SCIPvarGetUbLP(var->negatedvar, set);
12185 
12186  default:
12187  SCIPerrorMessage("unknown variable status\n");
12188  SCIPABORT();
12189  return SCIP_INVALID; /*lint !e527*/
12190  }
12191 }
12192 
12193 /** gets upper bound of variable in current SCIP_LP; the bound can be different from the bound stored in the variable's own
12194  * data due to diving or conflict analysis, that operate only on the LP without updating the variables
12195  */
12197  SCIP_VAR* var, /**< problem variable */
12198  SCIP_SET* set /**< global SCIP settings */
12199  )
12200 {
12201  assert(var != NULL);
12202  assert(set != NULL);
12203  assert(var->scip == set->scip);
12204 
12205  /* get bounds of attached variables */
12206  switch( SCIPvarGetStatus(var) )
12207  {
12209  assert(var->data.original.transvar != NULL);
12210  return SCIPvarGetUbLP(var->data.original.transvar, set);
12211 
12212  case SCIP_VARSTATUS_COLUMN:
12213  assert(var->data.col != NULL);
12214  return SCIPcolGetUb(var->data.col);
12215 
12216  case SCIP_VARSTATUS_LOOSE:
12217  case SCIP_VARSTATUS_FIXED:
12218  return var->locdom.ub;
12219 
12220  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
12221  assert(var->data.aggregate.var != NULL);
12222  if( (var->data.aggregate.scalar > 0.0 && SCIPsetIsInfinity(set, SCIPvarGetUbLP(var->data.aggregate.var, set)))
12223  || (var->data.aggregate.scalar < 0.0 && SCIPsetIsInfinity(set, -SCIPvarGetLbLP(var->data.aggregate.var, set))) )
12224  {
12225  return SCIPsetInfinity(set);
12226  }
12227  if( var->data.aggregate.scalar > 0.0 )
12228  {
12229  /* a > 0 -> get upper bound of y */
12230  return var->data.aggregate.scalar * SCIPvarGetUbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
12231  }
12232  else if( var->data.aggregate.scalar < 0.0 )
12233  {
12234  /* a < 0 -> get lower bound of y */
12235  return var->data.aggregate.scalar * SCIPvarGetLbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
12236  }
12237  else
12238  {
12239  SCIPerrorMessage("scalar is zero in aggregation\n");
12240  SCIPABORT();
12241  return SCIP_INVALID; /*lint !e527*/
12242  }
12243 
12245  SCIPerrorMessage("cannot get the bounds of a multi-aggregated variable.\n");
12246  SCIPABORT();
12247  return SCIP_INVALID; /*lint !e527*/
12248 
12249  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12250  assert(var->negatedvar != NULL);
12252  assert(var->negatedvar->negatedvar == var);
12253  return var->data.negate.constant - SCIPvarGetLbLP(var->negatedvar, set);
12254 
12255  default:
12256  SCIPerrorMessage("unknown variable status\n");
12257  SCIPABORT();
12258  return SCIP_INVALID; /*lint !e527*/
12259  }
12260 }
12261 
12262 /** gets primal LP solution value of variable */
12264  SCIP_VAR* var /**< problem variable */
12265  )
12266 {
12267  assert(var != NULL);
12268 
12269  switch( SCIPvarGetStatus(var) )
12270  {
12272  if( var->data.original.transvar == NULL )
12273  return SCIP_INVALID;
12274  return SCIPvarGetLPSol(var->data.original.transvar);
12275 
12276  case SCIP_VARSTATUS_LOOSE:
12277  return SCIPvarGetBestBoundLocal(var);
12278 
12279  case SCIP_VARSTATUS_COLUMN:
12280  assert(var->data.col != NULL);
12281  return SCIPcolGetPrimsol(var->data.col);
12282 
12283  case SCIP_VARSTATUS_FIXED:
12284  assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
12285  return var->locdom.lb;
12286 
12288  {
12289  SCIP_Real lpsolval;
12290 
12291  assert(var->data.aggregate.var != NULL);
12292  lpsolval = SCIPvarGetLPSol(var->data.aggregate.var);
12293 
12294  /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
12295  * corresponding infinity value instead of performing an arithmetical transformation (compare method
12296  * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
12297  * (or is called by) a public interface method; instead, we only assert that values are finite
12298  * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
12299  * positives and negatives if the parameter <numerics/infinity> is modified by the user
12300  */
12301  assert(lpsolval > -SCIP_DEFAULT_INFINITY);
12302  assert(lpsolval < +SCIP_DEFAULT_INFINITY);
12303  return var->data.aggregate.scalar * lpsolval + var->data.aggregate.constant;
12304  }
12306  {
12307  SCIP_Real primsol;
12308  int i;
12309 
12310  assert(!var->donotmultaggr);
12311  assert(var->data.multaggr.vars != NULL);
12312  assert(var->data.multaggr.scalars != NULL);
12313  /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
12314  * assert(var->data.multaggr.nvars >= 2);
12315  */
12316  primsol = var->data.multaggr.constant;
12317  for( i = 0; i < var->data.multaggr.nvars; ++i )
12318  primsol += var->data.multaggr.scalars[i] * SCIPvarGetLPSol(var->data.multaggr.vars[i]);
12319  return primsol;
12320  }
12321  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12322  assert(var->negatedvar != NULL);
12324  assert(var->negatedvar->negatedvar == var);
12325  return var->data.negate.constant - SCIPvarGetLPSol(var->negatedvar);
12326 
12327  default:
12328  SCIPerrorMessage("unknown variable status\n");
12329  SCIPABORT();
12330  return SCIP_INVALID; /*lint !e527*/
12331  }
12332 }
12333 
12334 /** gets primal NLP solution value of variable */
12336  SCIP_VAR* var /**< problem variable */
12337  )
12338 {
12339  SCIP_Real solval;
12340  int i;
12341 
12342  assert(var != NULL);
12343 
12344  /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */
12345  switch( SCIPvarGetStatus(var) )
12346  {
12348  return SCIPvarGetNLPSol(var->data.original.transvar);
12349 
12350  case SCIP_VARSTATUS_LOOSE:
12351  case SCIP_VARSTATUS_COLUMN:
12352  return var->nlpsol;
12353 
12354  case SCIP_VARSTATUS_FIXED:
12355  assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var)); /*lint !e777*/
12356  assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var)); /*lint !e777*/
12357  assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var)); /*lint !e777*/
12358  return SCIPvarGetLbGlobal(var);
12359 
12360  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
12361  solval = SCIPvarGetNLPSol(var->data.aggregate.var);
12362  return var->data.aggregate.scalar * solval + var->data.aggregate.constant;
12363 
12365  solval = var->data.multaggr.constant;
12366  for( i = 0; i < var->data.multaggr.nvars; ++i )
12367  solval += var->data.multaggr.scalars[i] * SCIPvarGetNLPSol(var->data.multaggr.vars[i]);
12368  return solval;
12369 
12371  solval = SCIPvarGetNLPSol(var->negatedvar);
12372  return var->data.negate.constant - solval;
12373 
12374  default:
12375  SCIPerrorMessage("unknown variable status\n");
12376  SCIPABORT();
12377  return SCIP_INVALID; /*lint !e527*/
12378  }
12379 }
12380 
12381 /** gets pseudo solution value of variable at current node */
12382 static
12384  SCIP_VAR* var /**< problem variable */
12385  )
12386 {
12387  SCIP_Real pseudosol;
12388  int i;
12389 
12390  assert(var != NULL);
12391 
12392  switch( SCIPvarGetStatus(var) )
12393  {
12395  if( var->data.original.transvar == NULL )
12396  return SCIP_INVALID;
12398 
12399  case SCIP_VARSTATUS_LOOSE:
12400  case SCIP_VARSTATUS_COLUMN:
12401  return SCIPvarGetBestBoundLocal(var);
12402 
12403  case SCIP_VARSTATUS_FIXED:
12404  assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
12405  return var->locdom.lb;
12406 
12408  {
12409  SCIP_Real pseudosolval;
12410  assert(var->data.aggregate.var != NULL);
12411  /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
12412  * corresponding infinity value instead of performing an arithmetical transformation (compare method
12413  * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
12414  * (or is called by) a public interface method; instead, we only assert that values are finite
12415  * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
12416  * positives and negatives if the parameter <numerics/infinity> is modified by the user
12417  */
12418  pseudosolval = SCIPvarGetPseudoSol(var->data.aggregate.var);
12419  assert(pseudosolval > -SCIP_DEFAULT_INFINITY);
12420  assert(pseudosolval < +SCIP_DEFAULT_INFINITY);
12421  return var->data.aggregate.scalar * pseudosolval + var->data.aggregate.constant;
12422  }
12424  assert(!var->donotmultaggr);
12425  assert(var->data.multaggr.vars != NULL);
12426  assert(var->data.multaggr.scalars != NULL);
12427  /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
12428  * assert(var->data.multaggr.nvars >= 2);
12429  */
12430  pseudosol = var->data.multaggr.constant;
12431  for( i = 0; i < var->data.multaggr.nvars; ++i )
12432  pseudosol += var->data.multaggr.scalars[i] * SCIPvarGetPseudoSol(var->data.multaggr.vars[i]);
12433  return pseudosol;
12434 
12435  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12436  assert(var->negatedvar != NULL);
12438  assert(var->negatedvar->negatedvar == var);
12439  return var->data.negate.constant - SCIPvarGetPseudoSol(var->negatedvar);
12440 
12441  default:
12442  SCIPerrorMessage("unknown variable status\n");
12443  SCIPABORT();
12444  return SCIP_INVALID; /*lint !e527*/
12445  }
12446 }
12447 
12448 /** gets current LP or pseudo solution value of variable */
12450  SCIP_VAR* var, /**< problem variable */
12451  SCIP_Bool getlpval /**< should the LP solution value be returned? */
12452  )
12453 {
12454  if( getlpval )
12455  return SCIPvarGetLPSol(var);
12456  else
12457  return SCIPvarGetPseudoSol(var);
12458 }
12459 
12460 /** remembers the current solution as root solution in the problem variables */
12462  SCIP_VAR* var, /**< problem variable */
12463  SCIP_Bool roothaslp /**< is the root solution from LP? */
12464  )
12465 {
12466  assert(var != NULL);
12467 
12468  var->rootsol = SCIPvarGetSol(var, roothaslp);
12469 }
12470 
12471 /** updates the current solution as best root solution of the given variable if it is better */
12473  SCIP_VAR* var, /**< problem variable */
12474  SCIP_SET* set, /**< global SCIP settings */
12475  SCIP_Real rootsol, /**< root solution value */
12476  SCIP_Real rootredcost, /**< root reduced cost */
12477  SCIP_Real rootlpobjval /**< objective value of the root LP */
12478  )
12479 {
12480  assert(var != NULL);
12481  assert(set != NULL);
12482  assert(var->scip == set->scip);
12483 
12484  /* if reduced cost are zero nothing to update */
12485  if( SCIPsetIsFeasZero(set, rootredcost) )
12486  return;
12487 
12488  /* check if we have already a best combination stored */
12489  if( !SCIPsetIsFeasZero(set, var->bestrootredcost) )
12490  {
12491  SCIP_Real currcutoffbound;
12492  SCIP_Real cutoffbound;
12493  SCIP_Real bound;
12494 
12495  /* compute the cutoff bound which would improve the corresponding bound with the current stored root solution,
12496  * root reduced cost, and root LP objective value combination
12497  */
12498  if( var->bestrootredcost > 0.0 )
12499  bound = SCIPvarGetUbGlobal(var);
12500  else
12501  bound = SCIPvarGetLbGlobal(var);
12502 
12503  currcutoffbound = (bound - var->bestrootsol) * var->bestrootredcost + var->bestrootlpobjval;
12504 
12505  /* compute the cutoff bound which would improve the corresponding bound with new root solution, root reduced
12506  * cost, and root LP objective value combination
12507  */
12508  if( rootredcost > 0.0 )
12509  bound = SCIPvarGetUbGlobal(var);
12510  else
12511  bound = SCIPvarGetLbGlobal(var);
12512 
12513  cutoffbound = (bound - rootsol) * rootredcost + rootlpobjval;
12514 
12515  /* check if an improving root solution, root reduced cost, and root LP objective value is at hand */
12516  if( cutoffbound > currcutoffbound )
12517  {
12518  SCIPdebugMessage("-> <%s> update potetial cutoff bound <%g> -> <%g>\n",
12519  SCIPvarGetName(var), currcutoffbound, cutoffbound);
12520 
12521  var->bestrootsol = rootsol;
12522  var->bestrootredcost = rootredcost;
12523  var->bestrootlpobjval = rootlpobjval;
12524  }
12525  }
12526  else
12527  {
12528  SCIPdebugMessage("-> <%s> initialize best root reduced cost information\n", SCIPvarGetName(var));
12529  SCIPdebugMessage(" -> rootsol <%g>\n", rootsol);
12530  SCIPdebugMessage(" -> rootredcost <%g>\n", rootredcost);
12531  SCIPdebugMessage(" -> rootlpobjval <%g>\n", rootlpobjval);
12532 
12533  var->bestrootsol = rootsol;
12534  var->bestrootredcost = rootredcost;
12535  var->bestrootlpobjval = rootlpobjval;
12536  }
12537 }
12538 
12539 /** returns the solution of the variable in the last root node's relaxation, if the root relaxation is not yet
12540  * completely solved, zero is returned
12541  */
12543  SCIP_VAR* var /**< problem variable */
12544  )
12545 {
12546  SCIP_Real rootsol;
12547  int i;
12548 
12549  assert(var != NULL);
12550 
12551  switch( SCIPvarGetStatus(var) )
12552  {
12554  if( var->data.original.transvar == NULL )
12555  return 0.0;
12556  return SCIPvarGetRootSol(var->data.original.transvar);
12557 
12558  case SCIP_VARSTATUS_LOOSE:
12559  case SCIP_VARSTATUS_COLUMN:
12560  return var->rootsol;
12561 
12562  case SCIP_VARSTATUS_FIXED:
12563  assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
12564  return var->locdom.lb;
12565 
12567  assert(var->data.aggregate.var != NULL);
12568  /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
12569  * corresponding infinity value instead of performing an arithmetical transformation (compare method
12570  * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
12571  * (or is called by) a public interface method; instead, we only assert that values are finite
12572  * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
12573  * positives and negatives if the parameter <numerics/infinity> is modified by the user
12574  */
12578 
12580  assert(!var->donotmultaggr);
12581  assert(var->data.multaggr.vars != NULL);
12582  assert(var->data.multaggr.scalars != NULL);
12583  /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
12584  * assert(var->data.multaggr.nvars >= 2);
12585  */
12586  rootsol = var->data.multaggr.constant;
12587  for( i = 0; i < var->data.multaggr.nvars; ++i )
12588  rootsol += var->data.multaggr.scalars[i] * SCIPvarGetRootSol(var->data.multaggr.vars[i]);
12589  return rootsol;
12590 
12591  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12592  assert(var->negatedvar != NULL);
12594  assert(var->negatedvar->negatedvar == var);
12595  return var->data.negate.constant - SCIPvarGetRootSol(var->negatedvar);
12596 
12597  default:
12598  SCIPerrorMessage("unknown variable status\n");
12599  SCIPABORT();
12600  return SCIP_INVALID; /*lint !e527*/
12601  }
12602 }
12603 
12604 /** returns for given variable the reduced cost */
12606  SCIP_VAR* var, /**< problem variable */
12607  SCIP_SET* set, /**< global SCIP settings */
12608  SCIP_Bool varfixing, /**< FALSE if for x == 0, TRUE for x == 1 */
12609  SCIP_STAT* stat, /**< problem statistics */
12610  SCIP_LP* lp /**< current LP data */
12611  )
12612 {
12614  {
12615  SCIP_COL* col;
12616  SCIP_Real primsol;
12617  SCIP_BASESTAT basestat;
12618  SCIP_Bool lpissolbasic;
12619 
12620  col = SCIPvarGetCol(var);
12621  assert(col != NULL);
12622 
12623  basestat = SCIPcolGetBasisStatus(col);
12624  lpissolbasic = SCIPlpIsSolBasic(lp);
12625  primsol = SCIPcolGetPrimsol(col);
12626 
12627  if( (lpissolbasic && (basestat == SCIP_BASESTAT_LOWER || basestat == SCIP_BASESTAT_UPPER)) ||
12628  (!lpissolbasic && (SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol) || SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol))) )
12629  {
12630  SCIP_Real redcost = SCIPcolGetRedcost(col, stat, lp);
12631 
12632  assert(((!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol)) ||
12633  (lpissolbasic && basestat == SCIP_BASESTAT_LOWER)) ? (!SCIPsetIsFeasNegative(set, redcost) ||
12635  assert(((!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol)) ||
12636  (lpissolbasic && basestat == SCIP_BASESTAT_UPPER)) ? (!SCIPsetIsFeasPositive(set, redcost) ||
12637  SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var))) : TRUE);
12638 
12639  if( (varfixing && ((lpissolbasic && basestat == SCIP_BASESTAT_LOWER) ||
12640  (!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol)))) ||
12641  (!varfixing && ((lpissolbasic && basestat == SCIP_BASESTAT_UPPER) ||
12642  (!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol)))) )
12643  return redcost;
12644  else
12645  return 0.0;
12646  }
12647 
12648  return 0.0;
12649  }
12650 
12651  return 0.0;
12652 }
12653 
12654 /** returns for the given binary variable the reduced cost which are given by the variable itself and its implication if
12655  * the binary variable is fixed to the given value
12656  */
12658  SCIP_VAR* var, /**< problem variable */
12659  SCIP_SET* set, /**< global SCIP settings */
12660  SCIP_Bool varfixing, /**< FALSE if for x == 0, TRUE for x == 1 */
12661  SCIP_STAT* stat, /**< problem statistics */
12662  SCIP_LP* lp /**< current LP data */
12663  )
12664 {
12665  SCIP_VAR** vars;
12666  SCIP_VAR* implvar;
12667  SCIP_BOUNDTYPE* boundtypes;
12668  SCIP_Real implredcost;
12669  SCIP_Real redcost;
12670  int nbinvars;
12671  int v;
12672 
12673  assert(SCIPvarIsBinary(var));
12674  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
12675 
12676  /* get reduced cost of given variable */
12677  implredcost = SCIPvarGetRedcost(var, set, varfixing, stat, lp);
12678 
12679  /* collect binary implication information */
12680  nbinvars = SCIPimplicsGetNBinImpls(var->implics, varfixing);
12681  vars = SCIPimplicsGetVars(var->implics, varfixing);
12682  boundtypes = SCIPimplicsGetTypes(var->implics, varfixing);
12683 
12684  for( v = 0; v < nbinvars; ++v )
12685  {
12686  implvar = vars[v];
12687  assert(implvar != NULL);
12688 
12689  /* ignore binary variable which are fixed */
12690  if( SCIPvarGetLbLocal(implvar) > 0.5 || SCIPvarGetUbLocal(implvar) < 0.5 )
12691  continue;
12692 
12693  assert((SCIP_Bool)SCIP_BOUNDTYPE_LOWER == FALSE);
12694  assert((SCIP_Bool)SCIP_BOUNDTYPE_UPPER == TRUE);
12695 
12696  if( (SCIP_Bool)boundtypes[v] != varfixing )
12697  redcost = SCIPvarGetRedcost(implvar, set, boundtypes[v] == SCIP_BOUNDTYPE_LOWER, stat, lp);
12698  else
12699  redcost = -SCIPvarGetRedcost(implvar, set, boundtypes[v] == SCIP_BOUNDTYPE_LOWER, stat, lp);
12700 
12701  if( !SCIPsetIsFeasZero(set, redcost) )
12702  implredcost += redcost;
12703  }
12704 
12705  return implredcost;
12706 }
12707 
12708 /** returns the best solution (w.r.t. root reduced cost propagation) of the variable in the root node's relaxation, if
12709  * the root relaxation is not yet completely solved, zero is returned
12710  */
12712  SCIP_VAR* var /**< problem variable */
12713  )
12714 {
12715  SCIP_Real rootsol;
12716  int i;
12717 
12718  assert(var != NULL);
12719 
12720  switch( SCIPvarGetStatus(var) )
12721  {
12723  if( var->data.original.transvar == NULL )
12724  return 0.0;
12726 
12727  case SCIP_VARSTATUS_LOOSE:
12728  case SCIP_VARSTATUS_COLUMN:
12729  return var->bestrootsol;
12730 
12731  case SCIP_VARSTATUS_FIXED:
12732  assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
12733  return var->locdom.lb;
12734 
12736  assert(var->data.aggregate.var != NULL);
12737  /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
12738  * corresponding infinity value instead of performing an arithmetical transformation (compare method
12739  * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
12740  * (or is called by) a public interface method; instead, we only assert that values are finite
12741  * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
12742  * positives and negatives if the parameter <numerics/infinity> is modified by the user
12743  */
12747 
12749  assert(!var->donotmultaggr);
12750  assert(var->data.multaggr.vars != NULL);
12751  assert(var->data.multaggr.scalars != NULL);
12752  /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
12753  * assert(var->data.multaggr.nvars >= 2);
12754  */
12755  rootsol = var->data.multaggr.constant;
12756  for( i = 0; i < var->data.multaggr.nvars; ++i )
12757  rootsol += var->data.multaggr.scalars[i] * SCIPvarGetBestRootSol(var->data.multaggr.vars[i]);
12758  return rootsol;
12759 
12760  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12761  assert(var->negatedvar != NULL);
12763  assert(var->negatedvar->negatedvar == var);
12764  return var->data.negate.constant - SCIPvarGetBestRootSol(var->negatedvar);
12765 
12766  default:
12767  SCIPerrorMessage("unknown variable status\n");
12768  SCIPABORT();
12769  return 0.0; /*lint !e527*/
12770  }
12771 }
12772 
12773 /** returns the best reduced costs (w.r.t. root reduced cost propagation) of the variable in the root node's relaxation,
12774  * if the root relaxation is not yet completely solved, or the variable was no column of the root LP, SCIP_INVALID is
12775  * returned
12776  */
12778  SCIP_VAR* var /**< problem variable */
12779  )
12780 {
12781  assert(var != NULL);
12782 
12783  switch( SCIPvarGetStatus(var) )
12784  {
12786  if( var->data.original.transvar == NULL )
12787  return SCIP_INVALID;
12789 
12790  case SCIP_VARSTATUS_LOOSE:
12791  case SCIP_VARSTATUS_COLUMN:
12792  return var->bestrootredcost;
12793 
12794  case SCIP_VARSTATUS_FIXED:
12798  return 0.0;
12799 
12800  default:
12801  SCIPerrorMessage("unknown variable status\n");
12802  SCIPABORT();
12803  return 0.0; /*lint !e527*/
12804  }
12805 }
12806 
12807 /** returns the best objective value (w.r.t. root reduced cost propagation) of the root LP which belongs the root
12808  * reduced cost which is accessible via SCIPvarGetRootRedcost() or the variable was no column of the root LP,
12809  * SCIP_INVALID is returned
12810  */
12812  SCIP_VAR* var /**< problem variable */
12813  )
12814 {
12815  assert(var != NULL);
12816 
12817  switch( SCIPvarGetStatus(var) )
12818  {
12820  if( var->data.original.transvar == NULL )
12821  return SCIP_INVALID;
12823 
12824  case SCIP_VARSTATUS_LOOSE:
12825  case SCIP_VARSTATUS_COLUMN:
12826  return var->bestrootlpobjval;
12827 
12828  case SCIP_VARSTATUS_FIXED:
12832  return SCIP_INVALID;
12833 
12834  default:
12835  SCIPerrorMessage("unknown variable status\n");
12836  SCIPABORT();
12837  return SCIP_INVALID; /*lint !e527*/
12838  }
12839 }
12840 
12841 /** set the given solution as the best root solution w.r.t. root reduced cost propagation in the variables */
12843  SCIP_VAR* var, /**< problem variable */
12844  SCIP_Real rootsol, /**< root solution value */
12845  SCIP_Real rootredcost, /**< root reduced cost */
12846  SCIP_Real rootlpobjval /**< objective value of the root LP */
12847  )
12848 {
12849  assert(var != NULL);
12850 
12851  var->bestrootsol = rootsol;
12852  var->bestrootredcost = rootredcost;
12853  var->bestrootlpobjval = rootlpobjval;
12854 }
12855 
12856 /** stores the solution value as relaxation solution in the problem variable */
12858  SCIP_VAR* var, /**< problem variable */
12859  SCIP_SET* set, /**< global SCIP settings */
12860  SCIP_RELAXATION* relaxation, /**< global relaxation data */
12861  SCIP_Real solval, /**< solution value in the current relaxation solution */
12862  SCIP_Bool updateobj /**< should the objective value be updated? */
12863  )
12864 {
12865  assert(var != NULL);
12866  assert(relaxation != NULL);
12867  assert(set != NULL);
12868  assert(var->scip == set->scip);
12869 
12870  /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */
12871  switch( SCIPvarGetStatus(var) )
12872  {
12874  SCIP_CALL( SCIPvarSetRelaxSol(var->data.original.transvar, set, relaxation, solval, updateobj) );
12875  break;
12876 
12877  case SCIP_VARSTATUS_LOOSE:
12878  case SCIP_VARSTATUS_COLUMN:
12879  if( updateobj )
12880  SCIPrelaxationSolObjAdd(relaxation, var->obj * (solval - var->relaxsol));
12881  var->relaxsol = solval;
12882  break;
12883 
12884  case SCIP_VARSTATUS_FIXED:
12885  if( !SCIPsetIsEQ(set, solval, var->glbdom.lb) )
12886  {
12887  SCIPerrorMessage("cannot set relaxation solution value for variable <%s> fixed to %.15g to different value %.15g\n",
12888  SCIPvarGetName(var), var->glbdom.lb, solval);
12889  return SCIP_INVALIDDATA;
12890  }
12891  break;
12892 
12893  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
12894  assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
12895  SCIP_CALL( SCIPvarSetRelaxSol(var->data.aggregate.var, set, relaxation,
12896  (solval - var->data.aggregate.constant)/var->data.aggregate.scalar, updateobj) );
12897  break;
12899  SCIPerrorMessage("cannot set solution value for multiple aggregated variable\n");
12900  return SCIP_INVALIDDATA;
12901 
12903  SCIP_CALL( SCIPvarSetRelaxSol(var->negatedvar, set, relaxation, var->data.negate.constant - solval, updateobj) );
12904  break;
12905 
12906  default:
12907  SCIPerrorMessage("unknown variable status\n");
12908  return SCIP_INVALIDDATA;
12909  }
12910 
12911  return SCIP_OKAY;
12912 }
12913 
12914 /** returns the solution value of the problem variable in the relaxation solution
12915  *
12916  * @todo Inline this function - similar to SCIPvarGetLPSol_rec.
12917  */
12919  SCIP_VAR* var, /**< problem variable */
12920  SCIP_SET* set /**< global SCIP settings */
12921  )
12922 {
12923  SCIP_Real solvalsum;
12924  SCIP_Real solval;
12925  int i;
12926 
12927  assert(var != NULL);
12928  assert(set != NULL);
12929  assert(var->scip == set->scip);
12930 
12931  /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */
12932  switch( SCIPvarGetStatus(var) )
12933  {
12935  return SCIPvarGetRelaxSol(var->data.original.transvar, set);
12936 
12937  case SCIP_VARSTATUS_LOOSE:
12938  case SCIP_VARSTATUS_COLUMN:
12939  return var->relaxsol;
12940 
12941  case SCIP_VARSTATUS_FIXED:
12942  assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var)); /*lint !e777*/
12943  assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var)); /*lint !e777*/
12944  assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var)); /*lint !e777*/
12945  return SCIPvarGetLbGlobal(var);
12946 
12947  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
12948  solval = SCIPvarGetRelaxSol(var->data.aggregate.var, set);
12949  if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) )
12950  {
12951  if( var->data.aggregate.scalar * solval > 0.0 )
12952  return SCIPsetInfinity(set);
12953  if( var->data.aggregate.scalar * solval < 0.0 )
12954  return -SCIPsetInfinity(set);
12955  }
12956  return var->data.aggregate.scalar * solval + var->data.aggregate.constant;
12957 
12959  solvalsum = var->data.multaggr.constant;
12960  for( i = 0; i < var->data.multaggr.nvars; ++i )
12961  {
12962  solval = SCIPvarGetRelaxSol(var->data.multaggr.vars[i], set);
12963  if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) )
12964  {
12965  if( var->data.multaggr.scalars[i] * solval > 0.0 )
12966  return SCIPsetInfinity(set);
12967  if( var->data.multaggr.scalars[i] * solval < 0.0 )
12968  return -SCIPsetInfinity(set);
12969  }
12970  solvalsum += var->data.multaggr.scalars[i] * solval;
12971  }
12972  return solvalsum;
12973 
12975  solval = SCIPvarGetRelaxSol(var->negatedvar, set);
12976  if( SCIPsetIsInfinity(set, solval) )
12977  return -SCIPsetInfinity(set);
12978  if( SCIPsetIsInfinity(set, -solval) )
12979  return SCIPsetInfinity(set);
12980  return var->data.negate.constant - solval;
12981 
12982  default:
12983  SCIPerrorMessage("unknown variable status\n");
12984  SCIPABORT();
12985  return SCIP_INVALID; /*lint !e527*/
12986  }
12987 }
12988 
12989 /** returns the solution value of the transformed problem variable in the relaxation solution */
12991  SCIP_VAR* var /**< problem variable */
12992  )
12993 {
12994  assert(var != NULL);
12996 
12997  return var->relaxsol;
12998 }
12999 
13000 /** stores the solution value as NLP solution in the problem variable */
13002  SCIP_VAR* var, /**< problem variable */
13003  SCIP_SET* set, /**< global SCIP settings */
13004  SCIP_Real solval /**< solution value in the current NLP solution */
13005  )
13006 {
13007  assert(var != NULL);
13008  assert(set != NULL);
13009  assert(var->scip == set->scip);
13010 
13011  /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */
13012  switch( SCIPvarGetStatus(var) )
13013  {
13015  SCIP_CALL( SCIPvarSetNLPSol(var->data.original.transvar, set, solval) );
13016  break;
13017 
13018  case SCIP_VARSTATUS_LOOSE:
13019  case SCIP_VARSTATUS_COLUMN:
13020  var->nlpsol = solval;
13021  break;
13022 
13023  case SCIP_VARSTATUS_FIXED:
13024  if( !SCIPsetIsEQ(set, solval, var->glbdom.lb) )
13025  {
13026  SCIPerrorMessage("cannot set NLP solution value for variable <%s> fixed to %.15g to different value %.15g\n",
13027  SCIPvarGetName(var), var->glbdom.lb, solval);
13028  SCIPABORT();
13029  return SCIP_INVALIDCALL; /*lint !e527*/
13030  }
13031  break;
13032 
13033  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
13034  assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
13035  SCIP_CALL( SCIPvarSetNLPSol(var->data.aggregate.var, set, (solval - var->data.aggregate.constant)/var->data.aggregate.scalar) );
13036  break;
13037 
13039  SCIPerrorMessage("cannot set solution value for multiple aggregated variable\n");
13040  SCIPABORT();
13041  return SCIP_INVALIDCALL; /*lint !e527*/
13042 
13044  SCIP_CALL( SCIPvarSetNLPSol(var->negatedvar, set, var->data.negate.constant - solval) );
13045  break;
13046 
13047  default:
13048  SCIPerrorMessage("unknown variable status\n");
13049  SCIPABORT();
13050  return SCIP_ERROR; /*lint !e527*/
13051  }
13052 
13053  return SCIP_OKAY;
13054 }
13055 
13056 /** returns a weighted average solution value of the variable in all feasible primal solutions found so far */
13058  SCIP_VAR* var /**< problem variable */
13059  )
13060 {
13061  SCIP_Real avgsol;
13062  int i;
13063 
13064  assert(var != NULL);
13065 
13066  switch( SCIPvarGetStatus(var) )
13067  {
13069  if( var->data.original.transvar == NULL )
13070  return 0.0;
13071  return SCIPvarGetAvgSol(var->data.original.transvar);
13072 
13073  case SCIP_VARSTATUS_LOOSE:
13074  case SCIP_VARSTATUS_COLUMN:
13075  avgsol = var->primsolavg;
13076  avgsol = MAX(avgsol, var->glbdom.lb);
13077  avgsol = MIN(avgsol, var->glbdom.ub);
13078  return avgsol;
13079 
13080  case SCIP_VARSTATUS_FIXED:
13081  assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13082  return var->locdom.lb;
13083 
13085  assert(var->data.aggregate.var != NULL);
13086  return var->data.aggregate.scalar * SCIPvarGetAvgSol(var->data.aggregate.var)
13087  + var->data.aggregate.constant;
13088 
13090  assert(!var->donotmultaggr);
13091  assert(var->data.multaggr.vars != NULL);
13092  assert(var->data.multaggr.scalars != NULL);
13093  /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13094  * assert(var->data.multaggr.nvars >= 2);
13095  */
13096  avgsol = var->data.multaggr.constant;
13097  for( i = 0; i < var->data.multaggr.nvars; ++i )
13098  avgsol += var->data.multaggr.scalars[i] * SCIPvarGetAvgSol(var->data.multaggr.vars[i]);
13099  return avgsol;
13100 
13101  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13102  assert(var->negatedvar != NULL);
13104  assert(var->negatedvar->negatedvar == var);
13105  return var->data.negate.constant - SCIPvarGetAvgSol(var->negatedvar);
13106 
13107  default:
13108  SCIPerrorMessage("unknown variable status\n");
13109  SCIPABORT();
13110  return 0.0; /*lint !e527*/
13111  }
13112 }
13113 
13114 /** returns solution value and index of variable lower bound that is closest to the variable's value in the given primal solution
13115  * or current LP solution if no primal solution is given; returns an index of -1 if no variable lower bound is available
13116  */
13118  SCIP_VAR* var, /**< active problem variable */
13119  SCIP_SOL* sol, /**< primal solution, or NULL for LP solution */
13120  SCIP_SET* set, /**< global SCIP settings */
13121  SCIP_STAT* stat, /**< problem statistics */
13122  SCIP_Real* closestvlb, /**< pointer to store the value of the closest variable lower bound */
13123  int* closestvlbidx /**< pointer to store the index of the closest variable lower bound */
13124  )
13125 {
13126  int nvlbs;
13127 
13128  assert(var != NULL);
13129  assert(stat != NULL);
13130  assert(set != NULL);
13131  assert(var->scip == set->scip);
13132  assert(closestvlb != NULL);
13133  assert(closestvlbidx != NULL);
13134 
13135  *closestvlbidx = -1;
13136  *closestvlb = SCIP_REAL_MIN;
13137 
13138  nvlbs = SCIPvarGetNVlbs(var);
13139  if( nvlbs > 0 )
13140  {
13141  SCIP_VAR** vlbvars;
13142  SCIP_Real* vlbcoefs;
13143  SCIP_Real* vlbconsts;
13144  int i;
13145 
13146  vlbvars = SCIPvarGetVlbVars(var);
13147  vlbcoefs = SCIPvarGetVlbCoefs(var);
13148  vlbconsts = SCIPvarGetVlbConstants(var);
13149 
13150  /* check for cached values */
13151  if( var->closestvblpcount == stat->lpcount && var->closestvlbidx != -1 && sol == NULL)
13152  {
13153  i = var->closestvlbidx;
13154  assert(0 <= i && i < nvlbs);
13155  assert(SCIPvarIsActive(vlbvars[i]));
13156  *closestvlbidx = i;
13157  *closestvlb = vlbcoefs[i] * SCIPvarGetLPSol(vlbvars[i]) + vlbconsts[i];
13158  }
13159  else
13160  {
13161  /* search best VUB */
13162  for( i = 0; i < nvlbs; i++ )
13163  {
13164  if( SCIPvarIsActive(vlbvars[i]) )
13165  {
13166  SCIP_Real vlbsol;
13167 
13168  vlbsol = vlbcoefs[i] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[i]) : SCIPsolGetVal(sol, set, stat, vlbvars[i])) + vlbconsts[i];
13169  if( vlbsol > *closestvlb )
13170  {
13171  *closestvlb = vlbsol;
13172  *closestvlbidx = i;
13173  }
13174  }
13175  }
13176 
13177  if( sol == NULL )
13178  {
13179  /* update cached value */
13180  if( var->closestvblpcount != stat->lpcount )
13181  var->closestvubidx = -1;
13182  var->closestvlbidx = *closestvlbidx;
13183  var->closestvblpcount = stat->lpcount;
13184  }
13185  }
13186  }
13187 }
13188 
13189 /** returns solution value and index of variable upper bound that is closest to the variable's value in the given primal solution;
13190  * or current LP solution if no primal solution is given; returns an index of -1 if no variable upper bound is available
13191  */
13193  SCIP_VAR* var, /**< active problem variable */
13194  SCIP_SOL* sol, /**< primal solution, or NULL for LP solution */
13195  SCIP_SET* set, /**< global SCIP settings */
13196  SCIP_STAT* stat, /**< problem statistics */
13197  SCIP_Real* closestvub, /**< pointer to store the value of the closest variable upper bound */
13198  int* closestvubidx /**< pointer to store the index of the closest variable upper bound */
13199  )
13200 {
13201  int nvubs;
13202 
13203  assert(var != NULL);
13204  assert(set != NULL);
13205  assert(var->scip == set->scip);
13206  assert(closestvub != NULL);
13207  assert(closestvubidx != NULL);
13208 
13209  *closestvubidx = -1;
13210  *closestvub = SCIP_REAL_MAX;
13211 
13212  nvubs = SCIPvarGetNVubs(var);
13213  if( nvubs > 0 )
13214  {
13215  SCIP_VAR** vubvars;
13216  SCIP_Real* vubcoefs;
13217  SCIP_Real* vubconsts;
13218  int i;
13219 
13220  vubvars = SCIPvarGetVubVars(var);
13221  vubcoefs = SCIPvarGetVubCoefs(var);
13222  vubconsts = SCIPvarGetVubConstants(var);
13223 
13224  /* check for cached values */
13225  if( var->closestvblpcount == stat->lpcount && var->closestvubidx != -1 && sol == NULL)
13226  {
13227  i = var->closestvubidx;
13228  assert(0 <= i && i < nvubs);
13229  assert(SCIPvarIsActive(vubvars[i]));
13230  *closestvubidx = i;
13231  *closestvub = vubcoefs[i] * SCIPvarGetLPSol(vubvars[i]) + vubconsts[i];
13232  }
13233  else
13234  {
13235  /* search best VUB */
13236  for( i = 0; i < nvubs; i++ )
13237  {
13238  if( SCIPvarIsActive(vubvars[i]) )
13239  {
13240  SCIP_Real vubsol;
13241 
13242  vubsol = vubcoefs[i] * (sol == NULL ? SCIPvarGetLPSol(vubvars[i]) : SCIPsolGetVal(sol, set, stat, vubvars[i])) + vubconsts[i];
13243  if( vubsol < *closestvub )
13244  {
13245  *closestvub = vubsol;
13246  *closestvubidx = i;
13247  }
13248  }
13249  }
13250 
13251  if( sol == NULL )
13252  {
13253  /* update cached value */
13254  if( var->closestvblpcount != stat->lpcount )
13255  var->closestvlbidx = -1;
13256  var->closestvubidx = *closestvubidx;
13257  var->closestvblpcount = stat->lpcount;
13258  }
13259  }
13260  }
13261 }
13262 
13263 /** resolves variable to columns and adds them with the coefficient to the row */
13265  SCIP_VAR* var, /**< problem variable */
13266  BMS_BLKMEM* blkmem, /**< block memory */
13267  SCIP_SET* set, /**< global SCIP settings */
13268  SCIP_STAT* stat, /**< problem statistics */
13269  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
13270  SCIP_PROB* prob, /**< problem data */
13271  SCIP_LP* lp, /**< current LP data */
13272  SCIP_ROW* row, /**< LP row */
13273  SCIP_Real val /**< value of coefficient */
13274  )
13275 {
13276  int i;
13277 
13278  assert(var != NULL);
13279  assert(set != NULL);
13280  assert(var->scip == set->scip);
13281  assert(row != NULL);
13282  assert(!SCIPsetIsInfinity(set, REALABS(val)));
13283 
13284  SCIPdebugMessage("adding coefficient %g<%s> to row <%s>\n", val, var->name, row->name);
13285 
13286  if ( SCIPsetIsZero(set, val) )
13287  return SCIP_OKAY;
13288 
13289  switch( SCIPvarGetStatus(var) )
13290  {
13292  if( var->data.original.transvar == NULL )
13293  {
13294  SCIPerrorMessage("cannot add untransformed original variable <%s> to LP row <%s>\n", var->name, row->name);
13295  return SCIP_INVALIDDATA;
13296  }
13297  SCIP_CALL( SCIPvarAddToRow(var->data.original.transvar, blkmem, set, stat, eventqueue, prob, lp, row, val) );
13298  return SCIP_OKAY;
13299 
13300  case SCIP_VARSTATUS_LOOSE:
13301  /* add globally fixed variables as constant */
13302  if( SCIPsetIsEQ(set, var->glbdom.lb, var->glbdom.ub) )
13303  {
13304  SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, val * var->glbdom.lb) );
13305  return SCIP_OKAY;
13306  }
13307  /* convert loose variable into column */
13308  SCIP_CALL( SCIPvarColumn(var, blkmem, set, stat, prob, lp) );
13309  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
13310  /*lint -fallthrough*/
13311 
13312  case SCIP_VARSTATUS_COLUMN:
13313  assert(var->data.col != NULL);
13314  assert(var->data.col->var == var);
13315  SCIP_CALL( SCIProwIncCoef(row, blkmem, set, eventqueue, lp, var->data.col, val) );
13316  return SCIP_OKAY;
13317 
13318  case SCIP_VARSTATUS_FIXED:
13319  assert(var->glbdom.lb == var->glbdom.ub); /*lint !e777*/
13320  assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13321  assert(var->locdom.lb == var->glbdom.lb); /*lint !e777*/
13322  assert(!SCIPsetIsInfinity(set, REALABS(var->locdom.lb)));
13323  SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, val * var->locdom.lb) );
13324  return SCIP_OKAY;
13325 
13327  assert(var->data.aggregate.var != NULL);
13328  SCIP_CALL( SCIPvarAddToRow(var->data.aggregate.var, blkmem, set, stat, eventqueue, prob, lp,
13329  row, var->data.aggregate.scalar * val) );
13330  SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.aggregate.constant * val) );
13331  return SCIP_OKAY;
13332 
13334  assert(!var->donotmultaggr);
13335  assert(var->data.multaggr.vars != NULL);
13336  assert(var->data.multaggr.scalars != NULL);
13337  /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13338  * assert(var->data.multaggr.nvars >= 2);
13339  */
13340  for( i = 0; i < var->data.multaggr.nvars; ++i )
13341  {
13342  SCIP_CALL( SCIPvarAddToRow(var->data.multaggr.vars[i], blkmem, set, stat, eventqueue, prob, lp,
13343  row, var->data.multaggr.scalars[i] * val) );
13344  }
13345  SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.multaggr.constant * val) );
13346  return SCIP_OKAY;
13347 
13348  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13349  assert(var->negatedvar != NULL);
13351  assert(var->negatedvar->negatedvar == var);
13352  SCIP_CALL( SCIPvarAddToRow(var->negatedvar, blkmem, set, stat, eventqueue, prob, lp, row, -val) );
13353  SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.negate.constant * val) );
13354  return SCIP_OKAY;
13355 
13356  default:
13357  SCIPerrorMessage("unknown variable status\n");
13358  return SCIP_INVALIDDATA;
13359  }
13360 }
13361 
13362 /** updates the pseudo costs of the given variable and the global pseudo costs after a change of
13363  * "solvaldelta" in the variable's solution value and resulting change of "objdelta" in the in the LP's objective value
13364  */
13366  SCIP_VAR* var, /**< problem variable */
13367  SCIP_SET* set, /**< global SCIP settings */
13368  SCIP_STAT* stat, /**< problem statistics */
13369  SCIP_Real solvaldelta, /**< difference of variable's new LP value - old LP value */
13370  SCIP_Real objdelta, /**< difference of new LP's objective value - old LP's objective value */
13371  SCIP_Real weight /**< weight in (0,1] of this update in pseudo cost sum */
13372  )
13373 {
13374  assert(var != NULL);
13375  assert(set != NULL);
13376  assert(var->scip == set->scip);
13377  assert(stat != NULL);
13378 
13379  /* check if history statistics should be collected for a variable */
13380  if( !stat->collectvarhistory )
13381  return SCIP_OKAY;
13382 
13383  switch( SCIPvarGetStatus(var) )
13384  {
13386  if( var->data.original.transvar == NULL )
13387  {
13388  SCIPerrorMessage("cannot update pseudo costs of original untransformed variable\n");
13389  return SCIP_INVALIDDATA;
13390  }
13391  SCIP_CALL( SCIPvarUpdatePseudocost(var->data.original.transvar, set, stat, solvaldelta, objdelta, weight) );
13392  return SCIP_OKAY;
13393 
13394  case SCIP_VARSTATUS_LOOSE:
13395  case SCIP_VARSTATUS_COLUMN:
13396  SCIPhistoryUpdatePseudocost(var->history, set, solvaldelta, objdelta, weight);
13397  SCIPhistoryUpdatePseudocost(var->historycrun, set, solvaldelta, objdelta, weight);
13398  SCIPhistoryUpdatePseudocost(stat->glbhistory, set, solvaldelta, objdelta, weight);
13399  SCIPhistoryUpdatePseudocost(stat->glbhistorycrun, set, solvaldelta, objdelta, weight);
13400  return SCIP_OKAY;
13401 
13402  case SCIP_VARSTATUS_FIXED:
13403  SCIPerrorMessage("cannot update pseudo cost values of a fixed variable\n");
13404  return SCIP_INVALIDDATA;
13405 
13407  assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
13409  solvaldelta/var->data.aggregate.scalar, objdelta, weight) );
13410  return SCIP_OKAY;
13411 
13413  SCIPerrorMessage("cannot update pseudo cost values of a multi-aggregated variable\n");
13414  return SCIP_INVALIDDATA;
13415 
13417  SCIP_CALL( SCIPvarUpdatePseudocost(var->negatedvar, set, stat, -solvaldelta, objdelta, weight) );
13418  return SCIP_OKAY;
13419 
13420  default:
13421  SCIPerrorMessage("unknown variable status\n");
13422  return SCIP_INVALIDDATA;
13423  }
13424 }
13425 
13426 /** gets the variable's pseudo cost value for the given step size "solvaldelta" in the variable's LP solution value */
13428  SCIP_VAR* var, /**< problem variable */
13429  SCIP_STAT* stat, /**< problem statistics */
13430  SCIP_Real solvaldelta /**< difference of variable's new LP value - old LP value */
13431  )
13432 {
13433  SCIP_BRANCHDIR dir;
13434 
13435  assert(var != NULL);
13436  assert(stat != NULL);
13437 
13438  switch( SCIPvarGetStatus(var) )
13439  {
13441  if( var->data.original.transvar == NULL )
13442  return SCIPhistoryGetPseudocost(stat->glbhistory, solvaldelta);
13443  else
13444  return SCIPvarGetPseudocost(var->data.original.transvar, stat, solvaldelta);
13445 
13446  case SCIP_VARSTATUS_LOOSE:
13447  case SCIP_VARSTATUS_COLUMN:
13448  dir = (solvaldelta >= 0.0 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
13449 
13450  return SCIPhistoryGetPseudocostCount(var->history, dir) > 0.0
13451  ? SCIPhistoryGetPseudocost(var->history, solvaldelta)
13452  : SCIPhistoryGetPseudocost(stat->glbhistory, solvaldelta);
13453 
13454  case SCIP_VARSTATUS_FIXED:
13455  return 0.0;
13456 
13458  return SCIPvarGetPseudocost(var->data.aggregate.var, stat, var->data.aggregate.scalar * solvaldelta);
13459 
13461  return 0.0;
13462 
13464  return SCIPvarGetPseudocost(var->negatedvar, stat, -solvaldelta);
13465 
13466  default:
13467  SCIPerrorMessage("unknown variable status\n");
13468  SCIPABORT();
13469  return 0.0; /*lint !e527*/
13470  }
13471 }
13472 
13473 /** gets the variable's pseudo cost value for the given step size "solvaldelta" in the variable's LP solution value,
13474  * only using the pseudo cost information of the current run
13475  */
13477  SCIP_VAR* var, /**< problem variable */
13478  SCIP_STAT* stat, /**< problem statistics */
13479  SCIP_Real solvaldelta /**< difference of variable's new LP value - old LP value */
13480  )
13481 {
13482  SCIP_BRANCHDIR dir;
13483 
13484  assert(var != NULL);
13485  assert(stat != NULL);
13486 
13487  switch( SCIPvarGetStatus(var) )
13488  {
13490  if( var->data.original.transvar == NULL )
13491  return SCIPhistoryGetPseudocost(stat->glbhistorycrun, solvaldelta);
13492  else
13493  return SCIPvarGetPseudocostCurrentRun(var->data.original.transvar, stat, solvaldelta);
13494 
13495  case SCIP_VARSTATUS_LOOSE:
13496  case SCIP_VARSTATUS_COLUMN:
13497  dir = (solvaldelta >= 0.0 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
13498 
13499  return SCIPhistoryGetPseudocostCount(var->historycrun, dir) > 0.0
13500  ? SCIPhistoryGetPseudocost(var->historycrun, solvaldelta)
13501  : SCIPhistoryGetPseudocost(stat->glbhistorycrun, solvaldelta);
13502 
13503  case SCIP_VARSTATUS_FIXED:
13504  return 0.0;
13505 
13507  return SCIPvarGetPseudocostCurrentRun(var->data.aggregate.var, stat, var->data.aggregate.scalar * solvaldelta);
13508 
13510  return 0.0;
13511 
13513  return SCIPvarGetPseudocostCurrentRun(var->negatedvar, stat, -solvaldelta);
13514 
13515  default:
13516  SCIPerrorMessage("unknown variable status\n");
13517  SCIPABORT();
13518  return 0.0; /*lint !e527*/
13519  }
13520 }
13521 
13522 /** gets the variable's (possible fractional) number of pseudo cost updates for the given direction */
13524  SCIP_VAR* var, /**< problem variable */
13525  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
13526  )
13527 {
13528  assert(var != NULL);
13529  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
13530 
13531  switch( SCIPvarGetStatus(var) )
13532  {
13534  if( var->data.original.transvar == NULL )
13535  return 0.0;
13536  else
13537  return SCIPvarGetPseudocostCount(var->data.original.transvar, dir);
13538 
13539  case SCIP_VARSTATUS_LOOSE:
13540  case SCIP_VARSTATUS_COLUMN:
13541  return SCIPhistoryGetPseudocostCount(var->history, dir);
13542 
13543  case SCIP_VARSTATUS_FIXED:
13544  return 0.0;
13545 
13547  if( var->data.aggregate.scalar > 0.0 )
13548  return SCIPvarGetPseudocostCount(var->data.aggregate.var, dir);
13549  else
13551 
13553  return 0.0;
13554 
13557 
13558  default:
13559  SCIPerrorMessage("unknown variable status\n");
13560  SCIPABORT();
13561  return 0.0; /*lint !e527*/
13562  }
13563 }
13564 
13565 /** gets the variable's (possible fractional) number of pseudo cost updates for the given direction,
13566  * only using the pseudo cost information of the current run
13567  */
13569  SCIP_VAR* var, /**< problem variable */
13570  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
13571  )
13572 {
13573  assert(var != NULL);
13574  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
13575 
13576  switch( SCIPvarGetStatus(var) )
13577  {
13579  if( var->data.original.transvar == NULL )
13580  return 0.0;
13581  else
13583 
13584  case SCIP_VARSTATUS_LOOSE:
13585  case SCIP_VARSTATUS_COLUMN:
13586  return SCIPhistoryGetPseudocostCount(var->historycrun, dir);
13587 
13588  case SCIP_VARSTATUS_FIXED:
13589  return 0.0;
13590 
13592  if( var->data.aggregate.scalar > 0.0 )
13594  else
13596 
13598  return 0.0;
13599 
13602 
13603  default:
13604  SCIPerrorMessage("unknown variable status\n");
13605  SCIPABORT();
13606  return 0.0; /*lint !e527*/
13607  }
13608 }
13609 
13610 /** find the corresponding history entry if already existing, otherwise create new entry */
13611 static
13613  SCIP_VAR* var, /**< problem variable */
13614  SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
13615  BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
13616  SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
13617  SCIP_HISTORY** history /**< pointer to store the value based history, or NULL */
13618  )
13619 {
13620  assert(var != NULL);
13621  assert(blkmem != NULL);
13622  assert(set != NULL);
13623  assert(history != NULL);
13624 
13625  (*history) = NULL;
13626 
13627  if( var->valuehistory == NULL )
13628  {
13629  SCIP_CALL( SCIPvaluehistoryCreate(&var->valuehistory, blkmem) );
13630  }
13631 
13632  SCIP_CALL( SCIPvaluehistoryFind(var->valuehistory, blkmem, set, value, history) );
13633 
13634  return SCIP_OKAY;
13635 }
13636 
13637 /** check if value based history should be used */
13638 static
13640  SCIP_VAR* var, /**< problem variable */
13641  SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
13642  SCIP_SET* set /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
13643  )
13644 {
13645  /* check if the domain value is unknown (not specific) */
13646  if( value == SCIP_UNKNOWN ) /*lint !e777*/
13647  return FALSE;
13648 
13649  assert(set != NULL);
13650 
13651  /* check if value based history should be collected */
13652  if( !set->history_valuebased )
13653  return FALSE;
13654 
13655  /* value based history is not collected for binary variable since the standard history already contains all information */
13656  if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
13657  return FALSE;
13658 
13659  /* value based history is not collected for continuous variables */
13661  return FALSE;
13662 
13663  return TRUE;
13664 }
13665 
13666 /** increases VSIDS of the variable by the given weight */
13668  SCIP_VAR* var, /**< problem variable */
13669  BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
13670  SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
13671  SCIP_STAT* stat, /**< problem statistics */
13672  SCIP_BRANCHDIR dir, /**< branching direction */
13673  SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
13674  SCIP_Real weight /**< weight of this update in VSIDS */
13675  )
13676 {
13677  assert(var != NULL);
13678  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
13679 
13680  /* check if history statistics should be collected for a variable */
13681  if( !stat->collectvarhistory )
13682  return SCIP_OKAY;
13683 
13684  if( SCIPsetIsZero(set, weight) )
13685  return SCIP_OKAY;
13686 
13687  switch( SCIPvarGetStatus(var) )
13688  {
13690  if( var->data.original.transvar == NULL )
13691  {
13692  SCIPerrorMessage("cannot update VSIDS of original untransformed variable\n");
13693  return SCIP_INVALIDDATA;
13694  }
13695  SCIP_CALL( SCIPvarIncVSIDS(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
13696  return SCIP_OKAY;
13697 
13698  case SCIP_VARSTATUS_LOOSE:
13699  case SCIP_VARSTATUS_COLUMN:
13700  {
13701  SCIPhistoryIncVSIDS(var->history, dir, weight);
13702  SCIPhistoryIncVSIDS(var->historycrun, dir, weight);
13703 
13704  if( useValuehistory(var, value, set) )
13705  {
13706  SCIP_HISTORY* history;
13707 
13708  SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
13709  assert(history != NULL);
13710 
13711  SCIPhistoryIncVSIDS(history, dir, weight);
13712  SCIPdebugMessage("variable (<%s> %s %g) + <%g> = <%g>\n", SCIPvarGetName(var), dir == SCIP_BRANCHDIR_UPWARDS ? ">=" : "<=",
13713  value, weight, SCIPhistoryGetVSIDS(history, dir));
13714  }
13715 
13716  return SCIP_OKAY;
13717  }
13718  case SCIP_VARSTATUS_FIXED:
13719  SCIPerrorMessage("cannot update VSIDS of a fixed variable\n");
13720  return SCIP_INVALIDDATA;
13721 
13723  value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
13724 
13725  if( var->data.aggregate.scalar > 0.0 )
13726  {
13727  SCIP_CALL( SCIPvarIncVSIDS(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
13728  }
13729  else
13730  {
13731  assert(var->data.aggregate.scalar < 0.0);
13732  SCIP_CALL( SCIPvarIncVSIDS(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
13733  }
13734  return SCIP_OKAY;
13735 
13737  SCIPerrorMessage("cannot update VSIDS of a multi-aggregated variable\n");
13738  return SCIP_INVALIDDATA;
13739 
13741  value = 1.0 - value;
13742 
13743  SCIP_CALL( SCIPvarIncVSIDS(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
13744  return SCIP_OKAY;
13745 
13746  default:
13747  SCIPerrorMessage("unknown variable status\n");
13748  return SCIP_INVALIDDATA;
13749  }
13750 }
13751 
13752 /** scales the VSIDS of the variable by the given scalar */
13754  SCIP_VAR* var, /**< problem variable */
13755  SCIP_Real scalar /**< scalar to multiply the VSIDSs with */
13756  )
13757 {
13758  assert(var != NULL);
13759 
13760  switch( SCIPvarGetStatus(var) )
13761  {
13763  if( var->data.original.transvar == NULL )
13764  {
13765  SCIPerrorMessage("cannot update VSIDS of original untransformed variable\n");
13766  return SCIP_INVALIDDATA;
13767  }
13769  return SCIP_OKAY;
13770 
13771  case SCIP_VARSTATUS_LOOSE:
13772  case SCIP_VARSTATUS_COLUMN:
13773  {
13774  SCIPhistoryScaleVSIDS(var->history, scalar);
13775  SCIPhistoryScaleVSIDS(var->historycrun, scalar);
13777 
13778  return SCIP_OKAY;
13779  }
13780  case SCIP_VARSTATUS_FIXED:
13781  SCIPerrorMessage("cannot update VSIDS of a fixed variable\n");
13782  return SCIP_INVALIDDATA;
13783 
13785  SCIP_CALL( SCIPvarScaleVSIDS(var->data.aggregate.var, scalar) );
13786  return SCIP_OKAY;
13787 
13789  SCIPerrorMessage("cannot update VSIDS of a multi-aggregated variable\n");
13790  return SCIP_INVALIDDATA;
13791 
13793  SCIP_CALL( SCIPvarScaleVSIDS(var->negatedvar, scalar) );
13794  return SCIP_OKAY;
13795 
13796  default:
13797  SCIPerrorMessage("unknown variable status\n");
13798  return SCIP_INVALIDDATA;
13799  }
13800 }
13801 
13802 /** increases the number of active conflicts by one and the overall length of the variable by the given length */
13804  SCIP_VAR* var, /**< problem variable */
13805  BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
13806  SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
13807  SCIP_STAT* stat, /**< problem statistics */
13808  SCIP_BRANCHDIR dir, /**< branching direction */
13809  SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
13810  SCIP_Real length /**< length of the conflict */
13811  )
13812 {
13813  assert(var != NULL);
13814  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
13815 
13816  /* check if history statistics should be collected for a variable */
13817  if( !stat->collectvarhistory )
13818  return SCIP_OKAY;
13819 
13820  switch( SCIPvarGetStatus(var) )
13821  {
13823  if( var->data.original.transvar == NULL )
13824  {
13825  SCIPerrorMessage("cannot update conflict score of original untransformed variable\n");
13826  return SCIP_INVALIDDATA;
13827  }
13828  SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.original.transvar, blkmem, set, stat, dir, value, length) );
13829  return SCIP_OKAY;
13830 
13831  case SCIP_VARSTATUS_LOOSE:
13832  case SCIP_VARSTATUS_COLUMN:
13833  {
13834  SCIPhistoryIncNActiveConflicts(var->history, dir, length);
13835  SCIPhistoryIncNActiveConflicts(var->historycrun, dir, length);
13836 
13837  if( useValuehistory(var, value, set) )
13838  {
13839  SCIP_HISTORY* history;
13840 
13841  SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
13842  assert(history != NULL);
13843 
13844  SCIPhistoryIncNActiveConflicts(history, dir, length);
13845  }
13846 
13847  return SCIP_OKAY;
13848  }
13849  case SCIP_VARSTATUS_FIXED:
13850  SCIPerrorMessage("cannot update conflict score of a fixed variable\n");
13851  return SCIP_INVALIDDATA;
13852 
13854  value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
13855 
13856  if( var->data.aggregate.scalar > 0.0 )
13857  {
13858  SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.aggregate.var, blkmem, set, stat, dir, value, length) );
13859  }
13860  else
13861  {
13862  assert(var->data.aggregate.scalar < 0.0);
13863  SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, length) );
13864  }
13865  return SCIP_OKAY;
13866 
13868  SCIPerrorMessage("cannot update conflict score of a multi-aggregated variable\n");
13869  return SCIP_INVALIDDATA;
13870 
13872  value = 1.0 - value;
13873 
13874  SCIP_CALL( SCIPvarIncNActiveConflicts(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, length) );
13875  return SCIP_OKAY;
13876 
13877  default:
13878  SCIPerrorMessage("unknown variable status\n");
13879  return SCIP_INVALIDDATA;
13880  }
13881 }
13882 
13883 /** gets the number of active conflicts containing this variable in given direction */
13885  SCIP_VAR* var, /**< problem variable */
13886  SCIP_STAT* stat, /**< problem statistics */
13887  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
13888  )
13889 {
13890  assert(var != NULL);
13891  assert(stat != NULL);
13892  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
13893 
13894  switch( SCIPvarGetStatus(var) )
13895  {
13897  if( var->data.original.transvar == NULL )
13898  return 0;
13899  else
13900  return SCIPvarGetNActiveConflicts(var->data.original.transvar, stat, dir);
13901 
13902  case SCIP_VARSTATUS_LOOSE:
13903  case SCIP_VARSTATUS_COLUMN:
13904  return SCIPhistoryGetNActiveConflicts(var->history, dir);
13905 
13906  case SCIP_VARSTATUS_FIXED:
13907  return 0;
13908 
13910  if( var->data.aggregate.scalar > 0.0 )
13911  return SCIPvarGetNActiveConflicts(var->data.aggregate.var, stat, dir);
13912  else
13914 
13916  return 0;
13917 
13920 
13921  default:
13922  SCIPerrorMessage("unknown variable status\n");
13923  SCIPABORT();
13924  return 0; /*lint !e527*/
13925  }
13926 }
13927 
13928 /** gets the number of active conflicts containing this variable in given direction
13929  * in the current run
13930  */
13932  SCIP_VAR* var, /**< problem variable */
13933  SCIP_STAT* stat, /**< problem statistics */
13934  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
13935  )
13936 {
13937  assert(var != NULL);
13938  assert(stat != NULL);
13939  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
13940 
13941  switch( SCIPvarGetStatus(var) )
13942  {
13944  if( var->data.original.transvar == NULL )
13945  return 0;
13946  else
13948 
13949  case SCIP_VARSTATUS_LOOSE:
13950  case SCIP_VARSTATUS_COLUMN:
13951  return SCIPhistoryGetNActiveConflicts(var->historycrun, dir);
13952 
13953  case SCIP_VARSTATUS_FIXED:
13954  return 0;
13955 
13957  if( var->data.aggregate.scalar > 0.0 )
13958  return SCIPvarGetNActiveConflictsCurrentRun(var->data.aggregate.var, stat, dir);
13959  else
13961 
13963  return 0;
13964 
13967 
13968  default:
13969  SCIPerrorMessage("unknown variable status\n");
13970  SCIPABORT();
13971  return 0; /*lint !e527*/
13972  }
13973 }
13974 
13975 /** gets the average conflict length in given direction due to branching on the variable */
13977  SCIP_VAR* var, /**< problem variable */
13978  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
13979  )
13980 {
13981  assert(var != NULL);
13982  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
13983 
13984  switch( SCIPvarGetStatus(var) )
13985  {
13987  if( var->data.original.transvar == NULL )
13988  return 0.0;
13989  else
13991 
13992  case SCIP_VARSTATUS_LOOSE:
13993  case SCIP_VARSTATUS_COLUMN:
13994  return SCIPhistoryGetAvgConflictlength(var->history, dir);
13995  case SCIP_VARSTATUS_FIXED:
13996  return 0.0;
13997 
13999  if( var->data.aggregate.scalar > 0.0 )
14000  return SCIPvarGetAvgConflictlength(var->data.aggregate.var, dir);
14001  else
14003 
14005  return 0.0;
14006 
14009 
14010  default:
14011  SCIPerrorMessage("unknown variable status\n");
14012  SCIPABORT();
14013  return 0.0; /*lint !e527*/
14014  }
14015 }
14016 
14017 /** gets the average conflict length in given direction due to branching on the variable
14018  * in the current run
14019  */
14021  SCIP_VAR* var, /**< problem variable */
14022  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14023  )
14024 {
14025  assert(var != NULL);
14026  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14027 
14028  switch( SCIPvarGetStatus(var) )
14029  {
14031  if( var->data.original.transvar == NULL )
14032  return 0.0;
14033  else
14035 
14036  case SCIP_VARSTATUS_LOOSE:
14037  case SCIP_VARSTATUS_COLUMN:
14038  return SCIPhistoryGetAvgConflictlength(var->historycrun, dir);
14039 
14040  case SCIP_VARSTATUS_FIXED:
14041  return 0.0;
14042 
14044  if( var->data.aggregate.scalar > 0.0 )
14046  else
14048 
14050  return 0.0;
14051 
14054 
14055  default:
14056  SCIPerrorMessage("unknown variable status\n");
14057  SCIPABORT();
14058  return 0.0; /*lint !e527*/
14059  }
14060 }
14061 
14062 /** increases the number of branchings counter of the variable */
14064  SCIP_VAR* var, /**< problem variable */
14065  BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
14066  SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
14067  SCIP_STAT* stat, /**< problem statistics */
14068  SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
14069  SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
14070  int depth /**< depth at which the bound change took place */
14071  )
14072 {
14073  assert(var != NULL);
14074  assert(stat != NULL);
14075  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14076 
14077  /* check if history statistics should be collected for a variable */
14078  if( !stat->collectvarhistory )
14079  return SCIP_OKAY;
14080 
14081  switch( SCIPvarGetStatus(var) )
14082  {
14084  if( var->data.original.transvar == NULL )
14085  {
14086  SCIPerrorMessage("cannot update branching counter of original untransformed variable\n");
14087  return SCIP_INVALIDDATA;
14088  }
14089  SCIP_CALL( SCIPvarIncNBranchings(var->data.original.transvar, blkmem, set, stat, dir, value, depth) );
14090  return SCIP_OKAY;
14091 
14092  case SCIP_VARSTATUS_LOOSE:
14093  case SCIP_VARSTATUS_COLUMN:
14094  {
14095  SCIPhistoryIncNBranchings(var->history, dir, depth);
14096  SCIPhistoryIncNBranchings(var->historycrun, dir, depth);
14097  SCIPhistoryIncNBranchings(stat->glbhistory, dir, depth);
14098  SCIPhistoryIncNBranchings(stat->glbhistorycrun, dir, depth);
14099 
14100  if( useValuehistory(var, value, set) )
14101  {
14102  SCIP_HISTORY* history;
14103 
14104  SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
14105  assert(history != NULL);
14106 
14107  SCIPhistoryIncNBranchings(history, dir, depth);
14108  }
14109 
14110  return SCIP_OKAY;
14111  }
14112  case SCIP_VARSTATUS_FIXED:
14113  SCIPerrorMessage("cannot update branching counter of a fixed variable\n");
14114  return SCIP_INVALIDDATA;
14115 
14117  value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
14118 
14119  if( var->data.aggregate.scalar > 0.0 )
14120  {
14121  SCIP_CALL( SCIPvarIncNBranchings(var->data.aggregate.var, blkmem, set, stat, dir, value, depth) );
14122  }
14123  else
14124  {
14125  assert(var->data.aggregate.scalar < 0.0);
14126  SCIP_CALL( SCIPvarIncNBranchings(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, depth) );
14127  }
14128  return SCIP_OKAY;
14129 
14131  SCIPerrorMessage("cannot update branching counter of a multi-aggregated variable\n");
14132  return SCIP_INVALIDDATA;
14133 
14135  value = 1.0 - value;
14136 
14137  SCIP_CALL( SCIPvarIncNBranchings(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, depth) );
14138  return SCIP_OKAY;
14139 
14140  default:
14141  SCIPerrorMessage("unknown variable status\n");
14142  return SCIP_INVALIDDATA;
14143  }
14144 }
14145 
14146 /** increases the inference sum of the variable by the given weight */
14148  SCIP_VAR* var, /**< problem variable */
14149  BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
14150  SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
14151  SCIP_STAT* stat, /**< problem statistics */
14152  SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
14153  SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
14154  SCIP_Real weight /**< weight of this update in inference score */
14155  )
14156 {
14157  assert(var != NULL);
14158  assert(stat != NULL);
14159  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14160 
14161  /* check if history statistics should be collected for a variable */
14162  if( !stat->collectvarhistory )
14163  return SCIP_OKAY;
14164 
14165  switch( SCIPvarGetStatus(var) )
14166  {
14168  if( var->data.original.transvar == NULL )
14169  {
14170  SCIPerrorMessage("cannot update inference counter of original untransformed variable\n");
14171  return SCIP_INVALIDDATA;
14172  }
14173  SCIP_CALL( SCIPvarIncInferenceSum(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
14174  return SCIP_OKAY;
14175 
14176  case SCIP_VARSTATUS_LOOSE:
14177  case SCIP_VARSTATUS_COLUMN:
14178  {
14179  SCIPhistoryIncInferenceSum(var->history, dir, weight);
14180  SCIPhistoryIncInferenceSum(var->historycrun, dir, weight);
14181  SCIPhistoryIncInferenceSum(stat->glbhistory, dir, weight);
14182  SCIPhistoryIncInferenceSum(stat->glbhistorycrun, dir, weight);
14183 
14184  if( useValuehistory(var, value, set) )
14185  {
14186  SCIP_HISTORY* history;
14187 
14188  SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
14189  assert(history != NULL);
14190 
14191  SCIPhistoryIncInferenceSum(history, dir, weight);
14192  }
14193 
14194  return SCIP_OKAY;
14195  }
14196  case SCIP_VARSTATUS_FIXED:
14197  SCIPerrorMessage("cannot update inference counter of a fixed variable\n");
14198  return SCIP_INVALIDDATA;
14199 
14201  value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
14202 
14203  if( var->data.aggregate.scalar > 0.0 )
14204  {
14205  SCIP_CALL( SCIPvarIncInferenceSum(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
14206  }
14207  else
14208  {
14209  assert(var->data.aggregate.scalar < 0.0);
14210  SCIP_CALL( SCIPvarIncInferenceSum(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
14211  }
14212  return SCIP_OKAY;
14213 
14215  SCIPerrorMessage("cannot update inference counter of a multi-aggregated variable\n");
14216  return SCIP_INVALIDDATA;
14217 
14219  value = 1.0 - value;
14220 
14221  SCIP_CALL( SCIPvarIncInferenceSum(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
14222  return SCIP_OKAY;
14223 
14224  default:
14225  SCIPerrorMessage("unknown variable status\n");
14226  return SCIP_INVALIDDATA;
14227  }
14228 }
14229 
14230 /** increases the cutoff sum of the variable by the given weight */
14232  SCIP_VAR* var, /**< problem variable */
14233  BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
14234  SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
14235  SCIP_STAT* stat, /**< problem statistics */
14236  SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
14237  SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
14238  SCIP_Real weight /**< weight of this update in cutoff score */
14239  )
14240 {
14241  assert(var != NULL);
14242  assert(stat != NULL);
14243  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14244 
14245  /* check if history statistics should be collected for a variable */
14246  if( !stat->collectvarhistory )
14247  return SCIP_OKAY;
14248 
14249  switch( SCIPvarGetStatus(var) )
14250  {
14252  if( var->data.original.transvar == NULL )
14253  {
14254  SCIPerrorMessage("cannot update cutoff sum of original untransformed variable\n");
14255  return SCIP_INVALIDDATA;
14256  }
14257  SCIP_CALL( SCIPvarIncCutoffSum(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
14258  return SCIP_OKAY;
14259 
14260  case SCIP_VARSTATUS_LOOSE:
14261  case SCIP_VARSTATUS_COLUMN:
14262  {
14263  SCIPhistoryIncCutoffSum(var->history, dir, weight);
14264  SCIPhistoryIncCutoffSum(var->historycrun, dir, weight);
14265  SCIPhistoryIncCutoffSum(stat->glbhistory, dir, weight);
14266  SCIPhistoryIncCutoffSum(stat->glbhistorycrun, dir, weight);
14267 
14268  if( useValuehistory(var, value, set) )
14269  {
14270  SCIP_HISTORY* history;
14271 
14272  SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
14273  assert(history != NULL);
14274 
14275  SCIPhistoryIncCutoffSum(history, dir, weight);
14276  }
14277 
14278  return SCIP_OKAY;
14279  }
14280  case SCIP_VARSTATUS_FIXED:
14281  SCIPerrorMessage("cannot update cutoff sum of a fixed variable\n");
14282  return SCIP_INVALIDDATA;
14283 
14285  value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
14286 
14287  if( var->data.aggregate.scalar > 0.0 )
14288  {
14289  SCIP_CALL( SCIPvarIncCutoffSum(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
14290  }
14291  else
14292  {
14293  assert(var->data.aggregate.scalar < 0.0);
14294  SCIP_CALL( SCIPvarIncCutoffSum(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
14295  }
14296  return SCIP_OKAY;
14297 
14299  SCIPerrorMessage("cannot update cutoff sum of a multi-aggregated variable\n");
14300  return SCIP_INVALIDDATA;
14301 
14303  value = 1.0 - value;
14304 
14305  SCIP_CALL( SCIPvarIncCutoffSum(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
14306  return SCIP_OKAY;
14307 
14308  default:
14309  SCIPerrorMessage("unknown variable status\n");
14310  return SCIP_INVALIDDATA;
14311  }
14312 }
14313 
14314 /** returns the number of times, a bound of the variable was changed in given direction due to branching */
14316  SCIP_VAR* var, /**< problem variable */
14317  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14318  )
14319 {
14320  assert(var != NULL);
14321  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14322 
14323  switch( SCIPvarGetStatus(var) )
14324  {
14326  if( var->data.original.transvar == NULL )
14327  return 0;
14328  else
14329  return SCIPvarGetNBranchings(var->data.original.transvar, dir);
14330 
14331  case SCIP_VARSTATUS_LOOSE:
14332  case SCIP_VARSTATUS_COLUMN:
14333  return SCIPhistoryGetNBranchings(var->history, dir);
14334 
14335  case SCIP_VARSTATUS_FIXED:
14336  return 0;
14337 
14339  if( var->data.aggregate.scalar > 0.0 )
14340  return SCIPvarGetNBranchings(var->data.aggregate.var, dir);
14341  else
14343 
14345  return 0;
14346 
14349 
14350  default:
14351  SCIPerrorMessage("unknown variable status\n");
14352  SCIPABORT();
14353  return 0; /*lint !e527*/
14354  }
14355 }
14356 
14357 /** returns the number of times, a bound of the variable was changed in given direction due to branching
14358  * in the current run
14359  */
14361  SCIP_VAR* var, /**< problem variable */
14362  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14363  )
14364 {
14365  assert(var != NULL);
14366  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14367 
14368  switch( SCIPvarGetStatus(var) )
14369  {
14371  if( var->data.original.transvar == NULL )
14372  return 0;
14373  else
14375 
14376  case SCIP_VARSTATUS_LOOSE:
14377  case SCIP_VARSTATUS_COLUMN:
14378  return SCIPhistoryGetNBranchings(var->historycrun, dir);
14379 
14380  case SCIP_VARSTATUS_FIXED:
14381  return 0;
14382 
14384  if( var->data.aggregate.scalar > 0.0 )
14386  else
14388 
14390  return 0;
14391 
14394 
14395  default:
14396  SCIPerrorMessage("unknown variable status\n");
14397  SCIPABORT();
14398  return 0; /*lint !e527*/
14399  }
14400 }
14401 
14402 /** returns the average depth of bound changes in given direction due to branching on the variable */
14404  SCIP_VAR* var, /**< problem variable */
14405  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14406  )
14407 {
14408  assert(var != NULL);
14409  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14410 
14411  switch( SCIPvarGetStatus(var) )
14412  {
14414  if( var->data.original.transvar == NULL )
14415  return 0.0;
14416  else
14417  return SCIPvarGetAvgBranchdepth(var->data.original.transvar, dir);
14418 
14419  case SCIP_VARSTATUS_LOOSE:
14420  case SCIP_VARSTATUS_COLUMN:
14421  return SCIPhistoryGetAvgBranchdepth(var->history, dir);
14422 
14423  case SCIP_VARSTATUS_FIXED:
14424  return 0.0;
14425 
14427  if( var->data.aggregate.scalar > 0.0 )
14428  return SCIPvarGetAvgBranchdepth(var->data.aggregate.var, dir);
14429  else
14431 
14433  return 0.0;
14434 
14437 
14438  default:
14439  SCIPerrorMessage("unknown variable status\n");
14440  SCIPABORT();
14441  return 0.0; /*lint !e527*/
14442  }
14443 }
14444 
14445 /** returns the average depth of bound changes in given direction due to branching on the variable
14446  * in the current run
14447  */
14449  SCIP_VAR* var, /**< problem variable */
14450  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14451  )
14452 {
14453  assert(var != NULL);
14454  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14455 
14456  switch( SCIPvarGetStatus(var) )
14457  {
14459  if( var->data.original.transvar == NULL )
14460  return 0.0;
14461  else
14463 
14464  case SCIP_VARSTATUS_LOOSE:
14465  case SCIP_VARSTATUS_COLUMN:
14466  return SCIPhistoryGetAvgBranchdepth(var->historycrun, dir);
14467 
14468  case SCIP_VARSTATUS_FIXED:
14469  return 0.0;
14470 
14472  if( var->data.aggregate.scalar > 0.0 )
14474  else
14476 
14478  return 0.0;
14479 
14482 
14483  default:
14484  SCIPerrorMessage("unknown variable status\n");
14485  SCIPABORT();
14486  return 0.0; /*lint !e527*/
14487  }
14488 }
14489 
14490 /** returns the variable's VSIDS score */
14492  SCIP_VAR* var, /**< problem variable */
14493  SCIP_STAT* stat, /**< problem statistics */
14494  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14495  )
14496 {
14497  assert(var != NULL);
14498  assert(stat != NULL);
14499  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14500 
14502  return SCIPvarGetVSIDS(var->data.original.transvar, stat, dir);
14503 
14504  switch( SCIPvarGetStatus(var) )
14505  {
14507  if( var->data.original.transvar == NULL )
14508  return 0.0;
14509  else
14510  return SCIPvarGetVSIDS(var->data.original.transvar, stat, dir);
14511 
14512  case SCIP_VARSTATUS_LOOSE:
14513  case SCIP_VARSTATUS_COLUMN:
14514  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); /* column case already handled in if condition above */
14515  return SCIPhistoryGetVSIDS(var->history, dir)/stat->vsidsweight;
14516 
14517  case SCIP_VARSTATUS_FIXED:
14518  return 0.0;
14519 
14521  if( var->data.aggregate.scalar > 0.0 )
14522  return SCIPvarGetVSIDS(var->data.aggregate.var, stat, dir);
14523  else
14524  return SCIPvarGetVSIDS(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
14525 
14527  return 0.0;
14528 
14530  return SCIPvarGetVSIDS(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
14531 
14532  default:
14533  SCIPerrorMessage("unknown variable status\n");
14534  SCIPABORT();
14535  return 0.0; /*lint !e527*/
14536  }
14537 }
14538 
14539 /** returns the variable's VSIDS score only using conflicts of the current run */
14541  SCIP_VAR* var, /**< problem variable */
14542  SCIP_STAT* stat, /**< problem statistics */
14543  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14544  )
14545 {
14546  assert(var != NULL);
14547  assert(stat != NULL);
14548  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14549 
14550  switch( SCIPvarGetStatus(var) )
14551  {
14553  if( var->data.original.transvar == NULL )
14554  return 0.0;
14555  else
14556  return SCIPvarGetVSIDSCurrentRun(var->data.original.transvar, stat, dir);
14557 
14558  case SCIP_VARSTATUS_LOOSE:
14559  case SCIP_VARSTATUS_COLUMN:
14560  return SCIPhistoryGetVSIDS(var->historycrun, dir)/stat->vsidsweight;
14561 
14562  case SCIP_VARSTATUS_FIXED:
14563  return 0.0;
14564 
14566  if( var->data.aggregate.scalar > 0.0 )
14567  return SCIPvarGetVSIDSCurrentRun(var->data.aggregate.var, stat, dir);
14568  else
14570 
14572  return 0.0;
14573 
14576 
14577  default:
14578  SCIPerrorMessage("unknown variable status\n");
14579  SCIPABORT();
14580  return 0.0; /*lint !e527*/
14581  }
14582 }
14583 
14584 /** returns the number of inferences branching on this variable in given direction triggered */
14586  SCIP_VAR* var, /**< problem variable */
14587  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14588  )
14589 {
14590  assert(var != NULL);
14591  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14592 
14593  switch( SCIPvarGetStatus(var) )
14594  {
14596  if( var->data.original.transvar == NULL )
14597  return 0.0;
14598  else
14599  return SCIPvarGetInferenceSum(var->data.original.transvar, dir);
14600 
14601  case SCIP_VARSTATUS_LOOSE:
14602  case SCIP_VARSTATUS_COLUMN:
14603  return SCIPhistoryGetInferenceSum(var->history, dir);
14604 
14605  case SCIP_VARSTATUS_FIXED:
14606  return 0.0;
14607 
14609  if( var->data.aggregate.scalar > 0.0 )
14610  return SCIPvarGetInferenceSum(var->data.aggregate.var, dir);
14611  else
14613 
14615  return 0.0;
14616 
14619 
14620  default:
14621  SCIPerrorMessage("unknown variable status\n");
14622  SCIPABORT();
14623  return 0.0; /*lint !e527*/
14624  }
14625 }
14626 
14627 /** returns the number of inferences branching on this variable in given direction triggered
14628  * in the current run
14629  */
14631  SCIP_VAR* var, /**< problem variable */
14632  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14633  )
14634 {
14635  assert(var != NULL);
14636  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14637 
14638  switch( SCIPvarGetStatus(var) )
14639  {
14641  if( var->data.original.transvar == NULL )
14642  return 0.0;
14643  else
14645 
14646  case SCIP_VARSTATUS_LOOSE:
14647  case SCIP_VARSTATUS_COLUMN:
14648  return SCIPhistoryGetInferenceSum(var->historycrun, dir);
14649 
14650  case SCIP_VARSTATUS_FIXED:
14651  return 0.0;
14652 
14654  if( var->data.aggregate.scalar > 0.0 )
14656  else
14658 
14660  return 0.0;
14661 
14664 
14665  default:
14666  SCIPerrorMessage("unknown variable status\n");
14667  SCIPABORT();
14668  return 0.0; /*lint !e527*/
14669  }
14670 }
14671 
14672 /** returns the average number of inferences found after branching on the variable in given direction */
14674  SCIP_VAR* var, /**< problem variable */
14675  SCIP_STAT* stat, /**< problem statistics */
14676  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14677  )
14678 {
14679  assert(var != NULL);
14680  assert(stat != NULL);
14681  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14682 
14683  switch( SCIPvarGetStatus(var) )
14684  {
14686  if( var->data.original.transvar == NULL )
14687  return SCIPhistoryGetAvgInferences(stat->glbhistory, dir);
14688  else
14689  return SCIPvarGetAvgInferences(var->data.original.transvar, stat, dir);
14690 
14691  case SCIP_VARSTATUS_LOOSE:
14692  case SCIP_VARSTATUS_COLUMN:
14693  if( SCIPhistoryGetNBranchings(var->history, dir) > 0 )
14694  return SCIPhistoryGetAvgInferences(var->history, dir);
14695  else
14696  {
14697  int nimpls;
14698  int ncliques;
14699 
14700  nimpls = SCIPvarGetNImpls(var, dir == SCIP_BRANCHDIR_UPWARDS);
14701  ncliques = SCIPvarGetNCliques(var, dir == SCIP_BRANCHDIR_UPWARDS);
14702  return nimpls + ncliques > 0 ? (SCIP_Real)(nimpls + 2*ncliques) : SCIPhistoryGetAvgInferences(stat->glbhistory, dir); /*lint !e790*/
14703  }
14704 
14705  case SCIP_VARSTATUS_FIXED:
14706  return 0.0;
14707 
14709  if( var->data.aggregate.scalar > 0.0 )
14710  return SCIPvarGetAvgInferences(var->data.aggregate.var, stat, dir);
14711  else
14713 
14715  return 0.0;
14716 
14718  return SCIPvarGetAvgInferences(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
14719 
14720  default:
14721  SCIPerrorMessage("unknown variable status\n");
14722  SCIPABORT();
14723  return 0.0; /*lint !e527*/
14724  }
14725 }
14726 
14727 /** returns the average number of inferences found after branching on the variable in given direction
14728  * in the current run
14729  */
14731  SCIP_VAR* var, /**< problem variable */
14732  SCIP_STAT* stat, /**< problem statistics */
14733  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14734  )
14735 {
14736  assert(var != NULL);
14737  assert(stat != NULL);
14738  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14739 
14740  switch( SCIPvarGetStatus(var) )
14741  {
14743  if( var->data.original.transvar == NULL )
14744  return SCIPhistoryGetAvgInferences(stat->glbhistorycrun, dir);
14745  else
14746  return SCIPvarGetAvgInferencesCurrentRun(var->data.original.transvar, stat, dir);
14747 
14748  case SCIP_VARSTATUS_LOOSE:
14749  case SCIP_VARSTATUS_COLUMN:
14750  if( SCIPhistoryGetNBranchings(var->historycrun, dir) > 0 )
14751  return SCIPhistoryGetAvgInferences(var->historycrun, dir);
14752  else
14753  {
14754  int nimpls;
14755  int ncliques;
14756 
14757  nimpls = SCIPvarGetNImpls(var, dir == SCIP_BRANCHDIR_UPWARDS);
14758  ncliques = SCIPvarGetNCliques(var, dir == SCIP_BRANCHDIR_UPWARDS);
14759  return nimpls + ncliques > 0 ? (SCIP_Real)(nimpls + 2*ncliques) : SCIPhistoryGetAvgInferences(stat->glbhistorycrun, dir); /*lint !e790*/
14760  }
14761 
14762  case SCIP_VARSTATUS_FIXED:
14763  return 0.0;
14764 
14766  if( var->data.aggregate.scalar > 0.0 )
14767  return SCIPvarGetAvgInferencesCurrentRun(var->data.aggregate.var, stat, dir);
14768  else
14770 
14772  return 0.0;
14773 
14776 
14777  default:
14778  SCIPerrorMessage("unknown variable status\n");
14779  SCIPABORT();
14780  return 0.0; /*lint !e527*/
14781  }
14782 }
14783 
14784 /** returns the number of cutoffs branching on this variable in given direction produced */
14786  SCIP_VAR* var, /**< problem variable */
14787  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14788  )
14789 {
14790  assert(var != NULL);
14791  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14792 
14793  switch( SCIPvarGetStatus(var) )
14794  {
14796  if( var->data.original.transvar == NULL )
14797  return 0;
14798  else
14799  return SCIPvarGetCutoffSum(var->data.original.transvar, dir);
14800 
14801  case SCIP_VARSTATUS_LOOSE:
14802  case SCIP_VARSTATUS_COLUMN:
14803  return SCIPhistoryGetCutoffSum(var->history, dir);
14804 
14805  case SCIP_VARSTATUS_FIXED:
14806  return 0;
14807 
14809  if( var->data.aggregate.scalar > 0.0 )
14810  return SCIPvarGetCutoffSum(var->data.aggregate.var, dir);
14811  else
14813 
14815  return 0;
14816 
14819 
14820  default:
14821  SCIPerrorMessage("unknown variable status\n");
14822  SCIPABORT();
14823  return 0; /*lint !e527*/
14824  }
14825 }
14826 
14827 /** returns the number of cutoffs branching on this variable in given direction produced in the current run */
14829  SCIP_VAR* var, /**< problem variable */
14830  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14831  )
14832 {
14833  assert(var != NULL);
14834  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14835 
14836  switch( SCIPvarGetStatus(var) )
14837  {
14839  if( var->data.original.transvar == NULL )
14840  return 0;
14841  else
14843 
14844  case SCIP_VARSTATUS_LOOSE:
14845  case SCIP_VARSTATUS_COLUMN:
14846  return SCIPhistoryGetCutoffSum(var->historycrun, dir);
14847 
14848  case SCIP_VARSTATUS_FIXED:
14849  return 0;
14850 
14852  if( var->data.aggregate.scalar > 0.0 )
14853  return SCIPvarGetCutoffSumCurrentRun(var->data.aggregate.var, dir);
14854  else
14856 
14858  return 0;
14859 
14862 
14863  default:
14864  SCIPerrorMessage("unknown variable status\n");
14865  SCIPABORT();
14866  return 0; /*lint !e527*/
14867  }
14868 }
14869 
14870 /** returns the average number of cutoffs found after branching on the variable in given direction */
14872  SCIP_VAR* var, /**< problem variable */
14873  SCIP_STAT* stat, /**< problem statistics */
14874  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14875  )
14876 {
14877  assert(var != NULL);
14878  assert(stat != NULL);
14879  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14880 
14881  switch( SCIPvarGetStatus(var) )
14882  {
14884  if( var->data.original.transvar == NULL )
14885  return SCIPhistoryGetAvgCutoffs(stat->glbhistory, dir);
14886  else
14887  return SCIPvarGetAvgCutoffs(var->data.original.transvar, stat, dir);
14888 
14889  case SCIP_VARSTATUS_LOOSE:
14890  case SCIP_VARSTATUS_COLUMN:
14891  return SCIPhistoryGetNBranchings(var->history, dir) > 0
14892  ? SCIPhistoryGetAvgCutoffs(var->history, dir)
14893  : SCIPhistoryGetAvgCutoffs(stat->glbhistory, dir);
14894 
14895  case SCIP_VARSTATUS_FIXED:
14896  return 0.0;
14897 
14899  if( var->data.aggregate.scalar > 0.0 )
14900  return SCIPvarGetAvgCutoffs(var->data.aggregate.var, stat, dir);
14901  else
14902  return SCIPvarGetAvgCutoffs(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
14903 
14905  return 0.0;
14906 
14908  return SCIPvarGetAvgCutoffs(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
14909 
14910  default:
14911  SCIPerrorMessage("unknown variable status\n");
14912  SCIPABORT();
14913  return 0.0; /*lint !e527*/
14914  }
14915 }
14916 
14917 /** returns the average number of cutoffs found after branching on the variable in given direction in the current run */
14919  SCIP_VAR* var, /**< problem variable */
14920  SCIP_STAT* stat, /**< problem statistics */
14921  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14922  )
14923 {
14924  assert(var != NULL);
14925  assert(stat != NULL);
14926  assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14927 
14928  switch( SCIPvarGetStatus(var) )
14929  {
14931  if( var->data.original.transvar == NULL )
14932  return SCIPhistoryGetAvgCutoffs(stat->glbhistorycrun, dir);
14933  else
14934  return SCIPvarGetAvgCutoffsCurrentRun(var->data.original.transvar, stat, dir);
14935 
14936  case SCIP_VARSTATUS_LOOSE:
14937  case SCIP_VARSTATUS_COLUMN:
14938  return SCIPhistoryGetNBranchings(var->historycrun, dir) > 0
14941 
14942  case SCIP_VARSTATUS_FIXED:
14943  return 0.0;
14944 
14946  if( var->data.aggregate.scalar > 0.0 )
14947  return SCIPvarGetAvgCutoffsCurrentRun(var->data.aggregate.var, stat, dir);
14948  else
14950 
14952  return 0.0;
14953 
14956 
14957  default:
14958  SCIPerrorMessage("unknown variable status\n");
14959  SCIPABORT();
14960  return 0.0; /*lint !e527*/
14961  }
14962 }
14963 
14964 
14965 
14966 
14967 /*
14968  * information methods for bound changes
14969  */
14970 
14971 /** creates an artificial bound change information object with depth = INT_MAX and pos = -1 */
14973  SCIP_BDCHGINFO** bdchginfo, /**< pointer to store bound change information */
14974  BMS_BLKMEM* blkmem, /**< block memory */
14975  SCIP_VAR* var, /**< active variable that changed the bounds */
14976  SCIP_BOUNDTYPE boundtype, /**< type of bound for var: lower or upper bound */
14977  SCIP_Real oldbound, /**< old value for bound */
14978  SCIP_Real newbound /**< new value for bound */
14979  )
14980 {
14981  assert(bdchginfo != NULL);
14982 
14983  SCIP_ALLOC( BMSallocBlockMemory(blkmem, bdchginfo) );
14984  (*bdchginfo)->oldbound = oldbound;
14985  (*bdchginfo)->newbound = newbound;
14986  (*bdchginfo)->var = var;
14987  (*bdchginfo)->inferencedata.var = var;
14988  (*bdchginfo)->inferencedata.reason.prop = NULL;
14989  (*bdchginfo)->inferencedata.info = 0;
14990  (*bdchginfo)->bdchgidx.depth = INT_MAX;
14991  (*bdchginfo)->bdchgidx.pos = -1;
14992  (*bdchginfo)->pos = 0;
14993  (*bdchginfo)->boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
14994  (*bdchginfo)->boundtype = boundtype; /*lint !e641*/
14995  (*bdchginfo)->inferboundtype = boundtype; /*lint !e641*/
14996  (*bdchginfo)->redundant = FALSE;
14997 
14998  return SCIP_OKAY;
14999 }
15000 
15001 /** frees a bound change information object */
15003  SCIP_BDCHGINFO** bdchginfo, /**< pointer to store bound change information */
15004  BMS_BLKMEM* blkmem /**< block memory */
15005  )
15006 {
15007  assert(bdchginfo != NULL);
15008 
15009  BMSfreeBlockMemory(blkmem, bdchginfo);
15010 }
15011 
15012 /** returns the bound change information for the last lower bound change on given active problem variable before or
15013  * after the bound change with the given index was applied;
15014  * returns NULL, if no change to the lower bound was applied up to this point of time
15015  */
15017  SCIP_VAR* var, /**< active problem variable */
15018  SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
15019  SCIP_Bool after /**< should the bound change with given index be included? */
15020  )
15021 {
15022  int i;
15023 
15024  assert(var != NULL);
15025  assert(SCIPvarIsActive(var));
15026 
15027  /* search the correct bound change information for the given bound change index */
15028  if( after )
15029  {
15030  for( i = var->nlbchginfos-1; i >= 0; --i )
15031  {
15032  assert(var->lbchginfos[i].var == var);
15034  assert(var->lbchginfos[i].pos == i);
15035 
15036  /* if we reached the (due to global bounds) redundant bound changes, return NULL */
15037  if( var->lbchginfos[i].redundant )
15038  return NULL;
15039  assert(var->lbchginfos[i].oldbound < var->lbchginfos[i].newbound);
15040 
15041  /* if we reached the bound change index, return the current bound change info */
15042  if( !SCIPbdchgidxIsEarlier(bdchgidx, &var->lbchginfos[i].bdchgidx) )
15043  return &var->lbchginfos[i];
15044  }
15045  }
15046  else
15047  {
15048  for( i = var->nlbchginfos-1; i >= 0; --i )
15049  {
15050  assert(var->lbchginfos[i].var == var);
15052  assert(var->lbchginfos[i].pos == i);
15053 
15054  /* if we reached the (due to global bounds) redundant bound changes, return NULL */
15055  if( var->lbchginfos[i].redundant )
15056  return NULL;
15057  assert(var->lbchginfos[i].oldbound < var->lbchginfos[i].newbound);
15058 
15059  /* if we reached the bound change index, return the current bound change info */
15060  if( SCIPbdchgidxIsEarlier(&var->lbchginfos[i].bdchgidx, bdchgidx) )
15061  return &var->lbchginfos[i];
15062  }
15063  }
15064 
15065  return NULL;
15066 }
15067 
15068 /** returns the bound change information for the last upper bound change on given active problem variable before or
15069  * after the bound change with the given index was applied;
15070  * returns NULL, if no change to the upper bound was applied up to this point of time
15071  */
15073  SCIP_VAR* var, /**< active problem variable */
15074  SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
15075  SCIP_Bool after /**< should the bound change with given index be included? */
15076  )
15077 {
15078  int i;
15079 
15080  assert(var != NULL);
15081  assert(SCIPvarIsActive(var));
15082 
15083  /* search the correct bound change information for the given bound change index */
15084  if( after )
15085  {
15086  for( i = var->nubchginfos-1; i >= 0; --i )
15087  {
15088  assert(var->ubchginfos[i].var == var);
15090  assert(var->ubchginfos[i].pos == i);
15091 
15092  /* if we reached the (due to global bounds) redundant bound changes, return NULL */
15093  if( var->ubchginfos[i].redundant )
15094  return NULL;
15095  assert(var->ubchginfos[i].oldbound > var->ubchginfos[i].newbound);
15096 
15097  /* if we reached the bound change index, return the current bound change info */
15098  if( !SCIPbdchgidxIsEarlier(bdchgidx, &var->ubchginfos[i].bdchgidx) )
15099  return &var->ubchginfos[i];
15100  }
15101  }
15102  else
15103  {
15104  for( i = var->nubchginfos-1; i >= 0; --i )
15105  {
15106  assert(var->ubchginfos[i].var == var);
15108  assert(var->ubchginfos[i].pos == i);
15109 
15110  /* if we reached the (due to global bounds) redundant bound changes, return NULL */
15111  if( var->ubchginfos[i].redundant )
15112  return NULL;
15113  assert(var->ubchginfos[i].oldbound > var->ubchginfos[i].newbound);
15114 
15115  /* if we reached the bound change index, return the current bound change info */
15116  if( SCIPbdchgidxIsEarlier(&var->ubchginfos[i].bdchgidx, bdchgidx) )
15117  return &var->ubchginfos[i];
15118  }
15119  }
15120 
15121  return NULL;
15122 }
15123 
15124 /** returns the bound change information for the last lower or upper bound change on given active problem variable
15125  * before or after the bound change with the given index was applied;
15126  * returns NULL, if no change to the lower/upper bound was applied up to this point of time
15127  */
15129  SCIP_VAR* var, /**< active problem variable */
15130  SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */
15131  SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
15132  SCIP_Bool after /**< should the bound change with given index be included? */
15133  )
15134 {
15135  if( boundtype == SCIP_BOUNDTYPE_LOWER )
15136  return SCIPvarGetLbchgInfo(var, bdchgidx, after);
15137  else
15138  {
15139  assert(boundtype == SCIP_BOUNDTYPE_UPPER);
15140  return SCIPvarGetUbchgInfo(var, bdchgidx, after);
15141  }
15142 }
15143 
15144 /** returns lower bound of variable directly before or after the bound change given by the bound change index
15145  * was applied
15146  */
15148  SCIP_VAR* var, /**< problem variable */
15149  SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
15150  SCIP_Bool after /**< should the bound change with given index be included? */
15151  )
15152 {
15153  SCIP_VARSTATUS varstatus;
15154  assert(var != NULL);
15155 
15156  varstatus = SCIPvarGetStatus(var);
15157 
15158  if( varstatus == SCIP_VARSTATUS_COLUMN || varstatus == SCIP_VARSTATUS_LOOSE )
15159  {
15160  if( bdchgidx == NULL )
15161  return SCIPvarGetLbLocal(var);
15162  else
15163  {
15164  SCIP_BDCHGINFO* bdchginfo;
15165 
15166  bdchginfo = SCIPvarGetLbchgInfo(var, bdchgidx, after);
15167  if( bdchginfo != NULL )
15168  return SCIPbdchginfoGetNewbound(bdchginfo);
15169  else
15170  return var->glbdom.lb;
15171  }
15172  }
15173 
15174  /* get bounds of attached variables */
15175  switch( varstatus )
15176  {
15178  assert(var->data.original.transvar != NULL);
15179  return SCIPvarGetLbAtIndex(var->data.original.transvar, bdchgidx, after);
15180 
15181  case SCIP_VARSTATUS_FIXED:
15182  return var->glbdom.lb;
15183 
15184  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
15185  assert(var->data.aggregate.var != NULL);
15186  /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
15187  * corresponding infinity value instead of performing an arithmetical transformation (compare method
15188  * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
15189  * (or is called by) a public interface method; instead, we only assert that values are finite
15190  * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
15191  * positives and negatives if the parameter <numerics/infinity> is modified by the user
15192  */
15193  if( var->data.aggregate.scalar > 0.0 )
15194  {
15195  /* a > 0 -> get lower bound of y */
15196  assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
15197  assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
15198  return var->data.aggregate.scalar * SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after)
15199  + var->data.aggregate.constant;
15200  }
15201  else if( var->data.aggregate.scalar < 0.0 )
15202  {
15203  /* a < 0 -> get upper bound of y */
15204  assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
15205  assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
15206  return var->data.aggregate.scalar * SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after)
15207  + var->data.aggregate.constant;
15208  }
15209  else
15210  {
15211  SCIPerrorMessage("scalar is zero in aggregation\n");
15212  SCIPABORT();
15213  return SCIP_INVALID; /*lint !e527*/
15214  }
15215 
15217  SCIPerrorMessage("cannot get the bounds of a multi-aggregated variable.\n");
15218  SCIPABORT();
15219  return SCIP_INVALID; /*lint !e527*/
15220 
15221  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
15222  assert(var->negatedvar != NULL);
15224  assert(var->negatedvar->negatedvar == var);
15225  return var->data.negate.constant - SCIPvarGetUbAtIndex(var->negatedvar, bdchgidx, after);
15226 
15227  case SCIP_VARSTATUS_COLUMN: /* for lint */
15228  case SCIP_VARSTATUS_LOOSE: /* for lint */
15229  default:
15230  SCIPerrorMessage("unknown variable status\n");
15231  SCIPABORT();
15232  return SCIP_INVALID; /*lint !e527*/
15233  }
15234 }
15235 
15236 /** returns upper bound of variable directly before or after the bound change given by the bound change index
15237  * was applied
15238  */
15240  SCIP_VAR* var, /**< problem variable */
15241  SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
15242  SCIP_Bool after /**< should the bound change with given index be included? */
15243  )
15244 {
15245  SCIP_VARSTATUS varstatus;
15246  assert(var != NULL);
15247 
15248  varstatus = SCIPvarGetStatus(var);
15249 
15250  if( varstatus == SCIP_VARSTATUS_COLUMN || varstatus == SCIP_VARSTATUS_LOOSE )
15251  {
15252  if( bdchgidx == NULL )
15253  return SCIPvarGetUbLocal(var);
15254  else
15255  {
15256  SCIP_BDCHGINFO* bdchginfo;
15257 
15258  bdchginfo = SCIPvarGetUbchgInfo(var, bdchgidx, after);
15259  if( bdchginfo != NULL )
15260  return SCIPbdchginfoGetNewbound(bdchginfo);
15261  else
15262  return var->glbdom.ub;
15263  }
15264  }
15265 
15266  /* get bounds of attached variables */
15267  switch( varstatus )
15268  {
15270  assert(var->data.original.transvar != NULL);
15271  return SCIPvarGetUbAtIndex(var->data.original.transvar, bdchgidx, after);
15272 
15273  case SCIP_VARSTATUS_FIXED:
15274  return var->glbdom.ub;
15275 
15276  case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
15277  assert(var->data.aggregate.var != NULL);
15278  /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
15279  * corresponding infinity value instead of performing an arithmetical transformation (compare method
15280  * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
15281  * (or is called by) a public interface method; instead, we only assert that values are finite
15282  * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
15283  * positives and negatives if the parameter <numerics/infinity> is modified by the user
15284  */
15285  if( var->data.aggregate.scalar > 0.0 )
15286  {
15287  /* a > 0 -> get lower bound of y */
15288  assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
15289  assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
15290  return var->data.aggregate.scalar * SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after)
15291  + var->data.aggregate.constant;
15292  }
15293  else if( var->data.aggregate.scalar < 0.0 )
15294  {
15295  /* a < 0 -> get upper bound of y */
15296  assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
15297  assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
15298  return var->data.aggregate.scalar * SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after)
15299  + var->data.aggregate.constant;
15300  }
15301  else
15302  {
15303  SCIPerrorMessage("scalar is zero in aggregation\n");
15304  SCIPABORT();
15305  return SCIP_INVALID; /*lint !e527*/
15306  }
15307 
15309  SCIPerrorMessage("cannot get the bounds of a multiple aggregated variable.\n");
15310  SCIPABORT();
15311  return SCIP_INVALID; /*lint !e527*/
15312 
15313  case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
15314  assert(var->negatedvar != NULL);
15316  assert(var->negatedvar->negatedvar == var);
15317  return var->data.negate.constant - SCIPvarGetLbAtIndex(var->negatedvar, bdchgidx, after);
15318 
15319  case SCIP_VARSTATUS_COLUMN: /* for lint */
15320  case SCIP_VARSTATUS_LOOSE: /* for lint */
15321  default:
15322  SCIPerrorMessage("unknown variable status\n");
15323  SCIPABORT();
15324  return SCIP_INVALID; /*lint !e527*/
15325  }
15326 }
15327 
15328 /** returns lower or upper bound of variable directly before or after the bound change given by the bound change index
15329  * was applied
15330  */
15332  SCIP_VAR* var, /**< problem variable */
15333  SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */
15334  SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
15335  SCIP_Bool after /**< should the bound change with given index be included? */
15336  )
15337 {
15338  if( boundtype == SCIP_BOUNDTYPE_LOWER )
15339  return SCIPvarGetLbAtIndex(var, bdchgidx, after);
15340  else
15341  {
15342  assert(boundtype == SCIP_BOUNDTYPE_UPPER);
15343  return SCIPvarGetUbAtIndex(var, bdchgidx, after);
15344  }
15345 }
15346 
15347 /** returns whether the binary variable was fixed at the time given by the bound change index */
15349  SCIP_VAR* var, /**< problem variable */
15350  SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
15351  SCIP_Bool after /**< should the bound change with given index be included? */
15352  )
15353 {
15354  assert(var != NULL);
15355  assert(SCIPvarIsBinary(var));
15356 
15357  /* check the current bounds first in order to decide at which bound change information we have to look
15358  * (which is expensive because we have to follow the aggregation tree to the active variable)
15359  */
15360  return ((SCIPvarGetLbLocal(var) > 0.5 && SCIPvarGetLbAtIndex(var, bdchgidx, after) > 0.5)
15361  || (SCIPvarGetUbLocal(var) < 0.5 && SCIPvarGetUbAtIndex(var, bdchgidx, after) < 0.5));
15362 }
15363 
15364 /** bound change index representing the initial time before any bound changes took place */
15365 static SCIP_BDCHGIDX initbdchgidx = {-2, 0};
15366 
15367 /** bound change index representing the presolving stage */
15369 
15370 /** returns the last bound change index, at which the bounds of the given variable were tightened */
15372  SCIP_VAR* var /**< problem variable */
15373  )
15374 {
15375  SCIP_BDCHGIDX* lbchgidx;
15376  SCIP_BDCHGIDX* ubchgidx;
15377 
15378  assert(var != NULL);
15379 
15380  var = SCIPvarGetProbvar(var);
15381 
15382  /* check, if variable is original without transformed variable */
15383  if( var == NULL )
15384  return &initbdchgidx;
15385 
15386  /* check, if variable was fixed in presolving */
15387  if( !SCIPvarIsActive(var) )
15388  return &presolvebdchgidx;
15389 
15391 
15392  /* get depths of last bound change information for the lower and upper bound */
15393  lbchgidx = (var->nlbchginfos > 0 && !var->lbchginfos[var->nlbchginfos-1].redundant
15394  ? &var->lbchginfos[var->nlbchginfos-1].bdchgidx : &initbdchgidx);
15395  ubchgidx = (var->nubchginfos > 0 && !var->ubchginfos[var->nubchginfos-1].redundant
15396  ? &var->ubchginfos[var->nubchginfos-1].bdchgidx : &initbdchgidx);
15397 
15398  if( SCIPbdchgidxIsEarlierNonNull(lbchgidx, ubchgidx) )
15399  return ubchgidx;
15400  else
15401  return lbchgidx;
15402 }
15403 
15404 /** returns the last depth level, at which the bounds of the given variable were tightened;
15405  * returns -2, if the variable's bounds are still the global bounds
15406  * returns -1, if the variable was fixed in presolving
15407  */
15409  SCIP_VAR* var /**< problem variable */
15410  )
15411 {
15412  SCIP_BDCHGIDX* bdchgidx;
15413 
15414  bdchgidx = SCIPvarGetLastBdchgIndex(var);
15415  assert(bdchgidx != NULL);
15416 
15417  return bdchgidx->depth;
15418 }
15419 
15420 /** returns at which depth in the tree a bound change was applied to the variable that conflicts with the
15421  * given bound; returns -1 if the bound does not conflict with the current local bounds of the variable
15422  */
15424  SCIP_VAR* var, /**< problem variable */
15425  SCIP_SET* set, /**< global SCIP settings */
15426  SCIP_BOUNDTYPE boundtype, /**< bound type of the conflicting bound */
15427  SCIP_Real bound /**< conflicting bound */
15428  )
15429 {
15430  int i;
15431 
15432  assert(var != NULL);
15433  assert(set != NULL);
15434  assert(var->scip == set->scip);
15435 
15436  if( boundtype == SCIP_BOUNDTYPE_LOWER )
15437  {
15438  /* check if the bound is in conflict with the current local bounds */
15439  if( SCIPsetIsLE(set, bound, var->locdom.ub) )
15440  return -1;
15441 
15442  /* check if the bound is in conflict with the global bound */
15443  if( SCIPsetIsGT(set, bound, var->glbdom.ub) )
15444  return 0;
15445 
15446  /* local bounds are in conflict with the given bound -> there must be at least one conflicting change! */
15447  assert(var->nubchginfos > 0);
15448  assert(SCIPsetIsGT(set, bound, var->ubchginfos[var->nubchginfos-1].newbound));
15449 
15450  /* search for the first conflicting bound change */
15451  for( i = var->nubchginfos-1; i > 0 && SCIPsetIsGT(set, bound, var->ubchginfos[i-1].newbound); --i )
15452  {
15453  assert(var->ubchginfos[i].var == var); /* perform sanity check on the search for the first conflicting bound */
15455  }
15456  assert(SCIPsetIsGT(set, bound, var->ubchginfos[i].newbound)); /* bound change i is conflicting */
15457  assert(i == 0 || SCIPsetIsLE(set, bound, var->ubchginfos[i-1].newbound)); /* bound change i-1 is not conflicting */
15458 
15459  /* return the depth at which the first conflicting bound change took place */
15460  return var->ubchginfos[i].bdchgidx.depth;
15461  }
15462  else
15463  {
15464  assert(boundtype == SCIP_BOUNDTYPE_UPPER);
15465 
15466  /* check if the bound is in conflict with the current local bounds */
15467  if( SCIPsetIsGE(set, bound, var->locdom.lb) )
15468  return -1;
15469 
15470  /* check if the bound is in conflict with the global bound */
15471  if( SCIPsetIsLT(set, bound, var->glbdom.lb) )
15472  return 0;
15473 
15474  /* local bounds are in conflict with the given bound -> there must be at least one conflicting change! */
15475  assert(var->nlbchginfos > 0);
15476  assert(SCIPsetIsLT(set, bound, var->lbchginfos[var->nlbchginfos-1].newbound));
15477 
15478  /* search for the first conflicting bound change */
15479  for( i = var->nlbchginfos-1; i > 0 && SCIPsetIsLT(set, bound, var->lbchginfos[i-1].newbound); --i )
15480  {
15481  assert(var->lbchginfos[i].var == var); /* perform sanity check on the search for the first conflicting bound */
15483  }
15484  assert(SCIPsetIsLT(set, bound, var->lbchginfos[i].newbound)); /* bound change i is conflicting */
15485  assert(i == 0 || SCIPsetIsGE(set, bound, var->lbchginfos[i-1].newbound)); /* bound change i-1 is not conflicting */
15486 
15487  /* return the depth at which the first conflicting bound change took place */
15488  return var->lbchginfos[i].bdchgidx.depth;
15489  }
15490 }
15491 
15492 /** returns whether the first binary variable was fixed earlier than the second one;
15493  * returns FALSE, if the first variable is not fixed, and returns TRUE, if the first variable is fixed, but the
15494  * second one is not fixed
15495  */
15497  SCIP_VAR* var1, /**< first binary variable */
15498  SCIP_VAR* var2 /**< second binary variable */
15499  )
15500 {
15501  SCIP_BDCHGIDX* bdchgidx1;
15502  SCIP_BDCHGIDX* bdchgidx2;
15503 
15504  assert(var1 != NULL);
15505  assert(var2 != NULL);
15506  assert(SCIPvarIsBinary(var1));
15507  assert(SCIPvarIsBinary(var2));
15508 
15509  var1 = SCIPvarGetProbvar(var1);
15510  var2 = SCIPvarGetProbvar(var2);
15511  assert(var1 != NULL);
15512  assert(var2 != NULL);
15513 
15514  /* check, if variables are globally fixed */
15515  if( !SCIPvarIsActive(var2) || var2->glbdom.lb > 0.5 || var2->glbdom.ub < 0.5 )
15516  return FALSE;
15517  if( !SCIPvarIsActive(var1) || var1->glbdom.lb > 0.5 || var1->glbdom.ub < 0.5 )
15518  return TRUE;
15519 
15522  assert(SCIPvarIsBinary(var1));
15523  assert(SCIPvarIsBinary(var2));
15524  assert(var1->nlbchginfos + var1->nubchginfos <= 1);
15525  assert(var2->nlbchginfos + var2->nubchginfos <= 1);
15526  assert(var1->nlbchginfos == 0 || !var1->lbchginfos[0].redundant); /* otherwise, var would be globally fixed */
15527  assert(var1->nubchginfos == 0 || !var1->ubchginfos[0].redundant); /* otherwise, var would be globally fixed */
15528  assert(var2->nlbchginfos == 0 || !var2->lbchginfos[0].redundant); /* otherwise, var would be globally fixed */
15529  assert(var2->nubchginfos == 0 || !var2->ubchginfos[0].redundant); /* otherwise, var would be globally fixed */
15530 
15531  if( var1->nlbchginfos == 1 )
15532  bdchgidx1 = &var1->lbchginfos[0].bdchgidx;
15533  else if( var1->nubchginfos == 1 )
15534  bdchgidx1 = &var1->ubchginfos[0].bdchgidx;
15535  else
15536  bdchgidx1 = NULL;
15537 
15538  if( var2->nlbchginfos == 1 )
15539  bdchgidx2 = &var2->lbchginfos[0].bdchgidx;
15540  else if( var2->nubchginfos == 1 )
15541  bdchgidx2 = &var2->ubchginfos[0].bdchgidx;
15542  else
15543  bdchgidx2 = NULL;
15544 
15545  return SCIPbdchgidxIsEarlier(bdchgidx1, bdchgidx2);
15546 }
15547 
15548 
15549 
15550 /*
15551  * Hash functions
15552  */
15553 
15554 /** gets the key (i.e. the name) of the given variable */
15555 SCIP_DECL_HASHGETKEY(SCIPhashGetKeyVar)
15556 { /*lint --e{715}*/
15557  SCIP_VAR* var = (SCIP_VAR*)elem;
15558 
15559  assert(var != NULL);
15560  return var->name;
15561 }
15562 
15563 
15564 
15565 
15566 /*
15567  * simple functions implemented as defines
15568  */
15569 
15570 /* In debug mode, the following methods are implemented as function calls to ensure
15571  * type validity.
15572  * In optimized mode, the methods are implemented as defines to improve performance.
15573  * However, we want to have them in the library anyways, so we have to undef the defines.
15574  */
15575 
15576 #undef SCIPboundchgGetNewbound
15577 #undef SCIPboundchgGetVar
15578 #undef SCIPboundchgGetBoundchgtype
15579 #undef SCIPboundchgGetBoundtype
15580 #undef SCIPboundchgIsRedundant
15581 #undef SCIPdomchgGetNBoundchgs
15582 #undef SCIPdomchgGetBoundchg
15583 #undef SCIPholelistGetLeft
15584 #undef SCIPholelistGetRight
15585 #undef SCIPholelistGetNext
15586 #undef SCIPvarGetName
15587 #undef SCIPvarGetNUses
15588 #undef SCIPvarGetData
15589 #undef SCIPvarSetData
15590 #undef SCIPvarSetDelorigData
15591 #undef SCIPvarSetTransData
15592 #undef SCIPvarSetDeltransData
15593 #undef SCIPvarGetStatus
15594 #undef SCIPvarIsOriginal
15595 #undef SCIPvarIsTransformed
15596 #undef SCIPvarIsNegated
15597 #undef SCIPvarGetType
15598 #undef SCIPvarIsBinary
15599 #undef SCIPvarIsIntegral
15600 #undef SCIPvarIsInitial
15601 #undef SCIPvarIsRemovable
15602 #undef SCIPvarIsDeleted
15603 #undef SCIPvarIsDeletable
15604 #undef SCIPvarMarkDeletable
15605 #undef SCIPvarMarkNotDeletable
15606 #undef SCIPvarIsActive
15607 #undef SCIPvarGetIndex
15608 #undef SCIPvarGetProbindex
15609 #undef SCIPvarGetTransVar
15610 #undef SCIPvarGetCol
15611 #undef SCIPvarIsInLP
15612 #undef SCIPvarGetAggrVar
15613 #undef SCIPvarGetAggrScalar
15614 #undef SCIPvarGetAggrConstant
15615 #undef SCIPvarGetMultaggrNVars
15616 #undef SCIPvarGetMultaggrVars
15617 #undef SCIPvarGetMultaggrScalars
15618 #undef SCIPvarGetMultaggrConstant
15619 #undef SCIPvarGetNegatedVar
15620 #undef SCIPvarGetNegationVar
15621 #undef SCIPvarGetNegationConstant
15622 #undef SCIPvarGetObj
15623 #undef SCIPvarGetLbOriginal
15624 #undef SCIPvarGetUbOriginal
15625 #undef SCIPvarGetHolelistOriginal
15626 #undef SCIPvarGetLbGlobal
15627 #undef SCIPvarGetUbGlobal
15628 #undef SCIPvarGetHolelistGlobal
15629 #undef SCIPvarGetBestBoundGlobal
15630 #undef SCIPvarGetWorstBoundGlobal
15631 #undef SCIPvarGetLbLocal
15632 #undef SCIPvarGetUbLocal
15633 #undef SCIPvarGetHolelistLocal
15634 #undef SCIPvarGetBestBoundLocal
15635 #undef SCIPvarGetWorstBoundLocal
15636 #undef SCIPvarGetBestBoundType
15637 #undef SCIPvarGetWorstBoundType
15638 #undef SCIPvarGetLbLazy
15639 #undef SCIPvarGetUbLazy
15640 #undef SCIPvarGetBranchFactor
15641 #undef SCIPvarGetBranchPriority
15642 #undef SCIPvarGetBranchDirection
15643 #undef SCIPvarGetNVlbs
15644 #undef SCIPvarGetVlbVars
15645 #undef SCIPvarGetVlbCoefs
15646 #undef SCIPvarGetVlbConstants
15647 #undef SCIPvarGetNVubs
15648 #undef SCIPvarGetVubVars
15649 #undef SCIPvarGetVubCoefs
15650 #undef SCIPvarGetVubConstants
15651 #undef SCIPvarGetNImpls
15652 #undef SCIPvarGetNBinImpls
15653 #undef SCIPvarGetImplVars
15654 #undef SCIPvarGetImplTypes
15655 #undef SCIPvarGetImplBounds
15656 #undef SCIPvarGetImplIds
15657 #undef SCIPvarGetNCliques
15658 #undef SCIPvarGetCliques
15659 #undef SCIPvarGetLPSol
15660 #undef SCIPvarGetNLPSol
15661 #undef SCIPvarGetBdchgInfoLb
15662 #undef SCIPvarGetNBdchgInfosLb
15663 #undef SCIPvarGetBdchgInfoUb
15664 #undef SCIPvarGetNBdchgInfosUb
15665 #undef SCIPvarGetValuehistory
15666 #undef SCIPvarGetPseudoSol
15667 #undef SCIPvarCatchEvent
15668 #undef SCIPvarDropEvent
15669 #undef SCIPvarGetVSIDS
15670 #undef SCIPbdchgidxGetPos
15671 #undef SCIPbdchgidxIsEarlierNonNull
15672 #undef SCIPbdchgidxIsEarlier
15673 #undef SCIPbdchginfoGetOldbound
15674 #undef SCIPbdchginfoGetNewbound
15675 #undef SCIPbdchginfoGetVar
15676 #undef SCIPbdchginfoGetChgtype
15677 #undef SCIPbdchginfoGetBoundtype
15678 #undef SCIPbdchginfoGetDepth
15679 #undef SCIPbdchginfoGetPos
15680 #undef SCIPbdchginfoGetIdx
15681 #undef SCIPbdchginfoGetInferVar
15682 #undef SCIPbdchginfoGetInferCons
15683 #undef SCIPbdchginfoGetInferProp
15684 #undef SCIPbdchginfoGetInferInfo
15685 #undef SCIPbdchginfoGetInferBoundtype
15686 #undef SCIPbdchginfoIsRedundant
15687 #undef SCIPbdchginfoHasInferenceReason
15688 #undef SCIPbdchginfoIsTighter
15689 
15690 /** returns the new value of the bound in the bound change data */
15692  SCIP_BOUNDCHG* boundchg /**< bound change data */
15693  )
15694 {
15695  assert(boundchg != NULL);
15696 
15697  return boundchg->newbound;
15698 }
15699 
15700 /** returns the variable of the bound change in the bound change data */
15702  SCIP_BOUNDCHG* boundchg /**< bound change data */
15703  )
15704 {
15705  assert(boundchg != NULL);
15706 
15707  return boundchg->var;
15708 }
15709 
15710 /** returns the bound change type of the bound change in the bound change data */
15712  SCIP_BOUNDCHG* boundchg /**< bound change data */
15713  )
15714 {
15715  assert(boundchg != NULL);
15716 
15717  return (SCIP_BOUNDCHGTYPE)(boundchg->boundchgtype);
15718 }
15719 
15720 /** returns the bound type of the bound change in the bound change data */
15722  SCIP_BOUNDCHG* boundchg /**< bound change data */
15723  )
15724 {
15725  assert(boundchg != NULL);
15726 
15727  return (SCIP_BOUNDTYPE)(boundchg->boundtype);
15728 }
15729 
15730 /** returns whether the bound change is redundant due to a more global bound that is at least as strong */
15732  SCIP_BOUNDCHG* boundchg /**< bound change data */
15733  )
15734 {
15735  assert(boundchg != NULL);
15736 
15737  return boundchg->redundant;
15738 }
15739 
15740 /** returns the number of bound changes in the domain change data */
15742  SCIP_DOMCHG* domchg /**< domain change data */
15743  )
15744 {
15745  return domchg != NULL ? domchg->domchgbound.nboundchgs : 0;
15746 }
15747 
15748 /** returns a particular bound change in the domain change data */
15750  SCIP_DOMCHG* domchg, /**< domain change data */
15751  int pos /**< position of the bound change in the domain change data */
15752  )
15753 {
15754  assert(domchg != NULL);
15755  assert(0 <= pos && pos < (int)domchg->domchgbound.nboundchgs);
15756 
15757  return &domchg->domchgbound.boundchgs[pos];
15758 }
15759 
15760 /** returns left bound of open interval in hole */
15762  SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */
15763  )
15764 {
15765  assert(holelist != NULL);
15766 
15767  return holelist->hole.left;
15768 }
15769 
15770 /** returns right bound of open interval in hole */
15772  SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */
15773  )
15774 {
15775  assert(holelist != NULL);
15776 
15777  return holelist->hole.right;
15778 }
15779 
15780 /** returns next hole in list */
15782  SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */
15783  )
15784 {
15785  assert(holelist != NULL);
15786 
15787  return holelist->next;
15788 }
15789 
15790 /** returns the name of the variable
15791  *
15792  * @note to change the name of a variable, use SCIPchgVarName() from scip.h
15793  */
15794 const char* SCIPvarGetName(
15795  SCIP_VAR* var /**< problem variable */
15796  )
15797 {
15798  assert(var != NULL);
15799 
15800  return var->name;
15801 }
15802 
15803 /** gets number of times, the variable is currently captured */
15805  SCIP_VAR* var /**< problem variable */
15806  )
15807 {
15808  assert(var != NULL);
15809 
15810  return var->nuses;
15811 }
15812 
15813 /** returns the user data of the variable */
15815  SCIP_VAR* var /**< problem variable */
15816  )
15817 {
15818  assert(var != NULL);
15819 
15820  return var->vardata;
15821 }
15822 
15823 /** sets the user data for the variable */
15825  SCIP_VAR* var, /**< problem variable */
15826  SCIP_VARDATA* vardata /**< user variable data */
15827  )
15828 {
15829  assert(var != NULL);
15830 
15831  var->vardata = vardata;
15832 }
15833 
15834 /** sets method to free user data for the original variable */
15836  SCIP_VAR* var, /**< problem variable */
15837  SCIP_DECL_VARDELORIG ((*vardelorig)) /**< frees user data of original variable */
15838  )
15839 {
15840  assert(var != NULL);
15841  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL);
15842 
15843  var->vardelorig = vardelorig;
15844 }
15845 
15846 /** sets method to transform user data of the variable */
15848  SCIP_VAR* var, /**< problem variable */
15849  SCIP_DECL_VARTRANS ((*vartrans)) /**< creates transformed user data by transforming original user data */
15850  )
15851 {
15852  assert(var != NULL);
15853  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL);
15854 
15855  var->vartrans = vartrans;
15856 }
15857 
15858 /** sets method to free transformed user data for the variable */
15860  SCIP_VAR* var, /**< problem variable */
15861  SCIP_DECL_VARDELTRANS ((*vardeltrans)) /**< frees user data of transformed variable */
15862  )
15863 {
15864  assert(var != NULL);
15865 
15866  var->vardeltrans = vardeltrans;
15867 }
15868 
15869 /** sets method to copy this variable into sub-SCIPs */
15871  SCIP_VAR* var, /**< problem variable */
15872  SCIP_DECL_VARCOPY ((*varcopy)) /**< copy method of the variable */
15873  )
15874 {
15875  assert(var != NULL);
15876 
15877  var->varcopy = varcopy;
15878 }
15879 
15880 /** sets the initial flag of a variable; only possible for original or loose variables */
15882  SCIP_VAR* var, /**< problem variable */
15883  SCIP_Bool initial /**< initial flag */
15884  )
15885 {
15886  assert(var != NULL);
15887 
15889  return SCIP_INVALIDCALL;
15890 
15891  var->initial = initial;
15892 
15893  return SCIP_OKAY;
15894 }
15895 
15896 /** sets the removable flag of a variable; only possible for original or loose variables */
15898  SCIP_VAR* var, /**< problem variable */
15899  SCIP_Bool removable /**< removable flag */
15900  )
15901 {
15902  assert(var != NULL);
15903 
15905  return SCIP_INVALIDCALL;
15906 
15907  var->removable = removable;
15908 
15909  return SCIP_OKAY;
15910 }
15911 
15912 /** gets status of variable */
15914  SCIP_VAR* var /**< problem variable */
15915  )
15916 {
15917  assert(var != NULL);
15918 
15919  return (SCIP_VARSTATUS)(var->varstatus);
15920 }
15921 
15922 /** returns whether the variable belongs to the original problem */
15924  SCIP_VAR* var /**< problem variable */
15925  )
15926 {
15927  assert(var != NULL);
15928  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED || var->negatedvar != NULL);
15929 
15933 }
15934 
15935 /** returns whether the variable belongs to the transformed problem */
15937  SCIP_VAR* var /**< problem variable */
15938  )
15939 {
15940  assert(var != NULL);
15941  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED || var->negatedvar != NULL);
15942 
15946 }
15947 
15948 /** returns whether the variable was created by negation of a different variable */
15950  SCIP_VAR* var /**< problem variable */
15951  )
15952 {
15953  assert(var != NULL);
15954 
15955  return (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
15956 }
15957 
15958 /** gets type of variable */
15960  SCIP_VAR* var /**< problem variable */
15961  )
15962 {
15963  assert(var != NULL);
15964 
15965  return (SCIP_VARTYPE)(var->vartype);
15966 }
15967 
15968 /** returns TRUE if the variable is of binary type; this is the case if:
15969  * (1) variable type is binary
15970  * (2) variable type is integer or implicit integer and
15971  * (i) the lazy lower bound or the global lower bound is greater or equal to zero
15972  * (ii) the lazy upper bound or the global upper bound is less tor equal to one
15973  */
15975  SCIP_VAR* var /**< problem variable */
15976  )
15977 {
15978  assert(var != NULL);
15979 
15980  return (SCIPvarGetType(var) == SCIP_VARTYPE_BINARY ||
15981  (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && MAX(var->glbdom.lb, var->lazylb) >= 0.0 && MIN(var->glbdom.ub, var->lazyub) <= 1.0));
15982 }
15983 
15984 /** returns whether variable is of integral type (binary, integer, or implicit integer) */
15986  SCIP_VAR* var /**< problem variable */
15987  )
15988 {
15989  assert(var != NULL);
15990 
15991  return (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
15992 }
15993 
15994 /** returns whether variable's column should be present in the initial root LP */
15996  SCIP_VAR* var /**< problem variable */
15997  )
15998 {
15999  assert(var != NULL);
16000 
16001  return var->initial;
16002 }
16003 
16004 /** returns whether variable's column is removable from the LP (due to aging or cleanup) */
16006  SCIP_VAR* var /**< problem variable */
16007  )
16008 {
16009  assert(var != NULL);
16010 
16011  return var->removable;
16012 }
16013 
16014 /** returns whether the variable was deleted from the problem */
16016  SCIP_VAR* var /**< problem variable */
16017  )
16018 {
16019  assert(var != NULL);
16020 
16021  return var->deleted;
16022 }
16023 
16024 /** marks the variable to be deletable, i.e., it may be deleted completely from the problem;
16025  * method can only be called before the variable is added to the problem by SCIPaddVar() or SCIPaddPricedVar()
16026  */
16028  SCIP_VAR* var /**< problem variable */
16029  )
16030 {
16031  assert(var != NULL);
16032  assert(var->probindex == -1);
16033 
16034  var->deletable = TRUE;
16035 }
16036 
16037 /** marks the variable to be not deletable from the problem */
16039  SCIP_VAR* var
16040  )
16041 {
16042  assert(var != NULL);
16043 
16044  var->deletable = FALSE;
16045 }
16046 
16047 /** returns whether variable is allowed to be deleted completely from the problem */
16049  SCIP_VAR* var
16050  )
16051 {
16052  assert(var != NULL);
16053 
16054  return var->deletable;
16055 }
16056 
16057 /** returns whether variable is an active (neither fixed nor aggregated) variable */
16059  SCIP_VAR* var /**< problem variable */
16060  )
16061 {
16062  assert(var != NULL);
16063 
16064  return (var->probindex >= 0);
16065 }
16066 
16067 /** gets unique index of variable */
16069  SCIP_VAR* var /**< problem variable */
16070  )
16071 {
16072  assert(var != NULL);
16073 
16074  return var->index;
16075 }
16076 
16077 /** gets position of variable in problem, or -1 if variable is not active */
16079  SCIP_VAR* var /**< problem variable */
16080  )
16081 {
16082  assert(var != NULL);
16083 
16084  return var->probindex;
16085 }
16086 
16087 /** gets transformed variable of ORIGINAL variable */
16089  SCIP_VAR* var /**< problem variable */
16090  )
16091 {
16092  assert(var != NULL);
16093  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL);
16094 
16095  return var->data.original.transvar;
16096 }
16097 
16098 /** gets column of COLUMN variable */
16100  SCIP_VAR* var /**< problem variable */
16101  )
16102 {
16103  assert(var != NULL);
16104  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
16105 
16106  return var->data.col;
16107 }
16108 
16109 /** returns whether the variable is a COLUMN variable that is member of the current LP */
16111  SCIP_VAR* var /**< problem variable */
16112  )
16113 {
16114  assert(var != NULL);
16115 
16116  return (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN && SCIPcolIsInLP(var->data.col));
16117 }
16118 
16119 /** gets aggregation variable y of an aggregated variable x = a*y + c */
16121  SCIP_VAR* var /**< problem variable */
16122  )
16123 {
16124  assert(var != NULL);
16126 
16127  return var->data.aggregate.var;
16128 }
16129 
16130 /** gets aggregation scalar a of an aggregated variable x = a*y + c */
16132  SCIP_VAR* var /**< problem variable */
16133  )
16134 {
16135  assert(var != NULL);
16137 
16138  return var->data.aggregate.scalar;
16139 }
16140 
16141 /** gets aggregation constant c of an aggregated variable x = a*y + c */
16143  SCIP_VAR* var /**< problem variable */
16144  )
16145 {
16146  assert(var != NULL);
16148 
16149  return var->data.aggregate.constant;
16150 }
16151 
16152 /** gets number n of aggregation variables of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
16154  SCIP_VAR* var /**< problem variable */
16155  )
16156 {
16157  assert(var != NULL);
16158  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
16159  assert(!var->donotmultaggr);
16160 
16161  return var->data.multaggr.nvars;
16162 }
16163 
16164 /** gets vector of aggregation variables y of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
16166  SCIP_VAR* var /**< problem variable */
16167  )
16168 {
16169  assert(var != NULL);
16170  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
16171  assert(!var->donotmultaggr);
16172 
16173  return var->data.multaggr.vars;
16174 }
16175 
16176 /** gets vector of aggregation scalars a of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
16178  SCIP_VAR* var /**< problem variable */
16179  )
16180 {
16181  assert(var != NULL);
16182  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
16183  assert(!var->donotmultaggr);
16184 
16185  return var->data.multaggr.scalars;
16186 }
16187 
16188 /** gets aggregation constant c of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
16190  SCIP_VAR* var /**< problem variable */
16191  )
16192 {
16193  assert(var != NULL);
16194  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
16195  assert(!var->donotmultaggr);
16196 
16197  return var->data.multaggr.constant;
16198 }
16199 
16200 /** gets the negation of the given variable; may return NULL, if no negation is existing yet */
16202  SCIP_VAR* var /**< negated problem variable */
16203  )
16204 {
16205  assert(var != NULL);
16206 
16207  return var->negatedvar;
16208 }
16209 
16210 /** gets the negation variable x of a negated variable x' = offset - x */
16212  SCIP_VAR* var /**< negated problem variable */
16213  )
16214 {
16215  assert(var != NULL);
16216  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
16217 
16218  return var->negatedvar;
16219 }
16220 
16221 /** gets the negation offset of a negated variable x' = offset - x */
16223  SCIP_VAR* var /**< negated problem variable */
16224  )
16225 {
16226  assert(var != NULL);
16227  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
16228 
16229  return var->data.negate.constant;
16230 }
16231 
16232 /** gets objective function value of variable */
16234  SCIP_VAR* var /**< problem variable */
16235  )
16236 {
16237  assert(var != NULL);
16238 
16239  return var->obj;
16240 }
16241 
16242 
16243 /** gets corresponding objective value of active, fixed, or multi-aggregated problem variable of given variable
16244  * e.g. obj(x) = 1 this method returns for ~x the value -1
16245  */
16247  SCIP_VAR* var, /**< problem variable */
16248  SCIP_Real* aggrobj /**< pointer to store the aggregated objective value */
16249  )
16250 {
16251  SCIP_VAR* probvar = var;
16252  SCIP_Real mult = 1.0;
16253 
16254  assert(probvar != NULL);
16255  assert(aggrobj != NULL);
16256 
16257  while( probvar != NULL )
16258  {
16259  switch( SCIPvarGetStatus(probvar) )
16260  {
16262  case SCIP_VARSTATUS_LOOSE:
16263  case SCIP_VARSTATUS_COLUMN:
16264  (*aggrobj) = mult * SCIPvarGetObj(probvar);
16265  return SCIP_OKAY;
16266 
16267  case SCIP_VARSTATUS_FIXED:
16268  assert(SCIPvarGetObj(probvar) == 0.0);
16269  (*aggrobj) = 0.0;
16270  return SCIP_OKAY;
16271 
16273  /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
16274  if ( probvar->data.multaggr.nvars == 1 )
16275  {
16276  assert( probvar->data.multaggr.vars != NULL );
16277  assert( probvar->data.multaggr.scalars != NULL );
16278  assert( probvar->data.multaggr.vars[0] != NULL );
16279  mult *= probvar->data.multaggr.scalars[0];
16280  probvar = probvar->data.multaggr.vars[0];
16281  break;
16282  }
16283  else
16284  {
16285  SCIP_Real tmpobj;
16286  int v;
16287 
16288  (*aggrobj) = 0.0;
16289 
16290  for( v = probvar->data.multaggr.nvars - 1; v >= 0; --v )
16291  {
16292  SCIP_CALL( SCIPvarGetAggregatedObj(probvar->data.multaggr.vars[v], &tmpobj) );
16293  (*aggrobj) += probvar->data.multaggr.scalars[v] * tmpobj;
16294  }
16295  return SCIP_OKAY;
16296  }
16297 
16298  case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */
16299  assert(probvar->data.aggregate.var != NULL);
16300  mult *= probvar->data.aggregate.scalar;
16301  probvar = probvar->data.aggregate.var;
16302  break;
16303 
16304  case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */
16305  assert(probvar->negatedvar != NULL);
16306  assert(SCIPvarGetStatus(probvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
16307  assert(probvar->negatedvar->negatedvar == probvar);
16308  mult *= -1.0;
16309  probvar = probvar->negatedvar;
16310  break;
16311 
16312  default:
16313  SCIPABORT();
16314  return SCIP_INVALIDDATA; /*lint !e527*/
16315  }
16316  }
16317 
16318  return SCIP_INVALIDDATA;
16319 }
16320 
16321 /** gets original lower bound of original problem variable (i.e. the bound set in problem creation) */
16323  SCIP_VAR* var /**< original problem variable */
16324  )
16325 {
16326  assert(var != NULL);
16327  assert(SCIPvarIsOriginal(var));
16328 
16330  return var->data.original.origdom.lb;
16331  else
16332  {
16333  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
16334  assert(var->negatedvar != NULL);
16336 
16337  return var->data.negate.constant - var->negatedvar->data.original.origdom.ub;
16338  }
16339 }
16340 
16341 /** gets original upper bound of original problem variable (i.e. the bound set in problem creation) */
16343  SCIP_VAR* var /**< original problem variable */
16344  )
16345 {
16346  assert(var != NULL);
16347  assert(SCIPvarIsOriginal(var));
16348 
16350  return var->data.original.origdom.ub;
16351  else
16352  {
16353  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
16354  assert(var->negatedvar != NULL);
16356 
16357  return var->data.negate.constant - var->negatedvar->data.original.origdom.lb;
16358  }
16359 }
16360 
16361 /** gets the original hole list of an original variable */
16363  SCIP_VAR* var /**< problem variable */
16364  )
16365 {
16366  assert(var != NULL);
16367  assert(SCIPvarIsOriginal(var));
16368 
16370  return var->data.original.origdom.holelist;
16371 
16372  return NULL;
16373 }
16374 
16375 /** gets global lower bound of variable */
16377  SCIP_VAR* var /**< problem variable */
16378  )
16379 {
16380  assert(var != NULL);
16381 
16382  return var->glbdom.lb;
16383 }
16384 
16385 /** gets global upper bound of variable */
16387  SCIP_VAR* var /**< problem variable */
16388  )
16389 {
16390  assert(var != NULL);
16391 
16392  return var->glbdom.ub;
16393 }
16394 
16395 /** gets the global hole list of an active variable */
16397  SCIP_VAR* var /**< problem variable */
16398  )
16399 {
16400  assert(var != NULL);
16401 
16402  return var->glbdom.holelist;
16403 }
16404 
16405 /** gets best global bound of variable with respect to the objective function */
16407  SCIP_VAR* var /**< problem variable */
16408  )
16409 {
16410  assert(var != NULL);
16411 
16412  if( var->obj >= 0.0 )
16413  return var->glbdom.lb;
16414  else
16415  return var->glbdom.ub;
16416 }
16417 
16418 /** gets worst global bound of variable with respect to the objective function */
16420  SCIP_VAR* var /**< problem variable */
16421  )
16422 {
16423  assert(var != NULL);
16424 
16425  if( var->obj >= 0.0 )
16426  return var->glbdom.ub;
16427  else
16428  return var->glbdom.lb;
16429 }
16430 
16431 /** gets current lower bound of variable */
16433  SCIP_VAR* var /**< problem variable */
16434  )
16435 {
16436  assert(var != NULL);
16437 
16438  return var->locdom.lb;
16439 }
16440 
16441 /** gets current upper bound of variable */
16443  SCIP_VAR* var /**< problem variable */
16444  )
16445 {
16446  assert(var != NULL);
16447 
16448  return var->locdom.ub;
16449 }
16450 
16451 /** gets the current hole list of an active variable */
16453  SCIP_VAR* var /**< problem variable */
16454  )
16455 {
16456  assert(var != NULL);
16457 
16458  return var->locdom.holelist;
16459 }
16460 
16461 /** gets best local bound of variable with respect to the objective function */
16463  SCIP_VAR* var /**< problem variable */
16464  )
16465 {
16466  assert(var != NULL);
16467 
16468  if( var->obj >= 0.0 )
16469  return var->locdom.lb;
16470  else
16471  return var->locdom.ub;
16472 }
16473 
16474 /** gets worst local bound of variable with respect to the objective function */
16476  SCIP_VAR* var /**< problem variable */
16477  )
16478 {
16479  assert(var != NULL);
16480 
16481  if( var->obj >= 0.0 )
16482  return var->locdom.ub;
16483  else
16484  return var->locdom.lb;
16485 }
16486 
16487 /** gets type (lower or upper) of best bound of variable with respect to the objective function */
16489  SCIP_VAR* var /**< problem variable */
16490  )
16491 {
16492  assert(var != NULL);
16493 
16494  if( var->obj >= 0.0 )
16495  return SCIP_BOUNDTYPE_LOWER;
16496  else
16497  return SCIP_BOUNDTYPE_UPPER;
16498 }
16499 
16500 /** gets type (lower or upper) of worst bound of variable with respect to the objective function */
16502  SCIP_VAR* var /**< problem variable */
16503  )
16504 {
16505  assert(var != NULL);
16506 
16507  if( var->obj >= 0.0 )
16508  return SCIP_BOUNDTYPE_UPPER;
16509  else
16510  return SCIP_BOUNDTYPE_LOWER;
16511 }
16512 
16513 /** gets lazy lower bound of variable, returns -infinity if the variable has no lazy lower bound */
16515  SCIP_VAR* var /**< problem variable */
16516  )
16517 {
16518  assert(var != NULL);
16519 
16520  return var->lazylb;
16521 }
16522 
16523 /** gets lazy upper bound of variable, returns infinity if the variable has no lazy upper bound */
16525  SCIP_VAR* var /**< problem variable */
16526  )
16527 {
16528  assert(var != NULL);
16529 
16530  return var->lazyub;
16531 }
16532 
16533 /** gets the branch factor of the variable; this value can be used in the branching methods to scale the score
16534  * values of the variables; higher factor leads to a higher probability that this variable is chosen for branching
16535  */
16537  SCIP_VAR* var /**< problem variable */
16538  )
16539 {
16540  assert(var != NULL);
16541 
16542  return var->branchfactor;
16543 }
16544 
16545 /** gets the branch priority of the variable; variables with higher priority should always be preferred to variables
16546  * with lower priority
16547  */
16549  SCIP_VAR* var /**< problem variable */
16550  )
16551 {
16552  assert(var != NULL);
16553 
16554  return var->branchpriority;
16555 }
16556 
16557 /** gets the preferred branch direction of the variable (downwards, upwards, or auto) */
16559  SCIP_VAR* var /**< problem variable */
16560  )
16561 {
16562  assert(var != NULL);
16563 
16564  return (SCIP_BRANCHDIR)var->branchdirection;
16565 }
16566 
16567 /** gets number of variable lower bounds x >= b_i*z_i + d_i of given variable x */
16569  SCIP_VAR* var /**< problem variable */
16570  )
16571 {
16572  assert(var != NULL);
16573 
16574  return SCIPvboundsGetNVbds(var->vlbs);
16575 }
16576 
16577 /** gets array with bounding variables z_i in variable lower bounds x >= b_i*z_i + d_i of given variable x;
16578  * the variable bounds are sorted by increasing variable index of the bounding variable z_i (see SCIPvarGetIndex())
16579  */
16581  SCIP_VAR* var /**< problem variable */
16582  )
16583 {
16584  assert(var != NULL);
16585 
16586  return SCIPvboundsGetVars(var->vlbs);
16587 }
16588 
16589 /** gets array with bounding coefficients b_i in variable lower bounds x >= b_i*z_i + d_i of given variable x */
16591  SCIP_VAR* var /**< problem variable */
16592  )
16593 {
16594  assert(var != NULL);
16595 
16596  return SCIPvboundsGetCoefs(var->vlbs);
16597 }
16598 
16599 /** gets array with bounding constants d_i in variable lower bounds x >= b_i*z_i + d_i of given variable x */
16601  SCIP_VAR* var /**< problem variable */
16602  )
16603 {
16604  assert(var != NULL);
16605 
16606  return SCIPvboundsGetConstants(var->vlbs);
16607 }
16608 
16609 /** gets number of variable upper bounds x <= b_i*z_i + d_i of given variable x */
16611  SCIP_VAR* var /**< problem variable */
16612  )
16613 {
16614  assert(var != NULL);
16615 
16616  return SCIPvboundsGetNVbds(var->vubs);
16617 }
16618 
16619 /** gets array with bounding variables z_i in variable upper bounds x <= b_i*z_i + d_i of given variable x;
16620  * the variable bounds are sorted by increasing variable index of the bounding variable z_i (see SCIPvarGetIndex())
16621  */
16623  SCIP_VAR* var /**< problem variable */
16624  )
16625 {
16626  assert(var != NULL);
16627 
16628  return SCIPvboundsGetVars(var->vubs);
16629 }
16630 
16631 /** gets array with bounding coefficients b_i in variable upper bounds x <= b_i*z_i + d_i of given variable x */
16633  SCIP_VAR* var /**< problem variable */
16634  )
16635 {
16636  assert(var != NULL);
16637 
16638  return SCIPvboundsGetCoefs(var->vubs);
16639 }
16640 
16641 /** gets array with bounding constants d_i in variable upper bounds x <= b_i*z_i + d_i of given variable x */
16643  SCIP_VAR* var /**< problem variable */
16644  )
16645 {
16646  assert(var != NULL);
16647 
16648  return SCIPvboundsGetConstants(var->vubs);
16649 }
16650 
16651 /** gets number of implications y <= b or y >= b for x == 0 or x == 1 of given active problem variable x,
16652  * there are no implications for nonbinary variable x
16653  */
16655  SCIP_VAR* var, /**< active problem variable */
16656  SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
16657  )
16658 {
16659  assert(var != NULL);
16660  assert(SCIPvarIsActive(var));
16661 
16662  return SCIPimplicsGetNImpls(var->implics, varfixing);
16663 }
16664 
16665 /** gets number of implications y <= 0 or y >= 1 for x == 0 or x == 1 of given active problem variable x with binary y,
16666  * there are no implications for nonbinary variable x
16667  */
16669  SCIP_VAR* var, /**< active problem variable */
16670  SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
16671  )
16672 {
16673  assert(var != NULL);
16674  assert(SCIPvarIsActive(var));
16675 
16676  return SCIPimplicsGetNBinImpls(var->implics, varfixing);
16677 }
16678 
16679 /** gets array with implication variables y of implications y <= b or y >= b for x == 0 or x == 1 of given active
16680  * problem variable x, there are no implications for nonbinary variable x;
16681  * the implications are sorted such that implications with binary implied variables precede the ones with non-binary
16682  * implied variables, and as a second criteria, the implied variables are sorted by increasing variable index
16683  * (see SCIPvarGetIndex())
16684  */
16686  SCIP_VAR* var, /**< active problem variable */
16687  SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
16688  )
16689 {
16690  assert(var != NULL);
16691  assert(SCIPvarIsActive(var));
16692 
16693  return SCIPimplicsGetVars(var->implics, varfixing);
16694 }
16695 
16696 /** gets array with implication types of implications y <= b or y >= b for x == 0 or x == 1 of given active problem
16697  * variable x (SCIP_BOUNDTYPE_UPPER if y <= b, SCIP_BOUNDTYPE_LOWER if y >= b),
16698  * there are no implications for nonbinary variable x
16699  */
16701  SCIP_VAR* var, /**< active problem variable */
16702  SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
16703  )
16704 {
16705  assert(var != NULL);
16706  assert(SCIPvarIsActive(var));
16707 
16708  return SCIPimplicsGetTypes(var->implics, varfixing);
16709 }
16710 
16711 /** gets array with implication bounds b of implications y <= b or y >= b for x == 0 or x == 1 of given active problem
16712  * variable x, there are no implications for nonbinary variable x
16713  */
16715  SCIP_VAR* var, /**< active problem variable */
16716  SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
16717  )
16718 {
16719  assert(var != NULL);
16720  assert(SCIPvarIsActive(var));
16721 
16722  return SCIPimplicsGetBounds(var->implics, varfixing);
16723 }
16724 
16725 /** Gets array with unique ids of implications y <= b or y >= b for x == 0 or x == 1 of given active problem variable x,
16726  * there are no implications for nonbinary variable x.
16727  * If an implication is a shortcut, i.e., it was added as part of the transitive closure of another implication,
16728  * its id is negative, otherwise it is nonnegative.
16729  */
16731  SCIP_VAR* var, /**< active problem variable */
16732  SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
16733  )
16734 {
16735  assert(var != NULL);
16736  assert(SCIPvarIsActive(var));
16737 
16738  return SCIPimplicsGetIds(var->implics, varfixing);
16739 }
16740 
16741 /** gets number of cliques, the active variable is contained in */
16743  SCIP_VAR* var, /**< active problem variable */
16744  SCIP_Bool varfixing /**< FALSE for cliques containing x == 0, TRUE for x == 1 */
16745  )
16746 {
16747  assert(var != NULL);
16748  assert(SCIPvarIsActive(var));
16749 
16750  return SCIPcliquelistGetNCliques(var->cliquelist, varfixing);
16751 }
16752 
16753 /** gets array of cliques, the active variable is contained in */
16755  SCIP_VAR* var, /**< active problem variable */
16756  SCIP_Bool varfixing /**< FALSE for cliques containing x == 0, TRUE for x == 1 */
16757  )
16758 {
16759  assert(var != NULL);
16760  assert(SCIPvarIsActive(var));
16761 
16762  return SCIPcliquelistGetCliques(var->cliquelist, varfixing);
16763 }
16764 
16765 /** gets primal LP solution value of variable */
16767  SCIP_VAR* var /**< problem variable */
16768  )
16769 {
16770  assert(var != NULL);
16771 
16773  return SCIPcolGetPrimsol(var->data.col);
16774  else
16775  return SCIPvarGetLPSol_rec(var);
16776 }
16777 
16778 /** gets primal NLP solution value of variable */
16780  SCIP_VAR* var /**< problem variable */
16781  )
16782 {
16783  assert(var != NULL);
16784 
16786  return var->nlpsol;
16787  else
16788  return SCIPvarGetNLPSol_rec(var);
16789 }
16790 
16791 /** return lower bound change info at requested position */
16793  SCIP_VAR* var, /**< problem variable */
16794  int pos /**< requested position */
16795  )
16796 {
16797  assert(pos >= 0);
16798  assert(pos < var->nlbchginfos);
16799 
16800  return &var->lbchginfos[pos];
16801 }
16802 
16803 /** gets the number of lower bound change info array */
16805  SCIP_VAR* var /**< problem variable */
16806  )
16807 {
16808  return var->nlbchginfos;
16809 }
16810 
16811 /** return upper bound change info at requested position */
16813  SCIP_VAR* var, /**< problem variable */
16814  int pos /**< requested position */
16815  )
16816 {
16817  assert(pos >= 0);
16818  assert(pos < var->nubchginfos);
16819 
16820  return &var->ubchginfos[pos];
16821 }
16822 
16823 /** gets the number upper bound change info array */
16825  SCIP_VAR* var /**< problem variable */
16826  )
16827 {
16828  assert(var != NULL);
16829 
16830  return var->nubchginfos;
16831 }
16832 
16833 /** returns the value based history for the variable */
16835  SCIP_VAR* var /**< problem variable */
16836  )
16837 {
16838  assert(var != NULL);
16839 
16840  return var->valuehistory;
16841 }
16842 
16843 /** gets pseudo solution value of variable */
16845  SCIP_VAR* var /**< problem variable */
16846  )
16847 {
16848  assert(var != NULL);
16849 
16851  return SCIPvarGetBestBoundLocal(var);
16852  else
16853  return SCIPvarGetPseudoSol_rec(var);
16854 }
16855 
16856 /** returns the variable's VSIDS score */
16858  SCIP_VAR* var, /**< problem variable */
16859  SCIP_STAT* stat, /**< problem statistics */
16860  SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16861  )
16862 {
16863  assert(var != NULL);
16864 
16866  return SCIPhistoryGetVSIDS(var->history, dir)/stat->vsidsweight;
16867  else
16868  return SCIPvarGetVSIDS_rec(var, stat, dir);
16869 }
16870 
16871 /** includes event handler with given data in variable's event filter */
16873  SCIP_VAR* var, /**< problem variable */
16874  BMS_BLKMEM* blkmem, /**< block memory */
16875  SCIP_SET* set, /**< global SCIP settings */
16876  SCIP_EVENTTYPE eventtype, /**< event type to catch */
16877  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
16878  SCIP_EVENTDATA* eventdata, /**< event data to pass to the event handler for the event processing */
16879  int* filterpos /**< pointer to store position of event filter entry, or NULL */
16880  )
16881 {
16882  assert(var != NULL);
16883  assert(set != NULL);
16884  assert(var->scip == set->scip);
16885  assert(var->eventfilter != NULL);
16886  assert((eventtype & ~SCIP_EVENTTYPE_VARCHANGED) == 0);
16887  assert((eventtype & SCIP_EVENTTYPE_VARCHANGED) != 0);
16888  assert(SCIPvarIsTransformed(var));
16889 
16890  SCIPdebugMessage("catch event of type 0x%x of variable <%s> with handler %p and data %p\n",
16891  eventtype, var->name, (void*)eventhdlr, (void*)eventdata);
16892 
16893  SCIP_CALL( SCIPeventfilterAdd(var->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) );
16894 
16895  return SCIP_OKAY;
16896 }
16897 
16898 /** deletes event handler with given data from variable's event filter */
16900  SCIP_VAR* var, /**< problem variable */
16901  BMS_BLKMEM* blkmem, /**< block memory */
16902  SCIP_SET* set, /**< global SCIP settings */
16903  SCIP_EVENTTYPE eventtype, /**< event type mask of dropped event */
16904  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
16905  SCIP_EVENTDATA* eventdata, /**< event data to pass to the event handler for the event processing */
16906  int filterpos /**< position of event filter entry returned by SCIPvarCatchEvent(), or -1 */
16907  )
16908 {
16909  assert(var != NULL);
16910  assert(set != NULL);
16911  assert(var->scip == set->scip);
16912  assert(var->eventfilter != NULL);
16913  assert(SCIPvarIsTransformed(var));
16914 
16915  SCIPdebugMessage("drop event of variable <%s> with handler %p and data %p\n", var->name, (void*)eventhdlr, (void*)eventdata);
16916 
16917  SCIP_CALL( SCIPeventfilterDel(var->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) );
16918 
16919  return SCIP_OKAY;
16920 }
16921 
16922 /** returns the position of the bound change index */
16924  SCIP_BDCHGIDX* bdchgidx /**< bound change index */
16925  )
16926 {
16927  assert(bdchgidx != NULL);
16928 
16929  return bdchgidx->pos;
16930 }
16931 
16932 /** returns whether first bound change index belongs to an earlier applied bound change than second one */
16934  SCIP_BDCHGIDX* bdchgidx1, /**< first bound change index */
16935  SCIP_BDCHGIDX* bdchgidx2 /**< second bound change index */
16936  )
16937 {
16938  assert(bdchgidx1 != NULL);
16939  assert(bdchgidx1->depth >= -2);
16940  assert(bdchgidx1->pos >= 0);
16941  assert(bdchgidx2 != NULL);
16942  assert(bdchgidx2->depth >= -2);
16943  assert(bdchgidx2->pos >= 0);
16944 
16945  return (bdchgidx1->depth < bdchgidx2->depth)
16946  || (bdchgidx1->depth == bdchgidx2->depth && (bdchgidx1->pos < bdchgidx2->pos));
16947 }
16948 
16949 /** returns whether first bound change index belongs to an earlier applied bound change than second one;
16950  * if a bound change index is NULL, the bound change index represents the current time, i.e. the time after the
16951  * last bound change was applied to the current node
16952  */
16954  SCIP_BDCHGIDX* bdchgidx1, /**< first bound change index, or NULL */
16955  SCIP_BDCHGIDX* bdchgidx2 /**< second bound change index, or NULL */
16956  )
16957 {
16958  assert(bdchgidx1 == NULL || bdchgidx1->depth >= -2);
16959  assert(bdchgidx1 == NULL || bdchgidx1->pos >= 0);
16960  assert(bdchgidx2 == NULL || bdchgidx2->depth >= -2);
16961  assert(bdchgidx2 == NULL || bdchgidx2->pos >= 0);
16962 
16963  if( bdchgidx1 == NULL )
16964  return FALSE;
16965  else if( bdchgidx2 == NULL )
16966  return TRUE;
16967  else
16968  return (bdchgidx1->depth < bdchgidx2->depth)
16969  || (bdchgidx1->depth == bdchgidx2->depth && (bdchgidx1->pos < bdchgidx2->pos));
16970 }
16971 
16972 /** returns old bound that was overwritten for given bound change information */
16974  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
16975  )
16976 {
16977  assert(bdchginfo != NULL);
16978 
16979  return bdchginfo->oldbound;
16980 }
16981 
16982 /** returns new bound installed for given bound change information */
16984  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
16985  )
16986 {
16987  assert(bdchginfo != NULL);
16988 
16989  return bdchginfo->newbound;
16990 }
16991 
16992 /** returns variable that belongs to the given bound change information */
16994  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
16995  )
16996 {
16997  assert(bdchginfo != NULL);
16998 
16999  return bdchginfo->var;
17000 }
17001 
17002 /** returns whether the bound change information belongs to a branching decision or a deduction */
17004  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17005  )
17006 {
17007  assert(bdchginfo != NULL);
17008 
17009  return (SCIP_BOUNDCHGTYPE)(bdchginfo->boundchgtype);
17010 }
17011 
17012 /** returns whether the bound change information belongs to a lower or upper bound change */
17014  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17015  )
17016 {
17017  assert(bdchginfo != NULL);
17018 
17019  return (SCIP_BOUNDTYPE)(bdchginfo->boundtype);
17020 }
17021 
17022 /** returns depth level of given bound change information */
17024  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17025  )
17026 {
17027  assert(bdchginfo != NULL);
17028 
17029  return bdchginfo->bdchgidx.depth;
17030 }
17031 
17032 /** returns bound change position in its depth level of given bound change information */
17034  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17035  )
17036 {
17037  assert(bdchginfo != NULL);
17038 
17039  return bdchginfo->bdchgidx.pos;
17040 }
17041 
17042 /** returns bound change index of given bound change information */
17044  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17045  )
17046 {
17047  assert(bdchginfo != NULL);
17048 
17049  return &bdchginfo->bdchgidx;
17050 }
17051 
17052 /** returns inference variable of given bound change information */
17054  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17055  )
17056 {
17057  assert(bdchginfo != NULL);
17060 
17061  return bdchginfo->inferencedata.var;
17062 }
17063 
17064 /** returns inference constraint of given bound change information */
17066  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17067  )
17068 {
17069  assert(bdchginfo != NULL);
17071  assert(bdchginfo->inferencedata.reason.cons != NULL);
17072 
17073  return bdchginfo->inferencedata.reason.cons;
17074 }
17075 
17076 /** returns inference propagator of given bound change information, or NULL if no propagator was responsible */
17078  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17079  )
17080 {
17081  assert(bdchginfo != NULL);
17083 
17084  return bdchginfo->inferencedata.reason.prop;
17085 }
17086 
17087 /** returns inference user information of given bound change information */
17089  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17090  )
17091 {
17092  assert(bdchginfo != NULL);
17095 
17096  return bdchginfo->inferencedata.info;
17097 }
17098 
17099 /** returns inference bound of inference variable of given bound change information */
17101  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17102  )
17103 {
17104  assert(bdchginfo != NULL);
17107 
17108  return (SCIP_BOUNDTYPE)(bdchginfo->inferboundtype);
17109 }
17110 
17111 /** returns the relaxed bound change type */
17113  SCIP_BDCHGINFO* bdchginfo /**< bound change to add to the conflict set */
17114  )
17115 {
17116  return ((SCIP_BOUNDTYPE)(bdchginfo->boundtype) == SCIP_BOUNDTYPE_LOWER ? bdchginfo->var->conflictrelaxedlb : bdchginfo->var->conflictrelaxedub);
17117 }
17118 
17119 
17120 /** returns whether the bound change information belongs to a redundant bound change */
17122  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17123  )
17124 {
17125  assert(bdchginfo != NULL);
17126  assert(bdchginfo->redundant == (bdchginfo->oldbound == bdchginfo->newbound)); /*lint !e777*/
17127 
17128  return bdchginfo->redundant;
17129 }
17130 
17131 /** returns whether the bound change has an inference reason (constraint or propagator), that can be resolved */
17133  SCIP_BDCHGINFO* bdchginfo /**< bound change information */
17134  )
17135 {
17136  assert(bdchginfo != NULL);
17137 
17140  && bdchginfo->inferencedata.reason.prop != NULL);
17141 }
17142 
17143 /** for two bound change informations belonging to the same variable and bound, returns whether the first bound change
17144  * has a tighter new bound as the second bound change
17145  */
17147  SCIP_BDCHGINFO* bdchginfo1, /**< first bound change information */
17148  SCIP_BDCHGINFO* bdchginfo2 /**< second bound change information */
17149  )
17150 {
17151  assert(bdchginfo1 != NULL);
17152  assert(bdchginfo2 != NULL);
17153  assert(bdchginfo1->var == bdchginfo2->var);
17154  assert(bdchginfo1->boundtype == bdchginfo2->boundtype);
17155 
17156  return (SCIPbdchginfoGetBoundtype(bdchginfo1) == SCIP_BOUNDTYPE_LOWER
17157  ? bdchginfo1->newbound > bdchginfo2->newbound
17158  : bdchginfo1->newbound < bdchginfo2->newbound);
17159 }
17160