Scippy

SCIP

Solving Constraint Integer Programs

heur_intdiving.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_intdiving.c
17  * @brief LP diving heuristic that fixes variables with integral LP value
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_intdiving.h"
27 
28 
29 #define HEUR_NAME "intdiving"
30 #define HEUR_DESC "LP diving heuristic that fixes binary variables with large LP value to one"
31 #define HEUR_DISPCHAR 'n'
32 #define HEUR_PRIORITY -1003500
33 #define HEUR_FREQ -1
34 #define HEUR_FREQOFS 9
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 
84 /*
85  * Callback methods
86  */
87 
88 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
89 static
90 SCIP_DECL_HEURCOPY(heurCopyIntdiving)
91 { /*lint --e{715}*/
92  assert(scip != NULL);
93  assert(heur != NULL);
94  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
95 
96  /* call inclusion method of primal heuristic */
98 
99  return SCIP_OKAY;
100 }
101 
102 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
103 static
104 SCIP_DECL_HEURFREE(heurFreeIntdiving) /*lint --e{715}*/
105 { /*lint --e{715}*/
106  SCIP_HEURDATA* heurdata;
107 
108  assert(heur != NULL);
109  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
110  assert(scip != NULL);
111 
112  /* free heuristic data */
113  heurdata = SCIPheurGetData(heur);
114  assert(heurdata != NULL);
115  SCIPfreeMemory(scip, &heurdata);
116  SCIPheurSetData(heur, NULL);
117 
118  return SCIP_OKAY;
119 }
120 
121 
122 /** initialization method of primal heuristic (called after problem was transformed) */
123 static
124 SCIP_DECL_HEURINIT(heurInitIntdiving) /*lint --e{715}*/
125 { /*lint --e{715}*/
126  SCIP_HEURDATA* heurdata;
127 
128  assert(heur != NULL);
129  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
130 
131  /* get heuristic data */
132  heurdata = SCIPheurGetData(heur);
133  assert(heurdata != NULL);
134 
135  /* create working solution */
136  SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
137 
138  /* initialize data */
139  heurdata->nlpiterations = 0;
140  heurdata->nsuccess = 0;
141 
142  return SCIP_OKAY;
143 }
144 
145 
146 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
147 static
148 SCIP_DECL_HEUREXIT(heurExitIntdiving) /*lint --e{715}*/
149 { /*lint --e{715}*/
150  SCIP_HEURDATA* heurdata;
151 
152  assert(heur != NULL);
153  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
154 
155  /* get heuristic data */
156  heurdata = SCIPheurGetData(heur);
157  assert(heurdata != NULL);
158 
159  /* free working solution */
160  SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
161 
162  return SCIP_OKAY;
163 }
164 
165 
166 /** execution method of primal heuristic */
167 static
168 SCIP_DECL_HEUREXEC(heurExecIntdiving) /*lint --e{715}*/
169 { /*lint --e{715}*/
170  SCIP_HEURDATA* heurdata;
171  SCIP_LPSOLSTAT lpsolstat;
172  SCIP_VAR** pseudocands;
173  SCIP_VAR** fixcands;
174  SCIP_Real* fixcandscores;
175  SCIP_Real searchubbound;
176  SCIP_Real searchavgbound;
177  SCIP_Real searchbound;
178  SCIP_Real objval;
179  SCIP_Bool lperror;
180  SCIP_Bool cutoff;
181  SCIP_Bool backtracked;
182  SCIP_Longint ncalls;
183  SCIP_Longint nsolsfound;
184  SCIP_Longint nlpiterations;
185  SCIP_Longint maxnlpiterations;
186  int nfixcands;
187  int nbinfixcands;
188  int depth;
189  int maxdepth;
190  int maxdivedepth;
191  int divedepth;
192  int nextcand;
193  int c;
194 
195  assert(heur != NULL);
196  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
197  assert(scip != NULL);
198  assert(result != NULL);
199  assert(SCIPhasCurrentNodeLP(scip));
200 
201  *result = SCIP_DELAYED;
202 
203  /* do not call heuristic of node was already detected to be infeasible */
204  if( nodeinfeasible )
205  return SCIP_OKAY;
206 
207  /* only call heuristic, if an optimal LP solution is at hand */
209  return SCIP_OKAY;
210 
211  /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
212  if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
213  return SCIP_OKAY;
214 
215  /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
216  if( !SCIPisLPSolBasic(scip) )
217  return SCIP_OKAY;
218 
219  /* don't dive two times at the same node */
220  if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
221  return SCIP_OKAY;
222 
223  *result = SCIP_DIDNOTRUN;
224 
225  /* get heuristic's data */
226  heurdata = SCIPheurGetData(heur);
227  assert(heurdata != NULL);
228 
229  /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
230  depth = SCIPgetDepth(scip);
231  maxdepth = SCIPgetMaxDepth(scip);
232  maxdepth = MAX(maxdepth, 100);
233  if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
234  return SCIP_OKAY;
235 
236  /* calculate the maximal number of LP iterations until heuristic is aborted */
237  nlpiterations = SCIPgetNNodeLPIterations(scip);
238  ncalls = SCIPheurGetNCalls(heur);
239  nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
240  maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
241  maxnlpiterations += heurdata->maxlpiterofs;
242 
243  /* don't try to dive, if we took too many LP iterations during diving */
244  if( heurdata->nlpiterations >= maxnlpiterations )
245  return SCIP_OKAY;
246 
247  /* allow at least a certain number of LP iterations in this dive */
248  maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);
249 
250  /* get unfixed integer variables */
251  SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, &nfixcands, NULL) );
252 
253  /* don't try to dive, if there are no fractional variables */
254  if( nfixcands == 0 )
255  return SCIP_OKAY;
256 
257  /* calculate the objective search bound */
258  if( SCIPgetNSolsFound(scip) == 0 )
259  {
260  if( heurdata->maxdiveubquotnosol > 0.0 )
261  searchubbound = SCIPgetLowerbound(scip)
262  + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
263  else
264  searchubbound = SCIPinfinity(scip);
265  if( heurdata->maxdiveavgquotnosol > 0.0 )
266  searchavgbound = SCIPgetLowerbound(scip)
267  + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
268  else
269  searchavgbound = SCIPinfinity(scip);
270  }
271  else
272  {
273  if( heurdata->maxdiveubquot > 0.0 )
274  searchubbound = SCIPgetLowerbound(scip)
275  + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
276  else
277  searchubbound = SCIPinfinity(scip);
278  if( heurdata->maxdiveavgquot > 0.0 )
279  searchavgbound = SCIPgetLowerbound(scip)
280  + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
281  else
282  searchavgbound = SCIPinfinity(scip);
283  }
284  searchbound = MIN(searchubbound, searchavgbound);
285  if( SCIPisObjIntegral(scip) )
286  searchbound = SCIPceil(scip, searchbound);
287 
288  /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
289  maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
290  maxdivedepth = MIN(maxdivedepth, maxdepth);
291  maxdivedepth *= 10;
292 
293  *result = SCIP_DIDNOTFIND;
294 
295  /* start diving */
296  SCIP_CALL( SCIPstartProbing(scip) );
297 
298  /* enables collection of variable statistics during probing */
299  SCIPenableVarHistory(scip);
300 
301  SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing intdiving heuristic: depth=%d, %d non-fixed, dualbound=%g, searchbound=%g\n",
302  SCIPgetNNodes(scip), SCIPgetDepth(scip), nfixcands, SCIPgetDualbound(scip), SCIPretransformObj(scip, searchbound));
303 
304  /* copy the pseudo candidates into own array, because we want to reorder them */
305  SCIP_CALL( SCIPduplicateBufferArray(scip, &fixcands, pseudocands, nfixcands) );
306 
307  /* sort non-fixed variables by non-increasing inference score, but prefer binaries over integers in any case */
308  SCIP_CALL( SCIPallocBufferArray(scip, &fixcandscores, nfixcands) );
309  nbinfixcands = 0;
310  for( c = 0; c < nfixcands; ++c )
311  {
312  SCIP_VAR* var;
313  SCIP_Real score;
314  int colveclen;
315  int left;
316  int right;
317  int i;
318 
319  assert(c >= nbinfixcands);
320  var = fixcands[c];
321  assert(SCIPvarIsIntegral(var));
322  colveclen = (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ? SCIPcolGetNNonz(SCIPvarGetCol(var)) : 0);
323  if( SCIPvarIsBinary(var) )
324  {
325  score = 500.0 * SCIPvarGetNCliques(var, TRUE) + 100.0 * SCIPvarGetNImpls(var, TRUE)
326  + SCIPgetVarAvgInferenceScore(scip, var) + (SCIP_Real)colveclen/100.0;
327 
328  /* shift the non-binary variables one slot to the right */
329  for( i = c; i > nbinfixcands; --i )
330  {
331  fixcands[i] = fixcands[i-1];
332  fixcandscores[i] = fixcandscores[i-1];
333  }
334  /* put the new candidate into the first nbinfixcands slot */
335  left = 0;
336  right = nbinfixcands;
337  nbinfixcands++;
338  }
339  else
340  {
341  score = 5.0 * (SCIPvarGetNCliques(var, FALSE) + SCIPvarGetNCliques(var, TRUE))
343  + (SCIP_Real)colveclen/10000.0;
344 
345  /* put the new candidate in the slots after the binary candidates */
346  left = nbinfixcands;
347  right = c;
348  }
349  for( i = right; i > left && score > fixcandscores[i-1]; --i )
350  {
351  fixcands[i] = fixcands[i-1];
352  fixcandscores[i] = fixcandscores[i-1];
353  }
354  fixcands[i] = var;
355  fixcandscores[i] = score;
356  SCIPdebugMessage(" <%s>: ncliques=%d/%d, nimpls=%d/%d, inferencescore=%g, colveclen=%d -> score=%g\n",
359  colveclen, score);
360  }
361  SCIPfreeBufferArray(scip, &fixcandscores);
362 
363  /* get LP objective value */
364  lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
365  objval = SCIPgetLPObjval(scip);
366 
367  /* dive as long we are in the given objective, depth and iteration limits, but if possible, we dive at least with
368  * the depth 10
369  */
370  lperror = FALSE;
371  cutoff = FALSE;
372  divedepth = 0;
373  nextcand = 0;
374  while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL
375  && (divedepth < 10
376  || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound))
377  && !SCIPisStopped(scip) )
378  {
379  SCIP_VAR* var;
380  SCIP_Real bestsolval;
381  SCIP_Real bestfixval;
382  int bestcand;
383  SCIP_Longint nnewlpiterations;
384  SCIP_Longint nnewdomreds;
385 
386  SCIP_CALL( SCIPnewProbingNode(scip) );
387  divedepth++;
388  nnewlpiterations = 0;
389  nnewdomreds = 0;
390 
391  /* fix binary variable that is closest to 1 in the LP solution to 1;
392  * if all binary variables are fixed, fix integer variable with least fractionality in LP solution
393  */
394  bestcand = -1;
395  bestsolval = -1.0;
396  bestfixval = 1.0;
397 
398  /* look in the binary variables for fixing candidates */
399  for( c = nextcand; c < nbinfixcands; ++c )
400  {
401  SCIP_Real solval;
402 
403  var = fixcands[c];
404 
405  /* ignore already fixed variables */
406  if( var == NULL )
407  continue;
408  if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 )
409  {
410  fixcands[c] = NULL;
411  continue;
412  }
413 
414  /* get the LP solution value */
415  solval = SCIPvarGetLPSol(var);
416 
417  if( solval > bestsolval )
418  {
419  bestcand = c;
420  bestfixval = 1.0;
421  bestsolval = solval;
422  if( SCIPisGE(scip, bestsolval, 1.0) )
423  {
424  /* we found an unfixed binary variable with LP solution value of 1.0 - there cannot be a better candidate */
425  break;
426  }
427  else if( SCIPisLE(scip, bestsolval, 0.0) )
428  {
429  /* the variable is currently at 0.0 - this is the only situation where we want to fix it to 0.0 */
430  bestfixval = 0.0;
431  }
432  }
433  }
434 
435  /* if all binary variables are fixed, look in the integer variables for a fixing candidate */
436  if( bestcand == -1 )
437  {
438  SCIP_Real bestfrac;
439 
440  bestfrac = SCIP_INVALID;
441  for( c = MAX(nextcand, nbinfixcands); c < nfixcands; ++c )
442  {
443  SCIP_Real solval;
444  SCIP_Real frac;
445 
446  var = fixcands[c];
447 
448  /* ignore already fixed variables */
449  if( var == NULL )
450  continue;
451  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
452  {
453  fixcands[c] = NULL;
454  continue;
455  }
456 
457  /* get the LP solution value */
458  solval = SCIPvarGetLPSol(var);
459  frac = SCIPfrac(scip, solval);
460 
461  /* ignore integer variables that are currently integral */
462  if( SCIPisFeasFracIntegral(scip, frac) )
463  continue;
464 
465  if( frac < bestfrac )
466  {
467  bestcand = c;
468  bestsolval = solval;
469  bestfrac = frac;
470  bestfixval = SCIPfloor(scip, bestsolval + 0.5);
471  if( SCIPisZero(scip, bestfrac) )
472  {
473  /* we found an unfixed integer variable with integral LP solution value */
474  break;
475  }
476  }
477  }
478  }
479  assert(-1 <= bestcand && bestcand < nfixcands);
480 
481  /* if there is no unfixed candidate left, we are done */
482  if( bestcand == -1 )
483  break;
484 
485  var = fixcands[bestcand];
486  assert(var != NULL);
487  assert(SCIPvarIsIntegral(var));
488  assert(SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) > 0.5);
489  assert(SCIPisGE(scip, bestfixval, SCIPvarGetLbLocal(var)));
490  assert(SCIPisLE(scip, bestfixval, SCIPvarGetUbLocal(var)));
491 
492  backtracked = FALSE;
493  do
494  {
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], diving aborted \n",
502  cutoff = TRUE;
503  break;
504  }
505  if( SCIPisFeasLT(scip, bestfixval, SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, bestfixval, 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), bestfixval);
509  assert(backtracked);
510  break;
511  }
512 
513  /* apply fixing of best candidate */
514  SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT", %d unfixed: var <%s>, sol=%g, oldbounds=[%g,%g], fixed to %g\n",
515  divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPgetNPseudoBranchCands(scip),
516  SCIPvarGetName(var), bestsolval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestfixval);
517  SCIP_CALL( SCIPfixVarProbing(scip, var, bestfixval) );
518 
519  /* apply domain propagation */
520  SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, &nnewdomreds) );
521  if( !cutoff )
522  {
523  /* if the best candidate was just fixed to its LP value and no domain reduction was found, the LP solution
524  * stays valid, and the LP does not need to be resolved
525  */
526  if( nnewdomreds > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) )
527  {
528  /* resolve the diving LP */
529  /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
530  * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
531  */
532 #ifdef NDEBUG
533  SCIP_RETCODE retstat;
534  nlpiterations = SCIPgetNLPIterations(scip);
535  retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff);
536  if( retstat != SCIP_OKAY )
537  {
538  SCIPwarningMessage(scip, "Error while solving LP in Intdiving heuristic; LP solve terminated with code <%d>\n",retstat);
539  }
540 #else
541  nlpiterations = SCIPgetNLPIterations(scip);
542  SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) );
543 #endif
544 
545  if( lperror )
546  break;
547 
548  /* update iteration count */
549  nnewlpiterations = SCIPgetNLPIterations(scip) - nlpiterations;
550  heurdata->nlpiterations += nnewlpiterations;
551 
552  /* get LP solution status */
553  lpsolstat = SCIPgetLPSolstat(scip);
554  assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE &&
555  (lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || SCIPisLT(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)))));
556  }
557  }
558 
559  /* perform backtracking if a cutoff was detected */
560  if( cutoff && !backtracked && heurdata->backtrack )
561  {
562  SCIPdebugMessage(" *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
564  SCIP_CALL( SCIPnewProbingNode(scip) );
565 
566  bestfixval = SCIPvarIsBinary(var)
567  ? 1.0 - bestfixval
568  : (SCIPisGT(scip, bestsolval, bestfixval) && SCIPisFeasLE(scip, bestfixval + 1, SCIPvarGetUbLocal(var)) ? bestfixval + 1 : bestfixval - 1);
569 
570  backtracked = TRUE;
571  }
572  else
573  backtracked = FALSE;
574  }
575  while( backtracked );
576 
577  if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
578  {
579  SCIP_Bool success;
580 
581  /* get new objective value */
582  objval = SCIPgetLPObjval(scip);
583 
584  if( nnewlpiterations > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) )
585  {
586  /* we must start again with the first candidate, since the LP solution changed */
587  nextcand = 0;
588 
589  /* create solution from diving LP and try to round it */
590  SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
591  SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
592  if( success )
593  {
594  SCIPdebugMessage("intdiving found roundable primal solution: obj=%g\n",
595  SCIPgetSolOrigObj(scip, heurdata->sol));
596 
597  /* try to add solution to SCIP */
598  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );
599 
600  /* check, if solution was feasible and good enough */
601  if( success )
602  {
603  SCIPdebugMessage(" -> solution was feasible and good enough\n");
604  *result = SCIP_FOUNDSOL;
605  }
606  }
607  }
608  else
609  nextcand = bestcand+1; /* continue with the next candidate in the following loop */
610  }
611  SCIPdebugMessage(" -> lpsolstat=%d, objval=%g/%g\n", lpsolstat, objval, searchbound);
612  }
613 
614  /* free temporary memory */
615  SCIPfreeBufferArray(scip, &fixcands);
616 
617  /* end diving */
618  SCIP_CALL( SCIPendProbing(scip) );
619 
620  if( *result == SCIP_FOUNDSOL )
621  heurdata->nsuccess++;
622 
623  SCIPdebugMessage("intdiving heuristic finished\n");
624 
625  return SCIP_OKAY;
626 }
627 
628 
629 /*
630  * heuristic specific interface methods
631  */
632 
633 /** creates the intdiving heuristic and includes it in SCIP */
635  SCIP* scip /**< SCIP data structure */
636  )
637 {
638  SCIP_HEURDATA* heurdata;
639  SCIP_HEUR* heur;
640 
641  /* create Intdiving primal heuristic data */
642  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
643 
644  /* include primal heuristic */
645  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
647  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecIntdiving, heurdata) );
648 
649  assert(heur != NULL);
650 
651  /* set non-NULL pointers to callback methods */
652  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyIntdiving) );
653  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeIntdiving) );
654  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitIntdiving) );
655  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitIntdiving) );
656 
657  /* intdiving heuristic parameters */
659  "heuristics/intdiving/minreldepth",
660  "minimal relative depth to start diving",
661  &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
663  "heuristics/intdiving/maxreldepth",
664  "maximal relative depth to start diving",
665  &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
667  "heuristics/intdiving/maxlpiterquot",
668  "maximal fraction of diving LP iterations compared to node LP iterations",
669  &heurdata->maxlpiterquot, FALSE, DEFAULT_MAXLPITERQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
671  "heuristics/intdiving/maxlpiterofs",
672  "additional number of allowed LP iterations",
673  &heurdata->maxlpiterofs, FALSE, DEFAULT_MAXLPITEROFS, 0, INT_MAX, NULL, NULL) );
675  "heuristics/intdiving/maxdiveubquot",
676  "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
677  &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
679  "heuristics/intdiving/maxdiveavgquot",
680  "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
681  &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
683  "heuristics/intdiving/maxdiveubquotnosol",
684  "maximal UBQUOT when no solution was found yet (0.0: no limit)",
685  &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
687  "heuristics/intdiving/maxdiveavgquotnosol",
688  "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
689  &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
691  "heuristics/intdiving/backtrack",
692  "use one level of backtracking if infeasibility is encountered?",
693  &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
694 
695  return SCIP_OKAY;
696 }
697 
698