1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /*                                                                           */
3 /*                  This file is part of the program and library             */
4 /*         SCIP --- Solving Constraint Integer Programs                      */
5 /*                                                                           */
6 /*    Copyright (C) 2002-2021 Konrad-Zuse-Zentrum                            */
7 /*                            fuer Informationstechnik Berlin                */
8 /*                                                                           */
9 /*  SCIP is distributed under the terms of the ZIB Academic License.         */
10 /*                                                                           */
11 /*  You should have received a copy of the ZIB Academic License              */
12 /*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13 /*                                                                           */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file   var.c
17  * @ingroup OTHER_CFILES
18  * @brief  methods for problem variables
19  * @author Tobias Achterberg
20  * @author Timo Berthold
21  * @author Gerald Gamrath
22  * @author Stefan Heinz
23  * @author Marc Pfetsch
24  * @author Michael Winkler
25  * @author Kati Wolter
26  * @author Stefan Vigerske
27  *
28  * @todo Possibly implement the access of bounds of multi-aggregated variables by accessing the
29  * corresponding linear constraint if it exists. This seems to require some work, since the linear
30  * constraint has to be stored. Moreover, it has even to be created in case the original constraint
31  * was deleted after multi-aggregation, but the bounds of the multi-aggregated variable should be
32  * changed. This has to be done with care in order to not loose the performance gains of
33  * multi-aggregation.
34  */
35 
36 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
37 
38 #include "scip/cons.h"
39 #include "scip/event.h"
40 #include "scip/history.h"
41 #include "scip/implics.h"
42 #include "scip/lp.h"
43 #include "scip/primal.h"
44 #include "scip/prob.h"
45 #include "scip/pub_cons.h"
46 #include "scip/pub_history.h"
47 #include "scip/pub_implics.h"
48 #include "scip/pub_lp.h"
49 #include "scip/pub_message.h"
50 #include "scip/pub_misc.h"
51 #include "scip/pub_misc_sort.h"
52 #include "scip/pub_prop.h"
53 #include "scip/pub_var.h"
54 #include "scip/relax.h"
55 #include "scip/set.h"
56 #include "scip/sol.h"
57 #include "scip/stat.h"
58 #include "scip/struct_event.h"
59 #include "scip/struct_lp.h"
60 #include "scip/struct_prob.h"
61 #include "scip/struct_set.h"
62 #include "scip/struct_stat.h"
63 #include "scip/struct_var.h"
64 #include "scip/tree.h"
65 #include "scip/var.h"
66 #include <string.h>
67 
68 #define MAXIMPLSCLOSURE 100  /**< maximal number of descendants of implied variable for building closure
69                               *   in implication graph */
70 #define MAXABSVBCOEF    1e+5 /**< maximal absolute coefficient in variable bounds added due to implications */
71 
72 /*
73  * hole, holelist, and domain methods
74  */
75 
76 /** creates a new holelist element */
77 static
holelistCreate(SCIP_HOLELIST ** holelist,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_Real left,SCIP_Real right)78 SCIP_RETCODE holelistCreate(
79    SCIP_HOLELIST**       holelist,           /**< pointer to holelist to create */
80    BMS_BLKMEM*           blkmem,             /**< block memory for target holelist */
81    SCIP_SET*             set,                /**< global SCIP settings */
82    SCIP_Real             left,               /**< left bound of open interval in new hole */
83    SCIP_Real             right               /**< right bound of open interval in new hole */
84    )
85 {
86    assert(holelist != NULL);
87    assert(blkmem != NULL);
88    assert(SCIPsetIsLT(set, left, right));
89 
90    SCIPsetDebugMsg(set, "create hole list element (%.15g,%.15g) in blkmem %p\n", left, right, (void*)blkmem);
91 
92    SCIP_ALLOC( BMSallocBlockMemory(blkmem, holelist) );
93    (*holelist)->hole.left = left;
94    (*holelist)->hole.right = right;
95    (*holelist)->next = NULL;
96 
97    return SCIP_OKAY;
98 }
99 
100 /** frees all elements in the holelist */
101 static
holelistFree(SCIP_HOLELIST ** holelist,BMS_BLKMEM * blkmem)102 void holelistFree(
103    SCIP_HOLELIST**       holelist,           /**< pointer to holelist to free */
104    BMS_BLKMEM*           blkmem              /**< block memory for target holelist */
105    )
106 {
107    assert(holelist != NULL);
108    assert(blkmem != NULL);
109 
110    while( *holelist != NULL )
111    {
112       SCIP_HOLELIST* next;
113 
114       SCIPdebugMessage("free hole list element (%.15g,%.15g) in blkmem %p\n",
115          (*holelist)->hole.left, (*holelist)->hole.right, (void*)blkmem);
116 
117       next = (*holelist)->next;
118       BMSfreeBlockMemory(blkmem, holelist);
119       assert(*holelist == NULL);
120 
121       *holelist = next;
122    }
123    assert(*holelist == NULL);
124 }
125 
126 /** duplicates a list of holes */
127 static
holelistDuplicate(SCIP_HOLELIST ** target,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_HOLELIST * source)128 SCIP_RETCODE holelistDuplicate(
129    SCIP_HOLELIST**       target,             /**< pointer to target holelist */
130    BMS_BLKMEM*           blkmem,             /**< block memory for target holelist */
131    SCIP_SET*             set,                /**< global SCIP settings */
132    SCIP_HOLELIST*        source              /**< holelist to duplicate */
133    )
134 {
135    assert(target != NULL);
136 
137    while( source != NULL )
138    {
139       assert(source->next == NULL || SCIPsetIsGE(set, source->next->hole.left, source->hole.right));
140       SCIP_CALL( holelistCreate(target, blkmem, set, source->hole.left, source->hole.right) );
141       source = source->next;
142       target = &(*target)->next;
143    }
144 
145    return SCIP_OKAY;
146 }
147 
148 /** adds a hole to the domain */
149 static
domAddHole(SCIP_DOM * dom,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_Real left,SCIP_Real right,SCIP_Bool * added)150 SCIP_RETCODE domAddHole(
151    SCIP_DOM*             dom,                /**< domain to add hole to */
152    BMS_BLKMEM*           blkmem,             /**< block memory */
153    SCIP_SET*             set,                /**< global SCIP settings */
154    SCIP_Real             left,               /**< left bound of open interval in new hole */
155    SCIP_Real             right,              /**< right bound of open interval in new hole */
156    SCIP_Bool*            added               /**< pointer to store whether the hole was added (variable didn't had that hole before), or NULL */
157    )
158 {
159    SCIP_HOLELIST** insertpos;
160    SCIP_HOLELIST* next;
161 
162    assert(dom != NULL);
163    assert(added != NULL);
164 
165    /* search for the position of the new hole */
166    insertpos = &dom->holelist;
167    while( *insertpos != NULL && (*insertpos)->hole.left < left )
168       insertpos = &(*insertpos)->next;
169 
170    /* check if new hole already exists in the hole list or is a sub hole of an existing one */
171    if( *insertpos != NULL && (*insertpos)->hole.left == left && (*insertpos)->hole.right >= right )  /*lint !e777 */
172    {
173       SCIPsetDebugMsg(set, "new hole (%.15g,%.15g) is redundant through known hole (%.15g,%.15g)\n",
174          left, right, (*insertpos)->hole.left, (*insertpos)->hole.right);
175       *added = FALSE;
176       return SCIP_OKAY;
177    }
178 
179    /* add hole */
180    *added = TRUE;
181 
182    next = *insertpos;
183    SCIP_CALL( holelistCreate(insertpos, blkmem, set, left, right) );
184    (*insertpos)->next = next;
185 
186    return SCIP_OKAY;
187 }
188 
189 /** merges overlapping holes into single holes, computes and moves lower and upper bound, respectively */
190 /**@todo  the domMerge() method is currently called if a lower or an upper bound locally or globally changed; this could
191  *        be more efficient if performed with the knowledge if it was a lower or an upper bound which triggered this
192  *        merge */
193 static
domMerge(SCIP_DOM * dom,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_Real * newlb,SCIP_Real * newub)194 void domMerge(
195    SCIP_DOM*             dom,                /**< domain to merge */
196    BMS_BLKMEM*           blkmem,             /**< block memory */
197    SCIP_SET*             set,                /**< global SCIP settings */
198    SCIP_Real*            newlb,              /**< pointer to store new lower bound */
199    SCIP_Real*            newub               /**< pointer to store new upper bound */
200    )
201 {
202    SCIP_HOLELIST** holelistptr;
203    SCIP_HOLELIST** lastnextptr;
204    SCIP_Real* lastrightptr;
205 
206    assert(dom != NULL);
207    assert(SCIPsetIsLE(set, dom->lb, dom->ub));
208 
209 #ifndef NDEBUG
210    {
211       /* check if the holelist is sorted w.r.t. to the left interval bounds */
212       SCIP_Real lastleft;
213 
214       holelistptr = &dom->holelist;
215 
216       lastleft = -SCIPsetInfinity(set);
217 
218       while( *holelistptr != NULL )
219       {
220          if( (*holelistptr)->next != NULL )
221          {
222             assert( SCIPsetIsLE(set, lastleft, (*holelistptr)->hole.left) );
223             lastleft = (*holelistptr)->hole.left;
224          }
225 
226          holelistptr = &(*holelistptr)->next;
227       }
228    }
229 #endif
230 
231    SCIPsetDebugMsg(set, "merge hole list\n");
232 
233    holelistptr = &dom->holelist;
234    lastrightptr = &dom->lb;  /* lower bound is the right bound of the hole (-infinity,lb) */
235    lastnextptr = holelistptr;
236 
237    while( *holelistptr != NULL )
238    {
239       SCIPsetDebugMsg(set, "check hole (%.15g,%.15g) last right interval was <%.15g>\n", (*holelistptr)->hole.left, (*holelistptr)->hole.right, *lastrightptr);
240 
241       /* check that the hole is not empty */
242       assert(SCIPsetIsLT(set, (*holelistptr)->hole.left, (*holelistptr)->hole.right));
243 
244       if( SCIPsetIsGE(set, (*holelistptr)->hole.left, dom->ub) )
245       {
246          /* the remaining holes start behind the upper bound: remove them */
247          SCIPsetDebugMsg(set, "remove remaining hole since upper bound <%.15g> is less then the left hand side of the current hole\n", dom->ub);
248          holelistFree(holelistptr, blkmem);
249          assert(*holelistptr == NULL);
250 
251          /* unlink this hole from the previous hole */
252          *lastnextptr = NULL;
253       }
254       else if( SCIPsetIsGT(set, (*holelistptr)->hole.right, dom->ub) )
255       {
256          /* the hole overlaps the upper bound: decrease upper bound, remove this hole and all remaining holes */
257          SCIPsetDebugMsg(set, "upper bound <%.15g> lays in current hole; store new upper bound and remove this and all remaining holes\n", dom->ub);
258 
259          assert(SCIPsetIsLT(set, (*holelistptr)->hole.left, dom->ub));
260 
261          /* adjust upper bound */
262          dom->ub = (*holelistptr)->hole.left;
263 
264          if(newub != NULL )
265             *newub = (*holelistptr)->hole.left;
266 
267          /* remove remaining hole list */
268          holelistFree(holelistptr, blkmem);
269          assert(*holelistptr == NULL);
270 
271          /* unlink this hole from the previous hole */
272          *lastnextptr = NULL;
273       }
274       else if( SCIPsetIsGT(set, *lastrightptr, (*holelistptr)->hole.left) )
275       {
276          /* the right bound of the last hole is greater than the left bound of this hole: increase the right bound of
277           * the last hole, delete this hole */
278          SCIP_HOLELIST* nextholelist;
279 
280          if( SCIPsetIsEQ(set, *lastrightptr, dom->lb ) )
281          {
282             /* the reason for the overlap results from the lower bound hole (-infinity,lb); therefore, we can increase
283              * the lower bound */
284             SCIPsetDebugMsg(set, "lower bound <%.15g> lays in current hole; store new lower bound and remove hole\n", dom->lb);
285             *lastrightptr = MAX(*lastrightptr, (*holelistptr)->hole.right);
286 
287             /* adjust lower bound */
288             dom->lb = *lastrightptr;
289 
290             if(newlb != NULL )
291                *newlb = *lastrightptr;
292          }
293          else
294          {
295             SCIPsetDebugMsg(set, "current hole overlaps with the previous one (...,%.15g); merge to (...,%.15g)\n",
296                *lastrightptr, MAX(*lastrightptr, (*holelistptr)->hole.right) );
297             *lastrightptr = MAX(*lastrightptr, (*holelistptr)->hole.right);
298          }
299          nextholelist = (*holelistptr)->next;
300          (*holelistptr)->next = NULL;
301          holelistFree(holelistptr, blkmem);
302 
303          /* connect the linked list after removing the hole */
304          *lastnextptr = nextholelist;
305 
306          /* get next hole */
307          *holelistptr = nextholelist;
308       }
309       else
310       {
311          /* the holes do not overlap: update lastholelist and lastrightptr */
312          lastrightptr = &(*holelistptr)->hole.right;
313          lastnextptr = &(*holelistptr)->next;
314 
315          /* get next hole */
316          holelistptr = &(*holelistptr)->next;
317       }
318    }
319 
320 #ifndef NDEBUG
321    {
322       /* check that holes are merged */
323       SCIP_Real lastright;
324 
325       lastright = dom->lb; /* lower bound is the right bound of the hole (-infinity,lb) */
326       holelistptr = &dom->holelist;
327 
328       while( *holelistptr != NULL )
329       {
330          /* check the the last right interval is smaller or equal to the current left interval (none overlapping) */
331          assert( SCIPsetIsLE(set, lastright, (*holelistptr)->hole.left) );
332 
333          /* check the hole property (check that the hole is not empty) */
334          assert( SCIPsetIsLT(set, (*holelistptr)->hole.left, (*holelistptr)->hole.right) );
335          lastright = (*holelistptr)->hole.right;
336 
337          /* get next hole */
338          holelistptr = &(*holelistptr)->next;
339       }
340 
341       /* check the the last right interval is smaller or equal to the upper bound (none overlapping) */
342       assert( SCIPsetIsLE(set, lastright, dom->ub) );
343    }
344 #endif
345 }
346 
347 /*
348  * domain change methods
349  */
350 
351 /** ensures, that bound change info array for lower bound changes can store at least num entries */
352 static
varEnsureLbchginfosSize(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)353 SCIP_RETCODE varEnsureLbchginfosSize(
354    SCIP_VAR*             var,                /**< problem variable */
355    BMS_BLKMEM*           blkmem,             /**< block memory */
356    SCIP_SET*             set,                /**< global SCIP settings */
357    int                   num                 /**< minimum number of entries to store */
358    )
359 {
360    assert(var != NULL);
361    assert(var->nlbchginfos <= var->lbchginfossize);
362    assert(SCIPvarIsTransformed(var));
363 
364    if( num > var->lbchginfossize )
365    {
366       int newsize;
367 
368       newsize = SCIPsetCalcMemGrowSize(set, num);
369       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->lbchginfos, var->lbchginfossize, newsize) );
370       var->lbchginfossize = newsize;
371    }
372    assert(num <= var->lbchginfossize);
373 
374    return SCIP_OKAY;
375 }
376 
377 /** ensures, that bound change info array for upper bound changes can store at least num entries */
378 static
varEnsureUbchginfosSize(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)379 SCIP_RETCODE varEnsureUbchginfosSize(
380    SCIP_VAR*             var,                /**< problem variable */
381    BMS_BLKMEM*           blkmem,             /**< block memory */
382    SCIP_SET*             set,                /**< global SCIP settings */
383    int                   num                 /**< minimum number of entries to store */
384    )
385 {
386    assert(var != NULL);
387    assert(var->nubchginfos <= var->ubchginfossize);
388    assert(SCIPvarIsTransformed(var));
389 
390    if( num > var->ubchginfossize )
391    {
392       int newsize;
393 
394       newsize = SCIPsetCalcMemGrowSize(set, num);
395       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->ubchginfos, var->ubchginfossize, newsize) );
396       var->ubchginfossize = newsize;
397    }
398    assert(num <= var->ubchginfossize);
399 
400    return SCIP_OKAY;
401 }
402 
403 /** adds domain change info to the variable's lower bound change info array */
404 static
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)405 SCIP_RETCODE varAddLbchginfo(
406    SCIP_VAR*             var,                /**< problem variable */
407    BMS_BLKMEM*           blkmem,             /**< block memory */
408    SCIP_SET*             set,                /**< global SCIP settings */
409    SCIP_Real             oldbound,           /**< old value for bound */
410    SCIP_Real             newbound,           /**< new value for bound */
411    int                   depth,              /**< depth in the tree, where the bound change takes place */
412    int                   pos,                /**< position of the bound change in its bound change array */
413    SCIP_VAR*             infervar,           /**< variable that was changed (parent of var, or var itself) */
414    SCIP_CONS*            infercons,          /**< constraint that infered this bound change, or NULL */
415    SCIP_PROP*            inferprop,          /**< propagator that deduced the bound change, or NULL */
416    int                   inferinfo,          /**< user information for inference to help resolving the conflict */
417    SCIP_BOUNDTYPE        inferboundtype,     /**< type of bound for inference var: lower or upper bound */
418    SCIP_BOUNDCHGTYPE     boundchgtype        /**< bound change type: branching decision or infered bound change */
419    )
420 {
421    assert(var != NULL);
422    assert(SCIPsetIsLT(set, oldbound, newbound));
423    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, oldbound));
424    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
425    assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, oldbound, 0.0));
426    assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, 1.0));
427    assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
428    assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
429    assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
430 
431    SCIPsetDebugMsg(set, "adding lower bound change info to var <%s>[%g,%g]: depth=%d, pos=%d, infer%s=<%s>, inferinfo=%d, %g -> %g\n",
432       SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, depth, pos, infercons != NULL ? "cons" : "prop",
433       infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo,
434       oldbound, newbound);
435 
436    SCIP_CALL( varEnsureLbchginfosSize(var, blkmem, set, var->nlbchginfos+1) );
437    var->lbchginfos[var->nlbchginfos].oldbound = oldbound;
438    var->lbchginfos[var->nlbchginfos].newbound = newbound;
439    var->lbchginfos[var->nlbchginfos].var = var;
440    var->lbchginfos[var->nlbchginfos].bdchgidx.depth = depth;
441    var->lbchginfos[var->nlbchginfos].bdchgidx.pos = pos;
442    var->lbchginfos[var->nlbchginfos].pos = var->nlbchginfos; /*lint !e732*/
443    var->lbchginfos[var->nlbchginfos].boundchgtype = boundchgtype; /*lint !e641*/
444    var->lbchginfos[var->nlbchginfos].boundtype = SCIP_BOUNDTYPE_LOWER; /*lint !e641*/
445    var->lbchginfos[var->nlbchginfos].redundant = FALSE;
446    var->lbchginfos[var->nlbchginfos].inferboundtype = inferboundtype; /*lint !e641*/
447    var->lbchginfos[var->nlbchginfos].inferencedata.var = infervar;
448    var->lbchginfos[var->nlbchginfos].inferencedata.info = inferinfo;
449 
450    /**@note The "pos" data member of the bound change info has a size of 27 bits */
451    assert(var->nlbchginfos < 1 << 27);
452 
453    switch( boundchgtype )
454    {
455    case SCIP_BOUNDCHGTYPE_BRANCHING:
456       break;
457    case SCIP_BOUNDCHGTYPE_CONSINFER:
458       assert(infercons != NULL);
459       var->lbchginfos[var->nlbchginfos].inferencedata.reason.cons = infercons;
460       break;
461    case SCIP_BOUNDCHGTYPE_PROPINFER:
462       var->lbchginfos[var->nlbchginfos].inferencedata.reason.prop = inferprop;
463       break;
464    default:
465       SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
466       return SCIP_INVALIDDATA;
467    }
468 
469    var->nlbchginfos++;
470 
471    assert(var->nlbchginfos < 2
472       || SCIPbdchgidxIsEarlier(&var->lbchginfos[var->nlbchginfos-2].bdchgidx,
473          &var->lbchginfos[var->nlbchginfos-1].bdchgidx));
474 
475    return SCIP_OKAY;
476 }
477 
478 /** adds domain change info to the variable's upper bound change info array */
479 static
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)480 SCIP_RETCODE varAddUbchginfo(
481    SCIP_VAR*             var,                /**< problem variable */
482    BMS_BLKMEM*           blkmem,             /**< block memory */
483    SCIP_SET*             set,                /**< global SCIP settings */
484    SCIP_Real             oldbound,           /**< old value for bound */
485    SCIP_Real             newbound,           /**< new value for bound */
486    int                   depth,              /**< depth in the tree, where the bound change takes place */
487    int                   pos,                /**< position of the bound change in its bound change array */
488    SCIP_VAR*             infervar,           /**< variable that was changed (parent of var, or var itself) */
489    SCIP_CONS*            infercons,          /**< constraint that infered this bound change, or NULL */
490    SCIP_PROP*            inferprop,          /**< propagator that deduced the bound change, or NULL */
491    int                   inferinfo,          /**< user information for inference to help resolving the conflict */
492    SCIP_BOUNDTYPE        inferboundtype,     /**< type of bound for inference var: lower or upper bound */
493    SCIP_BOUNDCHGTYPE     boundchgtype        /**< bound change type: branching decision or infered bound change */
494    )
495 {
496    assert(var != NULL);
497    assert(SCIPsetIsGT(set, oldbound, newbound));
498    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, oldbound));
499    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
500    assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, oldbound, 1.0));
501    assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, 0.0));
502    assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
503    assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
504    assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
505 
506    SCIPsetDebugMsg(set, "adding upper bound change info to var <%s>[%g,%g]: depth=%d, pos=%d, infer%s=<%s>, inferinfo=%d, %g -> %g\n",
507       SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, depth, pos, infercons != NULL ? "cons" : "prop",
508       infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo,
509       oldbound, newbound);
510 
511    SCIP_CALL( varEnsureUbchginfosSize(var, blkmem, set, var->nubchginfos+1) );
512    var->ubchginfos[var->nubchginfos].oldbound = oldbound;
513    var->ubchginfos[var->nubchginfos].newbound = newbound;
514    var->ubchginfos[var->nubchginfos].var = var;
515    var->ubchginfos[var->nubchginfos].bdchgidx.depth = depth;
516    var->ubchginfos[var->nubchginfos].bdchgidx.pos = pos;
517    var->ubchginfos[var->nubchginfos].pos = var->nubchginfos; /*lint !e732*/
518    var->ubchginfos[var->nubchginfos].boundchgtype = boundchgtype; /*lint !e641*/
519    var->ubchginfos[var->nubchginfos].boundtype = SCIP_BOUNDTYPE_UPPER; /*lint !e641*/
520    var->ubchginfos[var->nubchginfos].redundant = FALSE;
521    var->ubchginfos[var->nubchginfos].inferboundtype = inferboundtype; /*lint !e641*/
522    var->ubchginfos[var->nubchginfos].inferencedata.var = infervar;
523    var->ubchginfos[var->nubchginfos].inferencedata.info = inferinfo;
524 
525    /**@note The "pos" data member of the bound change info has a size of 27 bits */
526    assert(var->nubchginfos < 1 << 27);
527 
528    switch( boundchgtype )
529    {
530    case SCIP_BOUNDCHGTYPE_BRANCHING:
531       break;
532    case SCIP_BOUNDCHGTYPE_CONSINFER:
533       assert(infercons != NULL);
534       var->ubchginfos[var->nubchginfos].inferencedata.reason.cons = infercons;
535       break;
536    case SCIP_BOUNDCHGTYPE_PROPINFER:
537       var->ubchginfos[var->nubchginfos].inferencedata.reason.prop = inferprop;
538       break;
539    default:
540       SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
541       return SCIP_INVALIDDATA;
542    }
543 
544    var->nubchginfos++;
545 
546    assert(var->nubchginfos < 2
547       || SCIPbdchgidxIsEarlier(&var->ubchginfos[var->nubchginfos-2].bdchgidx,
548          &var->ubchginfos[var->nubchginfos-1].bdchgidx));
549 
550    return SCIP_OKAY;
551 }
552 
553 /** applies single bound change */
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)554 SCIP_RETCODE SCIPboundchgApply(
555    SCIP_BOUNDCHG*        boundchg,           /**< bound change to apply */
556    BMS_BLKMEM*           blkmem,             /**< block memory */
557    SCIP_SET*             set,                /**< global SCIP settings */
558    SCIP_STAT*            stat,               /**< problem statistics */
559    SCIP_LP*              lp,                 /**< current LP data */
560    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
561    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
562    int                   depth,              /**< depth in the tree, where the bound change takes place */
563    int                   pos,                /**< position of the bound change in its bound change array */
564    SCIP_Bool*            cutoff              /**< pointer to store whether an infeasible bound change was detected */
565    )
566 {
567    SCIP_VAR* var;
568 
569    assert(boundchg != NULL);
570    assert(stat != NULL);
571    assert(depth > 0);
572    assert(pos >= 0);
573    assert(cutoff != NULL);
574 
575    *cutoff = FALSE;
576 
577    /* ignore redundant bound changes */
578    if( boundchg->redundant )
579       return SCIP_OKAY;
580 
581    var = boundchg->var;
582    assert(var != NULL);
583    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
584    assert(!SCIPvarIsIntegral(var) || SCIPsetIsIntegral(set, boundchg->newbound));
585 
586    /* apply bound change */
587    switch( boundchg->boundtype )
588    {
589    case SCIP_BOUNDTYPE_LOWER:
590       /* check, if the bound change is still active (could be replaced by inference due to repropagation of higher node) */
591       if( SCIPsetIsGT(set, boundchg->newbound, var->locdom.lb) )
592       {
593          if( SCIPsetIsLE(set, boundchg->newbound, var->locdom.ub) )
594          {
595             /* add the bound change info to the variable's bound change info array */
596             switch( boundchg->boundchgtype )
597             {
598             case SCIP_BOUNDCHGTYPE_BRANCHING:
599                SCIPsetDebugMsg(set, " -> branching: new lower bound of <%s>[%g,%g]: %g\n",
600                   SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
601                SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
602                      NULL, NULL, NULL, 0, SCIP_BOUNDTYPE_LOWER, SCIP_BOUNDCHGTYPE_BRANCHING) );
603                stat->lastbranchvar = var;
604                stat->lastbranchdir = SCIP_BRANCHDIR_UPWARDS;
605                stat->lastbranchvalue = boundchg->newbound;
606                break;
607 
608             case SCIP_BOUNDCHGTYPE_CONSINFER:
609                assert(boundchg->data.inferencedata.reason.cons != NULL);
610                SCIPsetDebugMsg(set, " -> constraint <%s> inference: new lower bound of <%s>[%g,%g]: %g\n",
611                   SCIPconsGetName(boundchg->data.inferencedata.reason.cons),
612                   SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
613                SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
614                      boundchg->data.inferencedata.var, boundchg->data.inferencedata.reason.cons, NULL,
615                      boundchg->data.inferencedata.info,
616                      (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_CONSINFER) );
617                break;
618 
619             case SCIP_BOUNDCHGTYPE_PROPINFER:
620                SCIPsetDebugMsg(set, " -> propagator <%s> inference: new lower bound of <%s>[%g,%g]: %g\n",
621                   boundchg->data.inferencedata.reason.prop != NULL
622                   ? SCIPpropGetName(boundchg->data.inferencedata.reason.prop) : "-",
623                   SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
624                SCIP_CALL( varAddLbchginfo(var, blkmem, set, var->locdom.lb, boundchg->newbound, depth, pos,
625                      boundchg->data.inferencedata.var, NULL, boundchg->data.inferencedata.reason.prop,
626                      boundchg->data.inferencedata.info,
627                      (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_PROPINFER) );
628                break;
629 
630             default:
631                SCIPerrorMessage("invalid bound change type %d\n", boundchg->boundchgtype);
632                return SCIP_INVALIDDATA;
633             }
634 
635             /* change local bound of variable */
636             SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, boundchg->newbound) );
637          }
638          else
639          {
640             SCIPsetDebugMsg(set, " -> cutoff: new lower bound of <%s>[%g,%g]: %g\n",
641                SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
642             *cutoff = TRUE;
643             boundchg->redundant = TRUE; /* bound change has not entered the lbchginfos array of the variable! */
644          }
645       }
646       else
647       {
648          /* mark bound change to be inactive */
649          SCIPsetDebugMsg(set, " -> inactive %s: new lower bound of <%s>[%g,%g]: %g\n",
650             (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
651             SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
652          boundchg->redundant = TRUE;
653       }
654       break;
655 
656    case SCIP_BOUNDTYPE_UPPER:
657       /* check, if the bound change is still active (could be replaced by inference due to repropagation of higher node) */
658       if( SCIPsetIsLT(set, boundchg->newbound, var->locdom.ub) )
659       {
660          if( SCIPsetIsGE(set, boundchg->newbound, var->locdom.lb) )
661          {
662             /* add the bound change info to the variable's bound change info array */
663             switch( boundchg->boundchgtype )
664             {
665             case SCIP_BOUNDCHGTYPE_BRANCHING:
666                SCIPsetDebugMsg(set, " -> branching: new upper bound of <%s>[%g,%g]: %g\n",
667                   SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
668                SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
669                      NULL, NULL, NULL, 0, SCIP_BOUNDTYPE_UPPER, SCIP_BOUNDCHGTYPE_BRANCHING) );
670                stat->lastbranchvar = var;
671                stat->lastbranchdir = SCIP_BRANCHDIR_DOWNWARDS;
672                stat->lastbranchvalue = boundchg->newbound;
673                break;
674 
675             case SCIP_BOUNDCHGTYPE_CONSINFER:
676                assert(boundchg->data.inferencedata.reason.cons != NULL);
677                SCIPsetDebugMsg(set, " -> constraint <%s> inference: new upper bound of <%s>[%g,%g]: %g\n",
678                   SCIPconsGetName(boundchg->data.inferencedata.reason.cons),
679                   SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
680                SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
681                      boundchg->data.inferencedata.var, boundchg->data.inferencedata.reason.cons, NULL,
682                      boundchg->data.inferencedata.info,
683                      (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_CONSINFER) );
684                break;
685 
686             case SCIP_BOUNDCHGTYPE_PROPINFER:
687                SCIPsetDebugMsg(set, " -> propagator <%s> inference: new upper bound of <%s>[%g,%g]: %g\n",
688                   boundchg->data.inferencedata.reason.prop != NULL
689                   ? SCIPpropGetName(boundchg->data.inferencedata.reason.prop) : "-",
690                   SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
691                SCIP_CALL( varAddUbchginfo(var, blkmem, set, var->locdom.ub, boundchg->newbound, depth, pos,
692                      boundchg->data.inferencedata.var, NULL, boundchg->data.inferencedata.reason.prop,
693                      boundchg->data.inferencedata.info,
694                      (SCIP_BOUNDTYPE)(boundchg->inferboundtype), SCIP_BOUNDCHGTYPE_PROPINFER) );
695                break;
696 
697             default:
698                SCIPerrorMessage("invalid bound change type %d\n", boundchg->boundchgtype);
699                return SCIP_INVALIDDATA;
700             }
701 
702             /* change local bound of variable */
703             SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, boundchg->newbound) );
704          }
705          else
706          {
707             SCIPsetDebugMsg(set, " -> cutoff: new upper bound of <%s>[%g,%g]: %g\n",
708                SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
709             *cutoff = TRUE;
710             boundchg->redundant = TRUE; /* bound change has not entered the ubchginfos array of the variable! */
711          }
712       }
713       else
714       {
715          /* mark bound change to be inactive */
716          SCIPsetDebugMsg(set, " -> inactive %s: new upper bound of <%s>[%g,%g]: %g\n",
717             (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
718             SCIPvarGetName(var), var->locdom.lb, var->locdom.ub, boundchg->newbound);
719          boundchg->redundant = TRUE;
720       }
721       break;
722 
723    default:
724       SCIPerrorMessage("unknown bound type\n");
725       return SCIP_INVALIDDATA;
726    }
727 
728    /* update the branching and inference history */
729    if( !boundchg->applied && !boundchg->redundant )
730    {
731       assert(var == boundchg->var);
732 
733       if( (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING )
734       {
735          SCIP_CALL( SCIPvarIncNBranchings(var, blkmem, set, stat,
736                (SCIP_BOUNDTYPE)boundchg->boundtype == SCIP_BOUNDTYPE_LOWER
737                ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS, boundchg->newbound, depth) );
738       }
739       else if( stat->lastbranchvar != NULL )
740       {
741          /**@todo if last branching variable is unknown, retrieve it from the nodes' boundchg arrays */
742          SCIP_CALL( SCIPvarIncInferenceSum(stat->lastbranchvar, blkmem, set, stat, stat->lastbranchdir, stat->lastbranchvalue, 1.0) );
743       }
744       boundchg->applied = TRUE;
745    }
746 
747    return SCIP_OKAY;
748 }
749 
750 /** undoes single bound change */
SCIPboundchgUndo(SCIP_BOUNDCHG * boundchg,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue)751 SCIP_RETCODE SCIPboundchgUndo(
752    SCIP_BOUNDCHG*        boundchg,           /**< bound change to remove */
753    BMS_BLKMEM*           blkmem,             /**< block memory */
754    SCIP_SET*             set,                /**< global SCIP settings */
755    SCIP_STAT*            stat,               /**< problem statistics */
756    SCIP_LP*              lp,                 /**< current LP data */
757    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
758    SCIP_EVENTQUEUE*      eventqueue          /**< event queue */
759    )
760 {
761    SCIP_VAR* var;
762 
763    assert(boundchg != NULL);
764    assert(stat != NULL);
765 
766    /* ignore redundant bound changes */
767    if( boundchg->redundant )
768       return SCIP_OKAY;
769 
770    var = boundchg->var;
771    assert(var != NULL);
772    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
773 
774    /* undo bound change: apply the previous bound change of variable */
775    switch( boundchg->boundtype )
776    {
777    case SCIP_BOUNDTYPE_LOWER:
778       var->nlbchginfos--;
779       assert(var->nlbchginfos >= 0);
780       assert(var->lbchginfos != NULL);
781       assert( SCIPsetIsFeasEQ(set, var->lbchginfos[var->nlbchginfos].newbound, var->locdom.lb) ); /*lint !e777*/
782       assert( SCIPsetIsFeasLE(set, boundchg->newbound, var->locdom.lb) ); /* current lb might be larger to intermediate global bound change */
783 
784       SCIPsetDebugMsg(set, "removed lower bound change info of var <%s>[%g,%g]: depth=%d, pos=%d, %g -> %g\n",
785          SCIPvarGetName(var), var->locdom.lb, var->locdom.ub,
786          var->lbchginfos[var->nlbchginfos].bdchgidx.depth, var->lbchginfos[var->nlbchginfos].bdchgidx.pos,
787          var->lbchginfos[var->nlbchginfos].oldbound, var->lbchginfos[var->nlbchginfos].newbound);
788 
789       /* reinstall the previous local bound */
790       SCIP_CALL( SCIPvarChgLbLocal(boundchg->var, blkmem, set, stat, lp, branchcand, eventqueue,
791             var->lbchginfos[var->nlbchginfos].oldbound) );
792 
793       /* in case all bound changes are removed the local bound should match the global bound */
794       assert(var->nlbchginfos > 0 || SCIPsetIsFeasEQ(set, var->locdom.lb, var->glbdom.lb));
795 
796       break;
797 
798    case SCIP_BOUNDTYPE_UPPER:
799       var->nubchginfos--;
800       assert(var->nubchginfos >= 0);
801       assert(var->ubchginfos != NULL);
802       assert( SCIPsetIsFeasEQ(set, var->ubchginfos[var->nubchginfos].newbound, var->locdom.ub) ); /*lint !e777*/
803       assert( SCIPsetIsFeasGE(set, boundchg->newbound, var->locdom.ub) ); /* current ub might be smaller to intermediate global bound change */
804 
805       SCIPsetDebugMsg(set, "removed upper bound change info of var <%s>[%g,%g]: depth=%d, pos=%d, %g -> %g\n",
806          SCIPvarGetName(var), var->locdom.lb, var->locdom.ub,
807          var->ubchginfos[var->nubchginfos].bdchgidx.depth, var->ubchginfos[var->nubchginfos].bdchgidx.pos,
808          var->ubchginfos[var->nubchginfos].oldbound, var->ubchginfos[var->nubchginfos].newbound);
809 
810       /* reinstall the previous local bound */
811       SCIP_CALL( SCIPvarChgUbLocal(boundchg->var, blkmem, set, stat, lp, branchcand, eventqueue,
812             var->ubchginfos[var->nubchginfos].oldbound) );
813 
814       /* in case all bound changes are removed the local bound should match the global bound */
815       assert(var->nubchginfos > 0 || SCIPsetIsFeasEQ(set, var->locdom.ub, var->glbdom.ub));
816 
817       break;
818 
819    default:
820       SCIPerrorMessage("unknown bound type\n");
821       return SCIP_INVALIDDATA;
822    }
823 
824    /* update last branching variable */
825    if( (SCIP_BOUNDCHGTYPE)boundchg->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING )
826    {
827       stat->lastbranchvar = NULL;
828       stat->lastbranchvalue = SCIP_UNKNOWN;
829    }
830 
831    return SCIP_OKAY;
832 }
833 
834 /** applies single bound change to the global problem by changing the global bound of the corresponding variable */
835 static
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)836 SCIP_RETCODE boundchgApplyGlobal(
837    SCIP_BOUNDCHG*        boundchg,           /**< bound change to apply */
838    BMS_BLKMEM*           blkmem,             /**< block memory */
839    SCIP_SET*             set,                /**< global SCIP settings */
840    SCIP_STAT*            stat,               /**< problem statistics */
841    SCIP_LP*              lp,                 /**< current LP data */
842    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
843    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
844    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
845    SCIP_Bool*            cutoff              /**< pointer to store whether an infeasible bound change was detected */
846    )
847 {
848    SCIP_VAR* var;
849    SCIP_Real newbound;
850    SCIP_BOUNDTYPE boundtype;
851 
852    assert(boundchg != NULL);
853    assert(cutoff != NULL);
854 
855    *cutoff = FALSE;
856 
857    /* ignore redundant bound changes */
858    if( boundchg->redundant )
859       return SCIP_OKAY;
860 
861    var = SCIPboundchgGetVar(boundchg);
862    newbound = SCIPboundchgGetNewbound(boundchg);
863    boundtype = SCIPboundchgGetBoundtype(boundchg);
864 
865    /* check if the bound change is redundant which can happen due to a (better) global bound change which was performed
866     * after that bound change was applied
867     *
868     * @note a global bound change is not captured by the redundant member of the bound change data structure
869     */
870    if( (boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasLE(set, newbound, SCIPvarGetLbGlobal(var)))
871       || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasGE(set, newbound, SCIPvarGetUbGlobal(var))) )
872    {
873       return SCIP_OKAY;
874    }
875 
876    SCIPsetDebugMsg(set, "applying global bound change: <%s>[%g,%g] %s %g\n",
877       SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var),
878       boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", newbound);
879 
880    /* check for cutoff */
881    if( (boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGT(set, newbound, SCIPvarGetUbGlobal(var)))
882       || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLT(set, newbound, SCIPvarGetLbGlobal(var))) )
883    {
884       *cutoff = TRUE;
885       return SCIP_OKAY;
886    }
887 
888    /* apply bound change */
889    SCIP_CALL( SCIPvarChgBdGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound, boundtype) );
890 
891    return SCIP_OKAY;
892 }
893 
894 /** captures branching and inference data of bound change */
895 static
boundchgCaptureData(SCIP_BOUNDCHG * boundchg)896 SCIP_RETCODE boundchgCaptureData(
897    SCIP_BOUNDCHG*        boundchg            /**< bound change to remove */
898    )
899 {
900    assert(boundchg != NULL);
901 
902    /* capture variable associated with the bound change */
903    assert(boundchg->var != NULL);
904    SCIPvarCapture(boundchg->var);
905 
906    switch( boundchg->boundchgtype )
907    {
908    case SCIP_BOUNDCHGTYPE_BRANCHING:
909    case SCIP_BOUNDCHGTYPE_PROPINFER:
910       break;
911 
912    case SCIP_BOUNDCHGTYPE_CONSINFER:
913       assert(boundchg->data.inferencedata.var != NULL);
914       assert(boundchg->data.inferencedata.reason.cons != NULL);
915       SCIPconsCapture(boundchg->data.inferencedata.reason.cons);
916       break;
917 
918    default:
919       SCIPerrorMessage("invalid bound change type\n");
920       return SCIP_INVALIDDATA;
921    }
922 
923    return SCIP_OKAY;
924 }
925 
926 /** releases branching and inference data of bound change */
927 static
boundchgReleaseData(SCIP_BOUNDCHG * boundchg,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)928 SCIP_RETCODE boundchgReleaseData(
929    SCIP_BOUNDCHG*        boundchg,           /**< bound change to remove */
930    BMS_BLKMEM*           blkmem,             /**< block memory */
931    SCIP_SET*             set,                /**< global SCIP settings */
932    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
933    SCIP_LP*              lp                  /**< current LP data */
934 
935    )
936 {
937    assert(boundchg != NULL);
938 
939    switch( boundchg->boundchgtype )
940    {
941    case SCIP_BOUNDCHGTYPE_BRANCHING:
942    case SCIP_BOUNDCHGTYPE_PROPINFER:
943       break;
944 
945    case SCIP_BOUNDCHGTYPE_CONSINFER:
946       assert(boundchg->data.inferencedata.var != NULL);
947       assert(boundchg->data.inferencedata.reason.cons != NULL);
948       SCIP_CALL( SCIPconsRelease(&boundchg->data.inferencedata.reason.cons, blkmem, set) );
949       break;
950 
951    default:
952       SCIPerrorMessage("invalid bound change type\n");
953       return SCIP_INVALIDDATA;
954    }
955 
956    /* release variable */
957    assert(boundchg->var != NULL);
958    SCIP_CALL( SCIPvarRelease(&boundchg->var, blkmem, set, eventqueue, lp) );
959 
960    return SCIP_OKAY;
961 }
962 
963 /** creates empty domain change data with dynamic arrays */
964 static
domchgCreate(SCIP_DOMCHG ** domchg,BMS_BLKMEM * blkmem)965 SCIP_RETCODE domchgCreate(
966    SCIP_DOMCHG**         domchg,             /**< pointer to domain change data */
967    BMS_BLKMEM*           blkmem              /**< block memory */
968    )
969 {
970    assert(domchg != NULL);
971    assert(blkmem != NULL);
972 
973    SCIP_ALLOC( BMSallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN)) );
974    (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
975    (*domchg)->domchgdyn.nboundchgs = 0;
976    (*domchg)->domchgdyn.boundchgs = NULL;
977    (*domchg)->domchgdyn.nholechgs = 0;
978    (*domchg)->domchgdyn.holechgs = NULL;
979    (*domchg)->domchgdyn.boundchgssize = 0;
980    (*domchg)->domchgdyn.holechgssize = 0;
981 
982    return SCIP_OKAY;
983 }
984 
985 /** frees domain change data */
SCIPdomchgFree(SCIP_DOMCHG ** domchg,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)986 SCIP_RETCODE SCIPdomchgFree(
987    SCIP_DOMCHG**         domchg,             /**< pointer to domain change */
988    BMS_BLKMEM*           blkmem,             /**< block memory */
989    SCIP_SET*             set,                /**< global SCIP settings */
990    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
991    SCIP_LP*              lp                  /**< current LP data */
992    )
993 {
994    assert(domchg != NULL);
995    assert(blkmem != NULL);
996 
997    if( *domchg != NULL )
998    {
999       int i;
1000 
1001       /* release variables, branching and inference data associated with the bound changes */
1002       for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1003       {
1004          SCIP_CALL( boundchgReleaseData(&(*domchg)->domchgbound.boundchgs[i], blkmem, set, eventqueue, lp) );
1005       }
1006 
1007       /* free memory for bound and hole changes */
1008       switch( (*domchg)->domchgdyn.domchgtype )
1009       {
1010       case SCIP_DOMCHGTYPE_BOUND:
1011          BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgbound.boundchgs, (*domchg)->domchgbound.nboundchgs);
1012          BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOUND));
1013          break;
1014       case SCIP_DOMCHGTYPE_BOTH:
1015          BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgboth.boundchgs, (*domchg)->domchgboth.nboundchgs);
1016          BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgboth.holechgs, (*domchg)->domchgboth.nholechgs);
1017          BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH));
1018          break;
1019       case SCIP_DOMCHGTYPE_DYNAMIC:
1020          BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.boundchgs, (*domchg)->domchgdyn.boundchgssize);
1021          BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.holechgs, (*domchg)->domchgdyn.holechgssize);
1022          BMSfreeBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN));
1023          break;
1024       default:
1025          SCIPerrorMessage("invalid domain change type\n");
1026          return SCIP_INVALIDDATA;
1027       }
1028    }
1029 
1030    return SCIP_OKAY;
1031 }
1032 
1033 /** converts a static domain change data into a dynamic one */
1034 static
domchgMakeDynamic(SCIP_DOMCHG ** domchg,BMS_BLKMEM * blkmem)1035 SCIP_RETCODE domchgMakeDynamic(
1036    SCIP_DOMCHG**         domchg,             /**< pointer to domain change data */
1037    BMS_BLKMEM*           blkmem              /**< block memory */
1038    )
1039 {
1040    assert(domchg != NULL);
1041    assert(blkmem != NULL);
1042 
1043    SCIPdebugMessage("making domain change data %p pointing to %p dynamic\n", (void*)domchg, (void*)*domchg);
1044 
1045    if( *domchg == NULL )
1046    {
1047       SCIP_CALL( domchgCreate(domchg, blkmem) );
1048    }
1049    else
1050    {
1051       switch( (*domchg)->domchgdyn.domchgtype )
1052       {
1053       case SCIP_DOMCHGTYPE_BOUND:
1054          SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOUND), sizeof(SCIP_DOMCHGDYN)) );
1055          (*domchg)->domchgdyn.nholechgs = 0;
1056          (*domchg)->domchgdyn.holechgs = NULL;
1057          (*domchg)->domchgdyn.boundchgssize = (int) (*domchg)->domchgdyn.nboundchgs;
1058          (*domchg)->domchgdyn.holechgssize = 0;
1059          (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
1060          break;
1061       case SCIP_DOMCHGTYPE_BOTH:
1062          SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH), sizeof(SCIP_DOMCHGDYN)) );
1063          (*domchg)->domchgdyn.boundchgssize = (int) (*domchg)->domchgdyn.nboundchgs;
1064          (*domchg)->domchgdyn.holechgssize = (*domchg)->domchgdyn.nholechgs;
1065          (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_DYNAMIC; /*lint !e641*/
1066          break;
1067       case SCIP_DOMCHGTYPE_DYNAMIC:
1068          break;
1069       default:
1070          SCIPerrorMessage("invalid domain change type\n");
1071          return SCIP_INVALIDDATA;
1072       }
1073    }
1074 #ifndef NDEBUG
1075    {
1076       int i;
1077       for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1078          assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1079             || EPSISINT((*domchg)->domchgbound.boundchgs[i].newbound, 1e-06));
1080    }
1081 #endif
1082 
1083    return SCIP_OKAY;
1084 }
1085 
1086 /** converts a dynamic domain change data into a static one, using less memory than for a dynamic one */
SCIPdomchgMakeStatic(SCIP_DOMCHG ** domchg,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)1087 SCIP_RETCODE SCIPdomchgMakeStatic(
1088    SCIP_DOMCHG**         domchg,             /**< pointer to domain change data */
1089    BMS_BLKMEM*           blkmem,             /**< block memory */
1090    SCIP_SET*             set,                /**< global SCIP settings */
1091    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1092    SCIP_LP*              lp                  /**< current LP data */
1093    )
1094 {
1095    assert(domchg != NULL);
1096    assert(blkmem != NULL);
1097 
1098    SCIPsetDebugMsg(set, "making domain change data %p pointing to %p static\n", (void*)domchg, (void*)*domchg);
1099 
1100    if( *domchg != NULL )
1101    {
1102       switch( (*domchg)->domchgdyn.domchgtype )
1103       {
1104       case SCIP_DOMCHGTYPE_BOUND:
1105          if( (*domchg)->domchgbound.nboundchgs == 0 )
1106          {
1107             SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1108          }
1109          break;
1110       case SCIP_DOMCHGTYPE_BOTH:
1111          if( (*domchg)->domchgboth.nholechgs == 0 )
1112          {
1113             if( (*domchg)->domchgbound.nboundchgs == 0 )
1114             {
1115                SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1116             }
1117             else
1118             {
1119                SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGBOTH), sizeof(SCIP_DOMCHGBOUND)) );
1120                (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOUND; /*lint !e641*/
1121             }
1122          }
1123          break;
1124       case SCIP_DOMCHGTYPE_DYNAMIC:
1125          if( (*domchg)->domchgboth.nholechgs == 0 )
1126          {
1127             if( (*domchg)->domchgbound.nboundchgs == 0 )
1128             {
1129                SCIP_CALL( SCIPdomchgFree(domchg, blkmem, set, eventqueue, lp) );
1130             }
1131             else
1132             {
1133                /* shrink dynamic size arrays to their minimal sizes */
1134                SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.boundchgs, \
1135                      (*domchg)->domchgdyn.boundchgssize, (*domchg)->domchgdyn.nboundchgs) ); /*lint !e571*/
1136                BMSfreeBlockMemoryArrayNull(blkmem, &(*domchg)->domchgdyn.holechgs, (*domchg)->domchgdyn.holechgssize);
1137 
1138                /* convert into static domain change */
1139                SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN), sizeof(SCIP_DOMCHGBOUND)) );
1140                (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOUND; /*lint !e641*/
1141             }
1142          }
1143          else
1144          {
1145             /* shrink dynamic size arrays to their minimal sizes */
1146             SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.boundchgs, \
1147                   (*domchg)->domchgdyn.boundchgssize, (*domchg)->domchgdyn.nboundchgs) ); /*lint !e571*/
1148             SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*domchg)->domchgdyn.holechgs, \
1149                   (*domchg)->domchgdyn.holechgssize, (*domchg)->domchgdyn.nholechgs) );
1150 
1151             /* convert into static domain change */
1152             SCIP_ALLOC( BMSreallocBlockMemorySize(blkmem, domchg, sizeof(SCIP_DOMCHGDYN), sizeof(SCIP_DOMCHGBOTH)) );
1153             (*domchg)->domchgdyn.domchgtype = SCIP_DOMCHGTYPE_BOTH; /*lint !e641*/
1154          }
1155          break;
1156       default:
1157          SCIPerrorMessage("invalid domain change type\n");
1158          return SCIP_INVALIDDATA;
1159       }
1160 #ifndef NDEBUG
1161       if( *domchg != NULL )
1162       {
1163          int i;
1164          for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1165             assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1166                || SCIPsetIsFeasIntegral(set, (*domchg)->domchgbound.boundchgs[i].newbound));
1167       }
1168 #endif
1169    }
1170 
1171    return SCIP_OKAY;
1172 }
1173 
1174 /** ensures, that boundchgs array can store at least num entries */
1175 static
domchgEnsureBoundchgsSize(SCIP_DOMCHG * domchg,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)1176 SCIP_RETCODE domchgEnsureBoundchgsSize(
1177    SCIP_DOMCHG*          domchg,             /**< domain change data structure */
1178    BMS_BLKMEM*           blkmem,             /**< block memory */
1179    SCIP_SET*             set,                /**< global SCIP settings */
1180    int                   num                 /**< minimum number of entries to store */
1181    )
1182 {
1183    assert(domchg != NULL);
1184    assert(domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1185 
1186    if( num > domchg->domchgdyn.boundchgssize )
1187    {
1188       int newsize;
1189 
1190       newsize = SCIPsetCalcMemGrowSize(set, num);
1191       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &domchg->domchgdyn.boundchgs, domchg->domchgdyn.boundchgssize, newsize) );
1192       domchg->domchgdyn.boundchgssize = newsize;
1193    }
1194    assert(num <= domchg->domchgdyn.boundchgssize);
1195 
1196    return SCIP_OKAY;
1197 }
1198 
1199 /** ensures, that holechgs array can store at least num additional entries */
1200 static
domchgEnsureHolechgsSize(SCIP_DOMCHG * domchg,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)1201 SCIP_RETCODE domchgEnsureHolechgsSize(
1202    SCIP_DOMCHG*          domchg,             /**< domain change data structure */
1203    BMS_BLKMEM*           blkmem,             /**< block memory */
1204    SCIP_SET*             set,                /**< global SCIP settings */
1205    int                   num                 /**< minimum number of additional entries to store */
1206    )
1207 {
1208    assert(domchg != NULL);
1209    assert(domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1210 
1211    if( num > domchg->domchgdyn.holechgssize )
1212    {
1213       int newsize;
1214 
1215       newsize = SCIPsetCalcMemGrowSize(set, num);
1216       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &domchg->domchgdyn.holechgs, domchg->domchgdyn.holechgssize, newsize) );
1217       domchg->domchgdyn.holechgssize = newsize;
1218    }
1219    assert(num <= domchg->domchgdyn.holechgssize);
1220 
1221    return SCIP_OKAY;
1222 }
1223 
1224 /** applies domain change */
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)1225 SCIP_RETCODE SCIPdomchgApply(
1226    SCIP_DOMCHG*          domchg,             /**< domain change to apply */
1227    BMS_BLKMEM*           blkmem,             /**< block memory */
1228    SCIP_SET*             set,                /**< global SCIP settings */
1229    SCIP_STAT*            stat,               /**< problem statistics */
1230    SCIP_LP*              lp,                 /**< current LP data */
1231    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
1232    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1233    int                   depth,              /**< depth in the tree, where the domain change takes place */
1234    SCIP_Bool*            cutoff              /**< pointer to store whether an infeasible domain change was detected */
1235    )
1236 {
1237    int i;
1238 
1239    assert(cutoff != NULL);
1240 
1241    *cutoff = FALSE;
1242 
1243    SCIPsetDebugMsg(set, "applying domain changes at %p in depth %d\n", (void*)domchg, depth);
1244 
1245    if( domchg == NULL )
1246       return SCIP_OKAY;
1247 
1248    /* apply bound changes */
1249    for( i = 0; i < (int)domchg->domchgbound.nboundchgs; ++i )
1250    {
1251       SCIP_CALL( SCIPboundchgApply(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp,
1252             branchcand, eventqueue, depth, i, cutoff) );
1253       if( *cutoff )
1254          break;
1255    }
1256    SCIPsetDebugMsg(set, " -> %u bound changes (cutoff %u)\n", domchg->domchgbound.nboundchgs, *cutoff);
1257 
1258    /* mark all bound changes after a cutoff redundant */
1259    for( ; i < (int)domchg->domchgbound.nboundchgs; ++i )
1260       domchg->domchgbound.boundchgs[i].redundant = TRUE;
1261 
1262    /* apply holelist changes */
1263    if( domchg->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_BOUND ) /*lint !e641*/
1264    {
1265       for( i = 0; i < domchg->domchgboth.nholechgs; ++i )
1266          *(domchg->domchgboth.holechgs[i].ptr) = domchg->domchgboth.holechgs[i].newlist;
1267       SCIPsetDebugMsg(set, " -> %d hole changes\n", domchg->domchgboth.nholechgs);
1268    }
1269 
1270    return SCIP_OKAY;
1271 }
1272 
1273 /** undoes domain change */
SCIPdomchgUndo(SCIP_DOMCHG * domchg,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue)1274 SCIP_RETCODE SCIPdomchgUndo(
1275    SCIP_DOMCHG*          domchg,             /**< domain change to remove */
1276    BMS_BLKMEM*           blkmem,             /**< block memory */
1277    SCIP_SET*             set,                /**< global SCIP settings */
1278    SCIP_STAT*            stat,               /**< problem statistics */
1279    SCIP_LP*              lp,                 /**< current LP data */
1280    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
1281    SCIP_EVENTQUEUE*      eventqueue          /**< event queue */
1282    )
1283 {
1284    int i;
1285 
1286    SCIPsetDebugMsg(set, "undoing domain changes at %p\n", (void*)domchg);
1287    if( domchg == NULL )
1288       return SCIP_OKAY;
1289 
1290    /* undo holelist changes */
1291    if( domchg->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_BOUND ) /*lint !e641*/
1292    {
1293       for( i = domchg->domchgboth.nholechgs-1; i >= 0; --i )
1294          *(domchg->domchgboth.holechgs[i].ptr) = domchg->domchgboth.holechgs[i].oldlist;
1295       SCIPsetDebugMsg(set, " -> %d hole changes\n", domchg->domchgboth.nholechgs);
1296    }
1297 
1298    /* undo bound changes */
1299    for( i = domchg->domchgbound.nboundchgs-1; i >= 0; --i )
1300    {
1301       SCIP_CALL( SCIPboundchgUndo(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp, branchcand, eventqueue) );
1302    }
1303    SCIPsetDebugMsg(set, " -> %u bound changes\n", domchg->domchgbound.nboundchgs);
1304 
1305    return SCIP_OKAY;
1306 }
1307 
1308 /** applies domain change to the global problem */
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)1309 SCIP_RETCODE SCIPdomchgApplyGlobal(
1310    SCIP_DOMCHG*          domchg,             /**< domain change to apply */
1311    BMS_BLKMEM*           blkmem,             /**< block memory */
1312    SCIP_SET*             set,                /**< global SCIP settings */
1313    SCIP_STAT*            stat,               /**< problem statistics */
1314    SCIP_LP*              lp,                 /**< current LP data */
1315    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
1316    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1317    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
1318    SCIP_Bool*            cutoff              /**< pointer to store whether an infeasible domain change was detected */
1319    )
1320 {
1321    int i;
1322 
1323    assert(cutoff != NULL);
1324 
1325    *cutoff = FALSE;
1326 
1327    if( domchg == NULL )
1328       return SCIP_OKAY;
1329 
1330    SCIPsetDebugMsg(set, "applying domain changes at %p to the global problem\n", (void*)domchg);
1331 
1332    /* apply bound changes */
1333    for( i = 0; i < (int)domchg->domchgbound.nboundchgs; ++i )
1334    {
1335       SCIP_CALL( boundchgApplyGlobal(&domchg->domchgbound.boundchgs[i], blkmem, set, stat, lp,
1336             branchcand, eventqueue, cliquetable, cutoff) );
1337       if( *cutoff )
1338          break;
1339    }
1340    SCIPsetDebugMsg(set, " -> %u global bound changes\n", domchg->domchgbound.nboundchgs);
1341 
1342    /**@todo globally apply holelist changes - how can this be done without confusing pointer updates? */
1343 
1344    return SCIP_OKAY;
1345 }
1346 
1347 /** adds bound change to domain changes */
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)1348 SCIP_RETCODE SCIPdomchgAddBoundchg(
1349    SCIP_DOMCHG**         domchg,             /**< pointer to domain change data structure */
1350    BMS_BLKMEM*           blkmem,             /**< block memory */
1351    SCIP_SET*             set,                /**< global SCIP settings */
1352    SCIP_VAR*             var,                /**< variable to change the bounds for */
1353    SCIP_Real             newbound,           /**< new value for bound */
1354    SCIP_BOUNDTYPE        boundtype,          /**< type of bound for var: lower or upper bound */
1355    SCIP_BOUNDCHGTYPE     boundchgtype,       /**< type of bound change: branching decision or inference */
1356    SCIP_Real             lpsolval,           /**< solval of variable in last LP on path to node, or SCIP_INVALID if unknown */
1357    SCIP_VAR*             infervar,           /**< variable that was changed (parent of var, or var itself), or NULL */
1358    SCIP_CONS*            infercons,          /**< constraint that deduced the bound change, or NULL */
1359    SCIP_PROP*            inferprop,          /**< propagator that deduced the bound change, or NULL */
1360    int                   inferinfo,          /**< user information for inference to help resolving the conflict */
1361    SCIP_BOUNDTYPE        inferboundtype      /**< type of bound for inference var: lower or upper bound */
1362    )
1363 {
1364    SCIP_BOUNDCHG* boundchg;
1365 
1366    assert(domchg != NULL);
1367    assert(var != NULL);
1368    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
1369    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
1370    assert(!SCIPvarIsBinary(var) || SCIPsetIsEQ(set, newbound, boundtype == SCIP_BOUNDTYPE_LOWER ? 1.0 : 0.0));
1371    assert(boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING || infervar != NULL);
1372    assert((boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER) == (infercons != NULL));
1373    assert(boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER || inferprop == NULL);
1374 
1375    SCIPsetDebugMsg(set, "adding %s bound change <%s: %g> of variable <%s> to domain change at %p pointing to %p\n",
1376       boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ? "branching" : "inference",
1377       newbound, var->name, (void*)domchg, (void*)*domchg);
1378 
1379    /* if domain change data doesn't exist, create it;
1380     * if domain change is static, convert it into dynamic change
1381     */
1382    if( *domchg == NULL )
1383    {
1384       SCIP_CALL( domchgCreate(domchg, blkmem) );
1385    }
1386    else if( (*domchg)->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_DYNAMIC ) /*lint !e641*/
1387    {
1388       SCIP_CALL( domchgMakeDynamic(domchg, blkmem) );
1389    }
1390    assert(*domchg != NULL && (*domchg)->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1391 
1392    /* get memory for additional bound change */
1393    SCIP_CALL( domchgEnsureBoundchgsSize(*domchg, blkmem, set, (*domchg)->domchgdyn.nboundchgs+1) );
1394 
1395    /* fill in the bound change data */
1396    boundchg = &(*domchg)->domchgdyn.boundchgs[(*domchg)->domchgdyn.nboundchgs];
1397    boundchg->var = var;
1398    switch( boundchgtype )
1399    {
1400    case SCIP_BOUNDCHGTYPE_BRANCHING:
1401       boundchg->data.branchingdata.lpsolval = lpsolval;
1402       break;
1403    case SCIP_BOUNDCHGTYPE_CONSINFER:
1404       assert(infercons != NULL);
1405       boundchg->data.inferencedata.var = infervar;
1406       boundchg->data.inferencedata.reason.cons = infercons;
1407       boundchg->data.inferencedata.info = inferinfo;
1408       break;
1409    case SCIP_BOUNDCHGTYPE_PROPINFER:
1410       boundchg->data.inferencedata.var = infervar;
1411       boundchg->data.inferencedata.reason.prop = inferprop;
1412       boundchg->data.inferencedata.info = inferinfo;
1413       break;
1414    default:
1415       SCIPerrorMessage("invalid bound change type %d\n", boundchgtype);
1416       return SCIP_INVALIDDATA;
1417    }
1418 
1419    boundchg->newbound = newbound;
1420    boundchg->boundchgtype = boundchgtype; /*lint !e641*/
1421    boundchg->boundtype = boundtype; /*lint !e641*/
1422    boundchg->inferboundtype = inferboundtype; /*lint !e641*/
1423    boundchg->applied = FALSE;
1424    boundchg->redundant = FALSE;
1425    (*domchg)->domchgdyn.nboundchgs++;
1426 
1427    /* capture branching and inference data associated with the bound changes */
1428    SCIP_CALL( boundchgCaptureData(boundchg) );
1429 
1430 #ifdef SCIP_DISABLED_CODE /* expensive debug check */
1431 #ifdef SCIP_MORE_DEBUG
1432    {
1433       int i;
1434       for( i = 0; i < (int)(*domchg)->domchgbound.nboundchgs; ++i )
1435          assert(SCIPvarGetType((*domchg)->domchgbound.boundchgs[i].var) == SCIP_VARTYPE_CONTINUOUS
1436             || SCIPsetIsFeasIntegral(set, (*domchg)->domchgbound.boundchgs[i].newbound));
1437    }
1438 #endif
1439 #endif
1440 
1441    return SCIP_OKAY;
1442 }
1443 
1444 /** adds hole change to domain changes */
SCIPdomchgAddHolechg(SCIP_DOMCHG ** domchg,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_HOLELIST ** ptr,SCIP_HOLELIST * newlist,SCIP_HOLELIST * oldlist)1445 SCIP_RETCODE SCIPdomchgAddHolechg(
1446    SCIP_DOMCHG**         domchg,             /**< pointer to domain change data structure */
1447    BMS_BLKMEM*           blkmem,             /**< block memory */
1448    SCIP_SET*             set,                /**< global SCIP settings */
1449    SCIP_HOLELIST**       ptr,                /**< changed list pointer */
1450    SCIP_HOLELIST*        newlist,            /**< new value of list pointer */
1451    SCIP_HOLELIST*        oldlist             /**< old value of list pointer */
1452    )
1453 {
1454    SCIP_HOLECHG* holechg;
1455 
1456    assert(domchg != NULL);
1457    assert(ptr != NULL);
1458 
1459    /* if domain change data doesn't exist, create it;
1460     * if domain change is static, convert it into dynamic change
1461     */
1462    if( *domchg == NULL )
1463    {
1464       SCIP_CALL( domchgCreate(domchg, blkmem) );
1465    }
1466    else if( (*domchg)->domchgdyn.domchgtype != SCIP_DOMCHGTYPE_DYNAMIC ) /*lint !e641*/
1467    {
1468       SCIP_CALL( domchgMakeDynamic(domchg, blkmem) );
1469    }
1470    assert(*domchg != NULL && (*domchg)->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
1471 
1472    /* get memory for additional hole change */
1473    SCIP_CALL( domchgEnsureHolechgsSize(*domchg, blkmem, set, (*domchg)->domchgdyn.nholechgs+1) );
1474 
1475    /* fill in the hole change data */
1476    holechg = &(*domchg)->domchgdyn.holechgs[(*domchg)->domchgdyn.nholechgs];
1477    holechg->ptr = ptr;
1478    holechg->newlist = newlist;
1479    holechg->oldlist = oldlist;
1480    (*domchg)->domchgdyn.nholechgs++;
1481 
1482    return SCIP_OKAY;
1483 }
1484 
1485 
1486 
1487 
1488 /*
1489  * methods for variables
1490  */
1491 
1492 /** returns adjusted lower bound value, which is rounded for integral variable types */
1493 static
adjustedLb(SCIP_SET * set,SCIP_VARTYPE vartype,SCIP_Real lb)1494 SCIP_Real adjustedLb(
1495    SCIP_SET*             set,                /**< global SCIP settings */
1496    SCIP_VARTYPE          vartype,            /**< type of variable */
1497    SCIP_Real             lb                  /**< lower bound to adjust */
1498    )
1499 {
1500    if( lb < 0 && SCIPsetIsInfinity(set, -lb) )
1501       return -SCIPsetInfinity(set);
1502    else if( lb > 0 && SCIPsetIsInfinity(set, lb) )
1503       return SCIPsetInfinity(set);
1504    else if( vartype != SCIP_VARTYPE_CONTINUOUS )
1505       return SCIPsetFeasCeil(set, lb);
1506    else if( SCIPsetIsZero(set, lb) )
1507       return 0.0;
1508    else
1509       return lb;
1510 }
1511 
1512 /** returns adjusted upper bound value, which is rounded for integral variable types */
1513 static
adjustedUb(SCIP_SET * set,SCIP_VARTYPE vartype,SCIP_Real ub)1514 SCIP_Real adjustedUb(
1515    SCIP_SET*             set,                /**< global SCIP settings */
1516    SCIP_VARTYPE          vartype,            /**< type of variable */
1517    SCIP_Real             ub                  /**< upper bound to adjust */
1518    )
1519 {
1520    if( ub > 0 && SCIPsetIsInfinity(set, ub) )
1521       return SCIPsetInfinity(set);
1522    else if( ub < 0 && SCIPsetIsInfinity(set, -ub) )
1523       return -SCIPsetInfinity(set);
1524    else if( vartype != SCIP_VARTYPE_CONTINUOUS )
1525       return SCIPsetFeasFloor(set, ub);
1526    else if( SCIPsetIsZero(set, ub) )
1527       return 0.0;
1528    else
1529       return ub;
1530 }
1531 
1532 /** removes (redundant) cliques, implications and variable bounds of variable from all other variables' implications and variable
1533  *  bounds arrays, and optionally removes them also from the variable itself
1534  */
SCIPvarRemoveCliquesImplicsVbs(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_CLIQUETABLE * cliquetable,SCIP_SET * set,SCIP_Bool irrelevantvar,SCIP_Bool onlyredundant,SCIP_Bool removefromvar)1535 SCIP_RETCODE SCIPvarRemoveCliquesImplicsVbs(
1536    SCIP_VAR*             var,                /**< problem variable */
1537    BMS_BLKMEM*           blkmem,             /**< block memory */
1538    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
1539    SCIP_SET*             set,                /**< global SCIP settings */
1540    SCIP_Bool             irrelevantvar,      /**< has the variable become irrelevant? */
1541    SCIP_Bool             onlyredundant,      /**< should only the redundant implications and variable bounds be removed? */
1542    SCIP_Bool             removefromvar       /**< should the implications and variable bounds be removed from the var itself? */
1543    )
1544 {
1545    SCIP_Real lb;
1546    SCIP_Real ub;
1547 
1548    assert(var != NULL);
1549    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
1550    assert(SCIPvarIsActive(var) || SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
1551 
1552    lb = SCIPvarGetLbGlobal(var);
1553    ub = SCIPvarGetUbGlobal(var);
1554 
1555    SCIPsetDebugMsg(set, "removing %s implications and vbounds of %s<%s>[%g,%g]\n",
1556       onlyredundant ? "redundant" : "all", irrelevantvar ? "irrelevant " : "", SCIPvarGetName(var), lb, ub);
1557 
1558    /* remove implications of (fixed) binary variable */
1559    if( var->implics != NULL && (!onlyredundant || lb > 0.5 || ub < 0.5) )
1560    {
1561       SCIP_Bool varfixing;
1562 
1563       assert(SCIPvarIsBinary(var));
1564 
1565       varfixing = FALSE;
1566       do
1567       {
1568          SCIP_VAR** implvars;
1569          SCIP_BOUNDTYPE* impltypes;
1570          int nimpls;
1571          int i;
1572 
1573          nimpls = SCIPimplicsGetNImpls(var->implics, varfixing);
1574          implvars = SCIPimplicsGetVars(var->implics, varfixing);
1575          impltypes = SCIPimplicsGetTypes(var->implics, varfixing);
1576 
1577          for( i = 0; i < nimpls; i++ )
1578          {
1579             SCIP_VAR* implvar;
1580             SCIP_BOUNDTYPE impltype;
1581 
1582             implvar = implvars[i];
1583             impltype = impltypes[i];
1584             assert(implvar != var);
1585 
1586             /* remove for all implications z == 0 / 1  ==>  x <= p / x >= p (x not binary)
1587              * the following variable bound from x's variable bounds
1588              *   x <= b*z+d (z in vubs of x)            , for z == 0 / 1  ==>  x <= p
1589              *   x >= b*z+d (z in vlbs of x)            , for z == 0 / 1  ==>  x >= p
1590              */
1591             if( impltype == SCIP_BOUNDTYPE_UPPER )
1592             {
1593                if( implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1594                {
1595                   SCIPsetDebugMsg(set, "deleting variable bound: <%s> == %u  ==>  <%s> <= %g\n",
1596                      SCIPvarGetName(var), varfixing, SCIPvarGetName(implvar),
1597                      SCIPimplicsGetBounds(var->implics, varfixing)[i]);
1598                   SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, varfixing) );
1599                   implvar->closestvblpcount = -1;
1600                   var->closestvblpcount = -1;
1601                }
1602             }
1603             else
1604             {
1605                if( implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1606                {
1607                   SCIPsetDebugMsg(set, "deleting variable bound: <%s> == %u  ==>  <%s> >= %g\n",
1608                      SCIPvarGetName(var), varfixing, SCIPvarGetName(implvar),
1609                      SCIPimplicsGetBounds(var->implics, varfixing)[i]);
1610                   SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, !varfixing) );
1611                   implvar->closestvblpcount = -1;
1612                   var->closestvblpcount = -1;
1613                }
1614             }
1615          }
1616          varfixing = !varfixing;
1617       }
1618       while( varfixing == TRUE );
1619 
1620       if( removefromvar )
1621       {
1622          /* free the implications data structures */
1623          SCIPimplicsFree(&var->implics, blkmem);
1624       }
1625    }
1626 
1627    /* remove the (redundant) variable lower bounds */
1628    if( var->vlbs != NULL )
1629    {
1630       SCIP_VAR** vars;
1631       SCIP_Real* coefs;
1632       SCIP_Real* constants;
1633       int nvbds;
1634       int newnvbds;
1635       int i;
1636 
1637       nvbds = SCIPvboundsGetNVbds(var->vlbs);
1638       vars = SCIPvboundsGetVars(var->vlbs);
1639       coefs = SCIPvboundsGetCoefs(var->vlbs);
1640       constants = SCIPvboundsGetConstants(var->vlbs);
1641 
1642       /* remove for all variable bounds x >= b*z+d the following implication from z's implications
1643        *   z == ub  ==>  x >= b*ub + d           , if b > 0
1644        *   z == lb  ==>  x >= b*lb + d           , if b < 0
1645        */
1646       newnvbds = 0;
1647       for( i = 0; i < nvbds; i++ )
1648       {
1649          SCIP_VAR* implvar;
1650          SCIP_Real coef;
1651 
1652          assert(newnvbds <= i);
1653 
1654          implvar = vars[i];
1655          assert(implvar != NULL);
1656 
1657          coef = coefs[i];
1658          assert(!SCIPsetIsZero(set, coef));
1659 
1660          /* check, if we want to remove the variable bound */
1661          if( onlyredundant )
1662          {
1663             SCIP_Real vbound;
1664 
1665             vbound = MAX(coef * SCIPvarGetUbGlobal(implvar), coef * SCIPvarGetLbGlobal(implvar)) + constants[i];  /*lint !e666*/
1666             if( SCIPsetIsFeasGT(set, vbound, lb) )
1667             {
1668                /* the variable bound is not redundant: keep it */
1669                if( removefromvar )
1670                {
1671                   if( newnvbds < i )
1672                   {
1673                      vars[newnvbds] = implvar;
1674                      coefs[newnvbds] = coef;
1675                      constants[newnvbds] = constants[i];
1676                   }
1677                   newnvbds++;
1678                }
1679                continue;
1680             }
1681          }
1682 
1683          /* remove the corresponding implication */
1684          if( implvar->implics != NULL ) /* variable may have been aggregated in the mean time */
1685          {
1686             SCIPsetDebugMsg(set, "deleting implication: <%s> == %d  ==>  <%s> >= %g\n",
1687                SCIPvarGetName(implvar), (coef > 0.0), SCIPvarGetName(var), MAX(coef, 0.0) + constants[i]);
1688             SCIP_CALL( SCIPimplicsDel(&implvar->implics, blkmem, set, (coef > 0.0), var, SCIP_BOUNDTYPE_LOWER) );
1689          }
1690          if( coef > 0.0 && implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1691          {
1692             SCIPsetDebugMsg(set, "deleting variable upper bound from <%s> involving variable %s\n",
1693                SCIPvarGetName(implvar), SCIPvarGetName(var));
1694             SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, FALSE) );
1695             implvar->closestvblpcount = -1;
1696             var->closestvblpcount = -1;
1697          }
1698          else if( coef < 0.0 && implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1699          {
1700             SCIPsetDebugMsg(set, "deleting variable lower bound from <%s> involving variable %s\n",
1701                SCIPvarGetName(implvar), SCIPvarGetName(var));
1702             SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, TRUE) );
1703             implvar->closestvblpcount = -1;
1704             var->closestvblpcount = -1;
1705          }
1706       }
1707 
1708       if( removefromvar )
1709       {
1710          /* update the number of variable bounds */
1711          SCIPvboundsShrink(&var->vlbs, blkmem, newnvbds);
1712          var->closestvblpcount = -1;
1713       }
1714    }
1715 
1716    /**@todo in general, variable bounds like x >= b*z + d corresponding to an implication like z = ub ==> x >= b*ub + d
1717     *       might be missing because we only add variable bounds with reasonably small value of b. thus, we currently
1718     *       cannot remove such variables x from z's implications.
1719     */
1720 
1721    /* remove the (redundant) variable upper bounds */
1722    if( var->vubs != NULL )
1723    {
1724       SCIP_VAR** vars;
1725       SCIP_Real* coefs;
1726       SCIP_Real* constants;
1727       int nvbds;
1728       int newnvbds;
1729       int i;
1730 
1731       nvbds = SCIPvboundsGetNVbds(var->vubs);
1732       vars = SCIPvboundsGetVars(var->vubs);
1733       coefs = SCIPvboundsGetCoefs(var->vubs);
1734       constants = SCIPvboundsGetConstants(var->vubs);
1735 
1736       /* remove for all variable bounds x <= b*z+d the following implication from z's implications
1737        *   z == lb  ==>  x <= b*lb + d           , if b > 0
1738        *   z == ub  ==>  x <= b*ub + d           , if b < 0
1739        */
1740       newnvbds = 0;
1741       for( i = 0; i < nvbds; i++ )
1742       {
1743          SCIP_VAR* implvar;
1744          SCIP_Real coef;
1745 
1746          assert(newnvbds <= i);
1747 
1748          implvar = vars[i];
1749          assert(implvar != NULL);
1750 
1751          coef = coefs[i];
1752          assert(!SCIPsetIsZero(set, coef));
1753 
1754          /* check, if we want to remove the variable bound */
1755          if( onlyredundant )
1756          {
1757             SCIP_Real vbound;
1758 
1759             vbound = MIN(coef * SCIPvarGetUbGlobal(implvar), coef * SCIPvarGetLbGlobal(implvar)) + constants[i];  /*lint !e666*/
1760             if( SCIPsetIsFeasLT(set, vbound, ub) )
1761             {
1762                /* the variable bound is not redundant: keep it */
1763                if( removefromvar )
1764                {
1765                   if( newnvbds < i )
1766                   {
1767                      vars[newnvbds] = implvar;
1768                      coefs[newnvbds] = coefs[i];
1769                      constants[newnvbds] = constants[i];
1770                   }
1771                   newnvbds++;
1772                }
1773                continue;
1774             }
1775          }
1776 
1777          /* remove the corresponding implication */
1778          if( implvar->implics != NULL ) /* variable may have been aggregated in the mean time */
1779          {
1780             SCIPsetDebugMsg(set, "deleting implication: <%s> == %d  ==>  <%s> <= %g\n",
1781                SCIPvarGetName(implvar), (coef < 0.0), SCIPvarGetName(var), MIN(coef, 0.0) + constants[i]);
1782             SCIP_CALL( SCIPimplicsDel(&implvar->implics, blkmem, set, (coef < 0.0), var, SCIP_BOUNDTYPE_UPPER) );
1783          }
1784          if( coef < 0.0 && implvar->vubs != NULL ) /* implvar may have been aggregated in the mean time */
1785          {
1786             SCIPsetDebugMsg(set, "deleting variable upper bound from <%s> involving variable %s\n",
1787                SCIPvarGetName(implvar), SCIPvarGetName(var));
1788             SCIP_CALL( SCIPvboundsDel(&implvar->vubs, blkmem, var, TRUE) );
1789             implvar->closestvblpcount = -1;
1790             var->closestvblpcount = -1;
1791          }
1792          else if( coef > 0.0 && implvar->vlbs != NULL ) /* implvar may have been aggregated in the mean time */
1793          {
1794             SCIPsetDebugMsg(set, "deleting variable lower bound from <%s> involving variable %s\n",
1795                SCIPvarGetName(implvar), SCIPvarGetName(var));
1796             SCIP_CALL( SCIPvboundsDel(&implvar->vlbs, blkmem, var, FALSE) );
1797             implvar->closestvblpcount = -1;
1798             var->closestvblpcount = -1;
1799          }
1800       }
1801 
1802       if( removefromvar )
1803       {
1804          /* update the number of variable bounds */
1805          SCIPvboundsShrink(&var->vubs, blkmem, newnvbds);
1806          var->closestvblpcount = -1;
1807       }
1808    }
1809 
1810    /* remove the variable from all cliques */
1811    if( SCIPvarIsBinary(var) )
1812    {
1813       SCIPcliquelistRemoveFromCliques(var->cliquelist, cliquetable, var, irrelevantvar);
1814       SCIPcliquelistFree(&var->cliquelist, blkmem);
1815    }
1816 
1817    /**@todo variable bounds like x <= b*z + d with z general integer are not removed from x's vbd arrays, because
1818     *       z has no link (like in the binary case) to x
1819     */
1820 
1821    return SCIP_OKAY;
1822 }
1823 
1824 /** sets the variable name */
1825 static
varSetName(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_STAT * stat,const char * name)1826 SCIP_RETCODE varSetName(
1827    SCIP_VAR*             var,                /**< problem variable */
1828    BMS_BLKMEM*           blkmem,             /**< block memory */
1829    SCIP_STAT*            stat,               /**< problem statistics, or NULL */
1830    const char*           name                /**< name of variable, or NULL for automatic name creation */
1831    )
1832 {
1833    assert(blkmem != NULL);
1834    assert(var != NULL);
1835 
1836    if( name == NULL )
1837    {
1838       char s[SCIP_MAXSTRLEN];
1839 
1840       assert(stat != NULL);
1841 
1842       (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "_var%d_", stat->nvaridx);
1843       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->name, s, strlen(s)+1) );
1844    }
1845    else
1846    {
1847       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->name, name, strlen(name)+1) );
1848    }
1849 
1850    return SCIP_OKAY;
1851 }
1852 
1853 
1854 /** creates variable; if variable is of integral type, fractional bounds are automatically rounded; an integer variable
1855  *  with bounds zero and one is automatically converted into a binary variable
1856  */
1857 static
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)1858 SCIP_RETCODE varCreate(
1859    SCIP_VAR**            var,                /**< pointer to variable data */
1860    BMS_BLKMEM*           blkmem,             /**< block memory */
1861    SCIP_SET*             set,                /**< global SCIP settings */
1862    SCIP_STAT*            stat,               /**< problem statistics */
1863    const char*           name,               /**< name of variable, or NULL for automatic name creation */
1864    SCIP_Real             lb,                 /**< lower bound of variable */
1865    SCIP_Real             ub,                 /**< upper bound of variable */
1866    SCIP_Real             obj,                /**< objective function value */
1867    SCIP_VARTYPE          vartype,            /**< type of variable */
1868    SCIP_Bool             initial,            /**< should var's column be present in the initial root LP? */
1869    SCIP_Bool             removable,          /**< is var's column removable from the LP (due to aging or cleanup)? */
1870    SCIP_DECL_VARCOPY     ((*varcopy)),       /**< copies variable data if wanted to subscip, or NULL */
1871    SCIP_DECL_VARDELORIG  ((*vardelorig)),    /**< frees user data of original variable, or NULL */
1872    SCIP_DECL_VARTRANS    ((*vartrans)),      /**< creates transformed user data by transforming original user data, or NULL */
1873    SCIP_DECL_VARDELTRANS ((*vardeltrans)),   /**< frees user data of transformed variable, or NULL */
1874    SCIP_VARDATA*         vardata             /**< user data for this specific variable */
1875    )
1876 {
1877    int i;
1878 
1879    assert(var != NULL);
1880    assert(blkmem != NULL);
1881    assert(stat != NULL);
1882 
1883    /* adjust bounds of variable */
1884    lb = adjustedLb(set, vartype, lb);
1885    ub = adjustedUb(set, vartype, ub);
1886 
1887    /* convert [0,1]-integers into binary variables and check that binary variables have correct bounds */
1888    if( (SCIPsetIsEQ(set, lb, 0.0) || SCIPsetIsEQ(set, lb, 1.0))
1889       && (SCIPsetIsEQ(set, ub, 0.0) || SCIPsetIsEQ(set, ub, 1.0)) )
1890    {
1891       if( vartype == SCIP_VARTYPE_INTEGER )
1892          vartype = SCIP_VARTYPE_BINARY;
1893    }
1894    else
1895    {
1896       if( vartype == SCIP_VARTYPE_BINARY )
1897       {
1898          SCIPerrorMessage("invalid bounds [%.2g,%.2g] for binary variable <%s>\n", lb, ub, name);
1899          return SCIP_INVALIDDATA;
1900       }
1901    }
1902 
1903    assert(vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, lb, 0.0) || SCIPsetIsEQ(set, lb, 1.0));
1904    assert(vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, ub, 0.0) || SCIPsetIsEQ(set, ub, 1.0));
1905 
1906    SCIP_ALLOC( BMSallocBlockMemory(blkmem, var) );
1907 
1908    /* set variable's name */
1909    SCIP_CALL( varSetName(*var, blkmem, stat, name) );
1910 
1911 #ifndef NDEBUG
1912    (*var)->scip = set->scip;
1913 #endif
1914    (*var)->obj = obj;
1915    (*var)->unchangedobj = obj;
1916    (*var)->branchfactor = 1.0;
1917    (*var)->rootsol = 0.0;
1918    (*var)->bestrootsol = 0.0;
1919    (*var)->bestrootredcost = 0.0;
1920    (*var)->bestrootlpobjval = SCIP_INVALID;
1921    (*var)->relaxsol = 0.0;
1922    (*var)->nlpsol = 0.0;
1923    (*var)->primsolavg = 0.5 * (lb + ub);
1924    (*var)->conflictlb = SCIP_REAL_MIN;
1925    (*var)->conflictub = SCIP_REAL_MAX;
1926    (*var)->conflictrelaxedlb = (*var)->conflictlb;
1927    (*var)->conflictrelaxedub = (*var)->conflictub;
1928    (*var)->lazylb = -SCIPsetInfinity(set);
1929    (*var)->lazyub = SCIPsetInfinity(set);
1930    (*var)->glbdom.holelist = NULL;
1931    (*var)->glbdom.lb = lb;
1932    (*var)->glbdom.ub = ub;
1933    (*var)->locdom.holelist = NULL;
1934    (*var)->locdom.lb = lb;
1935    (*var)->locdom.ub = ub;
1936    (*var)->varcopy = varcopy;
1937    (*var)->vardelorig = vardelorig;
1938    (*var)->vartrans = vartrans;
1939    (*var)->vardeltrans = vardeltrans;
1940    (*var)->vardata = vardata;
1941    (*var)->parentvars = NULL;
1942    (*var)->negatedvar = NULL;
1943    (*var)->vlbs = NULL;
1944    (*var)->vubs = NULL;
1945    (*var)->implics = NULL;
1946    (*var)->cliquelist = NULL;
1947    (*var)->eventfilter = NULL;
1948    (*var)->lbchginfos = NULL;
1949    (*var)->ubchginfos = NULL;
1950    (*var)->index = stat->nvaridx;
1951    (*var)->probindex = -1;
1952    (*var)->pseudocandindex = -1;
1953    (*var)->eventqueueindexobj = -1;
1954    (*var)->eventqueueindexlb = -1;
1955    (*var)->eventqueueindexub = -1;
1956    (*var)->parentvarssize = 0;
1957    (*var)->nparentvars = 0;
1958    (*var)->nuses = 0;
1959    (*var)->branchpriority = 0;
1960    (*var)->branchdirection = SCIP_BRANCHDIR_AUTO; /*lint !e641*/
1961    (*var)->lbchginfossize = 0;
1962    (*var)->nlbchginfos = 0;
1963    (*var)->ubchginfossize = 0;
1964    (*var)->nubchginfos = 0;
1965    (*var)->conflictlbcount = 0;
1966    (*var)->conflictubcount = 0;
1967    (*var)->closestvlbidx = -1;
1968    (*var)->closestvubidx = -1;
1969    (*var)->closestvblpcount = -1;
1970    (*var)->initial = initial;
1971    (*var)->removable = removable;
1972    (*var)->deleted = FALSE;
1973    (*var)->donotmultaggr = FALSE;
1974    (*var)->vartype = vartype; /*lint !e641*/
1975    (*var)->pseudocostflag = FALSE;
1976    (*var)->eventqueueimpl = FALSE;
1977    (*var)->deletable = FALSE;
1978    (*var)->delglobalstructs = FALSE;
1979    (*var)->relaxationonly = FALSE;
1980 
1981    for( i = 0; i < NLOCKTYPES; i++ )
1982    {
1983       (*var)->nlocksdown[i] = 0;
1984       (*var)->nlocksup[i] = 0;
1985    }
1986 
1987    stat->nvaridx++;
1988 
1989    /* create branching and inference history entries */
1990    SCIP_CALL( SCIPhistoryCreate(&(*var)->history, blkmem) );
1991    SCIP_CALL( SCIPhistoryCreate(&(*var)->historycrun, blkmem) );
1992 
1993    /* the value based history is only created on demand */
1994    (*var)->valuehistory = NULL;
1995 
1996    return SCIP_OKAY;
1997 }
1998 
1999 /** creates and captures an original problem variable; an integer variable with bounds
2000  *  zero and one is automatically converted into a binary variable
2001  */
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)2002 SCIP_RETCODE SCIPvarCreateOriginal(
2003    SCIP_VAR**            var,                /**< pointer to variable data */
2004    BMS_BLKMEM*           blkmem,             /**< block memory */
2005    SCIP_SET*             set,                /**< global SCIP settings */
2006    SCIP_STAT*            stat,               /**< problem statistics */
2007    const char*           name,               /**< name of variable, or NULL for automatic name creation */
2008    SCIP_Real             lb,                 /**< lower bound of variable */
2009    SCIP_Real             ub,                 /**< upper bound of variable */
2010    SCIP_Real             obj,                /**< objective function value */
2011    SCIP_VARTYPE          vartype,            /**< type of variable */
2012    SCIP_Bool             initial,            /**< should var's column be present in the initial root LP? */
2013    SCIP_Bool             removable,          /**< is var's column removable from the LP (due to aging or cleanup)? */
2014    SCIP_DECL_VARDELORIG  ((*vardelorig)),    /**< frees user data of original variable, or NULL */
2015    SCIP_DECL_VARTRANS    ((*vartrans)),      /**< creates transformed user data by transforming original user data, or NULL */
2016    SCIP_DECL_VARDELTRANS ((*vardeltrans)),   /**< frees user data of transformed variable, or NULL */
2017    SCIP_DECL_VARCOPY     ((*varcopy)),       /**< copies variable data if wanted to subscip, or NULL */
2018    SCIP_VARDATA*         vardata             /**< user data for this specific variable */
2019    )
2020 {
2021    assert(var != NULL);
2022    assert(blkmem != NULL);
2023    assert(stat != NULL);
2024 
2025    /* create variable */
2026    SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2027          varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2028 
2029    /* set variable status and data */
2030    (*var)->varstatus = SCIP_VARSTATUS_ORIGINAL; /*lint !e641*/
2031    (*var)->data.original.origdom.holelist = NULL;
2032    (*var)->data.original.origdom.lb = lb;
2033    (*var)->data.original.origdom.ub = ub;
2034    (*var)->data.original.transvar = NULL;
2035 
2036    /* capture variable */
2037    SCIPvarCapture(*var);
2038 
2039    return SCIP_OKAY;
2040 }
2041 
2042 /** creates and captures a loose variable belonging to the transformed problem; an integer variable with bounds
2043  *  zero and one is automatically converted into a binary variable
2044  */
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)2045 SCIP_RETCODE SCIPvarCreateTransformed(
2046    SCIP_VAR**            var,                /**< pointer to variable data */
2047    BMS_BLKMEM*           blkmem,             /**< block memory */
2048    SCIP_SET*             set,                /**< global SCIP settings */
2049    SCIP_STAT*            stat,               /**< problem statistics */
2050    const char*           name,               /**< name of variable, or NULL for automatic name creation */
2051    SCIP_Real             lb,                 /**< lower bound of variable */
2052    SCIP_Real             ub,                 /**< upper bound of variable */
2053    SCIP_Real             obj,                /**< objective function value */
2054    SCIP_VARTYPE          vartype,            /**< type of variable */
2055    SCIP_Bool             initial,            /**< should var's column be present in the initial root LP? */
2056    SCIP_Bool             removable,          /**< is var's column removable from the LP (due to aging or cleanup)? */
2057    SCIP_DECL_VARDELORIG  ((*vardelorig)),    /**< frees user data of original variable, or NULL */
2058    SCIP_DECL_VARTRANS    ((*vartrans)),      /**< creates transformed user data by transforming original user data, or NULL */
2059    SCIP_DECL_VARDELTRANS ((*vardeltrans)),   /**< frees user data of transformed variable, or NULL */
2060    SCIP_DECL_VARCOPY     ((*varcopy)),       /**< copies variable data if wanted to subscip, or NULL */
2061    SCIP_VARDATA*         vardata             /**< user data for this specific variable */
2062    )
2063 {
2064    assert(var != NULL);
2065    assert(blkmem != NULL);
2066 
2067    /* create variable */
2068    SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2069          varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2070 
2071    /* create event filter for transformed variable */
2072    SCIP_CALL( SCIPeventfilterCreate(&(*var)->eventfilter, blkmem) );
2073 
2074    /* set variable status and data */
2075    (*var)->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
2076 
2077    /* capture variable */
2078    SCIPvarCapture(*var);
2079 
2080    return SCIP_OKAY;
2081 }
2082 
2083 /** copies and captures a variable from source to target SCIP; an integer variable with bounds zero and one is
2084  *  automatically converted into a binary variable; in case the variable data cannot be copied the variable is not
2085  *  copied at all
2086  */
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)2087 SCIP_RETCODE SCIPvarCopy(
2088    SCIP_VAR**            var,                /**< pointer to store the target variable */
2089    BMS_BLKMEM*           blkmem,             /**< block memory */
2090    SCIP_SET*             set,                /**< global SCIP settings */
2091    SCIP_STAT*            stat,               /**< problem statistics */
2092    SCIP*                 sourcescip,         /**< source SCIP data structure */
2093    SCIP_VAR*             sourcevar,          /**< source variable */
2094    SCIP_HASHMAP*         varmap,             /**< a hashmap to store the mapping of source variables corresponding
2095                                               *   target variables */
2096    SCIP_HASHMAP*         consmap,            /**< a hashmap to store the mapping of source constraints to the corresponding
2097                                               *   target constraints */
2098    SCIP_Bool             global              /**< should global or local bounds be used? */
2099    )
2100 {
2101    SCIP_VARDATA* targetdata;
2102    SCIP_RESULT result;
2103    SCIP_Real lb;
2104    SCIP_Real ub;
2105 
2106    assert(set != NULL);
2107    assert(blkmem != NULL);
2108    assert(stat != NULL);
2109    assert(sourcescip != NULL);
2110    assert(sourcevar != NULL);
2111    assert(var != NULL);
2112    assert(set->stage == SCIP_STAGE_PROBLEM);
2113    assert(varmap != NULL);
2114    assert(consmap != NULL);
2115 
2116    /** @todo copy hole lists */
2117    assert(global || SCIPvarGetHolelistLocal(sourcevar) == NULL);
2118    assert(!global || SCIPvarGetHolelistGlobal(sourcevar) == NULL);
2119 
2120    result = SCIP_DIDNOTRUN;
2121    targetdata = NULL;
2122 
2123    if( SCIPvarGetStatus(sourcevar) == SCIP_VARSTATUS_ORIGINAL )
2124    {
2125       lb = SCIPvarGetLbOriginal(sourcevar);
2126       ub = SCIPvarGetUbOriginal(sourcevar);
2127    }
2128    else
2129    {
2130       lb = global ? SCIPvarGetLbGlobal(sourcevar) : SCIPvarGetLbLocal(sourcevar);
2131       ub = global ? SCIPvarGetUbGlobal(sourcevar) : SCIPvarGetUbLocal(sourcevar);
2132    }
2133 
2134    /* creates and captures the variable in the target SCIP and initialize callback methods and variable data to NULL */
2135    SCIP_CALL( SCIPvarCreateOriginal(var, blkmem, set, stat, SCIPvarGetName(sourcevar),
2136          lb, ub, SCIPvarGetObj(sourcevar), SCIPvarGetType(sourcevar),
2137          SCIPvarIsInitial(sourcevar), SCIPvarIsRemovable(sourcevar),
2138          NULL, NULL, NULL, NULL, NULL) );
2139    assert(*var != NULL);
2140 
2141    /* directly copy donotmultaggr flag */
2142    (*var)->donotmultaggr = sourcevar->donotmultaggr;
2143 
2144    /* insert variable into mapping between source SCIP and the target SCIP */
2145    assert(!SCIPhashmapExists(varmap, sourcevar));
2146    SCIP_CALL( SCIPhashmapInsert(varmap, sourcevar, *var) );
2147 
2148    /* in case there exists variable data and the variable data copy callback, try to copy variable data */
2149    if( sourcevar->vardata != NULL && sourcevar->varcopy != NULL )
2150    {
2151       SCIP_CALL( sourcevar->varcopy(set->scip, sourcescip, sourcevar, sourcevar->vardata,
2152             varmap, consmap, (*var), &targetdata, &result) );
2153 
2154       /* evaluate result */
2155       if( result != SCIP_DIDNOTRUN && result != SCIP_SUCCESS )
2156       {
2157          SCIPerrorMessage("variable data copying method returned invalid result <%d>\n", result);
2158          return SCIP_INVALIDRESULT;
2159       }
2160 
2161       assert(targetdata == NULL || result == SCIP_SUCCESS);
2162 
2163       /* if copying was successful, add the created variable data to the variable as well as all callback methods */
2164       if( result == SCIP_SUCCESS )
2165       {
2166          (*var)->varcopy = sourcevar->varcopy;
2167          (*var)->vardelorig = sourcevar->vardelorig;
2168          (*var)->vartrans = sourcevar->vartrans;
2169          (*var)->vardeltrans = sourcevar->vardeltrans;
2170          (*var)->vardata = targetdata;
2171       }
2172    }
2173 
2174    /* we initialize histories of the variables by copying the source variable-information */
2175    if( set->history_allowtransfer )
2176    {
2177       SCIPvarMergeHistories((*var), sourcevar, stat);
2178    }
2179 
2180    /* in case the copying was successfully, add the created variable data to the variable as well as all callback
2181     * methods
2182     */
2183    if( result == SCIP_SUCCESS )
2184    {
2185       (*var)->varcopy = sourcevar->varcopy;
2186       (*var)->vardelorig = sourcevar->vardelorig;
2187       (*var)->vartrans = sourcevar->vartrans;
2188       (*var)->vardeltrans = sourcevar->vardeltrans;
2189       (*var)->vardata = targetdata;
2190    }
2191 
2192    SCIPsetDebugMsg(set, "created copy <%s> of variable <%s>\n", SCIPvarGetName(*var), SCIPvarGetName(sourcevar));
2193 
2194    return SCIP_OKAY;
2195 }
2196 
2197 /** parse given string for a SCIP_Real bound */
2198 static
parseValue(SCIP_SET * set,const char * str,SCIP_Real * value,char ** endptr)2199 SCIP_RETCODE parseValue(
2200    SCIP_SET*             set,                /**< global SCIP settings */
2201    const char*           str,                /**< string to parse */
2202    SCIP_Real*            value,              /**< pointer to store the parsed value */
2203    char**                endptr              /**< pointer to store the final string position if successfully parsed */
2204    )
2205 {
2206    /* first check for infinity value */
2207    if( strncmp(str, "+inf", 4) == 0 )
2208    {
2209       *value = SCIPsetInfinity(set);
2210       (*endptr) = (char*)str + 4;
2211    }
2212    else if( strncmp(str, "-inf", 4) == 0 )
2213    {
2214       *value = -SCIPsetInfinity(set);
2215       (*endptr) = (char*)str + 4;
2216    }
2217    else
2218    {
2219       if( !SCIPstrToRealValue(str, value, endptr) )
2220       {
2221          SCIPerrorMessage("expected value: %s.\n", str);
2222          return SCIP_READERROR;
2223       }
2224    }
2225 
2226    return SCIP_OKAY;
2227 }
2228 
2229 /** parse the characters as bounds */
2230 static
parseBounds(SCIP_SET * set,const char * str,char * type,SCIP_Real * lb,SCIP_Real * ub,char ** endptr)2231 SCIP_RETCODE parseBounds(
2232    SCIP_SET*             set,                /**< global SCIP settings */
2233    const char*           str,                /**< string to parse */
2234    char*                 type,               /**< bound type (global, local, or lazy) */
2235    SCIP_Real*            lb,                 /**< pointer to store the lower bound */
2236    SCIP_Real*            ub,                 /**< pointer to store the upper bound */
2237    char**                endptr              /**< pointer to store the final string position if successfully parsed (or NULL if an error occured) */
2238    )
2239 {
2240    char token[SCIP_MAXSTRLEN];
2241    char* tmpend;
2242 
2243    SCIPsetDebugMsg(set, "parsing bounds: '%s'\n", str);
2244 
2245    /* get bound type */
2246    SCIPstrCopySection(str, ' ', ' ', type, SCIP_MAXSTRLEN, endptr);
2247    if ( strncmp(type, "original", 8) != 0 && strncmp(type, "global", 6) != 0 && strncmp(type, "local", 5) != 0 && strncmp(type, "lazy", 4) != 0 )
2248    {
2249       SCIPsetDebugMsg(set, "unkown bound type <%s>\n", type);
2250       *endptr = NULL;
2251       return SCIP_OKAY;
2252    }
2253 
2254    SCIPsetDebugMsg(set, "parsed bound type <%s>\n", type);
2255 
2256    /* get lower bound */
2257    SCIPstrCopySection(str, '[', ',', token, SCIP_MAXSTRLEN, endptr);
2258    str = *endptr;
2259    SCIP_CALL( parseValue(set, token, lb, &tmpend) );
2260 
2261    /* get upper bound */
2262    SCIP_CALL( parseValue(set, str, ub, endptr) );
2263 
2264    SCIPsetDebugMsg(set, "parsed bounds: [%g,%g]\n", *lb, *ub);
2265 
2266    /* skip end of bounds */
2267    while ( **endptr != '\0' && (**endptr == ']' || **endptr == ',') )
2268       ++(*endptr);
2269 
2270    return SCIP_OKAY;
2271 }
2272 
2273 /** parses a given string for a variable informations */
2274 static
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)2275 SCIP_RETCODE varParse(
2276    SCIP_SET*             set,                /**< global SCIP settings */
2277    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
2278    const char*           str,                /**< string to parse */
2279    char*                 name,               /**< pointer to store the variable name */
2280    SCIP_Real*            lb,                 /**< pointer to store the lower bound */
2281    SCIP_Real*            ub,                 /**< pointer to store the upper bound */
2282    SCIP_Real*            obj,                /**< pointer to store the objective coefficient */
2283    SCIP_VARTYPE*         vartype,            /**< pointer to store the variable type */
2284    SCIP_Real*            lazylb,             /**< pointer to store if the lower bound is lazy */
2285    SCIP_Real*            lazyub,             /**< pointer to store if the upper bound is lazy */
2286    SCIP_Bool             local,              /**< should the local bound be applied */
2287    char**                endptr,             /**< pointer to store the final string position if successfully */
2288    SCIP_Bool*            success             /**< pointer store if the paring process was successful */
2289    )
2290 {
2291    SCIP_Real parsedlb;
2292    SCIP_Real parsedub;
2293    char token[SCIP_MAXSTRLEN];
2294    char* strptr;
2295    int i;
2296 
2297    assert(lb != NULL);
2298    assert(ub != NULL);
2299    assert(obj != NULL);
2300    assert(vartype != NULL);
2301    assert(lazylb != NULL);
2302    assert(lazyub != NULL);
2303    assert(success != NULL);
2304 
2305    (*success) = TRUE;
2306 
2307    /* copy variable type */
2308    SCIPstrCopySection(str, '[', ']', token, SCIP_MAXSTRLEN, endptr);
2309    assert(str != *endptr);
2310    SCIPsetDebugMsg(set, "parsed variable type <%s>\n", token);
2311 
2312    /* get variable type */
2313    if( strncmp(token, "binary", 3) == 0 )
2314       (*vartype) = SCIP_VARTYPE_BINARY;
2315    else if( strncmp(token, "integer", 3) == 0 )
2316       (*vartype) = SCIP_VARTYPE_INTEGER;
2317    else if( strncmp(token, "implicit", 3) == 0 )
2318       (*vartype) = SCIP_VARTYPE_IMPLINT;
2319    else if( strncmp(token, "continuous", 3) == 0 )
2320       (*vartype) = SCIP_VARTYPE_CONTINUOUS;
2321    else
2322    {
2323       SCIPmessagePrintWarning(messagehdlr, "unknown variable type\n");
2324       (*success) = FALSE;
2325       return SCIP_OKAY;
2326    }
2327 
2328    /* move string pointer behind variable type */
2329    str = *endptr;
2330 
2331    /* get variable name */
2332    SCIPstrCopySection(str, '<', '>', name, SCIP_MAXSTRLEN, endptr);
2333    assert(endptr != NULL);
2334    SCIPsetDebugMsg(set, "parsed variable name <%s>\n", name);
2335 
2336    /* move string pointer behind variable name */
2337    str = *endptr;
2338 
2339    /* cut out objective coefficient */
2340    SCIPstrCopySection(str, '=', ',', token, SCIP_MAXSTRLEN, endptr);
2341 
2342    /* move string pointer behind objective coefficient */
2343    str = *endptr;
2344 
2345    /* get objective coefficient */
2346    if( !SCIPstrToRealValue(token, obj, endptr) )
2347    {
2348       *endptr = NULL;
2349       return SCIP_READERROR;
2350    }
2351 
2352    SCIPsetDebugMsg(set, "parsed objective coefficient <%g>\n", *obj);
2353 
2354    /* parse global/original bounds */
2355    SCIP_CALL( parseBounds(set, str, token, lb, ub, endptr) );
2356    if ( *endptr == NULL )
2357    {
2358       SCIPerrorMessage("Expected bound type: %s.\n", token);
2359       return SCIP_READERROR;
2360    }
2361    assert(strncmp(token, "global", 6) == 0 || strncmp(token, "original", 8) == 0);
2362 
2363    /* initialize the lazy bound */
2364    *lazylb = -SCIPsetInfinity(set);
2365    *lazyub =  SCIPsetInfinity(set);
2366 
2367    /* store pointer */
2368    strptr = *endptr;
2369 
2370    /* possibly parse optional local and lazy bounds */
2371    for( i = 0; i < 2 && *endptr != NULL && **endptr != '\0'; ++i )
2372    {
2373       /* start after previous bounds */
2374       strptr = *endptr;
2375 
2376       /* parse global bounds */
2377       SCIP_CALL( parseBounds(set, strptr, token, &parsedlb, &parsedub, endptr) );
2378 
2379       /* stop if parsing of bounds failed */
2380       if( *endptr == NULL )
2381          break;
2382 
2383       if( strncmp(token, "local", 5) == 0 && local )
2384       {
2385          *lb = parsedlb;
2386          *ub = parsedub;
2387       }
2388       else if( strncmp(token, "lazy", 4) == 0 )
2389       {
2390          *lazylb = parsedlb;
2391          *lazyub = parsedub;
2392       }
2393    }
2394 
2395    /* restore pointer */
2396    if ( *endptr == NULL )
2397       *endptr = strptr;
2398 
2399    /* check bounds for binary variables */
2400    if ( (*vartype) == SCIP_VARTYPE_BINARY )
2401    {
2402       if ( SCIPsetIsLT(set, *lb, 0.0) || SCIPsetIsGT(set, *ub, 1.0) )
2403       {
2404          SCIPerrorMessage("Parsed invalid bounds for binary variable <%s>: [%f, %f].\n", name, *lb, *ub);
2405          return SCIP_READERROR;
2406       }
2407       if ( !SCIPsetIsInfinity(set, -(*lazylb)) && !SCIPsetIsInfinity(set, *lazyub) &&
2408            ( SCIPsetIsLT(set, *lazylb, 0.0) || SCIPsetIsGT(set, *lazyub, 1.0) ) )
2409       {
2410          SCIPerrorMessage("Parsed invalid lazy bounds for binary variable <%s>: [%f, %f].\n", name, *lazylb, *lazyub);
2411          return SCIP_READERROR;
2412       }
2413    }
2414 
2415    return SCIP_OKAY;
2416 }
2417 
2418 /** parses variable information (in cip format) out of a string; if the parsing process was successful an original
2419  *  variable is created and captured; if variable is of integral type, fractional bounds are automatically rounded; an
2420  *  integer variable with bounds zero and one is automatically converted into a binary variable
2421  */
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)2422 SCIP_RETCODE SCIPvarParseOriginal(
2423    SCIP_VAR**            var,                /**< pointer to variable data */
2424    BMS_BLKMEM*           blkmem,             /**< block memory */
2425    SCIP_SET*             set,                /**< global SCIP settings */
2426    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
2427    SCIP_STAT*            stat,               /**< problem statistics */
2428    const char*           str,                /**< string to parse */
2429    SCIP_Bool             initial,            /**< should var's column be present in the initial root LP? */
2430    SCIP_Bool             removable,          /**< is var's column removable from the LP (due to aging or cleanup)? */
2431    SCIP_DECL_VARCOPY     ((*varcopy)),       /**< copies variable data if wanted to subscip, or NULL */
2432    SCIP_DECL_VARDELORIG  ((*vardelorig)),    /**< frees user data of original variable */
2433    SCIP_DECL_VARTRANS    ((*vartrans)),      /**< creates transformed user data by transforming original user data */
2434    SCIP_DECL_VARDELTRANS ((*vardeltrans)),   /**< frees user data of transformed variable */
2435    SCIP_VARDATA*         vardata,            /**< user data for this specific variable */
2436    char**                endptr,             /**< pointer to store the final string position if successfully */
2437    SCIP_Bool*            success             /**< pointer store if the paring process was successful */
2438    )
2439 {
2440    char name[SCIP_MAXSTRLEN];
2441    SCIP_Real lb;
2442    SCIP_Real ub;
2443    SCIP_Real obj;
2444    SCIP_VARTYPE vartype;
2445    SCIP_Real lazylb;
2446    SCIP_Real lazyub;
2447 
2448    assert(var != NULL);
2449    assert(blkmem != NULL);
2450    assert(stat != NULL);
2451    assert(endptr != NULL);
2452    assert(success != NULL);
2453 
2454    /* parse string in cip format for variable information */
2455    SCIP_CALL( varParse(set, messagehdlr, str, name, &lb, &ub, &obj, &vartype, &lazylb, &lazyub, FALSE, endptr, success) );
2456 
2457    if( *success ) /*lint !e774*/
2458    {
2459       /* create variable */
2460       SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2461             varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2462 
2463       /* set variable status and data */
2464       (*var)->varstatus = SCIP_VARSTATUS_ORIGINAL; /*lint !e641*/
2465       (*var)->data.original.origdom.holelist = NULL;
2466       (*var)->data.original.origdom.lb = lb;
2467       (*var)->data.original.origdom.ub = ub;
2468       (*var)->data.original.transvar = NULL;
2469 
2470       /* set lazy status of variable bounds */
2471       (*var)->lazylb = lazylb;
2472       (*var)->lazyub = lazyub;
2473 
2474       /* capture variable */
2475       SCIPvarCapture(*var);
2476    }
2477 
2478    return SCIP_OKAY;
2479 }
2480 
2481 /** parses variable information (in cip format) out of a string; if the parsing process was successful a loose variable
2482  *  belonging to the transformed problem is created and captured; if variable is of integral type, fractional bounds are
2483  *  automatically rounded; an integer variable with bounds zero and one is automatically converted into a binary
2484  *  variable
2485  */
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)2486 SCIP_RETCODE SCIPvarParseTransformed(
2487    SCIP_VAR**            var,                /**< pointer to variable data */
2488    BMS_BLKMEM*           blkmem,             /**< block memory */
2489    SCIP_SET*             set,                /**< global SCIP settings */
2490    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
2491    SCIP_STAT*            stat,               /**< problem statistics */
2492    const char*           str,                /**< string to parse */
2493    SCIP_Bool             initial,            /**< should var's column be present in the initial root LP? */
2494    SCIP_Bool             removable,          /**< is var's column removable from the LP (due to aging or cleanup)? */
2495    SCIP_DECL_VARCOPY     ((*varcopy)),       /**< copies variable data if wanted to subscip, or NULL */
2496    SCIP_DECL_VARDELORIG  ((*vardelorig)),    /**< frees user data of original variable */
2497    SCIP_DECL_VARTRANS    ((*vartrans)),      /**< creates transformed user data by transforming original user data */
2498    SCIP_DECL_VARDELTRANS ((*vardeltrans)),   /**< frees user data of transformed variable */
2499    SCIP_VARDATA*         vardata,            /**< user data for this specific variable */
2500    char**                endptr,             /**< pointer to store the final string position if successfully */
2501    SCIP_Bool*            success             /**< pointer store if the paring process was successful */
2502    )
2503 {
2504    char name[SCIP_MAXSTRLEN];
2505    SCIP_Real lb;
2506    SCIP_Real ub;
2507    SCIP_Real obj;
2508    SCIP_VARTYPE vartype;
2509    SCIP_Real lazylb;
2510    SCIP_Real lazyub;
2511 
2512    assert(var != NULL);
2513    assert(blkmem != NULL);
2514    assert(endptr != NULL);
2515    assert(success != NULL);
2516 
2517    /* parse string in cip format for variable information */
2518    SCIP_CALL( varParse(set, messagehdlr, str, name, &lb, &ub, &obj, &vartype, &lazylb, &lazyub, TRUE, endptr, success) );
2519 
2520    if( *success ) /*lint !e774*/
2521    {
2522       /* create variable */
2523       SCIP_CALL( varCreate(var, blkmem, set, stat, name, lb, ub, obj, vartype, initial, removable,
2524             varcopy, vardelorig, vartrans, vardeltrans, vardata) );
2525 
2526       /* create event filter for transformed variable */
2527       SCIP_CALL( SCIPeventfilterCreate(&(*var)->eventfilter, blkmem) );
2528 
2529       /* set variable status and data */
2530       (*var)->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
2531 
2532       /* set lazy status of variable bounds */
2533       (*var)->lazylb = lazylb;
2534       (*var)->lazyub = lazyub;
2535 
2536       /* capture variable */
2537       SCIPvarCapture(*var);
2538    }
2539 
2540    return SCIP_OKAY;
2541 }
2542 
2543 /** ensures, that parentvars array of var can store at least num entries */
2544 static
varEnsureParentvarsSize(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)2545 SCIP_RETCODE varEnsureParentvarsSize(
2546    SCIP_VAR*             var,                /**< problem variable */
2547    BMS_BLKMEM*           blkmem,             /**< block memory */
2548    SCIP_SET*             set,                /**< global SCIP settings */
2549    int                   num                 /**< minimum number of entries to store */
2550    )
2551 {
2552    assert(var->nparentvars <= var->parentvarssize);
2553 
2554    if( num > var->parentvarssize )
2555    {
2556       int newsize;
2557 
2558       newsize = SCIPsetCalcMemGrowSize(set, num);
2559       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &var->parentvars, var->parentvarssize, newsize) );
2560       var->parentvarssize = newsize;
2561    }
2562    assert(num <= var->parentvarssize);
2563 
2564    return SCIP_OKAY;
2565 }
2566 
2567 /** adds variable to parent list of a variable and captures parent variable */
2568 static
varAddParent(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_VAR * parentvar)2569 SCIP_RETCODE varAddParent(
2570    SCIP_VAR*             var,                /**< variable to add parent to */
2571    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
2572    SCIP_SET*             set,                /**< global SCIP settings */
2573    SCIP_VAR*             parentvar           /**< parent variable to add */
2574    )
2575 {
2576    assert(var != NULL);
2577    assert(parentvar != NULL);
2578 
2579    /* the direct original counterpart must be stored as first parent */
2580    assert(var->nparentvars == 0 || SCIPvarGetStatus(parentvar) != SCIP_VARSTATUS_ORIGINAL);
2581 
2582    SCIPsetDebugMsg(set, "adding parent <%s>[%p] to variable <%s>[%p] in slot %d\n",
2583       parentvar->name, (void*)parentvar, var->name, (void*)var, var->nparentvars);
2584 
2585    SCIP_CALL( varEnsureParentvarsSize(var, blkmem, set, var->nparentvars+1) );
2586 
2587    var->parentvars[var->nparentvars] = parentvar;
2588    var->nparentvars++;
2589 
2590    SCIPvarCapture(parentvar);
2591 
2592    return SCIP_OKAY;
2593 }
2594 
2595 /** deletes and releases all variables from the parent list of a variable, frees the memory of parents array */
2596 static
varFreeParents(SCIP_VAR ** var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)2597 SCIP_RETCODE varFreeParents(
2598    SCIP_VAR**            var,                /**< pointer to variable */
2599    BMS_BLKMEM*           blkmem,             /**< block memory */
2600    SCIP_SET*             set,                /**< global SCIP settings */
2601    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue (or NULL, if it's an original variable) */
2602    SCIP_LP*              lp                  /**< current LP data (or NULL, if it's an original variable) */
2603    )
2604 {
2605    SCIP_VAR* parentvar;
2606    int i;
2607 
2608    SCIPsetDebugMsg(set, "free parents of <%s>\n", (*var)->name);
2609 
2610    /* release the parent variables and remove the link from the parent variable to the child */
2611    for( i = 0; i < (*var)->nparentvars; ++i )
2612    {
2613       assert((*var)->parentvars != NULL);
2614       parentvar = (*var)->parentvars[i];
2615       assert(parentvar != NULL);
2616 
2617       switch( SCIPvarGetStatus(parentvar) )
2618       {
2619       case SCIP_VARSTATUS_ORIGINAL:
2620          assert(parentvar->data.original.transvar == *var);
2621          assert(&parentvar->data.original.transvar != var);
2622          parentvar->data.original.transvar = NULL;
2623          break;
2624 
2625       case SCIP_VARSTATUS_AGGREGATED:
2626          assert(parentvar->data.aggregate.var == *var);
2627          assert(&parentvar->data.aggregate.var != var);
2628          parentvar->data.aggregate.var = NULL;
2629          break;
2630 
2631 #if 0
2632       /* The following code is unclear: should the current variable be removed from its parents? */
2633       case SCIP_VARSTATUS_MULTAGGR:
2634          assert(parentvar->data.multaggr.vars != NULL);
2635          for( v = 0; v < parentvar->data.multaggr.nvars && parentvar->data.multaggr.vars[v] != *var; ++v )
2636          {}
2637          assert(v < parentvar->data.multaggr.nvars && parentvar->data.multaggr.vars[v] == *var);
2638          if( v < parentvar->data.multaggr.nvars-1 )
2639          {
2640             parentvar->data.multaggr.vars[v] = parentvar->data.multaggr.vars[parentvar->data.multaggr.nvars-1];
2641             parentvar->data.multaggr.scalars[v] = parentvar->data.multaggr.scalars[parentvar->data.multaggr.nvars-1];
2642          }
2643          parentvar->data.multaggr.nvars--;
2644          break;
2645 #endif
2646 
2647       case SCIP_VARSTATUS_NEGATED:
2648          assert(parentvar->negatedvar == *var);
2649          assert((*var)->negatedvar == parentvar);
2650          parentvar->negatedvar = NULL;
2651          (*var)->negatedvar = NULL;
2652          break;
2653 
2654       default:
2655          SCIPerrorMessage("parent variable is neither ORIGINAL, AGGREGATED nor NEGATED\n");
2656          return SCIP_INVALIDDATA;
2657       }  /*lint !e788*/
2658 
2659       SCIP_CALL( SCIPvarRelease(&(*var)->parentvars[i], blkmem, set, eventqueue, lp) );
2660    }
2661 
2662    /* free parentvars array */
2663    BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->parentvars, (*var)->parentvarssize);
2664 
2665    return SCIP_OKAY;
2666 }
2667 
2668 /** frees a variable */
2669 static
varFree(SCIP_VAR ** var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)2670 SCIP_RETCODE varFree(
2671    SCIP_VAR**            var,                /**< pointer to variable */
2672    BMS_BLKMEM*           blkmem,             /**< block memory */
2673    SCIP_SET*             set,                /**< global SCIP settings */
2674    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue (may be NULL, if it's not a column variable) */
2675    SCIP_LP*              lp                  /**< current LP data (may be NULL, if it's not a column variable) */
2676    )
2677 {
2678    assert(var != NULL);
2679    assert(*var != NULL);
2680    assert(SCIPvarGetStatus(*var) != SCIP_VARSTATUS_COLUMN || &(*var)->data.col->var != var);
2681    assert((*var)->nuses == 0);
2682    assert((*var)->probindex == -1);
2683    assert((*var)->nlocksup[SCIP_LOCKTYPE_MODEL] == 0);
2684    assert((*var)->nlocksdown[SCIP_LOCKTYPE_MODEL] == 0);
2685 
2686    SCIPsetDebugMsg(set, "free variable <%s> with status=%d\n", (*var)->name, SCIPvarGetStatus(*var));
2687 
2688    switch( SCIPvarGetStatus(*var) )
2689    {
2690    case SCIP_VARSTATUS_ORIGINAL:
2691       assert((*var)->data.original.transvar == NULL); /* cannot free variable, if transformed variable is still existing */
2692       holelistFree(&(*var)->data.original.origdom.holelist, blkmem);
2693       assert((*var)->data.original.origdom.holelist == NULL);
2694       break;
2695    case SCIP_VARSTATUS_LOOSE:
2696       break;
2697    case SCIP_VARSTATUS_COLUMN:
2698       SCIP_CALL( SCIPcolFree(&(*var)->data.col, blkmem, set, eventqueue, lp) );  /* free corresponding LP column */
2699       break;
2700    case SCIP_VARSTATUS_FIXED:
2701    case SCIP_VARSTATUS_AGGREGATED:
2702       break;
2703    case SCIP_VARSTATUS_MULTAGGR:
2704       BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.vars, (*var)->data.multaggr.varssize);
2705       BMSfreeBlockMemoryArray(blkmem, &(*var)->data.multaggr.scalars, (*var)->data.multaggr.varssize);
2706       break;
2707    case SCIP_VARSTATUS_NEGATED:
2708       break;
2709    default:
2710       SCIPerrorMessage("unknown variable status\n");
2711       return SCIP_INVALIDDATA;
2712    }
2713 
2714    /* release all parent variables and free the parentvars array */
2715    SCIP_CALL( varFreeParents(var, blkmem, set, eventqueue, lp) );
2716 
2717    /* free user data */
2718    if( SCIPvarGetStatus(*var) == SCIP_VARSTATUS_ORIGINAL )
2719    {
2720       if( (*var)->vardelorig != NULL )
2721       {
2722          SCIP_CALL( (*var)->vardelorig(set->scip, *var, &(*var)->vardata) );
2723       }
2724    }
2725    else
2726    {
2727       if( (*var)->vardeltrans != NULL )
2728       {
2729          SCIP_CALL( (*var)->vardeltrans(set->scip, *var, &(*var)->vardata) );
2730       }
2731    }
2732 
2733    /* free event filter */
2734    if( (*var)->eventfilter != NULL )
2735    {
2736       SCIP_CALL( SCIPeventfilterFree(&(*var)->eventfilter, blkmem, set) );
2737    }
2738    assert((*var)->eventfilter == NULL);
2739 
2740    /* free hole lists */
2741    holelistFree(&(*var)->glbdom.holelist, blkmem);
2742    holelistFree(&(*var)->locdom.holelist, blkmem);
2743    assert((*var)->glbdom.holelist == NULL);
2744    assert((*var)->locdom.holelist == NULL);
2745 
2746    /* free variable bounds data structures */
2747    SCIPvboundsFree(&(*var)->vlbs, blkmem);
2748    SCIPvboundsFree(&(*var)->vubs, blkmem);
2749 
2750    /* free implications data structures */
2751    SCIPimplicsFree(&(*var)->implics, blkmem);
2752 
2753    /* free clique list data structures */
2754    SCIPcliquelistFree(&(*var)->cliquelist, blkmem);
2755 
2756    /* free bound change information arrays */
2757    BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->lbchginfos, (*var)->lbchginfossize);
2758    BMSfreeBlockMemoryArrayNull(blkmem, &(*var)->ubchginfos, (*var)->ubchginfossize);
2759 
2760    /* free branching and inference history entries */
2761    SCIPhistoryFree(&(*var)->history, blkmem);
2762    SCIPhistoryFree(&(*var)->historycrun, blkmem);
2763    SCIPvaluehistoryFree(&(*var)->valuehistory, blkmem);
2764 
2765    /* free variable data structure */
2766    BMSfreeBlockMemoryArray(blkmem, &(*var)->name, strlen((*var)->name)+1);
2767    BMSfreeBlockMemory(blkmem, var);
2768 
2769    return SCIP_OKAY;
2770 }
2771 
2772 /** increases usage counter of variable */
SCIPvarCapture(SCIP_VAR * var)2773 void SCIPvarCapture(
2774    SCIP_VAR*             var                 /**< variable */
2775    )
2776 {
2777    assert(var != NULL);
2778    assert(var->nuses >= 0);
2779 
2780    SCIPdebugMessage("capture variable <%s> with nuses=%d\n", var->name, var->nuses);
2781    var->nuses++;
2782 }
2783 
2784 /** decreases usage counter of variable, and frees memory if necessary */
SCIPvarRelease(SCIP_VAR ** var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)2785 SCIP_RETCODE SCIPvarRelease(
2786    SCIP_VAR**            var,                /**< pointer to variable */
2787    BMS_BLKMEM*           blkmem,             /**< block memory */
2788    SCIP_SET*             set,                /**< global SCIP settings */
2789    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2790    SCIP_LP*              lp                  /**< current LP data (or NULL, if it's an original variable) */
2791    )
2792 {
2793    assert(var != NULL);
2794    assert(*var != NULL);
2795    assert((*var)->nuses >= 1);
2796    assert(blkmem != NULL);
2797    assert((*var)->scip == set->scip);
2798 
2799    SCIPsetDebugMsg(set, "release variable <%s> with nuses=%d\n", (*var)->name, (*var)->nuses);
2800    (*var)->nuses--;
2801    if( (*var)->nuses == 0 )
2802    {
2803       SCIP_CALL( varFree(var, blkmem, set, eventqueue, lp) );
2804    }
2805 
2806    *var = NULL;
2807 
2808    return SCIP_OKAY;
2809 }
2810 
2811 /** change variable name */
SCIPvarChgName(SCIP_VAR * var,BMS_BLKMEM * blkmem,const char * name)2812 SCIP_RETCODE SCIPvarChgName(
2813    SCIP_VAR*             var,                /**< problem variable */
2814    BMS_BLKMEM*           blkmem,             /**< block memory */
2815    const char*           name                /**< name of variable */
2816    )
2817 {
2818    assert(name != NULL);
2819 
2820    /* remove old variable name */
2821    BMSfreeBlockMemoryArray(blkmem, &var->name, strlen(var->name)+1);
2822 
2823    /* set new variable name */
2824    SCIP_CALL( varSetName(var, blkmem, NULL, name) );
2825 
2826    return SCIP_OKAY;
2827 }
2828 
2829 /** initializes variable data structure for solving */
SCIPvarInitSolve(SCIP_VAR * var)2830 void SCIPvarInitSolve(
2831    SCIP_VAR*             var                 /**< problem variable */
2832    )
2833 {
2834    assert(var != NULL);
2835 
2836    SCIPhistoryReset(var->historycrun);
2837    var->conflictlbcount = 0;
2838    var->conflictubcount = 0;
2839 }
2840 
2841 /** outputs the given bounds into the file stream */
2842 static
printBounds(SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,FILE * file,SCIP_Real lb,SCIP_Real ub,const char * name)2843 void printBounds(
2844    SCIP_SET*             set,                /**< global SCIP settings */
2845    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
2846    FILE*                 file,               /**< output file (or NULL for standard output) */
2847    SCIP_Real             lb,                 /**< lower bound */
2848    SCIP_Real             ub,                 /**< upper bound */
2849    const char*           name                /**< bound type name */
2850    )
2851 {
2852    assert(set != NULL);
2853 
2854    SCIPmessageFPrintInfo(messagehdlr, file, ", %s=", name);
2855    if( SCIPsetIsInfinity(set, lb) )
2856       SCIPmessageFPrintInfo(messagehdlr, file, "[+inf,");
2857    else if( SCIPsetIsInfinity(set, -lb) )
2858       SCIPmessageFPrintInfo(messagehdlr, file, "[-inf,");
2859    else
2860       SCIPmessageFPrintInfo(messagehdlr, file, "[%.15g,", lb);
2861    if( SCIPsetIsInfinity(set, ub) )
2862       SCIPmessageFPrintInfo(messagehdlr, file, "+inf]");
2863    else if( SCIPsetIsInfinity(set, -ub) )
2864       SCIPmessageFPrintInfo(messagehdlr, file, "-inf]");
2865    else
2866       SCIPmessageFPrintInfo(messagehdlr, file, "%.15g]", ub);
2867 }
2868 
2869 /** prints hole list to file stream */
2870 static
printHolelist(SCIP_MESSAGEHDLR * messagehdlr,FILE * file,SCIP_HOLELIST * holelist,const char * name)2871 void printHolelist(
2872    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
2873    FILE*                 file,               /**< output file (or NULL for standard output) */
2874    SCIP_HOLELIST*        holelist,           /**< hole list pointer to hole of interest */
2875    const char*           name                /**< hole type name */
2876    )
2877 {  /*lint --e{715}*/
2878    SCIP_Real left;
2879    SCIP_Real right;
2880 
2881    if( holelist == NULL )
2882       return;
2883 
2884    left = SCIPholelistGetLeft(holelist);
2885    right = SCIPholelistGetRight(holelist);
2886 
2887    /* display first hole */
2888    SCIPmessageFPrintInfo(messagehdlr, file, ", %s=(%g,%g)", name, left, right);
2889    holelist = SCIPholelistGetNext(holelist);
2890 
2891    while(holelist != NULL  )
2892    {
2893       left = SCIPholelistGetLeft(holelist);
2894       right = SCIPholelistGetRight(holelist);
2895 
2896       /* display hole */
2897       SCIPmessageFPrintInfo(messagehdlr, file, "(%g,%g)", left, right);
2898 
2899       /* get next hole */
2900       holelist = SCIPholelistGetNext(holelist);
2901    }
2902 }
2903 
2904 /** outputs variable information into file stream */
SCIPvarPrint(SCIP_VAR * var,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,FILE * file)2905 SCIP_RETCODE SCIPvarPrint(
2906    SCIP_VAR*             var,                /**< problem variable */
2907    SCIP_SET*             set,                /**< global SCIP settings */
2908    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
2909    FILE*                 file                /**< output file (or NULL for standard output) */
2910    )
2911 {
2912    SCIP_HOLELIST* holelist;
2913    SCIP_Real lb;
2914    SCIP_Real ub;
2915    int i;
2916 
2917    assert(var != NULL);
2918    assert(var->scip == set->scip);
2919 
2920    /* type of variable */
2921    switch( SCIPvarGetType(var) )
2922    {
2923    case SCIP_VARTYPE_BINARY:
2924       SCIPmessageFPrintInfo(messagehdlr, file, "  [binary]");
2925       break;
2926    case SCIP_VARTYPE_INTEGER:
2927       SCIPmessageFPrintInfo(messagehdlr, file, "  [integer]");
2928       break;
2929    case SCIP_VARTYPE_IMPLINT:
2930       SCIPmessageFPrintInfo(messagehdlr, file, "  [implicit]");
2931       break;
2932    case SCIP_VARTYPE_CONTINUOUS:
2933       SCIPmessageFPrintInfo(messagehdlr, file, "  [continuous]");
2934       break;
2935    default:
2936       SCIPerrorMessage("unknown variable type\n");
2937       SCIPABORT();
2938       return SCIP_ERROR; /*lint !e527*/
2939    }
2940 
2941    /* name */
2942    SCIPmessageFPrintInfo(messagehdlr, file, " <%s>:", var->name);
2943 
2944    /* objective value */
2945    SCIPmessageFPrintInfo(messagehdlr, file, " obj=%.15g", var->obj);
2946 
2947    /* bounds (global bounds for transformed variables, original bounds for original variables) */
2948    if( !SCIPvarIsTransformed(var) )
2949    {
2950       /* output original bound */
2951       lb = SCIPvarGetLbOriginal(var);
2952       ub = SCIPvarGetUbOriginal(var);
2953       printBounds(set, messagehdlr, file, lb, ub, "original bounds");
2954 
2955       /* output lazy bound */
2956       lb = SCIPvarGetLbLazy(var);
2957       ub = SCIPvarGetUbLazy(var);
2958 
2959       /* only display the lazy bounds if they are different from [-infinity,infinity] */
2960       if( !SCIPsetIsInfinity(set, -lb) || !SCIPsetIsInfinity(set, ub) )
2961          printBounds(set, messagehdlr, file, lb, ub, "lazy bounds");
2962 
2963       holelist = SCIPvarGetHolelistOriginal(var);
2964       printHolelist(messagehdlr, file, holelist, "original holes");
2965    }
2966    else
2967    {
2968       /* output global bound */
2969       lb = SCIPvarGetLbGlobal(var);
2970       ub = SCIPvarGetUbGlobal(var);
2971       printBounds(set, messagehdlr, file, lb, ub, "global bounds");
2972 
2973       /* output local bound */
2974       lb = SCIPvarGetLbLocal(var);
2975       ub = SCIPvarGetUbLocal(var);
2976       printBounds(set, messagehdlr, file, lb, ub, "local bounds");
2977 
2978       /* output lazy bound */
2979       lb = SCIPvarGetLbLazy(var);
2980       ub = SCIPvarGetUbLazy(var);
2981 
2982       /* only display the lazy bounds if they are different from [-infinity,infinity] */
2983       if( !SCIPsetIsInfinity(set, -lb) || !SCIPsetIsInfinity(set, ub) )
2984          printBounds(set, messagehdlr, file, lb, ub, "lazy bounds");
2985 
2986       /* global hole list */
2987       holelist = SCIPvarGetHolelistGlobal(var);
2988       printHolelist(messagehdlr, file, holelist, "global holes");
2989 
2990       /* local hole list */
2991       holelist = SCIPvarGetHolelistLocal(var);
2992       printHolelist(messagehdlr, file, holelist, "local holes");
2993    }
2994 
2995    /* fixings and aggregations */
2996    switch( SCIPvarGetStatus(var) )
2997    {
2998    case SCIP_VARSTATUS_ORIGINAL:
2999    case SCIP_VARSTATUS_LOOSE:
3000    case SCIP_VARSTATUS_COLUMN:
3001       break;
3002 
3003    case SCIP_VARSTATUS_FIXED:
3004       SCIPmessageFPrintInfo(messagehdlr, file, ", fixed:");
3005       if( SCIPsetIsInfinity(set, var->glbdom.lb) )
3006          SCIPmessageFPrintInfo(messagehdlr, file, "+inf");
3007       else if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
3008          SCIPmessageFPrintInfo(messagehdlr, file, "-inf");
3009       else
3010          SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", var->glbdom.lb);
3011       break;
3012 
3013    case SCIP_VARSTATUS_AGGREGATED:
3014       SCIPmessageFPrintInfo(messagehdlr, file, ", aggregated:");
3015       if( !SCIPsetIsZero(set, var->data.aggregate.constant) )
3016          SCIPmessageFPrintInfo(messagehdlr, file, " %.15g", var->data.aggregate.constant);
3017       SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g<%s>", var->data.aggregate.scalar, SCIPvarGetName(var->data.aggregate.var));
3018       break;
3019 
3020    case SCIP_VARSTATUS_MULTAGGR:
3021       SCIPmessageFPrintInfo(messagehdlr, file, ", aggregated:");
3022       if( var->data.multaggr.nvars == 0 || !SCIPsetIsZero(set, var->data.multaggr.constant) )
3023          SCIPmessageFPrintInfo(messagehdlr, file, " %.15g", var->data.multaggr.constant);
3024       for( i = 0; i < var->data.multaggr.nvars; ++i )
3025          SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g<%s>", var->data.multaggr.scalars[i], SCIPvarGetName(var->data.multaggr.vars[i]));
3026       break;
3027 
3028    case SCIP_VARSTATUS_NEGATED:
3029       SCIPmessageFPrintInfo(messagehdlr, file, ", negated: %.15g - <%s>", var->data.negate.constant, SCIPvarGetName(var->negatedvar));
3030       break;
3031 
3032    default:
3033       SCIPerrorMessage("unknown variable status\n");
3034       SCIPABORT();
3035       return SCIP_ERROR; /*lint !e527*/
3036    }
3037 
3038    SCIPmessageFPrintInfo(messagehdlr, file, "\n");
3039 
3040    return SCIP_OKAY;
3041 }
3042 
3043 /** issues a VARUNLOCKED event on the given variable */
3044 static
varEventVarUnlocked(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue)3045 SCIP_RETCODE varEventVarUnlocked(
3046    SCIP_VAR*             var,                /**< problem variable to change */
3047    BMS_BLKMEM*           blkmem,             /**< block memory */
3048    SCIP_SET*             set,                /**< global SCIP settings */
3049    SCIP_EVENTQUEUE*      eventqueue          /**< event queue */
3050    )
3051 {
3052    SCIP_EVENT* event;
3053 
3054    assert(var != NULL);
3055    assert(var->nlocksdown[SCIP_LOCKTYPE_MODEL] <= 1 && var->nlocksup[SCIP_LOCKTYPE_MODEL] <= 1);
3056    assert(var->scip == set->scip);
3057 
3058    /* issue VARUNLOCKED event on variable */
3059    SCIP_CALL( SCIPeventCreateVarUnlocked(&event, blkmem, var) );
3060    SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
3061 
3062    return SCIP_OKAY;
3063 }
3064 
3065 /** modifies lock numbers for rounding */
SCIPvarAddLocks(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LOCKTYPE locktype,int addnlocksdown,int addnlocksup)3066 SCIP_RETCODE SCIPvarAddLocks(
3067    SCIP_VAR*             var,                /**< problem variable */
3068    BMS_BLKMEM*           blkmem,             /**< block memory */
3069    SCIP_SET*             set,                /**< global SCIP settings */
3070    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3071    SCIP_LOCKTYPE         locktype,           /**< type of the variable locks */
3072    int                   addnlocksdown,      /**< increase in number of rounding down locks */
3073    int                   addnlocksup         /**< increase in number of rounding up locks */
3074    )
3075 {
3076    SCIP_VAR* lockvar;
3077 
3078    assert(var != NULL);
3079    assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/
3080    assert(var->nlocksup[locktype] >= 0);
3081    assert(var->nlocksdown[locktype] >= 0);
3082    assert(var->scip == set->scip);
3083 
3084    if( addnlocksdown == 0 && addnlocksup == 0 )
3085       return SCIP_OKAY;
3086 
3087 #ifdef SCIP_DEBUG
3088    SCIPsetDebugMsg(set, "add rounding locks %d/%d to variable <%s> (locks=%d/%d, type=%u)\n",
3089          addnlocksdown, addnlocksup, var->name, var->nlocksdown[locktype], var->nlocksup[locktype], locktype);
3090 #endif
3091 
3092    lockvar = var;
3093 
3094    while( TRUE ) /*lint !e716 */
3095    {
3096       assert(lockvar != NULL);
3097 
3098       switch( SCIPvarGetStatus(lockvar) )
3099       {
3100       case SCIP_VARSTATUS_ORIGINAL:
3101          if( lockvar->data.original.transvar != NULL )
3102          {
3103             lockvar = lockvar->data.original.transvar;
3104             break;
3105          }
3106          else
3107          {
3108             lockvar->nlocksdown[locktype] += addnlocksdown;
3109             lockvar->nlocksup[locktype] += addnlocksup;
3110 
3111             assert(lockvar->nlocksdown[locktype] >= 0);
3112             assert(lockvar->nlocksup[locktype] >= 0);
3113 
3114             return SCIP_OKAY;
3115          }
3116       case SCIP_VARSTATUS_LOOSE:
3117       case SCIP_VARSTATUS_COLUMN:
3118       case SCIP_VARSTATUS_FIXED:
3119          lockvar->nlocksdown[locktype] += addnlocksdown;
3120          lockvar->nlocksup[locktype] += addnlocksup;
3121 
3122          assert(lockvar->nlocksdown[locktype] >= 0);
3123          assert(lockvar->nlocksup[locktype] >= 0);
3124 
3125          if( locktype == SCIP_LOCKTYPE_MODEL && lockvar->nlocksdown[locktype] <= 1
3126             && lockvar->nlocksup[locktype] <= 1 )
3127          {
3128             SCIP_CALL( varEventVarUnlocked(lockvar, blkmem, set, eventqueue) );
3129          }
3130 
3131          return SCIP_OKAY;
3132       case SCIP_VARSTATUS_AGGREGATED:
3133          if( lockvar->data.aggregate.scalar < 0.0 )
3134          {
3135             int tmp = addnlocksup;
3136 
3137             addnlocksup = addnlocksdown;
3138             addnlocksdown = tmp;
3139          }
3140 
3141          lockvar = lockvar->data.aggregate.var;
3142          break;
3143       case SCIP_VARSTATUS_MULTAGGR:
3144       {
3145          int v;
3146 
3147          assert(!lockvar->donotmultaggr);
3148 
3149          lockvar->nlocksdown[locktype] += addnlocksdown;
3150          lockvar->nlocksup[locktype] += addnlocksup;
3151 
3152          assert(lockvar->nlocksdown[locktype] >= 0);
3153          assert(lockvar->nlocksup[locktype] >= 0);
3154 
3155          for( v = lockvar->data.multaggr.nvars - 1; v >= 0; --v )
3156          {
3157             if( lockvar->data.multaggr.scalars[v] > 0.0 )
3158             {
3159                SCIP_CALL( SCIPvarAddLocks(lockvar->data.multaggr.vars[v], blkmem, set, eventqueue, locktype, addnlocksdown,
3160                      addnlocksup) );
3161             }
3162             else
3163             {
3164                SCIP_CALL( SCIPvarAddLocks(lockvar->data.multaggr.vars[v], blkmem, set, eventqueue, locktype, addnlocksup,
3165                      addnlocksdown) );
3166             }
3167          }
3168          return SCIP_OKAY;
3169       }
3170       case SCIP_VARSTATUS_NEGATED:
3171       {
3172          int tmp = addnlocksup;
3173 
3174          assert(lockvar->negatedvar != NULL);
3175          assert(SCIPvarGetStatus(lockvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
3176          assert(lockvar->negatedvar->negatedvar == lockvar);
3177 
3178          addnlocksup = addnlocksdown;
3179          addnlocksdown = tmp;
3180 
3181          lockvar = lockvar->negatedvar;
3182          break;
3183       }
3184       default:
3185          SCIPerrorMessage("unknown variable status\n");
3186          return SCIP_INVALIDDATA;
3187       }
3188    }
3189 }
3190 
3191 /** gets number of locks for rounding down of a special type */
SCIPvarGetNLocksDownType(SCIP_VAR * var,SCIP_LOCKTYPE locktype)3192 int SCIPvarGetNLocksDownType(
3193    SCIP_VAR*             var,                /**< problem variable */
3194    SCIP_LOCKTYPE         locktype            /**< type of variable locks */
3195    )
3196 {
3197    int nlocks;
3198    int i;
3199 
3200    assert(var != NULL);
3201    assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/
3202    assert(var->nlocksdown[locktype] >= 0);
3203 
3204    switch( SCIPvarGetStatus(var) )
3205    {
3206    case SCIP_VARSTATUS_ORIGINAL:
3207       if( var->data.original.transvar != NULL )
3208          return SCIPvarGetNLocksDownType(var->data.original.transvar, locktype);
3209       else
3210          return var->nlocksdown[locktype];
3211 
3212    case SCIP_VARSTATUS_LOOSE:
3213    case SCIP_VARSTATUS_COLUMN:
3214    case SCIP_VARSTATUS_FIXED:
3215       return var->nlocksdown[locktype];
3216 
3217    case SCIP_VARSTATUS_AGGREGATED:
3218       if( var->data.aggregate.scalar > 0.0 )
3219          return SCIPvarGetNLocksDownType(var->data.aggregate.var, locktype);
3220       else
3221          return SCIPvarGetNLocksUpType(var->data.aggregate.var, locktype);
3222 
3223    case SCIP_VARSTATUS_MULTAGGR:
3224       assert(!var->donotmultaggr);
3225       nlocks = 0;
3226       for( i = 0; i < var->data.multaggr.nvars; ++i )
3227       {
3228          if( var->data.multaggr.scalars[i] > 0.0 )
3229             nlocks += SCIPvarGetNLocksDownType(var->data.multaggr.vars[i], locktype);
3230          else
3231             nlocks += SCIPvarGetNLocksUpType(var->data.multaggr.vars[i], locktype);
3232       }
3233       return nlocks;
3234 
3235    case SCIP_VARSTATUS_NEGATED:
3236       assert(var->negatedvar != NULL);
3237       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
3238       assert(var->negatedvar->negatedvar == var);
3239       return SCIPvarGetNLocksUpType(var->negatedvar, locktype);
3240 
3241    default:
3242       SCIPerrorMessage("unknown variable status\n");
3243       SCIPABORT();
3244       return INT_MAX; /*lint !e527*/
3245    }
3246 }
3247 
3248 /** gets number of locks for rounding up of a special type */
SCIPvarGetNLocksUpType(SCIP_VAR * var,SCIP_LOCKTYPE locktype)3249 int SCIPvarGetNLocksUpType(
3250    SCIP_VAR*             var,                /**< problem variable */
3251    SCIP_LOCKTYPE         locktype            /**< type of variable locks */
3252    )
3253 {
3254    int nlocks;
3255    int i;
3256 
3257    assert(var != NULL);
3258    assert((int)locktype >= 0 && (int)locktype < (int)NLOCKTYPES); /*lint !e685 !e568 !e587 !e650*/
3259    assert(var->nlocksup[locktype] >= 0);
3260 
3261    switch( SCIPvarGetStatus(var) )
3262    {
3263    case SCIP_VARSTATUS_ORIGINAL:
3264       if( var->data.original.transvar != NULL )
3265          return SCIPvarGetNLocksUpType(var->data.original.transvar, locktype);
3266       else
3267          return var->nlocksup[locktype];
3268 
3269    case SCIP_VARSTATUS_LOOSE:
3270    case SCIP_VARSTATUS_COLUMN:
3271    case SCIP_VARSTATUS_FIXED:
3272       return var->nlocksup[locktype];
3273 
3274    case SCIP_VARSTATUS_AGGREGATED:
3275       if( var->data.aggregate.scalar > 0.0 )
3276          return SCIPvarGetNLocksUpType(var->data.aggregate.var, locktype);
3277       else
3278          return SCIPvarGetNLocksDownType(var->data.aggregate.var, locktype);
3279 
3280    case SCIP_VARSTATUS_MULTAGGR:
3281       assert(!var->donotmultaggr);
3282       nlocks = 0;
3283       for( i = 0; i < var->data.multaggr.nvars; ++i )
3284       {
3285          if( var->data.multaggr.scalars[i] > 0.0 )
3286             nlocks += SCIPvarGetNLocksUpType(var->data.multaggr.vars[i], locktype);
3287          else
3288             nlocks += SCIPvarGetNLocksDownType(var->data.multaggr.vars[i], locktype);
3289       }
3290       return nlocks;
3291 
3292    case SCIP_VARSTATUS_NEGATED:
3293       assert(var->negatedvar != NULL);
3294       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
3295       assert(var->negatedvar->negatedvar == var);
3296       return SCIPvarGetNLocksDownType(var->negatedvar, locktype);
3297 
3298    default:
3299       SCIPerrorMessage("unknown variable status\n");
3300       SCIPABORT();
3301       return INT_MAX; /*lint !e527*/
3302    }
3303 }
3304 
3305 /** gets number of locks for rounding down
3306  *
3307  *  @note This method will always return variable locks of type model
3308  *
3309  *  @note It is recommented to use SCIPvarGetNLocksDownType()
3310  */
SCIPvarGetNLocksDown(SCIP_VAR * var)3311 int SCIPvarGetNLocksDown(
3312    SCIP_VAR*             var                 /**< problem variable */
3313    )
3314 {
3315    return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL);
3316 }
3317 
3318 /** gets number of locks for rounding up
3319  *
3320  *  @note This method will always return variable locks of type model
3321  *
3322  *  @note It is recommented to use SCIPvarGetNLocksUpType()
3323  */
SCIPvarGetNLocksUp(SCIP_VAR * var)3324 int SCIPvarGetNLocksUp(
3325    SCIP_VAR*             var                 /**< problem variable */
3326    )
3327 {
3328    return SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
3329 }
3330 
3331 /** is it possible, to round variable down and stay feasible?
3332  *
3333  *  @note This method will always check w.r.t variable locks of type model
3334  */
SCIPvarMayRoundDown(SCIP_VAR * var)3335 SCIP_Bool SCIPvarMayRoundDown(
3336    SCIP_VAR*             var                 /**< problem variable */
3337    )
3338 {
3339    return (SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == 0);
3340 }
3341 
3342 /** is it possible, to round variable up and stay feasible?
3343  *
3344  *  @note This method will always check w.r.t. variable locks of type model
3345  */
SCIPvarMayRoundUp(SCIP_VAR * var)3346 SCIP_Bool SCIPvarMayRoundUp(
3347    SCIP_VAR*             var                 /**< problem variable */
3348    )
3349 {
3350    return (SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == 0);
3351 }
3352 
3353 /** gets and captures transformed variable of a given variable; if the variable is not yet transformed,
3354  *  a new transformed variable for this variable is created
3355  */
SCIPvarTransform(SCIP_VAR * origvar,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_OBJSENSE objsense,SCIP_VAR ** transvar)3356 SCIP_RETCODE SCIPvarTransform(
3357    SCIP_VAR*             origvar,            /**< original problem variable */
3358    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
3359    SCIP_SET*             set,                /**< global SCIP settings */
3360    SCIP_STAT*            stat,               /**< problem statistics */
3361    SCIP_OBJSENSE         objsense,           /**< objective sense of original problem; transformed is always MINIMIZE */
3362    SCIP_VAR**            transvar            /**< pointer to store the transformed variable */
3363    )
3364 {
3365    char name[SCIP_MAXSTRLEN];
3366 
3367    assert(origvar != NULL);
3368    assert(origvar->scip == set->scip);
3369    assert(SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_ORIGINAL);
3370    assert(SCIPsetIsEQ(set, origvar->glbdom.lb, origvar->locdom.lb));
3371    assert(SCIPsetIsEQ(set, origvar->glbdom.ub, origvar->locdom.ub));
3372    assert(origvar->vlbs == NULL);
3373    assert(origvar->vubs == NULL);
3374    assert(transvar != NULL);
3375 
3376    /* check if variable is already transformed */
3377    if( origvar->data.original.transvar != NULL )
3378    {
3379       *transvar = origvar->data.original.transvar;
3380       SCIPvarCapture(*transvar);
3381    }
3382    else
3383    {
3384       int i;
3385 
3386       /* create transformed variable */
3387       (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "t_%s", origvar->name);
3388       SCIP_CALL( SCIPvarCreateTransformed(transvar, blkmem, set, stat, name,
3389             origvar->glbdom.lb, origvar->glbdom.ub, (SCIP_Real)objsense * origvar->obj,
3390             SCIPvarGetType(origvar), origvar->initial, origvar->removable,
3391             origvar->vardelorig, origvar->vartrans, origvar->vardeltrans, origvar->varcopy, NULL) );
3392 
3393       /* copy the branch factor and priority */
3394       (*transvar)->branchfactor = origvar->branchfactor;
3395       (*transvar)->branchpriority = origvar->branchpriority;
3396       (*transvar)->branchdirection = origvar->branchdirection; /*lint !e732*/
3397 
3398       /* duplicate hole lists */
3399       SCIP_CALL( holelistDuplicate(&(*transvar)->glbdom.holelist, blkmem, set, origvar->glbdom.holelist) );
3400       SCIP_CALL( holelistDuplicate(&(*transvar)->locdom.holelist, blkmem, set, origvar->locdom.holelist) );
3401 
3402       /* link original and transformed variable */
3403       origvar->data.original.transvar = *transvar;
3404       SCIP_CALL( varAddParent(*transvar, blkmem, set, origvar) );
3405 
3406       /* copy rounding locks */
3407       for( i = 0; i < NLOCKTYPES; i++ )
3408       {
3409          (*transvar)->nlocksdown[i] = origvar->nlocksdown[i];
3410          (*transvar)->nlocksup[i] = origvar->nlocksup[i];
3411          assert((*transvar)->nlocksdown[i] >= 0);
3412          assert((*transvar)->nlocksup[i] >= 0);
3413       }
3414 
3415       /* copy doNotMultiaggr status */
3416       (*transvar)->donotmultaggr = origvar->donotmultaggr;
3417 
3418       /* copy lazy bounds */
3419       (*transvar)->lazylb = origvar->lazylb;
3420       (*transvar)->lazyub = origvar->lazyub;
3421 
3422       /* transfer eventual variable statistics; do not update global statistics, because this has been done
3423        * when original variable was created
3424        */
3425       SCIPhistoryUnite((*transvar)->history, origvar->history, FALSE);
3426 
3427       /* transform user data */
3428       if( origvar->vartrans != NULL )
3429       {
3430          SCIP_CALL( origvar->vartrans(set->scip, origvar, origvar->vardata, *transvar, &(*transvar)->vardata) );
3431       }
3432       else
3433          (*transvar)->vardata = origvar->vardata;
3434    }
3435 
3436    SCIPsetDebugMsg(set, "transformed variable: <%s>[%p] -> <%s>[%p]\n", origvar->name, (void*)origvar, (*transvar)->name, (void*)*transvar);
3437 
3438    return SCIP_OKAY;
3439 }
3440 
3441 /** gets corresponding transformed variable of an original or negated original variable */
SCIPvarGetTransformed(SCIP_VAR * origvar,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR ** transvar)3442 SCIP_RETCODE SCIPvarGetTransformed(
3443    SCIP_VAR*             origvar,            /**< original problem variable */
3444    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
3445    SCIP_SET*             set,                /**< global SCIP settings */
3446    SCIP_STAT*            stat,               /**< problem statistics */
3447    SCIP_VAR**            transvar            /**< pointer to store the transformed variable, or NULL if not existing yet */
3448    )
3449 {
3450    assert(origvar != NULL);
3451    assert(SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_NEGATED);
3452    assert(origvar->scip == set->scip);
3453 
3454    if( SCIPvarGetStatus(origvar) == SCIP_VARSTATUS_NEGATED )
3455    {
3456       assert(origvar->negatedvar != NULL);
3457       assert(SCIPvarGetStatus(origvar->negatedvar) == SCIP_VARSTATUS_ORIGINAL);
3458 
3459       if( origvar->negatedvar->data.original.transvar == NULL )
3460          *transvar = NULL;
3461       else
3462       {
3463          SCIP_CALL( SCIPvarNegate(origvar->negatedvar->data.original.transvar, blkmem, set, stat, transvar) );
3464       }
3465    }
3466    else
3467       *transvar = origvar->data.original.transvar;
3468 
3469    return SCIP_OKAY;
3470 }
3471 
3472 /** converts loose transformed variable into column variable, creates LP column */
SCIPvarColumn(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_LP * lp)3473 SCIP_RETCODE SCIPvarColumn(
3474    SCIP_VAR*             var,                /**< problem variable */
3475    BMS_BLKMEM*           blkmem,             /**< block memory */
3476    SCIP_SET*             set,                /**< global SCIP settings */
3477    SCIP_STAT*            stat,               /**< problem statistics */
3478    SCIP_PROB*            prob,               /**< problem data */
3479    SCIP_LP*              lp                  /**< current LP data */
3480    )
3481 {
3482    assert(var != NULL);
3483    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
3484    assert(var->scip == set->scip);
3485 
3486    SCIPsetDebugMsg(set, "creating column for variable <%s>\n", var->name);
3487 
3488    /* switch variable status */
3489    var->varstatus = SCIP_VARSTATUS_COLUMN; /*lint !e641*/
3490 
3491    /* create column of variable */
3492    SCIP_CALL( SCIPcolCreate(&var->data.col, blkmem, set, stat, var, 0, NULL, NULL, var->removable) );
3493 
3494    if( var->probindex != -1 )
3495    {
3496       /* inform problem about the variable's status change */
3497       SCIP_CALL( SCIPprobVarChangedStatus(prob, blkmem, set, NULL, NULL, var) );
3498 
3499       /* inform LP, that problem variable is now a column variable and no longer loose */
3500       SCIP_CALL( SCIPlpUpdateVarColumn(lp, set, var) );
3501    }
3502 
3503    return SCIP_OKAY;
3504 }
3505 
3506 /** converts column transformed variable back into loose variable, frees LP column */
SCIPvarLoose(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_PROB * prob,SCIP_LP * lp)3507 SCIP_RETCODE SCIPvarLoose(
3508    SCIP_VAR*             var,                /**< problem variable */
3509    BMS_BLKMEM*           blkmem,             /**< block memory */
3510    SCIP_SET*             set,                /**< global SCIP settings */
3511    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3512    SCIP_PROB*            prob,               /**< problem data */
3513    SCIP_LP*              lp                  /**< current LP data */
3514    )
3515 {
3516    assert(var != NULL);
3517    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
3518    assert(var->scip == set->scip);
3519    assert(var->data.col != NULL);
3520    assert(var->data.col->lppos == -1);
3521    assert(var->data.col->lpipos == -1);
3522 
3523    SCIPsetDebugMsg(set, "deleting column for variable <%s>\n", var->name);
3524 
3525    /* free column of variable */
3526    SCIP_CALL( SCIPcolFree(&var->data.col, blkmem, set, eventqueue, lp) );
3527 
3528    /* switch variable status */
3529    var->varstatus = SCIP_VARSTATUS_LOOSE; /*lint !e641*/
3530 
3531    if( var->probindex != -1 )
3532    {
3533       /* inform problem about the variable's status change */
3534       SCIP_CALL( SCIPprobVarChangedStatus(prob, blkmem, set, NULL, NULL, var) );
3535 
3536       /* inform LP, that problem variable is now a loose variable and no longer a column */
3537       SCIP_CALL( SCIPlpUpdateVarLoose(lp, set, var) );
3538    }
3539 
3540    return SCIP_OKAY;
3541 }
3542 
3543 /** issues a VARFIXED event on the given variable and all its parents (except ORIGINAL parents);
3544  *  the event issuing on the parents is necessary, because unlike with bound changes, the parent variables
3545  *  are not informed about a fixing of an active variable they are pointing to
3546  */
3547 static
varEventVarFixed(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,int fixeventtype)3548 SCIP_RETCODE varEventVarFixed(
3549    SCIP_VAR*             var,                /**< problem variable to change */
3550    BMS_BLKMEM*           blkmem,             /**< block memory */
3551    SCIP_SET*             set,                /**< global SCIP settings */
3552    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3553    int                   fixeventtype        /**< is this event a fixation(0), an aggregation(1), or a
3554 					      *   multi-aggregation(2)
3555 					      */
3556    )
3557 {
3558    SCIP_EVENT* event;
3559    SCIP_VARSTATUS varstatus;
3560    int i;
3561 
3562    assert(var != NULL);
3563    assert(var->scip == set->scip);
3564    assert(0 <= fixeventtype && fixeventtype <= 2);
3565 
3566    /* issue VARFIXED event on variable */
3567    SCIP_CALL( SCIPeventCreateVarFixed(&event, blkmem, var) );
3568    SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
3569 
3570 #ifndef NDEBUG
3571    for( i = var->nparentvars -1; i >= 0; --i )
3572    {
3573       assert(SCIPvarGetStatus(var->parentvars[i]) != SCIP_VARSTATUS_MULTAGGR);
3574    }
3575 #endif
3576 
3577    switch( fixeventtype )
3578    {
3579    case 0:
3580       /* process all parents of a fixed variable */
3581       for( i = var->nparentvars - 1; i >= 0; --i )
3582       {
3583 	 varstatus = SCIPvarGetStatus(var->parentvars[i]);
3584 
3585 	 assert(varstatus != SCIP_VARSTATUS_FIXED);
3586 
3587 	 /* issue event on all not yet fixed parent variables, (that should already issued this event) except the original
3588 	  * one
3589 	  */
3590 	 if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3591 	 {
3592 	    SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3593 	 }
3594       }
3595       break;
3596    case 1:
3597       /* process all parents of a aggregated variable */
3598       for( i = var->nparentvars - 1; i >= 0; --i )
3599       {
3600 	 varstatus = SCIPvarGetStatus(var->parentvars[i]);
3601 
3602 	 assert(varstatus != SCIP_VARSTATUS_FIXED);
3603 
3604 	 /* issue event for not aggregated parent variable, because for these and its parents the var event was already
3605           * issued(, except the original one)
3606           *
3607           * @note that even before an aggregated parent variable, there might be variables, for which the vent was not
3608           *       yet issued
3609 	  */
3610          if( varstatus == SCIP_VARSTATUS_AGGREGATED )
3611             continue;
3612 
3613 	 if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3614 	 {
3615 	    SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3616 	 }
3617       }
3618       break;
3619    case 2:
3620       /* process all parents of a aggregated variable */
3621       for( i = var->nparentvars - 1; i >= 0; --i )
3622       {
3623 	 varstatus = SCIPvarGetStatus(var->parentvars[i]);
3624 
3625 	 assert(varstatus != SCIP_VARSTATUS_FIXED);
3626 
3627 	 /* issue event on all parent variables except the original one */
3628 	 if( varstatus != SCIP_VARSTATUS_ORIGINAL )
3629 	 {
3630 	    SCIP_CALL( varEventVarFixed(var->parentvars[i], blkmem, set, eventqueue, fixeventtype) );
3631 	 }
3632       }
3633       break;
3634    default:
3635       SCIPerrorMessage("unknown variable fixation event origin\n");
3636       return SCIP_INVALIDDATA;
3637    }
3638 
3639    return SCIP_OKAY;
3640 }
3641 
3642 /** converts variable into fixed variable */
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)3643 SCIP_RETCODE SCIPvarFix(
3644    SCIP_VAR*             var,                /**< problem variable */
3645    BMS_BLKMEM*           blkmem,             /**< block memory */
3646    SCIP_SET*             set,                /**< global SCIP settings */
3647    SCIP_STAT*            stat,               /**< problem statistics */
3648    SCIP_PROB*            transprob,          /**< tranformed problem data */
3649    SCIP_PROB*            origprob,           /**< original problem data */
3650    SCIP_PRIMAL*          primal,             /**< primal data */
3651    SCIP_TREE*            tree,               /**< branch and bound tree */
3652    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
3653    SCIP_LP*              lp,                 /**< current LP data */
3654    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
3655    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
3656    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3657    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
3658    SCIP_Real             fixedval,           /**< value to fix variable at */
3659    SCIP_Bool*            infeasible,         /**< pointer to store whether the fixing is infeasible */
3660    SCIP_Bool*            fixed               /**< pointer to store whether the fixing was performed (variable was unfixed) */
3661    )
3662 {
3663    SCIP_Real obj;
3664    SCIP_Real childfixedval;
3665 
3666    assert(var != NULL);
3667    assert(var->scip == set->scip);
3668    assert(SCIPsetIsEQ(set, var->glbdom.lb, var->locdom.lb));
3669    assert(SCIPsetIsEQ(set, var->glbdom.ub, var->locdom.ub));
3670    assert(infeasible != NULL);
3671    assert(fixed != NULL);
3672 
3673    SCIPsetDebugMsg(set, "fix variable <%s>[%g,%g] to %g\n", var->name, var->glbdom.lb, var->glbdom.ub, fixedval);
3674 
3675    *infeasible = FALSE;
3676    *fixed = FALSE;
3677 
3678    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED )
3679    {
3680       *infeasible = !SCIPsetIsFeasEQ(set, fixedval, var->locdom.lb);
3681       SCIPsetDebugMsg(set, " -> variable already fixed to %g (fixedval=%g): infeasible=%u\n", var->locdom.lb, fixedval, *infeasible);
3682       return SCIP_OKAY;
3683    }
3684    else if( (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && !SCIPsetIsFeasIntegral(set, fixedval))
3685       || SCIPsetIsFeasLT(set, fixedval, var->locdom.lb)
3686       || SCIPsetIsFeasGT(set, fixedval, var->locdom.ub) )
3687    {
3688       SCIPsetDebugMsg(set, " -> fixing infeasible: locdom=[%g,%g], fixedval=%g\n", var->locdom.lb, var->locdom.ub, fixedval);
3689       *infeasible = TRUE;
3690       return SCIP_OKAY;
3691    }
3692 
3693    switch( SCIPvarGetStatus(var) )
3694    {
3695    case SCIP_VARSTATUS_ORIGINAL:
3696       if( var->data.original.transvar == NULL )
3697       {
3698          SCIPerrorMessage("cannot fix an untransformed original variable\n");
3699          return SCIP_INVALIDDATA;
3700       }
3701       SCIP_CALL( SCIPvarFix(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt,
3702             lp, branchcand, eventfilter, eventqueue, cliquetable, fixedval, infeasible, fixed) );
3703       break;
3704 
3705    case SCIP_VARSTATUS_LOOSE:
3706       assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
3707 
3708       /* set the fixed variable's objective value to 0.0 */
3709       obj = var->obj;
3710       SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
3711 
3712       /* since we change the variable type form loose to fixed, we have to adjust the number of loose
3713        * variables in the LP data structure; the loose objective value (looseobjval) in the LP data structure, however,
3714        * gets adjusted automatically, due to the event SCIP_EVENTTYPE_OBJCHANGED which dropped in the moment where the
3715        * objective of this variable is set to zero
3716        */
3717       SCIPlpDecNLoosevars(lp);
3718 
3719       /* change variable's bounds to fixed value (thereby removing redundant implications and variable bounds) */
3720       holelistFree(&var->glbdom.holelist, blkmem);
3721       holelistFree(&var->locdom.holelist, blkmem);
3722       SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, fixedval) );
3723       SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, fixedval) );
3724 
3725       /* explicitly set variable's bounds, even if the fixed value is in epsilon range of the old bound */
3726       var->glbdom.lb = fixedval;
3727       var->glbdom.ub = fixedval;
3728       var->locdom.lb = fixedval;
3729       var->locdom.ub = fixedval;
3730 
3731       /* delete implications and variable bounds information */
3732       SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) );
3733       assert(var->vlbs == NULL);
3734       assert(var->vubs == NULL);
3735       assert(var->implics == NULL);
3736       assert(var->cliquelist == NULL);
3737 
3738       /* clear the history of the variable */
3739       SCIPhistoryReset(var->history);
3740       SCIPhistoryReset(var->historycrun);
3741 
3742       /* convert variable into fixed variable */
3743       var->varstatus = SCIP_VARSTATUS_FIXED; /*lint !e641*/
3744 
3745       /* inform problem about the variable's status change */
3746       if( var->probindex != -1 )
3747       {
3748          SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) );
3749       }
3750 
3751       /* reset the objective value of the fixed variable, thus adjusting the problem's objective offset */
3752       SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) );
3753 
3754       /* issue VARFIXED event */
3755       SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 0) );
3756 
3757       *fixed = TRUE;
3758       break;
3759 
3760    case SCIP_VARSTATUS_COLUMN:
3761       SCIPerrorMessage("cannot fix a column variable\n");
3762       return SCIP_INVALIDDATA;
3763 
3764    case SCIP_VARSTATUS_FIXED:
3765       SCIPerrorMessage("cannot fix a fixed variable again\n");  /*lint !e527*/
3766       SCIPABORT(); /* case is already handled in earlier if condition */
3767       return SCIP_INVALIDDATA;  /*lint !e527*/
3768 
3769    case SCIP_VARSTATUS_AGGREGATED:
3770       /* fix aggregation variable y in x = a*y + c, instead of fixing x directly */
3771       assert(SCIPsetIsZero(set, var->obj));
3772       assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
3773       if( SCIPsetIsInfinity(set, fixedval) || SCIPsetIsInfinity(set, -fixedval) )
3774          childfixedval = (var->data.aggregate.scalar < 0.0 ? -fixedval : fixedval);
3775       else
3776          childfixedval = (fixedval - var->data.aggregate.constant)/var->data.aggregate.scalar;
3777       SCIP_CALL( SCIPvarFix(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
3778             branchcand, eventfilter, eventqueue, cliquetable, childfixedval, infeasible, fixed) );
3779       break;
3780 
3781    case SCIP_VARSTATUS_MULTAGGR:
3782       SCIPerrorMessage("cannot fix a multiple aggregated variable\n");
3783       SCIPABORT();
3784       return SCIP_INVALIDDATA;  /*lint !e527*/
3785 
3786    case SCIP_VARSTATUS_NEGATED:
3787       /* fix negation variable x in x' = offset - x, instead of fixing x' directly */
3788       assert(SCIPsetIsZero(set, var->obj));
3789       assert(var->negatedvar != NULL);
3790       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
3791       assert(var->negatedvar->negatedvar == var);
3792       SCIP_CALL( SCIPvarFix(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
3793             branchcand, eventfilter, eventqueue, cliquetable, var->data.negate.constant - fixedval, infeasible, fixed) );
3794       break;
3795 
3796    default:
3797       SCIPerrorMessage("unknown variable status\n");
3798       return SCIP_INVALIDDATA;
3799    }
3800 
3801    return SCIP_OKAY;
3802 }
3803 
3804 /** transforms given variables, scalars and constant to the corresponding active variables, scalars and constant
3805  *
3806  * If the number of needed active variables is greater than the available slots in the variable array, nothing happens except
3807  * that the required size is stored in the corresponding variable; hence, if afterwards the required size is greater than the
3808  * available slots (varssize), nothing happens; otherwise, the active variable representation is stored in the arrays.
3809  *
3810  * The reason for this approach is that we cannot reallocate memory, since we do not know how the
3811  * memory has been allocated (e.g., by a C++ 'new' or SCIP functions).
3812  */
SCIPvarGetActiveRepresentatives(SCIP_SET * set,SCIP_VAR ** vars,SCIP_Real * scalars,int * nvars,int varssize,SCIP_Real * constant,int * requiredsize,SCIP_Bool mergemultiples)3813 SCIP_RETCODE SCIPvarGetActiveRepresentatives(
3814    SCIP_SET*             set,                /**< global SCIP settings */
3815    SCIP_VAR**            vars,               /**< variable array to get active variables */
3816    SCIP_Real*            scalars,            /**< scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
3817    int*                  nvars,              /**< pointer to number of variables and values in vars and scalars array */
3818    int                   varssize,           /**< available slots in vars and scalars array */
3819    SCIP_Real*            constant,           /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c  */
3820    int*                  requiredsize,       /**< pointer to store the required array size for the active variables */
3821    SCIP_Bool             mergemultiples      /**< should multiple occurrences of a var be replaced by a single coeff? */
3822    )
3823 {
3824    SCIP_VAR** activevars;
3825    SCIP_Real* activescalars;
3826    int nactivevars;
3827    SCIP_Real activeconstant;
3828    SCIP_Bool activeconstantinf;
3829    int activevarssize;
3830 
3831    SCIP_VAR* var;
3832    SCIP_Real scalar;
3833    int v;
3834    int k;
3835 
3836    SCIP_VAR** tmpvars;
3837    SCIP_VAR** multvars;
3838    SCIP_Real* tmpscalars;
3839    SCIP_Real* multscalars;
3840    int tmpvarssize;
3841    int ntmpvars;
3842    int nmultvars;
3843 
3844    SCIP_VAR* multvar;
3845    SCIP_Real multscalar;
3846    SCIP_Real multconstant;
3847    int pos;
3848 
3849    int noldtmpvars;
3850 
3851    SCIP_VAR** tmpvars2;
3852    SCIP_Real* tmpscalars2;
3853    int tmpvarssize2;
3854    int ntmpvars2;
3855 
3856    SCIP_Bool sortagain = FALSE;
3857 
3858    assert(set != NULL);
3859    assert(nvars != NULL);
3860    assert(scalars != NULL || *nvars == 0);
3861    assert(constant != NULL);
3862    assert(requiredsize != NULL);
3863    assert(*nvars <= varssize);
3864 
3865    *requiredsize = 0;
3866 
3867    if( *nvars == 0 )
3868       return SCIP_OKAY;
3869 
3870    assert(vars != NULL);
3871 
3872    /* handle the "easy" case of just one variable and avoid memory allocation if the variable is already active */
3873    if( *nvars == 1 && (vars[0]->varstatus == ((int) SCIP_VARSTATUS_COLUMN) || vars[0]->varstatus == ((int) SCIP_VARSTATUS_LOOSE)) )
3874    {
3875       *requiredsize = 1;
3876 
3877       return SCIP_OKAY;
3878    }
3879 
3880    nactivevars = 0;
3881    activeconstant = 0.0;
3882    activeconstantinf = FALSE;
3883    activevarssize = (*nvars) * 2;
3884    ntmpvars = *nvars;
3885    tmpvarssize = *nvars;
3886 
3887    tmpvarssize2 = 1;
3888 
3889    /* allocate temporary memory */
3890    SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpvars2, tmpvarssize2) );
3891    SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpscalars2, tmpvarssize2) );
3892    SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) );
3893    SCIP_CALL( SCIPsetAllocBufferArray(set, &activescalars, activevarssize) );
3894    SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpvars, vars, ntmpvars) );
3895    SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpscalars, scalars, ntmpvars) );
3896 
3897    /* to avoid unnecessary expanding of variable arrays while disaggregating several variables multiple times combine same variables
3898     * first, first get all corresponding variables with status loose, column, multaggr or fixed
3899     */
3900    for( v = ntmpvars - 1; v >= 0; --v )
3901    {
3902       var = tmpvars[v];
3903       scalar = tmpscalars[v];
3904 
3905       assert(var != NULL);
3906       /* transforms given variable, scalar and constant to the corresponding active, fixed, or
3907        * multi-aggregated variable, scalar and constant; if the variable resolves to a fixed
3908        * variable, "scalar" will be 0.0 and the value of the sum will be stored in "constant".
3909        */
3910       SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &scalar, &activeconstant) );
3911       assert(var != NULL);
3912 
3913       assert(SCIPsetIsInfinity(set, activeconstant) == (activeconstant == SCIPsetInfinity(set))); /*lint !e777*/
3914       assert(SCIPsetIsInfinity(set, -activeconstant) == (activeconstant == -SCIPsetInfinity(set))); /*lint !e777*/
3915 
3916       activeconstantinf = SCIPsetIsInfinity(set, activeconstant) || SCIPsetIsInfinity(set, -activeconstant);
3917 
3918       assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
3919          || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
3920          || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR
3921          || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
3922 
3923       tmpvars[v] = var;
3924       tmpscalars[v] = scalar;
3925    }
3926    noldtmpvars = ntmpvars;
3927 
3928    /* sort all variables to combine equal variables easily */
3929    SCIPsortPtrReal((void**)tmpvars, tmpscalars, SCIPvarComp, noldtmpvars);
3930    ntmpvars = 0;
3931    for( v = 1; v < noldtmpvars; ++v )
3932    {
3933       /* combine same variables */
3934       if( SCIPvarCompare(tmpvars[v], tmpvars[ntmpvars]) == 0 )
3935       {
3936          tmpscalars[ntmpvars] += tmpscalars[v];
3937       }
3938       else
3939       {
3940          ++ntmpvars;
3941          if( v > ntmpvars )
3942          {
3943             tmpscalars[ntmpvars] = tmpscalars[v];
3944             tmpvars[ntmpvars] = tmpvars[v];
3945          }
3946       }
3947    }
3948    ++ntmpvars;
3949 
3950 #ifdef SCIP_MORE_DEBUG
3951    for( v = 1; v < ntmpvars; ++v )
3952       assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0);
3953 #endif
3954 
3955    /* collect for each variable the representation in active variables */
3956    while( ntmpvars >= 1 )
3957    {
3958       --ntmpvars;
3959       ntmpvars2 = 0;
3960       var = tmpvars[ntmpvars];
3961       scalar = tmpscalars[ntmpvars];
3962 
3963       assert(var != NULL);
3964 
3965       /* TODO: maybe we should test here on SCIPsetIsZero() instead of 0.0 */
3966       if( scalar == 0.0 )
3967          continue;
3968 
3969       assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
3970          || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
3971          || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR
3972          || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
3973 
3974       switch( SCIPvarGetStatus(var) )
3975       {
3976       case SCIP_VARSTATUS_LOOSE:
3977       case SCIP_VARSTATUS_COLUMN:
3978          /* x = a*y + c */
3979          if( nactivevars >= activevarssize )
3980          {
3981             activevarssize *= 2;
3982             SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) );
3983             SCIP_CALL( SCIPsetReallocBufferArray(set, &activescalars, activevarssize) );
3984             assert(nactivevars < activevarssize);
3985          }
3986          activevars[nactivevars] = var;
3987          activescalars[nactivevars] = scalar;
3988          nactivevars++;
3989          break;
3990 
3991       case SCIP_VARSTATUS_MULTAGGR:
3992          /* x = a_1*y_1 + ... + a_n*y_n + c */
3993          nmultvars = var->data.multaggr.nvars;
3994          multvars = var->data.multaggr.vars;
3995          multscalars = var->data.multaggr.scalars;
3996          sortagain = TRUE;
3997 
3998          if( nmultvars + ntmpvars > tmpvarssize )
3999          {
4000             while( nmultvars + ntmpvars > tmpvarssize )
4001                tmpvarssize *= 2;
4002             SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) );
4003             SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars, tmpvarssize) );
4004             assert(nmultvars + ntmpvars <= tmpvarssize);
4005          }
4006 
4007          if( nmultvars > tmpvarssize2 )
4008          {
4009             while( nmultvars > tmpvarssize2 )
4010                tmpvarssize2 *= 2;
4011             SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars2, tmpvarssize2) );
4012             SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars2, tmpvarssize2) );
4013             assert(nmultvars <= tmpvarssize2);
4014          }
4015 
4016          --nmultvars;
4017 
4018          for( ; nmultvars >= 0; --nmultvars )
4019          {
4020             multvar = multvars[nmultvars];
4021             multscalar = multscalars[nmultvars];
4022             multconstant = 0;
4023 
4024             assert(multvar != NULL);
4025             SCIP_CALL( SCIPvarGetProbvarSum(&multvar, set, &multscalar, &multconstant) );
4026             assert(multvar != NULL);
4027 
4028             assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
4029                || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
4030                || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR
4031                || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
4032 
4033             if( !activeconstantinf )
4034             {
4035                assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar));
4036 
4037                if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) )
4038                {
4039                   assert(scalar != 0.0);
4040                   if( scalar * multconstant > 0.0 )
4041                   {
4042                      activeconstant = SCIPsetInfinity(set);
4043                      activeconstantinf = TRUE;
4044                   }
4045                   else
4046                   {
4047                      activeconstant = -SCIPsetInfinity(set);
4048                      activeconstantinf = TRUE;
4049                   }
4050                }
4051                else
4052                   activeconstant += scalar * multconstant;
4053             }
4054 #ifndef NDEBUG
4055             else
4056             {
4057                assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 &&
4058                      (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4059                assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 &&
4060                      (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4061             }
4062 #endif
4063 
4064             if( SCIPsortedvecFindPtr((void**)tmpvars, SCIPvarComp, multvar, ntmpvars, &pos) )
4065             {
4066                assert(SCIPvarCompare(tmpvars[pos], multvar) == 0);
4067                tmpscalars[pos] += scalar * multscalar;
4068             }
4069             else
4070             {
4071                tmpvars2[ntmpvars2] = multvar;
4072                tmpscalars2[ntmpvars2] = scalar * multscalar;
4073                ++(ntmpvars2);
4074                assert(ntmpvars2 <= tmpvarssize2);
4075             }
4076          }
4077 
4078          if( ntmpvars2 > 0 )
4079          {
4080             /* sort all variables to combine equal variables easily */
4081             SCIPsortPtrReal((void**)tmpvars2, tmpscalars2, SCIPvarComp, ntmpvars2);
4082             pos = 0;
4083             for( v = 1; v < ntmpvars2; ++v )
4084             {
4085                /* combine same variables */
4086                if( SCIPvarCompare(tmpvars2[v], tmpvars2[pos]) == 0 )
4087                {
4088                   tmpscalars2[pos] += tmpscalars2[v];
4089                }
4090                else
4091                {
4092                   ++pos;
4093                   if( v > pos )
4094                   {
4095                      tmpscalars2[pos] = tmpscalars2[v];
4096                      tmpvars2[pos] = tmpvars2[v];
4097                   }
4098                }
4099             }
4100             ntmpvars2 = pos + 1;
4101 #ifdef SCIP_MORE_DEBUG
4102             for( v = 1; v < ntmpvars2; ++v )
4103             {
4104                assert(SCIPvarCompare(tmpvars2[v], tmpvars2[v-1]) > 0);
4105             }
4106             for( v = 1; v < ntmpvars; ++v )
4107             {
4108                assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0);
4109             }
4110 #endif
4111             v = ntmpvars - 1;
4112             k = ntmpvars2 - 1;
4113             pos = ntmpvars + ntmpvars2 - 1;
4114             ntmpvars += ntmpvars2;
4115 
4116             while( v >= 0 && k >= 0 )
4117             {
4118                assert(pos >= 0);
4119                assert(SCIPvarCompare(tmpvars[v], tmpvars2[k]) != 0);
4120                if( SCIPvarCompare(tmpvars[v], tmpvars2[k]) >= 0 )
4121                {
4122                   tmpvars[pos] = tmpvars[v];
4123                   tmpscalars[pos] = tmpscalars[v];
4124                   --v;
4125                }
4126                else
4127                {
4128                   tmpvars[pos] = tmpvars2[k];
4129                   tmpscalars[pos] = tmpscalars2[k];
4130                   --k;
4131                }
4132                --pos;
4133                assert(pos >= 0);
4134             }
4135             while( v >= 0 )
4136             {
4137                assert(pos >= 0);
4138                tmpvars[pos] = tmpvars[v];
4139                tmpscalars[pos] = tmpscalars[v];
4140                --v;
4141                --pos;
4142             }
4143             while( k >= 0 )
4144             {
4145                assert(pos >= 0);
4146                tmpvars[pos] = tmpvars2[k];
4147                tmpscalars[pos] = tmpscalars2[k];
4148                --k;
4149                --pos;
4150             }
4151          }
4152 #ifdef SCIP_MORE_DEBUG
4153          for( v = 1; v < ntmpvars; ++v )
4154          {
4155             assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0);
4156          }
4157 #endif
4158 
4159          if( !activeconstantinf )
4160          {
4161             assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar));
4162 
4163             multconstant = SCIPvarGetMultaggrConstant(var);
4164 
4165             if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) )
4166             {
4167                assert(scalar != 0.0);
4168                if( scalar * multconstant > 0.0 )
4169                {
4170                   activeconstant = SCIPsetInfinity(set);
4171                   activeconstantinf = TRUE;
4172                }
4173                else
4174                {
4175                   activeconstant = -SCIPsetInfinity(set);
4176                   activeconstantinf = TRUE;
4177                }
4178             }
4179             else
4180                activeconstant += scalar * multconstant;
4181          }
4182 #ifndef NDEBUG
4183          else
4184          {
4185             multconstant = SCIPvarGetMultaggrConstant(var);
4186             assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 &&
4187                   (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4188             assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 &&
4189                   (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant))));
4190          }
4191 #endif
4192          break;
4193 
4194       case SCIP_VARSTATUS_FIXED:
4195       case SCIP_VARSTATUS_ORIGINAL:
4196       case SCIP_VARSTATUS_AGGREGATED:
4197       case SCIP_VARSTATUS_NEGATED:
4198       default:
4199          /* case x = c, but actually we should not be here, since SCIPvarGetProbvarSum() returns a scalar of 0.0 for
4200           * fixed variables and is handled already
4201           */
4202          assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
4203          assert(SCIPsetIsZero(set, var->glbdom.lb) && SCIPsetIsEQ(set, var->glbdom.lb, var->glbdom.ub));
4204       }
4205    }
4206 
4207    if( mergemultiples )
4208    {
4209       if( sortagain )
4210       {
4211          /* sort variable and scalar array by variable index */
4212          SCIPsortPtrReal((void**)activevars, activescalars, SCIPvarComp, nactivevars);
4213 
4214          /* eliminate duplicates and count required size */
4215          v = nactivevars - 1;
4216          while( v > 0 )
4217          {
4218             /* combine both variable since they are the same */
4219             if( SCIPvarCompare(activevars[v - 1], activevars[v]) == 0 )
4220             {
4221                if( activescalars[v - 1] + activescalars[v] != 0.0 )
4222                {
4223                   activescalars[v - 1] += activescalars[v];
4224                   --nactivevars;
4225                   activevars[v] = activevars[nactivevars];
4226                   activescalars[v] = activescalars[nactivevars];
4227                }
4228                else
4229                {
4230                   --nactivevars;
4231                   activevars[v] = activevars[nactivevars];
4232                   activescalars[v] = activescalars[nactivevars];
4233                   --nactivevars;
4234                   --v;
4235                   activevars[v] = activevars[nactivevars];
4236                   activescalars[v] = activescalars[nactivevars];
4237                }
4238             }
4239             --v;
4240          }
4241       }
4242       /* the variables were added in reverse order, we revert the order now;
4243        * this should not be necessary, but not doing this changes the behavior sometimes
4244        */
4245       else
4246       {
4247          SCIP_VAR* tmpvar;
4248          SCIP_Real tmpscalar;
4249 
4250          for( v = 0; v < nactivevars / 2; ++v )
4251          {
4252             tmpvar = activevars[v];
4253             tmpscalar = activescalars[v];
4254             activevars[v] = activevars[nactivevars - 1 - v];
4255             activescalars[v] = activescalars[nactivevars - 1 - v];
4256             activevars[nactivevars - 1 - v] = tmpvar;
4257             activescalars[nactivevars - 1 - v] = tmpscalar;
4258          }
4259       }
4260    }
4261    *requiredsize = nactivevars;
4262 
4263    if( varssize >= *requiredsize )
4264    {
4265       assert(vars != NULL);
4266 
4267       *nvars = *requiredsize;
4268 
4269       if( !SCIPsetIsInfinity(set, *constant) && !SCIPsetIsInfinity(set, -(*constant)) )
4270       {
4271          /* if the activeconstant is infinite, the constant pointer gets the same value, otherwise add the value */
4272          if( activeconstantinf )
4273             (*constant) = activeconstant;
4274          else
4275             (*constant) += activeconstant;
4276       }
4277 #ifndef NDEBUG
4278       else
4279       {
4280          assert(!SCIPsetIsInfinity(set, (*constant)) || !SCIPsetIsInfinity(set, -activeconstant));
4281          assert(!SCIPsetIsInfinity(set, -(*constant)) || !SCIPsetIsInfinity(set, activeconstant));
4282       }
4283 #endif
4284 
4285       /* copy active variable and scalar array to the given arrays */
4286       for( v = 0; v < *nvars; ++v )
4287       {
4288          vars[v] = activevars[v];
4289          scalars[v] = activescalars[v]; /*lint !e613*/
4290       }
4291    }
4292 
4293    assert(SCIPsetIsInfinity(set, *constant) == ((*constant) == SCIPsetInfinity(set))); /*lint !e777*/
4294    assert(SCIPsetIsInfinity(set, -(*constant)) == ((*constant) == -SCIPsetInfinity(set))); /*lint !e777*/
4295 
4296    SCIPsetFreeBufferArray(set, &tmpscalars);
4297    SCIPsetFreeBufferArray(set, &tmpvars);
4298    SCIPsetFreeBufferArray(set, &activescalars);
4299    SCIPsetFreeBufferArray(set, &activevars);
4300    SCIPsetFreeBufferArray(set, &tmpscalars2);
4301    SCIPsetFreeBufferArray(set, &tmpvars2);
4302 
4303    return SCIP_OKAY;
4304 }
4305 
4306 
4307 /** flattens aggregation graph of multi-aggregated variable in order to avoid exponential recursion later on */
SCIPvarFlattenAggregationGraph(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue)4308 SCIP_RETCODE SCIPvarFlattenAggregationGraph(
4309    SCIP_VAR*             var,                /**< problem variable */
4310    BMS_BLKMEM*           blkmem,             /**< block memory */
4311    SCIP_SET*             set,                /**< global SCIP settings */
4312    SCIP_EVENTQUEUE*      eventqueue          /**< event queue */
4313    )
4314 {
4315    int nlocksup[NLOCKTYPES];
4316    int nlocksdown[NLOCKTYPES];
4317    SCIP_Real multconstant;
4318    int multvarssize;
4319    int nmultvars;
4320    int multrequiredsize;
4321    int i;
4322 
4323    assert( var != NULL );
4324    assert( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR );
4325    assert(var->scip == set->scip);
4326 
4327    /* in order to update the locks on the active representation of the multi-aggregated variable, we remove all locks
4328     * on the current representation now and re-add the locks once the variable graph has been flattened, which
4329     * may lead to duplicate occurences of the same variable being merged
4330     *
4331     * Here is an example. Assume we have the multi-aggregation z = x + y.
4332     * z occures with positive coefficient in a <= constraint c1, so it has an uplock from there.
4333     * When the multi-aggregation is performed, all locks are added to the active representation,
4334     * so x and y both get an uplock from c1. However, z was not yet replaced by x + y in c1.
4335     * Next, a negation y = 1 - x is identified. Again, locks are moved, so that the uplock of y originating
4336     * from c1 is added to x as a downlock. Thus, x has both an up- and downlock from c1.
4337     * The multi-aggregation changes to z = x + 1 - x, which corresponds to the locks.
4338     * However, before z is replaced by that sum, SCIPvarFlattenAggregationGraph() is called
4339     * which changes z = x + y = x + 1 - x = 1, since it merges multiple occurences of the same variable.
4340     * The up- and downlock of x, however, is not removed when replacing z in c1 by its active representation,
4341     * because it is just 1 now. Therefore, we need to update locks when flattening the aggregation graph.
4342     * For this, the multi-aggregated variable knows its locks in addition to adding them to the active
4343     * representation, which corresponds to the locks from constraints where the variable was not replaced yet.
4344     * By removing the locks here, based on the old representation and adding them again after flattening,
4345     * we ensure that the locks are correct afterwards if coefficients were merged.
4346     */
4347    for( i = 0; i < NLOCKTYPES; ++i )
4348    {
4349       nlocksup[i] = var->nlocksup[i];
4350       nlocksdown[i] = var->nlocksdown[i];
4351 
4352       SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, -nlocksdown[i], -nlocksup[i]) );
4353    }
4354 
4355    multconstant = var->data.multaggr.constant;
4356    nmultvars = var->data.multaggr.nvars;
4357    multvarssize = var->data.multaggr.varssize;
4358 
4359    SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) );
4360 
4361    if( multrequiredsize > multvarssize )
4362    {
4363       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.vars), multvarssize, multrequiredsize) );
4364       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.scalars), multvarssize, multrequiredsize) );
4365       multvarssize = multrequiredsize;
4366       SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) );
4367       assert( multrequiredsize <= multvarssize );
4368    }
4369    /**@note After the flattening the multi aggregation might resolve to be in fact an aggregation (or even a fixing?).
4370     * This issue is not resolved right now, since var->data.multaggr.nvars < 2 should not cause troubles. However, one
4371     * may loose performance hereby, since aggregated variables are easier to handle.
4372     *
4373     * Note, that there are two cases where SCIPvarFlattenAggregationGraph() is called: The easier one is that it is
4374     * called while installing the multi-aggregation. in principle, the described issue could be handled straightforward
4375     * in this case by aggregating or fixing the variable instead.  The more complicated case is the one, when the
4376     * multi-aggregation is used, e.g., in linear presolving (and the variable is already declared to be multi-aggregated).
4377     *
4378     * By now, it is not allowed to fix or aggregate multi-aggregated variables which would be necessary in this case.
4379     *
4380     * The same issue appears in the SCIPvarGetProbvar...() methods.
4381     */
4382 
4383    var->data.multaggr.constant = multconstant;
4384    var->data.multaggr.nvars = nmultvars;
4385    var->data.multaggr.varssize = multvarssize;
4386 
4387    for( i = 0; i < NLOCKTYPES; ++i )
4388    {
4389       SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) );
4390    }
4391 
4392    return SCIP_OKAY;
4393 }
4394 
4395 /** merge two variable histories together; a typical use case is that \p othervar is an image of the target variable
4396  *  in a SCIP copy. Method should be applied with care, especially because no internal checks are performed whether
4397  *  the history merge is reasonable
4398  *
4399  *  @note Do not use this method if the two variables originate from two SCIP's with different objective functions, since
4400  *        this corrupts the variable pseudo costs
4401  *  @note Apply with care; no internal checks are performed if the two variables should be merged
4402  */
SCIPvarMergeHistories(SCIP_VAR * targetvar,SCIP_VAR * othervar,SCIP_STAT * stat)4403 void SCIPvarMergeHistories(
4404    SCIP_VAR*             targetvar,          /**< the variable that should contain both histories afterwards */
4405    SCIP_VAR*             othervar,           /**< the variable whose history is to be merged with that of the target variable */
4406    SCIP_STAT*            stat                /**< problem statistics */
4407    )
4408 {
4409    /* merge only the history of the current run into the target history */
4410    SCIPhistoryUnite(targetvar->history, othervar->historycrun, FALSE);
4411 
4412    /* apply the changes also to the global history */
4413    SCIPhistoryUnite(stat->glbhistory, othervar->historycrun, FALSE);
4414 }
4415 
4416 /** sets the history of a variable; this method is typically used within reoptimization to keep and update the variable
4417  *  history over several iterations
4418  */
SCIPvarSetHistory(SCIP_VAR * var,SCIP_HISTORY * history,SCIP_STAT * stat)4419 void SCIPvarSetHistory(
4420    SCIP_VAR*             var,                /**< variable */
4421    SCIP_HISTORY*         history,            /**< the history which is to set */
4422    SCIP_STAT*            stat                /**< problem statistics */
4423    )
4424 {
4425    /* merge only the history of the current run into the target history */
4426    SCIPhistoryUnite(var->history, history, FALSE);
4427 
4428    /* apply the changes also to the global history */
4429    SCIPhistoryUnite(stat->glbhistory, history, FALSE);
4430 }
4431 
4432 /** tightens the bounds of both variables in aggregation x = a*y + c */
4433 static
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)4434 SCIP_RETCODE varUpdateAggregationBounds(
4435    SCIP_VAR*             var,                /**< problem variable */
4436    BMS_BLKMEM*           blkmem,             /**< block memory */
4437    SCIP_SET*             set,                /**< global SCIP settings */
4438    SCIP_STAT*            stat,               /**< problem statistics */
4439    SCIP_PROB*            transprob,          /**< tranformed problem data */
4440    SCIP_PROB*            origprob,           /**< original problem data */
4441    SCIP_PRIMAL*          primal,             /**< primal data */
4442    SCIP_TREE*            tree,               /**< branch and bound tree */
4443    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
4444    SCIP_LP*              lp,                 /**< current LP data */
4445    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
4446    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
4447    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
4448    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
4449    SCIP_VAR*             aggvar,             /**< variable y in aggregation x = a*y + c */
4450    SCIP_Real             scalar,             /**< multiplier a in aggregation x = a*y + c */
4451    SCIP_Real             constant,           /**< constant shift c in aggregation x = a*y + c */
4452    SCIP_Bool*            infeasible,         /**< pointer to store whether the aggregation is infeasible */
4453    SCIP_Bool*            fixed               /**< pointer to store whether the variables were fixed */
4454    )
4455 {
4456    SCIP_Real varlb;
4457    SCIP_Real varub;
4458    SCIP_Real aggvarlb;
4459    SCIP_Real aggvarub;
4460    SCIP_Bool aggvarbdschanged;
4461 
4462    assert(var != NULL);
4463    assert(var->scip == set->scip);
4464    assert(aggvar != NULL);
4465    assert(!SCIPsetIsZero(set, scalar));
4466    assert(infeasible != NULL);
4467    assert(fixed != NULL);
4468 
4469    *infeasible = FALSE;
4470    *fixed = FALSE;
4471 
4472    SCIPsetDebugMsg(set, "updating bounds of variables in aggregation <%s> == %g*<%s> %+g\n", var->name, scalar, aggvar->name, constant);
4473    SCIPsetDebugMsg(set, "  old bounds: <%s> [%g,%g]   <%s> [%g,%g]\n",
4474       var->name, var->glbdom.lb, var->glbdom.ub, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub);
4475 
4476    /* loop as long additional changes may be found */
4477    do
4478    {
4479       aggvarbdschanged = FALSE;
4480 
4481       /* update the bounds of the aggregated variable x in x = a*y + c */
4482       if( scalar > 0.0 )
4483       {
4484          if( SCIPsetIsInfinity(set, -aggvar->glbdom.lb) )
4485             varlb = -SCIPsetInfinity(set);
4486          else
4487             varlb = aggvar->glbdom.lb * scalar + constant;
4488          if( SCIPsetIsInfinity(set, aggvar->glbdom.ub) )
4489             varub = SCIPsetInfinity(set);
4490          else
4491             varub = aggvar->glbdom.ub * scalar + constant;
4492       }
4493       else
4494       {
4495          if( SCIPsetIsInfinity(set, -aggvar->glbdom.lb) )
4496             varub = SCIPsetInfinity(set);
4497          else
4498             varub = aggvar->glbdom.lb * scalar + constant;
4499          if( SCIPsetIsInfinity(set, aggvar->glbdom.ub) )
4500             varlb = -SCIPsetInfinity(set);
4501          else
4502             varlb = aggvar->glbdom.ub * scalar + constant;
4503       }
4504       varlb = MAX(varlb, var->glbdom.lb);
4505       varub = MIN(varub, var->glbdom.ub);
4506       SCIPvarAdjustLb(var, set, &varlb);
4507       SCIPvarAdjustUb(var, set, &varub);
4508 
4509       /* check the new bounds */
4510       if( SCIPsetIsGT(set, varlb, varub) )
4511       {
4512          /* the aggregation is infeasible */
4513          *infeasible = TRUE;
4514          return SCIP_OKAY;
4515       }
4516       else if( SCIPsetIsEQ(set, varlb, varub) )
4517       {
4518          /* the aggregated variable is fixed -> fix both variables */
4519          SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4520                eventfilter, eventqueue, cliquetable, varlb, infeasible, fixed) );
4521          if( !(*infeasible) )
4522          {
4523             SCIP_Bool aggfixed;
4524 
4525             SCIP_CALL( SCIPvarFix(aggvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4526                   eventfilter, eventqueue, cliquetable, (varlb-constant)/scalar, infeasible, &aggfixed) );
4527             assert(*fixed == aggfixed);
4528          }
4529          return SCIP_OKAY;
4530       }
4531       else
4532       {
4533          if( SCIPsetIsGT(set, varlb, var->glbdom.lb) )
4534          {
4535             SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, varlb) );
4536          }
4537          if( SCIPsetIsLT(set, varub, var->glbdom.ub) )
4538          {
4539             SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, varub) );
4540          }
4541 
4542          /* update the hole list of the aggregation variable */
4543          /**@todo update hole list of aggregation variable */
4544       }
4545 
4546       /* update the bounds of the aggregation variable y in x = a*y + c  ->  y = (x-c)/a */
4547       if( scalar > 0.0 )
4548       {
4549          if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
4550             aggvarlb = -SCIPsetInfinity(set);
4551          else
4552             aggvarlb = (var->glbdom.lb - constant) / scalar;
4553          if( SCIPsetIsInfinity(set, var->glbdom.ub) )
4554             aggvarub = SCIPsetInfinity(set);
4555          else
4556             aggvarub = (var->glbdom.ub - constant) / scalar;
4557       }
4558       else
4559       {
4560          if( SCIPsetIsInfinity(set, -var->glbdom.lb) )
4561             aggvarub = SCIPsetInfinity(set);
4562          else
4563             aggvarub = (var->glbdom.lb - constant) / scalar;
4564          if( SCIPsetIsInfinity(set, var->glbdom.ub) )
4565             aggvarlb = -SCIPsetInfinity(set);
4566          else
4567             aggvarlb = (var->glbdom.ub - constant) / scalar;
4568       }
4569       aggvarlb = MAX(aggvarlb, aggvar->glbdom.lb);
4570       aggvarub = MIN(aggvarub, aggvar->glbdom.ub);
4571       SCIPvarAdjustLb(aggvar, set, &aggvarlb);
4572       SCIPvarAdjustUb(aggvar, set, &aggvarub);
4573 
4574       /* check the new bounds */
4575       if( SCIPsetIsGT(set, aggvarlb, aggvarub) )
4576       {
4577          /* the aggregation is infeasible */
4578          *infeasible = TRUE;
4579          return SCIP_OKAY;
4580       }
4581       else if( SCIPsetIsEQ(set, aggvarlb, aggvarub) )
4582       {
4583          /* the aggregation variable is fixed -> fix both variables */
4584          SCIP_CALL( SCIPvarFix(aggvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4585                eventfilter, eventqueue, cliquetable, aggvarlb, infeasible, fixed) );
4586          if( !(*infeasible) )
4587          {
4588             SCIP_Bool varfixed;
4589 
4590             SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4591                   eventfilter, eventqueue, cliquetable, aggvarlb * scalar + constant, infeasible, &varfixed) );
4592             assert(*fixed == varfixed);
4593          }
4594          return SCIP_OKAY;
4595       }
4596       else
4597       {
4598          SCIP_Real oldbd;
4599          if( SCIPsetIsGT(set, aggvarlb, aggvar->glbdom.lb) )
4600          {
4601             oldbd = aggvar->glbdom.lb;
4602             SCIP_CALL( SCIPvarChgLbGlobal(aggvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, aggvarlb) );
4603             aggvarbdschanged = !SCIPsetIsEQ(set, oldbd, aggvar->glbdom.lb);
4604          }
4605          if( SCIPsetIsLT(set, aggvarub, aggvar->glbdom.ub) )
4606          {
4607             oldbd = aggvar->glbdom.ub;
4608             SCIP_CALL( SCIPvarChgUbGlobal(aggvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, aggvarub) );
4609             aggvarbdschanged = aggvarbdschanged || !SCIPsetIsEQ(set, oldbd, aggvar->glbdom.ub);
4610          }
4611 
4612          /* update the hole list of the aggregation variable */
4613          /**@todo update hole list of aggregation variable */
4614       }
4615    }
4616    while( aggvarbdschanged );
4617 
4618    SCIPsetDebugMsg(set, "  new bounds: <%s> [%g,%g]   <%s> [%g,%g]\n",
4619       var->name, var->glbdom.lb, var->glbdom.ub, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub);
4620 
4621    return SCIP_OKAY;
4622 }
4623 
4624 /** converts loose variable into aggregated variable */
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)4625 SCIP_RETCODE SCIPvarAggregate(
4626    SCIP_VAR*             var,                /**< loose problem variable */
4627    BMS_BLKMEM*           blkmem,             /**< block memory */
4628    SCIP_SET*             set,                /**< global SCIP settings */
4629    SCIP_STAT*            stat,               /**< problem statistics */
4630    SCIP_PROB*            transprob,          /**< tranformed problem data */
4631    SCIP_PROB*            origprob,           /**< original problem data */
4632    SCIP_PRIMAL*          primal,             /**< primal data */
4633    SCIP_TREE*            tree,               /**< branch and bound tree */
4634    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
4635    SCIP_LP*              lp,                 /**< current LP data */
4636    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
4637    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
4638    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
4639    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
4640    SCIP_VAR*             aggvar,             /**< loose variable y in aggregation x = a*y + c */
4641    SCIP_Real             scalar,             /**< multiplier a in aggregation x = a*y + c */
4642    SCIP_Real             constant,           /**< constant shift c in aggregation x = a*y + c */
4643    SCIP_Bool*            infeasible,         /**< pointer to store whether the aggregation is infeasible */
4644    SCIP_Bool*            aggregated          /**< pointer to store whether the aggregation was successful */
4645    )
4646 {
4647    SCIP_VAR** vars;
4648    SCIP_Real* coefs;
4649    SCIP_Real* constants;
4650    SCIP_Real obj;
4651    SCIP_Real branchfactor;
4652    SCIP_Bool fixed;
4653    int branchpriority;
4654    int nlocksdown[NLOCKTYPES];
4655    int nlocksup[NLOCKTYPES];
4656    int nvbds;
4657    int i;
4658    int j;
4659 
4660    assert(var != NULL);
4661    assert(aggvar != NULL);
4662    assert(var->scip == set->scip);
4663    assert(var->glbdom.lb == var->locdom.lb); /*lint !e777*/
4664    assert(var->glbdom.ub == var->locdom.ub); /*lint !e777*/
4665    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
4666    assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
4667    assert(infeasible != NULL);
4668    assert(aggregated != NULL);
4669 
4670    /* check aggregation on debugging solution */
4671    SCIP_CALL( SCIPdebugCheckAggregation(set, var, &aggvar, &scalar, constant, 1) ); /*lint !e506 !e774*/
4672 
4673    *infeasible = FALSE;
4674    *aggregated = FALSE;
4675 
4676    /* get active problem variable of aggregation variable */
4677    SCIP_CALL( SCIPvarGetProbvarSum(&aggvar, set, &scalar, &constant) );
4678 
4679    /* aggregation is a fixing, if the scalar is zero */
4680    if( SCIPsetIsZero(set, scalar) )
4681    {
4682       SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventfilter,
4683             eventqueue, cliquetable, constant, infeasible, aggregated) );
4684       return SCIP_OKAY;
4685    }
4686 
4687    /* don't perform the aggregation if the aggregation variable is multi-aggregated itself */
4688    if( SCIPvarGetStatus(aggvar) == SCIP_VARSTATUS_MULTAGGR )
4689       return SCIP_OKAY;
4690 
4691    /**@todo currently we don't perform the aggregation if the aggregation variable has a non-empty hole list; this
4692     *  should be changed in the future
4693     */
4694    if( SCIPvarGetHolelistGlobal(var) != NULL )
4695       return SCIP_OKAY;
4696 
4697    assert(aggvar->glbdom.lb == aggvar->locdom.lb); /*lint !e777*/
4698    assert(aggvar->glbdom.ub == aggvar->locdom.ub); /*lint !e777*/
4699    assert(SCIPvarGetStatus(aggvar) == SCIP_VARSTATUS_LOOSE);
4700 
4701    SCIPsetDebugMsg(set, "aggregate variable <%s>[%g,%g] == %g*<%s>[%g,%g] %+g\n", var->name, var->glbdom.lb, var->glbdom.ub,
4702       scalar, aggvar->name, aggvar->glbdom.lb, aggvar->glbdom.ub, constant);
4703 
4704    /* if variable and aggregation variable are equal, the variable can be fixed: x == a*x + c  =>  x == c/(1-a) */
4705    if( var == aggvar )
4706    {
4707       if( SCIPsetIsEQ(set, scalar, 1.0) )
4708          *infeasible = !SCIPsetIsZero(set, constant);
4709       else
4710       {
4711          SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
4712                eventfilter, eventqueue, cliquetable, constant/(1.0-scalar), infeasible, aggregated) );
4713       }
4714       return SCIP_OKAY;
4715    }
4716 
4717    /* tighten the bounds of aggregated and aggregation variable */
4718    SCIP_CALL( varUpdateAggregationBounds(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
4719          branchcand, eventfilter, eventqueue, cliquetable, aggvar, scalar, constant, infeasible, &fixed) );
4720    if( *infeasible || fixed )
4721    {
4722       *aggregated = fixed;
4723       return SCIP_OKAY;
4724    }
4725 
4726    /* delete implications and variable bounds of the aggregated variable from other variables, but keep them in the
4727     * aggregated variable
4728     */
4729    SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, FALSE) );
4730    assert(var->cliquelist == NULL);
4731 
4732    /* set the aggregated variable's objective value to 0.0 */
4733    obj = var->obj;
4734    SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
4735 
4736    /* unlock all locks */
4737    for( i = 0; i < NLOCKTYPES; i++ )
4738    {
4739       nlocksdown[i] = var->nlocksdown[i];
4740       nlocksup[i] = var->nlocksup[i];
4741 
4742       var->nlocksdown[i] = 0;
4743       var->nlocksup[i] = 0;
4744    }
4745 
4746    /* check, if variable should be used as NEGATED variable of the aggregation variable */
4747    if( SCIPvarIsBinary(var) && SCIPvarIsBinary(aggvar)
4748       && var->negatedvar == NULL && aggvar->negatedvar == NULL
4749       && SCIPsetIsEQ(set, scalar, -1.0) && SCIPsetIsEQ(set, constant, 1.0) )
4750    {
4751       /* link both variables as negation pair */
4752       var->varstatus = SCIP_VARSTATUS_NEGATED; /*lint !e641*/
4753       var->data.negate.constant = 1.0;
4754       var->negatedvar = aggvar;
4755       aggvar->negatedvar = var;
4756 
4757       /* copy doNotMultiaggr status */
4758       aggvar->donotmultaggr |= var->donotmultaggr;
4759 
4760       /* mark both variables to be non-deletable */
4761       SCIPvarMarkNotDeletable(var);
4762       SCIPvarMarkNotDeletable(aggvar);
4763    }
4764    else
4765    {
4766       /* convert variable into aggregated variable */
4767       var->varstatus = SCIP_VARSTATUS_AGGREGATED; /*lint !e641*/
4768       var->data.aggregate.var = aggvar;
4769       var->data.aggregate.scalar = scalar;
4770       var->data.aggregate.constant = constant;
4771 
4772       /* copy doNotMultiaggr status */
4773       aggvar->donotmultaggr |= var->donotmultaggr;
4774 
4775       /* mark both variables to be non-deletable */
4776       SCIPvarMarkNotDeletable(var);
4777       SCIPvarMarkNotDeletable(aggvar);
4778    }
4779 
4780    /* make aggregated variable a parent of the aggregation variable */
4781    SCIP_CALL( varAddParent(aggvar, blkmem, set, var) );
4782 
4783    /* relock the variable, thus increasing the locks of the aggregation variable */
4784    for( i = 0; i < NLOCKTYPES; i++ )
4785    {
4786       SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) );
4787    }
4788 
4789    /* move the variable bounds to the aggregation variable:
4790     *  - add all variable bounds again to the variable, thus adding it to the aggregation variable
4791     *  - free the variable bounds data structures
4792     */
4793    if( var->vlbs != NULL )
4794    {
4795       nvbds = SCIPvboundsGetNVbds(var->vlbs);
4796       vars = SCIPvboundsGetVars(var->vlbs);
4797       coefs = SCIPvboundsGetCoefs(var->vlbs);
4798       constants = SCIPvboundsGetConstants(var->vlbs);
4799       for( i = 0; i < nvbds && !(*infeasible); ++i )
4800       {
4801          SCIP_CALL( SCIPvarAddVlb(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
4802                eventqueue, vars[i], coefs[i], constants[i], FALSE, infeasible, NULL) );
4803       }
4804    }
4805    if( var->vubs != NULL )
4806    {
4807       nvbds = SCIPvboundsGetNVbds(var->vubs);
4808       vars = SCIPvboundsGetVars(var->vubs);
4809       coefs = SCIPvboundsGetCoefs(var->vubs);
4810       constants = SCIPvboundsGetConstants(var->vubs);
4811       for( i = 0; i < nvbds && !(*infeasible); ++i )
4812       {
4813          SCIP_CALL( SCIPvarAddVub(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
4814                eventqueue, vars[i], coefs[i], constants[i], FALSE, infeasible, NULL) );
4815       }
4816    }
4817    SCIPvboundsFree(&var->vlbs, blkmem);
4818    SCIPvboundsFree(&var->vubs, blkmem);
4819 
4820    /* move the implications to the aggregation variable:
4821     *  - add all implications again to the variable, thus adding it to the aggregation variable
4822     *  - free the implications data structures
4823     */
4824    if( var->implics != NULL && SCIPvarGetType(aggvar) == SCIP_VARTYPE_BINARY )
4825    {
4826       assert(SCIPvarIsBinary(var));
4827       for( i = 0; i < 2; ++i )
4828       {
4829          SCIP_VAR** implvars;
4830          SCIP_BOUNDTYPE* impltypes;
4831          SCIP_Real* implbounds;
4832          int nimpls;
4833 
4834          nimpls = SCIPimplicsGetNImpls(var->implics, (SCIP_Bool)i);
4835          implvars = SCIPimplicsGetVars(var->implics, (SCIP_Bool)i);
4836          impltypes = SCIPimplicsGetTypes(var->implics, (SCIP_Bool)i);
4837          implbounds = SCIPimplicsGetBounds(var->implics, (SCIP_Bool)i);
4838 
4839          for( j = 0; j < nimpls && !(*infeasible); ++j )
4840          {
4841             /* @todo can't we omit transitive closure, because it should already have been done when adding the
4842              *       implication to the aggregated variable?
4843              */
4844             SCIP_CALL( SCIPvarAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
4845                   branchcand, eventqueue, (SCIP_Bool)i, implvars[j], impltypes[j], implbounds[j], FALSE, infeasible,
4846                   NULL) );
4847             assert(nimpls == SCIPimplicsGetNImpls(var->implics, (SCIP_Bool)i));
4848          }
4849       }
4850    }
4851    SCIPimplicsFree(&var->implics, blkmem);
4852 
4853    /* add the history entries to the aggregation variable and clear the history of the aggregated variable */
4854    SCIPhistoryUnite(aggvar->history, var->history, scalar < 0.0);
4855    SCIPhistoryUnite(aggvar->historycrun, var->historycrun, scalar < 0.0);
4856    SCIPhistoryReset(var->history);
4857    SCIPhistoryReset(var->historycrun);
4858 
4859    /* update flags of aggregation variable */
4860    aggvar->removable &= var->removable;
4861 
4862    /* update branching factors and priorities of both variables to be the maximum of both variables */
4863    branchfactor = MAX(aggvar->branchfactor, var->branchfactor);
4864    branchpriority = MAX(aggvar->branchpriority, var->branchpriority);
4865    SCIP_CALL( SCIPvarChgBranchFactor(aggvar, set, branchfactor) );
4866    SCIP_CALL( SCIPvarChgBranchPriority(aggvar, branchpriority) );
4867    SCIP_CALL( SCIPvarChgBranchFactor(var, set, branchfactor) );
4868    SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) );
4869 
4870    /* update branching direction of both variables to agree to a single direction */
4871    if( scalar >= 0.0 )
4872    {
4873       if( (SCIP_BRANCHDIR)var->branchdirection == SCIP_BRANCHDIR_AUTO )
4874       {
4875          SCIP_CALL( SCIPvarChgBranchDirection(var, (SCIP_BRANCHDIR)aggvar->branchdirection) );
4876       }
4877       else if( (SCIP_BRANCHDIR)aggvar->branchdirection == SCIP_BRANCHDIR_AUTO )
4878       {
4879          SCIP_CALL( SCIPvarChgBranchDirection(aggvar, (SCIP_BRANCHDIR)var->branchdirection) );
4880       }
4881       else if( var->branchdirection != aggvar->branchdirection )
4882       {
4883          SCIP_CALL( SCIPvarChgBranchDirection(var, SCIP_BRANCHDIR_AUTO) );
4884       }
4885    }
4886    else
4887    {
4888       if( (SCIP_BRANCHDIR)var->branchdirection == SCIP_BRANCHDIR_AUTO )
4889       {
4890          SCIP_CALL( SCIPvarChgBranchDirection(var, SCIPbranchdirOpposite((SCIP_BRANCHDIR)aggvar->branchdirection)) );
4891       }
4892       else if( (SCIP_BRANCHDIR)aggvar->branchdirection == SCIP_BRANCHDIR_AUTO )
4893       {
4894          SCIP_CALL( SCIPvarChgBranchDirection(aggvar, SCIPbranchdirOpposite((SCIP_BRANCHDIR)var->branchdirection)) );
4895       }
4896       else if( var->branchdirection != aggvar->branchdirection )
4897       {
4898          SCIP_CALL( SCIPvarChgBranchDirection(var, SCIP_BRANCHDIR_AUTO) );
4899       }
4900    }
4901 
4902    if( var->probindex != -1 )
4903    {
4904       /* inform problem about the variable's status change */
4905       SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) );
4906    }
4907 
4908    /* reset the objective value of the aggregated variable, thus adjusting the objective value of the aggregation
4909     * variable and the problem's objective offset
4910     */
4911    SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) );
4912 
4913    /* issue VARFIXED event */
4914    SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 1) );
4915 
4916    *aggregated = TRUE;
4917 
4918    return SCIP_OKAY;
4919 }
4920 
4921 /** Tries to aggregate an equality a*x + b*y == c consisting of two (implicit) integral active problem variables x and
4922  *  y. An integer aggregation (i.e. integral coefficients a' and b', such that a'*x + b'*y == c') is searched.
4923  *
4924  *  This can lead to the detection of infeasibility (e.g. if c' is fractional), or to a rejection of the aggregation
4925  *  (denoted by aggregated == FALSE), if the resulting integer coefficients are too large and thus numerically instable.
4926  */
4927 static
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)4928 SCIP_RETCODE tryAggregateIntVars(
4929    SCIP_SET*             set,                /**< global SCIP settings */
4930    BMS_BLKMEM*           blkmem,             /**< block memory */
4931    SCIP_STAT*            stat,               /**< problem statistics */
4932    SCIP_PROB*            transprob,          /**< tranformed problem data */
4933    SCIP_PROB*            origprob,           /**< original problem data */
4934    SCIP_PRIMAL*          primal,             /**< primal data */
4935    SCIP_TREE*            tree,               /**< branch and bound tree */
4936    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
4937    SCIP_LP*              lp,                 /**< current LP data */
4938    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
4939    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
4940    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
4941    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
4942    SCIP_VAR*             varx,               /**< integral variable x in equality a*x + b*y == c */
4943    SCIP_VAR*             vary,               /**< integral variable y in equality a*x + b*y == c */
4944    SCIP_Real             scalarx,            /**< multiplier a in equality a*x + b*y == c */
4945    SCIP_Real             scalary,            /**< multiplier b in equality a*x + b*y == c */
4946    SCIP_Real             rhs,                /**< right hand side c in equality a*x + b*y == c */
4947    SCIP_Bool*            infeasible,         /**< pointer to store whether the aggregation is infeasible */
4948    SCIP_Bool*            aggregated          /**< pointer to store whether the aggregation was successful */
4949    )
4950 {
4951    SCIP_VAR* aggvar;
4952    char aggvarname[SCIP_MAXSTRLEN];
4953    SCIP_Longint scalarxn = 0;
4954    SCIP_Longint scalarxd = 0;
4955    SCIP_Longint scalaryn = 0;
4956    SCIP_Longint scalaryd = 0;
4957    SCIP_Longint a;
4958    SCIP_Longint b;
4959    SCIP_Longint c;
4960    SCIP_Longint scm;
4961    SCIP_Longint gcd;
4962    SCIP_Longint currentclass;
4963    SCIP_Longint classstep;
4964    SCIP_Longint xsol;
4965    SCIP_Longint ysol;
4966    SCIP_Bool success;
4967    SCIP_VARTYPE vartype;
4968 
4969 #define MAXDNOM 1000000LL
4970 
4971    assert(set != NULL);
4972    assert(blkmem != NULL);
4973    assert(stat != NULL);
4974    assert(transprob != NULL);
4975    assert(origprob != NULL);
4976    assert(tree != NULL);
4977    assert(lp != NULL);
4978    assert(cliquetable != NULL);
4979    assert(branchcand != NULL);
4980    assert(eventqueue != NULL);
4981    assert(varx != NULL);
4982    assert(vary != NULL);
4983    assert(varx != vary);
4984    assert(infeasible != NULL);
4985    assert(aggregated != NULL);
4986    assert(SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING);
4987    assert(SCIPvarGetStatus(varx) == SCIP_VARSTATUS_LOOSE);
4988    assert(SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(varx) == SCIP_VARTYPE_IMPLINT);
4989    assert(SCIPvarGetStatus(vary) == SCIP_VARSTATUS_LOOSE);
4990    assert(SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vary) == SCIP_VARTYPE_IMPLINT);
4991    assert(!SCIPsetIsZero(set, scalarx));
4992    assert(!SCIPsetIsZero(set, scalary));
4993 
4994    *infeasible = FALSE;
4995    *aggregated = FALSE;
4996 
4997    /* get rational representation of coefficients */
4998    success = SCIPrealToRational(scalarx, -SCIPsetEpsilon(set), SCIPsetEpsilon(set), MAXDNOM, &scalarxn, &scalarxd);
4999    if( success )
5000       success = SCIPrealToRational(scalary, -SCIPsetEpsilon(set), SCIPsetEpsilon(set), MAXDNOM, &scalaryn, &scalaryd);
5001    if( !success )
5002       return SCIP_OKAY;
5003    assert(scalarxd >= 1);
5004    assert(scalaryd >= 1);
5005 
5006    /* multiply equality with smallest common denominator */
5007    scm = SCIPcalcSmaComMul(scalarxd, scalaryd);
5008    a = (scm/scalarxd)*scalarxn;
5009    b = (scm/scalaryd)*scalaryn;
5010    rhs *= scm;
5011 
5012    /* divide equality by the greatest common divisor of a and b */
5013    gcd = SCIPcalcGreComDiv(ABS(a), ABS(b));
5014    a /= gcd;
5015    b /= gcd;
5016    rhs /= gcd;
5017    assert(a != 0);
5018    assert(b != 0);
5019 
5020    /* check, if right hand side is integral */
5021    if( !SCIPsetIsFeasIntegral(set, rhs) )
5022    {
5023       *infeasible = TRUE;
5024       return SCIP_OKAY;
5025    }
5026    c = (SCIP_Longint)(SCIPsetFeasFloor(set, rhs));
5027 
5028    /* check that the scalar and constant in the aggregation are not too large to avoid numerical problems */
5029    if( REALABS((SCIP_Real)(c/a)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) /*lint !e653*/
5030       || REALABS((SCIP_Real)(b)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) /*lint !e653*/
5031       || REALABS((SCIP_Real)(a)) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) ) /*lint !e653*/
5032    {
5033       return SCIP_OKAY;
5034    }
5035 
5036    /* check, if we are in an easy case with either |a| = 1 or |b| = 1 */
5037    if( (a == 1 || a == -1) && SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER )
5038    {
5039       /* aggregate x = - b/a*y + c/a */
5040       /*lint --e{653}*/
5041       SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5042             branchcand, eventfilter, eventqueue, vary, (SCIP_Real)(-b/a), (SCIP_Real)(c/a), infeasible, aggregated) );
5043       assert(*aggregated);
5044       return SCIP_OKAY;
5045    }
5046    if( (b == 1 || b == -1) && SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER )
5047    {
5048       /* aggregate y = - a/b*x + c/b */
5049       /*lint --e{653}*/
5050       SCIP_CALL( SCIPvarAggregate(vary, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5051             branchcand, eventfilter, eventqueue, varx, (SCIP_Real)(-a/b), (SCIP_Real)(c/b), infeasible, aggregated) );
5052       assert(*aggregated);
5053       return SCIP_OKAY;
5054    }
5055 
5056    /* Both variables are integers, their coefficients are not multiples of each other, and they don't have any
5057     * common divisor. Let (x',y') be a solution of the equality
5058     *   a*x + b*y == c    ->   a*x == c - b*y
5059     * Then x = -b*z + x', y = a*z + y' with z integral gives all solutions to the equality.
5060     */
5061 
5062    /* find initial solution (x',y'):
5063     *  - find y' such that c - b*y' is a multiple of a
5064     *    - start in equivalence class c%a
5065     *    - step through classes, where each step increases class number by (-b)%a, until class 0 is visited
5066     *    - if equivalence class 0 is visited, we are done: y' equals the number of steps taken
5067     *    - 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
5068     *  - calculate x' with x' = (c - b*y')/a (which must be integral)
5069     *
5070     * Algorithm works for a > 0 only.
5071     */
5072    if( a < 0 )
5073    {
5074       a = -a;
5075       b = -b;
5076       c = -c;
5077    }
5078    assert(a > 0);
5079 
5080    /* search upwards from ysol = 0 */
5081    ysol = 0;
5082    currentclass = c % a;
5083    if( currentclass < 0 )
5084       currentclass += a;
5085    assert(0 <= currentclass && currentclass < a);
5086 
5087    classstep = (-b) % a;
5088 
5089    if( classstep < 0 )
5090       classstep += a;
5091    assert(0 <= classstep && classstep < a);
5092 
5093    while( currentclass != 0 )
5094    {
5095       assert(0 <= currentclass && currentclass < a);
5096       currentclass += classstep;
5097       if( currentclass >= a )
5098          currentclass -= a;
5099       ysol++;
5100    }
5101    assert(ysol < a);
5102    assert(((c - b*ysol) % a) == 0);
5103 
5104    xsol = (c - b*ysol)/a;
5105 
5106    /* determine variable type for new artificial variable:
5107     *
5108     * if both variables are implicit integer the new variable can be implicit too, because the integer implication on
5109     * these both variables should be enforced by some other variables, otherwise the new variable needs to be of
5110     * integral type
5111     */
5112    vartype = ((SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER)
5113       ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_IMPLINT);
5114 
5115    /* feasible solutions are (x,y) = (x',y') + z*(-b,a)
5116     * - create new integer variable z with infinite bounds
5117     * - aggregate variable x = -b*z + x'
5118     * - aggregate variable y =  a*z + y'
5119     * - the bounds of z are calculated automatically during aggregation
5120     */
5121    (void) SCIPsnprintf(aggvarname, SCIP_MAXSTRLEN, "agg%d", stat->nvaridx);
5122    SCIP_CALL( SCIPvarCreateTransformed(&aggvar, blkmem, set, stat,
5123          aggvarname, -SCIPsetInfinity(set), SCIPsetInfinity(set), 0.0, vartype,
5124          SCIPvarIsInitial(varx) || SCIPvarIsInitial(vary), SCIPvarIsRemovable(varx) && SCIPvarIsRemovable(vary),
5125          NULL, NULL, NULL, NULL, NULL) );
5126 
5127    SCIP_CALL( SCIPprobAddVar(transprob, blkmem, set, lp, branchcand, eventfilter, eventqueue, aggvar) );
5128 
5129    SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5130          branchcand, eventfilter, eventqueue, aggvar, (SCIP_Real)(-b), (SCIP_Real)xsol, infeasible, aggregated) );
5131    assert(*aggregated || *infeasible);
5132 
5133    if( !(*infeasible) )
5134    {
5135       SCIP_CALL( SCIPvarAggregate(vary, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5136             branchcand, eventfilter, eventqueue, aggvar, (SCIP_Real)a, (SCIP_Real)ysol, infeasible, aggregated) );
5137       assert(*aggregated || *infeasible);
5138    }
5139 
5140    /* release z */
5141    SCIP_CALL( SCIPvarRelease(&aggvar, blkmem, set, eventqueue, lp) );
5142 
5143    return SCIP_OKAY;  /*lint !e438*/
5144 }
5145 
5146 /** performs second step of SCIPaggregateVars():
5147  *  the variable to be aggregated is chosen among active problem variables x' and y', preferring a less strict variable
5148  *  type as aggregation variable (i.e. continuous variables are preferred over implicit integers, implicit integers
5149  *  or integers over binaries). If none of the variables is continuous, it is tried to find an integer
5150  *  aggregation (i.e. integral coefficients a'' and b'', such that a''*x' + b''*y' == c''). This can lead to
5151  *  the detection of infeasibility (e.g. if c'' is fractional), or to a rejection of the aggregation (denoted by
5152  *  aggregated == FALSE), if the resulting integer coefficients are too large and thus numerically instable.
5153  *
5154  *  @todo check for fixings, infeasibility, bound changes, or domain holes:
5155  *     a) if there is no easy aggregation and we have one binary variable and another integer/implicit/binary variable
5156  *     b) for implicit integer variables with fractional aggregation scalar (we cannot (for technical reasons) and do
5157  *        not want to aggregate implicit integer variables, since we loose the corresponding divisibility property)
5158  */
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)5159 SCIP_RETCODE SCIPvarTryAggregateVars(
5160    SCIP_SET*             set,                /**< global SCIP settings */
5161    BMS_BLKMEM*           blkmem,             /**< block memory */
5162    SCIP_STAT*            stat,               /**< problem statistics */
5163    SCIP_PROB*            transprob,          /**< tranformed problem data */
5164    SCIP_PROB*            origprob,           /**< original problem data */
5165    SCIP_PRIMAL*          primal,             /**< primal data */
5166    SCIP_TREE*            tree,               /**< branch and bound tree */
5167    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
5168    SCIP_LP*              lp,                 /**< current LP data */
5169    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
5170    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
5171    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
5172    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5173    SCIP_VAR*             varx,               /**< variable x in equality a*x + b*y == c */
5174    SCIP_VAR*             vary,               /**< variable y in equality a*x + b*y == c */
5175    SCIP_Real             scalarx,            /**< multiplier a in equality a*x + b*y == c */
5176    SCIP_Real             scalary,            /**< multiplier b in equality a*x + b*y == c */
5177    SCIP_Real             rhs,                /**< right hand side c in equality a*x + b*y == c */
5178    SCIP_Bool*            infeasible,         /**< pointer to store whether the aggregation is infeasible */
5179    SCIP_Bool*            aggregated          /**< pointer to store whether the aggregation was successful */
5180    )
5181 {
5182    SCIP_Bool easyaggr;
5183    SCIP_Real maxscalar;
5184    SCIP_Real absquot;
5185 
5186    assert(set != NULL);
5187    assert(blkmem != NULL);
5188    assert(stat != NULL);
5189    assert(transprob != NULL);
5190    assert(origprob != NULL);
5191    assert(tree != NULL);
5192    assert(lp != NULL);
5193    assert(cliquetable != NULL);
5194    assert(branchcand != NULL);
5195    assert(eventqueue != NULL);
5196    assert(varx != NULL);
5197    assert(vary != NULL);
5198    assert(varx != vary);
5199    assert(infeasible != NULL);
5200    assert(aggregated != NULL);
5201    assert(SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING);
5202    assert(SCIPvarGetStatus(varx) == SCIP_VARSTATUS_LOOSE);
5203    assert(SCIPvarGetStatus(vary) == SCIP_VARSTATUS_LOOSE);
5204    assert(!SCIPsetIsZero(set, scalarx));
5205    assert(!SCIPsetIsZero(set, scalary));
5206 
5207    *infeasible = FALSE;
5208    *aggregated = FALSE;
5209 
5210    absquot = REALABS(scalarx / scalary);
5211    maxscalar = SCIPsetFeastol(set) / SCIPsetEpsilon(set);
5212    maxscalar = MAX(maxscalar, 1.0);
5213 
5214    if( absquot > maxscalar || absquot < 1 / maxscalar )
5215       return SCIP_OKAY;
5216 
5217    /* prefer aggregating the variable of more general type (preferred aggregation variable is varx) */
5218    if( SCIPvarGetType(vary) > SCIPvarGetType(varx) ||
5219          (SCIPvarGetType(vary) == SCIPvarGetType(varx) && !SCIPvarIsBinary(vary) && SCIPvarIsBinary(varx))  )
5220    {
5221       SCIP_VAR* var;
5222       SCIP_Real scalar;
5223 
5224       /* switch the variables, such that varx is the variable of more general type (cont > implint > int > bin) */
5225       var = vary;
5226       vary = varx;
5227       varx = var;
5228       scalar = scalary;
5229       scalary = scalarx;
5230       scalarx = scalar;
5231    }
5232 
5233    /* don't aggregate if the aggregation would lead to a binary variable aggregated to a non-binary variable */
5234    if( SCIPvarIsBinary(varx) && !SCIPvarIsBinary(vary) )
5235       return SCIP_OKAY;
5236 
5237    assert(SCIPvarGetType(varx) >= SCIPvarGetType(vary));
5238 
5239    /* figure out, which variable should be aggregated */
5240    easyaggr = FALSE;
5241 
5242    /* check if it is an easy aggregation that means:
5243     *
5244     *   a*x + b*y == c -> x == -b/a * y + c/a iff |b/a| > feastol and |a/b| > feastol
5245     */
5246    if( !SCIPsetIsFeasZero(set, scalary/scalarx) && !SCIPsetIsFeasZero(set, scalarx/scalary) )
5247    {
5248       if( SCIPvarGetType(varx) == SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(vary) < SCIP_VARTYPE_CONTINUOUS )
5249       {
5250          easyaggr = TRUE;
5251       }
5252       else if( SCIPsetIsFeasIntegral(set, scalary/scalarx) )
5253       {
5254          easyaggr = TRUE;
5255       }
5256       else if( SCIPsetIsFeasIntegral(set, scalarx/scalary) && SCIPvarGetType(vary) == SCIPvarGetType(varx) )
5257       {
5258          /* we have an easy aggregation if we flip the variables x and y */
5259          SCIP_VAR* var;
5260          SCIP_Real scalar;
5261 
5262          /* switch the variables, such that varx is the aggregated variable */
5263          var = vary;
5264          vary = varx;
5265          varx = var;
5266          scalar = scalary;
5267          scalary = scalarx;
5268          scalarx = scalar;
5269          easyaggr = TRUE;
5270       }
5271       else if( SCIPvarGetType(varx) == SCIP_VARTYPE_CONTINUOUS )
5272       {
5273          /* the aggregation is still easy if both variables are continuous */
5274          assert(SCIPvarGetType(vary) == SCIP_VARTYPE_CONTINUOUS); /* otherwise we are in the first case */
5275          easyaggr = TRUE;
5276       }
5277    }
5278 
5279    /* did we find an "easy" aggregation? */
5280    if( easyaggr )
5281    {
5282       SCIP_Real scalar;
5283       SCIP_Real constant;
5284 
5285       assert(SCIPvarGetType(varx) >= SCIPvarGetType(vary));
5286 
5287       /* calculate aggregation scalar and constant: a*x + b*y == c  =>  x == -b/a * y + c/a */
5288       scalar = -scalary/scalarx;
5289       constant = rhs/scalarx;
5290 
5291       if( REALABS(constant) > SCIPsetGetHugeValue(set) * SCIPsetFeastol(set) ) /*lint !e653*/
5292          return SCIP_OKAY;
5293 
5294       /* check aggregation for integer feasibility */
5295       if( SCIPvarGetType(varx) != SCIP_VARTYPE_CONTINUOUS
5296          && SCIPvarGetType(vary) != SCIP_VARTYPE_CONTINUOUS
5297          && SCIPsetIsFeasIntegral(set, scalar) && !SCIPsetIsFeasIntegral(set, constant) )
5298       {
5299          *infeasible = TRUE;
5300          return SCIP_OKAY;
5301       }
5302 
5303       /* if the aggregation scalar is fractional, we cannot (for technical reasons) and do not want to aggregate implicit integer variables,
5304        * since then we would loose the corresponding divisibility property
5305        */
5306       assert(SCIPvarGetType(varx) != SCIP_VARTYPE_IMPLINT || SCIPsetIsFeasIntegral(set, scalar));
5307 
5308       /* aggregate the variable */
5309       SCIP_CALL( SCIPvarAggregate(varx, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5310             branchcand, eventfilter, eventqueue, vary, scalar, constant, infeasible, aggregated) );
5311       assert(*aggregated || *infeasible);
5312    }
5313    else if( (SCIPvarGetType(varx) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(varx) == SCIP_VARTYPE_IMPLINT)
5314       && (SCIPvarGetType(vary) == SCIP_VARTYPE_INTEGER || SCIPvarGetType(vary) == SCIP_VARTYPE_IMPLINT) )
5315    {
5316       /* the variables are both integral: we have to try to find an integer aggregation */
5317       SCIP_CALL( tryAggregateIntVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp, cliquetable,
5318             branchcand, eventfilter, eventqueue, varx, vary, scalarx, scalary, rhs, infeasible, aggregated) );
5319    }
5320 
5321    return SCIP_OKAY;
5322 }
5323 
5324 /** converts variable into multi-aggregated variable */
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)5325 SCIP_RETCODE SCIPvarMultiaggregate(
5326    SCIP_VAR*             var,                /**< problem variable */
5327    BMS_BLKMEM*           blkmem,             /**< block memory */
5328    SCIP_SET*             set,                /**< global SCIP settings */
5329    SCIP_STAT*            stat,               /**< problem statistics */
5330    SCIP_PROB*            transprob,          /**< tranformed problem data */
5331    SCIP_PROB*            origprob,           /**< original problem data */
5332    SCIP_PRIMAL*          primal,             /**< primal data */
5333    SCIP_TREE*            tree,               /**< branch and bound tree */
5334    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
5335    SCIP_LP*              lp,                 /**< current LP data */
5336    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
5337    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
5338    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
5339    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5340    int                   naggvars,           /**< number n of variables in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5341    SCIP_VAR**            aggvars,            /**< variables y_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5342    SCIP_Real*            scalars,            /**< multipliers a_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5343    SCIP_Real             constant,           /**< constant shift c in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
5344    SCIP_Bool*            infeasible,         /**< pointer to store whether the aggregation is infeasible */
5345    SCIP_Bool*            aggregated          /**< pointer to store whether the aggregation was successful */
5346    )
5347 {
5348    SCIP_VAR** tmpvars;
5349    SCIP_Real* tmpscalars;
5350    SCIP_Real obj;
5351    SCIP_Real branchfactor;
5352    int branchpriority;
5353    SCIP_BRANCHDIR branchdirection;
5354    int nlocksdown[NLOCKTYPES];
5355    int nlocksup[NLOCKTYPES];
5356    int v;
5357    SCIP_Real tmpconstant;
5358    SCIP_Real tmpscalar;
5359    int ntmpvars;
5360    int tmpvarssize;
5361    int tmprequiredsize;
5362    int i;
5363 
5364    assert(var != NULL);
5365    assert(var->scip == set->scip);
5366    assert(var->glbdom.lb == var->locdom.lb); /*lint !e777*/
5367    assert(var->glbdom.ub == var->locdom.ub); /*lint !e777*/
5368    assert(naggvars == 0 || aggvars != NULL);
5369    assert(naggvars == 0 || scalars != NULL);
5370    assert(infeasible != NULL);
5371    assert(aggregated != NULL);
5372 
5373    SCIPsetDebugMsg(set, "trying multi-aggregating variable <%s> == ...%d vars... %+g\n", var->name, naggvars, constant);
5374 
5375    /* check multi-aggregation on debugging solution */
5376    SCIP_CALL( SCIPdebugCheckAggregation(set, var, aggvars, scalars, constant, naggvars) ); /*lint !e506 !e774*/
5377 
5378    *infeasible = FALSE;
5379    *aggregated = FALSE;
5380 
5381    switch( SCIPvarGetStatus(var) )
5382    {
5383    case SCIP_VARSTATUS_ORIGINAL:
5384       if( var->data.original.transvar == NULL )
5385       {
5386          SCIPerrorMessage("cannot multi-aggregate an untransformed original variable\n");
5387          return SCIP_INVALIDDATA;
5388       }
5389       SCIP_CALL( SCIPvarMultiaggregate(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree,
5390             reopt, lp, cliquetable, branchcand, eventfilter, eventqueue, naggvars, aggvars, scalars, constant, infeasible, aggregated) );
5391       break;
5392 
5393    case SCIP_VARSTATUS_LOOSE:
5394       assert(!SCIPeventqueueIsDelayed(eventqueue)); /* otherwise, the pseudo objective value update gets confused */
5395 
5396       /* check if we would create a self-reference */
5397       ntmpvars = naggvars;
5398       tmpvarssize = naggvars;
5399       tmpconstant = constant;
5400       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &tmpvars, aggvars, ntmpvars) );
5401       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &tmpscalars, scalars, ntmpvars) );
5402 
5403       /* get all active variables for multi-aggregation */
5404       SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) );
5405       if( tmprequiredsize > tmpvarssize )
5406       {
5407          SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpvars, tmpvarssize, tmprequiredsize) );
5408          SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpscalars, tmpvarssize, tmprequiredsize) );
5409          tmpvarssize = tmprequiredsize;
5410          SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) );
5411          assert( tmprequiredsize <= tmpvarssize );
5412       }
5413 
5414       tmpscalar = 0.0;
5415 
5416       /* iterate over all active variables of the multi-aggregation and filter all variables which are equal to the
5417        * possible multi-aggregated variable
5418        */
5419       for( v = ntmpvars - 1; v >= 0; --v )
5420       {
5421          assert(tmpvars[v] != NULL);
5422          assert(SCIPvarGetStatus(tmpvars[v]) == SCIP_VARSTATUS_LOOSE);
5423 
5424          if( tmpvars[v]->index == var->index )
5425          {
5426             tmpscalar += tmpscalars[v];
5427             tmpvars[v] = tmpvars[ntmpvars - 1];
5428             tmpscalars[v] = tmpscalars[ntmpvars - 1];
5429             --ntmpvars;
5430          }
5431       }
5432 
5433       /* this means that x = x + a_1*y_1 + ... + a_n*y_n + c */
5434       if( SCIPsetIsEQ(set, tmpscalar, 1.0) )
5435       {
5436          if( ntmpvars == 0 )
5437          {
5438             if( SCIPsetIsZero(set, tmpconstant) ) /* x = x */
5439             {
5440                SCIPsetDebugMsg(set, "Possible multi-aggregation was completely resolved and detected to be redundant.\n");
5441                goto TERMINATE;
5442             }
5443             else /* 0 = c and c != 0 */
5444             {
5445                SCIPsetDebugMsg(set, "Multi-aggregation was completely resolved and led to infeasibility.\n");
5446                *infeasible = TRUE;
5447                goto TERMINATE;
5448             }
5449          }
5450          else if( ntmpvars == 1 ) /* 0 = a*y + c => y = -c/a */
5451          {
5452             assert(tmpscalars[0] != 0.0);
5453             assert(tmpvars[0] != NULL);
5454 
5455             SCIPsetDebugMsg(set, "Possible multi-aggregation led to fixing of variable <%s> to %g.\n", SCIPvarGetName(tmpvars[0]), -constant/tmpscalars[0]);
5456             SCIP_CALL( SCIPvarFix(tmpvars[0], blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
5457                   branchcand, eventfilter, eventqueue, cliquetable, -constant/tmpscalars[0], infeasible, aggregated) );
5458             goto TERMINATE;
5459          }
5460          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 */
5461          {
5462 	    /* both variables are different active problem variables, and both scalars are non-zero: try to aggregate them */
5463 
5464             SCIPsetDebugMsg(set, "Possible multi-aggregation led to aggregation of variables <%s> and <%s> with scalars %g and %g and constant %g.\n",
5465                   SCIPvarGetName(tmpvars[0]), SCIPvarGetName(tmpvars[1]), tmpscalars[0], tmpscalars[1], -tmpconstant);
5466 
5467             SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp,
5468                   cliquetable, branchcand, eventfilter, eventqueue, tmpvars[0], tmpvars[1], tmpscalars[0],
5469                   tmpscalars[1], -tmpconstant, infeasible, aggregated) );
5470 
5471             goto TERMINATE;
5472          }
5473          else
5474             /* @todo: it is possible to multi-aggregate another variable, does it make sense?,
5475              *        rest looks like 0 = a_1*y_1 + ... + a_n*y_n + c and has at least three variables
5476              */
5477             goto TERMINATE;
5478       }
5479       /* this means that x = b*x + a_1*y_1 + ... + a_n*y_n + c */
5480       else if( !SCIPsetIsZero(set, tmpscalar) )
5481       {
5482          tmpscalar = 1 - tmpscalar;
5483          tmpconstant /= tmpscalar;
5484          for( v = ntmpvars - 1; v >= 0; --v )
5485             tmpscalars[v] /= tmpscalar;
5486       }
5487 
5488       /* check, if we are in one of the simple cases */
5489       if( ntmpvars == 0 )
5490       {
5491          SCIPsetDebugMsg(set, "Possible multi-aggregation led to fixing of variable <%s> to %g.\n", SCIPvarGetName(var), tmpconstant);
5492          SCIP_CALL( SCIPvarFix(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
5493                eventfilter, eventqueue, cliquetable, tmpconstant, infeasible, aggregated) );
5494          goto TERMINATE;
5495       }
5496 
5497       /* if only one aggregation variable is left, we perform a normal aggregation instead of a multi-aggregation */
5498       if( ntmpvars == 1 )
5499       {
5500          SCIPsetDebugMsg(set, "Possible multi-aggregation led to aggregation of variables <%s> and <%s> with scalars %g and %g and constant %g.\n",
5501             SCIPvarGetName(var), SCIPvarGetName(tmpvars[0]), 1.0, -tmpscalars[0], tmpconstant);
5502 
5503          SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal, tree, reopt, lp,
5504                cliquetable, branchcand, eventfilter, eventqueue, var, tmpvars[0], 1.0, -tmpscalars[0], tmpconstant,
5505                infeasible, aggregated) );
5506 
5507          goto TERMINATE;
5508       }
5509 
5510       /**@todo currently we don't perform the multi aggregation if the multi aggregation variable has a non
5511        *  empty hole list; this should be changed in the future  */
5512       if( SCIPvarGetHolelistGlobal(var) != NULL )
5513          goto TERMINATE;
5514 
5515       /* if the variable is not allowed to be multi-aggregated */
5516       if( SCIPvarDoNotMultaggr(var) )
5517       {
5518          SCIPsetDebugMsg(set, "variable is not allowed to be multi-aggregated.\n");
5519          goto TERMINATE;
5520       }
5521 
5522       /* if the variable to be multi-aggregated has implications or variable bounds (i.e. is the implied variable or
5523        * variable bound variable of another variable), we have to remove it from the other variables implications or
5524        * variable bounds
5525        */
5526       SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) );
5527       assert(var->vlbs == NULL);
5528       assert(var->vubs == NULL);
5529       assert(var->implics == NULL);
5530       assert(var->cliquelist == NULL);
5531 
5532       /* set the aggregated variable's objective value to 0.0 */
5533       obj = var->obj;
5534       SCIP_CALL( SCIPvarChgObj(var, blkmem, set, transprob, primal, lp, eventqueue, 0.0) );
5535 
5536       /* since we change the variable type form loose to multi aggregated, we have to adjust the number of loose
5537        * variables in the LP data structure; the loose objective value (looseobjval) in the LP data structure, however,
5538        * gets adjusted automatically, due to the event SCIP_EVENTTYPE_OBJCHANGED which dropped in the moment where the
5539        * objective of this variable is set to zero
5540        */
5541       SCIPlpDecNLoosevars(lp);
5542 
5543       /* unlock all rounding locks */
5544       for( i = 0; i < NLOCKTYPES; i++ )
5545       {
5546          nlocksdown[i] = var->nlocksdown[i];
5547          nlocksup[i] = var->nlocksup[i];
5548 
5549          var->nlocksdown[i] = 0;
5550          var->nlocksup[i] = 0;
5551       }
5552 
5553       /* convert variable into multi-aggregated variable */
5554       var->varstatus = SCIP_VARSTATUS_MULTAGGR; /*lint !e641*/
5555       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->data.multaggr.vars, tmpvars, ntmpvars) );
5556       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &var->data.multaggr.scalars, tmpscalars, ntmpvars) );
5557       var->data.multaggr.constant = tmpconstant;
5558       var->data.multaggr.nvars = ntmpvars;
5559       var->data.multaggr.varssize = ntmpvars;
5560 
5561       /* mark variable to be non-deletable */
5562       SCIPvarMarkNotDeletable(var);
5563 
5564       /* relock the variable, thus increasing the locks of the aggregation variables */
5565       for( i = 0; i < NLOCKTYPES; i++ )
5566       {
5567          SCIP_CALL( SCIPvarAddLocks(var, blkmem, set, eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) );
5568       }
5569 
5570       /* update flags and branching factors and priorities of aggregation variables;
5571        * update preferred branching direction of all aggregation variables that don't have a preferred direction yet
5572        */
5573       branchfactor = var->branchfactor;
5574       branchpriority = var->branchpriority;
5575       branchdirection = (SCIP_BRANCHDIR)var->branchdirection;
5576 
5577       for( v = 0; v < ntmpvars; ++v )
5578       {
5579          assert(tmpvars[v] != NULL);
5580          tmpvars[v]->removable &= var->removable;
5581          branchfactor = MAX(tmpvars[v]->branchfactor, branchfactor);
5582          branchpriority = MAX(tmpvars[v]->branchpriority, branchpriority);
5583 
5584          /* mark variable to be non-deletable */
5585          SCIPvarMarkNotDeletable(tmpvars[v]);
5586       }
5587       for( v = 0; v < ntmpvars; ++v )
5588       {
5589          SCIP_CALL( SCIPvarChgBranchFactor(tmpvars[v], set, branchfactor) );
5590          SCIP_CALL( SCIPvarChgBranchPriority(tmpvars[v], branchpriority) );
5591          if( (SCIP_BRANCHDIR)tmpvars[v]->branchdirection == SCIP_BRANCHDIR_AUTO )
5592          {
5593             if( tmpscalars[v] >= 0.0 )
5594             {
5595                SCIP_CALL( SCIPvarChgBranchDirection(tmpvars[v], branchdirection) );
5596             }
5597             else
5598             {
5599                SCIP_CALL( SCIPvarChgBranchDirection(tmpvars[v], SCIPbranchdirOpposite(branchdirection)) );
5600             }
5601          }
5602       }
5603       SCIP_CALL( SCIPvarChgBranchFactor(var, set, branchfactor) );
5604       SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) );
5605 
5606       if( var->probindex != -1 )
5607       {
5608          /* inform problem about the variable's status change */
5609          SCIP_CALL( SCIPprobVarChangedStatus(transprob, blkmem, set, branchcand, cliquetable, var) );
5610       }
5611 
5612       /* issue VARFIXED event */
5613       SCIP_CALL( varEventVarFixed(var, blkmem, set, eventqueue, 2) );
5614 
5615       /* reset the objective value of the aggregated variable, thus adjusting the objective value of the aggregation
5616        * variables and the problem's objective offset
5617        */
5618       SCIP_CALL( SCIPvarAddObj(var, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, eventfilter, eventqueue, obj) );
5619 
5620       *aggregated = TRUE;
5621 
5622    TERMINATE:
5623       BMSfreeBlockMemoryArray(blkmem, &tmpscalars, tmpvarssize);
5624       BMSfreeBlockMemoryArray(blkmem, &tmpvars, tmpvarssize);
5625 
5626       break;
5627 
5628    case SCIP_VARSTATUS_COLUMN:
5629       SCIPerrorMessage("cannot multi-aggregate a column variable\n");
5630       return SCIP_INVALIDDATA;
5631 
5632    case SCIP_VARSTATUS_FIXED:
5633       SCIPerrorMessage("cannot multi-aggregate a fixed variable\n");
5634       return SCIP_INVALIDDATA;
5635 
5636    case SCIP_VARSTATUS_AGGREGATED:
5637       SCIPerrorMessage("cannot multi-aggregate an aggregated variable\n");
5638       return SCIP_INVALIDDATA;
5639 
5640    case SCIP_VARSTATUS_MULTAGGR:
5641       SCIPerrorMessage("cannot multi-aggregate a multiple aggregated variable again\n");
5642       return SCIP_INVALIDDATA;
5643 
5644    case SCIP_VARSTATUS_NEGATED:
5645       /* aggregate negation variable x in x' = offset - x, instead of aggregating x' directly:
5646        *   x' = a_1*y_1 + ... + a_n*y_n + c  ->  x = offset - x' = offset - a_1*y_1 - ... - a_n*y_n - c
5647        */
5648       assert(SCIPsetIsZero(set, var->obj));
5649       assert(var->negatedvar != NULL);
5650       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
5651       assert(var->negatedvar->negatedvar == var);
5652 
5653       /* switch the signs of the aggregation scalars */
5654       for( v = 0; v < naggvars; ++v )
5655          scalars[v] *= -1.0;
5656 
5657       /* perform the multi aggregation on the negation variable */
5658       SCIP_CALL( SCIPvarMultiaggregate(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
5659             cliquetable, branchcand, eventfilter, eventqueue, naggvars, aggvars, scalars,
5660             var->data.negate.constant - constant, infeasible, aggregated) );
5661 
5662       /* switch the signs of the aggregation scalars again, to reset them to their original values */
5663       for( v = 0; v < naggvars; ++v )
5664          scalars[v] *= -1.0;
5665       break;
5666 
5667    default:
5668       SCIPerrorMessage("unknown variable status\n");
5669       return SCIP_INVALIDDATA;
5670    }
5671 
5672    return SCIP_OKAY;
5673 }
5674 
5675 /** transformed variables are resolved to their active, fixed, or multi-aggregated problem variable of a variable,
5676  * or for original variables the same variable is returned
5677  */
5678 static
varGetActiveVar(SCIP_VAR * var)5679 SCIP_VAR* varGetActiveVar(
5680    SCIP_VAR*             var                 /**< problem variable */
5681    )
5682 {
5683    SCIP_VAR* retvar;
5684 
5685    assert(var != NULL);
5686 
5687    retvar = var;
5688 
5689    SCIPdebugMessage("get active variable of <%s>\n", var->name);
5690 
5691    while( TRUE ) /*lint !e716 */
5692    {
5693       assert(retvar != NULL);
5694 
5695       switch( SCIPvarGetStatus(retvar) )
5696       {
5697       case SCIP_VARSTATUS_ORIGINAL:
5698       case SCIP_VARSTATUS_LOOSE:
5699       case SCIP_VARSTATUS_COLUMN:
5700       case SCIP_VARSTATUS_FIXED:
5701 	 return retvar;
5702 
5703       case SCIP_VARSTATUS_MULTAGGR:
5704 	 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
5705 	 if ( retvar->data.multaggr.nvars == 1 )
5706 	    retvar = retvar->data.multaggr.vars[0];
5707 	 else
5708 	    return retvar;
5709 	 break;
5710 
5711       case SCIP_VARSTATUS_AGGREGATED:
5712 	 retvar = retvar->data.aggregate.var;
5713 	 break;
5714 
5715       case SCIP_VARSTATUS_NEGATED:
5716 	 retvar = retvar->negatedvar;
5717 	 break;
5718 
5719       default:
5720 	 SCIPerrorMessage("unknown variable status\n");
5721 	 SCIPABORT();
5722 	 return NULL; /*lint !e527*/
5723       }
5724    }
5725 }
5726 
5727 /** returns whether variable is not allowed to be multi-aggregated */
SCIPvarDoNotMultaggr(SCIP_VAR * var)5728 SCIP_Bool SCIPvarDoNotMultaggr(
5729    SCIP_VAR*             var                 /**< problem variable */
5730    )
5731 {
5732    SCIP_VAR* retvar;
5733 
5734    assert(var != NULL);
5735 
5736    retvar = varGetActiveVar(var);
5737    assert(retvar != NULL);
5738 
5739    switch( SCIPvarGetStatus(retvar) )
5740    {
5741    case SCIP_VARSTATUS_ORIGINAL:
5742    case SCIP_VARSTATUS_LOOSE:
5743    case SCIP_VARSTATUS_COLUMN:
5744    case SCIP_VARSTATUS_FIXED:
5745       return retvar->donotmultaggr;
5746 
5747    case SCIP_VARSTATUS_MULTAGGR:
5748       return FALSE;
5749 
5750    case SCIP_VARSTATUS_AGGREGATED:
5751    case SCIP_VARSTATUS_NEGATED:
5752    default:
5753       SCIPerrorMessage("wrong variable status\n");
5754       SCIPABORT();
5755       return FALSE; /*lint !e527 */
5756    }
5757 }
5758 
5759 /** gets negated variable x' = offset - x of problem variable x; the negated variable is created if not yet existing;
5760  *  the negation offset of binary variables is always 1, the offset of other variables is fixed to lb + ub when the
5761  *  negated variable is created
5762  */
SCIPvarNegate(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR ** negvar)5763 SCIP_RETCODE SCIPvarNegate(
5764    SCIP_VAR*             var,                /**< problem variable to negate */
5765    BMS_BLKMEM*           blkmem,             /**< block memory of transformed problem */
5766    SCIP_SET*             set,                /**< global SCIP settings */
5767    SCIP_STAT*            stat,               /**< problem statistics */
5768    SCIP_VAR**            negvar              /**< pointer to store the negated variable */
5769    )
5770 {
5771    assert(var != NULL);
5772    assert(var->scip == set->scip);
5773    assert(negvar != NULL);
5774 
5775    /* check, if we already created the negated variable */
5776    if( var->negatedvar == NULL )
5777    {
5778       char negvarname[SCIP_MAXSTRLEN];
5779 
5780       assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED);
5781 
5782       SCIPsetDebugMsg(set, "creating negated variable of <%s>\n", var->name);
5783 
5784       /* negation is only possible for bounded variables */
5785       if( SCIPsetIsInfinity(set, -var->glbdom.lb) || SCIPsetIsInfinity(set, var->glbdom.ub) )
5786       {
5787          SCIPerrorMessage("cannot negate unbounded variable\n");
5788          return SCIP_INVALIDDATA;
5789       }
5790 
5791       (void) SCIPsnprintf(negvarname, SCIP_MAXSTRLEN, "%s_neg", var->name);
5792 
5793       /* create negated variable */
5794       SCIP_CALL( varCreate(negvar, blkmem, set, stat, negvarname, var->glbdom.lb, var->glbdom.ub, 0.0,
5795             SCIPvarGetType(var), var->initial, var->removable, NULL, NULL, NULL, NULL, NULL) );
5796       (*negvar)->varstatus = SCIP_VARSTATUS_NEGATED; /*lint !e641*/
5797       if( SCIPvarIsBinary(var) )
5798          (*negvar)->data.negate.constant = 1.0;
5799       else
5800          (*negvar)->data.negate.constant = var->glbdom.lb + var->glbdom.ub;
5801 
5802       /* create event filter for transformed variable */
5803       if( SCIPvarIsTransformed(var) )
5804       {
5805          SCIP_CALL( SCIPeventfilterCreate(&(*negvar)->eventfilter, blkmem) );
5806       }
5807 
5808       /* set the bounds corresponding to the negation variable */
5809       (*negvar)->glbdom.lb = (*negvar)->data.negate.constant - var->glbdom.ub;
5810       (*negvar)->glbdom.ub = (*negvar)->data.negate.constant - var->glbdom.lb;
5811       (*negvar)->locdom.lb = (*negvar)->data.negate.constant - var->locdom.ub;
5812       (*negvar)->locdom.ub = (*negvar)->data.negate.constant - var->locdom.lb;
5813       /**@todo create holes in the negated variable corresponding to the holes of the negation variable */
5814 
5815       /* link the variables together */
5816       var->negatedvar = *negvar;
5817       (*negvar)->negatedvar = var;
5818 
5819       /* mark both variables to be non-deletable */
5820       SCIPvarMarkNotDeletable(var);
5821       SCIPvarMarkNotDeletable(*negvar);
5822 
5823       /* copy the branch factor and priority, and use the negative preferred branching direction */
5824       (*negvar)->branchfactor = var->branchfactor;
5825       (*negvar)->branchpriority = var->branchpriority;
5826       (*negvar)->branchdirection = SCIPbranchdirOpposite((SCIP_BRANCHDIR)var->branchdirection); /*lint !e641*/
5827 
5828       /* copy doNotMultiaggr status */
5829       (*negvar)->donotmultaggr = var->donotmultaggr;
5830 
5831       /* copy lazy bounds (they have to be flipped) */
5832       (*negvar)->lazylb = (*negvar)->data.negate.constant - var->lazyub;
5833       (*negvar)->lazyub = (*negvar)->data.negate.constant - var->lazylb;
5834 
5835       /* make negated variable a parent of the negation variable (negated variable is captured as a parent) */
5836       SCIP_CALL( varAddParent(var, blkmem, set, *negvar) );
5837       assert((*negvar)->nuses == 1);
5838    }
5839    assert(var->negatedvar != NULL);
5840 
5841    /* return the negated variable */
5842    *negvar = var->negatedvar;
5843 
5844    /* exactly one variable of the negation pair has to be marked as negated variable */
5845    assert((SCIPvarGetStatus(*negvar) == SCIP_VARSTATUS_NEGATED) != (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED));
5846 
5847    return SCIP_OKAY;
5848 }
5849 
5850 /** informs variable that its position in problem's vars array changed */
5851 static
varSetProbindex(SCIP_VAR * var,int probindex)5852 void varSetProbindex(
5853    SCIP_VAR*             var,                /**< problem variable */
5854    int                   probindex           /**< new problem index of variable (-1 for removal) */
5855    )
5856 {
5857    assert(var != NULL);
5858    assert(probindex >= 0 || var->vlbs == NULL);
5859    assert(probindex >= 0 || var->vubs == NULL);
5860    assert(probindex >= 0 || var->implics == NULL);
5861 
5862    var->probindex = probindex;
5863    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
5864    {
5865       assert(var->data.col != NULL);
5866       var->data.col->var_probindex = probindex;
5867    }
5868 }
5869 
5870 /** informs variable that its position in problem's vars array changed */
SCIPvarSetProbindex(SCIP_VAR * var,int probindex)5871 void SCIPvarSetProbindex(
5872    SCIP_VAR*             var,                /**< problem variable */
5873    int                   probindex           /**< new problem index of variable */
5874    )
5875 {
5876    assert(var != NULL);
5877    assert(probindex >= 0);
5878 
5879    varSetProbindex(var, probindex);
5880 }
5881 
5882 /** gives the variable a new name
5883  *
5884  *  @note the old pointer is overwritten, which might result in a memory leakage
5885  */
SCIPvarSetNamePointer(SCIP_VAR * var,const char * name)5886 void SCIPvarSetNamePointer(
5887    SCIP_VAR*             var,                /**< problem variable */
5888    const char*           name                /**< new name of variable */
5889    )
5890 {
5891    assert(var != NULL);
5892    assert(name != NULL);
5893 
5894    var->name = (char*)name;
5895 }
5896 
5897 /** informs variable that it will be removed from the problem; adjusts probindex and removes variable from the
5898  *  implication graph;
5899  *  If 'final' is TRUE, the thorough implication graph removal is not performed. Instead, only the
5900  *  variable bounds and implication data structures of the variable are freed. Since in the final removal
5901  *  of all variables from the transformed problem, this deletes the implication graph completely and is faster
5902  *  than removing the variables one by one, each time updating all lists of the other variables.
5903  */
SCIPvarRemove(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_CLIQUETABLE * cliquetable,SCIP_SET * set,SCIP_Bool final)5904 SCIP_RETCODE SCIPvarRemove(
5905    SCIP_VAR*             var,                /**< problem variable */
5906    BMS_BLKMEM*           blkmem,             /**< block memory buffer */
5907    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
5908    SCIP_SET*             set,                /**< global SCIP settings */
5909    SCIP_Bool             final               /**< is this the final removal of all problem variables? */
5910    )
5911 {
5912    assert(SCIPvarGetProbindex(var) >= 0);
5913    assert(var->scip == set->scip);
5914 
5915    /* if the variable is active in the transformed problem, remove it from the implication graph */
5916    if( SCIPvarIsTransformed(var)
5917       && (SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN) )
5918    {
5919       if( final )
5920       {
5921          /* just destroy the data structures */
5922          SCIPvboundsFree(&var->vlbs, blkmem);
5923          SCIPvboundsFree(&var->vubs, blkmem);
5924          SCIPimplicsFree(&var->implics, blkmem);
5925       }
5926       else
5927       {
5928          /* unlink the variable from all other variables' lists and free the data structures */
5929          SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, FALSE, TRUE) );
5930       }
5931    }
5932 
5933    /* mark the variable to be no longer a member of the problem */
5934    varSetProbindex(var, -1);
5935 
5936    return SCIP_OKAY;
5937 }
5938 
5939 /** marks the variable to be deleted from the problem */
SCIPvarMarkDeleted(SCIP_VAR * var)5940 void SCIPvarMarkDeleted(
5941    SCIP_VAR*             var                 /**< problem variable */
5942    )
5943 {
5944    assert(var != NULL);
5945    assert(var->probindex != -1);
5946 
5947    var->deleted = TRUE;
5948 }
5949 
5950 /** marks the variable to not to be multi-aggregated */
SCIPvarMarkDoNotMultaggr(SCIP_VAR * var)5951 SCIP_RETCODE SCIPvarMarkDoNotMultaggr(
5952    SCIP_VAR*             var                 /**< problem variable */
5953    )
5954 {
5955    SCIP_VAR* retvar;
5956 
5957    assert(var != NULL);
5958 
5959    retvar = varGetActiveVar(var);
5960    assert(retvar != NULL);
5961 
5962    switch( SCIPvarGetStatus(retvar) )
5963    {
5964    case SCIP_VARSTATUS_ORIGINAL:
5965    case SCIP_VARSTATUS_LOOSE:
5966    case SCIP_VARSTATUS_COLUMN:
5967    case SCIP_VARSTATUS_FIXED:
5968       retvar->donotmultaggr = TRUE;
5969       break;
5970 
5971    case SCIP_VARSTATUS_MULTAGGR:
5972       SCIPerrorMessage("cannot mark a multi-aggregated variable to not be multi-aggregated.\n");
5973       return SCIP_INVALIDDATA;
5974 
5975    case SCIP_VARSTATUS_AGGREGATED:
5976    case SCIP_VARSTATUS_NEGATED:
5977    default:
5978       SCIPerrorMessage("wrong variable status\n");
5979       return SCIP_INVALIDDATA;
5980    }
5981 
5982    return SCIP_OKAY;
5983 }
5984 
5985 /** changes type of variable; cannot be called, if var belongs to a problem */
SCIPvarChgType(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_PRIMAL * primal,SCIP_LP * lp,SCIP_EVENTQUEUE * eventqueue,SCIP_VARTYPE vartype)5986 SCIP_RETCODE SCIPvarChgType(
5987    SCIP_VAR*             var,                /**< problem variable to change */
5988    BMS_BLKMEM*           blkmem,             /**< block memory */
5989    SCIP_SET*             set,                /**< global SCIP settings */
5990    SCIP_PRIMAL*          primal,             /**< primal data */
5991    SCIP_LP*              lp,                 /**< current LP data */
5992    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5993    SCIP_VARTYPE          vartype             /**< new type of variable */
5994    )
5995 {
5996    SCIP_EVENT* event;
5997    SCIP_VARTYPE oldtype;
5998 
5999    assert(var != NULL);
6000 
6001    SCIPdebugMessage("change type of <%s> from %d to %d\n", var->name, SCIPvarGetType(var), vartype);
6002 
6003    if( var->probindex >= 0 )
6004    {
6005       SCIPerrorMessage("cannot change type of variable already in the problem\n");
6006       return SCIP_INVALIDDATA;
6007    }
6008 
6009    oldtype = (SCIP_VARTYPE)var->vartype;
6010    var->vartype = vartype; /*lint !e641*/
6011 
6012    if( SCIPsetGetStage(set) > SCIP_STAGE_TRANSFORMING )
6013    {
6014       SCIP_CALL( SCIPeventCreateTypeChanged(&event, blkmem, var, oldtype, vartype) );
6015       SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) );
6016    }
6017 
6018    if( var->negatedvar != NULL )
6019    {
6020       assert(oldtype == (SCIP_VARTYPE)var->negatedvar->vartype
6021             || SCIPvarIsBinary(var) == SCIPvarIsBinary(var->negatedvar));
6022 
6023 
6024       var->negatedvar->vartype = vartype; /*lint !e641*/
6025 
6026       if( SCIPsetGetStage(set) > SCIP_STAGE_TRANSFORMING )
6027       {
6028          SCIP_CALL( SCIPeventCreateTypeChanged(&event, blkmem, var->negatedvar, oldtype, vartype) );
6029          SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) );
6030       }
6031    }
6032 
6033    return SCIP_OKAY;
6034 }
6035 
6036 /** appends OBJCHANGED event to the event queue */
6037 static
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)6038 SCIP_RETCODE varEventObjChanged(
6039    SCIP_VAR*             var,                /**< problem variable to change */
6040    BMS_BLKMEM*           blkmem,             /**< block memory */
6041    SCIP_SET*             set,                /**< global SCIP settings */
6042    SCIP_PRIMAL*          primal,             /**< primal data */
6043    SCIP_LP*              lp,                 /**< current LP data */
6044    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
6045    SCIP_Real             oldobj,             /**< old objective value for variable */
6046    SCIP_Real             newobj              /**< new objective value for variable */
6047    )
6048 {
6049    SCIP_EVENT* event;
6050 
6051    assert(var != NULL);
6052    assert(var->scip == set->scip);
6053    assert(var->eventfilter != NULL);
6054    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
6055    assert(SCIPvarIsTransformed(var));
6056 
6057    /* In the case where the objcetive value of a variable is very close to epsilon, and it is aggregated
6058    * into a variable with a big objective value, round-off errors might make the assert oldobj != newobj fail.
6059    * Hence, we relax it by letting it pass if the variables are percieved the same and we use very large values
6060    * that make comparison with values close to epsilon inaccurate.
6061    */
6062    assert(!SCIPsetIsEQ(set, oldobj, newobj) ||
6063           (SCIPsetIsEQ(set, oldobj, newobj) && REALABS(newobj) > 1e+15 * SCIPsetEpsilon(set))
6064    );
6065 
6066    SCIP_CALL( SCIPeventCreateObjChanged(&event, blkmem, var, oldobj, newobj) );
6067    SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, primal, lp, NULL, NULL, &event) );
6068 
6069    return SCIP_OKAY;
6070 }
6071 
6072 /** changes objective value of variable */
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)6073 SCIP_RETCODE SCIPvarChgObj(
6074    SCIP_VAR*             var,                /**< variable to change */
6075    BMS_BLKMEM*           blkmem,             /**< block memory */
6076    SCIP_SET*             set,                /**< global SCIP settings */
6077    SCIP_PROB*            prob,               /**< problem data */
6078    SCIP_PRIMAL*          primal,             /**< primal data */
6079    SCIP_LP*              lp,                 /**< current LP data */
6080    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
6081    SCIP_Real             newobj              /**< new objective value for variable */
6082    )
6083 {
6084    SCIP_Real oldobj;
6085 
6086    assert(var != NULL);
6087    assert(set != NULL);
6088    assert(var->scip == set->scip);
6089 
6090    SCIPsetDebugMsg(set, "changing objective value of <%s> from %g to %g\n", var->name, var->obj, newobj);
6091 
6092    if( !SCIPsetIsEQ(set, var->obj, newobj) )
6093    {
6094       switch( SCIPvarGetStatus(var) )
6095       {
6096       case SCIP_VARSTATUS_ORIGINAL:
6097          if( var->data.original.transvar != NULL )
6098          {
6099             assert(SCIPprobIsTransformed(prob));
6100 
6101             SCIP_CALL( SCIPvarChgObj(var->data.original.transvar, blkmem, set, prob, primal, lp, eventqueue,
6102                   (SCIP_Real) prob->objsense * newobj/prob->objscale) );
6103          }
6104          else
6105             assert(set->stage == SCIP_STAGE_PROBLEM);
6106 
6107          var->obj = newobj;
6108          var->unchangedobj = newobj;
6109 
6110          break;
6111 
6112       case SCIP_VARSTATUS_LOOSE:
6113       case SCIP_VARSTATUS_COLUMN:
6114          oldobj = var->obj;
6115          var->obj = newobj;
6116 
6117          /* update unchanged objective value of variable */
6118          if( !lp->divingobjchg )
6119             var->unchangedobj = newobj;
6120 
6121          /* update the number of variables with non-zero objective coefficient;
6122           * we only want to do the update, if the variable is added to the problem;
6123           * since the objective of inactive variables cannot be changed, this corresponds to probindex != -1
6124           */
6125          if( SCIPvarIsActive(var) )
6126             SCIPprobUpdateNObjVars(prob, set, oldobj, var->obj);
6127 
6128          SCIP_CALL( varEventObjChanged(var, blkmem, set, primal, lp, eventqueue, oldobj, var->obj) );
6129          break;
6130 
6131       case SCIP_VARSTATUS_FIXED:
6132       case SCIP_VARSTATUS_AGGREGATED:
6133       case SCIP_VARSTATUS_MULTAGGR:
6134       case SCIP_VARSTATUS_NEGATED:
6135          SCIPerrorMessage("cannot change objective value of a fixed, aggregated, multi-aggregated, or negated variable\n");
6136          return SCIP_INVALIDDATA;
6137 
6138       default:
6139          SCIPerrorMessage("unknown variable status\n");
6140          return SCIP_INVALIDDATA;
6141       }
6142    }
6143 
6144    return SCIP_OKAY;
6145 }
6146 
6147 /** adds value to objective value of variable */
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)6148 SCIP_RETCODE SCIPvarAddObj(
6149    SCIP_VAR*             var,                /**< variable to change */
6150    BMS_BLKMEM*           blkmem,             /**< block memory */
6151    SCIP_SET*             set,                /**< global SCIP settings */
6152    SCIP_STAT*            stat,               /**< problem statistics */
6153    SCIP_PROB*            transprob,          /**< transformed problem data */
6154    SCIP_PROB*            origprob,           /**< original problem data */
6155    SCIP_PRIMAL*          primal,             /**< primal data */
6156    SCIP_TREE*            tree,               /**< branch and bound tree */
6157    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
6158    SCIP_LP*              lp,                 /**< current LP data */
6159    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
6160    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
6161    SCIP_Real             addobj              /**< additional objective value for variable */
6162    )
6163 {
6164    assert(var != NULL);
6165    assert(set != NULL);
6166    assert(var->scip == set->scip);
6167    assert(set->stage < SCIP_STAGE_INITSOLVE);
6168 
6169    SCIPsetDebugMsg(set, "adding %g to objective value %g of <%s>\n", addobj, var->obj, var->name);
6170 
6171    if( !SCIPsetIsZero(set, addobj) )
6172    {
6173       SCIP_Real oldobj;
6174       int i;
6175 
6176       switch( SCIPvarGetStatus(var) )
6177       {
6178       case SCIP_VARSTATUS_ORIGINAL:
6179          if( var->data.original.transvar != NULL )
6180          {
6181             SCIP_CALL( SCIPvarAddObj(var->data.original.transvar, blkmem, set, stat, transprob, origprob, primal, tree,
6182                   reopt, lp, eventfilter, eventqueue, (SCIP_Real) transprob->objsense * addobj/transprob->objscale) );
6183          }
6184          else
6185             assert(set->stage == SCIP_STAGE_PROBLEM);
6186 
6187          var->obj += addobj;
6188          var->unchangedobj += addobj;
6189          assert(SCIPsetIsEQ(set, var->obj, var->unchangedobj));
6190 
6191          break;
6192 
6193       case SCIP_VARSTATUS_LOOSE:
6194       case SCIP_VARSTATUS_COLUMN:
6195          oldobj = var->obj;
6196          var->obj += addobj;
6197 
6198          /* update unchanged objective value of variable */
6199          if( !lp->divingobjchg )
6200          {
6201             var->unchangedobj += addobj;
6202             assert(SCIPsetIsEQ(set, var->obj, var->unchangedobj));
6203          }
6204 
6205          /* update the number of variables with non-zero objective coefficient;
6206           * we only want to do the update, if the variable is added to the problem;
6207           * since the objective of inactive variables cannot be changed, this corresponds to probindex != -1
6208           */
6209          if( SCIPvarIsActive(var) )
6210 	    SCIPprobUpdateNObjVars(transprob, set, oldobj, var->obj);
6211 
6212          SCIP_CALL( varEventObjChanged(var, blkmem, set, primal, lp, eventqueue, oldobj, var->obj) );
6213          break;
6214 
6215       case SCIP_VARSTATUS_FIXED:
6216          assert(SCIPsetIsEQ(set, var->locdom.lb, var->locdom.ub));
6217          SCIPprobAddObjoffset(transprob, var->locdom.lb * addobj);
6218          SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6219          break;
6220 
6221       case SCIP_VARSTATUS_AGGREGATED:
6222          /* x = a*y + c  ->  add a*addobj to obj. val. of y, and c*addobj to obj. offset of problem */
6223          SCIPprobAddObjoffset(transprob, var->data.aggregate.constant * addobj);
6224          SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6225          SCIP_CALL( SCIPvarAddObj(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, primal, tree, reopt,
6226                lp, eventfilter, eventqueue, var->data.aggregate.scalar * addobj) );
6227          break;
6228 
6229       case SCIP_VARSTATUS_MULTAGGR:
6230          assert(!var->donotmultaggr);
6231          /* 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 */
6232          SCIPprobAddObjoffset(transprob, var->data.multaggr.constant * addobj);
6233          SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6234          for( i = 0; i < var->data.multaggr.nvars; ++i )
6235          {
6236             SCIP_CALL( SCIPvarAddObj(var->data.multaggr.vars[i], blkmem, set, stat, transprob, origprob, primal, tree,
6237                   reopt, lp, eventfilter, eventqueue, var->data.multaggr.scalars[i] * addobj) );
6238          }
6239          break;
6240 
6241       case SCIP_VARSTATUS_NEGATED:
6242          /* x' = offset - x  ->  add -addobj to obj. val. of x and offset*addobj to obj. offset of problem */
6243          assert(var->negatedvar != NULL);
6244          assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
6245          assert(var->negatedvar->negatedvar == var);
6246          SCIPprobAddObjoffset(transprob, var->data.negate.constant * addobj);
6247          SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
6248          SCIP_CALL( SCIPvarAddObj(var->negatedvar, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp,
6249                eventfilter, eventqueue, -addobj) );
6250          break;
6251 
6252       default:
6253          SCIPerrorMessage("unknown variable status\n");
6254          return SCIP_INVALIDDATA;
6255       }
6256    }
6257 
6258    return SCIP_OKAY;
6259 }
6260 
6261 /** changes objective value of variable in current dive */
SCIPvarChgObjDive(SCIP_VAR * var,SCIP_SET * set,SCIP_LP * lp,SCIP_Real newobj)6262 SCIP_RETCODE SCIPvarChgObjDive(
6263    SCIP_VAR*             var,                /**< problem variable to change */
6264    SCIP_SET*             set,                /**< global SCIP settings */
6265    SCIP_LP*              lp,                 /**< current LP data */
6266    SCIP_Real             newobj              /**< new objective value for variable */
6267    )
6268 {
6269    assert(var != NULL);
6270    assert(set != NULL);
6271    assert(var->scip == set->scip);
6272    assert(lp != NULL);
6273 
6274    SCIPsetDebugMsg(set, "changing objective of <%s> to %g in current dive\n", var->name, newobj);
6275 
6276    if( SCIPsetIsZero(set, newobj) )
6277       newobj = 0.0;
6278 
6279    /* change objective value of attached variables */
6280    switch( SCIPvarGetStatus(var) )
6281    {
6282    case SCIP_VARSTATUS_ORIGINAL:
6283       assert(var->data.original.transvar != NULL);
6284       SCIP_CALL( SCIPvarChgObjDive(var->data.original.transvar, set, lp, newobj) );
6285       break;
6286 
6287    case SCIP_VARSTATUS_COLUMN:
6288       assert(var->data.col != NULL);
6289       SCIP_CALL( SCIPcolChgObj(var->data.col, set, lp, newobj) );
6290       break;
6291 
6292    case SCIP_VARSTATUS_LOOSE:
6293    case SCIP_VARSTATUS_FIXED:
6294       /* nothing to do here: only the constant shift in objective function would change */
6295       break;
6296 
6297    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
6298       assert(var->data.aggregate.var != NULL);
6299       assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
6300       SCIP_CALL( SCIPvarChgObjDive(var->data.aggregate.var, set, lp, newobj / var->data.aggregate.scalar) );
6301       /* the constant can be ignored, because it would only affect the objective shift */
6302       break;
6303 
6304    case SCIP_VARSTATUS_MULTAGGR:
6305       SCIPerrorMessage("cannot change diving objective value of a multi-aggregated variable\n");
6306       return SCIP_INVALIDDATA;
6307 
6308    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
6309       assert(var->negatedvar != NULL);
6310       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
6311       assert(var->negatedvar->negatedvar == var);
6312       SCIP_CALL( SCIPvarChgObjDive(var->negatedvar, set, lp, -newobj) );
6313       /* the offset can be ignored, because it would only affect the objective shift */
6314       break;
6315 
6316    default:
6317       SCIPerrorMessage("unknown variable status\n");
6318       return SCIP_INVALIDDATA;
6319    }
6320 
6321    return SCIP_OKAY;
6322 }
6323 
6324 /** adjust lower bound to integral value, if variable is integral */
SCIPvarAdjustLb(SCIP_VAR * var,SCIP_SET * set,SCIP_Real * lb)6325 void SCIPvarAdjustLb(
6326    SCIP_VAR*             var,                /**< problem variable */
6327    SCIP_SET*             set,                /**< global SCIP settings */
6328    SCIP_Real*            lb                  /**< pointer to lower bound to adjust */
6329    )
6330 {
6331    assert(var != NULL);
6332    assert(set != NULL);
6333    assert(var->scip == set->scip);
6334    assert(lb != NULL);
6335 
6336    SCIPsetDebugMsg(set, "adjust lower bound %g of <%s>\n", *lb, var->name);
6337 
6338    *lb = adjustedLb(set, SCIPvarGetType(var), *lb);
6339 }
6340 
6341 /** adjust upper bound to integral value, if variable is integral */
SCIPvarAdjustUb(SCIP_VAR * var,SCIP_SET * set,SCIP_Real * ub)6342 void SCIPvarAdjustUb(
6343    SCIP_VAR*             var,                /**< problem variable */
6344    SCIP_SET*             set,                /**< global SCIP settings */
6345    SCIP_Real*            ub                  /**< pointer to upper bound to adjust */
6346    )
6347 {
6348    assert(var != NULL);
6349    assert(set != NULL);
6350    assert(var->scip == set->scip);
6351    assert(ub != NULL);
6352 
6353    SCIPsetDebugMsg(set, "adjust upper bound %g of <%s>\n", *ub, var->name);
6354 
6355    *ub = adjustedUb(set, SCIPvarGetType(var), *ub);
6356 }
6357 
6358 /** adjust lower or upper bound to integral value, if variable is integral */
SCIPvarAdjustBd(SCIP_VAR * var,SCIP_SET * set,SCIP_BOUNDTYPE boundtype,SCIP_Real * bd)6359 void SCIPvarAdjustBd(
6360    SCIP_VAR*             var,                /**< problem variable */
6361    SCIP_SET*             set,                /**< global SCIP settings */
6362    SCIP_BOUNDTYPE        boundtype,          /**< type of bound to adjust */
6363    SCIP_Real*            bd                  /**< pointer to bound to adjust */
6364    )
6365 {
6366    assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER);
6367 
6368    if( boundtype == SCIP_BOUNDTYPE_LOWER )
6369       SCIPvarAdjustLb(var, set, bd);
6370    else
6371       SCIPvarAdjustUb(var, set, bd);
6372 }
6373 
6374 /** changes lower bound of original variable in original problem */
SCIPvarChgLbOriginal(SCIP_VAR * var,SCIP_SET * set,SCIP_Real newbound)6375 SCIP_RETCODE SCIPvarChgLbOriginal(
6376    SCIP_VAR*             var,                /**< problem variable to change */
6377    SCIP_SET*             set,                /**< global SCIP settings */
6378    SCIP_Real             newbound            /**< new bound for variable */
6379    )
6380 {
6381    int i;
6382 
6383    assert(var != NULL);
6384    assert(!SCIPvarIsTransformed(var));
6385    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
6386    assert(set != NULL);
6387    assert(var->scip == set->scip);
6388    assert(set->stage == SCIP_STAGE_PROBLEM);
6389 
6390    /* check that the bound is feasible */
6391    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsLE(set, newbound, SCIPvarGetUbOriginal(var)));
6392    /* adjust bound to integral value if variable is of integral type */
6393    newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
6394 
6395    if( SCIPsetIsZero(set, newbound) )
6396       newbound = 0.0;
6397 
6398    /* original domains are only stored for ORIGINAL variables, not for NEGATED */
6399    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL )
6400    {
6401       SCIPsetDebugMsg(set, "changing original lower bound of <%s> from %g to %g\n",
6402          var->name, var->data.original.origdom.lb, newbound);
6403 
6404       if( SCIPsetIsEQ(set, var->data.original.origdom.lb, newbound) )
6405          return SCIP_OKAY;
6406 
6407       /* change the bound */
6408       var->data.original.origdom.lb = newbound;
6409    }
6410    else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED )
6411    {
6412       assert( var->negatedvar != NULL );
6413       SCIP_CALL( SCIPvarChgUbOriginal(var->negatedvar, set, var->data.negate.constant - newbound) );
6414    }
6415 
6416    /* process parent variables */
6417    for( i = 0; i < var->nparentvars; ++i )
6418    {
6419       SCIP_VAR* parentvar;
6420 
6421       parentvar = var->parentvars[i];
6422       assert(parentvar != NULL);
6423       assert(SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_NEGATED);
6424       assert(parentvar->negatedvar == var);
6425       assert(var->negatedvar == parentvar);
6426 
6427       SCIP_CALL( SCIPvarChgUbOriginal(parentvar, set, parentvar->data.negate.constant - newbound) );
6428    }
6429 
6430    return SCIP_OKAY;
6431 }
6432 
6433 /** changes upper bound of original variable in original problem */
SCIPvarChgUbOriginal(SCIP_VAR * var,SCIP_SET * set,SCIP_Real newbound)6434 SCIP_RETCODE SCIPvarChgUbOriginal(
6435    SCIP_VAR*             var,                /**< problem variable to change */
6436    SCIP_SET*             set,                /**< global SCIP settings */
6437    SCIP_Real             newbound            /**< new bound for variable */
6438    )
6439 {
6440    int i;
6441 
6442    assert(var != NULL);
6443    assert(!SCIPvarIsTransformed(var));
6444    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
6445    assert(set != NULL);
6446    assert(var->scip == set->scip);
6447    assert(set->stage == SCIP_STAGE_PROBLEM);
6448 
6449    /* check that the bound is feasible */
6450    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsGE(set, newbound, SCIPvarGetLbOriginal(var)));
6451    /* adjust bound to integral value if variable is of integral type */
6452    newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
6453 
6454    if( SCIPsetIsZero(set, newbound) )
6455       newbound = 0.0;
6456 
6457    /* original domains are only stored for ORIGINAL variables, not for NEGATED */
6458    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL )
6459    {
6460       SCIPsetDebugMsg(set, "changing original upper bound of <%s> from %g to %g\n",
6461          var->name, var->data.original.origdom.ub, newbound);
6462 
6463       if( SCIPsetIsEQ(set, var->data.original.origdom.ub, newbound) )
6464          return SCIP_OKAY;
6465 
6466       /* change the bound */
6467       var->data.original.origdom.ub = newbound;
6468    }
6469    else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED )
6470    {
6471       assert( var->negatedvar != NULL );
6472       SCIP_CALL( SCIPvarChgLbOriginal(var->negatedvar, set, var->data.negate.constant - newbound) );
6473    }
6474 
6475    /* process parent variables */
6476    for( i = 0; i < var->nparentvars; ++i )
6477    {
6478       SCIP_VAR* parentvar;
6479 
6480       parentvar = var->parentvars[i];
6481       assert(parentvar != NULL);
6482       assert(SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_NEGATED);
6483       assert(parentvar->negatedvar == var);
6484       assert(var->negatedvar == parentvar);
6485 
6486       SCIP_CALL( SCIPvarChgLbOriginal(parentvar, set, parentvar->data.negate.constant - newbound) );
6487    }
6488 
6489    return SCIP_OKAY;
6490 }
6491 
6492 /** appends GLBCHANGED event to the event queue */
6493 static
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)6494 SCIP_RETCODE varEventGlbChanged(
6495    SCIP_VAR*             var,                /**< problem variable to change */
6496    BMS_BLKMEM*           blkmem,             /**< block memory */
6497    SCIP_SET*             set,                /**< global SCIP settings */
6498    SCIP_LP*              lp,                 /**< current LP data */
6499    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
6500    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
6501    SCIP_Real             oldbound,           /**< old lower bound for variable */
6502    SCIP_Real             newbound            /**< new lower bound for variable */
6503    )
6504 {
6505    assert(var != NULL);
6506    assert(var->eventfilter != NULL);
6507    assert(SCIPvarIsTransformed(var));
6508    assert(!SCIPsetIsEQ(set, oldbound, newbound) || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
6509    assert(set != NULL);
6510    assert(var->scip == set->scip);
6511 
6512    /* check, if the variable is being tracked for bound changes
6513     * COLUMN and LOOSE variables are tracked always, because global/root pseudo objective value has to be updated
6514     */
6515    if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GLBCHANGED) != 0)
6516       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
6517       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
6518    {
6519       SCIP_EVENT* event;
6520 
6521       SCIPsetDebugMsg(set, "issue GLBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
6522 
6523       SCIP_CALL( SCIPeventCreateGlbChanged(&event, blkmem, var, oldbound, newbound) );
6524       SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
6525    }
6526 
6527    return SCIP_OKAY;
6528 }
6529 
6530 /** appends GUBCHANGED event to the event queue */
6531 static
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)6532 SCIP_RETCODE varEventGubChanged(
6533    SCIP_VAR*             var,                /**< problem variable to change */
6534    BMS_BLKMEM*           blkmem,             /**< block memory */
6535    SCIP_SET*             set,                /**< global SCIP settings */
6536    SCIP_LP*              lp,                 /**< current LP data */
6537    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
6538    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
6539    SCIP_Real             oldbound,           /**< old lower bound for variable */
6540    SCIP_Real             newbound            /**< new lower bound for variable */
6541    )
6542 {
6543    assert(var != NULL);
6544    assert(var->eventfilter != NULL);
6545    assert(SCIPvarIsTransformed(var));
6546    assert(!SCIPsetIsEQ(set, oldbound, newbound) || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
6547    assert(set != NULL);
6548    assert(var->scip == set->scip);
6549 
6550    /* check, if the variable is being tracked for bound changes
6551     * COLUMN and LOOSE variables are tracked always, because global/root pseudo objective value has to be updated
6552     */
6553    if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GUBCHANGED) != 0)
6554       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
6555       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
6556    {
6557       SCIP_EVENT* event;
6558 
6559       SCIPsetDebugMsg(set, "issue GUBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
6560 
6561       SCIP_CALL( SCIPeventCreateGubChanged(&event, blkmem, var, oldbound, newbound) );
6562       SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
6563    }
6564 
6565    return SCIP_OKAY;
6566 }
6567 
6568 /** appends GHOLEADDED event to the event queue */
6569 static
varEventGholeAdded(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_Real left,SCIP_Real right)6570 SCIP_RETCODE varEventGholeAdded(
6571    SCIP_VAR*             var,                /**< problem variable to change */
6572    BMS_BLKMEM*           blkmem,             /**< block memory */
6573    SCIP_SET*             set,                /**< global SCIP settings */
6574    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
6575    SCIP_Real             left,               /**< left bound of open interval in new hole */
6576    SCIP_Real             right               /**< right bound of open interval in new hole */
6577    )
6578 {
6579    assert(var != NULL);
6580    assert(var->eventfilter != NULL);
6581    assert(SCIPvarIsTransformed(var));
6582    assert(set != NULL);
6583    assert(var->scip == set->scip);
6584    assert(SCIPsetIsLT(set, left, right));
6585 
6586    /* check, if the variable is being tracked for bound changes */
6587    if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_GHOLEADDED) != 0) )
6588    {
6589       SCIP_EVENT* event;
6590 
6591       SCIPsetDebugMsg(set, "issue GHOLEADDED event for variable <%s>: (%.15g,%.15g)\n", var->name, left, right);
6592 
6593       SCIP_CALL( SCIPeventCreateGholeAdded(&event, blkmem, var, left, right) );
6594       SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
6595    }
6596 
6597    return SCIP_OKAY;
6598 }
6599 
6600 /** increases root bound change statistics after a global bound change */
6601 static
varIncRootboundchgs(SCIP_VAR * var,SCIP_SET * set,SCIP_STAT * stat)6602 void varIncRootboundchgs(
6603    SCIP_VAR*             var,                /**< problem variable to change */
6604    SCIP_SET*             set,                /**< global SCIP settings */
6605    SCIP_STAT*            stat                /**< problem statistics */
6606    )
6607 {
6608    assert(var != NULL);
6609    assert(set != NULL);
6610    assert(var->scip == set->scip);
6611    assert(stat != NULL);
6612 
6613    if( SCIPvarIsActive(var) && SCIPvarIsTransformed(var) && set->stage == SCIP_STAGE_SOLVING )
6614    {
6615       stat->nrootboundchgs++;
6616       stat->nrootboundchgsrun++;
6617       if( SCIPvarIsIntegral(var) && SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
6618       {
6619          stat->nrootintfixings++;
6620          stat->nrootintfixingsrun++;
6621       }
6622    }
6623 }
6624 
6625 /* forward declaration, because both methods call each other recursively */
6626 
6627 /* performs the current change in upper bound, changes all parents accordingly */
6628 static
6629 SCIP_RETCODE varProcessChgUbGlobal(
6630    SCIP_VAR*             var,                /**< problem variable to change */
6631    BMS_BLKMEM*           blkmem,             /**< block memory */
6632    SCIP_SET*             set,                /**< global SCIP settings */
6633    SCIP_STAT*            stat,               /**< problem statistics */
6634    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
6635    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
6636    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
6637    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
6638    SCIP_Real             newbound            /**< new bound for variable */
6639    );
6640 
6641 /** performs the current change in lower bound, changes all parents accordingly */
6642 static
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)6643 SCIP_RETCODE varProcessChgLbGlobal(
6644    SCIP_VAR*             var,                /**< problem variable to change */
6645    BMS_BLKMEM*           blkmem,             /**< block memory */
6646    SCIP_SET*             set,                /**< global SCIP settings */
6647    SCIP_STAT*            stat,               /**< problem statistics */
6648    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
6649    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
6650    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
6651    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
6652    SCIP_Real             newbound            /**< new bound for variable */
6653    )
6654 {
6655    SCIP_VAR* parentvar;
6656    SCIP_Real oldbound;
6657    int i;
6658 
6659    assert(var != NULL);
6660    /* local domains can violate global bounds but not more than feasibility epsilon */
6661    assert(SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb));
6662    assert(SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub));
6663    assert(blkmem != NULL);
6664    assert(set != NULL);
6665    assert(var->scip == set->scip);
6666    assert(stat != NULL);
6667 
6668    /* adjust bound to integral value if variable is of integral type */
6669    newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
6670 
6671    /* check that the bound is feasible */
6672    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM && newbound > var->glbdom.ub )
6673    {
6674       /* due to numerics we only want to be feasible in feasibility tolerance */
6675       assert(SCIPsetIsFeasLE(set, newbound, var->glbdom.ub));
6676       newbound = var->glbdom.ub;
6677    }
6678    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
6679 
6680    assert(var->vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, newbound, 0.0) || SCIPsetIsEQ(set, newbound, 1.0));  /*lint !e641*/
6681 
6682    SCIPsetDebugMsg(set, "process changing global lower bound of <%s> from %f to %f\n", var->name, var->glbdom.lb, newbound);
6683 
6684    if( SCIPsetIsEQ(set, newbound, var->glbdom.lb) && !(newbound != var->glbdom.lb && newbound * var->glbdom.lb <= 0.0) )  /*lint !e777*/
6685       return SCIP_OKAY;
6686 
6687    /* check bound on debugging solution */
6688    SCIP_CALL( SCIPdebugCheckLbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
6689 
6690    /* change the bound */
6691    oldbound = var->glbdom.lb;
6692    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasLE(set, newbound, var->glbdom.ub));
6693    var->glbdom.lb = newbound;
6694    assert( SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb) );
6695    assert( SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub) );
6696 
6697    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
6698    {
6699       /* merges overlapping holes into single holes, moves bounds respectively */
6700       domMerge(&var->glbdom, blkmem, set, &newbound, NULL);
6701    }
6702 
6703    /* update the root bound changes counters */
6704    varIncRootboundchgs(var, set, stat);
6705 
6706    /* update the lbchginfos array by replacing worse local bounds with the new global bound and changing the
6707     * redundant bound changes to be branching decisions
6708     */
6709    for( i = 0; i < var->nlbchginfos; ++i )
6710    {
6711       assert(var->lbchginfos[i].var == var);
6712 
6713       if( var->lbchginfos[i].oldbound < var->glbdom.lb )
6714       {
6715          SCIPsetDebugMsg(set, " -> adjust lower bound change <%s>: %g -> %g due to new global lower bound %g\n",
6716             SCIPvarGetName(var), var->lbchginfos[i].oldbound, var->lbchginfos[i].newbound, var->glbdom.lb);
6717          var->lbchginfos[i].oldbound = var->glbdom.lb;
6718          if( SCIPsetIsLE(set, var->lbchginfos[i].newbound, var->glbdom.lb) )
6719          {
6720             /* this bound change is redundant due to the new global bound */
6721             var->lbchginfos[i].newbound = var->glbdom.lb;
6722             var->lbchginfos[i].boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
6723             var->lbchginfos[i].redundant = TRUE;
6724          }
6725          else
6726             break; /* from now on, the remaining local bound changes are not redundant */
6727       }
6728       else
6729          break; /* from now on, the remaining local bound changes are not redundant */
6730    }
6731 
6732    /* remove redundant implications and variable bounds */
6733    if( (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE)
6734       && (!set->reopt_enable || set->stage == SCIP_STAGE_PRESOLVING) )
6735    {
6736       SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, TRUE, TRUE) );
6737    }
6738 
6739    /* issue bound change event */
6740    assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
6741    if( var->eventfilter != NULL )
6742    {
6743       SCIP_CALL( varEventGlbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
6744    }
6745 
6746    /* process parent variables */
6747    for( i = 0; i < var->nparentvars; ++i )
6748    {
6749       parentvar = var->parentvars[i];
6750       assert(parentvar != NULL);
6751 
6752       switch( SCIPvarGetStatus(parentvar) )
6753       {
6754       case SCIP_VARSTATUS_ORIGINAL:
6755          SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
6756          break;
6757 
6758       case SCIP_VARSTATUS_COLUMN:
6759       case SCIP_VARSTATUS_LOOSE:
6760       case SCIP_VARSTATUS_FIXED:
6761       case SCIP_VARSTATUS_MULTAGGR:
6762          SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
6763          return SCIP_INVALIDDATA;
6764 
6765       case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
6766          assert(parentvar->data.aggregate.var == var);
6767          if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
6768          {
6769             SCIP_Real parentnewbound;
6770 
6771             /* a > 0 -> change lower bound of y */
6772             assert(SCIPsetIsInfinity(set, -parentvar->glbdom.lb) || SCIPsetIsInfinity(set, -oldbound)
6773                || SCIPsetIsFeasEQ(set, parentvar->glbdom.lb, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
6774                || (SCIPsetIsZero(set, parentvar->glbdom.lb / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
6775 
6776             if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6777                parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6778             else
6779                parentnewbound = newbound;
6780             SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
6781          }
6782          else
6783          {
6784             SCIP_Real parentnewbound;
6785 
6786             /* a < 0 -> change upper bound of y */
6787             assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
6788             assert(SCIPsetIsInfinity(set, parentvar->glbdom.ub) || SCIPsetIsInfinity(set, -oldbound)
6789                || SCIPsetIsFeasEQ(set, parentvar->glbdom.ub, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
6790                || (SCIPsetIsZero(set, parentvar->glbdom.ub / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
6791 
6792             if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6793                parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6794             else
6795                parentnewbound = -newbound;
6796             SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
6797          }
6798          break;
6799 
6800       case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
6801          assert(parentvar->negatedvar != NULL);
6802          assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
6803          assert(parentvar->negatedvar->negatedvar == parentvar);
6804          SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
6805                parentvar->data.negate.constant - newbound) );
6806          break;
6807 
6808       default:
6809          SCIPerrorMessage("unknown variable status\n");
6810          return SCIP_INVALIDDATA;
6811       }
6812    }
6813 
6814    return SCIP_OKAY;
6815 }
6816 
6817 /** performs the current change in upper bound, changes all parents accordingly */
6818 static
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)6819 SCIP_RETCODE varProcessChgUbGlobal(
6820    SCIP_VAR*             var,                /**< problem variable to change */
6821    BMS_BLKMEM*           blkmem,             /**< block memory */
6822    SCIP_SET*             set,                /**< global SCIP settings */
6823    SCIP_STAT*            stat,               /**< problem statistics */
6824    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
6825    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
6826    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
6827    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
6828    SCIP_Real             newbound            /**< new bound for variable */
6829    )
6830 {
6831    SCIP_VAR* parentvar;
6832    SCIP_Real oldbound;
6833    int i;
6834 
6835    assert(var != NULL);
6836    /* local domains can violate global bounds but not more than feasibility epsilon */
6837    assert(SCIPsetIsFeasLE(set, var->glbdom.lb , var->locdom.lb));
6838    assert(SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub));
6839    assert(blkmem != NULL);
6840    assert(set != NULL);
6841    assert(var->scip == set->scip);
6842    assert(stat != NULL);
6843 
6844    /* adjust bound to integral value if variable is of integral type */
6845    newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
6846 
6847    /* check that the bound is feasible */
6848    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM && newbound < var->glbdom.lb )
6849    {
6850       /* due to numerics we only want to be feasible in feasibility tolerance */
6851       assert(SCIPsetIsFeasGE(set, newbound, var->glbdom.lb));
6852       newbound = var->glbdom.lb;
6853    }
6854    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
6855 
6856    assert(var->vartype != SCIP_VARTYPE_BINARY || SCIPsetIsEQ(set, newbound, 0.0) || SCIPsetIsEQ(set, newbound, 1.0));  /*lint !e641*/
6857 
6858    SCIPsetDebugMsg(set, "process changing global upper bound of <%s> from %f to %f\n", var->name, var->glbdom.ub, newbound);
6859 
6860    if( SCIPsetIsEQ(set, newbound, var->glbdom.ub) && !(newbound != var->glbdom.ub && newbound * var->glbdom.ub <= 0.0) )  /*lint !e777*/
6861       return SCIP_OKAY;
6862 
6863    /* check bound on debugging solution */
6864    SCIP_CALL( SCIPdebugCheckUbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
6865 
6866    /* change the bound */
6867    oldbound = var->glbdom.ub;
6868    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasGE(set, newbound, var->glbdom.lb));
6869    var->glbdom.ub = newbound;
6870    assert( SCIPsetIsFeasLE(set, var->glbdom.lb, var->locdom.lb) );
6871    assert( SCIPsetIsFeasLE(set, var->locdom.ub, var->glbdom.ub) );
6872 
6873    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
6874    {
6875       /* merges overlapping holes into single holes, moves bounds respectively */
6876       domMerge(&var->glbdom, blkmem, set, NULL, &newbound);
6877    }
6878 
6879    /* update the root bound changes counters */
6880    varIncRootboundchgs(var, set, stat);
6881 
6882    /* update the ubchginfos array by replacing worse local bounds with the new global bound and changing the
6883     * redundant bound changes to be branching decisions
6884     */
6885    for( i = 0; i < var->nubchginfos; ++i )
6886    {
6887       assert(var->ubchginfos[i].var == var);
6888       if( var->ubchginfos[i].oldbound > var->glbdom.ub )
6889       {
6890          SCIPsetDebugMsg(set, " -> adjust upper bound change <%s>: %g -> %g due to new global upper bound %g\n",
6891             SCIPvarGetName(var), var->ubchginfos[i].oldbound, var->ubchginfos[i].newbound, var->glbdom.ub);
6892          var->ubchginfos[i].oldbound = var->glbdom.ub;
6893          if( SCIPsetIsGE(set, var->ubchginfos[i].newbound, var->glbdom.ub) )
6894          {
6895             /* this bound change is redundant due to the new global bound */
6896             var->ubchginfos[i].newbound = var->glbdom.ub;
6897             var->ubchginfos[i].boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
6898             var->ubchginfos[i].redundant = TRUE;
6899          }
6900          else
6901             break; /* from now on, the remaining local bound changes are not redundant */
6902       }
6903       else
6904          break; /* from now on, the remaining local bound changes are not redundant */
6905    }
6906 
6907    /* remove redundant implications and variable bounds */
6908    if( (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE)
6909       && (!set->reopt_enable || set->stage == SCIP_STAGE_PRESOLVING) )
6910    {
6911       SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, blkmem, cliquetable, set, FALSE, TRUE, TRUE) );
6912    }
6913 
6914    /* issue bound change event */
6915    assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
6916    if( var->eventfilter != NULL )
6917    {
6918       SCIP_CALL( varEventGubChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
6919    }
6920 
6921    /* process parent variables */
6922    for( i = 0; i < var->nparentvars; ++i )
6923    {
6924       parentvar = var->parentvars[i];
6925       assert(parentvar != NULL);
6926 
6927       switch( SCIPvarGetStatus(parentvar) )
6928       {
6929       case SCIP_VARSTATUS_ORIGINAL:
6930          SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
6931          break;
6932 
6933       case SCIP_VARSTATUS_COLUMN:
6934       case SCIP_VARSTATUS_LOOSE:
6935       case SCIP_VARSTATUS_FIXED:
6936       case SCIP_VARSTATUS_MULTAGGR:
6937          SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
6938          return SCIP_INVALIDDATA;
6939 
6940       case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
6941          assert(parentvar->data.aggregate.var == var);
6942          if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
6943          {
6944             SCIP_Real parentnewbound;
6945 
6946             /* a > 0 -> change upper bound of y */
6947             assert(SCIPsetIsInfinity(set, parentvar->glbdom.ub) || SCIPsetIsInfinity(set, oldbound)
6948                || SCIPsetIsFeasEQ(set, parentvar->glbdom.ub,
6949                   oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
6950             if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6951                parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6952             else
6953                parentnewbound = newbound;
6954             SCIP_CALL( varProcessChgUbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
6955          }
6956          else
6957          {
6958             SCIP_Real parentnewbound;
6959 
6960             /* a < 0 -> change lower bound of y */
6961             assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
6962             assert(SCIPsetIsInfinity(set, -parentvar->glbdom.lb) || SCIPsetIsInfinity(set, oldbound)
6963                || SCIPsetIsFeasEQ(set, parentvar->glbdom.lb,
6964                   oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
6965             if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
6966                parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
6967             else
6968                parentnewbound = -newbound;
6969             SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, parentnewbound) );
6970          }
6971          break;
6972 
6973       case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
6974          assert(parentvar->negatedvar != NULL);
6975          assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
6976          assert(parentvar->negatedvar->negatedvar == parentvar);
6977          SCIP_CALL( varProcessChgLbGlobal(parentvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
6978                parentvar->data.negate.constant - newbound) );
6979          break;
6980 
6981       default:
6982          SCIPerrorMessage("unknown variable status\n");
6983          return SCIP_INVALIDDATA;
6984       }
6985    }
6986 
6987    return SCIP_OKAY;
6988 }
6989 
6990 /** changes global lower bound of variable; if possible, adjusts bound to integral value;
6991  *  updates local lower bound if the global bound is tighter
6992  */
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)6993 SCIP_RETCODE SCIPvarChgLbGlobal(
6994    SCIP_VAR*             var,                /**< problem variable to change */
6995    BMS_BLKMEM*           blkmem,             /**< block memory */
6996    SCIP_SET*             set,                /**< global SCIP settings */
6997    SCIP_STAT*            stat,               /**< problem statistics */
6998    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
6999    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
7000    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
7001    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
7002    SCIP_Real             newbound            /**< new bound for variable */
7003    )
7004 {
7005    assert(var != NULL);
7006    assert(blkmem != NULL);
7007    assert(set != NULL);
7008    assert(var->scip == set->scip);
7009 
7010    /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7011     * of the domain within feastol
7012     */
7013    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->glbdom.ub));
7014 
7015    /* adjust bound to integral value if variable is of integral type */
7016    newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
7017 
7018    /* check that the adjusted bound is feasible
7019     * @todo this does not have to be the case if the original problem was infeasible due to bounds and we are called
7020     *       here because we reset bounds to their original value!
7021     */
7022    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->glbdom.ub));
7023 
7024    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7025    {
7026       /* we do not want to exceed the upperbound, which could have happened due to numerics */
7027       newbound = MIN(newbound, var->glbdom.ub);
7028    }
7029    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7030 
7031    /* the new global bound has to be tighter except we are in the original problem; this must be w.r.t. feastol because
7032     * SCIPvarFix() allows fixings that are outside of the domain within feastol
7033     */
7034    assert(lp == NULL || SCIPsetIsFeasLE(set, var->glbdom.lb, newbound) || (set->reopt_enable && set->stage == SCIP_STAGE_PRESOLVED));
7035 
7036    SCIPsetDebugMsg(set, "changing global lower bound of <%s> from %g to %g\n", var->name, var->glbdom.lb, newbound);
7037 
7038    if( SCIPsetIsEQ(set, var->glbdom.lb, newbound) && !(newbound != var->glbdom.lb && newbound * var->glbdom.lb <= 0.0) )  /*lint !e777*/
7039       return SCIP_OKAY;
7040 
7041    /* change bounds of attached variables */
7042    switch( SCIPvarGetStatus(var) )
7043    {
7044    case SCIP_VARSTATUS_ORIGINAL:
7045       if( var->data.original.transvar != NULL )
7046       {
7047          SCIP_CALL( SCIPvarChgLbGlobal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue,
7048                cliquetable, newbound) );
7049       }
7050       else
7051       {
7052          assert(set->stage == SCIP_STAGE_PROBLEM);
7053          if( newbound > SCIPvarGetLbLocal(var) )
7054          {
7055             SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7056          }
7057          SCIP_CALL( varProcessChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7058       }
7059       break;
7060 
7061    case SCIP_VARSTATUS_COLUMN:
7062    case SCIP_VARSTATUS_LOOSE:
7063       if( newbound > SCIPvarGetLbLocal(var) )
7064       {
7065          SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7066       }
7067       SCIP_CALL( varProcessChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7068       break;
7069 
7070    case SCIP_VARSTATUS_FIXED:
7071       SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7072       return SCIP_INVALIDDATA;
7073 
7074    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
7075       assert(var->data.aggregate.var != NULL);
7076       if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
7077       {
7078          SCIP_Real childnewbound;
7079 
7080          /* a > 0 -> change lower bound of y */
7081          assert((SCIPsetIsInfinity(set, -var->glbdom.lb) && SCIPsetIsInfinity(set, -var->data.aggregate.var->glbdom.lb))
7082             || SCIPsetIsFeasEQ(set, var->glbdom.lb,
7083                var->data.aggregate.var->glbdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant));
7084          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7085             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7086          else
7087             childnewbound = newbound;
7088          SCIP_CALL( SCIPvarChgLbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7089                childnewbound) );
7090       }
7091       else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7092       {
7093          SCIP_Real childnewbound;
7094 
7095          /* a < 0 -> change upper bound of y */
7096          assert((SCIPsetIsInfinity(set, -var->glbdom.lb) && SCIPsetIsInfinity(set, var->data.aggregate.var->glbdom.ub))
7097             || SCIPsetIsFeasEQ(set, var->glbdom.lb,
7098                var->data.aggregate.var->glbdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant));
7099          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7100             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7101          else
7102             childnewbound = -newbound;
7103          SCIP_CALL( SCIPvarChgUbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7104                childnewbound) );
7105       }
7106       else
7107       {
7108          SCIPerrorMessage("scalar is zero in aggregation\n");
7109          return SCIP_INVALIDDATA;
7110       }
7111       break;
7112 
7113    case SCIP_VARSTATUS_MULTAGGR:
7114       SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
7115       return SCIP_INVALIDDATA;
7116 
7117    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
7118       assert(var->negatedvar != NULL);
7119       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
7120       assert(var->negatedvar->negatedvar == var);
7121       SCIP_CALL( SCIPvarChgUbGlobal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7122             var->data.negate.constant - newbound) );
7123       break;
7124 
7125    default:
7126       SCIPerrorMessage("unknown variable status\n");
7127       return SCIP_INVALIDDATA;
7128    }
7129 
7130    return SCIP_OKAY;
7131 }
7132 
7133 /** changes global upper bound of variable; if possible, adjusts bound to integral value;
7134  *  updates local upper bound if the global bound is tighter
7135  */
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)7136 SCIP_RETCODE SCIPvarChgUbGlobal(
7137    SCIP_VAR*             var,                /**< problem variable to change */
7138    BMS_BLKMEM*           blkmem,             /**< block memory */
7139    SCIP_SET*             set,                /**< global SCIP settings */
7140    SCIP_STAT*            stat,               /**< problem statistics */
7141    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
7142    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
7143    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
7144    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
7145    SCIP_Real             newbound            /**< new bound for variable */
7146    )
7147 {
7148    assert(var != NULL);
7149    assert(blkmem != NULL);
7150    assert(set != NULL);
7151    assert(var->scip == set->scip);
7152 
7153    /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7154     * of the domain within feastol
7155     */
7156    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->glbdom.lb));
7157 
7158    /* adjust bound to integral value if variable is of integral type */
7159    newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
7160 
7161    /* check that the adjusted bound is feasible
7162     * @todo this does not have to be the case if the original problem was infeasible due to bounds and we are called
7163     *       here because we reset bounds to their original value!
7164     */
7165    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->glbdom.lb));
7166 
7167    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7168    {
7169       /* we do not want to undercut the lowerbound, which could have happened due to numerics */
7170       newbound = MAX(newbound, var->glbdom.lb);
7171    }
7172    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7173 
7174    /* the new global bound has to be tighter except we are in the original problem; this must be w.r.t. feastol because
7175     * SCIPvarFix() allows fixings that are outside of the domain within feastol
7176     */
7177    assert(lp == NULL || SCIPsetIsFeasGE(set, var->glbdom.ub, newbound) || (set->reopt_enable && set->stage == SCIP_STAGE_PRESOLVED));
7178 
7179    SCIPsetDebugMsg(set, "changing global upper bound of <%s> from %g to %g\n", var->name, var->glbdom.ub, newbound);
7180 
7181    if( SCIPsetIsEQ(set, var->glbdom.ub, newbound) && !(newbound != var->glbdom.ub && newbound * var->glbdom.ub <= 0.0) )  /*lint !e777*/
7182       return SCIP_OKAY;
7183 
7184    /* change bounds of attached variables */
7185    switch( SCIPvarGetStatus(var) )
7186    {
7187    case SCIP_VARSTATUS_ORIGINAL:
7188       if( var->data.original.transvar != NULL )
7189       {
7190          SCIP_CALL( SCIPvarChgUbGlobal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7191                newbound) );
7192       }
7193       else
7194       {
7195          assert(set->stage == SCIP_STAGE_PROBLEM);
7196          if( newbound < SCIPvarGetUbLocal(var) )
7197          {
7198             SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7199          }
7200          SCIP_CALL( varProcessChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7201       }
7202       break;
7203 
7204    case SCIP_VARSTATUS_COLUMN:
7205    case SCIP_VARSTATUS_LOOSE:
7206       if( newbound < SCIPvarGetUbLocal(var) )
7207       {
7208          SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7209       }
7210       SCIP_CALL( varProcessChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound) );
7211       break;
7212 
7213    case SCIP_VARSTATUS_FIXED:
7214       SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7215       return SCIP_INVALIDDATA;
7216 
7217    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
7218       assert(var->data.aggregate.var != NULL);
7219       if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
7220       {
7221          SCIP_Real childnewbound;
7222 
7223          /* a > 0 -> change lower bound of y */
7224          assert((SCIPsetIsInfinity(set, var->glbdom.ub) && SCIPsetIsInfinity(set, var->data.aggregate.var->glbdom.ub))
7225             || SCIPsetIsFeasEQ(set, var->glbdom.ub,
7226                var->data.aggregate.var->glbdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant));
7227          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7228             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7229          else
7230             childnewbound = newbound;
7231          SCIP_CALL( SCIPvarChgUbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7232                childnewbound) );
7233       }
7234       else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7235       {
7236          SCIP_Real childnewbound;
7237 
7238          /* a < 0 -> change upper bound of y */
7239          assert((SCIPsetIsInfinity(set, var->glbdom.ub) && SCIPsetIsInfinity(set, -var->data.aggregate.var->glbdom.lb))
7240             || SCIPsetIsFeasEQ(set, var->glbdom.ub,
7241                var->data.aggregate.var->glbdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant));
7242          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7243             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7244          else
7245             childnewbound = -newbound;
7246          SCIP_CALL( SCIPvarChgLbGlobal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7247                childnewbound) );
7248       }
7249       else
7250       {
7251          SCIPerrorMessage("scalar is zero in aggregation\n");
7252          return SCIP_INVALIDDATA;
7253       }
7254       break;
7255 
7256    case SCIP_VARSTATUS_MULTAGGR:
7257       SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
7258       return SCIP_INVALIDDATA;
7259 
7260    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
7261       assert(var->negatedvar != NULL);
7262       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
7263       assert(var->negatedvar->negatedvar == var);
7264       SCIP_CALL( SCIPvarChgLbGlobal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
7265             var->data.negate.constant - newbound) );
7266       break;
7267 
7268    default:
7269       SCIPerrorMessage("unknown variable status\n");
7270       return SCIP_INVALIDDATA;
7271    }
7272 
7273    return SCIP_OKAY;
7274 }
7275 
7276 /** changes lazy lower bound of the variable, this is only possible if the variable is not in the LP yet */
SCIPvarChgLbLazy(SCIP_VAR * var,SCIP_SET * set,SCIP_Real lazylb)7277 SCIP_RETCODE SCIPvarChgLbLazy(
7278    SCIP_VAR*             var,                /**< problem variable */
7279    SCIP_SET*             set,                /**< global SCIP settings */
7280    SCIP_Real             lazylb              /**< the lazy lower bound to be set */
7281    )
7282 {
7283    assert(var != NULL);
7284    assert(var->probindex != -1);
7285    assert(SCIPsetIsFeasGE(set, var->glbdom.ub, lazylb));
7286    assert(SCIPsetIsFeasGE(set, var->lazyub, lazylb));
7287    assert(set != NULL);
7288    assert(var->scip == set->scip);
7289 
7290    /* variable should not be in the LP */
7291    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
7292       return SCIP_INVALIDCALL;
7293 
7294    var->lazylb = lazylb;
7295 
7296    return SCIP_OKAY;
7297 }
7298 
7299 /** changes lazy upper bound of the variable, this is only possible if the variable is not in the LP yet */
SCIPvarChgUbLazy(SCIP_VAR * var,SCIP_SET * set,SCIP_Real lazyub)7300 SCIP_RETCODE SCIPvarChgUbLazy(
7301    SCIP_VAR*             var,                /**< problem variable */
7302    SCIP_SET*             set,                /**< global SCIP settings */
7303    SCIP_Real             lazyub              /**< the lazy lower bound to be set */
7304    )
7305 {
7306    assert(var != NULL);
7307    assert(var->probindex != -1);
7308    assert(SCIPsetIsFeasGE(set, lazyub, var->glbdom.lb));
7309    assert(SCIPsetIsFeasGE(set, lazyub, var->lazylb));
7310    assert(set != NULL);
7311    assert(var->scip == set->scip);
7312 
7313    /* variable should not be in the LP */
7314    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
7315       return SCIP_INVALIDCALL;
7316 
7317    var->lazyub = lazyub;
7318 
7319    return SCIP_OKAY;
7320 }
7321 
7322 
7323 /** changes global bound of variable; if possible, adjusts bound to integral value;
7324  *  updates local bound if the global bound is tighter
7325  */
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)7326 SCIP_RETCODE SCIPvarChgBdGlobal(
7327    SCIP_VAR*             var,                /**< problem variable to change */
7328    BMS_BLKMEM*           blkmem,             /**< block memory */
7329    SCIP_SET*             set,                /**< global SCIP settings */
7330    SCIP_STAT*            stat,               /**< problem statistics */
7331    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
7332    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
7333    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
7334    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
7335    SCIP_Real             newbound,           /**< new bound for variable */
7336    SCIP_BOUNDTYPE        boundtype           /**< type of bound: lower or upper bound */
7337    )
7338 {
7339    /* apply bound change to the LP data */
7340    switch( boundtype )
7341    {
7342    case SCIP_BOUNDTYPE_LOWER:
7343       return SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound);
7344    case SCIP_BOUNDTYPE_UPPER:
7345       return SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound);
7346    default:
7347       SCIPerrorMessage("unknown bound type\n");
7348       return SCIP_INVALIDDATA;
7349    }
7350 }
7351 
7352 /** appends LBTIGHTENED or LBRELAXED event to the event queue */
7353 static
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)7354 SCIP_RETCODE varEventLbChanged(
7355    SCIP_VAR*             var,                /**< problem variable to change */
7356    BMS_BLKMEM*           blkmem,             /**< block memory */
7357    SCIP_SET*             set,                /**< global SCIP settings */
7358    SCIP_LP*              lp,                 /**< current LP data */
7359    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
7360    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
7361    SCIP_Real             oldbound,           /**< old lower bound for variable */
7362    SCIP_Real             newbound            /**< new lower bound for variable */
7363    )
7364 {
7365    assert(var != NULL);
7366    assert(var->eventfilter != NULL);
7367    assert(SCIPvarIsTransformed(var));
7368    assert(!SCIPsetIsEQ(set, oldbound, newbound) || newbound == var->glbdom.lb || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
7369    assert(set != NULL);
7370    assert(var->scip == set->scip);
7371 
7372    /* check, if the variable is being tracked for bound changes
7373     * COLUMN and LOOSE variables are tracked always, because row activities and LP changes have to be updated
7374     */
7375    if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_LBCHANGED) != 0)
7376       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
7377       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
7378    {
7379       SCIP_EVENT* event;
7380 
7381       SCIPsetDebugMsg(set, "issue LBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
7382 
7383       SCIP_CALL( SCIPeventCreateLbChanged(&event, blkmem, var, oldbound, newbound) );
7384       SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
7385    }
7386 
7387    return SCIP_OKAY;
7388 }
7389 
7390 /** appends UBTIGHTENED or UBRELAXED event to the event queue */
7391 static
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)7392 SCIP_RETCODE varEventUbChanged(
7393    SCIP_VAR*             var,                /**< problem variable to change */
7394    BMS_BLKMEM*           blkmem,             /**< block memory */
7395    SCIP_SET*             set,                /**< global SCIP settings */
7396    SCIP_LP*              lp,                 /**< current LP data */
7397    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
7398    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
7399    SCIP_Real             oldbound,           /**< old upper bound for variable */
7400    SCIP_Real             newbound            /**< new upper bound for variable */
7401    )
7402 {
7403    assert(var != NULL);
7404    assert(var->eventfilter != NULL);
7405    assert(SCIPvarIsTransformed(var));
7406    assert(!SCIPsetIsEQ(set, oldbound, newbound) || newbound == var->glbdom.ub || (newbound != oldbound && newbound * oldbound <= 0.0)); /*lint !e777*/
7407    assert(set != NULL);
7408    assert(var->scip == set->scip);
7409 
7410    /* check, if the variable is being tracked for bound changes
7411     * COLUMN and LOOSE variables are tracked always, because row activities and LP changes have to be updated
7412     */
7413    if( (var->eventfilter->len > 0 && (var->eventfilter->eventmask & SCIP_EVENTTYPE_UBCHANGED) != 0)
7414       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
7415       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
7416    {
7417       SCIP_EVENT* event;
7418 
7419       SCIPsetDebugMsg(set, "issue UBCHANGED event for variable <%s>: %g -> %g\n", var->name, oldbound, newbound);
7420 
7421       SCIP_CALL( SCIPeventCreateUbChanged(&event, blkmem, var, oldbound, newbound) );
7422       SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, lp, branchcand, NULL, &event) );
7423    }
7424 
7425    return SCIP_OKAY;
7426 }
7427 
7428 /* forward declaration, because both methods call each other recursively */
7429 
7430 /* performs the current change in upper bound, changes all parents accordingly */
7431 static
7432 SCIP_RETCODE varProcessChgUbLocal(
7433    SCIP_VAR*             var,                /**< problem variable to change */
7434    BMS_BLKMEM*           blkmem,             /**< block memory */
7435    SCIP_SET*             set,                /**< global SCIP settings */
7436    SCIP_STAT*            stat,               /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7437    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
7438    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
7439    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
7440    SCIP_Real             newbound            /**< new bound for variable */
7441    );
7442 
7443 /** performs the current change in lower bound, changes all parents accordingly */
7444 static
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)7445 SCIP_RETCODE varProcessChgLbLocal(
7446    SCIP_VAR*             var,                /**< problem variable to change */
7447    BMS_BLKMEM*           blkmem,             /**< block memory */
7448    SCIP_SET*             set,                /**< global SCIP settings */
7449    SCIP_STAT*            stat,               /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7450    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
7451    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
7452    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
7453    SCIP_Real             newbound            /**< new bound for variable */
7454    )
7455 {
7456    SCIP_VAR* parentvar;
7457    SCIP_Real oldbound;
7458    int i;
7459 
7460    assert(var != NULL);
7461    assert(set != NULL);
7462    assert(var->scip == set->scip);
7463    assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && (SCIPsetIsZero(set, newbound) || SCIPsetIsEQ(set, newbound, 1.0)
7464             || SCIPsetIsEQ(set, newbound, var->locdom.ub)))
7465       || (SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS && (SCIPsetIsIntegral(set, newbound)
7466             || SCIPsetIsEQ(set, newbound, var->locdom.ub)))
7467       || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS);
7468 
7469    /* check that the bound is feasible */
7470    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsLE(set, newbound, var->glbdom.ub));
7471    /* adjust bound to integral value if variable is of integral type */
7472    newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
7473 
7474    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7475    {
7476       /* we do not want to exceed the upper bound, which could have happened due to numerics */
7477       newbound = MIN(newbound, var->locdom.ub);
7478 
7479       /* we do not want to undercut the global lower bound, which could have happened due to numerics */
7480       newbound = MAX(newbound, var->glbdom.lb);
7481    }
7482    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7483 
7484    SCIPsetDebugMsg(set, "process changing lower bound of <%s> from %g to %g\n", var->name, var->locdom.lb, newbound);
7485 
7486    if( SCIPsetIsEQ(set, newbound, var->glbdom.lb) && var->glbdom.lb != var->locdom.lb ) /*lint !e777*/
7487       newbound = var->glbdom.lb;
7488    else if( SCIPsetIsEQ(set, newbound, var->locdom.lb) && !(newbound != var->locdom.lb && newbound * var->locdom.lb <= 0.0) )  /*lint !e777*/
7489       return SCIP_OKAY;
7490 
7491    /* change the bound */
7492    oldbound = var->locdom.lb;
7493    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasLE(set, newbound, var->locdom.ub));
7494    var->locdom.lb = newbound;
7495 
7496    /* update statistic; during the update steps of the parent variable we pass a NULL pointer to ensure that we only
7497     * once update the statistic
7498     */
7499    if( stat != NULL )
7500       SCIPstatIncrement(stat, set, domchgcount);
7501 
7502    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7503    {
7504       /* merges overlapping holes into single holes, moves bounds respectively */
7505       domMerge(&var->locdom, blkmem, set, &newbound, NULL);
7506    }
7507 
7508    /* issue bound change event */
7509    assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
7510    if( var->eventfilter != NULL )
7511    {
7512       SCIP_CALL( varEventLbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
7513    }
7514 
7515    /* process parent variables */
7516    for( i = 0; i < var->nparentvars; ++i )
7517    {
7518       parentvar = var->parentvars[i];
7519       assert(parentvar != NULL);
7520 
7521       switch( SCIPvarGetStatus(parentvar) )
7522       {
7523       case SCIP_VARSTATUS_ORIGINAL:
7524          SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, newbound) );
7525          break;
7526 
7527       case SCIP_VARSTATUS_COLUMN:
7528       case SCIP_VARSTATUS_LOOSE:
7529       case SCIP_VARSTATUS_FIXED:
7530       case SCIP_VARSTATUS_MULTAGGR:
7531          SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
7532          return SCIP_INVALIDDATA;
7533 
7534       case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
7535          assert(parentvar->data.aggregate.var == var);
7536          if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
7537          {
7538             SCIP_Real parentnewbound;
7539 
7540             /* a > 0 -> change lower bound of y */
7541             assert(SCIPsetIsInfinity(set, -parentvar->locdom.lb) || SCIPsetIsInfinity(set, -oldbound)
7542                || SCIPsetIsFeasEQ(set, parentvar->locdom.lb, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
7543                || (SCIPsetIsZero(set, parentvar->locdom.lb / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
7544 
7545             if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7546             {
7547                parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7548                /* if parent's new lower bound exceeds its upper bound, then this could be due to numerical difficulties, e.g., if numbers are large
7549                 * thus, at least a relative comparision of the new lower bound and the current upper bound should proof consistency
7550                 * as a result, the parent's lower bound is set to it's upper bound, and not above
7551                 */
7552                if( parentnewbound > parentvar->glbdom.ub )
7553                {
7554                   /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7555                   assert(SCIPsetIsFeasLE(set, parentnewbound, parentvar->glbdom.ub));
7556                   parentnewbound = parentvar->glbdom.ub;
7557                }
7558             }
7559             else
7560                parentnewbound = newbound;
7561             SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7562          }
7563          else
7564          {
7565             SCIP_Real parentnewbound;
7566 
7567             /* a < 0 -> change upper bound of y */
7568             assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
7569             assert(SCIPsetIsInfinity(set, parentvar->locdom.ub) || SCIPsetIsInfinity(set, -oldbound)
7570                || SCIPsetIsFeasEQ(set, parentvar->locdom.ub, oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant)
7571                || (SCIPsetIsZero(set, parentvar->locdom.ub / parentvar->data.aggregate.scalar) && SCIPsetIsZero(set, oldbound)));
7572 
7573             if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7574             {
7575                parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7576                /* 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
7577                 * thus, at least a relative comparision of the new upper bound and the current lower bound should proof consistency
7578                 * as a result, the parent's upper bound is set to it's lower bound, and not below
7579                 */
7580                if( parentnewbound < parentvar->glbdom.lb )
7581                {
7582                   /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7583                   assert(SCIPsetIsFeasGE(set, parentnewbound, parentvar->glbdom.lb));
7584                   parentnewbound = parentvar->glbdom.lb;
7585                }
7586             }
7587             else
7588                parentnewbound = -newbound;
7589             SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7590          }
7591          break;
7592 
7593       case SCIP_VARSTATUS_NEGATED: /* x = offset - x'  ->  x' = offset - x */
7594          assert(parentvar->negatedvar != NULL);
7595          assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
7596          assert(parentvar->negatedvar->negatedvar == parentvar);
7597          SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue,
7598                parentvar->data.negate.constant - newbound) );
7599          break;
7600 
7601       default:
7602          SCIPerrorMessage("unknown variable status\n");
7603          return SCIP_INVALIDDATA;
7604       }
7605    }
7606 
7607    return SCIP_OKAY;
7608 }
7609 
7610 /** performs the current change in upper bound, changes all parents accordingly */
7611 static
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)7612 SCIP_RETCODE varProcessChgUbLocal(
7613    SCIP_VAR*             var,                /**< problem variable to change */
7614    BMS_BLKMEM*           blkmem,             /**< block memory */
7615    SCIP_SET*             set,                /**< global SCIP settings */
7616    SCIP_STAT*            stat,               /**< problem statistics, or NULL if the bound change belongs to updating the parent variables */
7617    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
7618    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
7619    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
7620    SCIP_Real             newbound            /**< new bound for variable */
7621    )
7622 {
7623    SCIP_VAR* parentvar;
7624    SCIP_Real oldbound;
7625    int i;
7626 
7627    assert(var != NULL);
7628    assert(set != NULL);
7629    assert(var->scip == set->scip);
7630    assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && (SCIPsetIsZero(set, newbound) || SCIPsetIsEQ(set, newbound, 1.0)
7631             || SCIPsetIsEQ(set, newbound, var->locdom.lb)))
7632       || (SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS && (SCIPsetIsIntegral(set, newbound)
7633             || SCIPsetIsEQ(set, newbound, var->locdom.lb)))
7634       || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS);
7635 
7636    /* check that the bound is feasible */
7637    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsGE(set, newbound, var->glbdom.lb));
7638    /* adjust bound to integral value if variable is of integral type */
7639    newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
7640 
7641    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7642    {
7643       /* we do not want to undercut the lower bound, which could have happened due to numerics */
7644       newbound = MAX(newbound, var->locdom.lb);
7645 
7646       /* we do not want to exceed the global upper bound, which could have happened due to numerics */
7647       newbound = MIN(newbound, var->glbdom.ub);
7648    }
7649    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7650 
7651    SCIPsetDebugMsg(set, "process changing upper bound of <%s> from %g to %g\n", var->name, var->locdom.ub, newbound);
7652 
7653    if( SCIPsetIsEQ(set, newbound, var->glbdom.ub) && var->glbdom.ub != var->locdom.ub  ) /*lint !e777*/
7654       newbound = var->glbdom.ub;
7655    else if( SCIPsetIsEQ(set, newbound, var->locdom.ub) && !(newbound != var->locdom.ub && newbound * var->locdom.ub <= 0.0) )  /*lint !e777*/
7656       return SCIP_OKAY;
7657 
7658    /* change the bound */
7659    oldbound = var->locdom.ub;
7660    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || SCIPsetIsFeasGE(set, newbound, var->locdom.lb));
7661    var->locdom.ub = newbound;
7662 
7663    /* update statistic; during the update steps of the parent variable we pass a NULL pointer to ensure that we only
7664     * once update the statistic
7665     */
7666    if( stat != NULL )
7667       SCIPstatIncrement(stat, set, domchgcount);
7668 
7669    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7670    {
7671       /* merges overlapping holes into single holes, moves bounds respectively */
7672       domMerge(&var->locdom, blkmem, set, NULL, &newbound);
7673    }
7674 
7675    /* issue bound change event */
7676    assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
7677    if( var->eventfilter != NULL )
7678    {
7679       SCIP_CALL( varEventUbChanged(var, blkmem, set, lp, branchcand, eventqueue, oldbound, newbound) );
7680    }
7681 
7682    /* process parent variables */
7683    for( i = 0; i < var->nparentvars; ++i )
7684    {
7685       parentvar = var->parentvars[i];
7686       assert(parentvar != NULL);
7687 
7688       switch( SCIPvarGetStatus(parentvar) )
7689       {
7690       case SCIP_VARSTATUS_ORIGINAL:
7691          SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, newbound) );
7692          break;
7693 
7694       case SCIP_VARSTATUS_COLUMN:
7695       case SCIP_VARSTATUS_LOOSE:
7696       case SCIP_VARSTATUS_FIXED:
7697       case SCIP_VARSTATUS_MULTAGGR:
7698          SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
7699          return SCIP_INVALIDDATA;
7700 
7701       case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
7702          assert(parentvar->data.aggregate.var == var);
7703          if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
7704          {
7705             SCIP_Real parentnewbound;
7706 
7707             /* a > 0 -> change upper bound of x */
7708             assert(SCIPsetIsInfinity(set, parentvar->locdom.ub) || SCIPsetIsInfinity(set, oldbound)
7709                || SCIPsetIsFeasEQ(set, parentvar->locdom.ub,
7710                   oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7711             if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7712             {
7713                parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7714                /* 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
7715                 * thus, at least a relative comparision of the new upper bound and the current lower bound should proof consistency
7716                 * as a result, the parent's upper bound is set to it's lower bound, and not below
7717                 */
7718                if( parentnewbound < parentvar->glbdom.lb )
7719                {
7720                   /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7721                   assert(SCIPsetIsFeasGE(set, parentnewbound, parentvar->glbdom.lb));
7722                   parentnewbound = parentvar->glbdom.lb;
7723                }
7724             }
7725             else
7726                parentnewbound = newbound;
7727             SCIP_CALL( varProcessChgUbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7728          }
7729          else
7730          {
7731             SCIP_Real parentnewbound;
7732 
7733             /* a < 0 -> change lower bound of x */
7734             assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
7735             assert(SCIPsetIsInfinity(set, -parentvar->locdom.lb) || SCIPsetIsInfinity(set, oldbound)
7736                || SCIPsetIsFeasEQ(set, parentvar->locdom.lb,
7737                   oldbound * parentvar->data.aggregate.scalar + parentvar->data.aggregate.constant));
7738             if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7739             {
7740                parentnewbound = parentvar->data.aggregate.scalar * newbound + parentvar->data.aggregate.constant;
7741                /* if parent's new lower bound exceeds its upper bound, then this could be due to numerical difficulties, e.g., if numbers are large
7742                 * thus, at least a relative comparision of the new lower bound and the current upper bound should proof consistency
7743                 * as a result, the parent's lower bound is set to it's upper bound, and not above
7744                 */
7745                if( parentnewbound > parentvar->glbdom.ub )
7746                {
7747                   /* due to numerics we only need to be feasible w.r.t. feasibility tolerance */
7748                   assert(SCIPsetIsFeasLE(set, parentnewbound, parentvar->glbdom.ub));
7749                   parentnewbound = parentvar->glbdom.ub;
7750                }
7751             }
7752             else
7753                parentnewbound = -newbound;
7754             SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue, parentnewbound) );
7755          }
7756          break;
7757 
7758       case SCIP_VARSTATUS_NEGATED: /* x = offset - x'  ->  x' = offset - x */
7759          assert(parentvar->negatedvar != NULL);
7760          assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
7761          assert(parentvar->negatedvar->negatedvar == parentvar);
7762          SCIP_CALL( varProcessChgLbLocal(parentvar, blkmem, set, NULL, lp, branchcand, eventqueue,
7763                parentvar->data.negate.constant - newbound) );
7764          break;
7765 
7766       default:
7767          SCIPerrorMessage("unknown variable status\n");
7768          return SCIP_INVALIDDATA;
7769       }
7770    }
7771 
7772    return SCIP_OKAY;
7773 }
7774 
7775 /** changes current local lower bound of variable; if possible, adjusts bound to integral value; stores inference
7776  *  information in variable
7777  */
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)7778 SCIP_RETCODE SCIPvarChgLbLocal(
7779    SCIP_VAR*             var,                /**< problem variable to change */
7780    BMS_BLKMEM*           blkmem,             /**< block memory */
7781    SCIP_SET*             set,                /**< global SCIP settings */
7782    SCIP_STAT*            stat,               /**< problem statistics */
7783    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
7784    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
7785    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
7786    SCIP_Real             newbound            /**< new bound for variable */
7787    )
7788 {
7789    assert(var != NULL);
7790    assert(blkmem != NULL);
7791    assert(set != NULL);
7792    assert(var->scip == set->scip);
7793 
7794    /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7795     * of the domain within feastol
7796     */
7797    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->locdom.ub));
7798 
7799    /* adjust bound to integral value if variable is of integral type */
7800    newbound = adjustedLb(set, SCIPvarGetType(var), newbound);
7801 
7802    /* check that the adjusted bound is feasible */
7803    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasGT(set, newbound, var->locdom.ub));
7804 
7805    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7806    {
7807       /* we do not want to exceed the upperbound, which could have happened due to numerics */
7808       newbound = MIN(newbound, var->locdom.ub);
7809    }
7810    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7811 
7812    SCIPsetDebugMsg(set, "changing lower bound of <%s>[%g,%g] to %g\n", var->name, var->locdom.lb, var->locdom.ub, newbound);
7813 
7814    if( SCIPsetIsEQ(set, var->locdom.lb, newbound) && (!SCIPsetIsEQ(set, var->glbdom.lb, newbound) || var->locdom.lb == newbound) /*lint !e777*/
7815          && !(newbound != var->locdom.lb && newbound * var->locdom.lb <= 0.0) ) /*lint !e777*/
7816       return SCIP_OKAY;
7817 
7818    /* change bounds of attached variables */
7819    switch( SCIPvarGetStatus(var) )
7820    {
7821    case SCIP_VARSTATUS_ORIGINAL:
7822       if( var->data.original.transvar != NULL )
7823       {
7824          SCIP_CALL( SCIPvarChgLbLocal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue,
7825                newbound) );
7826       }
7827       else
7828       {
7829          assert(set->stage == SCIP_STAGE_PROBLEM);
7830          SCIP_CALL( varProcessChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7831       }
7832       break;
7833 
7834    case SCIP_VARSTATUS_COLUMN:
7835    case SCIP_VARSTATUS_LOOSE:
7836       SCIP_CALL( varProcessChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7837       break;
7838 
7839    case SCIP_VARSTATUS_FIXED:
7840       SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7841       return SCIP_INVALIDDATA;
7842 
7843    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
7844       assert(var->data.aggregate.var != NULL);
7845       if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
7846       {
7847          SCIP_Real childnewbound;
7848 
7849          /* a > 0 -> change lower bound of y */
7850          assert((SCIPsetIsInfinity(set, -var->locdom.lb) && SCIPsetIsInfinity(set, -var->data.aggregate.var->locdom.lb))
7851             || SCIPsetIsFeasEQ(set, var->locdom.lb,
7852                var->data.aggregate.var->locdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant));
7853          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7854             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7855          else
7856             childnewbound = newbound;
7857          SCIP_CALL( SCIPvarChgLbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
7858                childnewbound) );
7859       }
7860       else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7861       {
7862          SCIP_Real childnewbound;
7863 
7864          /* a < 0 -> change upper bound of y */
7865          assert((SCIPsetIsInfinity(set, -var->locdom.lb) && SCIPsetIsInfinity(set, var->data.aggregate.var->locdom.ub))
7866             || SCIPsetIsFeasEQ(set, var->locdom.lb,
7867                var->data.aggregate.var->locdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant));
7868          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7869             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7870          else
7871             childnewbound = -newbound;
7872          SCIP_CALL( SCIPvarChgUbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
7873                childnewbound) );
7874       }
7875       else
7876       {
7877          SCIPerrorMessage("scalar is zero in aggregation\n");
7878          return SCIP_INVALIDDATA;
7879       }
7880       break;
7881 
7882    case SCIP_VARSTATUS_MULTAGGR:
7883       SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
7884       return SCIP_INVALIDDATA;
7885 
7886    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
7887       assert(var->negatedvar != NULL);
7888       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
7889       assert(var->negatedvar->negatedvar == var);
7890       SCIP_CALL( SCIPvarChgUbLocal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue,
7891             var->data.negate.constant - newbound) );
7892       break;
7893 
7894    default:
7895       SCIPerrorMessage("unknown variable status\n");
7896       return SCIP_INVALIDDATA;
7897    }
7898 
7899    return SCIP_OKAY;
7900 }
7901 
7902 /** changes current local upper bound of variable; if possible, adjusts bound to integral value; stores inference
7903  *  information in variable
7904  */
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)7905 SCIP_RETCODE SCIPvarChgUbLocal(
7906    SCIP_VAR*             var,                /**< problem variable to change */
7907    BMS_BLKMEM*           blkmem,             /**< block memory */
7908    SCIP_SET*             set,                /**< global SCIP settings */
7909    SCIP_STAT*            stat,               /**< problem statistics */
7910    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
7911    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
7912    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
7913    SCIP_Real             newbound            /**< new bound for variable */
7914    )
7915 {
7916    assert(var != NULL);
7917    assert(blkmem != NULL);
7918    assert(set != NULL);
7919    assert(var->scip == set->scip);
7920 
7921    /* check that the bound is feasible; this must be w.r.t. feastol because SCIPvarFix() allows fixings that are outside
7922     * of the domain within feastol
7923     */
7924    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->locdom.lb));
7925 
7926    /* adjust bound to integral value if variable is of integral type */
7927    newbound = adjustedUb(set, SCIPvarGetType(var), newbound);
7928 
7929    /* check that the adjusted bound is feasible */
7930    assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM || !SCIPsetIsFeasLT(set, newbound, var->locdom.lb));
7931 
7932    if( SCIPsetGetStage(set) != SCIP_STAGE_PROBLEM )
7933    {
7934       /* we do not want to undercut the lowerbound, which could have happened due to numerics */
7935       newbound = MAX(newbound, var->locdom.lb);
7936    }
7937    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, newbound));
7938 
7939    SCIPsetDebugMsg(set, "changing upper bound of <%s>[%g,%g] to %g\n", var->name, var->locdom.lb, var->locdom.ub, newbound);
7940 
7941    if( SCIPsetIsEQ(set, var->locdom.ub, newbound) && (!SCIPsetIsEQ(set, var->glbdom.ub, newbound) || var->locdom.ub == newbound) /*lint !e777*/
7942       && !(newbound != var->locdom.ub && newbound * var->locdom.ub <= 0.0) ) /*lint !e777*/
7943       return SCIP_OKAY;
7944 
7945    /* change bounds of attached variables */
7946    switch( SCIPvarGetStatus(var) )
7947    {
7948    case SCIP_VARSTATUS_ORIGINAL:
7949       if( var->data.original.transvar != NULL )
7950       {
7951          SCIP_CALL( SCIPvarChgUbLocal(var->data.original.transvar, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7952       }
7953       else
7954       {
7955          assert(set->stage == SCIP_STAGE_PROBLEM);
7956          SCIP_CALL( varProcessChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7957       }
7958       break;
7959 
7960    case SCIP_VARSTATUS_COLUMN:
7961    case SCIP_VARSTATUS_LOOSE:
7962       SCIP_CALL( varProcessChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound) );
7963       break;
7964 
7965    case SCIP_VARSTATUS_FIXED:
7966       SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
7967       return SCIP_INVALIDDATA;
7968 
7969    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
7970       assert(var->data.aggregate.var != NULL);
7971       if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
7972       {
7973          SCIP_Real childnewbound;
7974 
7975          /* a > 0 -> change upper bound of y */
7976          assert((SCIPsetIsInfinity(set, var->locdom.ub) && SCIPsetIsInfinity(set, var->data.aggregate.var->locdom.ub))
7977             || SCIPsetIsFeasEQ(set, var->locdom.ub,
7978                var->data.aggregate.var->locdom.ub * var->data.aggregate.scalar + var->data.aggregate.constant));
7979          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7980             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7981          else
7982             childnewbound = newbound;
7983          SCIP_CALL( SCIPvarChgUbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
7984                childnewbound) );
7985       }
7986       else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
7987       {
7988          SCIP_Real childnewbound;
7989 
7990          /* a < 0 -> change lower bound of y */
7991          assert((SCIPsetIsInfinity(set, var->locdom.ub) && SCIPsetIsInfinity(set, -var->data.aggregate.var->locdom.lb))
7992             || SCIPsetIsFeasEQ(set, var->locdom.ub,
7993                var->data.aggregate.var->locdom.lb * var->data.aggregate.scalar + var->data.aggregate.constant));
7994          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
7995             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
7996          else
7997             childnewbound = -newbound;
7998          SCIP_CALL( SCIPvarChgLbLocal(var->data.aggregate.var, blkmem, set, stat, lp, branchcand, eventqueue,
7999                childnewbound) );
8000       }
8001       else
8002       {
8003          SCIPerrorMessage("scalar is zero in aggregation\n");
8004          return SCIP_INVALIDDATA;
8005       }
8006       break;
8007 
8008    case SCIP_VARSTATUS_MULTAGGR:
8009       SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
8010       return SCIP_INVALIDDATA;
8011 
8012    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
8013       assert(var->negatedvar != NULL);
8014       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
8015       assert(var->negatedvar->negatedvar == var);
8016       SCIP_CALL( SCIPvarChgLbLocal(var->negatedvar, blkmem, set, stat, lp, branchcand, eventqueue,
8017             var->data.negate.constant - newbound) );
8018       break;
8019 
8020    default:
8021       SCIPerrorMessage("unknown variable status\n");
8022       return SCIP_INVALIDDATA;
8023    }
8024 
8025    return SCIP_OKAY;
8026 }
8027 
8028 /** changes current local bound of variable; if possible, adjusts bound to integral value; stores inference
8029  *  information in variable
8030  */
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)8031 SCIP_RETCODE SCIPvarChgBdLocal(
8032    SCIP_VAR*             var,                /**< problem variable to change */
8033    BMS_BLKMEM*           blkmem,             /**< block memory */
8034    SCIP_SET*             set,                /**< global SCIP settings */
8035    SCIP_STAT*            stat,               /**< problem statistics */
8036    SCIP_LP*              lp,                 /**< current LP data, may be NULL for original variables */
8037    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage, may be NULL for original variables */
8038    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
8039    SCIP_Real             newbound,           /**< new bound for variable */
8040    SCIP_BOUNDTYPE        boundtype           /**< type of bound: lower or upper bound */
8041    )
8042 {
8043    /* apply bound change to the LP data */
8044    switch( boundtype )
8045    {
8046    case SCIP_BOUNDTYPE_LOWER:
8047       return SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound);
8048    case SCIP_BOUNDTYPE_UPPER:
8049       return SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, newbound);
8050    default:
8051       SCIPerrorMessage("unknown bound type\n");
8052       return SCIP_INVALIDDATA;
8053    }
8054 }
8055 
8056 /** changes lower bound of variable in current dive; if possible, adjusts bound to integral value */
SCIPvarChgLbDive(SCIP_VAR * var,SCIP_SET * set,SCIP_LP * lp,SCIP_Real newbound)8057 SCIP_RETCODE SCIPvarChgLbDive(
8058    SCIP_VAR*             var,                /**< problem variable to change */
8059    SCIP_SET*             set,                /**< global SCIP settings */
8060    SCIP_LP*              lp,                 /**< current LP data */
8061    SCIP_Real             newbound            /**< new bound for variable */
8062    )
8063 {
8064    assert(var != NULL);
8065    assert(set != NULL);
8066    assert(var->scip == set->scip);
8067    assert(lp != NULL);
8068    assert(SCIPlpDiving(lp));
8069 
8070    /* adjust bound for integral variables */
8071    SCIPvarAdjustLb(var, set, &newbound);
8072 
8073    SCIPsetDebugMsg(set, "changing lower bound of <%s> to %g in current dive\n", var->name, newbound);
8074 
8075    /* change bounds of attached variables */
8076    switch( SCIPvarGetStatus(var) )
8077    {
8078    case SCIP_VARSTATUS_ORIGINAL:
8079       assert(var->data.original.transvar != NULL);
8080       SCIP_CALL( SCIPvarChgLbDive(var->data.original.transvar, set, lp, newbound) );
8081       break;
8082 
8083    case SCIP_VARSTATUS_COLUMN:
8084       assert(var->data.col != NULL);
8085       SCIP_CALL( SCIPcolChgLb(var->data.col, set, lp, newbound) );
8086       break;
8087 
8088    case SCIP_VARSTATUS_LOOSE:
8089       SCIPerrorMessage("cannot change variable's bounds in dive for LOOSE variables\n");
8090       return SCIP_INVALIDDATA;
8091 
8092    case SCIP_VARSTATUS_FIXED:
8093       SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
8094       return SCIP_INVALIDDATA;
8095 
8096    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
8097       assert(var->data.aggregate.var != NULL);
8098       if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
8099       {
8100          SCIP_Real childnewbound;
8101 
8102          /* a > 0 -> change lower bound of y */
8103          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8104             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8105          else
8106             childnewbound = newbound;
8107          SCIP_CALL( SCIPvarChgLbDive(var->data.aggregate.var, set, lp, childnewbound) );
8108       }
8109       else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8110       {
8111          SCIP_Real childnewbound;
8112 
8113          /* a < 0 -> change upper bound of y */
8114          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8115             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8116          else
8117             childnewbound = -newbound;
8118          SCIP_CALL( SCIPvarChgUbDive(var->data.aggregate.var, set, lp, childnewbound) );
8119       }
8120       else
8121       {
8122          SCIPerrorMessage("scalar is zero in aggregation\n");
8123          return SCIP_INVALIDDATA;
8124       }
8125       break;
8126 
8127    case SCIP_VARSTATUS_MULTAGGR:
8128       SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
8129       return SCIP_INVALIDDATA;
8130 
8131    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
8132       assert(var->negatedvar != NULL);
8133       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
8134       assert(var->negatedvar->negatedvar == var);
8135       SCIP_CALL( SCIPvarChgUbDive(var->negatedvar, set, lp, var->data.negate.constant - newbound) );
8136       break;
8137 
8138    default:
8139       SCIPerrorMessage("unknown variable status\n");
8140       return SCIP_INVALIDDATA;
8141    }
8142 
8143    return SCIP_OKAY;
8144 }
8145 
8146 /** changes upper bound of variable in current dive; if possible, adjusts bound to integral value */
SCIPvarChgUbDive(SCIP_VAR * var,SCIP_SET * set,SCIP_LP * lp,SCIP_Real newbound)8147 SCIP_RETCODE SCIPvarChgUbDive(
8148    SCIP_VAR*             var,                /**< problem variable to change */
8149    SCIP_SET*             set,                /**< global SCIP settings */
8150    SCIP_LP*              lp,                 /**< current LP data */
8151    SCIP_Real             newbound            /**< new bound for variable */
8152    )
8153 {
8154    assert(var != NULL);
8155    assert(set != NULL);
8156    assert(var->scip == set->scip);
8157    assert(lp != NULL);
8158    assert(SCIPlpDiving(lp));
8159 
8160    /* adjust bound for integral variables */
8161    SCIPvarAdjustUb(var, set, &newbound);
8162 
8163    SCIPsetDebugMsg(set, "changing upper bound of <%s> to %g in current dive\n", var->name, newbound);
8164 
8165    /* change bounds of attached variables */
8166    switch( SCIPvarGetStatus(var) )
8167    {
8168    case SCIP_VARSTATUS_ORIGINAL:
8169       assert(var->data.original.transvar != NULL);
8170       SCIP_CALL( SCIPvarChgUbDive(var->data.original.transvar, set, lp, newbound) );
8171       break;
8172 
8173    case SCIP_VARSTATUS_COLUMN:
8174       assert(var->data.col != NULL);
8175       SCIP_CALL( SCIPcolChgUb(var->data.col, set, lp, newbound) );
8176       break;
8177 
8178    case SCIP_VARSTATUS_LOOSE:
8179       SCIPerrorMessage("cannot change variable's bounds in dive for LOOSE variables\n");
8180       return SCIP_INVALIDDATA;
8181 
8182    case SCIP_VARSTATUS_FIXED:
8183       SCIPerrorMessage("cannot change the bounds of a fixed variable\n");
8184       return SCIP_INVALIDDATA;
8185 
8186    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
8187       assert(var->data.aggregate.var != NULL);
8188       if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
8189       {
8190          SCIP_Real childnewbound;
8191 
8192          /* a > 0 -> change upper bound of y */
8193          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8194             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8195          else
8196             childnewbound = newbound;
8197          SCIP_CALL( SCIPvarChgUbDive(var->data.aggregate.var, set, lp, childnewbound) );
8198       }
8199       else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8200       {
8201          SCIP_Real childnewbound;
8202 
8203          /* a < 0 -> change lower bound of y */
8204          if( !SCIPsetIsInfinity(set, -newbound) && !SCIPsetIsInfinity(set, newbound) )
8205             childnewbound = (newbound - var->data.aggregate.constant)/var->data.aggregate.scalar;
8206          else
8207             childnewbound = -newbound;
8208          SCIP_CALL( SCIPvarChgLbDive(var->data.aggregate.var, set, lp, childnewbound) );
8209       }
8210       else
8211       {
8212          SCIPerrorMessage("scalar is zero in aggregation\n");
8213          return SCIP_INVALIDDATA;
8214       }
8215       break;
8216 
8217    case SCIP_VARSTATUS_MULTAGGR:
8218       SCIPerrorMessage("cannot change the bounds of a multi-aggregated variable.\n");
8219       return SCIP_INVALIDDATA;
8220 
8221    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
8222       assert(var->negatedvar != NULL);
8223       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
8224       assert(var->negatedvar->negatedvar == var);
8225       SCIP_CALL( SCIPvarChgLbDive(var->negatedvar, set, lp, var->data.negate.constant - newbound) );
8226       break;
8227 
8228    default:
8229       SCIPerrorMessage("unknown variable status\n");
8230       return SCIP_INVALIDDATA;
8231    }
8232 
8233    return SCIP_OKAY;
8234 }
8235 
8236 /** for a multi-aggregated variable, gives the local lower bound computed by adding the local bounds from all
8237  *  aggregation variables, this lower bound may be tighter than the one given by SCIPvarGetLbLocal, since the latter is
8238  *  not updated if bounds of aggregation variables are changing
8239  *
8240  *  calling this function for a non-multi-aggregated variable is not allowed
8241  */
SCIPvarGetMultaggrLbLocal(SCIP_VAR * var,SCIP_SET * set)8242 SCIP_Real SCIPvarGetMultaggrLbLocal(
8243    SCIP_VAR*             var,                /**< problem variable */
8244    SCIP_SET*             set                 /**< global SCIP settings */
8245    )
8246 {
8247    int i;
8248    SCIP_Real lb;
8249    SCIP_Real bnd;
8250    SCIP_VAR* aggrvar;
8251    SCIP_Bool posinf;
8252    SCIP_Bool neginf;
8253 
8254    assert(var != NULL);
8255    assert(set != NULL);
8256    assert(var->scip == set->scip);
8257    assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR);
8258 
8259    posinf = FALSE;
8260    neginf = FALSE;
8261    lb = var->data.multaggr.constant;
8262    for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8263    {
8264       aggrvar = var->data.multaggr.vars[i];
8265       if( var->data.multaggr.scalars[i] > 0.0 )
8266       {
8267          bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbLocal(aggrvar, set) : SCIPvarGetLbLocal(aggrvar);
8268 
8269          if( SCIPsetIsInfinity(set, bnd) )
8270             posinf = TRUE;
8271          else if( SCIPsetIsInfinity(set, -bnd) )
8272             neginf = TRUE;
8273          else
8274             lb += var->data.multaggr.scalars[i] * bnd;
8275       }
8276       else
8277       {
8278          bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbLocal(aggrvar, set) : SCIPvarGetUbLocal(aggrvar);
8279 
8280          if( SCIPsetIsInfinity(set, -bnd) )
8281             posinf = TRUE;
8282          else if( SCIPsetIsInfinity(set, bnd) )
8283             neginf = TRUE;
8284          else
8285             lb += var->data.multaggr.scalars[i] * bnd;
8286       }
8287 
8288       /* stop if two diffrent infinities (or a -infinity) were found and return local lower bound of multi aggregated
8289        * variable
8290        */
8291       if( neginf )
8292          return SCIPvarGetLbLocal(var);
8293    }
8294 
8295    /* if positive infinity flag was set to true return infinity */
8296    if( posinf )
8297       return SCIPsetInfinity(set);
8298 
8299    return (MAX(lb, SCIPvarGetLbLocal(var))); /*lint !e666*/
8300 }
8301 
8302 /** for a multi-aggregated variable, gives the local upper bound computed by adding the local bounds from all
8303  *  aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbLocal, since the latter is
8304  *  not updated if bounds of aggregation variables are changing
8305  *
8306  *  calling this function for a non-multi-aggregated variable is not allowed
8307  */
SCIPvarGetMultaggrUbLocal(SCIP_VAR * var,SCIP_SET * set)8308 SCIP_Real SCIPvarGetMultaggrUbLocal(
8309    SCIP_VAR*             var,                /**< problem variable */
8310    SCIP_SET*             set                 /**< global SCIP settings */
8311    )
8312 {
8313    int i;
8314    SCIP_Real ub;
8315    SCIP_Real bnd;
8316    SCIP_VAR* aggrvar;
8317    SCIP_Bool posinf;
8318    SCIP_Bool neginf;
8319 
8320    assert(var != NULL);
8321    assert(set != NULL);
8322    assert(var->scip == set->scip);
8323    assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR);
8324 
8325    posinf = FALSE;
8326    neginf = FALSE;
8327    ub = var->data.multaggr.constant;
8328    for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8329    {
8330       aggrvar = var->data.multaggr.vars[i];
8331       if( var->data.multaggr.scalars[i] > 0.0 )
8332       {
8333          bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbLocal(aggrvar, set) : SCIPvarGetUbLocal(aggrvar);
8334 
8335          if( SCIPsetIsInfinity(set, bnd) )
8336             posinf = TRUE;
8337          else if( SCIPsetIsInfinity(set, -bnd) )
8338             neginf = TRUE;
8339          else
8340             ub += var->data.multaggr.scalars[i] * bnd;
8341       }
8342       else
8343       {
8344          bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbLocal(aggrvar, set) : SCIPvarGetLbLocal(aggrvar);
8345 
8346          if( SCIPsetIsInfinity(set, -bnd) )
8347             posinf = TRUE;
8348          else if( SCIPsetIsInfinity(set, bnd) )
8349             neginf = TRUE;
8350          else
8351             ub += var->data.multaggr.scalars[i] * bnd;
8352       }
8353 
8354       /* stop if two diffrent infinities (or a -infinity) were found and return local upper bound of multi aggregated
8355        * variable
8356        */
8357       if( posinf )
8358          return SCIPvarGetUbLocal(var);
8359    }
8360 
8361    /* if negative infinity flag was set to true return -infinity */
8362    if( neginf )
8363       return -SCIPsetInfinity(set);
8364 
8365    return (MIN(ub, SCIPvarGetUbLocal(var))); /*lint !e666*/
8366 }
8367 
8368 /** for a multi-aggregated variable, gives the global lower bound computed by adding the global bounds from all
8369  *  aggregation variables, this global bound may be tighter than the one given by SCIPvarGetLbGlobal, since the latter is
8370  *  not updated if bounds of aggregation variables are changing
8371  *
8372  *  calling this function for a non-multi-aggregated variable is not allowed
8373  */
SCIPvarGetMultaggrLbGlobal(SCIP_VAR * var,SCIP_SET * set)8374 SCIP_Real SCIPvarGetMultaggrLbGlobal(
8375    SCIP_VAR*             var,                /**< problem variable */
8376    SCIP_SET*             set                 /**< global SCIP settings */
8377    )
8378 {
8379    int i;
8380    SCIP_Real lb;
8381    SCIP_Real bnd;
8382    SCIP_VAR* aggrvar;
8383    SCIP_Bool posinf;
8384    SCIP_Bool neginf;
8385 
8386    assert(var != NULL);
8387    assert(set != NULL);
8388    assert(var->scip == set->scip);
8389    assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR);
8390 
8391    posinf = FALSE;
8392    neginf = FALSE;
8393    lb = var->data.multaggr.constant;
8394    for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8395    {
8396       aggrvar = var->data.multaggr.vars[i];
8397       if( var->data.multaggr.scalars[i] > 0.0 )
8398       {
8399          bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbGlobal(aggrvar, set) : SCIPvarGetLbGlobal(aggrvar);
8400 
8401          if( SCIPsetIsInfinity(set, bnd) )
8402             posinf = TRUE;
8403          else if( SCIPsetIsInfinity(set, -bnd) )
8404             neginf = TRUE;
8405          else
8406             lb += var->data.multaggr.scalars[i] * bnd;
8407       }
8408       else
8409       {
8410          bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbGlobal(aggrvar, set) : SCIPvarGetUbGlobal(aggrvar);
8411 
8412          if( SCIPsetIsInfinity(set, -bnd) )
8413             posinf = TRUE;
8414          else if( SCIPsetIsInfinity(set, bnd) )
8415             neginf = TRUE;
8416          else
8417             lb += var->data.multaggr.scalars[i] * bnd;
8418       }
8419 
8420       /* stop if two diffrent infinities (or a -infinity) were found and return global lower bound of multi aggregated
8421        * variable
8422        */
8423       if( neginf )
8424          return SCIPvarGetLbGlobal(var);
8425    }
8426 
8427    /* if positive infinity flag was set to true return infinity */
8428    if( posinf )
8429       return SCIPsetInfinity(set);
8430 
8431    return (MAX(lb, SCIPvarGetLbGlobal(var))); /*lint !e666*/
8432 }
8433 
8434 /** for a multi-aggregated variable, gives the global upper bound computed by adding the global bounds from all
8435  *  aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbGlobal, since the latter is
8436  *  not updated if bounds of aggregation variables are changing
8437  *
8438  *  calling this function for a non-multi-aggregated variable is not allowed
8439  */
SCIPvarGetMultaggrUbGlobal(SCIP_VAR * var,SCIP_SET * set)8440 SCIP_Real SCIPvarGetMultaggrUbGlobal(
8441    SCIP_VAR*             var,                /**< problem variable */
8442    SCIP_SET*             set                 /**< global SCIP settings */
8443    )
8444 {
8445    int i;
8446    SCIP_Real ub;
8447    SCIP_Real bnd;
8448    SCIP_VAR* aggrvar;
8449    SCIP_Bool posinf;
8450    SCIP_Bool neginf;
8451 
8452    assert(var != NULL);
8453    assert(set != NULL);
8454    assert(var->scip == set->scip);
8455    assert((SCIP_VARSTATUS) var->varstatus == SCIP_VARSTATUS_MULTAGGR);
8456 
8457    posinf = FALSE;
8458    neginf = FALSE;
8459    ub = var->data.multaggr.constant;
8460    for( i = var->data.multaggr.nvars-1 ; i >= 0 ; --i )
8461    {
8462       aggrvar = var->data.multaggr.vars[i];
8463       if( var->data.multaggr.scalars[i] > 0.0 )
8464       {
8465          bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrUbGlobal(aggrvar, set) : SCIPvarGetUbGlobal(aggrvar);
8466 
8467          if( SCIPsetIsInfinity(set, bnd) )
8468             posinf = TRUE;
8469          else if( SCIPsetIsInfinity(set, -bnd) )
8470             neginf = TRUE;
8471          else
8472             ub += var->data.multaggr.scalars[i] * bnd;
8473       }
8474       else
8475       {
8476          bnd = SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_MULTAGGR ? SCIPvarGetMultaggrLbGlobal(aggrvar, set) : SCIPvarGetLbGlobal(aggrvar);
8477 
8478          if( SCIPsetIsInfinity(set, -bnd) )
8479             posinf = TRUE;
8480          else if( SCIPsetIsInfinity(set, bnd) )
8481             neginf = TRUE;
8482          else
8483             ub += var->data.multaggr.scalars[i] * bnd;
8484       }
8485 
8486       /* stop if two diffrent infinities (or a -infinity) were found and return local upper bound of multi aggregated
8487        * variable
8488        */
8489       if( posinf )
8490          return SCIPvarGetUbGlobal(var);
8491    }
8492 
8493    /* if negative infinity flag was set to true return -infinity */
8494    if( neginf )
8495       return -SCIPsetInfinity(set);
8496 
8497    return (MIN(ub, SCIPvarGetUbGlobal(var))); /*lint !e666*/
8498 }
8499 
8500 /** adds a hole to the original domain of the variable */
SCIPvarAddHoleOriginal(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_Real left,SCIP_Real right)8501 SCIP_RETCODE SCIPvarAddHoleOriginal(
8502    SCIP_VAR*             var,                /**< problem variable */
8503    BMS_BLKMEM*           blkmem,             /**< block memory */
8504    SCIP_SET*             set,                /**< global SCIP settings */
8505    SCIP_Real             left,               /**< left bound of open interval in new hole */
8506    SCIP_Real             right               /**< right bound of open interval in new hole */
8507    )
8508 {
8509    SCIP_Bool added;
8510 
8511    assert(var != NULL);
8512    assert(!SCIPvarIsTransformed(var));
8513    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
8514    assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
8515    assert(set != NULL);
8516    assert(var->scip == set->scip);
8517    assert(set->stage == SCIP_STAGE_PROBLEM);
8518 
8519    SCIPsetDebugMsg(set, "adding original hole (%g,%g) to <%s>\n", left, right, var->name);
8520 
8521    if( SCIPsetIsEQ(set, left, right) )
8522       return SCIP_OKAY;
8523 
8524    /* the interval should not be empty */
8525    assert(SCIPsetIsLT(set, left, right));
8526 
8527    /* the the interval bound should already be adjusted */
8528    assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8529    assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8530 
8531    /* the the interval should lay between the lower and upper bound */
8532    assert(SCIPsetIsGE(set, left, SCIPvarGetLbOriginal(var)));
8533    assert(SCIPsetIsLE(set, right, SCIPvarGetUbOriginal(var)));
8534 
8535    /* add domain hole */
8536    SCIP_CALL( domAddHole(&var->data.original.origdom, blkmem, set, left, right, &added) );
8537 
8538    /* merges overlapping holes into single holes, moves bounds respectively if hole was added */
8539    if( added )
8540    {
8541       domMerge(&var->data.original.origdom, blkmem, set, NULL, NULL);
8542    }
8543 
8544    /**@todo add hole in parent and child variables (just like with bound changes);
8545     *       warning! original vars' holes are in original blkmem, transformed vars' holes in transformed blkmem
8546     */
8547 
8548    return SCIP_OKAY;
8549 }
8550 
8551 /** performs the current add of domain, changes all parents accordingly */
8552 static
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)8553 SCIP_RETCODE varProcessAddHoleGlobal(
8554    SCIP_VAR*             var,                /**< problem variable */
8555    BMS_BLKMEM*           blkmem,             /**< block memory */
8556    SCIP_SET*             set,                /**< global SCIP settings */
8557    SCIP_STAT*            stat,               /**< problem statistics */
8558    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
8559    SCIP_Real             left,               /**< left bound of open interval in new hole */
8560    SCIP_Real             right,              /**< right bound of open interval in new hole */
8561    SCIP_Bool*            added               /**< pointer to store whether the hole was added */
8562    )
8563 {
8564    SCIP_VAR* parentvar;
8565    SCIP_Real newlb;
8566    SCIP_Real newub;
8567    int i;
8568 
8569    assert(var != NULL);
8570    assert(added != NULL);
8571    assert(blkmem != NULL);
8572 
8573    /* the interval should not be empty */
8574    assert(SCIPsetIsLT(set, left, right));
8575 
8576    /* the interval bound should already be adjusted */
8577    assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8578    assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8579 
8580    /* the interval should lay between the lower and upper bound */
8581    assert(SCIPsetIsGE(set, left, SCIPvarGetLbGlobal(var)));
8582    assert(SCIPsetIsLE(set, right, SCIPvarGetUbGlobal(var)));
8583 
8584    /* @todo add debugging mechanism for holes when using a debugging solution */
8585 
8586    /* add hole to hole list */
8587    SCIP_CALL( domAddHole(&var->glbdom, blkmem, set, left, right, added) );
8588 
8589    /* check if the hole is redundant */
8590    if( !(*added) )
8591       return SCIP_OKAY;
8592 
8593    /* current bounds */
8594    newlb = var->glbdom.lb;
8595    newub = var->glbdom.ub;
8596 
8597    /* merge domain holes */
8598    domMerge(&var->glbdom, blkmem, set, &newlb, &newub);
8599 
8600    /* the bound should not be changed */
8601    assert(SCIPsetIsEQ(set, newlb, var->glbdom.lb));
8602    assert(SCIPsetIsEQ(set, newub, var->glbdom.ub));
8603 
8604    /* issue bound change event */
8605    assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
8606    if( var->eventfilter != NULL )
8607    {
8608       SCIP_CALL( varEventGholeAdded(var, blkmem, set, eventqueue, left, right) );
8609    }
8610 
8611    /* process parent variables */
8612    for( i = 0; i < var->nparentvars; ++i )
8613    {
8614       SCIP_Real parentnewleft;
8615       SCIP_Real parentnewright;
8616       SCIP_Bool localadded;
8617 
8618       parentvar = var->parentvars[i];
8619       assert(parentvar != NULL);
8620 
8621       switch( SCIPvarGetStatus(parentvar) )
8622       {
8623       case SCIP_VARSTATUS_ORIGINAL:
8624          parentnewleft = left;
8625          parentnewright = right;
8626          break;
8627 
8628       case SCIP_VARSTATUS_COLUMN:
8629       case SCIP_VARSTATUS_LOOSE:
8630       case SCIP_VARSTATUS_FIXED:
8631       case SCIP_VARSTATUS_MULTAGGR:
8632          SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
8633          return SCIP_INVALIDDATA;
8634 
8635       case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
8636          assert(parentvar->data.aggregate.var == var);
8637 
8638          if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
8639          {
8640             /* a > 0 -> change upper bound of x */
8641             parentnewleft = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8642             parentnewright = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8643          }
8644          else
8645          {
8646             /* a < 0 -> change lower bound of x */
8647             assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
8648 
8649             parentnewright = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8650             parentnewleft = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8651          }
8652          break;
8653 
8654       case SCIP_VARSTATUS_NEGATED: /* x = offset - x'  ->  x' = offset - x */
8655          assert(parentvar->negatedvar != NULL);
8656          assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
8657          assert(parentvar->negatedvar->negatedvar == parentvar);
8658 
8659          parentnewright = -left + parentvar->data.negate.constant;
8660          parentnewleft = -right + parentvar->data.negate.constant;
8661          break;
8662 
8663       default:
8664          SCIPerrorMessage("unknown variable status\n");
8665          return SCIP_INVALIDDATA;
8666       }
8667 
8668       SCIPsetDebugMsg(set, "add global hole (%g,%g) to parent variable <%s>\n", parentnewleft, parentnewright, SCIPvarGetName(parentvar));
8669 
8670       /* perform hole added for parent variable */
8671       assert(blkmem != NULL);
8672       assert(SCIPsetIsLT(set, parentnewleft, parentnewright));
8673       SCIP_CALL( varProcessAddHoleGlobal(parentvar, blkmem, set, stat, eventqueue,
8674             parentnewleft, parentnewright, &localadded) );
8675       assert(localadded);
8676    }
8677 
8678    return SCIP_OKAY;
8679 }
8680 
8681 /** adds a hole to the variable's global and local domain */
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)8682 SCIP_RETCODE SCIPvarAddHoleGlobal(
8683    SCIP_VAR*             var,                /**< problem variable */
8684    BMS_BLKMEM*           blkmem,             /**< block memory */
8685    SCIP_SET*             set,                /**< global SCIP settings */
8686    SCIP_STAT*            stat,               /**< problem statistics */
8687    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
8688    SCIP_Real             left,               /**< left bound of open interval in new hole */
8689    SCIP_Real             right,              /**< right bound of open interval in new hole */
8690    SCIP_Bool*            added               /**< pointer to store whether the hole was added */
8691    )
8692 {
8693    SCIP_Real childnewleft;
8694    SCIP_Real childnewright;
8695 
8696    assert(var != NULL);
8697    assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
8698    assert(blkmem != NULL);
8699    assert(added != NULL);
8700 
8701    SCIPsetDebugMsg(set, "adding global hole (%g,%g) to <%s>\n", left, right, var->name);
8702 
8703    /* the interval should not be empty */
8704    assert(SCIPsetIsLT(set, left, right));
8705 
8706    /* the the interval bound should already be adjusted */
8707    assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8708    assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8709 
8710    /* the the interval should lay between the lower and upper bound */
8711    assert(SCIPsetIsGE(set, left, SCIPvarGetLbGlobal(var)));
8712    assert(SCIPsetIsLE(set, right, SCIPvarGetUbGlobal(var)));
8713 
8714    /* change bounds of attached variables */
8715    switch( SCIPvarGetStatus(var) )
8716    {
8717    case SCIP_VARSTATUS_ORIGINAL:
8718       if( var->data.original.transvar != NULL )
8719       {
8720          SCIP_CALL( SCIPvarAddHoleGlobal(var->data.original.transvar, blkmem, set, stat, eventqueue,
8721                left, right, added) );
8722       }
8723       else
8724       {
8725          assert(set->stage == SCIP_STAGE_PROBLEM);
8726 
8727          SCIP_CALL( varProcessAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) );
8728          if( *added )
8729          {
8730             SCIP_Bool localadded;
8731 
8732             SCIP_CALL( SCIPvarAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, &localadded) );
8733          }
8734       }
8735       break;
8736 
8737    case SCIP_VARSTATUS_COLUMN:
8738    case SCIP_VARSTATUS_LOOSE:
8739       SCIP_CALL( varProcessAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) );
8740       if( *added )
8741       {
8742          SCIP_Bool localadded;
8743 
8744          SCIP_CALL( SCIPvarAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, &localadded) );
8745       }
8746       break;
8747 
8748    case SCIP_VARSTATUS_FIXED:
8749       SCIPerrorMessage("cannot add hole of a fixed variable\n");
8750       return SCIP_INVALIDDATA;
8751 
8752    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
8753       assert(var->data.aggregate.var != NULL);
8754 
8755       if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
8756       {
8757          /* a > 0 -> change lower bound of y */
8758          childnewleft = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
8759          childnewright = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
8760       }
8761       else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
8762       {
8763          childnewright = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
8764          childnewleft = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
8765       }
8766       else
8767       {
8768          SCIPerrorMessage("scalar is zero in aggregation\n");
8769          return SCIP_INVALIDDATA;
8770       }
8771       SCIP_CALL( SCIPvarAddHoleGlobal(var->data.aggregate.var, blkmem, set, stat, eventqueue,
8772             childnewleft, childnewright, added) );
8773       break;
8774 
8775    case SCIP_VARSTATUS_MULTAGGR:
8776       SCIPerrorMessage("cannot add a hole of a multi-aggregated variable.\n");
8777       return SCIP_INVALIDDATA;
8778 
8779    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
8780       assert(var->negatedvar != NULL);
8781       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
8782       assert(var->negatedvar->negatedvar == var);
8783 
8784       childnewright = -left + var->data.negate.constant;
8785       childnewleft = -right + var->data.negate.constant;
8786 
8787       SCIP_CALL( SCIPvarAddHoleGlobal(var->negatedvar, blkmem, set, stat, eventqueue,
8788             childnewleft, childnewright, added) );
8789       break;
8790 
8791    default:
8792       SCIPerrorMessage("unknown variable status\n");
8793       return SCIP_INVALIDDATA;
8794    }
8795 
8796    return SCIP_OKAY;
8797 }
8798 
8799 /** performs the current add of domain, changes all parents accordingly */
8800 static
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)8801 SCIP_RETCODE varProcessAddHoleLocal(
8802    SCIP_VAR*             var,                /**< problem variable */
8803    BMS_BLKMEM*           blkmem,             /**< block memory */
8804    SCIP_SET*             set,                /**< global SCIP settings */
8805    SCIP_STAT*            stat,               /**< problem statistics */
8806    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
8807    SCIP_Real             left,               /**< left bound of open interval in new hole */
8808    SCIP_Real             right,              /**< right bound of open interval in new hole */
8809    SCIP_Bool*            added               /**< pointer to store whether the hole was added, or NULL */
8810    )
8811 {
8812    SCIP_VAR* parentvar;
8813    SCIP_Real newlb;
8814    SCIP_Real newub;
8815    int i;
8816 
8817    assert(var != NULL);
8818    assert(added != NULL);
8819    assert(blkmem != NULL);
8820 
8821    /* the interval should not be empty */
8822    assert(SCIPsetIsLT(set, left, right));
8823 
8824    /* the the interval bound should already be adjusted */
8825    assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8826    assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8827 
8828    /* the the interval should lay between the lower and upper bound */
8829    assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
8830    assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
8831 
8832    /* add hole to hole list */
8833    SCIP_CALL( domAddHole(&var->locdom, blkmem, set, left, right, added) );
8834 
8835    /* check if the hole is redundant */
8836    if( !(*added) )
8837       return SCIP_OKAY;
8838 
8839    /* current bounds */
8840    newlb = var->locdom.lb;
8841    newub = var->locdom.ub;
8842 
8843    /* merge domain holes */
8844    domMerge(&var->locdom, blkmem, set, &newlb, &newub);
8845 
8846    /* the bound should not be changed */
8847    assert(SCIPsetIsEQ(set, newlb, var->locdom.lb));
8848    assert(SCIPsetIsEQ(set, newub, var->locdom.ub));
8849 
8850 #if 0
8851    /* issue bound change event */
8852    assert(SCIPvarIsTransformed(var) == (var->eventfilter != NULL));
8853    if( var->eventfilter != NULL )
8854    {
8855       SCIP_CALL( varEventLholeAdded(var, blkmem, set, lp, branchcand, eventqueue, left, right) );
8856    }
8857 #endif
8858 
8859    /* process parent variables */
8860    for( i = 0; i < var->nparentvars; ++i )
8861    {
8862       SCIP_Real parentnewleft;
8863       SCIP_Real parentnewright;
8864       SCIP_Bool localadded;
8865 
8866       parentvar = var->parentvars[i];
8867       assert(parentvar != NULL);
8868 
8869       switch( SCIPvarGetStatus(parentvar) )
8870       {
8871       case SCIP_VARSTATUS_ORIGINAL:
8872          parentnewleft = left;
8873          parentnewright = right;
8874          break;
8875 
8876       case SCIP_VARSTATUS_COLUMN:
8877       case SCIP_VARSTATUS_LOOSE:
8878       case SCIP_VARSTATUS_FIXED:
8879       case SCIP_VARSTATUS_MULTAGGR:
8880          SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
8881          return SCIP_INVALIDDATA;
8882 
8883       case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
8884          assert(parentvar->data.aggregate.var == var);
8885 
8886          if( SCIPsetIsPositive(set, parentvar->data.aggregate.scalar) )
8887          {
8888             /* a > 0 -> change upper bound of x */
8889             parentnewleft = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8890             parentnewright = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8891          }
8892          else
8893          {
8894             /* a < 0 -> change lower bound of x */
8895             assert(SCIPsetIsNegative(set, parentvar->data.aggregate.scalar));
8896 
8897             parentnewright = parentvar->data.aggregate.scalar * left + parentvar->data.aggregate.constant;
8898             parentnewleft = parentvar->data.aggregate.scalar * right + parentvar->data.aggregate.constant;
8899          }
8900          break;
8901 
8902       case SCIP_VARSTATUS_NEGATED: /* x = offset - x'  ->  x' = offset - x */
8903          assert(parentvar->negatedvar != NULL);
8904          assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
8905          assert(parentvar->negatedvar->negatedvar == parentvar);
8906 
8907          parentnewright = -left + parentvar->data.negate.constant;
8908          parentnewleft = -right + parentvar->data.negate.constant;
8909          break;
8910 
8911       default:
8912          SCIPerrorMessage("unknown variable status\n");
8913          return SCIP_INVALIDDATA;
8914       }
8915 
8916       SCIPsetDebugMsg(set, "add local hole (%g,%g) to parent variable <%s>\n", parentnewleft, parentnewright, SCIPvarGetName(parentvar));
8917 
8918       /* perform hole added for parent variable */
8919       assert(blkmem != NULL);
8920       assert(SCIPsetIsLT(set, parentnewleft, parentnewright));
8921       SCIP_CALL( varProcessAddHoleLocal(parentvar, blkmem, set, stat, eventqueue,
8922             parentnewleft, parentnewright, &localadded) );
8923       assert(localadded);
8924    }
8925 
8926    return SCIP_OKAY;
8927 }
8928 
8929 /** adds a hole to the variable's current local domain */
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)8930 SCIP_RETCODE SCIPvarAddHoleLocal(
8931    SCIP_VAR*             var,                /**< problem variable */
8932    BMS_BLKMEM*           blkmem,             /**< block memory */
8933    SCIP_SET*             set,                /**< global SCIP settings */
8934    SCIP_STAT*            stat,               /**< problem statistics */
8935    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue, may be NULL for original variables */
8936    SCIP_Real             left,               /**< left bound of open interval in new hole */
8937    SCIP_Real             right,              /**< right bound of open interval in new hole */
8938    SCIP_Bool*            added               /**< pointer to store whether the hole was added */
8939    )
8940 {
8941    SCIP_Real childnewleft;
8942    SCIP_Real childnewright;
8943 
8944    assert(var != NULL);
8945 
8946    SCIPsetDebugMsg(set, "adding local hole (%g,%g) to <%s>\n", left, right, var->name);
8947 
8948    assert(set != NULL);
8949    assert(var->scip == set->scip);
8950    assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
8951    assert(blkmem != NULL);
8952    assert(added != NULL);
8953 
8954    /* the interval should not be empty */
8955    assert(SCIPsetIsLT(set, left, right));
8956 
8957    /* the the interval bound should already be adjusted */
8958    assert(SCIPsetIsEQ(set, left, adjustedUb(set, SCIPvarGetType(var), left)));
8959    assert(SCIPsetIsEQ(set, right, adjustedLb(set, SCIPvarGetType(var), right)));
8960 
8961    /* the the interval should lay between the lower and upper bound */
8962    assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
8963    assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
8964 
8965    /* change bounds of attached variables */
8966    switch( SCIPvarGetStatus(var) )
8967    {
8968    case SCIP_VARSTATUS_ORIGINAL:
8969       if( var->data.original.transvar != NULL )
8970       {
8971          SCIP_CALL( SCIPvarAddHoleLocal(var->data.original.transvar, blkmem, set, stat, eventqueue,
8972                left, right, added) );
8973       }
8974       else
8975       {
8976          assert(set->stage == SCIP_STAGE_PROBLEM);
8977          SCIPstatIncrement(stat, set, domchgcount);
8978          SCIP_CALL( varProcessAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, added) );
8979       }
8980       break;
8981 
8982    case SCIP_VARSTATUS_COLUMN:
8983    case SCIP_VARSTATUS_LOOSE:
8984       SCIPstatIncrement(stat, set, domchgcount);
8985       SCIP_CALL( varProcessAddHoleLocal(var, blkmem, set, stat, eventqueue, left, right, added) );
8986       break;
8987 
8988    case SCIP_VARSTATUS_FIXED:
8989       SCIPerrorMessage("cannot add domain hole to a fixed variable\n");
8990       return SCIP_INVALIDDATA;
8991 
8992    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
8993       assert(var->data.aggregate.var != NULL);
8994 
8995       if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
8996       {
8997          /* a > 0 -> change lower bound of y */
8998          childnewleft = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
8999          childnewright = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
9000       }
9001       else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
9002       {
9003          childnewright = (left - var->data.aggregate.constant)/var->data.aggregate.scalar;
9004          childnewleft = (right - var->data.aggregate.constant)/var->data.aggregate.scalar;
9005       }
9006       else
9007       {
9008          SCIPerrorMessage("scalar is zero in aggregation\n");
9009          return SCIP_INVALIDDATA;
9010       }
9011       SCIP_CALL( SCIPvarAddHoleLocal(var->data.aggregate.var, blkmem, set, stat, eventqueue,
9012             childnewleft, childnewright, added) );
9013       break;
9014 
9015    case SCIP_VARSTATUS_MULTAGGR:
9016       SCIPerrorMessage("cannot add domain hole to a multi-aggregated variable.\n");
9017       return SCIP_INVALIDDATA;
9018 
9019    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
9020       assert(var->negatedvar != NULL);
9021       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
9022       assert(var->negatedvar->negatedvar == var);
9023 
9024       childnewright = -left + var->data.negate.constant;
9025       childnewleft = -right + var->data.negate.constant;
9026 
9027       SCIP_CALL( SCIPvarAddHoleLocal(var->negatedvar, blkmem, set, stat, eventqueue, childnewleft, childnewright, added) );
9028       break;
9029 
9030    default:
9031       SCIPerrorMessage("unknown variable status\n");
9032       return SCIP_INVALIDDATA;
9033    }
9034 
9035    return SCIP_OKAY;
9036 }
9037 
9038 /** resets the global and local bounds of original variable to their original values */
SCIPvarResetBounds(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat)9039 SCIP_RETCODE SCIPvarResetBounds(
9040    SCIP_VAR*             var,                /**< problem variable */
9041    BMS_BLKMEM*           blkmem,             /**< block memory */
9042    SCIP_SET*             set,                /**< global SCIP settings */
9043    SCIP_STAT*            stat                /**< problem statistics */
9044    )
9045 {
9046    assert(var != NULL);
9047    assert(set != NULL);
9048    assert(var->scip == set->scip);
9049    assert(SCIPvarIsOriginal(var));
9050    /* resetting of bounds on original variables which have a transformed counterpart easily fails if, e.g.,
9051     * the transformed variable has been fixed */
9052    assert(SCIPvarGetTransVar(var) == NULL);
9053 
9054    /* copy the original bounds back to the global and local bounds */
9055    SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, NULL, NULL, NULL, NULL, var->data.original.origdom.lb) );
9056    SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, NULL, NULL, NULL, NULL, var->data.original.origdom.ub) );
9057    SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.lb) );
9058    SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, NULL, NULL, NULL, var->data.original.origdom.ub) );
9059 
9060    /* free the global and local holelists and duplicate the original ones */
9061    /**@todo this has also to be called recursively with methods similar to SCIPvarChgLbGlobal() */
9062    holelistFree(&var->glbdom.holelist, blkmem);
9063    holelistFree(&var->locdom.holelist, blkmem);
9064    SCIP_CALL( holelistDuplicate(&var->glbdom.holelist, blkmem, set, var->data.original.origdom.holelist) );
9065    SCIP_CALL( holelistDuplicate(&var->locdom.holelist, blkmem, set, var->data.original.origdom.holelist) );
9066 
9067    return SCIP_OKAY;
9068 }
9069 
9070 /** issues a IMPLADDED event on the given variable */
9071 static
varEventImplAdded(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue)9072 SCIP_RETCODE varEventImplAdded(
9073    SCIP_VAR*             var,                /**< problem variable to change */
9074    BMS_BLKMEM*           blkmem,             /**< block memory */
9075    SCIP_SET*             set,                /**< global SCIP settings */
9076    SCIP_EVENTQUEUE*      eventqueue          /**< event queue */
9077    )
9078 {
9079    SCIP_EVENT* event;
9080 
9081    assert(var != NULL);
9082 
9083    /* issue IMPLADDED event on variable */
9084    SCIP_CALL( SCIPeventCreateImplAdded(&event, blkmem, var) );
9085    SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
9086 
9087    return SCIP_OKAY;
9088 }
9089 
9090 /** actually performs the addition of a variable bound to the variable's vbound arrays */
9091 static
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)9092 SCIP_RETCODE varAddVbound(
9093    SCIP_VAR*             var,                /**< problem variable x in x <= b*z + d  or  x >= b*z + d */
9094    BMS_BLKMEM*           blkmem,             /**< block memory */
9095    SCIP_SET*             set,                /**< global SCIP settings */
9096    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9097    SCIP_BOUNDTYPE        vbtype,             /**< type of variable bound (LOWER or UPPER) */
9098    SCIP_VAR*             vbvar,              /**< variable z    in x <= b*z + d  or  x >= b*z + d */
9099    SCIP_Real             vbcoef,             /**< coefficient b in x <= b*z + d  or  x >= b*z + d */
9100    SCIP_Real             vbconstant          /**< constant d    in x <= b*z + d  or  x >= b*z + d */
9101    )
9102 {
9103    SCIP_Bool added;
9104 
9105    /* It can happen that the variable "var" and the variable "vbvar" are the same variable. For example if a variable
9106     * gets aggregated, the variable bounds (vbound) of that variable are copied to the other variable. A variable bound
9107     * variable of the aggregated variable might be the same as the one its gets aggregated too.
9108     *
9109     * If the variable "var" and the variable "vbvar" are the same, the variable bound which should be added here has to
9110     * be redundant. This is the case since an infeasibility should have be detected in the previous methods. As well as
9111     * the bounds of the variable which should be also already be tightened in the previous methods. Therefore, the
9112     * variable bound can be ignored.
9113     *
9114     * From the way the the variable bound system is implemented (detecting infeasibility, tighten bounds), the
9115     * equivalence of the variables should be checked here.
9116     */
9117    if( var == vbvar )
9118    {
9119       /* in this case the variable bound has to be redundant, this means for possible assignments to this variable; this
9120        * can be checked via the global bounds of the variable */
9121 #ifndef NDEBUG
9122       SCIP_Real lb;
9123       SCIP_Real ub;
9124 
9125       lb = SCIPvarGetLbGlobal(var);
9126       ub = SCIPvarGetUbGlobal(var);
9127 
9128       if(vbtype == SCIP_BOUNDTYPE_LOWER)
9129       {
9130          if( vbcoef > 0.0 )
9131          {
9132             assert(SCIPsetIsGE(set, lb,  lb * vbcoef + vbconstant) );
9133             assert(SCIPsetIsGE(set, ub,  ub * vbcoef + vbconstant) );
9134          }
9135          else
9136          {
9137             assert(SCIPsetIsGE(set, lb,  ub * vbcoef + vbconstant) );
9138             assert(SCIPsetIsGE(set, ub,  lb * vbcoef + vbconstant) );
9139          }
9140       }
9141       else
9142       {
9143          assert(vbtype == SCIP_BOUNDTYPE_UPPER);
9144          if( vbcoef > 0.0 )
9145          {
9146             assert(SCIPsetIsLE(set, lb,  lb * vbcoef + vbconstant) );
9147             assert(SCIPsetIsLE(set, ub,  ub * vbcoef + vbconstant) );
9148          }
9149          else
9150          {
9151             assert(SCIPsetIsLE(set, lb,  ub * vbcoef + vbconstant) );
9152             assert(SCIPsetIsLE(set, ub,  lb * vbcoef + vbconstant) );
9153          }
9154       }
9155 #endif
9156       SCIPsetDebugMsg(set, "redundant variable bound: <%s> %s %g<%s> %+g\n",
9157          SCIPvarGetName(var), vbtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", vbcoef, SCIPvarGetName(vbvar), vbconstant);
9158 
9159       return SCIP_OKAY;
9160    }
9161 
9162    SCIPsetDebugMsg(set, "adding variable bound: <%s> %s %g<%s> %+g\n",
9163       SCIPvarGetName(var), vbtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", vbcoef, SCIPvarGetName(vbvar), vbconstant);
9164 
9165    /* check variable bound on debugging solution */
9166    SCIP_CALL( SCIPdebugCheckVbound(set, var, vbtype, vbvar, vbcoef, vbconstant) ); /*lint !e506 !e774*/
9167 
9168    /* perform the addition */
9169    if( vbtype == SCIP_BOUNDTYPE_LOWER )
9170    {
9171       SCIP_CALL( SCIPvboundsAdd(&var->vlbs, blkmem, set, vbtype, vbvar, vbcoef, vbconstant, &added) );
9172    }
9173    else
9174    {
9175       SCIP_CALL( SCIPvboundsAdd(&var->vubs, blkmem, set, vbtype, vbvar, vbcoef, vbconstant, &added) );
9176    }
9177    var->closestvblpcount = -1;
9178 
9179    if( added )
9180    {
9181       /* issue IMPLADDED event */
9182       SCIP_CALL( varEventImplAdded(var, blkmem, set, eventqueue) );
9183    }
9184 
9185    return SCIP_OKAY;
9186 }
9187 
9188 /** checks whether the given implication is redundant or infeasible w.r.t. the implied variables global bounds */
9189 static
checkImplic(SCIP_SET * set,SCIP_VAR * implvar,SCIP_BOUNDTYPE impltype,SCIP_Real implbound,SCIP_Bool * redundant,SCIP_Bool * infeasible)9190 void checkImplic(
9191    SCIP_SET*             set,                /**< global SCIP settings */
9192    SCIP_VAR*             implvar,            /**< variable y in implication y <= b or y >= b */
9193    SCIP_BOUNDTYPE        impltype,           /**< type       of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9194    SCIP_Real             implbound,          /**< bound b    in implication y <= b or y >= b */
9195    SCIP_Bool*            redundant,          /**< pointer to store whether the implication is redundant */
9196    SCIP_Bool*            infeasible          /**< pointer to store whether the implication is infeasible */
9197    )
9198 {
9199    SCIP_Real impllb;
9200    SCIP_Real implub;
9201 
9202    assert(redundant != NULL);
9203    assert(infeasible != NULL);
9204 
9205    impllb = SCIPvarGetLbGlobal(implvar);
9206    implub = SCIPvarGetUbGlobal(implvar);
9207    if( impltype == SCIP_BOUNDTYPE_LOWER )
9208    {
9209       *infeasible = SCIPsetIsFeasGT(set, implbound, implub);
9210       *redundant = SCIPsetIsFeasLE(set, implbound, impllb);
9211    }
9212    else
9213    {
9214       *infeasible = SCIPsetIsFeasLT(set, implbound, impllb);
9215       *redundant = SCIPsetIsFeasGE(set, implbound, implub);
9216    }
9217 }
9218 
9219 /** applies the given implication, if it is not redundant */
9220 static
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)9221 SCIP_RETCODE applyImplic(
9222    BMS_BLKMEM*           blkmem,             /**< block memory */
9223    SCIP_SET*             set,                /**< global SCIP settings */
9224    SCIP_STAT*            stat,               /**< problem statistics */
9225    SCIP_PROB*            transprob,          /**< transformed problem */
9226    SCIP_PROB*            origprob,           /**< original problem */
9227    SCIP_TREE*            tree,               /**< branch and bound tree if in solving stage */
9228    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
9229    SCIP_LP*              lp,                 /**< current LP data */
9230    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
9231    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9232    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
9233    SCIP_VAR*             implvar,            /**< variable y in implication y <= b or y >= b */
9234    SCIP_BOUNDTYPE        impltype,           /**< type       of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9235    SCIP_Real             implbound,          /**< bound b    in implication y <= b or y >= b */
9236    SCIP_Bool*            infeasible,         /**< pointer to store whether an infeasibility was detected */
9237    int*                  nbdchgs             /**< pointer to count the number of performed bound changes, or NULL */
9238    )
9239 {
9240    SCIP_Real implub;
9241    SCIP_Real impllb;
9242 
9243    assert(infeasible != NULL);
9244 
9245    *infeasible = FALSE;
9246 
9247    implub = SCIPvarGetUbGlobal(implvar);
9248    impllb = SCIPvarGetLbGlobal(implvar);
9249    if( impltype == SCIP_BOUNDTYPE_LOWER )
9250    {
9251       if( SCIPsetIsFeasGT(set, implbound, implub) )
9252       {
9253          /* the implication produces a conflict: the problem is infeasible */
9254          *infeasible = TRUE;
9255       }
9256       else if( SCIPsetIsFeasGT(set, implbound, impllb) )
9257       {
9258          /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9259           * with the local bound, in this case we need to store the bound change as pending bound change
9260           */
9261          if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9262          {
9263             assert(tree != NULL);
9264             assert(transprob != NULL);
9265             assert(SCIPprobIsTransformed(transprob));
9266 
9267             SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9268                   tree, reopt, lp, branchcand, eventqueue, cliquetable, implvar, implbound, SCIP_BOUNDTYPE_LOWER, FALSE) );
9269          }
9270          else
9271          {
9272             SCIP_CALL( SCIPvarChgLbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, implbound) );
9273          }
9274 
9275          if( nbdchgs != NULL )
9276             (*nbdchgs)++;
9277       }
9278    }
9279    else
9280    {
9281       if( SCIPsetIsFeasLT(set, implbound, impllb) )
9282       {
9283          /* the implication produces a conflict: the problem is infeasible */
9284          *infeasible = TRUE;
9285       }
9286       else if( SCIPsetIsFeasLT(set, implbound, implub) )
9287       {
9288          /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9289           * with the local bound, in this case we need to store the bound change as pending bound change
9290           */
9291          if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9292          {
9293             assert(tree != NULL);
9294             assert(transprob != NULL);
9295             assert(SCIPprobIsTransformed(transprob));
9296 
9297             SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9298                   tree, reopt, lp, branchcand, eventqueue, cliquetable, implvar, implbound, SCIP_BOUNDTYPE_UPPER, FALSE) );
9299          }
9300          else
9301          {
9302             SCIP_CALL( SCIPvarChgUbGlobal(implvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, implbound) );
9303          }
9304 
9305          if( nbdchgs != NULL )
9306             (*nbdchgs)++;
9307       }
9308    }
9309 
9310    return SCIP_OKAY;
9311 }
9312 
9313 /** actually performs the addition of an implication to the variable's implication arrays,
9314  *  and adds the corresponding implication or variable bound to the implied variable;
9315  *  if the implication is conflicting, the variable is fixed to the opposite value;
9316  *  if the variable is already fixed to the given value, the implication is performed immediately;
9317  *  if the implication is redundant with respect to the variables' global bounds, it is ignored
9318  */
9319 static
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)9320 SCIP_RETCODE varAddImplic(
9321    SCIP_VAR*             var,                /**< problem variable */
9322    BMS_BLKMEM*           blkmem,             /**< block memory */
9323    SCIP_SET*             set,                /**< global SCIP settings */
9324    SCIP_STAT*            stat,               /**< problem statistics */
9325    SCIP_PROB*            transprob,          /**< transformed problem */
9326    SCIP_PROB*            origprob,           /**< original problem */
9327    SCIP_TREE*            tree,               /**< branch and bound tree if in solving stage */
9328    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
9329    SCIP_LP*              lp,                 /**< current LP data */
9330    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
9331    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
9332    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9333    SCIP_Bool             varfixing,          /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9334    SCIP_VAR*             implvar,            /**< variable y in implication y <= b or y >= b */
9335    SCIP_BOUNDTYPE        impltype,           /**< type       of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9336    SCIP_Real             implbound,          /**< bound b    in implication y <= b or y >= b */
9337    SCIP_Bool             isshortcut,         /**< is the implication a shortcut, i.e., added as part of the transitive closure of another implication? */
9338    SCIP_Bool*            infeasible,         /**< pointer to store whether an infeasibility was detected */
9339    int*                  nbdchgs,            /**< pointer to count the number of performed bound changes, or NULL */
9340    SCIP_Bool*            added               /**< pointer to store whether an implication was added */
9341    )
9342 {
9343    SCIP_Bool redundant;
9344    SCIP_Bool conflict;
9345 
9346    assert(var != NULL);
9347    assert(SCIPvarIsActive(var));
9348    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
9349    assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
9350    assert(SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED);
9351    assert(infeasible != NULL);
9352    assert(added != NULL);
9353 
9354    /* check implication on debugging solution */
9355    SCIP_CALL( SCIPdebugCheckImplic(set, var, varfixing, implvar, impltype, implbound) ); /*lint !e506 !e774*/
9356 
9357    *infeasible = FALSE;
9358    *added = FALSE;
9359 
9360    /* check, if the implication is redundant or infeasible */
9361    checkImplic(set, implvar, impltype, implbound, &redundant, &conflict);
9362    assert(!redundant || !conflict);
9363    if( redundant )
9364       return SCIP_OKAY;
9365 
9366    if( var == implvar )
9367    {
9368       /* special cases appear were a bound to a variable implies itself to be outside the bounds:
9369        * x == varfixing  =>  x < 0 or x > 1
9370        */
9371       if( SCIPsetIsLT(set, implbound, 0.0) || SCIPsetIsGT(set, implbound, 1.0) )
9372          conflict = TRUE;
9373       else
9374       {
9375          /* variable implies itself: x == varfixing  =>  x == (impltype == SCIP_BOUNDTYPE_LOWER) */
9376          assert(SCIPsetIsZero(set, implbound) || SCIPsetIsEQ(set, implbound, 1.0));
9377          assert(SCIPsetIsZero(set, implbound) == (impltype == SCIP_BOUNDTYPE_UPPER));
9378          assert(SCIPsetIsEQ(set, implbound, 1.0) == (impltype == SCIP_BOUNDTYPE_LOWER));
9379          conflict = conflict || ((varfixing == TRUE) == (impltype == SCIP_BOUNDTYPE_UPPER));
9380          if( !conflict )
9381             return SCIP_OKAY;
9382       }
9383    }
9384 
9385    /* check, if the variable is already fixed */
9386    if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
9387    {
9388       /* if the variable is fixed to the given value, perform the implication; otherwise, ignore the implication */
9389       if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
9390       {
9391          SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
9392                cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) );
9393       }
9394       return SCIP_OKAY;
9395    }
9396 
9397    assert((impltype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, implbound, SCIPvarGetLbGlobal(implvar)))
9398       || (impltype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, implbound, SCIPvarGetUbGlobal(implvar))));
9399 
9400    if( !conflict )
9401    {
9402       assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9403 
9404       if( SCIPvarIsBinary(implvar) )
9405       {
9406          SCIP_VAR* vars[2];
9407          SCIP_Bool vals[2];
9408 
9409          assert(SCIPsetIsFeasEQ(set, implbound, 1.0) || SCIPsetIsFeasZero(set, implbound));
9410          assert((impltype == SCIP_BOUNDTYPE_UPPER) == SCIPsetIsFeasZero(set, implbound));
9411 
9412          vars[0] = var;
9413          vars[1] = implvar;
9414          vals[0] = varfixing;
9415          vals[1] = (impltype == SCIP_BOUNDTYPE_UPPER);
9416 
9417          /* add the clique to the clique table */
9418          SCIP_CALL( SCIPcliquetableAdd(cliquetable, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
9419                eventqueue, vars, vals, 2, FALSE, &conflict, nbdchgs) );
9420 
9421          if( !conflict )
9422             return SCIP_OKAY;
9423       }
9424       else
9425       {
9426          /* add implication x == 0/1 -> y <= b / y >= b to the implications list of x */
9427          SCIPsetDebugMsg(set, "adding implication: <%s> == %u  ==>  <%s> %s %g\n",
9428             SCIPvarGetName(var), varfixing,
9429             SCIPvarGetName(implvar), impltype == SCIP_BOUNDTYPE_UPPER ? "<=" : ">=", implbound);
9430          SCIP_CALL( SCIPimplicsAdd(&var->implics, blkmem, set, stat, varfixing, implvar, impltype, implbound,
9431                isshortcut, &conflict, added) );
9432       }
9433    }
9434    assert(!conflict || !(*added));
9435 
9436    /* on conflict, fix the variable to the opposite value */
9437    if( conflict )
9438    {
9439       SCIPsetDebugMsg(set, " -> implication yields a conflict: fix <%s> == %d\n", SCIPvarGetName(var), !varfixing);
9440 
9441       /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9442        * with the local bound, in this case we need to store the bound change as pending bound change
9443        */
9444       if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9445       {
9446          assert(tree != NULL);
9447          assert(transprob != NULL);
9448          assert(SCIPprobIsTransformed(transprob));
9449 
9450          if( varfixing )
9451          {
9452             SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9453                   tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) );
9454          }
9455          else
9456          {
9457             SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9458                   tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 1.0, SCIP_BOUNDTYPE_LOWER, FALSE) );
9459          }
9460       }
9461       else
9462       {
9463          if( varfixing )
9464          {
9465             SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 0.0) );
9466          }
9467          else
9468          {
9469             SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 1.0) );
9470          }
9471       }
9472       if( nbdchgs != NULL )
9473          (*nbdchgs)++;
9474 
9475       return SCIP_OKAY;
9476    }
9477    else if( *added )
9478    {
9479       /* issue IMPLADDED event */
9480       SCIP_CALL( varEventImplAdded(var, blkmem, set, eventqueue) );
9481    }
9482    else
9483    {
9484       /* the implication was redundant: the inverse is also redundant */
9485       return SCIP_OKAY;
9486    }
9487 
9488    assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9489 
9490    /* check, whether implied variable is binary */
9491    if( !SCIPvarIsBinary(implvar) )
9492    {
9493       SCIP_Real lb;
9494       SCIP_Real ub;
9495 
9496       /* add inverse variable bound to the variable bounds of y with global bounds y \in [lb,ub]:
9497        *   x == 0 -> y <= b  <->  y <= (ub - b)*x + b
9498        *   x == 1 -> y <= b  <->  y <= (b - ub)*x + ub
9499        *   x == 0 -> y >= b  <->  y >= (lb - b)*x + b
9500        *   x == 1 -> y >= b  <->  y >= (b - lb)*x + lb
9501        * for numerical reasons, ignore variable bounds with large absolute coefficient
9502        */
9503       lb = SCIPvarGetLbGlobal(implvar);
9504       ub = SCIPvarGetUbGlobal(implvar);
9505       if( impltype == SCIP_BOUNDTYPE_UPPER )
9506       {
9507          if( REALABS(implbound - ub) <= MAXABSVBCOEF )
9508          {
9509             SCIP_CALL( varAddVbound(implvar, blkmem, set, eventqueue, SCIP_BOUNDTYPE_UPPER, var,
9510                   varfixing ? implbound - ub : ub - implbound, varfixing ? ub : implbound) );
9511          }
9512       }
9513       else
9514       {
9515          if( REALABS(implbound - lb) <= MAXABSVBCOEF )
9516          {
9517             SCIP_CALL( varAddVbound(implvar, blkmem, set, eventqueue, SCIP_BOUNDTYPE_LOWER, var,
9518                   varfixing ? implbound - lb : lb - implbound, varfixing ? lb : implbound) );
9519          }
9520       }
9521    }
9522 
9523    return SCIP_OKAY;
9524 }
9525 
9526 /** adds transitive closure for binary implication x = a -> y = b */
9527 static
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)9528 SCIP_RETCODE varAddTransitiveBinaryClosureImplic(
9529    SCIP_VAR*             var,                /**< problem variable */
9530    BMS_BLKMEM*           blkmem,             /**< block memory */
9531    SCIP_SET*             set,                /**< global SCIP settings */
9532    SCIP_STAT*            stat,               /**< problem statistics */
9533    SCIP_PROB*            transprob,          /**< transformed problem */
9534    SCIP_PROB*            origprob,           /**< original problem */
9535    SCIP_TREE*            tree,               /**< branch and bound tree if in solving stage */
9536    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
9537    SCIP_LP*              lp,                 /**< current LP data */
9538    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
9539    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
9540    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9541    SCIP_Bool             varfixing,          /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9542    SCIP_VAR*             implvar,            /**< variable y in implication y <= b or y >= b */
9543    SCIP_Bool             implvarfixing,      /**< fixing b in implication */
9544    SCIP_Bool*            infeasible,         /**< pointer to store whether an infeasibility was detected */
9545    int*                  nbdchgs             /**< pointer to count the number of performed bound changes, or NULL */
9546    )
9547 {
9548    SCIP_VAR** implvars;
9549    SCIP_BOUNDTYPE* impltypes;
9550    SCIP_Real* implbounds;
9551    int nimpls;
9552    int i;
9553 
9554    *infeasible = FALSE;
9555 
9556    /* binary variable: implications of implvar */
9557    nimpls = SCIPimplicsGetNImpls(implvar->implics, implvarfixing);
9558    implvars = SCIPimplicsGetVars(implvar->implics, implvarfixing);
9559    impltypes = SCIPimplicsGetTypes(implvar->implics, implvarfixing);
9560    implbounds = SCIPimplicsGetBounds(implvar->implics, implvarfixing);
9561 
9562    /* if variable has too many implications, the implication graph may become too dense */
9563    i = MIN(nimpls, MAXIMPLSCLOSURE) - 1;
9564 
9565    /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9566     * implvars[i] is fixed, s.t. the implication y == varfixing -> z <= b / z >= b is deleted; this affects the
9567     * array over which we currently iterate; the only thing that can happen, is that elements of the array are
9568     * deleted; in this case, the subsequent elements are moved to the front; if we iterate from back to front, the
9569     * only thing that can happen is that we add the same implication twice - this does no harm
9570     */
9571    while ( i >= 0 && !(*infeasible) )
9572    {
9573       SCIP_Bool added;
9574 
9575       assert(implvars[i] != implvar);
9576 
9577       /* we have x == varfixing -> y == implvarfixing -> z <= b / z >= b:
9578        * add implication x == varfixing -> z <= b / z >= b to the implications list of x
9579        */
9580       if( SCIPvarIsActive(implvars[i]) )
9581       {
9582          SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
9583                eventqueue, varfixing, implvars[i], impltypes[i], implbounds[i], TRUE, infeasible, nbdchgs, &added) );
9584          assert(SCIPimplicsGetNImpls(implvar->implics, implvarfixing) <= nimpls);
9585          nimpls = SCIPimplicsGetNImpls(implvar->implics, implvarfixing);
9586          i = MIN(i, nimpls); /* some elements from the array could have been removed */
9587       }
9588       --i;
9589    }
9590 
9591    return SCIP_OKAY;
9592 }
9593 
9594 /** adds given implication to the variable's implication list, and adds all implications directly implied by this
9595  *  implication to the variable's implication list;
9596  *  if the implication is conflicting, the variable is fixed to the opposite value;
9597  *  if the variable is already fixed to the given value, the implication is performed immediately;
9598  *  if the implication is redundant with respect to the variables' global bounds, it is ignored
9599  */
9600 static
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)9601 SCIP_RETCODE varAddTransitiveImplic(
9602    SCIP_VAR*             var,                /**< problem variable */
9603    BMS_BLKMEM*           blkmem,             /**< block memory */
9604    SCIP_SET*             set,                /**< global SCIP settings */
9605    SCIP_STAT*            stat,               /**< problem statistics */
9606    SCIP_PROB*            transprob,          /**< transformed problem */
9607    SCIP_PROB*            origprob,           /**< original problem */
9608    SCIP_TREE*            tree,               /**< branch and bound tree if in solving stage */
9609    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
9610    SCIP_LP*              lp,                 /**< current LP data */
9611    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
9612    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
9613    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9614    SCIP_Bool             varfixing,          /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
9615    SCIP_VAR*             implvar,            /**< variable y in implication y <= b or y >= b */
9616    SCIP_BOUNDTYPE        impltype,           /**< type       of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
9617    SCIP_Real             implbound,          /**< bound b    in implication y <= b or y >= b */
9618    SCIP_Bool             transitive,         /**< should transitive closure of implication also be added? */
9619    SCIP_Bool*            infeasible,         /**< pointer to store whether an infeasibility was detected */
9620    int*                  nbdchgs             /**< pointer to count the number of performed bound changes, or NULL */
9621    )
9622 {
9623    SCIP_Bool added;
9624 
9625    assert(var != NULL);
9626    assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
9627    assert(SCIPvarIsActive(var));
9628    assert(implvar != NULL);
9629    assert(SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED);
9630    assert(infeasible != NULL);
9631 
9632    /* add implication x == varfixing -> y <= b / y >= b to the implications list of x */
9633    SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable, branchcand,
9634          eventqueue, varfixing, implvar, impltype, implbound, FALSE, infeasible, nbdchgs, &added) );
9635 
9636    if( *infeasible || var == implvar || !transitive || !added )
9637       return SCIP_OKAY;
9638 
9639    assert(SCIPvarIsActive(implvar)); /* a fixed implvar would either cause a redundancy or infeasibility */
9640 
9641    /* add transitive closure */
9642    if( SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY )
9643    {
9644       SCIP_Bool implvarfixing;
9645 
9646       implvarfixing = (impltype == SCIP_BOUNDTYPE_LOWER);
9647 
9648       /* binary variable: implications of implvar */
9649       SCIP_CALL( varAddTransitiveBinaryClosureImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
9650             cliquetable, branchcand, eventqueue, varfixing, implvar, implvarfixing, infeasible, nbdchgs) );
9651 
9652       /* inverse implication */
9653       if( !(*infeasible) )
9654       {
9655          SCIP_CALL( varAddTransitiveBinaryClosureImplic(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
9656                cliquetable, branchcand, eventqueue, !implvarfixing, var, !varfixing, infeasible, nbdchgs) );
9657       }
9658    }
9659    else
9660    {
9661       /* non-binary variable: variable lower bounds of implvar */
9662       if( impltype == SCIP_BOUNDTYPE_UPPER && implvar->vlbs != NULL )
9663       {
9664          SCIP_VAR** vlbvars;
9665          SCIP_Real* vlbcoefs;
9666          SCIP_Real* vlbconstants;
9667          int nvlbvars;
9668          int i;
9669 
9670          nvlbvars = SCIPvboundsGetNVbds(implvar->vlbs);
9671          vlbvars = SCIPvboundsGetVars(implvar->vlbs);
9672          vlbcoefs = SCIPvboundsGetCoefs(implvar->vlbs);
9673          vlbconstants = SCIPvboundsGetConstants(implvar->vlbs);
9674 
9675          /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9676           * vlbvars[i] is fixed, s.t. the variable bound is deleted; this affects the array over which we currently
9677           * iterate; the only thing that can happen, is that elements of the array are deleted; in this case, the
9678           * subsequent elements are moved to the front; if we iterate from back to front, the only thing that can happen
9679           * is that we add the same implication twice - this does no harm
9680           */
9681          i = nvlbvars-1;
9682          while ( i >= 0 && !(*infeasible) )
9683          {
9684             assert(vlbvars[i] != implvar);
9685             assert(!SCIPsetIsZero(set, vlbcoefs[i]));
9686 
9687             /* we have x == varfixing -> y <= b and y >= c*z + d:
9688              *   c > 0: add implication x == varfixing -> z <= (b-d)/c to the implications list of x
9689              *   c < 0: add implication x == varfixing -> z >= (b-d)/c to the implications list of x
9690              *
9691              * @note during an aggregation the aggregated variable "aggrvar" (the one which will have the status
9692              *       SCIP_VARSTATUS_AGGREGATED afterwards) copies its variable lower and uppers bounds to the
9693              *       aggregation variable (the one which will stay active);
9694              *
9695              *       W.l.o.g. we consider the variable upper bounds for now. Let "vubvar" be a variable upper bound of
9696              *       the aggregated variable "aggvar"; During that copying of that variable upper bound variable
9697              *       "vubvar" the variable lower and upper bounds of this variable "vubvar" are also considered; note
9698              *       that the "aggvar" can be a variable lower bound variable of the variable "vubvar"; Due to that
9699              *       situation it can happen that we reach that code place where "vlbvars[i] == aggvar". In particular
9700              *       the "aggvar" has already the variable status SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED
9701              *       but is still active since the aggregation is not finished yet (in SCIPvarAggregate()); therefore we
9702              *       have to explicitly check that the active variable has not a variable status
9703              *       SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED;
9704              */
9705             if( SCIPvarIsActive(vlbvars[i]) && SCIPvarGetStatus(vlbvars[i]) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(vlbvars[i]) != SCIP_VARSTATUS_NEGATED )
9706             {
9707                SCIP_Real vbimplbound;
9708 
9709                vbimplbound = (implbound - vlbconstants[i])/vlbcoefs[i];
9710                if( vlbcoefs[i] >= 0.0 )
9711                {
9712                   vbimplbound = adjustedUb(set, SCIPvarGetType(vlbvars[i]), vbimplbound);
9713                   SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9714                         branchcand, eventqueue, varfixing, vlbvars[i], SCIP_BOUNDTYPE_UPPER, vbimplbound, TRUE,
9715                         infeasible, nbdchgs, &added) );
9716                }
9717                else
9718                {
9719                   vbimplbound = adjustedLb(set, SCIPvarGetType(vlbvars[i]), vbimplbound);
9720                   SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9721                         branchcand, eventqueue, varfixing, vlbvars[i], SCIP_BOUNDTYPE_LOWER, vbimplbound, TRUE,
9722                         infeasible, nbdchgs, &added) );
9723                }
9724                nvlbvars = SCIPvboundsGetNVbds(implvar->vlbs);
9725                i = MIN(i, nvlbvars); /* some elements from the array could have been removed */
9726             }
9727             --i;
9728          }
9729       }
9730 
9731       /* non-binary variable: variable upper bounds of implvar */
9732       if( impltype == SCIP_BOUNDTYPE_LOWER && implvar->vubs != NULL )
9733       {
9734          SCIP_VAR** vubvars;
9735          SCIP_Real* vubcoefs;
9736          SCIP_Real* vubconstants;
9737          int nvubvars;
9738          int i;
9739 
9740          nvubvars = SCIPvboundsGetNVbds(implvar->vubs);
9741          vubvars = SCIPvboundsGetVars(implvar->vubs);
9742          vubcoefs = SCIPvboundsGetCoefs(implvar->vubs);
9743          vubconstants = SCIPvboundsGetConstants(implvar->vubs);
9744 
9745          /* we have to iterate from back to front, because in varAddImplic() it may happen that a conflict is detected and
9746           * vubvars[i] is fixed, s.t. the variable bound is deleted; this affects the array over which we currently
9747           * iterate; the only thing that can happen, is that elements of the array are deleted; in this case, the
9748           * subsequent elements are moved to the front; if we iterate from back to front, the only thing that can happen
9749           * is that we add the same implication twice - this does no harm
9750           */
9751          i = nvubvars-1;
9752          while ( i >= 0 && !(*infeasible) )
9753          {
9754             assert(vubvars[i] != implvar);
9755             assert(!SCIPsetIsZero(set, vubcoefs[i]));
9756 
9757             /* we have x == varfixing -> y >= b and y <= c*z + d:
9758              *   c > 0: add implication x == varfixing -> z >= (b-d)/c to the implications list of x
9759              *   c < 0: add implication x == varfixing -> z <= (b-d)/c to the implications list of x
9760              *
9761              * @note during an aggregation the aggregated variable "aggrvar" (the one which will have the status
9762              *       SCIP_VARSTATUS_AGGREGATED afterwards) copies its variable lower and uppers bounds to the
9763              *       aggregation variable (the one which will stay active);
9764              *
9765              *       W.l.o.g. we consider the variable lower bounds for now. Let "vlbvar" be a variable lower bound of
9766              *       the aggregated variable "aggvar"; During that copying of that variable lower bound variable
9767              *       "vlbvar" the variable lower and upper bounds of this variable "vlbvar" are also considered; note
9768              *       that the "aggvar" can be a variable upper bound variable of the variable "vlbvar"; Due to that
9769              *       situation it can happen that we reach that code place where "vubvars[i] == aggvar". In particular
9770              *       the "aggvar" has already the variable status SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED
9771              *       but is still active since the aggregation is not finished yet (in SCIPvarAggregate()); therefore we
9772              *       have to explicitly check that the active variable has not a variable status
9773              *       SCIP_VARSTATUS_AGGREGATED or SCIP_VARSTATUS_NEGATED;
9774              */
9775             if( SCIPvarIsActive(vubvars[i]) && SCIPvarGetStatus(vubvars[i]) != SCIP_VARSTATUS_AGGREGATED && SCIPvarGetStatus(vubvars[i]) != SCIP_VARSTATUS_NEGATED )
9776             {
9777                SCIP_Real vbimplbound;
9778 
9779                vbimplbound = (implbound - vubconstants[i])/vubcoefs[i];
9780                if( vubcoefs[i] >= 0.0 )
9781                {
9782                   vbimplbound = adjustedLb(set, SCIPvarGetType(vubvars[i]), vbimplbound);
9783                   SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9784                         branchcand, eventqueue, varfixing, vubvars[i], SCIP_BOUNDTYPE_LOWER, vbimplbound, TRUE,
9785                         infeasible, nbdchgs, &added) );
9786                }
9787                else
9788                {
9789                   vbimplbound = adjustedUb(set, SCIPvarGetType(vubvars[i]), vbimplbound);
9790                   SCIP_CALL( varAddImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
9791                         branchcand, eventqueue, varfixing, vubvars[i], SCIP_BOUNDTYPE_UPPER, vbimplbound, TRUE,
9792                         infeasible, nbdchgs, &added) );
9793                }
9794                nvubvars = SCIPvboundsGetNVbds(implvar->vubs);
9795                i = MIN(i, nvubvars); /* some elements from the array could have been removed */
9796             }
9797             --i;
9798          }
9799       }
9800    }
9801 
9802    return SCIP_OKAY;
9803 }
9804 
9805 /** informs variable x about a globally valid variable lower bound x >= b*z + d with integer variable z;
9806  *  if z is binary, the corresponding valid implication for z is also added;
9807  *  improves the global bounds of the variable and the vlb variable if possible
9808  */
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)9809 SCIP_RETCODE SCIPvarAddVlb(
9810    SCIP_VAR*             var,                /**< problem variable */
9811    BMS_BLKMEM*           blkmem,             /**< block memory */
9812    SCIP_SET*             set,                /**< global SCIP settings */
9813    SCIP_STAT*            stat,               /**< problem statistics */
9814    SCIP_PROB*            transprob,          /**< transformed problem */
9815    SCIP_PROB*            origprob,           /**< original problem */
9816    SCIP_TREE*            tree,               /**< branch and bound tree if in solving stage */
9817    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
9818    SCIP_LP*              lp,                 /**< current LP data */
9819    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
9820    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
9821    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9822    SCIP_VAR*             vlbvar,             /**< variable z    in x >= b*z + d */
9823    SCIP_Real             vlbcoef,            /**< coefficient b in x >= b*z + d */
9824    SCIP_Real             vlbconstant,        /**< constant d    in x >= b*z + d */
9825    SCIP_Bool             transitive,         /**< should transitive closure of implication also be added? */
9826    SCIP_Bool*            infeasible,         /**< pointer to store whether an infeasibility was detected */
9827    int*                  nbdchgs             /**< pointer to store the number of performed bound changes, or NULL */
9828    )
9829 {
9830    assert(var != NULL);
9831    assert(set != NULL);
9832    assert(var->scip == set->scip);
9833    assert(SCIPvarGetType(vlbvar) != SCIP_VARTYPE_CONTINUOUS);
9834    assert(infeasible != NULL);
9835 
9836    SCIPsetDebugMsg(set, "adding variable lower bound <%s> >= %g<%s> + %g\n", SCIPvarGetName(var), vlbcoef, SCIPvarGetName(vlbvar), vlbconstant);
9837 
9838    *infeasible = FALSE;
9839    if( nbdchgs != NULL )
9840       *nbdchgs = 0;
9841 
9842    switch( SCIPvarGetStatus(var) )
9843    {
9844    case SCIP_VARSTATUS_ORIGINAL:
9845       assert(var->data.original.transvar != NULL);
9846       SCIP_CALL( SCIPvarAddVlb(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
9847             cliquetable, branchcand, eventqueue, vlbvar, vlbcoef, vlbconstant, transitive, infeasible, nbdchgs) );
9848       break;
9849 
9850    case SCIP_VARSTATUS_COLUMN:
9851    case SCIP_VARSTATUS_LOOSE:
9852    case SCIP_VARSTATUS_FIXED:
9853       /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */
9854       SCIP_CALL( SCIPvarGetProbvarSum(&vlbvar, set, &vlbcoef, &vlbconstant) );
9855       SCIPsetDebugMsg(set, " -> transformed to variable lower bound <%s> >= %g<%s> + %g\n", SCIPvarGetName(var), vlbcoef, SCIPvarGetName(vlbvar), vlbconstant);
9856 
9857       /* if the vlb coefficient is zero, just update the lower bound of the variable */
9858       if( SCIPsetIsZero(set, vlbcoef) )
9859       {
9860          if( SCIPsetIsFeasGT(set, vlbconstant, SCIPvarGetUbGlobal(var)) )
9861             *infeasible = TRUE;
9862          else if( SCIPsetIsFeasGT(set, vlbconstant, SCIPvarGetLbGlobal(var)) )
9863          {
9864             /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9865              * with the local bound, in this case we need to store the bound change as pending bound change
9866              */
9867             if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9868             {
9869                assert(tree != NULL);
9870                assert(transprob != NULL);
9871                assert(SCIPprobIsTransformed(transprob));
9872 
9873                SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9874                      tree, reopt, lp, branchcand, eventqueue, cliquetable, var, vlbconstant, SCIP_BOUNDTYPE_LOWER, FALSE) );
9875             }
9876             else
9877             {
9878                SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, vlbconstant) );
9879             }
9880 
9881             if( nbdchgs != NULL )
9882                (*nbdchgs)++;
9883          }
9884       }
9885       else if( var == vlbvar )
9886       {
9887          /* the variables cancels out, the variable bound constraint is either redundant or proves global infeasibility */
9888          if( SCIPsetIsEQ(set, vlbcoef, 1.0) )
9889          {
9890             if( SCIPsetIsPositive(set, vlbconstant) )
9891                *infeasible = TRUE;
9892             return SCIP_OKAY;
9893          }
9894          else
9895          {
9896             SCIP_Real lb = SCIPvarGetLbGlobal(var);
9897             SCIP_Real ub = SCIPvarGetUbGlobal(var);
9898 
9899             /* the variable bound constraint defines a new upper bound */
9900             if( SCIPsetIsGT(set, vlbcoef, 1.0) )
9901             {
9902                SCIP_Real newub = vlbconstant / (1.0 - vlbcoef);
9903 
9904                if( SCIPsetIsFeasLT(set, newub, lb) )
9905                {
9906                   *infeasible = TRUE;
9907                   return SCIP_OKAY;
9908                }
9909                else if( SCIPsetIsFeasLT(set, newub, ub) )
9910                {
9911                   /* bound might be adjusted due to integrality condition */
9912                   newub = adjustedUb(set, SCIPvarGetType(var), newub);
9913 
9914                   /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9915                    * with the local bound, in this case we need to store the bound change as pending bound change
9916                    */
9917                   if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9918                   {
9919                      assert(tree != NULL);
9920                      assert(transprob != NULL);
9921                      assert(SCIPprobIsTransformed(transprob));
9922 
9923                      SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9924                            tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newub, SCIP_BOUNDTYPE_UPPER, FALSE) );
9925                   }
9926                   else
9927                   {
9928                      SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newub) );
9929                   }
9930 
9931                   if( nbdchgs != NULL )
9932                      (*nbdchgs)++;
9933                }
9934             }
9935             /* the variable bound constraint defines a new lower bound */
9936             else
9937             {
9938                SCIP_Real newlb;
9939 
9940                assert(SCIPsetIsLT(set, vlbcoef, 1.0));
9941 
9942                newlb = vlbconstant / (1.0 - vlbcoef);
9943 
9944                if( SCIPsetIsFeasGT(set, newlb, ub) )
9945                {
9946                   *infeasible = TRUE;
9947                   return SCIP_OKAY;
9948                }
9949                else if( SCIPsetIsFeasGT(set, newlb, lb) )
9950                {
9951                   /* bound might be adjusted due to integrality condition */
9952                   newlb = adjustedLb(set, SCIPvarGetType(var), newlb);
9953 
9954                   /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
9955                    * with the local bound, in this case we need to store the bound change as pending bound change
9956                    */
9957                   if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
9958                   {
9959                      assert(tree != NULL);
9960                      assert(transprob != NULL);
9961                      assert(SCIPprobIsTransformed(transprob));
9962 
9963                      SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
9964                            tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
9965                   }
9966                   else
9967                   {
9968                      SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newlb) );
9969                   }
9970 
9971                   if( nbdchgs != NULL )
9972                      (*nbdchgs)++;
9973                }
9974             }
9975          }
9976       }
9977       else if( SCIPvarIsActive(vlbvar) )
9978       {
9979          SCIP_Real xlb;
9980          SCIP_Real xub;
9981          SCIP_Real zlb;
9982          SCIP_Real zub;
9983          SCIP_Real minvlb;
9984          SCIP_Real maxvlb;
9985 
9986          assert(SCIPvarGetStatus(vlbvar) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(vlbvar) == SCIP_VARSTATUS_COLUMN);
9987          assert(vlbcoef != 0.0);
9988 
9989          minvlb = -SCIPsetInfinity(set);
9990          maxvlb = SCIPsetInfinity(set);
9991 
9992          xlb = SCIPvarGetLbGlobal(var);
9993          xub = SCIPvarGetUbGlobal(var);
9994          zlb = SCIPvarGetLbGlobal(vlbvar);
9995          zub = SCIPvarGetUbGlobal(vlbvar);
9996 
9997          /* improve global bounds of vlb variable, and calculate minimal and maximal value of variable bound */
9998          if( vlbcoef >= 0.0 )
9999          {
10000             SCIP_Real newzub;
10001 
10002             if( !SCIPsetIsInfinity(set, xub) )
10003             {
10004                /* x >= b*z + d  ->  z <= (x-d)/b */
10005                newzub = (xub - vlbconstant)/vlbcoef;
10006 
10007                /* return if the new bound is less than -infinity */
10008                if( SCIPsetIsInfinity(set, REALABS(newzub)) )
10009                   return SCIP_OKAY;
10010 
10011                if( SCIPsetIsFeasLT(set, newzub, zlb) )
10012                {
10013                   *infeasible = TRUE;
10014                   return SCIP_OKAY;
10015                }
10016                if( SCIPsetIsFeasLT(set, newzub, zub) )
10017                {
10018                   /* bound might be adjusted due to integrality condition */
10019                   newzub = adjustedUb(set, SCIPvarGetType(vlbvar), newzub);
10020 
10021                   /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10022                    * with the local bound, in this case we need to store the bound change as pending bound change
10023                    */
10024                   if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10025                   {
10026                      assert(tree != NULL);
10027                      assert(transprob != NULL);
10028                      assert(SCIPprobIsTransformed(transprob));
10029 
10030                      SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10031                            tree, reopt, lp, branchcand, eventqueue, cliquetable, vlbvar, newzub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10032                   }
10033                   else
10034                   {
10035                      SCIP_CALL( SCIPvarChgUbGlobal(vlbvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzub) );
10036                   }
10037                   zub = newzub;
10038 
10039                   if( nbdchgs != NULL )
10040                      (*nbdchgs)++;
10041                }
10042                maxvlb = vlbcoef * zub + vlbconstant;
10043                if( !SCIPsetIsInfinity(set, -zlb) )
10044                   minvlb = vlbcoef * zlb + vlbconstant;
10045             }
10046             else
10047             {
10048                if( !SCIPsetIsInfinity(set, zub) )
10049                   maxvlb = vlbcoef * zub + vlbconstant;
10050                if( !SCIPsetIsInfinity(set, -zlb) )
10051                   minvlb = vlbcoef * zlb + vlbconstant;
10052             }
10053          }
10054          else
10055          {
10056             SCIP_Real newzlb;
10057 
10058             if( !SCIPsetIsInfinity(set, xub) )
10059             {
10060                /* x >= b*z + d  ->  z >= (x-d)/b */
10061                newzlb = (xub - vlbconstant)/vlbcoef;
10062 
10063                /* return if the new bound is larger than infinity */
10064                if( SCIPsetIsInfinity(set, REALABS(newzlb)) )
10065                   return SCIP_OKAY;
10066 
10067                if( SCIPsetIsFeasGT(set, newzlb, zub) )
10068                {
10069                   *infeasible = TRUE;
10070                   return SCIP_OKAY;
10071                }
10072                if( SCIPsetIsFeasGT(set, newzlb, zlb) )
10073                {
10074                   /* bound might be adjusted due to integrality condition */
10075                   newzlb = adjustedLb(set, SCIPvarGetType(vlbvar), newzlb);
10076 
10077                   /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10078                    * with the local bound, in this case we need to store the bound change as pending bound change
10079                    */
10080                   if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10081                   {
10082                      assert(tree != NULL);
10083                      assert(transprob != NULL);
10084                      assert(SCIPprobIsTransformed(transprob));
10085 
10086                      SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10087                            tree, reopt, lp, branchcand, eventqueue, cliquetable, vlbvar, newzlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10088                   }
10089                   else
10090                   {
10091                      SCIP_CALL( SCIPvarChgLbGlobal(vlbvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzlb) );
10092                   }
10093                   zlb = newzlb;
10094 
10095                   if( nbdchgs != NULL )
10096                      (*nbdchgs)++;
10097                }
10098                maxvlb = vlbcoef * zlb + vlbconstant;
10099                if( !SCIPsetIsInfinity(set, zub) )
10100                   minvlb = vlbcoef * zub + vlbconstant;
10101             }
10102             else
10103             {
10104                if( !SCIPsetIsInfinity(set, -zlb) )
10105                   maxvlb = vlbcoef * zlb + vlbconstant;
10106                if( !SCIPsetIsInfinity(set, zub) )
10107                   minvlb = vlbcoef * zub + vlbconstant;
10108             }
10109          }
10110          if( maxvlb < minvlb )
10111             maxvlb = minvlb;
10112 
10113          /* adjust bounds due to integrality of variable */
10114          minvlb = adjustedLb(set, SCIPvarGetType(var), minvlb);
10115          maxvlb = adjustedLb(set, SCIPvarGetType(var), maxvlb);
10116 
10117          /* check bounds for feasibility */
10118          if( SCIPsetIsFeasGT(set, minvlb, xub) || (var == vlbvar && SCIPsetIsEQ(set, vlbcoef, 1.0) && SCIPsetIsFeasPositive(set, vlbconstant))  )
10119          {
10120             *infeasible = TRUE;
10121             return SCIP_OKAY;
10122          }
10123          /* improve global lower bound of variable */
10124          if( SCIPsetIsFeasGT(set, minvlb, xlb) )
10125          {
10126             /* bound might be adjusted due to integrality condition */
10127             minvlb = adjustedLb(set, SCIPvarGetType(var), minvlb);
10128 
10129             /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10130              * with the local bound, in this case we need to store the bound change as pending bound change
10131              */
10132             if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10133             {
10134                assert(tree != NULL);
10135                assert(transprob != NULL);
10136                assert(SCIPprobIsTransformed(transprob));
10137 
10138                SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10139                      tree, reopt, lp, branchcand, eventqueue, cliquetable, var, minvlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10140             }
10141             else
10142             {
10143                SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, minvlb) );
10144             }
10145             xlb = minvlb;
10146 
10147             if( nbdchgs != NULL )
10148                (*nbdchgs)++;
10149          }
10150          minvlb = xlb;
10151 
10152          /* improve variable bound for binary z by moving the variable's global bound to the vlb constant */
10153          if( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY )
10154          {
10155             /* b > 0: x >= (maxvlb - minvlb) * z + minvlb
10156              * b < 0: x >= (minvlb - maxvlb) * z + maxvlb
10157              */
10158 
10159             assert(!SCIPsetIsInfinity(set, maxvlb) && !SCIPsetIsInfinity(set, -minvlb));
10160 
10161             if( vlbcoef >= 0.0 )
10162             {
10163                vlbcoef = maxvlb - minvlb;
10164                vlbconstant = minvlb;
10165             }
10166             else
10167             {
10168                vlbcoef = minvlb - maxvlb;
10169                vlbconstant = maxvlb;
10170             }
10171          }
10172 
10173          /* add variable bound to the variable bounds list */
10174          if( SCIPsetIsFeasGT(set, maxvlb, xlb) )
10175          {
10176             assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED);
10177             assert(!SCIPsetIsZero(set, vlbcoef));
10178 
10179             /* if one of the variables is binary, add the corresponding implication to the variable's implication
10180              * list, thereby also adding the variable bound (or implication) to the other variable
10181              */
10182             if( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY )
10183             {
10184                /* add corresponding implication:
10185                 *   b > 0, x >= b*z + d  <->  z == 1 -> x >= b+d
10186                 *   b < 0, x >= b*z + d  <->  z == 0 -> x >= d
10187                 */
10188                SCIP_CALL( varAddTransitiveImplic(vlbvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10189                      cliquetable, branchcand, eventqueue, (vlbcoef >= 0.0), var, SCIP_BOUNDTYPE_LOWER, maxvlb, transitive,
10190                      infeasible, nbdchgs) );
10191             }
10192             else if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
10193             {
10194                /* add corresponding implication:
10195                 *   b > 0, x >= b*z + d  <->  x == 0 -> z <= -d/b
10196                 *   b < 0, x >= b*z + d  <->  x == 0 -> z >= -d/b
10197                 */
10198                SCIP_Real implbound;
10199                implbound = -vlbconstant/vlbcoef;
10200 
10201                /* tighten the implication bound if the variable is integer */
10202                if( SCIPvarIsIntegral(vlbvar) )
10203                {
10204                   if( vlbcoef >= 0 )
10205                      implbound = SCIPsetFloor(set, implbound);
10206                   else
10207                      implbound = SCIPsetCeil(set, implbound);
10208                }
10209                SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10210                      cliquetable, branchcand, eventqueue, FALSE, vlbvar, (vlbcoef >= 0.0 ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER),
10211                      implbound, transitive, infeasible, nbdchgs) );
10212             }
10213             else
10214             {
10215                SCIP_CALL( varAddVbound(var, blkmem, set, eventqueue, SCIP_BOUNDTYPE_LOWER, vlbvar, vlbcoef, vlbconstant) );
10216             }
10217          }
10218       }
10219       break;
10220 
10221    case SCIP_VARSTATUS_AGGREGATED:
10222       /* x = a*y + c:  x >= b*z + d  <=>  a*y + c >= b*z + d  <=>  y >= b/a * z + (d-c)/a, if a > 0
10223        *                                                           y <= b/a * z + (d-c)/a, if a < 0
10224        */
10225       assert(var->data.aggregate.var != NULL);
10226       if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
10227       {
10228          /* a > 0 -> add variable lower bound */
10229          SCIP_CALL( SCIPvarAddVlb(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10230                cliquetable, branchcand, eventqueue, vlbvar, vlbcoef/var->data.aggregate.scalar,
10231                (vlbconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10232       }
10233       else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
10234       {
10235          /* a < 0 -> add variable upper bound */
10236          SCIP_CALL( SCIPvarAddVub(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10237                cliquetable, branchcand, eventqueue, vlbvar, vlbcoef/var->data.aggregate.scalar,
10238                (vlbconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10239       }
10240       else
10241       {
10242          SCIPerrorMessage("scalar is zero in aggregation\n");
10243          return SCIP_INVALIDDATA;
10244       }
10245       break;
10246 
10247    case SCIP_VARSTATUS_MULTAGGR:
10248       /* nothing to do here */
10249       break;
10250 
10251    case SCIP_VARSTATUS_NEGATED:
10252       /* x = offset - x':  x >= b*z + d  <=>  offset - x' >= b*z + d  <=>  x' <= -b*z + (offset-d) */
10253       assert(var->negatedvar != NULL);
10254       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
10255       assert(var->negatedvar->negatedvar == var);
10256       SCIP_CALL( SCIPvarAddVub(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10257             branchcand, eventqueue, vlbvar, -vlbcoef, var->data.negate.constant - vlbconstant, transitive, infeasible,
10258             nbdchgs) );
10259       break;
10260 
10261    default:
10262       SCIPerrorMessage("unknown variable status\n");
10263       return SCIP_INVALIDDATA;
10264    }
10265 
10266    return SCIP_OKAY;
10267 }
10268 
10269 /** informs variable x about a globally valid variable upper bound x <= b*z + d with integer variable z;
10270  *  if z is binary, the corresponding valid implication for z is also added;
10271  *  updates the global bounds of the variable and the vub variable correspondingly
10272  */
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)10273 SCIP_RETCODE SCIPvarAddVub(
10274    SCIP_VAR*             var,                /**< problem variable */
10275    BMS_BLKMEM*           blkmem,             /**< block memory */
10276    SCIP_SET*             set,                /**< global SCIP settings */
10277    SCIP_STAT*            stat,               /**< problem statistics */
10278    SCIP_PROB*            transprob,          /**< transformed problem */
10279    SCIP_PROB*            origprob,           /**< original problem */
10280    SCIP_TREE*            tree,               /**< branch and bound tree if in solving stage */
10281    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
10282    SCIP_LP*              lp,                 /**< current LP data */
10283    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
10284    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
10285    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
10286    SCIP_VAR*             vubvar,             /**< variable z    in x <= b*z + d */
10287    SCIP_Real             vubcoef,            /**< coefficient b in x <= b*z + d */
10288    SCIP_Real             vubconstant,        /**< constant d    in x <= b*z + d */
10289    SCIP_Bool             transitive,         /**< should transitive closure of implication also be added? */
10290    SCIP_Bool*            infeasible,         /**< pointer to store whether an infeasibility was detected */
10291    int*                  nbdchgs             /**< pointer to store the number of performed bound changes, or NULL */
10292    )
10293 {
10294    assert(var != NULL);
10295    assert(set != NULL);
10296    assert(var->scip == set->scip);
10297    assert(SCIPvarGetType(vubvar) != SCIP_VARTYPE_CONTINUOUS);
10298    assert(infeasible != NULL);
10299 
10300    SCIPsetDebugMsg(set, "adding variable upper bound <%s> <= %g<%s> + %g\n", SCIPvarGetName(var), vubcoef, SCIPvarGetName(vubvar), vubconstant);
10301 
10302    *infeasible = FALSE;
10303    if( nbdchgs != NULL )
10304       *nbdchgs = 0;
10305 
10306    switch( SCIPvarGetStatus(var) )
10307    {
10308    case SCIP_VARSTATUS_ORIGINAL:
10309       assert(var->data.original.transvar != NULL);
10310       SCIP_CALL( SCIPvarAddVub(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10311             cliquetable, branchcand, eventqueue, vubvar, vubcoef, vubconstant, transitive, infeasible, nbdchgs) );
10312       break;
10313 
10314    case SCIP_VARSTATUS_COLUMN:
10315    case SCIP_VARSTATUS_LOOSE:
10316    case SCIP_VARSTATUS_FIXED:
10317       /* transform b*z + d into the corresponding sum after transforming z to an active problem variable */
10318       SCIP_CALL( SCIPvarGetProbvarSum(&vubvar, set, &vubcoef, &vubconstant) );
10319       SCIPsetDebugMsg(set, " -> transformed to variable upper bound <%s> <= %g<%s> + %g\n",
10320          SCIPvarGetName(var), vubcoef, SCIPvarGetName(vubvar), vubconstant);
10321 
10322       /* if the vub coefficient is zero, just update the upper bound of the variable */
10323       if( SCIPsetIsZero(set, vubcoef) )
10324       {
10325          if( SCIPsetIsFeasLT(set, vubconstant, SCIPvarGetLbGlobal(var)) )
10326             *infeasible = TRUE;
10327          else if( SCIPsetIsFeasLT(set, vubconstant, SCIPvarGetUbGlobal(var)) )
10328          {
10329             /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10330              * with the local bound, in this case we need to store the bound change as pending bound change
10331              */
10332             if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10333             {
10334                assert(tree != NULL);
10335                assert(transprob != NULL);
10336                assert(SCIPprobIsTransformed(transprob));
10337 
10338                SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10339                      tree, reopt, lp, branchcand, eventqueue, cliquetable, var, vubconstant, SCIP_BOUNDTYPE_UPPER, FALSE) );
10340             }
10341             else
10342             {
10343                SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, vubconstant) );
10344             }
10345 
10346             if( nbdchgs != NULL )
10347                (*nbdchgs)++;
10348          }
10349       }
10350       else if( var == vubvar )
10351       {
10352          /* the variables cancels out, the variable bound constraint is either redundant or proves global infeasibility */
10353          if( SCIPsetIsEQ(set, vubcoef, 1.0) )
10354          {
10355             if( SCIPsetIsNegative(set, vubconstant) )
10356                *infeasible = TRUE;
10357             return SCIP_OKAY;
10358          }
10359          else
10360          {
10361             SCIP_Real lb = SCIPvarGetLbGlobal(var);
10362             SCIP_Real ub = SCIPvarGetUbGlobal(var);
10363 
10364             /* the variable bound constraint defines a new lower bound */
10365             if( SCIPsetIsGT(set, vubcoef, 1.0) )
10366             {
10367                SCIP_Real newlb = vubconstant / (1.0 - vubcoef);
10368 
10369                if( SCIPsetIsFeasGT(set, newlb, ub) )
10370                {
10371                   *infeasible = TRUE;
10372                   return SCIP_OKAY;
10373                }
10374                else if( SCIPsetIsFeasGT(set, newlb, lb) )
10375                {
10376                   /* bound might be adjusted due to integrality condition */
10377                   newlb = adjustedLb(set, SCIPvarGetType(var), newlb);
10378 
10379                   /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10380                    * with the local bound, in this case we need to store the bound change as pending bound change
10381                    */
10382                   if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10383                   {
10384                      assert(tree != NULL);
10385                      assert(transprob != NULL);
10386                      assert(SCIPprobIsTransformed(transprob));
10387 
10388                      SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10389                            tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10390                   }
10391                   else
10392                   {
10393                      SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newlb) );
10394                   }
10395 
10396                   if( nbdchgs != NULL )
10397                      (*nbdchgs)++;
10398                }
10399             }
10400             /* the variable bound constraint defines a new upper bound */
10401             else
10402             {
10403                SCIP_Real newub;
10404 
10405                assert(SCIPsetIsLT(set, vubcoef, 1.0));
10406 
10407                newub = vubconstant / (1.0 - vubcoef);
10408 
10409                if( SCIPsetIsFeasLT(set, newub, lb) )
10410                {
10411                   *infeasible = TRUE;
10412                   return SCIP_OKAY;
10413                }
10414                else if( SCIPsetIsFeasLT(set, newub, ub) )
10415                {
10416                   /* bound might be adjusted due to integrality condition */
10417                   newub = adjustedUb(set, SCIPvarGetType(var), newub);
10418 
10419                   /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10420                    * with the local bound, in this case we need to store the bound change as pending bound change
10421                    */
10422                   if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10423                   {
10424                      assert(tree != NULL);
10425                      assert(transprob != NULL);
10426                      assert(SCIPprobIsTransformed(transprob));
10427 
10428                      SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10429                            tree, reopt, lp, branchcand, eventqueue, cliquetable, var, newub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10430                   }
10431                   else
10432                   {
10433                      SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newub) );
10434                   }
10435 
10436                   if( nbdchgs != NULL )
10437                      (*nbdchgs)++;
10438                }
10439             }
10440          }
10441       }
10442       else if( SCIPvarIsActive(vubvar) )
10443       {
10444          SCIP_Real xlb;
10445          SCIP_Real xub;
10446          SCIP_Real zlb;
10447          SCIP_Real zub;
10448          SCIP_Real minvub;
10449          SCIP_Real maxvub;
10450 
10451          assert(SCIPvarGetStatus(vubvar) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(vubvar) == SCIP_VARSTATUS_COLUMN);
10452          assert(vubcoef != 0.0);
10453 
10454          minvub = -SCIPsetInfinity(set);
10455          maxvub = SCIPsetInfinity(set);
10456 
10457          xlb = SCIPvarGetLbGlobal(var);
10458          xub = SCIPvarGetUbGlobal(var);
10459          zlb = SCIPvarGetLbGlobal(vubvar);
10460          zub = SCIPvarGetUbGlobal(vubvar);
10461 
10462          /* improve global bounds of vub variable, and calculate minimal and maximal value of variable bound */
10463          if( vubcoef >= 0.0 )
10464          {
10465             SCIP_Real newzlb;
10466 
10467             if( !SCIPsetIsInfinity(set, -xlb) )
10468             {
10469                /* x <= b*z + d  ->  z >= (x-d)/b */
10470                newzlb = (xlb - vubconstant)/vubcoef;
10471                if( SCIPsetIsFeasGT(set, newzlb, zub) )
10472                {
10473                   *infeasible = TRUE;
10474                   return SCIP_OKAY;
10475                }
10476                if( SCIPsetIsFeasGT(set, newzlb, zlb) )
10477                {
10478                   /* bound might be adjusted due to integrality condition */
10479                   newzlb = adjustedLb(set, SCIPvarGetType(vubvar), newzlb);
10480 
10481                   /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10482                    * with the local bound, in this case we need to store the bound change as pending bound change
10483                    */
10484                   if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10485                   {
10486                      assert(tree != NULL);
10487                      assert(transprob != NULL);
10488                      assert(SCIPprobIsTransformed(transprob));
10489 
10490                      SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10491                            tree, reopt, lp, branchcand, eventqueue, cliquetable, vubvar, newzlb, SCIP_BOUNDTYPE_LOWER, FALSE) );
10492                   }
10493                   else
10494                   {
10495                      SCIP_CALL( SCIPvarChgLbGlobal(vubvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzlb) );
10496                   }
10497                   zlb = newzlb;
10498 
10499                   if( nbdchgs != NULL )
10500                      (*nbdchgs)++;
10501                }
10502                minvub = vubcoef * zlb + vubconstant;
10503                if( !SCIPsetIsInfinity(set, zub) )
10504                   maxvub = vubcoef * zub + vubconstant;
10505             }
10506             else
10507             {
10508                if( !SCIPsetIsInfinity(set, zub) )
10509                   maxvub = vubcoef * zub + vubconstant;
10510                if( !SCIPsetIsInfinity(set, -zlb) )
10511                   minvub = vubcoef * zlb + vubconstant;
10512             }
10513          }
10514          else
10515          {
10516             SCIP_Real newzub;
10517 
10518             if( !SCIPsetIsInfinity(set, -xlb) )
10519             {
10520                /* x <= b*z + d  ->  z <= (x-d)/b */
10521                newzub = (xlb - vubconstant)/vubcoef;
10522                if( SCIPsetIsFeasLT(set, newzub, zlb) )
10523                {
10524                   *infeasible = TRUE;
10525                   return SCIP_OKAY;
10526                }
10527                if( SCIPsetIsFeasLT(set, newzub, zub) )
10528                {
10529                   /* bound might be adjusted due to integrality condition */
10530                   newzub = adjustedUb(set, SCIPvarGetType(vubvar), newzub);
10531 
10532                   /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10533                    * with the local bound, in this case we need to store the bound change as pending bound change
10534                    */
10535                   if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10536                   {
10537                      assert(tree != NULL);
10538                      assert(transprob != NULL);
10539                      assert(SCIPprobIsTransformed(transprob));
10540 
10541                      SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10542                            tree, reopt, lp, branchcand, eventqueue, cliquetable, vubvar, newzub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10543                   }
10544                   else
10545                   {
10546                      SCIP_CALL( SCIPvarChgUbGlobal(vubvar, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newzub) );
10547                   }
10548                   zub = newzub;
10549 
10550                   if( nbdchgs != NULL )
10551                      (*nbdchgs)++;
10552                }
10553                minvub = vubcoef * zub + vubconstant;
10554                if( !SCIPsetIsInfinity(set, -zlb) )
10555                   maxvub = vubcoef * zlb + vubconstant;
10556             }
10557             else
10558             {
10559                if( !SCIPsetIsInfinity(set, zub) )
10560                   minvub = vubcoef * zub + vubconstant;
10561                if( !SCIPsetIsInfinity(set, -zlb) )
10562                   maxvub = vubcoef * zlb + vubconstant;
10563             }
10564          }
10565          if( minvub > maxvub )
10566             minvub = maxvub;
10567 
10568          /* adjust bounds due to integrality of vub variable */
10569          minvub = adjustedUb(set, SCIPvarGetType(var), minvub);
10570          maxvub = adjustedUb(set, SCIPvarGetType(var), maxvub);
10571 
10572          /* check bounds for feasibility */
10573          if( SCIPsetIsFeasLT(set, maxvub, xlb) || (var == vubvar && SCIPsetIsEQ(set, vubcoef, 1.0) && SCIPsetIsFeasNegative(set, vubconstant))  )
10574          {
10575             *infeasible = TRUE;
10576             return SCIP_OKAY;
10577          }
10578 
10579          /* improve global upper bound of variable */
10580          if( SCIPsetIsFeasLT(set, maxvub, xub) )
10581          {
10582             /* bound might be adjusted due to integrality condition */
10583             maxvub = adjustedUb(set, SCIPvarGetType(var), maxvub);
10584 
10585             /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10586              * with the local bound, in this case we need to store the bound change as pending bound change
10587              */
10588             if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10589             {
10590                assert(tree != NULL);
10591                assert(transprob != NULL);
10592                assert(SCIPprobIsTransformed(transprob));
10593 
10594                SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10595                      tree, reopt, lp, branchcand, eventqueue, cliquetable, var, maxvub, SCIP_BOUNDTYPE_UPPER, FALSE) );
10596             }
10597             else
10598             {
10599                SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, maxvub) );
10600             }
10601             xub = maxvub;
10602 
10603             if( nbdchgs != NULL )
10604                (*nbdchgs)++;
10605          }
10606          maxvub = xub;
10607 
10608          /* improve variable bound for binary z by moving the variable's global bound to the vub constant */
10609          if( SCIPvarIsBinary(vubvar) )
10610          {
10611             /* b > 0: x <= (maxvub - minvub) * z + minvub
10612              * b < 0: x <= (minvub - maxvub) * z + maxvub
10613              */
10614 
10615             assert(!SCIPsetIsInfinity(set, maxvub) && !SCIPsetIsInfinity(set, -minvub));
10616 
10617             if( vubcoef >= 0.0 )
10618             {
10619                vubcoef = maxvub - minvub;
10620                vubconstant = minvub;
10621             }
10622             else
10623             {
10624                vubcoef = minvub - maxvub;
10625                vubconstant = maxvub;
10626             }
10627          }
10628 
10629          /* add variable bound to the variable bounds list */
10630          if( SCIPsetIsFeasLT(set, minvub, xub) )
10631          {
10632             assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED);
10633             assert(!SCIPsetIsZero(set, vubcoef));
10634 
10635             /* if one of the variables is binary, add the corresponding implication to the variable's implication
10636              * list, thereby also adding the variable bound (or implication) to the other variable
10637              */
10638             if( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY )
10639             {
10640                /* add corresponding implication:
10641                 *   b > 0, x <= b*z + d  <->  z == 0 -> x <= d
10642                 *   b < 0, x <= b*z + d  <->  z == 1 -> x <= b+d
10643                 */
10644                SCIP_CALL( varAddTransitiveImplic(vubvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10645                      cliquetable, branchcand, eventqueue, (vubcoef < 0.0), var, SCIP_BOUNDTYPE_UPPER, minvub, transitive,
10646                      infeasible, nbdchgs) );
10647             }
10648             else if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
10649             {
10650                /* add corresponding implication:
10651                 *   b > 0, x <= b*z + d  <->  x == 1 -> z >= (1-d)/b
10652                 *   b < 0, x <= b*z + d  <->  x == 1 -> z <= (1-d)/b
10653                 */
10654                SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10655                      cliquetable, branchcand, eventqueue, TRUE, vubvar, (vubcoef >= 0.0 ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER),
10656                      (1.0-vubconstant)/vubcoef, transitive, infeasible, nbdchgs) );
10657             }
10658             else
10659             {
10660                SCIP_CALL( varAddVbound(var, blkmem, set, eventqueue, SCIP_BOUNDTYPE_UPPER, vubvar, vubcoef, vubconstant) );
10661             }
10662          }
10663       }
10664       break;
10665 
10666    case SCIP_VARSTATUS_AGGREGATED:
10667       /* x = a*y + c:  x <= b*z + d  <=>  a*y + c <= b*z + d  <=>  y <= b/a * z + (d-c)/a, if a > 0
10668        *                                                           y >= b/a * z + (d-c)/a, if a < 0
10669        */
10670       assert(var->data.aggregate.var != NULL);
10671       if( SCIPsetIsPositive(set, var->data.aggregate.scalar) )
10672       {
10673          /* a > 0 -> add variable upper bound */
10674          SCIP_CALL( SCIPvarAddVub(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10675                cliquetable, branchcand, eventqueue, vubvar, vubcoef/var->data.aggregate.scalar,
10676                (vubconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10677       }
10678       else if( SCIPsetIsNegative(set, var->data.aggregate.scalar) )
10679       {
10680          /* a < 0 -> add variable lower bound */
10681          SCIP_CALL( SCIPvarAddVlb(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10682                cliquetable, branchcand, eventqueue, vubvar, vubcoef/var->data.aggregate.scalar,
10683                (vubconstant - var->data.aggregate.constant)/var->data.aggregate.scalar, transitive, infeasible, nbdchgs) );
10684       }
10685       else
10686       {
10687          SCIPerrorMessage("scalar is zero in aggregation\n");
10688          return SCIP_INVALIDDATA;
10689       }
10690       break;
10691 
10692    case SCIP_VARSTATUS_MULTAGGR:
10693       /* nothing to do here */
10694       break;
10695 
10696    case SCIP_VARSTATUS_NEGATED:
10697       /* x = offset - x':  x <= b*z + d  <=>  offset - x' <= b*z + d  <=>  x' >= -b*z + (offset-d) */
10698       assert(var->negatedvar != NULL);
10699       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
10700       assert(var->negatedvar->negatedvar == var);
10701       SCIP_CALL( SCIPvarAddVlb(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10702             branchcand, eventqueue, vubvar, -vubcoef, var->data.negate.constant - vubconstant, transitive, infeasible,
10703             nbdchgs) );
10704       break;
10705 
10706    default:
10707       SCIPerrorMessage("unknown variable status\n");
10708       return SCIP_INVALIDDATA;
10709    }
10710 
10711    return SCIP_OKAY;
10712 }
10713 
10714 /** informs binary variable x about a globally valid implication:  x == 0 or x == 1  ==>  y <= b  or  y >= b;
10715  *  also adds the corresponding implication or variable bound to the implied variable;
10716  *  if the implication is conflicting, the variable is fixed to the opposite value;
10717  *  if the variable is already fixed to the given value, the implication is performed immediately;
10718  *  if the implication is redundant with respect to the variables' global bounds, it is ignored
10719  */
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)10720 SCIP_RETCODE SCIPvarAddImplic(
10721    SCIP_VAR*             var,                /**< problem variable  */
10722    BMS_BLKMEM*           blkmem,             /**< block memory */
10723    SCIP_SET*             set,                /**< global SCIP settings */
10724    SCIP_STAT*            stat,               /**< problem statistics */
10725    SCIP_PROB*            transprob,          /**< transformed problem */
10726    SCIP_PROB*            origprob,           /**< original problem */
10727    SCIP_TREE*            tree,               /**< branch and bound tree if in solving stage */
10728    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
10729    SCIP_LP*              lp,                 /**< current LP data */
10730    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
10731    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
10732    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
10733    SCIP_Bool             varfixing,          /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
10734    SCIP_VAR*             implvar,            /**< variable y in implication y <= b or y >= b */
10735    SCIP_BOUNDTYPE        impltype,           /**< type       of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
10736    SCIP_Real             implbound,          /**< bound b    in implication y <= b or y >= b */
10737    SCIP_Bool             transitive,         /**< should transitive closure of implication also be added? */
10738    SCIP_Bool*            infeasible,         /**< pointer to store whether an infeasibility was detected */
10739    int*                  nbdchgs             /**< pointer to store the number of performed bound changes, or NULL */
10740    )
10741 {
10742    assert(var != NULL);
10743    assert(set != NULL);
10744    assert(var->scip == set->scip);
10745    assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
10746    assert(infeasible != NULL);
10747 
10748    *infeasible = FALSE;
10749    if( nbdchgs != NULL )
10750       *nbdchgs = 0;
10751 
10752    switch( SCIPvarGetStatus(var) )
10753    {
10754    case SCIP_VARSTATUS_ORIGINAL:
10755       assert(var->data.original.transvar != NULL);
10756       SCIP_CALL( SCIPvarAddImplic(var->data.original.transvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10757             cliquetable, branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible,
10758             nbdchgs) );
10759       break;
10760 
10761    case SCIP_VARSTATUS_COLUMN:
10762    case SCIP_VARSTATUS_LOOSE:
10763       /* if the variable is fixed (although it has no FIXED status), and varfixing corresponds to the fixed value of
10764        * the variable, the implication can be applied directly;
10765        * otherwise, add implication to the implications list (and add inverse of implication to the implied variable)
10766        */
10767       if( SCIPvarGetLbGlobal(var) > 0.5 || SCIPvarGetUbGlobal(var) < 0.5 )
10768       {
10769          if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
10770          {
10771             SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
10772                   cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) );
10773          }
10774       }
10775       else
10776       {
10777          SCIP_CALL( SCIPvarGetProbvarBound(&implvar, &implbound, &impltype) );
10778          SCIPvarAdjustBd(implvar, set, impltype, &implbound);
10779          if( SCIPvarIsActive(implvar) || SCIPvarGetStatus(implvar) == SCIP_VARSTATUS_FIXED )
10780          {
10781             SCIP_CALL( varAddTransitiveImplic(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10782                   branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible, nbdchgs) );
10783          }
10784       }
10785       break;
10786 
10787    case SCIP_VARSTATUS_FIXED:
10788       /* if varfixing corresponds to the fixed value of the variable, the implication can be applied directly */
10789       if( varfixing == (SCIPvarGetLbGlobal(var) > 0.5) )
10790       {
10791          SCIP_CALL( applyImplic(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
10792                cliquetable, implvar, impltype, implbound, infeasible, nbdchgs) );
10793       }
10794       break;
10795 
10796    case SCIP_VARSTATUS_AGGREGATED:
10797       /* implication added for x == 1:
10798        *   x == 1 && x =  1*z + 0  ==>  y <= b or y >= b    <==>    z >= 1  ==>  y <= b or y >= b
10799        *   x == 1 && x = -1*z + 1  ==>  y <= b or y >= b    <==>    z <= 0  ==>  y <= b or y >= b
10800        * implication added for x == 0:
10801        *   x == 0 && x =  1*z + 0  ==>  y <= b or y >= b    <==>    z <= 0  ==>  y <= b or y >= b
10802        *   x == 0 && x = -1*z + 1  ==>  y <= b or y >= b    <==>    z >= 1  ==>  y <= b or y >= b
10803        *
10804        * use only binary variables z
10805        */
10806       assert(var->data.aggregate.var != NULL);
10807       if( SCIPvarIsBinary(var->data.aggregate.var) )
10808       {
10809          assert( (SCIPsetIsEQ(set, var->data.aggregate.scalar, 1.0) && SCIPsetIsZero(set, var->data.aggregate.constant))
10810             || (SCIPsetIsEQ(set, var->data.aggregate.scalar, -1.0) && SCIPsetIsEQ(set, var->data.aggregate.constant, 1.0)) );
10811 
10812          if( var->data.aggregate.scalar > 0 )
10813          {
10814             SCIP_CALL( SCIPvarAddImplic(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10815                   cliquetable, branchcand, eventqueue, varfixing, implvar, impltype, implbound, transitive, infeasible,
10816                   nbdchgs) );
10817          }
10818          else
10819          {
10820             SCIP_CALL( SCIPvarAddImplic(var->data.aggregate.var, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10821                   cliquetable, branchcand, eventqueue, !varfixing, implvar, impltype, implbound, transitive, infeasible,
10822                   nbdchgs) );
10823          }
10824       }
10825       break;
10826 
10827    case SCIP_VARSTATUS_MULTAGGR:
10828       /* nothing to do here */
10829       break;
10830 
10831    case SCIP_VARSTATUS_NEGATED:
10832       /* implication added for x == 1:
10833        *   x == 1 && x = -1*z + 1  ==>  y <= b or y >= b    <==>    z <= 0  ==>  y <= b or y >= b
10834        * implication added for x == 0:
10835        *   x == 0 && x = -1*z + 1  ==>  y <= b or y >= b    <==>    z >= 1  ==>  y <= b or y >= b
10836        */
10837       assert(var->negatedvar != NULL);
10838       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
10839       assert(var->negatedvar->negatedvar == var);
10840       assert(SCIPvarIsBinary(var->negatedvar));
10841 
10842       if( SCIPvarGetType(var->negatedvar) == SCIP_VARTYPE_BINARY )
10843       {
10844          SCIP_CALL( SCIPvarAddImplic(var->negatedvar, blkmem, set, stat,  transprob, origprob, tree, reopt, lp,
10845                cliquetable, branchcand, eventqueue, !varfixing, implvar, impltype, implbound, transitive, infeasible, nbdchgs) );
10846       }
10847       /* in case one both variables are not of binary type we have to add the implication as variable bounds */
10848       else
10849       {
10850          /* if the implied variable is of binary type exchange the variables */
10851          if( SCIPvarGetType(implvar) == SCIP_VARTYPE_BINARY )
10852          {
10853             SCIP_CALL( SCIPvarAddImplic(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10854                   branchcand, eventqueue, (impltype == SCIP_BOUNDTYPE_UPPER) ? TRUE : FALSE, var->negatedvar,
10855                   varfixing ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER, varfixing ? 1.0 : 0.0, transitive,
10856                   infeasible, nbdchgs) );
10857          }
10858          else
10859          {
10860             /* both variables are not of binary type but are implicit binary; in that case we can only add this
10861              * implication as variable bounds
10862              */
10863 
10864             /* add variable lower bound on the negation of var */
10865             if( varfixing )
10866             {
10867                /* (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
10868                 * as variable lower bound
10869                 */
10870                SCIP_CALL( SCIPvarAddVlb(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10871                      cliquetable, branchcand, eventqueue, implvar, (impltype == SCIP_BOUNDTYPE_UPPER) ? 1.0 : -1.0,
10872                      (impltype == SCIP_BOUNDTYPE_UPPER) ? 0.0 : 1.0, transitive, infeasible, nbdchgs) );
10873             }
10874             else
10875             {
10876                /* (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
10877                 * as variable upper bound
10878                 */
10879                SCIP_CALL( SCIPvarAddVub(var->negatedvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
10880                      cliquetable, branchcand, eventqueue, implvar, (impltype == SCIP_BOUNDTYPE_UPPER) ? -1.0 : 1.0,
10881                      (impltype == SCIP_BOUNDTYPE_UPPER) ? 1.0 : 0.0, transitive, infeasible, nbdchgs) );
10882             }
10883 
10884             /* add variable bound on implvar */
10885             if( impltype == SCIP_BOUNDTYPE_UPPER )
10886             {
10887                /* (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
10888                 * as variable upper bound
10889                 */
10890                SCIP_CALL( SCIPvarAddVub(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10891                      branchcand, eventqueue, var->negatedvar, (varfixing) ? 1.0 : -1.0,
10892                      (varfixing) ? 0.0 : 1.0, transitive, infeasible, nbdchgs) );
10893             }
10894             else
10895             {
10896                /* (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
10897                 * as variable upper bound
10898                 */
10899                SCIP_CALL( SCIPvarAddVlb(implvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, cliquetable,
10900                      branchcand, eventqueue, var->negatedvar, (varfixing) ? -1.0 : 1.0, (varfixing) ? 1.0 : 0.0,
10901                      transitive, infeasible, nbdchgs) );
10902             }
10903          }
10904       }
10905       break;
10906 
10907    default:
10908       SCIPerrorMessage("unknown variable status\n");
10909       return SCIP_INVALIDDATA;
10910    }
10911 
10912    return SCIP_OKAY;
10913 }
10914 
10915 /** returns whether there is an implication x == varfixing -> y <= b or y >= b in the implication graph;
10916  *  implications that are represented as cliques in the clique table are not regarded (use SCIPvarsHaveCommonClique());
10917  *  both variables must be active, variable x must be binary
10918  */
SCIPvarHasImplic(SCIP_VAR * var,SCIP_Bool varfixing,SCIP_VAR * implvar,SCIP_BOUNDTYPE impltype)10919 SCIP_Bool SCIPvarHasImplic(
10920    SCIP_VAR*             var,                /**< problem variable x */
10921    SCIP_Bool             varfixing,          /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
10922    SCIP_VAR*             implvar,            /**< variable y to search for */
10923    SCIP_BOUNDTYPE        impltype            /**< type of implication y <=/>= b to search for */
10924    )
10925 {
10926    assert(var != NULL);
10927    assert(implvar != NULL);
10928    assert(SCIPvarIsActive(var));
10929    assert(SCIPvarIsActive(implvar));
10930    assert(SCIPvarIsBinary(var));
10931 
10932    return var->implics != NULL && SCIPimplicsContainsImpl(var->implics, varfixing, implvar, impltype);
10933 }
10934 
10935 /** returns whether there is an implication x == varfixing -> y == implvarfixing in the implication graph;
10936  *  implications that are represented as cliques in the clique table are not regarded (use SCIPvarsHaveCommonClique());
10937  *  both variables must be active binary variables
10938  */
SCIPvarHasBinaryImplic(SCIP_VAR * var,SCIP_Bool varfixing,SCIP_VAR * implvar,SCIP_Bool implvarfixing)10939 SCIP_Bool SCIPvarHasBinaryImplic(
10940    SCIP_VAR*             var,                /**< problem variable x */
10941    SCIP_Bool             varfixing,          /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
10942    SCIP_VAR*             implvar,            /**< variable y to search for */
10943    SCIP_Bool             implvarfixing       /**< value of the implied variable to search for */
10944    )
10945 {
10946    assert(SCIPvarIsBinary(implvar));
10947 
10948    return SCIPvarHasImplic(var, varfixing, implvar, implvarfixing ? SCIP_BOUNDTYPE_LOWER : SCIP_BOUNDTYPE_UPPER);
10949 }
10950 
10951 /** fixes the bounds of a binary variable to the given value, counting bound changes and detecting infeasibility */
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)10952 SCIP_RETCODE SCIPvarFixBinary(
10953    SCIP_VAR*             var,                /**< problem variable */
10954    BMS_BLKMEM*           blkmem,             /**< block memory */
10955    SCIP_SET*             set,                /**< global SCIP settings */
10956    SCIP_STAT*            stat,               /**< problem statistics */
10957    SCIP_PROB*            transprob,          /**< transformed problem */
10958    SCIP_PROB*            origprob,           /**< original problem */
10959    SCIP_TREE*            tree,               /**< branch and bound tree if in solving stage */
10960    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
10961    SCIP_LP*              lp,                 /**< current LP data */
10962    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
10963    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
10964    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
10965    SCIP_Bool             value,              /**< value to fix variable to */
10966    SCIP_Bool*            infeasible,         /**< pointer to store whether an infeasibility was detected */
10967    int*                  nbdchgs             /**< pointer to count the number of performed bound changes, or NULL */
10968    )
10969 {
10970    assert(var != NULL);
10971    assert(set != NULL);
10972    assert(var->scip == set->scip);
10973    assert(infeasible != NULL);
10974 
10975    *infeasible = FALSE;
10976 
10977    if( value == FALSE )
10978    {
10979       if( var->glbdom.lb > 0.5 )
10980          *infeasible = TRUE;
10981       else if( var->glbdom.ub > 0.5 )
10982       {
10983          /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
10984           * with the local bound, in this case we need to store the bound change as pending bound change
10985           */
10986          if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
10987          {
10988             assert(tree != NULL);
10989             assert(transprob != NULL);
10990             assert(SCIPprobIsTransformed(transprob));
10991 
10992             SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
10993                   tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) );
10994          }
10995          else
10996          {
10997             SCIP_CALL( SCIPvarChgUbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 0.0) );
10998          }
10999 
11000          if( nbdchgs != NULL )
11001             (*nbdchgs)++;
11002       }
11003    }
11004    else
11005    {
11006       if( var->glbdom.ub < 0.5 )
11007          *infeasible = TRUE;
11008       else if( var->glbdom.lb < 0.5 )
11009       {
11010          /* during solving stage it can happen that the global bound change cannot be applied directly because it conflicts
11011           * with the local bound, in this case we need to store the bound change as pending bound change
11012           */
11013          if( SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING )
11014          {
11015             assert(tree != NULL);
11016             assert(transprob != NULL);
11017             assert(SCIPprobIsTransformed(transprob));
11018 
11019             SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob,
11020                   tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 1.0, SCIP_BOUNDTYPE_LOWER, FALSE) );
11021          }
11022          else
11023          {
11024             SCIP_CALL( SCIPvarChgLbGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, 1.0) );
11025          }
11026 
11027          if( nbdchgs != NULL )
11028             (*nbdchgs)++;
11029       }
11030    }
11031 
11032    /* during presolving, the variable should have been removed immediately from all its cliques */
11033    assert(SCIPsetGetStage(set) >= SCIP_STAGE_SOLVING || var->cliquelist == NULL);
11034 
11035    return SCIP_OKAY;
11036 }
11037 
11038 /** adds the variable to the given clique and updates the list of cliques the binary variable is member of;
11039  *  if the variable now appears twice in the clique with the same value, it is fixed to the opposite value;
11040  *  if the variable now appears twice in the clique with opposite values, all other variables are fixed to
11041  *  the opposite of the value they take in the clique
11042  */
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)11043 SCIP_RETCODE SCIPvarAddClique(
11044    SCIP_VAR*             var,                /**< problem variable  */
11045    BMS_BLKMEM*           blkmem,             /**< block memory */
11046    SCIP_SET*             set,                /**< global SCIP settings */
11047    SCIP_STAT*            stat,               /**< problem statistics */
11048    SCIP_PROB*            transprob,          /**< transformed problem */
11049    SCIP_PROB*            origprob,           /**< original problem */
11050    SCIP_TREE*            tree,               /**< branch and bound tree if in solving stage */
11051    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
11052    SCIP_LP*              lp,                 /**< current LP data */
11053    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
11054    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
11055    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
11056    SCIP_Bool             value,              /**< value of the variable in the clique */
11057    SCIP_CLIQUE*          clique,             /**< clique the variable should be added to */
11058    SCIP_Bool*            infeasible,         /**< pointer to store whether an infeasibility was detected */
11059    int*                  nbdchgs             /**< pointer to count the number of performed bound changes, or NULL */
11060    )
11061 {
11062    assert(var != NULL);
11063    assert(set != NULL);
11064    assert(var->scip == set->scip);
11065    assert(SCIPvarIsBinary(var));
11066    assert(infeasible != NULL);
11067 
11068    *infeasible = FALSE;
11069 
11070    /* get corresponding active problem variable */
11071    SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
11072    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
11073       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
11074       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED
11075       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
11076    assert(SCIPvarIsBinary(var));
11077 
11078    /* only column and loose variables may be member of a clique */
11079    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
11080    {
11081       SCIP_Bool doubleentry;
11082       SCIP_Bool oppositeentry;
11083 
11084       /* add variable to clique */
11085       SCIP_CALL( SCIPcliqueAddVar(clique, blkmem, set, var, value, &doubleentry, &oppositeentry) );
11086 
11087       /* add clique to variable's clique list */
11088       SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, value, clique) );
11089 
11090       /* check consistency of cliquelist */
11091       SCIPcliquelistCheck(var->cliquelist, var);
11092 
11093       /* if the variable now appears twice with the same value in the clique, it can be fixed to the opposite value */
11094       if( doubleentry )
11095       {
11096          SCIP_CALL( SCIPvarFixBinary(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
11097                eventqueue, cliquetable, !value, infeasible, nbdchgs) );
11098       }
11099 
11100       /* if the variable appears with both values in the clique, all other variables of the clique can be fixed
11101        * to the opposite of the value they take in the clique
11102        */
11103       if( oppositeentry )
11104       {
11105          SCIP_VAR** vars;
11106          SCIP_Bool* values;
11107          int nvars;
11108          int i;
11109 
11110          nvars = SCIPcliqueGetNVars(clique);
11111          vars = SCIPcliqueGetVars(clique);
11112          values = SCIPcliqueGetValues(clique);
11113          for( i = 0; i < nvars && !(*infeasible); ++i )
11114          {
11115             if( vars[i] == var )
11116                continue;
11117 
11118             SCIP_CALL( SCIPvarFixBinary(vars[i], blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
11119                   eventqueue, cliquetable, !values[i], infeasible, nbdchgs) );
11120          }
11121       }
11122    }
11123 
11124    return SCIP_OKAY;
11125 }
11126 
11127 /** adds a filled clique to the cliquelists of all corresponding variables */
SCIPvarsAddClique(SCIP_VAR ** vars,SCIP_Bool * values,int nvars,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_CLIQUE * clique)11128 SCIP_RETCODE SCIPvarsAddClique(
11129    SCIP_VAR**            vars,               /**< problem variables */
11130    SCIP_Bool*            values,             /**< values of the variables in the clique */
11131    int                   nvars,              /**< number of problem variables */
11132    BMS_BLKMEM*           blkmem,             /**< block memory */
11133    SCIP_SET*             set,                /**< global SCIP settings */
11134    SCIP_CLIQUE*          clique              /**< clique that contains all given variables and values */
11135    )
11136 {
11137    SCIP_VAR* var;
11138    int v;
11139 
11140    assert(vars != NULL);
11141    assert(values != NULL);
11142    assert(nvars > 0);
11143    assert(set != NULL);
11144    assert(blkmem != NULL);
11145    assert(clique != NULL);
11146 
11147    for( v = nvars - 1; v >= 0; --v )
11148    {
11149       var = vars[v];
11150       assert(SCIPvarIsBinary(var));
11151       assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
11152 
11153       /* add clique to variable's clique list */
11154       SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, values[v], clique) );
11155 
11156       /* check consistency of cliquelist */
11157       SCIPcliquelistCheck(var->cliquelist, var);
11158    }
11159 
11160    return SCIP_OKAY;
11161 }
11162 
11163 /** adds a clique to the list of cliques of the given binary variable, but does not change the clique
11164  *  itself
11165  */
SCIPvarAddCliqueToList(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_Bool value,SCIP_CLIQUE * clique)11166 SCIP_RETCODE SCIPvarAddCliqueToList(
11167    SCIP_VAR*             var,                /**< problem variable  */
11168    BMS_BLKMEM*           blkmem,             /**< block memory */
11169    SCIP_SET*             set,                /**< global SCIP settings */
11170    SCIP_Bool             value,              /**< value of the variable in the clique */
11171    SCIP_CLIQUE*          clique              /**< clique that should be removed from the variable's clique list */
11172    )
11173 {
11174    assert(var != NULL);
11175    assert(SCIPvarIsBinary(var));
11176    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
11177 
11178    /* add clique to variable's clique list */
11179    SCIP_CALL( SCIPcliquelistAdd(&var->cliquelist, blkmem, set, value, clique) );
11180 
11181    return SCIP_OKAY;
11182 }
11183 
11184 
11185 /** deletes a clique from the list of cliques the binary variable is member of, but does not change the clique
11186  *  itself
11187  */
SCIPvarDelCliqueFromList(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_Bool value,SCIP_CLIQUE * clique)11188 SCIP_RETCODE SCIPvarDelCliqueFromList(
11189    SCIP_VAR*             var,                /**< problem variable  */
11190    BMS_BLKMEM*           blkmem,             /**< block memory */
11191    SCIP_Bool             value,              /**< value of the variable in the clique */
11192    SCIP_CLIQUE*          clique              /**< clique that should be removed from the variable's clique list */
11193    )
11194 {
11195    assert(var != NULL);
11196    assert(SCIPvarIsBinary(var));
11197 
11198    /* delete clique from variable's clique list */
11199    SCIP_CALL( SCIPcliquelistDel(&var->cliquelist, blkmem, value, clique) );
11200 
11201    return SCIP_OKAY;
11202 }
11203 
11204 /** deletes the variable from the given clique and updates the list of cliques the binary variable is member of */
SCIPvarDelClique(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_CLIQUETABLE * cliquetable,SCIP_Bool value,SCIP_CLIQUE * clique)11205 SCIP_RETCODE SCIPvarDelClique(
11206    SCIP_VAR*             var,                /**< problem variable  */
11207    BMS_BLKMEM*           blkmem,             /**< block memory */
11208    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
11209    SCIP_Bool             value,              /**< value of the variable in the clique */
11210    SCIP_CLIQUE*          clique              /**< clique the variable should be removed from */
11211    )
11212 {
11213    assert(var != NULL);
11214    assert(SCIPvarIsBinary(var));
11215 
11216    /* get corresponding active problem variable */
11217    SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
11218    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
11219       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
11220       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED
11221       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
11222    assert(SCIPvarIsBinary(var));
11223 
11224    /* only column and loose variables may be member of a clique */
11225    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
11226    {
11227       /* delete clique from variable's clique list */
11228       SCIP_CALL( SCIPcliquelistDel(&var->cliquelist, blkmem, value, clique) );
11229 
11230       /* delete variable from clique */
11231       SCIPcliqueDelVar(clique, cliquetable, var, value);
11232 
11233       /* check consistency of cliquelist */
11234       SCIPcliquelistCheck(var->cliquelist, var);
11235    }
11236 
11237    return SCIP_OKAY;
11238 }
11239 
11240 /** returns whether there is a clique that contains both given variable/value pairs;
11241  *  the variables must be active binary variables;
11242  *  if regardimplics is FALSE, only the cliques in the clique table are looked at;
11243  *  if regardimplics is TRUE, both the cliques and the implications of the implication graph are regarded
11244  *
11245  *  @note a variable with it's negated variable are NOT! in a clique
11246  *  @note a variable with itself are in a clique
11247  */
SCIPvarsHaveCommonClique(SCIP_VAR * var1,SCIP_Bool value1,SCIP_VAR * var2,SCIP_Bool value2,SCIP_Bool regardimplics)11248 SCIP_Bool SCIPvarsHaveCommonClique(
11249    SCIP_VAR*             var1,               /**< first variable */
11250    SCIP_Bool             value1,             /**< value of first variable */
11251    SCIP_VAR*             var2,               /**< second variable */
11252    SCIP_Bool             value2,             /**< value of second variable */
11253    SCIP_Bool             regardimplics       /**< should the implication graph also be searched for a clique? */
11254    )
11255 {
11256    assert(var1 != NULL);
11257    assert(var2 != NULL);
11258    assert(SCIPvarIsActive(var1));
11259    assert(SCIPvarIsActive(var2));
11260    assert(SCIPvarIsBinary(var1));
11261    assert(SCIPvarIsBinary(var2));
11262 
11263    return (SCIPcliquelistsHaveCommonClique(var1->cliquelist, value1, var2->cliquelist, value2)
11264       || (regardimplics && SCIPvarHasImplic(var1, value1, var2, value2 ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER)));
11265 }
11266 
11267 /** actually changes the branch factor of the variable and of all parent variables */
11268 static
varProcessChgBranchFactor(SCIP_VAR * var,SCIP_SET * set,SCIP_Real branchfactor)11269 SCIP_RETCODE varProcessChgBranchFactor(
11270    SCIP_VAR*             var,                /**< problem variable */
11271    SCIP_SET*             set,                /**< global SCIP settings */
11272    SCIP_Real             branchfactor        /**< factor to weigh variable's branching score with */
11273    )
11274 {
11275    SCIP_VAR* parentvar;
11276    SCIP_Real eps;
11277    int i;
11278 
11279    assert(var != NULL);
11280    assert(set != NULL);
11281    assert(var->scip == set->scip);
11282 
11283    /* only use positive values */
11284    eps = SCIPsetEpsilon(set);
11285    branchfactor = MAX(branchfactor, eps);
11286 
11287    SCIPsetDebugMsg(set, "process changing branch factor of <%s> from %f to %f\n", var->name, var->branchfactor, branchfactor);
11288 
11289    if( SCIPsetIsEQ(set, branchfactor, var->branchfactor) )
11290       return SCIP_OKAY;
11291 
11292    /* change the branch factor */
11293    var->branchfactor = branchfactor;
11294 
11295    /* process parent variables */
11296    for( i = 0; i < var->nparentvars; ++i )
11297    {
11298       parentvar = var->parentvars[i];
11299       assert(parentvar != NULL);
11300 
11301       switch( SCIPvarGetStatus(parentvar) )
11302       {
11303       case SCIP_VARSTATUS_ORIGINAL:
11304          /* do not change priorities across the border between transformed and original problem */
11305          break;
11306 
11307       case SCIP_VARSTATUS_COLUMN:
11308       case SCIP_VARSTATUS_LOOSE:
11309       case SCIP_VARSTATUS_FIXED:
11310       case SCIP_VARSTATUS_MULTAGGR:
11311          SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
11312          SCIPABORT();
11313          return SCIP_INVALIDDATA; /*lint !e527*/
11314 
11315       case SCIP_VARSTATUS_AGGREGATED:
11316       case SCIP_VARSTATUS_NEGATED:
11317          SCIP_CALL( varProcessChgBranchFactor(parentvar, set, branchfactor) );
11318          break;
11319 
11320       default:
11321          SCIPerrorMessage("unknown variable status\n");
11322          SCIPABORT();
11323          return SCIP_ERROR; /*lint !e527*/
11324       }
11325    }
11326 
11327    return SCIP_OKAY;
11328 }
11329 
11330 /** sets the branch factor of the variable; this value can be used in the branching methods to scale the score
11331  *  values of the variables; higher factor leads to a higher probability that this variable is chosen for branching
11332  */
SCIPvarChgBranchFactor(SCIP_VAR * var,SCIP_SET * set,SCIP_Real branchfactor)11333 SCIP_RETCODE SCIPvarChgBranchFactor(
11334    SCIP_VAR*             var,                /**< problem variable */
11335    SCIP_SET*             set,                /**< global SCIP settings */
11336    SCIP_Real             branchfactor        /**< factor to weigh variable's branching score with */
11337    )
11338 {
11339    int v;
11340 
11341    assert(var != NULL);
11342    assert(set != NULL);
11343    assert(var->scip == set->scip);
11344    assert(branchfactor >= 0.0);
11345 
11346    SCIPdebugMessage("changing branch factor of <%s> from %g to %g\n", var->name, var->branchfactor, branchfactor);
11347 
11348    if( SCIPsetIsEQ(set, var->branchfactor, branchfactor) )
11349       return SCIP_OKAY;
11350 
11351    /* change priorities of attached variables */
11352    switch( SCIPvarGetStatus(var) )
11353    {
11354    case SCIP_VARSTATUS_ORIGINAL:
11355       if( var->data.original.transvar != NULL )
11356       {
11357          SCIP_CALL( SCIPvarChgBranchFactor(var->data.original.transvar, set, branchfactor) );
11358       }
11359       else
11360       {
11361          assert(set->stage == SCIP_STAGE_PROBLEM);
11362          var->branchfactor = branchfactor;
11363       }
11364       break;
11365 
11366    case SCIP_VARSTATUS_COLUMN:
11367    case SCIP_VARSTATUS_LOOSE:
11368    case SCIP_VARSTATUS_FIXED:
11369       SCIP_CALL( varProcessChgBranchFactor(var, set, branchfactor) );
11370       break;
11371 
11372    case SCIP_VARSTATUS_AGGREGATED:
11373       assert(var->data.aggregate.var != NULL);
11374       SCIP_CALL( SCIPvarChgBranchFactor(var->data.aggregate.var, set, branchfactor) );
11375       break;
11376 
11377    case SCIP_VARSTATUS_MULTAGGR:
11378       assert(!var->donotmultaggr);
11379       for( v = 0; v < var->data.multaggr.nvars; ++v )
11380       {
11381          SCIP_CALL( SCIPvarChgBranchFactor(var->data.multaggr.vars[v], set, branchfactor) );
11382       }
11383       break;
11384 
11385    case SCIP_VARSTATUS_NEGATED:
11386       assert(var->negatedvar != NULL);
11387       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
11388       assert(var->negatedvar->negatedvar == var);
11389       SCIP_CALL( SCIPvarChgBranchFactor(var->negatedvar, set, branchfactor) );
11390       break;
11391 
11392    default:
11393       SCIPerrorMessage("unknown variable status\n");
11394       SCIPABORT();
11395       return SCIP_ERROR; /*lint !e527*/
11396    }
11397 
11398    return SCIP_OKAY;
11399 }
11400 
11401 /** actually changes the branch priority of the variable and of all parent variables */
11402 static
varProcessChgBranchPriority(SCIP_VAR * var,int branchpriority)11403 SCIP_RETCODE varProcessChgBranchPriority(
11404    SCIP_VAR*             var,                /**< problem variable */
11405    int                   branchpriority      /**< branching priority of the variable */
11406    )
11407 {
11408    SCIP_VAR* parentvar;
11409    int i;
11410 
11411    assert(var != NULL);
11412 
11413    SCIPdebugMessage("process changing branch priority of <%s> from %d to %d\n",
11414       var->name, var->branchpriority, branchpriority);
11415 
11416    if( branchpriority == var->branchpriority )
11417       return SCIP_OKAY;
11418 
11419    /* change the branch priority */
11420    var->branchpriority = branchpriority;
11421 
11422    /* process parent variables */
11423    for( i = 0; i < var->nparentvars; ++i )
11424    {
11425       parentvar = var->parentvars[i];
11426       assert(parentvar != NULL);
11427 
11428       switch( SCIPvarGetStatus(parentvar) )
11429       {
11430       case SCIP_VARSTATUS_ORIGINAL:
11431          /* do not change priorities across the border between transformed and original problem */
11432          break;
11433 
11434       case SCIP_VARSTATUS_COLUMN:
11435       case SCIP_VARSTATUS_LOOSE:
11436       case SCIP_VARSTATUS_FIXED:
11437       case SCIP_VARSTATUS_MULTAGGR:
11438          SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
11439          SCIPABORT();
11440          return SCIP_INVALIDDATA; /*lint !e527*/
11441 
11442       case SCIP_VARSTATUS_AGGREGATED:
11443       case SCIP_VARSTATUS_NEGATED:
11444          SCIP_CALL( varProcessChgBranchPriority(parentvar, branchpriority) );
11445          break;
11446 
11447       default:
11448          SCIPerrorMessage("unknown variable status\n");
11449          return SCIP_ERROR;
11450       }
11451    }
11452 
11453    return SCIP_OKAY;
11454 }
11455 
11456 /** sets the branch priority of the variable; variables with higher branch priority are always preferred to variables
11457  *  with lower priority in selection of branching variable
11458  */
SCIPvarChgBranchPriority(SCIP_VAR * var,int branchpriority)11459 SCIP_RETCODE SCIPvarChgBranchPriority(
11460    SCIP_VAR*             var,                /**< problem variable */
11461    int                   branchpriority      /**< branching priority of the variable */
11462    )
11463 {
11464    int v;
11465 
11466    assert(var != NULL);
11467 
11468    SCIPdebugMessage("changing branch priority of <%s> from %d to %d\n", var->name, var->branchpriority, branchpriority);
11469 
11470    if( var->branchpriority == branchpriority )
11471       return SCIP_OKAY;
11472 
11473    /* change priorities of attached variables */
11474    switch( SCIPvarGetStatus(var) )
11475    {
11476    case SCIP_VARSTATUS_ORIGINAL:
11477       if( var->data.original.transvar != NULL )
11478       {
11479          SCIP_CALL( SCIPvarChgBranchPriority(var->data.original.transvar, branchpriority) );
11480       }
11481       else
11482          var->branchpriority = branchpriority;
11483       break;
11484 
11485    case SCIP_VARSTATUS_COLUMN:
11486    case SCIP_VARSTATUS_LOOSE:
11487    case SCIP_VARSTATUS_FIXED:
11488       SCIP_CALL( varProcessChgBranchPriority(var, branchpriority) );
11489       break;
11490 
11491    case SCIP_VARSTATUS_AGGREGATED:
11492       assert(var->data.aggregate.var != NULL);
11493       SCIP_CALL( SCIPvarChgBranchPriority(var->data.aggregate.var, branchpriority) );
11494       break;
11495 
11496    case SCIP_VARSTATUS_MULTAGGR:
11497       assert(!var->donotmultaggr);
11498       for( v = 0; v < var->data.multaggr.nvars; ++v )
11499       {
11500          SCIP_CALL( SCIPvarChgBranchPriority(var->data.multaggr.vars[v], branchpriority) );
11501       }
11502       break;
11503 
11504    case SCIP_VARSTATUS_NEGATED:
11505       assert(var->negatedvar != NULL);
11506       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
11507       assert(var->negatedvar->negatedvar == var);
11508       SCIP_CALL( SCIPvarChgBranchPriority(var->negatedvar, branchpriority) );
11509       break;
11510 
11511    default:
11512       SCIPerrorMessage("unknown variable status\n");
11513       SCIPABORT();
11514       return SCIP_ERROR; /*lint !e527*/
11515    }
11516 
11517    return SCIP_OKAY;
11518 }
11519 
11520 /** actually changes the branch direction of the variable and of all parent variables */
11521 static
varProcessChgBranchDirection(SCIP_VAR * var,SCIP_BRANCHDIR branchdirection)11522 SCIP_RETCODE varProcessChgBranchDirection(
11523    SCIP_VAR*             var,                /**< problem variable */
11524    SCIP_BRANCHDIR        branchdirection     /**< preferred branch direction of the variable (downwards, upwards, auto) */
11525    )
11526 {
11527    SCIP_VAR* parentvar;
11528    int i;
11529 
11530    assert(var != NULL);
11531 
11532    SCIPdebugMessage("process changing branch direction of <%s> from %u to %d\n",
11533       var->name, var->branchdirection, branchdirection);
11534 
11535    if( branchdirection == (SCIP_BRANCHDIR)var->branchdirection )
11536       return SCIP_OKAY;
11537 
11538    /* change the branch direction */
11539    var->branchdirection = branchdirection; /*lint !e641*/
11540 
11541    /* process parent variables */
11542    for( i = 0; i < var->nparentvars; ++i )
11543    {
11544       parentvar = var->parentvars[i];
11545       assert(parentvar != NULL);
11546 
11547       switch( SCIPvarGetStatus(parentvar) )
11548       {
11549       case SCIP_VARSTATUS_ORIGINAL:
11550          /* do not change directions across the border between transformed and original problem */
11551          break;
11552 
11553       case SCIP_VARSTATUS_COLUMN:
11554       case SCIP_VARSTATUS_LOOSE:
11555       case SCIP_VARSTATUS_FIXED:
11556       case SCIP_VARSTATUS_MULTAGGR:
11557          SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
11558          SCIPABORT();
11559          return SCIP_INVALIDDATA; /*lint !e527*/
11560 
11561       case SCIP_VARSTATUS_AGGREGATED:
11562          if( parentvar->data.aggregate.scalar > 0.0 )
11563          {
11564             SCIP_CALL( varProcessChgBranchDirection(parentvar, branchdirection) );
11565          }
11566          else
11567          {
11568             SCIP_CALL( varProcessChgBranchDirection(parentvar, SCIPbranchdirOpposite(branchdirection)) );
11569          }
11570          break;
11571 
11572       case SCIP_VARSTATUS_NEGATED:
11573          SCIP_CALL( varProcessChgBranchDirection(parentvar, SCIPbranchdirOpposite(branchdirection)) );
11574          break;
11575 
11576       default:
11577          SCIPerrorMessage("unknown variable status\n");
11578          SCIPABORT();
11579          return SCIP_ERROR; /*lint !e527*/
11580       }
11581    }
11582 
11583    return SCIP_OKAY;
11584 }
11585 
11586 /** sets the branch direction of the variable; variables with higher branch direction are always preferred to variables
11587  *  with lower direction in selection of branching variable
11588  */
SCIPvarChgBranchDirection(SCIP_VAR * var,SCIP_BRANCHDIR branchdirection)11589 SCIP_RETCODE SCIPvarChgBranchDirection(
11590    SCIP_VAR*             var,                /**< problem variable */
11591    SCIP_BRANCHDIR        branchdirection     /**< preferred branch direction of the variable (downwards, upwards, auto) */
11592    )
11593 {
11594    int v;
11595 
11596    assert(var != NULL);
11597 
11598    SCIPdebugMessage("changing branch direction of <%s> from %u to %d\n", var->name, var->branchdirection, branchdirection);
11599 
11600    if( (SCIP_BRANCHDIR)var->branchdirection == branchdirection )
11601       return SCIP_OKAY;
11602 
11603    /* change directions of attached variables */
11604    switch( SCIPvarGetStatus(var) )
11605    {
11606    case SCIP_VARSTATUS_ORIGINAL:
11607       if( var->data.original.transvar != NULL )
11608       {
11609          SCIP_CALL( SCIPvarChgBranchDirection(var->data.original.transvar, branchdirection) );
11610       }
11611       else
11612          var->branchdirection = branchdirection; /*lint !e641*/
11613       break;
11614 
11615    case SCIP_VARSTATUS_COLUMN:
11616    case SCIP_VARSTATUS_LOOSE:
11617    case SCIP_VARSTATUS_FIXED:
11618       SCIP_CALL( varProcessChgBranchDirection(var, branchdirection) );
11619       break;
11620 
11621    case SCIP_VARSTATUS_AGGREGATED:
11622       assert(var->data.aggregate.var != NULL);
11623       if( var->data.aggregate.scalar > 0.0 )
11624       {
11625          SCIP_CALL( SCIPvarChgBranchDirection(var->data.aggregate.var, branchdirection) );
11626       }
11627       else
11628       {
11629          SCIP_CALL( SCIPvarChgBranchDirection(var->data.aggregate.var, SCIPbranchdirOpposite(branchdirection)) );
11630       }
11631       break;
11632 
11633    case SCIP_VARSTATUS_MULTAGGR:
11634       assert(!var->donotmultaggr);
11635       for( v = 0; v < var->data.multaggr.nvars; ++v )
11636       {
11637          /* only update branching direction of aggregation variables, if they don't have a preferred direction yet */
11638          assert(var->data.multaggr.vars[v] != NULL);
11639          if( (SCIP_BRANCHDIR)var->data.multaggr.vars[v]->branchdirection == SCIP_BRANCHDIR_AUTO )
11640          {
11641             if( var->data.multaggr.scalars[v] > 0.0 )
11642             {
11643                SCIP_CALL( SCIPvarChgBranchDirection(var->data.multaggr.vars[v], branchdirection) );
11644             }
11645             else
11646             {
11647                SCIP_CALL( SCIPvarChgBranchDirection(var->data.multaggr.vars[v], SCIPbranchdirOpposite(branchdirection)) );
11648             }
11649          }
11650       }
11651       break;
11652 
11653    case SCIP_VARSTATUS_NEGATED:
11654       assert(var->negatedvar != NULL);
11655       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
11656       assert(var->negatedvar->negatedvar == var);
11657       SCIP_CALL( SCIPvarChgBranchDirection(var->negatedvar, SCIPbranchdirOpposite(branchdirection)) );
11658       break;
11659 
11660    default:
11661       SCIPerrorMessage("unknown variable status\n");
11662       SCIPABORT();
11663       return SCIP_ERROR; /*lint !e527*/
11664    }
11665 
11666    return SCIP_OKAY;
11667 }
11668 
11669 /** compares the index of two variables, only active, fixed or negated variables are allowed, if a variable
11670  *  is negated then the index of the corresponding active variable is taken, returns -1 if first is
11671  *  smaller than, and +1 if first is greater than second variable index; returns 0 if both indices
11672  *  are equal, which means both variables are equal
11673  */
SCIPvarCompareActiveAndNegated(SCIP_VAR * var1,SCIP_VAR * var2)11674 int SCIPvarCompareActiveAndNegated(
11675    SCIP_VAR*             var1,               /**< first problem variable */
11676    SCIP_VAR*             var2                /**< second problem variable */
11677    )
11678 {
11679    assert(var1 != NULL);
11680    assert(var2 != NULL);
11681    assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_FIXED);
11682    assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_FIXED);
11683 
11684    if( SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED )
11685       var1 = SCIPvarGetNegatedVar(var1);
11686    if( SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED )
11687       var2 = SCIPvarGetNegatedVar(var2);
11688 
11689    assert(var1 != NULL);
11690    assert(var2 != NULL);
11691 
11692    if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
11693       return -1;
11694    else if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
11695       return +1;
11696 
11697    assert(var1 == var2);
11698    return 0;
11699 }
11700 
11701 /** comparison method for sorting active and negated variables by non-decreasing index, active and negated
11702  *  variables are handled as the same variables
11703  */
SCIP_DECL_SORTPTRCOMP(SCIPvarCompActiveAndNegated)11704 SCIP_DECL_SORTPTRCOMP(SCIPvarCompActiveAndNegated)
11705 {
11706    return SCIPvarCompareActiveAndNegated((SCIP_VAR*)elem1, (SCIP_VAR*)elem2);
11707 }
11708 
11709 /** compares the index of two variables, returns -1 if first is smaller than, and +1 if first is greater than second
11710  *  variable index; returns 0 if both indices are equal, which means both variables are equal
11711  */
SCIPvarCompare(SCIP_VAR * var1,SCIP_VAR * var2)11712 int SCIPvarCompare(
11713    SCIP_VAR*             var1,               /**< first problem variable */
11714    SCIP_VAR*             var2                /**< second problem variable */
11715    )
11716 {
11717    assert(var1 != NULL);
11718    assert(var2 != NULL);
11719 
11720    if( var1->index < var2->index )
11721       return -1;
11722    else if( var1->index > var2->index )
11723       return +1;
11724    else
11725    {
11726       assert(var1 == var2);
11727       return 0;
11728    }
11729 }
11730 
11731 /** comparison method for sorting variables by non-decreasing index */
SCIP_DECL_SORTPTRCOMP(SCIPvarComp)11732 SCIP_DECL_SORTPTRCOMP(SCIPvarComp)
11733 {
11734    return SCIPvarCompare((SCIP_VAR*)elem1, (SCIP_VAR*)elem2);
11735 }
11736 
11737 /** comparison method for sorting variables by non-decreasing objective coefficient */
SCIP_DECL_SORTPTRCOMP(SCIPvarCompObj)11738 SCIP_DECL_SORTPTRCOMP(SCIPvarCompObj)
11739 {
11740    SCIP_Real obj1;
11741    SCIP_Real obj2;
11742 
11743    obj1 = SCIPvarGetObj((SCIP_VAR*)elem1);
11744    obj2 = SCIPvarGetObj((SCIP_VAR*)elem2);
11745 
11746    if( obj1 < obj2 )
11747       return -1;
11748    else if( obj1 > obj2 )
11749       return +1;
11750    else
11751       return 0;
11752 }
11753 
11754 /** hash key retrieval function for variables */
SCIP_DECL_HASHGETKEY(SCIPvarGetHashkey)11755 SCIP_DECL_HASHGETKEY(SCIPvarGetHashkey)
11756 {  /*lint --e{715}*/
11757    return elem;
11758 }
11759 
11760 /** returns TRUE iff the indices of both variables are equal */
SCIP_DECL_HASHKEYEQ(SCIPvarIsHashkeyEq)11761 SCIP_DECL_HASHKEYEQ(SCIPvarIsHashkeyEq)
11762 {  /*lint --e{715}*/
11763    if( key1 == key2 )
11764       return TRUE;
11765    return FALSE;
11766 }
11767 
11768 /** returns the hash value of the key */
SCIP_DECL_HASHKEYVAL(SCIPvarGetHashkeyVal)11769 SCIP_DECL_HASHKEYVAL(SCIPvarGetHashkeyVal)
11770 {  /*lint --e{715}*/
11771    assert( SCIPvarGetIndex((SCIP_VAR*) key) >= 0 );
11772    return (unsigned int) SCIPvarGetIndex((SCIP_VAR*) key);
11773 }
11774 
11775 /** return for given variables all their active counterparts; all active variables will be pairwise different */
SCIPvarsGetActiveVars(SCIP_SET * set,SCIP_VAR ** vars,int * nvars,int varssize,int * requiredsize)11776 SCIP_RETCODE SCIPvarsGetActiveVars(
11777    SCIP_SET*             set,                /**< global SCIP settings */
11778    SCIP_VAR**            vars,               /**< variable array with given variables and as output all active
11779 					      *   variables, if enough slots exist
11780 					      */
11781    int*                  nvars,              /**< number of given variables, and as output number of active variables,
11782 					      *   if enough slots exist
11783 					      */
11784    int                   varssize,           /**< available slots in vars array */
11785    int*                  requiredsize        /**< pointer to store the required array size for the active variables */
11786    )
11787 {
11788    SCIP_VAR** activevars;
11789    int nactivevars;
11790    int activevarssize;
11791 
11792    SCIP_VAR* var;
11793    int v;
11794 
11795    SCIP_VAR** tmpvars;
11796    SCIP_VAR** multvars;
11797    int tmpvarssize;
11798    int ntmpvars;
11799    int noldtmpvars;
11800    int nmultvars;
11801 
11802    assert(set != NULL);
11803    assert(nvars != NULL);
11804    assert(vars != NULL || *nvars == 0);
11805    assert(varssize >= *nvars);
11806    assert(requiredsize != NULL);
11807 
11808    *requiredsize = 0;
11809 
11810    if( *nvars == 0 )
11811       return SCIP_OKAY;
11812 
11813    nactivevars = 0;
11814    activevarssize = *nvars;
11815    ntmpvars = *nvars;
11816    tmpvarssize = *nvars;
11817 
11818    /* temporary memory */
11819    SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) );
11820    /* coverity[copy_paste_error] */
11821    SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpvars, vars, ntmpvars) );
11822 
11823    noldtmpvars = ntmpvars;
11824 
11825    /* sort all variables to combine equal variables easily */
11826    SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
11827    for( v = ntmpvars - 1; v > 0; --v )
11828    {
11829       /* combine same variables */
11830       if( SCIPvarCompare(tmpvars[v], tmpvars[v - 1]) == 0 )
11831       {
11832          --ntmpvars;
11833          tmpvars[v] = tmpvars[ntmpvars];
11834       }
11835    }
11836    /* sort all variables again to combine equal variables later on */
11837    if( noldtmpvars > ntmpvars )
11838       SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
11839 
11840    /* collect for each variable the representation in active variables */
11841    while( ntmpvars >= 1 )
11842    {
11843       --ntmpvars;
11844       var = tmpvars[ntmpvars];
11845       assert( var != NULL );
11846 
11847       switch( SCIPvarGetStatus(var) )
11848       {
11849       case SCIP_VARSTATUS_ORIGINAL:
11850 	 if( var->data.original.transvar == NULL )
11851 	 {
11852 	    SCIPerrorMessage("original variable has no transformed variable attached\n");
11853 	    SCIPABORT();
11854 	    return SCIP_INVALIDDATA; /*lint !e527*/
11855 	 }
11856 	 tmpvars[ntmpvars] = var->data.original.transvar;
11857 	 ++ntmpvars;
11858 	 break;
11859 
11860       case SCIP_VARSTATUS_AGGREGATED:
11861 	 tmpvars[ntmpvars] = var->data.aggregate.var;
11862 	 ++ntmpvars;
11863 	 break;
11864 
11865       case SCIP_VARSTATUS_NEGATED:
11866 	 tmpvars[ntmpvars] = var->negatedvar;
11867 	 ++ntmpvars;
11868 	 break;
11869 
11870       case SCIP_VARSTATUS_LOOSE:
11871       case SCIP_VARSTATUS_COLUMN:
11872 	 /* check for space in temporary memory */
11873          if( nactivevars >= activevarssize )
11874          {
11875             activevarssize *= 2;
11876             SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) );
11877             assert(nactivevars < activevarssize);
11878          }
11879          activevars[nactivevars] = var;
11880          nactivevars++;
11881          break;
11882 
11883       case SCIP_VARSTATUS_MULTAGGR:
11884          /* x = a_1*y_1 + ... + a_n*y_n + c */
11885          nmultvars = var->data.multaggr.nvars;
11886          multvars = var->data.multaggr.vars;
11887 
11888 	 /* check for space in temporary memory */
11889          if( nmultvars + ntmpvars > tmpvarssize )
11890          {
11891             while( nmultvars + ntmpvars > tmpvarssize )
11892                tmpvarssize *= 2;
11893             SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) );
11894             assert(nmultvars + ntmpvars <= tmpvarssize);
11895          }
11896 
11897 	 /* copy all multi-aggregation variables into our working array */
11898 	 BMScopyMemoryArray(&tmpvars[ntmpvars], multvars, nmultvars); /*lint !e866*/
11899 
11900 	 /* get active, fixed or multi-aggregated corresponding variables for all new ones */
11901 	 SCIPvarsGetProbvar(&tmpvars[ntmpvars], nmultvars);
11902 
11903 	 ntmpvars += nmultvars;
11904 	 noldtmpvars = ntmpvars;
11905 
11906 	 /* sort all variables to combine equal variables easily */
11907 	 SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
11908 	 for( v = ntmpvars - 1; v > 0; --v )
11909 	 {
11910 	    /* combine same variables */
11911 	    if( SCIPvarCompare(tmpvars[v], tmpvars[v - 1]) == 0 )
11912 	    {
11913 	       --ntmpvars;
11914 	       tmpvars[v] = tmpvars[ntmpvars];
11915 	    }
11916 	 }
11917 	 /* sort all variables again to combine equal variables later on */
11918 	 if( noldtmpvars > ntmpvars )
11919 	    SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars);
11920 
11921          break;
11922 
11923       case SCIP_VARSTATUS_FIXED:
11924 	 /* no need for memorizing fixed variables */
11925          break;
11926 
11927       default:
11928 	 SCIPerrorMessage("unknown variable status\n");
11929          SCIPABORT();
11930 	 return SCIP_INVALIDDATA; /*lint !e527*/
11931       }
11932    }
11933 
11934    /* sort variable array by variable index */
11935    SCIPsortPtr((void**)activevars, SCIPvarComp, nactivevars);
11936 
11937    /* eliminate duplicates and count required size */
11938    v = nactivevars - 1;
11939    while( v > 0 )
11940    {
11941       /* combine both variable since they are the same */
11942       if( SCIPvarCompare(activevars[v - 1], activevars[v]) == 0 )
11943       {
11944 	 --nactivevars;
11945 	 activevars[v] = activevars[nactivevars];
11946       }
11947       --v;
11948    }
11949    *requiredsize = nactivevars;
11950 
11951    if( varssize >= *requiredsize )
11952    {
11953       assert(vars != NULL);
11954 
11955       *nvars = *requiredsize;
11956       BMScopyMemoryArray(vars, activevars, nactivevars);
11957    }
11958 
11959    SCIPsetFreeBufferArray(set, &tmpvars);
11960    SCIPsetFreeBufferArray(set, &activevars);
11961 
11962    return SCIP_OKAY;
11963 }
11964 
11965 /** gets corresponding active, fixed, or multi-aggregated problem variables of given variables,
11966  *  @note the content of the given array will/might change
11967  */
SCIPvarsGetProbvar(SCIP_VAR ** vars,int nvars)11968 void SCIPvarsGetProbvar(
11969    SCIP_VAR**            vars,               /**< array of problem variables */
11970    int                   nvars               /**< number of variables */
11971    )
11972 {
11973    int v;
11974 
11975    assert(vars != NULL || nvars == 0);
11976 
11977    for( v = nvars - 1; v >= 0; --v )
11978    {
11979       assert(vars != NULL);
11980       assert(vars[v] != NULL);
11981 
11982       vars[v] = SCIPvarGetProbvar(vars[v]);
11983       assert(vars[v] != NULL);
11984    }
11985 }
11986 
11987 /** gets corresponding active, fixed, or multi-aggregated problem variable of a variable */
SCIPvarGetProbvar(SCIP_VAR * var)11988 SCIP_VAR* SCIPvarGetProbvar(
11989    SCIP_VAR*             var                 /**< problem variable */
11990    )
11991 {
11992    SCIP_VAR* retvar;
11993 
11994    assert(var != NULL);
11995 
11996    retvar = var;
11997 
11998    SCIPdebugMessage("get problem variable of <%s>\n", var->name);
11999 
12000    while( TRUE ) /*lint !e716 */
12001    {
12002       assert(retvar != NULL);
12003 
12004       switch( SCIPvarGetStatus(retvar) )
12005       {
12006       case SCIP_VARSTATUS_ORIGINAL:
12007 	 if( retvar->data.original.transvar == NULL )
12008 	 {
12009 	    SCIPerrorMessage("original variable has no transformed variable attached\n");
12010 	    SCIPABORT();
12011 	    return NULL; /*lint !e527 */
12012 	 }
12013 	 retvar = retvar->data.original.transvar;
12014 	 break;
12015 
12016       case SCIP_VARSTATUS_LOOSE:
12017       case SCIP_VARSTATUS_COLUMN:
12018       case SCIP_VARSTATUS_FIXED:
12019 	 return retvar;
12020 
12021       case SCIP_VARSTATUS_MULTAGGR:
12022 	 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12023 	 if ( retvar->data.multaggr.nvars == 1 )
12024 	    retvar = retvar->data.multaggr.vars[0];
12025 	 else
12026 	    return retvar;
12027 	 break;
12028 
12029       case SCIP_VARSTATUS_AGGREGATED:
12030 	 retvar = retvar->data.aggregate.var;
12031 	 break;
12032 
12033       case SCIP_VARSTATUS_NEGATED:
12034 	 retvar = retvar->negatedvar;
12035 	 break;
12036 
12037       default:
12038 	 SCIPerrorMessage("unknown variable status\n");
12039 	 SCIPABORT();
12040 	 return NULL; /*lint !e527*/
12041       }
12042    }
12043 }
12044 
12045 /** gets corresponding active, fixed, or multi-aggregated problem variables of binary variables and updates the given
12046  *  negation status of each variable
12047  */
SCIPvarsGetProbvarBinary(SCIP_VAR *** vars,SCIP_Bool ** negatedarr,int nvars)12048 SCIP_RETCODE SCIPvarsGetProbvarBinary(
12049    SCIP_VAR***           vars,               /**< pointer to binary problem variables */
12050    SCIP_Bool**           negatedarr,         /**< pointer to corresponding array to update the negation status */
12051    int                   nvars               /**< number of variables and values in vars and negated array */
12052    )
12053 {
12054    SCIP_VAR** var;
12055    SCIP_Bool* negated;
12056    int v;
12057 
12058    assert(vars != NULL);
12059    assert(*vars != NULL || nvars == 0);
12060    assert(negatedarr != NULL);
12061    assert(*negatedarr != NULL || nvars == 0);
12062 
12063    for( v = nvars - 1; v >= 0; --v )
12064    {
12065       var = &((*vars)[v]);
12066       negated = &((*negatedarr)[v]);
12067 
12068       /* get problem variable */
12069       SCIP_CALL( SCIPvarGetProbvarBinary(var, negated) );
12070    }
12071 
12072    return SCIP_OKAY;
12073 }
12074 
12075 
12076 /** gets corresponding active, fixed, or multi-aggregated problem variable of a binary variable and updates the given
12077  *  negation status (this means you have to assign a value to SCIP_Bool negated before calling this method, usually
12078  *  FALSE is used)
12079  */
SCIPvarGetProbvarBinary(SCIP_VAR ** var,SCIP_Bool * negated)12080 SCIP_RETCODE SCIPvarGetProbvarBinary(
12081    SCIP_VAR**            var,                /**< pointer to binary problem variable */
12082    SCIP_Bool*            negated             /**< pointer to update the negation status */
12083    )
12084 {
12085    SCIP_Bool active = FALSE;
12086 #ifndef NDEBUG
12087    SCIP_Real constant = 0.0;
12088    SCIP_Bool orignegated;
12089 #endif
12090 
12091    assert(var != NULL);
12092    assert(*var != NULL);
12093    assert(negated != NULL);
12094    assert(SCIPvarIsBinary(*var));
12095 
12096 #ifndef NDEBUG
12097    orignegated = *negated;
12098 #endif
12099 
12100    while( !active && *var != NULL )
12101    {
12102       switch( SCIPvarGetStatus(*var) )
12103       {
12104       case SCIP_VARSTATUS_ORIGINAL:
12105          if( (*var)->data.original.transvar == NULL )
12106             return SCIP_OKAY;
12107          *var = (*var)->data.original.transvar;
12108          break;
12109 
12110       case SCIP_VARSTATUS_LOOSE:
12111       case SCIP_VARSTATUS_COLUMN:
12112       case SCIP_VARSTATUS_FIXED:
12113          active = TRUE;
12114          break;
12115 
12116       case SCIP_VARSTATUS_MULTAGGR:
12117          /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12118          if ( (*var)->data.multaggr.nvars == 1 )
12119          {
12120             assert( (*var)->data.multaggr.vars != NULL );
12121             assert( (*var)->data.multaggr.scalars != NULL );
12122             assert( SCIPvarIsBinary((*var)->data.multaggr.vars[0]) );
12123             assert(!EPSZ((*var)->data.multaggr.scalars[0], 1e-06));
12124 
12125             /* if not all variables were fully propagated, it might happen that a variable is multi-aggregated to
12126              * another variable which needs to be fixed
12127              *
12128              * e.g. x = y - 1 => (x = 0 && y = 1)
12129              * e.g. x = y + 1 => (x = 1 && y = 0)
12130              *
12131              * is this special case we need to return the muti-aggregation
12132              */
12133             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)) )
12134             {
12135                assert(EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06));
12136             }
12137             else
12138             {
12139                /* @note due to fixations, a multi-aggregation can have a constant of zero and a negative scalar or even
12140                 *       a scalar in absolute value unequal to one, in this case this aggregation variable needs to be
12141                 *       fixed to zero, but this should be done by another enforcement; so not depending on the scalar,
12142                 *       we will return the aggregated variable;
12143                 */
12144                if( !EPSEQ(REALABS((*var)->data.multaggr.scalars[0]), 1.0, 1e-06) )
12145                {
12146                   active = TRUE;
12147                   break;
12148                }
12149 
12150                /* @note it may also happen that the constant is larger than 1 or smaller than 0, in that case the
12151                 *       aggregation variable needs to be fixed to one, but this should be done by another enforcement;
12152                 *       so if this is the case, we will return the aggregated variable
12153                 */
12154                assert(EPSZ((*var)->data.multaggr.constant, 1e-06) || EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06)
12155                   || EPSZ((*var)->data.multaggr.constant + (*var)->data.multaggr.scalars[0], 1e-06)
12156                   || EPSEQ((*var)->data.multaggr.constant + (*var)->data.multaggr.scalars[0], 1.0, 1e-06));
12157 
12158                if( !EPSZ((*var)->data.multaggr.constant, 1e-06) && !EPSEQ((*var)->data.multaggr.constant, 1.0, 1e-06) )
12159                {
12160                   active = TRUE;
12161                   break;
12162                }
12163 
12164                assert(EPSEQ((*var)->data.multaggr.scalars[0], 1.0, 1e-06) || EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06));
12165 
12166                if( EPSZ((*var)->data.multaggr.constant, 1e-06) )
12167                {
12168                   /* if the scalar is negative, either the aggregation variable is already fixed to zero or has at
12169                    * least one uplock (that hopefully will enforce this fixation to zero); can it happen that this
12170                    * variable itself is multi-aggregated again?
12171                    */
12172                   assert(EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06) ?
12173                      ((SCIPvarGetUbGlobal((*var)->data.multaggr.vars[0]) < 0.5) ||
12174                         SCIPvarGetNLocksUpType((*var)->data.multaggr.vars[0], SCIP_LOCKTYPE_MODEL) > 0) : TRUE);
12175                }
12176                else
12177                {
12178                   assert(EPSEQ((*var)->data.multaggr.scalars[0], -1.0, 1e-06));
12179 #ifndef NDEBUG
12180                   constant += (*negated) != orignegated ? -1.0 : 1.0;
12181 #endif
12182 
12183                   *negated = !(*negated);
12184                }
12185                *var = (*var)->data.multaggr.vars[0];
12186                break;
12187             }
12188          }
12189          active = TRUE;  /*lint !e838*/
12190          break;
12191 
12192       case SCIP_VARSTATUS_AGGREGATED:  /* x = a'*x' + c'  =>  a*x + c == (a*a')*x' + (a*c' + c) */
12193          assert((*var)->data.aggregate.var != NULL);
12194          assert(EPSEQ((*var)->data.aggregate.scalar, 1.0, 1e-06) || EPSEQ((*var)->data.aggregate.scalar, -1.0, 1e-06));
12195          assert(EPSLE((*var)->data.aggregate.var->glbdom.ub - (*var)->data.aggregate.var->glbdom.lb, 1.0, 1e-06));
12196 #ifndef NDEBUG
12197          constant += (*negated) != orignegated ? -(*var)->data.aggregate.constant : (*var)->data.aggregate.constant;
12198 #endif
12199 
12200          *negated = ((*var)->data.aggregate.scalar > 0.0) ? *negated : !(*negated);
12201          *var = (*var)->data.aggregate.var;
12202          break;
12203 
12204       case SCIP_VARSTATUS_NEGATED:     /* x =  - x' + c'  =>  a*x + c ==   (-a)*x' + (a*c' + c) */
12205          assert((*var)->negatedvar != NULL);
12206 #ifndef NDEBUG
12207          constant += (*negated) != orignegated ? -1.0 : 1.0;
12208 #endif
12209 
12210          *negated = !(*negated);
12211          *var = (*var)->negatedvar;
12212          break;
12213 
12214       default:
12215          SCIPerrorMessage("unknown variable status\n");
12216          return SCIP_INVALIDDATA;
12217       }
12218    }
12219    assert(active == (*var != NULL));
12220 
12221    if( active )
12222    {
12223       assert(SCIPvarIsBinary(*var));
12224       assert(EPSZ(constant, 1e-06) || EPSEQ(constant, 1.0, 1e-06));
12225       assert(EPSZ(constant, 1e-06) == ((*negated) == orignegated));
12226 
12227       return SCIP_OKAY;
12228    }
12229    else
12230    {
12231       SCIPerrorMessage("active variable path leads to NULL pointer\n");
12232       return SCIP_INVALIDDATA;
12233    }
12234 }
12235 
12236 /** transforms given variable, boundtype and bound to the corresponding active, fixed, or multi-aggregated variable
12237  *  values
12238  */
SCIPvarGetProbvarBound(SCIP_VAR ** var,SCIP_Real * bound,SCIP_BOUNDTYPE * boundtype)12239 SCIP_RETCODE SCIPvarGetProbvarBound(
12240    SCIP_VAR**            var,                /**< pointer to problem variable */
12241    SCIP_Real*            bound,              /**< pointer to bound value to transform */
12242    SCIP_BOUNDTYPE*       boundtype           /**< pointer to type of bound: lower or upper bound */
12243    )
12244 {
12245    assert(var != NULL);
12246    assert(*var != NULL);
12247    assert(bound != NULL);
12248    assert(boundtype != NULL);
12249 
12250    SCIPdebugMessage("get probvar bound %g of type %d of variable <%s>\n", *bound, *boundtype, (*var)->name);
12251 
12252    switch( SCIPvarGetStatus(*var) )
12253    {
12254    case SCIP_VARSTATUS_ORIGINAL:
12255       if( (*var)->data.original.transvar == NULL )
12256       {
12257          SCIPerrorMessage("original variable has no transformed variable attached\n");
12258          return SCIP_INVALIDDATA;
12259       }
12260       *var = (*var)->data.original.transvar;
12261       SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12262       break;
12263 
12264    case SCIP_VARSTATUS_LOOSE:
12265    case SCIP_VARSTATUS_COLUMN:
12266    case SCIP_VARSTATUS_FIXED:
12267       break;
12268 
12269    case SCIP_VARSTATUS_MULTAGGR:
12270       /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12271       if ( (*var)->data.multaggr.nvars == 1 )
12272       {
12273          assert( (*var)->data.multaggr.vars != NULL );
12274          assert( (*var)->data.multaggr.scalars != NULL );
12275          assert( (*var)->data.multaggr.scalars[0] != 0.0 );
12276 
12277          (*bound) /= (*var)->data.multaggr.scalars[0];
12278          (*bound) -= (*var)->data.multaggr.constant/(*var)->data.multaggr.scalars[0];
12279          if ( (*var)->data.multaggr.scalars[0] < 0.0 )
12280          {
12281             if ( *boundtype == SCIP_BOUNDTYPE_LOWER )
12282                *boundtype = SCIP_BOUNDTYPE_UPPER;
12283             else
12284                *boundtype = SCIP_BOUNDTYPE_LOWER;
12285          }
12286          *var = (*var)->data.multaggr.vars[0];
12287          SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12288       }
12289       break;
12290 
12291    case SCIP_VARSTATUS_AGGREGATED:  /* x = a*y + c  ->  y = x/a - c/a */
12292       assert((*var)->data.aggregate.var != NULL);
12293       assert((*var)->data.aggregate.scalar != 0.0);
12294 
12295       (*bound) /= (*var)->data.aggregate.scalar;
12296       (*bound) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
12297       if( (*var)->data.aggregate.scalar < 0.0 )
12298       {
12299          if( *boundtype == SCIP_BOUNDTYPE_LOWER )
12300             *boundtype = SCIP_BOUNDTYPE_UPPER;
12301          else
12302             *boundtype = SCIP_BOUNDTYPE_LOWER;
12303       }
12304       *var = (*var)->data.aggregate.var;
12305       SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12306       break;
12307 
12308    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
12309       assert((*var)->negatedvar != NULL);
12310       assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
12311       assert((*var)->negatedvar->negatedvar == *var);
12312       (*bound) = (*var)->data.negate.constant - *bound;
12313       if( *boundtype == SCIP_BOUNDTYPE_LOWER )
12314          *boundtype = SCIP_BOUNDTYPE_UPPER;
12315       else
12316          *boundtype = SCIP_BOUNDTYPE_LOWER;
12317       *var = (*var)->negatedvar;
12318       SCIP_CALL( SCIPvarGetProbvarBound(var, bound, boundtype) );
12319       break;
12320 
12321    default:
12322       SCIPerrorMessage("unknown variable status\n");
12323       return SCIP_INVALIDDATA;
12324    }
12325 
12326    return SCIP_OKAY;
12327 }
12328 
12329 /** transforms given variable and domain hole to the corresponding active, fixed, or multi-aggregated variable
12330  *  values
12331  */
SCIPvarGetProbvarHole(SCIP_VAR ** var,SCIP_Real * left,SCIP_Real * right)12332 SCIP_RETCODE SCIPvarGetProbvarHole(
12333    SCIP_VAR**            var,                /**< pointer to problem variable */
12334    SCIP_Real*            left,               /**< pointer to left bound of open interval in hole to transform */
12335    SCIP_Real*            right               /**< pointer to right bound of open interval in hole to transform */
12336    )
12337 {
12338    assert(var != NULL);
12339    assert(*var != NULL);
12340    assert(left != NULL);
12341    assert(right != NULL);
12342 
12343    SCIPdebugMessage("get probvar hole (%g,%g) of variable <%s>\n", *left, *right, (*var)->name);
12344 
12345    switch( SCIPvarGetStatus(*var) )
12346    {
12347    case SCIP_VARSTATUS_ORIGINAL:
12348       if( (*var)->data.original.transvar == NULL )
12349       {
12350          SCIPerrorMessage("original variable has no transformed variable attached\n");
12351          return SCIP_INVALIDDATA;
12352       }
12353       *var = (*var)->data.original.transvar;
12354       SCIP_CALL( SCIPvarGetProbvarHole(var, left, right) );
12355       break;
12356 
12357    case SCIP_VARSTATUS_LOOSE:
12358    case SCIP_VARSTATUS_COLUMN:
12359    case SCIP_VARSTATUS_FIXED:
12360    case SCIP_VARSTATUS_MULTAGGR:
12361       break;
12362 
12363    case SCIP_VARSTATUS_AGGREGATED:  /* x = a*y + c  ->  y = x/a - c/a */
12364       assert((*var)->data.aggregate.var != NULL);
12365       assert((*var)->data.aggregate.scalar != 0.0);
12366 
12367       /* scale back */
12368       (*left) /= (*var)->data.aggregate.scalar;
12369       (*right) /= (*var)->data.aggregate.scalar;
12370 
12371       /* shift back */
12372       (*left) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
12373       (*right) -= (*var)->data.aggregate.constant/(*var)->data.aggregate.scalar;
12374 
12375       *var = (*var)->data.aggregate.var;
12376 
12377       /* check if the  interval bounds have to swapped */
12378       if( (*var)->data.aggregate.scalar < 0.0 )
12379       {
12380          SCIP_CALL( SCIPvarGetProbvarHole(var, right, left) );
12381       }
12382       else
12383       {
12384          SCIP_CALL( SCIPvarGetProbvarHole(var, left, right) );
12385       }
12386       break;
12387 
12388    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
12389       assert((*var)->negatedvar != NULL);
12390       assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
12391       assert((*var)->negatedvar->negatedvar == *var);
12392 
12393       /* shift and scale back */
12394       (*left) = (*var)->data.negate.constant - (*left);
12395       (*right) = (*var)->data.negate.constant - (*right);
12396 
12397       *var = (*var)->negatedvar;
12398 
12399       /* through the negated variable the left and right interval bound have to swapped */
12400       SCIP_CALL( SCIPvarGetProbvarHole(var, right, left) );
12401       break;
12402 
12403    default:
12404       SCIPerrorMessage("unknown variable status\n");
12405       return SCIP_INVALIDDATA;
12406    }
12407 
12408    return SCIP_OKAY;
12409 }
12410 
12411 /** transforms given variable, scalar and constant to the corresponding active, fixed, or
12412  *  multi-aggregated variable, scalar and constant; if the variable resolves to a fixed variable,
12413  *  "scalar" will be 0.0 and the value of the sum will be stored in "constant"; a multi-aggregation
12414  *  with only one active variable (this can happen due to fixings after the multi-aggregation),
12415  *  is treated like an aggregation; if the multi-aggregation constant is infinite, "scalar" will be 0.0
12416  */
SCIPvarGetProbvarSum(SCIP_VAR ** var,SCIP_SET * set,SCIP_Real * scalar,SCIP_Real * constant)12417 SCIP_RETCODE SCIPvarGetProbvarSum(
12418    SCIP_VAR**            var,                /**< pointer to problem variable x in sum a*x + c */
12419    SCIP_SET*             set,                /**< global SCIP settings */
12420    SCIP_Real*            scalar,             /**< pointer to scalar a in sum a*x + c */
12421    SCIP_Real*            constant            /**< pointer to constant c in sum a*x + c */
12422    )
12423 {
12424    assert(var != NULL);
12425    assert(scalar != NULL);
12426    assert(constant != NULL);
12427 
12428    while( *var != NULL )
12429    {
12430       switch( SCIPvarGetStatus(*var) )
12431       {
12432       case SCIP_VARSTATUS_ORIGINAL:
12433          if( (*var)->data.original.transvar == NULL )
12434          {
12435             SCIPerrorMessage("original variable has no transformed variable attached\n");
12436             return SCIP_INVALIDDATA;
12437          }
12438          *var = (*var)->data.original.transvar;
12439          break;
12440 
12441       case SCIP_VARSTATUS_LOOSE:
12442       case SCIP_VARSTATUS_COLUMN:
12443          return SCIP_OKAY;
12444 
12445       case SCIP_VARSTATUS_FIXED:       /* x = c'          =>  a*x + c ==             (a*c' + c) */
12446          if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12447          {
12448             if( SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)) )
12449             {
12450                assert(*scalar != 0.0);
12451                if( (*scalar) * (*var)->glbdom.lb > 0.0 )
12452                   (*constant) = SCIPsetInfinity(set);
12453                else
12454                   (*constant) = -SCIPsetInfinity(set);
12455             }
12456             else
12457                (*constant) += *scalar * (*var)->glbdom.lb;
12458          }
12459 #ifndef NDEBUG
12460          else
12461          {
12462             assert(!SCIPsetIsInfinity(set, (*constant)) || !((*scalar) * (*var)->glbdom.lb < 0.0 &&
12463                   (SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)))));
12464             assert(!SCIPsetIsInfinity(set, -(*constant)) || !((*scalar) * (*var)->glbdom.lb > 0.0 &&
12465                   (SCIPsetIsInfinity(set, (*var)->glbdom.lb) || SCIPsetIsInfinity(set, -((*var)->glbdom.lb)))));
12466          }
12467 #endif
12468          *scalar = 0.0;
12469          return SCIP_OKAY;
12470 
12471       case SCIP_VARSTATUS_MULTAGGR:
12472          /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
12473          if ( (*var)->data.multaggr.nvars == 1 )
12474          {
12475             assert((*var)->data.multaggr.vars != NULL);
12476             assert((*var)->data.multaggr.scalars != NULL);
12477             assert((*var)->data.multaggr.vars[0] != NULL);
12478             if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12479             {
12480                /* the multi-aggregation constant can be infinite, if one of the multi-aggregation variables
12481                 * was fixed to +/-infinity; ensure that the constant is set to +/-infinity, too, and the scalar
12482                 * is set to 0.0, because the multi-aggregated variable can be seen as fixed, too
12483                 */
12484                if( SCIPsetIsInfinity(set, (*var)->data.multaggr.constant)
12485                   || SCIPsetIsInfinity(set, -((*var)->data.multaggr.constant)) )
12486                {
12487                   if( (*scalar) * (*var)->data.multaggr.constant > 0 )
12488                   {
12489                      assert(!SCIPsetIsInfinity(set, -(*constant)));
12490                      (*constant) = SCIPsetInfinity(set);
12491                   }
12492                   else
12493                   {
12494                      assert(!SCIPsetIsInfinity(set, *constant));
12495                      (*constant) = -SCIPsetInfinity(set);
12496                   }
12497                   (*scalar) = 0.0;
12498                }
12499                else
12500                   (*constant) += *scalar * (*var)->data.multaggr.constant;
12501             }
12502             (*scalar) *= (*var)->data.multaggr.scalars[0];
12503             *var = (*var)->data.multaggr.vars[0];
12504             break;
12505          }
12506          return SCIP_OKAY;
12507 
12508       case SCIP_VARSTATUS_AGGREGATED:  /* x = a'*x' + c'  =>  a*x + c == (a*a')*x' + (a*c' + c) */
12509          assert((*var)->data.aggregate.var != NULL);
12510          assert(!SCIPsetIsInfinity(set, (*var)->data.aggregate.constant)
12511             && !SCIPsetIsInfinity(set, (*var)->data.aggregate.constant));
12512          if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12513             (*constant) += *scalar * (*var)->data.aggregate.constant;
12514          (*scalar) *= (*var)->data.aggregate.scalar;
12515          *var = (*var)->data.aggregate.var;
12516          break;
12517 
12518       case SCIP_VARSTATUS_NEGATED:     /* x =  - x' + c'  =>  a*x + c ==   (-a)*x' + (a*c' + c) */
12519          assert((*var)->negatedvar != NULL);
12520          assert(SCIPvarGetStatus((*var)->negatedvar) != SCIP_VARSTATUS_NEGATED);
12521          assert((*var)->negatedvar->negatedvar == *var);
12522          assert(!SCIPsetIsInfinity(set, (*var)->data.negate.constant)
12523             && !SCIPsetIsInfinity(set, (*var)->data.negate.constant));
12524          if( !SCIPsetIsInfinity(set, (*constant)) && !SCIPsetIsInfinity(set, -(*constant)) )
12525             (*constant) += *scalar * (*var)->data.negate.constant;
12526          (*scalar) *= -1.0;
12527          *var = (*var)->negatedvar;
12528          break;
12529 
12530       default:
12531          SCIPerrorMessage("unknown variable status\n");
12532 	 SCIPABORT();
12533          return SCIP_INVALIDDATA; /*lint !e527*/
12534       }
12535    }
12536    *scalar = 0.0;
12537 
12538    return SCIP_OKAY;
12539 }
12540 
12541 /** retransforms given variable, scalar and constant to the corresponding original variable, scalar
12542  *  and constant, if possible; if the retransformation is impossible, NULL is returned as variable
12543  */
SCIPvarGetOrigvarSum(SCIP_VAR ** var,SCIP_Real * scalar,SCIP_Real * constant)12544 SCIP_RETCODE SCIPvarGetOrigvarSum(
12545    SCIP_VAR**            var,                /**< pointer to problem variable x in sum a*x + c */
12546    SCIP_Real*            scalar,             /**< pointer to scalar a in sum a*x + c */
12547    SCIP_Real*            constant            /**< pointer to constant c in sum a*x + c */
12548    )
12549 {
12550    SCIP_VAR* parentvar;
12551 
12552    assert(var != NULL);
12553    assert(*var != NULL);
12554    assert(scalar != NULL);
12555    assert(constant != NULL);
12556 
12557    while( !SCIPvarIsOriginal(*var) )
12558    {
12559       /* if the variable has no parent variables, it was generated during solving and has no corresponding original
12560        * var
12561        */
12562       if( (*var)->nparentvars == 0 )
12563       {
12564          /* negated variables do not need to have a parent variables, and negated variables can exist in original
12565           * space
12566           */
12567          if( SCIPvarGetStatus(*var) == SCIP_VARSTATUS_NEGATED &&
12568             ((*var)->negatedvar->nparentvars == 0 || (*var)->negatedvar->parentvars[0] != *var) )
12569          {
12570             *scalar *= -1.0;
12571             *constant -= (*var)->data.negate.constant * (*scalar);
12572             *var = (*var)->negatedvar;
12573 
12574             continue;
12575          }
12576          /* if the variables does not have any parent the variables was created during solving and has no original
12577           * counterpart
12578           */
12579          else
12580          {
12581             *var = NULL;
12582 
12583             return SCIP_OKAY;
12584          }
12585       }
12586 
12587       /* follow the link to the first parent variable */
12588       parentvar = (*var)->parentvars[0];
12589       assert(parentvar != NULL);
12590 
12591       switch( SCIPvarGetStatus(parentvar) )
12592       {
12593       case SCIP_VARSTATUS_ORIGINAL:
12594          break;
12595 
12596       case SCIP_VARSTATUS_COLUMN:
12597       case SCIP_VARSTATUS_LOOSE:
12598       case SCIP_VARSTATUS_FIXED:
12599       case SCIP_VARSTATUS_MULTAGGR:
12600          SCIPerrorMessage("column, loose, fixed or multi-aggregated variable cannot be the parent of a variable\n");
12601          return SCIP_INVALIDDATA;
12602 
12603       case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + b  ->  y = (x-b)/a,  s*y + c = (s/a)*x + c-b*s/a */
12604          assert(parentvar->data.aggregate.var == *var);
12605          assert(parentvar->data.aggregate.scalar != 0.0);
12606          *scalar /= parentvar->data.aggregate.scalar;
12607          *constant -= parentvar->data.aggregate.constant * (*scalar);
12608          break;
12609 
12610       case SCIP_VARSTATUS_NEGATED: /* x = b - y  ->  y = b - x,  s*y + c = -s*x + c+b*s */
12611          assert(parentvar->negatedvar != NULL);
12612          assert(SCIPvarGetStatus(parentvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
12613          assert(parentvar->negatedvar->negatedvar == parentvar);
12614          *scalar *= -1.0;
12615          *constant -= parentvar->data.negate.constant * (*scalar);
12616          break;
12617 
12618       default:
12619          SCIPerrorMessage("unknown variable status\n");
12620          return SCIP_INVALIDDATA;
12621       }
12622 
12623       assert( parentvar != NULL );
12624       *var = parentvar;
12625    }
12626 
12627    return SCIP_OKAY;
12628 }
12629 
12630 /** returns whether the given variable is the direct counterpart of an original problem variable */
SCIPvarIsTransformedOrigvar(SCIP_VAR * var)12631 SCIP_Bool SCIPvarIsTransformedOrigvar(
12632    SCIP_VAR*             var                 /**< problem variable */
12633    )
12634 {
12635    SCIP_VAR* parentvar;
12636    assert(var != NULL);
12637 
12638    if( !SCIPvarIsTransformed(var) || var->nparentvars < 1 )
12639       return FALSE;
12640 
12641    assert(var->parentvars != NULL);
12642    parentvar = var->parentvars[0];
12643    assert(parentvar != NULL);
12644 
12645    /* we follow the aggregation tree to the root unless an original variable has been found - the first entries in the parentlist are candidates */
12646    while( parentvar->nparentvars >= 1 && SCIPvarGetStatus(parentvar) != SCIP_VARSTATUS_ORIGINAL )
12647       parentvar = parentvar->parentvars[0];
12648    assert( parentvar != NULL );
12649 
12650    return ( SCIPvarGetStatus(parentvar) == SCIP_VARSTATUS_ORIGINAL );
12651 }
12652 
12653 /** gets objective value of variable in current SCIP_LP; the value can be different from the objective value stored in
12654  *  the variable's own data due to diving, that operate only on the LP without updating the variables
12655  */
SCIPvarGetObjLP(SCIP_VAR * var)12656 SCIP_Real SCIPvarGetObjLP(
12657    SCIP_VAR*             var                 /**< problem variable */
12658    )
12659 {
12660    assert(var != NULL);
12661 
12662    /* get bounds of attached variables */
12663    switch( SCIPvarGetStatus(var) )
12664    {
12665    case SCIP_VARSTATUS_ORIGINAL:
12666       assert(var->data.original.transvar != NULL);
12667       return SCIPvarGetObjLP(var->data.original.transvar);
12668 
12669    case SCIP_VARSTATUS_COLUMN:
12670       assert(var->data.col != NULL);
12671       return SCIPcolGetObj(var->data.col);
12672 
12673    case SCIP_VARSTATUS_LOOSE:
12674    case SCIP_VARSTATUS_FIXED:
12675       return var->obj;
12676 
12677    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
12678       assert(var->data.aggregate.var != NULL);
12679       return var->data.aggregate.scalar * SCIPvarGetObjLP(var->data.aggregate.var);
12680 
12681    case SCIP_VARSTATUS_MULTAGGR:
12682       SCIPerrorMessage("cannot get the objective value of a multiple aggregated variable\n");
12683       SCIPABORT();
12684       return 0.0; /*lint !e527*/
12685 
12686    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
12687       assert(var->negatedvar != NULL);
12688       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
12689       assert(var->negatedvar->negatedvar == var);
12690       return -SCIPvarGetObjLP(var->negatedvar);
12691 
12692    default:
12693       SCIPerrorMessage("unknown variable status\n");
12694       SCIPABORT();
12695       return 0.0; /*lint !e527*/
12696    }
12697 }
12698 
12699 /** gets lower bound of variable in current SCIP_LP; the bound can be different from the bound stored in the variable's own
12700  *  data due to diving or conflict analysis, that operate only on the LP without updating the variables
12701  */
SCIPvarGetLbLP(SCIP_VAR * var,SCIP_SET * set)12702 SCIP_Real SCIPvarGetLbLP(
12703    SCIP_VAR*             var,                /**< problem variable */
12704    SCIP_SET*             set                 /**< global SCIP settings */
12705    )
12706 {
12707    assert(var != NULL);
12708    assert(set != NULL);
12709    assert(var->scip == set->scip);
12710 
12711    /* get bounds of attached variables */
12712    switch( SCIPvarGetStatus(var) )
12713    {
12714    case SCIP_VARSTATUS_ORIGINAL:
12715       assert(var->data.original.transvar != NULL);
12716       return SCIPvarGetLbLP(var->data.original.transvar, set);
12717 
12718    case SCIP_VARSTATUS_COLUMN:
12719       assert(var->data.col != NULL);
12720       return SCIPcolGetLb(var->data.col);
12721 
12722    case SCIP_VARSTATUS_LOOSE:
12723    case SCIP_VARSTATUS_FIXED:
12724       return var->locdom.lb;
12725 
12726    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
12727       assert(var->data.aggregate.var != NULL);
12728       if( (var->data.aggregate.scalar > 0.0 && SCIPsetIsInfinity(set, -SCIPvarGetLbLP(var->data.aggregate.var, set)))
12729          || (var->data.aggregate.scalar < 0.0 && SCIPsetIsInfinity(set, SCIPvarGetUbLP(var->data.aggregate.var, set))) )
12730       {
12731          return -SCIPsetInfinity(set);
12732       }
12733       else if( var->data.aggregate.scalar > 0.0 )
12734       {
12735          /* a > 0 -> get lower bound of y */
12736          return var->data.aggregate.scalar * SCIPvarGetLbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
12737       }
12738       else if( var->data.aggregate.scalar < 0.0 )
12739       {
12740          /* a < 0 -> get upper bound of y */
12741          return var->data.aggregate.scalar * SCIPvarGetUbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
12742       }
12743       else
12744       {
12745          SCIPerrorMessage("scalar is zero in aggregation\n");
12746          SCIPABORT();
12747          return SCIP_INVALID; /*lint !e527*/
12748       }
12749 
12750    case SCIP_VARSTATUS_MULTAGGR:
12751       /**@todo get the sides of the corresponding linear constraint */
12752       SCIPerrorMessage("getting the bounds of a multiple aggregated variable is not implemented yet\n");
12753       SCIPABORT();
12754       return SCIP_INVALID; /*lint !e527*/
12755 
12756    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
12757       assert(var->negatedvar != NULL);
12758       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
12759       assert(var->negatedvar->negatedvar == var);
12760       return var->data.negate.constant - SCIPvarGetUbLP(var->negatedvar, set);
12761 
12762    default:
12763       SCIPerrorMessage("unknown variable status\n");
12764       SCIPABORT();
12765       return SCIP_INVALID; /*lint !e527*/
12766    }
12767 }
12768 
12769 /** gets upper bound of variable in current SCIP_LP; the bound can be different from the bound stored in the variable's own
12770  *  data due to diving or conflict analysis, that operate only on the LP without updating the variables
12771  */
SCIPvarGetUbLP(SCIP_VAR * var,SCIP_SET * set)12772 SCIP_Real SCIPvarGetUbLP(
12773    SCIP_VAR*             var,                /**< problem variable */
12774    SCIP_SET*             set                 /**< global SCIP settings */
12775    )
12776 {
12777    assert(var != NULL);
12778    assert(set != NULL);
12779    assert(var->scip == set->scip);
12780 
12781    /* get bounds of attached variables */
12782    switch( SCIPvarGetStatus(var) )
12783    {
12784    case SCIP_VARSTATUS_ORIGINAL:
12785       assert(var->data.original.transvar != NULL);
12786       return SCIPvarGetUbLP(var->data.original.transvar, set);
12787 
12788    case SCIP_VARSTATUS_COLUMN:
12789       assert(var->data.col != NULL);
12790       return SCIPcolGetUb(var->data.col);
12791 
12792    case SCIP_VARSTATUS_LOOSE:
12793    case SCIP_VARSTATUS_FIXED:
12794       return var->locdom.ub;
12795 
12796    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
12797       assert(var->data.aggregate.var != NULL);
12798       if( (var->data.aggregate.scalar > 0.0 && SCIPsetIsInfinity(set, SCIPvarGetUbLP(var->data.aggregate.var, set)))
12799          || (var->data.aggregate.scalar < 0.0 && SCIPsetIsInfinity(set, -SCIPvarGetLbLP(var->data.aggregate.var, set))) )
12800       {
12801          return SCIPsetInfinity(set);
12802       }
12803       if( var->data.aggregate.scalar > 0.0 )
12804       {
12805          /* a > 0 -> get upper bound of y */
12806          return var->data.aggregate.scalar * SCIPvarGetUbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
12807       }
12808       else if( var->data.aggregate.scalar < 0.0 )
12809       {
12810          /* a < 0 -> get lower bound of y */
12811          return var->data.aggregate.scalar * SCIPvarGetLbLP(var->data.aggregate.var, set) + var->data.aggregate.constant;
12812       }
12813       else
12814       {
12815          SCIPerrorMessage("scalar is zero in aggregation\n");
12816          SCIPABORT();
12817          return SCIP_INVALID; /*lint !e527*/
12818       }
12819 
12820    case SCIP_VARSTATUS_MULTAGGR:
12821       SCIPerrorMessage("cannot get the bounds of a multi-aggregated variable.\n");
12822       SCIPABORT();
12823       return SCIP_INVALID; /*lint !e527*/
12824 
12825    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
12826       assert(var->negatedvar != NULL);
12827       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
12828       assert(var->negatedvar->negatedvar == var);
12829       return var->data.negate.constant - SCIPvarGetLbLP(var->negatedvar, set);
12830 
12831    default:
12832       SCIPerrorMessage("unknown variable status\n");
12833       SCIPABORT();
12834       return SCIP_INVALID; /*lint !e527*/
12835    }
12836 }
12837 
12838 /** gets primal LP solution value of variable */
SCIPvarGetLPSol_rec(SCIP_VAR * var)12839 SCIP_Real SCIPvarGetLPSol_rec(
12840    SCIP_VAR*             var                 /**< problem variable */
12841    )
12842 {
12843    assert(var != NULL);
12844 
12845    switch( SCIPvarGetStatus(var) )
12846    {
12847    case SCIP_VARSTATUS_ORIGINAL:
12848       if( var->data.original.transvar == NULL )
12849          return SCIP_INVALID;
12850       return SCIPvarGetLPSol(var->data.original.transvar);
12851 
12852    case SCIP_VARSTATUS_LOOSE:
12853       return SCIPvarGetBestBoundLocal(var);
12854 
12855    case SCIP_VARSTATUS_COLUMN:
12856       assert(var->data.col != NULL);
12857       return SCIPcolGetPrimsol(var->data.col);
12858 
12859    case SCIP_VARSTATUS_FIXED:
12860       assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
12861       return var->locdom.lb;
12862 
12863    case SCIP_VARSTATUS_AGGREGATED:
12864    {
12865       SCIP_Real lpsolval;
12866 
12867       assert(var->data.aggregate.var != NULL);
12868       lpsolval = SCIPvarGetLPSol(var->data.aggregate.var);
12869 
12870       /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
12871        * corresponding infinity value instead of performing an arithmetical transformation (compare method
12872        * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
12873        * (or is called by) a public interface method; instead, we only assert that values are finite
12874        * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
12875        * positives and negatives if the parameter <numerics/infinity> is modified by the user
12876        */
12877       assert(lpsolval > -SCIP_DEFAULT_INFINITY);
12878       assert(lpsolval < +SCIP_DEFAULT_INFINITY);
12879       return var->data.aggregate.scalar * lpsolval + var->data.aggregate.constant;
12880    }
12881    case SCIP_VARSTATUS_MULTAGGR:
12882    {
12883       SCIP_Real primsol;
12884       int i;
12885 
12886       assert(!var->donotmultaggr);
12887       assert(var->data.multaggr.vars != NULL);
12888       assert(var->data.multaggr.scalars != NULL);
12889       /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
12890        * assert(var->data.multaggr.nvars >= 2);
12891        */
12892       primsol = var->data.multaggr.constant;
12893       for( i = 0; i < var->data.multaggr.nvars; ++i )
12894          primsol += var->data.multaggr.scalars[i] * SCIPvarGetLPSol(var->data.multaggr.vars[i]);
12895       return primsol;
12896    }
12897    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
12898       assert(var->negatedvar != NULL);
12899       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
12900       assert(var->negatedvar->negatedvar == var);
12901       return var->data.negate.constant - SCIPvarGetLPSol(var->negatedvar);
12902 
12903    default:
12904       SCIPerrorMessage("unknown variable status\n");
12905       SCIPABORT();
12906       return SCIP_INVALID; /*lint !e527*/
12907    }
12908 }
12909 
12910 /** gets primal NLP solution value of variable */
SCIPvarGetNLPSol_rec(SCIP_VAR * var)12911 SCIP_Real SCIPvarGetNLPSol_rec(
12912    SCIP_VAR*             var                 /**< problem variable */
12913    )
12914 {
12915    SCIP_Real solval;
12916    int i;
12917 
12918    assert(var != NULL);
12919 
12920    /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */
12921    switch( SCIPvarGetStatus(var) )
12922    {
12923    case SCIP_VARSTATUS_ORIGINAL:
12924       return SCIPvarGetNLPSol(var->data.original.transvar);
12925 
12926    case SCIP_VARSTATUS_LOOSE:
12927    case SCIP_VARSTATUS_COLUMN:
12928          return var->nlpsol;
12929 
12930    case SCIP_VARSTATUS_FIXED:
12931       assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var));  /*lint !e777*/
12932       assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var));    /*lint !e777*/
12933       assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var));   /*lint !e777*/
12934       return SCIPvarGetLbGlobal(var);
12935 
12936    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  =>  y = (x-c)/a */
12937       solval = SCIPvarGetNLPSol(var->data.aggregate.var);
12938       return var->data.aggregate.scalar * solval + var->data.aggregate.constant;
12939 
12940    case SCIP_VARSTATUS_MULTAGGR:
12941       solval = var->data.multaggr.constant;
12942       for( i = 0; i < var->data.multaggr.nvars; ++i )
12943          solval += var->data.multaggr.scalars[i] * SCIPvarGetNLPSol(var->data.multaggr.vars[i]);
12944       return solval;
12945 
12946    case SCIP_VARSTATUS_NEGATED:
12947       solval = SCIPvarGetNLPSol(var->negatedvar);
12948       return var->data.negate.constant - solval;
12949 
12950    default:
12951       SCIPerrorMessage("unknown variable status\n");
12952       SCIPABORT();
12953       return SCIP_INVALID; /*lint !e527*/
12954    }
12955 }
12956 
12957 /** gets pseudo solution value of variable at current node */
12958 static
SCIPvarGetPseudoSol_rec(SCIP_VAR * var)12959 SCIP_Real SCIPvarGetPseudoSol_rec(
12960    SCIP_VAR*             var                 /**< problem variable */
12961    )
12962 {
12963    SCIP_Real pseudosol;
12964    int i;
12965 
12966    assert(var != NULL);
12967 
12968    switch( SCIPvarGetStatus(var) )
12969    {
12970    case SCIP_VARSTATUS_ORIGINAL:
12971       if( var->data.original.transvar == NULL )
12972          return SCIP_INVALID;
12973       return SCIPvarGetPseudoSol(var->data.original.transvar);
12974 
12975    case SCIP_VARSTATUS_LOOSE:
12976    case SCIP_VARSTATUS_COLUMN:
12977       return SCIPvarGetBestBoundLocal(var);
12978 
12979    case SCIP_VARSTATUS_FIXED:
12980       assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
12981       return var->locdom.lb;
12982 
12983    case SCIP_VARSTATUS_AGGREGATED:
12984    {
12985       SCIP_Real pseudosolval;
12986       assert(var->data.aggregate.var != NULL);
12987       /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
12988        * corresponding infinity value instead of performing an arithmetical transformation (compare method
12989        * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
12990        * (or is called by) a public interface method; instead, we only assert that values are finite
12991        * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
12992        * positives and negatives if the parameter <numerics/infinity> is modified by the user
12993        */
12994       pseudosolval = SCIPvarGetPseudoSol(var->data.aggregate.var);
12995       assert(pseudosolval > -SCIP_DEFAULT_INFINITY);
12996       assert(pseudosolval < +SCIP_DEFAULT_INFINITY);
12997       return var->data.aggregate.scalar * pseudosolval + var->data.aggregate.constant;
12998    }
12999    case SCIP_VARSTATUS_MULTAGGR:
13000       assert(!var->donotmultaggr);
13001       assert(var->data.multaggr.vars != NULL);
13002       assert(var->data.multaggr.scalars != NULL);
13003       /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13004        * assert(var->data.multaggr.nvars >= 2);
13005        */
13006       pseudosol = var->data.multaggr.constant;
13007       for( i = 0; i < var->data.multaggr.nvars; ++i )
13008          pseudosol += var->data.multaggr.scalars[i] * SCIPvarGetPseudoSol(var->data.multaggr.vars[i]);
13009       return pseudosol;
13010 
13011    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
13012       assert(var->negatedvar != NULL);
13013       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
13014       assert(var->negatedvar->negatedvar == var);
13015       return var->data.negate.constant - SCIPvarGetPseudoSol(var->negatedvar);
13016 
13017    default:
13018       SCIPerrorMessage("unknown variable status\n");
13019       SCIPABORT();
13020       return SCIP_INVALID; /*lint !e527*/
13021    }
13022 }
13023 
13024 /** gets current LP or pseudo solution value of variable */
SCIPvarGetSol(SCIP_VAR * var,SCIP_Bool getlpval)13025 SCIP_Real SCIPvarGetSol(
13026    SCIP_VAR*             var,                /**< problem variable */
13027    SCIP_Bool             getlpval            /**< should the LP solution value be returned? */
13028    )
13029 {
13030    if( getlpval )
13031       return SCIPvarGetLPSol(var);
13032    else
13033       return SCIPvarGetPseudoSol(var);
13034 }
13035 
13036 /** remembers the current solution as root solution in the problem variables */
SCIPvarStoreRootSol(SCIP_VAR * var,SCIP_Bool roothaslp)13037 void SCIPvarStoreRootSol(
13038    SCIP_VAR*             var,                /**< problem variable */
13039    SCIP_Bool             roothaslp           /**< is the root solution from LP? */
13040    )
13041 {
13042    assert(var != NULL);
13043 
13044    var->rootsol = SCIPvarGetSol(var, roothaslp);
13045 }
13046 
13047 /** updates the current solution as best root solution of the given variable if it is better */
SCIPvarUpdateBestRootSol(SCIP_VAR * var,SCIP_SET * set,SCIP_Real rootsol,SCIP_Real rootredcost,SCIP_Real rootlpobjval)13048 void SCIPvarUpdateBestRootSol(
13049    SCIP_VAR*             var,                /**< problem variable */
13050    SCIP_SET*             set,                /**< global SCIP settings */
13051    SCIP_Real             rootsol,            /**< root solution value */
13052    SCIP_Real             rootredcost,        /**< root reduced cost */
13053    SCIP_Real             rootlpobjval        /**< objective value of the root LP */
13054    )
13055 {
13056    assert(var != NULL);
13057    assert(set != NULL);
13058    assert(var->scip == set->scip);
13059 
13060    /* if reduced cost are zero nothing to update */
13061    if( SCIPsetIsDualfeasZero(set, rootredcost) )
13062       return;
13063 
13064    /* check if we have already a best combination stored */
13065    if( !SCIPsetIsDualfeasZero(set, var->bestrootredcost) )
13066    {
13067       SCIP_Real currcutoffbound;
13068       SCIP_Real cutoffbound;
13069       SCIP_Real bound;
13070 
13071       /* compute the cutoff bound which would improve the corresponding bound with the current stored root solution,
13072        * root reduced cost, and root LP objective value combination
13073        */
13074       if( var->bestrootredcost > 0.0 )
13075          bound = SCIPvarGetUbGlobal(var);
13076       else
13077          bound = SCIPvarGetLbGlobal(var);
13078 
13079       currcutoffbound = (bound - var->bestrootsol) * var->bestrootredcost + var->bestrootlpobjval;
13080 
13081       /* compute the cutoff bound which would improve the corresponding bound with new root solution, root reduced
13082        * cost, and root LP objective value combination
13083        */
13084       if( rootredcost > 0.0 )
13085          bound = SCIPvarGetUbGlobal(var);
13086       else
13087          bound = SCIPvarGetLbGlobal(var);
13088 
13089       cutoffbound = (bound - rootsol) * rootredcost + rootlpobjval;
13090 
13091       /* check if an improving root solution, root reduced cost, and root LP objective value is at hand */
13092       if( cutoffbound > currcutoffbound )
13093       {
13094          SCIPsetDebugMsg(set, "-> <%s> update potential cutoff bound <%g> -> <%g>\n",
13095             SCIPvarGetName(var), currcutoffbound, cutoffbound);
13096 
13097          var->bestrootsol = rootsol;
13098          var->bestrootredcost = rootredcost;
13099          var->bestrootlpobjval = rootlpobjval;
13100       }
13101    }
13102    else
13103    {
13104       SCIPsetDebugMsg(set, "-> <%s> initialize best root reduced cost information\n", SCIPvarGetName(var));
13105       SCIPsetDebugMsg(set, "   -> rootsol <%g>\n", rootsol);
13106       SCIPsetDebugMsg(set, "   -> rootredcost <%g>\n", rootredcost);
13107       SCIPsetDebugMsg(set, "   -> rootlpobjval <%g>\n", rootlpobjval);
13108 
13109       var->bestrootsol = rootsol;
13110       var->bestrootredcost = rootredcost;
13111       var->bestrootlpobjval = rootlpobjval;
13112    }
13113 }
13114 
13115 /** returns the solution of the variable in the last root node's relaxation, if the root relaxation is not yet
13116  *  completely solved, zero is returned
13117  */
SCIPvarGetRootSol(SCIP_VAR * var)13118 SCIP_Real SCIPvarGetRootSol(
13119    SCIP_VAR*             var                 /**< problem variable */
13120    )
13121 {
13122    SCIP_Real rootsol;
13123    int i;
13124 
13125    assert(var != NULL);
13126 
13127    switch( SCIPvarGetStatus(var) )
13128    {
13129    case SCIP_VARSTATUS_ORIGINAL:
13130       if( var->data.original.transvar == NULL )
13131          return 0.0;
13132       return SCIPvarGetRootSol(var->data.original.transvar);
13133 
13134    case SCIP_VARSTATUS_LOOSE:
13135    case SCIP_VARSTATUS_COLUMN:
13136       return var->rootsol;
13137 
13138    case SCIP_VARSTATUS_FIXED:
13139       assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13140       return var->locdom.lb;
13141 
13142    case SCIP_VARSTATUS_AGGREGATED:
13143       assert(var->data.aggregate.var != NULL);
13144       /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
13145        * corresponding infinity value instead of performing an arithmetical transformation (compare method
13146        * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
13147        * (or is called by) a public interface method; instead, we only assert that values are finite
13148        * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
13149        * positives and negatives if the parameter <numerics/infinity> is modified by the user
13150        */
13151       assert(SCIPvarGetRootSol(var->data.aggregate.var) > -SCIP_DEFAULT_INFINITY);
13152       assert(SCIPvarGetRootSol(var->data.aggregate.var) < +SCIP_DEFAULT_INFINITY);
13153       return var->data.aggregate.scalar * SCIPvarGetRootSol(var->data.aggregate.var) + var->data.aggregate.constant;
13154 
13155    case SCIP_VARSTATUS_MULTAGGR:
13156       assert(!var->donotmultaggr);
13157       assert(var->data.multaggr.vars != NULL);
13158       assert(var->data.multaggr.scalars != NULL);
13159       /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13160        * assert(var->data.multaggr.nvars >= 2);
13161        */
13162       rootsol = var->data.multaggr.constant;
13163       for( i = 0; i < var->data.multaggr.nvars; ++i )
13164          rootsol += var->data.multaggr.scalars[i] * SCIPvarGetRootSol(var->data.multaggr.vars[i]);
13165       return rootsol;
13166 
13167    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
13168       assert(var->negatedvar != NULL);
13169       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
13170       assert(var->negatedvar->negatedvar == var);
13171       return var->data.negate.constant - SCIPvarGetRootSol(var->negatedvar);
13172 
13173    default:
13174       SCIPerrorMessage("unknown variable status\n");
13175       SCIPABORT();
13176       return SCIP_INVALID; /*lint !e527*/
13177    }
13178 }
13179 
13180 /** returns for given variable the reduced cost */
13181 static
getImplVarRedcost(SCIP_VAR * var,SCIP_SET * set,SCIP_Bool varfixing,SCIP_STAT * stat,SCIP_LP * lp)13182 SCIP_Real getImplVarRedcost(
13183    SCIP_VAR*             var,                /**< problem variable */
13184    SCIP_SET*             set,                /**< global SCIP settings */
13185    SCIP_Bool             varfixing,          /**< FALSE if for x == 0, TRUE for x == 1 */
13186    SCIP_STAT*            stat,               /**< problem statistics */
13187    SCIP_LP*              lp                  /**< current LP data */
13188    )
13189 {
13190    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
13191    {
13192       SCIP_COL* col;
13193       SCIP_Real primsol;
13194       SCIP_BASESTAT basestat;
13195       SCIP_Bool lpissolbasic;
13196 
13197       col = SCIPvarGetCol(var);
13198       assert(col != NULL);
13199 
13200       basestat = SCIPcolGetBasisStatus(col);
13201       lpissolbasic = SCIPlpIsSolBasic(lp);
13202       primsol = SCIPcolGetPrimsol(col);
13203 
13204       if( (lpissolbasic && (basestat == SCIP_BASESTAT_LOWER || basestat == SCIP_BASESTAT_UPPER)) ||
13205          (!lpissolbasic && (SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol) || SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol))) )
13206       {
13207          SCIP_Real redcost = SCIPcolGetRedcost(col, stat, lp);
13208 
13209          assert(((!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol)) ||
13210                (lpissolbasic && basestat == SCIP_BASESTAT_LOWER)) ? (!SCIPsetIsDualfeasNegative(set, redcost) ||
13211                   SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var))) : TRUE);
13212          assert(((!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol)) ||
13213                (lpissolbasic && basestat == SCIP_BASESTAT_UPPER)) ? (!SCIPsetIsDualfeasPositive(set, redcost) ||
13214                   SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var))) : TRUE);
13215 
13216          if( (varfixing && ((lpissolbasic && basestat == SCIP_BASESTAT_LOWER) ||
13217                   (!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol)))) ||
13218             (!varfixing && ((lpissolbasic && basestat == SCIP_BASESTAT_UPPER) ||
13219                   (!lpissolbasic && SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol)))) )
13220             return redcost;
13221          else
13222             return 0.0;
13223       }
13224 
13225       return 0.0;
13226    }
13227 
13228    return 0.0;
13229 }
13230 
13231 #define MAX_CLIQUELENGTH 50
13232 /** returns for the given binary variable the reduced cost which are given by the variable itself and its implication if
13233  *  the binary variable is fixed to the given value
13234  */
SCIPvarGetImplRedcost(SCIP_VAR * var,SCIP_SET * set,SCIP_Bool varfixing,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_LP * lp)13235 SCIP_Real SCIPvarGetImplRedcost(
13236    SCIP_VAR*             var,                /**< problem variable */
13237    SCIP_SET*             set,                /**< global SCIP settings */
13238    SCIP_Bool             varfixing,          /**< FALSE if for x == 0, TRUE for x == 1 */
13239    SCIP_STAT*            stat,               /**< problem statistics */
13240    SCIP_PROB*            prob,               /**< transformed problem, or NULL */
13241    SCIP_LP*              lp                  /**< current LP data */
13242    )
13243 {
13244    SCIP_Real implredcost;
13245    int ncliques;
13246    int nvars;
13247 
13248    assert(SCIPvarIsBinary(var));
13249    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
13250 
13251    /* get reduced cost of given variable */
13252    implredcost = getImplVarRedcost(var, set, varfixing, stat, lp);
13253 
13254 #ifdef SCIP_MORE_DEBUG
13255    SCIPsetDebugMsg(set, "variable <%s> itself has reduced cost of %g\n", SCIPvarGetName(var), implredcost);
13256 #endif
13257 
13258    /* the following algorithm is expensive */
13259    ncliques = SCIPvarGetNCliques(var, varfixing);
13260 
13261    if( ncliques > 0 )
13262    {
13263       SCIP_CLIQUE** cliques;
13264       SCIP_CLIQUE* clique;
13265       SCIP_VAR** clqvars;
13266       SCIP_VAR** probvars;
13267       SCIP_VAR* clqvar;
13268       SCIP_Bool* clqvalues;
13269       int* entries;
13270       int* ids;
13271       SCIP_Real redcost;
13272       SCIP_Bool cleanedup;
13273       int nclqvars;
13274       int nentries;
13275       int nids;
13276       int id;
13277       int c;
13278       int v;
13279 
13280       assert(prob != NULL);
13281       assert(SCIPprobIsTransformed(prob));
13282 
13283       nentries = SCIPprobGetNVars(prob) - SCIPprobGetNContVars(prob) + 1;
13284 
13285       SCIP_CALL_ABORT( SCIPsetAllocBufferArray(set, &ids, nentries) );
13286       nids = 0;
13287       SCIP_CALL_ABORT( SCIPsetAllocCleanBufferArray(set, &entries, nentries) );
13288 
13289       cliques = SCIPvarGetCliques(var, varfixing);
13290       assert(cliques != NULL);
13291 
13292       for( c = ncliques - 1; c >= 0; --c )
13293       {
13294          clique = cliques[c];
13295          assert(clique != NULL);
13296          nclqvars = SCIPcliqueGetNVars(clique);
13297          assert(nclqvars > 0);
13298 
13299          if( nclqvars > MAX_CLIQUELENGTH )
13300             continue;
13301 
13302          clqvars = SCIPcliqueGetVars(clique);
13303          clqvalues = SCIPcliqueGetValues(clique);
13304          assert(clqvars != NULL);
13305          assert(clqvalues != NULL);
13306 
13307          cleanedup = SCIPcliqueIsCleanedUp(clique);
13308 
13309          for( v = nclqvars - 1; v >= 0; --v )
13310          {
13311             clqvar = clqvars[v];
13312             assert(clqvar != NULL);
13313 
13314             /* ignore binary variable which are fixed */
13315             if( clqvar != var && (cleanedup || SCIPvarIsActive(clqvar)) &&
13316                (SCIPvarGetLbLocal(clqvar) < 0.5 && SCIPvarGetUbLocal(clqvar) > 0.5) )
13317             {
13318                int probindex = SCIPvarGetProbindex(clqvar) + 1;
13319                assert(0 < probindex && probindex < nentries);
13320 
13321 #if 0
13322                /* check that the variable was not yet visited or does not appear with two contradicting implications, ->
13323                 * can appear since there is no guarantee that all these infeasible bounds were found
13324                 */
13325                assert(!entries[probindex] || entries[probindex] == (clqvalues[v] ? probindex : -probindex));
13326 #endif
13327                if( entries[probindex] == 0 )
13328                {
13329                   ids[nids] = probindex;
13330                   ++nids;
13331 
13332                   /* mark variable as visited */
13333                   entries[probindex] = (clqvalues[v] ? probindex : -probindex);
13334                }
13335             }
13336          }
13337       }
13338 
13339       probvars = SCIPprobGetVars(prob);
13340       assert(probvars != NULL);
13341 
13342       /* add all implied reduced cost */
13343       for( v = nids - 1; v >= 0; --v )
13344       {
13345          id = ids[v];
13346          assert(0 < id && id < nentries);
13347          assert(entries[id] != 0);
13348          assert(probvars[id - 1] != NULL);
13349          assert(SCIPvarIsActive(probvars[id - 1]));
13350          assert(SCIPvarIsBinary(probvars[id - 1]));
13351          assert(SCIPvarGetLbLocal(probvars[id - 1]) < 0.5 && SCIPvarGetUbLocal(probvars[id - 1]) > 0.5);
13352 
13353          if( (entries[id] > 0) != varfixing )
13354             redcost = getImplVarRedcost(probvars[id - 1], set, (entries[id] < 0), stat, lp);
13355          else
13356             redcost = -getImplVarRedcost(probvars[id - 1], set, (entries[id] < 0), stat, lp);
13357 
13358          if( (varfixing && SCIPsetIsDualfeasPositive(set, redcost)) || (!varfixing && SCIPsetIsDualfeasNegative(set, redcost)) )
13359             implredcost += redcost;
13360 
13361          /* reset entries clear buffer array */
13362          entries[id] = 0;
13363       }
13364 
13365       SCIPsetFreeCleanBufferArray(set, &entries);
13366       SCIPsetFreeBufferArray(set, &ids);
13367    }
13368 
13369 #ifdef SCIP_MORE_DEBUG
13370    SCIPsetDebugMsg(set, "variable <%s> incl. cliques (%d) has implied reduced cost of %g\n", SCIPvarGetName(var), ncliques,
13371       implredcost);
13372 #endif
13373 
13374    /* collect non-binary implication information */
13375    nvars = SCIPimplicsGetNImpls(var->implics, varfixing);
13376 
13377    if( nvars > 0 )
13378    {
13379       SCIP_VAR** vars;
13380       SCIP_VAR* implvar;
13381       SCIP_COL* col;
13382       SCIP_Real* bounds;
13383       SCIP_BOUNDTYPE* boundtypes;
13384       SCIP_Real redcost;
13385       SCIP_Real lb;
13386       SCIP_Real ub;
13387       SCIP_Bool lpissolbasic;
13388       int v;
13389 
13390       vars =  SCIPimplicsGetVars(var->implics, varfixing);
13391       boundtypes = SCIPimplicsGetTypes(var->implics, varfixing);
13392       bounds = SCIPimplicsGetBounds(var->implics, varfixing);
13393       lpissolbasic = SCIPlpIsSolBasic(lp);
13394 
13395       for( v = nvars - 1; v >= 0; --v )
13396       {
13397          implvar = vars[v];
13398          assert(implvar != NULL);
13399 
13400          lb = SCIPvarGetLbLocal(implvar);
13401          ub = SCIPvarGetUbLocal(implvar);
13402 
13403          /* ignore binary variable which are fixed or not of column status */
13404          if( SCIPvarGetStatus(implvar) != SCIP_VARSTATUS_COLUMN || SCIPsetIsFeasEQ(set, lb, ub) )
13405             continue;
13406 
13407          col = SCIPvarGetCol(implvar);
13408          assert(col != NULL);
13409          redcost = 0.0;
13410 
13411          /* solved lp with basis information or not? */
13412          if( lpissolbasic )
13413          {
13414             SCIP_BASESTAT basestat = SCIPcolGetBasisStatus(col);
13415 
13416             /* check if the implication is not not yet applied */
13417             if( basestat == SCIP_BASESTAT_LOWER && boundtypes[v] == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGT(set, bounds[v], lb) )
13418             {
13419                redcost = SCIPcolGetRedcost(col, stat, lp);
13420                assert(!SCIPsetIsDualfeasNegative(set, redcost));
13421 
13422                if( !varfixing )
13423                   redcost *= (lb - bounds[v]);
13424                else
13425                   redcost *= (bounds[v] - lb);
13426             }
13427             else if( basestat == SCIP_BASESTAT_UPPER && boundtypes[v] == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLT(set, bounds[v], ub) )
13428             {
13429                redcost = SCIPcolGetRedcost(col, stat, lp);
13430                assert(!SCIPsetIsDualfeasPositive(set, redcost));
13431 
13432                if( varfixing )
13433                   redcost *= (bounds[v] - ub);
13434                else
13435                   redcost *= (ub - bounds[v]);
13436             }
13437          }
13438          else
13439          {
13440             SCIP_Real primsol = SCIPcolGetPrimsol(col);
13441 
13442             /* check if the implication is not not yet applied */
13443             if( boundtypes[v] == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasEQ(set, lb, primsol) && SCIPsetIsFeasGT(set, bounds[v], lb) )
13444             {
13445                redcost = SCIPcolGetRedcost(col, stat, lp);
13446                assert(!SCIPsetIsDualfeasNegative(set, redcost));
13447 
13448                if( varfixing )
13449                   redcost *= (lb - bounds[v]);
13450                else
13451                   redcost *= (bounds[v] - lb);
13452             }
13453             else if( boundtypes[v] == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasEQ(set, ub, primsol) && SCIPsetIsFeasLT(set, bounds[v], ub) )
13454             {
13455                redcost = SCIPcolGetRedcost(col, stat, lp);
13456                assert(!SCIPsetIsDualfeasPositive(set, redcost));
13457 
13458                if( varfixing )
13459                   redcost *= (bounds[v] - ub);
13460                else
13461                   redcost *= (ub - bounds[v]);
13462             }
13463          }
13464 
13465          /* improve implied reduced cost */
13466          if( (varfixing && SCIPsetIsDualfeasPositive(set, redcost)) || (!varfixing && SCIPsetIsDualfeasNegative(set, redcost)) )
13467             implredcost += redcost;
13468       }
13469    }
13470 
13471 #ifdef SCIP_MORE_DEBUG
13472    SCIPsetDebugMsg(set, "variable <%s> incl. cliques (%d) and implications (%d) has implied reduced cost of %g\n",
13473       SCIPvarGetName(var), ncliques, nvars, implredcost);
13474 #endif
13475 
13476    return implredcost;
13477 }
13478 
13479 /** returns the best solution (w.r.t. root reduced cost propagation) of the variable in the root node's relaxation, if
13480  *  the root relaxation is not yet completely solved, zero is returned
13481  */
SCIPvarGetBestRootSol(SCIP_VAR * var)13482 SCIP_Real SCIPvarGetBestRootSol(
13483    SCIP_VAR*             var                 /**< problem variable */
13484    )
13485 {
13486    SCIP_Real rootsol;
13487    int i;
13488 
13489    assert(var != NULL);
13490 
13491    switch( SCIPvarGetStatus(var) )
13492    {
13493    case SCIP_VARSTATUS_ORIGINAL:
13494       if( var->data.original.transvar == NULL )
13495          return 0.0;
13496       return SCIPvarGetBestRootSol(var->data.original.transvar);
13497 
13498    case SCIP_VARSTATUS_LOOSE:
13499    case SCIP_VARSTATUS_COLUMN:
13500       return var->bestrootsol;
13501 
13502    case SCIP_VARSTATUS_FIXED:
13503       assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13504       return var->locdom.lb;
13505 
13506    case SCIP_VARSTATUS_AGGREGATED:
13507       assert(var->data.aggregate.var != NULL);
13508       /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
13509        * corresponding infinity value instead of performing an arithmetical transformation (compare method
13510        * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
13511        * (or is called by) a public interface method; instead, we only assert that values are finite
13512        * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
13513        * positives and negatives if the parameter <numerics/infinity> is modified by the user
13514        */
13515       assert(SCIPvarGetBestRootSol(var->data.aggregate.var) > -SCIP_DEFAULT_INFINITY);
13516       assert(SCIPvarGetBestRootSol(var->data.aggregate.var) < +SCIP_DEFAULT_INFINITY);
13517       return var->data.aggregate.scalar * SCIPvarGetBestRootSol(var->data.aggregate.var) + var->data.aggregate.constant;
13518 
13519    case SCIP_VARSTATUS_MULTAGGR:
13520       assert(!var->donotmultaggr);
13521       assert(var->data.multaggr.vars != NULL);
13522       assert(var->data.multaggr.scalars != NULL);
13523       /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13524        * assert(var->data.multaggr.nvars >= 2);
13525        */
13526       rootsol = var->data.multaggr.constant;
13527       for( i = 0; i < var->data.multaggr.nvars; ++i )
13528          rootsol += var->data.multaggr.scalars[i] * SCIPvarGetBestRootSol(var->data.multaggr.vars[i]);
13529       return rootsol;
13530 
13531    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
13532       assert(var->negatedvar != NULL);
13533       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
13534       assert(var->negatedvar->negatedvar == var);
13535       return var->data.negate.constant - SCIPvarGetBestRootSol(var->negatedvar);
13536 
13537    default:
13538       SCIPerrorMessage("unknown variable status\n");
13539       SCIPABORT();
13540       return 0.0; /*lint !e527*/
13541    }
13542 }
13543 
13544 /** returns the best reduced costs (w.r.t. root reduced cost propagation) of the variable in the root node's relaxation,
13545  *  if the root relaxation is not yet completely solved, or the variable was no column of the root LP, SCIP_INVALID is
13546  *  returned
13547  */
SCIPvarGetBestRootRedcost(SCIP_VAR * var)13548 SCIP_Real SCIPvarGetBestRootRedcost(
13549    SCIP_VAR*             var                 /**< problem variable */
13550    )
13551 {
13552    assert(var != NULL);
13553 
13554    switch( SCIPvarGetStatus(var) )
13555    {
13556    case SCIP_VARSTATUS_ORIGINAL:
13557       if( var->data.original.transvar == NULL )
13558          return SCIP_INVALID;
13559       return SCIPvarGetBestRootRedcost(var->data.original.transvar);
13560 
13561    case SCIP_VARSTATUS_LOOSE:
13562    case SCIP_VARSTATUS_COLUMN:
13563       return var->bestrootredcost;
13564 
13565    case SCIP_VARSTATUS_FIXED:
13566    case SCIP_VARSTATUS_AGGREGATED:
13567    case SCIP_VARSTATUS_MULTAGGR:
13568    case SCIP_VARSTATUS_NEGATED:
13569       return 0.0;
13570 
13571    default:
13572       SCIPerrorMessage("unknown variable status\n");
13573       SCIPABORT();
13574       return 0.0; /*lint !e527*/
13575    }
13576 }
13577 
13578 /** returns the best objective value (w.r.t. root reduced cost propagation) of the root LP which belongs the root
13579  *  reduced cost which is accessible via SCIPvarGetRootRedcost() or the variable was no column of the root LP,
13580  *  SCIP_INVALID is returned
13581  */
SCIPvarGetBestRootLPObjval(SCIP_VAR * var)13582 SCIP_Real SCIPvarGetBestRootLPObjval(
13583    SCIP_VAR*             var                 /**< problem variable */
13584    )
13585 {
13586    assert(var != NULL);
13587 
13588    switch( SCIPvarGetStatus(var) )
13589    {
13590    case SCIP_VARSTATUS_ORIGINAL:
13591       if( var->data.original.transvar == NULL )
13592          return SCIP_INVALID;
13593       return SCIPvarGetBestRootLPObjval(var->data.original.transvar);
13594 
13595    case SCIP_VARSTATUS_LOOSE:
13596    case SCIP_VARSTATUS_COLUMN:
13597       return var->bestrootlpobjval;
13598 
13599    case SCIP_VARSTATUS_FIXED:
13600    case SCIP_VARSTATUS_AGGREGATED:
13601    case SCIP_VARSTATUS_MULTAGGR:
13602    case SCIP_VARSTATUS_NEGATED:
13603       return SCIP_INVALID;
13604 
13605    default:
13606       SCIPerrorMessage("unknown variable status\n");
13607       SCIPABORT();
13608       return SCIP_INVALID; /*lint !e527*/
13609    }
13610 }
13611 
13612 /** set the given solution as the best root solution w.r.t. root reduced cost propagation in the variables */
SCIPvarSetBestRootSol(SCIP_VAR * var,SCIP_Real rootsol,SCIP_Real rootredcost,SCIP_Real rootlpobjval)13613 void SCIPvarSetBestRootSol(
13614    SCIP_VAR*             var,                /**< problem variable */
13615    SCIP_Real             rootsol,            /**< root solution value */
13616    SCIP_Real             rootredcost,        /**< root reduced cost */
13617    SCIP_Real             rootlpobjval        /**< objective value of the root LP */
13618    )
13619 {
13620    assert(var != NULL);
13621 
13622    var->bestrootsol = rootsol;
13623    var->bestrootredcost = rootredcost;
13624    var->bestrootlpobjval = rootlpobjval;
13625 }
13626 
13627 /** stores the solution value as relaxation solution in the problem variable */
SCIPvarSetRelaxSol(SCIP_VAR * var,SCIP_SET * set,SCIP_RELAXATION * relaxation,SCIP_Real solval,SCIP_Bool updateobj)13628 SCIP_RETCODE SCIPvarSetRelaxSol(
13629    SCIP_VAR*             var,                /**< problem variable */
13630    SCIP_SET*             set,                /**< global SCIP settings */
13631    SCIP_RELAXATION*      relaxation,         /**< global relaxation data */
13632    SCIP_Real             solval,             /**< solution value in the current relaxation solution */
13633    SCIP_Bool             updateobj           /**< should the objective value be updated? */
13634    )
13635 {
13636    assert(var != NULL);
13637    assert(relaxation != NULL);
13638    assert(set != NULL);
13639    assert(var->scip == set->scip);
13640 
13641    /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */
13642    switch( SCIPvarGetStatus(var) )
13643    {
13644    case SCIP_VARSTATUS_ORIGINAL:
13645       SCIP_CALL( SCIPvarSetRelaxSol(var->data.original.transvar, set, relaxation, solval, updateobj) );
13646       break;
13647 
13648    case SCIP_VARSTATUS_LOOSE:
13649    case SCIP_VARSTATUS_COLUMN:
13650       if( updateobj )
13651          SCIPrelaxationSolObjAdd(relaxation, var->obj * (solval - var->relaxsol));
13652       var->relaxsol = solval;
13653       break;
13654 
13655    case SCIP_VARSTATUS_FIXED:
13656       if( !SCIPsetIsEQ(set, solval, var->glbdom.lb) )
13657       {
13658          SCIPerrorMessage("cannot set relaxation solution value for variable <%s> fixed to %.15g to different value %.15g\n",
13659             SCIPvarGetName(var), var->glbdom.lb, solval);
13660          return SCIP_INVALIDDATA;
13661       }
13662       break;
13663 
13664    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  =>  y = (x-c)/a */
13665       assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
13666       SCIP_CALL( SCIPvarSetRelaxSol(var->data.aggregate.var, set, relaxation,
13667             (solval - var->data.aggregate.constant)/var->data.aggregate.scalar, updateobj) );
13668       break;
13669    case SCIP_VARSTATUS_MULTAGGR:
13670       SCIPerrorMessage("cannot set solution value for multiple aggregated variable\n");
13671       return SCIP_INVALIDDATA;
13672 
13673    case SCIP_VARSTATUS_NEGATED:
13674       SCIP_CALL( SCIPvarSetRelaxSol(var->negatedvar, set, relaxation, var->data.negate.constant - solval, updateobj) );
13675       break;
13676 
13677    default:
13678       SCIPerrorMessage("unknown variable status\n");
13679       return SCIP_INVALIDDATA;
13680    }
13681 
13682    return SCIP_OKAY;
13683 }
13684 
13685 /** returns the solution value of the problem variable in the relaxation solution
13686  *
13687  *  @todo Inline this function - similar to SCIPvarGetLPSol_rec.
13688  */
SCIPvarGetRelaxSol(SCIP_VAR * var,SCIP_SET * set)13689 SCIP_Real SCIPvarGetRelaxSol(
13690    SCIP_VAR*             var,                /**< problem variable */
13691    SCIP_SET*             set                 /**< global SCIP settings */
13692    )
13693 {
13694    SCIP_Real solvalsum;
13695    SCIP_Real solval;
13696    int i;
13697 
13698    assert(var != NULL);
13699    assert(set != NULL);
13700    assert(var->scip == set->scip);
13701 
13702    /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */
13703    switch( SCIPvarGetStatus(var) )
13704    {
13705    case SCIP_VARSTATUS_ORIGINAL:
13706       return SCIPvarGetRelaxSol(var->data.original.transvar, set);
13707 
13708    case SCIP_VARSTATUS_LOOSE:
13709    case SCIP_VARSTATUS_COLUMN:
13710       return var->relaxsol;
13711 
13712    case SCIP_VARSTATUS_FIXED:
13713       assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var));  /*lint !e777*/
13714       assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var));    /*lint !e777*/
13715       assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var));   /*lint !e777*/
13716       return SCIPvarGetLbGlobal(var);
13717 
13718    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  =>  y = (x-c)/a */
13719       solval = SCIPvarGetRelaxSol(var->data.aggregate.var, set);
13720       if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) )
13721       {
13722          if( var->data.aggregate.scalar * solval > 0.0 )
13723             return SCIPsetInfinity(set);
13724          if( var->data.aggregate.scalar * solval < 0.0 )
13725             return -SCIPsetInfinity(set);
13726       }
13727       return var->data.aggregate.scalar * solval + var->data.aggregate.constant;
13728 
13729    case SCIP_VARSTATUS_MULTAGGR:
13730       solvalsum = var->data.multaggr.constant;
13731       for( i = 0; i < var->data.multaggr.nvars; ++i )
13732       {
13733          solval = SCIPvarGetRelaxSol(var->data.multaggr.vars[i], set);
13734          if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) )
13735          {
13736             if( var->data.multaggr.scalars[i] * solval > 0.0 )
13737                return SCIPsetInfinity(set);
13738             if( var->data.multaggr.scalars[i] * solval < 0.0 )
13739                return -SCIPsetInfinity(set);
13740          }
13741          solvalsum += var->data.multaggr.scalars[i] * solval;
13742       }
13743       return solvalsum;
13744 
13745    case SCIP_VARSTATUS_NEGATED:
13746       solval = SCIPvarGetRelaxSol(var->negatedvar, set);
13747       if( SCIPsetIsInfinity(set, solval) )
13748          return -SCIPsetInfinity(set);
13749       if( SCIPsetIsInfinity(set, -solval) )
13750          return SCIPsetInfinity(set);
13751       return var->data.negate.constant - solval;
13752 
13753    default:
13754       SCIPerrorMessage("unknown variable status\n");
13755       SCIPABORT();
13756       return SCIP_INVALID; /*lint !e527*/
13757    }
13758 }
13759 
13760 /** returns the solution value of the transformed problem variable in the relaxation solution */
SCIPvarGetRelaxSolTransVar(SCIP_VAR * var)13761 SCIP_Real SCIPvarGetRelaxSolTransVar(
13762    SCIP_VAR*             var                 /**< problem variable */
13763    )
13764 {
13765    assert(var != NULL);
13766    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
13767 
13768    return var->relaxsol;
13769 }
13770 
13771 /** stores the solution value as NLP solution in the problem variable */
SCIPvarSetNLPSol(SCIP_VAR * var,SCIP_SET * set,SCIP_Real solval)13772 SCIP_RETCODE SCIPvarSetNLPSol(
13773    SCIP_VAR*             var,                /**< problem variable */
13774    SCIP_SET*             set,                /**< global SCIP settings */
13775    SCIP_Real             solval              /**< solution value in the current NLP solution */
13776    )
13777 {
13778    assert(var != NULL);
13779    assert(set != NULL);
13780    assert(var->scip == set->scip);
13781 
13782    /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */
13783    switch( SCIPvarGetStatus(var) )
13784    {
13785    case SCIP_VARSTATUS_ORIGINAL:
13786       SCIP_CALL( SCIPvarSetNLPSol(var->data.original.transvar, set, solval) );
13787       break;
13788 
13789    case SCIP_VARSTATUS_LOOSE:
13790    case SCIP_VARSTATUS_COLUMN:
13791       var->nlpsol = solval;
13792       break;
13793 
13794    case SCIP_VARSTATUS_FIXED:
13795       if( !SCIPsetIsEQ(set, solval, var->glbdom.lb) )
13796       {
13797          SCIPerrorMessage("cannot set NLP solution value for variable <%s> fixed to %.15g to different value %.15g\n",
13798             SCIPvarGetName(var), var->glbdom.lb, solval);
13799          SCIPABORT();
13800          return SCIP_INVALIDCALL; /*lint !e527*/
13801       }
13802       break;
13803 
13804    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  =>  y = (x-c)/a */
13805       assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
13806       SCIP_CALL( SCIPvarSetNLPSol(var->data.aggregate.var, set, (solval - var->data.aggregate.constant)/var->data.aggregate.scalar) );
13807       break;
13808 
13809    case SCIP_VARSTATUS_MULTAGGR:
13810       SCIPerrorMessage("cannot set solution value for multiple aggregated variable\n");
13811       SCIPABORT();
13812       return SCIP_INVALIDCALL; /*lint !e527*/
13813 
13814    case SCIP_VARSTATUS_NEGATED:
13815       SCIP_CALL( SCIPvarSetNLPSol(var->negatedvar, set, var->data.negate.constant - solval) );
13816       break;
13817 
13818    default:
13819       SCIPerrorMessage("unknown variable status\n");
13820       SCIPABORT();
13821       return SCIP_ERROR; /*lint !e527*/
13822    }
13823 
13824    return SCIP_OKAY;
13825 }
13826 
13827 /** returns a weighted average solution value of the variable in all feasible primal solutions found so far */
SCIPvarGetAvgSol(SCIP_VAR * var)13828 SCIP_Real SCIPvarGetAvgSol(
13829    SCIP_VAR*             var                 /**< problem variable */
13830    )
13831 {
13832    SCIP_Real avgsol;
13833    int i;
13834 
13835    assert(var != NULL);
13836 
13837    switch( SCIPvarGetStatus(var) )
13838    {
13839    case SCIP_VARSTATUS_ORIGINAL:
13840       if( var->data.original.transvar == NULL )
13841          return 0.0;
13842       return SCIPvarGetAvgSol(var->data.original.transvar);
13843 
13844    case SCIP_VARSTATUS_LOOSE:
13845    case SCIP_VARSTATUS_COLUMN:
13846       avgsol = var->primsolavg;
13847       avgsol = MAX(avgsol, var->glbdom.lb);
13848       avgsol = MIN(avgsol, var->glbdom.ub);
13849       return avgsol;
13850 
13851    case SCIP_VARSTATUS_FIXED:
13852       assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
13853       return var->locdom.lb;
13854 
13855    case SCIP_VARSTATUS_AGGREGATED:
13856       assert(var->data.aggregate.var != NULL);
13857       return var->data.aggregate.scalar * SCIPvarGetAvgSol(var->data.aggregate.var)
13858          + var->data.aggregate.constant;
13859 
13860    case SCIP_VARSTATUS_MULTAGGR:
13861       assert(!var->donotmultaggr);
13862       assert(var->data.multaggr.vars != NULL);
13863       assert(var->data.multaggr.scalars != NULL);
13864       /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
13865        * assert(var->data.multaggr.nvars >= 2);
13866        */
13867       avgsol = var->data.multaggr.constant;
13868       for( i = 0; i < var->data.multaggr.nvars; ++i )
13869          avgsol += var->data.multaggr.scalars[i] * SCIPvarGetAvgSol(var->data.multaggr.vars[i]);
13870       return avgsol;
13871 
13872    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
13873       assert(var->negatedvar != NULL);
13874       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
13875       assert(var->negatedvar->negatedvar == var);
13876       return var->data.negate.constant - SCIPvarGetAvgSol(var->negatedvar);
13877 
13878    default:
13879       SCIPerrorMessage("unknown variable status\n");
13880       SCIPABORT();
13881       return 0.0; /*lint !e527*/
13882    }
13883 }
13884 
13885 /** returns solution value and index of variable lower bound that is closest to the variable's value in the given primal solution
13886  *  or current LP solution if no primal solution is given; returns an index of -1 if no variable lower bound is available
13887  */
SCIPvarGetClosestVlb(SCIP_VAR * var,SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_Real * closestvlb,int * closestvlbidx)13888 void SCIPvarGetClosestVlb(
13889    SCIP_VAR*             var,                /**< active problem variable */
13890    SCIP_SOL*             sol,                /**< primal solution, or NULL for LP solution */
13891    SCIP_SET*             set,                /**< global SCIP settings */
13892    SCIP_STAT*            stat,               /**< problem statistics */
13893    SCIP_Real*            closestvlb,         /**< pointer to store the value of the closest variable lower bound */
13894    int*                  closestvlbidx       /**< pointer to store the index of the closest variable lower bound */
13895    )
13896 {
13897    int nvlbs;
13898 
13899    assert(var != NULL);
13900    assert(stat != NULL);
13901    assert(set != NULL);
13902    assert(var->scip == set->scip);
13903    assert(closestvlb != NULL);
13904    assert(closestvlbidx != NULL);
13905 
13906    *closestvlbidx = -1;
13907    *closestvlb = SCIP_REAL_MIN;
13908 
13909    nvlbs = SCIPvarGetNVlbs(var);
13910    if( nvlbs > 0 )
13911    {
13912       SCIP_VAR** vlbvars;
13913       SCIP_Real* vlbcoefs;
13914       SCIP_Real* vlbconsts;
13915       int i;
13916 
13917       vlbvars = SCIPvarGetVlbVars(var);
13918       vlbcoefs = SCIPvarGetVlbCoefs(var);
13919       vlbconsts = SCIPvarGetVlbConstants(var);
13920 
13921       /* check for cached values */
13922       if( var->closestvblpcount == stat->lpcount && var->closestvlbidx != -1 && sol == NULL)
13923       {
13924          i = var->closestvlbidx;
13925          assert(0 <= i && i < nvlbs);
13926          assert(SCIPvarIsActive(vlbvars[i]));
13927          *closestvlbidx = i;
13928          *closestvlb = vlbcoefs[i] * SCIPvarGetLPSol(vlbvars[i]) + vlbconsts[i];
13929       }
13930       else
13931       {
13932          /* search best VUB */
13933          for( i = 0; i < nvlbs; i++ )
13934          {
13935             if( SCIPvarIsActive(vlbvars[i]) )
13936             {
13937                SCIP_Real vlbsol;
13938 
13939                vlbsol = vlbcoefs[i] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[i]) : SCIPsolGetVal(sol, set, stat, vlbvars[i])) + vlbconsts[i];
13940                if( vlbsol > *closestvlb )
13941                {
13942                   *closestvlb = vlbsol;
13943                   *closestvlbidx = i;
13944                }
13945             }
13946          }
13947 
13948          if( sol == NULL )
13949          {
13950             /* update cached value */
13951             if( var->closestvblpcount != stat->lpcount )
13952                var->closestvubidx = -1;
13953             var->closestvlbidx = *closestvlbidx;
13954             var->closestvblpcount = stat->lpcount;
13955          }
13956       }
13957    }
13958 }
13959 
13960 /** returns solution value and index of variable upper bound that is closest to the variable's value in the given primal solution;
13961  *  or current LP solution if no primal solution is given; returns an index of -1 if no variable upper bound is available
13962  */
SCIPvarGetClosestVub(SCIP_VAR * var,SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_Real * closestvub,int * closestvubidx)13963 void SCIPvarGetClosestVub(
13964    SCIP_VAR*             var,                /**< active problem variable */
13965    SCIP_SOL*             sol,                /**< primal solution, or NULL for LP solution */
13966    SCIP_SET*             set,                /**< global SCIP settings */
13967    SCIP_STAT*            stat,               /**< problem statistics */
13968    SCIP_Real*            closestvub,         /**< pointer to store the value of the closest variable upper bound */
13969    int*                  closestvubidx       /**< pointer to store the index of the closest variable upper bound */
13970    )
13971 {
13972    int nvubs;
13973 
13974    assert(var != NULL);
13975    assert(set != NULL);
13976    assert(var->scip == set->scip);
13977    assert(closestvub != NULL);
13978    assert(closestvubidx != NULL);
13979 
13980    *closestvubidx = -1;
13981    *closestvub = SCIP_REAL_MAX;
13982 
13983    nvubs = SCIPvarGetNVubs(var);
13984    if( nvubs > 0 )
13985    {
13986       SCIP_VAR** vubvars;
13987       SCIP_Real* vubcoefs;
13988       SCIP_Real* vubconsts;
13989       int i;
13990 
13991       vubvars = SCIPvarGetVubVars(var);
13992       vubcoefs = SCIPvarGetVubCoefs(var);
13993       vubconsts = SCIPvarGetVubConstants(var);
13994 
13995       /* check for cached values */
13996       if( var->closestvblpcount == stat->lpcount && var->closestvubidx != -1 && sol == NULL)
13997       {
13998          i = var->closestvubidx;
13999          assert(0 <= i && i < nvubs);
14000          assert(SCIPvarIsActive(vubvars[i]));
14001          *closestvubidx = i;
14002          *closestvub = vubcoefs[i] * SCIPvarGetLPSol(vubvars[i]) + vubconsts[i];
14003       }
14004       else
14005       {
14006          /* search best VUB */
14007          for( i = 0; i < nvubs; i++ )
14008          {
14009             if( SCIPvarIsActive(vubvars[i]) )
14010             {
14011                SCIP_Real vubsol;
14012 
14013                vubsol = vubcoefs[i] * (sol == NULL ? SCIPvarGetLPSol(vubvars[i]) : SCIPsolGetVal(sol, set, stat, vubvars[i])) + vubconsts[i];
14014                if( vubsol < *closestvub )
14015                {
14016                   *closestvub = vubsol;
14017                   *closestvubidx = i;
14018                }
14019             }
14020          }
14021 
14022          if( sol == NULL )
14023          {
14024             /* update cached value */
14025             if( var->closestvblpcount != stat->lpcount )
14026                var->closestvlbidx = -1;
14027             var->closestvubidx = *closestvubidx;
14028             var->closestvblpcount = stat->lpcount;
14029          }
14030       }
14031    }
14032 }
14033 
14034 /** resolves variable to columns and adds them with the coefficient to the row */
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)14035 SCIP_RETCODE SCIPvarAddToRow(
14036    SCIP_VAR*             var,                /**< problem variable */
14037    BMS_BLKMEM*           blkmem,             /**< block memory */
14038    SCIP_SET*             set,                /**< global SCIP settings */
14039    SCIP_STAT*            stat,               /**< problem statistics */
14040    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
14041    SCIP_PROB*            prob,               /**< problem data */
14042    SCIP_LP*              lp,                 /**< current LP data */
14043    SCIP_ROW*             row,                /**< LP row */
14044    SCIP_Real             val                 /**< value of coefficient */
14045    )
14046 {
14047    int i;
14048 
14049    assert(var != NULL);
14050    assert(set != NULL);
14051    assert(var->scip == set->scip);
14052    assert(row != NULL);
14053    assert(!SCIPsetIsInfinity(set, REALABS(val)));
14054 
14055    SCIPsetDebugMsg(set, "adding coefficient %g<%s> to row <%s>\n", val, var->name, row->name);
14056 
14057    if ( SCIPsetIsZero(set, val) )
14058       return SCIP_OKAY;
14059 
14060    switch( SCIPvarGetStatus(var) )
14061    {
14062    case SCIP_VARSTATUS_ORIGINAL:
14063       if( var->data.original.transvar == NULL )
14064       {
14065          SCIPerrorMessage("cannot add untransformed original variable <%s> to LP row <%s>\n", var->name, row->name);
14066          return SCIP_INVALIDDATA;
14067       }
14068       SCIP_CALL( SCIPvarAddToRow(var->data.original.transvar, blkmem, set, stat, eventqueue, prob, lp, row, val) );
14069       return SCIP_OKAY;
14070 
14071    case SCIP_VARSTATUS_LOOSE:
14072       /* add globally fixed variables as constant */
14073       if( SCIPsetIsEQ(set, var->glbdom.lb, var->glbdom.ub) )
14074       {
14075          SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, val * var->glbdom.lb) );
14076          return SCIP_OKAY;
14077       }
14078       /* convert loose variable into column */
14079       SCIP_CALL( SCIPvarColumn(var, blkmem, set, stat, prob, lp) );
14080       assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
14081       /*lint -fallthrough*/
14082 
14083    case SCIP_VARSTATUS_COLUMN:
14084       assert(var->data.col != NULL);
14085       assert(var->data.col->var == var);
14086       SCIP_CALL( SCIProwIncCoef(row, blkmem, set, eventqueue, lp, var->data.col, val) );
14087       return SCIP_OKAY;
14088 
14089    case SCIP_VARSTATUS_FIXED:
14090       assert(var->glbdom.lb == var->glbdom.ub); /*lint !e777*/
14091       assert(var->locdom.lb == var->locdom.ub); /*lint !e777*/
14092       assert(var->locdom.lb == var->glbdom.lb); /*lint !e777*/
14093       assert(!SCIPsetIsInfinity(set, REALABS(var->locdom.lb)));
14094       SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, val * var->locdom.lb) );
14095       return SCIP_OKAY;
14096 
14097    case SCIP_VARSTATUS_AGGREGATED:
14098       assert(var->data.aggregate.var != NULL);
14099       SCIP_CALL( SCIPvarAddToRow(var->data.aggregate.var, blkmem, set, stat, eventqueue, prob, lp,
14100             row, var->data.aggregate.scalar * val) );
14101       SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.aggregate.constant * val) );
14102       return SCIP_OKAY;
14103 
14104    case SCIP_VARSTATUS_MULTAGGR:
14105       assert(!var->donotmultaggr);
14106       assert(var->data.multaggr.vars != NULL);
14107       assert(var->data.multaggr.scalars != NULL);
14108       /* Due to method SCIPvarFlattenAggregationGraph(), this assert is no longer correct
14109        * assert(var->data.multaggr.nvars >= 2);
14110        */
14111       for( i = 0; i < var->data.multaggr.nvars; ++i )
14112       {
14113          SCIP_CALL( SCIPvarAddToRow(var->data.multaggr.vars[i], blkmem, set, stat, eventqueue, prob, lp,
14114                row, var->data.multaggr.scalars[i] * val) );
14115       }
14116       SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.multaggr.constant * val) );
14117       return SCIP_OKAY;
14118 
14119    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
14120       assert(var->negatedvar != NULL);
14121       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
14122       assert(var->negatedvar->negatedvar == var);
14123       SCIP_CALL( SCIPvarAddToRow(var->negatedvar, blkmem, set, stat, eventqueue, prob, lp, row, -val) );
14124       SCIP_CALL( SCIProwAddConstant(row, blkmem, set, stat, eventqueue, lp, var->data.negate.constant * val) );
14125       return SCIP_OKAY;
14126 
14127    default:
14128       SCIPerrorMessage("unknown variable status\n");
14129       return SCIP_INVALIDDATA;
14130    }
14131 }
14132 
14133 /* optionally, define this compiler flag to write complete variable histories to a file */
14134 #ifdef SCIP_HISTORYTOFILE
14135 SCIP_Longint counter = 0l;
14136 const char* historypath="."; /* allows for user-defined path; use '.' for calling directory of SCIP */
14137 #include "scip/scip.h"
14138 #endif
14139 
14140 /** updates the pseudo costs of the given variable and the global pseudo costs after a change of
14141  *  "solvaldelta" in the variable's solution value and resulting change of "objdelta" in the in the LP's objective value
14142  */
SCIPvarUpdatePseudocost(SCIP_VAR * var,SCIP_SET * set,SCIP_STAT * stat,SCIP_Real solvaldelta,SCIP_Real objdelta,SCIP_Real weight)14143 SCIP_RETCODE SCIPvarUpdatePseudocost(
14144    SCIP_VAR*             var,                /**< problem variable */
14145    SCIP_SET*             set,                /**< global SCIP settings */
14146    SCIP_STAT*            stat,               /**< problem statistics */
14147    SCIP_Real             solvaldelta,        /**< difference of variable's new LP value - old LP value */
14148    SCIP_Real             objdelta,           /**< difference of new LP's objective value - old LP's objective value */
14149    SCIP_Real             weight              /**< weight in (0,1] of this update in pseudo cost sum */
14150    )
14151 {
14152    SCIP_Real oldrootpseudocosts;
14153    assert(var != NULL);
14154    assert(set != NULL);
14155    assert(var->scip == set->scip);
14156    assert(stat != NULL);
14157 
14158    /* check if history statistics should be collected for a variable */
14159    if( !stat->collectvarhistory )
14160       return SCIP_OKAY;
14161 
14162    switch( SCIPvarGetStatus(var) )
14163    {
14164    case SCIP_VARSTATUS_ORIGINAL:
14165       if( var->data.original.transvar == NULL )
14166       {
14167          SCIPerrorMessage("cannot update pseudo costs of original untransformed variable\n");
14168          return SCIP_INVALIDDATA;
14169       }
14170       SCIP_CALL( SCIPvarUpdatePseudocost(var->data.original.transvar, set, stat, solvaldelta, objdelta, weight) );
14171       return SCIP_OKAY;
14172 
14173    case SCIP_VARSTATUS_LOOSE:
14174    case SCIP_VARSTATUS_COLUMN:
14175       /* store old pseudo-costs for root LP best-estimate update */
14176       oldrootpseudocosts = SCIPvarGetMinPseudocostScore(var, stat, set, SCIPvarGetRootSol(var));
14177 
14178       /* update history */
14179       SCIPhistoryUpdatePseudocost(var->history, set, solvaldelta, objdelta, weight);
14180       SCIPhistoryUpdatePseudocost(var->historycrun, set, solvaldelta, objdelta, weight);
14181       SCIPhistoryUpdatePseudocost(stat->glbhistory, set, solvaldelta, objdelta, weight);
14182       SCIPhistoryUpdatePseudocost(stat->glbhistorycrun, set, solvaldelta, objdelta, weight);
14183 
14184       /* update root LP best-estimate */
14185       SCIP_CALL( SCIPstatUpdateVarRootLPBestEstimate(stat, set, var, oldrootpseudocosts) );
14186 
14187       /* append history to file */
14188 #ifdef SCIP_HISTORYTOFILE
14189    {
14190       FILE* f;
14191       char filename[256];
14192       SCIP_NODE* currentnode;
14193       SCIP_NODE* parentnode;
14194       currentnode = SCIPgetFocusNode(set->scip);
14195       parentnode = SCIPnodeGetParent(currentnode);
14196 
14197       sprintf(filename, "%s/%s.pse", historypath, SCIPgetProbName(set->scip));
14198       f = fopen(filename, "a");
14199       if( NULL != f )
14200       {
14201          fprintf(f, "%lld %s \t %lld \t %lld \t %lld \t %d \t %15.9f \t %.3f\n",
14202             ++counter,
14203             SCIPvarGetName(var),
14204             SCIPnodeGetNumber(currentnode),
14205             parentnode != NULL ? SCIPnodeGetNumber(parentnode) : -1,
14206             SCIPgetNLPIterations(set->scip),
14207             SCIPgetDepth(set->scip),
14208             objdelta,
14209             solvaldelta);
14210          fclose(f);
14211       }
14212    }
14213 #endif
14214       return SCIP_OKAY;
14215 
14216    case SCIP_VARSTATUS_FIXED:
14217       SCIPerrorMessage("cannot update pseudo cost values of a fixed variable\n");
14218       return SCIP_INVALIDDATA;
14219 
14220    case SCIP_VARSTATUS_AGGREGATED:
14221       assert(!SCIPsetIsZero(set, var->data.aggregate.scalar));
14222       SCIP_CALL( SCIPvarUpdatePseudocost(var->data.aggregate.var, set, stat,
14223             solvaldelta/var->data.aggregate.scalar, objdelta, weight) );
14224       return SCIP_OKAY;
14225 
14226    case SCIP_VARSTATUS_MULTAGGR:
14227       SCIPerrorMessage("cannot update pseudo cost values of a multi-aggregated variable\n");
14228       return SCIP_INVALIDDATA;
14229 
14230    case SCIP_VARSTATUS_NEGATED:
14231       SCIP_CALL( SCIPvarUpdatePseudocost(var->negatedvar, set, stat, -solvaldelta, objdelta, weight) );
14232       return SCIP_OKAY;
14233 
14234    default:
14235       SCIPerrorMessage("unknown variable status\n");
14236       return SCIP_INVALIDDATA;
14237    }
14238 }
14239 
14240 /** gets the variable's pseudo cost value for the given step size "solvaldelta" in the variable's LP solution value */
SCIPvarGetPseudocost(SCIP_VAR * var,SCIP_STAT * stat,SCIP_Real solvaldelta)14241 SCIP_Real SCIPvarGetPseudocost(
14242    SCIP_VAR*             var,                /**< problem variable */
14243    SCIP_STAT*            stat,               /**< problem statistics */
14244    SCIP_Real             solvaldelta         /**< difference of variable's new LP value - old LP value */
14245    )
14246 {
14247    SCIP_BRANCHDIR dir;
14248 
14249    assert(var != NULL);
14250    assert(stat != NULL);
14251 
14252    switch( SCIPvarGetStatus(var) )
14253    {
14254    case SCIP_VARSTATUS_ORIGINAL:
14255       if( var->data.original.transvar == NULL )
14256          return SCIPhistoryGetPseudocost(stat->glbhistory, solvaldelta);
14257       else
14258          return SCIPvarGetPseudocost(var->data.original.transvar, stat, solvaldelta);
14259 
14260    case SCIP_VARSTATUS_LOOSE:
14261    case SCIP_VARSTATUS_COLUMN:
14262       dir = (solvaldelta >= 0.0 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
14263 
14264       return SCIPhistoryGetPseudocostCount(var->history, dir) > 0.0
14265          ? SCIPhistoryGetPseudocost(var->history, solvaldelta)
14266          : SCIPhistoryGetPseudocost(stat->glbhistory, solvaldelta);
14267 
14268    case SCIP_VARSTATUS_FIXED:
14269       return 0.0;
14270 
14271    case SCIP_VARSTATUS_AGGREGATED:
14272       return SCIPvarGetPseudocost(var->data.aggregate.var, stat, var->data.aggregate.scalar * solvaldelta);
14273 
14274    case SCIP_VARSTATUS_MULTAGGR:
14275       return 0.0;
14276 
14277    case SCIP_VARSTATUS_NEGATED:
14278       return SCIPvarGetPseudocost(var->negatedvar, stat, -solvaldelta);
14279 
14280    default:
14281       SCIPerrorMessage("unknown variable status\n");
14282       SCIPABORT();
14283       return 0.0; /*lint !e527*/
14284    }
14285 }
14286 
14287 /** gets the variable's pseudo cost value for the given step size "solvaldelta" in the variable's LP solution value,
14288  *  only using the pseudo cost information of the current run
14289  */
SCIPvarGetPseudocostCurrentRun(SCIP_VAR * var,SCIP_STAT * stat,SCIP_Real solvaldelta)14290 SCIP_Real SCIPvarGetPseudocostCurrentRun(
14291    SCIP_VAR*             var,                /**< problem variable */
14292    SCIP_STAT*            stat,               /**< problem statistics */
14293    SCIP_Real             solvaldelta         /**< difference of variable's new LP value - old LP value */
14294    )
14295 {
14296    SCIP_BRANCHDIR dir;
14297 
14298    assert(var != NULL);
14299    assert(stat != NULL);
14300 
14301    switch( SCIPvarGetStatus(var) )
14302    {
14303    case SCIP_VARSTATUS_ORIGINAL:
14304       if( var->data.original.transvar == NULL )
14305          return SCIPhistoryGetPseudocost(stat->glbhistorycrun, solvaldelta);
14306       else
14307          return SCIPvarGetPseudocostCurrentRun(var->data.original.transvar, stat, solvaldelta);
14308 
14309    case SCIP_VARSTATUS_LOOSE:
14310    case SCIP_VARSTATUS_COLUMN:
14311       dir = (solvaldelta >= 0.0 ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
14312 
14313       return SCIPhistoryGetPseudocostCount(var->historycrun, dir) > 0.0
14314          ? SCIPhistoryGetPseudocost(var->historycrun, solvaldelta)
14315          : SCIPhistoryGetPseudocost(stat->glbhistorycrun, solvaldelta);
14316 
14317    case SCIP_VARSTATUS_FIXED:
14318       return 0.0;
14319 
14320    case SCIP_VARSTATUS_AGGREGATED:
14321       return SCIPvarGetPseudocostCurrentRun(var->data.aggregate.var, stat, var->data.aggregate.scalar * solvaldelta);
14322 
14323    case SCIP_VARSTATUS_MULTAGGR:
14324       return 0.0;
14325 
14326    case SCIP_VARSTATUS_NEGATED:
14327       return SCIPvarGetPseudocostCurrentRun(var->negatedvar, stat, -solvaldelta);
14328 
14329    default:
14330       SCIPerrorMessage("unknown variable status\n");
14331       SCIPABORT();
14332       return 0.0; /*lint !e527*/
14333    }
14334 }
14335 
14336 /** gets the variable's (possible fractional) number of pseudo cost updates for the given direction */
SCIPvarGetPseudocostCount(SCIP_VAR * var,SCIP_BRANCHDIR dir)14337 SCIP_Real SCIPvarGetPseudocostCount(
14338    SCIP_VAR*             var,                /**< problem variable */
14339    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
14340    )
14341 {
14342    assert(var != NULL);
14343    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14344 
14345    switch( SCIPvarGetStatus(var) )
14346    {
14347    case SCIP_VARSTATUS_ORIGINAL:
14348       if( var->data.original.transvar == NULL )
14349          return 0.0;
14350       else
14351          return SCIPvarGetPseudocostCount(var->data.original.transvar, dir);
14352 
14353    case SCIP_VARSTATUS_LOOSE:
14354    case SCIP_VARSTATUS_COLUMN:
14355       return SCIPhistoryGetPseudocostCount(var->history, dir);
14356 
14357    case SCIP_VARSTATUS_FIXED:
14358       return 0.0;
14359 
14360    case SCIP_VARSTATUS_AGGREGATED:
14361       if( var->data.aggregate.scalar > 0.0 )
14362          return SCIPvarGetPseudocostCount(var->data.aggregate.var, dir);
14363       else
14364          return SCIPvarGetPseudocostCount(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
14365 
14366    case SCIP_VARSTATUS_MULTAGGR:
14367       return 0.0;
14368 
14369    case SCIP_VARSTATUS_NEGATED:
14370       return SCIPvarGetPseudocostCount(var->negatedvar, SCIPbranchdirOpposite(dir));
14371 
14372    default:
14373       SCIPerrorMessage("unknown variable status\n");
14374       SCIPABORT();
14375       return 0.0; /*lint !e527*/
14376    }
14377 }
14378 
14379 /** gets the variable's (possible fractional) number of pseudo cost updates for the given direction,
14380  *  only using the pseudo cost information of the current run
14381  */
SCIPvarGetPseudocostCountCurrentRun(SCIP_VAR * var,SCIP_BRANCHDIR dir)14382 SCIP_Real SCIPvarGetPseudocostCountCurrentRun(
14383    SCIP_VAR*             var,                /**< problem variable */
14384    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
14385    )
14386 {
14387    assert(var != NULL);
14388    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14389 
14390    switch( SCIPvarGetStatus(var) )
14391    {
14392    case SCIP_VARSTATUS_ORIGINAL:
14393       if( var->data.original.transvar == NULL )
14394          return 0.0;
14395       else
14396          return SCIPvarGetPseudocostCountCurrentRun(var->data.original.transvar, dir);
14397 
14398    case SCIP_VARSTATUS_LOOSE:
14399    case SCIP_VARSTATUS_COLUMN:
14400       return SCIPhistoryGetPseudocostCount(var->historycrun, dir);
14401 
14402    case SCIP_VARSTATUS_FIXED:
14403       return 0.0;
14404 
14405    case SCIP_VARSTATUS_AGGREGATED:
14406       if( var->data.aggregate.scalar > 0.0 )
14407          return SCIPvarGetPseudocostCountCurrentRun(var->data.aggregate.var, dir);
14408       else
14409          return SCIPvarGetPseudocostCountCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
14410 
14411    case SCIP_VARSTATUS_MULTAGGR:
14412       return 0.0;
14413 
14414    case SCIP_VARSTATUS_NEGATED:
14415       return SCIPvarGetPseudocostCountCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir));
14416 
14417    default:
14418       SCIPerrorMessage("unknown variable status\n");
14419       SCIPABORT();
14420       return 0.0; /*lint !e527*/
14421    }
14422 }
14423 
14424 /** compares both possible directions for rounding the given solution value and returns the minimum pseudo-costs of the variable */
SCIPvarGetMinPseudocostScore(SCIP_VAR * var,SCIP_STAT * stat,SCIP_SET * set,SCIP_Real solval)14425 SCIP_Real SCIPvarGetMinPseudocostScore(
14426    SCIP_VAR*             var,                /**< problem variable */
14427    SCIP_STAT*            stat,               /**< problem statistics */
14428    SCIP_SET*             set,                /**< global SCIP settings */
14429    SCIP_Real             solval              /**< solution value, e.g., LP solution value */
14430    )
14431 {
14432    SCIP_Real upscore;
14433    SCIP_Real downscore;
14434    SCIP_Real solvaldeltaup;
14435    SCIP_Real solvaldeltadown;
14436 
14437    /* LP root estimate only works for variables with fractional LP root solution */
14438    if( SCIPsetIsFeasIntegral(set, solval) )
14439       return 0.0;
14440 
14441    /* no min pseudo-cost score is calculated as long as the variable was not initialized in a direction */
14442    if( SCIPvarGetPseudocostCount(var, SCIP_BRANCHDIR_DOWNWARDS) < 1.0 || SCIPvarGetPseudocostCount(var, SCIP_BRANCHDIR_UPWARDS) < 1.0 )
14443       return 0.0;
14444 
14445    /* compute delta's to ceil and floor of root LP solution value */
14446    solvaldeltaup = SCIPsetCeil(set, solval) - solval;
14447    solvaldeltadown = SCIPsetFloor(set, solval) - solval;
14448 
14449    upscore = SCIPvarGetPseudocost(var, stat, solvaldeltaup);
14450    downscore = SCIPvarGetPseudocost(var, stat, solvaldeltadown);
14451 
14452    return MIN(upscore, downscore);
14453 }
14454 
14455 /** gets the an estimate of the variable's pseudo cost variance in direction \p dir */
SCIPvarGetPseudocostVariance(SCIP_VAR * var,SCIP_BRANCHDIR dir,SCIP_Bool onlycurrentrun)14456 SCIP_Real SCIPvarGetPseudocostVariance(
14457    SCIP_VAR*             var,                /**< problem variable */
14458    SCIP_BRANCHDIR        dir,                /**< branching direction (downwards, or upwards) */
14459    SCIP_Bool             onlycurrentrun      /**< return pseudo cost variance only for current branch and bound run */
14460    )
14461 {
14462    assert(var != NULL);
14463    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14464 
14465    switch( SCIPvarGetStatus(var) )
14466    {
14467    case SCIP_VARSTATUS_ORIGINAL:
14468       if( var->data.original.transvar == NULL )
14469          return 0.0;
14470       else
14471          return SCIPvarGetPseudocostVariance(var->data.original.transvar, dir, onlycurrentrun);
14472 
14473    case SCIP_VARSTATUS_LOOSE:
14474    case SCIP_VARSTATUS_COLUMN:
14475       if( onlycurrentrun )
14476          return SCIPhistoryGetPseudocostVariance(var->historycrun, dir);
14477       else
14478          return SCIPhistoryGetPseudocostVariance(var->history, dir);
14479 
14480    case SCIP_VARSTATUS_FIXED:
14481       return 0.0;
14482 
14483    case SCIP_VARSTATUS_AGGREGATED:
14484       if( var->data.aggregate.scalar > 0.0 )
14485          return SCIPvarGetPseudocostVariance(var->data.aggregate.var, dir, onlycurrentrun);
14486       else
14487          return SCIPvarGetPseudocostVariance(var->data.aggregate.var, SCIPbranchdirOpposite(dir), onlycurrentrun);
14488 
14489    case SCIP_VARSTATUS_MULTAGGR:
14490       return 0.0;
14491 
14492    case SCIP_VARSTATUS_NEGATED:
14493       return SCIPvarGetPseudocostVariance(var->negatedvar, SCIPbranchdirOpposite(dir), onlycurrentrun);
14494 
14495    default:
14496       SCIPerrorMessage("unknown variable status\n");
14497       SCIPABORT();
14498       return 0.0; /*lint !e527*/
14499    }
14500 }
14501 
14502 /** calculates a confidence bound for this variable under the assumption of normally distributed pseudo costs
14503  *
14504  *  The confidence bound \f$ \theta \geq 0\f$ denotes the interval borders \f$ [X - \theta, \ X + \theta]\f$, which contains
14505  *  the true pseudo costs of the variable, i.e., the expected value of the normal distribution, with a probability
14506  *  of 2 * clevel - 1.
14507  *
14508  *  @return value of confidence bound for this variable
14509  */
SCIPvarCalcPscostConfidenceBound(SCIP_VAR * var,SCIP_SET * set,SCIP_BRANCHDIR dir,SCIP_Bool onlycurrentrun,SCIP_CONFIDENCELEVEL clevel)14510 SCIP_Real SCIPvarCalcPscostConfidenceBound(
14511    SCIP_VAR*             var,                /**< variable in question */
14512    SCIP_SET*             set,                /**< global SCIP settings */
14513    SCIP_BRANCHDIR        dir,                /**< the branching direction for the confidence bound */
14514    SCIP_Bool             onlycurrentrun,     /**< should only the current run be taken into account */
14515    SCIP_CONFIDENCELEVEL  clevel              /**< confidence level for the interval */
14516    )
14517 {
14518    SCIP_Real confidencebound;
14519 
14520    confidencebound = SCIPvarGetPseudocostVariance(var, dir, onlycurrentrun);
14521    if( SCIPsetIsFeasPositive(set, confidencebound) )
14522    {
14523       SCIP_Real count;
14524 
14525       if( onlycurrentrun )
14526          count = SCIPvarGetPseudocostCountCurrentRun(var, dir);
14527       else
14528          count = SCIPvarGetPseudocostCount(var, dir);
14529       /* assertion is valid because variance is positive */
14530       assert(count >= 1.9);
14531 
14532       confidencebound /= count; /*lint !e414 division by zero can obviously not occur */
14533       confidencebound = sqrt(confidencebound);
14534 
14535       /* the actual, underlying distribution of the mean is a student-t-distribution with degrees of freedom equal to
14536        * the number of pseudo cost evaluations of this variable in the respective direction. */
14537       confidencebound *= SCIPstudentTGetCriticalValue(clevel, (int)SCIPsetFloor(set, count) - 1);
14538    }
14539    else
14540       confidencebound = 0.0;
14541 
14542    return confidencebound;
14543 }
14544 
14545 /** check if the current pseudo cost relative error in a direction violates the given threshold. The Relative
14546  *  Error is calculated at a specific confidence level
14547  */
SCIPvarIsPscostRelerrorReliable(SCIP_VAR * var,SCIP_SET * set,SCIP_STAT * stat,SCIP_Real threshold,SCIP_CONFIDENCELEVEL clevel)14548 SCIP_Bool SCIPvarIsPscostRelerrorReliable(
14549    SCIP_VAR*             var,                /**< variable in question */
14550    SCIP_SET*             set,                /**< global SCIP settings */
14551    SCIP_STAT*            stat,               /**< problem statistics */
14552    SCIP_Real             threshold,          /**< threshold for relative errors to be considered reliable (enough) */
14553    SCIP_CONFIDENCELEVEL  clevel              /**< a given confidence level */
14554    )
14555 {
14556    SCIP_Real downsize;
14557    SCIP_Real upsize;
14558    SCIP_Real size;
14559    SCIP_Real relerrorup;
14560    SCIP_Real relerrordown;
14561    SCIP_Real relerror;
14562 
14563    /* check, if the pseudo cost score of the variable is reliable */
14564    downsize = SCIPvarGetPseudocostCountCurrentRun(var, SCIP_BRANCHDIR_DOWNWARDS);
14565    upsize = SCIPvarGetPseudocostCountCurrentRun(var, SCIP_BRANCHDIR_UPWARDS);
14566    size = MIN(downsize, upsize);
14567 
14568    /* Pseudo costs relative error can only be reliable if both directions have been tried at least twice */
14569    if( size <= 1.9 )
14570       return FALSE;
14571 
14572    /* use the relative error between the current mean pseudo cost value of the candidate and its upper
14573     * confidence interval bound at confidence level of 95% for individual variable reliability.
14574     * this is only possible if we have at least 2 measurements and therefore a valid variance estimate.
14575     */
14576    if( downsize >= 1.9 )
14577    {
14578       SCIP_Real normval;
14579 
14580       relerrordown = SCIPvarCalcPscostConfidenceBound(var, set, SCIP_BRANCHDIR_DOWNWARDS, TRUE, clevel);
14581       normval = SCIPvarGetPseudocostCurrentRun(var, stat, -1.0);
14582       normval = MAX(1.0, normval);
14583 
14584       relerrordown /= normval;
14585    }
14586    else
14587       relerrordown = 0.0;
14588 
14589    if( upsize >= 1.9 )
14590    {
14591       SCIP_Real normval;
14592 
14593       relerrorup = SCIPvarCalcPscostConfidenceBound(var, set, SCIP_BRANCHDIR_UPWARDS, TRUE, clevel);
14594       normval = SCIPvarGetPseudocostCurrentRun(var, stat, +1.0);
14595       normval = MAX(1.0, normval);
14596       relerrorup /= normval;
14597    }
14598    else
14599       relerrorup = 0.0;
14600 
14601    /* consider the relative error threshold violated, if it is violated in at least one branching direction */
14602    relerror = MAX(relerrorup, relerrordown);
14603 
14604    return (relerror <= threshold);
14605 }
14606 
14607 /** check if variable pseudo-costs have a significant difference in location. The significance depends on
14608  *  the choice of \p clevel and on the kind of tested hypothesis. The one-sided hypothesis, which
14609  *  should be rejected, is that fracy * mu_y >= fracx * mu_x, where mu_y and mu_x denote the
14610  *  unknown location means of the underlying pseudo-cost distributions of x and y.
14611  *
14612  *  This method is applied best if variable x has a better pseudo-cost score than y. The method hypothesizes that y were actually
14613  *  better than x (despite the current information), meaning that y can be expected to yield branching
14614  *  decisions as least as good as x in the long run. If the method returns TRUE, the current history information is
14615  *  sufficient to safely rely on the alternative hypothesis that x yields indeed a better branching score (on average)
14616  *  than y.
14617  *
14618  *  @note The order of x and y matters for the one-sided hypothesis
14619  *
14620  *  @note set \p onesided to FALSE if you are not sure which variable is better. The hypothesis tested then reads
14621  *        fracy * mu_y == fracx * mu_x vs the alternative hypothesis fracy * mu_y != fracx * mu_x.
14622  *
14623  *  @return TRUE if the hypothesis can be safely rejected at the given confidence level
14624  */
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)14625 SCIP_Bool SCIPvarSignificantPscostDifference(
14626    SCIP_SET*             set,                /**< global SCIP settings */
14627    SCIP_STAT*            stat,               /**< problem statistics */
14628    SCIP_VAR*             varx,               /**< variable x */
14629    SCIP_Real             fracx,              /**< the fractionality of variable x */
14630    SCIP_VAR*             vary,               /**< variable y */
14631    SCIP_Real             fracy,              /**< the fractionality of variable y */
14632    SCIP_BRANCHDIR        dir,                /**< branching direction */
14633    SCIP_CONFIDENCELEVEL  clevel,             /**< confidence level for rejecting hypothesis */
14634    SCIP_Bool             onesided            /**< should a one-sided hypothesis y >= x be tested? */
14635    )
14636 {
14637    SCIP_Real meanx;
14638    SCIP_Real meany;
14639    SCIP_Real variancex;
14640    SCIP_Real variancey;
14641    SCIP_Real countx;
14642    SCIP_Real county;
14643    SCIP_Real tresult;
14644    SCIP_Real realdirection;
14645 
14646    if( varx == vary )
14647       return FALSE;
14648 
14649    countx = SCIPvarGetPseudocostCount(varx, dir);
14650    county = SCIPvarGetPseudocostCount(vary, dir);
14651 
14652    /* if not at least 2 measurements were taken, return FALSE */
14653    if( countx <= 1.9 || county <= 1.9 )
14654       return FALSE;
14655 
14656    realdirection = (dir == SCIP_BRANCHDIR_DOWNWARDS ? -1.0 : 1.0);
14657 
14658    meanx = fracx * SCIPvarGetPseudocost(varx, stat, realdirection);
14659    meany = fracy * SCIPvarGetPseudocost(vary, stat, realdirection);
14660 
14661    variancex = SQR(fracx) * SCIPvarGetPseudocostVariance(varx, dir, FALSE);
14662    variancey = SQR(fracy) * SCIPvarGetPseudocostVariance(vary, dir, FALSE);
14663 
14664    /* if there is no variance, the means are taken from a constant distribution */
14665    if( SCIPsetIsFeasEQ(set, variancex + variancey, 0.0) )
14666       return (onesided ? SCIPsetIsFeasGT(set, meanx, meany) : !SCIPsetIsFeasEQ(set, meanx, meany));
14667 
14668    tresult = SCIPcomputeTwoSampleTTestValue(meanx, meany, variancex, variancey, countx, county);
14669 
14670    /* for the two-sided hypothesis, just take the absolute of t */
14671    if( !onesided )
14672       tresult = REALABS(tresult);
14673 
14674    return (tresult >= SCIPstudentTGetCriticalValue(clevel, (int)(countx + county - 2)));
14675 }
14676 
14677 /** tests at a given confidence level whether the variable pseudo-costs only have a small probability to
14678  *  exceed a \p threshold. This is useful to determine if past observations provide enough evidence
14679  *  to skip an expensive strong-branching step if there is already a candidate that has been proven to yield an improvement
14680  *  of at least \p threshold.
14681  *
14682  *  @note use \p clevel to adjust the level of confidence. For SCIP_CONFIDENCELEVEL_MIN, the method returns TRUE if
14683  *        the estimated probability to exceed \p threshold is less than 25 %.
14684  *
14685  *  @see  SCIP_Confidencelevel for a list of available levels. The used probability limits refer to the one-sided levels
14686  *        of confidence.
14687  *
14688  *  @return TRUE if the variable pseudo-cost probabilistic model is likely to be smaller than \p threshold
14689  *          at the given confidence level \p clevel.
14690  */
SCIPvarPscostThresholdProbabilityTest(SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR * var,SCIP_Real frac,SCIP_Real threshold,SCIP_BRANCHDIR dir,SCIP_CONFIDENCELEVEL clevel)14691 SCIP_Bool SCIPvarPscostThresholdProbabilityTest(
14692    SCIP_SET*             set,                /**< global SCIP settings */
14693    SCIP_STAT*            stat,               /**< problem statistics */
14694    SCIP_VAR*             var,                /**< variable x */
14695    SCIP_Real             frac,               /**< the fractionality of variable x */
14696    SCIP_Real             threshold,          /**< the threshold to test against */
14697    SCIP_BRANCHDIR        dir,                /**< branching direction */
14698    SCIP_CONFIDENCELEVEL  clevel              /**< confidence level for rejecting hypothesis */
14699    )
14700 {
14701    SCIP_Real mean;
14702    SCIP_Real variance;
14703    SCIP_Real count;
14704    SCIP_Real realdirection;
14705    SCIP_Real probability;
14706    SCIP_Real problimit;
14707 
14708    count = SCIPvarGetPseudocostCount(var, dir);
14709 
14710    /* if not at least 2 measurements were taken, return FALSE */
14711    if( count <= 1.9 )
14712       return FALSE;
14713 
14714    realdirection = (dir == SCIP_BRANCHDIR_DOWNWARDS ? -1.0 : 1.0);
14715 
14716    mean = frac * SCIPvarGetPseudocost(var, stat, realdirection);
14717    variance = SQR(frac) * SCIPvarGetPseudocostVariance(var, dir, FALSE);
14718 
14719    /* if mean is at least threshold, it has at least a 50% probability to exceed threshold, we therefore return FALSE */
14720    if( SCIPsetIsFeasGE(set, mean, threshold) )
14721       return FALSE;
14722 
14723    /* if there is no variance, the means are taken from a constant distribution */
14724    if( SCIPsetIsFeasEQ(set, variance, 0.0) )
14725       return SCIPsetIsFeasLT(set, mean, threshold);
14726 
14727    /* obtain probability of a normally distributed random variable at given mean and variance to yield at most threshold */
14728    probability = SCIPnormalCDF(mean, variance, threshold);
14729 
14730    /* determine a probability limit corresponding to the given confidence level */
14731    switch( clevel )
14732    {
14733       case SCIP_CONFIDENCELEVEL_MIN:
14734          problimit = 0.75;
14735          break;
14736       case SCIP_CONFIDENCELEVEL_LOW:
14737          problimit = 0.875;
14738          break;
14739       case SCIP_CONFIDENCELEVEL_MEDIUM:
14740          problimit = 0.9;
14741          break;
14742       case SCIP_CONFIDENCELEVEL_HIGH:
14743          problimit = 0.95;
14744          break;
14745       case SCIP_CONFIDENCELEVEL_MAX:
14746          problimit = 0.975;
14747          break;
14748       default:
14749          problimit = -1;
14750          SCIPerrorMessage("Confidence level set to unknown value <%d>", (int)clevel);
14751          SCIPABORT();
14752          break;
14753    }
14754 
14755    return (probability >= problimit);
14756 }
14757 
14758 /** find the corresponding history entry if already existing, otherwise create new entry */
14759 static
findValuehistoryEntry(SCIP_VAR * var,SCIP_Real value,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_HISTORY ** history)14760 SCIP_RETCODE findValuehistoryEntry(
14761    SCIP_VAR*             var,                /**< problem variable */
14762    SCIP_Real             value,              /**< domain value, or SCIP_UNKNOWN */
14763    BMS_BLKMEM*           blkmem,             /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
14764    SCIP_SET*             set,                /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
14765    SCIP_HISTORY**        history             /**< pointer to store the value based history, or NULL */
14766    )
14767 {
14768    assert(var != NULL);
14769    assert(blkmem != NULL);
14770    assert(set != NULL);
14771    assert(history != NULL);
14772 
14773    (*history) = NULL;
14774 
14775    if( var->valuehistory == NULL )
14776    {
14777       SCIP_CALL( SCIPvaluehistoryCreate(&var->valuehistory, blkmem) );
14778    }
14779 
14780    SCIP_CALL( SCIPvaluehistoryFind(var->valuehistory, blkmem, set, value, history) );
14781 
14782    return SCIP_OKAY;
14783 }
14784 
14785 /** check if value based history should be used */
14786 static
useValuehistory(SCIP_VAR * var,SCIP_Real value,SCIP_SET * set)14787 SCIP_Bool useValuehistory(
14788    SCIP_VAR*             var,                /**< problem variable */
14789    SCIP_Real             value,              /**< domain value, or SCIP_UNKNOWN */
14790    SCIP_SET*             set                 /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
14791    )
14792 {
14793    /* check if the domain value is unknown (not specific) */
14794    if( value == SCIP_UNKNOWN ) /*lint !e777*/
14795       return FALSE;
14796 
14797    assert(set != NULL);
14798 
14799    /* check if value based history should be collected */
14800    if( !set->history_valuebased )
14801       return FALSE;
14802 
14803    /* value based history is not collected for binary variable since the standard history already contains all information */
14804    if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
14805       return FALSE;
14806 
14807    /* value based history is not collected for continuous variables */
14808    if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
14809       return FALSE;
14810 
14811    return TRUE;
14812 }
14813 
14814 /** increases VSIDS of the variable by the given weight */
SCIPvarIncVSIDS(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_BRANCHDIR dir,SCIP_Real value,SCIP_Real weight)14815 SCIP_RETCODE SCIPvarIncVSIDS(
14816    SCIP_VAR*             var,                /**< problem variable */
14817    BMS_BLKMEM*           blkmem,             /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
14818    SCIP_SET*             set,                /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
14819    SCIP_STAT*            stat,               /**< problem statistics */
14820    SCIP_BRANCHDIR        dir,                /**< branching direction */
14821    SCIP_Real             value,              /**< domain value, or SCIP_UNKNOWN */
14822    SCIP_Real             weight              /**< weight of this update in VSIDS */
14823    )
14824 {
14825    assert(var != NULL);
14826    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14827 
14828    /* check if history statistics should be collected for a variable */
14829    if( !stat->collectvarhistory )
14830       return SCIP_OKAY;
14831 
14832    if( SCIPsetIsZero(set, weight) )
14833       return SCIP_OKAY;
14834 
14835    switch( SCIPvarGetStatus(var) )
14836    {
14837    case SCIP_VARSTATUS_ORIGINAL:
14838       if( var->data.original.transvar == NULL )
14839       {
14840          SCIPerrorMessage("cannot update VSIDS of original untransformed variable\n");
14841          return SCIP_INVALIDDATA;
14842       }
14843       SCIP_CALL( SCIPvarIncVSIDS(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
14844       return SCIP_OKAY;
14845 
14846    case SCIP_VARSTATUS_LOOSE:
14847    case SCIP_VARSTATUS_COLUMN:
14848    {
14849       SCIPhistoryIncVSIDS(var->history, dir, weight);
14850       SCIPhistoryIncVSIDS(var->historycrun, dir, weight);
14851 
14852       if( useValuehistory(var, value, set) )
14853       {
14854          SCIP_HISTORY* history;
14855 
14856          SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
14857          assert(history != NULL);
14858 
14859          SCIPhistoryIncVSIDS(history, dir, weight);
14860          SCIPsetDebugMsg(set, "variable (<%s> %s %g) + <%g> = <%g>\n", SCIPvarGetName(var), dir == SCIP_BRANCHDIR_UPWARDS ? ">=" : "<=",
14861             value, weight, SCIPhistoryGetVSIDS(history, dir));
14862       }
14863 
14864       return SCIP_OKAY;
14865    }
14866    case SCIP_VARSTATUS_FIXED:
14867       SCIPerrorMessage("cannot update VSIDS of a fixed variable\n");
14868       return SCIP_INVALIDDATA;
14869 
14870    case SCIP_VARSTATUS_AGGREGATED:
14871       value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
14872 
14873       if( var->data.aggregate.scalar > 0.0 )
14874       {
14875          SCIP_CALL( SCIPvarIncVSIDS(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
14876       }
14877       else
14878       {
14879          assert(var->data.aggregate.scalar < 0.0);
14880          SCIP_CALL( SCIPvarIncVSIDS(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
14881       }
14882       return SCIP_OKAY;
14883 
14884    case SCIP_VARSTATUS_MULTAGGR:
14885       SCIPerrorMessage("cannot update VSIDS of a multi-aggregated variable\n");
14886       return SCIP_INVALIDDATA;
14887 
14888    case SCIP_VARSTATUS_NEGATED:
14889       value = 1.0 - value;
14890 
14891       SCIP_CALL( SCIPvarIncVSIDS(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
14892       return SCIP_OKAY;
14893 
14894    default:
14895       SCIPerrorMessage("unknown variable status\n");
14896       return SCIP_INVALIDDATA;
14897    }
14898 }
14899 
14900 /** scales the VSIDS of the variable by the given scalar */
SCIPvarScaleVSIDS(SCIP_VAR * var,SCIP_Real scalar)14901 SCIP_RETCODE SCIPvarScaleVSIDS(
14902    SCIP_VAR*             var,                /**< problem variable */
14903    SCIP_Real             scalar              /**< scalar to multiply the VSIDSs with */
14904    )
14905 {
14906    assert(var != NULL);
14907 
14908    switch( SCIPvarGetStatus(var) )
14909    {
14910    case SCIP_VARSTATUS_ORIGINAL:
14911       if( var->data.original.transvar == NULL )
14912       {
14913          SCIPerrorMessage("cannot update VSIDS of original untransformed variable\n");
14914          return SCIP_INVALIDDATA;
14915       }
14916       SCIP_CALL( SCIPvarScaleVSIDS(var->data.original.transvar, scalar) );
14917       return SCIP_OKAY;
14918 
14919    case SCIP_VARSTATUS_LOOSE:
14920    case SCIP_VARSTATUS_COLUMN:
14921    {
14922       SCIPhistoryScaleVSIDS(var->history, scalar);
14923       SCIPhistoryScaleVSIDS(var->historycrun, scalar);
14924       SCIPvaluehistoryScaleVSIDS(var->valuehistory, scalar);
14925 
14926       return SCIP_OKAY;
14927    }
14928    case SCIP_VARSTATUS_FIXED:
14929       SCIPerrorMessage("cannot update VSIDS of a fixed variable\n");
14930       return SCIP_INVALIDDATA;
14931 
14932    case SCIP_VARSTATUS_AGGREGATED:
14933       SCIP_CALL( SCIPvarScaleVSIDS(var->data.aggregate.var, scalar) );
14934       return SCIP_OKAY;
14935 
14936    case SCIP_VARSTATUS_MULTAGGR:
14937       SCIPerrorMessage("cannot update VSIDS of a multi-aggregated variable\n");
14938       return SCIP_INVALIDDATA;
14939 
14940    case SCIP_VARSTATUS_NEGATED:
14941       SCIP_CALL( SCIPvarScaleVSIDS(var->negatedvar, scalar) );
14942       return SCIP_OKAY;
14943 
14944    default:
14945       SCIPerrorMessage("unknown variable status\n");
14946       return SCIP_INVALIDDATA;
14947    }
14948 }
14949 
14950 /** increases the number of active conflicts by one and the overall length of the variable by the given length */
SCIPvarIncNActiveConflicts(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_BRANCHDIR dir,SCIP_Real value,SCIP_Real length)14951 SCIP_RETCODE SCIPvarIncNActiveConflicts(
14952    SCIP_VAR*             var,                /**< problem variable */
14953    BMS_BLKMEM*           blkmem,             /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
14954    SCIP_SET*             set,                /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
14955    SCIP_STAT*            stat,               /**< problem statistics */
14956    SCIP_BRANCHDIR        dir,                /**< branching direction */
14957    SCIP_Real             value,              /**< domain value, or SCIP_UNKNOWN */
14958    SCIP_Real             length              /**< length of the conflict */
14959    )
14960 {
14961    assert(var != NULL);
14962    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
14963 
14964    /* check if history statistics should be collected for a variable */
14965    if( !stat->collectvarhistory )
14966       return SCIP_OKAY;
14967 
14968    switch( SCIPvarGetStatus(var) )
14969    {
14970    case SCIP_VARSTATUS_ORIGINAL:
14971       if( var->data.original.transvar == NULL )
14972       {
14973          SCIPerrorMessage("cannot update conflict score of original untransformed variable\n");
14974          return SCIP_INVALIDDATA;
14975       }
14976       SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.original.transvar, blkmem, set, stat, dir, value, length) );
14977       return SCIP_OKAY;
14978 
14979    case SCIP_VARSTATUS_LOOSE:
14980    case SCIP_VARSTATUS_COLUMN:
14981    {
14982       SCIPhistoryIncNActiveConflicts(var->history, dir, length);
14983       SCIPhistoryIncNActiveConflicts(var->historycrun, dir, length);
14984 
14985       if( useValuehistory(var, value, set) )
14986       {
14987          SCIP_HISTORY* history;
14988 
14989          SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
14990          assert(history != NULL);
14991 
14992          SCIPhistoryIncNActiveConflicts(history, dir, length);
14993       }
14994 
14995       return SCIP_OKAY;
14996    }
14997    case SCIP_VARSTATUS_FIXED:
14998       SCIPerrorMessage("cannot update conflict score of a fixed variable\n");
14999       return SCIP_INVALIDDATA;
15000 
15001    case SCIP_VARSTATUS_AGGREGATED:
15002       value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15003 
15004       if( var->data.aggregate.scalar > 0.0 )
15005       {
15006          SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.aggregate.var, blkmem, set, stat, dir, value, length) );
15007       }
15008       else
15009       {
15010          assert(var->data.aggregate.scalar < 0.0);
15011          SCIP_CALL( SCIPvarIncNActiveConflicts(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, length) );
15012       }
15013       return SCIP_OKAY;
15014 
15015    case SCIP_VARSTATUS_MULTAGGR:
15016       SCIPerrorMessage("cannot update conflict score of a multi-aggregated variable\n");
15017       return SCIP_INVALIDDATA;
15018 
15019    case SCIP_VARSTATUS_NEGATED:
15020       value = 1.0 - value;
15021 
15022       SCIP_CALL( SCIPvarIncNActiveConflicts(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, length) );
15023       return SCIP_OKAY;
15024 
15025    default:
15026       SCIPerrorMessage("unknown variable status\n");
15027       return SCIP_INVALIDDATA;
15028    }
15029 }
15030 
15031 /** gets the number of active conflicts containing this variable in given direction */
SCIPvarGetNActiveConflicts(SCIP_VAR * var,SCIP_STAT * stat,SCIP_BRANCHDIR dir)15032 SCIP_Longint SCIPvarGetNActiveConflicts(
15033    SCIP_VAR*             var,                /**< problem variable */
15034    SCIP_STAT*            stat,               /**< problem statistics */
15035    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15036    )
15037 {
15038    assert(var != NULL);
15039    assert(stat != NULL);
15040    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15041 
15042    switch( SCIPvarGetStatus(var) )
15043    {
15044    case SCIP_VARSTATUS_ORIGINAL:
15045       if( var->data.original.transvar == NULL )
15046          return 0;
15047       else
15048          return SCIPvarGetNActiveConflicts(var->data.original.transvar, stat, dir);
15049 
15050    case SCIP_VARSTATUS_LOOSE:
15051    case SCIP_VARSTATUS_COLUMN:
15052       return SCIPhistoryGetNActiveConflicts(var->history, dir);
15053 
15054    case SCIP_VARSTATUS_FIXED:
15055       return 0;
15056 
15057    case SCIP_VARSTATUS_AGGREGATED:
15058       if( var->data.aggregate.scalar > 0.0 )
15059          return SCIPvarGetNActiveConflicts(var->data.aggregate.var, stat, dir);
15060       else
15061          return SCIPvarGetNActiveConflicts(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
15062 
15063    case SCIP_VARSTATUS_MULTAGGR:
15064       return 0;
15065 
15066    case SCIP_VARSTATUS_NEGATED:
15067       return SCIPvarGetNActiveConflicts(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
15068 
15069    default:
15070       SCIPerrorMessage("unknown variable status\n");
15071       SCIPABORT();
15072       return 0; /*lint !e527*/
15073    }
15074 }
15075 
15076 /** gets the number of active conflicts containing this variable in given direction
15077  *  in the current run
15078  */
SCIPvarGetNActiveConflictsCurrentRun(SCIP_VAR * var,SCIP_STAT * stat,SCIP_BRANCHDIR dir)15079 SCIP_Longint SCIPvarGetNActiveConflictsCurrentRun(
15080    SCIP_VAR*             var,                /**< problem variable */
15081    SCIP_STAT*            stat,               /**< problem statistics */
15082    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15083    )
15084 {
15085    assert(var != NULL);
15086    assert(stat != NULL);
15087    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15088 
15089    switch( SCIPvarGetStatus(var) )
15090    {
15091    case SCIP_VARSTATUS_ORIGINAL:
15092       if( var->data.original.transvar == NULL )
15093          return 0;
15094       else
15095          return SCIPvarGetNActiveConflictsCurrentRun(var->data.original.transvar, stat, dir);
15096 
15097    case SCIP_VARSTATUS_LOOSE:
15098    case SCIP_VARSTATUS_COLUMN:
15099       return SCIPhistoryGetNActiveConflicts(var->historycrun, dir);
15100 
15101    case SCIP_VARSTATUS_FIXED:
15102       return 0;
15103 
15104    case SCIP_VARSTATUS_AGGREGATED:
15105       if( var->data.aggregate.scalar > 0.0 )
15106          return SCIPvarGetNActiveConflictsCurrentRun(var->data.aggregate.var, stat, dir);
15107       else
15108          return SCIPvarGetNActiveConflictsCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
15109 
15110    case SCIP_VARSTATUS_MULTAGGR:
15111       return 0;
15112 
15113    case SCIP_VARSTATUS_NEGATED:
15114       return SCIPvarGetNActiveConflictsCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
15115 
15116    default:
15117       SCIPerrorMessage("unknown variable status\n");
15118       SCIPABORT();
15119       return 0; /*lint !e527*/
15120    }
15121 }
15122 
15123 /** gets the average conflict length in given direction due to branching on the variable */
SCIPvarGetAvgConflictlength(SCIP_VAR * var,SCIP_BRANCHDIR dir)15124 SCIP_Real SCIPvarGetAvgConflictlength(
15125    SCIP_VAR*             var,                /**< problem variable */
15126    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15127    )
15128 {
15129    assert(var != NULL);
15130    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15131 
15132    switch( SCIPvarGetStatus(var) )
15133    {
15134    case SCIP_VARSTATUS_ORIGINAL:
15135       if( var->data.original.transvar == NULL )
15136          return 0.0;
15137       else
15138          return SCIPvarGetAvgConflictlength(var->data.original.transvar, dir);
15139 
15140    case SCIP_VARSTATUS_LOOSE:
15141    case SCIP_VARSTATUS_COLUMN:
15142          return SCIPhistoryGetAvgConflictlength(var->history, dir);
15143    case SCIP_VARSTATUS_FIXED:
15144       return 0.0;
15145 
15146    case SCIP_VARSTATUS_AGGREGATED:
15147       if( var->data.aggregate.scalar > 0.0 )
15148          return SCIPvarGetAvgConflictlength(var->data.aggregate.var, dir);
15149       else
15150          return SCIPvarGetAvgConflictlength(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15151 
15152    case SCIP_VARSTATUS_MULTAGGR:
15153       return 0.0;
15154 
15155    case SCIP_VARSTATUS_NEGATED:
15156       return SCIPvarGetAvgConflictlength(var->negatedvar, SCIPbranchdirOpposite(dir));
15157 
15158    default:
15159       SCIPerrorMessage("unknown variable status\n");
15160       SCIPABORT();
15161       return 0.0; /*lint !e527*/
15162    }
15163 }
15164 
15165 /**  gets the average conflict length in given direction due to branching on the variable
15166  *   in the current run
15167  */
SCIPvarGetAvgConflictlengthCurrentRun(SCIP_VAR * var,SCIP_BRANCHDIR dir)15168 SCIP_Real SCIPvarGetAvgConflictlengthCurrentRun(
15169    SCIP_VAR*             var,                /**< problem variable */
15170    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15171    )
15172 {
15173    assert(var != NULL);
15174    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15175 
15176    switch( SCIPvarGetStatus(var) )
15177    {
15178    case SCIP_VARSTATUS_ORIGINAL:
15179       if( var->data.original.transvar == NULL )
15180          return 0.0;
15181       else
15182          return SCIPvarGetAvgConflictlengthCurrentRun(var->data.original.transvar, dir);
15183 
15184    case SCIP_VARSTATUS_LOOSE:
15185    case SCIP_VARSTATUS_COLUMN:
15186       return  SCIPhistoryGetAvgConflictlength(var->historycrun, dir);
15187 
15188    case SCIP_VARSTATUS_FIXED:
15189       return 0.0;
15190 
15191    case SCIP_VARSTATUS_AGGREGATED:
15192       if( var->data.aggregate.scalar > 0.0 )
15193          return SCIPvarGetAvgConflictlengthCurrentRun(var->data.aggregate.var, dir);
15194       else
15195          return SCIPvarGetAvgConflictlengthCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15196 
15197    case SCIP_VARSTATUS_MULTAGGR:
15198       return 0.0;
15199 
15200    case SCIP_VARSTATUS_NEGATED:
15201       return SCIPvarGetAvgConflictlengthCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir));
15202 
15203    default:
15204       SCIPerrorMessage("unknown variable status\n");
15205       SCIPABORT();
15206       return 0.0; /*lint !e527*/
15207    }
15208 }
15209 
15210 /** increases the number of branchings counter of the variable */
SCIPvarIncNBranchings(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_BRANCHDIR dir,SCIP_Real value,int depth)15211 SCIP_RETCODE SCIPvarIncNBranchings(
15212    SCIP_VAR*             var,                /**< problem variable */
15213    BMS_BLKMEM*           blkmem,             /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15214    SCIP_SET*             set,                /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15215    SCIP_STAT*            stat,               /**< problem statistics */
15216    SCIP_BRANCHDIR        dir,                /**< branching direction (downwards, or upwards) */
15217    SCIP_Real             value,              /**< domain value, or SCIP_UNKNOWN */
15218    int                   depth               /**< depth at which the bound change took place */
15219    )
15220 {
15221    assert(var != NULL);
15222    assert(stat != NULL);
15223    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15224 
15225    /* check if history statistics should be collected for a variable */
15226    if( !stat->collectvarhistory )
15227       return SCIP_OKAY;
15228 
15229    switch( SCIPvarGetStatus(var) )
15230    {
15231    case SCIP_VARSTATUS_ORIGINAL:
15232       if( var->data.original.transvar == NULL )
15233       {
15234          SCIPerrorMessage("cannot update branching counter of original untransformed variable\n");
15235          return SCIP_INVALIDDATA;
15236       }
15237       SCIP_CALL( SCIPvarIncNBranchings(var->data.original.transvar, blkmem, set, stat, dir, value, depth) );
15238       return SCIP_OKAY;
15239 
15240    case SCIP_VARSTATUS_LOOSE:
15241    case SCIP_VARSTATUS_COLUMN:
15242    {
15243       SCIPhistoryIncNBranchings(var->history, dir, depth);
15244       SCIPhistoryIncNBranchings(var->historycrun, dir, depth);
15245       SCIPhistoryIncNBranchings(stat->glbhistory, dir, depth);
15246       SCIPhistoryIncNBranchings(stat->glbhistorycrun, dir, depth);
15247 
15248       if( useValuehistory(var, value, set) )
15249       {
15250          SCIP_HISTORY* history;
15251 
15252          SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15253          assert(history != NULL);
15254 
15255          SCIPhistoryIncNBranchings(history, dir, depth);
15256       }
15257 
15258       return SCIP_OKAY;
15259    }
15260    case SCIP_VARSTATUS_FIXED:
15261       SCIPerrorMessage("cannot update branching counter of a fixed variable\n");
15262       return SCIP_INVALIDDATA;
15263 
15264    case SCIP_VARSTATUS_AGGREGATED:
15265       value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15266 
15267       if( var->data.aggregate.scalar > 0.0 )
15268       {
15269          SCIP_CALL( SCIPvarIncNBranchings(var->data.aggregate.var, blkmem, set, stat, dir, value, depth) );
15270       }
15271       else
15272       {
15273          assert(var->data.aggregate.scalar < 0.0);
15274          SCIP_CALL( SCIPvarIncNBranchings(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, depth) );
15275       }
15276       return SCIP_OKAY;
15277 
15278    case SCIP_VARSTATUS_MULTAGGR:
15279       SCIPerrorMessage("cannot update branching counter of a multi-aggregated variable\n");
15280       return SCIP_INVALIDDATA;
15281 
15282    case SCIP_VARSTATUS_NEGATED:
15283       value = 1.0 - value;
15284 
15285       SCIP_CALL( SCIPvarIncNBranchings(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, depth) );
15286       return SCIP_OKAY;
15287 
15288    default:
15289       SCIPerrorMessage("unknown variable status\n");
15290       return SCIP_INVALIDDATA;
15291    }
15292 }
15293 
15294 /** increases the inference sum of the variable by the given weight */
SCIPvarIncInferenceSum(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_BRANCHDIR dir,SCIP_Real value,SCIP_Real weight)15295 SCIP_RETCODE SCIPvarIncInferenceSum(
15296    SCIP_VAR*             var,                /**< problem variable */
15297    BMS_BLKMEM*           blkmem,             /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15298    SCIP_SET*             set,                /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15299    SCIP_STAT*            stat,               /**< problem statistics */
15300    SCIP_BRANCHDIR        dir,                /**< branching direction (downwards, or upwards) */
15301    SCIP_Real             value,              /**< domain value, or SCIP_UNKNOWN */
15302    SCIP_Real             weight              /**< weight of this update in inference score */
15303    )
15304 {
15305    assert(var != NULL);
15306    assert(stat != NULL);
15307    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15308 
15309    /* check if history statistics should be collected for a variable */
15310    if( !stat->collectvarhistory )
15311       return SCIP_OKAY;
15312 
15313    switch( SCIPvarGetStatus(var) )
15314    {
15315    case SCIP_VARSTATUS_ORIGINAL:
15316       if( var->data.original.transvar == NULL )
15317       {
15318          SCIPerrorMessage("cannot update inference counter of original untransformed variable\n");
15319          return SCIP_INVALIDDATA;
15320       }
15321       SCIP_CALL( SCIPvarIncInferenceSum(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
15322       return SCIP_OKAY;
15323 
15324    case SCIP_VARSTATUS_LOOSE:
15325    case SCIP_VARSTATUS_COLUMN:
15326    {
15327       SCIPhistoryIncInferenceSum(var->history, dir, weight);
15328       SCIPhistoryIncInferenceSum(var->historycrun, dir, weight);
15329       SCIPhistoryIncInferenceSum(stat->glbhistory, dir, weight);
15330       SCIPhistoryIncInferenceSum(stat->glbhistorycrun, dir, weight);
15331 
15332       if( useValuehistory(var, value, set) )
15333       {
15334          SCIP_HISTORY* history;
15335 
15336          SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15337          assert(history != NULL);
15338 
15339          SCIPhistoryIncInferenceSum(history, dir, weight);
15340       }
15341 
15342       return SCIP_OKAY;
15343    }
15344    case SCIP_VARSTATUS_FIXED:
15345       SCIPerrorMessage("cannot update inference counter of a fixed variable\n");
15346       return SCIP_INVALIDDATA;
15347 
15348    case SCIP_VARSTATUS_AGGREGATED:
15349       value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15350 
15351       if( var->data.aggregate.scalar > 0.0 )
15352       {
15353          SCIP_CALL( SCIPvarIncInferenceSum(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
15354       }
15355       else
15356       {
15357          assert(var->data.aggregate.scalar < 0.0);
15358          SCIP_CALL( SCIPvarIncInferenceSum(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15359       }
15360       return SCIP_OKAY;
15361 
15362    case SCIP_VARSTATUS_MULTAGGR:
15363       SCIPerrorMessage("cannot update inference counter of a multi-aggregated variable\n");
15364       return SCIP_INVALIDDATA;
15365 
15366    case SCIP_VARSTATUS_NEGATED:
15367       value = 1.0 - value;
15368 
15369       SCIP_CALL( SCIPvarIncInferenceSum(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15370       return SCIP_OKAY;
15371 
15372    default:
15373       SCIPerrorMessage("unknown variable status\n");
15374       return SCIP_INVALIDDATA;
15375    }
15376 }
15377 
15378 /** increases the cutoff sum of the variable by the given weight */
SCIPvarIncCutoffSum(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_BRANCHDIR dir,SCIP_Real value,SCIP_Real weight)15379 SCIP_RETCODE SCIPvarIncCutoffSum(
15380    SCIP_VAR*             var,                /**< problem variable */
15381    BMS_BLKMEM*           blkmem,             /**< block memory, or NULL if the domain value is SCIP_UNKNOWN */
15382    SCIP_SET*             set,                /**< global SCIP settings, or NULL if the domain value is SCIP_UNKNOWN */
15383    SCIP_STAT*            stat,               /**< problem statistics */
15384    SCIP_BRANCHDIR        dir,                /**< branching direction (downwards, or upwards) */
15385    SCIP_Real             value,              /**< domain value, or SCIP_UNKNOWN */
15386    SCIP_Real             weight              /**< weight of this update in cutoff score */
15387    )
15388 {
15389    assert(var != NULL);
15390    assert(stat != NULL);
15391    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15392 
15393    /* check if history statistics should be collected for a variable */
15394    if( !stat->collectvarhistory )
15395       return SCIP_OKAY;
15396 
15397    switch( SCIPvarGetStatus(var) )
15398    {
15399    case SCIP_VARSTATUS_ORIGINAL:
15400       if( var->data.original.transvar == NULL )
15401       {
15402          SCIPerrorMessage("cannot update cutoff sum of original untransformed variable\n");
15403          return SCIP_INVALIDDATA;
15404       }
15405       SCIP_CALL( SCIPvarIncCutoffSum(var->data.original.transvar, blkmem, set, stat, dir, value, weight) );
15406       return SCIP_OKAY;
15407 
15408    case SCIP_VARSTATUS_LOOSE:
15409    case SCIP_VARSTATUS_COLUMN:
15410    {
15411       SCIPhistoryIncCutoffSum(var->history, dir, weight);
15412       SCIPhistoryIncCutoffSum(var->historycrun, dir, weight);
15413       SCIPhistoryIncCutoffSum(stat->glbhistory, dir, weight);
15414       SCIPhistoryIncCutoffSum(stat->glbhistorycrun, dir, weight);
15415 
15416       if( useValuehistory(var, value, set) )
15417       {
15418          SCIP_HISTORY* history;
15419 
15420          SCIP_CALL( findValuehistoryEntry(var, value, blkmem, set, &history) );
15421          assert(history != NULL);
15422 
15423          SCIPhistoryIncCutoffSum(history, dir, weight);
15424       }
15425 
15426       return SCIP_OKAY;
15427    }
15428    case SCIP_VARSTATUS_FIXED:
15429       SCIPerrorMessage("cannot update cutoff sum of a fixed variable\n");
15430       return SCIP_INVALIDDATA;
15431 
15432    case SCIP_VARSTATUS_AGGREGATED:
15433       value = (value - var->data.aggregate.constant)/var->data.aggregate.scalar;
15434 
15435       if( var->data.aggregate.scalar > 0.0 )
15436       {
15437          SCIP_CALL( SCIPvarIncCutoffSum(var->data.aggregate.var, blkmem, set, stat, dir, value, weight) );
15438       }
15439       else
15440       {
15441          assert(var->data.aggregate.scalar < 0.0);
15442          SCIP_CALL( SCIPvarIncCutoffSum(var->data.aggregate.var, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15443       }
15444       return SCIP_OKAY;
15445 
15446    case SCIP_VARSTATUS_MULTAGGR:
15447       SCIPerrorMessage("cannot update cutoff sum of a multi-aggregated variable\n");
15448       return SCIP_INVALIDDATA;
15449 
15450    case SCIP_VARSTATUS_NEGATED:
15451       value = 1.0 - value;
15452 
15453       SCIP_CALL( SCIPvarIncCutoffSum(var->negatedvar, blkmem, set, stat, SCIPbranchdirOpposite(dir), value, weight) );
15454       return SCIP_OKAY;
15455 
15456    default:
15457       SCIPerrorMessage("unknown variable status\n");
15458       return SCIP_INVALIDDATA;
15459    }
15460 }
15461 
15462 /** returns the number of times, a bound of the variable was changed in given direction due to branching */
SCIPvarGetNBranchings(SCIP_VAR * var,SCIP_BRANCHDIR dir)15463 SCIP_Longint SCIPvarGetNBranchings(
15464    SCIP_VAR*             var,                /**< problem variable */
15465    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15466    )
15467 {
15468    assert(var != NULL);
15469    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15470 
15471    switch( SCIPvarGetStatus(var) )
15472    {
15473    case SCIP_VARSTATUS_ORIGINAL:
15474       if( var->data.original.transvar == NULL )
15475          return 0;
15476       else
15477          return SCIPvarGetNBranchings(var->data.original.transvar, dir);
15478 
15479    case SCIP_VARSTATUS_LOOSE:
15480    case SCIP_VARSTATUS_COLUMN:
15481       return SCIPhistoryGetNBranchings(var->history, dir);
15482 
15483    case SCIP_VARSTATUS_FIXED:
15484       return 0;
15485 
15486    case SCIP_VARSTATUS_AGGREGATED:
15487       if( var->data.aggregate.scalar > 0.0 )
15488          return SCIPvarGetNBranchings(var->data.aggregate.var, dir);
15489       else
15490          return SCIPvarGetNBranchings(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15491 
15492    case SCIP_VARSTATUS_MULTAGGR:
15493       return 0;
15494 
15495    case SCIP_VARSTATUS_NEGATED:
15496       return SCIPvarGetNBranchings(var->negatedvar, SCIPbranchdirOpposite(dir));
15497 
15498    default:
15499       SCIPerrorMessage("unknown variable status\n");
15500       SCIPABORT();
15501       return 0; /*lint !e527*/
15502    }
15503 }
15504 
15505 /** returns the number of times, a bound of the variable was changed in given direction due to branching
15506  *  in the current run
15507  */
SCIPvarGetNBranchingsCurrentRun(SCIP_VAR * var,SCIP_BRANCHDIR dir)15508 SCIP_Longint SCIPvarGetNBranchingsCurrentRun(
15509    SCIP_VAR*             var,                /**< problem variable */
15510    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15511    )
15512 {
15513    assert(var != NULL);
15514    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15515 
15516    switch( SCIPvarGetStatus(var) )
15517    {
15518    case SCIP_VARSTATUS_ORIGINAL:
15519       if( var->data.original.transvar == NULL )
15520          return 0;
15521       else
15522          return SCIPvarGetNBranchingsCurrentRun(var->data.original.transvar, dir);
15523 
15524    case SCIP_VARSTATUS_LOOSE:
15525    case SCIP_VARSTATUS_COLUMN:
15526       return SCIPhistoryGetNBranchings(var->historycrun, dir);
15527 
15528    case SCIP_VARSTATUS_FIXED:
15529       return 0;
15530 
15531    case SCIP_VARSTATUS_AGGREGATED:
15532       if( var->data.aggregate.scalar > 0.0 )
15533          return SCIPvarGetNBranchingsCurrentRun(var->data.aggregate.var, dir);
15534       else
15535          return SCIPvarGetNBranchingsCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15536 
15537    case SCIP_VARSTATUS_MULTAGGR:
15538       return 0;
15539 
15540    case SCIP_VARSTATUS_NEGATED:
15541       return SCIPvarGetNBranchingsCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir));
15542 
15543    default:
15544       SCIPerrorMessage("unknown variable status\n");
15545       SCIPABORT();
15546       return 0; /*lint !e527*/
15547    }
15548 }
15549 
15550 /** returns the average depth of bound changes in given direction due to branching on the variable */
SCIPvarGetAvgBranchdepth(SCIP_VAR * var,SCIP_BRANCHDIR dir)15551 SCIP_Real SCIPvarGetAvgBranchdepth(
15552    SCIP_VAR*             var,                /**< problem variable */
15553    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15554    )
15555 {
15556    assert(var != NULL);
15557    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15558 
15559    switch( SCIPvarGetStatus(var) )
15560    {
15561    case SCIP_VARSTATUS_ORIGINAL:
15562       if( var->data.original.transvar == NULL )
15563          return 0.0;
15564       else
15565          return SCIPvarGetAvgBranchdepth(var->data.original.transvar, dir);
15566 
15567    case SCIP_VARSTATUS_LOOSE:
15568    case SCIP_VARSTATUS_COLUMN:
15569       return  SCIPhistoryGetAvgBranchdepth(var->history, dir);
15570 
15571    case SCIP_VARSTATUS_FIXED:
15572       return 0.0;
15573 
15574    case SCIP_VARSTATUS_AGGREGATED:
15575       if( var->data.aggregate.scalar > 0.0 )
15576          return SCIPvarGetAvgBranchdepth(var->data.aggregate.var, dir);
15577       else
15578          return SCIPvarGetAvgBranchdepth(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15579 
15580    case SCIP_VARSTATUS_MULTAGGR:
15581       return 0.0;
15582 
15583    case SCIP_VARSTATUS_NEGATED:
15584       return SCIPvarGetAvgBranchdepth(var->negatedvar, SCIPbranchdirOpposite(dir));
15585 
15586    default:
15587       SCIPerrorMessage("unknown variable status\n");
15588       SCIPABORT();
15589       return 0.0; /*lint !e527*/
15590    }
15591 }
15592 
15593 /** returns the average depth of bound changes in given direction due to branching on the variable
15594  *  in the current run
15595  */
SCIPvarGetAvgBranchdepthCurrentRun(SCIP_VAR * var,SCIP_BRANCHDIR dir)15596 SCIP_Real SCIPvarGetAvgBranchdepthCurrentRun(
15597    SCIP_VAR*             var,                /**< problem variable */
15598    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15599    )
15600 {
15601    assert(var != NULL);
15602    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15603 
15604    switch( SCIPvarGetStatus(var) )
15605    {
15606    case SCIP_VARSTATUS_ORIGINAL:
15607       if( var->data.original.transvar == NULL )
15608          return 0.0;
15609       else
15610          return SCIPvarGetAvgBranchdepthCurrentRun(var->data.original.transvar, dir);
15611 
15612    case SCIP_VARSTATUS_LOOSE:
15613    case SCIP_VARSTATUS_COLUMN:
15614       return  SCIPhistoryGetAvgBranchdepth(var->historycrun, dir);
15615 
15616    case SCIP_VARSTATUS_FIXED:
15617       return 0.0;
15618 
15619    case SCIP_VARSTATUS_AGGREGATED:
15620       if( var->data.aggregate.scalar > 0.0 )
15621          return SCIPvarGetAvgBranchdepthCurrentRun(var->data.aggregate.var, dir);
15622       else
15623          return SCIPvarGetAvgBranchdepthCurrentRun(var->data.aggregate.var,
15624             dir == SCIP_BRANCHDIR_DOWNWARDS ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
15625 
15626    case SCIP_VARSTATUS_MULTAGGR:
15627       return 0.0;
15628 
15629    case SCIP_VARSTATUS_NEGATED:
15630       return SCIPvarGetAvgBranchdepthCurrentRun(var->negatedvar,
15631          dir == SCIP_BRANCHDIR_DOWNWARDS ? SCIP_BRANCHDIR_UPWARDS : SCIP_BRANCHDIR_DOWNWARDS);
15632 
15633    default:
15634       SCIPerrorMessage("unknown variable status\n");
15635       SCIPABORT();
15636       return 0.0; /*lint !e527*/
15637    }
15638 }
15639 
15640 /** returns the variable's VSIDS score */
SCIPvarGetVSIDS_rec(SCIP_VAR * var,SCIP_STAT * stat,SCIP_BRANCHDIR dir)15641 SCIP_Real SCIPvarGetVSIDS_rec(
15642    SCIP_VAR*             var,                /**< problem variable */
15643    SCIP_STAT*            stat,               /**< problem statistics */
15644    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15645    )
15646 {
15647    assert(var != NULL);
15648    assert(stat != NULL);
15649    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15650 
15651    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
15652       return SCIPvarGetVSIDS(var->data.original.transvar, stat, dir);
15653 
15654    switch( SCIPvarGetStatus(var) )
15655    {
15656    case SCIP_VARSTATUS_ORIGINAL:
15657       if( var->data.original.transvar == NULL )
15658          return 0.0;
15659       else
15660          return SCIPvarGetVSIDS(var->data.original.transvar, stat, dir);
15661 
15662    case SCIP_VARSTATUS_LOOSE:
15663    case SCIP_VARSTATUS_COLUMN:
15664       assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE); /* column case already handled in if condition above */
15665       return SCIPhistoryGetVSIDS(var->history, dir)/stat->vsidsweight;
15666 
15667    case SCIP_VARSTATUS_FIXED:
15668       return 0.0;
15669 
15670    case SCIP_VARSTATUS_AGGREGATED:
15671       if( var->data.aggregate.scalar > 0.0 )
15672          return SCIPvarGetVSIDS(var->data.aggregate.var, stat, dir);
15673       else
15674          /* coverity[overrun-local] */
15675          return SCIPvarGetVSIDS(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
15676 
15677    case SCIP_VARSTATUS_MULTAGGR:
15678       return 0.0;
15679 
15680    case SCIP_VARSTATUS_NEGATED:
15681       /* coverity[overrun-local] */
15682       return SCIPvarGetVSIDS(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
15683 
15684    default:
15685       SCIPerrorMessage("unknown variable status\n");
15686       SCIPABORT();
15687       return 0.0; /*lint !e527*/
15688    }
15689 }
15690 
15691 /** returns the variable's VSIDS score only using conflicts of the current run */
SCIPvarGetVSIDSCurrentRun(SCIP_VAR * var,SCIP_STAT * stat,SCIP_BRANCHDIR dir)15692 SCIP_Real SCIPvarGetVSIDSCurrentRun(
15693    SCIP_VAR*             var,                /**< problem variable */
15694    SCIP_STAT*            stat,               /**< problem statistics */
15695    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15696    )
15697 {
15698    assert(var != NULL);
15699    assert(stat != NULL);
15700    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15701 
15702    if( dir != SCIP_BRANCHDIR_DOWNWARDS && dir != SCIP_BRANCHDIR_UPWARDS )
15703    {
15704       SCIPerrorMessage("invalid branching direction %d when asking for VSIDS value\n", dir);
15705       return SCIP_INVALID;
15706    }
15707 
15708    switch( SCIPvarGetStatus(var) )
15709    {
15710    case SCIP_VARSTATUS_ORIGINAL:
15711       if( var->data.original.transvar == NULL )
15712          return 0.0;
15713       else
15714          return SCIPvarGetVSIDSCurrentRun(var->data.original.transvar, stat, dir);
15715 
15716    case SCIP_VARSTATUS_LOOSE:
15717    case SCIP_VARSTATUS_COLUMN:
15718       return SCIPhistoryGetVSIDS(var->historycrun, dir)/stat->vsidsweight;
15719 
15720    case SCIP_VARSTATUS_FIXED:
15721       return 0.0;
15722 
15723    case SCIP_VARSTATUS_AGGREGATED:
15724       if( var->data.aggregate.scalar > 0.0 )
15725          return SCIPvarGetVSIDSCurrentRun(var->data.aggregate.var, stat, dir);
15726       else
15727          return SCIPvarGetVSIDSCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
15728 
15729    case SCIP_VARSTATUS_MULTAGGR:
15730       return 0.0;
15731 
15732    case SCIP_VARSTATUS_NEGATED:
15733       return SCIPvarGetVSIDSCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
15734 
15735    default:
15736       SCIPerrorMessage("unknown variable status\n");
15737       SCIPABORT();
15738       return 0.0; /*lint !e527*/
15739    }
15740 }
15741 
15742 /** returns the number of inferences branching on this variable in given direction triggered */
SCIPvarGetInferenceSum(SCIP_VAR * var,SCIP_BRANCHDIR dir)15743 SCIP_Real SCIPvarGetInferenceSum(
15744    SCIP_VAR*             var,                /**< problem variable */
15745    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15746    )
15747 {
15748    assert(var != NULL);
15749    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15750 
15751    switch( SCIPvarGetStatus(var) )
15752    {
15753    case SCIP_VARSTATUS_ORIGINAL:
15754       if( var->data.original.transvar == NULL )
15755          return 0.0;
15756       else
15757          return SCIPvarGetInferenceSum(var->data.original.transvar, dir);
15758 
15759    case SCIP_VARSTATUS_LOOSE:
15760    case SCIP_VARSTATUS_COLUMN:
15761       return SCIPhistoryGetInferenceSum(var->history, dir);
15762 
15763    case SCIP_VARSTATUS_FIXED:
15764       return 0.0;
15765 
15766    case SCIP_VARSTATUS_AGGREGATED:
15767       if( var->data.aggregate.scalar > 0.0 )
15768          return SCIPvarGetInferenceSum(var->data.aggregate.var, dir);
15769       else
15770          return SCIPvarGetInferenceSum(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15771 
15772    case SCIP_VARSTATUS_MULTAGGR:
15773       return 0.0;
15774 
15775    case SCIP_VARSTATUS_NEGATED:
15776       return SCIPvarGetInferenceSum(var->negatedvar, SCIPbranchdirOpposite(dir));
15777 
15778    default:
15779       SCIPerrorMessage("unknown variable status\n");
15780       SCIPABORT();
15781       return 0.0; /*lint !e527*/
15782    }
15783 }
15784 
15785 /** returns the number of inferences branching on this variable in given direction triggered
15786  *  in the current run
15787  */
SCIPvarGetInferenceSumCurrentRun(SCIP_VAR * var,SCIP_BRANCHDIR dir)15788 SCIP_Real SCIPvarGetInferenceSumCurrentRun(
15789    SCIP_VAR*             var,                /**< problem variable */
15790    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15791    )
15792 {
15793    assert(var != NULL);
15794    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15795 
15796    switch( SCIPvarGetStatus(var) )
15797    {
15798    case SCIP_VARSTATUS_ORIGINAL:
15799       if( var->data.original.transvar == NULL )
15800          return 0.0;
15801       else
15802          return SCIPvarGetInferenceSumCurrentRun(var->data.original.transvar, dir);
15803 
15804    case SCIP_VARSTATUS_LOOSE:
15805    case SCIP_VARSTATUS_COLUMN:
15806       return SCIPhistoryGetInferenceSum(var->historycrun, dir);
15807 
15808    case SCIP_VARSTATUS_FIXED:
15809       return 0.0;
15810 
15811    case SCIP_VARSTATUS_AGGREGATED:
15812       if( var->data.aggregate.scalar > 0.0 )
15813          return SCIPvarGetInferenceSumCurrentRun(var->data.aggregate.var, dir);
15814       else
15815          return SCIPvarGetInferenceSumCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15816 
15817    case SCIP_VARSTATUS_MULTAGGR:
15818       return 0.0;
15819 
15820    case SCIP_VARSTATUS_NEGATED:
15821       return SCIPvarGetInferenceSumCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir));
15822 
15823    default:
15824       SCIPerrorMessage("unknown variable status\n");
15825       SCIPABORT();
15826       return 0.0; /*lint !e527*/
15827    }
15828 }
15829 
15830 /** returns the average number of inferences found after branching on the variable in given direction */
SCIPvarGetAvgInferences(SCIP_VAR * var,SCIP_STAT * stat,SCIP_BRANCHDIR dir)15831 SCIP_Real SCIPvarGetAvgInferences(
15832    SCIP_VAR*             var,                /**< problem variable */
15833    SCIP_STAT*            stat,               /**< problem statistics */
15834    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15835    )
15836 {
15837    assert(var != NULL);
15838    assert(stat != NULL);
15839    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15840 
15841    switch( SCIPvarGetStatus(var) )
15842    {
15843    case SCIP_VARSTATUS_ORIGINAL:
15844       if( var->data.original.transvar == NULL )
15845          return SCIPhistoryGetAvgInferences(stat->glbhistory, dir);
15846       else
15847          return SCIPvarGetAvgInferences(var->data.original.transvar, stat, dir);
15848 
15849    case SCIP_VARSTATUS_LOOSE:
15850    case SCIP_VARSTATUS_COLUMN:
15851       if( SCIPhistoryGetNBranchings(var->history, dir) > 0 )
15852          return SCIPhistoryGetAvgInferences(var->history, dir);
15853       else
15854       {
15855          int nimpls;
15856          int ncliques;
15857 
15858          nimpls = SCIPvarGetNImpls(var, dir == SCIP_BRANCHDIR_UPWARDS);
15859          ncliques = SCIPvarGetNCliques(var, dir == SCIP_BRANCHDIR_UPWARDS);
15860          return nimpls + ncliques > 0 ? (SCIP_Real)(nimpls + 2*ncliques) : SCIPhistoryGetAvgInferences(stat->glbhistory, dir);  /*lint !e790*/
15861       }
15862 
15863    case SCIP_VARSTATUS_FIXED:
15864       return 0.0;
15865 
15866    case SCIP_VARSTATUS_AGGREGATED:
15867       if( var->data.aggregate.scalar > 0.0 )
15868          return SCIPvarGetAvgInferences(var->data.aggregate.var, stat, dir);
15869       else
15870          return SCIPvarGetAvgInferences(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
15871 
15872    case SCIP_VARSTATUS_MULTAGGR:
15873       return 0.0;
15874 
15875    case SCIP_VARSTATUS_NEGATED:
15876       return SCIPvarGetAvgInferences(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
15877 
15878    default:
15879       SCIPerrorMessage("unknown variable status\n");
15880       SCIPABORT();
15881       return 0.0; /*lint !e527*/
15882    }
15883 }
15884 
15885 /** returns the average number of inferences found after branching on the variable in given direction
15886  *  in the current run
15887  */
SCIPvarGetAvgInferencesCurrentRun(SCIP_VAR * var,SCIP_STAT * stat,SCIP_BRANCHDIR dir)15888 SCIP_Real SCIPvarGetAvgInferencesCurrentRun(
15889    SCIP_VAR*             var,                /**< problem variable */
15890    SCIP_STAT*            stat,               /**< problem statistics */
15891    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15892    )
15893 {
15894    assert(var != NULL);
15895    assert(stat != NULL);
15896    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15897 
15898    switch( SCIPvarGetStatus(var) )
15899    {
15900    case SCIP_VARSTATUS_ORIGINAL:
15901       if( var->data.original.transvar == NULL )
15902          return SCIPhistoryGetAvgInferences(stat->glbhistorycrun, dir);
15903       else
15904          return SCIPvarGetAvgInferencesCurrentRun(var->data.original.transvar, stat, dir);
15905 
15906    case SCIP_VARSTATUS_LOOSE:
15907    case SCIP_VARSTATUS_COLUMN:
15908       if( SCIPhistoryGetNBranchings(var->historycrun, dir) > 0 )
15909          return SCIPhistoryGetAvgInferences(var->historycrun, dir);
15910       else
15911       {
15912          int nimpls;
15913          int ncliques;
15914 
15915          nimpls = SCIPvarGetNImpls(var, dir == SCIP_BRANCHDIR_UPWARDS);
15916          ncliques = SCIPvarGetNCliques(var, dir == SCIP_BRANCHDIR_UPWARDS);
15917          return nimpls + ncliques > 0 ? (SCIP_Real)(nimpls + 2*ncliques) : SCIPhistoryGetAvgInferences(stat->glbhistorycrun, dir);  /*lint !e790*/
15918       }
15919 
15920    case SCIP_VARSTATUS_FIXED:
15921       return 0.0;
15922 
15923    case SCIP_VARSTATUS_AGGREGATED:
15924       if( var->data.aggregate.scalar > 0.0 )
15925          return SCIPvarGetAvgInferencesCurrentRun(var->data.aggregate.var, stat, dir);
15926       else
15927          return SCIPvarGetAvgInferencesCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
15928 
15929    case SCIP_VARSTATUS_MULTAGGR:
15930       return 0.0;
15931 
15932    case SCIP_VARSTATUS_NEGATED:
15933       return SCIPvarGetAvgInferencesCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
15934 
15935    default:
15936       SCIPerrorMessage("unknown variable status\n");
15937       SCIPABORT();
15938       return 0.0; /*lint !e527*/
15939    }
15940 }
15941 
15942 /** returns the number of cutoffs branching on this variable in given direction produced */
SCIPvarGetCutoffSum(SCIP_VAR * var,SCIP_BRANCHDIR dir)15943 SCIP_Real SCIPvarGetCutoffSum(
15944    SCIP_VAR*             var,                /**< problem variable */
15945    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15946    )
15947 {
15948    assert(var != NULL);
15949    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15950 
15951    switch( SCIPvarGetStatus(var) )
15952    {
15953    case SCIP_VARSTATUS_ORIGINAL:
15954       if( var->data.original.transvar == NULL )
15955          return 0;
15956       else
15957          return SCIPvarGetCutoffSum(var->data.original.transvar, dir);
15958 
15959    case SCIP_VARSTATUS_LOOSE:
15960    case SCIP_VARSTATUS_COLUMN:
15961       return SCIPhistoryGetCutoffSum(var->history, dir);
15962 
15963    case SCIP_VARSTATUS_FIXED:
15964       return 0;
15965 
15966    case SCIP_VARSTATUS_AGGREGATED:
15967       if( var->data.aggregate.scalar > 0.0 )
15968          return SCIPvarGetCutoffSum(var->data.aggregate.var, dir);
15969       else
15970          return SCIPvarGetCutoffSum(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
15971 
15972    case SCIP_VARSTATUS_MULTAGGR:
15973       return 0;
15974 
15975    case SCIP_VARSTATUS_NEGATED:
15976       return SCIPvarGetCutoffSum(var->negatedvar, SCIPbranchdirOpposite(dir));
15977 
15978    default:
15979       SCIPerrorMessage("unknown variable status\n");
15980       SCIPABORT();
15981       return 0; /*lint !e527*/
15982    }
15983 }
15984 
15985 /** returns the number of cutoffs branching on this variable in given direction produced in the current run */
SCIPvarGetCutoffSumCurrentRun(SCIP_VAR * var,SCIP_BRANCHDIR dir)15986 SCIP_Real SCIPvarGetCutoffSumCurrentRun(
15987    SCIP_VAR*             var,                /**< problem variable */
15988    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
15989    )
15990 {
15991    assert(var != NULL);
15992    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
15993 
15994    switch( SCIPvarGetStatus(var) )
15995    {
15996    case SCIP_VARSTATUS_ORIGINAL:
15997       if( var->data.original.transvar == NULL )
15998          return 0;
15999       else
16000          return SCIPvarGetCutoffSumCurrentRun(var->data.original.transvar, dir);
16001 
16002    case SCIP_VARSTATUS_LOOSE:
16003    case SCIP_VARSTATUS_COLUMN:
16004       return SCIPhistoryGetCutoffSum(var->historycrun, dir);
16005 
16006    case SCIP_VARSTATUS_FIXED:
16007       return 0;
16008 
16009    case SCIP_VARSTATUS_AGGREGATED:
16010       if( var->data.aggregate.scalar > 0.0 )
16011          return SCIPvarGetCutoffSumCurrentRun(var->data.aggregate.var, dir);
16012       else
16013          return SCIPvarGetCutoffSumCurrentRun(var->data.aggregate.var, SCIPbranchdirOpposite(dir));
16014 
16015    case SCIP_VARSTATUS_MULTAGGR:
16016       return 0;
16017 
16018    case SCIP_VARSTATUS_NEGATED:
16019       return SCIPvarGetCutoffSumCurrentRun(var->negatedvar, SCIPbranchdirOpposite(dir));
16020 
16021    default:
16022       SCIPerrorMessage("unknown variable status\n");
16023       SCIPABORT();
16024       return 0; /*lint !e527*/
16025    }
16026 }
16027 
16028 /** returns the average number of cutoffs found after branching on the variable in given direction */
SCIPvarGetAvgCutoffs(SCIP_VAR * var,SCIP_STAT * stat,SCIP_BRANCHDIR dir)16029 SCIP_Real SCIPvarGetAvgCutoffs(
16030    SCIP_VAR*             var,                /**< problem variable */
16031    SCIP_STAT*            stat,               /**< problem statistics */
16032    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
16033    )
16034 {
16035    assert(var != NULL);
16036    assert(stat != NULL);
16037    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16038 
16039    switch( SCIPvarGetStatus(var) )
16040    {
16041    case SCIP_VARSTATUS_ORIGINAL:
16042       if( var->data.original.transvar == NULL )
16043          return SCIPhistoryGetAvgCutoffs(stat->glbhistory, dir);
16044       else
16045          return SCIPvarGetAvgCutoffs(var->data.original.transvar, stat, dir);
16046 
16047    case SCIP_VARSTATUS_LOOSE:
16048    case SCIP_VARSTATUS_COLUMN:
16049       return SCIPhistoryGetNBranchings(var->history, dir) > 0
16050          ? SCIPhistoryGetAvgCutoffs(var->history, dir)
16051          : SCIPhistoryGetAvgCutoffs(stat->glbhistory, dir);
16052 
16053    case SCIP_VARSTATUS_FIXED:
16054       return 0.0;
16055 
16056    case SCIP_VARSTATUS_AGGREGATED:
16057       if( var->data.aggregate.scalar > 0.0 )
16058          return SCIPvarGetAvgCutoffs(var->data.aggregate.var, stat, dir);
16059       else
16060          return SCIPvarGetAvgCutoffs(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
16061 
16062    case SCIP_VARSTATUS_MULTAGGR:
16063       return 0.0;
16064 
16065    case SCIP_VARSTATUS_NEGATED:
16066       return SCIPvarGetAvgCutoffs(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
16067 
16068    default:
16069       SCIPerrorMessage("unknown variable status\n");
16070       SCIPABORT();
16071       return 0.0; /*lint !e527*/
16072    }
16073 }
16074 
16075 /** returns the average number of cutoffs found after branching on the variable in given direction in the current run */
SCIPvarGetAvgCutoffsCurrentRun(SCIP_VAR * var,SCIP_STAT * stat,SCIP_BRANCHDIR dir)16076 SCIP_Real SCIPvarGetAvgCutoffsCurrentRun(
16077    SCIP_VAR*             var,                /**< problem variable */
16078    SCIP_STAT*            stat,               /**< problem statistics */
16079    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
16080    )
16081 {
16082    assert(var != NULL);
16083    assert(stat != NULL);
16084    assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
16085 
16086    switch( SCIPvarGetStatus(var) )
16087    {
16088    case SCIP_VARSTATUS_ORIGINAL:
16089       if( var->data.original.transvar == NULL )
16090          return SCIPhistoryGetAvgCutoffs(stat->glbhistorycrun, dir);
16091       else
16092          return SCIPvarGetAvgCutoffsCurrentRun(var->data.original.transvar, stat, dir);
16093 
16094    case SCIP_VARSTATUS_LOOSE:
16095    case SCIP_VARSTATUS_COLUMN:
16096       return SCIPhistoryGetNBranchings(var->historycrun, dir) > 0
16097          ? SCIPhistoryGetAvgCutoffs(var->historycrun, dir)
16098          : SCIPhistoryGetAvgCutoffs(stat->glbhistorycrun, dir);
16099 
16100    case SCIP_VARSTATUS_FIXED:
16101       return 0.0;
16102 
16103    case SCIP_VARSTATUS_AGGREGATED:
16104       if( var->data.aggregate.scalar > 0.0 )
16105          return SCIPvarGetAvgCutoffsCurrentRun(var->data.aggregate.var, stat, dir);
16106       else
16107          return SCIPvarGetAvgCutoffsCurrentRun(var->data.aggregate.var, stat, SCIPbranchdirOpposite(dir));
16108 
16109    case SCIP_VARSTATUS_MULTAGGR:
16110       return 0.0;
16111 
16112    case SCIP_VARSTATUS_NEGATED:
16113       return SCIPvarGetAvgCutoffsCurrentRun(var->negatedvar, stat, SCIPbranchdirOpposite(dir));
16114 
16115    default:
16116       SCIPerrorMessage("unknown variable status\n");
16117       SCIPABORT();
16118       return 0.0; /*lint !e527*/
16119    }
16120 }
16121 
16122 
16123 
16124 
16125 /*
16126  * information methods for bound changes
16127  */
16128 
16129 /** creates an artificial bound change information object with depth = INT_MAX and pos = -1 */
SCIPbdchginfoCreate(SCIP_BDCHGINFO ** bdchginfo,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_BOUNDTYPE boundtype,SCIP_Real oldbound,SCIP_Real newbound)16130 SCIP_RETCODE SCIPbdchginfoCreate(
16131    SCIP_BDCHGINFO**      bdchginfo,          /**< pointer to store bound change information */
16132    BMS_BLKMEM*           blkmem,             /**< block memory */
16133    SCIP_VAR*             var,                /**< active variable that changed the bounds */
16134    SCIP_BOUNDTYPE        boundtype,          /**< type of bound for var: lower or upper bound */
16135    SCIP_Real             oldbound,           /**< old value for bound */
16136    SCIP_Real             newbound            /**< new value for bound */
16137    )
16138 {
16139    assert(bdchginfo != NULL);
16140 
16141    SCIP_ALLOC( BMSallocBlockMemory(blkmem, bdchginfo) );
16142    (*bdchginfo)->oldbound = oldbound;
16143    (*bdchginfo)->newbound = newbound;
16144    (*bdchginfo)->var = var;
16145    (*bdchginfo)->inferencedata.var = var;
16146    (*bdchginfo)->inferencedata.reason.prop = NULL;
16147    (*bdchginfo)->inferencedata.info = 0;
16148    (*bdchginfo)->bdchgidx.depth = INT_MAX;
16149    (*bdchginfo)->bdchgidx.pos = -1;
16150    (*bdchginfo)->pos = 0;
16151    (*bdchginfo)->boundchgtype = SCIP_BOUNDCHGTYPE_BRANCHING; /*lint !e641*/
16152    (*bdchginfo)->boundtype = boundtype; /*lint !e641*/
16153    (*bdchginfo)->inferboundtype = boundtype; /*lint !e641*/
16154    (*bdchginfo)->redundant = FALSE;
16155 
16156    return SCIP_OKAY;
16157 }
16158 
16159 /** frees a bound change information object */
SCIPbdchginfoFree(SCIP_BDCHGINFO ** bdchginfo,BMS_BLKMEM * blkmem)16160 void SCIPbdchginfoFree(
16161    SCIP_BDCHGINFO**      bdchginfo,          /**< pointer to store bound change information */
16162    BMS_BLKMEM*           blkmem              /**< block memory */
16163    )
16164 {
16165    assert(bdchginfo != NULL);
16166 
16167    BMSfreeBlockMemory(blkmem, bdchginfo);
16168 }
16169 
16170 /** returns the bound change information for the last lower bound change on given active problem variable before or
16171  *  after the bound change with the given index was applied;
16172  *  returns NULL, if no change to the lower bound was applied up to this point of time
16173  */
SCIPvarGetLbchgInfo(SCIP_VAR * var,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool after)16174 SCIP_BDCHGINFO* SCIPvarGetLbchgInfo(
16175    SCIP_VAR*             var,                /**< active problem variable */
16176    SCIP_BDCHGIDX*        bdchgidx,           /**< bound change index representing time on path to current node */
16177    SCIP_Bool             after               /**< should the bound change with given index be included? */
16178    )
16179 {
16180    int i;
16181 
16182    assert(var != NULL);
16183    assert(SCIPvarIsActive(var));
16184 
16185    /* search the correct bound change information for the given bound change index */
16186    if( after )
16187    {
16188       for( i = var->nlbchginfos-1; i >= 0; --i )
16189       {
16190          assert(var->lbchginfos[i].var == var);
16191          assert((SCIP_BOUNDTYPE)var->lbchginfos[i].boundtype == SCIP_BOUNDTYPE_LOWER);
16192          assert(var->lbchginfos[i].pos == i);
16193 
16194          /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16195          if( var->lbchginfos[i].redundant )
16196             return NULL;
16197          assert(var->lbchginfos[i].oldbound < var->lbchginfos[i].newbound);
16198 
16199          /* if we reached the bound change index, return the current bound change info */
16200          if( !SCIPbdchgidxIsEarlier(bdchgidx, &var->lbchginfos[i].bdchgidx) )
16201             return &var->lbchginfos[i];
16202       }
16203    }
16204    else
16205    {
16206       for( i = var->nlbchginfos-1; i >= 0; --i )
16207       {
16208          assert(var->lbchginfos[i].var == var);
16209          assert((SCIP_BOUNDTYPE)var->lbchginfos[i].boundtype == SCIP_BOUNDTYPE_LOWER);
16210          assert(var->lbchginfos[i].pos == i);
16211 
16212          /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16213          if( var->lbchginfos[i].redundant )
16214             return NULL;
16215          assert(var->lbchginfos[i].oldbound < var->lbchginfos[i].newbound);
16216 
16217          /* if we reached the bound change index, return the current bound change info */
16218          if( SCIPbdchgidxIsEarlier(&var->lbchginfos[i].bdchgidx, bdchgidx) )
16219             return &var->lbchginfos[i];
16220       }
16221    }
16222 
16223    return NULL;
16224 }
16225 
16226 /** returns the bound change information for the last upper bound change on given active problem variable before or
16227  *  after the bound change with the given index was applied;
16228  *  returns NULL, if no change to the upper bound was applied up to this point of time
16229  */
SCIPvarGetUbchgInfo(SCIP_VAR * var,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool after)16230 SCIP_BDCHGINFO* SCIPvarGetUbchgInfo(
16231    SCIP_VAR*             var,                /**< active problem variable */
16232    SCIP_BDCHGIDX*        bdchgidx,           /**< bound change index representing time on path to current node */
16233    SCIP_Bool             after               /**< should the bound change with given index be included? */
16234    )
16235 {
16236    int i;
16237 
16238    assert(var != NULL);
16239    assert(SCIPvarIsActive(var));
16240 
16241    /* search the correct bound change information for the given bound change index */
16242    if( after )
16243    {
16244       for( i = var->nubchginfos-1; i >= 0; --i )
16245       {
16246          assert(var->ubchginfos[i].var == var);
16247          assert((SCIP_BOUNDTYPE)var->ubchginfos[i].boundtype == SCIP_BOUNDTYPE_UPPER);
16248          assert(var->ubchginfos[i].pos == i);
16249 
16250          /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16251          if( var->ubchginfos[i].redundant )
16252             return NULL;
16253          assert(var->ubchginfos[i].oldbound > var->ubchginfos[i].newbound);
16254 
16255          /* if we reached the bound change index, return the current bound change info */
16256          if( !SCIPbdchgidxIsEarlier(bdchgidx, &var->ubchginfos[i].bdchgidx) )
16257             return &var->ubchginfos[i];
16258       }
16259    }
16260    else
16261    {
16262       for( i = var->nubchginfos-1; i >= 0; --i )
16263       {
16264          assert(var->ubchginfos[i].var == var);
16265          assert((SCIP_BOUNDTYPE)var->ubchginfos[i].boundtype == SCIP_BOUNDTYPE_UPPER);
16266          assert(var->ubchginfos[i].pos == i);
16267 
16268          /* if we reached the (due to global bounds) redundant bound changes, return NULL */
16269          if( var->ubchginfos[i].redundant )
16270             return NULL;
16271          assert(var->ubchginfos[i].oldbound > var->ubchginfos[i].newbound);
16272 
16273          /* if we reached the bound change index, return the current bound change info */
16274          if( SCIPbdchgidxIsEarlier(&var->ubchginfos[i].bdchgidx, bdchgidx) )
16275             return &var->ubchginfos[i];
16276       }
16277    }
16278 
16279    return NULL;
16280 }
16281 
16282 /** returns the bound change information for the last lower or upper bound change on given active problem variable
16283  *  before or after the bound change with the given index was applied;
16284  *  returns NULL, if no change to the lower/upper bound was applied up to this point of time
16285  */
SCIPvarGetBdchgInfo(SCIP_VAR * var,SCIP_BOUNDTYPE boundtype,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool after)16286 SCIP_BDCHGINFO* SCIPvarGetBdchgInfo(
16287    SCIP_VAR*             var,                /**< active problem variable */
16288    SCIP_BOUNDTYPE        boundtype,          /**< type of bound: lower or upper bound */
16289    SCIP_BDCHGIDX*        bdchgidx,           /**< bound change index representing time on path to current node */
16290    SCIP_Bool             after               /**< should the bound change with given index be included? */
16291    )
16292 {
16293    if( boundtype == SCIP_BOUNDTYPE_LOWER )
16294       return SCIPvarGetLbchgInfo(var, bdchgidx, after);
16295    else
16296    {
16297       assert(boundtype == SCIP_BOUNDTYPE_UPPER);
16298       return SCIPvarGetUbchgInfo(var, bdchgidx, after);
16299    }
16300 }
16301 
16302 /** returns lower bound of variable directly before or after the bound change given by the bound change index
16303  *  was applied
16304  *
16305  *  @deprecated Please use SCIPgetVarLbAtIndex()
16306  */
SCIPvarGetLbAtIndex(SCIP_VAR * var,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool after)16307 SCIP_Real SCIPvarGetLbAtIndex(
16308    SCIP_VAR*             var,                /**< problem variable */
16309    SCIP_BDCHGIDX*        bdchgidx,           /**< bound change index representing time on path to current node */
16310    SCIP_Bool             after               /**< should the bound change with given index be included? */
16311    )
16312 {
16313    SCIP_VARSTATUS varstatus;
16314    assert(var != NULL);
16315 
16316    varstatus = SCIPvarGetStatus(var);
16317 
16318    /* get bounds of attached variables */
16319    switch( varstatus )
16320    {
16321    case SCIP_VARSTATUS_ORIGINAL:
16322       assert(var->data.original.transvar != NULL);
16323       return SCIPvarGetLbAtIndex(var->data.original.transvar, bdchgidx, after);
16324 
16325    case SCIP_VARSTATUS_LOOSE:
16326    case SCIP_VARSTATUS_COLUMN:
16327       if( bdchgidx == NULL )
16328          return SCIPvarGetLbLocal(var);
16329       else
16330       {
16331          SCIP_BDCHGINFO* bdchginfo;
16332 
16333          bdchginfo = SCIPvarGetLbchgInfo(var, bdchgidx, after);
16334          if( bdchginfo != NULL )
16335             return SCIPbdchginfoGetNewbound(bdchginfo);
16336          else
16337             return var->glbdom.lb;
16338       }
16339    case SCIP_VARSTATUS_FIXED:
16340       return var->glbdom.lb;
16341 
16342    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
16343       assert(var->data.aggregate.var != NULL);
16344       /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
16345        * corresponding infinity value instead of performing an arithmetical transformation (compare method
16346        * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
16347        * (or is called by) a public interface method; instead, we only assert that values are finite
16348        * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
16349        * positives and negatives if the parameter <numerics/infinity> is modified by the user
16350        */
16351       if( var->data.aggregate.scalar > 0.0 )
16352       {
16353          /* a > 0 -> get lower bound of y */
16354          assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16355          assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16356          return var->data.aggregate.scalar * SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after)
16357             + var->data.aggregate.constant;
16358       }
16359       else if( var->data.aggregate.scalar < 0.0 )
16360       {
16361          /* a < 0 -> get upper bound of y */
16362          assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16363          assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16364          return var->data.aggregate.scalar * SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after)
16365             + var->data.aggregate.constant;
16366       }
16367       else
16368       {
16369          SCIPerrorMessage("scalar is zero in aggregation\n");
16370          SCIPABORT();
16371          return SCIP_INVALID; /*lint !e527*/
16372       }
16373 
16374    case SCIP_VARSTATUS_MULTAGGR:
16375       /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
16376       if ( var->data.multaggr.nvars == 1 )
16377       {
16378          assert(var->data.multaggr.vars != NULL);
16379          assert(var->data.multaggr.scalars != NULL);
16380          assert(var->data.multaggr.vars[0] != NULL);
16381 
16382          if( var->data.multaggr.scalars[0] > 0.0 )
16383          {
16384             /* a > 0 -> get lower bound of y */
16385             assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16386             assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16387             return var->data.multaggr.scalars[0] * SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16388                + var->data.multaggr.constant;
16389          }
16390          else if( var->data.multaggr.scalars[0] < 0.0 )
16391          {
16392             /* a < 0 -> get upper bound of y */
16393             assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16394             assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16395             return var->data.multaggr.scalars[0] * SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16396                + var->data.multaggr.constant;
16397          }
16398          else
16399          {
16400             SCIPerrorMessage("scalar is zero in multi-aggregation\n");
16401             SCIPABORT();
16402             return SCIP_INVALID; /*lint !e527*/
16403          }
16404       }
16405       SCIPerrorMessage("cannot get the bounds of a multi-aggregated variable.\n");
16406       SCIPABORT();
16407       return SCIP_INVALID; /*lint !e527*/
16408 
16409    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
16410       assert(var->negatedvar != NULL);
16411       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
16412       assert(var->negatedvar->negatedvar == var);
16413       return var->data.negate.constant - SCIPvarGetUbAtIndex(var->negatedvar, bdchgidx, after);
16414    default:
16415       SCIPerrorMessage("unknown variable status\n");
16416       SCIPABORT();
16417       return SCIP_INVALID; /*lint !e527*/
16418    }
16419 }
16420 
16421 /** returns upper bound of variable directly before or after the bound change given by the bound change index
16422  *  was applied
16423  *
16424  *  @deprecated Please use SCIPgetVarUbAtIndex()
16425  */
SCIPvarGetUbAtIndex(SCIP_VAR * var,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool after)16426 SCIP_Real SCIPvarGetUbAtIndex(
16427    SCIP_VAR*             var,                /**< problem variable */
16428    SCIP_BDCHGIDX*        bdchgidx,           /**< bound change index representing time on path to current node */
16429    SCIP_Bool             after               /**< should the bound change with given index be included? */
16430    )
16431 {
16432    SCIP_VARSTATUS varstatus;
16433    assert(var != NULL);
16434 
16435    varstatus = SCIPvarGetStatus(var);
16436 
16437    /* get bounds of attached variables */
16438    switch( varstatus )
16439    {
16440    case SCIP_VARSTATUS_ORIGINAL:
16441       assert(var->data.original.transvar != NULL);
16442       return SCIPvarGetUbAtIndex(var->data.original.transvar, bdchgidx, after);
16443 
16444    case SCIP_VARSTATUS_COLUMN:
16445    case SCIP_VARSTATUS_LOOSE:
16446       if( bdchgidx == NULL )
16447          return SCIPvarGetUbLocal(var);
16448       else
16449       {
16450          SCIP_BDCHGINFO* bdchginfo;
16451 
16452          bdchginfo = SCIPvarGetUbchgInfo(var, bdchgidx, after);
16453          if( bdchginfo != NULL )
16454             return SCIPbdchginfoGetNewbound(bdchginfo);
16455          else
16456             return var->glbdom.ub;
16457       }
16458 
16459    case SCIP_VARSTATUS_FIXED:
16460       return var->glbdom.ub;
16461 
16462    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  ->  y = (x-c)/a */
16463       assert(var->data.aggregate.var != NULL);
16464       /* a correct implementation would need to check the value of var->data.aggregate.var for infinity and return the
16465        * corresponding infinity value instead of performing an arithmetical transformation (compare method
16466        * SCIPvarGetLbLP()); however, we do not want to introduce a SCIP or SCIP_SET pointer to this method, since it is
16467        * (or is called by) a public interface method; instead, we only assert that values are finite
16468        * w.r.t. SCIP_DEFAULT_INFINITY, which seems to be true in our regression tests; note that this may yield false
16469        * positives and negatives if the parameter <numerics/infinity> is modified by the user
16470        */
16471       if( var->data.aggregate.scalar > 0.0 )
16472       {
16473          /* a > 0 -> get lower bound of y */
16474          assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16475          assert(SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16476          return var->data.aggregate.scalar * SCIPvarGetUbAtIndex(var->data.aggregate.var, bdchgidx, after)
16477             + var->data.aggregate.constant;
16478       }
16479       else if( var->data.aggregate.scalar < 0.0 )
16480       {
16481          /* a < 0 -> get upper bound of y */
16482          assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16483          assert(SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16484          return var->data.aggregate.scalar * SCIPvarGetLbAtIndex(var->data.aggregate.var, bdchgidx, after)
16485             + var->data.aggregate.constant;
16486       }
16487       else
16488       {
16489          SCIPerrorMessage("scalar is zero in aggregation\n");
16490          SCIPABORT();
16491          return SCIP_INVALID; /*lint !e527*/
16492       }
16493 
16494    case SCIP_VARSTATUS_MULTAGGR:
16495       /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
16496       if ( var->data.multaggr.nvars == 1 )
16497       {
16498          assert(var->data.multaggr.vars != NULL);
16499          assert(var->data.multaggr.scalars != NULL);
16500          assert(var->data.multaggr.vars[0] != NULL);
16501 
16502          if( var->data.multaggr.scalars[0] > 0.0 )
16503          {
16504             /* a > 0 -> get lower bound of y */
16505             assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16506             assert(SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16507             return var->data.multaggr.scalars[0] * SCIPvarGetUbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16508                + var->data.multaggr.constant;
16509          }
16510          else if( var->data.multaggr.scalars[0] < 0.0 )
16511          {
16512             /* a < 0 -> get upper bound of y */
16513             assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) > -SCIP_DEFAULT_INFINITY);
16514             assert(SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after) < +SCIP_DEFAULT_INFINITY);
16515             return var->data.multaggr.scalars[0] * SCIPvarGetLbAtIndex(var->data.multaggr.vars[0], bdchgidx, after)
16516                + var->data.multaggr.constant;
16517          }
16518          else
16519          {
16520             SCIPerrorMessage("scalar is zero in multi-aggregation\n");
16521             SCIPABORT();
16522             return SCIP_INVALID; /*lint !e527*/
16523          }
16524       }
16525       SCIPerrorMessage("cannot get the bounds of a multiple aggregated variable.\n");
16526       SCIPABORT();
16527       return SCIP_INVALID; /*lint !e527*/
16528 
16529    case SCIP_VARSTATUS_NEGATED: /* x' = offset - x  ->  x = offset - x' */
16530       assert(var->negatedvar != NULL);
16531       assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
16532       assert(var->negatedvar->negatedvar == var);
16533       return var->data.negate.constant - SCIPvarGetLbAtIndex(var->negatedvar, bdchgidx, after);
16534 
16535    default:
16536       SCIPerrorMessage("unknown variable status\n");
16537       SCIPABORT();
16538       return SCIP_INVALID; /*lint !e527*/
16539    }
16540 }
16541 
16542 /** returns lower or upper bound of variable directly before or after the bound change given by the bound change index
16543  *  was applied
16544  *
16545  *  @deprecated Please use SCIPgetVarBdAtIndex()
16546  */
SCIPvarGetBdAtIndex(SCIP_VAR * var,SCIP_BOUNDTYPE boundtype,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool after)16547 SCIP_Real SCIPvarGetBdAtIndex(
16548    SCIP_VAR*             var,                /**< problem variable */
16549    SCIP_BOUNDTYPE        boundtype,          /**< type of bound: lower or upper bound */
16550    SCIP_BDCHGIDX*        bdchgidx,           /**< bound change index representing time on path to current node */
16551    SCIP_Bool             after               /**< should the bound change with given index be included? */
16552    )
16553 {
16554    if( boundtype == SCIP_BOUNDTYPE_LOWER )
16555       return SCIPvarGetLbAtIndex(var, bdchgidx, after);
16556    else
16557    {
16558       assert(boundtype == SCIP_BOUNDTYPE_UPPER);
16559       return SCIPvarGetUbAtIndex(var, bdchgidx, after);
16560    }
16561 }
16562 
16563 /** returns whether the binary variable was fixed at the time given by the bound change index
16564  *
16565  *  @deprecated Please use SCIPgetVarWasFixedAtIndex()
16566  */
SCIPvarWasFixedAtIndex(SCIP_VAR * var,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool after)16567 SCIP_Bool SCIPvarWasFixedAtIndex(
16568    SCIP_VAR*             var,                /**< problem variable */
16569    SCIP_BDCHGIDX*        bdchgidx,           /**< bound change index representing time on path to current node */
16570    SCIP_Bool             after               /**< should the bound change with given index be included? */
16571    )
16572 {
16573    assert(var != NULL);
16574    assert(SCIPvarIsBinary(var));
16575 
16576    /* check the current bounds first in order to decide at which bound change information we have to look
16577     * (which is expensive because we have to follow the aggregation tree to the active variable)
16578     */
16579    return ((SCIPvarGetLbLocal(var) > 0.5 && SCIPvarGetLbAtIndex(var, bdchgidx, after) > 0.5)
16580       || (SCIPvarGetUbLocal(var) < 0.5 && SCIPvarGetUbAtIndex(var, bdchgidx, after) < 0.5));
16581 }
16582 
16583 /** bound change index representing the initial time before any bound changes took place */
16584 static SCIP_BDCHGIDX initbdchgidx = {-2, 0};
16585 
16586 /** bound change index representing the presolving stage */
16587 static SCIP_BDCHGIDX presolvebdchgidx = {-1, 0};
16588 
16589 /** returns the last bound change index, at which the bounds of the given variable were tightened */
SCIPvarGetLastBdchgIndex(SCIP_VAR * var)16590 SCIP_BDCHGIDX* SCIPvarGetLastBdchgIndex(
16591    SCIP_VAR*             var                 /**< problem variable */
16592    )
16593 {
16594    SCIP_BDCHGIDX* lbchgidx;
16595    SCIP_BDCHGIDX* ubchgidx;
16596 
16597    assert(var != NULL);
16598 
16599    var = SCIPvarGetProbvar(var);
16600 
16601    /* check, if variable is original without transformed variable */
16602    if( var == NULL )
16603       return &initbdchgidx;
16604 
16605    /* check, if variable was fixed in presolving */
16606    if( !SCIPvarIsActive(var) )
16607       return &presolvebdchgidx;
16608 
16609    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
16610 
16611    /* get depths of last bound change information for the lower and upper bound */
16612    lbchgidx = (var->nlbchginfos > 0 && !var->lbchginfos[var->nlbchginfos-1].redundant
16613       ? &var->lbchginfos[var->nlbchginfos-1].bdchgidx : &initbdchgidx);
16614    ubchgidx = (var->nubchginfos > 0 && !var->ubchginfos[var->nubchginfos-1].redundant
16615       ? &var->ubchginfos[var->nubchginfos-1].bdchgidx : &initbdchgidx);
16616 
16617    if( SCIPbdchgidxIsEarlierNonNull(lbchgidx, ubchgidx) )
16618       return ubchgidx;
16619    else
16620       return lbchgidx;
16621 }
16622 
16623 /** returns the last depth level, at which the bounds of the given variable were tightened;
16624  *  returns -2, if the variable's bounds are still the global bounds
16625  *  returns -1, if the variable was fixed in presolving
16626  */
SCIPvarGetLastBdchgDepth(SCIP_VAR * var)16627 int SCIPvarGetLastBdchgDepth(
16628    SCIP_VAR*             var                 /**< problem variable */
16629    )
16630 {
16631    SCIP_BDCHGIDX* bdchgidx;
16632 
16633    bdchgidx = SCIPvarGetLastBdchgIndex(var);
16634    assert(bdchgidx != NULL);
16635 
16636    return bdchgidx->depth;
16637 }
16638 
16639 /** returns at which depth in the tree a bound change was applied to the variable that conflicts with the
16640  *  given bound; returns -1 if the bound does not conflict with the current local bounds of the variable
16641  */
SCIPvarGetConflictingBdchgDepth(SCIP_VAR * var,SCIP_SET * set,SCIP_BOUNDTYPE boundtype,SCIP_Real bound)16642 int SCIPvarGetConflictingBdchgDepth(
16643    SCIP_VAR*             var,                /**< problem variable */
16644    SCIP_SET*             set,                /**< global SCIP settings */
16645    SCIP_BOUNDTYPE        boundtype,          /**< bound type of the conflicting bound */
16646    SCIP_Real             bound               /**< conflicting bound */
16647    )
16648 {
16649    int i;
16650 
16651    assert(var != NULL);
16652    assert(set != NULL);
16653    assert(var->scip == set->scip);
16654 
16655    if( boundtype == SCIP_BOUNDTYPE_LOWER )
16656    {
16657       /* check if the bound is in conflict with the current local bounds */
16658       if( SCIPsetIsLE(set, bound, var->locdom.ub) )
16659          return -1;
16660 
16661       /* check if the bound is in conflict with the global bound */
16662       if( SCIPsetIsGT(set, bound, var->glbdom.ub) )
16663          return 0;
16664 
16665       /* local bounds are in conflict with the given bound -> there must be at least one conflicting change! */
16666       assert(var->nubchginfos > 0);
16667       assert(SCIPsetIsGT(set, bound, var->ubchginfos[var->nubchginfos-1].newbound));
16668 
16669       /* search for the first conflicting bound change */
16670       for( i = var->nubchginfos-1; i > 0 && SCIPsetIsGT(set, bound, var->ubchginfos[i-1].newbound); --i )
16671       {
16672          assert(var->ubchginfos[i].var == var); /* perform sanity check on the search for the first conflicting bound */
16673          assert((SCIP_BOUNDTYPE)var->ubchginfos[i].boundtype == SCIP_BOUNDTYPE_UPPER);
16674       }
16675       assert(SCIPsetIsGT(set, bound, var->ubchginfos[i].newbound));             /* bound change i is conflicting */
16676       assert(i == 0 || SCIPsetIsLE(set, bound, var->ubchginfos[i-1].newbound)); /* bound change i-1 is not conflicting */
16677 
16678       /* return the depth at which the first conflicting bound change took place */
16679       return var->ubchginfos[i].bdchgidx.depth;
16680    }
16681    else
16682    {
16683       assert(boundtype == SCIP_BOUNDTYPE_UPPER);
16684 
16685       /* check if the bound is in conflict with the current local bounds */
16686       if( SCIPsetIsGE(set, bound, var->locdom.lb) )
16687          return -1;
16688 
16689       /* check if the bound is in conflict with the global bound */
16690       if( SCIPsetIsLT(set, bound, var->glbdom.lb) )
16691          return 0;
16692 
16693       /* local bounds are in conflict with the given bound -> there must be at least one conflicting change! */
16694       assert(var->nlbchginfos > 0);
16695       assert(SCIPsetIsLT(set, bound, var->lbchginfos[var->nlbchginfos-1].newbound));
16696 
16697       /* search for the first conflicting bound change */
16698       for( i = var->nlbchginfos-1; i > 0 && SCIPsetIsLT(set, bound, var->lbchginfos[i-1].newbound); --i )
16699       {
16700          assert(var->lbchginfos[i].var == var); /* perform sanity check on the search for the first conflicting bound */
16701          assert((SCIP_BOUNDTYPE)var->lbchginfos[i].boundtype == SCIP_BOUNDTYPE_LOWER);
16702       }
16703       assert(SCIPsetIsLT(set, bound, var->lbchginfos[i].newbound));             /* bound change i is conflicting */
16704       assert(i == 0 || SCIPsetIsGE(set, bound, var->lbchginfos[i-1].newbound)); /* bound change i-1 is not conflicting */
16705 
16706       /* return the depth at which the first conflicting bound change took place */
16707       return var->lbchginfos[i].bdchgidx.depth;
16708    }
16709 }
16710 
16711 /** returns whether the first binary variable was fixed earlier than the second one;
16712  *  returns FALSE, if the first variable is not fixed, and returns TRUE, if the first variable is fixed, but the
16713  *  second one is not fixed
16714  */
SCIPvarWasFixedEarlier(SCIP_VAR * var1,SCIP_VAR * var2)16715 SCIP_Bool SCIPvarWasFixedEarlier(
16716    SCIP_VAR*             var1,               /**< first binary variable */
16717    SCIP_VAR*             var2                /**< second binary variable */
16718    )
16719 {
16720    SCIP_BDCHGIDX* bdchgidx1;
16721    SCIP_BDCHGIDX* bdchgidx2;
16722 
16723    assert(var1 != NULL);
16724    assert(var2 != NULL);
16725    assert(SCIPvarIsBinary(var1));
16726    assert(SCIPvarIsBinary(var2));
16727 
16728    var1 = SCIPvarGetProbvar(var1);
16729    var2 = SCIPvarGetProbvar(var2);
16730    assert(var1 != NULL);
16731    assert(var2 != NULL);
16732 
16733    /* check, if variables are globally fixed */
16734    if( !SCIPvarIsActive(var2) || var2->glbdom.lb > 0.5 || var2->glbdom.ub < 0.5 )
16735       return FALSE;
16736    if( !SCIPvarIsActive(var1) || var1->glbdom.lb > 0.5 || var1->glbdom.ub < 0.5 )
16737       return TRUE;
16738 
16739    assert(SCIPvarGetStatus(var1) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_COLUMN);
16740    assert(SCIPvarGetStatus(var2) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_COLUMN);
16741    assert(SCIPvarIsBinary(var1));
16742    assert(SCIPvarIsBinary(var2));
16743    assert(var1->nlbchginfos + var1->nubchginfos <= 1);
16744    assert(var2->nlbchginfos + var2->nubchginfos <= 1);
16745    assert(var1->nlbchginfos == 0 || !var1->lbchginfos[0].redundant); /* otherwise, var would be globally fixed */
16746    assert(var1->nubchginfos == 0 || !var1->ubchginfos[0].redundant); /* otherwise, var would be globally fixed */
16747    assert(var2->nlbchginfos == 0 || !var2->lbchginfos[0].redundant); /* otherwise, var would be globally fixed */
16748    assert(var2->nubchginfos == 0 || !var2->ubchginfos[0].redundant); /* otherwise, var would be globally fixed */
16749 
16750    if( var1->nlbchginfos == 1 )
16751       bdchgidx1 = &var1->lbchginfos[0].bdchgidx;
16752    else if( var1->nubchginfos == 1 )
16753       bdchgidx1 = &var1->ubchginfos[0].bdchgidx;
16754    else
16755       bdchgidx1 = NULL;
16756 
16757    if( var2->nlbchginfos == 1 )
16758       bdchgidx2 = &var2->lbchginfos[0].bdchgidx;
16759    else if( var2->nubchginfos == 1 )
16760       bdchgidx2 = &var2->ubchginfos[0].bdchgidx;
16761    else
16762       bdchgidx2 = NULL;
16763 
16764    return SCIPbdchgidxIsEarlier(bdchgidx1, bdchgidx2);
16765 }
16766 
16767 
16768 
16769 /*
16770  * Hash functions
16771  */
16772 
16773 /** gets the key (i.e. the name) of the given variable */
SCIP_DECL_HASHGETKEY(SCIPhashGetKeyVar)16774 SCIP_DECL_HASHGETKEY(SCIPhashGetKeyVar)
16775 {  /*lint --e{715}*/
16776    SCIP_VAR* var = (SCIP_VAR*)elem;
16777 
16778    assert(var != NULL);
16779    return var->name;
16780 }
16781 
16782 
16783 
16784 
16785 /*
16786  * simple functions implemented as defines
16787  */
16788 
16789 /* In debug mode, the following methods are implemented as function calls to ensure
16790  * type validity.
16791  * In optimized mode, the methods are implemented as defines to improve performance.
16792  * However, we want to have them in the library anyways, so we have to undef the defines.
16793  */
16794 
16795 #undef SCIPboundchgGetNewbound
16796 #undef SCIPboundchgGetVar
16797 #undef SCIPboundchgGetBoundchgtype
16798 #undef SCIPboundchgGetBoundtype
16799 #undef SCIPboundchgIsRedundant
16800 #undef SCIPdomchgGetNBoundchgs
16801 #undef SCIPdomchgGetBoundchg
16802 #undef SCIPholelistGetLeft
16803 #undef SCIPholelistGetRight
16804 #undef SCIPholelistGetNext
16805 #undef SCIPvarGetName
16806 #undef SCIPvarGetNUses
16807 #undef SCIPvarGetData
16808 #undef SCIPvarSetData
16809 #undef SCIPvarSetDelorigData
16810 #undef SCIPvarSetTransData
16811 #undef SCIPvarSetDeltransData
16812 #undef SCIPvarGetStatus
16813 #undef SCIPvarIsOriginal
16814 #undef SCIPvarIsTransformed
16815 #undef SCIPvarIsNegated
16816 #undef SCIPvarGetType
16817 #undef SCIPvarIsBinary
16818 #undef SCIPvarIsIntegral
16819 #undef SCIPvarIsInitial
16820 #undef SCIPvarIsRemovable
16821 #undef SCIPvarIsDeleted
16822 #undef SCIPvarIsDeletable
16823 #undef SCIPvarMarkDeletable
16824 #undef SCIPvarMarkNotDeletable
16825 #undef SCIPvarIsActive
16826 #undef SCIPvarGetIndex
16827 #undef SCIPvarGetProbindex
16828 #undef SCIPvarGetTransVar
16829 #undef SCIPvarGetCol
16830 #undef SCIPvarIsInLP
16831 #undef SCIPvarGetAggrVar
16832 #undef SCIPvarGetAggrScalar
16833 #undef SCIPvarGetAggrConstant
16834 #undef SCIPvarGetMultaggrNVars
16835 #undef SCIPvarGetMultaggrVars
16836 #undef SCIPvarGetMultaggrScalars
16837 #undef SCIPvarGetMultaggrConstant
16838 #undef SCIPvarGetNegatedVar
16839 #undef SCIPvarGetNegationVar
16840 #undef SCIPvarGetNegationConstant
16841 #undef SCIPvarGetObj
16842 #undef SCIPvarGetLbOriginal
16843 #undef SCIPvarGetUbOriginal
16844 #undef SCIPvarGetHolelistOriginal
16845 #undef SCIPvarGetLbGlobal
16846 #undef SCIPvarGetUbGlobal
16847 #undef SCIPvarGetHolelistGlobal
16848 #undef SCIPvarGetBestBoundGlobal
16849 #undef SCIPvarGetWorstBoundGlobal
16850 #undef SCIPvarGetLbLocal
16851 #undef SCIPvarGetUbLocal
16852 #undef SCIPvarGetHolelistLocal
16853 #undef SCIPvarGetBestBoundLocal
16854 #undef SCIPvarGetWorstBoundLocal
16855 #undef SCIPvarGetBestBoundType
16856 #undef SCIPvarGetWorstBoundType
16857 #undef SCIPvarGetLbLazy
16858 #undef SCIPvarGetUbLazy
16859 #undef SCIPvarGetBranchFactor
16860 #undef SCIPvarGetBranchPriority
16861 #undef SCIPvarGetBranchDirection
16862 #undef SCIPvarGetNVlbs
16863 #undef SCIPvarGetVlbVars
16864 #undef SCIPvarGetVlbCoefs
16865 #undef SCIPvarGetVlbConstants
16866 #undef SCIPvarGetNVubs
16867 #undef SCIPvarGetVubVars
16868 #undef SCIPvarGetVubCoefs
16869 #undef SCIPvarGetVubConstants
16870 #undef SCIPvarGetNImpls
16871 #undef SCIPvarGetImplVars
16872 #undef SCIPvarGetImplTypes
16873 #undef SCIPvarGetImplBounds
16874 #undef SCIPvarGetImplIds
16875 #undef SCIPvarGetNCliques
16876 #undef SCIPvarGetCliques
16877 #undef SCIPvarGetLPSol
16878 #undef SCIPvarGetNLPSol
16879 #undef SCIPvarGetBdchgInfoLb
16880 #undef SCIPvarGetNBdchgInfosLb
16881 #undef SCIPvarGetBdchgInfoUb
16882 #undef SCIPvarGetNBdchgInfosUb
16883 #undef SCIPvarGetValuehistory
16884 #undef SCIPvarGetPseudoSol
16885 #undef SCIPvarCatchEvent
16886 #undef SCIPvarDropEvent
16887 #undef SCIPvarGetVSIDS
16888 #undef SCIPvarGetCliqueComponentIdx
16889 #undef SCIPvarIsRelaxationOnly
16890 #undef SCIPvarMarkRelaxationOnly
16891 #undef SCIPbdchgidxGetPos
16892 #undef SCIPbdchgidxIsEarlierNonNull
16893 #undef SCIPbdchgidxIsEarlier
16894 #undef SCIPbdchginfoGetOldbound
16895 #undef SCIPbdchginfoGetNewbound
16896 #undef SCIPbdchginfoGetVar
16897 #undef SCIPbdchginfoGetChgtype
16898 #undef SCIPbdchginfoGetBoundtype
16899 #undef SCIPbdchginfoGetDepth
16900 #undef SCIPbdchginfoGetPos
16901 #undef SCIPbdchginfoGetIdx
16902 #undef SCIPbdchginfoGetInferVar
16903 #undef SCIPbdchginfoGetInferCons
16904 #undef SCIPbdchginfoGetInferProp
16905 #undef SCIPbdchginfoGetInferInfo
16906 #undef SCIPbdchginfoGetInferBoundtype
16907 #undef SCIPbdchginfoIsRedundant
16908 #undef SCIPbdchginfoHasInferenceReason
16909 #undef SCIPbdchginfoIsTighter
16910 
16911 
16912 /** returns the new value of the bound in the bound change data */
SCIPboundchgGetNewbound(SCIP_BOUNDCHG * boundchg)16913 SCIP_Real SCIPboundchgGetNewbound(
16914    SCIP_BOUNDCHG*        boundchg            /**< bound change data */
16915    )
16916 {
16917    assert(boundchg != NULL);
16918 
16919    return boundchg->newbound;
16920 }
16921 
16922 /** returns the variable of the bound change in the bound change data */
SCIPboundchgGetVar(SCIP_BOUNDCHG * boundchg)16923 SCIP_VAR* SCIPboundchgGetVar(
16924    SCIP_BOUNDCHG*        boundchg            /**< bound change data */
16925    )
16926 {
16927    assert(boundchg != NULL);
16928 
16929    return boundchg->var;
16930 }
16931 
16932 /** returns the bound change type of the bound change in the bound change data */
SCIPboundchgGetBoundchgtype(SCIP_BOUNDCHG * boundchg)16933 SCIP_BOUNDCHGTYPE SCIPboundchgGetBoundchgtype(
16934    SCIP_BOUNDCHG*        boundchg            /**< bound change data */
16935    )
16936 {
16937    assert(boundchg != NULL);
16938 
16939    return (SCIP_BOUNDCHGTYPE)(boundchg->boundchgtype);
16940 }
16941 
16942 /** returns the bound type of the bound change in the bound change data */
SCIPboundchgGetBoundtype(SCIP_BOUNDCHG * boundchg)16943 SCIP_BOUNDTYPE SCIPboundchgGetBoundtype(
16944    SCIP_BOUNDCHG*        boundchg            /**< bound change data */
16945    )
16946 {
16947    assert(boundchg != NULL);
16948 
16949    return (SCIP_BOUNDTYPE)(boundchg->boundtype);
16950 }
16951 
16952 /** returns whether the bound change is redundant due to a more global bound that is at least as strong */
SCIPboundchgIsRedundant(SCIP_BOUNDCHG * boundchg)16953 SCIP_Bool SCIPboundchgIsRedundant(
16954    SCIP_BOUNDCHG*        boundchg            /**< bound change data */
16955    )
16956 {
16957    assert(boundchg != NULL);
16958 
16959    return boundchg->redundant;
16960 }
16961 
16962 /** returns the number of bound changes in the domain change data */
SCIPdomchgGetNBoundchgs(SCIP_DOMCHG * domchg)16963 int SCIPdomchgGetNBoundchgs(
16964    SCIP_DOMCHG*          domchg              /**< domain change data */
16965    )
16966 {
16967    return domchg != NULL ? domchg->domchgbound.nboundchgs : 0;
16968 }
16969 
16970 /** returns a particular bound change in the domain change data */
SCIPdomchgGetBoundchg(SCIP_DOMCHG * domchg,int pos)16971 SCIP_BOUNDCHG* SCIPdomchgGetBoundchg(
16972    SCIP_DOMCHG*          domchg,             /**< domain change data */
16973    int                   pos                 /**< position of the bound change in the domain change data */
16974    )
16975 {
16976    assert(domchg != NULL);
16977    assert(0 <= pos && pos < (int)domchg->domchgbound.nboundchgs);
16978 
16979    return &domchg->domchgbound.boundchgs[pos];
16980 }
16981 
16982 /** returns left bound of open interval in hole */
SCIPholelistGetLeft(SCIP_HOLELIST * holelist)16983 SCIP_Real SCIPholelistGetLeft(
16984    SCIP_HOLELIST*        holelist            /**< hole list pointer to hole of interest */
16985    )
16986 {
16987    assert(holelist != NULL);
16988 
16989    return holelist->hole.left;
16990 }
16991 
16992 /** returns right bound of open interval in hole */
SCIPholelistGetRight(SCIP_HOLELIST * holelist)16993 SCIP_Real SCIPholelistGetRight(
16994    SCIP_HOLELIST*        holelist            /**< hole list pointer to hole of interest */
16995    )
16996 {
16997    assert(holelist != NULL);
16998 
16999    return holelist->hole.right;
17000 }
17001 
17002 /** returns next hole in list */
SCIPholelistGetNext(SCIP_HOLELIST * holelist)17003 SCIP_HOLELIST* SCIPholelistGetNext(
17004    SCIP_HOLELIST*        holelist            /**< hole list pointer to hole of interest */
17005    )
17006 {
17007    assert(holelist != NULL);
17008 
17009    return holelist->next;
17010 }
17011 
17012 /** returns the name of the variable
17013  *
17014  *  @note to change the name of a variable, use SCIPchgVarName() from scip.h
17015  */
SCIPvarGetName(SCIP_VAR * var)17016 const char* SCIPvarGetName(
17017    SCIP_VAR*             var                 /**< problem variable */
17018    )
17019 {
17020    assert(var != NULL);
17021 
17022    return var->name;
17023 }
17024 
17025 /** gets number of times, the variable is currently captured */
SCIPvarGetNUses(SCIP_VAR * var)17026 int SCIPvarGetNUses(
17027    SCIP_VAR*             var                 /**< problem variable */
17028    )
17029 {
17030    assert(var != NULL);
17031 
17032    return var->nuses;
17033 }
17034 
17035 /** returns the user data of the variable */
SCIPvarGetData(SCIP_VAR * var)17036 SCIP_VARDATA* SCIPvarGetData(
17037    SCIP_VAR*             var                 /**< problem variable */
17038    )
17039 {
17040    assert(var != NULL);
17041 
17042    return var->vardata;
17043 }
17044 
17045 /** sets the user data for the variable */
SCIPvarSetData(SCIP_VAR * var,SCIP_VARDATA * vardata)17046 void SCIPvarSetData(
17047    SCIP_VAR*             var,                /**< problem variable */
17048    SCIP_VARDATA*         vardata             /**< user variable data */
17049    )
17050 {
17051    assert(var != NULL);
17052 
17053    var->vardata = vardata;
17054 }
17055 
17056 /** sets method to free user data for the original variable */
SCIPvarSetDelorigData(SCIP_VAR * var,SCIP_DECL_VARDELORIG ((* vardelorig)))17057 void SCIPvarSetDelorigData(
17058    SCIP_VAR*             var,                /**< problem variable */
17059    SCIP_DECL_VARDELORIG  ((*vardelorig))     /**< frees user data of original variable */
17060    )
17061 {
17062    assert(var != NULL);
17063    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL);
17064 
17065    var->vardelorig = vardelorig;
17066 }
17067 
17068 /** sets method to transform user data of the variable */
SCIPvarSetTransData(SCIP_VAR * var,SCIP_DECL_VARTRANS ((* vartrans)))17069 void SCIPvarSetTransData(
17070    SCIP_VAR*             var,                /**< problem variable */
17071    SCIP_DECL_VARTRANS    ((*vartrans))       /**< creates transformed user data by transforming original user data */
17072    )
17073 {
17074    assert(var != NULL);
17075    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL);
17076 
17077    var->vartrans = vartrans;
17078 }
17079 
17080 /** sets method to free transformed user data for the variable */
SCIPvarSetDeltransData(SCIP_VAR * var,SCIP_DECL_VARDELTRANS ((* vardeltrans)))17081 void SCIPvarSetDeltransData(
17082    SCIP_VAR*             var,                /**< problem variable */
17083    SCIP_DECL_VARDELTRANS ((*vardeltrans))    /**< frees user data of transformed variable */
17084    )
17085 {
17086    assert(var != NULL);
17087 
17088    var->vardeltrans = vardeltrans;
17089 }
17090 
17091 /** sets method to copy this variable into sub-SCIPs */
SCIPvarSetCopyData(SCIP_VAR * var,SCIP_DECL_VARCOPY ((* varcopy)))17092 void SCIPvarSetCopyData(
17093    SCIP_VAR*             var,                /**< problem variable */
17094    SCIP_DECL_VARCOPY     ((*varcopy))        /**< copy method of the variable */
17095    )
17096 {
17097    assert(var != NULL);
17098 
17099    var->varcopy = varcopy;
17100 }
17101 
17102 /** sets the initial flag of a variable; only possible for original or loose variables */
SCIPvarSetInitial(SCIP_VAR * var,SCIP_Bool initial)17103 SCIP_RETCODE SCIPvarSetInitial(
17104    SCIP_VAR*             var,                /**< problem variable */
17105    SCIP_Bool             initial             /**< initial flag */
17106    )
17107 {
17108    assert(var != NULL);
17109 
17110    if( (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_ORIGINAL && (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_LOOSE )
17111       return SCIP_INVALIDCALL;
17112 
17113    var->initial = initial;
17114 
17115    return SCIP_OKAY;
17116 }
17117 
17118 /** sets the removable flag of a variable; only possible for original or loose variables */
SCIPvarSetRemovable(SCIP_VAR * var,SCIP_Bool removable)17119 SCIP_RETCODE SCIPvarSetRemovable(
17120    SCIP_VAR*             var,                /**< problem variable */
17121    SCIP_Bool             removable           /**< removable flag */
17122    )
17123 {
17124    assert(var != NULL);
17125 
17126    if( (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_ORIGINAL && (SCIP_VARSTATUS)var->varstatus != SCIP_VARSTATUS_LOOSE )
17127       return SCIP_INVALIDCALL;
17128 
17129    var->removable = removable;
17130 
17131    return SCIP_OKAY;
17132 }
17133 
17134 /** gets status of variable */
SCIPvarGetStatus(SCIP_VAR * var)17135 SCIP_VARSTATUS SCIPvarGetStatus(
17136    SCIP_VAR*             var                 /**< problem variable */
17137    )
17138 {
17139    assert(var != NULL);
17140 
17141    return (SCIP_VARSTATUS)(var->varstatus);
17142 }
17143 
17144 /** returns whether the variable belongs to the original problem */
SCIPvarIsOriginal(SCIP_VAR * var)17145 SCIP_Bool SCIPvarIsOriginal(
17146    SCIP_VAR*             var                 /**< problem variable */
17147    )
17148 {
17149    assert(var != NULL);
17150    assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED || var->negatedvar != NULL);
17151 
17152    return (SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL
17153       || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED
17154          && SCIPvarGetStatus(var->negatedvar) == SCIP_VARSTATUS_ORIGINAL));
17155 }
17156 
17157 /** returns whether the variable belongs to the transformed problem */
SCIPvarIsTransformed(SCIP_VAR * var)17158 SCIP_Bool SCIPvarIsTransformed(
17159    SCIP_VAR*             var                 /**< problem variable */
17160    )
17161 {
17162    assert(var != NULL);
17163    assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED || var->negatedvar != NULL);
17164 
17165    return (SCIPvarGetStatus(var) != SCIP_VARSTATUS_ORIGINAL
17166       && (SCIPvarGetStatus(var) != SCIP_VARSTATUS_NEGATED
17167          || SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_ORIGINAL));
17168 }
17169 
17170 /** returns whether the variable was created by negation of a different variable */
SCIPvarIsNegated(SCIP_VAR * var)17171 SCIP_Bool SCIPvarIsNegated(
17172    SCIP_VAR*             var                 /**< problem variable */
17173    )
17174 {
17175    assert(var != NULL);
17176 
17177    return (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
17178 }
17179 
17180 /** gets type of variable */
SCIPvarGetType(SCIP_VAR * var)17181 SCIP_VARTYPE SCIPvarGetType(
17182    SCIP_VAR*             var                 /**< problem variable */
17183    )
17184 {
17185    assert(var != NULL);
17186 
17187    return (SCIP_VARTYPE)(var->vartype);
17188 }
17189 
17190 /** returns TRUE if the variable is of binary type; this is the case if:
17191  *  (1) variable type is binary
17192  *  (2) variable type is integer or implicit integer and
17193  *      (i)  the lazy lower bound or the global lower bound is greater than or equal to zero
17194  *      (ii) the lazy upper bound or the global upper bound is less than or equal to one
17195  */
SCIPvarIsBinary(SCIP_VAR * var)17196 SCIP_Bool SCIPvarIsBinary(
17197    SCIP_VAR*             var                 /**< problem variable */
17198    )
17199 {
17200    assert(var != NULL);
17201 
17202    return (SCIPvarGetType(var) == SCIP_VARTYPE_BINARY ||
17203       (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && MAX(var->glbdom.lb, var->lazylb) >= 0.0 && MIN(var->glbdom.ub, var->lazyub) <= 1.0));
17204 }
17205 
17206 /** returns whether variable is of integral type (binary, integer, or implicit integer) */
SCIPvarIsIntegral(SCIP_VAR * var)17207 SCIP_Bool SCIPvarIsIntegral(
17208    SCIP_VAR*             var                 /**< problem variable */
17209    )
17210 {
17211    assert(var != NULL);
17212 
17213    return (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
17214 }
17215 
17216 /** returns whether variable's column should be present in the initial root LP */
SCIPvarIsInitial(SCIP_VAR * var)17217 SCIP_Bool SCIPvarIsInitial(
17218    SCIP_VAR*             var                 /**< problem variable */
17219    )
17220 {
17221    assert(var != NULL);
17222 
17223    return var->initial;
17224 }
17225 
17226 /** returns whether variable's column is removable from the LP (due to aging or cleanup) */
SCIPvarIsRemovable(SCIP_VAR * var)17227 SCIP_Bool SCIPvarIsRemovable(
17228    SCIP_VAR*             var                 /**< problem variable */
17229    )
17230 {
17231    assert(var != NULL);
17232 
17233    return var->removable;
17234 }
17235 
17236 /** returns whether the variable was deleted from the problem */
SCIPvarIsDeleted(SCIP_VAR * var)17237 SCIP_Bool SCIPvarIsDeleted(
17238    SCIP_VAR*             var                 /**< problem variable */
17239    )
17240 {
17241    assert(var != NULL);
17242 
17243    return var->deleted;
17244 }
17245 
17246 /** marks the variable to be deletable, i.e., it may be deleted completely from the problem;
17247  *  method can only be called before the variable is added to the problem by SCIPaddVar() or SCIPaddPricedVar()
17248  */
SCIPvarMarkDeletable(SCIP_VAR * var)17249 void SCIPvarMarkDeletable(
17250    SCIP_VAR*             var                 /**< problem variable */
17251    )
17252 {
17253    assert(var != NULL);
17254    assert(var->probindex == -1);
17255 
17256    var->deletable = TRUE;
17257 }
17258 
17259 /** marks the variable to be not deletable from the problem */
SCIPvarMarkNotDeletable(SCIP_VAR * var)17260 void SCIPvarMarkNotDeletable(
17261    SCIP_VAR*             var
17262    )
17263 {
17264    assert(var != NULL);
17265 
17266    var->deletable = FALSE;
17267 }
17268 
17269 /** marks variable to be deleted from global structures (cliques etc.) when cleaning up
17270  *
17271  *  @note: this is not equivalent to marking the variable itself for deletion, this is done by using SCIPvarMarkDeletable()
17272  */
SCIPvarMarkDeleteGlobalStructures(SCIP_VAR * var)17273 void SCIPvarMarkDeleteGlobalStructures(
17274    SCIP_VAR*             var                 /**< problem variable */
17275    )
17276 {
17277    assert(var != NULL);
17278 
17279    var->delglobalstructs = TRUE;
17280 }
17281 
17282 /** returns whether the variable was flagged for deletion from global structures (cliques etc.) */
SCIPvarIsMarkedDeleteGlobalStructures(SCIP_VAR * var)17283 SCIP_Bool SCIPvarIsMarkedDeleteGlobalStructures(
17284    SCIP_VAR*             var                 /**< problem variable */
17285    )
17286 {
17287    assert(var != NULL);
17288 
17289    return var->delglobalstructs;
17290 }
17291 
17292 /** returns whether a variable has been introduced to define a relaxation
17293  *
17294  * These variables are only valid for the current SCIP solve round,
17295  * they are not contained in any (checked) constraints, but may be used
17296  * in cutting planes, for example.
17297  * Relaxation-only variables are not copied by SCIPcopyVars and cuts
17298  * that contain these variables are not added as linear constraints when
17299  * restarting or transferring information from a copied SCIP to a SCIP.
17300  * Also conflicts with relaxation-only variables are not generated at
17301  * the moment.
17302  */
SCIPvarIsRelaxationOnly(SCIP_VAR * var)17303 SCIP_Bool SCIPvarIsRelaxationOnly(
17304    SCIP_VAR*             var                 /**< problem variable */
17305    )
17306 {
17307    assert(var != NULL);
17308 
17309    return var->relaxationonly;
17310 }
17311 
17312 /** marks that this variable has only been introduced to define a relaxation
17313  *
17314  * The variable must not have a coefficient in the objective.
17315  *
17316  * @see SCIPvarIsRelaxationOnly
17317  */
SCIPvarMarkRelaxationOnly(SCIP_VAR * var)17318 void SCIPvarMarkRelaxationOnly(
17319    SCIP_VAR*             var                 /**< problem variable */
17320    )
17321 {
17322    assert(var != NULL);
17323    assert(SCIPvarGetObj(var) == 0.0);
17324 
17325    var->relaxationonly = TRUE;
17326 }
17327 
17328 /** returns whether variable is allowed to be deleted completely from the problem */
SCIPvarIsDeletable(SCIP_VAR * var)17329 SCIP_Bool SCIPvarIsDeletable(
17330    SCIP_VAR*             var
17331    )
17332 {
17333    assert(var != NULL);
17334 
17335    return var->deletable;
17336 }
17337 
17338 /** returns whether variable is an active (neither fixed nor aggregated) variable */
SCIPvarIsActive(SCIP_VAR * var)17339 SCIP_Bool SCIPvarIsActive(
17340    SCIP_VAR*             var                 /**< problem variable */
17341    )
17342 {
17343    assert(var != NULL);
17344 
17345    return (var->probindex >= 0);
17346 }
17347 
17348 /** gets unique index of variable */
SCIPvarGetIndex(SCIP_VAR * var)17349 int SCIPvarGetIndex(
17350    SCIP_VAR*             var                 /**< problem variable */
17351    )
17352 {
17353    assert(var != NULL);
17354 
17355    return var->index;
17356 }
17357 
17358 /** gets position of variable in problem, or -1 if variable is not active */
SCIPvarGetProbindex(SCIP_VAR * var)17359 int SCIPvarGetProbindex(
17360    SCIP_VAR*             var                 /**< problem variable */
17361    )
17362 {
17363    assert(var != NULL);
17364 
17365    return var->probindex;
17366 }
17367 
17368 /** gets transformed variable of ORIGINAL variable */
SCIPvarGetTransVar(SCIP_VAR * var)17369 SCIP_VAR* SCIPvarGetTransVar(
17370    SCIP_VAR*             var                 /**< problem variable */
17371    )
17372 {
17373    assert(var != NULL);
17374    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL);
17375 
17376    return var->data.original.transvar;
17377 }
17378 
17379 /** gets column of COLUMN variable */
SCIPvarGetCol(SCIP_VAR * var)17380 SCIP_COL* SCIPvarGetCol(
17381    SCIP_VAR*             var                 /**< problem variable */
17382    )
17383 {
17384    assert(var != NULL);
17385    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
17386 
17387    return var->data.col;
17388 }
17389 
17390 /** returns whether the variable is a COLUMN variable that is member of the current LP */
SCIPvarIsInLP(SCIP_VAR * var)17391 SCIP_Bool SCIPvarIsInLP(
17392    SCIP_VAR*             var                 /**< problem variable */
17393    )
17394 {
17395    assert(var != NULL);
17396 
17397    return (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN && SCIPcolIsInLP(var->data.col));
17398 }
17399 
17400 /** gets aggregation variable y of an aggregated variable x = a*y + c */
SCIPvarGetAggrVar(SCIP_VAR * var)17401 SCIP_VAR* SCIPvarGetAggrVar(
17402    SCIP_VAR*             var                 /**< problem variable */
17403    )
17404 {
17405    assert(var != NULL);
17406    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED);
17407 
17408    return var->data.aggregate.var;
17409 }
17410 
17411 /** gets aggregation scalar a of an aggregated variable x = a*y + c */
SCIPvarGetAggrScalar(SCIP_VAR * var)17412 SCIP_Real SCIPvarGetAggrScalar(
17413    SCIP_VAR*             var                 /**< problem variable */
17414    )
17415 {
17416    assert(var != NULL);
17417    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED);
17418 
17419    return var->data.aggregate.scalar;
17420 }
17421 
17422 /** gets aggregation constant c of an aggregated variable x = a*y + c */
SCIPvarGetAggrConstant(SCIP_VAR * var)17423 SCIP_Real SCIPvarGetAggrConstant(
17424    SCIP_VAR*             var                 /**< problem variable */
17425    )
17426 {
17427    assert(var != NULL);
17428    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED);
17429 
17430    return var->data.aggregate.constant;
17431 }
17432 
17433 /** gets number n of aggregation variables of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
SCIPvarGetMultaggrNVars(SCIP_VAR * var)17434 int SCIPvarGetMultaggrNVars(
17435    SCIP_VAR*             var                 /**< problem variable */
17436    )
17437 {
17438    assert(var != NULL);
17439    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
17440    assert(!var->donotmultaggr);
17441 
17442    return var->data.multaggr.nvars;
17443 }
17444 
17445 /** gets vector of aggregation variables y of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
SCIPvarGetMultaggrVars(SCIP_VAR * var)17446 SCIP_VAR** SCIPvarGetMultaggrVars(
17447    SCIP_VAR*             var                 /**< problem variable */
17448    )
17449 {
17450    assert(var != NULL);
17451    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
17452    assert(!var->donotmultaggr);
17453 
17454    return var->data.multaggr.vars;
17455 }
17456 
17457 /** gets vector of aggregation scalars a of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
SCIPvarGetMultaggrScalars(SCIP_VAR * var)17458 SCIP_Real* SCIPvarGetMultaggrScalars(
17459    SCIP_VAR*             var                 /**< problem variable */
17460    )
17461 {
17462    assert(var != NULL);
17463    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
17464    assert(!var->donotmultaggr);
17465 
17466    return var->data.multaggr.scalars;
17467 }
17468 
17469 /** gets aggregation constant c of a multi aggregated variable x = a0*y0 + ... + a(n-1)*y(n-1) + c */
SCIPvarGetMultaggrConstant(SCIP_VAR * var)17470 SCIP_Real SCIPvarGetMultaggrConstant(
17471    SCIP_VAR*             var                 /**< problem variable */
17472    )
17473 {
17474    assert(var != NULL);
17475    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
17476    assert(!var->donotmultaggr);
17477 
17478    return var->data.multaggr.constant;
17479 }
17480 
17481 /** gets the negation of the given variable; may return NULL, if no negation is existing yet */
SCIPvarGetNegatedVar(SCIP_VAR * var)17482 SCIP_VAR* SCIPvarGetNegatedVar(
17483    SCIP_VAR*             var                 /**< negated problem variable */
17484    )
17485 {
17486    assert(var != NULL);
17487 
17488    return var->negatedvar;
17489 }
17490 
17491 /** gets the negation variable x of a negated variable x' = offset - x */
SCIPvarGetNegationVar(SCIP_VAR * var)17492 SCIP_VAR* SCIPvarGetNegationVar(
17493    SCIP_VAR*             var                 /**< negated problem variable */
17494    )
17495 {
17496    assert(var != NULL);
17497    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
17498 
17499    return var->negatedvar;
17500 }
17501 
17502 /** gets the negation offset of a negated variable x' = offset - x */
SCIPvarGetNegationConstant(SCIP_VAR * var)17503 SCIP_Real SCIPvarGetNegationConstant(
17504    SCIP_VAR*             var                 /**< negated problem variable */
17505    )
17506 {
17507    assert(var != NULL);
17508    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
17509 
17510    return var->data.negate.constant;
17511 }
17512 
17513 /** gets objective function value of variable */
SCIPvarGetObj(SCIP_VAR * var)17514 SCIP_Real SCIPvarGetObj(
17515    SCIP_VAR*             var                 /**< problem variable */
17516    )
17517 {
17518    assert(var != NULL);
17519 
17520    return var->obj;
17521 }
17522 
17523 /** gets the unchanged objective function value of a variable (ignoring temproray changes performed in probing mode) */
SCIPvarGetUnchangedObj(SCIP_VAR * var)17524 SCIP_Real SCIPvarGetUnchangedObj(
17525    SCIP_VAR*             var                 /**< problem variable */
17526    )
17527 {
17528    assert(var != NULL);
17529 
17530    return var->unchangedobj;
17531 }
17532 
17533 /** gets corresponding objective value of active, fixed, or multi-aggregated problem variable of given variable
17534  *  e.g. obj(x) = 1 this method returns for ~x the value -1
17535  */
SCIPvarGetAggregatedObj(SCIP_VAR * var,SCIP_Real * aggrobj)17536 SCIP_RETCODE SCIPvarGetAggregatedObj(
17537    SCIP_VAR*             var,                /**< problem variable */
17538    SCIP_Real*            aggrobj             /**< pointer to store the aggregated objective value */
17539    )
17540 {
17541    SCIP_VAR* probvar = var;
17542    SCIP_Real mult = 1.0;
17543 
17544    assert(probvar != NULL);
17545    assert(aggrobj != NULL);
17546 
17547    while( probvar != NULL )
17548    {
17549       switch( SCIPvarGetStatus(probvar) )
17550       {
17551       case SCIP_VARSTATUS_ORIGINAL:
17552       case SCIP_VARSTATUS_LOOSE:
17553       case SCIP_VARSTATUS_COLUMN:
17554 	 (*aggrobj) = mult * SCIPvarGetObj(probvar);
17555 	 return SCIP_OKAY;
17556 
17557       case SCIP_VARSTATUS_FIXED:
17558 	 assert(SCIPvarGetObj(probvar) == 0.0);
17559 	 (*aggrobj) = 0.0;
17560          return SCIP_OKAY;
17561 
17562       case SCIP_VARSTATUS_MULTAGGR:
17563          /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
17564          if ( probvar->data.multaggr.nvars == 1 )
17565          {
17566             assert( probvar->data.multaggr.vars != NULL );
17567             assert( probvar->data.multaggr.scalars != NULL );
17568             assert( probvar->data.multaggr.vars[0] != NULL );
17569             mult *= probvar->data.multaggr.scalars[0];
17570             probvar = probvar->data.multaggr.vars[0];
17571             break;
17572          }
17573 	 else
17574 	 {
17575 	    SCIP_Real tmpobj;
17576 	    int v;
17577 
17578 	    (*aggrobj) = 0.0;
17579 
17580 	    for( v = probvar->data.multaggr.nvars - 1; v >= 0; --v )
17581 	    {
17582 	       SCIP_CALL( SCIPvarGetAggregatedObj(probvar->data.multaggr.vars[v], &tmpobj) );
17583 	       (*aggrobj) += probvar->data.multaggr.scalars[v] * tmpobj;
17584 	    }
17585 	    return SCIP_OKAY;
17586 	 }
17587 
17588       case SCIP_VARSTATUS_AGGREGATED:  /* x = a'*x' + c'  =>  a*x + c == (a*a')*x' + (a*c' + c) */
17589          assert(probvar->data.aggregate.var != NULL);
17590          mult *= probvar->data.aggregate.scalar;
17591          probvar = probvar->data.aggregate.var;
17592          break;
17593 
17594       case SCIP_VARSTATUS_NEGATED:     /* x =  - x' + c'  =>  a*x + c ==   (-a)*x' + (a*c' + c) */
17595          assert(probvar->negatedvar != NULL);
17596          assert(SCIPvarGetStatus(probvar->negatedvar) != SCIP_VARSTATUS_NEGATED);
17597          assert(probvar->negatedvar->negatedvar == probvar);
17598          mult *= -1.0;
17599          probvar = probvar->negatedvar;
17600          break;
17601 
17602       default:
17603 	 SCIPABORT();
17604 	 return SCIP_INVALIDDATA; /*lint !e527*/
17605       }
17606    }
17607 
17608    return SCIP_INVALIDDATA;
17609 }
17610 
17611 /** gets original lower bound of original problem variable (i.e. the bound set in problem creation) */
SCIPvarGetLbOriginal(SCIP_VAR * var)17612 SCIP_Real SCIPvarGetLbOriginal(
17613    SCIP_VAR*             var                 /**< original problem variable */
17614    )
17615 {
17616    assert(var != NULL);
17617    assert(SCIPvarIsOriginal(var));
17618 
17619    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL )
17620       return var->data.original.origdom.lb;
17621    else
17622    {
17623       assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
17624       assert(var->negatedvar != NULL);
17625       assert(SCIPvarGetStatus(var->negatedvar) == SCIP_VARSTATUS_ORIGINAL);
17626 
17627       return var->data.negate.constant - var->negatedvar->data.original.origdom.ub;
17628    }
17629 }
17630 
17631 /** gets original upper bound of original problem variable (i.e. the bound set in problem creation) */
SCIPvarGetUbOriginal(SCIP_VAR * var)17632 SCIP_Real SCIPvarGetUbOriginal(
17633    SCIP_VAR*             var                 /**< original problem variable */
17634    )
17635 {
17636    assert(var != NULL);
17637    assert(SCIPvarIsOriginal(var));
17638 
17639    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL )
17640       return var->data.original.origdom.ub;
17641    else
17642    {
17643       assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
17644       assert(var->negatedvar != NULL);
17645       assert(SCIPvarGetStatus(var->negatedvar) == SCIP_VARSTATUS_ORIGINAL);
17646 
17647       return var->data.negate.constant - var->negatedvar->data.original.origdom.lb;
17648    }
17649 }
17650 
17651 /** gets the original hole list of an original variable */
SCIPvarGetHolelistOriginal(SCIP_VAR * var)17652 SCIP_HOLELIST* SCIPvarGetHolelistOriginal(
17653    SCIP_VAR*             var                 /**< problem variable */
17654    )
17655 {
17656    assert(var != NULL);
17657    assert(SCIPvarIsOriginal(var));
17658 
17659    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL )
17660       return var->data.original.origdom.holelist;
17661 
17662    return NULL;
17663 }
17664 
17665 /** gets global lower bound of variable */
SCIPvarGetLbGlobal(SCIP_VAR * var)17666 SCIP_Real SCIPvarGetLbGlobal(
17667    SCIP_VAR*             var                 /**< problem variable */
17668    )
17669 {
17670    assert(var != NULL);
17671 
17672    return var->glbdom.lb;
17673 }
17674 
17675 /** gets global upper bound of variable */
SCIPvarGetUbGlobal(SCIP_VAR * var)17676 SCIP_Real SCIPvarGetUbGlobal(
17677    SCIP_VAR*             var                 /**< problem variable */
17678    )
17679 {
17680    assert(var != NULL);
17681 
17682    return var->glbdom.ub;
17683 }
17684 
17685 /** gets the global hole list of an active variable */
SCIPvarGetHolelistGlobal(SCIP_VAR * var)17686 SCIP_HOLELIST* SCIPvarGetHolelistGlobal(
17687    SCIP_VAR*             var                 /**< problem variable */
17688    )
17689 {
17690    assert(var != NULL);
17691 
17692    return var->glbdom.holelist;
17693 }
17694 
17695 /** gets best global bound of variable with respect to the objective function */
SCIPvarGetBestBoundGlobal(SCIP_VAR * var)17696 SCIP_Real SCIPvarGetBestBoundGlobal(
17697    SCIP_VAR*             var                 /**< problem variable */
17698    )
17699 {
17700    assert(var != NULL);
17701 
17702    if( var->obj >= 0.0 )
17703       return var->glbdom.lb;
17704    else
17705       return var->glbdom.ub;
17706 }
17707 
17708 /** gets worst global bound of variable with respect to the objective function */
SCIPvarGetWorstBoundGlobal(SCIP_VAR * var)17709 SCIP_Real SCIPvarGetWorstBoundGlobal(
17710    SCIP_VAR*             var                 /**< problem variable */
17711    )
17712 {
17713    assert(var != NULL);
17714 
17715    if( var->obj >= 0.0 )
17716       return var->glbdom.ub;
17717    else
17718       return var->glbdom.lb;
17719 }
17720 
17721 /** gets current lower bound of variable */
SCIPvarGetLbLocal(SCIP_VAR * var)17722 SCIP_Real SCIPvarGetLbLocal(
17723    SCIP_VAR*             var                 /**< problem variable */
17724    )
17725 {
17726    assert(var != NULL);
17727 
17728    return var->locdom.lb;
17729 }
17730 
17731 /** gets current upper bound of variable */
SCIPvarGetUbLocal(SCIP_VAR * var)17732 SCIP_Real SCIPvarGetUbLocal(
17733    SCIP_VAR*             var                 /**< problem variable */
17734    )
17735 {
17736    assert(var != NULL);
17737 
17738    return var->locdom.ub;
17739 }
17740 
17741 /** gets the current hole list of an active variable */
SCIPvarGetHolelistLocal(SCIP_VAR * var)17742 SCIP_HOLELIST* SCIPvarGetHolelistLocal(
17743    SCIP_VAR*             var                 /**< problem variable */
17744    )
17745 {
17746    assert(var != NULL);
17747 
17748    return var->locdom.holelist;
17749 }
17750 
17751 /** gets best local bound of variable with respect to the objective function */
SCIPvarGetBestBoundLocal(SCIP_VAR * var)17752 SCIP_Real SCIPvarGetBestBoundLocal(
17753    SCIP_VAR*             var                 /**< problem variable */
17754    )
17755 {
17756    assert(var != NULL);
17757 
17758    if( var->obj >= 0.0 )
17759       return var->locdom.lb;
17760    else
17761       return var->locdom.ub;
17762 }
17763 
17764 /** gets worst local bound of variable with respect to the objective function */
SCIPvarGetWorstBoundLocal(SCIP_VAR * var)17765 SCIP_Real SCIPvarGetWorstBoundLocal(
17766    SCIP_VAR*             var                 /**< problem variable */
17767    )
17768 {
17769    assert(var != NULL);
17770 
17771    if( var->obj >= 0.0 )
17772       return var->locdom.ub;
17773    else
17774       return var->locdom.lb;
17775 }
17776 
17777 /** gets type (lower or upper) of best bound of variable with respect to the objective function */
SCIPvarGetBestBoundType(SCIP_VAR * var)17778 SCIP_BOUNDTYPE SCIPvarGetBestBoundType(
17779    SCIP_VAR*             var                 /**< problem variable */
17780    )
17781 {
17782    assert(var != NULL);
17783 
17784    if( var->obj >= 0.0 )
17785       return SCIP_BOUNDTYPE_LOWER;
17786    else
17787       return SCIP_BOUNDTYPE_UPPER;
17788 }
17789 
17790 /** gets type (lower or upper) of worst bound of variable with respect to the objective function */
SCIPvarGetWorstBoundType(SCIP_VAR * var)17791 SCIP_BOUNDTYPE SCIPvarGetWorstBoundType(
17792    SCIP_VAR*             var                 /**< problem variable */
17793    )
17794 {
17795    assert(var != NULL);
17796 
17797    if( var->obj >= 0.0 )
17798       return SCIP_BOUNDTYPE_UPPER;
17799    else
17800       return SCIP_BOUNDTYPE_LOWER;
17801 }
17802 
17803 /** gets lazy lower bound of variable, returns -infinity if the variable has no lazy lower bound */
SCIPvarGetLbLazy(SCIP_VAR * var)17804 SCIP_Real SCIPvarGetLbLazy(
17805    SCIP_VAR*             var                 /**< problem variable */
17806    )
17807 {
17808    assert(var != NULL);
17809 
17810    return var->lazylb;
17811 }
17812 
17813 /** gets lazy upper bound of variable, returns infinity if the variable has no lazy upper bound */
SCIPvarGetUbLazy(SCIP_VAR * var)17814 SCIP_Real SCIPvarGetUbLazy(
17815    SCIP_VAR*             var                 /**< problem variable */
17816    )
17817 {
17818    assert(var != NULL);
17819 
17820    return var->lazyub;
17821 }
17822 
17823 /** gets the branch factor of the variable; this value can be used in the branching methods to scale the score
17824  *  values of the variables; higher factor leads to a higher probability that this variable is chosen for branching
17825  */
SCIPvarGetBranchFactor(SCIP_VAR * var)17826 SCIP_Real SCIPvarGetBranchFactor(
17827    SCIP_VAR*             var                 /**< problem variable */
17828    )
17829 {
17830    assert(var != NULL);
17831 
17832    return var->branchfactor;
17833 }
17834 
17835 /** gets the branch priority of the variable; variables with higher priority should always be preferred to variables
17836  *  with lower priority
17837  */
SCIPvarGetBranchPriority(SCIP_VAR * var)17838 int SCIPvarGetBranchPriority(
17839    SCIP_VAR*             var                 /**< problem variable */
17840    )
17841 {
17842    assert(var != NULL);
17843 
17844    return var->branchpriority;
17845 }
17846 
17847 /** gets the preferred branch direction of the variable (downwards, upwards, or auto) */
SCIPvarGetBranchDirection(SCIP_VAR * var)17848 SCIP_BRANCHDIR SCIPvarGetBranchDirection(
17849    SCIP_VAR*             var                 /**< problem variable */
17850    )
17851 {
17852    assert(var != NULL);
17853 
17854    return (SCIP_BRANCHDIR)var->branchdirection;
17855 }
17856 
17857 /** gets number of variable lower bounds x >= b_i*z_i + d_i of given variable x */
SCIPvarGetNVlbs(SCIP_VAR * var)17858 int SCIPvarGetNVlbs(
17859    SCIP_VAR*             var                 /**< problem variable */
17860    )
17861 {
17862    assert(var != NULL);
17863 
17864    return SCIPvboundsGetNVbds(var->vlbs);
17865 }
17866 
17867 /** gets array with bounding variables z_i in variable lower bounds x >= b_i*z_i + d_i of given variable x;
17868  *  the variable bounds are sorted by increasing variable index of the bounding variable z_i (see SCIPvarGetIndex())
17869  */
SCIPvarGetVlbVars(SCIP_VAR * var)17870 SCIP_VAR** SCIPvarGetVlbVars(
17871    SCIP_VAR*             var                 /**< problem variable */
17872    )
17873 {
17874    assert(var != NULL);
17875 
17876    return SCIPvboundsGetVars(var->vlbs);
17877 }
17878 
17879 /** gets array with bounding coefficients b_i in variable lower bounds x >= b_i*z_i + d_i of given variable x */
SCIPvarGetVlbCoefs(SCIP_VAR * var)17880 SCIP_Real* SCIPvarGetVlbCoefs(
17881    SCIP_VAR*             var                 /**< problem variable */
17882    )
17883 {
17884    assert(var != NULL);
17885 
17886    return SCIPvboundsGetCoefs(var->vlbs);
17887 }
17888 
17889 /** gets array with bounding constants d_i in variable lower bounds x >= b_i*z_i + d_i of given variable x */
SCIPvarGetVlbConstants(SCIP_VAR * var)17890 SCIP_Real* SCIPvarGetVlbConstants(
17891    SCIP_VAR*             var                 /**< problem variable */
17892    )
17893 {
17894    assert(var != NULL);
17895 
17896    return SCIPvboundsGetConstants(var->vlbs);
17897 }
17898 
17899 /** gets number of variable upper bounds x <= b_i*z_i + d_i of given variable x */
SCIPvarGetNVubs(SCIP_VAR * var)17900 int SCIPvarGetNVubs(
17901    SCIP_VAR*             var                 /**< problem variable */
17902    )
17903 {
17904    assert(var != NULL);
17905 
17906    return SCIPvboundsGetNVbds(var->vubs);
17907 }
17908 
17909 /** gets array with bounding variables z_i in variable upper bounds x <= b_i*z_i + d_i of given variable x;
17910  *  the variable bounds are sorted by increasing variable index of the bounding variable z_i (see SCIPvarGetIndex())
17911  */
SCIPvarGetVubVars(SCIP_VAR * var)17912 SCIP_VAR** SCIPvarGetVubVars(
17913    SCIP_VAR*             var                 /**< problem variable */
17914    )
17915 {
17916    assert(var != NULL);
17917 
17918    return SCIPvboundsGetVars(var->vubs);
17919 }
17920 
17921 /** gets array with bounding coefficients b_i in variable upper bounds x <= b_i*z_i + d_i of given variable x */
SCIPvarGetVubCoefs(SCIP_VAR * var)17922 SCIP_Real* SCIPvarGetVubCoefs(
17923    SCIP_VAR*             var                 /**< problem variable */
17924    )
17925 {
17926    assert(var != NULL);
17927 
17928    return SCIPvboundsGetCoefs(var->vubs);
17929 }
17930 
17931 /** gets array with bounding constants d_i in variable upper bounds x <= b_i*z_i + d_i of given variable x */
SCIPvarGetVubConstants(SCIP_VAR * var)17932 SCIP_Real* SCIPvarGetVubConstants(
17933    SCIP_VAR*             var                 /**< problem variable */
17934    )
17935 {
17936    assert(var != NULL);
17937 
17938    return SCIPvboundsGetConstants(var->vubs);
17939 }
17940 
17941 /** gets number of implications  y <= b or y >= b for x == 0 or x == 1 of given active problem variable x,
17942  *  there are no implications for nonbinary variable x
17943  */
SCIPvarGetNImpls(SCIP_VAR * var,SCIP_Bool varfixing)17944 int SCIPvarGetNImpls(
17945    SCIP_VAR*             var,                /**< active problem variable */
17946    SCIP_Bool             varfixing           /**< FALSE for implications for x == 0, TRUE for x == 1 */
17947    )
17948 {
17949    assert(var != NULL);
17950    assert(SCIPvarIsActive(var));
17951 
17952    return SCIPimplicsGetNImpls(var->implics, varfixing);
17953 }
17954 
17955 /** gets array with implication variables y of implications  y <= b or y >= b for x == 0 or x == 1 of given active
17956  *  problem variable x, there are no implications for nonbinary variable x;
17957  *  the implications are sorted such that implications with binary implied variables precede the ones with non-binary
17958  *  implied variables, and as a second criteria, the implied variables are sorted by increasing variable index
17959  *  (see SCIPvarGetIndex())
17960  */
SCIPvarGetImplVars(SCIP_VAR * var,SCIP_Bool varfixing)17961 SCIP_VAR** SCIPvarGetImplVars(
17962    SCIP_VAR*             var,                /**< active problem variable */
17963    SCIP_Bool             varfixing           /**< FALSE for implications for x == 0, TRUE for x == 1 */
17964    )
17965 {
17966    assert(var != NULL);
17967    assert(SCIPvarIsActive(var));
17968 
17969    return SCIPimplicsGetVars(var->implics, varfixing);
17970 }
17971 
17972 /** gets array with implication types of implications  y <= b or y >= b for x == 0 or x == 1 of given active problem
17973  *  variable x (SCIP_BOUNDTYPE_UPPER if y <= b, SCIP_BOUNDTYPE_LOWER if y >= b),
17974  *  there are no implications for nonbinary variable x
17975  */
SCIPvarGetImplTypes(SCIP_VAR * var,SCIP_Bool varfixing)17976 SCIP_BOUNDTYPE* SCIPvarGetImplTypes(
17977    SCIP_VAR*             var,                /**< active problem variable */
17978    SCIP_Bool             varfixing           /**< FALSE for implications for x == 0, TRUE for x == 1 */
17979    )
17980 {
17981    assert(var != NULL);
17982    assert(SCIPvarIsActive(var));
17983 
17984    return SCIPimplicsGetTypes(var->implics, varfixing);
17985 }
17986 
17987 /** gets array with implication bounds b of implications  y <= b or y >= b for x == 0 or x == 1 of given active problem
17988  *  variable x, there are no implications for nonbinary variable x
17989  */
SCIPvarGetImplBounds(SCIP_VAR * var,SCIP_Bool varfixing)17990 SCIP_Real* SCIPvarGetImplBounds(
17991    SCIP_VAR*             var,                /**< active problem variable */
17992    SCIP_Bool             varfixing           /**< FALSE for implications for x == 0, TRUE for x == 1 */
17993    )
17994 {
17995    assert(var != NULL);
17996    assert(SCIPvarIsActive(var));
17997 
17998    return SCIPimplicsGetBounds(var->implics, varfixing);
17999 }
18000 
18001 /** Gets array with unique ids of implications  y <= b or y >= b for x == 0 or x == 1 of given active problem variable x,
18002  *  there are no implications for nonbinary variable x.
18003  *  If an implication is a shortcut, i.e., it was added as part of the transitive closure of another implication,
18004  *  its id is negative, otherwise it is nonnegative.
18005  */
SCIPvarGetImplIds(SCIP_VAR * var,SCIP_Bool varfixing)18006 int* SCIPvarGetImplIds(
18007    SCIP_VAR*             var,                /**< active problem variable */
18008    SCIP_Bool             varfixing           /**< FALSE for implications for x == 0, TRUE for x == 1 */
18009    )
18010 {
18011    assert(var != NULL);
18012    assert(SCIPvarIsActive(var));
18013 
18014    return SCIPimplicsGetIds(var->implics, varfixing);
18015 }
18016 
18017 /** gets number of cliques, the active variable is contained in */
SCIPvarGetNCliques(SCIP_VAR * var,SCIP_Bool varfixing)18018 int SCIPvarGetNCliques(
18019    SCIP_VAR*             var,                /**< active problem variable */
18020    SCIP_Bool             varfixing           /**< FALSE for cliques containing x == 0, TRUE for x == 1 */
18021    )
18022 {
18023    assert(var != NULL);
18024 
18025    return SCIPcliquelistGetNCliques(var->cliquelist, varfixing);
18026 }
18027 
18028 /** gets array of cliques, the active variable is contained in */
SCIPvarGetCliques(SCIP_VAR * var,SCIP_Bool varfixing)18029 SCIP_CLIQUE** SCIPvarGetCliques(
18030    SCIP_VAR*             var,                /**< active problem variable */
18031    SCIP_Bool             varfixing           /**< FALSE for cliques containing x == 0, TRUE for x == 1 */
18032    )
18033 {
18034    assert(var != NULL);
18035 
18036    return SCIPcliquelistGetCliques(var->cliquelist, varfixing);
18037 }
18038 
18039 /** gets primal LP solution value of variable */
SCIPvarGetLPSol(SCIP_VAR * var)18040 SCIP_Real SCIPvarGetLPSol(
18041    SCIP_VAR*             var                 /**< problem variable */
18042    )
18043 {
18044    assert(var != NULL);
18045 
18046    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
18047       return SCIPcolGetPrimsol(var->data.col);
18048    else
18049       return SCIPvarGetLPSol_rec(var);
18050 }
18051 
18052 /** gets primal NLP solution value of variable */
SCIPvarGetNLPSol(SCIP_VAR * var)18053 SCIP_Real SCIPvarGetNLPSol(
18054    SCIP_VAR*             var                 /**< problem variable */
18055    )
18056 {
18057    assert(var != NULL);
18058 
18059    if( (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE) )
18060       return var->nlpsol;
18061    else
18062       return SCIPvarGetNLPSol_rec(var);
18063 }
18064 
18065 /** return lower bound change info at requested position */
SCIPvarGetBdchgInfoLb(SCIP_VAR * var,int pos)18066 SCIP_BDCHGINFO* SCIPvarGetBdchgInfoLb(
18067    SCIP_VAR*             var,                /**< problem variable */
18068    int                   pos                 /**< requested position */
18069    )
18070 {
18071    assert(pos >= 0);
18072    assert(pos < var->nlbchginfos);
18073 
18074    return &var->lbchginfos[pos];
18075 }
18076 
18077 /** gets the number of lower bound change info array */
SCIPvarGetNBdchgInfosLb(SCIP_VAR * var)18078 int SCIPvarGetNBdchgInfosLb(
18079    SCIP_VAR*             var                 /**< problem variable */
18080    )
18081 {
18082    return var->nlbchginfos;
18083 }
18084 
18085 /** return upper bound change info at requested position */
SCIPvarGetBdchgInfoUb(SCIP_VAR * var,int pos)18086 SCIP_BDCHGINFO* SCIPvarGetBdchgInfoUb(
18087    SCIP_VAR*             var,                /**< problem variable */
18088    int                   pos                 /**< requested position */
18089    )
18090 {
18091    assert(pos >= 0);
18092    assert(pos < var->nubchginfos);
18093 
18094    return &var->ubchginfos[pos];
18095 }
18096 
18097 /** gets the number upper bound change info array */
SCIPvarGetNBdchgInfosUb(SCIP_VAR * var)18098 int SCIPvarGetNBdchgInfosUb(
18099    SCIP_VAR*             var                 /**< problem variable */
18100    )
18101 {
18102    assert(var != NULL);
18103 
18104    return var->nubchginfos;
18105 }
18106 
18107 /** returns the value based history for the variable */
SCIPvarGetValuehistory(SCIP_VAR * var)18108 SCIP_VALUEHISTORY* SCIPvarGetValuehistory(
18109    SCIP_VAR*             var                 /**< problem variable */
18110    )
18111 {
18112    assert(var != NULL);
18113 
18114    return var->valuehistory;
18115 }
18116 
18117 /** gets pseudo solution value of variable */
SCIPvarGetPseudoSol(SCIP_VAR * var)18118 SCIP_Real SCIPvarGetPseudoSol(
18119    SCIP_VAR*             var                 /**< problem variable */
18120    )
18121 {
18122    assert(var != NULL);
18123 
18124    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
18125       return SCIPvarGetBestBoundLocal(var);
18126    else
18127       return SCIPvarGetPseudoSol_rec(var);
18128 }
18129 
18130 /** returns the variable's VSIDS score */
SCIPvarGetVSIDS(SCIP_VAR * var,SCIP_STAT * stat,SCIP_BRANCHDIR dir)18131 SCIP_Real SCIPvarGetVSIDS(
18132    SCIP_VAR*             var,                /**< problem variable */
18133    SCIP_STAT*            stat,               /**< problem statistics */
18134    SCIP_BRANCHDIR        dir                 /**< branching direction (downwards, or upwards) */
18135    )
18136 {
18137    assert(var != NULL);
18138 
18139    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
18140       return SCIPhistoryGetVSIDS(var->history, dir)/stat->vsidsweight;
18141    else
18142       return SCIPvarGetVSIDS_rec(var, stat, dir);
18143 }
18144 
18145 /** includes event handler with given data in variable's event filter */
SCIPvarCatchEvent(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTTYPE eventtype,SCIP_EVENTHDLR * eventhdlr,SCIP_EVENTDATA * eventdata,int * filterpos)18146 SCIP_RETCODE SCIPvarCatchEvent(
18147    SCIP_VAR*             var,                /**< problem variable */
18148    BMS_BLKMEM*           blkmem,             /**< block memory */
18149    SCIP_SET*             set,                /**< global SCIP settings */
18150    SCIP_EVENTTYPE        eventtype,          /**< event type to catch */
18151    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
18152    SCIP_EVENTDATA*       eventdata,          /**< event data to pass to the event handler for the event processing */
18153    int*                  filterpos           /**< pointer to store position of event filter entry, or NULL */
18154    )
18155 {
18156    assert(var != NULL);
18157    assert(set != NULL);
18158    assert(var->scip == set->scip);
18159    assert(var->eventfilter != NULL);
18160    assert((eventtype & ~SCIP_EVENTTYPE_VARCHANGED) == 0);
18161    assert((eventtype & SCIP_EVENTTYPE_VARCHANGED) != 0);
18162    assert(SCIPvarIsTransformed(var));
18163 
18164    SCIPsetDebugMsg(set, "catch event of type 0x%" SCIP_EVENTTYPE_FORMAT " of variable <%s> with handler %p and data %p\n",
18165       eventtype, var->name, (void*)eventhdlr, (void*)eventdata);
18166 
18167    SCIP_CALL( SCIPeventfilterAdd(var->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) );
18168 
18169    return SCIP_OKAY;
18170 }
18171 
18172 /** deletes event handler with given data from variable's event filter */
SCIPvarDropEvent(SCIP_VAR * var,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTTYPE eventtype,SCIP_EVENTHDLR * eventhdlr,SCIP_EVENTDATA * eventdata,int filterpos)18173 SCIP_RETCODE SCIPvarDropEvent(
18174    SCIP_VAR*             var,                /**< problem variable */
18175    BMS_BLKMEM*           blkmem,             /**< block memory */
18176    SCIP_SET*             set,                /**< global SCIP settings */
18177    SCIP_EVENTTYPE        eventtype,          /**< event type mask of dropped event */
18178    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
18179    SCIP_EVENTDATA*       eventdata,          /**< event data to pass to the event handler for the event processing */
18180    int                   filterpos           /**< position of event filter entry returned by SCIPvarCatchEvent(), or -1 */
18181    )
18182 {
18183    assert(var != NULL);
18184    assert(set != NULL);
18185    assert(var->scip == set->scip);
18186    assert(var->eventfilter != NULL);
18187    assert(SCIPvarIsTransformed(var));
18188 
18189    SCIPsetDebugMsg(set, "drop event of variable <%s> with handler %p and data %p\n", var->name, (void*)eventhdlr,
18190          (void*)eventdata);
18191 
18192    SCIP_CALL( SCIPeventfilterDel(var->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) );
18193 
18194    return SCIP_OKAY;
18195 }
18196 
18197 /** returns the position of the bound change index */
SCIPbdchgidxGetPos(SCIP_BDCHGIDX * bdchgidx)18198 int SCIPbdchgidxGetPos(
18199    SCIP_BDCHGIDX*        bdchgidx            /**< bound change index */
18200    )
18201 {
18202    assert(bdchgidx != NULL);
18203 
18204    return bdchgidx->pos;
18205 }
18206 
18207 /** returns whether first bound change index belongs to an earlier applied bound change than second one */
SCIPbdchgidxIsEarlierNonNull(SCIP_BDCHGIDX * bdchgidx1,SCIP_BDCHGIDX * bdchgidx2)18208 SCIP_Bool SCIPbdchgidxIsEarlierNonNull(
18209    SCIP_BDCHGIDX*        bdchgidx1,          /**< first bound change index */
18210    SCIP_BDCHGIDX*        bdchgidx2           /**< second bound change index */
18211    )
18212 {
18213    assert(bdchgidx1 != NULL);
18214    assert(bdchgidx1->depth >= -2);
18215    assert(bdchgidx1->pos >= 0);
18216    assert(bdchgidx2 != NULL);
18217    assert(bdchgidx2->depth >= -2);
18218    assert(bdchgidx2->pos >= 0);
18219 
18220    return (bdchgidx1->depth < bdchgidx2->depth)
18221       || (bdchgidx1->depth == bdchgidx2->depth && (bdchgidx1->pos < bdchgidx2->pos));
18222 }
18223 
18224 /** returns whether first bound change index belongs to an earlier applied bound change than second one;
18225  *  if a bound change index is NULL, the bound change index represents the current time, i.e. the time after the
18226  *  last bound change was applied to the current node
18227  */
SCIPbdchgidxIsEarlier(SCIP_BDCHGIDX * bdchgidx1,SCIP_BDCHGIDX * bdchgidx2)18228 SCIP_Bool SCIPbdchgidxIsEarlier(
18229    SCIP_BDCHGIDX*        bdchgidx1,          /**< first bound change index, or NULL */
18230    SCIP_BDCHGIDX*        bdchgidx2           /**< second bound change index, or NULL */
18231    )
18232 {
18233    assert(bdchgidx1 == NULL || bdchgidx1->depth >= -2);
18234    assert(bdchgidx1 == NULL || bdchgidx1->pos >= 0);
18235    assert(bdchgidx2 == NULL || bdchgidx2->depth >= -2);
18236    assert(bdchgidx2 == NULL || bdchgidx2->pos >= 0);
18237 
18238    if( bdchgidx1 == NULL )
18239       return FALSE;
18240    else if( bdchgidx2 == NULL )
18241       return TRUE;
18242    else
18243       return (bdchgidx1->depth < bdchgidx2->depth)
18244          || (bdchgidx1->depth == bdchgidx2->depth && (bdchgidx1->pos < bdchgidx2->pos));
18245 }
18246 
18247 /** returns old bound that was overwritten for given bound change information */
SCIPbdchginfoGetOldbound(SCIP_BDCHGINFO * bdchginfo)18248 SCIP_Real SCIPbdchginfoGetOldbound(
18249    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18250    )
18251 {
18252    assert(bdchginfo != NULL);
18253 
18254    return bdchginfo->oldbound;
18255 }
18256 
18257 /** returns new bound installed for given bound change information */
SCIPbdchginfoGetNewbound(SCIP_BDCHGINFO * bdchginfo)18258 SCIP_Real SCIPbdchginfoGetNewbound(
18259    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18260    )
18261 {
18262    assert(bdchginfo != NULL);
18263 
18264    return bdchginfo->newbound;
18265 }
18266 
18267 /** returns variable that belongs to the given bound change information */
SCIPbdchginfoGetVar(SCIP_BDCHGINFO * bdchginfo)18268 SCIP_VAR* SCIPbdchginfoGetVar(
18269    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18270    )
18271 {
18272    assert(bdchginfo != NULL);
18273 
18274    return bdchginfo->var;
18275 }
18276 
18277 /** returns whether the bound change information belongs to a branching decision or a deduction */
SCIPbdchginfoGetChgtype(SCIP_BDCHGINFO * bdchginfo)18278 SCIP_BOUNDCHGTYPE SCIPbdchginfoGetChgtype(
18279    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18280    )
18281 {
18282    assert(bdchginfo != NULL);
18283 
18284    return (SCIP_BOUNDCHGTYPE)(bdchginfo->boundchgtype);
18285 }
18286 
18287 /** returns whether the bound change information belongs to a lower or upper bound change */
SCIPbdchginfoGetBoundtype(SCIP_BDCHGINFO * bdchginfo)18288 SCIP_BOUNDTYPE SCIPbdchginfoGetBoundtype(
18289    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18290    )
18291 {
18292    assert(bdchginfo != NULL);
18293 
18294    return (SCIP_BOUNDTYPE)(bdchginfo->boundtype);
18295 }
18296 
18297 /** returns depth level of given bound change information */
SCIPbdchginfoGetDepth(SCIP_BDCHGINFO * bdchginfo)18298 int SCIPbdchginfoGetDepth(
18299    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18300    )
18301 {
18302    assert(bdchginfo != NULL);
18303 
18304    return bdchginfo->bdchgidx.depth;
18305 }
18306 
18307 /** returns bound change position in its depth level of given bound change information */
SCIPbdchginfoGetPos(SCIP_BDCHGINFO * bdchginfo)18308 int SCIPbdchginfoGetPos(
18309    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18310    )
18311 {
18312    assert(bdchginfo != NULL);
18313 
18314    return bdchginfo->bdchgidx.pos;
18315 }
18316 
18317 /** returns bound change index of given bound change information */
SCIPbdchginfoGetIdx(SCIP_BDCHGINFO * bdchginfo)18318 SCIP_BDCHGIDX* SCIPbdchginfoGetIdx(
18319    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18320    )
18321 {
18322    assert(bdchginfo != NULL);
18323 
18324    return &bdchginfo->bdchgidx;
18325 }
18326 
18327 /** returns inference variable of given bound change information */
SCIPbdchginfoGetInferVar(SCIP_BDCHGINFO * bdchginfo)18328 SCIP_VAR* SCIPbdchginfoGetInferVar(
18329    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18330    )
18331 {
18332    assert(bdchginfo != NULL);
18333    assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER
18334       || (SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER);
18335 
18336    return bdchginfo->inferencedata.var;
18337 }
18338 
18339 /** returns inference constraint of given bound change information */
SCIPbdchginfoGetInferCons(SCIP_BDCHGINFO * bdchginfo)18340 SCIP_CONS* SCIPbdchginfoGetInferCons(
18341    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18342    )
18343 {
18344    assert(bdchginfo != NULL);
18345    assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER);
18346    assert(bdchginfo->inferencedata.reason.cons != NULL);
18347 
18348    return bdchginfo->inferencedata.reason.cons;
18349 }
18350 
18351 /** returns inference propagator of given bound change information, or NULL if no propagator was responsible */
SCIPbdchginfoGetInferProp(SCIP_BDCHGINFO * bdchginfo)18352 SCIP_PROP* SCIPbdchginfoGetInferProp(
18353    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18354    )
18355 {
18356    assert(bdchginfo != NULL);
18357    assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER);
18358 
18359    return bdchginfo->inferencedata.reason.prop;
18360 }
18361 
18362 /** returns inference user information of given bound change information */
SCIPbdchginfoGetInferInfo(SCIP_BDCHGINFO * bdchginfo)18363 int SCIPbdchginfoGetInferInfo(
18364    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18365    )
18366 {
18367    assert(bdchginfo != NULL);
18368    assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER
18369       || (SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER);
18370 
18371    return bdchginfo->inferencedata.info;
18372 }
18373 
18374 /** returns inference bound of inference variable of given bound change information */
SCIPbdchginfoGetInferBoundtype(SCIP_BDCHGINFO * bdchginfo)18375 SCIP_BOUNDTYPE SCIPbdchginfoGetInferBoundtype(
18376    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18377    )
18378 {
18379    assert(bdchginfo != NULL);
18380    assert((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER
18381       || (SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER);
18382 
18383    return (SCIP_BOUNDTYPE)(bdchginfo->inferboundtype);
18384 }
18385 
18386 /** returns the relaxed bound change type */
SCIPbdchginfoGetRelaxedBound(SCIP_BDCHGINFO * bdchginfo)18387 SCIP_Real SCIPbdchginfoGetRelaxedBound(
18388    SCIP_BDCHGINFO*       bdchginfo           /**< bound change to add to the conflict set */
18389    )
18390 {
18391    return ((SCIP_BOUNDTYPE)(bdchginfo->boundtype) == SCIP_BOUNDTYPE_LOWER ? bdchginfo->var->conflictrelaxedlb : bdchginfo->var->conflictrelaxedub);
18392 }
18393 
18394 
18395 /** returns whether the bound change information belongs to a redundant bound change */
SCIPbdchginfoIsRedundant(SCIP_BDCHGINFO * bdchginfo)18396 SCIP_Bool SCIPbdchginfoIsRedundant(
18397    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18398    )
18399 {
18400    assert(bdchginfo != NULL);
18401    assert(bdchginfo->redundant == (bdchginfo->oldbound == bdchginfo->newbound)); /*lint !e777*/
18402 
18403    return bdchginfo->redundant;
18404 }
18405 
18406 /** returns whether the bound change has an inference reason (constraint or propagator), that can be resolved */
SCIPbdchginfoHasInferenceReason(SCIP_BDCHGINFO * bdchginfo)18407 SCIP_Bool SCIPbdchginfoHasInferenceReason(
18408    SCIP_BDCHGINFO*       bdchginfo           /**< bound change information */
18409    )
18410 {
18411    assert(bdchginfo != NULL);
18412 
18413    return ((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER)
18414       || ((SCIP_BOUNDCHGTYPE)bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER
18415          && bdchginfo->inferencedata.reason.prop != NULL);
18416 }
18417 
18418 /** for two bound change informations belonging to the same variable and bound, returns whether the first bound change
18419  *  has a tighter new bound as the second bound change
18420  */
SCIPbdchginfoIsTighter(SCIP_BDCHGINFO * bdchginfo1,SCIP_BDCHGINFO * bdchginfo2)18421 SCIP_Bool SCIPbdchginfoIsTighter(
18422    SCIP_BDCHGINFO*       bdchginfo1,         /**< first bound change information */
18423    SCIP_BDCHGINFO*       bdchginfo2          /**< second bound change information */
18424    )
18425 {
18426    assert(bdchginfo1 != NULL);
18427    assert(bdchginfo2 != NULL);
18428    assert(bdchginfo1->var == bdchginfo2->var);
18429    assert(bdchginfo1->boundtype == bdchginfo2->boundtype);
18430 
18431    return (SCIPbdchginfoGetBoundtype(bdchginfo1) == SCIP_BOUNDTYPE_LOWER
18432       ? bdchginfo1->newbound > bdchginfo2->newbound
18433       : bdchginfo1->newbound < bdchginfo2->newbound);
18434 }
18435