Scippy

SCIP

Solving Constraint Integer Programs

var.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file var.c
26 * @ingroup OTHER_CFILES
27 * @brief methods for problem variables
28 * @author Tobias Achterberg
29 * @author Timo Berthold
30 * @author Gerald Gamrath
31 * @author Stefan Heinz
32 * @author Marc Pfetsch
33 * @author Michael Winkler
34 * @author Kati Wolter
35 * @author Stefan Vigerske
36 *
37 * @todo Possibly implement the access of bounds of multi-aggregated variables by accessing the
38 * corresponding linear constraint if it exists. This seems to require some work, since the linear
39 * constraint has to be stored. Moreover, it has even to be created in case the original constraint
40 * was deleted after multi-aggregation, but the bounds of the multi-aggregated variable should be
41 * changed. This has to be done with care in order to not loose the performance gains of
42 * multi-aggregation.
43 */
44
45/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
46
47#include "scip/cons.h"
48#include "scip/event.h"
49#include "scip/history.h"
50#include "scip/implics.h"
51#include "scip/lp.h"
52#include "scip/primal.h"
53#include "scip/prob.h"
54#include "scip/pub_cons.h"
55#include "scip/pub_history.h"
56#include "scip/pub_implics.h"
57#include "scip/pub_lp.h"
58#include "scip/pub_message.h"
59#include "scip/pub_misc.h"
60#include "scip/pub_misc_sort.h"
61#include "scip/pub_prop.h"
62#include "scip/pub_var.h"
63#include "scip/relax.h"
64#include "scip/set.h"
65#include "scip/sol.h"
66#include "scip/stat.h"
67#include "scip/struct_event.h"
68#include "scip/struct_lp.h"
69#include "scip/struct_prob.h"
70#include "scip/struct_set.h"
71#include "scip/struct_stat.h"
72#include "scip/struct_var.h"
73#include "scip/tree.h"
74#include "scip/var.h"
75#include <string.h>
76
77#define MAXIMPLSCLOSURE 100 /**< maximal number of descendants of implied variable for building closure
78 * in implication graph */
79#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds added due to implications */
80
81
82/*
83 * Debugging variable release and capture
84 *
85 * Define DEBUGUSES_VARNAME to the name of the variable for which to print
86 * a backtrace when it is captured and released.
87 * Optionally define DEBUGUSES_PROBNAME to the name of a SCIP problem to consider.
88 * Have DEBUGUSES_NOADDR2LINE defined if you do not have addr2line installed on your system.
89 */
90/* #define DEBUGUSES_VARNAME "t_t_b7" */
91/* #define DEBUGUSES_PROBNAME "t_st_e35_rens" */
92/* #define DEBUGUSES_NOADDR2LINE */
93
94#ifdef DEBUGUSES_VARNAME
95#include <execinfo.h>
96#include <stdio.h>
97#include <stdlib.h>
98#include "scip/struct_scip.h"
99
100/** obtains a backtrace and prints it to stdout. */
101static
102void print_backtrace(void)
103{
104 void* array[10];
105 char** strings;
106 int size;
107 int i;
108
109 size = backtrace(array, 10);
110 strings = backtrace_symbols(array, size);
111 if( strings == NULL )
112 return;
113
114 /* skip first entry, which is the print_backtrace function */
115 for( i = 1; i < size; ++i )
116 {
117 /* if string is something like
118 * /path/to/scip/bin/../lib/shared/libscip-7.0.1.3.linux.x86_64.gnu.dbg.so(+0x2675dd3)
119 * (that is, no function name because it is a inlined function), then call
120 * addr2line -e <libname> <addr> to get func and code line
121 * dladdr() may be an alternative
122 */
123 char* openpar;
124 char* closepar = NULL;
125#ifndef DEBUGUSES_NOADDR2LINE
126 openpar = strchr(strings[i], '(');
127 if( openpar != NULL && openpar[1] == '+' )
128 closepar = strchr(openpar+2, ')');
129#endif
130 if( closepar != NULL )
131 {
132 char cmd[SCIP_MAXSTRLEN];
133 (void) SCIPsnprintf(cmd, SCIP_MAXSTRLEN, "addr2line -f -p -e \"%.*s\" %.*s", openpar - strings[i], strings[i], closepar-openpar-1, openpar+1);
134 printf(" ");
135 fflush(stdout);
136 system(cmd);
137 }
138 else
139 printf(" %s\n", strings[i]);
140 }
141
142 free(strings);
143}
144#endif
145
146/*
147 * hole, holelist, and domain methods
148 */
149
150/** creates a new holelist element */
151static
153 SCIP_HOLELIST** holelist, /**< pointer to holelist to create */
154 BMS_BLKMEM* blkmem, /**< block memory for target holelist */
155 SCIP_SET* set, /**< global SCIP settings */
156 SCIP_Real left, /**< left bound of open interval in new hole */
157 SCIP_Real right /**< right bound of open interval in new hole */
158 )
159{
160 assert(holelist != NULL);
161 assert(blkmem != NULL);
162 assert(SCIPsetIsLT(set, left, right));
163
164 SCIPsetDebugMsg(set, "create hole list element (%.15g,%.15g) in blkmem %p\n", left, right, (void*)blkmem);
165
166 SCIP_ALLOC( BMSallocBlockMemory(blkmem, holelist) );
167 (*holelist)->hole.left = left;
168 (*holelist)->hole.right = right;
169 (*holelist)->next = NULL;
170
171 return SCIP_OKAY;
172}
173
174/** frees all elements in the holelist */
175static
177 SCIP_HOLELIST** holelist, /**< pointer to holelist to free */
178 BMS_BLKMEM* blkmem /**< block memory for target holelist */
179 )
180{
181 assert(holelist != NULL);
182 assert(blkmem != NULL);
183
184 while( *holelist != NULL )
185 {
186 SCIP_HOLELIST* next;
187
188 SCIPdebugMessage("free hole list element (%.15g,%.15g) in blkmem %p\n",
189 (*holelist)->hole.left, (*holelist)->hole.right, (void*)blkmem);
190
191 next = (*holelist)->next;
192 BMSfreeBlockMemory(blkmem, holelist);
193 assert(*holelist == NULL);
194
195 *holelist = next;
196 }
197 assert(*holelist == NULL);
198}
199
200/** duplicates a list of holes */
201static
203 SCIP_HOLELIST** target, /**< pointer to target holelist */
204 BMS_BLKMEM* blkmem, /**< block memory for target holelist */
205 SCIP_SET* set, /**< global SCIP settings */
206 SCIP_HOLELIST* source /**< holelist to duplicate */
207 )
208{
209 assert(target != NULL);
210
211 while( source != NULL )
212 {
213 assert(source->next == NULL || SCIPsetIsGE(set, source->next->hole.left, source->hole.right));
214 SCIP_CALL( holelistCreate(target, blkmem, set, source->hole.left, source->hole.right) );
215 source = source->next;
216 target = &(*target)->next;
217 }
218
219 return SCIP_OKAY;
220}
221
222/** adds a hole to the domain */
223static
225 SCIP_DOM* dom, /**< domain to add hole to */
226 BMS_BLKMEM* blkmem, /**< block memory */
227 SCIP_SET* set, /**< global SCIP settings */
228 SCIP_Real left, /**< left bound of open interval in new hole */
229 SCIP_Real right, /**< right bound of open interval in new hole */
230 SCIP_Bool* added /**< pointer to store whether the hole was added (variable didn't had that hole before), or NULL */
231 )
232{
233 SCIP_HOLELIST** insertpos;
234 SCIP_HOLELIST* next;
235
236 assert(dom != NULL);
237 assert(added != NULL);
238
239 /* search for the position of the new hole */
240 insertpos = &dom->holelist;
241 while( *insertpos != NULL && (*insertpos)->hole.left < left )
242 insertpos = &(*insertpos)->next;
243
244 /* check if new hole already exists in the hole list or is a sub hole of an existing one */
245 if( *insertpos != NULL && (*insertpos)->hole.left == left && (*insertpos)->hole.right >= right ) /*lint !e777 */
246 {
247 SCIPsetDebugMsg(set, "new hole (%.15g,%.15g) is redundant through known hole (%.15g,%.15g)\n",
248 left, right, (*insertpos)->hole.left, (*insertpos)->hole.right);
249 *added = FALSE;
250 return SCIP_OKAY;
251 }
252
253 /* add hole */
254 *added = TRUE;
255
256 next = *insertpos;
257 SCIP_CALL( holelistCreate(insertpos, blkmem, set, left, right) );
258 (*insertpos)->next = next;
259
260 return SCIP_OKAY;
261}
262
263/** merges overlapping holes into single holes, computes and moves lower and upper bound, respectively */
264/**@todo the domMerge() method is currently called if a lower or an upper bound locally or globally changed; this could
265 * be more efficient if performed with the knowledge if it was a lower or an upper bound which triggered this
266 * merge */
267static
269 SCIP_DOM* dom, /**< domain to merge */
270 BMS_BLKMEM* blkmem, /**< block memory */
271 SCIP_SET* set, /**< global SCIP settings */
272 SCIP_Real* newlb, /**< pointer to store new lower bound */
273 SCIP_Real* newub /**< pointer to store new upper bound */
274 )
275{
276 SCIP_HOLELIST** holelistptr;
277 SCIP_HOLELIST** lastnextptr;
278 SCIP_Real* lastrightptr;
279
280 assert(dom != NULL);
281 assert(SCIPsetIsLE(set, dom->lb, dom->ub));
282
283#ifndef NDEBUG
284 {
285 /* check if the holelist is sorted w.r.t. to the left interval bounds */
286 SCIP_Real lastleft;
287
288 holelistptr = &dom->holelist;
289
290 lastleft = -SCIPsetInfinity(set);
291
292 while( *holelistptr != NULL )
293 {
294 if( (*holelistptr)->next != NULL )
295 {
296 assert( SCIPsetIsLE(set, lastleft, (*holelistptr)->hole.left) );
297 lastleft = (*holelistptr)->hole.left;
298 }
299
300 holelistptr = &(*holelistptr)->next;
301 }
302 }
303#endif
304
305 SCIPsetDebugMsg(set, "merge hole list\n");
306
307 holelistptr = &dom->holelist;
308 lastrightptr = &dom->lb; /* lower bound is the right bound of the hole (-infinity,lb) */
309 lastnextptr = holelistptr;
310
311 while( *holelistptr != NULL )
312 {
313 SCIPsetDebugMsg(set, "check hole (%.15g,%.15g) last right interval was <%.15g>\n", (*holelistptr)->hole.left, (*holelistptr)->hole.right, *lastrightptr);
314
315 /* check that the hole is not empty */
316 assert(SCIPsetIsLT(set, (*holelistptr)->hole.left, (*holelistptr)->hole.right));
317
318 if( SCIPsetIsGE(set, (*holelistptr)->hole.left, dom->ub) )
319 {
320 /* the remaining holes start behind the upper bound: remove them */
321 SCIPsetDebugMsg(set, "remove remaining hole since upper bound <%.15g> is less then the left hand side of the current hole\n", dom->ub);
322 holelistFree(holelistptr, blkmem);
323 assert(*holelistptr == NULL);
324
325 /* unlink this hole from the previous hole */
326 *lastnextptr = NULL;
327 }
328 else if( SCIPsetIsGT(set, (*holelistptr)->hole.right, dom->ub) )
329 {
330 /* the hole overlaps the upper bound: decrease upper bound, remove this hole and all remaining holes */
331 SCIPsetDebugMsg(set, "upper bound <%.15g> lays in current hole; store new upper bound and remove this and all remaining holes\n", dom->ub);
332
333 assert(SCIPsetIsLT(set, (*holelistptr)->hole.left, dom->ub));
334
335 /* adjust upper bound */
336 dom->ub = (*holelistptr)->hole.left;
337
338 if(newub != NULL )
339 *newub = (*holelistptr)->hole.left;
340
341 /* remove remaining hole list */
342 holelistFree(holelistptr, blkmem);
343 assert(*holelistptr == NULL);
344
345 /* unlink this hole from the previous hole */
346 *lastnextptr = NULL;
347 }
348 else if( SCIPsetIsGT(set, *lastrightptr, (*holelistptr)->hole.left) )
349 {
350 /* the right bound of the last hole is greater than the left bound of this hole: increase the right bound of
351 * the last hole, delete this hole */
352 SCIP_HOLELIST* nextholelist;
353
354 if( SCIPsetIsEQ(set, *lastrightptr, dom->lb ) )
355 {
356 /* the reason for the overlap results from the lower bound hole (-infinity,lb); therefore, we can increase
357 * the lower bound */
358 SCIPsetDebugMsg(set, "lower bound <%.15g> lays in current hole; store new lower bound and remove hole\n", dom->lb);
359 *lastrightptr = MAX(*lastrightptr, (*holelistptr)->hole.right);
360
361 /* adjust lower bound */
362 dom->lb = *lastrightptr;
363
364 if(newlb != NULL )
365 *newlb = *lastrightptr;
366 }
367 else
368 {
369 SCIPsetDebugMsg(set, "current hole overlaps with the previous one (...,%.15g); merge to (...,%.15g)\n",
370 *lastrightptr, MAX(*lastrightptr, (*holelistptr)->hole.right) );
371 *lastrightptr = MAX(*lastrightptr, (*holelistptr)->hole.right);
372 }
373 nextholelist = (*holelistptr)->next;
374 (*holelistptr)->next = NULL;
375 holelistFree(holelistptr, blkmem);
376
377 /* connect the linked list after removing the hole */
378 *lastnextptr = nextholelist;
379
380 /* get next hole */
381 *holelistptr = nextholelist;
382 }
383 else
384 {
385 /* the holes do not overlap: update lastholelist and lastrightptr */
386 lastrightptr = &(*holelistptr)->hole.right;
387 lastnextptr = &(*holelistptr)->next;
388
389 /* get next hole */
390 holelistptr = &(*holelistptr)->next;
391 }
392 }
393
394#ifndef NDEBUG
395 {
396 /* check that holes are merged */
397 SCIP_Real lastright;
398
399 lastright = dom->lb; /* lower bound is the right bound of the hole (-infinity,lb) */
400 holelistptr = &dom->holelist;
401
402 while( *holelistptr != NULL )
403 {
404 /* check the the last right interval is smaller or equal to the current left interval (none overlapping) */
405 assert( SCIPsetIsLE(set, lastright, (*holelistptr)->hole.left) );
406
407 /* check the hole property (check that the hole is not empty) */
408 assert( SCIPsetIsLT(set, (*holelistptr)->hole.left, (*holelistptr)->hole.right) );
409 lastright = (*holelistptr)->hole.right;
410
411 /* get next hole */
412 holelistptr = &(*holelistptr)->next;
413 }
414
415 /* check the the last right interval is smaller or equal to the upper bound (none overlapping) */
416 assert( SCIPsetIsLE(set, lastright, dom->ub) );
417 }
418#endif
419}
420
421/*
422 * domain change methods
423 */
424
425/** ensures, that bound change info array for lower bound changes can store at least num entries */
426static
428 SCIP_VAR* var, /**< problem variable */
429 BMS_BLKMEM* blkmem, /**< block memory */
430 SCIP_SET* set, /**< global SCIP settings */
431 int num /**< minimum number of entries to store */
432 )
433{
434 assert(var != NULL);
435 assert(var->nlbchginfos <= var->lbchginfossize);
436 assert(SCIPvarIsTransformed(var));
437
438 if( num > var->lbchginfossize )
439 {
440 int newsize;
441
442 newsize = SCIPsetCalcMemGrowSize(set, num);
443 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->lbchginfos, var->lbchginfossize, newsize) );
444 var->lbchginfossize = newsize;
445 }
446 assert(num <= var->lbchginfossize);
447
448 return SCIP_OKAY;
449}
450
451/** ensures, that bound change info array for upper bound changes can store at least num entries */
452static
454 SCIP_VAR* var, /**< problem variable */
455 BMS_BLKMEM* blkmem, /**< block memory */
456 SCIP_SET* set, /**< global SCIP settings */
457 int num /**< minimum number of entries to store */
458 )
459{
460 assert(var != NULL);
461 assert(var->nubchginfos <= var->ubchginfossize);
462 assert(SCIPvarIsTransformed(var));
463
464 if( num > var->ubchginfossize )
465 {
466 int newsize;
467
468 newsize = SCIPsetCalcMemGrowSize(set, num);
469 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->ubchginfos, var->ubchginfossize, newsize) );
470 var->ubchginfossize = newsize;
471 }
472 assert(num <= var->ubchginfossize);
473
474 return SCIP_OKAY;
475}
476
477/** adds domain change info to the variable's lower bound change info array */
478static
480 SCIP_VAR* var, /**< problem variable */
481 BMS_BLKMEM* blkmem, /**< block memory */
482 SCIP_SET* set, /**< global SCIP settings */
483 SCIP_Real oldbound, /**< old value for bound */
484 SCIP_Real newbound, /**< new value for bound */
485 int depth, /**< depth in the tree, where the bound change takes place */
486 int pos, /**< position of the bound change in its bound change array */
487 SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself) */
488 SCIP_CONS* infercons, /**< constraint that inferred this bound change, or NULL */
489 SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
490 int inferinfo, /**< user information for inference to help resolving the conflict */
491 SCIP_BOUNDTYPE inferboundtype, /**< type of bound for inference var: lower or upper bound */
492 SCIP_BOUNDCHGTYPE boundchgtype /**< bound change type: branching decision or inferred bound change */
493 )
494{
495 assert(var != NULL);
496 assert(SCIPsetIsLT(set, oldbound, newbound));
499 assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, oldbound, 0.0));
500 assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, 1.0));
501 assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
502 assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
503 assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
504
505 SCIPsetDebugMsg(set, "adding lower bound change info to var <%s>[%g,%g]: depth=%d, pos=%d, infer%s=<%s>, inferinfo=%d, %g -> %g\n",
506 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, depth, pos, infercons != NULL ? "cons" : "prop",
507 infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo,
508 oldbound, newbound);
509
510 SCIP_CALL( varEnsureLbchginfosSize(var, blkmem, set, var->nlbchginfos+1) );
511 var->lbchginfos[var->nlbchginfos].oldbound = oldbound;
512 var->lbchginfos[var->nlbchginfos].newbound = newbound;
513 var->lbchginfos[var->nlbchginfos].var = var;
514 var->lbchginfos[var->nlbchginfos].bdchgidx.depth = depth;
515 var->lbchginfos[var->nlbchginfos].bdchgidx.pos = pos;
516 var->lbchginfos[var->nlbchginfos].pos = var->nlbchginfos; /*lint !e732*/
517 var->lbchginfos[var->nlbchginfos].boundchgtype = boundchgtype; /*lint !e641*/
518 var->lbchginfos[var->nlbchginfos].boundtype = SCIP_BOUNDTYPE_LOWER; /*lint !e641*/
520 var->lbchginfos[var->nlbchginfos].inferboundtype = inferboundtype; /*lint !e641*/
521 var->lbchginfos[var->nlbchginfos].inferencedata.var = infervar;
522 var->lbchginfos[var->nlbchginfos].inferencedata.info = inferinfo;
523
524 /**@note The "pos" data member of the bound change info has a size of 27 bits */
525 assert(var->nlbchginfos < 1 << 27);
526
527 switch( boundchgtype )
528 {
530 break;
532 assert(infercons != NULL);
533 var->lbchginfos[var->nlbchginfos].inferencedata.reason.cons = infercons;
534 break;
536 var->lbchginfos[var->nlbchginfos].inferencedata.reason.prop = inferprop;
537 break;
538 default:
539 SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
540 return SCIP_INVALIDDATA;
541 }
542
543 var->nlbchginfos++;
544
545 assert(var->nlbchginfos < 2
547 &var->lbchginfos[var->nlbchginfos-1].bdchgidx));
548
549 return SCIP_OKAY;
550}
551
552/** adds domain change info to the variable's upper bound change info array */
553static
555 SCIP_VAR* var, /**< problem variable */
556 BMS_BLKMEM* blkmem, /**< block memory */
557 SCIP_SET* set, /**< global SCIP settings */
558 SCIP_Real oldbound, /**< old value for bound */
559 SCIP_Real newbound, /**< new value for bound */
560 int depth, /**< depth in the tree, where the bound change takes place */
561 int pos, /**< position of the bound change in its bound change array */
562 SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself) */
563 SCIP_CONS* infercons, /**< constraint that inferred this bound change, or NULL */
564 SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
565 int inferinfo, /**< user information for inference to help resolving the conflict */
566 SCIP_BOUNDTYPE inferboundtype, /**< type of bound for inference var: lower or upper bound */
567 SCIP_BOUNDCHGTYPE boundchgtype /**< bound change type: branching decision or inferred bound change */
568 )
569{
570 assert(var != NULL);
571 assert(SCIPsetIsGT(set, oldbound, newbound));
574 assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, oldbound, 1.0));
575 assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, 0.0));
576 assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
577 assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
578 assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
579
580 SCIPsetDebugMsg(set, "adding upper bound change info to var <%s>[%g,%g]: depth=%d, pos=%d, infer%s=<%s>, inferinfo=%d, %g -> %g\n",
581 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, depth, pos, infercons != NULL ? "cons" : "prop",
582 infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo,
583 oldbound, newbound);
584
585 SCIP_CALL( varEnsureUbchginfosSize(var, blkmem, set, var->nubchginfos+1) );
586 var->ubchginfos[var->nubchginfos].oldbound = oldbound;
587 var->ubchginfos[var->nubchginfos].newbound = newbound;
588 var->ubchginfos[var->nubchginfos].var = var;
589 var->ubchginfos[var->nubchginfos].bdchgidx.depth = depth;
590 var->ubchginfos[var->nubchginfos].bdchgidx.pos = pos;
591 var->ubchginfos[var->nubchginfos].pos = var->nubchginfos; /*lint !e732*/
592 var->ubchginfos[var->nubchginfos].boundchgtype = boundchgtype; /*lint !e641*/
593 var->ubchginfos[var->nubchginfos].boundtype = SCIP_BOUNDTYPE_UPPER; /*lint !e641*/
595 var->ubchginfos[var->nubchginfos].inferboundtype = inferboundtype; /*lint !e641*/
596 var->ubchginfos[var->nubchginfos].inferencedata.var = infervar;
597 var->ubchginfos[var->nubchginfos].inferencedata.info = inferinfo;
598
599 /**@note The "pos" data member of the bound change info has a size of 27 bits */
600 assert(var->nubchginfos < 1 << 27);
601
602 switch( boundchgtype )
603 {
605 break;
607 assert(infercons != NULL);
608 var->ubchginfos[var->nubchginfos].inferencedata.reason.cons = infercons;
609 break;
611 var->ubchginfos[var->nubchginfos].inferencedata.reason.prop = inferprop;
612 break;
613 default:
614 SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
615 return SCIP_INVALIDDATA;
616 }
617
618 var->nubchginfos++;
619
620 assert(var->nubchginfos < 2
622 &var->ubchginfos[var->nubchginfos-1].bdchgidx));
623
624 return SCIP_OKAY;
625}
626
627/** applies single bound change */
629 SCIP_BOUNDCHG* boundchg, /**< bound change to apply */
630 BMS_BLKMEM* blkmem, /**< block memory */
631 SCIP_SET* set, /**< global SCIP settings */
632 SCIP_STAT* stat, /**< problem statistics */
633 SCIP_LP* lp, /**< current LP data */
634 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
635 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
636 int depth, /**< depth in the tree, where the bound change takes place */
637 int pos, /**< position of the bound change in its bound change array */
638 SCIP_Bool* cutoff /**< pointer to store whether an infeasible bound change was detected */
639 )
640{
641 SCIP_VAR* var;
642
643 assert(boundchg != NULL);
644 assert(stat != NULL);
645 assert(depth > 0);
646 assert(pos >= 0);
647 assert(cutoff != NULL);
648
649 *cutoff = FALSE;
650
651 /* ignore redundant bound changes */
652 if( boundchg->redundant )
653 return SCIP_OKAY;
654
655 var = boundchg->var;
656 assert(var != NULL);
658 assert(!SCIPvarIsIntegral(var) || SCIPsetIsFeasIntegral(set, boundchg->newbound));
659
660 /* apply bound change */
661 switch( boundchg->boundtype )
662 {
664 /* check, if the bound change is still active (could be replaced by inference due to repropagation of higher node) */
665 if( SCIPsetIsGT(set, boundchg->newbound, var->locdom.lb) )
666 {
667 if( SCIPsetIsLE(set, boundchg->newbound, var->locdom.ub) )
668 {
669 /* add the bound change info to the variable's bound change info array */
670 switch( boundchg->boundchgtype )
671 {
673 SCIPsetDebugMsg(set, " -> branching: new lower bound of <%s>[%g,%g]: %g\n",
674 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
675 SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
677 stat->lastbranchvar = var;
679 stat->lastbranchvalue = boundchg->newbound;
680 break;
681
683 assert(boundchg->data.inferencedata.reason.cons != NULL);
684 SCIPsetDebugMsg(set, " -> constraint <%s> inference: new lower bound of <%s>[%g,%g]: %g\n",
685 SCIPconsGetName(boundchg->data.inferencedata.reason.cons),
686 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
687 SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
688 boundchg->data.inferencedata.var, boundchg->data.inferencedata.reason.cons, NULL,
689 boundchg->data.inferencedata.info,
691 break;
692
694 SCIPsetDebugMsg(set, " -> propagator <%s> inference: new lower bound of <%s>[%g,%g]: %g\n",
695 boundchg->data.inferencedata.reason.prop != NULL
696 ? SCIPpropGetName(boundchg->data.inferencedata.reason.prop) : "-",
697 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
698 SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
699 boundchg->data.inferencedata.var, NULL, boundchg->data.inferencedata.reason.prop,
700 boundchg->data.inferencedata.info,
702 break;
703
704 default:
705 SCIPerrorMessage("invalid bound change type %d\n", boundchg->boundchgtype);
706 return SCIP_INVALIDDATA;
707 }
708
709 /* change local bound of variable */
710 SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, boundchg->newbound) );
711 }
712 else
713 {
714 SCIPsetDebugMsg(set, " -> cutoff: new lower bound of <%s>[%g,%g]: %g\n",
715 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
716 *cutoff = TRUE;
717 boundchg->redundant = TRUE; /* bound change has not entered the lbchginfos array of the variable! */
718 }
719 }
720 else
721 {
722 /* mark bound change to be inactive */
723 SCIPsetDebugMsg(set, " -> inactive %s: new lower bound of <%s>[%g,%g]: %g\n",
724 (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
725 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
726 boundchg->redundant = TRUE;
727 }
728 break;
729
731 /* check, if the bound change is still active (could be replaced by inference due to repropagation of higher node) */
732 if( SCIPsetIsLT(set, boundchg->newbound, var->locdom.ub) )
733 {
734 if( SCIPsetIsGE(set, boundchg->newbound, var->locdom.lb) )
735 {
736 /* add the bound change info to the variable's bound change info array */
737 switch( boundchg->boundchgtype )
738 {
740 SCIPsetDebugMsg(set, " -> branching: new upper bound of <%s>[%g,%g]: %g\n",
741 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
742 SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
744 stat->lastbranchvar = var;
746 stat->lastbranchvalue = boundchg->newbound;
747 break;
748
750 assert(boundchg->data.inferencedata.reason.cons != NULL);
751 SCIPsetDebugMsg(set, " -> constraint <%s> inference: new upper bound of <%s>[%g,%g]: %g\n",
752 SCIPconsGetName(boundchg->data.inferencedata.reason.cons),
753 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
754 SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
755 boundchg->data.inferencedata.var, boundchg->data.inferencedata.reason.cons, NULL,
756 boundchg->data.inferencedata.info,
758 break;
759
761 SCIPsetDebugMsg(set, " -> propagator <%s> inference: new upper bound of <%s>[%g,%g]: %g\n",
762 boundchg->data.inferencedata.reason.prop != NULL
763 ? SCIPpropGetName(boundchg->data.inferencedata.reason.prop) : "-",
764 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
765 SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
766 boundchg->data.inferencedata.var, NULL, boundchg->data.inferencedata.reason.prop,
767 boundchg->data.inferencedata.info,
769 break;
770
771 default:
772 SCIPerrorMessage("invalid bound change type %d\n", boundchg->boundchgtype);
773 return SCIP_INVALIDDATA;
774 }
775
776 /* change local bound of variable */
777 SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, boundchg->newbound) );
778 }
779 else
780 {
781 SCIPsetDebugMsg(set, " -> cutoff: new upper bound of <%s>[%g,%g]: %g\n",
782 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
783 *cutoff = TRUE;
784 boundchg->redundant = TRUE; /* bound change has not entered the ubchginfos array of the variable! */
785 }
786 }
787 else
788 {
789 /* mark bound change to be inactive */
790 SCIPsetDebugMsg(set, " -> inactive %s: new upper bound of <%s>[%g,%g]: %g\n",
791 (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
792 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
793 boundchg->redundant = TRUE;
794 }
795 break;
796
797 default:
798 SCIPerrorMessage("unknown bound type\n");
799 return SCIP_INVALIDDATA;
800 }
801
802 /* update the branching and inference history */
803 if( !boundchg->applied && !boundchg->redundant )
804 {
805 assert(var == boundchg->var);
806
808 {
809 SCIP_CALL( SCIPvarIncNBranchings(var, blkmem, set, stat,
812 }
813 else if( stat->lastbranchvar != NULL )
814 {
815 /**@todo if last branching variable is unknown, retrieve it from the nodes' boundchg arrays */
816 SCIP_CALL( SCIPvarIncInferenceSum(stat->lastbranchvar, blkmem, set, stat, stat->lastbranchdir, stat->lastbranchvalue, 1.0) );
817 }
818 boundchg->applied = TRUE;
819 }
820
821 return SCIP_OKAY;
822}
823
824/** undoes single bound change */
826 SCIP_BOUNDCHG* boundchg, /**< bound change to remove */
827 BMS_BLKMEM* blkmem, /**< block memory */
828 SCIP_SET* set, /**< global SCIP settings */
829 SCIP_STAT* stat, /**< problem statistics */
830 SCIP_LP* lp, /**< current LP data */
831 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
832 SCIP_EVENTQUEUE* eventqueue /**< event queue */
833 )
834{
835 SCIP_VAR* var;
836
837 assert(boundchg != NULL);
838 assert(stat != NULL);
839
840 /* ignore redundant bound changes */
841 if( boundchg->redundant )
842 return SCIP_OKAY;
843
844 var = boundchg->var;
845 assert(var != NULL);
847
848 /* undo bound change: apply the previous bound change of variable */
849 switch( boundchg->boundtype )
850 {
852 var->nlbchginfos--;
853 assert(var->nlbchginfos >= 0);
854 assert(var->lbchginfos != NULL);
855 assert( SCIPsetIsFeasEQ(set, var->lbchginfos[var->nlbchginfos].newbound, var->locdom.lb) ); /*lint !e777*/
856 assert( SCIPsetIsFeasLE(set, boundchg->newbound, var->locdom.lb) ); /* current lb might be larger to intermediate global bound change */
857
858 SCIPsetDebugMsg(set, "removed lower bound change info of var <%s>[%g,%g]: depth=%d, pos=%d, %g -> %g\n",
859 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub,
862
863 /* reinstall the previous local bound */
864 SCIP_CALL( SCIPvarChgLbLocal(boundchg->var, blkmem, set, stat, lp, branchcand, eventqueue,
865 var->lbchginfos[var->nlbchginfos].oldbound) );
866
867 /* in case all bound changes are removed the local bound should match the global bound */
868 assert(var->nlbchginfos > 0 || SCIPsetIsFeasEQ(set, var->locdom.lb, var->glbdom.lb));
869
870 break;
871
873 var->nubchginfos--;
874 assert(var->nubchginfos >= 0);
875 assert(var->ubchginfos != NULL);
876 assert( SCIPsetIsFeasEQ(set, var->ubchginfos[var->nubchginfos].newbound, var->locdom.ub) ); /*lint !e777*/
877 assert( SCIPsetIsFeasGE(set, boundchg->newbound, var->locdom.ub) ); /* current ub might be smaller to intermediate global bound change */
878
879 SCIPsetDebugMsg(set, "removed upper bound change info of var <%s>[%g,%g]: depth=%d, pos=%d, %g -> %g\n",
880 SCIPvarGetName(var), var->locdom.lb, var->locdom.ub,
883
884 /* reinstall the previous local bound */
885 SCIP_CALL( SCIPvarChgUbLocal(boundchg->var, blkmem, set, stat, lp, branchcand, eventqueue,
886 var->ubchginfos[var->nubchginfos].oldbound) );
887
888 /* in case all bound changes are removed the local bound should match the global bound */
889 assert(var->nubchginfos > 0 || SCIPsetIsFeasEQ(set, var->locdom.ub, var->glbdom.ub));
890
891 break;
892
893 default:
894 SCIPerrorMessage("unknown bound type\n");
895 return SCIP_INVALIDDATA;
896 }
897
898 /* update last branching variable */
900 {
901 stat->lastbranchvar = NULL;
903 }
904
905 return SCIP_OKAY;
906}
907
908/** applies single bound change to the global problem by changing the global bound of the corresponding variable */
909static
911 SCIP_BOUNDCHG* boundchg, /**< bound change to apply */
912 BMS_BLKMEM* blkmem, /**< block memory */
913 SCIP_SET* set, /**< global SCIP settings */
914 SCIP_STAT* stat, /**< problem statistics */
915 SCIP_LP* lp, /**< current LP data */
916 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
917 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
918 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
919 SCIP_Bool* cutoff /**< pointer to store whether an infeasible bound change was detected */
920 )
921{
922 SCIP_VAR* var;
923 SCIP_Real newbound;
924 SCIP_BOUNDTYPE boundtype;
925
926 assert(boundchg != NULL);
927 assert(cutoff != NULL);
928
929 *cutoff = FALSE;
930
931 /* ignore redundant bound changes */
932 if( boundchg->redundant )
933 return SCIP_OKAY;
934
935 var = SCIPboundchgGetVar(boundchg);
936 newbound = SCIPboundchgGetNewbound(boundchg);
937 boundtype = SCIPboundchgGetBoundtype(boundchg);
938
939 /* check if the bound change is redundant which can happen due to a (better) global bound change which was performed
940 * after that bound change was applied
941 *
942 * @note a global bound change is not captured by the redundant member of the bound change data structure
943 */
944 if( (boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasLE(set, newbound, SCIPvarGetLbGlobal(var)))
945 || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasGE(set, newbound, SCIPvarGetUbGlobal(var))) )
946 {
947 return SCIP_OKAY;
948 }
949
950 SCIPsetDebugMsg(set, "applying global bound change: <%s>[%g,%g] %s %g\n",
952 boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", newbound);
953
954 /* check for cutoff */
955 if( (boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGT(set, newbound, SCIPvarGetUbGlobal(var)))
956 || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLT(set, newbound, SCIPvarGetLbGlobal(var))) )
957 {
958 *cutoff = TRUE;
959 return SCIP_OKAY;
960 }
961
962 /* apply bound change */
963 SCIP_CALL( SCIPvarChgBdGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound, boundtype) );
964
965 return SCIP_OKAY;
966}
967
968/** captures branching and inference data of bound change */
969static
971 SCIP_BOUNDCHG* boundchg /**< bound change to remove */
972 )
973{
974 assert(boundchg != NULL);
975
976 /* capture variable associated with the bound change */
977 assert(boundchg->var != NULL);
978 SCIPvarCapture(boundchg->var);
979
980 switch( boundchg->boundchgtype )
981 {
984 break;
985
987 assert(boundchg->data.inferencedata.var != NULL);
988 assert(boundchg->data.inferencedata.reason.cons != NULL);
989 SCIPconsCapture(boundchg->data.inferencedata.reason.cons);
990 break;
991
992 default:
993 SCIPerrorMessage("invalid bound change type\n");
994 return SCIP_INVALIDDATA;
995 }
996
997 return SCIP_OKAY;
998}
999
1000/** releases branching and inference data of bound change */
1001static
1003 SCIP_BOUNDCHG* boundchg, /**< bound change to remove */
1004 BMS_BLKMEM* blkmem, /**< block memory */
1005 SCIP_SET* set, /**< global SCIP settings */
1006 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1007 SCIP_LP* lp /**< current LP data */
1008
1009 )
1010{
1011 assert(boundchg != NULL);
1012
1013 switch( boundchg->boundchgtype )
1014 {
1017 break;
1018
1020 assert(boundchg->data.inferencedata.var != NULL);
1021 assert(boundchg->data.inferencedata.reason.cons != NULL);
1022 SCIP_CALL( SCIPconsRelease(&boundchg->data.inferencedata.reason.cons, blkmem, set) );
1023 break;
1024
1025 default:
1026 SCIPerrorMessage("invalid bound change type\n");
1027 return SCIP_INVALIDDATA;
1028 }
1029
1030 /* release variable */
1031 assert(boundchg->var != NULL);
1032 SCIP_CALL( SCIPvarRelease(&boundchg->var, blkmem, set, eventqueue, lp) );
1033
1034 return SCIP_OKAY;
1035}
1036
1037/** creates empty domain change data with dynamic arrays */
1038static
1040 SCIP_DOMCHG** domchg, /**< pointer to domain change data */
1041 BMS_BLKMEM* blkmem /**< block memory */
1042 )
1043{
1044 assert(domchg != NULL);
1045 assert(blkmem != NULL);
1046
1047 SCIP_ALLOC( BMSallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN)) );
1048 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
1049 (*domchg)->domchgdyn.nboundchgs = 0;
1050 (*domchg)->domchgdyn.boundchgs = NULL;
1051 (*domchg)->domchgdyn.nholechgs = 0;
1052 (*domchg)->domchgdyn.holechgs = NULL;
1053 (*domchg)->domchgdyn.boundchgssize = 0;
1054 (*domchg)->domchgdyn.holechgssize = 0;
1055
1056 return SCIP_OKAY;
1057}
1058
1059/** frees domain change data */
1061 SCIP_DOMCHG** domchg, /**< pointer to domain change */
1062 BMS_BLKMEM* blkmem, /**< block memory */
1063 SCIP_SET* set, /**< global SCIP settings */
1064 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1065 SCIP_LP* lp /**< current LP data */
1066 )
1067{
1068 assert(domchg != NULL);
1069 assert(blkmem != NULL);
1070
1071 if( *domchg != NULL )
1072 {
1073 int i;
1074
1075 /* release variables, branching and inference data associated with the bound changes */
1076 for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1077 {
1078 SCIP_CALL( boundchgReleaseData(&(*domchg)->domchgbound.boundchgs[i], blkmem, set, eventqueue, lp) );
1079 }
1080
1081 /* free memory for bound and hole changes */
1082 switch( (*domchg)->domchgdyn.domchgtype )
1083 {
1085 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgbound.boundchgs, (*domchg)->domchgbound.nboundchgs);
1086 BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOUND));
1087 break;
1089 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgboth.boundchgs, (*domchg)->domchgboth.nboundchgs);
1090 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgboth.holechgs, (*domchg)->domchgboth.nholechgs);
1091 BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH));
1092 break;
1094 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.boundchgs, (*domchg)->domchgdyn.boundchgssize);
1095 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.holechgs, (*domchg)->domchgdyn.holechgssize);
1096 BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN));
1097 break;
1098 default:
1099 SCIPerrorMessage("invalid domain change type\n");
1100 return SCIP_INVALIDDATA;
1101 }
1102 }
1103
1104 return SCIP_OKAY;
1105}
1106
1107/** converts a static domain change data into a dynamic one */
1108static
1110 SCIP_DOMCHG** domchg, /**< pointer to domain change data */
1111 BMS_BLKMEM* blkmem /**< block memory */
1112 )
1113{
1114 assert(domchg != NULL);
1115 assert(blkmem != NULL);
1116
1117 SCIPdebugMessage("making domain change data %p pointing to %p dynamic\n", (void*)domchg, (void*)*domchg);
1118
1119 if( *domchg == NULL )
1120 {
1121 SCIP_CALL( domchgCreate(domchg, blkmem) );
1122 }
1123 else
1124 {
1125 switch( (*domchg)->domchgdyn.domchgtype )
1126 {
1128 SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOUND), sizeof(SCIP_DOMCHGDYN)) );
1129 (*domchg)->domchgdyn.nholechgs = 0;
1130 (*domchg)->domchgdyn.holechgs = NULL;
1131 (*domchg)->domchgdyn.boundchgssize = (int) (*domchg)->domchgdyn.nboundchgs;
1132 (*domchg)->domchgdyn.holechgssize = 0;
1133 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
1134 break;
1136 SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH), sizeof(SCIP_DOMCHGDYN)) );
1137 (*domchg)->domchgdyn.boundchgssize = (int) (*domchg)->domchgdyn.nboundchgs;
1138 (*domchg)->domchgdyn.holechgssize = (*domchg)->domchgdyn.nholechgs;
1139 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
1140 break;
1142 break;
1143 default:
1144 SCIPerrorMessage("invalid domain change type\n");
1145 return SCIP_INVALIDDATA;
1146 }
1147 }
1148#ifndef NDEBUG
1149 {
1150 int i;
1151 for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1152 assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1153 || EPSISINT((*domchg)->domchgbound.boundchgs[i].newbound, 1e-06));
1154 }
1155#endif
1156
1157 return SCIP_OKAY;
1158}
1159
1160/** converts a dynamic domain change data into a static one, using less memory than for a dynamic one */
1162 SCIP_DOMCHG** domchg, /**< pointer to domain change data */
1163 BMS_BLKMEM* blkmem, /**< block memory */
1164 SCIP_SET* set, /**< global SCIP settings */
1165 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1166 SCIP_LP* lp /**< current LP data */
1167 )
1168{
1169 assert(domchg != NULL);
1170 assert(blkmem != NULL);
1171
1172 SCIPsetDebugMsg(set, "making domain change data %p pointing to %p static\n", (void*)domchg, (void*)*domchg);
1173
1174 if( *domchg != NULL )
1175 {
1176 switch( (*domchg)->domchgdyn.domchgtype )
1177 {
1179 if( (*domchg)->domchgbound.nboundchgs == 0 )
1180 {
1181 SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1182 }
1183 break;
1185 if( (*domchg)->domchgboth.nholechgs == 0 )
1186 {
1187 if( (*domchg)->domchgbound.nboundchgs == 0 )
1188 {
1189 SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1190 }
1191 else
1192 {
1193 SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH), sizeof(SCIP_DOMCHGBOUND)) );
1194 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOUND; /*lint !e641*/
1195 }
1196 }
1197 break;
1199 if( (*domchg)->domchgboth.nholechgs == 0 )
1200 {
1201 if( (*domchg)->domchgbound.nboundchgs == 0 )
1202 {
1203 SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1204 }
1205 else
1206 {
1207 /* shrink dynamic size arrays to their minimal sizes */
1208 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.boundchgs, \
1209 (*domchg)->domchgdyn.boundchgssize, (*domchg)->domchgdyn.nboundchgs) ); /*lint !e571*/
1210 BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.holechgs, (*domchg)->domchgdyn.holechgssize);
1211
1212 /* convert into static domain change */
1213 SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN), sizeof(SCIP_DOMCHGBOUND)) );
1214 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOUND; /*lint !e641*/
1215 }
1216 }
1217 else
1218 {
1219 /* shrink dynamic size arrays to their minimal sizes */
1220 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.boundchgs, \
1221 (*domchg)->domchgdyn.boundchgssize, (*domchg)->domchgdyn.nboundchgs) ); /*lint !e571*/
1222 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.holechgs, \
1223 (*domchg)->domchgdyn.holechgssize, (*domchg)->domchgdyn.nholechgs) );
1224
1225 /* convert into static domain change */
1226 SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN), sizeof(SCIP_DOMCHGBOTH)) );
1227 (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOTH; /*lint !e641*/
1228 }
1229 break;
1230 default:
1231 SCIPerrorMessage("invalid domain change type\n");
1232 return SCIP_INVALIDDATA;
1233 }
1234#ifndef NDEBUG
1235 if( *domchg != NULL )
1236 {
1237 int i;
1238 for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1239 assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1240 || SCIPsetIsFeasIntegral(set, (*domchg)->domchgbound.boundchgs[i].newbound));
1241 }
1242#endif
1243 }
1244
1245 return SCIP_OKAY;
1246}
1247
1248/** ensures, that boundchgs array can store at least num entries */
1249static
1251 SCIP_DOMCHG* domchg, /**< domain change data structure */
1252 BMS_BLKMEM* blkmem, /**< block memory */
1253 SCIP_SET* set, /**< global SCIP settings */
1254 int num /**< minimum number of entries to store */
1255 )
1256{
1257 assert(domchg != NULL);
1258 assert(domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1259
1260 if( num > domchg->domchgdyn.boundchgssize )
1261 {
1262 int newsize;
1263
1264 newsize = SCIPsetCalcMemGrowSize(set, num);
1265 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &domchg->domchgdyn.boundchgs, domchg->domchgdyn.boundchgssize, newsize) );
1266 domchg->domchgdyn.boundchgssize = newsize;
1267 }
1268 assert(num <= domchg->domchgdyn.boundchgssize);
1269
1270 return SCIP_OKAY;
1271}
1272
1273/** ensures, that holechgs array can store at least num additional entries */
1274static
1276 SCIP_DOMCHG* domchg, /**< domain change data structure */
1277 BMS_BLKMEM* blkmem, /**< block memory */
1278 SCIP_SET* set, /**< global SCIP settings */
1279 int num /**< minimum number of additional entries to store */
1280 )
1281{
1282 assert(domchg != NULL);
1283 assert(domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1284
1285 if( num > domchg->domchgdyn.holechgssize )
1286 {
1287 int newsize;
1288
1289 newsize = SCIPsetCalcMemGrowSize(set, num);
1290 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &domchg->domchgdyn.holechgs, domchg->domchgdyn.holechgssize, newsize) );
1291 domchg->domchgdyn.holechgssize = newsize;
1292 }
1293 assert(num <= domchg->domchgdyn.holechgssize);
1294
1295 return SCIP_OKAY;
1296}
1297
1298/** applies domain change */
1300 SCIP_DOMCHG* domchg, /**< domain change to apply */
1301 BMS_BLKMEM* blkmem, /**< block memory */
1302 SCIP_SET* set, /**< global SCIP settings */
1303 SCIP_STAT* stat, /**< problem statistics */
1304 SCIP_LP* lp, /**< current LP data */
1305 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1306 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1307 int depth, /**< depth in the tree, where the domain change takes place */
1308 SCIP_Bool* cutoff /**< pointer to store whether an infeasible domain change was detected */
1309 )
1310{
1311 int i;
1312
1313 assert(cutoff != NULL);
1314
1315 *cutoff = FALSE;
1316
1317 SCIPsetDebugMsg(set, "applying domain changes at %p in depth %d\n", (void*)domchg, depth);
1318
1319 if( domchg == NULL )
1320 return SCIP_OKAY;
1321
1322 /* apply bound changes */
1323 for( i = 0; i < (int)domchg->domchgbound.nboundchgs; ++i )
1324 {
1325 SCIP_CALL( SCIPboundchgApply(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp,
1326 branchcand, eventqueue, depth, i, cutoff) );
1327 if( *cutoff )
1328 break;
1329 }
1330 SCIPsetDebugMsg(set, " -> %u bound changes (cutoff %u)\n", domchg->domchgbound.nboundchgs, *cutoff);
1331
1332 /* mark all bound changes after a cutoff redundant */
1333 for( ; i < (int)domchg->domchgbound.nboundchgs; ++i )
1334 domchg->domchgbound.boundchgs[i].redundant = TRUE;
1335
1336 /* apply holelist changes */
1337 if( domchg->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_BOUND ) /*lint !e641*/
1338 {
1339 for( i = 0; i < domchg->domchgboth.nholechgs; ++i )
1340 *(domchg->domchgboth.holechgs[i].ptr) = domchg->domchgboth.holechgs[i].newlist;
1341 SCIPsetDebugMsg(set, " -> %d hole changes\n", domchg->domchgboth.nholechgs);
1342 }
1343
1344 return SCIP_OKAY;
1345}
1346
1347/** undoes domain change */
1349 SCIP_DOMCHG* domchg, /**< domain change to remove */
1350 BMS_BLKMEM* blkmem, /**< block memory */
1351 SCIP_SET* set, /**< global SCIP settings */
1352 SCIP_STAT* stat, /**< problem statistics */
1353 SCIP_LP* lp, /**< current LP data */
1354 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1355 SCIP_EVENTQUEUE* eventqueue /**< event queue */
1356 )
1357{
1358 int i;
1359
1360 SCIPsetDebugMsg(set, "undoing domain changes at %p\n", (void*)domchg);
1361 if( domchg == NULL )
1362 return SCIP_OKAY;
1363
1364 /* undo holelist changes */
1365 if( domchg->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_BOUND ) /*lint !e641*/
1366 {
1367 for( i = domchg->domchgboth.nholechgs-1; i >= 0; --i )
1368 *(domchg->domchgboth.holechgs[i].ptr) = domchg->domchgboth.holechgs[i].oldlist;
1369 SCIPsetDebugMsg(set, " -> %d hole changes\n", domchg->domchgboth.nholechgs);
1370 }
1371
1372 /* undo bound changes */
1373 for( i = domchg->domchgbound.nboundchgs-1; i >= 0; --i )
1374 {
1375 SCIP_CALL( SCIPboundchgUndo(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp, branchcand, eventqueue) );
1376 }
1377 SCIPsetDebugMsg(set, " -> %u bound changes\n", domchg->domchgbound.nboundchgs);
1378
1379 return SCIP_OKAY;
1380}
1381
1382/** applies domain change to the global problem */
1384 SCIP_DOMCHG* domchg, /**< domain change to apply */
1385 BMS_BLKMEM* blkmem, /**< block memory */
1386 SCIP_SET* set, /**< global SCIP settings */
1387 SCIP_STAT* stat, /**< problem statistics */
1388 SCIP_LP* lp, /**< current LP data */
1389 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1390 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1391 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1392 SCIP_Bool* cutoff /**< pointer to store whether an infeasible domain change was detected */
1393 )
1394{
1395 int i;
1396
1397 assert(cutoff != NULL);
1398
1399 *cutoff = FALSE;
1400
1401 if( domchg == NULL )
1402 return SCIP_OKAY;
1403
1404 SCIPsetDebugMsg(set, "applying domain changes at %p to the global problem\n", (void*)domchg);
1405
1406 /* apply bound changes */
1407 for( i = 0; i < (int)domchg->domchgbound.nboundchgs; ++i )
1408 {
1409 SCIP_CALL( boundchgApplyGlobal(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp,
1410 branchcand, eventqueue, cliquetable, cutoff) );
1411 if( *cutoff )
1412 break;
1413 }
1414 SCIPsetDebugMsg(set, " -> %u global bound changes\n", domchg->domchgbound.nboundchgs);
1415
1416 /**@todo globally apply holelist changes - how can this be done without confusing pointer updates? */
1417
1418 return SCIP_OKAY;
1419}
1420
1421/** adds bound change to domain changes */
1423 SCIP_DOMCHG** domchg, /**< pointer to domain change data structure */
1424 BMS_BLKMEM* blkmem, /**< block memory */
1425 SCIP_SET* set, /**< global SCIP settings */
1426 SCIP_VAR* var, /**< variable to change the bounds for */
1427 SCIP_Real newbound, /**< new value for bound */
1428 SCIP_BOUNDTYPE boundtype, /**< type of bound for var: lower or upper bound */
1429 SCIP_BOUNDCHGTYPE boundchgtype, /**< type of bound change: branching decision or inference */
1430 SCIP_Real lpsolval, /**< solval of variable in last LP on path to node, or SCIP_INVALID if unknown */
1431 SCIP_VAR* infervar, /**< variable that was changed (parent of var, or var itself), or NULL */
1432 SCIP_CONS* infercons, /**< constraint that deduced the bound change, or NULL */
1433 SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
1434 int inferinfo, /**< user information for inference to help resolving the conflict */
1435 SCIP_BOUNDTYPE inferboundtype /**< type of bound for inference var: lower or upper bound */
1436 )
1437{
1438 SCIP_BOUNDCHG* boundchg;
1439
1440 assert(domchg != NULL);
1441 assert(var != NULL);
1444 assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, boundtype == SCIP_BOUNDTYPE_LOWER ? 1.0 : 0.0));
1445 assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
1446 assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
1447 assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
1448
1449 SCIPsetDebugMsg(set, "adding %s bound change <%s: %g> of variable <%s> to domain change at %p pointing to %p\n",
1450 boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
1451 newbound, var->name, (void*)domchg, (void*)*domchg);
1452
1453 /* if domain change data doesn't exist, create it;
1454 * if domain change is static, convert it into dynamic change
1455 */
1456 if( *domchg == NULL )
1457 {
1458 SCIP_CALL( domchgCreate(domchg, blkmem) );
1459 }
1460 else if( (*domchg)->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_DYNAMIC ) /*lint !e641*/
1461 {
1462 SCIP_CALL( domchgMakeDynamic(domchg, blkmem) );
1463 }
1464 assert(*domchg != NULL && (*domchg)->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1465
1466 /* get memory for additional bound change */
1467 SCIP_CALL( domchgEnsureBoundchgsSize(*domchg, blkmem, set, (*domchg)->domchgdyn.nboundchgs+1) );
1468
1469 /* fill in the bound change data */
1470 boundchg = &(*domchg)->domchgdyn.boundchgs[(*domchg)->domchgdyn.nboundchgs];
1471 boundchg->var = var;
1472 switch( boundchgtype )
1473 {
1475 boundchg->data.branchingdata.lpsolval = lpsolval;
1476 break;
1478 assert(infercons != NULL);
1479 boundchg->data.inferencedata.var = infervar;
1480 boundchg->data.inferencedata.reason.cons = infercons;
1481 boundchg->data.inferencedata.info = inferinfo;
1482 break;
1484 boundchg->data.inferencedata.var = infervar;
1485 boundchg->data.inferencedata.reason.prop = inferprop;
1486 boundchg->data.inferencedata.info = inferinfo;
1487 break;
1488 default:
1489 SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
1490 return SCIP_INVALIDDATA;
1491 }
1492
1493 boundchg->newbound = newbound;
1494 boundchg->boundchgtype = boundchgtype; /*lint !e641*/
1495 boundchg->boundtype = boundtype; /*lint !e641*/
1496 boundchg->inferboundtype = inferboundtype; /*lint !e641*/
1497 boundchg->applied = FALSE;
1498 boundchg->redundant = FALSE;
1499 (*domchg)->domchgdyn.nboundchgs++;
1500
1501 /* capture branching and inference data associated with the bound changes */
1502 SCIP_CALL( boundchgCaptureData(boundchg) );
1503
1504#ifdef SCIP_DISABLED_CODE /* expensive debug check */
1505#ifdef SCIP_MORE_DEBUG
1506 {
1507 int i;
1508 for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1509 assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1510 || SCIPsetIsFeasIntegral(set, (*domchg)->domchgbound.boundchgs[i].newbound));
1511 }
1512#endif
1513#endif
1514
1515 return SCIP_OKAY;
1516}
1517
1518/** adds hole change to domain changes */
1520 SCIP_DOMCHG** domchg, /**< pointer to domain change data structure */
1521 BMS_BLKMEM* blkmem, /**< block memory */
1522 SCIP_SET* set, /**< global SCIP settings */
1523 SCIP_HOLELIST** ptr, /**< changed list pointer */
1524 SCIP_HOLELIST* newlist, /**< new value of list pointer */
1525 SCIP_HOLELIST* oldlist /**< old value of list pointer */
1526 )
1527{
1528 SCIP_HOLECHG* holechg;
1529
1530 assert(domchg != NULL);
1531 assert(ptr != NULL);
1532
1533 /* if domain change data doesn't exist, create it;
1534 * if domain change is static, convert it into dynamic change
1535 */
1536 if( *domchg == NULL )
1537 {
1538 SCIP_CALL( domchgCreate(domchg, blkmem) );
1539 }
1540 else if( (*domchg)->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_DYNAMIC ) /*lint !e641*/
1541 {
1542 SCIP_CALL( domchgMakeDynamic(domchg, blkmem) );
1543 }
1544 assert(*domchg != NULL && (*domchg)->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1545
1546 /* get memory for additional hole change */
1547 SCIP_CALL( domchgEnsureHolechgsSize(*domchg, blkmem, set, (*domchg)->domchgdyn.nholechgs+1) );
1548
1549 /* fill in the hole change data */
1550 holechg = &(*domchg)->domchgdyn.holechgs[(*domchg)->domchgdyn.nholechgs];
1551 holechg->ptr = ptr;
1552 holechg->newlist = newlist;
1553 holechg->oldlist = oldlist;
1554 (*domchg)->domchgdyn.nholechgs++;
1555
1556 return SCIP_OKAY;
1557}
1558
1559
1560
1561
1562/*
1563 * methods for variables
1564 */
1565
1566/** returns adjusted lower bound value, which is rounded for integral variable types */
1567static
1569 SCIP_SET* set, /**< global SCIP settings */
1570 SCIP_VARTYPE vartype, /**< type of variable */
1571 SCIP_Real lb /**< lower bound to adjust */
1572 )
1573{
1574 if( lb < 0.0 && SCIPsetIsInfinity(set, -lb) )
1575 return -SCIPsetInfinity(set);
1576 else if( lb > 0.0 && SCIPsetIsInfinity(set, lb) )
1577 return SCIPsetInfinity(set);
1578 else if( vartype != SCIP_VARTYPE_CONTINUOUS )
1579 return SCIPsetFeasCeil(set, lb);
1580 else if( lb > 0.0 && lb < SCIPsetEpsilon(set) )
1581 return 0.0;
1582 else
1583 return lb;
1584}
1585
1586/** returns adjusted upper bound value, which is rounded for integral variable types */
1587static
1589 SCIP_SET* set, /**< global SCIP settings */
1590 SCIP_VARTYPE vartype, /**< type of variable */
1591 SCIP_Real ub /**< upper bound to adjust */
1592 )
1593{
1594 if( ub > 0.0 && SCIPsetIsInfinity(set, ub) )
1595 return SCIPsetInfinity(set);
1596 else if( ub < 0.0 && SCIPsetIsInfinity(set, -ub) )
1597 return -SCIPsetInfinity(set);
1598 else if( vartype != SCIP_VARTYPE_CONTINUOUS )
1599 return SCIPsetFeasFloor(set, ub);
1600 else if( ub < 0.0 && ub > -SCIPsetEpsilon(set) )
1601 return 0.0;
1602 else
1603 return ub;
1604}
1605
1606/** removes (redundant) cliques, implications and variable bounds of variable from all other variables' implications and variable
1607 * bounds arrays, and optionally removes them also from the variable itself
1608 */
1610 SCIP_VAR* var, /**< problem variable */
1611 BMS_BLKMEM* blkmem, /**< block memory */
1612 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1613 SCIP_SET* set, /**< global SCIP settings */
1614 SCIP_Bool irrelevantvar, /**< has the variable become irrelevant? */
1615 SCIP_Bool onlyredundant, /**< should only the redundant implications and variable bounds be removed? */
1616 SCIP_Bool removefromvar /**< should the implications and variable bounds be removed from the var itself? */
1617 )
1618{
1619 SCIP_Real lb;
1620 SCIP_Real ub;
1621
1622 assert(var != NULL);
1624 assert(SCIPvarIsActive(var) || SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
1625
1626 lb = SCIPvarGetLbGlobal(var);
1627 ub = SCIPvarGetUbGlobal(var);
1628
1629 SCIPsetDebugMsg(set, "removing %s implications and vbounds of %s<%s>[%g,%g]\n",
1630 onlyredundant ? "redundant" : "all", irrelevantvar ? "irrelevant " : "", SCIPvarGetName(var), lb, ub);
1631
1632 /* remove implications of (fixed) binary variable */
1633 if( var->implics != NULL && (!onlyredundant || lb > 0.5 || ub < 0.5) )
1634 {
1635 SCIP_Bool varfixing;
1636
1637 assert(SCIPvarIsBinary(var));
1638
1639 varfixing = FALSE;
1640 do
1641 {
1642 SCIP_VAR** implvars;
1643 SCIP_BOUNDTYPE* impltypes;
1644 int nimpls;
1645 int i;
1646
1647 nimpls = SCIPimplicsGetNImpls(var->implics, varfixing);
1648 implvars = SCIPimplicsGetVars(var->implics, varfixing);
1649 impltypes = SCIPimplicsGetTypes(var->implics, varfixing);
1650
1651 for( i = 0; i < nimpls; i++ )
1652 {
1653 SCIP_VAR* implvar;
1654 SCIP_BOUNDTYPE impltype;
1655
1656 implvar = implvars[i];
1657 impltype = impltypes[i];
1658 assert(implvar != var);
1659
1660 /* remove for all implications z == 0 / 1 ==> x <= p / x >= p (x not binary)
1661 * the following variable bound from x's variable bounds
1662 * x <= b*z+d (z in vubs of x) , for z == 0 / 1 ==> x <= p
1663 * x >= b*z+d (z in vlbs of x) , for z == 0 / 1 ==> x >= p
1664 */
1665 if( impltype == SCIP_BOUNDTYPE_UPPER )
1666 {
1667 if( implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1668 {
1669 SCIPsetDebugMsg(set, "deleting variable bound: <%s> == %u ==> <%s> <= %g\n",
1670 SCIPvarGetName(var), varfixing, SCIPvarGetName(implvar),
1671 SCIPimplicsGetBounds(var->implics, varfixing)[i]);
1672 SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, varfixing) );
1673 implvar->closestvblpcount = -1;
1674 var->closestvblpcount = -1;
1675 }
1676 }
1677 else
1678 {
1679 if( implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1680 {
1681 SCIPsetDebugMsg(set, "deleting variable bound: <%s> == %u ==> <%s> >= %g\n",
1682 SCIPvarGetName(var), varfixing, SCIPvarGetName(implvar),
1683 SCIPimplicsGetBounds(var->implics, varfixing)[i]);
1684 SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, !varfixing) );
1685 implvar->closestvblpcount = -1;
1686 var->closestvblpcount = -1;
1687 }
1688 }
1689 }
1690 varfixing = !varfixing;
1691 }
1692 while( varfixing == TRUE );
1693
1694 if( removefromvar )
1695 {
1696 /* free the implications data structures */
1697 SCIPimplicsFree(&var->implics, blkmem);
1698 }
1699 }
1700
1701 /* remove the (redundant) variable lower bounds */
1702 if( var->vlbs != NULL )
1703 {
1704 SCIP_VAR** vars;
1705 SCIP_Real* coefs;
1706 SCIP_Real* constants;
1707 int nvbds;
1708 int newnvbds;
1709 int i;
1710
1711 nvbds = SCIPvboundsGetNVbds(var->vlbs);
1712 vars = SCIPvboundsGetVars(var->vlbs);
1713 coefs = SCIPvboundsGetCoefs(var->vlbs);
1714 constants = SCIPvboundsGetConstants(var->vlbs);
1715
1716 /* remove for all variable bounds x >= b*z+d the following implication from z's implications
1717 * z == ub ==> x >= b*ub + d , if b > 0
1718 * z == lb ==> x >= b*lb + d , if b < 0
1719 */
1720 newnvbds = 0;
1721 for( i = 0; i < nvbds; i++ )
1722 {
1723 SCIP_VAR* implvar;
1724 SCIP_Real coef;
1725
1726 assert(newnvbds <= i);
1727
1728 implvar = vars[i];
1729 assert(implvar != NULL);
1730
1731 coef = coefs[i];
1732 assert(!SCIPsetIsZero(set, coef));
1733
1734 /* check, if we want to remove the variable bound */
1735 if( onlyredundant )
1736 {
1737 SCIP_Real vbound;
1738
1739 vbound = MAX(coef * SCIPvarGetUbGlobal(implvar), coef * SCIPvarGetLbGlobal(implvar)) + constants[i]; /*lint !e666*/
1740 if( SCIPsetIsFeasGT(set, vbound, lb) )
1741 {
1742 /* the variable bound is not redundant: keep it */
1743 if( removefromvar )
1744 {
1745 if( newnvbds < i )
1746 {
1747 vars[newnvbds] = implvar;
1748 coefs[newnvbds] = coef;
1749 constants[newnvbds] = constants[i];
1750 }
1751 newnvbds++;
1752 }
1753 continue;
1754 }
1755 }
1756
1757 /* remove the corresponding implication */
1758 if( implvar->implics != NULL ) /* variable may have been aggregated in the mean time */
1759 {
1760 SCIPsetDebugMsg(set, "deleting implication: <%s> == %d ==> <%s> >= %g\n",
1761 SCIPvarGetName(implvar), (coef > 0.0), SCIPvarGetName(var), MAX(coef, 0.0) + constants[i]);
1762 SCIP_CALL( SCIPimplicsDel(&implvar->implics, blkmem, set, (coef > 0.0), var, SCIP_BOUNDTYPE_LOWER) );
1763 }
1764 if( coef > 0.0 && implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1765 {
1766 SCIPsetDebugMsg(set, "deleting variable upper bound from <%s> involving variable %s\n",
1767 SCIPvarGetName(implvar), SCIPvarGetName(var));
1768 SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, FALSE) );
1769 implvar->closestvblpcount = -1;
1770 var->closestvblpcount = -1;
1771 }
1772 else if( coef < 0.0 && implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1773 {
1774 SCIPsetDebugMsg(set, "deleting variable lower bound from <%s> involving variable %s\n",
1775 SCIPvarGetName(implvar), SCIPvarGetName(var));
1776 SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, TRUE) );
1777 implvar->closestvblpcount = -1;
1778 var->closestvblpcount = -1;
1779 }
1780 }
1781
1782 if( removefromvar )
1783 {
1784 /* update the number of variable bounds */
1785 SCIPvboundsShrink(&var->vlbs, blkmem, newnvbds);
1786 var->closestvblpcount = -1;
1787 }
1788 }
1789
1790 /**@todo in general, variable bounds like x >= b*z + d corresponding to an implication like z = ub ==> x >= b*ub + d
1791 * might be missing because we only add variable bounds with reasonably small value of b. thus, we currently
1792 * cannot remove such variables x from z's implications.
1793 */
1794
1795 /* remove the (redundant) variable upper bounds */
1796 if( var->vubs != NULL )
1797 {
1798 SCIP_VAR** vars;
1799 SCIP_Real* coefs;
1800 SCIP_Real* constants;
1801 int nvbds;
1802 int newnvbds;
1803 int i;
1804
1805 nvbds = SCIPvboundsGetNVbds(var->vubs);
1806 vars = SCIPvboundsGetVars(var->vubs);
1807 coefs = SCIPvboundsGetCoefs(var->vubs);
1808 constants = SCIPvboundsGetConstants(var->vubs);
1809
1810 /* remove for all variable bounds x <= b*z+d the following implication from z's implications
1811 * z == lb ==> x <= b*lb + d , if b > 0
1812 * z == ub ==> x <= b*ub + d , if b < 0
1813 */
1814 newnvbds = 0;
1815 for( i = 0; i < nvbds; i++ )
1816 {
1817 SCIP_VAR* implvar;
1818 SCIP_Real coef;
1819
1820 assert(newnvbds <= i);
1821
1822 implvar = vars[i];
1823 assert(implvar != NULL);
1824
1825 coef = coefs[i];
1826 assert(!SCIPsetIsZero(set, coef));
1827
1828 /* check, if we want to remove the variable bound */
1829 if( onlyredundant )
1830 {
1831 SCIP_Real vbound;
1832
1833 vbound = MIN(coef * SCIPvarGetUbGlobal(implvar), coef * SCIPvarGetLbGlobal(implvar)) + constants[i]; /*lint !e666*/
1834 if( SCIPsetIsFeasLT(set, vbound, ub) )
1835 {
1836 /* the variable bound is not redundant: keep it */
1837 if( removefromvar )
1838 {
1839 if( newnvbds < i )
1840 {
1841 vars[newnvbds] = implvar;
1842 coefs[newnvbds] = coefs[i];
1843 constants[newnvbds] = constants[i];
1844 }
1845 newnvbds++;
1846 }
1847 continue;
1848 }
1849 }
1850
1851 /* remove the corresponding implication */
1852 if( implvar->implics != NULL ) /* variable may have been aggregated in the mean time */
1853 {
1854 SCIPsetDebugMsg(set, "deleting implication: <%s> == %d ==> <%s> <= %g\n",
1855 SCIPvarGetName(implvar), (coef < 0.0), SCIPvarGetName(var), MIN(coef, 0.0) + constants[i]);
1856 SCIP_CALL( SCIPimplicsDel(&implvar->implics, blkmem, set, (coef < 0.0), var, SCIP_BOUNDTYPE_UPPER) );
1857 }
1858 if( coef < 0.0 && implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1859 {
1860 SCIPsetDebugMsg(set, "deleting variable upper bound from <%s> involving variable %s\n",
1861 SCIPvarGetName(implvar), SCIPvarGetName(var));
1862 SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, TRUE) );
1863 implvar->closestvblpcount = -1;
1864 var->closestvblpcount = -1;
1865 }
1866 else if( coef > 0.0 && implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1867 {
1868 SCIPsetDebugMsg(set, "deleting variable lower bound from <%s> involving variable %s\n",
1869 SCIPvarGetName(implvar), SCIPvarGetName(var));
1870 SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, FALSE) );
1871 implvar->closestvblpcount = -1;
1872 var->closestvblpcount = -1;
1873 }
1874 }
1875
1876 if( removefromvar )
1877 {
1878 /* update the number of variable bounds */
1879 SCIPvboundsShrink(&var->vubs, blkmem, newnvbds);
1880 var->closestvblpcount = -1;
1881 }
1882 }
1883
1884 /* remove the variable from all cliques */
1885 if( SCIPvarIsBinary(var) )
1886 SCIPcliquelistRemoveFromCliques(var->cliquelist, cliquetable, var, irrelevantvar);
1887
1888 /**@todo variable bounds like x <= b*z + d with z general integer are not removed from x's vbd arrays, because
1889 * z has no link (like in the binary case) to x
1890 */
1891
1892 return SCIP_OKAY;
1893}
1894
1895/** sets the variable name */
1896static
1898 SCIP_VAR* var, /**< problem variable */
1899 BMS_BLKMEM* blkmem, /**< block memory */
1900 SCIP_STAT* stat, /**< problem statistics, or NULL */
1901 const char* name /**< name of variable, or NULL for automatic name creation */
1902 )
1903{
1904 assert(blkmem != NULL);
1905 assert(var != NULL);
1906
1907 if( name == NULL )
1908 {
1909 char s[SCIP_MAXSTRLEN];
1910
1911 assert(stat != NULL);
1912
1913 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "_var%d_", stat->nvaridx);
1914 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->name, s, strlen(s)+1) );
1915 }
1916 else
1917 {
1918 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->name, name, strlen(name)+1) );
1919 }
1920
1921 return SCIP_OKAY;
1922}
1923
1924
1925/** creates variable; if variable is of integral type, fractional bounds are automatically rounded; an integer variable
1926 * with bounds zero and one is automatically converted into a binary variable
1927 */
1928static
1930 SCIP_VAR** var, /**< pointer to variable data */
1931 BMS_BLKMEM* blkmem, /**< block memory */
1932 SCIP_SET* set, /**< global SCIP settings */
1933 SCIP_STAT* stat, /**< problem statistics */
1934 const char* name, /**< name of variable, or NULL for automatic name creation */
1935 SCIP_Real lb, /**< lower bound of variable */
1936 SCIP_Real ub, /**< upper bound of variable */
1937 SCIP_Real obj, /**< objective function value */
1938 SCIP_VARTYPE vartype, /**< type of variable */
1939 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
1940 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
1941 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
1942 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */
1943 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */
1944 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */
1945 SCIP_VARDATA* vardata /**< user data for this specific variable */
1946 )
1947{
1948 int i;
1949
1950 assert(var != NULL);
1951 assert(blkmem != NULL);
1952 assert(stat != NULL);
1953
1954 /* adjust bounds of variable */
1955 lb = adjustedLb(set, vartype, lb);
1956 ub = adjustedUb(set, vartype, ub);
1957
1958 /* convert [0,1]-integers into binary variables and check that binary variables have correct bounds */
1959 if( (SCIPsetIsEQ(set, lb, 0.0) || SCIPsetIsEQ(set, lb, 1.0))
1960 && (SCIPsetIsEQ(set, ub, 0.0) || SCIPsetIsEQ(set, ub, 1.0)) )
1961 {
1962 if( vartype == SCIP_VARTYPE_INTEGER )
1963 vartype = SCIP_VARTYPE_BINARY;
1964 }
1965 else
1966 {
1967 if( vartype == SCIP_VARTYPE_BINARY )
1968 {
1969 SCIPerrorMessage("invalid bounds [%.2g,%.2g] for binary variable <%s>\n", lb, ub, name);
1970 return SCIP_INVALIDDATA;
1971 }
1972 }
1973
1974 assert(vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, lb, 0.0) || SCIPsetIsEQ(set, lb, 1.0));
1975 assert(vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, ub, 0.0) || SCIPsetIsEQ(set, ub, 1.0));
1976
1977 SCIP_ALLOC( BMSallocBlockMemory(blkmem, var) );
1978
1979 /* set variable's name */
1980 SCIP_CALL( varSetName(*var, blkmem, stat, name) );
1981
1982#ifndef NDEBUG
1983 (*var)->scip = set->scip;
1984#endif
1985 (*var)->obj = obj;
1986 (*var)->unchangedobj = obj;
1987 (*var)->branchfactor = 1.0;
1988 (*var)->rootsol = 0.0;
1989 (*var)->bestrootsol = 0.0;
1990 (*var)->bestrootredcost = 0.0;
1991 (*var)->bestrootlpobjval = SCIP_INVALID;
1992 (*var)->relaxsol = 0.0;
1993 (*var)->nlpsol = 0.0;
1994 (*var)->primsolavg = 0.5 * (lb + ub);
1995 (*var)->conflictlb = SCIP_REAL_MIN;
1996 (*var)->conflictub = SCIP_REAL_MAX;
1997 (*var)->conflictrelaxedlb = (*var)->conflictlb;
1998 (*var)->conflictrelaxedub = (*var)->conflictub;
1999 (*var)->lazylb = -SCIPsetInfinity(set);
2000 (*var)->lazyub = SCIPsetInfinity(set);
2001 (*var)->glbdom.holelist = NULL;
2002 (*var)->glbdom.lb = lb;
2003 (*var)->glbdom.ub = ub;
2004 (*var)->locdom.holelist = NULL;
2005 (*var)->locdom.lb = lb;
2006 (*var)->locdom.ub = ub;
2007 (*var)->varcopy = varcopy;
2008 (*var)->vardelorig = vardelorig;
2009 (*var)->vartrans = vartrans;
2010 (*var)->vardeltrans = vardeltrans;
2011 (*var)->vardata = vardata;
2012 (*var)->parentvars = NULL;
2013 (*var)->negatedvar = NULL;
2014 (*var)->vlbs = NULL;
2015 (*var)->vubs = NULL;
2016 (*var)->implics = NULL;
2017 (*var)->cliquelist = NULL;
2018 (*var)->eventfilter = NULL;
2019 (*var)->lbchginfos = NULL;
2020 (*var)->ubchginfos = NULL;
2021 (*var)->index = stat->nvaridx;
2022 (*var)->probindex = -1;
2023 (*var)->pseudocandindex = -1;
2024 (*var)->eventqueueindexobj = -1;
2025 (*var)->eventqueueindexlb = -1;
2026 (*var)->eventqueueindexub = -1;
2027 (*var)->parentvarssize = 0;
2028 (*var)->nparentvars = 0;
2029 (*var)->nuses = 0;
2030 (*var)->branchpriority = 0;
2031 (*var)->branchdirection = SCIP_BRANCHDIR_AUTO; /*lint !e641*/
2032 (*var)->lbchginfossize = 0;
2033 (*var)->nlbchginfos = 0;
2034 (*var)->ubchginfossize = 0;
2035 (*var)->nubchginfos = 0;
2036 (*var)->conflictlbcount = 0;
2037 (*var)->conflictubcount = 0;
2038 (*var)->closestvlbidx = -1;
2039 (*var)->closestvubidx = -1;
2040 (*var)->closestvblpcount = -1;
2041 (*var)->initial = initial;
2042 (*var)->removable = removable;
2043 (*var)->deleted = FALSE;
2044 (*var)->donotaggr = FALSE;
2045 (*var)->donotmultaggr = FALSE;
2046 (*var)->vartype = vartype; /*lint !e641*/
2047 (*var)->pseudocostflag = FALSE;
2048 (*var)->eventqueueimpl = FALSE;
2049 (*var)->deletable = FALSE;
2050 (*var)->delglobalstructs = FALSE;
2051 (*var)->relaxationonly = FALSE;
2052
2053 for( i = 0; i < NLOCKTYPES; i++ )
2054 {
2055 (*var)->nlocksdown[i] = 0;
2056 (*var)->nlocksup[i] = 0;
2057 }
2058
2059 stat->nvaridx++;
2060
2061 /* create branching and inference history entries */
2062 SCIP_CALL( SCIPhistoryCreate(&(*var)->history, blkmem) );
2063 SCIP_CALL( SCIPhistoryCreate(&(*var)->historycrun, blkmem) );
2064
2065 /* the value based history is only created on demand */
2066 (*var)->valuehistory = NULL;
2067
2068 return SCIP_OKAY;
2069}
2070
2071/** creates and captures an original problem variable; an integer variable with bounds
2072 * zero and one is automatically converted into a binary variable
2073 */
2075 SCIP_VAR** var, /**< pointer to variable data */
2076 BMS_BLKMEM* blkmem, /**< block memory */
2077 SCIP_SET* set, /**< global SCIP settings */
2078 SCIP_STAT* stat, /**< problem statistics */
2079 const char* name, /**< name of variable, or NULL for automatic name creation */
2080 SCIP_Real lb, /**< lower bound of variable */
2081 SCIP_Real ub, /**< upper bound of variable */
2082 SCIP_Real obj, /**< objective function value */
2083 SCIP_VARTYPE vartype, /**< type of variable */
2084 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2085 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2086 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */
2087 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */
2088 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */
2089 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2090 SCIP_VARDATA* vardata /**< user data for this specific variable */
2091 )
2092{
2093 assert(var != NULL);
2094 assert(blkmem != NULL);
2095 assert(stat != NULL);
2096
2097 /* create variable */
2098 SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2099 varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2100
2101 /* set variable status and data */
2102 (*var)->varstatus = SCIP_VARSTATUS_ORIGINAL; /*lint !e641*/
2103 (*var)->data.original.origdom.holelist = NULL;
2104 (*var)->data.original.origdom.lb = lb;
2105 (*var)->data.original.origdom.ub = ub;
2106 (*var)->data.original.transvar = NULL;
2107
2108 /* capture variable */
2109 SCIPvarCapture(*var);
2110
2111 return SCIP_OKAY;
2112}
2113
2114/** creates and captures a loose variable belonging to the transformed problem; an integer variable with bounds
2115 * zero and one is automatically converted into a binary variable
2116 */
2118 SCIP_VAR** var, /**< pointer to variable data */
2119 BMS_BLKMEM* blkmem, /**< block memory */
2120 SCIP_SET* set, /**< global SCIP settings */
2121 SCIP_STAT* stat, /**< problem statistics */
2122 const char* name, /**< name of variable, or NULL for automatic name creation */
2123 SCIP_Real lb, /**< lower bound of variable */
2124 SCIP_Real ub, /**< upper bound of variable */
2125 SCIP_Real obj, /**< objective function value */
2126 SCIP_VARTYPE vartype, /**< type of variable */
2127 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2128 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2129 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */
2130 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */
2131 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */
2132 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2133 SCIP_VARDATA* vardata /**< user data for this specific variable */
2134 )
2135{
2136 assert(var != NULL);
2137 assert(blkmem != NULL);
2138
2139 /* create variable */
2140 SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2141 varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2142
2143 /* create event filter for transformed variable */
2144 SCIP_CALL( SCIPeventfilterCreate(&(*var)->eventfilter, blkmem) );
2145
2146 /* set variable status and data */
2147 (*var)->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
2148
2149 /* capture variable */
2150 SCIPvarCapture(*var);
2151
2152 return SCIP_OKAY;
2153}
2154
2155/** copies and captures a variable from source to target SCIP; an integer variable with bounds zero and one is
2156 * automatically converted into a binary variable; in case the variable data cannot be copied the variable is not
2157 * copied at all
2158 */
2160 SCIP_VAR** var, /**< pointer to store the target variable */
2161 BMS_BLKMEM* blkmem, /**< block memory */
2162 SCIP_SET* set, /**< global SCIP settings */
2163 SCIP_STAT* stat, /**< problem statistics */
2164 SCIP* sourcescip, /**< source SCIP data structure */
2165 SCIP_VAR* sourcevar, /**< source variable */
2166 SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of source variables corresponding
2167 * target variables */
2168 SCIP_HASHMAP* consmap, /**< a hashmap to store the mapping of source constraints to the corresponding
2169 * target constraints */
2170 SCIP_Bool global /**< should global or local bounds be used? */
2171 )
2172{
2173 SCIP_VARDATA* targetdata;
2174 SCIP_RESULT result;
2175 SCIP_Real lb;
2176 SCIP_Real ub;
2177
2178 assert(set != NULL);
2179 assert(blkmem != NULL);
2180 assert(stat != NULL);
2181 assert(sourcescip != NULL);
2182 assert(sourcevar != NULL);
2183 assert(var != NULL);
2184 assert(set->stage == SCIP_STAGE_PROBLEM);
2185 assert(varmap != NULL);
2186 assert(consmap != NULL);
2187
2188 /** @todo copy hole lists */
2189 assert(global || SCIPvarGetHolelistLocal(sourcevar) == NULL);
2190 assert(!global || SCIPvarGetHolelistGlobal(sourcevar) == NULL);
2191
2192 result = SCIP_DIDNOTRUN;
2193 targetdata = NULL;
2194
2195 if( SCIPvarGetStatus(sourcevar) == SCIP_VARSTATUS_ORIGINAL )
2196 {
2197 lb = SCIPvarGetLbOriginal(sourcevar);
2198 ub = SCIPvarGetUbOriginal(sourcevar);
2199 }
2200 else
2201 {
2202 lb = global ? SCIPvarGetLbGlobal(sourcevar) : SCIPvarGetLbLocal(sourcevar);
2203 ub = global ? SCIPvarGetUbGlobal(sourcevar) : SCIPvarGetUbLocal(sourcevar);
2204 }
2205
2206 /* creates and captures the variable in the target SCIP and initialize callback methods and variable data to NULL */
2207 SCIP_CALL( SCIPvarCreateOriginal(var, blkmem, set, stat, SCIPvarGetName(sourcevar),
2208 lb, ub, SCIPvarGetObj(sourcevar), SCIPvarGetType(sourcevar),
2209 SCIPvarIsInitial(sourcevar), SCIPvarIsRemovable(sourcevar),
2210 NULL, NULL, NULL, NULL, NULL) );
2211 assert(*var != NULL);
2212
2213 /* directly copy donot(mult)aggr flag */
2214 (*var)->donotaggr = sourcevar->donotaggr;
2215 (*var)->donotmultaggr = sourcevar->donotmultaggr;
2216
2217 /* insert variable into mapping between source SCIP and the target SCIP */
2218 assert(!SCIPhashmapExists(varmap, sourcevar));
2219 SCIP_CALL( SCIPhashmapInsert(varmap, sourcevar, *var) );
2220
2221 /* in case there exists variable data and the variable data copy callback, try to copy variable data */
2222 if( sourcevar->vardata != NULL && sourcevar->varcopy != NULL )
2223 {
2224 SCIP_CALL( sourcevar->varcopy(set->scip, sourcescip, sourcevar, sourcevar->vardata,
2225 varmap, consmap, (*var), &targetdata, &result) );
2226
2227 /* evaluate result */
2228 if( result != SCIP_DIDNOTRUN && result != SCIP_SUCCESS )
2229 {
2230 SCIPerrorMessage("variable data copying method returned invalid result <%d>\n", result);
2231 return SCIP_INVALIDRESULT;
2232 }
2233
2234 assert(targetdata == NULL || result == SCIP_SUCCESS);
2235
2236 /* if copying was successful, add the created variable data to the variable as well as all callback methods */
2237 if( result == SCIP_SUCCESS )
2238 {
2239 (*var)->varcopy = sourcevar->varcopy;
2240 (*var)->vardelorig = sourcevar->vardelorig;
2241 (*var)->vartrans = sourcevar->vartrans;
2242 (*var)->vardeltrans = sourcevar->vardeltrans;
2243 (*var)->vardata = targetdata;
2244 }
2245 }
2246
2247 /* we initialize histories of the variables by copying the source variable-information */
2248 if( set->history_allowtransfer )
2249 {
2250 SCIPvarMergeHistories((*var), sourcevar, stat);
2251 }
2252
2253 /* in case the copying was successfully, add the created variable data to the variable as well as all callback
2254 * methods
2255 */
2256 if( result == SCIP_SUCCESS )
2257 {
2258 (*var)->varcopy = sourcevar->varcopy;
2259 (*var)->vardelorig = sourcevar->vardelorig;
2260 (*var)->vartrans = sourcevar->vartrans;
2261 (*var)->vardeltrans = sourcevar->vardeltrans;
2262 (*var)->vardata = targetdata;
2263 }
2264
2265 SCIPsetDebugMsg(set, "created copy <%s> of variable <%s>\n", SCIPvarGetName(*var), SCIPvarGetName(sourcevar));
2266
2267 return SCIP_OKAY;
2268}
2269
2270/** parse given string for a SCIP_Real bound */
2271static
2273 SCIP_SET* set, /**< global SCIP settings */
2274 const char* str, /**< string to parse */
2275 SCIP_Real* value, /**< pointer to store the parsed value */
2276 char** endptr /**< pointer to store the final string position if successfully parsed */
2277 )
2278{
2279 /* first check for infinity value */
2280 if( strncmp(str, "+inf", 4) == 0 )
2281 {
2282 *value = SCIPsetInfinity(set);
2283 (*endptr) = (char*)str + 4;
2284 }
2285 else if( strncmp(str, "-inf", 4) == 0 )
2286 {
2287 *value = -SCIPsetInfinity(set);
2288 (*endptr) = (char*)str + 4;
2289 }
2290 else
2291 {
2292 if( !SCIPstrToRealValue(str, value, endptr) )
2293 {
2294 SCIPerrorMessage("expected value: %s.\n", str);
2295 return SCIP_READERROR;
2296 }
2297 }
2298
2299 return SCIP_OKAY;
2300}
2301
2302/** parse the characters as bounds */
2303static
2305 SCIP_SET* set, /**< global SCIP settings */
2306 const char* str, /**< string to parse */
2307 char* type, /**< bound type (global, local, or lazy) */
2308 SCIP_Real* lb, /**< pointer to store the lower bound */
2309 SCIP_Real* ub, /**< pointer to store the upper bound */
2310 char** endptr /**< pointer to store the final string position if successfully parsed (or NULL if an error occured) */
2311 )
2312{
2313 char token[SCIP_MAXSTRLEN];
2314 char* tmpend;
2315
2316 SCIPsetDebugMsg(set, "parsing bounds: '%s'\n", str);
2317
2318 /* get bound type */
2319 SCIPstrCopySection(str, ' ', ' ', type, SCIP_MAXSTRLEN, endptr);
2320 if ( *endptr == str
2321 || ( strncmp(type, "original", 8) != 0 && strncmp(type, "global", 6) != 0 && strncmp(type, "local", 5) != 0 && strncmp(type, "lazy", 4) != 0 ) )
2322 {
2323 SCIPsetDebugMsg(set, "unkown bound type\n");
2324 *endptr = NULL;
2325 return SCIP_OKAY;
2326 }
2327
2328 SCIPsetDebugMsg(set, "parsed bound type <%s>\n", type);
2329
2330 /* get lower bound */
2331 SCIPstrCopySection(str, '[', ',', token, SCIP_MAXSTRLEN, endptr);
2332 str = *endptr;
2333 SCIP_CALL( parseValue(set, token, lb, &tmpend) );
2334
2335 /* get upper bound */
2336 SCIP_CALL( parseValue(set, str, ub, endptr) );
2337
2338 SCIPsetDebugMsg(set, "parsed bounds: [%g,%g]\n", *lb, *ub);
2339
2340 /* skip end of bounds */
2341 while ( **endptr != '\0' && (**endptr == ']' || **endptr == ',') )
2342 ++(*endptr);
2343
2344 return SCIP_OKAY;
2345}
2346
2347/** parses a given string for a variable informations */
2348static
2350 SCIP_SET* set, /**< global SCIP settings */
2351 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2352 const char* str, /**< string to parse */
2353 char* name, /**< pointer to store the variable name */
2354 SCIP_Real* lb, /**< pointer to store the lower bound */
2355 SCIP_Real* ub, /**< pointer to store the upper bound */
2356 SCIP_Real* obj, /**< pointer to store the objective coefficient */
2357 SCIP_VARTYPE* vartype, /**< pointer to store the variable type */
2358 SCIP_Real* lazylb, /**< pointer to store if the lower bound is lazy */
2359 SCIP_Real* lazyub, /**< pointer to store if the upper bound is lazy */
2360 SCIP_Bool local, /**< should the local bound be applied */
2361 char** endptr, /**< pointer to store the final string position if successfully */
2362 SCIP_Bool* success /**< pointer store if the paring process was successful */
2363 )
2364{
2365 SCIP_Real parsedlb;
2366 SCIP_Real parsedub;
2367 char token[SCIP_MAXSTRLEN];
2368 char* strptr;
2369 int i;
2370
2371 assert(lb != NULL);
2372 assert(ub != NULL);
2373 assert(obj != NULL);
2374 assert(vartype != NULL);
2375 assert(lazylb != NULL);
2376 assert(lazyub != NULL);
2377 assert(success != NULL);
2378
2379 (*success) = TRUE;
2380
2381 /* copy variable type */
2382 SCIPstrCopySection(str, '[', ']', token, SCIP_MAXSTRLEN, endptr);
2383 assert(*endptr != str);
2384 SCIPsetDebugMsg(set, "parsed variable type <%s>\n", token);
2385
2386 /* get variable type */
2387 if( strncmp(token, "binary", 3) == 0 )
2388 (*vartype) = SCIP_VARTYPE_BINARY;
2389 else if( strncmp(token, "integer", 3) == 0 )
2390 (*vartype) = SCIP_VARTYPE_INTEGER;
2391 else if( strncmp(token, "implicit", 3) == 0 )
2392 (*vartype) = SCIP_VARTYPE_IMPLINT;
2393 else if( strncmp(token, "continuous", 3) == 0 )
2394 (*vartype) = SCIP_VARTYPE_CONTINUOUS;
2395 else
2396 {
2397 SCIPmessagePrintWarning(messagehdlr, "unknown variable type\n");
2398 (*success) = FALSE;
2399 return SCIP_OKAY;
2400 }
2401
2402 /* move string pointer behind variable type */
2403 str = *endptr;
2404
2405 /* get variable name */
2406 SCIPstrCopySection(str, '<', '>', name, SCIP_MAXSTRLEN, endptr);
2407 assert(*endptr != str);
2408 SCIPsetDebugMsg(set, "parsed variable name <%s>\n", name);
2409
2410 /* move string pointer behind variable name */
2411 str = *endptr;
2412
2413 /* cut out objective coefficient */
2414 SCIPstrCopySection(str, '=', ',', token, SCIP_MAXSTRLEN, endptr);
2415
2416 /* move string pointer behind objective coefficient */
2417 str = *endptr;
2418
2419 /* get objective coefficient */
2420 if( !SCIPstrToRealValue(token, obj, endptr) )
2421 {
2422 *endptr = NULL;
2423 return SCIP_READERROR;
2424 }
2425
2426 SCIPsetDebugMsg(set, "parsed objective coefficient <%g>\n", *obj);
2427
2428 /* parse global/original bounds */
2429 SCIP_CALL( parseBounds(set, str, token, lb, ub, endptr) );
2430 if ( *endptr == NULL )
2431 {
2432 SCIPerrorMessage("Expected bound type: %s.\n", token);
2433 return SCIP_READERROR;
2434 }
2435 assert(strncmp(token, "global", 6) == 0 || strncmp(token, "original", 8) == 0);
2436
2437 /* initialize the lazy bound */
2438 *lazylb = -SCIPsetInfinity(set);
2439 *lazyub = SCIPsetInfinity(set);
2440
2441 /* store pointer */
2442 strptr = *endptr;
2443
2444 /* possibly parse optional local and lazy bounds */
2445 for( i = 0; i < 2 && *endptr != NULL && **endptr != '\0'; ++i )
2446 {
2447 /* start after previous bounds */
2448 strptr = *endptr;
2449
2450 /* parse global bounds */
2451 SCIP_CALL( parseBounds(set, strptr, token, &parsedlb, &parsedub, endptr) );
2452
2453 /* stop if parsing of bounds failed */
2454 if( *endptr == NULL )
2455 break;
2456
2457 if( strncmp(token, "local", 5) == 0 && local )
2458 {
2459 *lb = parsedlb;
2460 *ub = parsedub;
2461 }
2462 else if( strncmp(token, "lazy", 4) == 0 )
2463 {
2464 *lazylb = parsedlb;
2465 *lazyub = parsedub;
2466 }
2467 }
2468
2469 /* restore pointer */
2470 if ( *endptr == NULL )
2471 *endptr = strptr;
2472
2473 /* check bounds for binary variables */
2474 if ( (*vartype) == SCIP_VARTYPE_BINARY )
2475 {
2476 if ( SCIPsetIsLT(set, *lb, 0.0) || SCIPsetIsGT(set, *ub, 1.0) )
2477 {
2478 SCIPerrorMessage("Parsed invalid bounds for binary variable <%s>: [%f, %f].\n", name, *lb, *ub);
2479 return SCIP_READERROR;
2480 }
2481 if ( !SCIPsetIsInfinity(set, -(*lazylb)) && !SCIPsetIsInfinity(set, *lazyub) &&
2482 ( SCIPsetIsLT(set, *lazylb, 0.0) || SCIPsetIsGT(set, *lazyub, 1.0) ) )
2483 {
2484 SCIPerrorMessage("Parsed invalid lazy bounds for binary variable <%s>: [%f, %f].\n", name, *lazylb, *lazyub);
2485 return SCIP_READERROR;
2486 }
2487 }
2488
2489 return SCIP_OKAY;
2490}
2491
2492/** parses variable information (in cip format) out of a string; if the parsing process was successful an original
2493 * variable is created and captured; if variable is of integral type, fractional bounds are automatically rounded; an
2494 * integer variable with bounds zero and one is automatically converted into a binary variable
2495 */
2497 SCIP_VAR** var, /**< pointer to variable data */
2498 BMS_BLKMEM* blkmem, /**< block memory */
2499 SCIP_SET* set, /**< global SCIP settings */
2500 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2501 SCIP_STAT* stat, /**< problem statistics */
2502 const char* str, /**< string to parse */
2503 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2504 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2505 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2506 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable */
2507 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data */
2508 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable */
2509 SCIP_VARDATA* vardata, /**< user data for this specific variable */
2510 char** endptr, /**< pointer to store the final string position if successfully */
2511 SCIP_Bool* success /**< pointer store if the paring process was successful */
2512 )
2513{
2514 char name[SCIP_MAXSTRLEN];
2515 SCIP_Real lb;
2516 SCIP_Real ub;
2517 SCIP_Real obj;
2518 SCIP_VARTYPE vartype;
2519 SCIP_Real lazylb;
2520 SCIP_Real lazyub;
2521
2522 assert(var != NULL);
2523 assert(blkmem != NULL);
2524 assert(stat != NULL);
2525 assert(endptr != NULL);
2526 assert(success != NULL);
2527
2528 /* parse string in cip format for variable information */
2529 SCIP_CALL( varParse(set, messagehdlr, str, name, &lb, &ub, &obj, &vartype, &lazylb, &lazyub, FALSE, endptr, success) );
2530
2531 if( *success ) /*lint !e774*/
2532 {
2533 /* create variable */
2534 SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2535 varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2536
2537 /* set variable status and data */
2538 (*var)->varstatus = SCIP_VARSTATUS_ORIGINAL; /*lint !e641*/
2539 (*var)->data.original.origdom.holelist = NULL;
2540 (*var)->data.original.origdom.lb = lb;
2541 (*var)->data.original.origdom.ub = ub;
2542 (*var)->data.original.transvar = NULL;
2543
2544 /* set lazy status of variable bounds */
2545 (*var)->lazylb = lazylb;
2546 (*var)->lazyub = lazyub;
2547
2548 /* capture variable */
2549 SCIPvarCapture(*var);
2550 }
2551
2552 return SCIP_OKAY;
2553}
2554
2555/** parses variable information (in cip format) out of a string; if the parsing process was successful a loose variable
2556 * belonging to the transformed problem is created and captured; if variable is of integral type, fractional bounds are
2557 * automatically rounded; an integer variable with bounds zero and one is automatically converted into a binary
2558 * variable
2559 */
2561 SCIP_VAR** var, /**< pointer to variable data */
2562 BMS_BLKMEM* blkmem, /**< block memory */
2563 SCIP_SET* set, /**< global SCIP settings */
2564 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2565 SCIP_STAT* stat, /**< problem statistics */
2566 const char* str, /**< string to parse */
2567 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
2568 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
2569 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
2570 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable */
2571 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data */
2572 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable */
2573 SCIP_VARDATA* vardata, /**< user data for this specific variable */
2574 char** endptr, /**< pointer to store the final string position if successfully */
2575 SCIP_Bool* success /**< pointer store if the paring process was successful */
2576 )
2577{
2578 char name[SCIP_MAXSTRLEN];
2579 SCIP_Real lb;
2580 SCIP_Real ub;
2581 SCIP_Real obj;
2582 SCIP_VARTYPE vartype;
2583 SCIP_Real lazylb;
2584 SCIP_Real lazyub;
2585
2586 assert(var != NULL);
2587 assert(blkmem != NULL);
2588 assert(endptr != NULL);
2589 assert(success != NULL);
2590
2591 /* parse string in cip format for variable information */
2592 SCIP_CALL( varParse(set, messagehdlr, str, name, &lb, &ub, &obj, &vartype, &lazylb, &lazyub, TRUE, endptr, success) );
2593
2594 if( *success ) /*lint !e774*/
2595 {
2596 /* create variable */
2597 SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2598 varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2599
2600 /* create event filter for transformed variable */
2601 SCIP_CALL( SCIPeventfilterCreate(&(*var)->eventfilter, blkmem) );
2602
2603 /* set variable status and data */
2604 (*var)->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
2605
2606 /* set lazy status of variable bounds */
2607 (*var)->lazylb = lazylb;
2608 (*var)->lazyub = lazyub;
2609
2610 /* capture variable */
2611 SCIPvarCapture(*var);
2612 }
2613
2614 return SCIP_OKAY;
2615}
2616
2617/** ensures, that parentvars array of var can store at least num entries */
2618static
2620 SCIP_VAR* var, /**< problem variable */
2621 BMS_BLKMEM* blkmem, /**< block memory */
2622 SCIP_SET* set, /**< global SCIP settings */
2623 int num /**< minimum number of entries to store */
2624 )
2625{
2626 assert(var->nparentvars <= var->parentvarssize);
2627
2628 if( num > var->parentvarssize )
2629 {
2630 int newsize;
2631
2632 newsize = SCIPsetCalcMemGrowSize(set, num);
2633 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->parentvars, var->parentvarssize, newsize) );
2634 var->parentvarssize = newsize;
2635 }
2636 assert(num <= var->parentvarssize);
2637
2638 return SCIP_OKAY;
2639}
2640
2641/** adds variable to parent list of a variable and captures parent variable */
2642static
2644 SCIP_VAR* var, /**< variable to add parent to */
2645 BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
2646 SCIP_SET* set, /**< global SCIP settings */
2647 SCIP_VAR* parentvar /**< parent variable to add */
2648 )
2649{
2650 assert(var != NULL);
2651 assert(parentvar != NULL);
2652
2653 /* the direct original counterpart must be stored as first parent */
2654 assert(var->nparentvars == 0 || SCIPvarGetStatus(parentvar) != SCIP_VARSTATUS_ORIGINAL);
2655
2656 SCIPsetDebugMsg(set, "adding parent <%s>[%p] to variable <%s>[%p] in slot %d\n",
2657 parentvar->name, (void*)parentvar, var->name, (void*)var, var->nparentvars);
2658
2659 SCIP_CALL( varEnsureParentvarsSize(var, blkmem, set, var->nparentvars+1) );
2660
2661 var->parentvars[var->nparentvars] = parentvar;
2662 var->nparentvars++;
2663
2664 SCIPvarCapture(parentvar);
2665
2666 return SCIP_OKAY;
2667}
2668
2669/** deletes and releases all variables from the parent list of a variable, frees the memory of parents array */
2670static
2672 SCIP_VAR** var, /**< pointer to variable */
2673 BMS_BLKMEM* blkmem, /**< block memory */
2674 SCIP_SET* set, /**< global SCIP settings */
2675 SCIP_EVENTQUEUE* eventqueue, /**< event queue (or NULL, if it's an original variable) */
2676 SCIP_LP* lp /**< current LP data (or NULL, if it's an original variable) */
2677 )
2678{
2679 SCIP_VAR* parentvar;
2680 int i;
2681
2682 SCIPsetDebugMsg(set, "free parents of <%s>\n", (*var)->name);
2683
2684 /* release the parent variables and remove the link from the parent variable to the child */
2685 for( i = 0; i < (*var)->nparentvars; ++i )
2686 {
2687 assert((*var)->parentvars != NULL);
2688 parentvar = (*var)->parentvars[i];
2689 assert(parentvar != NULL);
2690
2691 switch( SCIPvarGetStatus(parentvar) )
2692 {
2694 assert(parentvar->data.original.transvar == *var);
2695 assert(&parentvar->data.original.transvar != var);
2696 parentvar->data.original.transvar = NULL;
2697 break;
2698
2700 assert(parentvar->data.aggregate.var == *var);
2701 assert(&parentvar->data.aggregate.var != var);
2702 parentvar->data.aggregate.var = NULL;
2703 break;
2704
2705#ifdef SCIP_DISABLED_CODE
2706 /* The following code is unclear: should the current variable be removed from its parents? */
2708 assert(parentvar->data.multaggr.vars != NULL);
2709 for( v = 0; v < parentvar->data.multaggr.nvars && parentvar->data.multaggr.vars[v] != *var; ++v )
2710 {}
2711 assert(v < parentvar->data.multaggr.nvars && parentvar->data.multaggr.vars[v] == *var);
2712 if( v < parentvar->data.multaggr.nvars-1 )
2713 {
2714 parentvar->data.multaggr.vars[v] = parentvar->data.multaggr.vars[parentvar->data.multaggr.nvars-1];
2715 parentvar->data.multaggr.scalars[v] = parentvar->data.multaggr.scalars[parentvar->data.multaggr.nvars-1];
2716 }
2717 parentvar->data.multaggr.nvars--;
2718 break;
2719#endif
2720
2722 assert(parentvar->negatedvar == *var);
2723 assert((*var)->negatedvar == parentvar);
2724 parentvar->negatedvar = NULL;
2725 (*var)->negatedvar = NULL;
2726 break;
2727
2728 default:
2729 SCIPerrorMessage("parent variable is neither ORIGINAL, AGGREGATED nor NEGATED\n");
2730 return SCIP_INVALIDDATA;
2731 } /*lint !e788*/
2732
2733 SCIP_CALL( SCIPvarRelease(&(*var)->parentvars[i], blkmem, set, eventqueue, lp) );
2734 }
2735
2736 /* free parentvars array */
2737 BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->parentvars, (*var)->parentvarssize);
2738
2739 return SCIP_OKAY;
2740}
2741
2742/** frees a variable */
2743static
2745 SCIP_VAR** var, /**< pointer to variable */
2746 BMS_BLKMEM* blkmem, /**< block memory */
2747 SCIP_SET* set, /**< global SCIP settings */
2748 SCIP_EVENTQUEUE* eventqueue, /**< event queue (may be NULL, if it's not a column variable) */
2749 SCIP_LP* lp /**< current LP data (may be NULL, if it's not a column variable) */
2750 )
2751{
2752 assert(var != NULL);
2753 assert(*var != NULL);
2754 assert(SCIPvarGetStatus(*var) != SCIP_VARSTATUS_COLUMN || &(*var)->data.col->var != var);
2755 assert((*var)->nuses == 0);
2756 assert((*var)->probindex == -1);
2757 assert((*var)->nlocksup[SCIP_LOCKTYPE_MODEL] == 0);
2758 assert((*var)->nlocksdown[SCIP_LOCKTYPE_MODEL] == 0);
2759
2760 SCIPsetDebugMsg(set, "free variable <%s> with status=%d\n", (*var)->name, SCIPvarGetStatus(*var));
2761
2762 switch( SCIPvarGetStatus(*var) )
2763 {
2765 assert((*var)->data.original.transvar == NULL); /* cannot free variable, if transformed variable is still existing */
2766 holelistFree(&(*var)->data.original.origdom.holelist, blkmem);
2767 assert((*var)->data.original.origdom.holelist == NULL);
2768 break;
2770 break;
2772 SCIP_CALL( SCIPcolFree(&(*var)->data.col, blkmem, set, eventqueue, lp) ); /* free corresponding LP column */
2773 break;
2776 break;
2778 BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.vars, (*var)->data.multaggr.varssize);
2779 BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.scalars, (*var)->data.multaggr.varssize);
2780 break;
2782 break;
2783 default:
2784 SCIPerrorMessage("unknown variable status\n");
2785 return SCIP_INVALIDDATA;
2786 }
2787
2788 /* release all parent variables and free the parentvars array */
2789 SCIP_CALL( varFreeParents(var, blkmem, set, eventqueue, lp) );
2790
2791 /* free user data */
2793 {
2794 if( (*var)->vardelorig != NULL )
2795 {
2796 SCIP_CALL( (*var)->vardelorig(set->scip, *var, &(*var)->vardata) );
2797 }
2798 }
2799 else
2800 {
2801 if( (*var)->vardeltrans != NULL )
2802 {
2803 SCIP_CALL( (*var)->vardeltrans(set->scip, *var, &(*var)->vardata) );
2804 }
2805 }
2806
2807 /* free event filter */
2808 if( (*var)->eventfilter != NULL )
2809 {
2810 SCIP_CALL( SCIPeventfilterFree(&(*var)->eventfilter, blkmem, set) );
2811 }
2812 assert((*var)->eventfilter == NULL);
2813
2814 /* free hole lists */
2815 holelistFree(&(*var)->glbdom.holelist, blkmem);
2816 holelistFree(&(*var)->locdom.holelist, blkmem);
2817 assert((*var)->glbdom.holelist == NULL);
2818 assert((*var)->locdom.holelist == NULL);
2819
2820 /* free variable bounds data structures */
2821 SCIPvboundsFree(&(*var)->vlbs, blkmem);
2822 SCIPvboundsFree(&(*var)->vubs, blkmem);
2823
2824 /* free implications data structures */
2825 SCIPimplicsFree(&(*var)->implics, blkmem);
2826
2827 /* free clique list data structures */
2828 SCIPcliquelistFree(&(*var)->cliquelist, blkmem);
2829
2830 /* free bound change information arrays */
2831 BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->lbchginfos, (*var)->lbchginfossize);
2832 BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->ubchginfos, (*var)->ubchginfossize);
2833
2834 /* free branching and inference history entries */
2835 SCIPhistoryFree(&(*var)->history, blkmem);
2836 SCIPhistoryFree(&(*var)->historycrun, blkmem);
2837 SCIPvaluehistoryFree(&(*var)->valuehistory, blkmem);
2838
2839 /* free variable data structure */
2840 BMSfreeBlockMemoryArray(blkmem, &(*var)->name, strlen((*var)->name)+1);
2841 BMSfreeBlockMemory(blkmem, var);
2842
2843 return SCIP_OKAY;
2844}
2845
2846/** increases usage counter of variable */
2848 SCIP_VAR* var /**< variable */
2849 )
2850{
2851 assert(var != NULL);
2852 assert(var->nuses >= 0);
2853
2854 SCIPdebugMessage("capture variable <%s> with nuses=%d\n", var->name, var->nuses);
2855 var->nuses++;
2856
2857#ifdef DEBUGUSES_VARNAME
2858 if( strcmp(var->name, DEBUGUSES_VARNAME) == 0
2859#ifdef DEBUGUSES_PROBNAME
2860 && ((var->scip->transprob != NULL && strcmp(SCIPprobGetName(var->scip->transprob), DEBUGUSES_PROBNAME) == 0) ||
2861 strcmp(SCIPprobGetName(var->scip->origprob), DEBUGUSES_PROBNAME) == 0)
2862#endif
2863 )
2864 {
2865 printf("Captured variable " DEBUGUSES_VARNAME " in SCIP %p, now %d uses; captured at\n", (void*)var->scip, var->nuses);
2866 print_backtrace();
2867 }
2868#endif
2869}
2870
2871/** decreases usage counter of variable, and frees memory if necessary */
2873 SCIP_VAR** var, /**< pointer to variable */
2874 BMS_BLKMEM* blkmem, /**< block memory */
2875 SCIP_SET* set, /**< global SCIP settings */
2876 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2877 SCIP_LP* lp /**< current LP data (or NULL, if it's an original variable) */
2878 )
2879{
2880 assert(var != NULL);
2881 assert(*var != NULL);
2882 assert((*var)->nuses >= 1);
2883 assert(blkmem != NULL);
2884 assert((*var)->scip == set->scip);
2885
2886 SCIPsetDebugMsg(set, "release variable <%s> with nuses=%d\n", (*var)->name, (*var)->nuses);
2887 (*var)->nuses--;
2888
2889#ifdef DEBUGUSES_VARNAME
2890 if( strcmp((*var)->name, DEBUGUSES_VARNAME) == 0
2891#ifdef DEBUGUSES_PROBNAME
2892 && (((*var)->scip->transprob != NULL && strcmp(SCIPprobGetName((*var)->scip->transprob), DEBUGUSES_PROBNAME) == 0) ||
2893 strcmp(SCIPprobGetName((*var)->scip->origprob), DEBUGUSES_PROBNAME) == 0)
2894#endif
2895 )
2896 {
2897 printf("Released variable " DEBUGUSES_VARNAME " in SCIP %p, now %d uses; released at\n", (void*)(*var)->scip, (*var)->nuses);
2898 print_backtrace();
2899 }
2900#endif
2901
2902 if( (*var)->nuses == 0 )
2903 {
2904 SCIP_CALL( varFree(var, blkmem, set, eventqueue, lp) );
2905 }
2906
2907 *var = NULL;
2908
2909 return SCIP_OKAY;
2910}
2911
2912/** change variable name */
2914 SCIP_VAR* var, /**< problem variable */
2915 BMS_BLKMEM* blkmem, /**< block memory */
2916 const char* name /**< name of variable */
2917 )
2918{
2919 assert(name != NULL);
2920
2921 /* remove old variable name */
2922 BMSfreeBlockMemoryArray(blkmem, &var->name, strlen(var->name)+1);
2923
2924 /* set new variable name */
2925 SCIP_CALL( varSetName(var, blkmem, NULL, name) );
2926
2927 return SCIP_OKAY;
2928}
2929
2930/** initializes variable data structure for solving */
2932 SCIP_VAR* var /**< problem variable */
2933 )
2934{
2935 assert(var != NULL);
2936
2938 var->conflictlbcount = 0;
2939 var->conflictubcount = 0;
2940}
2941
2942/** outputs the given bounds into the file stream */
2943static
2945 SCIP_SET* set, /**< global SCIP settings */
2946 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2947 FILE* file, /**< output file (or NULL for standard output) */
2948 SCIP_Real lb, /**< lower bound */
2949 SCIP_Real ub, /**< upper bound */
2950 const char* name /**< bound type name */
2951 )
2952{
2953 assert(set != NULL);
2954
2955 SCIPmessageFPrintInfo(messagehdlr, file, ", %s=", name);
2956 if( SCIPsetIsInfinity(set, lb) )
2957 SCIPmessageFPrintInfo(messagehdlr, file, "[+inf,");
2958 else if( SCIPsetIsInfinity(set, -lb) )
2959 SCIPmessageFPrintInfo(messagehdlr, file, "[-inf,");
2960 else
2961 SCIPmessageFPrintInfo(messagehdlr, file, "[%.15g,", lb);
2962 if( SCIPsetIsInfinity(set, ub) )
2963 SCIPmessageFPrintInfo(messagehdlr, file, "+inf]");
2964 else if( SCIPsetIsInfinity(set, -ub) )
2965 SCIPmessageFPrintInfo(messagehdlr, file, "-inf]");
2966 else
2967 SCIPmessageFPrintInfo(messagehdlr, file, "%.15g]", ub);
2968}
2969
2970/** prints hole list to file stream */
2971static
2973 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2974 FILE* file, /**< output file (or NULL for standard output) */
2975 SCIP_HOLELIST* holelist, /**< hole list pointer to hole of interest */
2976 const char* name /**< hole type name */
2977 )
2978{ /*lint --e{715}*/
2979 SCIP_Real left;
2980 SCIP_Real right;
2981
2982 if( holelist == NULL )
2983 return;
2984
2985 left = SCIPholelistGetLeft(holelist);
2986 right = SCIPholelistGetRight(holelist);
2987
2988 /* display first hole */
2989 SCIPmessageFPrintInfo(messagehdlr, file, ", %s=(%g,%g)", name, left, right);
2990 holelist = SCIPholelistGetNext(holelist);
2991
2992 while(holelist != NULL )
2993 {
2994 left = SCIPholelistGetLeft(holelist);
2995 right = SCIPholelistGetRight(holelist);
2996
2997 /* display hole */
2998 SCIPmessageFPrintInfo(messagehdlr, file, "(%g,%g)", left, right);
2999
3000 /* get next hole */
3001 holelist = SCIPholelistGetNext(holelist);
3002 }
3003}
3004
3005/** outputs variable information into file stream */
3007 SCIP_VAR* var, /**< problem variable */
3008 SCIP_SET* set, /**< global SCIP settings */
3009 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
3010 FILE* file /**< output file (or NULL for standard output) */
3011 )
3012{
3013 SCIP_HOLELIST* holelist;
3014 SCIP_Real lb;
3015 SCIP_Real ub;
3016 int i;
3017
3018 assert(var != NULL);
3019 assert(var->scip == set->scip);
3020
3021 /* type of variable */
3022 switch( SCIPvarGetType(var) )
3023 {
3025 SCIPmessageFPrintInfo(messagehdlr, file, " [binary]");
3026 break;
3028 SCIPmessageFPrintInfo(messagehdlr, file, " [integer]");
3029 break;
3031 SCIPmessageFPrintInfo(messagehdlr, file, " [implicit]");
3032 break;
3034 SCIPmessageFPrintInfo(messagehdlr, file, " [continuous]");
3035 break;
3036 default:
3037 SCIPerrorMessage("unknown variable type\n");
3038 SCIPABORT();
3039 return SCIP_ERROR; /*lint !e527*/
3040 }
3041
3042 /* name */
3043 SCIPmessageFPrintInfo(messagehdlr, file, " <%s>:", var->name);
3044
3045 /* objective value */
3046 SCIPmessageFPrintInfo(messagehdlr, file, " obj=%.15g", var->obj);
3047
3048 /* bounds (global bounds for transformed variables, original bounds for original variables) */
3049 if( !SCIPvarIsTransformed(var) )
3050 {
3051 /* output original bound */
3052 lb = SCIPvarGetLbOriginal(var);
3053 ub = SCIPvarGetUbOriginal(var);
3054 printBounds(set, messagehdlr, file, lb, ub, "original bounds");
3055
3056 /* output lazy bound */
3057 lb = SCIPvarGetLbLazy(var);
3058 ub = SCIPvarGetUbLazy(var);
3059
3060 /* only display the lazy bounds if they are different from [-infinity,infinity] */
3061 if( !SCIPsetIsInfinity(set, -lb) || !SCIPsetIsInfinity(set, ub) )
3062 printBounds(set, messagehdlr, file, lb, ub, "lazy bounds");
3063
3064 holelist = SCIPvarGetHolelistOriginal(var);
3065 printHolelist(messagehdlr, file, holelist, "original holes");
3066 }
3067 else
3068 {
3069 /* output global bound */
3070 lb = SCIPvarGetLbGlobal(var);
3071 ub = SCIPvarGetUbGlobal(var);
3072 printBounds(set, messagehdlr, file, lb, ub, "global bounds");
3073
3074 /* output local bound */
3075 lb = SCIPvarGetLbLocal(var);
3076 ub = SCIPvarGetUbLocal(var);
3077 printBounds(set, messagehdlr, file, lb, ub, "local bounds");
3078
3079 /* output lazy bound */
3080 lb = SCIPvarGetLbLazy(var);
3081 ub = SCIPvarGetUbLazy(var);
3082
3083 /* only display the lazy bounds if they are different from [-infinity,infinity] */
3084 if( !SCIPsetIsInfinity(set, -lb) || !SCIPsetIsInfinity(set, ub) )
3085 printBounds(set, messagehdlr, file, lb, ub, "lazy bounds");
3086
3087 /* global hole list */
3088 holelist = SCIPvarGetHolelistGlobal(var);
3089 printHolelist(messagehdlr, file, holelist, "global holes");
3090
3091 /* local hole list */
3092 holelist = SCIPvarGetHolelistLocal(var);
3093 printHolelist(messagehdlr, file, holelist, "local holes");
3094 }
3095
3096 /* fixings and aggregations */
3097 switch( SCIPvarGetStatus(var) )
3098 {
3102 break;
3103
3105 SCIPmessageFPrintInfo(messagehdlr, file, ", fixed:");
3106 if( SCIPsetIsInfinity(set, var->glbdom.lb) )
3107 SCIPmessageFPrintInfo(messagehdlr, file, "+inf");
3108 else if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
3109 SCIPmessageFPrintInfo(messagehdlr, file, "-inf");
3110 else
3111 SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", var->glbdom.lb);
3112 break;
3113
3115 SCIPmessageFPrintInfo(messagehdlr, file, ", aggregated:");
3117 SCIPmessageFPrintInfo(messagehdlr, file, " %.15g", var->data.aggregate.constant);
3118 SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g<%s>", var->data.aggregate.scalar, SCIPvarGetName(var->data.aggregate.var));
3119 break;
3120
3122 SCIPmessageFPrintInfo(messagehdlr, file, ", aggregated:");
3123 if( var->data.multaggr.nvars == 0 || !SCIPsetIsZero(set, var->data.multaggr.constant) )
3124 SCIPmessageFPrintInfo(messagehdlr, file, " %.15g", var->data.multaggr.constant);
3125 for( i = 0; i < var->data.multaggr.nvars; ++i )
3126 SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g<%s>", var->data.multaggr.scalars[i], SCIPvarGetName(var->data.multaggr.vars[i]));
3127 break;
3128
3130 SCIPmessageFPrintInfo(messagehdlr, file, ", negated: %.15g - <%s>", var->data.negate.constant, SCIPvarGetName(var->negatedvar));
3131 break;
3132
3133 default:
3134 SCIPerrorMessage("unknown variable status\n");
3135 SCIPABORT();
3136 return SCIP_ERROR; /*lint !e527*/
3137 }
3138
3139 SCIPmessageFPrintInfo(messagehdlr, file, "\n");
3140
3141 return SCIP_OKAY;
3142}
3143
3144/** issues a VARUNLOCKED event on the given variable */
3145static
3147 SCIP_VAR* var, /**< problem variable to change */
3148 BMS_BLKMEM* blkmem, /**< block memory */
3149 SCIP_SET* set, /**< global SCIP settings */
3150 SCIP_EVENTQUEUE* eventqueue /**< event queue */
3151 )
3152{
3153 SCIP_EVENT* event;
3154
3155 assert(var != NULL);
3156 assert(var->nlocksdown[SCIP_LOCKTYPE_MODEL] <= 1 && var->nlocksup[SCIP_LOCKTYPE_MODEL] <= 1);
3157 assert(var->scip == set->scip);
3158
3159 /* issue VARUNLOCKED event on variable */
3160 SCIP_CALL( SCIPeventCreateVarUnlocked(&event, blkmem, var) );
3161 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
3162
3163 return SCIP_OKAY;
3164}
3165
3166/** modifies lock numbers for rounding */
3168 SCIP_VAR* var, /**< problem variable */
3169 BMS_BLKMEM* blkmem, /**< block memory */
3170 SCIP_SET* set, /**< global SCIP settings */
3171 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3172 SCIP_LOCKTYPE locktype, /**< type of the variable locks */
3173 int addnlocksdown, /**< increase in number of rounding down locks */
3174 int addnlocksup /**< increase in number of rounding up locks */
3175 )
3176{
3177 SCIP_VAR* lockvar;
3178
3179 assert(var != NULL);
3180 assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/
3181 assert(var->nlocksup[locktype] >= 0);
3182 assert(var->nlocksdown[locktype] >= 0);
3183 assert(var->scip == set->scip);
3184
3185 if( addnlocksdown == 0 && addnlocksup == 0 )
3186 return SCIP_OKAY;
3187
3188#ifdef SCIP_DEBUG
3189 SCIPsetDebugMsg(set, "add rounding locks %d/%d to variable <%s> (locks=%d/%d, type=%u)\n",
3190 addnlocksdown, addnlocksup, var->name, var->nlocksdown[locktype], var->nlocksup[locktype], locktype);
3191#endif
3192
3193 lockvar = var;
3194
3195 while( TRUE ) /*lint !e716 */
3196 {
3197 assert(lockvar != NULL);
3198
3199 switch( SCIPvarGetStatus(lockvar) )
3200 {
3202 if( lockvar->data.original.transvar != NULL )
3203 {
3204 lockvar = lockvar->data.original.transvar;
3205 break;
3206 }
3207 else
3208 {
3209 lockvar->nlocksdown[locktype] += addnlocksdown;
3210 lockvar->nlocksup[locktype] += addnlocksup;
3211
3212 assert(lockvar->nlocksdown[locktype] >= 0);
3213 assert(lockvar->nlocksup[locktype] >= 0);
3214
3215 return SCIP_OKAY;
3216 }
3220 lockvar->nlocksdown[locktype] += addnlocksdown;
3221 lockvar->nlocksup[locktype] += addnlocksup;
3222
3223 assert(lockvar->nlocksdown[locktype] >= 0);
3224 assert(lockvar->nlocksup[locktype] >= 0);
3225
3226 if( locktype == SCIP_LOCKTYPE_MODEL && lockvar->nlocksdown[locktype] <= 1
3227 && lockvar->nlocksup[locktype] <= 1 )
3228 {
3229 SCIP_CALL( varEventVarUnlocked(lockvar, blkmem, set, eventqueue) );
3230 }
3231
3232 return SCIP_OKAY;
3234 assert(!lockvar->donotaggr);
3235
3236 if( lockvar->data.aggregate.scalar < 0.0 )
3237 {
3238 int tmp = addnlocksup;
3239
3240 addnlocksup = addnlocksdown;
3241 addnlocksdown = tmp;
3242 }
3243
3244 lockvar = lockvar->data.aggregate.var;
3245 break;
3247 {
3248 int v;
3249
3250 assert(!lockvar->donotmultaggr);
3251
3252 lockvar->nlocksdown[locktype] += addnlocksdown;
3253 lockvar->nlocksup[locktype] += addnlocksup;
3254
3255 assert(lockvar->nlocksdown[locktype] >= 0);
3256 assert(lockvar->nlocksup[locktype] >= 0);
3257
3258 for( v = lockvar->data.multaggr.nvars - 1; v >= 0; --v )
3259 {
3260 if( lockvar->data.multaggr.scalars[v] > 0.0 )
3261 {
3262 SCIP_CALL( SCIPvarAddLocks(lockvar->data.multaggr.vars[v], blkmem, set, eventqueue, locktype, addnlocksdown,
3263 addnlocksup) );
3264 }
3265 else
3266 {
3267 SCIP_CALL( SCIPvarAddLocks(lockvar->data.multaggr.vars[v], blkmem, set, eventqueue, locktype, addnlocksup,
3268 addnlocksdown) );
3269 }
3270 }
3271 return SCIP_OKAY;
3272 }
3274 {
3275 int tmp = addnlocksup;
3276
3277 assert(lockvar->negatedvar != NULL);
3279 assert(lockvar->negatedvar->negatedvar == lockvar);
3280
3281 addnlocksup = addnlocksdown;
3282 addnlocksdown = tmp;
3283
3284 lockvar = lockvar->negatedvar;
3285 break;
3286 }
3287 default:
3288 SCIPerrorMessage("unknown variable status\n");
3289 return SCIP_INVALIDDATA;
3290 }
3291 }
3292}
3293
3294/** gets number of locks for rounding down of a special type */
3296 SCIP_VAR* var, /**< problem variable */
3297 SCIP_LOCKTYPE locktype /**< type of variable locks */
3298 )
3299{
3300 int nlocks;
3301 int i;
3302
3303 assert(var != NULL);
3304 assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/
3305 assert(var->nlocksdown[locktype] >= 0);
3306
3307 switch( SCIPvarGetStatus(var) )
3308 {
3310 if( var->data.original.transvar != NULL )
3311 return SCIPvarGetNLocksDownType(var->data.original.transvar, locktype);
3312 else
3313 return var->nlocksdown[locktype];
3314
3318 return var->nlocksdown[locktype];
3319
3321 assert(!var->donotaggr);
3322 if( var->data.aggregate.scalar > 0.0 )
3323 return SCIPvarGetNLocksDownType(var->data.aggregate.var, locktype);
3324 else
3325 return SCIPvarGetNLocksUpType(var->data.aggregate.var, locktype);
3326
3328 assert(!var->donotmultaggr);
3329 nlocks = 0;
3330 for( i = 0; i < var->data.multaggr.nvars; ++i )
3331 {
3332 if( var->data.multaggr.scalars[i] > 0.0 )
3333 nlocks += SCIPvarGetNLocksDownType(var->data.multaggr.vars[i], locktype);
3334 else
3335 nlocks += SCIPvarGetNLocksUpType(var->data.multaggr.vars[i], locktype);
3336 }
3337 return nlocks;
3338
3340 assert(var->negatedvar != NULL);
3342 assert(var->negatedvar->negatedvar == var);
3343 return SCIPvarGetNLocksUpType(var->negatedvar, locktype);
3344
3345 default:
3346 SCIPerrorMessage("unknown variable status\n");
3347 SCIPABORT();
3348 return INT_MAX; /*lint !e527*/
3349 }
3350}
3351
3352/** gets number of locks for rounding up of a special type */
3354 SCIP_VAR* var, /**< problem variable */
3355 SCIP_LOCKTYPE locktype /**< type of variable locks */
3356 )
3357{
3358 int nlocks;
3359 int i;
3360
3361 assert(var != NULL);
3362 assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/
3363 assert(var->nlocksup[locktype] >= 0);
3364
3365 switch( SCIPvarGetStatus(var) )
3366 {
3368 if( var->data.original.transvar != NULL )
3369 return SCIPvarGetNLocksUpType(var->data.original.transvar, locktype);
3370 else
3371 return var->nlocksup[locktype];
3372
3376 return var->nlocksup[locktype];
3377
3379 assert(!var->donotaggr);
3380 if( var->data.aggregate.scalar > 0.0 )
3381 return SCIPvarGetNLocksUpType(var->data.aggregate.var, locktype);
3382 else
3383 return SCIPvarGetNLocksDownType(var->data.aggregate.var, locktype);
3384
3386 assert(!var->donotmultaggr);
3387 nlocks = 0;
3388 for( i = 0; i < var->data.multaggr.nvars; ++i )
3389 {
3390 if( var->data.multaggr.scalars[i] > 0.0 )
3391 nlocks += SCIPvarGetNLocksUpType(var->data.multaggr.vars[i], locktype);
3392 else
3393 nlocks += SCIPvarGetNLocksDownType(var->data.multaggr.vars[i], locktype);
3394 }
3395 return nlocks;
3396
3398 assert(var->negatedvar != NULL);
3400 assert(var->negatedvar->negatedvar == var);
3401 return SCIPvarGetNLocksDownType(var->negatedvar, locktype);
3402
3403 default:
3404 SCIPerrorMessage("unknown variable status\n");
3405 SCIPABORT();
3406 return INT_MAX; /*lint !e527*/
3407 }
3408}
3409
3410/** gets number of locks for rounding down
3411 *
3412 * @note This method will always return variable locks of type model
3413 *
3414 * @note It is recommented to use SCIPvarGetNLocksDownType()
3415 */
3417 SCIP_VAR* var /**< problem variable */
3418 )
3419{
3421}
3422
3423/** gets number of locks for rounding up
3424 *
3425 * @note This method will always return variable locks of type model
3426 *
3427 * @note It is recommented to use SCIPvarGetNLocksUpType()
3428 */
3430 SCIP_VAR* var /**< problem variable */
3431 )
3432{
3434}
3435
3436/** is it possible, to round variable down and stay feasible?
3437 *
3438 * @note This method will always check w.r.t variable locks of type model
3439 */
3441 SCIP_VAR* var /**< problem variable */
3442 )
3443{
3445}
3446
3447/** is it possible, to round variable up and stay feasible?
3448 *
3449 * @note This method will always check w.r.t. variable locks of type model
3450 */
3452 SCIP_VAR* var /**< problem variable */
3453 )
3454{
3455 return (SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == 0);
3456}
3457
3458/** gets and captures transformed variable of a given variable; if the variable is not yet transformed,
3459 * a new transformed variable for this variable is created
3460 */
3462 SCIP_VAR* origvar, /**< original problem variable */
3463 BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
3464 SCIP_SET* set, /**< global SCIP settings */
3465 SCIP_STAT* stat, /**< problem statistics */
3466 SCIP_OBJSENSE objsense, /**< objective sense of original problem; transformed is always MINIMIZE */
3467 SCIP_VAR** transvar /**< pointer to store the transformed variable */
3468 )
3469{
3470 char name[SCIP_MAXSTRLEN];
3471
3472 assert(origvar != NULL);
3473 assert(origvar->scip == set->scip);
3474 assert(SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_ORIGINAL);
3475 assert(SCIPsetIsEQ(set, origvar->glbdom.lb, origvar->locdom.lb));
3476 assert(SCIPsetIsEQ(set, origvar->glbdom.ub, origvar->locdom.ub));
3477 assert(origvar->vlbs == NULL);
3478 assert(origvar->vubs == NULL);
3479 assert(transvar != NULL);
3480
3481 /* check if variable is already transformed */
3482 if( origvar->data.original.transvar != NULL )
3483 {
3484 *transvar = origvar->data.original.transvar;
3485 SCIPvarCapture(*transvar);
3486 }
3487 else
3488 {
3489 int i;
3490
3491 /* create transformed variable */
3492 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "t_%s", origvar->name);
3493 SCIP_CALL( SCIPvarCreateTransformed(transvar, blkmem, set, stat, name,
3494 origvar->glbdom.lb, origvar->glbdom.ub, (SCIP_Real)objsense * origvar->obj,
3495 SCIPvarGetType(origvar), origvar->initial, origvar->removable,
3496 origvar->vardelorig, origvar->vartrans, origvar->vardeltrans, origvar->varcopy, NULL) );
3497
3498 /* copy the branch factor and priority */
3499 (*transvar)->branchfactor = origvar->branchfactor;
3500 (*transvar)->branchpriority = origvar->branchpriority;
3501 (*transvar)->branchdirection = origvar->branchdirection; /*lint !e732*/
3502
3503 /* duplicate hole lists */
3504 SCIP_CALL( holelistDuplicate(&(*transvar)->glbdom.holelist, blkmem, set, origvar->glbdom.holelist) );
3505 SCIP_CALL( holelistDuplicate(&(*transvar)->locdom.holelist, blkmem, set, origvar->locdom.holelist) );
3506
3507 /* link original and transformed variable */
3508 origvar->data.original.transvar = *transvar;
3509 SCIP_CALL( varAddParent(*transvar, blkmem, set, origvar) );
3510
3511 /* copy rounding locks */
3512 for( i = 0; i < NLOCKTYPES; i++ )
3513 {
3514 (*transvar)->nlocksdown[i] = origvar->nlocksdown[i];
3515 (*transvar)->nlocksup[i] = origvar->nlocksup[i];
3516 assert((*transvar)->nlocksdown[i] >= 0);
3517 assert((*transvar)->nlocksup[i] >= 0);
3518 }
3519
3520 /* copy donot(mult)aggr status */
3521 (*transvar)->donotaggr = origvar->donotaggr;
3522 (*transvar)->donotmultaggr = origvar->donotmultaggr;
3523
3524 /* copy lazy bounds */
3525 (*transvar)->lazylb = origvar->lazylb;
3526 (*transvar)->lazyub = origvar->lazyub;
3527
3528 /* transfer eventual variable statistics; do not update global statistics, because this has been done
3529 * when original variable was created
3530 */
3531 SCIPhistoryUnite((*transvar)->history, origvar->history, FALSE);
3532
3533 /* transform user data */
3534 if( origvar->vartrans != NULL )
3535 {
3536 SCIP_CALL( origvar->vartrans(set->scip, origvar, origvar->vardata, *transvar, &(*transvar)->vardata) );
3537 }
3538 else
3539 (*transvar)->vardata = origvar->vardata;
3540 }
3541
3542 SCIPsetDebugMsg(set, "transformed variable: <%s>[%p] -> <%s>[%p]\n", origvar->name, (void*)origvar, (*transvar)->name, (void*)*transvar);
3543
3544 return SCIP_OKAY;
3545}
3546
3547/** gets corresponding transformed variable of an original or negated original variable */
3549 SCIP_VAR* origvar, /**< original problem variable */
3550 BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
3551 SCIP_SET* set, /**< global SCIP settings */
3552 SCIP_STAT* stat, /**< problem statistics */
3553 SCIP_VAR** transvar /**< pointer to store the transformed variable, or NULL if not existing yet */
3554 )
3555{
3556 assert(origvar != NULL);
3558 assert(origvar->scip == set->scip);
3559
3561 {
3562 assert(origvar->negatedvar != NULL);
3564
3565 if( origvar->negatedvar->data.original.transvar == NULL )
3566 *transvar = NULL;
3567 else
3568 {
3569 SCIP_CALL( SCIPvarNegate(origvar->negatedvar->data.original.transvar, blkmem, set, stat, transvar) );
3570 }
3571 }
3572 else
3573 *transvar = origvar->data.original.transvar;
3574
3575 return SCIP_OKAY;
3576}
3577
3578/** converts loose transformed variable into column variable, creates LP column */
3580 SCIP_VAR* var, /**< problem variable */
3581 BMS_BLKMEM* blkmem, /**< block memory */
3582 SCIP_SET* set, /**< global SCIP settings */
3583 SCIP_STAT* stat, /**< problem statistics */
3584 SCIP_PROB* prob, /**< problem data */
3585 SCIP_LP* lp /**< current LP data */
3586 )
3587{
3588 assert(var != NULL);
3589 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
3590 assert(var->scip == set->scip);
3591
3592 SCIPsetDebugMsg(set, "creating column for variable <%s>\n", var->name);
3593
3594 /* switch variable status */
3595 var->varstatus = SCIP_VARSTATUS_COLUMN; /*lint !e641*/
3596
3597 /* create column of variable */
3598 SCIP_CALL( SCIPcolCreate(&var->data.col, blkmem, set, stat, var, 0, NULL, NULL, var->removable) );
3599
3600 if( var->probindex != -1 )
3601 {
3602 /* inform problem about the variable's status change */
3603 SCIP_CALL( SCIPprobVarChangedStatus(prob, blkmem, set, NULL, NULL, var) );
3604
3605 /* inform LP, that problem variable is now a column variable and no longer loose */
3606 SCIP_CALL( SCIPlpUpdateVarColumn(lp, set, var) );
3607 }
3608
3609 return SCIP_OKAY;
3610}
3611
3612/** converts column transformed variable back into loose variable, frees LP column */
3614 SCIP_VAR* var, /**< problem variable */
3615 BMS_BLKMEM* blkmem, /**< block memory */
3616 SCIP_SET* set, /**< global SCIP settings */
3617 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3618 SCIP_PROB* prob, /**< problem data */
3619 SCIP_LP* lp /**< current LP data */
3620 )
3621{
3622 assert(var != NULL);
3624 assert(var->scip == set->scip);
3625 assert(var->data.col != NULL);
3626 assert(var->data.col->lppos == -1);
3627 assert(var->data.col->lpipos == -1);
3628
3629 SCIPsetDebugMsg(set, "deleting column for variable <%s>\n", var->name);
3630
3631 /* free column of variable */
3632 SCIP_CALL( SCIPcolFree(&var->data.col, blkmem, set, eventqueue, lp) );
3633
3634 /* switch variable status */
3635 var->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
3636
3637 if( var->probindex != -1 )
3638 {
3639 /* inform problem about the variable's status change */
3640 SCIP_CALL( SCIPprobVarChangedStatus(prob, blkmem, set, NULL, NULL, var) );
3641
3642 /* inform LP, that problem variable is now a loose variable and no longer a column */
3643 SCIP_CALL( SCIPlpUpdateVarLoose(lp, set, var) );
3644 }
3645
3646 return SCIP_OKAY;
3647}
3648
3649/** issues a VARFIXED event on the given variable and all its parents (except ORIGINAL parents);
3650 * the event issuing on the parents is necessary, because unlike with bound changes, the parent variables
3651 * are not informed about a fixing of an active variable they are pointing to
3652 */
3653static
3655 SCIP_VAR* var, /**< problem variable to change */
3656 BMS_BLKMEM* blkmem, /**< block memory */
3657 SCIP_SET* set, /**< global SCIP settings */
3658 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3659 int fixeventtype /**< is this event a fixation(0), an aggregation(1), or a
3660 * multi-aggregation(2)
3661 */
3662 )
3663{
3664 SCIP_EVENT* event;
3665 SCIP_VARSTATUS varstatus;
3666 int i;
3667
3668 assert(var != NULL);
3669 assert(var->scip == set->scip);
3670 assert(0 <= fixeventtype && fixeventtype <= 2);
3671
3672 /* issue VARFIXED event on variable */
3673 SCIP_CALL( SCIPeventCreateVarFixed(&event, blkmem, var) );
3674 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
3675
3676#ifndef NDEBUG
3677 for( i = var->nparentvars -1; i >= 0; --i )
3678 {
3680 }
3681#endif
3682
3683 switch( fixeventtype )
3684 {
3685 case 0:
3686 /* process all parents of a fixed variable */
3687 for( i = var->nparentvars - 1; i >= 0; --i )
3688 {
3689 varstatus = SCIPvarGetStatus(var->parentvars[i]);
3690
3691 assert(varstatus != SCIP_VARSTATUS_FIXED);
3692
3693 /* issue event on all not yet fixed parent variables, (that should already issued this event) except the original
3694 * one
3695 */
3696 if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3697 {
3698 SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3699 }
3700 }
3701 break;
3702 case 1:
3703 /* process all parents of a aggregated variable */
3704 for( i = var->nparentvars - 1; i >= 0; --i )
3705 {
3706 varstatus = SCIPvarGetStatus(var->parentvars[i]);
3707
3708 assert(varstatus != SCIP_VARSTATUS_FIXED);
3709
3710 /* issue event for not aggregated parent variable, because for these and its parents the var event was already
3711 * issued(, except the original one)
3712 *
3713 * @note that even before an aggregated parent variable, there might be variables, for which the vent was not
3714 * yet issued
3715 */
3716 if( varstatus == SCIP_VARSTATUS_AGGREGATED )
3717 continue;
3718
3719 if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3720 {
3721 SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3722 }
3723 }
3724 break;
3725 case 2:
3726 /* process all parents of a aggregated variable */
3727 for( i = var->nparentvars - 1; i >= 0; --i )
3728 {
3729 varstatus = SCIPvarGetStatus(var->parentvars[i]);
3730
3731 assert(varstatus != SCIP_VARSTATUS_FIXED);
3732
3733 /* issue event on all parent variables except the original one */
3734 if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3735 {
3736 SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3737 }
3738 }
3739 break;
3740 default:
3741 SCIPerrorMessage("unknown variable fixation event origin\n");
3742 return SCIP_INVALIDDATA;
3743 }
3744
3745 return SCIP_OKAY;
3746}
3747
3748/** converts variable into fixed variable */
3750 SCIP_VAR* var, /**< problem variable */
3751 BMS_BLKMEM* blkmem, /**< block memory */
3752 SCIP_SET* set, /**< global SCIP settings */
3753 SCIP_STAT* stat, /**< problem statistics */
3754 SCIP_PROB* transprob, /**< tranformed problem data */
3755 SCIP_PROB* origprob, /**< original problem data */
3756 SCIP_PRIMAL* primal, /**< primal data */
3757 SCIP_TREE* tree, /**< branch and bound tree */
3758 SCIP_REOPT* reopt, /**< reoptimization data structure */
3759 SCIP_LP* lp, /**< current LP data */
3760 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
3761 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
3762 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3763 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
3764 SCIP_Real fixedval, /**< value to fix variable at */
3765 SCIP_Bool* infeasible, /**< pointer to store whether the fixing is infeasible */
3766 SCIP_Bool* fixed /**< pointer to store whether the fixing was performed (variable was unfixed) */
3767 )
3768{
3769 SCIP_Real obj;
3770 SCIP_Real childfixedval;
3771
3772 assert(var != NULL);
3773 assert(var->scip == set->scip);
3774 assert(SCIPsetIsEQ(set, var->glbdom.lb, var->locdom.lb));
3775 assert(SCIPsetIsEQ(set, var->glbdom.ub, var->locdom.ub));
3776 assert(infeasible != NULL);
3777 assert(fixed != NULL);
3778
3779 SCIPsetDebugMsg(set, "fix variable <%s>[%g,%g] to %g\n", var->name, var->glbdom.lb, var->glbdom.ub, fixedval);
3780
3781 *infeasible = FALSE;
3782 *fixed = FALSE;
3783
3785 {
3786 *infeasible = !SCIPsetIsFeasEQ(set, fixedval, var->locdom.lb);
3787 SCIPsetDebugMsg(set, " -> variable already fixed to %g (fixedval=%g): infeasible=%u\n", var->locdom.lb, fixedval, *infeasible);
3788 return SCIP_OKAY;
3789 }
3790 else if( (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && !SCIPsetIsFeasIntegral(set, fixedval))
3791 || SCIPsetIsFeasLT(set, fixedval, var->locdom.lb)
3792 || SCIPsetIsFeasGT(set, fixedval, var->locdom.ub) )
3793 {
3794 SCIPsetDebugMsg(set, " -> fixing infeasible: locdom=[%g,%g], fixedval=%g\n", var->locdom.lb, var->locdom.ub, fixedval);
3795 *infeasible = TRUE;
3796 return SCIP_OKAY;
3797 }
3798
3799 switch( SCIPvarGetStatus(var) )
3800 {
3802 if( var->data.original.transvar == NULL )
3803 {
3804 SCIPerrorMessage("cannot fix an untransformed original variable\n");
3805 return SCIP_INVALIDDATA;
3806 }
3807 SCIP_CALL( SCIPvarFix(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt,
3808 lp, branchcand, eventfilter, eventqueue, cliquetable, fixedval, infeasible, fixed) );
3809 break;
3810
3812 assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
3813
3814 /* set the fixed variable's objective value to 0.0 */
3815 obj = var->obj;
3816 SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
3817
3818 /* since we change the variable type form loose to fixed, we have to adjust the number of loose
3819 * variables in the LP data structure; the loose objective value (looseobjval) in the LP data structure, however,
3820 * gets adjusted automatically, due to the event SCIP_EVENTTYPE_OBJCHANGED which dropped in the moment where the
3821 * objective of this variable is set to zero
3822 */
3824
3825 /* change variable's bounds to fixed value (thereby removing redundant implications and variable bounds) */
3826 holelistFree(&var->glbdom.holelist, blkmem);
3827 holelistFree(&var->locdom.holelist, blkmem);
3828 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, fixedval) );
3829 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, fixedval) );
3830
3831 if( var->glbdom.lb != var->glbdom.ub ) /*lint !e777*/
3832 {
3833 /* explicitly set variable's bounds if the fixed value was in epsilon range of the old bound (so above call didn't set bound) */
3835 {
3836 /* if not continuous variable, then make sure variable is fixed to integer value */
3837 assert(SCIPsetIsIntegral(set, fixedval));
3838 fixedval = SCIPsetRound(set, fixedval);
3839 }
3840 var->glbdom.lb = fixedval;
3841 var->glbdom.ub = fixedval;
3842 }
3843
3844 /* ensure local domain is fixed to same value as global domain */
3845 var->locdom.lb = var->glbdom.lb;
3846 var->locdom.ub = var->glbdom.ub;
3847
3848 /* delete implications and variable bounds information */
3849 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) );
3850 assert(var->vlbs == NULL);
3851 assert(var->vubs == NULL);
3852 assert(var->implics == NULL);
3853
3854 /* clear the history of the variable */
3857
3858 /* convert variable into fixed variable */
3859 var->varstatus = SCIP_VARSTATUS_FIXED; /*lint !e641*/
3860
3861 /* inform problem about the variable's status change */
3862 if( var->probindex != -1 )
3863 {
3864 SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) );
3865 }
3866
3867 /* reset the objective value of the fixed variable, thus adjusting the problem's objective offset */
3868 SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) );
3869
3870 /* issue VARFIXED event */
3871 SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 0) );
3872
3873 *fixed = TRUE;
3874 break;
3875
3877 SCIPerrorMessage("cannot fix a column variable\n");
3878 return SCIP_INVALIDDATA;
3879
3881 SCIPerrorMessage("cannot fix a fixed variable again\n"); /*lint !e527*/
3882 SCIPABORT(); /* case is already handled in earlier if condition */
3883 return SCIP_INVALIDDATA; /*lint !e527*/
3884
3886 /* fix aggregation variable y in x = a*y + c, instead of fixing x directly */
3887 assert(SCIPsetIsZero(set, var->obj));
3888 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
3889 if( SCIPsetIsInfinity(set, fixedval) || SCIPsetIsInfinity(set, -fixedval) )
3890 childfixedval = (var->data.aggregate.scalar < 0.0 ? -fixedval : fixedval);
3891 else
3892 childfixedval = (fixedval - var->data.aggregate.constant)/var->data.aggregate.scalar;
3893 SCIP_CALL( SCIPvarFix(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
3894 branchcand, eventfilter, eventqueue, cliquetable, childfixedval, infeasible, fixed) );
3895 break;
3896
3898 SCIPerrorMessage("cannot fix a multiple aggregated variable\n");
3899 SCIPABORT();
3900 return SCIP_INVALIDDATA; /*lint !e527*/
3901
3903 /* fix negation variable x in x' = offset - x, instead of fixing x' directly */
3904 assert(SCIPsetIsZero(set, var->obj));
3905 assert(var->negatedvar != NULL);
3907 assert(var->negatedvar->negatedvar == var);
3908 SCIP_CALL( SCIPvarFix(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
3909 branchcand, eventfilter, eventqueue, cliquetable, var->data.negate.constant - fixedval, infeasible, fixed) );
3910 break;
3911
3912 default:
3913 SCIPerrorMessage("unknown variable status\n");
3914 return SCIP_INVALIDDATA;
3915 }
3916
3917 return SCIP_OKAY;
3918}
3919
3920/** transforms given variables, scalars and constant to the corresponding active variables, scalars and constant
3921 *
3922 * If the number of needed active variables is greater than the available slots in the variable array, nothing happens except
3923 * that the required size is stored in the corresponding variable; hence, if afterwards the required size is greater than the
3924 * available slots (varssize), nothing happens; otherwise, the active variable representation is stored in the arrays.
3925 *
3926 * The reason for this approach is that we cannot reallocate memory, since we do not know how the
3927 * memory has been allocated (e.g., by a C++ 'new' or SCIP functions).
3928 */
3930 SCIP_SET* set, /**< global SCIP settings */
3931 SCIP_VAR** vars, /**< variable array to get active variables */
3932 SCIP_Real* scalars, /**< scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
3933 int* nvars, /**< pointer to number of variables and values in vars and scalars array */
3934 int varssize, /**< available slots in vars and scalars array */
3935 SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */
3936 int* requiredsize, /**< pointer to store the required array size for the active variables */
3937 SCIP_Bool mergemultiples /**< should multiple occurrences of a var be replaced by a single coeff? */
3938 )
3939{
3940 SCIP_VAR** activevars;
3941 SCIP_Real* activescalars;
3942 int nactivevars;
3943 SCIP_Real activeconstant;
3944 SCIP_Bool activeconstantinf;
3945 int activevarssize;
3946
3947 SCIP_VAR* var;
3948 SCIP_Real scalar;
3949 int v;
3950 int k;
3951
3952 SCIP_VAR** tmpvars;
3953 SCIP_VAR** multvars;
3954 SCIP_Real* tmpscalars;
3955 SCIP_Real* multscalars;
3956 int tmpvarssize;
3957 int ntmpvars;
3958 int nmultvars;
3959
3960 SCIP_VAR* multvar;
3961 SCIP_Real multscalar;
3962 SCIP_Real multconstant;
3963 int pos;
3964
3965 int noldtmpvars;
3966
3967 SCIP_VAR** tmpvars2;
3968 SCIP_Real* tmpscalars2;
3969 int tmpvarssize2;
3970 int ntmpvars2;
3971
3972 SCIP_Bool sortagain = FALSE;
3973
3974 assert(set != NULL);
3975 assert(nvars != NULL);
3976 assert(scalars != NULL || *nvars == 0);
3977 assert(constant != NULL);
3978 assert(requiredsize != NULL);
3979 assert(*nvars <= varssize);
3980
3981 *requiredsize = 0;
3982
3983 if( *nvars == 0 )
3984 return SCIP_OKAY;
3985
3986 assert(vars != NULL);
3987
3988 /* handle the "easy" case of just one variable and avoid memory allocation if the variable is already active */
3989 if( *nvars == 1 && (vars[0]->varstatus == ((int) SCIP_VARSTATUS_COLUMN) || vars[0]->varstatus == ((int) SCIP_VARSTATUS_LOOSE)) )
3990 {
3991 *requiredsize = 1;
3992
3993 return SCIP_OKAY;
3994 }
3995
3996 nactivevars = 0;
3997 activeconstant = 0.0;
3998 activeconstantinf = FALSE;
3999 activevarssize = (*nvars) * 2;
4000 ntmpvars = *nvars;
4001 tmpvarssize = *nvars;
4002
4003 tmpvarssize2 = 1;
4004
4005 /* allocate temporary memory */
4006 SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpvars2, tmpvarssize2) );
4007 SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpscalars2, tmpvarssize2) );
4008 SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) );
4009 SCIP_CALL( SCIPsetAllocBufferArray(set, &activescalars, activevarssize) );
4010 SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpvars, vars, ntmpvars) );
4011 SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpscalars, scalars, ntmpvars) );
4012
4013 /* to avoid unnecessary expanding of variable arrays while disaggregating several variables multiple times combine same variables
4014 * first, first get all corresponding variables with status loose, column, multaggr or fixed
4015 */
4016 for( v = ntmpvars - 1; v >= 0; --v )
4017 {
4018 var = tmpvars[v];
4019 scalar = tmpscalars[v];
4020
4021 assert(var != NULL);
4022 /* transforms given variable, scalar and constant to the corresponding active, fixed, or
4023 * multi-aggregated variable, scalar and constant; if the variable resolves to a fixed
4024 * variable, "scalar" will be 0.0 and the value of the sum will be stored in "constant".
4025 */
4026 SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &scalar, &activeconstant) );
4027 assert(var != NULL);
4028
4029 assert(SCIPsetIsInfinity(set, activeconstant) == (activeconstant == SCIPsetInfinity(set))); /*lint !e777*/
4030 assert(SCIPsetIsInfinity(set, -activeconstant) == (activeconstant == -SCIPsetInfinity(set))); /*lint !e777*/
4031
4032 activeconstantinf = SCIPsetIsInfinity(set, activeconstant) || SCIPsetIsInfinity(set, -activeconstant);
4033
4038
4039 tmpvars[v] = var;
4040 tmpscalars[v] = scalar;
4041 }
4042 noldtmpvars = ntmpvars;
4043
4044 /* sort all variables to combine equal variables easily */
4045 SCIPsortPtrReal((void**)tmpvars, tmpscalars, SCIPvarComp, noldtmpvars);
4046 ntmpvars = 0;
4047 for( v = 1; v < noldtmpvars; ++v )
4048 {
4049 /* combine same variables */
4050 if( SCIPvarCompare(tmpvars[v], tmpvars[ntmpvars]) == 0 )
4051 {
4052 tmpscalars[ntmpvars] += tmpscalars[v];
4053 }
4054 else
4055 {
4056 ++ntmpvars;
4057 if( v > ntmpvars )
4058 {
4059 tmpscalars[ntmpvars] = tmpscalars[v];
4060 tmpvars[ntmpvars] = tmpvars[v];
4061 }
4062 }
4063 }
4064 ++ntmpvars;
4065
4066#ifdef SCIP_MORE_DEBUG
4067 for( v = 1; v < ntmpvars; ++v )
4068 assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0);
4069#endif
4070
4071 /* collect for each variable the representation in active variables */
4072 while( ntmpvars >= 1 )
4073 {
4074 --ntmpvars;
4075 ntmpvars2 = 0;
4076 var = tmpvars[ntmpvars];
4077 scalar = tmpscalars[ntmpvars];
4078
4079 assert(var != NULL);
4080
4081 /* TODO: maybe we should test here on SCIPsetIsZero() instead of 0.0 */
4082 if( scalar == 0.0 )
4083 continue;
4084
4089
4090 switch( SCIPvarGetStatus(var) )
4091 {
4094 /* x = a*y + c */
4095 if( nactivevars >= activevarssize )
4096 {
4097 activevarssize *= 2;
4098 SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) );
4099 SCIP_CALL( SCIPsetReallocBufferArray(set, &activescalars, activevarssize) );
4100 assert(nactivevars < activevarssize);
4101 }
4102 activevars[nactivevars] = var;
4103 activescalars[nactivevars] = scalar;
4104 nactivevars++;
4105 break;
4106
4108 /* x = a_1*y_1 + ... + a_n*y_n + c */
4109 nmultvars = var->data.multaggr.nvars;
4110 multvars = var->data.multaggr.vars;
4111 multscalars = var->data.multaggr.scalars;
4112 sortagain = TRUE;
4113
4114 if( nmultvars + ntmpvars > tmpvarssize )
4115 {
4116 while( nmultvars + ntmpvars > tmpvarssize )
4117 tmpvarssize *= 2;
4118 SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) );
4119 SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars, tmpvarssize) );
4120 assert(nmultvars + ntmpvars <= tmpvarssize);
4121 }
4122
4123 if( nmultvars > tmpvarssize2 )
4124 {
4125 while( nmultvars > tmpvarssize2 )
4126 tmpvarssize2 *= 2;
4127 SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars2, tmpvarssize2) );
4128 SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars2, tmpvarssize2) );
4129 assert(nmultvars <= tmpvarssize2);
4130 }
4131
4132 --nmultvars;
4133
4134 for( ; nmultvars >= 0; --nmultvars )
4135 {
4136 multvar = multvars[nmultvars];
4137 multscalar = multscalars[nmultvars];
4138 multconstant = 0;
4139
4140 assert(multvar != NULL);
4141 SCIP_CALL( SCIPvarGetProbvarSum(&multvar, set, &multscalar, &multconstant) );
4142 assert(multvar != NULL);
4143
4148
4149 if( !activeconstantinf )
4150 {
4151 assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar));
4152
4153 if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) )
4154 {
4155 assert(scalar != 0.0);
4156 if( scalar * multconstant > 0.0 )
4157 {
4158 activeconstant = SCIPsetInfinity(set);
4159 activeconstantinf = TRUE;
4160 }
4161 else
4162 {
4163 activeconstant = -SCIPsetInfinity(set);
4164 activeconstantinf = TRUE;
4165 }
4166 }
4167 else
4168 activeconstant += scalar * multconstant;
4169 }
4170#ifndef NDEBUG
4171 else
4172 {
4173 assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 &&
4174 (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4175 assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 &&
4176 (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4177 }
4178#endif
4179
4180 if( SCIPsortedvecFindPtr((void**)tmpvars, SCIPvarComp, multvar, ntmpvars, &pos) )
4181 {
4182 assert(SCIPvarCompare(tmpvars[pos], multvar) == 0);
4183 tmpscalars[pos] += scalar * multscalar;
4184 }
4185 else
4186 {
4187 tmpvars2[ntmpvars2] = multvar;
4188 tmpscalars2[ntmpvars2] = scalar * multscalar;
4189 ++(ntmpvars2);
4190 assert(ntmpvars2 <= tmpvarssize2);
4191 }
4192 }
4193
4194 if( ntmpvars2 > 0 )
4195 {
4196 /* sort all variables to combine equal variables easily */
4197 SCIPsortPtrReal((void**)tmpvars2, tmpscalars2, SCIPvarComp, ntmpvars2);
4198 pos = 0;
4199 for( v = 1; v < ntmpvars2; ++v )
4200 {
4201 /* combine same variables */
4202 if( SCIPvarCompare(tmpvars2[v], tmpvars2[pos]) == 0 )
4203 {
4204 tmpscalars2[pos] += tmpscalars2[v];
4205 }
4206 else
4207 {
4208 ++pos;
4209 if( v > pos )
4210 {
4211 tmpscalars2[pos] = tmpscalars2[v];
4212 tmpvars2[pos] = tmpvars2[v];
4213 }
4214 }
4215 }
4216 ntmpvars2 = pos + 1;
4217#ifdef SCIP_MORE_DEBUG
4218 for( v = 1; v < ntmpvars2; ++v )
4219 {
4220 assert(SCIPvarCompare(tmpvars2[v], tmpvars2[v-1]) > 0);
4221 }
4222 for( v = 1; v < ntmpvars; ++v )
4223 {
4224 assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0);
4225 }
4226#endif
4227 v = ntmpvars - 1;
4228 k = ntmpvars2 - 1;
4229 pos = ntmpvars + ntmpvars2 - 1;
4230 ntmpvars += ntmpvars2;
4231
4232 while( v >= 0 && k >= 0 )
4233 {
4234 assert(pos >= 0);
4235 assert(SCIPvarCompare(tmpvars[v], tmpvars2[k]) != 0);
4236 if( SCIPvarCompare(tmpvars[v], tmpvars2[k]) >= 0 )
4237 {
4238 tmpvars[pos] = tmpvars[v];
4239 tmpscalars[pos] = tmpscalars[v];
4240 --v;
4241 }
4242 else
4243 {
4244 tmpvars[pos] = tmpvars2[k];
4245 tmpscalars[pos] = tmpscalars2[k];
4246 --k;
4247 }
4248 --pos;
4249 assert(pos >= 0);
4250 }
4251 while( v >= 0 )
4252 {
4253 assert(pos >= 0);
4254 tmpvars[pos] = tmpvars[v];
4255 tmpscalars[pos] = tmpscalars[v];
4256 --v;
4257 --pos;
4258 }
4259 while( k >= 0 )
4260 {
4261 assert(pos >= 0);
4262 tmpvars[pos] = tmpvars2[k];
4263 tmpscalars[pos] = tmpscalars2[k];
4264 --k;
4265 --pos;
4266 }
4267 }
4268#ifdef SCIP_MORE_DEBUG
4269 for( v = 1; v < ntmpvars; ++v )
4270 {
4271 assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0);
4272 }
4273#endif
4274
4275 if( !activeconstantinf )
4276 {
4277 assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar));
4278
4279 multconstant = SCIPvarGetMultaggrConstant(var);
4280
4281 if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) )
4282 {
4283 assert(scalar != 0.0);
4284 if( scalar * multconstant > 0.0 )
4285 {
4286 activeconstant = SCIPsetInfinity(set);
4287 activeconstantinf = TRUE;
4288 }
4289 else
4290 {
4291 activeconstant = -SCIPsetInfinity(set);
4292 activeconstantinf = TRUE;
4293 }
4294 }
4295 else
4296 activeconstant += scalar * multconstant;
4297 }
4298#ifndef NDEBUG
4299 else
4300 {
4301 multconstant = SCIPvarGetMultaggrConstant(var);
4302 assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 &&
4303 (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4304 assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 &&
4305 (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4306 }
4307#endif
4308 break;
4309
4314 default:
4315 /* case x = c, but actually we should not be here, since SCIPvarGetProbvarSum() returns a scalar of 0.0 for
4316 * fixed variables and is handled already
4317 */
4318 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
4319 assert(SCIPsetIsZero(set, var->glbdom.lb) && SCIPsetIsEQ(set, var->glbdom.lb, var->glbdom.ub));
4320 }
4321 }
4322
4323 if( mergemultiples )
4324 {
4325 if( sortagain )
4326 {
4327 /* sort variable and scalar array by variable index */
4328 SCIPsortPtrReal((void**)activevars, activescalars, SCIPvarComp, nactivevars);
4329
4330 /* eliminate duplicates and count required size */
4331 v = nactivevars - 1;
4332 while( v > 0 )
4333 {
4334 /* combine both variable since they are the same */
4335 if( SCIPvarCompare(activevars[v - 1], activevars[v]) == 0 )
4336 {
4337 if( activescalars[v - 1] + activescalars[v] != 0.0 )
4338 {
4339 activescalars[v - 1] += activescalars[v];
4340 --nactivevars;
4341 activevars[v] = activevars[nactivevars];
4342 activescalars[v] = activescalars[nactivevars];
4343 }
4344 else
4345 {
4346 --nactivevars;
4347 activevars[v] = activevars[nactivevars];
4348 activescalars[v] = activescalars[nactivevars];
4349 --nactivevars;
4350 --v;
4351 activevars[v] = activevars[nactivevars];
4352 activescalars[v] = activescalars[nactivevars];
4353 }
4354 }
4355 --v;
4356 }
4357 }
4358 /* the variables were added in reverse order, we revert the order now;
4359 * this should not be necessary, but not doing this changes the behavior sometimes
4360 */
4361 else
4362 {
4363 SCIP_VAR* tmpvar;
4364 SCIP_Real tmpscalar;
4365
4366 for( v = 0; v < nactivevars / 2; ++v )
4367 {
4368 tmpvar = activevars[v];
4369 tmpscalar = activescalars[v];
4370 activevars[v] = activevars[nactivevars - 1 - v];
4371 activescalars[v] = activescalars[nactivevars - 1 - v];
4372 activevars[nactivevars - 1 - v] = tmpvar;
4373 activescalars[nactivevars - 1 - v] = tmpscalar;
4374 }
4375 }
4376 }
4377 *requiredsize = nactivevars;
4378
4379 if( varssize >= *requiredsize )
4380 {
4381 assert(vars != NULL);
4382
4383 *nvars = *requiredsize;
4384
4385 if( !SCIPsetIsInfinity(set, *constant) && !SCIPsetIsInfinity(set, -(*constant)) )
4386 {
4387 /* if the activeconstant is infinite, the constant pointer gets the same value, otherwise add the value */
4388 if( activeconstantinf )
4389 (*constant) = activeconstant;
4390 else
4391 (*constant) += activeconstant;
4392 }
4393#ifndef NDEBUG
4394 else
4395 {
4396 assert(!SCIPsetIsInfinity(set, (*constant)) || !SCIPsetIsInfinity(set, -activeconstant));
4397 assert(!SCIPsetIsInfinity(set, -(*constant)) || !SCIPsetIsInfinity(set, activeconstant));
4398 }
4399#endif
4400
4401 /* copy active variable and scalar array to the given arrays */
4402 for( v = 0; v < *nvars; ++v )
4403 {
4404 vars[v] = activevars[v];
4405 scalars[v] = activescalars[v]; /*lint !e613*/
4406 }
4407 }
4408
4409 assert(SCIPsetIsInfinity(set, *constant) == ((*constant) == SCIPsetInfinity(set))); /*lint !e777*/
4410 assert(SCIPsetIsInfinity(set, -(*constant)) == ((*constant) == -SCIPsetInfinity(set))); /*lint !e777*/
4411
4412 SCIPsetFreeBufferArray(set, &tmpscalars);
4413 SCIPsetFreeBufferArray(set, &tmpvars);
4414 SCIPsetFreeBufferArray(set, &activescalars);
4415 SCIPsetFreeBufferArray(set, &activevars);
4416 SCIPsetFreeBufferArray(set, &tmpscalars2);
4417 SCIPsetFreeBufferArray(set, &tmpvars2);
4418
4419 return SCIP_OKAY;
4420}
4421
4422
4423/** flattens aggregation graph of multi-aggregated variable in order to avoid exponential recursion later on */
4425 SCIP_VAR* var, /**< problem variable */
4426 BMS_BLKMEM* blkmem, /**< block memory */
4427 SCIP_SET* set, /**< global SCIP settings */
4428 SCIP_EVENTQUEUE* eventqueue /**< event queue */
4429 )
4430{
4431 int nlocksup[NLOCKTYPES];
4432 int nlocksdown[NLOCKTYPES];
4433 SCIP_Real multconstant;
4434 int multvarssize;
4435 int nmultvars;
4436 int multrequiredsize;
4437 int i;
4438
4439 assert( var != NULL );
4440 assert( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR );
4441 assert(var->scip == set->scip);
4442
4443 /* in order to update the locks on the active representation of the multi-aggregated variable, we remove all locks
4444 * on the current representation now and re-add the locks once the variable graph has been flattened, which
4445 * may lead to duplicate occurences of the same variable being merged
4446 *
4447 * Here is an example. Assume we have the multi-aggregation z = x + y.
4448 * z occures with positive coefficient in a <= constraint c1, so it has an uplock from there.
4449 * When the multi-aggregation is performed, all locks are added to the active representation,
4450 * so x and y both get an uplock from c1. However, z was not yet replaced by x + y in c1.
4451 * Next, a negation y = 1 - x is identified. Again, locks are moved, so that the uplock of y originating
4452 * from c1 is added to x as a downlock. Thus, x has both an up- and downlock from c1.
4453 * The multi-aggregation changes to z = x + 1 - x, which corresponds to the locks.
4454 * However, before z is replaced by that sum, SCIPvarFlattenAggregationGraph() is called
4455 * which changes z = x + y = x + 1 - x = 1, since it merges multiple occurences of the same variable.
4456 * The up- and downlock of x, however, is not removed when replacing z in c1 by its active representation,
4457 * because it is just 1 now. Therefore, we need to update locks when flattening the aggregation graph.
4458 * For this, the multi-aggregated variable knows its locks in addition to adding them to the active
4459 * representation, which corresponds to the locks from constraints where the variable was not replaced yet.
4460 * By removing the locks here, based on the old representation and adding them again after flattening,
4461 * we ensure that the locks are correct afterwards if coefficients were merged.
4462 */
4463 for( i = 0; i < NLOCKTYPES; ++i )
4464 {
4465 nlocksup[i] = var->nlocksup[i];
4466 nlocksdown[i] = var->nlocksdown[i];
4467
4468 SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, -nlocksdown[i], -nlocksup[i]) );
4469 }
4470
4471 multconstant = var->data.multaggr.constant;
4472 nmultvars = var->data.multaggr.nvars;
4473 multvarssize = var->data.multaggr.varssize;
4474
4475 SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) );
4476
4477 if( multrequiredsize > multvarssize )
4478 {
4479 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.vars), multvarssize, multrequiredsize) );
4480 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.scalars), multvarssize, multrequiredsize) );
4481 multvarssize = multrequiredsize;
4482 SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) );
4483 assert( multrequiredsize <= multvarssize );
4484 }
4485 /**@note After the flattening the multi aggregation might resolve to be in fact an aggregation (or even a fixing?).
4486 * This issue is not resolved right now, since var->data.multaggr.nvars < 2 should not cause troubles. However, one
4487 * may loose performance hereby, since aggregated variables are easier to handle.
4488 *
4489 * Note, that there are two cases where SCIPvarFlattenAggregationGraph() is called: The easier one is that it is
4490 * called while installing the multi-aggregation. in principle, the described issue could be handled straightforward
4491 * in this case by aggregating or fixing the variable instead. The more complicated case is the one, when the
4492 * multi-aggregation is used, e.g., in linear presolving (and the variable is already declared to be multi-aggregated).
4493 *
4494 * By now, it is not allowed to fix or aggregate multi-aggregated variables which would be necessary in this case.
4495 *
4496 * The same issue appears in the SCIPvarGetProbvar...() methods.
4497 */
4498
4499 var->data.multaggr.constant = multconstant;
4500 var->data.multaggr.nvars = nmultvars;
4501 var->data.multaggr.varssize = multvarssize;
4502
4503 for( i = 0; i < NLOCKTYPES; ++i )
4504 {
4505 SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) );
4506 }
4507
4508 return SCIP_OKAY;
4509}
4510
4511/** merge two variable histories together; a typical use case is that \p othervar is an image of the target variable
4512 * in a SCIP copy. Method should be applied with care, especially because no internal checks are performed whether
4513 * the history merge is reasonable
4514 *
4515 * @note Do not use this method if the two variables originate from two SCIP's with different objective functions, since
4516 * this corrupts the variable pseudo costs
4517 * @note Apply with care; no internal checks are performed if the two variables should be merged
4518 */
4520 SCIP_VAR* targetvar, /**< the variable that should contain both histories afterwards */
4521 SCIP_VAR* othervar, /**< the variable whose history is to be merged with that of the target variable */
4522 SCIP_STAT* stat /**< problem statistics */
4523 )
4524{
4525 /* merge only the history of the current run into the target history */
4526 SCIPhistoryUnite(targetvar->history, othervar->historycrun, FALSE);
4527
4528 /* apply the changes also to the global history */
4529 SCIPhistoryUnite(stat->glbhistory, othervar->historycrun, FALSE);
4530}
4531
4532/** sets the history of a variable; this method is typically used within reoptimization to keep and update the variable
4533 * history over several iterations
4534 */
4536 SCIP_VAR* var, /**< variable */
4537 SCIP_HISTORY* history, /**< the history which is to set */
4538 SCIP_STAT* stat /**< problem statistics */
4539 )
4540{
4541 /* merge only the history of the current run into the target history */
4542 SCIPhistoryUnite(var->history, history, FALSE);
4543
4544 /* apply the changes also to the global history */
4545 SCIPhistoryUnite(stat->glbhistory, history, FALSE);
4546}
4547
4548/** tightens the bounds of both variables in aggregation x = a*y + c */
4549static
4551 SCIP_VAR* var, /**< problem variable */
4552 BMS_BLKMEM* blkmem, /**< block memory */
4553 SCIP_SET* set, /**< global SCIP settings */
4554 SCIP_STAT* stat, /**< problem statistics */
4555 SCIP_PROB* transprob, /**< tranformed problem data */
4556 SCIP_PROB* origprob, /**< original problem data */
4557 SCIP_PRIMAL* primal, /**< primal data */
4558 SCIP_TREE* tree, /**< branch and bound tree */
4559 SCIP_REOPT* reopt, /**< reoptimization data structure */
4560 SCIP_LP* lp, /**< current LP data */
4561 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4562 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
4563 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4564 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
4565 SCIP_VAR* aggvar, /**< variable y in aggregation x = a*y + c */
4566 SCIP_Real scalar, /**< multiplier a in aggregation x = a*y + c */
4567 SCIP_Real constant, /**< constant shift c in aggregation x = a*y + c */
4568 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
4569 SCIP_Bool* fixed /**< pointer to store whether the variables were fixed */
4570 )
4571{
4572 SCIP_Real varlb;
4573 SCIP_Real varub;
4574 SCIP_Real aggvarlb;
4575 SCIP_Real aggvarub;
4576 SCIP_Bool aggvarbdschanged;
4577
4578 assert(var != NULL);
4579 assert(var->scip == set->scip);
4580 assert(aggvar != NULL);
4581 assert(!SCIPsetIsZero(set, scalar));
4582 assert(infeasible != NULL);
4583 assert(fixed != NULL);
4584
4585 *infeasible = FALSE;
4586 *fixed = FALSE;
4587
4588 SCIPsetDebugMsg(set, "updating bounds of variables in aggregation <%s> == %g*<%s> %+g\n", var->name, scalar, aggvar->name, constant);
4589 SCIPsetDebugMsg(set, " old bounds: <%s> [%g,%g] <%s> [%g,%g]\n",
4590 var->name, var->glbdom.lb, var->glbdom.ub, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub);
4591
4592 /* loop as long additional changes may be found */
4593 do
4594 {
4595 aggvarbdschanged = FALSE;
4596
4597 /* update the bounds of the aggregated variable x in x = a*y + c */
4598 if( scalar > 0.0 )
4599 {
4600 if( SCIPsetIsInfinity(set, -aggvar->glbdom.lb) )
4601 varlb = -SCIPsetInfinity(set);
4602 else
4603 varlb = aggvar->glbdom.lb * scalar + constant;
4604 if( SCIPsetIsInfinity(set, aggvar->glbdom.ub) )
4605 varub = SCIPsetInfinity(set);
4606 else
4607 varub = aggvar->glbdom.ub * scalar + constant;
4608 }
4609 else
4610 {
4611 if( SCIPsetIsInfinity(set, -aggvar->glbdom.lb) )
4612 varub = SCIPsetInfinity(set);
4613 else
4614 varub = aggvar->glbdom.lb * scalar + constant;
4615 if( SCIPsetIsInfinity(set, aggvar->glbdom.ub) )
4616 varlb = -SCIPsetInfinity(set);
4617 else
4618 varlb = aggvar->glbdom.ub * scalar + constant;
4619 }
4620 varlb = MAX(varlb, var->glbdom.lb);
4621 varub = MIN(varub, var->glbdom.ub);
4622 SCIPvarAdjustLb(var, set, &varlb);
4623 SCIPvarAdjustUb(var, set, &varub);
4624
4625 /* check the new bounds */
4626 if( SCIPsetIsGT(set, varlb, varub) )
4627 {
4628 /* the aggregation is infeasible */
4629 *infeasible = TRUE;
4630 return SCIP_OKAY;
4631 }
4632 else if( SCIPsetIsEQ(set, varlb, varub) )
4633 {
4634 /* the aggregated variable is fixed -> fix both variables */
4635 SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4636 eventfilter, eventqueue, cliquetable, varlb, infeasible, fixed) );
4637 if( !(*infeasible) )
4638 {
4639 SCIP_Bool aggfixed;
4640
4641 SCIP_CALL( SCIPvarFix(aggvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4642 eventfilter, eventqueue, cliquetable, (varlb-constant)/scalar, infeasible, &aggfixed) );
4643 assert(*fixed == aggfixed);
4644 }
4645 return SCIP_OKAY;
4646 }
4647 else
4648 {
4649 if( SCIPsetIsGT(set, varlb, var->glbdom.lb) )
4650 {
4651 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, varlb) );
4652 }
4653 if( SCIPsetIsLT(set, varub, var->glbdom.ub) )
4654 {
4655 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, varub) );
4656 }
4657
4658 /* update the hole list of the aggregation variable */
4659 /**@todo update hole list of aggregation variable */
4660 }
4661
4662 /* update the bounds of the aggregation variable y in x = a*y + c -> y = (x-c)/a */
4663 if( scalar > 0.0 )
4664 {
4665 if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
4666 aggvarlb = -SCIPsetInfinity(set);
4667 else
4668 aggvarlb = (var->glbdom.lb - constant) / scalar;
4669 if( SCIPsetIsInfinity(set, var->glbdom.ub) )
4670 aggvarub = SCIPsetInfinity(set);
4671 else
4672 aggvarub = (var->glbdom.ub - constant) / scalar;
4673 }
4674 else
4675 {
4676 if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
4677 aggvarub = SCIPsetInfinity(set);
4678 else
4679 aggvarub = (var->glbdom.lb - constant) / scalar;
4680 if( SCIPsetIsInfinity(set, var->glbdom.ub) )
4681 aggvarlb = -SCIPsetInfinity(set);
4682 else
4683 aggvarlb = (var->glbdom.ub - constant) / scalar;
4684 }
4685 aggvarlb = MAX(aggvarlb, aggvar->glbdom.lb);
4686 aggvarub = MIN(aggvarub, aggvar->glbdom.ub);
4687 SCIPvarAdjustLb(aggvar, set, &aggvarlb);
4688 SCIPvarAdjustUb(aggvar, set, &aggvarub);
4689
4690 /* check the new bounds */
4691 if( SCIPsetIsGT(set, aggvarlb, aggvarub) )
4692 {
4693 /* the aggregation is infeasible */
4694 *infeasible = TRUE;
4695 return SCIP_OKAY;
4696 }
4697 else if( SCIPsetIsEQ(set, aggvarlb, aggvarub) )
4698 {
4699 /* the aggregation variable is fixed -> fix both variables */
4700 SCIP_CALL( SCIPvarFix(aggvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4701 eventfilter, eventqueue, cliquetable, aggvarlb, infeasible, fixed) );
4702 if( !(*infeasible) )
4703 {
4704 SCIP_Bool varfixed;
4705
4706 SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4707 eventfilter, eventqueue, cliquetable, aggvarlb * scalar + constant, infeasible, &varfixed) );
4708 assert(*fixed == varfixed);
4709 }
4710 return SCIP_OKAY;
4711 }
4712 else
4713 {
4714 SCIP_Real oldbd;
4715 if( SCIPsetIsGT(set, aggvarlb, aggvar->glbdom.lb) )
4716 {
4717 oldbd = aggvar->glbdom.lb;
4718 SCIP_CALL( SCIPvarChgLbGlobal(aggvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, aggvarlb) );
4719 aggvarbdschanged = !SCIPsetIsEQ(set, oldbd, aggvar->glbdom.lb);
4720 }
4721 if( SCIPsetIsLT(set, aggvarub, aggvar->glbdom.ub) )
4722 {
4723 oldbd = aggvar->glbdom.ub;
4724 SCIP_CALL( SCIPvarChgUbGlobal(aggvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, aggvarub) );
4725 aggvarbdschanged = aggvarbdschanged || !SCIPsetIsEQ(set, oldbd, aggvar->glbdom.ub);
4726 }
4727
4728 /* update the hole list of the aggregation variable */
4729 /**@todo update hole list of aggregation variable */
4730 }
4731 }
4732 while( aggvarbdschanged );
4733
4734 SCIPsetDebugMsg(set, " new bounds: <%s> [%g,%g] <%s> [%g,%g]\n",
4735 var->name, var->glbdom.lb, var->glbdom.ub, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub);
4736
4737 return SCIP_OKAY;
4738}
4739
4740/** converts loose variable into aggregated variable */
4742 SCIP_VAR* var, /**< loose problem variable */
4743 BMS_BLKMEM* blkmem, /**< block memory */
4744 SCIP_SET* set, /**< global SCIP settings */
4745 SCIP_STAT* stat, /**< problem statistics */
4746 SCIP_PROB* transprob, /**< tranformed problem data */
4747 SCIP_PROB* origprob, /**< original problem data */
4748 SCIP_PRIMAL* primal, /**< primal data */
4749 SCIP_TREE* tree, /**< branch and bound tree */
4750 SCIP_REOPT* reopt, /**< reoptimization data structure */
4751 SCIP_LP* lp, /**< current LP data */
4752 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
4753 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4754 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
4755 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4756 SCIP_VAR* aggvar, /**< loose variable y in aggregation x = a*y + c */
4757 SCIP_Real scalar, /**< multiplier a in aggregation x = a*y + c */
4758 SCIP_Real constant, /**< constant shift c in aggregation x = a*y + c */
4759 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
4760 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
4761 )
4762{
4763 SCIP_VAR** vars;
4764 SCIP_Real* coefs;
4765 SCIP_Real* constants;
4766 SCIP_Real obj;
4767 SCIP_Real branchfactor;
4768 SCIP_Bool fixed;
4769 int branchpriority;
4770 int nlocksdown[NLOCKTYPES];
4771 int nlocksup[NLOCKTYPES];
4772 int nvbds;
4773 int i;
4774 int j;
4775
4776 assert(var != NULL);
4777 assert(aggvar != NULL);
4778 assert(var->scip == set->scip);
4779 assert(var->glbdom.lb == var->locdom.lb); /*lint !e777*/
4780 assert(var->glbdom.ub == var->locdom.ub); /*lint !e777*/
4781 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
4782 assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
4783 assert(infeasible != NULL);
4784 assert(aggregated != NULL);
4785
4786 *infeasible = FALSE;
4787 *aggregated = FALSE;
4788
4789 /* get active problem variable of aggregation variable */
4790 SCIP_CALL( SCIPvarGetProbvarSum(&aggvar, set, &scalar, &constant) );
4791
4792 /* aggregation is a fixing, if the scalar is zero */
4793 if( SCIPsetIsZero(set, scalar) )
4794 {
4795 SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventfilter,
4796 eventqueue, cliquetable, constant, infeasible, aggregated) );
4797 goto TERMINATE;
4798 }
4799
4800 /* don't perform the aggregation if the aggregation variable is multi-aggregated itself */
4802 return SCIP_OKAY;
4803
4804 /**@todo currently we don't perform the aggregation if the aggregation variable has a non-empty hole list; this
4805 * should be changed in the future
4806 */
4807 if( SCIPvarGetHolelistGlobal(var) != NULL )
4808 return SCIP_OKAY;
4809
4810 /* if the variable is not allowed to be aggregated */
4811 if( SCIPvarDoNotAggr(var) )
4812 {
4813 SCIPsetDebugMsg(set, "variable is not allowed to be aggregated.\n");
4814 return SCIP_OKAY;
4815 }
4816
4817 assert(aggvar->glbdom.lb == aggvar->locdom.lb); /*lint !e777*/
4818 assert(aggvar->glbdom.ub == aggvar->locdom.ub); /*lint !e777*/
4819 assert(SCIPvarGetStatus(aggvar) == SCIP_VARSTATUS_LOOSE);
4820
4821 SCIPsetDebugMsg(set, "aggregate variable <%s>[%g,%g] == %g*<%s>[%g,%g] %+g\n", var->name, var->glbdom.lb, var->glbdom.ub,
4822 scalar, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub, constant);
4823
4824 /* if variable and aggregation variable are equal, the variable can be fixed: x == a*x + c => x == c/(1-a) */
4825 if( var == aggvar )
4826 {
4827 if( SCIPsetIsEQ(set, scalar, 1.0) )
4828 *infeasible = !SCIPsetIsZero(set, constant);
4829 else
4830 {
4831 SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4832 eventfilter, eventqueue, cliquetable, constant/(1.0-scalar), infeasible, aggregated) );
4833 }
4834 goto TERMINATE;
4835 }
4836
4837 /* tighten the bounds of aggregated and aggregation variable */
4838 SCIP_CALL( varUpdateAggregationBounds(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
4839 branchcand, eventfilter, eventqueue, cliquetable, aggvar, scalar, constant, infeasible, &fixed) );
4840 if( *infeasible || fixed )
4841 {
4842 *aggregated = fixed;
4843 goto TERMINATE;
4844 }
4845
4846 /* delete implications and variable bounds of the aggregated variable from other variables, but keep them in the
4847 * aggregated variable
4848 */
4849 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, FALSE) );
4850
4851 /* set the aggregated variable's objective value to 0.0 */
4852 obj = var->obj;
4853 SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
4854
4855 /* unlock all locks */
4856 for( i = 0; i < NLOCKTYPES; i++ )
4857 {
4858 nlocksdown[i] = var->nlocksdown[i];
4859 nlocksup[i] = var->nlocksup[i];
4860
4861 var->nlocksdown[i] = 0;
4862 var->nlocksup[i] = 0;
4863 }
4864
4865 /* check, if variable should be used as NEGATED variable of the aggregation variable */
4866 if( SCIPvarIsBinary(var) && SCIPvarIsBinary(aggvar)
4867 && var->negatedvar == NULL && aggvar->negatedvar == NULL
4868 && SCIPsetIsEQ(set, scalar, -1.0) && SCIPsetIsEQ(set, constant, 1.0) )
4869 {
4870 /* link both variables as negation pair */
4871 var->varstatus = SCIP_VARSTATUS_NEGATED; /*lint !e641*/
4872 var->data.negate.constant = 1.0;
4873 var->negatedvar = aggvar;
4874 aggvar->negatedvar = var;
4875
4876 /* copy donot(mult)aggr status */
4877 aggvar->donotaggr |= var->donotaggr;
4878 aggvar->donotmultaggr |= var->donotmultaggr;
4879
4880 /* mark both variables to be non-deletable */
4883 }
4884 else
4885 {
4886 /* convert variable into aggregated variable */
4887 var->varstatus = SCIP_VARSTATUS_AGGREGATED; /*lint !e641*/
4888 var->data.aggregate.var = aggvar;
4889 var->data.aggregate.scalar = scalar;
4890 var->data.aggregate.constant = constant;
4891
4892 /* copy donot(mult)aggr status */
4893 aggvar->donotaggr |= var->donotaggr;
4894 aggvar->donotmultaggr |= var->donotmultaggr;
4895
4896 /* mark both variables to be non-deletable */
4899 }
4900
4901 /* make aggregated variable a parent of the aggregation variable */
4902 SCIP_CALL( varAddParent(aggvar, blkmem, set, var) );
4903
4904 /* relock the variable, thus increasing the locks of the aggregation variable */
4905 for( i = 0; i < NLOCKTYPES; i++ )
4906 {
4907 SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) );
4908 }
4909
4910 /* move the variable bounds to the aggregation variable:
4911 * - add all variable bounds again to the variable, thus adding it to the aggregation variable
4912 * - free the variable bounds data structures
4913 */
4914 if( var->vlbs != NULL )
4915 {
4916 nvbds = SCIPvboundsGetNVbds(var->vlbs);
4917 vars = SCIPvboundsGetVars(var->vlbs);
4918 coefs = SCIPvboundsGetCoefs(var->vlbs);
4919 constants = SCIPvboundsGetConstants(var->vlbs);
4920 for( i = 0; i < nvbds && !(*infeasible); ++i )
4921 {
4922 SCIP_CALL( SCIPvarAddVlb(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
4923 eventqueue, vars[i], coefs[i], constants[i], FALSE, infeasible, NULL) );
4924 }
4925 }
4926 if( var->vubs != NULL )
4927 {
4928 nvbds = SCIPvboundsGetNVbds(var->vubs);
4929 vars = SCIPvboundsGetVars(var->vubs);
4930 coefs = SCIPvboundsGetCoefs(var->vubs);
4931 constants = SCIPvboundsGetConstants(var->vubs);
4932 for( i = 0; i < nvbds && !(*infeasible); ++i )
4933 {
4934 SCIP_CALL( SCIPvarAddVub(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
4935 eventqueue, vars[i], coefs[i], constants[i], FALSE, infeasible, NULL) );
4936 }
4937 }
4938 SCIPvboundsFree(&var->vlbs, blkmem);
4939 SCIPvboundsFree(&var->vubs, blkmem);
4940
4941 /* move the implications to the aggregation variable:
4942 * - add all implications again to the variable, thus adding it to the aggregation variable
4943 * - free the implications data structures
4944 */
4945 if( var->implics != NULL && SCIPvarGetType(aggvar) == SCIP_VARTYPE_BINARY )
4946 {
4947 assert(SCIPvarIsBinary(var));
4948 for( i = 0; i < 2; ++i )
4949 {
4950 SCIP_VAR** implvars;
4951 SCIP_BOUNDTYPE* impltypes;
4952 SCIP_Real* implbounds;
4953 int nimpls;
4954
4955 nimpls = SCIPimplicsGetNImpls(var->implics, (SCIP_Bool)i);
4956 implvars = SCIPimplicsGetVars(var->implics, (SCIP_Bool)i);
4957 impltypes = SCIPimplicsGetTypes(var->implics, (SCIP_Bool)i);
4958 implbounds = SCIPimplicsGetBounds(var->implics, (SCIP_Bool)i);
4959
4960 for( j = 0; j < nimpls && !(*infeasible); ++j )
4961 {
4962 /* @todo can't we omit transitive closure, because it should already have been done when adding the
4963 * implication to the aggregated variable?
4964 */
4965 SCIP_CALL( SCIPvarAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
4966 branchcand, eventqueue, (SCIP_Bool)i, implvars[j], impltypes[j], implbounds[j], FALSE, infeasible,
4967 NULL) );
4968 assert(nimpls == SCIPimplicsGetNImpls(var->implics, (SCIP_Bool)i));
4969 }
4970 }
4971 }
4972 SCIPimplicsFree(&var->implics, blkmem);
4973
4974 /* add the history entries to the aggregation variable and clear the history of the aggregated variable */
4975 SCIPhistoryUnite(aggvar->history, var->history, scalar < 0.0);
4976 SCIPhistoryUnite(aggvar->historycrun, var->historycrun, scalar < 0.0);
4979
4980 /* update flags of aggregation variable */
4981 aggvar->removable &= var->removable;
4982
4983 /* update branching factors and priorities of both variables to be the maximum of both variables */
4984 branchfactor = MAX(aggvar->branchfactor, var->branchfactor);
4985 branchpriority = MAX(aggvar->branchpriority, var->branchpriority);
4986 SCIP_CALL( SCIPvarChgBranchFactor(aggvar, set, branchfactor) );
4987 SCIP_CALL( SCIPvarChgBranchPriority(aggvar, branchpriority) );
4988 SCIP_CALL( SCIPvarChgBranchFactor(var, set, branchfactor) );
4989 SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) );
4990
4991 /* update branching direction of both variables to agree to a single direction */
4992 if( scalar >= 0.0 )
4993 {
4995 {
4997 }
4999 {
5001 }
5002 else if( var->branchdirection != aggvar->branchdirection )
5003 {
5005 }
5006 }
5007 else
5008 {
5010 {
5012 }
5014 {
5016 }
5017 else if( var->branchdirection != aggvar->branchdirection )
5018 {
5020 }
5021 }
5022
5023 if( var->probindex != -1 )
5024 {
5025 /* inform problem about the variable's status change */
5026 SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) );
5027 }
5028
5029 /* reset the objective value of the aggregated variable, thus adjusting the objective value of the aggregation
5030 * variable and the problem's objective offset
5031 */
5032 SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) );
5033
5034 /* issue VARFIXED event */
5035 SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 1) );
5036
5037 *aggregated = TRUE;
5038
5039TERMINATE:
5040 /* check aggregation on debugging solution */
5041 if( *infeasible || *aggregated )
5042 SCIP_CALL( SCIPdebugCheckAggregation(set, var, &aggvar, &scalar, constant, 1) ); /*lint !e506 !e774*/
5043
5044 return SCIP_OKAY;
5045}
5046
5047/** Tries to aggregate an equality a*x + b*y == c consisting of two (implicit) integral active problem variables x and
5048 * y. An integer aggregation (i.e. integral coefficients a' and b', such that a'*x + b'*y == c') is searched.
5049 *
5050 * This can lead to the detection of infeasibility (e.g. if c' is fractional), or to a rejection of the aggregation
5051 * (denoted by aggregated == FALSE), if the resulting integer coefficients are too large and thus numerically instable.
5052 */
5053static
5055 SCIP_SET* set, /**< global SCIP settings */
5056 BMS_BLKMEM* blkmem, /**< block memory */
5057 SCIP_STAT* stat, /**< problem statistics */
5058 SCIP_PROB* transprob, /**< tranformed problem data */
5059 SCIP_PROB* origprob, /**< original problem data */
5060 SCIP_PRIMAL* primal, /**< primal data */
5061 SCIP_TREE* tree, /**< branch and bound tree */
5062 SCIP_REOPT* reopt, /**< reoptimization data structure */
5063 SCIP_LP* lp, /**< current LP data */
5064 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
5065 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
5066 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
5067 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5068 SCIP_VAR* varx, /**< integral variable x in equality a*x + b*y == c */
5069 SCIP_VAR* vary, /**< integral variable y in equality a*x + b*y == c */
5070 SCIP_Real scalarx, /**< multiplier a in equality a*x + b*y == c */
5071 SCIP_Real scalary, /**< multiplier b in equality a*x + b*y == c */
5072 SCIP_Real rhs, /**< right hand side c in equality a*x + b*y == c */
5073 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
5074 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
5075 )
5076{
5077 SCIP_VAR* aggvar;
5078 char aggvarname[SCIP_MAXSTRLEN];
5079 SCIP_Longint scalarxn = 0;
5080 SCIP_Longint scalarxd = 0;
5081 SCIP_Longint scalaryn = 0;
5082 SCIP_Longint scalaryd = 0;
5085 SCIP_Longint c;
5086 SCIP_Longint scm;
5087 SCIP_Longint gcd;
5088 SCIP_Longint currentclass;
5089 SCIP_Longint classstep;
5090 SCIP_Longint xsol;
5091 SCIP_Longint ysol;
5092 SCIP_Bool success;
5093 SCIP_VARTYPE vartype;
5094
5095#define MAXDNOM 1000000LL
5096
5097 assert(set != NULL);
5098 assert(blkmem != NULL);
5099 assert(stat != NULL);
5100 assert(transprob != NULL);
5101 assert(origprob != NULL);
5102 assert(tree != NULL);
5103 assert(lp != NULL);
5104 assert(cliquetable != NULL);
5105 assert(branchcand != NULL);
5106 assert(eventqueue != NULL);
5107 assert(varx != NULL);
5108 assert(vary != NULL);
5109 assert(varx != vary);
5110 assert(infeasible != NULL);
5111 assert(aggregated != NULL);
5113 assert(SCIPvarGetStatus(varx) == SCIP_VARSTATUS_LOOSE);
5115 assert(SCIPvarGetStatus(vary) == SCIP_VARSTATUS_LOOSE);
5117 assert(!SCIPsetIsZero(set, scalarx));
5118 assert(!SCIPsetIsZero(set, scalary));
5119
5120 *infeasible = FALSE;
5121 *aggregated = FALSE;
5122
5123 /* if the variable is not allowed to be aggregated */
5124 if( SCIPvarDoNotAggr(varx) )
5125 {
5126 SCIPsetDebugMsg(set, "variable is not allowed to be aggregated.\n");
5127 return SCIP_OKAY;
5128 }
5129
5130 /* get rational representation of coefficients */
5131 success = SCIPrealToRational(scalarx, -SCIPsetEpsilon(set), SCIPsetEpsilon(set), MAXDNOM, &scalarxn, &scalarxd);
5132 if( success )
5133 success = SCIPrealToRational(scalary, -SCIPsetEpsilon(set), SCIPsetEpsilon(set), MAXDNOM, &scalaryn, &scalaryd);
5134 if( !success )
5135 return SCIP_OKAY;
5136 assert(scalarxd >= 1);
5137 assert(scalaryd >= 1);
5138
5139 /* multiply equality with smallest common denominator */
5140 scm = SCIPcalcSmaComMul(scalarxd, scalaryd);
5141 a = (scm/scalarxd)*scalarxn;
5142 b = (scm/scalaryd)*scalaryn;
5143 rhs *= scm;
5144
5145 /* divide equality by the greatest common divisor of a and b */
5146 gcd = SCIPcalcGreComDiv(ABS(a), ABS(b));
5147 a /= gcd;
5148 b /= gcd;
5149 rhs /= gcd;
5150 assert(a != 0);
5151 assert(b != 0);
5152
5153 /* check, if right hand side is integral */
5154 if( !SCIPsetIsFeasIntegral(set, rhs) )
5155 {
5156 *infeasible = TRUE;
5157 return SCIP_OKAY;
5158 }
5159 c = (SCIP_Longint)(SCIPsetFeasFloor(set, rhs));
5160
5161 /* check that the scalar and constant in the aggregation are not too large to avoid numerical problems */
5162 if( REALABS((SCIP_Real)(c/a)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) /*lint !e653*/
5163 || REALABS((SCIP_Real)(b)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) /*lint !e653*/
5164 || REALABS((SCIP_Real)(a)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) ) /*lint !e653*/
5165 {
5166 return SCIP_OKAY;
5167 }
5168
5169 /* check, if we are in an easy case with either |a| = 1 or |b| = 1 */
5170 if( (a == 1 || a == -1) && SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER )
5171 {
5172 /* aggregate x = - b/a*y + c/a */
5173 /*lint --e{653}*/
5174 SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5175 branchcand, eventfilter, eventqueue, vary, (SCIP_Real)(-b/a), (SCIP_Real)(c/a), infeasible, aggregated) );
5176 assert(*aggregated);
5177 return SCIP_OKAY;
5178 }
5179 if( (b == 1 || b == -1) && SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER )
5180 {
5181 /* aggregate y = - a/b*x + c/b */
5182 /*lint --e{653}*/
5183 SCIP_CALL( SCIPvarAggregate(vary, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5184 branchcand, eventfilter, eventqueue, varx, (SCIP_Real)(-a/b), (SCIP_Real)(c/b), infeasible, aggregated) );
5185 assert(*aggregated);
5186 return SCIP_OKAY;
5187 }
5188
5189 /* Both variables are integers, their coefficients are not multiples of each other, and they don't have any
5190 * common divisor. Let (x',y') be a solution of the equality
5191 * a*x + b*y == c -> a*x == c - b*y
5192 * Then x = -b*z + x', y = a*z + y' with z integral gives all solutions to the equality.
5193 */
5194
5195 /* find initial solution (x',y'):
5196 * - find y' such that c - b*y' is a multiple of a
5197 * - start in equivalence class c%a
5198 * - step through classes, where each step increases class number by (-b)%a, until class 0 is visited
5199 * - if equivalence class 0 is visited, we are done: y' equals the number of steps taken
5200 * - 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
5201 * - calculate x' with x' = (c - b*y')/a (which must be integral)
5202 *
5203 * Algorithm works for a > 0 only.
5204 */
5205 if( a < 0 )
5206 {
5207 a = -a;
5208 b = -b;
5209 c = -c;
5210 }
5211 assert(a > 0);
5212
5213 /* search upwards from ysol = 0 */
5214 ysol = 0;
5215 currentclass = c % a;
5216 if( currentclass < 0 )
5217 currentclass += a;
5218 assert(0 <= currentclass && currentclass < a);
5219
5220 classstep = (-b) % a;
5221
5222 if( classstep < 0 )
5223 classstep += a;
5224 assert(0 <= classstep && classstep < a);
5225
5226 while( currentclass != 0 )
5227 {
5228 assert(0 <= currentclass && currentclass < a);
5229 currentclass += classstep;
5230 if( currentclass >= a )
5231 currentclass -= a;
5232 ysol++;
5233 }
5234 assert(ysol < a);
5235 assert(((c - b*ysol) % a) == 0);
5236
5237 xsol = (c - b*ysol)/a;
5238
5239 /* determine variable type for new artificial variable:
5240 *
5241 * if both variables are implicit integer the new variable can be implicit too, because the integer implication on
5242 * these both variables should be enforced by some other variables, otherwise the new variable needs to be of
5243 * integral type
5244 */
5247
5248 /* feasible solutions are (x,y) = (x',y') + z*(-b,a)
5249 * - create new integer variable z with infinite bounds
5250 * - aggregate variable x = -b*z + x'
5251 * - aggregate variable y = a*z + y'
5252 * - the bounds of z are calculated automatically during aggregation
5253 */
5254 (void) SCIPsnprintf(aggvarname, SCIP_MAXSTRLEN, "agg%d", stat->nvaridx);
5255 SCIP_CALL( SCIPvarCreateTransformed(&aggvar, blkmem, set, stat,
5256 aggvarname, -SCIPsetInfinity(set), SCIPsetInfinity(set), 0.0, vartype,
5258 NULL, NULL, NULL, NULL, NULL) );
5259
5260 SCIP_CALL( SCIPprobAddVar(transprob, blkmem, set, lp, branchcand, eventfilter, eventqueue, aggvar) );
5261
5262 SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5263 branchcand, eventfilter, eventqueue, aggvar, (SCIP_Real)(-b), (SCIP_Real)xsol, infeasible, aggregated) );
5264 assert(*aggregated || *infeasible);
5265
5266 if( !(*infeasible) )
5267 {
5268 SCIP_CALL( SCIPvarAggregate(vary, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5269 branchcand, eventfilter, eventqueue, aggvar, (SCIP_Real)a, (SCIP_Real)ysol, infeasible, aggregated) );
5270 assert(*aggregated || *infeasible);
5271 }
5272
5273 /* release z */
5274 SCIP_CALL( SCIPvarRelease(&aggvar, blkmem, set, eventqueue, lp) );
5275
5276 return SCIP_OKAY; /*lint !e438*/
5277}
5278
5279/** performs second step of SCIPaggregateVars():
5280 * the variable to be aggregated is chosen among active problem variables x' and y', preferring a less strict variable
5281 * type as aggregation variable (i.e. continuous variables are preferred over implicit integers, implicit integers
5282 * or integers over binaries). If none of the variables is continuous, it is tried to find an integer
5283 * aggregation (i.e. integral coefficients a'' and b'', such that a''*x' + b''*y' == c''). This can lead to
5284 * the detection of infeasibility (e.g. if c'' is fractional), or to a rejection of the aggregation (denoted by
5285 * aggregated == FALSE), if the resulting integer coefficients are too large and thus numerically instable.
5286 *
5287 * @todo check for fixings, infeasibility, bound changes, or domain holes:
5288 * a) if there is no easy aggregation and we have one binary variable and another integer/implicit/binary variable
5289 * b) for implicit integer variables with fractional aggregation scalar (we cannot (for technical reasons) and do
5290 * not want to aggregate implicit integer variables, since we loose the corresponding divisibility property)
5291 */
5293 SCIP_SET* set, /**< global SCIP settings */
5294 BMS_BLKMEM* blkmem, /**< block memory */
5295 SCIP_STAT* stat, /**< problem statistics */
5296 SCIP_PROB* transprob, /**< tranformed problem data */
5297 SCIP_PROB* origprob, /**< original problem data */
5298 SCIP_PRIMAL* primal, /**< primal data */
5299 SCIP_TREE* tree, /**< branch and bound tree */
5300 SCIP_REOPT* reopt, /**< reoptimization data structure */
5301 SCIP_LP* lp, /**< current LP data */
5302 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
5303 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
5304 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
5305 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5306 SCIP_VAR* varx, /**< variable x in equality a*x + b*y == c */
5307 SCIP_VAR* vary, /**< variable y in equality a*x + b*y == c */
5308 SCIP_Real scalarx, /**< multiplier a in equality a*x + b*y == c */
5309 SCIP_Real scalary, /**< multiplier b in equality a*x + b*y == c */
5310 SCIP_Real rhs, /**< right hand side c in equality a*x + b*y == c */
5311 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
5312 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
5313 )
5314{
5315 SCIP_Bool easyaggr;
5316
5317 assert(set != NULL);
5318 assert(blkmem != NULL);
5319 assert(stat != NULL);
5320 assert(transprob != NULL);
5321 assert(origprob != NULL);
5322 assert(tree != NULL);
5323 assert(lp != NULL);
5324 assert(cliquetable != NULL);
5325 assert(branchcand != NULL);
5326 assert(eventqueue != NULL);
5327 assert(varx != NULL);
5328 assert(vary != NULL);
5329 assert(varx != vary);
5330 assert(infeasible != NULL);
5331 assert(aggregated != NULL);
5333 assert(SCIPvarGetStatus(varx) == SCIP_VARSTATUS_LOOSE);
5334 assert(SCIPvarGetStatus(vary) == SCIP_VARSTATUS_LOOSE);
5335 assert(!SCIPsetIsZero(set, scalarx));
5336 assert(!SCIPsetIsZero(set, scalary));
5337
5338 *infeasible = FALSE;
5339 *aggregated = FALSE;
5340
5341 if( SCIPsetIsZero(set, scalarx / scalary) || SCIPsetIsZero(set, scalary / scalarx) )
5342 return SCIP_OKAY;
5343
5344 /* prefer aggregating the variable of more general type (preferred aggregation variable is varx) */
5345 if( SCIPvarGetType(vary) > SCIPvarGetType(varx) ||
5346 (SCIPvarGetType(vary) == SCIPvarGetType(varx) && !SCIPvarIsBinary(vary) && SCIPvarIsBinary(varx)) )
5347 {
5348 SCIP_VAR* var;
5349 SCIP_Real scalar;
5350
5351 /* switch the variables, such that varx is the variable of more general type (cont > implint > int > bin) */
5352 var = vary;
5353 vary = varx;
5354 varx = var;
5355 scalar = scalary;
5356 scalary = scalarx;
5357 scalarx = scalar;
5358 }
5359
5360 /* don't aggregate if the aggregation would lead to a binary variable aggregated to a non-binary variable */
5361 if( SCIPvarIsBinary(varx) && !SCIPvarIsBinary(vary) )
5362 return SCIP_OKAY;
5363
5364 assert(SCIPvarGetType(varx) >= SCIPvarGetType(vary));
5365
5366 /* figure out, which variable should be aggregated */
5367 easyaggr = FALSE;
5368
5369 /* check if it is an easy aggregation */
5371 {
5372 easyaggr = TRUE;
5373 }
5374 else if( SCIPsetIsFeasIntegral(set, scalary/scalarx) )
5375 {
5376 easyaggr = TRUE;
5377 }
5378 else if( SCIPsetIsFeasIntegral(set, scalarx/scalary) && SCIPvarGetType(vary) == SCIPvarGetType(varx) )
5379 {
5380 /* we have an easy aggregation if we flip the variables x and y */
5381 SCIP_VAR* var;
5382 SCIP_Real scalar;
5383
5384 /* switch the variables, such that varx is the aggregated variable */
5385 var = vary;
5386 vary = varx;
5387 varx = var;
5388 scalar = scalary;
5389 scalary = scalarx;
5390 scalarx = scalar;
5391 easyaggr = TRUE;
5392 }
5393 else if( SCIPvarGetType(varx) == SCIP_VARTYPE_CONTINUOUS )
5394 {
5395 /* the aggregation is still easy if both variables are continuous */
5396 assert(SCIPvarGetType(vary) == SCIP_VARTYPE_CONTINUOUS); /* otherwise we are in the first case */
5397 easyaggr = TRUE;
5398 }
5399
5400 /* did we find an "easy" aggregation? */
5401 if( easyaggr )
5402 {
5403 SCIP_Real scalar;
5404 SCIP_Real constant;
5405
5406 assert(SCIPvarGetType(varx) >= SCIPvarGetType(vary));
5407
5408 /* calculate aggregation scalar and constant: a*x + b*y == c => x == -b/a * y + c/a */
5409 scalar = -scalary/scalarx;
5410 constant = rhs/scalarx;
5411
5412 if( REALABS(constant) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) ) /*lint !e653*/
5413 return SCIP_OKAY;
5414
5415 /* check aggregation for integer feasibility */
5418 && SCIPsetIsFeasIntegral(set, scalar) && !SCIPsetIsFeasIntegral(set, constant) )
5419 {
5420 *infeasible = TRUE;
5421 return SCIP_OKAY;
5422 }
5423
5424 /* if the aggregation scalar is fractional, we cannot (for technical reasons) and do not want to aggregate implicit integer variables,
5425 * since then we would loose the corresponding divisibility property
5426 */
5427 assert(SCIPvarGetType(varx) != SCIP_VARTYPE_IMPLINT || SCIPsetIsFeasIntegral(set, scalar));
5428
5429 /* aggregate the variable */
5430 SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5431 branchcand, eventfilter, eventqueue, vary, scalar, constant, infeasible, aggregated) );
5432 assert(*aggregated || *infeasible || SCIPvarDoNotAggr(varx));
5433 }
5436 {
5437 /* the variables are both integral: we have to try to find an integer aggregation */
5438 SCIP_CALL( tryAggregateIntVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5439 branchcand, eventfilter, eventqueue, varx, vary, scalarx, scalary, rhs, infeasible, aggregated) );
5440 }
5441
5442 return SCIP_OKAY;
5443}
5444
5445/** converts variable into multi-aggregated variable */
5447 SCIP_VAR* var, /**< problem variable */
5448 BMS_BLKMEM* blkmem, /**< block memory */
5449 SCIP_SET* set, /**< global SCIP settings */
5450 SCIP_STAT* stat, /**< problem statistics */
5451 SCIP_PROB* transprob, /**< tranformed problem data */
5452 SCIP_PROB* origprob, /**< original problem data */
5453 SCIP_PRIMAL* primal, /**< primal data */
5454 SCIP_TREE* tree, /**< branch and bound tree */
5455 SCIP_REOPT* reopt, /**< reoptimization data structure */
5456 SCIP_LP* lp, /**< current LP data */
5457 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
5458 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
5459 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
5460 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
5461 int naggvars, /**< number n of variables in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5462 SCIP_VAR** aggvars, /**< variables y_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5463 SCIP_Real* scalars, /**< multipliers a_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5464 SCIP_Real constant, /**< constant shift c in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5465 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
5466 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
5467 )
5468{
5469 SCIP_VAR** tmpvars;
5470 SCIP_Real* tmpscalars;
5471 SCIP_Real obj;
5472 SCIP_Real branchfactor;
5473 int branchpriority;
5474 SCIP_BRANCHDIR branchdirection;
5475 int nlocksdown[NLOCKTYPES];
5476 int nlocksup[NLOCKTYPES];
5477 int v;
5478 SCIP_Real tmpconstant;
5479 SCIP_Real tmpscalar;
5480 int ntmpvars;
5481 int tmpvarssize;
5482 int tmprequiredsize;
5483 int i;
5484
5485 assert(var != NULL);
5486 assert(var->scip == set->scip);
5487 assert(var->glbdom.lb == var->locdom.lb); /*lint !e777*/
5488 assert(var->glbdom.ub == var->locdom.ub); /*lint !e777*/
5489 assert(naggvars == 0 || aggvars != NULL);
5490 assert(naggvars == 0 || scalars != NULL);
5491 assert(infeasible != NULL);
5492 assert(aggregated != NULL);
5493
5494 SCIPsetDebugMsg(set, "trying multi-aggregating variable <%s> == ...%d vars... %+g\n", var->name, naggvars, constant);
5495
5496 *infeasible = FALSE;
5497 *aggregated = FALSE;
5498
5499 switch( SCIPvarGetStatus(var) )
5500 {
5502 if( var->data.original.transvar == NULL )
5503 {
5504 SCIPerrorMessage("cannot multi-aggregate an untransformed original variable\n");
5505 return SCIP_INVALIDDATA;
5506 }
5507 SCIP_CALL( SCIPvarMultiaggregate(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree,
5508 reopt, lp, cliquetable, branchcand, eventfilter, eventqueue, naggvars, aggvars, scalars, constant, infeasible, aggregated) );
5509 break;
5510
5512 assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
5513
5514 /* check if we would create a self-reference */
5515 ntmpvars = naggvars;
5516 tmpvarssize = naggvars;
5517 tmpconstant = constant;
5518 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &tmpvars, aggvars, ntmpvars) );
5519 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &tmpscalars, scalars, ntmpvars) );
5520
5521 /* get all active variables for multi-aggregation */
5522 SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) );
5523 if( tmprequiredsize > tmpvarssize )
5524 {
5525 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpvars, tmpvarssize, tmprequiredsize) );
5526 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpscalars, tmpvarssize, tmprequiredsize) );
5527 tmpvarssize = tmprequiredsize;
5528 SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) );
5529 assert( tmprequiredsize <= tmpvarssize );
5530 }
5531
5532 tmpscalar = 0.0;
5533
5534 /* iterate over all active variables of the multi-aggregation and filter all variables which are equal to the
5535 * possible multi-aggregated variable
5536 */
5537 for( v = ntmpvars - 1; v >= 0; --v )
5538 {
5539 assert(tmpvars[v] != NULL);
5540 assert(SCIPvarGetStatus(tmpvars[v]) == SCIP_VARSTATUS_LOOSE);
5541
5542 if( tmpvars[v]->index == var->index )
5543 {
5544 tmpscalar += tmpscalars[v];
5545 tmpvars[v] = tmpvars[ntmpvars - 1];
5546 tmpscalars[v] = tmpscalars[ntmpvars - 1];
5547 --ntmpvars;
5548 }
5549 }
5550
5551 /* this means that x = x + a_1*y_1 + ... + a_n*y_n + c */
5552 if( SCIPsetIsEQ(set, tmpscalar, 1.0) )
5553 {
5554 if( ntmpvars == 0 )
5555 {
5556 if( SCIPsetIsZero(set, tmpconstant) ) /* x = x */
5557 {
5558 SCIPsetDebugMsg(set, "Possible multi-aggregation was completely resolved and detected to be redundant.\n");
5559 goto TERMINATE;
5560 }
5561 else /* 0 = c and c != 0 */
5562 {
5563 SCIPsetDebugMsg(set, "Multi-aggregation was completely resolved and led to infeasibility.\n");
5564 *infeasible = TRUE;
5565 goto TERMINATE;
5566 }
5567 }
5568 else if( ntmpvars == 1 ) /* 0 = a*y + c => y = -c/a */
5569 {
5570 assert(tmpscalars[0] != 0.0);
5571 assert(tmpvars[0] != NULL);
5572
5573 SCIPsetDebugMsg(set, "Possible multi-aggregation led to fixing of variable <%s> to %g.\n", SCIPvarGetName(tmpvars[0]), -constant/tmpscalars[0]);
5574 SCIP_CALL( SCIPvarFix(tmpvars[0], blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
5575 branchcand, eventfilter, eventqueue, cliquetable, -constant/tmpscalars[0], infeasible, aggregated) );
5576 goto TERMINATE;
5577 }
5578 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 */
5579 {
5580 /* both variables are different active problem variables, and both scalars are non-zero: try to aggregate them */
5581 SCIPsetDebugMsg(set, "Possible multi-aggregation led to aggregation of variables <%s> and <%s> with scalars %g and %g and constant %g.\n",
5582 SCIPvarGetName(tmpvars[0]), SCIPvarGetName(tmpvars[1]), tmpscalars[0], tmpscalars[1], -tmpconstant);
5583
5584 SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp,
5585 cliquetable, branchcand, eventfilter, eventqueue, tmpvars[0], tmpvars[1], tmpscalars[0],
5586 tmpscalars[1], -tmpconstant, infeasible, aggregated) );
5587
5588 goto TERMINATE;
5589 }
5590 else
5591 /* @todo: it is possible to multi-aggregate another variable, does it make sense?,
5592 * rest looks like 0 = a_1*y_1 + ... + a_n*y_n + c and has at least three variables
5593 */
5594 goto TERMINATE;
5595 }
5596 /* this means that x = b*x + a_1*y_1 + ... + a_n*y_n + c */
5597 else if( !SCIPsetIsZero(set, tmpscalar) )
5598 {
5599 tmpscalar = 1 - tmpscalar;
5600 tmpconstant /= tmpscalar;
5601 for( v = ntmpvars - 1; v >= 0; --v )
5602 tmpscalars[v] /= tmpscalar;
5603 }
5604
5605 /* check, if we are in one of the simple cases */
5606 if( ntmpvars == 0 )
5607 {
5608 SCIPsetDebugMsg(set, "Possible multi-aggregation led to fixing of variable <%s> to %g.\n", SCIPvarGetName(var), tmpconstant);
5609 SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
5610 eventfilter, eventqueue, cliquetable, tmpconstant, infeasible, aggregated) );
5611 goto TERMINATE;
5612 }
5613
5614 /* if only one aggregation variable is left, we perform a normal aggregation instead of a multi-aggregation */
5615 if( ntmpvars == 1 )
5616 {
5617 SCIPsetDebugMsg(set, "Possible multi-aggregation led to aggregation of variables <%s> and <%s> with scalars %g and %g and constant %g.\n",
5618 SCIPvarGetName(var), SCIPvarGetName(tmpvars[0]), 1.0, -tmpscalars[0], tmpconstant);
5619
5620 SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp,
5621 cliquetable, branchcand, eventfilter, eventqueue, var, tmpvars[0], 1.0, -tmpscalars[0], tmpconstant,
5622 infeasible, aggregated) );
5623
5624 goto TERMINATE;
5625 }
5626
5627 /**@todo currently we don't perform the multi aggregation if the multi aggregation variable has a non
5628 * empty hole list; this should be changed in the future */
5629 if( SCIPvarGetHolelistGlobal(var) != NULL )
5630 goto TERMINATE;
5631
5632 /* if the variable is not allowed to be multi-aggregated */
5633 if( SCIPvarDoNotMultaggr(var) )
5634 {
5635 SCIPsetDebugMsg(set, "variable is not allowed to be multi-aggregated.\n");
5636 goto TERMINATE;
5637 }
5638
5639 /* if the variable to be multi-aggregated has implications or variable bounds (i.e. is the implied variable or
5640 * variable bound variable of another variable), we have to remove it from the other variables implications or
5641 * variable bounds
5642 */
5643 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) );
5644 assert(var->vlbs == NULL);
5645 assert(var->vubs == NULL);
5646 assert(var->implics == NULL);
5647
5648 /* set the aggregated variable's objective value to 0.0 */
5649 obj = var->obj;
5650 SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
5651
5652 /* since we change the variable type form loose to multi aggregated, we have to adjust the number of loose
5653 * variables in the LP data structure; the loose objective value (looseobjval) in the LP data structure, however,
5654 * gets adjusted automatically, due to the event SCIP_EVENTTYPE_OBJCHANGED which dropped in the moment where the
5655 * objective of this variable is set to zero
5656 */
5658
5659 /* unlock all rounding locks */
5660 for( i = 0; i < NLOCKTYPES; i++ )
5661 {
5662 nlocksdown[i] = var->nlocksdown[i];
5663 nlocksup[i] = var->nlocksup[i];
5664
5665 var->nlocksdown[i] = 0;
5666 var->nlocksup[i] = 0;
5667 }
5668
5669 /* convert variable into multi-aggregated variable */
5670 var->varstatus = SCIP_VARSTATUS_MULTAGGR; /*lint !e641*/
5671 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->data.multaggr.vars, tmpvars, ntmpvars) );
5672 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->data.multaggr.scalars, tmpscalars, ntmpvars) );
5673 var->data.multaggr.constant = tmpconstant;
5674 var->data.multaggr.nvars = ntmpvars;
5675 var->data.multaggr.varssize = ntmpvars;
5676
5677 /* mark variable to be non-deletable */
5679
5680 /* relock the variable, thus increasing the locks of the aggregation variables */
5681 for( i = 0; i < NLOCKTYPES; i++ )
5682 {
5683 SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) );
5684 }
5685
5686 /* update flags and branching factors and priorities of aggregation variables;
5687 * update preferred branching direction of all aggregation variables that don't have a preferred direction yet
5688 */
5689 branchfactor = var->branchfactor;
5690 branchpriority = var->branchpriority;
5691 branchdirection = (SCIP_BRANCHDIR)var->branchdirection;
5692
5693 for( v = 0; v < ntmpvars; ++v )
5694 {
5695 assert(tmpvars[v] != NULL);
5696 tmpvars[v]->removable &= var->removable;
5697 branchfactor = MAX(tmpvars[v]->branchfactor, branchfactor);
5698 branchpriority = MAX(tmpvars[v]->branchpriority, branchpriority);
5699
5700 /* mark variable to be non-deletable */
5701 SCIPvarMarkNotDeletable(tmpvars[v]);
5702 }
5703 for( v = 0; v < ntmpvars; ++v )
5704 {
5705 SCIP_CALL( SCIPvarChgBranchFactor(tmpvars[v], set, branchfactor) );
5706 SCIP_CALL( SCIPvarChgBranchPriority(tmpvars[v], branchpriority) );
5707 if( (SCIP_BRANCHDIR)tmpvars[v]->branchdirection == SCIP_BRANCHDIR_AUTO )
5708 {
5709 if( tmpscalars[v] >= 0.0 )
5710 {
5711 SCIP_CALL( SCIPvarChgBranchDirection(tmpvars[v], branchdirection) );
5712 }
5713 else
5714 {
5715 SCIP_CALL( SCIPvarChgBranchDirection(tmpvars[v], SCIPbranchdirOpposite(branchdirection)) );
5716 }
5717 }
5718 }
5719 SCIP_CALL( SCIPvarChgBranchFactor(var, set, branchfactor) );
5720 SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) );
5721
5722 if( var->probindex != -1 )
5723 {
5724 /* inform problem about the variable's status change */
5725 SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) );
5726 }
5727
5728 /* issue VARFIXED event */
5729 SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 2) );
5730
5731 /* reset the objective value of the aggregated variable, thus adjusting the objective value of the aggregation
5732 * variables and the problem's objective offset
5733 */
5734 SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) );
5735
5736 *aggregated = TRUE;
5737
5738 TERMINATE:
5739 BMSfreeBlockMemoryArray(blkmem, &tmpscalars, tmpvarssize);
5740 BMSfreeBlockMemoryArray(blkmem, &tmpvars, tmpvarssize);
5741
5742 break;
5743
5745 SCIPerrorMessage("cannot multi-aggregate a column variable\n");
5746 return SCIP_INVALIDDATA;
5747
5749 SCIPerrorMessage("cannot multi-aggregate a fixed variable\n");
5750 return SCIP_INVALIDDATA;
5751
5753 SCIPerrorMessage("cannot multi-aggregate an aggregated variable\n");
5754 return SCIP_INVALIDDATA;
5755
5757 SCIPerrorMessage("cannot multi-aggregate a multiple aggregated variable again\n");
5758 return SCIP_INVALIDDATA;
5759
5761 /* aggregate negation variable x in x' = offset - x, instead of aggregating x' directly:
5762 * x' = a_1*y_1 + ... + a_n*y_n + c -> x = offset - x' = offset - a_1*y_1 - ... - a_n*y_n - c
5763 */
5764 assert(SCIPsetIsZero(set, var->obj));
5765 assert(var->negatedvar != NULL);
5767 assert(var->negatedvar->negatedvar == var);
5768
5769 /* switch the signs of the aggregation scalars */
5770 for( v = 0; v < naggvars; ++v )
5771 scalars[v] *= -1.0;
5772
5773 /* perform the multi aggregation on the negation variable */
5774 SCIP_CALL( SCIPvarMultiaggregate(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
5775 cliquetable, branchcand, eventfilter, eventqueue, naggvars, aggvars, scalars,
5776 var->data.negate.constant - constant, infeasible, aggregated) );
5777
5778 /* switch the signs of the aggregation scalars again, to reset them to their original values */
5779 for( v = 0; v < naggvars; ++v )
5780 scalars[v] *= -1.0;
5781 break;
5782
5783 default:
5784 SCIPerrorMessage("unknown variable status\n");
5785 return SCIP_INVALIDDATA;
5786 }
5787
5788 /* check multi-aggregation on debugging solution */
5789 if( *infeasible || *aggregated )
5790 SCIP_CALL( SCIPdebugCheckAggregation(set, var, aggvars, scalars, constant, naggvars) ); /*lint !e506 !e774*/
5791
5792 return SCIP_OKAY;
5793}
5794
5795/** transformed variables are resolved to their active, fixed, or multi-aggregated problem variable of a variable,
5796 * or for original variables the same variable is returned
5797 */
5798static
5800 SCIP_VAR* var /**< problem variable */
5801 )
5802{
5803 SCIP_VAR* retvar;
5804
5805 assert(var != NULL);
5806
5807 retvar = var;
5808
5809 SCIPdebugMessage("get active variable of <%s>\n", var->name);
5810
5811 while( TRUE ) /*lint !e716 */
5812 {
5813 assert(retvar != NULL);
5814
5815 switch( SCIPvarGetStatus(retvar) )
5816 {
5821 return retvar;
5822
5824 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
5825 if ( retvar->data.multaggr.nvars == 1 )
5826 retvar = retvar->data.multaggr.vars[0];
5827 else
5828 return retvar;
5829 break;
5830
5832 retvar = retvar->data.aggregate.var;
5833 break;
5834
5836 retvar = retvar->negatedvar;
5837 break;
5838
5839 default:
5840 SCIPerrorMessage("unknown variable status\n");
5841 SCIPABORT();
5842 return NULL; /*lint !e527*/
5843 }
5844 }
5845}
5846
5847/** returns whether variable is not allowed to be aggregated */
5849 SCIP_VAR* var /**< problem variable */
5850 )
5851{
5852 SCIP_VAR* retvar;
5853
5854 assert(var != NULL);
5855
5856 retvar = varGetActiveVar(var);
5857 assert(retvar != NULL);
5858
5859 switch( SCIPvarGetStatus(retvar) )
5860 {
5865 return retvar->donotaggr;
5866
5868 return FALSE;
5869
5872 default:
5873 /* aggregated and negated variables should be resolved by varGetActiveVar() */
5874 SCIPerrorMessage("wrong variable status\n");
5875 SCIPABORT();
5876 return FALSE; /*lint !e527 */
5877 }
5878}
5879
5880/** returns whether variable is not allowed to be multi-aggregated */
5882 SCIP_VAR* var /**< problem variable */
5883 )
5884{
5885 SCIP_VAR* retvar;
5886
5887 assert(var != NULL);
5888
5889 retvar = varGetActiveVar(var);
5890 assert(retvar != NULL);
5891
5892 switch( SCIPvarGetStatus(retvar) )
5893 {
5898 return retvar->donotmultaggr;
5899
5901 return FALSE;
5902
5905 default:
5906 /* aggregated and negated variables should be resolved by varGetActiveVar() */
5907 SCIPerrorMessage("wrong variable status\n");
5908 SCIPABORT();
5909 return FALSE; /*lint !e527 */
5910 }
5911}
5912
5913/** gets negated variable x' = offset - x of problem variable x; the negated variable is created if not yet existing;
5914 * the negation offset of binary variables is always 1, the offset of other variables is fixed to lb + ub when the
5915 * negated variable is created
5916 */
5918 SCIP_VAR* var, /**< problem variable to negate */
5919 BMS_BLKMEM* blkmem, /**< block memory of transformed problem */
5920 SCIP_SET* set, /**< global SCIP settings */
5921 SCIP_STAT* stat, /**< problem statistics */
5922 SCIP_VAR** negvar /**< pointer to store the negated variable */
5923 )
5924{
5925 assert(var != NULL);
5926 assert(var->scip == set->scip);
5927 assert(negvar != NULL);
5928
5929 /* check, if we already created the negated variable */
5930 if( var->negatedvar == NULL )
5931 {
5932 char negvarname[SCIP_MAXSTRLEN];
5933
5935
5936 SCIPsetDebugMsg(set, "creating negated variable of <%s>\n", var->name);
5937
5938 /* negation is only possible for bounded variables */
5940 {
5941 SCIPerrorMessage("cannot negate unbounded variable\n");
5942 return SCIP_INVALIDDATA;
5943 }
5944
5945 (void) SCIPsnprintf(negvarname, SCIP_MAXSTRLEN, "%s_neg", var->name);
5946
5947 /* create negated variable */
5948 SCIP_CALL( varCreate(negvar, blkmem, set, stat, negvarname, var->glbdom.lb, var->glbdom.ub, 0.0,
5949 SCIPvarGetType(var), var->initial, var->removable, NULL, NULL, NULL, NULL, NULL) );
5950 (*negvar)->varstatus = SCIP_VARSTATUS_NEGATED; /*lint !e641*/
5951 if( SCIPvarIsBinary(var) )
5952 (*negvar)->data.negate.constant = 1.0;
5953 else
5954 (*negvar)->data.negate.constant = var->glbdom.lb + var->glbdom.ub;
5955
5956 /* create event filter for transformed variable */
5957 if( SCIPvarIsTransformed(var) )
5958 {
5959 SCIP_CALL( SCIPeventfilterCreate(&(*negvar)->eventfilter, blkmem) );
5960 }
5961
5962 /* set the bounds corresponding to the negation variable */
5963 (*negvar)->glbdom.lb = (*negvar)->data.negate.constant - var->glbdom.ub;
5964 (*negvar)->glbdom.ub = (*negvar)->data.negate.constant - var->glbdom.lb;
5965 (*negvar)->locdom.lb = (*negvar)->data.negate.constant - var->locdom.ub;
5966 (*negvar)->locdom.ub = (*negvar)->data.negate.constant - var->locdom.lb;
5967 /**@todo create holes in the negated variable corresponding to the holes of the negation variable */
5968
5969 /* link the variables together */
5970 var->negatedvar = *negvar;
5971 (*negvar)->negatedvar = var;
5972
5973 /* mark both variables to be non-deletable */
5975 SCIPvarMarkNotDeletable(*negvar);
5976
5977 /* copy the branch factor and priority, and use the negative preferred branching direction */
5978 (*negvar)->branchfactor = var->branchfactor;
5979 (*negvar)->branchpriority = var->branchpriority;
5980 (*negvar)->branchdirection = SCIPbranchdirOpposite((SCIP_BRANCHDIR)var->branchdirection); /*lint !e641*/
5981
5982 /* copy donot(mult)aggr status */
5983 (*negvar)->donotaggr = var->donotaggr;
5984 (*negvar)->donotmultaggr = var->donotmultaggr;
5985
5986 /* copy lazy bounds (they have to be flipped) */
5987 (*negvar)->lazylb = (*negvar)->data.negate.constant - var->lazyub;
5988 (*negvar)->lazyub = (*negvar)->data.negate.constant - var->lazylb;
5989
5990 /* make negated variable a parent of the negation variable (negated variable is captured as a parent) */
5991 SCIP_CALL( varAddParent(var, blkmem, set, *negvar) );
5992 assert((*negvar)->nuses == 1);
5993 }
5994 assert(var->negatedvar != NULL);
5995
5996 /* return the negated variable */
5997 *negvar = var->negatedvar;
5998
5999 /* exactly one variable of the negation pair has to be marked as negated variable */
6001
6002 return SCIP_OKAY;
6003}
6004
6005/** informs variable that its position in problem's vars array changed */
6006static
6008 SCIP_VAR* var, /**< problem variable */
6009 int probindex /**< new problem index of variable (-1 for removal) */
6010 )
6011{
6012 assert(var != NULL);
6013 assert(probindex >= 0 || var->vlbs == NULL);
6014 assert(probindex >= 0 || var->vubs == NULL);
6015 assert(probindex >= 0 || var->implics == NULL);
6016
6017 var->probindex = probindex;
6019 {
6020 assert(var->data.col != NULL);
6021 var->data.col->var_probindex = probindex;
6022 }
6023}
6024
6025/** informs variable that its position in problem's vars array changed */
6027 SCIP_VAR* var, /**< problem variable */
6028 int probindex /**< new problem index of variable */
6029 )
6030{
6031 assert(var != NULL);
6032 assert(probindex >= 0);
6033
6034 varSetProbindex(var, probindex);
6035}
6036
6037/** gives the variable a new name
6038 *
6039 * @note the old pointer is overwritten, which might result in a memory leakage
6040 */
6042 SCIP_VAR* var, /**< problem variable */
6043 const char* name /**< new name of variable */
6044 )
6045{
6046 assert(var != NULL);
6047 assert(name != NULL);
6048
6049 var->name = (char*)name;
6050}
6051
6052/** informs variable that it will be removed from the problem; adjusts probindex and removes variable from the
6053 * implication graph;
6054 * If 'final' is TRUE, the thorough implication graph removal is not performed. Instead, only the
6055 * variable bounds and implication data structures of the variable are freed. Since in the final removal
6056 * of all variables from the transformed problem, this deletes the implication graph completely and is faster
6057 * than removing the variables one by one, each time updating all lists of the other variables.
6058 */
6060 SCIP_VAR* var, /**< problem variable */
6061 BMS_BLKMEM* blkmem, /**< block memory buffer */
6062 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
6063 SCIP_SET* set, /**< global SCIP settings */
6064 SCIP_Bool final /**< is this the final removal of all problem variables? */
6065 )
6066{
6067 assert(SCIPvarGetProbindex(var) >= 0);
6068 assert(var->scip == set->scip);
6069
6070 /* if the variable is active in the transformed problem, remove it from the implication graph */
6071 if( SCIPvarIsTransformed(var)
6073 {
6074 if( final )
6075 {
6076 /* just destroy the data structures */
6077 SCIPvboundsFree(&var->vlbs, blkmem);
6078 SCIPvboundsFree(&var->vubs, blkmem);
6079 SCIPimplicsFree(&var->implics, blkmem);
6080 }
6081 else
6082 {
6083 /* unlink the variable from all other variables' lists and free the data structures */
6084 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) );
6085 }
6086 }
6087
6088 /* mark the variable to be no longer a member of the problem */
6089 varSetProbindex(var, -1);
6090
6091 return SCIP_OKAY;
6092}
6093
6094/** marks the variable to be deleted from the problem */
6096 SCIP_VAR* var /**< problem variable */
6097 )
6098{
6099 assert(var != NULL);
6100 assert(var->probindex != -1);
6101
6102 var->deleted = TRUE;
6103}
6104
6105/** marks the variable to not to be aggregated */
6107 SCIP_VAR* var /**< problem variable */
6108 )
6109{
6110 SCIP_VAR* retvar;
6111
6112 assert(var != NULL);
6113
6114 retvar = varGetActiveVar(var);
6115 assert(retvar != NULL);
6116
6117 switch( SCIPvarGetStatus(retvar) )
6118 {
6123 retvar->donotaggr = TRUE;
6124 break;
6125
6127 SCIPerrorMessage("cannot mark a multi-aggregated variable to not be aggregated.\n");
6128 return SCIP_INVALIDDATA;
6129
6132 default:
6133 /* aggregated and negated variables should be resolved by varGetActiveVar() */
6134 SCIPerrorMessage("wrong variable status\n");
6135 return SCIP_INVALIDDATA;
6136 }
6137
6138 return SCIP_OKAY;
6139}
6140
6141/** marks the variable to not to be multi-aggregated */
6143 SCIP_VAR* var /**< problem variable */
6144 )
6145{
6146 SCIP_VAR* retvar;
6147
6148 assert(var != NULL);
6149
6150 retvar = varGetActiveVar(var);
6151 assert(retvar != NULL);
6152
6153 switch( SCIPvarGetStatus(retvar) )
6154 {
6159 retvar->donotmultaggr = TRUE;
6160 break;
6161
6163 SCIPerrorMessage("cannot mark a multi-aggregated variable to not be multi-aggregated.\n");
6164 return SCIP_INVALIDDATA;
6165
6168 default:
6169 /* aggregated and negated variables should be resolved by varGetActiveVar() */
6170 SCIPerrorMessage("wrong variable status\n");
6171 return SCIP_INVALIDDATA;
6172 }
6173
6174 return SCIP_OKAY;
6175}
6176
6177/** changes type of variable; cannot be called, if var belongs to a problem */
6179 SCIP_VAR* var, /**< problem variable to change */
6180 BMS_BLKMEM* blkmem, /**< block memory */
6181 SCIP_SET* set, /**< global SCIP settings */
6182 SCIP_PRIMAL* primal, /**< primal data */
6183 SCIP_LP* lp, /**< current LP data */
6184 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6185 SCIP_VARTYPE vartype /**< new type of variable */
6186 )
6187{
6188 SCIP_EVENT* event;
6189 SCIP_VARTYPE oldtype;
6190
6191 assert(var != NULL);
6192
6193 SCIPdebugMessage("change type of <%s> from %d to %d\n", var->name, SCIPvarGetType(var), vartype);
6194
6195 if( var->probindex >= 0 )
6196 {
6197 SCIPerrorMessage("cannot change type of variable already in the problem\n");
6198 return SCIP_INVALIDDATA;
6199 }
6200
6201 oldtype = (SCIP_VARTYPE)var->vartype;
6202 var->vartype = vartype; /*lint !e641*/
6203
6205 {
6206 SCIP_CALL( SCIPeventCreateTypeChanged(&event, blkmem, var, oldtype, vartype) );
6207 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) );
6208 }
6209
6210 if( var->negatedvar != NULL )
6211 {
6212 assert(oldtype == (SCIP_VARTYPE)var->negatedvar->vartype
6213 || SCIPvarIsBinary(var) == SCIPvarIsBinary(var->negatedvar));
6214
6215 var->negatedvar->vartype = vartype; /*lint !e641*/
6216
6218 {
6219 SCIP_CALL( SCIPeventCreateTypeChanged(&event, blkmem, var->negatedvar, oldtype, vartype) );
6220 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) );
6221 }
6222 }
6223
6224 return SCIP_OKAY;
6225}
6226
6227/** appends OBJCHANGED event to the event queue */
6228static
6230 SCIP_VAR* var, /**< problem variable to change */
6231 BMS_BLKMEM* blkmem, /**< block memory */
6232 SCIP_SET* set, /**< global SCIP settings */
6233 SCIP_PRIMAL* primal, /**< primal data */
6234 SCIP_LP* lp, /**< current LP data */
6235 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6236 SCIP_Real oldobj, /**< old objective value for variable */
6237 SCIP_Real newobj /**< new objective value for variable */
6238 )
6239{
6240 SCIP_EVENT* event;
6241
6242 assert(var != NULL);
6243 assert(var->scip == set->scip);
6244 assert(var->eventfilter != NULL);
6246 assert(SCIPvarIsTransformed(var));
6247
6248 /* In the case where the objcetive value of a variable is very close to epsilon, and it is aggregated
6249 * into a variable with a big objective value, round-off errors might make the assert oldobj != newobj fail.
6250 * Hence, we relax it by letting it pass if the variables are percieved the same and we use very large values
6251 * that make comparison with values close to epsilon inaccurate.
6252 */
6253 assert(!SCIPsetIsEQ(set, oldobj, newobj) ||
6254 (SCIPsetIsEQ(set, oldobj, newobj) && REALABS(newobj) > 1e+15 * SCIPsetEpsilon(set))
6255 );
6256
6257 SCIP_CALL( SCIPeventCreateObjChanged(&event, blkmem, var, oldobj, newobj) );
6258 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) );
6259
6260 return SCIP_OKAY;
6261}
6262
6263/** changes objective value of variable */
6265 SCIP_VAR* var, /**< variable to change */
6266 BMS_BLKMEM* blkmem, /**< block memory */
6267 SCIP_SET* set, /**< global SCIP settings */
6268 SCIP_PROB* prob, /**< problem data */
6269 SCIP_PRIMAL* primal, /**< primal data */
6270 SCIP_LP* lp, /**< current LP data */
6271 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6272 SCIP_Real newobj /**< new objective value for variable */
6273 )
6274{
6275 SCIP_Real oldobj;
6276
6277 assert(var != NULL);
6278 assert(set != NULL);
6279 assert(var->scip == set->scip);
6280
6281 SCIPsetDebugMsg(set, "changing objective value of <%s> from %g to %g\n", var->name, var->obj, newobj);
6282
6283 if( !SCIPsetIsEQ(set, var->obj, newobj) )
6284 {
6285 switch( SCIPvarGetStatus(var) )
6286 {
6288 if( var->data.original.transvar != NULL )
6289 {
6290 assert(SCIPprobIsTransformed(prob));
6291
6292 SCIP_CALL( SCIPvarChgObj(var->data.original.transvar, blkmem, set, prob, primal, lp, eventqueue,
6293 (SCIP_Real) prob->objsense * newobj/prob->objscale) );
6294 }
6295 else
6296 assert(set->stage == SCIP_STAGE_PROBLEM);
6297
6298 var->obj = newobj;
6299 var->unchangedobj = newobj;
6300
6301 break;
6302
6305 oldobj = var->obj;
6306 var->obj = newobj;
6307
6308 /* update unchanged objective value of variable */
6309 if( !lp->divingobjchg )
6310 var->unchangedobj = newobj;
6311
6312 /* update the number of variables with non-zero objective coefficient;
6313 * we only want to do the update, if the variable is added to the problem;
6314 * since the objective of inactive variables cannot be changed, this corresponds to probindex != -1
6315 */
6316 if( SCIPvarIsActive(var) )
6317 SCIPprobUpdateNObjVars(prob, set, oldobj, var->obj);
6318
6319 SCIP_CALL( varEventObjChanged(var, blkmem, set, primal, lp, eventqueue, oldobj, var->obj) );
6320 break;
6321
6326 SCIPerrorMessage("cannot change objective value of a fixed, aggregated, multi-aggregated, or negated variable\n");
6327 return SCIP_INVALIDDATA;
6328
6329 default:
6330 SCIPerrorMessage("unknown variable status\n");
6331 return SCIP_INVALIDDATA;
6332 }
6333 }
6334
6335 return SCIP_OKAY;
6336}
6337
6338/** adds value to objective value of variable */
6340 SCIP_VAR* var, /**< variable to change */
6341 BMS_BLKMEM* blkmem, /**< block memory */
6342 SCIP_SET* set, /**< global SCIP settings */
6343 SCIP_STAT* stat, /**< problem statistics */
6344 SCIP_PROB* transprob, /**< transformed problem data */
6345 SCIP_PROB* origprob, /**< original problem data */
6346 SCIP_PRIMAL* primal, /**< primal data */
6347 SCIP_TREE* tree, /**< branch and bound tree */
6348 SCIP_REOPT* reopt, /**< reoptimization data structure */
6349 SCIP_LP* lp, /**< current LP data */
6350 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
6351 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6352 SCIP_Real addobj /**< additional objective value for variable */
6353 )
6354{
6355 assert(var != NULL);
6356 assert(set != NULL);
6357 assert(var->scip == set->scip);
6358 assert(set->stage < SCIP_STAGE_INITSOLVE);
6359
6360 SCIPsetDebugMsg(set, "adding %g to objective value %g of <%s>\n", addobj, var->obj, var->name);
6361
6362 if( !SCIPsetIsZero(set, addobj) )
6363 {
6364 SCIP_Real oldobj;
6365 int i;
6366
6367 switch( SCIPvarGetStatus(var) )
6368 {
6370 if( var->data.original.transvar != NULL )
6371 {
6372 SCIP_CALL( SCIPvarAddObj(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree,
6373 reopt, lp, eventfilter, eventqueue, (SCIP_Real) transprob->objsense * addobj/transprob->objscale) );
6374 }
6375 else
6376 assert(set->stage == SCIP_STAGE_PROBLEM);
6377
6378 var->obj += addobj;
6379 var->unchangedobj += addobj;
6380 assert(SCIPsetIsEQ(set, var->obj, var->unchangedobj));
6381
6382 break;
6383
6386 oldobj = var->obj;
6387 var->obj += addobj;
6388
6389 /* update unchanged objective value of variable */
6390 if( !lp->divingobjchg )
6391 {
6392 var->unchangedobj += addobj;
6393 assert(SCIPsetIsEQ(set, var->obj, var->unchangedobj));
6394 }
6395
6396 /* update the number of variables with non-zero objective coefficient;
6397 * we only want to do the update, if the variable is added to the problem;
6398 * since the objective of inactive variables cannot be changed, this corresponds to probindex != -1
6399 */
6400 if( SCIPvarIsActive(var) )
6401 SCIPprobUpdateNObjVars(transprob, set, oldobj, var->obj);
6402
6403 SCIP_CALL( varEventObjChanged(var, blkmem, set, primal, lp, eventqueue, oldobj, var->obj) );
6404 break;
6405
6407 assert(SCIPsetIsEQ(set, var->locdom.lb, var->locdom.ub));
6408 SCIPprobAddObjoffset(transprob, var->locdom.lb * addobj);
6409 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6410 break;
6411
6413 assert(!var->donotaggr);
6414 /* x = a*y + c -> add a*addobj to obj. val. of y, and c*addobj to obj. offset of problem */
6415 SCIPprobAddObjoffset(transprob, var->data.aggregate.constant * addobj);
6416 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6417 SCIP_CALL( SCIPvarAddObj(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, primal, tree, reopt,
6418 lp, eventfilter, eventqueue, var->data.aggregate.scalar * addobj) );
6419 break;
6420
6422 assert(!var->donotmultaggr);
6423 /* 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 */
6424 SCIPprobAddObjoffset(transprob, var->data.multaggr.constant * addobj);
6425 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6426 for( i = 0; i < var->data.multaggr.nvars; ++i )
6427 {
6428 SCIP_CALL( SCIPvarAddObj(var->data.multaggr.vars[i], blkmem, set, stat, transprob, origprob, primal, tree,
6429 reopt, lp, eventfilter, eventqueue, var->data.multaggr.scalars[i] * addobj) );
6430 }
6431 break;
6432
6434 /* x' = offset - x -> add -addobj to obj. val. of x and offset*addobj to obj. offset of problem */
6435 assert(var->negatedvar != NULL);
6437 assert(var->negatedvar->negatedvar == var);
6438 SCIPprobAddObjoffset(transprob, var->data.negate.constant * addobj);
6439 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6440 SCIP_CALL( SCIPvarAddObj(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
6441 eventfilter, eventqueue, -addobj) );
6442 break;
6443
6444 default:
6445 SCIPerrorMessage("unknown variable status\n");
6446 return SCIP_INVALIDDATA;
6447 }
6448 }
6449
6450 return SCIP_OKAY;
6451}
6452
6453/** changes objective value of variable in current dive */
6455 SCIP_VAR* var, /**< problem variable to change */
6456 SCIP_SET* set, /**< global SCIP settings */
6457 SCIP_LP* lp, /**< current LP data */
6458 SCIP_Real newobj /**< new objective value for variable */
6459 )
6460{
6461 assert(var != NULL);
6462 assert(set != NULL);
6463 assert(var->scip == set->scip);
6464 assert(lp != NULL);
6465
6466 SCIPsetDebugMsg(set, "changing objective of <%s> to %g in current dive\n", var->name, newobj);
6467
6468 if( SCIPsetIsZero(set, newobj) )
6469 newobj = 0.0;
6470
6471 /* change objective value of attached variables */
6472 switch( SCIPvarGetStatus(var) )
6473 {
6475 assert(var->data.original.transvar != NULL);
6476 SCIP_CALL( SCIPvarChgObjDive(var->data.original.transvar, set, lp, newobj) );
6477 break;
6478
6480 assert(var->data.col != NULL);
6481 SCIP_CALL( SCIPcolChgObj(var->data.col, set, lp, newobj) );
6482 break;
6483
6486 /* nothing to do here: only the constant shift in objective function would change */
6487 break;
6488
6489 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
6490 assert(var->data.aggregate.var != NULL);
6491 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
6492 SCIP_CALL( SCIPvarChgObjDive(var->data.aggregate.var, set, lp, newobj / var->data.aggregate.scalar) );
6493 /* the constant can be ignored, because it would only affect the objective shift */
6494 break;
6495
6497 SCIPerrorMessage("cannot change diving objective value of a multi-aggregated variable\n");
6498 return SCIP_INVALIDDATA;
6499
6500 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
6501 assert(var->negatedvar != NULL);
6503 assert(var->negatedvar->negatedvar == var);
6504 SCIP_CALL( SCIPvarChgObjDive(var->negatedvar, set, lp, -newobj) );
6505 /* the offset can be ignored, because it would only affect the objective shift */
6506 break;
6507
6508 default:
6509 SCIPerrorMessage("unknown variable status\n");
6510 return SCIP_INVALIDDATA;
6511 }
6512
6513 return SCIP_OKAY;
6514}
6515
6516/** adjust lower bound to integral value, if variable is integral */
6518 SCIP_VAR* var, /**< problem variable */
6519 SCIP_SET* set, /**< global SCIP settings */
6520 SCIP_Real* lb /**< pointer to lower bound to adjust */
6521 )
6522{
6523 assert(var != NULL);
6524 assert(set != NULL);
6525 assert(var->scip == set->scip);
6526 assert(lb != NULL);
6527
6528 SCIPsetDebugMsg(set, "adjust lower bound %g of <%s>\n", *lb, var->name);
6529
6530 *lb = adjustedLb(set, SCIPvarGetType(var), *lb);
6531}
6532
6533/** adjust upper bound to integral value, if variable is integral */
6535 SCIP_VAR* var, /**< problem variable */
6536 SCIP_SET* set, /**< global SCIP settings */
6537 SCIP_Real* ub /**< pointer to upper bound to adjust */
6538 )
6539{
6540 assert(var != NULL);
6541 assert(set != NULL);
6542 assert(var->scip == set->scip);
6543 assert(ub != NULL);
6544
6545 SCIPsetDebugMsg(set, "adjust upper bound %g of <%s>\n", *ub, var->name);
6546
6547 *ub = adjustedUb(set, SCIPvarGetType(var), *ub);
6548}
6549
6550/** adjust lower or upper bound to integral value, if variable is integral */
6552 SCIP_VAR* var, /**< problem variable */
6553 SCIP_SET* set, /**< global SCIP settings */
6554 SCIP_BOUNDTYPE boundtype, /**< type of bound to adjust */
6555 SCIP_Real* bd /**< pointer to bound to adjust */
6556 )
6557{
6558 assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER);
6559
6560 if( boundtype == SCIP_BOUNDTYPE_LOWER )
6561 SCIPvarAdjustLb(var, set, bd);
6562 else
6563 SCIPvarAdjustUb(var, set, bd);
6564}
6565
6566/** changes lower bound of original variable in original problem */
6568 SCIP_VAR* var, /**< problem variable to change */
6569 SCIP_SET* set, /**< global SCIP settings */
6570 SCIP_Real newbound /**< new bound for variable */
6571 )
6572{
6573 int i;
6574
6575 assert(var != NULL);
6576 assert(!SCIPvarIsTransformed(var));
6578 assert(set != NULL);
6579 assert(var->scip == set->scip);
6580 assert(set->stage == SCIP_STAGE_PROBLEM);
6581
6582 /* check that the bound is feasible */
6584 /* adjust bound to integral value if variable is of integral type */
6585 newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
6586
6587 if( SCIPsetIsZero(set, newbound) )
6588 newbound = 0.0;
6589
6590 /* original domains are only stored for ORIGINAL variables, not for NEGATED */
6592 {
6593 SCIPsetDebugMsg(set, "changing original lower bound of <%s> from %g to %g\n",
6594 var->name, var->data.original.origdom.lb, newbound);
6595
6596 if( SCIPsetIsEQ(set, var->data.original.origdom.lb, newbound) )
6597 return SCIP_OKAY;
6598
6599 /* change the bound */
6600 var->data.original.origdom.lb = newbound;
6601 }
6602 else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED )
6603 {
6604 assert( var->negatedvar != NULL );
6605 SCIP_CALL( SCIPvarChgUbOriginal(var->negatedvar, set, var->data.negate.constant - newbound) );
6606 }
6607
6608 /* process parent variables */
6609 for( i = 0; i < var->nparentvars; ++i )
6610 {
6611 SCIP_VAR* parentvar;
6612
6613 parentvar = var->parentvars[i];
6614 assert(parentvar != NULL);
6615 assert(SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_NEGATED);
6616 assert(parentvar->negatedvar == var);
6617 assert(var->negatedvar == parentvar);
6618
6619 SCIP_CALL( SCIPvarChgUbOriginal(parentvar, set, parentvar->data.negate.constant - newbound) );
6620 }
6621
6622 return SCIP_OKAY;
6623}
6624
6625/** changes upper bound of original variable in original problem */
6627 SCIP_VAR* var, /**< problem variable to change */
6628 SCIP_SET* set, /**< global SCIP settings */
6629 SCIP_Real newbound /**< new bound for variable */
6630 )
6631{
6632 int i;
6633
6634 assert(var != NULL);
6635 assert(!SCIPvarIsTransformed(var));
6637 assert(set != NULL);
6638 assert(var->scip == set->scip);
6639 assert(set->stage == SCIP_STAGE_PROBLEM);
6640
6641 /* check that the bound is feasible */
6643 /* adjust bound to integral value if variable is of integral type */
6644 newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
6645
6646 if( SCIPsetIsZero(set, newbound) )
6647 newbound = 0.0;
6648
6649 /* original domains are only stored for ORIGINAL variables, not for NEGATED */
6651 {
6652 SCIPsetDebugMsg(set, "changing original upper bound of <%s> from %g to %g\n",
6653 var->name, var->data.original.origdom.ub, newbound);
6654
6655 if( SCIPsetIsEQ(set, var->data.original.origdom.ub, newbound) )
6656 return SCIP_OKAY;
6657
6658 /* change the bound */
6659 var->data.original.origdom.ub = newbound;
6660 }
6661 else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED )
6662 {
6663 assert( var->negatedvar != NULL );
6664 SCIP_CALL( SCIPvarChgLbOriginal(var->negatedvar, set, var->data.negate.constant - newbound) );
6665 }
6666
6667 /* process parent variables */
6668 for( i = 0; i < var->nparentvars; ++i )
6669 {
6670 SCIP_VAR* parentvar;
6671
6672 parentvar = var->parentvars[i];
6673 assert(parentvar != NULL);
6674 assert(SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_NEGATED);
6675 assert(parentvar->negatedvar == var);
6676 assert(var->negatedvar == parentvar);
6677
6678 SCIP_CALL( SCIPvarChgLbOriginal(parentvar, set, parentvar->data.negate.constant - newbound) );
6679 }
6680
6681 return SCIP_OKAY;
6682}
6683
6684/** appends GLBCHANGED event to the event queue */
6685static
6687 SCIP_VAR* var, /**< problem variable to change */
6688 BMS_BLKMEM* blkmem, /**< block memory */
6689 SCIP_SET* set, /**< global SCIP settings */
6690 SCIP_LP* lp, /**< current LP data */
6691 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
6692 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6693 SCIP_Real oldbound, /**< old lower bound for variable */
6694 SCIP_Real newbound /**< new lower bound for variable */
6695 )
6696{
6697 assert(var != NULL);
6698 assert(var->eventfilter != NULL);
6699 assert(SCIPvarIsTransformed(var));
6700 assert(!SCIPsetIsEQ(set, oldbound, newbound) || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
6701 assert(set != NULL);
6702 assert(var->scip == set->scip);
6703
6704 /* check, if the variable is being tracked for bound changes
6705 * COLUMN and LOOSE variables are tracked always, because global/root pseudo objective value has to be updated
6706 */
6707 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GLBCHANGED) != 0)
6710 {
6711 SCIP_EVENT* event;
6712
6713 SCIPsetDebugMsg(set, "issue GLBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
6714
6715 SCIP_CALL( SCIPeventCreateGlbChanged(&event, blkmem, var, oldbound, newbound) );
6716 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
6717 }
6718
6719 return SCIP_OKAY;
6720}
6721
6722/** appends GUBCHANGED event to the event queue */
6723static
6725 SCIP_VAR* var, /**< problem variable to change */
6726 BMS_BLKMEM* blkmem, /**< block memory */
6727 SCIP_SET* set, /**< global SCIP settings */
6728 SCIP_LP* lp, /**< current LP data */
6729 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
6730 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6731 SCIP_Real oldbound, /**< old lower bound for variable */
6732 SCIP_Real newbound /**< new lower bound for variable */
6733 )
6734{
6735 assert(var != NULL);
6736 assert(var->eventfilter != NULL);
6737 assert(SCIPvarIsTransformed(var));
6738 assert(!SCIPsetIsEQ(set, oldbound, newbound) || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
6739 assert(set != NULL);
6740 assert(var->scip == set->scip);
6741
6742 /* check, if the variable is being tracked for bound changes
6743 * COLUMN and LOOSE variables are tracked always, because global/root pseudo objective value has to be updated
6744 */
6745 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GUBCHANGED) != 0)
6748 {
6749 SCIP_EVENT* event;
6750
6751 SCIPsetDebugMsg(set, "issue GUBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
6752
6753 SCIP_CALL( SCIPeventCreateGubChanged(&event, blkmem, var, oldbound, newbound) );
6754 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
6755 }
6756
6757 return SCIP_OKAY;
6758}
6759
6760/** appends GHOLEADDED event to the event queue */
6761static
6763 SCIP_VAR* var, /**< problem variable to change */
6764 BMS_BLKMEM* blkmem, /**< block memory */
6765 SCIP_SET* set, /**< global SCIP settings */
6766 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
6767 SCIP_Real left, /**< left bound of open interval in new hole */
6768 SCIP_Real right /**< right bound of open interval in new hole */
6769 )
6770{
6771 assert(var != NULL);
6772 assert(var->eventfilter != NULL);
6773 assert(SCIPvarIsTransformed(var));
6774 assert(set != NULL);
6775 assert(var->scip == set->scip);
6776 assert(SCIPsetIsLT(set, left, right));
6777
6778 /* check, if the variable is being tracked for bound changes */
6779 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GHOLEADDED) != 0) )
6780 {
6781 SCIP_EVENT* event;
6782
6783 SCIPsetDebugMsg(set, "issue GHOLEADDED event for variable <%s>: (%.15g,%.15g)\n", var->name, left, right);
6784
6785 SCIP_CALL( SCIPeventCreateGholeAdded(&event, blkmem, var, left, right) );
6786 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
6787 }
6788
6789 return SCIP_OKAY;
6790}
6791
6792/** increases root bound change statistics after a global bound change */
6793static
6795 SCIP_VAR* var, /**< problem variable to change */
6796 SCIP_SET* set, /**< global SCIP settings */
6797 SCIP_STAT* stat /**< problem statistics */
6798 )
6799{
6800 assert(var != NULL);
6801 assert(set != NULL);
6802 assert(var->scip == set->scip);
6803 assert(stat != NULL);
6804
6805 if( SCIPvarIsActive(var) && SCIPvarIsTransformed(var) && set->stage == SCIP_STAGE_SOLVING )
6806 {
6807 stat->nrootboundchgs++;
6808 stat->nrootboundchgsrun++;
6809 if( SCIPvarIsIntegral(var) && SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
6810 {
6811 stat->nrootintfixings++;
6812 stat->nrootintfixingsrun++;
6813 }
6814 }
6815}
6816
6817/* forward declaration, because both methods call each other recursively */
6818
6819/* performs the current change in upper bound, changes all parents accordingly */
6820static
6822 SCIP_VAR* var, /**< problem variable to change */
6823 BMS_BLKMEM* blkmem, /**< block memory */
6824 SCIP_SET* set, /**< global SCIP settings */
6825 SCIP_STAT* stat, /**< problem statistics */
6826 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
6827 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
6828 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
6829 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
6830 SCIP_Real newbound /**< new bound for variable */
6831 );
6832
6833/** performs the current change in lower bound, changes all parents accordingly */
6834static
6836 SCIP_VAR* var, /**< problem variable to change */
6837 BMS_BLKMEM* blkmem, /**< block memory */
6838 SCIP_SET* set, /**< global SCIP settings */
6839 SCIP_STAT* stat, /**< problem statistics */
6840 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
6841 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
6842 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
6843 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
6844 SCIP_Real newbound /**< new bound for variable */
6845 )
6846{
6847 SCIP_VAR* parentvar;
6848 SCIP_Real oldbound;
6849 int i;
6850
6851 assert(var != NULL);
6852 /* local domains can violate global bounds but not more than feasibility epsilon */
6853 assert(SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb));
6854 assert(SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub));
6855 assert(blkmem != NULL);
6856 assert(set != NULL);
6857 assert(var->scip == set->scip);
6858 assert(stat != NULL);
6859
6860 /* adjust bound to integral value if variable is of integral type */
6861 newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
6862
6863 /* check that the bound is feasible */
6864 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM && newbound > var->glbdom.ub )
6865 {
6866 /* due to numerics we only want to be feasible in feasibility tolerance */
6867 assert(SCIPsetIsFeasLE(set, newbound, var->glbdom.ub));
6868 newbound = var->glbdom.ub;
6869 }
6871
6872 assert(var->vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, newbound, 0.0) || SCIPsetIsEQ(set, newbound, 1.0)); /*lint !e641*/
6873
6874 SCIPsetDebugMsg(set, "process changing global lower bound of <%s> from %f to %f\n", var->name, var->glbdom.lb, newbound);
6875
6876 if( SCIPsetIsEQ(set, newbound, var->glbdom.lb) && !(newbound != var->glbdom.lb && newbound * var->glbdom.lb <= 0.0) ) /*lint !e777*/
6877 return SCIP_OKAY;
6878
6879 /* check bound on debugging solution */
6880 SCIP_CALL( SCIPdebugCheckLbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
6881
6882 /* change the bound */
6883 oldbound = var->glbdom.lb;
6884 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasLE(set, newbound, var->glbdom.ub));
6885 var->glbdom.lb = newbound;
6886 assert( SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb) );
6887 assert( SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub) );
6888
6890 {
6891 /* merges overlapping holes into single holes, moves bounds respectively */
6892 domMerge(&var->glbdom, blkmem, set, &newbound, NULL);
6893 }
6894
6895 /* update the root bound changes counters */
6896 varIncRootboundchgs(var, set, stat);
6897
6898 /* update the lbchginfos array by replacing worse local bounds with the new global bound and changing the
6899 * redundant bound changes to be branching decisions
6900 */
6901 for( i = 0; i < var->nlbchginfos; ++i )
6902 {
6903 assert(var->lbchginfos[i].var == var);
6904
6905 if( var->lbchginfos[i].oldbound < var->glbdom.lb )
6906 {
6907 SCIPsetDebugMsg(set, " -> adjust lower bound change <%s>: %g -> %g due to new global lower bound %g\n",
6908 SCIPvarGetName(var), var->lbchginfos[i].oldbound, var->lbchginfos[i].newbound, var->glbdom.lb);
6909 var->lbchginfos[i].oldbound = var->glbdom.lb;
6910 if( SCIPsetIsLE(set, var->lbchginfos[i].newbound, var->glbdom.lb) )
6911 {
6912 /* this bound change is redundant due to the new global bound */
6913 var->lbchginfos[i].newbound = var->glbdom.lb;
6914 var->lbchginfos[i].boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
6915 var->lbchginfos[i].redundant = TRUE;
6916 }
6917 else
6918 break; /* from now on, the remaining local bound changes are not redundant */
6919 }
6920 else
6921 break; /* from now on, the remaining local bound changes are not redundant */
6922 }
6923
6924 /* remove redundant implications and variable bounds */
6926 && (!set->reopt_enable || set->stage == SCIP_STAGE_PRESOLVING) )
6927 {
6928 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, TRUE, TRUE) );
6929 }
6930
6931 /* issue bound change event */
6932 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
6934 {
6935 SCIP_CALL( varEventGlbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
6936 }
6937
6938 /* process parent variables */
6939 for( i = 0; i < var->nparentvars; ++i )
6940 {
6941 parentvar = var->parentvars[i];
6942 assert(parentvar != NULL);
6943
6944 switch( SCIPvarGetStatus(parentvar) )
6945 {
6947 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
6948 break;
6949
6954 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
6955 return SCIP_INVALIDDATA;
6956
6957 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
6958 assert(parentvar->data.aggregate.var == var);
6959 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
6960 {
6961 SCIP_Real parentnewbound;
6962
6963 /* a > 0 -> change lower bound of y */
6964 assert(SCIPsetIsInfinity(set, -parentvar->glbdom.lb) || SCIPsetIsInfinity(set, -oldbound)
6965 || SCIPsetIsFeasEQ(set, parentvar->glbdom.lb, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
6966 || (SCIPsetIsZero(set, parentvar->glbdom.lb / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
6967
6968 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6969 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6970 else
6971 parentnewbound = newbound;
6972 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
6973 }
6974 else
6975 {
6976 SCIP_Real parentnewbound;
6977
6978 /* a < 0 -> change upper bound of y */
6979 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
6980 assert(SCIPsetIsInfinity(set, parentvar->glbdom.ub) || SCIPsetIsInfinity(set, -oldbound)
6981 || SCIPsetIsFeasEQ(set, parentvar->glbdom.ub, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
6982 || (SCIPsetIsZero(set, parentvar->glbdom.ub / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
6983
6984 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6985 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6986 else
6987 parentnewbound = -newbound;
6988 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
6989 }
6990 break;
6991
6992 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
6993 assert(parentvar->negatedvar != NULL);
6994 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
6995 assert(parentvar->negatedvar->negatedvar == parentvar);
6996 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
6997 parentvar->data.negate.constant - newbound) );
6998 break;
6999
7000 default:
7001 SCIPerrorMessage("unknown variable status\n");
7002 return SCIP_INVALIDDATA;
7003 }
7004 }
7005
7006 return SCIP_OKAY;
7007}
7008
7009/** performs the current change in upper bound, changes all parents accordingly */
7010static
7012 SCIP_VAR* var, /**< problem variable to change */
7013 BMS_BLKMEM* blkmem, /**< block memory */
7014 SCIP_SET* set, /**< global SCIP settings */
7015 SCIP_STAT* stat, /**< problem statistics */
7016 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7017 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7018 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7019 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
7020 SCIP_Real newbound /**< new bound for variable */
7021 )
7022{
7023 SCIP_VAR* parentvar;
7024 SCIP_Real oldbound;
7025 int i;
7026
7027 assert(var != NULL);
7028 /* local domains can violate global bounds but not more than feasibility epsilon */
7029 assert(SCIPsetIsFeasLE(set, var->glbdom.lb , var->locdom.lb));
7030 assert(SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub));
7031 assert(blkmem != NULL);
7032 assert(set != NULL);
7033 assert(var->scip == set->scip);
7034 assert(stat != NULL);
7035
7036 /* adjust bound to integral value if variable is of integral type */
7037 newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
7038
7039 /* check that the bound is feasible */
7040 if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM && newbound < var->glbdom.lb )
7041 {
7042 /* due to numerics we only want to be feasible in feasibility tolerance */
7043 assert(SCIPsetIsFeasGE(set, newbound, var->glbdom.lb));
7044 newbound = var->glbdom.lb;
7045 }
7047
7048 assert(var->vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, newbound, 0.0) || SCIPsetIsEQ(set, newbound, 1.0)); /*lint !e641*/
7049
7050 SCIPsetDebugMsg(set, "process changing global upper bound of <%s> from %f to %f\n", var->name, var->glbdom.ub, newbound);
7051
7052 if( SCIPsetIsEQ(set, newbound, var->glbdom.ub) && !(newbound != var->glbdom.ub && newbound * var->glbdom.ub <= 0.0) ) /*lint !e777*/
7053 return SCIP_OKAY;
7054
7055 /* check bound on debugging solution */
7056 SCIP_CALL( SCIPdebugCheckUbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
7057
7058 /* change the bound */
7059 oldbound = var->glbdom.ub;
7060 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasGE(set, newbound, var->glbdom.lb));
7061 var->glbdom.ub = newbound;
7062 assert( SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb) );
7063 assert( SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub) );
7064
7066 {
7067 /* merges overlapping holes into single holes, moves bounds respectively */
7068 domMerge(&var->glbdom, blkmem, set, NULL, &newbound);
7069 }
7070
7071 /* update the root bound changes counters */
7072 varIncRootboundchgs(var, set, stat);
7073
7074 /* update the ubchginfos array by replacing worse local bounds with the new global bound and changing the
7075 * redundant bound changes to be branching decisions
7076 */
7077 for( i = 0; i < var->nubchginfos; ++i )
7078 {
7079 assert(var->ubchginfos[i].var == var);
7080 if( var->ubchginfos[i].oldbound > var->glbdom.ub )
7081 {
7082 SCIPsetDebugMsg(set, " -> adjust upper bound change <%s>: %g -> %g due to new global upper bound %g\n",
7083 SCIPvarGetName(var), var->ubchginfos[i].oldbound, var->ubchginfos[i].newbound, var->glbdom.ub);
7084 var->ubchginfos[i].oldbound = var->glbdom.ub;
7085 if( SCIPsetIsGE(set, var->ubchginfos[i].newbound, var->glbdom.ub) )
7086 {
7087 /* this bound change is redundant due to the new global bound */
7088 var->ubchginfos[i].newbound = var->glbdom.ub;
7089 var->ubchginfos[i].boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
7090 var->ubchginfos[i].redundant = TRUE;
7091 }
7092 else
7093 break; /* from now on, the remaining local bound changes are not redundant */
7094 }
7095 else
7096 break; /* from now on, the remaining local bound changes are not redundant */
7097 }
7098
7099 /* remove redundant implications and variable bounds */
7101 && (!set->reopt_enable || set->stage == SCIP_STAGE_PRESOLVING) )
7102 {
7103 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, TRUE, TRUE) );
7104 }
7105
7106 /* issue bound change event */
7107 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
7109 {
7110 SCIP_CALL( varEventGubChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
7111 }
7112
7113 /* process parent variables */
7114 for( i = 0; i < var->nparentvars; ++i )
7115 {
7116 parentvar = var->parentvars[i];
7117 assert(parentvar != NULL);
7118
7119 switch( SCIPvarGetStatus(parentvar) )
7120 {
7122 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7123 break;
7124
7129 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
7130 return SCIP_INVALIDDATA;
7131
7132 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7133 assert(parentvar->data.aggregate.var == var);
7134 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
7135 {
7136 SCIP_Real parentnewbound;
7137
7138 /* a > 0 -> change upper bound of y */
7139 assert(SCIPsetIsInfinity(set, parentvar->glbdom.ub) || SCIPsetIsInfinity(set, oldbound)
7140 || SCIPsetIsFeasEQ(set, parentvar->glbdom.ub,
7141 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7142 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7143 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7144 else
7145 parentnewbound = newbound;
7146 SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
7147 }
7148 else
7149 {
7150 SCIP_Real parentnewbound;
7151
7152 /* a < 0 -> change lower bound of y */
7153 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
7154 assert(SCIPsetIsInfinity(set, -parentvar->glbdom.lb) || SCIPsetIsInfinity(set, oldbound)
7155 || SCIPsetIsFeasEQ(set, parentvar->glbdom.lb,
7156 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7157 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7158 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7159 else
7160 parentnewbound = -newbound;
7161 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
7162 }
7163 break;
7164
7165 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
7166 assert(parentvar->negatedvar != NULL);
7167 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
7168 assert(parentvar->negatedvar->negatedvar == parentvar);
7169 SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7170 parentvar->data.negate.constant - newbound) );
7171 break;
7172
7173 default:
7174 SCIPerrorMessage("unknown variable status\n");
7175 return SCIP_INVALIDDATA;
7176 }
7177 }
7178
7179 return SCIP_OKAY;
7180}
7181
7182/** changes global lower bound of variable; if possible, adjusts bound to integral value;
7183 * updates local lower bound if the global bound is tighter
7184 */
7186 SCIP_VAR* var, /**< problem variable to change */
7187 BMS_BLKMEM* blkmem, /**< block memory */
7188 SCIP_SET* set, /**< global SCIP settings */
7189 SCIP_STAT* stat, /**< problem statistics */
7190 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7191 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7192 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7193 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
7194 SCIP_Real newbound /**< new bound for variable */
7195 )
7196{
7197 assert(var != NULL);
7198 assert(blkmem != NULL);
7199 assert(set != NULL);
7200 assert(var->scip == set->scip);
7201
7202 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7203 * of the domain within feastol
7204 */
7205 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->glbdom.ub));
7206
7207 /* adjust bound to integral value if variable is of integral type */
7208 newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
7209
7210 /* check that the adjusted bound is feasible
7211 * @todo this does not have to be the case if the original problem was infeasible due to bounds and we are called
7212 * here because we reset bounds to their original value!
7213 */
7214 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->glbdom.ub));
7215
7217 {
7218 /* we do not want to exceed the upperbound, which could have happened due to numerics */
7219 newbound = MIN(newbound, var->glbdom.ub);
7220 }
7222
7223 /* the new global bound has to be tighter except we are in the original problem; this must be w.r.t. feastol because
7224 * SCIPvarFix() allows fixings that are outside of the domain within feastol
7225 */
7226 assert(lp == NULL || SCIPsetIsFeasLE(set, var->glbdom.lb, newbound) || (set->reopt_enable && set->stage == SCIP_STAGE_PRESOLVED));
7227
7228 SCIPsetDebugMsg(set, "changing global lower bound of <%s> from %g to %g\n", var->name, var->glbdom.lb, newbound);
7229
7230 if( SCIPsetIsEQ(set, var->glbdom.lb, newbound) && !(newbound != var->glbdom.lb && newbound * var->glbdom.lb <= 0.0) ) /*lint !e777*/
7231 return SCIP_OKAY;
7232
7233 /* change bounds of attached variables */
7234 switch( SCIPvarGetStatus(var) )
7235 {
7237 if( var->data.original.transvar != NULL )
7238 {
7239 SCIP_CALL( SCIPvarChgLbGlobal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue,
7240 cliquetable, newbound) );
7241 }
7242 else
7243 {
7244 assert(set->stage == SCIP_STAGE_PROBLEM);
7245 if( newbound > SCIPvarGetLbLocal(var) )
7246 {
7247 SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7248 }
7249 SCIP_CALL( varProcessChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7250 }
7251 break;
7252
7255 if( newbound > SCIPvarGetLbLocal(var) )
7256 {
7257 SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7258 }
7259 SCIP_CALL( varProcessChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7260 break;
7261
7263 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7264 return SCIP_INVALIDDATA;
7265
7266 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7267 assert(var->data.aggregate.var != NULL);
7269 {
7270 SCIP_Real childnewbound;
7271
7272 /* a > 0 -> change lower bound of y */
7274 || SCIPsetIsFeasEQ(set, var->glbdom.lb,
7276 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7277 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7278 else
7279 childnewbound = newbound;
7280 SCIP_CALL( SCIPvarChgLbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7281 childnewbound) );
7282 }
7283 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7284 {
7285 SCIP_Real childnewbound;
7286
7287 /* a < 0 -> change upper bound of y */
7289 || SCIPsetIsFeasEQ(set, var->glbdom.lb,
7291 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7292 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7293 else
7294 childnewbound = -newbound;
7295 SCIP_CALL( SCIPvarChgUbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7296 childnewbound) );
7297 }
7298 else
7299 {
7300 SCIPerrorMessage("scalar is zero in aggregation\n");
7301 return SCIP_INVALIDDATA;
7302 }
7303 break;
7304
7306 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
7307 return SCIP_INVALIDDATA;
7308
7309 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
7310 assert(var->negatedvar != NULL);
7312 assert(var->negatedvar->negatedvar == var);
7313 SCIP_CALL( SCIPvarChgUbGlobal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7314 var->data.negate.constant - newbound) );
7315 break;
7316
7317 default:
7318 SCIPerrorMessage("unknown variable status\n");
7319 return SCIP_INVALIDDATA;
7320 }
7321
7322 return SCIP_OKAY;
7323}
7324
7325/** changes global upper bound of variable; if possible, adjusts bound to integral value;
7326 * updates local upper bound if the global bound is tighter
7327 */
7329 SCIP_VAR* var, /**< problem variable to change */
7330 BMS_BLKMEM* blkmem, /**< block memory */
7331 SCIP_SET* set, /**< global SCIP settings */
7332 SCIP_STAT* stat, /**< problem statistics */
7333 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7334 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7335 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7336 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
7337 SCIP_Real newbound /**< new bound for variable */
7338 )
7339{
7340 assert(var != NULL);
7341 assert(blkmem != NULL);
7342 assert(set != NULL);
7343 assert(var->scip == set->scip);
7344
7345 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7346 * of the domain within feastol
7347 */
7348 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->glbdom.lb));
7349
7350 /* adjust bound to integral value if variable is of integral type */
7351 newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
7352
7353 /* check that the adjusted bound is feasible
7354 * @todo this does not have to be the case if the original problem was infeasible due to bounds and we are called
7355 * here because we reset bounds to their original value!
7356 */
7357 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->glbdom.lb));
7358
7360 {
7361 /* we do not want to undercut the lowerbound, which could have happened due to numerics */
7362 newbound = MAX(newbound, var->glbdom.lb);
7363 }
7365
7366 /* the new global bound has to be tighter except we are in the original problem; this must be w.r.t. feastol because
7367 * SCIPvarFix() allows fixings that are outside of the domain within feastol
7368 */
7369 assert(lp == NULL || SCIPsetIsFeasGE(set, var->glbdom.ub, newbound) || (set->reopt_enable && set->stage == SCIP_STAGE_PRESOLVED));
7370
7371 SCIPsetDebugMsg(set, "changing global upper bound of <%s> from %g to %g\n", var->name, var->glbdom.ub, newbound);
7372
7373 if( SCIPsetIsEQ(set, var->glbdom.ub, newbound) && !(newbound != var->glbdom.ub && newbound * var->glbdom.ub <= 0.0) ) /*lint !e777*/
7374 return SCIP_OKAY;
7375
7376 /* change bounds of attached variables */
7377 switch( SCIPvarGetStatus(var) )
7378 {
7380 if( var->data.original.transvar != NULL )
7381 {
7382 SCIP_CALL( SCIPvarChgUbGlobal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7383 newbound) );
7384 }
7385 else
7386 {
7387 assert(set->stage == SCIP_STAGE_PROBLEM);
7388 if( newbound < SCIPvarGetUbLocal(var) )
7389 {
7390 SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7391 }
7392 SCIP_CALL( varProcessChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7393 }
7394 break;
7395
7398 if( newbound < SCIPvarGetUbLocal(var) )
7399 {
7400 SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7401 }
7402 SCIP_CALL( varProcessChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7403 break;
7404
7406 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7407 return SCIP_INVALIDDATA;
7408
7409 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7410 assert(var->data.aggregate.var != NULL);
7412 {
7413 SCIP_Real childnewbound;
7414
7415 /* a > 0 -> change lower bound of y */
7417 || SCIPsetIsFeasEQ(set, var->glbdom.ub,
7419 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7420 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7421 else
7422 childnewbound = newbound;
7423 SCIP_CALL( SCIPvarChgUbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7424 childnewbound) );
7425 }
7426 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7427 {
7428 SCIP_Real childnewbound;
7429
7430 /* a < 0 -> change upper bound of y */
7432 || SCIPsetIsFeasEQ(set, var->glbdom.ub,
7434 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7435 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7436 else
7437 childnewbound = -newbound;
7438 SCIP_CALL( SCIPvarChgLbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7439 childnewbound) );
7440 }
7441 else
7442 {
7443 SCIPerrorMessage("scalar is zero in aggregation\n");
7444 return SCIP_INVALIDDATA;
7445 }
7446 break;
7447
7449 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
7450 return SCIP_INVALIDDATA;
7451
7452 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
7453 assert(var->negatedvar != NULL);
7455 assert(var->negatedvar->negatedvar == var);
7456 SCIP_CALL( SCIPvarChgLbGlobal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7457 var->data.negate.constant - newbound) );
7458 break;
7459
7460 default:
7461 SCIPerrorMessage("unknown variable status\n");
7462 return SCIP_INVALIDDATA;
7463 }
7464
7465 return SCIP_OKAY;
7466}
7467
7468/** changes lazy lower bound of the variable, this is only possible if the variable is not in the LP yet */
7470 SCIP_VAR* var, /**< problem variable */
7471 SCIP_SET* set, /**< global SCIP settings */
7472 SCIP_Real lazylb /**< the lazy lower bound to be set */
7473 )
7474{
7475 assert(var != NULL);
7476 assert(var->probindex != -1);
7477 assert(SCIPsetIsFeasGE(set, var->glbdom.ub, lazylb));
7478 assert(SCIPsetIsFeasGE(set, var->lazyub, lazylb));
7479 assert(set != NULL);
7480 assert(var->scip == set->scip);
7481
7482 /* variable should not be in the LP */
7484 return SCIP_INVALIDCALL;
7485
7486 var->lazylb = lazylb;
7487
7488 return SCIP_OKAY;
7489}
7490
7491/** changes lazy upper bound of the variable, this is only possible if the variable is not in the LP yet */
7493 SCIP_VAR* var, /**< problem variable */
7494 SCIP_SET* set, /**< global SCIP settings */
7495 SCIP_Real lazyub /**< the lazy lower bound to be set */
7496 )
7497{
7498 assert(var != NULL);
7499 assert(var->probindex != -1);
7500 assert(SCIPsetIsFeasGE(set, lazyub, var->glbdom.lb));
7501 assert(SCIPsetIsFeasGE(set, lazyub, var->lazylb));
7502 assert(set != NULL);
7503 assert(var->scip == set->scip);
7504
7505 /* variable should not be in the LP */
7507 return SCIP_INVALIDCALL;
7508
7509 var->lazyub = lazyub;
7510
7511 return SCIP_OKAY;
7512}
7513
7514
7515/** changes global bound of variable; if possible, adjusts bound to integral value;
7516 * updates local bound if the global bound is tighter
7517 */
7519 SCIP_VAR* var, /**< problem variable to change */
7520 BMS_BLKMEM* blkmem, /**< block memory */
7521 SCIP_SET* set, /**< global SCIP settings */
7522 SCIP_STAT* stat, /**< problem statistics */
7523 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7524 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7525 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7526 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
7527 SCIP_Real newbound, /**< new bound for variable */
7528 SCIP_BOUNDTYPE boundtype /**< type of bound: lower or upper bound */
7529 )
7530{
7531 /* apply bound change to the LP data */
7532 switch( boundtype )
7533 {
7535 return SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound);
7537 return SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound);
7538 default:
7539 SCIPerrorMessage("unknown bound type\n");
7540 return SCIP_INVALIDDATA;
7541 }
7542}
7543
7544/** appends LBTIGHTENED or LBRELAXED event to the event queue */
7545static
7547 SCIP_VAR* var, /**< problem variable to change */
7548 BMS_BLKMEM* blkmem, /**< block memory */
7549 SCIP_SET* set, /**< global SCIP settings */
7550 SCIP_LP* lp, /**< current LP data */
7551 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
7552 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
7553 SCIP_Real oldbound, /**< old lower bound for variable */
7554 SCIP_Real newbound /**< new lower bound for variable */
7555 )
7556{
7557 assert(var != NULL);
7558 assert(var->eventfilter != NULL);
7559 assert(SCIPvarIsTransformed(var));
7560 assert(!SCIPsetIsEQ(set, oldbound, newbound) || newbound == var->glbdom.lb || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
7561 assert(set != NULL);
7562 assert(var->scip == set->scip);
7563
7564 /* check, if the variable is being tracked for bound changes
7565 * COLUMN and LOOSE variables are tracked always, because row activities and LP changes have to be updated
7566 */
7567 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_LBCHANGED) != 0)
7570 {
7571 SCIP_EVENT* event;
7572
7573 SCIPsetDebugMsg(set, "issue LBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
7574
7575 SCIP_CALL( SCIPeventCreateLbChanged(&event, blkmem, var, oldbound, newbound) );
7576 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
7577 }
7578
7579 return SCIP_OKAY;
7580}
7581
7582/** appends UBTIGHTENED or UBRELAXED event to the event queue */
7583static
7585 SCIP_VAR* var, /**< problem variable to change */
7586 BMS_BLKMEM* blkmem, /**< block memory */
7587 SCIP_SET* set, /**< global SCIP settings */
7588 SCIP_LP* lp, /**< current LP data */
7589 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
7590 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
7591 SCIP_Real oldbound, /**< old upper bound for variable */
7592 SCIP_Real newbound /**< new upper bound for variable */
7593 )
7594{
7595 assert(var != NULL);
7596 assert(var->eventfilter != NULL);
7597 assert(SCIPvarIsTransformed(var));
7598 assert(!SCIPsetIsEQ(set, oldbound, newbound) || newbound == var->glbdom.ub || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
7599 assert(set != NULL);
7600 assert(var->scip == set->scip);
7601
7602 /* check, if the variable is being tracked for bound changes
7603 * COLUMN and LOOSE variables are tracked always, because row activities and LP changes have to be updated
7604 */
7605 if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_UBCHANGED) != 0)
7608 {
7609 SCIP_EVENT* event;
7610
7611 SCIPsetDebugMsg(set, "issue UBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
7612
7613 SCIP_CALL( SCIPeventCreateUbChanged(&event, blkmem, var, oldbound, newbound) );
7614 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
7615 }
7616
7617 return SCIP_OKAY;
7618}
7619
7620/* forward declaration, because both methods call each other recursively */
7621
7622/* performs the current change in upper bound, changes all parents accordingly */
7623static
7625 SCIP_VAR* var, /**< problem variable to change */
7626 BMS_BLKMEM* blkmem, /**< block memory */
7627 SCIP_SET* set, /**< global SCIP settings */
7628 SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7629 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7630 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7631 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7632 SCIP_Real newbound /**< new bound for variable */
7633 );
7634
7635/** performs the current change in lower bound, changes all parents accordingly */
7636static
7638 SCIP_VAR* var, /**< problem variable to change */
7639 BMS_BLKMEM* blkmem, /**< block memory */
7640 SCIP_SET* set, /**< global SCIP settings */
7641 SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7642 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7643 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7644 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7645 SCIP_Real newbound /**< new bound for variable */
7646 )
7647{
7648 SCIP_VAR* parentvar;
7649 SCIP_Real oldbound;
7650 int i;
7651
7652 assert(var != NULL);
7653 assert(set != NULL);
7654 assert(var->scip == set->scip);
7655 assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && (SCIPsetIsZero(set, newbound) || SCIPsetIsEQ(set, newbound, 1.0)
7656 || SCIPsetIsEQ(set, newbound, var->locdom.ub)))
7658 || SCIPsetIsEQ(set, newbound, var->locdom.ub)))
7660
7661 /* check that the bound is feasible */
7662 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsLE(set, newbound, var->glbdom.ub));
7663 /* adjust bound to integral value if variable is of integral type */
7664 newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
7665
7667 {
7668 /* we do not want to exceed the upper bound, which could have happened due to numerics */
7669 newbound = MIN(newbound, var->locdom.ub);
7670
7671 /* we do not want to undercut the global lower bound, which could have happened due to numerics */
7672 newbound = MAX(newbound, var->glbdom.lb);
7673 }
7675
7676 SCIPsetDebugMsg(set, "process changing lower bound of <%s> from %g to %g\n", var->name, var->locdom.lb, newbound);
7677
7678 if( SCIPsetIsEQ(set, newbound, var->glbdom.lb) && var->glbdom.lb != var->locdom.lb ) /*lint !e777*/
7679 newbound = var->glbdom.lb;
7680 else if( SCIPsetIsEQ(set, newbound, var->locdom.lb) && !(newbound != var->locdom.lb && newbound * var->locdom.lb <= 0.0) ) /*lint !e777*/
7681 return SCIP_OKAY;
7682
7683 /* change the bound */
7684 oldbound = var->locdom.lb;
7685 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasLE(set, newbound, var->locdom.ub));
7686 var->locdom.lb = newbound;
7687
7688 /* update statistic; during the update steps of the parent variable we pass a NULL pointer to ensure that we only
7689 * once update the statistic
7690 */
7691 if( stat != NULL )
7692 SCIPstatIncrement(stat, set, domchgcount);
7693
7695 {
7696 /* merges overlapping holes into single holes, moves bounds respectively */
7697 domMerge(&var->locdom, blkmem, set, &newbound, NULL);
7698 }
7699
7700 /* issue bound change event */
7701 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
7703 {
7704 SCIP_CALL( varEventLbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
7705 }
7706
7707 /* process parent variables */
7708 for( i = 0; i < var->nparentvars; ++i )
7709 {
7710 parentvar = var->parentvars[i];
7711 assert(parentvar != NULL);
7712
7713 switch( SCIPvarGetStatus(parentvar) )
7714 {
7716 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, newbound) );
7717 break;
7718
7723 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
7724 return SCIP_INVALIDDATA;
7725
7726 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7727 assert(parentvar->data.aggregate.var == var);
7728 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
7729 {
7730 SCIP_Real parentnewbound;
7731
7732 /* a > 0 -> change lower bound of y */
7733 assert(SCIPsetIsInfinity(set, -parentvar->locdom.lb) || SCIPsetIsInfinity(set, -oldbound)
7734 || SCIPsetIsFeasEQ(set, parentvar->locdom.lb, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
7735 || (SCIPsetIsZero(set, parentvar->locdom.lb / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
7736
7737 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7738 {
7739 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7740 /* if parent's new lower bound exceeds its upper bound, then this could be due to numerical difficulties, e.g., if numbers are large
7741 * thus, at least a relative comparision of the new lower bound and the current upper bound should proof consistency
7742 * as a result, the parent's lower bound is set to it's upper bound, and not above
7743 */
7744 if( parentnewbound > parentvar->glbdom.ub )
7745 {
7746 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7747 assert(SCIPsetIsFeasLE(set, parentnewbound, parentvar->glbdom.ub));
7748 parentnewbound = parentvar->glbdom.ub;
7749 }
7750 }
7751 else
7752 parentnewbound = newbound;
7753 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7754 }
7755 else
7756 {
7757 SCIP_Real parentnewbound;
7758
7759 /* a < 0 -> change upper bound of y */
7760 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
7761 assert(SCIPsetIsInfinity(set, parentvar->locdom.ub) || SCIPsetIsInfinity(set, -oldbound)
7762 || SCIPsetIsFeasEQ(set, parentvar->locdom.ub, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
7763 || (SCIPsetIsZero(set, parentvar->locdom.ub / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
7764
7765 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7766 {
7767 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7768 /* 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
7769 * thus, at least a relative comparision of the new upper bound and the current lower bound should proof consistency
7770 * as a result, the parent's upper bound is set to it's lower bound, and not below
7771 */
7772 if( parentnewbound < parentvar->glbdom.lb )
7773 {
7774 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7775 assert(SCIPsetIsFeasGE(set, parentnewbound, parentvar->glbdom.lb));
7776 parentnewbound = parentvar->glbdom.lb;
7777 }
7778 }
7779 else
7780 parentnewbound = -newbound;
7781 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7782 }
7783 break;
7784
7785 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
7786 assert(parentvar->negatedvar != NULL);
7787 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
7788 assert(parentvar->negatedvar->negatedvar == parentvar);
7789 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue,
7790 parentvar->data.negate.constant - newbound) );
7791 break;
7792
7793 default:
7794 SCIPerrorMessage("unknown variable status\n");
7795 return SCIP_INVALIDDATA;
7796 }
7797 }
7798
7799 return SCIP_OKAY;
7800}
7801
7802/** performs the current change in upper bound, changes all parents accordingly */
7803static
7805 SCIP_VAR* var, /**< problem variable to change */
7806 BMS_BLKMEM* blkmem, /**< block memory */
7807 SCIP_SET* set, /**< global SCIP settings */
7808 SCIP_STAT* stat, /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7809 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7810 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7811 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7812 SCIP_Real newbound /**< new bound for variable */
7813 )
7814{
7815 SCIP_VAR* parentvar;
7816 SCIP_Real oldbound;
7817 int i;
7818
7819 assert(var != NULL);
7820 assert(set != NULL);
7821 assert(var->scip == set->scip);
7822 assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && (SCIPsetIsZero(set, newbound) || SCIPsetIsEQ(set, newbound, 1.0)
7823 || SCIPsetIsEQ(set, newbound, var->locdom.lb)))
7825 || SCIPsetIsEQ(set, newbound, var->locdom.lb)))
7827
7828 /* check that the bound is feasible */
7829 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsGE(set, newbound, var->glbdom.lb));
7830 /* adjust bound to integral value if variable is of integral type */
7831 newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
7832
7834 {
7835 /* we do not want to undercut the lower bound, which could have happened due to numerics */
7836 newbound = MAX(newbound, var->locdom.lb);
7837
7838 /* we do not want to exceed the global upper bound, which could have happened due to numerics */
7839 newbound = MIN(newbound, var->glbdom.ub);
7840 }
7842
7843 SCIPsetDebugMsg(set, "process changing upper bound of <%s> from %g to %g\n", var->name, var->locdom.ub, newbound);
7844
7845 if( SCIPsetIsEQ(set, newbound, var->glbdom.ub) && var->glbdom.ub != var->locdom.ub ) /*lint !e777*/
7846 newbound = var->glbdom.ub;
7847 else if( SCIPsetIsEQ(set, newbound, var->locdom.ub) && !(newbound != var->locdom.ub && newbound * var->locdom.ub <= 0.0) ) /*lint !e777*/
7848 return SCIP_OKAY;
7849
7850 /* change the bound */
7851 oldbound = var->locdom.ub;
7852 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasGE(set, newbound, var->locdom.lb));
7853 var->locdom.ub = newbound;
7854
7855 /* update statistic; during the update steps of the parent variable we pass a NULL pointer to ensure that we only
7856 * once update the statistic
7857 */
7858 if( stat != NULL )
7859 SCIPstatIncrement(stat, set, domchgcount);
7860
7862 {
7863 /* merges overlapping holes into single holes, moves bounds respectively */
7864 domMerge(&var->locdom, blkmem, set, NULL, &newbound);
7865 }
7866
7867 /* issue bound change event */
7868 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
7870 {
7871 SCIP_CALL( varEventUbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
7872 }
7873
7874 /* process parent variables */
7875 for( i = 0; i < var->nparentvars; ++i )
7876 {
7877 parentvar = var->parentvars[i];
7878 assert(parentvar != NULL);
7879
7880 switch( SCIPvarGetStatus(parentvar) )
7881 {
7883 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, newbound) );
7884 break;
7885
7890 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
7891 return SCIP_INVALIDDATA;
7892
7893 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
7894 assert(parentvar->data.aggregate.var == var);
7895 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
7896 {
7897 SCIP_Real parentnewbound;
7898
7899 /* a > 0 -> change upper bound of x */
7900 assert(SCIPsetIsInfinity(set, parentvar->locdom.ub) || SCIPsetIsInfinity(set, oldbound)
7901 || SCIPsetIsFeasEQ(set, parentvar->locdom.ub,
7902 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7903 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7904 {
7905 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7906 /* 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
7907 * thus, at least a relative comparision of the new upper bound and the current lower bound should proof consistency
7908 * as a result, the parent's upper bound is set to it's lower bound, and not below
7909 */
7910 if( parentnewbound < parentvar->glbdom.lb )
7911 {
7912 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7913 assert(SCIPsetIsFeasGE(set, parentnewbound, parentvar->glbdom.lb));
7914 parentnewbound = parentvar->glbdom.lb;
7915 }
7916 }
7917 else
7918 parentnewbound = newbound;
7919 SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7920 }
7921 else
7922 {
7923 SCIP_Real parentnewbound;
7924
7925 /* a < 0 -> change lower bound of x */
7926 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
7927 assert(SCIPsetIsInfinity(set, -parentvar->locdom.lb) || SCIPsetIsInfinity(set, oldbound)
7928 || SCIPsetIsFeasEQ(set, parentvar->locdom.lb,
7929 oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7930 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7931 {
7932 parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7933 /* if parent's new lower bound exceeds its upper bound, then this could be due to numerical difficulties, e.g., if numbers are large
7934 * thus, at least a relative comparision of the new lower bound and the current upper bound should proof consistency
7935 * as a result, the parent's lower bound is set to it's upper bound, and not above
7936 */
7937 if( parentnewbound > parentvar->glbdom.ub )
7938 {
7939 /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7940 assert(SCIPsetIsFeasLE(set, parentnewbound, parentvar->glbdom.ub));
7941 parentnewbound = parentvar->glbdom.ub;
7942 }
7943 }
7944 else
7945 parentnewbound = -newbound;
7946 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7947 }
7948 break;
7949
7950 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
7951 assert(parentvar->negatedvar != NULL);
7952 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
7953 assert(parentvar->negatedvar->negatedvar == parentvar);
7954 SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue,
7955 parentvar->data.negate.constant - newbound) );
7956 break;
7957
7958 default:
7959 SCIPerrorMessage("unknown variable status\n");
7960 return SCIP_INVALIDDATA;
7961 }
7962 }
7963
7964 return SCIP_OKAY;
7965}
7966
7967/** changes current local lower bound of variable; if possible, adjusts bound to integral value; stores inference
7968 * information in variable
7969 */
7971 SCIP_VAR* var, /**< problem variable to change */
7972 BMS_BLKMEM* blkmem, /**< block memory */
7973 SCIP_SET* set, /**< global SCIP settings */
7974 SCIP_STAT* stat, /**< problem statistics */
7975 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
7976 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
7977 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
7978 SCIP_Real newbound /**< new bound for variable */
7979 )
7980{
7981 assert(var != NULL);
7982 assert(blkmem != NULL);
7983 assert(set != NULL);
7984 assert(var->scip == set->scip);
7985
7986 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7987 * of the domain within feastol
7988 */
7989 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->locdom.ub));
7990
7991 /* adjust bound to integral value if variable is of integral type */
7992 newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
7993
7994 /* check that the adjusted bound is feasible */
7995 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->locdom.ub));
7996
7998 {
7999 /* we do not want to exceed the upperbound, which could have happened due to numerics */
8000 newbound = MIN(newbound, var->locdom.ub);
8001 }
8003
8004 SCIPsetDebugMsg(set, "changing lower bound of <%s>[%g,%g] to %g\n", var->name, var->locdom.lb, var->locdom.ub, newbound);
8005
8006 if( SCIPsetIsEQ(set, var->locdom.lb, newbound) && (!SCIPsetIsEQ(set, var->glbdom.lb, newbound) || var->locdom.lb == newbound) /*lint !e777*/
8007 && !(newbound != var->locdom.lb && newbound * var->locdom.lb <= 0.0) ) /*lint !e777*/
8008 return SCIP_OKAY;
8009
8010 /* change bounds of attached variables */
8011 switch( SCIPvarGetStatus(var) )
8012 {
8014 if( var->data.original.transvar != NULL )
8015 {
8016 SCIP_CALL( SCIPvarChgLbLocal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue,
8017 newbound) );
8018 }
8019 else
8020 {
8021 assert(set->stage == SCIP_STAGE_PROBLEM);
8022 SCIP_CALL( varProcessChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
8023 }
8024 break;
8025
8028 SCIP_CALL( varProcessChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
8029 break;
8030
8032 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
8033 return SCIP_INVALIDDATA;
8034
8035 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8036 assert(var->data.aggregate.var != NULL);
8038 {
8039 SCIP_Real childnewbound;
8040
8041 /* a > 0 -> change lower bound of y */
8043 || SCIPsetIsFeasEQ(set, var->locdom.lb,
8045 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8046 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8047 else
8048 childnewbound = newbound;
8049 SCIP_CALL( SCIPvarChgLbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
8050 childnewbound) );
8051 }
8052 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8053 {
8054 SCIP_Real childnewbound;
8055
8056 /* a < 0 -> change upper bound of y */
8058 || SCIPsetIsFeasEQ(set, var->locdom.lb,
8060 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8061 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8062 else
8063 childnewbound = -newbound;
8064 SCIP_CALL( SCIPvarChgUbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
8065 childnewbound) );
8066 }
8067 else
8068 {
8069 SCIPerrorMessage("scalar is zero in aggregation\n");
8070 return SCIP_INVALIDDATA;
8071 }
8072 break;
8073
8075 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
8076 return SCIP_INVALIDDATA;
8077
8078 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8079 assert(var->negatedvar != NULL);
8081 assert(var->negatedvar->negatedvar == var);
8082 SCIP_CALL( SCIPvarChgUbLocal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue,
8083 var->data.negate.constant - newbound) );
8084 break;
8085
8086 default:
8087 SCIPerrorMessage("unknown variable status\n");
8088 return SCIP_INVALIDDATA;
8089 }
8090
8091 return SCIP_OKAY;
8092}
8093
8094/** changes current local upper bound of variable; if possible, adjusts bound to integral value; stores inference
8095 * information in variable
8096 */
8098 SCIP_VAR* var, /**< problem variable to change */
8099 BMS_BLKMEM* blkmem, /**< block memory */
8100 SCIP_SET* set, /**< global SCIP settings */
8101 SCIP_STAT* stat, /**< problem statistics */
8102 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
8103 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
8104 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8105 SCIP_Real newbound /**< new bound for variable */
8106 )
8107{
8108 assert(var != NULL);
8109 assert(blkmem != NULL);
8110 assert(set != NULL);
8111 assert(var->scip == set->scip);
8112
8113 /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
8114 * of the domain within feastol
8115 */
8116 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->locdom.lb));
8117
8118 /* adjust bound to integral value if variable is of integral type */
8119 newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
8120
8121 /* check that the adjusted bound is feasible */
8122 assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->locdom.lb));
8123
8125 {
8126 /* we do not want to undercut the lowerbound, which could have happened due to numerics */
8127 newbound = MAX(newbound, var->locdom.lb);
8128 }
8130
8131 SCIPsetDebugMsg(set, "changing upper bound of <%s>[%g,%g] to %g\n", var->name, var->locdom.lb, var->locdom.ub, newbound);
8132
8133 if( SCIPsetIsEQ(set, var->locdom.ub, newbound) && (!SCIPsetIsEQ(set, var->glbdom.ub, newbound) || var->locdom.ub == newbound) /*lint !e777*/
8134 && !(newbound != var->locdom.ub && newbound * var->locdom.ub <= 0.0) ) /*lint !e777*/
8135 return SCIP_OKAY;
8136
8137 /* change bounds of attached variables */
8138 switch( SCIPvarGetStatus(var) )
8139 {
8141 if( var->data.original.transvar != NULL )
8142 {
8143 SCIP_CALL( SCIPvarChgUbLocal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
8144 }
8145 else
8146 {
8147 assert(set->stage == SCIP_STAGE_PROBLEM);
8148 SCIP_CALL( varProcessChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
8149 }
8150 break;
8151
8154 SCIP_CALL( varProcessChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
8155 break;
8156
8158 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
8159 return SCIP_INVALIDDATA;
8160
8161 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8162 assert(var->data.aggregate.var != NULL);
8164 {
8165 SCIP_Real childnewbound;
8166
8167 /* a > 0 -> change upper bound of y */
8169 || SCIPsetIsFeasEQ(set, var->locdom.ub,
8171 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8172 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8173 else
8174 childnewbound = newbound;
8175 SCIP_CALL( SCIPvarChgUbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
8176 childnewbound) );
8177 }
8178 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8179 {
8180 SCIP_Real childnewbound;
8181
8182 /* a < 0 -> change lower bound of y */
8184 || SCIPsetIsFeasEQ(set, var->locdom.ub,
8186 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8187 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8188 else
8189 childnewbound = -newbound;
8190 SCIP_CALL( SCIPvarChgLbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
8191 childnewbound) );
8192 }
8193 else
8194 {
8195 SCIPerrorMessage("scalar is zero in aggregation\n");
8196 return SCIP_INVALIDDATA;
8197 }
8198 break;
8199
8201 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
8202 return SCIP_INVALIDDATA;
8203
8204 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8205 assert(var->negatedvar != NULL);
8207 assert(var->negatedvar->negatedvar == var);
8208 SCIP_CALL( SCIPvarChgLbLocal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue,
8209 var->data.negate.constant - newbound) );
8210 break;
8211
8212 default:
8213 SCIPerrorMessage("unknown variable status\n");
8214 return SCIP_INVALIDDATA;
8215 }
8216
8217 return SCIP_OKAY;
8218}
8219
8220/** changes current local bound of variable; if possible, adjusts bound to integral value; stores inference
8221 * information in variable
8222 */
8224 SCIP_VAR* var, /**< problem variable to change */
8225 BMS_BLKMEM* blkmem, /**< block memory */
8226 SCIP_SET* set, /**< global SCIP settings */
8227 SCIP_STAT* stat, /**< problem statistics */
8228 SCIP_LP* lp, /**< current LP data, may be NULL for original variables */
8229 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage, may be NULL for original variables */
8230 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8231 SCIP_Real newbound, /**< new bound for variable */
8232 SCIP_BOUNDTYPE boundtype /**< type of bound: lower or upper bound */
8233 )
8234{
8235 /* apply bound change to the LP data */
8236 switch( boundtype )
8237 {
8239 return SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound);
8241 return SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound);
8242 default:
8243 SCIPerrorMessage("unknown bound type\n");
8244 return SCIP_INVALIDDATA;
8245 }
8246}
8247
8248/** changes lower bound of variable in current dive; if possible, adjusts bound to integral value */
8250 SCIP_VAR* var, /**< problem variable to change */
8251 SCIP_SET* set, /**< global SCIP settings */
8252 SCIP_LP* lp, /**< current LP data */
8253 SCIP_Real newbound /**< new bound for variable */
8254 )
8255{
8256 assert(var != NULL);
8257 assert(set != NULL);
8258 assert(var->scip == set->scip);
8259 assert(lp != NULL);
8260 assert(SCIPlpDiving(lp));
8261
8262 /* adjust bound for integral variables */
8263 SCIPvarAdjustLb(var, set, &newbound);
8264
8265 SCIPsetDebugMsg(set, "changing lower bound of <%s> to %g in current dive\n", var->name, newbound);
8266
8267 /* change bounds of attached variables */
8268 switch( SCIPvarGetStatus(var) )
8269 {
8271 assert(var->data.original.transvar != NULL);
8272 SCIP_CALL( SCIPvarChgLbDive(var->data.original.transvar, set, lp, newbound) );
8273 break;
8274
8276 assert(var->data.col != NULL);
8277 SCIP_CALL( SCIPcolChgLb(var->data.col, set, lp, newbound) );
8278 break;
8279
8281 SCIPerrorMessage("cannot change variable's bounds in dive for LOOSE variables\n");
8282 return SCIP_INVALIDDATA;
8283
8285 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
8286 return SCIP_INVALIDDATA;
8287
8288 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8289 assert(var->data.aggregate.var != NULL);
8291 {
8292 SCIP_Real childnewbound;
8293
8294 /* a > 0 -> change lower bound of y */
8295 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8296 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8297 else
8298 childnewbound = newbound;
8299 SCIP_CALL( SCIPvarChgLbDive(var->data.aggregate.var, set, lp, childnewbound) );
8300 }
8301 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8302 {
8303 SCIP_Real childnewbound;
8304
8305 /* a < 0 -> change upper bound of y */
8306 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8307 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8308 else
8309 childnewbound = -newbound;
8310 SCIP_CALL( SCIPvarChgUbDive(var->data.aggregate.var, set, lp, childnewbound) );
8311 }
8312 else
8313 {
8314 SCIPerrorMessage("scalar is zero in aggregation\n");
8315 return SCIP_INVALIDDATA;
8316 }
8317 break;
8318
8320 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
8321 return SCIP_INVALIDDATA;
8322
8323 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8324 assert(var->negatedvar != NULL);
8326 assert(var->negatedvar->negatedvar == var);
8327 SCIP_CALL( SCIPvarChgUbDive(var->negatedvar, set, lp, var->data.negate.constant - newbound) );
8328 break;
8329
8330 default:
8331 SCIPerrorMessage("unknown variable status\n");
8332 return SCIP_INVALIDDATA;
8333 }
8334
8335 return SCIP_OKAY;
8336}
8337
8338/** changes upper bound of variable in current dive; if possible, adjusts bound to integral value */
8340 SCIP_VAR* var, /**< problem variable to change */
8341 SCIP_SET* set, /**< global SCIP settings */
8342 SCIP_LP* lp, /**< current LP data */
8343 SCIP_Real newbound /**< new bound for variable */
8344 )
8345{
8346 assert(var != NULL);
8347 assert(set != NULL);
8348 assert(var->scip == set->scip);
8349 assert(lp != NULL);
8350 assert(SCIPlpDiving(lp));
8351
8352 /* adjust bound for integral variables */
8353 SCIPvarAdjustUb(var, set, &newbound);
8354
8355 SCIPsetDebugMsg(set, "changing upper bound of <%s> to %g in current dive\n", var->name, newbound);
8356
8357 /* change bounds of attached variables */
8358 switch( SCIPvarGetStatus(var) )
8359 {
8361 assert(var->data.original.transvar != NULL);
8362 SCIP_CALL( SCIPvarChgUbDive(var->data.original.transvar, set, lp, newbound) );
8363 break;
8364
8366 assert(var->data.col != NULL);
8367 SCIP_CALL( SCIPcolChgUb(var->data.col, set, lp, newbound) );
8368 break;
8369
8371 SCIPerrorMessage("cannot change variable's bounds in dive for LOOSE variables\n");
8372 return SCIP_INVALIDDATA;
8373
8375 SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
8376 return SCIP_INVALIDDATA;
8377
8378 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8379 assert(var->data.aggregate.var != NULL);
8381 {
8382 SCIP_Real childnewbound;
8383
8384 /* a > 0 -> change upper bound of y */
8385 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8386 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8387 else
8388 childnewbound = newbound;
8389 SCIP_CALL( SCIPvarChgUbDive(var->data.aggregate.var, set, lp, childnewbound) );
8390 }
8391 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8392 {
8393 SCIP_Real childnewbound;
8394
8395 /* a < 0 -> change lower bound of y */
8396 if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8397 childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8398 else
8399 childnewbound = -newbound;
8400 SCIP_CALL( SCIPvarChgLbDive(var->data.aggregate.var, set, lp, childnewbound) );
8401 }
8402 else
8403 {
8404 SCIPerrorMessage("scalar is zero in aggregation\n");
8405 return SCIP_INVALIDDATA;
8406 }
8407 break;
8408
8410 SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
8411 return SCIP_INVALIDDATA;
8412
8413 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8414 assert(var->negatedvar != NULL);
8416 assert(var->negatedvar->negatedvar == var);
8417 SCIP_CALL( SCIPvarChgLbDive(var->negatedvar, set, lp, var->data.negate.constant - newbound) );
8418 break;
8419
8420 default:
8421 SCIPerrorMessage("unknown variable status\n");
8422 return SCIP_INVALIDDATA;
8423 }
8424
8425 return SCIP_OKAY;
8426}
8427
8428/** for a multi-aggregated variable, gives the local lower bound computed by adding the local bounds from all
8429 * aggregation variables, this lower bound may be tighter than the one given by SCIPvarGetLbLocal, since the latter is
8430 * not updated if bounds of aggregation variables are changing
8431 *
8432 * calling this function for a non-multi-aggregated variable is not allowed
8433 */
8435 SCIP_VAR* var, /**< problem variable */
8436 SCIP_SET* set /**< global SCIP settings */
8437 )
8438{
8439 int i;
8440 SCIP_Real lb;
8441 SCIP_Real bnd;
8442 SCIP_VAR* aggrvar;
8443 SCIP_Bool posinf;
8444 SCIP_Bool neginf;
8445
8446 assert(var != NULL);
8447 assert(set != NULL);
8448 assert(var->scip == set->scip);
8450
8451 posinf = FALSE;
8452 neginf = FALSE;
8453 lb = var->data.multaggr.constant;
8454 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8455 {
8456 aggrvar = var->data.multaggr.vars[i];
8457 if( var->data.multaggr.scalars[i] > 0.0 )
8458 {
8460
8461 if( SCIPsetIsInfinity(set, bnd) )
8462 posinf = TRUE;
8463 else if( SCIPsetIsInfinity(set, -bnd) )
8464 neginf = TRUE;
8465 else
8466 lb += var->data.multaggr.scalars[i] * bnd;
8467 }
8468 else
8469 {
8471
8472 if( SCIPsetIsInfinity(set, -bnd) )
8473 posinf = TRUE;
8474 else if( SCIPsetIsInfinity(set, bnd) )
8475 neginf = TRUE;
8476 else
8477 lb += var->data.multaggr.scalars[i] * bnd;
8478 }
8479
8480 /* stop if two diffrent infinities (or a -infinity) were found and return local lower bound of multi aggregated
8481 * variable
8482 */
8483 if( neginf )
8484 return SCIPvarGetLbLocal(var);
8485 }
8486
8487 /* if positive infinity flag was set to true return infinity */
8488 if( posinf )
8489 return SCIPsetInfinity(set);
8490
8491 return (MAX(lb, SCIPvarGetLbLocal(var))); /*lint !e666*/
8492}
8493
8494/** for a multi-aggregated variable, gives the local upper bound computed by adding the local bounds from all
8495 * aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbLocal, since the latter is
8496 * not updated if bounds of aggregation variables are changing
8497 *
8498 * calling this function for a non-multi-aggregated variable is not allowed
8499 */
8501 SCIP_VAR* var, /**< problem variable */
8502 SCIP_SET* set /**< global SCIP settings */
8503 )
8504{
8505 int i;
8506 SCIP_Real ub;
8507 SCIP_Real bnd;
8508 SCIP_VAR* aggrvar;
8509 SCIP_Bool posinf;
8510 SCIP_Bool neginf;
8511
8512 assert(var != NULL);
8513 assert(set != NULL);
8514 assert(var->scip == set->scip);
8516
8517 posinf = FALSE;
8518 neginf = FALSE;
8519 ub = var->data.multaggr.constant;
8520 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8521 {
8522 aggrvar = var->data.multaggr.vars[i];
8523 if( var->data.multaggr.scalars[i] > 0.0 )
8524 {
8526
8527 if( SCIPsetIsInfinity(set, bnd) )
8528 posinf = TRUE;
8529 else if( SCIPsetIsInfinity(set, -bnd) )
8530 neginf = TRUE;
8531 else
8532 ub += var->data.multaggr.scalars[i] * bnd;
8533 }
8534 else
8535 {
8537
8538 if( SCIPsetIsInfinity(set, -bnd) )
8539 posinf = TRUE;
8540 else if( SCIPsetIsInfinity(set, bnd) )
8541 neginf = TRUE;
8542 else
8543 ub += var->data.multaggr.scalars[i] * bnd;
8544 }
8545
8546 /* stop if two diffrent infinities (or a -infinity) were found and return local upper bound of multi aggregated
8547 * variable
8548 */
8549 if( posinf )
8550 return SCIPvarGetUbLocal(var);
8551 }
8552
8553 /* if negative infinity flag was set to true return -infinity */
8554 if( neginf )
8555 return -SCIPsetInfinity(set);
8556
8557 return (MIN(ub, SCIPvarGetUbLocal(var))); /*lint !e666*/
8558}
8559
8560/** for a multi-aggregated variable, gives the global lower bound computed by adding the global bounds from all
8561 * aggregation variables, this global bound may be tighter than the one given by SCIPvarGetLbGlobal, since the latter is
8562 * not updated if bounds of aggregation variables are changing
8563 *
8564 * calling this function for a non-multi-aggregated variable is not allowed
8565 */
8567 SCIP_VAR* var, /**< problem variable */
8568 SCIP_SET* set /**< global SCIP settings */
8569 )
8570{
8571 int i;
8572 SCIP_Real lb;
8573 SCIP_Real bnd;
8574 SCIP_VAR* aggrvar;
8575 SCIP_Bool posinf;
8576 SCIP_Bool neginf;
8577
8578 assert(var != NULL);
8579 assert(set != NULL);
8580 assert(var->scip == set->scip);
8582
8583 posinf = FALSE;
8584 neginf = FALSE;
8585 lb = var->data.multaggr.constant;
8586 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8587 {
8588 aggrvar = var->data.multaggr.vars[i];
8589 if( var->data.multaggr.scalars[i] > 0.0 )
8590 {
8592
8593 if( SCIPsetIsInfinity(set, bnd) )
8594 posinf = TRUE;
8595 else if( SCIPsetIsInfinity(set, -bnd) )
8596 neginf = TRUE;
8597 else
8598 lb += var->data.multaggr.scalars[i] * bnd;
8599 }
8600 else
8601 {
8603
8604 if( SCIPsetIsInfinity(set, -bnd) )
8605 posinf = TRUE;
8606 else if( SCIPsetIsInfinity(set, bnd) )
8607 neginf = TRUE;
8608 else
8609 lb += var->data.multaggr.scalars[i] * bnd;
8610 }
8611
8612 /* stop if two diffrent infinities (or a -infinity) were found and return global lower bound of multi aggregated
8613 * variable
8614 */
8615 if( neginf )
8616 return SCIPvarGetLbGlobal(var);
8617 }
8618
8619 /* if positive infinity flag was set to true return infinity */
8620 if( posinf )
8621 return SCIPsetInfinity(set);
8622
8623 return (MAX(lb, SCIPvarGetLbGlobal(var))); /*lint !e666*/
8624}
8625
8626/** for a multi-aggregated variable, gives the global upper bound computed by adding the global bounds from all
8627 * aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbGlobal, since the latter is
8628 * not updated if bounds of aggregation variables are changing
8629 *
8630 * calling this function for a non-multi-aggregated variable is not allowed
8631 */
8633 SCIP_VAR* var, /**< problem variable */
8634 SCIP_SET* set /**< global SCIP settings */
8635 )
8636{
8637 int i;
8638 SCIP_Real ub;
8639 SCIP_Real bnd;
8640 SCIP_VAR* aggrvar;
8641 SCIP_Bool posinf;
8642 SCIP_Bool neginf;
8643
8644 assert(var != NULL);
8645 assert(set != NULL);
8646 assert(var->scip == set->scip);
8648
8649 posinf = FALSE;
8650 neginf = FALSE;
8651 ub = var->data.multaggr.constant;
8652 for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8653 {
8654 aggrvar = var->data.multaggr.vars[i];
8655 if( var->data.multaggr.scalars[i] > 0.0 )
8656 {
8658
8659 if( SCIPsetIsInfinity(set, bnd) )
8660 posinf = TRUE;
8661 else if( SCIPsetIsInfinity(set, -bnd) )
8662 neginf = TRUE;
8663 else
8664 ub += var->data.multaggr.scalars[i] * bnd;
8665 }
8666 else
8667 {
8669
8670 if( SCIPsetIsInfinity(set, -bnd) )
8671 posinf = TRUE;
8672 else if( SCIPsetIsInfinity(set, bnd) )
8673 neginf = TRUE;
8674 else
8675 ub += var->data.multaggr.scalars[i] * bnd;
8676 }
8677
8678 /* stop if two diffrent infinities (or a -infinity) were found and return local upper bound of multi aggregated
8679 * variable
8680 */
8681 if( posinf )
8682 return SCIPvarGetUbGlobal(var);
8683 }
8684
8685 /* if negative infinity flag was set to true return -infinity */
8686 if( neginf )
8687 return -SCIPsetInfinity(set);
8688
8689 return (MIN(ub, SCIPvarGetUbGlobal(var))); /*lint !e666*/
8690}
8691
8692/** adds a hole to the original domain of the variable */
8694 SCIP_VAR* var, /**< problem variable */
8695 BMS_BLKMEM* blkmem, /**< block memory */
8696 SCIP_SET* set, /**< global SCIP settings */
8697 SCIP_Real left, /**< left bound of open interval in new hole */
8698 SCIP_Real right /**< right bound of open interval in new hole */
8699 )
8700{
8701 SCIP_Bool added;
8702
8703 assert(var != NULL);
8704 assert(!SCIPvarIsTransformed(var));
8707 assert(set != NULL);
8708 assert(var->scip == set->scip);
8709 assert(set->stage == SCIP_STAGE_PROBLEM);
8710
8711 SCIPsetDebugMsg(set, "adding original hole (%g,%g) to <%s>\n", left, right, var->name);
8712
8713 if( SCIPsetIsEQ(set, left, right) )
8714 return SCIP_OKAY;
8715
8716 /* the interval should not be empty */
8717 assert(SCIPsetIsLT(set, left, right));
8718
8719 /* the the interval bound should already be adjusted */
8720 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8721 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8722
8723 /* the the interval should lay between the lower and upper bound */
8724 assert(SCIPsetIsGE(set, left, SCIPvarGetLbOriginal(var)));
8725 assert(SCIPsetIsLE(set, right, SCIPvarGetUbOriginal(var)));
8726
8727 /* add domain hole */
8728 SCIP_CALL( domAddHole(&var->data.original.origdom, blkmem, set, left, right, &added) );
8729
8730 /* merges overlapping holes into single holes, moves bounds respectively if hole was added */
8731 if( added )
8732 {
8733 domMerge(&var->data.original.origdom, blkmem, set, NULL, NULL);
8734 }
8735
8736 /**@todo add hole in parent and child variables (just like with bound changes);
8737 * warning! original vars' holes are in original blkmem, transformed vars' holes in transformed blkmem
8738 */
8739
8740 return SCIP_OKAY;
8741}
8742
8743/** performs the current add of domain, changes all parents accordingly */
8744static
8746 SCIP_VAR* var, /**< problem variable */
8747 BMS_BLKMEM* blkmem, /**< block memory */
8748 SCIP_SET* set, /**< global SCIP settings */
8749 SCIP_STAT* stat, /**< problem statistics */
8750 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8751 SCIP_Real left, /**< left bound of open interval in new hole */
8752 SCIP_Real right, /**< right bound of open interval in new hole */
8753 SCIP_Bool* added /**< pointer to store whether the hole was added */
8754 )
8755{
8756 SCIP_VAR* parentvar;
8757 SCIP_Real newlb;
8758 SCIP_Real newub;
8759 int i;
8760
8761 assert(var != NULL);
8762 assert(added != NULL);
8763 assert(blkmem != NULL);
8764
8765 /* the interval should not be empty */
8766 assert(SCIPsetIsLT(set, left, right));
8767
8768 /* the interval bound should already be adjusted */
8769 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8770 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8771
8772 /* the interval should lay between the lower and upper bound */
8773 assert(SCIPsetIsGE(set, left, SCIPvarGetLbGlobal(var)));
8774 assert(SCIPsetIsLE(set, right, SCIPvarGetUbGlobal(var)));
8775
8776 /* @todo add debugging mechanism for holes when using a debugging solution */
8777
8778 /* add hole to hole list */
8779 SCIP_CALL( domAddHole(&var->glbdom, blkmem, set, left, right, added) );
8780
8781 /* check if the hole is redundant */
8782 if( !(*added) )
8783 return SCIP_OKAY;
8784
8785 /* current bounds */
8786 newlb = var->glbdom.lb;
8787 newub = var->glbdom.ub;
8788
8789 /* merge domain holes */
8790 domMerge(&var->glbdom, blkmem, set, &newlb, &newub);
8791
8792 /* the bound should not be changed */
8793 assert(SCIPsetIsEQ(set, newlb, var->glbdom.lb));
8794 assert(SCIPsetIsEQ(set, newub, var->glbdom.ub));
8795
8796 /* issue bound change event */
8797 assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
8798 if( var->eventfilter != NULL )
8799 {
8800 SCIP_CALL( varEventGholeAdded(var, blkmem, set, eventqueue, left, right) );
8801 }
8802
8803 /* process parent variables */
8804 for( i = 0; i < var->nparentvars; ++i )
8805 {
8806 SCIP_Real parentnewleft;
8807 SCIP_Real parentnewright;
8808 SCIP_Bool localadded;
8809
8810 parentvar = var->parentvars[i];
8811 assert(parentvar != NULL);
8812
8813 switch( SCIPvarGetStatus(parentvar) )
8814 {
8816 parentnewleft = left;
8817 parentnewright = right;
8818 break;
8819
8824 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
8825 return SCIP_INVALIDDATA;
8826
8827 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8828 assert(parentvar->data.aggregate.var == var);
8829
8830 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
8831 {
8832 /* a > 0 -> change upper bound of x */
8833 parentnewleft = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8834 parentnewright = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8835 }
8836 else
8837 {
8838 /* a < 0 -> change lower bound of x */
8839 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
8840
8841 parentnewright = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8842 parentnewleft = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8843 }
8844 break;
8845
8846 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
8847 assert(parentvar->negatedvar != NULL);
8848 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
8849 assert(parentvar->negatedvar->negatedvar == parentvar);
8850
8851 parentnewright = -left + parentvar->data.negate.constant;
8852 parentnewleft = -right + parentvar->data.negate.constant;
8853 break;
8854
8855 default:
8856 SCIPerrorMessage("unknown variable status\n");
8857 return SCIP_INVALIDDATA;
8858 }
8859
8860 SCIPsetDebugMsg(set, "add global hole (%g,%g) to parent variable <%s>\n", parentnewleft, parentnewright, SCIPvarGetName(parentvar));
8861
8862 /* perform hole added for parent variable */
8863 assert(blkmem != NULL);
8864 assert(SCIPsetIsLT(set, parentnewleft, parentnewright));
8865 SCIP_CALL( varProcessAddHoleGlobal(parentvar, blkmem, set, stat, eventqueue,
8866 parentnewleft, parentnewright, &localadded) );
8867 assert(localadded);
8868 }
8869
8870 return SCIP_OKAY;
8871}
8872
8873/** adds a hole to the variable's global and local domain */
8875 SCIP_VAR* var, /**< problem variable */
8876 BMS_BLKMEM* blkmem, /**< block memory */
8877 SCIP_SET* set, /**< global SCIP settings */
8878 SCIP_STAT* stat, /**< problem statistics */
8879 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8880 SCIP_Real left, /**< left bound of open interval in new hole */
8881 SCIP_Real right, /**< right bound of open interval in new hole */
8882 SCIP_Bool* added /**< pointer to store whether the hole was added */
8883 )
8884{
8885 SCIP_Real childnewleft;
8886 SCIP_Real childnewright;
8887
8888 assert(var != NULL);
8890 assert(blkmem != NULL);
8891 assert(added != NULL);
8892
8893 SCIPsetDebugMsg(set, "adding global hole (%g,%g) to <%s>\n", left, right, var->name);
8894
8895 /* the interval should not be empty */
8896 assert(SCIPsetIsLT(set, left, right));
8897
8898 /* the the interval bound should already be adjusted */
8899 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8900 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8901
8902 /* the the interval should lay between the lower and upper bound */
8903 assert(SCIPsetIsGE(set, left, SCIPvarGetLbGlobal(var)));
8904 assert(SCIPsetIsLE(set, right, SCIPvarGetUbGlobal(var)));
8905
8906 /* change bounds of attached variables */
8907 switch( SCIPvarGetStatus(var) )
8908 {
8910 if( var->data.original.transvar != NULL )
8911 {
8912 SCIP_CALL( SCIPvarAddHoleGlobal(var->data.original.transvar, blkmem, set, stat, eventqueue,
8913 left, right, added) );
8914 }
8915 else
8916 {
8917 assert(set->stage == SCIP_STAGE_PROBLEM);
8918
8919 SCIP_CALL( varProcessAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) );
8920 if( *added )
8921 {
8922 SCIP_Bool localadded;
8923
8924 SCIP_CALL( SCIPvarAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, &localadded) );
8925 }
8926 }
8927 break;
8928
8931 SCIP_CALL( varProcessAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) );
8932 if( *added )
8933 {
8934 SCIP_Bool localadded;
8935
8936 SCIP_CALL( SCIPvarAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, &localadded) );
8937 }
8938 break;
8939
8941 SCIPerrorMessage("cannot add hole of a fixed variable\n");
8942 return SCIP_INVALIDDATA;
8943
8944 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
8945 assert(var->data.aggregate.var != NULL);
8946
8948 {
8949 /* a > 0 -> change lower bound of y */
8950 childnewleft = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
8951 childnewright = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
8952 }
8953 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8954 {
8955 childnewright = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
8956 childnewleft = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
8957 }
8958 else
8959 {
8960 SCIPerrorMessage("scalar is zero in aggregation\n");
8961 return SCIP_INVALIDDATA;
8962 }
8963 SCIP_CALL( SCIPvarAddHoleGlobal(var->data.aggregate.var, blkmem, set, stat, eventqueue,
8964 childnewleft, childnewright, added) );
8965 break;
8966
8968 SCIPerrorMessage("cannot add a hole of a multi-aggregated variable.\n");
8969 return SCIP_INVALIDDATA;
8970
8971 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
8972 assert(var->negatedvar != NULL);
8974 assert(var->negatedvar->negatedvar == var);
8975
8976 childnewright = -left + var->data.negate.constant;
8977 childnewleft = -right + var->data.negate.constant;
8978
8979 SCIP_CALL( SCIPvarAddHoleGlobal(var->negatedvar, blkmem, set, stat, eventqueue,
8980 childnewleft, childnewright, added) );
8981 break;
8982
8983 default:
8984 SCIPerrorMessage("unknown variable status\n");
8985 return SCIP_INVALIDDATA;
8986 }
8987
8988 return SCIP_OKAY;
8989}
8990
8991/** performs the current add of domain, changes all parents accordingly */
8992static
8994 SCIP_VAR* var, /**< problem variable */
8995 BMS_BLKMEM* blkmem, /**< block memory */
8996 SCIP_SET* set, /**< global SCIP settings */
8997 SCIP_STAT* stat, /**< problem statistics */
8998 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
8999 SCIP_Real left, /**< left bound of open interval in new hole */
9000 SCIP_Real right, /**< right bound of open interval in new hole */
9001 SCIP_Bool* added /**< pointer to store whether the hole was added, or NULL */
9002 )
9003{
9004 SCIP_VAR* parentvar;
9005 SCIP_Real newlb;
9006 SCIP_Real newub;
9007 int i;
9008
9009 assert(var != NULL);
9010 assert(added != NULL);
9011 assert(blkmem != NULL);
9012
9013 /* the interval should not be empty */
9014 assert(SCIPsetIsLT(set, left, right));
9015
9016 /* the the interval bound should already be adjusted */
9017 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
9018 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
9019
9020 /* the the interval should lay between the lower and upper bound */
9021 assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
9022 assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
9023
9024 /* add hole to hole list */
9025 SCIP_CALL( domAddHole(&var->locdom, blkmem, set, left, right, added) );
9026
9027 /* check if the hole is redundant */
9028 if( !(*added) )
9029 return SCIP_OKAY;
9030
9031 /* current bounds */
9032 newlb = var->locdom.lb;
9033 newub = var->locdom.ub;
9034
9035 /* merge domain holes */
9036 domMerge(&var->locdom, blkmem, set, &newlb, &newub);
9037
9038 /* the bound should not be changed */
9039 assert(SCIPsetIsEQ(set, newlb, var->locdom.lb));
9040 assert(SCIPsetIsEQ(set, newub, var->locdom.ub));
9041
9042#ifdef SCIP_DISABLED_CODE
9043 /* issue LHOLEADDED event */
9044 SCIP_EVENT event;
9045 assert(var->eventfilter != NULL);
9047 SCIP_CALL( SCIPeventProcess(&event, set, NULL, NULL, NULL, var->eventfilter) );
9048#endif
9049
9050 /* process parent variables */
9051 for( i = 0; i < var->nparentvars; ++i )
9052 {
9053 SCIP_Real parentnewleft;
9054 SCIP_Real parentnewright;
9055 SCIP_Bool localadded;
9056
9057 parentvar = var->parentvars[i];
9058 assert(parentvar != NULL);
9059
9060 switch( SCIPvarGetStatus(parentvar) )
9061 {
9063 parentnewleft = left;
9064 parentnewright = right;
9065 break;
9066
9071 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
9072 return SCIP_INVALIDDATA;
9073
9074 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
9075 assert(parentvar->data.aggregate.var == var);
9076
9077 if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
9078 {
9079 /* a > 0 -> change upper bound of x */
9080 parentnewleft = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
9081 parentnewright = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
9082 }
9083 else
9084 {
9085 /* a < 0 -> change lower bound of x */
9086 assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
9087
9088 parentnewright = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
9089 parentnewleft = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
9090 }
9091 break;
9092
9093 case SCIP_VARSTATUS_NEGATED: /* x = offset - x' -> x' = offset - x */
9094 assert(parentvar->negatedvar != NULL);
9095 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
9096 assert(parentvar->negatedvar->negatedvar == parentvar);
9097
9098 parentnewright = -left + parentvar->data.negate.constant;
9099 parentnewleft = -right + parentvar->data.negate.constant;
9100 break;
9101
9102 default:
9103 SCIPerrorMessage("unknown variable status\n");
9104 return SCIP_INVALIDDATA;
9105 }
9106
9107 SCIPsetDebugMsg(set, "add local hole (%g,%g) to parent variable <%s>\n", parentnewleft, parentnewright, SCIPvarGetName(parentvar));
9108
9109 /* perform hole added for parent variable */
9110 assert(blkmem != NULL);
9111 assert(SCIPsetIsLT(set, parentnewleft, parentnewright));
9112 SCIP_CALL( varProcessAddHoleLocal(parentvar, blkmem, set, stat, eventqueue,
9113 parentnewleft, parentnewright, &localadded) );
9114 assert(localadded);
9115 }
9116
9117 return SCIP_OKAY;
9118}
9119
9120/** adds a hole to the variable's current local domain */
9122 SCIP_VAR* var, /**< problem variable */
9123 BMS_BLKMEM* blkmem, /**< block memory */
9124 SCIP_SET* set, /**< global SCIP settings */
9125 SCIP_STAT* stat, /**< problem statistics */
9126 SCIP_EVENTQUEUE* eventqueue, /**< event queue, may be NULL for original variables */
9127 SCIP_Real left, /**< left bound of open interval in new hole */
9128 SCIP_Real right, /**< right bound of open interval in new hole */
9129 SCIP_Bool* added /**< pointer to store whether the hole was added */
9130 )
9131{
9132 SCIP_Real childnewleft;
9133 SCIP_Real childnewright;
9134
9135 assert(var != NULL);
9136
9137 SCIPsetDebugMsg(set, "adding local hole (%g,%g) to <%s>\n", left, right, var->name);
9138
9139 assert(set != NULL);
9140 assert(var->scip == set->scip);
9142 assert(blkmem != NULL);
9143 assert(added != NULL);
9144
9145 /* the interval should not be empty */
9146 assert(SCIPsetIsLT(set, left, right));
9147
9148 /* the the interval bound should already be adjusted */
9149 assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
9150 assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
9151
9152 /* the the interval should lay between the lower and upper bound */
9153 assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
9154 assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
9155
9156 /* change bounds of attached variables */
9157 switch( SCIPvarGetStatus(var) )
9158 {
9160 if( var->data.original.transvar != NULL )
9161 {
9162 SCIP_CALL( SCIPvarAddHoleLocal(var->data.original.transvar, blkmem, set, stat, eventqueue,
9163 left, right, added) );
9164 }
9165 else
9166 {
9167 assert(set->stage == SCIP_STAGE_PROBLEM);
9168 SCIPstatIncrement(stat, set, domchgcount);
9169 SCIP_CALL( varProcessAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, added) );
9170 }
9171 break;
9172
9175 SCIPstatIncrement(stat, set, domchgcount);
9176 SCIP_CALL( varProcessAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, added) );
9177 break;
9178
9180 SCIPerrorMessage("cannot add domain hole to a fixed variable\n");
9181 return SCIP_INVALIDDATA;
9182
9183 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
9184 assert(var->data.aggregate.var != NULL);
9185
9187 {
9188 /* a > 0 -> change lower bound of y */
9189 childnewleft = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
9190 childnewright = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
9191 }
9192 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
9193 {
9194 childnewright = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
9195 childnewleft = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
9196 }
9197 else
9198 {
9199 SCIPerrorMessage("scalar is zero in aggregation\n");
9200 return SCIP_INVALIDDATA;
9201 }
9202 SCIP_CALL( SCIPvarAddHoleLocal(var->data.aggregate.var, blkmem, set, stat, eventqueue,
9203 childnewleft, childnewright, added) );
9204 break;
9205
9207 SCIPerrorMessage("cannot add domain hole to a multi-aggregated variable.\n");
9208 return SCIP_INVALIDDATA;
9209
9210 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
9211 assert(var->negatedvar != NULL);
9213 assert(var->negatedvar->negatedvar == var);
9214
9215 childnewright = -left + var->data.negate.constant;
9216 childnewleft = -right + var->data.negate.constant;
9217
9218 SCIP_CALL( SCIPvarAddHoleLocal(var->negatedvar, blkmem, set, stat, eventqueue, childnewleft, childnewright, added) );
9219 break;
9220
9221 default:
9222 SCIPerrorMessage("unknown variable status\n");
9223 return SCIP_INVALIDDATA;
9224 }
9225
9226 return SCIP_OKAY;
9227}
9228
9229/** resets the global and local bounds of original variable to their original values */
9231 SCIP_VAR* var, /**< problem variable */
9232 BMS_BLKMEM* blkmem, /**< block memory */
9233 SCIP_SET* set, /**< global SCIP settings */
9234 SCIP_STAT* stat /**< problem statistics */
9235 )
9236{
9237 assert(var != NULL);
9238 assert(set != NULL);
9239 assert(var->scip == set->scip);
9240 assert(SCIPvarIsOriginal(var));
9241 /* resetting of bounds on original variables which have a transformed counterpart easily fails if, e.g.,
9242 * the transformed variable has been fixed */
9243 assert(SCIPvarGetTransVar(var) == NULL);
9244
9245 /* copy the original bounds back to the global and local bounds */
9246 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, NULL, NULL, NULL, NULL, var->data.original.origdom.lb) );
9247 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, NULL, NULL, NULL, NULL, var->data.original.origdom.ub) );
9248 SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.lb) );
9249 SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.ub) );
9250
9251 /* free the global and local holelists and duplicate the original ones */
9252 /**@todo this has also to be called recursively with methods similar to SCIPvarChgLbGlobal() */
9253 holelistFree(&var->glbdom.holelist, blkmem);
9254 holelistFree(&var->locdom.holelist, blkmem);
9257
9258 return SCIP_OKAY;
9259}
9260
9261/** issues a IMPLADDED event on the given variable */
9262static
9264 SCIP_VAR* var, /**< problem variable to change */
9265 BMS_BLKMEM* blkmem, /**< block memory */
9266 SCIP_SET* set, /**< global SCIP settings */
9267 SCIP_EVENTQUEUE* eventqueue /**< event queue */
9268 )
9269{
9270 SCIP_EVENT* event;
9271
9272 assert(var != NULL);
9273
9274 /* issue IMPLADDED event on variable */
9275 SCIP_CALL( SCIPeventCreateImplAdded(&event, blkmem, var) );
9276 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
9277
9278 return SCIP_OKAY;
9279}
9280
9281/** actually performs the addition of a variable bound to the variable's vbound arrays */
9282static
9284 SCIP_VAR* var, /**< problem variable x in x <= b*z + d or x >= b*z + d */
9285 BMS_BLKMEM* blkmem, /**< block memory */
9286 SCIP_SET* set, /**< global SCIP settings */
9287 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9288 SCIP_BOUNDTYPE vbtype, /**< type of variable bound (LOWER or UPPER) */
9289 SCIP_VAR* vbvar, /**< variable z in x <= b*z + d or x >= b*z + d */
9290 SCIP_Real vbcoef, /**< coefficient b in x <= b*z + d or x >= b*z + d */
9291 SCIP_Real vbconstant /**< constant d in x <= b*z + d or x >= b*z + d */
9292 )
9293{
9294 SCIP_Bool added;
9295
9296 /* It can happen that the variable "var" and the variable "vbvar" are the same variable. For example if a variable
9297 * gets aggregated, the variable bounds (vbound) of that variable are copied to the other variable. A variable bound
9298 * variable of the aggregated variable might be the same as the one its gets aggregated too.
9299 *
9300 * If the variable "var" and the variable "vbvar" are the same, the variable bound which should be added here has to
9301 * be redundant. This is the case since an infeasibility should have be detected in the previous methods. As well as
9302 * the bounds of the variable which should be also already be tightened in the previous methods. Therefore, the
9303 * variable bound can be ignored.
9304 *
9305 * From the way the the variable bound system is implemented (detecting infeasibility, tighten bounds), the
9306 * equivalence of the variables should be checked here.
9307 */
9308 if( var == vbvar )
9309 {
9310 /* in this case the variable bound has to be redundant, this means for possible assignments to this variable; this
9311 * can be checked via the global bounds of the variable */
9312#ifndef NDEBUG
9313 SCIP_Real lb;
9314 SCIP_Real ub;
9315
9316 lb = SCIPvarGetLbGlobal(var);
9317 ub = SCIPvarGetUbGlobal(var);
9318
9319 if(vbtype == SCIP_BOUNDTYPE_LOWER)
9320 {
9321 if( vbcoef > 0.0 )
9322 {
9323 assert(SCIPsetIsGE(set, lb, lb * vbcoef + vbconstant) );
9324 assert(SCIPsetIsGE(set, ub, ub * vbcoef + vbconstant) );
9325 }
9326 else
9327 {
9328 assert(SCIPsetIsGE(set, lb, ub * vbcoef + vbconstant) );
9329 assert(SCIPsetIsGE(set, ub, lb * vbcoef + vbconstant) );
9330 }
9331 }
9332 else
9333 {
9334 assert(vbtype == SCIP_BOUNDTYPE_UPPER);
9335 if( vbcoef > 0.0 )
9336 {
9337 assert(SCIPsetIsLE(set, lb, lb * vbcoef + vbconstant) );
9338 assert(SCIPsetIsLE(set, ub, ub * vbcoef + vbconstant) );
9339 }
9340 else
9341 {
9342 assert(SCIPsetIsLE(set, lb, ub * vbcoef + vbconstant) );
9343 assert(SCIPsetIsLE(set, ub, lb * vbcoef + vbconstant) );
9344 }
9345 }
9346#endif
9347 SCIPsetDebugMsg(set, "redundant variable bound: <%s> %s %g<%s> %+g\n",
9348 SCIPvarGetName(var), vbtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", vbcoef, SCIPvarGetName(vbvar), vbconstant);
9349
9350 return SCIP_OKAY;
9351 }
9352
9353 SCIPsetDebugMsg(set, "adding variable bound: <%s> %s %g<%s> %+g\n",
9354 SCIPvarGetName(var), vbtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", vbcoef, SCIPvarGetName(vbvar), vbconstant);
9355
9356 /* check variable bound on debugging solution */
9357 SCIP_CALL( SCIPdebugCheckVbound(set, var, vbtype, vbvar, vbcoef, vbconstant) ); /*lint !e506 !e774*/
9358
9359 /* perform the addition */
9360 if( vbtype == SCIP_BOUNDTYPE_LOWER )
9361 {
9362 SCIP_CALL( SCIPvboundsAdd(&var->vlbs, blkmem, set, vbtype, vbvar, vbcoef, vbconstant, &added) );
9363 }
9364 else
9365 {
9366 SCIP_CALL( SCIPvboundsAdd(&var->vubs, blkmem, set, vbtype, vbvar, vbcoef, vbconstant, &added) );
9367 }
9368 var->closestvblpcount = -1;
9369
9370 if( added )
9371 {
9372 /* issue IMPLADDED event */
9373 SCIP_CALL( varEventImplAdded(var, blkmem, set, eventqueue) );
9374 }
9375
9376 return SCIP_OKAY;
9377}
9378
9379/** checks whether the given implication is redundant or infeasible w.r.t. the implied variables global bounds */
9380static
9382 SCIP_SET* set, /**< global SCIP settings */
9383 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9384 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9385 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
9386 SCIP_Bool* redundant, /**< pointer to store whether the implication is redundant */
9387 SCIP_Bool* infeasible /**< pointer to store whether the implication is infeasible */
9388 )
9389{
9390 SCIP_Real impllb;
9391 SCIP_Real implub;
9392
9393 assert(redundant != NULL);
9394 assert(infeasible != NULL);
9395
9396 impllb = SCIPvarGetLbGlobal(implvar);
9397 implub = SCIPvarGetUbGlobal(implvar);
9398 if( impltype == SCIP_BOUNDTYPE_LOWER )
9399 {
9400 *infeasible = SCIPsetIsFeasGT(set, implbound, implub);
9401 *redundant = SCIPsetIsFeasLE(set, implbound, impllb);
9402 }
9403 else
9404 {
9405 *infeasible = SCIPsetIsFeasLT(set, implbound, impllb);
9406 *redundant = SCIPsetIsFeasGE(set, implbound, implub);
9407 }
9408}
9409
9410/** applies the given implication, if it is not redundant */
9411static
9413 BMS_BLKMEM* blkmem, /**< block memory */
9414 SCIP_SET* set, /**< global SCIP settings */
9415 SCIP_STAT* stat, /**< problem statistics */
9416 SCIP_PROB* transprob, /**< transformed problem */
9417 SCIP_PROB* origprob, /**< original problem */
9418 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9419 SCIP_REOPT* reopt, /**< reoptimization data structure */
9420 SCIP_LP* lp, /**< current LP data */
9421 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9422 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9423 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
9424 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9425 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9426 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
9427 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9428 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
9429 )
9430{
9431 SCIP_Real implub;
9432 SCIP_Real impllb;
9433
9434 assert(infeasible != NULL);
9435
9436 *infeasible = FALSE;
9437
9438 implub = SCIPvarGetUbGlobal(implvar);
9439 impllb = SCIPvarGetLbGlobal(implvar);
9440 if( impltype == SCIP_BOUNDTYPE_LOWER )
9441 {
9442 if( SCIPsetIsFeasGT(set, implbound, implub) )
9443 {
9444 /* the implication produces a conflict: the problem is infeasible */
9445 *infeasible = TRUE;
9446 }
9447 else if( SCIPsetIsFeasGT(set, implbound, impllb) )
9448 {
9449 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9450 * with the local bound, in this case we need to store the bound change as pending bound change
9451 */
9453 {
9454 assert(tree != NULL);
9455 assert(transprob != NULL);
9456 assert(SCIPprobIsTransformed(transprob));
9457
9458 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9459 tree, reopt, lp, branchcand, eventqueue, cliquetable, implvar, implbound, SCIP_BOUNDTYPE_LOWER, FALSE) );
9460 }
9461 else
9462 {
9463 SCIP_CALL( SCIPvarChgLbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, implbound) );
9464 }
9465
9466 if( nbdchgs != NULL )
9467 (*nbdchgs)++;
9468 }
9469 }
9470 else
9471 {
9472 if( SCIPsetIsFeasLT(set, implbound, impllb) )
9473 {
9474 /* the implication produces a conflict: the problem is infeasible */
9475 *infeasible = TRUE;
9476 }
9477 else if( SCIPsetIsFeasLT(set, implbound, implub) )
9478 {
9479 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9480 * with the local bound, in this case we need to store the bound change as pending bound change
9481 */
9483 {
9484 assert(tree != NULL);
9485 assert(transprob != NULL);
9486 assert(SCIPprobIsTransformed(transprob));
9487
9488 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9489 tree, reopt, lp, branchcand, eventqueue, cliquetable, implvar, implbound, SCIP_BOUNDTYPE_UPPER, FALSE) );
9490 }
9491 else
9492 {
9493 SCIP_CALL( SCIPvarChgUbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, implbound) );
9494 }
9495
9496 if( nbdchgs != NULL )
9497 (*nbdchgs)++;
9498 }
9499 }
9500
9501 return SCIP_OKAY;
9502}
9503
9504/** actually performs the addition of an implication to the variable's implication arrays,
9505 * and adds the corresponding implication or variable bound to the implied variable;
9506 * if the implication is conflicting, the variable is fixed to the opposite value;
9507 * if the variable is already fixed to the given value, the implication is performed immediately;
9508 * if the implication is redundant with respect to the variables' global bounds, it is ignored
9509 */
9510static
9512 SCIP_VAR* var, /**< problem variable */
9513 BMS_BLKMEM* blkmem, /**< block memory */
9514 SCIP_SET* set, /**< global SCIP settings */
9515 SCIP_STAT* stat, /**< problem statistics */
9516 SCIP_PROB* transprob, /**< transformed problem */
9517 SCIP_PROB* origprob, /**< original problem */
9518 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9519 SCIP_REOPT* reopt, /**< reoptimization data structure */
9520 SCIP_LP* lp, /**< current LP data */
9521 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
9522 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9523 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9524 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9525 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9526 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9527 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
9528 SCIP_Bool isshortcut, /**< is the implication a shortcut, i.e., added as part of the transitive closure of another implication? */
9529 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9530 int* nbdchgs, /**< pointer to count the number of performed bound changes, or NULL */
9531 SCIP_Bool* added /**< pointer to store whether an implication was added */
9532 )
9533{
9534 SCIP_Bool redundant;
9535 SCIP_Bool conflict;
9536
9537 assert(var != NULL);
9538 assert(SCIPvarIsActive(var));
9540 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
9541 assert(SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED);
9542 assert(infeasible != NULL);
9543 assert(added != NULL);
9544
9545 /* check implication on debugging solution */
9546 SCIP_CALL( SCIPdebugCheckImplic(set, var, varfixing, implvar, impltype, implbound) ); /*lint !e506 !e774*/
9547
9548 *infeasible = FALSE;
9549 *added = FALSE;
9550
9551 /* check, if the implication is redundant or infeasible */
9552 checkImplic(set, implvar, impltype, implbound, &redundant, &conflict);
9553 assert(!redundant || !conflict);
9554 if( redundant )
9555 return SCIP_OKAY;
9556
9557 if( var == implvar )
9558 {
9559 /* special cases appear were a bound to a variable implies itself to be outside the bounds:
9560 * x == varfixing => x < 0 or x > 1
9561 */
9562 if( SCIPsetIsLT(set, implbound, 0.0) || SCIPsetIsGT(set, implbound, 1.0) )
9563 conflict = TRUE;
9564 else
9565 {
9566 /* variable implies itself: x == varfixing => x == (impltype == SCIP_BOUNDTYPE_LOWER) */
9567 assert(SCIPsetIsZero(set, implbound) || SCIPsetIsEQ(set, implbound, 1.0));
9568 assert(SCIPsetIsZero(set, implbound) == (impltype == SCIP_BOUNDTYPE_UPPER));
9569 assert(SCIPsetIsEQ(set, implbound, 1.0) == (impltype == SCIP_BOUNDTYPE_LOWER));
9570 conflict = conflict || ((varfixing == TRUE) == (impltype == SCIP_BOUNDTYPE_UPPER));
9571 if( !conflict )
9572 return SCIP_OKAY;
9573 }
9574 }
9575
9576 /* check, if the variable is already fixed */
9577 if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
9578 {
9579 /* if the variable is fixed to the given value, perform the implication; otherwise, ignore the implication */
9580 if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
9581 {
9582 SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
9583 cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) );
9584 }
9585 return SCIP_OKAY;
9586 }
9587
9588 assert((impltype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, implbound, SCIPvarGetLbGlobal(implvar)))
9589 || (impltype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, implbound, SCIPvarGetUbGlobal(implvar))));
9590
9591 if( !conflict )
9592 {
9593 assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9594
9595 if( SCIPvarIsBinary(implvar) )
9596 {
9597 SCIP_VAR* vars[2];
9598 SCIP_Bool vals[2];
9599
9600 assert(SCIPsetIsFeasEQ(set, implbound, 1.0) || SCIPsetIsFeasZero(set, implbound));
9601 assert((impltype == SCIP_BOUNDTYPE_UPPER) == SCIPsetIsFeasZero(set, implbound));
9602
9603 vars[0] = var;
9604 vars[1] = implvar;
9605 vals[0] = varfixing;
9606 vals[1] = (impltype == SCIP_BOUNDTYPE_UPPER);
9607
9608 /* add the clique to the clique table */
9609 SCIP_CALL( SCIPcliquetableAdd(cliquetable, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
9610 eventqueue, vars, vals, 2, FALSE, &conflict, nbdchgs) );
9611
9612 if( !conflict )
9613 return SCIP_OKAY;
9614 }
9615 else
9616 {
9617 /* add implication x == 0/1 -> y <= b / y >= b to the implications list of x */
9618 SCIPsetDebugMsg(set, "adding implication: <%s> == %u ==> <%s> %s %g\n",
9619 SCIPvarGetName(var), varfixing,
9620 SCIPvarGetName(implvar), impltype == SCIP_BOUNDTYPE_UPPER ? "<=" : ">=", implbound);
9621 SCIP_CALL( SCIPimplicsAdd(&var->implics, blkmem, set, stat, varfixing, implvar, impltype, implbound,
9622 isshortcut, &conflict, added) );
9623 }
9624 }
9625 assert(!conflict || !(*added));
9626
9627 /* on conflict, fix the variable to the opposite value */
9628 if( conflict )
9629 {
9630 SCIPsetDebugMsg(set, " -> implication yields a conflict: fix <%s> == %d\n", SCIPvarGetName(var), !varfixing);
9631
9632 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9633 * with the local bound, in this case we need to store the bound change as pending bound change
9634 */
9636 {
9637 assert(tree != NULL);
9638 assert(transprob != NULL);
9639 assert(SCIPprobIsTransformed(transprob));
9640
9641 if( varfixing )
9642 {
9643 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9644 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) );
9645 }
9646 else
9647 {
9648 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9649 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 1.0, SCIP_BOUNDTYPE_LOWER, FALSE) );
9650 }
9651 }
9652 else
9653 {
9654 if( varfixing )
9655 {
9656 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 0.0) );
9657 }
9658 else
9659 {
9660 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 1.0) );
9661 }
9662 }
9663 if( nbdchgs != NULL )
9664 (*nbdchgs)++;
9665
9666 return SCIP_OKAY;
9667 }
9668 else if( *added )
9669 {
9670 /* issue IMPLADDED event */
9671 SCIP_CALL( varEventImplAdded(var, blkmem, set, eventqueue) );
9672 }
9673 else
9674 {
9675 /* the implication was redundant: the inverse is also redundant */
9676 return SCIP_OKAY;
9677 }
9678
9679 assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9680
9681 /* check, whether implied variable is binary */
9682 if( !SCIPvarIsBinary(implvar) )
9683 {
9684 SCIP_Real lb;
9685 SCIP_Real ub;
9686
9687 /* add inverse variable bound to the variable bounds of y with global bounds y \in [lb,ub]:
9688 * x == 0 -> y <= b <-> y <= (ub - b)*x + b
9689 * x == 1 -> y <= b <-> y <= (b - ub)*x + ub
9690 * x == 0 -> y >= b <-> y >= (lb - b)*x + b
9691 * x == 1 -> y >= b <-> y >= (b - lb)*x + lb
9692 * for numerical reasons, ignore variable bounds with large absolute coefficient
9693 */
9694 lb = SCIPvarGetLbGlobal(implvar);
9695 ub = SCIPvarGetUbGlobal(implvar);
9696 if( impltype == SCIP_BOUNDTYPE_UPPER )
9697 {
9698 if( REALABS(implbound - ub) <= MAXABSVBCOEF )
9699 {
9700 SCIP_CALL( varAddVbound(implvar, blkmem, set, eventqueue, SCIP_BOUNDTYPE_UPPER, var,
9701 varfixing ? implbound - ub : ub - implbound, varfixing ? ub : implbound) );
9702 }
9703 }
9704 else
9705 {
9706 if( REALABS(implbound - lb) <= MAXABSVBCOEF )
9707 {
9708 SCIP_CALL( varAddVbound(implvar, blkmem, set, eventqueue, SCIP_BOUNDTYPE_LOWER, var,
9709 varfixing ? implbound - lb : lb - implbound, varfixing ? lb : implbound) );
9710 }
9711 }
9712 }
9713
9714 return SCIP_OKAY;
9715}
9716
9717/** adds transitive closure for binary implication x = a -> y = b */
9718static
9720 SCIP_VAR* var, /**< problem variable */
9721 BMS_BLKMEM* blkmem, /**< block memory */
9722 SCIP_SET* set, /**< global SCIP settings */
9723 SCIP_STAT* stat, /**< problem statistics */
9724 SCIP_PROB* transprob, /**< transformed problem */
9725 SCIP_PROB* origprob, /**< original problem */
9726 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9727 SCIP_REOPT* reopt, /**< reoptimization data structure */
9728 SCIP_LP* lp, /**< current LP data */
9729 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
9730 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9731 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9732 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9733 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9734 SCIP_Bool implvarfixing, /**< fixing b in implication */
9735 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9736 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
9737 )
9738{
9739 SCIP_VAR** implvars;
9740 SCIP_BOUNDTYPE* impltypes;
9741 SCIP_Real* implbounds;
9742 int nimpls;
9743 int i;
9744
9745 *infeasible = FALSE;
9746
9747 /* binary variable: implications of implvar */
9748 nimpls = SCIPimplicsGetNImpls(implvar->implics, implvarfixing);
9749 implvars = SCIPimplicsGetVars(implvar->implics, implvarfixing);
9750 impltypes = SCIPimplicsGetTypes(implvar->implics, implvarfixing);
9751 implbounds = SCIPimplicsGetBounds(implvar->implics, implvarfixing);
9752
9753 /* if variable has too many implications, the implication graph may become too dense */
9754 i = MIN(nimpls, MAXIMPLSCLOSURE) - 1;
9755
9756 /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9757 * implvars[i] is fixed, s.t. the implication y == varfixing -> z <= b / z >= b is deleted; this affects the
9758 * array over which we currently iterate; the only thing that can happen, is that elements of the array are
9759 * deleted; in this case, the subsequent elements are moved to the front; if we iterate from back to front, the
9760 * only thing that can happen is that we add the same implication twice - this does no harm
9761 */
9762 while ( i >= 0 && !(*infeasible) )
9763 {
9764 SCIP_Bool added;
9765
9766 assert(implvars[i] != implvar);
9767
9768 /* we have x == varfixing -> y == implvarfixing -> z <= b / z >= b:
9769 * add implication x == varfixing -> z <= b / z >= b to the implications list of x
9770 */
9771 if( SCIPvarIsActive(implvars[i]) )
9772 {
9773 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
9774 eventqueue, varfixing, implvars[i], impltypes[i], implbounds[i], TRUE, infeasible, nbdchgs, &added) );
9775 assert(SCIPimplicsGetNImpls(implvar->implics, implvarfixing) <= nimpls);
9776 nimpls = SCIPimplicsGetNImpls(implvar->implics, implvarfixing);
9777 i = MIN(i, nimpls); /* some elements from the array could have been removed */
9778 }
9779 --i;
9780 }
9781
9782 return SCIP_OKAY;
9783}
9784
9785/** adds given implication to the variable's implication list, and adds all implications directly implied by this
9786 * implication to the variable's implication list;
9787 * if the implication is conflicting, the variable is fixed to the opposite value;
9788 * if the variable is already fixed to the given value, the implication is performed immediately;
9789 * if the implication is redundant with respect to the variables' global bounds, it is ignored
9790 */
9791static
9793 SCIP_VAR* var, /**< problem variable */
9794 BMS_BLKMEM* blkmem, /**< block memory */
9795 SCIP_SET* set, /**< global SCIP settings */
9796 SCIP_STAT* stat, /**< problem statistics */
9797 SCIP_PROB* transprob, /**< transformed problem */
9798 SCIP_PROB* origprob, /**< original problem */
9799 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
9800 SCIP_REOPT* reopt, /**< reoptimization data structure */
9801 SCIP_LP* lp, /**< current LP data */
9802 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
9803 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
9804 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
9805 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9806 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
9807 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9808 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
9809 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
9810 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
9811 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
9812 )
9813{
9814 SCIP_Bool added;
9815
9816 assert(var != NULL);
9817 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
9818 assert(SCIPvarIsActive(var));
9819 assert(implvar != NULL);
9820 assert(SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED);
9821 assert(infeasible != NULL);
9822
9823 /* add implication x == varfixing -> y <= b / y >= b to the implications list of x */
9824 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
9825 eventqueue, varfixing, implvar, impltype, implbound, FALSE, infeasible, nbdchgs, &added) );
9826
9827 if( *infeasible || var == implvar || !transitive || !added )
9828 return SCIP_OKAY;
9829
9830 assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9831
9832 /* add transitive closure */
9833 if( SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY )
9834 {
9835 SCIP_Bool implvarfixing;
9836
9837 implvarfixing = (impltype == SCIP_BOUNDTYPE_LOWER);
9838
9839 /* binary variable: implications of implvar */
9840 SCIP_CALL( varAddTransitiveBinaryClosureImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
9841 cliquetable, branchcand, eventqueue, varfixing, implvar, implvarfixing, infeasible, nbdchgs) );
9842
9843 /* inverse implication */
9844 if( !(*infeasible) )
9845 {
9846 SCIP_CALL( varAddTransitiveBinaryClosureImplic(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
9847 cliquetable, branchcand, eventqueue, !implvarfixing, var, !varfixing, infeasible, nbdchgs) );
9848 }
9849 }
9850 else
9851 {
9852 /* non-binary variable: variable lower bounds of implvar */
9853 if( impltype == SCIP_BOUNDTYPE_UPPER && implvar->vlbs != NULL )
9854 {
9855 SCIP_VAR** vlbvars;
9856 SCIP_Real* vlbcoefs;
9857 SCIP_Real* vlbconstants;
9858 int nvlbvars;
9859 int i;
9860
9861 nvlbvars = SCIPvboundsGetNVbds(implvar->vlbs);
9862 vlbvars = SCIPvboundsGetVars(implvar->vlbs);
9863 vlbcoefs = SCIPvboundsGetCoefs(implvar->vlbs);
9864 vlbconstants = SCIPvboundsGetConstants(implvar->vlbs);
9865
9866 /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9867 * vlbvars[i] is fixed, s.t. the variable bound is deleted; this affects the array over which we currently
9868 * iterate; the only thing that can happen, is that elements of the array are deleted; in this case, the
9869 * subsequent elements are moved to the front; if we iterate from back to front, the only thing that can happen
9870 * is that we add the same implication twice - this does no harm
9871 */
9872 i = nvlbvars-1;
9873 while ( i >= 0 && !(*infeasible) )
9874 {
9875 assert(vlbvars[i] != implvar);
9876 assert(!SCIPsetIsZero(set, vlbcoefs[i]));
9877
9878 /* we have x == varfixing -> y <= b and y >= c*z + d:
9879 * c > 0: add implication x == varfixing -> z <= (b-d)/c to the implications list of x
9880 * c < 0: add implication x == varfixing -> z >= (b-d)/c to the implications list of x
9881 *
9882 * @note during an aggregation the aggregated variable "aggrvar" (the one which will have the status
9883 * SCIP_VARSTATUS_AGGREGATED afterwards) copies its variable lower and uppers bounds to the
9884 * aggregation variable (the one which will stay active);
9885 *
9886 * W.l.o.g. we consider the variable upper bounds for now. Let "vubvar" be a variable upper bound of
9887 * the aggregated variable "aggvar"; During that copying of that variable upper bound variable
9888 * "vubvar" the variable lower and upper bounds of this variable "vubvar" are also considered; note
9889 * that the "aggvar" can be a variable lower bound variable of the variable "vubvar"; Due to that
9890 * situation it can happen that we reach that code place where "vlbvars[i] == aggvar". In particular
9891 * the "aggvar" has already the variable status SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED
9892 * but is still active since the aggregation is not finished yet (in SCIPvarAggregate()); therefore we
9893 * have to explicitly check that the active variable has not a variable status
9894 * SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED;
9895 */
9896 if( SCIPvarIsActive(vlbvars[i]) && SCIPvarGetStatus(vlbvars[i]) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(vlbvars[i]) != SCIP_VARSTATUS_NEGATED )
9897 {
9898 SCIP_Real vbimplbound;
9899
9900 vbimplbound = (implbound - vlbconstants[i])/vlbcoefs[i];
9901 if( vlbcoefs[i] >= 0.0 )
9902 {
9903 vbimplbound = adjustedUb(set, SCIPvarGetType(vlbvars[i]), vbimplbound);
9904 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9905 branchcand, eventqueue, varfixing, vlbvars[i], SCIP_BOUNDTYPE_UPPER, vbimplbound, TRUE,
9906 infeasible, nbdchgs, &added) );
9907 }
9908 else
9909 {
9910 vbimplbound = adjustedLb(set, SCIPvarGetType(vlbvars[i]), vbimplbound);
9911 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9912 branchcand, eventqueue, varfixing, vlbvars[i], SCIP_BOUNDTYPE_LOWER, vbimplbound, TRUE,
9913 infeasible, nbdchgs, &added) );
9914 }
9915 nvlbvars = SCIPvboundsGetNVbds(implvar->vlbs);
9916 i = MIN(i, nvlbvars); /* some elements from the array could have been removed */
9917 }
9918 --i;
9919 }
9920 }
9921
9922 /* non-binary variable: variable upper bounds of implvar */
9923 if( impltype == SCIP_BOUNDTYPE_LOWER && implvar->vubs != NULL )
9924 {
9925 SCIP_VAR** vubvars;
9926 SCIP_Real* vubcoefs;
9927 SCIP_Real* vubconstants;
9928 int nvubvars;
9929 int i;
9930
9931 nvubvars = SCIPvboundsGetNVbds(implvar->vubs);
9932 vubvars = SCIPvboundsGetVars(implvar->vubs);
9933 vubcoefs = SCIPvboundsGetCoefs(implvar->vubs);
9934 vubconstants = SCIPvboundsGetConstants(implvar->vubs);
9935
9936 /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9937 * vubvars[i] is fixed, s.t. the variable bound is deleted; this affects the array over which we currently
9938 * iterate; the only thing that can happen, is that elements of the array are deleted; in this case, the
9939 * subsequent elements are moved to the front; if we iterate from back to front, the only thing that can happen
9940 * is that we add the same implication twice - this does no harm
9941 */
9942 i = nvubvars-1;
9943 while ( i >= 0 && !(*infeasible) )
9944 {
9945 assert(vubvars[i] != implvar);
9946 assert(!SCIPsetIsZero(set, vubcoefs[i]));
9947
9948 /* we have x == varfixing -> y >= b and y <= c*z + d:
9949 * c > 0: add implication x == varfixing -> z >= (b-d)/c to the implications list of x
9950 * c < 0: add implication x == varfixing -> z <= (b-d)/c to the implications list of x
9951 *
9952 * @note during an aggregation the aggregated variable "aggrvar" (the one which will have the status
9953 * SCIP_VARSTATUS_AGGREGATED afterwards) copies its variable lower and uppers bounds to the
9954 * aggregation variable (the one which will stay active);
9955 *
9956 * W.l.o.g. we consider the variable lower bounds for now. Let "vlbvar" be a variable lower bound of
9957 * the aggregated variable "aggvar"; During that copying of that variable lower bound variable
9958 * "vlbvar" the variable lower and upper bounds of this variable "vlbvar" are also considered; note
9959 * that the "aggvar" can be a variable upper bound variable of the variable "vlbvar"; Due to that
9960 * situation it can happen that we reach that code place where "vubvars[i] == aggvar". In particular
9961 * the "aggvar" has already the variable status SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED
9962 * but is still active since the aggregation is not finished yet (in SCIPvarAggregate()); therefore we
9963 * have to explicitly check that the active variable has not a variable status
9964 * SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED;
9965 */
9966 if( SCIPvarIsActive(vubvars[i]) && SCIPvarGetStatus(vubvars[i]) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(vubvars[i]) != SCIP_VARSTATUS_NEGATED )
9967 {
9968 SCIP_Real vbimplbound;
9969
9970 vbimplbound = (implbound - vubconstants[i])/vubcoefs[i];
9971 if( vubcoefs[i] >= 0.0 )
9972 {
9973 vbimplbound = adjustedLb(set, SCIPvarGetType(vubvars[i]), vbimplbound);
9974 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9975 branchcand, eventqueue, varfixing, vubvars[i], SCIP_BOUNDTYPE_LOWER, vbimplbound, TRUE,
9976 infeasible, nbdchgs, &added) );
9977 }
9978 else
9979 {
9980 vbimplbound = adjustedUb(set, SCIPvarGetType(vubvars[i]), vbimplbound);
9981 SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9982 branchcand, eventqueue, varfixing, vubvars[i], SCIP_BOUNDTYPE_UPPER, vbimplbound, TRUE,
9983 infeasible, nbdchgs, &added) );
9984 }
9985 nvubvars = SCIPvboundsGetNVbds(implvar->vubs);
9986 i = MIN(i, nvubvars); /* some elements from the array could have been removed */
9987 }
9988 --i;
9989 }
9990 }
9991 }
9992
9993 return SCIP_OKAY;
9994}
9995
9996/** informs variable x about a globally valid variable lower bound x >= b*z + d with integer variable z;
9997 * if z is binary, the corresponding valid implication for z is also added;
9998 * improves the global bounds of the variable and the vlb variable if possible
9999 */
10001 SCIP_VAR* var, /**< problem variable */
10002 BMS_BLKMEM* blkmem, /**< block memory */
10003 SCIP_SET* set, /**< global SCIP settings */
10004 SCIP_STAT* stat, /**< problem statistics */
10005 SCIP_PROB* transprob, /**< transformed problem */
10006 SCIP_PROB* origprob, /**< original problem */
10007 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
10008 SCIP_REOPT* reopt, /**< reoptimization data structure */
10009 SCIP_LP* lp, /**< current LP data */
10010 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
10011 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
10012 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
10013 SCIP_VAR* vlbvar, /**< variable z in x >= b*z + d */
10014 SCIP_Real vlbcoef, /**< coefficient b in x >= b*z + d */
10015 SCIP_Real vlbconstant, /**< constant d in x >= b*z + d */
10016 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
10017 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
10018 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
10019 )
10020{
10021 assert(var != NULL);
10022 assert(set != NULL);
10023 assert(var->scip == set->scip);
10024 assert(SCIPvarGetType(vlbvar) != SCIP_VARTYPE_CONTINUOUS);
10025 assert(infeasible != NULL);
10026
10027 SCIPsetDebugMsg(set, "adding variable lower bound <%s> >= %g<%s> + %g\n", SCIPvarGetName(var), vlbcoef, SCIPvarGetName(vlbvar), vlbconstant);
10028
10029 *infeasible = FALSE;
10030 if( nbdchgs != NULL )
10031 *nbdchgs = 0;
10032
10033 switch( SCIPvarGetStatus(var) )
10034 {
10036 assert(var->data.original.transvar != NULL);
10037 SCIP_CALL( SCIPvarAddVlb(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10038 cliquetable, branchcand, eventqueue, vlbvar, vlbcoef, vlbconstant, transitive, infeasible, nbdchgs) );
10039 break;
10040
10044 /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */
10045 SCIP_CALL( SCIPvarGetProbvarSum(&vlbvar, set, &vlbcoef, &vlbconstant) );
10046 SCIPsetDebugMsg(set, " -> transformed to variable lower bound <%s> >= %g<%s> + %g\n",
10047 SCIPvarGetName(var), vlbcoef, SCIPvarGetName(vlbvar), vlbconstant);
10048
10049 /* if the variables are the same, just update the corresponding bound */
10050 if( var == vlbvar )
10051 {
10052 /* if the variables cancel out, the variable bound constraint is redundant or proves global infeasibility */
10053 if( SCIPsetIsEQ(set, vlbcoef, 1.0) )
10054 {
10055 if( SCIPsetIsFeasPositive(set, vlbconstant) )
10056 *infeasible = TRUE;
10057 }
10058 else
10059 {
10060 SCIP_Real lb = SCIPvarGetLbGlobal(var);
10061 SCIP_Real ub = SCIPvarGetUbGlobal(var);
10062
10063 /* the variable bound constraint defines a new upper bound */
10064 if( SCIPsetIsGT(set, vlbcoef, 1.0) )
10065 {
10066 SCIP_Real newub = vlbconstant / (1.0 - vlbcoef);
10067
10068 if( SCIPsetIsFeasLT(set, newub, lb) )
10069 {
10070 *infeasible = TRUE;
10071 return SCIP_OKAY;
10072 }
10073 else if( SCIPsetIsFeasLT(set, newub, ub) )
10074 {
10075 /* bound might be adjusted due to integrality condition */
10076 newub = adjustedUb(set, SCIPvarGetType(var), newub);
10077
10078 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10079 * with the local bound, in this case we need to store the bound change as pending bound change
10080 */
10082 {
10083 assert(tree != NULL);
10084 assert(transprob != NULL);
10085 assert(SCIPprobIsTransformed(transprob));
10086
10087 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10088 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10089 }
10090 else
10091 {
10092 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newub) );
10093 }
10094
10095 if( nbdchgs != NULL )
10096 (*nbdchgs)++;
10097 }
10098 }
10099 /* the variable bound constraint defines a new lower bound */
10100 else
10101 {
10102 SCIP_Real newlb;
10103
10104 assert(SCIPsetIsLT(set, vlbcoef, 1.0));
10105
10106 newlb = vlbconstant / (1.0 - vlbcoef);
10107
10108 if( SCIPsetIsFeasGT(set, newlb, ub) )
10109 {
10110 *infeasible = TRUE;
10111 return SCIP_OKAY;
10112 }
10113 else if( SCIPsetIsFeasGT(set, newlb, lb) )
10114 {
10115 /* bound might be adjusted due to integrality condition */
10116 newlb = adjustedLb(set, SCIPvarGetType(var), newlb);
10117
10118 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10119 * with the local bound, in this case we need to store the bound change as pending bound change
10120 */
10122 {
10123 assert(tree != NULL);
10124 assert(transprob != NULL);
10125 assert(SCIPprobIsTransformed(transprob));
10126
10127 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10128 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10129 }
10130 else
10131 {
10132 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newlb) );
10133 }
10134
10135 if( nbdchgs != NULL )
10136 (*nbdchgs)++;
10137 }
10138 }
10139 }
10140 }
10141 /* if the vlb coefficient is zero, just update the lower bound of the variable */
10142 else if( SCIPsetIsZero(set, vlbcoef) )
10143 {
10144 if( SCIPsetIsFeasGT(set, vlbconstant, SCIPvarGetUbGlobal(var)) )
10145 *infeasible = TRUE;
10146 else if( SCIPsetIsFeasGT(set, vlbconstant, SCIPvarGetLbGlobal(var)) )
10147 {
10148 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10149 * with the local bound, in this case we need to store the bound change as pending bound change
10150 */
10152 {
10153 assert(tree != NULL);
10154 assert(transprob != NULL);
10155 assert(SCIPprobIsTransformed(transprob));
10156
10157 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10158 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, vlbconstant, SCIP_BOUNDTYPE_LOWER, FALSE) );
10159 }
10160 else
10161 {
10162 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, vlbconstant) );
10163 }
10164
10165 if( nbdchgs != NULL )
10166 (*nbdchgs)++;
10167 }
10168 }
10169 else if( SCIPvarIsActive(vlbvar) )
10170 {
10171 SCIP_Real xlb;
10172 SCIP_Real xub;
10173 SCIP_Real zlb;
10174 SCIP_Real zub;
10175 SCIP_Real minvlb;
10176 SCIP_Real maxvlb;
10177
10179 assert(vlbcoef != 0.0);
10180
10181 minvlb = -SCIPsetInfinity(set);
10182 maxvlb = SCIPsetInfinity(set);
10183
10184 xlb = SCIPvarGetLbGlobal(var);
10185 xub = SCIPvarGetUbGlobal(var);
10186 zlb = SCIPvarGetLbGlobal(vlbvar);
10187 zub = SCIPvarGetUbGlobal(vlbvar);
10188
10189 /* improve global bounds of vlb variable, and calculate minimal and maximal value of variable bound */
10190 if( vlbcoef >= 0.0 )
10191 {
10192 SCIP_Real newzub;
10193
10194 if( !SCIPsetIsInfinity(set, xub) )
10195 {
10196 /* x >= b*z + d -> z <= (x-d)/b */
10197 newzub = (xub - vlbconstant)/vlbcoef;
10198
10199 /* return if the new bound is less than -infinity */
10200 if( SCIPsetIsInfinity(set, REALABS(newzub)) )
10201 return SCIP_OKAY;
10202
10203 if( SCIPsetIsFeasLT(set, newzub, zlb) )
10204 {
10205 *infeasible = TRUE;
10206 return SCIP_OKAY;
10207 }
10208 if( SCIPsetIsFeasLT(set, newzub, zub) )
10209 {
10210 /* bound might be adjusted due to integrality condition */
10211 newzub = adjustedUb(set, SCIPvarGetType(vlbvar), newzub);
10212
10213 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10214 * with the local bound, in this case we need to store the bound change as pending bound change
10215 */
10217 {
10218 assert(tree != NULL);
10219 assert(transprob != NULL);
10220 assert(SCIPprobIsTransformed(transprob));
10221
10222 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10223 tree, reopt, lp, branchcand, eventqueue, cliquetable, vlbvar, newzub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10224 }
10225 else
10226 {
10227 SCIP_CALL( SCIPvarChgUbGlobal(vlbvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzub) );
10228 }
10229 zub = newzub;
10230
10231 if( nbdchgs != NULL )
10232 (*nbdchgs)++;
10233 }
10234 maxvlb = vlbcoef * zub + vlbconstant;
10235 if( !SCIPsetIsInfinity(set, -zlb) )
10236 minvlb = vlbcoef * zlb + vlbconstant;
10237 }
10238 else
10239 {
10240 if( !SCIPsetIsInfinity(set, zub) )
10241 maxvlb = vlbcoef * zub + vlbconstant;
10242 if( !SCIPsetIsInfinity(set, -zlb) )
10243 minvlb = vlbcoef * zlb + vlbconstant;
10244 }
10245 }
10246 else
10247 {
10248 SCIP_Real newzlb;
10249
10250 if( !SCIPsetIsInfinity(set, xub) )
10251 {
10252 /* x >= b*z + d -> z >= (x-d)/b */
10253 newzlb = (xub - vlbconstant)/vlbcoef;
10254
10255 /* return if the new bound is larger than infinity */
10256 if( SCIPsetIsInfinity(set, REALABS(newzlb)) )
10257 return SCIP_OKAY;
10258
10259 if( SCIPsetIsFeasGT(set, newzlb, zub) )
10260 {
10261 *infeasible = TRUE;
10262 return SCIP_OKAY;
10263 }
10264 if( SCIPsetIsFeasGT(set, newzlb, zlb) )
10265 {
10266 /* bound might be adjusted due to integrality condition */
10267 newzlb = adjustedLb(set, SCIPvarGetType(vlbvar), newzlb);
10268
10269 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10270 * with the local bound, in this case we need to store the bound change as pending bound change
10271 */
10273 {
10274 assert(tree != NULL);
10275 assert(transprob != NULL);
10276 assert(SCIPprobIsTransformed(transprob));
10277
10278 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10279 tree, reopt, lp, branchcand, eventqueue, cliquetable, vlbvar, newzlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10280 }
10281 else
10282 {
10283 SCIP_CALL( SCIPvarChgLbGlobal(vlbvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzlb) );
10284 }
10285 zlb = newzlb;
10286
10287 if( nbdchgs != NULL )
10288 (*nbdchgs)++;
10289 }
10290 maxvlb = vlbcoef * zlb + vlbconstant;
10291 if( !SCIPsetIsInfinity(set, zub) )
10292 minvlb = vlbcoef * zub + vlbconstant;
10293 }
10294 else
10295 {
10296 if( !SCIPsetIsInfinity(set, -zlb) )
10297 maxvlb = vlbcoef * zlb + vlbconstant;
10298 if( !SCIPsetIsInfinity(set, zub) )
10299 minvlb = vlbcoef * zub + vlbconstant;
10300 }
10301 }
10302 if( maxvlb < minvlb )
10303 maxvlb = minvlb;
10304
10305 /* adjust bounds due to integrality of variable */
10306 minvlb = adjustedLb(set, SCIPvarGetType(var), minvlb);
10307 maxvlb = adjustedLb(set, SCIPvarGetType(var), maxvlb);
10308
10309 /* check bounds for feasibility */
10310 if( SCIPsetIsFeasGT(set, minvlb, xub) )
10311 {
10312 *infeasible = TRUE;
10313 return SCIP_OKAY;
10314 }
10315 /* improve global lower bound of variable */
10316 if( SCIPsetIsFeasGT(set, minvlb, xlb) )
10317 {
10318 /* bound might be adjusted due to integrality condition */
10319 minvlb = adjustedLb(set, SCIPvarGetType(var), minvlb);
10320
10321 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10322 * with the local bound, in this case we need to store the bound change as pending bound change
10323 */
10325 {
10326 assert(tree != NULL);
10327 assert(transprob != NULL);
10328 assert(SCIPprobIsTransformed(transprob));
10329
10330 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10331 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, minvlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10332 }
10333 else
10334 {
10335 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, minvlb) );
10336 }
10337 xlb = minvlb;
10338
10339 if( nbdchgs != NULL )
10340 (*nbdchgs)++;
10341 }
10342 minvlb = xlb;
10343
10344 /* improve variable bound for binary z by moving the variable's global bound to the vlb constant */
10345 if( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY )
10346 {
10347 /* b > 0: x >= (maxvlb - minvlb) * z + minvlb
10348 * b < 0: x >= (minvlb - maxvlb) * z + maxvlb
10349 */
10350
10351 assert(!SCIPsetIsInfinity(set, maxvlb) && !SCIPsetIsInfinity(set, -minvlb));
10352
10353 if( vlbcoef >= 0.0 )
10354 {
10355 vlbcoef = maxvlb - minvlb;
10356 vlbconstant = minvlb;
10357 }
10358 else
10359 {
10360 vlbcoef = minvlb - maxvlb;
10361 vlbconstant = maxvlb;
10362 }
10363 }
10364
10365 /* add variable bound to the variable bounds list */
10366 if( SCIPsetIsFeasGT(set, maxvlb, xlb) )
10367 {
10368 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED);
10369 assert(!SCIPsetIsZero(set, vlbcoef));
10370
10371 /* if one of the variables is binary, add the corresponding implication to the variable's implication
10372 * list, thereby also adding the variable bound (or implication) to the other variable
10373 */
10374 if( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY )
10375 {
10376 /* add corresponding implication:
10377 * b > 0, x >= b*z + d <-> z == 1 -> x >= b+d
10378 * b < 0, x >= b*z + d <-> z == 0 -> x >= d
10379 */
10380 SCIP_CALL( varAddTransitiveImplic(vlbvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10381 cliquetable, branchcand, eventqueue, (vlbcoef >= 0.0), var, SCIP_BOUNDTYPE_LOWER, maxvlb, transitive,
10382 infeasible, nbdchgs) );
10383 }
10384 else if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
10385 {
10386 /* add corresponding implication:
10387 * b > 0, x >= b*z + d <-> x == 0 -> z <= -d/b
10388 * b < 0, x >= b*z + d <-> x == 0 -> z >= -d/b
10389 */
10390 SCIP_Real implbound;
10391 implbound = -vlbconstant/vlbcoef;
10392
10393 /* tighten the implication bound if the variable is integer */
10394 if( SCIPvarIsIntegral(vlbvar) )
10395 {
10396 if( vlbcoef >= 0 )
10397 implbound = SCIPsetFloor(set, implbound);
10398 else
10399 implbound = SCIPsetCeil(set, implbound);
10400 }
10401 SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10402 cliquetable, branchcand, eventqueue, FALSE, vlbvar, (vlbcoef >= 0.0 ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER),
10403 implbound, transitive, infeasible, nbdchgs) );
10404 }
10405 else
10406 {
10407 SCIP_CALL( varAddVbound(var, blkmem, set, eventqueue, SCIP_BOUNDTYPE_LOWER, vlbvar, vlbcoef, vlbconstant) );
10408 }
10409 }
10410 }
10411 break;
10412
10414 /* x = a*y + c: x >= b*z + d <=> a*y + c >= b*z + d <=> y >= b/a * z + (d-c)/a, if a > 0
10415 * y <= b/a * z + (d-c)/a, if a < 0
10416 */
10417
10418 /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */
10419 SCIP_CALL( SCIPvarGetProbvarSum(&vlbvar, set, &vlbcoef, &vlbconstant) );
10420
10421 /* if the variables cancel out, the variable bound constraint is redundant or proves global infeasibility */
10422 assert(var->data.aggregate.var != NULL);
10423 if( var->data.aggregate.var == vlbvar && SCIPsetIsEQ(set, var->data.aggregate.scalar, vlbcoef) )
10424 {
10425 if( SCIPsetIsFeasLT(set, var->data.aggregate.constant, vlbconstant) )
10426 *infeasible = TRUE;
10427 }
10428 else if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
10429 {
10430 /* a > 0 -> add variable lower bound */
10431 SCIP_CALL( SCIPvarAddVlb(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10432 cliquetable, branchcand, eventqueue, vlbvar, vlbcoef/var->data.aggregate.scalar,
10433 (vlbconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10434 }
10435 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
10436 {
10437 /* a < 0 -> add variable upper bound */
10438 SCIP_CALL( SCIPvarAddVub(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10439 cliquetable, branchcand, eventqueue, vlbvar, vlbcoef/var->data.aggregate.scalar,
10440 (vlbconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10441 }
10442 else
10443 {
10444 SCIPerrorMessage("scalar is zero in aggregation\n");
10445 return SCIP_INVALIDDATA;
10446 }
10447 break;
10448
10450 /* nothing to do here */
10451 break;
10452
10454 /* x = offset - x': x >= b*z + d <=> offset - x' >= b*z + d <=> x' <= -b*z + (offset-d) */
10455 assert(var->negatedvar != NULL);
10457 assert(var->negatedvar->negatedvar == var);
10458 SCIP_CALL( SCIPvarAddVub(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10459 branchcand, eventqueue, vlbvar, -vlbcoef, var->data.negate.constant - vlbconstant, transitive, infeasible,
10460 nbdchgs) );
10461 break;
10462
10463 default:
10464 SCIPerrorMessage("unknown variable status\n");
10465 return SCIP_INVALIDDATA;
10466 }
10467
10468 return SCIP_OKAY;
10469}
10470
10471/** informs variable x about a globally valid variable upper bound x <= b*z + d with integer variable z;
10472 * if z is binary, the corresponding valid implication for z is also added;
10473 * updates the global bounds of the variable and the vub variable correspondingly
10474 */
10476 SCIP_VAR* var, /**< problem variable */
10477 BMS_BLKMEM* blkmem, /**< block memory */
10478 SCIP_SET* set, /**< global SCIP settings */
10479 SCIP_STAT* stat, /**< problem statistics */
10480 SCIP_PROB* transprob, /**< transformed problem */
10481 SCIP_PROB* origprob, /**< original problem */
10482 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
10483 SCIP_REOPT* reopt, /**< reoptimization data structure */
10484 SCIP_LP* lp, /**< current LP data */
10485 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
10486 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
10487 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
10488 SCIP_VAR* vubvar, /**< variable z in x <= b*z + d */
10489 SCIP_Real vubcoef, /**< coefficient b in x <= b*z + d */
10490 SCIP_Real vubconstant, /**< constant d in x <= b*z + d */
10491 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
10492 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
10493 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
10494 )
10495{
10496 assert(var != NULL);
10497 assert(set != NULL);
10498 assert(var->scip == set->scip);
10499 assert(SCIPvarGetType(vubvar) != SCIP_VARTYPE_CONTINUOUS);
10500 assert(infeasible != NULL);
10501
10502 SCIPsetDebugMsg(set, "adding variable upper bound <%s> <= %g<%s> + %g\n", SCIPvarGetName(var), vubcoef, SCIPvarGetName(vubvar), vubconstant);
10503
10504 *infeasible = FALSE;
10505 if( nbdchgs != NULL )
10506 *nbdchgs = 0;
10507
10508 switch( SCIPvarGetStatus(var) )
10509 {
10511 assert(var->data.original.transvar != NULL);
10512 SCIP_CALL( SCIPvarAddVub(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10513 cliquetable, branchcand, eventqueue, vubvar, vubcoef, vubconstant, transitive, infeasible, nbdchgs) );
10514 break;
10515
10519 /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */
10520 SCIP_CALL( SCIPvarGetProbvarSum(&vubvar, set, &vubcoef, &vubconstant) );
10521 SCIPsetDebugMsg(set, " -> transformed to variable upper bound <%s> <= %g<%s> + %g\n",
10522 SCIPvarGetName(var), vubcoef, SCIPvarGetName(vubvar), vubconstant);
10523
10524 /* if the variables are the same, just update the corresponding bound */
10525 if( var == vubvar )
10526 {
10527 /* if the variables cancel out, the variable bound constraint is redundant or proves global infeasibility */
10528 if( SCIPsetIsEQ(set, vubcoef, 1.0) )
10529 {
10530 if( SCIPsetIsFeasNegative(set, vubconstant) )
10531 *infeasible = TRUE;
10532 }
10533 else
10534 {
10535 SCIP_Real lb = SCIPvarGetLbGlobal(var);
10536 SCIP_Real ub = SCIPvarGetUbGlobal(var);
10537
10538 /* the variable bound constraint defines a new lower bound */
10539 if( SCIPsetIsGT(set, vubcoef, 1.0) )
10540 {
10541 SCIP_Real newlb = vubconstant / (1.0 - vubcoef);
10542
10543 if( SCIPsetIsFeasGT(set, newlb, ub) )
10544 {
10545 *infeasible = TRUE;
10546 return SCIP_OKAY;
10547 }
10548 else if( SCIPsetIsFeasGT(set, newlb, lb) )
10549 {
10550 /* bound might be adjusted due to integrality condition */
10551 newlb = adjustedLb(set, SCIPvarGetType(var), newlb);
10552
10553 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10554 * with the local bound, in this case we need to store the bound change as pending bound change
10555 */
10557 {
10558 assert(tree != NULL);
10559 assert(transprob != NULL);
10560 assert(SCIPprobIsTransformed(transprob));
10561
10562 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10563 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10564 }
10565 else
10566 {
10567 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newlb) );
10568 }
10569
10570 if( nbdchgs != NULL )
10571 (*nbdchgs)++;
10572 }
10573 }
10574 /* the variable bound constraint defines a new upper bound */
10575 else
10576 {
10577 SCIP_Real newub;
10578
10579 assert(SCIPsetIsLT(set, vubcoef, 1.0));
10580
10581 newub = vubconstant / (1.0 - vubcoef);
10582
10583 if( SCIPsetIsFeasLT(set, newub, lb) )
10584 {
10585 *infeasible = TRUE;
10586 return SCIP_OKAY;
10587 }
10588 else if( SCIPsetIsFeasLT(set, newub, ub) )
10589 {
10590 /* bound might be adjusted due to integrality condition */
10591 newub = adjustedUb(set, SCIPvarGetType(var), newub);
10592
10593 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10594 * with the local bound, in this case we need to store the bound change as pending bound change
10595 */
10597 {
10598 assert(tree != NULL);
10599 assert(transprob != NULL);
10600 assert(SCIPprobIsTransformed(transprob));
10601
10602 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10603 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10604 }
10605 else
10606 {
10607 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newub) );
10608 }
10609
10610 if( nbdchgs != NULL )
10611 (*nbdchgs)++;
10612 }
10613 }
10614 }
10615 }
10616 /* if the vub coefficient is zero, just update the upper bound of the variable */
10617 else if( SCIPsetIsZero(set, vubcoef) )
10618 {
10619 if( SCIPsetIsFeasLT(set, vubconstant, SCIPvarGetLbGlobal(var)) )
10620 *infeasible = TRUE;
10621 else if( SCIPsetIsFeasLT(set, vubconstant, SCIPvarGetUbGlobal(var)) )
10622 {
10623 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10624 * with the local bound, in this case we need to store the bound change as pending bound change
10625 */
10627 {
10628 assert(tree != NULL);
10629 assert(transprob != NULL);
10630 assert(SCIPprobIsTransformed(transprob));
10631
10632 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10633 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, vubconstant, SCIP_BOUNDTYPE_UPPER, FALSE) );
10634 }
10635 else
10636 {
10637 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, vubconstant) );
10638 }
10639
10640 if( nbdchgs != NULL )
10641 (*nbdchgs)++;
10642 }
10643 }
10644 else if( SCIPvarIsActive(vubvar) )
10645 {
10646 SCIP_Real xlb;
10647 SCIP_Real xub;
10648 SCIP_Real zlb;
10649 SCIP_Real zub;
10650 SCIP_Real minvub;
10651 SCIP_Real maxvub;
10652
10654 assert(vubcoef != 0.0);
10655
10656 minvub = -SCIPsetInfinity(set);
10657 maxvub = SCIPsetInfinity(set);
10658
10659 xlb = SCIPvarGetLbGlobal(var);
10660 xub = SCIPvarGetUbGlobal(var);
10661 zlb = SCIPvarGetLbGlobal(vubvar);
10662 zub = SCIPvarGetUbGlobal(vubvar);
10663
10664 /* improve global bounds of vub variable, and calculate minimal and maximal value of variable bound */
10665 if( vubcoef >= 0.0 )
10666 {
10667 SCIP_Real newzlb;
10668
10669 if( !SCIPsetIsInfinity(set, -xlb) )
10670 {
10671 /* x <= b*z + d -> z >= (x-d)/b */
10672 newzlb = (xlb - vubconstant)/vubcoef;
10673 if( SCIPsetIsFeasGT(set, newzlb, zub) )
10674 {
10675 *infeasible = TRUE;
10676 return SCIP_OKAY;
10677 }
10678 if( SCIPsetIsFeasGT(set, newzlb, zlb) )
10679 {
10680 /* bound might be adjusted due to integrality condition */
10681 newzlb = adjustedLb(set, SCIPvarGetType(vubvar), newzlb);
10682
10683 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10684 * with the local bound, in this case we need to store the bound change as pending bound change
10685 */
10687 {
10688 assert(tree != NULL);
10689 assert(transprob != NULL);
10690 assert(SCIPprobIsTransformed(transprob));
10691
10692 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10693 tree, reopt, lp, branchcand, eventqueue, cliquetable, vubvar, newzlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10694 }
10695 else
10696 {
10697 SCIP_CALL( SCIPvarChgLbGlobal(vubvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzlb) );
10698 }
10699 zlb = newzlb;
10700
10701 if( nbdchgs != NULL )
10702 (*nbdchgs)++;
10703 }
10704 minvub = vubcoef * zlb + vubconstant;
10705 if( !SCIPsetIsInfinity(set, zub) )
10706 maxvub = vubcoef * zub + vubconstant;
10707 }
10708 else
10709 {
10710 if( !SCIPsetIsInfinity(set, zub) )
10711 maxvub = vubcoef * zub + vubconstant;
10712 if( !SCIPsetIsInfinity(set, -zlb) )
10713 minvub = vubcoef * zlb + vubconstant;
10714 }
10715 }
10716 else
10717 {
10718 SCIP_Real newzub;
10719
10720 if( !SCIPsetIsInfinity(set, -xlb) )
10721 {
10722 /* x <= b*z + d -> z <= (x-d)/b */
10723 newzub = (xlb - vubconstant)/vubcoef;
10724 if( SCIPsetIsFeasLT(set, newzub, zlb) )
10725 {
10726 *infeasible = TRUE;
10727 return SCIP_OKAY;
10728 }
10729 if( SCIPsetIsFeasLT(set, newzub, zub) )
10730 {
10731 /* bound might be adjusted due to integrality condition */
10732 newzub = adjustedUb(set, SCIPvarGetType(vubvar), newzub);
10733
10734 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10735 * with the local bound, in this case we need to store the bound change as pending bound change
10736 */
10738 {
10739 assert(tree != NULL);
10740 assert(transprob != NULL);
10741 assert(SCIPprobIsTransformed(transprob));
10742
10743 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10744 tree, reopt, lp, branchcand, eventqueue, cliquetable, vubvar, newzub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10745 }
10746 else
10747 {
10748 SCIP_CALL( SCIPvarChgUbGlobal(vubvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzub) );
10749 }
10750 zub = newzub;
10751
10752 if( nbdchgs != NULL )
10753 (*nbdchgs)++;
10754 }
10755 minvub = vubcoef * zub + vubconstant;
10756 if( !SCIPsetIsInfinity(set, -zlb) )
10757 maxvub = vubcoef * zlb + vubconstant;
10758 }
10759 else
10760 {
10761 if( !SCIPsetIsInfinity(set, zub) )
10762 minvub = vubcoef * zub + vubconstant;
10763 if( !SCIPsetIsInfinity(set, -zlb) )
10764 maxvub = vubcoef * zlb + vubconstant;
10765 }
10766 }
10767 if( minvub > maxvub )
10768 minvub = maxvub;
10769
10770 /* adjust bounds due to integrality of vub variable */
10771 minvub = adjustedUb(set, SCIPvarGetType(var), minvub);
10772 maxvub = adjustedUb(set, SCIPvarGetType(var), maxvub);
10773
10774 /* check bounds for feasibility */
10775 if( SCIPsetIsFeasLT(set, maxvub, xlb) )
10776 {
10777 *infeasible = TRUE;
10778 return SCIP_OKAY;
10779 }
10780
10781 /* improve global upper bound of variable */
10782 if( SCIPsetIsFeasLT(set, maxvub, xub) )
10783 {
10784 /* bound might be adjusted due to integrality condition */
10785 maxvub = adjustedUb(set, SCIPvarGetType(var), maxvub);
10786
10787 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10788 * with the local bound, in this case we need to store the bound change as pending bound change
10789 */
10791 {
10792 assert(tree != NULL);
10793 assert(transprob != NULL);
10794 assert(SCIPprobIsTransformed(transprob));
10795
10796 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10797 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, maxvub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10798 }
10799 else
10800 {
10801 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, maxvub) );
10802 }
10803 xub = maxvub;
10804
10805 if( nbdchgs != NULL )
10806 (*nbdchgs)++;
10807 }
10808 maxvub = xub;
10809
10810 /* improve variable bound for binary z by moving the variable's global bound to the vub constant */
10811 if( SCIPvarIsBinary(vubvar) )
10812 {
10813 /* b > 0: x <= (maxvub - minvub) * z + minvub
10814 * b < 0: x <= (minvub - maxvub) * z + maxvub
10815 */
10816
10817 assert(!SCIPsetIsInfinity(set, maxvub) && !SCIPsetIsInfinity(set, -minvub));
10818
10819 if( vubcoef >= 0.0 )
10820 {
10821 vubcoef = maxvub - minvub;
10822 vubconstant = minvub;
10823 }
10824 else
10825 {
10826 vubcoef = minvub - maxvub;
10827 vubconstant = maxvub;
10828 }
10829 }
10830
10831 /* add variable bound to the variable bounds list */
10832 if( SCIPsetIsFeasLT(set, minvub, xub) )
10833 {
10834 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED);
10835 assert(!SCIPsetIsZero(set, vubcoef));
10836
10837 /* if one of the variables is binary, add the corresponding implication to the variable's implication
10838 * list, thereby also adding the variable bound (or implication) to the other variable
10839 */
10840 if( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY )
10841 {
10842 /* add corresponding implication:
10843 * b > 0, x <= b*z + d <-> z == 0 -> x <= d
10844 * b < 0, x <= b*z + d <-> z == 1 -> x <= b+d
10845 */
10846 SCIP_CALL( varAddTransitiveImplic(vubvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10847 cliquetable, branchcand, eventqueue, (vubcoef < 0.0), var, SCIP_BOUNDTYPE_UPPER, minvub, transitive,
10848 infeasible, nbdchgs) );
10849 }
10850 else if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
10851 {
10852 /* add corresponding implication:
10853 * b > 0, x <= b*z + d <-> x == 1 -> z >= (1-d)/b
10854 * b < 0, x <= b*z + d <-> x == 1 -> z <= (1-d)/b
10855 */
10856 SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10857 cliquetable, branchcand, eventqueue, TRUE, vubvar, (vubcoef >= 0.0 ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER),
10858 (1.0-vubconstant)/vubcoef, transitive, infeasible, nbdchgs) );
10859 }
10860 else
10861 {
10862 SCIP_CALL( varAddVbound(var, blkmem, set, eventqueue, SCIP_BOUNDTYPE_UPPER, vubvar, vubcoef, vubconstant) );
10863 }
10864 }
10865 }
10866 break;
10867
10869 /* x = a*y + c: x <= b*z + d <=> a*y + c <= b*z + d <=> y <= b/a * z + (d-c)/a, if a > 0
10870 * y >= b/a * z + (d-c)/a, if a < 0
10871 */
10872
10873 /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */
10874 SCIP_CALL( SCIPvarGetProbvarSum(&vubvar, set, &vubcoef, &vubconstant) );
10875
10876 /* if the variables cancel out, the variable bound constraint is redundant or proves global infeasibility */
10877 assert(var->data.aggregate.var != NULL);
10878 if( var->data.aggregate.var == vubvar && SCIPsetIsEQ(set, var->data.aggregate.scalar, vubcoef) )
10879 {
10880 if( SCIPsetIsFeasGT(set, var->data.aggregate.constant, vubconstant) )
10881 *infeasible = TRUE;
10882 }
10883 else if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
10884 {
10885 /* a > 0 -> add variable upper bound */
10886 SCIP_CALL( SCIPvarAddVub(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10887 cliquetable, branchcand, eventqueue, vubvar, vubcoef/var->data.aggregate.scalar,
10888 (vubconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10889 }
10890 else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
10891 {
10892 /* a < 0 -> add variable lower bound */
10893 SCIP_CALL( SCIPvarAddVlb(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10894 cliquetable, branchcand, eventqueue, vubvar, vubcoef/var->data.aggregate.scalar,
10895 (vubconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10896 }
10897 else
10898 {
10899 SCIPerrorMessage("scalar is zero in aggregation\n");
10900 return SCIP_INVALIDDATA;
10901 }
10902 break;
10903
10905 /* nothing to do here */
10906 break;
10907
10909 /* x = offset - x': x <= b*z + d <=> offset - x' <= b*z + d <=> x' >= -b*z + (offset-d) */
10910 assert(var->negatedvar != NULL);
10912 assert(var->negatedvar->negatedvar == var);
10913 SCIP_CALL( SCIPvarAddVlb(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10914 branchcand, eventqueue, vubvar, -vubcoef, var->data.negate.constant - vubconstant, transitive, infeasible,
10915 nbdchgs) );
10916 break;
10917
10918 default:
10919 SCIPerrorMessage("unknown variable status\n");
10920 return SCIP_INVALIDDATA;
10921 }
10922
10923 return SCIP_OKAY;
10924}
10925
10926/** informs binary variable x about a globally valid implication: x == 0 or x == 1 ==> y <= b or y >= b;
10927 * also adds the corresponding implication or variable bound to the implied variable;
10928 * if the implication is conflicting, the variable is fixed to the opposite value;
10929 * if the variable is already fixed to the given value, the implication is performed immediately;
10930 * if the implication is redundant with respect to the variables' global bounds, it is ignored
10931 */
10933 SCIP_VAR* var, /**< problem variable */
10934 BMS_BLKMEM* blkmem, /**< block memory */
10935 SCIP_SET* set, /**< global SCIP settings */
10936 SCIP_STAT* stat, /**< problem statistics */
10937 SCIP_PROB* transprob, /**< transformed problem */
10938 SCIP_PROB* origprob, /**< original problem */
10939 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
10940 SCIP_REOPT* reopt, /**< reoptimization data structure */
10941 SCIP_LP* lp, /**< current LP data */
10942 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
10943 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
10944 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
10945 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
10946 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
10947 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
10948 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
10949 SCIP_Bool transitive, /**< should transitive closure of implication also be added? */
10950 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
10951 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
10952 )
10953{
10954 assert(var != NULL);
10955 assert(set != NULL);
10956 assert(var->scip == set->scip);
10957 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
10958 assert(infeasible != NULL);
10959
10960 *infeasible = FALSE;
10961 if( nbdchgs != NULL )
10962 *nbdchgs = 0;
10963
10964 switch( SCIPvarGetStatus(var) )
10965 {
10967 assert(var->data.original.transvar != NULL);
10968 SCIP_CALL( SCIPvarAddImplic(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10969 cliquetable, branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible,
10970 nbdchgs) );
10971 break;
10972
10975 /* if the variable is fixed (although it has no FIXED status), and varfixing corresponds to the fixed value of
10976 * the variable, the implication can be applied directly;
10977 * otherwise, add implication to the implications list (and add inverse of implication to the implied variable)
10978 */
10979 if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
10980 {
10981 if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
10982 {
10983 SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
10984 cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) );
10985 }
10986 }
10987 else
10988 {
10989 SCIP_CALL( SCIPvarGetProbvarBound(&implvar, &implbound, &impltype) );
10990 SCIPvarAdjustBd(implvar, set, impltype, &implbound);
10991 if( SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED )
10992 {
10993 SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10994 branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible, nbdchgs) );
10995 }
10996 }
10997 break;
10998
11000 /* if varfixing corresponds to the fixed value of the variable, the implication can be applied directly */
11001 if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
11002 {
11003 SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
11004 cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) );
11005 }
11006 break;
11007
11009 /* implication added for x == 1:
11010 * x == 1 && x = 1*z + 0 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b
11011 * x == 1 && x = -1*z + 1 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b
11012 * implication added for x == 0:
11013 * x == 0 && x = 1*z + 0 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b
11014 * x == 0 && x = -1*z + 1 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b
11015 *
11016 * use only binary variables z
11017 */
11018 assert(var->data.aggregate.var != NULL);
11019 if( SCIPvarIsBinary(var->data.aggregate.var) )
11020 {
11021 assert( (SCIPsetIsEQ(set, var->data.aggregate.scalar, 1.0) && SCIPsetIsZero(set, var->data.aggregate.constant))
11022 || (SCIPsetIsEQ(set, var->data.aggregate.scalar, -1.0) && SCIPsetIsEQ(set, var->data.aggregate.constant, 1.0)) );
11023
11024 if( var->data.aggregate.scalar > 0 )
11025 {
11026 SCIP_CALL( SCIPvarAddImplic(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
11027 cliquetable, branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible,
11028 nbdchgs) );
11029 }
11030 else
11031 {
11032 SCIP_CALL( SCIPvarAddImplic(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
11033 cliquetable, branchcand, eventqueue, !varfixing, implvar, impltype, implbound, transitive, infeasible,
11034 nbdchgs) );
11035 }
11036 }
11037 break;
11038
11040 /* nothing to do here */
11041 break;
11042
11044 /* implication added for x == 1:
11045 * x == 1 && x = -1*z + 1 ==> y <= b or y >= b <==> z <= 0 ==> y <= b or y >= b
11046 * implication added for x == 0:
11047 * x == 0 && x = -1*z + 1 ==> y <= b or y >= b <==> z >= 1 ==> y <= b or y >= b
11048 */
11049 assert(var->negatedvar != NULL);
11051 assert(var->negatedvar->negatedvar == var);
11052 assert(SCIPvarIsBinary(var->negatedvar));
11053
11055 {
11056 SCIP_CALL( SCIPvarAddImplic(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
11057 cliquetable, branchcand, eventqueue, !varfixing, implvar, impltype, implbound, transitive, infeasible, nbdchgs) );
11058 }
11059 /* in case one both variables are not of binary type we have to add the implication as variable bounds */
11060 else
11061 {
11062 /* if the implied variable is of binary type exchange the variables */
11063 if( SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY )
11064 {
11065 SCIP_CALL( SCIPvarAddImplic(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
11066 branchcand, eventqueue, (impltype == SCIP_BOUNDTYPE_UPPER) ? TRUE : FALSE, var->negatedvar,
11067 varfixing ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER, varfixing ? 1.0 : 0.0, transitive,
11068 infeasible, nbdchgs) );
11069 }
11070 else
11071 {
11072 /* both variables are not of binary type but are implicit binary; in that case we can only add this
11073 * implication as variable bounds
11074 */
11075
11076 /* add variable lower bound on the negation of var */
11077 if( varfixing )
11078 {
11079 /* (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
11080 * as variable lower bound
11081 */
11082 SCIP_CALL( SCIPvarAddVlb(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
11083 cliquetable, branchcand, eventqueue, implvar, (impltype == SCIP_BOUNDTYPE_UPPER) ? 1.0 : -1.0,
11084 (impltype == SCIP_BOUNDTYPE_UPPER) ? 0.0 : 1.0, transitive, infeasible, nbdchgs) );
11085 }
11086 else
11087 {
11088 /* (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
11089 * as variable upper bound
11090 */
11091 SCIP_CALL( SCIPvarAddVub(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
11092 cliquetable, branchcand, eventqueue, implvar, (impltype == SCIP_BOUNDTYPE_UPPER) ? -1.0 : 1.0,
11093 (impltype == SCIP_BOUNDTYPE_UPPER) ? 1.0 : 0.0, transitive, infeasible, nbdchgs) );
11094 }
11095
11096 /* add variable bound on implvar */
11097 if( impltype == SCIP_BOUNDTYPE_UPPER )
11098 {
11099 /* (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
11100 * as variable upper bound
11101 */
11102 SCIP_CALL( SCIPvarAddVub(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
11103 branchcand, eventqueue, var->negatedvar, (varfixing) ? 1.0 : -1.0,
11104 (varfixing) ? 0.0 : 1.0, transitive, infeasible, nbdchgs) );
11105 }
11106 else
11107 {
11108 /* (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
11109 * as variable upper bound
11110 */
11111 SCIP_CALL( SCIPvarAddVlb(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
11112 branchcand, eventqueue, var->negatedvar, (varfixing) ? -1.0 : 1.0, (varfixing) ? 1.0 : 0.0,
11113 transitive, infeasible, nbdchgs) );
11114 }
11115 }
11116 }
11117 break;
11118
11119 default:
11120 SCIPerrorMessage("unknown variable status\n");
11121 return SCIP_INVALIDDATA;
11122 }
11123
11124 return SCIP_OKAY;
11125}
11126
11127/** returns whether there is an implication x == varfixing -> y <= b or y >= b in the implication graph;
11128 * implications that are represented as cliques in the clique table are not regarded (use SCIPvarsHaveCommonClique());
11129 * both variables must be active, variable x must be binary
11130 */
11132 SCIP_VAR* var, /**< problem variable x */
11133 SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
11134 SCIP_VAR* implvar, /**< variable y to search for */
11135 SCIP_BOUNDTYPE impltype /**< type of implication y <=/>= b to search for */
11136 )
11137{
11138 assert(var != NULL);
11139 assert(implvar != NULL);
11140 assert(SCIPvarIsActive(var));
11141 assert(SCIPvarIsActive(implvar));
11142 assert(SCIPvarIsBinary(var));
11143
11144 return var->implics != NULL && SCIPimplicsContainsImpl(var->implics, varfixing, implvar, impltype);
11145}
11146
11147/** returns whether there is an implication x == varfixing -> y == implvarfixing in the implication graph;
11148 * implications that are represented as cliques in the clique table are not regarded (use SCIPvarsHaveCommonClique());
11149 * both variables must be active binary variables
11150 */
11152 SCIP_VAR* var, /**< problem variable x */
11153 SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
11154 SCIP_VAR* implvar, /**< variable y to search for */
11155 SCIP_Bool implvarfixing /**< value of the implied variable to search for */
11156 )
11157{
11158 assert(SCIPvarIsBinary(implvar));
11159
11160 return SCIPvarHasImplic(var, varfixing, implvar, implvarfixing ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER);
11161}
11162
11163/** gets the values of b in implications x == varfixing -> y <= b or y >= b in the implication graph;
11164 * the values are set to SCIP_INVALID if there is no implied bound
11165 */
11167 SCIP_VAR* var, /**< problem variable x */
11168 SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
11169 SCIP_VAR* implvar, /**< variable y to search for */
11170 SCIP_Real* lb, /**< buffer to store the value of the implied lower bound */
11171 SCIP_Real* ub /**< buffer to store the value of the implied upper bound */
11172 )
11173{
11174 int lowerpos;
11175 int upperpos;
11176 SCIP_Real* bounds;
11177
11178 assert(lb != NULL);
11179 assert(ub != NULL);
11180
11181 *lb = SCIP_INVALID;
11182 *ub = SCIP_INVALID;
11183
11184 if( var->implics == NULL )
11185 return;
11186
11187 SCIPimplicsGetVarImplicPoss(var->implics, varfixing, implvar, &lowerpos, &upperpos);
11188 bounds = SCIPvarGetImplBounds(var, varfixing);
11189
11190 if( bounds == NULL )
11191 return;
11192
11193 if( lowerpos >= 0 )
11194 *lb = bounds[lowerpos];
11195
11196 if( upperpos >= 0 )
11197 *ub = bounds[upperpos];
11198}
11199
11200
11201/** fixes the bounds of a binary variable to the given value, counting bound changes and detecting infeasibility */
11203 SCIP_VAR* var, /**< problem variable */
11204 BMS_BLKMEM* blkmem, /**< block memory */
11205 SCIP_SET* set, /**< global SCIP settings */
11206 SCIP_STAT* stat, /**< problem statistics */
11207 SCIP_PROB* transprob, /**< transformed problem */
11208 SCIP_PROB* origprob, /**< original problem */
11209 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
11210 SCIP_REOPT* reopt, /**< reoptimization data structure */
11211 SCIP_LP* lp, /**< current LP data */
11212 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
11213 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
11214 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
11215 SCIP_Bool value, /**< value to fix variable to */
11216 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
11217 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
11218 )
11219{
11220 assert(var != NULL);
11221 assert(set != NULL);
11222 assert(var->scip == set->scip);
11223 assert(infeasible != NULL);
11224
11225 *infeasible = FALSE;
11226
11227 if( value == FALSE )
11228 {
11229 if( var->glbdom.lb > 0.5 )
11230 *infeasible = TRUE;
11231 else if( var->glbdom.ub > 0.5 )
11232 {
11233 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
11234 * with the local bound, in this case we need to store the bound change as pending bound change
11235 */
11237 {
11238 assert(tree != NULL);
11239 assert(transprob != NULL);
11240 assert(SCIPprobIsTransformed(transprob));
11241
11242 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
11243 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) );
11244 }
11245 else
11246 {
11247 SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 0.0) );
11248 }
11249
11250 if( nbdchgs != NULL )
11251 (*nbdchgs)++;
11252 }
11253 }
11254 else
11255 {
11256 if( var->glbdom.ub < 0.5 )
11257 *infeasible = TRUE;
11258 else if( var->glbdom.lb < 0.5 )
11259 {
11260 /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
11261 * with the local bound, in this case we need to store the bound change as pending bound change
11262 */
11264 {
11265 assert(tree != NULL);
11266 assert(transprob != NULL);
11267 assert(SCIPprobIsTransformed(transprob));
11268
11269 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
11270 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 1.0, SCIP_BOUNDTYPE_LOWER, FALSE) );
11271 }
11272 else
11273 {
11274 SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 1.0) );
11275 }
11276
11277 if( nbdchgs != NULL )
11278 (*nbdchgs)++;
11279 }
11280 }
11281
11282 return SCIP_OKAY;
11283}
11284
11285/** adds the variable to the given clique and updates the list of cliques the binary variable is member of;
11286 * if the variable now appears twice in the clique with the same value, it is fixed to the opposite value;
11287 * if the variable now appears twice in the clique with opposite values, all other variables are fixed to
11288 * the opposite of the value they take in the clique
11289 */
11291 SCIP_VAR* var, /**< problem variable */
11292 BMS_BLKMEM* blkmem, /**< block memory */
11293 SCIP_SET* set, /**< global SCIP settings */
11294 SCIP_STAT* stat, /**< problem statistics */
11295 SCIP_PROB* transprob, /**< transformed problem */
11296 SCIP_PROB* origprob, /**< original problem */
11297 SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
11298 SCIP_REOPT* reopt, /**< reoptimization data structure */
11299 SCIP_LP* lp, /**< current LP data */
11300 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
11301 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
11302 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
11303 SCIP_Bool value, /**< value of the variable in the clique */
11304 SCIP_CLIQUE* clique, /**< clique the variable should be added to */
11305 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
11306 int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
11307 )
11308{
11309 assert(var != NULL);
11310 assert(set != NULL);
11311 assert(var->scip == set->scip);
11312 assert(SCIPvarIsBinary(var));
11313 assert(infeasible != NULL);
11314
11315 *infeasible = FALSE;
11316
11317 /* get corresponding active problem variable */
11318 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
11323 assert(SCIPvarIsBinary(var));
11324
11325 /* only column and loose variables may be member of a clique */
11327 {
11328 SCIP_Bool doubleentry;
11329 SCIP_Bool oppositeentry;
11330
11331 /* add variable to clique */
11332 SCIP_CALL( SCIPcliqueAddVar(clique, blkmem, set, var, value, &doubleentry, &oppositeentry) );
11333
11334 /* add clique to variable's clique list */
11335 SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, value, clique) );
11336
11337 /* check consistency of cliquelist */
11339
11340 /* if the variable now appears twice with the same value in the clique, it can be fixed to the opposite value */
11341 if( doubleentry )
11342 {
11343 SCIP_CALL( SCIPvarFixBinary(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
11344 eventqueue, cliquetable, !value, infeasible, nbdchgs) );
11345 }
11346
11347 /* if the variable appears with both values in the clique, all other variables of the clique can be fixed
11348 * to the opposite of the value they take in the clique
11349 */
11350 if( oppositeentry )
11351 {
11352 SCIP_VAR** vars;
11353 SCIP_Bool* values;
11354 int nvars;
11355 int i;
11356
11357 nvars = SCIPcliqueGetNVars(clique);
11358 vars = SCIPcliqueGetVars(clique);
11359 values = SCIPcliqueGetValues(clique);
11360 for( i = 0; i < nvars && !(*infeasible); ++i )
11361 {
11362 if( vars[i] == var )
11363 continue;
11364
11365 SCIP_CALL( SCIPvarFixBinary(vars[i], blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
11366 eventqueue, cliquetable, !values[i], infeasible, nbdchgs) );
11367 }
11368 }
11369 }
11370
11371 return SCIP_OKAY;
11372}
11373
11374/** adds a filled clique to the cliquelists of all corresponding variables */
11376 SCIP_VAR** vars, /**< problem variables */
11377 SCIP_Bool* values, /**< values of the variables in the clique */
11378 int nvars, /**< number of problem variables */
11379 BMS_BLKMEM* blkmem, /**< block memory */
11380 SCIP_SET* set, /**< global SCIP settings */
11381 SCIP_CLIQUE* clique /**< clique that contains all given variables and values */
11382 )
11383{
11384 SCIP_VAR* var;
11385 int v;
11386
11387 assert(vars != NULL);
11388 assert(values != NULL);
11389 assert(nvars > 0);
11390 assert(set != NULL);
11391 assert(blkmem != NULL);
11392 assert(clique != NULL);
11393
11394 for( v = nvars - 1; v >= 0; --v )
11395 {
11396 var = vars[v];
11397 assert(SCIPvarIsBinary(var));
11399
11400 /* add clique to variable's clique list */
11401 SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, values[v], clique) );
11402
11403 /* check consistency of cliquelist */
11405 }
11406
11407 return SCIP_OKAY;
11408}
11409
11410/** adds a clique to the list of cliques of the given binary variable, but does not change the clique
11411 * itself
11412 */
11414 SCIP_VAR* var, /**< problem variable */
11415 BMS_BLKMEM* blkmem, /**< block memory */
11416 SCIP_SET* set, /**< global SCIP settings */
11417 SCIP_Bool value, /**< value of the variable in the clique */
11418 SCIP_CLIQUE* clique /**< clique that should be removed from the variable's clique list */
11419 )
11420{
11421 assert(var != NULL);
11422 assert(SCIPvarIsBinary(var));
11424
11425 /* add clique to variable's clique list */
11426 SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, value, clique) );
11427
11428 return SCIP_OKAY;
11429}
11430
11431
11432/** deletes a clique from the list of cliques the binary variable is member of, but does not change the clique
11433 * itself
11434 */
11436 SCIP_VAR* var, /**< problem variable */
11437 BMS_BLKMEM* blkmem, /**< block memory */
11438 SCIP_Bool value, /**< value of the variable in the clique */
11439 SCIP_CLIQUE* clique /**< clique that should be removed from the variable's clique list */
11440 )
11441{
11442 assert(var != NULL);
11443 assert(SCIPvarIsBinary(var));
11444
11445 /* delete clique from variable's clique list */
11446 SCIP_CALL( SCIPcliquelistDel(&var->cliquelist, blkmem, value, clique) );
11447
11448 return SCIP_OKAY;
11449}
11450
11451/** deletes the variable from the given clique and updates the list of cliques the binary variable is member of */
11453 SCIP_VAR* var, /**< problem variable */
11454 BMS_BLKMEM* blkmem, /**< block memory */
11455 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
11456 SCIP_Bool value, /**< value of the variable in the clique */
11457 SCIP_CLIQUE* clique /**< clique the variable should be removed from */
11458 )
11459{
11460 assert(var != NULL);
11461 assert(SCIPvarIsBinary(var));
11462
11463 /* get corresponding active problem variable */
11464 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
11469 assert(SCIPvarIsBinary(var));
11470
11471 /* only column and loose variables may be member of a clique */
11473 {
11474 /* delete clique from variable's clique list */
11475 SCIP_CALL( SCIPcliquelistDel(&var->cliquelist, blkmem, value, clique) );
11476
11477 /* delete variable from clique */
11478 SCIPcliqueDelVar(clique, cliquetable, var, value);
11479
11480 /* check consistency of cliquelist */
11482 }
11483
11484 return SCIP_OKAY;
11485}
11486
11487/** returns whether there is a clique that contains both given variable/value pairs;
11488 * the variables must be active binary variables;
11489 * if regardimplics is FALSE, only the cliques in the clique table are looked at;
11490 * if regardimplics is TRUE, both the cliques and the implications of the implication graph are regarded
11491 *
11492 * @note a variable with it's negated variable are NOT! in a clique
11493 * @note a variable with itself are in a clique
11494 */
11496 SCIP_VAR* var1, /**< first variable */
11497 SCIP_Bool value1, /**< value of first variable */
11498 SCIP_VAR* var2, /**< second variable */
11499 SCIP_Bool value2, /**< value of second variable */
11500 SCIP_Bool regardimplics /**< should the implication graph also be searched for a clique? */
11501 )
11502{
11503 assert(var1 != NULL);
11504 assert(var2 != NULL);
11505 assert(SCIPvarIsActive(var1));
11506 assert(SCIPvarIsActive(var2));
11507 assert(SCIPvarIsBinary(var1));
11508 assert(SCIPvarIsBinary(var2));
11509
11510 return (SCIPcliquelistsHaveCommonClique(var1->cliquelist, value1, var2->cliquelist, value2)
11511 || (regardimplics && SCIPvarHasImplic(var1, value1, var2, value2 ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER)));
11512}
11513
11514/** actually changes the branch factor of the variable and of all parent variables */
11515static
11517 SCIP_VAR* var, /**< problem variable */
11518 SCIP_SET* set, /**< global SCIP settings */
11519 SCIP_Real branchfactor /**< factor to weigh variable's branching score with */
11520 )
11521{
11522 SCIP_VAR* parentvar;
11523 SCIP_Real eps;
11524 int i;
11525
11526 assert(var != NULL);
11527 assert(set != NULL);
11528 assert(var->scip == set->scip);
11529
11530 /* only use positive values */
11532 branchfactor = MAX(branchfactor, eps);
11533
11534 SCIPsetDebugMsg(set, "process changing branch factor of <%s> from %f to %f\n", var->name, var->branchfactor, branchfactor);
11535
11536 if( SCIPsetIsEQ(set, branchfactor, var->branchfactor) )
11537 return SCIP_OKAY;
11538
11539 /* change the branch factor */
11540 var->branchfactor = branchfactor;
11541
11542 /* process parent variables */
11543 for( i = 0; i < var->nparentvars; ++i )
11544 {
11545 parentvar = var->parentvars[i];
11546 assert(parentvar != NULL);
11547
11548 switch( SCIPvarGetStatus(parentvar) )
11549 {
11551 /* do not change priorities across the border between transformed and original problem */
11552 break;
11553
11558 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
11559 SCIPABORT();
11560 return SCIP_INVALIDDATA; /*lint !e527*/
11561
11564 SCIP_CALL( varProcessChgBranchFactor(parentvar, set, branchfactor) );
11565 break;
11566
11567 default:
11568 SCIPerrorMessage("unknown variable status\n");
11569 SCIPABORT();
11570 return SCIP_ERROR; /*lint !e527*/
11571 }
11572 }
11573
11574 return SCIP_OKAY;
11575}
11576
11577/** sets the branch factor of the variable; this value can be used in the branching methods to scale the score
11578 * values of the variables; higher factor leads to a higher probability that this variable is chosen for branching
11579 */
11581 SCIP_VAR* var, /**< problem variable */
11582 SCIP_SET* set, /**< global SCIP settings */
11583 SCIP_Real branchfactor /**< factor to weigh variable's branching score with */
11584 )
11585{
11586 int v;
11587
11588 assert(var != NULL);
11589 assert(set != NULL);
11590 assert(var->scip == set->scip);
11591 assert(branchfactor >= 0.0);
11592
11593 SCIPdebugMessage("changing branch factor of <%s> from %g to %g\n", var->name, var->branchfactor, branchfactor);
11594
11595 if( SCIPsetIsEQ(set, var->branchfactor, branchfactor) )
11596 return SCIP_OKAY;
11597
11598 /* change priorities of attached variables */
11599 switch( SCIPvarGetStatus(var) )
11600 {
11602 if( var->data.original.transvar != NULL )
11603 {
11604 SCIP_CALL( SCIPvarChgBranchFactor(var->data.original.transvar, set, branchfactor) );
11605 }
11606 else
11607 {
11608 assert(set->stage == SCIP_STAGE_PROBLEM);
11609 var->branchfactor = branchfactor;
11610 }
11611 break;
11612
11616 SCIP_CALL( varProcessChgBranchFactor(var, set, branchfactor) );
11617 break;
11618
11620 assert(!var->donotaggr);
11621 assert(var->data.aggregate.var != NULL);
11622 SCIP_CALL( SCIPvarChgBranchFactor(var->data.aggregate.var, set, branchfactor) );
11623 break;
11624
11626 assert(!var->donotmultaggr);
11627 for( v = 0; v < var->data.multaggr.nvars; ++v )
11628 {
11629 SCIP_CALL( SCIPvarChgBranchFactor(var->data.multaggr.vars[v], set, branchfactor) );
11630 }
11631 break;
11632
11634 assert(var->negatedvar != NULL);
11636 assert(var->negatedvar->negatedvar == var);
11637 SCIP_CALL( SCIPvarChgBranchFactor(var->negatedvar, set, branchfactor) );
11638 break;
11639
11640 default:
11641 SCIPerrorMessage("unknown variable status\n");
11642 SCIPABORT();
11643 return SCIP_ERROR; /*lint !e527*/
11644 }
11645
11646 return SCIP_OKAY;
11647}
11648
11649/** actually changes the branch priority of the variable and of all parent variables */
11650static
11652 SCIP_VAR* var, /**< problem variable */
11653 int branchpriority /**< branching priority of the variable */
11654 )
11655{
11656 SCIP_VAR* parentvar;
11657 int i;
11658
11659 assert(var != NULL);
11660
11661 SCIPdebugMessage("process changing branch priority of <%s> from %d to %d\n",
11662 var->name, var->branchpriority, branchpriority);
11663
11664 if( branchpriority == var->branchpriority )
11665 return SCIP_OKAY;
11666
11667 /* change the branch priority */
11668 var->branchpriority = branchpriority;
11669
11670 /* process parent variables */
11671 for( i = 0; i < var->nparentvars; ++i )
11672 {
11673 parentvar = var->parentvars[i];
11674 assert(parentvar != NULL);
11675
11676 switch( SCIPvarGetStatus(parentvar) )
11677 {
11679 /* do not change priorities across the border between transformed and original problem */
11680 break;
11681
11686 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
11687 SCIPABORT();
11688 return SCIP_INVALIDDATA; /*lint !e527*/
11689
11692 SCIP_CALL( varProcessChgBranchPriority(parentvar, branchpriority) );
11693 break;
11694
11695 default:
11696 SCIPerrorMessage("unknown variable status\n");
11697 return SCIP_ERROR;
11698 }
11699 }
11700
11701 return SCIP_OKAY;
11702}
11703
11704/** sets the branch priority of the variable; variables with higher branch priority are always preferred to variables
11705 * with lower priority in selection of branching variable
11706 */
11708 SCIP_VAR* var, /**< problem variable */
11709 int branchpriority /**< branching priority of the variable */
11710 )
11711{
11712 int v;
11713
11714 assert(var != NULL);
11715
11716 SCIPdebugMessage("changing branch priority of <%s> from %d to %d\n", var->name, var->branchpriority, branchpriority);
11717
11718 if( var->branchpriority == branchpriority )
11719 return SCIP_OKAY;
11720
11721 /* change priorities of attached variables */
11722 switch( SCIPvarGetStatus(var) )
11723 {
11725 if( var->data.original.transvar != NULL )
11726 {
11727 SCIP_CALL( SCIPvarChgBranchPriority(var->data.original.transvar, branchpriority) );
11728 }
11729 else
11730 var->branchpriority = branchpriority;
11731 break;
11732
11736 SCIP_CALL( varProcessChgBranchPriority(var, branchpriority) );
11737 break;
11738
11740 assert(!var->donotaggr);
11741 assert(var->data.aggregate.var != NULL);
11742 SCIP_CALL( SCIPvarChgBranchPriority(var->data.aggregate.var, branchpriority) );
11743 break;
11744
11746 assert(!var->donotmultaggr);
11747 for( v = 0; v < var->data.multaggr.nvars; ++v )
11748 {
11749 SCIP_CALL( SCIPvarChgBranchPriority(var->data.multaggr.vars[v], branchpriority) );
11750 }
11751 break;
11752
11754 assert(var->negatedvar != NULL);
11756 assert(var->negatedvar->negatedvar == var);
11757 SCIP_CALL( SCIPvarChgBranchPriority(var->negatedvar, branchpriority) );
11758 break;
11759
11760 default:
11761 SCIPerrorMessage("unknown variable status\n");
11762 SCIPABORT();
11763 return SCIP_ERROR; /*lint !e527*/
11764 }
11765
11766 return SCIP_OKAY;
11767}
11768
11769/** actually changes the branch direction of the variable and of all parent variables */
11770static
11772 SCIP_VAR* var, /**< problem variable */
11773 SCIP_BRANCHDIR branchdirection /**< preferred branch direction of the variable (downwards, upwards, auto) */
11774 )
11775{
11776 SCIP_VAR* parentvar;
11777 int i;
11778
11779 assert(var != NULL);
11780
11781 SCIPdebugMessage("process changing branch direction of <%s> from %u to %d\n",
11782 var->name, var->branchdirection, branchdirection);
11783
11784 if( branchdirection == (SCIP_BRANCHDIR)var->branchdirection )
11785 return SCIP_OKAY;
11786
11787 /* change the branch direction */
11788 var->branchdirection = branchdirection; /*lint !e641*/
11789
11790 /* process parent variables */
11791 for( i = 0; i < var->nparentvars; ++i )
11792 {
11793 parentvar = var->parentvars[i];
11794 assert(parentvar != NULL);
11795
11796 switch( SCIPvarGetStatus(parentvar) )
11797 {
11799 /* do not change directions across the border between transformed and original problem */
11800 break;
11801
11806 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
11807 SCIPABORT();
11808 return SCIP_INVALIDDATA; /*lint !e527*/
11809
11811 if( parentvar->data.aggregate.scalar > 0.0 )
11812 {
11813 SCIP_CALL( varProcessChgBranchDirection(parentvar, branchdirection) );
11814 }
11815 else
11816 {
11817 SCIP_CALL( varProcessChgBranchDirection(parentvar, SCIPbranchdirOpposite(branchdirection)) );
11818 }
11819 break;
11820
11822 SCIP_CALL( varProcessChgBranchDirection(parentvar, SCIPbranchdirOpposite(branchdirection)) );
11823 break;
11824
11825 default:
11826 SCIPerrorMessage("unknown variable status\n");
11827 SCIPABORT();
11828 return SCIP_ERROR; /*lint !e527*/
11829 }
11830 }
11831
11832 return SCIP_OKAY;
11833}
11834
11835/** sets the branch direction of the variable; variables with higher branch direction are always preferred to variables
11836 * with lower direction in selection of branching variable
11837 */
11839 SCIP_VAR* var, /**< problem variable */
11840 SCIP_BRANCHDIR branchdirection /**< preferred branch direction of the variable (downwards, upwards, auto) */
11841 )
11842{
11843 int v;
11844
11845 assert(var != NULL);
11846
11847 SCIPdebugMessage("changing branch direction of <%s> from %u to %d\n", var->name, var->branchdirection, branchdirection);
11848
11849 if( (SCIP_BRANCHDIR)var->branchdirection == branchdirection )
11850 return SCIP_OKAY;
11851
11852 /* change directions of attached variables */
11853 switch( SCIPvarGetStatus(var) )
11854 {
11856 if( var->data.original.transvar != NULL )
11857 {
11858 SCIP_CALL( SCIPvarChgBranchDirection(var->data.original.transvar, branchdirection) );
11859 }
11860 else
11861 var->branchdirection = branchdirection; /*lint !e641*/
11862 break;
11863
11867 SCIP_CALL( varProcessChgBranchDirection(var, branchdirection) );
11868 break;
11869
11871 assert(!var->donotaggr);
11872 assert(var->data.aggregate.var != NULL);
11873 if( var->data.aggregate.scalar > 0.0 )
11874 {
11875 SCIP_CALL( SCIPvarChgBranchDirection(var->data.aggregate.var, branchdirection) );
11876 }
11877 else
11878 {
11880 }
11881 break;
11882
11884 assert(!var->donotmultaggr);
11885 for( v = 0; v < var->data.multaggr.nvars; ++v )
11886 {
11887 /* only update branching direction of aggregation variables, if they don't have a preferred direction yet */
11888 assert(var->data.multaggr.vars[v] != NULL);
11890 {
11891 if( var->data.multaggr.scalars[v] > 0.0 )
11892 {
11893 SCIP_CALL( SCIPvarChgBranchDirection(var->data.multaggr.vars[v], branchdirection) );
11894 }
11895 else
11896 {
11898 }
11899 }
11900 }
11901 break;
11902
11904 assert(var->negatedvar != NULL);
11906 assert(var->negatedvar->negatedvar == var);
11908 break;
11909
11910 default:
11911 SCIPerrorMessage("unknown variable status\n");
11912 SCIPABORT();
11913 return SCIP_ERROR; /*lint !e527*/
11914 }
11915
11916 return SCIP_OKAY;
11917}
11918
11919/** compares the index of two variables, only active, fixed or negated variables are allowed, if a variable
11920 * is negated then the index of the corresponding active variable is taken, returns -1 if first is
11921 * smaller than, and +1 if first is greater than second variable index; returns 0 if both indices
11922 * are equal, which means both variables are equal
11923 */
11925 SCIP_VAR* var1, /**< first problem variable */
11926 SCIP_VAR* var2 /**< second problem variable */
11927 )
11928{
11929 assert(var1 != NULL);
11930 assert(var2 != NULL);
11933
11935 var1 = SCIPvarGetNegatedVar(var1);
11937 var2 = SCIPvarGetNegatedVar(var2);
11938
11939 assert(var1 != NULL);
11940 assert(var2 != NULL);
11941
11942 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
11943 return -1;
11944 else if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
11945 return +1;
11946
11947 assert(var1 == var2);
11948 return 0;
11949}
11950
11951/** comparison method for sorting active and negated variables by non-decreasing index, active and negated
11952 * variables are handled as the same variables
11953 */
11954SCIP_DECL_SORTPTRCOMP(SCIPvarCompActiveAndNegated)
11955{
11956 return SCIPvarCompareActiveAndNegated((SCIP_VAR*)elem1, (SCIP_VAR*)elem2);
11957}
11958
11959/** compares the index of two variables, returns -1 if first is smaller than, and +1 if first is greater than second
11960 * variable index; returns 0 if both indices are equal, which means both variables are equal
11961 */
11963 SCIP_VAR* var1, /**< first problem variable */
11964 SCIP_VAR* var2 /**< second problem variable */
11965 )
11966{
11967 assert(var1 != NULL);
11968 assert(var2 != NULL);
11969
11970 if( var1->index < var2->index )
11971 return -1;
11972 else if( var1->index > var2->index )
11973 return +1;
11974 else
11975 {
11976 assert(var1 == var2);
11977 return 0;
11978 }
11979}
11980
11981/** comparison method for sorting variables by non-decreasing index */
11983{
11984 return SCIPvarCompare((SCIP_VAR*)elem1, (SCIP_VAR*)elem2);
11985}
11986
11987/** comparison method for sorting variables by non-decreasing objective coefficient */
11989{
11990 SCIP_Real obj1;
11991 SCIP_Real obj2;
11992
11993 obj1 = SCIPvarGetObj((SCIP_VAR*)elem1);
11994 obj2 = SCIPvarGetObj((SCIP_VAR*)elem2);
11995
11996 if( obj1 < obj2 )
11997 return -1;
11998 else if( obj1 > obj2 )
11999 return +1;
12000 else
12001 return 0;
12002}
12003
12004/** hash key retrieval function for variables */
12005SCIP_DECL_HASHGETKEY(SCIPvarGetHashkey)
12006{ /*lint --e{715}*/
12007 return elem;
12008}
12009
12010/** returns TRUE iff the indices of both variables are equal */
12011SCIP_DECL_HASHKEYEQ(SCIPvarIsHashkeyEq)
12012{ /*lint --e{715}*/
12013 if( key1 == key2 )
12014 return TRUE;
12015 return FALSE;
12016}
12017
12018/** returns the hash value of the key */
12019SCIP_DECL_HASHKEYVAL(SCIPvarGetHashkeyVal)
12020{ /*lint --e{715}*/
12021 assert( SCIPvarGetIndex((SCIP_VAR*) key) >= 0 );
12022 return (unsigned int) SCIPvarGetIndex((SCIP_VAR*) key);
12023}
12024
12025/** return for given variables all their active counterparts; all active variables will be pairwise different */
12027 SCIP_SET* set, /**< global SCIP settings */
12028 SCIP_VAR** vars, /**< variable array with given variables and as output all active
12029 * variables, if enough slots exist
12030 */
12031 int* nvars, /**< number of given variables, and as output number of active variables,
12032 * if enough slots exist
12033 */
12034 int varssize, /**< available slots in vars array */
12035 int* requiredsize /**< pointer to store the required array size for the active variables */
12036 )
12037{
12038 SCIP_VAR** activevars;
12039 int nactivevars;
12040 int activevarssize;
12041
12042 SCIP_VAR* var;
12043 int v;
12044
12045 SCIP_VAR** tmpvars;
12046 SCIP_VAR** multvars;
12047 int tmpvarssize;
12048 int ntmpvars;
12049 int noldtmpvars;
12050 int nmultvars;
12051
12052 assert(set != NULL);
12053 assert(nvars != NULL);
12054 assert(vars != NULL || *nvars == 0);
12055 assert(varssize >= *nvars);
12056 assert(requiredsize != NULL);
12057
12058 *requiredsize = 0;
12059
12060 if( *nvars == 0 )
12061 return SCIP_OKAY;
12062
12063 nactivevars = 0;
12064 activevarssize = *nvars;
12065 ntmpvars = *nvars;
12066 tmpvarssize = *nvars;
12067
12068 /* temporary memory */
12069 SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) );
12070 /* coverity[copy_paste_error] */
12071 SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpvars, vars, ntmpvars) );
12072
12073 noldtmpvars = ntmpvars;
12074
12075 /* sort all variables to combine equal variables easily */
12076 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
12077 for( v = ntmpvars - 1; v > 0; --v )
12078 {
12079 /* combine same variables */
12080 if( SCIPvarCompare(tmpvars[v], tmpvars[v - 1]) == 0 )
12081 {
12082 --ntmpvars;
12083 tmpvars[v] = tmpvars[ntmpvars];
12084 }
12085 }
12086 /* sort all variables again to combine equal variables later on */
12087 if( noldtmpvars > ntmpvars )
12088 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
12089
12090 /* collect for each variable the representation in active variables */
12091 while( ntmpvars >= 1 )
12092 {
12093 --ntmpvars;
12094 var = tmpvars[ntmpvars];
12095 assert( var != NULL );
12096
12097 switch( SCIPvarGetStatus(var) )
12098 {
12100 if( var->data.original.transvar == NULL )
12101 {
12102 SCIPerrorMessage("original variable has no transformed variable attached\n");
12103 SCIPABORT();
12104 return SCIP_INVALIDDATA; /*lint !e527*/
12105 }
12106 tmpvars[ntmpvars] = var->data.original.transvar;
12107 ++ntmpvars;
12108 break;
12109
12111 tmpvars[ntmpvars] = var->data.aggregate.var;
12112 ++ntmpvars;
12113 break;
12114
12116 tmpvars[ntmpvars] = var->negatedvar;
12117 ++ntmpvars;
12118 break;
12119
12122 /* check for space in temporary memory */
12123 if( nactivevars >= activevarssize )
12124 {
12125 activevarssize *= 2;
12126 SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) );
12127 assert(nactivevars < activevarssize);
12128 }
12129 activevars[nactivevars] = var;
12130 nactivevars++;
12131 break;
12132
12134 /* x = a_1*y_1 + ... + a_n*y_n + c */
12135 nmultvars = var->data.multaggr.nvars;
12136 multvars = var->data.multaggr.vars;
12137
12138 /* check for space in temporary memory */
12139 if( nmultvars + ntmpvars > tmpvarssize )
12140 {
12141 while( nmultvars + ntmpvars > tmpvarssize )
12142 tmpvarssize *= 2;
12143 SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) );
12144 assert(nmultvars + ntmpvars <= tmpvarssize);
12145 }
12146
12147 /* copy all multi-aggregation variables into our working array */
12148 BMScopyMemoryArray(&tmpvars[ntmpvars], multvars, nmultvars); /*lint !e866*/
12149
12150 /* get active, fixed or multi-aggregated corresponding variables for all new ones */
12151 SCIPvarsGetProbvar(&tmpvars[ntmpvars], nmultvars);
12152
12153 ntmpvars += nmultvars;
12154 noldtmpvars = ntmpvars;
12155
12156 /* sort all variables to combine equal variables easily */
12157 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
12158 for( v = ntmpvars - 1; v > 0; --v )
12159 {
12160 /* combine same variables */
12161 if( SCIPvarCompare(tmpvars[v], tmpvars[v - 1]) == 0 )
12162 {
12163 --ntmpvars;
12164 tmpvars[v] = tmpvars[ntmpvars];
12165 }
12166 }
12167 /* sort all variables again to combine equal variables later on */
12168 if( noldtmpvars > ntmpvars )
12169 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
12170
12171 break;
12172
12174 /* no need for memorizing fixed variables */
12175 break;
12176
12177 default:
12178 SCIPerrorMessage("unknown variable status\n");
12179 SCIPABORT();
12180 return SCIP_INVALIDDATA; /*lint !e527*/
12181 }
12182 }
12183
12184 /* sort variable array by variable index */
12185 SCIPsortPtr((void**)activevars, SCIPvarComp, nactivevars);
12186
12187 /* eliminate duplicates and count required size */
12188 v = nactivevars - 1;
12189 while( v > 0 )
12190 {
12191 /* combine both variable since they are the same */
12192 if( SCIPvarCompare(activevars[v - 1], activevars[v]) == 0 )
12193 {
12194 --nactivevars;
12195 activevars[v] = activevars[nactivevars];
12196 }
12197 --v;
12198 }
12199 *requiredsize = nactivevars;
12200
12201 if( varssize >= *requiredsize )
12202 {
12203 assert(vars != NULL);
12204
12205 *nvars = *requiredsize;
12206 BMScopyMemoryArray(vars, activevars, nactivevars);
12207 }
12208
12209 SCIPsetFreeBufferArray(set, &tmpvars);
12210 SCIPsetFreeBufferArray(set, &activevars);
12211
12212 return SCIP_OKAY;
12213}
12214
12215/** gets corresponding active, fixed, or multi-aggregated problem variables of given variables,
12216 * @note the content of the given array will/might change
12217 */
12219 SCIP_VAR** vars, /**< array of problem variables */
12220 int nvars /**< number of variables */
12221 )
12222{
12223 int v;
12224
12225 assert(vars != NULL || nvars == 0);
12226
12227 for( v = nvars - 1; v >= 0; --v )
12228 {
12229 assert(vars != NULL);
12230 assert(vars[v] != NULL);
12231
12232 vars[v] = SCIPvarGetProbvar(vars[v]);
12233 assert(vars[v] != NULL);
12234 }
12235}
12236
12237/** gets corresponding active, fixed, or multi-aggregated problem variable of a variable */
12239 SCIP_VAR* var /**< problem variable */
12240 )
12241{
12242 SCIP_VAR* retvar;
12243
12244 assert(var != NULL);
12245
12246 retvar = var;
12247
12248 SCIPdebugMessage("get problem variable of <%s>\n", var->name);
12249
12250 while( TRUE ) /*lint !e716 */
12251 {
12252 assert(retvar != NULL);
12253
12254 switch( SCIPvarGetStatus(retvar) )
12255 {
12257 if( retvar->data.original.transvar == NULL )
12258 {
12259 SCIPerrorMessage("original variable has no transformed variable attached\n");
12260 SCIPABORT();
12261 return NULL; /*lint !e527 */
12262 }
12263 retvar = retvar->data.original.transvar;
12264 break;
12265
12269 return retvar;
12270
12272 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12273 if ( retvar->data.multaggr.nvars == 1 )
12274 retvar = retvar->data.multaggr.vars[0];
12275 else
12276 return retvar;
12277 break;
12278
12280 retvar = retvar->data.aggregate.var;
12281 break;
12282
12284 retvar = retvar->negatedvar;
12285 break;
12286
12287 default:
12288 SCIPerrorMessage("unknown variable status\n");
12289 SCIPABORT();
12290 return NULL; /*lint !e527*/
12291 }
12292 }
12293}
12294
12295/** gets corresponding active, fixed, or multi-aggregated problem variables of binary variables and updates the given
12296 * negation status of each variable
12297 */
12299 SCIP_VAR*** vars, /**< pointer to binary problem variables */
12300 SCIP_Bool** negatedarr, /**< pointer to corresponding array to update the negation status */
12301 int nvars /**< number of variables and values in vars and negated array */
12302 )
12303{
12304 SCIP_VAR** var;
12305 SCIP_Bool* negated;
12306 int v;
12307
12308 assert(vars != NULL);
12309 assert(*vars != NULL || nvars == 0);
12310 assert(negatedarr != NULL);
12311 assert(*negatedarr != NULL || nvars == 0);
12312
12313 for( v = nvars - 1; v >= 0; --v )
12314 {
12315 var = &((*vars)[v]);
12316 negated = &((*negatedarr)[v]);
12317
12318 /* get problem variable */
12319 SCIP_CALL( SCIPvarGetProbvarBinary(var, negated) );
12320 }
12321
12322 return SCIP_OKAY;
12323}
12324
12325
12326/** gets corresponding active, fixed, or multi-aggregated problem variable of a binary variable and updates the given
12327 * negation status (this means you have to assign a value to SCIP_Bool negated before calling this method, usually
12328 * FALSE is used)
12329 */
12331 SCIP_VAR** var, /**< pointer to binary problem variable */
12332 SCIP_Bool* negated /**< pointer to update the negation status */
12333 )
12334{
12336#ifndef NDEBUG
12337 SCIP_Real constant = 0.0;
12338 SCIP_Bool orignegated;
12339#endif
12340
12341 assert(var != NULL);
12342 assert(*var != NULL);
12343 assert(negated != NULL);
12344 assert(SCIPvarIsBinary(*var));
12345
12346#ifndef NDEBUG
12347 orignegated = *negated;
12348#endif
12349
12350 while( !active && *var != NULL )
12351 {
12352 switch( SCIPvarGetStatus(*var) )
12353 {
12355 if( (*var)->data.original.transvar == NULL )
12356 return SCIP_OKAY;
12357 *var = (*var)->data.original.transvar;
12358 break;
12359
12363 active = TRUE;
12364 break;
12365
12367 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12368 if ( (*var)->data.multaggr.nvars == 1 )
12369 {
12370 assert( (*var)->data.multaggr.vars != NULL );
12371 assert( (*var)->data.multaggr.scalars != NULL );
12372 assert( SCIPvarIsBinary((*var)->data.multaggr.vars[0]) );
12373 assert(!EPSZ((*var)->data.multaggr.scalars[0], 1e-06));
12374
12375 /* if not all variables were fully propagated, it might happen that a variable is multi-aggregated to
12376 * another variable which needs to be fixed
12377 *
12378 * e.g. x = y - 1 => (x = 0 && y = 1)
12379 * e.g. x = y + 1 => (x = 1 && y = 0)
12380 *
12381 * is this special case we need to return the muti-aggregation
12382 */
12383 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)) )
12384 {
12385 assert(EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06));
12386 }
12387 else
12388 {
12389 /* @note due to fixations, a multi-aggregation can have a constant of zero and a negative scalar or even
12390 * a scalar in absolute value unequal to one, in this case this aggregation variable needs to be
12391 * fixed to zero, but this should be done by another enforcement; so not depending on the scalar,
12392 * we will return the aggregated variable;
12393 */
12394 if( !EPSEQ(REALABS((*var)->data.multaggr.scalars[0]), 1.0, 1e-06) )
12395 {
12396 active = TRUE;
12397 break;
12398 }
12399
12400 /* @note it may also happen that the constant is larger than 1 or smaller than 0, in that case the
12401 * aggregation variable needs to be fixed to one, but this should be done by another enforcement;
12402 * so if this is the case, we will return the aggregated variable
12403 */
12404 assert(EPSZ((*var)->data.multaggr.constant, 1e-06) || EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06)
12405 || EPSZ((*var)->data.multaggr.constant + (*var)->data.multaggr.scalars[0], 1e-06)
12406 || EPSEQ((*var)->data.multaggr.constant + (*var)->data.multaggr.scalars[0], 1.0, 1e-06));
12407
12408 if( !EPSZ((*var)->data.multaggr.constant, 1e-06) && !EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06) )
12409 {
12410 active = TRUE;
12411 break;
12412 }
12413
12414 assert(EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06) || EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06));
12415
12416 if( EPSZ((*var)->data.multaggr.constant, 1e-06) )
12417 {
12418 /* if the scalar is negative, either the aggregation variable is already fixed to zero or has at
12419 * least one uplock (that hopefully will enforce this fixation to zero); can it happen that this
12420 * variable itself is multi-aggregated again?
12421 */
12422 assert(EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06) ?
12423 ((SCIPvarGetUbGlobal((*var)->data.multaggr.vars[0]) < 0.5) ||
12424 SCIPvarGetNLocksUpType((*var)->data.multaggr.vars[0], SCIP_LOCKTYPE_MODEL) > 0) : TRUE);
12425 }
12426 else
12427 {
12428 assert(EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06));
12429#ifndef NDEBUG
12430 constant += (*negated) != orignegated ? -1.0 : 1.0;
12431#endif
12432
12433 *negated = !(*negated);
12434 }
12435 *var = (*var)->data.multaggr.vars[0];
12436 break;
12437 }
12438 }
12439 active = TRUE; /*lint !e838*/
12440 break;
12441
12442 case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */
12443 assert((*var)->data.aggregate.var != NULL);
12444 assert(EPSEQ((*var)->data.aggregate.scalar, 1.0, 1e-06) || EPSEQ((*var)->data.aggregate.scalar, -1.0, 1e-06));
12445 assert(EPSLE((*var)->data.aggregate.var->glbdom.ub - (*var)->data.aggregate.var->glbdom.lb, 1.0, 1e-06));
12446#ifndef NDEBUG
12447 constant += (*negated) != orignegated ? -(*var)->data.aggregate.constant : (*var)->data.aggregate.constant;
12448#endif
12449
12450 *negated = ((*var)->data.aggregate.scalar > 0.0) ? *negated : !(*negated);
12451 *var = (*var)->data.aggregate.var;
12452 break;
12453
12454 case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */
12455 assert((*var)->negatedvar != NULL);
12456#ifndef NDEBUG
12457 constant += (*negated) != orignegated ? -1.0 : 1.0;
12458#endif
12459
12460 *negated = !(*negated);
12461 *var = (*var)->negatedvar;
12462 break;
12463
12464 default:
12465 SCIPerrorMessage("unknown variable status\n");
12466 return SCIP_INVALIDDATA;
12467 }
12468 }
12469 assert(active == (*var != NULL));
12470
12471 if( active )
12472 {
12473 assert(SCIPvarIsBinary(*var));
12474 assert(EPSZ(constant, 1e-06) || EPSEQ(constant, 1.0, 1e-06));
12475 assert(EPSZ(constant, 1e-06) == ((*negated) == orignegated));
12476
12477 return SCIP_OKAY;
12478 }
12479 else
12480 {
12481 SCIPerrorMessage("active variable path leads to NULL pointer\n");
12482 return SCIP_INVALIDDATA;
12483 }
12484}
12485
12486/** transforms given variable, boundtype and bound to the corresponding active, fixed, or multi-aggregated variable
12487 * values
12488 */
12490 SCIP_VAR** var, /**< pointer to problem variable */
12491 SCIP_Real* bound, /**< pointer to bound value to transform */
12492 SCIP_BOUNDTYPE* boundtype /**< pointer to type of bound: lower or upper bound */
12493 )
12494{
12495 assert(var != NULL);
12496 assert(*var != NULL);
12497 assert(bound != NULL);
12498 assert(boundtype != NULL);
12499
12500 SCIPdebugMessage("get probvar bound %g of type %d of variable <%s>\n", *bound, *boundtype, (*var)->name);
12501
12502 switch( SCIPvarGetStatus(*var) )
12503 {
12505 if( (*var)->data.original.transvar == NULL )
12506 {
12507 SCIPerrorMessage("original variable has no transformed variable attached\n");
12508 return SCIP_INVALIDDATA;
12509 }
12510 *var = (*var)->data.original.transvar;
12511 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12512 break;
12513
12517 break;
12518
12520 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12521 if ( (*var)->data.multaggr.nvars == 1 )
12522 {
12523 assert( (*var)->data.multaggr.vars != NULL );
12524 assert( (*var)->data.multaggr.scalars != NULL );
12525 assert( (*var)->data.multaggr.scalars[0] != 0.0 );
12526
12527 (*bound) /= (*var)->data.multaggr.scalars[0];
12528 (*bound) -= (*var)->data.multaggr.constant/(*var)->data.multaggr.scalars[0];
12529 if ( (*var)->data.multaggr.scalars[0] < 0.0 )
12530 {
12531 if ( *boundtype == SCIP_BOUNDTYPE_LOWER )
12532 *boundtype = SCIP_BOUNDTYPE_UPPER;
12533 else
12534 *boundtype = SCIP_BOUNDTYPE_LOWER;
12535 }
12536 *var = (*var)->data.multaggr.vars[0];
12537 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12538 }
12539 break;
12540
12541 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = x/a - c/a */
12542 assert((*var)->data.aggregate.var != NULL);
12543 assert((*var)->data.aggregate.scalar != 0.0);
12544
12545 (*bound) /= (*var)->data.aggregate.scalar;
12546 (*bound) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
12547 if( (*var)->data.aggregate.scalar < 0.0 )
12548 {
12549 if( *boundtype == SCIP_BOUNDTYPE_LOWER )
12550 *boundtype = SCIP_BOUNDTYPE_UPPER;
12551 else
12552 *boundtype = SCIP_BOUNDTYPE_LOWER;
12553 }
12554 *var = (*var)->data.aggregate.var;
12555 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12556 break;
12557
12558 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12559 assert((*var)->negatedvar != NULL);
12560 assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
12561 assert((*var)->negatedvar->negatedvar == *var);
12562 (*bound) = (*var)->data.negate.constant - *bound;
12563 if( *boundtype == SCIP_BOUNDTYPE_LOWER )
12564 *boundtype = SCIP_BOUNDTYPE_UPPER;
12565 else
12566 *boundtype = SCIP_BOUNDTYPE_LOWER;
12567 *var = (*var)->negatedvar;
12568 SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12569 break;
12570
12571 default:
12572 SCIPerrorMessage("unknown variable status\n");
12573 return SCIP_INVALIDDATA;
12574 }
12575
12576 return SCIP_OKAY;
12577}
12578
12579/** transforms given variable and domain hole to the corresponding active, fixed, or multi-aggregated variable
12580 * values
12581 */
12583 SCIP_VAR** var, /**< pointer to problem variable */
12584 SCIP_Real* left, /**< pointer to left bound of open interval in hole to transform */
12585 SCIP_Real* right /**< pointer to right bound of open interval in hole to transform */
12586 )
12587{
12588 assert(var != NULL);
12589 assert(*var != NULL);
12590 assert(left != NULL);
12591 assert(right != NULL);
12592
12593 SCIPdebugMessage("get probvar hole (%g,%g) of variable <%s>\n", *left, *right, (*var)->name);
12594
12595 switch( SCIPvarGetStatus(*var) )
12596 {
12598 if( (*var)->data.original.transvar == NULL )
12599 {
12600 SCIPerrorMessage("original variable has no transformed variable attached\n");
12601 return SCIP_INVALIDDATA;
12602 }
12603 *var = (*var)->data.original.transvar;
12604 SCIP_CALL( SCIPvarGetProbvarHole(var, left, right) );
12605 break;
12606
12611 break;
12612
12613 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = x/a - c/a */
12614 assert((*var)->data.aggregate.var != NULL);
12615 assert((*var)->data.aggregate.scalar != 0.0);
12616
12617 /* scale back */
12618 (*left) /= (*var)->data.aggregate.scalar;
12619 (*right) /= (*var)->data.aggregate.scalar;
12620
12621 /* shift back */
12622 (*left) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
12623 (*right) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
12624
12625 *var = (*var)->data.aggregate.var;
12626
12627 /* check if the interval bounds have to swapped */
12628 if( (*var)->data.aggregate.scalar < 0.0 )
12629 {
12630 SCIP_CALL( SCIPvarGetProbvarHole(var, right, left) );
12631 }
12632 else
12633 {
12634 SCIP_CALL( SCIPvarGetProbvarHole(var, left, right) );
12635 }
12636 break;
12637
12638 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12639 assert((*var)->negatedvar != NULL);
12640 assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
12641 assert((*var)->negatedvar->negatedvar == *var);
12642
12643 /* shift and scale back */
12644 (*left) = (*var)->data.negate.constant - (*left);
12645 (*right) = (*var)->data.negate.constant - (*right);
12646
12647 *var = (*var)->negatedvar;
12648
12649 /* through the negated variable the left and right interval bound have to swapped */
12650 SCIP_CALL( SCIPvarGetProbvarHole(var, right, left) );
12651 break;
12652
12653 default:
12654 SCIPerrorMessage("unknown variable status\n");
12655 return SCIP_INVALIDDATA;
12656 }
12657
12658 return SCIP_OKAY;
12659}
12660
12661/** transforms given variable, scalar and constant to the corresponding active, fixed, or
12662 * multi-aggregated variable, scalar and constant; if the variable resolves to a fixed variable,
12663 * "scalar" will be 0.0 and the value of the sum will be stored in "constant"; a multi-aggregation
12664 * with only one active variable (this can happen due to fixings after the multi-aggregation),
12665 * is treated like an aggregation; if the multi-aggregation constant is infinite, "scalar" will be 0.0
12666 */
12668 SCIP_VAR** var, /**< pointer to problem variable x in sum a*x + c */
12669 SCIP_SET* set, /**< global SCIP settings */
12670 SCIP_Real* scalar, /**< pointer to scalar a in sum a*x + c */
12671 SCIP_Real* constant /**< pointer to constant c in sum a*x + c */
12672 )
12673{
12674 assert(var != NULL);
12675 assert(scalar != NULL);
12676 assert(constant != NULL);
12677
12678 while( *var != NULL )
12679 {
12680 switch( SCIPvarGetStatus(*var) )
12681 {
12683 if( (*var)->data.original.transvar == NULL )
12684 {
12685 SCIPerrorMessage("original variable has no transformed variable attached\n");
12686 return SCIP_INVALIDDATA;
12687 }
12688 *var = (*var)->data.original.transvar;
12689 break;
12690
12693 return SCIP_OKAY;
12694
12695 case SCIP_VARSTATUS_FIXED: /* x = c' => a*x + c == (a*c' + c) */
12696 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12697 {
12698 if( SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)) )
12699 {
12700 assert(*scalar != 0.0);
12701 if( (*scalar) * (*var)->glbdom.lb > 0.0 )
12702 (*constant) = SCIPsetInfinity(set);
12703 else
12704 (*constant) = -SCIPsetInfinity(set);
12705 }
12706 else
12707 (*constant) += *scalar * (*var)->glbdom.lb;
12708 }
12709#ifndef NDEBUG
12710 else
12711 {
12712 assert(!SCIPsetIsInfinity(set, (*constant)) || !((*scalar) * (*var)->glbdom.lb < 0.0 &&
12713 (SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)))));
12714 assert(!SCIPsetIsInfinity(set, -(*constant)) || !((*scalar) * (*var)->glbdom.lb > 0.0 &&
12715 (SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)))));
12716 }
12717#endif
12718 *scalar = 0.0;
12719 return SCIP_OKAY;
12720
12722 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12723 if ( (*var)->data.multaggr.nvars == 1 )
12724 {
12725 assert((*var)->data.multaggr.vars != NULL);
12726 assert((*var)->data.multaggr.scalars != NULL);
12727 assert((*var)->data.multaggr.vars[0] != NULL);
12728 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12729 {
12730 /* the multi-aggregation constant can be infinite, if one of the multi-aggregation variables
12731 * was fixed to +/-infinity; ensure that the constant is set to +/-infinity, too, and the scalar
12732 * is set to 0.0, because the multi-aggregated variable can be seen as fixed, too
12733 */
12734 if( SCIPsetIsInfinity(set, (*var)->data.multaggr.constant)
12735 || SCIPsetIsInfinity(set, -((*var)->data.multaggr.constant)) )
12736 {
12737 if( (*scalar) * (*var)->data.multaggr.constant > 0 )
12738 {
12739 assert(!SCIPsetIsInfinity(set, -(*constant)));
12740 (*constant) = SCIPsetInfinity(set);
12741 }
12742 else
12743 {
12744 assert(!SCIPsetIsInfinity(set, *constant));
12745 (*constant) = -SCIPsetInfinity(set);
12746 }
12747 (*scalar) = 0.0;
12748 }
12749 else
12750 (*constant) += *scalar * (*var)->data.multaggr.constant;
12751 }
12752 (*scalar) *= (*var)->data.multaggr.scalars[0];
12753 *var = (*var)->data.multaggr.vars[0];
12754 break;
12755 }
12756 return SCIP_OKAY;
12757
12758 case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */
12759 assert((*var)->data.aggregate.var != NULL);
12760 assert(!SCIPsetIsInfinity(set, (*var)->data.aggregate.constant)
12761 && !SCIPsetIsInfinity(set, (*var)->data.aggregate.constant));
12762 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12763 (*constant) += *scalar * (*var)->data.aggregate.constant;
12764 (*scalar) *= (*var)->data.aggregate.scalar;
12765 *var = (*var)->data.aggregate.var;
12766 break;
12767
12768 case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */
12769 assert((*var)->negatedvar != NULL);
12770 assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
12771 assert((*var)->negatedvar->negatedvar == *var);
12772 assert(!SCIPsetIsInfinity(set, (*var)->data.negate.constant)
12773 && !SCIPsetIsInfinity(set, (*var)->data.negate.constant));
12774 if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12775 (*constant) += *scalar * (*var)->data.negate.constant;
12776 (*scalar) *= -1.0;
12777 *var = (*var)->negatedvar;
12778 break;
12779
12780 default:
12781 SCIPerrorMessage("unknown variable status\n");
12782 SCIPABORT();
12783 return SCIP_INVALIDDATA; /*lint !e527*/
12784 }
12785 }
12786 *scalar = 0.0;
12787
12788 return SCIP_OKAY;
12789}
12790
12791/** retransforms given variable, scalar and constant to the corresponding original variable, scalar
12792 * and constant, if possible; if the retransformation is impossible, NULL is returned as variable
12793 */
12795 SCIP_VAR** var, /**< pointer to problem variable x in sum a*x + c */
12796 SCIP_Real* scalar, /**< pointer to scalar a in sum a*x + c */
12797 SCIP_Real* constant /**< pointer to constant c in sum a*x + c */
12798 )
12799{
12800 SCIP_VAR* parentvar;
12801
12802 assert(var != NULL);
12803 assert(*var != NULL);
12804 assert(scalar != NULL);
12805 assert(constant != NULL);
12806
12807 while( !SCIPvarIsOriginal(*var) )
12808 {
12809 /* if the variable has no parent variables, it was generated during solving and has no corresponding original
12810 * var
12811 */
12812 if( (*var)->nparentvars == 0 )
12813 {
12814 /* negated variables do not need to have a parent variables, and negated variables can exist in original
12815 * space
12816 */
12818 ((*var)->negatedvar->nparentvars == 0 || (*var)->negatedvar->parentvars[0] != *var) )
12819 {
12820 *scalar *= -1.0;
12821 *constant -= (*var)->data.negate.constant * (*scalar);
12822 *var = (*var)->negatedvar;
12823
12824 continue;
12825 }
12826 /* if the variables does not have any parent the variables was created during solving and has no original
12827 * counterpart
12828 */
12829 else
12830 {
12831 *var = NULL;
12832
12833 return SCIP_OKAY;
12834 }
12835 }
12836
12837 /* follow the link to the first parent variable */
12838 parentvar = (*var)->parentvars[0];
12839 assert(parentvar != NULL);
12840
12841 switch( SCIPvarGetStatus(parentvar) )
12842 {
12844 break;
12845
12850 SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
12851 return SCIP_INVALIDDATA;
12852
12853 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + b -> y = (x-b)/a, s*y + c = (s/a)*x + c-b*s/a */
12854 assert(parentvar->data.aggregate.var == *var);
12855 assert(parentvar->data.aggregate.scalar != 0.0);
12856 *scalar /= parentvar->data.aggregate.scalar;
12857 *constant -= parentvar->data.aggregate.constant * (*scalar);
12858 break;
12859
12860 case SCIP_VARSTATUS_NEGATED: /* x = b - y -> y = b - x, s*y + c = -s*x + c+b*s */
12861 assert(parentvar->negatedvar != NULL);
12862 assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
12863 assert(parentvar->negatedvar->negatedvar == parentvar);
12864 *scalar *= -1.0;
12865 *constant -= parentvar->data.negate.constant * (*scalar);
12866 break;
12867
12868 default:
12869 SCIPerrorMessage("unknown variable status\n");
12870 return SCIP_INVALIDDATA;
12871 }
12872
12873 assert( parentvar != NULL );
12874 *var = parentvar;
12875 }
12876
12877 return SCIP_OKAY;
12878}
12879
12880/** returns whether the given variable is the direct counterpart of an original problem variable */
12882 SCIP_VAR* var /**< problem variable */
12883 )
12884{
12885 SCIP_VAR* parentvar;
12886 assert(var != NULL);
12887
12888 if( !SCIPvarIsTransformed(var) || var->nparentvars < 1 )
12889 return FALSE;
12890
12891 assert(var->parentvars != NULL);
12892 parentvar = var->parentvars[0];
12893 assert(parentvar != NULL);
12894
12895 /* we follow the aggregation tree to the root unless an original variable has been found - the first entries in the parentlist are candidates */
12896 while( parentvar->nparentvars >= 1 && SCIPvarGetStatus(parentvar) != SCIP_VARSTATUS_ORIGINAL )
12897 parentvar = parentvar->parentvars[0];
12898 assert( parentvar != NULL );
12899
12900 return ( SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_ORIGINAL );
12901}
12902
12903/** gets objective value of variable in current SCIP_LP; the value can be different from the objective value stored in
12904 * the variable's own data due to diving, that operate only on the LP without updating the variables
12905 */
12907 SCIP_VAR* var /**< problem variable */
12908 )
12909{
12910 assert(var != NULL);
12911
12912 /* get bounds of attached variables */
12913 switch( SCIPvarGetStatus(var) )
12914 {
12916 assert(var->data.original.transvar != NULL);
12918
12920 assert(var->data.col != NULL);
12921 return SCIPcolGetObj(var->data.col);
12922
12925 return var->obj;
12926
12927 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
12928 assert(var->data.aggregate.var != NULL);
12930
12932 SCIPerrorMessage("cannot get the objective value of a multiple aggregated variable\n");
12933 SCIPABORT();
12934 return 0.0; /*lint !e527*/
12935
12936 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
12937 assert(var->negatedvar != NULL);
12939 assert(var->negatedvar->negatedvar == var);
12940 return -SCIPvarGetObjLP(var->negatedvar);
12941
12942 default:
12943 SCIPerrorMessage("unknown variable status\n");
12944 SCIPABORT();
12945 return 0.0; /*lint !e527*/
12946 }
12947}
12948
12949/** gets lower bound of variable in current SCIP_LP; the bound can be different from the bound stored in the variable's own
12950 * data due to diving or conflict analysis, that operate only on the LP without updating the variables
12951 */
12953 SCIP_VAR* var, /**< problem variable */
12954 SCIP_SET* set /**< global SCIP settings */
12955 )
12956{
12957 assert(var != NULL);
12958 assert(set != NULL);
12959 assert(var->scip == set->scip);
12960
12961 /* get bounds of attached variables */
12962 switch( SCIPvarGetStatus(var) )
12963 {
12965 assert(var->data.original.transvar != NULL);
12966 return SCIPvarGetLbLP(var->data.original.transvar, set);
12967
12969 assert(var->data.col != NULL);
12970 return SCIPcolGetLb(var->data.col);
12971
12974 return var->locdom.lb;
12975
12976 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
12977 assert(var->data.aggregate.var != NULL);
12980 {
12981 return -SCIPsetInfinity(set);
12982 }
12983 else if( var->data.aggregate.scalar > 0.0 )
12984 {
12985 /* a > 0 -> get lower bound of y */
12987 }
12988 else if( var->data.aggregate.scalar < 0.0 )
12989 {
12990 /* a < 0 -> get upper bound of y */
12992 }
12993 else
12994 {
12995 SCIPerrorMessage("scalar is zero in aggregation\n");
12996 SCIPABORT();
12997 return SCIP_INVALID; /*lint !e527*/
12998 }
12999
13001 /**@todo get the sides of the corresponding linear constraint */
13002 SCIPerrorMessage("getting the bounds of a multiple aggregated variable is not implemented yet\n");
13003 SCIPABORT();
13004 return SCIP_INVALID; /*lint !e527*/
13005
13006 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13007 assert(var->negatedvar != NULL);
13009 assert(var->negatedvar->negatedvar == var);
13010 return var->data.negate.constant - SCIPvarGetUbLP(var->negatedvar, set);
13011
13012 default:
13013 SCIPerrorMessage("unknown variable status\n");
13014 SCIPABORT();
13015 return SCIP_INVALID; /*lint !e527*/
13016 }
13017}
13018
13019/** gets upper bound of variable in current SCIP_LP; the bound can be different from the bound stored in the variable's own
13020 * data due to diving or conflict analysis, that operate only on the LP without updating the variables
13021 */
13023 SCIP_VAR* var, /**< problem variable */
13024 SCIP_SET* set /**< global SCIP settings */
13025 )
13026{
13027 assert(var != NULL);
13028 assert(set != NULL);
13029 assert(var->scip == set->scip);
13030
13031 /* get bounds of attached variables */
13032 switch( SCIPvarGetStatus(var) )
13033 {
13035 assert(var->data.original.transvar != NULL);
13036 return SCIPvarGetUbLP(var->data.original.transvar, set);
13037
13039 assert(var->data.col != NULL);
13040 return SCIPcolGetUb(var->data.col);
13041
13044 return var->locdom.ub;
13045
13046 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
13047 assert(var->data.aggregate.var != NULL);
13050 {
13051 return SCIPsetInfinity(set);
13052 }
13053 if( var->data.aggregate.scalar > 0.0 )
13054 {
13055 /* a > 0 -> get upper bound of y */
13057 }
13058 else if( var->data.aggregate.scalar < 0.0 )
13059 {
13060 /* a < 0 -> get lower bound of y */
13062 }
13063 else
13064 {
13065 SCIPerrorMessage("scalar is zero in aggregation\n");
13066 SCIPABORT();
13067 return SCIP_INVALID; /*lint !e527*/
13068 }
13069
13071 SCIPerrorMessage("cannot get the bounds of a multi-aggregated variable.\n");
13072 SCIPABORT();
13073 return SCIP_INVALID; /*lint !e527*/
13074
13075 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13076 assert(var->negatedvar != NULL);
13078 assert(var->negatedvar->negatedvar == var);
13079 return var->data.negate.constant - SCIPvarGetLbLP(var->negatedvar, set);
13080
13081 default:
13082 SCIPerrorMessage("unknown variable status\n");
13083 SCIPABORT();
13084 return SCIP_INVALID; /*lint !e527*/
13085 }
13086}
13087
13088/** gets primal LP solution value of variable */
13090 SCIP_VAR* var /**< problem variable */
13091 )
13092{
13093 assert(var != NULL);
13094
13095 switch( SCIPvarGetStatus(var) )
13096 {
13098 if( var->data.original.transvar == NULL )
13099 return SCIP_INVALID;
13101
13103 return SCIPvarGetBestBoundLocal(var);
13104
13106 assert(var->data.col != NULL);
13107 return SCIPcolGetPrimsol(var->data.col);
13108
13110 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13111 return var->locdom.lb;
13112
13114 {
13115 SCIP_Real lpsolval;
13116
13117 assert(!var->donotaggr);
13118 assert(var->data.aggregate.var != NULL);
13119 lpsolval = SCIPvarGetLPSol(var->data.aggregate.var);
13120
13121 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
13122 * corresponding infinity value instead of performing an arithmetical transformation (compare method
13123 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
13124 * (or is called by) a public interface method; instead, we only assert that values are finite
13125 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
13126 * positives and negatives if the parameter <numerics/infinity> is modified by the user
13127 */
13128 assert(lpsolval > -SCIP_DEFAULT_INFINITY);
13129 assert(lpsolval < +SCIP_DEFAULT_INFINITY);
13130 return var->data.aggregate.scalar * lpsolval + var->data.aggregate.constant;
13131 }
13133 {
13134 SCIP_Real primsol;
13135 int i;
13136
13137 assert(!var->donotmultaggr);
13138 assert(var->data.multaggr.vars != NULL);
13139 assert(var->data.multaggr.scalars != NULL);
13140 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13141 * assert(var->data.multaggr.nvars >= 2);
13142 */
13143 primsol = var->data.multaggr.constant;
13144 for( i = 0; i < var->data.multaggr.nvars; ++i )
13145 primsol += var->data.multaggr.scalars[i] * SCIPvarGetLPSol(var->data.multaggr.vars[i]);
13146 return primsol;
13147 }
13148 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13149 assert(var->negatedvar != NULL);
13151 assert(var->negatedvar->negatedvar == var);
13152 return var->data.negate.constant - SCIPvarGetLPSol(var->negatedvar);
13153
13154 default:
13155 SCIPerrorMessage("unknown variable status\n");
13156 SCIPABORT();
13157 return SCIP_INVALID; /*lint !e527*/
13158 }
13159}
13160
13161/** gets primal NLP solution value of variable */
13163 SCIP_VAR* var /**< problem variable */
13164 )
13165{
13166 SCIP_Real solval;
13167 int i;
13168
13169 assert(var != NULL);
13170
13171 /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */
13172 switch( SCIPvarGetStatus(var) )
13173 {
13176
13179 return var->nlpsol;
13180
13182 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var)); /*lint !e777*/
13183 assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var)); /*lint !e777*/
13184 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var)); /*lint !e777*/
13185 return SCIPvarGetLbGlobal(var);
13186
13187 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
13188 solval = SCIPvarGetNLPSol(var->data.aggregate.var);
13189 return var->data.aggregate.scalar * solval + var->data.aggregate.constant;
13190
13192 solval = var->data.multaggr.constant;
13193 for( i = 0; i < var->data.multaggr.nvars; ++i )
13194 solval += var->data.multaggr.scalars[i] * SCIPvarGetNLPSol(var->data.multaggr.vars[i]);
13195 return solval;
13196
13198 solval = SCIPvarGetNLPSol(var->negatedvar);
13199 return var->data.negate.constant - solval;
13200
13201 default:
13202 SCIPerrorMessage("unknown variable status\n");
13203 SCIPABORT();
13204 return SCIP_INVALID; /*lint !e527*/
13205 }
13206}
13207
13208/** gets pseudo solution value of variable at current node */
13209static
13211 SCIP_VAR* var /**< problem variable */
13212 )
13213{
13214 SCIP_Real pseudosol;
13215 int i;
13216
13217 assert(var != NULL);
13218
13219 switch( SCIPvarGetStatus(var) )
13220 {
13222 if( var->data.original.transvar == NULL )
13223 return SCIP_INVALID;
13225
13228 return SCIPvarGetBestBoundLocal(var);
13229
13231 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13232 return var->locdom.lb;
13233
13235 {
13236 SCIP_Real pseudosolval;
13237 assert(!var->donotaggr);
13238 assert(var->data.aggregate.var != NULL);
13239 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
13240 * corresponding infinity value instead of performing an arithmetical transformation (compare method
13241 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
13242 * (or is called by) a public interface method; instead, we only assert that values are finite
13243 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
13244 * positives and negatives if the parameter <numerics/infinity> is modified by the user
13245 */
13246 pseudosolval = SCIPvarGetPseudoSol(var->data.aggregate.var);
13247 assert(pseudosolval > -SCIP_DEFAULT_INFINITY);
13248 assert(pseudosolval < +SCIP_DEFAULT_INFINITY);
13249 return var->data.aggregate.scalar * pseudosolval + var->data.aggregate.constant;
13250 }
13252 assert(!var->donotmultaggr);
13253 assert(var->data.multaggr.vars != NULL);
13254 assert(var->data.multaggr.scalars != NULL);
13255 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13256 * assert(var->data.multaggr.nvars >= 2);
13257 */
13258 pseudosol = var->data.multaggr.constant;
13259 for( i = 0; i < var->data.multaggr.nvars; ++i )
13260 pseudosol += var->data.multaggr.scalars[i] * SCIPvarGetPseudoSol(var->data.multaggr.vars[i]);
13261 return pseudosol;
13262
13263 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13264 assert(var->negatedvar != NULL);
13266 assert(var->negatedvar->negatedvar == var);
13268
13269 default:
13270 SCIPerrorMessage("unknown variable status\n");
13271 SCIPABORT();
13272 return SCIP_INVALID; /*lint !e527*/
13273 }
13274}
13275
13276/** gets current LP or pseudo solution value of variable */
13278 SCIP_VAR* var, /**< problem variable */
13279 SCIP_Bool getlpval /**< should the LP solution value be returned? */
13280 )
13281{
13282 if( getlpval )
13283 return SCIPvarGetLPSol(var);
13284 else
13285 return SCIPvarGetPseudoSol(var);
13286}
13287
13288/** remembers the current solution as root solution in the problem variables */
13290 SCIP_VAR* var, /**< problem variable */
13291 SCIP_Bool roothaslp /**< is the root solution from LP? */
13292 )
13293{
13294 assert(var != NULL);
13295
13296 var->rootsol = SCIPvarGetSol(var, roothaslp);
13297}
13298
13299/** updates the current solution as best root solution of the given variable if it is better */
13301 SCIP_VAR* var, /**< problem variable */
13302 SCIP_SET* set, /**< global SCIP settings */
13303 SCIP_Real rootsol, /**< root solution value */
13304 SCIP_Real rootredcost, /**< root reduced cost */
13305 SCIP_Real rootlpobjval /**< objective value of the root LP */
13306 )
13307{
13308 assert(var != NULL);
13309 assert(set != NULL);
13310 assert(var->scip == set->scip);
13311
13312 /* if reduced cost are zero nothing to update */
13313 if( SCIPsetIsDualfeasZero(set, rootredcost) )
13314 return;
13315
13316 /* check if we have already a best combination stored */
13318 {
13319 SCIP_Real currcutoffbound;
13320 SCIP_Real cutoffbound;
13322
13323 /* compute the cutoff bound which would improve the corresponding bound with the current stored root solution,
13324 * root reduced cost, and root LP objective value combination
13325 */
13326 if( var->bestrootredcost > 0.0 )
13328 else
13330
13331 currcutoffbound = (bound - var->bestrootsol) * var->bestrootredcost + var->bestrootlpobjval;
13332
13333 /* compute the cutoff bound which would improve the corresponding bound with new root solution, root reduced
13334 * cost, and root LP objective value combination
13335 */
13336 if( rootredcost > 0.0 )
13338 else
13340
13341 cutoffbound = (bound - rootsol) * rootredcost + rootlpobjval;
13342
13343 /* check if an improving root solution, root reduced cost, and root LP objective value is at hand */
13344 if( cutoffbound > currcutoffbound )
13345 {
13346 SCIPsetDebugMsg(set, "-> <%s> update potential cutoff bound <%g> -> <%g>\n",
13347 SCIPvarGetName(var), currcutoffbound, cutoffbound);
13348
13349 var->bestrootsol = rootsol;
13350 var->bestrootredcost = rootredcost;
13351 var->bestrootlpobjval = rootlpobjval;
13352 }
13353 }
13354 else
13355 {
13356 SCIPsetDebugMsg(set, "-> <%s> initialize best root reduced cost information\n", SCIPvarGetName(var));
13357 SCIPsetDebugMsg(set, " -> rootsol <%g>\n", rootsol);
13358 SCIPsetDebugMsg(set, " -> rootredcost <%g>\n", rootredcost);
13359 SCIPsetDebugMsg(set, " -> rootlpobjval <%g>\n", rootlpobjval);
13360
13361 var->bestrootsol = rootsol;
13362 var->bestrootredcost = rootredcost;
13363 var->bestrootlpobjval = rootlpobjval;
13364 }
13365}
13366
13367/** returns the solution of the variable in the last root node's relaxation, if the root relaxation is not yet
13368 * completely solved, zero is returned
13369 */
13371 SCIP_VAR* var /**< problem variable */
13372 )
13373{
13374 SCIP_Real rootsol;
13375 int i;
13376
13377 assert(var != NULL);
13378
13379 switch( SCIPvarGetStatus(var) )
13380 {
13382 if( var->data.original.transvar == NULL )
13383 return 0.0;
13385
13388 return var->rootsol;
13389
13391 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13392 return var->locdom.lb;
13393
13395 assert(!var->donotaggr);
13396 assert(var->data.aggregate.var != NULL);
13397 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
13398 * corresponding infinity value instead of performing an arithmetical transformation (compare method
13399 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
13400 * (or is called by) a public interface method; instead, we only assert that values are finite
13401 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
13402 * positives and negatives if the parameter <numerics/infinity> is modified by the user
13403 */
13407
13409 assert(!var->donotmultaggr);
13410 assert(var->data.multaggr.vars != NULL);
13411 assert(var->data.multaggr.scalars != NULL);
13412 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13413 * assert(var->data.multaggr.nvars >= 2);
13414 */
13415 rootsol = var->data.multaggr.constant;
13416 for( i = 0; i < var->data.multaggr.nvars; ++i )
13417 rootsol += var->data.multaggr.scalars[i] * SCIPvarGetRootSol(var->data.multaggr.vars[i]);
13418 return rootsol;
13419
13420 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13421 assert(var->negatedvar != NULL);
13423 assert(var->negatedvar->negatedvar == var);
13424 return var->data.negate.constant - SCIPvarGetRootSol(var->negatedvar);
13425
13426 default:
13427 SCIPerrorMessage("unknown variable status\n");
13428 SCIPABORT();
13429 return SCIP_INVALID; /*lint !e527*/
13430 }
13431}
13432
13433/** returns for given variable the reduced cost */
13434static
13436 SCIP_VAR* var, /**< problem variable */
13437 SCIP_SET* set, /**< global SCIP settings */
13438 SCIP_Bool varfixing, /**< FALSE if for x == 0, TRUE for x == 1 */
13439 SCIP_STAT* stat, /**< problem statistics */
13440 SCIP_LP* lp /**< current LP data */
13441 )
13442{
13444 {
13445 SCIP_COL* col;
13446 SCIP_Real primsol;
13447 SCIP_BASESTAT basestat;
13448 SCIP_Bool lpissolbasic;
13449
13450 col = SCIPvarGetCol(var);
13451 assert(col != NULL);
13452
13453 basestat = SCIPcolGetBasisStatus(col);
13454 lpissolbasic = SCIPlpIsSolBasic(lp);
13455 primsol = SCIPcolGetPrimsol(col);
13456
13457 if( (lpissolbasic && (basestat == SCIP_BASESTAT_LOWER || basestat == SCIP_BASESTAT_UPPER)) ||
13458 (!lpissolbasic && (SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol) || SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol))) )
13459 {
13460 SCIP_Real redcost = SCIPcolGetRedcost(col, stat, lp);
13461
13462 assert(((!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol)) ||
13463 (lpissolbasic && basestat == SCIP_BASESTAT_LOWER)) ? (!SCIPsetIsDualfeasNegative(set, redcost) ||
13465 assert(((!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol)) ||
13466 (lpissolbasic && basestat == SCIP_BASESTAT_UPPER)) ? (!SCIPsetIsDualfeasPositive(set, redcost) ||
13468
13469 if( (varfixing && ((lpissolbasic && basestat == SCIP_BASESTAT_LOWER) ||
13470 (!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol)))) ||
13471 (!varfixing && ((lpissolbasic && basestat == SCIP_BASESTAT_UPPER) ||
13472 (!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol)))) )
13473 return redcost;
13474 else
13475 return 0.0;
13476 }
13477
13478 return 0.0;
13479 }
13480
13481 return 0.0;
13482}
13483
13484#define MAX_CLIQUELENGTH 50
13485/** returns for the given binary variable the reduced cost which are given by the variable itself and its implication if
13486 * the binary variable is fixed to the given value
13487 */
13489 SCIP_VAR* var, /**< problem variable */
13490 SCIP_SET* set, /**< global SCIP settings */
13491 SCIP_Bool varfixing, /**< FALSE if for x == 0, TRUE for x == 1 */
13492 SCIP_STAT* stat, /**< problem statistics */
13493 SCIP_PROB* prob, /**< transformed problem, or NULL */
13494 SCIP_LP* lp /**< current LP data */
13495 )
13496{
13497 SCIP_Real implredcost;
13498 int ncliques;
13499 int nvars;
13500
13501 assert(SCIPvarIsBinary(var));
13503
13504 /* get reduced cost of given variable */
13505 implredcost = getImplVarRedcost(var, set, varfixing, stat, lp);
13506
13507#ifdef SCIP_MORE_DEBUG
13508 SCIPsetDebugMsg(set, "variable <%s> itself has reduced cost of %g\n", SCIPvarGetName(var), implredcost);
13509#endif
13510
13511 /* the following algorithm is expensive */
13512 ncliques = SCIPvarGetNCliques(var, varfixing);
13513
13514 if( ncliques > 0 )
13515 {
13516 SCIP_CLIQUE** cliques;
13517 SCIP_CLIQUE* clique;
13518 SCIP_VAR** clqvars;
13519 SCIP_VAR** probvars;
13520 SCIP_VAR* clqvar;
13521 SCIP_Bool* clqvalues;
13522 int* entries;
13523 int* ids;
13524 SCIP_Real redcost;
13525 SCIP_Bool cleanedup;
13526 int nclqvars;
13527 int nentries;
13528 int nids;
13529 int id;
13530 int c;
13531 int v;
13532
13533 assert(prob != NULL);
13534 assert(SCIPprobIsTransformed(prob));
13535
13536 nentries = SCIPprobGetNVars(prob) - SCIPprobGetNContVars(prob) + 1;
13537
13538 SCIP_CALL_ABORT( SCIPsetAllocBufferArray(set, &ids, nentries) );
13539 nids = 0;
13540 SCIP_CALL_ABORT( SCIPsetAllocCleanBufferArray(set, &entries, nentries) );
13541
13542 cliques = SCIPvarGetCliques(var, varfixing);
13543 assert(cliques != NULL);
13544
13545 for( c = ncliques - 1; c >= 0; --c )
13546 {
13547 clique = cliques[c];
13548 assert(clique != NULL);
13549 nclqvars = SCIPcliqueGetNVars(clique);
13550 assert(nclqvars > 0);
13551
13552 if( nclqvars > MAX_CLIQUELENGTH )
13553 continue;
13554
13555 clqvars = SCIPcliqueGetVars(clique);
13556 clqvalues = SCIPcliqueGetValues(clique);
13557 assert(clqvars != NULL);
13558 assert(clqvalues != NULL);
13559
13560 cleanedup = SCIPcliqueIsCleanedUp(clique);
13561
13562 for( v = nclqvars - 1; v >= 0; --v )
13563 {
13564 clqvar = clqvars[v];
13565 assert(clqvar != NULL);
13566
13567 /* ignore binary variable which are fixed */
13568 if( clqvar != var && (cleanedup || SCIPvarIsActive(clqvar)) &&
13569 (SCIPvarGetLbLocal(clqvar) < 0.5 && SCIPvarGetUbLocal(clqvar) > 0.5) )
13570 {
13571 int probindex = SCIPvarGetProbindex(clqvar) + 1;
13572 assert(0 < probindex && probindex < nentries);
13573
13574#ifdef SCIP_DISABLED_CODE
13575 /* check that the variable was not yet visited or does not appear with two contradicting implications, ->
13576 * can appear since there is no guarantee that all these infeasible bounds were found
13577 */
13578 assert(!entries[probindex] || entries[probindex] == (clqvalues[v] ? probindex : -probindex));
13579#endif
13580 if( entries[probindex] == 0 )
13581 {
13582 ids[nids] = probindex;
13583 ++nids;
13584
13585 /* mark variable as visited */
13586 entries[probindex] = (clqvalues[v] ? probindex : -probindex);
13587 }
13588 }
13589 }
13590 }
13591
13592 probvars = SCIPprobGetVars(prob);
13593 assert(probvars != NULL);
13594
13595 /* add all implied reduced cost */
13596 for( v = nids - 1; v >= 0; --v )
13597 {
13598 id = ids[v];
13599 assert(0 < id && id < nentries);
13600 assert(entries[id] != 0);
13601 assert(probvars[id - 1] != NULL);
13602 assert(SCIPvarIsActive(probvars[id - 1]));
13603 assert(SCIPvarIsBinary(probvars[id - 1]));
13604 assert(SCIPvarGetLbLocal(probvars[id - 1]) < 0.5 && SCIPvarGetUbLocal(probvars[id - 1]) > 0.5);
13605
13606 if( (entries[id] > 0) != varfixing )
13607 redcost = getImplVarRedcost(probvars[id - 1], set, (entries[id] < 0), stat, lp);
13608 else
13609 redcost = -getImplVarRedcost(probvars[id - 1], set, (entries[id] < 0), stat, lp);
13610
13611 if( (varfixing && SCIPsetIsDualfeasPositive(set, redcost)) || (!varfixing && SCIPsetIsDualfeasNegative(set, redcost)) )
13612 implredcost += redcost;
13613
13614 /* reset entries clear buffer array */
13615 entries[id] = 0;
13616 }
13617
13620 }
13621
13622#ifdef SCIP_MORE_DEBUG
13623 SCIPsetDebugMsg(set, "variable <%s> incl. cliques (%d) has implied reduced cost of %g\n", SCIPvarGetName(var), ncliques,
13624 implredcost);
13625#endif
13626
13627 /* collect non-binary implication information */
13628 nvars = SCIPimplicsGetNImpls(var->implics, varfixing);
13629
13630 if( nvars > 0 )
13631 {
13632 SCIP_VAR** vars;
13633 SCIP_VAR* implvar;
13634 SCIP_COL* col;
13635 SCIP_Real* bounds;
13636 SCIP_BOUNDTYPE* boundtypes;
13637 SCIP_Real redcost;
13638 SCIP_Real lb;
13639 SCIP_Real ub;
13640 SCIP_Bool lpissolbasic;
13641 int v;
13642
13643 vars = SCIPimplicsGetVars(var->implics, varfixing);
13644 boundtypes = SCIPimplicsGetTypes(var->implics, varfixing);
13645 bounds = SCIPimplicsGetBounds(var->implics, varfixing);
13646 lpissolbasic = SCIPlpIsSolBasic(lp);
13647
13648 for( v = nvars - 1; v >= 0; --v )
13649 {
13650 implvar = vars[v];
13651 assert(implvar != NULL);
13652
13653 lb = SCIPvarGetLbLocal(implvar);
13654 ub = SCIPvarGetUbLocal(implvar);
13655
13656 /* ignore binary variable which are fixed or not of column status */
13657 if( SCIPvarGetStatus(implvar) != SCIP_VARSTATUS_COLUMN || SCIPsetIsFeasEQ(set, lb, ub) )
13658 continue;
13659
13660 col = SCIPvarGetCol(implvar);
13661 assert(col != NULL);
13662 redcost = 0.0;
13663
13664 /* solved lp with basis information or not? */
13665 if( lpissolbasic )
13666 {
13667 SCIP_BASESTAT basestat = SCIPcolGetBasisStatus(col);
13668
13669 /* check if the implication is not not yet applied */
13670 if( basestat == SCIP_BASESTAT_LOWER && boundtypes[v] == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGT(set, bounds[v], lb) )
13671 {
13672 redcost = SCIPcolGetRedcost(col, stat, lp);
13673 assert(!SCIPsetIsDualfeasNegative(set, redcost));
13674
13675 if( !varfixing )
13676 redcost *= (lb - bounds[v]);
13677 else
13678 redcost *= (bounds[v] - lb);
13679 }
13680 else if( basestat == SCIP_BASESTAT_UPPER && boundtypes[v] == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLT(set, bounds[v], ub) )
13681 {
13682 redcost = SCIPcolGetRedcost(col, stat, lp);
13683 assert(!SCIPsetIsDualfeasPositive(set, redcost));
13684
13685 if( varfixing )
13686 redcost *= (bounds[v] - ub);
13687 else
13688 redcost *= (ub - bounds[v]);
13689 }
13690 }
13691 else
13692 {
13693 SCIP_Real primsol = SCIPcolGetPrimsol(col);
13694
13695 /* check if the implication is not not yet applied */
13696 if( boundtypes[v] == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasEQ(set, lb, primsol) && SCIPsetIsFeasGT(set, bounds[v], lb) )
13697 {
13698 redcost = SCIPcolGetRedcost(col, stat, lp);
13699 assert(!SCIPsetIsDualfeasNegative(set, redcost));
13700
13701 if( varfixing )
13702 redcost *= (lb - bounds[v]);
13703 else
13704 redcost *= (bounds[v] - lb);
13705 }
13706 else if( boundtypes[v] == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasEQ(set, ub, primsol) && SCIPsetIsFeasLT(set, bounds[v], ub) )
13707 {
13708 redcost = SCIPcolGetRedcost(col, stat, lp);
13709 assert(!SCIPsetIsDualfeasPositive(set, redcost));
13710
13711 if( varfixing )
13712 redcost *= (bounds[v] - ub);
13713 else
13714 redcost *= (ub - bounds[v]);
13715 }
13716 }
13717
13718 /* improve implied reduced cost */
13719 if( (varfixing && SCIPsetIsDualfeasPositive(set, redcost)) || (!varfixing && SCIPsetIsDualfeasNegative(set, redcost)) )
13720 implredcost += redcost;
13721 }
13722 }
13723
13724#ifdef SCIP_MORE_DEBUG
13725 SCIPsetDebugMsg(set, "variable <%s> incl. cliques (%d) and implications (%d) has implied reduced cost of %g\n",
13726 SCIPvarGetName(var), ncliques, nvars, implredcost);
13727#endif
13728
13729 return implredcost;
13730}
13731
13732/** returns the best solution (w.r.t. root reduced cost propagation) of the variable in the root node's relaxation, if
13733 * the root relaxation is not yet completely solved, zero is returned
13734 */
13736 SCIP_VAR* var /**< problem variable */
13737 )
13738{
13739 SCIP_Real rootsol;
13740 int i;
13741
13742 assert(var != NULL);
13743
13744 switch( SCIPvarGetStatus(var) )
13745 {
13747 if( var->data.original.transvar == NULL )
13748 return 0.0;
13750
13753 return var->bestrootsol;
13754
13756 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13757 return var->locdom.lb;
13758
13760 assert(!var->donotaggr);
13761 assert(var->data.aggregate.var != NULL);
13762 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
13763 * corresponding infinity value instead of performing an arithmetical transformation (compare method
13764 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
13765 * (or is called by) a public interface method; instead, we only assert that values are finite
13766 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
13767 * positives and negatives if the parameter <numerics/infinity> is modified by the user
13768 */
13772
13774 assert(!var->donotmultaggr);
13775 assert(var->data.multaggr.vars != NULL);
13776 assert(var->data.multaggr.scalars != NULL);
13777 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13778 * assert(var->data.multaggr.nvars >= 2);
13779 */
13780 rootsol = var->data.multaggr.constant;
13781 for( i = 0; i < var->data.multaggr.nvars; ++i )
13782 rootsol += var->data.multaggr.scalars[i] * SCIPvarGetBestRootSol(var->data.multaggr.vars[i]);
13783 return rootsol;
13784
13785 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
13786 assert(var->negatedvar != NULL);
13788 assert(var->negatedvar->negatedvar == var);
13790
13791 default:
13792 SCIPerrorMessage("unknown variable status\n");
13793 SCIPABORT();
13794 return 0.0; /*lint !e527*/
13795 }
13796}
13797
13798/** returns the best reduced costs (w.r.t. root reduced cost propagation) of the variable in the root node's relaxation,
13799 * if the root relaxation is not yet completely solved, or the variable was no column of the root LP, SCIP_INVALID is
13800 * returned
13801 */
13803 SCIP_VAR* var /**< problem variable */
13804 )
13805{
13806 assert(var != NULL);
13807
13808 switch( SCIPvarGetStatus(var) )
13809 {
13811 if( var->data.original.transvar == NULL )
13812 return SCIP_INVALID;
13814
13817 return var->bestrootredcost;
13818
13823 return 0.0;
13824
13825 default:
13826 SCIPerrorMessage("unknown variable status\n");
13827 SCIPABORT();
13828 return 0.0; /*lint !e527*/
13829 }
13830}
13831
13832/** returns the best objective value (w.r.t. root reduced cost propagation) of the root LP which belongs the root
13833 * reduced cost which is accessible via SCIPvarGetRootRedcost() or the variable was no column of the root LP,
13834 * SCIP_INVALID is returned
13835 */
13837 SCIP_VAR* var /**< problem variable */
13838 )
13839{
13840 assert(var != NULL);
13841
13842 switch( SCIPvarGetStatus(var) )
13843 {
13845 if( var->data.original.transvar == NULL )
13846 return SCIP_INVALID;
13848
13851 return var->bestrootlpobjval;
13852
13857 return SCIP_INVALID;
13858
13859 default:
13860 SCIPerrorMessage("unknown variable status\n");
13861 SCIPABORT();
13862 return SCIP_INVALID; /*lint !e527*/
13863 }
13864}
13865
13866/** set the given solution as the best root solution w.r.t. root reduced cost propagation in the variables */
13868 SCIP_VAR* var, /**< problem variable */
13869 SCIP_Real rootsol, /**< root solution value */
13870 SCIP_Real rootredcost, /**< root reduced cost */
13871 SCIP_Real rootlpobjval /**< objective value of the root LP */
13872 )
13873{
13874 assert(var != NULL);
13875
13876 var->bestrootsol = rootsol;
13877 var->bestrootredcost = rootredcost;
13878 var->bestrootlpobjval = rootlpobjval;
13879}
13880
13881/** stores the solution value as relaxation solution in the problem variable */
13883 SCIP_VAR* var, /**< problem variable */
13884 SCIP_SET* set, /**< global SCIP settings */
13885 SCIP_RELAXATION* relaxation, /**< global relaxation data */
13886 SCIP_Real solval, /**< solution value in the current relaxation solution */
13887 SCIP_Bool updateobj /**< should the objective value be updated? */
13888 )
13889{
13890 assert(var != NULL);
13891 assert(relaxation != NULL);
13892 assert(set != NULL);
13893 assert(var->scip == set->scip);
13894
13895 /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */
13896 switch( SCIPvarGetStatus(var) )
13897 {
13899 SCIP_CALL( SCIPvarSetRelaxSol(var->data.original.transvar, set, relaxation, solval, updateobj) );
13900 break;
13901
13904 if( updateobj )
13905 SCIPrelaxationSolObjAdd(relaxation, var->obj * (solval - var->relaxsol));
13906 var->relaxsol = solval;
13907 break;
13908
13910 if( !SCIPsetIsEQ(set, solval, var->glbdom.lb) )
13911 {
13912 SCIPerrorMessage("cannot set relaxation solution value for variable <%s> fixed to %.15g to different value %.15g\n",
13913 SCIPvarGetName(var), var->glbdom.lb, solval);
13914 return SCIP_INVALIDDATA;
13915 }
13916 break;
13917
13918 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
13919 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
13920 SCIP_CALL( SCIPvarSetRelaxSol(var->data.aggregate.var, set, relaxation,
13921 (solval - var->data.aggregate.constant)/var->data.aggregate.scalar, updateobj) );
13922 break;
13924 SCIPerrorMessage("cannot set solution value for multiple aggregated variable\n");
13925 return SCIP_INVALIDDATA;
13926
13928 SCIP_CALL( SCIPvarSetRelaxSol(var->negatedvar, set, relaxation, var->data.negate.constant - solval, updateobj) );
13929 break;
13930
13931 default:
13932 SCIPerrorMessage("unknown variable status\n");
13933 return SCIP_INVALIDDATA;
13934 }
13935
13936 return SCIP_OKAY;
13937}
13938
13939/** returns the solution value of the problem variable in the relaxation solution
13940 *
13941 * @todo Inline this function - similar to SCIPvarGetLPSol_rec.
13942 */
13944 SCIP_VAR* var, /**< problem variable */
13945 SCIP_SET* set /**< global SCIP settings */
13946 )
13947{
13948 SCIP_Real solvalsum;
13949 SCIP_Real solval;
13950 int i;
13951
13952 assert(var != NULL);
13953 assert(set != NULL);
13954 assert(var->scip == set->scip);
13955
13956 /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */
13957 switch( SCIPvarGetStatus(var) )
13958 {
13961
13964 return var->relaxsol;
13965
13967 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var)); /*lint !e777*/
13968 assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var)); /*lint !e777*/
13969 assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var)); /*lint !e777*/
13970 return SCIPvarGetLbGlobal(var);
13971
13972 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
13973 solval = SCIPvarGetRelaxSol(var->data.aggregate.var, set);
13974 if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) )
13975 {
13976 if( var->data.aggregate.scalar * solval > 0.0 )
13977 return SCIPsetInfinity(set);
13978 if( var->data.aggregate.scalar * solval < 0.0 )
13979 return -SCIPsetInfinity(set);
13980 }
13981 return var->data.aggregate.scalar * solval + var->data.aggregate.constant;
13982
13984 solvalsum = var->data.multaggr.constant;
13985 for( i = 0; i < var->data.multaggr.nvars; ++i )
13986 {
13987 solval = SCIPvarGetRelaxSol(var->data.multaggr.vars[i], set);
13988 if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) )
13989 {
13990 if( var->data.multaggr.scalars[i] * solval > 0.0 )
13991 return SCIPsetInfinity(set);
13992 if( var->data.multaggr.scalars[i] * solval < 0.0 )
13993 return -SCIPsetInfinity(set);
13994 }
13995 solvalsum += var->data.multaggr.scalars[i] * solval;
13996 }
13997 return solvalsum;
13998
14000 solval = SCIPvarGetRelaxSol(var->negatedvar, set);
14001 if( SCIPsetIsInfinity(set, solval) )
14002 return -SCIPsetInfinity(set);
14003 if( SCIPsetIsInfinity(set, -solval) )
14004 return SCIPsetInfinity(set);
14005 return var->data.negate.constant - solval;
14006
14007 default:
14008 SCIPerrorMessage("unknown variable status\n");
14009 SCIPABORT();
14010 return SCIP_INVALID; /*lint !e527*/
14011 }
14012}
14013
14014/** returns the solution value of the transformed problem variable in the relaxation solution */
14016 SCIP_VAR* var /**< problem variable */
14017 )
14018{
14019 assert(var != NULL);
14021
14022 return var->relaxsol;
14023}
14024
14025/** stores the solution value as NLP solution in the problem variable */
14027 SCIP_VAR* var, /**< problem variable */
14028 SCIP_SET* set, /**< global SCIP settings */
14029 SCIP_Real solval /**< solution value in the current NLP solution */
14030 )
14031{
14032 assert(var != NULL);
14033 assert(set != NULL);
14034 assert(var->scip == set->scip);
14035
14036 /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */
14037 switch( SCIPvarGetStatus(var) )
14038 {
14041 break;
14042
14045 var->nlpsol = solval;
14046 break;
14047
14049 if( !SCIPsetIsEQ(set, solval, var->glbdom.lb) )
14050 {
14051 SCIPerrorMessage("cannot set NLP solution value for variable <%s> fixed to %.15g to different value %.15g\n",
14052 SCIPvarGetName(var), var->glbdom.lb, solval);
14053 SCIPABORT();
14054 return SCIP_INVALIDCALL; /*lint !e527*/
14055 }
14056 break;
14057
14058 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c => y = (x-c)/a */
14059 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
14061 break;
14062
14064 SCIPerrorMessage("cannot set solution value for multiple aggregated variable\n");
14065 SCIPABORT();
14066 return SCIP_INVALIDCALL; /*lint !e527*/
14067
14069 SCIP_CALL( SCIPvarSetNLPSol(var->negatedvar, set, var->data.negate.constant - solval) );
14070 break;
14071
14072 default:
14073 SCIPerrorMessage("unknown variable status\n");
14074 SCIPABORT();
14075 return SCIP_ERROR; /*lint !e527*/
14076 }
14077
14078 return SCIP_OKAY;
14079}
14080
14081/** returns a weighted average solution value of the variable in all feasible primal solutions found so far */
14083 SCIP_VAR* var /**< problem variable */
14084 )
14085{
14086 SCIP_Real avgsol;
14087 int i;
14088
14089 assert(var != NULL);
14090
14091 switch( SCIPvarGetStatus(var) )
14092 {
14094 if( var->data.original.transvar == NULL )
14095 return 0.0;
14097
14100 avgsol = var->primsolavg;
14101 avgsol = MAX(avgsol, var->glbdom.lb);
14102 avgsol = MIN(avgsol, var->glbdom.ub);
14103 return avgsol;
14104
14106 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
14107 return var->locdom.lb;
14108
14110 assert(!var->donotaggr);
14111 assert(var->data.aggregate.var != NULL);
14113 + var->data.aggregate.constant;
14114
14116 assert(!var->donotmultaggr);
14117 assert(var->data.multaggr.vars != NULL);
14118 assert(var->data.multaggr.scalars != NULL);
14119 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
14120 * assert(var->data.multaggr.nvars >= 2);
14121 */
14122 avgsol = var->data.multaggr.constant;
14123 for( i = 0; i < var->data.multaggr.nvars; ++i )
14124 avgsol += var->data.multaggr.scalars[i] * SCIPvarGetAvgSol(var->data.multaggr.vars[i]);
14125 return avgsol;
14126
14127 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
14128 assert(var->negatedvar != NULL);
14130 assert(var->negatedvar->negatedvar == var);
14131 return var->data.negate.constant - SCIPvarGetAvgSol(var->negatedvar);
14132
14133 default:
14134 SCIPerrorMessage("unknown variable status\n");
14135 SCIPABORT();
14136 return 0.0; /*lint !e527*/
14137 }
14138}
14139
14140/** returns solution value and index of variable lower bound that is closest to the variable's value in the given primal solution
14141 * or current LP solution if no primal solution is given; returns an index of -1 if no variable lower bound is available
14142 */
14144 SCIP_VAR* var, /**< active problem variable */
14145 SCIP_SOL* sol, /**< primal solution, or NULL for LP solution */
14146 SCIP_SET* set, /**< global SCIP settings */
14147 SCIP_STAT* stat, /**< problem statistics */
14148 SCIP_Real* closestvlb, /**< pointer to store the value of the closest variable lower bound */
14149 int* closestvlbidx /**< pointer to store the index of the closest variable lower bound */
14150 )
14151{
14152 int nvlbs;
14153
14154 assert(var != NULL);
14155 assert(stat != NULL);
14156 assert(set != NULL);
14157 assert(var->scip == set->scip);
14158 assert(closestvlb != NULL);
14159 assert(closestvlbidx != NULL);
14160
14161 *closestvlbidx = -1;
14162 *closestvlb = SCIP_REAL_MIN;
14163
14164 nvlbs = SCIPvarGetNVlbs(var);
14165 if( nvlbs > 0 )
14166 {
14167 SCIP_VAR** vlbvars;
14168 SCIP_Real* vlbcoefs;
14169 SCIP_Real* vlbconsts;
14170 int i;
14171
14172 vlbvars = SCIPvarGetVlbVars(var);
14173 vlbcoefs = SCIPvarGetVlbCoefs(var);
14174 vlbconsts = SCIPvarGetVlbConstants(var);
14175
14176 /* check for cached values */
14177 if( var->closestvblpcount == stat->lpcount && var->closestvlbidx != -1 && sol == NULL)
14178 {
14179 i = var->closestvlbidx;
14180 assert(0 <= i && i < nvlbs);
14181 assert(SCIPvarIsActive(vlbvars[i]));
14182 *closestvlbidx = i;
14183 *closestvlb = vlbcoefs[i] * SCIPvarGetLPSol(vlbvars[i]) + vlbconsts[i];
14184 }
14185 else
14186 {
14187 /* search best VUB */
14188 for( i = 0; i < nvlbs; i++ )
14189 {
14190 if( SCIPvarIsActive(vlbvars[i]) )
14191 {
14192 SCIP_Real vlbsol;
14193
14194 vlbsol = vlbcoefs[i] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[i]) : SCIPsolGetVal(sol, set, stat, vlbvars[i])) + vlbconsts[i];
14195 if( vlbsol > *closestvlb )
14196 {
14197 *closestvlb = vlbsol;
14198 *closestvlbidx = i;
14199 }
14200 }
14201 }
14202
14203 if( sol == NULL )
14204 {
14205 /* update cached value */
14206 if( var->closestvblpcount != stat->lpcount )
14207 var->closestvubidx = -1;
14208 var->closestvlbidx = *closestvlbidx;
14209 var->closestvblpcount = stat->lpcount;
14210 }
14211 }
14212 }
14213}
14214
14215/** returns solution value and index of variable upper bound that is closest to the variable's value in the given primal solution;
14216 * or current LP solution if no primal solution is given; returns an index of -1 if no variable upper bound is available
14217 */
14219 SCIP_VAR* var, /**< active problem variable */
14220 SCIP_SOL* sol, /**< primal solution, or NULL for LP solution */
14221 SCIP_SET* set, /**< global SCIP settings */
14222 SCIP_STAT* stat, /**< problem statistics */
14223 SCIP_Real* closestvub, /**< pointer to store the value of the closest variable upper bound */
14224 int* closestvubidx /**< pointer to store the index of the closest variable upper bound */
14225 )
14226{
14227 int nvubs;
14228
14229 assert(var != NULL);
14230 assert(set != NULL);
14231 assert(var->scip == set->scip);
14232 assert(closestvub != NULL);
14233 assert(closestvubidx != NULL);
14234
14235 *closestvubidx = -1;
14236 *closestvub = SCIP_REAL_MAX;
14237
14238 nvubs = SCIPvarGetNVubs(var);
14239 if( nvubs > 0 )
14240 {
14241 SCIP_VAR** vubvars;
14242 SCIP_Real* vubcoefs;
14243 SCIP_Real* vubconsts;
14244 int i;
14245
14246 vubvars = SCIPvarGetVubVars(var);
14247 vubcoefs = SCIPvarGetVubCoefs(var);
14248 vubconsts = SCIPvarGetVubConstants(var);
14249
14250 /* check for cached values */
14251 if( var->closestvblpcount == stat->lpcount && var->closestvubidx != -1 && sol == NULL)
14252 {
14253 i = var->closestvubidx;
14254 assert(0 <= i && i < nvubs);
14255 assert(SCIPvarIsActive(vubvars[i]));
14256 *closestvubidx = i;
14257 *closestvub = vubcoefs[i] * SCIPvarGetLPSol(vubvars[i]) + vubconsts[i];
14258 }
14259 else
14260 {
14261 /* search best VUB */
14262 for( i = 0; i < nvubs; i++ )
14263 {
14264 if( SCIPvarIsActive(vubvars[i]) )
14265 {
14266 SCIP_Real vubsol;
14267
14268 vubsol = vubcoefs[i] * (sol == NULL ? SCIPvarGetLPSol(vubvars[i]) : SCIPsolGetVal(sol, set, stat, vubvars[i])) + vubconsts[i];
14269 if( vubsol < *closestvub )
14270 {
14271 *closestvub = vubsol;
14272 *closestvubidx = i;
14273 }
14274 }
14275 }
14276
14277 if( sol == NULL )
14278 {
14279 /* update cached value */
14280 if( var->closestvblpcount != stat->lpcount )
14281 var->closestvlbidx = -1;
14282 var->closestvubidx = *closestvubidx;
14283 var->closestvblpcount = stat->lpcount;
14284 }
14285 }
14286 }
14287}
14288
14289/** resolves variable to columns and adds them with the coefficient to the row */
14291 SCIP_VAR* var, /**< problem variable */
14292 BMS_BLKMEM* blkmem, /**< block memory */
14293 SCIP_SET* set, /**< global SCIP settings */
14294 SCIP_STAT* stat, /**< problem statistics */
14295 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
14296 SCIP_PROB* prob, /**< problem data */
14297 SCIP_LP* lp, /**< current LP data */
14298 SCIP_ROW* row, /**< LP row */
14299 SCIP_Real val /**< value of coefficient */
14300 )
14301{
14302 int i;
14303
14304 assert(var != NULL);
14305 assert(set != NULL);
14306 assert(var->scip == set->scip);
14307 assert(row != NULL);
14308 assert(!SCIPsetIsInfinity(set, REALABS(val)));
14309
14310 SCIPsetDebugMsg(set, "adding coefficient %g<%s> to row <%s>\n", val, var->name, row->name);
14311
14312 if ( SCIPsetIsZero(set, val) )
14313 return SCIP_OKAY;
14314
14315 switch( SCIPvarGetStatus(var) )
14316 {
14318 if( var->data.original.transvar == NULL )
14319 {
14320 SCIPerrorMessage("cannot add untransformed original variable <%s> to LP row <%s>\n", var->name, row->name);
14321 return SCIP_INVALIDDATA;
14322 }
14323 SCIP_CALL( SCIPvarAddToRow(var->data.original.transvar, blkmem, set, stat, eventqueue, prob, lp, row, val) );
14324 return SCIP_OKAY;
14325
14327 /* add globally fixed variables as constant */
14328 if( SCIPsetIsEQ(set, var->glbdom.lb, var->glbdom.ub) )
14329 {
14330 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, val * var->glbdom.lb) );
14331 return SCIP_OKAY;
14332 }
14333 /* convert loose variable into column */
14334 SCIP_CALL( SCIPvarColumn(var, blkmem, set, stat, prob, lp) );
14336 /*lint -fallthrough*/
14337
14339 assert(var->data.col != NULL);
14340 assert(var->data.col->var == var);
14341 SCIP_CALL( SCIProwIncCoef(row, blkmem, set, eventqueue, lp, var->data.col, val) );
14342 return SCIP_OKAY;
14343
14345 assert(var->glbdom.lb == var->glbdom.ub); /*lint !e777*/
14346 assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
14347 assert(var->locdom.lb == var->glbdom.lb); /*lint !e777*/
14348 assert(!SCIPsetIsInfinity(set, REALABS(var->locdom.lb)));
14349 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, val * var->locdom.lb) );
14350 return SCIP_OKAY;
14351
14353 assert(!var->donotaggr);
14354 assert(var->data.aggregate.var != NULL);
14355 SCIP_CALL( SCIPvarAddToRow(var->data.aggregate.var, blkmem, set, stat, eventqueue, prob, lp,
14356 row, var->data.aggregate.scalar * val) );
14357 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.aggregate.constant * val) );
14358 return SCIP_OKAY;
14359
14361 assert(!var->donotmultaggr);
14362 assert(var->data.multaggr.vars != NULL);
14363 assert(var->data.multaggr.scalars != NULL);
14364 /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
14365 * assert(var->data.multaggr.nvars >= 2);
14366 */
14367 for( i = 0; i < var->data.multaggr.nvars; ++i )
14368 {
14369 SCIP_CALL( SCIPvarAddToRow(var->data.multaggr.vars[i], blkmem, set, stat, eventqueue, prob, lp,
14370 row, var->data.multaggr.scalars[i] * val) );
14371 }
14372 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.multaggr.constant * val) );
14373 return SCIP_OKAY;
14374
14375 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
14376 assert(var->negatedvar != NULL);
14378 assert(var->negatedvar->negatedvar == var);
14379 SCIP_CALL( SCIPvarAddToRow(var->negatedvar, blkmem, set, stat, eventqueue, prob, lp, row, -val) );
14380 SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.negate.constant * val) );
14381 return SCIP_OKAY;
14382
14383 default:
14384 SCIPerrorMessage("unknown variable status\n");
14385 return SCIP_INVALIDDATA;
14386 }
14387}
14388
14389/* optionally, define this compiler flag to write complete variable histories to a file */
14390#ifdef SCIP_HISTORYTOFILE
14391SCIP_Longint counter = 0l;
14392const char* historypath="."; /* allows for user-defined path; use '.' for calling directory of SCIP */
14393#include "scip/scip.h"
14394#endif
14395
14396/** updates the pseudo costs of the given variable and the global pseudo costs after a change of
14397 * "solvaldelta" in the variable's solution value and resulting change of "objdelta" in the in the LP's objective value
14398 */
14400 SCIP_VAR* var, /**< problem variable */
14401 SCIP_SET* set, /**< global SCIP settings */
14402 SCIP_STAT* stat, /**< problem statistics */
14403 SCIP_Real solvaldelta, /**< difference of variable's new LP value - old LP value */
14404 SCIP_Real objdelta, /**< difference of new LP's objective value - old LP's objective value */
14405 SCIP_Real weight /**< weight in (0,1] of this update in pseudo cost sum */
14406 )
14407{
14408 SCIP_Real oldrootpseudocosts;
14409 assert(var != NULL);
14410 assert(set != NULL);
14411 assert(var->scip == set->scip);
14412 assert(stat != NULL);
14413
14414 /* check if history statistics should be collected for a variable */
14415 if( !stat->collectvarhistory )
14416 return SCIP_OKAY;
14417
14418 switch( SCIPvarGetStatus(var) )
14419 {
14421 if( var->data.original.transvar == NULL )
14422 {
14423 SCIPerrorMessage("cannot update pseudo costs of original untransformed variable\n");
14424 return SCIP_INVALIDDATA;
14425 }
14426 SCIP_CALL( SCIPvarUpdatePseudocost(var->data.original.transvar, set, stat, solvaldelta, objdelta, weight) );
14427 return SCIP_OKAY;
14428
14431 /* store old pseudo-costs for root LP best-estimate update */
14432 oldrootpseudocosts = SCIPvarGetMinPseudocostScore(var, stat, set, SCIPvarGetRootSol(var));
14433
14434 /* update history */
14435 SCIPhistoryUpdatePseudocost(var->history, set, solvaldelta, objdelta, weight);
14436 SCIPhistoryUpdatePseudocost(var->historycrun, set, solvaldelta, objdelta, weight);
14437 SCIPhistoryUpdatePseudocost(stat->glbhistory, set, solvaldelta, objdelta, weight);
14438 SCIPhistoryUpdatePseudocost(stat->glbhistorycrun, set, solvaldelta, objdelta, weight);
14439
14440 /* update root LP best-estimate */
14441 SCIP_CALL( SCIPstatUpdateVarRootLPBestEstimate(stat, set, var, oldrootpseudocosts) );
14442
14443 /* append history to file */
14444#ifdef SCIP_HISTORYTOFILE
14445 {
14446 FILE* f;
14447 char filename[256];
14448 SCIP_NODE* currentnode;
14449 SCIP_NODE* parentnode;
14450 currentnode = SCIPgetFocusNode(set->scip);
14451 parentnode = SCIPnodeGetParent(currentnode);
14452
14453 sprintf(filename, "%s/%s.pse", historypath, SCIPgetProbName(set->scip));
14454 f = fopen(filename, "a");
14455 if( NULL != f )
14456 {
14457 fprintf(f, "%lld %s \t %lld \t %lld \t %lld \t %d \t %15.9f \t %.3f\n",
14458 ++counter,
14459 SCIPvarGetName(var),
14460 SCIPnodeGetNumber(currentnode),
14461 parentnode != NULL ? SCIPnodeGetNumber(parentnode) : -1,
14463 SCIPgetDepth(set->scip),
14464 objdelta,
14465 solvaldelta);
14466 fclose(f);
14467 }
14468 }
14469#endif
14470 return SCIP_OKAY;
14471
14473 SCIPerrorMessage("cannot update pseudo cost values of a fixed variable\n");
14474 return SCIP_INVALIDDATA;
14475
14477 assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
14479 solvaldelta/var->data.aggregate.scalar, objdelta, weight) );
14480 return SCIP_OKAY;
14481
14483 SCIPerrorMessage("cannot update pseudo cost values of a multi-aggregated variable\n");
14484 return SCIP_INVALIDDATA;
14485
14487 SCIP_CALL( SCIPvarUpdatePseudocost(var->negatedvar, set, stat, -solvaldelta, objdelta, weight) );
14488 return SCIP_OKAY;
14489
14490 default:
14491 SCIPerrorMessage("unknown variable status\n");
14492 return SCIP_INVALIDDATA;
14493 }
14494}
14495
14496/** gets the variable's pseudo cost value for the given step size "solvaldelta" in the variable's LP solution value */
14498 SCIP_VAR* var, /**< problem variable */
14499 SCIP_STAT* stat, /**< problem statistics */
14500 SCIP_Real solvaldelta /**< difference of variable's new LP value - old LP value */
14501 )
14502{
14503 SCIP_BRANCHDIR dir;
14504
14505 assert(var != NULL);
14506 assert(stat != NULL);
14507
14508 switch( SCIPvarGetStatus(var) )
14509 {
14511 if( var->data.original.transvar == NULL )
14512 return SCIPhistoryGetPseudocost(stat->glbhistory, solvaldelta);
14513 else
14514 return SCIPvarGetPseudocost(var->data.original.transvar, stat, solvaldelta);
14515
14518 dir = (solvaldelta >= 0.0 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
14519
14520 return SCIPhistoryGetPseudocostCount(var->history, dir) > 0.0
14521 ? SCIPhistoryGetPseudocost(var->history, solvaldelta)
14522 : SCIPhistoryGetPseudocost(stat->glbhistory, solvaldelta);
14523
14525 return 0.0;
14526
14528 return SCIPvarGetPseudocost(var->data.aggregate.var, stat, var->data.aggregate.scalar * solvaldelta);
14529
14531 return 0.0;
14532
14534 return SCIPvarGetPseudocost(var->negatedvar, stat, -solvaldelta);
14535
14536 default:
14537 SCIPerrorMessage("unknown variable status\n");
14538 SCIPABORT();
14539 return 0.0; /*lint !e527*/
14540 }
14541}
14542
14543/** gets the variable's pseudo cost value for the given step size "solvaldelta" in the variable's LP solution value,
14544 * only using the pseudo cost information of the current run
14545 */
14547 SCIP_VAR* var, /**< problem variable */
14548 SCIP_STAT* stat, /**< problem statistics */
14549 SCIP_Real solvaldelta /**< difference of variable's new LP value - old LP value */
14550 )
14551{
14552 SCIP_BRANCHDIR dir;
14553
14554 assert(var != NULL);
14555 assert(stat != NULL);
14556
14557 switch( SCIPvarGetStatus(var) )
14558 {
14560 if( var->data.original.transvar == NULL )
14561 return SCIPhistoryGetPseudocost(stat->glbhistorycrun, solvaldelta);
14562 else
14563 return SCIPvarGetPseudocostCurrentRun(var->data.original.transvar, stat, solvaldelta);
14564
14567 dir = (solvaldelta >= 0.0 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
14568
14569 return SCIPhistoryGetPseudocostCount(var->historycrun, dir) > 0.0
14570 ? SCIPhistoryGetPseudocost(var->historycrun, solvaldelta)
14571 : SCIPhistoryGetPseudocost(stat->glbhistorycrun, solvaldelta);
14572
14574 return 0.0;
14575
14577 return SCIPvarGetPseudocostCurrentRun(var->data.aggregate.var, stat, var->data.aggregate.scalar * solvaldelta);
14578
14580 return 0.0;
14581
14583 return SCIPvarGetPseudocostCurrentRun(var->negatedvar, stat, -solvaldelta);
14584
14585 default:
14586 SCIPerrorMessage("unknown variable status\n");
14587 SCIPABORT();
14588 return 0.0; /*lint !e527*/
14589 }
14590}
14591
14592/** gets the variable's (possible fractional) number of pseudo cost updates for the given direction */
14594 SCIP_VAR* var, /**< problem variable */
14595 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14596 )
14597{
14598 assert(var != NULL);
14599 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14600
14601 switch( SCIPvarGetStatus(var) )
14602 {
14604 if( var->data.original.transvar == NULL )
14605 return 0.0;
14606 else
14608
14611 return SCIPhistoryGetPseudocostCount(var->history, dir);
14612
14614 return 0.0;
14615
14617 if( var->data.aggregate.scalar > 0.0 )
14618 return SCIPvarGetPseudocostCount(var->data.aggregate.var, dir);
14619 else
14621
14623 return 0.0;
14624
14627
14628 default:
14629 SCIPerrorMessage("unknown variable status\n");
14630 SCIPABORT();
14631 return 0.0; /*lint !e527*/
14632 }
14633}
14634
14635/** gets the variable's (possible fractional) number of pseudo cost updates for the given direction,
14636 * only using the pseudo cost information of the current run
14637 */
14639 SCIP_VAR* var, /**< problem variable */
14640 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
14641 )
14642{
14643 assert(var != NULL);
14644 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14645
14646 switch( SCIPvarGetStatus(var) )
14647 {
14649 if( var->data.original.transvar == NULL )
14650 return 0.0;
14651 else
14653
14657
14659 return 0.0;
14660
14662 if( var->data.aggregate.scalar > 0.0 )
14664 else
14666
14668 return 0.0;
14669
14672
14673 default:
14674 SCIPerrorMessage("unknown variable status\n");
14675 SCIPABORT();
14676 return 0.0; /*lint !e527*/
14677 }
14678}
14679
14680/** compares both possible directions for rounding the given solution value and returns the minimum pseudo-costs of the variable */
14682 SCIP_VAR* var, /**< problem variable */
14683 SCIP_STAT* stat, /**< problem statistics */
14684 SCIP_SET* set, /**< global SCIP settings */
14685 SCIP_Real solval /**< solution value, e.g., LP solution value */
14686 )
14687{
14688 SCIP_Real upscore;
14689 SCIP_Real downscore;
14690 SCIP_Real solvaldeltaup;
14691 SCIP_Real solvaldeltadown;
14692
14693 /* LP root estimate only works for variables with fractional LP root solution */
14694 if( SCIPsetIsFeasIntegral(set, solval) )
14695 return 0.0;
14696
14697 /* no min pseudo-cost score is calculated as long as the variable was not initialized in a direction */
14699 return 0.0;
14700
14701 /* compute delta's to ceil and floor of root LP solution value */
14702 solvaldeltaup = SCIPsetCeil(set, solval) - solval;
14703 solvaldeltadown = SCIPsetFloor(set, solval) - solval;
14704
14705 upscore = SCIPvarGetPseudocost(var, stat, solvaldeltaup);
14706 downscore = SCIPvarGetPseudocost(var, stat, solvaldeltadown);
14707
14708 return MIN(upscore, downscore);
14709}
14710
14711/** gets the an estimate of the variable's pseudo cost variance in direction \p dir */
14713 SCIP_VAR* var, /**< problem variable */
14714 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
14715 SCIP_Bool onlycurrentrun /**< return pseudo cost variance only for current branch and bound run */
14716 )
14717{
14718 assert(var != NULL);
14719 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14720
14721 switch( SCIPvarGetStatus(var) )
14722 {
14724 if( var->data.original.transvar == NULL )
14725 return 0.0;
14726 else
14727 return SCIPvarGetPseudocostVariance(var->data.original.transvar, dir, onlycurrentrun);
14728
14731 if( onlycurrentrun )
14733 else
14734 return SCIPhistoryGetPseudocostVariance(var->history, dir);
14735
14737 return 0.0;
14738
14740 if( var->data.aggregate.scalar > 0.0 )
14741 return SCIPvarGetPseudocostVariance(var->data.aggregate.var, dir, onlycurrentrun);
14742 else
14743 return SCIPvarGetPseudocostVariance(var->data.aggregate.var, SCIPbranchdirOpposite(dir), onlycurrentrun);
14744
14746 return 0.0;
14747
14749 return SCIPvarGetPseudocostVariance(var->negatedvar, SCIPbranchdirOpposite(dir), onlycurrentrun);
14750
14751 default:
14752 SCIPerrorMessage("unknown variable status\n");
14753 SCIPABORT();
14754 return 0.0; /*lint !e527*/
14755 }
14756}
14757
14758/** calculates a confidence bound for this variable under the assumption of normally distributed pseudo costs
14759 *
14760 * The confidence bound \f$ \theta \geq 0\f$ denotes the interval borders \f$ [X - \theta, \ X + \theta]\f$, which contains
14761 * the true pseudo costs of the variable, i.e., the expected value of the normal distribution, with a probability
14762 * of 2 * clevel - 1.
14763 *
14764 * @return value of confidence bound for this variable
14765 */
14767 SCIP_VAR* var, /**< variable in question */
14768 SCIP_SET* set, /**< global SCIP settings */
14769 SCIP_BRANCHDIR dir, /**< the branching direction for the confidence bound */
14770 SCIP_Bool onlycurrentrun, /**< should only the current run be taken into account */
14771 SCIP_CONFIDENCELEVEL clevel /**< confidence level for the interval */
14772 )
14773{
14774 SCIP_Real confidencebound;
14775
14776 confidencebound = SCIPvarGetPseudocostVariance(var, dir, onlycurrentrun);
14777 if( SCIPsetIsFeasPositive(set, confidencebound) )
14778 {
14779 SCIP_Real count;
14780
14781 if( onlycurrentrun )
14782 count = SCIPvarGetPseudocostCountCurrentRun(var, dir);
14783 else
14784 count = SCIPvarGetPseudocostCount(var, dir);
14785 /* assertion is valid because variance is positive */
14786 assert(count >= 1.9);
14787
14788 confidencebound /= count; /*lint !e414 division by zero can obviously not occur */
14789 confidencebound = sqrt(confidencebound);
14790
14791 /* the actual, underlying distribution of the mean is a student-t-distribution with degrees of freedom equal to
14792 * the number of pseudo cost evaluations of this variable in the respective direction. */
14793 confidencebound *= SCIPstudentTGetCriticalValue(clevel, (int)SCIPsetFloor(set, count) - 1);
14794 }
14795 else
14796 confidencebound = 0.0;
14797
14798 return confidencebound;
14799}
14800
14801/** check if the current pseudo cost relative error in a direction violates the given threshold. The Relative
14802 * Error is calculated at a specific confidence level
14803 */
14805 SCIP_VAR* var, /**< variable in question */
14806 SCIP_SET* set, /**< global SCIP settings */
14807 SCIP_STAT* stat, /**< problem statistics */
14808 SCIP_Real threshold, /**< threshold for relative errors to be considered reliable (enough) */
14809 SCIP_CONFIDENCELEVEL clevel /**< a given confidence level */
14810 )
14811{
14812 SCIP_Real downsize;
14813 SCIP_Real upsize;
14814 SCIP_Real size;
14815 SCIP_Real relerrorup;
14816 SCIP_Real relerrordown;
14817 SCIP_Real relerror;
14818
14819 /* check, if the pseudo cost score of the variable is reliable */
14822 size = MIN(downsize, upsize);
14823
14824 /* Pseudo costs relative error can only be reliable if both directions have been tried at least twice */
14825 if( size <= 1.9 )
14826 return FALSE;
14827
14828 /* use the relative error between the current mean pseudo cost value of the candidate and its upper
14829 * confidence interval bound at confidence level of 95% for individual variable reliability.
14830 * this is only possible if we have at least 2 measurements and therefore a valid variance estimate.
14831 */
14832 if( downsize >= 1.9 )
14833 {
14834 SCIP_Real normval;
14835
14837 normval = SCIPvarGetPseudocostCurrentRun(var, stat, -1.0);
14838 normval = MAX(1.0, normval);
14839
14840 relerrordown /= normval;
14841 }
14842 else
14843 relerrordown = 0.0;
14844
14845 if( upsize >= 1.9 )
14846 {
14847 SCIP_Real normval;
14848
14850 normval = SCIPvarGetPseudocostCurrentRun(var, stat, +1.0);
14851 normval = MAX(1.0, normval);
14852 relerrorup /= normval;
14853 }
14854 else
14855 relerrorup = 0.0;
14856
14857 /* consider the relative error threshold violated, if it is violated in at least one branching direction */
14858 relerror = MAX(relerrorup, relerrordown);
14859
14860 return (relerror <= threshold);
14861}
14862
14863/** check if variable pseudo-costs have a significant difference in location. The significance depends on
14864 * the choice of \p clevel and on the kind of tested hypothesis. The one-sided hypothesis, which
14865 * should be rejected, is that fracy * mu_y >= fracx * mu_x, where mu_y and mu_x denote the
14866 * unknown location means of the underlying pseudo-cost distributions of x and y.
14867 *
14868 * This method is applied best if variable x has a better pseudo-cost score than y. The method hypothesizes that y were actually
14869 * better than x (despite the current information), meaning that y can be expected to yield branching
14870 * decisions as least as good as x in the long run. If the method returns TRUE, the current history information is
14871 * sufficient to safely rely on the alternative hypothesis that x yields indeed a better branching score (on average)
14872 * than y.
14873 *
14874 * @note The order of x and y matters for the one-sided hypothesis
14875 *
14876 * @note set \p onesided to FALSE if you are not sure which variable is better. The hypothesis tested then reads
14877 * fracy * mu_y == fracx * mu_x vs the alternative hypothesis fracy * mu_y != fracx * mu_x.
14878 *
14879 * @return TRUE if the hypothesis can be safely rejected at the given confidence level
14880 */
14882 SCIP_SET* set, /**< global SCIP settings */
14883 SCIP_STAT* stat, /**< problem statistics */
14884 SCIP_VAR* varx, /**< variable x */
14885 SCIP_Real fracx, /**< the fractionality of variable x */
14886 SCIP_VAR* vary, /**< variable y */
14887 SCIP_Real fracy, /**< the fractionality of variable y */
14888 SCIP_BRANCHDIR dir, /**< branching direction */
14889 SCIP_CONFIDENCELEVEL clevel, /**< confidence level for rejecting hypothesis */
14890 SCIP_Bool onesided /**< should a one-sided hypothesis y >= x be tested? */
14891 )
14892{
14893 SCIP_Real meanx;
14894 SCIP_Real meany;
14895 SCIP_Real variancex;
14896 SCIP_Real variancey;
14897 SCIP_Real countx;
14898 SCIP_Real county;
14899 SCIP_Real tresult;
14900 SCIP_Real realdirection;
14901
14902 if( varx == vary )
14903 return FALSE;
14904
14905 countx = SCIPvarGetPseudocostCount(varx, dir);
14906 county = SCIPvarGetPseudocostCount(vary, dir);
14907
14908 /* if not at least 2 measurements were taken, return FALSE */
14909 if( countx <= 1.9 || county <= 1.9 )
14910 return FALSE;
14911
14912 realdirection = (dir == SCIP_BRANCHDIR_DOWNWARDS ? -1.0 : 1.0);
14913
14914 meanx = fracx * SCIPvarGetPseudocost(varx, stat, realdirection);
14915 meany = fracy * SCIPvarGetPseudocost(vary, stat, realdirection);
14916
14917 variancex = SQR(fracx) * SCIPvarGetPseudocostVariance(varx, dir, FALSE);
14918 variancey = SQR(fracy) * SCIPvarGetPseudocostVariance(vary, dir, FALSE);
14919
14920 /* if there is no variance, the means are taken from a constant distribution */
14921 if( SCIPsetIsFeasEQ(set, variancex + variancey, 0.0) )
14922 return (onesided ? SCIPsetIsFeasGT(set, meanx, meany) : !SCIPsetIsFeasEQ(set, meanx, meany));
14923
14924 tresult = SCIPcomputeTwoSampleTTestValue(meanx, meany, variancex, variancey, countx, county);
14925
14926 /* for the two-sided hypothesis, just take the absolute of t */
14927 if( !onesided )
14928 tresult = REALABS(tresult);
14929
14930 return (tresult >= SCIPstudentTGetCriticalValue(clevel, (int)(countx + county - 2)));
14931}
14932
14933/** tests at a given confidence level whether the variable pseudo-costs only have a small probability to
14934 * exceed a \p threshold. This is useful to determine if past observations provide enough evidence
14935 * to skip an expensive strong-branching step if there is already a candidate that has been proven to yield an improvement
14936 * of at least \p threshold.
14937 *
14938 * @note use \p clevel to adjust the level of confidence. For SCIP_CONFIDENCELEVEL_MIN, the method returns TRUE if
14939 * the estimated probability to exceed \p threshold is less than 25 %.
14940 *
14941 * @see SCIP_Confidencelevel for a list of available levels. The used probability limits refer to the one-sided levels
14942 * of confidence.
14943 *
14944 * @return TRUE if the variable pseudo-cost probabilistic model is likely to be smaller than \p threshold
14945 * at the given confidence level \p clevel.
14946 */
14948 SCIP_SET* set, /**< global SCIP settings */
14949 SCIP_STAT* stat, /**< problem statistics */
14950 SCIP_VAR* var, /**< variable x */
14951 SCIP_Real frac, /**< the fractionality of variable x */
14952 SCIP_Real threshold, /**< the threshold to test against */
14953 SCIP_BRANCHDIR dir, /**< branching direction */
14954 SCIP_CONFIDENCELEVEL clevel /**< confidence level for rejecting hypothesis */
14955 )
14956{
14957 SCIP_Real mean;
14958 SCIP_Real variance;
14959 SCIP_Real count;
14960 SCIP_Real realdirection;
14961 SCIP_Real probability;
14962 SCIP_Real problimit;
14963
14964 count = SCIPvarGetPseudocostCount(var, dir);
14965
14966 /* if not at least 2 measurements were taken, return FALSE */
14967 if( count <= 1.9 )
14968 return FALSE;
14969
14970 realdirection = (dir == SCIP_BRANCHDIR_DOWNWARDS ? -1.0 : 1.0);
14971
14972 mean = frac * SCIPvarGetPseudocost(var, stat, realdirection);
14973 variance = SQR(frac) * SCIPvarGetPseudocostVariance(var, dir, FALSE);
14974
14975 /* if mean is at least threshold, it has at least a 50% probability to exceed threshold, we therefore return FALSE */
14976 if( SCIPsetIsFeasGE(set, mean, threshold) )
14977 return FALSE;
14978
14979 /* if there is no variance, the means are taken from a constant distribution */
14980 if( SCIPsetIsFeasEQ(set, variance, 0.0) )
14981 return SCIPsetIsFeasLT(set, mean, threshold);
14982
14983 /* obtain probability of a normally distributed random variable at given mean and variance to yield at most threshold */
14984 probability = SCIPnormalCDF(mean, variance, threshold);
14985
14986 /* determine a probability limit corresponding to the given confidence level */
14987 switch( clevel )
14988 {
14990 problimit = 0.75;
14991 break;
14993 problimit = 0.875;
14994 break;
14996 problimit = 0.9;
14997 break;
14999 problimit = 0.95;
15000 break;
15002 problimit = 0.975;
15003 break;
15004 default:
15005 problimit = -1;
15006 SCIPerrorMessage("Confidence level set to unknown value <%d>", (int)clevel);
15007 SCIPABORT();
15008 break;
15009 }
15010
15011 return (probability >= problimit);
15012}
15013
15014/** find the corresponding history entry if already existing, otherwise create new entry */
15015static
15017 SCIP_VAR* var, /**< problem variable */
15018 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15019 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15020 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15021 SCIP_HISTORY** history /**< pointer to store the value based history, or NULL */
15022 )
15023{
15024 assert(var != NULL);
15025 assert(blkmem != NULL);
15026 assert(set != NULL);
15027 assert(history != NULL);
15028
15029 (*history) = NULL;
15030
15031 if( var->valuehistory == NULL )
15032 {
15034 }
15035
15036 SCIP_CALL( SCIPvaluehistoryFind(var->valuehistory, blkmem, set, value, history) );
15037
15038 return SCIP_OKAY;
15039}
15040
15041/** check if value based history should be used */
15042static
15044 SCIP_VAR* var, /**< problem variable */
15045 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15046 SCIP_SET* set /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15047 )
15048{
15049 /* check if the domain value is unknown (not specific) */
15050 if( value == SCIP_UNKNOWN ) /*lint !e777*/
15051 return FALSE;
15052
15053 assert(set != NULL);
15054
15055 /* check if value based history should be collected */
15056 if( !set->history_valuebased )
15057 return FALSE;
15058
15059 /* value based history is not collected for binary variable since the standard history already contains all information */
15061 return FALSE;
15062
15063 /* value based history is not collected for continuous variables */
15065 return FALSE;
15066
15067 return TRUE;
15068}
15069
15070/** increases VSIDS of the variable by the given weight */
15072 SCIP_VAR* var, /**< problem variable */
15073 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15074 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15075 SCIP_STAT* stat, /**< problem statistics */
15076 SCIP_BRANCHDIR dir, /**< branching direction */
15077 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15078 SCIP_Real weight /**< weight of this update in VSIDS */
15079 )
15080{
15081 assert(var != NULL);
15082 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15083
15084 /* check if history statistics should be collected for a variable */
15085 if( !stat->collectvarhistory )
15086 return SCIP_OKAY;
15087
15088 if( SCIPsetIsZero(set, weight) )
15089 return SCIP_OKAY;
15090
15091 switch( SCIPvarGetStatus(var) )
15092 {
15094 if( var->data.original.transvar == NULL )
15095 {
15096 SCIPerrorMessage("cannot update VSIDS of original untransformed variable\n");
15097 return SCIP_INVALIDDATA;
15098 }
15099 SCIP_CALL( SCIPvarIncVSIDS(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
15100 return SCIP_OKAY;
15101
15104 {
15105 SCIPhistoryIncVSIDS(var->history, dir, weight);
15106 SCIPhistoryIncVSIDS(var->historycrun, dir, weight);
15107
15108 if( useValuehistory(var, value, set) )
15109 {
15110 SCIP_HISTORY* history;
15111
15112 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15113 assert(history != NULL);
15114
15115 SCIPhistoryIncVSIDS(history, dir, weight);
15116 SCIPsetDebugMsg(set, "variable (<%s> %s %g) + <%g> = <%g>\n", SCIPvarGetName(var), dir == SCIP_BRANCHDIR_UPWARDS ? ">=" : "<=",
15117 value, weight, SCIPhistoryGetVSIDS(history, dir));
15118 }
15119
15120 return SCIP_OKAY;
15121 }
15123 SCIPerrorMessage("cannot update VSIDS of a fixed variable\n");
15124 return SCIP_INVALIDDATA;
15125
15127 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15128
15129 if( var->data.aggregate.scalar > 0.0 )
15130 {
15131 SCIP_CALL( SCIPvarIncVSIDS(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
15132 }
15133 else
15134 {
15135 assert(var->data.aggregate.scalar < 0.0);
15136 SCIP_CALL( SCIPvarIncVSIDS(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15137 }
15138 return SCIP_OKAY;
15139
15141 SCIPerrorMessage("cannot update VSIDS of a multi-aggregated variable\n");
15142 return SCIP_INVALIDDATA;
15143
15145 value = 1.0 - value;
15146
15147 SCIP_CALL( SCIPvarIncVSIDS(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15148 return SCIP_OKAY;
15149
15150 default:
15151 SCIPerrorMessage("unknown variable status\n");
15152 return SCIP_INVALIDDATA;
15153 }
15154}
15155
15156/** scales the VSIDS of the variable by the given scalar */
15158 SCIP_VAR* var, /**< problem variable */
15159 SCIP_Real scalar /**< scalar to multiply the VSIDSs with */
15160 )
15161{
15162 assert(var != NULL);
15163
15164 switch( SCIPvarGetStatus(var) )
15165 {
15167 if( var->data.original.transvar == NULL )
15168 {
15169 SCIPerrorMessage("cannot update VSIDS of original untransformed variable\n");
15170 return SCIP_INVALIDDATA;
15171 }
15173 return SCIP_OKAY;
15174
15177 {
15178 SCIPhistoryScaleVSIDS(var->history, scalar);
15179 SCIPhistoryScaleVSIDS(var->historycrun, scalar);
15181
15182 return SCIP_OKAY;
15183 }
15185 SCIPerrorMessage("cannot update VSIDS of a fixed variable\n");
15186 return SCIP_INVALIDDATA;
15187
15189 SCIP_CALL( SCIPvarScaleVSIDS(var->data.aggregate.var, scalar) );
15190 return SCIP_OKAY;
15191
15193 SCIPerrorMessage("cannot update VSIDS of a multi-aggregated variable\n");
15194 return SCIP_INVALIDDATA;
15195
15197 SCIP_CALL( SCIPvarScaleVSIDS(var->negatedvar, scalar) );
15198 return SCIP_OKAY;
15199
15200 default:
15201 SCIPerrorMessage("unknown variable status\n");
15202 return SCIP_INVALIDDATA;
15203 }
15204}
15205
15206/** increases the number of active conflicts by one and the overall length of the variable by the given length */
15208 SCIP_VAR* var, /**< problem variable */
15209 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15210 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15211 SCIP_STAT* stat, /**< problem statistics */
15212 SCIP_BRANCHDIR dir, /**< branching direction */
15213 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15214 SCIP_Real length /**< length of the conflict */
15215 )
15216{
15217 assert(var != NULL);
15218 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15219
15220 /* check if history statistics should be collected for a variable */
15221 if( !stat->collectvarhistory )
15222 return SCIP_OKAY;
15223
15224 switch( SCIPvarGetStatus(var) )
15225 {
15227 if( var->data.original.transvar == NULL )
15228 {
15229 SCIPerrorMessage("cannot update conflict score of original untransformed variable\n");
15230 return SCIP_INVALIDDATA;
15231 }
15232 SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.original.transvar, blkmem, set, stat, dir, value, length) );
15233 return SCIP_OKAY;
15234
15237 {
15238 SCIPhistoryIncNActiveConflicts(var->history, dir, length);
15240
15241 if( useValuehistory(var, value, set) )
15242 {
15243 SCIP_HISTORY* history;
15244
15245 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15246 assert(history != NULL);
15247
15248 SCIPhistoryIncNActiveConflicts(history, dir, length);
15249 }
15250
15251 return SCIP_OKAY;
15252 }
15254 SCIPerrorMessage("cannot update conflict score of a fixed variable\n");
15255 return SCIP_INVALIDDATA;
15256
15258 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15259
15260 if( var->data.aggregate.scalar > 0.0 )
15261 {
15262 SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.aggregate.var, blkmem, set, stat, dir, value, length) );
15263 }
15264 else
15265 {
15266 assert(var->data.aggregate.scalar < 0.0);
15267 SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, length) );
15268 }
15269 return SCIP_OKAY;
15270
15272 SCIPerrorMessage("cannot update conflict score of a multi-aggregated variable\n");
15273 return SCIP_INVALIDDATA;
15274
15276 value = 1.0 - value;
15277
15278 SCIP_CALL( SCIPvarIncNActiveConflicts(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, length) );
15279 return SCIP_OKAY;
15280
15281 default:
15282 SCIPerrorMessage("unknown variable status\n");
15283 return SCIP_INVALIDDATA;
15284 }
15285}
15286
15287/** gets the number of active conflicts containing this variable in given direction */
15289 SCIP_VAR* var, /**< problem variable */
15290 SCIP_STAT* stat, /**< problem statistics */
15291 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15292 )
15293{
15294 assert(var != NULL);
15295 assert(stat != NULL);
15296 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15297
15298 switch( SCIPvarGetStatus(var) )
15299 {
15301 if( var->data.original.transvar == NULL )
15302 return 0;
15303 else
15304 return SCIPvarGetNActiveConflicts(var->data.original.transvar, stat, dir);
15305
15308 return SCIPhistoryGetNActiveConflicts(var->history, dir);
15309
15311 return 0;
15312
15314 if( var->data.aggregate.scalar > 0.0 )
15315 return SCIPvarGetNActiveConflicts(var->data.aggregate.var, stat, dir);
15316 else
15318
15320 return 0;
15321
15324
15325 default:
15326 SCIPerrorMessage("unknown variable status\n");
15327 SCIPABORT();
15328 return 0; /*lint !e527*/
15329 }
15330}
15331
15332/** gets the number of active conflicts containing this variable in given direction
15333 * in the current run
15334 */
15336 SCIP_VAR* var, /**< problem variable */
15337 SCIP_STAT* stat, /**< problem statistics */
15338 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15339 )
15340{
15341 assert(var != NULL);
15342 assert(stat != NULL);
15343 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15344
15345 switch( SCIPvarGetStatus(var) )
15346 {
15348 if( var->data.original.transvar == NULL )
15349 return 0;
15350 else
15352
15356
15358 return 0;
15359
15361 if( var->data.aggregate.scalar > 0.0 )
15363 else
15365
15367 return 0;
15368
15371
15372 default:
15373 SCIPerrorMessage("unknown variable status\n");
15374 SCIPABORT();
15375 return 0; /*lint !e527*/
15376 }
15377}
15378
15379/** gets the average conflict length in given direction due to branching on the variable */
15381 SCIP_VAR* var, /**< problem variable */
15382 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15383 )
15384{
15385 assert(var != NULL);
15386 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15387
15388 switch( SCIPvarGetStatus(var) )
15389 {
15391 if( var->data.original.transvar == NULL )
15392 return 0.0;
15393 else
15395
15398 return SCIPhistoryGetAvgConflictlength(var->history, dir);
15400 return 0.0;
15401
15403 if( var->data.aggregate.scalar > 0.0 )
15405 else
15407
15409 return 0.0;
15410
15413
15414 default:
15415 SCIPerrorMessage("unknown variable status\n");
15416 SCIPABORT();
15417 return 0.0; /*lint !e527*/
15418 }
15419}
15420
15421/** gets the average conflict length in given direction due to branching on the variable
15422 * in the current run
15423 */
15425 SCIP_VAR* var, /**< problem variable */
15426 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15427 )
15428{
15429 assert(var != NULL);
15430 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15431
15432 switch( SCIPvarGetStatus(var) )
15433 {
15435 if( var->data.original.transvar == NULL )
15436 return 0.0;
15437 else
15439
15443
15445 return 0.0;
15446
15448 if( var->data.aggregate.scalar > 0.0 )
15450 else
15452
15454 return 0.0;
15455
15458
15459 default:
15460 SCIPerrorMessage("unknown variable status\n");
15461 SCIPABORT();
15462 return 0.0; /*lint !e527*/
15463 }
15464}
15465
15466/** increases the number of branchings counter of the variable */
15468 SCIP_VAR* var, /**< problem variable */
15469 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15470 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15471 SCIP_STAT* stat, /**< problem statistics */
15472 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
15473 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15474 int depth /**< depth at which the bound change took place */
15475 )
15476{
15477 assert(var != NULL);
15478 assert(stat != NULL);
15479 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15480
15481 /* check if history statistics should be collected for a variable */
15482 if( !stat->collectvarhistory )
15483 return SCIP_OKAY;
15484
15485 switch( SCIPvarGetStatus(var) )
15486 {
15488 if( var->data.original.transvar == NULL )
15489 {
15490 SCIPerrorMessage("cannot update branching counter of original untransformed variable\n");
15491 return SCIP_INVALIDDATA;
15492 }
15493 SCIP_CALL( SCIPvarIncNBranchings(var->data.original.transvar, blkmem, set, stat, dir, value, depth) );
15494 return SCIP_OKAY;
15495
15498 {
15499 SCIPhistoryIncNBranchings(var->history, dir, depth);
15500 SCIPhistoryIncNBranchings(var->historycrun, dir, depth);
15501 SCIPhistoryIncNBranchings(stat->glbhistory, dir, depth);
15502 SCIPhistoryIncNBranchings(stat->glbhistorycrun, dir, depth);
15503
15504 if( useValuehistory(var, value, set) )
15505 {
15506 SCIP_HISTORY* history;
15507
15508 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15509 assert(history != NULL);
15510
15511 SCIPhistoryIncNBranchings(history, dir, depth);
15512 }
15513
15514 return SCIP_OKAY;
15515 }
15517 SCIPerrorMessage("cannot update branching counter of a fixed variable\n");
15518 return SCIP_INVALIDDATA;
15519
15521 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15522
15523 if( var->data.aggregate.scalar > 0.0 )
15524 {
15525 SCIP_CALL( SCIPvarIncNBranchings(var->data.aggregate.var, blkmem, set, stat, dir, value, depth) );
15526 }
15527 else
15528 {
15529 assert(var->data.aggregate.scalar < 0.0);
15530 SCIP_CALL( SCIPvarIncNBranchings(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, depth) );
15531 }
15532 return SCIP_OKAY;
15533
15535 SCIPerrorMessage("cannot update branching counter of a multi-aggregated variable\n");
15536 return SCIP_INVALIDDATA;
15537
15539 value = 1.0 - value;
15540
15541 SCIP_CALL( SCIPvarIncNBranchings(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, depth) );
15542 return SCIP_OKAY;
15543
15544 default:
15545 SCIPerrorMessage("unknown variable status\n");
15546 return SCIP_INVALIDDATA;
15547 }
15548}
15549
15550/** increases the inference sum of the variable by the given weight */
15552 SCIP_VAR* var, /**< problem variable */
15553 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15554 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15555 SCIP_STAT* stat, /**< problem statistics */
15556 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
15557 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15558 SCIP_Real weight /**< weight of this update in inference score */
15559 )
15560{
15561 assert(var != NULL);
15562 assert(stat != NULL);
15563 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15564
15565 /* check if history statistics should be collected for a variable */
15566 if( !stat->collectvarhistory )
15567 return SCIP_OKAY;
15568
15569 switch( SCIPvarGetStatus(var) )
15570 {
15572 if( var->data.original.transvar == NULL )
15573 {
15574 SCIPerrorMessage("cannot update inference counter of original untransformed variable\n");
15575 return SCIP_INVALIDDATA;
15576 }
15577 SCIP_CALL( SCIPvarIncInferenceSum(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
15578 return SCIP_OKAY;
15579
15582 {
15583 SCIPhistoryIncInferenceSum(var->history, dir, weight);
15584 SCIPhistoryIncInferenceSum(var->historycrun, dir, weight);
15585 SCIPhistoryIncInferenceSum(stat->glbhistory, dir, weight);
15586 SCIPhistoryIncInferenceSum(stat->glbhistorycrun, dir, weight);
15587
15588 if( useValuehistory(var, value, set) )
15589 {
15590 SCIP_HISTORY* history;
15591
15592 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15593 assert(history != NULL);
15594
15595 SCIPhistoryIncInferenceSum(history, dir, weight);
15596 }
15597
15598 return SCIP_OKAY;
15599 }
15601 SCIPerrorMessage("cannot update inference counter of a fixed variable\n");
15602 return SCIP_INVALIDDATA;
15603
15605 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15606
15607 if( var->data.aggregate.scalar > 0.0 )
15608 {
15609 SCIP_CALL( SCIPvarIncInferenceSum(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
15610 }
15611 else
15612 {
15613 assert(var->data.aggregate.scalar < 0.0);
15614 SCIP_CALL( SCIPvarIncInferenceSum(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15615 }
15616 return SCIP_OKAY;
15617
15619 SCIPerrorMessage("cannot update inference counter of a multi-aggregated variable\n");
15620 return SCIP_INVALIDDATA;
15621
15623 value = 1.0 - value;
15624
15625 SCIP_CALL( SCIPvarIncInferenceSum(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15626 return SCIP_OKAY;
15627
15628 default:
15629 SCIPerrorMessage("unknown variable status\n");
15630 return SCIP_INVALIDDATA;
15631 }
15632}
15633
15634/** increases the cutoff sum of the variable by the given weight */
15636 SCIP_VAR* var, /**< problem variable */
15637 BMS_BLKMEM* blkmem, /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15638 SCIP_SET* set, /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15639 SCIP_STAT* stat, /**< problem statistics */
15640 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
15641 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
15642 SCIP_Real weight /**< weight of this update in cutoff score */
15643 )
15644{
15645 assert(var != NULL);
15646 assert(stat != NULL);
15647 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15648
15649 /* check if history statistics should be collected for a variable */
15650 if( !stat->collectvarhistory )
15651 return SCIP_OKAY;
15652
15653 switch( SCIPvarGetStatus(var) )
15654 {
15656 if( var->data.original.transvar == NULL )
15657 {
15658 SCIPerrorMessage("cannot update cutoff sum of original untransformed variable\n");
15659 return SCIP_INVALIDDATA;
15660 }
15661 SCIP_CALL( SCIPvarIncCutoffSum(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
15662 return SCIP_OKAY;
15663
15666 {
15667 SCIPhistoryIncCutoffSum(var->history, dir, weight);
15668 SCIPhistoryIncCutoffSum(var->historycrun, dir, weight);
15669 SCIPhistoryIncCutoffSum(stat->glbhistory, dir, weight);
15670 SCIPhistoryIncCutoffSum(stat->glbhistorycrun, dir, weight);
15671
15672 if( useValuehistory(var, value, set) )
15673 {
15674 SCIP_HISTORY* history;
15675
15676 SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15677 assert(history != NULL);
15678
15679 SCIPhistoryIncCutoffSum(history, dir, weight);
15680 }
15681
15682 return SCIP_OKAY;
15683 }
15685 SCIPerrorMessage("cannot update cutoff sum of a fixed variable\n");
15686 return SCIP_INVALIDDATA;
15687
15689 value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15690
15691 if( var->data.aggregate.scalar > 0.0 )
15692 {
15693 SCIP_CALL( SCIPvarIncCutoffSum(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
15694 }
15695 else
15696 {
15697 assert(var->data.aggregate.scalar < 0.0);
15698 SCIP_CALL( SCIPvarIncCutoffSum(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15699 }
15700 return SCIP_OKAY;
15701
15703 SCIPerrorMessage("cannot update cutoff sum of a multi-aggregated variable\n");
15704 return SCIP_INVALIDDATA;
15705
15707 value = 1.0 - value;
15708
15709 SCIP_CALL( SCIPvarIncCutoffSum(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15710 return SCIP_OKAY;
15711
15712 default:
15713 SCIPerrorMessage("unknown variable status\n");
15714 return SCIP_INVALIDDATA;
15715 }
15716}
15717
15718/** returns the number of times, a bound of the variable was changed in given direction due to branching */
15720 SCIP_VAR* var, /**< problem variable */
15721 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15722 )
15723{
15724 assert(var != NULL);
15725 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15726
15727 switch( SCIPvarGetStatus(var) )
15728 {
15730 if( var->data.original.transvar == NULL )
15731 return 0;
15732 else
15733 return SCIPvarGetNBranchings(var->data.original.transvar, dir);
15734
15737 return SCIPhistoryGetNBranchings(var->history, dir);
15738
15740 return 0;
15741
15743 if( var->data.aggregate.scalar > 0.0 )
15744 return SCIPvarGetNBranchings(var->data.aggregate.var, dir);
15745 else
15747
15749 return 0;
15750
15753
15754 default:
15755 SCIPerrorMessage("unknown variable status\n");
15756 SCIPABORT();
15757 return 0; /*lint !e527*/
15758 }
15759}
15760
15761/** returns the number of times, a bound of the variable was changed in given direction due to branching
15762 * in the current run
15763 */
15765 SCIP_VAR* var, /**< problem variable */
15766 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15767 )
15768{
15769 assert(var != NULL);
15770 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15771
15772 switch( SCIPvarGetStatus(var) )
15773 {
15775 if( var->data.original.transvar == NULL )
15776 return 0;
15777 else
15779
15782 return SCIPhistoryGetNBranchings(var->historycrun, dir);
15783
15785 return 0;
15786
15788 if( var->data.aggregate.scalar > 0.0 )
15790 else
15792
15794 return 0;
15795
15798
15799 default:
15800 SCIPerrorMessage("unknown variable status\n");
15801 SCIPABORT();
15802 return 0; /*lint !e527*/
15803 }
15804}
15805
15806/** returns the average depth of bound changes in given direction due to branching on the variable */
15808 SCIP_VAR* var, /**< problem variable */
15809 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15810 )
15811{
15812 assert(var != NULL);
15813 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15814
15815 switch( SCIPvarGetStatus(var) )
15816 {
15818 if( var->data.original.transvar == NULL )
15819 return 0.0;
15820 else
15822
15825 return SCIPhistoryGetAvgBranchdepth(var->history, dir);
15826
15828 return 0.0;
15829
15831 if( var->data.aggregate.scalar > 0.0 )
15832 return SCIPvarGetAvgBranchdepth(var->data.aggregate.var, dir);
15833 else
15835
15837 return 0.0;
15838
15841
15842 default:
15843 SCIPerrorMessage("unknown variable status\n");
15844 SCIPABORT();
15845 return 0.0; /*lint !e527*/
15846 }
15847}
15848
15849/** returns the average depth of bound changes in given direction due to branching on the variable
15850 * in the current run
15851 */
15853 SCIP_VAR* var, /**< problem variable */
15854 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15855 )
15856{
15857 assert(var != NULL);
15858 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15859
15860 switch( SCIPvarGetStatus(var) )
15861 {
15863 if( var->data.original.transvar == NULL )
15864 return 0.0;
15865 else
15867
15870 return SCIPhistoryGetAvgBranchdepth(var->historycrun, dir);
15871
15873 return 0.0;
15874
15876 if( var->data.aggregate.scalar > 0.0 )
15878 else
15881
15883 return 0.0;
15884
15888
15889 default:
15890 SCIPerrorMessage("unknown variable status\n");
15891 SCIPABORT();
15892 return 0.0; /*lint !e527*/
15893 }
15894}
15895
15896/** returns the variable's VSIDS score */
15898 SCIP_VAR* var, /**< problem variable */
15899 SCIP_STAT* stat, /**< problem statistics */
15900 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15901 )
15902{
15903 assert(var != NULL);
15904 assert(stat != NULL);
15905 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15906
15908 return SCIPvarGetVSIDS(var->data.original.transvar, stat, dir);
15909
15910 switch( SCIPvarGetStatus(var) )
15911 {
15913 if( var->data.original.transvar == NULL )
15914 return 0.0;
15915 else
15916 return SCIPvarGetVSIDS(var->data.original.transvar, stat, dir);
15917
15920 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); /* column case already handled in if condition above */
15921 return SCIPhistoryGetVSIDS(var->history, dir)/stat->vsidsweight;
15922
15924 return 0.0;
15925
15927 if( var->data.aggregate.scalar > 0.0 )
15928 return SCIPvarGetVSIDS(var->data.aggregate.var, stat, dir);
15929 else
15930 /* coverity[overrun-local] */
15931 return SCIPvarGetVSIDS(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
15932
15934 return 0.0;
15935
15937 /* coverity[overrun-local] */
15938 return SCIPvarGetVSIDS(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
15939
15940 default:
15941 SCIPerrorMessage("unknown variable status\n");
15942 SCIPABORT();
15943 return 0.0; /*lint !e527*/
15944 }
15945}
15946
15947/** returns the variable's VSIDS score only using conflicts of the current run */
15949 SCIP_VAR* var, /**< problem variable */
15950 SCIP_STAT* stat, /**< problem statistics */
15951 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
15952 )
15953{
15954 assert(var != NULL);
15955 assert(stat != NULL);
15956 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15957
15959 {
15960 SCIPerrorMessage("invalid branching direction %d when asking for VSIDS value\n", dir);
15961 return SCIP_INVALID;
15962 }
15963
15964 switch( SCIPvarGetStatus(var) )
15965 {
15967 if( var->data.original.transvar == NULL )
15968 return 0.0;
15969 else
15970 return SCIPvarGetVSIDSCurrentRun(var->data.original.transvar, stat, dir);
15971
15974 return SCIPhistoryGetVSIDS(var->historycrun, dir)/stat->vsidsweight;
15975
15977 return 0.0;
15978
15980 if( var->data.aggregate.scalar > 0.0 )
15981 return SCIPvarGetVSIDSCurrentRun(var->data.aggregate.var, stat, dir);
15982 else
15984
15986 return 0.0;
15987
15990
15991 default:
15992 SCIPerrorMessage("unknown variable status\n");
15993 SCIPABORT();
15994 return 0.0; /*lint !e527*/
15995 }
15996}
15997
15998/** returns the number of inferences branching on this variable in given direction triggered */
16000 SCIP_VAR* var, /**< problem variable */
16001 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16002 )
16003{
16004 assert(var != NULL);
16005 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16006
16007 switch( SCIPvarGetStatus(var) )
16008 {
16010 if( var->data.original.transvar == NULL )
16011 return 0.0;
16012 else
16013 return SCIPvarGetInferenceSum(var->data.original.transvar, dir);
16014
16017 return SCIPhistoryGetInferenceSum(var->history, dir);
16018
16020 return 0.0;
16021
16023 if( var->data.aggregate.scalar > 0.0 )
16024 return SCIPvarGetInferenceSum(var->data.aggregate.var, dir);
16025 else
16027
16029 return 0.0;
16030
16033
16034 default:
16035 SCIPerrorMessage("unknown variable status\n");
16036 SCIPABORT();
16037 return 0.0; /*lint !e527*/
16038 }
16039}
16040
16041/** returns the number of inferences branching on this variable in given direction triggered
16042 * in the current run
16043 */
16045 SCIP_VAR* var, /**< problem variable */
16046 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16047 )
16048{
16049 assert(var != NULL);
16050 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16051
16052 switch( SCIPvarGetStatus(var) )
16053 {
16055 if( var->data.original.transvar == NULL )
16056 return 0.0;
16057 else
16059
16062 return SCIPhistoryGetInferenceSum(var->historycrun, dir);
16063
16065 return 0.0;
16066
16068 if( var->data.aggregate.scalar > 0.0 )
16070 else
16072
16074 return 0.0;
16075
16078
16079 default:
16080 SCIPerrorMessage("unknown variable status\n");
16081 SCIPABORT();
16082 return 0.0; /*lint !e527*/
16083 }
16084}
16085
16086/** returns the average number of inferences found after branching on the variable in given direction */
16088 SCIP_VAR* var, /**< problem variable */
16089 SCIP_STAT* stat, /**< problem statistics */
16090 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16091 )
16092{
16093 assert(var != NULL);
16094 assert(stat != NULL);
16095 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16096
16097 switch( SCIPvarGetStatus(var) )
16098 {
16100 if( var->data.original.transvar == NULL )
16101 return SCIPhistoryGetAvgInferences(stat->glbhistory, dir);
16102 else
16103 return SCIPvarGetAvgInferences(var->data.original.transvar, stat, dir);
16104
16107 if( SCIPhistoryGetNBranchings(var->history, dir) > 0 )
16108 return SCIPhistoryGetAvgInferences(var->history, dir);
16109 else
16110 {
16111 int nimpls;
16112 int ncliques;
16113
16114 nimpls = SCIPvarGetNImpls(var, dir == SCIP_BRANCHDIR_UPWARDS);
16115 ncliques = SCIPvarGetNCliques(var, dir == SCIP_BRANCHDIR_UPWARDS);
16116 return nimpls + ncliques > 0 ? (SCIP_Real)(nimpls + 2*ncliques) : SCIPhistoryGetAvgInferences(stat->glbhistory, dir); /*lint !e790*/
16117 }
16118
16120 return 0.0;
16121
16123 if( var->data.aggregate.scalar > 0.0 )
16124 return SCIPvarGetAvgInferences(var->data.aggregate.var, stat, dir);
16125 else
16127
16129 return 0.0;
16130
16133
16134 default:
16135 SCIPerrorMessage("unknown variable status\n");
16136 SCIPABORT();
16137 return 0.0; /*lint !e527*/
16138 }
16139}
16140
16141/** returns the average number of inferences found after branching on the variable in given direction
16142 * in the current run
16143 */
16145 SCIP_VAR* var, /**< problem variable */
16146 SCIP_STAT* stat, /**< problem statistics */
16147 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16148 )
16149{
16150 assert(var != NULL);
16151 assert(stat != NULL);
16152 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16153
16154 switch( SCIPvarGetStatus(var) )
16155 {
16157 if( var->data.original.transvar == NULL )
16159 else
16161
16164 if( SCIPhistoryGetNBranchings(var->historycrun, dir) > 0 )
16165 return SCIPhistoryGetAvgInferences(var->historycrun, dir);
16166 else
16167 {
16168 int nimpls;
16169 int ncliques;
16170
16171 nimpls = SCIPvarGetNImpls(var, dir == SCIP_BRANCHDIR_UPWARDS);
16172 ncliques = SCIPvarGetNCliques(var, dir == SCIP_BRANCHDIR_UPWARDS);
16173 return nimpls + ncliques > 0 ? (SCIP_Real)(nimpls + 2*ncliques) : SCIPhistoryGetAvgInferences(stat->glbhistorycrun, dir); /*lint !e790*/
16174 }
16175
16177 return 0.0;
16178
16180 if( var->data.aggregate.scalar > 0.0 )
16181 return SCIPvarGetAvgInferencesCurrentRun(var->data.aggregate.var, stat, dir);
16182 else
16184
16186 return 0.0;
16187
16190
16191 default:
16192 SCIPerrorMessage("unknown variable status\n");
16193 SCIPABORT();
16194 return 0.0; /*lint !e527*/
16195 }
16196}
16197
16198/** returns the number of cutoffs branching on this variable in given direction produced */
16200 SCIP_VAR* var, /**< problem variable */
16201 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16202 )
16203{
16204 assert(var != NULL);
16205 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16206
16207 switch( SCIPvarGetStatus(var) )
16208 {
16210 if( var->data.original.transvar == NULL )
16211 return 0;
16212 else
16213 return SCIPvarGetCutoffSum(var->data.original.transvar, dir);
16214
16217 return SCIPhistoryGetCutoffSum(var->history, dir);
16218
16220 return 0;
16221
16223 if( var->data.aggregate.scalar > 0.0 )
16224 return SCIPvarGetCutoffSum(var->data.aggregate.var, dir);
16225 else
16227
16229 return 0;
16230
16233
16234 default:
16235 SCIPerrorMessage("unknown variable status\n");
16236 SCIPABORT();
16237 return 0; /*lint !e527*/
16238 }
16239}
16240
16241/** returns the number of cutoffs branching on this variable in given direction produced in the current run */
16243 SCIP_VAR* var, /**< problem variable */
16244 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16245 )
16246{
16247 assert(var != NULL);
16248 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16249
16250 switch( SCIPvarGetStatus(var) )
16251 {
16253 if( var->data.original.transvar == NULL )
16254 return 0;
16255 else
16257
16260 return SCIPhistoryGetCutoffSum(var->historycrun, dir);
16261
16263 return 0;
16264
16266 if( var->data.aggregate.scalar > 0.0 )
16268 else
16270
16272 return 0;
16273
16276
16277 default:
16278 SCIPerrorMessage("unknown variable status\n");
16279 SCIPABORT();
16280 return 0; /*lint !e527*/
16281 }
16282}
16283
16284/** returns the average number of cutoffs found after branching on the variable in given direction */
16286 SCIP_VAR* var, /**< problem variable */
16287 SCIP_STAT* stat, /**< problem statistics */
16288 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16289 )
16290{
16291 assert(var != NULL);
16292 assert(stat != NULL);
16293 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16294
16295 switch( SCIPvarGetStatus(var) )
16296 {
16298 if( var->data.original.transvar == NULL )
16299 return SCIPhistoryGetAvgCutoffs(stat->glbhistory, dir);
16300 else
16301 return SCIPvarGetAvgCutoffs(var->data.original.transvar, stat, dir);
16302
16305 return SCIPhistoryGetNBranchings(var->history, dir) > 0
16308
16310 return 0.0;
16311
16313 if( var->data.aggregate.scalar > 0.0 )
16314 return SCIPvarGetAvgCutoffs(var->data.aggregate.var, stat, dir);
16315 else
16317
16319 return 0.0;
16320
16322 return SCIPvarGetAvgCutoffs(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
16323
16324 default:
16325 SCIPerrorMessage("unknown variable status\n");
16326 SCIPABORT();
16327 return 0.0; /*lint !e527*/
16328 }
16329}
16330
16331/** returns the average number of cutoffs found after branching on the variable in given direction in the current run */
16333 SCIP_VAR* var, /**< problem variable */
16334 SCIP_STAT* stat, /**< problem statistics */
16335 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
16336 )
16337{
16338 assert(var != NULL);
16339 assert(stat != NULL);
16340 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16341
16342 switch( SCIPvarGetStatus(var) )
16343 {
16345 if( var->data.original.transvar == NULL )
16346 return SCIPhistoryGetAvgCutoffs(stat->glbhistorycrun, dir);
16347 else
16348 return SCIPvarGetAvgCutoffsCurrentRun(var->data.original.transvar, stat, dir);
16349
16352 return SCIPhistoryGetNBranchings(var->historycrun, dir) > 0
16355
16357 return 0.0;
16358
16360 if( var->data.aggregate.scalar > 0.0 )
16361 return SCIPvarGetAvgCutoffsCurrentRun(var->data.aggregate.var, stat, dir);
16362 else
16364
16366 return 0.0;
16367
16370
16371 default:
16372 SCIPerrorMessage("unknown variable status\n");
16373 SCIPABORT();
16374 return 0.0; /*lint !e527*/
16375 }
16376}
16377
16378/** returns the variable's average GMI efficacy score value generated from simplex tableau rows of this variable */
16380 SCIP_VAR* var, /**< problem variable */
16381 SCIP_STAT* stat /**< problem statistics */
16382 )
16383{
16384 assert(var != NULL);
16385 assert(stat != NULL);
16386
16387 switch( SCIPvarGetStatus(var) )
16388 {
16390 if( var->data.original.transvar == NULL )
16391 return 0.0;
16392 else
16393 return SCIPvarGetAvgGMIScore(var->data.original.transvar, stat);
16394
16397 return SCIPhistoryGetAvgGMIeff(var->history);
16398
16400 return 0.0;
16401
16403 return SCIPvarGetAvgGMIScore(var->data.aggregate.var, stat);
16404
16406 return 0.0;
16407
16409 return SCIPvarGetAvgGMIScore(var->negatedvar, stat);
16410
16411 default:
16412 SCIPerrorMessage("unknown variable status\n");
16413 SCIPABORT();
16414 return 0.0; /*lint !e527*/
16415 }
16416}
16417
16418/** increase the variable's GMI efficacy scores generated from simplex tableau rows of this variable */
16420 SCIP_VAR* var, /**< problem variable */
16421 SCIP_STAT* stat, /**< problem statistics */
16422 SCIP_Real gmieff /**< efficacy of last GMI cut produced when variable was frac and basic */
16423 )
16424{
16425 assert(var != NULL);
16426 assert(stat != NULL);
16427 assert(gmieff >= 0);
16428
16429 switch( SCIPvarGetStatus(var) )
16430 {
16432 if( var->data.original.transvar != NULL )
16433 SCIP_CALL( SCIPvarIncGMIeffSum(var->data.original.transvar, stat, gmieff) );
16434 return SCIP_OKAY;
16435
16438 SCIPhistoryIncGMIeffSum(var->history, gmieff);
16439 return SCIP_OKAY;
16440
16442 return SCIP_INVALIDDATA;
16443
16445 SCIP_CALL( SCIPvarIncGMIeffSum(var->data.aggregate.var, stat, gmieff) );
16446 return SCIP_OKAY;
16447
16449 SCIP_CALL( SCIPvarIncGMIeffSum(var->negatedvar, stat, gmieff) );
16450 return SCIP_OKAY;
16451
16453 return SCIP_INVALIDDATA;
16454
16455 default:
16456 SCIPerrorMessage("unknown variable status\n");
16457 SCIPABORT();
16458 return SCIP_INVALIDDATA; /*lint !e527*/
16459 }
16460}
16461
16462/** returns the variable's last GMI efficacy score value generated from a simplex tableau row of this variable */
16464 SCIP_VAR* var, /**< problem variable */
16465 SCIP_STAT* stat /**< problem statistics */
16466 )
16467{
16468 assert(var != NULL);
16469 assert(stat != NULL);
16470
16471 switch( SCIPvarGetStatus(var) )
16472 {
16474 if( var->data.original.transvar != NULL )
16475 return SCIPvarGetLastGMIScore(var->data.original.transvar, stat);
16476 return 0.0;
16477
16480 return SCIPhistoryGetLastGMIeff(var->history);
16481
16483 return 0.0;
16484
16486 return SCIPvarGetLastGMIScore(var->data.aggregate.var, stat);
16487
16489 return 0.0;
16490
16492 return SCIPvarGetLastGMIScore(var->negatedvar, stat);
16493
16494 default:
16495 SCIPerrorMessage("unknown variable status\n");
16496 SCIPABORT();
16497 return 0.0; /*lint !e527*/
16498 }
16499}
16500
16501
16502/** sets the variable's last GMI efficacy score value generated from a simplex tableau row of this variable */
16504 SCIP_VAR* var, /**< problem variable */
16505 SCIP_STAT* stat, /**< problem statistics */
16506 SCIP_Real gmieff /**< efficacy of last GMI cut produced when variable was frac and basic */
16507 )
16508{
16509 assert(var != NULL);
16510 assert(stat != NULL);
16511 assert(gmieff >= 0);
16512
16513 switch( SCIPvarGetStatus(var) )
16514 {
16516 if( var->data.original.transvar != NULL )
16517 SCIP_CALL( SCIPvarSetLastGMIScore(var->data.original.transvar, stat, gmieff) );
16518 return SCIP_OKAY;
16519
16522 SCIPhistorySetLastGMIeff(var->history, gmieff);
16523 return SCIP_OKAY;
16524
16526 return SCIP_INVALIDDATA;
16527
16529 SCIP_CALL( SCIPvarSetLastGMIScore(var->data.aggregate.var, stat, gmieff) );
16530 return SCIP_OKAY;
16531
16533 SCIP_CALL( SCIPvarSetLastGMIScore(var->negatedvar, stat, gmieff) );
16534 return SCIP_OKAY;
16535
16537 return SCIP_INVALIDDATA;
16538
16539 default:
16540 SCIPerrorMessage("unknown variable status\n");
16541 SCIPABORT();
16542 return SCIP_INVALIDDATA; /*lint !e527*/
16543 }
16544}
16545
16546
16547
16548/*
16549 * information methods for bound changes
16550 */
16551
16552/** creates an artificial bound change information object with depth = INT_MAX and pos = -1 */
16554 SCIP_BDCHGINFO** bdchginfo, /**< pointer to store bound change information */
16555 BMS_BLKMEM* blkmem, /**< block memory */
16556 SCIP_VAR* var, /**< active variable that changed the bounds */
16557 SCIP_BOUNDTYPE boundtype, /**< type of bound for var: lower or upper bound */
16558 SCIP_Real oldbound, /**< old value for bound */
16559 SCIP_Real newbound /**< new value for bound */
16560 )
16561{
16562 assert(bdchginfo != NULL);
16563
16564 SCIP_ALLOC( BMSallocBlockMemory(blkmem, bdchginfo) );
16565 (*bdchginfo)->oldbound = oldbound;
16566 (*bdchginfo)->newbound = newbound;
16567 (*bdchginfo)->var = var;
16568 (*bdchginfo)->inferencedata.var = var;
16569 (*bdchginfo)->inferencedata.reason.prop = NULL;
16570 (*bdchginfo)->inferencedata.info = 0;
16571 (*bdchginfo)->bdchgidx.depth = INT_MAX;
16572 (*bdchginfo)->bdchgidx.pos = -1;
16573 (*bdchginfo)->pos = 0;
16574 (*bdchginfo)->boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
16575 (*bdchginfo)->boundtype = boundtype; /*lint !e641*/
16576 (*bdchginfo)->inferboundtype = boundtype; /*lint !e641*/
16577 (*bdchginfo)->redundant = FALSE;
16578
16579 return SCIP_OKAY;
16580}
16581
16582/** frees a bound change information object */
16584 SCIP_BDCHGINFO** bdchginfo, /**< pointer to store bound change information */
16585 BMS_BLKMEM* blkmem /**< block memory */
16586 )
16587{
16588 assert(bdchginfo != NULL);
16589
16590 BMSfreeBlockMemory(blkmem, bdchginfo);
16591}
16592
16593/** returns the bound change information for the last lower bound change on given active problem variable before or
16594 * after the bound change with the given index was applied;
16595 * returns NULL, if no change to the lower bound was applied up to this point of time
16596 */
16598 SCIP_VAR* var, /**< active problem variable */
16599 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16600 SCIP_Bool after /**< should the bound change with given index be included? */
16601 )
16602{
16603 int i;
16604
16605 assert(var != NULL);
16606 assert(SCIPvarIsActive(var));
16607
16608 /* search the correct bound change information for the given bound change index */
16609 if( after )
16610 {
16611 for( i = var->nlbchginfos-1; i >= 0; --i )
16612 {
16613 assert(var->lbchginfos[i].var == var);
16615 assert(var->lbchginfos[i].pos == i);
16616
16617 /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16618 if( var->lbchginfos[i].redundant )
16619 return NULL;
16620 assert(var->lbchginfos[i].oldbound < var->lbchginfos[i].newbound);
16621
16622 /* if we reached the bound change index, return the current bound change info */
16623 if( !SCIPbdchgidxIsEarlier(bdchgidx, &var->lbchginfos[i].bdchgidx) )
16624 return &var->lbchginfos[i];
16625 }
16626 }
16627 else
16628 {
16629 for( i = var->nlbchginfos-1; i >= 0; --i )
16630 {
16631 assert(var->lbchginfos[i].var == var);
16633 assert(var->lbchginfos[i].pos == i);
16634
16635 /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16636 if( var->lbchginfos[i].redundant )
16637 return NULL;
16638 assert(var->lbchginfos[i].oldbound < var->lbchginfos[i].newbound);
16639
16640 /* if we reached the bound change index, return the current bound change info */
16641 if( SCIPbdchgidxIsEarlier(&var->lbchginfos[i].bdchgidx, bdchgidx) )
16642 return &var->lbchginfos[i];
16643 }
16644 }
16645
16646 return NULL;
16647}
16648
16649/** returns the bound change information for the last upper bound change on given active problem variable before or
16650 * after the bound change with the given index was applied;
16651 * returns NULL, if no change to the upper bound was applied up to this point of time
16652 */
16654 SCIP_VAR* var, /**< active problem variable */
16655 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16656 SCIP_Bool after /**< should the bound change with given index be included? */
16657 )
16658{
16659 int i;
16660
16661 assert(var != NULL);
16662 assert(SCIPvarIsActive(var));
16663
16664 /* search the correct bound change information for the given bound change index */
16665 if( after )
16666 {
16667 for( i = var->nubchginfos-1; i >= 0; --i )
16668 {
16669 assert(var->ubchginfos[i].var == var);
16671 assert(var->ubchginfos[i].pos == i);
16672
16673 /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16674 if( var->ubchginfos[i].redundant )
16675 return NULL;
16676 assert(var->ubchginfos[i].oldbound > var->ubchginfos[i].newbound);
16677
16678 /* if we reached the bound change index, return the current bound change info */
16679 if( !SCIPbdchgidxIsEarlier(bdchgidx, &var->ubchginfos[i].bdchgidx) )
16680 return &var->ubchginfos[i];
16681 }
16682 }
16683 else
16684 {
16685 for( i = var->nubchginfos-1; i >= 0; --i )
16686 {
16687 assert(var->ubchginfos[i].var == var);
16689 assert(var->ubchginfos[i].pos == i);
16690
16691 /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16692 if( var->ubchginfos[i].redundant )
16693 return NULL;
16694 assert(var->ubchginfos[i].oldbound > var->ubchginfos[i].newbound);
16695
16696 /* if we reached the bound change index, return the current bound change info */
16697 if( SCIPbdchgidxIsEarlier(&var->ubchginfos[i].bdchgidx, bdchgidx) )
16698 return &var->ubchginfos[i];
16699 }
16700 }
16701
16702 return NULL;
16703}
16704
16705/** returns the bound change information for the last lower or upper bound change on given active problem variable
16706 * before or after the bound change with the given index was applied;
16707 * returns NULL, if no change to the lower/upper bound was applied up to this point of time
16708 */
16710 SCIP_VAR* var, /**< active problem variable */
16711 SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */
16712 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16713 SCIP_Bool after /**< should the bound change with given index be included? */
16714 )
16715{
16716 if( boundtype == SCIP_BOUNDTYPE_LOWER )
16717 return SCIPvarGetLbchgInfo(var, bdchgidx, after);
16718 else
16719 {
16720 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
16721 return SCIPvarGetUbchgInfo(var, bdchgidx, after);
16722 }
16723}
16724
16725/** returns lower bound of variable directly before or after the bound change given by the bound change index
16726 * was applied
16727 *
16728 * @deprecated Please use SCIPgetVarLbAtIndex()
16729 */
16731 SCIP_VAR* var, /**< problem variable */
16732 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16733 SCIP_Bool after /**< should the bound change with given index be included? */
16734 )
16735{
16736 SCIP_VARSTATUS varstatus;
16737 assert(var != NULL);
16738
16739 varstatus = SCIPvarGetStatus(var);
16740
16741 /* get bounds of attached variables */
16742 switch( varstatus )
16743 {
16745 assert(var->data.original.transvar != NULL);
16746 return SCIPvarGetLbAtIndex(var->data.original.transvar, bdchgidx, after);
16747
16750 if( bdchgidx == NULL )
16751 return SCIPvarGetLbLocal(var);
16752 else
16753 {
16754 SCIP_BDCHGINFO* bdchginfo;
16755
16756 bdchginfo = SCIPvarGetLbchgInfo(var, bdchgidx, after);
16757 if( bdchginfo != NULL )
16758 return SCIPbdchginfoGetNewbound(bdchginfo);
16759 else
16760 return var->glbdom.lb;
16761 }
16763 return var->glbdom.lb;
16764
16765 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
16766 assert(var->data.aggregate.var != NULL);
16767 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
16768 * corresponding infinity value instead of performing an arithmetical transformation (compare method
16769 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
16770 * (or is called by) a public interface method; instead, we only assert that values are finite
16771 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
16772 * positives and negatives if the parameter <numerics/infinity> is modified by the user
16773 */
16774 if( var->data.aggregate.scalar > 0.0 )
16775 {
16776 /* a > 0 -> get lower bound of y */
16777 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16778 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16779 return var->data.aggregate.scalar * SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after)
16780 + var->data.aggregate.constant;
16781 }
16782 else if( var->data.aggregate.scalar < 0.0 )
16783 {
16784 /* a < 0 -> get upper bound of y */
16785 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16786 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16787 return var->data.aggregate.scalar * SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after)
16788 + var->data.aggregate.constant;
16789 }
16790 else
16791 {
16792 SCIPerrorMessage("scalar is zero in aggregation\n");
16793 SCIPABORT();
16794 return SCIP_INVALID; /*lint !e527*/
16795 }
16796
16798 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
16799 if ( var->data.multaggr.nvars == 1 )
16800 {
16801 assert(var->data.multaggr.vars != NULL);
16802 assert(var->data.multaggr.scalars != NULL);
16803 assert(var->data.multaggr.vars[0] != NULL);
16804
16805 if( var->data.multaggr.scalars[0] > 0.0 )
16806 {
16807 /* a > 0 -> get lower bound of y */
16808 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16809 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16810 return var->data.multaggr.scalars[0] * SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16811 + var->data.multaggr.constant;
16812 }
16813 else if( var->data.multaggr.scalars[0] < 0.0 )
16814 {
16815 /* a < 0 -> get upper bound of y */
16816 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16817 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16818 return var->data.multaggr.scalars[0] * SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16819 + var->data.multaggr.constant;
16820 }
16821 else
16822 {
16823 SCIPerrorMessage("scalar is zero in multi-aggregation\n");
16824 SCIPABORT();
16825 return SCIP_INVALID; /*lint !e527*/
16826 }
16827 }
16828 SCIPerrorMessage("cannot get the bounds of a multi-aggregated variable.\n");
16829 SCIPABORT();
16830 return SCIP_INVALID; /*lint !e527*/
16831
16832 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
16833 assert(var->negatedvar != NULL);
16835 assert(var->negatedvar->negatedvar == var);
16836 return var->data.negate.constant - SCIPvarGetUbAtIndex(var->negatedvar, bdchgidx, after);
16837 default:
16838 SCIPerrorMessage("unknown variable status\n");
16839 SCIPABORT();
16840 return SCIP_INVALID; /*lint !e527*/
16841 }
16842}
16843
16844/** returns upper bound of variable directly before or after the bound change given by the bound change index
16845 * was applied
16846 *
16847 * @deprecated Please use SCIPgetVarUbAtIndex()
16848 */
16850 SCIP_VAR* var, /**< problem variable */
16851 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16852 SCIP_Bool after /**< should the bound change with given index be included? */
16853 )
16854{
16855 SCIP_VARSTATUS varstatus;
16856 assert(var != NULL);
16857
16858 varstatus = SCIPvarGetStatus(var);
16859
16860 /* get bounds of attached variables */
16861 switch( varstatus )
16862 {
16864 assert(var->data.original.transvar != NULL);
16865 return SCIPvarGetUbAtIndex(var->data.original.transvar, bdchgidx, after);
16866
16869 if( bdchgidx == NULL )
16870 return SCIPvarGetUbLocal(var);
16871 else
16872 {
16873 SCIP_BDCHGINFO* bdchginfo;
16874
16875 bdchginfo = SCIPvarGetUbchgInfo(var, bdchgidx, after);
16876 if( bdchginfo != NULL )
16877 return SCIPbdchginfoGetNewbound(bdchginfo);
16878 else
16879 return var->glbdom.ub;
16880 }
16881
16883 return var->glbdom.ub;
16884
16885 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
16886 assert(var->data.aggregate.var != NULL);
16887 /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
16888 * corresponding infinity value instead of performing an arithmetical transformation (compare method
16889 * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
16890 * (or is called by) a public interface method; instead, we only assert that values are finite
16891 * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
16892 * positives and negatives if the parameter <numerics/infinity> is modified by the user
16893 */
16894 if( var->data.aggregate.scalar > 0.0 )
16895 {
16896 /* a > 0 -> get lower bound of y */
16897 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16898 assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16899 return var->data.aggregate.scalar * SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after)
16900 + var->data.aggregate.constant;
16901 }
16902 else if( var->data.aggregate.scalar < 0.0 )
16903 {
16904 /* a < 0 -> get upper bound of y */
16905 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16906 assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16907 return var->data.aggregate.scalar * SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after)
16908 + var->data.aggregate.constant;
16909 }
16910 else
16911 {
16912 SCIPerrorMessage("scalar is zero in aggregation\n");
16913 SCIPABORT();
16914 return SCIP_INVALID; /*lint !e527*/
16915 }
16916
16918 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
16919 if ( var->data.multaggr.nvars == 1 )
16920 {
16921 assert(var->data.multaggr.vars != NULL);
16922 assert(var->data.multaggr.scalars != NULL);
16923 assert(var->data.multaggr.vars[0] != NULL);
16924
16925 if( var->data.multaggr.scalars[0] > 0.0 )
16926 {
16927 /* a > 0 -> get lower bound of y */
16928 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16929 assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16930 return var->data.multaggr.scalars[0] * SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16931 + var->data.multaggr.constant;
16932 }
16933 else if( var->data.multaggr.scalars[0] < 0.0 )
16934 {
16935 /* a < 0 -> get upper bound of y */
16936 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16937 assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16938 return var->data.multaggr.scalars[0] * SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16939 + var->data.multaggr.constant;
16940 }
16941 else
16942 {
16943 SCIPerrorMessage("scalar is zero in multi-aggregation\n");
16944 SCIPABORT();
16945 return SCIP_INVALID; /*lint !e527*/
16946 }
16947 }
16948 SCIPerrorMessage("cannot get the bounds of a multiple aggregated variable.\n");
16949 SCIPABORT();
16950 return SCIP_INVALID; /*lint !e527*/
16951
16952 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
16953 assert(var->negatedvar != NULL);
16955 assert(var->negatedvar->negatedvar == var);
16956 return var->data.negate.constant - SCIPvarGetLbAtIndex(var->negatedvar, bdchgidx, after);
16957
16958 default:
16959 SCIPerrorMessage("unknown variable status\n");
16960 SCIPABORT();
16961 return SCIP_INVALID; /*lint !e527*/
16962 }
16963}
16964
16965/** returns lower or upper bound of variable directly before or after the bound change given by the bound change index
16966 * was applied
16967 *
16968 * @deprecated Please use SCIPgetVarBdAtIndex()
16969 */
16971 SCIP_VAR* var, /**< problem variable */
16972 SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */
16973 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16974 SCIP_Bool after /**< should the bound change with given index be included? */
16975 )
16976{
16977 if( boundtype == SCIP_BOUNDTYPE_LOWER )
16978 return SCIPvarGetLbAtIndex(var, bdchgidx, after);
16979 else
16980 {
16981 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
16982 return SCIPvarGetUbAtIndex(var, bdchgidx, after);
16983 }
16984}
16985
16986/** returns whether the binary variable was fixed at the time given by the bound change index
16987 *
16988 * @deprecated Please use SCIPgetVarWasFixedAtIndex()
16989 */
16991 SCIP_VAR* var, /**< problem variable */
16992 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
16993 SCIP_Bool after /**< should the bound change with given index be included? */
16994 )
16995{
16996 assert(var != NULL);
16997 assert(SCIPvarIsBinary(var));
16998
16999 /* check the current bounds first in order to decide at which bound change information we have to look
17000 * (which is expensive because we have to follow the aggregation tree to the active variable)
17001 */
17002 return ((SCIPvarGetLbLocal(var) > 0.5 && SCIPvarGetLbAtIndex(var, bdchgidx, after) > 0.5)
17003 || (SCIPvarGetUbLocal(var) < 0.5 && SCIPvarGetUbAtIndex(var, bdchgidx, after) < 0.5));
17004}
17005
17006/** bound change index representing the initial time before any bound changes took place */
17008
17009/** bound change index representing the presolving stage */
17011
17012/** returns the last bound change index, at which the bounds of the given variable were tightened */
17014 SCIP_VAR* var /**< problem variable */
17015 )
17016{
17017 SCIP_BDCHGIDX* lbchgidx;
17018 SCIP_BDCHGIDX* ubchgidx;
17019
17020 assert(var != NULL);
17021
17022 var = SCIPvarGetProbvar(var);
17023
17024 /* check, if variable is original without transformed variable */
17025 if( var == NULL )
17026 return &initbdchgidx;
17027
17028 /* check, if variable was fixed in presolving */
17029 if( !SCIPvarIsActive(var) )
17030 return &presolvebdchgidx;
17031
17033
17034 /* get depths of last bound change information for the lower and upper bound */
17035 lbchgidx = (var->nlbchginfos > 0 && !var->lbchginfos[var->nlbchginfos-1].redundant
17036 ? &var->lbchginfos[var->nlbchginfos-1].bdchgidx : &initbdchgidx);
17037 ubchgidx = (var->nubchginfos > 0 && !var->ubchginfos[var->nubchginfos-1].redundant
17038 ? &var->ubchginfos[var->nubchginfos-1].bdchgidx : &initbdchgidx);
17039
17040 if( SCIPbdchgidxIsEarlierNonNull(lbchgidx, ubchgidx) )
17041 return ubchgidx;
17042 else
17043 return lbchgidx;
17044}
17045
17046/** returns the last depth level, at which the bounds of the given variable were tightened;
17047 * returns -2, if the variable's bounds are still the global bounds
17048 * returns -1, if the variable was fixed in presolving
17049 */
17051 SCIP_VAR* var /**< problem variable */
17052 )
17053{
17054 SCIP_BDCHGIDX* bdchgidx;
17055
17056 bdchgidx = SCIPvarGetLastBdchgIndex(var);
17057 assert(bdchgidx != NULL);
17058
17059 return bdchgidx->depth;
17060}
17061
17062/** returns at which depth in the tree a bound change was applied to the variable that conflicts with the
17063 * given bound; returns -1 if the bound does not conflict with the current local bounds of the variable
17064 */
17066 SCIP_VAR* var, /**< problem variable */
17067 SCIP_SET* set, /**< global SCIP settings */
17068 SCIP_BOUNDTYPE boundtype, /**< bound type of the conflicting bound */
17069 SCIP_Real bound /**< conflicting bound */
17070 )
17071{
17072 int i;
17073
17074 assert(var != NULL);
17075 assert(set != NULL);
17076 assert(var->scip == set->scip);
17077
17078 if( boundtype == SCIP_BOUNDTYPE_LOWER )
17079 {
17080 /* check if the bound is in conflict with the current local bounds */
17081 if( SCIPsetIsLE(set, bound, var->locdom.ub) )
17082 return -1;
17083
17084 /* check if the bound is in conflict with the global bound */
17085 if( SCIPsetIsGT(set, bound, var->glbdom.ub) )
17086 return 0;
17087
17088 /* local bounds are in conflict with the given bound -> there must be at least one conflicting change! */
17089 assert(var->nubchginfos > 0);
17090 assert(SCIPsetIsGT(set, bound, var->ubchginfos[var->nubchginfos-1].newbound));
17091
17092 /* search for the first conflicting bound change */
17093 for( i = var->nubchginfos-1; i > 0 && SCIPsetIsGT(set, bound, var->ubchginfos[i-1].newbound); --i )
17094 {
17095 assert(var->ubchginfos[i].var == var); /* perform sanity check on the search for the first conflicting bound */
17097 }
17098 assert(SCIPsetIsGT(set, bound, var->ubchginfos[i].newbound)); /* bound change i is conflicting */
17099 assert(i == 0 || SCIPsetIsLE(set, bound, var->ubchginfos[i-1].newbound)); /* bound change i-1 is not conflicting */
17100
17101 /* return the depth at which the first conflicting bound change took place */
17102 return var->ubchginfos[i].bdchgidx.depth;
17103 }
17104 else
17105 {
17106 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
17107
17108 /* check if the bound is in conflict with the current local bounds */
17109 if( SCIPsetIsGE(set, bound, var->locdom.lb) )
17110 return -1;
17111
17112 /* check if the bound is in conflict with the global bound */
17113 if( SCIPsetIsLT(set, bound, var->glbdom.lb) )
17114 return 0;
17115
17116 /* local bounds are in conflict with the given bound -> there must be at least one conflicting change! */
17117 assert(var->nlbchginfos > 0);
17118 assert(SCIPsetIsLT(set, bound, var->lbchginfos[var->nlbchginfos-1].newbound));
17119
17120 /* search for the first conflicting bound change */
17121 for( i = var->nlbchginfos-1; i > 0 && SCIPsetIsLT(set, bound, var->lbchginfos[i-1].newbound); --i )
17122 {
17123 assert(var->lbchginfos[i].var == var); /* perform sanity check on the search for the first conflicting bound */
17125 }
17126 assert(SCIPsetIsLT(set, bound, var->lbchginfos[i].newbound)); /* bound change i is conflicting */
17127 assert(i == 0 || SCIPsetIsGE(set, bound, var->lbchginfos[i-1].newbound)); /* bound change i-1 is not conflicting */
17128
17129 /* return the depth at which the first conflicting bound change took place */
17130 return var->lbchginfos[i].bdchgidx.depth;
17131 }
17132}
17133
17134/** returns whether the first binary variable was fixed earlier than the second one;
17135 * returns FALSE, if the first variable is not fixed, and returns TRUE, if the first variable is fixed, but the
17136 * second one is not fixed
17137 */
17139 SCIP_VAR* var1, /**< first binary variable */
17140 SCIP_VAR* var2 /**< second binary variable */
17141 )
17142{
17143 SCIP_BDCHGIDX* bdchgidx1;
17144 SCIP_BDCHGIDX* bdchgidx2;
17145
17146 assert(var1 != NULL);
17147 assert(var2 != NULL);
17148 assert(SCIPvarIsBinary(var1));
17149 assert(SCIPvarIsBinary(var2));
17150
17151 var1 = SCIPvarGetProbvar(var1);
17152 var2 = SCIPvarGetProbvar(var2);
17153 assert(var1 != NULL);
17154 assert(var2 != NULL);
17155
17156 /* check, if variables are globally fixed */
17157 if( !SCIPvarIsActive(var2) || var2->glbdom.lb > 0.5 || var2->glbdom.ub < 0.5 )
17158 return FALSE;
17159 if( !SCIPvarIsActive(var1) || var1->glbdom.lb > 0.5 || var1->glbdom.ub < 0.5 )
17160 return TRUE;
17161
17164 assert(SCIPvarIsBinary(var1));
17165 assert(SCIPvarIsBinary(var2));
17166 assert(var1->nlbchginfos + var1->nubchginfos <= 1);
17167 assert(var2->nlbchginfos + var2->nubchginfos <= 1);
17168 assert(var1->nlbchginfos == 0 || !var1->lbchginfos[0].redundant); /* otherwise, var would be globally fixed */
17169 assert(var1->nubchginfos == 0 || !var1->ubchginfos[0].redundant); /* otherwise, var would be globally fixed */
17170 assert(var2->nlbchginfos == 0 || !var2->lbchginfos[0].redundant); /* otherwise, var would be globally fixed */
17171 assert(var2->nubchginfos == 0 || !var2->ubchginfos[0].redundant); /* otherwise, var would be globally fixed */
17172
17173 if( var1->nlbchginfos == 1 )
17174 bdchgidx1 = &var1->lbchginfos[0].bdchgidx;
17175 else if( var1->nubchginfos == 1 )
17176 bdchgidx1 = &var1->ubchginfos[0].bdchgidx;
17177 else
17178 bdchgidx1 = NULL;
17179
17180 if( var2->nlbchginfos == 1 )
17181 bdchgidx2 = &var2->lbchginfos[0].bdchgidx;
17182 else if( var2->nubchginfos == 1 )
17183 bdchgidx2 = &var2->ubchginfos[0].bdchgidx;
17184 else
17185 bdchgidx2 = NULL;
17186
17187 return SCIPbdchgidxIsEarlier(bdchgidx1, bdchgidx2);
17188}
17189
17190
17191
17192/*
17193 * Hash functions
17194 */
17195
17196/** gets the key (i.e. the name) of the given variable */
17197SCIP_DECL_HASHGETKEY(SCIPhashGetKeyVar)
17198{ /*lint --e{715}*/
17199 SCIP_VAR* var = (SCIP_VAR*)elem;
17200
17201 assert(var != NULL);
17202 return var->name;
17203}
17204
17205
17206
17207
17208/*
17209 * simple functions implemented as defines
17210 */
17211
17212/* In debug mode, the following methods are implemented as function calls to ensure
17213 * type validity.
17214 * In optimized mode, the methods are implemented as defines to improve performance.
17215 * However, we want to have them in the library anyways, so we have to undef the defines.
17216 */
17217
17218#undef SCIPboundchgGetNewbound
17219#undef SCIPboundchgGetVar
17220#undef SCIPboundchgGetBoundchgtype
17221#undef SCIPboundchgGetBoundtype
17222#undef SCIPboundchgIsRedundant
17223#undef SCIPdomchgGetNBoundchgs
17224#undef SCIPdomchgGetBoundchg
17225#undef SCIPholelistGetLeft
17226#undef SCIPholelistGetRight
17227#undef SCIPholelistGetNext
17228#undef SCIPvarGetName
17229#undef SCIPvarGetNUses
17230#undef SCIPvarGetData
17231#undef SCIPvarSetData
17232#undef SCIPvarSetDelorigData
17233#undef SCIPvarSetTransData
17234#undef SCIPvarSetDeltransData
17235#undef SCIPvarGetStatus
17236#undef SCIPvarIsOriginal
17237#undef SCIPvarIsTransformed
17238#undef SCIPvarIsNegated
17239#undef SCIPvarGetType
17240#undef SCIPvarIsBinary
17241#undef SCIPvarIsIntegral
17242#undef SCIPvarIsInitial
17243#undef SCIPvarIsRemovable
17244#undef SCIPvarIsDeleted
17245#undef SCIPvarIsDeletable
17246#undef SCIPvarMarkDeletable
17247#undef SCIPvarMarkNotDeletable
17248#undef SCIPvarIsActive
17249#undef SCIPvarGetIndex
17250#undef SCIPvarGetProbindex
17251#undef SCIPvarGetTransVar
17252#undef SCIPvarGetCol
17253#undef SCIPvarIsInLP
17254#undef SCIPvarGetAggrVar
17255#undef SCIPvarGetAggrScalar
17256#undef SCIPvarGetAggrConstant
17257#undef SCIPvarGetMultaggrNVars
17258#undef SCIPvarGetMultaggrVars
17259#undef SCIPvarGetMultaggrScalars
17260#undef SCIPvarGetMultaggrConstant
17261#undef SCIPvarGetNegatedVar
17262#undef SCIPvarGetNegationVar
17263#undef SCIPvarGetNegationConstant
17264#undef SCIPvarGetObj
17265#undef SCIPvarGetLbOriginal
17266#undef SCIPvarGetUbOriginal
17267#undef SCIPvarGetHolelistOriginal
17268#undef SCIPvarGetLbGlobal
17269#undef SCIPvarGetUbGlobal
17270#undef SCIPvarGetHolelistGlobal
17271#undef SCIPvarGetBestBoundGlobal
17272#undef SCIPvarGetWorstBoundGlobal
17273#undef SCIPvarGetLbLocal
17274#undef SCIPvarGetUbLocal
17275#undef SCIPvarGetHolelistLocal
17276#undef SCIPvarGetBestBoundLocal
17277#undef SCIPvarGetWorstBoundLocal
17278#undef SCIPvarGetBestBoundType
17279#undef SCIPvarGetWorstBoundType
17280#undef SCIPvarGetLbLazy
17281#undef SCIPvarGetUbLazy
17282#undef SCIPvarGetBranchFactor
17283#undef SCIPvarGetBranchPriority
17284#undef SCIPvarGetBranchDirection
17285#undef SCIPvarGetNVlbs
17286#undef SCIPvarGetVlbVars
17287#undef SCIPvarGetVlbCoefs
17288#undef SCIPvarGetVlbConstants
17289#undef SCIPvarGetNVubs
17290#undef SCIPvarGetVubVars
17291#undef SCIPvarGetVubCoefs
17292#undef SCIPvarGetVubConstants
17293#undef SCIPvarGetNImpls
17294#undef SCIPvarGetImplVars
17295#undef SCIPvarGetImplTypes
17296#undef SCIPvarGetImplBounds
17297#undef SCIPvarGetImplIds
17298#undef SCIPvarGetNCliques
17299#undef SCIPvarGetCliques
17300#undef SCIPvarGetLPSol
17301#undef SCIPvarGetNLPSol
17302#undef SCIPvarGetBdchgInfoLb
17303#undef SCIPvarGetNBdchgInfosLb
17304#undef SCIPvarGetBdchgInfoUb
17305#undef SCIPvarGetNBdchgInfosUb
17306#undef SCIPvarGetValuehistory
17307#undef SCIPvarGetPseudoSol
17308#undef SCIPvarCatchEvent
17309#undef SCIPvarDropEvent
17310#undef SCIPvarGetVSIDS
17311#undef SCIPvarGetCliqueComponentIdx
17312#undef SCIPvarIsRelaxationOnly
17313#undef SCIPvarMarkRelaxationOnly
17314#undef SCIPbdchgidxGetPos
17315#undef SCIPbdchgidxIsEarlierNonNull
17316#undef SCIPbdchgidxIsEarlier
17317#undef SCIPbdchginfoGetOldbound
17318#undef SCIPbdchginfoGetNewbound
17319#undef SCIPbdchginfoGetVar
17320#undef SCIPbdchginfoGetChgtype
17321#undef SCIPbdchginfoGetBoundtype
17322#undef SCIPbdchginfoGetDepth
17323#undef SCIPbdchginfoGetPos
17324#undef SCIPbdchginfoGetIdx
17325#undef SCIPbdchginfoGetInferVar
17326#undef SCIPbdchginfoGetInferCons
17327#undef SCIPbdchginfoGetInferProp
17328#undef SCIPbdchginfoGetInferInfo
17329#undef SCIPbdchginfoGetInferBoundtype
17330#undef SCIPbdchginfoIsRedundant
17331#undef SCIPbdchginfoHasInferenceReason
17332#undef SCIPbdchginfoIsTighter
17333
17334
17335/** returns the new value of the bound in the bound change data */
17337 SCIP_BOUNDCHG* boundchg /**< bound change data */
17338 )
17339{
17340 assert(boundchg != NULL);
17341
17342 return boundchg->newbound;
17343}
17344
17345/** returns the variable of the bound change in the bound change data */
17347 SCIP_BOUNDCHG* boundchg /**< bound change data */
17348 )
17349{
17350 assert(boundchg != NULL);
17351
17352 return boundchg->var;
17353}
17354
17355/** returns the bound change type of the bound change in the bound change data */
17357 SCIP_BOUNDCHG* boundchg /**< bound change data */
17358 )
17359{
17360 assert(boundchg != NULL);
17361
17362 return (SCIP_BOUNDCHGTYPE)(boundchg->boundchgtype);
17363}
17364
17365/** returns the bound type of the bound change in the bound change data */
17367 SCIP_BOUNDCHG* boundchg /**< bound change data */
17368 )
17369{
17370 assert(boundchg != NULL);
17371
17372 return (SCIP_BOUNDTYPE)(boundchg->boundtype);
17373}
17374
17375/** returns whether the bound change is redundant due to a more global bound that is at least as strong */
17377 SCIP_BOUNDCHG* boundchg /**< bound change data */
17378 )
17379{
17380 assert(boundchg != NULL);
17381
17382 return boundchg->redundant;
17383}
17384
17385/** returns the number of bound changes in the domain change data */
17387 SCIP_DOMCHG* domchg /**< domain change data */
17388 )
17389{
17390 return domchg != NULL ? domchg->domchgbound.nboundchgs : 0;
17391}
17392
17393/** returns a particular bound change in the domain change data */
17395 SCIP_DOMCHG* domchg, /**< domain change data */
17396 int pos /**< position of the bound change in the domain change data */
17397 )
17398{
17399 assert(domchg != NULL);
17400 assert(0 <= pos && pos < (int)domchg->domchgbound.nboundchgs);
17401
17402 return &domchg->domchgbound.boundchgs[pos];
17403}
17404
17405/** returns left bound of open interval in hole */
17407 SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */
17408 )
17409{
17410 assert(holelist != NULL);
17411
17412 return holelist->hole.left;
17413}
17414
17415/** returns right bound of open interval in hole */
17417 SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */
17418 )
17419{
17420 assert(holelist != NULL);
17421
17422 return holelist->hole.right;
17423}
17424
17425/** returns next hole in list */
17427 SCIP_HOLELIST* holelist /**< hole list pointer to hole of interest */
17428 )
17429{
17430 assert(holelist != NULL);
17431
17432 return holelist->next;
17433}
17434
17435/** returns the name of the variable
17436 *
17437 * @note to change the name of a variable, use SCIPchgVarName() from scip.h
17438 */
17439const char* SCIPvarGetName(
17440 SCIP_VAR* var /**< problem variable */
17441 )
17442{
17443 assert(var != NULL);
17444
17445 return var->name;
17446}
17447
17448/** gets number of times, the variable is currently captured */
17450 SCIP_VAR* var /**< problem variable */
17451 )
17452{
17453 assert(var != NULL);
17454
17455 return var->nuses;
17456}
17457
17458/** returns the user data of the variable */
17460 SCIP_VAR* var /**< problem variable */
17461 )
17462{
17463 assert(var != NULL);
17464
17465 return var->vardata;
17466}
17467
17468/** sets the user data for the variable */
17470 SCIP_VAR* var, /**< problem variable */
17471 SCIP_VARDATA* vardata /**< user variable data */
17472 )
17473{
17474 assert(var != NULL);
17475
17476 var->vardata = vardata;
17477}
17478
17479/** sets method to free user data for the original variable */
17481 SCIP_VAR* var, /**< problem variable */
17482 SCIP_DECL_VARDELORIG ((*vardelorig)) /**< frees user data of original variable */
17483 )
17484{
17485 assert(var != NULL);
17487
17488 var->vardelorig = vardelorig;
17489}
17490
17491/** sets method to transform user data of the variable */
17493 SCIP_VAR* var, /**< problem variable */
17494 SCIP_DECL_VARTRANS ((*vartrans)) /**< creates transformed user data by transforming original user data */
17495 )
17496{
17497 assert(var != NULL);
17499
17500 var->vartrans = vartrans;
17501}
17502
17503/** sets method to free transformed user data for the variable */
17505 SCIP_VAR* var, /**< problem variable */
17506 SCIP_DECL_VARDELTRANS ((*vardeltrans)) /**< frees user data of transformed variable */
17507 )
17508{
17509 assert(var != NULL);
17510
17511 var->vardeltrans = vardeltrans;
17512}
17513
17514/** sets method to copy this variable into sub-SCIPs */
17516 SCIP_VAR* var, /**< problem variable */
17517 SCIP_DECL_VARCOPY ((*varcopy)) /**< copy method of the variable */
17518 )
17519{
17520 assert(var != NULL);
17521
17522 var->varcopy = varcopy;
17523}
17524
17525/** sets the initial flag of a variable; only possible for original or loose variables */
17527 SCIP_VAR* var, /**< problem variable */
17528 SCIP_Bool initial /**< initial flag */
17529 )
17530{
17531 assert(var != NULL);
17532
17534 return SCIP_INVALIDCALL;
17535
17536 var->initial = initial;
17537
17538 return SCIP_OKAY;
17539}
17540
17541/** sets the removable flag of a variable; only possible for original or loose variables */
17543 SCIP_VAR* var, /**< problem variable */
17544 SCIP_Bool removable /**< removable flag */
17545 )
17546{
17547 assert(var != NULL);
17548
17550 return SCIP_INVALIDCALL;
17551
17552 var->removable = removable;
17553
17554 return SCIP_OKAY;
17555}
17556
17557/** gets status of variable */
17559 SCIP_VAR* var /**< problem variable */
17560 )
17561{
17562 assert(var != NULL);
17563
17564 return (SCIP_VARSTATUS)(var->varstatus);
17565}
17566
17567/** returns whether the variable belongs to the original problem */
17569 SCIP_VAR* var /**< problem variable */
17570 )
17571{
17572 assert(var != NULL);
17573 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED || var->negatedvar != NULL);
17574
17578}
17579
17580/** returns whether the variable belongs to the transformed problem */
17582 SCIP_VAR* var /**< problem variable */
17583 )
17584{
17585 assert(var != NULL);
17586 assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED || var->negatedvar != NULL);
17587
17591}
17592
17593/** returns whether the variable was created by negation of a different variable */
17595 SCIP_VAR* var /**< problem variable */
17596 )
17597{
17598 assert(var != NULL);
17599
17601}
17602
17603/** gets type of variable */
17605 SCIP_VAR* var /**< problem variable */
17606 )
17607{
17608 assert(var != NULL);
17609
17610 return (SCIP_VARTYPE)(var->vartype);
17611}
17612
17613/** returns TRUE if the variable is of binary type; this is the case if:
17614 * (1) variable type is binary
17615 * (2) variable type is integer or implicit integer and
17616 * (i) the global lower bound is greater than or equal to zero
17617 * (ii) the global upper bound is less than or equal to one
17618 */
17620 SCIP_VAR* var /**< problem variable */
17621 )
17622{
17623 assert(var != NULL);
17624
17625 return (SCIPvarGetType(var) == SCIP_VARTYPE_BINARY ||
17626 (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && var->glbdom.lb >= 0.0 && var->glbdom.ub <= 1.0));
17627}
17628
17629/** returns whether variable is of integral type (binary, integer, or implicit integer) */
17631 SCIP_VAR* var /**< problem variable */
17632 )
17633{
17634 assert(var != NULL);
17635
17636 return (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
17637}
17638
17639/** returns whether variable's column should be present in the initial root LP */
17641 SCIP_VAR* var /**< problem variable */
17642 )
17643{
17644 assert(var != NULL);
17645
17646 return var->initial;
17647}
17648
17649/** returns whether variable's column is removable from the LP (due to aging or cleanup) */
17651 SCIP_VAR* var /**< problem variable */
17652 )
17653{
17654 assert(var != NULL);
17655
17656 return var->removable;
17657}
17658
17659/** returns whether the variable was deleted from the problem */
17661 SCIP_VAR* var /**< problem variable */
17662 )
17663{
17664 assert(var != NULL);
17665
17666 return var->deleted;
17667}
17668
17669/** marks the variable to be deletable, i.e., it may be deleted completely from the problem;
17670 * method can only be called before the variable is added to the problem by SCIPaddVar() or SCIPaddPricedVar()
17671 */
17673 SCIP_VAR* var /**< problem variable */
17674 )
17675{
17676 assert(var != NULL);
17677 assert(var->probindex == -1);
17678
17679 var->deletable = TRUE;
17680}
17681
17682/** marks the variable to be not deletable from the problem */
17684 SCIP_VAR* var
17685 )
17686{
17687 assert(var != NULL);
17688
17689 var->deletable = FALSE;
17690}
17691
17692/** marks variable to be deleted from global structures (cliques etc.) when cleaning up
17693 *
17694 * @note: this is not equivalent to marking the variable itself for deletion, this is done by using SCIPvarMarkDeletable()
17695 */
17697 SCIP_VAR* var /**< problem variable */
17698 )
17699{
17700 assert(var != NULL);
17701
17702 var->delglobalstructs = TRUE;
17703}
17704
17705/** returns whether the variable was flagged for deletion from global structures (cliques etc.) */
17707 SCIP_VAR* var /**< problem variable */
17708 )
17709{
17710 assert(var != NULL);
17711
17712 return var->delglobalstructs;
17713}
17714
17715/** returns whether a variable has been introduced to define a relaxation
17716 *
17717 * These variables are only valid for the current SCIP solve round,
17718 * they are not contained in any (checked) constraints, but may be used
17719 * in cutting planes, for example.
17720 * Relaxation-only variables are not copied by SCIPcopyVars and cuts
17721 * that contain these variables are not added as linear constraints when
17722 * restarting or transferring information from a copied SCIP to a SCIP.
17723 * Also conflicts with relaxation-only variables are not generated at
17724 * the moment.
17725 */
17727 SCIP_VAR* var /**< problem variable */
17728 )
17729{
17730 assert(var != NULL);
17731
17732 return var->relaxationonly;
17733}
17734
17735/** marks that this variable has only been introduced to define a relaxation
17736 *
17737 * The variable must not have a coefficient in the objective and must be deletable.
17738 * If it is not marked deletable, it will be marked as deletable, which is only possible
17739 * before the variable is added to a problem.
17740 *
17741 * @see SCIPvarIsRelaxationOnly
17742 * @see SCIPvarMarkDeletable
17743 */
17745 SCIP_VAR* var /**< problem variable */
17746 )
17747{
17748 assert(var != NULL);
17749 assert(SCIPvarGetObj(var) == 0.0);
17750
17751 if( !SCIPvarIsDeletable(var) )
17753
17754 var->relaxationonly = TRUE;
17755}
17756
17757/** returns whether variable is allowed to be deleted completely from the problem */
17759 SCIP_VAR* var
17760 )
17761{
17762 assert(var != NULL);
17763
17764 return var->deletable;
17765}
17766
17767/** returns whether variable is an active (neither fixed nor aggregated) variable */
17769 SCIP_VAR* var /**< problem variable */
17770 )
17771{
17772 assert(var != NULL);
17773
17774 return (var->probindex >= 0);
17775}
17776
17777/** gets unique index of variable */
17779 SCIP_VAR* var /**< problem variable */
17780 )
17781{
17782 assert(var != NULL);
17783
17784 return var->index;
17785}
17786
17787/** gets position of variable in problem, or -1 if variable is not active */
17789 SCIP_VAR* var /**< problem variable */
17790 )
17791{
17792 assert(var != NULL);
17793
17794 return var->probindex;
17795}
17796
17797/** gets transformed variable of ORIGINAL variable */
17799 SCIP_VAR* var /**< problem variable */
17800 )
17801{
17802 assert(var != NULL);
17804
17805 return var->data.original.transvar;
17806}
17807
17808/** gets column of COLUMN variable */
17810 SCIP_VAR* var /**< problem variable */
17811 )
17812{
17813 assert(var != NULL);
17815
17816 return var->data.col;
17817}
17818
17819/** returns whether the variable is a COLUMN variable that is member of the current LP */
17821 SCIP_VAR* var /**< problem variable */
17822 )
17823{
17824 assert(var != NULL);
17825
17827}
17828
17829/** gets aggregation variable y of an aggregated variable x = a*y + c */
17831 SCIP_VAR* var /**< problem variable */
17832 )
17833{
17834 assert(var != NULL);
17836 assert(!var->donotaggr);
17837
17838 return var->data.aggregate.var;
17839}
17840
17841/** gets aggregation scalar a of an aggregated variable x = a*y + c */
17843 SCIP_VAR* var /**< problem variable */
17844 )
17845{
17846 assert(var != NULL);
17848 assert(!var->donotaggr);
17849
17850 return var->data.aggregate.scalar;
17851}
17852
17853/** gets aggregation constant c of an aggregated variable x = a*y + c */
17855 SCIP_VAR* var /**< problem variable */
17856 )
17857{
17858 assert(var != NULL);
17860 assert(!var->donotaggr);
17861
17862 return var->data.aggregate.constant;
17863}
17864
17865/** gets number n of aggregation variables of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
17867 SCIP_VAR* var /**< problem variable */
17868 )
17869{
17870 assert(var != NULL);
17872 assert(!var->donotmultaggr);
17873
17874 return var->data.multaggr.nvars;
17875}
17876
17877/** gets vector of aggregation variables y of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
17879 SCIP_VAR* var /**< problem variable */
17880 )
17881{
17882 assert(var != NULL);
17884 assert(!var->donotmultaggr);
17885
17886 return var->data.multaggr.vars;
17887}
17888
17889/** gets vector of aggregation scalars a of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
17891 SCIP_VAR* var /**< problem variable */
17892 )
17893{
17894 assert(var != NULL);
17896 assert(!var->donotmultaggr);
17897
17898 return var->data.multaggr.scalars;
17899}
17900
17901/** gets aggregation constant c of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
17903 SCIP_VAR* var /**< problem variable */
17904 )
17905{
17906 assert(var != NULL);
17908 assert(!var->donotmultaggr);
17909
17910 return var->data.multaggr.constant;
17911}
17912
17913/** gets the negation of the given variable; may return NULL, if no negation is existing yet */
17915 SCIP_VAR* var /**< negated problem variable */
17916 )
17917{
17918 assert(var != NULL);
17919
17920 return var->negatedvar;
17921}
17922
17923/** gets the negation variable x of a negated variable x' = offset - x */
17925 SCIP_VAR* var /**< negated problem variable */
17926 )
17927{
17928 assert(var != NULL);
17930
17931 return var->negatedvar;
17932}
17933
17934/** gets the negation offset of a negated variable x' = offset - x */
17936 SCIP_VAR* var /**< negated problem variable */
17937 )
17938{
17939 assert(var != NULL);
17941
17942 return var->data.negate.constant;
17943}
17944
17945/** gets objective function value of variable */
17947 SCIP_VAR* var /**< problem variable */
17948 )
17949{
17950 assert(var != NULL);
17951
17952 return var->obj;
17953}
17954
17955/** gets the unchanged objective function value of a variable (ignoring temproray changes performed in probing mode) */
17957 SCIP_VAR* var /**< problem variable */
17958 )
17959{
17960 assert(var != NULL);
17961
17962 return var->unchangedobj;
17963}
17964
17965/** gets corresponding objective value of active, fixed, or multi-aggregated problem variable of given variable
17966 * e.g. obj(x) = 1 this method returns for ~x the value -1
17967 */
17969 SCIP_VAR* var, /**< problem variable */
17970 SCIP_Real* aggrobj /**< pointer to store the aggregated objective value */
17971 )
17972{
17973 SCIP_VAR* probvar = var;
17974 SCIP_Real mult = 1.0;
17975
17976 assert(probvar != NULL);
17977 assert(aggrobj != NULL);
17978
17979 while( probvar != NULL )
17980 {
17981 switch( SCIPvarGetStatus(probvar) )
17982 {
17986 (*aggrobj) = mult * SCIPvarGetObj(probvar);
17987 return SCIP_OKAY;
17988
17990 assert(SCIPvarGetObj(probvar) == 0.0);
17991 (*aggrobj) = 0.0;
17992 return SCIP_OKAY;
17993
17995 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
17996 if ( probvar->data.multaggr.nvars == 1 )
17997 {
17998 assert( probvar->data.multaggr.vars != NULL );
17999 assert( probvar->data.multaggr.scalars != NULL );
18000 assert( probvar->data.multaggr.vars[0] != NULL );
18001 mult *= probvar->data.multaggr.scalars[0];
18002 probvar = probvar->data.multaggr.vars[0];
18003 break;
18004 }
18005 else
18006 {
18007 SCIP_Real tmpobj;
18008 int v;
18009
18010 (*aggrobj) = 0.0;
18011
18012 for( v = probvar->data.multaggr.nvars - 1; v >= 0; --v )
18013 {
18014 SCIP_CALL( SCIPvarGetAggregatedObj(probvar->data.multaggr.vars[v], &tmpobj) );
18015 (*aggrobj) += probvar->data.multaggr.scalars[v] * tmpobj;
18016 }
18017 return SCIP_OKAY;
18018 }
18019
18020 case SCIP_VARSTATUS_AGGREGATED: /* x = a'*x' + c' => a*x + c == (a*a')*x' + (a*c' + c) */
18021 assert(probvar->data.aggregate.var != NULL);
18022 mult *= probvar->data.aggregate.scalar;
18023 probvar = probvar->data.aggregate.var;
18024 break;
18025
18026 case SCIP_VARSTATUS_NEGATED: /* x = - x' + c' => a*x + c == (-a)*x' + (a*c' + c) */
18027 assert(probvar->negatedvar != NULL);
18029 assert(probvar->negatedvar->negatedvar == probvar);
18030 mult *= -1.0;
18031 probvar = probvar->negatedvar;
18032 break;
18033
18034 default:
18035 SCIPABORT();
18036 return SCIP_INVALIDDATA; /*lint !e527*/
18037 }
18038 }
18039
18040 return SCIP_INVALIDDATA;
18041}
18042
18043/** gets original lower bound of original problem variable (i.e. the bound set in problem creation) */
18045 SCIP_VAR* var /**< original problem variable */
18046 )
18047{
18048 assert(var != NULL);
18049 assert(SCIPvarIsOriginal(var));
18050
18052 return var->data.original.origdom.lb;
18053 else
18054 {
18056 assert(var->negatedvar != NULL);
18058
18059 return var->data.negate.constant - var->negatedvar->data.original.origdom.ub;
18060 }
18061}
18062
18063/** gets original upper bound of original problem variable (i.e. the bound set in problem creation) */
18065 SCIP_VAR* var /**< original problem variable */
18066 )
18067{
18068 assert(var != NULL);
18069 assert(SCIPvarIsOriginal(var));
18070
18072 return var->data.original.origdom.ub;
18073 else
18074 {
18076 assert(var->negatedvar != NULL);
18078
18079 return var->data.negate.constant - var->negatedvar->data.original.origdom.lb;
18080 }
18081}
18082
18083/** gets the original hole list of an original variable */
18085 SCIP_VAR* var /**< problem variable */
18086 )
18087{
18088 assert(var != NULL);
18089 assert(SCIPvarIsOriginal(var));
18090
18092 return var->data.original.origdom.holelist;
18093
18094 return NULL;
18095}
18096
18097/** gets global lower bound of variable */
18099 SCIP_VAR* var /**< problem variable */
18100 )
18101{
18102 assert(var != NULL);
18103
18104 return var->glbdom.lb;
18105}
18106
18107/** gets global upper bound of variable */
18109 SCIP_VAR* var /**< problem variable */
18110 )
18111{
18112 assert(var != NULL);
18113
18114 return var->glbdom.ub;
18115}
18116
18117/** gets the global hole list of an active variable */
18119 SCIP_VAR* var /**< problem variable */
18120 )
18121{
18122 assert(var != NULL);
18123
18124 return var->glbdom.holelist;
18125}
18126
18127/** gets best global bound of variable with respect to the objective function */
18129 SCIP_VAR* var /**< problem variable */
18130 )
18131{
18132 assert(var != NULL);
18133
18134 if( var->obj >= 0.0 )
18135 return var->glbdom.lb;
18136 else
18137 return var->glbdom.ub;
18138}
18139
18140/** gets worst global bound of variable with respect to the objective function */
18142 SCIP_VAR* var /**< problem variable */
18143 )
18144{
18145 assert(var != NULL);
18146
18147 if( var->obj >= 0.0 )
18148 return var->glbdom.ub;
18149 else
18150 return var->glbdom.lb;
18151}
18152
18153/** gets current lower bound of variable */
18155 SCIP_VAR* var /**< problem variable */
18156 )
18157{
18158 assert(var != NULL);
18159
18160 return var->locdom.lb;
18161}
18162
18163/** gets current upper bound of variable */
18165 SCIP_VAR* var /**< problem variable */
18166 )
18167{
18168 assert(var != NULL);
18169
18170 return var->locdom.ub;
18171}
18172
18173/** gets the current hole list of an active variable */
18175 SCIP_VAR* var /**< problem variable */
18176 )
18177{
18178 assert(var != NULL);
18179
18180 return var->locdom.holelist;
18181}
18182
18183/** gets best local bound of variable with respect to the objective function */
18185 SCIP_VAR* var /**< problem variable */
18186 )
18187{
18188 assert(var != NULL);
18189
18190 if( var->obj >= 0.0 )
18191 return var->locdom.lb;
18192 else
18193 return var->locdom.ub;
18194}
18195
18196/** gets worst local bound of variable with respect to the objective function */
18198 SCIP_VAR* var /**< problem variable */
18199 )
18200{
18201 assert(var != NULL);
18202
18203 if( var->obj >= 0.0 )
18204 return var->locdom.ub;
18205 else
18206 return var->locdom.lb;
18207}
18208
18209/** gets type (lower or upper) of best bound of variable with respect to the objective function */
18211 SCIP_VAR* var /**< problem variable */
18212 )
18213{
18214 assert(var != NULL);
18215
18216 if( var->obj >= 0.0 )
18217 return SCIP_BOUNDTYPE_LOWER;
18218 else
18219 return SCIP_BOUNDTYPE_UPPER;
18220}
18221
18222/** gets type (lower or upper) of worst bound of variable with respect to the objective function */
18224 SCIP_VAR* var /**< problem variable */
18225 )
18226{
18227 assert(var != NULL);
18228
18229 if( var->obj >= 0.0 )
18230 return SCIP_BOUNDTYPE_UPPER;
18231 else
18232 return SCIP_BOUNDTYPE_LOWER;
18233}
18234
18235/** gets lazy lower bound of variable, returns -infinity if the variable has no lazy lower bound */
18237 SCIP_VAR* var /**< problem variable */
18238 )
18239{
18240 assert(var != NULL);
18241
18242 return var->lazylb;
18243}
18244
18245/** gets lazy upper bound of variable, returns infinity if the variable has no lazy upper bound */
18247 SCIP_VAR* var /**< problem variable */
18248 )
18249{
18250 assert(var != NULL);
18251
18252 return var->lazyub;
18253}
18254
18255/** gets the branch factor of the variable; this value can be used in the branching methods to scale the score
18256 * values of the variables; higher factor leads to a higher probability that this variable is chosen for branching
18257 */
18259 SCIP_VAR* var /**< problem variable */
18260 )
18261{
18262 assert(var != NULL);
18263
18264 return var->branchfactor;
18265}
18266
18267/** gets the branch priority of the variable; variables with higher priority should always be preferred to variables
18268 * with lower priority
18269 */
18271 SCIP_VAR* var /**< problem variable */
18272 )
18273{
18274 assert(var != NULL);
18275
18276 return var->branchpriority;
18277}
18278
18279/** gets the preferred branch direction of the variable (downwards, upwards, or auto) */
18281 SCIP_VAR* var /**< problem variable */
18282 )
18283{
18284 assert(var != NULL);
18285
18286 return (SCIP_BRANCHDIR)var->branchdirection;
18287}
18288
18289/** gets number of variable lower bounds x >= b_i*z_i + d_i of given variable x */
18291 SCIP_VAR* var /**< problem variable */
18292 )
18293{
18294 assert(var != NULL);
18295
18296 return SCIPvboundsGetNVbds(var->vlbs);
18297}
18298
18299/** gets array with bounding variables z_i in variable lower bounds x >= b_i*z_i + d_i of given variable x;
18300 * the variable bounds are sorted by increasing variable index of the bounding variable z_i (see SCIPvarGetIndex())
18301 */
18303 SCIP_VAR* var /**< problem variable */
18304 )
18305{
18306 assert(var != NULL);
18307
18308 return SCIPvboundsGetVars(var->vlbs);
18309}
18310
18311/** gets array with bounding coefficients b_i in variable lower bounds x >= b_i*z_i + d_i of given variable x */
18313 SCIP_VAR* var /**< problem variable */
18314 )
18315{
18316 assert(var != NULL);
18317
18318 return SCIPvboundsGetCoefs(var->vlbs);
18319}
18320
18321/** gets array with bounding constants d_i in variable lower bounds x >= b_i*z_i + d_i of given variable x */
18323 SCIP_VAR* var /**< problem variable */
18324 )
18325{
18326 assert(var != NULL);
18327
18328 return SCIPvboundsGetConstants(var->vlbs);
18329}
18330
18331/** gets number of variable upper bounds x <= b_i*z_i + d_i of given variable x */
18333 SCIP_VAR* var /**< problem variable */
18334 )
18335{
18336 assert(var != NULL);
18337
18338 return SCIPvboundsGetNVbds(var->vubs);
18339}
18340
18341/** gets array with bounding variables z_i in variable upper bounds x <= b_i*z_i + d_i of given variable x;
18342 * the variable bounds are sorted by increasing variable index of the bounding variable z_i (see SCIPvarGetIndex())
18343 */
18345 SCIP_VAR* var /**< problem variable */
18346 )
18347{
18348 assert(var != NULL);
18349
18350 return SCIPvboundsGetVars(var->vubs);
18351}
18352
18353/** gets array with bounding coefficients b_i in variable upper bounds x <= b_i*z_i + d_i of given variable x */
18355 SCIP_VAR* var /**< problem variable */
18356 )
18357{
18358 assert(var != NULL);
18359
18360 return SCIPvboundsGetCoefs(var->vubs);
18361}
18362
18363/** gets array with bounding constants d_i in variable upper bounds x <= b_i*z_i + d_i of given variable x */
18365 SCIP_VAR* var /**< problem variable */
18366 )
18367{
18368 assert(var != NULL);
18369
18370 return SCIPvboundsGetConstants(var->vubs);
18371}
18372
18373/** gets number of implications y <= b or y >= b for x == 0 or x == 1 of given active problem variable x,
18374 * there are no implications for nonbinary variable x
18375 */
18377 SCIP_VAR* var, /**< active problem variable */
18378 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
18379 )
18380{
18381 assert(var != NULL);
18382 assert(SCIPvarIsActive(var));
18383
18384 return SCIPimplicsGetNImpls(var->implics, varfixing);
18385}
18386
18387/** gets array with implication variables y of implications y <= b or y >= b for x == 0 or x == 1 of given active
18388 * problem variable x, there are no implications for nonbinary variable x;
18389 * the implications are sorted such that implications with binary implied variables precede the ones with non-binary
18390 * implied variables, and as a second criteria, the implied variables are sorted by increasing variable index
18391 * (see SCIPvarGetIndex())
18392 */
18394 SCIP_VAR* var, /**< active problem variable */
18395 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
18396 )
18397{
18398 assert(var != NULL);
18399 assert(SCIPvarIsActive(var));
18400
18401 return SCIPimplicsGetVars(var->implics, varfixing);
18402}
18403
18404/** gets array with implication types of implications y <= b or y >= b for x == 0 or x == 1 of given active problem
18405 * variable x (SCIP_BOUNDTYPE_UPPER if y <= b, SCIP_BOUNDTYPE_LOWER if y >= b),
18406 * there are no implications for nonbinary variable x
18407 */
18409 SCIP_VAR* var, /**< active problem variable */
18410 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
18411 )
18412{
18413 assert(var != NULL);
18414 assert(SCIPvarIsActive(var));
18415
18416 return SCIPimplicsGetTypes(var->implics, varfixing);
18417}
18418
18419/** gets array with implication bounds b of implications y <= b or y >= b for x == 0 or x == 1 of given active problem
18420 * variable x, there are no implications for nonbinary variable x
18421 */
18423 SCIP_VAR* var, /**< active problem variable */
18424 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
18425 )
18426{
18427 assert(var != NULL);
18428 assert(SCIPvarIsActive(var));
18429
18430 return SCIPimplicsGetBounds(var->implics, varfixing);
18431}
18432
18433/** Gets array with unique ids of implications y <= b or y >= b for x == 0 or x == 1 of given active problem variable x,
18434 * there are no implications for nonbinary variable x.
18435 * If an implication is a shortcut, i.e., it was added as part of the transitive closure of another implication,
18436 * its id is negative, otherwise it is nonnegative.
18437 */
18439 SCIP_VAR* var, /**< active problem variable */
18440 SCIP_Bool varfixing /**< FALSE for implications for x == 0, TRUE for x == 1 */
18441 )
18442{
18443 assert(var != NULL);
18444 assert(SCIPvarIsActive(var));
18445
18446 return SCIPimplicsGetIds(var->implics, varfixing);
18447}
18448
18449/** gets number of cliques, the active variable is contained in */
18451 SCIP_VAR* var, /**< active problem variable */
18452 SCIP_Bool varfixing /**< FALSE for cliques containing x == 0, TRUE for x == 1 */
18453 )
18454{
18455 assert(var != NULL);
18456
18457 return SCIPcliquelistGetNCliques(var->cliquelist, varfixing);
18458}
18459
18460/** gets array of cliques, the active variable is contained in */
18462 SCIP_VAR* var, /**< active problem variable */
18463 SCIP_Bool varfixing /**< FALSE for cliques containing x == 0, TRUE for x == 1 */
18464 )
18465{
18466 assert(var != NULL);
18467
18468 return SCIPcliquelistGetCliques(var->cliquelist, varfixing);
18469}
18470
18471/** gets primal LP solution value of variable */
18473 SCIP_VAR* var /**< problem variable */
18474 )
18475{
18476 assert(var != NULL);
18477
18479 return SCIPcolGetPrimsol(var->data.col);
18480 else
18481 return SCIPvarGetLPSol_rec(var);
18482}
18483
18484/** gets primal NLP solution value of variable */
18486 SCIP_VAR* var /**< problem variable */
18487 )
18488{
18489 assert(var != NULL);
18490
18492 return var->nlpsol;
18493 else
18494 return SCIPvarGetNLPSol_rec(var);
18495}
18496
18497/** return lower bound change info at requested position */
18499 SCIP_VAR* var, /**< problem variable */
18500 int pos /**< requested position */
18501 )
18502{
18503 assert(pos >= 0);
18504 assert(pos < var->nlbchginfos);
18505
18506 return &var->lbchginfos[pos];
18507}
18508
18509/** gets the number of lower bound change info array */
18511 SCIP_VAR* var /**< problem variable */
18512 )
18513{
18514 return var->nlbchginfos;
18515}
18516
18517/** return upper bound change info at requested position */
18519 SCIP_VAR* var, /**< problem variable */
18520 int pos /**< requested position */
18521 )
18522{
18523 assert(pos >= 0);
18524 assert(pos < var->nubchginfos);
18525
18526 return &var->ubchginfos[pos];
18527}
18528
18529/** gets the number upper bound change info array */
18531 SCIP_VAR* var /**< problem variable */
18532 )
18533{
18534 assert(var != NULL);
18535
18536 return var->nubchginfos;
18537}
18538
18539/** returns the value based history for the variable */
18541 SCIP_VAR* var /**< problem variable */
18542 )
18543{
18544 assert(var != NULL);
18545
18546 return var->valuehistory;
18547}
18548
18549/** gets pseudo solution value of variable */
18551 SCIP_VAR* var /**< problem variable */
18552 )
18553{
18554 assert(var != NULL);
18555
18557 return SCIPvarGetBestBoundLocal(var);
18558 else
18559 return SCIPvarGetPseudoSol_rec(var);
18560}
18561
18562/** returns the variable's VSIDS score */
18564 SCIP_VAR* var, /**< problem variable */
18565 SCIP_STAT* stat, /**< problem statistics */
18566 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
18567 )
18568{
18569 assert(var != NULL);
18570
18572 return SCIPhistoryGetVSIDS(var->history, dir)/stat->vsidsweight;
18573 else
18574 return SCIPvarGetVSIDS_rec(var, stat, dir);
18575}
18576
18577/** includes event handler with given data in variable's event filter */
18579 SCIP_VAR* var, /**< problem variable */
18580 BMS_BLKMEM* blkmem, /**< block memory */
18581 SCIP_SET* set, /**< global SCIP settings */
18582 SCIP_EVENTTYPE eventtype, /**< event type to catch */
18583 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
18584 SCIP_EVENTDATA* eventdata, /**< event data to pass to the event handler for the event processing */
18585 int* filterpos /**< pointer to store position of event filter entry, or NULL */
18586 )
18587{
18588 assert(var != NULL);
18589 assert(set != NULL);
18590 assert(var->scip == set->scip);
18591 assert(var->eventfilter != NULL);
18592 assert((eventtype & ~SCIP_EVENTTYPE_VARCHANGED) == 0);
18593 assert((eventtype & SCIP_EVENTTYPE_VARCHANGED) != 0);
18594 assert(SCIPvarIsTransformed(var));
18595
18596 SCIPsetDebugMsg(set, "catch event of type 0x%" SCIP_EVENTTYPE_FORMAT " of variable <%s> with handler %p and data %p\n",
18597 eventtype, var->name, (void*)eventhdlr, (void*)eventdata);
18598
18599 SCIP_CALL( SCIPeventfilterAdd(var->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) );
18600
18601 return SCIP_OKAY;
18602}
18603
18604/** deletes event handler with given data from variable's event filter */
18606 SCIP_VAR* var, /**< problem variable */
18607 BMS_BLKMEM* blkmem, /**< block memory */
18608 SCIP_SET* set, /**< global SCIP settings */
18609 SCIP_EVENTTYPE eventtype, /**< event type mask of dropped event */
18610 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
18611 SCIP_EVENTDATA* eventdata, /**< event data to pass to the event handler for the event processing */
18612 int filterpos /**< position of event filter entry returned by SCIPvarCatchEvent(), or -1 */
18613 )
18614{
18615 assert(var != NULL);
18616 assert(set != NULL);
18617 assert(var->scip == set->scip);
18618 assert(var->eventfilter != NULL);
18619 assert(SCIPvarIsTransformed(var));
18620
18621 SCIPsetDebugMsg(set, "drop event of variable <%s> with handler %p and data %p\n", var->name, (void*)eventhdlr,
18622 (void*)eventdata);
18623
18624 SCIP_CALL( SCIPeventfilterDel(var->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) );
18625
18626 return SCIP_OKAY;
18627}
18628
18629/** returns the position of the bound change index */
18631 SCIP_BDCHGIDX* bdchgidx /**< bound change index */
18632 )
18633{
18634 assert(bdchgidx != NULL);
18635
18636 return bdchgidx->pos;
18637}
18638
18639/** returns whether first bound change index belongs to an earlier applied bound change than second one */
18641 SCIP_BDCHGIDX* bdchgidx1, /**< first bound change index */
18642 SCIP_BDCHGIDX* bdchgidx2 /**< second bound change index */
18643 )
18644{
18645 assert(bdchgidx1 != NULL);
18646 assert(bdchgidx1->depth >= -2);
18647 assert(bdchgidx1->pos >= 0);
18648 assert(bdchgidx2 != NULL);
18649 assert(bdchgidx2->depth >= -2);
18650 assert(bdchgidx2->pos >= 0);
18651
18652 return (bdchgidx1->depth < bdchgidx2->depth)
18653 || (bdchgidx1->depth == bdchgidx2->depth && (bdchgidx1->pos < bdchgidx2->pos));
18654}
18655
18656/** returns whether first bound change index belongs to an earlier applied bound change than second one;
18657 * if a bound change index is NULL, the bound change index represents the current time, i.e. the time after the
18658 * last bound change was applied to the current node
18659 */
18661 SCIP_BDCHGIDX* bdchgidx1, /**< first bound change index, or NULL */
18662 SCIP_BDCHGIDX* bdchgidx2 /**< second bound change index, or NULL */
18663 )
18664{
18665 assert(bdchgidx1 == NULL || bdchgidx1->depth >= -2);
18666 assert(bdchgidx1 == NULL || bdchgidx1->pos >= 0);
18667 assert(bdchgidx2 == NULL || bdchgidx2->depth >= -2);
18668 assert(bdchgidx2 == NULL || bdchgidx2->pos >= 0);
18669
18670 if( bdchgidx1 == NULL )
18671 return FALSE;
18672 else if( bdchgidx2 == NULL )
18673 return TRUE;
18674 else
18675 return (bdchgidx1->depth < bdchgidx2->depth)
18676 || (bdchgidx1->depth == bdchgidx2->depth && (bdchgidx1->pos < bdchgidx2->pos));
18677}
18678
18679/** returns old bound that was overwritten for given bound change information */
18681 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18682 )
18683{
18684 assert(bdchginfo != NULL);
18685
18686 return bdchginfo->oldbound;
18687}
18688
18689/** returns new bound installed for given bound change information */
18691 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18692 )
18693{
18694 assert(bdchginfo != NULL);
18695
18696 return bdchginfo->newbound;
18697}
18698
18699/** returns variable that belongs to the given bound change information */
18701 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18702 )
18703{
18704 assert(bdchginfo != NULL);
18705
18706 return bdchginfo->var;
18707}
18708
18709/** returns whether the bound change information belongs to a branching decision or a deduction */
18711 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18712 )
18713{
18714 assert(bdchginfo != NULL);
18715
18716 return (SCIP_BOUNDCHGTYPE)(bdchginfo->boundchgtype);
18717}
18718
18719/** returns whether the bound change information belongs to a lower or upper bound change */
18721 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18722 )
18723{
18724 assert(bdchginfo != NULL);
18725
18726 return (SCIP_BOUNDTYPE)(bdchginfo->boundtype);
18727}
18728
18729/** returns depth level of given bound change information */
18731 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18732 )
18733{
18734 assert(bdchginfo != NULL);
18735
18736 return bdchginfo->bdchgidx.depth;
18737}
18738
18739/** returns bound change position in its depth level of given bound change information */
18741 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18742 )
18743{
18744 assert(bdchginfo != NULL);
18745
18746 return bdchginfo->bdchgidx.pos;
18747}
18748
18749/** returns bound change index of given bound change information */
18751 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18752 )
18753{
18754 assert(bdchginfo != NULL);
18755
18756 return &bdchginfo->bdchgidx;
18757}
18758
18759/** returns inference variable of given bound change information */
18761 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18762 )
18763{
18764 assert(bdchginfo != NULL);
18767
18768 return bdchginfo->inferencedata.var;
18769}
18770
18771/** returns inference constraint of given bound change information */
18773 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18774 )
18775{
18776 assert(bdchginfo != NULL);
18778 assert(bdchginfo->inferencedata.reason.cons != NULL);
18779
18780 return bdchginfo->inferencedata.reason.cons;
18781}
18782
18783/** returns inference propagator of given bound change information, or NULL if no propagator was responsible */
18785 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18786 )
18787{
18788 assert(bdchginfo != NULL);
18790
18791 return bdchginfo->inferencedata.reason.prop;
18792}
18793
18794/** returns inference user information of given bound change information */
18796 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18797 )
18798{
18799 assert(bdchginfo != NULL);
18802
18803 return bdchginfo->inferencedata.info;
18804}
18805
18806/** returns inference bound of inference variable of given bound change information */
18808 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18809 )
18810{
18811 assert(bdchginfo != NULL);
18814
18815 return (SCIP_BOUNDTYPE)(bdchginfo->inferboundtype);
18816}
18817
18818/** returns the relaxed bound change type */
18820 SCIP_BDCHGINFO* bdchginfo /**< bound change to add to the conflict set */
18821 )
18822{
18823 return ((SCIP_BOUNDTYPE)(bdchginfo->boundtype) == SCIP_BOUNDTYPE_LOWER ? bdchginfo->var->conflictrelaxedlb : bdchginfo->var->conflictrelaxedub);
18824}
18825
18826
18827/** returns whether the bound change information belongs to a redundant bound change */
18829 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18830 )
18831{
18832 assert(bdchginfo != NULL);
18833 assert(bdchginfo->redundant == (bdchginfo->oldbound == bdchginfo->newbound)); /*lint !e777*/
18834
18835 return bdchginfo->redundant;
18836}
18837
18838/** returns whether the bound change has an inference reason (constraint or propagator), that can be resolved */
18840 SCIP_BDCHGINFO* bdchginfo /**< bound change information */
18841 )
18842{
18843 assert(bdchginfo != NULL);
18844
18847 && bdchginfo->inferencedata.reason.prop != NULL);
18848}
18849
18850/** for two bound change informations belonging to the same variable and bound, returns whether the first bound change
18851 * has a tighter new bound as the second bound change
18852 */
18854 SCIP_BDCHGINFO* bdchginfo1, /**< first bound change information */
18855 SCIP_BDCHGINFO* bdchginfo2 /**< second bound change information */
18856 )
18857{
18858 assert(bdchginfo1 != NULL);
18859 assert(bdchginfo2 != NULL);
18860 assert(bdchginfo1->var == bdchginfo2->var);
18861 assert(bdchginfo1->boundtype == bdchginfo2->boundtype);
18862
18863 return (SCIPbdchginfoGetBoundtype(bdchginfo1) == SCIP_BOUNDTYPE_LOWER
18864 ? bdchginfo1->newbound > bdchginfo2->newbound
18865 : bdchginfo1->newbound < bdchginfo2->newbound);
18866}
static long bound
static GRAPHNODE ** active
SCIP_VAR * a
Definition: circlepacking.c:66
SCIP_VAR ** b
Definition: circlepacking.c:65
void SCIPconsCapture(SCIP_CONS *cons)
Definition: cons.c:6254
SCIP_RETCODE SCIPconsRelease(SCIP_CONS **cons, BMS_BLKMEM *blkmem, SCIP_SET *set)
Definition: cons.c:6266
internal methods for constraints and constraint handlers
#define SCIPdebugCheckLbGlobal(scip, var, lb)
Definition: debug.h:285
#define SCIPdebugCheckImplic(set, var, varfixing, implvar, impltype, implbound)
Definition: debug.h:292
#define SCIPdebugCheckUbGlobal(scip, var, ub)
Definition: debug.h:286
#define SCIPdebugCheckVbound(set, var, vbtype, vbvar, vbcoef, vbconstant)
Definition: debug.h:291
#define SCIPdebugCheckAggregation(set, var, aggrvars, scalars, constant, naggrvars)
Definition: debug.h:293
#define SCIP_DEFAULT_INFINITY
Definition: def.h:177
#define NULL
Definition: def.h:266
#define SCIP_MAXSTRLEN
Definition: def.h:287
#define SCIP_Longint
Definition: def.h:157
#define EPSISINT(x, eps)
Definition: def.h:209
#define SCIP_REAL_MAX
Definition: def.h:173
#define SCIP_INVALID
Definition: def.h:192
#define SCIP_Bool
Definition: def.h:91
#define EPSLE(x, y, eps)
Definition: def.h:199
#define MIN(x, y)
Definition: def.h:242
#define SCIP_ALLOC(x)
Definition: def.h:384
#define SCIP_Real
Definition: def.h:172
#define SCIP_UNKNOWN
Definition: def.h:193
#define ABS(x)
Definition: def.h:234
#define SQR(x)
Definition: def.h:213
#define EPSEQ(x, y, eps)
Definition: def.h:197
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:238
#define SCIP_CALL_ABORT(x)
Definition: def.h:352
#define SCIPABORT()
Definition: def.h:345
#define SCIP_REAL_MIN
Definition: def.h:174
#define REALABS(x)
Definition: def.h:196
#define EPSZ(x, eps)
Definition: def.h:202
#define SCIP_CALL(x)
Definition: def.h:373
SCIP_RETCODE SCIPeventCreateLbChanged(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var, SCIP_Real oldbound, SCIP_Real newbound)
Definition: event.c:674
SCIP_RETCODE SCIPeventCreateVarFixed(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var)
Definition: event.c:562
SCIP_RETCODE SCIPeventCreateUbChanged(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var, SCIP_Real oldbound, SCIP_Real newbound)
Definition: event.c:700
SCIP_RETCODE SCIPeventCreateVarUnlocked(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var)
Definition: event.c:584
SCIP_RETCODE SCIPeventCreateObjChanged(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var, SCIP_Real oldobj, SCIP_Real newobj)
Definition: event.c:605
SCIP_RETCODE SCIPeventqueueAdd(SCIP_EVENTQUEUE *eventqueue, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_PRIMAL *primal, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENT **event)
Definition: event.c:2240
SCIP_RETCODE SCIPeventfilterFree(SCIP_EVENTFILTER **eventfilter, BMS_BLKMEM *blkmem, SCIP_SET *set)
Definition: event.c:1846
SCIP_Bool SCIPeventqueueIsDelayed(SCIP_EVENTQUEUE *eventqueue)
Definition: event.c:2568
SCIP_RETCODE SCIPeventCreateGholeAdded(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var, SCIP_Real left, SCIP_Real right)
Definition: event.c:726
SCIP_RETCODE SCIPeventfilterDel(SCIP_EVENTFILTER *eventfilter, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: event.c:1979
SCIP_RETCODE SCIPeventfilterCreate(SCIP_EVENTFILTER **eventfilter, BMS_BLKMEM *blkmem)
Definition: event.c:1821
SCIP_RETCODE SCIPeventProcess(SCIP_EVENT *event, SCIP_SET *set, SCIP_PRIMAL *primal, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter)
Definition: event.c:1574
SCIP_RETCODE SCIPeventCreateImplAdded(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var)
Definition: event.c:814
SCIP_RETCODE SCIPeventChgType(SCIP_EVENT *event, SCIP_EVENTTYPE eventtype)
Definition: event.c:1040
SCIP_RETCODE SCIPeventfilterAdd(SCIP_EVENTFILTER *eventfilter, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: event.c:1886
SCIP_RETCODE SCIPeventCreateGubChanged(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var, SCIP_Real oldbound, SCIP_Real newbound)
Definition: event.c:651
SCIP_RETCODE SCIPeventCreateGlbChanged(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var, SCIP_Real oldbound, SCIP_Real newbound)
Definition: event.c:628
SCIP_RETCODE SCIPeventCreateTypeChanged(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var, SCIP_VARTYPE oldtype, SCIP_VARTYPE newtype)
Definition: event.c:833
internal methods for managing events
const char * SCIPgetProbName(SCIP *scip)
Definition: scip_prob.c:1067
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:3159
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3426
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9124
SCIP_Longint SCIPcalcSmaComMul(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9376
SCIP_Bool SCIPrealToRational(SCIP_Real val, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Longint *nominator, SCIP_Longint *denominator)
Definition: misc.c:9397
SCIP_Real SCIPcolGetObj(SCIP_COL *col)
Definition: lp.c:16953
SCIP_Real SCIPcolGetLb(SCIP_COL *col)
Definition: lp.c:16963
SCIP_Real SCIPcolGetPrimsol(SCIP_COL *col)
Definition: lp.c:16996
SCIP_Real SCIPcolGetUb(SCIP_COL *col)
Definition: lp.c:16973
SCIP_Bool SCIPcolIsInLP(SCIP_COL *col)
Definition: lp.c:17115
SCIP_BASESTAT SCIPcolGetBasisStatus(SCIP_COL *col)
Definition: lp.c:17031
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8214
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7515
SCIP_NODE * SCIPnodeGetParent(SCIP_NODE *node)
Definition: tree.c:7810
const char * SCIPpropGetName(SCIP_PROP *prop)
Definition: prop.c:941
SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
SCIP_NODE * SCIPgetFocusNode(SCIP *scip)
Definition: scip_tree.c:72
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:17640
SCIP_Real SCIPvarGetLPSol_rec(SCIP_VAR *var)
Definition: var.c:13089
int SCIPvarCompareActiveAndNegated(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11924
void SCIPvarSetDelorigData(SCIP_VAR *var, SCIP_DECL_VARDELORIG((*vardelorig)))
Definition: var.c:17480
SCIP_RETCODE SCIPvarGetOrigvarSum(SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: var.c:12794
SCIP_HOLELIST * SCIPvarGetHolelistLocal(SCIP_VAR *var)
Definition: var.c:18174
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:18290
SCIP_RETCODE SCIPvarGetProbvarBound(SCIP_VAR **var, SCIP_Real *bound, SCIP_BOUNDTYPE *boundtype)
Definition: var.c:12489
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:17660
SCIP_Real SCIPvarGetNegationConstant(SCIP_VAR *var)
Definition: var.c:17935
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:17809
SCIP_Bool SCIPbdchginfoIsRedundant(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18828
SCIP_Bool SCIPvarWasFixedAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:16990
SCIP_Real SCIPvarGetAvgBranchdepthCurrentRun(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:15852
SCIP_Bool SCIPvarMayRoundUp(SCIP_VAR *var)
Definition: var.c:3451
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17902
SCIP_BOUNDTYPE SCIPvarGetBestBoundType(SCIP_VAR *var)
Definition: var.c:18210
void SCIPvarsGetProbvar(SCIP_VAR **vars, int nvars)
Definition: var.c:12218
SCIP_Real SCIPvarGetSol(SCIP_VAR *var, SCIP_Bool getlpval)
Definition: var.c:13277
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:17914
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:18312
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17768
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17619
SCIP_BOUNDTYPE SCIPboundchgGetBoundtype(SCIP_BOUNDCHG *boundchg)
Definition: var.c:17366
SCIP_Real SCIPholelistGetRight(SCIP_HOLELIST *holelist)
Definition: var.c:17416
void SCIPvarSetTransData(SCIP_VAR *var, SCIP_DECL_VARTRANS((*vartrans)))
Definition: var.c:17492
SCIP_Real SCIPvarGetAvgBranchdepth(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:15807
SCIP_Real SCIPvarGetBestBoundGlobal(SCIP_VAR *var)
Definition: var.c:18128
SCIP_Bool SCIPbdchgidxIsEarlier(SCIP_BDCHGIDX *bdchgidx1, SCIP_BDCHGIDX *bdchgidx2)
Definition: var.c:18660
SCIP_Bool SCIPvarWasFixedEarlier(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:17138
SCIP_BDCHGIDX * SCIPbdchginfoGetIdx(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18750
SCIP_VAR * SCIPboundchgGetVar(SCIP_BOUNDCHG *boundchg)
Definition: var.c:17346
SCIP_Bool SCIPvarHasImplic(SCIP_VAR *var, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype)
Definition: var.c:11131
SCIP_BOUNDCHG * SCIPdomchgGetBoundchg(SCIP_DOMCHG *domchg, int pos)
Definition: var.c:17394
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18376
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17558
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3353
SCIP_BOUNDCHGTYPE SCIPboundchgGetBoundchgtype(SCIP_BOUNDCHG *boundchg)
Definition: var.c:17356
SCIP_Real SCIPvarGetInferenceSum(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:15999
SCIP_Real SCIPvarGetAggrConstant(SCIP_VAR *var)
Definition: var.c:17854
SCIP_RETCODE SCIPvarGetAggregatedObj(SCIP_VAR *var, SCIP_Real *aggrobj)
Definition: var.c:17968
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18164
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3416
SCIP_Real SCIPvarGetBestRootSol(SCIP_VAR *var)
Definition: var.c:13735
void SCIPvarSetDeltransData(SCIP_VAR *var, SCIP_DECL_VARDELTRANS((*vardeltrans)))
Definition: var.c:17504
SCIP_HOLELIST * SCIPholelistGetNext(SCIP_HOLELIST *holelist)
Definition: var.c:17426
SCIP_Real SCIPvarGetLbOriginal(SCIP_VAR *var)
Definition: var.c:18044
SCIP_BDCHGINFO * SCIPvarGetLbchgInfo(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:16597
SCIP_DECL_HASHGETKEY(SCIPvarGetHashkey)
Definition: var.c:12005
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17581
void SCIPvarMarkDeletable(SCIP_VAR *var)
Definition: var.c:17672
void SCIPvarGetImplicVarBounds(SCIP_VAR *var, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_Real *lb, SCIP_Real *ub)
Definition: var.c:11166
SCIP_PROP * SCIPbdchginfoGetInferProp(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18784
SCIP_Real SCIPboundchgGetNewbound(SCIP_BOUNDCHG *boundchg)
Definition: var.c:17336
SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR *var)
Definition: var.c:3440
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17946
SCIP_Real SCIPvarGetAggrScalar(SCIP_VAR *var)
Definition: var.c:17842
SCIP_DECL_SORTPTRCOMP(SCIPvarCompActiveAndNegated)
Definition: var.c:11954
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:12238
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition: var.c:17744
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17604
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18108
SCIP_RETCODE SCIPvarSetInitial(SCIP_VAR *var, SCIP_Bool initial)
Definition: var.c:17526
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18393
void SCIPvarSetBestRootSol(SCIP_VAR *var, SCIP_Real rootsol, SCIP_Real rootredcost, SCIP_Real rootlpobjval)
Definition: var.c:13867
int SCIPbdchginfoGetDepth(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18730
int SCIPbdchginfoGetInferInfo(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18795
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17778
SCIP_CONS * SCIPbdchginfoGetInferCons(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18772
SCIP_Real SCIPvarGetNLPSol_rec(SCIP_VAR *var)
Definition: var.c:13162
SCIP_BDCHGIDX * SCIPvarGetLastBdchgIndex(SCIP_VAR *var)
Definition: var.c:17013
int SCIPbdchginfoGetPos(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18740
SCIP_Real SCIPvarGetWorstBoundLocal(SCIP_VAR *var)
Definition: var.c:18197
int SCIPvarGetNUses(SCIP_VAR *var)
Definition: var.c:17449
int SCIPdomchgGetNBoundchgs(SCIP_DOMCHG *domchg)
Definition: var.c:17386
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17788
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17439
SCIP_Real SCIPvarGetUbOriginal(SCIP_VAR *var)
Definition: var.c:18064
SCIP_Real SCIPvarGetWorstBoundGlobal(SCIP_VAR *var)
Definition: var.c:18141
SCIP_VAR * SCIPbdchginfoGetVar(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18700
SCIP_Bool SCIPvarHasBinaryImplic(SCIP_VAR *var, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_Bool implvarfixing)
Definition: var.c:11151
void SCIPvarMarkDeleteGlobalStructures(SCIP_VAR *var)
Definition: var.c:17696
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:18322
SCIP_Real SCIPvarGetRootSol(SCIP_VAR *var)
Definition: var.c:13370
int * SCIPvarGetImplIds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18438
SCIP_Real SCIPvarGetBestBoundLocal(SCIP_VAR *var)
Definition: var.c:18184
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18332
SCIP_Real SCIPvarGetBranchFactor(SCIP_VAR *var)
Definition: var.c:18258
SCIP_Real SCIPvarGetAvgSol(SCIP_VAR *var)
Definition: var.c:14082
SCIP_Bool SCIPvarIsDeletable(SCIP_VAR *var)
Definition: var.c:17758
SCIP_Real SCIPbdchginfoGetOldbound(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18680
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17630
SCIP_Bool SCIPvarIsTransformedOrigvar(SCIP_VAR *var)
Definition: var.c:12881
SCIP_Real SCIPvarGetUbLazy(SCIP_VAR *var)
Definition: var.c:18246
SCIP_Real SCIPvarGetPseudoSol(SCIP_VAR *var)
Definition: var.c:18550
SCIP_BRANCHDIR SCIPvarGetBranchDirection(SCIP_VAR *var)
Definition: var.c:18280
SCIP_BOUNDTYPE SCIPbdchginfoGetInferBoundtype(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18807
void SCIPvarSetData(SCIP_VAR *var, SCIP_VARDATA *vardata)
Definition: var.c:17469
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18422
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition: var.c:18472
SCIP_BDCHGINFO * SCIPvarGetBdchgInfo(SCIP_VAR *var, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:16709
SCIP_VARDATA * SCIPvarGetData(SCIP_VAR *var)
Definition: var.c:17459
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17878
SCIP_Bool SCIPbdchginfoIsTighter(SCIP_BDCHGINFO *bdchginfo1, SCIP_BDCHGINFO *bdchginfo2)
Definition: var.c:18853
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17866
SCIP_RETCODE SCIPvarSetRemovable(SCIP_VAR *var, SCIP_Bool removable)
Definition: var.c:17542
SCIP_HOLELIST * SCIPvarGetHolelistOriginal(SCIP_VAR *var)
Definition: var.c:18084
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:17650
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18450
SCIP_BOUNDCHGTYPE SCIPbdchginfoGetChgtype(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18710
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18154
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17594
SCIP_DECL_HASHKEYEQ(SCIPvarIsHashkeyEq)
Definition: var.c:12011
SCIP_VAR * SCIPbdchginfoGetInferVar(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18760
SCIP_Bool SCIPbdchginfoHasInferenceReason(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18839
SCIP_Bool SCIPboundchgIsRedundant(SCIP_BOUNDCHG *boundchg)
Definition: var.c:17376
SCIP_Longint SCIPvarGetNBranchings(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:15719
SCIP_Bool SCIPvarIsRelaxationOnly(SCIP_VAR *var)
Definition: var.c:17726
SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
Definition: var.c:17924
SCIP_RETCODE SCIPvarGetProbvarHole(SCIP_VAR **var, SCIP_Real *left, SCIP_Real *right)
Definition: var.c:12582
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18302
SCIP_BDCHGINFO * SCIPvarGetUbchgInfo(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:16653
SCIP_Real SCIPholelistGetLeft(SCIP_HOLELIST *holelist)
Definition: var.c:17406
int SCIPvarGetBranchPriority(SCIP_VAR *var)
Definition: var.c:18270
SCIP_Bool SCIPvarIsOriginal(SCIP_VAR *var)
Definition: var.c:17568
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18461
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18098
void SCIPvarMarkNotDeletable(SCIP_VAR *var)
Definition: var.c:17683
SCIP_Real SCIPvarGetBestRootRedcost(SCIP_VAR *var)
Definition: var.c:13802
SCIP_BDCHGINFO * SCIPvarGetBdchgInfoLb(SCIP_VAR *var, int pos)
Definition: var.c:18498
SCIP_DECL_HASHKEYVAL(SCIPvarGetHashkeyVal)
Definition: var.c:12019
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11962
SCIP_Real SCIPvarGetCutoffSumCurrentRun(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:16242
SCIP_Real SCIPvarGetBestRootLPObjval(SCIP_VAR *var)
Definition: var.c:13836
SCIP_Real SCIPvarGetLbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:16730
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:12330
SCIP_Longint SCIPvarGetNBranchingsCurrentRun(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:15764
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18364
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3429
SCIP_VAR * SCIPvarGetTransVar(SCIP_VAR *var)
Definition: var.c:17798
SCIP_Real SCIPvarGetNLPSol(SCIP_VAR *var)
Definition: var.c:18485
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18344
int SCIPvarGetNBdchgInfosUb(SCIP_VAR *var)
Definition: var.c:18530
SCIP_BOUNDTYPE SCIPbdchginfoGetBoundtype(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18720
SCIP_VALUEHISTORY * SCIPvarGetValuehistory(SCIP_VAR *var)
Definition: var.c:18540
SCIP_BOUNDTYPE SCIPvarGetWorstBoundType(SCIP_VAR *var)
Definition: var.c:18223
SCIP_Real SCIPvarGetInferenceSumCurrentRun(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:16044
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: var.c:11495
SCIP_Bool SCIPbdchgidxIsEarlierNonNull(SCIP_BDCHGIDX *bdchgidx1, SCIP_BDCHGIDX *bdchgidx2)
Definition: var.c:18640
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18354
SCIP_HOLELIST * SCIPvarGetHolelistGlobal(SCIP_VAR *var)
Definition: var.c:18118
SCIP_Real SCIPvarGetBdAtIndex(SCIP_VAR *var, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:16970
SCIP_Real SCIPbdchginfoGetNewbound(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18690
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3295
SCIP_Real SCIPvarGetUbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:16849
SCIP_BDCHGINFO * SCIPvarGetBdchgInfoUb(SCIP_VAR *var, int pos)
Definition: var.c:18518
int SCIPvarGetNBdchgInfosLb(SCIP_VAR *var)
Definition: var.c:18510
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18408
int SCIPvarGetLastBdchgDepth(SCIP_VAR *var)
Definition: var.c:17050
void SCIPvarSetCopyData(SCIP_VAR *var, SCIP_DECL_VARCOPY((*varcopy)))
Definition: var.c:17515
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:12298
SCIP_Real SCIPvarGetUnchangedObj(SCIP_VAR *var)
Definition: var.c:17956
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17890
SCIP_Real SCIPvarGetCutoffSum(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:16199
SCIP_Real SCIPvarGetLbLazy(SCIP_VAR *var)
Definition: var.c:18236
SCIP_Bool SCIPvarIsInLP(SCIP_VAR *var)
Definition: var.c:17820
SCIP_VAR * SCIPvarGetAggrVar(SCIP_VAR *var)
Definition: var.c:17830
SCIP_Real SCIPnormalCDF(SCIP_Real mean, SCIP_Real variance, SCIP_Real value)
Definition: misc.c:199
SCIP_Real SCIPcomputeTwoSampleTTestValue(SCIP_Real meanx, SCIP_Real meany, SCIP_Real variancex, SCIP_Real variancey, SCIP_Real countx, SCIP_Real county)
Definition: misc.c:126
SCIP_Real SCIPstudentTGetCriticalValue(SCIP_CONFIDENCELEVEL clevel, int df)
Definition: misc.c:109
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10880
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:11008
void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
Definition: misc.c:11038
SCIP_RETCODE SCIPvaluehistoryCreate(SCIP_VALUEHISTORY **valuehistory, BMS_BLKMEM *blkmem)
Definition: history.c:243
SCIP_RETCODE SCIPvaluehistoryFind(SCIP_VALUEHISTORY *valuehistory, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Real value, SCIP_HISTORY **history)
Definition: history.c:284
void SCIPvaluehistoryFree(SCIP_VALUEHISTORY **valuehistory, BMS_BLKMEM *blkmem)
Definition: history.c:262
void SCIPvaluehistoryScaleVSIDS(SCIP_VALUEHISTORY *valuehistory, SCIP_Real scalar)
Definition: history.c:329
void SCIPhistoryReset(SCIP_HISTORY *history)
Definition: history.c:78
SCIP_Real SCIPhistoryGetPseudocost(SCIP_HISTORY *history, SCIP_Real solvaldelta)
Definition: history.c:446
SCIP_Real SCIPhistoryGetAvgInferences(SCIP_HISTORY *history, SCIP_BRANCHDIR dir)
Definition: history.c:665
SCIP_Longint SCIPhistoryGetNActiveConflicts(SCIP_HISTORY *history, SCIP_BRANCHDIR dir)
Definition: history.c:565
SCIP_Longint SCIPhistoryGetNBranchings(SCIP_HISTORY *history, SCIP_BRANCHDIR dir)
Definition: history.c:639
SCIP_Real SCIPhistoryGetAvgConflictlength(SCIP_HISTORY *history, SCIP_BRANCHDIR dir)
Definition: history.c:578
SCIP_Real SCIPhistoryGetAvgCutoffs(SCIP_HISTORY *history, SCIP_BRANCHDIR dir)
Definition: history.c:691
SCIP_RETCODE SCIPhistoryCreate(SCIP_HISTORY **history, BMS_BLKMEM *blkmem)
Definition: history.c:51
void SCIPhistorySetLastGMIeff(SCIP_HISTORY *history, SCIP_Real gmieff)
Definition: history.c:782
void SCIPhistoryIncInferenceSum(SCIP_HISTORY *history, SCIP_BRANCHDIR dir, SCIP_Real weight)
Definition: history.c:607
SCIP_Real SCIPhistoryGetCutoffSum(SCIP_HISTORY *history, SCIP_BRANCHDIR dir)
Definition: history.c:678
SCIP_Real SCIPhistoryGetPseudocostCount(SCIP_HISTORY *history, SCIP_BRANCHDIR dir)
Definition: history.c:484
SCIP_Real SCIPhistoryGetPseudocostVariance(SCIP_HISTORY *history, SCIP_BRANCHDIR direction)
Definition: history.c:460
void SCIPhistoryIncNActiveConflicts(SCIP_HISTORY *history, SCIP_BRANCHDIR dir, SCIP_Real length)
Definition: history.c:549
void SCIPhistoryScaleVSIDS(SCIP_HISTORY *history, SCIP_Real scalar)
Definition: history.c:524
void SCIPhistoryIncCutoffSum(SCIP_HISTORY *history, SCIP_BRANCHDIR dir, SCIP_Real weight)
Definition: history.c:623
void SCIPhistoryIncNBranchings(SCIP_HISTORY *history, SCIP_BRANCHDIR dir, int depth)
Definition: history.c:591
void SCIPhistoryUpdatePseudocost(SCIP_HISTORY *history, SCIP_SET *set, SCIP_Real solvaldelta, SCIP_Real objdelta, SCIP_Real weight)
Definition: history.c:174
SCIP_Real SCIPhistoryGetVSIDS(SCIP_HISTORY *history, SCIP_BRANCHDIR dir)
Definition: history.c:536
SCIP_Real SCIPhistoryGetAvgBranchdepth(SCIP_HISTORY *history, SCIP_BRANCHDIR dir)
Definition: history.c:704
SCIP_Real SCIPhistoryGetLastGMIeff(SCIP_HISTORY *history)
Definition: history.c:772
SCIP_Real SCIPhistoryGetAvgGMIeff(SCIP_HISTORY *history)
Definition: history.c:749
SCIP_Real SCIPhistoryGetInferenceSum(SCIP_HISTORY *history, SCIP_BRANCHDIR dir)
Definition: history.c:652
void SCIPhistoryFree(SCIP_HISTORY **history, BMS_BLKMEM *blkmem)
Definition: history.c:66
void SCIPhistoryUnite(SCIP_HISTORY *history, SCIP_HISTORY *addhistory, SCIP_Bool switcheddirs)
Definition: history.c:113
void SCIPhistoryIncGMIeffSum(SCIP_HISTORY *history, SCIP_Real gmieff)
Definition: history.c:759
SCIP_BRANCHDIR SCIPbranchdirOpposite(SCIP_BRANCHDIR dir)
Definition: history.c:437
void SCIPhistoryIncVSIDS(SCIP_HISTORY *history, SCIP_BRANCHDIR dir, SCIP_Real weight)
Definition: history.c:510
internal methods for branching and inference history
SCIP_VAR ** SCIPimplicsGetVars(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3331
void SCIPcliqueDelVar(SCIP_CLIQUE *clique, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Bool value)
Definition: implics.c:1285
void SCIPcliquelistRemoveFromCliques(SCIP_CLIQUELIST *cliquelist, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Bool irrelevantvar)
Definition: implics.c:1683
void SCIPvboundsFree(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem)
Definition: implics.c:73
SCIP_Real * SCIPvboundsGetCoefs(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3306
void SCIPvboundsShrink(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem, int newnvbds)
Definition: implics.c:333
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3380
SCIP_CLIQUE ** SCIPcliquelistGetCliques(SCIP_CLIQUELIST *cliquelist, SCIP_Bool value)
Definition: implics.c:3455
SCIP_Bool SCIPcliquelistsHaveCommonClique(SCIP_CLIQUELIST *cliquelist1, SCIP_Bool value1, SCIP_CLIQUELIST *cliquelist2, SCIP_Bool value2)
Definition: implics.c:1605
SCIP_Real * SCIPimplicsGetBounds(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3349
void SCIPcliquelistCheck(SCIP_CLIQUELIST *cliquelist, SCIP_VAR *var)
Definition: implics.c:3464
SCIP_VAR ** SCIPvboundsGetVars(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3298
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3370
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3392
SCIP_RETCODE SCIPvboundsDel(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem, SCIP_VAR *vbdvar, SCIP_Bool negativecoef)
Definition: implics.c:288
SCIP_RETCODE SCIPcliquetableAdd(SCIP_CLIQUETABLE *cliquetable, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition: implics.c:2376
int * SCIPimplicsGetIds(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3361
SCIP_RETCODE SCIPimplicsAdd(SCIP_IMPLICS **implics, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, SCIP_Real implbound, SCIP_Bool isshortcut, SCIP_Bool *conflict, SCIP_Bool *added)
Definition: implics.c:633
SCIP_RETCODE SCIPvboundsAdd(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_BOUNDTYPE vboundtype, SCIP_VAR *var, SCIP_Real coef, SCIP_Real constant, SCIP_Bool *added)
Definition: implics.c:206
void SCIPcliquelistFree(SCIP_CLIQUELIST **cliquelist, BMS_BLKMEM *blkmem)
Definition: implics.c:1441
int SCIPimplicsGetNImpls(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3322
SCIP_RETCODE SCIPcliqueAddVar(SCIP_CLIQUE *clique, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_VAR *var, SCIP_Bool value, SCIP_Bool *doubleentry, SCIP_Bool *oppositeentry)
Definition: implics.c:1151
SCIP_BOUNDTYPE * SCIPimplicsGetTypes(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3340
int SCIPcliquelistGetNCliques(SCIP_CLIQUELIST *cliquelist, SCIP_Bool value)
Definition: implics.c:3446
SCIP_RETCODE SCIPcliquelistDel(SCIP_CLIQUELIST **cliquelist, BMS_BLKMEM *blkmem, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: implics.c:1527
SCIP_Bool SCIPcliqueIsCleanedUp(SCIP_CLIQUE *clique)
Definition: implics.c:3426
void SCIPimplicsGetVarImplicPoss(SCIP_IMPLICS *implics, SCIP_Bool varfixing, SCIP_VAR *implvar, int *lowerimplicpos, int *upperimplicpos)
Definition: implics.c:916
SCIP_RETCODE SCIPimplicsDel(SCIP_IMPLICS **implics, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype)
Definition: implics.c:836
SCIP_Real * SCIPvboundsGetConstants(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3314
int SCIPvboundsGetNVbds(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3290
SCIP_Bool SCIPimplicsContainsImpl(SCIP_IMPLICS *implics, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype)
Definition: implics.c:933
void SCIPimplicsFree(SCIP_IMPLICS **implics, BMS_BLKMEM *blkmem)
Definition: implics.c:451
SCIP_RETCODE SCIPcliquelistAdd(SCIP_CLIQUELIST **cliquelist, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: implics.c:1482
methods for implications, variable bounds, and cliques
SCIP_Bool SCIPlpIsSolBasic(SCIP_LP *lp)
Definition: lp.c:17837
SCIP_RETCODE SCIPcolChgUb(SCIP_COL *col, SCIP_SET *set, SCIP_LP *lp, SCIP_Real newub)
Definition: lp.c:3799
SCIP_RETCODE SCIPcolFree(SCIP_COL **col, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_LP *lp)
Definition: lp.c:3374
SCIP_RETCODE SCIPcolChgLb(SCIP_COL *col, SCIP_SET *set, SCIP_LP *lp, SCIP_Real newlb)
Definition: lp.c:3754
void SCIPlpDecNLoosevars(SCIP_LP *lp)
Definition: lp.c:14330
SCIP_RETCODE SCIProwAddConstant(SCIP_ROW *row, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_LP *lp, SCIP_Real addval)
Definition: lp.c:5637
SCIP_RETCODE SCIPcolChgObj(SCIP_COL *col, SCIP_SET *set, SCIP_LP *lp, SCIP_Real newobj)
Definition: lp.c:3695
SCIP_RETCODE SCIProwIncCoef(SCIP_ROW *row, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_LP *lp, SCIP_COL *col, SCIP_Real incval)
Definition: lp.c:5525
SCIP_Bool SCIPlpDiving(SCIP_LP *lp)
Definition: lp.c:17847
SCIP_Real SCIPcolGetRedcost(SCIP_COL *col, SCIP_STAT *stat, SCIP_LP *lp)
Definition: lp.c:3949
SCIP_RETCODE SCIPcolCreate(SCIP_COL **col, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_VAR *var, int len, SCIP_ROW **rows, SCIP_Real *vals, SCIP_Bool removable)
Definition: lp.c:3276
SCIP_RETCODE SCIPlpUpdateVarLoose(SCIP_LP *lp, SCIP_SET *set, SCIP_VAR *var)
Definition: lp.c:14309
static const SCIP_Real scalars[]
Definition: lp.c:5740
SCIP_RETCODE SCIPlpUpdateVarColumn(SCIP_LP *lp, SCIP_SET *set, SCIP_VAR *var)
Definition: lp.c:14185
internal methods for LP management
#define BMSreallocBlockMemorySize(mem, ptr, oldsize, newsize)
Definition: memory.h:456
#define BMSduplicateBlockMemoryArray(mem, ptr, source, num)
Definition: memory.h:462
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:465
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:451
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:468
#define BMSfreeBlockMemorySize(mem, ptr, size)
Definition: memory.h:469
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
#define BMSfreeBlockMemoryArray(mem, ptr, num)
Definition: memory.h:467
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:458
#define BMSallocBlockMemorySize(mem, ptr, size)
Definition: memory.h:453
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:437
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:618
void SCIPmessagePrintWarning(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:427
real eps
SCIP_RETCODE SCIPprimalUpdateObjoffset(SCIP_PRIMAL *primal, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTFILTER *eventfilter, SCIP_EVENTQUEUE *eventqueue, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp)
Definition: primal.c:471
internal methods for collecting primal CIP solutions and primal informations
void SCIPprobUpdateNObjVars(SCIP_PROB *prob, SCIP_SET *set, SCIP_Real oldobj, SCIP_Real newobj)
Definition: prob.c:1592
int SCIPprobGetNContVars(SCIP_PROB *prob)
Definition: prob.c:2437
SCIP_RETCODE SCIPprobAddVar(SCIP_PROB *prob, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENTQUEUE *eventqueue, SCIP_VAR *var)
Definition: prob.c:970
SCIP_RETCODE SCIPprobVarChangedStatus(SCIP_PROB *prob, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_BRANCHCAND *branchcand, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var)
Definition: prob.c:1224
const char * SCIPprobGetName(SCIP_PROB *prob)
Definition: prob.c:2392
void SCIPprobAddObjoffset(SCIP_PROB *prob, SCIP_Real addval)
Definition: prob.c:1481
int SCIPprobGetNVars(SCIP_PROB *prob)
Definition: prob.c:2401
SCIP_VAR ** SCIPprobGetVars(SCIP_PROB *prob)
Definition: prob.c:2446
SCIP_Bool SCIPprobIsTransformed(SCIP_PROB *prob)
Definition: prob.c:2336
internal methods for storing and manipulating the main problem
public methods for managing constraints
public methods for branching and inference history structure
public methods for implications, variable bounds, and cliques
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
#define SCIPdebugMessage
Definition: pub_message.h:96
public data structures and miscellaneous methods
methods for sorting joint arrays of various types
public methods for propagators
public methods for problem variables
void SCIPrelaxationSolObjAdd(SCIP_RELAXATION *relaxation, SCIP_Real val)
Definition: relax.c:849
internal methods for relaxators
SCIP callable library.
SCIP_Bool SCIPsetIsDualfeasZero(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6918
SCIP_Real SCIPsetFloor(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6386
SCIP_Bool SCIPsetIsFeasPositive(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6718
SCIP_Bool SCIPsetIsGE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6293
SCIP_Real SCIPsetFeasCeil(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6775
SCIP_Bool SCIPsetIsFeasNegative(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6729
SCIP_Real SCIPsetFeastol(SCIP_SET *set)
Definition: set.c:6106
SCIP_Real SCIPsetCeil(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6397
SCIP_Bool SCIPsetIsFeasGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6663
SCIP_Bool SCIPsetIsFeasLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6641
SCIP_Bool SCIPsetIsFeasEQ(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6597
SCIP_Bool SCIPsetIsPositive(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6322
SCIP_Bool SCIPsetIsLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6257
SCIP_Real SCIPsetFeasFloor(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6764
SCIP_Bool SCIPsetIsDualfeasNegative(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6940
SCIP_Real SCIPsetEpsilon(SCIP_SET *set)
Definition: set.c:6086
SCIP_Bool SCIPsetIsEQ(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6221
SCIP_Bool SCIPsetIsFeasZero(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6707
SCIP_STAGE SCIPsetGetStage(SCIP_SET *set)
Definition: set.c:2952
SCIP_Bool SCIPsetIsFeasLT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6619
SCIP_Real SCIPsetInfinity(SCIP_SET *set)
Definition: set.c:6064
SCIP_Bool SCIPsetIsLT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6239
SCIP_Bool SCIPsetIsInfinity(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6199
SCIP_Bool SCIPsetIsDualfeasPositive(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6929
SCIP_Bool SCIPsetIsGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6275
SCIP_Bool SCIPsetIsIntegral(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6344
SCIP_Bool SCIPsetIsZero(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6311
SCIP_Bool SCIPsetIsFeasGE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6685
SCIP_Real SCIPsetGetHugeValue(SCIP_SET *set)
Definition: set.c:6076
SCIP_Real SCIPsetRound(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6408
int SCIPsetCalcMemGrowSize(SCIP_SET *set, int num)
Definition: set.c:5764
SCIP_Bool SCIPsetIsFeasIntegral(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6740
SCIP_Bool SCIPsetIsNegative(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6333
internal methods for global SCIP settings
#define SCIPsetFreeBufferArray(set, ptr)
Definition: set.h:1755
#define SCIPsetFreeCleanBufferArray(set, ptr)
Definition: set.h:1762
#define SCIPsetAllocBufferArray(set, ptr, num)
Definition: set.h:1748
#define SCIPsetAllocCleanBufferArray(set, ptr, num)
Definition: set.h:1759
#define SCIPsetDuplicateBufferArray(set, ptr, source, num)
Definition: set.h:1750
#define SCIPsetDebugMsg
Definition: set.h:1784
#define SCIPsetReallocBufferArray(set, ptr, num)
Definition: set.h:1752
SCIP_Real SCIPsolGetVal(SCIP_SOL *sol, SCIP_SET *set, SCIP_STAT *stat, SCIP_VAR *var)
Definition: sol.c:1372
internal methods for storing primal CIP solutions
SCIP_RETCODE SCIPstatUpdateVarRootLPBestEstimate(SCIP_STAT *stat, SCIP_SET *set, SCIP_VAR *var, SCIP_Real oldrootpscostscore)
Definition: stat.c:807
internal methods for problem statistics
#define SCIPstatIncrement(stat, set, field)
Definition: stat.h:260
SCIP_VAR * var
Definition: struct_var.h:187
SCIP_Real scalar
Definition: struct_var.h:185
SCIP_Real constant
Definition: struct_var.h:186
SCIP_BDCHGIDX bdchgidx
Definition: struct_var.h:121
SCIP_Real newbound
Definition: struct_var.h:118
SCIP_INFERENCEDATA inferencedata
Definition: struct_var.h:120
unsigned int boundchgtype
Definition: struct_var.h:123
unsigned int boundtype
Definition: struct_var.h:124
SCIP_VAR * var
Definition: struct_var.h:119
unsigned int redundant
Definition: struct_var.h:126
unsigned int inferboundtype
Definition: struct_var.h:125
SCIP_Real oldbound
Definition: struct_var.h:117
unsigned int pos
Definition: struct_var.h:122
union SCIP_BoundChg::@21 data
SCIP_Real newbound
Definition: struct_var.h:93
unsigned int applied
Definition: struct_var.h:103
unsigned int boundtype
Definition: struct_var.h:101
SCIP_INFERENCEDATA inferencedata
Definition: struct_var.h:97
unsigned int redundant
Definition: struct_var.h:104
SCIP_VAR * var
Definition: struct_var.h:99
SCIP_BRANCHINGDATA branchingdata
Definition: struct_var.h:96
unsigned int inferboundtype
Definition: struct_var.h:102
unsigned int boundchgtype
Definition: struct_var.h:100
int lppos
Definition: struct_lp.h:172
int lpipos
Definition: struct_lp.h:173
SCIP_VAR * var
Definition: struct_lp.h:160
int var_probindex
Definition: struct_lp.h:178
SCIP_HOLECHG * holechgs
Definition: struct_var.h:143
SCIP_BOUNDCHG * boundchgs
Definition: struct_var.h:134
unsigned int nboundchgs
Definition: struct_var.h:132
SCIP_BOUNDCHG * boundchgs
Definition: struct_var.h:152
SCIP_HOLECHG * holechgs
Definition: struct_var.h:153
unsigned int domchgtype
Definition: struct_var.h:151
SCIP_Real lb
Definition: struct_var.h:170
SCIP_Real ub
Definition: struct_var.h:171
SCIP_HOLELIST * holelist
Definition: struct_var.h:172
SCIP_EVENTTYPE eventmask
Definition: struct_event.h:198
SCIP_HOLELIST ** ptr
Definition: struct_var.h:67
SCIP_HOLELIST * oldlist
Definition: struct_var.h:69
SCIP_HOLELIST * newlist
Definition: struct_var.h:68
SCIP_Real right
Definition: struct_var.h:54
SCIP_Real left
Definition: struct_var.h:53
SCIP_HOLELIST * next
Definition: struct_var.h:61
SCIP_HOLE hole
Definition: struct_var.h:60
SCIP_Bool divingobjchg
Definition: struct_lp.h:381
SCIP_VAR ** vars
Definition: struct_var.h:195
SCIP_Real constant
Definition: struct_var.h:193
SCIP_Real * scalars
Definition: struct_var.h:194
SCIP_Real constant
Definition: struct_var.h:203
SCIP_DOM origdom
Definition: struct_var.h:178
SCIP_VAR * transvar
Definition: struct_var.h:179
SCIP_OBJSENSE objsense
Definition: struct_prob.h:87
SCIP_Real objscale
Definition: struct_prob.h:51
char * name
Definition: struct_lp.h:226
SCIP_VAR * lastbranchvar
Definition: struct_stat.h:183
SCIP_Longint lpcount
Definition: struct_stat.h:190
SCIP_HISTORY * glbhistory
Definition: struct_stat.h:181
int nrootboundchgs
Definition: struct_stat.h:222
int nrootintfixingsrun
Definition: struct_stat.h:225
int nrootintfixings
Definition: struct_stat.h:224
SCIP_Real vsidsweight
Definition: struct_stat.h:132
SCIP_BRANCHDIR lastbranchdir
Definition: struct_stat.h:187
int nrootboundchgsrun
Definition: struct_stat.h:223
SCIP_Bool collectvarhistory
Definition: struct_stat.h:281
SCIP_HISTORY * glbhistorycrun
Definition: struct_stat.h:182
SCIP_Real lastbranchvalue
Definition: struct_stat.h:143
SCIP_Real lazylb
Definition: struct_var.h:223
SCIP_VARDATA * vardata
Definition: struct_var.h:240
SCIP_EVENTFILTER * eventfilter
Definition: struct_var.h:247
int nubchginfos
Definition: struct_var.h:269
SCIP_Real lazyub
Definition: struct_var.h:224
SCIP_ORIGINAL original
Definition: struct_var.h:229
SCIP_VBOUNDS * vlbs
Definition: struct_var.h:243
SCIP_AGGREGATE aggregate
Definition: struct_var.h:231
SCIP_IMPLICS * implics
Definition: struct_var.h:245
SCIP_VAR ** parentvars
Definition: struct_var.h:241
SCIP_BDCHGINFO * lbchginfos
Definition: struct_var.h:248
SCIP_Real rootsol
Definition: struct_var.h:212
SCIP_VAR * negatedvar
Definition: struct_var.h:242
SCIP * scip
Definition: struct_var.h:288
unsigned int varstatus
Definition: struct_var.h:281
union SCIP_Var::@22 data
int nlocksdown[NLOCKTYPES]
Definition: struct_var.h:263
SCIP_Real bestrootsol
Definition: struct_var.h:213
SCIP_HISTORY * historycrun
Definition: struct_var.h:251
unsigned int relaxationonly
Definition: struct_var.h:286
unsigned int donotmultaggr
Definition: struct_var.h:279
int closestvubidx
Definition: struct_var.h:273
SCIP_DOM glbdom
Definition: struct_var.h:225
unsigned int vartype
Definition: struct_var.h:280
SCIP_Real branchfactor
Definition: struct_var.h:211
int conflictubcount
Definition: struct_var.h:271
SCIP_Real unchangedobj
Definition: struct_var.h:210
SCIP_Real conflictrelaxedub
Definition: struct_var.h:222
SCIP_BDCHGINFO * ubchginfos
Definition: struct_var.h:249
SCIP_Real bestrootredcost
Definition: struct_var.h:214
char * name
Definition: struct_var.h:235
SCIP_Real conflictrelaxedlb
Definition: struct_var.h:221
unsigned int deletable
Definition: struct_var.h:276
unsigned int initial
Definition: struct_var.h:274
SCIP_DOM locdom
Definition: struct_var.h:226
unsigned int removable
Definition: struct_var.h:275
SCIP_CLIQUELIST * cliquelist
Definition: struct_var.h:246
SCIP_COL * col
Definition: struct_var.h:230
unsigned int deleted
Definition: struct_var.h:277
SCIP_MULTAGGR multaggr
Definition: struct_var.h:232
SCIP_Real obj
Definition: struct_var.h:209
int probindex
Definition: struct_var.h:255
SCIP_Real nlpsol
Definition: struct_var.h:217
int nlocksup[NLOCKTYPES]
Definition: struct_var.h:264
int nlbchginfos
Definition: struct_var.h:267
unsigned int branchdirection
Definition: struct_var.h:283
unsigned int delglobalstructs
Definition: struct_var.h:285
int lbchginfossize
Definition: struct_var.h:266
SCIP_HISTORY * history
Definition: struct_var.h:250
int index
Definition: struct_var.h:254
SCIP_VBOUNDS * vubs
Definition: struct_var.h:244
int nparentvars
Definition: struct_var.h:261
unsigned int donotaggr
Definition: struct_var.h:278
int parentvarssize
Definition: struct_var.h:260
int nuses
Definition: struct_var.h:262
int closestvlbidx
Definition: struct_var.h:272
SCIP_NEGATE negate
Definition: struct_var.h:233
SCIP_Real primsolavg
Definition: struct_var.h:218
SCIP_Real relaxsol
Definition: struct_var.h:216
SCIP_Longint closestvblpcount
Definition: struct_var.h:253
SCIP_Real bestrootlpobjval
Definition: struct_var.h:215
int ubchginfossize
Definition: struct_var.h:268
SCIP_VALUEHISTORY * valuehistory
Definition: struct_var.h:252
int branchpriority
Definition: struct_var.h:265
int conflictlbcount
Definition: struct_var.h:270
SCIP_PROB * origprob
Definition: struct_scip.h:81
SCIP_PROB * transprob
Definition: struct_scip.h:99
datastructures for managing events
data structures for LP management
datastructures for storing and manipulating the main problem
SCIP main data structure.
datastructures for global SCIP settings
datastructures for problem statistics
datastructures for problem variables
Definition: heur_padm.c:135
SCIP_NODE * SCIPtreeGetRootNode(SCIP_TREE *tree)
Definition: tree.c:8557
SCIP_RETCODE SCIPnodeAddBoundchg(SCIP_NODE *node, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Real newbound, SCIP_BOUNDTYPE boundtype, SCIP_Bool probingchange)
Definition: tree.c:2107
internal methods for branch and bound tree
#define SCIP_EVENTTYPE_GHOLEADDED
Definition: type_event.h:81
#define SCIP_EVENTTYPE_GUBCHANGED
Definition: type_event.h:76
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:173
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:152
#define SCIP_EVENTTYPE_GLBCHANGED
Definition: type_event.h:75
#define SCIP_EVENTTYPE_VARCHANGED
Definition: type_event.h:130
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:121
#define SCIP_EVENTTYPE_UBCHANGED
Definition: type_event.h:122
#define SCIP_EVENTTYPE_LHOLEADDED
Definition: type_event.h:83
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:151
@ SCIP_BRANCHDIR_DOWNWARDS
Definition: type_history.h:43
@ SCIP_BRANCHDIR_AUTO
Definition: type_history.h:46
@ SCIP_BRANCHDIR_UPWARDS
Definition: type_history.h:44
enum SCIP_BranchDir SCIP_BRANCHDIR
Definition: type_history.h:48
@ SCIP_BOUNDTYPE_UPPER
Definition: type_lp.h:57
@ SCIP_BOUNDTYPE_LOWER
Definition: type_lp.h:56
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
@ SCIP_BASESTAT_UPPER
Definition: type_lpi.h:93
@ SCIP_BASESTAT_LOWER
Definition: type_lpi.h:91
enum SCIP_BaseStat SCIP_BASESTAT
Definition: type_lpi.h:96
@ SCIP_CONFIDENCELEVEL_MAX
Definition: type_misc.h:51
@ SCIP_CONFIDENCELEVEL_MEDIUM
Definition: type_misc.h:49
@ SCIP_CONFIDENCELEVEL_HIGH
Definition: type_misc.h:50
@ SCIP_CONFIDENCELEVEL_MIN
Definition: type_misc.h:47
@ SCIP_CONFIDENCELEVEL_LOW
Definition: type_misc.h:48
enum SCIP_Confidencelevel SCIP_CONFIDENCELEVEL
Definition: type_misc.h:53
enum SCIP_Objsense SCIP_OBJSENSE
Definition: type_prob.h:50
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_SUCCESS
Definition: type_result.h:58
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_INVALIDRESULT
Definition: type_retcode.h:53
@ SCIP_READERROR
Definition: type_retcode.h:45
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_INVALIDCALL
Definition: type_retcode.h:51
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_PROBLEM
Definition: type_set.h:45
@ SCIP_STAGE_PRESOLVING
Definition: type_set.h:49
@ SCIP_STAGE_INITSOLVE
Definition: type_set.h:52
@ SCIP_STAGE_SOLVING
Definition: type_set.h:53
@ SCIP_STAGE_TRANSFORMING
Definition: type_set.h:46
@ SCIP_STAGE_PRESOLVED
Definition: type_set.h:51
struct SCIP_VarData SCIP_VARDATA
Definition: type_var.h:120
enum SCIP_BoundchgType SCIP_BOUNDCHGTYPE
Definition: type_var.h:91
#define NLOCKTYPES
Definition: type_var.h:94
#define SCIP_DECL_VARDELORIG(x)
Definition: type_var.h:131
@ SCIP_DOMCHGTYPE_DYNAMIC
Definition: type_var.h:78
@ SCIP_DOMCHGTYPE_BOUND
Definition: type_var.h:80
@ SCIP_DOMCHGTYPE_BOTH
Definition: type_var.h:79
#define SCIP_DECL_VARTRANS(x)
Definition: type_var.h:151
@ SCIP_VARTYPE_INTEGER
Definition: type_var.h:63
@ SCIP_VARTYPE_CONTINUOUS
Definition: type_var.h:71
@ SCIP_VARTYPE_IMPLINT
Definition: type_var.h:64
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:62
@ SCIP_BOUNDCHGTYPE_PROPINFER
Definition: type_var.h:89
@ SCIP_BOUNDCHGTYPE_BRANCHING
Definition: type_var.h:87
@ SCIP_BOUNDCHGTYPE_CONSINFER
Definition: type_var.h:88
@ SCIP_VARSTATUS_ORIGINAL
Definition: type_var.h:49
@ SCIP_VARSTATUS_FIXED
Definition: type_var.h:52
@ SCIP_VARSTATUS_COLUMN
Definition: type_var.h:51
@ SCIP_VARSTATUS_MULTAGGR
Definition: type_var.h:54
@ SCIP_VARSTATUS_NEGATED
Definition: type_var.h:55
@ SCIP_VARSTATUS_AGGREGATED
Definition: type_var.h:53
@ SCIP_VARSTATUS_LOOSE
Definition: type_var.h:50
#define SCIP_DECL_VARCOPY(x)
Definition: type_var.h:194
#define SCIP_DECL_VARDELTRANS(x)
Definition: type_var.h:164
enum SCIP_LockType SCIP_LOCKTYPE
Definition: type_var.h:100
@ SCIP_LOCKTYPE_MODEL
Definition: type_var.h:97
enum SCIP_Vartype SCIP_VARTYPE
Definition: type_var.h:73
enum SCIP_Varstatus SCIP_VARSTATUS
Definition: type_var.h:57
SCIP_DOMCHGBOUND domchgbound
Definition: struct_var.h:162
SCIP_DOMCHGDYN domchgdyn
Definition: struct_var.h:164
SCIP_DOMCHGBOTH domchgboth
Definition: struct_var.h:163
SCIP_RETCODE SCIPvarRemove(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_CLIQUETABLE *cliquetable, SCIP_SET *set, SCIP_Bool final)
Definition: var.c:6059
static SCIP_RETCODE varParse(SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, const char *str, char *name, SCIP_Real *lb, SCIP_Real *ub, SCIP_Real *obj, SCIP_VARTYPE *vartype, SCIP_Real *lazylb, SCIP_Real *lazyub, SCIP_Bool local, char **endptr, SCIP_Bool *success)
Definition: var.c:2349
SCIP_RETCODE SCIPvarAddObj(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_PRIMAL *primal, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_EVENTFILTER *eventfilter, SCIP_EVENTQUEUE *eventqueue, SCIP_Real addobj)
Definition: var.c:6339
SCIP_Real SCIPvarGetObjLP(SCIP_VAR *var)
Definition: var.c:12906
SCIP_Real SCIPvarGetPseudocost(SCIP_VAR *var, SCIP_STAT *stat, SCIP_Real solvaldelta)
Definition: var.c:14497
SCIP_RETCODE SCIPvarsGetActiveVars(SCIP_SET *set, SCIP_VAR **vars, int *nvars, int varssize, int *requiredsize)
Definition: var.c:12026
static SCIP_RETCODE tryAggregateIntVars(SCIP_SET *set, BMS_BLKMEM *blkmem, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_PRIMAL *primal, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_CLIQUETABLE *cliquetable, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENTQUEUE *eventqueue, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *aggregated)
Definition: var.c:5054
SCIP_RETCODE SCIPvarIncNBranchings(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_BRANCHDIR dir, SCIP_Real value, int depth)
Definition: var.c:15467
static SCIP_RETCODE varEventGlbChanged(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Real oldbound, SCIP_Real newbound)
Definition: var.c:6686
static SCIP_RETCODE varEnsureUbchginfosSize(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, int num)
Definition: var.c:453
SCIP_RETCODE SCIPvarChgLbLazy(SCIP_VAR *var, SCIP_SET *set, SCIP_Real lazylb)
Definition: var.c:7469
static SCIP_RETCODE domchgEnsureBoundchgsSize(SCIP_DOMCHG *domchg, BMS_BLKMEM *blkmem, SCIP_SET *set, int num)
Definition: var.c:1250
SCIP_RETCODE SCIPvarCreateTransformed(SCIP_VAR **var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: var.c:2117
static SCIP_RETCODE varProcessChgUbLocal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Real newbound)
Definition: var.c:7804
SCIP_Real SCIPvarGetPseudocostCount(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:14593
SCIP_RETCODE SCIPvarResetBounds(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat)
Definition: var.c:9230
void SCIPbdchginfoFree(SCIP_BDCHGINFO **bdchginfo, BMS_BLKMEM *blkmem)
Definition: var.c:16583
static SCIP_RETCODE domAddHole(SCIP_DOM *dom, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Real left, SCIP_Real right, SCIP_Bool *added)
Definition: var.c:224
SCIP_RETCODE SCIPvarGetTransformed(SCIP_VAR *origvar, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_VAR **transvar)
Definition: var.c:3548
SCIP_RETCODE SCIPvarChgObj(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_PROB *prob, SCIP_PRIMAL *primal, SCIP_LP *lp, SCIP_EVENTQUEUE *eventqueue, SCIP_Real newobj)
Definition: var.c:6264
static SCIP_RETCODE varProcessChgBranchPriority(SCIP_VAR *var, int branchpriority)
Definition: var.c:11651
static SCIP_RETCODE parseValue(SCIP_SET *set, const char *str, SCIP_Real *value, char **endptr)
Definition: var.c:2272
#define MAXDNOM
SCIP_Real SCIPvarGetPseudocostVariance(SCIP_VAR *var, SCIP_BRANCHDIR dir, SCIP_Bool onlycurrentrun)
Definition: var.c:14712
static SCIP_RETCODE boundchgApplyGlobal(SCIP_BOUNDCHG *boundchg, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_Bool *cutoff)
Definition: var.c:910
SCIP_Real SCIPvarGetImplRedcost(SCIP_VAR *var, SCIP_SET *set, SCIP_Bool varfixing, SCIP_STAT *stat, SCIP_PROB *prob, SCIP_LP *lp)
Definition: var.c:13488
static SCIP_RETCODE varCreate(SCIP_VAR **var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARCOPY((*varcopy)), SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_VARDATA *vardata)
Definition: var.c:1929
SCIP_RETCODE SCIPvarSetLastGMIScore(SCIP_VAR *var, SCIP_STAT *stat, SCIP_Real gmieff)
Definition: var.c:16503
SCIP_RETCODE SCIPvarFix(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_PRIMAL *primal, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: var.c:3749
static SCIP_RETCODE varAddImplic(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_CLIQUETABLE *cliquetable, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, SCIP_Real implbound, SCIP_Bool isshortcut, SCIP_Bool *infeasible, int *nbdchgs, SCIP_Bool *added)
Definition: var.c:9511
void SCIPvarInitSolve(SCIP_VAR *var)
Definition: var.c:2931
SCIP_RETCODE SCIPvarIncInferenceSum(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_BRANCHDIR dir, SCIP_Real value, SCIP_Real weight)
Definition: var.c:15551
static void printBounds(SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, SCIP_Real lb, SCIP_Real ub, const char *name)
Definition: var.c:2944
SCIP_RETCODE SCIPvarIncVSIDS(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_BRANCHDIR dir, SCIP_Real value, SCIP_Real weight)
Definition: var.c:15071
static SCIP_RETCODE varProcessChgLbLocal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Real newbound)
Definition: var.c:7637
static SCIP_RETCODE varAddLbchginfo(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Real oldbound, SCIP_Real newbound, int depth, int pos, SCIP_VAR *infervar, SCIP_CONS *infercons, SCIP_PROP *inferprop, int inferinfo, SCIP_BOUNDTYPE inferboundtype, SCIP_BOUNDCHGTYPE boundchgtype)
Definition: var.c:479
SCIP_RETCODE SCIPdomchgUndo(SCIP_DOMCHG *domchg, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue)
Definition: var.c:1348
static SCIP_RETCODE varProcessAddHoleLocal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_Real left, SCIP_Real right, SCIP_Bool *added)
Definition: var.c:8993
SCIP_Real SCIPvarGetAvgCutoffs(SCIP_VAR *var, SCIP_STAT *stat, SCIP_BRANCHDIR dir)
Definition: var.c:16285
SCIP_RETCODE SCIPboundchgApply(SCIP_BOUNDCHG *boundchg, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, int depth, int pos, SCIP_Bool *cutoff)
Definition: var.c:628
SCIP_RETCODE SCIPdomchgMakeStatic(SCIP_DOMCHG **domchg, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_LP *lp)
Definition: var.c:1161
static void checkImplic(SCIP_SET *set, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, SCIP_Real implbound, SCIP_Bool *redundant, SCIP_Bool *infeasible)
Definition: var.c:9381
static SCIP_VAR * varGetActiveVar(SCIP_VAR *var)
Definition: var.c:5799
SCIP_RETCODE SCIPvarUpdatePseudocost(SCIP_VAR *var, SCIP_SET *set, SCIP_STAT *stat, SCIP_Real solvaldelta, SCIP_Real objdelta, SCIP_Real weight)
Definition: var.c:14399
SCIP_RETCODE SCIPvarTransform(SCIP_VAR *origvar, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_OBJSENSE objsense, SCIP_VAR **transvar)
Definition: var.c:3461
SCIP_RETCODE SCIPvarAddHoleOriginal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Real left, SCIP_Real right)
Definition: var.c:8693
SCIP_RETCODE SCIPvarAddCliqueToList(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: var.c:11413
static SCIP_RETCODE varEventObjChanged(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_PRIMAL *primal, SCIP_LP *lp, SCIP_EVENTQUEUE *eventqueue, SCIP_Real oldobj, SCIP_Real newobj)
Definition: var.c:6229
static SCIP_RETCODE varFree(SCIP_VAR **var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_LP *lp)
Definition: var.c:2744
SCIP_RETCODE SCIPvarAddHoleGlobal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_Real left, SCIP_Real right, SCIP_Bool *added)
Definition: var.c:8874
SCIP_Real SCIPvarGetAvgInferencesCurrentRun(SCIP_VAR *var, SCIP_STAT *stat, SCIP_BRANCHDIR dir)
Definition: var.c:16144
static SCIP_RETCODE varEventImplAdded(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue)
Definition: var.c:9263
SCIP_RETCODE SCIPvarRelease(SCIP_VAR **var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_LP *lp)
Definition: var.c:2872
void SCIPvarGetClosestVub(SCIP_VAR *var, SCIP_SOL *sol, SCIP_SET *set, SCIP_STAT *stat, SCIP_Real *closestvub, int *closestvubidx)
Definition: var.c:14218
SCIP_RETCODE SCIPvarIncNActiveConflicts(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_BRANCHDIR dir, SCIP_Real value, SCIP_Real length)
Definition: var.c:15207
void SCIPvarAdjustLb(SCIP_VAR *var, SCIP_SET *set, SCIP_Real *lb)
Definition: var.c:6517
SCIP_RETCODE SCIPvarDropEvent(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: var.c:18605
SCIP_RETCODE SCIPvarChgLbGlobal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_Real newbound)
Definition: var.c:7185
SCIP_RETCODE SCIPvarSetNLPSol(SCIP_VAR *var, SCIP_SET *set, SCIP_Real solval)
Definition: var.c:14026
SCIP_RETCODE SCIPvarCopy(SCIP_VAR **var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP *sourcescip, SCIP_VAR *sourcevar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global)
Definition: var.c:2159
SCIP_Real SCIPvarCalcPscostConfidenceBound(SCIP_VAR *var, SCIP_SET *set, SCIP_BRANCHDIR dir, SCIP_Bool onlycurrentrun, SCIP_CONFIDENCELEVEL clevel)
Definition: var.c:14766
static SCIP_BDCHGIDX presolvebdchgidx
Definition: var.c:17010
static SCIP_RETCODE varEventLbChanged(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Real oldbound, SCIP_Real newbound)
Definition: var.c:7546
SCIP_Bool SCIPvarIsPscostRelerrorReliable(SCIP_VAR *var, SCIP_SET *set, SCIP_STAT *stat, SCIP_Real threshold, SCIP_CONFIDENCELEVEL clevel)
Definition: var.c:14804
SCIP_RETCODE SCIPvarChgLbOriginal(SCIP_VAR *var, SCIP_SET *set, SCIP_Real newbound)
Definition: var.c:6567
SCIP_RETCODE SCIPvarAddToRow(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_PROB *prob, SCIP_LP *lp, SCIP_ROW *row, SCIP_Real val)
Definition: var.c:14290
SCIP_Real SCIPvarGetLbLP(SCIP_VAR *var, SCIP_SET *set)
Definition: var.c:12952
void SCIPvarAdjustBd(SCIP_VAR *var, SCIP_SET *set, SCIP_BOUNDTYPE boundtype, SCIP_Real *bd)
Definition: var.c:6551
static SCIP_RETCODE varEventUbChanged(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Real oldbound, SCIP_Real newbound)
Definition: var.c:7584
SCIP_RETCODE SCIPvarChgObjDive(SCIP_VAR *var, SCIP_SET *set, SCIP_LP *lp, SCIP_Real newobj)
Definition: var.c:6454
SCIP_RETCODE SCIPdomchgFree(SCIP_DOMCHG **domchg, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_LP *lp)
Definition: var.c:1060
SCIP_Real SCIPvarGetRelaxSolTransVar(SCIP_VAR *var)
Definition: var.c:14015
SCIP_RETCODE SCIPvarPrint(SCIP_VAR *var, SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: var.c:3006
SCIP_Real SCIPvarGetAvgGMIScore(SCIP_VAR *var, SCIP_STAT *stat)
Definition: var.c:16379
SCIP_Real SCIPvarGetVSIDS(SCIP_VAR *var, SCIP_STAT *stat, SCIP_BRANCHDIR dir)
Definition: var.c:18563
static SCIP_RETCODE varEventVarFixed(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, int fixeventtype)
Definition: var.c:3654
SCIP_RETCODE SCIPvarIncCutoffSum(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_BRANCHDIR dir, SCIP_Real value, SCIP_Real weight)
Definition: var.c:15635
SCIP_Real SCIPvarGetMultaggrLbLocal(SCIP_VAR *var, SCIP_SET *set)
Definition: var.c:8434
static SCIP_RETCODE varUpdateAggregationBounds(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_PRIMAL *primal, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *aggvar, SCIP_Real scalar, SCIP_Real constant, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: var.c:4550
SCIP_Bool SCIPvarSignificantPscostDifference(SCIP_SET *set, SCIP_STAT *stat, SCIP_VAR *varx, SCIP_Real fracx, SCIP_VAR *vary, SCIP_Real fracy, SCIP_BRANCHDIR dir, SCIP_CONFIDENCELEVEL clevel, SCIP_Bool onesided)
Definition: var.c:14881
void SCIPvarCapture(SCIP_VAR *var)
Definition: var.c:2847
static SCIP_RETCODE varEventGubChanged(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Real oldbound, SCIP_Real newbound)
Definition: var.c:6724
SCIP_RETCODE SCIPvarChgBranchDirection(SCIP_VAR *var, SCIP_BRANCHDIR branchdirection)
Definition: var.c:11838
SCIP_Real SCIPvarGetPseudocostCurrentRun(SCIP_VAR *var, SCIP_STAT *stat, SCIP_Real solvaldelta)
Definition: var.c:14546
static SCIP_Real adjustedLb(SCIP_SET *set, SCIP_VARTYPE vartype, SCIP_Real lb)
Definition: var.c:1568
SCIP_RETCODE SCIPdomchgAddHolechg(SCIP_DOMCHG **domchg, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_HOLELIST **ptr, SCIP_HOLELIST *newlist, SCIP_HOLELIST *oldlist)
Definition: var.c:1519
void SCIPvarStoreRootSol(SCIP_VAR *var, SCIP_Bool roothaslp)
Definition: var.c:13289
static SCIP_RETCODE domchgEnsureHolechgsSize(SCIP_DOMCHG *domchg, BMS_BLKMEM *blkmem, SCIP_SET *set, int num)
Definition: var.c:1275
static SCIP_RETCODE varEnsureLbchginfosSize(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, int num)
Definition: var.c:427
SCIP_Bool SCIPvarDoNotAggr(SCIP_VAR *var)
Definition: var.c:5848
SCIP_RETCODE SCIPvarChgType(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_PRIMAL *primal, SCIP_LP *lp, SCIP_EVENTQUEUE *eventqueue, SCIP_VARTYPE vartype)
Definition: var.c:6178
SCIP_RETCODE SCIPvarFlattenAggregationGraph(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue)
Definition: var.c:4424
SCIP_Longint SCIPvarGetNActiveConflicts(SCIP_VAR *var, SCIP_STAT *stat, SCIP_BRANCHDIR dir)
Definition: var.c:15288
void SCIPvarUpdateBestRootSol(SCIP_VAR *var, SCIP_SET *set, SCIP_Real rootsol, SCIP_Real rootredcost, SCIP_Real rootlpobjval)
Definition: var.c:13300
SCIP_RETCODE SCIPvarCreateOriginal(SCIP_VAR **var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: var.c:2074
SCIP_Real SCIPvarGetVSIDS_rec(SCIP_VAR *var, SCIP_STAT *stat, SCIP_BRANCHDIR dir)
Definition: var.c:15897
SCIP_RETCODE SCIPvarChgBdLocal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Real newbound, SCIP_BOUNDTYPE boundtype)
Definition: var.c:8223
SCIP_RETCODE SCIPvarFixBinary(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_Bool value, SCIP_Bool *infeasible, int *nbdchgs)
Definition: var.c:11202
SCIP_RETCODE SCIPvarScaleVSIDS(SCIP_VAR *var, SCIP_Real scalar)
Definition: var.c:15157
static SCIP_RETCODE findValuehistoryEntry(SCIP_VAR *var, SCIP_Real value, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_HISTORY **history)
Definition: var.c:15016
SCIP_Real SCIPvarGetAvgConflictlength(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:15380
static SCIP_RETCODE varProcessChgUbGlobal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_Real newbound)
Definition: var.c:7011
SCIP_Real SCIPvarGetPseudocostCountCurrentRun(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:14638
SCIP_RETCODE SCIPvarChgUbGlobal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_Real newbound)
Definition: var.c:7328
static SCIP_RETCODE varEnsureParentvarsSize(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, int num)
Definition: var.c:2619
SCIP_RETCODE SCIPvarGetActiveRepresentatives(SCIP_SET *set, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize, SCIP_Bool mergemultiples)
Definition: var.c:3929
#define MAX_CLIQUELENGTH
Definition: var.c:13484
SCIP_RETCODE SCIPvarParseTransformed(SCIP_VAR **var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, SCIP_STAT *stat, const char *str, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARCOPY((*varcopy)), SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_VARDATA *vardata, char **endptr, SCIP_Bool *success)
Definition: var.c:2560
SCIP_Real SCIPvarGetUbLP(SCIP_VAR *var, SCIP_SET *set)
Definition: var.c:13022
SCIP_RETCODE SCIPvarColumn(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *prob, SCIP_LP *lp)
Definition: var.c:3579
SCIP_RETCODE SCIPvarChgUbOriginal(SCIP_VAR *var, SCIP_SET *set, SCIP_Real newbound)
Definition: var.c:6626
SCIP_RETCODE SCIPvarChgUbDive(SCIP_VAR *var, SCIP_SET *set, SCIP_LP *lp, SCIP_Real newbound)
Definition: var.c:8339
static void domMerge(SCIP_DOM *dom, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Real *newlb, SCIP_Real *newub)
Definition: var.c:268
SCIP_Real SCIPvarGetAvgInferences(SCIP_VAR *var, SCIP_STAT *stat, SCIP_BRANCHDIR dir)
Definition: var.c:16087
int SCIPvarGetConflictingBdchgDepth(SCIP_VAR *var, SCIP_SET *set, SCIP_BOUNDTYPE boundtype, SCIP_Real bound)
Definition: var.c:17065
static SCIP_RETCODE varEventVarUnlocked(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue)
Definition: var.c:3146
SCIP_Real SCIPvarGetMultaggrUbGlobal(SCIP_VAR *var, SCIP_SET *set)
Definition: var.c:8632
void SCIPvarGetClosestVlb(SCIP_VAR *var, SCIP_SOL *sol, SCIP_SET *set, SCIP_STAT *stat, SCIP_Real *closestvlb, int *closestvlbidx)
Definition: var.c:14143
SCIP_RETCODE SCIPvarChgUbLazy(SCIP_VAR *var, SCIP_SET *set, SCIP_Real lazyub)
Definition: var.c:7492
static SCIP_RETCODE varAddVbound(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_BOUNDTYPE vbtype, SCIP_VAR *vbvar, SCIP_Real vbcoef, SCIP_Real vbconstant)
Definition: var.c:9283
SCIP_Bool SCIPvarPscostThresholdProbabilityTest(SCIP_SET *set, SCIP_STAT *stat, SCIP_VAR *var, SCIP_Real frac, SCIP_Real threshold, SCIP_BRANCHDIR dir, SCIP_CONFIDENCELEVEL clevel)
Definition: var.c:14947
SCIP_RETCODE SCIPdomchgApplyGlobal(SCIP_DOMCHG *domchg, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_Bool *cutoff)
Definition: var.c:1383
SCIP_RETCODE SCIPvarTryAggregateVars(SCIP_SET *set, BMS_BLKMEM *blkmem, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_PRIMAL *primal, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_CLIQUETABLE *cliquetable, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENTQUEUE *eventqueue, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *aggregated)
Definition: var.c:5292
SCIP_RETCODE SCIPboundchgUndo(SCIP_BOUNDCHG *boundchg, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue)
Definition: var.c:825
void SCIPvarMarkDeleted(SCIP_VAR *var)
Definition: var.c:6095
#define MAXIMPLSCLOSURE
Definition: var.c:77
static SCIP_RETCODE varSetName(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_STAT *stat, const char *name)
Definition: var.c:1897
void SCIPvarMergeHistories(SCIP_VAR *targetvar, SCIP_VAR *othervar, SCIP_STAT *stat)
Definition: var.c:4519
static SCIP_RETCODE varEventGholeAdded(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_Real left, SCIP_Real right)
Definition: var.c:6762
static void printHolelist(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, SCIP_HOLELIST *holelist, const char *name)
Definition: var.c:2972
static SCIP_RETCODE varAddUbchginfo(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Real oldbound, SCIP_Real newbound, int depth, int pos, SCIP_VAR *infervar, SCIP_CONS *infercons, SCIP_PROP *inferprop, int inferinfo, SCIP_BOUNDTYPE inferboundtype, SCIP_BOUNDCHGTYPE boundchgtype)
Definition: var.c:554
SCIP_RETCODE SCIPvarCatchEvent(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: var.c:18578
SCIP_RETCODE SCIPvarAddHoleLocal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_Real left, SCIP_Real right, SCIP_Bool *added)
Definition: var.c:9121
SCIP_Bool SCIPvarIsMarkedDeleteGlobalStructures(SCIP_VAR *var)
Definition: var.c:17706
SCIP_RETCODE SCIPdomchgApply(SCIP_DOMCHG *domchg, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, int depth, SCIP_Bool *cutoff)
Definition: var.c:1299
SCIP_RETCODE SCIPvarDelClique(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_CLIQUETABLE *cliquetable, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: var.c:11452
SCIP_RETCODE SCIPvarAggregate(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_PRIMAL *primal, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_CLIQUETABLE *cliquetable, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENTQUEUE *eventqueue, SCIP_VAR *aggvar, SCIP_Real scalar, SCIP_Real constant, SCIP_Bool *infeasible, SCIP_Bool *aggregated)
Definition: var.c:4741
SCIP_Real SCIPvarGetRelaxSol(SCIP_VAR *var, SCIP_SET *set)
Definition: var.c:13943
SCIP_RETCODE SCIPvarDelCliqueFromList(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: var.c:11435
int SCIPbdchgidxGetPos(SCIP_BDCHGIDX *bdchgidx)
Definition: var.c:18630
SCIP_RETCODE SCIPvarChgBdGlobal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_Real newbound, SCIP_BOUNDTYPE boundtype)
Definition: var.c:7518
static SCIP_Bool useValuehistory(SCIP_VAR *var, SCIP_Real value, SCIP_SET *set)
Definition: var.c:15043
static SCIP_Real adjustedUb(SCIP_SET *set, SCIP_VARTYPE vartype, SCIP_Real ub)
Definition: var.c:1588
SCIP_RETCODE SCIPvarAddImplic(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_CLIQUETABLE *cliquetable, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, SCIP_Real implbound, SCIP_Bool transitive, SCIP_Bool *infeasible, int *nbdchgs)
Definition: var.c:10932
SCIP_RETCODE SCIPvarsAddClique(SCIP_VAR **vars, SCIP_Bool *values, int nvars, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_CLIQUE *clique)
Definition: var.c:11375
SCIP_RETCODE SCIPvarMarkDoNotAggr(SCIP_VAR *var)
Definition: var.c:6106
static SCIP_RETCODE varProcessChgBranchFactor(SCIP_VAR *var, SCIP_SET *set, SCIP_Real branchfactor)
Definition: var.c:11516
SCIP_RETCODE SCIPdomchgAddBoundchg(SCIP_DOMCHG **domchg, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_VAR *var, SCIP_Real newbound, SCIP_BOUNDTYPE boundtype, SCIP_BOUNDCHGTYPE boundchgtype, SCIP_Real lpsolval, SCIP_VAR *infervar, SCIP_CONS *infercons, SCIP_PROP *inferprop, int inferinfo, SCIP_BOUNDTYPE inferboundtype)
Definition: var.c:1422
SCIP_RETCODE SCIPvarChgLbLocal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Real newbound)
Definition: var.c:7970
SCIP_RETCODE SCIPvarLoose(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_PROB *prob, SCIP_LP *lp)
Definition: var.c:3613
static SCIP_RETCODE varFreeParents(SCIP_VAR **var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_LP *lp)
Definition: var.c:2671
static SCIP_BDCHGIDX initbdchgidx
Definition: var.c:17007
SCIP_RETCODE SCIPvarChgBranchPriority(SCIP_VAR *var, int branchpriority)
Definition: var.c:11707
static SCIP_RETCODE domchgCreate(SCIP_DOMCHG **domchg, BMS_BLKMEM *blkmem)
Definition: var.c:1039
SCIP_RETCODE SCIPvarMarkDoNotMultaggr(SCIP_VAR *var)
Definition: var.c:6142
static SCIP_RETCODE holelistCreate(SCIP_HOLELIST **holelist, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Real left, SCIP_Real right)
Definition: var.c:152
SCIP_RETCODE SCIPvarAddLocks(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_LOCKTYPE locktype, int addnlocksdown, int addnlocksup)
Definition: var.c:3167
SCIP_RETCODE SCIPvarNegate(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_VAR **negvar)
Definition: var.c:5917
SCIP_Real SCIPvarGetMultaggrUbLocal(SCIP_VAR *var, SCIP_SET *set)
Definition: var.c:8500
SCIP_RETCODE SCIPbdchginfoCreate(SCIP_BDCHGINFO **bdchginfo, BMS_BLKMEM *blkmem, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype, SCIP_Real oldbound, SCIP_Real newbound)
Definition: var.c:16553
static SCIP_RETCODE varAddTransitiveImplic(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_CLIQUETABLE *cliquetable, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, SCIP_Real implbound, SCIP_Bool transitive, SCIP_Bool *infeasible, int *nbdchgs)
Definition: var.c:9792
SCIP_Real SCIPvarGetMinPseudocostScore(SCIP_VAR *var, SCIP_STAT *stat, SCIP_SET *set, SCIP_Real solval)
Definition: var.c:14681
SCIP_RETCODE SCIPvarGetProbvarSum(SCIP_VAR **var, SCIP_SET *set, SCIP_Real *scalar, SCIP_Real *constant)
Definition: var.c:12667
SCIP_RETCODE SCIPvarIncGMIeffSum(SCIP_VAR *var, SCIP_STAT *stat, SCIP_Real gmieff)
Definition: var.c:16419
static void holelistFree(SCIP_HOLELIST **holelist, BMS_BLKMEM *blkmem)
Definition: var.c:176
static SCIP_RETCODE varProcessChgLbGlobal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_Real newbound)
Definition: var.c:6835
static SCIP_RETCODE applyImplic(BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, SCIP_Real implbound, SCIP_Bool *infeasible, int *nbdchgs)
Definition: var.c:9412
SCIP_Real SCIPvarGetLastGMIScore(SCIP_VAR *var, SCIP_STAT *stat)
Definition: var.c:16463
void SCIPvarAdjustUb(SCIP_VAR *var, SCIP_SET *set, SCIP_Real *ub)
Definition: var.c:6534
SCIP_Real SCIPbdchginfoGetRelaxedBound(SCIP_BDCHGINFO *bdchginfo)
Definition: var.c:18819
static SCIP_Real getImplVarRedcost(SCIP_VAR *var, SCIP_SET *set, SCIP_Bool varfixing, SCIP_STAT *stat, SCIP_LP *lp)
Definition: var.c:13435
SCIP_RETCODE SCIPvarChgLbDive(SCIP_VAR *var, SCIP_SET *set, SCIP_LP *lp, SCIP_Real newbound)
Definition: var.c:8249
SCIP_RETCODE SCIPvarMultiaggregate(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_PRIMAL *primal, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_CLIQUETABLE *cliquetable, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENTQUEUE *eventqueue, int naggvars, SCIP_VAR **aggvars, SCIP_Real *scalars, SCIP_Real constant, SCIP_Bool *infeasible, SCIP_Bool *aggregated)
Definition: var.c:5446
static SCIP_Real SCIPvarGetPseudoSol_rec(SCIP_VAR *var)
Definition: var.c:13210
#define MAXABSVBCOEF
Definition: var.c:79
SCIP_Real SCIPvarGetAvgConflictlengthCurrentRun(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: var.c:15424
SCIP_RETCODE SCIPvarChgUbLocal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Real newbound)
Definition: var.c:8097
static SCIP_RETCODE domchgMakeDynamic(SCIP_DOMCHG **domchg, BMS_BLKMEM *blkmem)
Definition: var.c:1109
SCIP_RETCODE SCIPvarAddVlb(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_CLIQUETABLE *cliquetable, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconstant, SCIP_Bool transitive, SCIP_Bool *infeasible, int *nbdchgs)
Definition: var.c:10000
SCIP_RETCODE SCIPvarParseOriginal(SCIP_VAR **var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, SCIP_STAT *stat, const char *str, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARCOPY((*varcopy)), SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_VARDATA *vardata, char **endptr, SCIP_Bool *success)
Definition: var.c:2496
static SCIP_RETCODE parseBounds(SCIP_SET *set, const char *str, char *type, SCIP_Real *lb, SCIP_Real *ub, char **endptr)
Definition: var.c:2304
SCIP_Real SCIPvarGetVSIDSCurrentRun(SCIP_VAR *var, SCIP_STAT *stat, SCIP_BRANCHDIR dir)
Definition: var.c:15948
static void varIncRootboundchgs(SCIP_VAR *var, SCIP_SET *set, SCIP_STAT *stat)
Definition: var.c:6794
void SCIPvarSetNamePointer(SCIP_VAR *var, const char *name)
Definition: var.c:6041
static SCIP_RETCODE holelistDuplicate(SCIP_HOLELIST **target, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_HOLELIST *source)
Definition: var.c:202
SCIP_RETCODE SCIPvarChgName(SCIP_VAR *var, BMS_BLKMEM *blkmem, const char *name)
Definition: var.c:2913
void SCIPvarSetHistory(SCIP_VAR *var, SCIP_HISTORY *history, SCIP_STAT *stat)
Definition: var.c:4535
static SCIP_RETCODE varProcessAddHoleGlobal(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_Real left, SCIP_Real right, SCIP_Bool *added)
Definition: var.c:8745
void SCIPvarSetProbindex(SCIP_VAR *var, int probindex)
Definition: var.c:6026
SCIP_RETCODE SCIPvarAddVub(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_CLIQUETABLE *cliquetable, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_VAR *vubvar, SCIP_Real vubcoef, SCIP_Real vubconstant, SCIP_Bool transitive, SCIP_Bool *infeasible, int *nbdchgs)
Definition: var.c:10475
static SCIP_RETCODE varAddParent(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_VAR *parentvar)
Definition: var.c:2643
SCIP_Real SCIPvarGetMultaggrLbGlobal(SCIP_VAR *var, SCIP_SET *set)
Definition: var.c:8566
SCIP_RETCODE SCIPvarSetRelaxSol(SCIP_VAR *var, SCIP_SET *set, SCIP_RELAXATION *relaxation, SCIP_Real solval, SCIP_Bool updateobj)
Definition: var.c:13882
SCIP_RETCODE SCIPvarChgBranchFactor(SCIP_VAR *var, SCIP_SET *set, SCIP_Real branchfactor)
Definition: var.c:11580
static SCIP_RETCODE boundchgReleaseData(SCIP_BOUNDCHG *boundchg, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_LP *lp)
Definition: var.c:1002
SCIP_Longint SCIPvarGetNActiveConflictsCurrentRun(SCIP_VAR *var, SCIP_STAT *stat, SCIP_BRANCHDIR dir)
Definition: var.c:15335
SCIP_RETCODE SCIPvarAddClique(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_Bool value, SCIP_CLIQUE *clique, SCIP_Bool *infeasible, int *nbdchgs)
Definition: var.c:11290
static SCIP_RETCODE boundchgCaptureData(SCIP_BOUNDCHG *boundchg)
Definition: var.c:970
static SCIP_RETCODE varProcessChgBranchDirection(SCIP_VAR *var, SCIP_BRANCHDIR branchdirection)
Definition: var.c:11771
SCIP_Real SCIPvarGetAvgCutoffsCurrentRun(SCIP_VAR *var, SCIP_STAT *stat, SCIP_BRANCHDIR dir)
Definition: var.c:16332
SCIP_Bool SCIPvarDoNotMultaggr(SCIP_VAR *var)
Definition: var.c:5881
SCIP_RETCODE SCIPvarRemoveCliquesImplicsVbs(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_CLIQUETABLE *cliquetable, SCIP_SET *set, SCIP_Bool irrelevantvar, SCIP_Bool onlyredundant, SCIP_Bool removefromvar)
Definition: var.c:1609
static void varSetProbindex(SCIP_VAR *var, int probindex)
Definition: var.c:6007
static SCIP_RETCODE varAddTransitiveBinaryClosureImplic(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_CLIQUETABLE *cliquetable, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_Bool implvarfixing, SCIP_Bool *infeasible, int *nbdchgs)
Definition: var.c:9719
internal methods for problem variables