Scippy

SCIP

Solving Constraint Integer Programs

heur_pscostdiving.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_pscostdiving.c
17  * @brief LP diving heuristic that chooses fixings w.r.t. the pseudo cost values
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_pscostdiving.h"
27 
28 
29 #define HEUR_NAME "pscostdiving"
30 #define HEUR_DESC "LP diving heuristic that chooses fixings w.r.t. the pseudo cost values"
31 #define HEUR_DISPCHAR 'p'
32 #define HEUR_PRIORITY -1002000
33 #define HEUR_FREQ 10
34 #define HEUR_FREQOFS 2
35 #define HEUR_MAXDEPTH -1
36 #define HEUR_TIMING SCIP_HEURTIMING_AFTERLPPLUNGE
37 #define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
38 
39 
40 /*
41  * Default parameter settings
42  */
43 
44 #define DEFAULT_MINRELDEPTH 0.0 /**< minimal relative depth to start diving */
45 #define DEFAULT_MAXRELDEPTH 1.0 /**< maximal relative depth to start diving */
46 #define DEFAULT_MAXLPITERQUOT 0.05 /**< maximal fraction of diving LP iterations compared to node LP iterations */
47 #define DEFAULT_MAXLPITEROFS 1000 /**< additional number of allowed LP iterations */
48 #define DEFAULT_MAXDIVEUBQUOT 0.8 /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
49  * where diving is performed (0.0: no limit) */
50 #define DEFAULT_MAXDIVEAVGQUOT 0.0 /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
51  * where diving is performed (0.0: no limit) */
52 #define DEFAULT_MAXDIVEUBQUOTNOSOL 0.1 /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
53 #define DEFAULT_MAXDIVEAVGQUOTNOSOL 0.0 /**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
54 #define DEFAULT_BACKTRACK TRUE /**< use one level of backtracking if infeasibility is encountered? */
55 
56 #define MINLPITER 10000 /**< minimal number of LP iterations allowed in each LP solving call */
57 
58 
59 /* locally defined heuristic data */
60 struct SCIP_HeurData
61 {
62  SCIP_SOL* sol; /**< working solution */
63  SCIP_Real minreldepth; /**< minimal relative depth to start diving */
64  SCIP_Real maxreldepth; /**< maximal relative depth to start diving */
65  SCIP_Real maxlpiterquot; /**< maximal fraction of diving LP iterations compared to node LP iterations */
66  int maxlpiterofs; /**< additional number of allowed LP iterations */
67  SCIP_Real maxdiveubquot; /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
68  * where diving is performed (0.0: no limit) */
69  SCIP_Real maxdiveavgquot; /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
70  * where diving is performed (0.0: no limit) */
71  SCIP_Real maxdiveubquotnosol; /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
72  SCIP_Real maxdiveavgquotnosol;/**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
73  SCIP_Bool backtrack; /**< use one level of backtracking if infeasibility is encountered? */
74  SCIP_Longint nlpiterations; /**< LP iterations used in this heuristic */
75  int nsuccess; /**< number of runs that produced at least one feasible solution */
76 };
77 
78 
79 /*
80  * local methods
81  */
82 
83 /** calculates the pseudocost score for a given variable w.r.t. a given solution value and a given rounding direction */
84 static
85 void calcPscostQuot(
86  SCIP* scip, /**< SCIP data structure */
87  SCIP_VAR* var, /**< problem variable */
88  SCIP_Real primsol, /**< primal solution of variable */
89  SCIP_Real frac, /**< fractionality of variable */
90  int rounddir, /**< -1: round down, +1: round up, 0: select due to pseudo cost values */
91  SCIP_Real* pscostquot, /**< pointer to store pseudo cost quotient */
92  SCIP_Bool* roundup /**< pointer to store whether the variable should be rounded up */
93  )
94 {
95  SCIP_Real pscostdown;
96  SCIP_Real pscostup;
97 
98  assert(pscostquot != NULL);
99  assert(roundup != NULL);
100  assert(SCIPisEQ(scip, frac, primsol - SCIPfeasFloor(scip, primsol)));
101 
102  /* bound fractions to not prefer variables that are nearly integral */
103  frac = MAX(frac, 0.1);
104  frac = MIN(frac, 0.9);
105 
106  /* get pseudo cost quotient */
107  pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0-frac);
108  pscostup = SCIPgetVarPseudocostVal(scip, var, 1.0-frac);
109  assert(pscostdown >= 0.0 && pscostup >= 0.0);
110 
111  /* choose rounding direction */
112  if( rounddir == -1 )
113  *roundup = FALSE;
114  else if( rounddir == +1 )
115  *roundup = TRUE;
116  else if( primsol < SCIPvarGetRootSol(var) - 0.4 )
117  *roundup = FALSE;
118  else if( primsol > SCIPvarGetRootSol(var) + 0.4 )
119  *roundup = TRUE;
120  else if( frac < 0.3 )
121  *roundup = FALSE;
122  else if( frac > 0.7 )
123  *roundup = TRUE;
124  else if( pscostdown < pscostup )
125  *roundup = FALSE;
126  else
127  *roundup = TRUE;
128 
129  /* calculate pseudo cost quotient */
130  if( *roundup )
131  *pscostquot = sqrt(frac) * (1.0+pscostdown) / (1.0+pscostup);
132  else
133  *pscostquot = sqrt(1.0-frac) * (1.0+pscostup) / (1.0+pscostdown);
134 
135  /* prefer decisions on binary variables */
136  if( SCIPvarIsBinary(var) )
137  (*pscostquot) *= 1000.0;
138 }
139 
140 
141 /*
142  * Callback methods
143  */
144 
145 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
146 static
147 SCIP_DECL_HEURCOPY(heurCopyPscostdiving)
148 { /*lint --e{715}*/
149  assert(scip != NULL);
150  assert(heur != NULL);
151  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
152 
153  /* call inclusion method of primal heuristic */
155 
156  return SCIP_OKAY;
157 }
158 
159 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
160 static
161 SCIP_DECL_HEURFREE(heurFreePscostdiving) /*lint --e{715}*/
162 { /*lint --e{715}*/
163  SCIP_HEURDATA* heurdata;
164 
165  assert(heur != NULL);
166  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
167  assert(scip != NULL);
168 
169  /* free heuristic data */
170  heurdata = SCIPheurGetData(heur);
171  assert(heurdata != NULL);
172  SCIPfreeMemory(scip, &heurdata);
173  SCIPheurSetData(heur, NULL);
174 
175  return SCIP_OKAY;
176 }
177 
178 
179 /** initialization method of primal heuristic (called after problem was transformed) */
180 static
181 SCIP_DECL_HEURINIT(heurInitPscostdiving) /*lint --e{715}*/
182 { /*lint --e{715}*/
183  SCIP_HEURDATA* heurdata;
184 
185  assert(heur != NULL);
186  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
187 
188  /* get heuristic data */
189  heurdata = SCIPheurGetData(heur);
190  assert(heurdata != NULL);
191 
192  /* create working solution */
193  SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
194 
195  /* initialize data */
196  heurdata->nlpiterations = 0;
197  heurdata->nsuccess = 0;
198 
199  return SCIP_OKAY;
200 }
201 
202 
203 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
204 static
205 SCIP_DECL_HEUREXIT(heurExitPscostdiving) /*lint --e{715}*/
206 { /*lint --e{715}*/
207  SCIP_HEURDATA* heurdata;
208 
209  assert(heur != NULL);
210  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
211 
212  /* get heuristic data */
213  heurdata = SCIPheurGetData(heur);
214  assert(heurdata != NULL);
215 
216  /* free working solution */
217  SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
218 
219  return SCIP_OKAY;
220 }
221 
222 
223 /** execution method of primal heuristic */
224 static
225 SCIP_DECL_HEUREXEC(heurExecPscostdiving) /*lint --e{715}*/
226 { /*lint --e{715}*/
227  SCIP_HEURDATA* heurdata;
228  SCIP_LPSOLSTAT lpsolstat;
229  SCIP_VAR* var;
230  SCIP_VAR** lpcands;
231  SCIP_Real* lpcandssol;
232  SCIP_Real* lpcandsfrac;
233  SCIP_Real searchubbound;
234  SCIP_Real searchavgbound;
235  SCIP_Real searchbound;
236  SCIP_Real objval;
237  SCIP_Real oldobjval;
238  SCIP_Real primsol;
239  SCIP_Real frac;
240  SCIP_Real pscostquot;
241  SCIP_Real bestpscostquot;
242  SCIP_Bool bestcandmayrounddown;
243  SCIP_Bool bestcandmayroundup;
244  SCIP_Bool bestcandroundup;
245  SCIP_Bool mayrounddown;
246  SCIP_Bool mayroundup;
247  SCIP_Bool roundup;
248  SCIP_Bool lperror;
249  SCIP_Bool cutoff;
250  SCIP_Bool backtracked;
251  SCIP_Bool backtrack;
252  SCIP_Longint ncalls;
253  SCIP_Longint nsolsfound;
254  SCIP_Longint nlpiterations;
255  SCIP_Longint maxnlpiterations;
256  int nlpcands;
257  int startnlpcands;
258  int depth;
259  int maxdepth;
260  int maxdivedepth;
261  int divedepth;
262  int bestcand;
263  int c;
264 
265  assert(heur != NULL);
266  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
267  assert(scip != NULL);
268  assert(result != NULL);
269  assert(SCIPhasCurrentNodeLP(scip));
270 
271  *result = SCIP_DELAYED;
272 
273  /* do not call heuristic of node was already detected to be infeasible */
274  if( nodeinfeasible )
275  return SCIP_OKAY;
276 
277  /* only call heuristic, if an optimal LP solution is at hand */
279  return SCIP_OKAY;
280 
281  /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
282  if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
283  return SCIP_OKAY;
284 
285  /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
286  if( !SCIPisLPSolBasic(scip) )
287  return SCIP_OKAY;
288 
289  /* don't dive two times at the same node */
290  if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
291  return SCIP_OKAY;
292 
293  *result = SCIP_DIDNOTRUN;
294 
295  /* get heuristic's data */
296  heurdata = SCIPheurGetData(heur);
297  assert(heurdata != NULL);
298 
299  /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
300  depth = SCIPgetDepth(scip);
301  maxdepth = SCIPgetMaxDepth(scip);
302  maxdepth = MAX(maxdepth, 30);
303  if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
304  return SCIP_OKAY;
305 
306  /* calculate the maximal number of LP iterations until heuristic is aborted */
307  nlpiterations = SCIPgetNNodeLPIterations(scip);
308  ncalls = SCIPheurGetNCalls(heur);
309  nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
310  maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
311  maxnlpiterations += heurdata->maxlpiterofs;
312 
313  /* don't try to dive, if we took too many LP iterations during diving */
314  if( heurdata->nlpiterations >= maxnlpiterations )
315  return SCIP_OKAY;
316 
317  /* allow at least a certain number of LP iterations in this dive */
318  maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);
319 
320  /* get fractional variables that should be integral */
321  SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
322 
323  /* don't try to dive, if there are no fractional variables */
324  if( nlpcands == 0 )
325  return SCIP_OKAY;
326 
327  /* calculate the objective search bound */
328  if( SCIPgetNSolsFound(scip) == 0 )
329  {
330  if( heurdata->maxdiveubquotnosol > 0.0 )
331  searchubbound = SCIPgetLowerbound(scip)
332  + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
333  else
334  searchubbound = SCIPinfinity(scip);
335  if( heurdata->maxdiveavgquotnosol > 0.0 )
336  searchavgbound = SCIPgetLowerbound(scip)
337  + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
338  else
339  searchavgbound = SCIPinfinity(scip);
340  }
341  else
342  {
343  if( heurdata->maxdiveubquot > 0.0 )
344  searchubbound = SCIPgetLowerbound(scip)
345  + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
346  else
347  searchubbound = SCIPinfinity(scip);
348  if( heurdata->maxdiveavgquot > 0.0 )
349  searchavgbound = SCIPgetLowerbound(scip)
350  + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
351  else
352  searchavgbound = SCIPinfinity(scip);
353  }
354  searchbound = MIN(searchubbound, searchavgbound);
355  if( SCIPisObjIntegral(scip) )
356  searchbound = SCIPceil(scip, searchbound);
357 
358  /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
359  maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
360  maxdivedepth = MIN(maxdivedepth, maxdepth);
361  maxdivedepth *= 10;
362 
363 
364  *result = SCIP_DIDNOTFIND;
365 
366  /* start diving */
367  SCIP_CALL( SCIPstartProbing(scip) );
368 
369  /* enables collection of variable statistics during probing */
370  SCIPenableVarHistory(scip);
371 
372  /* get LP objective value */
373  lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
374  objval = SCIPgetLPObjval(scip);
375 
376  SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing pscostdiving heuristic: depth=%d, %d fractionals, dualbound=%g, searchbound=%g\n",
377  SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), SCIPretransformObj(scip, searchbound));
378 
379  /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but
380  * - if possible, we dive at least with the depth 10
381  * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
382  */
383  lperror = FALSE;
384  cutoff = FALSE;
385  divedepth = 0;
386  bestcandmayrounddown = FALSE;
387  bestcandmayroundup = FALSE;
388  startnlpcands = nlpcands;
389  while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0
390  && (divedepth < 10
391  || nlpcands <= startnlpcands - divedepth/2
392  || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound))
393  && !SCIPisStopped(scip) )
394  {
395  SCIP_CALL( SCIPnewProbingNode(scip) );
396  divedepth++;
397 
398  /* choose variable fixing:
399  * - prefer variables that may not be rounded without destroying LP feasibility:
400  * - of these variables, round variable with largest rel. difference of pseudo cost values in corresponding
401  * direction
402  * - if all remaining fractional variables may be rounded without destroying LP feasibility:
403  * - round variable in the objective value direction
404  */
405  bestcand = -1;
406  bestpscostquot = -1.0;
407  bestcandmayrounddown = TRUE;
408  bestcandmayroundup = TRUE;
409  bestcandroundup = FALSE;
410  for( c = 0; c < nlpcands; ++c )
411  {
412  var = lpcands[c];
413  mayrounddown = SCIPvarMayRoundDown(var);
414  mayroundup = SCIPvarMayRoundUp(var);
415  primsol = lpcandssol[c];
416  frac = lpcandsfrac[c];
417  if( mayrounddown || mayroundup )
418  {
419  /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
420  if( bestcandmayrounddown || bestcandmayroundup )
421  {
422  /* choose rounding direction:
423  * - if variable may be rounded in both directions, round corresponding to the pseudo cost values
424  * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
425  * the current fractional solution
426  */
427  roundup = FALSE;
428  if( mayrounddown && mayroundup )
429  calcPscostQuot(scip, var, primsol, frac, 0, &pscostquot, &roundup);
430  else if( mayrounddown )
431  calcPscostQuot(scip, var, primsol, frac, +1, &pscostquot, &roundup);
432  else
433  calcPscostQuot(scip, var, primsol, frac, -1, &pscostquot, &roundup);
434 
435  /* check, if candidate is new best candidate */
436  if( pscostquot > bestpscostquot )
437  {
438  bestcand = c;
439  bestpscostquot = pscostquot;
440  bestcandmayrounddown = mayrounddown;
441  bestcandmayroundup = mayroundup;
442  bestcandroundup = roundup;
443  }
444  }
445  }
446  else
447  {
448  /* the candidate may not be rounded: calculate pseudo cost quotient and preferred direction */
449  calcPscostQuot(scip, var, primsol, frac, 0, &pscostquot, &roundup);
450 
451  /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
452  if( bestcandmayrounddown || bestcandmayroundup || pscostquot > bestpscostquot )
453  {
454  bestcand = c;
455  bestpscostquot = pscostquot;
456  bestcandmayrounddown = FALSE;
457  bestcandmayroundup = FALSE;
458  bestcandroundup = roundup;
459  }
460  }
461  }
462  assert(bestcand != -1);
463 
464  /* if all candidates are roundable, try to round the solution */
465  if( bestcandmayrounddown || bestcandmayroundup )
466  {
467  SCIP_Bool success;
468 
469  /* create solution from diving LP and try to round it */
470  SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
471  SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
472 
473  if( success )
474  {
475  SCIPdebugMessage("pscostdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
476 
477  /* try to add solution to SCIP */
478  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );
479 
480  /* check, if solution was feasible and good enough */
481  if( success )
482  {
483  SCIPdebugMessage(" -> solution was feasible and good enough\n");
484  *result = SCIP_FOUNDSOL;
485  }
486  }
487  }
488 
489  var = lpcands[bestcand];
490 
491  backtracked = FALSE;
492  do
493  {
494  backtrack = FALSE;
495  /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
496  * occured or variable was fixed by propagation while backtracking => Abort diving!
497  */
498  if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
499  {
500  SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
501  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]);
502  cutoff = TRUE;
503  break;
504  }
505  if( SCIPisFeasLT(scip, lpcandssol[bestcand], SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, lpcandssol[bestcand], SCIPvarGetUbLocal(var)) )
506  {
507  SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
508  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]);
509  assert(backtracked);
510  break;
511  }
512 
513  /* apply rounding of best candidate */
514  if( bestcandroundup == !backtracked )
515  {
516  /* round variable up */
517  SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
518  divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
519  SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
520  lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
521  SCIPfeasCeil(scip, lpcandssol[bestcand]), SCIPvarGetUbLocal(var));
522 
523  SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) );
524  roundup = TRUE;
525  }
526  else
527  {
528  /* round variable down */
529  SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
530  divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
531  SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
532  lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
533  SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, lpcandssol[bestcand]));
534 
535  SCIP_CALL( SCIPchgVarUbProbing(scip, lpcands[bestcand], SCIPfeasFloor(scip, lpcandssol[bestcand])) );
536  roundup = FALSE;
537  }
538 
539  /* apply domain propagation */
540  SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
541  if( !cutoff )
542  {
543  /* resolve the diving LP */
544  /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
545  * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
546  */
547 #ifdef NDEBUG
548  SCIP_RETCODE retstat;
549  nlpiterations = SCIPgetNLPIterations(scip);
550  retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff);
551  if( retstat != SCIP_OKAY )
552  {
553  SCIPwarningMessage(scip, "Error while solving LP in Pscostdiving heuristic; LP solve terminated with code <%d>\n",retstat);
554  }
555 #else
556  nlpiterations = SCIPgetNLPIterations(scip);
557  SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) );
558 #endif
559 
560  if( lperror )
561  break;
562 
563  /* update iteration count */
564  heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations;
565 
566  /* get LP solution status, objective value, and fractional variables, that should be integral */
567  lpsolstat = SCIPgetLPSolstat(scip);
568  assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE &&
569  (lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || SCIPisLT(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)))));
570  }
571 
572  /* perform backtracking if a cutoff was detected */
573  if( cutoff && !backtracked && heurdata->backtrack )
574  {
575  SCIPdebugMessage(" *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
577  SCIP_CALL( SCIPnewProbingNode(scip) );
578  backtracked = TRUE;
579  backtrack = TRUE;
580  }
581  else
582  backtrack = FALSE;
583  }
584  while( backtrack );
585 
586  if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
587  {
588  /* get new objective value */
589  oldobjval = objval;
590  objval = SCIPgetLPObjval(scip);
591 
592  /* update pseudo cost values */
593  if( SCIPisGT(scip, objval, oldobjval) )
594  {
595  if( roundup )
596  {
597  assert(bestcandroundup || backtracked);
598  SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 1.0-lpcandsfrac[bestcand],
599  objval - oldobjval, 1.0) );
600  }
601  else
602  {
603  assert(!bestcandroundup || backtracked);
604  SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 0.0-lpcandsfrac[bestcand],
605  objval - oldobjval, 1.0) );
606  }
607  }
608 
609  /* get new fractional variables */
610  SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
611  }
612  SCIPdebugMessage(" -> lpsolstat=%d, objval=%g/%g, nfrac=%d, lpiterations=%"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT"\n",
613  lpsolstat, objval, searchbound, nlpcands, heurdata->nlpiterations, maxnlpiterations);
614  }
615 
616  /* check if a solution has been found */
617  if( nlpcands == 0 && !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
618  {
619  SCIP_Bool success;
620 
621  /* create solution from diving LP */
622  SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
623  SCIPdebugMessage("pscostdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
624 
625  /* try to add solution to SCIP */
626  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );
627 
628  /* check, if solution was feasible and good enough */
629  if( success )
630  {
631  SCIPdebugMessage(" -> solution was feasible and good enough\n");
632  *result = SCIP_FOUNDSOL;
633  }
634  }
635 
636  /* end diving */
637  SCIP_CALL( SCIPendProbing(scip) );
638 
639  if( *result == SCIP_FOUNDSOL )
640  heurdata->nsuccess++;
641 
642  SCIPdebugMessage("pscostdiving heuristic finished\n");
643 
644  return SCIP_OKAY;
645 }
646 
647 
648 /*
649  * heuristic specific interface methods
650  */
651 
652 /** creates the pscostdiving heuristic and includes it in SCIP */
654  SCIP* scip /**< SCIP data structure */
655  )
656 {
657  SCIP_HEURDATA* heurdata;
658  SCIP_HEUR* heur;
659 
660  /* create Pscostdiving primal heuristic data */
661  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
662 
663  /* include primal heuristic */
664  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
666  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecPscostdiving, heurdata) );
667 
668  assert(heur != NULL);
669 
670  /* set non-NULL pointers to callback methods */
671  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyPscostdiving) );
672  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreePscostdiving) );
673  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitPscostdiving) );
674  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitPscostdiving) );
675 
676  /* pscostdiving heuristic parameters */
678  "heuristics/pscostdiving/minreldepth",
679  "minimal relative depth to start diving",
680  &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
682  "heuristics/pscostdiving/maxreldepth",
683  "maximal relative depth to start diving",
684  &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
686  "heuristics/pscostdiving/maxlpiterquot",
687  "maximal fraction of diving LP iterations compared to node LP iterations",
688  &heurdata->maxlpiterquot, FALSE, DEFAULT_MAXLPITERQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
690  "heuristics/pscostdiving/maxlpiterofs",
691  "additional number of allowed LP iterations",
692  &heurdata->maxlpiterofs, FALSE, DEFAULT_MAXLPITEROFS, 0, INT_MAX, NULL, NULL) );
694  "heuristics/pscostdiving/maxdiveubquot",
695  "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
696  &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
698  "heuristics/pscostdiving/maxdiveavgquot",
699  "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
700  &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
702  "heuristics/pscostdiving/maxdiveubquotnosol",
703  "maximal UBQUOT when no solution was found yet (0.0: no limit)",
704  &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
706  "heuristics/pscostdiving/maxdiveavgquotnosol",
707  "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
708  &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
710  "heuristics/pscostdiving/backtrack",
711  "use one level of backtracking if infeasibility is encountered?",
712  &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
713 
714  return SCIP_OKAY;
715 }
716 
#define HEUR_PRIORITY
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38254
SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip.c:29936
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_Real SCIPgetAvgLowerbound(SCIP *scip)
Definition: scip.c:35019
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:15788
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
SCIP_RETCODE SCIPbacktrackProbing(SCIP *scip, int probingdepth)
Definition: scip.c:29573
#define HEUR_MAXDEPTH
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:15968
SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR *var)
Definition: var.c:3269
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1206
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38667
SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
Definition: scip.c:34147
void SCIPenableVarHistory(SCIP *scip)
Definition: scip.c:21124
#define NULL
Definition: lpi_spx.cpp:129
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:16426
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1111
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:38803
#define DEFAULT_MAXDIVEUBQUOTNOSOL
#define MINLPITER
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
SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
Definition: scip.c:29766
#define FALSE
Definition: def.h:52
int SCIPgetNBinVars(SCIP *scip)
Definition: scip.c:10116
#define TRUE
Definition: def.h:51
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPupdateVarPseudocost(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta, SCIP_Real objdelta, SCIP_Real weight)
Definition: scip.c:21163
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition: scip.c:21194
struct SCIP_HeurData SCIP_HEURDATA
Definition: type_heur.h:44
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
LP diving heuristic that chooses fixings w.r.t. the pseudo cost values.
enum SCIP_LPSolStat SCIP_LPSOLSTAT
Definition: type_lp.h:42
#define HEUR_USESSUBSCIP
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip.c:24179
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
Definition: scip.c:38815
SCIP_Real SCIPgetLowerbound(SCIP *scip)
Definition: scip.c:35061
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31855
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:3388
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:3414
SCIP_Real SCIPvarGetRootSol(SCIP_VAR *var)
Definition: var.c:12536
#define HEUR_FREQ
static SCIP_DECL_HEURFREE(heurFreePscostdiving)
#define HEUR_DESC
static void calcPscostQuot(SCIP *scip, SCIP_VAR *var, SCIP_Real primsol, SCIP_Real frac, int rounddir, SCIP_Real *pscostquot, SCIP_Bool *roundup)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38273
#define DEFAULT_MAXLPITEROFS
SCIP_Real SCIPgetDualbound(SCIP *scip)
Definition: scip.c:35040
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:19159
SCIP_Bool SCIPisObjIntegral(SCIP *scip)
Definition: scip.c:9683
int SCIPgetProbingDepth(SCIP *scip)
Definition: scip.c:29546
SCIPInterval sqrt(const SCIPInterval &x)
int SCIPgetMaxDepth(SCIP *scip)
Definition: scip.c:34883
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:30856
#define HEUR_DISPCHAR
#define HEUR_FREQOFS
static SCIP_DECL_HEUREXIT(heurExitPscostdiving)
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
#define HEUR_NAME
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38705
SCIP_Longint SCIPgetLastDivenode(SCIP *scip)
Definition: scip.c:29390
void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
Definition: heur.c:512
#define DEFAULT_BACKTRACK
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38311
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:16436
#define SCIP_Bool
Definition: def.h:49
SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
Definition: scip.c:31962
#define HEUR_TIMING
#define MAX(x, y)
Definition: tclique_def.h:75
#define DEFAULT_MAXDIVEAVGQUOT
#define DEFAULT_MAXRELDEPTH
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
Definition: scip.c:29476
SCIP_RETCODE SCIPendProbing(SCIP *scip)
Definition: scip.c:29607
#define DEFAULT_MAXDIVEUBQUOT
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:34833
SCIP_RETCODE SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31444
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
SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
Definition: scip.c:7046
#define SCIP_REAL_MAX
Definition: def.h:124
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
Definition: scip.c:38482
SCIP_Longint SCIPheurGetNBestSolsFound(SCIP_HEUR *heur)
Definition: heur.c:737
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:19176
#define DEFAULT_MAXDIVEAVGQUOTNOSOL
#define DEFAULT_MINRELDEPTH
SCIP_Longint SCIPgetNSolsFound(SCIP *scip)
Definition: scip.c:35410
int SCIPgetNIntVars(SCIP *scip)
Definition: scip.c:10161
SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip.c:29674
SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
Definition: scip.c:7030
#define SCIP_Real
Definition: def.h:123
SCIP_RETCODE SCIPnewProbingNode(SCIP *scip)
Definition: scip.c:29513
SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip.c:29640
#define MIN(x, y)
Definition: memory.c:59
SCIP_Bool SCIPvarMayRoundUp(SCIP_VAR *var)
Definition: var.c:3277
#define SCIP_Longint
Definition: def.h:107
static SCIP_DECL_HEURINIT(heurInitPscostdiving)
static SCIP_DECL_HEUREXEC(heurExecPscostdiving)
SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
Definition: heur.c:502
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip.c:24544
SCIP_RETCODE SCIPincludeHeurPscostdiving(SCIP *scip)
SCIP_Longint SCIPgetNNodeLPIterations(SCIP *scip)
Definition: scip.c:34442
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:3470
#define DEFAULT_MAXLPITERQUOT
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_HEURCOPY(heurCopyPscostdiving)
SCIP_Longint SCIPgetNNodes(SCIP *scip)
Definition: scip.c:34065
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:31403
SCIP_RETCODE SCIProundSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *success)
Definition: scip.c:32673