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