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