Scippy

SCIP

Solving Constraint Integer Programs

heur_twoopt.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-2016 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_twoopt.c
17  * @brief primal heuristic to improve incumbent solution by flipping pairs of variables
18  * @author Timo Berthold
19  * @author Gregor Hendel
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 #include "scip/heur_twoopt.h"
27 
28 #define HEUR_NAME "twoopt"
29 #define HEUR_DESC "primal heuristic to improve incumbent solution by flipping pairs of variables"
30 #define HEUR_DISPCHAR 'B'
31 #define HEUR_PRIORITY -20100
32 #define HEUR_FREQ -1
33 #define HEUR_FREQOFS 0
34 #define HEUR_MAXDEPTH -1
35 
36 #define HEUR_TIMING SCIP_HEURTIMING_AFTERNODE
37 #define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
38 
39 /* default parameter values */
40 #define DEFAULT_INTOPT FALSE /**< optional integer optimization is applied by default */
41 #define DEFAULT_WAITINGNODES 0 /**< default number of nodes to wait after current best solution before calling heuristic */
42 #define DEFAULT_MATCHINGRATE 0.5 /**< default percentage by which two variables have to match in their LP-row set to be
43  * associated as pair by heuristic */
44 #define DEFAULT_MAXNSLAVES 199 /**< default number of slave candidates for a master variable */
45 #define DEFAULT_ARRAYSIZE 10 /**< the default array size for temporary arrays */
46 
47 
48 /*
49  * Data structures
50  */
51 
52 /** primal heuristic data */
53 struct SCIP_HeurData
54 {
55  int lastsolindex; /**< index of last solution for which heuristic was performed */
56  SCIP_Real matchingrate; /**< percentage by which two variables have have to match in their LP-row
57  * set to be associated as pair by heuristic */
58  SCIP_VAR** binvars; /**< Array of binary variables which are sorted with respect to their occurrence
59  * in the LP-rows */
60  int nbinvars; /**< number of binary variables stored in heuristic array */
61  int waitingnodes; /**< user parameter to determine number of nodes to wait after last best solution
62  * before calling heuristic */
63  SCIP_Bool presolved; /**< flag to indicate whether presolving has already been executed */
64  int* binblockstart; /**< array to store the start indices of each binary block */
65  int* binblockend; /**< array to store the end indices of each binary block */
66  int nbinblocks; /**< number of blocks */
67 
68  /* integer variable twoopt data */
69  SCIP_Bool intopt; /**< parameter to determine if integer 2-opt should be applied */
70  SCIP_VAR** intvars; /**< array to store the integer variables in non-decreasing order
71  * with respect to their objective coefficient */
72  int nintvars; /**< the number of integer variables stored in array intvars */
73  int* intblockstart; /**< array to store the start indices of each binary block */
74  int* intblockend; /**< array to store the end indices of each binary block */
75  int nintblocks; /**< number of blocks */
76 
77  SCIP_Bool execute; /**< has presolveTwoOpt detected necessary structure for execution of heuristic? */
78  unsigned int randseed; /**< seed value for random number generator */
79  int maxnslaves; /**< delimits the maximum number of slave candidates for a master variable */
80 
81 #ifdef SCIP_STATISTIC
82  /* statistics */
83  int ntotalbinvars; /**< total number of binary variables over all runs */
84  int ntotalintvars; /**< total number of Integer variables over all runs */
85  int nruns; /**< counts the number of runs, i.e. the number of initialized
86  * branch and bound processes */
87  int maxbinblocksize; /**< maximum size of a binary block */
88  int maxintblocksize; /**< maximum size of an integer block */
89  int binnblockvars; /**< number of binary variables that appear in blocks */
90  int binnblocks; /**< number of blocks with at least two variables */
91  int intnblockvars; /**< number of Integer variables that appear in blocks */
92  int intnblocks; /**< number of blocks with at least two variables */
93  int binnexchanges; /**< number of executed changes of binary solution values leading to
94  * improvement in objective function */
95  int intnexchanges; /**< number of executed changes of Integer solution values leading to improvement in
96  * objective function */
97 #endif
98 };
99 
100 /** indicator for optimizing for binaries or integer variables */
101 enum Opttype
102 {
103  OPTTYPE_BINARY = 1,
105 };
106 typedef enum Opttype OPTTYPE;
108 /** indicator for direction of shifting variables */
109 enum Direction
110 {
111  DIRECTION_UP = 1,
114 };
115 typedef enum Direction DIRECTION;
117 /*
118  * Local methods
119  */
120 
121 /** Tries to switch the values of two binary or integer variables and checks feasibility with respect to the LP.
122  *
123  * @todo Adapt method not to copy entire activities array, but only the relevant region.
124  */
125 static
127  SCIP* scip, /**< scip instance */
128  SCIP_VAR* master, /**< first variable of variable pair */
129  SCIP_VAR* slave, /**< second variable of pair */
130  SCIP_Real mastersolval, /**< current value of variable1 in solution */
131  DIRECTION masterdir, /**< the direction into which the master variable has to be shifted */
132  SCIP_Real slavesolval, /**< current value of variable2 in solution */
133  DIRECTION slavedir, /**< the direction into which the slave variable has to be shifted */
134  SCIP_Real shiftval, /**< the value that variables should be shifted by */
135  SCIP_Real* activities, /**< the LP-row activities */
136  int nrows, /**< size of activities array */
137  SCIP_Bool* feasible /**< set to true if method has successfully switched the variable values */
138  )
139 { /*lint --e{715}*/
140  SCIP_COL* col;
141  SCIP_ROW** masterrows;
142  SCIP_ROW** slaverows;
143  SCIP_Real* mastercolvals;
144  SCIP_Real* slavecolvals;
145  int ncolmasterrows;
146  int ncolslaverows;
147  int i;
148  int j;
149 
150  assert(scip != NULL);
151  assert(master != NULL);
152  assert(slave != NULL);
153  assert(activities != NULL);
154  assert(SCIPisFeasGT(scip, shiftval, 0.0));
155 
156  assert(SCIPisFeasGE(scip, mastersolval + (int)masterdir * shiftval, SCIPvarGetLbGlobal(master)));
157  assert(SCIPisFeasLE(scip, mastersolval + (int)masterdir * shiftval, SCIPvarGetUbGlobal(master)));
158 
159  assert(SCIPisFeasGE(scip, slavesolval + (int)slavedir * shiftval, SCIPvarGetLbGlobal(slave)));
160  assert(SCIPisFeasLE(scip, slavesolval + (int)slavedir * shiftval, SCIPvarGetUbGlobal(slave)));
161 
162  /* get variable specific rows and coefficients for both master and slave. */
163  col = SCIPvarGetCol(master);
164  masterrows = SCIPcolGetRows(col);
165  mastercolvals = SCIPcolGetVals(col);
166  ncolmasterrows = SCIPcolGetNNonz(col);
167  assert(ncolmasterrows == 0 || masterrows != NULL);
168 
169  col = SCIPvarGetCol(slave);
170  slaverows = SCIPcolGetRows(col);
171  slavecolvals = SCIPcolGetVals(col);
172  ncolslaverows = SCIPcolGetNNonz(col);
173  assert(ncolslaverows == 0 || slaverows != NULL);
174 
175  /* update the activities of the LP rows of the master variable */
176  for( i = 0; i < ncolmasterrows && SCIProwGetLPPos(masterrows[i]) >= 0; ++i )
177  {
178  int rowpos;
179 
180  rowpos = SCIProwGetLPPos(masterrows[i]);
181  assert(rowpos < nrows);
182 
183  /* skip local rows */
184  if( rowpos >= 0 && ! SCIProwIsLocal(masterrows[i]) )
185  activities[rowpos] += mastercolvals[i] * (int)masterdir * shiftval;
186  }
187 
188  /* update the activities of the LP rows of the slave variable */
189  for( j = 0; j < ncolslaverows && SCIProwGetLPPos(slaverows[j]) >= 0; ++j )
190  {
191  int rowpos;
192 
193  rowpos = SCIProwGetLPPos(slaverows[j]);
194  assert(rowpos < nrows);
195 
196  /* skip local rows */
197  if( rowpos >= 0 && ! SCIProwIsLocal(slaverows[j]) )
198  {
199  activities[rowpos] += slavecolvals[j] * (int)slavedir * shiftval;
200  assert(SCIPisFeasGE(scip, activities[rowpos], SCIProwGetLhs(slaverows[j])));
201  assert(SCIPisFeasLE(scip, activities[rowpos], SCIProwGetRhs(slaverows[j])));
202  }
203  }
204 
205  /* in debug mode, the master rows are checked for feasibility which should be granted by the
206  * decision for a shift value */
207 #ifndef NDEBUG
208  for( i = 0; i < ncolmasterrows && SCIProwGetLPPos(masterrows[i]) >= 0; ++i )
209  {
210  /* local rows can be skipped */
211  if( SCIProwIsLocal(masterrows[i]) )
212  continue;
213 
214  assert(SCIPisFeasGE(scip, activities[SCIProwGetLPPos(masterrows[i])], SCIProwGetLhs(masterrows[i])));
215  assert(SCIPisFeasLE(scip, activities[SCIProwGetLPPos(masterrows[i])], SCIProwGetRhs(masterrows[i])));
216  }
217 #endif
218 
219  *feasible = TRUE;
220 
221  return SCIP_OKAY;
222 }
223 
224 /** Compare two variables with respect to their columns.
225  *
226  * Columns are treated as {0,1} vector, where every nonzero entry is treated as '1', and compared to each other
227  * lexicographically. I.e. var1 is < var2 if the corresponding column of var2 has the smaller single nonzero index of
228  * the two columns. This comparison costs O(constraints) in the worst case
229  */
230 static
231 int varColCompare(
232  SCIP_VAR* var1, /**< left argument of comparison */
233  SCIP_VAR* var2 /**< right argument of comparison */
234  )
235 {
236  SCIP_COL* col1;
237  SCIP_COL* col2;
238  SCIP_ROW** rows1;
239  SCIP_ROW** rows2;
240  int nnonzeros1;
241  int nnonzeros2;
242  int i;
243 
244  assert(var1 != NULL);
245  assert(var2 != NULL);
246 
247  /* get the necessary row and column data */
248  col1 = SCIPvarGetCol(var1);
249  col2 = SCIPvarGetCol(var2);
250  rows1 = SCIPcolGetRows(col1);
251  rows2 = SCIPcolGetRows(col2);
252  nnonzeros1 = SCIPcolGetNNonz(col1);
253  nnonzeros2 = SCIPcolGetNNonz(col2);
254 
255  assert(nnonzeros1 == 0 || rows1 != NULL);
256  assert(nnonzeros2 == 0 || rows2 != NULL);
257 
258  /* loop over the rows, stopped as soon as they differ in one index,
259  * or if counter reaches the end of a variables row set */
260  for( i = 0; i < nnonzeros1 && i < nnonzeros2; ++i )
261  {
262  if( SCIProwGetIndex(rows1[i]) != SCIProwGetIndex(rows2[i]) )
263  return SCIProwGetIndex(rows1[i]) - SCIProwGetIndex(rows2[i]);
264  }
265 
266  /* loop is finished, without differing in one of common row indices, due to loop invariant
267  * variable i reached either nnonzeros1 or nnonzeros2 or both.
268  * one can easily check that the difference of these two numbers always has the desired sign for comparison. */
269  return nnonzeros2 - nnonzeros1 ;
270 }
271 
272 /** implements a comparator to compare two variables with respect to their column entries */
273 static
274 SCIP_DECL_SORTPTRCOMP(SCIPvarcolComp)
275 {
276  return varColCompare((SCIP_VAR*) elem1, (SCIP_VAR*) elem2);
277 }
278 
279 /** checks if two given variables are contained in common LP rows,
280  * returns true if variables share the necessary percentage (matchingrate) of rows.
281  */
282 static
284  SCIP* scip, /**< current SCIP instance */
285  SCIP_VAR* var1, /**< first variable */
286  SCIP_VAR* var2, /**< second variable */
287  SCIP_Real matchingrate /**< determines the ratio of shared LP rows compared to the total number of
288  * LP-rows each variable appears in */
289  )
290 {
291  SCIP_COL* col1;
292  SCIP_COL* col2;
293  SCIP_ROW** rows1;
294  SCIP_ROW** rows2;
295  int nnonzeros1;
296  int nnonzeros2;
297  int i;
298  int j;
299  int nrows1not2; /* the number of LP-rows of variable 1 which variable 2 doesn't appear in */
300  int nrows2not1; /* vice versa */
301  int nrowmaximum;
302  int nrowabs;
303 
304  assert(var1 != NULL);
305  assert(var2 != NULL);
306 
307  /* get the necessary row and column data */
308  col1 = SCIPvarGetCol(var1);
309  col2 = SCIPvarGetCol(var2);
310  rows1 = SCIPcolGetRows(col1);
311  rows2 = SCIPcolGetRows(col2);
312  nnonzeros1 = SCIPcolGetNNonz(col1);
313  nnonzeros2 = SCIPcolGetNNonz(col2);
314 
315  assert(nnonzeros1 == 0 || rows1 != NULL);
316  assert(nnonzeros2 == 0 || rows2 != NULL);
317 
318  if( nnonzeros1 == 0 && nnonzeros2 == 0 )
319  return TRUE;
320 
321  /* initialize the counters for the number of rows not shared. */
322  nrowmaximum = MAX(nnonzeros1, nnonzeros2);
323 
324  nrowabs = ABS(nnonzeros1 - nnonzeros2);
325  nrows1not2 = nrowmaximum - nnonzeros2;
326  nrows2not1 = nrowmaximum - nnonzeros1;
327 
328  /* if the numbers of nonzero rows differs too much, w.r.t.matching ratio, the more expensive check over the rows
329  * doesn't have to be applied anymore because the counters for not shared rows can only increase.
330  */
331  assert(nrowmaximum > 0);
332 
333  if( (nrowmaximum - nrowabs) / (SCIP_Real) nrowmaximum < matchingrate )
334  return FALSE;
335 
336  i = 0;
337  j = 0;
338 
339  /* loop over all rows and determine number of non-shared rows */
340  while( i < nnonzeros1 && j < nnonzeros2 )
341  {
342  /* variables share a common row */
343  if( SCIProwGetIndex(rows1[i]) == SCIProwGetIndex(rows2[j]) )
344  {
345  ++i;
346  ++j;
347  }
348  /* variable 1 appears in rows1[i], variable 2 doesn't */
349  else if( SCIProwGetIndex(rows1[i]) < SCIProwGetIndex(rows2[j]) )
350  {
351  ++i;
352  ++nrows1not2;
353  }
354  /* variable 2 appears in rows2[j], variable 1 doesn't */
355  else
356  {
357  ++j;
358  ++nrows2not1;
359  }
360  }
361 
362  /* now apply the ratio based comparison, that is if the ratio of shared rows is greater or equal the matching rate
363  * for each variable */
364  return ( SCIPisFeasLE(scip, matchingrate, (nnonzeros1 - nrows1not2) / (SCIP_Real)(nnonzeros1)) ||
365  SCIPisFeasLE(scip, matchingrate, (nnonzeros2 - nrows2not1) / (SCIP_Real)(nnonzeros2)) ); /*lint !e795 */
366 }
367 
368 /** Determines a bound by which the absolute solution value of two integer variables can be shifted at most.
369  *
370  * The criterion is the maintenance of feasibility of any global LP row.
371  * The first implementation only considers shifting proportion 1:1, i.e. if master value is shifted by a certain
372  * integer value k downwards, the value of slave is simultaneously shifted by k upwards.
373  */
374 static
376  SCIP* scip, /**< current scip instance */
377  SCIP_SOL* sol, /**< current incumbent */
378  SCIP_VAR* master, /**< current master variable */
379  DIRECTION masterdirection, /**< the shifting direction of the master variable */
380  SCIP_VAR* slave, /**< slave variable with same LP_row set as master variable */
381  DIRECTION slavedirection, /**< the shifting direction of the slave variable */
382  SCIP_Real* activities, /**< array of LP row activities */
383  int nrows /**< the number of rows in LP and the size of the activities array */
384  )
385 { /*lint --e{715}*/
386  SCIP_Real masterbound;
387  SCIP_Real slavebound;
388  SCIP_Real bound;
389 
390  SCIP_COL* col;
391  SCIP_ROW** slaverows;
392  SCIP_ROW** masterrows;
393  SCIP_Real* mastercolvals;
394  SCIP_Real* slavecolvals;
395  int nslaverows;
396  int nmasterrows;
397  int i;
398  int j;
399 
400  assert(scip != NULL);
401  assert(sol != NULL);
402  assert(master != NULL);
403  assert(slave != NULL);
404  assert(SCIPvarIsIntegral(master) && SCIPvarIsIntegral(slave));
405  assert(masterdirection == DIRECTION_UP || masterdirection == DIRECTION_DOWN);
406  assert(slavedirection == DIRECTION_UP || slavedirection == DIRECTION_DOWN);
407 
408  /* determine the trivial variable bounds for shift */
409  if( masterdirection == DIRECTION_UP )
410  masterbound = SCIPvarGetUbGlobal(master) - SCIPgetSolVal(scip, sol, master);
411  else
412  masterbound = SCIPgetSolVal(scip, sol, master) - SCIPvarGetLbGlobal(master);
413 
414  if( slavedirection == DIRECTION_UP )
415  slavebound = SCIPvarGetUbGlobal(slave) - SCIPgetSolVal(scip, sol, slave);
416  else
417  slavebound = SCIPgetSolVal(scip, sol, slave) - SCIPvarGetLbGlobal(slave);
418 
419  bound = MIN(slavebound, masterbound);
420  assert(!SCIPisInfinity(scip,bound));
421  if( SCIPisFeasZero(scip, bound) )
422  return 0.0;
423 
424  /* get the necessary row and and column data for each variable */
425  col = SCIPvarGetCol(slave);
426  slaverows = SCIPcolGetRows(col);
427  slavecolvals = SCIPcolGetVals(col);
428  nslaverows = SCIPcolGetNNonz(col);
429 
430  col = SCIPvarGetCol(master);
431  mastercolvals = SCIPcolGetVals(col);
432  masterrows = SCIPcolGetRows(col);
433  nmasterrows = SCIPcolGetNNonz(col);
434 
435  assert(nslaverows == 0 || slavecolvals != NULL);
436  assert(nmasterrows == 0 || mastercolvals != NULL);
437 
438  SCIPdebugMessage(" Master: %s with direction %d and %d rows, Slave: %s with direction %d and %d rows \n", SCIPvarGetName(master),
439  (int)masterdirection, nmasterrows, SCIPvarGetName(slave), (int)slavedirection, nslaverows);
440 
441  /* loop over all LP rows and determine the maximum integer bound by which both variables
442  * can be shifted without loss of feasibility
443  */
444  i = 0;
445  j = 0;
446  while( (i < nslaverows || j < nmasterrows) && SCIPisPositive(scip, bound) )
447  {
448  SCIP_ROW* row;
449  SCIP_Real effect;
450  SCIP_Real rhs;
451  SCIP_Real lhs;
452  SCIP_Real activity;
453  int rowpos;
454  int masterindex;
455  int slaveindex;
456  SCIP_Bool slaveincrement;
457  SCIP_Bool masterincrement;
458 
459  /* check if one pointer already reached the end of the respective array */
460  if( i < nslaverows && SCIProwGetLPPos(slaverows[i]) == -1 )
461  {
462  SCIPdebugMessage(" Slaverow %s is not in LP (i=%d, j=%d)\n", SCIProwGetName(slaverows[i]), i, j);
463  i = nslaverows;
464  continue;
465  }
466  if( j < nmasterrows && SCIProwGetLPPos(masterrows[j]) == -1 )
467  {
468  SCIPdebugMessage(" Masterrow %s is not in LP (i=%d, j=%d) \n", SCIProwGetName(masterrows[j]), i, j);
469  j = nmasterrows;
470  continue;
471  }
472 
473  slaveincrement = FALSE;
474  masterincrement = FALSE;
475  /* If one counter has already reached its limit, assign a huge number to the corresponding
476  * row index to simulate an always greater row position. */
477  if( i < nslaverows )
478  slaveindex = SCIProwGetIndex(slaverows[i]);
479  else
480  slaveindex = INT_MAX;
481 
482  if( j < nmasterrows )
483  masterindex = SCIProwGetIndex(masterrows[j]);
484  else
485  masterindex = INT_MAX;
486 
487  assert(0 <= slaveindex && 0 <= masterindex);
488 
489  assert(slaveindex < INT_MAX || masterindex < INT_MAX);
490 
491  /* the current row is the one with the smaller index */
492  if( slaveindex <= masterindex )
493  {
494  rowpos = SCIProwGetLPPos(slaverows[i]);
495  row = slaverows[i];
496  slaveincrement = TRUE;
497  masterincrement = (slaveindex == masterindex);
498  }
499  else
500  {
501  assert(j < nmasterrows);
502 
503  rowpos = SCIProwGetLPPos(masterrows[j]);
504  row = masterrows[j];
505  masterincrement = TRUE;
506  }
507  assert(row != NULL);
508 
509  /* local rows can be skipped */
510  if( !SCIProwIsLocal(row) )
511  {
512  /* effect is the effect on the row activity by shifting the variables by 1 in the respective directions */
513  effect = 0.0;
514  if( slaveindex <= masterindex )
515  effect += (slavecolvals[i] * (int)slavedirection);
516  if( masterindex <= slaveindex )
517  effect += (mastercolvals[j] * (int)masterdirection);
518 
519  /* get information about the current row */
520  if( rowpos >= 0 && !SCIPisFeasZero(scip, effect) )
521  {
522  /* effect does not equal zero, the bound is determined as minimum positive integer such that
523  * feasibility of this constraint is maintained.
524  * if constraint is an equality constraint, activity and lhs/rhs should be feasibly equal, which
525  * will cause the method to return zero.
526  */
527  assert(rowpos < nrows);
528 
529  activity = activities[rowpos];
530  rhs = SCIProwGetRhs(row);
531  lhs = SCIProwGetLhs(row);
532 
533  /* if the row is an equation, abort because of effect being nonzero */
534  if( SCIPisFeasEQ(scip, lhs, rhs) )
535  return 0.0;
536 
537  assert(SCIPisFeasLE(scip, lhs, activity) && SCIPisFeasLE(scip, activity, rhs));
538 
539  SCIPdebugMessage(" %g <= %g <= %g, bound = %g, effect = %g (%g * %d + %g * %d) (i=%d,j=%d)\n", lhs, activity, rhs, bound, effect,
540  slaveindex <= masterindex ? slavecolvals[i] : 0.0, (int)slavedirection, masterindex <= slaveindex ? mastercolvals[j] : 0.0,
541  (int)masterdirection, i, j);
542 
543  /* if the row has a left hand side, ensure that shifting preserves feasibility of this ">="-constraint */
544  if( !SCIPisInfinity(scip, -lhs) && SCIPisFeasLT(scip, activity + (effect * bound), lhs) )
545  {
546  SCIP_Real newval;
547 
548  assert(SCIPisNegative(scip, effect));
549 
550  newval = SCIPfeasFloor(scip, (lhs - activity)/effect); /*lint !e414*/
551  bound = MIN(bound - 1.0, newval);
552  }
553 
554  /* if the row has an upper bound, ensure that shifting preserves feasibility of this "<="-constraint */
555  if( !SCIPisInfinity(scip, rhs) && SCIPisFeasGT(scip, activity + (effect * bound), rhs) )
556  {
557  SCIP_Real newval;
558 
559  assert(SCIPisPositive(scip, effect));
560 
561  newval = SCIPfeasFloor(scip, (rhs - activity)/effect); /*lint !e414*/
562  bound = MIN(bound - 1.0, newval);
563  }
564 
565  assert(SCIPisFeasLE(scip, lhs, activity + effect * bound) && SCIPisFeasGE(scip, rhs, activity + effect * bound));
566  assert(SCIPisFeasIntegral(scip, bound));
567  }
568  else
569  {
570  SCIPdebugMessage(" Zero effect on row %s, effect %g, master coeff: %g slave coeff: %g (i=%d, j=%d)\n",
571  SCIProwGetName(row), effect, mastercolvals[j], slavecolvals[i], i, j);
572  }
573  }
574  else
575  {
576  SCIPdebugMessage(" Row %s is local.\n", SCIProwGetName(row));
577  }
578 
579  /* increase the counters which belong to the corresponding row. Both counters are increased by
580  * 1 iff rowpos1 <= rowpos2 <= rowpos1 */
581  if( slaveincrement )
582  ++i;
583  if( masterincrement )
584  ++j;
585  }
586 
587  /* due to numerical reasons, bound can be negative. A variable shift by a negative bound is not desired by
588  * by the heuristic -> Change the return value to zero */
589  if( !SCIPisPositive(scip, bound) )
590  bound = 0.0;
591 
592  return bound;
593 }
594 
595 /** Disposes variable with no heuristic relevancy, e.g., due to a fixed solution value, from its neighborhood block.
596  *
597  * The affected neighborhood block is reduced by 1.
598  */
599 static
600 void disposeVariable(
601  SCIP_VAR** vars, /**< problem variables */
602  int* blockend, /**< contains end index of block */
603  int varindex /**< variable index */
604  )
605 {
606  assert(blockend != NULL);
607  assert(varindex <= *blockend);
608 
609  vars[varindex] = vars[*blockend];
610  --(*blockend);
611 }
612 
613 /** realizes the presolve independently from type of variables it's applied to */
614 static
616  SCIP* scip, /**< current scip */
617  SCIP_VAR** vars, /**< problem vars */
618  SCIP_VAR*** varspointer, /**< pointer to heuristic specific variable memory */
619  int nvars, /**< the number of variables */
620  int* nblocks, /**< pointer to store the number of detected blocks */
621  int* maxblocksize, /**< maximum size of a block */
622  int* nblockvars, /**< pointer to store the number of block variables */
623  int** blockstart, /**< pointer to store the array of block start indices */
624  int** blockend, /**< pointer to store the array of block end indices */
625  SCIP_HEUR* heur, /**< the heuristic */
626  SCIP_HEURDATA* heurdata /**< the heuristic data */
627  )
628 {
629  int v;
630  int startindex;
631 
632  assert(scip != NULL);
633  assert(vars != NULL);
634  assert(nvars >= 2);
635  assert(nblocks != NULL);
636  assert(nblockvars != NULL);
637  assert(blockstart != NULL);
638  assert(blockend != NULL);
639  assert(heur != NULL);
640  assert(heurdata != NULL);
641 
642  /* allocate the heuristic specific variables */
643  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, varspointer, vars, nvars));
644 
645  /* sort the variables with respect to their columns */
646  SCIPsortPtr((void**)(*varspointer), SCIPvarcolComp, nvars);
647 
648  /* start determining blocks, i.e. a set of at least two variables which share most of their row set.
649  * If there is none, heuristic does not need to be executed.
650  */
651  startindex = 0;
652  *nblocks = 0;
653  *nblockvars = 0;
654 
655  SCIP_CALL( SCIPallocBlockMemoryArray(scip, blockstart, nvars/2) );
656  SCIP_CALL( SCIPallocBlockMemoryArray(scip, blockend, nvars/2) );
657 
658  /* loop over variables and compare neighbors */
659  for( v = 1; v < nvars; ++v )
660  {
661  if( !checkConstraintMatching(scip, (*varspointer)[startindex], (*varspointer)[v], heurdata->matchingrate) )
662  {
663  /* current block has its last variable at position v-1. If v differs from startindex by at least 2,
664  * a block is detected. Update the data correspondingly */
665  if( v - startindex >= 2 )
666  {
667  assert(*nblocks < nvars/2);
668  (*nblockvars) += v - startindex;
669  (*maxblocksize) = MAX((*maxblocksize), v - startindex);
670  (*blockstart)[*nblocks] = startindex;
671  (*blockend)[*nblocks] = v - 1;
672  (*nblocks)++;
673  }
674  startindex = v;
675  }
676  else if( v == nvars - 1 && v - startindex >= 1 )
677  {
678  assert(*nblocks < nvars/2);
679  (*nblockvars) += v - startindex + 1;
680  (*maxblocksize) = MAX((*maxblocksize), v - startindex + 1);
681  (*blockstart)[*nblocks] = startindex;
682  (*blockend)[*nblocks] = v;
683  (*nblocks)++;
684  }
685  }
686 
687  /* reallocate memory with respect to the number of found blocks; if there were none, free the memory */
688  if( *nblocks > 0 )
689  {
690  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, blockstart, nvars/2, *nblocks) );
691  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, blockend, nvars/2, *nblocks) );
692  }
693  else
694  {
695  SCIPfreeBlockMemoryArray(scip, blockstart, nvars/2);
696  SCIPfreeBlockMemoryArray(scip, blockend, nvars/2);
697 
698  *blockstart = NULL;
699  *blockend = NULL;
700  }
701 
702  return SCIP_OKAY;
703 }
704 
705 /** initializes the required structures for execution of heuristic.
706  *
707  * If objective coefficient functions are not all equal, each Binary and Integer variables are sorted
708  * into heuristic-specific arrays with respect to their lexicographical column order,
709  * where every zero in a column is interpreted as zero and every nonzero as '1'.
710  * After the sorting, the variables are compared with respect to user parameter matchingrate and
711  * the heuristic specific blocks are determined.
712  */
713 static
715  SCIP* scip, /**< current scip instance */
716  SCIP_HEUR* heur, /**< heuristic */
717  SCIP_HEURDATA* heurdata /**< the heuristic data */
718  )
719 {
720  int nbinvars;
721  int nintvars;
722  int nvars;
723  SCIP_VAR** vars;
724  int nbinblockvars = 0;
725  int nintblockvars;
726  int maxbinblocksize = 0;
727  int maxintblocksize;
728 
729  assert(scip != NULL);
730  assert(heurdata != NULL);
731 
732  /* ensure that method is not executed if presolving was already applied once in current branch and bound process */
733  if( heurdata->presolved )
734  return SCIP_OKAY;
735 
736  /* get necessary variable information, i.e. number of binary and integer variables */
737  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );
738 
739  /* if number of binary problem variables exceeds 2, they are subject to 2-optimization algorithm, hence heuristic
740  * calls innerPresolve method to detect necessary structures. */
741  if( nbinvars >= 2 )
742  {
743  SCIP_CALL( innerPresolve(scip, vars, &(heurdata->binvars), nbinvars, &(heurdata->nbinblocks), &maxbinblocksize,
744  &nbinblockvars, &(heurdata->binblockstart), &(heurdata->binblockend), heur, heurdata) );
745  }
746 
747  heurdata->nbinvars = nbinvars;
748  heurdata->execute = nbinvars > 1 && heurdata->nbinblocks > 0;
749 
750 #ifdef SCIP_STATISTIC
751  /* update statistics */
752  heurdata->binnblocks += (heurdata->nbinblocks);
753  heurdata->binnblockvars += nbinblockvars;
754  heurdata->ntotalbinvars += nbinvars;
755  heurdata->maxbinblocksize = MAX(maxbinblocksize, heurdata->maxbinblocksize);
756 
757  SCIPstatisticMessage(" Twoopt BINARY presolving finished with <%d> blocks, <%d> block variables \n",
758  heurdata->nbinblocks, nbinblockvars);
759 #endif
760 
761  if( heurdata->intopt && nintvars > 1 )
762  {
763  SCIP_CALL( innerPresolve(scip, &(vars[nbinvars]), &(heurdata->intvars), nintvars, &(heurdata->nintblocks), &maxintblocksize,
764  &nintblockvars, &(heurdata->intblockstart), &(heurdata->intblockend),
765  heur, heurdata) );
766 
767  heurdata->execute = heurdata->execute || heurdata->nintblocks > 0;
768 
769 #ifdef SCIP_STATISTIC
770  /* update statistics */
771  heurdata->intnblocks += heurdata->nintblocks;
772  heurdata->intnblockvars += nintblockvars;
773  heurdata->ntotalintvars += nintvars;
774  heurdata->maxintblocksize = MAX(maxintblocksize, heurdata->maxintblocksize);
775  SCIPstatisticMessage(" Twoopt Integer presolving finished with <%d> blocks, <%d> block variables \n",
776  heurdata->nintblocks, nintblockvars);
777  SCIPstatisticMessage(" INTEGER coefficients are all equal \n");
778 #endif
779  }
780  heurdata->nintvars = nintvars;
781 
782  /* presolving is finished, heuristic data is updated*/
783  heurdata->presolved = TRUE;
784  SCIPheurSetData(heur, heurdata);
785 
786  return SCIP_OKAY;
787 }
788 
789 /*
790  * Callback methods of primal heuristic
791  */
792 
793 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
794 static
795 SCIP_DECL_HEURCOPY(heurCopyTwoopt)
796 { /*lint --e{715}*/
797  assert(scip != NULL);
798  assert(heur != NULL);
799  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
800 
801  /* call inclusion method of primal heuristic */
803 
804  return SCIP_OKAY;
805 }
806 
807 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
808 static
809 SCIP_DECL_HEURFREE(heurFreeTwoopt)
810 { /*lint --e{715}*/
811  SCIP_HEURDATA* heurdata;
812 
813  assert(heur != NULL);
814  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
815  assert(scip != NULL);
816 
817  /* free heuristic data */
818  heurdata = SCIPheurGetData(heur);
819  assert(heurdata != NULL);
820 
821  SCIPfreeMemory(scip, &heurdata);
822  SCIPheurSetData(heur, NULL);
823 
824  return SCIP_OKAY;
825 }
826 
827 /** initialization method of primal heuristic (called after problem was transformed) */
828 static
829 SCIP_DECL_HEURINIT(heurInitTwoopt)
830 {
831  SCIP_HEURDATA* heurdata;
832  assert(heur != NULL);
833  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
834  assert(scip != NULL);
835 
836  heurdata = SCIPheurGetData(heur);
837  assert(heurdata != NULL);
838 
839  /* heuristic has not run yet, all heuristic specific data is set to initial values */
840  heurdata->nbinvars = 0;
841  heurdata->nintvars = 0;
842  heurdata->lastsolindex = -1;
843  heurdata->presolved = FALSE;
844  heurdata->nbinblocks = 0;
845  heurdata->nintblocks = 0;
846 
847  heurdata->randseed = 0;
848 
849 #ifdef SCIP_STATISTIC
850  /* initialize statistics */
851  heurdata->binnexchanges = 0;
852  heurdata->intnexchanges = 0;
853  heurdata->binnblockvars = 0;
854  heurdata->intnblockvars = 0;
855  heurdata->binnblocks = 0;
856  heurdata->intnblocks = 0;
857 
858  heurdata->maxbinblocksize = 0;
859  heurdata->maxintblocksize = 0;
860 
861  heurdata->ntotalbinvars = 0;
862  heurdata->ntotalintvars = 0;
863  heurdata->nruns = 0;
864 #endif
865 
866  /* all pointers are initially set to NULL. Since presolving
867  * of the heuristic requires a lot of calculation time on some instances,
868  * but might not be needed e.g. if problem is infeasible, presolving is applied
869  * when heuristic is executed for the first time
870  */
871  heurdata->binvars = NULL;
872  heurdata->intvars = NULL;
873  heurdata->binblockstart = NULL;
874  heurdata->binblockend = NULL;
875  heurdata->intblockstart = NULL;
876  heurdata->intblockend = NULL;
877 
878  SCIPheurSetData(heur, heurdata);
879 
880  return SCIP_OKAY;
881 }
882 
883 /* Realizes the 2-optimization algorithm, which tries to improve incumbent solution
884  * by shifting pairs of variables which share a common row set.
885  */
886 static
888  SCIP* scip, /**< current SCIP instance */
889  SCIP_SOL* worksol, /**< working solution */
890  SCIP_VAR** vars, /**< binary or integer variables */
891  int* blockstart, /**< contains start indices of blocks */
892  int* blockend, /**< contains end indices of blocks */
893  int nblocks, /**< the number of blocks */
894  OPTTYPE opttype, /**< are binaries or integers optimized */
895  SCIP_Real* activities, /**< the LP-row activities */
896  int nrows, /**< the number of LP rows */
897  SCIP_Bool* improvement, /**< was there a successful shift? */
898  SCIP_Bool* varboundserr, /**< has the current incumbent already been cut off */
899  SCIP_HEURDATA* heurdata /**< the heuristic data */
900  )
901 { /*lint --e{715}*/
902  int b;
903  SCIP_Real* objchanges;
904  SCIP_VAR** bestmasters;
905  SCIP_VAR** bestslaves;
906  int* bestdirections;
907  int arraysize;
908  int npairs = 0;
909 
910  assert(scip != NULL);
911  assert(nblocks > 0);
912  assert(blockstart != NULL && blockend != NULL);
913  assert(varboundserr != NULL);
914  assert(activities != NULL);
915  assert(worksol != NULL);
916  assert(improvement != NULL);
917 
918  *varboundserr = FALSE;
919 
920  SCIP_CALL( SCIPallocBufferArray(scip, &bestmasters, DEFAULT_ARRAYSIZE) );
921  SCIP_CALL( SCIPallocBufferArray(scip, &bestslaves, DEFAULT_ARRAYSIZE) );
922  SCIP_CALL( SCIPallocBufferArray(scip, &objchanges, DEFAULT_ARRAYSIZE) );
923  SCIP_CALL( SCIPallocBufferArray(scip, &bestdirections, DEFAULT_ARRAYSIZE) );
924  arraysize = DEFAULT_ARRAYSIZE;
925 
926  /* iterate over blocks */
927  for( b = 0; b < nblocks; ++b )
928  {
929  int m;
930  int blocklen;
931 
932  blocklen = blockend[b] - blockstart[b] + 1;
933 
934  /* iterate over variables in current block */
935  for( m = 0; m < blocklen; ++m )
936  {
937  /* determine the new master variable for heuristic's optimization method */
938  SCIP_VAR* master;
939  SCIP_Real masterobj;
940  SCIP_Real mastersolval;
941  SCIP_Real bestimprovement;
942  SCIP_Real bestbound;
943  int bestslavepos;
944  int s;
945  int firstslave;
946  int nslaves;
947  int bestdirection;
948  DIRECTION bestmasterdir;
949  DIRECTION bestslavedir;
950 
951  master = vars[blockstart[b] + m]; /*lint !e679*/
952  masterobj = SCIPvarGetObj(master);
953  mastersolval = SCIPgetSolVal(scip, worksol, master);
954 
955  /* due to cuts or fixings of solution values, worksol might not be feasible w.r.t. its bounds.
956  * Exit method in that case. */
957  if( SCIPisFeasGT(scip, mastersolval, SCIPvarGetUbGlobal(master)) || SCIPisFeasLT(scip, mastersolval, SCIPvarGetLbGlobal(master)) )
958  {
959  *varboundserr = TRUE;
960  SCIPdebugMessage("Solution has violated variable bounds for var %s: %g <= %g <= %g \n",
961  SCIPvarGetName(master), SCIPvarGetLbGlobal(master), mastersolval, SCIPvarGetUbGlobal(master));
962  goto TERMINATE;
963  }
964 
965  /* if variable has fixed solution value, it is deleted from heuristic array */
966  if( SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(master), SCIPvarGetLbGlobal(master)) )
967  {
968  disposeVariable(vars, &(blockend[b]), blockstart[b] + m);
969  --blocklen;
970  continue;
971  }
972  else if( SCIPvarGetStatus(master) != SCIP_VARSTATUS_COLUMN )
973  continue;
974 
975  assert(SCIPisFeasIntegral(scip, mastersolval));
976 
977  assert(opttype == OPTTYPE_INTEGER || (SCIPisFeasEQ(scip, mastersolval, 1.0) || SCIPisFeasEQ(scip, mastersolval, 0.0)));
978 
979  /* initialize the data of the best available shift */
980  bestimprovement = 0.0;
981  bestslavepos = -1;
982  bestbound = 0.0;
983  bestmasterdir = DIRECTION_NONE;
984  bestslavedir = DIRECTION_NONE;
985  bestdirection = -1;
986 
987  /* in blocks with more than heurdata->maxnslaves variables, a slave candidate region is chosen */
988  if( heurdata->maxnslaves >= 0 && blocklen > heurdata->maxnslaves )
989  firstslave = SCIPgetRandomInt(blockstart[b] + m, blockend[b], &heurdata->randseed);
990  else
991  firstslave = blockstart[b] + m + 1;
992 
993  nslaves = MIN((heurdata->maxnslaves == -1 ? INT_MAX : heurdata->maxnslaves), blocklen);
994 
995  /* Loop over block and determine a slave shift candidate for master variable.
996  * If more than one candidate is available, choose the shift which improves objective function
997  * the most. */
998  for( s = 0; s < nslaves; ++s )
999  {
1000  SCIP_VAR* slave;
1001  SCIP_Real slaveobj;
1002  SCIP_Real slavesolval;
1003  SCIP_Real changedobj;
1004  SCIP_Real diffdirbound;
1005  SCIP_Real equaldirbound;
1006  int directions;
1007  int slaveindex;
1008 
1009  slaveindex = (firstslave + s - blockstart[b]) % blocklen;
1010  slaveindex += blockstart[b];
1011 
1012  /* in case of a small block, we do not want to try possible pairings twice */
1013  if( (blocklen <= heurdata->maxnslaves || heurdata->maxnslaves == -1) && slaveindex < blockstart[b] + m )
1014  break;
1015  /* master and slave should not be the same variable */
1016  if( slaveindex == blockstart[b] + m )
1017  continue;
1018 
1019  /* get the next slave variable */
1020  slave = vars[slaveindex];
1021  slaveobj = SCIPvarGetObj(slave);
1022  slavesolval = SCIPgetSolVal(scip, worksol, slave);
1023  changedobj = 0.0;
1024 
1025  assert(SCIPvarGetType(master) == SCIPvarGetType(slave));
1026  assert(SCIPisFeasIntegral(scip, slavesolval));
1027  assert(opttype == OPTTYPE_INTEGER || (SCIPisFeasEQ(scip, slavesolval, 1.0) || SCIPisFeasEQ(scip, slavesolval, 0.0)));
1028 
1029  /* solution is not feasible w.r.t. the variable bounds, stop optimization in this case */
1030  if( SCIPisFeasGT(scip, slavesolval, SCIPvarGetUbGlobal(slave)) || SCIPisFeasLT(scip, slavesolval, SCIPvarGetLbGlobal(slave)) )
1031  {
1032  *varboundserr = TRUE;
1033  SCIPdebugMessage("Solution has violated variable bounds for var %s: %g <= %g <= %g \n",
1034  SCIPvarGetName(slave), SCIPvarGetLbGlobal(slave), slavesolval, SCIPvarGetUbGlobal(slave));
1035  goto TERMINATE;
1036  }
1037 
1038  /* if solution value of the variable is fixed, delete it from the remaining candidates in the block */
1039  if( SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(slave), SCIPvarGetLbGlobal(slave) ) )
1040  {
1041  disposeVariable(vars, &(blockend[b]), slaveindex);
1042  --blocklen;
1043  continue;
1044  }
1045  else if( SCIPvarGetStatus(master) != SCIP_VARSTATUS_COLUMN )
1046  continue;
1047 
1048  /* determine the shifting direction to improve the objective function */
1049  /* assert(SCIPisFeasGT(scip, masterobj, slaveobj)); */
1050 
1051  /* The heuristic chooses the shifting direction and the corresponding maximum nonnegative
1052  * integer shift value for the two variables which preserves feasibility and improves
1053  * the objective function value. */
1054  directions = -1;
1055  diffdirbound = 0.0;
1056  equaldirbound = 0.0;
1057 
1058  if( SCIPisFeasLT(scip, masterobj - slaveobj, 0.0) )
1059  {
1060  diffdirbound = determineBound(scip, worksol, master, DIRECTION_UP, slave, DIRECTION_DOWN, activities, nrows);
1061  directions = 2;
1062  /* the improvement of objective function is calculated */
1063  changedobj = (masterobj - slaveobj) * diffdirbound;
1064  }
1065  else if( SCIPisFeasGT(scip, masterobj - slaveobj, 0.0) )
1066  {
1067  diffdirbound = determineBound(scip, worksol, master, DIRECTION_DOWN, slave, DIRECTION_UP, activities, nrows);
1068  directions = 1;
1069  changedobj = (slaveobj - masterobj) * diffdirbound;
1070  }
1071 
1072  if( SCIPisFeasLT(scip, masterobj + slaveobj, 0.0) )
1073  {
1074  equaldirbound = determineBound(scip, worksol, master, DIRECTION_UP, slave, DIRECTION_UP, activities, nrows);
1075  if( SCIPisFeasLT(scip, (slaveobj + masterobj) * equaldirbound, changedobj) )
1076  {
1077  changedobj = (slaveobj + masterobj) * equaldirbound;
1078  directions = 3;
1079  }
1080  }
1081  else if( SCIPisFeasGT(scip, masterobj + slaveobj, 0.0) )
1082  {
1083  equaldirbound = determineBound(scip, worksol, master, DIRECTION_DOWN, slave, DIRECTION_DOWN, activities, nrows);
1084  if( SCIPisFeasLT(scip, -(slaveobj + masterobj) * equaldirbound, changedobj) )
1085  {
1086  changedobj = -(slaveobj + masterobj) * equaldirbound;
1087  directions = 0;
1088  }
1089  }
1090  assert(SCIPisFeasIntegral(scip, equaldirbound));
1091  assert(SCIPisFeasIntegral(scip, diffdirbound));
1092  assert(SCIPisFeasGE(scip, equaldirbound, 0.0));
1093  assert(SCIPisFeasGE(scip, diffdirbound, 0.0));
1094 
1095  /* choose the candidate which improves the objective function the most */
1096  if( (SCIPisFeasGT(scip, equaldirbound, 0.0) || SCIPisFeasGT(scip, diffdirbound, 0.0))
1097  && SCIPisFeasLT(scip, changedobj, bestimprovement) )
1098  {
1099  bestimprovement = changedobj;
1100  bestslavepos = slaveindex;
1101  bestdirection = directions;
1102 
1103  /* the most promising shift, i.e., the one which can improve the objective
1104  * the most, is recorded by the integer 'directions'. It is recovered via the use
1105  * of a binary representation of the four different combinations for the shifting directions
1106  * of two variables */
1107  if( directions / 2 == 1 )
1108  bestmasterdir = DIRECTION_UP;
1109  else
1110  bestmasterdir = DIRECTION_DOWN;
1111 
1112  if( directions % 2 == 1 )
1113  bestslavedir = DIRECTION_UP;
1114  else
1115  bestslavedir = DIRECTION_DOWN;
1116 
1117  if( bestmasterdir == bestslavedir )
1118  bestbound = equaldirbound;
1119  else
1120  bestbound = diffdirbound;
1121  }
1122  }
1123 
1124  /* choose the most promising candidate, if one exists */
1125  if( bestslavepos >= 0 )
1126  {
1127  if( npairs == arraysize )
1128  {
1129  SCIP_CALL( SCIPreallocBufferArray(scip, &bestmasters, 2 * arraysize) );
1130  SCIP_CALL( SCIPreallocBufferArray(scip, &bestslaves, 2 * arraysize) );
1131  SCIP_CALL( SCIPreallocBufferArray(scip, &objchanges, 2 * arraysize) );
1132  SCIP_CALL( SCIPreallocBufferArray(scip, &bestdirections, 2 * arraysize) );
1133  arraysize = 2 * arraysize;
1134  }
1135  assert( npairs < arraysize );
1136 
1137  bestmasters[npairs] = master;
1138  bestslaves[npairs] = vars[bestslavepos];
1139  objchanges[npairs] = ((int)bestslavedir * SCIPvarGetObj(bestslaves[npairs]) + (int)bestmasterdir * masterobj) * bestbound;
1140  bestdirections[npairs] = bestdirection;
1141 
1142  assert(objchanges[npairs] < 0);
1143 
1144  SCIPdebugMessage(" Saved candidate pair {%s=%g, %s=%g} with objectives <%g>, <%g> to be set to {%g, %g} %d\n",
1145  SCIPvarGetName(master), mastersolval, SCIPvarGetName(bestslaves[npairs]), SCIPgetSolVal(scip, worksol, bestslaves[npairs]) ,
1146  masterobj, SCIPvarGetObj(bestslaves[npairs]), mastersolval + (int)bestmasterdir * bestbound, SCIPgetSolVal(scip, worksol, bestslaves[npairs])
1147  + (int)bestslavedir * bestbound, bestdirections[npairs]);
1148 
1149  ++npairs;
1150  }
1151  }
1152  }
1153 
1154  if( npairs == 0 )
1155  goto TERMINATE;
1156 
1157  SCIPsortRealPtrPtrInt(objchanges, (void**)bestmasters, (void**)bestslaves, bestdirections, npairs);
1158 
1159  for( b = 0; b < npairs; ++b )
1160  {
1161  SCIP_VAR* master;
1162  SCIP_VAR* slave;
1163  SCIP_Real mastersolval;
1164  SCIP_Real slavesolval;
1165  SCIP_Real masterobj;
1166  SCIP_Real slaveobj;
1167  SCIP_Real bound;
1168  DIRECTION masterdir;
1169  DIRECTION slavedir;
1170 
1171  master = bestmasters[b];
1172  slave = bestslaves[b];
1173  mastersolval = SCIPgetSolVal(scip, worksol, master);
1174  slavesolval = SCIPgetSolVal(scip, worksol, slave);
1175  masterobj =SCIPvarGetObj(master);
1176  slaveobj = SCIPvarGetObj(slave);
1177 
1178  assert(0 <= bestdirections[b] && bestdirections[b] < 4);
1179 
1180  if( bestdirections[b] / 2 == 1 )
1181  masterdir = DIRECTION_UP;
1182  else
1183  masterdir = DIRECTION_DOWN;
1184 
1185  if( bestdirections[b] % 2 == 1 )
1186  slavedir = DIRECTION_UP;
1187  else
1188  slavedir = DIRECTION_DOWN;
1189 
1190  bound = determineBound(scip, worksol, master, masterdir, slave, slavedir, activities, nrows);
1191 
1192  if( !SCIPisZero(scip, bound) )
1193  {
1194  SCIP_Bool feasible;
1195 #ifndef NDEBUG
1196  SCIP_Real changedobj;
1197 #endif
1198 
1199  SCIPdebugMessage(" Promising candidates {%s=%g, %s=%g} with objectives <%g>, <%g> to be set to {%g, %g}\n",
1200  SCIPvarGetName(master), mastersolval, SCIPvarGetName(slave), slavesolval,
1201  masterobj, slaveobj, mastersolval + (int)masterdir * bound, slavesolval + (int)slavedir * bound);
1202 
1203 #ifndef NDEBUG
1204  /* the improvement of objective function is calculated */
1205  changedobj = ((int)slavedir * slaveobj + (int)masterdir * masterobj) * bound;
1206  assert(SCIPisFeasLT(scip, changedobj, 0.0));
1207 #endif
1208 
1210  /* try to change the solution values of the variables */
1211  feasible = FALSE;
1212  SCIP_CALL( shiftValues(scip, master, slave, mastersolval, masterdir, slavesolval, slavedir, bound,
1213  activities, nrows, &feasible) );
1214 
1215  if( feasible )
1216  {
1217  /* The variables' solution values were successfully shifted and can hence be updated. */
1218  assert(SCIPisFeasIntegral(scip, mastersolval + ((int)masterdir * bound)));
1219  assert(SCIPisFeasIntegral(scip, slavesolval + ((int)slavedir * bound)));
1220 
1221  SCIP_CALL( SCIPsetSolVal(scip, worksol, master, mastersolval + (int)masterdir * bound) );
1222  SCIP_CALL( SCIPsetSolVal(scip, worksol, slave, slavesolval + (int)slavedir * bound) );
1223  SCIPdebugMessage(" Feasible shift: <%s>[%g, %g] (obj: %f) <%f> --> <%f>\n",
1224  SCIPvarGetName(master), SCIPvarGetLbGlobal(master), SCIPvarGetUbGlobal(master), masterobj, mastersolval, SCIPgetSolVal(scip, worksol, master));
1225  SCIPdebugMessage(" <%s>[%g, %g] (obj: %f) <%f> --> <%f>\n",
1226  SCIPvarGetName(slave), SCIPvarGetLbGlobal(slave), SCIPvarGetUbGlobal(slave), slaveobj, slavesolval, SCIPgetSolVal(scip, worksol, slave));
1227 
1228 #ifdef SCIP_STATISTIC
1229  /* update statistics */
1230  if( opttype == OPTTYPE_BINARY )
1231  ++(heurdata->binnexchanges);
1232  else
1233  ++(heurdata->intnexchanges);
1234 #endif
1235 
1236  *improvement = TRUE;
1237  }
1238  }
1239  }
1240  TERMINATE:
1241  SCIPfreeBufferArray(scip, &bestdirections);
1242  SCIPfreeBufferArray(scip, &objchanges);
1243  SCIPfreeBufferArray(scip, &bestslaves);
1244  SCIPfreeBufferArray(scip, &bestmasters);
1245 
1246  return SCIP_OKAY;
1247 }
1248 
1249 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
1250 static
1251 SCIP_DECL_HEUREXIT(heurExitTwoopt)
1253  SCIP_HEURDATA* heurdata;
1254 
1255  heurdata = SCIPheurGetData(heur);
1256  assert(heurdata != NULL);
1257 
1258  /*ensure that initialization was successful */
1259  assert(heurdata->nbinvars <= 1 || heurdata->binvars != NULL);
1260 
1261 #ifdef SCIP_STATISTIC
1262  /* print relevant statistics to console */
1264  " Twoopt Binary Statistics : "
1265  "%6.2g %6.2g %4.2g %4.0g %6d (blocks/run, variables/run, varpercentage, avg. block size, max block size) \n",
1266  heurdata->nruns == 0 ? 0.0 : (SCIP_Real)heurdata->binnblocks/(heurdata->nruns),
1267  heurdata->nruns == 0 ? 0.0 : (SCIP_Real)heurdata->binnblockvars/(heurdata->nruns),
1268  heurdata->ntotalbinvars == 0 ? 0.0 : (SCIP_Real)heurdata->binnblockvars/(heurdata->ntotalbinvars) * 100.0,
1269  heurdata->binnblocks == 0 ? 0.0 : heurdata->binnblockvars/(SCIP_Real)(heurdata->binnblocks),
1270  heurdata->maxbinblocksize);
1271 
1273  " Twoopt Integer statistics : "
1274  "%6.2g %6.2g %4.2g %4.0g %6d (blocks/run, variables/run, varpercentage, avg block size, max block size) \n",
1275  heurdata->nruns == 0 ? 0.0 : (SCIP_Real)heurdata->intnblocks/(heurdata->nruns),
1276  heurdata->nruns == 0 ? 0.0 : (SCIP_Real)heurdata->intnblockvars/(heurdata->nruns),
1277  heurdata->ntotalintvars == 0 ? 0.0 : (SCIP_Real)heurdata->intnblockvars/(heurdata->ntotalintvars) * 100.0,
1278  heurdata->intnblocks == 0 ? 0.0 : heurdata->intnblockvars/(SCIP_Real)(heurdata->intnblocks),
1279  heurdata->maxintblocksize);
1280 
1282  " Twoopt results : "
1283  "%6d %6d %4d %4.2g (runs, binary exchanges, Integer shiftings, matching rate)\n",
1284  heurdata->nruns,
1285  heurdata->binnexchanges,
1286  heurdata->intnexchanges,
1287  heurdata->matchingrate);
1288 
1289  /* set statistics to initial values*/
1290  heurdata->binnblockvars = 0;
1291  heurdata->binnblocks = 0;
1292  heurdata->intnblocks = 0;
1293  heurdata->intnblockvars = 0;
1294  heurdata->binnexchanges = 0;
1295  heurdata->intnexchanges = 0;
1296 #endif
1297 
1298  /* free the allocated memory for the binary variables */
1299  if( heurdata->binvars != NULL )
1300  {
1301  SCIPfreeBlockMemoryArray(scip, &heurdata->binvars, heurdata->nbinvars);
1302  }
1303 
1304  if( heurdata->nbinblocks > 0 )
1305  {
1306  assert(heurdata->binblockstart != NULL);
1307  assert(heurdata->binblockend != NULL);
1308 
1309  SCIPfreeBlockMemoryArray(scip, &heurdata->binblockstart, heurdata->nbinblocks);
1310  SCIPfreeBlockMemoryArray(scip, &heurdata->binblockend, heurdata->nbinblocks);
1311  }
1312  heurdata->nbinvars = 0;
1313  heurdata->nbinblocks = 0;
1314 
1315  if( heurdata->nintblocks > 0 )
1316  {
1317  assert(heurdata->intblockstart != NULL);
1318  assert(heurdata->intblockend != NULL);
1319 
1320  SCIPfreeBlockMemoryArray(scip, &heurdata->intblockstart, heurdata->nintblocks);
1321  SCIPfreeBlockMemoryArray(scip, &heurdata->intblockend, heurdata->nintblocks);
1322  }
1323 
1324  /* free the allocated memory for the integers */
1325  if( heurdata->intvars != NULL )
1326  {
1327  SCIPfreeBlockMemoryArray(scip, &heurdata->intvars, heurdata->nintvars);
1328  }
1329 
1330  heurdata->nbinblocks = 0;
1331  heurdata->nintblocks = 0;
1332  heurdata->nbinvars = 0;
1333  heurdata->nintvars = 0;
1334 
1335  assert(heurdata->binvars == NULL);
1336  assert(heurdata->intvars == NULL);
1337 
1338  SCIPheurSetData(heur, heurdata);
1339 
1340  return SCIP_OKAY;
1341 }
1342 
1343 /** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
1344 static
1345 SCIP_DECL_HEURINITSOL(heurInitsolTwoopt)
1347  SCIP_HEURDATA* heurdata;
1348  assert(heur != NULL);
1349  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1350  assert(scip != NULL);
1351 
1352  /* get heuristic data */
1353  heurdata = SCIPheurGetData(heur);
1354 
1355  assert(heurdata != NULL);
1356  assert(heurdata->binvars == NULL && heurdata->intvars == NULL);
1357  assert(heurdata->binblockstart == NULL && heurdata->binblockend == NULL);
1358  assert(heurdata->intblockstart == NULL && heurdata->intblockend == NULL);
1359 
1360  /* set heuristic data to initial values, but increase the total number of runs */
1361  heurdata->nbinvars = 0;
1362  heurdata->nintvars = 0;
1363  heurdata->lastsolindex = -1;
1364  heurdata->presolved = FALSE;
1365 
1366 #ifdef SCIP_STATISTIC
1367  ++(heurdata->nruns);
1368 #endif
1369 
1370  SCIPheurSetData(heur, heurdata);
1371 
1372  return SCIP_OKAY;
1373 }
1374 
1375 
1376 /** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
1377 static
1378 SCIP_DECL_HEUREXITSOL(heurExitsolTwoopt)
1380  SCIP_HEURDATA* heurdata;
1381  int nbinvars;
1382  int nintvars;
1383 
1384  assert(heur != NULL);
1385  assert(scip != NULL);
1386  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1387  assert(scip != NULL);
1388 
1389  /* get heuristic data */
1390  heurdata = SCIPheurGetData(heur);
1391 
1392  assert(heurdata != NULL);
1393 
1394  nbinvars = heurdata->nbinvars;
1395  nintvars = heurdata->nintvars;
1396 
1397  /* free the allocated memory for the binary variables */
1398  if( heurdata->binvars != NULL )
1399  {
1400  SCIPfreeBlockMemoryArray(scip, &heurdata->binvars, nbinvars);
1401  }
1402  if( heurdata->binblockstart != NULL )
1403  {
1404  assert(heurdata->binblockend != NULL);
1405 
1406  SCIPfreeBlockMemoryArray(scip, &heurdata->binblockstart, heurdata->nbinblocks);
1407  SCIPfreeBlockMemoryArray(scip, &heurdata->binblockend, heurdata->nbinblocks);
1408  }
1409  heurdata->nbinvars = 0;
1410  heurdata->nbinblocks = 0;
1411 
1412  if( heurdata->intblockstart != NULL )
1413  {
1414  assert(heurdata->intblockend != NULL);
1415 
1416  SCIPfreeBlockMemoryArray(scip, &heurdata->intblockstart, heurdata->nintblocks);
1417  SCIPfreeBlockMemoryArray(scip, &heurdata->intblockend, heurdata->nintblocks);
1418  }
1419  heurdata->nintblocks = 0;
1420 
1421  /* free the allocated memory for the integers */
1422  if( heurdata->intvars != NULL )
1423  {
1424  SCIPfreeBlockMemoryArray(scip, &heurdata->intvars, nintvars);
1425  }
1426 
1427  heurdata->nintvars = 0;
1428 
1429  assert(heurdata->binvars == NULL && heurdata->intvars == NULL);
1430  assert(heurdata->binblockstart == NULL && heurdata->binblockend == NULL);
1431  assert(heurdata->intblockstart == NULL && heurdata->intblockend == NULL);
1432 
1433  /* set heuristic data */
1434  SCIPheurSetData(heur, heurdata);
1435 
1436  return SCIP_OKAY;
1437 }
1438 
1439 /** execution method of primal heuristic */
1440 static
1441 SCIP_DECL_HEUREXEC(heurExecTwoopt)
1442 { /*lint --e{715}*/
1443  SCIP_HEURDATA* heurdata;
1444  SCIP_SOL* bestsol;
1445  SCIP_SOL* worksol;
1446  SCIP_ROW** lprows;
1447  SCIP_Real* activities;
1448  SCIP_COL** cols;
1449  int ncols;
1450  int nbinvars;
1451  int nintvars;
1452  int ndiscvars;
1453  int nlprows;
1454  int i;
1455  int ncolsforsorting;
1456  SCIP_Bool improvement;
1457  SCIP_Bool presolthiscall;
1458  SCIP_Bool varboundserr;
1459 
1460  assert(heur != NULL);
1461  assert(scip != NULL);
1462  assert(result != NULL);
1463 
1464  /* get heuristic data */
1465  heurdata = SCIPheurGetData(heur);
1466  assert(heurdata != NULL);
1467 
1468  *result = SCIP_DIDNOTRUN;
1469 
1470  /* we need an LP */
1471  if( SCIPgetNLPRows(scip) == 0 )
1472  return SCIP_OKAY;
1473 
1474  bestsol = SCIPgetBestSol(scip);
1475 
1476  /* ensure that heuristic has not already been processed on current incumbent */
1477  if( bestsol == NULL || heurdata->lastsolindex == SCIPsolGetIndex(bestsol) )
1478  return SCIP_OKAY;
1479 
1480  heurdata->lastsolindex = SCIPsolGetIndex(bestsol);
1481 
1482  /* we can only work on solutions valid in the transformed space */
1483  if( SCIPsolIsOriginal(bestsol) )
1484  return SCIP_OKAY;
1485 
1486 #ifdef SCIP_DEBUG
1487  SCIP_CALL( SCIPprintSol(scip, bestsol, NULL, TRUE) );
1488 #endif
1489 
1490  /* ensure that the user defined number of nodes after last best solution has been reached, return otherwise */
1491  if( (SCIPgetNNodes(scip) - SCIPsolGetNodenum(bestsol)) < heurdata->waitingnodes )
1492  return SCIP_OKAY;
1493 
1494  presolthiscall = FALSE;
1495  SCIP_CALL( SCIPgetLPColsData(scip,&cols, &ncols) );
1496  ndiscvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
1497  ncolsforsorting = MIN(ncols, ndiscvars);
1498 
1499  /* ensure that heuristic specific presolve is applied when heuristic is executed first */
1500  if( !heurdata->presolved )
1501  {
1502  SCIP_CALL( SCIPgetLPColsData(scip,&cols, &ncols) );
1503 
1504  for( i = 0; i < ncolsforsorting; ++i )
1505  SCIPcolSort(cols[i]);
1506 
1507  SCIP_CALL( presolveTwoOpt(scip, heur, heurdata) );
1508  presolthiscall = TRUE;
1509  }
1510 
1511  assert(heurdata->presolved);
1512 
1513  SCIPdebugMessage(" Twoopt heuristic is %sexecuting.\n", heurdata->execute ? "" : "not ");
1514  /* ensure that presolve has detected structures in the problem to which the 2-optimization can be applied.
1515  * That is if variables exist which share a common set of LP-rows. */
1516  if( !heurdata->execute )
1517  return SCIP_OKAY;
1518 
1519  nbinvars = heurdata->nbinvars;
1520  nintvars = heurdata->nintvars;
1521  ndiscvars = nbinvars + nintvars;
1522 
1523  /* we need to be able to start diving from current node in order to resolve the LP
1524  * with continuous or implicit integer variables
1525  */
1526  if( SCIPgetNVars(scip) > ndiscvars && ( !SCIPhasCurrentNodeLP(scip) || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) )
1527  return SCIP_OKAY;
1528 
1529  /* problem satisfies all necessary conditions for 2-optimization heuristic, execute heuristic! */
1530  *result = SCIP_DIDNOTFIND;
1531 
1532  /* initialize a working solution as a copy of the current incumbent to be able to store
1533  * possible improvements obtained by 2-optimization */
1534  SCIP_CALL( SCIPcreateSolCopy(scip, &worksol, bestsol) );
1535  SCIPsolSetHeur(worksol, heur);
1536 
1537  /* get the LP row activities from current incumbent bestsol */
1538  SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) );
1539  SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) );
1540 
1541  for( i = 0; i < nlprows; i++ )
1542  {
1543  SCIP_ROW* row;
1544 
1545  row = lprows[i];
1546  assert(row != NULL);
1547  assert(SCIProwGetLPPos(row) == i);
1548  SCIPdebugMessage(" Row <%d> is %sin LP: \n", i, SCIProwGetLPPos(row) >= 0 ? "" : "not ");
1549  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
1550  activities[i] = SCIPgetRowSolActivity(scip, row, bestsol);
1551 
1552  /* Heuristic does not provide infeasibility recovery, thus if any constraint is violated,
1553  * execution has to be terminated.
1554  */
1555  if( !SCIProwIsLocal(row) && (SCIPisFeasLT(scip, activities[i], SCIProwGetLhs(row))
1556  || SCIPisFeasGT(scip, activities[i], SCIProwGetRhs(row))) )
1557  goto TERMINATE;
1558  }
1559 
1560  if( !presolthiscall )
1561  {
1562  for( i = 0; i < ncolsforsorting; ++i )
1563  SCIPcolSort(cols[i]);
1564  }
1565  SCIPdebugMessage(" Twoopt heuristic has initialized activities and sorted rows! \n");
1566 
1567  /* start with binary optimization */
1568  improvement = FALSE;
1569  varboundserr = FALSE;
1570 
1571  if( heurdata->nbinblocks > 0 )
1572  {
1573  SCIP_CALL( optimize(scip, worksol, heurdata->binvars, heurdata->binblockstart, heurdata->binblockend, heurdata->nbinblocks,
1574  OPTTYPE_BINARY, activities, nlprows, &improvement, &varboundserr, heurdata) );
1575 
1576  SCIPdebugMessage(" Binary Optimization finished!\n");
1577  }
1578 
1579  if( varboundserr )
1580  goto TERMINATE;
1581 
1582  /* ensure that their are at least two integer variables which do not have the same coefficient
1583  * in the objective function. In one of these cases, the heuristic will automatically skip the
1584  * integer variable optimization */
1585  if( heurdata->nintblocks > 0 )
1586  {
1587  assert(heurdata->intopt);
1588  SCIP_CALL( optimize(scip, worksol, heurdata->intvars, heurdata->intblockstart, heurdata->intblockend, heurdata->nintblocks,
1589  OPTTYPE_INTEGER, activities, nlprows, &improvement, &varboundserr, heurdata) );
1590 
1591  SCIPdebugMessage(" Integer Optimization finished!\n");
1592  }
1593 
1594  if( ! improvement || varboundserr )
1595  goto TERMINATE;
1596 
1597  if( SCIPgetNVars(scip) == ndiscvars )
1598  {
1599  /* the problem is a pure IP, hence, no continuous or implicit variables are left for diving.
1600  * try if new working solution is feasible in original problem */
1601  SCIP_Bool success;
1602 #ifndef NDEBUG
1603  SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, TRUE, TRUE, TRUE, &success) );
1604 #else
1605  SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, FALSE, TRUE, &success) );
1606 #endif
1607 
1608  if( success )
1609  {
1610  SCIPdebugMessage("found feasible shifted solution:\n");
1611  SCIPdebug( SCIP_CALL( SCIPprintSol(scip, worksol, NULL, FALSE) ) );
1612  heurdata->lastsolindex = SCIPsolGetIndex(bestsol);
1613  *result = SCIP_FOUNDSOL;
1614 
1615 #ifdef SCIP_STATISTIC
1616  SCIPstatisticMessage("***Twoopt improved solution found by %10s . \n",
1617  SCIPsolGetHeur(bestsol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(bestsol)) :"Tree");
1618 #endif
1619  }
1620  }
1621  /* fix the integer variables and start diving to optimize continuous variables with respect to reduced domain */
1622  else
1623  {
1624  SCIP_VAR** allvars;
1625  SCIP_Bool lperror;
1626 #ifdef NDEBUG
1627  SCIP_RETCODE retstat;
1628 #endif
1629 
1630  SCIPdebugMessage("shifted solution should be feasible -> solve LP to fix continuous variables to best values\n");
1631 
1632  allvars = SCIPgetVars(scip);
1633 
1634 #ifdef SCIP_DEBUG
1635  for( i = ndiscvars; i < SCIPgetNVars(scip); ++i )
1636  {
1637  SCIPdebugMessage(" Cont. variable <%s>, status %d with bounds [%g <= %g <= x <= %g <= %g]\n",
1638  SCIPvarGetName(allvars[i]), SCIPvarGetStatus(allvars[i]), SCIPvarGetLbGlobal(allvars[i]), SCIPvarGetLbLocal(allvars[i]), SCIPvarGetUbLocal(allvars[i]),
1639  SCIPvarGetUbGlobal(allvars[i]));
1640  }
1641 #endif
1642 
1643  /* start diving to calculate the LP relaxation */
1644  SCIP_CALL( SCIPstartDive(scip) );
1645 
1646  /* set the bounds of the variables: fixed for integers, global bounds for continuous */
1647  for( i = 0; i < SCIPgetNVars(scip); ++i )
1648  {
1649  if( SCIPvarGetStatus(allvars[i]) == SCIP_VARSTATUS_COLUMN )
1650  {
1651  SCIP_CALL( SCIPchgVarLbDive(scip, allvars[i], SCIPvarGetLbGlobal(allvars[i])) );
1652  SCIP_CALL( SCIPchgVarUbDive(scip, allvars[i], SCIPvarGetUbGlobal(allvars[i])) );
1653  }
1654  }
1655 
1656  /* apply this after global bounds to not cause an error with intermediate empty domains */
1657  for( i = 0; i < ndiscvars; ++i )
1658  {
1659  if( SCIPvarGetStatus(allvars[i]) == SCIP_VARSTATUS_COLUMN )
1660  {
1661  SCIP_Real solval;
1662 
1663  solval = SCIPgetSolVal(scip, worksol, allvars[i]);
1664 
1665  assert(SCIPvarGetType(allvars[i]) != SCIP_VARTYPE_CONTINUOUS && SCIPisFeasIntegral(scip, solval));
1666 
1667  SCIP_CALL( SCIPchgVarLbDive(scip, allvars[i], solval) );
1668  SCIP_CALL( SCIPchgVarUbDive(scip, allvars[i], solval) );
1669  }
1670  }
1671  for( i = 0; i < ndiscvars; ++i )
1672  {
1673  assert( SCIPisFeasEQ(scip, SCIPgetVarLbDive(scip, allvars[i]), SCIPgetVarUbDive(scip, allvars[i])) );
1674  }
1675  /* solve LP */
1676  SCIPdebugMessage(" -> old LP iterations: %" SCIP_LONGINT_FORMAT "\n", SCIPgetNLPIterations(scip));
1677 
1678  /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
1679  * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */
1680 #ifdef NDEBUG
1681  retstat = SCIPsolveDiveLP(scip, -1, &lperror, NULL);
1682  if( retstat != SCIP_OKAY )
1683  {
1684  SCIPwarningMessage(scip, "Error while solving LP in Twoopt heuristic; LP solve terminated with code <%d>\n",retstat);
1685  }
1686 #else
1687  SCIP_CALL( SCIPsolveDiveLP(scip, -1, &lperror, NULL) );
1688 #endif
1689 
1690  SCIPdebugMessage(" -> new LP iterations: %" SCIP_LONGINT_FORMAT "\n", SCIPgetNLPIterations(scip));
1691  SCIPdebugMessage(" -> error=%u, status=%d\n", lperror, SCIPgetLPSolstat(scip));
1692 
1693  /* check if this is a feasible solution */
1694  if( !lperror && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
1695  {
1696  SCIP_Bool success;
1697 
1698  /* copy the current LP solution to the working solution */
1699  SCIP_CALL( SCIPlinkLPSol(scip, worksol) );
1700 
1701  /* check solution for feasibility */
1702 #ifndef NDEBUG
1703  SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, TRUE, TRUE, TRUE, &success) );
1704 #else
1705  SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, FALSE, TRUE, &success) );
1706 #endif
1707 
1708  if( success )
1709  {
1710  SCIPdebugMessage("found feasible shifted solution:\n");
1711  SCIPdebug( SCIP_CALL( SCIPprintSol(scip, worksol, NULL, FALSE) ) );
1712  heurdata->lastsolindex = SCIPsolGetIndex(bestsol);
1713  *result = SCIP_FOUNDSOL;
1714 
1715 #ifdef SCIP_STATISTIC
1716  SCIPstatisticMessage("*** Twoopt improved solution found by %10s . \n",
1717  SCIPsolGetHeur(bestsol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(bestsol)) :"Tree");
1718 #endif
1719  }
1720  }
1721 
1722  /* terminate the diving */
1723  SCIP_CALL( SCIPendDive(scip) );
1724  }
1725 
1726  TERMINATE:
1727  SCIPdebugMessage("Termination of Twoopt heuristic\n");
1728  SCIPfreeBufferArray(scip, &activities);
1729  SCIP_CALL( SCIPfreeSol(scip, &worksol) );
1730 
1731  return SCIP_OKAY;
1732 }
1733 
1734 /*
1735  * primal heuristic specific interface methods
1736  */
1737 
1738 /** creates the twoopt primal heuristic and includes it in SCIP */
1740  SCIP* scip /**< SCIP data structure */
1741  )
1742 {
1743  SCIP_HEURDATA* heurdata;
1744  SCIP_HEUR* heur;
1745 
1746  /* create Twoopt primal heuristic data */
1747  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
1748 
1749  /* include primal heuristic */
1750  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
1752  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecTwoopt, heurdata) );
1753 
1754  assert(heur != NULL);
1755 
1756  /* set non-NULL pointers to callback methods */
1757  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyTwoopt) );
1758  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeTwoopt) );
1759  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitTwoopt) );
1760  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitTwoopt) );
1761  SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolTwoopt) );
1762  SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolTwoopt) );
1763 
1764  /* include boolean flag intopt */
1765  SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/twoopt/intopt", " Should Integer-2-Optimization be applied or not?",
1766  &heurdata->intopt, TRUE, DEFAULT_INTOPT, NULL, NULL) );
1767 
1768  /* include parameter waitingnodes */
1769  SCIP_CALL( SCIPaddIntParam(scip, "heuristics/twoopt/waitingnodes", "user parameter to determine number of "
1770  "nodes to wait after last best solution before calling heuristic",
1771  &heurdata->waitingnodes, TRUE, DEFAULT_WAITINGNODES, 0, 10000, NULL, NULL));
1772 
1773  /* include parameter maxnslaves */
1774  SCIP_CALL( SCIPaddIntParam(scip, "heuristics/twoopt/maxnslaves", "maximum number of slaves for one master variable",
1775  &heurdata->maxnslaves, TRUE, DEFAULT_MAXNSLAVES, -1, 1000000, NULL, NULL) );
1776 
1777  /* include parameter matchingrate */
1778  SCIP_CALL( SCIPaddRealParam(scip, "heuristics/twoopt/matchingrate",
1779  "parameter to determine the percentage of rows two variables have to share before they are considered equal",
1780  &heurdata->matchingrate, TRUE, DEFAULT_MATCHINGRATE, 0.0, 1.0, NULL, NULL) );
1781 
1782  return SCIP_OKAY;
1783 }
SCIP_RETCODE SCIPsetHeurInitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINITSOL((*heurinitsol)))
Definition: scip.c:7361
static SCIP_RETCODE shiftValues(SCIP *scip, SCIP_VAR *master, SCIP_VAR *slave, SCIP_Real mastersolval, DIRECTION masterdir, SCIP_Real slavesolval, DIRECTION slavedir, SCIP_Real shiftval, SCIP_Real *activities, int nrows, SCIP_Bool *feasible)
Definition: heur_twoopt.c:127
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41685
Primal heuristic to improve incumbent solution by flipping pairs of variables.
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:10698
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:20526
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2252
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16443
SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip.c:28285
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:20589
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:41648
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1147
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20573
static SCIP_DECL_HEURFREE(heurFreeTwoopt)
Definition: heur_twoopt.c:810
SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
Definition: scip.c:7297
void SCIPsortRealPtrPtrInt(SCIP_Real *realarray, void **ptrarray1, void **ptrarray2, int *intarray, int len)
SCIP_RETCODE SCIPincludeHeurTwoopt(SCIP *scip)
Definition: heur_twoopt.c:1740
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1248
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41920
SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
Definition: scip.c:37454
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:10653
#define NULL
Definition: lpi_spx.cpp:130
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17113
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:42032
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:18915
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17067
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:34843
#define DEFAULT_WAITINGNODES
Definition: heur_twoopt.c:41
SCIP_RETCODE SCIPincludeHeurBasic(SCIP *scip, SCIP_HEUR **heur, const char *name, const char *desc, char dispchar, int priority, int freq, int freqofs, int maxdepth, unsigned int timingmask, SCIP_Bool usessubscip, SCIP_DECL_HEUREXEC((*heurexec)), SCIP_HEURDATA *heurdata)
Definition: scip.c:7252
SCIP_RETCODE SCIPchgVarUbDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip.c:31772
#define DEFAULT_MAXNSLAVES
Definition: heur_twoopt.c:45
#define DEFAULT_INTOPT
Definition: heur_twoopt.c:40
int SCIProwGetIndex(SCIP_ROW *row)
Definition: lp.c:18984
#define FALSE
Definition: def.h:56
static SCIP_RETCODE optimize(SCIP *scip, SCIP_SOL *worksol, SCIP_VAR **vars, int *blockstart, int *blockend, int nblocks, OPTTYPE opttype, SCIP_Real *activities, int nrows, SCIP_Bool *improvement, SCIP_Bool *varboundserr, SCIP_HEURDATA *heurdata)
Definition: heur_twoopt.c:888
int SCIPgetNBinVars(SCIP *scip)
Definition: scip.c:10743
#define HEUR_FREQ
Definition: heur_twoopt.c:32
#define TRUE
Definition: def.h:55
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
#define SCIPstatisticMessage
Definition: pub_message.h:104
void SCIPcolSort(SCIP_COL *col)
Definition: lp.c:3241
#define SCIP_CALL(x)
Definition: def.h:266
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41972
struct SCIP_HeurData SCIP_HEURDATA
Definition: type_heur.h:51
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:42008
#define HEUR_FREQOFS
Definition: heur_twoopt.c:33
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20556
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:26439
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:34983
static SCIP_DECL_SORTPTRCOMP(SCIPvarcolComp)
Definition: heur_twoopt.c:275
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:16905
#define HEUR_NAME
Definition: heur_twoopt.c:28
#define HEUR_TIMING
Definition: heur_twoopt.c:36
SCIP_RETCODE SCIPstartDive(SCIP *scip)
Definition: scip.c:31575
static SCIP_DECL_HEURINITSOL(heurInitsolTwoopt)
Definition: heur_twoopt.c:1346
SCIP_RETCODE SCIPgetLPColsData(SCIP *scip, SCIP_COL ***cols, int *ncols)
Definition: scip.c:26672
Direction
Definition: heur_twoopt.c:110
SCIP_RETCODE SCIPchgVarLbDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip.c:31740
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3547
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16562
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3573
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16634
static SCIP_DECL_HEURINIT(heurInitTwoopt)
Definition: heur_twoopt.c:830
static SCIP_DECL_HEUREXIT(heurExitTwoopt)
Definition: heur_twoopt.c:1252
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:20542
static SCIP_RETCODE presolveTwoOpt(SCIP *scip, SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
Definition: heur_twoopt.c:715
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition: lp.c:18784
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:41709
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:18925
void SCIPsolSetHeur(SCIP_SOL *sol, SCIP_HEUR *heur)
Definition: sol.c:2293
static SCIP_DECL_HEUREXEC(heurExecTwoopt)
Definition: heur_twoopt.c:1442
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41907
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:19024
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:20562
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:16771
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip.c:26750
static int varColCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: heur_twoopt.c:232
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Bool SCIPhasCurrentNodeLP(SCIP *scip)
Definition: scip.c:26354
SCIP_Real SCIPgetVarLbDive(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:31937
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:18974
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41946
void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
Definition: heur.c:1068
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17123
#define SCIP_Bool
Definition: def.h:53
#define DEFAULT_ARRAYSIZE
Definition: heur_twoopt.c:46
#define HEUR_DESC
Definition: heur_twoopt.c:29
SCIP_Longint SCIPsolGetNodenum(SCIP_SOL *sol)
Definition: sol.c:2232
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip.c:34271
static SCIP_RETCODE innerPresolve(SCIP *scip, SCIP_VAR **vars, SCIP_VAR ***varspointer, int nvars, int *nblocks, int *maxblocksize, int *nblockvars, int **blockstart, int **blockend, SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
Definition: heur_twoopt.c:616
enum Direction DIRECTION
Definition: heur_twoopt.c:116
Opttype
Definition: heur_twoopt.c:102
SCIP_RETCODE SCIPsetHeurExitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXITSOL((*heurexitsol)))
Definition: scip.c:7377
int SCIPsolGetIndex(SCIP_SOL *sol)
Definition: sol.c:2283
SCIP_RETCODE SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:34648
SCIP_Bool SCIPsolIsOriginal(SCIP_SOL *sol)
Definition: sol.c:2179
#define DEFAULT_MATCHINGRATE
Definition: heur_twoopt.c:42
SCIP_RETCODE SCIPsetHeurExit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXIT((*heurexit)))
Definition: scip.c:7345
int SCIPgetRandomInt(int minrandval, int maxrandval, unsigned int *seedp)
Definition: misc.c:7700
SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
Definition: scip.c:7329
enum Opttype OPTTYPE
Definition: heur_twoopt.c:107
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16608
static SCIP_DECL_HEURCOPY(heurCopyTwoopt)
Definition: heur_twoopt.c:796
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:20585
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17057
#define HEUR_MAXDEPTH
Definition: heur_twoopt.c:34
static void disposeVariable(SCIP_VAR **vars, int *blockend, int varindex)
Definition: heur_twoopt.c:601
SCIP_RETCODE SCIPendDive(SCIP *scip)
Definition: scip.c:31618
int SCIPgetNIntVars(SCIP *scip)
Definition: scip.c:10788
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41933
SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
Definition: scip.c:7313
#define SCIP_Real
Definition: def.h:127
#define HEUR_PRIORITY
Definition: heur_twoopt.c:31
#define MIN(x, y)
Definition: memory.c:67
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:28334
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41959
#define HEUR_USESSUBSCIP
Definition: heur_twoopt.c:37
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:20568
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:19104
SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
Definition: heur.c:1058
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip.c:10572
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:20597
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41697
SCIP_RETCODE SCIPsolveDiveLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip.c:31999
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip.c:35767
SCIP_Real * SCIPcolGetVals(SCIP_COL *col)
Definition: lp.c:18794
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3629
int SCIPcolGetNNonz(SCIP_COL *col)
Definition: lp.c:18759
#define HEUR_DISPCHAR
Definition: heur_twoopt.c:30
static SCIP_DECL_HEUREXITSOL(heurExitsolTwoopt)
Definition: heur_twoopt.c:1379
SCIP_Real SCIPgetVarUbDive(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:31966
int SCIPgetNLPRows(SCIP *scip)
Definition: scip.c:26806
SCIP_RETCODE SCIPtrySol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
Definition: scip.c:36217
static SCIP_Bool checkConstraintMatching(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real matchingrate)
Definition: heur_twoopt.c:284
SCIP_Longint SCIPgetNNodes(SCIP *scip)
Definition: scip.c:37372
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip.c:35397
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:34607
static SCIP_Real determineBound(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *master, DIRECTION masterdirection, SCIP_VAR *slave, DIRECTION slavedirection, SCIP_Real *activities, int nrows)
Definition: heur_twoopt.c:376