Scippy

SCIP

Solving Constraint Integer Programs

heur_crossover.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_crossover.c
17  * @brief crossover primal heuristic
18  * @author Timo Berthold
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <assert.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include "scip/scip.h"
27 #include "scip/scipdefplugins.h"
28 #include "scip/cons_linear.h"
29 #include "scip/heur_crossover.h"
30 #include "scip/pub_misc.h"
31 
32 #define HEUR_NAME "crossover"
33 #define HEUR_DESC "LNS heuristic that fixes all variables that are identic in a couple of solutions"
34 #define HEUR_DISPCHAR 'C'
35 #define HEUR_PRIORITY -1104000
36 #define HEUR_FREQ 30
37 #define HEUR_FREQOFS 0
38 #define HEUR_MAXDEPTH -1
39 #define HEUR_TIMING SCIP_HEURTIMING_AFTERNODE
40 #define HEUR_USESSUBSCIP TRUE /**< does the heuristic use a secondary SCIP instance? */
41 
42 #define DEFAULT_MAXNODES 5000LL /* maximum number of nodes to regard in the subproblem */
43 #define DEFAULT_MINIMPROVE 0.01 /* factor by which Crossover should at least improve the incumbent */
44 #define DEFAULT_MINNODES 50LL /* minimum number of nodes to regard in the subproblem */
45 #define DEFAULT_MINFIXINGRATE 0.666 /* minimum percentage of integer variables that have to be fixed */
46 #define DEFAULT_NODESOFS 500LL /* number of nodes added to the contingent of the total nodes */
47 #define DEFAULT_NODESQUOT 0.1 /* subproblem nodes in relation to nodes of the original problem */
48 #define DEFAULT_LPLIMFAC 2.0 /* factor by which the limit on the number of LP depends on the node limit */
49 #define DEFAULT_NUSEDSOLS 3 /* number of solutions that will be taken into account */
50 #define DEFAULT_NWAITINGNODES 200LL /* number of nodes without incumbent change heuristic should wait */
51 #define DEFAULT_RANDOMIZATION TRUE /* should the choice which sols to take be randomized? */
52 #define DEFAULT_DONTWAITATROOT FALSE /* should the nwaitingnodes parameter be ignored at the root node? */
53 #define DEFAULT_USELPROWS FALSE /* should subproblem be created out of the rows in the LP rows,
54  * otherwise, the copy constructors of the constraints handlers are used */
55 #define DEFAULT_COPYCUTS TRUE /* if DEFAULT_USELPROWS is FALSE, then should all active cuts from the
56  * cutpool of the original scip be copied to constraints of the subscip
57  */
58 #define DEFAULT_PERMUTE FALSE /* should the subproblem be permuted to increase diversification? */
59 #define HASHSIZE_SOLS 11113 /* size of hash table for solution tuples in crossover heuristic */
60 
61 /* event handler properties */
62 #define EVENTHDLR_NAME "Crossover"
63 #define EVENTHDLR_DESC "LP event handler for "HEUR_NAME" heuristic"
64 
65 /*
66  * Data structures
67  */
68 
69 typedef struct SolTuple SOLTUPLE;
70 
71 /** primal heuristic data */
72 struct SCIP_HeurData
73 {
74  SCIP_SOL* prevlastsol; /**< worst solution taken into account during the previous run */
75  SCIP_SOL* prevbestsol; /**< best solution during the previous run */
76  int prevnsols; /**< number of all solutions during the previous run */
77 
78  SCIP_Longint maxnodes; /**< maximum number of nodes to regard in the subproblem */
79  SCIP_Longint minnodes; /**< minimum number of nodes to regard in the subproblem */
80  SCIP_Longint nodesofs; /**< number of nodes added to the contingent of the total nodes */
81  SCIP_Longint usednodes; /**< nodes already used by crossover in earlier calls */
82  SCIP_Real nodesquot; /**< subproblem nodes in relation to nodes of the original problem */
83 
84  int nusedsols; /**< number of solutions that will be taken into account */
85  SCIP_Longint nwaitingnodes; /**< number of nodes without incumbent change heuristic should wait */
86  unsigned int nfailures; /**< number of failures since last successful call */
87  SCIP_Longint nextnodenumber; /**< number of nodes at which crossover should be called the next time */
88  SCIP_Real minfixingrate; /**< minimum percentage of integer variables that have to be fixed */
89  SCIP_Real minimprove; /**< factor by which Crossover should at least improve the incumbent */
90  SCIP_Real nodelimit; /**< the nodelimit employed in the current sub-SCIP, for the event handler*/
91  SCIP_Real lplimfac; /**< factor by which the limit on the number of LP depends on the node limit */
92  SCIP_Bool randomization; /**< should the choice which sols to take be randomized? */
93  SCIP_Bool dontwaitatroot; /**< should the nwaitingnodes parameter be ignored at the root node? */
94  unsigned int randseed; /**< seed value for random number generator */
95  SCIP_HASHTABLE* hashtable; /**< hashtable used to store the solution tuples already used */
96  SOLTUPLE* lasttuple; /**< last tuple of solutions created by crossover */
97  SCIP_Bool uselprows; /**< should subproblem be created out of the rows in the LP rows? */
98  SCIP_Bool copycuts; /**< if uselprows == FALSE, should all active cuts from cutpool be copied
99  * to constraints in subproblem? */
100  SCIP_Bool permute; /**< should the subproblem be permuted to increase diversification? */
101 };
102 
103 /** n-tuple of solutions and their hashkey */
104 struct SolTuple
105 {
106  int* indices; /**< sorted array of solution indices */
107  int size; /**< size of the array (should be heurdata->nusedsols) */
108  unsigned int key; /**< hashkey of the tuple */
109  SOLTUPLE* prev; /**< previous solution tuple created */
110 };
111 
112 
113 /*
114  * Local methods
115  */
116 
118 /** gets the hash key of a solution tuple */
119 static
120 SCIP_DECL_HASHGETKEY(hashGetKeySols)
121 { /*lint --e{715}*/
122  return elem;
123 }
124 
126 /** returns TRUE iff both solution tuples are identical */
127 static
128 SCIP_DECL_HASHKEYEQ(hashKeyEqSols)
129 { /*lint --e{715}*/
130  int i;
131  int size;
132 
133  int* indices1;
134  int* indices2;
135 
136  indices1 = ((SOLTUPLE*)key1)->indices;
137  indices2 = ((SOLTUPLE*)key2)->indices;
138 
139  /* there should be two nonempty arrays of the same size */
140  assert(indices1 != NULL);
141  assert(indices2 != NULL);
142  assert(((SOLTUPLE*)key1)->size == ((SOLTUPLE*)key2)->size);
143 
144  size = ((SOLTUPLE*)key1)->size;
145 
146  /* compare arrays by components, return TRUE, iff equal */
147  for( i = 0; i < size; i++ )
148  {
149  if( indices1[i] != indices2[i] )
150  return FALSE;
151  }
152 
153  return TRUE;
154 }
155 
157 /** returns hashkey of a solution tuple */
158 static
159 SCIP_DECL_HASHKEYVAL(hashKeyValSols)
160 { /*lint --e{715}*/
161  return ((SOLTUPLE*)key)->key;
162 }
163 
165 /** calculates a hash key for a given tuple of solution indices */
166 static
167 unsigned int calculateHashKey(
168  int* indices, /**< indices of solutions */
169  int size /**< number of solutions */
170  )
171 {
172  int i;
173  unsigned int hashkey;
174 
175  /* hashkey should be (x1+1) * (x2+1) * ... * (xn+1) + x1 + x2 + ... + xn */
176  hashkey = 1;
177  for( i = 0; i < size; i++ )
178  hashkey *= indices[i] + 1;
179  for( i = 0; i < size; i++ )
180  hashkey += indices[i];
181 
182  return hashkey;
183 }
185 
186 /** insertion sort for a small int array */
187 static void sortArray(
188  int* a, /**< array to be sorted */
189  int size /**< size of array */
190  )
191 {
192  int i;
193  int j;
194  int tmp;
195 
196  /* simple insertion sort algorithm */
197  for( i = 1; i < size; i++ )
198  {
199  tmp = a[i];
200  j = i-1;
201  while( j >= 0 && a[j] > tmp )
202  {
203  a[j+1] = a[j];
204  j = j-1;
205  }
206  a[j+1] = tmp;
207  }
208 }
209 
211 /** creates a new tuple of solutions */
212 static
214  SCIP* scip, /**< original SCIP data structure */
215  SOLTUPLE** elem, /**< tuple of solutions which should be created */
216  int* indices, /**< indices of solutions */
217  int size, /**< number of solutions */
218  SCIP_HEURDATA* heurdata /**< primal heuristic data */
219  )
220 {
221  /* memory allocation */
222  SCIP_CALL( SCIPallocBlockMemory(scip, elem) );
223  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*elem)->indices,size) );
224  BMScopyMemoryArray((*elem)->indices, indices, size);
225 
226  /* data input */
227  sortArray(indices,size);
228  (*elem)->size = size;
229  (*elem)->key = calculateHashKey((*elem)->indices, (*elem)->size);
230  (*elem)->prev = heurdata->lasttuple;
231 
232  /* update heurdata */
233  heurdata->lasttuple = *elem;
234  return SCIP_OKAY;
235 }
237 /* checks whether the new solution was found at the same node by the same heuristic as an already selected one */
238 static
240  SCIP_SOL** sols, /**< feasible SCIP solutions */
241  int* selection, /**< pool of solutions crossover uses */
242  int selectionsize, /**< size of solution pool */
243  int newsol /**< candidate solution */
244 )
245 {
246  int i;
247 
248  for( i = 0; i < selectionsize; i++)
249  if( SCIPsolGetHeur(sols[selection[i]]) == SCIPsolGetHeur(sols[newsol])
250  && SCIPsolGetNodenum(sols[selection[i]]) == SCIPsolGetNodenum(sols[newsol]) )
251  return FALSE;
252 
253  return TRUE;
254 }
256 /** randomly selects the solutions crossover will use from the pool of all solutions found so far */
257 static
259  SCIP* scip, /**< original SCIP data structure */
260  int* selection, /**< pool of solutions crossover uses */
261  SCIP_HEURDATA* heurdata, /**< primal heuristic data */
262  SCIP_Bool* success /**< pointer to store whether the process was successful */
263  )
264 {
265 
266  int i;
267  int j;
268  int lastsol; /* the worst solution possible to choose */
269  int nusedsols; /* number of solutions which will be chosen */
270 
271  SOLTUPLE* elem;
272  SCIP_SOL** sols;
273 
274  /* initialization */
275  nusedsols = heurdata->nusedsols;
276  lastsol = SCIPgetNSols(scip);
277  sols = SCIPgetSols(scip);
278  assert(nusedsols < lastsol);
279 
280  i = 0;
281  *success = FALSE;
282 
283  /* perform at maximum 10 restarts and stop as soon as a new set of solutions is found */
284  while( !*success && i < 10 )
285  {
286  SCIP_Bool validtuple;
287 
288  validtuple = TRUE;
289  for( j = 0; j < nusedsols && validtuple; j++ )
290  {
291  int k;
292  k = SCIPgetRandomInt(nusedsols-j-1, lastsol-1, &heurdata->randseed);
293 
294  /* ensure that the solution does not have a similar source as the others */
295  while( k >= nusedsols-j-1 && !solHasNewSource(sols, selection, j, k) )
296  k--;
297 
298  validtuple = (k >= nusedsols-j-1);
299  selection[j] = k;
300  lastsol = k;
301  }
302 
303  if( validtuple )
304  {
305  /* creates an object ready to be inserted into the hashtable */
306  SCIP_CALL( createSolTuple(scip, &elem, selection, nusedsols, heurdata) );
307 
308  /* check whether the randomized set is already in the hashtable, if not, insert it */
309  if( !SCIPhashtableExists(heurdata->hashtable, elem) )
310  {
311  SCIP_CALL( SCIPhashtableInsert(heurdata->hashtable, elem) );
312  *success = TRUE;
313  }
314  }
315  i++;
316  }
317 
318  return SCIP_OKAY;
319 }
321 
322 /** creates the all variables of the subproblem */
324  SCIP* scip, /**< original SCIP data structure */
325  SCIP* subscip, /**< SCIP data structure for the subproblemd */
326  SCIP_VAR** subvars, /**< the variables of the subproblem */
327  int* selection, /**< pool of solutions crossover will use */
328  SCIP_HEURDATA* heurdata, /**< primal heuristic data */
329  SCIP_Bool* success /**< pointer to store whether the problem was created successfully */
330  )
331 {
332  SCIP_VAR** vars; /* original scip variables */
333  SCIP_SOL** sols; /* pool of solutions */
334  SCIP_Real fixingrate; /* percentage of variables that are fixed */
335 
336  int nvars;
337  int nbinvars;
338  int nintvars;
339 
340  int i;
341  int j;
342  int fixingcounter;
343 
344  sols = SCIPgetSols(scip);
345  assert(sols != NULL);
346 
347  /* get required data of the original problem */
348  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
349 
350  fixingcounter = 0;
351 
352  /* create the binary and general integer variables of the subproblem */
353  for( i = 0; i < nbinvars + nintvars; i++ )
354  {
355  SCIP_Real solval;
356  SCIP_Bool fixable;
357 
358  fixable = TRUE;
359  solval = SCIPgetSolVal(scip, sols[selection[0]], vars[i]);
360 
361  /* check, whether variable's value is identical for each selected solution */
362  for( j = 1; j < heurdata->nusedsols; j++ )
363  {
364  SCIP_Real varsolval;
365  varsolval = SCIPgetSolVal(scip, sols[selection[j]], vars[i]);
366  if( REALABS(solval - varsolval) > 0.5 )
367  {
368  fixable = FALSE;
369  break;
370  }
371  }
372 
373  /* original solval can be outside transformed global bounds */
374  fixable = fixable && SCIPvarGetLbGlobal(vars[i]) <= solval && solval <= SCIPvarGetUbGlobal(vars[i]);
375 
376  /* if solutions' values are equal, variable is fixed in the subproblem */
377  if( fixable )
378  {
379  SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], solval) );
380  SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], solval) );
381  fixingcounter++;
382  }
383  }
384 
385  fixingrate = (SCIP_Real)fixingcounter / (SCIP_Real)(MAX(nbinvars + nintvars, 1));
386 
387  /* if all variables were fixed or amount of fixed variables is insufficient, skip residual part of
388  * subproblem creation and abort immediately */
389  *success = fixingcounter < nbinvars + nintvars && fixingrate >= heurdata->minfixingrate;
390 
391  return SCIP_OKAY;
392 }
394 /** creates the rows of the subproblem */
395 static
397  SCIP* scip, /**< original SCIP data structure */
398  SCIP* subscip, /**< SCIP data structure for the subproblem */
399  SCIP_VAR** subvars /**< the variables of the subproblem */
400  )
401 {
402  SCIP_ROW** rows; /* original scip rows */
403  SCIP_CONS* cons; /* new constraint */
404  SCIP_VAR** consvars; /* new constraint's variables */
405  SCIP_COL** cols; /* original row's columns */
406 
407  SCIP_Real constant; /* constant added to the row */
408  SCIP_Real lhs; /* left hand side of the row */
409  SCIP_Real rhs; /* left right side of the row */
410  SCIP_Real* vals; /* variables' coefficient values of the row */
411 
412  int nrows;
413  int nnonz;
414  int i;
415  int j;
416 
417  /* get the rows and their number */
418  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
419 
420  /* copy all rows to linear constraints */
421  for( i = 0; i < nrows; i++ )
422  {
423  /* ignore rows that are only locally valid */
424  if( SCIProwIsLocal(rows[i]) )
425  continue;
426 
427  /* get the row's data */
428  constant = SCIProwGetConstant(rows[i]);
429  lhs = SCIProwGetLhs(rows[i]) - constant;
430  rhs = SCIProwGetRhs(rows[i]) - constant;
431  vals = SCIProwGetVals(rows[i]);
432  nnonz = SCIProwGetNNonz(rows[i]);
433  cols = SCIProwGetCols(rows[i]);
434 
435  assert(lhs <= rhs);
436 
437  /* allocate memory array to be filled with the corresponding subproblem variables */
438  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nnonz) );
439  for( j = 0; j < nnonz; j++ )
440  consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))];
441 
442  /* create a new linear constraint and add it to the subproblem */
443  SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs,
444  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
445  SCIP_CALL( SCIPaddCons(subscip, cons) );
446  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
447 
448  /* free temporary memory */
449  SCIPfreeBufferArray(scip, &consvars);
450  }
451 
452  return SCIP_OKAY;
453 }
455 /** creates a subproblem for subscip by fixing a number of variables */
456 static
458  SCIP* scip, /**< original SCIP data structure */
459  SCIP* subscip, /**< SCIP data structure for the subproblem */
460  SCIP_VAR** subvars, /**< the variables of the subproblem */
461  int* selection, /**< pool of solutions crossover will use */
462  SCIP_HEURDATA* heurdata, /**< primal heuristic data */
463  SCIP_Bool* success /**< pointer to store whether the problem was created successfully */
464  )
465 {
466  SCIP_SOL** sols; /* array of all solutions found so far */
467  int nsols; /* number of all solutions found so far */
468  int nusedsols; /* number of solutions to use in crossover */
469 
470  int i;
471  char consname[SCIP_MAXSTRLEN];
472 
473  /* get solutions' data */
474  nsols = SCIPgetNSols(scip);
475  sols = SCIPgetSols(scip);
476  nusedsols = heurdata->nusedsols;
477 
478  assert(nusedsols > 1);
479  assert(nsols >= nusedsols);
480 
481  /* use nusedsols best solutions if randomization is deactivated or there are only nusedsols solutions at hand
482  * or a good new solution was found since last call */
483  if( !heurdata->randomization || nsols == nusedsols || heurdata->prevlastsol != sols[nusedsols-1] )
484  {
485  SOLTUPLE* elem;
486  SCIP_HEUR* solheur;
487  SCIP_Longint solnodenum;
488  SCIP_Bool allsame;
489 
490  for( i = 0; i < nusedsols; i++ )
491  selection[i] = i;
492  SCIP_CALL( createSolTuple(scip, &elem, selection, nusedsols, heurdata) );
493 
494  solheur = SCIPsolGetHeur(sols[0]);
495  solnodenum = SCIPsolGetNodenum(sols[0]);
496  allsame = TRUE;
497 
498  /* check, whether all solutions have been found by the same heuristic at the same node; in this case we do not run
499  * crossover, since it would probably just optimize over the same space as the other heuristic
500  */
501  for( i = 1; i < nusedsols; i++ )
502  {
503  if( SCIPsolGetHeur(sols[i]) != solheur || SCIPsolGetNodenum(sols[i]) != solnodenum )
504  allsame = FALSE;
505  }
506  *success = !allsame && !SCIPhashtableExists(heurdata->hashtable, elem);
507 
508  /* check, whether solution tuple has already been tried */
509  if( !SCIPhashtableExists(heurdata->hashtable, elem) )
510  {
511  SCIP_CALL( SCIPhashtableInsert(heurdata->hashtable, elem) );
512  }
513 
514  /* if solution tuple has already been tried, randomization is allowed and enough solutions are at hand, try
515  * to randomize another tuple. E.g., this can happen if the last crossover solution was among the best ones */
516  if( !(*success) && heurdata->randomization && nsols > nusedsols )
517  {
518  SCIP_CALL( selectSolsRandomized(scip, selection, heurdata, success) );
519  }
520 
521  }
522  /* otherwise randomize the set of solutions */
523  else
524  {
525  SCIP_CALL( selectSolsRandomized(scip, selection, heurdata, success) );
526  }
527 
528  /* no acceptable solution tuple could be created */
529  if( !(*success) )
530  return SCIP_OKAY;
531 
532  /* get name of the original problem and add the string "_crossoversub" */
533  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_crossoversub", SCIPgetProbName(scip));
534 
535  /* set up the variables of the subproblem */
536  SCIP_CALL( fixVariables(scip, subscip, subvars, selection, heurdata, success) );
537 
538  /* we copy the rows of the LP, if the enough variables could be fixed and we work on the MIP
539  relaxation of the problem */
540  if( *success && heurdata->uselprows )
541  {
542  SCIP_CALL( createRows(scip, subscip, subvars) );
543  }
544 
545  return SCIP_OKAY;
546 }
547 
549 /** creates a new solution for the original problem by copying the solution of the subproblem */
550 static
552  SCIP* scip, /**< original SCIP data structure */
553  SCIP* subscip, /**< SCIP structure of the subproblem */
554  SCIP_VAR** subvars, /**< the variables of the subproblem */
555  SCIP_HEUR* heur, /**< crossover heuristic structure */
556  SCIP_SOL* subsol, /**< solution of the subproblem */
557  int* solindex, /**< index of the solution */
558  SCIP_Bool* success /**< used to store whether new solution was found or not */
559  )
560 {
561  SCIP_VAR** vars; /* the original problem's variables */
562  int nvars;
563  SCIP_SOL* newsol; /* solution to be created for the original problem */
564  SCIP_Real* subsolvals; /* solution values of the subproblem */
565 
566  assert(scip != NULL);
567  assert(subscip != NULL);
568  assert(subvars != NULL);
569  assert(subsol != NULL);
570 
571  /* get variables' data */
572  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
573  /* sub-SCIP may have more variables than the number of active (transformed) variables in the main SCIP
574  * since constraint copying may have required the copy of variables that are fixed in the main SCIP
575  */
576  assert(nvars <= SCIPgetNOrigVars(subscip));
577 
578  SCIP_CALL( SCIPallocBufferArray(scip, &subsolvals, nvars) );
579 
580  /* copy the solution */
581  SCIP_CALL( SCIPgetSolVals(subscip, subsol, nvars, subvars, subsolvals) );
582 
583  /* create new solution for the original problem */
584  SCIP_CALL( SCIPcreateSol(scip, &newsol, heur) );
585  SCIP_CALL( SCIPsetSolVals(scip, newsol, nvars, vars, subsolvals) );
586  *solindex = SCIPsolGetIndex(newsol);
587 
588  /* try to add new solution to scip and free it immediately */
589  SCIP_CALL( SCIPtrySolFree(scip, &newsol, FALSE, TRUE, TRUE, TRUE, success) );
590 
591  SCIPfreeBufferArray(scip, &subsolvals);
592 
593  return SCIP_OKAY;
594 }
596 /** updates heurdata after a run of crossover */
597 static
599  SCIP* scip, /**< original SCIP data structure */
600  SCIP_HEURDATA* heurdata /**< primal heuristic data */
601  )
602 {
603  /* increase number of failures, calculate next node at which crossover should be called and update actual solutions */
604  heurdata->nfailures++;
605  heurdata->nextnodenumber = (heurdata->nfailures <= 25
606  ? SCIPgetNNodes(scip) + 100*(2LL << heurdata->nfailures) /*lint !e703*/
607  : SCIP_LONGINT_MAX);
608 }
609 
610 /* ---------------- Callback methods of event handler ---------------- */
611 
612 /* exec the event handler
613  *
614  * we interrupt the solution process
615  */
616 static
617 SCIP_DECL_EVENTEXEC(eventExecCrossover)
618 {
619  SCIP_HEURDATA* heurdata;
620 
621  assert(eventhdlr != NULL);
622  assert(eventdata != NULL);
623  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
624  assert(event != NULL);
625  assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_LPSOLVED);
626 
627  heurdata = (SCIP_HEURDATA*)eventdata;
628  assert(heurdata != NULL);
629 
630  /* interrupt solution process of sub-SCIP */
631  if( SCIPgetNLPs(scip) > heurdata->lplimfac * heurdata->nodelimit )
632  {
633  SCIPdebugMessage("interrupt after %"SCIP_LONGINT_FORMAT" LPs\n",SCIPgetNLPs(scip));
634  SCIP_CALL( SCIPinterruptSolve(scip) );
635  }
636 
637  return SCIP_OKAY;
638 }
639 
640 /*
641  * Callback methods of primal heuristic
642  */
644 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
645 static
646 SCIP_DECL_HEURCOPY(heurCopyCrossover)
647 { /*lint --e{715}*/
648  assert(scip != NULL);
649  assert(heur != NULL);
650  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
651 
652  /* call inclusion method of primal heuristic */
654 
655  return SCIP_OKAY;
656 }
658 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
659 static
660 SCIP_DECL_HEURFREE(heurFreeCrossover)
661 { /*lint --e{715}*/
662  SCIP_HEURDATA* heurdata;
663 
664  assert(heur != NULL);
665  assert(scip != NULL);
666 
667  /* get heuristic data */
668  heurdata = SCIPheurGetData(heur);
669  assert(heurdata != NULL);
670 
671  /* free heuristic data */
672  SCIPfreeMemory(scip, &heurdata);
673  SCIPheurSetData(heur, NULL);
674 
675  return SCIP_OKAY;
676 }
678 /** initialization method of primal heuristic (called after problem was transformed) */
679 static
680 SCIP_DECL_HEURINIT(heurInitCrossover)
681 { /*lint --e{715}*/
682  SCIP_HEURDATA* heurdata;
683 
684  assert(heur != NULL);
685  assert(scip != NULL);
686 
687  /* get heuristic's data */
688  heurdata = SCIPheurGetData(heur);
689  assert(heurdata != NULL);
690 
691  /* initialize data */
692  heurdata->usednodes = 0;
693  heurdata->prevlastsol = NULL;
694  heurdata->prevbestsol = NULL;
695  heurdata->randseed = 0;
696  heurdata->lasttuple = NULL;
697  heurdata->nfailures = 0;
698  heurdata->prevnsols = 0;
699  heurdata->nextnodenumber = 0;
700 
701  /* initialize hash table */
702  SCIP_CALL( SCIPhashtableCreate(&heurdata->hashtable, SCIPblkmem(scip), HASHSIZE_SOLS,
703  hashGetKeySols, hashKeyEqSols, hashKeyValSols, NULL) );
704  assert(heurdata->hashtable != NULL );
705 
706  return SCIP_OKAY;
707 }
709 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
710 static
711 SCIP_DECL_HEUREXIT(heurExitCrossover)
712 { /*lint --e{715}*/
713  SCIP_HEURDATA* heurdata;
714  SOLTUPLE* soltuple;
715 
716  assert(heur != NULL);
717  assert(scip != NULL);
718 
719  /* get heuristic data */
720  heurdata = SCIPheurGetData(heur);
721  assert(heurdata != NULL);
722  soltuple = heurdata->lasttuple;
723 
724  /* free all soltuples iteratively */
725  while( soltuple != NULL )
726  {
727  SOLTUPLE* tmp;
728  tmp = soltuple->prev;
729  SCIPfreeBlockMemoryArray(scip,&soltuple->indices,soltuple->size);
730  SCIPfreeBlockMemory(scip,&soltuple);
731  soltuple = tmp;
732  }
733 
734  /* free hash table */
735  assert(heurdata->hashtable != NULL );
736  SCIPhashtableFree(&heurdata->hashtable);
737 
738  return SCIP_OKAY;
739 }
740 
742 /** execution method of primal heuristic */
743 static
744 SCIP_DECL_HEUREXEC(heurExecCrossover)
745 { /*lint --e{715}*/
746  SCIP_HEURDATA* heurdata; /* primal heuristic data */
747  SCIP* subscip; /* the subproblem created by crossover */
748  SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */
749  SCIP_EVENTHDLR* eventhdlr; /* event handler for LP events */
750 
751  SCIP_VAR** vars; /* original problem's variables */
752  SCIP_VAR** subvars; /* subproblem's variables */
753  SCIP_SOL** sols;
754 
755  SCIP_Real memorylimit; /* memory limit for the subproblem */
756  SCIP_Real timelimit; /* time limit for the subproblem */
757  SCIP_Real cutoff; /* objective cutoff for the subproblem */
758  SCIP_Real upperbound;
759  SCIP_Bool success;
760 
761  SCIP_Longint nstallnodes; /* node limit for the subproblem */
762 
763  int* selection; /* pool of solutions crossover uses */
764  int nvars; /* number of original problem's variables */
765  int nbinvars;
766  int nintvars;
767  int nusedsols;
768  int i;
769 
770  SCIP_RETCODE retcode;
771 
772  assert(heur != NULL);
773  assert(scip != NULL);
774  assert(result != NULL);
775 
776  /* get heuristic's data */
777  heurdata = SCIPheurGetData(heur);
778  assert(heurdata != NULL);
779  nusedsols = heurdata->nusedsols;
780 
781  *result = SCIP_DELAYED;
782 
783  /* only call heuristic, if enough solutions are at hand */
784  if( SCIPgetNSols(scip) < nusedsols )
785  return SCIP_OKAY;
786 
787  sols = SCIPgetSols(scip);
788  assert(sols != NULL);
789 
790  /* if one good solution was found, heuristic should not be delayed any longer */
791  if( sols[nusedsols-1] != heurdata->prevlastsol )
792  {
793  heurdata->nextnodenumber = SCIPgetNNodes(scip);
794  if( sols[0] != heurdata->prevbestsol )
795  heurdata->nfailures = 0;
796  }
797  /* in nonrandomized mode: only recall heuristic, if at least one new good solution was found in the meantime */
798  else if( !heurdata->randomization )
799  return SCIP_OKAY;
800 
801  /* if heuristic should be delayed, wait until certain number of nodes is reached */
802  if( SCIPgetNNodes(scip) < heurdata->nextnodenumber )
803  return SCIP_OKAY;
804 
805  /* only call heuristic, if enough nodes were processed since last incumbent */
806  if( SCIPgetNNodes(scip) - SCIPgetSolNodenum(scip,SCIPgetBestSol(scip)) < heurdata->nwaitingnodes
807  && (SCIPgetDepth(scip) > 0 || !heurdata->dontwaitatroot) )
808  return SCIP_OKAY;
809 
810  *result = SCIP_DIDNOTRUN;
811 
812  /* calculate the maximal number of branching nodes until heuristic is aborted */
813  nstallnodes = (SCIP_Longint)(heurdata->nodesquot * SCIPgetNNodes(scip));
814 
815  /* reward Crossover if it succeeded often */
816  nstallnodes = (SCIP_Longint)
817  (nstallnodes * (1.0 + 2.0*(SCIPheurGetNBestSolsFound(heur)+1.0)/(SCIPheurGetNCalls(heur)+1.0)));
818 
819  /* count the setup costs for the sub-MIP as 100 nodes */
820  nstallnodes -= 100 * SCIPheurGetNCalls(heur);
821  nstallnodes += heurdata->nodesofs;
822 
823  /* determine the node limit for the current process */
824  nstallnodes -= heurdata->usednodes;
825  nstallnodes = MIN(nstallnodes, heurdata->maxnodes);
826 
827  /* check whether we have enough nodes left to call subproblem solving */
828  if( nstallnodes < heurdata->minnodes )
829  return SCIP_OKAY;
830 
831  if( SCIPisStopped(scip) )
832  return SCIP_OKAY;
833 
834  *result = SCIP_DIDNOTFIND;
835 
836  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
837  assert(nvars > 0);
838 
839  /* check whether discrete variables are available */
840  if( nbinvars == 0 && nintvars == 0 )
841  return SCIP_OKAY;
842 
843  /* initializing the subproblem */
844  SCIP_CALL( SCIPcreate(&subscip) );
845 
846  /* create the variable mapping hash map */
847  SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) );
848  success = FALSE;
849 
850  eventhdlr = NULL;
851 
852  if( heurdata->uselprows )
853  {
854  char probname[SCIP_MAXSTRLEN];
855 
856  /* copy all plugins */
858 
859  /* get name of the original problem and add the string "_crossoversub" */
860  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_crossoversub", SCIPgetProbName(scip));
861 
862  /* create the subproblem */
863  SCIP_CALL( SCIPcreateProb(subscip, probname, NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
864 
865  /* copy all variables */
866  SCIP_CALL( SCIPcopyVars(scip, subscip, varmapfw, NULL, TRUE) );
867  }
868  else
869  {
870  SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "crossover", TRUE, FALSE, TRUE, &success) );
871 
872  if( heurdata->copycuts )
873  {
874  /* copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */
875  SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, TRUE, NULL) );
876  }
877 
878  /* create event handler for LP events */
879  SCIP_CALL( SCIPincludeEventhdlrBasic(subscip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCrossover, NULL) );
880  if( eventhdlr == NULL )
881  {
882  SCIPerrorMessage("event handler for "HEUR_NAME" heuristic not found.\n");
883  return SCIP_PLUGINNOTFOUND;
884  }
885  }
886 
887  SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) );
888  SCIP_CALL( SCIPallocBufferArray(scip, &selection, nusedsols) );
889 
890  for( i = 0; i < nvars; i++ )
891  subvars[i] = (SCIP_VAR*) (size_t) SCIPhashmapGetImage(varmapfw, vars[i]);
892 
893  /* free hash map */
894  SCIPhashmapFree(&varmapfw);
895 
896  success = FALSE;
897 
898  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
899  /* create a new problem, which fixes variables with same value in a certain set of solutions */
900  SCIP_CALL( setupSubproblem(scip, subscip, subvars, selection, heurdata, &success) );
901 
902  heurdata->prevbestsol = SCIPgetBestSol(scip);
903  heurdata->prevlastsol = sols[heurdata->nusedsols-1];
904 
905  /* if creation of sub-SCIP was aborted (e.g. due to number of fixings), free sub-SCIP and abort */
906  if( !success )
907  {
908  *result = SCIP_DIDNOTRUN;
909 
910  /* this run will be counted as a failure since no new solution tuple could be generated or the neighborhood of the
911  * solution was not fruitful in the sense that it was too big
912  */
913  updateFailureStatistic(scip, heurdata);
914 
915  goto TERMINATE;
916  }
917 
918  /* do not abort subproblem on CTRL-C */
919  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
920 
921  /* disable output to console */
922 
923 #ifdef SCIP_DEBUG
924  /* for debugging DINS, enable MIP output */
925  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) );
926  SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 1) );
927 #endif
928 
929  /* check whether there is enough time and memory left */
930  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
931  if( !SCIPisInfinity(scip, timelimit) )
932  timelimit -= SCIPgetSolvingTime(scip);
933  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
934 
935  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
936  if( !SCIPisInfinity(scip, memorylimit) )
937  {
938  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
939  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
940  }
941 
942  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
943  if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 )
944  goto TERMINATE;
945 
946  /* set limits for the subproblem */
947  heurdata->nodelimit = nstallnodes;
948  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nstallnodes) );
949  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
950  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
951 
952  /* forbid recursive call of heuristics and separators solving subMIPs */
953  SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
954 
955  /* disable cutting plane separation */
957 
958  /* disable expensive presolving */
960 
961  /* use best estimate node selection */
962  if( SCIPfindNodesel(subscip, "estimate") != NULL && !SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") )
963  {
964  SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) );
965  }
966 
967  /* use inference branching */
968  if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") )
969  {
970  SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) );
971  }
972 
973  /* disable conflict analysis */
974  if( !SCIPisParamFixed(subscip, "conflict/useprop") )
975  {
976  SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useprop", FALSE) );
977  }
978  if( !SCIPisParamFixed(subscip, "conflict/useinflp") )
979  {
980  SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useinflp", FALSE) );
981  }
982  if( !SCIPisParamFixed(subscip, "conflict/useboundlp") )
983  {
984  SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useboundlp", FALSE) );
985  }
986  if( !SCIPisParamFixed(subscip, "conflict/usesb") )
987  {
988  SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usesb", FALSE) );
989  }
990  if( !SCIPisParamFixed(subscip, "conflict/usepseudo") )
991  {
992  SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usepseudo", FALSE) );
993  }
994 
995  /* employ a limit on the number of enforcement rounds in the quadratic constraint handler; this fixes the issue that
996  * sometimes the quadratic constraint handler needs hundreds or thousands of enforcement rounds to determine the
997  * feasibility status of a single node without fractional branching candidates by separation (namely for uflquad
998  * instances); however, the solution status of the sub-SCIP might get corrupted by this; hence no deductions shall be
999  * made for the original SCIP
1000  */
1001  if( SCIPfindConshdlr(subscip, "quadratic") != NULL && !SCIPisParamFixed(subscip, "constraints/quadratic/enfolplimit") )
1002  {
1003  SCIP_CALL( SCIPsetIntParam(subscip, "constraints/quadratic/enfolplimit", 500) );
1004  }
1005 
1006  /* add an objective cutoff */
1007  cutoff = SCIPinfinity(scip);
1008  assert(!SCIPisInfinity(scip, SCIPgetUpperbound(scip)));
1009 
1010  upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip);
1011  if( !SCIPisInfinity(scip,-1.0*SCIPgetLowerbound(scip)) )
1012  {
1013  cutoff = (1-heurdata->minimprove)*SCIPgetUpperbound(scip) + heurdata->minimprove*SCIPgetLowerbound(scip);
1014  }
1015  else
1016  {
1017  if( SCIPgetUpperbound ( scip ) >= 0 )
1018  cutoff = ( 1 - heurdata->minimprove ) * SCIPgetUpperbound ( scip );
1019  else
1020  cutoff = ( 1 + heurdata->minimprove ) * SCIPgetUpperbound ( scip );
1021  }
1022  cutoff = MIN(upperbound, cutoff );
1023  SCIP_CALL( SCIPsetObjlimit(subscip, cutoff) );
1024 
1025  /* permute the subproblem to increase diversification */
1026  if( heurdata->permute )
1027  {
1028  SCIP_CALL( SCIPpermuteProb(subscip, (unsigned int) SCIPheurGetNCalls(heur), TRUE, TRUE, TRUE, TRUE, TRUE) );
1029  }
1030 
1031  /* catch LP events of sub-SCIP */
1032  if( !heurdata->uselprows )
1033  {
1034  assert(eventhdlr != NULL);
1035 
1036  SCIP_CALL( SCIPtransformProb(subscip) );
1037  SCIP_CALL( SCIPcatchEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, NULL) );
1038  }
1039 
1040  /* solve the subproblem */
1041  SCIPdebugMessage("Solve Crossover subMIP\n");
1042  retcode = SCIPsolve(subscip);
1043 
1044  /* drop LP events of sub-SCIP */
1045  if( !heurdata->uselprows )
1046  {
1047  assert(eventhdlr != NULL);
1048 
1049  SCIP_CALL( SCIPdropEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, -1) );
1050  }
1051 
1052  /* Errors in solving the subproblem should not kill the overall solving process.
1053  * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */
1054  if( retcode != SCIP_OKAY )
1055  {
1056 #ifndef NDEBUG
1057  SCIP_CALL( retcode );
1058 #endif
1059  SCIPwarningMessage(scip, "Error while solving subproblem in Crossover heuristic; sub-SCIP terminated with code <%d>\n", retcode);
1060  }
1061 
1062  /* print solving statistics of subproblem if we are in SCIP's debug mode */
1063  SCIPdebug( SCIP_CALL( SCIPprintStatistics(subscip, NULL) ) );
1064 
1065  heurdata->usednodes += SCIPgetNNodes(subscip);
1066 
1067  /* check, whether a solution was found */
1068  if( SCIPgetNSols(subscip) > 0 )
1069  {
1070  SCIP_SOL** subsols;
1071  int nsubsols;
1072  int solindex; /* index of the solution created by crossover */
1073 
1074  /* check, whether a solution was found;
1075  * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */
1076  nsubsols = SCIPgetNSols(subscip);
1077  subsols = SCIPgetSols(subscip);
1078  success = FALSE;
1079  solindex = -1;
1080  for( i = 0; i < nsubsols && !success; ++i )
1081  {
1082  SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &solindex, &success) );
1083  }
1084 
1085  if( success )
1086  {
1087  int tmp;
1088 
1089  assert(solindex != -1);
1090 
1091  *result = SCIP_FOUNDSOL;
1092 
1093  /* insert all crossings of the new solution and (nusedsols-1) of its parents into the hashtable
1094  * in order to avoid incest ;)
1095  */
1096  for( i = 0; i < nusedsols; i++ )
1097  {
1098  SOLTUPLE* elem;
1099  tmp = selection[i];
1100  selection[i] = solindex;
1101 
1102  SCIP_CALL( createSolTuple(scip, &elem, selection, nusedsols, heurdata) );
1103  SCIP_CALL( SCIPhashtableInsert(heurdata->hashtable, elem) );
1104  selection[i] = tmp;
1105  }
1106 
1107  /* if solution was among the best ones, crossover should not be called until another good solution was found */
1108  if( !heurdata->randomization )
1109  {
1110  heurdata->prevbestsol = SCIPgetBestSol(scip);
1111  heurdata->prevlastsol = SCIPgetSols(scip)[heurdata->nusedsols-1];
1112  }
1113  }
1114 
1115  /* if solution is not better then incumbent or could not be added to problem => run is counted as a failure */
1116  if( !success || solindex != SCIPsolGetIndex(SCIPgetBestSol(scip)) )
1117  updateFailureStatistic(scip, heurdata);
1118  }
1119  else
1120  {
1121  /* if no new solution was found, run was a failure */
1122  updateFailureStatistic(scip, heurdata);
1123  }
1124 
1125  TERMINATE:
1126  /* free subproblem */
1127  SCIPfreeBufferArray(scip, &selection);
1128  SCIPfreeBufferArray(scip, &subvars);
1129  SCIP_CALL( SCIPfree(&subscip) );
1130 
1131  return SCIP_OKAY;
1132 }
1133 
1134 
1135 /*
1136  * primal heuristic specific interface methods
1137  */
1138 
1139 /** creates the crossover primal heuristic and includes it in SCIP */
1141  SCIP* scip /**< SCIP data structure */
1142  )
1143 {
1144  SCIP_HEURDATA* heurdata;
1145  SCIP_HEUR* heur;
1146 
1147  /* create Crossover primal heuristic data */
1148  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
1149 
1150  /* include primal heuristic */
1151  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
1153  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecCrossover, heurdata) );
1154 
1155  assert(heur != NULL);
1156 
1157  /* set non-NULL pointers to callback methods */
1158  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyCrossover) );
1159  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeCrossover) );
1160  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitCrossover) );
1161  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitCrossover) );
1162 
1163  /* add crossover primal heuristic parameters */
1164 
1165  SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/"HEUR_NAME"/nodesofs",
1166  "number of nodes added to the contingent of the total nodes",
1167  &heurdata->nodesofs, FALSE, DEFAULT_NODESOFS, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
1168 
1169  SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/"HEUR_NAME"/maxnodes",
1170  "maximum number of nodes to regard in the subproblem",
1171  &heurdata->maxnodes, TRUE, DEFAULT_MAXNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
1172 
1173  SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/"HEUR_NAME"/minnodes",
1174  "minimum number of nodes required to start the subproblem",
1175  &heurdata->minnodes, TRUE, DEFAULT_MINNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
1176 
1177  SCIP_CALL( SCIPaddIntParam(scip, "heuristics/"HEUR_NAME"/nusedsols",
1178  "number of solutions to be taken into account",
1179  &heurdata->nusedsols, FALSE, DEFAULT_NUSEDSOLS, 2, INT_MAX, NULL, NULL) );
1180 
1181  SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/"HEUR_NAME"/nwaitingnodes",
1182  "number of nodes without incumbent change that heuristic should wait",
1183  &heurdata->nwaitingnodes, TRUE, DEFAULT_NWAITINGNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
1184 
1185  SCIP_CALL( SCIPaddRealParam(scip, "heuristics/"HEUR_NAME"/nodesquot",
1186  "contingent of sub problem nodes in relation to the number of nodes of the original problem",
1187  &heurdata->nodesquot, FALSE, DEFAULT_NODESQUOT, 0.0, 1.0, NULL, NULL) );
1188 
1189  SCIP_CALL( SCIPaddRealParam(scip, "heuristics/"HEUR_NAME"/minfixingrate",
1190  "minimum percentage of integer variables that have to be fixed",
1191  &heurdata->minfixingrate, FALSE, DEFAULT_MINFIXINGRATE, 0.0, 1.0, NULL, NULL) );
1192 
1193  SCIP_CALL( SCIPaddRealParam(scip, "heuristics/"HEUR_NAME"/minimprove",
1194  "factor by which Crossover should at least improve the incumbent",
1195  &heurdata->minimprove, TRUE, DEFAULT_MINIMPROVE, 0.0, 1.0, NULL, NULL) );
1196 
1197  SCIP_CALL( SCIPaddRealParam(scip, "heuristics/"HEUR_NAME"/lplimfac",
1198  "factor by which the limit on the number of LP depends on the node limit",
1199  &heurdata->lplimfac, TRUE, DEFAULT_LPLIMFAC, 1.0, SCIP_REAL_MAX, NULL, NULL) );
1200 
1201  SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/"HEUR_NAME"/randomization",
1202  "should the choice which sols to take be randomized?",
1203  &heurdata->randomization, TRUE, DEFAULT_RANDOMIZATION, NULL, NULL) );
1204 
1205  SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/"HEUR_NAME"/dontwaitatroot",
1206  "should the nwaitingnodes parameter be ignored at the root node?",
1207  &heurdata->dontwaitatroot, TRUE, DEFAULT_DONTWAITATROOT, NULL, NULL) );
1208 
1209  SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/"HEUR_NAME"/uselprows",
1210  "should subproblem be created out of the rows in the LP rows?",
1211  &heurdata->uselprows, TRUE, DEFAULT_USELPROWS, NULL, NULL) );
1212 
1213  SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/"HEUR_NAME"/copycuts",
1214  "if uselprows == FALSE, should all active cuts from cutpool be copied to constraints in subproblem?",
1215  &heurdata->copycuts, TRUE, DEFAULT_COPYCUTS, NULL, NULL) );
1216 
1217  SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/"HEUR_NAME"/permute",
1218  "should the subproblem be permuted to increase diversification?",
1219  &heurdata->permute, TRUE, DEFAULT_PERMUTE, NULL, NULL) );
1220 
1221  return SCIP_OKAY;
1222 }
1223