Scippy

SCIP

Solving Constraint Integer Programs

heur_feaspump.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_feaspump.c
17  * @brief Objective Feasibility Pump 2.0
18  * @author Timo Berthold
19  * @author Domenico Salvagnin
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_feaspump.h"
28 #include "scip/cons_linear.h"
29 #include "scip/scipdefplugins.h"
30 
31 #define HEUR_NAME "feaspump"
32 #define HEUR_DESC "objective feasibility pump 2.0"
33 #define HEUR_DISPCHAR 'F'
34 #define HEUR_PRIORITY -1000000
35 #define HEUR_FREQ 20
36 #define HEUR_FREQOFS 0
37 #define HEUR_MAXDEPTH -1
38 #define HEUR_TIMING SCIP_HEURTIMING_AFTERLPPLUNGE
39 #define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
40 
41 #define DEFAULT_MAXLPITERQUOT 0.01 /**< maximal fraction of diving LP iterations compared to node LP iterations */
42 #define DEFAULT_MAXLPITEROFS 1000 /**< additional number of allowed LP iterations */
43 #define DEFAULT_MAXSOLS 10 /**< total number of feasible solutions found up to which heuristic is called
44  * (-1: no limit) */
45 #define DEFAULT_MAXLOOPS 10000 /**< maximal number of pumping rounds (-1: no limit) */
46 #define DEFAULT_MAXSTALLLOOPS 10 /**< maximal number of pumping rounds without fractionality improvement (-1: no limit) */
47 #define DEFAULT_MINFLIPS 10 /**< minimum number of random variables to flip, if a 1-cycle is encountered */
48 #define DEFAULT_CYCLELENGTH 3 /**< maximum length of cycles to be checked explicitly in each round */
49 #define DEFAULT_PERTURBFREQ 100 /**< number of iterations until a random perturbation is forced */
50 #define DEFAULT_OBJFACTOR 0.1 /**< factor by which the regard of the objective is decreased in each round,
51  * 1.0 for dynamic, depending on solutions already found */
52 #define DEFAULT_ALPHA 1.0 /**< initial weight of the objective function in the convex combination */
53 #define DEFAULT_ALPHADIFF 1.0 /**< threshold difference for the convex parameter to perform perturbation */
54 #define DEFAULT_BEFORECUTS TRUE /**< should the feasibility pump be called at root node before cut separation? */
55 #define DEFAULT_USEFP20 FALSE /**< should an iterative round-and-propagate scheme be used to find the integral points? */
56 #define DEFAULT_PERTSOLFOUND TRUE /**< should a random perturbation be performed if a feasible solution was found? */
57 #define DEFAULT_STAGE3 FALSE /**< should we solve a local branching sub-MIP if no solution could be found? */
58 #define DEFAULT_NEIGHBORHOODSIZE 18 /**< radius of the neighborhood to be searched in stage 3 */
59 #define DEFAULT_COPYCUTS TRUE /**< should all active cuts from the cutpool of the original SCIP be copied to
60  * constraints of the subscip
61  */
62 
63 #define MINLPITER 5000 /**< minimal number of LP iterations allowed in each LP solving call */
64 
65 
66 /** primal heuristic data */
67 struct SCIP_HeurData
68 {
69  SCIP_SOL* sol; /**< working solution */
70  SCIP_SOL* roundedsol; /**< rounded solution */
71  SCIP_Longint nlpiterations; /**< number of LP iterations used in this heuristic */
72  SCIP_Real maxlpiterquot; /**< maximal fraction of diving LP iterations compared to node LP iterations */
73  SCIP_Real objfactor; /**< factor by which the regard of the objective is decreased in each round,
74  * 1.0 for dynamic, depending on solutions already found */
75  SCIP_Real alpha; /**< initial weight of the objective function in the convex combination */
76  SCIP_Real alphadiff; /**< threshold difference for the convex parameter to perform perturbation */
77 
78  int maxlpiterofs; /**< additional number of allowed LP iterations */
79  int maxsols; /**< total number of feasible solutions found up to which heuristic is called
80  * (-1: no limit) */
81  int maxloops; /**< maximum number of loops (-1: no limit) */
82  int maxstallloops; /**< maximal number of pumping rounds without fractionality improvement (-1: no limit) */
83  int minflips; /**< minimum number of random variables to flip, if a 1-cycle is encountered */
84  int cyclelength; /**< maximum length of cycles to be checked explicitly in each round */
85  int perturbfreq; /**< number of iterations until a random perturbation is forced */
86  int nsuccess; /**< number of runs that produced at least one feasible solution */
87  int neighborhoodsize; /**< radius of the neighborhood to be searched in stage 3 */
88 
89  unsigned int randseed; /**< seed value for random number generator */
90  SCIP_Bool beforecuts; /**< should the feasibility pump be called at root node before cut separation? */
91  SCIP_Bool usefp20; /**< should an iterative round-and-propagate scheme be used to find the integral points? */
92  SCIP_Bool pertsolfound; /**< should a random perturbation be performed if a feasible solution was found? */
93  SCIP_Bool stage3; /**< should we solve a local branching sub-MIP if no solution could be found? */
94  SCIP_Bool copycuts; /**< should all active cuts from cutpool be copied to constraints in
95  * subproblem?
96  */
97 };
98 
99 /* copies SCIP to probing SCIP and creates variable hashmap */
100 static
102  SCIP* scip, /**< SCIP data structure */
103  SCIP** probingscip, /**< sub-SCIP data structure */
104  SCIP_HASHMAP** varmapfw, /**< mapping of SCIP variables to sub-SCIP variables */
105  SCIP_Bool copycuts, /**< should all active cuts from cutpool of scip copied to constraints in subscip */
106  SCIP_Bool* success /**< was copying successful? */
107  )
108 {
109  /* initializing the subproblem */
110  SCIP_CALL( SCIPcreate(probingscip) );
111 
112  /* create the variable mapping hash map */
113  SCIP_CALL( SCIPhashmapCreate(varmapfw, SCIPblkmem(*probingscip), SCIPgetNVars(scip)) );
114  *success = FALSE;
115 
116  /* copy SCIP instance */
117  SCIP_CALL( SCIPcopy(scip, *probingscip, *varmapfw, NULL, "feaspump", FALSE, FALSE, TRUE, success) );
118 
119  if( copycuts )
120  {
121  /* copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */
122  SCIP_CALL( SCIPcopyCuts(scip, *probingscip, *varmapfw, NULL, FALSE, NULL) );
123  }
124 
125  return SCIP_OKAY;
126 }
127 
128 /** set appropriate parameters for probing SCIP in FP2 */
129 static
131  SCIP* scip, /**< SCIP data structure */
132  SCIP* probingscip /**< sub-SCIP data structure */
133  )
134 {
135  if( SCIPisParamFixed(probingscip, "heuristics/"HEUR_NAME"/freq") )
136  {
137  SCIPwarningMessage(scip, "unfixing parameter heuristics/"HEUR_NAME"/freq in probingscip of "HEUR_NAME" heuristic to avoid recursive calls\n");
138  SCIP_CALL( SCIPunfixParam(probingscip, "heuristics/"HEUR_NAME"/freq") );
139  }
140  SCIP_CALL( SCIPsetIntParam(probingscip, "heuristics/"HEUR_NAME"/freq", -1) );
141 
142  /* do not abort subproblem on CTRL-C */
143  SCIP_CALL( SCIPsetBoolParam(probingscip, "misc/catchctrlc", FALSE) );
144 
145 #ifndef SCIP_DEBUG
146  /* disable output to console */
147  SCIP_CALL( SCIPsetIntParam(probingscip, "display/verblevel", 0) );
148 #endif
149 
150  /* disable expensive and useless stuff */
151  SCIP_CALL( SCIPsetLongintParam(probingscip, "limits/nodes", 1LL) );
152  if( SCIPisParamFixed(probingscip, "lp/solvefreq") )
153  {
154  SCIPwarningMessage(scip, "unfixing parameter lp/solvefreq in probingscip of "HEUR_NAME" heuristic to speed up propagation\n");
155  SCIP_CALL( SCIPunfixParam(probingscip, "lp/solvefreq") );
156  }
157  SCIP_CALL( SCIPsetIntParam(probingscip, "lp/solvefreq", -1) );
158  SCIP_CALL( SCIPsetBoolParam(probingscip, "conflict/enable", FALSE) );
159  SCIP_CALL( SCIPsetBoolParam(probingscip, "constraints/disableenfops", TRUE) );
160  SCIP_CALL( SCIPsetBoolParam(probingscip, "constraints/knapsack/negatedclique", FALSE) );
163  return SCIP_OKAY;
164 }
165 
166 /** set appropriate parameters for probing SCIP in Stage 3 */
167 static
169  SCIP* scip, /**< SCIP data structure */
170  SCIP* probingscip, /**< sub-SCIP data structure */
171  SCIP_Real timelimit, /**< time limit for Stage3 */
172  SCIP_Real memorylimit /**< memory limit for Stage3 */
173  )
174 {
175  SCIP_CALL( SCIPcopyParamSettings(scip, probingscip) );
176  /* do not abort subproblem on CTRL-C */
177  SCIP_CALL( SCIPsetBoolParam(probingscip, "misc/catchctrlc", FALSE) );
178 
179 #ifndef SCIP_DEBUG
180  /* disable output to console */
181  SCIP_CALL( SCIPsetIntParam(probingscip, "display/verblevel", 0) );
182 #endif
183  /* set limits for the subproblem */
184  SCIP_CALL( SCIPsetLongintParam(probingscip, "limits/nodes", 1000LL) );
185  SCIP_CALL( SCIPsetLongintParam(probingscip, "limits/stallnodes", 100LL) );
186  SCIP_CALL( SCIPsetRealParam(probingscip, "limits/time", timelimit) );
187  SCIP_CALL( SCIPsetRealParam(probingscip, "limits/memory", memorylimit) );
188 
189  /* forbid recursive call of heuristics and separators solving sub-SCIPs */
190  SCIP_CALL( SCIPsetSubscipsOff(probingscip, TRUE) );
191  if( SCIPisParamFixed(probingscip, "heuristics/"HEUR_NAME"/freq") )
192  {
193  SCIPwarningMessage(scip,"unfixing parameter heuristics/"HEUR_NAME"/freq in probingscip of "HEUR_NAME" heuristic to avoid recursive calls\n");
194  SCIP_CALL( SCIPunfixParam(probingscip, "heuristics/"HEUR_NAME"/freq") );
195  }
196  SCIP_CALL( SCIPsetIntParam(probingscip, "heuristics/feaspump/freq", -1) );
197 
198  /* disable heuristics which aim to feasibility instead of optimality */
199  if( !SCIPisParamFixed(probingscip, "heuristics/octane/freq") )
200  {
201  SCIP_CALL( SCIPsetIntParam(probingscip, "heuristics/octane/freq", -1) );
202  }
203  if( !SCIPisParamFixed(probingscip, "heuristics/objpscostdiving/freq") )
204  {
205  SCIP_CALL( SCIPsetIntParam(probingscip, "heuristics/objpscostdiving/freq", -1) );
206  }
207  if( !SCIPisParamFixed(probingscip, "heuristics/rootsoldiving/freq") )
208  {
209  SCIP_CALL( SCIPsetIntParam(probingscip, "heuristics/rootsoldiving/freq", -1) );
210  }
211 
212  /* disable cutting plane separation */
214 
215  /* disable expensive presolving */
217 
218  /* use best estimate node selection */
219  if( SCIPfindNodesel(probingscip, "estimate") != NULL && !SCIPisParamFixed(probingscip, "nodeselection/estimate/stdpriority") )
220  {
221  SCIP_CALL( SCIPsetIntParam(probingscip, "nodeselection/estimate/stdpriority", INT_MAX/4) );
222  }
223 
224  /* use inference branching */
225  if( SCIPfindBranchrule(probingscip, "inference") != NULL && !SCIPisParamFixed(probingscip, "branching/inference/priority") )
226  {
227  SCIP_CALL( SCIPsetIntParam(probingscip, "branching/inference/priority", INT_MAX/4) );
228  }
229 
230  /* disable conflict analysis */
231  if( !SCIPisParamFixed(probingscip, "conflict/useprop") )
232  {
233  SCIP_CALL( SCIPsetBoolParam(probingscip, "conflict/useprop", FALSE) );
234  }
235  if( !SCIPisParamFixed(probingscip, "conflict/useinflp") )
236  {
237  SCIP_CALL( SCIPsetBoolParam(probingscip, "conflict/useinflp", FALSE) );
238  }
239  if( !SCIPisParamFixed(probingscip, "conflict/useboundlp") )
240  {
241  SCIP_CALL( SCIPsetBoolParam(probingscip, "conflict/useboundlp", FALSE) );
242  }
243  if( !SCIPisParamFixed(probingscip, "conflict/usesb") )
244  {
245  SCIP_CALL( SCIPsetBoolParam(probingscip, "conflict/usesb", FALSE) );
246  }
247  if( !SCIPisParamFixed(probingscip, "conflict/usepseudo") )
248  {
249  SCIP_CALL( SCIPsetBoolParam(probingscip, "conflict/usepseudo", FALSE) );
250  }
251 
252  return SCIP_OKAY;
253 }
254 
255 /** checks whether a variable is one of the currently most fractional ones */
256 static
258  SCIP_VAR** mostfracvars, /**< sorted array of the currently most fractional variables */
259  SCIP_Real* mostfracvals, /**< array of their fractionality, decreasingly sorted */
260  int* nflipcands, /**< number of fractional variables already labeled to be flipped*/
261  int maxnflipcands, /**< typically randomized number of maximum amount of variables to flip */
262  SCIP_VAR* var, /**< variable to be checked */
263  SCIP_Real frac /**< fractional value of the variable */
264  )
265 {
266  int i;
267 
268  assert(mostfracvars != NULL);
269  assert(mostfracvals != NULL);
270  assert(nflipcands != NULL);
271 
272  /* instead of the fractional value use the fractionality */
273  if( frac > 0.5 )
274  frac = 1 - frac;
275 
276  /* if there are already enough candidates and the variable is less fractional, return, else reserve the last entry */
277  if( *nflipcands >= maxnflipcands )
278  {
279  if( frac <= mostfracvals[*nflipcands-1] )
280  return;
281  else
282  (*nflipcands)--;
283  }
284 
285  /* shifting var and frac through the (sorted) arrays */
286  for( i = *nflipcands; i > 0 && mostfracvals[i-1] < frac; i-- )
287  {
288  mostfracvars[i] = mostfracvars[i-1];
289  mostfracvals[i] = mostfracvals[i-1];
290  }
291  assert(0 <= i && i <= *nflipcands && *nflipcands < maxnflipcands);
292 
293  /* insert the variable and its fractionality */
294  mostfracvars[i] = var;
295  mostfracvals[i] = frac;
296 
297  /* we've found another candidate */
298  (*nflipcands)++;
299 }
300 
301 /** flips the roundings of the most fractional variables, if a 1-cycle was found */
302 static
304  SCIP* scip, /**< SCIP data structure */
305  SCIP_HEURDATA* heurdata, /**< data of this special heuristic */
306  SCIP_VAR** mostfracvars, /**< sorted array of the currently most fractional variables */
307  int nflipcands, /**< number of variables to flip */
308  SCIP_Real alpha /**< factor how much the original objective is regarded */
309  )
310 {
311  SCIP_VAR* var;
312  SCIP_Real solval;
313  SCIP_Real frac;
314  SCIP_Real newobjcoeff;
315  SCIP_Real orgobjcoeff;
316  int i;
317 
318  /* just flipping the objective coefficients from +1 to -1 and the rounding from floor to ceil */
319  for( i = 0; i < nflipcands; i++ )
320  {
321  var = mostfracvars[i];
322  solval = SCIPvarGetLPSol(var);
323  orgobjcoeff = SCIPvarGetObj(var);
324  frac = SCIPfeasFrac(scip, solval);
325 
326  if( frac > 0.5 )
327  {
328  newobjcoeff = (1.0 - alpha) + alpha * orgobjcoeff;
329  solval = SCIPfeasFloor(scip, solval);
330  }
331  else
332  {
333  newobjcoeff = - (1.0 - alpha) + alpha * orgobjcoeff;
334  solval = SCIPfeasCeil(scip, solval);
335  }
336  /* updating the rounded solution and the objective */
337  SCIP_CALL( SCIPsetSolVal(scip, heurdata->roundedsol, var, solval) );
338  SCIP_CALL( SCIPchgVarObjDive(scip, var, newobjcoeff) );
339  }
340  return SCIP_OKAY;
341 }
342 
343 /** flips the roundings of randomly chosen fractional variables, preferring highly fractional ones,
344  * if a longer cycle was found
345  */
346 static
348  SCIP* scip, /**< SCIP data structure */
349  SCIP_HEURDATA* heurdata, /**< data of this special heuristic */
350  SCIP_VAR** vars, /**< array of all variables */
351  int nbinandintvars, /**< number of general integer and 0-1 variables */
352  SCIP_Real alpha /**< factor how much the original objective is regarded */
353  )
354 {
355  SCIP_VAR* var;
356  SCIP_Real solval;
357  SCIP_Real frac;
358  SCIP_Real newobjcoeff;
359  SCIP_Real orgobjcoeff;
360  SCIP_Real flipprob;
361  int i;
362 
363  /* just flipping the objective coefficients from +1 to -1 and the rounding from floor to ceil */
364  for( i = 0; i < nbinandintvars; i++ )
365  {
366  /* decide arbitrarily whether the variable will be flipped or not */
367  var = vars[i];
368  solval = SCIPvarGetLPSol(var);
369  orgobjcoeff = SCIPvarGetObj(var);
370  frac = SCIPfeasFrac(scip, solval);
371  flipprob = -0.3 + SCIPgetRandomReal(0.0, 1.0, &heurdata->randseed);
372 
373  /* flip, iff the sum of the randomized number and the fractionality is big enough */
374  if( MIN(frac, 1.0-frac) + MAX(flipprob, 0.0) > 0.5 )
375  {
376  if( frac > 0.5 )
377  {
378  newobjcoeff = (1.0 - alpha) + alpha * orgobjcoeff;
379  solval = SCIPfeasFloor(scip, solval);
380  }
381  else
382  {
383  newobjcoeff = - (1.0 - alpha) + alpha * orgobjcoeff;
384  solval = SCIPfeasCeil(scip, solval);
385  }
386  SCIP_CALL( SCIPsetSolVal(scip, heurdata->roundedsol, var, solval) );
387  SCIP_CALL( SCIPchgVarObjDive(scip, var, newobjcoeff) );
388  }
389  }
390 
391  return SCIP_OKAY;
392 }
393 
394 /** create the extra constraint of local branching and add it to subscip */
395 static
397  SCIP* scip, /**< SCIP data structure of the original problem */
398  SCIP* probingscip, /**< SCIP data structure of the subproblem */
399  SCIP_HASHMAP* varmapfw, /**< mapping of SCIP variables to sub-SCIP variables */
400  SCIP_SOL* bestsol, /**< SCIP solution */
401  SCIP_Real neighborhoodsize /**< rhs for LB constraint */
402  )
403 {
404  SCIP_CONS* cons; /* local branching constraint to create */
405  SCIP_VAR** consvars;
406  SCIP_VAR** vars;
407 
408  int nbinvars;
409  int i;
410  SCIP_Real lhs;
411  SCIP_Real rhs;
412  SCIP_Real* consvals;
413  char consname[SCIP_MAXSTRLEN];
414 
415  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_localbranchcons", SCIPgetProbName(scip));
416 
417  /* get vars data */
418  SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, NULL, NULL, NULL) );
419  /* memory allocation */
420  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
421  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
422 
423  /* set initial left and right hand sides of local branching constraint */
424  lhs = 0.0;
425  rhs = neighborhoodsize;
426 
427  /* create the distance (to incumbent) function of the binary variables */
428  for( i = 0; i < nbinvars; i++ )
429  {
430  SCIP_Real solval;
431 
432  solval = SCIPgetSolVal(scip, bestsol, vars[i]);
433  assert( SCIPisFeasIntegral(scip,solval) );
434 
435  /* is variable i part of the binary support of closest sol? */
436  if( SCIPisFeasEQ(scip,solval,1.0) )
437  {
438  consvals[i] = -1.0;
439  rhs -= 1.0;
440  lhs -= 1.0;
441  }
442  else
443  consvals[i] = 1.0;
444  consvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]);
445  SCIP_CALL( SCIPchgVarObj(probingscip, consvars[i], consvals[i]) );
446  assert( SCIPvarGetType(consvars[i]) == SCIP_VARTYPE_BINARY );
447  }
448 
449  /* creates localbranching constraint and adds it to subscip */
450  SCIP_CALL( SCIPcreateConsLinear(probingscip, &cons, consname, nbinvars, consvars, consvals,
451  lhs, rhs, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
452  SCIP_CALL( SCIPaddCons(probingscip, cons) );
453  SCIP_CALL( SCIPreleaseCons(probingscip, &cons) );
454 
455  /* free local memory */
456  SCIPfreeBufferArray(scip, &consvals);
457  SCIPfreeBufferArray(scip, &consvars);
458 
459  return SCIP_OKAY;
460 }
461 
462 /** creates new solutions for the original problem by copying the solutions of the subproblem */
463 static
465  SCIP* scip, /**< original SCIP data structure */
466  SCIP* subscip, /**< SCIP structure of the subproblem */
467  SCIP_HASHMAP* varmapfw, /**< mapping of SCIP variables to sub-SCIP variables */
468  SCIP_HEUR* heur, /**< heuristic structure */
469  SCIP_Bool* success /**< used to store whether new solution was found or not */
470  )
471 {
472  SCIP_VAR** vars; /* the original problem's variables */
473  int nvars;
474  SCIP_SOL** subsols;
475  int nsubsols;
476  SCIP_VAR** subvars;
477  SCIP_Real* subsolvals; /* solution values of the subproblem */
478  SCIP_SOL* newsol; /* solution to be created for the original problem */
479  int i;
480 
481  assert(scip != NULL);
482  assert(subscip != NULL);
483 
484  /* get variables' data */
485  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
486 
487  /* sub-SCIP may have more variables than the number of active (transformed) variables in the main SCIP
488  * since constraint copying may have required the copy of variables that are fixed in the main SCIP
489  */
490  assert(nvars <= SCIPgetNOrigVars(subscip));
491 
492  /* for copying a solution we need an explicit mapping */
493  SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) );
494  for( i = 0; i < nvars; i++ )
495  subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]);
496 
497  SCIP_CALL( SCIPallocBufferArray(scip, &subsolvals, nvars) );
498 
499  nsubsols = SCIPgetNSols(subscip);
500  subsols = SCIPgetSols(subscip);
501  *success = FALSE;
502 
503  for( i = 0; i < nsubsols && !(*success); ++i )
504  {
505  /* copy the solution */
506  SCIP_CALL( SCIPgetSolVals(subscip, subsols[i], nvars, subvars, subsolvals) );
507 
508  /* create new solution for the original problem */
509  SCIP_CALL( SCIPcreateSol(scip, &newsol, heur) );
510  SCIP_CALL( SCIPsetSolVals(scip, newsol, nvars, vars, subsolvals) );
511 
512  /* try to add new solution to scip and free it immediately */
513  SCIP_CALL( SCIPtrySolFree(scip, &newsol, FALSE, TRUE, TRUE, TRUE, success) );
514  }
515 
516  SCIPfreeBufferArray(scip, &subvars);
517  SCIPfreeBufferArray(scip, &subsolvals);
518 
519  return SCIP_OKAY;
520 }
521 
522 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
523 static
524 SCIP_DECL_HEURCOPY(heurCopyFeaspump)
525 {
526  assert(scip != NULL);
527  assert(heur != NULL);
528  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
529 
530  /* call inclusion method of primal heuristic */
532 
533  return SCIP_OKAY;
534 }
535 
536 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
537 static
538 SCIP_DECL_HEURFREE(heurFreeFeaspump)
539 {
540  SCIP_HEURDATA* heurdata;
541 
542  assert(heur != NULL);
543  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
544  assert(scip != NULL);
545 
546  /* free heuristic data */
547  heurdata = SCIPheurGetData(heur);
548  assert(heurdata != NULL);
549  SCIPfreeMemory(scip, &heurdata);
550  SCIPheurSetData(heur, NULL);
551 
552  return SCIP_OKAY;
553 }
554 
555 
556 /** initialization method of primal heuristic (called after problem was transformed) */
557 static
558 SCIP_DECL_HEURINIT(heurInitFeaspump)
559 {
560  SCIP_HEURDATA* heurdata;
561 
562  assert(heur != NULL);
563  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
564 
565  /* get heuristic data */
566  heurdata = SCIPheurGetData(heur);
567  assert(heurdata != NULL);
568 
569  /* create working solution */
570  SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
571  SCIP_CALL( SCIPcreateSol(scip, &heurdata->roundedsol, heur) );
572 
573  /* initialize data */
574  heurdata->nlpiterations = 0;
575  heurdata->nsuccess = 0;
576  heurdata->randseed = 0;
577 
578  return SCIP_OKAY;
579 }
580 
581 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
582 static
583 SCIP_DECL_HEUREXIT(heurExitFeaspump)
584 {
585  SCIP_HEURDATA* heurdata;
586 
587  assert(heur != NULL);
588  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
589 
590  /* get heuristic data */
591  heurdata = SCIPheurGetData(heur);
592  assert(heurdata != NULL);
593 
594  /* free working solution */
595  SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
596  SCIP_CALL( SCIPfreeSol(scip, &heurdata->roundedsol) );
597 
598  return SCIP_OKAY;
599 }
600 
601 
602 /** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
603 static
604 SCIP_DECL_HEURINITSOL(heurInitsolFeaspump)
605 {
606  SCIP_HEURDATA* heurdata;
607 
608  heurdata = SCIPheurGetData(heur);
609  assert(heurdata != NULL);
610 
611  /* if the heuristic is called at the root node, we may want to be called directly after the initial root LP solve */
612  if( heurdata->beforecuts && SCIPheurGetFreqofs(heur) == 0 )
614 
615  return SCIP_OKAY;
616 }
617 
618 
619 /** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
620 static
621 SCIP_DECL_HEUREXITSOL(heurExitsolFeaspump)
622 {
623  /* reset the timing mask to its default value */
625 
626  return SCIP_OKAY;
627 }
628 
629 /** calculates an adjusted maximal number of LP iterations */
630 static
632  SCIP_Longint maxnlpiterations, /**< regular maximal number of LP iterations */
633  SCIP_Longint nsolsfound, /**< total number of solutions found so far by SCIP */
634  int nstallloops /**< current number of stalling rounds */
635  )
636 {
637  if( nstallloops <= 1 )
638  {
639  if( nsolsfound == 0 )
640  return 4*maxnlpiterations;
641  else
642  return 2*maxnlpiterations;
643  }
644  else
645  return maxnlpiterations;
646 }
647 
648 /** execution method of primal heuristic */
649 static
650 SCIP_DECL_HEUREXEC(heurExecFeaspump)
651 {
652  SCIP_HEURDATA* heurdata;
653  SCIP_SOL* tmpsol; /* only used for swapping */
654  SCIP_SOL** lastroundedsols;/* solutions of the last pumping rounds (depending on heurdata->cyclelength) */
655  SCIP_SOL* closestsol; /* rounded solution closest to the LP relaxation: used for stage3 */
656  SCIP_Real* lastalphas; /* alpha values associated to solutions in lastroundedsols */
657 
658  SCIP* probingscip; /* copied SCIP structure, used for round-and-propagate loop of feasibility pump 2.0 */
659  SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */
660 
661 
662  SCIP_VAR** vars;
663  SCIP_VAR** pseudocands;
664  SCIP_VAR** tmppseudocands;
665  SCIP_VAR** mostfracvars; /* the 30 most fractional variables, needed to avoid 1-cycles */
666  SCIP_VAR* var;
667 
668  SCIP_Real* mostfracvals; /* the values of the variables above */
669  SCIP_Real newobjcoeff; /* used for changing the objective */
670  SCIP_Real orgobjcoeff; /* used for regarding the original objective */
671  SCIP_Real oldsolval; /* one value of the last solution */
672  SCIP_Real solval; /* one value of the actual solution */
673  SCIP_Real frac; /* the fractional part of the value above */
674  SCIP_Real objfactor; /* factor by which the regard of the objective is decreased in each round, in [0,0.99] */
675  SCIP_Real alpha; /* factor how the original objective is regarded, used for convex combination of two functions */
676  SCIP_Real objnorm; /* Euclidean norm of the objective function, used for scaling */
677  SCIP_Real scalingfactor; /* factor to scale the original objective function with */
678  SCIP_Real mindistance; /* distance of the closest rounded solution from the LP relaxation: used for stage3 */
679 
680  SCIP_Longint nlpiterations; /* number of LP iterations done during one pumping round */
681  SCIP_Longint maxnlpiterations; /* maximum number of LP iterations for this heuristic */
682  SCIP_Longint nsolsfound; /* number of solutions found by this heuristic */
683  SCIP_Longint ncalls; /* number of calls of this heuristic */
684  SCIP_Longint nbestsolsfound; /* current total number of best solution updates in SCIP */
685 
686  SCIP_LPSOLSTAT lpsolstat; /* status of the LP solution */
687 
688  int nvars; /* number of variables */
689  int nbinvars; /* number of 0-1-variables */
690  int nintvars; /* number of integer variables */
691  int nfracs; /* number of fractional variables updated after each pumping round*/
692  int nflipcands; /* how many flipcands (most frac. var.) have been found */
693  int npseudocands;
694  int maxnflipcands; /* maximal number of candidates to flip in the current pumping round */
695  int nloops; /* how many pumping rounds have been made */
696  int maxflips; /* maximum number of flips, if a 1-cycle is found (depending on heurdata->minflips) */
697  int maxloops; /* maximum number of pumping rounds */
698  int nstallloops; /* number of loops without reducing the current best number of factional variables */
699  int maxstallloops; /* maximal number of allowed stalling loops */
700  int bestnfracs; /* best number of fractional variables */
701  int i;
702  int j;
703 
704  SCIP_Bool success;
705  SCIP_Bool lperror;
706  SCIP_Bool* cycles; /* are there short cycles */
707 
708  SCIP_RETCODE retcode;
709 
710  assert(heur != NULL);
711  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
712  assert(scip != NULL);
713  assert(result != NULL);
714  assert(SCIPhasCurrentNodeLP(scip));
715 
716  *result = SCIP_DELAYED;
717 
718  /* do not call heuristic of node was already detected to be infeasible */
719  if( nodeinfeasible )
720  return SCIP_OKAY;
721 
722  /* only call heuristic, if an optimal LP solution is at hand */
724  return SCIP_OKAY;
725 
726  /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
727  if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
728  return SCIP_OKAY;
729 
730  /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
731  if( !SCIPisLPSolBasic(scip) )
732  return SCIP_OKAY;
733 
734  *result = SCIP_DIDNOTRUN;
735 
736  /* don't dive two times at the same node */
737  if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
738  return SCIP_OKAY;
739 
740  /* only call feaspump once at the root */
741  if( SCIPgetDepth(scip) == 0 && SCIPheurGetNCalls(heur) > 0 )
742  return SCIP_OKAY;
743 
744  /* reset the timing mask to its default value (at the root node it could be different) */
746 
747  /* only call the heuristic before cutting planes if we do not have an incumbent and no pricer exists */
748  if( heurtiming == SCIP_HEURTIMING_DURINGLPLOOP && SCIPgetNSolsFound(scip) > 0 && SCIPgetNPricers(scip) == 0 )
749  return SCIP_OKAY;
750 
751  /* get heuristic's data */
752  heurdata = SCIPheurGetData(heur);
753  assert(heurdata != NULL);
754 
755  /* only apply heuristic, if only a few solutions have been found and no pricer exists */
756  if( heurdata->maxsols >= 0 && SCIPgetNSolsFound(scip) > heurdata->maxsols && SCIPgetNPricers(scip) == 0 )
757  return SCIP_OKAY;
758 
759  /* get all variables of LP and number of fractional variables in LP solution that should be integral */
760  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
761  nfracs = SCIPgetNLPBranchCands(scip);
762  assert(0 <= nfracs && nfracs <= nbinvars + nintvars);
763  if( nfracs == 0 )
764  return SCIP_OKAY;
765 
766  /* calculate the maximal number of LP iterations until heuristic is aborted */
767  nlpiterations = SCIPgetNLPIterations(scip);
768  ncalls = SCIPheurGetNCalls(heur);
769  nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
770  maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
771  maxnlpiterations += heurdata->maxlpiterofs;
772 
773  /* don't try to dive, if we took too many LP iterations during diving */
774  if( heurdata->nlpiterations >= maxnlpiterations )
775  return SCIP_OKAY;
776 
777  /* at the first root call, allow more iterations if there is no feasible solution yet */
778  if( SCIPheurGetNCalls(heur) == 0 && SCIPgetNSolsFound(scip) == 0 && SCIPgetDepth(scip) == 0 )
779  maxnlpiterations += nlpiterations;
780 
781  /* allow at least a certain number of LP iterations in this dive */
782  maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);
783 
784  /* calculate maximal number of flips and loops */
785  maxflips = 3*heurdata->minflips;
786  maxloops = (heurdata->maxloops == -1 ? INT_MAX : heurdata->maxloops);
787  maxstallloops = (heurdata->maxstallloops == -1 ? INT_MAX : heurdata->maxstallloops);
788 
789  SCIPdebugMessage("executing feasibility pump heuristic, nlpiters=%"SCIP_LONGINT_FORMAT", maxnlpit:%"SCIP_LONGINT_FORMAT", maxflips:%d \n",
790  nlpiterations, maxnlpiterations, maxflips);
791 
792  *result = SCIP_DIDNOTFIND;
793 
794  probingscip = NULL;
795  varmapfw = NULL;
796 
797  if( heurdata->usefp20 )
798  {
799  SCIP_CALL( setupProbingSCIP(scip, &probingscip, &varmapfw, heurdata->copycuts, &success) );
800 
801  if( success )
802  {
803  SCIP_CALL( setupSCIPparamsFP2(scip, probingscip) );
804 
805  retcode = SCIPsolve(probingscip);
806 
807  /* errors in solving the subproblem should not kill the overall solving process;
808  * hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */
809  if( retcode != SCIP_OKAY )
810  {
811 #ifndef NDEBUG
812  SCIP_CALL( retcode );
813 #endif
814  SCIPwarningMessage(scip, "Error while solving subproblem in feaspump heuristic; sub-SCIP terminated with code <%d>\n", retcode);
815 
816  /* free hash map and copied SCIP */
817  SCIPhashmapFree(&varmapfw);
818  SCIP_CALL( SCIPfree(&probingscip) );
819  return SCIP_OKAY;
820  }
821 
822  if( SCIPgetStage(probingscip) != SCIP_STAGE_SOLVING)
823  {
824  SCIP_STATUS probingstatus = SCIPgetStatus(probingscip);
825 
826  if( probingstatus == SCIP_STATUS_OPTIMAL )
827  {
828  assert( SCIPgetNSols(probingscip) > 0 );
829  SCIP_CALL( createNewSols(scip, probingscip, varmapfw, heur, &success) );
830  if( success )
831  *result = SCIP_FOUNDSOL;
832  }
833 
834  /* free hash map and copied SCIP */
835  SCIPhashmapFree(&varmapfw);
836  SCIP_CALL( SCIPfree(&probingscip) );
837  return SCIP_OKAY;
838  }
839  SCIP_CALL( SCIPsetLongintParam(probingscip, "limits/nodes", 2LL) );
840 
841  /* set SCIP into probing mode and create root node of the probing tree */
842  SCIP_CALL( SCIPstartProbing(probingscip) );
843  SCIP_CALL( SCIPnewProbingNode(probingscip) );
844 
845  SCIPdebugMessage("successfully copied SCIP instance -> feasibility pump 2.0 can be used.\n");
846  }
847  }
848 
849  /* memory allocation */
850  SCIP_CALL( SCIPallocBufferArray(scip, &mostfracvars, maxflips) );
851  SCIP_CALL( SCIPallocBufferArray(scip, &mostfracvals, maxflips) );
852  SCIP_CALL( SCIPallocBufferArray(scip, &lastroundedsols, heurdata->cyclelength) );
853  SCIP_CALL( SCIPallocBufferArray(scip, &lastalphas, heurdata->cyclelength) );
854  SCIP_CALL( SCIPallocBufferArray(scip, &cycles, heurdata->cyclelength) );
855 
856  for( j = 0; j < heurdata->cyclelength; j++ )
857  {
858  SCIP_CALL( SCIPcreateSol(scip, &lastroundedsols[j], heur) );
859  }
860 
861  closestsol = NULL;
862  if( heurdata->stage3 )
863  {
864  SCIP_CALL( SCIPcreateSol(scip, &closestsol, heur) );
865  }
866 
867  /* start diving */
868  SCIP_CALL( SCIPstartDive(scip) );
869 
870  /* lp was solved optimal */
871  lperror = FALSE;
872  lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
873 
874  /* pumping rounds */
875  nsolsfound = SCIPgetNBestSolsFound(scip);
876  if( heurdata->objfactor == 1.0 )
877  objfactor = MIN(1.0 - 0.1 / (SCIP_Real)(1 + nsolsfound), 0.999);
878  else
879  objfactor = heurdata->objfactor;
880 
881  /* scale distance function and original objective to the same norm */
882  objnorm = SCIPgetObjNorm(scip);
883  objnorm = MAX(objnorm, 1.0);
884  scalingfactor = SQRT((SCIP_Real)(nbinvars + nintvars)) / objnorm;
885 
886  /* data initialization */
887  alpha = heurdata->alpha;
888  nloops = 0;
889  nstallloops = 0;
890  nbestsolsfound = SCIPgetNBestSolsFound(scip);
891  bestnfracs = INT_MAX;
892  mindistance = SCIPinfinity(scip);
893 
894  /* pumping loop */
895  while( nfracs > 0
896  && heurdata->nlpiterations < adjustedMaxNLPIterations(maxnlpiterations, nsolsfound, nstallloops)
897  && nloops < maxloops && nstallloops < maxstallloops
898  && !SCIPisStopped(scip) )
899  {
900  int minimum;
901  SCIP_Real* pseudocandsfrac;
902  SCIP_Longint nlpiterationsleft;
903  int iterlimit;
904 
905  /* decrease convex combination scalar */
906  nloops++;
907  alpha *= objfactor;
908 
909  SCIPdebugMessage("feasibility pump loop %d: %d fractional variables (alpha: %.4f, stall: %d/%d)\n",
910  nloops, nfracs, alpha, nstallloops, maxstallloops);
911 
912  success = FALSE;
913 
914  /* create solution from diving LP and try to round it */
915  SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
916  SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
917 
918  /* if the rounded solution is feasible and better, add it to SCIP */
919  /*if( success )
920  {
921  SCIPdebugMessage("feasibility pump trying rounded solution\n");
922  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );
923  if( success )
924  *result = SCIP_FOUNDSOL;
925  }*/
926 
927  SCIP_CALL( SCIPlinkLPSol(scip, heurdata->roundedsol) );
928 
929  /* randomly choose maximum number of variables to flip in current pumping round in case of a 1-cycle */
930  maxnflipcands = SCIPgetRandomInt(MIN(nfracs/2+1, heurdata->minflips), MIN(nfracs, maxflips), &heurdata->randseed);
931  nflipcands = 0;
932 
933  /* get all unfixed integer variables */
934  SCIP_CALL( SCIPgetPseudoBranchCands(scip, &tmppseudocands, &npseudocands, NULL) );
935  SCIP_CALL( SCIPduplicateBufferArray(scip, &pseudocands, tmppseudocands, npseudocands) );
936 
937  /* get array of all fractional variables and sort it w.r.t. their fractionalities */
938  if( heurdata->usefp20 )
939  {
940  SCIP_CALL( SCIPallocBufferArray(scip, &pseudocandsfrac, npseudocands) );
941 
942  for( i = 0; i < npseudocands; i++ )
943  {
944  frac = SCIPfeasFrac(scip, SCIPvarGetLPSol(pseudocands[i]));
945  pseudocandsfrac[i] = MIN(frac, 1.0-frac); /* always a number between 0 and 0.5 */
946  if( SCIPvarGetType(pseudocands[i]) == SCIP_VARTYPE_BINARY )
947  pseudocandsfrac[i] -= 10.0; /* binaries always come first */
948  }
949  SCIPsortRealPtr(pseudocandsfrac, (void**)pseudocands, npseudocands);
950  SCIPfreeBufferArray(scip, &pseudocandsfrac);
951 
952  SCIPdebugMessage("iteratively fix and propagate variables\n");
953  }
954 
955  for( i = 0; i < npseudocands; i++ )
956  {
957  SCIP_VAR* probingvar;
958  SCIP_Bool infeasible;
959  SCIP_Longint ndomreds;
960 
961  var = pseudocands[i];
962  orgobjcoeff = SCIPvarGetObj(var);
963 
964  /* round the LP solution */
965  solval = SCIPvarGetLPSol(var);
966  frac = SCIPfeasFrac(scip, solval);
967 
968  solval = SCIPfloor(scip, solval+0.5);
969 
970  /* ensure, that the fixing value is inside the local domains */
971  if( heurdata->usefp20 )
972  {
973  SCIP_Real lb;
974  SCIP_Real ub;
975 
976  probingvar = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, var);
977  lb = SCIPvarGetLbLocal(probingvar);
978  ub = SCIPvarGetUbLocal(probingvar);
979 
980  solval = MAX(solval, lb);
981  solval = MIN(solval, ub);
982 
983  /* fix the variable and propagate the domain change */
984  if( !SCIPisFeasEQ(probingscip, lb, ub) )
985  {
986  assert(SCIPisFeasLE(probingscip, lb, ub));
987  /* SCIP_CALL( SCIPnewProbingNode(probingscip) ); */
988  SCIPdebugMessage("try to fix variable <%s> (domain [%f,%f] to %f\n",SCIPvarGetName(probingvar), lb, ub,
989  solval);
990  SCIP_CALL( SCIPfixVarProbing(probingscip, probingvar, solval) );
991  SCIP_CALL( SCIPpropagateProbing(probingscip, -1, &infeasible, &ndomreds) );
992  SCIPdebugMessage(" -> reduced %"SCIP_LONGINT_FORMAT" domains\n", ndomreds);
993 
994  if( infeasible )
995  {
996  SCIPdebugMessage(" -> infeasible!\n");
997  SCIP_CALL( SCIPbacktrackProbing(probingscip, 0/*SCIPgetProbingDepth(probingscip)-1*/) );
998  }
999  }
1000  else
1001  {
1002  SCIPdebugMessage("variable <%s> is already fixed to %f\n",SCIPvarGetName(probingvar), solval);
1003  }
1004  }
1005 
1006  assert(SCIPisFeasLE(scip, SCIPvarGetLbLocal(var), solval) && SCIPisFeasLE(scip, solval, SCIPvarGetUbLocal(var)));
1007  assert(SCIPisIntegral(scip,solval));
1008  SCIP_CALL( SCIPsetSolVal(scip, heurdata->roundedsol, var, solval) );
1009 
1010  /* variables which are already integral, are treated separately */
1011  if( SCIPisFeasZero(scip, frac) )
1012  {
1013  SCIP_Real lb;
1014  SCIP_Real ub;
1015 
1016  /* variables at their bounds should be kept there */
1017  lb = SCIPvarGetLbLocal(var);
1018  ub = SCIPvarGetUbLocal(var);
1019  if( SCIPisFeasEQ(scip, solval, lb) )
1020  newobjcoeff = (1.0 - alpha)/scalingfactor + alpha * orgobjcoeff;
1021  else if( SCIPisFeasEQ(scip, solval, ub) )
1022  newobjcoeff = - (1.0 - alpha)/scalingfactor + alpha * orgobjcoeff;
1023  else
1024  newobjcoeff = alpha * orgobjcoeff;
1025  }
1026  else
1027  {
1028  /* check whether the variable is one of the most fractionals and label if so */
1029  insertFlipCand(mostfracvars, mostfracvals, &nflipcands, maxnflipcands, var, frac);
1030 
1031  if( frac > 0.5 )
1032  newobjcoeff = - (1.0 - alpha)/scalingfactor + alpha * orgobjcoeff;
1033  else
1034  newobjcoeff = (1.0 - alpha)/scalingfactor + alpha * orgobjcoeff;
1035  }
1036 
1037  /* change one coefficient of the objective */
1038  SCIP_CALL( SCIPchgVarObjDive(scip, var, newobjcoeff) );
1039 
1040  }
1041 
1042  if( heurdata->usefp20 )
1043  {
1044  SCIP_CALL( SCIPbacktrackProbing(probingscip, 0) );
1045  }
1046 
1047  /* change objective coefficients for continuous variables */
1048  for( i = nbinvars+nintvars; i < nvars; i++ )
1049  {
1050  SCIP_CALL( SCIPchgVarObjDive(scip, vars[i], alpha * SCIPvarGetObj(vars[i])) );
1051  }
1052 
1053  SCIPfreeBufferArray(scip, &pseudocands);
1054 
1055  /* initialize cycle check */
1056  minimum = MIN(heurdata->cyclelength, nloops-1);
1057  for( j = 0; j < heurdata->cyclelength; j++ )
1058  cycles[j] = (nloops > j+1) && (REALABS(lastalphas[j] - alpha) < heurdata->alphadiff);
1059 
1060  /* check for j-cycles */
1061  for( i = 0; i < nbinvars+nintvars; i++ )
1062  {
1063  solval = SCIPgetSolVal(scip, heurdata->roundedsol, vars[i]);
1064 
1065  /* cycles exist, iff all solution values are equal */
1066  for( j = 0; j < minimum; j++ )
1067  {
1068  oldsolval = SCIPgetSolVal(scip, lastroundedsols[j], vars[i]);
1069  cycles[j] = cycles[j] && SCIPisFeasEQ(scip, solval, oldsolval);
1070  }
1071  }
1072 
1073  /* force to flip variables at random after a couple of pumping rounds,
1074  * or if a new best solution in the current region has been found
1075  */
1076  assert(heurdata->perturbfreq > 0);
1077  if( nloops % heurdata->perturbfreq == 0 || (heurdata->pertsolfound && SCIPgetNBestSolsFound(scip) > nbestsolsfound) )
1078  {
1079  SCIPdebugMessage(" -> random perturbation\n");
1080  SCIP_CALL( handleCycle(scip, heurdata, vars, nintvars+nbinvars, alpha) );
1081  nbestsolsfound = SCIPgetNBestSolsFound(scip);
1082  }
1083  else
1084  {
1085  minimum = MIN(heurdata->cyclelength, nloops-1);
1086 
1087  for( j = 0; j < minimum; j++ )
1088  {
1089  /* if we got the same rounded solution as in some step before, we have to flip some variables */
1090  if( cycles[j] )
1091  {
1092  /* 1-cycles have a special flipping rule (flip most fractional variables) */
1093  if( j == 0 )
1094  {
1095  SCIPdebugMessage(" -> avoiding 1-cycle: flipping %d candidates\n", nflipcands);
1096  SCIP_CALL( handle1Cycle(scip, heurdata, mostfracvars, nflipcands, alpha) );
1097  }
1098  else
1099  {
1100  SCIPdebugMessage(" -> avoiding %d-cycle by random flip\n", j+1);
1101  SCIP_CALL( handleCycle(scip, heurdata, vars, nintvars+nbinvars, alpha) );
1102  }
1103  break;
1104  }
1105  }
1106  }
1107 
1108  /* the LP with the new (distance) objective is solved */
1109  nlpiterations = SCIPgetNLPIterations(scip);
1110  nlpiterationsleft = adjustedMaxNLPIterations(maxnlpiterations, nsolsfound, nstallloops) - heurdata->nlpiterations;
1111  iterlimit = MAX((int)nlpiterationsleft, MINLPITER);
1112  SCIPdebugMessage(" -> solve LP with iteration limit %d\n", iterlimit);
1113 
1114  if( heurdata->stage3 )
1115  {
1116  SCIP_CALL( SCIPunlinkSol(scip, heurdata->roundedsol) );
1117  }
1118 
1119  retcode = SCIPsolveDiveLP(scip, iterlimit, &lperror, NULL);
1120  lpsolstat = SCIPgetLPSolstat(scip);
1121 
1122  /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
1123  * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
1124  */
1125  if( retcode != SCIP_OKAY )
1126  {
1127 #ifndef NDEBUG
1128  if( lpsolstat != SCIP_LPSOLSTAT_UNBOUNDEDRAY )
1129  {
1130  SCIP_CALL( retcode );
1131  }
1132 #endif
1133  SCIPwarningMessage(scip, "Error while solving LP in Feaspump heuristic; LP solve terminated with code <%d>\n", retcode);
1134  SCIPwarningMessage(scip, "This does not affect the remaining solution procedure --> continue\n");
1135  }
1136 
1137  /* update iteration count */
1138  heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations;
1139  SCIPdebugMessage(" -> number of iterations: %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT", lperror=%u, lpsolstat=%d\n",
1140  heurdata->nlpiterations, adjustedMaxNLPIterations(maxnlpiterations, nsolsfound, nstallloops), lperror, lpsolstat);
1141 
1142  /* check whether LP was solved optimal */
1143  if( lperror || lpsolstat != SCIP_LPSOLSTAT_OPTIMAL )
1144  break;
1145 
1146  if( heurdata->stage3 )
1147  {
1148  SCIP_Real distance; /* distance of the current rounded solution from the LP solution */
1149 
1150  assert(closestsol != NULL);
1151 
1152  /* calculate distance */
1153  distance = 0.0;
1154  for( i = 0; i < nbinvars+nintvars; i++ )
1155  {
1156  SCIP_Real roundedval;
1157  SCIP_Real lpval;
1158 
1159  roundedval = SCIPgetSolVal(scip, heurdata->roundedsol, vars[i]);
1160  lpval = SCIPvarGetLPSol(vars[i]);
1161  distance += REALABS(roundedval - lpval);
1162  }
1163 
1164  /* copy solution and update minimum distance */
1165  if( SCIPisLT(scip, distance, mindistance) )
1166  {
1167  for( i = 0; i < nbinvars+nintvars; i++ )
1168  {
1169  assert(SCIPisIntegral(scip,SCIPgetSolVal(scip, heurdata->roundedsol, vars[i])));
1170  SCIP_CALL( SCIPsetSolVal(scip, closestsol, vars[i], SCIPgetSolVal(scip, heurdata->roundedsol, vars[i])) );
1171  }
1172  mindistance = distance;
1173  }
1174  }
1175 
1176  /* swap the last solutions */
1177  tmpsol = lastroundedsols[heurdata->cyclelength-1];
1178  for( j = heurdata->cyclelength-1; j > 0; j-- )
1179  {
1180  lastroundedsols[j] = lastroundedsols[j-1];
1181  lastalphas[j] = lastalphas[j-1];
1182  }
1183  lastroundedsols[0] = heurdata->roundedsol;
1184  lastalphas[0] = alpha;
1185  heurdata->roundedsol = tmpsol;
1186 
1187  /* check for improvement in number of fractionals */
1188  nfracs = SCIPgetNLPBranchCands(scip);
1189  if( nfracs < bestnfracs )
1190  {
1191  bestnfracs = nfracs;
1192  nstallloops = 0;
1193  }
1194  else
1195  nstallloops++;
1196 
1197  SCIPdebugMessage(" -> loop finished: %d fractional variables (stall: %d/%d, iterations: %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT")\n",
1198  nfracs, nstallloops, maxstallloops, heurdata->nlpiterations, adjustedMaxNLPIterations(maxnlpiterations, nsolsfound, nstallloops));
1199  }
1200 
1201  /* try final solution, if no more fractional variables are left */
1202  if( nfracs == 0 && !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
1203  {
1204  success = FALSE;
1205 
1206  SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
1207  SCIPdebugMessage("feasibility pump found solution (%d fractional variables)\n", nfracs);
1208  SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );
1209  if( success )
1210  *result = SCIP_FOUNDSOL;
1211  }
1212 
1213  /* end diving */
1214  SCIP_CALL( SCIPendDive(scip) );
1215 
1216  /* end probing in order to be able to apply stage 3 */
1217  if( heurdata->usefp20 )
1218  {
1219  SCIP_CALL( SCIPendProbing(probingscip) );
1220  }
1221 
1222  /*if( heurdata->usefp20 )
1223  {
1224  SCIP_CALL( SCIPprintStatistics(probingscip, NULL) );
1225  }*/
1226 
1227  /* only do stage 3 if we have not found a solution yet */
1228  /* only do stage 3 if the distance of the closest infeasible solution to the polyhedron is below a certain threshold */
1229  if( heurdata->stage3 && (*result != SCIP_FOUNDSOL) && SCIPisLE(scip, mindistance, (SCIP_Real) heurdata->neighborhoodsize) )
1230  {
1231  /* setup some parameters for the sub-SCIP */
1232  SCIP_Real timelimit;
1233  SCIP_Real memorylimit;
1234 
1235  assert(closestsol != NULL);
1236  assert(!SCIPisInfinity(scip, mindistance) || nloops == 0);
1237 
1238  /* if we do not use feasibility pump 2.0, we have not created a copied SCIP instance yet */
1239  if( heurdata->usefp20 )
1240  {
1241  assert(probingscip != NULL);
1242  SCIP_CALL( SCIPfreeTransform(probingscip) );
1243  }
1244  else
1245  {
1246  assert(probingscip == NULL);
1247  SCIP_CALL( setupProbingSCIP(scip, &probingscip, &varmapfw, heurdata->copycuts, &success) );
1248  }
1249 
1250  /* check whether there is enough time and memory left */
1251  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
1252  if( !SCIPisInfinity(scip, timelimit) )
1253  timelimit -= SCIPgetSolvingTime(scip);
1254  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
1255 
1256  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
1257  if( !SCIPisInfinity(scip, memorylimit) )
1258  {
1259  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
1260  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
1261  }
1262 
1263  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
1264  if( timelimit > 0.0 && memorylimit > 2.0*SCIPgetMemExternEstim(scip)/1048576.0 )
1265  {
1266  SCIP_CALL( setupSCIPparamsStage3(scip, probingscip, timelimit, memorylimit) );
1267 
1268  /* the neighborhood size is double the distance plus another ten percent */
1269  mindistance = SCIPceil(scip, 2.2*mindistance);
1270 
1271  SCIP_CALL( addLocalBranchingConstraint(scip, probingscip, varmapfw, closestsol, mindistance) );
1272 
1273  /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
1274  * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
1275  */
1276 #ifdef NDEBUG
1277  retcode = SCIPsolve(probingscip);
1278  if( retcode != SCIP_OKAY )
1279  {
1280  SCIPwarningMessage(scip, "Error while solving sub-SCIP in stage 3 of feasibility pump heuristic; sub-SCIP terminated with code <%d>\n",
1281  retcode);
1282  }
1283 #else
1284  SCIP_CALL( SCIPsolve(probingscip) );
1285 #endif
1286  /* check, whether a solution was found */
1287  if( SCIPgetNSols(probingscip) > 0 )
1288  {
1289  success = FALSE;
1290  SCIP_CALL( createNewSols(scip, probingscip, varmapfw, heur, &success) );
1291  if( success )
1292  *result = SCIP_FOUNDSOL;
1293  }
1294  }
1295  }
1296 
1297  if( *result == SCIP_FOUNDSOL )
1298  heurdata->nsuccess++;
1299 
1300  /* free hash map and copied SCIP */
1301  if( varmapfw != NULL )
1302  SCIPhashmapFree(&varmapfw);
1303 
1304  if( probingscip != NULL )
1305  {
1306  SCIP_CALL( SCIPfree(&probingscip) );
1307  }
1308 
1309  if( heurdata->stage3 )
1310  {
1311  SCIP_CALL( SCIPfreeSol(scip, &closestsol) );
1312  }
1313 
1314  /* free memory */
1315  for( j = 0; j < heurdata->cyclelength; j++ )
1316  {
1317  SCIP_CALL( SCIPfreeSol(scip, &lastroundedsols[j]) );
1318  }
1319 
1320  SCIPfreeBufferArray(scip, &cycles);
1321  SCIPfreeBufferArray(scip, &lastalphas);
1322  SCIPfreeBufferArray(scip, &lastroundedsols);
1323  SCIPfreeBufferArray(scip, &mostfracvals);
1324  SCIPfreeBufferArray(scip, &mostfracvars);
1325 
1326  SCIPdebugMessage("feasibility pump finished [%d iterations done].\n", nloops);
1327 
1328 #ifdef SCIP_STATISTIC
1329  if( nfracs == 0 )
1330  {
1331  double objval;
1332  double primalBound;
1333 
1334  objval = SCIPgetSolOrigObj(scip, heurdata->sol);
1335  primalBound = SCIPgetPrimalbound(scip);
1336  SCIPstatisticMessage("feasibility pump found: 1, objval: %f, iterations: %d, primal bound: %f\n", objval, nloops, primalBound);
1337  }
1338  else
1339  {
1340  double primalBound;
1341 
1342  primalBound = SCIPgetPrimalbound(scip);
1343  SCIPstatisticMessage("feasibility pump found: 0, objval: +inf, iterations: %d, primal bound: %f\n", nloops, primalBound);
1344  }
1345 
1346 #endif /* SCIP_STATISTIC */
1347  return SCIP_OKAY;
1348 }
1349 
1350 
1351 /*
1352  * primal heuristic specific interface methods
1353  */
1354 
1355 /** creates the feaspump primal heuristic and includes it in SCIP */
1357  SCIP* scip /**< SCIP data structure */
1358  )
1359 {
1360  SCIP_HEURDATA* heurdata;
1361  SCIP_HEUR* heur;
1362 
1363  /* create Feaspump primal heuristic data */
1364  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
1365 
1366  /* include primal heuristic */
1367  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
1369  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecFeaspump, heurdata) );
1370 
1371  assert(heur != NULL);
1372 
1373  /* set non-NULL pointers to callback methods */
1374  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyFeaspump) );
1375  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeFeaspump) );
1376  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitFeaspump) );
1377  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitFeaspump) );
1378  SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolFeaspump) );
1379  SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolFeaspump) );
1380 
1381  /* add feaspump primal heuristic parameters */
1383  "heuristics/"HEUR_NAME"/maxlpiterquot",
1384  "maximal fraction of diving LP iterations compared to node LP iterations",
1385  &heurdata->maxlpiterquot, FALSE, DEFAULT_MAXLPITERQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1387  "heuristics/"HEUR_NAME"/objfactor",
1388  "factor by which the regard of the objective is decreased in each round, 1.0 for dynamic",
1389  &heurdata->objfactor, FALSE, DEFAULT_OBJFACTOR, 0.0, 1.0, NULL, NULL) );
1391  "heuristics/"HEUR_NAME"/alpha",
1392  "initial weight of the objective function in the convex combination",
1393  &heurdata->alpha, FALSE, DEFAULT_ALPHA, 0.0, 1.0, NULL, NULL) );
1395  "heuristics/"HEUR_NAME"/alphadiff",
1396  "threshold difference for the convex parameter to perform perturbation",
1397  &heurdata->alphadiff, FALSE, DEFAULT_ALPHADIFF, 0.0, 1.0, NULL, NULL) );
1398 
1399  SCIP_CALL( SCIPaddIntParam(scip,
1400  "heuristics/"HEUR_NAME"/maxlpiterofs",
1401  "additional number of allowed LP iterations",
1402  &heurdata->maxlpiterofs, FALSE, DEFAULT_MAXLPITEROFS, 0, INT_MAX, NULL, NULL) );
1403  SCIP_CALL( SCIPaddIntParam(scip,
1404  "heuristics/"HEUR_NAME"/maxsols",
1405  "total number of feasible solutions found up to which heuristic is called (-1: no limit)",
1406  &heurdata->maxsols, TRUE, DEFAULT_MAXSOLS, -1, INT_MAX, NULL, NULL) );
1407  SCIP_CALL( SCIPaddIntParam(scip,
1408  "heuristics/"HEUR_NAME"/maxloops",
1409  "maximal number of pumping loops (-1: no limit)",
1410  &heurdata->maxloops, TRUE, DEFAULT_MAXLOOPS, -1, INT_MAX, NULL, NULL) );
1411  SCIP_CALL( SCIPaddIntParam(scip,
1412  "heuristics/"HEUR_NAME"/maxstallloops",
1413  "maximal number of pumping rounds without fractionality improvement (-1: no limit)",
1414  &heurdata->maxstallloops, TRUE, DEFAULT_MAXSTALLLOOPS, -1, INT_MAX, NULL, NULL) );
1415  SCIP_CALL( SCIPaddIntParam(scip,
1416  "heuristics/"HEUR_NAME"/minflips",
1417  "minimum number of random variables to flip, if a 1-cycle is encountered",
1418  &heurdata->minflips, TRUE, DEFAULT_MINFLIPS, 1, INT_MAX, NULL, NULL) );
1419  SCIP_CALL( SCIPaddIntParam(scip,
1420  "heuristics/"HEUR_NAME"/cyclelength",
1421  "maximum length of cycles to be checked explicitly in each round",
1422  &heurdata->cyclelength, TRUE, DEFAULT_CYCLELENGTH, 1, 100, NULL, NULL) );
1423  SCIP_CALL( SCIPaddIntParam(scip,
1424  "heuristics/"HEUR_NAME"/perturbfreq",
1425  "number of iterations until a random perturbation is forced",
1426  &heurdata->perturbfreq, TRUE, DEFAULT_PERTURBFREQ, 1, INT_MAX, NULL, NULL) );
1427  SCIP_CALL( SCIPaddIntParam(scip, "heuristics/"HEUR_NAME"/neighborhoodsize",
1428  "radius (using Manhattan metric) of the neighborhood to be searched in stage 3",
1429  &heurdata->neighborhoodsize, FALSE, DEFAULT_NEIGHBORHOODSIZE, 1, INT_MAX, NULL, NULL) );
1430 
1432  "heuristics/"HEUR_NAME"/beforecuts",
1433  "should the feasibility pump be called at root node before cut separation?",
1434  &heurdata->beforecuts, FALSE, DEFAULT_BEFORECUTS, NULL, NULL) );
1436  "heuristics/"HEUR_NAME"/usefp20",
1437  "should an iterative round-and-propagate scheme be used to find the integral points?",
1438  &heurdata->usefp20, FALSE, DEFAULT_USEFP20, NULL, NULL) );
1440  "heuristics/"HEUR_NAME"/pertsolfound",
1441  "should a random perturbation be performed if a feasible solution was found?",
1442  &heurdata->pertsolfound, FALSE, DEFAULT_PERTSOLFOUND, NULL, NULL) );
1444  "heuristics/"HEUR_NAME"/stage3",
1445  "should we solve a local branching sub-MIP if no solution could be found?",
1446  &heurdata->stage3, FALSE, DEFAULT_STAGE3, NULL, NULL) );
1447  SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/"HEUR_NAME"/copycuts",
1448  "should all active cuts from cutpool be copied to constraints in subproblem?",
1449  &heurdata->copycuts, TRUE, DEFAULT_COPYCUTS, NULL, NULL) );
1450 
1451  return SCIP_OKAY;
1452 }
1453