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
143 SCIP_RETCODE holelistCreate(
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
193 SCIP_RETCODE holelistDuplicate(
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
215 SCIP_RETCODE domAddHole(
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
418 SCIP_RETCODE varEnsureLbchginfosSize(
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
444 SCIP_RETCODE varEnsureUbchginfosSize(
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
470 SCIP_RETCODE varAddLbchginfo(
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 {
520 case SCIP_BOUNDCHGTYPE_BRANCHING:
521 break;
522 case SCIP_BOUNDCHGTYPE_CONSINFER:
523 assert(infercons != NULL);
524 var->lbchginfos[var->nlbchginfos].inferencedata.reason.cons = infercons;
525 break;
526 case SCIP_BOUNDCHGTYPE_PROPINFER:
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
537 || SCIPbdchgidxIsEarlier(&var->lbchginfos[var->nlbchginfos-2].bdchgidx,
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
545 SCIP_RETCODE varAddUbchginfo(
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 {
595 case SCIP_BOUNDCHGTYPE_BRANCHING:
596 break;
597 case SCIP_BOUNDCHGTYPE_CONSINFER:
598 assert(infercons != NULL);
599 var->ubchginfos[var->nubchginfos].inferencedata.reason.cons = infercons;
600 break;
601 case SCIP_BOUNDCHGTYPE_PROPINFER:
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
612 || SCIPbdchgidxIsEarlier(&var->ubchginfos[var->nubchginfos-2].bdchgidx,
613 &var->ubchginfos[var->nubchginfos-1].bdchgidx));
614
615 return SCIP_OKAY;
616 }
617
618 /** applies single bound change */
619 SCIP_RETCODE SCIPboundchgApply(
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);
648 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
649 assert(!SCIPvarIsIntegral(var) || SCIPsetIsFeasIntegral(set, boundchg->newbound));
650
651 /* apply bound change */
652 switch( boundchg->boundtype )
653 {
654 case SCIP_BOUNDTYPE_LOWER:
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 {
663 case SCIP_BOUNDCHGTYPE_BRANCHING:
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,
667 NULL, NULL, NULL, 0, SCIP_BOUNDTYPE_LOWER, SCIP_BOUNDCHGTYPE_BRANCHING) );
668 stat->lastbranchvar = var;
669 stat->lastbranchdir = SCIP_BRANCHDIR_UPWARDS;
670 stat->lastbranchvalue = boundchg->newbound;
671 break;
672
673 case SCIP_BOUNDCHGTYPE_CONSINFER:
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,
681 (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_CONSINFER) );
682 break;
683
684 case SCIP_BOUNDCHGTYPE_PROPINFER:
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,
692 (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_PROPINFER) );
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
721 case SCIP_BOUNDTYPE_UPPER:
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 {
730 case SCIP_BOUNDCHGTYPE_BRANCHING:
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,
734 NULL, NULL, NULL, 0, SCIP_BOUNDTYPE_UPPER, SCIP_BOUNDCHGTYPE_BRANCHING) );
735 stat->lastbranchvar = var;
736 stat->lastbranchdir = SCIP_BRANCHDIR_DOWNWARDS;
737 stat->lastbranchvalue = boundchg->newbound;
738 break;
739
740 case SCIP_BOUNDCHGTYPE_CONSINFER:
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,
748 (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_CONSINFER) );
749 break;
750
751 case SCIP_BOUNDCHGTYPE_PROPINFER:
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,
759 (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_PROPINFER) );
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
798 if( (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING )
799 {
800 SCIP_CALL( SCIPvarIncNBranchings(var, blkmem, set, stat,
801 (SCIP_BOUNDTYPE)boundchg->boundtype == SCIP_BOUNDTYPE_LOWER
802 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS, boundchg->newbound, depth) );
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 */
816 SCIP_RETCODE SCIPboundchgUndo(
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);
837 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
838
839 /* undo bound change: apply the previous bound change of variable */
840 switch( boundchg->boundtype )
841 {
842 case SCIP_BOUNDTYPE_LOWER:
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,
851 var->lbchginfos[var->nlbchginfos].bdchgidx.depth, var->lbchginfos[var->nlbchginfos].bdchgidx.pos,
852 var->lbchginfos[var->nlbchginfos].oldbound, var->lbchginfos[var->nlbchginfos].newbound);
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
863 case SCIP_BOUNDTYPE_UPPER:
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,
872 var->ubchginfos[var->nubchginfos].bdchgidx.depth, var->ubchginfos[var->nubchginfos].bdchgidx.pos,
873 var->ubchginfos[var->nubchginfos].oldbound, var->ubchginfos[var->nubchginfos].newbound);
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 */
890 if( (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING )
891 {
892 stat->lastbranchvar = NULL;
893 stat->lastbranchvalue = SCIP_UNKNOWN;
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
901 SCIP_RETCODE boundchgApplyGlobal(
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",
942 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var),
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
961 SCIP_RETCODE boundchgCaptureData(
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 {
973 case SCIP_BOUNDCHGTYPE_BRANCHING:
974 case SCIP_BOUNDCHGTYPE_PROPINFER:
975 break;
976
977 case SCIP_BOUNDCHGTYPE_CONSINFER:
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
993 SCIP_RETCODE boundchgReleaseData(
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 {
1006 case SCIP_BOUNDCHGTYPE_BRANCHING:
1007 case SCIP_BOUNDCHGTYPE_PROPINFER:
1008 break;
1009
1010 case SCIP_BOUNDCHGTYPE_CONSINFER:
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
1030 SCIP_RETCODE domchgCreate(
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 */
1051 SCIP_RETCODE SCIPdomchgFree(
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;
1084 case SCIP_DOMCHGTYPE_DYNAMIC:
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
1100 SCIP_RETCODE domchgMakeDynamic(
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;
1132 case SCIP_DOMCHGTYPE_DYNAMIC:
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 */
1152 SCIP_RETCODE SCIPdomchgMakeStatic(
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;
1189 case SCIP_DOMCHGTYPE_DYNAMIC:
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
1241 SCIP_RETCODE domchgEnsureBoundchgsSize(
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
1266 SCIP_RETCODE domchgEnsureHolechgsSize(
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 */
1290 SCIP_RETCODE SCIPdomchgApply(
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 */
1339 SCIP_RETCODE SCIPdomchgUndo(
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 */
1374 SCIP_RETCODE SCIPdomchgApplyGlobal(
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 */
1413 SCIP_RETCODE SCIPdomchgAddBoundchg(
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);
1433 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
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 {
1465 case SCIP_BOUNDCHGTYPE_BRANCHING:
1466 boundchg->data.branchingdata.lpsolval = lpsolval;
1467 break;
1468 case SCIP_BOUNDCHGTYPE_CONSINFER:
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;
1474 case SCIP_BOUNDCHGTYPE_PROPINFER:
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 */
1510 SCIP_RETCODE SCIPdomchgAddHolechg(
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
1559 SCIP_Real adjustedLb(
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
1579 SCIP_Real adjustedUb(
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 */
1600 SCIP_RETCODE SCIPvarRemoveCliquesImplicsVbs(
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);
1614 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
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
1891 SCIP_RETCODE varSetName(
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
1923 SCIP_RETCODE varCreate(
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 */
2068 SCIP_RETCODE SCIPvarCreateOriginal(
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 */
2111 SCIP_RETCODE SCIPvarCreateTransformed(
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 */
2153 SCIP_RETCODE SCIPvarCopy(
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
2266 SCIP_RETCODE parseValue(
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
2298 SCIP_RETCODE parseBounds(
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
2342 SCIP_RETCODE varParse(
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 */
2489 SCIP_RETCODE SCIPvarParseOriginal(
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 */
2553 SCIP_RETCODE SCIPvarParseTransformed(
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
2612 SCIP_RETCODE varEnsureParentvarsSize(
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
2636 SCIP_RETCODE varAddParent(
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
2664 SCIP_RETCODE varFreeParents(
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 {
2686 case SCIP_VARSTATUS_ORIGINAL:
2687 assert(parentvar->data.original.transvar == *var);
2688 assert(&parentvar->data.original.transvar != var);
2689 parentvar->data.original.transvar = NULL;
2690 break;
2691
2692 case SCIP_VARSTATUS_AGGREGATED:
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? */
2700 case SCIP_VARSTATUS_MULTAGGR:
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
2714 case SCIP_VARSTATUS_NEGATED:
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
2737 SCIP_RETCODE varFree(
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 {
2757 case SCIP_VARSTATUS_ORIGINAL:
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:
2768 case SCIP_VARSTATUS_AGGREGATED:
2769 break;
2770 case SCIP_VARSTATUS_MULTAGGR:
2771 BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.vars, (*var)->data.multaggr.varssize);
2772 BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.scalars, (*var)->data.multaggr.varssize);
2773 break;
2774 case SCIP_VARSTATUS_NEGATED:
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 */
2785 if( SCIPvarGetStatus(*var) == SCIP_VARSTATUS_ORIGINAL )
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 */
2865 SCIP_RETCODE SCIPvarRelease(
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 */
2906 SCIP_RETCODE SCIPvarChgName(
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
2930 SCIPhistoryReset(var->historycrun);
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 */
2999 SCIP_RETCODE SCIPvarPrint(
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;
3026 case SCIP_VARTYPE_CONTINUOUS:
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 {
3092 case SCIP_VARSTATUS_ORIGINAL:
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
3107 case SCIP_VARSTATUS_AGGREGATED:
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
3114 case SCIP_VARSTATUS_MULTAGGR:
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
3122 case SCIP_VARSTATUS_NEGATED:
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
3139 SCIP_RETCODE varEventVarUnlocked(
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 */
3160 SCIP_RETCODE SCIPvarAddLocks(
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 {
3194 case SCIP_VARSTATUS_ORIGINAL:
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;
3226 case SCIP_VARSTATUS_AGGREGATED:
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;
3239 case SCIP_VARSTATUS_MULTAGGR:
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 }
3266 case SCIP_VARSTATUS_NEGATED:
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 */
3288 int SCIPvarGetNLocksDownType(
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 {
3302 case SCIP_VARSTATUS_ORIGINAL:
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
3313 case SCIP_VARSTATUS_AGGREGATED:
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
3320 case SCIP_VARSTATUS_MULTAGGR:
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
3332 case SCIP_VARSTATUS_NEGATED:
3333 assert(var->negatedvar != NULL);
3334 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
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 */
3346 int SCIPvarGetNLocksUpType(
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 {
3360 case SCIP_VARSTATUS_ORIGINAL:
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
3371 case SCIP_VARSTATUS_AGGREGATED:
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
3378 case SCIP_VARSTATUS_MULTAGGR:
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
3390 case SCIP_VARSTATUS_NEGATED:
3391 assert(var->negatedvar != NULL);
3392 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
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 */
3409 int SCIPvarGetNLocksDown(
3410 SCIP_VAR* var /**< problem variable */
3411 )
3412 {
3413 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL);
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 {
3426 return SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
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 */
3433 SCIP_Bool SCIPvarMayRoundDown(
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 */
3444 SCIP_Bool SCIPvarMayRoundUp(
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 */
3454 SCIP_RETCODE SCIPvarTransform(
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 */
3541 SCIP_RETCODE SCIPvarGetTransformed(
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);
3550 assert(SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_NEGATED);
3551 assert(origvar->scip == set->scip);
3552
3553 if( SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_NEGATED )
3554 {
3555 assert(origvar->negatedvar != NULL);
3556 assert(SCIPvarGetStatus(origvar->negatedvar) == SCIP_VARSTATUS_ORIGINAL);
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 */
3572 SCIP_RETCODE SCIPvarColumn(
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 */
3606 SCIP_RETCODE SCIPvarLoose(
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
3647 SCIP_RETCODE varEventVarFixed(
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 {
3672 assert(SCIPvarGetStatus(var->parentvars[i]) != SCIP_VARSTATUS_MULTAGGR);
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 */
3742 SCIP_RETCODE SCIPvarFix(
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
3777 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED )
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 {
3794 case SCIP_VARSTATUS_ORIGINAL:
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);
3839 SCIPhistoryReset(var->historycrun);
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
3868 case SCIP_VARSTATUS_AGGREGATED:
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
3880 case SCIP_VARSTATUS_MULTAGGR:
3881 SCIPerrorMessage("cannot fix a multiple aggregated variable\n");
3882 SCIPABORT();
3883 return SCIP_INVALIDDATA; /*lint !e527*/
3884
3885 case SCIP_VARSTATUS_NEGATED:
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);
3889 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
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 */
3912 SCIP_RETCODE SCIPvarGetActiveRepresentatives(
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
4019 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR
4020 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
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
4070 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR
4071 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
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
4090 case SCIP_VARSTATUS_MULTAGGR:
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
4129 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR
4130 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
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:
4294 case SCIP_VARSTATUS_ORIGINAL:
4295 case SCIP_VARSTATUS_AGGREGATED:
4296 case SCIP_VARSTATUS_NEGATED:
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 */
4407 SCIP_RETCODE SCIPvarFlattenAggregationGraph(
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 */
4502 void SCIPvarMergeHistories(
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
4533 SCIP_RETCODE varUpdateAggregationBounds(
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 */
4724 SCIP_RETCODE SCIPvarAggregate(
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 */
4868 SCIPvarMarkNotDeletable(var);
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 */
4884 SCIPvarMarkNotDeletable(var);
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);
4965 SCIPhistoryReset(var->historycrun);
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 {
4981 if( (SCIP_BRANCHDIR)var->branchdirection == SCIP_BRANCHDIR_AUTO )
4982 {
4983 SCIP_CALL( SCIPvarChgBranchDirection(var, (SCIP_BRANCHDIR)aggvar->branchdirection) );
4984 }
4985 else if( (SCIP_BRANCHDIR)aggvar->branchdirection == SCIP_BRANCHDIR_AUTO )
4986 {
4987 SCIP_CALL( SCIPvarChgBranchDirection(aggvar, (SCIP_BRANCHDIR)var->branchdirection) );
4988 }
4989 else if( var->branchdirection != aggvar->branchdirection )
4990 {
4991 SCIP_CALL( SCIPvarChgBranchDirection(var, SCIP_BRANCHDIR_AUTO) );
4992 }
4993 }
4994 else
4995 {
4996 if( (SCIP_BRANCHDIR)var->branchdirection == SCIP_BRANCHDIR_AUTO )
4997 {
4998 SCIP_CALL( SCIPvarChgBranchDirection(var, SCIPbranchdirOpposite((SCIP_BRANCHDIR)aggvar->branchdirection)) );
4999 }
5000 else if( (SCIP_BRANCHDIR)aggvar->branchdirection == SCIP_BRANCHDIR_AUTO )
5001 {
5002 SCIP_CALL( SCIPvarChgBranchDirection(aggvar, SCIPbranchdirOpposite((SCIP_BRANCHDIR)var->branchdirection)) );
5003 }
5004 else if( var->branchdirection != aggvar->branchdirection )
5005 {
5006 SCIP_CALL( SCIPvarChgBranchDirection(var, SCIP_BRANCHDIR_AUTO) );
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
5036 SCIP_RETCODE tryAggregateIntVars(
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);
5096 assert(SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(varx) == SCIP_VARTYPE_IMPLINT);
5097 assert(SCIPvarGetStatus(vary) == SCIP_VARSTATUS_LOOSE);
5098 assert(SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vary) == SCIP_VARTYPE_IMPLINT);
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 /* check, if right hand side is integral */
5136 if( !SCIPsetIsFeasIntegral(set, rhs) )
5137 {
5138 *infeasible = TRUE;
5139 return SCIP_OKAY;
5140 }
5141 c = (SCIP_Longint)(SCIPsetFeasFloor(set, rhs));
5142
5143 /* check that the scalar and constant in the aggregation are not too large to avoid numerical problems */
5144 if( REALABS((SCIP_Real)(c/a)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) /*lint !e653*/
5145 || REALABS((SCIP_Real)(b)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) /*lint !e653*/
5146 || REALABS((SCIP_Real)(a)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) ) /*lint !e653*/
5147 {
5148 return SCIP_OKAY;
5149 }
5150
5151 /* check, if we are in an easy case with either |a| = 1 or |b| = 1 */
5152 if( (a == 1 || a == -1) && SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER )
5153 {
5154 /* aggregate x = - b/a*y + c/a */
5155 /*lint --e{653}*/
5156 SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5157 branchcand, eventfilter, eventqueue, vary, (SCIP_Real)(-b/a), (SCIP_Real)(c/a), infeasible, aggregated) );
5158 assert(*aggregated);
5159 return SCIP_OKAY;
5160 }
5161 if( (b == 1 || b == -1) && SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER )
5162 {
5163 /* aggregate y = - a/b*x + c/b */
5164 /*lint --e{653}*/
5165 SCIP_CALL( SCIPvarAggregate(vary, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5166 branchcand, eventfilter, eventqueue, varx, (SCIP_Real)(-a/b), (SCIP_Real)(c/b), infeasible, aggregated) );
5167 assert(*aggregated);
5168 return SCIP_OKAY;
5169 }
5170
5171 /* Both variables are integers, their coefficients are not multiples of each other, and they don't have any
5172 * common divisor. Let (x',y') be a solution of the equality
5173 * a*x + b*y == c -> a*x == c - b*y
5174 * Then x = -b*z + x', y = a*z + y' with z integral gives all solutions to the equality.
5175 */
5176
5177 /* find initial solution (x',y'):
5178 * - find y' such that c - b*y' is a multiple of a
5179 * - start in equivalence class c%a
5180 * - step through classes, where each step increases class number by (-b)%a, until class 0 is visited
5181 * - if equivalence class 0 is visited, we are done: y' equals the number of steps taken
5182 * - because a and b don't have a common divisor, each class is visited at most once, and at most a-1 steps are needed
5183 * - calculate x' with x' = (c - b*y')/a (which must be integral)
5184 *
5185 * Algorithm works for a > 0 only.
5186 */
5187 if( a < 0 )
5188 {
5189 a = -a;
5190 b = -b;
5191 c = -c;
5192 }
5193 assert(a > 0);
5194
5195 /* search upwards from ysol = 0 */
5196 ysol = 0;
5197 currentclass = c % a;
5198 if( currentclass < 0 )
5199 currentclass += a;
5200 assert(0 <= currentclass && currentclass < a);
5201
5202 classstep = (-b) % a;
5203
5204 if( classstep < 0 )
5205 classstep += a;
5206 assert(0 <= classstep && classstep < a);
5207
5208 while( currentclass != 0 )
5209 {
5210 assert(0 <= currentclass && currentclass < a);
5211 currentclass += classstep;
5212 if( currentclass >= a )
5213 currentclass -= a;
5214 ysol++;
5215 }
5216 assert(ysol < a);
5217 assert(((c - b*ysol) % a) == 0);
5218
5219 xsol = (c - b*ysol)/a;
5220
5221 /* determine variable type for new artificial variable:
5222 *
5223 * if both variables are implicit integer the new variable can be implicit too, because the integer implication on
5224 * these both variables should be enforced by some other variables, otherwise the new variable needs to be of
5225 * integral type
5226 */
5227 vartype = ((SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER)
5228 ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_IMPLINT);
5229
5230 /* feasible solutions are (x,y) = (x',y') + z*(-b,a)
5231 * - create new integer variable z with infinite bounds
5232 * - aggregate variable x = -b*z + x'
5233 * - aggregate variable y = a*z + y'
5234 * - the bounds of z are calculated automatically during aggregation
5235 */
5236 (void) SCIPsnprintf(aggvarname, SCIP_MAXSTRLEN, "agg%d", stat->nvaridx);
5237 SCIP_CALL( SCIPvarCreateTransformed(&aggvar, blkmem, set, stat,
5238 aggvarname, -SCIPsetInfinity(set), SCIPsetInfinity(set), 0.0, vartype,
5239 SCIPvarIsInitial(varx) || SCIPvarIsInitial(vary), SCIPvarIsRemovable(varx) && SCIPvarIsRemovable(vary),
5240 NULL, NULL, NULL, NULL, NULL) );
5241
5242 SCIP_CALL( SCIPprobAddVar(transprob, blkmem, set, lp, branchcand, eventfilter, eventqueue, aggvar) );
5243
5244 SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5245 branchcand, eventfilter, eventqueue, aggvar, (SCIP_Real)(-b), (SCIP_Real)xsol, infeasible, aggregated) );
5246 assert(*aggregated || *infeasible);
5247
5248 if( !(*infeasible) )
5249 {
5250 SCIP_CALL( SCIPvarAggregate(vary, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5251 branchcand, eventfilter, eventqueue, aggvar, (SCIP_Real)a, (SCIP_Real)ysol, infeasible, aggregated) );
5252 assert(*aggregated || *infeasible);
5253 }
5254
5255 /* release z */
5256 SCIP_CALL( SCIPvarRelease(&aggvar, blkmem, set, eventqueue, lp) );
5257
5258 return SCIP_OKAY; /*lint !e438*/
5259 }
5260
5261 /** performs second step of SCIPaggregateVars():
5262 * the variable to be aggregated is chosen among active problem variables x' and y', preferring a less strict variable
5263 * type as aggregation variable (i.e. continuous variables are preferred over implicit integers, implicit integers
5264 * or integers over binaries). If none of the variables is continuous, it is tried to find an integer
5265 * aggregation (i.e. integral coefficients a'' and b'', such that a''*x' + b''*y' == c''). This can lead to
5266 * the detection of infeasibility (e.g. if c'' is fractional), or to a rejection of the aggregation (denoted by
5267 * aggregated == FALSE), if the resulting integer coefficients are too large and thus numerically instable.
5268 *
5269 * @todo check for fixings, infeasibility, bound changes, or domain holes:
5270 * a) if there is no easy aggregation and we have one binary variable and another integer/implicit/binary variable
5271 * b) for implicit integer variables with fractional aggregation scalar (we cannot (for technical reasons) and do
5272 * not want to aggregate implicit integer variables, since we loose the corresponding divisibility property)
5273 */
5274 SCIP_RETCODE SCIPvarTryAggregateVars(
5275 SCIP_SET* set, /**< global SCIP settings */
5276 BMS_BLKMEM* blkmem, /**< block memory */
5277 SCIP_STAT* stat, /**< problem statistics */
5278 SCIP_PROB* transprob, /**< tranformed problem data */
5279 SCIP_PROB* origprob, /**< original problem data */
5280 SCIP_PRIMAL* primal, /**< primal data */
5281 SCIP_TREE* tree, /**< branch and bound tree */
5282 SCIP_REOPT* reopt, /**< reoptimization data structure */
5283 SCIP_LP* lp, /**< current LP data */
5284 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
5285 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
5286 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
5287 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5288 SCIP_VAR* varx, /**< variable x in equality a*x + b*y == c */
5289 SCIP_VAR* vary, /**< variable y in equality a*x + b*y == c */
5290 SCIP_Real scalarx, /**< multiplier a in equality a*x + b*y == c */
5291 SCIP_Real scalary, /**< multiplier b in equality a*x + b*y == c */
5292 SCIP_Real rhs, /**< right hand side c in equality a*x + b*y == c */
5293 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
5294 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
5295 )
5296 {
5297 SCIP_Bool easyaggr;
5298 SCIP_Real maxscalar;
5299 SCIP_Real absquot;
5300
5301 assert(set != NULL);
5302 assert(blkmem != NULL);
5303 assert(stat != NULL);
5304 assert(transprob != NULL);
5305 assert(origprob != NULL);
5306 assert(tree != NULL);
5307 assert(lp != NULL);
5308 assert(cliquetable != NULL);
5309 assert(branchcand != NULL);
5310 assert(eventqueue != NULL);
5311 assert(varx != NULL);
5312 assert(vary != NULL);
5313 assert(varx != vary);
5314 assert(infeasible != NULL);
5315 assert(aggregated != NULL);
5316 assert(SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING);
5317 assert(SCIPvarGetStatus(varx) == SCIP_VARSTATUS_LOOSE);
5318 assert(SCIPvarGetStatus(vary) == SCIP_VARSTATUS_LOOSE);
5319 assert(!SCIPsetIsZero(set, scalarx));
5320 assert(!SCIPsetIsZero(set, scalary));
5321
5322 *infeasible = FALSE;
5323 *aggregated = FALSE;
5324
5325 absquot = REALABS(scalarx / scalary);
5326 maxscalar = SCIPsetFeastol(set) / SCIPsetEpsilon(set);
5327 maxscalar = MAX(maxscalar, 1.0);
5328
5329 if( absquot > maxscalar || absquot < 1 / maxscalar )
5330 return SCIP_OKAY;
5331
5332 /* prefer aggregating the variable of more general type (preferred aggregation variable is varx) */
5333 if( SCIPvarGetType(vary) > SCIPvarGetType(varx) ||
5334 (SCIPvarGetType(vary) == SCIPvarGetType(varx) && !SCIPvarIsBinary(vary) && SCIPvarIsBinary(varx)) )
5335 {
5336 SCIP_VAR* var;
5337 SCIP_Real scalar;
5338
5339 /* switch the variables, such that varx is the variable of more general type (cont > implint > int > bin) */
5340 var = vary;
5341 vary = varx;
5342 varx = var;
5343 scalar = scalary;
5344 scalary = scalarx;
5345 scalarx = scalar;
5346 }
5347
5348 /* don't aggregate if the aggregation would lead to a binary variable aggregated to a non-binary variable */
5349 if( SCIPvarIsBinary(varx) && !SCIPvarIsBinary(vary) )
5350 return SCIP_OKAY;
5351
5352 assert(SCIPvarGetType(varx) >= SCIPvarGetType(vary));
5353
5354 /* figure out, which variable should be aggregated */
5355 easyaggr = FALSE;
5356
5357 /* check if it is an easy aggregation that means:
5358 *
5359 * a*x + b*y == c -> x == -b/a * y + c/a iff |b/a| > feastol and |a/b| > feastol
5360 */
5361 if( !SCIPsetIsFeasZero(set, scalary/scalarx) && !SCIPsetIsFeasZero(set, scalarx/scalary) )
5362 {
5363 if( SCIPvarGetType(varx) == SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(vary) < SCIP_VARTYPE_CONTINUOUS )
5364 {
5365 easyaggr = TRUE;
5366 }
5367 else if( SCIPsetIsFeasIntegral(set, scalary/scalarx) )
5368 {
5369 easyaggr = TRUE;
5370 }
5371 else if( SCIPsetIsFeasIntegral(set, scalarx/scalary) && SCIPvarGetType(vary) == SCIPvarGetType(varx) )
5372 {
5373 /* we have an easy aggregation if we flip the variables x and y */
5374 SCIP_VAR* var;
5375 SCIP_Real scalar;
5376
5377 /* switch the variables, such that varx is the aggregated variable */
5378 var = vary;
5379 vary = varx;
5380 varx = var;
5381 scalar = scalary;
5382 scalary = scalarx;
5383 scalarx = scalar;
5384 easyaggr = TRUE;
5385 }
5386 else if( SCIPvarGetType(varx) == SCIP_VARTYPE_CONTINUOUS )
5387 {
5388 /* the aggregation is still easy if both variables are continuous */
5389 assert(SCIPvarGetType(vary) == SCIP_VARTYPE_CONTINUOUS); /* otherwise we are in the first case */
5390 easyaggr = TRUE;
5391 }
5392 }
5393
5394 /* did we find an "easy" aggregation? */
5395 if( easyaggr )
5396 {
5397 SCIP_Real scalar;
5398 SCIP_Real constant;
5399
5400 assert(SCIPvarGetType(varx) >= SCIPvarGetType(vary));
5401
5402 /* calculate aggregation scalar and constant: a*x + b*y == c => x == -b/a * y + c/a */
5403 scalar = -scalary/scalarx;
5404 constant = rhs/scalarx;
5405
5406 if( REALABS(constant) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) ) /*lint !e653*/
5407 return SCIP_OKAY;
5408
5409 /* check aggregation for integer feasibility */
5410 if( SCIPvarGetType(varx) != SCIP_VARTYPE_CONTINUOUS
5411 && SCIPvarGetType(vary) != SCIP_VARTYPE_CONTINUOUS
5412 && SCIPsetIsFeasIntegral(set, scalar) && !SCIPsetIsFeasIntegral(set, constant) )
5413 {
5414 *infeasible = TRUE;
5415 return SCIP_OKAY;
5416 }
5417
5418 /* if the aggregation scalar is fractional, we cannot (for technical reasons) and do not want to aggregate implicit integer variables,
5419 * since then we would loose the corresponding divisibility property
5420 */
5421 assert(SCIPvarGetType(varx) != SCIP_VARTYPE_IMPLINT || SCIPsetIsFeasIntegral(set, scalar));
5422
5423 /* aggregate the variable */
5424 SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5425 branchcand, eventfilter, eventqueue, vary, scalar, constant, infeasible, aggregated) );
5426 assert(*aggregated || *infeasible);
5427 }
5428 else if( (SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(varx) == SCIP_VARTYPE_IMPLINT)
5429 && (SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vary) == SCIP_VARTYPE_IMPLINT) )
5430 {
5431 /* the variables are both integral: we have to try to find an integer aggregation */
5432 SCIP_CALL( tryAggregateIntVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5433 branchcand, eventfilter, eventqueue, varx, vary, scalarx, scalary, rhs, infeasible, aggregated) );
5434 }
5435
5436 return SCIP_OKAY;
5437 }
5438
5439 /** converts variable into multi-aggregated variable */
5440 SCIP_RETCODE SCIPvarMultiaggregate(
5441 SCIP_VAR* var, /**< problem variable */
5442 BMS_BLKMEM* blkmem, /**< block memory */
5443 SCIP_SET* set, /**< global SCIP settings */
5444 SCIP_STAT* stat, /**< problem statistics */
5445 SCIP_PROB* transprob, /**< tranformed problem data */
5446 SCIP_PROB* origprob, /**< original problem data */
5447 SCIP_PRIMAL* primal, /**< primal data */
5448 SCIP_TREE* tree, /**< branch and bound tree */
5449 SCIP_REOPT* reopt, /**< reoptimization data structure */
5450 SCIP_LP* lp, /**< current LP data */
5451 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
5452 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
5453 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
5454 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5455 int naggvars, /**< number n of variables in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5456 SCIP_VAR** aggvars, /**< variables y_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5457 SCIP_Real* scalars, /**< multipliers a_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5458 SCIP_Real constant, /**< constant shift c in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5459 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
5460 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
5461 )
5462 {
5463 SCIP_VAR** tmpvars;
5464 SCIP_Real* tmpscalars;
5465 SCIP_Real obj;
5466 SCIP_Real branchfactor;
5467 int branchpriority;
5468 SCIP_BRANCHDIR branchdirection;
5469 int nlocksdown[NLOCKTYPES];
5470 int nlocksup[NLOCKTYPES];
5471 int v;
5472 SCIP_Real tmpconstant;
5473 SCIP_Real tmpscalar;
5474 int ntmpvars;
5475 int tmpvarssize;
5476 int tmprequiredsize;
5477 int i;
5478
5479 assert(var != NULL);
5480 assert(var->scip == set->scip);
5481 assert(var->glbdom.lb == var->locdom.lb); /*lint !e777*/
5482 assert(var->glbdom.ub == var->locdom.ub); /*lint !e777*/
5483 assert(naggvars == 0 || aggvars != NULL);
5484 assert(naggvars == 0 || scalars != NULL);
5485 assert(infeasible != NULL);
5486 assert(aggregated != NULL);
5487
5488 SCIPsetDebugMsg(set, "trying multi-aggregating variable <%s> == ...%d vars... %+g\n", var->name, naggvars, constant);
5489
5490 /* check multi-aggregation on debugging solution */
5491 SCIP_CALL( SCIPdebugCheckAggregation(set, var, aggvars, scalars, constant, naggvars) ); /*lint !e506 !e774*/
5492
5493 *infeasible = FALSE;
5494 *aggregated = FALSE;
5495
5496 switch( SCIPvarGetStatus(var) )
5497 {
5498 case SCIP_VARSTATUS_ORIGINAL:
5499 if( var->data.original.transvar == NULL )
5500 {
5501 SCIPerrorMessage("cannot multi-aggregate an untransformed original variable\n");
5502 return SCIP_INVALIDDATA;
5503 }
5504 SCIP_CALL( SCIPvarMultiaggregate(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree,
5505 reopt, lp, cliquetable, branchcand, eventfilter, eventqueue, naggvars, aggvars, scalars, constant, infeasible, aggregated) );
5506 break;
5507
5508 case SCIP_VARSTATUS_LOOSE:
5509 assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
5510
5511 /* check if we would create a self-reference */
5512 ntmpvars = naggvars;
5513 tmpvarssize = naggvars;
5514 tmpconstant = constant;
5515 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &tmpvars, aggvars, ntmpvars) );
5516 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &tmpscalars, scalars, ntmpvars) );
5517
5518 /* get all active variables for multi-aggregation */
5519 SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) );
5520 if( tmprequiredsize > tmpvarssize )
5521 {
5522 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpvars, tmpvarssize, tmprequiredsize) );
5523 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpscalars, tmpvarssize, tmprequiredsize) );
5524 tmpvarssize = tmprequiredsize;
5525 SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) );
5526 assert( tmprequiredsize <= tmpvarssize );
5527 }
5528
5529 tmpscalar = 0.0;
5530
5531 /* iterate over all active variables of the multi-aggregation and filter all variables which are equal to the
5532 * possible multi-aggregated variable
5533 */
5534 for( v = ntmpvars - 1; v >= 0; --v )
5535 {
5536 assert(tmpvars[v] != NULL);
5537 assert(SCIPvarGetStatus(tmpvars[v]) == SCIP_VARSTATUS_LOOSE);
5538
5539 if( tmpvars[v]->index == var->index )
5540 {
5541 tmpscalar += tmpscalars[v];
5542 tmpvars[v] = tmpvars[ntmpvars - 1];
5543 tmpscalars[v] = tmpscalars[ntmpvars - 1];
5544 --ntmpvars;
5545 }
5546 }
5547
5548 /* this means that x = x + a_1*y_1 + ... + a_n*y_n + c */
5549 if( SCIPsetIsEQ(set, tmpscalar, 1.0) )
5550 {
5551 if( ntmpvars == 0 )
5552 {
5553 if( SCIPsetIsZero(set, tmpconstant) ) /* x = x */
5554 {
5555 SCIPsetDebugMsg(set, "Possible multi-aggregation was completely resolved and detected to be redundant.\n");
5556 goto TERMINATE;
5557 }
5558 else /* 0 = c and c != 0 */
5559 {
5560 SCIPsetDebugMsg(set, "Multi-aggregation was completely resolved and led to infeasibility.\n");
5561 *infeasible = TRUE;
5562 goto TERMINATE;
5563 }
5564 }
5565 else if( ntmpvars == 1 ) /* 0 = a*y + c => y = -c/a */
5566 {
5567 assert(tmpscalars[0] != 0.0);
5568 assert(tmpvars[0] != NULL);
5569
5570 SCIPsetDebugMsg(set, "Possible multi-aggregation led to fixing of variable <%s> to %g.\n", SCIPvarGetName(tmpvars[0]), -constant/tmpscalars[0]);
5571 SCIP_CALL( SCIPvarFix(tmpvars[0], blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
5572 branchcand, eventfilter, eventqueue, cliquetable, -constant/tmpscalars[0], infeasible, aggregated) );
5573 goto TERMINATE;
5574 }
5575 else if( ntmpvars == 2 ) /* 0 = a_1*y_1 + a_2*y_2 + c => y_1 = -a_2/a_1 * y_2 - c/a_1 */
5576 {
5577 /* both variables are different active problem variables, and both scalars are non-zero: try to aggregate them */
5578 SCIPsetDebugMsg(set, "Possible multi-aggregation led to aggregation of variables <%s> and <%s> with scalars %g and %g and constant %g.\n",
5579 SCIPvarGetName(tmpvars[0]), SCIPvarGetName(tmpvars[1]), tmpscalars[0], tmpscalars[1], -tmpconstant);
5580
5581 SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp,
5582 cliquetable, branchcand, eventfilter, eventqueue, tmpvars[0], tmpvars[1], tmpscalars[0],
5583 tmpscalars[1], -tmpconstant, infeasible, aggregated) );
5584
5585 goto TERMINATE;
5586 }
5587 else
5588 /* @todo: it is possible to multi-aggregate another variable, does it make sense?,
5589 * rest looks like 0 = a_1*y_1 + ... + a_n*y_n + c and has at least three variables
5590 */
5591 goto TERMINATE;
5592 }
5593 /* this means that x = b*x + a_1*y_1 + ... + a_n*y_n + c */
5594 else if( !SCIPsetIsZero(set, tmpscalar) )
5595 {
5596 tmpscalar = 1 - tmpscalar;
5597 tmpconstant /= tmpscalar;
5598 for( v = ntmpvars - 1; v >= 0; --v )
5599 tmpscalars[v] /= tmpscalar;
5600 }
5601
5602 /* check, if we are in one of the simple cases */
5603 if( ntmpvars == 0 )
5604 {
5605 SCIPsetDebugMsg(set, "Possible multi-aggregation led to fixing of variable <%s> to %g.\n", SCIPvarGetName(var), tmpconstant);
5606 SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
5607 eventfilter, eventqueue, cliquetable, tmpconstant, infeasible, aggregated) );
5608 goto TERMINATE;
5609 }
5610
5611 /* if only one aggregation variable is left, we perform a normal aggregation instead of a multi-aggregation */
5612 if( ntmpvars == 1 )
5613 {
5614 SCIPsetDebugMsg(set, "Possible multi-aggregation led to aggregation of variables <%s> and <%s> with scalars %g and %g and constant %g.\n",
5615 SCIPvarGetName(var), SCIPvarGetName(tmpvars[0]), 1.0, -tmpscalars[0], tmpconstant);
5616
5617 SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp,
5618 cliquetable, branchcand, eventfilter, eventqueue, var, tmpvars[0], 1.0, -tmpscalars[0], tmpconstant,
5619 infeasible, aggregated) );
5620
5621 goto TERMINATE;
5622 }
5623
5624 /**@todo currently we don't perform the multi aggregation if the multi aggregation variable has a non
5625 * empty hole list; this should be changed in the future */
5626 if( SCIPvarGetHolelistGlobal(var) != NULL )
5627 goto TERMINATE;
5628
5629 /* if the variable is not allowed to be multi-aggregated */
5630 if( SCIPvarDoNotMultaggr(var) )
5631 {
5632 SCIPsetDebugMsg(set, "variable is not allowed to be multi-aggregated.\n");
5633 goto TERMINATE;
5634 }
5635
5636 /* if the variable to be multi-aggregated has implications or variable bounds (i.e. is the implied variable or
5637 * variable bound variable of another variable), we have to remove it from the other variables implications or
5638 * variable bounds
5639 */
5640 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) );
5641 assert(var->vlbs == NULL);
5642 assert(var->vubs == NULL);
5643 assert(var->implics == NULL);
5644 assert(var->cliquelist == NULL);
5645
5646 /* set the aggregated variable's objective value to 0.0 */
5647 obj = var->obj;
5648 SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
5649
5650 /* since we change the variable type form loose to multi aggregated, we have to adjust the number of loose
5651 * variables in the LP data structure; the loose objective value (looseobjval) in the LP data structure, however,
5652 * gets adjusted automatically, due to the event SCIP_EVENTTYPE_OBJCHANGED which dropped in the moment where the
5653 * objective of this variable is set to zero
5654 */
5655 SCIPlpDecNLoosevars(lp);
5656
5657 /* unlock all rounding locks */
5658 for( i = 0; i < NLOCKTYPES; i++ )
5659 {
5660 nlocksdown[i] = var->nlocksdown[i];
5661 nlocksup[i] = var->nlocksup[i];
5662
5663 var->nlocksdown[i] = 0;
5664 var->nlocksup[i] = 0;
5665 }
5666
5667 /* convert variable into multi-aggregated variable */
5668 var->varstatus = SCIP_VARSTATUS_MULTAGGR; /*lint !e641*/
5669 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->data.multaggr.vars, tmpvars, ntmpvars) );
5670 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->data.multaggr.scalars, tmpscalars, ntmpvars) );
5671 var->data.multaggr.constant = tmpconstant;
5672 var->data.multaggr.nvars = ntmpvars;
5673 var->data.multaggr.varssize = ntmpvars;
5674
5675 /* mark variable to be non-deletable */
5676 SCIPvarMarkNotDeletable(var);
5677
5678 /* relock the variable, thus increasing the locks of the aggregation variables */
5679 for( i = 0; i < NLOCKTYPES; i++ )
5680 {
5681 SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) );
5682 }
5683
5684 /* update flags and branching factors and priorities of aggregation variables;
5685 * update preferred branching direction of all aggregation variables that don't have a preferred direction yet
5686 */
5687 branchfactor = var->branchfactor;
5688 branchpriority = var->branchpriority;
5689 branchdirection = (SCIP_BRANCHDIR)var->branchdirection;
5690
5691 for( v = 0; v < ntmpvars; ++v )
5692 {
5693 assert(tmpvars[v] != NULL);
5694 tmpvars[v]->removable &= var->removable;
5695 branchfactor = MAX(tmpvars[v]->branchfactor, branchfactor);
5696 branchpriority = MAX(tmpvars[v]->branchpriority, branchpriority);
5697
5698 /* mark variable to be non-deletable */
5699 SCIPvarMarkNotDeletable(tmpvars[v]);
5700 }
5701 for( v = 0; v < ntmpvars; ++v )
5702 {
5703 SCIP_CALL( SCIPvarChgBranchFactor(tmpvars[v], set, branchfactor) );
5704 SCIP_CALL( SCIPvarChgBranchPriority(tmpvars[v], branchpriority) );
5705 if( (SCIP_BRANCHDIR)tmpvars[v]->branchdirection == SCIP_BRANCHDIR_AUTO )
5706 {
5707 if( tmpscalars[v] >= 0.0 )
5708 {
5709 SCIP_CALL( SCIPvarChgBranchDirection(tmpvars[v], branchdirection) );
5710 }
5711 else
5712 {
5713 SCIP_CALL( SCIPvarChgBranchDirection(tmpvars[v], SCIPbranchdirOpposite(branchdirection)) );
5714 }
5715 }
5716 }
5717 SCIP_CALL( SCIPvarChgBranchFactor(var, set, branchfactor) );
5718 SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) );
5719
5720 if( var->probindex != -1 )
5721 {
5722 /* inform problem about the variable's status change */
5723 SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) );
5724 }
5725
5726 /* issue VARFIXED event */
5727 SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 2) );
5728
5729 /* reset the objective value of the aggregated variable, thus adjusting the objective value of the aggregation
5730 * variables and the problem's objective offset
5731 */
5732 SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) );
5733
5734 *aggregated = TRUE;
5735
5736 TERMINATE:
5737 BMSfreeBlockMemoryArray(blkmem, &tmpscalars, tmpvarssize);
5738 BMSfreeBlockMemoryArray(blkmem, &tmpvars, tmpvarssize);
5739
5740 break;
5741
5742 case SCIP_VARSTATUS_COLUMN:
5743 SCIPerrorMessage("cannot multi-aggregate a column variable\n");
5744 return SCIP_INVALIDDATA;
5745
5746 case SCIP_VARSTATUS_FIXED:
5747 SCIPerrorMessage("cannot multi-aggregate a fixed variable\n");
5748 return SCIP_INVALIDDATA;
5749
5750 case SCIP_VARSTATUS_AGGREGATED:
5751 SCIPerrorMessage("cannot multi-aggregate an aggregated variable\n");
5752 return SCIP_INVALIDDATA;
5753
5754 case SCIP_VARSTATUS_MULTAGGR:
5755 SCIPerrorMessage("cannot multi-aggregate a multiple aggregated variable again\n");
5756 return SCIP_INVALIDDATA;
5757
5758 case SCIP_VARSTATUS_NEGATED:
5759 /* aggregate negation variable x in x' = offset - x, instead of aggregating x' directly:
5760 * x' = a_1*y_1 + ... + a_n*y_n + c -> x = offset - x' = offset - a_1*y_1 - ... - a_n*y_n - c
5761 */
5762 assert(SCIPsetIsZero(set, var->obj));
5763 assert(var->negatedvar != NULL);
5764 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
5765 assert(var->negatedvar->negatedvar == var);
5766
5767 /* switch the signs of the aggregation scalars */
5768 for( v = 0; v < naggvars; ++v )
5769 scalars[v] *= -1.0;
5770
5771 /* perform the multi aggregation on the negation variable */
5772 SCIP_CALL( SCIPvarMultiaggregate(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
5773 cliquetable, branchcand, eventfilter, eventqueue, naggvars, aggvars, scalars,
5774 var->data.negate.constant - constant, infeasible, aggregated) );
5775
5776 /* switch the signs of the aggregation scalars again, to reset them to their original values */
5777 for( v = 0; v < naggvars; ++v )
5778 scalars[v] *= -1.0;
5779 break;
5780
5781 default:
5782 SCIPerrorMessage("unknown variable status\n");
5783 return SCIP_INVALIDDATA;
5784 }
5785
5786 return SCIP_OKAY;
5787 }
5788
5789 /** transformed variables are resolved to their active, fixed, or multi-aggregated problem variable of a variable,
5790 * or for original variables the same variable is returned
5791 */
5792 static
5793 SCIP_VAR* varGetActiveVar(
5794 SCIP_VAR* var /**< problem variable */
5795 )
5796 {
5797 SCIP_VAR* retvar;
5798
5799 assert(var != NULL);
5800
5801 retvar = var;
5802
5803 SCIPdebugMessage("get active variable of <%s>\n", var->name);
5804
5805 while( TRUE ) /*lint !e716 */
5806 {
5807 assert(retvar != NULL);
5808
5809 switch( SCIPvarGetStatus(retvar) )
5810 {
5811 case SCIP_VARSTATUS_ORIGINAL:
5812 case SCIP_VARSTATUS_LOOSE:
5813 case SCIP_VARSTATUS_COLUMN:
5814 case SCIP_VARSTATUS_FIXED:
5815 return retvar;
5816
5817 case SCIP_VARSTATUS_MULTAGGR:
5818 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
5819 if ( retvar->data.multaggr.nvars == 1 )
5820 retvar = retvar->data.multaggr.vars[0];
5821 else
5822 return retvar;
5823 break;
5824
5825 case SCIP_VARSTATUS_AGGREGATED:
5826 retvar = retvar->data.aggregate.var;
5827 break;
5828
5829 case SCIP_VARSTATUS_NEGATED:
5830 retvar = retvar->negatedvar;
5831 break;
5832
5833 default:
5834 SCIPerrorMessage("unknown variable status\n");
5835 SCIPABORT();
5836 return NULL; /*lint !e527*/
5837 }
5838 }
5839 }
5840
5841 /** returns whether variable is not allowed to be aggregated */
5842 SCIP_Bool SCIPvarDoNotAggr(
5843 SCIP_VAR* var /**< problem variable */
5844 )
5845 {
5846 SCIP_VAR* retvar;
5847
5848 assert(var != NULL);
5849
5850 retvar = varGetActiveVar(var);
5851 assert(retvar != NULL);
5852
5853 switch( SCIPvarGetStatus(retvar) )
5854 {
5855 case SCIP_VARSTATUS_ORIGINAL:
5856 case SCIP_VARSTATUS_LOOSE:
5857 case SCIP_VARSTATUS_COLUMN:
5858 case SCIP_VARSTATUS_FIXED:
5859 return retvar->donotaggr;
5860
5861 case SCIP_VARSTATUS_MULTAGGR:
5862 return FALSE;
5863
5864 case SCIP_VARSTATUS_AGGREGATED:
5865 case SCIP_VARSTATUS_NEGATED:
5866 default:
5867 /* aggregated and negated variables should be resolved by varGetActiveVar() */
5868 SCIPerrorMessage("wrong variable status\n");
5869 SCIPABORT();
5870 return FALSE; /*lint !e527 */
5871 }
5872 }
5873
5874 /** returns whether variable is not allowed to be multi-aggregated */
5875 SCIP_Bool SCIPvarDoNotMultaggr(
5876 SCIP_VAR* var /**< problem variable */
5877 )
5878 {
5879 SCIP_VAR* retvar;
5880
5881 assert(var != NULL);
5882
5883 retvar = varGetActiveVar(var);
5884 assert(retvar != NULL);
5885
5886 switch( SCIPvarGetStatus(retvar) )
5887 {
5888 case SCIP_VARSTATUS_ORIGINAL:
5889 case SCIP_VARSTATUS_LOOSE:
5890 case SCIP_VARSTATUS_COLUMN:
5891 case SCIP_VARSTATUS_FIXED:
5892 return retvar->donotmultaggr;
5893
5894 case SCIP_VARSTATUS_MULTAGGR:
5895 return FALSE;
5896
5897 case SCIP_VARSTATUS_AGGREGATED:
5898 case SCIP_VARSTATUS_NEGATED:
5899 default:
5900 /* aggregated and negated variables should be resolved by varGetActiveVar() */
5901 SCIPerrorMessage("wrong variable status\n");
5902 SCIPABORT();
5903 return FALSE; /*lint !e527 */
5904 }
5905 }
5906
5907 /** gets negated variable x' = offset - x of problem variable x; the negated variable is created if not yet existing;
5908 * the negation offset of binary variables is always 1, the offset of other variables is fixed to lb + ub when the
5909 * negated variable is created
5910 */
5911 SCIP_RETCODE SCIPvarNegate(
5912 SCIP_VAR* var, /**< problem variable to negate */
5913 BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
5914 SCIP_SET* set, /**< global SCIP settings */
5915 SCIP_STAT* stat, /**< problem statistics */
5916 SCIP_VAR** negvar /**< pointer to store the negated variable */
5917 )
5918 {
5919 assert(var != NULL);
5920 assert(var->scip == set->scip);
5921 assert(negvar != NULL);
5922
5923 /* check, if we already created the negated variable */
5924 if( var->negatedvar == NULL )
5925 {
5926 char negvarname[SCIP_MAXSTRLEN];
5927
5928 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED);
5929
5930 SCIPsetDebugMsg(set, "creating negated variable of <%s>\n", var->name);
5931
5932 /* negation is only possible for bounded variables */
5933 if( SCIPsetIsInfinity(set, -var->glbdom.lb) || SCIPsetIsInfinity(set, var->glbdom.ub) )
5934 {
5935 SCIPerrorMessage("cannot negate unbounded variable\n");
5936 return SCIP_INVALIDDATA;
5937 }
5938
5939 (void) SCIPsnprintf(negvarname, SCIP_MAXSTRLEN, "%s_neg", var->name);
5940
5941 /* create negated variable */
5942 SCIP_CALL( varCreate(negvar, blkmem, set, stat, negvarname, var->glbdom.lb, var->glbdom.ub, 0.0,
5943 SCIPvarGetType(var), var->initial, var->removable, NULL, NULL, NULL, NULL, NULL) );
5944 (*negvar)->varstatus = SCIP_VARSTATUS_NEGATED; /*lint !e641*/
5945 if( SCIPvarIsBinary(var) )
5946 (*negvar)->data.negate.constant = 1.0;
5947 else
5948 (*negvar)->data.negate.constant = var->glbdom.lb + var->glbdom.ub;
5949
5950 /* create event filter for transformed variable */
5951 if( SCIPvarIsTransformed(var) )
5952 {
5953 SCIP_CALL( SCIPeventfilterCreate(&(*negvar)->eventfilter, blkmem) );
5954 }
5955
5956 /* set the bounds corresponding to the negation variable */
5957 (*negvar)->glbdom.lb = (*negvar)->data.negate.constant - var->glbdom.ub;
5958 (*negvar)->glbdom.ub = (*negvar)->data.negate.constant - var->glbdom.lb;
5959 (*negvar)->locdom.lb = (*negvar)->data.negate.constant - var->locdom.ub;
5960 (*negvar)->locdom.ub = (*negvar)->data.negate.constant - var->locdom.lb;
5961 /**@todo create holes in the negated variable corresponding to the holes of the negation variable */
5962
5963 /* link the variables together */
5964 var->negatedvar = *negvar;
5965 (*negvar)->negatedvar = var;
5966
5967 /* mark both variables to be non-deletable */
5968 SCIPvarMarkNotDeletable(var);
5969 SCIPvarMarkNotDeletable(*negvar);
5970
5971 /* copy the branch factor and priority, and use the negative preferred branching direction */
5972 (*negvar)->branchfactor = var->branchfactor;
5973 (*negvar)->branchpriority = var->branchpriority;
5974 (*negvar)->branchdirection = SCIPbranchdirOpposite((SCIP_BRANCHDIR)var->branchdirection); /*lint !e641*/
5975
5976 /* copy donot(mult)aggr status */
5977 (*negvar)->donotaggr = var->donotaggr;
5978 (*negvar)->donotmultaggr = var->donotmultaggr;
5979
5980 /* copy lazy bounds (they have to be flipped) */
5981 (*negvar)->lazylb = (*negvar)->data.negate.constant - var->lazyub;
5982 (*negvar)->lazyub = (*negvar)->data.negate.constant - var->lazylb;
5983
5984 /* make negated variable a parent of the negation variable (negated variable is captured as a parent) */
5985 SCIP_CALL( varAddParent(var, blkmem, set, *negvar) );
5986 assert((*negvar)->nuses == 1);
5987 }
5988 assert(var->negatedvar != NULL);
5989
5990 /* return the negated variable */
5991 *negvar = var->negatedvar;
5992
5993 /* exactly one variable of the negation pair has to be marked as negated variable */
5994 assert((SCIPvarGetStatus(*negvar) == SCIP_VARSTATUS_NEGATED) != (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED));
5995
5996 return SCIP_OKAY;
5997 }
5998
5999 /** informs variable that its position in problem's vars array changed */
6000 static
6001 void varSetProbindex(
6002 SCIP_VAR* var, /**< problem variable */
6003 int probindex /**< new problem index of variable (-1 for removal) */
6004 )
6005 {
6006 assert(var != NULL);
6007 assert(probindex >= 0 || var->vlbs == NULL);
6008 assert(probindex >= 0 || var->vubs == NULL);
6009 assert(probindex >= 0 || var->implics == NULL);
6010
6011 var->probindex = probindex;
6012 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
6013 {
6014 assert(var->data.col != NULL);
6015 var->data.col->var_probindex = probindex;
6016 }
6017 }
6018
6019 /** informs variable that its position in problem's vars array changed */
6020 void SCIPvarSetProbindex(
6021 SCIP_VAR* var, /**< problem variable */
6022 int probindex /**< new problem index of variable */
6023 )
6024 {
6025 assert(var != NULL);
6026 assert(probindex >= 0);
6027
6028 varSetProbindex(var, probindex);
6029 }
6030
6031 /** gives the variable a new name
6032 *
6033 * @note the old pointer is overwritten, which might result in a memory leakage
6034 */
6035 void SCIPvarSetNamePointer(
6036 SCIP_VAR* var, /**< problem variable */
6037 const char* name /**< new name of variable */
6038 )
6039 {
6040 assert(var != NULL);
6041 assert(name != NULL);
6042
6043 var->name = (char*)name;
6044 }
6045
6046 /** informs variable that it will be removed from the problem; adjusts probindex and removes variable from the
6047 * implication graph;
6048 * If 'final' is TRUE, the thorough implication graph removal is not performed. Instead, only the
6049 * variable bounds and implication data structures of the variable are freed. Since in the final removal
6050 * of all variables from the transformed problem, this deletes the implication graph completely and is faster
6051 * than removing the variables one by one, each time updating all lists of the other variables.
6052 */
6053 SCIP_RETCODE SCIPvarRemove(
6054 SCIP_VAR* var, /**< problem variable */
6055 BMS_BLKMEM* blkmem, /**< block memory buffer */
6056 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
6057 SCIP_SET* set, /**< global SCIP settings */
6058 SCIP_Bool final /**< is this the final removal of all problem variables? */
6059 )
6060 {
6061 assert(SCIPvarGetProbindex(var) >= 0);
6062 assert(var->scip == set->scip);
6063
6064 /* if the variable is active in the transformed problem, remove it from the implication graph */
6065 if( SCIPvarIsTransformed(var)
6066 && (SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN) )
6067 {
6068 if( final )
6069 {
6070 /* just destroy the data structures */
6071 SCIPvboundsFree(&var->vlbs, blkmem);
6072 SCIPvboundsFree(&var->vubs, blkmem);
6073 SCIPimplicsFree(&var->implics, blkmem);
6074 }
6075 else
6076 {
6077 /* unlink the variable from all other variables' lists and free the data structures */
6078 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) );
6079 }
6080 }
6081
6082 /* mark the variable to be no longer a member of the problem */
6083 varSetProbindex(var, -1);
6084
6085 return SCIP_OKAY;
6086 }
6087
6088 /** marks the variable to be deleted from the problem */
6089 void SCIPvarMarkDeleted(
6090 SCIP_VAR* var /**< problem variable */
6091 )
6092 {
6093 assert(var != NULL);
6094 assert(var->probindex != -1);
6095
6096 var->deleted = TRUE;
6097 }
6098
6099 /** marks the variable to not to be aggregated */
6100 SCIP_RETCODE SCIPvarMarkDoNotAggr(
6101 SCIP_VAR* var /**< problem variable */
6102 )
6103 {
6104 SCIP_VAR* retvar;
6105
6106 assert(var != NULL);
6107
6108 retvar = varGetActiveVar(var);
6109 assert(retvar != NULL);
6110
6111 switch( SCIPvarGetStatus(retvar) )
6112 {
6113 case SCIP_VARSTATUS_ORIGINAL:
6114 case SCIP_VARSTATUS_LOOSE:
6115 case SCIP_VARSTATUS_COLUMN:
6116 case SCIP_VARSTATUS_FIXED:
6117 retvar->donotaggr = TRUE;
6118 break;
6119
6120 case SCIP_VARSTATUS_MULTAGGR:
6121 SCIPerrorMessage("cannot mark a multi-aggregated variable to not be aggregated.\n");
6122 return SCIP_INVALIDDATA;
6123
6124 case SCIP_VARSTATUS_AGGREGATED:
6125 case SCIP_VARSTATUS_NEGATED:
6126 default:
6127 /* aggregated and negated variables should be resolved by varGetActiveVar() */
6128 SCIPerrorMessage("wrong variable status\n");
6129 return SCIP_INVALIDDATA;
6130 }
6131
6132 return SCIP_OKAY;
6133 }
6134
6135 /** marks the variable to not to be multi-aggregated */
6136 SCIP_RETCODE SCIPvarMarkDoNotMultaggr(
6137 SCIP_VAR* var /**< problem variable */
6138 )
6139 {
6140 SCIP_VAR* retvar;
6141
6142 assert(var != NULL);
6143
6144 retvar = varGetActiveVar(var);
6145 assert(retvar != NULL);
6146
6147 switch( SCIPvarGetStatus(retvar) )
6148 {
6149 case SCIP_VARSTATUS_ORIGINAL:
6150 case SCIP_VARSTATUS_LOOSE:
6151 case SCIP_VARSTATUS_COLUMN:
6152 case SCIP_VARSTATUS_FIXED:
6153 retvar->donotmultaggr = TRUE;
6154 break;
6155
6156 case SCIP_VARSTATUS_MULTAGGR:
6157 SCIPerrorMessage("cannot mark a multi-aggregated variable to not be multi-aggregated.\n");
6158 return SCIP_INVALIDDATA;
6159
6160 case SCIP_VARSTATUS_AGGREGATED:
6161 case SCIP_VARSTATUS_NEGATED:
6162 default:
6163 /* aggregated and negated variables should be resolved by varGetActiveVar() */
6164 SCIPerrorMessage("wrong variable status\n");
6165 return SCIP_INVALIDDATA;
6166 }
6167
6168 return SCIP_OKAY;
6169 }
6170
6171 /** changes type of variable; cannot be called, if var belongs to a problem */
6172 SCIP_RETCODE SCIPvarChgType(
6173 SCIP_VAR* var, /**< problem variable to change */
6174 BMS_BLKMEM* blkmem, /**< block memory */
6175 SCIP_SET* set, /**< global SCIP settings */
6176 SCIP_PRIMAL* primal, /**< primal data */
6177 SCIP_LP* lp, /**< current LP data */
6178 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6179 SCIP_VARTYPE vartype /**< new type of variable */
6180 )
6181 {
6182 SCIP_EVENT* event;
6183 SCIP_VARTYPE oldtype;
6184
6185 assert(var != NULL);
6186
6187 SCIPdebugMessage("change type of <%s> from %d to %d\n", var->name, SCIPvarGetType(var), vartype);
6188
6189 if( var->probindex >= 0 )
6190 {
6191 SCIPerrorMessage("cannot change type of variable already in the problem\n");
6192 return SCIP_INVALIDDATA;
6193 }
6194
6195 oldtype = (SCIP_VARTYPE)var->vartype;
6196 var->vartype = vartype; /*lint !e641*/
6197
6198 if( SCIPsetGetStage(set) > SCIP_STAGE_TRANSFORMING )
6199 {
6200 SCIP_CALL( SCIPeventCreateTypeChanged(&event, blkmem, var, oldtype, vartype) );
6201 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) );
6202 }
6203
6204 if( var->negatedvar != NULL )
6205 {
6206 assert(oldtype == (SCIP_VARTYPE)var->negatedvar->vartype
6207 || SCIPvarIsBinary(var) == SCIPvarIsBinary(var->negatedvar));
6208
6209
6210 var->negatedvar->vartype = vartype; /*lint !e641*/
6211
6212 if( SCIPsetGetStage(set) > SCIP_STAGE_TRANSFORMING )
6213 {
6214 SCIP_CALL( SCIPeventCreateTypeChanged(&event, blkmem, var->negatedvar, oldtype, vartype) );
6215 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) );
6216 }
6217 }
6218
6219 return SCIP_OKAY;
6220 }
6221
6222 /** appends OBJCHANGED event to the event queue */
6223 static
6224 SCIP_RETCODE varEventObjChanged(
6225 SCIP_VAR* var, /**< problem variable to change */
6226 BMS_BLKMEM* blkmem, /**< block memory */
6227 SCIP_SET* set, /**< global SCIP settings */
6228 SCIP_PRIMAL* primal, /**< primal data */
6229 SCIP_LP* lp, /**< current LP data */
6230 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6231 SCIP_Real oldobj, /**< old objective value for variable */
6232 SCIP_Real newobj /**< new objective value for variable */
6233 )
6234 {
6235 SCIP_EVENT* event;
6236
6237 assert(var != NULL);
6238 assert(var->scip == set->scip);
6239 assert(var->eventfilter != NULL);
6240 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
6241 assert(SCIPvarIsTransformed(var));
6242
6243 /* In the case where the objcetive value of a variable is very close to epsilon, and it is aggregated
6244 * into a variable with a big objective value, round-off errors might make the assert oldobj != newobj fail.
6245 * Hence, we relax it by letting it pass if the variables are percieved the same and we use very large values
6246 * that make comparison with values close to epsilon inaccurate.
6247 */
6248 assert(!SCIPsetIsEQ(set, oldobj, newobj) ||
6249 (SCIPsetIsEQ(set, oldobj, newobj) && REALABS(newobj) > 1e+15 * SCIPsetEpsilon(set))
6250 );
6251
6252 SCIP_CALL( SCIPeventCreateObjChanged(&event, blkmem, var, oldobj, newobj) );
6253 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) );
6254
6255 return SCIP_OKAY;
6256 }
6257
6258 /** changes objective value of variable */
6259 SCIP_RETCODE SCIPvarChgObj(
6260 SCIP_VAR* var, /**< variable to change */
6261 BMS_BLKMEM* blkmem, /**< block memory */
6262 SCIP_SET* set, /**< global SCIP settings */
6263 SCIP_PROB* prob, /**< problem data */
6264 SCIP_PRIMAL* primal, /**< primal data */
6265 SCIP_LP* lp, /**< current LP data */
6266 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6267 SCIP_Real newobj /**< new objective value for variable */
6268 )
6269 {
6270 SCIP_Real oldobj;
6271
6272 assert(var != NULL);
6273 assert(set != NULL);
6274 assert(var->scip == set->scip);
6275
6276 SCIPsetDebugMsg(set, "changing objective value of <%s> from %g to %g\n", var->name, var->obj, newobj);
6277
6278 if( !SCIPsetIsEQ(set, var->obj, newobj) )
6279 {
6280 switch( SCIPvarGetStatus(var) )
6281 {
6282 case SCIP_VARSTATUS_ORIGINAL:
6283 if( var->data.original.transvar != NULL )
6284 {
6285 assert(SCIPprobIsTransformed(prob));
6286
6287 SCIP_CALL( SCIPvarChgObj(var->data.original.transvar, blkmem, set, prob, primal, lp, eventqueue,
6288 (SCIP_Real) prob->objsense * newobj/prob->objscale) );
6289 }
6290 else
6291 assert(set->stage == SCIP_STAGE_PROBLEM);
6292
6293 var->obj = newobj;
6294 var->unchangedobj = newobj;
6295
6296 break;
6297
6298 case SCIP_VARSTATUS_LOOSE:
6299 case SCIP_VARSTATUS_COLUMN:
6300 oldobj = var->obj;
6301 var->obj = newobj;
6302
6303 /* update unchanged objective value of variable */
6304 if( !lp->divingobjchg )
6305 var->unchangedobj = newobj;
6306
6307 /* update the number of variables with non-zero objective coefficient;
6308 * we only want to do the update, if the variable is added to the problem;
6309 * since the objective of inactive variables cannot be changed, this corresponds to probindex != -1
6310 */
6311 if( SCIPvarIsActive(var) )
6312 SCIPprobUpdateNObjVars(prob, set, oldobj, var->obj);
6313
6314 SCIP_CALL( varEventObjChanged(var, blkmem, set, primal, lp, eventqueue, oldobj, var->obj) );
6315 break;
6316
6317 case SCIP_VARSTATUS_FIXED:
6318 case SCIP_VARSTATUS_AGGREGATED:
6319 case SCIP_VARSTATUS_MULTAGGR:
6320 case SCIP_VARSTATUS_NEGATED:
6321 SCIPerrorMessage("cannot change objective value of a fixed, aggregated, multi-aggregated, or negated variable\n");
6322 return SCIP_INVALIDDATA;
6323
6324 default:
6325 SCIPerrorMessage("unknown variable status\n");
6326 return SCIP_INVALIDDATA;
6327 }
6328 }
6329
6330 return SCIP_OKAY;
6331 }
6332
6333 /** adds value to objective value of variable */
6334 SCIP_RETCODE SCIPvarAddObj(
6335 SCIP_VAR* var, /**< variable to change */
6336 BMS_BLKMEM* blkmem, /**< block memory */
6337 SCIP_SET* set, /**< global SCIP settings */
6338 SCIP_STAT* stat, /**< problem statistics */
6339 SCIP_PROB* transprob, /**< transformed problem data */
6340 SCIP_PROB* origprob, /**< original problem data */
6341 SCIP_PRIMAL* primal, /**< primal data */
6342 SCIP_TREE* tree, /**< branch and bound tree */
6343 SCIP_REOPT* reopt, /**< reoptimization data structure */
6344 SCIP_LP* lp, /**< current LP data */
6345 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
6346 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6347 SCIP_Real addobj /**< additional objective value for variable */
6348 )
6349 {
6350 assert(var != NULL);
6351 assert(set != NULL);
6352 assert(var->scip == set->scip);
6353 assert(set->stage < SCIP_STAGE_INITSOLVE);
6354
6355 SCIPsetDebugMsg(set, "adding %g to objective value %g of <%s>\n", addobj, var->obj, var->name);
6356
6357 if( !SCIPsetIsZero(set, addobj) )
6358 {
6359 SCIP_Real oldobj;
6360 int i;
6361
6362 switch( SCIPvarGetStatus(var) )
6363 {
6364 case SCIP_VARSTATUS_ORIGINAL:
6365 if( var->data.original.transvar != NULL )
6366 {
6367 SCIP_CALL( SCIPvarAddObj(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree,
6368 reopt, lp, eventfilter, eventqueue, (SCIP_Real) transprob->objsense * addobj/transprob->objscale) );
6369 }
6370 else
6371 assert(set->stage == SCIP_STAGE_PROBLEM);
6372
6373 var->obj += addobj;
6374 var->unchangedobj += addobj;
6375 assert(SCIPsetIsEQ(set, var->obj, var->unchangedobj));
6376
6377 break;
6378
6379 case SCIP_VARSTATUS_LOOSE:
6380 case SCIP_VARSTATUS_COLUMN:
6381 oldobj = var->obj;
6382 var->obj += addobj;
6383
6384 /* update unchanged objective value of variable */
6385 if( !lp->divingobjchg )
6386 {
6387 var->unchangedobj += addobj;
6388 assert(SCIPsetIsEQ(set, var->obj, var->unchangedobj));
6389 }
6390
6391 /* update the number of variables with non-zero objective coefficient;
6392 * we only want to do the update, if the variable is added to the problem;
6393 * since the objective of inactive variables cannot be changed, this corresponds to probindex != -1
6394 */
6395 if( SCIPvarIsActive(var) )
6396 SCIPprobUpdateNObjVars(transprob, set, oldobj, var->obj);
6397
6398 SCIP_CALL( varEventObjChanged(var, blkmem, set, primal, lp, eventqueue, oldobj, var->obj) );
6399 break;
6400
6401 case SCIP_VARSTATUS_FIXED:
6402 assert(SCIPsetIsEQ(set, var->locdom.lb, var->locdom.ub));
6403 SCIPprobAddObjoffset(transprob, var->locdom.lb * addobj);
6404 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6405 break;
6406
6407 case SCIP_VARSTATUS_AGGREGATED:
6408 assert(!var->donotaggr);
6409 /* x = a*y + c -> add a*addobj to obj. val. of y, and c*addobj to obj. offset of problem */
6410 SCIPprobAddObjoffset(transprob, var->data.aggregate.constant * addobj);
6411 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6412 SCIP_CALL( SCIPvarAddObj(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, primal, tree, reopt,
6413 lp, eventfilter, eventqueue, var->data.aggregate.scalar * addobj) );
6414 break;
6415
6416 case SCIP_VARSTATUS_MULTAGGR:
6417 assert(!var->donotmultaggr);
6418 /* x = a_1*y_1 + ... + a_n*y_n + c -> add a_i*addobj to obj. val. of y_i, and c*addobj to obj. offset */
6419 SCIPprobAddObjoffset(transprob, var->data.multaggr.constant * addobj);
6420 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6421 for( i = 0; i < var->data.multaggr.nvars; ++i )
6422 {
6423 SCIP_CALL( SCIPvarAddObj(var->data.multaggr.vars[i], blkmem, set, stat, transprob, origprob, primal, tree,
6424 reopt, lp, eventfilter, eventqueue, var->data.multaggr.scalars[i] * addobj) );
6425 }
6426 break;
6427
6428 case SCIP_VARSTATUS_NEGATED:
6429 /* x' = offset - x -> add -addobj to obj. val. of x and offset*addobj to obj. offset of problem */
6430 assert(var->negatedvar != NULL);
6431 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
6432 assert(var->negatedvar->negatedvar == var);
6433 SCIPprobAddObjoffset(transprob, var->data.negate.constant * addobj);
6434 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6435 SCIP_CALL( SCIPvarAddObj(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
6436 eventfilter, eventqueue, -addobj) );
6437 break;
6438
6439 default:
6440 SCIPerrorMessage("unknown variable status\n");
6441 return SCIP_INVALIDDATA;
6442 }
6443 }
6444
6445 return SCIP_OKAY;
6446 }
6447
6448 /** changes objective value of variable in current dive */
6449 SCIP_RETCODE SCIPvarChgObjDive(
6450 SCIP_VAR* var, /**< problem variable to change */
6451 SCIP_SET* set, /**< global SCIP settings */
6452 SCIP_LP* lp, /**< current LP data */
6453 SCIP_Real newobj /**< new objective value for variable */
6454 )
6455 {
6456 assert(var != NULL);
6457 assert(set != NULL);
6458 assert(var->scip == set->scip);
6459 assert(lp != NULL);
6460
6461 SCIPsetDebugMsg(set, "changing objective of <%s> to %g in current dive\n", var->name, newobj);
6462
6463 if( SCIPsetIsZero(set, newobj) )
6464 newobj = 0.0;
6465
6466 /* change objective value of attached variables */
6467 switch( SCIPvarGetStatus(var) )
6468 {
6469 case SCIP_VARSTATUS_ORIGINAL:
6470 assert(var->data.original.transvar != NULL);
6471 SCIP_CALL( SCIPvarChgObjDive(var->data.original.transvar, set, lp, newobj) );
6472 break;
6473
6474 case SCIP_VARSTATUS_COLUMN:
6475 assert(var->data.col != NULL);
6476 SCIP_CALL( SCIPcolChgObj(var->data.col, set, lp, newobj) );
6477 break;
6478
6479 case SCIP_VARSTATUS_LOOSE:
6480 case SCIP_VARSTATUS_FIXED:
6481 /* nothing to do here: only the constant shift in objective function would change */
6482 break;
6483
6484 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
6485 assert(var->data.aggregate.var != NULL);
6486 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
6487 SCIP_CALL( SCIPvarChgObjDive(var->data.aggregate.var, set, lp, newobj / var->data.aggregate.scalar) );
6488 /* the constant can be ignored, because it would only affect the objective shift */
6489 break;
6490
6491 case SCIP_VARSTATUS_MULTAGGR:
6492 SCIPerrorMessage("cannot change diving objective value of a multi-aggregated variable\n");
6493 return SCIP_INVALIDDATA;
6494
6495 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
6496 assert(var->negatedvar != NULL);
6497 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
6498 assert(var->negatedvar->negatedvar == var);
6499 SCIP_CALL( SCIPvarChgObjDive(var->negatedvar, set, lp, -newobj) );
6500 /* the offset can be ignored, because it would only affect the objective shift */
6501 break;
6502
6503 default:
6504 SCIPerrorMessage("unknown variable status\n");
6505 return SCIP_INVALIDDATA;
6506 }
6507
6508 return SCIP_OKAY;
6509 }
6510
6511 /** adjust lower bound to integral value, if variable is integral */
6512 void SCIPvarAdjustLb(
6513 SCIP_VAR* var, /**< problem variable */
6514 SCIP_SET* set, /**< global SCIP settings */
6515 SCIP_Real* lb /**< pointer to lower bound to adjust */
6516 )
6517 {
6518 assert(var != NULL);
6519 assert(set != NULL);
6520 assert(var->scip == set->scip);
6521 assert(lb != NULL);
6522
6523 SCIPsetDebugMsg(set, "adjust lower bound %g of <%s>\n", *lb, var->name);
6524
6525 *lb = adjustedLb(set, SCIPvarGetType(var), *lb);
6526 }
6527
6528 /** adjust upper bound to integral value, if variable is integral */
6529 void SCIPvarAdjustUb(
6530 SCIP_VAR* var, /**< problem variable */
6531 SCIP_SET* set, /**< global SCIP settings */
6532 SCIP_Real* ub /**< pointer to upper bound to adjust */
6533 )
6534 {
6535 assert(var != NULL);
6536 assert(set != NULL);
6537 assert(var->scip == set->scip);
6538 assert(ub != NULL);
6539
6540 SCIPsetDebugMsg(set, "adjust upper bound %g of <%s>\n", *ub, var->name);
6541
6542 *ub = adjustedUb(set, SCIPvarGetType(var), *ub);
6543 }
6544
6545 /** adjust lower or upper bound to integral value, if variable is integral */
6546 void SCIPvarAdjustBd(
6547 SCIP_VAR* var, /**< problem variable */
6548 SCIP_SET* set, /**< global SCIP settings */
6549 SCIP_BOUNDTYPE boundtype, /**< type of bound to adjust */
6550 SCIP_Real* bd /**< pointer to bound to adjust */
6551 )
6552 {
6553 assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER);
6554
6555 if( boundtype == SCIP_BOUNDTYPE_LOWER )
6556 SCIPvarAdjustLb(var, set, bd);
6557 else
6558 SCIPvarAdjustUb(var, set, bd);
6559 }
6560
6561 /** changes lower bound of original variable in original problem */
6562 SCIP_RETCODE SCIPvarChgLbOriginal(
6563 SCIP_VAR* var, /**< problem variable to change */
6564 SCIP_SET* set, /**< global SCIP settings */
6565 SCIP_Real newbound /**< new bound for variable */
6566 )
6567 {
6568 int i;
6569
6570 assert(var != NULL);
6571 assert(!SCIPvarIsTransformed(var));
6572 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
6573 assert(set != NULL);
6574 assert(var->scip == set->scip);
6575 assert(set->stage == SCIP_STAGE_PROBLEM);
6576
6577 /* check that the bound is feasible */
6578 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsLE(set, newbound, SCIPvarGetUbOriginal(var)));
6579 /* adjust bound to integral value if variable is of integral type */
6580 newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
6581
6582 if( SCIPsetIsZero(set, newbound) )
6583 newbound = 0.0;
6584
6585 /* original domains are only stored for ORIGINAL variables, not for NEGATED */
6586 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL )
6587 {
6588 SCIPsetDebugMsg(set, "changing original lower bound of <%s> from %g to %g\n",
6589 var->name, var->data.original.origdom.lb, newbound);
6590
6591 if( SCIPsetIsEQ(set, var->data.original.origdom.lb, newbound) )
6592 return SCIP_OKAY;
6593
6594 /* change the bound */
6595 var->data.original.origdom.lb = newbound;
6596 }
6597 else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED )
6598 {
6599 assert( var->negatedvar != NULL );
6600 SCIP_CALL( SCIPvarChgUbOriginal(var->negatedvar, set, var->data.negate.constant - newbound) );
6601 }
6602
6603 /* process parent variables */
6604 for( i = 0; i < var->nparentvars; ++i )
6605 {
6606 SCIP_VAR* parentvar;
6607
6608 parentvar = var->parentvars[i];
6609 assert(parentvar != NULL);
6610 assert(SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_NEGATED);
6611 assert(parentvar->negatedvar == var);
6612 assert(var->negatedvar == parentvar);
6613
6614 SCIP_CALL( SCIPvarChgUbOriginal(parentvar, set, parentvar->data.negate.constant - newbound) );
6615 }
6616
6617 return SCIP_OKAY;
6618 }
6619
6620 /** changes upper bound of original variable in original problem */
6621 SCIP_RETCODE SCIPvarChgUbOriginal(
6622 SCIP_VAR* var, /**< problem variable to change */
6623 SCIP_SET* set, /**< global SCIP settings */
6624 SCIP_Real newbound /**< new bound for variable */
6625 )
6626 {
6627 int i;
6628
6629 assert(var != NULL);
6630 assert(!SCIPvarIsTransformed(var));
6631 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
6632 assert(set != NULL);
6633 assert(var->scip == set->scip);
6634 assert(set->stage == SCIP_STAGE_PROBLEM);
6635
6636 /* check that the bound is feasible */
6637 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsGE(set, newbound, SCIPvarGetLbOriginal(var)));
6638 /* adjust bound to integral value if variable is of integral type */
6639 newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
6640
6641 if( SCIPsetIsZero(set, newbound) )
6642 newbound = 0.0;
6643
6644 /* original domains are only stored for ORIGINAL variables, not for NEGATED */
6645 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL )
6646 {
6647 SCIPsetDebugMsg(set, "changing original upper bound of <%s> from %g to %g\n",
6648 var->name, var->data.original.origdom.ub, newbound);
6649
6650 if( SCIPsetIsEQ(set, var->data.original.origdom.ub, newbound) )
6651 return SCIP_OKAY;
6652
6653 /* change the bound */
6654 var->data.original.origdom.ub = newbound;
6655 }
6656 else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED )
6657 {
6658 assert( var->negatedvar != NULL );
6659 SCIP_CALL( SCIPvarChgLbOriginal(var->negatedvar, set, var->data.negate.constant - newbound) );
6660 }
6661
6662 /* process parent variables */
6663 for( i = 0; i < var->nparentvars; ++i )
6664 {
6665 SCIP_VAR* parentvar;
6666
6667 parentvar = var->parentvars[i];
6668 assert(parentvar != NULL);
6669 assert(SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_NEGATED);
6670 assert(parentvar->negatedvar == var);
6671 assert(var->negatedvar == parentvar);
6672
6673 SCIP_CALL( SCIPvarChgLbOriginal(parentvar, set, parentvar->data.negate.constant - newbound) );
6674 }
6675
6676 return SCIP_OKAY;
6677 }
6678
6679 /** appends GLBCHANGED event to the event queue */
6680 static
6681 SCIP_RETCODE varEventGlbChanged(
6682 SCIP_VAR* var, /**< problem variable to change */
6683 BMS_BLKMEM* blkmem, /**< block memory */
6684 SCIP_SET* set, /**< global SCIP settings */
6685 SCIP_LP* lp, /**< current LP data */
6686 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
6687 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6688 SCIP_Real oldbound, /**< old lower bound for variable */
6689 SCIP_Real newbound /**< new lower bound for variable */
6690 )
6691 {
6692 assert(var != NULL);
6693 assert(var->eventfilter != NULL);
6694 assert(SCIPvarIsTransformed(var));
6695 assert(!SCIPsetIsEQ(set, oldbound, newbound) || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
6696 assert(set != NULL);
6697 assert(var->scip == set->scip);
6698
6699 /* check, if the variable is being tracked for bound changes
6700 * COLUMN and LOOSE variables are tracked always, because global/root pseudo objective value has to be updated
6701 */
6702 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GLBCHANGED) != 0)
6703 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
6704 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
6705 {
6706 SCIP_EVENT* event;
6707
6708 SCIPsetDebugMsg(set, "issue GLBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
6709
6710 SCIP_CALL( SCIPeventCreateGlbChanged(&event, blkmem, var, oldbound, newbound) );
6711 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
6712 }
6713
6714 return SCIP_OKAY;
6715 }
6716
6717 /** appends GUBCHANGED event to the event queue */
6718 static
6719 SCIP_RETCODE varEventGubChanged(
6720 SCIP_VAR* var, /**< problem variable to change */
6721 BMS_BLKMEM* blkmem, /**< block memory */
6722 SCIP_SET* set, /**< global SCIP settings */
6723 SCIP_LP* lp, /**< current LP data */
6724 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
6725 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6726 SCIP_Real oldbound, /**< old lower bound for variable */
6727 SCIP_Real newbound /**< new lower bound for variable */
6728 )
6729 {
6730 assert(var != NULL);
6731 assert(var->eventfilter != NULL);
6732 assert(SCIPvarIsTransformed(var));
6733 assert(!SCIPsetIsEQ(set, oldbound, newbound) || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
6734 assert(set != NULL);
6735 assert(var->scip == set->scip);
6736
6737 /* check, if the variable is being tracked for bound changes
6738 * COLUMN and LOOSE variables are tracked always, because global/root pseudo objective value has to be updated
6739 */
6740 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GUBCHANGED) != 0)
6741 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
6742 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
6743 {
6744 SCIP_EVENT* event;
6745
6746 SCIPsetDebugMsg(set, "issue GUBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
6747
6748 SCIP_CALL( SCIPeventCreateGubChanged(&event, blkmem, var, oldbound, newbound) );
6749 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
6750 }
6751
6752 return SCIP_OKAY;
6753 }
6754
6755 /** appends GHOLEADDED event to the event queue */
6756 static
6757 SCIP_RETCODE varEventGholeAdded(
6758 SCIP_VAR* var, /**< problem variable to change */
6759 BMS_BLKMEM* blkmem, /**< block memory */
6760 SCIP_SET* set, /**< global SCIP settings */
6761 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6762 SCIP_Real left, /**< left bound of open interval in new hole */
6763 SCIP_Real right /**< right bound of open interval in new hole */
6764 )
6765 {
6766 assert(var != NULL);
6767 assert(var->eventfilter != NULL);
6768 assert(SCIPvarIsTransformed(var));
6769 assert(set != NULL);
6770 assert(var->scip == set->scip);
6771 assert(SCIPsetIsLT(set, left, right));
6772
6773 /* check, if the variable is being tracked for bound changes */
6774 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GHOLEADDED) != 0) )
6775 {
6776 SCIP_EVENT* event;
6777
6778 SCIPsetDebugMsg(set, "issue GHOLEADDED event for variable <%s>: (%.15g,%.15g)\n", var->name, left, right);
6779
6780 SCIP_CALL( SCIPeventCreateGholeAdded(&event, blkmem, var, left, right) );
6781 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
6782 }
6783
6784 return SCIP_OKAY;
6785 }
6786
6787 /** increases root bound change statistics after a global bound change */
6788 static
6789 void varIncRootboundchgs(
6790 SCIP_VAR* var, /**< problem variable to change */
6791 SCIP_SET* set, /**< global SCIP settings */
6792 SCIP_STAT* stat /**< problem statistics */
6793 )
6794 {
6795 assert(var != NULL);
6796 assert(set != NULL);
6797 assert(var->scip == set->scip);
6798 assert(stat != NULL);
6799
6800 if( SCIPvarIsActive(var) && SCIPvarIsTransformed(var) && set->stage == SCIP_STAGE_SOLVING )
6801 {
6802 stat->nrootboundchgs++;
6803 stat->nrootboundchgsrun++;
6804 if( SCIPvarIsIntegral(var) && SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
6805 {
6806 stat->nrootintfixings++;
6807 stat->nrootintfixingsrun++;
6808 }
6809 }
6810 }
6811
6812 /* forward declaration, because both methods call each other recursively */
6813
6814 /* performs the current change in upper bound, changes all parents accordingly */
6815 static
6816 SCIP_RETCODE varProcessChgUbGlobal(
6817 SCIP_VAR* var, /**< problem variable to change */
6818 BMS_BLKMEM* blkmem, /**< block memory */
6819 SCIP_SET* set, /**< global SCIP settings */
6820 SCIP_STAT* stat, /**< problem statistics */
6821 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
6822 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
6823 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
6824 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
6825 SCIP_Real newbound /**< new bound for variable */
6826 );
6827
6828 /** performs the current change in lower bound, changes all parents accordingly */
6829 static
6830 SCIP_RETCODE varProcessChgLbGlobal(
6831 SCIP_VAR* var, /**< problem variable to change */
6832 BMS_BLKMEM* blkmem, /**< block memory */
6833 SCIP_SET* set, /**< global SCIP settings */
6834 SCIP_STAT* stat, /**< problem statistics */
6835 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
6836 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
6837 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
6838 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
6839 SCIP_Real newbound /**< new bound for variable */
6840 )
6841 {
6842 SCIP_VAR* parentvar;
6843 SCIP_Real oldbound;
6844 int i;
6845
6846 assert(var != NULL);
6847 /* local domains can violate global bounds but not more than feasibility epsilon */
6848 assert(SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb));
6849 assert(SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub));
6850 assert(blkmem != NULL);
6851 assert(set != NULL);
6852 assert(var->scip == set->scip);
6853 assert(stat != NULL);
6854
6855 /* adjust bound to integral value if variable is of integral type */
6856 newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
6857
6858 /* check that the bound is feasible */
6859 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM && newbound > var->glbdom.ub )
6860 {
6861 /* due to numerics we only want to be feasible in feasibility tolerance */
6862 assert(SCIPsetIsFeasLE(set, newbound, var->glbdom.ub));
6863 newbound = var->glbdom.ub;
6864 }
6865 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
6866
6867 assert(var->vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, newbound, 0.0) || SCIPsetIsEQ(set, newbound, 1.0)); /*lint !e641*/
6868
6869 SCIPsetDebugMsg(set, "process changing global lower bound of <%s> from %f to %f\n", var->name, var->glbdom.lb, newbound);
6870
6871 if( SCIPsetIsEQ(set, newbound, var->glbdom.lb) && !(newbound != var->glbdom.lb && newbound * var->glbdom.lb <= 0.0) ) /*lint !e777*/
6872 return SCIP_OKAY;
6873
6874 /* check bound on debugging solution */
6875 SCIP_CALL( SCIPdebugCheckLbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
6876
6877 /* change the bound */
6878 oldbound = var->glbdom.lb;
6879 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasLE(set, newbound, var->glbdom.ub));
6880 var->glbdom.lb = newbound;
6881 assert( SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb) );
6882 assert( SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub) );
6883
6884 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
6885 {
6886 /* merges overlapping holes into single holes, moves bounds respectively */
6887 domMerge(&var->glbdom, blkmem, set, &newbound, NULL);
6888 }
6889
6890 /* update the root bound changes counters */
6891 varIncRootboundchgs(var, set, stat);
6892
6893 /* update the lbchginfos array by replacing worse local bounds with the new global bound and changing the
6894 * redundant bound changes to be branching decisions
6895 */
6896 for( i = 0; i < var->nlbchginfos; ++i )
6897 {
6898 assert(var->lbchginfos[i].var == var);
6899
6900 if( var->lbchginfos[i].oldbound < var->glbdom.lb )
6901 {
6902 SCIPsetDebugMsg(set, " -> adjust lower bound change <%s>: %g -> %g due to new global lower bound %g\n",
6903 SCIPvarGetName(var), var->lbchginfos[i].oldbound, var->lbchginfos[i].newbound, var->glbdom.lb);
6904 var->lbchginfos[i].oldbound = var->glbdom.lb;
6905 if( SCIPsetIsLE(set, var->lbchginfos[i].newbound, var->glbdom.lb) )
6906 {
6907 /* this bound change is redundant due to the new global bound */
6908 var->lbchginfos[i].newbound = var->glbdom.lb;
6909 var->lbchginfos[i].boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
6910 var->lbchginfos[i].redundant = TRUE;
6911 }
6912 else
6913 break; /* from now on, the remaining local bound changes are not redundant */
6914 }
6915 else
6916 break; /* from now on, the remaining local bound changes are not redundant */
6917 }
6918
6919 /* remove redundant implications and variable bounds */
6920 if( (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE)
6921 && (!set->reopt_enable || set->stage == SCIP_STAGE_PRESOLVING) )
6922 {
6923 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, TRUE, TRUE) );
6924 }
6925
6926 /* issue bound change event */
6927 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
6928 if( var->eventfilter != NULL )
6929 {
6930 SCIP_CALL( varEventGlbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
6931 }
6932
6933 /* process parent variables */
6934 for( i = 0; i < var->nparentvars; ++i )
6935 {
6936 parentvar = var->parentvars[i];
6937 assert(parentvar != NULL);
6938
6939 switch( SCIPvarGetStatus(parentvar) )
6940 {
6941 case SCIP_VARSTATUS_ORIGINAL:
6942 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
6943 break;
6944
6945 case SCIP_VARSTATUS_COLUMN:
6946 case SCIP_VARSTATUS_LOOSE:
6947 case SCIP_VARSTATUS_FIXED:
6948 case SCIP_VARSTATUS_MULTAGGR:
6949 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
6950 return SCIP_INVALIDDATA;
6951
6952 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
6953 assert(parentvar->data.aggregate.var == var);
6954 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
6955 {
6956 SCIP_Real parentnewbound;
6957
6958 /* a > 0 -> change lower bound of y */
6959 assert(SCIPsetIsInfinity(set, -parentvar->glbdom.lb) || SCIPsetIsInfinity(set, -oldbound)
6960 || SCIPsetIsFeasEQ(set, parentvar->glbdom.lb, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
6961 || (SCIPsetIsZero(set, parentvar->glbdom.lb / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
6962
6963 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6964 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6965 else
6966 parentnewbound = newbound;
6967 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
6968 }
6969 else
6970 {
6971 SCIP_Real parentnewbound;
6972
6973 /* a < 0 -> change upper bound of y */
6974 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
6975 assert(SCIPsetIsInfinity(set, parentvar->glbdom.ub) || SCIPsetIsInfinity(set, -oldbound)
6976 || SCIPsetIsFeasEQ(set, parentvar->glbdom.ub, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
6977 || (SCIPsetIsZero(set, parentvar->glbdom.ub / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
6978
6979 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6980 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6981 else
6982 parentnewbound = -newbound;
6983 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
6984 }
6985 break;
6986
6987 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
6988 assert(parentvar->negatedvar != NULL);
6989 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
6990 assert(parentvar->negatedvar->negatedvar == parentvar);
6991 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
6992 parentvar->data.negate.constant - newbound) );
6993 break;
6994
6995 default:
6996 SCIPerrorMessage("unknown variable status\n");
6997 return SCIP_INVALIDDATA;
6998 }
6999 }
7000
7001 return SCIP_OKAY;
7002 }
7003
7004 /** performs the current change in upper bound, changes all parents accordingly */
7005 static
7006 SCIP_RETCODE varProcessChgUbGlobal(
7007 SCIP_VAR* var, /**< problem variable to change */
7008 BMS_BLKMEM* blkmem, /**< block memory */
7009 SCIP_SET* set, /**< global SCIP settings */
7010 SCIP_STAT* stat, /**< problem statistics */
7011 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7012 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7013 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7014 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
7015 SCIP_Real newbound /**< new bound for variable */
7016 )
7017 {
7018 SCIP_VAR* parentvar;
7019 SCIP_Real oldbound;
7020 int i;
7021
7022 assert(var != NULL);
7023 /* local domains can violate global bounds but not more than feasibility epsilon */
7024 assert(SCIPsetIsFeasLE(set, var->glbdom.lb , var->locdom.lb));
7025 assert(SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub));
7026 assert(blkmem != NULL);
7027 assert(set != NULL);
7028 assert(var->scip == set->scip);
7029 assert(stat != NULL);
7030
7031 /* adjust bound to integral value if variable is of integral type */
7032 newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
7033
7034 /* check that the bound is feasible */
7035 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM && newbound < var->glbdom.lb )
7036 {
7037 /* due to numerics we only want to be feasible in feasibility tolerance */
7038 assert(SCIPsetIsFeasGE(set, newbound, var->glbdom.lb));
7039 newbound = var->glbdom.lb;
7040 }
7041 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7042
7043 assert(var->vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, newbound, 0.0) || SCIPsetIsEQ(set, newbound, 1.0)); /*lint !e641*/
7044
7045 SCIPsetDebugMsg(set, "process changing global upper bound of <%s> from %f to %f\n", var->name, var->glbdom.ub, newbound);
7046
7047 if( SCIPsetIsEQ(set, newbound, var->glbdom.ub) && !(newbound != var->glbdom.ub && newbound * var->glbdom.ub <= 0.0) ) /*lint !e777*/
7048 return SCIP_OKAY;
7049
7050 /* check bound on debugging solution */
7051 SCIP_CALL( SCIPdebugCheckUbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
7052
7053 /* change the bound */
7054 oldbound = var->glbdom.ub;
7055 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasGE(set, newbound, var->glbdom.lb));
7056 var->glbdom.ub = newbound;
7057 assert( SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb) );
7058 assert( SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub) );
7059
7060 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7061 {
7062 /* merges overlapping holes into single holes, moves bounds respectively */
7063 domMerge(&var->glbdom, blkmem, set, NULL, &newbound);
7064 }
7065
7066 /* update the root bound changes counters */
7067 varIncRootboundchgs(var, set, stat);
7068
7069 /* update the ubchginfos array by replacing worse local bounds with the new global bound and changing the
7070 * redundant bound changes to be branching decisions
7071 */
7072 for( i = 0; i < var->nubchginfos; ++i )
7073 {
7074 assert(var->ubchginfos[i].var == var);
7075 if( var->ubchginfos[i].oldbound > var->glbdom.ub )
7076 {
7077 SCIPsetDebugMsg(set, " -> adjust upper bound change <%s>: %g -> %g due to new global upper bound %g\n",
7078 SCIPvarGetName(var), var->ubchginfos[i].oldbound, var->ubchginfos[i].newbound, var->glbdom.ub);
7079 var->ubchginfos[i].oldbound = var->glbdom.ub;
7080 if( SCIPsetIsGE(set, var->ubchginfos[i].newbound, var->glbdom.ub) )
7081 {
7082 /* this bound change is redundant due to the new global bound */
7083 var->ubchginfos[i].newbound = var->glbdom.ub;
7084 var->ubchginfos[i].boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
7085 var->ubchginfos[i].redundant = TRUE;
7086 }
7087 else
7088 break; /* from now on, the remaining local bound changes are not redundant */
7089 }
7090 else
7091 break; /* from now on, the remaining local bound changes are not redundant */
7092 }
7093
7094 /* remove redundant implications and variable bounds */
7095 if( (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE)
7096 && (!set->reopt_enable || set->stage == SCIP_STAGE_PRESOLVING) )
7097 {
7098 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, TRUE, TRUE) );
7099 }
7100
7101 /* issue bound change event */
7102 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
7103 if( var->eventfilter != NULL )
7104 {
7105 SCIP_CALL( varEventGubChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
7106 }
7107
7108 /* process parent variables */
7109 for( i = 0; i < var->nparentvars; ++i )
7110 {
7111 parentvar = var->parentvars[i];
7112 assert(parentvar != NULL);
7113
7114 switch( SCIPvarGetStatus(parentvar) )
7115 {
7116 case SCIP_VARSTATUS_ORIGINAL:
7117 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7118 break;
7119
7120 case SCIP_VARSTATUS_COLUMN:
7121 case SCIP_VARSTATUS_LOOSE:
7122 case SCIP_VARSTATUS_FIXED:
7123 case SCIP_VARSTATUS_MULTAGGR:
7124 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
7125 return SCIP_INVALIDDATA;
7126
7127 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7128 assert(parentvar->data.aggregate.var == var);
7129 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
7130 {
7131 SCIP_Real parentnewbound;
7132
7133 /* a > 0 -> change upper bound of y */
7134 assert(SCIPsetIsInfinity(set, parentvar->glbdom.ub) || SCIPsetIsInfinity(set, oldbound)
7135 || SCIPsetIsFeasEQ(set, parentvar->glbdom.ub,
7136 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7137 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7138 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7139 else
7140 parentnewbound = newbound;
7141 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
7142 }
7143 else
7144 {
7145 SCIP_Real parentnewbound;
7146
7147 /* a < 0 -> change lower bound of y */
7148 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
7149 assert(SCIPsetIsInfinity(set, -parentvar->glbdom.lb) || SCIPsetIsInfinity(set, oldbound)
7150 || SCIPsetIsFeasEQ(set, parentvar->glbdom.lb,
7151 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7152 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7153 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7154 else
7155 parentnewbound = -newbound;
7156 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
7157 }
7158 break;
7159
7160 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
7161 assert(parentvar->negatedvar != NULL);
7162 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
7163 assert(parentvar->negatedvar->negatedvar == parentvar);
7164 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7165 parentvar->data.negate.constant - newbound) );
7166 break;
7167
7168 default:
7169 SCIPerrorMessage("unknown variable status\n");
7170 return SCIP_INVALIDDATA;
7171 }
7172 }
7173
7174 return SCIP_OKAY;
7175 }
7176
7177 /** changes global lower bound of variable; if possible, adjusts bound to integral value;
7178 * updates local lower bound if the global bound is tighter
7179 */
7180 SCIP_RETCODE SCIPvarChgLbGlobal(
7181 SCIP_VAR* var, /**< problem variable to change */
7182 BMS_BLKMEM* blkmem, /**< block memory */
7183 SCIP_SET* set, /**< global SCIP settings */
7184 SCIP_STAT* stat, /**< problem statistics */
7185 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7186 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7187 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7188 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
7189 SCIP_Real newbound /**< new bound for variable */
7190 )
7191 {
7192 assert(var != NULL);
7193 assert(blkmem != NULL);
7194 assert(set != NULL);
7195 assert(var->scip == set->scip);
7196
7197 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7198 * of the domain within feastol
7199 */
7200 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->glbdom.ub));
7201
7202 /* adjust bound to integral value if variable is of integral type */
7203 newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
7204
7205 /* check that the adjusted bound is feasible
7206 * @todo this does not have to be the case if the original problem was infeasible due to bounds and we are called
7207 * here because we reset bounds to their original value!
7208 */
7209 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->glbdom.ub));
7210
7211 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7212 {
7213 /* we do not want to exceed the upperbound, which could have happened due to numerics */
7214 newbound = MIN(newbound, var->glbdom.ub);
7215 }
7216 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7217
7218 /* the new global bound has to be tighter except we are in the original problem; this must be w.r.t. feastol because
7219 * SCIPvarFix() allows fixings that are outside of the domain within feastol
7220 */
7221 assert(lp == NULL || SCIPsetIsFeasLE(set, var->glbdom.lb, newbound) || (set->reopt_enable && set->stage == SCIP_STAGE_PRESOLVED));
7222
7223 SCIPsetDebugMsg(set, "changing global lower bound of <%s> from %g to %g\n", var->name, var->glbdom.lb, newbound);
7224
7225 if( SCIPsetIsEQ(set, var->glbdom.lb, newbound) && !(newbound != var->glbdom.lb && newbound * var->glbdom.lb <= 0.0) ) /*lint !e777*/
7226 return SCIP_OKAY;
7227
7228 /* change bounds of attached variables */
7229 switch( SCIPvarGetStatus(var) )
7230 {
7231 case SCIP_VARSTATUS_ORIGINAL:
7232 if( var->data.original.transvar != NULL )
7233 {
7234 SCIP_CALL( SCIPvarChgLbGlobal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue,
7235 cliquetable, newbound) );
7236 }
7237 else
7238 {
7239 assert(set->stage == SCIP_STAGE_PROBLEM);
7240 if( newbound > SCIPvarGetLbLocal(var) )
7241 {
7242 SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7243 }
7244 SCIP_CALL( varProcessChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7245 }
7246 break;
7247
7248 case SCIP_VARSTATUS_COLUMN:
7249 case SCIP_VARSTATUS_LOOSE:
7250 if( newbound > SCIPvarGetLbLocal(var) )
7251 {
7252 SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7253 }
7254 SCIP_CALL( varProcessChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7255 break;
7256
7257 case SCIP_VARSTATUS_FIXED:
7258 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7259 return SCIP_INVALIDDATA;
7260
7261 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7262 assert(var->data.aggregate.var != NULL);
7263 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
7264 {
7265 SCIP_Real childnewbound;
7266
7267 /* a > 0 -> change lower bound of y */
7268 assert((SCIPsetIsInfinity(set, -var->glbdom.lb) && SCIPsetIsInfinity(set, -var->data.aggregate.var->glbdom.lb))
7269 || SCIPsetIsFeasEQ(set, var->glbdom.lb,
7270 var->data.aggregate.var->glbdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant));
7271 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7272 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7273 else
7274 childnewbound = newbound;
7275 SCIP_CALL( SCIPvarChgLbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7276 childnewbound) );
7277 }
7278 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7279 {
7280 SCIP_Real childnewbound;
7281
7282 /* a < 0 -> change upper bound of y */
7283 assert((SCIPsetIsInfinity(set, -var->glbdom.lb) && SCIPsetIsInfinity(set, var->data.aggregate.var->glbdom.ub))
7284 || SCIPsetIsFeasEQ(set, var->glbdom.lb,
7285 var->data.aggregate.var->glbdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant));
7286 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7287 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7288 else
7289 childnewbound = -newbound;
7290 SCIP_CALL( SCIPvarChgUbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7291 childnewbound) );
7292 }
7293 else
7294 {
7295 SCIPerrorMessage("scalar is zero in aggregation\n");
7296 return SCIP_INVALIDDATA;
7297 }
7298 break;
7299
7300 case SCIP_VARSTATUS_MULTAGGR:
7301 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
7302 return SCIP_INVALIDDATA;
7303
7304 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
7305 assert(var->negatedvar != NULL);
7306 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
7307 assert(var->negatedvar->negatedvar == var);
7308 SCIP_CALL( SCIPvarChgUbGlobal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7309 var->data.negate.constant - newbound) );
7310 break;
7311
7312 default:
7313 SCIPerrorMessage("unknown variable status\n");
7314 return SCIP_INVALIDDATA;
7315 }
7316
7317 return SCIP_OKAY;
7318 }
7319
7320 /** changes global upper bound of variable; if possible, adjusts bound to integral value;
7321 * updates local upper bound if the global bound is tighter
7322 */
7323 SCIP_RETCODE SCIPvarChgUbGlobal(
7324 SCIP_VAR* var, /**< problem variable to change */
7325 BMS_BLKMEM* blkmem, /**< block memory */
7326 SCIP_SET* set, /**< global SCIP settings */
7327 SCIP_STAT* stat, /**< problem statistics */
7328 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7329 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7330 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7331 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
7332 SCIP_Real newbound /**< new bound for variable */
7333 )
7334 {
7335 assert(var != NULL);
7336 assert(blkmem != NULL);
7337 assert(set != NULL);
7338 assert(var->scip == set->scip);
7339
7340 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7341 * of the domain within feastol
7342 */
7343 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->glbdom.lb));
7344
7345 /* adjust bound to integral value if variable is of integral type */
7346 newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
7347
7348 /* check that the adjusted bound is feasible
7349 * @todo this does not have to be the case if the original problem was infeasible due to bounds and we are called
7350 * here because we reset bounds to their original value!
7351 */
7352 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->glbdom.lb));
7353
7354 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7355 {
7356 /* we do not want to undercut the lowerbound, which could have happened due to numerics */
7357 newbound = MAX(newbound, var->glbdom.lb);
7358 }
7359 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7360
7361 /* the new global bound has to be tighter except we are in the original problem; this must be w.r.t. feastol because
7362 * SCIPvarFix() allows fixings that are outside of the domain within feastol
7363 */
7364 assert(lp == NULL || SCIPsetIsFeasGE(set, var->glbdom.ub, newbound) || (set->reopt_enable && set->stage == SCIP_STAGE_PRESOLVED));
7365
7366 SCIPsetDebugMsg(set, "changing global upper bound of <%s> from %g to %g\n", var->name, var->glbdom.ub, newbound);
7367
7368 if( SCIPsetIsEQ(set, var->glbdom.ub, newbound) && !(newbound != var->glbdom.ub && newbound * var->glbdom.ub <= 0.0) ) /*lint !e777*/
7369 return SCIP_OKAY;
7370
7371 /* change bounds of attached variables */
7372 switch( SCIPvarGetStatus(var) )
7373 {
7374 case SCIP_VARSTATUS_ORIGINAL:
7375 if( var->data.original.transvar != NULL )
7376 {
7377 SCIP_CALL( SCIPvarChgUbGlobal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7378 newbound) );
7379 }
7380 else
7381 {
7382 assert(set->stage == SCIP_STAGE_PROBLEM);
7383 if( newbound < SCIPvarGetUbLocal(var) )
7384 {
7385 SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7386 }
7387 SCIP_CALL( varProcessChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7388 }
7389 break;
7390
7391 case SCIP_VARSTATUS_COLUMN:
7392 case SCIP_VARSTATUS_LOOSE:
7393 if( newbound < SCIPvarGetUbLocal(var) )
7394 {
7395 SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7396 }
7397 SCIP_CALL( varProcessChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7398 break;
7399
7400 case SCIP_VARSTATUS_FIXED:
7401 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7402 return SCIP_INVALIDDATA;
7403
7404 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7405 assert(var->data.aggregate.var != NULL);
7406 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
7407 {
7408 SCIP_Real childnewbound;
7409
7410 /* a > 0 -> change lower bound of y */
7411 assert((SCIPsetIsInfinity(set, var->glbdom.ub) && SCIPsetIsInfinity(set, var->data.aggregate.var->glbdom.ub))
7412 || SCIPsetIsFeasEQ(set, var->glbdom.ub,
7413 var->data.aggregate.var->glbdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant));
7414 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7415 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7416 else
7417 childnewbound = newbound;
7418 SCIP_CALL( SCIPvarChgUbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7419 childnewbound) );
7420 }
7421 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7422 {
7423 SCIP_Real childnewbound;
7424
7425 /* a < 0 -> change upper bound of y */
7426 assert((SCIPsetIsInfinity(set, var->glbdom.ub) && SCIPsetIsInfinity(set, -var->data.aggregate.var->glbdom.lb))
7427 || SCIPsetIsFeasEQ(set, var->glbdom.ub,
7428 var->data.aggregate.var->glbdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant));
7429 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7430 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7431 else
7432 childnewbound = -newbound;
7433 SCIP_CALL( SCIPvarChgLbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7434 childnewbound) );
7435 }
7436 else
7437 {
7438 SCIPerrorMessage("scalar is zero in aggregation\n");
7439 return SCIP_INVALIDDATA;
7440 }
7441 break;
7442
7443 case SCIP_VARSTATUS_MULTAGGR:
7444 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
7445 return SCIP_INVALIDDATA;
7446
7447 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
7448 assert(var->negatedvar != NULL);
7449 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
7450 assert(var->negatedvar->negatedvar == var);
7451 SCIP_CALL( SCIPvarChgLbGlobal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7452 var->data.negate.constant - newbound) );
7453 break;
7454
7455 default:
7456 SCIPerrorMessage("unknown variable status\n");
7457 return SCIP_INVALIDDATA;
7458 }
7459
7460 return SCIP_OKAY;
7461 }
7462
7463 /** changes lazy lower bound of the variable, this is only possible if the variable is not in the LP yet */
7464 SCIP_RETCODE SCIPvarChgLbLazy(
7465 SCIP_VAR* var, /**< problem variable */
7466 SCIP_SET* set, /**< global SCIP settings */
7467 SCIP_Real lazylb /**< the lazy lower bound to be set */
7468 )
7469 {
7470 assert(var != NULL);
7471 assert(var->probindex != -1);
7472 assert(SCIPsetIsFeasGE(set, var->glbdom.ub, lazylb));
7473 assert(SCIPsetIsFeasGE(set, var->lazyub, lazylb));
7474 assert(set != NULL);
7475 assert(var->scip == set->scip);
7476
7477 /* variable should not be in the LP */
7478 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
7479 return SCIP_INVALIDCALL;
7480
7481 var->lazylb = lazylb;
7482
7483 return SCIP_OKAY;
7484 }
7485
7486 /** changes lazy upper bound of the variable, this is only possible if the variable is not in the LP yet */
7487 SCIP_RETCODE SCIPvarChgUbLazy(
7488 SCIP_VAR* var, /**< problem variable */
7489 SCIP_SET* set, /**< global SCIP settings */
7490 SCIP_Real lazyub /**< the lazy lower bound to be set */
7491 )
7492 {
7493 assert(var != NULL);
7494 assert(var->probindex != -1);
7495 assert(SCIPsetIsFeasGE(set, lazyub, var->glbdom.lb));
7496 assert(SCIPsetIsFeasGE(set, lazyub, var->lazylb));
7497 assert(set != NULL);
7498 assert(var->scip == set->scip);
7499
7500 /* variable should not be in the LP */
7501 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
7502 return SCIP_INVALIDCALL;
7503
7504 var->lazyub = lazyub;
7505
7506 return SCIP_OKAY;
7507 }
7508
7509
7510 /** changes global bound of variable; if possible, adjusts bound to integral value;
7511 * updates local bound if the global bound is tighter
7512 */
7513 SCIP_RETCODE SCIPvarChgBdGlobal(
7514 SCIP_VAR* var, /**< problem variable to change */
7515 BMS_BLKMEM* blkmem, /**< block memory */
7516 SCIP_SET* set, /**< global SCIP settings */
7517 SCIP_STAT* stat, /**< problem statistics */
7518 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7519 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7520 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7521 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
7522 SCIP_Real newbound, /**< new bound for variable */
7523 SCIP_BOUNDTYPE boundtype /**< type of bound: lower or upper bound */
7524 )
7525 {
7526 /* apply bound change to the LP data */
7527 switch( boundtype )
7528 {
7529 case SCIP_BOUNDTYPE_LOWER:
7530 return SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound);
7531 case SCIP_BOUNDTYPE_UPPER:
7532 return SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound);
7533 default:
7534 SCIPerrorMessage("unknown bound type\n");
7535 return SCIP_INVALIDDATA;
7536 }
7537 }
7538
7539 /** appends LBTIGHTENED or LBRELAXED event to the event queue */
7540 static
7541 SCIP_RETCODE varEventLbChanged(
7542 SCIP_VAR* var, /**< problem variable to change */
7543 BMS_BLKMEM* blkmem, /**< block memory */
7544 SCIP_SET* set, /**< global SCIP settings */
7545 SCIP_LP* lp, /**< current LP data */
7546 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
7547 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
7548 SCIP_Real oldbound, /**< old lower bound for variable */
7549 SCIP_Real newbound /**< new lower bound for variable */
7550 )
7551 {
7552 assert(var != NULL);
7553 assert(var->eventfilter != NULL);
7554 assert(SCIPvarIsTransformed(var));
7555 assert(!SCIPsetIsEQ(set, oldbound, newbound) || newbound == var->glbdom.lb || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
7556 assert(set != NULL);
7557 assert(var->scip == set->scip);
7558
7559 /* check, if the variable is being tracked for bound changes
7560 * COLUMN and LOOSE variables are tracked always, because row activities and LP changes have to be updated
7561 */
7562 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_LBCHANGED) != 0)
7563 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
7564 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
7565 {
7566 SCIP_EVENT* event;
7567
7568 SCIPsetDebugMsg(set, "issue LBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
7569
7570 SCIP_CALL( SCIPeventCreateLbChanged(&event, blkmem, var, oldbound, newbound) );
7571 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
7572 }
7573
7574 return SCIP_OKAY;
7575 }
7576
7577 /** appends UBTIGHTENED or UBRELAXED event to the event queue */
7578 static
7579 SCIP_RETCODE varEventUbChanged(
7580 SCIP_VAR* var, /**< problem variable to change */
7581 BMS_BLKMEM* blkmem, /**< block memory */
7582 SCIP_SET* set, /**< global SCIP settings */
7583 SCIP_LP* lp, /**< current LP data */
7584 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
7585 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
7586 SCIP_Real oldbound, /**< old upper bound for variable */
7587 SCIP_Real newbound /**< new upper bound for variable */
7588 )
7589 {
7590 assert(var != NULL);
7591 assert(var->eventfilter != NULL);
7592 assert(SCIPvarIsTransformed(var));
7593 assert(!SCIPsetIsEQ(set, oldbound, newbound) || newbound == var->glbdom.ub || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
7594 assert(set != NULL);
7595 assert(var->scip == set->scip);
7596
7597 /* check, if the variable is being tracked for bound changes
7598 * COLUMN and LOOSE variables are tracked always, because row activities and LP changes have to be updated
7599 */
7600 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_UBCHANGED) != 0)
7601 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
7602 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
7603 {
7604 SCIP_EVENT* event;
7605
7606 SCIPsetDebugMsg(set, "issue UBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
7607
7608 SCIP_CALL( SCIPeventCreateUbChanged(&event, blkmem, var, oldbound, newbound) );
7609 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
7610 }
7611
7612 return SCIP_OKAY;
7613 }
7614
7615 /* forward declaration, because both methods call each other recursively */
7616
7617 /* performs the current change in upper bound, changes all parents accordingly */
7618 static
7619 SCIP_RETCODE varProcessChgUbLocal(
7620 SCIP_VAR* var, /**< problem variable to change */
7621 BMS_BLKMEM* blkmem, /**< block memory */
7622 SCIP_SET* set, /**< global SCIP settings */
7623 SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7624 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7625 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7626 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7627 SCIP_Real newbound /**< new bound for variable */
7628 );
7629
7630 /** performs the current change in lower bound, changes all parents accordingly */
7631 static
7632 SCIP_RETCODE varProcessChgLbLocal(
7633 SCIP_VAR* var, /**< problem variable to change */
7634 BMS_BLKMEM* blkmem, /**< block memory */
7635 SCIP_SET* set, /**< global SCIP settings */
7636 SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7637 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7638 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7639 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7640 SCIP_Real newbound /**< new bound for variable */
7641 )
7642 {
7643 SCIP_VAR* parentvar;
7644 SCIP_Real oldbound;
7645 int i;
7646
7647 assert(var != NULL);
7648 assert(set != NULL);
7649 assert(var->scip == set->scip);
7650 assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && (SCIPsetIsZero(set, newbound) || SCIPsetIsEQ(set, newbound, 1.0)
7651 || SCIPsetIsEQ(set, newbound, var->locdom.ub)))
7652 || (SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS && (SCIPsetIsIntegral(set, newbound)
7653 || SCIPsetIsEQ(set, newbound, var->locdom.ub)))
7654 || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS);
7655
7656 /* check that the bound is feasible */
7657 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsLE(set, newbound, var->glbdom.ub));
7658 /* adjust bound to integral value if variable is of integral type */
7659 newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
7660
7661 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7662 {
7663 /* we do not want to exceed the upper bound, which could have happened due to numerics */
7664 newbound = MIN(newbound, var->locdom.ub);
7665
7666 /* we do not want to undercut the global lower bound, which could have happened due to numerics */
7667 newbound = MAX(newbound, var->glbdom.lb);
7668 }
7669 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7670
7671 SCIPsetDebugMsg(set, "process changing lower bound of <%s> from %g to %g\n", var->name, var->locdom.lb, newbound);
7672
7673 if( SCIPsetIsEQ(set, newbound, var->glbdom.lb) && var->glbdom.lb != var->locdom.lb ) /*lint !e777*/
7674 newbound = var->glbdom.lb;
7675 else if( SCIPsetIsEQ(set, newbound, var->locdom.lb) && !(newbound != var->locdom.lb && newbound * var->locdom.lb <= 0.0) ) /*lint !e777*/
7676 return SCIP_OKAY;
7677
7678 /* change the bound */
7679 oldbound = var->locdom.lb;
7680 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasLE(set, newbound, var->locdom.ub));
7681 var->locdom.lb = newbound;
7682
7683 /* update statistic; during the update steps of the parent variable we pass a NULL pointer to ensure that we only
7684 * once update the statistic
7685 */
7686 if( stat != NULL )
7687 SCIPstatIncrement(stat, set, domchgcount);
7688
7689 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7690 {
7691 /* merges overlapping holes into single holes, moves bounds respectively */
7692 domMerge(&var->locdom, blkmem, set, &newbound, NULL);
7693 }
7694
7695 /* issue bound change event */
7696 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
7697 if( var->eventfilter != NULL )
7698 {
7699 SCIP_CALL( varEventLbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
7700 }
7701
7702 /* process parent variables */
7703 for( i = 0; i < var->nparentvars; ++i )
7704 {
7705 parentvar = var->parentvars[i];
7706 assert(parentvar != NULL);
7707
7708 switch( SCIPvarGetStatus(parentvar) )
7709 {
7710 case SCIP_VARSTATUS_ORIGINAL:
7711 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, newbound) );
7712 break;
7713
7714 case SCIP_VARSTATUS_COLUMN:
7715 case SCIP_VARSTATUS_LOOSE:
7716 case SCIP_VARSTATUS_FIXED:
7717 case SCIP_VARSTATUS_MULTAGGR:
7718 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
7719 return SCIP_INVALIDDATA;
7720
7721 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7722 assert(parentvar->data.aggregate.var == var);
7723 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
7724 {
7725 SCIP_Real parentnewbound;
7726
7727 /* a > 0 -> change lower bound of y */
7728 assert(SCIPsetIsInfinity(set, -parentvar->locdom.lb) || SCIPsetIsInfinity(set, -oldbound)
7729 || SCIPsetIsFeasEQ(set, parentvar->locdom.lb, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
7730 || (SCIPsetIsZero(set, parentvar->locdom.lb / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
7731
7732 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7733 {
7734 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7735 /* if parent's new lower bound exceeds its upper bound, then this could be due to numerical difficulties, e.g., if numbers are large
7736 * thus, at least a relative comparision of the new lower bound and the current upper bound should proof consistency
7737 * as a result, the parent's lower bound is set to it's upper bound, and not above
7738 */
7739 if( parentnewbound > parentvar->glbdom.ub )
7740 {
7741 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7742 assert(SCIPsetIsFeasLE(set, parentnewbound, parentvar->glbdom.ub));
7743 parentnewbound = parentvar->glbdom.ub;
7744 }
7745 }
7746 else
7747 parentnewbound = newbound;
7748 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7749 }
7750 else
7751 {
7752 SCIP_Real parentnewbound;
7753
7754 /* a < 0 -> change upper bound of y */
7755 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
7756 assert(SCIPsetIsInfinity(set, parentvar->locdom.ub) || SCIPsetIsInfinity(set, -oldbound)
7757 || SCIPsetIsFeasEQ(set, parentvar->locdom.ub, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
7758 || (SCIPsetIsZero(set, parentvar->locdom.ub / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
7759
7760 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7761 {
7762 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7763 /* if parent's new upper bound is below its lower bound, then this could be due to numerical difficulties, e.g., if numbers are large
7764 * thus, at least a relative comparision of the new upper bound and the current lower bound should proof consistency
7765 * as a result, the parent's upper bound is set to it's lower bound, and not below
7766 */
7767 if( parentnewbound < parentvar->glbdom.lb )
7768 {
7769 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7770 assert(SCIPsetIsFeasGE(set, parentnewbound, parentvar->glbdom.lb));
7771 parentnewbound = parentvar->glbdom.lb;
7772 }
7773 }
7774 else
7775 parentnewbound = -newbound;
7776 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7777 }
7778 break;
7779
7780 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
7781 assert(parentvar->negatedvar != NULL);
7782 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
7783 assert(parentvar->negatedvar->negatedvar == parentvar);
7784 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue,
7785 parentvar->data.negate.constant - newbound) );
7786 break;
7787
7788 default:
7789 SCIPerrorMessage("unknown variable status\n");
7790 return SCIP_INVALIDDATA;
7791 }
7792 }
7793
7794 return SCIP_OKAY;
7795 }
7796
7797 /** performs the current change in upper bound, changes all parents accordingly */
7798 static
7799 SCIP_RETCODE varProcessChgUbLocal(
7800 SCIP_VAR* var, /**< problem variable to change */
7801 BMS_BLKMEM* blkmem, /**< block memory */
7802 SCIP_SET* set, /**< global SCIP settings */
7803 SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7804 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7805 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7806 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7807 SCIP_Real newbound /**< new bound for variable */
7808 )
7809 {
7810 SCIP_VAR* parentvar;
7811 SCIP_Real oldbound;
7812 int i;
7813
7814 assert(var != NULL);
7815 assert(set != NULL);
7816 assert(var->scip == set->scip);
7817 assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && (SCIPsetIsZero(set, newbound) || SCIPsetIsEQ(set, newbound, 1.0)
7818 || SCIPsetIsEQ(set, newbound, var->locdom.lb)))
7819 || (SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS && (SCIPsetIsIntegral(set, newbound)
7820 || SCIPsetIsEQ(set, newbound, var->locdom.lb)))
7821 || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS);
7822
7823 /* check that the bound is feasible */
7824 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsGE(set, newbound, var->glbdom.lb));
7825 /* adjust bound to integral value if variable is of integral type */
7826 newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
7827
7828 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7829 {
7830 /* we do not want to undercut the lower bound, which could have happened due to numerics */
7831 newbound = MAX(newbound, var->locdom.lb);
7832
7833 /* we do not want to exceed the global upper bound, which could have happened due to numerics */
7834 newbound = MIN(newbound, var->glbdom.ub);
7835 }
7836 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7837
7838 SCIPsetDebugMsg(set, "process changing upper bound of <%s> from %g to %g\n", var->name, var->locdom.ub, newbound);
7839
7840 if( SCIPsetIsEQ(set, newbound, var->glbdom.ub) && var->glbdom.ub != var->locdom.ub ) /*lint !e777*/
7841 newbound = var->glbdom.ub;
7842 else if( SCIPsetIsEQ(set, newbound, var->locdom.ub) && !(newbound != var->locdom.ub && newbound * var->locdom.ub <= 0.0) ) /*lint !e777*/
7843 return SCIP_OKAY;
7844
7845 /* change the bound */
7846 oldbound = var->locdom.ub;
7847 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasGE(set, newbound, var->locdom.lb));
7848 var->locdom.ub = newbound;
7849
7850 /* update statistic; during the update steps of the parent variable we pass a NULL pointer to ensure that we only
7851 * once update the statistic
7852 */
7853 if( stat != NULL )
7854 SCIPstatIncrement(stat, set, domchgcount);
7855
7856 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7857 {
7858 /* merges overlapping holes into single holes, moves bounds respectively */
7859 domMerge(&var->locdom, blkmem, set, NULL, &newbound);
7860 }
7861
7862 /* issue bound change event */
7863 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
7864 if( var->eventfilter != NULL )
7865 {
7866 SCIP_CALL( varEventUbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
7867 }
7868
7869 /* process parent variables */
7870 for( i = 0; i < var->nparentvars; ++i )
7871 {
7872 parentvar = var->parentvars[i];
7873 assert(parentvar != NULL);
7874
7875 switch( SCIPvarGetStatus(parentvar) )
7876 {
7877 case SCIP_VARSTATUS_ORIGINAL:
7878 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, newbound) );
7879 break;
7880
7881 case SCIP_VARSTATUS_COLUMN:
7882 case SCIP_VARSTATUS_LOOSE:
7883 case SCIP_VARSTATUS_FIXED:
7884 case SCIP_VARSTATUS_MULTAGGR:
7885 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
7886 return SCIP_INVALIDDATA;
7887
7888 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7889 assert(parentvar->data.aggregate.var == var);
7890 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
7891 {
7892 SCIP_Real parentnewbound;
7893
7894 /* a > 0 -> change upper bound of x */
7895 assert(SCIPsetIsInfinity(set, parentvar->locdom.ub) || SCIPsetIsInfinity(set, oldbound)
7896 || SCIPsetIsFeasEQ(set, parentvar->locdom.ub,
7897 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7898 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7899 {
7900 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7901 /* if parent's new upper bound is below its lower bound, then this could be due to numerical difficulties, e.g., if numbers are large
7902 * thus, at least a relative comparision of the new upper bound and the current lower bound should proof consistency
7903 * as a result, the parent's upper bound is set to it's lower bound, and not below
7904 */
7905 if( parentnewbound < parentvar->glbdom.lb )
7906 {
7907 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7908 assert(SCIPsetIsFeasGE(set, parentnewbound, parentvar->glbdom.lb));
7909 parentnewbound = parentvar->glbdom.lb;
7910 }
7911 }
7912 else
7913 parentnewbound = newbound;
7914 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7915 }
7916 else
7917 {
7918 SCIP_Real parentnewbound;
7919
7920 /* a < 0 -> change lower bound of x */
7921 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
7922 assert(SCIPsetIsInfinity(set, -parentvar->locdom.lb) || SCIPsetIsInfinity(set, oldbound)
7923 || SCIPsetIsFeasEQ(set, parentvar->locdom.lb,
7924 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7925 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7926 {
7927 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7928 /* if parent's new lower bound exceeds its upper bound, then this could be due to numerical difficulties, e.g., if numbers are large
7929 * thus, at least a relative comparision of the new lower bound and the current upper bound should proof consistency
7930 * as a result, the parent's lower bound is set to it's upper bound, and not above
7931 */
7932 if( parentnewbound > parentvar->glbdom.ub )
7933 {
7934 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7935 assert(SCIPsetIsFeasLE(set, parentnewbound, parentvar->glbdom.ub));
7936 parentnewbound = parentvar->glbdom.ub;
7937 }
7938 }
7939 else
7940 parentnewbound = -newbound;
7941 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7942 }
7943 break;
7944
7945 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
7946 assert(parentvar->negatedvar != NULL);
7947 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
7948 assert(parentvar->negatedvar->negatedvar == parentvar);
7949 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue,
7950 parentvar->data.negate.constant - newbound) );
7951 break;
7952
7953 default:
7954 SCIPerrorMessage("unknown variable status\n");
7955 return SCIP_INVALIDDATA;
7956 }
7957 }
7958
7959 return SCIP_OKAY;
7960 }
7961
7962 /** changes current local lower bound of variable; if possible, adjusts bound to integral value; stores inference
7963 * information in variable
7964 */
7965 SCIP_RETCODE SCIPvarChgLbLocal(
7966 SCIP_VAR* var, /**< problem variable to change */
7967 BMS_BLKMEM* blkmem, /**< block memory */
7968 SCIP_SET* set, /**< global SCIP settings */
7969 SCIP_STAT* stat, /**< problem statistics */
7970 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7971 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7972 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7973 SCIP_Real newbound /**< new bound for variable */
7974 )
7975 {
7976 assert(var != NULL);
7977 assert(blkmem != NULL);
7978 assert(set != NULL);
7979 assert(var->scip == set->scip);
7980
7981 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7982 * of the domain within feastol
7983 */
7984 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->locdom.ub));
7985
7986 /* adjust bound to integral value if variable is of integral type */
7987 newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
7988
7989 /* check that the adjusted bound is feasible */
7990 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->locdom.ub));
7991
7992 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7993 {
7994 /* we do not want to exceed the upperbound, which could have happened due to numerics */
7995 newbound = MIN(newbound, var->locdom.ub);
7996 }
7997 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7998
7999 SCIPsetDebugMsg(set, "changing lower bound of <%s>[%g,%g] to %g\n", var->name, var->locdom.lb, var->locdom.ub, newbound);
8000
8001 if( SCIPsetIsEQ(set, var->locdom.lb, newbound) && (!SCIPsetIsEQ(set, var->glbdom.lb, newbound) || var->locdom.lb == newbound) /*lint !e777*/
8002 && !(newbound != var->locdom.lb && newbound * var->locdom.lb <= 0.0) ) /*lint !e777*/
8003 return SCIP_OKAY;
8004
8005 /* change bounds of attached variables */
8006 switch( SCIPvarGetStatus(var) )
8007 {
8008 case SCIP_VARSTATUS_ORIGINAL:
8009 if( var->data.original.transvar != NULL )
8010 {
8011 SCIP_CALL( SCIPvarChgLbLocal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue,
8012 newbound) );
8013 }
8014 else
8015 {
8016 assert(set->stage == SCIP_STAGE_PROBLEM);
8017 SCIP_CALL( varProcessChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
8018 }
8019 break;
8020
8021 case SCIP_VARSTATUS_COLUMN:
8022 case SCIP_VARSTATUS_LOOSE:
8023 SCIP_CALL( varProcessChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
8024 break;
8025
8026 case SCIP_VARSTATUS_FIXED:
8027 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
8028 return SCIP_INVALIDDATA;
8029
8030 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8031 assert(var->data.aggregate.var != NULL);
8032 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
8033 {
8034 SCIP_Real childnewbound;
8035
8036 /* a > 0 -> change lower bound of y */
8037 assert((SCIPsetIsInfinity(set, -var->locdom.lb) && SCIPsetIsInfinity(set, -var->data.aggregate.var->locdom.lb))
8038 || SCIPsetIsFeasEQ(set, var->locdom.lb,
8039 var->data.aggregate.var->locdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant));
8040 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8041 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8042 else
8043 childnewbound = newbound;
8044 SCIP_CALL( SCIPvarChgLbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
8045 childnewbound) );
8046 }
8047 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8048 {
8049 SCIP_Real childnewbound;
8050
8051 /* a < 0 -> change upper bound of y */
8052 assert((SCIPsetIsInfinity(set, -var->locdom.lb) && SCIPsetIsInfinity(set, var->data.aggregate.var->locdom.ub))
8053 || SCIPsetIsFeasEQ(set, var->locdom.lb,
8054 var->data.aggregate.var->locdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant));
8055 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8056 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8057 else
8058 childnewbound = -newbound;
8059 SCIP_CALL( SCIPvarChgUbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
8060 childnewbound) );
8061 }
8062 else
8063 {
8064 SCIPerrorMessage("scalar is zero in aggregation\n");
8065 return SCIP_INVALIDDATA;
8066 }
8067 break;
8068
8069 case SCIP_VARSTATUS_MULTAGGR:
8070 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
8071 return SCIP_INVALIDDATA;
8072
8073 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8074 assert(var->negatedvar != NULL);
8075 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
8076 assert(var->negatedvar->negatedvar == var);
8077 SCIP_CALL( SCIPvarChgUbLocal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue,
8078 var->data.negate.constant - newbound) );
8079 break;
8080
8081 default:
8082 SCIPerrorMessage("unknown variable status\n");
8083 return SCIP_INVALIDDATA;
8084 }
8085
8086 return SCIP_OKAY;
8087 }
8088
8089 /** changes current local upper bound of variable; if possible, adjusts bound to integral value; stores inference
8090 * information in variable
8091 */
8092 SCIP_RETCODE SCIPvarChgUbLocal(
8093 SCIP_VAR* var, /**< problem variable to change */
8094 BMS_BLKMEM* blkmem, /**< block memory */
8095 SCIP_SET* set, /**< global SCIP settings */
8096 SCIP_STAT* stat, /**< problem statistics */
8097 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
8098 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
8099 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8100 SCIP_Real newbound /**< new bound for variable */
8101 )
8102 {
8103 assert(var != NULL);
8104 assert(blkmem != NULL);
8105 assert(set != NULL);
8106 assert(var->scip == set->scip);
8107
8108 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
8109 * of the domain within feastol
8110 */
8111 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->locdom.lb));
8112
8113 /* adjust bound to integral value if variable is of integral type */
8114 newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
8115
8116 /* check that the adjusted bound is feasible */
8117 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->locdom.lb));
8118
8119 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
8120 {
8121 /* we do not want to undercut the lowerbound, which could have happened due to numerics */
8122 newbound = MAX(newbound, var->locdom.lb);
8123 }
8124 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
8125
8126 SCIPsetDebugMsg(set, "changing upper bound of <%s>[%g,%g] to %g\n", var->name, var->locdom.lb, var->locdom.ub, newbound);
8127
8128 if( SCIPsetIsEQ(set, var->locdom.ub, newbound) && (!SCIPsetIsEQ(set, var->glbdom.ub, newbound) || var->locdom.ub == newbound) /*lint !e777*/
8129 && !(newbound != var->locdom.ub && newbound * var->locdom.ub <= 0.0) ) /*lint !e777*/
8130 return SCIP_OKAY;
8131
8132 /* change bounds of attached variables */
8133 switch( SCIPvarGetStatus(var) )
8134 {
8135 case SCIP_VARSTATUS_ORIGINAL:
8136 if( var->data.original.transvar != NULL )
8137 {
8138 SCIP_CALL( SCIPvarChgUbLocal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
8139 }
8140 else
8141 {
8142 assert(set->stage == SCIP_STAGE_PROBLEM);
8143 SCIP_CALL( varProcessChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
8144 }
8145 break;
8146
8147 case SCIP_VARSTATUS_COLUMN:
8148 case SCIP_VARSTATUS_LOOSE:
8149 SCIP_CALL( varProcessChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
8150 break;
8151
8152 case SCIP_VARSTATUS_FIXED:
8153 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
8154 return SCIP_INVALIDDATA;
8155
8156 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8157 assert(var->data.aggregate.var != NULL);
8158 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
8159 {
8160 SCIP_Real childnewbound;
8161
8162 /* a > 0 -> change upper bound of y */
8163 assert((SCIPsetIsInfinity(set, var->locdom.ub) && SCIPsetIsInfinity(set, var->data.aggregate.var->locdom.ub))
8164 || SCIPsetIsFeasEQ(set, var->locdom.ub,
8165 var->data.aggregate.var->locdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant));
8166 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8167 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8168 else
8169 childnewbound = newbound;
8170 SCIP_CALL( SCIPvarChgUbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
8171 childnewbound) );
8172 }
8173 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8174 {
8175 SCIP_Real childnewbound;
8176
8177 /* a < 0 -> change lower bound of y */
8178 assert((SCIPsetIsInfinity(set, var->locdom.ub) && SCIPsetIsInfinity(set, -var->data.aggregate.var->locdom.lb))
8179 || SCIPsetIsFeasEQ(set, var->locdom.ub,
8180 var->data.aggregate.var->locdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant));
8181 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8182 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8183 else
8184 childnewbound = -newbound;
8185 SCIP_CALL( SCIPvarChgLbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
8186 childnewbound) );
8187 }
8188 else
8189 {
8190 SCIPerrorMessage("scalar is zero in aggregation\n");
8191 return SCIP_INVALIDDATA;
8192 }
8193 break;
8194
8195 case SCIP_VARSTATUS_MULTAGGR:
8196 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
8197 return SCIP_INVALIDDATA;
8198
8199 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8200 assert(var->negatedvar != NULL);
8201 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
8202 assert(var->negatedvar->negatedvar == var);
8203 SCIP_CALL( SCIPvarChgLbLocal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue,
8204 var->data.negate.constant - newbound) );
8205 break;
8206
8207 default:
8208 SCIPerrorMessage("unknown variable status\n");
8209 return SCIP_INVALIDDATA;
8210 }
8211
8212 return SCIP_OKAY;
8213 }
8214
8215 /** changes current local bound of variable; if possible, adjusts bound to integral value; stores inference
8216 * information in variable
8217 */
8218 SCIP_RETCODE SCIPvarChgBdLocal(
8219 SCIP_VAR* var, /**< problem variable to change */
8220 BMS_BLKMEM* blkmem, /**< block memory */
8221 SCIP_SET* set, /**< global SCIP settings */
8222 SCIP_STAT* stat, /**< problem statistics */
8223 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
8224 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
8225 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8226 SCIP_Real newbound, /**< new bound for variable */
8227 SCIP_BOUNDTYPE boundtype /**< type of bound: lower or upper bound */
8228 )
8229 {
8230 /* apply bound change to the LP data */
8231 switch( boundtype )
8232 {
8233 case SCIP_BOUNDTYPE_LOWER:
8234 return SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound);
8235 case SCIP_BOUNDTYPE_UPPER:
8236 return SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound);
8237 default:
8238 SCIPerrorMessage("unknown bound type\n");
8239 return SCIP_INVALIDDATA;
8240 }
8241 }
8242
8243 /** changes lower bound of variable in current dive; if possible, adjusts bound to integral value */
8244 SCIP_RETCODE SCIPvarChgLbDive(
8245 SCIP_VAR* var, /**< problem variable to change */
8246 SCIP_SET* set, /**< global SCIP settings */
8247 SCIP_LP* lp, /**< current LP data */
8248 SCIP_Real newbound /**< new bound for variable */
8249 )
8250 {
8251 assert(var != NULL);
8252 assert(set != NULL);
8253 assert(var->scip == set->scip);
8254 assert(lp != NULL);
8255 assert(SCIPlpDiving(lp));
8256
8257 /* adjust bound for integral variables */
8258 SCIPvarAdjustLb(var, set, &newbound);
8259
8260 SCIPsetDebugMsg(set, "changing lower bound of <%s> to %g in current dive\n", var->name, newbound);
8261
8262 /* change bounds of attached variables */
8263 switch( SCIPvarGetStatus(var) )
8264 {
8265 case SCIP_VARSTATUS_ORIGINAL:
8266 assert(var->data.original.transvar != NULL);
8267 SCIP_CALL( SCIPvarChgLbDive(var->data.original.transvar, set, lp, newbound) );
8268 break;
8269
8270 case SCIP_VARSTATUS_COLUMN:
8271 assert(var->data.col != NULL);
8272 SCIP_CALL( SCIPcolChgLb(var->data.col, set, lp, newbound) );
8273 break;
8274
8275 case SCIP_VARSTATUS_LOOSE:
8276 SCIPerrorMessage("cannot change variable's bounds in dive for LOOSE variables\n");
8277 return SCIP_INVALIDDATA;
8278
8279 case SCIP_VARSTATUS_FIXED:
8280 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
8281 return SCIP_INVALIDDATA;
8282
8283 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8284 assert(var->data.aggregate.var != NULL);
8285 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
8286 {
8287 SCIP_Real childnewbound;
8288
8289 /* a > 0 -> change lower bound of y */
8290 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8291 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8292 else
8293 childnewbound = newbound;
8294 SCIP_CALL( SCIPvarChgLbDive(var->data.aggregate.var, set, lp, childnewbound) );
8295 }
8296 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8297 {
8298 SCIP_Real childnewbound;
8299
8300 /* a < 0 -> change upper bound of y */
8301 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8302 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8303 else
8304 childnewbound = -newbound;
8305 SCIP_CALL( SCIPvarChgUbDive(var->data.aggregate.var, set, lp, childnewbound) );
8306 }
8307 else
8308 {
8309 SCIPerrorMessage("scalar is zero in aggregation\n");
8310 return SCIP_INVALIDDATA;
8311 }
8312 break;
8313
8314 case SCIP_VARSTATUS_MULTAGGR:
8315 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
8316 return SCIP_INVALIDDATA;
8317
8318 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8319 assert(var->negatedvar != NULL);
8320 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
8321 assert(var->negatedvar->negatedvar == var);
8322 SCIP_CALL( SCIPvarChgUbDive(var->negatedvar, set, lp, var->data.negate.constant - newbound) );
8323 break;
8324
8325 default:
8326 SCIPerrorMessage("unknown variable status\n");
8327 return SCIP_INVALIDDATA;
8328 }
8329
8330 return SCIP_OKAY;
8331 }
8332
8333 /** changes upper bound of variable in current dive; if possible, adjusts bound to integral value */
8334 SCIP_RETCODE SCIPvarChgUbDive(
8335 SCIP_VAR* var, /**< problem variable to change */
8336 SCIP_SET* set, /**< global SCIP settings */
8337 SCIP_LP* lp, /**< current LP data */
8338 SCIP_Real newbound /**< new bound for variable */
8339 )
8340 {
8341 assert(var != NULL);
8342 assert(set != NULL);
8343 assert(var->scip == set->scip);
8344 assert(lp != NULL);
8345 assert(SCIPlpDiving(lp));
8346
8347 /* adjust bound for integral variables */
8348 SCIPvarAdjustUb(var, set, &newbound);
8349
8350 SCIPsetDebugMsg(set, "changing upper bound of <%s> to %g in current dive\n", var->name, newbound);
8351
8352 /* change bounds of attached variables */
8353 switch( SCIPvarGetStatus(var) )
8354 {
8355 case SCIP_VARSTATUS_ORIGINAL:
8356 assert(var->data.original.transvar != NULL);
8357 SCIP_CALL( SCIPvarChgUbDive(var->data.original.transvar, set, lp, newbound) );
8358 break;
8359
8360 case SCIP_VARSTATUS_COLUMN:
8361 assert(var->data.col != NULL);
8362 SCIP_CALL( SCIPcolChgUb(var->data.col, set, lp, newbound) );
8363 break;
8364
8365 case SCIP_VARSTATUS_LOOSE:
8366 SCIPerrorMessage("cannot change variable's bounds in dive for LOOSE variables\n");
8367 return SCIP_INVALIDDATA;
8368
8369 case SCIP_VARSTATUS_FIXED:
8370 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
8371 return SCIP_INVALIDDATA;
8372
8373 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8374 assert(var->data.aggregate.var != NULL);
8375 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
8376 {
8377 SCIP_Real childnewbound;
8378
8379 /* a > 0 -> change upper bound of y */
8380 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8381 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8382 else
8383 childnewbound = newbound;
8384 SCIP_CALL( SCIPvarChgUbDive(var->data.aggregate.var, set, lp, childnewbound) );
8385 }
8386 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8387 {
8388 SCIP_Real childnewbound;
8389
8390 /* a < 0 -> change lower bound of y */
8391 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8392 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8393 else
8394 childnewbound = -newbound;
8395 SCIP_CALL( SCIPvarChgLbDive(var->data.aggregate.var, set, lp, childnewbound) );
8396 }
8397 else
8398 {
8399 SCIPerrorMessage("scalar is zero in aggregation\n");
8400 return SCIP_INVALIDDATA;
8401 }
8402 break;
8403
8404 case SCIP_VARSTATUS_MULTAGGR:
8405 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
8406 return SCIP_INVALIDDATA;
8407
8408 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8409 assert(var->negatedvar != NULL);
8410 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
8411 assert(var->negatedvar->negatedvar == var);
8412 SCIP_CALL( SCIPvarChgLbDive(var->negatedvar, set, lp, var->data.negate.constant - newbound) );
8413 break;
8414
8415 default:
8416 SCIPerrorMessage("unknown variable status\n");
8417 return SCIP_INVALIDDATA;
8418 }
8419
8420 return SCIP_OKAY;
8421 }
8422
8423 /** for a multi-aggregated variable, gives the local lower bound computed by adding the local bounds from all
8424 * aggregation variables, this lower bound may be tighter than the one given by SCIPvarGetLbLocal, since the latter is
8425 * not updated if bounds of aggregation variables are changing
8426 *
8427 * calling this function for a non-multi-aggregated variable is not allowed
8428 */
8429 SCIP_Real SCIPvarGetMultaggrLbLocal(
8430 SCIP_VAR* var, /**< problem variable */
8431 SCIP_SET* set /**< global SCIP settings */
8432 )
8433 {
8434 int i;
8435 SCIP_Real lb;
8436 SCIP_Real bnd;
8437 SCIP_VAR* aggrvar;
8438 SCIP_Bool posinf;
8439 SCIP_Bool neginf;
8440
8441 assert(var != NULL);
8442 assert(set != NULL);
8443 assert(var->scip == set->scip);
8444 assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR);
8445
8446 posinf = FALSE;
8447 neginf = FALSE;
8448 lb = var->data.multaggr.constant;
8449 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8450 {
8451 aggrvar = var->data.multaggr.vars[i];
8452 if( var->data.multaggr.scalars[i] > 0.0 )
8453 {
8454 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbLocal(aggrvar, set) : SCIPvarGetLbLocal(aggrvar);
8455
8456 if( SCIPsetIsInfinity(set, bnd) )
8457 posinf = TRUE;
8458 else if( SCIPsetIsInfinity(set, -bnd) )
8459 neginf = TRUE;
8460 else
8461 lb += var->data.multaggr.scalars[i] * bnd;
8462 }
8463 else
8464 {
8465 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbLocal(aggrvar, set) : SCIPvarGetUbLocal(aggrvar);
8466
8467 if( SCIPsetIsInfinity(set, -bnd) )
8468 posinf = TRUE;
8469 else if( SCIPsetIsInfinity(set, bnd) )
8470 neginf = TRUE;
8471 else
8472 lb += var->data.multaggr.scalars[i] * bnd;
8473 }
8474
8475 /* stop if two diffrent infinities (or a -infinity) were found and return local lower bound of multi aggregated
8476 * variable
8477 */
8478 if( neginf )
8479 return SCIPvarGetLbLocal(var);
8480 }
8481
8482 /* if positive infinity flag was set to true return infinity */
8483 if( posinf )
8484 return SCIPsetInfinity(set);
8485
8486 return (MAX(lb, SCIPvarGetLbLocal(var))); /*lint !e666*/
8487 }
8488
8489 /** for a multi-aggregated variable, gives the local upper bound computed by adding the local bounds from all
8490 * aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbLocal, since the latter is
8491 * not updated if bounds of aggregation variables are changing
8492 *
8493 * calling this function for a non-multi-aggregated variable is not allowed
8494 */
8495 SCIP_Real SCIPvarGetMultaggrUbLocal(
8496 SCIP_VAR* var, /**< problem variable */
8497 SCIP_SET* set /**< global SCIP settings */
8498 )
8499 {
8500 int i;
8501 SCIP_Real ub;
8502 SCIP_Real bnd;
8503 SCIP_VAR* aggrvar;
8504 SCIP_Bool posinf;
8505 SCIP_Bool neginf;
8506
8507 assert(var != NULL);
8508 assert(set != NULL);
8509 assert(var->scip == set->scip);
8510 assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR);
8511
8512 posinf = FALSE;
8513 neginf = FALSE;
8514 ub = var->data.multaggr.constant;
8515 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8516 {
8517 aggrvar = var->data.multaggr.vars[i];
8518 if( var->data.multaggr.scalars[i] > 0.0 )
8519 {
8520 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbLocal(aggrvar, set) : SCIPvarGetUbLocal(aggrvar);
8521
8522 if( SCIPsetIsInfinity(set, bnd) )
8523 posinf = TRUE;
8524 else if( SCIPsetIsInfinity(set, -bnd) )
8525 neginf = TRUE;
8526 else
8527 ub += var->data.multaggr.scalars[i] * bnd;
8528 }
8529 else
8530 {
8531 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbLocal(aggrvar, set) : SCIPvarGetLbLocal(aggrvar);
8532
8533 if( SCIPsetIsInfinity(set, -bnd) )
8534 posinf = TRUE;
8535 else if( SCIPsetIsInfinity(set, bnd) )
8536 neginf = TRUE;
8537 else
8538 ub += var->data.multaggr.scalars[i] * bnd;
8539 }
8540
8541 /* stop if two diffrent infinities (or a -infinity) were found and return local upper bound of multi aggregated
8542 * variable
8543 */
8544 if( posinf )
8545 return SCIPvarGetUbLocal(var);
8546 }
8547
8548 /* if negative infinity flag was set to true return -infinity */
8549 if( neginf )
8550 return -SCIPsetInfinity(set);
8551
8552 return (MIN(ub, SCIPvarGetUbLocal(var))); /*lint !e666*/
8553 }
8554
8555 /** for a multi-aggregated variable, gives the global lower bound computed by adding the global bounds from all
8556 * aggregation variables, this global bound may be tighter than the one given by SCIPvarGetLbGlobal, since the latter is
8557 * not updated if bounds of aggregation variables are changing
8558 *
8559 * calling this function for a non-multi-aggregated variable is not allowed
8560 */
8561 SCIP_Real SCIPvarGetMultaggrLbGlobal(
8562 SCIP_VAR* var, /**< problem variable */
8563 SCIP_SET* set /**< global SCIP settings */
8564 )
8565 {
8566 int i;
8567 SCIP_Real lb;
8568 SCIP_Real bnd;
8569 SCIP_VAR* aggrvar;
8570 SCIP_Bool posinf;
8571 SCIP_Bool neginf;
8572
8573 assert(var != NULL);
8574 assert(set != NULL);
8575 assert(var->scip == set->scip);
8576 assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR);
8577
8578 posinf = FALSE;
8579 neginf = FALSE;
8580 lb = var->data.multaggr.constant;
8581 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8582 {
8583 aggrvar = var->data.multaggr.vars[i];
8584 if( var->data.multaggr.scalars[i] > 0.0 )
8585 {
8586 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbGlobal(aggrvar, set) : SCIPvarGetLbGlobal(aggrvar);
8587
8588 if( SCIPsetIsInfinity(set, bnd) )
8589 posinf = TRUE;
8590 else if( SCIPsetIsInfinity(set, -bnd) )
8591 neginf = TRUE;
8592 else
8593 lb += var->data.multaggr.scalars[i] * bnd;
8594 }
8595 else
8596 {
8597 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbGlobal(aggrvar, set) : SCIPvarGetUbGlobal(aggrvar);
8598
8599 if( SCIPsetIsInfinity(set, -bnd) )
8600 posinf = TRUE;
8601 else if( SCIPsetIsInfinity(set, bnd) )
8602 neginf = TRUE;
8603 else
8604 lb += var->data.multaggr.scalars[i] * bnd;
8605 }
8606
8607 /* stop if two diffrent infinities (or a -infinity) were found and return global lower bound of multi aggregated
8608 * variable
8609 */
8610 if( neginf )
8611 return SCIPvarGetLbGlobal(var);
8612 }
8613
8614 /* if positive infinity flag was set to true return infinity */
8615 if( posinf )
8616 return SCIPsetInfinity(set);
8617
8618 return (MAX(lb, SCIPvarGetLbGlobal(var))); /*lint !e666*/
8619 }
8620
8621 /** for a multi-aggregated variable, gives the global upper bound computed by adding the global bounds from all
8622 * aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbGlobal, since the latter is
8623 * not updated if bounds of aggregation variables are changing
8624 *
8625 * calling this function for a non-multi-aggregated variable is not allowed
8626 */
8627 SCIP_Real SCIPvarGetMultaggrUbGlobal(
8628 SCIP_VAR* var, /**< problem variable */
8629 SCIP_SET* set /**< global SCIP settings */
8630 )
8631 {
8632 int i;
8633 SCIP_Real ub;
8634 SCIP_Real bnd;
8635 SCIP_VAR* aggrvar;
8636 SCIP_Bool posinf;
8637 SCIP_Bool neginf;
8638
8639 assert(var != NULL);
8640 assert(set != NULL);
8641 assert(var->scip == set->scip);
8642 assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR);
8643
8644 posinf = FALSE;
8645 neginf = FALSE;
8646 ub = var->data.multaggr.constant;
8647 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8648 {
8649 aggrvar = var->data.multaggr.vars[i];
8650 if( var->data.multaggr.scalars[i] > 0.0 )
8651 {
8652 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbGlobal(aggrvar, set) : SCIPvarGetUbGlobal(aggrvar);
8653
8654 if( SCIPsetIsInfinity(set, bnd) )
8655 posinf = TRUE;
8656 else if( SCIPsetIsInfinity(set, -bnd) )
8657 neginf = TRUE;
8658 else
8659 ub += var->data.multaggr.scalars[i] * bnd;
8660 }
8661 else
8662 {
8663 bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbGlobal(aggrvar, set) : SCIPvarGetLbGlobal(aggrvar);
8664
8665 if( SCIPsetIsInfinity(set, -bnd) )
8666 posinf = TRUE;
8667 else if( SCIPsetIsInfinity(set, bnd) )
8668 neginf = TRUE;
8669 else
8670 ub += var->data.multaggr.scalars[i] * bnd;
8671 }
8672
8673 /* stop if two diffrent infinities (or a -infinity) were found and return local upper bound of multi aggregated
8674 * variable
8675 */
8676 if( posinf )
8677 return SCIPvarGetUbGlobal(var);
8678 }
8679
8680 /* if negative infinity flag was set to true return -infinity */
8681 if( neginf )
8682 return -SCIPsetInfinity(set);
8683
8684 return (MIN(ub, SCIPvarGetUbGlobal(var))); /*lint !e666*/
8685 }
8686
8687 /** adds a hole to the original domain of the variable */
8688 SCIP_RETCODE SCIPvarAddHoleOriginal(
8689 SCIP_VAR* var, /**< problem variable */
8690 BMS_BLKMEM* blkmem, /**< block memory */
8691 SCIP_SET* set, /**< global SCIP settings */
8692 SCIP_Real left, /**< left bound of open interval in new hole */
8693 SCIP_Real right /**< right bound of open interval in new hole */
8694 )
8695 {
8696 SCIP_Bool added;
8697
8698 assert(var != NULL);
8699 assert(!SCIPvarIsTransformed(var));
8700 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
8701 assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
8702 assert(set != NULL);
8703 assert(var->scip == set->scip);
8704 assert(set->stage == SCIP_STAGE_PROBLEM);
8705
8706 SCIPsetDebugMsg(set, "adding original hole (%g,%g) to <%s>\n", left, right, var->name);
8707
8708 if( SCIPsetIsEQ(set, left, right) )
8709 return SCIP_OKAY;
8710
8711 /* the interval should not be empty */
8712 assert(SCIPsetIsLT(set, left, right));
8713
8714 /* the the interval bound should already be adjusted */
8715 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8716 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8717
8718 /* the the interval should lay between the lower and upper bound */
8719 assert(SCIPsetIsGE(set, left, SCIPvarGetLbOriginal(var)));
8720 assert(SCIPsetIsLE(set, right, SCIPvarGetUbOriginal(var)));
8721
8722 /* add domain hole */
8723 SCIP_CALL( domAddHole(&var->data.original.origdom, blkmem, set, left, right, &added) );
8724
8725 /* merges overlapping holes into single holes, moves bounds respectively if hole was added */
8726 if( added )
8727 {
8728 domMerge(&var->data.original.origdom, blkmem, set, NULL, NULL);
8729 }
8730
8731 /**@todo add hole in parent and child variables (just like with bound changes);
8732 * warning! original vars' holes are in original blkmem, transformed vars' holes in transformed blkmem
8733 */
8734
8735 return SCIP_OKAY;
8736 }
8737
8738 /** performs the current add of domain, changes all parents accordingly */
8739 static
8740 SCIP_RETCODE varProcessAddHoleGlobal(
8741 SCIP_VAR* var, /**< problem variable */
8742 BMS_BLKMEM* blkmem, /**< block memory */
8743 SCIP_SET* set, /**< global SCIP settings */
8744 SCIP_STAT* stat, /**< problem statistics */
8745 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8746 SCIP_Real left, /**< left bound of open interval in new hole */
8747 SCIP_Real right, /**< right bound of open interval in new hole */
8748 SCIP_Bool* added /**< pointer to store whether the hole was added */
8749 )
8750 {
8751 SCIP_VAR* parentvar;
8752 SCIP_Real newlb;
8753 SCIP_Real newub;
8754 int i;
8755
8756 assert(var != NULL);
8757 assert(added != NULL);
8758 assert(blkmem != NULL);
8759
8760 /* the interval should not be empty */
8761 assert(SCIPsetIsLT(set, left, right));
8762
8763 /* the interval bound should already be adjusted */
8764 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8765 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8766
8767 /* the interval should lay between the lower and upper bound */
8768 assert(SCIPsetIsGE(set, left, SCIPvarGetLbGlobal(var)));
8769 assert(SCIPsetIsLE(set, right, SCIPvarGetUbGlobal(var)));
8770
8771 /* @todo add debugging mechanism for holes when using a debugging solution */
8772
8773 /* add hole to hole list */
8774 SCIP_CALL( domAddHole(&var->glbdom, blkmem, set, left, right, added) );
8775
8776 /* check if the hole is redundant */
8777 if( !(*added) )
8778 return SCIP_OKAY;
8779
8780 /* current bounds */
8781 newlb = var->glbdom.lb;
8782 newub = var->glbdom.ub;
8783
8784 /* merge domain holes */
8785 domMerge(&var->glbdom, blkmem, set, &newlb, &newub);
8786
8787 /* the bound should not be changed */
8788 assert(SCIPsetIsEQ(set, newlb, var->glbdom.lb));
8789 assert(SCIPsetIsEQ(set, newub, var->glbdom.ub));
8790
8791 /* issue bound change event */
8792 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
8793 if( var->eventfilter != NULL )
8794 {
8795 SCIP_CALL( varEventGholeAdded(var, blkmem, set, eventqueue, left, right) );
8796 }
8797
8798 /* process parent variables */
8799 for( i = 0; i < var->nparentvars; ++i )
8800 {
8801 SCIP_Real parentnewleft;
8802 SCIP_Real parentnewright;
8803 SCIP_Bool localadded;
8804
8805 parentvar = var->parentvars[i];
8806 assert(parentvar != NULL);
8807
8808 switch( SCIPvarGetStatus(parentvar) )
8809 {
8810 case SCIP_VARSTATUS_ORIGINAL:
8811 parentnewleft = left;
8812 parentnewright = right;
8813 break;
8814
8815 case SCIP_VARSTATUS_COLUMN:
8816 case SCIP_VARSTATUS_LOOSE:
8817 case SCIP_VARSTATUS_FIXED:
8818 case SCIP_VARSTATUS_MULTAGGR:
8819 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
8820 return SCIP_INVALIDDATA;
8821
8822 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8823 assert(parentvar->data.aggregate.var == var);
8824
8825 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
8826 {
8827 /* a > 0 -> change upper bound of x */
8828 parentnewleft = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8829 parentnewright = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8830 }
8831 else
8832 {
8833 /* a < 0 -> change lower bound of x */
8834 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
8835
8836 parentnewright = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8837 parentnewleft = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8838 }
8839 break;
8840
8841 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
8842 assert(parentvar->negatedvar != NULL);
8843 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
8844 assert(parentvar->negatedvar->negatedvar == parentvar);
8845
8846 parentnewright = -left + parentvar->data.negate.constant;
8847 parentnewleft = -right + parentvar->data.negate.constant;
8848 break;
8849
8850 default:
8851 SCIPerrorMessage("unknown variable status\n");
8852 return SCIP_INVALIDDATA;
8853 }
8854
8855 SCIPsetDebugMsg(set, "add global hole (%g,%g) to parent variable <%s>\n", parentnewleft, parentnewright, SCIPvarGetName(parentvar));
8856
8857 /* perform hole added for parent variable */
8858 assert(blkmem != NULL);
8859 assert(SCIPsetIsLT(set, parentnewleft, parentnewright));
8860 SCIP_CALL( varProcessAddHoleGlobal(parentvar, blkmem, set, stat, eventqueue,
8861 parentnewleft, parentnewright, &localadded) );
8862 assert(localadded);
8863 }
8864
8865 return SCIP_OKAY;
8866 }
8867
8868 /** adds a hole to the variable's global and local domain */
8869 SCIP_RETCODE SCIPvarAddHoleGlobal(
8870 SCIP_VAR* var, /**< problem variable */
8871 BMS_BLKMEM* blkmem, /**< block memory */
8872 SCIP_SET* set, /**< global SCIP settings */
8873 SCIP_STAT* stat, /**< problem statistics */
8874 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8875 SCIP_Real left, /**< left bound of open interval in new hole */
8876 SCIP_Real right, /**< right bound of open interval in new hole */
8877 SCIP_Bool* added /**< pointer to store whether the hole was added */
8878 )
8879 {
8880 SCIP_Real childnewleft;
8881 SCIP_Real childnewright;
8882
8883 assert(var != NULL);
8884 assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
8885 assert(blkmem != NULL);
8886 assert(added != NULL);
8887
8888 SCIPsetDebugMsg(set, "adding global hole (%g,%g) to <%s>\n", left, right, var->name);
8889
8890 /* the interval should not be empty */
8891 assert(SCIPsetIsLT(set, left, right));
8892
8893 /* the the interval bound should already be adjusted */
8894 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8895 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8896
8897 /* the the interval should lay between the lower and upper bound */
8898 assert(SCIPsetIsGE(set, left, SCIPvarGetLbGlobal(var)));
8899 assert(SCIPsetIsLE(set, right, SCIPvarGetUbGlobal(var)));
8900
8901 /* change bounds of attached variables */
8902 switch( SCIPvarGetStatus(var) )
8903 {
8904 case SCIP_VARSTATUS_ORIGINAL:
8905 if( var->data.original.transvar != NULL )
8906 {
8907 SCIP_CALL( SCIPvarAddHoleGlobal(var->data.original.transvar, blkmem, set, stat, eventqueue,
8908 left, right, added) );
8909 }
8910 else
8911 {
8912 assert(set->stage == SCIP_STAGE_PROBLEM);
8913
8914 SCIP_CALL( varProcessAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) );
8915 if( *added )
8916 {
8917 SCIP_Bool localadded;
8918
8919 SCIP_CALL( SCIPvarAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, &localadded) );
8920 }
8921 }
8922 break;
8923
8924 case SCIP_VARSTATUS_COLUMN:
8925 case SCIP_VARSTATUS_LOOSE:
8926 SCIP_CALL( varProcessAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) );
8927 if( *added )
8928 {
8929 SCIP_Bool localadded;
8930
8931 SCIP_CALL( SCIPvarAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, &localadded) );
8932 }
8933 break;
8934
8935 case SCIP_VARSTATUS_FIXED:
8936 SCIPerrorMessage("cannot add hole of a fixed variable\n");
8937 return SCIP_INVALIDDATA;
8938
8939 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8940 assert(var->data.aggregate.var != NULL);
8941
8942 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
8943 {
8944 /* a > 0 -> change lower bound of y */
8945 childnewleft = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
8946 childnewright = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
8947 }
8948 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8949 {
8950 childnewright = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
8951 childnewleft = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
8952 }
8953 else
8954 {
8955 SCIPerrorMessage("scalar is zero in aggregation\n");
8956 return SCIP_INVALIDDATA;
8957 }
8958 SCIP_CALL( SCIPvarAddHoleGlobal(var->data.aggregate.var, blkmem, set, stat, eventqueue,
8959 childnewleft, childnewright, added) );
8960 break;
8961
8962 case SCIP_VARSTATUS_MULTAGGR:
8963 SCIPerrorMessage("cannot add a hole of a multi-aggregated variable.\n");
8964 return SCIP_INVALIDDATA;
8965
8966 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8967 assert(var->negatedvar != NULL);
8968 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
8969 assert(var->negatedvar->negatedvar == var);
8970
8971 childnewright = -left + var->data.negate.constant;
8972 childnewleft = -right + var->data.negate.constant;
8973
8974 SCIP_CALL( SCIPvarAddHoleGlobal(var->negatedvar, blkmem, set, stat, eventqueue,
8975 childnewleft, childnewright, added) );
8976 break;
8977
8978 default:
8979 SCIPerrorMessage("unknown variable status\n");
8980 return SCIP_INVALIDDATA;
8981 }
8982
8983 return SCIP_OKAY;
8984 }
8985
8986 /** performs the current add of domain, changes all parents accordingly */
8987 static
8988 SCIP_RETCODE varProcessAddHoleLocal(
8989 SCIP_VAR* var, /**< problem variable */
8990 BMS_BLKMEM* blkmem, /**< block memory */
8991 SCIP_SET* set, /**< global SCIP settings */
8992 SCIP_STAT* stat, /**< problem statistics */
8993 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8994 SCIP_Real left, /**< left bound of open interval in new hole */
8995 SCIP_Real right, /**< right bound of open interval in new hole */
8996 SCIP_Bool* added /**< pointer to store whether the hole was added, or NULL */
8997 )
8998 {
8999 SCIP_VAR* parentvar;
9000 SCIP_Real newlb;
9001 SCIP_Real newub;
9002 int i;
9003
9004 assert(var != NULL);
9005 assert(added != NULL);
9006 assert(blkmem != NULL);
9007
9008 /* the interval should not be empty */
9009 assert(SCIPsetIsLT(set, left, right));
9010
9011 /* the the interval bound should already be adjusted */
9012 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
9013 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
9014
9015 /* the the interval should lay between the lower and upper bound */
9016 assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
9017 assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
9018
9019 /* add hole to hole list */
9020 SCIP_CALL( domAddHole(&var->locdom, blkmem, set, left, right, added) );
9021
9022 /* check if the hole is redundant */
9023 if( !(*added) )
9024 return SCIP_OKAY;
9025
9026 /* current bounds */
9027 newlb = var->locdom.lb;
9028 newub = var->locdom.ub;
9029
9030 /* merge domain holes */
9031 domMerge(&var->locdom, blkmem, set, &newlb, &newub);
9032
9033 /* the bound should not be changed */
9034 assert(SCIPsetIsEQ(set, newlb, var->locdom.lb));
9035 assert(SCIPsetIsEQ(set, newub, var->locdom.ub));
9036
9037 #if 0
9038 /* issue bound change event */
9039 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
9040 if( var->eventfilter != NULL )
9041 {
9042 SCIP_CALL( varEventLholeAdded(var, blkmem, set, lp, branchcand, eventqueue, left, right) );
9043 }
9044 #endif
9045
9046 /* process parent variables */
9047 for( i = 0; i < var->nparentvars; ++i )
9048 {
9049 SCIP_Real parentnewleft;
9050 SCIP_Real parentnewright;
9051 SCIP_Bool localadded;
9052
9053 parentvar = var->parentvars[i];
9054 assert(parentvar != NULL);
9055
9056 switch( SCIPvarGetStatus(parentvar) )
9057 {
9058 case SCIP_VARSTATUS_ORIGINAL:
9059 parentnewleft = left;
9060 parentnewright = right;
9061 break;
9062
9063 case SCIP_VARSTATUS_COLUMN:
9064 case SCIP_VARSTATUS_LOOSE:
9065 case SCIP_VARSTATUS_FIXED:
9066 case SCIP_VARSTATUS_MULTAGGR:
9067 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
9068 return SCIP_INVALIDDATA;
9069
9070 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
9071 assert(parentvar->data.aggregate.var == var);
9072
9073 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
9074 {
9075 /* a > 0 -> change upper bound of x */
9076 parentnewleft = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
9077 parentnewright = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
9078 }
9079 else
9080 {
9081 /* a < 0 -> change lower bound of x */
9082 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
9083
9084 parentnewright = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
9085 parentnewleft = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
9086 }
9087 break;
9088
9089 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
9090 assert(parentvar->negatedvar != NULL);
9091 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
9092 assert(parentvar->negatedvar->negatedvar == parentvar);
9093
9094 parentnewright = -left + parentvar->data.negate.constant;
9095 parentnewleft = -right + parentvar->data.negate.constant;
9096 break;
9097
9098 default:
9099 SCIPerrorMessage("unknown variable status\n");
9100 return SCIP_INVALIDDATA;
9101 }
9102
9103 SCIPsetDebugMsg(set, "add local hole (%g,%g) to parent variable <%s>\n", parentnewleft, parentnewright, SCIPvarGetName(parentvar));
9104
9105 /* perform hole added for parent variable */
9106 assert(blkmem != NULL);
9107 assert(SCIPsetIsLT(set, parentnewleft, parentnewright));
9108 SCIP_CALL( varProcessAddHoleLocal(parentvar, blkmem, set, stat, eventqueue,
9109 parentnewleft, parentnewright, &localadded) );
9110 assert(localadded);
9111 }
9112
9113 return SCIP_OKAY;
9114 }
9115
9116 /** adds a hole to the variable's current local domain */
9117 SCIP_RETCODE SCIPvarAddHoleLocal(
9118 SCIP_VAR* var, /**< problem variable */
9119 BMS_BLKMEM* blkmem, /**< block memory */
9120 SCIP_SET* set, /**< global SCIP settings */
9121 SCIP_STAT* stat, /**< problem statistics */
9122 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
9123 SCIP_Real left, /**< left bound of open interval in new hole */
9124 SCIP_Real right, /**< right bound of open interval in new hole */
9125 SCIP_Bool* added /**< pointer to store whether the hole was added */
9126 )
9127 {
9128 SCIP_Real childnewleft;
9129 SCIP_Real childnewright;
9130
9131 assert(var != NULL);
9132
9133 SCIPsetDebugMsg(set, "adding local hole (%g,%g) to <%s>\n", left, right, var->name);
9134
9135 assert(set != NULL);
9136 assert(var->scip == set->scip);
9137 assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
9138 assert(blkmem != NULL);
9139 assert(added != NULL);
9140
9141 /* the interval should not be empty */
9142 assert(SCIPsetIsLT(set, left, right));
9143
9144 /* the the interval bound should already be adjusted */
9145 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
9146 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
9147
9148 /* the the interval should lay between the lower and upper bound */
9149 assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
9150 assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
9151
9152 /* change bounds of attached variables */
9153 switch( SCIPvarGetStatus(var) )
9154 {
9155 case SCIP_VARSTATUS_ORIGINAL:
9156 if( var->data.original.transvar != NULL )
9157 {
9158 SCIP_CALL( SCIPvarAddHoleLocal(var->data.original.transvar, blkmem, set, stat, eventqueue,
9159 left, right, added) );
9160 }
9161 else
9162 {
9163 assert(set->stage == SCIP_STAGE_PROBLEM);
9164 SCIPstatIncrement(stat, set, domchgcount);
9165 SCIP_CALL( varProcessAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, added) );
9166 }
9167 break;
9168
9169 case SCIP_VARSTATUS_COLUMN:
9170 case SCIP_VARSTATUS_LOOSE:
9171 SCIPstatIncrement(stat, set, domchgcount);
9172 SCIP_CALL( varProcessAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, added) );
9173 break;
9174
9175 case SCIP_VARSTATUS_FIXED:
9176 SCIPerrorMessage("cannot add domain hole to a fixed variable\n");
9177 return SCIP_INVALIDDATA;
9178
9179 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
9180 assert(var->data.aggregate.var != NULL);
9181
9182 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
9183 {
9184 /* a > 0 -> change lower bound of y */
9185 childnewleft = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
9186 childnewright = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
9187 }
9188 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
9189 {
9190 childnewright = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
9191 childnewleft = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
9192 }
9193 else
9194 {
9195 SCIPerrorMessage("scalar is zero in aggregation\n");
9196 return SCIP_INVALIDDATA;
9197 }
9198 SCIP_CALL( SCIPvarAddHoleLocal(var->data.aggregate.var, blkmem, set, stat, eventqueue,
9199 childnewleft, childnewright, added) );
9200 break;
9201
9202 case SCIP_VARSTATUS_MULTAGGR:
9203 SCIPerrorMessage("cannot add domain hole to a multi-aggregated variable.\n");
9204 return SCIP_INVALIDDATA;
9205
9206 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
9207 assert(var->negatedvar != NULL);
9208 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
9209 assert(var->negatedvar->negatedvar == var);
9210
9211 childnewright = -left + var->data.negate.constant;
9212 childnewleft = -right + var->data.negate.constant;
9213
9214 SCIP_CALL( SCIPvarAddHoleLocal(var->negatedvar, blkmem, set, stat, eventqueue, childnewleft, childnewright, added) );
9215 break;
9216
9217 default:
9218 SCIPerrorMessage("unknown variable status\n");
9219 return SCIP_INVALIDDATA;
9220 }
9221
9222 return SCIP_OKAY;
9223 }
9224
9225 /** resets the global and local bounds of original variable to their original values */
9226 SCIP_RETCODE SCIPvarResetBounds(
9227 SCIP_VAR* var, /**< problem variable */
9228 BMS_BLKMEM* blkmem, /**< block memory */
9229 SCIP_SET* set, /**< global SCIP settings */
9230 SCIP_STAT* stat /**< problem statistics */
9231 )
9232 {
9233 assert(var != NULL);
9234 assert(set != NULL);
9235 assert(var->scip == set->scip);
9236 assert(SCIPvarIsOriginal(var));
9237 /* resetting of bounds on original variables which have a transformed counterpart easily fails if, e.g.,
9238 * the transformed variable has been fixed */
9239 assert(SCIPvarGetTransVar(var) == NULL);
9240
9241 /* copy the original bounds back to the global and local bounds */
9242 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, NULL, NULL, NULL, NULL, var->data.original.origdom.lb) );
9243 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, NULL, NULL, NULL, NULL, var->data.original.origdom.ub) );
9244 SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.lb) );
9245 SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.ub) );
9246
9247 /* free the global and local holelists and duplicate the original ones */
9248 /**@todo this has also to be called recursively with methods similar to SCIPvarChgLbGlobal() */
9249 holelistFree(&var->glbdom.holelist, blkmem);
9250 holelistFree(&var->locdom.holelist, blkmem);
9251 SCIP_CALL( holelistDuplicate(&var->glbdom.holelist, blkmem, set, var->data.original.origdom.holelist) );
9252 SCIP_CALL( holelistDuplicate(&var->locdom.holelist, blkmem, set, var->data.original.origdom.holelist) );
9253
9254 return SCIP_OKAY;
9255 }
9256
9257 /** issues a IMPLADDED event on the given variable */
9258 static
9259 SCIP_RETCODE varEventImplAdded(
9260 SCIP_VAR* var, /**< problem variable to change */
9261 BMS_BLKMEM* blkmem, /**< block memory */
9262 SCIP_SET* set, /**< global SCIP settings */
9263 SCIP_EVENTQUEUE* eventqueue /**< event queue */
9264 )
9265 {
9266 SCIP_EVENT* event;
9267
9268 assert(var != NULL);
9269
9270 /* issue IMPLADDED event on variable */
9271 SCIP_CALL( SCIPeventCreateImplAdded(&event, blkmem, var) );
9272 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
9273
9274 return SCIP_OKAY;
9275 }
9276
9277 /** actually performs the addition of a variable bound to the variable's vbound arrays */
9278 static
9279 SCIP_RETCODE varAddVbound(
9280 SCIP_VAR* var, /**< problem variable x in x <= b*z + d or x >= b*z + d */
9281 BMS_BLKMEM* blkmem, /**< block memory */
9282 SCIP_SET* set, /**< global SCIP settings */
9283 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9284 SCIP_BOUNDTYPE vbtype, /**< type of variable bound (LOWER or UPPER) */
9285 SCIP_VAR* vbvar, /**< variable z in x <= b*z + d or x >= b*z + d */
9286 SCIP_Real vbcoef, /**< coefficient b in x <= b*z + d or x >= b*z + d */
9287 SCIP_Real vbconstant /**< constant d in x <= b*z + d or x >= b*z + d */
9288 )
9289 {
9290 SCIP_Bool added;
9291
9292 /* It can happen that the variable "var" and the variable "vbvar" are the same variable. For example if a variable
9293 * gets aggregated, the variable bounds (vbound) of that variable are copied to the other variable. A variable bound
9294 * variable of the aggregated variable might be the same as the one its gets aggregated too.
9295 *
9296 * If the variable "var" and the variable "vbvar" are the same, the variable bound which should be added here has to
9297 * be redundant. This is the case since an infeasibility should have be detected in the previous methods. As well as
9298 * the bounds of the variable which should be also already be tightened in the previous methods. Therefore, the
9299 * variable bound can be ignored.
9300 *
9301 * From the way the the variable bound system is implemented (detecting infeasibility, tighten bounds), the
9302 * equivalence of the variables should be checked here.
9303 */
9304 if( var == vbvar )
9305 {
9306 /* in this case the variable bound has to be redundant, this means for possible assignments to this variable; this
9307 * can be checked via the global bounds of the variable */
9308 #ifndef NDEBUG
9309 SCIP_Real lb;
9310 SCIP_Real ub;
9311
9312 lb = SCIPvarGetLbGlobal(var);
9313 ub = SCIPvarGetUbGlobal(var);
9314
9315 if(vbtype == SCIP_BOUNDTYPE_LOWER)
9316 {
9317 if( vbcoef > 0.0 )
9318 {
9319 assert(SCIPsetIsGE(set, lb, lb * vbcoef + vbconstant) );
9320 assert(SCIPsetIsGE(set, ub, ub * vbcoef + vbconstant) );
9321 }
9322 else
9323 {
9324 assert(SCIPsetIsGE(set, lb, ub * vbcoef + vbconstant) );
9325 assert(SCIPsetIsGE(set, ub, lb * vbcoef + vbconstant) );
9326 }
9327 }
9328 else
9329 {
9330 assert(vbtype == SCIP_BOUNDTYPE_UPPER);
9331 if( vbcoef > 0.0 )
9332 {
9333 assert(SCIPsetIsLE(set, lb, lb * vbcoef + vbconstant) );
9334 assert(SCIPsetIsLE(set, ub, ub * vbcoef + vbconstant) );
9335 }
9336 else
9337 {
9338 assert(SCIPsetIsLE(set, lb, ub * vbcoef + vbconstant) );
9339 assert(SCIPsetIsLE(set, ub, lb * vbcoef + vbconstant) );
9340 }
9341 }
9342 #endif
9343 SCIPsetDebugMsg(set, "redundant variable bound: <%s> %s %g<%s> %+g\n",
9344 SCIPvarGetName(var), vbtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", vbcoef, SCIPvarGetName(vbvar), vbconstant);
9345
9346 return SCIP_OKAY;
9347 }
9348
9349 SCIPsetDebugMsg(set, "adding variable bound: <%s> %s %g<%s> %+g\n",
9350 SCIPvarGetName(var), vbtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", vbcoef, SCIPvarGetName(vbvar), vbconstant);
9351
9352 /* check variable bound on debugging solution */
9353 SCIP_CALL( SCIPdebugCheckVbound(set, var, vbtype, vbvar, vbcoef, vbconstant) ); /*lint !e506 !e774*/
9354
9355 /* perform the addition */
9356 if( vbtype == SCIP_BOUNDTYPE_LOWER )
9357 {
9358 SCIP_CALL( SCIPvboundsAdd(&var->vlbs, blkmem, set, vbtype, vbvar, vbcoef, vbconstant, &added) );
9359 }
9360 else
9361 {
9362 SCIP_CALL( SCIPvboundsAdd(&var->vubs, blkmem, set, vbtype, vbvar, vbcoef, vbconstant, &added) );
9363 }
9364 var->closestvblpcount = -1;
9365
9366 if( added )
9367 {
9368 /* issue IMPLADDED event */
9369 SCIP_CALL( varEventImplAdded(var, blkmem, set, eventqueue) );
9370 }
9371
9372 return SCIP_OKAY;
9373 }
9374
9375 /** checks whether the given implication is redundant or infeasible w.r.t. the implied variables global bounds */
9376 static
9377 void checkImplic(
9378 SCIP_SET* set, /**< global SCIP settings */
9379 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9380 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9381 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
9382 SCIP_Bool* redundant, /**< pointer to store whether the implication is redundant */
9383 SCIP_Bool* infeasible /**< pointer to store whether the implication is infeasible */
9384 )
9385 {
9386 SCIP_Real impllb;
9387 SCIP_Real implub;
9388
9389 assert(redundant != NULL);
9390 assert(infeasible != NULL);
9391
9392 impllb = SCIPvarGetLbGlobal(implvar);
9393 implub = SCIPvarGetUbGlobal(implvar);
9394 if( impltype == SCIP_BOUNDTYPE_LOWER )
9395 {
9396 *infeasible = SCIPsetIsFeasGT(set, implbound, implub);
9397 *redundant = SCIPsetIsFeasLE(set, implbound, impllb);
9398 }
9399 else
9400 {
9401 *infeasible = SCIPsetIsFeasLT(set, implbound, impllb);
9402 *redundant = SCIPsetIsFeasGE(set, implbound, implub);
9403 }
9404 }
9405
9406 /** applies the given implication, if it is not redundant */
9407 static
9408 SCIP_RETCODE applyImplic(
9409 BMS_BLKMEM* blkmem, /**< block memory */
9410 SCIP_SET* set, /**< global SCIP settings */
9411 SCIP_STAT* stat, /**< problem statistics */
9412 SCIP_PROB* transprob, /**< transformed problem */
9413 SCIP_PROB* origprob, /**< original problem */
9414 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9415 SCIP_REOPT* reopt, /**< reoptimization data structure */
9416 SCIP_LP* lp, /**< current LP data */
9417 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9418 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9419 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
9420 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9421 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9422 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
9423 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9424 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
9425 )
9426 {
9427 SCIP_Real implub;
9428 SCIP_Real impllb;
9429
9430 assert(infeasible != NULL);
9431
9432 *infeasible = FALSE;
9433
9434 implub = SCIPvarGetUbGlobal(implvar);
9435 impllb = SCIPvarGetLbGlobal(implvar);
9436 if( impltype == SCIP_BOUNDTYPE_LOWER )
9437 {
9438 if( SCIPsetIsFeasGT(set, implbound, implub) )
9439 {
9440 /* the implication produces a conflict: the problem is infeasible */
9441 *infeasible = TRUE;
9442 }
9443 else if( SCIPsetIsFeasGT(set, implbound, impllb) )
9444 {
9445 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9446 * with the local bound, in this case we need to store the bound change as pending bound change
9447 */
9448 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9449 {
9450 assert(tree != NULL);
9451 assert(transprob != NULL);
9452 assert(SCIPprobIsTransformed(transprob));
9453
9454 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9455 tree, reopt, lp, branchcand, eventqueue, cliquetable, implvar, implbound, SCIP_BOUNDTYPE_LOWER, FALSE) );
9456 }
9457 else
9458 {
9459 SCIP_CALL( SCIPvarChgLbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, implbound) );
9460 }
9461
9462 if( nbdchgs != NULL )
9463 (*nbdchgs)++;
9464 }
9465 }
9466 else
9467 {
9468 if( SCIPsetIsFeasLT(set, implbound, impllb) )
9469 {
9470 /* the implication produces a conflict: the problem is infeasible */
9471 *infeasible = TRUE;
9472 }
9473 else if( SCIPsetIsFeasLT(set, implbound, implub) )
9474 {
9475 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9476 * with the local bound, in this case we need to store the bound change as pending bound change
9477 */
9478 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9479 {
9480 assert(tree != NULL);
9481 assert(transprob != NULL);
9482 assert(SCIPprobIsTransformed(transprob));
9483
9484 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9485 tree, reopt, lp, branchcand, eventqueue, cliquetable, implvar, implbound, SCIP_BOUNDTYPE_UPPER, FALSE) );
9486 }
9487 else
9488 {
9489 SCIP_CALL( SCIPvarChgUbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, implbound) );
9490 }
9491
9492 if( nbdchgs != NULL )
9493 (*nbdchgs)++;
9494 }
9495 }
9496
9497 return SCIP_OKAY;
9498 }
9499
9500 /** actually performs the addition of an implication to the variable's implication arrays,
9501 * and adds the corresponding implication or variable bound to the implied variable;
9502 * if the implication is conflicting, the variable is fixed to the opposite value;
9503 * if the variable is already fixed to the given value, the implication is performed immediately;
9504 * if the implication is redundant with respect to the variables' global bounds, it is ignored
9505 */
9506 static
9507 SCIP_RETCODE varAddImplic(
9508 SCIP_VAR* var, /**< problem variable */
9509 BMS_BLKMEM* blkmem, /**< block memory */
9510 SCIP_SET* set, /**< global SCIP settings */
9511 SCIP_STAT* stat, /**< problem statistics */
9512 SCIP_PROB* transprob, /**< transformed problem */
9513 SCIP_PROB* origprob, /**< original problem */
9514 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9515 SCIP_REOPT* reopt, /**< reoptimization data structure */
9516 SCIP_LP* lp, /**< current LP data */
9517 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
9518 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9519 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9520 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9521 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9522 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9523 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
9524 SCIP_Bool isshortcut, /**< is the implication a shortcut, i.e., added as part of the transitive closure of another implication? */
9525 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9526 int* nbdchgs, /**< pointer to count the number of performed bound changes, or NULL */
9527 SCIP_Bool* added /**< pointer to store whether an implication was added */
9528 )
9529 {
9530 SCIP_Bool redundant;
9531 SCIP_Bool conflict;
9532
9533 assert(var != NULL);
9534 assert(SCIPvarIsActive(var));
9535 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
9536 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
9537 assert(SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED);
9538 assert(infeasible != NULL);
9539 assert(added != NULL);
9540
9541 /* check implication on debugging solution */
9542 SCIP_CALL( SCIPdebugCheckImplic(set, var, varfixing, implvar, impltype, implbound) ); /*lint !e506 !e774*/
9543
9544 *infeasible = FALSE;
9545 *added = FALSE;
9546
9547 /* check, if the implication is redundant or infeasible */
9548 checkImplic(set, implvar, impltype, implbound, &redundant, &conflict);
9549 assert(!redundant || !conflict);
9550 if( redundant )
9551 return SCIP_OKAY;
9552
9553 if( var == implvar )
9554 {
9555 /* special cases appear were a bound to a variable implies itself to be outside the bounds:
9556 * x == varfixing => x < 0 or x > 1
9557 */
9558 if( SCIPsetIsLT(set, implbound, 0.0) || SCIPsetIsGT(set, implbound, 1.0) )
9559 conflict = TRUE;
9560 else
9561 {
9562 /* variable implies itself: x == varfixing => x == (impltype == SCIP_BOUNDTYPE_LOWER) */
9563 assert(SCIPsetIsZero(set, implbound) || SCIPsetIsEQ(set, implbound, 1.0));
9564 assert(SCIPsetIsZero(set, implbound) == (impltype == SCIP_BOUNDTYPE_UPPER));
9565 assert(SCIPsetIsEQ(set, implbound, 1.0) == (impltype == SCIP_BOUNDTYPE_LOWER));
9566 conflict = conflict || ((varfixing == TRUE) == (impltype == SCIP_BOUNDTYPE_UPPER));
9567 if( !conflict )
9568 return SCIP_OKAY;
9569 }
9570 }
9571
9572 /* check, if the variable is already fixed */
9573 if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
9574 {
9575 /* if the variable is fixed to the given value, perform the implication; otherwise, ignore the implication */
9576 if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
9577 {
9578 SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
9579 cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) );
9580 }
9581 return SCIP_OKAY;
9582 }
9583
9584 assert((impltype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, implbound, SCIPvarGetLbGlobal(implvar)))
9585 || (impltype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, implbound, SCIPvarGetUbGlobal(implvar))));
9586
9587 if( !conflict )
9588 {
9589 assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9590
9591 if( SCIPvarIsBinary(implvar) )
9592 {
9593 SCIP_VAR* vars[2];
9594 SCIP_Bool vals[2];
9595
9596 assert(SCIPsetIsFeasEQ(set, implbound, 1.0) || SCIPsetIsFeasZero(set, implbound));
9597 assert((impltype == SCIP_BOUNDTYPE_UPPER) == SCIPsetIsFeasZero(set, implbound));
9598
9599 vars[0] = var;
9600 vars[1] = implvar;
9601 vals[0] = varfixing;
9602 vals[1] = (impltype == SCIP_BOUNDTYPE_UPPER);
9603
9604 /* add the clique to the clique table */
9605 SCIP_CALL( SCIPcliquetableAdd(cliquetable, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
9606 eventqueue, vars, vals, 2, FALSE, &conflict, nbdchgs) );
9607
9608 if( !conflict )
9609 return SCIP_OKAY;
9610 }
9611 else
9612 {
9613 /* add implication x == 0/1 -> y <= b / y >= b to the implications list of x */
9614 SCIPsetDebugMsg(set, "adding implication: <%s> == %u ==> <%s> %s %g\n",
9615 SCIPvarGetName(var), varfixing,
9616 SCIPvarGetName(implvar), impltype == SCIP_BOUNDTYPE_UPPER ? "<=" : ">=", implbound);
9617 SCIP_CALL( SCIPimplicsAdd(&var->implics, blkmem, set, stat, varfixing, implvar, impltype, implbound,
9618 isshortcut, &conflict, added) );
9619 }
9620 }
9621 assert(!conflict || !(*added));
9622
9623 /* on conflict, fix the variable to the opposite value */
9624 if( conflict )
9625 {
9626 SCIPsetDebugMsg(set, " -> implication yields a conflict: fix <%s> == %d\n", SCIPvarGetName(var), !varfixing);
9627
9628 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9629 * with the local bound, in this case we need to store the bound change as pending bound change
9630 */
9631 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9632 {
9633 assert(tree != NULL);
9634 assert(transprob != NULL);
9635 assert(SCIPprobIsTransformed(transprob));
9636
9637 if( varfixing )
9638 {
9639 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9640 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) );
9641 }
9642 else
9643 {
9644 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9645 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 1.0, SCIP_BOUNDTYPE_LOWER, FALSE) );
9646 }
9647 }
9648 else
9649 {
9650 if( varfixing )
9651 {
9652 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 0.0) );
9653 }
9654 else
9655 {
9656 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 1.0) );
9657 }
9658 }
9659 if( nbdchgs != NULL )
9660 (*nbdchgs)++;
9661
9662 return SCIP_OKAY;
9663 }
9664 else if( *added )
9665 {
9666 /* issue IMPLADDED event */
9667 SCIP_CALL( varEventImplAdded(var, blkmem, set, eventqueue) );
9668 }
9669 else
9670 {
9671 /* the implication was redundant: the inverse is also redundant */
9672 return SCIP_OKAY;
9673 }
9674
9675 assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9676
9677 /* check, whether implied variable is binary */
9678 if( !SCIPvarIsBinary(implvar) )
9679 {
9680 SCIP_Real lb;
9681 SCIP_Real ub;
9682
9683 /* add inverse variable bound to the variable bounds of y with global bounds y \in [lb,ub]:
9684 * x == 0 -> y <= b <-> y <= (ub - b)*x + b
9685 * x == 1 -> y <= b <-> y <= (b - ub)*x + ub
9686 * x == 0 -> y >= b <-> y >= (lb - b)*x + b
9687 * x == 1 -> y >= b <-> y >= (b - lb)*x + lb
9688 * for numerical reasons, ignore variable bounds with large absolute coefficient
9689 */
9690 lb = SCIPvarGetLbGlobal(implvar);
9691 ub = SCIPvarGetUbGlobal(implvar);
9692 if( impltype == SCIP_BOUNDTYPE_UPPER )
9693 {
9694 if( REALABS(implbound - ub) <= MAXABSVBCOEF )
9695 {
9696 SCIP_CALL( varAddVbound(implvar, blkmem, set, eventqueue, SCIP_BOUNDTYPE_UPPER, var,
9697 varfixing ? implbound - ub : ub - implbound, varfixing ? ub : implbound) );
9698 }
9699 }
9700 else
9701 {
9702 if( REALABS(implbound - lb) <= MAXABSVBCOEF )
9703 {
9704 SCIP_CALL( varAddVbound(implvar, blkmem, set, eventqueue, SCIP_BOUNDTYPE_LOWER, var,
9705 varfixing ? implbound - lb : lb - implbound, varfixing ? lb : implbound) );
9706 }
9707 }
9708 }
9709
9710 return SCIP_OKAY;
9711 }
9712
9713 /** adds transitive closure for binary implication x = a -> y = b */
9714 static
9715 SCIP_RETCODE varAddTransitiveBinaryClosureImplic(
9716 SCIP_VAR* var, /**< problem variable */
9717 BMS_BLKMEM* blkmem, /**< block memory */
9718 SCIP_SET* set, /**< global SCIP settings */
9719 SCIP_STAT* stat, /**< problem statistics */
9720 SCIP_PROB* transprob, /**< transformed problem */
9721 SCIP_PROB* origprob, /**< original problem */
9722 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9723 SCIP_REOPT* reopt, /**< reoptimization data structure */
9724 SCIP_LP* lp, /**< current LP data */
9725 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
9726 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9727 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9728 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9729 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9730 SCIP_Bool implvarfixing, /**< fixing b in implication */
9731 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9732 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
9733 )
9734 {
9735 SCIP_VAR** implvars;
9736 SCIP_BOUNDTYPE* impltypes;
9737 SCIP_Real* implbounds;
9738 int nimpls;
9739 int i;
9740
9741 *infeasible = FALSE;
9742
9743 /* binary variable: implications of implvar */
9744 nimpls = SCIPimplicsGetNImpls(implvar->implics, implvarfixing);
9745 implvars = SCIPimplicsGetVars(implvar->implics, implvarfixing);
9746 impltypes = SCIPimplicsGetTypes(implvar->implics, implvarfixing);
9747 implbounds = SCIPimplicsGetBounds(implvar->implics, implvarfixing);
9748
9749 /* if variable has too many implications, the implication graph may become too dense */
9750 i = MIN(nimpls, MAXIMPLSCLOSURE) - 1;
9751
9752 /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9753 * implvars[i] is fixed, s.t. the implication y == varfixing -> z <= b / z >= b is deleted; this affects the
9754 * array over which we currently iterate; the only thing that can happen, is that elements of the array are
9755 * deleted; in this case, the subsequent elements are moved to the front; if we iterate from back to front, the
9756 * only thing that can happen is that we add the same implication twice - this does no harm
9757 */
9758 while ( i >= 0 && !(*infeasible) )
9759 {
9760 SCIP_Bool added;
9761
9762 assert(implvars[i] != implvar);
9763
9764 /* we have x == varfixing -> y == implvarfixing -> z <= b / z >= b:
9765 * add implication x == varfixing -> z <= b / z >= b to the implications list of x
9766 */
9767 if( SCIPvarIsActive(implvars[i]) )
9768 {
9769 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
9770 eventqueue, varfixing, implvars[i], impltypes[i], implbounds[i], TRUE, infeasible, nbdchgs, &added) );
9771 assert(SCIPimplicsGetNImpls(implvar->implics, implvarfixing) <= nimpls);
9772 nimpls = SCIPimplicsGetNImpls(implvar->implics, implvarfixing);
9773 i = MIN(i, nimpls); /* some elements from the array could have been removed */
9774 }
9775 --i;
9776 }
9777
9778 return SCIP_OKAY;
9779 }
9780
9781 /** adds given implication to the variable's implication list, and adds all implications directly implied by this
9782 * implication to the variable's implication list;
9783 * if the implication is conflicting, the variable is fixed to the opposite value;
9784 * if the variable is already fixed to the given value, the implication is performed immediately;
9785 * if the implication is redundant with respect to the variables' global bounds, it is ignored
9786 */
9787 static
9788 SCIP_RETCODE varAddTransitiveImplic(
9789 SCIP_VAR* var, /**< problem variable */
9790 BMS_BLKMEM* blkmem, /**< block memory */
9791 SCIP_SET* set, /**< global SCIP settings */
9792 SCIP_STAT* stat, /**< problem statistics */
9793 SCIP_PROB* transprob, /**< transformed problem */
9794 SCIP_PROB* origprob, /**< original problem */
9795 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9796 SCIP_REOPT* reopt, /**< reoptimization data structure */
9797 SCIP_LP* lp, /**< current LP data */
9798 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
9799 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9800 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9801 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9802 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9803 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9804 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
9805 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
9806 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9807 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
9808 )
9809 {
9810 SCIP_Bool added;
9811
9812 assert(var != NULL);
9813 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
9814 assert(SCIPvarIsActive(var));
9815 assert(implvar != NULL);
9816 assert(SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED);
9817 assert(infeasible != NULL);
9818
9819 /* add implication x == varfixing -> y <= b / y >= b to the implications list of x */
9820 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
9821 eventqueue, varfixing, implvar, impltype, implbound, FALSE, infeasible, nbdchgs, &added) );
9822
9823 if( *infeasible || var == implvar || !transitive || !added )
9824 return SCIP_OKAY;
9825
9826 assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9827
9828 /* add transitive closure */
9829 if( SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY )
9830 {
9831 SCIP_Bool implvarfixing;
9832
9833 implvarfixing = (impltype == SCIP_BOUNDTYPE_LOWER);
9834
9835 /* binary variable: implications of implvar */
9836 SCIP_CALL( varAddTransitiveBinaryClosureImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
9837 cliquetable, branchcand, eventqueue, varfixing, implvar, implvarfixing, infeasible, nbdchgs) );
9838
9839 /* inverse implication */
9840 if( !(*infeasible) )
9841 {
9842 SCIP_CALL( varAddTransitiveBinaryClosureImplic(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
9843 cliquetable, branchcand, eventqueue, !implvarfixing, var, !varfixing, infeasible, nbdchgs) );
9844 }
9845 }
9846 else
9847 {
9848 /* non-binary variable: variable lower bounds of implvar */
9849 if( impltype == SCIP_BOUNDTYPE_UPPER && implvar->vlbs != NULL )
9850 {
9851 SCIP_VAR** vlbvars;
9852 SCIP_Real* vlbcoefs;
9853 SCIP_Real* vlbconstants;
9854 int nvlbvars;
9855 int i;
9856
9857 nvlbvars = SCIPvboundsGetNVbds(implvar->vlbs);
9858 vlbvars = SCIPvboundsGetVars(implvar->vlbs);
9859 vlbcoefs = SCIPvboundsGetCoefs(implvar->vlbs);
9860 vlbconstants = SCIPvboundsGetConstants(implvar->vlbs);
9861
9862 /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9863 * vlbvars[i] is fixed, s.t. the variable bound is deleted; this affects the array over which we currently
9864 * iterate; the only thing that can happen, is that elements of the array are deleted; in this case, the
9865 * subsequent elements are moved to the front; if we iterate from back to front, the only thing that can happen
9866 * is that we add the same implication twice - this does no harm
9867 */
9868 i = nvlbvars-1;
9869 while ( i >= 0 && !(*infeasible) )
9870 {
9871 assert(vlbvars[i] != implvar);
9872 assert(!SCIPsetIsZero(set, vlbcoefs[i]));
9873
9874 /* we have x == varfixing -> y <= b and y >= c*z + d:
9875 * c > 0: add implication x == varfixing -> z <= (b-d)/c to the implications list of x
9876 * c < 0: add implication x == varfixing -> z >= (b-d)/c to the implications list of x
9877 *
9878 * @note during an aggregation the aggregated variable "aggrvar" (the one which will have the status
9879 * SCIP_VARSTATUS_AGGREGATED afterwards) copies its variable lower and uppers bounds to the
9880 * aggregation variable (the one which will stay active);
9881 *
9882 * W.l.o.g. we consider the variable upper bounds for now. Let "vubvar" be a variable upper bound of
9883 * the aggregated variable "aggvar"; During that copying of that variable upper bound variable
9884 * "vubvar" the variable lower and upper bounds of this variable "vubvar" are also considered; note
9885 * that the "aggvar" can be a variable lower bound variable of the variable "vubvar"; Due to that
9886 * situation it can happen that we reach that code place where "vlbvars[i] == aggvar". In particular
9887 * the "aggvar" has already the variable status SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED
9888 * but is still active since the aggregation is not finished yet (in SCIPvarAggregate()); therefore we
9889 * have to explicitly check that the active variable has not a variable status
9890 * SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED;
9891 */
9892 if( SCIPvarIsActive(vlbvars[i]) && SCIPvarGetStatus(vlbvars[i]) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(vlbvars[i]) != SCIP_VARSTATUS_NEGATED )
9893 {
9894 SCIP_Real vbimplbound;
9895
9896 vbimplbound = (implbound - vlbconstants[i])/vlbcoefs[i];
9897 if( vlbcoefs[i] >= 0.0 )
9898 {
9899 vbimplbound = adjustedUb(set, SCIPvarGetType(vlbvars[i]), vbimplbound);
9900 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9901 branchcand, eventqueue, varfixing, vlbvars[i], SCIP_BOUNDTYPE_UPPER, vbimplbound, TRUE,
9902 infeasible, nbdchgs, &added) );
9903 }
9904 else
9905 {
9906 vbimplbound = adjustedLb(set, SCIPvarGetType(vlbvars[i]), vbimplbound);
9907 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9908 branchcand, eventqueue, varfixing, vlbvars[i], SCIP_BOUNDTYPE_LOWER, vbimplbound, TRUE,
9909 infeasible, nbdchgs, &added) );
9910 }
9911 nvlbvars = SCIPvboundsGetNVbds(implvar->vlbs);
9912 i = MIN(i, nvlbvars); /* some elements from the array could have been removed */
9913 }
9914 --i;
9915 }
9916 }
9917
9918 /* non-binary variable: variable upper bounds of implvar */
9919 if( impltype == SCIP_BOUNDTYPE_LOWER && implvar->vubs != NULL )
9920 {
9921 SCIP_VAR** vubvars;
9922 SCIP_Real* vubcoefs;
9923 SCIP_Real* vubconstants;
9924 int nvubvars;
9925 int i;
9926
9927 nvubvars = SCIPvboundsGetNVbds(implvar->vubs);
9928 vubvars = SCIPvboundsGetVars(implvar->vubs);
9929 vubcoefs = SCIPvboundsGetCoefs(implvar->vubs);
9930 vubconstants = SCIPvboundsGetConstants(implvar->vubs);
9931
9932 /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9933 * vubvars[i] is fixed, s.t. the variable bound is deleted; this affects the array over which we currently
9934 * iterate; the only thing that can happen, is that elements of the array are deleted; in this case, the
9935 * subsequent elements are moved to the front; if we iterate from back to front, the only thing that can happen
9936 * is that we add the same implication twice - this does no harm
9937 */
9938 i = nvubvars-1;
9939 while ( i >= 0 && !(*infeasible) )
9940 {
9941 assert(vubvars[i] != implvar);
9942 assert(!SCIPsetIsZero(set, vubcoefs[i]));
9943
9944 /* we have x == varfixing -> y >= b and y <= c*z + d:
9945 * c > 0: add implication x == varfixing -> z >= (b-d)/c to the implications list of x
9946 * c < 0: add implication x == varfixing -> z <= (b-d)/c to the implications list of x
9947 *
9948 * @note during an aggregation the aggregated variable "aggrvar" (the one which will have the status
9949 * SCIP_VARSTATUS_AGGREGATED afterwards) copies its variable lower and uppers bounds to the
9950 * aggregation variable (the one which will stay active);
9951 *
9952 * W.l.o.g. we consider the variable lower bounds for now. Let "vlbvar" be a variable lower bound of
9953 * the aggregated variable "aggvar"; During that copying of that variable lower bound variable
9954 * "vlbvar" the variable lower and upper bounds of this variable "vlbvar" are also considered; note
9955 * that the "aggvar" can be a variable upper bound variable of the variable "vlbvar"; Due to that
9956 * situation it can happen that we reach that code place where "vubvars[i] == aggvar". In particular
9957 * the "aggvar" has already the variable status SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED
9958 * but is still active since the aggregation is not finished yet (in SCIPvarAggregate()); therefore we
9959 * have to explicitly check that the active variable has not a variable status
9960 * SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED;
9961 */
9962 if( SCIPvarIsActive(vubvars[i]) && SCIPvarGetStatus(vubvars[i]) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(vubvars[i]) != SCIP_VARSTATUS_NEGATED )
9963 {
9964 SCIP_Real vbimplbound;
9965
9966 vbimplbound = (implbound - vubconstants[i])/vubcoefs[i];
9967 if( vubcoefs[i] >= 0.0 )
9968 {
9969 vbimplbound = adjustedLb(set, SCIPvarGetType(vubvars[i]), vbimplbound);
9970 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9971 branchcand, eventqueue, varfixing, vubvars[i], SCIP_BOUNDTYPE_LOWER, vbimplbound, TRUE,
9972 infeasible, nbdchgs, &added) );
9973 }
9974 else
9975 {
9976 vbimplbound = adjustedUb(set, SCIPvarGetType(vubvars[i]), vbimplbound);
9977 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9978 branchcand, eventqueue, varfixing, vubvars[i], SCIP_BOUNDTYPE_UPPER, vbimplbound, TRUE,
9979 infeasible, nbdchgs, &added) );
9980 }
9981 nvubvars = SCIPvboundsGetNVbds(implvar->vubs);
9982 i = MIN(i, nvubvars); /* some elements from the array could have been removed */
9983 }
9984 --i;
9985 }
9986 }
9987 }
9988
9989 return SCIP_OKAY;
9990 }
9991
9992 /** informs variable x about a globally valid variable lower bound x >= b*z + d with integer variable z;
9993 * if z is binary, the corresponding valid implication for z is also added;
9994 * improves the global bounds of the variable and the vlb variable if possible
9995 */
9996 SCIP_RETCODE SCIPvarAddVlb(
9997 SCIP_VAR* var, /**< problem variable */
9998 BMS_BLKMEM* blkmem, /**< block memory */
9999 SCIP_SET* set, /**< global SCIP settings */
10000 SCIP_STAT* stat, /**< problem statistics */
10001 SCIP_PROB* transprob, /**< transformed problem */
10002 SCIP_PROB* origprob, /**< original problem */
10003 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
10004 SCIP_REOPT* reopt, /**< reoptimization data structure */
10005 SCIP_LP* lp, /**< current LP data */
10006 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
10007 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
10008 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
10009 SCIP_VAR* vlbvar, /**< variable z in x >= b*z + d */
10010 SCIP_Real vlbcoef, /**< coefficient b in x >= b*z + d */
10011 SCIP_Real vlbconstant, /**< constant d in x >= b*z + d */
10012 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
10013 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
10014 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
10015 )
10016 {
10017 assert(var != NULL);
10018 assert(set != NULL);
10019 assert(var->scip == set->scip);
10020 assert(SCIPvarGetType(vlbvar) != SCIP_VARTYPE_CONTINUOUS);
10021 assert(infeasible != NULL);
10022
10023 SCIPsetDebugMsg(set, "adding variable lower bound <%s> >= %g<%s> + %g\n", SCIPvarGetName(var), vlbcoef, SCIPvarGetName(vlbvar), vlbconstant);
10024
10025 *infeasible = FALSE;
10026 if( nbdchgs != NULL )
10027 *nbdchgs = 0;
10028
10029 switch( SCIPvarGetStatus(var) )
10030 {
10031 case SCIP_VARSTATUS_ORIGINAL:
10032 assert(var->data.original.transvar != NULL);
10033 SCIP_CALL( SCIPvarAddVlb(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10034 cliquetable, branchcand, eventqueue, vlbvar, vlbcoef, vlbconstant, transitive, infeasible, nbdchgs) );
10035 break;
10036
10037 case SCIP_VARSTATUS_COLUMN:
10038 case SCIP_VARSTATUS_LOOSE:
10039 case SCIP_VARSTATUS_FIXED:
10040 /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */
10041 SCIP_CALL( SCIPvarGetProbvarSum(&vlbvar, set, &vlbcoef, &vlbconstant) );
10042 SCIPsetDebugMsg(set, " -> transformed to variable lower bound <%s> >= %g<%s> + %g\n", SCIPvarGetName(var), vlbcoef, SCIPvarGetName(vlbvar), vlbconstant);
10043
10044 /* if the vlb coefficient is zero, just update the lower bound of the variable */
10045 if( SCIPsetIsZero(set, vlbcoef) )
10046 {
10047 if( SCIPsetIsFeasGT(set, vlbconstant, SCIPvarGetUbGlobal(var)) )
10048 *infeasible = TRUE;
10049 else if( SCIPsetIsFeasGT(set, vlbconstant, SCIPvarGetLbGlobal(var)) )
10050 {
10051 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10052 * with the local bound, in this case we need to store the bound change as pending bound change
10053 */
10054 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10055 {
10056 assert(tree != NULL);
10057 assert(transprob != NULL);
10058 assert(SCIPprobIsTransformed(transprob));
10059
10060 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10061 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, vlbconstant, SCIP_BOUNDTYPE_LOWER, FALSE) );
10062 }
10063 else
10064 {
10065 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, vlbconstant) );
10066 }
10067
10068 if( nbdchgs != NULL )
10069 (*nbdchgs)++;
10070 }
10071 }
10072 else if( var == vlbvar )
10073 {
10074 /* the variables cancels out, the variable bound constraint is either redundant or proves global infeasibility */
10075 if( SCIPsetIsEQ(set, vlbcoef, 1.0) )
10076 {
10077 if( SCIPsetIsPositive(set, vlbconstant) )
10078 *infeasible = TRUE;
10079 return SCIP_OKAY;
10080 }
10081 else
10082 {
10083 SCIP_Real lb = SCIPvarGetLbGlobal(var);
10084 SCIP_Real ub = SCIPvarGetUbGlobal(var);
10085
10086 /* the variable bound constraint defines a new upper bound */
10087 if( SCIPsetIsGT(set, vlbcoef, 1.0) )
10088 {
10089 SCIP_Real newub = vlbconstant / (1.0 - vlbcoef);
10090
10091 if( SCIPsetIsFeasLT(set, newub, lb) )
10092 {
10093 *infeasible = TRUE;
10094 return SCIP_OKAY;
10095 }
10096 else if( SCIPsetIsFeasLT(set, newub, ub) )
10097 {
10098 /* bound might be adjusted due to integrality condition */
10099 newub = adjustedUb(set, SCIPvarGetType(var), newub);
10100
10101 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10102 * with the local bound, in this case we need to store the bound change as pending bound change
10103 */
10104 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10105 {
10106 assert(tree != NULL);
10107 assert(transprob != NULL);
10108 assert(SCIPprobIsTransformed(transprob));
10109
10110 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10111 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10112 }
10113 else
10114 {
10115 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newub) );
10116 }
10117
10118 if( nbdchgs != NULL )
10119 (*nbdchgs)++;
10120 }
10121 }
10122 /* the variable bound constraint defines a new lower bound */
10123 else
10124 {
10125 SCIP_Real newlb;
10126
10127 assert(SCIPsetIsLT(set, vlbcoef, 1.0));
10128
10129 newlb = vlbconstant / (1.0 - vlbcoef);
10130
10131 if( SCIPsetIsFeasGT(set, newlb, ub) )
10132 {
10133 *infeasible = TRUE;
10134 return SCIP_OKAY;
10135 }
10136 else if( SCIPsetIsFeasGT(set, newlb, lb) )
10137 {
10138 /* bound might be adjusted due to integrality condition */
10139 newlb = adjustedLb(set, SCIPvarGetType(var), newlb);
10140
10141 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10142 * with the local bound, in this case we need to store the bound change as pending bound change
10143 */
10144 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10145 {
10146 assert(tree != NULL);
10147 assert(transprob != NULL);
10148 assert(SCIPprobIsTransformed(transprob));
10149
10150 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10151 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10152 }
10153 else
10154 {
10155 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newlb) );
10156 }
10157
10158 if( nbdchgs != NULL )
10159 (*nbdchgs)++;
10160 }
10161 }
10162 }
10163 }
10164 else if( SCIPvarIsActive(vlbvar) )
10165 {
10166 SCIP_Real xlb;
10167 SCIP_Real xub;
10168 SCIP_Real zlb;
10169 SCIP_Real zub;
10170 SCIP_Real minvlb;
10171 SCIP_Real maxvlb;
10172
10173 assert(SCIPvarGetStatus(vlbvar) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(vlbvar) == SCIP_VARSTATUS_COLUMN);
10174 assert(vlbcoef != 0.0);
10175
10176 minvlb = -SCIPsetInfinity(set);
10177 maxvlb = SCIPsetInfinity(set);
10178
10179 xlb = SCIPvarGetLbGlobal(var);
10180 xub = SCIPvarGetUbGlobal(var);
10181 zlb = SCIPvarGetLbGlobal(vlbvar);
10182 zub = SCIPvarGetUbGlobal(vlbvar);
10183
10184 /* improve global bounds of vlb variable, and calculate minimal and maximal value of variable bound */
10185 if( vlbcoef >= 0.0 )
10186 {
10187 SCIP_Real newzub;
10188
10189 if( !SCIPsetIsInfinity(set, xub) )
10190 {
10191 /* x >= b*z + d -> z <= (x-d)/b */
10192 newzub = (xub - vlbconstant)/vlbcoef;
10193
10194 /* return if the new bound is less than -infinity */
10195 if( SCIPsetIsInfinity(set, REALABS(newzub)) )
10196 return SCIP_OKAY;
10197
10198 if( SCIPsetIsFeasLT(set, newzub, zlb) )
10199 {
10200 *infeasible = TRUE;
10201 return SCIP_OKAY;
10202 }
10203 if( SCIPsetIsFeasLT(set, newzub, zub) )
10204 {
10205 /* bound might be adjusted due to integrality condition */
10206 newzub = adjustedUb(set, SCIPvarGetType(vlbvar), newzub);
10207
10208 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10209 * with the local bound, in this case we need to store the bound change as pending bound change
10210 */
10211 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10212 {
10213 assert(tree != NULL);
10214 assert(transprob != NULL);
10215 assert(SCIPprobIsTransformed(transprob));
10216
10217 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10218 tree, reopt, lp, branchcand, eventqueue, cliquetable, vlbvar, newzub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10219 }
10220 else
10221 {
10222 SCIP_CALL( SCIPvarChgUbGlobal(vlbvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzub) );
10223 }
10224 zub = newzub;
10225
10226 if( nbdchgs != NULL )
10227 (*nbdchgs)++;
10228 }
10229 maxvlb = vlbcoef * zub + vlbconstant;
10230 if( !SCIPsetIsInfinity(set, -zlb) )
10231 minvlb = vlbcoef * zlb + vlbconstant;
10232 }
10233 else
10234 {
10235 if( !SCIPsetIsInfinity(set, zub) )
10236 maxvlb = vlbcoef * zub + vlbconstant;
10237 if( !SCIPsetIsInfinity(set, -zlb) )
10238 minvlb = vlbcoef * zlb + vlbconstant;
10239 }
10240 }
10241 else
10242 {
10243 SCIP_Real newzlb;
10244
10245 if( !SCIPsetIsInfinity(set, xub) )
10246 {
10247 /* x >= b*z + d -> z >= (x-d)/b */
10248 newzlb = (xub - vlbconstant)/vlbcoef;
10249
10250 /* return if the new bound is larger than infinity */
10251 if( SCIPsetIsInfinity(set, REALABS(newzlb)) )
10252 return SCIP_OKAY;
10253
10254 if( SCIPsetIsFeasGT(set, newzlb, zub) )
10255 {
10256 *infeasible = TRUE;
10257 return SCIP_OKAY;
10258 }
10259 if( SCIPsetIsFeasGT(set, newzlb, zlb) )
10260 {
10261 /* bound might be adjusted due to integrality condition */
10262 newzlb = adjustedLb(set, SCIPvarGetType(vlbvar), newzlb);
10263
10264 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10265 * with the local bound, in this case we need to store the bound change as pending bound change
10266 */
10267 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10268 {
10269 assert(tree != NULL);
10270 assert(transprob != NULL);
10271 assert(SCIPprobIsTransformed(transprob));
10272
10273 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10274 tree, reopt, lp, branchcand, eventqueue, cliquetable, vlbvar, newzlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10275 }
10276 else
10277 {
10278 SCIP_CALL( SCIPvarChgLbGlobal(vlbvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzlb) );
10279 }
10280 zlb = newzlb;
10281
10282 if( nbdchgs != NULL )
10283 (*nbdchgs)++;
10284 }
10285 maxvlb = vlbcoef * zlb + vlbconstant;
10286 if( !SCIPsetIsInfinity(set, zub) )
10287 minvlb = vlbcoef * zub + vlbconstant;
10288 }
10289 else
10290 {
10291 if( !SCIPsetIsInfinity(set, -zlb) )
10292 maxvlb = vlbcoef * zlb + vlbconstant;
10293 if( !SCIPsetIsInfinity(set, zub) )
10294 minvlb = vlbcoef * zub + vlbconstant;
10295 }
10296 }
10297 if( maxvlb < minvlb )
10298 maxvlb = minvlb;
10299
10300 /* adjust bounds due to integrality of variable */
10301 minvlb = adjustedLb(set, SCIPvarGetType(var), minvlb);
10302 maxvlb = adjustedLb(set, SCIPvarGetType(var), maxvlb);
10303
10304 /* check bounds for feasibility */
10305 if( SCIPsetIsFeasGT(set, minvlb, xub) || (var == vlbvar && SCIPsetIsEQ(set, vlbcoef, 1.0) && SCIPsetIsFeasPositive(set, vlbconstant)) )
10306 {
10307 *infeasible = TRUE;
10308 return SCIP_OKAY;
10309 }
10310 /* improve global lower bound of variable */
10311 if( SCIPsetIsFeasGT(set, minvlb, xlb) )
10312 {
10313 /* bound might be adjusted due to integrality condition */
10314 minvlb = adjustedLb(set, SCIPvarGetType(var), minvlb);
10315
10316 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10317 * with the local bound, in this case we need to store the bound change as pending bound change
10318 */
10319 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10320 {
10321 assert(tree != NULL);
10322 assert(transprob != NULL);
10323 assert(SCIPprobIsTransformed(transprob));
10324
10325 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10326 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, minvlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10327 }
10328 else
10329 {
10330 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, minvlb) );
10331 }
10332 xlb = minvlb;
10333
10334 if( nbdchgs != NULL )
10335 (*nbdchgs)++;
10336 }
10337 minvlb = xlb;
10338
10339 /* improve variable bound for binary z by moving the variable's global bound to the vlb constant */
10340 if( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY )
10341 {
10342 /* b > 0: x >= (maxvlb - minvlb) * z + minvlb
10343 * b < 0: x >= (minvlb - maxvlb) * z + maxvlb
10344 */
10345
10346 assert(!SCIPsetIsInfinity(set, maxvlb) && !SCIPsetIsInfinity(set, -minvlb));
10347
10348 if( vlbcoef >= 0.0 )
10349 {
10350 vlbcoef = maxvlb - minvlb;
10351 vlbconstant = minvlb;
10352 }
10353 else
10354 {
10355 vlbcoef = minvlb - maxvlb;
10356 vlbconstant = maxvlb;
10357 }
10358 }
10359
10360 /* add variable bound to the variable bounds list */
10361 if( SCIPsetIsFeasGT(set, maxvlb, xlb) )
10362 {
10363 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED);
10364 assert(!SCIPsetIsZero(set, vlbcoef));
10365
10366 /* if one of the variables is binary, add the corresponding implication to the variable's implication
10367 * list, thereby also adding the variable bound (or implication) to the other variable
10368 */
10369 if( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY )
10370 {
10371 /* add corresponding implication:
10372 * b > 0, x >= b*z + d <-> z == 1 -> x >= b+d
10373 * b < 0, x >= b*z + d <-> z == 0 -> x >= d
10374 */
10375 SCIP_CALL( varAddTransitiveImplic(vlbvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10376 cliquetable, branchcand, eventqueue, (vlbcoef >= 0.0), var, SCIP_BOUNDTYPE_LOWER, maxvlb, transitive,
10377 infeasible, nbdchgs) );
10378 }
10379 else if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
10380 {
10381 /* add corresponding implication:
10382 * b > 0, x >= b*z + d <-> x == 0 -> z <= -d/b
10383 * b < 0, x >= b*z + d <-> x == 0 -> z >= -d/b
10384 */
10385 SCIP_Real implbound;
10386 implbound = -vlbconstant/vlbcoef;
10387
10388 /* tighten the implication bound if the variable is integer */
10389 if( SCIPvarIsIntegral(vlbvar) )
10390 {
10391 if( vlbcoef >= 0 )
10392 implbound = SCIPsetFloor(set, implbound);
10393 else
10394 implbound = SCIPsetCeil(set, implbound);
10395 }
10396 SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10397 cliquetable, branchcand, eventqueue, FALSE, vlbvar, (vlbcoef >= 0.0 ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER),
10398 implbound, transitive, infeasible, nbdchgs) );
10399 }
10400 else
10401 {
10402 SCIP_CALL( varAddVbound(var, blkmem, set, eventqueue, SCIP_BOUNDTYPE_LOWER, vlbvar, vlbcoef, vlbconstant) );
10403 }
10404 }
10405 }
10406 break;
10407
10408 case SCIP_VARSTATUS_AGGREGATED:
10409 /* x = a*y + c: x >= b*z + d <=> a*y + c >= b*z + d <=> y >= b/a * z + (d-c)/a, if a > 0
10410 * y <= b/a * z + (d-c)/a, if a < 0
10411 */
10412 assert(var->data.aggregate.var != NULL);
10413 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
10414 {
10415 /* a > 0 -> add variable lower bound */
10416 SCIP_CALL( SCIPvarAddVlb(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10417 cliquetable, branchcand, eventqueue, vlbvar, vlbcoef/var->data.aggregate.scalar,
10418 (vlbconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10419 }
10420 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
10421 {
10422 /* a < 0 -> add variable upper bound */
10423 SCIP_CALL( SCIPvarAddVub(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10424 cliquetable, branchcand, eventqueue, vlbvar, vlbcoef/var->data.aggregate.scalar,
10425 (vlbconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10426 }
10427 else
10428 {
10429 SCIPerrorMessage("scalar is zero in aggregation\n");
10430 return SCIP_INVALIDDATA;
10431 }
10432 break;
10433
10434 case SCIP_VARSTATUS_MULTAGGR:
10435 /* nothing to do here */
10436 break;
10437
10438 case SCIP_VARSTATUS_NEGATED:
10439 /* x = offset - x': x >= b*z + d <=> offset - x' >= b*z + d <=> x' <= -b*z + (offset-d) */
10440 assert(var->negatedvar != NULL);
10441 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
10442 assert(var->negatedvar->negatedvar == var);
10443 SCIP_CALL( SCIPvarAddVub(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10444 branchcand, eventqueue, vlbvar, -vlbcoef, var->data.negate.constant - vlbconstant, transitive, infeasible,
10445 nbdchgs) );
10446 break;
10447
10448 default:
10449 SCIPerrorMessage("unknown variable status\n");
10450 return SCIP_INVALIDDATA;
10451 }
10452
10453 return SCIP_OKAY;
10454 }
10455
10456 /** informs variable x about a globally valid variable upper bound x <= b*z + d with integer variable z;
10457 * if z is binary, the corresponding valid implication for z is also added;
10458 * updates the global bounds of the variable and the vub variable correspondingly
10459 */
10460 SCIP_RETCODE SCIPvarAddVub(
10461 SCIP_VAR* var, /**< problem variable */
10462 BMS_BLKMEM* blkmem, /**< block memory */
10463 SCIP_SET* set, /**< global SCIP settings */
10464 SCIP_STAT* stat, /**< problem statistics */
10465 SCIP_PROB* transprob, /**< transformed problem */
10466 SCIP_PROB* origprob, /**< original problem */
10467 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
10468 SCIP_REOPT* reopt, /**< reoptimization data structure */
10469 SCIP_LP* lp, /**< current LP data */
10470 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
10471 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
10472 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
10473 SCIP_VAR* vubvar, /**< variable z in x <= b*z + d */
10474 SCIP_Real vubcoef, /**< coefficient b in x <= b*z + d */
10475 SCIP_Real vubconstant, /**< constant d in x <= b*z + d */
10476 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
10477 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
10478 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
10479 )
10480 {
10481 assert(var != NULL);
10482 assert(set != NULL);
10483 assert(var->scip == set->scip);
10484 assert(SCIPvarGetType(vubvar) != SCIP_VARTYPE_CONTINUOUS);
10485 assert(infeasible != NULL);
10486
10487 SCIPsetDebugMsg(set, "adding variable upper bound <%s> <= %g<%s> + %g\n", SCIPvarGetName(var), vubcoef, SCIPvarGetName(vubvar), vubconstant);
10488
10489 *infeasible = FALSE;
10490 if( nbdchgs != NULL )
10491 *nbdchgs = 0;
10492
10493 switch( SCIPvarGetStatus(var) )
10494 {
10495 case SCIP_VARSTATUS_ORIGINAL:
10496 assert(var->data.original.transvar != NULL);
10497 SCIP_CALL( SCIPvarAddVub(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10498 cliquetable, branchcand, eventqueue, vubvar, vubcoef, vubconstant, transitive, infeasible, nbdchgs) );
10499 break;
10500
10501 case SCIP_VARSTATUS_COLUMN:
10502 case SCIP_VARSTATUS_LOOSE:
10503 case SCIP_VARSTATUS_FIXED:
10504 /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */
10505 SCIP_CALL( SCIPvarGetProbvarSum(&vubvar, set, &vubcoef, &vubconstant) );
10506 SCIPsetDebugMsg(set, " -> transformed to variable upper bound <%s> <= %g<%s> + %g\n",
10507 SCIPvarGetName(var), vubcoef, SCIPvarGetName(vubvar), vubconstant);
10508
10509 /* if the vub coefficient is zero, just update the upper bound of the variable */
10510 if( SCIPsetIsZero(set, vubcoef) )
10511 {
10512 if( SCIPsetIsFeasLT(set, vubconstant, SCIPvarGetLbGlobal(var)) )
10513 *infeasible = TRUE;
10514 else if( SCIPsetIsFeasLT(set, vubconstant, SCIPvarGetUbGlobal(var)) )
10515 {
10516 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10517 * with the local bound, in this case we need to store the bound change as pending bound change
10518 */
10519 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10520 {
10521 assert(tree != NULL);
10522 assert(transprob != NULL);
10523 assert(SCIPprobIsTransformed(transprob));
10524
10525 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10526 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, vubconstant, SCIP_BOUNDTYPE_UPPER, FALSE) );
10527 }
10528 else
10529 {
10530 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, vubconstant) );
10531 }
10532
10533 if( nbdchgs != NULL )
10534 (*nbdchgs)++;
10535 }
10536 }
10537 else if( var == vubvar )
10538 {
10539 /* the variables cancels out, the variable bound constraint is either redundant or proves global infeasibility */
10540 if( SCIPsetIsEQ(set, vubcoef, 1.0) )
10541 {
10542 if( SCIPsetIsNegative(set, vubconstant) )
10543 *infeasible = TRUE;
10544 return SCIP_OKAY;
10545 }
10546 else
10547 {
10548 SCIP_Real lb = SCIPvarGetLbGlobal(var);
10549 SCIP_Real ub = SCIPvarGetUbGlobal(var);
10550
10551 /* the variable bound constraint defines a new lower bound */
10552 if( SCIPsetIsGT(set, vubcoef, 1.0) )
10553 {
10554 SCIP_Real newlb = vubconstant / (1.0 - vubcoef);
10555
10556 if( SCIPsetIsFeasGT(set, newlb, ub) )
10557 {
10558 *infeasible = TRUE;
10559 return SCIP_OKAY;
10560 }
10561 else if( SCIPsetIsFeasGT(set, newlb, lb) )
10562 {
10563 /* bound might be adjusted due to integrality condition */
10564 newlb = adjustedLb(set, SCIPvarGetType(var), newlb);
10565
10566 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10567 * with the local bound, in this case we need to store the bound change as pending bound change
10568 */
10569 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10570 {
10571 assert(tree != NULL);
10572 assert(transprob != NULL);
10573 assert(SCIPprobIsTransformed(transprob));
10574
10575 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10576 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10577 }
10578 else
10579 {
10580 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newlb) );
10581 }
10582
10583 if( nbdchgs != NULL )
10584 (*nbdchgs)++;
10585 }
10586 }
10587 /* the variable bound constraint defines a new upper bound */
10588 else
10589 {
10590 SCIP_Real newub;
10591
10592 assert(SCIPsetIsLT(set, vubcoef, 1.0));
10593
10594 newub = vubconstant / (1.0 - vubcoef);
10595
10596 if( SCIPsetIsFeasLT(set, newub, lb) )
10597 {
10598 *infeasible = TRUE;
10599 return SCIP_OKAY;
10600 }
10601 else if( SCIPsetIsFeasLT(set, newub, ub) )
10602 {
10603 /* bound might be adjusted due to integrality condition */
10604 newub = adjustedUb(set, SCIPvarGetType(var), newub);
10605
10606 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10607 * with the local bound, in this case we need to store the bound change as pending bound change
10608 */
10609 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10610 {
10611 assert(tree != NULL);
10612 assert(transprob != NULL);
10613 assert(SCIPprobIsTransformed(transprob));
10614
10615 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10616 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10617 }
10618 else
10619 {
10620 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newub) );
10621 }
10622
10623 if( nbdchgs != NULL )
10624 (*nbdchgs)++;
10625 }
10626 }
10627 }
10628 }
10629 else if( SCIPvarIsActive(vubvar) )
10630 {
10631 SCIP_Real xlb;
10632 SCIP_Real xub;
10633 SCIP_Real zlb;
10634 SCIP_Real zub;
10635 SCIP_Real minvub;
10636 SCIP_Real maxvub;
10637
10638 assert(SCIPvarGetStatus(vubvar) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(vubvar) == SCIP_VARSTATUS_COLUMN);
10639 assert(vubcoef != 0.0);
10640
10641 minvub = -SCIPsetInfinity(set);
10642 maxvub = SCIPsetInfinity(set);
10643
10644 xlb = SCIPvarGetLbGlobal(var);
10645 xub = SCIPvarGetUbGlobal(var);
10646 zlb = SCIPvarGetLbGlobal(vubvar);
10647 zub = SCIPvarGetUbGlobal(vubvar);
10648
10649 /* improve global bounds of vub variable, and calculate minimal and maximal value of variable bound */
10650 if( vubcoef >= 0.0 )
10651 {
10652 SCIP_Real newzlb;
10653
10654 if( !SCIPsetIsInfinity(set, -xlb) )
10655 {
10656 /* x <= b*z + d -> z >= (x-d)/b */
10657 newzlb = (xlb - vubconstant)/vubcoef;
10658 if( SCIPsetIsFeasGT(set, newzlb, zub) )
10659 {
10660 *infeasible = TRUE;
10661 return SCIP_OKAY;
10662 }
10663 if( SCIPsetIsFeasGT(set, newzlb, zlb) )
10664 {
10665 /* bound might be adjusted due to integrality condition */
10666 newzlb = adjustedLb(set, SCIPvarGetType(vubvar), newzlb);
10667
10668 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10669 * with the local bound, in this case we need to store the bound change as pending bound change
10670 */
10671 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10672 {
10673 assert(tree != NULL);
10674 assert(transprob != NULL);
10675 assert(SCIPprobIsTransformed(transprob));
10676
10677 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10678 tree, reopt, lp, branchcand, eventqueue, cliquetable, vubvar, newzlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10679 }
10680 else
10681 {
10682 SCIP_CALL( SCIPvarChgLbGlobal(vubvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzlb) );
10683 }
10684 zlb = newzlb;
10685
10686 if( nbdchgs != NULL )
10687 (*nbdchgs)++;
10688 }
10689 minvub = vubcoef * zlb + vubconstant;
10690 if( !SCIPsetIsInfinity(set, zub) )
10691 maxvub = vubcoef * zub + vubconstant;
10692 }
10693 else
10694 {
10695 if( !SCIPsetIsInfinity(set, zub) )
10696 maxvub = vubcoef * zub + vubconstant;
10697 if( !SCIPsetIsInfinity(set, -zlb) )
10698 minvub = vubcoef * zlb + vubconstant;
10699 }
10700 }
10701 else
10702 {
10703 SCIP_Real newzub;
10704
10705 if( !SCIPsetIsInfinity(set, -xlb) )
10706 {
10707 /* x <= b*z + d -> z <= (x-d)/b */
10708 newzub = (xlb - vubconstant)/vubcoef;
10709 if( SCIPsetIsFeasLT(set, newzub, zlb) )
10710 {
10711 *infeasible = TRUE;
10712 return SCIP_OKAY;
10713 }
10714 if( SCIPsetIsFeasLT(set, newzub, zub) )
10715 {
10716 /* bound might be adjusted due to integrality condition */
10717 newzub = adjustedUb(set, SCIPvarGetType(vubvar), newzub);
10718
10719 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10720 * with the local bound, in this case we need to store the bound change as pending bound change
10721 */
10722 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10723 {
10724 assert(tree != NULL);
10725 assert(transprob != NULL);
10726 assert(SCIPprobIsTransformed(transprob));
10727
10728 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10729 tree, reopt, lp, branchcand, eventqueue, cliquetable, vubvar, newzub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10730 }
10731 else
10732 {
10733 SCIP_CALL( SCIPvarChgUbGlobal(vubvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzub) );
10734 }
10735 zub = newzub;
10736
10737 if( nbdchgs != NULL )
10738 (*nbdchgs)++;
10739 }
10740 minvub = vubcoef * zub + vubconstant;
10741 if( !SCIPsetIsInfinity(set, -zlb) )
10742 maxvub = vubcoef * zlb + vubconstant;
10743 }
10744 else
10745 {
10746 if( !SCIPsetIsInfinity(set, zub) )
10747 minvub = vubcoef * zub + vubconstant;
10748 if( !SCIPsetIsInfinity(set, -zlb) )
10749 maxvub = vubcoef * zlb + vubconstant;
10750 }
10751 }
10752 if( minvub > maxvub )
10753 minvub = maxvub;
10754
10755 /* adjust bounds due to integrality of vub variable */
10756 minvub = adjustedUb(set, SCIPvarGetType(var), minvub);
10757 maxvub = adjustedUb(set, SCIPvarGetType(var), maxvub);
10758
10759 /* check bounds for feasibility */
10760 if( SCIPsetIsFeasLT(set, maxvub, xlb) || (var == vubvar && SCIPsetIsEQ(set, vubcoef, 1.0) && SCIPsetIsFeasNegative(set, vubconstant)) )
10761 {
10762 *infeasible = TRUE;
10763 return SCIP_OKAY;
10764 }
10765
10766 /* improve global upper bound of variable */
10767 if( SCIPsetIsFeasLT(set, maxvub, xub) )
10768 {
10769 /* bound might be adjusted due to integrality condition */
10770 maxvub = adjustedUb(set, SCIPvarGetType(var), maxvub);
10771
10772 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10773 * with the local bound, in this case we need to store the bound change as pending bound change
10774 */
10775 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10776 {
10777 assert(tree != NULL);
10778 assert(transprob != NULL);
10779 assert(SCIPprobIsTransformed(transprob));
10780
10781 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10782 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, maxvub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10783 }
10784 else
10785 {
10786 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, maxvub) );
10787 }
10788 xub = maxvub;
10789
10790 if( nbdchgs != NULL )
10791 (*nbdchgs)++;
10792 }
10793 maxvub = xub;
10794
10795 /* improve variable bound for binary z by moving the variable's global bound to the vub constant */
10796 if( SCIPvarIsBinary(vubvar) )
10797 {
10798 /* b > 0: x <= (maxvub - minvub) * z + minvub
10799 * b < 0: x <= (minvub - maxvub) * z + maxvub
10800 */
10801
10802 assert(!SCIPsetIsInfinity(set, maxvub) && !SCIPsetIsInfinity(set, -minvub));
10803
10804 if( vubcoef >= 0.0 )
10805 {
10806 vubcoef = maxvub - minvub;
10807 vubconstant = minvub;
10808 }
10809 else
10810 {
10811 vubcoef = minvub - maxvub;
10812 vubconstant = maxvub;
10813 }
10814 }
10815
10816 /* add variable bound to the variable bounds list */
10817 if( SCIPsetIsFeasLT(set, minvub, xub) )
10818 {
10819 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED);
10820 assert(!SCIPsetIsZero(set, vubcoef));
10821
10822 /* if one of the variables is binary, add the corresponding implication to the variable's implication
10823 * list, thereby also adding the variable bound (or implication) to the other variable
10824 */
10825 if( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY )
10826 {
10827 /* add corresponding implication:
10828 * b > 0, x <= b*z + d <-> z == 0 -> x <= d
10829 * b < 0, x <= b*z + d <-> z == 1 -> x <= b+d
10830 */
10831 SCIP_CALL( varAddTransitiveImplic(vubvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10832 cliquetable, branchcand, eventqueue, (vubcoef < 0.0), var, SCIP_BOUNDTYPE_UPPER, minvub, transitive,
10833 infeasible, nbdchgs) );
10834 }
10835 else if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
10836 {
10837 /* add corresponding implication:
10838 * b > 0, x <= b*z + d <-> x == 1 -> z >= (1-d)/b
10839 * b < 0, x <= b*z + d <-> x == 1 -> z <= (1-d)/b
10840 */
10841 SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10842 cliquetable, branchcand, eventqueue, TRUE, vubvar, (vubcoef >= 0.0 ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER),
10843 (1.0-vubconstant)/vubcoef, transitive, infeasible, nbdchgs) );
10844 }
10845 else
10846 {
10847 SCIP_CALL( varAddVbound(var, blkmem, set, eventqueue, SCIP_BOUNDTYPE_UPPER, vubvar, vubcoef, vubconstant) );
10848 }
10849 }
10850 }
10851 break;
10852
10853 case SCIP_VARSTATUS_AGGREGATED:
10854 /* x = a*y + c: x <= b*z + d <=> a*y + c <= b*z + d <=> y <= b/a * z + (d-c)/a, if a > 0
10855 * y >= b/a * z + (d-c)/a, if a < 0
10856 */
10857 assert(var->data.aggregate.var != NULL);
10858 if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
10859 {
10860 /* a > 0 -> add variable upper bound */
10861 SCIP_CALL( SCIPvarAddVub(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10862 cliquetable, branchcand, eventqueue, vubvar, vubcoef/var->data.aggregate.scalar,
10863 (vubconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10864 }
10865 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
10866 {
10867 /* a < 0 -> add variable lower bound */
10868 SCIP_CALL( SCIPvarAddVlb(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10869 cliquetable, branchcand, eventqueue, vubvar, vubcoef/var->data.aggregate.scalar,
10870 (vubconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10871 }
10872 else
10873 {
10874 SCIPerrorMessage("scalar is zero in aggregation\n");
10875 return SCIP_INVALIDDATA;
10876 }
10877 break;
10878
10879 case SCIP_VARSTATUS_MULTAGGR:
10880 /* nothing to do here */
10881 break;
10882
10883 case SCIP_VARSTATUS_NEGATED:
10884 /* x = offset - x': x <= b*z + d <=> offset - x' <= b*z + d <=> x' >= -b*z + (offset-d) */
10885 assert(var->negatedvar != NULL);
10886 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
10887 assert(var->negatedvar->negatedvar == var);
10888 SCIP_CALL( SCIPvarAddVlb(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10889 branchcand, eventqueue, vubvar, -vubcoef, var->data.negate.constant - vubconstant, transitive, infeasible,
10890 nbdchgs) );
10891 break;
10892
10893 default:
10894 SCIPerrorMessage("unknown variable status\n");
10895 return SCIP_INVALIDDATA;
10896 }
10897
10898 return SCIP_OKAY;
10899 }
10900
10901 /** informs binary variable x about a globally valid implication: x == 0 or x == 1 ==> y <= b or y >= b;
10902 * also adds the corresponding implication or variable bound to the implied variable;
10903 * if the implication is conflicting, the variable is fixed to the opposite value;
10904 * if the variable is already fixed to the given value, the implication is performed immediately;
10905 * if the implication is redundant with respect to the variables' global bounds, it is ignored
10906 */
10907 SCIP_RETCODE SCIPvarAddImplic(
10908 SCIP_VAR* var, /**< problem variable */
10909 BMS_BLKMEM* blkmem, /**< block memory */
10910 SCIP_SET* set, /**< global SCIP settings */
10911 SCIP_STAT* stat, /**< problem statistics */
10912 SCIP_PROB* transprob, /**< transformed problem */
10913 SCIP_PROB* origprob, /**< original problem */
10914 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
10915 SCIP_REOPT* reopt, /**< reoptimization data structure */
10916 SCIP_LP* lp, /**< current LP data */
10917 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
10918 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
10919 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
10920 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
10921 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
10922 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
10923 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
10924 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
10925 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
10926 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
10927 )
10928 {
10929 assert(var != NULL);
10930 assert(set != NULL);
10931 assert(var->scip == set->scip);
10932 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
10933 assert(infeasible != NULL);
10934
10935 *infeasible = FALSE;
10936 if( nbdchgs != NULL )
10937 *nbdchgs = 0;
10938
10939 switch( SCIPvarGetStatus(var) )
10940 {
10941 case SCIP_VARSTATUS_ORIGINAL:
10942 assert(var->data.original.transvar != NULL);
10943 SCIP_CALL( SCIPvarAddImplic(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10944 cliquetable, branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible,
10945 nbdchgs) );
10946 break;
10947
10948 case SCIP_VARSTATUS_COLUMN:
10949 case SCIP_VARSTATUS_LOOSE:
10950 /* if the variable is fixed (although it has no FIXED status), and varfixing corresponds to the fixed value of
10951 * the variable, the implication can be applied directly;
10952 * otherwise, add implication to the implications list (and add inverse of implication to the implied variable)
10953 */
10954 if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
10955 {
10956 if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
10957 {
10958 SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
10959 cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) );
10960 }
10961 }
10962 else
10963 {
10964 SCIP_CALL( SCIPvarGetProbvarBound(&implvar, &implbound, &impltype) );
10965 SCIPvarAdjustBd(implvar, set, impltype, &implbound);
10966 if( SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED )
10967 {
10968 SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10969 branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible, nbdchgs) );
10970 }
10971 }
10972 break;
10973
10974 case SCIP_VARSTATUS_FIXED:
10975 /* if varfixing corresponds to the fixed value of the variable, the implication can be applied directly */
10976 if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
10977 {
10978 SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
10979 cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) );
10980 }
10981 break;
10982
10983 case SCIP_VARSTATUS_AGGREGATED:
10984 /* implication added for x == 1:
10985 * x == 1 && x = 1*z + 0 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b
10986 * x == 1 && x = -1*z + 1 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b
10987 * implication added for x == 0:
10988 * x == 0 && x = 1*z + 0 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b
10989 * x == 0 && x = -1*z + 1 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b
10990 *
10991 * use only binary variables z
10992 */
10993 assert(var->data.aggregate.var != NULL);
10994 if( SCIPvarIsBinary(var->data.aggregate.var) )
10995 {
10996 assert( (SCIPsetIsEQ(set, var->data.aggregate.scalar, 1.0) && SCIPsetIsZero(set, var->data.aggregate.constant))
10997 || (SCIPsetIsEQ(set, var->data.aggregate.scalar, -1.0) && SCIPsetIsEQ(set, var->data.aggregate.constant, 1.0)) );
10998
10999 if( var->data.aggregate.scalar > 0 )
11000 {
11001 SCIP_CALL( SCIPvarAddImplic(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
11002 cliquetable, branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible,
11003 nbdchgs) );
11004 }
11005 else
11006 {
11007 SCIP_CALL( SCIPvarAddImplic(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
11008 cliquetable, branchcand, eventqueue, !varfixing, implvar, impltype, implbound, transitive, infeasible,
11009 nbdchgs) );
11010 }
11011 }
11012 break;
11013
11014 case SCIP_VARSTATUS_MULTAGGR:
11015 /* nothing to do here */
11016 break;
11017
11018 case SCIP_VARSTATUS_NEGATED:
11019 /* implication added for x == 1:
11020 * x == 1 && x = -1*z + 1 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b
11021 * implication added for x == 0:
11022 * x == 0 && x = -1*z + 1 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b
11023 */
11024 assert(var->negatedvar != NULL);
11025 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
11026 assert(var->negatedvar->negatedvar == var);
11027 assert(SCIPvarIsBinary(var->negatedvar));
11028
11029 if( SCIPvarGetType(var->negatedvar) == SCIP_VARTYPE_BINARY )
11030 {
11031 SCIP_CALL( SCIPvarAddImplic(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
11032 cliquetable, branchcand, eventqueue, !varfixing, implvar, impltype, implbound, transitive, infeasible, nbdchgs) );
11033 }
11034 /* in case one both variables are not of binary type we have to add the implication as variable bounds */
11035 else
11036 {
11037 /* if the implied variable is of binary type exchange the variables */
11038 if( SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY )
11039 {
11040 SCIP_CALL( SCIPvarAddImplic(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
11041 branchcand, eventqueue, (impltype == SCIP_BOUNDTYPE_UPPER) ? TRUE : FALSE, var->negatedvar,
11042 varfixing ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER, varfixing ? 1.0 : 0.0, transitive,
11043 infeasible, nbdchgs) );
11044 }
11045 else
11046 {
11047 /* both variables are not of binary type but are implicit binary; in that case we can only add this
11048 * implication as variable bounds
11049 */
11050
11051 /* add variable lower bound on the negation of var */
11052 if( varfixing )
11053 {
11054 /* (x = 1 => i) z = 0 ii) z = 1) <=> ( i) z = 1 ii) z = 0 => ~x = 1), this is done by adding ~x >= b*z + d
11055 * as variable lower bound
11056 */
11057 SCIP_CALL( SCIPvarAddVlb(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
11058 cliquetable, branchcand, eventqueue, implvar, (impltype == SCIP_BOUNDTYPE_UPPER) ? 1.0 : -1.0,
11059 (impltype == SCIP_BOUNDTYPE_UPPER) ? 0.0 : 1.0, transitive, infeasible, nbdchgs) );
11060 }
11061 else
11062 {
11063 /* (x = 0 => i) z = 0 ii) z = 1) <=> ( i) z = 1 ii) z = 0 => ~x = 0), this is done by adding ~x <= b*z + d
11064 * as variable upper bound
11065 */
11066 SCIP_CALL( SCIPvarAddVub(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
11067 cliquetable, branchcand, eventqueue, implvar, (impltype == SCIP_BOUNDTYPE_UPPER) ? -1.0 : 1.0,
11068 (impltype == SCIP_BOUNDTYPE_UPPER) ? 1.0 : 0.0, transitive, infeasible, nbdchgs) );
11069 }
11070
11071 /* add variable bound on implvar */
11072 if( impltype == SCIP_BOUNDTYPE_UPPER )
11073 {
11074 /* (z = 1 => i) x = 0 ii) x = 1) <=> ( i) ~x = 0 ii) ~x = 1 => z = 0), this is done by adding z <= b*~x + d
11075 * as variable upper bound
11076 */
11077 SCIP_CALL( SCIPvarAddVub(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
11078 branchcand, eventqueue, var->negatedvar, (varfixing) ? 1.0 : -1.0,
11079 (varfixing) ? 0.0 : 1.0, transitive, infeasible, nbdchgs) );
11080 }
11081 else
11082 {
11083 /* (z = 0 => i) x = 0 ii) x = 1) <=> ( i) ~x = 0 ii) ~x = 1 => z = 1), this is done by adding z >= b*~x + d
11084 * as variable upper bound
11085 */
11086 SCIP_CALL( SCIPvarAddVlb(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
11087 branchcand, eventqueue, var->negatedvar, (varfixing) ? -1.0 : 1.0, (varfixing) ? 1.0 : 0.0,
11088 transitive, infeasible, nbdchgs) );
11089 }
11090 }
11091 }
11092 break;
11093
11094 default:
11095 SCIPerrorMessage("unknown variable status\n");
11096 return SCIP_INVALIDDATA;
11097 }
11098
11099 return SCIP_OKAY;
11100 }
11101
11102 /** returns whether there is an implication x == varfixing -> y <= b or y >= b in the implication graph;
11103 * implications that are represented as cliques in the clique table are not regarded (use SCIPvarsHaveCommonClique());
11104 * both variables must be active, variable x must be binary
11105 */
11106 SCIP_Bool SCIPvarHasImplic(
11107 SCIP_VAR* var, /**< problem variable x */
11108 SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
11109 SCIP_VAR* implvar, /**< variable y to search for */
11110 SCIP_BOUNDTYPE impltype /**< type of implication y <=/>= b to search for */
11111 )
11112 {
11113 assert(var != NULL);
11114 assert(implvar != NULL);
11115 assert(SCIPvarIsActive(var));
11116 assert(SCIPvarIsActive(implvar));
11117 assert(SCIPvarIsBinary(var));
11118
11119 return var->implics != NULL && SCIPimplicsContainsImpl(var->implics, varfixing, implvar, impltype);
11120 }
11121
11122 /** returns whether there is an implication x == varfixing -> y == implvarfixing in the implication graph;
11123 * implications that are represented as cliques in the clique table are not regarded (use SCIPvarsHaveCommonClique());
11124 * both variables must be active binary variables
11125 */
11126 SCIP_Bool SCIPvarHasBinaryImplic(
11127 SCIP_VAR* var, /**< problem variable x */
11128 SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
11129 SCIP_VAR* implvar, /**< variable y to search for */
11130 SCIP_Bool implvarfixing /**< value of the implied variable to search for */
11131 )
11132 {
11133 assert(SCIPvarIsBinary(implvar));
11134
11135 return SCIPvarHasImplic(var, varfixing, implvar, implvarfixing ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER);
11136 }
11137
11138 /** gets the values of b in implications x == varfixing -> y <= b or y >= b in the implication graph;
11139 * the values are set to SCIP_INVALID if there is no implied bound
11140 */
11141 void SCIPvarGetImplicVarBounds(
11142 SCIP_VAR* var, /**< problem variable x */
11143 SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
11144 SCIP_VAR* implvar, /**< variable y to search for */
11145 SCIP_Real* lb, /**< buffer to store the value of the implied lower bound */
11146 SCIP_Real* ub /**< buffer to store the value of the implied upper bound */
11147 )
11148 {
11149 int lowerpos;
11150 int upperpos;
11151 SCIP_Real* bounds;
11152
11153 assert(lb != NULL);
11154 assert(ub != NULL);
11155
11156 *lb = SCIP_INVALID;
11157 *ub = SCIP_INVALID;
11158
11159 if( var->implics == NULL )
11160 return;
11161
11162 SCIPimplicsGetVarImplicPoss(var->implics, varfixing, implvar, &lowerpos, &upperpos);
11163 bounds = SCIPvarGetImplBounds(var, varfixing);
11164
11165 if( bounds == NULL )
11166 return;
11167
11168 if( lowerpos >= 0 )
11169 *lb = bounds[lowerpos];
11170
11171 if( upperpos >= 0 )
11172 *ub = bounds[upperpos];
11173 }
11174
11175
11176 /** fixes the bounds of a binary variable to the given value, counting bound changes and detecting infeasibility */
11177 SCIP_RETCODE SCIPvarFixBinary(
11178 SCIP_VAR* var, /**< problem variable */
11179 BMS_BLKMEM* blkmem, /**< block memory */
11180 SCIP_SET* set, /**< global SCIP settings */
11181 SCIP_STAT* stat, /**< problem statistics */
11182 SCIP_PROB* transprob, /**< transformed problem */
11183 SCIP_PROB* origprob, /**< original problem */
11184 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
11185 SCIP_REOPT* reopt, /**< reoptimization data structure */
11186 SCIP_LP* lp, /**< current LP data */
11187 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
11188 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
11189 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
11190 SCIP_Bool value, /**< value to fix variable to */
11191 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
11192 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
11193 )
11194 {
11195 assert(var != NULL);
11196 assert(set != NULL);
11197 assert(var->scip == set->scip);
11198 assert(infeasible != NULL);
11199
11200 *infeasible = FALSE;
11201
11202 if( value == FALSE )
11203 {
11204 if( var->glbdom.lb > 0.5 )
11205 *infeasible = TRUE;
11206 else if( var->glbdom.ub > 0.5 )
11207 {
11208 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
11209 * with the local bound, in this case we need to store the bound change as pending bound change
11210 */
11211 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
11212 {
11213 assert(tree != NULL);
11214 assert(transprob != NULL);
11215 assert(SCIPprobIsTransformed(transprob));
11216
11217 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
11218 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) );
11219 }
11220 else
11221 {
11222 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 0.0) );
11223 }
11224
11225 if( nbdchgs != NULL )
11226 (*nbdchgs)++;
11227 }
11228 }
11229 else
11230 {
11231 if( var->glbdom.ub < 0.5 )
11232 *infeasible = TRUE;
11233 else if( var->glbdom.lb < 0.5 )
11234 {
11235 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
11236 * with the local bound, in this case we need to store the bound change as pending bound change
11237 */
11238 if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
11239 {
11240 assert(tree != NULL);
11241 assert(transprob != NULL);
11242 assert(SCIPprobIsTransformed(transprob));
11243
11244 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
11245 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 1.0, SCIP_BOUNDTYPE_LOWER, FALSE) );
11246 }
11247 else
11248 {
11249 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 1.0) );
11250 }
11251
11252 if( nbdchgs != NULL )
11253 (*nbdchgs)++;
11254 }
11255 }
11256
11257 /* during presolving, the variable should have been removed immediately from all its cliques */
11258 assert(SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING || var->cliquelist == NULL);
11259
11260 return SCIP_OKAY;
11261 }
11262
11263 /** adds the variable to the given clique and updates the list of cliques the binary variable is member of;
11264 * if the variable now appears twice in the clique with the same value, it is fixed to the opposite value;
11265 * if the variable now appears twice in the clique with opposite values, all other variables are fixed to
11266 * the opposite of the value they take in the clique
11267 */
11268 SCIP_RETCODE SCIPvarAddClique(
11269 SCIP_VAR* var, /**< problem variable */
11270 BMS_BLKMEM* blkmem, /**< block memory */
11271 SCIP_SET* set, /**< global SCIP settings */
11272 SCIP_STAT* stat, /**< problem statistics */
11273 SCIP_PROB* transprob, /**< transformed problem */
11274 SCIP_PROB* origprob, /**< original problem */
11275 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
11276 SCIP_REOPT* reopt, /**< reoptimization data structure */
11277 SCIP_LP* lp, /**< current LP data */
11278 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
11279 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
11280 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
11281 SCIP_Bool value, /**< value of the variable in the clique */
11282 SCIP_CLIQUE* clique, /**< clique the variable should be added to */
11283 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
11284 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
11285 )
11286 {
11287 assert(var != NULL);
11288 assert(set != NULL);
11289 assert(var->scip == set->scip);
11290 assert(SCIPvarIsBinary(var));
11291 assert(infeasible != NULL);
11292
11293 *infeasible = FALSE;
11294
11295 /* get corresponding active problem variable */
11296 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
11297 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
11298 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
11299 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED
11300 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
11301 assert(SCIPvarIsBinary(var));
11302
11303 /* only column and loose variables may be member of a clique */
11304 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
11305 {
11306 SCIP_Bool doubleentry;
11307 SCIP_Bool oppositeentry;
11308
11309 /* add variable to clique */
11310 SCIP_CALL( SCIPcliqueAddVar(clique, blkmem, set, var, value, &doubleentry, &oppositeentry) );
11311
11312 /* add clique to variable's clique list */
11313 SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, value, clique) );
11314
11315 /* check consistency of cliquelist */
11316 SCIPcliquelistCheck(var->cliquelist, var);
11317
11318 /* if the variable now appears twice with the same value in the clique, it can be fixed to the opposite value */
11319 if( doubleentry )
11320 {
11321 SCIP_CALL( SCIPvarFixBinary(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
11322 eventqueue, cliquetable, !value, infeasible, nbdchgs) );
11323 }
11324
11325 /* if the variable appears with both values in the clique, all other variables of the clique can be fixed
11326 * to the opposite of the value they take in the clique
11327 */
11328 if( oppositeentry )
11329 {
11330 SCIP_VAR** vars;
11331 SCIP_Bool* values;
11332 int nvars;
11333 int i;
11334
11335 nvars = SCIPcliqueGetNVars(clique);
11336 vars = SCIPcliqueGetVars(clique);
11337 values = SCIPcliqueGetValues(clique);
11338 for( i = 0; i < nvars && !(*infeasible); ++i )
11339 {
11340 if( vars[i] == var )
11341 continue;
11342
11343 SCIP_CALL( SCIPvarFixBinary(vars[i], blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
11344 eventqueue, cliquetable, !values[i], infeasible, nbdchgs) );
11345 }
11346 }
11347 }
11348
11349 return SCIP_OKAY;
11350 }
11351
11352 /** adds a filled clique to the cliquelists of all corresponding variables */
11353 SCIP_RETCODE SCIPvarsAddClique(
11354 SCIP_VAR** vars, /**< problem variables */
11355 SCIP_Bool* values, /**< values of the variables in the clique */
11356 int nvars, /**< number of problem variables */
11357 BMS_BLKMEM* blkmem, /**< block memory */
11358 SCIP_SET* set, /**< global SCIP settings */
11359 SCIP_CLIQUE* clique /**< clique that contains all given variables and values */
11360 )
11361 {
11362 SCIP_VAR* var;
11363 int v;
11364
11365 assert(vars != NULL);
11366 assert(values != NULL);
11367 assert(nvars > 0);
11368 assert(set != NULL);
11369 assert(blkmem != NULL);
11370 assert(clique != NULL);
11371
11372 for( v = nvars - 1; v >= 0; --v )
11373 {
11374 var = vars[v];
11375 assert(SCIPvarIsBinary(var));
11376 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
11377
11378 /* add clique to variable's clique list */
11379 SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, values[v], clique) );
11380
11381 /* check consistency of cliquelist */
11382 SCIPcliquelistCheck(var->cliquelist, var);
11383 }
11384
11385 return SCIP_OKAY;
11386 }
11387
11388 /** adds a clique to the list of cliques of the given binary variable, but does not change the clique
11389 * itself
11390 */
11391 SCIP_RETCODE SCIPvarAddCliqueToList(
11392 SCIP_VAR* var, /**< problem variable */
11393 BMS_BLKMEM* blkmem, /**< block memory */
11394 SCIP_SET* set, /**< global SCIP settings */
11395 SCIP_Bool value, /**< value of the variable in the clique */
11396 SCIP_CLIQUE* clique /**< clique that should be removed from the variable's clique list */
11397 )
11398 {
11399 assert(var != NULL);
11400 assert(SCIPvarIsBinary(var));
11401 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
11402
11403 /* add clique to variable's clique list */
11404 SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, value, clique) );
11405
11406 return SCIP_OKAY;
11407 }
11408
11409
11410 /** deletes a clique from the list of cliques the binary variable is member of, but does not change the clique
11411 * itself
11412 */
11413 SCIP_RETCODE SCIPvarDelCliqueFromList(
11414 SCIP_VAR* var, /**< problem variable */
11415 BMS_BLKMEM* blkmem, /**< block memory */
11416 SCIP_Bool value, /**< value of the variable in the clique */
11417 SCIP_CLIQUE* clique /**< clique that should be removed from the variable's clique list */
11418 )
11419 {
11420 assert(var != NULL);
11421 assert(SCIPvarIsBinary(var));
11422
11423 /* delete clique from variable's clique list */
11424 SCIP_CALL( SCIPcliquelistDel(&var->cliquelist, blkmem, value, clique) );
11425
11426 return SCIP_OKAY;
11427 }
11428
11429 /** deletes the variable from the given clique and updates the list of cliques the binary variable is member of */
11430 SCIP_RETCODE SCIPvarDelClique(
11431 SCIP_VAR* var, /**< problem variable */
11432 BMS_BLKMEM* blkmem, /**< block memory */
11433 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
11434 SCIP_Bool value, /**< value of the variable in the clique */
11435 SCIP_CLIQUE* clique /**< clique the variable should be removed from */
11436 )
11437 {
11438 assert(var != NULL);
11439 assert(SCIPvarIsBinary(var));
11440
11441 /* get corresponding active problem variable */
11442 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
11443 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
11444 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
11445 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED
11446 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
11447 assert(SCIPvarIsBinary(var));
11448
11449 /* only column and loose variables may be member of a clique */
11450 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
11451 {
11452 /* delete clique from variable's clique list */
11453 SCIP_CALL( SCIPcliquelistDel(&var->cliquelist, blkmem, value, clique) );
11454
11455 /* delete variable from clique */
11456 SCIPcliqueDelVar(clique, cliquetable, var, value);
11457
11458 /* check consistency of cliquelist */
11459 SCIPcliquelistCheck(var->cliquelist, var);
11460 }
11461
11462 return SCIP_OKAY;
11463 }
11464
11465 /** returns whether there is a clique that contains both given variable/value pairs;
11466 * the variables must be active binary variables;
11467 * if regardimplics is FALSE, only the cliques in the clique table are looked at;
11468 * if regardimplics is TRUE, both the cliques and the implications of the implication graph are regarded
11469 *
11470 * @note a variable with it's negated variable are NOT! in a clique
11471 * @note a variable with itself are in a clique
11472 */
11473 SCIP_Bool SCIPvarsHaveCommonClique(
11474 SCIP_VAR* var1, /**< first variable */
11475 SCIP_Bool value1, /**< value of first variable */
11476 SCIP_VAR* var2, /**< second variable */
11477 SCIP_Bool value2, /**< value of second variable */
11478 SCIP_Bool regardimplics /**< should the implication graph also be searched for a clique? */
11479 )
11480 {
11481 assert(var1 != NULL);
11482 assert(var2 != NULL);
11483 assert(SCIPvarIsActive(var1));
11484 assert(SCIPvarIsActive(var2));
11485 assert(SCIPvarIsBinary(var1));
11486 assert(SCIPvarIsBinary(var2));
11487
11488 return (SCIPcliquelistsHaveCommonClique(var1->cliquelist, value1, var2->cliquelist, value2)
11489 || (regardimplics && SCIPvarHasImplic(var1, value1, var2, value2 ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER)));
11490 }
11491
11492 /** actually changes the branch factor of the variable and of all parent variables */
11493 static
11494 SCIP_RETCODE varProcessChgBranchFactor(
11495 SCIP_VAR* var, /**< problem variable */
11496 SCIP_SET* set, /**< global SCIP settings */
11497 SCIP_Real branchfactor /**< factor to weigh variable's branching score with */
11498 )
11499 {
11500 SCIP_VAR* parentvar;
11501 SCIP_Real eps;
11502 int i;
11503
11504 assert(var != NULL);
11505 assert(set != NULL);
11506 assert(var->scip == set->scip);
11507
11508 /* only use positive values */
11509 eps = SCIPsetEpsilon(set);
11510 branchfactor = MAX(branchfactor, eps);
11511
11512 SCIPsetDebugMsg(set, "process changing branch factor of <%s> from %f to %f\n", var->name, var->branchfactor, branchfactor);
11513
11514 if( SCIPsetIsEQ(set, branchfactor, var->branchfactor) )
11515 return SCIP_OKAY;
11516
11517 /* change the branch factor */
11518 var->branchfactor = branchfactor;
11519
11520 /* process parent variables */
11521 for( i = 0; i < var->nparentvars; ++i )
11522 {
11523 parentvar = var->parentvars[i];
11524 assert(parentvar != NULL);
11525
11526 switch( SCIPvarGetStatus(parentvar) )
11527 {
11528 case SCIP_VARSTATUS_ORIGINAL:
11529 /* do not change priorities across the border between transformed and original problem */
11530 break;
11531
11532 case SCIP_VARSTATUS_COLUMN:
11533 case SCIP_VARSTATUS_LOOSE:
11534 case SCIP_VARSTATUS_FIXED:
11535 case SCIP_VARSTATUS_MULTAGGR:
11536 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
11537 SCIPABORT();
11538 return SCIP_INVALIDDATA; /*lint !e527*/
11539
11540 case SCIP_VARSTATUS_AGGREGATED:
11541 case SCIP_VARSTATUS_NEGATED:
11542 SCIP_CALL( varProcessChgBranchFactor(parentvar, set, branchfactor) );
11543 break;
11544
11545 default:
11546 SCIPerrorMessage("unknown variable status\n");
11547 SCIPABORT();
11548 return SCIP_ERROR; /*lint !e527*/
11549 }
11550 }
11551
11552 return SCIP_OKAY;
11553 }
11554
11555 /** sets the branch factor of the variable; this value can be used in the branching methods to scale the score
11556 * values of the variables; higher factor leads to a higher probability that this variable is chosen for branching
11557 */
11558 SCIP_RETCODE SCIPvarChgBranchFactor(
11559 SCIP_VAR* var, /**< problem variable */
11560 SCIP_SET* set, /**< global SCIP settings */
11561 SCIP_Real branchfactor /**< factor to weigh variable's branching score with */
11562 )
11563 {
11564 int v;
11565
11566 assert(var != NULL);
11567 assert(set != NULL);
11568 assert(var->scip == set->scip);
11569 assert(branchfactor >= 0.0);
11570
11571 SCIPdebugMessage("changing branch factor of <%s> from %g to %g\n", var->name, var->branchfactor, branchfactor);
11572
11573 if( SCIPsetIsEQ(set, var->branchfactor, branchfactor) )
11574 return SCIP_OKAY;
11575
11576 /* change priorities of attached variables */
11577 switch( SCIPvarGetStatus(var) )
11578 {
11579 case SCIP_VARSTATUS_ORIGINAL:
11580 if( var->data.original.transvar != NULL )
11581 {
11582 SCIP_CALL( SCIPvarChgBranchFactor(var->data.original.transvar, set, branchfactor) );
11583 }
11584 else
11585 {
11586 assert(set->stage == SCIP_STAGE_PROBLEM);
11587 var->branchfactor = branchfactor;
11588 }
11589 break;
11590
11591 case SCIP_VARSTATUS_COLUMN:
11592 case SCIP_VARSTATUS_LOOSE:
11593 case SCIP_VARSTATUS_FIXED:
11594 SCIP_CALL( varProcessChgBranchFactor(var, set, branchfactor) );
11595 break;
11596
11597 case SCIP_VARSTATUS_AGGREGATED:
11598 assert(!var->donotaggr);
11599 assert(var->data.aggregate.var != NULL);
11600 SCIP_CALL( SCIPvarChgBranchFactor(var->data.aggregate.var, set, branchfactor) );
11601 break;
11602
11603 case SCIP_VARSTATUS_MULTAGGR:
11604 assert(!var->donotmultaggr);
11605 for( v = 0; v < var->data.multaggr.nvars; ++v )
11606 {
11607 SCIP_CALL( SCIPvarChgBranchFactor(var->data.multaggr.vars[v], set, branchfactor) );
11608 }
11609 break;
11610
11611 case SCIP_VARSTATUS_NEGATED:
11612 assert(var->negatedvar != NULL);
11613 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
11614 assert(var->negatedvar->negatedvar == var);
11615 SCIP_CALL( SCIPvarChgBranchFactor(var->negatedvar, set, branchfactor) );
11616 break;
11617
11618 default:
11619 SCIPerrorMessage("unknown variable status\n");
11620 SCIPABORT();
11621 return SCIP_ERROR; /*lint !e527*/
11622 }
11623
11624 return SCIP_OKAY;
11625 }
11626
11627 /** actually changes the branch priority of the variable and of all parent variables */
11628 static
11629 SCIP_RETCODE varProcessChgBranchPriority(
11630 SCIP_VAR* var, /**< problem variable */
11631 int branchpriority /**< branching priority of the variable */
11632 )
11633 {
11634 SCIP_VAR* parentvar;
11635 int i;
11636
11637 assert(var != NULL);
11638
11639 SCIPdebugMessage("process changing branch priority of <%s> from %d to %d\n",
11640 var->name, var->branchpriority, branchpriority);
11641
11642 if( branchpriority == var->branchpriority )
11643 return SCIP_OKAY;
11644
11645 /* change the branch priority */
11646 var->branchpriority = branchpriority;
11647
11648 /* process parent variables */
11649 for( i = 0; i < var->nparentvars; ++i )
11650 {
11651 parentvar = var->parentvars[i];
11652 assert(parentvar != NULL);
11653
11654 switch( SCIPvarGetStatus(parentvar) )
11655 {
11656 case SCIP_VARSTATUS_ORIGINAL:
11657 /* do not change priorities across the border between transformed and original problem */
11658 break;
11659
11660 case SCIP_VARSTATUS_COLUMN:
11661 case SCIP_VARSTATUS_LOOSE:
11662 case SCIP_VARSTATUS_FIXED:
11663 case SCIP_VARSTATUS_MULTAGGR:
11664 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
11665 SCIPABORT();
11666 return SCIP_INVALIDDATA; /*lint !e527*/
11667
11668 case SCIP_VARSTATUS_AGGREGATED:
11669 case SCIP_VARSTATUS_NEGATED:
11670 SCIP_CALL( varProcessChgBranchPriority(parentvar, branchpriority) );
11671 break;
11672
11673 default:
11674 SCIPerrorMessage("unknown variable status\n");
11675 return SCIP_ERROR;
11676 }
11677 }
11678
11679 return SCIP_OKAY;
11680 }
11681
11682 /** sets the branch priority of the variable; variables with higher branch priority are always preferred to variables
11683 * with lower priority in selection of branching variable
11684 */
11685 SCIP_RETCODE SCIPvarChgBranchPriority(
11686 SCIP_VAR* var, /**< problem variable */
11687 int branchpriority /**< branching priority of the variable */
11688 )
11689 {
11690 int v;
11691
11692 assert(var != NULL);
11693
11694 SCIPdebugMessage("changing branch priority of <%s> from %d to %d\n", var->name, var->branchpriority, branchpriority);
11695
11696 if( var->branchpriority == branchpriority )
11697 return SCIP_OKAY;
11698
11699 /* change priorities of attached variables */
11700 switch( SCIPvarGetStatus(var) )
11701 {
11702 case SCIP_VARSTATUS_ORIGINAL:
11703 if( var->data.original.transvar != NULL )
11704 {
11705 SCIP_CALL( SCIPvarChgBranchPriority(var->data.original.transvar, branchpriority) );
11706 }
11707 else
11708 var->branchpriority = branchpriority;
11709 break;
11710
11711 case SCIP_VARSTATUS_COLUMN:
11712 case SCIP_VARSTATUS_LOOSE:
11713 case SCIP_VARSTATUS_FIXED:
11714 SCIP_CALL( varProcessChgBranchPriority(var, branchpriority) );
11715 break;
11716
11717 case SCIP_VARSTATUS_AGGREGATED:
11718 assert(!var->donotaggr);
11719 assert(var->data.aggregate.var != NULL);
11720 SCIP_CALL( SCIPvarChgBranchPriority(var->data.aggregate.var, branchpriority) );
11721 break;
11722
11723 case SCIP_VARSTATUS_MULTAGGR:
11724 assert(!var->donotmultaggr);
11725 for( v = 0; v < var->data.multaggr.nvars; ++v )
11726 {
11727 SCIP_CALL( SCIPvarChgBranchPriority(var->data.multaggr.vars[v], branchpriority) );
11728 }
11729 break;
11730
11731 case SCIP_VARSTATUS_NEGATED:
11732 assert(var->negatedvar != NULL);
11733 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
11734 assert(var->negatedvar->negatedvar == var);
11735 SCIP_CALL( SCIPvarChgBranchPriority(var->negatedvar, branchpriority) );
11736 break;
11737
11738 default:
11739 SCIPerrorMessage("unknown variable status\n");
11740 SCIPABORT();
11741 return SCIP_ERROR; /*lint !e527*/
11742 }
11743
11744 return SCIP_OKAY;
11745 }
11746
11747 /** actually changes the branch direction of the variable and of all parent variables */
11748 static
11749 SCIP_RETCODE varProcessChgBranchDirection(
11750 SCIP_VAR* var, /**< problem variable */
11751 SCIP_BRANCHDIR branchdirection /**< preferred branch direction of the variable (downwards, upwards, auto) */
11752 )
11753 {
11754 SCIP_VAR* parentvar;
11755 int i;
11756
11757 assert(var != NULL);
11758
11759 SCIPdebugMessage("process changing branch direction of <%s> from %u to %d\n",
11760 var->name, var->branchdirection, branchdirection);
11761
11762 if( branchdirection == (SCIP_BRANCHDIR)var->branchdirection )
11763 return SCIP_OKAY;
11764
11765 /* change the branch direction */
11766 var->branchdirection = branchdirection; /*lint !e641*/
11767
11768 /* process parent variables */
11769 for( i = 0; i < var->nparentvars; ++i )
11770 {
11771 parentvar = var->parentvars[i];
11772 assert(parentvar != NULL);
11773
11774 switch( SCIPvarGetStatus(parentvar) )
11775 {
11776 case SCIP_VARSTATUS_ORIGINAL:
11777 /* do not change directions across the border between transformed and original problem */
11778 break;
11779
11780 case SCIP_VARSTATUS_COLUMN:
11781 case SCIP_VARSTATUS_LOOSE:
11782 case SCIP_VARSTATUS_FIXED:
11783 case SCIP_VARSTATUS_MULTAGGR:
11784 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
11785 SCIPABORT();
11786 return SCIP_INVALIDDATA; /*lint !e527*/
11787
11788 case SCIP_VARSTATUS_AGGREGATED:
11789 if( parentvar->data.aggregate.scalar > 0.0 )
11790 {
11791 SCIP_CALL( varProcessChgBranchDirection(parentvar, branchdirection) );
11792 }
11793 else
11794 {
11795 SCIP_CALL( varProcessChgBranchDirection(parentvar, SCIPbranchdirOpposite(branchdirection)) );
11796 }
11797 break;
11798
11799 case SCIP_VARSTATUS_NEGATED:
11800 SCIP_CALL( varProcessChgBranchDirection(parentvar, SCIPbranchdirOpposite(branchdirection)) );
11801 break;
11802
11803 default:
11804 SCIPerrorMessage("unknown variable status\n");
11805 SCIPABORT();
11806 return SCIP_ERROR; /*lint !e527*/
11807 }
11808 }
11809
11810 return SCIP_OKAY;
11811 }
11812
11813 /** sets the branch direction of the variable; variables with higher branch direction are always preferred to variables
11814 * with lower direction in selection of branching variable
11815 */
11816 SCIP_RETCODE SCIPvarChgBranchDirection(
11817 SCIP_VAR* var, /**< problem variable */
11818 SCIP_BRANCHDIR branchdirection /**< preferred branch direction of the variable (downwards, upwards, auto) */
11819 )
11820 {
11821 int v;
11822
11823 assert(var != NULL);
11824
11825 SCIPdebugMessage("changing branch direction of <%s> from %u to %d\n", var->name, var->branchdirection, branchdirection);
11826
11827 if( (SCIP_BRANCHDIR)var->branchdirection == branchdirection )
11828 return SCIP_OKAY;
11829
11830 /* change directions of attached variables */
11831 switch( SCIPvarGetStatus(var) )
11832 {
11833 case SCIP_VARSTATUS_ORIGINAL:
11834 if( var->data.original.transvar != NULL )
11835 {
11836 SCIP_CALL( SCIPvarChgBranchDirection(var->data.original.transvar, branchdirection) );
11837 }
11838 else
11839 var->branchdirection = branchdirection; /*lint !e641*/
11840 break;
11841
11842 case SCIP_VARSTATUS_COLUMN:
11843 case SCIP_VARSTATUS_LOOSE:
11844 case SCIP_VARSTATUS_FIXED:
11845 SCIP_CALL( varProcessChgBranchDirection(var, branchdirection) );
11846 break;
11847
11848 case SCIP_VARSTATUS_AGGREGATED:
11849 assert(!var->donotaggr);
11850 assert(var->data.aggregate.var != NULL);
11851 if( var->data.aggregate.scalar > 0.0 )
11852 {
11853 SCIP_CALL( SCIPvarChgBranchDirection(var->data.aggregate.var, branchdirection) );
11854 }
11855 else
11856 {
11857 SCIP_CALL( SCIPvarChgBranchDirection(var->data.aggregate.var, SCIPbranchdirOpposite(branchdirection)) );
11858 }
11859 break;
11860
11861 case SCIP_VARSTATUS_MULTAGGR:
11862 assert(!var->donotmultaggr);
11863 for( v = 0; v < var->data.multaggr.nvars; ++v )
11864 {
11865 /* only update branching direction of aggregation variables, if they don't have a preferred direction yet */
11866 assert(var->data.multaggr.vars[v] != NULL);
11867 if( (SCIP_BRANCHDIR)var->data.multaggr.vars[v]->branchdirection == SCIP_BRANCHDIR_AUTO )
11868 {
11869 if( var->data.multaggr.scalars[v] > 0.0 )
11870 {
11871 SCIP_CALL( SCIPvarChgBranchDirection(var->data.multaggr.vars[v], branchdirection) );
11872 }
11873 else
11874 {
11875 SCIP_CALL( SCIPvarChgBranchDirection(var->data.multaggr.vars[v], SCIPbranchdirOpposite(branchdirection)) );
11876 }
11877 }
11878 }
11879 break;
11880
11881 case SCIP_VARSTATUS_NEGATED:
11882 assert(var->negatedvar != NULL);
11883 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
11884 assert(var->negatedvar->negatedvar == var);
11885 SCIP_CALL( SCIPvarChgBranchDirection(var->negatedvar, SCIPbranchdirOpposite(branchdirection)) );
11886 break;
11887
11888 default:
11889 SCIPerrorMessage("unknown variable status\n");
11890 SCIPABORT();
11891 return SCIP_ERROR; /*lint !e527*/
11892 }
11893
11894 return SCIP_OKAY;
11895 }
11896
11897 /** compares the index of two variables, only active, fixed or negated variables are allowed, if a variable
11898 * is negated then the index of the corresponding active variable is taken, returns -1 if first is
11899 * smaller than, and +1 if first is greater than second variable index; returns 0 if both indices
11900 * are equal, which means both variables are equal
11901 */
11902 int SCIPvarCompareActiveAndNegated(
11903 SCIP_VAR* var1, /**< first problem variable */
11904 SCIP_VAR* var2 /**< second problem variable */
11905 )
11906 {
11907 assert(var1 != NULL);
11908 assert(var2 != NULL);
11909 assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_FIXED);
11910 assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_FIXED);
11911
11912 if( SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED )
11913 var1 = SCIPvarGetNegatedVar(var1);
11914 if( SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED )
11915 var2 = SCIPvarGetNegatedVar(var2);
11916
11917 assert(var1 != NULL);
11918 assert(var2 != NULL);
11919
11920 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
11921 return -1;
11922 else if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
11923 return +1;
11924
11925 assert(var1 == var2);
11926 return 0;
11927 }
11928
11929 /** comparison method for sorting active and negated variables by non-decreasing index, active and negated
11930 * variables are handled as the same variables
11931 */
11932 SCIP_DECL_SORTPTRCOMP(SCIPvarCompActiveAndNegated)
11933 {
11934 return SCIPvarCompareActiveAndNegated((SCIP_VAR*)elem1, (SCIP_VAR*)elem2);
11935 }
11936
11937 /** compares the index of two variables, returns -1 if first is smaller than, and +1 if first is greater than second
11938 * variable index; returns 0 if both indices are equal, which means both variables are equal
11939 */
11940 int SCIPvarCompare(
11941 SCIP_VAR* var1, /**< first problem variable */
11942 SCIP_VAR* var2 /**< second problem variable */
11943 )
11944 {
11945 assert(var1 != NULL);
11946 assert(var2 != NULL);
11947
11948 if( var1->index < var2->index )
11949 return -1;
11950 else if( var1->index > var2->index )
11951 return +1;
11952 else
11953 {
11954 assert(var1 == var2);
11955 return 0;
11956 }
11957 }
11958
11959 /** comparison method for sorting variables by non-decreasing index */
11960 SCIP_DECL_SORTPTRCOMP(SCIPvarComp)
11961 {
11962 return SCIPvarCompare((SCIP_VAR*)elem1, (SCIP_VAR*)elem2);
11963 }
11964
11965 /** comparison method for sorting variables by non-decreasing objective coefficient */
11966 SCIP_DECL_SORTPTRCOMP(SCIPvarCompObj)
11967 {
11968 SCIP_Real obj1;
11969 SCIP_Real obj2;
11970
11971 obj1 = SCIPvarGetObj((SCIP_VAR*)elem1);
11972 obj2 = SCIPvarGetObj((SCIP_VAR*)elem2);
11973
11974 if( obj1 < obj2 )
11975 return -1;
11976 else if( obj1 > obj2 )
11977 return +1;
11978 else
11979 return 0;
11980 }
11981
11982 /** hash key retrieval function for variables */
11983 SCIP_DECL_HASHGETKEY(SCIPvarGetHashkey)
11984 { /*lint --e{715}*/
11985 return elem;
11986 }
11987
11988 /** returns TRUE iff the indices of both variables are equal */
11989 SCIP_DECL_HASHKEYEQ(SCIPvarIsHashkeyEq)
11990 { /*lint --e{715}*/
11991 if( key1 == key2 )
11992 return TRUE;
11993 return FALSE;
11994 }
11995
11996 /** returns the hash value of the key */
11997 SCIP_DECL_HASHKEYVAL(SCIPvarGetHashkeyVal)
11998 { /*lint --e{715}*/
11999 assert( SCIPvarGetIndex((SCIP_VAR*) key) >= 0 );
12000 return (unsigned int) SCIPvarGetIndex((SCIP_VAR*) key);
12001 }
12002
12003 /** return for given variables all their active counterparts; all active variables will be pairwise different */
12004 SCIP_RETCODE SCIPvarsGetActiveVars(
12005 SCIP_SET* set, /**< global SCIP settings */
12006 SCIP_VAR** vars, /**< variable array with given variables and as output all active
12007 * variables, if enough slots exist
12008 */
12009 int* nvars, /**< number of given variables, and as output number of active variables,
12010 * if enough slots exist
12011 */
12012 int varssize, /**< available slots in vars array */
12013 int* requiredsize /**< pointer to store the required array size for the active variables */
12014 )
12015 {
12016 SCIP_VAR** activevars;
12017 int nactivevars;
12018 int activevarssize;
12019
12020 SCIP_VAR* var;
12021 int v;
12022
12023 SCIP_VAR** tmpvars;
12024 SCIP_VAR** multvars;
12025 int tmpvarssize;
12026 int ntmpvars;
12027 int noldtmpvars;
12028 int nmultvars;
12029
12030 assert(set != NULL);
12031 assert(nvars != NULL);
12032 assert(vars != NULL || *nvars == 0);
12033 assert(varssize >= *nvars);
12034 assert(requiredsize != NULL);
12035
12036 *requiredsize = 0;
12037
12038 if( *nvars == 0 )
12039 return SCIP_OKAY;
12040
12041 nactivevars = 0;
12042 activevarssize = *nvars;
12043 ntmpvars = *nvars;
12044 tmpvarssize = *nvars;
12045
12046 /* temporary memory */
12047 SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) );
12048 /* coverity[copy_paste_error] */
12049 SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpvars, vars, ntmpvars) );
12050
12051 noldtmpvars = ntmpvars;
12052
12053 /* sort all variables to combine equal variables easily */
12054 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
12055 for( v = ntmpvars - 1; v > 0; --v )
12056 {
12057 /* combine same variables */
12058 if( SCIPvarCompare(tmpvars[v], tmpvars[v - 1]) == 0 )
12059 {
12060 --ntmpvars;
12061 tmpvars[v] = tmpvars[ntmpvars];
12062 }
12063 }
12064 /* sort all variables again to combine equal variables later on */
12065 if( noldtmpvars > ntmpvars )
12066 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
12067
12068 /* collect for each variable the representation in active variables */
12069 while( ntmpvars >= 1 )
12070 {
12071 --ntmpvars;
12072 var = tmpvars[ntmpvars];
12073 assert( var != NULL );
12074
12075 switch( SCIPvarGetStatus(var) )
12076 {
12077 case SCIP_VARSTATUS_ORIGINAL:
12078 if( var->data.original.transvar == NULL )
12079 {
12080 SCIPerrorMessage("original variable has no transformed variable attached\n");
12081 SCIPABORT();
12082 return SCIP_INVALIDDATA; /*lint !e527*/
12083 }
12084 tmpvars[ntmpvars] = var->data.original.transvar;
12085 ++ntmpvars;
12086 break;
12087
12088 case SCIP_VARSTATUS_AGGREGATED:
12089 tmpvars[ntmpvars] = var->data.aggregate.var;
12090 ++ntmpvars;
12091 break;
12092
12093 case SCIP_VARSTATUS_NEGATED:
12094 tmpvars[ntmpvars] = var->negatedvar;
12095 ++ntmpvars;
12096 break;
12097
12098 case SCIP_VARSTATUS_LOOSE:
12099 case SCIP_VARSTATUS_COLUMN:
12100 /* check for space in temporary memory */
12101 if( nactivevars >= activevarssize )
12102 {
12103 activevarssize *= 2;
12104 SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) );
12105 assert(nactivevars < activevarssize);
12106 }
12107 activevars[nactivevars] = var;
12108 nactivevars++;
12109 break;
12110
12111 case SCIP_VARSTATUS_MULTAGGR:
12112 /* x = a_1*y_1 + ... + a_n*y_n + c */
12113 nmultvars = var->data.multaggr.nvars;
12114 multvars = var->data.multaggr.vars;
12115
12116 /* check for space in temporary memory */
12117 if( nmultvars + ntmpvars > tmpvarssize )
12118 {
12119 while( nmultvars + ntmpvars > tmpvarssize )
12120 tmpvarssize *= 2;
12121 SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) );
12122 assert(nmultvars + ntmpvars <= tmpvarssize);
12123 }
12124
12125 /* copy all multi-aggregation variables into our working array */
12126 BMScopyMemoryArray(&tmpvars[ntmpvars], multvars, nmultvars); /*lint !e866*/
12127
12128 /* get active, fixed or multi-aggregated corresponding variables for all new ones */
12129 SCIPvarsGetProbvar(&tmpvars[ntmpvars], nmultvars);
12130
12131 ntmpvars += nmultvars;
12132 noldtmpvars = ntmpvars;
12133
12134 /* sort all variables to combine equal variables easily */
12135 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
12136 for( v = ntmpvars - 1; v > 0; --v )
12137 {
12138 /* combine same variables */
12139 if( SCIPvarCompare(tmpvars[v], tmpvars[v - 1]) == 0 )
12140 {
12141 --ntmpvars;
12142 tmpvars[v] = tmpvars[ntmpvars];
12143 }
12144 }
12145 /* sort all variables again to combine equal variables later on */
12146 if( noldtmpvars > ntmpvars )
12147 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
12148
12149 break;
12150
12151 case SCIP_VARSTATUS_FIXED:
12152 /* no need for memorizing fixed variables */
12153 break;
12154
12155 default:
12156 SCIPerrorMessage("unknown variable status\n");
12157 SCIPABORT();
12158 return SCIP_INVALIDDATA; /*lint !e527*/
12159 }
12160 }
12161
12162 /* sort variable array by variable index */
12163 SCIPsortPtr((void**)activevars, SCIPvarComp, nactivevars);
12164
12165 /* eliminate duplicates and count required size */
12166 v = nactivevars - 1;
12167 while( v > 0 )
12168 {
12169 /* combine both variable since they are the same */
12170 if( SCIPvarCompare(activevars[v - 1], activevars[v]) == 0 )
12171 {
12172 --nactivevars;
12173 activevars[v] = activevars[nactivevars];
12174 }
12175 --v;
12176 }
12177 *requiredsize = nactivevars;
12178
12179 if( varssize >= *requiredsize )
12180 {
12181 assert(vars != NULL);
12182
12183 *nvars = *requiredsize;
12184 BMScopyMemoryArray(vars, activevars, nactivevars);
12185 }
12186
12187 SCIPsetFreeBufferArray(set, &tmpvars);
12188 SCIPsetFreeBufferArray(set, &activevars);
12189
12190 return SCIP_OKAY;
12191 }
12192
12193 /** gets corresponding active, fixed, or multi-aggregated problem variables of given variables,
12194 * @note the content of the given array will/might change
12195 */
12196 void SCIPvarsGetProbvar(
12197 SCIP_VAR** vars, /**< array of problem variables */
12198 int nvars /**< number of variables */
12199 )
12200 {
12201 int v;
12202
12203 assert(vars != NULL || nvars == 0);
12204
12205 for( v = nvars - 1; v >= 0; --v )
12206 {
12207 assert(vars != NULL);
12208 assert(vars[v] != NULL);
12209
12210 vars[v] = SCIPvarGetProbvar(vars[v]);
12211 assert(vars[v] != NULL);
12212 }
12213 }
12214
12215 /** gets corresponding active, fixed, or multi-aggregated problem variable of a variable */
12216 SCIP_VAR* SCIPvarGetProbvar(
12217 SCIP_VAR* var /**< problem variable */
12218 )
12219 {
12220 SCIP_VAR* retvar;
12221
12222 assert(var != NULL);
12223
12224 retvar = var;
12225
12226 SCIPdebugMessage("get problem variable of <%s>\n", var->name);
12227
12228 while( TRUE ) /*lint !e716 */
12229 {
12230 assert(retvar != NULL);
12231
12232 switch( SCIPvarGetStatus(retvar) )
12233 {
12234 case SCIP_VARSTATUS_ORIGINAL:
12235 if( retvar->data.original.transvar == NULL )
12236 {
12237 SCIPerrorMessage("original variable has no transformed variable attached\n");
12238 SCIPABORT();
12239 return NULL; /*lint !e527 */
12240 }
12241 retvar = retvar->data.original.transvar;
12242 break;
12243
12244 case SCIP_VARSTATUS_LOOSE:
12245 case SCIP_VARSTATUS_COLUMN:
12246 case SCIP_VARSTATUS_FIXED:
12247 return retvar;
12248
12249 case SCIP_VARSTATUS_MULTAGGR:
12250 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12251 if ( retvar->data.multaggr.nvars == 1 )
12252 retvar = retvar->data.multaggr.vars[0];
12253 else
12254 return retvar;
12255 break;
12256
12257 case SCIP_VARSTATUS_AGGREGATED:
12258 retvar = retvar->data.aggregate.var;
12259 break;
12260
12261 case SCIP_VARSTATUS_NEGATED:
12262 retvar = retvar->negatedvar;
12263 break;
12264
12265 default:
12266 SCIPerrorMessage("unknown variable status\n");
12267 SCIPABORT();
12268 return NULL; /*lint !e527*/
12269 }
12270 }
12271 }
12272
12273 /** gets corresponding active, fixed, or multi-aggregated problem variables of binary variables and updates the given
12274 * negation status of each variable
12275 */
12276 SCIP_RETCODE SCIPvarsGetProbvarBinary(
12277 SCIP_VAR*** vars, /**< pointer to binary problem variables */
12278 SCIP_Bool** negatedarr, /**< pointer to corresponding array to update the negation status */
12279 int nvars /**< number of variables and values in vars and negated array */
12280 )
12281 {
12282 SCIP_VAR** var;
12283 SCIP_Bool* negated;
12284 int v;
12285
12286 assert(vars != NULL);
12287 assert(*vars != NULL || nvars == 0);
12288 assert(negatedarr != NULL);
12289 assert(*negatedarr != NULL || nvars == 0);
12290
12291 for( v = nvars - 1; v >= 0; --v )
12292 {
12293 var = &((*vars)[v]);
12294 negated = &((*negatedarr)[v]);
12295
12296 /* get problem variable */
12297 SCIP_CALL( SCIPvarGetProbvarBinary(var, negated) );
12298 }
12299
12300 return SCIP_OKAY;
12301 }
12302
12303
12304 /** gets corresponding active, fixed, or multi-aggregated problem variable of a binary variable and updates the given
12305 * negation status (this means you have to assign a value to SCIP_Bool negated before calling this method, usually
12306 * FALSE is used)
12307 */
12308 SCIP_RETCODE SCIPvarGetProbvarBinary(
12309 SCIP_VAR** var, /**< pointer to binary problem variable */
12310 SCIP_Bool* negated /**< pointer to update the negation status */
12311 )
12312 {
12313 SCIP_Bool active = FALSE;
12314 #ifndef NDEBUG
12315 SCIP_Real constant = 0.0;
12316 SCIP_Bool orignegated;
12317 #endif
12318
12319 assert(var != NULL);
12320 assert(*var != NULL);
12321 assert(negated != NULL);
12322 assert(SCIPvarIsBinary(*var));
12323
12324 #ifndef NDEBUG
12325 orignegated = *negated;
12326 #endif
12327
12328 while( !active && *var != NULL )
12329 {
12330 switch( SCIPvarGetStatus(*var) )
12331 {
12332 case SCIP_VARSTATUS_ORIGINAL:
12333 if( (*var)->data.original.transvar == NULL )
12334 return SCIP_OKAY;
12335 *var = (*var)->data.original.transvar;
12336 break;
12337
12338 case SCIP_VARSTATUS_LOOSE:
12339 case SCIP_VARSTATUS_COLUMN:
12340 case SCIP_VARSTATUS_FIXED:
12341 active = TRUE;
12342 break;
12343
12344 case SCIP_VARSTATUS_MULTAGGR:
12345 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12346 if ( (*var)->data.multaggr.nvars == 1 )
12347 {
12348 assert( (*var)->data.multaggr.vars != NULL );
12349 assert( (*var)->data.multaggr.scalars != NULL );
12350 assert( SCIPvarIsBinary((*var)->data.multaggr.vars[0]) );
12351 assert(!EPSZ((*var)->data.multaggr.scalars[0], 1e-06));
12352
12353 /* if not all variables were fully propagated, it might happen that a variable is multi-aggregated to
12354 * another variable which needs to be fixed
12355 *
12356 * e.g. x = y - 1 => (x = 0 && y = 1)
12357 * e.g. x = y + 1 => (x = 1 && y = 0)
12358 *
12359 * is this special case we need to return the muti-aggregation
12360 */
12361 if( EPSEQ((*var)->data.multaggr.constant, -1.0, 1e-06) || (EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06) && EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06)) )
12362 {
12363 assert(EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06));
12364 }
12365 else
12366 {
12367 /* @note due to fixations, a multi-aggregation can have a constant of zero and a negative scalar or even
12368 * a scalar in absolute value unequal to one, in this case this aggregation variable needs to be
12369 * fixed to zero, but this should be done by another enforcement; so not depending on the scalar,
12370 * we will return the aggregated variable;
12371 */
12372 if( !EPSEQ(REALABS((*var)->data.multaggr.scalars[0]), 1.0, 1e-06) )
12373 {
12374 active = TRUE;
12375 break;
12376 }
12377
12378 /* @note it may also happen that the constant is larger than 1 or smaller than 0, in that case the
12379 * aggregation variable needs to be fixed to one, but this should be done by another enforcement;
12380 * so if this is the case, we will return the aggregated variable
12381 */
12382 assert(EPSZ((*var)->data.multaggr.constant, 1e-06) || EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06)
12383 || EPSZ((*var)->data.multaggr.constant + (*var)->data.multaggr.scalars[0], 1e-06)
12384 || EPSEQ((*var)->data.multaggr.constant + (*var)->data.multaggr.scalars[0], 1.0, 1e-06));
12385
12386 if( !EPSZ((*var)->data.multaggr.constant, 1e-06) && !EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06) )
12387 {
12388 active = TRUE;
12389 break;
12390 }
12391
12392 assert(EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06) || EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06));
12393
12394 if( EPSZ((*var)->data.multaggr.constant, 1e-06) )
12395 {
12396 /* if the scalar is negative, either the aggregation variable is already fixed to zero or has at
12397 * least one uplock (that hopefully will enforce this fixation to zero); can it happen that this
12398 * variable itself is multi-aggregated again?
12399 */
12400 assert(EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06) ?
12401 ((SCIPvarGetUbGlobal((*var)->data.multaggr.vars[0]) < 0.5) ||
12402 SCIPvarGetNLocksUpType((*var)->data.multaggr.vars[0], SCIP_LOCKTYPE_MODEL) > 0) : TRUE);
12403 }
12404 else
12405 {
12406 assert(EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06));
12407 #ifndef NDEBUG
12408 constant += (*negated) != orignegated ? -1.0 : 1.0;
12409 #endif
12410
12411 *negated = !(*negated);
12412 }
12413 *var = (*var)->data.multaggr.vars[0];
12414 break;
12415 }
12416 }
12417 active = TRUE; /*lint !e838*/
12418 break;
12419
12420 case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */
12421 assert((*var)->data.aggregate.var != NULL);
12422 assert(EPSEQ((*var)->data.aggregate.scalar, 1.0, 1e-06) || EPSEQ((*var)->data.aggregate.scalar, -1.0, 1e-06));
12423 assert(EPSLE((*var)->data.aggregate.var->glbdom.ub - (*var)->data.aggregate.var->glbdom.lb, 1.0, 1e-06));
12424 #ifndef NDEBUG
12425 constant += (*negated) != orignegated ? -(*var)->data.aggregate.constant : (*var)->data.aggregate.constant;
12426 #endif
12427
12428 *negated = ((*var)->data.aggregate.scalar > 0.0) ? *negated : !(*negated);
12429 *var = (*var)->data.aggregate.var;
12430 break;
12431
12432 case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */
12433 assert((*var)->negatedvar != NULL);
12434 #ifndef NDEBUG
12435 constant += (*negated) != orignegated ? -1.0 : 1.0;
12436 #endif
12437
12438 *negated = !(*negated);
12439 *var = (*var)->negatedvar;
12440 break;
12441
12442 default:
12443 SCIPerrorMessage("unknown variable status\n");
12444 return SCIP_INVALIDDATA;
12445 }
12446 }
12447 assert(active == (*var != NULL));
12448
12449 if( active )
12450 {
12451 assert(SCIPvarIsBinary(*var));
12452 assert(EPSZ(constant, 1e-06) || EPSEQ(constant, 1.0, 1e-06));
12453 assert(EPSZ(constant, 1e-06) == ((*negated) == orignegated));
12454
12455 return SCIP_OKAY;
12456 }
12457 else
12458 {
12459 SCIPerrorMessage("active variable path leads to NULL pointer\n");
12460 return SCIP_INVALIDDATA;
12461 }
12462 }
12463
12464 /** transforms given variable, boundtype and bound to the corresponding active, fixed, or multi-aggregated variable
12465 * values
12466 */
12467 SCIP_RETCODE SCIPvarGetProbvarBound(
12468 SCIP_VAR** var, /**< pointer to problem variable */
12469 SCIP_Real* bound, /**< pointer to bound value to transform */
12470 SCIP_BOUNDTYPE* boundtype /**< pointer to type of bound: lower or upper bound */
12471 )
12472 {
12473 assert(var != NULL);
12474 assert(*var != NULL);
12475 assert(bound != NULL);
12476 assert(boundtype != NULL);
12477
12478 SCIPdebugMessage("get probvar bound %g of type %d of variable <%s>\n", *bound, *boundtype, (*var)->name);
12479
12480 switch( SCIPvarGetStatus(*var) )
12481 {
12482 case SCIP_VARSTATUS_ORIGINAL:
12483 if( (*var)->data.original.transvar == NULL )
12484 {
12485 SCIPerrorMessage("original variable has no transformed variable attached\n");
12486 return SCIP_INVALIDDATA;
12487 }
12488 *var = (*var)->data.original.transvar;
12489 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12490 break;
12491
12492 case SCIP_VARSTATUS_LOOSE:
12493 case SCIP_VARSTATUS_COLUMN:
12494 case SCIP_VARSTATUS_FIXED:
12495 break;
12496
12497 case SCIP_VARSTATUS_MULTAGGR:
12498 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12499 if ( (*var)->data.multaggr.nvars == 1 )
12500 {
12501 assert( (*var)->data.multaggr.vars != NULL );
12502 assert( (*var)->data.multaggr.scalars != NULL );
12503 assert( (*var)->data.multaggr.scalars[0] != 0.0 );
12504
12505 (*bound) /= (*var)->data.multaggr.scalars[0];
12506 (*bound) -= (*var)->data.multaggr.constant/(*var)->data.multaggr.scalars[0];
12507 if ( (*var)->data.multaggr.scalars[0] < 0.0 )
12508 {
12509 if ( *boundtype == SCIP_BOUNDTYPE_LOWER )
12510 *boundtype = SCIP_BOUNDTYPE_UPPER;
12511 else
12512 *boundtype = SCIP_BOUNDTYPE_LOWER;
12513 }
12514 *var = (*var)->data.multaggr.vars[0];
12515 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12516 }
12517 break;
12518
12519 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = x/a - c/a */
12520 assert((*var)->data.aggregate.var != NULL);
12521 assert((*var)->data.aggregate.scalar != 0.0);
12522
12523 (*bound) /= (*var)->data.aggregate.scalar;
12524 (*bound) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
12525 if( (*var)->data.aggregate.scalar < 0.0 )
12526 {
12527 if( *boundtype == SCIP_BOUNDTYPE_LOWER )
12528 *boundtype = SCIP_BOUNDTYPE_UPPER;
12529 else
12530 *boundtype = SCIP_BOUNDTYPE_LOWER;
12531 }
12532 *var = (*var)->data.aggregate.var;
12533 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12534 break;
12535
12536 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12537 assert((*var)->negatedvar != NULL);
12538 assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
12539 assert((*var)->negatedvar->negatedvar == *var);
12540 (*bound) = (*var)->data.negate.constant - *bound;
12541 if( *boundtype == SCIP_BOUNDTYPE_LOWER )
12542 *boundtype = SCIP_BOUNDTYPE_UPPER;
12543 else
12544 *boundtype = SCIP_BOUNDTYPE_LOWER;
12545 *var = (*var)->negatedvar;
12546 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12547 break;
12548
12549 default:
12550 SCIPerrorMessage("unknown variable status\n");
12551 return SCIP_INVALIDDATA;
12552 }
12553
12554 return SCIP_OKAY;
12555 }
12556
12557 /** transforms given variable and domain hole to the corresponding active, fixed, or multi-aggregated variable
12558 * values
12559 */
12560 SCIP_RETCODE SCIPvarGetProbvarHole(
12561 SCIP_VAR** var, /**< pointer to problem variable */
12562 SCIP_Real* left, /**< pointer to left bound of open interval in hole to transform */
12563 SCIP_Real* right /**< pointer to right bound of open interval in hole to transform */
12564 )
12565 {
12566 assert(var != NULL);
12567 assert(*var != NULL);
12568 assert(left != NULL);
12569 assert(right != NULL);
12570
12571 SCIPdebugMessage("get probvar hole (%g,%g) of variable <%s>\n", *left, *right, (*var)->name);
12572
12573 switch( SCIPvarGetStatus(*var) )
12574 {
12575 case SCIP_VARSTATUS_ORIGINAL:
12576 if( (*var)->data.original.transvar == NULL )
12577 {
12578 SCIPerrorMessage("original variable has no transformed variable attached\n");
12579 return SCIP_INVALIDDATA;
12580 }
12581 *var = (*var)->data.original.transvar;
12582 SCIP_CALL( SCIPvarGetProbvarHole(var, left, right) );
12583 break;
12584
12585 case SCIP_VARSTATUS_LOOSE:
12586 case SCIP_VARSTATUS_COLUMN:
12587 case SCIP_VARSTATUS_FIXED:
12588 case SCIP_VARSTATUS_MULTAGGR:
12589 break;
12590
12591 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = x/a - c/a */
12592 assert((*var)->data.aggregate.var != NULL);
12593 assert((*var)->data.aggregate.scalar != 0.0);
12594
12595 /* scale back */
12596 (*left) /= (*var)->data.aggregate.scalar;
12597 (*right) /= (*var)->data.aggregate.scalar;
12598
12599 /* shift back */
12600 (*left) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
12601 (*right) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
12602
12603 *var = (*var)->data.aggregate.var;
12604
12605 /* check if the interval bounds have to swapped */
12606 if( (*var)->data.aggregate.scalar < 0.0 )
12607 {
12608 SCIP_CALL( SCIPvarGetProbvarHole(var, right, left) );
12609 }
12610 else
12611 {
12612 SCIP_CALL( SCIPvarGetProbvarHole(var, left, right) );
12613 }
12614 break;
12615
12616 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12617 assert((*var)->negatedvar != NULL);
12618 assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
12619 assert((*var)->negatedvar->negatedvar == *var);
12620
12621 /* shift and scale back */
12622 (*left) = (*var)->data.negate.constant - (*left);
12623 (*right) = (*var)->data.negate.constant - (*right);
12624
12625 *var = (*var)->negatedvar;
12626
12627 /* through the negated variable the left and right interval bound have to swapped */
12628 SCIP_CALL( SCIPvarGetProbvarHole(var, right, left) );
12629 break;
12630
12631 default:
12632 SCIPerrorMessage("unknown variable status\n");
12633 return SCIP_INVALIDDATA;
12634 }
12635
12636 return SCIP_OKAY;
12637 }
12638
12639 /** transforms given variable, scalar and constant to the corresponding active, fixed, or
12640 * multi-aggregated variable, scalar and constant; if the variable resolves to a fixed variable,
12641 * "scalar" will be 0.0 and the value of the sum will be stored in "constant"; a multi-aggregation
12642 * with only one active variable (this can happen due to fixings after the multi-aggregation),
12643 * is treated like an aggregation; if the multi-aggregation constant is infinite, "scalar" will be 0.0
12644 */
12645 SCIP_RETCODE SCIPvarGetProbvarSum(
12646 SCIP_VAR** var, /**< pointer to problem variable x in sum a*x + c */
12647 SCIP_SET* set, /**< global SCIP settings */
12648 SCIP_Real* scalar, /**< pointer to scalar a in sum a*x + c */
12649 SCIP_Real* constant /**< pointer to constant c in sum a*x + c */
12650 )
12651 {
12652 assert(var != NULL);
12653 assert(scalar != NULL);
12654 assert(constant != NULL);
12655
12656 while( *var != NULL )
12657 {
12658 switch( SCIPvarGetStatus(*var) )
12659 {
12660 case SCIP_VARSTATUS_ORIGINAL:
12661 if( (*var)->data.original.transvar == NULL )
12662 {
12663 SCIPerrorMessage("original variable has no transformed variable attached\n");
12664 return SCIP_INVALIDDATA;
12665 }
12666 *var = (*var)->data.original.transvar;
12667 break;
12668
12669 case SCIP_VARSTATUS_LOOSE:
12670 case SCIP_VARSTATUS_COLUMN:
12671 return SCIP_OKAY;
12672
12673 case SCIP_VARSTATUS_FIXED: /* x = c' => a*x + c == (a*c' + c) */
12674 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12675 {
12676 if( SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)) )
12677 {
12678 assert(*scalar != 0.0);
12679 if( (*scalar) * (*var)->glbdom.lb > 0.0 )
12680 (*constant) = SCIPsetInfinity(set);
12681 else
12682 (*constant) = -SCIPsetInfinity(set);
12683 }
12684 else
12685 (*constant) += *scalar * (*var)->glbdom.lb;
12686 }
12687 #ifndef NDEBUG
12688 else
12689 {
12690 assert(!SCIPsetIsInfinity(set, (*constant)) || !((*scalar) * (*var)->glbdom.lb < 0.0 &&
12691 (SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)))));
12692 assert(!SCIPsetIsInfinity(set, -(*constant)) || !((*scalar) * (*var)->glbdom.lb > 0.0 &&
12693 (SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)))));
12694 }
12695 #endif
12696 *scalar = 0.0;
12697 return SCIP_OKAY;
12698
12699 case SCIP_VARSTATUS_MULTAGGR:
12700 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12701 if ( (*var)->data.multaggr.nvars == 1 )
12702 {
12703 assert((*var)->data.multaggr.vars != NULL);
12704 assert((*var)->data.multaggr.scalars != NULL);
12705 assert((*var)->data.multaggr.vars[0] != NULL);
12706 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12707 {
12708 /* the multi-aggregation constant can be infinite, if one of the multi-aggregation variables
12709 * was fixed to +/-infinity; ensure that the constant is set to +/-infinity, too, and the scalar
12710 * is set to 0.0, because the multi-aggregated variable can be seen as fixed, too
12711 */
12712 if( SCIPsetIsInfinity(set, (*var)->data.multaggr.constant)
12713 || SCIPsetIsInfinity(set, -((*var)->data.multaggr.constant)) )
12714 {
12715 if( (*scalar) * (*var)->data.multaggr.constant > 0 )
12716 {
12717 assert(!SCIPsetIsInfinity(set, -(*constant)));
12718 (*constant) = SCIPsetInfinity(set);
12719 }
12720 else
12721 {
12722 assert(!SCIPsetIsInfinity(set, *constant));
12723 (*constant) = -SCIPsetInfinity(set);
12724 }
12725 (*scalar) = 0.0;
12726 }
12727 else
12728 (*constant) += *scalar * (*var)->data.multaggr.constant;
12729 }
12730 (*scalar) *= (*var)->data.multaggr.scalars[0];
12731 *var = (*var)->data.multaggr.vars[0];
12732 break;
12733 }
12734 return SCIP_OKAY;
12735
12736 case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */
12737 assert((*var)->data.aggregate.var != NULL);
12738 assert(!SCIPsetIsInfinity(set, (*var)->data.aggregate.constant)
12739 && !SCIPsetIsInfinity(set, (*var)->data.aggregate.constant));
12740 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12741 (*constant) += *scalar * (*var)->data.aggregate.constant;
12742 (*scalar) *= (*var)->data.aggregate.scalar;
12743 *var = (*var)->data.aggregate.var;
12744 break;
12745
12746 case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */
12747 assert((*var)->negatedvar != NULL);
12748 assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
12749 assert((*var)->negatedvar->negatedvar == *var);
12750 assert(!SCIPsetIsInfinity(set, (*var)->data.negate.constant)
12751 && !SCIPsetIsInfinity(set, (*var)->data.negate.constant));
12752 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12753 (*constant) += *scalar * (*var)->data.negate.constant;
12754 (*scalar) *= -1.0;
12755 *var = (*var)->negatedvar;
12756 break;
12757
12758 default:
12759 SCIPerrorMessage("unknown variable status\n");
12760 SCIPABORT();
12761 return SCIP_INVALIDDATA; /*lint !e527*/
12762 }
12763 }
12764 *scalar = 0.0;
12765
12766 return SCIP_OKAY;
12767 }
12768
12769 /** retransforms given variable, scalar and constant to the corresponding original variable, scalar
12770 * and constant, if possible; if the retransformation is impossible, NULL is returned as variable
12771 */
12772 SCIP_RETCODE SCIPvarGetOrigvarSum(
12773 SCIP_VAR** var, /**< pointer to problem variable x in sum a*x + c */
12774 SCIP_Real* scalar, /**< pointer to scalar a in sum a*x + c */
12775 SCIP_Real* constant /**< pointer to constant c in sum a*x + c */
12776 )
12777 {
12778 SCIP_VAR* parentvar;
12779
12780 assert(var != NULL);
12781 assert(*var != NULL);
12782 assert(scalar != NULL);
12783 assert(constant != NULL);
12784
12785 while( !SCIPvarIsOriginal(*var) )
12786 {
12787 /* if the variable has no parent variables, it was generated during solving and has no corresponding original
12788 * var
12789 */
12790 if( (*var)->nparentvars == 0 )
12791 {
12792 /* negated variables do not need to have a parent variables, and negated variables can exist in original
12793 * space
12794 */
12795 if( SCIPvarGetStatus(*var) == SCIP_VARSTATUS_NEGATED &&
12796 ((*var)->negatedvar->nparentvars == 0 || (*var)->negatedvar->parentvars[0] != *var) )
12797 {
12798 *scalar *= -1.0;
12799 *constant -= (*var)->data.negate.constant * (*scalar);
12800 *var = (*var)->negatedvar;
12801
12802 continue;
12803 }
12804 /* if the variables does not have any parent the variables was created during solving and has no original
12805 * counterpart
12806 */
12807 else
12808 {
12809 *var = NULL;
12810
12811 return SCIP_OKAY;
12812 }
12813 }
12814
12815 /* follow the link to the first parent variable */
12816 parentvar = (*var)->parentvars[0];
12817 assert(parentvar != NULL);
12818
12819 switch( SCIPvarGetStatus(parentvar) )
12820 {
12821 case SCIP_VARSTATUS_ORIGINAL:
12822 break;
12823
12824 case SCIP_VARSTATUS_COLUMN:
12825 case SCIP_VARSTATUS_LOOSE:
12826 case SCIP_VARSTATUS_FIXED:
12827 case SCIP_VARSTATUS_MULTAGGR:
12828 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
12829 return SCIP_INVALIDDATA;
12830
12831 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + b -> y = (x-b)/a, s*y + c = (s/a)*x + c-b*s/a */
12832 assert(parentvar->data.aggregate.var == *var);
12833 assert(parentvar->data.aggregate.scalar != 0.0);
12834 *scalar /= parentvar->data.aggregate.scalar;
12835 *constant -= parentvar->data.aggregate.constant * (*scalar);
12836 break;
12837
12838 case SCIP_VARSTATUS_NEGATED: /* x = b - y -> y = b - x, s*y + c = -s*x + c+b*s */
12839 assert(parentvar->negatedvar != NULL);
12840 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
12841 assert(parentvar->negatedvar->negatedvar == parentvar);
12842 *scalar *= -1.0;
12843 *constant -= parentvar->data.negate.constant * (*scalar);
12844 break;
12845
12846 default:
12847 SCIPerrorMessage("unknown variable status\n");
12848 return SCIP_INVALIDDATA;
12849 }
12850
12851 assert( parentvar != NULL );
12852 *var = parentvar;
12853 }
12854
12855 return SCIP_OKAY;
12856 }
12857
12858 /** returns whether the given variable is the direct counterpart of an original problem variable */
12859 SCIP_Bool SCIPvarIsTransformedOrigvar(
12860 SCIP_VAR* var /**< problem variable */
12861 )
12862 {
12863 SCIP_VAR* parentvar;
12864 assert(var != NULL);
12865
12866 if( !SCIPvarIsTransformed(var) || var->nparentvars < 1 )
12867 return FALSE;
12868
12869 assert(var->parentvars != NULL);
12870 parentvar = var->parentvars[0];
12871 assert(parentvar != NULL);
12872
12873 /* we follow the aggregation tree to the root unless an original variable has been found - the first entries in the parentlist are candidates */
12874 while( parentvar->nparentvars >= 1 && SCIPvarGetStatus(parentvar) != SCIP_VARSTATUS_ORIGINAL )
12875 parentvar = parentvar->parentvars[0];
12876 assert( parentvar != NULL );
12877
12878 return ( SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_ORIGINAL );
12879 }
12880
12881 /** gets objective value of variable in current SCIP_LP; the value can be different from the objective value stored in
12882 * the variable's own data due to diving, that operate only on the LP without updating the variables
12883 */
12884 SCIP_Real SCIPvarGetObjLP(
12885 SCIP_VAR* var /**< problem variable */
12886 )
12887 {
12888 assert(var != NULL);
12889
12890 /* get bounds of attached variables */
12891 switch( SCIPvarGetStatus(var) )
12892 {
12893 case SCIP_VARSTATUS_ORIGINAL:
12894 assert(var->data.original.transvar != NULL);
12895 return SCIPvarGetObjLP(var->data.original.transvar);
12896
12897 case SCIP_VARSTATUS_COLUMN:
12898 assert(var->data.col != NULL);
12899 return SCIPcolGetObj(var->data.col);
12900
12901 case SCIP_VARSTATUS_LOOSE:
12902 case SCIP_VARSTATUS_FIXED:
12903 return var->obj;
12904
12905 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
12906 assert(var->data.aggregate.var != NULL);
12907 return var->data.aggregate.scalar * SCIPvarGetObjLP(var->data.aggregate.var);
12908
12909 case SCIP_VARSTATUS_MULTAGGR:
12910 SCIPerrorMessage("cannot get the objective value of a multiple aggregated variable\n");
12911 SCIPABORT();
12912 return 0.0; /*lint !e527*/
12913
12914 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12915 assert(var->negatedvar != NULL);
12916 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
12917 assert(var->negatedvar->negatedvar == var);
12918 return -SCIPvarGetObjLP(var->negatedvar);
12919
12920 default:
12921 SCIPerrorMessage("unknown variable status\n");
12922 SCIPABORT();
12923 return 0.0; /*lint !e527*/
12924 }
12925 }
12926
12927 /** gets lower bound of variable in current SCIP_LP; the bound can be different from the bound stored in the variable's own
12928 * data due to diving or conflict analysis, that operate only on the LP without updating the variables
12929 */
12930 SCIP_Real SCIPvarGetLbLP(
12931 SCIP_VAR* var, /**< problem variable */
12932 SCIP_SET* set /**< global SCIP settings */
12933 )
12934 {
12935 assert(var != NULL);
12936 assert(set != NULL);
12937 assert(var->scip == set->scip);
12938
12939 /* get bounds of attached variables */
12940 switch( SCIPvarGetStatus(var) )
12941 {
12942 case SCIP_VARSTATUS_ORIGINAL:
12943 assert(var->data.original.transvar != NULL);
12944 return SCIPvarGetLbLP(var->data.original.transvar, set);
12945
12946 case SCIP_VARSTATUS_COLUMN:
12947 assert(var->data.col != NULL);
12948 return SCIPcolGetLb(var->data.col);
12949
12950 case SCIP_VARSTATUS_LOOSE:
12951 case SCIP_VARSTATUS_FIXED:
12952 return var->locdom.lb;
12953
12954 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
12955 assert(var->data.aggregate.var != NULL);
12956 if( (var->data.aggregate.scalar > 0.0 && SCIPsetIsInfinity(set, -SCIPvarGetLbLP(var->data.aggregate.var, set)))
12957 || (var->data.aggregate.scalar < 0.0 && SCIPsetIsInfinity(set, SCIPvarGetUbLP(var->data.aggregate.var, set))) )
12958 {
12959 return -SCIPsetInfinity(set);
12960 }
12961 else if( var->data.aggregate.scalar > 0.0 )
12962 {
12963 /* a > 0 -> get lower bound of y */
12964 return var->data.aggregate.scalar * SCIPvarGetLbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
12965 }
12966 else if( var->data.aggregate.scalar < 0.0 )
12967 {
12968 /* a < 0 -> get upper bound of y */
12969 return var->data.aggregate.scalar * SCIPvarGetUbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
12970 }
12971 else
12972 {
12973 SCIPerrorMessage("scalar is zero in aggregation\n");
12974 SCIPABORT();
12975 return SCIP_INVALID; /*lint !e527*/
12976 }
12977
12978 case SCIP_VARSTATUS_MULTAGGR:
12979 /**@todo get the sides of the corresponding linear constraint */
12980 SCIPerrorMessage("getting the bounds of a multiple aggregated variable is not implemented yet\n");
12981 SCIPABORT();
12982 return SCIP_INVALID; /*lint !e527*/
12983
12984 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12985 assert(var->negatedvar != NULL);
12986 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
12987 assert(var->negatedvar->negatedvar == var);
12988 return var->data.negate.constant - SCIPvarGetUbLP(var->negatedvar, set);
12989
12990 default:
12991 SCIPerrorMessage("unknown variable status\n");
12992 SCIPABORT();
12993 return SCIP_INVALID; /*lint !e527*/
12994 }
12995 }
12996
12997 /** gets upper bound of variable in current SCIP_LP; the bound can be different from the bound stored in the variable's own
12998 * data due to diving or conflict analysis, that operate only on the LP without updating the variables
12999 */
13000 SCIP_Real SCIPvarGetUbLP(
13001 SCIP_VAR* var, /**< problem variable */
13002 SCIP_SET* set /**< global SCIP settings */
13003 )
13004 {
13005 assert(var != NULL);
13006 assert(set != NULL);
13007 assert(var->scip == set->scip);
13008
13009 /* get bounds of attached variables */
13010 switch( SCIPvarGetStatus(var) )
13011 {
13012 case SCIP_VARSTATUS_ORIGINAL:
13013 assert(var->data.original.transvar != NULL);
13014 return SCIPvarGetUbLP(var->data.original.transvar, set);
13015
13016 case SCIP_VARSTATUS_COLUMN:
13017 assert(var->data.col != NULL);
13018 return SCIPcolGetUb(var->data.col);
13019
13020 case SCIP_VARSTATUS_LOOSE:
13021 case SCIP_VARSTATUS_FIXED:
13022 return var->locdom.ub;
13023
13024 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
13025 assert(var->data.aggregate.var != NULL);
13026 if( (var->data.aggregate.scalar > 0.0 && SCIPsetIsInfinity(set, SCIPvarGetUbLP(var->data.aggregate.var, set)))
13027 || (var->data.aggregate.scalar < 0.0 && SCIPsetIsInfinity(set, -SCIPvarGetLbLP(var->data.aggregate.var, set))) )
13028 {
13029 return SCIPsetInfinity(set);
13030 }
13031 if( var->data.aggregate.scalar > 0.0 )
13032 {
13033 /* a > 0 -> get upper bound of y */
13034 return var->data.aggregate.scalar * SCIPvarGetUbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
13035 }
13036 else if( var->data.aggregate.scalar < 0.0 )
13037 {
13038 /* a < 0 -> get lower bound of y */
13039 return var->data.aggregate.scalar * SCIPvarGetLbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
13040 }
13041 else
13042 {
13043 SCIPerrorMessage("scalar is zero in aggregation\n");
13044 SCIPABORT();
13045 return SCIP_INVALID; /*lint !e527*/
13046 }
13047
13048 case SCIP_VARSTATUS_MULTAGGR:
13049 SCIPerrorMessage("cannot get the bounds of a multi-aggregated variable.\n");
13050 SCIPABORT();
13051 return SCIP_INVALID; /*lint !e527*/
13052
13053 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13054 assert(var->negatedvar != NULL);
13055 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
13056 assert(var->negatedvar->negatedvar == var);
13057 return var->data.negate.constant - SCIPvarGetLbLP(var->negatedvar, set);
13058
13059 default:
13060 SCIPerrorMessage("unknown variable status\n");
13061 SCIPABORT();
13062 return SCIP_INVALID; /*lint !e527*/
13063 }
13064 }
13065
13066 /** gets primal LP solution value of variable */
13067 SCIP_Real SCIPvarGetLPSol_rec(
13068 SCIP_VAR* var /**< problem variable */
13069 )
13070 {
13071 assert(var != NULL);
13072
13073 switch( SCIPvarGetStatus(var) )
13074 {
13075 case SCIP_VARSTATUS_ORIGINAL:
13076 if( var->data.original.transvar == NULL )
13077 return SCIP_INVALID;
13078 return SCIPvarGetLPSol(var->data.original.transvar);
13079
13080 case SCIP_VARSTATUS_LOOSE:
13081 return SCIPvarGetBestBoundLocal(var);
13082
13083 case SCIP_VARSTATUS_COLUMN:
13084 assert(var->data.col != NULL);
13085 return SCIPcolGetPrimsol(var->data.col);
13086
13087 case SCIP_VARSTATUS_FIXED:
13088 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13089 return var->locdom.lb;
13090
13091 case SCIP_VARSTATUS_AGGREGATED:
13092 {
13093 SCIP_Real lpsolval;
13094
13095 assert(!var->donotaggr);
13096 assert(var->data.aggregate.var != NULL);
13097 lpsolval = SCIPvarGetLPSol(var->data.aggregate.var);
13098
13099 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
13100 * corresponding infinity value instead of performing an arithmetical transformation (compare method
13101 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
13102 * (or is called by) a public interface method; instead, we only assert that values are finite
13103 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
13104 * positives and negatives if the parameter <numerics/infinity> is modified by the user
13105 */
13106 assert(lpsolval > -SCIP_DEFAULT_INFINITY);
13107 assert(lpsolval < +SCIP_DEFAULT_INFINITY);
13108 return var->data.aggregate.scalar * lpsolval + var->data.aggregate.constant;
13109 }
13110 case SCIP_VARSTATUS_MULTAGGR:
13111 {
13112 SCIP_Real primsol;
13113 int i;
13114
13115 assert(!var->donotmultaggr);
13116 assert(var->data.multaggr.vars != NULL);
13117 assert(var->data.multaggr.scalars != NULL);
13118 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13119 * assert(var->data.multaggr.nvars >= 2);
13120 */
13121 primsol = var->data.multaggr.constant;
13122 for( i = 0; i < var->data.multaggr.nvars; ++i )
13123 primsol += var->data.multaggr.scalars[i] * SCIPvarGetLPSol(var->data.multaggr.vars[i]);
13124 return primsol;
13125 }
13126 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13127 assert(var->negatedvar != NULL);
13128 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
13129 assert(var->negatedvar->negatedvar == var);
13130 return var->data.negate.constant - SCIPvarGetLPSol(var->negatedvar);
13131
13132 default:
13133 SCIPerrorMessage("unknown variable status\n");
13134 SCIPABORT();
13135 return SCIP_INVALID; /*lint !e527*/
13136 }
13137 }
13138
13139 /** gets primal NLP solution value of variable */
13140 SCIP_Real SCIPvarGetNLPSol_rec(
13141 SCIP_VAR* var /**< problem variable */
13142 )
13143 {
13144 SCIP_Real solval;
13145 int i;
13146
13147 assert(var != NULL);
13148
13149 /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */
13150 switch( SCIPvarGetStatus(var) )
13151 {
13152 case SCIP_VARSTATUS_ORIGINAL:
13153 return SCIPvarGetNLPSol(var->data.original.transvar);
13154
13155 case SCIP_VARSTATUS_LOOSE:
13156 case SCIP_VARSTATUS_COLUMN:
13157 return var->nlpsol;
13158
13159 case SCIP_VARSTATUS_FIXED:
13160 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var)); /*lint !e777*/
13161 assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var)); /*lint !e777*/
13162 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var)); /*lint !e777*/
13163 return SCIPvarGetLbGlobal(var);
13164
13165 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
13166 solval = SCIPvarGetNLPSol(var->data.aggregate.var);
13167 return var->data.aggregate.scalar * solval + var->data.aggregate.constant;
13168
13169 case SCIP_VARSTATUS_MULTAGGR:
13170 solval = var->data.multaggr.constant;
13171 for( i = 0; i < var->data.multaggr.nvars; ++i )
13172 solval += var->data.multaggr.scalars[i] * SCIPvarGetNLPSol(var->data.multaggr.vars[i]);
13173 return solval;
13174
13175 case SCIP_VARSTATUS_NEGATED:
13176 solval = SCIPvarGetNLPSol(var->negatedvar);
13177 return var->data.negate.constant - solval;
13178
13179 default:
13180 SCIPerrorMessage("unknown variable status\n");
13181 SCIPABORT();
13182 return SCIP_INVALID; /*lint !e527*/
13183 }
13184 }
13185
13186 /** gets pseudo solution value of variable at current node */
13187 static
13188 SCIP_Real SCIPvarGetPseudoSol_rec(
13189 SCIP_VAR* var /**< problem variable */
13190 )
13191 {
13192 SCIP_Real pseudosol;
13193 int i;
13194
13195 assert(var != NULL);
13196
13197 switch( SCIPvarGetStatus(var) )
13198 {
13199 case SCIP_VARSTATUS_ORIGINAL:
13200 if( var->data.original.transvar == NULL )
13201 return SCIP_INVALID;
13202 return SCIPvarGetPseudoSol(var->data.original.transvar);
13203
13204 case SCIP_VARSTATUS_LOOSE:
13205 case SCIP_VARSTATUS_COLUMN:
13206 return SCIPvarGetBestBoundLocal(var);
13207
13208 case SCIP_VARSTATUS_FIXED:
13209 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13210 return var->locdom.lb;
13211
13212 case SCIP_VARSTATUS_AGGREGATED:
13213 {
13214 SCIP_Real pseudosolval;
13215 assert(!var->donotaggr);
13216 assert(var->data.aggregate.var != NULL);
13217 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
13218 * corresponding infinity value instead of performing an arithmetical transformation (compare method
13219 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
13220 * (or is called by) a public interface method; instead, we only assert that values are finite
13221 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
13222 * positives and negatives if the parameter <numerics/infinity> is modified by the user
13223 */
13224 pseudosolval = SCIPvarGetPseudoSol(var->data.aggregate.var);
13225 assert(pseudosolval > -SCIP_DEFAULT_INFINITY);
13226 assert(pseudosolval < +SCIP_DEFAULT_INFINITY);
13227 return var->data.aggregate.scalar * pseudosolval + var->data.aggregate.constant;
13228 }
13229 case SCIP_VARSTATUS_MULTAGGR:
13230 assert(!var->donotmultaggr);
13231 assert(var->data.multaggr.vars != NULL);
13232 assert(var->data.multaggr.scalars != NULL);
13233 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13234 * assert(var->data.multaggr.nvars >= 2);
13235 */
13236 pseudosol = var->data.multaggr.constant;
13237 for( i = 0; i < var->data.multaggr.nvars; ++i )
13238 pseudosol += var->data.multaggr.scalars[i] * SCIPvarGetPseudoSol(var->data.multaggr.vars[i]);
13239 return pseudosol;
13240
13241 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13242 assert(var->negatedvar != NULL);
13243 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
13244 assert(var->negatedvar->negatedvar == var);
13245 return var->data.negate.constant - SCIPvarGetPseudoSol(var->negatedvar);
13246
13247 default:
13248 SCIPerrorMessage("unknown variable status\n");
13249 SCIPABORT();
13250 return SCIP_INVALID; /*lint !e527*/
13251 }
13252 }
13253
13254 /** gets current LP or pseudo solution value of variable */
13255 SCIP_Real SCIPvarGetSol(
13256 SCIP_VAR* var, /**< problem variable */
13257 SCIP_Bool getlpval /**< should the LP solution value be returned? */
13258 )
13259 {
13260 if( getlpval )
13261 return SCIPvarGetLPSol(var);
13262 else
13263 return SCIPvarGetPseudoSol(var);
13264 }
13265
13266 /** remembers the current solution as root solution in the problem variables */
13267 void SCIPvarStoreRootSol(
13268 SCIP_VAR* var, /**< problem variable */
13269 SCIP_Bool roothaslp /**< is the root solution from LP? */
13270 )
13271 {
13272 assert(var != NULL);
13273
13274 var->rootsol = SCIPvarGetSol(var, roothaslp);
13275 }
13276
13277 /** updates the current solution as best root solution of the given variable if it is better */
13278 void SCIPvarUpdateBestRootSol(
13279 SCIP_VAR* var, /**< problem variable */
13280 SCIP_SET* set, /**< global SCIP settings */
13281 SCIP_Real rootsol, /**< root solution value */
13282 SCIP_Real rootredcost, /**< root reduced cost */
13283 SCIP_Real rootlpobjval /**< objective value of the root LP */
13284 )
13285 {
13286 assert(var != NULL);
13287 assert(set != NULL);
13288 assert(var->scip == set->scip);
13289
13290 /* if reduced cost are zero nothing to update */
13291 if( SCIPsetIsDualfeasZero(set, rootredcost) )
13292 return;
13293
13294 /* check if we have already a best combination stored */
13295 if( !SCIPsetIsDualfeasZero(set, var->bestrootredcost) )
13296 {
13297 SCIP_Real currcutoffbound;
13298 SCIP_Real cutoffbound;
13299 SCIP_Real bound;
13300
13301 /* compute the cutoff bound which would improve the corresponding bound with the current stored root solution,
13302 * root reduced cost, and root LP objective value combination
13303 */
13304 if( var->bestrootredcost > 0.0 )
13305 bound = SCIPvarGetUbGlobal(var);
13306 else
13307 bound = SCIPvarGetLbGlobal(var);
13308
13309 currcutoffbound = (bound - var->bestrootsol) * var->bestrootredcost + var->bestrootlpobjval;
13310
13311 /* compute the cutoff bound which would improve the corresponding bound with new root solution, root reduced
13312 * cost, and root LP objective value combination
13313 */
13314 if( rootredcost > 0.0 )
13315 bound = SCIPvarGetUbGlobal(var);
13316 else
13317 bound = SCIPvarGetLbGlobal(var);
13318
13319 cutoffbound = (bound - rootsol) * rootredcost + rootlpobjval;
13320
13321 /* check if an improving root solution, root reduced cost, and root LP objective value is at hand */
13322 if( cutoffbound > currcutoffbound )
13323 {
13324 SCIPsetDebugMsg(set, "-> <%s> update potential cutoff bound <%g> -> <%g>\n",
13325 SCIPvarGetName(var), currcutoffbound, cutoffbound);
13326
13327 var->bestrootsol = rootsol;
13328 var->bestrootredcost = rootredcost;
13329 var->bestrootlpobjval = rootlpobjval;
13330 }
13331 }
13332 else
13333 {
13334 SCIPsetDebugMsg(set, "-> <%s> initialize best root reduced cost information\n", SCIPvarGetName(var));
13335 SCIPsetDebugMsg(set, " -> rootsol <%g>\n", rootsol);
13336 SCIPsetDebugMsg(set, " -> rootredcost <%g>\n", rootredcost);
13337 SCIPsetDebugMsg(set, " -> rootlpobjval <%g>\n", rootlpobjval);
13338
13339 var->bestrootsol = rootsol;
13340 var->bestrootredcost = rootredcost;
13341 var->bestrootlpobjval = rootlpobjval;
13342 }
13343 }
13344
13345 /** returns the solution of the variable in the last root node's relaxation, if the root relaxation is not yet
13346 * completely solved, zero is returned
13347 */
13348 SCIP_Real SCIPvarGetRootSol(
13349 SCIP_VAR* var /**< problem variable */
13350 )
13351 {
13352 SCIP_Real rootsol;
13353 int i;
13354
13355 assert(var != NULL);
13356
13357 switch( SCIPvarGetStatus(var) )
13358 {
13359 case SCIP_VARSTATUS_ORIGINAL:
13360 if( var->data.original.transvar == NULL )
13361 return 0.0;
13362 return SCIPvarGetRootSol(var->data.original.transvar);
13363
13364 case SCIP_VARSTATUS_LOOSE:
13365 case SCIP_VARSTATUS_COLUMN:
13366 return var->rootsol;
13367
13368 case SCIP_VARSTATUS_FIXED:
13369 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13370 return var->locdom.lb;
13371
13372 case SCIP_VARSTATUS_AGGREGATED:
13373 assert(!var->donotaggr);
13374 assert(var->data.aggregate.var != NULL);
13375 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
13376 * corresponding infinity value instead of performing an arithmetical transformation (compare method
13377 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
13378 * (or is called by) a public interface method; instead, we only assert that values are finite
13379 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
13380 * positives and negatives if the parameter <numerics/infinity> is modified by the user
13381 */
13382 assert(SCIPvarGetRootSol(var->data.aggregate.var) > -SCIP_DEFAULT_INFINITY);
13383 assert(SCIPvarGetRootSol(var->data.aggregate.var) < +SCIP_DEFAULT_INFINITY);
13384 return var->data.aggregate.scalar * SCIPvarGetRootSol(var->data.aggregate.var) + var->data.aggregate.constant;
13385
13386 case SCIP_VARSTATUS_MULTAGGR:
13387 assert(!var->donotmultaggr);
13388 assert(var->data.multaggr.vars != NULL);
13389 assert(var->data.multaggr.scalars != NULL);
13390 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13391 * assert(var->data.multaggr.nvars >= 2);
13392 */
13393 rootsol = var->data.multaggr.constant;
13394 for( i = 0; i < var->data.multaggr.nvars; ++i )
13395 rootsol += var->data.multaggr.scalars[i] * SCIPvarGetRootSol(var->data.multaggr.vars[i]);
13396 return rootsol;
13397
13398 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13399 assert(var->negatedvar != NULL);
13400 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
13401 assert(var->negatedvar->negatedvar == var);
13402 return var->data.negate.constant - SCIPvarGetRootSol(var->negatedvar);
13403
13404 default:
13405 SCIPerrorMessage("unknown variable status\n");
13406 SCIPABORT();
13407 return SCIP_INVALID; /*lint !e527*/
13408 }
13409 }
13410
13411 /** returns for given variable the reduced cost */
13412 static
13413 SCIP_Real getImplVarRedcost(
13414 SCIP_VAR* var, /**< problem variable */
13415 SCIP_SET* set, /**< global SCIP settings */
13416 SCIP_Bool varfixing, /**< FALSE if for x == 0, TRUE for x == 1 */
13417 SCIP_STAT* stat, /**< problem statistics */
13418 SCIP_LP* lp /**< current LP data */
13419 )
13420 {
13421 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
13422 {
13423 SCIP_COL* col;
13424 SCIP_Real primsol;
13425 SCIP_BASESTAT basestat;
13426 SCIP_Bool lpissolbasic;
13427
13428 col = SCIPvarGetCol(var);
13429 assert(col != NULL);
13430
13431 basestat = SCIPcolGetBasisStatus(col);
13432 lpissolbasic = SCIPlpIsSolBasic(lp);
13433 primsol = SCIPcolGetPrimsol(col);
13434
13435 if( (lpissolbasic && (basestat == SCIP_BASESTAT_LOWER || basestat == SCIP_BASESTAT_UPPER)) ||
13436 (!lpissolbasic && (SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol) || SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol))) )
13437 {
13438 SCIP_Real redcost = SCIPcolGetRedcost(col, stat, lp);
13439
13440 assert(((!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol)) ||
13441 (lpissolbasic && basestat == SCIP_BASESTAT_LOWER)) ? (!SCIPsetIsDualfeasNegative(set, redcost) ||
13442 SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var))) : TRUE);
13443 assert(((!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol)) ||
13444 (lpissolbasic && basestat == SCIP_BASESTAT_UPPER)) ? (!SCIPsetIsDualfeasPositive(set, redcost) ||
13445 SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var))) : TRUE);
13446
13447 if( (varfixing && ((lpissolbasic && basestat == SCIP_BASESTAT_LOWER) ||
13448 (!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol)))) ||
13449 (!varfixing && ((lpissolbasic && basestat == SCIP_BASESTAT_UPPER) ||
13450 (!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol)))) )
13451 return redcost;
13452 else
13453 return 0.0;
13454 }
13455
13456 return 0.0;
13457 }
13458
13459 return 0.0;
13460 }
13461
13462 #define MAX_CLIQUELENGTH 50
13463 /** returns for the given binary variable the reduced cost which are given by the variable itself and its implication if
13464 * the binary variable is fixed to the given value
13465 */
13466 SCIP_Real SCIPvarGetImplRedcost(
13467 SCIP_VAR* var, /**< problem variable */
13468 SCIP_SET* set, /**< global SCIP settings */
13469 SCIP_Bool varfixing, /**< FALSE if for x == 0, TRUE for x == 1 */
13470 SCIP_STAT* stat, /**< problem statistics */
13471 SCIP_PROB* prob, /**< transformed problem, or NULL */
13472 SCIP_LP* lp /**< current LP data */
13473 )
13474 {
13475 SCIP_Real implredcost;
13476 int ncliques;
13477 int nvars;
13478
13479 assert(SCIPvarIsBinary(var));
13480 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
13481
13482 /* get reduced cost of given variable */
13483 implredcost = getImplVarRedcost(var, set, varfixing, stat, lp);
13484
13485 #ifdef SCIP_MORE_DEBUG
13486 SCIPsetDebugMsg(set, "variable <%s> itself has reduced cost of %g\n", SCIPvarGetName(var), implredcost);
13487 #endif
13488
13489 /* the following algorithm is expensive */
13490 ncliques = SCIPvarGetNCliques(var, varfixing);
13491
13492 if( ncliques > 0 )
13493 {
13494 SCIP_CLIQUE** cliques;
13495 SCIP_CLIQUE* clique;
13496 SCIP_VAR** clqvars;
13497 SCIP_VAR** probvars;
13498 SCIP_VAR* clqvar;
13499 SCIP_Bool* clqvalues;
13500 int* entries;
13501 int* ids;
13502 SCIP_Real redcost;
13503 SCIP_Bool cleanedup;
13504 int nclqvars;
13505 int nentries;
13506 int nids;
13507 int id;
13508 int c;
13509 int v;
13510
13511 assert(prob != NULL);
13512 assert(SCIPprobIsTransformed(prob));
13513
13514 nentries = SCIPprobGetNVars(prob) - SCIPprobGetNContVars(prob) + 1;
13515
13516 SCIP_CALL_ABORT( SCIPsetAllocBufferArray(set, &ids, nentries) );
13517 nids = 0;
13518 SCIP_CALL_ABORT( SCIPsetAllocCleanBufferArray(set, &entries, nentries) );
13519
13520 cliques = SCIPvarGetCliques(var, varfixing);
13521 assert(cliques != NULL);
13522
13523 for( c = ncliques - 1; c >= 0; --c )
13524 {
13525 clique = cliques[c];
13526 assert(clique != NULL);
13527 nclqvars = SCIPcliqueGetNVars(clique);
13528 assert(nclqvars > 0);
13529
13530 if( nclqvars > MAX_CLIQUELENGTH )
13531 continue;
13532
13533 clqvars = SCIPcliqueGetVars(clique);
13534 clqvalues = SCIPcliqueGetValues(clique);
13535 assert(clqvars != NULL);
13536 assert(clqvalues != NULL);
13537
13538 cleanedup = SCIPcliqueIsCleanedUp(clique);
13539
13540 for( v = nclqvars - 1; v >= 0; --v )
13541 {
13542 clqvar = clqvars[v];
13543 assert(clqvar != NULL);
13544
13545 /* ignore binary variable which are fixed */
13546 if( clqvar != var && (cleanedup || SCIPvarIsActive(clqvar)) &&
13547 (SCIPvarGetLbLocal(clqvar) < 0.5 && SCIPvarGetUbLocal(clqvar) > 0.5) )
13548 {
13549 int probindex = SCIPvarGetProbindex(clqvar) + 1;
13550 assert(0 < probindex && probindex < nentries);
13551
13552 #if 0
13553 /* check that the variable was not yet visited or does not appear with two contradicting implications, ->
13554 * can appear since there is no guarantee that all these infeasible bounds were found
13555 */
13556 assert(!entries[probindex] || entries[probindex] == (clqvalues[v] ? probindex : -probindex));
13557 #endif
13558 if( entries[probindex] == 0 )
13559 {
13560 ids[nids] = probindex;
13561 ++nids;
13562
13563 /* mark variable as visited */
13564 entries[probindex] = (clqvalues[v] ? probindex : -probindex);
13565 }
13566 }
13567 }
13568 }
13569
13570 probvars = SCIPprobGetVars(prob);
13571 assert(probvars != NULL);
13572
13573 /* add all implied reduced cost */
13574 for( v = nids - 1; v >= 0; --v )
13575 {
13576 id = ids[v];
13577 assert(0 < id && id < nentries);
13578 assert(entries[id] != 0);
13579 assert(probvars[id - 1] != NULL);
13580 assert(SCIPvarIsActive(probvars[id - 1]));
13581 assert(SCIPvarIsBinary(probvars[id - 1]));
13582 assert(SCIPvarGetLbLocal(probvars[id - 1]) < 0.5 && SCIPvarGetUbLocal(probvars[id - 1]) > 0.5);
13583
13584 if( (entries[id] > 0) != varfixing )
13585 redcost = getImplVarRedcost(probvars[id - 1], set, (entries[id] < 0), stat, lp);
13586 else
13587 redcost = -getImplVarRedcost(probvars[id - 1], set, (entries[id] < 0), stat, lp);
13588
13589 if( (varfixing && SCIPsetIsDualfeasPositive(set, redcost)) || (!varfixing && SCIPsetIsDualfeasNegative(set, redcost)) )
13590 implredcost += redcost;
13591
13592 /* reset entries clear buffer array */
13593 entries[id] = 0;
13594 }
13595
13596 SCIPsetFreeCleanBufferArray(set, &entries);
13597 SCIPsetFreeBufferArray(set, &ids);
13598 }
13599
13600 #ifdef SCIP_MORE_DEBUG
13601 SCIPsetDebugMsg(set, "variable <%s> incl. cliques (%d) has implied reduced cost of %g\n", SCIPvarGetName(var), ncliques,
13602 implredcost);
13603 #endif
13604
13605 /* collect non-binary implication information */
13606 nvars = SCIPimplicsGetNImpls(var->implics, varfixing);
13607
13608 if( nvars > 0 )
13609 {
13610 SCIP_VAR** vars;
13611 SCIP_VAR* implvar;
13612 SCIP_COL* col;
13613 SCIP_Real* bounds;
13614 SCIP_BOUNDTYPE* boundtypes;
13615 SCIP_Real redcost;
13616 SCIP_Real lb;
13617 SCIP_Real ub;
13618 SCIP_Bool lpissolbasic;
13619 int v;
13620
13621 vars = SCIPimplicsGetVars(var->implics, varfixing);
13622 boundtypes = SCIPimplicsGetTypes(var->implics, varfixing);
13623 bounds = SCIPimplicsGetBounds(var->implics, varfixing);
13624 lpissolbasic = SCIPlpIsSolBasic(lp);
13625
13626 for( v = nvars - 1; v >= 0; --v )
13627 {
13628 implvar = vars[v];
13629 assert(implvar != NULL);
13630
13631 lb = SCIPvarGetLbLocal(implvar);
13632 ub = SCIPvarGetUbLocal(implvar);
13633
13634 /* ignore binary variable which are fixed or not of column status */
13635 if( SCIPvarGetStatus(implvar) != SCIP_VARSTATUS_COLUMN || SCIPsetIsFeasEQ(set, lb, ub) )
13636 continue;
13637
13638 col = SCIPvarGetCol(implvar);
13639 assert(col != NULL);
13640 redcost = 0.0;
13641
13642 /* solved lp with basis information or not? */
13643 if( lpissolbasic )
13644 {
13645 SCIP_BASESTAT basestat = SCIPcolGetBasisStatus(col);
13646
13647 /* check if the implication is not not yet applied */
13648 if( basestat == SCIP_BASESTAT_LOWER && boundtypes[v] == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGT(set, bounds[v], lb) )
13649 {
13650 redcost = SCIPcolGetRedcost(col, stat, lp);
13651 assert(!SCIPsetIsDualfeasNegative(set, redcost));
13652
13653 if( !varfixing )
13654 redcost *= (lb - bounds[v]);
13655 else
13656 redcost *= (bounds[v] - lb);
13657 }
13658 else if( basestat == SCIP_BASESTAT_UPPER && boundtypes[v] == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLT(set, bounds[v], ub) )
13659 {
13660 redcost = SCIPcolGetRedcost(col, stat, lp);
13661 assert(!SCIPsetIsDualfeasPositive(set, redcost));
13662
13663 if( varfixing )
13664 redcost *= (bounds[v] - ub);
13665 else
13666 redcost *= (ub - bounds[v]);
13667 }
13668 }
13669 else
13670 {
13671 SCIP_Real primsol = SCIPcolGetPrimsol(col);
13672
13673 /* check if the implication is not not yet applied */
13674 if( boundtypes[v] == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasEQ(set, lb, primsol) && SCIPsetIsFeasGT(set, bounds[v], lb) )
13675 {
13676 redcost = SCIPcolGetRedcost(col, stat, lp);
13677 assert(!SCIPsetIsDualfeasNegative(set, redcost));
13678
13679 if( varfixing )
13680 redcost *= (lb - bounds[v]);
13681 else
13682 redcost *= (bounds[v] - lb);
13683 }
13684 else if( boundtypes[v] == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasEQ(set, ub, primsol) && SCIPsetIsFeasLT(set, bounds[v], ub) )
13685 {
13686 redcost = SCIPcolGetRedcost(col, stat, lp);
13687 assert(!SCIPsetIsDualfeasPositive(set, redcost));
13688
13689 if( varfixing )
13690 redcost *= (bounds[v] - ub);
13691 else
13692 redcost *= (ub - bounds[v]);
13693 }
13694 }
13695
13696 /* improve implied reduced cost */
13697 if( (varfixing && SCIPsetIsDualfeasPositive(set, redcost)) || (!varfixing && SCIPsetIsDualfeasNegative(set, redcost)) )
13698 implredcost += redcost;
13699 }
13700 }
13701
13702 #ifdef SCIP_MORE_DEBUG
13703 SCIPsetDebugMsg(set, "variable <%s> incl. cliques (%d) and implications (%d) has implied reduced cost of %g\n",
13704 SCIPvarGetName(var), ncliques, nvars, implredcost);
13705 #endif
13706
13707 return implredcost;
13708 }
13709
13710 /** returns the best solution (w.r.t. root reduced cost propagation) of the variable in the root node's relaxation, if
13711 * the root relaxation is not yet completely solved, zero is returned
13712 */
13713 SCIP_Real SCIPvarGetBestRootSol(
13714 SCIP_VAR* var /**< problem variable */
13715 )
13716 {
13717 SCIP_Real rootsol;
13718 int i;
13719
13720 assert(var != NULL);
13721
13722 switch( SCIPvarGetStatus(var) )
13723 {
13724 case SCIP_VARSTATUS_ORIGINAL:
13725 if( var->data.original.transvar == NULL )
13726 return 0.0;
13727 return SCIPvarGetBestRootSol(var->data.original.transvar);
13728
13729 case SCIP_VARSTATUS_LOOSE:
13730 case SCIP_VARSTATUS_COLUMN:
13731 return var->bestrootsol;
13732
13733 case SCIP_VARSTATUS_FIXED:
13734 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13735 return var->locdom.lb;
13736
13737 case SCIP_VARSTATUS_AGGREGATED:
13738 assert(!var->donotaggr);
13739 assert(var->data.aggregate.var != NULL);
13740 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
13741 * corresponding infinity value instead of performing an arithmetical transformation (compare method
13742 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
13743 * (or is called by) a public interface method; instead, we only assert that values are finite
13744 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
13745 * positives and negatives if the parameter <numerics/infinity> is modified by the user
13746 */
13747 assert(SCIPvarGetBestRootSol(var->data.aggregate.var) > -SCIP_DEFAULT_INFINITY);
13748 assert(SCIPvarGetBestRootSol(var->data.aggregate.var) < +SCIP_DEFAULT_INFINITY);
13749 return var->data.aggregate.scalar * SCIPvarGetBestRootSol(var->data.aggregate.var) + var->data.aggregate.constant;
13750
13751 case SCIP_VARSTATUS_MULTAGGR:
13752 assert(!var->donotmultaggr);
13753 assert(var->data.multaggr.vars != NULL);
13754 assert(var->data.multaggr.scalars != NULL);
13755 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13756 * assert(var->data.multaggr.nvars >= 2);
13757 */
13758 rootsol = var->data.multaggr.constant;
13759 for( i = 0; i < var->data.multaggr.nvars; ++i )
13760 rootsol += var->data.multaggr.scalars[i] * SCIPvarGetBestRootSol(var->data.multaggr.vars[i]);
13761 return rootsol;
13762
13763 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13764 assert(var->negatedvar != NULL);
13765 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
13766 assert(var->negatedvar->negatedvar == var);
13767 return var->data.negate.constant - SCIPvarGetBestRootSol(var->negatedvar);
13768
13769 default:
13770 SCIPerrorMessage("unknown variable status\n");
13771 SCIPABORT();
13772 return 0.0; /*lint !e527*/
13773 }
13774 }
13775
13776 /** returns the best reduced costs (w.r.t. root reduced cost propagation) of the variable in the root node's relaxation,
13777 * if the root relaxation is not yet completely solved, or the variable was no column of the root LP, SCIP_INVALID is
13778 * returned
13779 */
13780 SCIP_Real SCIPvarGetBestRootRedcost(
13781 SCIP_VAR* var /**< problem variable */
13782 )
13783 {
13784 assert(var != NULL);
13785
13786 switch( SCIPvarGetStatus(var) )
13787 {
13788 case SCIP_VARSTATUS_ORIGINAL:
13789 if( var->data.original.transvar == NULL )
13790 return SCIP_INVALID;
13791 return SCIPvarGetBestRootRedcost(var->data.original.transvar);
13792
13793 case SCIP_VARSTATUS_LOOSE:
13794 case SCIP_VARSTATUS_COLUMN:
13795 return var->bestrootredcost;
13796
13797 case SCIP_VARSTATUS_FIXED:
13798 case SCIP_VARSTATUS_AGGREGATED:
13799 case SCIP_VARSTATUS_MULTAGGR:
13800 case SCIP_VARSTATUS_NEGATED:
13801 return 0.0;
13802
13803 default:
13804 SCIPerrorMessage("unknown variable status\n");
13805 SCIPABORT();
13806 return 0.0; /*lint !e527*/
13807 }
13808 }
13809
13810 /** returns the best objective value (w.r.t. root reduced cost propagation) of the root LP which belongs the root
13811 * reduced cost which is accessible via SCIPvarGetRootRedcost() or the variable was no column of the root LP,
13812 * SCIP_INVALID is returned
13813 */
13814 SCIP_Real SCIPvarGetBestRootLPObjval(
13815 SCIP_VAR* var /**< problem variable */
13816 )
13817 {
13818 assert(var != NULL);
13819
13820 switch( SCIPvarGetStatus(var) )
13821 {
13822 case SCIP_VARSTATUS_ORIGINAL:
13823 if( var->data.original.transvar == NULL )
13824 return SCIP_INVALID;
13825 return SCIPvarGetBestRootLPObjval(var->data.original.transvar);
13826
13827 case SCIP_VARSTATUS_LOOSE:
13828 case SCIP_VARSTATUS_COLUMN:
13829 return var->bestrootlpobjval;
13830
13831 case SCIP_VARSTATUS_FIXED:
13832 case SCIP_VARSTATUS_AGGREGATED:
13833 case SCIP_VARSTATUS_MULTAGGR:
13834 case SCIP_VARSTATUS_NEGATED:
13835 return SCIP_INVALID;
13836
13837 default:
13838 SCIPerrorMessage("unknown variable status\n");
13839 SCIPABORT();
13840 return SCIP_INVALID; /*lint !e527*/
13841 }
13842 }
13843
13844 /** set the given solution as the best root solution w.r.t. root reduced cost propagation in the variables */
13845 void SCIPvarSetBestRootSol(
13846 SCIP_VAR* var, /**< problem variable */
13847 SCIP_Real rootsol, /**< root solution value */
13848 SCIP_Real rootredcost, /**< root reduced cost */
13849 SCIP_Real rootlpobjval /**< objective value of the root LP */
13850 )
13851 {
13852 assert(var != NULL);
13853
13854 var->bestrootsol = rootsol;
13855 var->bestrootredcost = rootredcost;
13856 var->bestrootlpobjval = rootlpobjval;
13857 }
13858
13859 /** stores the solution value as relaxation solution in the problem variable */
13860 SCIP_RETCODE SCIPvarSetRelaxSol(
13861 SCIP_VAR* var, /**< problem variable */
13862 SCIP_SET* set, /**< global SCIP settings */
13863 SCIP_RELAXATION* relaxation, /**< global relaxation data */
13864 SCIP_Real solval, /**< solution value in the current relaxation solution */
13865 SCIP_Bool updateobj /**< should the objective value be updated? */
13866 )
13867 {
13868 assert(var != NULL);
13869 assert(relaxation != NULL);
13870 assert(set != NULL);
13871 assert(var->scip == set->scip);
13872
13873 /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */
13874 switch( SCIPvarGetStatus(var) )
13875 {
13876 case SCIP_VARSTATUS_ORIGINAL:
13877 SCIP_CALL( SCIPvarSetRelaxSol(var->data.original.transvar, set, relaxation, solval, updateobj) );
13878 break;
13879
13880 case SCIP_VARSTATUS_LOOSE:
13881 case SCIP_VARSTATUS_COLUMN:
13882 if( updateobj )
13883 SCIPrelaxationSolObjAdd(relaxation, var->obj * (solval - var->relaxsol));
13884 var->relaxsol = solval;
13885 break;
13886
13887 case SCIP_VARSTATUS_FIXED:
13888 if( !SCIPsetIsEQ(set, solval, var->glbdom.lb) )
13889 {
13890 SCIPerrorMessage("cannot set relaxation solution value for variable <%s> fixed to %.15g to different value %.15g\n",
13891 SCIPvarGetName(var), var->glbdom.lb, solval);
13892 return SCIP_INVALIDDATA;
13893 }
13894 break;
13895
13896 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
13897 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
13898 SCIP_CALL( SCIPvarSetRelaxSol(var->data.aggregate.var, set, relaxation,
13899 (solval - var->data.aggregate.constant)/var->data.aggregate.scalar, updateobj) );
13900 break;
13901 case SCIP_VARSTATUS_MULTAGGR:
13902 SCIPerrorMessage("cannot set solution value for multiple aggregated variable\n");
13903 return SCIP_INVALIDDATA;
13904
13905 case SCIP_VARSTATUS_NEGATED:
13906 SCIP_CALL( SCIPvarSetRelaxSol(var->negatedvar, set, relaxation, var->data.negate.constant - solval, updateobj) );
13907 break;
13908
13909 default:
13910 SCIPerrorMessage("unknown variable status\n");
13911 return SCIP_INVALIDDATA;
13912 }
13913
13914 return SCIP_OKAY;
13915 }
13916
13917 /** returns the solution value of the problem variable in the relaxation solution
13918 *
13919 * @todo Inline this function - similar to SCIPvarGetLPSol_rec.
13920 */
13921 SCIP_Real SCIPvarGetRelaxSol(
13922 SCIP_VAR* var, /**< problem variable */
13923 SCIP_SET* set /**< global SCIP settings */
13924 )
13925 {
13926 SCIP_Real solvalsum;
13927 SCIP_Real solval;
13928 int i;
13929
13930 assert(var != NULL);
13931 assert(set != NULL);
13932 assert(var->scip == set->scip);
13933
13934 /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */
13935 switch( SCIPvarGetStatus(var) )
13936 {
13937 case SCIP_VARSTATUS_ORIGINAL:
13938 return SCIPvarGetRelaxSol(var->data.original.transvar, set);
13939
13940 case SCIP_VARSTATUS_LOOSE:
13941 case SCIP_VARSTATUS_COLUMN:
13942 return var->relaxsol;
13943
13944 case SCIP_VARSTATUS_FIXED:
13945 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var)); /*lint !e777*/
13946 assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var)); /*lint !e777*/
13947 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var)); /*lint !e777*/
13948 return SCIPvarGetLbGlobal(var);
13949
13950 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
13951 solval = SCIPvarGetRelaxSol(var->data.aggregate.var, set);
13952 if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) )
13953 {
13954 if( var->data.aggregate.scalar * solval > 0.0 )
13955 return SCIPsetInfinity(set);
13956 if( var->data.aggregate.scalar * solval < 0.0 )
13957 return -SCIPsetInfinity(set);
13958 }
13959 return var->data.aggregate.scalar * solval + var->data.aggregate.constant;
13960
13961 case SCIP_VARSTATUS_MULTAGGR:
13962 solvalsum = var->data.multaggr.constant;
13963 for( i = 0; i < var->data.multaggr.nvars; ++i )
13964 {
13965 solval = SCIPvarGetRelaxSol(var->data.multaggr.vars[i], set);
13966 if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) )
13967 {
13968 if( var->data.multaggr.scalars[i] * solval > 0.0 )
13969 return SCIPsetInfinity(set);
13970 if( var->data.multaggr.scalars[i] * solval < 0.0 )
13971 return -SCIPsetInfinity(set);
13972 }
13973 solvalsum += var->data.multaggr.scalars[i] * solval;
13974 }
13975 return solvalsum;
13976
13977 case SCIP_VARSTATUS_NEGATED:
13978 solval = SCIPvarGetRelaxSol(var->negatedvar, set);
13979 if( SCIPsetIsInfinity(set, solval) )
13980 return -SCIPsetInfinity(set);
13981 if( SCIPsetIsInfinity(set, -solval) )
13982 return SCIPsetInfinity(set);
13983 return var->data.negate.constant - solval;
13984
13985 default:
13986 SCIPerrorMessage("unknown variable status\n");
13987 SCIPABORT();
13988 return SCIP_INVALID; /*lint !e527*/
13989 }
13990 }
13991
13992 /** returns the solution value of the transformed problem variable in the relaxation solution */
13993 SCIP_Real SCIPvarGetRelaxSolTransVar(
13994 SCIP_VAR* var /**< problem variable */
13995 )
13996 {
13997 assert(var != NULL);
13998 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
13999
14000 return var->relaxsol;
14001 }
14002
14003 /** stores the solution value as NLP solution in the problem variable */
14004 SCIP_RETCODE SCIPvarSetNLPSol(
14005 SCIP_VAR* var, /**< problem variable */
14006 SCIP_SET* set, /**< global SCIP settings */
14007 SCIP_Real solval /**< solution value in the current NLP solution */
14008 )
14009 {
14010 assert(var != NULL);
14011 assert(set != NULL);
14012 assert(var->scip == set->scip);
14013
14014 /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */
14015 switch( SCIPvarGetStatus(var) )
14016 {
14017 case SCIP_VARSTATUS_ORIGINAL:
14018 SCIP_CALL( SCIPvarSetNLPSol(var->data.original.transvar, set, solval) );
14019 break;
14020
14021 case SCIP_VARSTATUS_LOOSE:
14022 case SCIP_VARSTATUS_COLUMN:
14023 var->nlpsol = solval;
14024 break;
14025
14026 case SCIP_VARSTATUS_FIXED:
14027 if( !SCIPsetIsEQ(set, solval, var->glbdom.lb) )
14028 {
14029 SCIPerrorMessage("cannot set NLP solution value for variable <%s> fixed to %.15g to different value %.15g\n",
14030 SCIPvarGetName(var), var->glbdom.lb, solval);
14031 SCIPABORT();
14032 return SCIP_INVALIDCALL; /*lint !e527*/
14033 }
14034 break;
14035
14036 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
14037 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
14038 SCIP_CALL( SCIPvarSetNLPSol(var->data.aggregate.var, set, (solval - var->data.aggregate.constant)/var->data.aggregate.scalar) );
14039 break;
14040
14041 case SCIP_VARSTATUS_MULTAGGR:
14042 SCIPerrorMessage("cannot set solution value for multiple aggregated variable\n");
14043 SCIPABORT();
14044 return SCIP_INVALIDCALL; /*lint !e527*/
14045
14046 case SCIP_VARSTATUS_NEGATED:
14047 SCIP_CALL( SCIPvarSetNLPSol(var->negatedvar, set, var->data.negate.constant - solval) );
14048 break;
14049
14050 default:
14051 SCIPerrorMessage("unknown variable status\n");
14052 SCIPABORT();
14053 return SCIP_ERROR; /*lint !e527*/
14054 }
14055
14056 return SCIP_OKAY;
14057 }
14058
14059 /** returns a weighted average solution value of the variable in all feasible primal solutions found so far */
14060 SCIP_Real SCIPvarGetAvgSol(
14061 SCIP_VAR* var /**< problem variable */
14062 )
14063 {
14064 SCIP_Real avgsol;
14065 int i;
14066
14067 assert(var != NULL);
14068
14069 switch( SCIPvarGetStatus(var) )
14070 {
14071 case SCIP_VARSTATUS_ORIGINAL:
14072 if( var->data.original.transvar == NULL )
14073 return 0.0;
14074 return SCIPvarGetAvgSol(var->data.original.transvar);
14075
14076 case SCIP_VARSTATUS_LOOSE:
14077 case SCIP_VARSTATUS_COLUMN:
14078 avgsol = var->primsolavg;
14079 avgsol = MAX(avgsol, var->glbdom.lb);
14080 avgsol = MIN(avgsol, var->glbdom.ub);
14081 return avgsol;
14082
14083 case SCIP_VARSTATUS_FIXED:
14084 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
14085 return var->locdom.lb;
14086
14087 case SCIP_VARSTATUS_AGGREGATED:
14088 assert(!var->donotaggr);
14089 assert(var->data.aggregate.var != NULL);
14090 return var->data.aggregate.scalar * SCIPvarGetAvgSol(var->data.aggregate.var)
14091 + var->data.aggregate.constant;
14092
14093 case SCIP_VARSTATUS_MULTAGGR:
14094 assert(!var->donotmultaggr);
14095 assert(var->data.multaggr.vars != NULL);
14096 assert(var->data.multaggr.scalars != NULL);
14097 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
14098 * assert(var->data.multaggr.nvars >= 2);
14099 */
14100 avgsol = var->data.multaggr.constant;
14101 for( i = 0; i < var->data.multaggr.nvars; ++i )
14102 avgsol += var->data.multaggr.scalars[i] * SCIPvarGetAvgSol(var->data.multaggr.vars[i]);
14103 return avgsol;
14104
14105 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
14106 assert(var->negatedvar != NULL);
14107 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
14108 assert(var->negatedvar->negatedvar == var);
14109 return var->data.negate.constant - SCIPvarGetAvgSol(var->negatedvar);
14110
14111 default:
14112 SCIPerrorMessage("unknown variable status\n");
14113 SCIPABORT();
14114 return 0.0; /*lint !e527*/
14115 }
14116 }
14117
14118 /** returns solution value and index of variable lower bound that is closest to the variable's value in the given primal solution
14119 * or current LP solution if no primal solution is given; returns an index of -1 if no variable lower bound is available
14120 */
14121 void SCIPvarGetClosestVlb(
14122 SCIP_VAR* var, /**< active problem variable */
14123 SCIP_SOL* sol, /**< primal solution, or NULL for LP solution */
14124 SCIP_SET* set, /**< global SCIP settings */
14125 SCIP_STAT* stat, /**< problem statistics */
14126 SCIP_Real* closestvlb, /**< pointer to store the value of the closest variable lower bound */
14127 int* closestvlbidx /**< pointer to store the index of the closest variable lower bound */
14128 )
14129 {
14130 int nvlbs;
14131
14132 assert(var != NULL);
14133 assert(stat != NULL);
14134 assert(set != NULL);
14135 assert(var->scip == set->scip);
14136 assert(closestvlb != NULL);
14137 assert(closestvlbidx != NULL);
14138
14139 *closestvlbidx = -1;
14140 *closestvlb = SCIP_REAL_MIN;
14141
14142 nvlbs = SCIPvarGetNVlbs(var);
14143 if( nvlbs > 0 )
14144 {
14145 SCIP_VAR** vlbvars;
14146 SCIP_Real* vlbcoefs;
14147 SCIP_Real* vlbconsts;
14148 int i;
14149
14150 vlbvars = SCIPvarGetVlbVars(var);
14151 vlbcoefs = SCIPvarGetVlbCoefs(var);
14152 vlbconsts = SCIPvarGetVlbConstants(var);
14153
14154 /* check for cached values */
14155 if( var->closestvblpcount == stat->lpcount && var->closestvlbidx != -1 && sol == NULL)
14156 {
14157 i = var->closestvlbidx;
14158 assert(0 <= i && i < nvlbs);
14159 assert(SCIPvarIsActive(vlbvars[i]));
14160 *closestvlbidx = i;
14161 *closestvlb = vlbcoefs[i] * SCIPvarGetLPSol(vlbvars[i]) + vlbconsts[i];
14162 }
14163 else
14164 {
14165 /* search best VUB */
14166 for( i = 0; i < nvlbs; i++ )
14167 {
14168 if( SCIPvarIsActive(vlbvars[i]) )
14169 {
14170 SCIP_Real vlbsol;
14171
14172 vlbsol = vlbcoefs[i] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[i]) : SCIPsolGetVal(sol, set, stat, vlbvars[i])) + vlbconsts[i];
14173 if( vlbsol > *closestvlb )
14174 {
14175 *closestvlb = vlbsol;
14176 *closestvlbidx = i;
14177 }
14178 }
14179 }
14180
14181 if( sol == NULL )
14182 {
14183 /* update cached value */
14184 if( var->closestvblpcount != stat->lpcount )
14185 var->closestvubidx = -1;
14186 var->closestvlbidx = *closestvlbidx;
14187 var->closestvblpcount = stat->lpcount;
14188 }
14189 }
14190 }
14191 }
14192
14193 /** returns solution value and index of variable upper bound that is closest to the variable's value in the given primal solution;
14194 * or current LP solution if no primal solution is given; returns an index of -1 if no variable upper bound is available
14195 */
14196 void SCIPvarGetClosestVub(
14197 SCIP_VAR* var, /**< active problem variable */
14198 SCIP_SOL* sol, /**< primal solution, or NULL for LP solution */
14199 SCIP_SET* set, /**< global SCIP settings */
14200 SCIP_STAT* stat, /**< problem statistics */
14201 SCIP_Real* closestvub, /**< pointer to store the value of the closest variable upper bound */
14202 int* closestvubidx /**< pointer to store the index of the closest variable upper bound */
14203 )
14204 {
14205 int nvubs;
14206
14207 assert(var != NULL);
14208 assert(set != NULL);
14209 assert(var->scip == set->scip);
14210 assert(closestvub != NULL);
14211 assert(closestvubidx != NULL);
14212
14213 *closestvubidx = -1;
14214 *closestvub = SCIP_REAL_MAX;
14215
14216 nvubs = SCIPvarGetNVubs(var);
14217 if( nvubs > 0 )
14218 {
14219 SCIP_VAR** vubvars;
14220 SCIP_Real* vubcoefs;
14221 SCIP_Real* vubconsts;
14222 int i;
14223
14224 vubvars = SCIPvarGetVubVars(var);
14225 vubcoefs = SCIPvarGetVubCoefs(var);
14226 vubconsts = SCIPvarGetVubConstants(var);
14227
14228 /* check for cached values */
14229 if( var->closestvblpcount == stat->lpcount && var->closestvubidx != -1 && sol == NULL)
14230 {
14231 i = var->closestvubidx;
14232 assert(0 <= i && i < nvubs);
14233 assert(SCIPvarIsActive(vubvars[i]));
14234 *closestvubidx = i;
14235 *closestvub = vubcoefs[i] * SCIPvarGetLPSol(vubvars[i]) + vubconsts[i];
14236 }
14237 else
14238 {
14239 /* search best VUB */
14240 for( i = 0; i < nvubs; i++ )
14241 {
14242 if( SCIPvarIsActive(vubvars[i]) )
14243 {
14244 SCIP_Real vubsol;
14245
14246 vubsol = vubcoefs[i] * (sol == NULL ? SCIPvarGetLPSol(vubvars[i]) : SCIPsolGetVal(sol, set, stat, vubvars[i])) + vubconsts[i];
14247 if( vubsol < *closestvub )
14248 {
14249 *closestvub = vubsol;
14250 *closestvubidx = i;
14251 }
14252 }
14253 }
14254
14255 if( sol == NULL )
14256 {
14257 /* update cached value */
14258 if( var->closestvblpcount != stat->lpcount )
14259 var->closestvlbidx = -1;
14260 var->closestvubidx = *closestvubidx;
14261 var->closestvblpcount = stat->lpcount;
14262 }
14263 }
14264 }
14265 }
14266
14267 /** resolves variable to columns and adds them with the coefficient to the row */
14268 SCIP_RETCODE SCIPvarAddToRow(
14269 SCIP_VAR* var, /**< problem variable */
14270 BMS_BLKMEM* blkmem, /**< block memory */
14271 SCIP_SET* set, /**< global SCIP settings */
14272 SCIP_STAT* stat, /**< problem statistics */
14273 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
14274 SCIP_PROB* prob, /**< problem data */
14275 SCIP_LP* lp, /**< current LP data */
14276 SCIP_ROW* row, /**< LP row */
14277 SCIP_Real val /**< value of coefficient */
14278 )
14279 {
14280 int i;
14281
14282 assert(var != NULL);
14283 assert(set != NULL);
14284 assert(var->scip == set->scip);
14285 assert(row != NULL);
14286 assert(!SCIPsetIsInfinity(set, REALABS(val)));
14287
|
(1) Event cond_false: |
Condition "0", taking false branch. |
|
(2) Event loop_end: |
Reached end of loop. |
14288 SCIPsetDebugMsg(set, "adding coefficient %g<%s> to row <%s>\n", val, var->name, row->name);
14289
|
(3) Event cond_false: |
Condition "fabs(val) <= set->num_epsilon", taking false branch. |
14290 if ( SCIPsetIsZero(set, val) )
|
(4) Event if_end: |
End of if statement. |
14291 return SCIP_OKAY;
14292
|
(5) Event deref_parm: |
Directly dereferencing parameter "var". |
14293 switch( SCIPvarGetStatus(var) )
14294 {
14295 case SCIP_VARSTATUS_ORIGINAL:
14296 if( var->data.original.transvar == NULL )
14297 {
14298 SCIPerrorMessage("cannot add untransformed original variable <%s> to LP row <%s>\n", var->name, row->name);
14299 return SCIP_INVALIDDATA;
14300 }
14301 SCIP_CALL( SCIPvarAddToRow(var->data.original.transvar, blkmem, set, stat, eventqueue, prob, lp, row, val) );
14302 return SCIP_OKAY;
14303
14304 case SCIP_VARSTATUS_LOOSE:
14305 /* add globally fixed variables as constant */
14306 if( SCIPsetIsEQ(set, var->glbdom.lb, var->glbdom.ub) )
14307 {
14308 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, val * var->glbdom.lb) );
14309 return SCIP_OKAY;
14310 }
14311 /* convert loose variable into column */
14312 SCIP_CALL( SCIPvarColumn(var, blkmem, set, stat, prob, lp) );
14313 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
14314 /*lint -fallthrough*/
14315
14316 case SCIP_VARSTATUS_COLUMN:
14317 assert(var->data.col != NULL);
14318 assert(var->data.col->var == var);
14319 SCIP_CALL( SCIProwIncCoef(row, blkmem, set, eventqueue, lp, var->data.col, val) );
14320 return SCIP_OKAY;
14321
14322 case SCIP_VARSTATUS_FIXED:
14323 assert(var->glbdom.lb == var->glbdom.ub); /*lint !e777*/
14324 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
14325 assert(var->locdom.lb == var->glbdom.lb); /*lint !e777*/
14326 assert(!SCIPsetIsInfinity(set, REALABS(var->locdom.lb)));
14327 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, val * var->locdom.lb) );
14328 return SCIP_OKAY;
14329
14330 case SCIP_VARSTATUS_AGGREGATED:
14331 assert(!var->donotaggr);
14332 assert(var->data.aggregate.var != NULL);
14333 SCIP_CALL( SCIPvarAddToRow(var->data.aggregate.var, blkmem, set, stat, eventqueue, prob, lp,
14334 row, var->data.aggregate.scalar * val) );
14335 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.aggregate.constant * val) );
14336 return SCIP_OKAY;
14337
14338 case SCIP_VARSTATUS_MULTAGGR:
14339 assert(!var->donotmultaggr);
14340 assert(var->data.multaggr.vars != NULL);
14341 assert(var->data.multaggr.scalars != NULL);
14342 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
14343 * assert(var->data.multaggr.nvars >= 2);
14344 */
14345 for( i = 0; i < var->data.multaggr.nvars; ++i )
14346 {
14347 SCIP_CALL( SCIPvarAddToRow(var->data.multaggr.vars[i], blkmem, set, stat, eventqueue, prob, lp,
14348 row, var->data.multaggr.scalars[i] * val) );
14349 }
14350 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.multaggr.constant * val) );
14351 return SCIP_OKAY;
14352
14353 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
14354 assert(var->negatedvar != NULL);
14355 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
14356 assert(var->negatedvar->negatedvar == var);
14357 SCIP_CALL( SCIPvarAddToRow(var->negatedvar, blkmem, set, stat, eventqueue, prob, lp, row, -val) );
14358 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.negate.constant * val) );
14359 return SCIP_OKAY;
14360
14361 default:
14362 SCIPerrorMessage("unknown variable status\n");
14363 return SCIP_INVALIDDATA;
14364 }
14365 }
14366
14367 /* optionally, define this compiler flag to write complete variable histories to a file */
14368 #ifdef SCIP_HISTORYTOFILE
14369 SCIP_Longint counter = 0l;
14370 const char* historypath="."; /* allows for user-defined path; use '.' for calling directory of SCIP */
14371 #include "scip/scip.h"
14372 #endif
14373
14374 /** updates the pseudo costs of the given variable and the global pseudo costs after a change of
14375 * "solvaldelta" in the variable's solution value and resulting change of "objdelta" in the in the LP's objective value
14376 */
14377 SCIP_RETCODE SCIPvarUpdatePseudocost(
14378 SCIP_VAR* var, /**< problem variable */
14379 SCIP_SET* set, /**< global SCIP settings */
14380 SCIP_STAT* stat, /**< problem statistics */
14381 SCIP_Real solvaldelta, /**< difference of variable's new LP value - old LP value */
14382 SCIP_Real objdelta, /**< difference of new LP's objective value - old LP's objective value */
14383 SCIP_Real weight /**< weight in (0,1] of this update in pseudo cost sum */
14384 )
14385 {
14386 SCIP_Real oldrootpseudocosts;
14387 assert(var != NULL);
14388 assert(set != NULL);
14389 assert(var->scip == set->scip);
14390 assert(stat != NULL);
14391
14392 /* check if history statistics should be collected for a variable */
14393 if( !stat->collectvarhistory )
14394 return SCIP_OKAY;
14395
14396 switch( SCIPvarGetStatus(var) )
14397 {
14398 case SCIP_VARSTATUS_ORIGINAL:
14399 if( var->data.original.transvar == NULL )
14400 {
14401 SCIPerrorMessage("cannot update pseudo costs of original untransformed variable\n");
14402 return SCIP_INVALIDDATA;
14403 }
14404 SCIP_CALL( SCIPvarUpdatePseudocost(var->data.original.transvar, set, stat, solvaldelta, objdelta, weight) );
14405 return SCIP_OKAY;
14406
14407 case SCIP_VARSTATUS_LOOSE:
14408 case SCIP_VARSTATUS_COLUMN:
14409 /* store old pseudo-costs for root LP best-estimate update */
14410 oldrootpseudocosts = SCIPvarGetMinPseudocostScore(var, stat, set, SCIPvarGetRootSol(var));
14411
14412 /* update history */
14413 SCIPhistoryUpdatePseudocost(var->history, set, solvaldelta, objdelta, weight);
14414 SCIPhistoryUpdatePseudocost(var->historycrun, set, solvaldelta, objdelta, weight);
14415 SCIPhistoryUpdatePseudocost(stat->glbhistory, set, solvaldelta, objdelta, weight);
14416 SCIPhistoryUpdatePseudocost(stat->glbhistorycrun, set, solvaldelta, objdelta, weight);
14417
14418 /* update root LP best-estimate */
14419 SCIP_CALL( SCIPstatUpdateVarRootLPBestEstimate(stat, set, var, oldrootpseudocosts) );
14420
14421 /* append history to file */
14422 #ifdef SCIP_HISTORYTOFILE
14423 {
14424 FILE* f;
14425 char filename[256];
14426 SCIP_NODE* currentnode;
14427 SCIP_NODE* parentnode;
14428 currentnode = SCIPgetFocusNode(set->scip);
14429 parentnode = SCIPnodeGetParent(currentnode);
14430
14431 sprintf(filename, "%s/%s.pse", historypath, SCIPgetProbName(set->scip));
14432 f = fopen(filename, "a");
14433 if( NULL != f )
14434 {
14435 fprintf(f, "%lld %s \t %lld \t %lld \t %lld \t %d \t %15.9f \t %.3f\n",
14436 ++counter,
14437 SCIPvarGetName(var),
14438 SCIPnodeGetNumber(currentnode),
14439 parentnode != NULL ? SCIPnodeGetNumber(parentnode) : -1,
14440 SCIPgetNLPIterations(set->scip),
14441 SCIPgetDepth(set->scip),
14442 objdelta,
14443 solvaldelta);
14444 fclose(f);
14445 }
14446 }
14447 #endif
14448 return SCIP_OKAY;
14449
14450 case SCIP_VARSTATUS_FIXED:
14451 SCIPerrorMessage("cannot update pseudo cost values of a fixed variable\n");
14452 return SCIP_INVALIDDATA;
14453
14454 case SCIP_VARSTATUS_AGGREGATED:
14455 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
14456 SCIP_CALL( SCIPvarUpdatePseudocost(var->data.aggregate.var, set, stat,
14457 solvaldelta/var->data.aggregate.scalar, objdelta, weight) );
14458 return SCIP_OKAY;
14459
14460 case SCIP_VARSTATUS_MULTAGGR:
14461 SCIPerrorMessage("cannot update pseudo cost values of a multi-aggregated variable\n");
14462 return SCIP_INVALIDDATA;
14463
14464 case SCIP_VARSTATUS_NEGATED:
14465 SCIP_CALL( SCIPvarUpdatePseudocost(var->negatedvar, set, stat, -solvaldelta, objdelta, weight) );
14466 return SCIP_OKAY;
14467
14468 default:
14469 SCIPerrorMessage("unknown variable status\n");
14470 return SCIP_INVALIDDATA;
14471 }
14472 }
14473
14474 /** gets the variable's pseudo cost value for the given step size "solvaldelta" in the variable's LP solution value */
14475 SCIP_Real SCIPvarGetPseudocost(
14476 SCIP_VAR* var, /**< problem variable */
14477 SCIP_STAT* stat, /**< problem statistics */
14478 SCIP_Real solvaldelta /**< difference of variable's new LP value - old LP value */
14479 )
14480 {
14481 SCIP_BRANCHDIR dir;
14482
14483 assert(var != NULL);
14484 assert(stat != NULL);
14485
14486 switch( SCIPvarGetStatus(var) )
14487 {
14488 case SCIP_VARSTATUS_ORIGINAL:
14489 if( var->data.original.transvar == NULL )
14490 return SCIPhistoryGetPseudocost(stat->glbhistory, solvaldelta);
14491 else
14492 return SCIPvarGetPseudocost(var->data.original.transvar, stat, solvaldelta);
14493
14494 case SCIP_VARSTATUS_LOOSE:
14495 case SCIP_VARSTATUS_COLUMN:
14496 dir = (solvaldelta >= 0.0 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
14497
14498 return SCIPhistoryGetPseudocostCount(var->history, dir) > 0.0
14499 ? SCIPhistoryGetPseudocost(var->history, solvaldelta)
14500 : SCIPhistoryGetPseudocost(stat->glbhistory, solvaldelta);
14501
14502 case SCIP_VARSTATUS_FIXED:
14503 return 0.0;
14504
14505 case SCIP_VARSTATUS_AGGREGATED:
14506 return SCIPvarGetPseudocost(var->data.aggregate.var, stat, var->data.aggregate.scalar * solvaldelta);
14507
14508 case SCIP_VARSTATUS_MULTAGGR:
14509 return 0.0;
14510
14511 case SCIP_VARSTATUS_NEGATED:
14512 return SCIPvarGetPseudocost(var->negatedvar, stat, -solvaldelta);
14513
14514 default:
14515 SCIPerrorMessage("unknown variable status\n");
14516 SCIPABORT();
14517 return 0.0; /*lint !e527*/
14518 }
14519 }
14520
14521 /** gets the variable's pseudo cost value for the given step size "solvaldelta" in the variable's LP solution value,
14522 * only using the pseudo cost information of the current run
14523 */
14524 SCIP_Real SCIPvarGetPseudocostCurrentRun(
14525 SCIP_VAR* var, /**< problem variable */
14526 SCIP_STAT* stat, /**< problem statistics */
14527 SCIP_Real solvaldelta /**< difference of variable's new LP value - old LP value */
14528 )
14529 {
14530 SCIP_BRANCHDIR dir;
14531
14532 assert(var != NULL);
14533 assert(stat != NULL);
14534
14535 switch( SCIPvarGetStatus(var) )
14536 {
14537 case SCIP_VARSTATUS_ORIGINAL:
14538 if( var->data.original.transvar == NULL )
14539 return SCIPhistoryGetPseudocost(stat->glbhistorycrun, solvaldelta);
14540 else
14541 return SCIPvarGetPseudocostCurrentRun(var->data.original.transvar, stat, solvaldelta);
14542
14543 case SCIP_VARSTATUS_LOOSE:
14544 case SCIP_VARSTATUS_COLUMN:
14545 dir = (solvaldelta >= 0.0 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
14546
14547 return SCIPhistoryGetPseudocostCount(var->historycrun, dir) > 0.0
14548 ? SCIPhistoryGetPseudocost(var->historycrun, solvaldelta)
14549 : SCIPhistoryGetPseudocost(stat->glbhistorycrun, solvaldelta);
14550
14551 case SCIP_VARSTATUS_FIXED:
14552 return 0.0;
14553
14554 case SCIP_VARSTATUS_AGGREGATED:
14555 return SCIPvarGetPseudocostCurrentRun(var->data.aggregate.var, stat, var->data.aggregate.scalar * solvaldelta);
14556
14557 case SCIP_VARSTATUS_MULTAGGR:
14558 return 0.0;
14559
14560 case SCIP_VARSTATUS_NEGATED:
14561 return SCIPvarGetPseudocostCurrentRun(var->negatedvar, stat, -solvaldelta);
14562
14563 default:
14564 SCIPerrorMessage("unknown variable status\n");
14565 SCIPABORT();
14566 return 0.0; /*lint !e527*/
14567 }
14568 }
14569
14570 /** gets the variable's (possible fractional) number of pseudo cost updates for the given direction */
14571 SCIP_Real SCIPvarGetPseudocostCount(
14572 SCIP_VAR* var, /**< problem variable */
14573 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14574 )
14575 {
14576 assert(var != NULL);
14577 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14578
14579 switch( SCIPvarGetStatus(var) )
14580 {
14581 case SCIP_VARSTATUS_ORIGINAL:
14582 if( var->data.original.transvar == NULL )
14583 return 0.0;
14584 else
14585 return SCIPvarGetPseudocostCount(var->data.original.transvar, dir);
14586
14587 case SCIP_VARSTATUS_LOOSE:
14588 case SCIP_VARSTATUS_COLUMN:
14589 return SCIPhistoryGetPseudocostCount(var->history, dir);
14590
14591 case SCIP_VARSTATUS_FIXED:
14592 return 0.0;
14593
14594 case SCIP_VARSTATUS_AGGREGATED:
14595 if( var->data.aggregate.scalar > 0.0 )
14596 return SCIPvarGetPseudocostCount(var->data.aggregate.var, dir);
14597 else
14598 return SCIPvarGetPseudocostCount(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
14599
14600 case SCIP_VARSTATUS_MULTAGGR:
14601 return 0.0;
14602
14603 case SCIP_VARSTATUS_NEGATED:
14604 return SCIPvarGetPseudocostCount(var->negatedvar, SCIPbranchdirOpposite(dir));
14605
14606 default:
14607 SCIPerrorMessage("unknown variable status\n");
14608 SCIPABORT();
14609 return 0.0; /*lint !e527*/
14610 }
14611 }
14612
14613 /** gets the variable's (possible fractional) number of pseudo cost updates for the given direction,
14614 * only using the pseudo cost information of the current run
14615 */
14616 SCIP_Real SCIPvarGetPseudocostCountCurrentRun(
14617 SCIP_VAR* var, /**< problem variable */
14618 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14619 )
14620 {
14621 assert(var != NULL);
14622 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14623
14624 switch( SCIPvarGetStatus(var) )
14625 {
14626 case SCIP_VARSTATUS_ORIGINAL:
14627 if( var->data.original.transvar == NULL )
14628 return 0.0;
14629 else
14630 return SCIPvarGetPseudocostCountCurrentRun(var->data.original.transvar, dir);
14631
14632 case SCIP_VARSTATUS_LOOSE:
14633 case SCIP_VARSTATUS_COLUMN:
14634 return SCIPhistoryGetPseudocostCount(var->historycrun, dir);
14635
14636 case SCIP_VARSTATUS_FIXED:
14637 return 0.0;
14638
14639 case SCIP_VARSTATUS_AGGREGATED:
14640 if( var->data.aggregate.scalar > 0.0 )
14641 return SCIPvarGetPseudocostCountCurrentRun(var->data.aggregate.var, dir);
14642 else
14643 return SCIPvarGetPseudocostCountCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
14644
14645 case SCIP_VARSTATUS_MULTAGGR:
14646 return 0.0;
14647
14648 case SCIP_VARSTATUS_NEGATED:
14649 return SCIPvarGetPseudocostCountCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir));
14650
14651 default:
14652 SCIPerrorMessage("unknown variable status\n");
14653 SCIPABORT();
14654 return 0.0; /*lint !e527*/
14655 }
14656 }
14657
14658 /** compares both possible directions for rounding the given solution value and returns the minimum pseudo-costs of the variable */
14659 SCIP_Real SCIPvarGetMinPseudocostScore(
14660 SCIP_VAR* var, /**< problem variable */
14661 SCIP_STAT* stat, /**< problem statistics */
14662 SCIP_SET* set, /**< global SCIP settings */
14663 SCIP_Real solval /**< solution value, e.g., LP solution value */
14664 )
14665 {
14666 SCIP_Real upscore;
14667 SCIP_Real downscore;
14668 SCIP_Real solvaldeltaup;
14669 SCIP_Real solvaldeltadown;
14670
14671 /* LP root estimate only works for variables with fractional LP root solution */
14672 if( SCIPsetIsFeasIntegral(set, solval) )
14673 return 0.0;
14674
14675 /* no min pseudo-cost score is calculated as long as the variable was not initialized in a direction */
14676 if( SCIPvarGetPseudocostCount(var, SCIP_BRANCHDIR_DOWNWARDS) < 1.0 || SCIPvarGetPseudocostCount(var, SCIP_BRANCHDIR_UPWARDS) < 1.0 )
14677 return 0.0;
14678
14679 /* compute delta's to ceil and floor of root LP solution value */
14680 solvaldeltaup = SCIPsetCeil(set, solval) - solval;
14681 solvaldeltadown = SCIPsetFloor(set, solval) - solval;
14682
14683 upscore = SCIPvarGetPseudocost(var, stat, solvaldeltaup);
14684 downscore = SCIPvarGetPseudocost(var, stat, solvaldeltadown);
14685
14686 return MIN(upscore, downscore);
14687 }
14688
14689 /** gets the an estimate of the variable's pseudo cost variance in direction \p dir */
14690 SCIP_Real SCIPvarGetPseudocostVariance(
14691 SCIP_VAR* var, /**< problem variable */
14692 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
14693 SCIP_Bool onlycurrentrun /**< return pseudo cost variance only for current branch and bound run */
14694 )
14695 {
14696 assert(var != NULL);
14697 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14698
14699 switch( SCIPvarGetStatus(var) )
14700 {
14701 case SCIP_VARSTATUS_ORIGINAL:
14702 if( var->data.original.transvar == NULL )
14703 return 0.0;
14704 else
14705 return SCIPvarGetPseudocostVariance(var->data.original.transvar, dir, onlycurrentrun);
14706
14707 case SCIP_VARSTATUS_LOOSE:
14708 case SCIP_VARSTATUS_COLUMN:
14709 if( onlycurrentrun )
14710 return SCIPhistoryGetPseudocostVariance(var->historycrun, dir);
14711 else
14712 return SCIPhistoryGetPseudocostVariance(var->history, dir);
14713
14714 case SCIP_VARSTATUS_FIXED:
14715 return 0.0;
14716
14717 case SCIP_VARSTATUS_AGGREGATED:
14718 if( var->data.aggregate.scalar > 0.0 )
14719 return SCIPvarGetPseudocostVariance(var->data.aggregate.var, dir, onlycurrentrun);
14720 else
14721 return SCIPvarGetPseudocostVariance(var->data.aggregate.var, SCIPbranchdirOpposite(dir), onlycurrentrun);
14722
14723 case SCIP_VARSTATUS_MULTAGGR:
14724 return 0.0;
14725
14726 case SCIP_VARSTATUS_NEGATED:
14727 return SCIPvarGetPseudocostVariance(var->negatedvar, SCIPbranchdirOpposite(dir), onlycurrentrun);
14728
14729 default:
14730 SCIPerrorMessage("unknown variable status\n");
14731 SCIPABORT();
14732 return 0.0; /*lint !e527*/
14733 }
14734 }
14735
14736 /** calculates a confidence bound for this variable under the assumption of normally distributed pseudo costs
14737 *
14738 * The confidence bound \f$ \theta \geq 0\f$ denotes the interval borders \f$ [X - \theta, \ X + \theta]\f$, which contains
14739 * the true pseudo costs of the variable, i.e., the expected value of the normal distribution, with a probability
14740 * of 2 * clevel - 1.
14741 *
14742 * @return value of confidence bound for this variable
14743 */
14744 SCIP_Real SCIPvarCalcPscostConfidenceBound(
14745 SCIP_VAR* var, /**< variable in question */
14746 SCIP_SET* set, /**< global SCIP settings */
14747 SCIP_BRANCHDIR dir, /**< the branching direction for the confidence bound */
14748 SCIP_Bool onlycurrentrun, /**< should only the current run be taken into account */
14749 SCIP_CONFIDENCELEVEL clevel /**< confidence level for the interval */
14750 )
14751 {
14752 SCIP_Real confidencebound;
14753
14754 confidencebound = SCIPvarGetPseudocostVariance(var, dir, onlycurrentrun);
14755 if( SCIPsetIsFeasPositive(set, confidencebound) )
14756 {
14757 SCIP_Real count;
14758
14759 if( onlycurrentrun )
14760 count = SCIPvarGetPseudocostCountCurrentRun(var, dir);
14761 else
14762 count = SCIPvarGetPseudocostCount(var, dir);
14763 /* assertion is valid because variance is positive */
14764 assert(count >= 1.9);
14765
14766 confidencebound /= count; /*lint !e414 division by zero can obviously not occur */
14767 confidencebound = sqrt(confidencebound);
14768
14769 /* the actual, underlying distribution of the mean is a student-t-distribution with degrees of freedom equal to
14770 * the number of pseudo cost evaluations of this variable in the respective direction. */
14771 confidencebound *= SCIPstudentTGetCriticalValue(clevel, (int)SCIPsetFloor(set, count) - 1);
14772 }
14773 else
14774 confidencebound = 0.0;
14775
14776 return confidencebound;
14777 }
14778
14779 /** check if the current pseudo cost relative error in a direction violates the given threshold. The Relative
14780 * Error is calculated at a specific confidence level
14781 */
14782 SCIP_Bool SCIPvarIsPscostRelerrorReliable(
14783 SCIP_VAR* var, /**< variable in question */
14784 SCIP_SET* set, /**< global SCIP settings */
14785 SCIP_STAT* stat, /**< problem statistics */
14786 SCIP_Real threshold, /**< threshold for relative errors to be considered reliable (enough) */
14787 SCIP_CONFIDENCELEVEL clevel /**< a given confidence level */
14788 )
14789 {
14790 SCIP_Real downsize;
14791 SCIP_Real upsize;
14792 SCIP_Real size;
14793 SCIP_Real relerrorup;
14794 SCIP_Real relerrordown;
14795 SCIP_Real relerror;
14796
14797 /* check, if the pseudo cost score of the variable is reliable */
14798 downsize = SCIPvarGetPseudocostCountCurrentRun(var, SCIP_BRANCHDIR_DOWNWARDS);
14799 upsize = SCIPvarGetPseudocostCountCurrentRun(var, SCIP_BRANCHDIR_UPWARDS);
14800 size = MIN(downsize, upsize);
14801
14802 /* Pseudo costs relative error can only be reliable if both directions have been tried at least twice */
14803 if( size <= 1.9 )
14804 return FALSE;
14805
14806 /* use the relative error between the current mean pseudo cost value of the candidate and its upper
14807 * confidence interval bound at confidence level of 95% for individual variable reliability.
14808 * this is only possible if we have at least 2 measurements and therefore a valid variance estimate.
14809 */
14810 if( downsize >= 1.9 )
14811 {
14812 SCIP_Real normval;
14813
14814 relerrordown = SCIPvarCalcPscostConfidenceBound(var, set, SCIP_BRANCHDIR_DOWNWARDS, TRUE, clevel);
14815 normval = SCIPvarGetPseudocostCurrentRun(var, stat, -1.0);
14816 normval = MAX(1.0, normval);
14817
14818 relerrordown /= normval;
14819 }
14820 else
14821 relerrordown = 0.0;
14822
14823 if( upsize >= 1.9 )
14824 {
14825 SCIP_Real normval;
14826
14827 relerrorup = SCIPvarCalcPscostConfidenceBound(var, set, SCIP_BRANCHDIR_UPWARDS, TRUE, clevel);
14828 normval = SCIPvarGetPseudocostCurrentRun(var, stat, +1.0);
14829 normval = MAX(1.0, normval);
14830 relerrorup /= normval;
14831 }
14832 else
14833 relerrorup = 0.0;
14834
14835 /* consider the relative error threshold violated, if it is violated in at least one branching direction */
14836 relerror = MAX(relerrorup, relerrordown);
14837
14838 return (relerror <= threshold);
14839 }
14840
14841 /** check if variable pseudo-costs have a significant difference in location. The significance depends on
14842 * the choice of \p clevel and on the kind of tested hypothesis. The one-sided hypothesis, which
14843 * should be rejected, is that fracy * mu_y >= fracx * mu_x, where mu_y and mu_x denote the
14844 * unknown location means of the underlying pseudo-cost distributions of x and y.
14845 *
14846 * This method is applied best if variable x has a better pseudo-cost score than y. The method hypothesizes that y were actually
14847 * better than x (despite the current information), meaning that y can be expected to yield branching
14848 * decisions as least as good as x in the long run. If the method returns TRUE, the current history information is
14849 * sufficient to safely rely on the alternative hypothesis that x yields indeed a better branching score (on average)
14850 * than y.
14851 *
14852 * @note The order of x and y matters for the one-sided hypothesis
14853 *
14854 * @note set \p onesided to FALSE if you are not sure which variable is better. The hypothesis tested then reads
14855 * fracy * mu_y == fracx * mu_x vs the alternative hypothesis fracy * mu_y != fracx * mu_x.
14856 *
14857 * @return TRUE if the hypothesis can be safely rejected at the given confidence level
14858 */
14859 SCIP_Bool SCIPvarSignificantPscostDifference(
14860 SCIP_SET* set, /**< global SCIP settings */
14861 SCIP_STAT* stat, /**< problem statistics */
14862 SCIP_VAR* varx, /**< variable x */
14863 SCIP_Real fracx, /**< the fractionality of variable x */
14864 SCIP_VAR* vary, /**< variable y */
14865 SCIP_Real fracy, /**< the fractionality of variable y */
14866 SCIP_BRANCHDIR dir, /**< branching direction */
14867 SCIP_CONFIDENCELEVEL clevel, /**< confidence level for rejecting hypothesis */
14868 SCIP_Bool onesided /**< should a one-sided hypothesis y >= x be tested? */
14869 )
14870 {
14871 SCIP_Real meanx;
14872 SCIP_Real meany;
14873 SCIP_Real variancex;
14874 SCIP_Real variancey;
14875 SCIP_Real countx;
14876 SCIP_Real county;
14877 SCIP_Real tresult;
14878 SCIP_Real realdirection;
14879
14880 if( varx == vary )
14881 return FALSE;
14882
14883 countx = SCIPvarGetPseudocostCount(varx, dir);
14884 county = SCIPvarGetPseudocostCount(vary, dir);
14885
14886 /* if not at least 2 measurements were taken, return FALSE */
14887 if( countx <= 1.9 || county <= 1.9 )
14888 return FALSE;
14889
14890 realdirection = (dir == SCIP_BRANCHDIR_DOWNWARDS ? -1.0 : 1.0);
14891
14892 meanx = fracx * SCIPvarGetPseudocost(varx, stat, realdirection);
14893 meany = fracy * SCIPvarGetPseudocost(vary, stat, realdirection);
14894
14895 variancex = SQR(fracx) * SCIPvarGetPseudocostVariance(varx, dir, FALSE);
14896 variancey = SQR(fracy) * SCIPvarGetPseudocostVariance(vary, dir, FALSE);
14897
14898 /* if there is no variance, the means are taken from a constant distribution */
14899 if( SCIPsetIsFeasEQ(set, variancex + variancey, 0.0) )
14900 return (onesided ? SCIPsetIsFeasGT(set, meanx, meany) : !SCIPsetIsFeasEQ(set, meanx, meany));
14901
14902 tresult = SCIPcomputeTwoSampleTTestValue(meanx, meany, variancex, variancey, countx, county);
14903
14904 /* for the two-sided hypothesis, just take the absolute of t */
14905 if( !onesided )
14906 tresult = REALABS(tresult);
14907
14908 return (tresult >= SCIPstudentTGetCriticalValue(clevel, (int)(countx + county - 2)));
14909 }
14910
14911 /** tests at a given confidence level whether the variable pseudo-costs only have a small probability to
14912 * exceed a \p threshold. This is useful to determine if past observations provide enough evidence
14913 * to skip an expensive strong-branching step if there is already a candidate that has been proven to yield an improvement
14914 * of at least \p threshold.
14915 *
14916 * @note use \p clevel to adjust the level of confidence. For SCIP_CONFIDENCELEVEL_MIN, the method returns TRUE if
14917 * the estimated probability to exceed \p threshold is less than 25 %.
14918 *
14919 * @see SCIP_Confidencelevel for a list of available levels. The used probability limits refer to the one-sided levels
14920 * of confidence.
14921 *
14922 * @return TRUE if the variable pseudo-cost probabilistic model is likely to be smaller than \p threshold
14923 * at the given confidence level \p clevel.
14924 */
14925 SCIP_Bool SCIPvarPscostThresholdProbabilityTest(
14926 SCIP_SET* set, /**< global SCIP settings */
14927 SCIP_STAT* stat, /**< problem statistics */
14928 SCIP_VAR* var, /**< variable x */
14929 SCIP_Real frac, /**< the fractionality of variable x */
14930 SCIP_Real threshold, /**< the threshold to test against */
14931 SCIP_BRANCHDIR dir, /**< branching direction */
14932 SCIP_CONFIDENCELEVEL clevel /**< confidence level for rejecting hypothesis */
14933 )
14934 {
14935 SCIP_Real mean;
14936 SCIP_Real variance;
14937 SCIP_Real count;
14938 SCIP_Real realdirection;
14939 SCIP_Real probability;
14940 SCIP_Real problimit;
14941
14942 count = SCIPvarGetPseudocostCount(var, dir);
14943
14944 /* if not at least 2 measurements were taken, return FALSE */
14945 if( count <= 1.9 )
14946 return FALSE;
14947
14948 realdirection = (dir == SCIP_BRANCHDIR_DOWNWARDS ? -1.0 : 1.0);
14949
14950 mean = frac * SCIPvarGetPseudocost(var, stat, realdirection);
14951 variance = SQR(frac) * SCIPvarGetPseudocostVariance(var, dir, FALSE);
14952
14953 /* if mean is at least threshold, it has at least a 50% probability to exceed threshold, we therefore return FALSE */
14954 if( SCIPsetIsFeasGE(set, mean, threshold) )
14955 return FALSE;
14956
14957 /* if there is no variance, the means are taken from a constant distribution */
14958 if( SCIPsetIsFeasEQ(set, variance, 0.0) )
14959 return SCIPsetIsFeasLT(set, mean, threshold);
14960
14961 /* obtain probability of a normally distributed random variable at given mean and variance to yield at most threshold */
14962 probability = SCIPnormalCDF(mean, variance, threshold);
14963
14964 /* determine a probability limit corresponding to the given confidence level */
14965 switch( clevel )
14966 {
14967 case SCIP_CONFIDENCELEVEL_MIN:
14968 problimit = 0.75;
14969 break;
14970 case SCIP_CONFIDENCELEVEL_LOW:
14971 problimit = 0.875;
14972 break;
14973 case SCIP_CONFIDENCELEVEL_MEDIUM:
14974 problimit = 0.9;
14975 break;
14976 case SCIP_CONFIDENCELEVEL_HIGH:
14977 problimit = 0.95;
14978 break;
14979 case SCIP_CONFIDENCELEVEL_MAX:
14980 problimit = 0.975;
14981 break;
14982 default:
14983 problimit = -1;
14984 SCIPerrorMessage("Confidence level set to unknown value <%d>", (int)clevel);
14985 SCIPABORT();
14986 break;
14987 }
14988
14989 return (probability >= problimit);
14990 }
14991
14992 /** find the corresponding history entry if already existing, otherwise create new entry */
14993 static
14994 SCIP_RETCODE findValuehistoryEntry(
14995 SCIP_VAR* var, /**< problem variable */
14996 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
14997 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
14998 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
14999 SCIP_HISTORY** history /**< pointer to store the value based history, or NULL */
15000 )
15001 {
15002 assert(var != NULL);
15003 assert(blkmem != NULL);
15004 assert(set != NULL);
15005 assert(history != NULL);
15006
15007 (*history) = NULL;
15008
15009 if( var->valuehistory == NULL )
15010 {
15011 SCIP_CALL( SCIPvaluehistoryCreate(&var->valuehistory, blkmem) );
15012 }
15013
15014 SCIP_CALL( SCIPvaluehistoryFind(var->valuehistory, blkmem, set, value, history) );
15015
15016 return SCIP_OKAY;
15017 }
15018
15019 /** check if value based history should be used */
15020 static
15021 SCIP_Bool useValuehistory(
15022 SCIP_VAR* var, /**< problem variable */
15023 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15024 SCIP_SET* set /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15025 )
15026 {
15027 /* check if the domain value is unknown (not specific) */
15028 if( value == SCIP_UNKNOWN ) /*lint !e777*/
15029 return FALSE;
15030
15031 assert(set != NULL);
15032
15033 /* check if value based history should be collected */
15034 if( !set->history_valuebased )
15035 return FALSE;
15036
15037 /* value based history is not collected for binary variable since the standard history already contains all information */
15038 if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
15039 return FALSE;
15040
15041 /* value based history is not collected for continuous variables */
15042 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
15043 return FALSE;
15044
15045 return TRUE;
15046 }
15047
15048 /** increases VSIDS of the variable by the given weight */
15049 SCIP_RETCODE SCIPvarIncVSIDS(
15050 SCIP_VAR* var, /**< problem variable */
15051 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15052 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15053 SCIP_STAT* stat, /**< problem statistics */
15054 SCIP_BRANCHDIR dir, /**< branching direction */
15055 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15056 SCIP_Real weight /**< weight of this update in VSIDS */
15057 )
15058 {
15059 assert(var != NULL);
15060 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15061
15062 /* check if history statistics should be collected for a variable */
15063 if( !stat->collectvarhistory )
15064 return SCIP_OKAY;
15065
15066 if( SCIPsetIsZero(set, weight) )
15067 return SCIP_OKAY;
15068
15069 switch( SCIPvarGetStatus(var) )
15070 {
15071 case SCIP_VARSTATUS_ORIGINAL:
15072 if( var->data.original.transvar == NULL )
15073 {
15074 SCIPerrorMessage("cannot update VSIDS of original untransformed variable\n");
15075 return SCIP_INVALIDDATA;
15076 }
15077 SCIP_CALL( SCIPvarIncVSIDS(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
15078 return SCIP_OKAY;
15079
15080 case SCIP_VARSTATUS_LOOSE:
15081 case SCIP_VARSTATUS_COLUMN:
15082 {
15083 SCIPhistoryIncVSIDS(var->history, dir, weight);
15084 SCIPhistoryIncVSIDS(var->historycrun, dir, weight);
15085
15086 if( useValuehistory(var, value, set) )
15087 {
15088 SCIP_HISTORY* history;
15089
15090 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15091 assert(history != NULL);
15092
15093 SCIPhistoryIncVSIDS(history, dir, weight);
15094 SCIPsetDebugMsg(set, "variable (<%s> %s %g) + <%g> = <%g>\n", SCIPvarGetName(var), dir == SCIP_BRANCHDIR_UPWARDS ? ">=" : "<=",
15095 value, weight, SCIPhistoryGetVSIDS(history, dir));
15096 }
15097
15098 return SCIP_OKAY;
15099 }
15100 case SCIP_VARSTATUS_FIXED:
15101 SCIPerrorMessage("cannot update VSIDS of a fixed variable\n");
15102 return SCIP_INVALIDDATA;
15103
15104 case SCIP_VARSTATUS_AGGREGATED:
15105 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15106
15107 if( var->data.aggregate.scalar > 0.0 )
15108 {
15109 SCIP_CALL( SCIPvarIncVSIDS(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
15110 }
15111 else
15112 {
15113 assert(var->data.aggregate.scalar < 0.0);
15114 SCIP_CALL( SCIPvarIncVSIDS(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15115 }
15116 return SCIP_OKAY;
15117
15118 case SCIP_VARSTATUS_MULTAGGR:
15119 SCIPerrorMessage("cannot update VSIDS of a multi-aggregated variable\n");
15120 return SCIP_INVALIDDATA;
15121
15122 case SCIP_VARSTATUS_NEGATED:
15123 value = 1.0 - value;
15124
15125 SCIP_CALL( SCIPvarIncVSIDS(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15126 return SCIP_OKAY;
15127
15128 default:
15129 SCIPerrorMessage("unknown variable status\n");
15130 return SCIP_INVALIDDATA;
15131 }
15132 }
15133
15134 /** scales the VSIDS of the variable by the given scalar */
15135 SCIP_RETCODE SCIPvarScaleVSIDS(
15136 SCIP_VAR* var, /**< problem variable */
15137 SCIP_Real scalar /**< scalar to multiply the VSIDSs with */
15138 )
15139 {
15140 assert(var != NULL);
15141
15142 switch( SCIPvarGetStatus(var) )
15143 {
15144 case SCIP_VARSTATUS_ORIGINAL:
15145 if( var->data.original.transvar == NULL )
15146 {
15147 SCIPerrorMessage("cannot update VSIDS of original untransformed variable\n");
15148 return SCIP_INVALIDDATA;
15149 }
15150 SCIP_CALL( SCIPvarScaleVSIDS(var->data.original.transvar, scalar) );
15151 return SCIP_OKAY;
15152
15153 case SCIP_VARSTATUS_LOOSE:
15154 case SCIP_VARSTATUS_COLUMN:
15155 {
15156 SCIPhistoryScaleVSIDS(var->history, scalar);
15157 SCIPhistoryScaleVSIDS(var->historycrun, scalar);
15158 SCIPvaluehistoryScaleVSIDS(var->valuehistory, scalar);
15159
15160 return SCIP_OKAY;
15161 }
15162 case SCIP_VARSTATUS_FIXED:
15163 SCIPerrorMessage("cannot update VSIDS of a fixed variable\n");
15164 return SCIP_INVALIDDATA;
15165
15166 case SCIP_VARSTATUS_AGGREGATED:
15167 SCIP_CALL( SCIPvarScaleVSIDS(var->data.aggregate.var, scalar) );
15168 return SCIP_OKAY;
15169
15170 case SCIP_VARSTATUS_MULTAGGR:
15171 SCIPerrorMessage("cannot update VSIDS of a multi-aggregated variable\n");
15172 return SCIP_INVALIDDATA;
15173
15174 case SCIP_VARSTATUS_NEGATED:
15175 SCIP_CALL( SCIPvarScaleVSIDS(var->negatedvar, scalar) );
15176 return SCIP_OKAY;
15177
15178 default:
15179 SCIPerrorMessage("unknown variable status\n");
15180 return SCIP_INVALIDDATA;
15181 }
15182 }
15183
15184 /** increases the number of active conflicts by one and the overall length of the variable by the given length */
15185 SCIP_RETCODE SCIPvarIncNActiveConflicts(
15186 SCIP_VAR* var, /**< problem variable */
15187 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15188 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15189 SCIP_STAT* stat, /**< problem statistics */
15190 SCIP_BRANCHDIR dir, /**< branching direction */
15191 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15192 SCIP_Real length /**< length of the conflict */
15193 )
15194 {
15195 assert(var != NULL);
15196 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15197
15198 /* check if history statistics should be collected for a variable */
15199 if( !stat->collectvarhistory )
15200 return SCIP_OKAY;
15201
15202 switch( SCIPvarGetStatus(var) )
15203 {
15204 case SCIP_VARSTATUS_ORIGINAL:
15205 if( var->data.original.transvar == NULL )
15206 {
15207 SCIPerrorMessage("cannot update conflict score of original untransformed variable\n");
15208 return SCIP_INVALIDDATA;
15209 }
15210 SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.original.transvar, blkmem, set, stat, dir, value, length) );
15211 return SCIP_OKAY;
15212
15213 case SCIP_VARSTATUS_LOOSE:
15214 case SCIP_VARSTATUS_COLUMN:
15215 {
15216 SCIPhistoryIncNActiveConflicts(var->history, dir, length);
15217 SCIPhistoryIncNActiveConflicts(var->historycrun, dir, length);
15218
15219 if( useValuehistory(var, value, set) )
15220 {
15221 SCIP_HISTORY* history;
15222
15223 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15224 assert(history != NULL);
15225
15226 SCIPhistoryIncNActiveConflicts(history, dir, length);
15227 }
15228
15229 return SCIP_OKAY;
15230 }
15231 case SCIP_VARSTATUS_FIXED:
15232 SCIPerrorMessage("cannot update conflict score of a fixed variable\n");
15233 return SCIP_INVALIDDATA;
15234
15235 case SCIP_VARSTATUS_AGGREGATED:
15236 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15237
15238 if( var->data.aggregate.scalar > 0.0 )
15239 {
15240 SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.aggregate.var, blkmem, set, stat, dir, value, length) );
15241 }
15242 else
15243 {
15244 assert(var->data.aggregate.scalar < 0.0);
15245 SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, length) );
15246 }
15247 return SCIP_OKAY;
15248
15249 case SCIP_VARSTATUS_MULTAGGR:
15250 SCIPerrorMessage("cannot update conflict score of a multi-aggregated variable\n");
15251 return SCIP_INVALIDDATA;
15252
15253 case SCIP_VARSTATUS_NEGATED:
15254 value = 1.0 - value;
15255
15256 SCIP_CALL( SCIPvarIncNActiveConflicts(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, length) );
15257 return SCIP_OKAY;
15258
15259 default:
15260 SCIPerrorMessage("unknown variable status\n");
15261 return SCIP_INVALIDDATA;
15262 }
15263 }
15264
15265 /** gets the number of active conflicts containing this variable in given direction */
15266 SCIP_Longint SCIPvarGetNActiveConflicts(
15267 SCIP_VAR* var, /**< problem variable */
15268 SCIP_STAT* stat, /**< problem statistics */
15269 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15270 )
15271 {
15272 assert(var != NULL);
15273 assert(stat != NULL);
15274 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15275
15276 switch( SCIPvarGetStatus(var) )
15277 {
15278 case SCIP_VARSTATUS_ORIGINAL:
15279 if( var->data.original.transvar == NULL )
15280 return 0;
15281 else
15282 return SCIPvarGetNActiveConflicts(var->data.original.transvar, stat, dir);
15283
15284 case SCIP_VARSTATUS_LOOSE:
15285 case SCIP_VARSTATUS_COLUMN:
15286 return SCIPhistoryGetNActiveConflicts(var->history, dir);
15287
15288 case SCIP_VARSTATUS_FIXED:
15289 return 0;
15290
15291 case SCIP_VARSTATUS_AGGREGATED:
15292 if( var->data.aggregate.scalar > 0.0 )
15293 return SCIPvarGetNActiveConflicts(var->data.aggregate.var, stat, dir);
15294 else
15295 return SCIPvarGetNActiveConflicts(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
15296
15297 case SCIP_VARSTATUS_MULTAGGR:
15298 return 0;
15299
15300 case SCIP_VARSTATUS_NEGATED:
15301 return SCIPvarGetNActiveConflicts(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
15302
15303 default:
15304 SCIPerrorMessage("unknown variable status\n");
15305 SCIPABORT();
15306 return 0; /*lint !e527*/
15307 }
15308 }
15309
15310 /** gets the number of active conflicts containing this variable in given direction
15311 * in the current run
15312 */
15313 SCIP_Longint SCIPvarGetNActiveConflictsCurrentRun(
15314 SCIP_VAR* var, /**< problem variable */
15315 SCIP_STAT* stat, /**< problem statistics */
15316 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15317 )
15318 {
15319 assert(var != NULL);
15320 assert(stat != NULL);
15321 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15322
15323 switch( SCIPvarGetStatus(var) )
15324 {
15325 case SCIP_VARSTATUS_ORIGINAL:
15326 if( var->data.original.transvar == NULL )
15327 return 0;
15328 else
15329 return SCIPvarGetNActiveConflictsCurrentRun(var->data.original.transvar, stat, dir);
15330
15331 case SCIP_VARSTATUS_LOOSE:
15332 case SCIP_VARSTATUS_COLUMN:
15333 return SCIPhistoryGetNActiveConflicts(var->historycrun, dir);
15334
15335 case SCIP_VARSTATUS_FIXED:
15336 return 0;
15337
15338 case SCIP_VARSTATUS_AGGREGATED:
15339 if( var->data.aggregate.scalar > 0.0 )
15340 return SCIPvarGetNActiveConflictsCurrentRun(var->data.aggregate.var, stat, dir);
15341 else
15342 return SCIPvarGetNActiveConflictsCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
15343
15344 case SCIP_VARSTATUS_MULTAGGR:
15345 return 0;
15346
15347 case SCIP_VARSTATUS_NEGATED:
15348 return SCIPvarGetNActiveConflictsCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
15349
15350 default:
15351 SCIPerrorMessage("unknown variable status\n");
15352 SCIPABORT();
15353 return 0; /*lint !e527*/
15354 }
15355 }
15356
15357 /** gets the average conflict length in given direction due to branching on the variable */
15358 SCIP_Real SCIPvarGetAvgConflictlength(
15359 SCIP_VAR* var, /**< problem variable */
15360 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15361 )
15362 {
15363 assert(var != NULL);
15364 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15365
15366 switch( SCIPvarGetStatus(var) )
15367 {
15368 case SCIP_VARSTATUS_ORIGINAL:
15369 if( var->data.original.transvar == NULL )
15370 return 0.0;
15371 else
15372 return SCIPvarGetAvgConflictlength(var->data.original.transvar, dir);
15373
15374 case SCIP_VARSTATUS_LOOSE:
15375 case SCIP_VARSTATUS_COLUMN:
15376 return SCIPhistoryGetAvgConflictlength(var->history, dir);
15377 case SCIP_VARSTATUS_FIXED:
15378 return 0.0;
15379
15380 case SCIP_VARSTATUS_AGGREGATED:
15381 if( var->data.aggregate.scalar > 0.0 )
15382 return SCIPvarGetAvgConflictlength(var->data.aggregate.var, dir);
15383 else
15384 return SCIPvarGetAvgConflictlength(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15385
15386 case SCIP_VARSTATUS_MULTAGGR:
15387 return 0.0;
15388
15389 case SCIP_VARSTATUS_NEGATED:
15390 return SCIPvarGetAvgConflictlength(var->negatedvar, SCIPbranchdirOpposite(dir));
15391
15392 default:
15393 SCIPerrorMessage("unknown variable status\n");
15394 SCIPABORT();
15395 return 0.0; /*lint !e527*/
15396 }
15397 }
15398
15399 /** gets the average conflict length in given direction due to branching on the variable
15400 * in the current run
15401 */
15402 SCIP_Real SCIPvarGetAvgConflictlengthCurrentRun(
15403 SCIP_VAR* var, /**< problem variable */
15404 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15405 )
15406 {
15407 assert(var != NULL);
15408 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15409
15410 switch( SCIPvarGetStatus(var) )
15411 {
15412 case SCIP_VARSTATUS_ORIGINAL:
15413 if( var->data.original.transvar == NULL )
15414 return 0.0;
15415 else
15416 return SCIPvarGetAvgConflictlengthCurrentRun(var->data.original.transvar, dir);
15417
15418 case SCIP_VARSTATUS_LOOSE:
15419 case SCIP_VARSTATUS_COLUMN:
15420 return SCIPhistoryGetAvgConflictlength(var->historycrun, dir);
15421
15422 case SCIP_VARSTATUS_FIXED:
15423 return 0.0;
15424
15425 case SCIP_VARSTATUS_AGGREGATED:
15426 if( var->data.aggregate.scalar > 0.0 )
15427 return SCIPvarGetAvgConflictlengthCurrentRun(var->data.aggregate.var, dir);
15428 else
15429 return SCIPvarGetAvgConflictlengthCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15430
15431 case SCIP_VARSTATUS_MULTAGGR:
15432 return 0.0;
15433
15434 case SCIP_VARSTATUS_NEGATED:
15435 return SCIPvarGetAvgConflictlengthCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir));
15436
15437 default:
15438 SCIPerrorMessage("unknown variable status\n");
15439 SCIPABORT();
15440 return 0.0; /*lint !e527*/
15441 }
15442 }
15443
15444 /** increases the number of branchings counter of the variable */
15445 SCIP_RETCODE SCIPvarIncNBranchings(
15446 SCIP_VAR* var, /**< problem variable */
15447 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15448 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15449 SCIP_STAT* stat, /**< problem statistics */
15450 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
15451 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15452 int depth /**< depth at which the bound change took place */
15453 )
15454 {
15455 assert(var != NULL);
15456 assert(stat != NULL);
15457 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15458
15459 /* check if history statistics should be collected for a variable */
15460 if( !stat->collectvarhistory )
15461 return SCIP_OKAY;
15462
15463 switch( SCIPvarGetStatus(var) )
15464 {
15465 case SCIP_VARSTATUS_ORIGINAL:
15466 if( var->data.original.transvar == NULL )
15467 {
15468 SCIPerrorMessage("cannot update branching counter of original untransformed variable\n");
15469 return SCIP_INVALIDDATA;
15470 }
15471 SCIP_CALL( SCIPvarIncNBranchings(var->data.original.transvar, blkmem, set, stat, dir, value, depth) );
15472 return SCIP_OKAY;
15473
15474 case SCIP_VARSTATUS_LOOSE:
15475 case SCIP_VARSTATUS_COLUMN:
15476 {
15477 SCIPhistoryIncNBranchings(var->history, dir, depth);
15478 SCIPhistoryIncNBranchings(var->historycrun, dir, depth);
15479 SCIPhistoryIncNBranchings(stat->glbhistory, dir, depth);
15480 SCIPhistoryIncNBranchings(stat->glbhistorycrun, dir, depth);
15481
15482 if( useValuehistory(var, value, set) )
15483 {
15484 SCIP_HISTORY* history;
15485
15486 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15487 assert(history != NULL);
15488
15489 SCIPhistoryIncNBranchings(history, dir, depth);
15490 }
15491
15492 return SCIP_OKAY;
15493 }
15494 case SCIP_VARSTATUS_FIXED:
15495 SCIPerrorMessage("cannot update branching counter of a fixed variable\n");
15496 return SCIP_INVALIDDATA;
15497
15498 case SCIP_VARSTATUS_AGGREGATED:
15499 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15500
15501 if( var->data.aggregate.scalar > 0.0 )
15502 {
15503 SCIP_CALL( SCIPvarIncNBranchings(var->data.aggregate.var, blkmem, set, stat, dir, value, depth) );
15504 }
15505 else
15506 {
15507 assert(var->data.aggregate.scalar < 0.0);
15508 SCIP_CALL( SCIPvarIncNBranchings(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, depth) );
15509 }
15510 return SCIP_OKAY;
15511
15512 case SCIP_VARSTATUS_MULTAGGR:
15513 SCIPerrorMessage("cannot update branching counter of a multi-aggregated variable\n");
15514 return SCIP_INVALIDDATA;
15515
15516 case SCIP_VARSTATUS_NEGATED:
15517 value = 1.0 - value;
15518
15519 SCIP_CALL( SCIPvarIncNBranchings(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, depth) );
15520 return SCIP_OKAY;
15521
15522 default:
15523 SCIPerrorMessage("unknown variable status\n");
15524 return SCIP_INVALIDDATA;
15525 }
15526 }
15527
15528 /** increases the inference sum of the variable by the given weight */
15529 SCIP_RETCODE SCIPvarIncInferenceSum(
15530 SCIP_VAR* var, /**< problem variable */
15531 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15532 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15533 SCIP_STAT* stat, /**< problem statistics */
15534 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
15535 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15536 SCIP_Real weight /**< weight of this update in inference score */
15537 )
15538 {
15539 assert(var != NULL);
15540 assert(stat != NULL);
15541 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15542
15543 /* check if history statistics should be collected for a variable */
15544 if( !stat->collectvarhistory )
15545 return SCIP_OKAY;
15546
15547 switch( SCIPvarGetStatus(var) )
15548 {
15549 case SCIP_VARSTATUS_ORIGINAL:
15550 if( var->data.original.transvar == NULL )
15551 {
15552 SCIPerrorMessage("cannot update inference counter of original untransformed variable\n");
15553 return SCIP_INVALIDDATA;
15554 }
15555 SCIP_CALL( SCIPvarIncInferenceSum(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
15556 return SCIP_OKAY;
15557
15558 case SCIP_VARSTATUS_LOOSE:
15559 case SCIP_VARSTATUS_COLUMN:
15560 {
15561 SCIPhistoryIncInferenceSum(var->history, dir, weight);
15562 SCIPhistoryIncInferenceSum(var->historycrun, dir, weight);
15563 SCIPhistoryIncInferenceSum(stat->glbhistory, dir, weight);
15564 SCIPhistoryIncInferenceSum(stat->glbhistorycrun, dir, weight);
15565
15566 if( useValuehistory(var, value, set) )
15567 {
15568 SCIP_HISTORY* history;
15569
15570 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15571 assert(history != NULL);
15572
15573 SCIPhistoryIncInferenceSum(history, dir, weight);
15574 }
15575
15576 return SCIP_OKAY;
15577 }
15578 case SCIP_VARSTATUS_FIXED:
15579 SCIPerrorMessage("cannot update inference counter of a fixed variable\n");
15580 return SCIP_INVALIDDATA;
15581
15582 case SCIP_VARSTATUS_AGGREGATED:
15583 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15584
15585 if( var->data.aggregate.scalar > 0.0 )
15586 {
15587 SCIP_CALL( SCIPvarIncInferenceSum(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
15588 }
15589 else
15590 {
15591 assert(var->data.aggregate.scalar < 0.0);
15592 SCIP_CALL( SCIPvarIncInferenceSum(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15593 }
15594 return SCIP_OKAY;
15595
15596 case SCIP_VARSTATUS_MULTAGGR:
15597 SCIPerrorMessage("cannot update inference counter of a multi-aggregated variable\n");
15598 return SCIP_INVALIDDATA;
15599
15600 case SCIP_VARSTATUS_NEGATED:
15601 value = 1.0 - value;
15602
15603 SCIP_CALL( SCIPvarIncInferenceSum(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15604 return SCIP_OKAY;
15605
15606 default:
15607 SCIPerrorMessage("unknown variable status\n");
15608 return SCIP_INVALIDDATA;
15609 }
15610 }
15611
15612 /** increases the cutoff sum of the variable by the given weight */
15613 SCIP_RETCODE SCIPvarIncCutoffSum(
15614 SCIP_VAR* var, /**< problem variable */
15615 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15616 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15617 SCIP_STAT* stat, /**< problem statistics */
15618 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
15619 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15620 SCIP_Real weight /**< weight of this update in cutoff score */
15621 )
15622 {
15623 assert(var != NULL);
15624 assert(stat != NULL);
15625 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15626
15627 /* check if history statistics should be collected for a variable */
15628 if( !stat->collectvarhistory )
15629 return SCIP_OKAY;
15630
15631 switch( SCIPvarGetStatus(var) )
15632 {
15633 case SCIP_VARSTATUS_ORIGINAL:
15634 if( var->data.original.transvar == NULL )
15635 {
15636 SCIPerrorMessage("cannot update cutoff sum of original untransformed variable\n");
15637 return SCIP_INVALIDDATA;
15638 }
15639 SCIP_CALL( SCIPvarIncCutoffSum(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
15640 return SCIP_OKAY;
15641
15642 case SCIP_VARSTATUS_LOOSE:
15643 case SCIP_VARSTATUS_COLUMN:
15644 {
15645 SCIPhistoryIncCutoffSum(var->history, dir, weight);
15646 SCIPhistoryIncCutoffSum(var->historycrun, dir, weight);
15647 SCIPhistoryIncCutoffSum(stat->glbhistory, dir, weight);
15648 SCIPhistoryIncCutoffSum(stat->glbhistorycrun, dir, weight);
15649
15650 if( useValuehistory(var, value, set) )
15651 {
15652 SCIP_HISTORY* history;
15653
15654 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15655 assert(history != NULL);
15656
15657 SCIPhistoryIncCutoffSum(history, dir, weight);
15658 }
15659
15660 return SCIP_OKAY;
15661 }
15662 case SCIP_VARSTATUS_FIXED:
15663 SCIPerrorMessage("cannot update cutoff sum of a fixed variable\n");
15664 return SCIP_INVALIDDATA;
15665
15666 case SCIP_VARSTATUS_AGGREGATED:
15667 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15668
15669 if( var->data.aggregate.scalar > 0.0 )
15670 {
15671 SCIP_CALL( SCIPvarIncCutoffSum(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
15672 }
15673 else
15674 {
15675 assert(var->data.aggregate.scalar < 0.0);
15676 SCIP_CALL( SCIPvarIncCutoffSum(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15677 }
15678 return SCIP_OKAY;
15679
15680 case SCIP_VARSTATUS_MULTAGGR:
15681 SCIPerrorMessage("cannot update cutoff sum of a multi-aggregated variable\n");
15682 return SCIP_INVALIDDATA;
15683
15684 case SCIP_VARSTATUS_NEGATED:
15685 value = 1.0 - value;
15686
15687 SCIP_CALL( SCIPvarIncCutoffSum(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15688 return SCIP_OKAY;
15689
15690 default:
15691 SCIPerrorMessage("unknown variable status\n");
15692 return SCIP_INVALIDDATA;
15693 }
15694 }
15695
15696 /** returns the number of times, a bound of the variable was changed in given direction due to branching */
15697 SCIP_Longint SCIPvarGetNBranchings(
15698 SCIP_VAR* var, /**< problem variable */
15699 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15700 )
15701 {
15702 assert(var != NULL);
15703 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15704
15705 switch( SCIPvarGetStatus(var) )
15706 {
15707 case SCIP_VARSTATUS_ORIGINAL:
15708 if( var->data.original.transvar == NULL )
15709 return 0;
15710 else
15711 return SCIPvarGetNBranchings(var->data.original.transvar, dir);
15712
15713 case SCIP_VARSTATUS_LOOSE:
15714 case SCIP_VARSTATUS_COLUMN:
15715 return SCIPhistoryGetNBranchings(var->history, dir);
15716
15717 case SCIP_VARSTATUS_FIXED:
15718 return 0;
15719
15720 case SCIP_VARSTATUS_AGGREGATED:
15721 if( var->data.aggregate.scalar > 0.0 )
15722 return SCIPvarGetNBranchings(var->data.aggregate.var, dir);
15723 else
15724 return SCIPvarGetNBranchings(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15725
15726 case SCIP_VARSTATUS_MULTAGGR:
15727 return 0;
15728
15729 case SCIP_VARSTATUS_NEGATED:
15730 return SCIPvarGetNBranchings(var->negatedvar, SCIPbranchdirOpposite(dir));
15731
15732 default:
15733 SCIPerrorMessage("unknown variable status\n");
15734 SCIPABORT();
15735 return 0; /*lint !e527*/
15736 }
15737 }
15738
15739 /** returns the number of times, a bound of the variable was changed in given direction due to branching
15740 * in the current run
15741 */
15742 SCIP_Longint SCIPvarGetNBranchingsCurrentRun(
15743 SCIP_VAR* var, /**< problem variable */
15744 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15745 )
15746 {
15747 assert(var != NULL);
15748 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15749
15750 switch( SCIPvarGetStatus(var) )
15751 {
15752 case SCIP_VARSTATUS_ORIGINAL:
15753 if( var->data.original.transvar == NULL )
15754 return 0;
15755 else
15756 return SCIPvarGetNBranchingsCurrentRun(var->data.original.transvar, dir);
15757
15758 case SCIP_VARSTATUS_LOOSE:
15759 case SCIP_VARSTATUS_COLUMN:
15760 return SCIPhistoryGetNBranchings(var->historycrun, dir);
15761
15762 case SCIP_VARSTATUS_FIXED:
15763 return 0;
15764
15765 case SCIP_VARSTATUS_AGGREGATED:
15766 if( var->data.aggregate.scalar > 0.0 )
15767 return SCIPvarGetNBranchingsCurrentRun(var->data.aggregate.var, dir);
15768 else
15769 return SCIPvarGetNBranchingsCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15770
15771 case SCIP_VARSTATUS_MULTAGGR:
15772 return 0;
15773
15774 case SCIP_VARSTATUS_NEGATED:
15775 return SCIPvarGetNBranchingsCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir));
15776
15777 default:
15778 SCIPerrorMessage("unknown variable status\n");
15779 SCIPABORT();
15780 return 0; /*lint !e527*/
15781 }
15782 }
15783
15784 /** returns the average depth of bound changes in given direction due to branching on the variable */
15785 SCIP_Real SCIPvarGetAvgBranchdepth(
15786 SCIP_VAR* var, /**< problem variable */
15787 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15788 )
15789 {
15790 assert(var != NULL);
15791 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15792
15793 switch( SCIPvarGetStatus(var) )
15794 {
15795 case SCIP_VARSTATUS_ORIGINAL:
15796 if( var->data.original.transvar == NULL )
15797 return 0.0;
15798 else
15799 return SCIPvarGetAvgBranchdepth(var->data.original.transvar, dir);
15800
15801 case SCIP_VARSTATUS_LOOSE:
15802 case SCIP_VARSTATUS_COLUMN:
15803 return SCIPhistoryGetAvgBranchdepth(var->history, dir);
15804
15805 case SCIP_VARSTATUS_FIXED:
15806 return 0.0;
15807
15808 case SCIP_VARSTATUS_AGGREGATED:
15809 if( var->data.aggregate.scalar > 0.0 )
15810 return SCIPvarGetAvgBranchdepth(var->data.aggregate.var, dir);
15811 else
15812 return SCIPvarGetAvgBranchdepth(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15813
15814 case SCIP_VARSTATUS_MULTAGGR:
15815 return 0.0;
15816
15817 case SCIP_VARSTATUS_NEGATED:
15818 return SCIPvarGetAvgBranchdepth(var->negatedvar, SCIPbranchdirOpposite(dir));
15819
15820 default:
15821 SCIPerrorMessage("unknown variable status\n");
15822 SCIPABORT();
15823 return 0.0; /*lint !e527*/
15824 }
15825 }
15826
15827 /** returns the average depth of bound changes in given direction due to branching on the variable
15828 * in the current run
15829 */
15830 SCIP_Real SCIPvarGetAvgBranchdepthCurrentRun(
15831 SCIP_VAR* var, /**< problem variable */
15832 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15833 )
15834 {
15835 assert(var != NULL);
15836 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15837
15838 switch( SCIPvarGetStatus(var) )
15839 {
15840 case SCIP_VARSTATUS_ORIGINAL:
15841 if( var->data.original.transvar == NULL )
15842 return 0.0;
15843 else
15844 return SCIPvarGetAvgBranchdepthCurrentRun(var->data.original.transvar, dir);
15845
15846 case SCIP_VARSTATUS_LOOSE:
15847 case SCIP_VARSTATUS_COLUMN:
15848 return SCIPhistoryGetAvgBranchdepth(var->historycrun, dir);
15849
15850 case SCIP_VARSTATUS_FIXED:
15851 return 0.0;
15852
15853 case SCIP_VARSTATUS_AGGREGATED:
15854 if( var->data.aggregate.scalar > 0.0 )
15855 return SCIPvarGetAvgBranchdepthCurrentRun(var->data.aggregate.var, dir);
15856 else
15857 return SCIPvarGetAvgBranchdepthCurrentRun(var->data.aggregate.var,
15858 dir == SCIP_BRANCHDIR_DOWNWARDS ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
15859
15860 case SCIP_VARSTATUS_MULTAGGR:
15861 return 0.0;
15862
15863 case SCIP_VARSTATUS_NEGATED:
15864 return SCIPvarGetAvgBranchdepthCurrentRun(var->negatedvar,
15865 dir == SCIP_BRANCHDIR_DOWNWARDS ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
15866
15867 default:
15868 SCIPerrorMessage("unknown variable status\n");
15869 SCIPABORT();
15870 return 0.0; /*lint !e527*/
15871 }
15872 }
15873
15874 /** returns the variable's VSIDS score */
15875 SCIP_Real SCIPvarGetVSIDS_rec(
15876 SCIP_VAR* var, /**< problem variable */
15877 SCIP_STAT* stat, /**< problem statistics */
15878 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15879 )
15880 {
15881 assert(var != NULL);
15882 assert(stat != NULL);
15883 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15884
15885 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
15886 return SCIPvarGetVSIDS(var->data.original.transvar, stat, dir);
15887
15888 switch( SCIPvarGetStatus(var) )
15889 {
15890 case SCIP_VARSTATUS_ORIGINAL:
15891 if( var->data.original.transvar == NULL )
15892 return 0.0;
15893 else
15894 return SCIPvarGetVSIDS(var->data.original.transvar, stat, dir);
15895
15896 case SCIP_VARSTATUS_LOOSE:
15897 case SCIP_VARSTATUS_COLUMN:
15898 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); /* column case already handled in if condition above */
15899 return SCIPhistoryGetVSIDS(var->history, dir)/stat->vsidsweight;
15900
15901 case SCIP_VARSTATUS_FIXED:
15902 return 0.0;
15903
15904 case SCIP_VARSTATUS_AGGREGATED:
15905 if( var->data.aggregate.scalar > 0.0 )
15906 return SCIPvarGetVSIDS(var->data.aggregate.var, stat, dir);
15907 else
15908 /* coverity[overrun-local] */
15909 return SCIPvarGetVSIDS(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
15910
15911 case SCIP_VARSTATUS_MULTAGGR:
15912 return 0.0;
15913
15914 case SCIP_VARSTATUS_NEGATED:
15915 /* coverity[overrun-local] */
15916 return SCIPvarGetVSIDS(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
15917
15918 default:
15919 SCIPerrorMessage("unknown variable status\n");
15920 SCIPABORT();
15921 return 0.0; /*lint !e527*/
15922 }
15923 }
15924
15925 /** returns the variable's VSIDS score only using conflicts of the current run */
15926 SCIP_Real SCIPvarGetVSIDSCurrentRun(
15927 SCIP_VAR* var, /**< problem variable */
15928 SCIP_STAT* stat, /**< problem statistics */
15929 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15930 )
15931 {
15932 assert(var != NULL);
15933 assert(stat != NULL);
15934 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15935
15936 if( dir != SCIP_BRANCHDIR_DOWNWARDS && dir != SCIP_BRANCHDIR_UPWARDS )
15937 {
15938 SCIPerrorMessage("invalid branching direction %d when asking for VSIDS value\n", dir);
15939 return SCIP_INVALID;
15940 }
15941
15942 switch( SCIPvarGetStatus(var) )
15943 {
15944 case SCIP_VARSTATUS_ORIGINAL:
15945 if( var->data.original.transvar == NULL )
15946 return 0.0;
15947 else
15948 return SCIPvarGetVSIDSCurrentRun(var->data.original.transvar, stat, dir);
15949
15950 case SCIP_VARSTATUS_LOOSE:
15951 case SCIP_VARSTATUS_COLUMN:
15952 return SCIPhistoryGetVSIDS(var->historycrun, dir)/stat->vsidsweight;
15953
15954 case SCIP_VARSTATUS_FIXED:
15955 return 0.0;
15956
15957 case SCIP_VARSTATUS_AGGREGATED:
15958 if( var->data.aggregate.scalar > 0.0 )
15959 return SCIPvarGetVSIDSCurrentRun(var->data.aggregate.var, stat, dir);
15960 else
15961 return SCIPvarGetVSIDSCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
15962
15963 case SCIP_VARSTATUS_MULTAGGR:
15964 return 0.0;
15965
15966 case SCIP_VARSTATUS_NEGATED:
15967 return SCIPvarGetVSIDSCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
15968
15969 default:
15970 SCIPerrorMessage("unknown variable status\n");
15971 SCIPABORT();
15972 return 0.0; /*lint !e527*/
15973 }
15974 }
15975
15976 /** returns the number of inferences branching on this variable in given direction triggered */
15977 SCIP_Real SCIPvarGetInferenceSum(
15978 SCIP_VAR* var, /**< problem variable */
15979 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15980 )
15981 {
15982 assert(var != NULL);
15983 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15984
15985 switch( SCIPvarGetStatus(var) )
15986 {
15987 case SCIP_VARSTATUS_ORIGINAL:
15988 if( var->data.original.transvar == NULL )
15989 return 0.0;
15990 else
15991 return SCIPvarGetInferenceSum(var->data.original.transvar, dir);
15992
15993 case SCIP_VARSTATUS_LOOSE:
15994 case SCIP_VARSTATUS_COLUMN:
15995 return SCIPhistoryGetInferenceSum(var->history, dir);
15996
15997 case SCIP_VARSTATUS_FIXED:
15998 return 0.0;
15999
16000 case SCIP_VARSTATUS_AGGREGATED:
16001 if( var->data.aggregate.scalar > 0.0 )
16002 return SCIPvarGetInferenceSum(var->data.aggregate.var, dir);
16003 else
16004 return SCIPvarGetInferenceSum(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
16005
16006 case SCIP_VARSTATUS_MULTAGGR:
16007 return 0.0;
16008
16009 case SCIP_VARSTATUS_NEGATED:
16010 return SCIPvarGetInferenceSum(var->negatedvar, SCIPbranchdirOpposite(dir));
16011
16012 default:
16013 SCIPerrorMessage("unknown variable status\n");
16014 SCIPABORT();
16015 return 0.0; /*lint !e527*/
16016 }
16017 }
16018
16019 /** returns the number of inferences branching on this variable in given direction triggered
16020 * in the current run
16021 */
16022 SCIP_Real SCIPvarGetInferenceSumCurrentRun(
16023 SCIP_VAR* var, /**< problem variable */
16024 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16025 )
16026 {
16027 assert(var != NULL);
16028 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16029
16030 switch( SCIPvarGetStatus(var) )
16031 {
16032 case SCIP_VARSTATUS_ORIGINAL:
16033 if( var->data.original.transvar == NULL )
16034 return 0.0;
16035 else
16036 return SCIPvarGetInferenceSumCurrentRun(var->data.original.transvar, dir);
16037
16038 case SCIP_VARSTATUS_LOOSE:
16039 case SCIP_VARSTATUS_COLUMN:
16040 return SCIPhistoryGetInferenceSum(var->historycrun, dir);
16041
16042 case SCIP_VARSTATUS_FIXED:
16043 return 0.0;
16044
16045 case SCIP_VARSTATUS_AGGREGATED:
16046 if( var->data.aggregate.scalar > 0.0 )
16047 return SCIPvarGetInferenceSumCurrentRun(var->data.aggregate.var, dir);
16048 else
16049 return SCIPvarGetInferenceSumCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
16050
16051 case SCIP_VARSTATUS_MULTAGGR:
16052 return 0.0;
16053
16054 case SCIP_VARSTATUS_NEGATED:
16055 return SCIPvarGetInferenceSumCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir));
16056
16057 default:
16058 SCIPerrorMessage("unknown variable status\n");
16059 SCIPABORT();
16060 return 0.0; /*lint !e527*/
16061 }
16062 }
16063
16064 /** returns the average number of inferences found after branching on the variable in given direction */
16065 SCIP_Real SCIPvarGetAvgInferences(
16066 SCIP_VAR* var, /**< problem variable */
16067 SCIP_STAT* stat, /**< problem statistics */
16068 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16069 )
16070 {
16071 assert(var != NULL);
16072 assert(stat != NULL);
16073 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16074
16075 switch( SCIPvarGetStatus(var) )
16076 {
16077 case SCIP_VARSTATUS_ORIGINAL:
16078 if( var->data.original.transvar == NULL )
16079 return SCIPhistoryGetAvgInferences(stat->glbhistory, dir);
16080 else
16081 return SCIPvarGetAvgInferences(var->data.original.transvar, stat, dir);
16082
16083 case SCIP_VARSTATUS_LOOSE:
16084 case SCIP_VARSTATUS_COLUMN:
16085 if( SCIPhistoryGetNBranchings(var->history, dir) > 0 )
16086 return SCIPhistoryGetAvgInferences(var->history, dir);
16087 else
16088 {
16089 int nimpls;
16090 int ncliques;
16091
16092 nimpls = SCIPvarGetNImpls(var, dir == SCIP_BRANCHDIR_UPWARDS);
16093 ncliques = SCIPvarGetNCliques(var, dir == SCIP_BRANCHDIR_UPWARDS);
16094 return nimpls + ncliques > 0 ? (SCIP_Real)(nimpls + 2*ncliques) : SCIPhistoryGetAvgInferences(stat->glbhistory, dir); /*lint !e790*/
16095 }
16096
16097 case SCIP_VARSTATUS_FIXED:
16098 return 0.0;
16099
16100 case SCIP_VARSTATUS_AGGREGATED:
16101 if( var->data.aggregate.scalar > 0.0 )
16102 return SCIPvarGetAvgInferences(var->data.aggregate.var, stat, dir);
16103 else
16104 return SCIPvarGetAvgInferences(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
16105
16106 case SCIP_VARSTATUS_MULTAGGR:
16107 return 0.0;
16108
16109 case SCIP_VARSTATUS_NEGATED:
16110 return SCIPvarGetAvgInferences(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
16111
16112 default:
16113 SCIPerrorMessage("unknown variable status\n");
16114 SCIPABORT();
16115 return 0.0; /*lint !e527*/
16116 }
16117 }
16118
16119 /** returns the average number of inferences found after branching on the variable in given direction
16120 * in the current run
16121 */
16122 SCIP_Real SCIPvarGetAvgInferencesCurrentRun(
16123 SCIP_VAR* var, /**< problem variable */
16124 SCIP_STAT* stat, /**< problem statistics */
16125 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16126 )
16127 {
16128 assert(var != NULL);
16129 assert(stat != NULL);
16130 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16131
16132 switch( SCIPvarGetStatus(var) )
16133 {
16134 case SCIP_VARSTATUS_ORIGINAL:
16135 if( var->data.original.transvar == NULL )
16136 return SCIPhistoryGetAvgInferences(stat->glbhistorycrun, dir);
16137 else
16138 return SCIPvarGetAvgInferencesCurrentRun(var->data.original.transvar, stat, dir);
16139
16140 case SCIP_VARSTATUS_LOOSE:
16141 case SCIP_VARSTATUS_COLUMN:
16142 if( SCIPhistoryGetNBranchings(var->historycrun, dir) > 0 )
16143 return SCIPhistoryGetAvgInferences(var->historycrun, dir);
16144 else
16145 {
16146 int nimpls;
16147 int ncliques;
16148
16149 nimpls = SCIPvarGetNImpls(var, dir == SCIP_BRANCHDIR_UPWARDS);
16150 ncliques = SCIPvarGetNCliques(var, dir == SCIP_BRANCHDIR_UPWARDS);
16151 return nimpls + ncliques > 0 ? (SCIP_Real)(nimpls + 2*ncliques) : SCIPhistoryGetAvgInferences(stat->glbhistorycrun, dir); /*lint !e790*/
16152 }
16153
16154 case SCIP_VARSTATUS_FIXED:
16155 return 0.0;
16156
16157 case SCIP_VARSTATUS_AGGREGATED:
16158 if( var->data.aggregate.scalar > 0.0 )
16159 return SCIPvarGetAvgInferencesCurrentRun(var->data.aggregate.var, stat, dir);
16160 else
16161 return SCIPvarGetAvgInferencesCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
16162
16163 case SCIP_VARSTATUS_MULTAGGR:
16164 return 0.0;
16165
16166 case SCIP_VARSTATUS_NEGATED:
16167 return SCIPvarGetAvgInferencesCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
16168
16169 default:
16170 SCIPerrorMessage("unknown variable status\n");
16171 SCIPABORT();
16172 return 0.0; /*lint !e527*/
16173 }
16174 }
16175
16176 /** returns the number of cutoffs branching on this variable in given direction produced */
16177 SCIP_Real SCIPvarGetCutoffSum(
16178 SCIP_VAR* var, /**< problem variable */
16179 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16180 )
16181 {
16182 assert(var != NULL);
16183 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16184
16185 switch( SCIPvarGetStatus(var) )
16186 {
16187 case SCIP_VARSTATUS_ORIGINAL:
16188 if( var->data.original.transvar == NULL )
16189 return 0;
16190 else
16191 return SCIPvarGetCutoffSum(var->data.original.transvar, dir);
16192
16193 case SCIP_VARSTATUS_LOOSE:
16194 case SCIP_VARSTATUS_COLUMN:
16195 return SCIPhistoryGetCutoffSum(var->history, dir);
16196
16197 case SCIP_VARSTATUS_FIXED:
16198 return 0;
16199
16200 case SCIP_VARSTATUS_AGGREGATED:
16201 if( var->data.aggregate.scalar > 0.0 )
16202 return SCIPvarGetCutoffSum(var->data.aggregate.var, dir);
16203 else
16204 return SCIPvarGetCutoffSum(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
16205
16206 case SCIP_VARSTATUS_MULTAGGR:
16207 return 0;
16208
16209 case SCIP_VARSTATUS_NEGATED:
16210 return SCIPvarGetCutoffSum(var->negatedvar, SCIPbranchdirOpposite(dir));
16211
16212 default:
16213 SCIPerrorMessage("unknown variable status\n");
16214 SCIPABORT();
16215 return 0; /*lint !e527*/
16216 }
16217 }
16218
16219 /** returns the number of cutoffs branching on this variable in given direction produced in the current run */
16220 SCIP_Real SCIPvarGetCutoffSumCurrentRun(
16221 SCIP_VAR* var, /**< problem variable */
16222 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16223 )
16224 {
16225 assert(var != NULL);
16226 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16227
16228 switch( SCIPvarGetStatus(var) )
16229 {
16230 case SCIP_VARSTATUS_ORIGINAL:
16231 if( var->data.original.transvar == NULL )
16232 return 0;
16233 else
16234 return SCIPvarGetCutoffSumCurrentRun(var->data.original.transvar, dir);
16235
16236 case SCIP_VARSTATUS_LOOSE:
16237 case SCIP_VARSTATUS_COLUMN:
16238 return SCIPhistoryGetCutoffSum(var->historycrun, dir);
16239
16240 case SCIP_VARSTATUS_FIXED:
16241 return 0;
16242
16243 case SCIP_VARSTATUS_AGGREGATED:
16244 if( var->data.aggregate.scalar > 0.0 )
16245 return SCIPvarGetCutoffSumCurrentRun(var->data.aggregate.var, dir);
16246 else
16247 return SCIPvarGetCutoffSumCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
16248
16249 case SCIP_VARSTATUS_MULTAGGR:
16250 return 0;
16251
16252 case SCIP_VARSTATUS_NEGATED:
16253 return SCIPvarGetCutoffSumCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir));
16254
16255 default:
16256 SCIPerrorMessage("unknown variable status\n");
16257 SCIPABORT();
16258 return 0; /*lint !e527*/
16259 }
16260 }
16261
16262 /** returns the average number of cutoffs found after branching on the variable in given direction */
16263 SCIP_Real SCIPvarGetAvgCutoffs(
16264 SCIP_VAR* var, /**< problem variable */
16265 SCIP_STAT* stat, /**< problem statistics */
16266 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16267 )
16268 {
16269 assert(var != NULL);
16270 assert(stat != NULL);
16271 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16272
16273 switch( SCIPvarGetStatus(var) )
16274 {
16275 case SCIP_VARSTATUS_ORIGINAL:
16276 if( var->data.original.transvar == NULL )
16277 return SCIPhistoryGetAvgCutoffs(stat->glbhistory, dir);
16278 else
16279 return SCIPvarGetAvgCutoffs(var->data.original.transvar, stat, dir);
16280
16281 case SCIP_VARSTATUS_LOOSE:
16282 case SCIP_VARSTATUS_COLUMN:
16283 return SCIPhistoryGetNBranchings(var->history, dir) > 0
16284 ? SCIPhistoryGetAvgCutoffs(var->history, dir)
16285 : SCIPhistoryGetAvgCutoffs(stat->glbhistory, dir);
16286
16287 case SCIP_VARSTATUS_FIXED:
16288 return 0.0;
16289
16290 case SCIP_VARSTATUS_AGGREGATED:
16291 if( var->data.aggregate.scalar > 0.0 )
16292 return SCIPvarGetAvgCutoffs(var->data.aggregate.var, stat, dir);
16293 else
16294 return SCIPvarGetAvgCutoffs(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
16295
16296 case SCIP_VARSTATUS_MULTAGGR:
16297 return 0.0;
16298
16299 case SCIP_VARSTATUS_NEGATED:
16300 return SCIPvarGetAvgCutoffs(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
16301
16302 default:
16303 SCIPerrorMessage("unknown variable status\n");
16304 SCIPABORT();
16305 return 0.0; /*lint !e527*/
16306 }
16307 }
16308
16309 /** returns the average number of cutoffs found after branching on the variable in given direction in the current run */
16310 SCIP_Real SCIPvarGetAvgCutoffsCurrentRun(
16311 SCIP_VAR* var, /**< problem variable */
16312 SCIP_STAT* stat, /**< problem statistics */
16313 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16314 )
16315 {
16316 assert(var != NULL);
16317 assert(stat != NULL);
16318 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16319
16320 switch( SCIPvarGetStatus(var) )
16321 {
16322 case SCIP_VARSTATUS_ORIGINAL:
16323 if( var->data.original.transvar == NULL )
16324 return SCIPhistoryGetAvgCutoffs(stat->glbhistorycrun, dir);
16325 else
16326 return SCIPvarGetAvgCutoffsCurrentRun(var->data.original.transvar, stat, dir);
16327
16328 case SCIP_VARSTATUS_LOOSE:
16329 case SCIP_VARSTATUS_COLUMN:
16330 return SCIPhistoryGetNBranchings(var->historycrun, dir) > 0
16331 ? SCIPhistoryGetAvgCutoffs(var->historycrun, dir)
16332 : SCIPhistoryGetAvgCutoffs(stat->glbhistorycrun, dir);
16333
16334 case SCIP_VARSTATUS_FIXED:
16335 return 0.0;
16336
16337 case SCIP_VARSTATUS_AGGREGATED:
16338 if( var->data.aggregate.scalar > 0.0 )
16339 return SCIPvarGetAvgCutoffsCurrentRun(var->data.aggregate.var, stat, dir);
16340 else
16341 return SCIPvarGetAvgCutoffsCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
16342
16343 case SCIP_VARSTATUS_MULTAGGR:
16344 return 0.0;
16345
16346 case SCIP_VARSTATUS_NEGATED:
16347 return SCIPvarGetAvgCutoffsCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
16348
16349 default:
16350 SCIPerrorMessage("unknown variable status\n");
16351 SCIPABORT();
16352 return 0.0; /*lint !e527*/
16353 }
16354 }
16355
16356
16357
16358
16359 /*
16360 * information methods for bound changes
16361 */
16362
16363 /** creates an artificial bound change information object with depth = INT_MAX and pos = -1 */
16364 SCIP_RETCODE SCIPbdchginfoCreate(
16365 SCIP_BDCHGINFO** bdchginfo, /**< pointer to store bound change information */
16366 BMS_BLKMEM* blkmem, /**< block memory */
16367 SCIP_VAR* var, /**< active variable that changed the bounds */
16368 SCIP_BOUNDTYPE boundtype, /**< type of bound for var: lower or upper bound */
16369 SCIP_Real oldbound, /**< old value for bound */
16370 SCIP_Real newbound /**< new value for bound */
16371 )
16372 {
16373 assert(bdchginfo != NULL);
16374
16375 SCIP_ALLOC( BMSallocBlockMemory(blkmem, bdchginfo) );
16376 (*bdchginfo)->oldbound = oldbound;
16377 (*bdchginfo)->newbound = newbound;
16378 (*bdchginfo)->var = var;
16379 (*bdchginfo)->inferencedata.var = var;
16380 (*bdchginfo)->inferencedata.reason.prop = NULL;
16381 (*bdchginfo)->inferencedata.info = 0;
16382 (*bdchginfo)->bdchgidx.depth = INT_MAX;
16383 (*bdchginfo)->bdchgidx.pos = -1;
16384 (*bdchginfo)->pos = 0;
16385 (*bdchginfo)->boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
16386 (*bdchginfo)->boundtype = boundtype; /*lint !e641*/
16387 (*bdchginfo)->inferboundtype = boundtype; /*lint !e641*/
16388 (*bdchginfo)->redundant = FALSE;
16389
16390 return SCIP_OKAY;
16391 }
16392
16393 /** frees a bound change information object */
16394 void SCIPbdchginfoFree(
16395 SCIP_BDCHGINFO** bdchginfo, /**< pointer to store bound change information */
16396 BMS_BLKMEM* blkmem /**< block memory */
16397 )
16398 {
16399 assert(bdchginfo != NULL);
16400
16401 BMSfreeBlockMemory(blkmem, bdchginfo);
16402 }
16403
16404 /** returns the bound change information for the last lower bound change on given active problem variable before or
16405 * after the bound change with the given index was applied;
16406 * returns NULL, if no change to the lower bound was applied up to this point of time
16407 */
16408 SCIP_BDCHGINFO* SCIPvarGetLbchgInfo(
16409 SCIP_VAR* var, /**< active problem variable */
16410 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16411 SCIP_Bool after /**< should the bound change with given index be included? */
16412 )
16413 {
16414 int i;
16415
16416 assert(var != NULL);
16417 assert(SCIPvarIsActive(var));
16418
16419 /* search the correct bound change information for the given bound change index */
16420 if( after )
16421 {
16422 for( i = var->nlbchginfos-1; i >= 0; --i )
16423 {
16424 assert(var->lbchginfos[i].var == var);
16425 assert((SCIP_BOUNDTYPE)var->lbchginfos[i].boundtype == SCIP_BOUNDTYPE_LOWER);
16426 assert(var->lbchginfos[i].pos == i);
16427
16428 /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16429 if( var->lbchginfos[i].redundant )
16430 return NULL;
16431 assert(var->lbchginfos[i].oldbound < var->lbchginfos[i].newbound);
16432
16433 /* if we reached the bound change index, return the current bound change info */
16434 if( !SCIPbdchgidxIsEarlier(bdchgidx, &var->lbchginfos[i].bdchgidx) )
16435 return &var->lbchginfos[i];
16436 }
16437 }
16438 else
16439 {
16440 for( i = var->nlbchginfos-1; i >= 0; --i )
16441 {
16442 assert(var->lbchginfos[i].var == var);
16443 assert((SCIP_BOUNDTYPE)var->lbchginfos[i].boundtype == SCIP_BOUNDTYPE_LOWER);
16444 assert(var->lbchginfos[i].pos == i);
16445
16446 /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16447 if( var->lbchginfos[i].redundant )
16448 return NULL;
16449 assert(var->lbchginfos[i].oldbound < var->lbchginfos[i].newbound);
16450
16451 /* if we reached the bound change index, return the current bound change info */
16452 if( SCIPbdchgidxIsEarlier(&var->lbchginfos[i].bdchgidx, bdchgidx) )
16453 return &var->lbchginfos[i];
16454 }
16455 }
16456
16457 return NULL;
16458 }
16459
16460 /** returns the bound change information for the last upper bound change on given active problem variable before or
16461 * after the bound change with the given index was applied;
16462 * returns NULL, if no change to the upper bound was applied up to this point of time
16463 */
16464 SCIP_BDCHGINFO* SCIPvarGetUbchgInfo(
16465 SCIP_VAR* var, /**< active problem variable */
16466 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16467 SCIP_Bool after /**< should the bound change with given index be included? */
16468 )
16469 {
16470 int i;
16471
16472 assert(var != NULL);
16473 assert(SCIPvarIsActive(var));
16474
16475 /* search the correct bound change information for the given bound change index */
16476 if( after )
16477 {
16478 for( i = var->nubchginfos-1; i >= 0; --i )
16479 {
16480 assert(var->ubchginfos[i].var == var);
16481 assert((SCIP_BOUNDTYPE)var->ubchginfos[i].boundtype == SCIP_BOUNDTYPE_UPPER);
16482 assert(var->ubchginfos[i].pos == i);
16483
16484 /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16485 if( var->ubchginfos[i].redundant )
16486 return NULL;
16487 assert(var->ubchginfos[i].oldbound > var->ubchginfos[i].newbound);
16488
16489 /* if we reached the bound change index, return the current bound change info */
16490 if( !SCIPbdchgidxIsEarlier(bdchgidx, &var->ubchginfos[i].bdchgidx) )
16491 return &var->ubchginfos[i];
16492 }
16493 }
16494 else
16495 {
16496 for( i = var->nubchginfos-1; i >= 0; --i )
16497 {
16498 assert(var->ubchginfos[i].var == var);
16499 assert((SCIP_BOUNDTYPE)var->ubchginfos[i].boundtype == SCIP_BOUNDTYPE_UPPER);
16500 assert(var->ubchginfos[i].pos == i);
16501
16502 /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16503 if( var->ubchginfos[i].redundant )
16504 return NULL;
16505 assert(var->ubchginfos[i].oldbound > var->ubchginfos[i].newbound);
16506
16507 /* if we reached the bound change index, return the current bound change info */
16508 if( SCIPbdchgidxIsEarlier(&var->ubchginfos[i].bdchgidx, bdchgidx) )
16509 return &var->ubchginfos[i];
16510 }
16511 }
16512
16513 return NULL;
16514 }
16515
16516 /** returns the bound change information for the last lower or upper bound change on given active problem variable
16517 * before or after the bound change with the given index was applied;
16518 * returns NULL, if no change to the lower/upper bound was applied up to this point of time
16519 */
16520 SCIP_BDCHGINFO* SCIPvarGetBdchgInfo(
16521 SCIP_VAR* var, /**< active problem variable */
16522 SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */
16523 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16524 SCIP_Bool after /**< should the bound change with given index be included? */
16525 )
16526 {
16527 if( boundtype == SCIP_BOUNDTYPE_LOWER )
16528 return SCIPvarGetLbchgInfo(var, bdchgidx, after);
16529 else
16530 {
16531 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
16532 return SCIPvarGetUbchgInfo(var, bdchgidx, after);
16533 }
16534 }
16535
16536 /** returns lower bound of variable directly before or after the bound change given by the bound change index
16537 * was applied
16538 *
16539 * @deprecated Please use SCIPgetVarLbAtIndex()
16540 */
16541 SCIP_Real SCIPvarGetLbAtIndex(
16542 SCIP_VAR* var, /**< problem variable */
16543 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16544 SCIP_Bool after /**< should the bound change with given index be included? */
16545 )
16546 {
16547 SCIP_VARSTATUS varstatus;
16548 assert(var != NULL);
16549
16550 varstatus = SCIPvarGetStatus(var);
16551
16552 /* get bounds of attached variables */
16553 switch( varstatus )
16554 {
16555 case SCIP_VARSTATUS_ORIGINAL:
16556 assert(var->data.original.transvar != NULL);
16557 return SCIPvarGetLbAtIndex(var->data.original.transvar, bdchgidx, after);
16558
16559 case SCIP_VARSTATUS_LOOSE:
16560 case SCIP_VARSTATUS_COLUMN:
16561 if( bdchgidx == NULL )
16562 return SCIPvarGetLbLocal(var);
16563 else
16564 {
16565 SCIP_BDCHGINFO* bdchginfo;
16566
16567 bdchginfo = SCIPvarGetLbchgInfo(var, bdchgidx, after);
16568 if( bdchginfo != NULL )
16569 return SCIPbdchginfoGetNewbound(bdchginfo);
16570 else
16571 return var->glbdom.lb;
16572 }
16573 case SCIP_VARSTATUS_FIXED:
16574 return var->glbdom.lb;
16575
16576 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
16577 assert(var->data.aggregate.var != NULL);
16578 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
16579 * corresponding infinity value instead of performing an arithmetical transformation (compare method
16580 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
16581 * (or is called by) a public interface method; instead, we only assert that values are finite
16582 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
16583 * positives and negatives if the parameter <numerics/infinity> is modified by the user
16584 */
16585 if( var->data.aggregate.scalar > 0.0 )
16586 {
16587 /* a > 0 -> get lower bound of y */
16588 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16589 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16590 return var->data.aggregate.scalar * SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after)
16591 + var->data.aggregate.constant;
16592 }
16593 else if( var->data.aggregate.scalar < 0.0 )
16594 {
16595 /* a < 0 -> get upper bound of y */
16596 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16597 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16598 return var->data.aggregate.scalar * SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after)
16599 + var->data.aggregate.constant;
16600 }
16601 else
16602 {
16603 SCIPerrorMessage("scalar is zero in aggregation\n");
16604 SCIPABORT();
16605 return SCIP_INVALID; /*lint !e527*/
16606 }
16607
16608 case SCIP_VARSTATUS_MULTAGGR:
16609 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
16610 if ( var->data.multaggr.nvars == 1 )
16611 {
16612 assert(var->data.multaggr.vars != NULL);
16613 assert(var->data.multaggr.scalars != NULL);
16614 assert(var->data.multaggr.vars[0] != NULL);
16615
16616 if( var->data.multaggr.scalars[0] > 0.0 )
16617 {
16618 /* a > 0 -> get lower bound of y */
16619 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16620 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16621 return var->data.multaggr.scalars[0] * SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16622 + var->data.multaggr.constant;
16623 }
16624 else if( var->data.multaggr.scalars[0] < 0.0 )
16625 {
16626 /* a < 0 -> get upper bound of y */
16627 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16628 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16629 return var->data.multaggr.scalars[0] * SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16630 + var->data.multaggr.constant;
16631 }
16632 else
16633 {
16634 SCIPerrorMessage("scalar is zero in multi-aggregation\n");
16635 SCIPABORT();
16636 return SCIP_INVALID; /*lint !e527*/
16637 }
16638 }
16639 SCIPerrorMessage("cannot get the bounds of a multi-aggregated variable.\n");
16640 SCIPABORT();
16641 return SCIP_INVALID; /*lint !e527*/
16642
16643 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
16644 assert(var->negatedvar != NULL);
16645 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
16646 assert(var->negatedvar->negatedvar == var);
16647 return var->data.negate.constant - SCIPvarGetUbAtIndex(var->negatedvar, bdchgidx, after);
16648 default:
16649 SCIPerrorMessage("unknown variable status\n");
16650 SCIPABORT();
16651 return SCIP_INVALID; /*lint !e527*/
16652 }
16653 }
16654
16655 /** returns upper bound of variable directly before or after the bound change given by the bound change index
16656 * was applied
16657 *
16658 * @deprecated Please use SCIPgetVarUbAtIndex()
16659 */
16660 SCIP_Real SCIPvarGetUbAtIndex(
16661 SCIP_VAR* var, /**< problem variable */
16662 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16663 SCIP_Bool after /**< should the bound change with given index be included? */
16664 )
16665 {
16666 SCIP_VARSTATUS varstatus;
16667 assert(var != NULL);
16668
16669 varstatus = SCIPvarGetStatus(var);
16670
16671 /* get bounds of attached variables */
16672 switch( varstatus )
16673 {
16674 case SCIP_VARSTATUS_ORIGINAL:
16675 assert(var->data.original.transvar != NULL);
16676 return SCIPvarGetUbAtIndex(var->data.original.transvar, bdchgidx, after);
16677
16678 case SCIP_VARSTATUS_COLUMN:
16679 case SCIP_VARSTATUS_LOOSE:
16680 if( bdchgidx == NULL )
16681 return SCIPvarGetUbLocal(var);
16682 else
16683 {
16684 SCIP_BDCHGINFO* bdchginfo;
16685
16686 bdchginfo = SCIPvarGetUbchgInfo(var, bdchgidx, after);
16687 if( bdchginfo != NULL )
16688 return SCIPbdchginfoGetNewbound(bdchginfo);
16689 else
16690 return var->glbdom.ub;
16691 }
16692
16693 case SCIP_VARSTATUS_FIXED:
16694 return var->glbdom.ub;
16695
16696 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
16697 assert(var->data.aggregate.var != NULL);
16698 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
16699 * corresponding infinity value instead of performing an arithmetical transformation (compare method
16700 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
16701 * (or is called by) a public interface method; instead, we only assert that values are finite
16702 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
16703 * positives and negatives if the parameter <numerics/infinity> is modified by the user
16704 */
16705 if( var->data.aggregate.scalar > 0.0 )
16706 {
16707 /* a > 0 -> get lower bound of y */
16708 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16709 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16710 return var->data.aggregate.scalar * SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after)
16711 + var->data.aggregate.constant;
16712 }
16713 else if( var->data.aggregate.scalar < 0.0 )
16714 {
16715 /* a < 0 -> get upper bound of y */
16716 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16717 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16718 return var->data.aggregate.scalar * SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after)
16719 + var->data.aggregate.constant;
16720 }
16721 else
16722 {
16723 SCIPerrorMessage("scalar is zero in aggregation\n");
16724 SCIPABORT();
16725 return SCIP_INVALID; /*lint !e527*/
16726 }
16727
16728 case SCIP_VARSTATUS_MULTAGGR:
16729 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
16730 if ( var->data.multaggr.nvars == 1 )
16731 {
16732 assert(var->data.multaggr.vars != NULL);
16733 assert(var->data.multaggr.scalars != NULL);
16734 assert(var->data.multaggr.vars[0] != NULL);
16735
16736 if( var->data.multaggr.scalars[0] > 0.0 )
16737 {
16738 /* a > 0 -> get lower bound of y */
16739 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16740 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16741 return var->data.multaggr.scalars[0] * SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16742 + var->data.multaggr.constant;
16743 }
16744 else if( var->data.multaggr.scalars[0] < 0.0 )
16745 {
16746 /* a < 0 -> get upper bound of y */
16747 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16748 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16749 return var->data.multaggr.scalars[0] * SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16750 + var->data.multaggr.constant;
16751 }
16752 else
16753 {
16754 SCIPerrorMessage("scalar is zero in multi-aggregation\n");
16755 SCIPABORT();
16756 return SCIP_INVALID; /*lint !e527*/
16757 }
16758 }
16759 SCIPerrorMessage("cannot get the bounds of a multiple aggregated variable.\n");
16760 SCIPABORT();
16761 return SCIP_INVALID; /*lint !e527*/
16762
16763 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
16764 assert(var->negatedvar != NULL);
16765 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
16766 assert(var->negatedvar->negatedvar == var);
16767 return var->data.negate.constant - SCIPvarGetLbAtIndex(var->negatedvar, bdchgidx, after);
16768
16769 default:
16770 SCIPerrorMessage("unknown variable status\n");
16771 SCIPABORT();
16772 return SCIP_INVALID; /*lint !e527*/
16773 }
16774 }
16775
16776 /** returns lower or upper bound of variable directly before or after the bound change given by the bound change index
16777 * was applied
16778 *
16779 * @deprecated Please use SCIPgetVarBdAtIndex()
16780 */
16781 SCIP_Real SCIPvarGetBdAtIndex(
16782 SCIP_VAR* var, /**< problem variable */
16783 SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */
16784 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16785 SCIP_Bool after /**< should the bound change with given index be included? */
16786 )
16787 {
16788 if( boundtype == SCIP_BOUNDTYPE_LOWER )
16789 return SCIPvarGetLbAtIndex(var, bdchgidx, after);
16790 else
16791 {
16792 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
16793 return SCIPvarGetUbAtIndex(var, bdchgidx, after);
16794 }
16795 }
16796
16797 /** returns whether the binary variable was fixed at the time given by the bound change index
16798 *
16799 * @deprecated Please use SCIPgetVarWasFixedAtIndex()
16800 */
16801 SCIP_Bool SCIPvarWasFixedAtIndex(
16802 SCIP_VAR* var, /**< problem variable */
16803 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16804 SCIP_Bool after /**< should the bound change with given index be included? */
16805 )
16806 {
16807 assert(var != NULL);
16808 assert(SCIPvarIsBinary(var));
16809
16810 /* check the current bounds first in order to decide at which bound change information we have to look
16811 * (which is expensive because we have to follow the aggregation tree to the active variable)
16812 */
16813 return ((SCIPvarGetLbLocal(var) > 0.5 && SCIPvarGetLbAtIndex(var, bdchgidx, after) > 0.5)
16814 || (SCIPvarGetUbLocal(var) < 0.5 && SCIPvarGetUbAtIndex(var, bdchgidx, after) < 0.5));
16815 }
16816
16817 /** bound change index representing the initial time before any bound changes took place */
16818 static SCIP_BDCHGIDX initbdchgidx = {-2, 0};
16819
16820 /** bound change index representing the presolving stage */
16821 static SCIP_BDCHGIDX presolvebdchgidx = {-1, 0};
16822
16823 /** returns the last bound change index, at which the bounds of the given variable were tightened */
16824 SCIP_BDCHGIDX* SCIPvarGetLastBdchgIndex(
16825 SCIP_VAR* var /**< problem variable */
16826 )
16827 {
16828 SCIP_BDCHGIDX* lbchgidx;
16829 SCIP_BDCHGIDX* ubchgidx;
16830
16831 assert(var != NULL);
16832
16833 var = SCIPvarGetProbvar(var);
16834
16835 /* check, if variable is original without transformed variable */
16836 if( var == NULL )
16837 return &initbdchgidx;
16838
16839 /* check, if variable was fixed in presolving */
16840 if( !SCIPvarIsActive(var) )
16841 return &presolvebdchgidx;
16842
16843 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
16844
16845 /* get depths of last bound change information for the lower and upper bound */
16846 lbchgidx = (var->nlbchginfos > 0 && !var->lbchginfos[var->nlbchginfos-1].redundant
16847 ? &var->lbchginfos[var->nlbchginfos-1].bdchgidx : &initbdchgidx);
16848 ubchgidx = (var->nubchginfos > 0 && !var->ubchginfos[var->nubchginfos-1].redundant
16849 ? &var->ubchginfos[var->nubchginfos-1].bdchgidx : &initbdchgidx);
16850
16851 if( SCIPbdchgidxIsEarlierNonNull(lbchgidx, ubchgidx) )
16852 return ubchgidx;
16853 else
16854 return lbchgidx;
16855 }
16856
16857 /** returns the last depth level, at which the bounds of the given variable were tightened;
16858 * returns -2, if the variable's bounds are still the global bounds
16859 * returns -1, if the variable was fixed in presolving
16860 */
16861 int SCIPvarGetLastBdchgDepth(
16862 SCIP_VAR* var /**< problem variable */
16863 )
16864 {
16865 SCIP_BDCHGIDX* bdchgidx;
16866
16867 bdchgidx = SCIPvarGetLastBdchgIndex(var);
16868 assert(bdchgidx != NULL);
16869
16870 return bdchgidx->depth;
16871 }
16872
16873 /** returns at which depth in the tree a bound change was applied to the variable that conflicts with the
16874 * given bound; returns -1 if the bound does not conflict with the current local bounds of the variable
16875 */
16876 int SCIPvarGetConflictingBdchgDepth(
16877 SCIP_VAR* var, /**< problem variable */
16878 SCIP_SET* set, /**< global SCIP settings */
16879 SCIP_BOUNDTYPE boundtype, /**< bound type of the conflicting bound */
16880 SCIP_Real bound /**< conflicting bound */
16881 )
16882 {
16883 int i;
16884
16885 assert(var != NULL);
16886 assert(set != NULL);
16887 assert(var->scip == set->scip);
16888
16889 if( boundtype == SCIP_BOUNDTYPE_LOWER )
16890 {
16891 /* check if the bound is in conflict with the current local bounds */
16892 if( SCIPsetIsLE(set, bound, var->locdom.ub) )
16893 return -1;
16894
16895 /* check if the bound is in conflict with the global bound */
16896 if( SCIPsetIsGT(set, bound, var->glbdom.ub) )
16897 return 0;
16898
16899 /* local bounds are in conflict with the given bound -> there must be at least one conflicting change! */
16900 assert(var->nubchginfos > 0);
16901 assert(SCIPsetIsGT(set, bound, var->ubchginfos[var->nubchginfos-1].newbound));
16902
16903 /* search for the first conflicting bound change */
16904 for( i = var->nubchginfos-1; i > 0 && SCIPsetIsGT(set, bound, var->ubchginfos[i-1].newbound); --i )
16905 {
16906 assert(var->ubchginfos[i].var == var); /* perform sanity check on the search for the first conflicting bound */
16907 assert((SCIP_BOUNDTYPE)var->ubchginfos[i].boundtype == SCIP_BOUNDTYPE_UPPER);
16908 }
16909 assert(SCIPsetIsGT(set, bound, var->ubchginfos[i].newbound)); /* bound change i is conflicting */
16910 assert(i == 0 || SCIPsetIsLE(set, bound, var->ubchginfos[i-1].newbound)); /* bound change i-1 is not conflicting */
16911
16912 /* return the depth at which the first conflicting bound change took place */
16913 return var->ubchginfos[i].bdchgidx.depth;
16914 }
16915 else
16916 {
16917 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
16918
16919 /* check if the bound is in conflict with the current local bounds */
16920 if( SCIPsetIsGE(set, bound, var->locdom.lb) )
16921 return -1;
16922
16923 /* check if the bound is in conflict with the global bound */
16924 if( SCIPsetIsLT(set, bound, var->glbdom.lb) )
16925 return 0;
16926
16927 /* local bounds are in conflict with the given bound -> there must be at least one conflicting change! */
16928 assert(var->nlbchginfos > 0);
16929 assert(SCIPsetIsLT(set, bound, var->lbchginfos[var->nlbchginfos-1].newbound));
16930
16931 /* search for the first conflicting bound change */
16932 for( i = var->nlbchginfos-1; i > 0 && SCIPsetIsLT(set, bound, var->lbchginfos[i-1].newbound); --i )
16933 {
16934 assert(var->lbchginfos[i].var == var); /* perform sanity check on the search for the first conflicting bound */
16935 assert((SCIP_BOUNDTYPE)var->lbchginfos[i].boundtype == SCIP_BOUNDTYPE_LOWER);
16936 }
16937 assert(SCIPsetIsLT(set, bound, var->lbchginfos[i].newbound)); /* bound change i is conflicting */
16938 assert(i == 0 || SCIPsetIsGE(set, bound, var->lbchginfos[i-1].newbound)); /* bound change i-1 is not conflicting */
16939
16940 /* return the depth at which the first conflicting bound change took place */
16941 return var->lbchginfos[i].bdchgidx.depth;
16942 }
16943 }
16944
16945 /** returns whether the first binary variable was fixed earlier than the second one;
16946 * returns FALSE, if the first variable is not fixed, and returns TRUE, if the first variable is fixed, but the
16947 * second one is not fixed
16948 */
16949 SCIP_Bool SCIPvarWasFixedEarlier(
16950 SCIP_VAR* var1, /**< first binary variable */
16951 SCIP_VAR* var2 /**< second binary variable */
16952 )
16953 {
16954 SCIP_BDCHGIDX* bdchgidx1;
16955 SCIP_BDCHGIDX* bdchgidx2;
16956
16957 assert(var1 != NULL);
16958 assert(var2 != NULL);
16959 assert(SCIPvarIsBinary(var1));
16960 assert(SCIPvarIsBinary(var2));
16961
16962 var1 = SCIPvarGetProbvar(var1);
16963 var2 = SCIPvarGetProbvar(var2);
16964 assert(var1 != NULL);
16965 assert(var2 != NULL);
16966
16967 /* check, if variables are globally fixed */
16968 if( !SCIPvarIsActive(var2) || var2->glbdom.lb > 0.5 || var2->glbdom.ub < 0.5 )
16969 return FALSE;
16970 if( !SCIPvarIsActive(var1) || var1->glbdom.lb > 0.5 || var1->glbdom.ub < 0.5 )
16971 return TRUE;
16972
16973 assert(SCIPvarGetStatus(var1) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_COLUMN);
16974 assert(SCIPvarGetStatus(var2) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_COLUMN);
16975 assert(SCIPvarIsBinary(var1));
16976 assert(SCIPvarIsBinary(var2));
16977 assert(var1->nlbchginfos + var1->nubchginfos <= 1);
16978 assert(var2->nlbchginfos + var2->nubchginfos <= 1);
16979 assert(var1->nlbchginfos == 0 || !var1->lbchginfos[0].redundant); /* otherwise, var would be globally fixed */
16980 assert(var1->nubchginfos == 0 || !var1->ubchginfos[0].redundant); /* otherwise, var would be globally fixed */
16981 assert(var2->nlbchginfos == 0 || !var2->lbchginfos[0].redundant); /* otherwise, var would be globally fixed */
16982 assert(var2->nubchginfos == 0 || !var2->ubchginfos[0].redundant); /* otherwise, var would be globally fixed */
16983
16984 if( var1->nlbchginfos == 1 )
16985 bdchgidx1 = &var1->lbchginfos[0].bdchgidx;
16986 else if( var1->nubchginfos == 1 )
16987 bdchgidx1 = &var1->ubchginfos[0].bdchgidx;
16988 else
16989 bdchgidx1 = NULL;
16990
16991 if( var2->nlbchginfos == 1 )
16992 bdchgidx2 = &var2->lbchginfos[0].bdchgidx;
16993 else if( var2->nubchginfos == 1 )
16994 bdchgidx2 = &var2->ubchginfos[0].bdchgidx;
16995 else
16996 bdchgidx2 = NULL;
16997
16998 return SCIPbdchgidxIsEarlier(bdchgidx1, bdchgidx2);
16999 }
17000
17001
17002
17003 /*
17004 * Hash functions
17005 */
17006
17007 /** gets the key (i.e. the name) of the given variable */
17008 SCIP_DECL_HASHGETKEY(SCIPhashGetKeyVar)
17009 { /*lint --e{715}*/
17010 SCIP_VAR* var = (SCIP_VAR*)elem;
17011
17012 assert(var != NULL);
17013 return var->name;
17014 }
17015
17016
17017
17018
17019 /*
17020 * simple functions implemented as defines
17021 */
17022
17023 /* In debug mode, the following methods are implemented as function calls to ensure
17024 * type validity.
17025 * In optimized mode, the methods are implemented as defines to improve performance.
17026 * However, we want to have them in the library anyways, so we have to undef the defines.
17027 */
17028
17029 #undef SCIPboundchgGetNewbound
17030 #undef SCIPboundchgGetVar
17031 #undef SCIPboundchgGetBoundchgtype
17032 #undef SCIPboundchgGetBoundtype
17033 #undef SCIPboundchgIsRedundant
17034 #undef SCIPdomchgGetNBoundchgs
17035 #undef SCIPdomchgGetBoundchg
17036 #undef SCIPholelistGetLeft
17037 #undef SCIPholelistGetRight
17038 #undef SCIPholelistGetNext
17039 #undef SCIPvarGetName
17040 #undef SCIPvarGetNUses
17041 #undef SCIPvarGetData
17042 #undef SCIPvarSetData
17043 #undef SCIPvarSetDelorigData
17044 #undef SCIPvarSetTransData
17045 #undef SCIPvarSetDeltransData
17046 #undef SCIPvarGetStatus
17047 #undef SCIPvarIsOriginal
17048 #undef SCIPvarIsTransformed
17049 #undef SCIPvarIsNegated
17050 #undef SCIPvarGetType
17051 #undef SCIPvarIsBinary
17052 #undef SCIPvarIsIntegral
17053 #undef SCIPvarIsInitial
17054 #undef SCIPvarIsRemovable
17055 #undef SCIPvarIsDeleted
17056 #undef SCIPvarIsDeletable
17057 #undef SCIPvarMarkDeletable
17058 #undef SCIPvarMarkNotDeletable
17059 #undef SCIPvarIsActive
17060 #undef SCIPvarGetIndex
17061 #undef SCIPvarGetProbindex
17062 #undef SCIPvarGetTransVar
17063 #undef SCIPvarGetCol
17064 #undef SCIPvarIsInLP
17065 #undef SCIPvarGetAggrVar
17066 #undef SCIPvarGetAggrScalar
17067 #undef SCIPvarGetAggrConstant
17068 #undef SCIPvarGetMultaggrNVars
17069 #undef SCIPvarGetMultaggrVars
17070 #undef SCIPvarGetMultaggrScalars
17071 #undef SCIPvarGetMultaggrConstant
17072 #undef SCIPvarGetNegatedVar
17073 #undef SCIPvarGetNegationVar
17074 #undef SCIPvarGetNegationConstant
17075 #undef SCIPvarGetObj
17076 #undef SCIPvarGetLbOriginal
17077 #undef SCIPvarGetUbOriginal
17078 #undef SCIPvarGetHolelistOriginal
17079 #undef SCIPvarGetLbGlobal
17080 #undef SCIPvarGetUbGlobal
17081 #undef SCIPvarGetHolelistGlobal
17082 #undef SCIPvarGetBestBoundGlobal
17083 #undef SCIPvarGetWorstBoundGlobal
17084 #undef SCIPvarGetLbLocal
17085 #undef SCIPvarGetUbLocal
17086 #undef SCIPvarGetHolelistLocal
17087 #undef SCIPvarGetBestBoundLocal
17088 #undef SCIPvarGetWorstBoundLocal
17089 #undef SCIPvarGetBestBoundType
17090 #undef SCIPvarGetWorstBoundType
17091 #undef SCIPvarGetLbLazy
17092 #undef SCIPvarGetUbLazy
17093 #undef SCIPvarGetBranchFactor
17094 #undef SCIPvarGetBranchPriority
17095 #undef SCIPvarGetBranchDirection
17096 #undef SCIPvarGetNVlbs
17097 #undef SCIPvarGetVlbVars
17098 #undef SCIPvarGetVlbCoefs
17099 #undef SCIPvarGetVlbConstants
17100 #undef SCIPvarGetNVubs
17101 #undef SCIPvarGetVubVars
17102 #undef SCIPvarGetVubCoefs
17103 #undef SCIPvarGetVubConstants
17104 #undef SCIPvarGetNImpls
17105 #undef SCIPvarGetImplVars
17106 #undef SCIPvarGetImplTypes
17107 #undef SCIPvarGetImplBounds
17108 #undef SCIPvarGetImplIds
17109 #undef SCIPvarGetNCliques
17110 #undef SCIPvarGetCliques
17111 #undef SCIPvarGetLPSol
17112 #undef SCIPvarGetNLPSol
17113 #undef SCIPvarGetBdchgInfoLb
17114 #undef SCIPvarGetNBdchgInfosLb
17115 #undef SCIPvarGetBdchgInfoUb
17116 #undef SCIPvarGetNBdchgInfosUb
17117 #undef SCIPvarGetValuehistory
17118 #undef SCIPvarGetPseudoSol
17119 #undef SCIPvarCatchEvent
17120 #undef SCIPvarDropEvent
17121 #undef SCIPvarGetVSIDS
17122 #undef SCIPvarGetCliqueComponentIdx
17123 #undef SCIPvarIsRelaxationOnly
17124 #undef SCIPvarMarkRelaxationOnly
17125 #undef SCIPbdchgidxGetPos
17126 #undef SCIPbdchgidxIsEarlierNonNull
17127 #undef SCIPbdchgidxIsEarlier
17128 #undef SCIPbdchginfoGetOldbound
17129 #undef SCIPbdchginfoGetNewbound
17130 #undef SCIPbdchginfoGetVar
17131 #undef SCIPbdchginfoGetChgtype
17132 #undef SCIPbdchginfoGetBoundtype
17133 #undef SCIPbdchginfoGetDepth
17134 #undef SCIPbdchginfoGetPos
17135 #undef SCIPbdchginfoGetIdx
17136 #undef SCIPbdchginfoGetInferVar
17137 #undef SCIPbdchginfoGetInferCons
17138 #undef SCIPbdchginfoGetInferProp
17139 #undef SCIPbdchginfoGetInferInfo
17140 #undef SCIPbdchginfoGetInferBoundtype
17141 #undef SCIPbdchginfoIsRedundant
17142 #undef SCIPbdchginfoHasInferenceReason
17143 #undef SCIPbdchginfoIsTighter
17144
17145
17146 /** returns the new value of the bound in the bound change data */
17147 SCIP_Real SCIPboundchgGetNewbound(
17148 SCIP_BOUNDCHG* boundchg /**< bound change data */
17149 )
17150 {
17151 assert(boundchg != NULL);
17152
17153 return boundchg->newbound;
17154 }
17155
17156 /** returns the variable of the bound change in the bound change data */
17157 SCIP_VAR* SCIPboundchgGetVar(
17158 SCIP_BOUNDCHG* boundchg /**< bound change data */
17159 )
17160 {
17161 assert(boundchg != NULL);
17162
17163 return boundchg->var;
17164 }
17165
17166 /** returns the bound change type of the bound change in the bound change data */
17167 SCIP_BOUNDCHGTYPE SCIPboundchgGetBoundchgtype(
17168 SCIP_BOUNDCHG* boundchg /**< bound change data */
17169 )
17170 {
17171 assert(boundchg != NULL);
17172
17173 return (SCIP_BOUNDCHGTYPE)(boundchg->boundchgtype);
17174 }
17175
17176 /** returns the bound type of the bound change in the bound change data */
17177 SCIP_BOUNDTYPE SCIPboundchgGetBoundtype(
17178 SCIP_BOUNDCHG* boundchg /**< bound change data */
17179 )
17180 {
17181 assert(boundchg != NULL);
17182
17183 return (SCIP_BOUNDTYPE)(boundchg->boundtype);
17184 }
17185
17186 /** returns whether the bound change is redundant due to a more global bound that is at least as strong */
17187 SCIP_Bool SCIPboundchgIsRedundant(
17188 SCIP_BOUNDCHG* boundchg /**< bound change data */
17189 )
17190 {
17191 assert(boundchg != NULL);
17192
17193 return boundchg->redundant;
17194 }
17195
17196 /** returns the number of bound changes in the domain change data */
17197 int SCIPdomchgGetNBoundchgs(
17198 SCIP_DOMCHG* domchg /**< domain change data */
17199 )
17200 {
17201 return domchg != NULL ? domchg->domchgbound.nboundchgs : 0;
17202 }
17203
17204 /** returns a particular bound change in the domain change data */
17205 SCIP_BOUNDCHG* SCIPdomchgGetBoundchg(
17206 SCIP_DOMCHG* domchg, /**< domain change data */
17207 int pos /**< position of the bound change in the domain change data */
17208 )
17209 {
17210 assert(domchg != NULL);
17211 assert(0 <= pos && pos < (int)domchg->domchgbound.nboundchgs);
17212
17213 return &domchg->domchgbound.boundchgs[pos];
17214 }
17215
17216 /** returns left bound of open interval in hole */
17217 SCIP_Real SCIPholelistGetLeft(
17218 SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */
17219 )
17220 {
17221 assert(holelist != NULL);
17222
17223 return holelist->hole.left;
17224 }
17225
17226 /** returns right bound of open interval in hole */
17227 SCIP_Real SCIPholelistGetRight(
17228 SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */
17229 )
17230 {
17231 assert(holelist != NULL);
17232
17233 return holelist->hole.right;
17234 }
17235
17236 /** returns next hole in list */
17237 SCIP_HOLELIST* SCIPholelistGetNext(
17238 SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */
17239 )
17240 {
17241 assert(holelist != NULL);
17242
17243 return holelist->next;
17244 }
17245
17246 /** returns the name of the variable
17247 *
17248 * @note to change the name of a variable, use SCIPchgVarName() from scip.h
17249 */
17250 const char* SCIPvarGetName(
17251 SCIP_VAR* var /**< problem variable */
17252 )
17253 {
17254 assert(var != NULL);
17255
17256 return var->name;
17257 }
17258
17259 /** gets number of times, the variable is currently captured */
17260 int SCIPvarGetNUses(
17261 SCIP_VAR* var /**< problem variable */
17262 )
17263 {
17264 assert(var != NULL);
17265
17266 return var->nuses;
17267 }
17268
17269 /** returns the user data of the variable */
17270 SCIP_VARDATA* SCIPvarGetData(
17271 SCIP_VAR* var /**< problem variable */
17272 )
17273 {
17274 assert(var != NULL);
17275
17276 return var->vardata;
17277 }
17278
17279 /** sets the user data for the variable */
17280 void SCIPvarSetData(
17281 SCIP_VAR* var, /**< problem variable */
17282 SCIP_VARDATA* vardata /**< user variable data */
17283 )
17284 {
17285 assert(var != NULL);
17286
17287 var->vardata = vardata;
17288 }
17289
17290 /** sets method to free user data for the original variable */
17291 void SCIPvarSetDelorigData(
17292 SCIP_VAR* var, /**< problem variable */
17293 SCIP_DECL_VARDELORIG ((*vardelorig)) /**< frees user data of original variable */
17294 )
17295 {
17296 assert(var != NULL);
17297 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL);
17298
17299 var->vardelorig = vardelorig;
17300 }
17301
17302 /** sets method to transform user data of the variable */
17303 void SCIPvarSetTransData(
17304 SCIP_VAR* var, /**< problem variable */
17305 SCIP_DECL_VARTRANS ((*vartrans)) /**< creates transformed user data by transforming original user data */
17306 )
17307 {
17308 assert(var != NULL);
17309 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL);
17310
17311 var->vartrans = vartrans;
17312 }
17313
17314 /** sets method to free transformed user data for the variable */
17315 void SCIPvarSetDeltransData(
17316 SCIP_VAR* var, /**< problem variable */
17317 SCIP_DECL_VARDELTRANS ((*vardeltrans)) /**< frees user data of transformed variable */
17318 )
17319 {
17320 assert(var != NULL);
17321
17322 var->vardeltrans = vardeltrans;
17323 }
17324
17325 /** sets method to copy this variable into sub-SCIPs */
17326 void SCIPvarSetCopyData(
17327 SCIP_VAR* var, /**< problem variable */
17328 SCIP_DECL_VARCOPY ((*varcopy)) /**< copy method of the variable */
17329 )
17330 {
17331 assert(var != NULL);
17332
17333 var->varcopy = varcopy;
17334 }
17335
17336 /** sets the initial flag of a variable; only possible for original or loose variables */
17337 SCIP_RETCODE SCIPvarSetInitial(
17338 SCIP_VAR* var, /**< problem variable */
17339 SCIP_Bool initial /**< initial flag */
17340 )
17341 {
17342 assert(var != NULL);
17343
17344 if( (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_ORIGINAL && (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_LOOSE )
17345 return SCIP_INVALIDCALL;
17346
17347 var->initial = initial;
17348
17349 return SCIP_OKAY;
17350 }
17351
17352 /** sets the removable flag of a variable; only possible for original or loose variables */
17353 SCIP_RETCODE SCIPvarSetRemovable(
17354 SCIP_VAR* var, /**< problem variable */
17355 SCIP_Bool removable /**< removable flag */
17356 )
17357 {
17358 assert(var != NULL);
17359
17360 if( (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_ORIGINAL && (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_LOOSE )
17361 return SCIP_INVALIDCALL;
17362
17363 var->removable = removable;
17364
17365 return SCIP_OKAY;
17366 }
17367
17368 /** gets status of variable */
17369 SCIP_VARSTATUS SCIPvarGetStatus(
17370 SCIP_VAR* var /**< problem variable */
17371 )
17372 {
17373 assert(var != NULL);
17374
17375 return (SCIP_VARSTATUS)(var->varstatus);
17376 }
17377
17378 /** returns whether the variable belongs to the original problem */
17379 SCIP_Bool SCIPvarIsOriginal(
17380 SCIP_VAR* var /**< problem variable */
17381 )
17382 {
17383 assert(var != NULL);
17384 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED || var->negatedvar != NULL);
17385
17386 return (SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL
17387 || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED
17388 && SCIPvarGetStatus(var->negatedvar) == SCIP_VARSTATUS_ORIGINAL));
17389 }
17390
17391 /** returns whether the variable belongs to the transformed problem */
17392 SCIP_Bool SCIPvarIsTransformed(
17393 SCIP_VAR* var /**< problem variable */
17394 )
17395 {
17396 assert(var != NULL);
17397 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED || var->negatedvar != NULL);
17398
17399 return (SCIPvarGetStatus(var) != SCIP_VARSTATUS_ORIGINAL
17400 && (SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED
17401 || SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_ORIGINAL));
17402 }
17403
17404 /** returns whether the variable was created by negation of a different variable */
17405 SCIP_Bool SCIPvarIsNegated(
17406 SCIP_VAR* var /**< problem variable */
17407 )
17408 {
17409 assert(var != NULL);
17410
17411 return (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
17412 }
17413
17414 /** gets type of variable */
17415 SCIP_VARTYPE SCIPvarGetType(
17416 SCIP_VAR* var /**< problem variable */
17417 )
17418 {
17419 assert(var != NULL);
17420
17421 return (SCIP_VARTYPE)(var->vartype);
17422 }
17423
17424 /** returns TRUE if the variable is of binary type; this is the case if:
17425 * (1) variable type is binary
17426 * (2) variable type is integer or implicit integer and
17427 * (i) the global lower bound is greater than or equal to zero
17428 * (ii) the global upper bound is less than or equal to one
17429 */
17430 SCIP_Bool SCIPvarIsBinary(
17431 SCIP_VAR* var /**< problem variable */
17432 )
17433 {
17434 assert(var != NULL);
17435
17436 return (SCIPvarGetType(var) == SCIP_VARTYPE_BINARY ||
17437 (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && var->glbdom.lb >= 0.0 && var->glbdom.ub <= 1.0));
17438 }
17439
17440 /** returns whether variable is of integral type (binary, integer, or implicit integer) */
17441 SCIP_Bool SCIPvarIsIntegral(
17442 SCIP_VAR* var /**< problem variable */
17443 )
17444 {
17445 assert(var != NULL);
17446
17447 return (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
17448 }
17449
17450 /** returns whether variable's column should be present in the initial root LP */
17451 SCIP_Bool SCIPvarIsInitial(
17452 SCIP_VAR* var /**< problem variable */
17453 )
17454 {
17455 assert(var != NULL);
17456
17457 return var->initial;
17458 }
17459
17460 /** returns whether variable's column is removable from the LP (due to aging or cleanup) */
17461 SCIP_Bool SCIPvarIsRemovable(
17462 SCIP_VAR* var /**< problem variable */
17463 )
17464 {
17465 assert(var != NULL);
17466
17467 return var->removable;
17468 }
17469
17470 /** returns whether the variable was deleted from the problem */
17471 SCIP_Bool SCIPvarIsDeleted(
17472 SCIP_VAR* var /**< problem variable */
17473 )
17474 {
17475 assert(var != NULL);
17476
17477 return var->deleted;
17478 }
17479
17480 /** marks the variable to be deletable, i.e., it may be deleted completely from the problem;
17481 * method can only be called before the variable is added to the problem by SCIPaddVar() or SCIPaddPricedVar()
17482 */
17483 void SCIPvarMarkDeletable(
17484 SCIP_VAR* var /**< problem variable */
17485 )
17486 {
17487 assert(var != NULL);
17488 assert(var->probindex == -1);
17489
17490 var->deletable = TRUE;
17491 }
17492
17493 /** marks the variable to be not deletable from the problem */
17494 void SCIPvarMarkNotDeletable(
17495 SCIP_VAR* var
17496 )
17497 {
17498 assert(var != NULL);
17499
17500 var->deletable = FALSE;
17501 }
17502
17503 /** marks variable to be deleted from global structures (cliques etc.) when cleaning up
17504 *
17505 * @note: this is not equivalent to marking the variable itself for deletion, this is done by using SCIPvarMarkDeletable()
17506 */
17507 void SCIPvarMarkDeleteGlobalStructures(
17508 SCIP_VAR* var /**< problem variable */
17509 )
17510 {
17511 assert(var != NULL);
17512
17513 var->delglobalstructs = TRUE;
17514 }
17515
17516 /** returns whether the variable was flagged for deletion from global structures (cliques etc.) */
17517 SCIP_Bool SCIPvarIsMarkedDeleteGlobalStructures(
17518 SCIP_VAR* var /**< problem variable */
17519 )
17520 {
17521 assert(var != NULL);
17522
17523 return var->delglobalstructs;
17524 }
17525
17526 /** returns whether a variable has been introduced to define a relaxation
17527 *
17528 * These variables are only valid for the current SCIP solve round,
17529 * they are not contained in any (checked) constraints, but may be used
17530 * in cutting planes, for example.
17531 * Relaxation-only variables are not copied by SCIPcopyVars and cuts
17532 * that contain these variables are not added as linear constraints when
17533 * restarting or transferring information from a copied SCIP to a SCIP.
17534 * Also conflicts with relaxation-only variables are not generated at
17535 * the moment.
17536 */
17537 SCIP_Bool SCIPvarIsRelaxationOnly(
17538 SCIP_VAR* var /**< problem variable */
17539 )
17540 {
17541 assert(var != NULL);
17542
17543 return var->relaxationonly;
17544 }
17545
17546 /** marks that this variable has only been introduced to define a relaxation
17547 *
17548 * The variable must not have a coefficient in the objective and must be deletable.
17549 * If it is not marked deletable, it will be marked as deletable, which is only possible
17550 * before the variable is added to a problem.
17551 *
17552 * @see SCIPvarIsRelaxationOnly
17553 * @see SCIPvarMarkDeletable
17554 */
17555 void SCIPvarMarkRelaxationOnly(
17556 SCIP_VAR* var /**< problem variable */
17557 )
17558 {
17559 assert(var != NULL);
17560 assert(SCIPvarGetObj(var) == 0.0);
17561
17562 if( !SCIPvarIsDeletable(var) )
17563 SCIPvarMarkDeletable(var);
17564
17565 var->relaxationonly = TRUE;
17566 }
17567
17568 /** returns whether variable is allowed to be deleted completely from the problem */
17569 SCIP_Bool SCIPvarIsDeletable(
17570 SCIP_VAR* var
17571 )
17572 {
17573 assert(var != NULL);
17574
17575 return var->deletable;
17576 }
17577
17578 /** returns whether variable is an active (neither fixed nor aggregated) variable */
17579 SCIP_Bool SCIPvarIsActive(
17580 SCIP_VAR* var /**< problem variable */
17581 )
17582 {
17583 assert(var != NULL);
17584
17585 return (var->probindex >= 0);
17586 }
17587
17588 /** gets unique index of variable */
17589 int SCIPvarGetIndex(
17590 SCIP_VAR* var /**< problem variable */
17591 )
17592 {
17593 assert(var != NULL);
17594
17595 return var->index;
17596 }
17597
17598 /** gets position of variable in problem, or -1 if variable is not active */
17599 int SCIPvarGetProbindex(
17600 SCIP_VAR* var /**< problem variable */
17601 )
17602 {
17603 assert(var != NULL);
17604
17605 return var->probindex;
17606 }
17607
17608 /** gets transformed variable of ORIGINAL variable */
17609 SCIP_VAR* SCIPvarGetTransVar(
17610 SCIP_VAR* var /**< problem variable */
17611 )
17612 {
17613 assert(var != NULL);
17614 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL);
17615
17616 return var->data.original.transvar;
17617 }
17618
17619 /** gets column of COLUMN variable */
17620 SCIP_COL* SCIPvarGetCol(
17621 SCIP_VAR* var /**< problem variable */
17622 )
17623 {
17624 assert(var != NULL);
17625 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
17626
17627 return var->data.col;
17628 }
17629
17630 /** returns whether the variable is a COLUMN variable that is member of the current LP */
17631 SCIP_Bool SCIPvarIsInLP(
17632 SCIP_VAR* var /**< problem variable */
17633 )
17634 {
17635 assert(var != NULL);
17636
17637 return (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN && SCIPcolIsInLP(var->data.col));
17638 }
17639
17640 /** gets aggregation variable y of an aggregated variable x = a*y + c */
17641 SCIP_VAR* SCIPvarGetAggrVar(
17642 SCIP_VAR* var /**< problem variable */
17643 )
17644 {
17645 assert(var != NULL);
17646 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED);
17647 assert(!var->donotaggr);
17648
17649 return var->data.aggregate.var;
17650 }
17651
17652 /** gets aggregation scalar a of an aggregated variable x = a*y + c */
17653 SCIP_Real SCIPvarGetAggrScalar(
17654 SCIP_VAR* var /**< problem variable */
17655 )
17656 {
17657 assert(var != NULL);
17658 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED);
17659 assert(!var->donotaggr);
17660
17661 return var->data.aggregate.scalar;
17662 }
17663
17664 /** gets aggregation constant c of an aggregated variable x = a*y + c */
17665 SCIP_Real SCIPvarGetAggrConstant(
17666 SCIP_VAR* var /**< problem variable */
17667 )
17668 {
17669 assert(var != NULL);
17670 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED);
17671 assert(!var->donotaggr);
17672
17673 return var->data.aggregate.constant;
17674 }
17675
17676 /** gets number n of aggregation variables of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
17677 int SCIPvarGetMultaggrNVars(
17678 SCIP_VAR* var /**< problem variable */
17679 )
17680 {
17681 assert(var != NULL);
17682 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
17683 assert(!var->donotmultaggr);
17684
17685 return var->data.multaggr.nvars;
17686 }
17687
17688 /** gets vector of aggregation variables y of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
17689 SCIP_VAR** SCIPvarGetMultaggrVars(
17690 SCIP_VAR* var /**< problem variable */
17691 )
17692 {
17693 assert(var != NULL);
17694 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
17695 assert(!var->donotmultaggr);
17696
17697 return var->data.multaggr.vars;
17698 }
17699
17700 /** gets vector of aggregation scalars a of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
17701 SCIP_Real* SCIPvarGetMultaggrScalars(
17702 SCIP_VAR* var /**< problem variable */
17703 )
17704 {
17705 assert(var != NULL);
17706 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
17707 assert(!var->donotmultaggr);
17708
17709 return var->data.multaggr.scalars;
17710 }
17711
17712 /** gets aggregation constant c of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
17713 SCIP_Real SCIPvarGetMultaggrConstant(
17714 SCIP_VAR* var /**< problem variable */
17715 )
17716 {
17717 assert(var != NULL);
17718 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
17719 assert(!var->donotmultaggr);
17720
17721 return var->data.multaggr.constant;
17722 }
17723
17724 /** gets the negation of the given variable; may return NULL, if no negation is existing yet */
17725 SCIP_VAR* SCIPvarGetNegatedVar(
17726 SCIP_VAR* var /**< negated problem variable */
17727 )
17728 {
17729 assert(var != NULL);
17730
17731 return var->negatedvar;
17732 }
17733
17734 /** gets the negation variable x of a negated variable x' = offset - x */
17735 SCIP_VAR* SCIPvarGetNegationVar(
17736 SCIP_VAR* var /**< negated problem variable */
17737 )
17738 {
17739 assert(var != NULL);
17740 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
17741
17742 return var->negatedvar;
17743 }
17744
17745 /** gets the negation offset of a negated variable x' = offset - x */
17746 SCIP_Real SCIPvarGetNegationConstant(
17747 SCIP_VAR* var /**< negated problem variable */
17748 )
17749 {
17750 assert(var != NULL);
17751 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
17752
17753 return var->data.negate.constant;
17754 }
17755
17756 /** gets objective function value of variable */
17757 SCIP_Real SCIPvarGetObj(
17758 SCIP_VAR* var /**< problem variable */
17759 )
17760 {
17761 assert(var != NULL);
17762
17763 return var->obj;
17764 }
17765
17766 /** gets the unchanged objective function value of a variable (ignoring temproray changes performed in probing mode) */
17767 SCIP_Real SCIPvarGetUnchangedObj(
17768 SCIP_VAR* var /**< problem variable */
17769 )
17770 {
17771 assert(var != NULL);
17772
17773 return var->unchangedobj;
17774 }
17775
17776 /** gets corresponding objective value of active, fixed, or multi-aggregated problem variable of given variable
17777 * e.g. obj(x) = 1 this method returns for ~x the value -1
17778 */
17779 SCIP_RETCODE SCIPvarGetAggregatedObj(
17780 SCIP_VAR* var, /**< problem variable */
17781 SCIP_Real* aggrobj /**< pointer to store the aggregated objective value */
17782 )
17783 {
17784 SCIP_VAR* probvar = var;
17785 SCIP_Real mult = 1.0;
17786
17787 assert(probvar != NULL);
17788 assert(aggrobj != NULL);
17789
17790 while( probvar != NULL )
17791 {
17792 switch( SCIPvarGetStatus(probvar) )
17793 {
17794 case SCIP_VARSTATUS_ORIGINAL:
17795 case SCIP_VARSTATUS_LOOSE:
17796 case SCIP_VARSTATUS_COLUMN:
17797 (*aggrobj) = mult * SCIPvarGetObj(probvar);
17798 return SCIP_OKAY;
17799
17800 case SCIP_VARSTATUS_FIXED:
17801 assert(SCIPvarGetObj(probvar) == 0.0);
17802 (*aggrobj) = 0.0;
17803 return SCIP_OKAY;
17804
17805 case SCIP_VARSTATUS_MULTAGGR:
17806 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
17807 if ( probvar->data.multaggr.nvars == 1 )
17808 {
17809 assert( probvar->data.multaggr.vars != NULL );
17810 assert( probvar->data.multaggr.scalars != NULL );
17811 assert( probvar->data.multaggr.vars[0] != NULL );
17812 mult *= probvar->data.multaggr.scalars[0];
17813 probvar = probvar->data.multaggr.vars[0];
17814 break;
17815 }
17816 else
17817 {
17818 SCIP_Real tmpobj;
17819 int v;
17820
17821 (*aggrobj) = 0.0;
17822
17823 for( v = probvar->data.multaggr.nvars - 1; v >= 0; --v )
17824 {
17825 SCIP_CALL( SCIPvarGetAggregatedObj(probvar->data.multaggr.vars[v], &tmpobj) );
17826 (*aggrobj) += probvar->data.multaggr.scalars[v] * tmpobj;
17827 }
17828 return SCIP_OKAY;
17829 }
17830
17831 case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */
17832 assert(probvar->data.aggregate.var != NULL);
17833 mult *= probvar->data.aggregate.scalar;
17834 probvar = probvar->data.aggregate.var;
17835 break;
17836
17837 case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */
17838 assert(probvar->negatedvar != NULL);
17839 assert(SCIPvarGetStatus(probvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
17840 assert(probvar->negatedvar->negatedvar == probvar);
17841 mult *= -1.0;
17842 probvar = probvar->negatedvar;
17843 break;
17844
17845 default:
17846 SCIPABORT();
17847 return SCIP_INVALIDDATA; /*lint !e527*/
17848 }
17849 }
17850
17851 return SCIP_INVALIDDATA;
17852 }
17853
17854 /** gets original lower bound of original problem variable (i.e. the bound set in problem creation) */
17855 SCIP_Real SCIPvarGetLbOriginal(
17856 SCIP_VAR* var /**< original problem variable */
17857 )
17858 {
17859 assert(var != NULL);
17860 assert(SCIPvarIsOriginal(var));
17861
17862 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL )
17863 return var->data.original.origdom.lb;
17864 else
17865 {
17866 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
17867 assert(var->negatedvar != NULL);
17868 assert(SCIPvarGetStatus(var->negatedvar) == SCIP_VARSTATUS_ORIGINAL);
17869
17870 return var->data.negate.constant - var->negatedvar->data.original.origdom.ub;
17871 }
17872 }
17873
17874 /** gets original upper bound of original problem variable (i.e. the bound set in problem creation) */
17875 SCIP_Real SCIPvarGetUbOriginal(
17876 SCIP_VAR* var /**< original problem variable */
17877 )
17878 {
17879 assert(var != NULL);
17880 assert(SCIPvarIsOriginal(var));
17881
17882 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL )
17883 return var->data.original.origdom.ub;
17884 else
17885 {
17886 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
17887 assert(var->negatedvar != NULL);
17888 assert(SCIPvarGetStatus(var->negatedvar) == SCIP_VARSTATUS_ORIGINAL);
17889
17890 return var->data.negate.constant - var->negatedvar->data.original.origdom.lb;
17891 }
17892 }
17893
17894 /** gets the original hole list of an original variable */
17895 SCIP_HOLELIST* SCIPvarGetHolelistOriginal(
17896 SCIP_VAR* var /**< problem variable */
17897 )
17898 {
17899 assert(var != NULL);
17900 assert(SCIPvarIsOriginal(var));
17901
17902 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL )
17903 return var->data.original.origdom.holelist;
17904
17905 return NULL;
17906 }
17907
17908 /** gets global lower bound of variable */
17909 SCIP_Real SCIPvarGetLbGlobal(
17910 SCIP_VAR* var /**< problem variable */
17911 )
17912 {
17913 assert(var != NULL);
17914
17915 return var->glbdom.lb;
17916 }
17917
17918 /** gets global upper bound of variable */
17919 SCIP_Real SCIPvarGetUbGlobal(
17920 SCIP_VAR* var /**< problem variable */
17921 )
17922 {
17923 assert(var != NULL);
17924
17925 return var->glbdom.ub;
17926 }
17927
17928 /** gets the global hole list of an active variable */
17929 SCIP_HOLELIST* SCIPvarGetHolelistGlobal(
17930 SCIP_VAR* var /**< problem variable */
17931 )
17932 {
17933 assert(var != NULL);
17934
17935 return var->glbdom.holelist;
17936 }
17937
17938 /** gets best global bound of variable with respect to the objective function */
17939 SCIP_Real SCIPvarGetBestBoundGlobal(
17940 SCIP_VAR* var /**< problem variable */
17941 )
17942 {
17943 assert(var != NULL);
17944
17945 if( var->obj >= 0.0 )
17946 return var->glbdom.lb;
17947 else
17948 return var->glbdom.ub;
17949 }
17950
17951 /** gets worst global bound of variable with respect to the objective function */
17952 SCIP_Real SCIPvarGetWorstBoundGlobal(
17953 SCIP_VAR* var /**< problem variable */
17954 )
17955 {
17956 assert(var != NULL);
17957
17958 if( var->obj >= 0.0 )
17959 return var->glbdom.ub;
17960 else
17961 return var->glbdom.lb;
17962 }
17963
17964 /** gets current lower bound of variable */
17965 SCIP_Real SCIPvarGetLbLocal(
17966 SCIP_VAR* var /**< problem variable */
17967 )
17968 {
17969 assert(var != NULL);
17970
17971 return var->locdom.lb;
17972 }
17973
17974 /** gets current upper bound of variable */
17975 SCIP_Real SCIPvarGetUbLocal(
17976 SCIP_VAR* var /**< problem variable */
17977 )
17978 {
17979 assert(var != NULL);
17980
17981 return var->locdom.ub;
17982 }
17983
17984 /** gets the current hole list of an active variable */
17985 SCIP_HOLELIST* SCIPvarGetHolelistLocal(
17986 SCIP_VAR* var /**< problem variable */
17987 )
17988 {
17989 assert(var != NULL);
17990
17991 return var->locdom.holelist;
17992 }
17993
17994 /** gets best local bound of variable with respect to the objective function */
17995 SCIP_Real SCIPvarGetBestBoundLocal(
17996 SCIP_VAR* var /**< problem variable */
17997 )
17998 {
17999 assert(var != NULL);
18000
18001 if( var->obj >= 0.0 )
18002 return var->locdom.lb;
18003 else
18004 return var->locdom.ub;
18005 }
18006
18007 /** gets worst local bound of variable with respect to the objective function */
18008 SCIP_Real SCIPvarGetWorstBoundLocal(
18009 SCIP_VAR* var /**< problem variable */
18010 )
18011 {
18012 assert(var != NULL);
18013
18014 if( var->obj >= 0.0 )
18015 return var->locdom.ub;
18016 else
18017 return var->locdom.lb;
18018 }
18019
18020 /** gets type (lower or upper) of best bound of variable with respect to the objective function */
18021 SCIP_BOUNDTYPE SCIPvarGetBestBoundType(
18022 SCIP_VAR* var /**< problem variable */
18023 )
18024 {
18025 assert(var != NULL);
18026
18027 if( var->obj >= 0.0 )
18028 return SCIP_BOUNDTYPE_LOWER;
18029 else
18030 return SCIP_BOUNDTYPE_UPPER;
18031 }
18032
18033 /** gets type (lower or upper) of worst bound of variable with respect to the objective function */
18034 SCIP_BOUNDTYPE SCIPvarGetWorstBoundType(
18035 SCIP_VAR* var /**< problem variable */
18036 )
18037 {
18038 assert(var != NULL);
18039
18040 if( var->obj >= 0.0 )
18041 return SCIP_BOUNDTYPE_UPPER;
18042 else
18043 return SCIP_BOUNDTYPE_LOWER;
18044 }
18045
18046 /** gets lazy lower bound of variable, returns -infinity if the variable has no lazy lower bound */
18047 SCIP_Real SCIPvarGetLbLazy(
18048 SCIP_VAR* var /**< problem variable */
18049 )
18050 {
18051 assert(var != NULL);
18052
18053 return var->lazylb;
18054 }
18055
18056 /** gets lazy upper bound of variable, returns infinity if the variable has no lazy upper bound */
18057 SCIP_Real SCIPvarGetUbLazy(
18058 SCIP_VAR* var /**< problem variable */
18059 )
18060 {
18061 assert(var != NULL);
18062
18063 return var->lazyub;
18064 }
18065
18066 /** gets the branch factor of the variable; this value can be used in the branching methods to scale the score
18067 * values of the variables; higher factor leads to a higher probability that this variable is chosen for branching
18068 */
18069 SCIP_Real SCIPvarGetBranchFactor(
18070 SCIP_VAR* var /**< problem variable */
18071 )
18072 {
18073 assert(var != NULL);
18074
18075 return var->branchfactor;
18076 }
18077
18078 /** gets the branch priority of the variable; variables with higher priority should always be preferred to variables
18079 * with lower priority
18080 */
18081 int SCIPvarGetBranchPriority(
18082 SCIP_VAR* var /**< problem variable */
18083 )
18084 {
18085 assert(var != NULL);
18086
18087 return var->branchpriority;
18088 }
18089
18090 /** gets the preferred branch direction of the variable (downwards, upwards, or auto) */
18091 SCIP_BRANCHDIR SCIPvarGetBranchDirection(
18092 SCIP_VAR* var /**< problem variable */
18093 )
18094 {
18095 assert(var != NULL);
18096
18097 return (SCIP_BRANCHDIR)var->branchdirection;
18098 }
18099
18100 /** gets number of variable lower bounds x >= b_i*z_i + d_i of given variable x */
18101 int SCIPvarGetNVlbs(
18102 SCIP_VAR* var /**< problem variable */
18103 )
18104 {
18105 assert(var != NULL);
18106
18107 return SCIPvboundsGetNVbds(var->vlbs);
18108 }
18109
18110 /** gets array with bounding variables z_i in variable lower bounds x >= b_i*z_i + d_i of given variable x;
18111 * the variable bounds are sorted by increasing variable index of the bounding variable z_i (see SCIPvarGetIndex())
18112 */
18113 SCIP_VAR** SCIPvarGetVlbVars(
18114 SCIP_VAR* var /**< problem variable */
18115 )
18116 {
18117 assert(var != NULL);
18118
18119 return SCIPvboundsGetVars(var->vlbs);
18120 }
18121
18122 /** gets array with bounding coefficients b_i in variable lower bounds x >= b_i*z_i + d_i of given variable x */
18123 SCIP_Real* SCIPvarGetVlbCoefs(
18124 SCIP_VAR* var /**< problem variable */
18125 )
18126 {
18127 assert(var != NULL);
18128
18129 return SCIPvboundsGetCoefs(var->vlbs);
18130 }
18131
18132 /** gets array with bounding constants d_i in variable lower bounds x >= b_i*z_i + d_i of given variable x */
18133 SCIP_Real* SCIPvarGetVlbConstants(
18134 SCIP_VAR* var /**< problem variable */
18135 )
18136 {
18137 assert(var != NULL);
18138
18139 return SCIPvboundsGetConstants(var->vlbs);
18140 }
18141
18142 /** gets number of variable upper bounds x <= b_i*z_i + d_i of given variable x */
18143 int SCIPvarGetNVubs(
18144 SCIP_VAR* var /**< problem variable */
18145 )
18146 {
18147 assert(var != NULL);
18148
18149 return SCIPvboundsGetNVbds(var->vubs);
18150 }
18151
18152 /** gets array with bounding variables z_i in variable upper bounds x <= b_i*z_i + d_i of given variable x;
18153 * the variable bounds are sorted by increasing variable index of the bounding variable z_i (see SCIPvarGetIndex())
18154 */
18155 SCIP_VAR** SCIPvarGetVubVars(
18156 SCIP_VAR* var /**< problem variable */
18157 )
18158 {
18159 assert(var != NULL);
18160
18161 return SCIPvboundsGetVars(var->vubs);
18162 }
18163
18164 /** gets array with bounding coefficients b_i in variable upper bounds x <= b_i*z_i + d_i of given variable x */
18165 SCIP_Real* SCIPvarGetVubCoefs(
18166 SCIP_VAR* var /**< problem variable */
18167 )
18168 {
18169 assert(var != NULL);
18170
18171 return SCIPvboundsGetCoefs(var->vubs);
18172 }
18173
18174 /** gets array with bounding constants d_i in variable upper bounds x <= b_i*z_i + d_i of given variable x */
18175 SCIP_Real* SCIPvarGetVubConstants(
18176 SCIP_VAR* var /**< problem variable */
18177 )
18178 {
18179 assert(var != NULL);
18180
18181 return SCIPvboundsGetConstants(var->vubs);
18182 }
18183
18184 /** gets number of implications y <= b or y >= b for x == 0 or x == 1 of given active problem variable x,
18185 * there are no implications for nonbinary variable x
18186 */
18187 int SCIPvarGetNImpls(
18188 SCIP_VAR* var, /**< active problem variable */
18189 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
18190 )
18191 {
18192 assert(var != NULL);
18193 assert(SCIPvarIsActive(var));
18194
18195 return SCIPimplicsGetNImpls(var->implics, varfixing);
18196 }
18197
18198 /** gets array with implication variables y of implications y <= b or y >= b for x == 0 or x == 1 of given active
18199 * problem variable x, there are no implications for nonbinary variable x;
18200 * the implications are sorted such that implications with binary implied variables precede the ones with non-binary
18201 * implied variables, and as a second criteria, the implied variables are sorted by increasing variable index
18202 * (see SCIPvarGetIndex())
18203 */
18204 SCIP_VAR** SCIPvarGetImplVars(
18205 SCIP_VAR* var, /**< active problem variable */
18206 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
18207 )
18208 {
18209 assert(var != NULL);
18210 assert(SCIPvarIsActive(var));
18211
18212 return SCIPimplicsGetVars(var->implics, varfixing);
18213 }
18214
18215 /** gets array with implication types of implications y <= b or y >= b for x == 0 or x == 1 of given active problem
18216 * variable x (SCIP_BOUNDTYPE_UPPER if y <= b, SCIP_BOUNDTYPE_LOWER if y >= b),
18217 * there are no implications for nonbinary variable x
18218 */
18219 SCIP_BOUNDTYPE* SCIPvarGetImplTypes(
18220 SCIP_VAR* var, /**< active problem variable */
18221 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
18222 )
18223 {
18224 assert(var != NULL);
18225 assert(SCIPvarIsActive(var));
18226
18227 return SCIPimplicsGetTypes(var->implics, varfixing);
18228 }
18229
18230 /** gets array with implication bounds b of implications y <= b or y >= b for x == 0 or x == 1 of given active problem
18231 * variable x, there are no implications for nonbinary variable x
18232 */
18233 SCIP_Real* SCIPvarGetImplBounds(
18234 SCIP_VAR* var, /**< active problem variable */
18235 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
18236 )
18237 {
18238 assert(var != NULL);
18239 assert(SCIPvarIsActive(var));
18240
18241 return SCIPimplicsGetBounds(var->implics, varfixing);
18242 }
18243
18244 /** Gets array with unique ids of implications y <= b or y >= b for x == 0 or x == 1 of given active problem variable x,
18245 * there are no implications for nonbinary variable x.
18246 * If an implication is a shortcut, i.e., it was added as part of the transitive closure of another implication,
18247 * its id is negative, otherwise it is nonnegative.
18248 */
18249 int* SCIPvarGetImplIds(
18250 SCIP_VAR* var, /**< active problem variable */
18251 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
18252 )
18253 {
18254 assert(var != NULL);
18255 assert(SCIPvarIsActive(var));
18256
18257 return SCIPimplicsGetIds(var->implics, varfixing);
18258 }
18259
18260 /** gets number of cliques, the active variable is contained in */
18261 int SCIPvarGetNCliques(
18262 SCIP_VAR* var, /**< active problem variable */
18263 SCIP_Bool varfixing /**< FALSE for cliques containing x == 0, TRUE for x == 1 */
18264 )
18265 {
18266 assert(var != NULL);
18267
18268 return SCIPcliquelistGetNCliques(var->cliquelist, varfixing);
18269 }
18270
18271 /** gets array of cliques, the active variable is contained in */
18272 SCIP_CLIQUE** SCIPvarGetCliques(
18273 SCIP_VAR* var, /**< active problem variable */
18274 SCIP_Bool varfixing /**< FALSE for cliques containing x == 0, TRUE for x == 1 */
18275 )
18276 {
18277 assert(var != NULL);
18278
18279 return SCIPcliquelistGetCliques(var->cliquelist, varfixing);
18280 }
18281
18282 /** gets primal LP solution value of variable */
18283 SCIP_Real SCIPvarGetLPSol(
18284 SCIP_VAR* var /**< problem variable */
18285 )
18286 {
18287 assert(var != NULL);
18288
18289 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
18290 return SCIPcolGetPrimsol(var->data.col);
18291 else
18292 return SCIPvarGetLPSol_rec(var);
18293 }
18294
18295 /** gets primal NLP solution value of variable */
18296 SCIP_Real SCIPvarGetNLPSol(
18297 SCIP_VAR* var /**< problem variable */
18298 )
18299 {
18300 assert(var != NULL);
18301
18302 if( (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE) )
18303 return var->nlpsol;
18304 else
18305 return SCIPvarGetNLPSol_rec(var);
18306 }
18307
18308 /** return lower bound change info at requested position */
18309 SCIP_BDCHGINFO* SCIPvarGetBdchgInfoLb(
18310 SCIP_VAR* var, /**< problem variable */
18311 int pos /**< requested position */
18312 )
18313 {
18314 assert(pos >= 0);
18315 assert(pos < var->nlbchginfos);
18316
18317 return &var->lbchginfos[pos];
18318 }
18319
18320 /** gets the number of lower bound change info array */
18321 int SCIPvarGetNBdchgInfosLb(
18322 SCIP_VAR* var /**< problem variable */
18323 )
18324 {
18325 return var->nlbchginfos;
18326 }
18327
18328 /** return upper bound change info at requested position */
18329 SCIP_BDCHGINFO* SCIPvarGetBdchgInfoUb(
18330 SCIP_VAR* var, /**< problem variable */
18331 int pos /**< requested position */
18332 )
18333 {
18334 assert(pos >= 0);
18335 assert(pos < var->nubchginfos);
18336
18337 return &var->ubchginfos[pos];
18338 }
18339
18340 /** gets the number upper bound change info array */
18341 int SCIPvarGetNBdchgInfosUb(
18342 SCIP_VAR* var /**< problem variable */
18343 )
18344 {
18345 assert(var != NULL);
18346
18347 return var->nubchginfos;
18348 }
18349
18350 /** returns the value based history for the variable */
18351 SCIP_VALUEHISTORY* SCIPvarGetValuehistory(
18352 SCIP_VAR* var /**< problem variable */
18353 )
18354 {
18355 assert(var != NULL);
18356
18357 return var->valuehistory;
18358 }
18359
18360 /** gets pseudo solution value of variable */
18361 SCIP_Real SCIPvarGetPseudoSol(
18362 SCIP_VAR* var /**< problem variable */
18363 )
18364 {
18365 assert(var != NULL);
18366
18367 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
18368 return SCIPvarGetBestBoundLocal(var);
18369 else
18370 return SCIPvarGetPseudoSol_rec(var);
18371 }
18372
18373 /** returns the variable's VSIDS score */
18374 SCIP_Real SCIPvarGetVSIDS(
18375 SCIP_VAR* var, /**< problem variable */
18376 SCIP_STAT* stat, /**< problem statistics */
18377 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
18378 )
18379 {
18380 assert(var != NULL);
18381
18382 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
18383 return SCIPhistoryGetVSIDS(var->history, dir)/stat->vsidsweight;
18384 else
18385 return SCIPvarGetVSIDS_rec(var, stat, dir);
18386 }
18387
18388 /** includes event handler with given data in variable's event filter */
18389 SCIP_RETCODE SCIPvarCatchEvent(
18390 SCIP_VAR* var, /**< problem variable */
18391 BMS_BLKMEM* blkmem, /**< block memory */
18392 SCIP_SET* set, /**< global SCIP settings */
18393 SCIP_EVENTTYPE eventtype, /**< event type to catch */
18394 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
18395 SCIP_EVENTDATA* eventdata, /**< event data to pass to the event handler for the event processing */
18396 int* filterpos /**< pointer to store position of event filter entry, or NULL */
18397 )
18398 {
18399 assert(var != NULL);
18400 assert(set != NULL);
18401 assert(var->scip == set->scip);
18402 assert(var->eventfilter != NULL);
18403 assert((eventtype & ~SCIP_EVENTTYPE_VARCHANGED) == 0);
18404 assert((eventtype & SCIP_EVENTTYPE_VARCHANGED) != 0);
18405 assert(SCIPvarIsTransformed(var));
18406
18407 SCIPsetDebugMsg(set, "catch event of type 0x%" SCIP_EVENTTYPE_FORMAT " of variable <%s> with handler %p and data %p\n",
18408 eventtype, var->name, (void*)eventhdlr, (void*)eventdata);
18409
18410 SCIP_CALL( SCIPeventfilterAdd(var->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) );
18411
18412 return SCIP_OKAY;
18413 }
18414
18415 /** deletes event handler with given data from variable's event filter */
18416 SCIP_RETCODE SCIPvarDropEvent(
18417 SCIP_VAR* var, /**< problem variable */
18418 BMS_BLKMEM* blkmem, /**< block memory */
18419 SCIP_SET* set, /**< global SCIP settings */
18420 SCIP_EVENTTYPE eventtype, /**< event type mask of dropped event */
18421 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
18422 SCIP_EVENTDATA* eventdata, /**< event data to pass to the event handler for the event processing */
18423 int filterpos /**< position of event filter entry returned by SCIPvarCatchEvent(), or -1 */
18424 )
18425 {
18426 assert(var != NULL);
18427 assert(set != NULL);
18428 assert(var->scip == set->scip);
18429 assert(var->eventfilter != NULL);
18430 assert(SCIPvarIsTransformed(var));
18431
18432 SCIPsetDebugMsg(set, "drop event of variable <%s> with handler %p and data %p\n", var->name, (void*)eventhdlr,
18433 (void*)eventdata);
18434
18435 SCIP_CALL( SCIPeventfilterDel(var->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) );
18436
18437 return SCIP_OKAY;
18438 }
18439
18440 /** returns the position of the bound change index */
18441 int SCIPbdchgidxGetPos(
18442 SCIP_BDCHGIDX* bdchgidx /**< bound change index */
18443 )
18444 {
18445 assert(bdchgidx != NULL);
18446
18447 return bdchgidx->pos;
18448 }
18449
18450 /** returns whether first bound change index belongs to an earlier applied bound change than second one */
18451 SCIP_Bool SCIPbdchgidxIsEarlierNonNull(
18452 SCIP_BDCHGIDX* bdchgidx1, /**< first bound change index */
18453 SCIP_BDCHGIDX* bdchgidx2 /**< second bound change index */
18454 )
18455 {
18456 assert(bdchgidx1 != NULL);
18457 assert(bdchgidx1->depth >= -2);
18458 assert(bdchgidx1->pos >= 0);
18459 assert(bdchgidx2 != NULL);
18460 assert(bdchgidx2->depth >= -2);
18461 assert(bdchgidx2->pos >= 0);
18462
18463 return (bdchgidx1->depth < bdchgidx2->depth)
18464 || (bdchgidx1->depth == bdchgidx2->depth && (bdchgidx1->pos < bdchgidx2->pos));
18465 }
18466
18467 /** returns whether first bound change index belongs to an earlier applied bound change than second one;
18468 * if a bound change index is NULL, the bound change index represents the current time, i.e. the time after the
18469 * last bound change was applied to the current node
18470 */
18471 SCIP_Bool SCIPbdchgidxIsEarlier(
18472 SCIP_BDCHGIDX* bdchgidx1, /**< first bound change index, or NULL */
18473 SCIP_BDCHGIDX* bdchgidx2 /**< second bound change index, or NULL */
18474 )
18475 {
18476 assert(bdchgidx1 == NULL || bdchgidx1->depth >= -2);
18477 assert(bdchgidx1 == NULL || bdchgidx1->pos >= 0);
18478 assert(bdchgidx2 == NULL || bdchgidx2->depth >= -2);
18479 assert(bdchgidx2 == NULL || bdchgidx2->pos >= 0);
18480
18481 if( bdchgidx1 == NULL )
18482 return FALSE;
18483 else if( bdchgidx2 == NULL )
18484 return TRUE;
18485 else
18486 return (bdchgidx1->depth < bdchgidx2->depth)
18487 || (bdchgidx1->depth == bdchgidx2->depth && (bdchgidx1->pos < bdchgidx2->pos));
18488 }
18489
18490 /** returns old bound that was overwritten for given bound change information */
18491 SCIP_Real SCIPbdchginfoGetOldbound(
18492 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18493 )
18494 {
18495 assert(bdchginfo != NULL);
18496
18497 return bdchginfo->oldbound;
18498 }
18499
18500 /** returns new bound installed for given bound change information */
18501 SCIP_Real SCIPbdchginfoGetNewbound(
18502 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18503 )
18504 {
18505 assert(bdchginfo != NULL);
18506
18507 return bdchginfo->newbound;
18508 }
18509
18510 /** returns variable that belongs to the given bound change information */
18511 SCIP_VAR* SCIPbdchginfoGetVar(
18512 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18513 )
18514 {
18515 assert(bdchginfo != NULL);
18516
18517 return bdchginfo->var;
18518 }
18519
18520 /** returns whether the bound change information belongs to a branching decision or a deduction */
18521 SCIP_BOUNDCHGTYPE SCIPbdchginfoGetChgtype(
18522 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18523 )
18524 {
18525 assert(bdchginfo != NULL);
18526
18527 return (SCIP_BOUNDCHGTYPE)(bdchginfo->boundchgtype);
18528 }
18529
18530 /** returns whether the bound change information belongs to a lower or upper bound change */
18531 SCIP_BOUNDTYPE SCIPbdchginfoGetBoundtype(
18532 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18533 )
18534 {
18535 assert(bdchginfo != NULL);
18536
18537 return (SCIP_BOUNDTYPE)(bdchginfo->boundtype);
18538 }
18539
18540 /** returns depth level of given bound change information */
18541 int SCIPbdchginfoGetDepth(
18542 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18543 )
18544 {
18545 assert(bdchginfo != NULL);
18546
18547 return bdchginfo->bdchgidx.depth;
18548 }
18549
18550 /** returns bound change position in its depth level of given bound change information */
18551 int SCIPbdchginfoGetPos(
18552 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18553 )
18554 {
18555 assert(bdchginfo != NULL);
18556
18557 return bdchginfo->bdchgidx.pos;
18558 }
18559
18560 /** returns bound change index of given bound change information */
18561 SCIP_BDCHGIDX* SCIPbdchginfoGetIdx(
18562 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18563 )
18564 {
18565 assert(bdchginfo != NULL);
18566
18567 return &bdchginfo->bdchgidx;
18568 }
18569
18570 /** returns inference variable of given bound change information */
18571 SCIP_VAR* SCIPbdchginfoGetInferVar(
18572 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18573 )
18574 {
18575 assert(bdchginfo != NULL);
18576 assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER
18577 || (SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER);
18578
18579 return bdchginfo->inferencedata.var;
18580 }
18581
18582 /** returns inference constraint of given bound change information */
18583 SCIP_CONS* SCIPbdchginfoGetInferCons(
18584 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18585 )
18586 {
18587 assert(bdchginfo != NULL);
18588 assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER);
18589 assert(bdchginfo->inferencedata.reason.cons != NULL);
18590
18591 return bdchginfo->inferencedata.reason.cons;
18592 }
18593
18594 /** returns inference propagator of given bound change information, or NULL if no propagator was responsible */
18595 SCIP_PROP* SCIPbdchginfoGetInferProp(
18596 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18597 )
18598 {
18599 assert(bdchginfo != NULL);
18600 assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER);
18601
18602 return bdchginfo->inferencedata.reason.prop;
18603 }
18604
18605 /** returns inference user information of given bound change information */
18606 int SCIPbdchginfoGetInferInfo(
18607 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18608 )
18609 {
18610 assert(bdchginfo != NULL);
18611 assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER
18612 || (SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER);
18613
18614 return bdchginfo->inferencedata.info;
18615 }
18616
18617 /** returns inference bound of inference variable of given bound change information */
18618 SCIP_BOUNDTYPE SCIPbdchginfoGetInferBoundtype(
18619 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18620 )
18621 {
18622 assert(bdchginfo != NULL);
18623 assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER
18624 || (SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER);
18625
18626 return (SCIP_BOUNDTYPE)(bdchginfo->inferboundtype);
18627 }
18628
18629 /** returns the relaxed bound change type */
18630 SCIP_Real SCIPbdchginfoGetRelaxedBound(
18631 SCIP_BDCHGINFO* bdchginfo /**< bound change to add to the conflict set */
18632 )
18633 {
18634 return ((SCIP_BOUNDTYPE)(bdchginfo->boundtype) == SCIP_BOUNDTYPE_LOWER ? bdchginfo->var->conflictrelaxedlb : bdchginfo->var->conflictrelaxedub);
18635 }
18636
18637
18638 /** returns whether the bound change information belongs to a redundant bound change */
18639 SCIP_Bool SCIPbdchginfoIsRedundant(
18640 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18641 )
18642 {
18643 assert(bdchginfo != NULL);
18644 assert(bdchginfo->redundant == (bdchginfo->oldbound == bdchginfo->newbound)); /*lint !e777*/
18645
18646 return bdchginfo->redundant;
18647 }
18648
18649 /** returns whether the bound change has an inference reason (constraint or propagator), that can be resolved */
18650 SCIP_Bool SCIPbdchginfoHasInferenceReason(
18651 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18652 )
18653 {
18654 assert(bdchginfo != NULL);
18655
18656 return ((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER)
18657 || ((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER
18658 && bdchginfo->inferencedata.reason.prop != NULL);
18659 }
18660
18661 /** for two bound change informations belonging to the same variable and bound, returns whether the first bound change
18662 * has a tighter new bound as the second bound change
18663 */
18664 SCIP_Bool SCIPbdchginfoIsTighter(
18665 SCIP_BDCHGINFO* bdchginfo1, /**< first bound change information */
18666 SCIP_BDCHGINFO* bdchginfo2 /**< second bound change information */
18667 )
18668 {
18669 assert(bdchginfo1 != NULL);
18670 assert(bdchginfo2 != NULL);
18671 assert(bdchginfo1->var == bdchginfo2->var);
18672 assert(bdchginfo1->boundtype == bdchginfo2->boundtype);
18673
18674 return (SCIPbdchginfoGetBoundtype(bdchginfo1) == SCIP_BOUNDTYPE_LOWER
18675 ? bdchginfo1->newbound > bdchginfo2->newbound
18676 : bdchginfo1->newbound < bdchginfo2->newbound);
18677 }
18678