Scippy

SCIP

Solving Constraint Integer Programs

heur_zirounding.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-2017 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 email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file heur_zirounding.c
17  * @brief zirounding primal heuristic
18  * @author Gregor Hendel
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <assert.h>
24 #include <string.h>
25 
26 #include "scip/heur_zirounding.h"
27 #include "scip.h"
28 
29 #define HEUR_NAME "zirounding"
30 #define HEUR_DESC "LP rounding heuristic as suggested by C. Wallace taking row slacks and bounds into account"
31 #define HEUR_DISPCHAR 'z'
32 #define HEUR_PRIORITY -500
33 #define HEUR_FREQ 1
34 #define HEUR_FREQOFS 0
35 #define HEUR_MAXDEPTH -1
36 #define HEUR_TIMING SCIP_HEURTIMING_AFTERLPNODE
37 #define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
38 
39 #define DEFAULT_MAXROUNDINGLOOPS 2 /**< delimits the number of main loops, can be set to -1 for no limit */
40 #define DEFAULT_STOPZIROUND TRUE /**< deactivation check is enabled by default */
41 #define DEFAULT_STOPPERCENTAGE 0.02 /**< the tolerance percentage after which zirounding will not be executed anymore */
42 #define DEFAULT_MINSTOPNCALLS 1000 /**< number of heuristic calls before deactivation check */
43 
44 
45 /*
46  * Data structures
47  */
48 
49 /** primal heuristic data */
50 struct SCIP_HeurData
51 {
52  SCIP_SOL* sol; /**< working solution */
53  SCIP_Longint lastlp; /**< the number of the last LP for which ZIRounding was called */
54  int maxroundingloops; /**< limits rounding loops in execution */
55  SCIP_Bool stopziround; /**< sets deactivation check */
56  SCIP_Real stoppercentage; /**< threshold for deactivation check */
57  int minstopncalls; /**< number of heuristic calls before deactivation check */
58 };
59 
61 {
64 };
65 typedef enum Direction DIRECTION;
66 
67 /*
68  * Local methods
69  */
70 
71 /** returns the fractionality of a value x, which is calculated as zivalue(x) = min(x-floor(x), ceil(x)-x) */
72 static
74  SCIP* scip, /**< pointer to current SCIP data structure */
75  SCIP_Real val /**< the value for which the fractionality should be computed */
76  )
77 {
78  SCIP_Real upgap; /* the gap between val and ceil(val) */
79  SCIP_Real downgap; /* the gap between val and floor(val) */
80 
81  assert(scip != NULL);
82 
83  upgap = SCIPfeasCeil(scip, val) - val;
84  downgap = val - SCIPfeasFloor(scip, val);
85 
86  return MIN(upgap, downgap);
87 }
88 
89 /** determines shifting bounds for variable */
90 static
92  SCIP* scip, /**< pointer to current SCIP data structure */
93  SCIP_VAR* var, /**< the variable for which lb and ub have to be calculated */
94  SCIP_Real currentvalue, /**< the current value of var in the working solution */
95  SCIP_Real* upperbound, /**< pointer to store the calculated upper bound on the variable shift */
96  SCIP_Real* lowerbound, /**< pointer to store the calculated lower bound on the variable shift */
97  SCIP_Real* upslacks, /**< array that contains the slacks between row activities and the right hand sides of the rows */
98  SCIP_Real* downslacks, /**< array that contains lhs slacks */
99  int nslacks, /**< current number of slacks */
100  SCIP_Bool* numericalerror /**< flag to determine whether a numerical error occurred */
101  )
102 {
103  SCIP_COL* col;
104  SCIP_ROW** colrows;
105  SCIP_Real* colvals;
106  int ncolvals;
107  int i;
108 
109  assert(scip != NULL);
110  assert(var != NULL);
111  assert(upslacks != NULL);
112  assert(downslacks != NULL);
113  assert(upperbound != NULL);
114  assert(lowerbound != NULL);
115 
116  /* get the column associated to the variable, the nonzero rows and the nonzero coefficients */
117  col = SCIPvarGetCol(var);
118  colrows = SCIPcolGetRows(col);
119  colvals = SCIPcolGetVals(col);
120  ncolvals = SCIPcolGetNLPNonz(col);
121 
122  /* only proceed, when variable has nonzero coefficients */
123  if( ncolvals == 0 )
124  return;
125 
126  assert(colvals != NULL);
127  assert(colrows != NULL);
128 
129  /* initialize the bounds on the shift to be the gap of the current solution value to the bounds of the variable */
130  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
131  *upperbound = SCIPinfinity(scip);
132  else
133  *upperbound = SCIPvarGetUbGlobal(var) - currentvalue;
134 
135  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
136  *lowerbound = SCIPinfinity(scip);
137  else
138  *lowerbound = currentvalue - SCIPvarGetLbGlobal(var);
139 
140  /* go through every nonzero row coefficient corresponding to var to determine bounds for shifting
141  * in such a way that shifting maintains feasibility in every LP row.
142  * a lower or upper bound as it is calculated in zirounding always has to be >= 0.0.
143  * if one of these values is significantly < 0.0, this will cause the abort of execution of the heuristic so that
144  * infeasible solutions are avoided
145  */
146  for( i = 0; i < ncolvals && (*lowerbound > 0.0 || *upperbound > 0.0); ++i )
147  {
148  SCIP_ROW* row;
149  int rowpos;
150 
151  row = colrows[i];
152  rowpos = SCIProwGetLPPos(row);
153 
154  /* the row might currently not be in the LP, ignore it! */
155  if( rowpos == -1 )
156  continue;
157 
158  assert(0 <= rowpos && rowpos < nslacks);
159 
160  /* all bounds and slacks as they are calculated in zirounding always have to be greater equal zero.
161  * It might however be due to numerical issues, e.g. with scaling, that they are not. Better abort in this case.
162  */
163  if( SCIPisFeasLT(scip, *lowerbound, 0.0) || SCIPisFeasLT(scip, *upperbound, 0.0)
164  || SCIPisFeasLT(scip, upslacks[rowpos], 0.0) || SCIPisFeasLT(scip, downslacks[rowpos] , 0.0) )
165  {
166  *numericalerror = TRUE;
167  return;
168  }
169 
170  SCIPdebugMsg(scip, "colval: %15.8g, downslack: %15.8g, upslack: %5.2g, lb: %5.2g, ub: %5.2g\n", colvals[i], downslacks[rowpos], upslacks[rowpos],
171  *lowerbound, *upperbound);
172 
173  /* if coefficient > 0, rounding up might violate up slack and rounding down might violate down slack
174  * thus search for the minimum so that no constraint is violated; vice versa for coefficient < 0
175  */
176  if( colvals[i] > 0 )
177  {
178  if( !SCIPisInfinity(scip, upslacks[rowpos]) )
179  {
180  SCIP_Real upslack;
181  upslack = MAX(upslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
182  *upperbound = MIN(*upperbound, upslack/colvals[i]);
183  }
184 
185  if( !SCIPisInfinity(scip, downslacks[rowpos]) )
186  {
187  SCIP_Real downslack;
188  downslack = MAX(downslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
189  *lowerbound = MIN(*lowerbound, downslack/colvals[i]);
190  }
191  }
192  else
193  {
194  assert(colvals[i] != 0.0);
195 
196  if( !SCIPisInfinity(scip, upslacks[rowpos]) )
197  {
198  SCIP_Real upslack;
199  upslack = MAX(upslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
200  *lowerbound = MIN(*lowerbound, -upslack/colvals[i]);
201  }
202 
203  if( !SCIPisInfinity(scip, downslacks[rowpos]) )
204  {
205  SCIP_Real downslack;
206  downslack = MAX(downslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
207  *upperbound = MIN(*upperbound, -downslack/colvals[i]);
208  }
209  }
210  }
211 }
212 
213 /** when a variable is shifted, the activities and slacks of all rows it appears in have to be updated */
214 static
216  SCIP* scip, /**< pointer to current SCIP data structure */
217  SCIP_SOL* sol, /**< working solution */
218  SCIP_VAR* var, /**< pointer to variable to be modified */
219  SCIP_Real shiftvalue, /**< the value by which the variable is shifted */
220  SCIP_Real* upslacks, /**< upslacks of all rows the variable appears in */
221  SCIP_Real* downslacks, /**< downslacks of all rows the variable appears in */
222  SCIP_Real* activities, /**< activities of the LP rows */
223  SCIP_VAR** slackvars, /**< the slack variables for equality rows */
224  SCIP_Real* slackcoeffs, /**< the slack variable coefficients */
225  int nslacks /**< size of the arrays */
226  )
227 {
228  SCIP_COL* col; /* the corresponding column of variable var */
229  SCIP_ROW** rows; /* pointer to the nonzero coefficient rows for variable var */
230  int nrows; /* the number of nonzeros */
231  SCIP_Real* colvals; /* array to store the nonzero coefficients */
232  int i;
233 
234  assert(scip != NULL);
235  assert(sol != NULL);
236  assert(var != NULL);
237  assert(upslacks != NULL);
238  assert(downslacks != NULL);
239  assert(activities != NULL);
240  assert(nslacks >= 0);
241 
242  col = SCIPvarGetCol(var);
243  assert(col != NULL);
244 
245  rows = SCIPcolGetRows(col);
246  nrows = SCIPcolGetNLPNonz(col);
247  colvals = SCIPcolGetVals(col);
248  assert(nrows == 0 || (rows != NULL && colvals != NULL));
249 
250  /* go through all rows the shifted variable appears in */
251  for( i = 0; i < nrows; ++i )
252  {
253  int rowpos;
254 
255  rowpos = SCIProwGetLPPos(rows[i]);
256  assert(-1 <= rowpos && rowpos < nslacks);
257 
258  /* if the row is in the LP, update its activity, up and down slack */
259  if( rowpos >= 0 )
260  {
261  SCIP_Real val;
262 
263  val = colvals[i] * shiftvalue;
264 
265  /* if the row is an equation, we update its slack variable instead of its activities */
266  if( SCIPisFeasEQ(scip, SCIProwGetLhs(rows[i]), SCIProwGetRhs(rows[i])) )
267  {
268  SCIP_Real slackvarshiftval;
269  SCIP_Real slackvarsolval;
270 
271  assert(slackvars[rowpos] != NULL);
272  assert(!SCIPisFeasZero(scip, slackcoeffs[rowpos]));
273 
274  slackvarsolval = SCIPgetSolVal(scip, sol, slackvars[rowpos]);
275  slackvarshiftval = -val / slackcoeffs[rowpos];
276 
277  assert(SCIPisFeasGE(scip, slackvarsolval + slackvarshiftval, SCIPvarGetLbGlobal(slackvars[rowpos])));
278  assert(SCIPisFeasLE(scip, slackvarsolval + slackvarshiftval, SCIPvarGetUbGlobal(slackvars[rowpos])));
279 
280  SCIP_CALL( SCIPsetSolVal(scip, sol, slackvars[rowpos], slackvarsolval + slackvarshiftval) );
281  }
282  else if( !SCIPisInfinity(scip, -activities[rowpos]) && !SCIPisInfinity(scip, activities[rowpos]) )
283  activities[rowpos] += val;
284 
285  /* the slacks of the row now can be updated independently of its type */
286  if( !SCIPisInfinity(scip, upslacks[rowpos]) )
287  upslacks[rowpos] -= val;
288  if( !SCIPisInfinity(scip, -downslacks[rowpos]) )
289  downslacks[rowpos] += val;
290 
291  assert(!SCIPisFeasNegative(scip, upslacks[rowpos]));
292  assert(!SCIPisFeasNegative(scip, downslacks[rowpos]));
293  }
294  }
295  return SCIP_OKAY;
296 }
297 
298 /** finds a continuous slack variable for an equation row, NULL if none exists */
299 static
301  SCIP* scip, /**< pointer to current SCIP data structure */
302  SCIP_ROW* row, /**< the row for which a slack variable is searched */
303  SCIP_VAR** varpointer, /**< pointer to store the slack variable */
304  SCIP_Real* coeffpointer /**< pointer to store the coefficient of the slack variable */
305  )
306 {
307  int v;
308  SCIP_COL** rowcols;
309  SCIP_Real* rowvals;
310  int nrowvals;
311 
312  assert(row != NULL);
313  assert(varpointer != NULL);
314  assert(coeffpointer != NULL);
315 
316  rowcols = SCIProwGetCols(row);
317  rowvals = SCIProwGetVals(row);
318  nrowvals = SCIProwGetNNonz(row);
319 
320  assert(nrowvals == 0 || rowvals != NULL);
321  assert(nrowvals == 0 || rowcols != NULL);
322 
323  /* iterate over the row variables. Stop after the first unfixed continuous variable was found. */
324  for( v = nrowvals - 1; v >= 0; --v )
325  {
326  SCIP_VAR* colvar;
327 
328  assert(rowcols[v] != NULL);
329  if( SCIPcolGetLPPos(rowcols[v]) == -1 )
330  continue;
331 
332  colvar = SCIPcolGetVar(rowcols[v]);
333 
335  && !SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(colvar), SCIPvarGetUbGlobal(colvar))
336  && SCIPcolGetNLPNonz(rowcols[v]) == 1 )
337  {
338  SCIPdebugMsg(scip, " slack variable for row %s found: %s\n", SCIProwGetName(row), SCIPvarGetName(colvar));
339 
340  *coeffpointer = rowvals[v];
341  *varpointer = colvar;
342 
343  return;
344  }
345  }
346 
347  *varpointer = NULL;
348  *coeffpointer = 0.0;
349 
350  SCIPdebugMsg(scip, "No slack variable for row %s found. \n", SCIProwGetName(row));
351 }
352 
353 /*
354  * Callback methods of primal heuristic
355  */
356 
357 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
358 static
359 SCIP_DECL_HEURCOPY(heurCopyZirounding)
360 { /*lint --e{715}*/
361  assert(scip != NULL);
362  assert(heur != NULL);
363  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
364 
365  /* call inclusion method of primal heuristic */
367 
368  return SCIP_OKAY;
369 }
370 
371 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
372 static
373 SCIP_DECL_HEURFREE(heurFreeZirounding)
374 { /*lint --e{715}*/
375  SCIP_HEURDATA* heurdata;
376 
377  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
378 
379  heurdata = SCIPheurGetData(heur);
380  assert(heurdata != NULL);
381 
382  /* free heuristic data */
383  SCIPfreeBlockMemory(scip, &heurdata);
384  SCIPheurSetData(heur, NULL);
385 
386  return SCIP_OKAY;
387 }
388 
389 /** initialization method of primal heuristic (called after problem was transformed) */
390 static
391 SCIP_DECL_HEURINIT(heurInitZirounding)
392 { /*lint --e{715}*/
393  SCIP_HEURDATA* heurdata;
394 
395  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
396 
397  heurdata = SCIPheurGetData(heur);
398  assert(heurdata != NULL);
399 
400  /* create working solution */
401  SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
402 
403  return SCIP_OKAY;
404 }
405 
406 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
407 static
408 SCIP_DECL_HEUREXIT(heurExitZirounding) /*lint --e{715}*/
409 { /*lint --e{715}*/
410  SCIP_HEURDATA* heurdata;
411 
412  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
413 
414  heurdata = SCIPheurGetData(heur);
415  assert(heurdata != NULL);
416 
417  /* free working solution */
418  SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
419 
420  return SCIP_OKAY;
421 }
422 
423 /** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
424 static
425 SCIP_DECL_HEURINITSOL(heurInitsolZirounding)
426 { /*lint --e{715}*/
427  SCIP_HEURDATA* heurdata;
428 
429  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
430 
431  heurdata = SCIPheurGetData(heur);
432  assert(heurdata != NULL);
433 
434  heurdata->lastlp = -1;
435 
436  return SCIP_OKAY;
437 }
438 
439 
440 /** execution method of primal heuristic */
441 static
442 SCIP_DECL_HEUREXEC(heurExecZirounding)
443 { /*lint --e{715}*/
444  SCIP_HEURDATA* heurdata;
445  SCIP_SOL* sol;
446  SCIP_VAR** lpcands;
447  SCIP_VAR** zilpcands;
448 
449  SCIP_VAR** slackvars;
450  SCIP_Real* upslacks;
451  SCIP_Real* downslacks;
452  SCIP_Real* activities;
453  SCIP_Real* slackvarcoeffs;
454  SCIP_Bool* rowneedsslackvar;
455 
456  SCIP_ROW** rows;
457  SCIP_Real* lpcandssol;
458  SCIP_Real* solarray;
459 
460  SCIP_Longint nlps;
461  int currentlpcands;
462  int nlpcands;
463  int nimplfracs;
464  int i;
465  int c;
466  int nslacks;
467  int nroundings;
468 
469  SCIP_Bool improvementfound;
470  SCIP_Bool numericalerror;
471 
472  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
473  assert(result != NULL);
474  assert(SCIPhasCurrentNodeLP(scip));
475 
476  *result = SCIP_DIDNOTRUN;
477 
478  /* do not call heuristic of node was already detected to be infeasible */
479  if( nodeinfeasible )
480  return SCIP_OKAY;
481 
482  /* only call heuristic if an optimal LP-solution is at hand */
484  return SCIP_OKAY;
485 
486  /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
488  return SCIP_OKAY;
489 
490  /* get heuristic data */
491  heurdata = SCIPheurGetData(heur);
492  assert(heurdata != NULL);
493 
494  /* Do not call heuristic if deactivation check is enabled and percentage of found solutions in relation
495  * to number of calls falls below heurdata->stoppercentage */
496  if( heurdata->stopziround && SCIPheurGetNCalls(heur) >= heurdata->minstopncalls
497  && SCIPheurGetNSolsFound(heur)/(SCIP_Real)SCIPheurGetNCalls(heur) < heurdata->stoppercentage )
498  return SCIP_OKAY;
499 
500  /* assure that heuristic has not already been called after the last LP had been solved */
501  nlps = SCIPgetNLPs(scip);
502  if( nlps == heurdata->lastlp )
503  return SCIP_OKAY;
504 
505  heurdata->lastlp = nlps;
506 
507  /* get fractional variables */
508  SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, &nimplfracs) );
509  nlpcands = nlpcands + nimplfracs;
510  /* make sure that there is at least one fractional variable that should be integral */
511  if( nlpcands == 0 )
512  return SCIP_OKAY;
513 
514  assert(nlpcands > 0);
515  assert(lpcands != NULL);
516  assert(lpcandssol != NULL);
517 
518  /* get LP rows data */
519  rows = SCIPgetLPRows(scip);
520  nslacks = SCIPgetNLPRows(scip);
521 
522  /* cannot do anything if LP is empty */
523  if( nslacks == 0 )
524  return SCIP_OKAY;
525 
526  assert(rows != NULL);
527  assert(nslacks > 0);
528 
529  /* get the working solution from heuristic's local data */
530  sol = heurdata->sol;
531  assert(sol != NULL);
532 
533  *result = SCIP_DIDNOTFIND;
534 
535  solarray = NULL;
536  zilpcands = NULL;
537 
538  /* copy the current LP solution to the working solution and allocate memory for local data */
539  SCIP_CALL( SCIPlinkLPSol(scip, sol) );
540  SCIP_CALL( SCIPallocBufferArray(scip, &solarray, nlpcands) );
541  SCIP_CALL( SCIPallocBufferArray(scip, &zilpcands, nlpcands) );
542 
543  /* copy necessary data to local arrays */
544  BMScopyMemoryArray(solarray, lpcandssol, nlpcands);
545  BMScopyMemoryArray(zilpcands, lpcands, nlpcands);
546 
547  /* allocate buffer data arrays */
548  SCIP_CALL( SCIPallocBufferArray(scip, &slackvars, nslacks) );
549  SCIP_CALL( SCIPallocBufferArray(scip, &upslacks, nslacks) );
550  SCIP_CALL( SCIPallocBufferArray(scip, &downslacks, nslacks) );
551  SCIP_CALL( SCIPallocBufferArray(scip, &slackvarcoeffs, nslacks) );
552  SCIP_CALL( SCIPallocBufferArray(scip, &rowneedsslackvar, nslacks) );
553  SCIP_CALL( SCIPallocBufferArray(scip, &activities, nslacks) );
554 
555  BMSclearMemoryArray(slackvars, nslacks);
556  BMSclearMemoryArray(slackvarcoeffs, nslacks);
557  BMSclearMemoryArray(rowneedsslackvar, nslacks);
558 
559  numericalerror = FALSE;
560  nroundings = 0;
561 
562  /* loop over fractional variables and involved LP rows to find all rows which require a slack variable */
563  for( c = 0; c < nlpcands; ++c )
564  {
565  SCIP_VAR* cand;
566  SCIP_ROW** candrows;
567  int r;
568  int ncandrows;
569 
570  cand = zilpcands[c];
571  assert(cand != NULL);
572  assert(SCIPcolGetLPPos(SCIPvarGetCol(cand)) >= 0);
573 
574  candrows = SCIPcolGetRows(SCIPvarGetCol(cand));
575  ncandrows = SCIPcolGetNLPNonz(SCIPvarGetCol(cand));
576 
577  assert(candrows == NULL || ncandrows > 0);
578 
579  for( r = 0; r < ncandrows; ++r )
580  {
581  int rowpos;
582 
583  assert(candrows != NULL); /* to please flexelint */
584  assert(candrows[r] != NULL);
585  rowpos = SCIProwGetLPPos(candrows[r]);
586 
587  if( rowpos >= 0 && SCIPisFeasEQ(scip, SCIProwGetLhs(candrows[r]), SCIProwGetRhs(candrows[r])) )
588  {
589  rowneedsslackvar[rowpos] = TRUE;
590  SCIPdebugMsg(scip, " Row %s needs slack variable for variable %s\n", SCIProwGetName(candrows[r]), SCIPvarGetName(cand));
591  }
592  }
593  }
594 
595  /* calculate row slacks for every every row that belongs to the current LP and ensure, that the current solution
596  * has no violated constraint -- if any constraint is violated, i.e. a slack is significantly smaller than zero,
597  * this will cause the termination of the heuristic because Zirounding does not provide feasibility recovering
598  */
599  for( i = 0; i < nslacks; ++i )
600  {
601  SCIP_ROW* row;
602  SCIP_Real lhs;
603  SCIP_Real rhs;
604 
605  row = rows[i];
606 
607  assert(row != NULL);
608 
609  lhs = SCIProwGetLhs(row);
610  rhs = SCIProwGetRhs(row);
611 
612  /* get row activity */
613  activities[i] = SCIPgetRowActivity(scip, row);
614  assert(SCIPisFeasLE(scip, lhs, activities[i]) && SCIPisFeasLE(scip, activities[i], rhs));
615 
616  /* in special case if LHS or RHS is (-)infinity slacks have to be initialized as infinity */
617  if( SCIPisInfinity(scip, -lhs) )
618  downslacks[i] = SCIPinfinity(scip);
619  else
620  downslacks[i] = activities[i] - lhs;
621 
622  if( SCIPisInfinity(scip, rhs) )
623  upslacks[i] = SCIPinfinity(scip);
624  else
625  upslacks[i] = rhs - activities[i];
626 
627  SCIPdebugMsg(scip, "lhs:%5.2f <= act:%5.2g <= rhs:%5.2g --> down: %5.2g, up:%5.2g\n", lhs, activities[i], rhs, downslacks[i], upslacks[i]);
628 
629  /* row is an equation. Try to find a slack variable in the row, i.e.,
630  * a continuous variable which occurs only in this row. If no such variable exists,
631  * there is no hope for an IP-feasible solution in this round
632  */
633  if( SCIPisFeasEQ(scip, lhs, rhs) && rowneedsslackvar[i] )
634  {
635  /* @todo: This is only necessary for rows containing fractional variables. */
636  rowFindSlackVar(scip, row, &(slackvars[i]), &(slackvarcoeffs[i]));
637 
638  if( slackvars[i] == NULL )
639  {
640  SCIPdebugMsg(scip, "No slack variable found for equation %s, terminating ZI Round heuristic\n", SCIProwGetName(row));
641  goto TERMINATE;
642  }
643  else
644  {
645  SCIP_Real ubslackvar;
646  SCIP_Real lbslackvar;
647  SCIP_Real solvalslackvar;
648  SCIP_Real coeffslackvar;
649  SCIP_Real ubgap;
650  SCIP_Real lbgap;
651 
652  assert(SCIPvarGetType(slackvars[i]) == SCIP_VARTYPE_CONTINUOUS);
653  solvalslackvar = SCIPgetSolVal(scip, sol, slackvars[i]);
654  ubslackvar = SCIPvarGetUbGlobal(slackvars[i]);
655  lbslackvar = SCIPvarGetLbGlobal(slackvars[i]);
656 
657  coeffslackvar = slackvarcoeffs[i];
658  assert(!SCIPisFeasZero(scip, coeffslackvar));
659 
660  ubgap = ubslackvar - solvalslackvar;
661  lbgap = solvalslackvar - lbslackvar;
662 
663  if( SCIPisFeasZero(scip, ubgap) )
664  ubgap = 0.0;
665  if( SCIPisFeasZero(scip, lbgap) )
666  lbgap = 0.0;
667 
668  if( SCIPisFeasPositive(scip, coeffslackvar) )
669  {
670  if( !SCIPisInfinity(scip, lbslackvar) )
671  upslacks[i] += coeffslackvar * lbgap;
672  else
673  upslacks[i] = SCIPinfinity(scip);
674  if( !SCIPisInfinity(scip, ubslackvar) )
675  downslacks[i] += coeffslackvar * ubgap;
676  else
677  downslacks[i] = SCIPinfinity(scip);
678  }
679  else
680  {
681  if( !SCIPisInfinity(scip, ubslackvar) )
682  upslacks[i] -= coeffslackvar * ubgap;
683  else
684  upslacks[i] = SCIPinfinity(scip);
685  if( !SCIPisInfinity(scip, lbslackvar) )
686  downslacks[i] -= coeffslackvar * lbgap;
687  else
688  downslacks[i] = SCIPinfinity(scip);
689  }
690  SCIPdebugMsg(scip, " Slack variable for row %s at pos %d: %g <= %s = %g <= %g; Coeff %g, upslack = %g, downslack = %g \n",
691  SCIProwGetName(row), SCIProwGetLPPos(row), lbslackvar, SCIPvarGetName(slackvars[i]), solvalslackvar, ubslackvar, coeffslackvar,
692  upslacks[i], downslacks[i]);
693  }
694  }
695  /* due to numerical inaccuracies, the rows might be feasible, even if the slacks are
696  * significantly smaller than zero -> terminate
697  */
698  if( SCIPisFeasLT(scip, upslacks[i], 0.0) || SCIPisFeasLT(scip, downslacks[i], 0.0) )
699  goto TERMINATE;
700  }
701 
702  assert(nslacks == 0 || (upslacks != NULL && downslacks != NULL && activities != NULL));
703 
704  /* initialize number of remaining variables and flag to enter the main loop */
705  currentlpcands = nlpcands;
706  improvementfound = TRUE;
707 
708  /* iterate over variables as long as there are fractional variables left */
709  while( currentlpcands > 0 && improvementfound && (heurdata->maxroundingloops == -1 || nroundings < heurdata->maxroundingloops) )
710  { /*lint --e{850}*/
711  improvementfound = FALSE;
712  nroundings++;
713  SCIPdebugMsg(scip, "zirounding enters while loop for %d time with %d candidates left. \n", nroundings, currentlpcands);
714 
715  /* check for every remaining fractional variable if a shifting decreases ZI-value of the variable */
716  for( c = 0; c < currentlpcands; ++c )
717  {
718  SCIP_VAR* var;
719  SCIP_Real oldsolval;
720  SCIP_Real upperbound;
721  SCIP_Real lowerbound;
722  SCIP_Real up;
723  SCIP_Real down;
724  SCIP_Real ziup;
725  SCIP_Real zidown;
726  SCIP_Real zicurrent;
727  SCIP_Real shiftval;
728 
729  DIRECTION direction;
730 
731  /* get values from local data */
732  oldsolval = solarray[c];
733  var = zilpcands[c];
734 
735  assert(!SCIPisFeasIntegral(scip, oldsolval));
736  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
737 
738  /* calculate bounds for variable and make sure that there are no numerical inconsistencies */
739  upperbound = SCIPinfinity(scip);
740  lowerbound = SCIPinfinity(scip);
741  calculateBounds(scip, var, oldsolval, &upperbound, &lowerbound, upslacks, downslacks, nslacks, &numericalerror);
742 
743  if( numericalerror )
744  goto TERMINATE;
745 
746  /* calculate the possible values after shifting */
747  up = oldsolval + upperbound;
748  down = oldsolval - lowerbound;
749 
750  /* if the variable is integer or implicit binary, do not shift further than the nearest integer */
752  {
753  SCIP_Real ceilx;
754  SCIP_Real floorx;
755 
756  ceilx = SCIPfeasCeil(scip, oldsolval);
757  floorx = SCIPfeasFloor(scip, oldsolval);
758  up = MIN(up, ceilx);
759  down = MAX(down, floorx);
760  }
761 
762  /* calculate necessary values */
763  ziup = getZiValue(scip, up);
764  zidown = getZiValue(scip, down);
765  zicurrent = getZiValue(scip, oldsolval);
766 
767  /* calculate the shifting direction that reduces ZI-value the most,
768  * if both directions improve ZI-value equally, take the direction which improves the objective
769  */
770  if( SCIPisFeasLT(scip, zidown, zicurrent) || SCIPisFeasLT(scip, ziup, zicurrent) )
771  {
772  if( SCIPisFeasEQ(scip,ziup, zidown) )
773  direction = SCIPisFeasGE(scip, SCIPvarGetObj(var), 0.0) ? DIRECTION_DOWN : DIRECTION_UP;
774  else if( SCIPisFeasLT(scip, zidown, ziup) )
775  direction = DIRECTION_DOWN;
776  else
777  direction = DIRECTION_UP;
778 
779  /* once a possible shifting direction and value have been found, variable value is updated */
780  shiftval = (direction == DIRECTION_UP ? up - oldsolval : down - oldsolval);
781 
782  /* this improves numerical stability in some cases */
783  if( direction == DIRECTION_UP )
784  shiftval = MIN(shiftval, upperbound);
785  else
786  shiftval = MIN(shiftval, lowerbound);
787  /* update the solution */
788  solarray[c] = direction == DIRECTION_UP ? up : down;
789  SCIP_CALL( SCIPsetSolVal(scip, sol, var, solarray[c]) );
790 
791  /* update the rows activities and slacks */
792  SCIP_CALL( updateSlacks(scip, sol, var, shiftval, upslacks,
793  downslacks, activities, slackvars, slackvarcoeffs, nslacks) );
794 
795  SCIPdebugMsg(scip, "zirounding update step : %d var index, oldsolval=%g, shiftval=%g\n",
796  SCIPvarGetIndex(var), oldsolval, shiftval);
797  /* since at least one improvement has been found, heuristic will enter main loop for another time because the improvement
798  * might affect many LP rows and their current slacks and thus make further rounding steps possible */
799  improvementfound = TRUE;
800  }
801 
802  /* if solution value of variable has become feasibly integral due to rounding step,
803  * variable is put at the end of remaining candidates array so as not to be considered in future loops
804  */
805  if( SCIPisFeasIntegral(scip, solarray[c]) )
806  {
807  zilpcands[c] = zilpcands[currentlpcands - 1];
808  solarray[c] = solarray[currentlpcands - 1];
809  currentlpcands--;
810 
811  /* counter is decreased if end of candidates array has not been reached yet */
812  if( c < currentlpcands )
813  c--;
814  }
815  else if( nroundings == heurdata->maxroundingloops - 1 )
816  goto TERMINATE;
817  }
818  }
819 
820  /* in case that no candidate is left for rounding after the final main loop
821  * the found solution has to be checked for feasibility in the original problem
822  */
823  if( currentlpcands == 0 )
824  {
825  SCIP_Bool stored;
826  SCIP_CALL(SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, TRUE, FALSE, &stored));
827  if( stored )
828  {
829 #ifdef SCIP_DEBUG
830  SCIPdebugMsg(scip, "found feasible rounded solution:\n");
831  SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) );
832 #endif
833  SCIPstatisticMessage(" ZI Round solution value: %g \n", SCIPgetSolOrigObj(scip, sol));
834 
835  *result = SCIP_FOUNDSOL;
836  }
837  }
838 
839  /* free memory for all locally allocated data */
840  TERMINATE:
841  SCIPfreeBufferArrayNull(scip, &activities);
842  SCIPfreeBufferArrayNull(scip, &rowneedsslackvar);
843  SCIPfreeBufferArrayNull(scip, &slackvarcoeffs);
844  SCIPfreeBufferArrayNull(scip, &downslacks);
845  SCIPfreeBufferArrayNull(scip, &upslacks);
846  SCIPfreeBufferArrayNull(scip, &slackvars);
847  SCIPfreeBufferArrayNull(scip, &zilpcands);
848  SCIPfreeBufferArrayNull(scip, &solarray);
849 
850  return SCIP_OKAY;
851 }
852 
853 /*
854  * primal heuristic specific interface methods
855  */
856 
857 /** creates the zirounding primal heuristic and includes it in SCIP */
859  SCIP* scip /**< SCIP data structure */
860  )
861 {
862  SCIP_HEURDATA* heurdata;
863  SCIP_HEUR* heur;
864 
865  /* create zirounding primal heuristic data */
866  SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
867 
868  /* include primal heuristic */
869  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
871  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecZirounding, heurdata) );
872 
873  assert(heur != NULL);
874 
875  /* set non-NULL pointers to callback methods */
876  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyZirounding) );
877  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeZirounding) );
878  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitZirounding) );
879  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitZirounding) );
880  SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolZirounding) );
881 
882  /* add zirounding primal heuristic parameters */
883  SCIP_CALL( SCIPaddIntParam(scip, "heuristics/zirounding/maxroundingloops",
884  "determines maximum number of rounding loops",
885  &heurdata->maxroundingloops, TRUE, DEFAULT_MAXROUNDINGLOOPS, -1, INT_MAX, NULL, NULL) );
886  SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/zirounding/stopziround",
887  "flag to determine if Zirounding is deactivated after a certain percentage of unsuccessful calls",
888  &heurdata->stopziround, TRUE, DEFAULT_STOPZIROUND, NULL, NULL) );
889  SCIP_CALL( SCIPaddRealParam(scip,"heuristics/zirounding/stoppercentage",
890  "if percentage of found solutions falls below this parameter, Zirounding will be deactivated",
891  &heurdata->stoppercentage, TRUE, DEFAULT_STOPPERCENTAGE, 0.0, 1.0, NULL, NULL) );
892  SCIP_CALL( SCIPaddIntParam(scip, "heuristics/zirounding/minstopncalls",
893  "determines the minimum number of calls before percentage-based deactivation of Zirounding is applied",
894  &heurdata->minstopncalls, TRUE, DEFAULT_MINSTOPNCALLS, 1, INT_MAX, NULL, NULL) );
895 
896  return SCIP_OKAY;
897 }
static void calculateBounds(SCIP *scip, SCIP_VAR *var, SCIP_Real currentvalue, SCIP_Real *upperbound, SCIP_Real *lowerbound, SCIP_Real *upslacks, SCIP_Real *downslacks, int nslacks, SCIP_Bool *numericalerror)
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip.c:36128
static SCIP_Real getZiValue(SCIP *scip, SCIP_Real val)
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip.c:29200
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:46151
SCIP_RETCODE SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:37672
enum Direction DIRECTION
#define HEUR_DESC
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46086
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46099
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
Definition: scip.c:42499
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17166
#define HEUR_FREQ
SCIP_Real * SCIPcolGetVals(SCIP_COL *col)
Definition: lp.c:16190
SCIP_RETCODE SCIPsetHeurExit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXIT((*heurexit)))
Definition: scip.c:8092
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16232
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45803
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:16370
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:46175
#define DEFAULT_MAXROUNDINGLOOPS
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46138
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16311
#define FALSE
Definition: def.h:64
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:45816
#define HEUR_NAME
#define TRUE
Definition: def.h:63
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
#define SCIPstatisticMessage
Definition: pub_message.h:104
struct SCIP_HeurData SCIP_HEURDATA
Definition: type_heur.h:51
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:21907
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.c:7999
SCIP_RETCODE SCIPincludeHeurZirounding(SCIP *scip)
#define HEUR_FREQOFS
void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
Definition: heur.c:1102
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:21890
#define HEUR_DISPCHAR
#define SCIPdebugMsg
Definition: scip.h:451
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.c:4202
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
Definition: scip.c:46223
Direction
Definition: heur_twoopt.c:111
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:46211
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17176
SCIP_RETCODE SCIPsetHeurInitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINITSOL((*heurinitsol)))
Definition: scip.c:8108
static SCIP_DECL_HEUREXIT(heurExitZirounding)
#define DEFAULT_STOPZIROUND
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1181
SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
Definition: scip.c:8060
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition: lp.c:16180
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:21938
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16552
static SCIP_DECL_HEURCOPY(heurCopyZirounding)
#define NULL
Definition: lpi_spx1.cpp:137
int SCIPgetNLPRows(SCIP *scip)
Definition: scip.c:29221
#define SCIP_CALL(x)
Definition: def.h:306
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46112
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16321
SCIP_Longint SCIPheurGetNCalls(SCIP_HEUR *heur)
Definition: heur.c:1307
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:16257
SCIP_Bool SCIPhasCurrentNodeLP(SCIP *scip)
Definition: scip.c:28769
#define HEUR_TIMING
#define DEFAULT_MINSTOPNCALLS
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:21925
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:37867
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:16267
#define SCIP_Bool
Definition: def.h:61
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:28854
#define HEUR_USESSUBSCIP
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:37631
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17014
enum Direction DIRECTION
Definition: heur_twoopt.c:117
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:89
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:16880
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:38090
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:45827
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.c:39749
ZI Round primal heuristic.
#define DEFAULT_STOPPERCENTAGE
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip.c:28897
static SCIP_DECL_HEUREXEC(heurExecZirounding)
static SCIP_DECL_HEURINITSOL(heurInitsolZirounding)
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16081
static SCIP_RETCODE updateSlacks(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real shiftvalue, SCIP_Real *upslacks, SCIP_Real *downslacks, SCIP_Real *activities, SCIP_VAR **slackvars, SCIP_Real *slackcoeffs, int nslacks)
SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
Definition: scip.c:8076
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:46163
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16671
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:16500
#define SCIP_Real
Definition: def.h:135
static SCIP_DECL_HEURFREE(heurFreeZirounding)
#define MIN(x, y)
Definition: memory.c:75
#define SCIP_Longint
Definition: def.h:120
SCIP_Longint SCIPheurGetNSolsFound(SCIP_HEUR *heur)
Definition: heur.c:1317
#define HEUR_PRIORITY
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:16849
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16717
static void rowFindSlackVar(SCIP *scip, SCIP_ROW *row, SCIP_VAR **varpointer, SCIP_Real *coeffpointer)
SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
Definition: scip.c:8044
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:46187
static SCIP_DECL_HEURINIT(heurInitZirounding)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
Definition: heur.c:1092
SCIP_Longint SCIPgetNLPs(SCIP *scip)
Definition: scip.c:41363
#define HEUR_MAXDEPTH
int SCIPcolGetNLPNonz(SCIP_COL *col)
Definition: lp.c:16169
int SCIPcolGetLPPos(SCIP_COL *col)
Definition: lp.c:16122
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:38007
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4258
SCIP callable library.
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.c:4176
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30673
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:37005
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip.c:38421