Scippy

SCIP

Solving Constraint Integer Programs

heur_actconsdiving.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_actconsdiving.c
17  * @brief LP diving heuristic that chooses fixings w.r.t. the active constraints the variable appear in
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 
27 
28 
29 #define HEUR_NAME "actconsdiving"
30 #define HEUR_DESC "LP diving heuristic that chooses fixings w.r.t. the active constraints"
31 #define HEUR_DISPCHAR 'a'
32 #define HEUR_PRIORITY -1003700
33 #define HEUR_FREQ -1
34 #define HEUR_FREQOFS 5
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 /** returns a score value for the given variable based on the active constraints that the variable appears in */
84 static
86  SCIP* scip, /**< SCIP data structure */
87  SCIP_VAR* var, /**< variable to get the score value for */
88  SCIP_Real* downscore, /**< pointer to store the score for branching downwards */
89  SCIP_Real* upscore /**< pointer to store the score for branching upwards */
90  )
91 {
92  SCIP_COL* col;
93  SCIP_ROW** rows;
94  SCIP_Real* vals;
95  int nrows;
96  int r;
97  int nactrows;
98  SCIP_Real downcoefsum;
99  SCIP_Real upcoefsum;
100  SCIP_Real score;
101 
102  assert(downscore != NULL);
103  assert(upscore != NULL);
104 
105  *downscore = 0.0;
106  *upscore = 0.0;
108  return 0.0;
109 
110  col = SCIPvarGetCol(var);
111  assert(col != NULL);
112 
113  rows = SCIPcolGetRows(col);
114  vals = SCIPcolGetVals(col);
115  nrows = SCIPcolGetNLPNonz(col);
116  nactrows = 0;
117  downcoefsum = 0.0;
118  upcoefsum = 0.0;
119  for( r = 0; r < nrows; ++r )
120  {
121  SCIP_Real activity;
122  SCIP_Real lhs;
123  SCIP_Real rhs;
124  SCIP_Real dualsol;
125 
126  /* calculate number of active constraint sides, i.e., count equations as two */
127  lhs = SCIProwGetLhs(rows[r]);
128  rhs = SCIProwGetRhs(rows[r]);
129  activity = SCIPgetRowLPActivity(scip, rows[r]);
130  dualsol = SCIProwGetDualsol(rows[r]);
131  if( SCIPisFeasEQ(scip, activity, lhs) )
132  {
133  SCIP_Real coef;
134 
135  nactrows++;
136  coef = vals[r] / SCIProwGetNorm(rows[r]);
137  if( SCIPisFeasPositive(scip, dualsol) )
138  {
139  if( coef > 0.0 )
140  downcoefsum += coef;
141  else
142  upcoefsum -= coef;
143  }
144  }
145  else if( SCIPisFeasEQ(scip, activity, rhs) )
146  {
147  SCIP_Real coef;
148 
149  nactrows++;
150  coef = vals[r] / SCIProwGetNorm(rows[r]);
151  if( SCIPisFeasNegative(scip, dualsol) )
152  {
153  if( coef > 0.0 )
154  upcoefsum += coef;
155  else
156  downcoefsum -= coef;
157  }
158  }
159  }
160  score = 1e-3*nactrows + (downcoefsum + 1e-6) * (upcoefsum + 1e-6);
161  *downscore = -downcoefsum;
162  *upscore = -upcoefsum;
163 
164  return score;
165 }
166 
167 
168 /*
169  * Callback methods
170  */
171 
172 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
173 static
174 SCIP_DECL_HEURCOPY(heurCopyActconsdiving)
175 { /*lint --e{715}*/
176  assert(scip != NULL);
177  assert(heur != NULL);
178  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
179 
180  /* call inclusion method of primal heuristic */
182 
183  return SCIP_OKAY;
184 }
185 
186 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
187 static
188 SCIP_DECL_HEURFREE(heurFreeActconsdiving) /*lint --e{715}*/
189 { /*lint --e{715}*/
190  SCIP_HEURDATA* heurdata;
191 
192  assert(heur != NULL);
193  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
194  assert(scip != NULL);
195 
196  /* free heuristic data */
197  heurdata = SCIPheurGetData(heur);
198  assert(heurdata != NULL);
199  SCIPfreeMemory(scip, &heurdata);
200  SCIPheurSetData(heur, NULL);
201 
202  return SCIP_OKAY;
203 }
204 
205 
206 /** initialization method of primal heuristic (called after problem was transformed) */
207 static
208 SCIP_DECL_HEURINIT(heurInitActconsdiving) /*lint --e{715}*/
209 { /*lint --e{715}*/
210  SCIP_HEURDATA* heurdata;
211 
212  assert(heur != NULL);
213  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
214 
215  /* get heuristic data */
216  heurdata = SCIPheurGetData(heur);
217  assert(heurdata != NULL);
218 
219  /* create working solution */
220  SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
221 
222  /* initialize data */
223  heurdata->nlpiterations = 0;
224  heurdata->nsuccess = 0;
225 
226  return SCIP_OKAY;
227 }
228 
229 
230 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
231 static
232 SCIP_DECL_HEUREXIT(heurExitActconsdiving) /*lint --e{715}*/
233 { /*lint --e{715}*/
234  SCIP_HEURDATA* heurdata;
235 
236  assert(heur != NULL);
237  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
238 
239  /* get heuristic data */
240  heurdata = SCIPheurGetData(heur);
241  assert(heurdata != NULL);
242 
243  /* free working solution */
244  SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
245 
246  return SCIP_OKAY;
247 }
248 
249 
250 /** execution method of primal heuristic */
251 static
252 SCIP_DECL_HEUREXEC(heurExecActconsdiving) /*lint --e{715}*/
253 { /*lint --e{715}*/
254  SCIP_HEURDATA* heurdata;
255  SCIP_LPSOLSTAT lpsolstat;
256  SCIP_VAR* var;
257  SCIP_VAR** lpcands;
258  SCIP_Real* lpcandssol;
259  SCIP_Real* lpcandsfrac;
260  SCIP_Real searchubbound;
261  SCIP_Real searchavgbound;
262  SCIP_Real searchbound;
263  SCIP_Real objval;
264  SCIP_Real oldobjval;
265  SCIP_Real frac;
266  SCIP_Real bestfrac;
267  SCIP_Bool bestcandmayrounddown;
268  SCIP_Bool bestcandmayroundup;
269  SCIP_Bool bestcandroundup;
270  SCIP_Bool mayrounddown;
271  SCIP_Bool mayroundup;
272  SCIP_Bool roundup;
273  SCIP_Bool lperror;
274  SCIP_Bool cutoff;
275  SCIP_Bool backtracked;
276  SCIP_Bool backtrack;
277  SCIP_Longint ncalls;
278  SCIP_Longint nsolsfound;
279  SCIP_Longint nlpiterations;
280  SCIP_Longint maxnlpiterations;
281  int nlpcands;
282  int startnlpcands;
283  int depth;
284  int maxdepth;
285  int maxdivedepth;
286  int divedepth;
287  SCIP_Real actscore;
288  SCIP_Real downscore;
289  SCIP_Real upscore;
290  SCIP_Real bestactscore;
291  int bestcand;
292  int c;
293 
294  assert(heur != NULL);
295  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
296  assert(scip != NULL);
297  assert(result != NULL);
298  assert(SCIPhasCurrentNodeLP(scip));
299 
300  *result = SCIP_DELAYED;
301 
302  /* do not call heuristic of node was already detected to be infeasible */
303  if( nodeinfeasible )
304  return SCIP_OKAY;
305 
306  /* only call heuristic, if an optimal LP solution is at hand */
308  return SCIP_OKAY;
309 
310  /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
311  if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
312  return SCIP_OKAY;
313 
314  /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
315  if( !SCIPisLPSolBasic(scip) )
316  return SCIP_OKAY;
317 
318  /* don't dive two times at the same node */
319  if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
320  return SCIP_OKAY;
321 
322  *result = SCIP_DIDNOTRUN;
323 
324  /* get heuristic's data */
325  heurdata = SCIPheurGetData(heur);
326  assert(heurdata != NULL);
327 
328  /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
329  depth = SCIPgetDepth(scip);
330  maxdepth = SCIPgetMaxDepth(scip);
331  maxdepth = MAX(maxdepth, 30);
332  if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
333  return SCIP_OKAY;
334 
335  /* calculate the maximal number of LP iterations until heuristic is aborted */
336  nlpiterations = SCIPgetNNodeLPIterations(scip);
337  ncalls = SCIPheurGetNCalls(heur);
338  nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
339  maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
340  maxnlpiterations += heurdata->maxlpiterofs;
341 
342  /* don't try to dive, if we took too many LP iterations during diving */
343  if( heurdata->nlpiterations >= maxnlpiterations )
344  return SCIP_OKAY;
345 
346  /* allow at least a certain number of LP iterations in this dive */
347  maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);
348 
349  /* get fractional variables that should be integral */
350  SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
351 
352  /* don't try to dive, if there are no fractional variables */
353  if( nlpcands == 0 )
354  return SCIP_OKAY;
355 
356  /* calculate the objective search bound */
357  if( SCIPgetNSolsFound(scip) == 0 )
358  {
359  if( heurdata->maxdiveubquotnosol > 0.0 )
360  searchubbound = SCIPgetLowerbound(scip)
361  + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
362  else
363  searchubbound = SCIPinfinity(scip);
364  if( heurdata->maxdiveavgquotnosol > 0.0 )
365  searchavgbound = SCIPgetLowerbound(scip)
366  + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
367  else
368  searchavgbound = SCIPinfinity(scip);
369  }
370  else
371  {
372  if( heurdata->maxdiveubquot > 0.0 )
373  searchubbound = SCIPgetLowerbound(scip)
374  + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
375  else
376  searchubbound = SCIPinfinity(scip);
377  if( heurdata->maxdiveavgquot > 0.0 )
378  searchavgbound = SCIPgetLowerbound(scip)
379  + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
380  else
381  searchavgbound = SCIPinfinity(scip);
382  }
383  searchbound = MIN(searchubbound, searchavgbound);
384  if( SCIPisObjIntegral(scip) )
385  searchbound = SCIPceil(scip, searchbound);
386 
387  /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
388  maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
389  maxdivedepth = MIN(maxdivedepth, maxdepth);
390  maxdivedepth *= 10;
391 
392  *result = SCIP_DIDNOTFIND;
393 
394  /* start diving */
395  SCIP_CALL( SCIPstartProbing(scip) );
396 
397  /* enables collection of variable statistics during probing */
398  SCIPenableVarHistory(scip);
399 
400  /* get LP objective value */
401  lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
402  objval = SCIPgetLPObjval(scip);
403 
404  SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing actconsdiving heuristic: depth=%d, %d fractionals, dualbound=%g, avgbound=%g, cutoffbound=%g, searchbound=%g\n",
405  SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), SCIPgetAvgDualbound(scip),
406  SCIPretransformObj(scip, SCIPgetCutoffbound(scip)), SCIPretransformObj(scip, searchbound));
407 
408  /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but
409  * - if possible, we dive at least with the depth 10
410  * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
411  */
412  lperror = FALSE;
413  cutoff = FALSE;
414  divedepth = 0;
415  bestcandmayrounddown = FALSE;
416  bestcandmayroundup = FALSE;
417  startnlpcands = nlpcands;
418  roundup = FALSE;
419 
420  while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0
421  && (divedepth < 10
422  || nlpcands <= startnlpcands - divedepth/2
423  || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound))
424  && !SCIPisStopped(scip) )
425  {
426  divedepth++;
427  SCIP_CALL( SCIPnewProbingNode(scip) );
428 
429  /* choose variable fixing:
430  * - prefer variables that may not be rounded without destroying LP feasibility:
431  * - of these variables, round variable with least number of locks in corresponding direction
432  * - if all remaining fractional variables may be rounded without destroying LP feasibility:
433  * - round variable with least number of locks in opposite of its feasible rounding direction
434  */
435  bestcand = -1;
436  bestactscore = -1.0;
437  bestfrac = SCIP_INVALID;
438  bestcandmayrounddown = TRUE;
439  bestcandmayroundup = TRUE;
440  bestcandroundup = FALSE;
441  for( c = 0; c < nlpcands; ++c )
442  {
443  var = lpcands[c];
444  mayrounddown = SCIPvarMayRoundDown(var);
445  mayroundup = SCIPvarMayRoundUp(var);
446  frac = lpcandsfrac[c];
447  if( mayrounddown || mayroundup )
448  {
449  /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
450  if( bestcandmayrounddown || bestcandmayroundup )
451  {
452  /* choose rounding direction:
453  * - if variable may be rounded in both directions, round corresponding to the fractionality
454  * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
455  * the current fractional solution
456  */
457  if( mayrounddown && mayroundup )
458  roundup = (frac > 0.5);
459  else
460  roundup = mayrounddown;
461 
462  if( roundup )
463  frac = 1.0 - frac;
464  actscore = getNActiveConsScore(scip, var, &downscore, &upscore);
465 
466  /* penalize too small fractions */
467  if( frac < 0.01 )
468  actscore *= 0.01;
469 
470  /* prefer decisions on binary variables */
471  if( !SCIPvarIsBinary(var) )
472  actscore *= 0.01;
473 
474  /* check, if candidate is new best candidate */
475  assert(0.0 < frac && frac < 1.0);
476  if( SCIPisGT(scip, actscore, bestactscore) || (SCIPisGE(scip, actscore, bestactscore) && frac < bestfrac) )
477  {
478  bestcand = c;
479  bestactscore = actscore;
480  bestfrac = frac;
481  bestcandmayrounddown = mayrounddown;
482  bestcandmayroundup = mayroundup;
483  bestcandroundup = roundup;
484  }
485  }
486  }
487  else
488  {
489  /* the candidate may not be rounded */
490  actscore = getNActiveConsScore(scip, var, &downscore, &upscore);
491  roundup = (downscore < upscore);
492  if( roundup )
493  frac = 1.0 - frac;
494 
495  /* penalize too small fractions */
496  if( frac < 0.01 )
497  actscore *= 0.01;
498 
499  /* prefer decisions on binary variables */
500  if( !SCIPvarIsBinary(var) )
501  actscore *= 0.01;
502 
503  /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
504  assert(0.0 < frac && frac < 1.0);
505  if( bestcandmayrounddown || bestcandmayroundup || SCIPisGT(scip, actscore, bestactscore) ||
506  (SCIPisGE(scip, actscore, bestactscore) && frac < bestfrac) )
507  {
508  bestcand = c;
509  bestactscore = actscore;
510  bestfrac = frac;
511  bestcandmayrounddown = FALSE;
512  bestcandmayroundup = FALSE;
513  bestcandroundup = roundup;
514  }
515  assert(bestfrac < SCIP_INVALID);
516  }
517  }
518  assert(bestcand != -1);
519 
520  /* if all candidates are roundable, try to round the solution */
521  if( bestcandmayrounddown || bestcandmayroundup )
522  {
523  SCIP_Bool success;
524 
525  /* create solution from diving LP and try to round it */
526  SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
527  SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
528 
529  if( success )
530  {
531  SCIPdebugMessage("actconsdiving found roundable 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  assert(bestcand != -1);
545  var = lpcands[bestcand];
546 
547  backtracked = FALSE;
548  do
549  {
550  backtrack = FALSE;
551  /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
552  * occured or variable was fixed by propagation while backtracking => Abort diving!
553  */
554  if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
555  {
556  SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
557  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]);
558  cutoff = TRUE;
559  break;
560  }
561  if( SCIPisFeasLT(scip, lpcandssol[bestcand], SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, lpcandssol[bestcand], SCIPvarGetUbLocal(var)) )
562  {
563  SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
564  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]);
565  assert(backtracked);
566  break;
567  }
568 
569  /* apply rounding of best candidate */
570  if( bestcandroundup == !backtracked )
571  {
572  /* round variable up */
573  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",
574  divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
575  SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
576  lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
577  SCIPfeasCeil(scip, lpcandssol[bestcand]), SCIPvarGetUbLocal(var));
578 
579  SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) );
580  roundup = TRUE;
581  }
582  else
583  {
584  /* round variable down */
585  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",
586  divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
587  SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
588  lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
589  SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, lpcandssol[bestcand]));
590 
591  SCIP_CALL( SCIPchgVarUbProbing(scip, lpcands[bestcand], SCIPfeasFloor(scip, lpcandssol[bestcand])) );
592  roundup = FALSE;
593  }
594 
595  /* apply domain propagation */
596  SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
597  if( !cutoff )
598  {
599  /* resolve the diving LP */
600  /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
601  * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
602  */
603 #ifdef NDEBUG
604  SCIP_RETCODE retstat;
605  nlpiterations = SCIPgetNLPIterations(scip);
606  retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff);
607  if( retstat != SCIP_OKAY )
608  {
609  SCIPwarningMessage(scip, "Error while solving LP in Actconsdiving heuristic; LP solve terminated with code <%d>\n",retstat);
610  }
611 #else
612  nlpiterations = SCIPgetNLPIterations(scip);
613  SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) );
614 #endif
615 
616  if( lperror )
617  break;
618 
619  /* update iteration count */
620  heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations;
621 
622  /* get LP solution status, objective value, and fractional variables, that should be integral */
623  lpsolstat = SCIPgetLPSolstat(scip);
624  assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE &&
625  (lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || SCIPisLT(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)))));
626  }
627 
628  /* perform backtracking if a cutoff was detected */
629  if( cutoff && !backtracked && heurdata->backtrack )
630  {
631  SCIPdebugMessage(" *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
633  SCIP_CALL( SCIPnewProbingNode(scip) );
634  backtracked = TRUE;
635  backtrack = TRUE;
636  }
637  else
638  backtrack = FALSE;
639  }
640  while( backtrack );
641 
642  if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
643  {
644  /* get new objective value */
645  oldobjval = objval;
646  objval = SCIPgetLPObjval(scip);
647 
648  /* update pseudo cost values */
649  if( SCIPisGT(scip, objval, oldobjval) )
650  {
651  if( roundup )
652  {
653  assert(bestcandroundup || backtracked);
654  SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 1.0-lpcandsfrac[bestcand],
655  objval - oldobjval, 1.0) );
656  }
657  else
658  {
659  assert(!bestcandroundup || backtracked);
660  SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 0.0-lpcandsfrac[bestcand],
661  objval - oldobjval, 1.0) );
662  }
663  }
664 
665  /* get new fractional variables */
666  SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
667  }
668  SCIPdebugMessage(" -> lpsolstat=%d, objval=%g/%g, nfrac=%d\n", lpsolstat, objval, searchbound, nlpcands);
669  }
670 
671  /* check if a solution has been found */
672  if( nlpcands == 0 && !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
673  {
674  SCIP_Bool success;
675 
676  /* create solution from diving LP */
677  SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
678  SCIPdebugMessage("actconsdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
679 
680  /* try to add solution to SCIP */
681  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );
682 
683  /* check, if solution was feasible and good enough */
684  if( success )
685  {
686  SCIPdebugMessage(" -> solution was feasible and good enough\n");
687  *result = SCIP_FOUNDSOL;
688  }
689  }
690 
691  /* end diving */
692  SCIP_CALL( SCIPendProbing(scip) );
693 
694  if( *result == SCIP_FOUNDSOL )
695  heurdata->nsuccess++;
696 
697  SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") finished actconsdiving heuristic: %d fractionals, dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT", objval=%g/%g, lpsolstat=%d, cutoff=%u\n",
698  SCIPgetNNodes(scip), nlpcands, divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
699  SCIPretransformObj(scip, objval), SCIPretransformObj(scip, searchbound), lpsolstat, cutoff);
700 
701  return SCIP_OKAY;
702 }
703 
704 
705 /*
706  * heuristic specific interface methods
707  */
708 
709 /** creates the actconsdiving heuristic and includes it in SCIP */
711  SCIP* scip /**< SCIP data structure */
712  )
713 {
714  SCIP_HEURDATA* heurdata;
715  SCIP_HEUR* heur;
716 
717  /* create actconsdiving primal heuristic data */
718  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
719 
720  /* include primal heuristic */
721  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
723  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecActconsdiving, heurdata) );
724 
725  assert(heur != NULL);
726 
727  /* set non-NULL pointers to callback methods */
728  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyActconsdiving) );
729  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeActconsdiving) );
730  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitActconsdiving) );
731  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitActconsdiving) );
732 
733  /* actconsdiving heuristic parameters */
735  "heuristics/actconsdiving/minreldepth",
736  "minimal relative depth to start diving",
737  &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
739  "heuristics/actconsdiving/maxreldepth",
740  "maximal relative depth to start diving",
741  &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
743  "heuristics/actconsdiving/maxlpiterquot",
744  "maximal fraction of diving LP iterations compared to node LP iterations",
745  &heurdata->maxlpiterquot, FALSE, DEFAULT_MAXLPITERQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
747  "heuristics/actconsdiving/maxlpiterofs",
748  "additional number of allowed LP iterations",
749  &heurdata->maxlpiterofs, FALSE, DEFAULT_MAXLPITEROFS, 0, INT_MAX, NULL, NULL) );
751  "heuristics/actconsdiving/maxdiveubquot",
752  "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
753  &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
755  "heuristics/actconsdiving/maxdiveavgquot",
756  "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
757  &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
759  "heuristics/actconsdiving/maxdiveubquotnosol",
760  "maximal UBQUOT when no solution was found yet (0.0: no limit)",
761  &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
763  "heuristics/actconsdiving/maxdiveavgquotnosol",
764  "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
765  &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
767  "heuristics/actconsdiving/backtrack",
768  "use one level of backtracking if infeasibility is encountered?",
769  &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
770 
771  return SCIP_OKAY;
772 }
773 
#define DEFAULT_MAXDIVEAVGQUOT
#define HEUR_USESSUBSCIP
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
#define MINLPITER
#define HEUR_FREQ
SCIP_RETCODE SCIPincludeHeurActconsdiving(SCIP *scip)
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
static SCIP_Real getNActiveConsScore(SCIP *scip, SCIP_VAR *var, SCIP_Real *downscore, SCIP_Real *upscore)
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
#define DEFAULT_MAXLPITEROFS
#define DEFAULT_BACKTRACK
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
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:18637
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
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
enum SCIP_LPSolStat SCIP_LPSOLSTAT
Definition: type_lp.h:42
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
#define DEFAULT_MAXDIVEUBQUOTNOSOL
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31855
static SCIP_DECL_HEURFREE(heurFreeActconsdiving)
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_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:15907
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
static SCIP_DECL_HEUREXEC(heurExecActconsdiving)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38273
SCIP_Real SCIPgetAvgDualbound(SCIP *scip)
Definition: scip.c:35000
SCIP_Real SCIPgetDualbound(SCIP *scip)
Definition: scip.c:35040
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition: lp.c:18506
#define HEUR_FREQOFS
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:38755
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:19159
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:18647
SCIP_Bool SCIPisObjIntegral(SCIP *scip)
Definition: scip.c:9683
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:38767
#define HEUR_DISPCHAR
int SCIPgetProbingDepth(SCIP *scip)
Definition: scip.c:29546
int SCIPgetMaxDepth(SCIP *scip)
Definition: scip.c:34883
#define DEFAULT_MINRELDEPTH
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:30856
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38648
LP diving heuristic that chooses fixings w.r.t. the active constraints the variable appear in...
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:16093
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
static SCIP_DECL_HEURINIT(heurInitActconsdiving)
#define HEUR_PRIORITY
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_MAXLPITERQUOT
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
SCIP_Real SCIProwGetNorm(SCIP_ROW *row)
Definition: lp.c:18613
#define HEUR_DESC
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
Definition: scip.c:29476
SCIP_RETCODE SCIPendProbing(SCIP *scip)
Definition: scip.c:29607
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:34833
SCIP_RETCODE SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31444
#define HEUR_TIMING
#define HEUR_NAME
#define DEFAULT_MAXDIVEUBQUOT
static SCIP_DECL_HEUREXIT(heurExitActconsdiving)
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 DEFAULT_MAXDIVEAVGQUOTNOSOL
#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
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:18657
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
#define HEUR_MAXDEPTH
SCIP_Bool SCIPvarMayRoundUp(SCIP_VAR *var)
Definition: var.c:3277
#define SCIP_INVALID
Definition: def.h:142
#define SCIP_Longint
Definition: def.h:107
SCIP_Real SCIPgetRowLPActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:25810
SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
Definition: heur.c:502
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip.c:24544
SCIP_Longint SCIPgetNNodeLPIterations(SCIP *scip)
Definition: scip.c:34442
SCIP_Real * SCIPcolGetVals(SCIP_COL *col)
Definition: lp.c:18516
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_MAXRELDEPTH
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(heurCopyActconsdiving)
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