Scippy

SCIP

Solving Constraint Integer Programs

heur_shifting.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-2014 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_shifting.c
17  * @brief LP rounding heuristic that tries to recover from intermediate infeasibilities and shifts continuous variables
18  * @author Tobias Achterberg
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_shifting.h"
27 
28 
29 #define HEUR_NAME "shifting"
30 #define HEUR_DESC "LP rounding heuristic with infeasibility recovering also using continuous variables"
31 #define HEUR_DISPCHAR 's'
32 #define HEUR_PRIORITY -5000
33 #define HEUR_FREQ 10
34 #define HEUR_FREQOFS 0
35 #define HEUR_MAXDEPTH -1
36 #define HEUR_TIMING SCIP_HEURTIMING_DURINGLPLOOP
37 #define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
38 
39 #define MAXSHIFTINGS 50 /**< maximal number of non improving shiftings */
40 #define WEIGHTFACTOR 1.1
41 
42 
43 /* locally defined heuristic data */
44 struct SCIP_HeurData
45 {
46  SCIP_SOL* sol; /**< working solution */
47  SCIP_Longint lastlp; /**< last LP number where the heuristic was applied */
48  unsigned int randseed; /**< seed value for random number generator */
49 };
50 
51 
52 /*
53  * local methods
54  */
55 
56 /** update row violation arrays after a row's activity value changed */
57 static
59  SCIP* scip, /**< SCIP data structure */
60  SCIP_ROW* row, /**< LP row */
61  SCIP_ROW** violrows, /**< array with currently violated rows */
62  int* violrowpos, /**< position of LP rows in violrows array */
63  int* nviolrows, /**< pointer to the number of currently violated rows */
64  SCIP_Real oldactivity, /**< old activity value of LP row */
65  SCIP_Real newactivity /**< new activity value of LP row */
66  )
67 {
68  SCIP_Real lhs;
69  SCIP_Real rhs;
70  SCIP_Bool oldviol;
71  SCIP_Bool newviol;
72 
73  assert(violrows != NULL);
74  assert(violrowpos != NULL);
75  assert(nviolrows != NULL);
76 
77  lhs = SCIProwGetLhs(row);
78  rhs = SCIProwGetRhs(row);
79  oldviol = (SCIPisFeasLT(scip, oldactivity, lhs) || SCIPisFeasGT(scip, oldactivity, rhs));
80  newviol = (SCIPisFeasLT(scip, newactivity, lhs) || SCIPisFeasGT(scip, newactivity, rhs));
81  if( oldviol != newviol )
82  {
83  int rowpos;
84  int violpos;
85 
86  rowpos = SCIProwGetLPPos(row);
87  assert(rowpos >= 0);
88 
89  if( oldviol )
90  {
91  /* the row violation was repaired: remove row from violrows array, decrease violation count */
92  violpos = violrowpos[rowpos];
93  assert(0 <= violpos && violpos < *nviolrows);
94  assert(violrows[violpos] == row);
95  violrowpos[rowpos] = -1;
96  if( violpos != *nviolrows-1 )
97  {
98  violrows[violpos] = violrows[*nviolrows-1];
99  violrowpos[SCIProwGetLPPos(violrows[violpos])] = violpos;
100  }
101  (*nviolrows)--;
102  }
103  else
104  {
105  /* the row is now violated: add row to violrows array, increase violation count */
106  assert(violrowpos[rowpos] == -1);
107  violrows[*nviolrows] = row;
108  violrowpos[rowpos] = *nviolrows;
109  (*nviolrows)++;
110  }
111  }
112 }
113 
114 /** update row activities after a variable's solution value changed */
115 static
117  SCIP* scip, /**< SCIP data structure */
118  SCIP_Real* activities, /**< LP row activities */
119  SCIP_ROW** violrows, /**< array with currently violated rows */
120  int* violrowpos, /**< position of LP rows in violrows array */
121  int* nviolrows, /**< pointer to the number of currently violated rows */
122  int nlprows, /**< number of rows in current LP */
123  SCIP_VAR* var, /**< variable that has been changed */
124  SCIP_Real oldsolval, /**< old solution value of variable */
125  SCIP_Real newsolval /**< new solution value of variable */
126  )
127 {
128  SCIP_COL* col;
129  SCIP_ROW** colrows;
130  SCIP_Real* colvals;
131  SCIP_Real delta;
132  int ncolrows;
133  int r;
134 
135  assert(activities != NULL);
136  assert(nviolrows != NULL);
137  assert(0 <= *nviolrows && *nviolrows <= nlprows);
138 
139  delta = newsolval - oldsolval;
140  col = SCIPvarGetCol(var);
141  colrows = SCIPcolGetRows(col);
142  colvals = SCIPcolGetVals(col);
143  ncolrows = SCIPcolGetNLPNonz(col);
144  assert(ncolrows == 0 || (colrows != NULL && colvals != NULL));
145 
146  for( r = 0; r < ncolrows; ++r )
147  {
148  SCIP_ROW* row;
149  int rowpos;
150 
151  row = colrows[r];
152  rowpos = SCIProwGetLPPos(row);
153  assert(-1 <= rowpos && rowpos < nlprows);
154 
155  if( rowpos >= 0 && !SCIProwIsLocal(row) )
156  {
157  SCIP_Real oldactivity;
158  SCIP_Real newactivity;
159 
160  assert(SCIProwIsInLP(row));
161 
162  /* update row activity */
163  oldactivity = activities[rowpos];
164  if( !SCIPisInfinity(scip, -oldactivity) && !SCIPisInfinity(scip, oldactivity) )
165  {
166  newactivity = oldactivity + delta * colvals[r];
167  if( SCIPisInfinity(scip, newactivity) )
168  newactivity = SCIPinfinity(scip);
169  else if( SCIPisInfinity(scip, -newactivity) )
170  newactivity = -SCIPinfinity(scip);
171  activities[rowpos] = newactivity;
172 
173  /* update row violation arrays */
174  updateViolations(scip, row, violrows, violrowpos, nviolrows, oldactivity, newactivity);
175  }
176  }
177  }
178 
179  return SCIP_OKAY;
180 }
181 
182 /** returns a variable, that pushes activity of the row in the given direction with minimal negative impact on other rows;
183  * if variables have equal impact, chooses the one with best objective value improvement in corresponding direction;
184  * prefer fractional integers over other variables in order to become integral during the process;
185  * shifting in a direction is forbidden, if this forces the objective value over the upper bound, or if the variable
186  * was already shifted in the opposite direction
187  */
188 static
190  SCIP* scip, /**< SCIP data structure */
191  SCIP_SOL* sol, /**< primal solution */
192  SCIP_ROW* row, /**< LP row */
193  SCIP_Real rowactivity, /**< activity of LP row */
194  int direction, /**< should the activity be increased (+1) or decreased (-1)? */
195  SCIP_Real* nincreases, /**< array with weighted number of increasings per variables */
196  SCIP_Real* ndecreases, /**< array with weighted number of decreasings per variables */
197  SCIP_Real increaseweight, /**< current weight of increase/decrease updates */
198  SCIP_VAR** shiftvar, /**< pointer to store the shifting variable, returns NULL if impossible */
199  SCIP_Real* oldsolval, /**< pointer to store old solution value of shifting variable */
200  SCIP_Real* newsolval /**< pointer to store new (shifted) solution value of shifting variable */
201  )
202 {
203  SCIP_COL** rowcols;
204  SCIP_Real* rowvals;
205  int nrowcols;
206  SCIP_Real activitydelta;
207  SCIP_Real bestshiftscore;
208  SCIP_Real bestdeltaobj;
209  int c;
210 
211  assert(direction == +1 || direction == -1);
212  assert(nincreases != NULL);
213  assert(ndecreases != NULL);
214  assert(shiftvar != NULL);
215  assert(oldsolval != NULL);
216  assert(newsolval != NULL);
217 
218  /* get row entries */
219  rowcols = SCIProwGetCols(row);
220  rowvals = SCIProwGetVals(row);
221  nrowcols = SCIProwGetNLPNonz(row);
222 
223  /* calculate how much the activity must be shifted in order to become feasible */
224  activitydelta = (direction == +1 ? SCIProwGetLhs(row) - rowactivity : SCIProwGetRhs(row) - rowactivity);
225  assert((direction == +1 && SCIPisPositive(scip, activitydelta))
226  || (direction == -1 && SCIPisNegative(scip, activitydelta)));
227 
228  /* select shifting variable */
229  bestshiftscore = SCIP_REAL_MAX;
230  bestdeltaobj = SCIPinfinity(scip);
231  *shiftvar = NULL;
232  *newsolval = 0.0;
233  *oldsolval = 0.0;
234  for( c = 0; c < nrowcols; ++c )
235  {
236  SCIP_COL* col;
237  SCIP_VAR* var;
238  SCIP_Real val;
239  SCIP_Real solval;
240  SCIP_Real shiftval;
241  SCIP_Real shiftscore;
242  SCIP_Bool isinteger;
243  SCIP_Bool isfrac;
244  SCIP_Bool increase;
245 
246  col = rowcols[c];
247  var = SCIPcolGetVar(col);
248  val = rowvals[c];
249  assert(!SCIPisZero(scip, val));
250  solval = SCIPgetSolVal(scip, sol, var);
251 
253  isfrac = isinteger && !SCIPisFeasIntegral(scip, solval);
254  increase = (direction * val > 0.0);
255 
256  /* calculate the score of the shifting (prefer smaller values) */
257  if( isfrac )
258  shiftscore = increase ? -1.0 / (SCIPvarGetNLocksUp(var) + 1.0) :
259  -1.0 / (SCIPvarGetNLocksDown(var) + 1.0);
260  else
261  {
262  int probindex;
263  probindex = SCIPvarGetProbindex(var);
264 
265  if( increase )
266  shiftscore = ndecreases[probindex]/increaseweight;
267  else
268  shiftscore = nincreases[probindex]/increaseweight;
269  if( isinteger )
270  shiftscore += 1.0;
271  }
272 
273  if( shiftscore <= bestshiftscore )
274  {
275  SCIP_Real deltaobj;
276 
277  if( !increase )
278  {
279  /* shifting down */
280  assert(direction * val < 0.0);
281  if( isfrac )
282  shiftval = SCIPfeasFloor(scip, solval);
283  else
284  {
285  SCIP_Real lb;
286 
287  assert(activitydelta/val < 0.0);
288  shiftval = solval + activitydelta/val;
289  assert(shiftval <= solval); /* may be equal due to numerical digit erasement in the subtraction */
290  if( SCIPvarIsIntegral(var) )
291  shiftval = SCIPfeasFloor(scip, shiftval);
292  lb = SCIPvarGetLbGlobal(var);
293  shiftval = MAX(shiftval, lb);
294  }
295  }
296  else
297  {
298  /* shifting up */
299  assert(direction * val > 0.0);
300  if( isfrac )
301  shiftval = SCIPfeasCeil(scip, solval);
302  else
303  {
304  SCIP_Real ub;
305 
306  assert(activitydelta/val > 0.0);
307  shiftval = solval + activitydelta/val;
308  assert(shiftval >= solval); /* may be equal due to numerical digit erasement in the subtraction */
309  if( SCIPvarIsIntegral(var) )
310  shiftval = SCIPfeasCeil(scip, shiftval);
311  ub = SCIPvarGetUbGlobal(var);
312  shiftval = MIN(shiftval, ub);
313  }
314  }
315 
316  if( SCIPisEQ(scip, shiftval, solval) )
317  continue;
318 
319  deltaobj = SCIPvarGetObj(var) * (shiftval - solval);
320  if( shiftscore < bestshiftscore || deltaobj < bestdeltaobj )
321  {
322  bestshiftscore = shiftscore;
323  bestdeltaobj = deltaobj;
324  *shiftvar = var;
325  *oldsolval = solval;
326  *newsolval = shiftval;
327  }
328  }
329  }
330 
331  return SCIP_OKAY;
332 }
333 
334 /** returns a fractional variable, that has most impact on rows in opposite direction, i.e. that is most crucial to
335  * fix in the other direction;
336  * if variables have equal impact, chooses the one with best objective value improvement in corresponding direction;
337  * shifting in a direction is forbidden, if this forces the objective value over the upper bound
338  */
339 static
341  SCIP* scip, /**< SCIP data structure */
342  SCIP_SOL* sol, /**< primal solution */
343  SCIP_Real minobj, /**< minimal objective value possible after shifting remaining fractional vars */
344  SCIP_VAR** lpcands, /**< fractional variables in LP */
345  int nlpcands, /**< number of fractional variables in LP */
346  SCIP_VAR** shiftvar, /**< pointer to store the shifting variable, returns NULL if impossible */
347  SCIP_Real* oldsolval, /**< old (fractional) solution value of shifting variable */
348  SCIP_Real* newsolval /**< new (shifted) solution value of shifting variable */
349  )
350 {
351  SCIP_VAR* var;
352  SCIP_Real solval;
353  SCIP_Real shiftval;
354  SCIP_Real obj;
355  SCIP_Real deltaobj;
356  SCIP_Real bestdeltaobj;
357  int maxnlocks;
358  int nlocks;
359  int v;
360 
361  assert(shiftvar != NULL);
362  assert(oldsolval != NULL);
363  assert(newsolval != NULL);
364 
365  /* select shifting variable */
366  maxnlocks = -1;
367  bestdeltaobj = SCIPinfinity(scip);
368  *shiftvar = NULL;
369  for( v = 0; v < nlpcands; ++v )
370  {
371  var = lpcands[v];
373 
374  solval = SCIPgetSolVal(scip, sol, var);
375  if( !SCIPisFeasIntegral(scip, solval) )
376  {
377  obj = SCIPvarGetObj(var);
378 
379  /* shifting down */
380  nlocks = SCIPvarGetNLocksUp(var);
381  if( nlocks >= maxnlocks )
382  {
383  shiftval = SCIPfeasFloor(scip, solval);
384  deltaobj = obj * (shiftval - solval);
385  if( (nlocks > maxnlocks || deltaobj < bestdeltaobj) && minobj - obj < SCIPgetCutoffbound(scip) )
386  {
387  maxnlocks = nlocks;
388  bestdeltaobj = deltaobj;
389  *shiftvar = var;
390  *oldsolval = solval;
391  *newsolval = shiftval;
392  }
393  }
394 
395  /* shifting up */
396  nlocks = SCIPvarGetNLocksDown(var);
397  if( nlocks >= maxnlocks )
398  {
399  shiftval = SCIPfeasCeil(scip, solval);
400  deltaobj = obj * (shiftval - solval);
401  if( (nlocks > maxnlocks || deltaobj < bestdeltaobj) && minobj + obj < SCIPgetCutoffbound(scip) )
402  {
403  maxnlocks = nlocks;
404  bestdeltaobj = deltaobj;
405  *shiftvar = var;
406  *oldsolval = solval;
407  *newsolval = shiftval;
408  }
409  }
410  }
411  }
412 
413  return SCIP_OKAY;
414 }
415 
416 /** adds a given value to the fractionality counters of the rows in which the given variable appears */
417 static
419  int* nfracsinrow, /**< array to store number of fractional variables per row */
420  int nlprows, /**< number of rows in LP */
421  SCIP_VAR* var, /**< variable for which the counting should be updated */
422  int incval /**< value that should be added to the corresponding array entries */
423  )
424 {
425  SCIP_COL* col;
426  SCIP_ROW** rows;
427  int nrows;
428  int r;
429 
430  col = SCIPvarGetCol(var);
431  rows = SCIPcolGetRows(col);
432  nrows = SCIPcolGetNLPNonz(col);
433  for( r = 0; r < nrows; ++r )
434  {
435  int rowidx;
436 
437  rowidx = SCIProwGetLPPos(rows[r]);
438  assert(0 <= rowidx && rowidx < nlprows);
439  nfracsinrow[rowidx] += incval;
440  assert(nfracsinrow[rowidx] >= 0);
441  }
442 }
443 
444 
445 /*
446  * Callback methods
447  */
448 
449 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
450 static
451 SCIP_DECL_HEURCOPY(heurCopyShifting)
452 { /*lint --e{715}*/
453  assert(scip != NULL);
454  assert(heur != NULL);
455  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
456 
457  /* call inclusion method of primal heuristic */
459 
460  return SCIP_OKAY;
461 }
462 
463 
464 /** initialization method of primal heuristic (called after problem was transformed) */
465 static
466 SCIP_DECL_HEURINIT(heurInitShifting) /*lint --e{715}*/
467 { /*lint --e{715}*/
468  SCIP_HEURDATA* heurdata;
469 
470  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
471  assert(SCIPheurGetData(heur) == NULL);
472 
473  /* create heuristic data */
474  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
475  SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
476  heurdata->lastlp = -1;
477  heurdata->randseed = 0;
478  SCIPheurSetData(heur, heurdata);
479 
480  return SCIP_OKAY;
481 }
482 
483 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
484 static
485 SCIP_DECL_HEUREXIT(heurExitShifting) /*lint --e{715}*/
486 { /*lint --e{715}*/
487  SCIP_HEURDATA* heurdata;
488 
489  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
490 
491  /* free heuristic data */
492  heurdata = SCIPheurGetData(heur);
493  assert(heurdata != NULL);
494  SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
495  SCIPfreeMemory(scip, &heurdata);
496  SCIPheurSetData(heur, NULL);
497 
498  return SCIP_OKAY;
499 }
500 
501 /** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
502 static
503 SCIP_DECL_HEURINITSOL(heurInitsolShifting)
504 {
505  SCIP_HEURDATA* heurdata;
506 
507  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
508 
509  heurdata = SCIPheurGetData(heur);
510  assert(heurdata != NULL);
511  heurdata->lastlp = -1;
512 
513  return SCIP_OKAY;
514 }
515 
516 
517 /** execution method of primal heuristic */
518 static
519 SCIP_DECL_HEUREXEC(heurExecShifting) /*lint --e{715}*/
520 { /*lint --e{715}*/
521  SCIP_HEURDATA* heurdata;
522  SCIP_SOL* sol;
523  SCIP_VAR** lpcands;
524  SCIP_Real* lpcandssol;
525  SCIP_ROW** lprows;
526  SCIP_Real* activities;
527  SCIP_ROW** violrows;
528  SCIP_Real* nincreases;
529  SCIP_Real* ndecreases;
530  int* violrowpos;
531  int* nfracsinrow;
532  SCIP_Real increaseweight;
533  SCIP_Real obj;
534  SCIP_Real bestshiftval;
535  SCIP_Real minobj;
536  int nlpcands;
537  int nlprows;
538  int nvars;
539  int nfrac;
540  int nviolrows;
541  int nprevviolrows;
542  int minnviolrows;
543  int nnonimprovingshifts;
544  int c;
545  int r;
546  SCIP_Longint nlps;
547  SCIP_Longint ncalls;
548  SCIP_Longint nsolsfound;
549  SCIP_Longint nnodes;
550 
551  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
552  assert(scip != NULL);
553  assert(result != NULL);
554  assert(SCIPhasCurrentNodeLP(scip));
555 
556  *result = SCIP_DIDNOTRUN;
557 
558  /* only call heuristic, if an optimal LP solution is at hand */
560  return SCIP_OKAY;
561 
562  /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
563  if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
564  return SCIP_OKAY;
565 
566  /* get heuristic data */
567  heurdata = SCIPheurGetData(heur);
568  assert(heurdata != NULL);
569 
570  /* don't call heuristic, if we have already processed the current LP solution */
571  nlps = SCIPgetNLPs(scip);
572  if( nlps == heurdata->lastlp )
573  return SCIP_OKAY;
574  heurdata->lastlp = nlps;
575 
576  /* don't call heuristic, if it was not successful enough in the past */
577  ncalls = SCIPheurGetNCalls(heur);
578  nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + SCIPheurGetNSolsFound(heur);
579  nnodes = SCIPgetNNodes(scip);
580  if( nnodes % ((ncalls/100)/(nsolsfound+1)+1) != 0 )
581  return SCIP_OKAY;
582 
583  /* get fractional variables, that should be integral */
584  /* todo check if heuristic should include implicit integer variables for its calculations */
585  SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, NULL) );
586  nfrac = nlpcands;
587 
588  /* only call heuristic, if LP solution is fractional */
589  if( nfrac == 0 )
590  return SCIP_OKAY;
591 
592  *result = SCIP_DIDNOTFIND;
593 
594  /* get LP rows */
595  SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) );
596 
597  SCIPdebugMessage("executing shifting heuristic: %d LP rows, %d fractionals\n", nlprows, nfrac);
598 
599  /* get memory for activities, violated rows, and row violation positions */
600  nvars = SCIPgetNVars(scip);
601  SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) );
602  SCIP_CALL( SCIPallocBufferArray(scip, &violrows, nlprows) );
603  SCIP_CALL( SCIPallocBufferArray(scip, &violrowpos, nlprows) );
604  SCIP_CALL( SCIPallocBufferArray(scip, &nfracsinrow, nlprows) );
605  SCIP_CALL( SCIPallocBufferArray(scip, &nincreases, nvars) );
606  SCIP_CALL( SCIPallocBufferArray(scip, &ndecreases, nvars) );
607  BMSclearMemoryArray(nfracsinrow, nlprows);
608  BMSclearMemoryArray(nincreases, nvars);
609  BMSclearMemoryArray(ndecreases, nvars);
610 
611  /* get the activities for all globally valid rows;
612  * the rows should be feasible, but due to numerical inaccuracies in the LP solver, they can be violated
613  */
614  nviolrows = 0;
615  for( r = 0; r < nlprows; ++r )
616  {
617  SCIP_ROW* row;
618 
619  row = lprows[r];
620  assert(SCIProwGetLPPos(row) == r);
621 
622  if( !SCIProwIsLocal(row) )
623  {
624  activities[r] = SCIPgetRowActivity(scip, row);
625  if( SCIPisFeasLT(scip, activities[r], SCIProwGetLhs(row))
626  || SCIPisFeasGT(scip, activities[r], SCIProwGetRhs(row)) )
627  {
628  violrows[nviolrows] = row;
629  violrowpos[r] = nviolrows;
630  nviolrows++;
631  }
632  else
633  violrowpos[r] = -1;
634  }
635  }
636 
637  /* calc the current number of fractional variables in rows */
638  for( c = 0; c < nlpcands; ++c )
639  addFracCounter(nfracsinrow, nlprows, lpcands[c], +1);
640 
641  /* get the working solution from heuristic's local data */
642  sol = heurdata->sol;
643  assert(sol != NULL);
644 
645  /* copy the current LP solution to the working solution */
646  SCIP_CALL( SCIPlinkLPSol(scip, sol) );
647 
648  /* calculate the minimal objective value possible after rounding fractional variables */
649  minobj = SCIPgetSolTransObj(scip, sol);
650  assert(minobj < SCIPgetCutoffbound(scip));
651  for( c = 0; c < nlpcands; ++c )
652  {
653  obj = SCIPvarGetObj(lpcands[c]);
654  bestshiftval = obj > 0.0 ? SCIPfeasFloor(scip, lpcandssol[c]) : SCIPfeasCeil(scip, lpcandssol[c]);
655  minobj += obj * (bestshiftval - lpcandssol[c]);
656  }
657 
658  /* try to shift remaining variables in order to become/stay feasible */
659  nnonimprovingshifts = 0;
660  minnviolrows = INT_MAX;
661  increaseweight = 1.0;
662  while( (nfrac > 0 || nviolrows > 0) && nnonimprovingshifts < MAXSHIFTINGS )
663  {
664  SCIP_VAR* shiftvar;
665  SCIP_Real oldsolval;
666  SCIP_Real newsolval;
667  SCIP_Bool oldsolvalisfrac;
668  int probindex;
669 
670  SCIPdebugMessage("shifting heuristic: nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g), cutoff=%g\n",
671  nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj),
673 
674  nprevviolrows = nviolrows;
675 
676  /* choose next variable to process:
677  * - if a violated row exists, shift a variable decreasing the violation, that has least impact on other rows
678  * - otherwise, shift a variable, that has strongest devastating impact on rows in opposite direction
679  */
680  shiftvar = NULL;
681  oldsolval = 0.0;
682  newsolval = 0.0;
683  if( nviolrows > 0 && (nfrac == 0 || nnonimprovingshifts < MAXSHIFTINGS-1) )
684  {
685  SCIP_ROW* row;
686  int rowidx;
687  int rowpos;
688  int direction;
689 
690  rowidx = -1;
691  rowpos = -1;
692  row = NULL;
693  if( nfrac > 0 )
694  {
695  for( rowidx = nviolrows-1; rowidx >= 0; --rowidx )
696  {
697  row = violrows[rowidx];
698  rowpos = SCIProwGetLPPos(row);
699  assert(violrowpos[rowpos] == rowidx);
700  if( nfracsinrow[rowpos] > 0 )
701  break;
702  }
703  }
704  if( rowidx == -1 )
705  {
706  rowidx = SCIPgetRandomInt(0, nviolrows-1, &heurdata->randseed);
707  row = violrows[rowidx];
708  rowpos = SCIProwGetLPPos(row);
709  assert(0 <= rowpos && rowpos < nlprows);
710  assert(violrowpos[rowpos] == rowidx);
711  assert(nfracsinrow[rowpos] == 0);
712  }
713  assert(violrowpos[rowpos] == rowidx);
714 
715  SCIPdebugMessage("shifting heuristic: try to fix violated row <%s>: %g <= %g <= %g\n",
716  SCIProwGetName(row), SCIProwGetLhs(row), activities[rowpos], SCIProwGetRhs(row));
717  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
718 
719  /* get direction in which activity must be shifted */
720  assert(SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row))
721  || SCIPisFeasGT(scip, activities[rowpos], SCIProwGetRhs(row)));
722  direction = SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row)) ? +1 : -1;
723 
724  /* search a variable that can shift the activity in the necessary direction */
725  SCIP_CALL( selectShifting(scip, sol, row, activities[rowpos], direction,
726  nincreases, ndecreases, increaseweight, &shiftvar, &oldsolval, &newsolval) );
727  }
728 
729  if( shiftvar == NULL && nfrac > 0 )
730  {
731  SCIPdebugMessage("shifting heuristic: search rounding variable and try to stay feasible\n");
732  SCIP_CALL( selectEssentialRounding(scip, sol, minobj, lpcands, nlpcands, &shiftvar, &oldsolval, &newsolval) );
733  }
734 
735  /* check, whether shifting was possible */
736  if( shiftvar == NULL || SCIPisEQ(scip, oldsolval, newsolval) )
737  {
738  SCIPdebugMessage("shifting heuristic: -> didn't find a shifting variable\n");
739  break;
740  }
741 
742  SCIPdebugMessage("shifting heuristic: -> shift var <%s>[%g,%g], type=%d, oldval=%g, newval=%g, obj=%g\n",
743  SCIPvarGetName(shiftvar), SCIPvarGetLbGlobal(shiftvar), SCIPvarGetUbGlobal(shiftvar), SCIPvarGetType(shiftvar),
744  oldsolval, newsolval, SCIPvarGetObj(shiftvar));
745 
746  /* update row activities of globally valid rows */
747  SCIP_CALL( updateActivities(scip, activities, violrows, violrowpos, &nviolrows, nlprows,
748  shiftvar, oldsolval, newsolval) );
749  if( nviolrows >= nprevviolrows )
750  nnonimprovingshifts++;
751  else if( nviolrows < minnviolrows )
752  {
753  minnviolrows = nviolrows;
754  nnonimprovingshifts = 0;
755  }
756 
757  /* store new solution value and decrease fractionality counter */
758  SCIP_CALL( SCIPsetSolVal(scip, sol, shiftvar, newsolval) );
759 
760  /* update fractionality counter and minimal objective value possible after shifting remaining variables */
761  oldsolvalisfrac = !SCIPisFeasIntegral(scip, oldsolval)
762  && (SCIPvarGetType(shiftvar) == SCIP_VARTYPE_BINARY || SCIPvarGetType(shiftvar) == SCIP_VARTYPE_INTEGER);
763  obj = SCIPvarGetObj(shiftvar);
764  if( (SCIPvarGetType(shiftvar) == SCIP_VARTYPE_BINARY || SCIPvarGetType(shiftvar) == SCIP_VARTYPE_INTEGER)
765  && oldsolvalisfrac )
766  {
767  assert(SCIPisFeasIntegral(scip, newsolval));
768  nfrac--;
769  nnonimprovingshifts = 0;
770  minnviolrows = INT_MAX;
771  addFracCounter(nfracsinrow, nlprows, shiftvar, -1);
772 
773  /* the rounding was already calculated into the minobj -> update only if rounding in "wrong" direction */
774  if( obj > 0.0 && newsolval > oldsolval )
775  minobj += obj;
776  else if( obj < 0.0 && newsolval < oldsolval )
777  minobj -= obj;
778  }
779  else
780  {
781  /* update minimal possible objective value */
782  minobj += obj * (newsolval - oldsolval);
783  }
784 
785  /* update increase/decrease arrays */
786  if( !oldsolvalisfrac )
787  {
788  probindex = SCIPvarGetProbindex(shiftvar);
789  assert(0 <= probindex && probindex < nvars);
790  increaseweight *= WEIGHTFACTOR;
791  if( newsolval < oldsolval )
792  ndecreases[probindex] += increaseweight;
793  else
794  nincreases[probindex] += increaseweight;
795  if( increaseweight >= 1e+09 )
796  {
797  int i;
798 
799  for( i = 0; i < nvars; ++i )
800  {
801  nincreases[i] /= increaseweight;
802  ndecreases[i] /= increaseweight;
803  }
804  increaseweight = 1.0;
805  }
806  }
807 
808  SCIPdebugMessage("shifting heuristic: -> nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n",
809  nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj));
810  }
811 
812  /* check, if the new solution is feasible */
813  if( nfrac == 0 && nviolrows == 0 )
814  {
815  SCIP_Bool stored;
816 
817  /* check solution for feasibility, and add it to solution store if possible
818  * neither integrality nor feasibility of LP rows has to be checked, because this is already
819  * done in the shifting heuristic itself; however, we better check feasibility of LP rows,
820  * because of numerical problems with activity updating
821  */
822  SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, TRUE, &stored) );
823 
824  if( stored )
825  {
826  SCIPdebugMessage("found feasible shifted solution:\n");
827  SCIPdebug( SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ) );
828  *result = SCIP_FOUNDSOL;
829  }
830  }
831 
832  /* free memory buffers */
833  SCIPfreeBufferArray(scip, &ndecreases);
834  SCIPfreeBufferArray(scip, &nincreases);
835  SCIPfreeBufferArray(scip, &nfracsinrow);
836  SCIPfreeBufferArray(scip, &violrowpos);
837  SCIPfreeBufferArray(scip, &violrows);
838  SCIPfreeBufferArray(scip, &activities);
839 
840  return SCIP_OKAY;
841 }
842 
843 
844 /*
845  * heuristic specific interface methods
846  */
847 
848 /** creates the shifting heuristic with infeasibility recovering and includes it in SCIP */
850  SCIP* scip /**< SCIP data structure */
851  )
852 {
853  SCIP_HEUR* heur;
854 
855  /* include primal heuristic */
856  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
858  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecShifting, NULL) );
859 
860  assert(heur != NULL);
861 
862  /* set non-NULL pointers to callback methods */
863  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyShifting) );
864  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitShifting) );
865  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitShifting) );
866  SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolShifting) );
867 
868  return SCIP_OKAY;
869 }
870 
SCIP_RETCODE SCIPsetHeurInitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINITSOL((*heurinitsol)))
Definition: scip.c:7078
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38254
static SCIP_DECL_HEUREXEC(heurExecShifting)
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip.c:30002
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:38397
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:10071
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:15788
static SCIP_RETCODE selectEssentialRounding(SCIP *scip, SCIP_SOL *sol, SCIP_Real minobj, SCIP_VAR **lpcands, int nlpcands, SCIP_VAR **shiftvar, SCIP_Real *oldsolval, SCIP_Real *newsolval)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:38360
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:591
SCIP_Longint SCIPheurGetNCalls(SCIP_HEUR *heur)
Definition: heur.c:717
SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
Definition: scip.c:7014
LP rounding heuristic that tries to recover from intermediate infeasibilities and shifts continuous v...
SCIP_Longint SCIPheurGetNSolsFound(SCIP_HEUR *heur)
Definition: heur.c:727
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38667
#define NULL
Definition: lpi_spx.cpp:129
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:38803
#define HEUR_FREQ
Definition: heur_shifting.c:33
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:18637
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:18583
#define HEUR_FREQOFS
Definition: heur_shifting.c:34
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:16380
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:31639
SCIP_RETCODE SCIPincludeHeurBasic(SCIP *scip, SCIP_HEUR **heur, const char *name, const char *desc, char dispchar, int priority, int freq, int freqofs, int maxdepth, unsigned int timingmask, SCIP_Bool usessubscip, SCIP_DECL_HEUREXEC((*heurexec)), SCIP_HEURDATA *heurdata)
Definition: scip.c:6969
int SCIProwGetNLPNonz(SCIP_ROW *row)
Definition: lp.c:18572
static SCIP_DECL_HEURINITSOL(heurInitsolShifting)
#define FALSE
Definition: def.h:52
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31902
#define TRUE
Definition: def.h:51
#define SCIPdebug(x)
Definition: pub_message.h:74
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
struct SCIP_HeurData SCIP_HEURDATA
Definition: type_heur.h:44
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:38779
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
Definition: scip.c:35229
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:24136
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:31775
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:19214
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:16227
static SCIP_RETCODE updateActivities(SCIP *scip, SCIP_Real *activities, SCIP_ROW **violrows, int *violrowpos, int *nviolrows, int nlprows, SCIP_VAR *var, SCIP_Real oldsolval, SCIP_Real newsolval)
#define HEUR_DISPCHAR
Definition: heur_shifting.c:31
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip.c:24179
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
Definition: scip.c:38815
SCIP_RETCODE SCIPincludeHeurShifting(SCIP *scip)
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31855
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:15979
#define HEUR_USESSUBSCIP
Definition: heur_shifting.c:37
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition: lp.c:18506
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:38421
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:19159
#define HEUR_PRIORITY
Definition: heur_shifting.c:32
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:19221
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:18647
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:30856
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:18848
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:18746
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:16093
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip.c:24447
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3214
#define WEIGHTFACTOR
Definition: heur_shifting.c:40
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:38349
#define SCIP_CALL(x)
Definition: def.h:258
SCIP_Bool SCIPhasCurrentNodeLP(SCIP *scip)
Definition: scip.c:24051
int SCIPcolGetNLPNonz(SCIP_COL *col)
Definition: lp.c:18495
SCIP_Longint SCIPgetNLPs(SCIP *scip)
Definition: scip.c:34128
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:18696
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38705
#define HEUR_MAXDEPTH
Definition: heur_shifting.c:35
void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
Definition: heur.c:512
#define SCIP_Bool
Definition: def.h:49
SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
Definition: scip.c:31962
static SCIP_DECL_HEURINIT(heurInitShifting)
#define MAX(x, y)
Definition: tclique_def.h:75
static void updateViolations(SCIP *scip, SCIP_ROW *row, SCIP_ROW **violrows, int *violrowpos, int *nviolrows, SCIP_Real oldactivity, SCIP_Real newactivity)
Definition: heur_shifting.c:58
SCIP_RETCODE SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31444
#define HEUR_NAME
Definition: heur_shifting.c:29
SCIP_RETCODE SCIPsetHeurExit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXIT((*heurexit)))
Definition: scip.c:7062
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38330
int SCIPgetRandomInt(int minrandval, int maxrandval, unsigned int *seedp)
Definition: misc.c:7212
SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
Definition: scip.c:7046
static void addFracCounter(int *nfracsinrow, int nlprows, SCIP_VAR *var, int incval)
#define SCIP_REAL_MAX
Definition: def.h:124
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:15953
SCIP_Longint SCIPheurGetNBestSolsFound(SCIP_HEUR *heur)
Definition: heur.c:737
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:19176
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:16370
static SCIP_DECL_HEURCOPY(heurCopyShifting)
#define MAXSHIFTINGS
Definition: heur_shifting.c:39
static SCIP_RETCODE selectShifting(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *row, SCIP_Real rowactivity, int direction, SCIP_Real *nincreases, SCIP_Real *ndecreases, SCIP_Real increaseweight, SCIP_VAR **shiftvar, SCIP_Real *oldsolval, SCIP_Real *newsolval)
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:18593
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:16072
#define SCIP_Real
Definition: def.h:123
#define MIN(x, y)
Definition: memory.c:59
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:26010
#define SCIP_Longint
Definition: def.h:107
#define HEUR_DESC
Definition: heur_shifting.c:30
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:18826
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:25921
SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
Definition: heur.c:502
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:98
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:18407
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:38409
SCIP_Real * SCIPcolGetVals(SCIP_COL *col)
Definition: lp.c:18516
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3159
SCIP_RETCODE SCIPtrySol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
Definition: scip.c:32978
static SCIP_DECL_HEUREXIT(heurExitShifting)
SCIP_Longint SCIPgetNNodes(SCIP *scip)
Definition: scip.c:34065
#define HEUR_TIMING
Definition: heur_shifting.c:36
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip.c:32161
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:31403