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