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   sol.c
17  * @ingroup OTHER_CFILES
18  * @brief  methods for storing primal CIP solutions
19  * @author Tobias Achterberg
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include "scip/clock.h"
25 #include "scip/cons.h"
26 #include "scip/lp.h"
27 #include "scip/misc.h"
28 #include "scip/nlp.h"
29 #include "scip/primal.h"
30 #include "scip/prob.h"
31 #include "scip/pub_lp.h"
32 #include "scip/pub_message.h"
33 #include "scip/pub_sol.h"
34 #include "scip/pub_var.h"
35 #include "scip/relax.h"
36 #include "scip/set.h"
37 #include "scip/sol.h"
38 #include "scip/stat.h"
39 #include "scip/struct_lp.h"
40 #include "scip/struct_prob.h"
41 #include "scip/struct_set.h"
42 #include "scip/struct_sol.h"
43 #include "scip/struct_stat.h"
44 #include "scip/struct_var.h"
45 #include "scip/tree.h"
46 #include "scip/var.h"
47 
48 
49 
50 /** clears solution arrays of primal CIP solution */
51 static
solClearArrays(SCIP_SOL * sol)52 SCIP_RETCODE solClearArrays(
53    SCIP_SOL*             sol                 /**< primal CIP solution */
54    )
55 {
56    assert(sol != NULL);
57 
58    SCIP_CALL( SCIPboolarrayClear(sol->valid) );
59    sol->hasinfval = FALSE;
60 
61    return SCIP_OKAY;
62 }
63 
64 /** sets value of variable in the solution's array */
65 static
solSetArrayVal(SCIP_SOL * sol,SCIP_SET * set,SCIP_VAR * var,SCIP_Real val)66 SCIP_RETCODE solSetArrayVal(
67    SCIP_SOL*             sol,                /**< primal CIP solution */
68    SCIP_SET*             set,                /**< global SCIP settings */
69    SCIP_VAR*             var,                /**< problem variable */
70    SCIP_Real             val                 /**< value to set variable to */
71    )
72 {
73    int idx;
74 
75    assert(sol != NULL);
76 
77    idx = SCIPvarGetIndex(var);
78 
79    /* from now on, variable must not be deleted */
80    SCIPvarMarkNotDeletable(var);
81 
82    /* mark the variable valid */
83    SCIP_CALL( SCIPboolarraySetVal(sol->valid, set->mem_arraygrowinit, set->mem_arraygrowfac, idx, TRUE) );
84 
85    /* set the value in the solution array */
86    SCIP_CALL( SCIPrealarraySetVal(sol->vals, set->mem_arraygrowinit, set->mem_arraygrowfac, idx, val) );
87 
88    /* store whether the solution has infinite values assigned to variables */
89    if( val != SCIP_UNKNOWN ) /*lint !e777*/
90       sol->hasinfval = (sol->hasinfval || SCIPsetIsInfinity(set, val) || SCIPsetIsInfinity(set, -val));
91 
92    return SCIP_OKAY;
93 }
94 
95 /** increases value of variable in the solution's array */
96 static
solIncArrayVal(SCIP_SOL * sol,SCIP_SET * set,SCIP_VAR * var,SCIP_Real incval)97 SCIP_RETCODE solIncArrayVal(
98    SCIP_SOL*             sol,                /**< primal CIP solution */
99    SCIP_SET*             set,                /**< global SCIP settings */
100    SCIP_VAR*             var,                /**< problem variable */
101    SCIP_Real             incval              /**< increase of variable's solution value */
102    )
103 {
104    int idx;
105 
106    assert(sol != NULL);
107 
108    idx = SCIPvarGetIndex(var);
109 
110    /* from now on, variable must not be deleted */
111    SCIPvarMarkNotDeletable(var);
112 
113    /* if the variable was not valid, mark it to be valid and set the value to the incval (it is 0.0 if not valid) */
114    if( !SCIPboolarrayGetVal(sol->valid, idx) )
115    {
116       /* mark the variable valid */
117       SCIP_CALL( SCIPboolarraySetVal(sol->valid, set->mem_arraygrowinit, set->mem_arraygrowfac, idx, TRUE) );
118 
119       /* set the value in the solution array */
120       SCIP_CALL( SCIPrealarraySetVal(sol->vals, set->mem_arraygrowinit, set->mem_arraygrowfac, idx, incval) );
121    }
122    else
123    {
124       /* increase the value in the solution array */
125       SCIP_CALL( SCIPrealarrayIncVal(sol->vals, set->mem_arraygrowinit, set->mem_arraygrowfac, idx, incval) );
126    }
127 
128    /* store whether the solution has infinite values assigned to variables */
129    incval = SCIPrealarrayGetVal(sol->vals, idx);
130    if( incval != SCIP_UNKNOWN ) /*lint !e777*/
131       sol->hasinfval = (sol->hasinfval || SCIPsetIsInfinity(set, incval) || SCIPsetIsInfinity(set, -incval));
132 
133    return SCIP_OKAY;
134 }
135 
136 /** returns the value of the variable in the given solution */
137 static
solGetArrayVal(SCIP_SOL * sol,SCIP_VAR * var)138 SCIP_Real solGetArrayVal(
139    SCIP_SOL*             sol,                /**< primal CIP solution */
140    SCIP_VAR*             var                 /**< problem variable */
141    )
142 {
143    int idx;
144 
145    assert(sol != NULL);
146 
147    idx = SCIPvarGetIndex(var);
148 
149    /* check, if the variable's value is valid */
150    if( SCIPboolarrayGetVal(sol->valid, idx) )
151    {
152       return SCIPrealarrayGetVal(sol->vals, idx);
153    }
154    else
155    {
156       /* return the variable's value corresponding to the origin */
157       switch( sol->solorigin )
158       {
159       case SCIP_SOLORIGIN_ORIGINAL:
160       case SCIP_SOLORIGIN_ZERO:
161          return 0.0;
162 
163       case SCIP_SOLORIGIN_LPSOL:
164          return SCIPvarGetLPSol(var);
165 
166       case SCIP_SOLORIGIN_NLPSOL:
167          return SCIPvarGetNLPSol(var);
168 
169       case SCIP_SOLORIGIN_RELAXSOL:
170          return SCIPvarGetRelaxSolTransVar(var);
171 
172       case SCIP_SOLORIGIN_PSEUDOSOL:
173          return SCIPvarGetPseudoSol(var);
174 
175       case SCIP_SOLORIGIN_PARTIAL:
176       case SCIP_SOLORIGIN_UNKNOWN:
177          return SCIP_UNKNOWN;
178 
179       default:
180          SCIPerrorMessage("unknown solution origin <%d>\n", sol->solorigin);
181          SCIPABORT();
182          return 0.0; /*lint !e527*/
183       }
184    }
185 }
186 
187 /** stores solution value of variable in solution's own array */
188 static
solUnlinkVar(SCIP_SOL * sol,SCIP_SET * set,SCIP_VAR * var)189 SCIP_RETCODE solUnlinkVar(
190    SCIP_SOL*             sol,                /**< primal CIP solution */
191    SCIP_SET*             set,                /**< global SCIP settings */
192    SCIP_VAR*             var                 /**< problem variable */
193    )
194 {
195    SCIP_Real solval;
196 
197    assert(sol != NULL);
198    assert(var != NULL);
199    assert(SCIPvarIsTransformed(var));
200    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
201 
202    /* if variable is already valid, nothing has to be done */
203    if( SCIPboolarrayGetVal(sol->valid, SCIPvarGetIndex(var)) )
204       return SCIP_OKAY;
205 
206    SCIPsetDebugMsg(set, "unlinking solution value of variable <%s>\n", SCIPvarGetName(var));
207 
208    /* store the correct solution value into the solution array */
209    switch( sol->solorigin )
210    {
211    case SCIP_SOLORIGIN_ORIGINAL:
212       SCIPerrorMessage("cannot unlink solutions of original problem space\n");
213       return SCIP_INVALIDDATA;
214 
215    case SCIP_SOLORIGIN_ZERO:
216       return SCIP_OKAY;
217 
218    case SCIP_SOLORIGIN_LPSOL:
219       solval = SCIPvarGetLPSol(var);
220       SCIP_CALL( solSetArrayVal(sol, set, var, solval) );
221       return SCIP_OKAY;
222 
223    case SCIP_SOLORIGIN_NLPSOL:
224       solval = SCIPvarGetNLPSol(var);
225       SCIP_CALL( solSetArrayVal(sol, set, var, solval) );
226       return SCIP_OKAY;
227 
228    case SCIP_SOLORIGIN_RELAXSOL:
229       solval = SCIPvarGetRelaxSolTransVar(var);
230       SCIP_CALL( solSetArrayVal(sol, set, var, solval) );
231       return SCIP_OKAY;
232 
233    case SCIP_SOLORIGIN_PSEUDOSOL:
234       solval = SCIPvarGetPseudoSol(var);
235       SCIP_CALL( solSetArrayVal(sol, set, var, solval) );
236       return SCIP_OKAY;
237 
238    case SCIP_SOLORIGIN_PARTIAL:
239    case SCIP_SOLORIGIN_UNKNOWN:
240       SCIP_CALL( solSetArrayVal(sol, set, var, SCIP_UNKNOWN) );
241       return SCIP_OKAY;
242 
243    default:
244       SCIPerrorMessage("unknown solution origin <%d>\n", sol->solorigin);
245       return SCIP_INVALIDDATA;
246    }
247 }
248 
249 /** sets the solution time, nodenum, runnum, and depth stamp to the current values */
250 static
solStamp(SCIP_SOL * sol,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_Bool checktime)251 void solStamp(
252    SCIP_SOL*             sol,                /**< primal CIP solution */
253    SCIP_STAT*            stat,               /**< problem statistics data */
254    SCIP_TREE*            tree,               /**< branch and bound tree, or NULL */
255    SCIP_Bool             checktime           /**< should the time be updated? */
256    )
257 {
258    assert(sol != NULL);
259    assert(stat != NULL);
260 
261    if( checktime )
262    {
263       sol->time = SCIPclockGetTime(stat->solvingtime);
264 #ifndef NDEBUG
265       sol->lpcount = stat->lpcount;
266 #endif
267    }
268    else
269       sol->time = SCIPclockGetLastTime(stat->solvingtime);
270    sol->nodenum = stat->nnodes;
271    sol->runnum = stat->nruns;
272    if( tree == NULL )
273       sol->depth = -1;
274    else
275       sol->depth = SCIPtreeGetCurrentDepth(tree);
276 }
277 
278 /** creates primal CIP solution, initialized to zero */
SCIPsolCreate(SCIP_SOL ** sol,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_HEUR * heur)279 SCIP_RETCODE SCIPsolCreate(
280    SCIP_SOL**            sol,                /**< pointer to primal CIP solution */
281    BMS_BLKMEM*           blkmem,             /**< block memory */
282    SCIP_SET*             set,                /**< global SCIP settings */
283    SCIP_STAT*            stat,               /**< problem statistics data */
284    SCIP_PRIMAL*          primal,             /**< primal data */
285    SCIP_TREE*            tree,               /**< branch and bound tree */
286    SCIP_HEUR*            heur                /**< heuristic that found the solution (or NULL if it's from the tree) */
287    )
288 {
289    assert(sol != NULL);
290    assert(blkmem != NULL);
291    assert(stat != NULL);
292 
293    SCIP_ALLOC( BMSallocBlockMemory(blkmem, sol) );
294    SCIP_CALL( SCIPrealarrayCreate(&(*sol)->vals, blkmem) );
295    SCIP_CALL( SCIPboolarrayCreate(&(*sol)->valid, blkmem) );
296 
297    (*sol)->solorigin = SCIP_SOLORIGIN_ZERO;
298    (*sol)->obj = 0.0;
299    (*sol)->primalindex = -1;
300    (*sol)->index = stat->solindex;
301    (*sol)->hasinfval = FALSE;
302    SCIPsolResetViolations(*sol);
303    stat->solindex++;
304    solStamp(*sol, stat, tree, TRUE);
305    SCIPsolResetViolations(*sol);
306 
307    /* set solution type and creator depending on whether a heuristic or NULL is passed */
308    SCIPsolSetHeur(*sol, heur);
309 
310    SCIP_CALL( SCIPprimalSolCreated(primal, set, *sol) );
311 
312    return SCIP_OKAY;
313 }
314 
315 /** creates primal CIP solution in original problem space, initialized to the offset in the original problem */
SCIPsolCreateOriginal(SCIP_SOL ** sol,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * origprob,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_HEUR * heur)316 SCIP_RETCODE SCIPsolCreateOriginal(
317    SCIP_SOL**            sol,                /**< pointer to primal CIP solution */
318    BMS_BLKMEM*           blkmem,             /**< block memory */
319    SCIP_SET*             set,                /**< global SCIP settings */
320    SCIP_STAT*            stat,               /**< problem statistics data */
321    SCIP_PROB*            origprob,           /**< original problem data */
322    SCIP_PRIMAL*          primal,             /**< primal data */
323    SCIP_TREE*            tree,               /**< branch and bound tree */
324    SCIP_HEUR*            heur                /**< heuristic that found the solution (or NULL if it's from the tree) */
325    )
326 {
327    assert(sol != NULL);
328    assert(blkmem != NULL);
329    assert(stat != NULL);
330 
331    SCIP_ALLOC( BMSallocBlockMemory(blkmem, sol) );
332    SCIP_CALL( SCIPrealarrayCreate(&(*sol)->vals, blkmem) );
333    SCIP_CALL( SCIPboolarrayCreate(&(*sol)->valid, blkmem) );
334    (*sol)->solorigin = SCIP_SOLORIGIN_ORIGINAL;
335    (*sol)->obj = origprob->objoffset;
336    (*sol)->primalindex = -1;
337    (*sol)->index = stat->solindex;
338    (*sol)->hasinfval = FALSE;
339    stat->solindex++;
340    solStamp(*sol, stat, tree, TRUE);
341 
342    /* set solution type and creator depending on whether a heuristic or NULL is passed */
343    SCIPsolSetHeur(*sol, heur);
344 
345    SCIPsolResetViolations(*sol);
346 
347    SCIP_CALL( SCIPprimalSolCreated(primal, set, *sol) );
348 
349    return SCIP_OKAY;
350 }
351 
352 /** creates a copy of a primal CIP solution */
SCIPsolCopy(SCIP_SOL ** sol,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PRIMAL * primal,SCIP_SOL * sourcesol)353 SCIP_RETCODE SCIPsolCopy(
354    SCIP_SOL**            sol,                /**< pointer to store the copy of the primal CIP solution */
355    BMS_BLKMEM*           blkmem,             /**< block memory */
356    SCIP_SET*             set,                /**< global SCIP settings */
357    SCIP_STAT*            stat,               /**< problem statistics data */
358    SCIP_PRIMAL*          primal,             /**< primal data */
359    SCIP_SOL*             sourcesol           /**< primal CIP solution to copy */
360    )
361 {
362    assert(sol != NULL);
363    assert(sourcesol != NULL);
364 
365    SCIP_ALLOC( BMSallocBlockMemory(blkmem, sol) );
366    SCIP_CALL( SCIPrealarrayCopy(&(*sol)->vals, blkmem, sourcesol->vals) );
367    SCIP_CALL( SCIPboolarrayCopy(&(*sol)->valid, blkmem, sourcesol->valid) );
368 
369    /* copy solution type and creator information */
370    switch( sourcesol->type )
371    {
372    case SCIP_SOLTYPE_UNKNOWN:
373    case SCIP_SOLTYPE_LPRELAX:
374    case SCIP_SOLTYPE_STRONGBRANCH:
375    case SCIP_SOLTYPE_PSEUDO:
376       (*sol)->type = sourcesol->type;
377       break;
378    case SCIP_SOLTYPE_HEUR:
379       SCIPsolSetHeur((*sol), SCIPsolGetHeur(sourcesol));
380       break;
381    case SCIP_SOLTYPE_RELAX:
382       SCIPsolSetRelax((*sol), SCIPsolGetRelax(sourcesol));
383       break;
384    default:
385       SCIPerrorMessage("Unknown source solution type %d!\n", sourcesol->type);
386       return SCIP_INVALIDDATA;
387    }
388    (*sol)->obj = sourcesol->obj;
389    (*sol)->primalindex = -1;
390    (*sol)->time = sourcesol->time;
391 #ifndef NDEBUG
392    (*sol)->lpcount = sourcesol->lpcount;
393 #endif
394    (*sol)->nodenum = sourcesol->nodenum;
395    (*sol)->solorigin = sourcesol->solorigin;
396    (*sol)->runnum = sourcesol->runnum;
397    (*sol)->depth = sourcesol->depth;
398    (*sol)->index = stat->solindex;
399    (*sol)->hasinfval = sourcesol->hasinfval;
400    stat->solindex++;
401    (*sol)->viol.absviolbounds = sourcesol->viol.absviolbounds;
402    (*sol)->viol.absviolcons = sourcesol->viol.absviolcons;
403    (*sol)->viol.absviolintegrality = sourcesol->viol.absviolintegrality;
404    (*sol)->viol.absviollprows = sourcesol->viol.absviollprows;
405    (*sol)->viol.relviolbounds = sourcesol->viol.relviolbounds;
406    (*sol)->viol.relviolcons = sourcesol->viol.relviolcons;
407    (*sol)->viol.relviollprows = sourcesol->viol.relviollprows;
408 
409    SCIP_CALL( SCIPprimalSolCreated(primal, set, *sol) );
410 
411    return SCIP_OKAY;
412 }
413 
414 /** transformes given original solution to the transformed space; a corresponding transformed solution has to be given
415  *  which is copied into the existing solution and freed afterwards
416  */
SCIPsolTransform(SCIP_SOL * sol,SCIP_SOL ** transsol,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_PRIMAL * primal)417 SCIP_RETCODE SCIPsolTransform(
418    SCIP_SOL*             sol,                /**< primal CIP solution to change, living in original space */
419    SCIP_SOL**            transsol,           /**< pointer to corresponding transformed primal CIP solution */
420    BMS_BLKMEM*           blkmem,             /**< block memory */
421    SCIP_SET*             set,                /**< global SCIP settings */
422    SCIP_PRIMAL*          primal              /**< primal data */
423    )
424 {  /*lint --e{715}*/
425    SCIP_REALARRAY* tmpvals;
426    SCIP_BOOLARRAY* tmpvalid;
427    SCIP_SOL* tsol;
428 
429    assert(sol != NULL);
430    assert(transsol != NULL);
431    assert(set != NULL);
432    assert(SCIPsolIsOriginal(sol));
433    assert(sol->primalindex > -1);
434 
435    tsol = *transsol;
436    assert(tsol != NULL);
437    assert(!SCIPsolIsOriginal(tsol));
438 
439    /* switch vals and valid arrays; the exisiting solution gets the arrays of the transformed solution;
440     * the transformed one gets the original arrays, because they have to be freed anyway and freeing the transsol
441     * automatically frees its arrays
442     */
443    tmpvals = sol->vals;
444    tmpvalid = sol->valid;
445    sol->vals = tsol->vals;
446    sol->valid = tsol->valid;
447    tsol->vals = tmpvals;
448    tsol->valid = tmpvalid;
449 
450    /* copy solorigin and objective (should be the same, only to avoid numerical issues);
451     * we keep the other statistics of the original solution, since that was the first time that this solution as found
452     */
453    sol->solorigin = tsol->solorigin;
454    sol->obj = tsol->obj;
455 
456    SCIP_CALL( SCIPsolFree(transsol, blkmem, primal) );
457 
458    return SCIP_OKAY;
459 }
460 
461 /** adjusts solution values of implicit integer variables in handed solution. Solution objective value is not
462  *  deteriorated by this method.
463  */
SCIPsolAdjustImplicitSolVals(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_TREE * tree,SCIP_Bool uselprows)464 SCIP_RETCODE SCIPsolAdjustImplicitSolVals(
465    SCIP_SOL*             sol,                /**< primal CIP solution */
466    SCIP_SET*             set,                /**< global SCIP settings */
467    SCIP_STAT*            stat,               /**< problem statistics data */
468    SCIP_PROB*            prob,               /**< either original or transformed problem, depending on sol origin */
469    SCIP_TREE*            tree,               /**< branch and bound tree */
470    SCIP_Bool             uselprows           /**< should LP row information be considered for none-objective variables */
471    )
472 {
473    SCIP_VAR** vars;
474    int nimplvars;
475    int nbinvars;
476    int nintvars;
477    int v;
478 
479    assert(sol != NULL);
480    assert(prob != NULL);
481 
482    /* get variable data */
483    vars = SCIPprobGetVars(prob);
484    nbinvars = SCIPprobGetNBinVars(prob);
485    nintvars = SCIPprobGetNIntVars(prob);
486    nimplvars = SCIPprobGetNImplVars(prob);
487 
488    if( nimplvars == 0 )
489       return SCIP_OKAY;
490 
491    /* calculate the last array position of implicit integer variables */
492    nimplvars = nbinvars + nintvars + nimplvars;
493 
494    /* loop over implicit integer variables and round them up or down */
495    for( v = nbinvars + nintvars; v < nimplvars; ++v )
496    {
497       SCIP_VAR* var;
498       SCIP_Real solval;
499       SCIP_Real obj;
500       SCIP_Real newsolval;
501       SCIP_Bool roundup;
502       SCIP_Bool rounddown;
503       int nuplocks;
504       int ndownlocks;
505 
506       var = vars[v];
507 
508       assert( SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT );
509       solval = SCIPsolGetVal(sol, set, stat, var);
510 
511       /* we do not need to round integral solution values or those of variables which are not column variables */
512       if( SCIPsetIsFeasIntegral(set, solval) || SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
513          continue;
514 
515       nuplocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
516       ndownlocks = SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL);
517       obj = SCIPvarGetUnchangedObj(var);
518 
519       roundup = FALSE;
520       rounddown = FALSE;
521 
522       /* in case of a non-zero objective coefficient, there is only one possible rounding direction */
523       if( SCIPsetIsFeasNegative(set, obj) )
524          roundup = TRUE;
525       else if( SCIPsetIsFeasPositive(set, obj) )
526          rounddown = TRUE;
527       else if( uselprows )
528       {
529          /* determine rounding direction based on row violations */
530          SCIP_COL* col;
531          SCIP_ROW** rows;
532          SCIP_Real* vals;
533          int nrows;
534          int r;
535 
536          col = SCIPvarGetCol(var);
537          vals = SCIPcolGetVals(col);
538          rows = SCIPcolGetRows(col);
539          nrows = SCIPcolGetNNonz(col);
540 
541          /* loop over rows and search for equations whose violation can be decreased by rounding */
542          for( r = 0; r < nrows && !(roundup && rounddown); ++r )
543          {
544             SCIP_ROW* row;
545             SCIP_Real activity;
546             SCIP_Real rhs;
547             SCIP_Real lhs;
548 
549             row = rows[r];
550 
551             if( SCIProwIsLocal(row) || !SCIProwIsInLP(row) )
552                continue;
553 
554             rhs = SCIProwGetRhs(row);
555             lhs = SCIProwGetLhs(row);
556 
557             if( SCIPsetIsInfinity(set, rhs) || SCIPsetIsInfinity(set, -lhs) )
558                continue;
559 
560             activity = SCIProwGetSolActivity(row, set, stat, sol);
561             if( SCIPsetIsFeasLE(set, activity, rhs) && SCIPsetIsFeasLE(set, lhs, activity) )
562                continue;
563 
564             assert(! SCIPsetIsZero(set, vals[r]));
565             if( (SCIPsetIsFeasGT(set, activity, rhs) && SCIPsetIsPositive(set, vals[r]))
566                   || (SCIPsetIsFeasLT(set, activity, lhs) && SCIPsetIsNegative(set, vals[r])) )
567                rounddown = TRUE;
568             else
569                roundup = TRUE;
570          }
571       }
572 
573       /* in case of a tie, we select the rounding step based on the number of variable locks */
574       if( roundup == rounddown )
575       {
576          rounddown = ndownlocks <= nuplocks;
577          roundup = !rounddown;
578       }
579 
580       /* round the variable up or down */
581       if( roundup )
582       {
583          newsolval = SCIPsetCeil(set, solval);
584          assert(SCIPsetIsFeasLE(set, newsolval, SCIPvarGetUbGlobal(var)));
585       }
586       else
587       {
588          assert( rounddown ); /* should be true because of the code above */
589          newsolval = SCIPsetFloor(set, solval);
590          assert(SCIPsetIsFeasGE(set, newsolval, SCIPvarGetLbGlobal(var)));
591       }
592 
593       SCIP_CALL( SCIPsolSetVal(sol, set, stat, tree, var, newsolval) );
594    }
595 
596    return SCIP_OKAY;
597 }
598 /** creates primal CIP solution, initialized to the current LP solution */
SCIPsolCreateLPSol(SCIP_SOL ** sol,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_LP * lp,SCIP_HEUR * heur)599 SCIP_RETCODE SCIPsolCreateLPSol(
600    SCIP_SOL**            sol,                /**< pointer to primal CIP solution */
601    BMS_BLKMEM*           blkmem,             /**< block memory */
602    SCIP_SET*             set,                /**< global SCIP settings */
603    SCIP_STAT*            stat,               /**< problem statistics data */
604    SCIP_PROB*            prob,               /**< transformed problem data */
605    SCIP_PRIMAL*          primal,             /**< primal data */
606    SCIP_TREE*            tree,               /**< branch and bound tree */
607    SCIP_LP*              lp,                 /**< current LP data */
608    SCIP_HEUR*            heur                /**< heuristic that found the solution (or NULL if it's from the tree) */
609    )
610 {
611    assert(sol != NULL);
612    assert(lp != NULL);
613    assert(SCIPlpIsSolved(lp));
614 
615    SCIP_CALL( SCIPsolCreate(sol, blkmem, set, stat, primal, tree, heur) );
616    SCIP_CALL( SCIPsolLinkLPSol(*sol, set, stat, prob, tree, lp) );
617 
618    return SCIP_OKAY;
619 }
620 
621 /** creates primal CIP solution, initialized to the current NLP solution */
SCIPsolCreateNLPSol(SCIP_SOL ** sol,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_NLP * nlp,SCIP_HEUR * heur)622 SCIP_RETCODE SCIPsolCreateNLPSol(
623    SCIP_SOL**            sol,                /**< pointer to primal CIP solution */
624    BMS_BLKMEM*           blkmem,             /**< block memory */
625    SCIP_SET*             set,                /**< global SCIP settings */
626    SCIP_STAT*            stat,               /**< problem statistics data */
627    SCIP_PRIMAL*          primal,             /**< primal data */
628    SCIP_TREE*            tree,               /**< branch and bound tree */
629    SCIP_NLP*             nlp,                /**< current NLP data */
630    SCIP_HEUR*            heur                /**< heuristic that found the solution (or NULL if it's from the tree) */
631    )
632 {
633    assert(sol != NULL);
634    assert(nlp != NULL);
635 
636    SCIP_CALL( SCIPsolCreate(sol, blkmem, set, stat, primal, tree, heur) );
637    SCIP_CALL( SCIPsolLinkNLPSol(*sol, stat, tree, nlp) );
638 
639    return SCIP_OKAY;
640 }
641 
642 /** creates primal CIP solution, initialized to the current relaxation solution */
SCIPsolCreateRelaxSol(SCIP_SOL ** sol,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_RELAXATION * relaxation,SCIP_HEUR * heur)643 SCIP_RETCODE SCIPsolCreateRelaxSol(
644    SCIP_SOL**            sol,                /**< pointer to primal CIP solution */
645    BMS_BLKMEM*           blkmem,             /**< block memory */
646    SCIP_SET*             set,                /**< global SCIP settings */
647    SCIP_STAT*            stat,               /**< problem statistics data */
648    SCIP_PRIMAL*          primal,             /**< primal data */
649    SCIP_TREE*            tree,               /**< branch and bound tree */
650    SCIP_RELAXATION*      relaxation,         /**< global relaxation data */
651    SCIP_HEUR*            heur                /**< heuristic that found the solution (or NULL if it's from the tree) */
652    )
653 {
654    assert(sol != NULL);
655    assert(relaxation != NULL);
656    assert(SCIPrelaxationIsSolValid(relaxation));
657 
658    SCIP_CALL( SCIPsolCreate(sol, blkmem, set, stat, primal, tree, heur) );
659    SCIP_CALL( SCIPsolLinkRelaxSol(*sol, set, stat, tree, relaxation) );
660 
661    /* update solution type and store relaxator as creator only if no heuristic is specified as creator */
662    if( heur == NULL )
663       SCIPsolSetRelax(*sol, SCIPrelaxationGetSolRelax(relaxation));
664 
665    return SCIP_OKAY;
666 }
667 
668 /** creates primal CIP solution, initialized to the current pseudo solution */
SCIPsolCreatePseudoSol(SCIP_SOL ** sol,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_LP * lp,SCIP_HEUR * heur)669 SCIP_RETCODE SCIPsolCreatePseudoSol(
670    SCIP_SOL**            sol,                /**< pointer to primal CIP solution */
671    BMS_BLKMEM*           blkmem,             /**< block memory */
672    SCIP_SET*             set,                /**< global SCIP settings */
673    SCIP_STAT*            stat,               /**< problem statistics data */
674    SCIP_PROB*            prob,               /**< transformed problem data */
675    SCIP_PRIMAL*          primal,             /**< primal data */
676    SCIP_TREE*            tree,               /**< branch and bound tree, or NULL */
677    SCIP_LP*              lp,                 /**< current LP data */
678    SCIP_HEUR*            heur                /**< heuristic that found the solution (or NULL if it's from the tree) */
679    )
680 {
681    assert(sol != NULL);
682 
683    SCIP_CALL( SCIPsolCreate(sol, blkmem, set, stat, primal, tree, heur) );
684    SCIP_CALL( SCIPsolLinkPseudoSol(*sol, set, stat, prob, tree, lp) );
685 
686    /* update solution type to pseudo solution */
687    if( heur == NULL )
688       SCIPsolSetPseudo(*sol);
689 
690    return SCIP_OKAY;
691 }
692 
693 /** creates primal CIP solution, initialized to the current solution */
SCIPsolCreateCurrentSol(SCIP_SOL ** sol,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_LP * lp,SCIP_HEUR * heur)694 SCIP_RETCODE SCIPsolCreateCurrentSol(
695    SCIP_SOL**            sol,                /**< pointer to primal CIP solution */
696    BMS_BLKMEM*           blkmem,             /**< block memory */
697    SCIP_SET*             set,                /**< global SCIP settings */
698    SCIP_STAT*            stat,               /**< problem statistics data */
699    SCIP_PROB*            prob,               /**< transformed problem data */
700    SCIP_PRIMAL*          primal,             /**< primal data */
701    SCIP_TREE*            tree,               /**< branch and bound tree */
702    SCIP_LP*              lp,                 /**< current LP data */
703    SCIP_HEUR*            heur                /**< heuristic that found the solution (or NULL if it's from the tree) */
704    )
705 {
706    assert(tree != NULL);
707 
708    if( SCIPtreeHasCurrentNodeLP(tree) )
709    {
710       SCIP_CALL( SCIPsolCreateLPSol(sol, blkmem, set, stat, prob, primal, tree, lp, heur) );
711    }
712    else
713    {
714       SCIP_CALL( SCIPsolCreatePseudoSol(sol, blkmem, set, stat, prob, primal, tree, lp, heur) );
715    }
716 
717    return SCIP_OKAY;
718 }
719 
720 /** creates partial primal CIP solution, initialized to unknown values */
SCIPsolCreatePartial(SCIP_SOL ** sol,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PRIMAL * primal,SCIP_HEUR * heur)721 SCIP_RETCODE SCIPsolCreatePartial(
722    SCIP_SOL**            sol,                /**< pointer to primal CIP solution */
723    BMS_BLKMEM*           blkmem,             /**< block memory */
724    SCIP_SET*             set,                /**< global SCIP settings */
725    SCIP_STAT*            stat,               /**< problem statistics data */
726    SCIP_PRIMAL*          primal,             /**< primal data */
727    SCIP_HEUR*            heur                /**< heuristic that found the solution (or NULL if it's from the tree) */
728    )
729 {
730    assert(sol != NULL);
731    assert(blkmem != NULL);
732    assert(set != NULL);
733    assert(stat != NULL);
734    assert(primal != NULL);
735 
736    SCIP_ALLOC( BMSallocBlockMemory(blkmem, sol) );
737    SCIP_CALL( SCIPrealarrayCreate(&(*sol)->vals, blkmem) );
738    SCIP_CALL( SCIPboolarrayCreate(&(*sol)->valid, blkmem) );
739    (*sol)->solorigin = SCIP_SOLORIGIN_PARTIAL;
740    (*sol)->obj = SCIP_UNKNOWN;
741    (*sol)->primalindex = -1;
742    (*sol)->index = stat->solindex;
743    (*sol)->hasinfval = FALSE;
744    stat->solindex++;
745    solStamp(*sol, stat, NULL, TRUE);
746    SCIPsolResetViolations(*sol);
747 
748    /* set solution type and creator depending on whether a heuristic or NULL is passed */
749    SCIPsolSetHeur(*sol, heur);
750 
751    SCIP_CALL( SCIPprimalSolCreated(primal, set, *sol) );
752 
753    return SCIP_OKAY;
754 }
755 
756 /** creates primal CIP solution, initialized to unknown values */
SCIPsolCreateUnknown(SCIP_SOL ** sol,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_HEUR * heur)757 SCIP_RETCODE SCIPsolCreateUnknown(
758    SCIP_SOL**            sol,                /**< pointer to primal CIP solution */
759    BMS_BLKMEM*           blkmem,             /**< block memory */
760    SCIP_SET*             set,                /**< global SCIP settings */
761    SCIP_STAT*            stat,               /**< problem statistics data */
762    SCIP_PRIMAL*          primal,             /**< primal data */
763    SCIP_TREE*            tree,               /**< branch and bound tree */
764    SCIP_HEUR*            heur                /**< heuristic that found the solution (or NULL if it's from the tree) */
765    )
766 {
767    assert(sol != NULL);
768    assert(blkmem != NULL);
769    assert(stat != NULL);
770 
771    SCIP_ALLOC( BMSallocBlockMemory(blkmem, sol) );
772    SCIP_CALL( SCIPrealarrayCreate(&(*sol)->vals, blkmem) );
773    SCIP_CALL( SCIPboolarrayCreate(&(*sol)->valid, blkmem) );
774    (*sol)->solorigin = SCIP_SOLORIGIN_UNKNOWN;
775    (*sol)->obj = 0.0;
776    (*sol)->primalindex = -1;
777    (*sol)->index = stat->solindex;
778    (*sol)->hasinfval = FALSE;
779    stat->solindex++;
780    solStamp(*sol, stat, tree, TRUE);
781    SCIPsolResetViolations(*sol);
782 
783    /* set solution type and creator depending on whether a heuristic or NULL is passed */
784    SCIPsolSetHeur(*sol, heur);
785 
786    SCIP_CALL( SCIPprimalSolCreated(primal, set, *sol) );
787 
788    return SCIP_OKAY;
789 }
790 
791 /** frees primal CIP solution */
SCIPsolFree(SCIP_SOL ** sol,BMS_BLKMEM * blkmem,SCIP_PRIMAL * primal)792 SCIP_RETCODE SCIPsolFree(
793    SCIP_SOL**            sol,                /**< pointer to primal CIP solution */
794    BMS_BLKMEM*           blkmem,             /**< block memory */
795    SCIP_PRIMAL*          primal              /**< primal data */
796    )
797 {
798    assert(sol != NULL);
799    assert(*sol != NULL);
800 
801    SCIPprimalSolFreed(primal, *sol);
802 
803    SCIP_CALL( SCIPrealarrayFree(&(*sol)->vals) );
804    SCIP_CALL( SCIPboolarrayFree(&(*sol)->valid) );
805    BMSfreeBlockMemory(blkmem, sol);
806 
807    return SCIP_OKAY;
808 }
809 
810 /** copies current LP solution into CIP solution by linking */
SCIPsolLinkLPSol(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_TREE * tree,SCIP_LP * lp)811 SCIP_RETCODE SCIPsolLinkLPSol(
812    SCIP_SOL*             sol,                /**< primal CIP solution */
813    SCIP_SET*             set,                /**< global SCIP settings */
814    SCIP_STAT*            stat,               /**< problem statistics data */
815    SCIP_PROB*            prob,               /**< transformed problem data */
816    SCIP_TREE*            tree,               /**< branch and bound tree */
817    SCIP_LP*              lp                  /**< current LP data */
818    )
819 {
820    assert(sol != NULL);
821    assert(stat != NULL);
822    assert(tree != NULL);
823    assert(lp != NULL);
824    assert(lp->solved);
825    assert(SCIPlpDiving(lp) || SCIPtreeProbing(tree) || !SCIPlpDivingObjChanged(lp));
826 
827    SCIPsetDebugMsg(set, "linking solution to LP\n");
828 
829    /* clear the old solution arrays */
830    SCIP_CALL( solClearArrays(sol) );
831 
832    /* link solution to LP solution */
833    if( SCIPlpDivingObjChanged(lp) )
834    {
835       /* the objective value has to be calculated manually, because the LP's value is invalid;
836        * use objective values of variables, because columns objective values are changed to dive values
837        */
838       sol->obj = SCIPlpGetLooseObjval(lp, set, prob);
839       if( !SCIPsetIsInfinity(set, -sol->obj) )
840       {
841          SCIP_VAR* var;
842          SCIP_COL** cols;
843          int ncols;
844          int c;
845 
846          cols = SCIPlpGetCols(lp);
847          ncols = SCIPlpGetNCols(lp);
848          for( c = 0; c < ncols; ++c )
849          {
850             var = SCIPcolGetVar(cols[c]);
851             sol->obj += SCIPvarGetUnchangedObj(var) * cols[c]->primsol;
852          }
853       }
854    }
855    else
856    {
857       /* the objective value in the columns is correct, s.t. the LP's objective value is also correct */
858       sol->obj = SCIPlpGetObjval(lp, set, prob);
859    }
860    sol->solorigin = SCIP_SOLORIGIN_LPSOL;
861    solStamp(sol, stat, tree, TRUE);
862 
863    SCIPsetDebugMsg(set, " -> objective value: %g\n", sol->obj);
864 
865    return SCIP_OKAY;
866 }
867 
868 /** copies current NLP solution into CIP solution by linking */
SCIPsolLinkNLPSol(SCIP_SOL * sol,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_NLP * nlp)869 SCIP_RETCODE SCIPsolLinkNLPSol(
870    SCIP_SOL*             sol,                /**< primal CIP solution */
871    SCIP_STAT*            stat,               /**< problem statistics data */
872    SCIP_TREE*            tree,               /**< branch and bound tree */
873    SCIP_NLP*             nlp                 /**< current NLP data */
874    )
875 {
876    assert(sol != NULL);
877    assert(stat != NULL);
878    assert(tree != NULL);
879    assert(nlp != NULL);
880    assert(SCIPnlpGetSolstat(nlp) <= SCIP_NLPSOLSTAT_FEASIBLE);
881 
882    SCIPstatDebugMsg(stat, "linking solution to NLP\n");
883 
884    /* clear the old solution arrays */
885    SCIP_CALL( solClearArrays(sol) );
886 
887    /* get objective value of NLP solution */
888    if( SCIPnlpIsDivingObjChanged(nlp) )
889    {
890       /* the objective value has to be calculated manually, because the NLP's value is invalid */
891 
892       SCIP_VAR** vars;
893       int nvars;
894       int v;
895 
896       sol->obj = 0.0;
897 
898       vars = SCIPnlpGetVars(nlp);
899       nvars = SCIPnlpGetNVars(nlp);
900       for( v = 0; v < nvars; ++v )
901       {
902          assert(SCIPvarIsActive(vars[v]));
903          sol->obj += SCIPvarGetUnchangedObj(vars[v]) * SCIPvarGetNLPSol(vars[v]);
904       }
905    }
906    else
907    {
908       sol->obj = SCIPnlpGetObjval(nlp);
909    }
910 
911    sol->solorigin = SCIP_SOLORIGIN_NLPSOL;
912    solStamp(sol, stat, tree, TRUE);
913 
914    SCIPstatDebugMsg(stat, " -> objective value: %g\n", sol->obj);
915 
916    return SCIP_OKAY;
917 }
918 
919 /** copies current relaxation solution into CIP solution by linking */
SCIPsolLinkRelaxSol(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_RELAXATION * relaxation)920 SCIP_RETCODE SCIPsolLinkRelaxSol(
921    SCIP_SOL*             sol,                /**< primal CIP solution */
922    SCIP_SET*             set,                /**< global SCIP settings */
923    SCIP_STAT*            stat,               /**< problem statistics data */
924    SCIP_TREE*            tree,               /**< branch and bound tree */
925    SCIP_RELAXATION*      relaxation          /**< global relaxation data */
926    )
927 {  /*lint --e{715}*/
928    assert(sol != NULL);
929    assert(stat != NULL);
930    assert(tree != NULL);
931    assert(relaxation != NULL);
932    assert(SCIPrelaxationIsSolValid(relaxation));
933 
934    SCIPsetDebugMsg(set, "linking solution to relaxation\n");
935 
936    /* clear the old solution arrays */
937    SCIP_CALL( solClearArrays(sol) );
938 
939    /* the objective value in the columns is correct, s.t. the LP's objective value is also correct */
940    sol->obj = SCIPrelaxationGetSolObj(relaxation);
941    sol->solorigin = SCIP_SOLORIGIN_RELAXSOL;
942    solStamp(sol, stat, tree, TRUE);
943 
944    SCIPsetDebugMsg(set, " -> objective value: %g\n", sol->obj);
945 
946    return SCIP_OKAY;
947 }
948 
949 /** copies current pseudo solution into CIP solution by linking */
SCIPsolLinkPseudoSol(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_TREE * tree,SCIP_LP * lp)950 SCIP_RETCODE SCIPsolLinkPseudoSol(
951    SCIP_SOL*             sol,                /**< primal CIP solution */
952    SCIP_SET*             set,                /**< global SCIP settings */
953    SCIP_STAT*            stat,               /**< problem statistics data */
954    SCIP_PROB*            prob,               /**< transformed problem data */
955    SCIP_TREE*            tree,               /**< branch and bound tree, or NULL */
956    SCIP_LP*              lp                  /**< current LP data */
957    )
958 {
959    assert(sol != NULL);
960    assert(stat != NULL);
961    assert(tree != NULL);
962 
963    SCIPsetDebugMsg(set, "linking solution to pseudo solution\n");
964 
965    /* clear the old solution arrays */
966    SCIP_CALL( solClearArrays(sol) );
967 
968    /* link solution to pseudo solution */
969    sol->obj = SCIPlpGetPseudoObjval(lp, set, prob);
970    sol->solorigin = SCIP_SOLORIGIN_PSEUDOSOL;
971    solStamp(sol, stat, tree, TRUE);
972 
973    SCIPsetDebugMsg(set, " -> objective value: %g\n", sol->obj);
974 
975    return SCIP_OKAY;
976 }
977 
978 /** copies current solution (LP or pseudo solution) into CIP solution by linking */
SCIPsolLinkCurrentSol(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_TREE * tree,SCIP_LP * lp)979 SCIP_RETCODE SCIPsolLinkCurrentSol(
980    SCIP_SOL*             sol,                /**< primal CIP solution */
981    SCIP_SET*             set,                /**< global SCIP settings */
982    SCIP_STAT*            stat,               /**< problem statistics data */
983    SCIP_PROB*            prob,               /**< transformed problem data */
984    SCIP_TREE*            tree,               /**< branch and bound tree */
985    SCIP_LP*              lp                  /**< current LP data */
986    )
987 {
988    assert(tree != NULL);
989 
990    SCIPsetDebugMsg(set, "linking solution to current solution\n");
991 
992    if( SCIPtreeHasCurrentNodeLP(tree) && SCIPlpIsSolved(lp) )
993    {
994       SCIP_CALL( SCIPsolLinkLPSol(sol, set, stat, prob, tree, lp) );
995    }
996    else
997    {
998       SCIP_CALL( SCIPsolLinkPseudoSol(sol, set, stat, prob, tree, lp) );
999    }
1000 
1001    return SCIP_OKAY;
1002 }
1003 
1004 /** clears primal CIP solution */
SCIPsolClear(SCIP_SOL * sol,SCIP_STAT * stat,SCIP_TREE * tree)1005 SCIP_RETCODE SCIPsolClear(
1006    SCIP_SOL*             sol,                /**< primal CIP solution */
1007    SCIP_STAT*            stat,               /**< problem statistics data */
1008    SCIP_TREE*            tree                /**< branch and bound tree */
1009    )
1010 {
1011    assert(sol != NULL);
1012 
1013    SCIP_CALL( solClearArrays(sol) );
1014    sol->solorigin = SCIP_SOLORIGIN_ZERO;
1015    sol->obj = 0.0;
1016    solStamp(sol, stat, tree, TRUE);
1017 
1018    return SCIP_OKAY;
1019 }
1020 
1021 /** declares all entries in the primal CIP solution to be unknown */
SCIPsolSetUnknown(SCIP_SOL * sol,SCIP_STAT * stat,SCIP_TREE * tree)1022 SCIP_RETCODE SCIPsolSetUnknown(
1023    SCIP_SOL*             sol,                /**< primal CIP solution */
1024    SCIP_STAT*            stat,               /**< problem statistics data */
1025    SCIP_TREE*            tree                /**< branch and bound tree */
1026    )
1027 {
1028    assert(sol != NULL);
1029 
1030    SCIP_CALL( solClearArrays(sol) );
1031    sol->solorigin = SCIP_SOLORIGIN_UNKNOWN;
1032    sol->obj = 0.0;
1033    solStamp(sol, stat, tree, TRUE);
1034 
1035    return SCIP_OKAY;
1036 }
1037 
1038 /** stores solution values of variables in solution's own array */
SCIPsolUnlink(SCIP_SOL * sol,SCIP_SET * set,SCIP_PROB * prob)1039 SCIP_RETCODE SCIPsolUnlink(
1040    SCIP_SOL*             sol,                /**< primal CIP solution */
1041    SCIP_SET*             set,                /**< global SCIP settings */
1042    SCIP_PROB*            prob                /**< transformed problem data */
1043    )
1044 {
1045    int v;
1046 
1047    assert(sol != NULL);
1048    assert(prob != NULL);
1049    assert(prob->nvars == 0 || prob->vars != NULL);
1050 
1051    if( !SCIPsolIsOriginal(sol) && sol->solorigin != SCIP_SOLORIGIN_ZERO
1052       && sol->solorigin != SCIP_SOLORIGIN_UNKNOWN )
1053    {
1054       SCIPsetDebugMsg(set, "completing solution %p\n", (void*)sol);
1055 
1056       for( v = 0; v < prob->nvars; ++v )
1057       {
1058          SCIP_CALL( solUnlinkVar(sol, set, prob->vars[v]) );
1059       }
1060 
1061       sol->solorigin = SCIP_SOLORIGIN_ZERO;
1062    }
1063 
1064    return SCIP_OKAY;
1065 }
1066 
1067 /** sets value of variable in primal CIP solution */
SCIPsolSetVal(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_VAR * var,SCIP_Real val)1068 SCIP_RETCODE SCIPsolSetVal(
1069    SCIP_SOL*             sol,                /**< primal CIP solution */
1070    SCIP_SET*             set,                /**< global SCIP settings */
1071    SCIP_STAT*            stat,               /**< problem statistics data */
1072    SCIP_TREE*            tree,               /**< branch and bound tree, or NULL */
1073    SCIP_VAR*             var,                /**< variable to add to solution */
1074    SCIP_Real             val                 /**< solution value of variable */
1075    )
1076 {
1077    SCIP_Real oldval;
1078 
1079    assert(sol != NULL);
1080    assert(stat != NULL);
1081    assert(sol->solorigin == SCIP_SOLORIGIN_ORIGINAL
1082       || sol->solorigin == SCIP_SOLORIGIN_ZERO
1083       || sol->solorigin == SCIP_SOLORIGIN_PARTIAL
1084       || sol->solorigin == SCIP_SOLORIGIN_UNKNOWN
1085       || (sol->nodenum == stat->nnodes && sol->runnum == stat->nruns));
1086    assert(var != NULL);
1087    assert(SCIPisFinite(val));
1088 
1089    SCIPsetDebugMsg(set, "setting value of <%s> in solution %p to %g\n", SCIPvarGetName(var), (void*)sol, val);
1090 
1091    /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */
1092    switch( SCIPvarGetStatus(var) )
1093    {
1094    case SCIP_VARSTATUS_ORIGINAL:
1095       if( SCIPsolIsOriginal(sol) )
1096       {
1097          oldval = solGetArrayVal(sol, var);
1098 
1099          if( val != oldval )  /*lint !e777*/
1100          {
1101             SCIP_Real obj;
1102             SCIP_Real objcont;
1103 
1104             SCIP_CALL( solSetArrayVal(sol, set, var, val) );
1105 
1106             /* update the objective value; we do not need to do this for partial solutions */
1107             if( !SCIPsolIsPartial(sol) )
1108             {
1109                /* an unknown solution value does not count towards the objective */
1110                obj = SCIPvarGetUnchangedObj(var);
1111                if( oldval != SCIP_UNKNOWN ) /*lint !e777*/
1112                {
1113                   objcont = obj * oldval;
1114 
1115                   /* we want to use a clean infinity */
1116                   if( SCIPsetIsInfinity(set, -objcont) || SCIPsetIsInfinity(set, sol->obj-objcont) )
1117                      sol->obj = SCIPsetInfinity(set);
1118                   else if( SCIPsetIsInfinity(set, objcont) || SCIPsetIsInfinity(set, -(sol->obj-objcont)) )
1119                      sol->obj = -SCIPsetInfinity(set);
1120                   else
1121                      sol->obj -= objcont;
1122                }
1123                if( val != SCIP_UNKNOWN ) /*lint !e777*/
1124                {
1125                   objcont = obj * val;
1126 
1127                   /* we want to use a clean infinity */
1128                   if( SCIPsetIsInfinity(set, objcont) || SCIPsetIsInfinity(set, sol->obj+objcont) )
1129                      sol->obj = SCIPsetInfinity(set);
1130                   else if( SCIPsetIsInfinity(set, objcont) || SCIPsetIsInfinity(set, -(sol->obj+objcont)) )
1131                      sol->obj = -SCIPsetInfinity(set);
1132                   else
1133                      sol->obj += objcont;
1134                }
1135             }
1136 
1137             solStamp(sol, stat, tree, FALSE);
1138          }
1139          return SCIP_OKAY;
1140       }
1141       else
1142          return SCIPsolSetVal(sol, set, stat, tree, SCIPvarGetTransVar(var), val);
1143 
1144    case SCIP_VARSTATUS_LOOSE:
1145    case SCIP_VARSTATUS_COLUMN:
1146       assert(!SCIPsolIsOriginal(sol));
1147       assert(sol->solorigin != SCIP_SOLORIGIN_LPSOL || SCIPboolarrayGetVal(sol->valid, SCIPvarGetIndex(var))
1148          || sol->lpcount == stat->lpcount);
1149       oldval = solGetArrayVal(sol, var);
1150       if( val != oldval )  /*lint !e777*/
1151       {
1152          SCIP_Real obj;
1153          SCIP_Real objcont;
1154 
1155          SCIP_CALL( solSetArrayVal(sol, set, var, val) );
1156 
1157          /* update objective: an unknown solution value does not count towards the objective */
1158          obj = SCIPvarGetUnchangedObj(var);
1159 
1160          if( oldval != SCIP_UNKNOWN ) /*lint !e777*/
1161          {
1162             objcont = obj * oldval;
1163 
1164             /* we want to use a clean infinity */
1165             if( SCIPsetIsInfinity(set, -objcont) || SCIPsetIsInfinity(set, sol->obj-objcont) )
1166                sol->obj = SCIPsetInfinity(set);
1167             else if( SCIPsetIsInfinity(set, objcont) || SCIPsetIsInfinity(set, -(sol->obj-objcont)) )
1168                sol->obj = -SCIPsetInfinity(set);
1169             else
1170                sol->obj -= objcont;
1171          }
1172          if( val != SCIP_UNKNOWN ) /*lint !e777*/
1173          {
1174             objcont = obj * val;
1175 
1176             /* we want to use a clean infinity */
1177             if( SCIPsetIsInfinity(set, objcont) || SCIPsetIsInfinity(set, sol->obj+objcont) )
1178                sol->obj = SCIPsetInfinity(set);
1179             else if( SCIPsetIsInfinity(set, -objcont) || SCIPsetIsInfinity(set, -(sol->obj+objcont)) )
1180                sol->obj = -SCIPsetInfinity(set);
1181             else
1182                sol->obj += objcont;
1183          }
1184 
1185          solStamp(sol, stat, tree, FALSE);
1186       }
1187       return SCIP_OKAY;
1188 
1189    case SCIP_VARSTATUS_FIXED:
1190       assert(!SCIPsolIsOriginal(sol));
1191       oldval = SCIPvarGetLbGlobal(var);
1192       if( val != oldval )  /*lint !e777*/
1193       {
1194          SCIPerrorMessage("cannot set solution value for variable <%s> fixed to %.15g to different value %.15g\n",
1195             SCIPvarGetName(var), oldval, val);
1196          return SCIP_INVALIDDATA;
1197       }
1198       return SCIP_OKAY;
1199 
1200    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  =>  y = (x-c)/a */
1201       assert(!SCIPsetIsZero(set, SCIPvarGetAggrScalar(var)));
1202       assert(!SCIPsetIsInfinity(set, SCIPvarGetAggrConstant(var)) && !SCIPsetIsInfinity(set, -SCIPvarGetAggrConstant(var)));
1203       assert(!SCIPsetIsInfinity(set, SCIPvarGetAggrScalar(var)) && !SCIPsetIsInfinity(set, -SCIPvarGetAggrScalar(var)));
1204 
1205       if( val == SCIP_UNKNOWN )/*lint !e777*/
1206          return SCIPsolSetVal(sol, set, stat, tree, SCIPvarGetAggrVar(var), val);
1207       if( SCIPsetIsInfinity(set, val) || SCIPsetIsInfinity(set, -val) )
1208          return SCIPsolSetVal(sol, set, stat, tree, SCIPvarGetAggrVar(var),  SCIPvarGetAggrScalar(var) > 0 ? val : -val);
1209       else
1210          return SCIPsolSetVal(sol, set, stat, tree, SCIPvarGetAggrVar(var), (val - SCIPvarGetAggrConstant(var))/SCIPvarGetAggrScalar(var));
1211 
1212    case SCIP_VARSTATUS_MULTAGGR:
1213       if ( SCIPvarGetMultaggrNVars(var) == 1 )
1214       {
1215          SCIP_VAR** multaggrvars;
1216          SCIP_Real* multaggrscalars;
1217          SCIP_Real multaggrconstant;
1218 
1219          multaggrvars = SCIPvarGetMultaggrVars(var);
1220          multaggrscalars = SCIPvarGetMultaggrScalars(var);
1221          multaggrconstant = SCIPvarGetMultaggrConstant(var);
1222 
1223          if( SCIPsetIsInfinity(set, multaggrconstant) || SCIPsetIsInfinity(set, -multaggrconstant) )
1224          {
1225             if( (SCIPsetIsInfinity(set, multaggrconstant) && !SCIPsetIsInfinity(set, val))
1226                || (SCIPsetIsInfinity(set, -multaggrconstant) && !SCIPsetIsInfinity(set, -val)) )
1227             {
1228                SCIPerrorMessage("cannot set solution value for variable <%s> fixed to %.15g to different value %.15g\n",
1229                   SCIPvarGetName(var), multaggrconstant, val);
1230                return SCIP_INVALIDDATA;
1231             }
1232             return SCIP_OKAY;
1233          }
1234          else
1235          {
1236             if( SCIPsetIsInfinity(set, val) || SCIPsetIsInfinity(set, -val) )
1237                return SCIPsolSetVal(sol, set, stat, tree, multaggrvars[0],  multaggrscalars[0] > 0 ? val : -val);
1238             else
1239                return SCIPsolSetVal(sol, set, stat, tree, multaggrvars[0], (val - multaggrconstant)/multaggrscalars[0]);
1240          }
1241       }
1242       SCIPerrorMessage("cannot set solution value for multiple aggregated variable\n");
1243       return SCIP_INVALIDDATA;
1244 
1245    case SCIP_VARSTATUS_NEGATED:
1246       assert(!SCIPsetIsInfinity(set, SCIPvarGetNegationConstant(var)) && !SCIPsetIsInfinity(set, -SCIPvarGetNegationConstant(var)));
1247 
1248       if( val == SCIP_UNKNOWN )/*lint !e777*/
1249          return SCIPsolSetVal(sol, set, stat, tree, SCIPvarGetNegationVar(var), val);
1250       else if( SCIPsetIsInfinity(set, val) || SCIPsetIsInfinity(set, -val) )
1251          return SCIPsolSetVal(sol, set, stat, tree, SCIPvarGetNegationVar(var), -val);
1252       else
1253          return SCIPsolSetVal(sol, set, stat, tree, SCIPvarGetNegationVar(var), SCIPvarGetNegationConstant(var) - val);
1254 
1255    default:
1256       SCIPerrorMessage("unknown variable status\n");
1257       return SCIP_INVALIDDATA;
1258    }
1259 }
1260 
1261 /** increases value of variable in primal CIP solution */
SCIPsolIncVal(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_VAR * var,SCIP_Real incval)1262 SCIP_RETCODE SCIPsolIncVal(
1263    SCIP_SOL*             sol,                /**< primal CIP solution */
1264    SCIP_SET*             set,                /**< global SCIP settings */
1265    SCIP_STAT*            stat,               /**< problem statistics data */
1266    SCIP_TREE*            tree,               /**< branch and bound tree */
1267    SCIP_VAR*             var,                /**< variable to increase solution value for */
1268    SCIP_Real             incval              /**< increment for solution value of variable */
1269    )
1270 {
1271    SCIP_Real oldval;
1272 
1273    assert(sol != NULL);
1274    assert(stat != NULL);
1275    assert(sol->solorigin == SCIP_SOLORIGIN_ORIGINAL
1276       || sol->solorigin == SCIP_SOLORIGIN_ZERO
1277       || (sol->nodenum == stat->nnodes && sol->runnum == stat->nruns));
1278    assert(var != NULL);
1279    assert(!SCIPsetIsInfinity(set, incval) && !SCIPsetIsInfinity(set, -incval));
1280 
1281    SCIPsetDebugMsg(set, "increasing value of <%s> in solution %p by %g\n", SCIPvarGetName(var), (void*)sol, incval);
1282 
1283    if( SCIPsetIsZero(set, incval) )
1284       return SCIP_OKAY;
1285 
1286    assert(sol->solorigin != SCIP_SOLORIGIN_LPSOL || SCIPboolarrayGetVal(sol->valid, SCIPvarGetIndex(var))
1287       || sol->lpcount == stat->lpcount);
1288 
1289    oldval = solGetArrayVal(sol, var);
1290    if( SCIPsetIsInfinity(set, oldval) || SCIPsetIsInfinity(set, -oldval) )
1291       return SCIP_OKAY;
1292 
1293    /* we want to store only values for non fixed variables (LOOSE or COLUMN); others have to be transformed */
1294    /* @todo: handle strange cases, such as sums that yield infinite values */
1295    switch( SCIPvarGetStatus(var) )
1296    {
1297    case SCIP_VARSTATUS_ORIGINAL:
1298       if( SCIPsolIsOriginal(sol) )
1299       {
1300          SCIP_CALL( solIncArrayVal(sol, set, var, incval) );
1301          sol->obj += SCIPvarGetUnchangedObj(var) * incval;
1302          solStamp(sol, stat, tree, FALSE);
1303          return SCIP_OKAY;
1304       }
1305       else
1306          return SCIPsolIncVal(sol, set, stat, tree, SCIPvarGetTransVar(var), incval);
1307 
1308    case SCIP_VARSTATUS_LOOSE:
1309    case SCIP_VARSTATUS_COLUMN:
1310       assert(!SCIPsolIsOriginal(sol));
1311       SCIP_CALL( solIncArrayVal(sol, set, var, incval) );
1312       sol->obj += SCIPvarGetUnchangedObj(var) * incval;
1313       solStamp(sol, stat, tree, FALSE);
1314       return SCIP_OKAY;
1315 
1316    case SCIP_VARSTATUS_FIXED:
1317       SCIPerrorMessage("cannot increase solution value for fixed variable\n");
1318       return SCIP_INVALIDDATA;
1319 
1320    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  =>  y = (x-c)/a */
1321       assert(!SCIPsetIsZero(set, SCIPvarGetAggrScalar(var)));
1322       return SCIPsolIncVal(sol, set, stat, tree, SCIPvarGetAggrVar(var), incval/SCIPvarGetAggrScalar(var));
1323 
1324    case SCIP_VARSTATUS_MULTAGGR:
1325       SCIPerrorMessage("cannot increase solution value for multiple aggregated variable\n");
1326       return SCIP_INVALIDDATA;
1327 
1328    case SCIP_VARSTATUS_NEGATED:
1329       return SCIPsolIncVal(sol, set, stat, tree, SCIPvarGetNegationVar(var), -incval);
1330 
1331    default:
1332       SCIPerrorMessage("unknown variable status\n");
1333       return SCIP_INVALIDDATA;
1334    }
1335 }
1336 
1337 /** returns value of variable in primal CIP solution */
SCIPsolGetVal(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR * var)1338 SCIP_Real SCIPsolGetVal(
1339    SCIP_SOL*             sol,                /**< primal CIP solution */
1340    SCIP_SET*             set,                /**< global SCIP settings */
1341    SCIP_STAT*            stat,               /**< problem statistics data */
1342    SCIP_VAR*             var                 /**< variable to get value for */
1343    )
1344 {
1345    SCIP_VAR** vars;
1346    SCIP_Real* scalars;
1347    SCIP_Real solval;
1348    SCIP_Real solvalsum;
1349    int nvars;
1350    int i;
1351 
1352    assert(sol != NULL);
1353    assert(sol->solorigin == SCIP_SOLORIGIN_ORIGINAL
1354       || sol->solorigin == SCIP_SOLORIGIN_ZERO
1355       || sol->solorigin == SCIP_SOLORIGIN_PARTIAL
1356       || sol->solorigin == SCIP_SOLORIGIN_UNKNOWN
1357       || (sol->nodenum == stat->nnodes && sol->runnum == stat->nruns));
1358    assert(var != NULL);
1359 
1360    /* if the value of a transformed variable in an original solution is requested, we need to project the variable back
1361     * to the original space, the opposite case is handled below
1362     */
1363    if( SCIPsolIsOriginal(sol) && SCIPvarIsTransformed(var) )
1364    {
1365       SCIP_RETCODE retcode;
1366       SCIP_VAR* origvar;
1367       SCIP_Real scalar;
1368       SCIP_Real constant;
1369 
1370       /* we cannot get the value of a transformed variable for a solution that lives in the original problem space
1371        * -> get the corresponding original variable first
1372        */
1373       origvar = var;
1374       scalar = 1.0;
1375       constant = 0.0;
1376       retcode = SCIPvarGetOrigvarSum(&origvar, &scalar, &constant);
1377       if ( retcode != SCIP_OKAY )
1378          return SCIP_INVALID;
1379       if( origvar == NULL )
1380       {
1381          /* the variable has no original counterpart: in the original solution, it has a value of zero */
1382          return 0.0;
1383       }
1384       assert(!SCIPvarIsTransformed(origvar));
1385 
1386       solval = SCIPsolGetVal(sol, set, stat, origvar);
1387       if( solval == SCIP_UNKNOWN ) /*lint !e777*/
1388          return SCIP_UNKNOWN;
1389       else
1390          return scalar * solval + constant;
1391    }
1392 
1393    /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */
1394    switch( SCIPvarGetStatus(var) )
1395    {
1396    case SCIP_VARSTATUS_ORIGINAL:
1397       if( SCIPsolIsOriginal(sol) )
1398          return solGetArrayVal(sol, var);
1399       else
1400          return SCIPsolGetVal(sol, set, stat, SCIPvarGetTransVar(var));
1401 
1402    case SCIP_VARSTATUS_LOOSE:
1403    case SCIP_VARSTATUS_COLUMN:
1404       assert(!SCIPsolIsOriginal(sol));
1405       assert(sol->solorigin != SCIP_SOLORIGIN_LPSOL || SCIPboolarrayGetVal(sol->valid, SCIPvarGetIndex(var))
1406          || sol->lpcount == stat->lpcount);
1407       return solGetArrayVal(sol, var);
1408 
1409    case SCIP_VARSTATUS_FIXED:
1410       assert(!SCIPsolIsOriginal(sol));
1411       assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var)); /*lint !e777*/
1412       assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var)); /*lint !e777*/
1413       assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var)); /*lint !e777*/
1414       return SCIPvarGetLbGlobal(var);
1415 
1416    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  =>  y = (x-c)/a */
1417       solval = SCIPsolGetVal(sol, set, stat, SCIPvarGetAggrVar(var));
1418       if( solval == SCIP_UNKNOWN ) /*lint !e777*/
1419          return SCIP_UNKNOWN;
1420       if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) )
1421       {
1422          if( SCIPvarGetAggrScalar(var) * solval > 0.0 )
1423             return SCIPsetInfinity(set);
1424          if( SCIPvarGetAggrScalar(var) * solval < 0.0 )
1425             return -SCIPsetInfinity(set);
1426       }
1427       return SCIPvarGetAggrScalar(var) * solval + SCIPvarGetAggrConstant(var);
1428 
1429    case SCIP_VARSTATUS_MULTAGGR:
1430       nvars = SCIPvarGetMultaggrNVars(var);
1431       vars = SCIPvarGetMultaggrVars(var);
1432       scalars = SCIPvarGetMultaggrScalars(var);
1433       solvalsum = SCIPvarGetMultaggrConstant(var);
1434       for( i = 0; i < nvars; ++i )
1435       {
1436          solval = SCIPsolGetVal(sol, set, stat, vars[i]);
1437          if( solval == SCIP_UNKNOWN ) /*lint !e777*/
1438             return SCIP_UNKNOWN;
1439          if( SCIPsetIsInfinity(set, solval) || SCIPsetIsInfinity(set, -solval) )
1440          {
1441             if( scalars[i] * solval > 0.0 )
1442                return SCIPsetInfinity(set);
1443             if( scalars[i] * solval < 0.0 )
1444                return -SCIPsetInfinity(set);
1445          }
1446          solvalsum += scalars[i] * solval;
1447       }
1448       return solvalsum;
1449 
1450    case SCIP_VARSTATUS_NEGATED:
1451       solval = SCIPsolGetVal(sol, set, stat, SCIPvarGetNegationVar(var));
1452       if( solval == SCIP_UNKNOWN ) /*lint !e777*/
1453          return SCIP_UNKNOWN;
1454       if( SCIPsetIsInfinity(set, solval) )
1455          return -SCIPsetInfinity(set);
1456       if( SCIPsetIsInfinity(set, -solval) )
1457          return SCIPsetInfinity(set);
1458       return SCIPvarGetNegationConstant(var) - solval;
1459 
1460    default:
1461       SCIPerrorMessage("unknown variable status\n");
1462       SCIPABORT();
1463       return 0.0; /*lint !e527*/
1464    }
1465 }
1466 
1467 /** returns value of variable in primal ray represented by primal CIP solution */
SCIPsolGetRayVal(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR * var)1468 SCIP_Real SCIPsolGetRayVal(
1469    SCIP_SOL*             sol,                /**< primal CIP solution, representing a primal ray */
1470    SCIP_SET*             set,                /**< global SCIP settings */
1471    SCIP_STAT*            stat,               /**< problem statistics data */
1472    SCIP_VAR*             var                 /**< variable to get value for */
1473    )
1474 {
1475    SCIP_VAR** vars;
1476    SCIP_Real* scalars;
1477    SCIP_Real solval;
1478    SCIP_Real solvalsum;
1479    int nvars;
1480    int i;
1481 
1482    assert(sol != NULL);
1483    assert(sol->solorigin == SCIP_SOLORIGIN_ZERO);
1484    assert(var != NULL);
1485 
1486    /* only values for non fixed variables (LOOSE or COLUMN) are stored; others have to be transformed */
1487    switch( SCIPvarGetStatus(var) )
1488    {
1489    case SCIP_VARSTATUS_ORIGINAL:
1490       return SCIPsolGetRayVal(sol, set, stat, SCIPvarGetTransVar(var));
1491 
1492    case SCIP_VARSTATUS_LOOSE:
1493    case SCIP_VARSTATUS_COLUMN:
1494       return solGetArrayVal(sol, var);
1495 
1496    case SCIP_VARSTATUS_FIXED:
1497       assert(!SCIPsolIsOriginal(sol));
1498       assert(SCIPvarGetLbGlobal(var) == SCIPvarGetUbGlobal(var)); /*lint !e777*/
1499       assert(SCIPvarGetLbLocal(var) == SCIPvarGetUbLocal(var)); /*lint !e777*/
1500       assert(SCIPvarGetLbGlobal(var) == SCIPvarGetLbLocal(var)); /*lint !e777*/
1501       return 0.0; /* constants are ignored for computing the ray direction */
1502 
1503    case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c  =>  y = (x-c)/a */
1504       solval = SCIPsolGetRayVal(sol, set, stat, SCIPvarGetAggrVar(var));
1505       assert(solval != SCIP_UNKNOWN); /*lint !e777*/
1506       assert(!SCIPsetIsInfinity(set, REALABS(solval)));
1507       return SCIPvarGetAggrScalar(var) * solval; /* constants are ignored for computing the ray direction */
1508 
1509    case SCIP_VARSTATUS_MULTAGGR:
1510       nvars = SCIPvarGetMultaggrNVars(var);
1511       vars = SCIPvarGetMultaggrVars(var);
1512       scalars = SCIPvarGetMultaggrScalars(var);
1513       solvalsum = 0.0; /* constants are ignored for computing the ray direction */
1514       for( i = 0; i < nvars; ++i )
1515       {
1516          solval = SCIPsolGetRayVal(sol, set, stat, vars[i]);
1517          assert(solval != SCIP_UNKNOWN ); /*lint !e777*/
1518          assert(!SCIPsetIsInfinity(set, REALABS(solval)));
1519          solvalsum += scalars[i] * solval;
1520       }
1521       return solvalsum;
1522 
1523    case SCIP_VARSTATUS_NEGATED:
1524       solval = SCIPsolGetRayVal(sol, set, stat, SCIPvarGetNegationVar(var));
1525       assert(solval != SCIP_UNKNOWN); /*lint !e777*/
1526       assert(!SCIPsetIsInfinity(set, REALABS(solval)));
1527       return -solval; /* constants are ignored for computing the ray direction */
1528 
1529    default:
1530       SCIPerrorMessage("unknown variable status\n");
1531       SCIPABORT();
1532       return 0.0; /*lint !e527*/
1533    }
1534 }
1535 
1536 /** gets objective value of primal CIP solution in transformed problem */
SCIPsolGetObj(SCIP_SOL * sol,SCIP_SET * set,SCIP_PROB * transprob,SCIP_PROB * origprob)1537 SCIP_Real SCIPsolGetObj(
1538    SCIP_SOL*             sol,                /**< primal CIP solution */
1539    SCIP_SET*             set,                /**< global SCIP settings */
1540    SCIP_PROB*            transprob,          /**< tranformed problem data */
1541    SCIP_PROB*            origprob            /**< original problem data */
1542    )
1543 {
1544    assert(sol != NULL);
1545 
1546    /* for original solutions, sol->obj contains the external objective value */
1547    if( SCIPsolIsOriginal(sol) )
1548       return SCIPprobInternObjval(transprob, origprob, set, sol->obj);
1549    else
1550       return sol->obj;
1551 }
1552 
1553 /** updates primal solutions after a change in a variable's objective value */
SCIPsolUpdateVarObj(SCIP_SOL * sol,SCIP_VAR * var,SCIP_Real oldobj,SCIP_Real newobj)1554 void SCIPsolUpdateVarObj(
1555    SCIP_SOL*             sol,                /**< primal CIP solution */
1556    SCIP_VAR*             var,                /**< problem variable */
1557    SCIP_Real             oldobj,             /**< old objective value */
1558    SCIP_Real             newobj              /**< new objective value */
1559    )
1560 {
1561    SCIP_Real solval;
1562 
1563    assert(sol != NULL);
1564    assert(!SCIPsolIsOriginal(sol));
1565    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
1566 
1567    solval = solGetArrayVal(sol, var);
1568    if( solval != SCIP_UNKNOWN ) /*lint !e777*/
1569       sol->obj += (newobj - oldobj) * solval;
1570 }
1571 
1572 /* mark the given solution as partial solution */
SCIPsolMarkPartial(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR ** vars,int nvars)1573 SCIP_RETCODE SCIPsolMarkPartial(
1574    SCIP_SOL*             sol,                /**< primal CIP solution */
1575    SCIP_SET*             set,                /**< global SCIP settings */
1576    SCIP_STAT*            stat,               /**< problem statistics */
1577    SCIP_VAR**            vars,               /**< problem variables */
1578    int                   nvars               /**< number of problem variables */
1579    )
1580 {
1581    SCIP_Real* vals;
1582    int v;
1583 
1584    assert(sol != NULL);
1585    assert(sol->solorigin == SCIP_SOLORIGIN_ORIGINAL);
1586    assert(nvars == 0 || vars != NULL);
1587 
1588    if( nvars == 0 )
1589       return SCIP_OKAY;;
1590 
1591    SCIP_CALL( SCIPsetAllocBufferArray(set, &vals, nvars) );
1592 
1593    /* get values */
1594    for( v = 0; v < nvars; v++ )
1595    {
1596       assert(!SCIPvarIsTransformed(vars[v]));
1597       vals[v] = SCIPsolGetVal(sol, set, stat, vars[v]);
1598    }
1599 
1600    /* change origin to partial */
1601    sol->solorigin = SCIP_SOLORIGIN_PARTIAL;
1602 
1603    /* set values */
1604    for( v = 0; v < nvars; v++ )
1605    {
1606       int idx = SCIPvarGetIndex(vars[v]);
1607 
1608       if( vals[v] != SCIP_UNKNOWN ) /*lint !e777*/
1609       {
1610          /* from now on, variable must not be deleted */
1611          SCIPvarMarkNotDeletable(vars[v]);
1612 
1613          /* mark the variable valid */
1614          SCIP_CALL( SCIPboolarraySetVal(sol->valid, set->mem_arraygrowinit, set->mem_arraygrowfac, idx, TRUE) );
1615 
1616          /* set the value in the solution array */
1617          SCIP_CALL( SCIPrealarraySetVal(sol->vals, set->mem_arraygrowinit, set->mem_arraygrowfac, idx, vals[v]) );
1618       }
1619       else
1620       {
1621          /* mark the variable invalid */
1622          SCIP_CALL( SCIPboolarraySetVal(sol->valid, set->mem_arraygrowinit, set->mem_arraygrowfac, idx, FALSE) );
1623       }
1624    }
1625 
1626    /* free buffer */
1627    SCIPsetFreeBufferArray(set, &vals);
1628 
1629    return SCIP_OKAY;
1630 }
1631 
1632 /** checks primal CIP solution for feasibility
1633  *
1634  *  @note The difference between SCIPsolCheck() and SCIPcheckSolOrig() is that modifiable constraints are handled
1635  *        differently. There might be some variables which do not have an original counter part (e.g. in
1636  *        branch-and-price). Therefore, modifiable constraints can not be double-checked in the original space.
1637  */
SCIPsolCheck(SCIP_SOL * sol,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,BMS_BLKMEM * blkmem,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_Bool printreason,SCIP_Bool completely,SCIP_Bool checkbounds,SCIP_Bool checkintegrality,SCIP_Bool checklprows,SCIP_Bool * feasible)1638 SCIP_RETCODE SCIPsolCheck(
1639    SCIP_SOL*             sol,                /**< primal CIP solution */
1640    SCIP_SET*             set,                /**< global SCIP settings */
1641    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
1642    BMS_BLKMEM*           blkmem,             /**< block memory */
1643    SCIP_STAT*            stat,               /**< problem statistics */
1644    SCIP_PROB*            prob,               /**< transformed problem data */
1645    SCIP_Bool             printreason,        /**< Should all reasons of violations be printed? */
1646    SCIP_Bool             completely,         /**< Should all violations be checked? */
1647    SCIP_Bool             checkbounds,        /**< Should the bounds of the variables be checked? */
1648    SCIP_Bool             checkintegrality,   /**< Has integrality to be checked? */
1649    SCIP_Bool             checklprows,        /**< Do constraints represented by rows in the current LP have to be checked? */
1650    SCIP_Bool*            feasible            /**< stores whether solution is feasible */
1651    )
1652 {
1653    SCIP_RESULT result;
1654    int h;
1655 
1656    assert(sol != NULL);
1657    assert(!SCIPsolIsOriginal(sol));
1658    assert(set != NULL);
1659    assert(prob != NULL);
1660    assert(feasible != NULL);
1661 
1662    SCIPsetDebugMsg(set, "checking solution with objective value %g (nodenum=%" SCIP_LONGINT_FORMAT ", origin=%u)\n",
1663       sol->obj, sol->nodenum, sol->solorigin);
1664 
1665    *feasible = TRUE;
1666 
1667    SCIPsolResetViolations(sol);
1668 
1669    if( !printreason )
1670       completely = FALSE;
1671 
1672    /* check whether the solution respects the global bounds of the variables */
1673    if( checkbounds || sol->hasinfval )
1674    {
1675       int v;
1676 
1677       for( v = 0; v < prob->nvars && (*feasible || completely); ++v )
1678       {
1679          SCIP_VAR* var;
1680          SCIP_Real solval;
1681 
1682          var = prob->vars[v];
1683          solval = SCIPsolGetVal(sol, set, stat, var);
1684 
1685          if( solval != SCIP_UNKNOWN ) /*lint !e777*/
1686          {
1687             SCIP_Real lb;
1688             SCIP_Real ub;
1689 
1690             lb = SCIPvarGetLbGlobal(var);
1691             ub = SCIPvarGetUbGlobal(var);
1692 
1693             /* if we have to check bound and one of the current bounds is violated */
1694             if( checkbounds && ((!SCIPsetIsInfinity(set, -lb) && SCIPsetIsFeasLT(set, solval, lb))
1695                      || (!SCIPsetIsInfinity(set, ub) && SCIPsetIsFeasGT(set, solval, ub))) )
1696             {
1697                *feasible = FALSE;
1698 
1699                if( printreason )
1700                {
1701                   SCIPmessagePrintInfo(messagehdlr, "solution value %g violates bounds of <%s>[%g,%g] by %g\n", solval, SCIPvarGetName(var),
1702                         SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), MAX(lb - solval, 0.0) + MAX(solval - ub, 0.0));
1703                }
1704 #ifdef SCIP_DEBUG
1705                else
1706                {
1707                   SCIPsetDebugMsgPrint(set, "  -> solution value %g violates bounds of <%s>[%g,%g]\n", solval, SCIPvarGetName(var),
1708                         SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
1709                }
1710 #endif
1711             }
1712 
1713             /* check whether there are infinite variable values that lead to an objective value of +infinity */
1714             if( *feasible && sol->hasinfval )
1715             {
1716                *feasible = *feasible && (!SCIPsetIsInfinity(set, solval) || SCIPsetIsLE(set, SCIPvarGetUnchangedObj(var), 0.0) );
1717                *feasible = *feasible && (!SCIPsetIsInfinity(set, -solval) || SCIPsetIsGE(set, SCIPvarGetUnchangedObj(var), 0.0) );
1718 
1719                if( ((SCIPsetIsInfinity(set, solval) && SCIPsetIsGT(set, SCIPvarGetUnchangedObj(var), 0.0)) || (SCIPsetIsInfinity(set, -solval) && SCIPsetIsLT(set, SCIPvarGetUnchangedObj(var), 0.0))) )
1720                {
1721                   if( printreason )
1722                   {
1723                      SCIPmessagePrintInfo(messagehdlr, "infinite solution value %g for variable  <%s> with obj %g implies objective value +infinity\n",
1724                         solval, SCIPvarGetName(var), SCIPvarGetUnchangedObj(var));
1725                   }
1726 #ifdef SCIP_DEBUG
1727                   else
1728                   {
1729                      SCIPsetDebugMsgPrint(set, "infinite solution value %g for variable  <%s> with obj %g implies objective value +infinity\n",
1730                         solval, SCIPvarGetName(var), SCIPvarGetUnchangedObj(var));
1731                   }
1732 #endif
1733                }
1734             }
1735          }
1736       }
1737    }
1738 
1739    /* check whether the solution fulfills all constraints */
1740    for( h = 0; h < set->nconshdlrs && (*feasible || completely); ++h )
1741    {
1742       SCIP_CALL( SCIPconshdlrCheck(set->conshdlrs[h], blkmem, set, stat, sol,
1743             checkintegrality, checklprows, printreason, completely, &result) );
1744       *feasible = *feasible && (result == SCIP_FEASIBLE);
1745 
1746 #ifdef SCIP_DEBUG
1747       if( !(*feasible) )
1748       {
1749          SCIPdebugPrintf("  -> infeasibility detected in constraint handler <%s>\n",
1750             SCIPconshdlrGetName(set->conshdlrs[h]));
1751       }
1752 #endif
1753    }
1754 
1755    return SCIP_OKAY;
1756 }
1757 
1758 /** try to round given solution */
SCIPsolRound(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_TREE * tree,SCIP_Bool * success)1759 SCIP_RETCODE SCIPsolRound(
1760    SCIP_SOL*             sol,                /**< primal solution */
1761    SCIP_SET*             set,                /**< global SCIP settings */
1762    SCIP_STAT*            stat,               /**< problem statistics data */
1763    SCIP_PROB*            prob,               /**< transformed problem data */
1764    SCIP_TREE*            tree,               /**< branch and bound tree */
1765    SCIP_Bool*            success             /**< pointer to store whether rounding was successful */
1766    )
1767 {
1768    int nvars;
1769    int v;
1770 
1771    assert(sol != NULL);
1772    assert(!SCIPsolIsOriginal(sol));
1773    assert(prob != NULL);
1774    assert(prob->transformed);
1775    assert(success != NULL);
1776 
1777    /* round all roundable fractional variables in the corresponding direction as long as no unroundable var was found */
1778    nvars = prob->nbinvars + prob->nintvars;
1779    for( v = 0; v < nvars; ++v )
1780    {
1781       SCIP_VAR* var;
1782       SCIP_Real solval;
1783       SCIP_Bool mayrounddown;
1784       SCIP_Bool mayroundup;
1785 
1786       var = prob->vars[v];
1787       assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
1788       assert(sol->solorigin != SCIP_SOLORIGIN_LPSOL || SCIPboolarrayGetVal(sol->valid, SCIPvarGetIndex(var))
1789          || sol->lpcount == stat->lpcount);
1790       solval = solGetArrayVal(sol, var);
1791 
1792       /* solutions with unknown entries cannot be rounded */
1793       if( solval == SCIP_UNKNOWN ) /*lint !e777*/
1794          break;
1795 
1796       /* if solution value is already integral with feastol, continue */
1797       if( SCIPsetIsFeasIntegral(set, solval) )
1798          continue;
1799 
1800       /* get rounding possibilities */
1801       mayrounddown = SCIPvarMayRoundDown(var);
1802       mayroundup = SCIPvarMayRoundUp(var);
1803 
1804       /* choose rounding direction */
1805       if( mayrounddown && mayroundup )
1806       {
1807          /* we can round in both directions: round in objective function direction */
1808          if( SCIPvarGetUnchangedObj(var) >= 0.0 )
1809             solval = SCIPsetFeasFloor(set, solval);
1810          else
1811             solval = SCIPsetFeasCeil(set, solval);
1812       }
1813       else if( mayrounddown )
1814          solval = SCIPsetFeasFloor(set, solval);
1815       else if( mayroundup )
1816          solval = SCIPsetFeasCeil(set, solval);
1817       else
1818          break;
1819 
1820       /* store new solution value */
1821       SCIP_CALL( SCIPsolSetVal(sol, set, stat, tree, var, solval) );
1822    }
1823 
1824    /* check, if rounding was successful */
1825    *success = (v == nvars);
1826 
1827    return SCIP_OKAY;
1828 }
1829 
1830 /** updates the solution value sums in variables by adding the value in the given solution */
SCIPsolUpdateVarsum(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_Real weight)1831 void SCIPsolUpdateVarsum(
1832    SCIP_SOL*             sol,                /**< primal CIP solution */
1833    SCIP_SET*             set,                /**< global SCIP settings */
1834    SCIP_STAT*            stat,               /**< problem statistics data */
1835    SCIP_PROB*            prob,               /**< transformed problem data */
1836    SCIP_Real             weight              /**< weight of solution in weighted average */
1837    )
1838 {
1839    SCIP_Real solval;
1840    int v;
1841 
1842    assert(sol != NULL);
1843    assert(!SCIPsolIsOriginal(sol));
1844    assert(0.0 <= weight && weight <= 1.0);
1845 
1846    for( v = 0; v < prob->nvars; ++v )
1847    {
1848       assert(prob->vars[v] != NULL);
1849       solval = SCIPsolGetVal(sol, set, stat, prob->vars[v]);
1850       if( solval != SCIP_UNKNOWN ) /*lint !e777*/
1851       {
1852          prob->vars[v]->primsolavg *= (1.0-weight);
1853          prob->vars[v]->primsolavg += weight*solval;
1854       }
1855    }
1856 }
1857 
1858 /** retransforms solution to original problem space */
SCIPsolRetransform(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * origprob,SCIP_PROB * transprob,SCIP_Bool * hasinfval)1859 SCIP_RETCODE SCIPsolRetransform(
1860    SCIP_SOL*             sol,                /**< primal CIP solution */
1861    SCIP_SET*             set,                /**< global SCIP settings */
1862    SCIP_STAT*            stat,               /**< problem statistics data */
1863    SCIP_PROB*            origprob,           /**< original problem */
1864    SCIP_PROB*            transprob,          /**< transformed problem */
1865    SCIP_Bool*            hasinfval           /**< pointer to store whether the solution has infinite values */
1866    )
1867 {
1868    SCIP_VAR** transvars;
1869    SCIP_VAR** vars;
1870    SCIP_VAR** activevars;
1871    SCIP_Real* solvals;
1872    SCIP_Real* activevals;
1873    SCIP_Real* transsolvals;
1874    SCIP_Real constant;
1875    int requiredsize;
1876    int ntransvars;
1877    int nactivevars;
1878    int nvars;
1879    int v;
1880    int i;
1881 
1882    assert(sol != NULL);
1883    assert(sol->solorigin == SCIP_SOLORIGIN_ZERO);
1884    assert(origprob != NULL);
1885    assert(transprob != NULL);
1886    assert(hasinfval != NULL);
1887    assert(!origprob->transformed);
1888    assert(transprob->transformed);
1889 
1890    *hasinfval = FALSE;
1891 
1892    /* This method was a performance bottleneck when retransforming a solution during presolving, before flattening the
1893     * aggregation graph. In that case, calling SCIPsolGetVal() on the original variable consumed too much
1894     * time. Therefore, we now first compute the active representation of each original variable using
1895     * SCIPvarGetActiveRepresentatives(), which is much faster, and sum up the solution values of the active variables by
1896     * hand for each original variable.
1897     */
1898    vars = origprob->vars;
1899    nvars = origprob->nvars;
1900    transvars = transprob->vars;
1901    ntransvars = transprob->nvars;
1902 
1903    /* allocate temporary memory for getting the active representation of the original variables, buffering the solution
1904     * values of all active variables and storing the original solution values
1905     */
1906    SCIP_CALL( SCIPsetAllocBufferArray(set, &transsolvals, ntransvars + 1) );
1907    SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, ntransvars + 1) );
1908    SCIP_CALL( SCIPsetAllocBufferArray(set, &activevals, ntransvars + 1) );
1909    SCIP_CALL( SCIPsetAllocBufferArray(set, &solvals, nvars) );
1910    assert(transsolvals != NULL); /* for flexelint */
1911    assert(solvals != NULL); /* for flexelint */
1912 
1913    /* get the solution values of all active variables */
1914    for( v = 0; v < ntransvars; ++v )
1915    {
1916       transsolvals[v] = SCIPsolGetVal(sol, set, stat, transvars[v]);
1917    }
1918 
1919    /* get the solution in original problem variables */
1920    for( v = 0; v < nvars; ++v )
1921    {
1922       activevars[0] = vars[v];
1923       activevals[0] = 1.0;
1924       nactivevars = 1;
1925       constant = 0.0;
1926 
1927       /* get active representation of the original variable */
1928       SCIP_CALL( SCIPvarGetActiveRepresentatives(set, activevars, activevals, &nactivevars, ntransvars + 1, &constant,
1929             &requiredsize, TRUE) );
1930       assert(requiredsize <= ntransvars);
1931 
1932       /* compute solution value of the original variable */
1933       solvals[v] = constant;
1934       for( i = 0; i < nactivevars; ++i )
1935       {
1936          assert(0 <= SCIPvarGetProbindex(activevars[i]) && SCIPvarGetProbindex(activevars[i]) < ntransvars);
1937          assert(!SCIPsetIsInfinity(set, -solvals[v]) || !SCIPsetIsInfinity(set, activevals[i] * transsolvals[SCIPvarGetProbindex(activevars[i])]));
1938          assert(!SCIPsetIsInfinity(set, solvals[v]) || !SCIPsetIsInfinity(set, -activevals[i] * transsolvals[SCIPvarGetProbindex(activevars[i])]));
1939          solvals[v] += activevals[i] * transsolvals[SCIPvarGetProbindex(activevars[i])];
1940       }
1941 
1942       if( SCIPsetIsInfinity(set, solvals[v]) )
1943       {
1944          solvals[v] = SCIPsetInfinity(set);
1945          *hasinfval = TRUE;
1946       }
1947       else if( SCIPsetIsInfinity(set, -solvals[v]) )
1948       {
1949          solvals[v] = -SCIPsetInfinity(set);
1950          *hasinfval = TRUE;
1951       }
1952    }
1953 
1954    /* clear the solution and convert it into original space */
1955    SCIP_CALL( solClearArrays(sol) );
1956    sol->solorigin = SCIP_SOLORIGIN_ORIGINAL;
1957    sol->obj = origprob->objoffset;
1958 
1959    /* reinsert the values of the original variables */
1960    for( v = 0; v < nvars; ++v )
1961    {
1962       assert(SCIPvarGetUnchangedObj(vars[v]) == SCIPvarGetObj(vars[v])); /*lint !e777*/
1963 
1964       if( !SCIPsetIsZero(set, solvals[v]) )
1965       {
1966          SCIP_CALL( solSetArrayVal(sol, set, vars[v], solvals[v]) );
1967          if( solvals[v] != SCIP_UNKNOWN ) /*lint !e777*/
1968             sol->obj += SCIPvarGetUnchangedObj(vars[v]) * solvals[v];
1969       }
1970    }
1971 
1972    /**@todo remember the variables without original counterpart (priced variables) in the solution */
1973 
1974    /* free temporary memory */
1975    SCIPsetFreeBufferArray(set, &solvals);
1976    SCIPsetFreeBufferArray(set, &activevals);
1977    SCIPsetFreeBufferArray(set, &activevars);
1978    SCIPsetFreeBufferArray(set, &transsolvals);
1979 
1980    return SCIP_OKAY;
1981 }
1982 
1983 /** recomputes the objective value of an original solution, e.g., when transferring solutions
1984  *  from the solution pool (objective coefficients might have changed in the meantime)
1985  */
SCIPsolRecomputeObj(SCIP_SOL * sol,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * origprob)1986 void SCIPsolRecomputeObj(
1987    SCIP_SOL*             sol,                /**< primal CIP solution */
1988    SCIP_SET*             set,                /**< global SCIP settings */
1989    SCIP_STAT*            stat,               /**< problem statistics data */
1990    SCIP_PROB*            origprob            /**< original problem */
1991    )
1992 {
1993    SCIP_VAR** vars;
1994    SCIP_Real solval;
1995    int nvars;
1996    int v;
1997 
1998    assert(sol != NULL);
1999    assert(SCIPsolIsOriginal(sol));
2000    assert(origprob != NULL);
2001 
2002    vars = origprob->vars;
2003    nvars = origprob->nvars;
2004 
2005    /* recompute the objective value */
2006    sol->obj = SCIPprobGetObjoffset(origprob);
2007    for( v = 0; v < nvars; ++v )
2008    {
2009       solval = SCIPsolGetVal(sol, set, stat, vars[v]);
2010       if( !SCIPsetIsZero(set, solval) && solval != SCIP_UNKNOWN ) /*lint !e777*/
2011       {
2012          sol->obj += SCIPvarGetUnchangedObj(vars[v]) * solval;
2013       }
2014    }
2015 
2016    if( SCIPsetIsInfinity(set, -sol->obj) )
2017       sol->obj = -SCIPsetInfinity(set);
2018 }
2019 
2020 /** returns whether the given solutions are equal */
SCIPsolsAreEqual(SCIP_SOL * sol1,SCIP_SOL * sol2,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * origprob,SCIP_PROB * transprob)2021 SCIP_Bool SCIPsolsAreEqual(
2022    SCIP_SOL*             sol1,               /**< first primal CIP solution */
2023    SCIP_SOL*             sol2,               /**< second primal CIP solution */
2024    SCIP_SET*             set,                /**< global SCIP settings */
2025    SCIP_STAT*            stat,               /**< problem statistics data */
2026    SCIP_PROB*            origprob,           /**< original problem */
2027    SCIP_PROB*            transprob           /**< transformed problem after presolve, or NULL if both solution are
2028                                               *   defined in the original problem space */
2029    )
2030 {
2031    SCIP_PROB* prob;
2032    SCIP_Bool infobjs;
2033    SCIP_Real obj1;
2034    SCIP_Real obj2;
2035    int v;
2036 
2037    assert(sol1 != NULL);
2038    assert(sol2 != NULL);
2039    assert((SCIPsolIsOriginal(sol1) && SCIPsolIsOriginal(sol2)) || transprob != NULL);
2040 
2041    /* if both solutions are original or both are transformed, take the objective values stored in the solutions */
2042    if( SCIPsolIsOriginal(sol1) == SCIPsolIsOriginal(sol2) )
2043    {
2044       obj1 = sol1->obj;
2045       obj2 = sol2->obj;
2046    }
2047    /* one solution is original and the other not, so we have to get for both the objective in the transformed problem */
2048    else
2049    {
2050       obj1 = SCIPsolGetObj(sol1, set, transprob, origprob);
2051       obj2 = SCIPsolGetObj(sol2, set, transprob, origprob);
2052    }
2053 
2054    /* solutions with different objective values cannot be the same; we consider two infinite objective values with the
2055     * same sign always to be different
2056     */
2057    infobjs = (SCIPsetIsInfinity(set, obj1) && SCIPsetIsInfinity(set, obj2))
2058       || (SCIPsetIsInfinity(set, -obj1) && SCIPsetIsInfinity(set, -obj2));
2059    if( !infobjs && !SCIPsetIsEQ(set, obj1, obj2) )
2060       return FALSE;
2061 
2062    /* if one of the solutions is defined in the original space, the comparison has to be performed in the original
2063     * space
2064     */
2065    prob = transprob;
2066    if( SCIPsolIsOriginal(sol1) || SCIPsolIsOriginal(sol2) )
2067       prob = origprob;
2068    assert(prob != NULL);
2069 
2070    /* compare each variable value */
2071    for( v = 0; v < prob->nvars; ++v )
2072    {
2073       SCIP_Real val1;
2074       SCIP_Real val2;
2075 
2076       val1 = SCIPsolGetVal(sol1, set, stat, prob->vars[v]);
2077       val2 = SCIPsolGetVal(sol2, set, stat, prob->vars[v]);
2078       if( !SCIPsetIsEQ(set, val1, val2) )
2079          return FALSE;
2080    }
2081 
2082    return TRUE;
2083 }
2084 
2085 /** outputs non-zero elements of solution to file stream */
SCIPsolPrint(SCIP_SOL * sol,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_PROB * transprob,FILE * file,SCIP_Bool mipstart,SCIP_Bool printzeros)2086 SCIP_RETCODE SCIPsolPrint(
2087    SCIP_SOL*             sol,                /**< primal CIP solution */
2088    SCIP_SET*             set,                /**< global SCIP settings */
2089    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
2090    SCIP_STAT*            stat,               /**< problem statistics data */
2091    SCIP_PROB*            prob,               /**< problem data (original or transformed) */
2092    SCIP_PROB*            transprob,          /**< transformed problem data or NULL (to display priced variables) */
2093    FILE*                 file,               /**< output file (or NULL for standard output) */
2094    SCIP_Bool             mipstart,           /**< should only discrete variables be printed? */
2095    SCIP_Bool             printzeros          /**< should variables set to zero be printed? */
2096    )
2097 {
2098    SCIP_Real solval;
2099    int v;
2100 
2101    assert(sol != NULL);
2102    assert(prob != NULL);
2103    assert(SCIPsolIsOriginal(sol) || prob->transformed || transprob != NULL);
2104    assert(!mipstart || !SCIPsolIsPartial(sol));
2105 
2106    /* display variables of problem data */
2107    for( v = 0; v < prob->nfixedvars; ++v )
2108    {
2109       assert(prob->fixedvars[v] != NULL);
2110 
2111       /* skip non-discrete variables in a mip start */
2112       if( mipstart && !SCIPvarIsIntegral(prob->fixedvars[v]) )
2113          continue;
2114 
2115       solval = SCIPsolGetVal(sol, set, stat, prob->fixedvars[v]);
2116       if( printzeros || mipstart
2117          || (sol->solorigin != SCIP_SOLORIGIN_PARTIAL && !SCIPsetIsZero(set, solval))
2118          || (sol->solorigin == SCIP_SOLORIGIN_PARTIAL && solval != SCIP_UNKNOWN) ) /*lint !e777*/
2119       {
2120          SCIPmessageFPrintInfo(messagehdlr, file, "%-32s", SCIPvarGetName(prob->fixedvars[v]));
2121          if( solval == SCIP_UNKNOWN ) /*lint !e777*/
2122             SCIPmessageFPrintInfo(messagehdlr, file, "              unknown");
2123          else if( SCIPsetIsInfinity(set, solval) )
2124             SCIPmessageFPrintInfo(messagehdlr, file, "            +infinity");
2125          else if( SCIPsetIsInfinity(set, -solval) )
2126             SCIPmessageFPrintInfo(messagehdlr, file, "            -infinity");
2127          else
2128             SCIPmessageFPrintInfo(messagehdlr, file, " % 20.15g", solval);
2129          SCIPmessageFPrintInfo(messagehdlr, file, " \t(obj:%.15g)\n", SCIPvarGetUnchangedObj(prob->fixedvars[v]));
2130       }
2131    }
2132 
2133    for( v = 0; v < prob->nvars; ++v )
2134    {
2135       assert(prob->vars[v] != NULL);
2136 
2137       /* skip non-discrete variables in a mip start */
2138       if( mipstart && !SCIPvarIsIntegral(prob->vars[v]) )
2139          continue;
2140 
2141       solval = SCIPsolGetVal(sol, set, stat, prob->vars[v]);
2142       if( printzeros || mipstart
2143          || (sol->solorigin != SCIP_SOLORIGIN_PARTIAL && !SCIPsetIsZero(set, solval))
2144          || (sol->solorigin == SCIP_SOLORIGIN_PARTIAL && solval != SCIP_UNKNOWN) ) /*lint !e777*/
2145       {
2146          SCIPmessageFPrintInfo(messagehdlr, file, "%-32s", SCIPvarGetName(prob->vars[v]));
2147          if( solval == SCIP_UNKNOWN ) /*lint !e777*/
2148             SCIPmessageFPrintInfo(messagehdlr, file, "              unknown");
2149          else if( SCIPsetIsInfinity(set, solval) )
2150             SCIPmessageFPrintInfo(messagehdlr, file, "            +infinity");
2151          else if( SCIPsetIsInfinity(set, -solval) )
2152             SCIPmessageFPrintInfo(messagehdlr, file, "            -infinity");
2153          else
2154             SCIPmessageFPrintInfo(messagehdlr, file, " %20.15g", solval);
2155          SCIPmessageFPrintInfo(messagehdlr, file, " \t(obj:%.15g)\n", SCIPvarGetUnchangedObj(prob->vars[v]));
2156       }
2157    }
2158 
2159    /* display additional priced variables (if given problem data is original problem); consider these variables only
2160     * if there is at least one active pricer, otherwise we might print variables that have been added by, e.g., the
2161     * dual sparsify presolver (see #2946)
2162     */
2163    if( !prob->transformed && !SCIPsolIsOriginal(sol) && set->nactivepricers > 0 )
2164    {
2165       assert(transprob != NULL);
2166       for( v = 0; v < transprob->nfixedvars; ++v )
2167       {
2168          assert(transprob->fixedvars[v] != NULL);
2169          if( SCIPvarIsTransformedOrigvar(transprob->fixedvars[v]) )
2170             continue;
2171 
2172          /* skip non-discrete variables in a mip start */
2173          if( mipstart && !SCIPvarIsIntegral(transprob->fixedvars[v]) )
2174             continue;
2175 
2176          solval = SCIPsolGetVal(sol, set, stat, transprob->fixedvars[v]);
2177          if( printzeros || mipstart || !SCIPsetIsZero(set, solval) )
2178          {
2179             SCIPmessageFPrintInfo(messagehdlr, file, "%-32s", SCIPvarGetName(transprob->fixedvars[v]));
2180             if( solval == SCIP_UNKNOWN ) /*lint !e777*/
2181                SCIPmessageFPrintInfo(messagehdlr, file, "              unknown");
2182             else if( SCIPsetIsInfinity(set, solval) )
2183                SCIPmessageFPrintInfo(messagehdlr, file, "            +infinity");
2184             else if( SCIPsetIsInfinity(set, -solval) )
2185                SCIPmessageFPrintInfo(messagehdlr, file, "            -infinity");
2186             else
2187                SCIPmessageFPrintInfo(messagehdlr, file, " % 20.15g", solval);
2188             SCIPmessageFPrintInfo(messagehdlr, file, " \t(obj:%.15g)\n", SCIPvarGetUnchangedObj(transprob->fixedvars[v]));
2189          }
2190       }
2191       for( v = 0; v < transprob->nvars; ++v )
2192       {
2193          assert(transprob->vars[v] != NULL);
2194          if( SCIPvarIsTransformedOrigvar(transprob->vars[v]) )
2195             continue;
2196 
2197          /* skip non-discrete variables in a mip start */
2198          if( mipstart && !SCIPvarIsIntegral(transprob->vars[v]) )
2199             continue;
2200 
2201          solval = SCIPsolGetVal(sol, set, stat, transprob->vars[v]);
2202          if( printzeros || !SCIPsetIsZero(set, solval) )
2203          {
2204             SCIPmessageFPrintInfo(messagehdlr, file, "%-32s", SCIPvarGetName(transprob->vars[v]));
2205             if( solval == SCIP_UNKNOWN ) /*lint !e777*/
2206                SCIPmessageFPrintInfo(messagehdlr, file, "              unknown");
2207             else if( SCIPsetIsInfinity(set, solval) )
2208                SCIPmessageFPrintInfo(messagehdlr, file, "            +infinity");
2209             else if( SCIPsetIsInfinity(set, -solval) )
2210                SCIPmessageFPrintInfo(messagehdlr, file, "            -infinity");
2211             else
2212                SCIPmessageFPrintInfo(messagehdlr, file, " % 20.15g", solval);
2213             SCIPmessageFPrintInfo(messagehdlr, file, " \t(obj:%.15g)\n", SCIPvarGetUnchangedObj(transprob->vars[v]));
2214          }
2215       }
2216    }
2217 
2218    return SCIP_OKAY;
2219 }
2220 
2221 /** outputs non-zero elements of solution representing a ray to file stream */
SCIPsolPrintRay(SCIP_SOL * sol,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_PROB * transprob,FILE * file,SCIP_Bool printzeros)2222 SCIP_RETCODE SCIPsolPrintRay(
2223    SCIP_SOL*             sol,                /**< primal CIP solution */
2224    SCIP_SET*             set,                /**< global SCIP settings */
2225    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
2226    SCIP_STAT*            stat,               /**< problem statistics data */
2227    SCIP_PROB*            prob,               /**< problem data (original or transformed) */
2228    SCIP_PROB*            transprob,          /**< transformed problem data or NULL (to display priced variables) */
2229    FILE*                 file,               /**< output file (or NULL for standard output) */
2230    SCIP_Bool             printzeros          /**< should variables set to zero be printed? */
2231    )
2232 {
2233    SCIP_Real solval;
2234    int v;
2235 
2236    assert(sol != NULL);
2237    assert(prob != NULL);
2238    assert(SCIPsolIsOriginal(sol) || prob->transformed || transprob != NULL);
2239 
2240    /* display variables of problem data */
2241    for( v = 0; v < prob->nfixedvars; ++v )
2242    {
2243       assert(prob->fixedvars[v] != NULL);
2244       solval = SCIPsolGetRayVal(sol, set, stat, prob->fixedvars[v]);
2245       if( printzeros || !SCIPsetIsZero(set, solval) )
2246       {
2247          SCIPmessageFPrintInfo(messagehdlr, file, "%-32s", SCIPvarGetName(prob->fixedvars[v]));
2248          if( solval == SCIP_UNKNOWN ) /*lint !e777*/
2249             SCIPmessageFPrintInfo(messagehdlr, file, "              unknown");
2250          else if( SCIPsetIsInfinity(set, solval) )
2251             SCIPmessageFPrintInfo(messagehdlr, file, "            +infinity");
2252          else if( SCIPsetIsInfinity(set, -solval) )
2253             SCIPmessageFPrintInfo(messagehdlr, file, "            -infinity");
2254          else
2255             SCIPmessageFPrintInfo(messagehdlr, file, " % 20.15g", solval);
2256          SCIPmessageFPrintInfo(messagehdlr, file, " \t(obj:%.15g)\n", SCIPvarGetUnchangedObj(prob->fixedvars[v]));
2257       }
2258    }
2259    for( v = 0; v < prob->nvars; ++v )
2260    {
2261       assert(prob->vars[v] != NULL);
2262       solval = SCIPsolGetRayVal(sol, set, stat, prob->vars[v]);
2263       if( printzeros || !SCIPsetIsZero(set, solval) )
2264       {
2265          SCIPmessageFPrintInfo(messagehdlr, file, "%-32s", SCIPvarGetName(prob->vars[v]));
2266          if( solval == SCIP_UNKNOWN ) /*lint !e777*/
2267             SCIPmessageFPrintInfo(messagehdlr, file, "              unknown");
2268          else if( SCIPsetIsInfinity(set, solval) )
2269             SCIPmessageFPrintInfo(messagehdlr, file, "            +infinity");
2270          else if( SCIPsetIsInfinity(set, -solval) )
2271             SCIPmessageFPrintInfo(messagehdlr, file, "            -infinity");
2272          else
2273             SCIPmessageFPrintInfo(messagehdlr, file, " %20.15g", solval);
2274          SCIPmessageFPrintInfo(messagehdlr, file, " \t(obj:%.15g)\n", SCIPvarGetUnchangedObj(prob->vars[v]));
2275       }
2276    }
2277 
2278    /* display additional priced variables (if given problem data is original problem) */
2279    if( !prob->transformed && !SCIPsolIsOriginal(sol) )
2280    {
2281       assert(transprob != NULL);
2282       for( v = 0; v < transprob->nfixedvars; ++v )
2283       {
2284          assert(transprob->fixedvars[v] != NULL);
2285          if( SCIPvarIsTransformedOrigvar(transprob->fixedvars[v]) )
2286             continue;
2287 
2288          solval = SCIPsolGetRayVal(sol, set, stat, transprob->fixedvars[v]);
2289          if( printzeros || !SCIPsetIsZero(set, solval) )
2290          {
2291             SCIPmessageFPrintInfo(messagehdlr, file, "%-32s", SCIPvarGetName(transprob->fixedvars[v]));
2292             if( solval == SCIP_UNKNOWN ) /*lint !e777*/
2293                SCIPmessageFPrintInfo(messagehdlr, file, "              unknown");
2294             else if( SCIPsetIsInfinity(set, solval) )
2295                SCIPmessageFPrintInfo(messagehdlr, file, "            +infinity");
2296             else if( SCIPsetIsInfinity(set, -solval) )
2297                SCIPmessageFPrintInfo(messagehdlr, file, "            -infinity");
2298             else
2299                SCIPmessageFPrintInfo(messagehdlr, file, " % 20.15g", solval);
2300             SCIPmessageFPrintInfo(messagehdlr, file, " \t(obj:%.15g)\n", SCIPvarGetUnchangedObj(transprob->fixedvars[v]));
2301          }
2302       }
2303       for( v = 0; v < transprob->nvars; ++v )
2304       {
2305          assert(transprob->vars[v] != NULL);
2306          if( SCIPvarIsTransformedOrigvar(transprob->vars[v]) )
2307             continue;
2308 
2309          solval = SCIPsolGetRayVal(sol, set, stat, transprob->vars[v]);
2310          if( printzeros || !SCIPsetIsZero(set, solval) )
2311          {
2312             SCIPmessageFPrintInfo(messagehdlr, file, "%-32s", SCIPvarGetName(transprob->vars[v]));
2313             if( solval == SCIP_UNKNOWN ) /*lint !e777*/
2314                SCIPmessageFPrintInfo(messagehdlr, file, "              unknown");
2315             else if( SCIPsetIsInfinity(set, solval) )
2316                SCIPmessageFPrintInfo(messagehdlr, file, "            +infinity");
2317             else if( SCIPsetIsInfinity(set, -solval) )
2318                SCIPmessageFPrintInfo(messagehdlr, file, "            -infinity");
2319             else
2320                SCIPmessageFPrintInfo(messagehdlr, file, " % 20.15g", solval);
2321             SCIPmessageFPrintInfo(messagehdlr, file, " \t(obj:%.15g)\n", SCIPvarGetUnchangedObj(transprob->vars[v]));
2322          }
2323       }
2324    }
2325 
2326    return SCIP_OKAY;
2327 }
2328 
2329 /*
2330  * methods for accumulated numerical violations of a solution
2331  */
2332 
2333 /** reset violations of a solution */
SCIPsolResetViolations(SCIP_SOL * sol)2334 void SCIPsolResetViolations(
2335    SCIP_SOL*             sol                 /**< primal CIP solution */
2336    )
2337 {
2338    assert(sol != NULL);
2339 
2340    sol->viol.absviolbounds = 0.0;
2341    sol->viol.relviolbounds = 0.0;
2342    sol->viol.absviolintegrality = 0.0;
2343    sol->viol.absviollprows = 0.0;
2344    sol->viol.relviollprows = 0.0;
2345    sol->viol.absviolcons = 0.0;
2346    sol->viol.relviolcons = 0.0;
2347 }
2348 
2349 /** update integrality violation of a solution */
SCIPsolUpdateIntegralityViolation(SCIP_SOL * sol,SCIP_Real absviolintegrality)2350 void SCIPsolUpdateIntegralityViolation(
2351    SCIP_SOL*             sol,                /**< primal CIP solution */
2352    SCIP_Real             absviolintegrality  /**< absolute violation of integrality */
2353    )
2354 {
2355    assert(sol != NULL);
2356 
2357    sol->viol.absviolintegrality = MAX(sol->viol.absviolintegrality, absviolintegrality);
2358 }
2359 
2360 /** update bound violation of a solution */
SCIPsolUpdateBoundViolation(SCIP_SOL * sol,SCIP_Real absviolbounds,SCIP_Real relviolbounds)2361 void SCIPsolUpdateBoundViolation(
2362    SCIP_SOL*             sol,                /**< primal CIP solution */
2363    SCIP_Real             absviolbounds,      /**< absolute violation of bounds */
2364    SCIP_Real             relviolbounds       /**< relative violation of bounds */
2365    )
2366 {
2367    assert(sol != NULL);
2368 
2369    sol->viol.absviolbounds = MAX(sol->viol.absviolbounds, absviolbounds);
2370    sol->viol.relviolbounds = MAX(sol->viol.relviolbounds, relviolbounds);
2371 }
2372 
2373 /** update LP row violation of a solution */
SCIPsolUpdateLPRowViolation(SCIP_SOL * sol,SCIP_Real absviollprows,SCIP_Real relviollprows)2374 void SCIPsolUpdateLPRowViolation(
2375    SCIP_SOL*             sol,                /**< primal CIP solution */
2376    SCIP_Real             absviollprows,      /**< absolute violation of LP rows */
2377    SCIP_Real             relviollprows       /**< relative violation of LP rows */
2378    )
2379 {
2380    assert(sol != NULL);
2381 
2382    sol->viol.absviollprows = MAX(sol->viol.absviollprows, absviollprows);
2383    sol->viol.relviollprows = MAX(sol->viol.relviollprows, relviollprows);
2384 }
2385 
2386 /** update constraint violation of a solution */
SCIPsolUpdateConsViolation(SCIP_SOL * sol,SCIP_Real absviolcons,SCIP_Real relviolcons)2387 void SCIPsolUpdateConsViolation(
2388    SCIP_SOL*             sol,                /**< primal CIP solution */
2389    SCIP_Real             absviolcons,        /**< absolute violation of constraint */
2390    SCIP_Real             relviolcons         /**< relative violation of constraint */
2391    )
2392 {
2393    assert(sol != NULL);
2394 
2395    sol->viol.absviolcons = MAX(sol->viol.absviolcons, absviolcons);
2396    sol->viol.relviolcons = MAX(sol->viol.relviolcons, relviolcons);
2397 }
2398 
2399 /** update violation of a constraint that is represented in the LP */
SCIPsolUpdateLPConsViolation(SCIP_SOL * sol,SCIP_Real absviol,SCIP_Real relviol)2400 void SCIPsolUpdateLPConsViolation(
2401    SCIP_SOL*             sol,                /**< primal CIP solution */
2402    SCIP_Real             absviol,            /**< absolute violation of constraint */
2403    SCIP_Real             relviol             /**< relative violation of constraint */
2404    )
2405 {
2406    assert(sol != NULL);
2407 
2408    SCIPsolUpdateConsViolation(sol, absviol, relviol);
2409    SCIPsolUpdateLPRowViolation(sol, absviol, relviol);
2410 }
2411 
2412 /** get maximum absolute bound violation of solution */
SCIPsolGetAbsBoundViolation(SCIP_SOL * sol)2413 SCIP_Real SCIPsolGetAbsBoundViolation(
2414    SCIP_SOL*             sol                 /**< primal CIP solution */
2415    )
2416 {
2417    assert(sol != NULL);
2418 
2419    return sol->viol.absviolbounds;
2420 }
2421 
2422 /** get maximum relative bound violation of solution */
SCIPsolGetRelBoundViolation(SCIP_SOL * sol)2423 SCIP_Real SCIPsolGetRelBoundViolation(
2424    SCIP_SOL*             sol                 /**< primal CIP solution */
2425    )
2426 {
2427    assert(sol != NULL);
2428 
2429    return sol->viol.relviolbounds;
2430 }
2431 
2432 /** get maximum absolute integrality violation of solution */
SCIPsolGetAbsIntegralityViolation(SCIP_SOL * sol)2433 SCIP_Real SCIPsolGetAbsIntegralityViolation(
2434    SCIP_SOL*             sol                 /**< primal CIP solution */
2435    )
2436 {
2437    assert(sol != NULL);
2438 
2439    return sol->viol.absviolintegrality;
2440 }
2441 
2442 /** get maximum absolute LP row violation of solution */
SCIPsolGetAbsLPRowViolation(SCIP_SOL * sol)2443 SCIP_Real SCIPsolGetAbsLPRowViolation(
2444    SCIP_SOL*             sol                 /**< primal CIP solution */
2445    )
2446 {
2447    assert(sol != NULL);
2448 
2449    return sol->viol.absviollprows;
2450 }
2451 
2452 /** get maximum relative LP row violation of solution */
SCIPsolGetRelLPRowViolation(SCIP_SOL * sol)2453 SCIP_Real SCIPsolGetRelLPRowViolation(
2454    SCIP_SOL*             sol                 /**< primal CIP solution */
2455    )
2456 {
2457    assert(sol != NULL);
2458 
2459    return sol->viol.relviollprows;
2460 }
2461 
2462 /** get maximum absolute constraint violation of solution */
SCIPsolGetAbsConsViolation(SCIP_SOL * sol)2463 SCIP_Real SCIPsolGetAbsConsViolation(
2464    SCIP_SOL*             sol                 /**< primal CIP solution */
2465    )
2466 {
2467    assert(sol != NULL);
2468 
2469    return sol->viol.absviolcons;
2470 }
2471 
2472 /** get maximum relative constraint violation of solution */
SCIPsolGetRelConsViolation(SCIP_SOL * sol)2473 SCIP_Real SCIPsolGetRelConsViolation(
2474    SCIP_SOL*             sol                 /**< primal CIP solution */
2475    )
2476 {
2477    assert(sol != NULL);
2478 
2479    return sol->viol.relviolcons;
2480 }
2481 
2482 /*
2483  * simple functions implemented as defines
2484  */
2485 
2486 /* In debug mode, the following methods are implemented as function calls to ensure
2487  * type validity.
2488  * In optimized mode, the methods are implemented as defines to improve performance.
2489  * However, we want to have them in the library anyways, so we have to undef the defines.
2490  */
2491 
2492 #undef SCIPsolGetOrigin
2493 #undef SCIPsolIsOriginal
2494 #undef SCIPsolGetOrigObj
2495 #undef SCIPsolGetTime
2496 #undef SCIPsolGetNodenum
2497 #undef SCIPsolGetRunnum
2498 #undef SCIPsolGetDepth
2499 #undef SCIPsolGetHeur
2500 #undef SCIPsolGetRelax
2501 #undef SCIPsolOrigAddObjval
2502 #undef SCIPsolGetPrimalIndex
2503 #undef SCIPsolSetPrimalIndex
2504 #undef SCIPsolGetIndex
2505 #undef SCIPsolGetType
2506 #undef SCIPsolSetLPRelaxation
2507 #undef SCIPsolSetStrongbranching
2508 #undef SCIPsolSetPseudo
2509 
2510 /** gets origin of solution */
SCIPsolGetOrigin(SCIP_SOL * sol)2511 SCIP_SOLORIGIN SCIPsolGetOrigin(
2512    SCIP_SOL*             sol                 /**< primal CIP solution */
2513    )
2514 {
2515    assert(sol != NULL);
2516 
2517    return sol->solorigin;
2518 }
2519 
2520 /** returns whether the given solution is defined on original variables */
SCIPsolIsOriginal(SCIP_SOL * sol)2521 SCIP_Bool SCIPsolIsOriginal(
2522    SCIP_SOL*             sol                 /**< primal CIP solution */
2523    )
2524 {
2525    assert(sol != NULL);
2526 
2527    return (sol->solorigin == SCIP_SOLORIGIN_ORIGINAL || sol->solorigin == SCIP_SOLORIGIN_PARTIAL);
2528 }
2529 
2530 /** returns whether the given solution is defined on original variables and containes unknown solution values */
SCIPsolIsPartial(SCIP_SOL * sol)2531 SCIP_Bool SCIPsolIsPartial(
2532    SCIP_SOL*             sol                 /**< primal CIP solution */
2533    )
2534 {
2535    assert(sol != NULL);
2536 
2537    return (sol->solorigin == SCIP_SOLORIGIN_PARTIAL);
2538 }
2539 
2540 /** gets objective value of primal CIP solution which lives in the original problem space */
SCIPsolGetOrigObj(SCIP_SOL * sol)2541 SCIP_Real SCIPsolGetOrigObj(
2542    SCIP_SOL*             sol                 /**< primal CIP solution */
2543    )
2544 {
2545    assert(sol != NULL);
2546    assert(SCIPsolIsOriginal(sol));
2547 
2548    return sol->obj;
2549 }
2550 
2551 /** adds value to the objective value of a given original primal CIP solution */
SCIPsolOrigAddObjval(SCIP_SOL * sol,SCIP_Real addval)2552 void SCIPsolOrigAddObjval(
2553    SCIP_SOL*             sol,                /**< primal CIP solution */
2554    SCIP_Real             addval              /**< offset value to add */
2555    )
2556 {
2557    assert(sol != NULL);
2558    assert(sol->solorigin == SCIP_SOLORIGIN_ORIGINAL);
2559 
2560    sol->obj += addval;
2561 }
2562 
2563 /** gets clock time, when this solution was found */
SCIPsolGetTime(SCIP_SOL * sol)2564 SCIP_Real SCIPsolGetTime(
2565    SCIP_SOL*             sol                 /**< primal CIP solution */
2566    )
2567 {
2568    assert(sol != NULL);
2569 
2570    return sol->time;
2571 }
2572 
2573 /** gets branch and bound run number, where this solution was found */
SCIPsolGetRunnum(SCIP_SOL * sol)2574 int SCIPsolGetRunnum(
2575    SCIP_SOL*             sol                 /**< primal CIP solution */
2576    )
2577 {
2578    assert(sol != NULL);
2579 
2580    return sol->runnum;
2581 }
2582 
2583 /** gets node number, where this solution was found */
SCIPsolGetNodenum(SCIP_SOL * sol)2584 SCIP_Longint SCIPsolGetNodenum(
2585    SCIP_SOL*             sol                 /**< primal CIP solution */
2586    )
2587 {
2588    assert(sol != NULL);
2589 
2590    return sol->nodenum;
2591 }
2592 
2593 /** gets node's depth, where this solution was found */
SCIPsolGetDepth(SCIP_SOL * sol)2594 int SCIPsolGetDepth(
2595    SCIP_SOL*             sol                 /**< primal CIP solution */
2596    )
2597 {
2598    assert(sol != NULL);
2599 
2600    return sol->depth;
2601 }
2602 
2603 /** gets heuristic, that found this solution or NULL if solution has type different than SCIP_SOLTYPE_HEUR */
SCIPsolGetHeur(SCIP_SOL * sol)2604 SCIP_HEUR* SCIPsolGetHeur(
2605    SCIP_SOL*             sol                 /**< primal CIP solution */
2606    )
2607 {
2608    assert(sol != NULL);
2609 
2610    return sol->type == SCIP_SOLTYPE_HEUR ? sol->creator.heur : NULL;
2611 }
2612 
2613 /** gets current position of solution in array of existing solutions of primal data */
SCIPsolGetPrimalIndex(SCIP_SOL * sol)2614 int SCIPsolGetPrimalIndex(
2615    SCIP_SOL*             sol                 /**< primal CIP solution */
2616    )
2617 {
2618    assert(sol != NULL);
2619 
2620    return sol->primalindex;
2621 }
2622 
2623 /** sets current position of solution in array of existing solutions of primal data */
SCIPsolSetPrimalIndex(SCIP_SOL * sol,int primalindex)2624 void SCIPsolSetPrimalIndex(
2625    SCIP_SOL*             sol,                /**< primal CIP solution */
2626    int                   primalindex         /**< new primal index of solution */
2627    )
2628 {
2629    assert(sol != NULL);
2630 
2631    sol->primalindex = primalindex;
2632 }
2633 
2634 /** returns unique index of given solution */
SCIPsolGetIndex(SCIP_SOL * sol)2635 int SCIPsolGetIndex(
2636    SCIP_SOL*             sol                 /**< primal CIP solution */
2637    )
2638 {
2639    assert(sol != NULL);
2640 
2641    return sol->index;
2642 }
2643 
2644 /** informs the solution that it now belongs to the given primal heuristic. For convenience and backwards compatibility,
2645  *  the method accepts NULL as input for \p heur, in which case the solution type is set to SCIP_SOLTYPE_LPRELAX.
2646  *
2647  *  @note Relaxation handlers should use SCIPsolSetRelax() instead.
2648  */
SCIPsolSetHeur(SCIP_SOL * sol,SCIP_HEUR * heur)2649 void SCIPsolSetHeur(
2650    SCIP_SOL*             sol,                /**< primal CIP solution */
2651    SCIP_HEUR*            heur                /**< primal heuristic that found the solution, or NULL for LP solutions */
2652    )
2653 {
2654    assert(sol != NULL);
2655 
2656    if( heur == NULL )
2657       SCIPsolSetLPRelaxation(sol);
2658    else
2659    {
2660       sol->type = SCIP_SOLTYPE_HEUR;
2661       sol->creator.heur = heur;
2662    }
2663 }
2664 
2665 /** gets information if solution was found by the LP, a primal heuristic, or a custom relaxator */
SCIPsolGetType(SCIP_SOL * sol)2666 SCIP_SOLTYPE SCIPsolGetType(
2667    SCIP_SOL*             sol                 /**< primal CIP solution */
2668    )
2669 {
2670    assert(sol != NULL);
2671 
2672    return sol->type;
2673 }
2674 
2675 /** gets relaxation handler that found this solution, or NULL if solution has different type than SCIP_SOLTYPE_RELAX */
SCIPsolGetRelax(SCIP_SOL * sol)2676 SCIP_RELAX* SCIPsolGetRelax(
2677    SCIP_SOL*             sol                 /**< primal CIP solution */
2678    )
2679 {
2680    assert(sol != NULL);
2681 
2682    return sol->type == SCIP_SOLTYPE_RELAX ? sol->creator.relax : NULL;
2683 }
2684 
2685 /** informs the solution that it now belongs to the given relaxation handler */
SCIPsolSetRelax(SCIP_SOL * sol,SCIP_RELAX * relax)2686 void SCIPsolSetRelax(
2687    SCIP_SOL*             sol,                /**< primal CIP solution */
2688    SCIP_RELAX*           relax               /**< relaxator that found the solution */
2689    )
2690 {
2691    assert(sol != NULL);
2692    assert(relax != NULL);
2693 
2694    sol->type = SCIP_SOLTYPE_RELAX;
2695    sol->creator.relax = relax;
2696 }
2697 
2698 /** informs the solution that it is an LP relaxation solution */
SCIPsolSetLPRelaxation(SCIP_SOL * sol)2699 void SCIPsolSetLPRelaxation(
2700    SCIP_SOL*             sol                 /**< primal CIP solution */
2701    )
2702 {
2703    assert(sol != NULL);
2704 
2705    sol->type = SCIP_SOLTYPE_LPRELAX;
2706 }
2707 
2708 /** informs the solution that it is a solution found during strong branching */
SCIPsolSetStrongbranching(SCIP_SOL * sol)2709 void SCIPsolSetStrongbranching(
2710    SCIP_SOL*             sol                 /**< primal CIP solution */
2711    )
2712 {
2713    assert(sol != NULL);
2714 
2715    sol->type = SCIP_SOLTYPE_STRONGBRANCH;
2716 }
2717 
2718 /** informs the solution that it originates from a pseudo solution */
SCIPsolSetPseudo(SCIP_SOL * sol)2719 void SCIPsolSetPseudo(
2720    SCIP_SOL*             sol                 /**< primal CIP solution */
2721    )
2722 {
2723    assert(sol != NULL);
2724 
2725    sol->type = SCIP_SOLTYPE_PSEUDO;
2726 }
2727 
2728