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-2022 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 visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file var.c
17  * @ingroup OTHER_CFILES
18  * @brief methods for problem variables
19  * @author Tobias Achterberg
20  * @author Timo Berthold
21  * @author Gerald Gamrath
22  * @author Stefan Heinz
23  * @author Marc Pfetsch
24  * @author Michael Winkler
25  * @author Kati Wolter
26  * @author Stefan Vigerske
27  *
28  * @todo Possibly implement the access of bounds of multi-aggregated variables by accessing the
29  * corresponding linear constraint if it exists. This seems to require some work, since the linear
30  * constraint has to be stored. Moreover, it has even to be created in case the original constraint
31  * was deleted after multi-aggregation, but the bounds of the multi-aggregated variable should be
32  * changed. This has to be done with care in order to not loose the performance gains of
33  * multi-aggregation.
34  */
35 
36 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
37 
38 #include "scip/cons.h"
39 #include "scip/event.h"
40 #include "scip/history.h"
41 #include "scip/implics.h"
42 #include "scip/lp.h"
43 #include "scip/primal.h"
44 #include "scip/prob.h"
45 #include "scip/pub_cons.h"
46 #include "scip/pub_history.h"
47 #include "scip/pub_implics.h"
48 #include "scip/pub_lp.h"
49 #include "scip/pub_message.h"
50 #include "scip/pub_misc.h"
51 #include "scip/pub_misc_sort.h"
52 #include "scip/pub_prop.h"
53 #include "scip/pub_var.h"
54 #include "scip/relax.h"
55 #include "scip/set.h"
56 #include "scip/sol.h"
57 #include "scip/stat.h"
58 #include "scip/struct_event.h"
59 #include "scip/struct_lp.h"
60 #include "scip/struct_prob.h"
61 #include "scip/struct_set.h"
62 #include "scip/struct_stat.h"
63 #include "scip/struct_var.h"
64 #include "scip/tree.h"
65 #include "scip/var.h"
66 #include <string.h>
67 
68 #define MAXIMPLSCLOSURE 100 /**< maximal number of descendants of implied variable for building closure
69  * in implication graph */
70 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds added due to implications */
71 
72 
73 /*
74  * Debugging variable release and capture
75  *
76  * Define DEBUGUSES_VARNAME to the name of the variable for which to print
77  * a backtrace when it is captured and released.
78  * Optionally define DEBUGUSES_PROBNAME to the name of a SCIP problem to consider.
79  * Have DEBUGUSES_NOADDR2LINE defined if you do not have addr2line installed on your system.
80  */
81 /* #define DEBUGUSES_VARNAME "t_t_b7" */
82 /* #define DEBUGUSES_PROBNAME "t_st_e35_rens" */
83 /* #define DEBUGUSES_NOADDR2LINE */
84 
85 #ifdef DEBUGUSES_VARNAME
86 #include <execinfo.h>
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include "scip/struct_scip.h"
90 
91 /** obtains a backtrace and prints it to stdout. */
92 static
93 void print_backtrace(void)
94 {
95  void* array[10];
96  char** strings;
97  int size;
98  int i;
99 
100  size = backtrace(array, 10);
101  strings = backtrace_symbols(array, size);
102  if( strings == NULL )
103  return;
104 
105  /* skip first entry, which is the print_backtrace function */
106  for( i = 1; i < size; ++i )
107  {
108  /* if string is something like
109  * /path/to/scip/bin/../lib/shared/libscip-7.0.1.3.linux.x86_64.gnu.dbg.so(+0x2675dd3)
110  * (that is, no function name because it is a inlined function), then call
111  * addr2line -e <libname> <addr> to get func and code line
112  * dladdr() may be an alternative
113  */
114  char* openpar;
115  char* closepar = NULL;
116 #ifndef DEBUGUSES_NOADDR2LINE
117  openpar = strchr(strings[i], '(');
118  if( openpar != NULL && openpar[1] == '+' )
119  closepar = strchr(openpar+2, ')');
120 #endif
121  if( closepar != NULL )
122  {
123  char cmd[SCIP_MAXSTRLEN];
124  (void) SCIPsnprintf(cmd, SCIP_MAXSTRLEN, "addr2line -f -p -e \"%.*s\" %.*s", openpar - strings[i], strings[i], closepar-openpar-1, openpar+1);
125  printf(" ");
126  fflush(stdout);
127  system(cmd);
128  }
129  else
130  printf(" %s\n", strings[i]);
131  }
132 
133  free(strings);
134 }
135 #endif
136 
137 /*
138  * hole, holelist, and domain methods
139  */
140 
141 /** creates a new holelist element */
142 static
144  SCIP_HOLELIST** holelist, /**< pointer to holelist to create */
145  BMS_BLKMEM* blkmem, /**< block memory for target holelist */
146  SCIP_SET* set, /**< global SCIP settings */
147  SCIP_Real left, /**< left bound of open interval in new hole */
148  SCIP_Real right /**< right bound of open interval in new hole */
149  )
150 {
151  assert(holelist != NULL);
152  assert(blkmem != NULL);
153  assert(SCIPsetIsLT(set, left, right));
154 
155  SCIPsetDebugMsg(set, "create hole list element (%.15g,%.15g) in blkmem %p\n", left, right, (void*)blkmem);
156 
157  SCIP_ALLOC( BMSallocBlockMemory(blkmem, holelist) );
158  (*holelist)->hole.left = left;
159  (*holelist)->hole.right = right;
160  (*holelist)->next = NULL;
161 
162  return SCIP_OKAY;
163 }
164 
165 /** frees all elements in the holelist */
166 static
167 void holelistFree(
168  SCIP_HOLELIST** holelist, /**< pointer to holelist to free */
169  BMS_BLKMEM* blkmem /**< block memory for target holelist */
170  )
171 {
172  assert(holelist != NULL);
173  assert(blkmem != NULL);
174 
175  while( *holelist != NULL )
176  {
177  SCIP_HOLELIST* next;
178 
179  SCIPdebugMessage("free hole list element (%.15g,%.15g) in blkmem %p\n",
180  (*holelist)->hole.left, (*holelist)->hole.right, (void*)blkmem);
181 
182  next = (*holelist)->next;
183  BMSfreeBlockMemory(blkmem, holelist);
184  assert(*holelist == NULL);
185 
186  *holelist = next;
187  }
188  assert(*holelist == NULL);
189 }
190 
191 /** duplicates a list of holes */
192 static
194  SCIP_HOLELIST** target, /**< pointer to target holelist */
195  BMS_BLKMEM* blkmem, /**< block memory for target holelist */
196  SCIP_SET* set, /**< global SCIP settings */
197  SCIP_HOLELIST* source /**< holelist to duplicate */
198  )
199 {
200  assert(target != NULL);
201 
202  while( source != NULL )
203  {
204  assert(source->next == NULL || SCIPsetIsGE(set, source->next->hole.left, source->hole.right));
205  SCIP_CALL( holelistCreate(target, blkmem, set, source->hole.left, source->hole.right) );
206  source = source->next;
207  target = &(*target)->next;
208  }
209 
210  return SCIP_OKAY;
211 }
212 
213 /** adds a hole to the domain */
214 static
216  SCIP_DOM* dom, /**< domain to add hole to */
217  BMS_BLKMEM* blkmem, /**< block memory */
218  SCIP_SET* set, /**< global SCIP settings */
219  SCIP_Real left, /**< left bound of open interval in new hole */
220  SCIP_Real right, /**< right bound of open interval in new hole */
221  SCIP_Bool* added /**< pointer to store whether the hole was added (variable didn't had that hole before), or NULL */
222  )
223 {
224  SCIP_HOLELIST** insertpos;
225  SCIP_HOLELIST* next;
226 
227  assert(dom != NULL);
228  assert(added != NULL);
229 
230  /* search for the position of the new hole */
231  insertpos = &dom->holelist;
232  while( *insertpos != NULL && (*insertpos)->hole.left < left )
233  insertpos = &(*insertpos)->next;
234 
235  /* check if new hole already exists in the hole list or is a sub hole of an existing one */
236  if( *insertpos != NULL && (*insertpos)->hole.left == left && (*insertpos)->hole.right >= right ) /*lint !e777 */
237  {
238  SCIPsetDebugMsg(set, "new hole (%.15g,%.15g) is redundant through known hole (%.15g,%.15g)\n",
239  left, right, (*insertpos)->hole.left, (*insertpos)->hole.right);
240  *added = FALSE;
241  return SCIP_OKAY;
242  }
243 
244  /* add hole */
245  *added = TRUE;
246 
247  next = *insertpos;
248  SCIP_CALL( holelistCreate(insertpos, blkmem, set, left, right) );
249  (*insertpos)->next = next;
250 
251  return SCIP_OKAY;
252 }
253 
254 /** merges overlapping holes into single holes, computes and moves lower and upper bound, respectively */
255 /**@todo the domMerge() method is currently called if a lower or an upper bound locally or globally changed; this could
256  * be more efficient if performed with the knowledge if it was a lower or an upper bound which triggered this
257  * merge */
258 static
259 void domMerge(
260  SCIP_DOM* dom, /**< domain to merge */
261  BMS_BLKMEM* blkmem, /**< block memory */
262  SCIP_SET* set, /**< global SCIP settings */
263  SCIP_Real* newlb, /**< pointer to store new lower bound */
264  SCIP_Real* newub /**< pointer to store new upper bound */
265  )
266 {
267  SCIP_HOLELIST** holelistptr;
268  SCIP_HOLELIST** lastnextptr;
269  SCIP_Real* lastrightptr;
270 
271  assert(dom != NULL);
272  assert(SCIPsetIsLE(set, dom->lb, dom->ub));
273 
274 #ifndef NDEBUG
275  {
276  /* check if the holelist is sorted w.r.t. to the left interval bounds */
277  SCIP_Real lastleft;
278 
279  holelistptr = &dom->holelist;
280 
281  lastleft = -SCIPsetInfinity(set);
282 
283  while( *holelistptr != NULL )
284  {
285  if( (*holelistptr)->next != NULL )
286  {
287  assert( SCIPsetIsLE(set, lastleft, (*holelistptr)->hole.left) );
288  lastleft = (*holelistptr)->hole.left;
289  }
290 
291  holelistptr = &(*holelistptr)->next;
292  }
293  }
294 #endif
295 
296  SCIPsetDebugMsg(set, "merge hole list\n");
297 
298  holelistptr = &dom->holelist;
299  lastrightptr = &dom->lb; /* lower bound is the right bound of the hole (-infinity,lb) */
300  lastnextptr = holelistptr;
301 
302  while( *holelistptr != NULL )
303  {
304  SCIPsetDebugMsg(set, "check hole (%.15g,%.15g) last right interval was <%.15g>\n", (*holelistptr)->hole.left, (*holelistptr)->hole.right, *lastrightptr);
305 
306  /* check that the hole is not empty */
307  assert(SCIPsetIsLT(set, (*holelistptr)->hole.left, (*holelistptr)->hole.right));
308 
309  if( SCIPsetIsGE(set, (*holelistptr)->hole.left, dom->ub) )
310  {
311  /* the remaining holes start behind the upper bound: remove them */
312  SCIPsetDebugMsg(set, "remove remaining hole since upper bound <%.15g> is less then the left hand side of the current hole\n", dom->ub);
313  holelistFree(holelistptr, blkmem);
314  assert(*holelistptr == NULL);
315 
316  /* unlink this hole from the previous hole */
317  *lastnextptr = NULL;
318  }
319  else if( SCIPsetIsGT(set, (*holelistptr)->hole.right, dom->ub) )
320  {
321  /* the hole overlaps the upper bound: decrease upper bound, remove this hole and all remaining holes */
322  SCIPsetDebugMsg(set, "upper bound <%.15g> lays in current hole; store new upper bound and remove this and all remaining holes\n", dom->ub);
323 
324  assert(SCIPsetIsLT(set, (*holelistptr)->hole.left, dom->ub));
325 
326  /* adjust upper bound */
327  dom->ub = (*holelistptr)->hole.left;
328 
329  if(newub != NULL )
330  *newub = (*holelistptr)->hole.left;
331 
332  /* remove remaining hole list */
333  holelistFree(holelistptr, blkmem);
334  assert(*holelistptr == NULL);
335 
336  /* unlink this hole from the previous hole */
337  *lastnextptr = NULL;
338  }
339  else if( SCIPsetIsGT(set, *lastrightptr, (*holelistptr)->hole.left) )
340  {
341  /* the right bound of the last hole is greater than the left bound of this hole: increase the right bound of
342  * the last hole, delete this hole */
343  SCIP_HOLELIST* nextholelist;
344 
345  if( SCIPsetIsEQ(set, *lastrightptr, dom->lb ) )
346  {
347  /* the reason for the overlap results from the lower bound hole (-infinity,lb); therefore, we can increase
348  * the lower bound */
349  SCIPsetDebugMsg(set, "lower bound <%.15g> lays in current hole; store new lower bound and remove hole\n", dom->lb);
350  *lastrightptr = MAX(*lastrightptr, (*holelistptr)->hole.right);
351 
352  /* adjust lower bound */
353  dom->lb = *lastrightptr;
354 
355  if(newlb != NULL )
356  *newlb = *lastrightptr;
357  }
358  else
359  {
360  SCIPsetDebugMsg(set, "current hole overlaps with the previous one (...,%.15g); merge to (...,%.15g)\n",
361  *lastrightptr, MAX(*lastrightptr, (*holelistptr)->hole.right) );
362  *lastrightptr = MAX(*lastrightptr, (*holelistptr)->hole.right);
363  }
364  nextholelist = (*holelistptr)->next;
365  (*holelistptr)->next = NULL;
366  holelistFree(holelistptr, blkmem);
367 
368  /* connect the linked list after removing the hole */
369  *lastnextptr = nextholelist;
370 
371  /* get next hole */
372  *holelistptr = nextholelist;
373  }
374  else
375  {
376  /* the holes do not overlap: update lastholelist and lastrightptr */
377  lastrightptr = &(*holelistptr)->hole.right;
378  lastnextptr = &(*holelistptr)->next;
379 
380  /* get next hole */
381  holelistptr = &(*holelistptr)->next;
382  }
383  }
384 
385 #ifndef NDEBUG
386  {
387  /* check that holes are merged */
388  SCIP_Real lastright;
389 
390  lastright = dom->lb; /* lower bound is the right bound of the hole (-infinity,lb) */
391  holelistptr = &dom->holelist;
392 
393  while( *holelistptr != NULL )
394  {
395  /* check the the last right interval is smaller or equal to the current left interval (none overlapping) */
396  assert( SCIPsetIsLE(set, lastright, (*holelistptr)->hole.left) );
397 
398  /* check the hole property (check that the hole is not empty) */
399  assert( SCIPsetIsLT(set, (*holelistptr)->hole.left, (*holelistptr)->hole.right) );
400  lastright = (*holelistptr)->hole.right;
401 
402  /* get next hole */
403  holelistptr = &(*holelistptr)->next;
404  }
405 
406  /* check the the last right interval is smaller or equal to the upper bound (none overlapping) */
407  assert( SCIPsetIsLE(set, lastright, dom->ub) );
408  }
409 #endif
410 }
411 
412 /*
413  * domain change methods
414  */
415 
416 /** ensures, that bound change info array for lower bound changes can store at least num entries */
417 static
419  SCIP_VAR* var, /**< problem variable */
420  BMS_BLKMEM* blkmem, /**< block memory */
421  SCIP_SET* set, /**< global SCIP settings */
422  int num /**< minimum number of entries to store */
423  )
424 {
425  assert(var != NULL);
426  assert(var->nlbchginfos <= var->lbchginfossize);
427  assert(SCIPvarIsTransformed(var));
428 
429  if( num > var->lbchginfossize )
430  {
431  int newsize;
432 
433  newsize = SCIPsetCalcMemGrowSize(set, num);
434  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->lbchginfos, var->lbchginfossize, newsize) );
435  var->lbchginfossize = newsize;
436  }
437  assert(num <= var->lbchginfossize);
438 
439  return SCIP_OKAY;
440 }
441 
442 /** ensures, that bound change info array for upper bound changes can store at least num entries */
443 static
445  SCIP_VAR* var, /**< problem variable */
446  BMS_BLKMEM* blkmem, /**< block memory */
447  SCIP_SET* set, /**< global SCIP settings */
448  int num /**< minimum number of entries to store */
449  )
450 {
451  assert(var != NULL);
452  assert(var->nubchginfos <= var->ubchginfossize);
453  assert(SCIPvarIsTransformed(var));
454 
455  if( num > var->ubchginfossize )
456  {
457  int newsize;
458 
459  newsize = SCIPsetCalcMemGrowSize(set, num);
460  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->ubchginfos, var->ubchginfossize, newsize) );
461  var->ubchginfossize = newsize;
462  }
463  assert(num <= var->ubchginfossize);
464 
465  return SCIP_OKAY;
466 }
467 
468 /** adds domain change info to the variable's lower bound change info array */
469 static
471  SCIP_VAR* var, /**< problem variable */
472  BMS_BLKMEM* blkmem, /**< block memory */
473  SCIP_SET* set, /**< global SCIP settings */
474  SCIP_Real oldbound, /**< old value for bound */
475  SCIP_Real newbound, /**< new value for bound */
476  int depth, /**< depth in the tree, where the bound change takes place */
477  int pos, /**< position of the bound change in its bound change array */
478  SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself) */
479  SCIP_CONS* infercons, /**< constraint that infered this bound change, or NULL */
480  SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
481  int inferinfo, /**< user information for inference to help resolving the conflict */
482  SCIP_BOUNDTYPE inferboundtype, /**< type of bound for inference var: lower or upper bound */
483  SCIP_BOUNDCHGTYPE boundchgtype /**< bound change type: branching decision or infered bound change */
484  )
485 {
486  assert(var != NULL);
487  assert(SCIPsetIsLT(set, oldbound, newbound));
488  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, oldbound));
489  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
490  assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, oldbound, 0.0));
491  assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, 1.0));
492  assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
493  assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
494  assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
495 
496  SCIPsetDebugMsg(set, "adding lower bound change info to var <%s>[%g,%g]: depth=%d, pos=%d, infer%s=<%s>, inferinfo=%d, %g -> %g\n",
497  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, depth, pos, infercons != NULL ? "cons" : "prop",
498  infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo,
499  oldbound, newbound);
500 
501  SCIP_CALL( varEnsureLbchginfosSize(var, blkmem, set, var->nlbchginfos+1) );
502  var->lbchginfos[var->nlbchginfos].oldbound = oldbound;
503  var->lbchginfos[var->nlbchginfos].newbound = newbound;
504  var->lbchginfos[var->nlbchginfos].var = var;
505  var->lbchginfos[var->nlbchginfos].bdchgidx.depth = depth;
506  var->lbchginfos[var->nlbchginfos].bdchgidx.pos = pos;
507  var->lbchginfos[var->nlbchginfos].pos = var->nlbchginfos; /*lint !e732*/
508  var->lbchginfos[var->nlbchginfos].boundchgtype = boundchgtype; /*lint !e641*/
509  var->lbchginfos[var->nlbchginfos].boundtype = SCIP_BOUNDTYPE_LOWER; /*lint !e641*/
510  var->lbchginfos[var->nlbchginfos].redundant = FALSE;
511  var->lbchginfos[var->nlbchginfos].inferboundtype = inferboundtype; /*lint !e641*/
512  var->lbchginfos[var->nlbchginfos].inferencedata.var = infervar;
513  var->lbchginfos[var->nlbchginfos].inferencedata.info = inferinfo;
514 
515  /**@note The "pos" data member of the bound change info has a size of 27 bits */
516  assert(var->nlbchginfos < 1 << 27);
517 
518  switch( boundchgtype )
519  {
521  break;
523  assert(infercons != NULL);
524  var->lbchginfos[var->nlbchginfos].inferencedata.reason.cons = infercons;
525  break;
527  var->lbchginfos[var->nlbchginfos].inferencedata.reason.prop = inferprop;
528  break;
529  default:
530  SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
531  return SCIP_INVALIDDATA;
532  }
533 
534  var->nlbchginfos++;
535 
536  assert(var->nlbchginfos < 2
538  &var->lbchginfos[var->nlbchginfos-1].bdchgidx));
539 
540  return SCIP_OKAY;
541 }
542 
543 /** adds domain change info to the variable's upper bound change info array */
544 static
546  SCIP_VAR* var, /**< problem variable */
547  BMS_BLKMEM* blkmem, /**< block memory */
548  SCIP_SET* set, /**< global SCIP settings */
549  SCIP_Real oldbound, /**< old value for bound */
550  SCIP_Real newbound, /**< new value for bound */
551  int depth, /**< depth in the tree, where the bound change takes place */
552  int pos, /**< position of the bound change in its bound change array */
553  SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself) */
554  SCIP_CONS* infercons, /**< constraint that infered this bound change, or NULL */
555  SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
556  int inferinfo, /**< user information for inference to help resolving the conflict */
557  SCIP_BOUNDTYPE inferboundtype, /**< type of bound for inference var: lower or upper bound */
558  SCIP_BOUNDCHGTYPE boundchgtype /**< bound change type: branching decision or infered bound change */
559  )
560 {
561  assert(var != NULL);
562  assert(SCIPsetIsGT(set, oldbound, newbound));
563  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, oldbound));
564  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
565  assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, oldbound, 1.0));
566  assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, 0.0));
567  assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
568  assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
569  assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
570 
571  SCIPsetDebugMsg(set, "adding upper bound change info to var <%s>[%g,%g]: depth=%d, pos=%d, infer%s=<%s>, inferinfo=%d, %g -> %g\n",
572  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, depth, pos, infercons != NULL ? "cons" : "prop",
573  infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo,
574  oldbound, newbound);
575 
576  SCIP_CALL( varEnsureUbchginfosSize(var, blkmem, set, var->nubchginfos+1) );
577  var->ubchginfos[var->nubchginfos].oldbound = oldbound;
578  var->ubchginfos[var->nubchginfos].newbound = newbound;
579  var->ubchginfos[var->nubchginfos].var = var;
580  var->ubchginfos[var->nubchginfos].bdchgidx.depth = depth;
581  var->ubchginfos[var->nubchginfos].bdchgidx.pos = pos;
582  var->ubchginfos[var->nubchginfos].pos = var->nubchginfos; /*lint !e732*/
583  var->ubchginfos[var->nubchginfos].boundchgtype = boundchgtype; /*lint !e641*/
584  var->ubchginfos[var->nubchginfos].boundtype = SCIP_BOUNDTYPE_UPPER; /*lint !e641*/
585  var->ubchginfos[var->nubchginfos].redundant = FALSE;
586  var->ubchginfos[var->nubchginfos].inferboundtype = inferboundtype; /*lint !e641*/
587  var->ubchginfos[var->nubchginfos].inferencedata.var = infervar;
588  var->ubchginfos[var->nubchginfos].inferencedata.info = inferinfo;
589 
590  /**@note The "pos" data member of the bound change info has a size of 27 bits */
591  assert(var->nubchginfos < 1 << 27);
592 
593  switch( boundchgtype )
594  {
596  break;
598  assert(infercons != NULL);
599  var->ubchginfos[var->nubchginfos].inferencedata.reason.cons = infercons;
600  break;
602  var->ubchginfos[var->nubchginfos].inferencedata.reason.prop = inferprop;
603  break;
604  default:
605  SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
606  return SCIP_INVALIDDATA;
607  }
608 
609  var->nubchginfos++;
610 
611  assert(var->nubchginfos < 2
613  &var->ubchginfos[var->nubchginfos-1].bdchgidx));
614 
615  return SCIP_OKAY;
616 }
617 
618 /** applies single bound change */
620  SCIP_BOUNDCHG* boundchg, /**< bound change to apply */
621  BMS_BLKMEM* blkmem, /**< block memory */
622  SCIP_SET* set, /**< global SCIP settings */
623  SCIP_STAT* stat, /**< problem statistics */
624  SCIP_LP* lp, /**< current LP data */
625  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
626  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
627  int depth, /**< depth in the tree, where the bound change takes place */
628  int pos, /**< position of the bound change in its bound change array */
629  SCIP_Bool* cutoff /**< pointer to store whether an infeasible bound change was detected */
630  )
631 {
632  SCIP_VAR* var;
633 
634  assert(boundchg != NULL);
635  assert(stat != NULL);
636  assert(depth > 0);
637  assert(pos >= 0);
638  assert(cutoff != NULL);
639 
640  *cutoff = FALSE;
641 
642  /* ignore redundant bound changes */
643  if( boundchg->redundant )
644  return SCIP_OKAY;
645 
646  var = boundchg->var;
647  assert(var != NULL);
649  assert(!SCIPvarIsIntegral(var) || SCIPsetIsFeasIntegral(set, boundchg->newbound));
650 
651  /* apply bound change */
652  switch( boundchg->boundtype )
653  {
655  /* check, if the bound change is still active (could be replaced by inference due to repropagation of higher node) */
656  if( SCIPsetIsGT(set, boundchg->newbound, var->locdom.lb) )
657  {
658  if( SCIPsetIsLE(set, boundchg->newbound, var->locdom.ub) )
659  {
660  /* add the bound change info to the variable's bound change info array */
661  switch( boundchg->boundchgtype )
662  {
664  SCIPsetDebugMsg(set, " -> branching: new lower bound of <%s>[%g,%g]: %g\n",
665  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
666  SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
668  stat->lastbranchvar = var;
670  stat->lastbranchvalue = boundchg->newbound;
671  break;
672 
674  assert(boundchg->data.inferencedata.reason.cons != NULL);
675  SCIPsetDebugMsg(set, " -> constraint <%s> inference: new lower bound of <%s>[%g,%g]: %g\n",
676  SCIPconsGetName(boundchg->data.inferencedata.reason.cons),
677  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
678  SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
679  boundchg->data.inferencedata.var, boundchg->data.inferencedata.reason.cons, NULL,
680  boundchg->data.inferencedata.info,
682  break;
683 
685  SCIPsetDebugMsg(set, " -> propagator <%s> inference: new lower bound of <%s>[%g,%g]: %g\n",
686  boundchg->data.inferencedata.reason.prop != NULL
687  ? SCIPpropGetName(boundchg->data.inferencedata.reason.prop) : "-",
688  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
689  SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
690  boundchg->data.inferencedata.var, NULL, boundchg->data.inferencedata.reason.prop,
691  boundchg->data.inferencedata.info,
693  break;
694 
695  default:
696  SCIPerrorMessage("invalid bound change type %d\n", boundchg->boundchgtype);
697  return SCIP_INVALIDDATA;
698  }
699 
700  /* change local bound of variable */
701  SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, boundchg->newbound) );
702  }
703  else
704  {
705  SCIPsetDebugMsg(set, " -> cutoff: new lower bound of <%s>[%g,%g]: %g\n",
706  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
707  *cutoff = TRUE;
708  boundchg->redundant = TRUE; /* bound change has not entered the lbchginfos array of the variable! */
709  }
710  }
711  else
712  {
713  /* mark bound change to be inactive */
714  SCIPsetDebugMsg(set, " -> inactive %s: new lower bound of <%s>[%g,%g]: %g\n",
715  (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
716  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
717  boundchg->redundant = TRUE;
718  }
719  break;
720 
722  /* check, if the bound change is still active (could be replaced by inference due to repropagation of higher node) */
723  if( SCIPsetIsLT(set, boundchg->newbound, var->locdom.ub) )
724  {
725  if( SCIPsetIsGE(set, boundchg->newbound, var->locdom.lb) )
726  {
727  /* add the bound change info to the variable's bound change info array */
728  switch( boundchg->boundchgtype )
729  {
731  SCIPsetDebugMsg(set, " -> branching: new upper bound of <%s>[%g,%g]: %g\n",
732  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
733  SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
735  stat->lastbranchvar = var;
737  stat->lastbranchvalue = boundchg->newbound;
738  break;
739 
741  assert(boundchg->data.inferencedata.reason.cons != NULL);
742  SCIPsetDebugMsg(set, " -> constraint <%s> inference: new upper bound of <%s>[%g,%g]: %g\n",
743  SCIPconsGetName(boundchg->data.inferencedata.reason.cons),
744  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
745  SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
746  boundchg->data.inferencedata.var, boundchg->data.inferencedata.reason.cons, NULL,
747  boundchg->data.inferencedata.info,
749  break;
750 
752  SCIPsetDebugMsg(set, " -> propagator <%s> inference: new upper bound of <%s>[%g,%g]: %g\n",
753  boundchg->data.inferencedata.reason.prop != NULL
754  ? SCIPpropGetName(boundchg->data.inferencedata.reason.prop) : "-",
755  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
756  SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
757  boundchg->data.inferencedata.var, NULL, boundchg->data.inferencedata.reason.prop,
758  boundchg->data.inferencedata.info,
760  break;
761 
762  default:
763  SCIPerrorMessage("invalid bound change type %d\n", boundchg->boundchgtype);
764  return SCIP_INVALIDDATA;
765  }
766 
767  /* change local bound of variable */
768  SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, boundchg->newbound) );
769  }
770  else
771  {
772  SCIPsetDebugMsg(set, " -> cutoff: new upper bound of <%s>[%g,%g]: %g\n",
773  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
774  *cutoff = TRUE;
775  boundchg->redundant = TRUE; /* bound change has not entered the ubchginfos array of the variable! */
776  }
777  }
778  else
779  {
780  /* mark bound change to be inactive */
781  SCIPsetDebugMsg(set, " -> inactive %s: new upper bound of <%s>[%g,%g]: %g\n",
782  (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
783  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
784  boundchg->redundant = TRUE;
785  }
786  break;
787 
788  default:
789  SCIPerrorMessage("unknown bound type\n");
790  return SCIP_INVALIDDATA;
791  }
792 
793  /* update the branching and inference history */
794  if( !boundchg->applied && !boundchg->redundant )
795  {
796  assert(var == boundchg->var);
797 
799  {
800  SCIP_CALL( SCIPvarIncNBranchings(var, blkmem, set, stat,
803  }
804  else if( stat->lastbranchvar != NULL )
805  {
806  /**@todo if last branching variable is unknown, retrieve it from the nodes' boundchg arrays */
807  SCIP_CALL( SCIPvarIncInferenceSum(stat->lastbranchvar, blkmem, set, stat, stat->lastbranchdir, stat->lastbranchvalue, 1.0) );
808  }
809  boundchg->applied = TRUE;
810  }
811 
812  return SCIP_OKAY;
813 }
814 
815 /** undoes single bound change */
817  SCIP_BOUNDCHG* boundchg, /**< bound change to remove */
818  BMS_BLKMEM* blkmem, /**< block memory */
819  SCIP_SET* set, /**< global SCIP settings */
820  SCIP_STAT* stat, /**< problem statistics */
821  SCIP_LP* lp, /**< current LP data */
822  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
823  SCIP_EVENTQUEUE* eventqueue /**< event queue */
824  )
825 {
826  SCIP_VAR* var;
827 
828  assert(boundchg != NULL);
829  assert(stat != NULL);
830 
831  /* ignore redundant bound changes */
832  if( boundchg->redundant )
833  return SCIP_OKAY;
834 
835  var = boundchg->var;
836  assert(var != NULL);
838 
839  /* undo bound change: apply the previous bound change of variable */
840  switch( boundchg->boundtype )
841  {
843  var->nlbchginfos--;
844  assert(var->nlbchginfos >= 0);
845  assert(var->lbchginfos != NULL);
846  assert( SCIPsetIsFeasEQ(set, var->lbchginfos[var->nlbchginfos].newbound, var->locdom.lb) ); /*lint !e777*/
847  assert( SCIPsetIsFeasLE(set, boundchg->newbound, var->locdom.lb) ); /* current lb might be larger to intermediate global bound change */
848 
849  SCIPsetDebugMsg(set, "removed lower bound change info of var <%s>[%g,%g]: depth=%d, pos=%d, %g -> %g\n",
850  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub,
853 
854  /* reinstall the previous local bound */
855  SCIP_CALL( SCIPvarChgLbLocal(boundchg->var, blkmem, set, stat, lp, branchcand, eventqueue,
856  var->lbchginfos[var->nlbchginfos].oldbound) );
857 
858  /* in case all bound changes are removed the local bound should match the global bound */
859  assert(var->nlbchginfos > 0 || SCIPsetIsFeasEQ(set, var->locdom.lb, var->glbdom.lb));
860 
861  break;
862 
864  var->nubchginfos--;
865  assert(var->nubchginfos >= 0);
866  assert(var->ubchginfos != NULL);
867  assert( SCIPsetIsFeasEQ(set, var->ubchginfos[var->nubchginfos].newbound, var->locdom.ub) ); /*lint !e777*/
868  assert( SCIPsetIsFeasGE(set, boundchg->newbound, var->locdom.ub) ); /* current ub might be smaller to intermediate global bound change */
869 
870  SCIPsetDebugMsg(set, "removed upper bound change info of var <%s>[%g,%g]: depth=%d, pos=%d, %g -> %g\n",
871  SCIPvarGetName(var), var->locdom.lb, var->locdom.ub,
874 
875  /* reinstall the previous local bound */
876  SCIP_CALL( SCIPvarChgUbLocal(boundchg->var, blkmem, set, stat, lp, branchcand, eventqueue,
877  var->ubchginfos[var->nubchginfos].oldbound) );
878 
879  /* in case all bound changes are removed the local bound should match the global bound */
880  assert(var->nubchginfos > 0 || SCIPsetIsFeasEQ(set, var->locdom.ub, var->glbdom.ub));
881 
882  break;
883 
884  default:
885  SCIPerrorMessage("unknown bound type\n");
886  return SCIP_INVALIDDATA;
887  }
888 
889  /* update last branching variable */
891  {
892  stat->lastbranchvar = NULL;
894  }
895 
896  return SCIP_OKAY;
897 }
898 
899 /** applies single bound change to the global problem by changing the global bound of the corresponding variable */
900 static
902  SCIP_BOUNDCHG* boundchg, /**< bound change to apply */
903  BMS_BLKMEM* blkmem, /**< block memory */
904  SCIP_SET* set, /**< global SCIP settings */
905  SCIP_STAT* stat, /**< problem statistics */
906  SCIP_LP* lp, /**< current LP data */
907  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
908  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
909  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
910  SCIP_Bool* cutoff /**< pointer to store whether an infeasible bound change was detected */
911  )
912 {
913  SCIP_VAR* var;
914  SCIP_Real newbound;
915  SCIP_BOUNDTYPE boundtype;
916 
917  assert(boundchg != NULL);
918  assert(cutoff != NULL);
919 
920  *cutoff = FALSE;
921 
922  /* ignore redundant bound changes */
923  if( boundchg->redundant )
924  return SCIP_OKAY;
925 
926  var = SCIPboundchgGetVar(boundchg);
927  newbound = SCIPboundchgGetNewbound(boundchg);
928  boundtype = SCIPboundchgGetBoundtype(boundchg);
929 
930  /* check if the bound change is redundant which can happen due to a (better) global bound change which was performed
931  * after that bound change was applied
932  *
933  * @note a global bound change is not captured by the redundant member of the bound change data structure
934  */
935  if( (boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasLE(set, newbound, SCIPvarGetLbGlobal(var)))
936  || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasGE(set, newbound, SCIPvarGetUbGlobal(var))) )
937  {
938  return SCIP_OKAY;
939  }
940 
941  SCIPsetDebugMsg(set, "applying global bound change: <%s>[%g,%g] %s %g\n",
943  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", newbound);
944 
945  /* check for cutoff */
946  if( (boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGT(set, newbound, SCIPvarGetUbGlobal(var)))
947  || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLT(set, newbound, SCIPvarGetLbGlobal(var))) )
948  {
949  *cutoff = TRUE;
950  return SCIP_OKAY;
951  }
952 
953  /* apply bound change */
954  SCIP_CALL( SCIPvarChgBdGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound, boundtype) );
955 
956  return SCIP_OKAY;
957 }
958 
959 /** captures branching and inference data of bound change */
960 static
962  SCIP_BOUNDCHG* boundchg /**< bound change to remove */
963  )
964 {
965  assert(boundchg != NULL);
966 
967  /* capture variable associated with the bound change */
968  assert(boundchg->var != NULL);
969  SCIPvarCapture(boundchg->var);
970 
971  switch( boundchg->boundchgtype )
972  {
975  break;
976 
978  assert(boundchg->data.inferencedata.var != NULL);
979  assert(boundchg->data.inferencedata.reason.cons != NULL);
980  SCIPconsCapture(boundchg->data.inferencedata.reason.cons);
981  break;
982 
983  default:
984  SCIPerrorMessage("invalid bound change type\n");
985  return SCIP_INVALIDDATA;
986  }
987 
988  return SCIP_OKAY;
989 }
990 
991 /** releases branching and inference data of bound change */
992 static
994  SCIP_BOUNDCHG* boundchg, /**< bound change to remove */
995  BMS_BLKMEM* blkmem, /**< block memory */
996  SCIP_SET* set, /**< global SCIP settings */
997  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
998  SCIP_LP* lp /**< current LP data */
999 
1000  )
1001 {
1002  assert(boundchg != NULL);
1003 
1004  switch( boundchg->boundchgtype )
1005  {
1008  break;
1009 
1011  assert(boundchg->data.inferencedata.var != NULL);
1012  assert(boundchg->data.inferencedata.reason.cons != NULL);
1013  SCIP_CALL( SCIPconsRelease(&boundchg->data.inferencedata.reason.cons, blkmem, set) );
1014  break;
1015 
1016  default:
1017  SCIPerrorMessage("invalid bound change type\n");
1018  return SCIP_INVALIDDATA;
1019  }
1020 
1021  /* release variable */
1022  assert(boundchg->var != NULL);
1023  SCIP_CALL( SCIPvarRelease(&boundchg->var, blkmem, set, eventqueue, lp) );
1024 
1025  return SCIP_OKAY;
1026 }
1027 
1028 /** creates empty domain change data with dynamic arrays */
1029 static
1031  SCIP_DOMCHG** domchg, /**< pointer to domain change data */
1032  BMS_BLKMEM* blkmem /**< block memory */
1033  )
1034 {
1035  assert(domchg != NULL);
1036  assert(blkmem != NULL);
1037 
1038  SCIP_ALLOC( BMSallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN)) );
1039  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
1040  (*domchg)->domchgdyn.nboundchgs = 0;
1041  (*domchg)->domchgdyn.boundchgs = NULL;
1042  (*domchg)->domchgdyn.nholechgs = 0;
1043  (*domchg)->domchgdyn.holechgs = NULL;
1044  (*domchg)->domchgdyn.boundchgssize = 0;
1045  (*domchg)->domchgdyn.holechgssize = 0;
1046 
1047  return SCIP_OKAY;
1048 }
1049 
1050 /** frees domain change data */
1052  SCIP_DOMCHG** domchg, /**< pointer to domain change */
1053  BMS_BLKMEM* blkmem, /**< block memory */
1054  SCIP_SET* set, /**< global SCIP settings */
1055  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1056  SCIP_LP* lp /**< current LP data */
1057  )
1058 {
1059  assert(domchg != NULL);
1060  assert(blkmem != NULL);
1061 
1062  if( *domchg != NULL )
1063  {
1064  int i;
1065 
1066  /* release variables, branching and inference data associated with the bound changes */
1067  for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1068  {
1069  SCIP_CALL( boundchgReleaseData(&(*domchg)->domchgbound.boundchgs[i], blkmem, set, eventqueue, lp) );
1070  }
1071 
1072  /* free memory for bound and hole changes */
1073  switch( (*domchg)->domchgdyn.domchgtype )
1074  {
1075  case SCIP_DOMCHGTYPE_BOUND:
1076  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgbound.boundchgs, (*domchg)->domchgbound.nboundchgs);
1077  BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOUND));
1078  break;
1079  case SCIP_DOMCHGTYPE_BOTH:
1080  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgboth.boundchgs, (*domchg)->domchgboth.nboundchgs);
1081  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgboth.holechgs, (*domchg)->domchgboth.nholechgs);
1082  BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH));
1083  break;
1085  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.boundchgs, (*domchg)->domchgdyn.boundchgssize);
1086  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.holechgs, (*domchg)->domchgdyn.holechgssize);
1087  BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN));
1088  break;
1089  default:
1090  SCIPerrorMessage("invalid domain change type\n");
1091  return SCIP_INVALIDDATA;
1092  }
1093  }
1094 
1095  return SCIP_OKAY;
1096 }
1097 
1098 /** converts a static domain change data into a dynamic one */
1099 static
1101  SCIP_DOMCHG** domchg, /**< pointer to domain change data */
1102  BMS_BLKMEM* blkmem /**< block memory */
1103  )
1104 {
1105  assert(domchg != NULL);
1106  assert(blkmem != NULL);
1107 
1108  SCIPdebugMessage("making domain change data %p pointing to %p dynamic\n", (void*)domchg, (void*)*domchg);
1109 
1110  if( *domchg == NULL )
1111  {
1112  SCIP_CALL( domchgCreate(domchg, blkmem) );
1113  }
1114  else
1115  {
1116  switch( (*domchg)->domchgdyn.domchgtype )
1117  {
1118  case SCIP_DOMCHGTYPE_BOUND:
1119  SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOUND), sizeof(SCIP_DOMCHGDYN)) );
1120  (*domchg)->domchgdyn.nholechgs = 0;
1121  (*domchg)->domchgdyn.holechgs = NULL;
1122  (*domchg)->domchgdyn.boundchgssize = (int) (*domchg)->domchgdyn.nboundchgs;
1123  (*domchg)->domchgdyn.holechgssize = 0;
1124  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
1125  break;
1126  case SCIP_DOMCHGTYPE_BOTH:
1127  SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH), sizeof(SCIP_DOMCHGDYN)) );
1128  (*domchg)->domchgdyn.boundchgssize = (int) (*domchg)->domchgdyn.nboundchgs;
1129  (*domchg)->domchgdyn.holechgssize = (*domchg)->domchgdyn.nholechgs;
1130  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
1131  break;
1133  break;
1134  default:
1135  SCIPerrorMessage("invalid domain change type\n");
1136  return SCIP_INVALIDDATA;
1137  }
1138  }
1139 #ifndef NDEBUG
1140  {
1141  int i;
1142  for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1143  assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1144  || EPSISINT((*domchg)->domchgbound.boundchgs[i].newbound, 1e-06));
1145  }
1146 #endif
1147 
1148  return SCIP_OKAY;
1149 }
1150 
1151 /** converts a dynamic domain change data into a static one, using less memory than for a dynamic one */
1153  SCIP_DOMCHG** domchg, /**< pointer to domain change data */
1154  BMS_BLKMEM* blkmem, /**< block memory */
1155  SCIP_SET* set, /**< global SCIP settings */
1156  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1157  SCIP_LP* lp /**< current LP data */
1158  )
1159 {
1160  assert(domchg != NULL);
1161  assert(blkmem != NULL);
1162 
1163  SCIPsetDebugMsg(set, "making domain change data %p pointing to %p static\n", (void*)domchg, (void*)*domchg);
1164 
1165  if( *domchg != NULL )
1166  {
1167  switch( (*domchg)->domchgdyn.domchgtype )
1168  {
1169  case SCIP_DOMCHGTYPE_BOUND:
1170  if( (*domchg)->domchgbound.nboundchgs == 0 )
1171  {
1172  SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1173  }
1174  break;
1175  case SCIP_DOMCHGTYPE_BOTH:
1176  if( (*domchg)->domchgboth.nholechgs == 0 )
1177  {
1178  if( (*domchg)->domchgbound.nboundchgs == 0 )
1179  {
1180  SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1181  }
1182  else
1183  {
1184  SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH), sizeof(SCIP_DOMCHGBOUND)) );
1185  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOUND; /*lint !e641*/
1186  }
1187  }
1188  break;
1190  if( (*domchg)->domchgboth.nholechgs == 0 )
1191  {
1192  if( (*domchg)->domchgbound.nboundchgs == 0 )
1193  {
1194  SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1195  }
1196  else
1197  {
1198  /* shrink dynamic size arrays to their minimal sizes */
1199  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.boundchgs, \
1200  (*domchg)->domchgdyn.boundchgssize, (*domchg)->domchgdyn.nboundchgs) ); /*lint !e571*/
1201  BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.holechgs, (*domchg)->domchgdyn.holechgssize);
1202 
1203  /* convert into static domain change */
1204  SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN), sizeof(SCIP_DOMCHGBOUND)) );
1205  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOUND; /*lint !e641*/
1206  }
1207  }
1208  else
1209  {
1210  /* shrink dynamic size arrays to their minimal sizes */
1211  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.boundchgs, \
1212  (*domchg)->domchgdyn.boundchgssize, (*domchg)->domchgdyn.nboundchgs) ); /*lint !e571*/
1213  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.holechgs, \
1214  (*domchg)->domchgdyn.holechgssize, (*domchg)->domchgdyn.nholechgs) );
1215 
1216  /* convert into static domain change */
1217  SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN), sizeof(SCIP_DOMCHGBOTH)) );
1218  (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOTH; /*lint !e641*/
1219  }
1220  break;
1221  default:
1222  SCIPerrorMessage("invalid domain change type\n");
1223  return SCIP_INVALIDDATA;
1224  }
1225 #ifndef NDEBUG
1226  if( *domchg != NULL )
1227  {
1228  int i;
1229  for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1230  assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1231  || SCIPsetIsFeasIntegral(set, (*domchg)->domchgbound.boundchgs[i].newbound));
1232  }
1233 #endif
1234  }
1235 
1236  return SCIP_OKAY;
1237 }
1238 
1239 /** ensures, that boundchgs array can store at least num entries */
1240 static
1242  SCIP_DOMCHG* domchg, /**< domain change data structure */
1243  BMS_BLKMEM* blkmem, /**< block memory */
1244  SCIP_SET* set, /**< global SCIP settings */
1245  int num /**< minimum number of entries to store */
1246  )
1247 {
1248  assert(domchg != NULL);
1249  assert(domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1250 
1251  if( num > domchg->domchgdyn.boundchgssize )
1252  {
1253  int newsize;
1254 
1255  newsize = SCIPsetCalcMemGrowSize(set, num);
1256  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &domchg->domchgdyn.boundchgs, domchg->domchgdyn.boundchgssize, newsize) );
1257  domchg->domchgdyn.boundchgssize = newsize;
1258  }
1259  assert(num <= domchg->domchgdyn.boundchgssize);
1260 
1261  return SCIP_OKAY;
1262 }
1263 
1264 /** ensures, that holechgs array can store at least num additional entries */
1265 static
1267  SCIP_DOMCHG* domchg, /**< domain change data structure */
1268  BMS_BLKMEM* blkmem, /**< block memory */
1269  SCIP_SET* set, /**< global SCIP settings */
1270  int num /**< minimum number of additional entries to store */
1271  )
1272 {
1273  assert(domchg != NULL);
1274  assert(domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1275 
1276  if( num > domchg->domchgdyn.holechgssize )
1277  {
1278  int newsize;
1279 
1280  newsize = SCIPsetCalcMemGrowSize(set, num);
1281  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &domchg->domchgdyn.holechgs, domchg->domchgdyn.holechgssize, newsize) );
1282  domchg->domchgdyn.holechgssize = newsize;
1283  }
1284  assert(num <= domchg->domchgdyn.holechgssize);
1285 
1286  return SCIP_OKAY;
1287 }
1288 
1289 /** applies domain change */
1291  SCIP_DOMCHG* domchg, /**< domain change to apply */
1292  BMS_BLKMEM* blkmem, /**< block memory */
1293  SCIP_SET* set, /**< global SCIP settings */
1294  SCIP_STAT* stat, /**< problem statistics */
1295  SCIP_LP* lp, /**< current LP data */
1296  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1297  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1298  int depth, /**< depth in the tree, where the domain change takes place */
1299  SCIP_Bool* cutoff /**< pointer to store whether an infeasible domain change was detected */
1300  )
1301 {
1302  int i;
1303 
1304  assert(cutoff != NULL);
1305 
1306  *cutoff = FALSE;
1307 
1308  SCIPsetDebugMsg(set, "applying domain changes at %p in depth %d\n", (void*)domchg, depth);
1309 
1310  if( domchg == NULL )
1311  return SCIP_OKAY;
1312 
1313  /* apply bound changes */
1314  for( i = 0; i < (int)domchg->domchgbound.nboundchgs; ++i )
1315  {
1316  SCIP_CALL( SCIPboundchgApply(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp,
1317  branchcand, eventqueue, depth, i, cutoff) );
1318  if( *cutoff )
1319  break;
1320  }
1321  SCIPsetDebugMsg(set, " -> %u bound changes (cutoff %u)\n", domchg->domchgbound.nboundchgs, *cutoff);
1322 
1323  /* mark all bound changes after a cutoff redundant */
1324  for( ; i < (int)domchg->domchgbound.nboundchgs; ++i )
1325  domchg->domchgbound.boundchgs[i].redundant = TRUE;
1326 
1327  /* apply holelist changes */
1328  if( domchg->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_BOUND ) /*lint !e641*/
1329  {
1330  for( i = 0; i < domchg->domchgboth.nholechgs; ++i )
1331  *(domchg->domchgboth.holechgs[i].ptr) = domchg->domchgboth.holechgs[i].newlist;
1332  SCIPsetDebugMsg(set, " -> %d hole changes\n", domchg->domchgboth.nholechgs);
1333  }
1334 
1335  return SCIP_OKAY;
1336 }
1337 
1338 /** undoes domain change */
1340  SCIP_DOMCHG* domchg, /**< domain change to remove */
1341  BMS_BLKMEM* blkmem, /**< block memory */
1342  SCIP_SET* set, /**< global SCIP settings */
1343  SCIP_STAT* stat, /**< problem statistics */
1344  SCIP_LP* lp, /**< current LP data */
1345  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1346  SCIP_EVENTQUEUE* eventqueue /**< event queue */
1347  )
1348 {
1349  int i;
1350 
1351  SCIPsetDebugMsg(set, "undoing domain changes at %p\n", (void*)domchg);
1352  if( domchg == NULL )
1353  return SCIP_OKAY;
1354 
1355  /* undo holelist changes */
1356  if( domchg->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_BOUND ) /*lint !e641*/
1357  {
1358  for( i = domchg->domchgboth.nholechgs-1; i >= 0; --i )
1359  *(domchg->domchgboth.holechgs[i].ptr) = domchg->domchgboth.holechgs[i].oldlist;
1360  SCIPsetDebugMsg(set, " -> %d hole changes\n", domchg->domchgboth.nholechgs);
1361  }
1362 
1363  /* undo bound changes */
1364  for( i = domchg->domchgbound.nboundchgs-1; i >= 0; --i )
1365  {
1366  SCIP_CALL( SCIPboundchgUndo(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp, branchcand, eventqueue) );
1367  }
1368  SCIPsetDebugMsg(set, " -> %u bound changes\n", domchg->domchgbound.nboundchgs);
1369 
1370  return SCIP_OKAY;
1371 }
1372 
1373 /** applies domain change to the global problem */
1375  SCIP_DOMCHG* domchg, /**< domain change to apply */
1376  BMS_BLKMEM* blkmem, /**< block memory */
1377  SCIP_SET* set, /**< global SCIP settings */
1378  SCIP_STAT* stat, /**< problem statistics */
1379  SCIP_LP* lp, /**< current LP data */
1380  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1381  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1382  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1383  SCIP_Bool* cutoff /**< pointer to store whether an infeasible domain change was detected */
1384  )
1385 {
1386  int i;
1387 
1388  assert(cutoff != NULL);
1389 
1390  *cutoff = FALSE;
1391 
1392  if( domchg == NULL )
1393  return SCIP_OKAY;
1394 
1395  SCIPsetDebugMsg(set, "applying domain changes at %p to the global problem\n", (void*)domchg);
1396 
1397  /* apply bound changes */
1398  for( i = 0; i < (int)domchg->domchgbound.nboundchgs; ++i )
1399  {
1400  SCIP_CALL( boundchgApplyGlobal(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp,
1401  branchcand, eventqueue, cliquetable, cutoff) );
1402  if( *cutoff )
1403  break;
1404  }
1405  SCIPsetDebugMsg(set, " -> %u global bound changes\n", domchg->domchgbound.nboundchgs);
1406 
1407  /**@todo globally apply holelist changes - how can this be done without confusing pointer updates? */
1408 
1409  return SCIP_OKAY;
1410 }
1411 
1412 /** adds bound change to domain changes */
1414  SCIP_DOMCHG** domchg, /**< pointer to domain change data structure */
1415  BMS_BLKMEM* blkmem, /**< block memory */
1416  SCIP_SET* set, /**< global SCIP settings */
1417  SCIP_VAR* var, /**< variable to change the bounds for */
1418  SCIP_Real newbound, /**< new value for bound */
1419  SCIP_BOUNDTYPE boundtype, /**< type of bound for var: lower or upper bound */
1420  SCIP_BOUNDCHGTYPE boundchgtype, /**< type of bound change: branching decision or inference */
1421  SCIP_Real lpsolval, /**< solval of variable in last LP on path to node, or SCIP_INVALID if unknown */
1422  SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself), or NULL */
1423  SCIP_CONS* infercons, /**< constraint that deduced the bound change, or NULL */
1424  SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
1425  int inferinfo, /**< user information for inference to help resolving the conflict */
1426  SCIP_BOUNDTYPE inferboundtype /**< type of bound for inference var: lower or upper bound */
1427  )
1428 {
1429  SCIP_BOUNDCHG* boundchg;
1430 
1431  assert(domchg != NULL);
1432  assert(var != NULL);
1434  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
1435  assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, boundtype == SCIP_BOUNDTYPE_LOWER ? 1.0 : 0.0));
1436  assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
1437  assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
1438  assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
1439 
1440  SCIPsetDebugMsg(set, "adding %s bound change <%s: %g> of variable <%s> to domain change at %p pointing to %p\n",
1441  boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
1442  newbound, var->name, (void*)domchg, (void*)*domchg);
1443 
1444  /* if domain change data doesn't exist, create it;
1445  * if domain change is static, convert it into dynamic change
1446  */
1447  if( *domchg == NULL )
1448  {
1449  SCIP_CALL( domchgCreate(domchg, blkmem) );
1450  }
1451  else if( (*domchg)->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_DYNAMIC ) /*lint !e641*/
1452  {
1453  SCIP_CALL( domchgMakeDynamic(domchg, blkmem) );
1454  }
1455  assert(*domchg != NULL && (*domchg)->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1456 
1457  /* get memory for additional bound change */
1458  SCIP_CALL( domchgEnsureBoundchgsSize(*domchg, blkmem, set, (*domchg)->domchgdyn.nboundchgs+1) );
1459 
1460  /* fill in the bound change data */
1461  boundchg = &(*domchg)->domchgdyn.boundchgs[(*domchg)->domchgdyn.nboundchgs];
1462  boundchg->var = var;
1463  switch( boundchgtype )
1464  {
1466  boundchg->data.branchingdata.lpsolval = lpsolval;
1467  break;
1469  assert(infercons != NULL);
1470  boundchg->data.inferencedata.var = infervar;
1471  boundchg->data.inferencedata.reason.cons = infercons;
1472  boundchg->data.inferencedata.info = inferinfo;
1473  break;
1475  boundchg->data.inferencedata.var = infervar;
1476  boundchg->data.inferencedata.reason.prop = inferprop;
1477  boundchg->data.inferencedata.info = inferinfo;
1478  break;
1479  default:
1480  SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
1481  return SCIP_INVALIDDATA;
1482  }
1483 
1484  boundchg->newbound = newbound;
1485  boundchg->boundchgtype = boundchgtype; /*lint !e641*/
1486  boundchg->boundtype = boundtype; /*lint !e641*/
1487  boundchg->inferboundtype = inferboundtype; /*lint !e641*/
1488  boundchg->applied = FALSE;
1489  boundchg->redundant = FALSE;
1490  (*domchg)->domchgdyn.nboundchgs++;
1491 
1492  /* capture branching and inference data associated with the bound changes */
1493  SCIP_CALL( boundchgCaptureData(boundchg) );
1494 
1495 #ifdef SCIP_DISABLED_CODE /* expensive debug check */
1496 #ifdef SCIP_MORE_DEBUG
1497  {
1498  int i;
1499  for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1500  assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1501  || SCIPsetIsFeasIntegral(set, (*domchg)->domchgbound.boundchgs[i].newbound));
1502  }
1503 #endif
1504 #endif
1505 
1506  return SCIP_OKAY;
1507 }
1508 
1509 /** adds hole change to domain changes */
1511  SCIP_DOMCHG** domchg, /**< pointer to domain change data structure */
1512  BMS_BLKMEM* blkmem, /**< block memory */
1513  SCIP_SET* set, /**< global SCIP settings */
1514  SCIP_HOLELIST** ptr, /**< changed list pointer */
1515  SCIP_HOLELIST* newlist, /**< new value of list pointer */
1516  SCIP_HOLELIST* oldlist /**< old value of list pointer */
1517  )
1518 {
1519  SCIP_HOLECHG* holechg;
1520 
1521  assert(domchg != NULL);
1522  assert(ptr != NULL);
1523 
1524  /* if domain change data doesn't exist, create it;
1525  * if domain change is static, convert it into dynamic change
1526  */
1527  if( *domchg == NULL )
1528  {
1529  SCIP_CALL( domchgCreate(domchg, blkmem) );
1530  }
1531  else if( (*domchg)->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_DYNAMIC ) /*lint !e641*/
1532  {
1533  SCIP_CALL( domchgMakeDynamic(domchg, blkmem) );
1534  }
1535  assert(*domchg != NULL && (*domchg)->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1536 
1537  /* get memory for additional hole change */
1538  SCIP_CALL( domchgEnsureHolechgsSize(*domchg, blkmem, set, (*domchg)->domchgdyn.nholechgs+1) );
1539 
1540  /* fill in the hole change data */
1541  holechg = &(*domchg)->domchgdyn.holechgs[(*domchg)->domchgdyn.nholechgs];
1542  holechg->ptr = ptr;
1543  holechg->newlist = newlist;
1544  holechg->oldlist = oldlist;
1545  (*domchg)->domchgdyn.nholechgs++;
1546 
1547  return SCIP_OKAY;
1548 }
1549 
1550 
1551 
1552 
1553 /*
1554  * methods for variables
1555  */
1556 
1557 /** returns adjusted lower bound value, which is rounded for integral variable types */
1558 static
1560  SCIP_SET* set, /**< global SCIP settings */
1561  SCIP_VARTYPE vartype, /**< type of variable */
1562  SCIP_Real lb /**< lower bound to adjust */
1563  )
1564 {
1565  if( lb < 0.0 && SCIPsetIsInfinity(set, -lb) )
1566  return -SCIPsetInfinity(set);
1567  else if( lb > 0.0 && SCIPsetIsInfinity(set, lb) )
1568  return SCIPsetInfinity(set);
1569  else if( vartype != SCIP_VARTYPE_CONTINUOUS )
1570  return SCIPsetFeasCeil(set, lb);
1571  else if( lb > 0.0 && lb < SCIPsetEpsilon(set) )
1572  return 0.0;
1573  else
1574  return lb;
1575 }
1576 
1577 /** returns adjusted upper bound value, which is rounded for integral variable types */
1578 static
1580  SCIP_SET* set, /**< global SCIP settings */
1581  SCIP_VARTYPE vartype, /**< type of variable */
1582  SCIP_Real ub /**< upper bound to adjust */
1583  )
1584 {
1585  if( ub > 0.0 && SCIPsetIsInfinity(set, ub) )
1586  return SCIPsetInfinity(set);
1587  else if( ub < 0.0 && SCIPsetIsInfinity(set, -ub) )
1588  return -SCIPsetInfinity(set);
1589  else if( vartype != SCIP_VARTYPE_CONTINUOUS )
1590  return SCIPsetFeasFloor(set, ub);
1591  else if( ub < 0.0 && ub > -SCIPsetEpsilon(set) )
1592  return 0.0;
1593  else
1594  return ub;
1595 }
1596 
1597 /** removes (redundant) cliques, implications and variable bounds of variable from all other variables' implications and variable
1598  * bounds arrays, and optionally removes them also from the variable itself
1599  */
1601  SCIP_VAR* var, /**< problem variable */
1602  BMS_BLKMEM* blkmem, /**< block memory */
1603  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1604  SCIP_SET* set, /**< global SCIP settings */
1605  SCIP_Bool irrelevantvar, /**< has the variable become irrelevant? */
1606  SCIP_Bool onlyredundant, /**< should only the redundant implications and variable bounds be removed? */
1607  SCIP_Bool removefromvar /**< should the implications and variable bounds be removed from the var itself? */
1608  )
1609 {
1610  SCIP_Real lb;
1611  SCIP_Real ub;
1612 
1613  assert(var != NULL);
1615  assert(SCIPvarIsActive(var) || SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
1616 
1617  lb = SCIPvarGetLbGlobal(var);
1618  ub = SCIPvarGetUbGlobal(var);
1619 
1620  SCIPsetDebugMsg(set, "removing %s implications and vbounds of %s<%s>[%g,%g]\n",
1621  onlyredundant ? "redundant" : "all", irrelevantvar ? "irrelevant " : "", SCIPvarGetName(var), lb, ub);
1622 
1623  /* remove implications of (fixed) binary variable */
1624  if( var->implics != NULL && (!onlyredundant || lb > 0.5 || ub < 0.5) )
1625  {
1626  SCIP_Bool varfixing;
1627 
1628  assert(SCIPvarIsBinary(var));
1629 
1630  varfixing = FALSE;
1631  do
1632  {
1633  SCIP_VAR** implvars;
1634  SCIP_BOUNDTYPE* impltypes;
1635  int nimpls;
1636  int i;
1637 
1638  nimpls = SCIPimplicsGetNImpls(var->implics, varfixing);
1639  implvars = SCIPimplicsGetVars(var->implics, varfixing);
1640  impltypes = SCIPimplicsGetTypes(var->implics, varfixing);
1641 
1642  for( i = 0; i < nimpls; i++ )
1643  {
1644  SCIP_VAR* implvar;
1645  SCIP_BOUNDTYPE impltype;
1646 
1647  implvar = implvars[i];
1648  impltype = impltypes[i];
1649  assert(implvar != var);
1650 
1651  /* remove for all implications z == 0 / 1 ==> x <= p / x >= p (x not binary)
1652  * the following variable bound from x's variable bounds
1653  * x <= b*z+d (z in vubs of x) , for z == 0 / 1 ==> x <= p
1654  * x >= b*z+d (z in vlbs of x) , for z == 0 / 1 ==> x >= p
1655  */
1656  if( impltype == SCIP_BOUNDTYPE_UPPER )
1657  {
1658  if( implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1659  {
1660  SCIPsetDebugMsg(set, "deleting variable bound: <%s> == %u ==> <%s> <= %g\n",
1661  SCIPvarGetName(var), varfixing, SCIPvarGetName(implvar),
1662  SCIPimplicsGetBounds(var->implics, varfixing)[i]);
1663  SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, varfixing) );
1664  implvar->closestvblpcount = -1;
1665  var->closestvblpcount = -1;
1666  }
1667  }
1668  else
1669  {
1670  if( implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1671  {
1672  SCIPsetDebugMsg(set, "deleting variable bound: <%s> == %u ==> <%s> >= %g\n",
1673  SCIPvarGetName(var), varfixing, SCIPvarGetName(implvar),
1674  SCIPimplicsGetBounds(var->implics, varfixing)[i]);
1675  SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, !varfixing) );
1676  implvar->closestvblpcount = -1;
1677  var->closestvblpcount = -1;
1678  }
1679  }
1680  }
1681  varfixing = !varfixing;
1682  }
1683  while( varfixing == TRUE );
1684 
1685  if( removefromvar )
1686  {
1687  /* free the implications data structures */
1688  SCIPimplicsFree(&var->implics, blkmem);
1689  }
1690  }
1691 
1692  /* remove the (redundant) variable lower bounds */
1693  if( var->vlbs != NULL )
1694  {
1695  SCIP_VAR** vars;
1696  SCIP_Real* coefs;
1697  SCIP_Real* constants;
1698  int nvbds;
1699  int newnvbds;
1700  int i;
1701 
1702  nvbds = SCIPvboundsGetNVbds(var->vlbs);
1703  vars = SCIPvboundsGetVars(var->vlbs);
1704  coefs = SCIPvboundsGetCoefs(var->vlbs);
1705  constants = SCIPvboundsGetConstants(var->vlbs);
1706 
1707  /* remove for all variable bounds x >= b*z+d the following implication from z's implications
1708  * z == ub ==> x >= b*ub + d , if b > 0
1709  * z == lb ==> x >= b*lb + d , if b < 0
1710  */
1711  newnvbds = 0;
1712  for( i = 0; i < nvbds; i++ )
1713  {
1714  SCIP_VAR* implvar;
1715  SCIP_Real coef;
1716 
1717  assert(newnvbds <= i);
1718 
1719  implvar = vars[i];
1720  assert(implvar != NULL);
1721 
1722  coef = coefs[i];
1723  assert(!SCIPsetIsZero(set, coef));
1724 
1725  /* check, if we want to remove the variable bound */
1726  if( onlyredundant )
1727  {
1728  SCIP_Real vbound;
1729 
1730  vbound = MAX(coef * SCIPvarGetUbGlobal(implvar), coef * SCIPvarGetLbGlobal(implvar)) + constants[i]; /*lint !e666*/
1731  if( SCIPsetIsFeasGT(set, vbound, lb) )
1732  {
1733  /* the variable bound is not redundant: keep it */
1734  if( removefromvar )
1735  {
1736  if( newnvbds < i )
1737  {
1738  vars[newnvbds] = implvar;
1739  coefs[newnvbds] = coef;
1740  constants[newnvbds] = constants[i];
1741  }
1742  newnvbds++;
1743  }
1744  continue;
1745  }
1746  }
1747 
1748  /* remove the corresponding implication */
1749  if( implvar->implics != NULL ) /* variable may have been aggregated in the mean time */
1750  {
1751  SCIPsetDebugMsg(set, "deleting implication: <%s> == %d ==> <%s> >= %g\n",
1752  SCIPvarGetName(implvar), (coef > 0.0), SCIPvarGetName(var), MAX(coef, 0.0) + constants[i]);
1753  SCIP_CALL( SCIPimplicsDel(&implvar->implics, blkmem, set, (coef > 0.0), var, SCIP_BOUNDTYPE_LOWER) );
1754  }
1755  if( coef > 0.0 && implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1756  {
1757  SCIPsetDebugMsg(set, "deleting variable upper bound from <%s> involving variable %s\n",
1758  SCIPvarGetName(implvar), SCIPvarGetName(var));
1759  SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, FALSE) );
1760  implvar->closestvblpcount = -1;
1761  var->closestvblpcount = -1;
1762  }
1763  else if( coef < 0.0 && implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1764  {
1765  SCIPsetDebugMsg(set, "deleting variable lower bound from <%s> involving variable %s\n",
1766  SCIPvarGetName(implvar), SCIPvarGetName(var));
1767  SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, TRUE) );
1768  implvar->closestvblpcount = -1;
1769  var->closestvblpcount = -1;
1770  }
1771  }
1772 
1773  if( removefromvar )
1774  {
1775  /* update the number of variable bounds */
1776  SCIPvboundsShrink(&var->vlbs, blkmem, newnvbds);
1777  var->closestvblpcount = -1;
1778  }
1779  }
1780 
1781  /**@todo in general, variable bounds like x >= b*z + d corresponding to an implication like z = ub ==> x >= b*ub + d
1782  * might be missing because we only add variable bounds with reasonably small value of b. thus, we currently
1783  * cannot remove such variables x from z's implications.
1784  */
1785 
1786  /* remove the (redundant) variable upper bounds */
1787  if( var->vubs != NULL )
1788  {
1789  SCIP_VAR** vars;
1790  SCIP_Real* coefs;
1791  SCIP_Real* constants;
1792  int nvbds;
1793  int newnvbds;
1794  int i;
1795 
1796  nvbds = SCIPvboundsGetNVbds(var->vubs);
1797  vars = SCIPvboundsGetVars(var->vubs);
1798  coefs = SCIPvboundsGetCoefs(var->vubs);
1799  constants = SCIPvboundsGetConstants(var->vubs);
1800 
1801  /* remove for all variable bounds x <= b*z+d the following implication from z's implications
1802  * z == lb ==> x <= b*lb + d , if b > 0
1803  * z == ub ==> x <= b*ub + d , if b < 0
1804  */
1805  newnvbds = 0;
1806  for( i = 0; i < nvbds; i++ )
1807  {
1808  SCIP_VAR* implvar;
1809  SCIP_Real coef;
1810 
1811  assert(newnvbds <= i);
1812 
1813  implvar = vars[i];
1814  assert(implvar != NULL);
1815 
1816  coef = coefs[i];
1817  assert(!SCIPsetIsZero(set, coef));
1818 
1819  /* check, if we want to remove the variable bound */
1820  if( onlyredundant )
1821  {
1822  SCIP_Real vbound;
1823 
1824  vbound = MIN(coef * SCIPvarGetUbGlobal(implvar), coef * SCIPvarGetLbGlobal(implvar)) + constants[i]; /*lint !e666*/
1825  if( SCIPsetIsFeasLT(set, vbound, ub) )
1826  {
1827  /* the variable bound is not redundant: keep it */
1828  if( removefromvar )
1829  {
1830  if( newnvbds < i )
1831  {
1832  vars[newnvbds] = implvar;
1833  coefs[newnvbds] = coefs[i];
1834  constants[newnvbds] = constants[i];
1835  }
1836  newnvbds++;
1837  }
1838  continue;
1839  }
1840  }
1841 
1842  /* remove the corresponding implication */
1843  if( implvar->implics != NULL ) /* variable may have been aggregated in the mean time */
1844  {
1845  SCIPsetDebugMsg(set, "deleting implication: <%s> == %d ==> <%s> <= %g\n",
1846  SCIPvarGetName(implvar), (coef < 0.0), SCIPvarGetName(var), MIN(coef, 0.0) + constants[i]);
1847  SCIP_CALL( SCIPimplicsDel(&implvar->implics, blkmem, set, (coef < 0.0), var, SCIP_BOUNDTYPE_UPPER) );
1848  }
1849  if( coef < 0.0 && implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1850  {
1851  SCIPsetDebugMsg(set, "deleting variable upper bound from <%s> involving variable %s\n",
1852  SCIPvarGetName(implvar), SCIPvarGetName(var));
1853  SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, TRUE) );
1854  implvar->closestvblpcount = -1;
1855  var->closestvblpcount = -1;
1856  }
1857  else if( coef > 0.0 && implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1858  {
1859  SCIPsetDebugMsg(set, "deleting variable lower bound from <%s> involving variable %s\n",
1860  SCIPvarGetName(implvar), SCIPvarGetName(var));
1861  SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, FALSE) );
1862  implvar->closestvblpcount = -1;
1863  var->closestvblpcount = -1;
1864  }
1865  }
1866 
1867  if( removefromvar )
1868  {
1869  /* update the number of variable bounds */
1870  SCIPvboundsShrink(&var->vubs, blkmem, newnvbds);
1871  var->closestvblpcount = -1;
1872  }
1873  }
1874 
1875  /* remove the variable from all cliques */
1876  if( SCIPvarIsBinary(var) )
1877  {
1878  SCIPcliquelistRemoveFromCliques(var->cliquelist, cliquetable, var, irrelevantvar);
1879  SCIPcliquelistFree(&var->cliquelist, blkmem);
1880  }
1881 
1882  /**@todo variable bounds like x <= b*z + d with z general integer are not removed from x's vbd arrays, because
1883  * z has no link (like in the binary case) to x
1884  */
1885 
1886  return SCIP_OKAY;
1887 }
1888 
1889 /** sets the variable name */
1890 static
1892  SCIP_VAR* var, /**< problem variable */
1893  BMS_BLKMEM* blkmem, /**< block memory */
1894  SCIP_STAT* stat, /**< problem statistics, or NULL */
1895  const char* name /**< name of variable, or NULL for automatic name creation */
1896  )
1897 {
1898  assert(blkmem != NULL);
1899  assert(var != NULL);
1900 
1901  if( name == NULL )
1902  {
1903  char s[SCIP_MAXSTRLEN];
1904 
1905  assert(stat != NULL);
1906 
1907  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "_var%d_", stat->nvaridx);
1908  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->name, s, strlen(s)+1) );
1909  }
1910  else
1911  {
1912  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->name, name, strlen(name)+1) );
1913  }
1914 
1915  return SCIP_OKAY;
1916 }
1917 
1918 
1919 /** creates variable; if variable is of integral type, fractional bounds are automatically rounded; an integer variable
1920  * with bounds zero and one is automatically converted into a binary variable
1921  */
1922 static
1924  SCIP_VAR** var, /**< pointer to variable data */
1925  BMS_BLKMEM* blkmem, /**< block memory */
1926  SCIP_SET* set, /**< global SCIP settings */
1927  SCIP_STAT* stat, /**< problem statistics */
1928  const char* name, /**< name of variable, or NULL for automatic name creation */
1929  SCIP_Real lb, /**< lower bound of variable */
1930  SCIP_Real ub, /**< upper bound of variable */
1931  SCIP_Real obj, /**< objective function value */
1932  SCIP_VARTYPE vartype, /**< type of variable */
1933  SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
1934  SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
1935  SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
1936  SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */
1937  SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */
1938  SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */
1939  SCIP_VARDATA* vardata /**< user data for this specific variable */
1940  )
1941 {
1942  int i;
1943 
1944  assert(var != NULL);
1945  assert(blkmem != NULL);
1946  assert(stat != NULL);
1947 
1948  /* adjust bounds of variable */
1949  lb = adjustedLb(set, vartype, lb);
1950  ub = adjustedUb(set, vartype, ub);
1951 
1952  /* convert [0,1]-integers into binary variables and check that binary variables have correct bounds */
1953  if( (SCIPsetIsEQ(set, lb, 0.0) || SCIPsetIsEQ(set, lb, 1.0))
1954  && (SCIPsetIsEQ(set, ub, 0.0) || SCIPsetIsEQ(set, ub, 1.0)) )
1955  {
1956  if( vartype == SCIP_VARTYPE_INTEGER )
1957  vartype = SCIP_VARTYPE_BINARY;
1958  }
1959  else
1960  {
1961  if( vartype == SCIP_VARTYPE_BINARY )
1962  {
1963  SCIPerrorMessage("invalid bounds [%.2g,%.2g] for binary variable <%s>\n", lb, ub, name);
1964  return SCIP_INVALIDDATA;
1965  }
1966  }
1967 
1968  assert(vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, lb, 0.0) || SCIPsetIsEQ(set, lb, 1.0));
1969  assert(vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, ub, 0.0) || SCIPsetIsEQ(set, ub, 1.0));
1970 
1971  SCIP_ALLOC( BMSallocBlockMemory(blkmem, var) );
1972 
1973  /* set variable's name */
1974  SCIP_CALL( varSetName(*var, blkmem, stat, name) );
1975 
1976 #ifndef NDEBUG
1977  (*var)->scip = set->scip;
1978 #endif
1979  (*var)->obj = obj;
1980  (*var)->unchangedobj = obj;
1981  (*var)->branchfactor = 1.0;
1982  (*var)->rootsol = 0.0;
1983  (*var)->bestrootsol = 0.0;
1984  (*var)->bestrootredcost = 0.0;
1985  (*var)->bestrootlpobjval = SCIP_INVALID;
1986  (*var)->relaxsol = 0.0;
1987  (*var)->nlpsol = 0.0;
1988  (*var)->primsolavg = 0.5 * (lb + ub);
1989  (*var)->conflictlb = SCIP_REAL_MIN;
1990  (*var)->conflictub = SCIP_REAL_MAX;
1991  (*var)->conflictrelaxedlb = (*var)->conflictlb;
1992  (*var)->conflictrelaxedub = (*var)->conflictub;
1993  (*var)->lazylb = -SCIPsetInfinity(set);
1994  (*var)->lazyub = SCIPsetInfinity(set);
1995  (*var)->glbdom.holelist = NULL;
1996  (*var)->glbdom.lb = lb;
1997  (*var)->glbdom.ub = ub;
1998  (*var)->locdom.holelist = NULL;
1999  (*var)->locdom.lb = lb;
2000  (*var)->locdom.ub = ub;
2001  (*var)->varcopy = varcopy;
2002  (*var)->vardelorig = vardelorig;
2003  (*var)->vartrans = vartrans;
2004  (*var)->vardeltrans = vardeltrans;
2005  (*var)->vardata = vardata;
2006  (*var)->parentvars = NULL;
2007  (*var)->negatedvar = NULL;
2008  (*var)->vlbs = NULL;
2009  (*var)->vubs = NULL;
2010  (*var)->implics = NULL;
2011  (*var)->cliquelist = NULL;
2012  (*var)->eventfilter = NULL;
2013  (*var)->lbchginfos = NULL;
2014  (*var)->ubchginfos = NULL;
2015  (*var)->index = stat->nvaridx;
2016  (*var)->probindex = -1;
2017  (*var)->pseudocandindex = -1;
2018  (*var)->eventqueueindexobj = -1;
2019  (*var)->eventqueueindexlb = -1;
2020  (*var)->eventqueueindexub = -1;
2021  (*var)->parentvarssize = 0;
2022  (*var)->nparentvars = 0;
2023  (*var)->nuses = 0;
2024  (*var)->branchpriority = 0;
2025  (*var)->branchdirection = SCIP_BRANCHDIR_AUTO; /*lint !e641*/
2026  (*var)->lbchginfossize = 0;
2027  (*var)->nlbchginfos = 0;
2028  (*var)->ubchginfossize = 0;
2029  (*var)->nubchginfos = 0;
2030  (*var)->conflictlbcount = 0;
2031  (*var)->conflictubcount = 0;
2032  (*var)->closestvlbidx = -1;
2033  (*var)->closestvubidx = -1;
2034  (*var)->closestvblpcount = -1;
2035  (*var)->initial = initial;
2036  (*var)->removable = removable;
2037  (*var)->deleted = FALSE;
2038  (*var)->donotaggr = FALSE;
2039  (*var)->donotmultaggr = FALSE;
2040  (*var)->vartype = vartype; /*lint !e641*/
2041  (*var)->pseudocostflag = FALSE;
2042  (*var)->eventqueueimpl = FALSE;
2043  (*var)->deletable = FALSE;
2044  (*var)->delglobalstructs = FALSE;
2045  (*var)->relaxationonly = FALSE;
2046 
2047  for( i = 0; i < NLOCKTYPES; i++ )
2048  {
2049  (*var)->nlocksdown[i] = 0;
2050  (*var)->nlocksup[i] = 0;
2051  }
2052 
2053  stat->nvaridx++;
2054 
2055  /* create branching and inference history entries */
2056  SCIP_CALL( SCIPhistoryCreate(&(*var)->history, blkmem) );
2057  SCIP_CALL( SCIPhistoryCreate(&(*var)->historycrun, blkmem) );
2058 
2059  /* the value based history is only created on demand */
2060  (*var)->valuehistory = NULL;
2061 
2062  return SCIP_OKAY;
2063 }
2064 
2065 /** creates and captures an original problem variable; an integer variable with bounds
2066  * zero and one is automatically converted into a binary variable
2067  */
2069  SCIP_VAR** var, /**< pointer to variable data */
2070  BMS_BLKMEM* blkmem, /**< block memory */
2071  SCIP_SET* set, /**< global SCIP settings */
2072  SCIP_STAT* stat, /**< problem statistics */
2073  const char* name, /**< name of variable, or NULL for automatic name creation */
2074  SCIP_Real lb, /**< lower bound of variable */
2075  SCIP_Real ub, /**< upper bound of variable */
2076  SCIP_Real obj, /**< objective function value */
2077  SCIP_VARTYPE vartype, /**< type of variable */
2078  SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2079  SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2080  SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */
2081  SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */
2082  SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */
2083  SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2084  SCIP_VARDATA* vardata /**< user data for this specific variable */
2085  )
2086 {
2087  assert(var != NULL);
2088  assert(blkmem != NULL);
2089  assert(stat != NULL);
2090 
2091  /* create variable */
2092  SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2093  varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2094 
2095  /* set variable status and data */
2096  (*var)->varstatus = SCIP_VARSTATUS_ORIGINAL; /*lint !e641*/
2097  (*var)->data.original.origdom.holelist = NULL;
2098  (*var)->data.original.origdom.lb = lb;
2099  (*var)->data.original.origdom.ub = ub;
2100  (*var)->data.original.transvar = NULL;
2101 
2102  /* capture variable */
2103  SCIPvarCapture(*var);
2104 
2105  return SCIP_OKAY;
2106 }
2107 
2108 /** creates and captures a loose variable belonging to the transformed problem; an integer variable with bounds
2109  * zero and one is automatically converted into a binary variable
2110  */
2112  SCIP_VAR** var, /**< pointer to variable data */
2113  BMS_BLKMEM* blkmem, /**< block memory */
2114  SCIP_SET* set, /**< global SCIP settings */
2115  SCIP_STAT* stat, /**< problem statistics */
2116  const char* name, /**< name of variable, or NULL for automatic name creation */
2117  SCIP_Real lb, /**< lower bound of variable */
2118  SCIP_Real ub, /**< upper bound of variable */
2119  SCIP_Real obj, /**< objective function value */
2120  SCIP_VARTYPE vartype, /**< type of variable */
2121  SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2122  SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2123  SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */
2124  SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */
2125  SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */
2126  SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2127  SCIP_VARDATA* vardata /**< user data for this specific variable */
2128  )
2129 {
2130  assert(var != NULL);
2131  assert(blkmem != NULL);
2132 
2133  /* create variable */
2134  SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2135  varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2136 
2137  /* create event filter for transformed variable */
2138  SCIP_CALL( SCIPeventfilterCreate(&(*var)->eventfilter, blkmem) );
2139 
2140  /* set variable status and data */
2141  (*var)->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
2142 
2143  /* capture variable */
2144  SCIPvarCapture(*var);
2145 
2146  return SCIP_OKAY;
2147 }
2148 
2149 /** copies and captures a variable from source to target SCIP; an integer variable with bounds zero and one is
2150  * automatically converted into a binary variable; in case the variable data cannot be copied the variable is not
2151  * copied at all
2152  */
2154  SCIP_VAR** var, /**< pointer to store the target variable */
2155  BMS_BLKMEM* blkmem, /**< block memory */
2156  SCIP_SET* set, /**< global SCIP settings */
2157  SCIP_STAT* stat, /**< problem statistics */
2158  SCIP* sourcescip, /**< source SCIP data structure */
2159  SCIP_VAR* sourcevar, /**< source variable */
2160  SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of source variables corresponding
2161  * target variables */
2162  SCIP_HASHMAP* consmap, /**< a hashmap to store the mapping of source constraints to the corresponding
2163  * target constraints */
2164  SCIP_Bool global /**< should global or local bounds be used? */
2165  )
2166 {
2167  SCIP_VARDATA* targetdata;
2168  SCIP_RESULT result;
2169  SCIP_Real lb;
2170  SCIP_Real ub;
2171 
2172  assert(set != NULL);
2173  assert(blkmem != NULL);
2174  assert(stat != NULL);
2175  assert(sourcescip != NULL);
2176  assert(sourcevar != NULL);
2177  assert(var != NULL);
2178  assert(set->stage == SCIP_STAGE_PROBLEM);
2179  assert(varmap != NULL);
2180  assert(consmap != NULL);
2181 
2182  /** @todo copy hole lists */
2183  assert(global || SCIPvarGetHolelistLocal(sourcevar) == NULL);
2184  assert(!global || SCIPvarGetHolelistGlobal(sourcevar) == NULL);
2185 
2186  result = SCIP_DIDNOTRUN;
2187  targetdata = NULL;
2188 
2189  if( SCIPvarGetStatus(sourcevar) == SCIP_VARSTATUS_ORIGINAL )
2190  {
2191  lb = SCIPvarGetLbOriginal(sourcevar);
2192  ub = SCIPvarGetUbOriginal(sourcevar);
2193  }
2194  else
2195  {
2196  lb = global ? SCIPvarGetLbGlobal(sourcevar) : SCIPvarGetLbLocal(sourcevar);
2197  ub = global ? SCIPvarGetUbGlobal(sourcevar) : SCIPvarGetUbLocal(sourcevar);
2198  }
2199 
2200  /* creates and captures the variable in the target SCIP and initialize callback methods and variable data to NULL */
2201  SCIP_CALL( SCIPvarCreateOriginal(var, blkmem, set, stat, SCIPvarGetName(sourcevar),
2202  lb, ub, SCIPvarGetObj(sourcevar), SCIPvarGetType(sourcevar),
2203  SCIPvarIsInitial(sourcevar), SCIPvarIsRemovable(sourcevar),
2204  NULL, NULL, NULL, NULL, NULL) );
2205  assert(*var != NULL);
2206 
2207  /* directly copy donot(mult)aggr flag */
2208  (*var)->donotaggr = sourcevar->donotaggr;
2209  (*var)->donotmultaggr = sourcevar->donotmultaggr;
2210 
2211  /* insert variable into mapping between source SCIP and the target SCIP */
2212  assert(!SCIPhashmapExists(varmap, sourcevar));
2213  SCIP_CALL( SCIPhashmapInsert(varmap, sourcevar, *var) );
2214 
2215  /* in case there exists variable data and the variable data copy callback, try to copy variable data */
2216  if( sourcevar->vardata != NULL && sourcevar->varcopy != NULL )
2217  {
2218  SCIP_CALL( sourcevar->varcopy(set->scip, sourcescip, sourcevar, sourcevar->vardata,
2219  varmap, consmap, (*var), &targetdata, &result) );
2220 
2221  /* evaluate result */
2222  if( result != SCIP_DIDNOTRUN && result != SCIP_SUCCESS )
2223  {
2224  SCIPerrorMessage("variable data copying method returned invalid result <%d>\n", result);
2225  return SCIP_INVALIDRESULT;
2226  }
2227 
2228  assert(targetdata == NULL || result == SCIP_SUCCESS);
2229 
2230  /* if copying was successful, add the created variable data to the variable as well as all callback methods */
2231  if( result == SCIP_SUCCESS )
2232  {
2233  (*var)->varcopy = sourcevar->varcopy;
2234  (*var)->vardelorig = sourcevar->vardelorig;
2235  (*var)->vartrans = sourcevar->vartrans;
2236  (*var)->vardeltrans = sourcevar->vardeltrans;
2237  (*var)->vardata = targetdata;
2238  }
2239  }
2240 
2241  /* we initialize histories of the variables by copying the source variable-information */
2242  if( set->history_allowtransfer )
2243  {
2244  SCIPvarMergeHistories((*var), sourcevar, stat);
2245  }
2246 
2247  /* in case the copying was successfully, add the created variable data to the variable as well as all callback
2248  * methods
2249  */
2250  if( result == SCIP_SUCCESS )
2251  {
2252  (*var)->varcopy = sourcevar->varcopy;
2253  (*var)->vardelorig = sourcevar->vardelorig;
2254  (*var)->vartrans = sourcevar->vartrans;
2255  (*var)->vardeltrans = sourcevar->vardeltrans;
2256  (*var)->vardata = targetdata;
2257  }
2258 
2259  SCIPsetDebugMsg(set, "created copy <%s> of variable <%s>\n", SCIPvarGetName(*var), SCIPvarGetName(sourcevar));
2260 
2261  return SCIP_OKAY;
2262 }
2263 
2264 /** parse given string for a SCIP_Real bound */
2265 static
2267  SCIP_SET* set, /**< global SCIP settings */
2268  const char* str, /**< string to parse */
2269  SCIP_Real* value, /**< pointer to store the parsed value */
2270  char** endptr /**< pointer to store the final string position if successfully parsed */
2271  )
2272 {
2273  /* first check for infinity value */
2274  if( strncmp(str, "+inf", 4) == 0 )
2275  {
2276  *value = SCIPsetInfinity(set);
2277  (*endptr) = (char*)str + 4;
2278  }
2279  else if( strncmp(str, "-inf", 4) == 0 )
2280  {
2281  *value = -SCIPsetInfinity(set);
2282  (*endptr) = (char*)str + 4;
2283  }
2284  else
2285  {
2286  if( !SCIPstrToRealValue(str, value, endptr) )
2287  {
2288  SCIPerrorMessage("expected value: %s.\n", str);
2289  return SCIP_READERROR;
2290  }
2291  }
2292 
2293  return SCIP_OKAY;
2294 }
2295 
2296 /** parse the characters as bounds */
2297 static
2299  SCIP_SET* set, /**< global SCIP settings */
2300  const char* str, /**< string to parse */
2301  char* type, /**< bound type (global, local, or lazy) */
2302  SCIP_Real* lb, /**< pointer to store the lower bound */
2303  SCIP_Real* ub, /**< pointer to store the upper bound */
2304  char** endptr /**< pointer to store the final string position if successfully parsed (or NULL if an error occured) */
2305  )
2306 {
2307  char token[SCIP_MAXSTRLEN];
2308  char* tmpend;
2309 
2310  SCIPsetDebugMsg(set, "parsing bounds: '%s'\n", str);
2311 
2312  /* get bound type */
2313  SCIPstrCopySection(str, ' ', ' ', type, SCIP_MAXSTRLEN, endptr);
2314  if ( strncmp(type, "original", 8) != 0 && strncmp(type, "global", 6) != 0 && strncmp(type, "local", 5) != 0 && strncmp(type, "lazy", 4) != 0 )
2315  {
2316  SCIPsetDebugMsg(set, "unkown bound type <%s>\n", type);
2317  *endptr = NULL;
2318  return SCIP_OKAY;
2319  }
2320 
2321  SCIPsetDebugMsg(set, "parsed bound type <%s>\n", type);
2322 
2323  /* get lower bound */
2324  SCIPstrCopySection(str, '[', ',', token, SCIP_MAXSTRLEN, endptr);
2325  str = *endptr;
2326  SCIP_CALL( parseValue(set, token, lb, &tmpend) );
2327 
2328  /* get upper bound */
2329  SCIP_CALL( parseValue(set, str, ub, endptr) );
2330 
2331  SCIPsetDebugMsg(set, "parsed bounds: [%g,%g]\n", *lb, *ub);
2332 
2333  /* skip end of bounds */
2334  while ( **endptr != '\0' && (**endptr == ']' || **endptr == ',') )
2335  ++(*endptr);
2336 
2337  return SCIP_OKAY;
2338 }
2339 
2340 /** parses a given string for a variable informations */
2341 static
2343  SCIP_SET* set, /**< global SCIP settings */
2344  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2345  const char* str, /**< string to parse */
2346  char* name, /**< pointer to store the variable name */
2347  SCIP_Real* lb, /**< pointer to store the lower bound */
2348  SCIP_Real* ub, /**< pointer to store the upper bound */
2349  SCIP_Real* obj, /**< pointer to store the objective coefficient */
2350  SCIP_VARTYPE* vartype, /**< pointer to store the variable type */
2351  SCIP_Real* lazylb, /**< pointer to store if the lower bound is lazy */
2352  SCIP_Real* lazyub, /**< pointer to store if the upper bound is lazy */
2353  SCIP_Bool local, /**< should the local bound be applied */
2354  char** endptr, /**< pointer to store the final string position if successfully */
2355  SCIP_Bool* success /**< pointer store if the paring process was successful */
2356  )
2357 {
2358  SCIP_Real parsedlb;
2359  SCIP_Real parsedub;
2360  char token[SCIP_MAXSTRLEN];
2361  char* strptr;
2362  int i;
2363 
2364  assert(lb != NULL);
2365  assert(ub != NULL);
2366  assert(obj != NULL);
2367  assert(vartype != NULL);
2368  assert(lazylb != NULL);
2369  assert(lazyub != NULL);
2370  assert(success != NULL);
2371 
2372  (*success) = TRUE;
2373 
2374  /* copy variable type */
2375  SCIPstrCopySection(str, '[', ']', token, SCIP_MAXSTRLEN, endptr);
2376  assert(str != *endptr);
2377  SCIPsetDebugMsg(set, "parsed variable type <%s>\n", token);
2378 
2379  /* get variable type */
2380  if( strncmp(token, "binary", 3) == 0 )
2381  (*vartype) = SCIP_VARTYPE_BINARY;
2382  else if( strncmp(token, "integer", 3) == 0 )
2383  (*vartype) = SCIP_VARTYPE_INTEGER;
2384  else if( strncmp(token, "implicit", 3) == 0 )
2385  (*vartype) = SCIP_VARTYPE_IMPLINT;
2386  else if( strncmp(token, "continuous", 3) == 0 )
2387  (*vartype) = SCIP_VARTYPE_CONTINUOUS;
2388  else
2389  {
2390  SCIPmessagePrintWarning(messagehdlr, "unknown variable type\n");
2391  (*success) = FALSE;
2392  return SCIP_OKAY;
2393  }
2394 
2395  /* move string pointer behind variable type */
2396  str = *endptr;
2397 
2398  /* get variable name */
2399  SCIPstrCopySection(str, '<', '>', name, SCIP_MAXSTRLEN, endptr);
2400  assert(endptr != NULL);
2401  SCIPsetDebugMsg(set, "parsed variable name <%s>\n", name);
2402 
2403  /* move string pointer behind variable name */
2404  str = *endptr;
2405 
2406  /* cut out objective coefficient */
2407  SCIPstrCopySection(str, '=', ',', token, SCIP_MAXSTRLEN, endptr);
2408 
2409  /* move string pointer behind objective coefficient */
2410  str = *endptr;
2411 
2412  /* get objective coefficient */
2413  if( !SCIPstrToRealValue(token, obj, endptr) )
2414  {
2415  *endptr = NULL;
2416  return SCIP_READERROR;
2417  }
2418 
2419  SCIPsetDebugMsg(set, "parsed objective coefficient <%g>\n", *obj);
2420 
2421  /* parse global/original bounds */
2422  SCIP_CALL( parseBounds(set, str, token, lb, ub, endptr) );
2423  if ( *endptr == NULL )
2424  {
2425  SCIPerrorMessage("Expected bound type: %s.\n", token);
2426  return SCIP_READERROR;
2427  }
2428  assert(strncmp(token, "global", 6) == 0 || strncmp(token, "original", 8) == 0);
2429 
2430  /* initialize the lazy bound */
2431  *lazylb = -SCIPsetInfinity(set);
2432  *lazyub = SCIPsetInfinity(set);
2433 
2434  /* store pointer */
2435  strptr = *endptr;
2436 
2437  /* possibly parse optional local and lazy bounds */
2438  for( i = 0; i < 2 && *endptr != NULL && **endptr != '\0'; ++i )
2439  {
2440  /* start after previous bounds */
2441  strptr = *endptr;
2442 
2443  /* parse global bounds */
2444  SCIP_CALL( parseBounds(set, strptr, token, &parsedlb, &parsedub, endptr) );
2445 
2446  /* stop if parsing of bounds failed */
2447  if( *endptr == NULL )
2448  break;
2449 
2450  if( strncmp(token, "local", 5) == 0 && local )
2451  {
2452  *lb = parsedlb;
2453  *ub = parsedub;
2454  }
2455  else if( strncmp(token, "lazy", 4) == 0 )
2456  {
2457  *lazylb = parsedlb;
2458  *lazyub = parsedub;
2459  }
2460  }
2461 
2462  /* restore pointer */
2463  if ( *endptr == NULL )
2464  *endptr = strptr;
2465 
2466  /* check bounds for binary variables */
2467  if ( (*vartype) == SCIP_VARTYPE_BINARY )
2468  {
2469  if ( SCIPsetIsLT(set, *lb, 0.0) || SCIPsetIsGT(set, *ub, 1.0) )
2470  {
2471  SCIPerrorMessage("Parsed invalid bounds for binary variable <%s>: [%f, %f].\n", name, *lb, *ub);
2472  return SCIP_READERROR;
2473  }
2474  if ( !SCIPsetIsInfinity(set, -(*lazylb)) && !SCIPsetIsInfinity(set, *lazyub) &&
2475  ( SCIPsetIsLT(set, *lazylb, 0.0) || SCIPsetIsGT(set, *lazyub, 1.0) ) )
2476  {
2477  SCIPerrorMessage("Parsed invalid lazy bounds for binary variable <%s>: [%f, %f].\n", name, *lazylb, *lazyub);
2478  return SCIP_READERROR;
2479  }
2480  }
2481 
2482  return SCIP_OKAY;
2483 }
2484 
2485 /** parses variable information (in cip format) out of a string; if the parsing process was successful an original
2486  * variable is created and captured; if variable is of integral type, fractional bounds are automatically rounded; an
2487  * integer variable with bounds zero and one is automatically converted into a binary variable
2488  */
2490  SCIP_VAR** var, /**< pointer to variable data */
2491  BMS_BLKMEM* blkmem, /**< block memory */
2492  SCIP_SET* set, /**< global SCIP settings */
2493  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2494  SCIP_STAT* stat, /**< problem statistics */
2495  const char* str, /**< string to parse */
2496  SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2497  SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2498  SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2499  SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable */
2500  SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data */
2501  SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable */
2502  SCIP_VARDATA* vardata, /**< user data for this specific variable */
2503  char** endptr, /**< pointer to store the final string position if successfully */
2504  SCIP_Bool* success /**< pointer store if the paring process was successful */
2505  )
2506 {
2507  char name[SCIP_MAXSTRLEN];
2508  SCIP_Real lb;
2509  SCIP_Real ub;
2510  SCIP_Real obj;
2511  SCIP_VARTYPE vartype;
2512  SCIP_Real lazylb;
2513  SCIP_Real lazyub;
2514 
2515  assert(var != NULL);
2516  assert(blkmem != NULL);
2517  assert(stat != NULL);
2518  assert(endptr != NULL);
2519  assert(success != NULL);
2520 
2521  /* parse string in cip format for variable information */
2522  SCIP_CALL( varParse(set, messagehdlr, str, name, &lb, &ub, &obj, &vartype, &lazylb, &lazyub, FALSE, endptr, success) );
2523 
2524  if( *success ) /*lint !e774*/
2525  {
2526  /* create variable */
2527  SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2528  varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2529 
2530  /* set variable status and data */
2531  (*var)->varstatus = SCIP_VARSTATUS_ORIGINAL; /*lint !e641*/
2532  (*var)->data.original.origdom.holelist = NULL;
2533  (*var)->data.original.origdom.lb = lb;
2534  (*var)->data.original.origdom.ub = ub;
2535  (*var)->data.original.transvar = NULL;
2536 
2537  /* set lazy status of variable bounds */
2538  (*var)->lazylb = lazylb;
2539  (*var)->lazyub = lazyub;
2540 
2541  /* capture variable */
2542  SCIPvarCapture(*var);
2543  }
2544 
2545  return SCIP_OKAY;
2546 }
2547 
2548 /** parses variable information (in cip format) out of a string; if the parsing process was successful a loose variable
2549  * belonging to the transformed problem is created and captured; if variable is of integral type, fractional bounds are
2550  * automatically rounded; an integer variable with bounds zero and one is automatically converted into a binary
2551  * variable
2552  */
2554  SCIP_VAR** var, /**< pointer to variable data */
2555  BMS_BLKMEM* blkmem, /**< block memory */
2556  SCIP_SET* set, /**< global SCIP settings */
2557  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2558  SCIP_STAT* stat, /**< problem statistics */
2559  const char* str, /**< string to parse */
2560  SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2561  SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2562  SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2563  SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable */
2564  SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data */
2565  SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable */
2566  SCIP_VARDATA* vardata, /**< user data for this specific variable */
2567  char** endptr, /**< pointer to store the final string position if successfully */
2568  SCIP_Bool* success /**< pointer store if the paring process was successful */
2569  )
2570 {
2571  char name[SCIP_MAXSTRLEN];
2572  SCIP_Real lb;
2573  SCIP_Real ub;
2574  SCIP_Real obj;
2575  SCIP_VARTYPE vartype;
2576  SCIP_Real lazylb;
2577  SCIP_Real lazyub;
2578 
2579  assert(var != NULL);
2580  assert(blkmem != NULL);
2581  assert(endptr != NULL);
2582  assert(success != NULL);
2583 
2584  /* parse string in cip format for variable information */
2585  SCIP_CALL( varParse(set, messagehdlr, str, name, &lb, &ub, &obj, &vartype, &lazylb, &lazyub, TRUE, endptr, success) );
2586 
2587  if( *success ) /*lint !e774*/
2588  {
2589  /* create variable */
2590  SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2591  varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2592 
2593  /* create event filter for transformed variable */
2594  SCIP_CALL( SCIPeventfilterCreate(&(*var)->eventfilter, blkmem) );
2595 
2596  /* set variable status and data */
2597  (*var)->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
2598 
2599  /* set lazy status of variable bounds */
2600  (*var)->lazylb = lazylb;
2601  (*var)->lazyub = lazyub;
2602 
2603  /* capture variable */
2604  SCIPvarCapture(*var);
2605  }
2606 
2607  return SCIP_OKAY;
2608 }
2609 
2610 /** ensures, that parentvars array of var can store at least num entries */
2611 static
2613  SCIP_VAR* var, /**< problem variable */
2614  BMS_BLKMEM* blkmem, /**< block memory */
2615  SCIP_SET* set, /**< global SCIP settings */
2616  int num /**< minimum number of entries to store */
2617  )
2618 {
2619  assert(var->nparentvars <= var->parentvarssize);
2620 
2621  if( num > var->parentvarssize )
2622  {
2623  int newsize;
2624 
2625  newsize = SCIPsetCalcMemGrowSize(set, num);
2626  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->parentvars, var->parentvarssize, newsize) );
2627  var->parentvarssize = newsize;
2628  }
2629  assert(num <= var->parentvarssize);
2630 
2631  return SCIP_OKAY;
2632 }
2633 
2634 /** adds variable to parent list of a variable and captures parent variable */
2635 static
2637  SCIP_VAR* var, /**< variable to add parent to */
2638  BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
2639  SCIP_SET* set, /**< global SCIP settings */
2640  SCIP_VAR* parentvar /**< parent variable to add */
2641  )
2642 {
2643  assert(var != NULL);
2644  assert(parentvar != NULL);
2645 
2646  /* the direct original counterpart must be stored as first parent */
2647  assert(var->nparentvars == 0 || SCIPvarGetStatus(parentvar) != SCIP_VARSTATUS_ORIGINAL);
2648 
2649  SCIPsetDebugMsg(set, "adding parent <%s>[%p] to variable <%s>[%p] in slot %d\n",
2650  parentvar->name, (void*)parentvar, var->name, (void*)var, var->nparentvars);
2651 
2652  SCIP_CALL( varEnsureParentvarsSize(var, blkmem, set, var->nparentvars+1) );
2653 
2654  var->parentvars[var->nparentvars] = parentvar;
2655  var->nparentvars++;
2656 
2657  SCIPvarCapture(parentvar);
2658 
2659  return SCIP_OKAY;
2660 }
2661 
2662 /** deletes and releases all variables from the parent list of a variable, frees the memory of parents array */
2663 static
2665  SCIP_VAR** var, /**< pointer to variable */
2666  BMS_BLKMEM* blkmem, /**< block memory */
2667  SCIP_SET* set, /**< global SCIP settings */
2668  SCIP_EVENTQUEUE* eventqueue, /**< event queue (or NULL, if it's an original variable) */
2669  SCIP_LP* lp /**< current LP data (or NULL, if it's an original variable) */
2670  )
2671 {
2672  SCIP_VAR* parentvar;
2673  int i;
2674 
2675  SCIPsetDebugMsg(set, "free parents of <%s>\n", (*var)->name);
2676 
2677  /* release the parent variables and remove the link from the parent variable to the child */
2678  for( i = 0; i < (*var)->nparentvars; ++i )
2679  {
2680  assert((*var)->parentvars != NULL);
2681  parentvar = (*var)->parentvars[i];
2682  assert(parentvar != NULL);
2683 
2684  switch( SCIPvarGetStatus(parentvar) )
2685  {
2687  assert(parentvar->data.original.transvar == *var);
2688  assert(&parentvar->data.original.transvar != var);
2689  parentvar->data.original.transvar = NULL;
2690  break;
2691 
2693  assert(parentvar->data.aggregate.var == *var);
2694  assert(&parentvar->data.aggregate.var != var);
2695  parentvar->data.aggregate.var = NULL;
2696  break;
2697 
2698 #if 0
2699  /* The following code is unclear: should the current variable be removed from its parents? */
2701  assert(parentvar->data.multaggr.vars != NULL);
2702  for( v = 0; v < parentvar->data.multaggr.nvars && parentvar->data.multaggr.vars[v] != *var; ++v )
2703  {}
2704  assert(v < parentvar->data.multaggr.nvars && parentvar->data.multaggr.vars[v] == *var);
2705  if( v < parentvar->data.multaggr.nvars-1 )
2706  {
2707  parentvar->data.multaggr.vars[v] = parentvar->data.multaggr.vars[parentvar->data.multaggr.nvars-1];
2708  parentvar->data.multaggr.scalars[v] = parentvar->data.multaggr.scalars[parentvar->data.multaggr.nvars-1];
2709  }
2710  parentvar->data.multaggr.nvars--;
2711  break;
2712 #endif
2713 
2715  assert(parentvar->negatedvar == *var);
2716  assert((*var)->negatedvar == parentvar);
2717  parentvar->negatedvar = NULL;
2718  (*var)->negatedvar = NULL;
2719  break;
2720 
2721  default:
2722  SCIPerrorMessage("parent variable is neither ORIGINAL, AGGREGATED nor NEGATED\n");
2723  return SCIP_INVALIDDATA;
2724  } /*lint !e788*/
2725 
2726  SCIP_CALL( SCIPvarRelease(&(*var)->parentvars[i], blkmem, set, eventqueue, lp) );
2727  }
2728 
2729  /* free parentvars array */
2730  BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->parentvars, (*var)->parentvarssize);
2731 
2732  return SCIP_OKAY;
2733 }
2734 
2735 /** frees a variable */
2736 static
2738  SCIP_VAR** var, /**< pointer to variable */
2739  BMS_BLKMEM* blkmem, /**< block memory */
2740  SCIP_SET* set, /**< global SCIP settings */
2741  SCIP_EVENTQUEUE* eventqueue, /**< event queue (may be NULL, if it's not a column variable) */
2742  SCIP_LP* lp /**< current LP data (may be NULL, if it's not a column variable) */
2743  )
2744 {
2745  assert(var != NULL);
2746  assert(*var != NULL);
2747  assert(SCIPvarGetStatus(*var) != SCIP_VARSTATUS_COLUMN || &(*var)->data.col->var != var);
2748  assert((*var)->nuses == 0);
2749  assert((*var)->probindex == -1);
2750  assert((*var)->nlocksup[SCIP_LOCKTYPE_MODEL] == 0);
2751  assert((*var)->nlocksdown[SCIP_LOCKTYPE_MODEL] == 0);
2752 
2753  SCIPsetDebugMsg(set, "free variable <%s> with status=%d\n", (*var)->name, SCIPvarGetStatus(*var));
2754 
2755  switch( SCIPvarGetStatus(*var) )
2756  {
2758  assert((*var)->data.original.transvar == NULL); /* cannot free variable, if transformed variable is still existing */
2759  holelistFree(&(*var)->data.original.origdom.holelist, blkmem);
2760  assert((*var)->data.original.origdom.holelist == NULL);
2761  break;
2762  case SCIP_VARSTATUS_LOOSE:
2763  break;
2764  case SCIP_VARSTATUS_COLUMN:
2765  SCIP_CALL( SCIPcolFree(&(*var)->data.col, blkmem, set, eventqueue, lp) ); /* free corresponding LP column */
2766  break;
2767  case SCIP_VARSTATUS_FIXED:
2769  break;
2771  BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.vars, (*var)->data.multaggr.varssize);
2772  BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.scalars, (*var)->data.multaggr.varssize);
2773  break;
2775  break;
2776  default:
2777  SCIPerrorMessage("unknown variable status\n");
2778  return SCIP_INVALIDDATA;
2779  }
2780 
2781  /* release all parent variables and free the parentvars array */
2782  SCIP_CALL( varFreeParents(var, blkmem, set, eventqueue, lp) );
2783 
2784  /* free user data */
2786  {
2787  if( (*var)->vardelorig != NULL )
2788  {
2789  SCIP_CALL( (*var)->vardelorig(set->scip, *var, &(*var)->vardata) );
2790  }
2791  }
2792  else
2793  {
2794  if( (*var)->vardeltrans != NULL )
2795  {
2796  SCIP_CALL( (*var)->vardeltrans(set->scip, *var, &(*var)->vardata) );
2797  }
2798  }
2799 
2800  /* free event filter */
2801  if( (*var)->eventfilter != NULL )
2802  {
2803  SCIP_CALL( SCIPeventfilterFree(&(*var)->eventfilter, blkmem, set) );
2804  }
2805  assert((*var)->eventfilter == NULL);
2806 
2807  /* free hole lists */
2808  holelistFree(&(*var)->glbdom.holelist, blkmem);
2809  holelistFree(&(*var)->locdom.holelist, blkmem);
2810  assert((*var)->glbdom.holelist == NULL);
2811  assert((*var)->locdom.holelist == NULL);
2812 
2813  /* free variable bounds data structures */
2814  SCIPvboundsFree(&(*var)->vlbs, blkmem);
2815  SCIPvboundsFree(&(*var)->vubs, blkmem);
2816 
2817  /* free implications data structures */
2818  SCIPimplicsFree(&(*var)->implics, blkmem);
2819 
2820  /* free clique list data structures */
2821  SCIPcliquelistFree(&(*var)->cliquelist, blkmem);
2822 
2823  /* free bound change information arrays */
2824  BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->lbchginfos, (*var)->lbchginfossize);
2825  BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->ubchginfos, (*var)->ubchginfossize);
2826 
2827  /* free branching and inference history entries */
2828  SCIPhistoryFree(&(*var)->history, blkmem);
2829  SCIPhistoryFree(&(*var)->historycrun, blkmem);
2830  SCIPvaluehistoryFree(&(*var)->valuehistory, blkmem);
2831 
2832  /* free variable data structure */
2833  BMSfreeBlockMemoryArray(blkmem, &(*var)->name, strlen((*var)->name)+1);
2834  BMSfreeBlockMemory(blkmem, var);
2835 
2836  return SCIP_OKAY;
2837 }
2838 
2839 /** increases usage counter of variable */
2840 void SCIPvarCapture(
2841  SCIP_VAR* var /**< variable */
2842  )
2843 {
2844  assert(var != NULL);
2845  assert(var->nuses >= 0);
2846 
2847  SCIPdebugMessage("capture variable <%s> with nuses=%d\n", var->name, var->nuses);
2848  var->nuses++;
2849 
2850 #ifdef DEBUGUSES_VARNAME
2851  if( strcmp(var->name, DEBUGUSES_VARNAME) == 0
2852 #ifdef DEBUGUSES_PROBNAME
2853  && ((var->scip->transprob != NULL && strcmp(SCIPprobGetName(var->scip->transprob), DEBUGUSES_PROBNAME) == 0) ||
2854  strcmp(SCIPprobGetName(var->scip->origprob), DEBUGUSES_PROBNAME) == 0)
2855 #endif
2856  )
2857  {
2858  printf("Captured variable " DEBUGUSES_VARNAME " in SCIP %p, now %d uses; captured at\n", (void*)var->scip, var->nuses);
2859  print_backtrace();
2860  }
2861 #endif
2862 }
2863 
2864 /** decreases usage counter of variable, and frees memory if necessary */
2866  SCIP_VAR** var, /**< pointer to variable */
2867  BMS_BLKMEM* blkmem, /**< block memory */
2868  SCIP_SET* set, /**< global SCIP settings */
2869  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2870  SCIP_LP* lp /**< current LP data (or NULL, if it's an original variable) */
2871  )
2872 {
2873  assert(var != NULL);
2874  assert(*var != NULL);
2875  assert((*var)->nuses >= 1);
2876  assert(blkmem != NULL);
2877  assert((*var)->scip == set->scip);
2878 
2879  SCIPsetDebugMsg(set, "release variable <%s> with nuses=%d\n", (*var)->name, (*var)->nuses);
2880  (*var)->nuses--;
2881 
2882 #ifdef DEBUGUSES_VARNAME
2883  if( strcmp((*var)->name, DEBUGUSES_VARNAME) == 0
2884 #ifdef DEBUGUSES_PROBNAME
2885  && (((*var)->scip->transprob != NULL && strcmp(SCIPprobGetName((*var)->scip->transprob), DEBUGUSES_PROBNAME) == 0) ||
2886  strcmp(SCIPprobGetName((*var)->scip->origprob), DEBUGUSES_PROBNAME) == 0)
2887 #endif
2888  )
2889  {
2890  printf("Released variable " DEBUGUSES_VARNAME " in SCIP %p, now %d uses; released at\n", (void*)(*var)->scip, (*var)->nuses);
2891  print_backtrace();
2892  }
2893 #endif
2894 
2895  if( (*var)->nuses == 0 )
2896  {
2897  SCIP_CALL( varFree(var, blkmem, set, eventqueue, lp) );
2898  }
2899 
2900  *var = NULL;
2901 
2902  return SCIP_OKAY;
2903 }
2904 
2905 /** change variable name */
2907  SCIP_VAR* var, /**< problem variable */
2908  BMS_BLKMEM* blkmem, /**< block memory */
2909  const char* name /**< name of variable */
2910  )
2911 {
2912  assert(name != NULL);
2913 
2914  /* remove old variable name */
2915  BMSfreeBlockMemoryArray(blkmem, &var->name, strlen(var->name)+1);
2916 
2917  /* set new variable name */
2918  SCIP_CALL( varSetName(var, blkmem, NULL, name) );
2919 
2920  return SCIP_OKAY;
2921 }
2922 
2923 /** initializes variable data structure for solving */
2924 void SCIPvarInitSolve(
2925  SCIP_VAR* var /**< problem variable */
2926  )
2927 {
2928  assert(var != NULL);
2929 
2931  var->conflictlbcount = 0;
2932  var->conflictubcount = 0;
2933 }
2934 
2935 /** outputs the given bounds into the file stream */
2936 static
2937 void printBounds(
2938  SCIP_SET* set, /**< global SCIP settings */
2939  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2940  FILE* file, /**< output file (or NULL for standard output) */
2941  SCIP_Real lb, /**< lower bound */
2942  SCIP_Real ub, /**< upper bound */
2943  const char* name /**< bound type name */
2944  )
2945 {
2946  assert(set != NULL);
2947 
2948  SCIPmessageFPrintInfo(messagehdlr, file, ", %s=", name);
2949  if( SCIPsetIsInfinity(set, lb) )
2950  SCIPmessageFPrintInfo(messagehdlr, file, "[+inf,");
2951  else if( SCIPsetIsInfinity(set, -lb) )
2952  SCIPmessageFPrintInfo(messagehdlr, file, "[-inf,");
2953  else
2954  SCIPmessageFPrintInfo(messagehdlr, file, "[%.15g,", lb);
2955  if( SCIPsetIsInfinity(set, ub) )
2956  SCIPmessageFPrintInfo(messagehdlr, file, "+inf]");
2957  else if( SCIPsetIsInfinity(set, -ub) )
2958  SCIPmessageFPrintInfo(messagehdlr, file, "-inf]");
2959  else
2960  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g]", ub);
2961 }
2962 
2963 /** prints hole list to file stream */
2964 static
2965 void printHolelist(
2966  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2967  FILE* file, /**< output file (or NULL for standard output) */
2968  SCIP_HOLELIST* holelist, /**< hole list pointer to hole of interest */
2969  const char* name /**< hole type name */
2970  )
2971 { /*lint --e{715}*/
2972  SCIP_Real left;
2973  SCIP_Real right;
2974 
2975  if( holelist == NULL )
2976  return;
2977 
2978  left = SCIPholelistGetLeft(holelist);
2979  right = SCIPholelistGetRight(holelist);
2980 
2981  /* display first hole */
2982  SCIPmessageFPrintInfo(messagehdlr, file, ", %s=(%g,%g)", name, left, right);
2983  holelist = SCIPholelistGetNext(holelist);
2984 
2985  while(holelist != NULL )
2986  {
2987  left = SCIPholelistGetLeft(holelist);
2988  right = SCIPholelistGetRight(holelist);
2989 
2990  /* display hole */
2991  SCIPmessageFPrintInfo(messagehdlr, file, "(%g,%g)", left, right);
2992 
2993  /* get next hole */
2994  holelist = SCIPholelistGetNext(holelist);
2995  }
2996 }
2997 
2998 /** outputs variable information into file stream */
3000  SCIP_VAR* var, /**< problem variable */
3001  SCIP_SET* set, /**< global SCIP settings */
3002  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
3003  FILE* file /**< output file (or NULL for standard output) */
3004  )
3005 {
3006  SCIP_HOLELIST* holelist;
3007  SCIP_Real lb;
3008  SCIP_Real ub;
3009  int i;
3010 
3011  assert(var != NULL);
3012  assert(var->scip == set->scip);
3013 
3014  /* type of variable */
3015  switch( SCIPvarGetType(var) )
3016  {
3017  case SCIP_VARTYPE_BINARY:
3018  SCIPmessageFPrintInfo(messagehdlr, file, " [binary]");
3019  break;
3020  case SCIP_VARTYPE_INTEGER:
3021  SCIPmessageFPrintInfo(messagehdlr, file, " [integer]");
3022  break;
3023  case SCIP_VARTYPE_IMPLINT:
3024  SCIPmessageFPrintInfo(messagehdlr, file, " [implicit]");
3025  break;
3027  SCIPmessageFPrintInfo(messagehdlr, file, " [continuous]");
3028  break;
3029  default:
3030  SCIPerrorMessage("unknown variable type\n");
3031  SCIPABORT();
3032  return SCIP_ERROR; /*lint !e527*/
3033  }
3034 
3035  /* name */
3036  SCIPmessageFPrintInfo(messagehdlr, file, " <%s>:", var->name);
3037 
3038  /* objective value */
3039  SCIPmessageFPrintInfo(messagehdlr, file, " obj=%.15g", var->obj);
3040 
3041  /* bounds (global bounds for transformed variables, original bounds for original variables) */
3042  if( !SCIPvarIsTransformed(var) )
3043  {
3044  /* output original bound */
3045  lb = SCIPvarGetLbOriginal(var);
3046  ub = SCIPvarGetUbOriginal(var);
3047  printBounds(set, messagehdlr, file, lb, ub, "original bounds");
3048 
3049  /* output lazy bound */
3050  lb = SCIPvarGetLbLazy(var);
3051  ub = SCIPvarGetUbLazy(var);
3052 
3053  /* only display the lazy bounds if they are different from [-infinity,infinity] */
3054  if( !SCIPsetIsInfinity(set, -lb) || !SCIPsetIsInfinity(set, ub) )
3055  printBounds(set, messagehdlr, file, lb, ub, "lazy bounds");
3056 
3057  holelist = SCIPvarGetHolelistOriginal(var);
3058  printHolelist(messagehdlr, file, holelist, "original holes");
3059  }
3060  else
3061  {
3062  /* output global bound */
3063  lb = SCIPvarGetLbGlobal(var);
3064  ub = SCIPvarGetUbGlobal(var);
3065  printBounds(set, messagehdlr, file, lb, ub, "global bounds");
3066 
3067  /* output local bound */
3068  lb = SCIPvarGetLbLocal(var);
3069  ub = SCIPvarGetUbLocal(var);
3070  printBounds(set, messagehdlr, file, lb, ub, "local bounds");
3071 
3072  /* output lazy bound */
3073  lb = SCIPvarGetLbLazy(var);
3074  ub = SCIPvarGetUbLazy(var);
3075 
3076  /* only display the lazy bounds if they are different from [-infinity,infinity] */
3077  if( !SCIPsetIsInfinity(set, -lb) || !SCIPsetIsInfinity(set, ub) )
3078  printBounds(set, messagehdlr, file, lb, ub, "lazy bounds");
3079 
3080  /* global hole list */
3081  holelist = SCIPvarGetHolelistGlobal(var);
3082  printHolelist(messagehdlr, file, holelist, "global holes");
3083 
3084  /* local hole list */
3085  holelist = SCIPvarGetHolelistLocal(var);
3086  printHolelist(messagehdlr, file, holelist, "local holes");
3087  }
3088 
3089  /* fixings and aggregations */
3090  switch( SCIPvarGetStatus(var) )
3091  {
3093  case SCIP_VARSTATUS_LOOSE:
3094  case SCIP_VARSTATUS_COLUMN:
3095  break;
3096 
3097  case SCIP_VARSTATUS_FIXED:
3098  SCIPmessageFPrintInfo(messagehdlr, file, ", fixed:");
3099  if( SCIPsetIsInfinity(set, var->glbdom.lb) )
3100  SCIPmessageFPrintInfo(messagehdlr, file, "+inf");
3101  else if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
3102  SCIPmessageFPrintInfo(messagehdlr, file, "-inf");
3103  else
3104  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", var->glbdom.lb);
3105  break;
3106 
3108  SCIPmessageFPrintInfo(messagehdlr, file, ", aggregated:");
3109  if( !SCIPsetIsZero(set, var->data.aggregate.constant) )
3110  SCIPmessageFPrintInfo(messagehdlr, file, " %.15g", var->data.aggregate.constant);
3111  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g<%s>", var->data.aggregate.scalar, SCIPvarGetName(var->data.aggregate.var));
3112  break;
3113 
3115  SCIPmessageFPrintInfo(messagehdlr, file, ", aggregated:");
3116  if( var->data.multaggr.nvars == 0 || !SCIPsetIsZero(set, var->data.multaggr.constant) )
3117  SCIPmessageFPrintInfo(messagehdlr, file, " %.15g", var->data.multaggr.constant);
3118  for( i = 0; i < var->data.multaggr.nvars; ++i )
3119  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g<%s>", var->data.multaggr.scalars[i], SCIPvarGetName(var->data.multaggr.vars[i]));
3120  break;
3121 
3123  SCIPmessageFPrintInfo(messagehdlr, file, ", negated: %.15g - <%s>", var->data.negate.constant, SCIPvarGetName(var->negatedvar));
3124  break;
3125 
3126  default:
3127  SCIPerrorMessage("unknown variable status\n");
3128  SCIPABORT();
3129  return SCIP_ERROR; /*lint !e527*/
3130  }
3131 
3132  SCIPmessageFPrintInfo(messagehdlr, file, "\n");
3133 
3134  return SCIP_OKAY;
3135 }
3136 
3137 /** issues a VARUNLOCKED event on the given variable */
3138 static
3140  SCIP_VAR* var, /**< problem variable to change */
3141  BMS_BLKMEM* blkmem, /**< block memory */
3142  SCIP_SET* set, /**< global SCIP settings */
3143  SCIP_EVENTQUEUE* eventqueue /**< event queue */
3144  )
3145 {
3146  SCIP_EVENT* event;
3147 
3148  assert(var != NULL);
3149  assert(var->nlocksdown[SCIP_LOCKTYPE_MODEL] <= 1 && var->nlocksup[SCIP_LOCKTYPE_MODEL] <= 1);
3150  assert(var->scip == set->scip);
3151 
3152  /* issue VARUNLOCKED event on variable */
3153  SCIP_CALL( SCIPeventCreateVarUnlocked(&event, blkmem, var) );
3154  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
3155 
3156  return SCIP_OKAY;
3157 }
3158 
3159 /** modifies lock numbers for rounding */
3161  SCIP_VAR* var, /**< problem variable */
3162  BMS_BLKMEM* blkmem, /**< block memory */
3163  SCIP_SET* set, /**< global SCIP settings */
3164  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3165  SCIP_LOCKTYPE locktype, /**< type of the variable locks */
3166  int addnlocksdown, /**< increase in number of rounding down locks */
3167  int addnlocksup /**< increase in number of rounding up locks */
3168  )
3169 {
3170  SCIP_VAR* lockvar;
3171 
3172  assert(var != NULL);
3173  assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/
3174  assert(var->nlocksup[locktype] >= 0);
3175  assert(var->nlocksdown[locktype] >= 0);
3176  assert(var->scip == set->scip);
3177 
3178  if( addnlocksdown == 0 && addnlocksup == 0 )
3179  return SCIP_OKAY;
3180 
3181 #ifdef SCIP_DEBUG
3182  SCIPsetDebugMsg(set, "add rounding locks %d/%d to variable <%s> (locks=%d/%d, type=%u)\n",
3183  addnlocksdown, addnlocksup, var->name, var->nlocksdown[locktype], var->nlocksup[locktype], locktype);
3184 #endif
3185 
3186  lockvar = var;
3187 
3188  while( TRUE ) /*lint !e716 */
3189  {
3190  assert(lockvar != NULL);
3191 
3192  switch( SCIPvarGetStatus(lockvar) )
3193  {
3195  if( lockvar->data.original.transvar != NULL )
3196  {
3197  lockvar = lockvar->data.original.transvar;
3198  break;
3199  }
3200  else
3201  {
3202  lockvar->nlocksdown[locktype] += addnlocksdown;
3203  lockvar->nlocksup[locktype] += addnlocksup;
3204 
3205  assert(lockvar->nlocksdown[locktype] >= 0);
3206  assert(lockvar->nlocksup[locktype] >= 0);
3207 
3208  return SCIP_OKAY;
3209  }
3210  case SCIP_VARSTATUS_LOOSE:
3211  case SCIP_VARSTATUS_COLUMN:
3212  case SCIP_VARSTATUS_FIXED:
3213  lockvar->nlocksdown[locktype] += addnlocksdown;
3214  lockvar->nlocksup[locktype] += addnlocksup;
3215 
3216  assert(lockvar->nlocksdown[locktype] >= 0);
3217  assert(lockvar->nlocksup[locktype] >= 0);
3218 
3219  if( locktype == SCIP_LOCKTYPE_MODEL && lockvar->nlocksdown[locktype] <= 1
3220  && lockvar->nlocksup[locktype] <= 1 )
3221  {
3222  SCIP_CALL( varEventVarUnlocked(lockvar, blkmem, set, eventqueue) );
3223  }
3224 
3225  return SCIP_OKAY;
3227  assert(!lockvar->donotaggr);
3228 
3229  if( lockvar->data.aggregate.scalar < 0.0 )
3230  {
3231  int tmp = addnlocksup;
3232 
3233  addnlocksup = addnlocksdown;
3234  addnlocksdown = tmp;
3235  }
3236 
3237  lockvar = lockvar->data.aggregate.var;
3238  break;
3240  {
3241  int v;
3242 
3243  assert(!lockvar->donotmultaggr);
3244 
3245  lockvar->nlocksdown[locktype] += addnlocksdown;
3246  lockvar->nlocksup[locktype] += addnlocksup;
3247 
3248  assert(lockvar->nlocksdown[locktype] >= 0);
3249  assert(lockvar->nlocksup[locktype] >= 0);
3250 
3251  for( v = lockvar->data.multaggr.nvars - 1; v >= 0; --v )
3252  {
3253  if( lockvar->data.multaggr.scalars[v] > 0.0 )
3254  {
3255  SCIP_CALL( SCIPvarAddLocks(lockvar->data.multaggr.vars[v], blkmem, set, eventqueue, locktype, addnlocksdown,
3256  addnlocksup) );
3257  }
3258  else
3259  {
3260  SCIP_CALL( SCIPvarAddLocks(lockvar->data.multaggr.vars[v], blkmem, set, eventqueue, locktype, addnlocksup,
3261  addnlocksdown) );
3262  }
3263  }
3264  return SCIP_OKAY;
3265  }
3267  {
3268  int tmp = addnlocksup;
3269 
3270  assert(lockvar->negatedvar != NULL);
3271  assert(SCIPvarGetStatus(lockvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
3272  assert(lockvar->negatedvar->negatedvar == lockvar);
3273 
3274  addnlocksup = addnlocksdown;
3275  addnlocksdown = tmp;
3276 
3277  lockvar = lockvar->negatedvar;
3278  break;
3279  }
3280  default:
3281  SCIPerrorMessage("unknown variable status\n");
3282  return SCIP_INVALIDDATA;
3283  }
3284  }
3285 }
3286 
3287 /** gets number of locks for rounding down of a special type */
3289  SCIP_VAR* var, /**< problem variable */
3290  SCIP_LOCKTYPE locktype /**< type of variable locks */
3291  )
3292 {
3293  int nlocks;
3294  int i;
3295 
3296  assert(var != NULL);
3297  assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/
3298  assert(var->nlocksdown[locktype] >= 0);
3299 
3300  switch( SCIPvarGetStatus(var) )
3301  {
3303  if( var->data.original.transvar != NULL )
3304  return SCIPvarGetNLocksDownType(var->data.original.transvar, locktype);
3305  else
3306  return var->nlocksdown[locktype];
3307 
3308  case SCIP_VARSTATUS_LOOSE:
3309  case SCIP_VARSTATUS_COLUMN:
3310  case SCIP_VARSTATUS_FIXED:
3311  return var->nlocksdown[locktype];
3312 
3314  assert(!var->donotaggr);
3315  if( var->data.aggregate.scalar > 0.0 )
3316  return SCIPvarGetNLocksDownType(var->data.aggregate.var, locktype);
3317  else
3318  return SCIPvarGetNLocksUpType(var->data.aggregate.var, locktype);
3319 
3321  assert(!var->donotmultaggr);
3322  nlocks = 0;
3323  for( i = 0; i < var->data.multaggr.nvars; ++i )
3324  {
3325  if( var->data.multaggr.scalars[i] > 0.0 )
3326  nlocks += SCIPvarGetNLocksDownType(var->data.multaggr.vars[i], locktype);
3327  else
3328  nlocks += SCIPvarGetNLocksUpType(var->data.multaggr.vars[i], locktype);
3329  }
3330  return nlocks;
3331 
3333  assert(var->negatedvar != NULL);
3335  assert(var->negatedvar->negatedvar == var);
3336  return SCIPvarGetNLocksUpType(var->negatedvar, locktype);
3337 
3338  default:
3339  SCIPerrorMessage("unknown variable status\n");
3340  SCIPABORT();
3341  return INT_MAX; /*lint !e527*/
3342  }
3343 }
3344 
3345 /** gets number of locks for rounding up of a special type */
3347  SCIP_VAR* var, /**< problem variable */
3348  SCIP_LOCKTYPE locktype /**< type of variable locks */
3349  )
3350 {
3351  int nlocks;
3352  int i;
3353 
3354  assert(var != NULL);
3355  assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/
3356  assert(var->nlocksup[locktype] >= 0);
3357 
3358  switch( SCIPvarGetStatus(var) )
3359  {
3361  if( var->data.original.transvar != NULL )
3362  return SCIPvarGetNLocksUpType(var->data.original.transvar, locktype);
3363  else
3364  return var->nlocksup[locktype];
3365 
3366  case SCIP_VARSTATUS_LOOSE:
3367  case SCIP_VARSTATUS_COLUMN:
3368  case SCIP_VARSTATUS_FIXED:
3369  return var->nlocksup[locktype];
3370 
3372  assert(!var->donotaggr);
3373  if( var->data.aggregate.scalar > 0.0 )
3374  return SCIPvarGetNLocksUpType(var->data.aggregate.var, locktype);
3375  else
3376  return SCIPvarGetNLocksDownType(var->data.aggregate.var, locktype);
3377 
3379  assert(!var->donotmultaggr);
3380  nlocks = 0;
3381  for( i = 0; i < var->data.multaggr.nvars; ++i )
3382  {
3383  if( var->data.multaggr.scalars[i] > 0.0 )
3384  nlocks += SCIPvarGetNLocksUpType(var->data.multaggr.vars[i], locktype);
3385  else
3386  nlocks += SCIPvarGetNLocksDownType(var->data.multaggr.vars[i], locktype);
3387  }
3388  return nlocks;
3389 
3391  assert(var->negatedvar != NULL);
3393  assert(var->negatedvar->negatedvar == var);
3394  return SCIPvarGetNLocksDownType(var->negatedvar, locktype);
3395 
3396  default:
3397  SCIPerrorMessage("unknown variable status\n");
3398  SCIPABORT();
3399  return INT_MAX; /*lint !e527*/
3400  }
3401 }
3402 
3403 /** gets number of locks for rounding down
3404  *
3405  * @note This method will always return variable locks of type model
3406  *
3407  * @note It is recommented to use SCIPvarGetNLocksDownType()
3408  */
3410  SCIP_VAR* var /**< problem variable */
3411  )
3412 {
3414 }
3415 
3416 /** gets number of locks for rounding up
3417  *
3418  * @note This method will always return variable locks of type model
3419  *
3420  * @note It is recommented to use SCIPvarGetNLocksUpType()
3421  */
3422 int SCIPvarGetNLocksUp(
3423  SCIP_VAR* var /**< problem variable */
3424  )
3425 {
3427 }
3428 
3429 /** is it possible, to round variable down and stay feasible?
3430  *
3431  * @note This method will always check w.r.t variable locks of type model
3432  */
3434  SCIP_VAR* var /**< problem variable */
3435  )
3436 {
3437  return (SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == 0);
3438 }
3439 
3440 /** is it possible, to round variable up and stay feasible?
3441  *
3442  * @note This method will always check w.r.t. variable locks of type model
3443  */
3445  SCIP_VAR* var /**< problem variable */
3446  )
3447 {
3448  return (SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == 0);
3449 }
3450 
3451 /** gets and captures transformed variable of a given variable; if the variable is not yet transformed,
3452  * a new transformed variable for this variable is created
3453  */
3455  SCIP_VAR* origvar, /**< original problem variable */
3456  BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
3457  SCIP_SET* set, /**< global SCIP settings */
3458  SCIP_STAT* stat, /**< problem statistics */
3459  SCIP_OBJSENSE objsense, /**< objective sense of original problem; transformed is always MINIMIZE */
3460  SCIP_VAR** transvar /**< pointer to store the transformed variable */
3461  )
3462 {
3463  char name[SCIP_MAXSTRLEN];
3464 
3465  assert(origvar != NULL);
3466  assert(origvar->scip == set->scip);
3467  assert(SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_ORIGINAL);
3468  assert(SCIPsetIsEQ(set, origvar->glbdom.lb, origvar->locdom.lb));
3469  assert(SCIPsetIsEQ(set, origvar->glbdom.ub, origvar->locdom.ub));
3470  assert(origvar->vlbs == NULL);
3471  assert(origvar->vubs == NULL);
3472  assert(transvar != NULL);
3473 
3474  /* check if variable is already transformed */
3475  if( origvar->data.original.transvar != NULL )
3476  {
3477  *transvar = origvar->data.original.transvar;
3478  SCIPvarCapture(*transvar);
3479  }
3480  else
3481  {
3482  int i;
3483 
3484  /* create transformed variable */
3485  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "t_%s", origvar->name);
3486  SCIP_CALL( SCIPvarCreateTransformed(transvar, blkmem, set, stat, name,
3487  origvar->glbdom.lb, origvar->glbdom.ub, (SCIP_Real)objsense * origvar->obj,
3488  SCIPvarGetType(origvar), origvar->initial, origvar->removable,
3489  origvar->vardelorig, origvar->vartrans, origvar->vardeltrans, origvar->varcopy, NULL) );
3490 
3491  /* copy the branch factor and priority */
3492  (*transvar)->branchfactor = origvar->branchfactor;
3493  (*transvar)->branchpriority = origvar->branchpriority;
3494  (*transvar)->branchdirection = origvar->branchdirection; /*lint !e732*/
3495 
3496  /* duplicate hole lists */
3497  SCIP_CALL( holelistDuplicate(&(*transvar)->glbdom.holelist, blkmem, set, origvar->glbdom.holelist) );
3498  SCIP_CALL( holelistDuplicate(&(*transvar)->locdom.holelist, blkmem, set, origvar->locdom.holelist) );
3499 
3500  /* link original and transformed variable */
3501  origvar->data.original.transvar = *transvar;
3502  SCIP_CALL( varAddParent(*transvar, blkmem, set, origvar) );
3503 
3504  /* copy rounding locks */
3505  for( i = 0; i < NLOCKTYPES; i++ )
3506  {
3507  (*transvar)->nlocksdown[i] = origvar->nlocksdown[i];
3508  (*transvar)->nlocksup[i] = origvar->nlocksup[i];
3509  assert((*transvar)->nlocksdown[i] >= 0);
3510  assert((*transvar)->nlocksup[i] >= 0);
3511  }
3512 
3513  /* copy donot(mult)aggr status */
3514  (*transvar)->donotaggr = origvar->donotaggr;
3515  (*transvar)->donotmultaggr = origvar->donotmultaggr;
3516 
3517  /* copy lazy bounds */
3518  (*transvar)->lazylb = origvar->lazylb;
3519  (*transvar)->lazyub = origvar->lazyub;
3520 
3521  /* transfer eventual variable statistics; do not update global statistics, because this has been done
3522  * when original variable was created
3523  */
3524  SCIPhistoryUnite((*transvar)->history, origvar->history, FALSE);
3525 
3526  /* transform user data */
3527  if( origvar->vartrans != NULL )
3528  {
3529  SCIP_CALL( origvar->vartrans(set->scip, origvar, origvar->vardata, *transvar, &(*transvar)->vardata) );
3530  }
3531  else
3532  (*transvar)->vardata = origvar->vardata;
3533  }
3534 
3535  SCIPsetDebugMsg(set, "transformed variable: <%s>[%p] -> <%s>[%p]\n", origvar->name, (void*)origvar, (*transvar)->name, (void*)*transvar);
3536 
3537  return SCIP_OKAY;
3538 }
3539 
3540 /** gets corresponding transformed variable of an original or negated original variable */
3542  SCIP_VAR* origvar, /**< original problem variable */
3543  BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
3544  SCIP_SET* set, /**< global SCIP settings */
3545  SCIP_STAT* stat, /**< problem statistics */
3546  SCIP_VAR** transvar /**< pointer to store the transformed variable, or NULL if not existing yet */
3547  )
3548 {
3549  assert(origvar != NULL);
3551  assert(origvar->scip == set->scip);
3552 
3553  if( SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_NEGATED )
3554  {
3555  assert(origvar->negatedvar != NULL);
3557 
3558  if( origvar->negatedvar->data.original.transvar == NULL )
3559  *transvar = NULL;
3560  else
3561  {
3562  SCIP_CALL( SCIPvarNegate(origvar->negatedvar->data.original.transvar, blkmem, set, stat, transvar) );
3563  }
3564  }
3565  else
3566  *transvar = origvar->data.original.transvar;
3567 
3568  return SCIP_OKAY;
3569 }
3570 
3571 /** converts loose transformed variable into column variable, creates LP column */
3573  SCIP_VAR* var, /**< problem variable */
3574  BMS_BLKMEM* blkmem, /**< block memory */
3575  SCIP_SET* set, /**< global SCIP settings */
3576  SCIP_STAT* stat, /**< problem statistics */
3577  SCIP_PROB* prob, /**< problem data */
3578  SCIP_LP* lp /**< current LP data */
3579  )
3580 {
3581  assert(var != NULL);
3582  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
3583  assert(var->scip == set->scip);
3584 
3585  SCIPsetDebugMsg(set, "creating column for variable <%s>\n", var->name);
3586 
3587  /* switch variable status */
3588  var->varstatus = SCIP_VARSTATUS_COLUMN; /*lint !e641*/
3589 
3590  /* create column of variable */
3591  SCIP_CALL( SCIPcolCreate(&var->data.col, blkmem, set, stat, var, 0, NULL, NULL, var->removable) );
3592 
3593  if( var->probindex != -1 )
3594  {
3595  /* inform problem about the variable's status change */
3596  SCIP_CALL( SCIPprobVarChangedStatus(prob, blkmem, set, NULL, NULL, var) );
3597 
3598  /* inform LP, that problem variable is now a column variable and no longer loose */
3599  SCIP_CALL( SCIPlpUpdateVarColumn(lp, set, var) );
3600  }
3601 
3602  return SCIP_OKAY;
3603 }
3604 
3605 /** converts column transformed variable back into loose variable, frees LP column */
3607  SCIP_VAR* var, /**< problem variable */
3608  BMS_BLKMEM* blkmem, /**< block memory */
3609  SCIP_SET* set, /**< global SCIP settings */
3610  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3611  SCIP_PROB* prob, /**< problem data */
3612  SCIP_LP* lp /**< current LP data */
3613  )
3614 {
3615  assert(var != NULL);
3616  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
3617  assert(var->scip == set->scip);
3618  assert(var->data.col != NULL);
3619  assert(var->data.col->lppos == -1);
3620  assert(var->data.col->lpipos == -1);
3621 
3622  SCIPsetDebugMsg(set, "deleting column for variable <%s>\n", var->name);
3623 
3624  /* free column of variable */
3625  SCIP_CALL( SCIPcolFree(&var->data.col, blkmem, set, eventqueue, lp) );
3626 
3627  /* switch variable status */
3628  var->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
3629 
3630  if( var->probindex != -1 )
3631  {
3632  /* inform problem about the variable's status change */
3633  SCIP_CALL( SCIPprobVarChangedStatus(prob, blkmem, set, NULL, NULL, var) );
3634 
3635  /* inform LP, that problem variable is now a loose variable and no longer a column */
3636  SCIP_CALL( SCIPlpUpdateVarLoose(lp, set, var) );
3637  }
3638 
3639  return SCIP_OKAY;
3640 }
3641 
3642 /** issues a VARFIXED event on the given variable and all its parents (except ORIGINAL parents);
3643  * the event issuing on the parents is necessary, because unlike with bound changes, the parent variables
3644  * are not informed about a fixing of an active variable they are pointing to
3645  */
3646 static
3648  SCIP_VAR* var, /**< problem variable to change */
3649  BMS_BLKMEM* blkmem, /**< block memory */
3650  SCIP_SET* set, /**< global SCIP settings */
3651  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3652  int fixeventtype /**< is this event a fixation(0), an aggregation(1), or a
3653  * multi-aggregation(2)
3654  */
3655  )
3656 {
3657  SCIP_EVENT* event;
3658  SCIP_VARSTATUS varstatus;
3659  int i;
3660 
3661  assert(var != NULL);
3662  assert(var->scip == set->scip);
3663  assert(0 <= fixeventtype && fixeventtype <= 2);
3664 
3665  /* issue VARFIXED event on variable */
3666  SCIP_CALL( SCIPeventCreateVarFixed(&event, blkmem, var) );
3667  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
3668 
3669 #ifndef NDEBUG
3670  for( i = var->nparentvars -1; i >= 0; --i )
3671  {
3673  }
3674 #endif
3675 
3676  switch( fixeventtype )
3677  {
3678  case 0:
3679  /* process all parents of a fixed variable */
3680  for( i = var->nparentvars - 1; i >= 0; --i )
3681  {
3682  varstatus = SCIPvarGetStatus(var->parentvars[i]);
3683 
3684  assert(varstatus != SCIP_VARSTATUS_FIXED);
3685 
3686  /* issue event on all not yet fixed parent variables, (that should already issued this event) except the original
3687  * one
3688  */
3689  if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3690  {
3691  SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3692  }
3693  }
3694  break;
3695  case 1:
3696  /* process all parents of a aggregated variable */
3697  for( i = var->nparentvars - 1; i >= 0; --i )
3698  {
3699  varstatus = SCIPvarGetStatus(var->parentvars[i]);
3700 
3701  assert(varstatus != SCIP_VARSTATUS_FIXED);
3702 
3703  /* issue event for not aggregated parent variable, because for these and its parents the var event was already
3704  * issued(, except the original one)
3705  *
3706  * @note that even before an aggregated parent variable, there might be variables, for which the vent was not
3707  * yet issued
3708  */
3709  if( varstatus == SCIP_VARSTATUS_AGGREGATED )
3710  continue;
3711 
3712  if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3713  {
3714  SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3715  }
3716  }
3717  break;
3718  case 2:
3719  /* process all parents of a aggregated variable */
3720  for( i = var->nparentvars - 1; i >= 0; --i )
3721  {
3722  varstatus = SCIPvarGetStatus(var->parentvars[i]);
3723 
3724  assert(varstatus != SCIP_VARSTATUS_FIXED);
3725 
3726  /* issue event on all parent variables except the original one */
3727  if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3728  {
3729  SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3730  }
3731  }
3732  break;
3733  default:
3734  SCIPerrorMessage("unknown variable fixation event origin\n");
3735  return SCIP_INVALIDDATA;
3736  }
3737 
3738  return SCIP_OKAY;
3739 }
3740 
3741 /** converts variable into fixed variable */
3743  SCIP_VAR* var, /**< problem variable */
3744  BMS_BLKMEM* blkmem, /**< block memory */
3745  SCIP_SET* set, /**< global SCIP settings */
3746  SCIP_STAT* stat, /**< problem statistics */
3747  SCIP_PROB* transprob, /**< tranformed problem data */
3748  SCIP_PROB* origprob, /**< original problem data */
3749  SCIP_PRIMAL* primal, /**< primal data */
3750  SCIP_TREE* tree, /**< branch and bound tree */
3751  SCIP_REOPT* reopt, /**< reoptimization data structure */
3752  SCIP_LP* lp, /**< current LP data */
3753  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
3754  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
3755  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3756  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
3757  SCIP_Real fixedval, /**< value to fix variable at */
3758  SCIP_Bool* infeasible, /**< pointer to store whether the fixing is infeasible */
3759  SCIP_Bool* fixed /**< pointer to store whether the fixing was performed (variable was unfixed) */
3760  )
3761 {
3762  SCIP_Real obj;
3763  SCIP_Real childfixedval;
3764 
3765  assert(var != NULL);
3766  assert(var->scip == set->scip);
3767  assert(SCIPsetIsEQ(set, var->glbdom.lb, var->locdom.lb));
3768  assert(SCIPsetIsEQ(set, var->glbdom.ub, var->locdom.ub));
3769  assert(infeasible != NULL);
3770  assert(fixed != NULL);
3771 
3772  SCIPsetDebugMsg(set, "fix variable <%s>[%g,%g] to %g\n", var->name, var->glbdom.lb, var->glbdom.ub, fixedval);
3773 
3774  *infeasible = FALSE;
3775  *fixed = FALSE;
3776 
3778  {
3779  *infeasible = !SCIPsetIsFeasEQ(set, fixedval, var->locdom.lb);
3780  SCIPsetDebugMsg(set, " -> variable already fixed to %g (fixedval=%g): infeasible=%u\n", var->locdom.lb, fixedval, *infeasible);
3781  return SCIP_OKAY;
3782  }
3783  else if( (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && !SCIPsetIsFeasIntegral(set, fixedval))
3784  || SCIPsetIsFeasLT(set, fixedval, var->locdom.lb)
3785  || SCIPsetIsFeasGT(set, fixedval, var->locdom.ub) )
3786  {
3787  SCIPsetDebugMsg(set, " -> fixing infeasible: locdom=[%g,%g], fixedval=%g\n", var->locdom.lb, var->locdom.ub, fixedval);
3788  *infeasible = TRUE;
3789  return SCIP_OKAY;
3790  }
3791 
3792  switch( SCIPvarGetStatus(var) )
3793  {
3795  if( var->data.original.transvar == NULL )
3796  {
3797  SCIPerrorMessage("cannot fix an untransformed original variable\n");
3798  return SCIP_INVALIDDATA;
3799  }
3800  SCIP_CALL( SCIPvarFix(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt,
3801  lp, branchcand, eventfilter, eventqueue, cliquetable, fixedval, infeasible, fixed) );
3802  break;
3803 
3804  case SCIP_VARSTATUS_LOOSE:
3805  assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
3806 
3807  /* set the fixed variable's objective value to 0.0 */
3808  obj = var->obj;
3809  SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
3810 
3811  /* since we change the variable type form loose to fixed, we have to adjust the number of loose
3812  * variables in the LP data structure; the loose objective value (looseobjval) in the LP data structure, however,
3813  * gets adjusted automatically, due to the event SCIP_EVENTTYPE_OBJCHANGED which dropped in the moment where the
3814  * objective of this variable is set to zero
3815  */
3816  SCIPlpDecNLoosevars(lp);
3817 
3818  /* change variable's bounds to fixed value (thereby removing redundant implications and variable bounds) */
3819  holelistFree(&var->glbdom.holelist, blkmem);
3820  holelistFree(&var->locdom.holelist, blkmem);
3821  SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, fixedval) );
3822  SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, fixedval) );
3823 
3824  /* explicitly set variable's bounds, even if the fixed value is in epsilon range of the old bound */
3825  var->glbdom.lb = fixedval;
3826  var->glbdom.ub = fixedval;
3827  var->locdom.lb = fixedval;
3828  var->locdom.ub = fixedval;
3829 
3830  /* delete implications and variable bounds information */
3831  SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) );
3832  assert(var->vlbs == NULL);
3833  assert(var->vubs == NULL);
3834  assert(var->implics == NULL);
3835  assert(var->cliquelist == NULL);
3836 
3837  /* clear the history of the variable */
3838  SCIPhistoryReset(var->history);
3840 
3841  /* convert variable into fixed variable */
3842  var->varstatus = SCIP_VARSTATUS_FIXED; /*lint !e641*/
3843 
3844  /* inform problem about the variable's status change */
3845  if( var->probindex != -1 )
3846  {
3847  SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) );
3848  }
3849 
3850  /* reset the objective value of the fixed variable, thus adjusting the problem's objective offset */
3851  SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) );
3852 
3853  /* issue VARFIXED event */
3854  SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 0) );
3855 
3856  *fixed = TRUE;
3857  break;
3858 
3859  case SCIP_VARSTATUS_COLUMN:
3860  SCIPerrorMessage("cannot fix a column variable\n");
3861  return SCIP_INVALIDDATA;
3862 
3863  case SCIP_VARSTATUS_FIXED:
3864  SCIPerrorMessage("cannot fix a fixed variable again\n"); /*lint !e527*/
3865  SCIPABORT(); /* case is already handled in earlier if condition */
3866  return SCIP_INVALIDDATA; /*lint !e527*/
3867 
3869  /* fix aggregation variable y in x = a*y + c, instead of fixing x directly */
3870  assert(SCIPsetIsZero(set, var->obj));
3871  assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
3872  if( SCIPsetIsInfinity(set, fixedval) || SCIPsetIsInfinity(set, -fixedval) )
3873  childfixedval = (var->data.aggregate.scalar < 0.0 ? -fixedval : fixedval);
3874  else
3875  childfixedval = (fixedval - var->data.aggregate.constant)/var->data.aggregate.scalar;
3876  SCIP_CALL( SCIPvarFix(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
3877  branchcand, eventfilter, eventqueue, cliquetable, childfixedval, infeasible, fixed) );
3878  break;
3879 
3881  SCIPerrorMessage("cannot fix a multiple aggregated variable\n");
3882  SCIPABORT();
3883  return SCIP_INVALIDDATA; /*lint !e527*/
3884 
3886  /* fix negation variable x in x' = offset - x, instead of fixing x' directly */
3887  assert(SCIPsetIsZero(set, var->obj));
3888  assert(var->negatedvar != NULL);
3890  assert(var->negatedvar->negatedvar == var);
3891  SCIP_CALL( SCIPvarFix(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
3892  branchcand, eventfilter, eventqueue, cliquetable, var->data.negate.constant - fixedval, infeasible, fixed) );
3893  break;
3894 
3895  default:
3896  SCIPerrorMessage("unknown variable status\n");
3897  return SCIP_INVALIDDATA;
3898  }
3899 
3900  return SCIP_OKAY;
3901 }
3902 
3903 /** transforms given variables, scalars and constant to the corresponding active variables, scalars and constant
3904  *
3905  * If the number of needed active variables is greater than the available slots in the variable array, nothing happens except
3906  * that the required size is stored in the corresponding variable; hence, if afterwards the required size is greater than the
3907  * available slots (varssize), nothing happens; otherwise, the active variable representation is stored in the arrays.
3908  *
3909  * The reason for this approach is that we cannot reallocate memory, since we do not know how the
3910  * memory has been allocated (e.g., by a C++ 'new' or SCIP functions).
3911  */
3913  SCIP_SET* set, /**< global SCIP settings */
3914  SCIP_VAR** vars, /**< variable array to get active variables */
3915  SCIP_Real* scalars, /**< scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
3916  int* nvars, /**< pointer to number of variables and values in vars and scalars array */
3917  int varssize, /**< available slots in vars and scalars array */
3918  SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */
3919  int* requiredsize, /**< pointer to store the required array size for the active variables */
3920  SCIP_Bool mergemultiples /**< should multiple occurrences of a var be replaced by a single coeff? */
3921  )
3922 {
3923  SCIP_VAR** activevars;
3924  SCIP_Real* activescalars;
3925  int nactivevars;
3926  SCIP_Real activeconstant;
3927  SCIP_Bool activeconstantinf;
3928  int activevarssize;
3929 
3930  SCIP_VAR* var;
3931  SCIP_Real scalar;
3932  int v;
3933  int k;
3934 
3935  SCIP_VAR** tmpvars;
3936  SCIP_VAR** multvars;
3937  SCIP_Real* tmpscalars;
3938  SCIP_Real* multscalars;
3939  int tmpvarssize;
3940  int ntmpvars;
3941  int nmultvars;
3942 
3943  SCIP_VAR* multvar;
3944  SCIP_Real multscalar;
3945  SCIP_Real multconstant;
3946  int pos;
3947 
3948  int noldtmpvars;
3949 
3950  SCIP_VAR** tmpvars2;
3951  SCIP_Real* tmpscalars2;
3952  int tmpvarssize2;
3953  int ntmpvars2;
3954 
3955  SCIP_Bool sortagain = FALSE;
3956 
3957  assert(set != NULL);
3958  assert(nvars != NULL);
3959  assert(scalars != NULL || *nvars == 0);
3960  assert(constant != NULL);
3961  assert(requiredsize != NULL);
3962  assert(*nvars <= varssize);
3963 
3964  *requiredsize = 0;
3965 
3966  if( *nvars == 0 )
3967  return SCIP_OKAY;
3968 
3969  assert(vars != NULL);
3970 
3971  /* handle the "easy" case of just one variable and avoid memory allocation if the variable is already active */
3972  if( *nvars == 1 && (vars[0]->varstatus == ((int) SCIP_VARSTATUS_COLUMN) || vars[0]->varstatus == ((int) SCIP_VARSTATUS_LOOSE)) )
3973  {
3974  *requiredsize = 1;
3975 
3976  return SCIP_OKAY;
3977  }
3978 
3979  nactivevars = 0;
3980  activeconstant = 0.0;
3981  activeconstantinf = FALSE;
3982  activevarssize = (*nvars) * 2;
3983  ntmpvars = *nvars;
3984  tmpvarssize = *nvars;
3985 
3986  tmpvarssize2 = 1;
3987 
3988  /* allocate temporary memory */
3989  SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpvars2, tmpvarssize2) );
3990  SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpscalars2, tmpvarssize2) );
3991  SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) );
3992  SCIP_CALL( SCIPsetAllocBufferArray(set, &activescalars, activevarssize) );
3993  SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpvars, vars, ntmpvars) );
3994  SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpscalars, scalars, ntmpvars) );
3995 
3996  /* to avoid unnecessary expanding of variable arrays while disaggregating several variables multiple times combine same variables
3997  * first, first get all corresponding variables with status loose, column, multaggr or fixed
3998  */
3999  for( v = ntmpvars - 1; v >= 0; --v )
4000  {
4001  var = tmpvars[v];
4002  scalar = tmpscalars[v];
4003 
4004  assert(var != NULL);
4005  /* transforms given variable, scalar and constant to the corresponding active, fixed, or
4006  * multi-aggregated variable, scalar and constant; if the variable resolves to a fixed
4007  * variable, "scalar" will be 0.0 and the value of the sum will be stored in "constant".
4008  */
4009  SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &scalar, &activeconstant) );
4010  assert(var != NULL);
4011 
4012  assert(SCIPsetIsInfinity(set, activeconstant) == (activeconstant == SCIPsetInfinity(set))); /*lint !e777*/
4013  assert(SCIPsetIsInfinity(set, -activeconstant) == (activeconstant == -SCIPsetInfinity(set))); /*lint !e777*/
4014 
4015  activeconstantinf = SCIPsetIsInfinity(set, activeconstant) || SCIPsetIsInfinity(set, -activeconstant);
4016 
4017  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
4018  || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
4021 
4022  tmpvars[v] = var;
4023  tmpscalars[v] = scalar;
4024  }
4025  noldtmpvars = ntmpvars;
4026 
4027  /* sort all variables to combine equal variables easily */
4028  SCIPsortPtrReal((void**)tmpvars, tmpscalars, SCIPvarComp, noldtmpvars);
4029  ntmpvars = 0;
4030  for( v = 1; v < noldtmpvars; ++v )
4031  {
4032  /* combine same variables */
4033  if( SCIPvarCompare(tmpvars[v], tmpvars[ntmpvars]) == 0 )
4034  {
4035  tmpscalars[ntmpvars] += tmpscalars[v];
4036  }
4037  else
4038  {
4039  ++ntmpvars;
4040  if( v > ntmpvars )
4041  {
4042  tmpscalars[ntmpvars] = tmpscalars[v];
4043  tmpvars[ntmpvars] = tmpvars[v];
4044  }
4045  }
4046  }
4047  ++ntmpvars;
4048 
4049 #ifdef SCIP_MORE_DEBUG
4050  for( v = 1; v < ntmpvars; ++v )
4051  assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0);
4052 #endif
4053 
4054  /* collect for each variable the representation in active variables */
4055  while( ntmpvars >= 1 )
4056  {
4057  --ntmpvars;
4058  ntmpvars2 = 0;
4059  var = tmpvars[ntmpvars];
4060  scalar = tmpscalars[ntmpvars];
4061 
4062  assert(var != NULL);
4063 
4064  /* TODO: maybe we should test here on SCIPsetIsZero() instead of 0.0 */
4065  if( scalar == 0.0 )
4066  continue;
4067 
4068  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
4069  || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
4072 
4073  switch( SCIPvarGetStatus(var) )
4074  {
4075  case SCIP_VARSTATUS_LOOSE:
4076  case SCIP_VARSTATUS_COLUMN:
4077  /* x = a*y + c */
4078  if( nactivevars >= activevarssize )
4079  {
4080  activevarssize *= 2;
4081  SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) );
4082  SCIP_CALL( SCIPsetReallocBufferArray(set, &activescalars, activevarssize) );
4083  assert(nactivevars < activevarssize);
4084  }
4085  activevars[nactivevars] = var;
4086  activescalars[nactivevars] = scalar;
4087  nactivevars++;
4088  break;
4089 
4091  /* x = a_1*y_1 + ... + a_n*y_n + c */
4092  nmultvars = var->data.multaggr.nvars;
4093  multvars = var->data.multaggr.vars;
4094  multscalars = var->data.multaggr.scalars;
4095  sortagain = TRUE;
4096 
4097  if( nmultvars + ntmpvars > tmpvarssize )
4098  {
4099  while( nmultvars + ntmpvars > tmpvarssize )
4100  tmpvarssize *= 2;
4101  SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) );
4102  SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars, tmpvarssize) );
4103  assert(nmultvars + ntmpvars <= tmpvarssize);
4104  }
4105 
4106  if( nmultvars > tmpvarssize2 )
4107  {
4108  while( nmultvars > tmpvarssize2 )
4109  tmpvarssize2 *= 2;
4110  SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars2, tmpvarssize2) );
4111  SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars2, tmpvarssize2) );
4112  assert(nmultvars <= tmpvarssize2);
4113  }
4114 
4115  --nmultvars;
4116 
4117  for( ; nmultvars >= 0; --nmultvars )
4118  {
4119  multvar = multvars[nmultvars];
4120  multscalar = multscalars[nmultvars];
4121  multconstant = 0;
4122 
4123  assert(multvar != NULL);
4124  SCIP_CALL( SCIPvarGetProbvarSum(&multvar, set, &multscalar, &multconstant) );
4125  assert(multvar != NULL);
4126 
4127  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
4128  || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
4131 
4132  if( !activeconstantinf )
4133  {
4134  assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar));
4135 
4136  if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) )
4137  {
4138  assert(scalar != 0.0);
4139  if( scalar * multconstant > 0.0 )
4140  {
4141  activeconstant = SCIPsetInfinity(set);
4142  activeconstantinf = TRUE;
4143  }
4144  else
4145  {
4146  activeconstant = -SCIPsetInfinity(set);
4147  activeconstantinf = TRUE;
4148  }
4149  }
4150  else
4151  activeconstant += scalar * multconstant;
4152  }
4153 #ifndef NDEBUG
4154  else
4155  {
4156  assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 &&
4157  (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4158  assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 &&
4159  (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4160  }
4161 #endif
4162 
4163  if( SCIPsortedvecFindPtr((void**)tmpvars, SCIPvarComp, multvar, ntmpvars, &pos) )
4164  {
4165  assert(SCIPvarCompare(tmpvars[pos], multvar) == 0);
4166  tmpscalars[pos] += scalar * multscalar;
4167  }
4168  else
4169  {
4170  tmpvars2[ntmpvars2] = multvar;
4171  tmpscalars2[ntmpvars2] = scalar * multscalar;
4172  ++(ntmpvars2);
4173  assert(ntmpvars2 <= tmpvarssize2);
4174  }
4175  }
4176 
4177  if( ntmpvars2 > 0 )
4178  {
4179  /* sort all variables to combine equal variables easily */
4180  SCIPsortPtrReal((void**)tmpvars2, tmpscalars2, SCIPvarComp, ntmpvars2);
4181  pos = 0;
4182  for( v = 1; v < ntmpvars2; ++v )
4183  {
4184  /* combine same variables */
4185  if( SCIPvarCompare(tmpvars2[v], tmpvars2[pos]) == 0 )
4186  {
4187  tmpscalars2[pos] += tmpscalars2[v];
4188  }
4189  else
4190  {
4191  ++pos;
4192  if( v > pos )
4193  {
4194  tmpscalars2[pos] = tmpscalars2[v];
4195  tmpvars2[pos] = tmpvars2[v];
4196  }
4197  }
4198  }
4199  ntmpvars2 = pos + 1;
4200 #ifdef SCIP_MORE_DEBUG
4201  for( v = 1; v < ntmpvars2; ++v )
4202  {
4203  assert(SCIPvarCompare(tmpvars2[v], tmpvars2[v-1]) > 0);
4204  }
4205  for( v = 1; v < ntmpvars; ++v )
4206  {
4207  assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0);
4208  }
4209 #endif
4210  v = ntmpvars - 1;
4211  k = ntmpvars2 - 1;
4212  pos = ntmpvars + ntmpvars2 - 1;
4213  ntmpvars += ntmpvars2;
4214 
4215  while( v >= 0 && k >= 0 )
4216  {
4217  assert(pos >= 0);
4218  assert(SCIPvarCompare(tmpvars[v], tmpvars2[k]) != 0);
4219  if( SCIPvarCompare(tmpvars[v], tmpvars2[k]) >= 0 )
4220  {
4221  tmpvars[pos] = tmpvars[v];
4222  tmpscalars[pos] = tmpscalars[v];
4223  --v;
4224  }
4225  else
4226  {
4227  tmpvars[pos] = tmpvars2[k];
4228  tmpscalars[pos] = tmpscalars2[k];
4229  --k;
4230  }
4231  --pos;
4232  assert(pos >= 0);
4233  }
4234  while( v >= 0 )
4235  {
4236  assert(pos >= 0);
4237  tmpvars[pos] = tmpvars[v];
4238  tmpscalars[pos] = tmpscalars[v];
4239  --v;
4240  --pos;
4241  }
4242  while( k >= 0 )
4243  {
4244  assert(pos >= 0);
4245  tmpvars[pos] = tmpvars2[k];
4246  tmpscalars[pos] = tmpscalars2[k];
4247  --k;
4248  --pos;
4249  }
4250  }
4251 #ifdef SCIP_MORE_DEBUG
4252  for( v = 1; v < ntmpvars; ++v )
4253  {
4254  assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0);
4255  }
4256 #endif
4257 
4258  if( !activeconstantinf )
4259  {
4260  assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar));
4261 
4262  multconstant = SCIPvarGetMultaggrConstant(var);
4263 
4264  if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) )
4265  {
4266  assert(scalar != 0.0);
4267  if( scalar * multconstant > 0.0 )
4268  {
4269  activeconstant = SCIPsetInfinity(set);
4270  activeconstantinf = TRUE;
4271  }
4272  else
4273  {
4274  activeconstant = -SCIPsetInfinity(set);
4275  activeconstantinf = TRUE;
4276  }
4277  }
4278  else
4279  activeconstant += scalar * multconstant;
4280  }
4281 #ifndef NDEBUG
4282  else
4283  {
4284  multconstant = SCIPvarGetMultaggrConstant(var);
4285  assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 &&
4286  (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4287  assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 &&
4288  (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4289  }
4290 #endif
4291  break;
4292 
4293  case SCIP_VARSTATUS_FIXED:
4297  default:
4298  /* case x = c, but actually we should not be here, since SCIPvarGetProbvarSum() returns a scalar of 0.0 for
4299  * fixed variables and is handled already
4300  */
4301  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
4302  assert(SCIPsetIsZero(set, var->glbdom.lb) && SCIPsetIsEQ(set, var->glbdom.lb, var->glbdom.ub));
4303  }
4304  }
4305 
4306  if( mergemultiples )
4307  {
4308  if( sortagain )
4309  {
4310  /* sort variable and scalar array by variable index */
4311  SCIPsortPtrReal((void**)activevars, activescalars, SCIPvarComp, nactivevars);
4312 
4313  /* eliminate duplicates and count required size */
4314  v = nactivevars - 1;
4315  while( v > 0 )
4316  {
4317  /* combine both variable since they are the same */
4318  if( SCIPvarCompare(activevars[v - 1], activevars[v]) == 0 )
4319  {
4320  if( activescalars[v - 1] + activescalars[v] != 0.0 )
4321  {
4322  activescalars[v - 1] += activescalars[v];
4323  --nactivevars;
4324  activevars[v] = activevars[nactivevars];
4325  activescalars[v] = activescalars[nactivevars];
4326  }
4327  else
4328  {
4329  --nactivevars;
4330  activevars[v] = activevars[nactivevars];
4331  activescalars[v] = activescalars[nactivevars];
4332  --nactivevars;
4333  --v;
4334  activevars[v] = activevars[nactivevars];
4335  activescalars[v] = activescalars[nactivevars];
4336  }
4337  }
4338  --v;
4339  }
4340  }
4341  /* the variables were added in reverse order, we revert the order now;
4342  * this should not be necessary, but not doing this changes the behavior sometimes
4343  */
4344  else
4345  {
4346  SCIP_VAR* tmpvar;
4347  SCIP_Real tmpscalar;
4348 
4349  for( v = 0; v < nactivevars / 2; ++v )
4350  {
4351  tmpvar = activevars[v];
4352  tmpscalar = activescalars[v];
4353  activevars[v] = activevars[nactivevars - 1 - v];
4354  activescalars[v] = activescalars[nactivevars - 1 - v];
4355  activevars[nactivevars - 1 - v] = tmpvar;
4356  activescalars[nactivevars - 1 - v] = tmpscalar;
4357  }
4358  }
4359  }
4360  *requiredsize = nactivevars;
4361 
4362  if( varssize >= *requiredsize )
4363  {
4364  assert(vars != NULL);
4365 
4366  *nvars = *requiredsize;
4367 
4368  if( !SCIPsetIsInfinity(set, *constant) && !SCIPsetIsInfinity(set, -(*constant)) )
4369  {
4370  /* if the activeconstant is infinite, the constant pointer gets the same value, otherwise add the value */
4371  if( activeconstantinf )
4372  (*constant) = activeconstant;
4373  else
4374  (*constant) += activeconstant;
4375  }
4376 #ifndef NDEBUG
4377  else
4378  {
4379  assert(!SCIPsetIsInfinity(set, (*constant)) || !SCIPsetIsInfinity(set, -activeconstant));
4380  assert(!SCIPsetIsInfinity(set, -(*constant)) || !SCIPsetIsInfinity(set, activeconstant));
4381  }
4382 #endif
4383 
4384  /* copy active variable and scalar array to the given arrays */
4385  for( v = 0; v < *nvars; ++v )
4386  {
4387  vars[v] = activevars[v];
4388  scalars[v] = activescalars[v]; /*lint !e613*/
4389  }
4390  }
4391 
4392  assert(SCIPsetIsInfinity(set, *constant) == ((*constant) == SCIPsetInfinity(set))); /*lint !e777*/
4393  assert(SCIPsetIsInfinity(set, -(*constant)) == ((*constant) == -SCIPsetInfinity(set))); /*lint !e777*/
4394 
4395  SCIPsetFreeBufferArray(set, &tmpscalars);
4396  SCIPsetFreeBufferArray(set, &tmpvars);
4397  SCIPsetFreeBufferArray(set, &activescalars);
4398  SCIPsetFreeBufferArray(set, &activevars);
4399  SCIPsetFreeBufferArray(set, &tmpscalars2);
4400  SCIPsetFreeBufferArray(set, &tmpvars2);
4401 
4402  return SCIP_OKAY;
4403 }
4404 
4405 
4406 /** flattens aggregation graph of multi-aggregated variable in order to avoid exponential recursion later on */
4408  SCIP_VAR* var, /**< problem variable */
4409  BMS_BLKMEM* blkmem, /**< block memory */
4410  SCIP_SET* set, /**< global SCIP settings */
4411  SCIP_EVENTQUEUE* eventqueue /**< event queue */
4412  )
4413 {
4414  int nlocksup[NLOCKTYPES];
4415  int nlocksdown[NLOCKTYPES];
4416  SCIP_Real multconstant;
4417  int multvarssize;
4418  int nmultvars;
4419  int multrequiredsize;
4420  int i;
4421 
4422  assert( var != NULL );
4423  assert( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR );
4424  assert(var->scip == set->scip);
4425 
4426  /* in order to update the locks on the active representation of the multi-aggregated variable, we remove all locks
4427  * on the current representation now and re-add the locks once the variable graph has been flattened, which
4428  * may lead to duplicate occurences of the same variable being merged
4429  *
4430  * Here is an example. Assume we have the multi-aggregation z = x + y.
4431  * z occures with positive coefficient in a <= constraint c1, so it has an uplock from there.
4432  * When the multi-aggregation is performed, all locks are added to the active representation,
4433  * so x and y both get an uplock from c1. However, z was not yet replaced by x + y in c1.
4434  * Next, a negation y = 1 - x is identified. Again, locks are moved, so that the uplock of y originating
4435  * from c1 is added to x as a downlock. Thus, x has both an up- and downlock from c1.
4436  * The multi-aggregation changes to z = x + 1 - x, which corresponds to the locks.
4437  * However, before z is replaced by that sum, SCIPvarFlattenAggregationGraph() is called
4438  * which changes z = x + y = x + 1 - x = 1, since it merges multiple occurences of the same variable.
4439  * The up- and downlock of x, however, is not removed when replacing z in c1 by its active representation,
4440  * because it is just 1 now. Therefore, we need to update locks when flattening the aggregation graph.
4441  * For this, the multi-aggregated variable knows its locks in addition to adding them to the active
4442  * representation, which corresponds to the locks from constraints where the variable was not replaced yet.
4443  * By removing the locks here, based on the old representation and adding them again after flattening,
4444  * we ensure that the locks are correct afterwards if coefficients were merged.
4445  */
4446  for( i = 0; i < NLOCKTYPES; ++i )
4447  {
4448  nlocksup[i] = var->nlocksup[i];
4449  nlocksdown[i] = var->nlocksdown[i];
4450 
4451  SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, -nlocksdown[i], -nlocksup[i]) );
4452  }
4453 
4454  multconstant = var->data.multaggr.constant;
4455  nmultvars = var->data.multaggr.nvars;
4456  multvarssize = var->data.multaggr.varssize;
4457 
4458  SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) );
4459 
4460  if( multrequiredsize > multvarssize )
4461  {
4462  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.vars), multvarssize, multrequiredsize) );
4463  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.scalars), multvarssize, multrequiredsize) );
4464  multvarssize = multrequiredsize;
4465  SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) );
4466  assert( multrequiredsize <= multvarssize );
4467  }
4468  /**@note After the flattening the multi aggregation might resolve to be in fact an aggregation (or even a fixing?).
4469  * This issue is not resolved right now, since var->data.multaggr.nvars < 2 should not cause troubles. However, one
4470  * may loose performance hereby, since aggregated variables are easier to handle.
4471  *
4472  * Note, that there are two cases where SCIPvarFlattenAggregationGraph() is called: The easier one is that it is
4473  * called while installing the multi-aggregation. in principle, the described issue could be handled straightforward
4474  * in this case by aggregating or fixing the variable instead. The more complicated case is the one, when the
4475  * multi-aggregation is used, e.g., in linear presolving (and the variable is already declared to be multi-aggregated).
4476  *
4477  * By now, it is not allowed to fix or aggregate multi-aggregated variables which would be necessary in this case.
4478  *
4479  * The same issue appears in the SCIPvarGetProbvar...() methods.
4480  */
4481 
4482  var->data.multaggr.constant = multconstant;
4483  var->data.multaggr.nvars = nmultvars;
4484  var->data.multaggr.varssize = multvarssize;
4485 
4486  for( i = 0; i < NLOCKTYPES; ++i )
4487  {
4488  SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) );
4489  }
4490 
4491  return SCIP_OKAY;
4492 }
4493 
4494 /** merge two variable histories together; a typical use case is that \p othervar is an image of the target variable
4495  * in a SCIP copy. Method should be applied with care, especially because no internal checks are performed whether
4496  * the history merge is reasonable
4497  *
4498  * @note Do not use this method if the two variables originate from two SCIP's with different objective functions, since
4499  * this corrupts the variable pseudo costs
4500  * @note Apply with care; no internal checks are performed if the two variables should be merged
4501  */
4503  SCIP_VAR* targetvar, /**< the variable that should contain both histories afterwards */
4504  SCIP_VAR* othervar, /**< the variable whose history is to be merged with that of the target variable */
4505  SCIP_STAT* stat /**< problem statistics */
4506  )
4507 {
4508  /* merge only the history of the current run into the target history */
4509  SCIPhistoryUnite(targetvar->history, othervar->historycrun, FALSE);
4510 
4511  /* apply the changes also to the global history */
4512  SCIPhistoryUnite(stat->glbhistory, othervar->historycrun, FALSE);
4513 }
4514 
4515 /** sets the history of a variable; this method is typically used within reoptimization to keep and update the variable
4516  * history over several iterations
4517  */
4518 void SCIPvarSetHistory(
4519  SCIP_VAR* var, /**< variable */
4520  SCIP_HISTORY* history, /**< the history which is to set */
4521  SCIP_STAT* stat /**< problem statistics */
4522  )
4523 {
4524  /* merge only the history of the current run into the target history */
4525  SCIPhistoryUnite(var->history, history, FALSE);
4526 
4527  /* apply the changes also to the global history */
4528  SCIPhistoryUnite(stat->glbhistory, history, FALSE);
4529 }
4530 
4531 /** tightens the bounds of both variables in aggregation x = a*y + c */
4532 static
4534  SCIP_VAR* var, /**< problem variable */
4535  BMS_BLKMEM* blkmem, /**< block memory */
4536  SCIP_SET* set, /**< global SCIP settings */
4537  SCIP_STAT* stat, /**< problem statistics */
4538  SCIP_PROB* transprob, /**< tranformed problem data */
4539  SCIP_PROB* origprob, /**< original problem data */
4540  SCIP_PRIMAL* primal, /**< primal data */
4541  SCIP_TREE* tree, /**< branch and bound tree */
4542  SCIP_REOPT* reopt, /**< reoptimization data structure */
4543  SCIP_LP* lp, /**< current LP data */
4544  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4545  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
4546  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4547  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
4548  SCIP_VAR* aggvar, /**< variable y in aggregation x = a*y + c */
4549  SCIP_Real scalar, /**< multiplier a in aggregation x = a*y + c */
4550  SCIP_Real constant, /**< constant shift c in aggregation x = a*y + c */
4551  SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
4552  SCIP_Bool* fixed /**< pointer to store whether the variables were fixed */
4553  )
4554 {
4555  SCIP_Real varlb;
4556  SCIP_Real varub;
4557  SCIP_Real aggvarlb;
4558  SCIP_Real aggvarub;
4559  SCIP_Bool aggvarbdschanged;
4560 
4561  assert(var != NULL);
4562  assert(var->scip == set->scip);
4563  assert(aggvar != NULL);
4564  assert(!SCIPsetIsZero(set, scalar));
4565  assert(infeasible != NULL);
4566  assert(fixed != NULL);
4567 
4568  *infeasible = FALSE;
4569  *fixed = FALSE;
4570 
4571  SCIPsetDebugMsg(set, "updating bounds of variables in aggregation <%s> == %g*<%s> %+g\n", var->name, scalar, aggvar->name, constant);
4572  SCIPsetDebugMsg(set, " old bounds: <%s> [%g,%g] <%s> [%g,%g]\n",
4573  var->name, var->glbdom.lb, var->glbdom.ub, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub);
4574 
4575  /* loop as long additional changes may be found */
4576  do
4577  {
4578  aggvarbdschanged = FALSE;
4579 
4580  /* update the bounds of the aggregated variable x in x = a*y + c */
4581  if( scalar > 0.0 )
4582  {
4583  if( SCIPsetIsInfinity(set, -aggvar->glbdom.lb) )
4584  varlb = -SCIPsetInfinity(set);
4585  else
4586  varlb = aggvar->glbdom.lb * scalar + constant;
4587  if( SCIPsetIsInfinity(set, aggvar->glbdom.ub) )
4588  varub = SCIPsetInfinity(set);
4589  else
4590  varub = aggvar->glbdom.ub * scalar + constant;
4591  }
4592  else
4593  {
4594  if( SCIPsetIsInfinity(set, -aggvar->glbdom.lb) )
4595  varub = SCIPsetInfinity(set);
4596  else
4597  varub = aggvar->glbdom.lb * scalar + constant;
4598  if( SCIPsetIsInfinity(set, aggvar->glbdom.ub) )
4599  varlb = -SCIPsetInfinity(set);
4600  else
4601  varlb = aggvar->glbdom.ub * scalar + constant;
4602  }
4603  varlb = MAX(varlb, var->glbdom.lb);
4604  varub = MIN(varub, var->glbdom.ub);
4605  SCIPvarAdjustLb(var, set, &varlb);
4606  SCIPvarAdjustUb(var, set, &varub);
4607 
4608  /* check the new bounds */
4609  if( SCIPsetIsGT(set, varlb, varub) )
4610  {
4611  /* the aggregation is infeasible */
4612  *infeasible = TRUE;
4613  return SCIP_OKAY;
4614  }
4615  else if( SCIPsetIsEQ(set, varlb, varub) )
4616  {
4617  /* the aggregated variable is fixed -> fix both variables */
4618  SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4619  eventfilter, eventqueue, cliquetable, varlb, infeasible, fixed) );
4620  if( !(*infeasible) )
4621  {
4622  SCIP_Bool aggfixed;
4623 
4624  SCIP_CALL( SCIPvarFix(aggvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4625  eventfilter, eventqueue, cliquetable, (varlb-constant)/scalar, infeasible, &aggfixed) );
4626  assert(*fixed == aggfixed);
4627  }
4628  return SCIP_OKAY;
4629  }
4630  else
4631  {
4632  if( SCIPsetIsGT(set, varlb, var->glbdom.lb) )
4633  {
4634  SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, varlb) );
4635  }
4636  if( SCIPsetIsLT(set, varub, var->glbdom.ub) )
4637  {
4638  SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, varub) );
4639  }
4640 
4641  /* update the hole list of the aggregation variable */
4642  /**@todo update hole list of aggregation variable */
4643  }
4644 
4645  /* update the bounds of the aggregation variable y in x = a*y + c -> y = (x-c)/a */
4646  if( scalar > 0.0 )
4647  {
4648  if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
4649  aggvarlb = -SCIPsetInfinity(set);
4650  else
4651  aggvarlb = (var->glbdom.lb - constant) / scalar;
4652  if( SCIPsetIsInfinity(set, var->glbdom.ub) )
4653  aggvarub = SCIPsetInfinity(set);
4654  else
4655  aggvarub = (var->glbdom.ub - constant) / scalar;
4656  }
4657  else
4658  {
4659  if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
4660  aggvarub = SCIPsetInfinity(set);
4661  else
4662  aggvarub = (var->glbdom.lb - constant) / scalar;
4663  if( SCIPsetIsInfinity(set, var->glbdom.ub) )
4664  aggvarlb = -SCIPsetInfinity(set);
4665  else
4666  aggvarlb = (var->glbdom.ub - constant) / scalar;
4667  }
4668  aggvarlb = MAX(aggvarlb, aggvar->glbdom.lb);
4669  aggvarub = MIN(aggvarub, aggvar->glbdom.ub);
4670  SCIPvarAdjustLb(aggvar, set, &aggvarlb);
4671  SCIPvarAdjustUb(aggvar, set, &aggvarub);
4672 
4673  /* check the new bounds */
4674  if( SCIPsetIsGT(set, aggvarlb, aggvarub) )
4675  {
4676  /* the aggregation is infeasible */
4677  *infeasible = TRUE;
4678  return SCIP_OKAY;
4679  }
4680  else if( SCIPsetIsEQ(set, aggvarlb, aggvarub) )
4681  {
4682  /* the aggregation variable is fixed -> fix both variables */
4683  SCIP_CALL( SCIPvarFix(aggvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4684  eventfilter, eventqueue, cliquetable, aggvarlb, infeasible, fixed) );
4685  if( !(*infeasible) )
4686  {
4687  SCIP_Bool varfixed;
4688 
4689  SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4690  eventfilter, eventqueue, cliquetable, aggvarlb * scalar + constant, infeasible, &varfixed) );
4691  assert(*fixed == varfixed);
4692  }
4693  return SCIP_OKAY;
4694  }
4695  else
4696  {
4697  SCIP_Real oldbd;
4698  if( SCIPsetIsGT(set, aggvarlb, aggvar->glbdom.lb) )
4699  {
4700  oldbd = aggvar->glbdom.lb;
4701  SCIP_CALL( SCIPvarChgLbGlobal(aggvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, aggvarlb) );
4702  aggvarbdschanged = !SCIPsetIsEQ(set, oldbd, aggvar->glbdom.lb);
4703  }
4704  if( SCIPsetIsLT(set, aggvarub, aggvar->glbdom.ub) )
4705  {
4706  oldbd = aggvar->glbdom.ub;
4707  SCIP_CALL( SCIPvarChgUbGlobal(aggvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, aggvarub) );
4708  aggvarbdschanged = aggvarbdschanged || !SCIPsetIsEQ(set, oldbd, aggvar->glbdom.ub);
4709  }
4710 
4711  /* update the hole list of the aggregation variable */
4712  /**@todo update hole list of aggregation variable */
4713  }
4714  }
4715  while( aggvarbdschanged );
4716 
4717  SCIPsetDebugMsg(set, " new bounds: <%s> [%g,%g] <%s> [%g,%g]\n",
4718  var->name, var->glbdom.lb, var->glbdom.ub, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub);
4719 
4720  return SCIP_OKAY;
4721 }
4722 
4723 /** converts loose variable into aggregated variable */
4725  SCIP_VAR* var, /**< loose problem variable */
4726  BMS_BLKMEM* blkmem, /**< block memory */
4727  SCIP_SET* set, /**< global SCIP settings */
4728  SCIP_STAT* stat, /**< problem statistics */
4729  SCIP_PROB* transprob, /**< tranformed problem data */
4730  SCIP_PROB* origprob, /**< original problem data */
4731  SCIP_PRIMAL* primal, /**< primal data */
4732  SCIP_TREE* tree, /**< branch and bound tree */
4733  SCIP_REOPT* reopt, /**< reoptimization data structure */
4734  SCIP_LP* lp, /**< current LP data */
4735  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
4736  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4737  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
4738  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4739  SCIP_VAR* aggvar, /**< loose variable y in aggregation x = a*y + c */
4740  SCIP_Real scalar, /**< multiplier a in aggregation x = a*y + c */
4741  SCIP_Real constant, /**< constant shift c in aggregation x = a*y + c */
4742  SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
4743  SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
4744  )
4745 {
4746  SCIP_VAR** vars;
4747  SCIP_Real* coefs;
4748  SCIP_Real* constants;
4749  SCIP_Real obj;
4750  SCIP_Real branchfactor;
4751  SCIP_Bool fixed;
4752  int branchpriority;
4753  int nlocksdown[NLOCKTYPES];
4754  int nlocksup[NLOCKTYPES];
4755  int nvbds;
4756  int i;
4757  int j;
4758 
4759  assert(var != NULL);
4760  assert(aggvar != NULL);
4761  assert(var->scip == set->scip);
4762  assert(var->glbdom.lb == var->locdom.lb); /*lint !e777*/
4763  assert(var->glbdom.ub == var->locdom.ub); /*lint !e777*/
4764  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
4765  assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
4766  assert(infeasible != NULL);
4767  assert(aggregated != NULL);
4768 
4769  /* check aggregation on debugging solution */
4770  SCIP_CALL( SCIPdebugCheckAggregation(set, var, &aggvar, &scalar, constant, 1) ); /*lint !e506 !e774*/
4771 
4772  *infeasible = FALSE;
4773  *aggregated = FALSE;
4774 
4775  /* get active problem variable of aggregation variable */
4776  SCIP_CALL( SCIPvarGetProbvarSum(&aggvar, set, &scalar, &constant) );
4777 
4778  /* aggregation is a fixing, if the scalar is zero */
4779  if( SCIPsetIsZero(set, scalar) )
4780  {
4781  SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventfilter,
4782  eventqueue, cliquetable, constant, infeasible, aggregated) );
4783  return SCIP_OKAY;
4784  }
4785 
4786  /* don't perform the aggregation if the aggregation variable is multi-aggregated itself */
4787  if( SCIPvarGetStatus(aggvar) == SCIP_VARSTATUS_MULTAGGR )
4788  return SCIP_OKAY;
4789 
4790  /**@todo currently we don't perform the aggregation if the aggregation variable has a non-empty hole list; this
4791  * should be changed in the future
4792  */
4793  if( SCIPvarGetHolelistGlobal(var) != NULL )
4794  return SCIP_OKAY;
4795 
4796  /* if the variable is not allowed to be aggregated */
4797  if( SCIPvarDoNotAggr(var) )
4798  {
4799  SCIPsetDebugMsg(set, "variable is not allowed to be aggregated.\n");
4800  return SCIP_OKAY;
4801  }
4802 
4803  assert(aggvar->glbdom.lb == aggvar->locdom.lb); /*lint !e777*/
4804  assert(aggvar->glbdom.ub == aggvar->locdom.ub); /*lint !e777*/
4805  assert(SCIPvarGetStatus(aggvar) == SCIP_VARSTATUS_LOOSE);
4806 
4807  SCIPsetDebugMsg(set, "aggregate variable <%s>[%g,%g] == %g*<%s>[%g,%g] %+g\n", var->name, var->glbdom.lb, var->glbdom.ub,
4808  scalar, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub, constant);
4809 
4810  /* if variable and aggregation variable are equal, the variable can be fixed: x == a*x + c => x == c/(1-a) */
4811  if( var == aggvar )
4812  {
4813  if( SCIPsetIsEQ(set, scalar, 1.0) )
4814  *infeasible = !SCIPsetIsZero(set, constant);
4815  else
4816  {
4817  SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4818  eventfilter, eventqueue, cliquetable, constant/(1.0-scalar), infeasible, aggregated) );
4819  }
4820  return SCIP_OKAY;
4821  }
4822 
4823  /* tighten the bounds of aggregated and aggregation variable */
4824  SCIP_CALL( varUpdateAggregationBounds(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
4825  branchcand, eventfilter, eventqueue, cliquetable, aggvar, scalar, constant, infeasible, &fixed) );
4826  if( *infeasible || fixed )
4827  {
4828  *aggregated = fixed;
4829  return SCIP_OKAY;
4830  }
4831 
4832  /* delete implications and variable bounds of the aggregated variable from other variables, but keep them in the
4833  * aggregated variable
4834  */
4835  SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, FALSE) );
4836  assert(var->cliquelist == NULL);
4837 
4838  /* set the aggregated variable's objective value to 0.0 */
4839  obj = var->obj;
4840  SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
4841 
4842  /* unlock all locks */
4843  for( i = 0; i < NLOCKTYPES; i++ )
4844  {
4845  nlocksdown[i] = var->nlocksdown[i];
4846  nlocksup[i] = var->nlocksup[i];
4847 
4848  var->nlocksdown[i] = 0;
4849  var->nlocksup[i] = 0;
4850  }
4851 
4852  /* check, if variable should be used as NEGATED variable of the aggregation variable */
4853  if( SCIPvarIsBinary(var) && SCIPvarIsBinary(aggvar)
4854  && var->negatedvar == NULL && aggvar->negatedvar == NULL
4855  && SCIPsetIsEQ(set, scalar, -1.0) && SCIPsetIsEQ(set, constant, 1.0) )
4856  {
4857  /* link both variables as negation pair */
4858  var->varstatus = SCIP_VARSTATUS_NEGATED; /*lint !e641*/
4859  var->data.negate.constant = 1.0;
4860  var->negatedvar = aggvar;
4861  aggvar->negatedvar = var;
4862 
4863  /* copy donot(mult)aggr status */
4864  aggvar->donotaggr |= var->donotaggr;
4865  aggvar->donotmultaggr |= var->donotmultaggr;
4866 
4867  /* mark both variables to be non-deletable */
4869  SCIPvarMarkNotDeletable(aggvar);
4870  }
4871  else
4872  {
4873  /* convert variable into aggregated variable */
4874  var->varstatus = SCIP_VARSTATUS_AGGREGATED; /*lint !e641*/
4875  var->data.aggregate.var = aggvar;
4876  var->data.aggregate.scalar = scalar;
4877  var->data.aggregate.constant = constant;
4878 
4879  /* copy donot(mult)aggr status */
4880  aggvar->donotaggr |= var->donotaggr;
4881  aggvar->donotmultaggr |= var->donotmultaggr;
4882 
4883  /* mark both variables to be non-deletable */
4885  SCIPvarMarkNotDeletable(aggvar);
4886  }
4887 
4888  /* make aggregated variable a parent of the aggregation variable */
4889  SCIP_CALL( varAddParent(aggvar, blkmem, set, var) );
4890 
4891  /* relock the variable, thus increasing the locks of the aggregation variable */
4892  for( i = 0; i < NLOCKTYPES; i++ )
4893  {
4894  SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) );
4895  }
4896 
4897  /* move the variable bounds to the aggregation variable:
4898  * - add all variable bounds again to the variable, thus adding it to the aggregation variable
4899  * - free the variable bounds data structures
4900  */
4901  if( var->vlbs != NULL )
4902  {
4903  nvbds = SCIPvboundsGetNVbds(var->vlbs);
4904  vars = SCIPvboundsGetVars(var->vlbs);
4905  coefs = SCIPvboundsGetCoefs(var->vlbs);
4906  constants = SCIPvboundsGetConstants(var->vlbs);
4907  for( i = 0; i < nvbds && !(*infeasible); ++i )
4908  {
4909  SCIP_CALL( SCIPvarAddVlb(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
4910  eventqueue, vars[i], coefs[i], constants[i], FALSE, infeasible, NULL) );
4911  }
4912  }
4913  if( var->vubs != NULL )
4914  {
4915  nvbds = SCIPvboundsGetNVbds(var->vubs);
4916  vars = SCIPvboundsGetVars(var->vubs);
4917  coefs = SCIPvboundsGetCoefs(var->vubs);
4918  constants = SCIPvboundsGetConstants(var->vubs);
4919  for( i = 0; i < nvbds && !(*infeasible); ++i )
4920  {
4921  SCIP_CALL( SCIPvarAddVub(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
4922  eventqueue, vars[i], coefs[i], constants[i], FALSE, infeasible, NULL) );
4923  }
4924  }
4925  SCIPvboundsFree(&var->vlbs, blkmem);
4926  SCIPvboundsFree(&var->vubs, blkmem);
4927 
4928  /* move the implications to the aggregation variable:
4929  * - add all implications again to the variable, thus adding it to the aggregation variable
4930  * - free the implications data structures
4931  */
4932  if( var->implics != NULL && SCIPvarGetType(aggvar) == SCIP_VARTYPE_BINARY )
4933  {
4934  assert(SCIPvarIsBinary(var));
4935  for( i = 0; i < 2; ++i )
4936  {
4937  SCIP_VAR** implvars;
4938  SCIP_BOUNDTYPE* impltypes;
4939  SCIP_Real* implbounds;
4940  int nimpls;
4941 
4942  nimpls = SCIPimplicsGetNImpls(var->implics, (SCIP_Bool)i);
4943  implvars = SCIPimplicsGetVars(var->implics, (SCIP_Bool)i);
4944  impltypes = SCIPimplicsGetTypes(var->implics, (SCIP_Bool)i);
4945  implbounds = SCIPimplicsGetBounds(var->implics, (SCIP_Bool)i);
4946 
4947  for( j = 0; j < nimpls && !(*infeasible); ++j )
4948  {
4949  /* @todo can't we omit transitive closure, because it should already have been done when adding the
4950  * implication to the aggregated variable?
4951  */
4952  SCIP_CALL( SCIPvarAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
4953  branchcand, eventqueue, (SCIP_Bool)i, implvars[j], impltypes[j], implbounds[j], FALSE, infeasible,
4954  NULL) );
4955  assert(nimpls == SCIPimplicsGetNImpls(var->implics, (SCIP_Bool)i));
4956  }
4957  }
4958  }
4959  SCIPimplicsFree(&var->implics, blkmem);
4960 
4961  /* add the history entries to the aggregation variable and clear the history of the aggregated variable */
4962  SCIPhistoryUnite(aggvar->history, var->history, scalar < 0.0);
4963  SCIPhistoryUnite(aggvar->historycrun, var->historycrun, scalar < 0.0);
4964  SCIPhistoryReset(var->history);
4966 
4967  /* update flags of aggregation variable */
4968  aggvar->removable &= var->removable;
4969 
4970  /* update branching factors and priorities of both variables to be the maximum of both variables */
4971  branchfactor = MAX(aggvar->branchfactor, var->branchfactor);
4972  branchpriority = MAX(aggvar->branchpriority, var->branchpriority);
4973  SCIP_CALL( SCIPvarChgBranchFactor(aggvar, set, branchfactor) );
4974  SCIP_CALL( SCIPvarChgBranchPriority(aggvar, branchpriority) );
4975  SCIP_CALL( SCIPvarChgBranchFactor(var, set, branchfactor) );
4976  SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) );
4977 
4978  /* update branching direction of both variables to agree to a single direction */
4979  if( scalar >= 0.0 )
4980  {
4982  {
4984  }
4985  else if( (SCIP_BRANCHDIR)aggvar->branchdirection == SCIP_BRANCHDIR_AUTO )
4986  {
4988  }
4989  else if( var->branchdirection != aggvar->branchdirection )
4990  {
4992  }
4993  }
4994  else
4995  {
4997  {
4999  }
5000  else if( (SCIP_BRANCHDIR)aggvar->branchdirection == SCIP_BRANCHDIR_AUTO )
5001  {
5003  }
5004  else if( var->branchdirection != aggvar->branchdirection )
5005  {
5007  }
5008  }
5009 
5010  if( var->probindex != -1 )
5011  {
5012  /* inform problem about the variable's status change */
5013  SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) );
5014  }
5015 
5016  /* reset the objective value of the aggregated variable, thus adjusting the objective value of the aggregation
5017  * variable and the problem's objective offset
5018  */
5019  SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) );
5020 
5021  /* issue VARFIXED event */
5022  SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 1) );
5023 
5024  *aggregated = TRUE;
5025 
5026  return SCIP_OKAY;
5027 }
5028 
5029 /** Tries to aggregate an equality a*x + b*y == c consisting of two (implicit) integral active problem variables x and
5030  * y. An integer aggregation (i.e. integral coefficients a' and b', such that a'*x + b'*y == c') is searched.
5031  *
5032  * This can lead to the detection of infeasibility (e.g. if c' is fractional), or to a rejection of the aggregation
5033  * (denoted by aggregated == FALSE), if the resulting integer coefficients are too large and thus numerically instable.
5034  */
5035 static
5037  SCIP_SET* set, /**< global SCIP settings */
5038  BMS_BLKMEM* blkmem, /**< block memory */
5039  SCIP_STAT* stat, /**< problem statistics */
5040  SCIP_PROB* transprob, /**< tranformed problem data */
5041  SCIP_PROB* origprob, /**< original problem data */
5042  SCIP_PRIMAL* primal, /**< primal data */
5043  SCIP_TREE* tree, /**< branch and bound tree */
5044  SCIP_REOPT* reopt, /**< reoptimization data structure */
5045  SCIP_LP* lp, /**< current LP data */
5046  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
5047  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
5048  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
5049  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5050  SCIP_VAR* varx, /**< integral variable x in equality a*x + b*y == c */
5051  SCIP_VAR* vary, /**< integral variable y in equality a*x + b*y == c */
5052  SCIP_Real scalarx, /**< multiplier a in equality a*x + b*y == c */
5053  SCIP_Real scalary, /**< multiplier b in equality a*x + b*y == c */
5054  SCIP_Real rhs, /**< right hand side c in equality a*x + b*y == c */
5055  SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
5056  SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
5057  )
5058 {
5059  SCIP_VAR* aggvar;
5060  char aggvarname[SCIP_MAXSTRLEN];
5061  SCIP_Longint scalarxn = 0;
5062  SCIP_Longint scalarxd = 0;
5063  SCIP_Longint scalaryn = 0;
5064  SCIP_Longint scalaryd = 0;
5065  SCIP_Longint a;
5066  SCIP_Longint b;
5067  SCIP_Longint c;
5068  SCIP_Longint scm;
5069  SCIP_Longint gcd;
5070  SCIP_Longint currentclass;
5071  SCIP_Longint classstep;
5072  SCIP_Longint xsol;
5073  SCIP_Longint ysol;
5074  SCIP_Bool success;
5075  SCIP_VARTYPE vartype;
5076 
5077 #define MAXDNOM 1000000LL
5078 
5079  assert(set != NULL);
5080  assert(blkmem != NULL);
5081  assert(stat != NULL);
5082  assert(transprob != NULL);
5083  assert(origprob != NULL);
5084  assert(tree != NULL);
5085  assert(lp != NULL);
5086  assert(cliquetable != NULL);
5087  assert(branchcand != NULL);
5088  assert(eventqueue != NULL);
5089  assert(varx != NULL);
5090  assert(vary != NULL);
5091  assert(varx != vary);
5092  assert(infeasible != NULL);
5093  assert(aggregated != NULL);
5094  assert(SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING);
5095  assert(SCIPvarGetStatus(varx) == SCIP_VARSTATUS_LOOSE);
5097  assert(SCIPvarGetStatus(vary) == SCIP_VARSTATUS_LOOSE);
5099  assert(!SCIPsetIsZero(set, scalarx));
5100  assert(!SCIPsetIsZero(set, scalary));
5101 
5102  *infeasible = FALSE;
5103  *aggregated = FALSE;
5104 
5105  /* if the variable is not allowed to be aggregated */
5106  if( SCIPvarDoNotAggr(varx) )
5107  {
5108  SCIPsetDebugMsg(set, "variable is not allowed to be aggregated.\n");
5109  return SCIP_OKAY;
5110  }
5111 
5112  /* get rational representation of coefficients */
5113  success = SCIPrealToRational(scalarx, -SCIPsetEpsilon(set), SCIPsetEpsilon(set), MAXDNOM, &scalarxn, &scalarxd);
5114  if( success )
5115  success = SCIPrealToRational(scalary, -SCIPsetEpsilon(set), SCIPsetEpsilon(set), MAXDNOM, &scalaryn, &scalaryd);
5116  if( !success )
5117  return SCIP_OKAY;
5118  assert(scalarxd >= 1);
5119  assert(scalaryd >= 1);
5120 
5121  /* multiply equality with smallest common denominator */
5122  scm = SCIPcalcSmaComMul(scalarxd, scalaryd);
5123  a = (scm/scalarxd)*scalarxn;
5124  b = (scm/scalaryd)*scalaryn;
5125  rhs *= scm;
5126 
5127  /* divide equality by the greatest common divisor of a and b */
5128  gcd = SCIPcalcGreComDiv(ABS(a), ABS(b));
5129  a /= gcd;
5130  b /= gcd;
5131  rhs /= gcd;
5132  assert(a != 0);
5133  assert(b != 0);
5134 
5135