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