Scippy

SCIP

Solving Constraint Integer Programs

heur_nlpdiving.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_nlpdiving.c
17  * @brief NLP diving heuristic that chooses fixings w.r.t. the fractionalities
18  * @author Timo Berthold
19  * @author Stefan Vigerske
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include <assert.h>
25 #include <string.h>
26 
27 #include "scip/heur_nlpdiving.h"
28 #include "scip/heur_subnlp.h" /* for NLP initialization */
29 #include "scip/heur_undercover.h" /* for cover computation */
30 #include "nlpi/nlpi.h" /* for NLP statistics, currently */
31 
32 
33 #define HEUR_NAME "nlpdiving"
34 #define HEUR_DESC "NLP diving heuristic that chooses fixings w.r.t. the fractionalities"
35 #define HEUR_DISPCHAR 'd'
36 #define HEUR_PRIORITY -1003000
37 #define HEUR_FREQ 10
38 #define HEUR_FREQOFS 3
39 #define HEUR_MAXDEPTH -1
40 #define HEUR_TIMING SCIP_HEURTIMING_AFTERLPPLUNGE
41 #define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
42 
43 /* event handler properties */
44 #define EVENTHDLR_NAME "Nlpdiving"
45 #define EVENTHDLR_DESC "bound change event handler for "HEUR_NAME" heuristic"
46 
47 
48 /*
49  * Default parameter settings
50  */
51 
52 #define DEFAULT_MINRELDEPTH 0.0 /**< minimal relative depth to start diving */
53 #define DEFAULT_MAXRELDEPTH 1.0 /**< maximal relative depth to start diving */
54 #define DEFAULT_MAXNLPITERABS 200 /**< minimial absolute number of allowed NLP iterations */
55 #define DEFAULT_MAXNLPITERREL 10 /**< additional allowed number of NLP iterations relative to successfully found solutions */
56 #define DEFAULT_MAXDIVEUBQUOT 0.8 /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
57  * where diving is performed (0.0: no limit) */
58 #define DEFAULT_MAXDIVEAVGQUOT 0.0 /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
59  * where diving is performed (0.0: no limit) */
60 #define DEFAULT_MAXDIVEUBQUOTNOSOL 0.1 /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
61 #define DEFAULT_MAXDIVEAVGQUOTNOSOL 0.0 /**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
62 #define DEFAULT_MINSUCCQUOT 0.1 /**< heuristic will not run if less then this percentage of calls succeeded (0.0: no limit) */
63 #define DEFAULT_MAXFEASNLPS 10 /**< maximal number of NLPs with feasible solution to solve during one dive */
64 #define DEFAULT_FIXQUOT 0.2 /**< percentage of fractional variables that should be fixed before the next NLP solve */
65 #define DEFAULT_BACKTRACK TRUE /**< use one level of backtracking if infeasibility is encountered? */
66 #define DEFAULT_LP FALSE /**< should the LP relaxation be solved before the NLP relaxation? */
67 #define DEFAULT_PREFERLPFRACS FALSE /**< prefer variables that are also fractional in LP solution? */
68 #define DEFAULT_PREFERCOVER TRUE /**< should variables in a minimal cover be preferred? */
69 #define DEFAULT_SOLVESUBMIP FALSE /**< should a sub-MIP be solved if all cover variables are fixed? */
70 #define DEFAULT_NLPSTART 's' /**< which point should be used as starting point for the NLP solver? */
71 #define DEFAULT_VARSELRULE 'd' /**< which variable selection should be used? ('f'ractionality, 'c'oefficient,
72  * 'p'seudocost, 'g'uided, 'd'ouble)
73  */
74 #define DEFAULT_NLPFASTFAIL TRUE /**< should the NLP solver stop early if it converges slow? */
75 
76 #define MINNLPITER 10 /**< minimal number of NLP iterations allowed in each NLP solving call */
77 
78 /* locally defined heuristic data */
79 struct SCIP_HeurData
80 {
81  SCIP_SOL* sol; /**< working solution */
82  SCIP_Real minreldepth; /**< minimal relative depth to start diving */
83  SCIP_Real maxreldepth; /**< maximal relative depth to start diving */
84  int maxnlpiterabs; /**< minimial absolute number of allowed NLP iterations */
85  int maxnlpiterrel; /**< additional allowed number of NLP iterations relative to successfully found solutions */
86  SCIP_Real maxdiveubquot; /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
87  * where diving is performed (0.0: no limit) */
88  SCIP_Real maxdiveavgquot; /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
89  * where diving is performed (0.0: no limit) */
90  SCIP_Real maxdiveubquotnosol; /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
91  SCIP_Real maxdiveavgquotnosol;/**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
92  int maxfeasnlps; /**< maximal number of NLPs with feasible solution to solve during one dive */
93  SCIP_Real minsuccquot; /**< heuristic will not run if less then this percentage of calls succeeded (0.0: no limit) */
94  SCIP_Real fixquot; /**< percentage of fractional variables that should be fixed before the next NLP solve */
95  SCIP_Bool backtrack; /**< use one level of backtracking if infeasibility is encountered? */
96  SCIP_Bool lp; /**< should the LP relaxation be solved before the NLP relaxation? */
97  SCIP_Bool preferlpfracs; /**< prefer variables that are also fractional in LP solution? */
98  SCIP_Bool prefercover; /**< should variables in a minimal cover be preferred? */
99  SCIP_Bool solvesubmip; /**< should a sub-MIP be solved if all cover variables are fixed? */
100  SCIP_Bool nlpfastfail; /**< should the NLP solver stop early if it converges slow? */
101  char nlpstart; /**< which point should be used as starting point for the NLP solver? */
102  char varselrule; /**< which variable selection should be used? ('f'ractionality, 'c'oefficient,
103  * 'p'seudocost, 'g'uided, 'd'ouble)
104  */
105 
106  int nnlpiterations; /**< NLP iterations used in this heuristic */
107  int nsuccess; /**< number of runs that produced at least one feasible solution */
108  int nfixedcovervars; /**< number of variables in the cover that are already fixed */
109 #ifdef SCIP_STATISTIC
110  int nnlpsolves; /**< number of NLP solves */
111  int nfailcutoff; /**< number of fails due to cutoff */
112  int nfaildepth; /**< number of fails due to too deep */
113  int nfailnlperror; /**< number of fails due to NLP error */
114 #endif
115  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
116 };
117 
118 
119 /*
120  * local methods
121  */
122 
123 /** gets fractional variables of last NLP solution along with solution values and fractionalities
124  *
125  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
126  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
127  *
128  * @pre This method can be called if SCIP is in one of the following stages:
129  * - \ref SCIP_STAGE_INITSOLVE
130  * - \ref SCIP_STAGE_SOLVING
131  */
132 static
134  SCIP* scip, /**< SCIP data structure */
135  SCIP_HEURDATA* heurdata, /**< heuristic data structure */
136  SCIP_VAR*** nlpcands, /**< pointer to store the array of NLP fractional variables, or NULL */
137  SCIP_Real** nlpcandssol, /**< pointer to store the array of NLP fractional variables solution values, or NULL */
138  SCIP_Real** nlpcandsfrac, /**< pointer to store the array of NLP fractional variables fractionalities, or NULL */
139  int* nnlpcands /**< pointer to store the number of NLP fractional variables , or NULL */
140  )
141 {
142  int c;
143 
144  assert(scip != NULL);
145  assert(heurdata != NULL);
146  assert(nlpcands != NULL);
147  assert(nlpcandssol != NULL);
148  assert(nlpcandsfrac != NULL);
149  assert(nnlpcands != NULL);
150 
151  /* get fractional variables that should be integral */
152  SCIP_CALL( SCIPgetNLPFracVars(scip, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, NULL) );
153 
154  /* values may be outside the domain in exact arithmetic, but inside the domain within relative tolerance, and still
155  * slightly fractional, because SCIPisFeasIntegral() uses absolute tolerance; project value onto domain to avoid this
156  * (example: primsol=29.99999853455704, lower bound = 30)
157  */
158  for( c = 0; c < *nnlpcands; ++c )
159  {
160  assert(!SCIPisFeasIntegral(scip, (*nlpcandssol)[c]));
161 
162  if( (*nlpcandssol)[c] < SCIPvarGetLbLocal((*nlpcands)[c]) || (*nlpcandssol)[c] > SCIPvarGetUbLocal((*nlpcands)[c]) )
163  {
164  SCIP_Real newval;
165 
166  newval = ((*nlpcandssol)[c] < SCIPvarGetLbLocal((*nlpcands)[c]))
167  ? SCIPvarGetLbLocal((*nlpcands)[c]) - 0.5*SCIPfeastol(scip)
168  : SCIPvarGetUbLocal((*nlpcands)[c]) + 0.5*SCIPfeastol(scip);
169 
170  assert(SCIPisFeasIntegral(scip, newval));
171 
172  SCIP_CALL( SCIPsetSolVal(scip, heurdata->sol, (*nlpcands)[c], newval) );
173 
174  (*nnlpcands)--;
175 
176  if( c < *nnlpcands )
177  {
178  (*nlpcands)[c] = (*nlpcands)[*nnlpcands];
179  (*nlpcandssol)[c] = (*nlpcandssol)[*nnlpcands];
180  (*nlpcandsfrac)[c] = (*nlpcandsfrac)[*nnlpcands];
181  }
182  }
183  }
184 
185  /* prefer decisions on variables which are also fractional in LP solution */
186  if( heurdata->preferlpfracs && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
187  {
188  for( c = 0; c < *nnlpcands; ++c )
189  {
190  if( SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, NULL, (*nlpcands)[c])) )
191  (*nlpcandsfrac)[c] *= 100.0;
192  }
193  }
194 
195  return SCIP_OKAY;
196 }
197 
198 /** finds best candidate variable w.r.t. fractionality:
199  * - prefer variables that may not be rounded without destroying NLP feasibility:
200  * - of these variables, round least fractional variable in corresponding direction
201  * - if all remaining fractional variables may be rounded without destroying NLP feasibility:
202  * - round variable with least increasing objective value
203  * - binary variables are prefered
204  * - variables in a minimal cover or variables that are also fractional in an optimal LP solution might
205  * also be prefered if a correpsonding parameter is set
206  */
207 static
209  SCIP* scip, /**< original SCIP data structure */
210  SCIP_HEURDATA* heurdata, /**< heuristic data structure */
211  SCIP_VAR** nlpcands, /**< array of NLP fractional variables */
212  SCIP_Real* nlpcandssol, /**< array of NLP fractional variables solution values */
213  SCIP_Real* nlpcandsfrac, /**< array of NLP fractional variables fractionalities */
214  int nnlpcands, /**< number of NLP fractional variables */
215  SCIP_HASHMAP* varincover, /**< hash map for variables */
216  SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
217  int* bestcand, /**< pointer to store the index of the best candidate variable */
218  SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
219  SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
220  )
221 {
222  SCIP_Real bestobjgain;
223  SCIP_Real bestfrac;
224  SCIP_Bool bestcandmayrounddown;
225  SCIP_Bool bestcandmayroundup;
226  int c;
227 
228  /* check preconditions */
229  assert(scip != NULL);
230  assert(heurdata != NULL);
231  assert(nlpcands != NULL);
232  assert(nlpcandssol != NULL);
233  assert(nlpcandsfrac != NULL);
234  assert(covercomputed == (varincover != NULL));
235  assert(bestcand != NULL);
236  assert(bestcandmayround != NULL);
237  assert(bestcandroundup != NULL);
238 
239  bestcandmayrounddown = TRUE;
240  bestcandmayroundup = TRUE;
241  bestobjgain = SCIPinfinity(scip);
242  bestfrac = SCIP_INVALID;
243 
244  for( c = 0; c < nnlpcands; ++c )
245  {
246  SCIP_VAR* var;
247  SCIP_Bool mayrounddown;
248  SCIP_Bool mayroundup;
249  SCIP_Bool roundup;
250  SCIP_Real frac;
251  SCIP_Real obj;
252  SCIP_Real objgain;
253 
254  var = nlpcands[c];
255 
256  mayrounddown = SCIPvarMayRoundDown(var);
257  mayroundup = SCIPvarMayRoundUp(var);
258  frac = nlpcandsfrac[c];
259  obj = SCIPvarGetObj(var);
260 
261  /* since we are not solving the NLP after each fixing, the old NLP solution might be outside the propagated bounds */
262  if( SCIPisLT(scip, nlpcandssol[c], SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpcandssol[c], SCIPvarGetUbLocal(var)) )
263  continue;
264 
265  if( mayrounddown || mayroundup )
266  {
267  /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
268  if( bestcandmayrounddown || bestcandmayroundup )
269  {
270  /* choose rounding direction:
271  * - if variable may be rounded in both directions, round corresponding to the fractionality
272  * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
273  * the current fractional solution
274  */
275  if( mayrounddown && mayroundup )
276  roundup = (frac > 0.5);
277  else
278  roundup = mayrounddown;
279 
280  if( roundup )
281  {
282  frac = 1.0 - frac;
283  objgain = frac*obj;
284  }
285  else
286  objgain = -frac*obj;
287 
288  /* penalize too small fractions */
289  if( frac < 0.01 )
290  objgain *= 1000.0;
291 
292  /* prefer decisions on binary variables */
293  if( !SCIPvarIsBinary(var) )
294  objgain *= 1000.0;
295 
296  /* prefer decisions on cover variables */
297  if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
298  objgain *= 1000.0;
299 
300  /* check, if candidate is new best candidate */
301  if( SCIPisLT(scip, objgain, bestobjgain) || (SCIPisEQ(scip, objgain, bestobjgain) && frac < bestfrac) )
302  {
303  *bestcand = c;
304  bestobjgain = objgain;
305  bestfrac = frac;
306  bestcandmayrounddown = mayrounddown;
307  bestcandmayroundup = mayroundup;
308  *bestcandroundup = roundup;
309  }
310  }
311  }
312  else
313  {
314  /* the candidate may not be rounded */
315  if( frac < 0.5 )
316  roundup = FALSE;
317  else
318  {
319  roundup = TRUE;
320  frac = 1.0 - frac;
321  }
322 
323  /* penalize too small fractions */
324  if( frac < 0.01 )
325  frac += 10.0;
326 
327  /* prefer decisions on binary variables */
328  if( !SCIPvarIsBinary(var) )
329  frac *= 1000.0;
330 
331  /* prefer decisions on cover variables */
332  if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
333  frac *= 1000.0;
334 
335  /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
336  if( bestcandmayrounddown || bestcandmayroundup || frac < bestfrac )
337  {
338  *bestcand = c;
339  bestfrac = frac;
340  bestcandmayrounddown = FALSE;
341  bestcandmayroundup = FALSE;
342  *bestcandroundup = roundup;
343  }
344  assert(bestfrac < SCIP_INVALID);
345  }
346  }
347 
348  *bestcandmayround = bestcandmayroundup || bestcandmayrounddown;
349 
350  return SCIP_OKAY;
351 }
352 
353 /** finds best candidate variable w.r.t. vector length:
354  * - round variable with a small ratio between the increase in the objective and the locking numbers
355  * - binary variables are prefered
356  * - variables in a minimal cover or variables that are also fractional in an optimal LP solution might
357  * also be prefered if a corresponding parameter is set
358  */
359 static
361  SCIP* scip, /**< original SCIP data structure */
362  SCIP_HEURDATA* heurdata, /**< heuristic data structure */
363  SCIP_VAR** nlpcands, /**< array of NLP fractional variables */
364  SCIP_Real* nlpcandssol, /**< array of NLP fractional variables solution values */
365  SCIP_Real* nlpcandsfrac, /**< array of NLP fractional variables fractionalities */
366  int nnlpcands, /**< number of NLP fractional variables */
367  SCIP_HASHMAP* varincover, /**< hash map for variables */
368  SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
369  int* bestcand, /**< pointer to store the index of the best candidate variable */
370  SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
371  SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
372  )
373 {
374  SCIP_Real bestscore;
375  int c;
376 
377  /* check preconditions */
378  assert(scip != NULL);
379  assert(heurdata != NULL);
380  assert(nlpcands != NULL);
381  assert(nlpcandsfrac != NULL);
382  assert(nlpcandssol != NULL);
383  assert(bestcand != NULL);
384  assert(bestcandmayround != NULL);
385  assert(bestcandroundup != NULL);
386 
387  *bestcandmayround = TRUE;
388  bestscore = SCIP_REAL_MAX;
389 
390  /* get best candidate */
391  for( c = 0; c < nnlpcands; ++c )
392  {
393  SCIP_VAR* var;
394 
395  SCIP_Real obj;
396  SCIP_Real objdelta;
397  SCIP_Real frac;
398  SCIP_Real score;
399 
400  int nlocks;
401 
402  SCIP_Bool roundup;
403 
404  var = nlpcands[c];
405 
406  /* since we are not solving the NLP after each fixing, the old NLP solution might be outside the propagated bounds */
407  if( SCIPisLT(scip, nlpcandssol[c], SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpcandssol[c], SCIPvarGetUbLocal(var)) )
408  continue;
409 
410  frac = nlpcandsfrac[c];
411  obj = SCIPvarGetObj(var);
412  roundup = (obj >= 0.0);
413  objdelta = (roundup ? (1.0-frac)*obj : -frac * obj);
414  assert(objdelta >= 0.0);
415 
416  /* check whether the variable is roundable */
417  *bestcandmayround = *bestcandmayround && (SCIPvarMayRoundDown(var) || SCIPvarMayRoundUp(var));
418  nlocks = SCIPvarGetNLocksDown(var) + SCIPvarGetNLocksUp(var);
419 
420  /* smaller score is better */
421  score = (objdelta + SCIPsumepsilon(scip))/((SCIP_Real)nlocks+1.0);
422 
423  /* prefer decisions on binary variables */
424  if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY )
425  score *= 1000.0;
426 
427  /* prefer decisions on cover variables */
428  if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
429  score *= 1000;
430 
431  /* check, if candidate is new best candidate */
432  if( score < bestscore )
433  {
434  *bestcand = c;
435  bestscore = score;
436  *bestcandroundup = roundup;
437  }
438  }
439 
440  return SCIP_OKAY;
441 }
442 
443 
444 /** finds best candidate variable w.r.t. locking numbers:
445  * - prefer variables that may not be rounded without destroying LP feasibility:
446  * - of these variables, round variable with least number of locks in corresponding direction
447  * - if all remaining fractional variables may be rounded without destroying LP feasibility:
448  * - round variable with least number of locks in opposite of its feasible rounding direction
449  * - binary variables are prefered
450  * - variables in a minimal cover or variables that are also fractional in an optimal LP solution might
451  * also be prefered if a correpsonding parameter is set
452  */
453 static
455  SCIP* scip, /**< original SCIP data structure */
456  SCIP_HEURDATA* heurdata, /**< heuristic data structure */
457  SCIP_VAR** nlpcands, /**< array of NLP fractional variables */
458  SCIP_Real* nlpcandssol, /**< array of NLP fractional variables solution values */
459  SCIP_Real* nlpcandsfrac, /**< array of NLP fractional variables fractionalities */
460  int nnlpcands, /**< number of NLP fractional variables */
461  SCIP_HASHMAP* varincover, /**< hash map for variables */
462  SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
463  int* bestcand, /**< pointer to store the index of the best candidate variable */
464  SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
465  SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
466  )
467 {
468  SCIP_Bool bestcandmayrounddown;
469  SCIP_Bool bestcandmayroundup;
470  int bestnviolrows; /* number of violated rows for best candidate */
471  SCIP_Real bestcandfrac; /* fractionality of best candidate */
472  int c;
473 
474  /* check preconditions */
475  assert(scip != NULL);
476  assert(heurdata != NULL);
477  assert(nlpcands != NULL);
478  assert(nlpcandsfrac != NULL);
479  assert(nlpcandssol != NULL);
480  assert(bestcand != NULL);
481  assert(bestcandmayround != NULL);
482  assert(bestcandroundup != NULL);
483 
484  bestcandmayrounddown = TRUE;
485  bestcandmayroundup = TRUE;
486  bestnviolrows = INT_MAX;
487  bestcandfrac = SCIP_INVALID;
488 
489  /* get best candidate */
490  for( c = 0; c < nnlpcands; ++c )
491  {
492  SCIP_VAR* var;
493 
494  int nlocksdown;
495  int nlocksup;
496  int nviolrows;
497 
498  SCIP_Bool mayrounddown;
499  SCIP_Bool mayroundup;
500  SCIP_Bool roundup;
501  SCIP_Real frac;
502 
503  var = nlpcands[c];
504  mayrounddown = SCIPvarMayRoundDown(var);
505  mayroundup = SCIPvarMayRoundUp(var);
506  frac = nlpcandsfrac[c];
507 
508  /* since we are not solving the NLP after each fixing, the old NLP solution might be outside the propagated bounds */
509  if( SCIPisLT(scip, nlpcandssol[c], SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpcandssol[c], SCIPvarGetUbLocal(var)) )
510  continue;
511 
512  if( mayrounddown || mayroundup )
513  {
514  /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
515  if( bestcandmayrounddown || bestcandmayroundup )
516  {
517  /* choose rounding direction:
518  * - if variable may be rounded in both directions, round corresponding to the fractionality
519  * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
520  * the current fractional solution
521  */
522  if( mayrounddown && mayroundup )
523  roundup = (frac > 0.5);
524  else
525  roundup = mayrounddown;
526 
527  if( roundup )
528  {
529  frac = 1.0 - frac;
530  nviolrows = SCIPvarGetNLocksUp(var);
531  }
532  else
533  nviolrows = SCIPvarGetNLocksDown(var);
534 
535  /* penalize too small fractions */
536  if( frac < 0.01 )
537  nviolrows *= 100;
538 
539  /* prefer decisions on binary variables */
540  if( !SCIPvarIsBinary(var) )
541  nviolrows *= 1000;
542 
543  /* prefer decisions on cover variables */
544  if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
545  nviolrows *= 1000;
546 
547  /* check, if candidate is new best candidate */
548  assert( (0.0 < frac && frac < 1.0) || SCIPvarIsBinary(var) );
549  if( nviolrows + frac < bestnviolrows + bestcandfrac )
550  {
551  *bestcand = c;
552  bestnviolrows = nviolrows;
553  bestcandfrac = frac;
554  bestcandmayrounddown = mayrounddown;
555  bestcandmayroundup = mayroundup;
556  *bestcandroundup = roundup;
557  }
558  }
559  }
560  else
561  {
562  /* the candidate may not be rounded */
563  nlocksdown = SCIPvarGetNLocksDown(var);
564  nlocksup = SCIPvarGetNLocksUp(var);
565  roundup = (nlocksdown > nlocksup || (nlocksdown == nlocksup && frac > 0.5));
566  if( roundup )
567  {
568  nviolrows = nlocksup;
569  frac = 1.0 - frac;
570  }
571  else
572  nviolrows = nlocksdown;
573 
574  /* penalize too small fractions */
575  if( frac < 0.01 )
576  nviolrows *= 100;
577 
578  /* prefer decisions on binary variables */
579  if( !SCIPvarIsBinary(var) )
580  nviolrows *= 100;
581 
582  /* prefer decisions on cover variables */
583  if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
584  nviolrows *= 1000;
585 
586  /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
587  assert((0.0 < frac && frac < 1.0) || SCIPvarIsBinary(var));
588  if( bestcandmayrounddown || bestcandmayroundup || nviolrows + frac < bestnviolrows + bestcandfrac )
589  {
590  *bestcand = c;
591  bestnviolrows = nviolrows;
592  bestcandfrac = frac;
593  bestcandmayrounddown = FALSE;
594  bestcandmayroundup = FALSE;
595  *bestcandroundup = roundup;
596  }
597  assert(bestcandfrac < SCIP_INVALID);
598  }
599  }
600 
601  *bestcandmayround = bestcandmayroundup || bestcandmayrounddown;
602 
603  return SCIP_OKAY;
604 }
605 
606 /** calculates the pseudocost score for a given variable w.r.t. a given solution value and a given rounding direction */
607 static
609  SCIP* scip, /**< SCIP data structure */
610  SCIP_VAR* var, /**< problem variable */
611  SCIP_Real primsol, /**< primal solution of variable */
612  SCIP_Real frac, /**< fractionality of variable */
613  int rounddir, /**< -1: round down, +1: round up, 0: select due to pseudo cost values */
614  SCIP_Real* pscostquot, /**< pointer to store pseudo cost quotient */
615  SCIP_Bool* roundup, /**< pointer to store whether the variable should be rounded up */
616  SCIP_Bool prefvar /**< should this variable be prefered because it is in a minimal cover? */
617  )
618 {
619  SCIP_Real pscostdown;
620  SCIP_Real pscostup;
621 
622  assert(pscostquot != NULL);
623  assert(roundup != NULL);
624  assert(SCIPisEQ(scip, frac, primsol - SCIPfeasFloor(scip, primsol)));
625 
626  /* bound fractions to not prefer variables that are nearly integral */
627  frac = MAX(frac, 0.1);
628  frac = MIN(frac, 0.9);
629 
630  /* get pseudo cost quotient */
631  pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0-frac);
632  pscostup = SCIPgetVarPseudocostVal(scip, var, 1.0-frac);
633  assert(pscostdown >= 0.0 && pscostup >= 0.0);
634 
635  /* choose rounding direction */
636  if( rounddir == -1 )
637  *roundup = FALSE;
638  else if( rounddir == +1 )
639  *roundup = TRUE;
640  else if( primsol < SCIPvarGetRootSol(var) - 0.4 )
641  *roundup = FALSE;
642  else if( primsol > SCIPvarGetRootSol(var) + 0.4 )
643  *roundup = TRUE;
644  else if( frac < 0.3 )
645  *roundup = FALSE;
646  else if( frac > 0.7 )
647  *roundup = TRUE;
648  else if( pscostdown < pscostup )
649  *roundup = FALSE;
650  else
651  *roundup = TRUE;
652 
653  /* calculate pseudo cost quotient */
654  if( *roundup )
655  *pscostquot = sqrt(frac) * (1.0+pscostdown) / (1.0+pscostup);
656  else
657  *pscostquot = sqrt(1.0-frac) * (1.0+pscostup) / (1.0+pscostdown);
658 
659  /* prefer decisions on binary variables */
660  if( SCIPvarIsBinary(var) )
661  (*pscostquot) *= 1000.0;
662 
663  /* prefer decisions on cover variables */
664  if( prefvar )
665  (*pscostquot) *= 1000.0;
666 }
667 
668 /** finds best candidate variable w.r.t. pseudo costs:
669  * - prefer variables that may not be rounded without destroying LP feasibility:
670  * - of these variables, round variable with largest rel. difference of pseudo cost values in corresponding
671  * direction
672  * - if all remaining fractional variables may be rounded without destroying LP feasibility:
673  * - round variable in the objective value direction
674  * - binary variables are prefered
675  * - variables in a minimal cover or variables that are also fractional in an optimal LP solution might
676  * also be prefered if a correpsonding parameter is set
677  */
678 static
680  SCIP* scip, /**< original SCIP data structure */
681  SCIP_HEURDATA* heurdata, /**< heuristic data structure */
682  SCIP_VAR** nlpcands, /**< array of NLP fractional variables */
683  SCIP_Real* nlpcandssol, /**< array of NLP fractional variables solution values */
684  SCIP_Real* nlpcandsfrac, /**< array of NLP fractional variables fractionalities */
685  int nnlpcands, /**< number of NLP fractional variables */
686  SCIP_HASHMAP* varincover, /**< hash map for variables */
687  SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
688  int* bestcand, /**< pointer to store the index of the best candidate variable */
689  SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
690  SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
691  )
692 {
693  SCIP_Bool bestcandmayrounddown;
694  SCIP_Bool bestcandmayroundup;
695  SCIP_Real bestpscostquot;
696  int c;
697 
698  /* check preconditions */
699  assert(scip != NULL);
700  assert(heurdata != NULL);
701  assert(nlpcands != NULL);
702  assert(nlpcandsfrac != NULL);
703  assert(nlpcandssol != NULL);
704  assert(bestcand != NULL);
705  assert(bestcandmayround != NULL);
706  assert(bestcandroundup != NULL);
707 
708  bestcandmayrounddown = TRUE;
709  bestcandmayroundup = TRUE;
710  bestpscostquot = -1.0;
711 
712  for( c = 0; c < nnlpcands; ++c )
713  {
714  SCIP_VAR* var;
715  SCIP_Real primsol;
716 
717  SCIP_Bool mayrounddown;
718  SCIP_Bool mayroundup;
719  SCIP_Bool roundup;
720  SCIP_Bool prefvar;
721  SCIP_Real frac;
722  SCIP_Real pscostquot;
723 
724  var = nlpcands[c];
725  mayrounddown = SCIPvarMayRoundDown(var);
726  mayroundup = SCIPvarMayRoundUp(var);
727  primsol = nlpcandssol[c];
728  frac = nlpcandsfrac[c];
729  prefvar = covercomputed && heurdata->prefercover && SCIPhashmapExists(varincover, var);
730  pscostquot = SCIP_INVALID;
731 
732  if( SCIPisLT(scip, nlpcandssol[c], SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpcandssol[c], SCIPvarGetUbLocal(var)) )
733  continue;
734 
735  if( mayrounddown || mayroundup )
736  {
737  /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
738  if( bestcandmayrounddown || bestcandmayroundup )
739  {
740  /* choose rounding direction:
741  * - if variable may be rounded in both directions, round corresponding to the pseudo cost values
742  * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
743  * the current fractional solution
744  */
745  roundup = FALSE;
746  if( mayrounddown && mayroundup )
747  calcPscostQuot(scip, var, primsol, frac, 0, &pscostquot, &roundup, prefvar);
748  else if( mayrounddown )
749  calcPscostQuot(scip, var, primsol, frac, +1, &pscostquot, &roundup, prefvar);
750  else
751  calcPscostQuot(scip, var, primsol, frac, -1, &pscostquot, &roundup, prefvar);
752 
753  assert(!SCIPisInfinity(scip,ABS(pscostquot)));
754 
755  /* check, if candidate is new best candidate */
756  if( pscostquot > bestpscostquot )
757  {
758  *bestcand = c;
759  bestpscostquot = pscostquot;
760  bestcandmayrounddown = mayrounddown;
761  bestcandmayroundup = mayroundup;
762  *bestcandroundup = roundup;
763  }
764  }
765  }
766  else
767  {
768  /* the candidate may not be rounded: calculate pseudo cost quotient and preferred direction */
769  calcPscostQuot(scip, var, primsol, frac, 0, &pscostquot, &roundup, prefvar);
770  assert(!SCIPisInfinity(scip,ABS(pscostquot)));
771 
772  /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
773  if( bestcandmayrounddown || bestcandmayroundup || pscostquot > bestpscostquot )
774  {
775  *bestcand = c;
776  bestpscostquot = pscostquot;
777  bestcandmayrounddown = FALSE;
778  bestcandmayroundup = FALSE;
779  *bestcandroundup = roundup;
780  }
781  }
782  }
783 
784  *bestcandmayround = bestcandmayroundup || bestcandmayrounddown;
785 
786  return SCIP_OKAY;
787 }
788 
789 /** finds best candidate variable w.r.t. the incumbent solution:
790  * - prefer variables that may not be rounded without destroying LP feasibility:
791  * - of these variables, round a variable to its value in direction of incumbent solution, and choose the
792  * variable that is closest to its rounded value
793  * - if all remaining fractional variables may be rounded without destroying LP feasibility:
794  * - round variable in direction that destroys LP feasibility (other direction is checked by SCIProundSol())
795  * - round variable with least increasing objective value
796  * - binary variables are prefered
797  * - variables in a minimal cover or variables that are also fractional in an optimal LP solution might
798  * also be prefered if a correpsonding parameter is set
799  */
800 static
802  SCIP* scip, /**< original SCIP data structure */
803  SCIP_HEURDATA* heurdata, /**< heuristic data structure */
804  SCIP_VAR** nlpcands, /**< array of NLP fractional variables */
805  SCIP_Real* nlpcandssol, /**< array of NLP fractional variables solution values */
806  SCIP_Real* nlpcandsfrac, /**< array of NLP fractional variables fractionalities */
807  int nnlpcands, /**< number of NLP fractional variables */
808  SCIP_SOL* bestsol, /**< incumbent solution */
809  SCIP_HASHMAP* varincover, /**< hash map for variables */
810  SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
811  int* bestcand, /**< pointer to store the index of the best candidate variable */
812  SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
813  SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
814  )
815 {
816  SCIP_Real bestobjgain;
817  SCIP_Real bestfrac;
818  SCIP_Bool bestcandmayrounddown;
819  SCIP_Bool bestcandmayroundup;
820  int c;
821 
822  /* check preconditions */
823  assert(scip != NULL);
824  assert(heurdata != NULL);
825  assert(nlpcands != NULL);
826  assert(nlpcandsfrac != NULL);
827  assert(nlpcandssol != NULL);
828  assert(bestcand != NULL);
829  assert(bestcandmayround != NULL);
830  assert(bestcandroundup != NULL);
831 
832  bestcandmayrounddown = TRUE;
833  bestcandmayroundup = TRUE;
834  bestobjgain = SCIPinfinity(scip);
835  bestfrac = SCIP_INVALID;
836 
837  for( c = 0; c < nnlpcands; ++c )
838  {
839  SCIP_VAR* var;
840  SCIP_Real bestsolval;
841  SCIP_Real solval;
842  SCIP_Real obj;
843  SCIP_Real frac;
844  SCIP_Real objgain;
845 
846  SCIP_Bool mayrounddown;
847  SCIP_Bool mayroundup;
848  SCIP_Bool roundup;
849 
850  var = nlpcands[c];
851  mayrounddown = SCIPvarMayRoundDown(var);
852  mayroundup = SCIPvarMayRoundUp(var);
853  solval = nlpcandssol[c];
854  frac = nlpcandsfrac[c];
855  obj = SCIPvarGetObj(var);
856  bestsolval = SCIPgetSolVal(scip, bestsol, var);
857 
858  /* since we are not solving the NLP after each fixing, the old NLP solution might be outside the propagated bounds */
859  if( SCIPisLT(scip, solval, SCIPvarGetLbLocal(var)) || SCIPisGT(scip, solval, SCIPvarGetUbLocal(var)) )
860  continue;
861 
862  /* select default rounding direction */
863  roundup = (solval < bestsolval);
864 
865  if( mayrounddown || mayroundup )
866  {
867  /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
868  if( bestcandmayrounddown || bestcandmayroundup )
869  {
870  /* choose rounding direction:
871  * - if variable may be rounded in both directions, round corresponding to its value in incumbent solution
872  * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
873  * the current fractional solution with SCIProundSol()
874  */
875  if( !mayrounddown || !mayroundup )
876  roundup = mayrounddown;
877 
878  if( roundup )
879  {
880  frac = 1.0 - frac;
881  objgain = frac*obj;
882  }
883  else
884  objgain = -frac*obj;
885 
886  /* penalize too small fractions */
887  if( frac < 0.01 )
888  objgain *= 1000.0;
889 
890  /* prefer decisions on binary variables */
891  if( !SCIPvarIsBinary(var) )
892  objgain *= 1000.0;
893 
894  /* prefer decisions on cover variables */
895  if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
896  objgain *= 1000.0;
897 
898  /* check, if candidate is new best candidate */
899  if( SCIPisLT(scip, objgain, bestobjgain) || (SCIPisEQ(scip, objgain, bestobjgain) && frac < bestfrac) )
900  {
901  *bestcand = c;
902  bestobjgain = objgain;
903  bestfrac = frac;
904  bestcandmayrounddown = mayrounddown;
905  bestcandmayroundup = mayroundup;
906  *bestcandroundup = roundup;
907  }
908  }
909  }
910  else
911  {
912  /* the candidate may not be rounded */
913  if( roundup )
914  frac = 1.0 - frac;
915 
916  /* penalize too small fractions */
917  if( frac < 0.01 )
918  frac += 10.0;
919 
920  /* prefer decisions on binary variables */
921  if( !SCIPvarIsBinary(var) )
922  frac *= 1000.0;
923 
924  /* prefer decisions on cover variables */
925  if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
926  frac *= 1000.0;
927 
928  /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
929  if( bestcandmayrounddown || bestcandmayroundup || frac < bestfrac )
930  {
931  *bestcand = c;
932  bestfrac = frac;
933  bestcandmayrounddown = FALSE;
934  bestcandmayroundup = FALSE;
935  *bestcandroundup = roundup;
936  }
937  }
938  }
939 
940  *bestcandmayround = bestcandmayroundup || bestcandmayrounddown;
941 
942  return SCIP_OKAY;
943 }
944 
945 /** finds best candidate variable w.r.t. both, the LP and the NLP solution:
946  * - choose a variable for which the sum of the distances from the relaxations' solutions to a common
947  * integer value is minimal
948  * - binary variables are prefered
949  * - variables in a minimal cover might be prefered if a corresponding parameter is set
950  */
951 static
953  SCIP* scip, /**< original SCIP data structure */
954  SCIP_HEURDATA* heurdata, /**< heuristic data structure */
955  SCIP_VAR** pseudocands, /**< array of non-fixed variables */
956  SCIP_Real* pseudocandsnlpsol, /**< array of NLP solution values */
957  SCIP_Real* pseudocandslpsol, /**< array of LP solution values */
958  int npseudocands, /**< number of NLP fractional variables */
959  SCIP_HASHMAP* varincover, /**< hash map for variables */
960  SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
961  int* bestcand, /**< pointer to store the index of the best candidate variable */
962  SCIP_Real* bestboundval, /**< pointer to store the bound, the best candidate should be rounded to */
963  SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
964  SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
965  )
966 {
967  SCIP_Real bestfrac;
968  int c;
969 
970  /* check preconditions */
971  assert(scip != NULL);
972  assert(heurdata != NULL);
973  assert(pseudocands != NULL);
974  assert(pseudocandsnlpsol != NULL);
975  assert(pseudocandslpsol != NULL);
976  assert(covercomputed == (varincover != NULL));
977  assert(bestcand != NULL);
978  assert(bestcandmayround != NULL);
979  assert(bestcandroundup != NULL);
980 
981  bestfrac = SCIP_INVALID;
982 
983  for( c = 0; c < npseudocands; ++c )
984  {
985  SCIP_VAR* var;
986  SCIP_Bool mayround;
987  SCIP_Bool roundup;
988 
989  SCIP_Real frac;
990  SCIP_Real lpsol;
991  SCIP_Real nlpsol;
992  SCIP_Real lpsolfloor;
993  SCIP_Real nlpsolfloor;
994  SCIP_Real lpsolceil;
995  SCIP_Real nlpsolceil;
996  SCIP_Real boundval;
997  SCIP_Real floorval;
998  SCIP_Real ceilval;
999 
1000  var = pseudocands[c];
1001  lpsol = pseudocandslpsol[c];
1002  nlpsol = pseudocandsnlpsol[c];
1003 
1004  assert(SCIPvarGetUbLocal(var)-SCIPvarGetLbLocal(var) > 0.5);
1005  assert(SCIPisLE(scip, SCIPvarGetLbLocal(var), lpsol) && SCIPisLE(scip, lpsol, SCIPvarGetUbLocal(var)));
1006 
1007  /* since we are not solving the NLP after each fixing, the old NLP solution might be outside the propagated bounds */
1008  if( SCIPisLT(scip, nlpsol, SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpsol, SCIPvarGetUbLocal(var)) )
1009  continue;
1010 
1011  mayround = SCIPvarMayRoundDown(var) || SCIPvarMayRoundUp(var);
1012 
1013  /* if this candidate is trivially roundable, and we already know a candidate that is not, continue */
1014  if( mayround && !(*bestcandmayround) )
1015  continue;
1016 
1017  if( SCIPisFeasEQ(scip, lpsol, nlpsol) && SCIPisFeasIntegral(scip, lpsol))
1018  continue;
1019 
1020  lpsolfloor = SCIPfeasFloor(scip, lpsol);
1021  nlpsolfloor = SCIPfeasFloor(scip, nlpsol);
1022  lpsolceil = SCIPfeasCeil(scip, lpsol);
1023  nlpsolceil = SCIPfeasCeil(scip, nlpsol);
1024  floorval = MIN(lpsolfloor,nlpsolfloor);
1025  ceilval = MAX(lpsolceil,nlpsolceil);
1026  /* if both values are in the same interval, find out which integer is (in sum) the closer one, this will be the
1027  * new bound. The minima and maxima are necessary since one or both values with be integer
1028  */
1029  if( SCIPvarIsBinary(var) || ceilval-floorval < 1.5 )
1030  {
1031 
1032  frac = 0.33*(lpsol-floorval) + 0.67*(nlpsol-floorval);
1033  if( frac < 0.5 )
1034  {
1035  roundup = FALSE;
1036  boundval = MIN(lpsolfloor,nlpsolfloor);
1037  }
1038  else
1039  {
1040  roundup = TRUE;
1041  frac = 1.0-frac;
1042  boundval = MAX(nlpsolceil,lpsolceil);
1043  }
1044  }
1045  else
1046  {
1047  /* determine new bound in the middle of both relaxations, such that the NLP stays feasible */
1048  SCIP_Real midval;
1049  midval = (nlpsol+lpsol)/2.0;
1050  roundup = nlpsol > lpsol;
1051  frac = ABS(nlpsol-lpsol);
1052 
1053  if( roundup )
1054  boundval = SCIPfeasCeil(scip, midval);
1055  else
1056  boundval = SCIPfeasFloor(scip, midval);
1057 
1058  assert(roundup == SCIPisGT(scip, nlpsol, boundval));
1059  }
1060 
1061  /* penalize too small fractions */
1062  if( frac < 0.01 )
1063  frac += 10.0;
1064 
1065  /* prefer decisions on binary variables */
1066  if( !SCIPvarIsBinary(var) )
1067  frac *= 1000.0;
1068 
1069  /* prefer decisions on cover variables */
1070  if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
1071  frac *= 1000.0;
1072 
1073  /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
1074  if( frac < bestfrac || (*bestcandmayround && !mayround) )
1075  {
1076  *bestcand = c;
1077  bestfrac = frac;
1078  *bestcandmayround = FALSE;
1079  *bestcandroundup = roundup;
1080  *bestboundval = boundval;
1081  }
1082  assert(bestfrac < SCIP_INVALID);
1083  }
1084 
1085  if( *bestcandroundup )
1086  *bestboundval -= 0.5;
1087  else
1088  *bestboundval += 0.5;
1089 
1090  return SCIP_OKAY;
1091 }
1092 
1093 /** creates a new solution for the original problem by copying the solution of the subproblem */
1094 static
1096  SCIP* scip, /**< original SCIP data structure */
1097  SCIP* subscip, /**< SCIP structure of the subproblem */
1098  SCIP_HEUR* heur, /**< heuristic structure */
1099  SCIP_HASHMAP* varmap, /**< hash map for variables */
1100  SCIP_SOL* subsol, /**< solution of the subproblem */
1101  SCIP_Bool* success /**< used to store whether new solution was found or not */
1102  )
1103 {
1104  SCIP_VAR** vars; /* the original problem's variables */
1105  SCIP_VAR** subvars;
1106  SCIP_Real* subsolvals; /* solution values of the subproblem */
1107  SCIP_SOL* newsol; /* solution to be created for the original problem */
1108  int nvars; /* the original problem's number of variables */
1109  int i;
1110 
1111  assert(scip != NULL);
1112  assert(subscip != NULL);
1113  assert(subsol != NULL);
1114 
1115  /* get variables' data */
1116  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
1117 
1118  /* sub-SCIP may have more variables than the number of active (transformed) variables in the main SCIP
1119  * since constraint copying may have required the copy of variables that are fixed in the main SCIP
1120  */
1121  assert(nvars <= SCIPgetNOrigVars(subscip));
1122 
1123  SCIP_CALL( SCIPallocBufferArray(scip, &subsolvals, nvars) );
1124  SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) );
1125 
1126  for( i = 0; i < nvars; i++ )
1127  subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmap, vars[i]);
1128 
1129  /* copy the solution */
1130  SCIP_CALL( SCIPgetSolVals(subscip, subsol, nvars, subvars, subsolvals) );
1131 
1132  /* create new solution for the original problem */
1133  SCIP_CALL( SCIPcreateSol(scip, &newsol, heur) );
1134  SCIP_CALL( SCIPsetSolVals(scip, newsol, nvars, vars, subsolvals) );
1135 
1136  /* try to add new solution to scip and free it immediately */
1137  SCIP_CALL( SCIPtrySolFree(scip, &newsol, FALSE, TRUE, TRUE, TRUE, success) );
1138 
1139  SCIPfreeBufferArray(scip, &subvars);
1140  SCIPfreeBufferArray(scip, &subsolvals);
1141 
1142  return SCIP_OKAY;
1143 }
1144 
1145 
1146 /** solves subproblem and passes best feasible solution to original SCIP instance */
1147 static
1149  SCIP* scip, /**< SCIP data structure of the original problem */
1150  SCIP_HEUR* heur, /**< heuristic data structure */
1151  SCIP_VAR** covervars, /**< variables in the cover, should be fixed locally */
1152  int ncovervars, /**< number of variables in the cover */
1153  SCIP_Bool* success /**< pointer to store whether a solution was found */
1154  )
1155 {
1156  SCIP* subscip;
1157  SCIP_HASHMAP* varmap;
1158  SCIP_SOL** subsols;
1159  SCIP_Real timelimit;
1160  SCIP_Real memorylimit;
1161  SCIP_RETCODE retcode;
1162  int c;
1163  int nsubsols;
1164  SCIP_Bool valid;
1165 
1166  /* create subproblem */
1167  SCIP_CALL( SCIPcreate(&subscip) );
1168 
1169  /* create the variable mapping hash map */
1170  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * SCIPgetNVars(scip))) );
1171 
1172  *success = FALSE;
1173 
1174  /* copy original problem to subproblem; do not copy pricers */
1175  SCIP_CALL( SCIPcopy(scip, subscip, varmap, NULL, "undercoversub", FALSE, FALSE, TRUE, &valid) );
1176 
1177  /* assert that cover variables are fixed in source and target SCIP */
1178  for( c = 0; c < ncovervars; c++)
1179  {
1180  assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(covervars[c]), SCIPvarGetUbLocal(covervars[c])));
1181  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal((SCIP_VAR*) SCIPhashmapGetImage(varmap, covervars[c])),
1182  SCIPvarGetUbGlobal((SCIP_VAR*) SCIPhashmapGetImage(varmap, covervars[c]))));
1183  }
1184 
1185  /* set parameters for sub-SCIP */
1186 
1187  /* do not abort subproblem on CTRL-C */
1188  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1189 
1190  /* disable output to console */
1191  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1192 
1193  /* check whether there is enough time and memory left */
1194  timelimit = 0.0;
1195  memorylimit = 0.0;
1196  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
1197  if( !SCIPisInfinity(scip, timelimit))
1198  timelimit -= SCIPgetSolvingTime(scip);
1199  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
1200 
1201  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
1202  if( !SCIPisInfinity(scip, memorylimit) )
1203  {
1204  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
1205  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
1206  }
1207 
1208  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
1209  if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 )
1210  goto TERMINATE;
1211 
1212  /* set limits for the subproblem */
1213  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/stallnodes", (SCIP_Longint)100) );
1214  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", (SCIP_Longint)500) );
1215  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1216  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1217 
1218  /* forbid recursive call of heuristics and separators solving sub-SCIPs */
1219  SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1220 
1221  /* disable cutting plane separation */
1223 
1224  /* disable expensive presolving */
1226 
1227  /* use best estimate node selection */
1228  if( SCIPfindNodesel(subscip, "estimate") != NULL && !SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") )
1229  {
1230  SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) );
1231  }
1232 
1233  /* use inference branching */
1234  if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") )
1235  {
1236  SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) );
1237  }
1238 
1239  /* disable conflict analysis */
1240  if( !SCIPisParamFixed(subscip, "conflict/useprop") )
1241  {
1242  SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useprop", FALSE) );
1243  }
1244  if( !SCIPisParamFixed(subscip, "conflict/useinflp") )
1245  {
1246  SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useinflp", FALSE) );
1247  }
1248  if( !SCIPisParamFixed(subscip, "conflict/useboundlp") )
1249  {
1250  SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useboundlp", FALSE) );
1251  }
1252  if( !SCIPisParamFixed(subscip, "conflict/usesb") )
1253  {
1254  SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usesb", FALSE) );
1255  }
1256  if( !SCIPisParamFixed(subscip, "conflict/usepseudo") )
1257  {
1258  SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usepseudo", FALSE) );
1259  }
1260 
1261  if( SCIPgetNSols(scip) > 0 )
1262  {
1263  SCIP_Real upperbound;
1264  SCIP_Real cutoffbound;
1265  SCIP_Real minimprove;
1266 
1267  cutoffbound = SCIPinfinity(scip);
1268  assert( !SCIPisInfinity(scip,SCIPgetUpperbound(scip)) );
1269 
1270  upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip);
1271  minimprove = 0.01;
1272 
1273  if( !SCIPisInfinity(scip,-1.0*SCIPgetLowerbound(scip)) )
1274  {
1275  cutoffbound = (1-minimprove)*SCIPgetUpperbound(scip) + minimprove*SCIPgetLowerbound(scip);
1276  }
1277  else
1278  {
1279  if( SCIPgetUpperbound(scip) >= 0 )
1280  cutoffbound = (1 - minimprove)*SCIPgetUpperbound(scip);
1281  else
1282  cutoffbound = (1 + minimprove)*SCIPgetUpperbound(scip);
1283  }
1284  cutoffbound = MIN(upperbound, cutoffbound);
1285  SCIP_CALL( SCIPsetObjlimit(subscip, cutoffbound) );
1286  }
1287 
1288 #ifdef SCIP_DEBUG
1289  /* for debugging, enable sub-SCIP output */
1290  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) );
1291  SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 100000000) );
1292 #endif
1293 
1294  retcode = SCIPsolve(subscip);
1295 
1296  /* Errors in solving the subproblem should not kill the overall solving process
1297  * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
1298  */
1299  if( retcode != SCIP_OKAY )
1300  {
1301 #ifndef NDEBUG
1302  SCIP_CALL( retcode );
1303 #endif
1304  SCIPwarningMessage(scip, "Error while solving subproblem in "HEUR_NAME" heuristic; sub-SCIP terminated with code <%d>\n",retcode);
1305  }
1306 
1307  /* check, whether a solution was found;
1308  * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted
1309  */
1310  nsubsols = SCIPgetNSols(subscip);
1311  subsols = SCIPgetSols(subscip);
1312  for( c = 0; c < nsubsols && !(*success); ++c )
1313  {
1314  SCIP_CALL( createNewSol(scip, subscip, heur, varmap, subsols[c], success) );
1315  }
1316 
1317  TERMINATE:
1318  /* free sub-SCIP and hash map */
1319  SCIP_CALL( SCIPfree(&subscip) );
1320  SCIPhashmapFree(&varmap);
1321 
1322  return SCIP_OKAY;
1323 }
1324 
1325 /* ---------------- Callback methods of event handler ---------------- */
1326 
1327 /* exec the event handler
1328  *
1329  * We update the number of variables fixed in the cover
1330  */
1331 static
1332 SCIP_DECL_EVENTEXEC(eventExecNlpdiving)
1333 {
1334  SCIP_EVENTTYPE eventtype;
1335  SCIP_HEURDATA* heurdata;
1336  SCIP_VAR* var;
1337 
1338  SCIP_Real oldbound;
1339  SCIP_Real newbound;
1340  SCIP_Real otherbound;
1341 
1342  assert(eventhdlr != NULL);
1343  assert(eventdata != NULL);
1344  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
1345  assert(event != NULL);
1346 
1347  heurdata = (SCIP_HEURDATA*)eventdata;
1348  assert(heurdata != NULL);
1349  assert(0 <= heurdata->nfixedcovervars && heurdata->nfixedcovervars <= SCIPgetNVars(scip));
1350 
1351  oldbound = SCIPeventGetOldbound(event);
1352  newbound = SCIPeventGetNewbound(event);
1353  var = SCIPeventGetVar(event);
1354 
1355  eventtype = SCIPeventGetType(event);
1356  otherbound = (eventtype & SCIP_EVENTTYPE_LBCHANGED) ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
1357 
1358  switch( eventtype )
1359  {
1362  /* if cover variable is now fixed */
1363  if( SCIPisFeasEQ(scip, newbound, otherbound) )
1364  {
1365  assert(!SCIPisEQ(scip, oldbound, otherbound));
1366  ++(heurdata->nfixedcovervars);
1367  }
1368  break;
1371  /* if cover variable is now unfixed */
1372  if( SCIPisFeasEQ(scip, oldbound,otherbound) )
1373  {
1374  assert(!SCIPisEQ(scip, newbound, otherbound));
1375  --(heurdata->nfixedcovervars);
1376  }
1377  break;
1378  default:
1379  SCIPerrorMessage("invalid event type.\n");
1380  return SCIP_INVALIDDATA;
1381  }
1382  assert(0 <= heurdata->nfixedcovervars && heurdata->nfixedcovervars <= SCIPgetNVars(scip));
1383 
1384  /* SCIPdebugMessage("changed bound of cover variable <%s> from %f to %f (nfixedcovervars: %d).\n", SCIPvarGetName(var),
1385  oldbound, newbound, heurdata->nfixedcovervars); */
1386 
1387  return SCIP_OKAY;
1388 }
1389 
1390 
1391 /*
1392  * Callback methods
1393  */
1394 
1395 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
1396 static
1397 SCIP_DECL_HEURCOPY(heurCopyNlpdiving)
1398 { /*lint --e{715}*/
1399  assert(scip != NULL);
1400  assert(heur != NULL);
1401  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1402 
1403  /* call inclusion method of primal heuristic */
1405 
1406  return SCIP_OKAY;
1407 }
1408 
1409 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
1410 static
1411 SCIP_DECL_HEURFREE(heurFreeNlpdiving) /*lint --e{715}*/
1412 { /*lint --e{715}*/
1413  SCIP_HEURDATA* heurdata;
1414 
1415  assert(heur != NULL);
1416  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1417  assert(scip != NULL);
1418 
1419  /* free heuristic data */
1420  heurdata = SCIPheurGetData(heur);
1421  assert(heurdata != NULL);
1422  SCIPfreeMemory(scip, &heurdata);
1423  SCIPheurSetData(heur, NULL);
1424 
1425  return SCIP_OKAY;
1426 }
1427 
1428 
1429 /** initialization method of primal heuristic (called after problem was transformed) */
1430 static
1431 SCIP_DECL_HEURINIT(heurInitNlpdiving) /*lint --e{715}*/
1432 { /*lint --e{715}*/
1433  SCIP_HEURDATA* heurdata;
1434 
1435  assert(heur != NULL);
1436  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1437 
1438  /* get heuristic data */
1439  heurdata = SCIPheurGetData(heur);
1440  assert(heurdata != NULL);
1441 
1442  /* create working solution */
1443  SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
1444 
1445  /* initialize data */
1446  heurdata->nnlpiterations = 0;
1447  heurdata->nsuccess = 0;
1448  heurdata->nfixedcovervars = 0;
1449  SCIPstatistic(
1450  heurdata->nnlpsolves = 0;
1451  heurdata->nfailcutoff = 0;
1452  heurdata->nfaildepth = 0;
1453  heurdata->nfailnlperror = 0;
1454  );
1455 
1456  return SCIP_OKAY;
1457 }
1458 
1459 
1460 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
1461 static
1462 SCIP_DECL_HEUREXIT(heurExitNlpdiving) /*lint --e{715}*/
1463 { /*lint --e{715}*/
1464  SCIP_HEURDATA* heurdata;
1465 
1466  assert(heur != NULL);
1467  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1468 
1469  /* get heuristic data */
1470  heurdata = SCIPheurGetData(heur);
1471  assert(heurdata != NULL);
1472 
1473  /* free working solution */
1474  SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
1475 
1476  SCIPstatistic(
1477  if( strstr(SCIPgetProbName(scip), "_covering") == NULL && SCIPheurGetNCalls(heur) > 0 )
1478  {
1479  SCIPstatisticMessage("%-30s %5"SCIP_LONGINT_FORMAT" sols in %5"SCIP_LONGINT_FORMAT" runs, %6.1fs, %7d NLP iters in %5d NLP solves, %5.1f avg., %3d%% success %3d%% cutoff %3d%% depth %3d%% nlperror\n",
1481  heurdata->nnlpiterations, heurdata->nnlpsolves, heurdata->nnlpiterations/MAX(1.0,(SCIP_Real)heurdata->nnlpsolves),
1482  (100*heurdata->nsuccess) / (int)SCIPheurGetNCalls(heur), (100*heurdata->nfailcutoff) / (int)SCIPheurGetNCalls(heur), (100*heurdata->nfaildepth) / (int)SCIPheurGetNCalls(heur), (100*heurdata->nfailnlperror) / (int)SCIPheurGetNCalls(heur)
1483  );
1484  }
1485  );
1486 
1487  return SCIP_OKAY;
1488 }
1489 
1490 
1491 /** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
1492 static
1493 SCIP_DECL_HEURINITSOL(heurInitsolNlpdiving)
1494 { /*lint --e{715}*/
1495  SCIP_HEUR* nlpheur;
1496 
1497  if( !SCIPisNLPConstructed(scip) )
1498  return SCIP_OKAY;
1499 
1500  /* find NLP local search heuristic */
1501  nlpheur = SCIPfindHeur(scip, "subnlp");
1502 
1503  /* add global linear constraints to NLP relaxation */
1504  if( nlpheur != NULL )
1505  {
1507  }
1508 
1509  return SCIP_OKAY;
1510 }
1511 
1512 
1513 /** execution method of primal heuristic */
1514 static
1515 SCIP_DECL_HEUREXEC(heurExecNlpdiving)
1516 { /*lint --e{715}*/
1517  SCIP_HEURDATA* heurdata;
1518  SCIP_NLPSOLSTAT nlpsolstat;
1519  SCIP_LPSOLSTAT lpsolstat;
1520  SCIP_SOL* nlpstartsol;
1521  SCIP_SOL* bestsol;
1522  SCIP_VAR** nlpcands;
1523  SCIP_VAR** covervars;
1524  SCIP_Real* nlpcandssol;
1525  SCIP_Real* nlpcandsfrac;
1526  SCIP_Real* pseudocandslpsol;
1527  SCIP_Real* pseudocandsnlpsol;
1528  SCIP_HASHMAP* varincover;
1529  SCIP_Real searchubbound;
1530  SCIP_Real searchavgbound;
1531  SCIP_Real searchbound;
1532  SCIP_Real objval;
1533  SCIP_Real oldobjval;
1534  SCIP_Real fixquot;
1535  SCIP_Real bestboundval;
1536  SCIP_Bool bestcandmayround;
1537  SCIP_Bool bestcandroundup;
1538  SCIP_Bool nlperror;
1539  SCIP_Bool lperror;
1540  SCIP_Bool cutoff;
1541  SCIP_Bool backtracked;
1542  SCIP_Bool solvenlp;
1543  SCIP_Bool covercomputed;
1544  SCIP_Bool solvesubmip;
1545  SCIP_Longint ncalls;
1546  SCIP_Longint nsolsfound;
1547  int avgnnlpiterations;
1548  int maxnnlpiterations;
1549  int npseudocands;
1550  int nlpbranchcands;
1551  int ncovervars;
1552  int nnlpcands;
1553  int startnnlpcands;
1554  int depth;
1555  int maxdepth;
1556  int maxdivedepth;
1557  int divedepth;
1558  int lastnlpsolvedepth;
1559  int nfeasnlps;
1560  int bestcand;
1561  int origiterlim;
1562  int origfastfail;
1563  int c;
1564  int backtrackdepth; /* depth where to go when backtracking */
1565  SCIP_VAR* backtrackvar; /* (first) variable to fix differently in backtracking */
1566  SCIP_Real backtrackvarval; /* (fractional) value of backtrack variable */
1567  SCIP_Bool backtrackroundup; /* whether variable should be rounded up in backtracking */
1568 
1569  backtrackdepth = -1;
1570  backtrackvar = NULL;
1571  backtrackvarval = 0.0;
1572  backtrackroundup = FALSE;
1573  bestsol = NULL;
1574  pseudocandsnlpsol = NULL;
1575  pseudocandslpsol = NULL;
1576  covervars = NULL;
1577 
1578  assert(heur != NULL);
1579  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1580  assert(scip != NULL);
1581  assert(result != NULL);
1582  /* assert(SCIPhasCurrentNodeLP(scip)); */
1583 
1584  *result = SCIP_DIDNOTRUN;
1585 
1586  /* do not call heuristic of node was already detected to be infeasible */
1587  if( nodeinfeasible )
1588  return SCIP_OKAY;
1589 
1590  /* only call heuristic, if an NLP relaxation has been constructed */
1591  if( !SCIPisNLPConstructed(scip) || SCIPgetNNlpis(scip) == 0 )
1592  return SCIP_OKAY;
1593 
1594  /* only call heuristic, if the current node will not be cutoff, e.g., due to a (integer and NLP-)feasible LP solution */
1595  if( SCIPisFeasGE(scip, SCIPgetLocalLowerbound(scip), SCIPgetUpperbound(scip)) )
1596  return SCIP_OKAY;
1597 
1598  /* get heuristic's data */
1599  heurdata = SCIPheurGetData(heur);
1600  assert(heurdata != NULL);
1601 
1602  /* do not call heuristic, if it barely succeded */
1603  if( (SCIPheurGetNSolsFound(heur) + 1.0) / (SCIP_Real)(SCIPheurGetNCalls(heur) + 1.0) < heurdata->minsuccquot )
1604  return SCIP_OKAY;
1605 
1606  *result = SCIP_DELAYED;
1607 
1608  /* don't dive two times at the same node */
1609  if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
1610  return SCIP_OKAY;
1611 
1612  *result = SCIP_DIDNOTRUN;
1613 
1614  /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
1615  depth = SCIPgetDepth(scip);
1616  maxdepth = SCIPgetMaxDepth(scip);
1617  maxdepth = MAX(maxdepth, 30);
1618  if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
1619  return SCIP_OKAY;
1620 
1621  /* calculate the maximal number of NLP iterations until heuristic is aborted
1622  * maximal number is maxnlpiterabs plus a success-depending multiplier of maxnlpiterrel
1623  */
1624  ncalls = SCIPheurGetNCalls(heur);
1625  nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
1626  maxnnlpiterations = heurdata->maxnlpiterabs;
1627  maxnnlpiterations += (int)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxnlpiterrel);
1628 
1629  /* don't try to dive, if we took too many NLP iterations during diving */
1630  if( heurdata->nnlpiterations >= maxnnlpiterations )
1631  return SCIP_OKAY;
1632 
1633  /* allow at least a bit more than the so far average number of NLP iterations per dive */
1634  avgnnlpiterations = (int)(heurdata->nnlpiterations / MAX(ncalls, 1.0));
1635  maxnnlpiterations = (int)MAX((SCIP_Real) maxnnlpiterations, (SCIP_Real) heurdata->nnlpiterations + 1.2*avgnnlpiterations);
1636 
1637  /* don't try to dive, if there are no unfixed discrete variables */
1638  SCIP_CALL( SCIPgetPseudoBranchCands(scip, NULL, &npseudocands, NULL) );
1639  if( npseudocands == 0 )
1640  return SCIP_OKAY;
1641 
1642  *result = SCIP_DIDNOTFIND;
1643 
1644 #if 0 /* def SCIP_DEBUG */
1646 #endif
1647 
1648  /* set iteration limit */
1649  SCIP_CALL( SCIPgetNLPIntPar(scip, SCIP_NLPPAR_ITLIM, &origiterlim) );
1650  SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_ITLIM, maxnnlpiterations - heurdata->nnlpiterations) );
1651 
1652  /* set whether NLP solver should fail fast */
1653  SCIP_CALL( SCIPgetNLPIntPar(scip, SCIP_NLPPAR_FASTFAIL, &origfastfail) );
1654  SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_FASTFAIL, (int)heurdata->nlpfastfail) );
1655 
1656  /* set starting point to lp solution */
1658 
1659  /* solve NLP relaxation, if not solved already */
1660  nlpsolstat = SCIPgetNLPSolstat(scip);
1661  if( nlpsolstat > SCIP_NLPSOLSTAT_FEASIBLE )
1662  {
1663  SCIP_NLPSTATISTICS* nlpstatistics;
1664 
1665  SCIP_CALL( SCIPsolveNLP(scip) );
1666  SCIPstatistic( ++heurdata->nnlpsolves );
1667 
1668  /* update iteration count */
1670  {
1671  SCIP_CALL( SCIPnlpStatisticsCreate(&nlpstatistics) );
1672  SCIP_CALL( SCIPgetNLPStatistics(scip, nlpstatistics) );
1673  heurdata->nnlpiterations += SCIPnlpStatisticsGetNIterations(nlpstatistics);
1674  SCIPnlpStatisticsFree(&nlpstatistics);
1675  }
1676 
1677  nlpsolstat = SCIPgetNLPSolstat(scip);
1678 
1679  /* give up, if no feasible solution found */
1680  if( nlpsolstat >= SCIP_NLPSOLSTAT_LOCINFEASIBLE )
1681  {
1682  SCIPdebugMessage("initial NLP infeasible or not solvable --> stop\n");
1683 
1685  {
1686  SCIPstatistic( heurdata->nfailcutoff++ );
1687  }
1688  else
1689  {
1690  SCIPstatistic( heurdata->nfailnlperror++ );
1691  }
1692 
1693  /* reset changed NLP parameters */
1694  SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_ITLIM, origiterlim) );
1695  SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_FASTFAIL, origfastfail) );
1696 
1697  return SCIP_OKAY;
1698  }
1699  }
1700 
1701  /* get NLP solution */
1702  SCIP_CALL( SCIPlinkNLPSol(scip, heurdata->sol) );
1703 
1704  /* get fractional variables that should be integral */
1705  SCIP_CALL( getNLPFracVars(scip, heurdata, &nlpcands, &nlpcandssol, &nlpcandsfrac, &nnlpcands) );
1706  assert(nnlpcands <= npseudocands);
1707 
1708  /* get LP candidates if LP solution is optimal */
1709  lpsolstat = SCIPgetLPSolstat(scip);
1710  if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
1711  nlpbranchcands = SCIPgetNLPBranchCands(scip);
1712  else
1713  nlpbranchcands = 0;
1714 
1715  /* don't try to dive, if there are no fractional variables */
1716  if( nnlpcands == 0 )
1717  {
1718  SCIP_Bool success;
1719 
1720  /* check, if solution was feasible and good enough */
1721 #ifdef SCIP_DEBUG
1722  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, TRUE, FALSE, FALSE, TRUE, &success) );
1723 #else
1724  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, TRUE, &success) );
1725 #endif
1726  if( success )
1727  {
1728  SCIPdebugMessage(" -> solution of first NLP was integral, feasible, and good enough\n");
1729  *result = SCIP_FOUNDSOL;
1730  }
1731 
1732  /* reset changed NLP parameters */
1733  SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_ITLIM, origiterlim) );
1734  SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_FASTFAIL, origfastfail) );
1735 
1736  return SCIP_OKAY;
1737  }
1738 
1739  nlpstartsol = NULL;
1740  assert(nlpcandsfrac != NULL);
1741  assert(nlpcands != NULL);
1742  assert(nlpcandssol != NULL);
1743 
1744  /* save solution of first NLP, if we may use it later */
1745  if( heurdata->nlpstart != 'n' )
1746  {
1747  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpstartsol, heur) );
1748  SCIP_CALL( SCIPunlinkSol(scip, nlpstartsol) );
1749  }
1750 
1751  /* calculate the objective search bound */
1752  if( SCIPgetNSolsFound(scip) == 0 )
1753  {
1754  if( heurdata->maxdiveubquotnosol > 0.0 )
1755  searchubbound = SCIPgetLowerbound(scip)
1756  + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
1757  else
1758  searchubbound = SCIPinfinity(scip);
1759  if( heurdata->maxdiveavgquotnosol > 0.0 )
1760  searchavgbound = SCIPgetLowerbound(scip)
1761  + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
1762  else
1763  searchavgbound = SCIPinfinity(scip);
1764  }
1765  else
1766  {
1767  if( heurdata->maxdiveubquot > 0.0 )
1768  searchubbound = SCIPgetLowerbound(scip)
1769  + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
1770  else
1771  searchubbound = SCIPinfinity(scip);
1772  if( heurdata->maxdiveavgquot > 0.0 )
1773  searchavgbound = SCIPgetLowerbound(scip)
1774  + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
1775  else
1776  searchavgbound = SCIPinfinity(scip);
1777  }
1778  searchbound = MIN(searchubbound, searchavgbound);
1779  if( SCIPisObjIntegral(scip) )
1780  searchbound = SCIPceil(scip, searchbound);
1781 
1782  /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
1783  maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
1784  maxdivedepth = MIN(maxdivedepth, maxdepth);
1785  maxdivedepth *= 10;
1786 
1787  covercomputed = FALSE;
1788  varincover = NULL;
1789 
1790  /* compute cover, if required */
1791  if( heurdata->prefercover || heurdata->solvesubmip )
1792  {
1793  SCIP_Real timelimit;
1794  SCIP_Real memorylimit;
1795 
1796  /* get limits */
1797  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
1798  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
1799  if( !SCIPisInfinity(scip, timelimit) )
1800  timelimit -= SCIPgetSolvingTime(scip);
1801 
1802  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
1803  if( !SCIPisInfinity(scip, memorylimit) )
1804  {
1805  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
1806  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
1807  }
1808 
1809  /* compute cover */
1810  ncovervars = -1;
1811  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, SCIPgetNVars(scip)) );
1812  if( memorylimit > 2.0*SCIPgetMemExternEstim(scip)/1048576.0 && timelimit > 0.0 )
1813  {
1814  SCIP_CALL( SCIPcomputeCoverUndercover(scip, &ncovervars, covervars, timelimit, memorylimit, SCIPinfinity(scip), FALSE, FALSE, FALSE, 'u', &covercomputed) );
1815  }
1816 
1817  if( covercomputed )
1818  {
1819  /* a cover can be empty, if the cover computation reveals that all nonlinear constraints are linear w.r.t. current variable fixations */
1820  assert(ncovervars >= 0);
1821 
1822  /* create hash map */
1823  SCIP_CALL( SCIPhashmapCreate(&varincover, SCIPblkmem(scip), SCIPcalcHashtableSize(2 * ncovervars)) );
1824 
1825  /* process variables in the cover */
1826  for( c = 0; c < ncovervars; c++ )
1827  {
1828  /* insert variable into hash map */
1829  if( SCIPvarGetType(covervars[c]) < SCIP_VARTYPE_IMPLINT )
1830  {
1831  assert(!SCIPhashmapExists(varincover, covervars[c]));
1832  SCIP_CALL( SCIPhashmapInsert(varincover, covervars[c], (void*) (size_t) (c+1)) );
1833  }
1834 
1835  /* catch bound change events of cover variables */
1836  assert(heurdata->eventhdlr != NULL);
1837  SCIP_CALL( SCIPcatchVarEvent(scip, covervars[c], SCIP_EVENTTYPE_BOUNDCHANGED, heurdata->eventhdlr,
1838  (SCIP_EVENTDATA*) heurdata, NULL) );
1839  assert(!SCIPisFeasEQ(scip, SCIPvarGetLbLocal(covervars[c]), SCIPvarGetUbLocal(covervars[c])));
1840  }
1841  }
1842  }
1843  else
1844  {
1845  covervars = NULL;
1846  ncovervars = 0;
1847  }
1848 
1849  /* start diving */
1850  SCIP_CALL( SCIPstartProbing(scip) );
1851 
1852  /* enables collection of variable statistics during probing */
1853  SCIPenableVarHistory(scip);
1854 
1855  /* get NLP objective value*/
1856  objval = SCIPgetNLPObjval(scip);
1857 
1858  SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing nlpdiving heuristic: depth=%d, %d fractionals, dualbound=%g, searchbound=%g\n",
1859  SCIPgetNNodes(scip), SCIPgetDepth(scip), nnlpcands, SCIPgetDualbound(scip), SCIPretransformObj(scip, searchbound));
1860 
1861  /* store a copy of the best solution, if guided diving should be used */
1862  if( heurdata->varselrule == 'g' )
1863  {
1864  /* don't dive, if no feasible solutions exist */
1865  if( SCIPgetNSols(scip) == 0 )
1866  return SCIP_OKAY;
1867 
1868  /* get best solution that should guide the search; if this solution lives in the original variable space,
1869  * we cannot use it since it might violate the global bounds of the current problem
1870  */
1871  if( SCIPsolIsOriginal(SCIPgetBestSol(scip)) )
1872  return SCIP_OKAY;
1873 
1874  SCIP_CALL( SCIPcreateSolCopy(scip, &bestsol, SCIPgetBestSol(scip)) );
1875  }
1876 
1877  /* if double diving should be used, create arrays to hold to entire LP and NLP solution */
1878  if( heurdata->varselrule == 'd' )
1879  {
1880  SCIP_CALL( SCIPallocBufferArray(scip, &pseudocandslpsol, npseudocands) );
1881  SCIP_CALL( SCIPallocBufferArray(scip, &pseudocandsnlpsol, npseudocands) );
1882  }
1883 
1884  /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but
1885  * - if possible, we dive at least with the depth 10
1886  * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
1887  */
1888  nlperror = FALSE;
1889  lperror = FALSE;
1890  cutoff = FALSE;
1891  divedepth = 0;
1892  lastnlpsolvedepth = 0;
1893  backtracked = FALSE; /* whether we are in backtracking */
1894  fixquot = heurdata->fixquot;
1895  nfeasnlps = 1;
1896  startnnlpcands = nnlpcands;
1897  solvesubmip = heurdata->solvesubmip;
1898 
1899  while( !nlperror && !cutoff && (nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE || nlpsolstat == SCIP_NLPSOLSTAT_UNKNOWN) && nnlpcands > 0
1900  && (nfeasnlps < heurdata->maxfeasnlps
1901  || nnlpcands <= startnnlpcands - divedepth/2
1902  || (nfeasnlps < maxdivedepth && heurdata->nnlpiterations < maxnnlpiterations && objval < searchbound))
1903  && !SCIPisStopped(scip) )
1904  {
1905  SCIP_VAR* var;
1906  SCIP_Bool updatepscost;
1907 
1908  SCIP_CALL( SCIPnewProbingNode(scip) );
1909  divedepth++;
1910 
1911  bestcand = -1;
1912  bestcandmayround = TRUE;
1913  bestcandroundup = FALSE;
1914  bestboundval = SCIP_INVALID;
1915  updatepscost = TRUE;
1916  var = NULL;
1917 
1918  /* find best candidate variable */
1919  switch( heurdata->varselrule )
1920  {
1921  case 'c':
1922  SCIP_CALL( chooseCoefVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
1923  &bestcand, &bestcandmayround, &bestcandroundup) );
1924  if( bestcand >= 0 )
1925  {
1926  var = nlpcands[bestcand];
1927  bestboundval = nlpcandssol[bestcand];
1928  }
1929  break;
1930  case 'v':
1931  SCIP_CALL( chooseVeclenVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
1932  &bestcand, &bestcandmayround, &bestcandroundup) );
1933  if( bestcand >= 0 )
1934  {
1935  var = nlpcands[bestcand];
1936  bestboundval = nlpcandssol[bestcand];
1937  }
1938  break;
1939  case 'p':
1940  SCIP_CALL( choosePscostVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
1941  &bestcand, &bestcandmayround, &bestcandroundup) );
1942  if( bestcand >= 0 )
1943  {
1944  var = nlpcands[bestcand];
1945  bestboundval = nlpcandssol[bestcand];
1946  }
1947  break;
1948  case 'g':
1949  SCIP_CALL( chooseGuidedVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, bestsol, varincover, covercomputed,
1950  &bestcand, &bestcandmayround, &bestcandroundup) );
1951  if( bestcand >= 0 )
1952  {
1953  var = nlpcands[bestcand];
1954  bestboundval = nlpcandssol[bestcand];
1955  }
1956  break;
1957  case 'd':
1958  /* double diving only works if we have both relaxations at hand, otherwise we fall back to fractional diving */
1959  if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
1960  {
1961  SCIP_VAR** pseudocands;
1962 
1963  SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, &npseudocands, NULL) );
1964  assert(backtrackdepth > 0 || nnlpcands <= npseudocands);
1965  assert(SCIPgetNLPBranchCands(scip) <= npseudocands);
1966  SCIP_CALL( SCIPgetSolVals(scip, NULL, npseudocands, pseudocands, pseudocandslpsol) );
1967  SCIP_CALL( SCIPgetSolVals(scip, heurdata->sol, npseudocands, pseudocands, pseudocandsnlpsol) );
1968  SCIP_CALL( chooseDoubleVar(scip, heurdata, pseudocands, pseudocandsnlpsol, pseudocandslpsol, npseudocands,
1969  varincover, covercomputed, &bestcand, &bestboundval, &bestcandmayround, &bestcandroundup) );
1970  if( bestcand >= 0 )
1971  var = pseudocands[bestcand];
1972  break;
1973  }
1974  else
1975  updatepscost = FALSE;
1976  /*lint -fallthrough*/
1977  case 'f':
1978  SCIP_CALL( chooseFracVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
1979  &bestcand, &bestcandmayround, &bestcandroundup) );
1980  if( bestcand >= 0 )
1981  {
1982  var = nlpcands[bestcand];
1983  bestboundval = nlpcandssol[bestcand];
1984  }
1985  break;
1986  default:
1987  SCIPerrorMessage("invalid variable selection rule\n");
1988  return SCIP_INVALIDDATA;
1989  }
1990 
1991  /* if all candidates are roundable, try to round the solution
1992  * if var == NULL (i.e., bestcand == -1), then all solution candidates are outside bounds
1993  * this should only happen if they are slightly outside bounds (i.e., still within feastol, relative tolerance),
1994  * but far enough out to be considered as fractional (within feastol, but using absolute tolerance)
1995  * in this case, we also try our luck with rounding
1996  */
1997  if( (var == NULL || bestcandmayround) && backtrackdepth == -1 )
1998  {
1999  SCIP_Bool success;
2000 
2001  /* create solution from diving NLP and try to round it */
2002  SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
2003 
2004  if( success )
2005  {
2006  SCIPdebugMessage("nlpdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
2007 
2008  /* try to add solution to SCIP */
2009 #ifdef SCIP_DEBUG
2010  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, TRUE, FALSE, FALSE, TRUE, &success) );
2011 #else
2012  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, TRUE, &success) );
2013 #endif
2014 
2015  /* check, if solution was feasible and good enough */
2016  if( success )
2017  {
2018  SCIPdebugMessage(" -> solution was feasible and good enough\n");
2019  *result = SCIP_FOUNDSOL;
2020  }
2021  }
2022  }
2023 
2024  /* if all variables have been found to be essentially integral (even though there is some numerical doubt, see comment above), then stop */
2025  if( var == NULL )
2026  break;
2027 
2028  do
2029  {
2030  SCIP_Real frac;
2031  frac = SCIP_INVALID;
2032 
2033  if( backtracked && backtrackdepth > 0 )
2034  {
2035  assert(backtrackvar != NULL);
2036 
2037  /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
2038  * occured or variable was fixed by propagation while backtracking => Abort diving!
2039  */
2040  if( SCIPvarGetLbLocal(backtrackvar) >= SCIPvarGetUbLocal(backtrackvar) - 0.5 )
2041  {
2042  SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
2043  SCIPvarGetName(backtrackvar), SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar), backtrackvarval);
2044  cutoff = TRUE;
2045  break;
2046  }
2047  if( SCIPisFeasLT(scip, backtrackvarval, SCIPvarGetLbLocal(backtrackvar)) || SCIPisFeasGT(scip, backtrackvarval, SCIPvarGetUbLocal(backtrackvar)) )
2048  {
2049  SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
2050  SCIPvarGetName(backtrackvar), SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar), backtrackvarval);
2051  assert(backtracked);
2052  break;
2053  }
2054 
2055  /* round backtrack variable up or down */
2056  if( backtrackroundup )
2057  {
2058  SCIPdebugMessage(" dive %d/%d, NLP iter %d/%d: var <%s>, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
2059  divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
2060  SCIPvarGetName(backtrackvar), backtrackvarval, SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar),
2061  SCIPfeasCeil(scip, backtrackvarval), SCIPvarGetUbLocal(backtrackvar));
2062  SCIP_CALL( SCIPchgVarLbProbing(scip, backtrackvar, SCIPfeasCeil(scip, backtrackvarval)) );
2063  }
2064  else
2065  {
2066  SCIPdebugMessage(" dive %d/%d, NLP iter %d/%d: var <%s>, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
2067  divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
2068  SCIPvarGetName(backtrackvar), backtrackvarval, SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar),
2069  SCIPvarGetLbLocal(backtrackvar), SCIPfeasFloor(scip, backtrackvarval));
2070  SCIP_CALL( SCIPchgVarUbProbing(scip, backtrackvar, SCIPfeasFloor(scip, backtrackvarval)) );
2071  }
2072 
2073  /* forget about backtrack variable */
2074  backtrackdepth = -1;
2075 
2076  /* for pseudo cost computation */
2077  bestcandroundup = backtrackroundup;
2078  frac = SCIPfrac(scip, backtrackvarval);
2079  var = backtrackvar;
2080  }
2081  else
2082  {
2083  assert(var != NULL);
2084 
2085  /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
2086  * occured or variable was fixed by propagation while backtracking => Abort diving!
2087  */
2088  if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
2089  {
2090  SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
2091  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestboundval);
2092  cutoff = TRUE;
2093  break;
2094  }
2095  if( SCIPisFeasLT(scip, bestboundval, SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, bestboundval, SCIPvarGetUbLocal(var)) )
2096  {
2097  SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
2098  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestboundval);
2099  assert(backtracked);
2100  break;
2101  }
2102 
2103  /* apply rounding of best candidate */
2104  if( bestcandroundup == !backtracked )
2105  {
2106  /* round variable up */
2107  SCIPdebugMessage(" dive %d/%d, NLP iter %d/%d: var <%s>, round=%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
2108  divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
2109  SCIPvarGetName(var), bestcandmayround,
2110  bestboundval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
2111  SCIPfeasCeil(scip, bestboundval), SCIPvarGetUbLocal(var));
2112  SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, bestboundval)) );
2113 
2114  /* remember variable for backtracking, if we have none yet (e.g., we are just after NLP solve) or we are half way to the next NLP solve */
2115  if( backtrackdepth == -1 || (divedepth - lastnlpsolvedepth == (int)(MIN(fixquot * nnlpcands, nlpbranchcands)/2.0)) )
2116  {
2117  backtrackdepth = divedepth;
2118  backtrackvar = var;
2119  backtrackvarval = bestboundval;
2120  backtrackroundup = FALSE;
2121  }
2122  }
2123  else
2124  {
2125  /* round variable down */
2126  SCIPdebugMessage(" dive %d/%d, NLP iter %d/%d: var <%s>, round=%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
2127  divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
2128  SCIPvarGetName(var), bestcandmayround,
2129  bestboundval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
2130  SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, bestboundval));
2131  SCIP_CALL( SCIPchgVarUbProbing(scip, var, SCIPfeasFloor(scip, bestboundval)) );
2132 
2133  /* remember variable for backtracking, if we have none yet (e.g., we are just after NLP solve) or we are half way to the next NLP solve */
2134  if( backtrackdepth == -1 || (divedepth - lastnlpsolvedepth == (int)(MIN(fixquot * nnlpcands, nlpbranchcands)/2.0)) )
2135  {
2136  backtrackdepth = divedepth;
2137  backtrackvar = var;
2138  backtrackvarval = bestboundval;
2139  backtrackroundup = TRUE;
2140  }
2141  }
2142 
2143  /* for pseudo-cost computation */
2144  if( updatepscost && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
2145  {
2146  if( heurdata->varselrule == 'd' )
2147  {
2148  assert(pseudocandsnlpsol != NULL);
2149  assert(0 <= bestcand && bestcand < npseudocands);
2150  frac = SCIPfrac(scip, pseudocandsnlpsol[bestcand]);
2151  }
2152  else
2153  frac = nlpcandsfrac[bestcand];
2154  }
2155  }
2156 
2157  /* apply domain propagation */
2158  SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
2159  if( cutoff )
2160  {
2161  SCIPdebugMessage(" *** cutoff detected in propagation at level %d\n", SCIPgetProbingDepth(scip));
2162  }
2163 
2164  /* if all variables in the cover are fixed or there is no fractional variable in the cover,
2165  * then solve a sub-MIP
2166  */
2167  if( !cutoff && solvesubmip && covercomputed &&
2168  (heurdata->nfixedcovervars == ncovervars ||
2169  (heurdata->nfixedcovervars >= (ncovervars+1)/2 && !SCIPhashmapExists(varincover, var))) )
2170  {
2171  int probingdepth;
2172 
2173  solvesubmip = FALSE;
2174  probingdepth = SCIPgetProbingDepth(scip);
2175  assert(probingdepth >= 1);
2176  assert(covervars != NULL);
2177 
2178  if( heurdata->nfixedcovervars != ncovervars )
2179  {
2180  /* fix all remaining cover variables */
2181  for( c = 0; c < ncovervars && !cutoff ; c++ )
2182  {
2183  SCIP_Real lb;
2184  SCIP_Real ub;
2185  lb = SCIPvarGetLbLocal(covervars[c]);
2186  ub = SCIPvarGetUbLocal(covervars[c]);
2187  if( !SCIPisFeasEQ(scip, lb, ub) )
2188  {
2189  SCIP_Real nlpsolval;
2190 
2191  /* adopt lpsolval w.r.t. intermediate bound changes by propagation */
2192  nlpsolval = SCIPvarGetNLPSol(covervars[c]);
2193  nlpsolval = MIN(nlpsolval,ub);
2194  nlpsolval = MAX(nlpsolval,lb);
2195  assert(SCIPvarGetType(covervars[c]) == SCIP_VARTYPE_CONTINUOUS || SCIPisFeasIntegral(scip, nlpsolval));
2196 
2197  /* fix and propagate */
2198  SCIP_CALL( SCIPnewProbingNode(scip) );
2199  assert(SCIPisLbBetter(scip, nlpsolval, lb, ub) || SCIPisUbBetter(scip, nlpsolval, lb, ub));
2200 
2201  if( SCIPisLbBetter(scip, nlpsolval, lb, ub) )
2202  {
2203  SCIP_CALL( SCIPchgVarLbProbing(scip, covervars[c], nlpsolval) );
2204  }
2205  if( SCIPisUbBetter(scip, nlpsolval, lb, ub) )
2206  {
2207  SCIP_CALL( SCIPchgVarUbProbing(scip, covervars[c], nlpsolval) );
2208  }
2209 
2210  SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
2211  }
2212  }
2213  }
2214 
2215  /* solve sub-MIP or return to standard diving */
2216  if( cutoff )
2217  {
2218  SCIP_CALL( SCIPbacktrackProbing(scip, probingdepth) );
2219  }
2220  else
2221  {
2222  SCIP_Bool success;
2223  success = FALSE;
2224 
2225  SCIP_CALL( solveSubMIP(scip, heur, covervars, ncovervars, &success));
2226  if( success )
2227  *result = SCIP_FOUNDSOL;
2228  backtracked = TRUE; /* to avoid backtracking */
2229  nnlpcands = 0; /* to force termination */
2230  cutoff = TRUE;
2231  }
2232  }
2233 
2234  /* resolve the diving LP */
2235  if( !cutoff && !lperror && (heurdata->lp || heurdata->varselrule == 'd')
2237  {
2238  SCIP_CALL( SCIPsolveProbingLP(scip, 100, &lperror, &cutoff) );
2239 
2240  /* get LP solution status, objective value, and fractional variables, that should be integral */
2241  lpsolstat = SCIPgetLPSolstat(scip);
2242  assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE &&
2243  (lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || SCIPisLT(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)))));
2244 
2245  if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
2246  {
2247  nlpbranchcands = SCIPgetNLPBranchCands(scip);
2248 
2249  /* get new objective value */
2250  oldobjval = objval;
2251  objval = SCIPgetLPObjval(scip);
2252 
2253  /* update pseudo cost values */
2254  if( updatepscost && SCIPisGT(scip, objval, oldobjval) )
2255  {
2256  assert(frac != SCIP_INVALID); /*lint !e777*/
2257  if( bestcandroundup )
2258  {
2259  SCIP_CALL( SCIPupdateVarPseudocost(scip, var, 1.0-frac, objval - oldobjval, 1.0) );
2260  }
2261  else
2262  {
2263  SCIP_CALL( SCIPupdateVarPseudocost(scip, var, 0.0-frac, objval - oldobjval, 1.0) );
2264  }
2265  }
2266  }
2267  else
2268  {
2269  nlpbranchcands = 0;
2270  }
2271 
2272  if( cutoff )
2273  {
2274  SCIPdebugMessage(" *** cutoff detected in LP solving at level %d, lpsolstat = %d\n", SCIPgetProbingDepth(scip), lpsolstat);
2275  }
2276  }
2277  else
2278  lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
2279 
2280  /* check whether we want to solve the NLP, which is the case if
2281  * - we are in backtracking, or
2282  * - we have (actively) fixed/rounded fixquot*nnlpcands variables
2283  * - all fractional variables were rounded/fixed (due to fixing and domain propagation)
2284  */
2285  solvenlp = backtracked;
2286  if( !solvenlp && !cutoff )
2287  {
2288  solvenlp = (lastnlpsolvedepth < divedepth - fixquot * nnlpcands);
2289  if( !solvenlp )
2290  {
2291  /* check if fractional NLP variables are left (some may have been fixed by propagation) */
2292  for( c = 0; c < nnlpcands; ++c )
2293  {
2294  var = nlpcands[c];
2295  if( SCIPisLT(scip, nlpcandssol[c], SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpcandssol[c], SCIPvarGetUbLocal(var)) )
2296  continue;
2297  else
2298  break;
2299  }
2300  if( c == nnlpcands )
2301  solvenlp = TRUE;
2302  }
2303  }
2304 
2305  nlpsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
2306 
2307  /* resolve the diving NLP */
2308  if( !cutoff && solvenlp )
2309  {
2310  SCIP_NLPTERMSTAT termstat;
2311  SCIP_NLPSTATISTICS* nlpstatistics;
2312 
2313  /* set iteration limit, allow at least MINNLPITER many iterations */
2314  SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_ITLIM, MAX(maxnnlpiterations - heurdata->nnlpiterations, MINNLPITER)) );
2315 
2316  /* set start solution, if we are in backtracking (previous NLP solve was infeasible) */
2317  if( heurdata->nlpstart != 'n' && backtracked )
2318  {
2319  assert(nlpstartsol != NULL);
2320 
2321  SCIPdebugMessage("setting NLP initial guess\n");
2322 
2323  SCIP_CALL( SCIPsetNLPInitialGuessSol(scip, nlpstartsol) );
2324  }
2325 
2326  SCIP_CALL( SCIPsolveNLP(scip) );
2327  SCIPstatistic( ++heurdata->nnlpsolves );
2328 
2329  termstat = SCIPgetNLPTermstat(scip);
2330  if( termstat >= SCIP_NLPTERMSTAT_NUMERR )
2331  {
2332  SCIPwarningMessage(scip, "Error while solving NLP in nlpdiving heuristic; NLP solve terminated with code <%d>\n", termstat);
2333  nlperror = TRUE;
2334  break;
2335  }
2336 
2337  /* update iteration count */
2338  SCIP_CALL( SCIPnlpStatisticsCreate(&nlpstatistics) );
2339  SCIP_CALL( SCIPgetNLPStatistics(scip, nlpstatistics) );
2340  heurdata->nnlpiterations += SCIPnlpStatisticsGetNIterations(nlpstatistics);
2341  SCIPnlpStatisticsFree(&nlpstatistics);
2342 
2343  /* get NLP solution status, objective value, and fractional variables, that should be integral */
2344  nlpsolstat = SCIPgetNLPSolstat(scip);
2345  cutoff = (nlpsolstat > SCIP_NLPSOLSTAT_FEASIBLE);
2346 
2347  if( cutoff )
2348  {
2349  SCIPdebugMessage(" *** cutoff detected in NLP solving at level %d, nlpsolstat: %d\n", SCIPgetProbingDepth(scip), nlpsolstat);
2350  }
2351  else
2352  {
2353  SCIP_CALL( SCIPlinkNLPSol(scip, heurdata->sol) );
2354 
2355  /* remember that we have solve NLP on this depth successfully */
2356  lastnlpsolvedepth = divedepth;
2357  /* forget previous backtrack variable, we will never go back to a depth before the current one */
2358  backtrackdepth = -1;
2359  /* store NLP solution for warmstarting, if nlpstart is 'f' */
2360  if( heurdata->nlpstart == 'f' )
2361  {
2362  assert(nlpstartsol != NULL);
2363 
2364  /* copy NLP solution values into nlpstartsol, is there a better way to do this???? */
2365  SCIP_CALL( SCIPlinkNLPSol(scip, nlpstartsol) );
2366  SCIP_CALL( SCIPunlinkSol(scip, nlpstartsol) );
2367  }
2368  /* increase counter on number of NLP solves with feasible solution */
2369  ++nfeasnlps;
2370  }
2371  }
2372 
2373  /* perform backtracking if a cutoff was detected */
2374  if( cutoff && !backtracked && heurdata->backtrack )
2375  {
2376  if( backtrackdepth == -1 )
2377  {
2378  /* backtrack one step */
2379  SCIPdebugMessage(" *** cutoff detected at level %d - backtracking one step\n", SCIPgetProbingDepth(scip));
2381  SCIP_CALL( SCIPnewProbingNode(scip) );
2382  }
2383  else
2384  {
2385  /* if we have a stored a depth for backtracking, go there */
2386  SCIPdebugMessage(" *** cutoff detected at level %d - backtracking to depth %d\n", SCIPgetProbingDepth(scip), backtrackdepth);
2387  SCIP_CALL( SCIPbacktrackProbing(scip, backtrackdepth-1) );
2388  SCIP_CALL( SCIPnewProbingNode(scip) );
2389  divedepth = backtrackdepth;
2390 
2391  /* do not update pseudocosts if backtracking by more than one level */
2392  updatepscost = FALSE;
2393 
2394  /* in case, we are feasible after backtracking, fix less variables at once in continuing diving
2395  * @todo should we remember the fixquot in heurdata for the next run?
2396  */
2397  fixquot *= 0.5;
2398  }
2399  /* remember that we are backtracking now */
2400  backtracked = TRUE;
2401  }
2402  else
2403  backtracked = FALSE;
2404  }
2405  while( backtracked );
2406 
2407  if( !nlperror && !cutoff && nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2408  {
2409  /* get new fractional variables */
2410  SCIP_CALL( getNLPFracVars(scip, heurdata, &nlpcands, &nlpcandssol, &nlpcandsfrac, &nnlpcands) );
2411  }
2412  SCIPdebugMessage(" -> nlpsolstat=%d, objval=%g/%g, nfrac nlp=%d lp=%d\n", nlpsolstat, objval, searchbound, nnlpcands, nlpbranchcands);
2413  }
2414 
2415  /*lint --e{774}*/
2416  SCIPdebugMessage("NLP nlpdiving ABORT due to ");
2417  if( nlperror || (nlpsolstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE && nlpsolstat != SCIP_NLPSOLSTAT_UNKNOWN) )
2418  {
2419  SCIPdebugPrintf("NLP bad status - nlperror: %ud nlpsolstat: %d \n", nlperror, nlpsolstat);
2420  SCIPstatistic( heurdata->nfailnlperror++ );
2421  }
2422  else if( SCIPisStopped(scip) || cutoff )
2423  {
2424  SCIPdebugPrintf("LIMIT hit - stop: %ud cutoff: %ud \n", SCIPisStopped(scip), cutoff);
2425  SCIPstatistic( heurdata->nfailcutoff++ );
2426  }
2427  else if(! (divedepth < 10
2428  || nnlpcands <= startnnlpcands - divedepth/2
2429  || (divedepth < maxdivedepth && heurdata->nnlpiterations < maxnnlpiterations && objval < searchbound) ) )
2430  {
2431  SCIPdebugPrintf("TOO DEEP - divedepth: %4d cands halfed: %d ltmaxdepth: %d ltmaxiter: %d bound: %d\n", divedepth,
2432  (nnlpcands > startnnlpcands - divedepth/2), (divedepth >= maxdivedepth), (heurdata->nnlpiterations >= maxnnlpiterations),
2433  (objval >= searchbound));
2434  SCIPstatistic( heurdata->nfaildepth++ );
2435  }
2436  else if( nnlpcands == 0 && !nlperror && !cutoff && nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2437  {
2438  SCIPdebugPrintf("SUCCESS\n");
2439  }
2440  else
2441  {
2442  SCIPdebugPrintf("UNKNOWN, very mysterical reason\n"); /* see also special case var == NULL (bestcand == -1) after choose*Var above */
2443  }
2444 
2445  /* check if a solution has been found */
2446  if( nnlpcands == 0 && !nlperror && !cutoff && nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE )
2447  {
2448  SCIP_Bool success;
2449 
2450  /* create solution from diving NLP */
2451  SCIPdebugMessage("nlpdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
2452 
2453  /* try to add solution to SCIP */
2454 #ifdef SCIP_DEBUG
2455  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, TRUE, FALSE, FALSE, TRUE, &success) );
2456 #else
2457  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, TRUE, &success) );
2458 #endif
2459 
2460  /* check, if solution was feasible and good enough */
2461  if( success )
2462  {
2463  SCIPdebugMessage(" -> solution was feasible and good enough\n");
2464  *result = SCIP_FOUNDSOL;
2465  }
2466  else
2467  {
2468  SCIPdebugMessage(" -> solution was not accepted\n");
2469  }
2470  }
2471 
2472  /* end diving */
2473  SCIP_CALL( SCIPendProbing(scip) );
2474 
2475  /* free hash map and drop variable bound change events */
2476  if( covercomputed )
2477  {
2478  assert(heurdata->eventhdlr != NULL);
2479  assert(heurdata->nfixedcovervars >= 0); /* variables might have been globally fixed in propagation */
2480  assert(varincover != NULL);
2481  assert(covervars != NULL);
2482 
2483  SCIPhashmapFree(&varincover);
2484 
2485  /* drop bound change events of cover variables */
2486  for( c = 0; c < ncovervars; c++ )
2487  {
2488  SCIP_CALL( SCIPdropVarEvent(scip, covervars[c], SCIP_EVENTTYPE_BOUNDCHANGED, heurdata->eventhdlr, (SCIP_EVENTDATA*)heurdata, -1) );
2489  }
2490  }
2491  else
2492  assert(varincover == NULL);
2493 
2494  /* free array of cover variables */
2495  if( heurdata->prefercover || heurdata->solvesubmip )
2496  {
2497  assert(covervars != NULL || !covercomputed);
2498  if( covervars != NULL )
2499  SCIPfreeBufferArray(scip, &covervars);
2500  }
2501  else
2502  assert(covervars == NULL);
2503 
2504  /* free NLP start solution */
2505  if( nlpstartsol != NULL )
2506  {
2507  SCIP_CALL( SCIPfreeSol(scip, &nlpstartsol) );
2508  }
2509 
2510  /* reset changed NLP parameters */
2511  SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_ITLIM, origiterlim) );
2512  SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_FASTFAIL, origfastfail) );
2513 
2514  /* free copied best solution */
2515  if( heurdata->varselrule == 'g' )
2516  {
2517  assert(bestsol != NULL);
2518  SCIP_CALL( SCIPfreeSol(scip, &bestsol) );
2519  }
2520  else
2521  assert(bestsol == NULL);
2522 
2523  /* free arrays of LP and NLP solution */
2524  if( heurdata->varselrule == 'd' )
2525  {
2526  assert(pseudocandsnlpsol != NULL);
2527  assert(pseudocandsnlpsol != NULL);
2528  SCIPfreeBufferArray(scip, &pseudocandslpsol);
2529  SCIPfreeBufferArray(scip, &pseudocandsnlpsol);
2530  }
2531  else
2532  {
2533  assert(pseudocandsnlpsol == NULL);
2534  assert(pseudocandsnlpsol == NULL);
2535  }
2536 
2537  if( *result == SCIP_FOUNDSOL )
2538  heurdata->nsuccess++;
2539 
2540  SCIPdebugMessage("nlpdiving heuristic finished\n");
2541 
2542  return SCIP_OKAY;
2543 }
2544 
2545 
2546 /*
2547  * heuristic specific interface methods
2548  */
2549 
2550 /** creates the nlpdiving heuristic and includes it in SCIP */
2552  SCIP* scip /**< SCIP data structure */
2553  )
2554 {
2555  SCIP_HEURDATA* heurdata;
2556  SCIP_HEUR* heur;
2557 
2558  /* create heuristic data */
2559  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
2560 
2561  heur = NULL;
2562  /* include heuristic */
2564  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecNlpdiving, heurdata) );
2565 
2566  assert(heur != NULL);
2567  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyNlpdiving) );
2568  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeNlpdiving) );
2569  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitNlpdiving) );
2570  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitNlpdiving) );
2571  SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolNlpdiving) );
2572 
2573  /* get event handler for bound change events */
2574  heurdata->eventhdlr = NULL;
2575  /* create event handler for bound change events */
2576  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &heurdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC,
2577  eventExecNlpdiving, NULL) );
2578  if ( heurdata->eventhdlr == NULL )
2579  {
2580  SCIPerrorMessage("event handler for "HEUR_NAME" heuristic not found.\n");
2581  return SCIP_PLUGINNOTFOUND;
2582  }
2583 
2584  /* nlpdiving heuristic parameters */
2586  "heuristics/"HEUR_NAME"/minreldepth",
2587  "minimal relative depth to start diving",
2588  &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
2590  "heuristics/"HEUR_NAME"/maxreldepth",
2591  "maximal relative depth to start diving",
2592  &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
2593  SCIP_CALL( SCIPaddIntParam(scip,
2594  "heuristics/"HEUR_NAME"/maxnlpiterabs",
2595  "minimial absolute number of allowed NLP iterations",
2596  &heurdata->maxnlpiterabs, FALSE, DEFAULT_MAXNLPITERABS, 0, INT_MAX, NULL, NULL) );
2597  SCIP_CALL( SCIPaddIntParam(scip,
2598  "heuristics/"HEUR_NAME"/maxnlpiterrel",
2599  "additional allowed number of NLP iterations relative to successfully found solutions",
2600  &heurdata->maxnlpiterrel, FALSE, DEFAULT_MAXNLPITERREL, 0, INT_MAX, NULL, NULL) );
2602  "heuristics/"HEUR_NAME"/maxdiveubquot",
2603  "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
2604  &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
2606  "heuristics/"HEUR_NAME"/maxdiveavgquot",
2607  "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
2608  &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2610  "heuristics/"HEUR_NAME"/maxdiveubquotnosol",
2611  "maximal UBQUOT when no solution was found yet (0.0: no limit)",
2612  &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
2614  "heuristics/"HEUR_NAME"/maxdiveavgquotnosol",
2615  "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
2616  &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2617  SCIP_CALL( SCIPaddIntParam(scip,
2618  "heuristics/"HEUR_NAME"/maxfeasnlps",
2619  "maximal number of NLPs with feasible solution to solve during one dive",
2620  &heurdata->maxfeasnlps, FALSE, DEFAULT_MAXFEASNLPS, 1, INT_MAX, NULL, NULL) );
2622  "heuristics/"HEUR_NAME"/backtrack",
2623  "use one level of backtracking if infeasibility is encountered?",
2624  &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
2626  "heuristics/"HEUR_NAME"/lp",
2627  "should the LP relaxation be solved before the NLP relaxation?",
2628  &heurdata->lp, TRUE, DEFAULT_LP, NULL, NULL) );
2630  "heuristics/"HEUR_NAME"/preferlpfracs",
2631  "prefer variables that are also fractional in LP solution?",
2632  &heurdata->preferlpfracs, TRUE, DEFAULT_PREFERLPFRACS, NULL, NULL) );
2634  "heuristics/"HEUR_NAME"/minsuccquot",
2635  "heuristic will not run if less then this percentage of calls succeeded (0.0: no limit)",
2636  &heurdata->minsuccquot, FALSE, DEFAULT_MINSUCCQUOT, 0.0, 1.0, NULL, NULL) );
2638  "heuristics/"HEUR_NAME"/fixquot",
2639  "percentage of fractional variables that should be fixed before the next NLP solve",
2640  &heurdata->fixquot, FALSE, DEFAULT_FIXQUOT, 0.0, 1.0, NULL, NULL) );
2642  "heuristics/"HEUR_NAME"/prefercover",
2643  "should variables in a minimal cover be preferred?",
2644  &heurdata->prefercover, FALSE, DEFAULT_PREFERCOVER, NULL, NULL) );
2646  "heuristics/"HEUR_NAME"/solvesubmip",
2647  "should a sub-MIP be solved if all cover variables are fixed?",
2648  &heurdata->solvesubmip, FALSE, DEFAULT_SOLVESUBMIP, NULL, NULL) );
2650  "heuristics/"HEUR_NAME"/nlpfastfail",
2651  "should the NLP solver stop early if it converges slow?",
2652  &heurdata->nlpfastfail, FALSE, DEFAULT_NLPFASTFAIL, NULL, NULL) );
2654  "heuristics/"HEUR_NAME"/nlpstart",
2655  "which point should be used as starting point for the NLP solver? ('n'one, last 'f'easible, from dive's'tart)",
2656  &heurdata->nlpstart, TRUE, DEFAULT_NLPSTART, "fns", NULL, NULL) );
2658  "heuristics/"HEUR_NAME"/varselrule",
2659  "which variable selection should be used? ('f'ractionality, 'c'oefficient, 'p'seudocost, 'g'uided, 'd'ouble, 'v'eclen)",
2660  &heurdata->varselrule, FALSE, DEFAULT_VARSELRULE, "fcpgdv", NULL, NULL) );
2661 
2662  return SCIP_OKAY;
2663 }
2664