Scippy

SCIP

Solving Constraint Integer Programs

heur_bound.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2019 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 scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file heur_bound.c
17  * @brief heuristic which fixes all integer variables to a bound (lower/upper) and solves the remaining LP
18  * @author Gerald Gamrath
19  *
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include "scip/heur_bound.h"
25 #include "scip/pub_heur.h"
26 #include "scip/pub_message.h"
27 #include "scip/pub_tree.h"
28 #include "scip/pub_var.h"
29 #include "scip/scip_branch.h"
30 #include "scip/scip_general.h"
31 #include "scip/scip_heur.h"
32 #include "scip/scip_lp.h"
33 #include "scip/scip_mem.h"
34 #include "scip/scip_message.h"
35 #include "scip/scip_numerics.h"
36 #include "scip/scip_param.h"
37 #include "scip/scip_prob.h"
38 #include "scip/scip_probing.h"
39 #include "scip/scip_sol.h"
40 #include "scip/scip_solvingstats.h"
41 #include "scip/scip_timing.h"
42 #include "scip/scip_tree.h"
43 #include <string.h>
44 
45 #ifdef SCIP_STATISTIC
46 #include "scip/clock.h"
47 #endif
48 
49 #define HEUR_NAME "bound"
50 #define HEUR_DESC "heuristic which fixes all integer variables to a bound and solves the remaining LP"
51 #define HEUR_DISPCHAR 'H'
52 #define HEUR_PRIORITY -1107000
53 #define HEUR_FREQ -1
54 #define HEUR_FREQOFS 0
55 #define HEUR_MAXDEPTH -1
56 #define HEUR_TIMING SCIP_HEURTIMING_BEFORENODE
57 #define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
58 
59 #define DEFAULT_ONLYWITHOUTSOL TRUE /**< Should heuristic only be executed if no primal solution was found, yet? */
60 #define DEFAULT_MAXPROPROUNDS 0 /* maximum number of propagation rounds during probing */
61 #define DEFAULT_BOUND 'l' /**< to which bound should integer variables be fixed? */
62 
63 
64 /*
65  * Data structures
66  */
67 
68 /** primal heuristic data */
69 struct SCIP_HeurData
70 {
71  SCIP_Bool onlywithoutsol; /**< Should heuristic only be executed if no primal solution was found, yet? */
72  int maxproprounds; /**< maximum number of propagation rounds during probing */
73  char bound; /**< to which bound should integer variables be fixed? */
74 };
75 
76 /*
77  * Local methods
78  */
79 
80 /** main procedure of the bound heuristic */
81 static
83  SCIP* scip, /**< original SCIP data structure */
84  SCIP_HEUR* heur, /**< heuristic */
85  SCIP_HEURDATA* heurdata, /**< heuristic data structure */
86  SCIP_Bool lower, /**< should integer variables be fixed to their lower bound? */
87  SCIP_RESULT* result /**< pointer to store the result */
88  )
89 {
90  SCIP_VAR** vars;
91  SCIP_VAR* var;
92  SCIP_Bool infeasible = FALSE;
93  int maxproprounds;
94  int nbinvars;
95  int nintvars;
96  int nvars;
97  int v;
98 
99  /* get variable data of original problem */
100  SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, &nintvars, NULL, NULL) );
101 
102  maxproprounds = heurdata->maxproprounds;
103  if( maxproprounds == -2 )
104  maxproprounds = 0;
105 
106  /* only look at binary and integer variables */
107  nvars = nbinvars + nintvars;
108 
109  /* stop if we would have infinite fixings */
110  if( lower )
111  {
112  for( v = 0; v < nvars; ++v )
113  {
114  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(vars[v])) )
115  return SCIP_OKAY;
116  }
117  }
118  else
119  {
120  for( v = 0; v < nvars; ++v )
121  {
122  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(vars[v])) )
123  return SCIP_OKAY;
124  }
125  }
126 
127  /* start probing */
128  SCIP_CALL( SCIPstartProbing(scip) );
129 
130  for( v = 0; v < nvars; ++v )
131  {
132  var = vars[v];
133 
134  assert(SCIPvarGetType(var) < SCIP_VARTYPE_IMPLINT);
135 
136  /* skip variables which are already fixed */
137  if( SCIPvarGetLbLocal(var) + 0.5 > SCIPvarGetUbLocal(var) )
138  continue;
139 
140  /* fix variable to lower bound */
141  if( lower )
142  {
143  SCIP_CALL( SCIPfixVarProbing(scip, var, SCIPvarGetLbLocal(var)) );
144  SCIPdebugMsg(scip, "fixing %d: variable <%s> to lower bound <%g> (%d pseudo cands)\n",
146  }
147  /* fix variable to upper bound */
148  else
149  {
150  SCIP_CALL( SCIPfixVarProbing(scip, var, SCIPvarGetUbLocal(var)) );
151  SCIPdebugMsg(scip, "fixing %d: variable <%s> to upper bound <%g> (%d pseudo cands)\n",
153  }
154 
155  /* propagate fixings */
156  if( heurdata->maxproprounds != 0 )
157  {
158  SCIP_CALL( SCIPpropagateProbing(scip, maxproprounds, &infeasible, NULL) );
159  }
160 
161  /* try to repair probing */
162  if( infeasible )
163  {
164 #if 0
166 
167  /* fix the last variable, which was fixed the reverse bound */
168  SCIP_CALL( SCIPfixVarProbing(scip, var, SCIPvarGetUbLocal(var)) );
169 
170  /* propagate fixings */
171  SCIP_CALL( SCIPpropagateProbing(scip, maxproprounds, &infeasible, NULL) );
172 
173  SCIPdebugMsg(scip, "backtracking ended with %sfeasible problem\n", (infeasible ? "in" : ""));
174 
175  if( infeasible )
176 #endif
177  break;
178  }
179  }
180 
181  SCIPdebugMsg(scip, "probing ended with %sfeasible problem\n", infeasible ? "in" : "");
182 
183  /*************************** Probing LP Solving ***************************/
184 
185  /* solve lp only if the problem is still feasible */
186  if( !infeasible )
187  {
188  SCIP_LPSOLSTAT lpstatus;
189  SCIP_Bool lperror;
190 
191  SCIPdebugMsg(scip, "starting solving bound-heur LP at time %g, LP iterations: %" SCIP_LONGINT_FORMAT "\n",
193 
194  /* solve LP; errors in the LP solver should not kill the overall solving process, if the LP is just needed for a
195  * heuristic. hence in optimized mode, the return code is caught and a warning is printed, only in debug mode,
196  * SCIP will stop.
197  */
198 #ifdef NDEBUG
199  {
200  SCIP_Bool retstat;
201  retstat = SCIPsolveProbingLP(scip, -1, &lperror, NULL);
202  if( retstat != SCIP_OKAY )
203  {
204  SCIPwarningMessage(scip, "Error while solving LP in bound heuristic; LP solve terminated with code <%d>\n",
205  retstat);
206  }
207  }
208 #else
209  SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, NULL) );
210 #endif
211  SCIPdebugMsg(scip, "ending solving bound-heur LP at time %g\n", SCIPgetSolvingTime(scip));
212 
213  lpstatus = SCIPgetLPSolstat(scip);
214 
215  SCIPdebugMsg(scip, " -> new LP iterations: %" SCIP_LONGINT_FORMAT "\n", SCIPgetNLPIterations(scip));
216  SCIPdebugMsg(scip, " -> error=%u, status=%d\n", lperror, lpstatus);
217 
218  /* check if this is a feasible solution */
219  if( lpstatus == SCIP_LPSOLSTAT_OPTIMAL && !lperror )
220  {
221  SCIP_SOL* newsol;
222  SCIP_Bool stored;
223  SCIP_Bool success;
224 
225  /* create temporary solution */
226  SCIP_CALL( SCIPcreateSol(scip, &newsol, heur) );
227 
228  /* copy the current LP solution to the working solution */
229  SCIP_CALL( SCIPlinkLPSol(scip, newsol) );
230 
231  SCIP_CALL( SCIProundSol(scip, newsol, &success) );
232 
233  if( success )
234  {
235  SCIPdebugMsg(scip, "bound heuristic found roundable primal solution: obj=%g\n",
236  SCIPgetSolOrigObj(scip, newsol));
237 
238  /* check solution for feasibility, and add it to solution store if possible.
239  * Neither integrality nor feasibility of LP rows have to be checked, because they
240  * are guaranteed by the heuristic at this stage.
241  */
242 #ifdef SCIP_DEBUG
243  SCIP_CALL( SCIPtrySol(scip, newsol, TRUE, TRUE, TRUE, TRUE, TRUE, &stored) );
244 #else
245  SCIP_CALL( SCIPtrySol(scip, newsol, FALSE, FALSE, TRUE, FALSE, FALSE, &stored) );
246 #endif
247 
248  if( stored )
249  {
250  SCIPdebugMsg(scip, "found feasible solution:\n");
251  *result = SCIP_FOUNDSOL;
252  }
253  }
254 
255  /* free solution */
256  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
257  }
258  }
259 
260  /* exit probing mode */
261  SCIP_CALL( SCIPendProbing(scip) );
262 
263  return SCIP_OKAY;
264 }
265 
266 
267 /*
268  * Callback methods of primal heuristic
269  */
270 
271 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
272 static
273 SCIP_DECL_HEURCOPY(heurCopyBound)
274 { /*lint --e{715}*/
275  assert(scip != NULL);
276  assert(heur != NULL);
277  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
278 
279  /* call inclusion method of heuristic */
281 
282  return SCIP_OKAY;
283 }
284 
285 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
286 static
287 SCIP_DECL_HEURFREE(heurFreeBound)
288 { /*lint --e{715}*/
289  SCIP_HEURDATA* heurdata;
290 
291  /* free heuristic data */
292  heurdata = SCIPheurGetData(heur);
293 
294  SCIPfreeBlockMemory(scip, &heurdata);
295  SCIPheurSetData(heur, NULL);
296 
297  return SCIP_OKAY;
298 }
299 
300 /** execution method of primal heuristic */
301 static
302 SCIP_DECL_HEUREXEC(heurExecBound)
303 { /*lint --e{715}*/
304  SCIP_HEURDATA* heurdata;
305 
306  assert(heur != NULL);
307  assert(scip != NULL);
308  assert(result != NULL);
309 
310  *result = SCIP_DIDNOTRUN;
311 
312  if( SCIPgetNPseudoBranchCands(scip) == 0 )
313  return SCIP_OKAY;
314 
315  if( !SCIPhasCurrentNodeLP(scip) )
316  return SCIP_OKAY;
317 
318  heurdata = SCIPheurGetData(heur);
319  assert(heurdata != NULL);
320 
321  *result = SCIP_DIDNOTFIND;
322 
323  if( SCIPisStopped(scip) )
324  return SCIP_OKAY;
325 
326  /* stop execution method if there is already a primal feasible solution at hand */
327  if( SCIPgetBestSol(scip) != NULL && heurdata->onlywithoutsol )
328  return SCIP_OKAY;
329 
330  SCIPdebugMsg(scip, "apply bound heuristic at node %lld\n",
332 
333  if( !SCIPisLPConstructed(scip) )
334  {
335  SCIP_Bool cutoff;
336 
337  SCIP_CALL( SCIPconstructLP(scip, &cutoff) );
338 
339  /* manually cut off the node if the LP construction detected infeasibility (heuristics cannot return such a result) */
340  if( cutoff )
341  {
343  return SCIP_OKAY;
344  }
345 
347  }
348 
349  if( heurdata->bound == 'l' || heurdata->bound == 'b' )
350  {
351  SCIP_CALL(applyBoundHeur(scip, heur, heurdata, TRUE, result) );
352  }
353  if( heurdata->bound == 'u' || heurdata->bound == 'b' )
354  {
355  SCIP_CALL(applyBoundHeur(scip, heur, heurdata, FALSE, result) );
356  }
357 
358  return SCIP_OKAY;
359 }
360 
361 /*
362  * primal heuristic specific interface methods
363  */
364 
365 /** creates the bound primal heuristic and includes it in SCIP */
367  SCIP* scip /**< SCIP data structure */
368  )
369 {
370  SCIP_HEURDATA* heurdata;
371  SCIP_HEUR* heur;
372 
373  /* create bound primal heuristic data */
374  SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
375 
376  /* include primal heuristic */
377  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
379  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecBound, heurdata) );
380 
381  assert(heur != NULL);
382 
383  /* set non-NULL pointers to callback methods */
384  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyBound) );
385  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeBound) );
386 
387  /* add bound heuristic parameters */
388 
389  SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/onlywithoutsol",
390  "Should heuristic only be executed if no primal solution was found, yet?",
391  &heurdata->onlywithoutsol, TRUE, DEFAULT_ONLYWITHOUTSOL, NULL, NULL) );
392 
393  SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/maxproprounds",
394  "maximum number of propagation rounds during probing (-1 infinity, -2 parameter settings)",
395  &heurdata->maxproprounds, TRUE, DEFAULT_MAXPROPROUNDS, -1, INT_MAX/4, NULL, NULL) );
396 
397  SCIP_CALL( SCIPaddCharParam(scip, "heuristics/" HEUR_NAME "/bound",
398  "to which bound should integer variables be fixed? ('l'ower, 'u'pper, or 'b'oth)",
399  &heurdata->bound, FALSE, DEFAULT_BOUND, "lub", NULL, NULL) );
400 
401  return SCIP_OKAY;
402 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
SCIP_RETCODE SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1075
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:436
#define NULL
Definition: def.h:246
#define HEUR_PRIORITY
Definition: heur_bound.c:52
static SCIP_DECL_HEURCOPY(heurCopyBound)
Definition: heur_bound.c:273
public methods for SCIP parameter handling
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:158
public methods for branch and bound tree
SCIP_RETCODE SCIPbacktrackProbing(SCIP *scip, int probingdepth)
Definition: scip_probing.c:280
SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
static SCIP_DECL_HEUREXEC(heurExecBound)
Definition: heur_bound.c:302
public methods for memory management
int SCIPgetProbingDepth(SCIP *scip)
Definition: scip_probing.c:253
#define DEFAULT_MAXPROPROUNDS
Definition: heur_bound.c:60
#define HEUR_DESC
Definition: heur_bound.c:50
internal methods for clocks and timing issues
static long bound
#define HEUR_FREQ
Definition: heur_bound.c:53
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17400
int SCIPgetNPseudoBranchCands(SCIP *scip)
Definition: scip_branch.c:747
public methods for timing
SCIP_RETCODE SCIPincludeHeurBound(SCIP *scip)
Definition: heur_bound.c:366
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:1918
#define FALSE
Definition: def.h:72
SCIP_RETCODE SCIPcutoffNode(SCIP *scip, SCIP_NODE *node)
Definition: scip_tree.c:501
#define TRUE
Definition: def.h:71
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
struct SCIP_HeurData SCIP_HEURDATA
Definition: type_heur.h:51
public methods for problem variables
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:114
SCIP_RETCODE SCIPincludeHeurBasic(SCIP *scip, SCIP_HEUR **heur, const char *name, const char *desc, char dispchar, int priority, int freq, int freqofs, int maxdepth, SCIP_HEURTIMING timingmask, SCIP_Bool usessubscip, SCIP_DECL_HEUREXEC((*heurexec)), SCIP_HEURDATA *heurdata)
Definition: scip_heur.c:187
SCIP_RETCODE SCIPconstructLP(SCIP *scip, SCIP_Bool *cutoff)
Definition: scip_lp.c:182
#define HEUR_FREQOFS
Definition: heur_bound.c:54
enum SCIP_LPSolStat SCIP_LPSOLSTAT
Definition: type_lp.h:42
void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
Definition: heur.c:1175
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:97
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:203
#define SCIPdebugMsg
Definition: scip_message.h:88
#define HEUR_DISPCHAR
Definition: heur_bound.c:51
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:155
public methods for numerical tolerances
public methods for querying solving statistics
public methods for the branch-and-bound tree
SCIP_Bool SCIPisLPConstructed(SCIP *scip)
Definition: scip_lp.c:159
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7347
static SCIP_RETCODE applyBoundHeur(SCIP *scip, SCIP_HEUR *heur, SCIP_HEURDATA *heurdata, SCIP_Bool lower, SCIP_RESULT *result)
Definition: heur_bound.c:82
#define DEFAULT_BOUND
Definition: heur_bound.c:61
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1254
SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
Definition: scip_heur.c:248
SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
Definition: scip_probing.c:630
SCIP_RETCODE SCIPfixVarProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval)
Definition: scip_probing.c:473
SCIP_RETCODE SCIPendProbing(SCIP *scip)
Definition: scip_probing.c:315
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16730
#define HEUR_MAXDEPTH
Definition: heur_bound.c:55
#define SCIP_CALL(x)
Definition: def.h:358
static SCIP_DECL_HEURFREE(heurFreeBound)
Definition: heur_bound.c:287
SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip_probing.c:866
#define DEFAULT_ONLYWITHOUTSOL
Definition: heur_bound.c:59
#define HEUR_USESSUBSCIP
Definition: heur_bound.c:57
SCIP_Bool SCIPhasCurrentNodeLP(SCIP *scip)
Definition: scip_lp.c:141
public methods for primal heuristic plugins and divesets
#define HEUR_NAME
Definition: heur_bound.c:49
#define SCIP_Bool
Definition: def.h:69
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:226
SCIP_RETCODE SCIProundSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *success)
Definition: scip_sol.c:2504
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1034
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1493
SCIP_RETCODE SCIPflushLP(SCIP *scip)
Definition: scip_lp.c:206
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPtrySol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
Definition: scip_sol.c:3182
public methods for the LP relaxation, rows and columns
#define SCIP_LONGINT_FORMAT
Definition: def.h:149
public methods for branching rule plugins and branching
general public methods
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2362
SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:239
public methods for solutions
public methods for the probing mode
public methods for message output
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:738
public methods for message handling
#define HEUR_TIMING
Definition: heur_bound.c:56
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16895
SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
Definition: scip_heur.c:232
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17410
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
Definition: scip_probing.c:174
public methods for primal heuristics
SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
Definition: heur.c:1165
public methods for global and local (sub)problems
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:129
heuristic which fixes all integer variables to a bound (lower/upper) and solves the remaining LP ...
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:377