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