Scippy

SCIP

Solving Constraint Integer Programs

heur_veclendiving.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_veclendiving.c
17  * @brief LP diving heuristic that rounds variables with long column vectors
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_veclendiving.h"
27 
28 
29 #define HEUR_NAME "veclendiving"
30 #define HEUR_DESC "LP diving heuristic that rounds variables with long column vectors"
31 #define HEUR_DISPCHAR 'v'
32 #define HEUR_PRIORITY -1003100
33 #define HEUR_FREQ 10
34 #define HEUR_FREQOFS 4
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(heurCopyVeclendiving)
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(heurFreeVeclendiving) /*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(heurInitVeclendiving) /*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(heurExitVeclendiving) /*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(heurExecVeclendiving) /*lint --e{715}*/
169 { /*lint --e{715}*/
170  SCIP_HEURDATA* heurdata;
171  SCIP_LPSOLSTAT lpsolstat;
172  SCIP_VAR** lpcands;
173  SCIP_Real* lpcandssol;
174  SCIP_Real* lpcandsfrac;
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 nlpcands;
187  int startnlpcands;
188  int depth;
189  int maxdepth;
190  int maxdivedepth;
191  int divedepth;
192 
193  assert(heur != NULL);
194  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
195  assert(scip != NULL);
196  assert(result != NULL);
197  assert(SCIPhasCurrentNodeLP(scip));
198 
199  *result = SCIP_DELAYED;
200 
201  /* do not call heuristic of node was already detected to be infeasible */
202  if( nodeinfeasible )
203  return SCIP_OKAY;
204 
205  /* only call heuristic, if an optimal LP solution is at hand */
207  return SCIP_OKAY;
208 
209  /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
210  if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
211  return SCIP_OKAY;
212 
213  /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
214  if( !SCIPisLPSolBasic(scip) )
215  return SCIP_OKAY;
216 
217  /* don't dive two times at the same node */
218  if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
219  return SCIP_OKAY;
220 
221  *result = SCIP_DIDNOTRUN;
222 
223  /* get heuristic's data */
224  heurdata = SCIPheurGetData(heur);
225  assert(heurdata != NULL);
226 
227  /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
228  depth = SCIPgetDepth(scip);
229  maxdepth = SCIPgetMaxDepth(scip);
230  maxdepth = MAX(maxdepth, 30);
231  if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
232  return SCIP_OKAY;
233 
234  /* calculate the maximal number of LP iterations until heuristic is aborted */
235  nlpiterations = SCIPgetNNodeLPIterations(scip);
236  ncalls = SCIPheurGetNCalls(heur);
237  nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
238  maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
239  maxnlpiterations += heurdata->maxlpiterofs;
240 
241  /* don't try to dive, if we took too many LP iterations during diving */
242  if( heurdata->nlpiterations >= maxnlpiterations )
243  return SCIP_OKAY;
244 
245  /* allow at least a certain number of LP iterations in this dive */
246  maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);
247 
248  /* get fractional variables that should be integral */
249  SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
250 
251  /* don't try to dive, if there are no fractional variables */
252  if( nlpcands == 0 )
253  return SCIP_OKAY;
254 
255  /* calculate the objective search bound */
256  if( SCIPgetNSolsFound(scip) == 0 )
257  {
258  if( heurdata->maxdiveubquotnosol > 0.0 )
259  searchubbound = SCIPgetLowerbound(scip)
260  + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
261  else
262  searchubbound = SCIPinfinity(scip);
263  if( heurdata->maxdiveavgquotnosol > 0.0 )
264  searchavgbound = SCIPgetLowerbound(scip)
265  + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
266  else
267  searchavgbound = SCIPinfinity(scip);
268  }
269  else
270  {
271  if( heurdata->maxdiveubquot > 0.0 )
272  searchubbound = SCIPgetLowerbound(scip)
273  + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
274  else
275  searchubbound = SCIPinfinity(scip);
276  if( heurdata->maxdiveavgquot > 0.0 )
277  searchavgbound = SCIPgetLowerbound(scip)
278  + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
279  else
280  searchavgbound = SCIPinfinity(scip);
281  }
282  searchbound = MIN(searchubbound, searchavgbound);
283  if( SCIPisObjIntegral(scip) )
284  searchbound = SCIPceil(scip, searchbound);
285 
286  /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
287  maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
288  maxdivedepth = MIN(maxdivedepth, maxdepth);
289  maxdivedepth *= 10;
290 
291 
292  *result = SCIP_DIDNOTFIND;
293 
294  /* start diving */
295  SCIP_CALL( SCIPstartProbing(scip) );
296 
297  /* enables collection of variable statistics during probing */
298  SCIPenableVarHistory(scip);
299 
300  /* get LP objective value */
301  lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
302  objval = SCIPgetLPObjval(scip);
303 
304  SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing veclendiving heuristic: depth=%d, %d fractionals, dualbound=%g, searchbound=%g\n",
305  SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), SCIPretransformObj(scip, searchbound));
306 
307  /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but
308  * - if possible, we dive at least with the depth 10
309  * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
310  */
311  lperror = FALSE;
312  cutoff = FALSE;
313  divedepth = 0;
314  startnlpcands = nlpcands;
315  while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0
316  && (divedepth < 10
317  || nlpcands <= startnlpcands - divedepth/2
318  || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound))
319  && !SCIPisStopped(scip) )
320  {
321  SCIP_VAR* var;
322  SCIP_Real bestscore;
323  SCIP_Bool bestcandroundup;
324  SCIP_Bool allroundable;
325  int bestcand;
326  int c;
327 
328  SCIP_CALL( SCIPnewProbingNode(scip) );
329  divedepth++;
330 
331  /* choose variable fixing:
332  * - round variables in direction where objective value gets worse; for zero objective coefficient, round upwards
333  * - round variable with least objective value deficit per row the variable appears in
334  * (we want to "fix" as many rows as possible with the least damage to the objective function)
335  */
336  bestcand = -1;
337  bestcandroundup = FALSE;
338  bestscore = SCIP_REAL_MAX;
339  allroundable = TRUE;
340  for( c = 0; c < nlpcands; ++c )
341  {
342  SCIP_Real obj;
343  SCIP_Real frac;
344  SCIP_Real objdelta;
345  SCIP_Real score;
346  SCIP_Bool roundup;
347  int colveclen;
348 
349  var = lpcands[c];
350  frac = lpcandsfrac[c];
351  obj = SCIPvarGetObj(var);
352  roundup = (obj >= 0.0);
353  objdelta = (roundup ? (1.0-frac)*obj : -frac * obj);
354  assert(objdelta >= 0.0);
355 
356  colveclen = (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ? SCIPcolGetNNonz(SCIPvarGetCol(var)) : 0);
357 
358  /* check whether the variable is roundable */
359  allroundable = allroundable && (SCIPvarMayRoundDown(var) || SCIPvarMayRoundUp(var));
360 
361  /* smaller score is better */
362  score = (objdelta + SCIPsumepsilon(scip))/((SCIP_Real)colveclen+1.0);
363 
364  /* prefer decisions on binary variables */
365  if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY )
366  score *= 1000.0;
367 
368  /* check, if candidate is new best candidate */
369  if( score < bestscore )
370  {
371  bestcand = c;
372  bestscore = score;
373  bestcandroundup = roundup;
374  }
375 
376  /*SCIPdebugMessage(" <%s>: sol=%g, obj=%g, objdelta=%g, colveclen=%d -> score=%g (bestscore=%g)\n",
377  SCIPvarGetName(var), lpcandssol[c], obj, objdelta, colveclen, score, bestscore);*/
378  }
379  assert(bestcand != -1);
380 
381  /* if all candidates are roundable, try to round the solution */
382  if( allroundable )
383  {
384  SCIP_Bool success;
385 
386  /* create solution from diving LP and try to round it */
387  SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
388  SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
389 
390  if( success )
391  {
392  SCIPdebugMessage("veclendiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
393 
394  /* try to add solution to SCIP */
395  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );
396 
397  /* check, if solution was feasible and good enough */
398  if( success )
399  {
400  SCIPdebugMessage(" -> solution was feasible and good enough\n");
401  *result = SCIP_FOUNDSOL;
402  }
403  }
404  }
405 
406  var = lpcands[bestcand];
407 
408  backtracked = FALSE;
409  do
410  {
411  /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
412  * occured or variable was fixed by propagation while backtracking => Abort diving!
413  */
414  if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
415  {
416  SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
417  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]);
418  cutoff = TRUE;
419  break;
420  }
421  if( SCIPisFeasLT(scip, lpcandssol[bestcand], SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, lpcandssol[bestcand], SCIPvarGetUbLocal(var)) )
422  {
423  SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
424  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]);
425  assert(backtracked);
426  break;
427  }
428 
429  /* apply rounding of best candidate */
430  if( bestcandroundup == !backtracked )
431  {
432  /* round variable up */
433  SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
434  divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
435  SCIPvarGetName(var), lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
436  SCIPfeasCeil(scip, lpcandssol[bestcand]), SCIPvarGetUbLocal(var));
437  SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) );
438  }
439  else
440  {
441  /* round variable down */
442  SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
443  divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
444  SCIPvarGetName(var), lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
445  SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, lpcandssol[bestcand]));
446  SCIP_CALL( SCIPchgVarUbProbing(scip, var, SCIPfeasFloor(scip, lpcandssol[bestcand])) );
447  }
448 
449  /* apply domain propagation */
450  SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
451  if( !cutoff )
452  {
453  /* resolve the diving LP */
454  /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
455  * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
456  */
457 #ifdef NDEBUG
458  SCIP_RETCODE retstat;
459  nlpiterations = SCIPgetNLPIterations(scip);
460  retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff);
461  if( retstat != SCIP_OKAY )
462  {
463  SCIPwarningMessage(scip, "Error while solving LP in Veclendiving heuristic; LP solve terminated with code <%d>\n",retstat);
464  }
465 #else
466  nlpiterations = SCIPgetNLPIterations(scip);
467  SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) );
468 #endif
469 
470  if( lperror )
471  break;
472 
473  /* update iteration count */
474  heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations;
475 
476  /* get LP solution status, objective value, and fractional variables, that should be integral */
477  lpsolstat = SCIPgetLPSolstat(scip);
478  assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE &&
479  (lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || SCIPisLT(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)))));
480  }
481 
482  /* perform backtracking if a cutoff was detected */
483  if( cutoff && !backtracked && heurdata->backtrack )
484  {
485  SCIPdebugMessage(" *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
487  SCIP_CALL( SCIPnewProbingNode(scip) );
488  backtracked = TRUE;
489  }
490  else
491  backtracked = FALSE;
492  }
493  while( backtracked );
494 
495  if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
496  {
497  SCIP_Real oldobjval;
498 
499  /* get new objective value */
500  oldobjval = objval;
501  objval = SCIPgetLPObjval(scip);
502 
503  /* update pseudo cost values */
504  if( SCIPisGT(scip, objval, oldobjval) )
505  {
506  if( bestcandroundup )
507  {
508  SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 1.0-lpcandsfrac[bestcand],
509  objval - oldobjval, 1.0) );
510  }
511  else
512  {
513  SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 0.0-lpcandsfrac[bestcand],
514  objval - oldobjval, 1.0) );
515  }
516  }
517 
518  /* get new fractional variables */
519  SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
520  }
521  SCIPdebugMessage(" -> lpsolstat=%d, objval=%g/%g, nfrac=%d\n", lpsolstat, objval, searchbound, nlpcands);
522  }
523 
524  /* check if a solution has been found */
525  if( nlpcands == 0 && !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
526  {
527  SCIP_Bool success;
528 
529  /* create solution from diving LP */
530  SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
531  SCIPdebugMessage("veclendiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
532 
533  /* try to add solution to SCIP */
534  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );
535 
536  /* check, if solution was feasible and good enough */
537  if( success )
538  {
539  SCIPdebugMessage(" -> solution was feasible and good enough\n");
540  *result = SCIP_FOUNDSOL;
541  }
542  }
543 
544  /* end diving */
545  SCIP_CALL( SCIPendProbing(scip) );
546 
547  if( *result == SCIP_FOUNDSOL )
548  heurdata->nsuccess++;
549 
550  SCIPdebugMessage("veclendiving heuristic finished\n");
551 
552  return SCIP_OKAY;
553 }
554 
555 
556 /*
557  * heuristic specific interface methods
558  */
559 
560 /** creates the veclendiving heuristic and includes it in SCIP */
562  SCIP* scip /**< SCIP data structure */
563  )
564 {
565  SCIP_HEURDATA* heurdata;
566  SCIP_HEUR* heur;
567 
568  /* create Veclendiving primal heuristic data */
569  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
570 
571  /* include primal heuristic */
572  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
574  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecVeclendiving, heurdata) );
575 
576  assert(heur != NULL);
577 
578  /* set non-NULL pointers to callback methods */
579  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyVeclendiving) );
580  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeVeclendiving) );
581  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitVeclendiving) );
582  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitVeclendiving) );
583 
584  /* veclendiving heuristic parameters */
586  "heuristics/veclendiving/minreldepth",
587  "minimal relative depth to start diving",
588  &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
590  "heuristics/veclendiving/maxreldepth",
591  "maximal relative depth to start diving",
592  &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
594  "heuristics/veclendiving/maxlpiterquot",
595  "maximal fraction of diving LP iterations compared to node LP iterations",
596  &heurdata->maxlpiterquot, FALSE, DEFAULT_MAXLPITERQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
598  "heuristics/veclendiving/maxlpiterofs",
599  "additional number of allowed LP iterations",
600  &heurdata->maxlpiterofs, FALSE, DEFAULT_MAXLPITEROFS, 0, INT_MAX, NULL, NULL) );
602  "heuristics/veclendiving/maxdiveubquot",
603  "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
604  &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
606  "heuristics/veclendiving/maxdiveavgquot",
607  "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
608  &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
610  "heuristics/veclendiving/maxdiveubquotnosol",
611  "maximal UBQUOT when no solution was found yet (0.0: no limit)",
612  &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
614  "heuristics/veclendiving/maxdiveavgquotnosol",
615  "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
616  &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
618  "heuristics/veclendiving/backtrack",
619  "use one level of backtracking if infeasibility is encountered?",
620  &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
621 
622  return SCIP_OKAY;
623 }
624 
625