SCIP Doxygen Documentation
Loading...
Searching...
No Matches
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-2026 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
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 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 */
134typedef enum Opttype OPTTYPE;
135
136/** indicator for direction of shifting variables */
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);
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 );
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)) );
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
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 */
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;
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
879
880 /* call inclusion method of primal heuristic */
882
883 return SCIP_OKAY;
884}
885
886/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
887static
888SCIP_DECL_HEURFREE(heurFreeTwoopt)
889{ /*lint --e{715}*/
891
892 assert(heur != NULL);
893 assert(scip != NULL);
894
896
897 /* free heuristic data */
899 assert(heurdata != NULL);
900
902 SCIPheurSetData(heur, NULL);
903
904 return SCIP_OKAY;
905}
906
907/** initialization method of primal heuristic (called after problem was transformed) */
908static
909SCIP_DECL_HEURINIT(heurInitTwoopt)
910{
912 assert(heur != NULL);
913 assert(scip != NULL);
914
916
918 assert(heurdata != NULL);
919
920 /* heuristic has not run yet, all heuristic specific data is set to initial values */
921 heurdata->nbinvars = 0;
922 heurdata->nintvars = 0;
923 heurdata->lastsolindex = -1;
924 heurdata->presolved = FALSE;
925 heurdata->nbinblocks = 0;
926 heurdata->nintblocks = 0;
927
928 /* create random number generator */
931
932#ifdef SCIP_STATISTIC
933 /* initialize statistics */
934 heurdata->binnexchanges = 0;
935 heurdata->intnexchanges = 0;
936 heurdata->binnblockvars = 0;
937 heurdata->intnblockvars = 0;
938 heurdata->binnblocks = 0;
939 heurdata->intnblocks = 0;
940
941 heurdata->maxbinblocksize = 0;
942 heurdata->maxintblocksize = 0;
943
944 heurdata->ntotalbinvars = 0;
945 heurdata->ntotalintvars = 0;
946 heurdata->nruns = 0;
947#endif
948
949 /* all pointers are initially set to NULL. Since presolving
950 * of the heuristic requires a lot of calculation time on some instances,
951 * but might not be needed e.g. if problem is infeasible, presolving is applied
952 * when heuristic is executed for the first time
953 */
954 heurdata->binvars = NULL;
955 heurdata->intvars = NULL;
956 heurdata->binblockstart = NULL;
957 heurdata->binblockend = NULL;
958 heurdata->intblockstart = NULL;
959 heurdata->intblockend = NULL;
960
962
963 return SCIP_OKAY;
964}
965
966/* Realizes the 2-optimization algorithm, which tries to improve incumbent solution
967 * by shifting pairs of variables which share a common row set.
968 */
969static
971 SCIP* scip, /**< current SCIP instance */
972 SCIP_SOL* worksol, /**< working solution */
973 SCIP_VAR** vars, /**< binary or integer variables */
974 int* blockstart, /**< contains start indices of blocks */
975 int* blockend, /**< contains end indices of blocks */
976 int nblocks, /**< the number of blocks */
977 OPTTYPE opttype, /**< are binaries or integers optimized */
978 SCIP_Real* activities, /**< the LP-row activities */
979 int nrows, /**< the number of LP rows */
980 SCIP_Bool* improvement, /**< was there a successful shift? */
981 SCIP_Bool* varboundserr, /**< has the current incumbent already been cut off */
982 SCIP_HEURDATA* heurdata /**< the heuristic data */
983 )
984{ /*lint --e{715}*/
985 SCIP_Real* objchanges;
986 SCIP_VAR** bestmasters;
987 SCIP_VAR** bestslaves;
988 int* bestdirections;
989 int arraysize;
990 int npairs = 0;
991
992 assert(scip != NULL);
993 assert(nblocks > 0);
994 assert(blockstart != NULL && blockend != NULL);
995 assert(varboundserr != NULL);
997 assert(worksol != NULL);
998 assert(improvement != NULL);
999
1000 *varboundserr = FALSE;
1001
1006 arraysize = DEFAULT_ARRAYSIZE;
1007
1008 /* iterate over blocks */
1009 for( int b = 0; b < nblocks; ++b )
1010 {
1011 int blocklen;
1012
1013 blocklen = blockend[b] - blockstart[b] + 1;
1014
1015 /* iterate over variables in current block */
1016 for( int m = 0; m < blocklen; ++m )
1017 {
1018 /* determine the new master variable for heuristic's optimization method */
1019 SCIP_VAR* master;
1020 SCIP_Real masterobj;
1021 SCIP_Real mastersolval;
1022 SCIP_Real bestimprovement;
1023 SCIP_Real bestbound;
1024 int bestslavepos;
1025 int firstslave;
1026 int nslaves;
1027 int bestdirection;
1028 DIRECTION bestmasterdir;
1029 DIRECTION bestslavedir;
1030
1031 master = vars[blockstart[b] + m]; /*lint !e679*/
1032 masterobj = SCIPvarGetObj(master);
1033 mastersolval = SCIPgetSolVal(scip, worksol, master);
1034
1035 /* due to cuts or fixings of solution values, worksol might not be feasible w.r.t. its bounds.
1036 * Exit method in that case. */
1037 if( SCIPisFeasGT(scip, mastersolval, SCIPvarGetUbGlobal(master)) || SCIPisFeasLT(scip, mastersolval, SCIPvarGetLbGlobal(master)) )
1038 {
1039 *varboundserr = TRUE;
1040 SCIPdebugMsg(scip, "Solution has violated variable bounds for var %s: %g <= %g <= %g \n",
1041 SCIPvarGetName(master), SCIPvarGetLbGlobal(master), mastersolval, SCIPvarGetUbGlobal(master));
1042 goto TERMINATE;
1043 }
1044
1045 /* if variable has fixed solution value, it is deleted from heuristic array */
1047 {
1048 disposeVariable(vars, &(blockend[b]), blockstart[b] + m);
1049 --blocklen;
1050 continue;
1051 }
1052 else if( SCIPvarGetStatus(master) != SCIP_VARSTATUS_COLUMN )
1053 continue;
1054
1055 assert(SCIPisFeasIntegral(scip, mastersolval));
1056
1057 assert(opttype == OPTTYPE_INTEGER || (SCIPisFeasLE(scip, mastersolval, 1.0) || SCIPisFeasGE(scip, mastersolval, 0.0)));
1058
1059 /* initialize the data of the best available shift */
1060 bestimprovement = 0.0;
1061 bestslavepos = -1;
1062 bestbound = 0.0;
1063 bestmasterdir = DIRECTION_NONE;
1064 bestslavedir = DIRECTION_NONE;
1065 bestdirection = -1;
1066
1067 /* in blocks with more than heurdata->maxnslaves variables, a slave candidate region is chosen */
1068 if( heurdata->maxnslaves >= 0 && blocklen > heurdata->maxnslaves )
1069 firstslave = SCIPrandomGetInt(heurdata->randnumgen, blockstart[b] + m, blockend[b]);
1070 else
1071 firstslave = blockstart[b] + m + 1;
1072
1073 nslaves = MIN((heurdata->maxnslaves == -1 ? INT_MAX : heurdata->maxnslaves), blocklen);
1074
1075 /* Loop over block and determine a slave shift candidate for master variable.
1076 * If more than one candidate is available, choose the shift which improves objective function
1077 * the most. */
1078 for( int s = 0; s < nslaves; ++s )
1079 {
1080 SCIP_VAR* slave;
1081 SCIP_Real slaveobj;
1082 SCIP_Real slavesolval;
1083 SCIP_Real changedobj;
1084 SCIP_Real diffdirbound;
1085 SCIP_Real equaldirbound;
1086 int directions;
1087 int slaveindex;
1088
1089 slaveindex = (firstslave + s - blockstart[b]) % blocklen;
1090 slaveindex += blockstart[b];
1091
1092 /* in case of a small block, we do not want to try possible pairings twice */
1093 if( (blocklen <= heurdata->maxnslaves || heurdata->maxnslaves == -1) && slaveindex < blockstart[b] + m )
1094 break;
1095 /* master and slave should not be the same variable */
1096 if( slaveindex == blockstart[b] + m )
1097 continue;
1098
1099 /* get the next slave variable */
1100 slave = vars[slaveindex];
1101 slaveobj = SCIPvarGetObj(slave);
1102 slavesolval = SCIPgetSolVal(scip, worksol, slave);
1103 changedobj = 0.0;
1104
1105 assert(SCIPvarGetType(master) == SCIPvarGetType(slave));
1106 assert(SCIPisFeasIntegral(scip, slavesolval));
1107 assert(opttype == OPTTYPE_INTEGER || (SCIPisFeasLE(scip, mastersolval, 1.0) || SCIPisFeasGE(scip, mastersolval, 0.0)));
1108
1109 /* solution is not feasible w.r.t. the variable bounds, stop optimization in this case */
1110 if( SCIPisFeasGT(scip, slavesolval, SCIPvarGetUbGlobal(slave)) || SCIPisFeasLT(scip, slavesolval, SCIPvarGetLbGlobal(slave)) )
1111 {
1112 *varboundserr = TRUE;
1113 SCIPdebugMsg(scip, "Solution has violated variable bounds for var %s: %g <= %g <= %g \n",
1114 SCIPvarGetName(slave), SCIPvarGetLbGlobal(slave), slavesolval, SCIPvarGetUbGlobal(slave));
1115 goto TERMINATE;
1116 }
1117
1118 /* if solution value of the variable is fixed, delete it from the remaining candidates in the block */
1120 {
1121 disposeVariable(vars, &(blockend[b]), slaveindex);
1122 --blocklen;
1123 continue;
1124 }
1125 else if( SCIPvarGetStatus(master) != SCIP_VARSTATUS_COLUMN )
1126 continue;
1127
1128 /* determine the shifting direction to improve the objective function */
1129 /* The heuristic chooses the shifting direction and the corresponding maximum nonnegative
1130 * integer shift value for the two variables which preserves feasibility and improves
1131 * the objective function value. */
1132 directions = -1;
1133 diffdirbound = 0.0;
1134 equaldirbound = 0.0;
1135
1136 if( SCIPisPositive(scip, slaveobj - masterobj) )
1137 {
1138 diffdirbound = determineBound(scip, worksol, master, DIRECTION_UP, slave, DIRECTION_DOWN, activities, nrows);
1139 directions = 2;
1140 /* the improvement of objective function is calculated */
1141 changedobj = (masterobj - slaveobj) * diffdirbound;
1142 }
1143 else if( SCIPisPositive(scip, masterobj - slaveobj) )
1144 {
1145 diffdirbound = determineBound(scip, worksol, master, DIRECTION_DOWN, slave, DIRECTION_UP, activities, nrows);
1146 directions = 1;
1147 changedobj = (slaveobj - masterobj) * diffdirbound;
1148 }
1149
1150 if( SCIPisPositive(scip, -(masterobj + slaveobj)) )
1151 {
1152 equaldirbound = determineBound(scip, worksol, master, DIRECTION_UP, slave, DIRECTION_UP, activities, nrows);
1153 if( (masterobj + slaveobj) * equaldirbound < changedobj )
1154 {
1155 changedobj = (masterobj + slaveobj) * equaldirbound;
1156 directions = 3;
1157 }
1158 }
1159 else if( SCIPisPositive(scip, masterobj + slaveobj) )
1160 {
1161 equaldirbound = determineBound(scip, worksol, master, DIRECTION_DOWN, slave, DIRECTION_DOWN, activities, nrows);
1162 if( -(masterobj + slaveobj) * equaldirbound < changedobj )
1163 {
1164 changedobj = -(masterobj + slaveobj) * equaldirbound;
1165 directions = 0;
1166 }
1167 }
1168 assert(SCIPisFeasIntegral(scip, equaldirbound));
1169 assert(SCIPisFeasIntegral(scip, diffdirbound));
1170 assert(SCIPisFeasGE(scip, equaldirbound, 0.0));
1171 assert(SCIPisFeasGE(scip, diffdirbound, 0.0));
1172
1173 /* choose the candidate which improves the objective function the most */
1174 if( (SCIPisFeasGT(scip, equaldirbound, 0.0) || SCIPisFeasGT(scip, diffdirbound, 0.0))
1175 && changedobj < bestimprovement )
1176 {
1177 bestimprovement = changedobj;
1178 bestslavepos = slaveindex;
1179 bestdirection = directions;
1180
1181 /* the most promising shift, i.e., the one which can improve the objective
1182 * the most, is recorded by the integer 'directions'. It is recovered via the use
1183 * of a binary representation of the four different combinations for the shifting directions
1184 * of two variables */
1185 if( directions / 2 == 1 )
1186 bestmasterdir = DIRECTION_UP;
1187 else
1188 bestmasterdir = DIRECTION_DOWN;
1189
1190 if( directions % 2 == 1 )
1191 bestslavedir = DIRECTION_UP;
1192 else
1193 bestslavedir = DIRECTION_DOWN;
1194
1195 if( bestmasterdir == bestslavedir )
1196 bestbound = equaldirbound;
1197 else
1198 bestbound = diffdirbound;
1199 }
1200 }
1201
1202 /* choose the most promising candidate, if one exists */
1203 if( bestslavepos >= 0 )
1204 {
1205 if( npairs == arraysize )
1206 {
1207 SCIP_CALL( SCIPreallocBufferArray(scip, &bestmasters, 2 * arraysize) );
1208 SCIP_CALL( SCIPreallocBufferArray(scip, &bestslaves, 2 * arraysize) );
1209 SCIP_CALL( SCIPreallocBufferArray(scip, &objchanges, 2 * arraysize) );
1210 SCIP_CALL( SCIPreallocBufferArray(scip, &bestdirections, 2 * arraysize) );
1211 arraysize = 2 * arraysize;
1212 }
1213 assert( npairs < arraysize );
1214
1215 bestmasters[npairs] = master;
1216 bestslaves[npairs] = vars[bestslavepos];
1217 objchanges[npairs] = ((int)bestslavedir * SCIPvarGetObj(bestslaves[npairs]) + (int)bestmasterdir * masterobj) * bestbound;
1218 bestdirections[npairs] = bestdirection;
1219
1220 assert(objchanges[npairs] < 0);
1221
1222 SCIPdebugMsg(scip, " Saved candidate pair {%s=%g, %s=%g} with objectives <%g>, <%g> to be set to {%g, %g} %d\n",
1223 SCIPvarGetName(master), mastersolval, SCIPvarGetName(bestslaves[npairs]), SCIPgetSolVal(scip, worksol, bestslaves[npairs]) ,
1224 masterobj, SCIPvarGetObj(bestslaves[npairs]), mastersolval + (int)bestmasterdir * bestbound, SCIPgetSolVal(scip, worksol, bestslaves[npairs])
1225 + (int)bestslavedir * bestbound, bestdirections[npairs]);
1226
1227 ++npairs;
1228 }
1229 }
1230 }
1231
1232 if( npairs == 0 )
1233 goto TERMINATE;
1234
1235 SCIPsortRealPtrPtrInt(objchanges, (void**)bestmasters, (void**)bestslaves, bestdirections, npairs);
1236
1237 for( int b = 0; b < npairs; ++b )
1238 {
1239 SCIP_VAR* master;
1240 SCIP_VAR* slave;
1241 SCIP_Real mastersolval;
1242 SCIP_Real slavesolval;
1243 SCIP_Real masterobj;
1244 SCIP_Real slaveobj;
1246 DIRECTION masterdir;
1247 DIRECTION slavedir;
1248
1249 master = bestmasters[b];
1250 slave = bestslaves[b];
1251 mastersolval = SCIPgetSolVal(scip, worksol, master);
1252 slavesolval = SCIPgetSolVal(scip, worksol, slave);
1253 masterobj =SCIPvarGetObj(master);
1254 slaveobj = SCIPvarGetObj(slave);
1255
1256 assert(0 <= bestdirections[b] && bestdirections[b] < 4);
1257
1258 if( bestdirections[b] / 2 == 1 )
1259 masterdir = DIRECTION_UP;
1260 else
1261 masterdir = DIRECTION_DOWN;
1262
1263 if( bestdirections[b] % 2 == 1 )
1264 slavedir = DIRECTION_UP;
1265 else
1266 slavedir = DIRECTION_DOWN;
1267
1268 bound = determineBound(scip, worksol, master, masterdir, slave, slavedir, activities, nrows);
1269
1270 if( !SCIPisZero(scip, bound) )
1271 {
1272 SCIP_Bool feasible;
1273#ifndef NDEBUG
1274 SCIP_Real changedobj;
1275#endif
1276
1277 SCIPdebugMsg(scip, " Promising candidates {%s=%g, %s=%g} with objectives <%g>, <%g> to be set to {%g, %g}\n",
1278 SCIPvarGetName(master), mastersolval, SCIPvarGetName(slave), slavesolval,
1279 masterobj, slaveobj, mastersolval + (int)masterdir * bound, slavesolval + (int)slavedir * bound);
1280
1281#ifndef NDEBUG
1282 /* the improvement of objective function is calculated */
1283 changedobj = ((int)slavedir * slaveobj + (int)masterdir * masterobj) * bound;
1284 assert( SCIPisPositive(scip, -changedobj) );
1285#endif
1286
1288 /* try to change the solution values of the variables */
1289 feasible = FALSE;
1290 SCIP_CALL( shiftValues(scip, master, slave, mastersolval, masterdir, slavesolval, slavedir, bound,
1291 activities, nrows, &feasible) );
1292
1293 if( feasible )
1294 {
1295 /* The variables' solution values were successfully shifted and can hence be updated. */
1296 assert(SCIPisFeasIntegral(scip, mastersolval + ((int)masterdir * bound)));
1297 assert(SCIPisFeasIntegral(scip, slavesolval + ((int)slavedir * bound)));
1298
1299 SCIP_CALL( SCIPsetSolVal(scip, worksol, master, mastersolval + (int)masterdir * bound) );
1300 SCIP_CALL( SCIPsetSolVal(scip, worksol, slave, slavesolval + (int)slavedir * bound) );
1301 SCIPdebugMsg(scip, " Feasible shift: <%s>[%g, %g] (obj: %f) <%f> --> <%f>\n",
1302 SCIPvarGetName(master), SCIPvarGetLbGlobal(master), SCIPvarGetUbGlobal(master), masterobj, mastersolval, SCIPgetSolVal(scip, worksol, master));
1303 SCIPdebugMsg(scip, " <%s>[%g, %g] (obj: %f) <%f> --> <%f>\n",
1304 SCIPvarGetName(slave), SCIPvarGetLbGlobal(slave), SCIPvarGetUbGlobal(slave), slaveobj, slavesolval, SCIPgetSolVal(scip, worksol, slave));
1305
1306#ifdef SCIP_STATISTIC
1307 /* update statistics */
1308 if( opttype == OPTTYPE_BINARY )
1309 ++(heurdata->binnexchanges);
1310 else
1311 ++(heurdata->intnexchanges);
1312#endif
1313
1314 *improvement = TRUE;
1315 }
1316 }
1317 }
1318 TERMINATE:
1319 SCIPfreeBufferArray(scip, &bestdirections);
1320 SCIPfreeBufferArray(scip, &objchanges);
1321 SCIPfreeBufferArray(scip, &bestslaves);
1322 SCIPfreeBufferArray(scip, &bestmasters);
1323
1324 return SCIP_OKAY;
1325}
1326
1327/** deinitialization method of primal heuristic (called before transformed problem is freed) */
1328static
1329SCIP_DECL_HEUREXIT(heurExitTwoopt)
1330{
1332
1333 heurdata = SCIPheurGetData(heur);
1334 assert(heurdata != NULL);
1335
1336 /*ensure that initialization was successful */
1337 assert(heurdata->nbinvars <= 1 || heurdata->binvars != NULL);
1338
1339#ifdef SCIP_STATISTIC
1340 /* print relevant statistics to console */
1342 " Twoopt Binary Statistics : "
1343 "%6.2g %6.2g %4.2g %4.0g %6d (blocks/run, variables/run, varpercentage, avg. block size, max block size) \n",
1344 heurdata->nruns == 0 ? 0.0 : (SCIP_Real)heurdata->binnblocks/(heurdata->nruns),
1345 heurdata->nruns == 0 ? 0.0 : (SCIP_Real)heurdata->binnblockvars/(heurdata->nruns),
1346 heurdata->ntotalbinvars == 0 ? 0.0 : (SCIP_Real)heurdata->binnblockvars/(heurdata->ntotalbinvars) * 100.0,
1347 heurdata->binnblocks == 0 ? 0.0 : heurdata->binnblockvars/(SCIP_Real)(heurdata->binnblocks),
1348 heurdata->maxbinblocksize);
1349
1351 " Twoopt Integer statistics : "
1352 "%6.2g %6.2g %4.2g %4.0g %6d (blocks/run, variables/run, varpercentage, avg block size, max block size) \n",
1353 heurdata->nruns == 0 ? 0.0 : (SCIP_Real)heurdata->intnblocks/(heurdata->nruns),
1354 heurdata->nruns == 0 ? 0.0 : (SCIP_Real)heurdata->intnblockvars/(heurdata->nruns),
1355 heurdata->ntotalintvars == 0 ? 0.0 : (SCIP_Real)heurdata->intnblockvars/(heurdata->ntotalintvars) * 100.0,
1356 heurdata->intnblocks == 0 ? 0.0 : heurdata->intnblockvars/(SCIP_Real)(heurdata->intnblocks),
1357 heurdata->maxintblocksize);
1358
1360 " Twoopt results : "
1361 "%6d %6d %4d %4.2g (runs, binary exchanges, Integer shiftings, matching rate)\n",
1362 heurdata->nruns,
1363 heurdata->binnexchanges,
1364 heurdata->intnexchanges,
1365 heurdata->matchingrate);
1366
1367 /* set statistics to initial values*/
1368 heurdata->binnblockvars = 0;
1369 heurdata->binnblocks = 0;
1370 heurdata->intnblocks = 0;
1371 heurdata->intnblockvars = 0;
1372 heurdata->binnexchanges = 0;
1373 heurdata->intnexchanges = 0;
1374#endif
1375
1376 /* free the allocated memory for the binary variables */
1377 if( heurdata->binvars != NULL )
1378 {
1379 SCIPfreeBlockMemoryArray(scip, &heurdata->binvars, heurdata->nbinvars);
1380 }
1381
1382 if( heurdata->nbinblocks > 0 )
1383 {
1384 assert(heurdata->binblockstart != NULL);
1385 assert(heurdata->binblockend != NULL);
1386
1387 SCIPfreeBlockMemoryArray(scip, &heurdata->binblockstart, heurdata->nbinblocks);
1388 SCIPfreeBlockMemoryArray(scip, &heurdata->binblockend, heurdata->nbinblocks);
1389 }
1390 heurdata->nbinvars = 0;
1391 heurdata->nbinblocks = 0;
1392
1393 if( heurdata->nintblocks > 0 )
1394 {
1395 assert(heurdata->intblockstart != NULL);
1396 assert(heurdata->intblockend != NULL);
1397
1398 SCIPfreeBlockMemoryArray(scip, &heurdata->intblockstart, heurdata->nintblocks);
1399 SCIPfreeBlockMemoryArray(scip, &heurdata->intblockend, heurdata->nintblocks);
1400 }
1401
1402 /* free the allocated memory for the integers */
1403 if( heurdata->intvars != NULL )
1404 {
1405 SCIPfreeBlockMemoryArray(scip, &heurdata->intvars, heurdata->nintvars);
1406 }
1407
1408 heurdata->nbinblocks = 0;
1409 heurdata->nintblocks = 0;
1410 heurdata->nbinvars = 0;
1411 heurdata->nintvars = 0;
1412
1413 assert(heurdata->binvars == NULL);
1414 assert(heurdata->intvars == NULL);
1415
1416 /* free random number generator */
1417 SCIPfreeRandom(scip, &heurdata->randnumgen);
1418
1420
1421 return SCIP_OKAY;
1422}
1423
1424/** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
1425static
1426SCIP_DECL_HEURINITSOL(heurInitsolTwoopt)
1427{
1429 assert(heur != NULL);
1430 assert(scip != NULL);
1431
1433
1434 /* get heuristic data */
1435 heurdata = SCIPheurGetData(heur);
1436
1437 assert(heurdata != NULL);
1438 assert(heurdata->binvars == NULL && heurdata->intvars == NULL);
1439 assert(heurdata->binblockstart == NULL && heurdata->binblockend == NULL);
1440 assert(heurdata->intblockstart == NULL && heurdata->intblockend == NULL);
1441
1442 /* set heuristic data to initial values, but increase the total number of runs */
1443 heurdata->nbinvars = 0;
1444 heurdata->nintvars = 0;
1445 heurdata->lastsolindex = -1;
1446 heurdata->presolved = FALSE;
1447
1448#ifdef SCIP_STATISTIC
1449 ++(heurdata->nruns);
1450#endif
1451
1453
1454 return SCIP_OKAY;
1455}
1456
1457
1458/** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
1459static
1460SCIP_DECL_HEUREXITSOL(heurExitsolTwoopt)
1461{
1463 int nbinvars;
1464 int nintvars;
1465
1466 assert(heur != NULL);
1467 assert(scip != NULL);
1468 assert(scip != NULL);
1469
1471
1472 /* get heuristic data */
1473 heurdata = SCIPheurGetData(heur);
1474
1475 assert(heurdata != NULL);
1476
1477 nbinvars = heurdata->nbinvars;
1478 nintvars = heurdata->nintvars;
1479
1480 /* free the allocated memory for the binary variables */
1481 if( heurdata->binvars != NULL )
1482 {
1483 SCIPfreeBlockMemoryArray(scip, &heurdata->binvars, nbinvars);
1484 }
1485 if( heurdata->binblockstart != NULL )
1486 {
1487 assert(heurdata->binblockend != NULL);
1488
1489 SCIPfreeBlockMemoryArray(scip, &heurdata->binblockstart, heurdata->nbinblocks);
1490 SCIPfreeBlockMemoryArray(scip, &heurdata->binblockend, heurdata->nbinblocks);
1491 }
1492 heurdata->nbinvars = 0;
1493 heurdata->nbinblocks = 0;
1494
1495 if( heurdata->intblockstart != NULL )
1496 {
1497 assert(heurdata->intblockend != NULL);
1498
1499 SCIPfreeBlockMemoryArray(scip, &heurdata->intblockstart, heurdata->nintblocks);
1500 SCIPfreeBlockMemoryArray(scip, &heurdata->intblockend, heurdata->nintblocks);
1501 }
1502 heurdata->nintblocks = 0;
1503
1504 /* free the allocated memory for the integers */
1505 if( heurdata->intvars != NULL )
1506 {
1507 SCIPfreeBlockMemoryArray(scip, &heurdata->intvars, nintvars);
1508 }
1509
1510 heurdata->nintvars = 0;
1511
1512 assert(heurdata->binvars == NULL && heurdata->intvars == NULL);
1513 assert(heurdata->binblockstart == NULL && heurdata->binblockend == NULL);
1514 assert(heurdata->intblockstart == NULL && heurdata->intblockend == NULL);
1515
1516 /* set heuristic data */
1518
1519 return SCIP_OKAY;
1520}
1521
1522/** execution method of primal heuristic */
1523static
1524SCIP_DECL_HEUREXEC(heurExecTwoopt)
1525{ /*lint --e{715}*/
1527 SCIP_ROW** lprows;
1528 SCIP_COL** cols;
1529 SCIP_SOL* bestsol;
1530 SCIP_SOL* worksol;
1532 SCIP_Bool improvement;
1533 SCIP_Bool presolthiscall;
1534 SCIP_Bool varboundserr;
1535 int ncols;
1536 int ndiscvars;
1537 int nlprows;
1538 int ncolsforsorting;
1539
1540 assert(heur != NULL);
1541 assert(scip != NULL);
1542 assert(result != NULL);
1543
1544 /* get heuristic data */
1545 heurdata = SCIPheurGetData(heur);
1546 assert(heurdata != NULL);
1547
1549
1550 /* we need an LP */
1551 if( SCIPgetNLPRows(scip) == 0 )
1552 return SCIP_OKAY;
1553
1554 bestsol = SCIPgetBestSol(scip);
1555
1556 /* ensure that heuristic has not already been processed on current incumbent */
1557 if( bestsol == NULL || heurdata->lastsolindex == SCIPsolGetIndex(bestsol) )
1558 return SCIP_OKAY;
1559
1560 heurdata->lastsolindex = SCIPsolGetIndex(bestsol);
1561
1562 /* we can only work on solutions valid in the transformed space */
1563 if( SCIPsolIsOriginal(bestsol) )
1564 return SCIP_OKAY;
1565
1566#ifdef SCIP_DEBUG
1567 SCIP_CALL( SCIPprintSol(scip, bestsol, NULL, TRUE) );
1568#endif
1569
1570 /* ensure that the user defined number of nodes after last best solution has been reached, return otherwise */
1571 if( (SCIPgetNNodes(scip) - SCIPsolGetNodenum(bestsol)) < heurdata->waitingnodes )
1572 return SCIP_OKAY;
1573
1575 assert(ndiscvars >= 0);
1576
1577 /* we need to be able to start diving from current node in order to resolve the LP
1578 * with continuous variables
1579 */
1581 return SCIP_OKAY;
1582
1583 /* ensure that heuristic specific presolve is applied when heuristic is executed first */
1584 presolthiscall = FALSE;
1585 SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
1586 ncolsforsorting = MIN(ncols, ndiscvars);
1587 if( !heurdata->presolved )
1588 {
1589 SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
1590
1591 for( int i = 0; i < ncolsforsorting; ++i )
1592 SCIPcolSort(cols[i]);
1593
1595 presolthiscall = TRUE;
1596 }
1597 assert(heurdata->presolved);
1598 assert(heurdata->nbinvars + heurdata->nintvars <= ndiscvars);
1599
1600 SCIPdebugMsg(scip, " Twoopt heuristic is %sexecuting.\n", heurdata->execute ? "" : "not ");
1601
1602 /* ensure that presolve has detected structures in the problem to which the 2-optimization can be applied.
1603 * That is if variables exist which share a common set of LP-rows. */
1604 if( !heurdata->execute )
1605 return SCIP_OKAY;
1606 assert(heurdata->nbinvars + heurdata->nintvars > 1);
1607
1608 /* problem satisfies all necessary conditions for 2-optimization heuristic, execute heuristic! */
1610
1611 /* initialize a working solution as a copy of the current incumbent to be able to store
1612 * possible improvements obtained by 2-optimization */
1613 SCIP_CALL( SCIPcreateSolCopy(scip, &worksol, bestsol) );
1614 SCIPsolSetHeur(worksol, heur);
1615
1616 /* get the LP row activities from current incumbent bestsol */
1619
1620 for( int i = 0; i < nlprows; ++i )
1621 {
1622 SCIP_ROW* row;
1623
1624 row = lprows[i];
1625 assert(row != NULL);
1626 assert(SCIProwGetLPPos(row) == i);
1627 SCIPdebugMsg(scip, " Row <%d> is %sin LP: \n", i, SCIProwGetLPPos(row) >= 0 ? "" : "not ");
1629 activities[i] = SCIPgetRowSolActivity(scip, row, bestsol);
1630
1631 /* Heuristic does not provide infeasibility recovery, thus if any constraint is violated,
1632 * execution has to be terminated.
1633 */
1636 goto TERMINATE;
1637 }
1638
1639 if( !presolthiscall )
1640 {
1641 for( int i = 0; i < ncolsforsorting; ++i )
1642 SCIPcolSort(cols[i]);
1643 }
1644 SCIPdebugMsg(scip, " Twoopt heuristic has initialized activities and sorted rows! \n");
1645
1646 /* start with binary optimization */
1647 improvement = FALSE;
1648 varboundserr = FALSE;
1649
1650 if( heurdata->nbinblocks > 0 )
1651 {
1652 SCIP_CALL( optimize(scip, worksol, heurdata->binvars, heurdata->binblockstart, heurdata->binblockend, heurdata->nbinblocks,
1653 OPTTYPE_BINARY, activities, nlprows, &improvement, &varboundserr, heurdata) );
1654
1655 SCIPdebugMsg(scip, " Binary Optimization finished!\n");
1656 }
1657
1658 if( varboundserr )
1659 goto TERMINATE;
1660
1661 /* ensure that their are at least two integer variables which do not have the same coefficient
1662 * in the objective function. In one of these cases, the heuristic will automatically skip the
1663 * integer variable optimization */
1664 if( heurdata->nintblocks > 0 )
1665 {
1666 assert(heurdata->intopt);
1667 SCIP_CALL( optimize(scip, worksol, heurdata->intvars, heurdata->intblockstart, heurdata->intblockend, heurdata->nintblocks,
1668 OPTTYPE_INTEGER, activities, nlprows, &improvement, &varboundserr, heurdata) );
1669
1670 SCIPdebugMsg(scip, " Integer Optimization finished!\n");
1671 }
1672
1673 if( ! improvement || varboundserr )
1674 goto TERMINATE;
1675
1676 if( SCIPgetNVars(scip) == ndiscvars )
1677 {
1678 /* the problem is a pure IP, hence, no continuous variables are left for diving.
1679 * try if new working solution is feasible in original problem */
1680 SCIP_Bool success;
1681#ifndef NDEBUG
1682 SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, TRUE, TRUE, TRUE, &success) );
1683#else
1684 SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, FALSE, FALSE, TRUE, &success) );
1685#endif
1686
1687 if( success )
1688 {
1689 SCIPdebugMsg(scip, "found feasible shifted solution:\n");
1690 SCIPdebug( SCIP_CALL( SCIPprintSol(scip, worksol, NULL, FALSE) ) );
1691 heurdata->lastsolindex = SCIPsolGetIndex(bestsol);
1693
1694#ifdef SCIP_STATISTIC
1695 SCIPstatisticMessage("***Twoopt improved solution found by %10s . \n",
1696 SCIPsolGetHeur(bestsol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(bestsol)) :"Tree");
1697#endif
1698 }
1699 }
1700 /* fix the integer variables and start diving to optimize continuous variables with respect to reduced domain */
1701 else
1702 {
1703 SCIP_VAR** allvars;
1705#ifdef NDEBUG
1706 SCIP_RETCODE retstat;
1707#endif
1708
1709 SCIPdebugMsg(scip, "shifted solution should be feasible -> solve LP to fix continuous variables to best values\n");
1710
1711 allvars = SCIPgetVars(scip);
1712
1713#ifdef SCIP_DEBUG
1714 for( int i = ndiscvars; i < SCIPgetNVars(scip); ++i )
1715 {
1716 SCIPdebugMsg(scip, " Cont. variable <%s>, status %d with bounds [%g <= %g <= x <= %g <= %g]\n",
1717 SCIPvarGetName(allvars[i]), SCIPvarGetStatus(allvars[i]), SCIPvarGetLbGlobal(allvars[i]), SCIPvarGetLbLocal(allvars[i]), SCIPvarGetUbLocal(allvars[i]),
1718 SCIPvarGetUbGlobal(allvars[i]));
1719 }
1720#endif
1721
1722 /* start diving to calculate the LP relaxation */
1724
1725 /* set the bounds of the variables: fixed for integers, global bounds for continuous */
1726 for( int i = 0; i < SCIPgetNVars(scip); ++i )
1727 {
1728 if( SCIPvarGetStatus(allvars[i]) == SCIP_VARSTATUS_COLUMN )
1729 {
1730 SCIP_CALL( SCIPchgVarLbDive(scip, allvars[i], SCIPvarGetLbGlobal(allvars[i])) );
1731 SCIP_CALL( SCIPchgVarUbDive(scip, allvars[i], SCIPvarGetUbGlobal(allvars[i])) );
1732 }
1733 }
1734
1735 /* apply this after global bounds to not cause an error with intermediate empty domains */
1736 for( int i = 0; i < ndiscvars; ++i )
1737 {
1738 if( SCIPvarGetStatus(allvars[i]) == SCIP_VARSTATUS_COLUMN )
1739 {
1740 SCIP_Real solval;
1741
1742 solval = SCIPgetSolVal(scip, worksol, allvars[i]);
1743
1744 assert(SCIPvarIsIntegral(allvars[i]) && SCIPisFeasIntegral(scip, solval));
1745
1746 SCIP_CALL( SCIPchgVarLbDive(scip, allvars[i], solval) );
1747 SCIP_CALL( SCIPchgVarUbDive(scip, allvars[i], solval) );
1748 }
1749 }
1750 for( int i = 0; i < ndiscvars; ++i )
1751 {
1752 assert( SCIPisFeasEQ(scip, SCIPgetVarLbDive(scip, allvars[i]), SCIPgetVarUbDive(scip, allvars[i])) );
1753 }
1754 /* solve LP */
1755 SCIPdebugMsg(scip, " -> old LP iterations: %" SCIP_LONGINT_FORMAT "\n", SCIPgetNLPIterations(scip));
1756
1757 /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
1758 * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */
1759#ifdef NDEBUG
1760 retstat = SCIPsolveDiveLP(scip, -1, &lperror, NULL);
1761 if( retstat != SCIP_OKAY )
1762 {
1763 SCIPwarningMessage(scip, "Error while solving LP in Twoopt heuristic; LP solve terminated with code <%d>\n",retstat);
1764 }
1765#else
1767#endif
1768
1769 SCIPdebugMsg(scip, " -> new LP iterations: %" SCIP_LONGINT_FORMAT "\n", SCIPgetNLPIterations(scip));
1770 SCIPdebugMsg(scip, " -> error=%u, status=%d\n", lperror, SCIPgetLPSolstat(scip));
1771
1772 /* check if this is a feasible solution */
1774 {
1775 SCIP_Bool success;
1776
1777 /* copy the current LP solution to the working solution */
1778 SCIP_CALL( SCIPlinkLPSol(scip, worksol) );
1779
1780 /* in exact mode we have to end diving prior to trying the solution */
1781 if( SCIPisExact(scip) )
1782 {
1783 SCIP_CALL( SCIPunlinkSol(scip, worksol) );
1785 }
1786
1787 /* check solution for feasibility */
1788#ifndef NDEBUG
1789 SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, TRUE, TRUE, TRUE, &success) );
1790#else
1791 SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, FALSE, FALSE, TRUE, &success) );
1792#endif
1793
1794 if( success )
1795 {
1796 SCIPdebugMsg(scip, "found feasible shifted solution:\n");
1797 SCIPdebug( SCIP_CALL( SCIPprintSol(scip, worksol, NULL, FALSE) ) );
1798 heurdata->lastsolindex = SCIPsolGetIndex(bestsol);
1800
1801#ifdef SCIP_STATISTIC
1802 SCIPstatisticMessage("*** Twoopt improved solution found by %10s . \n",
1803 SCIPsolGetHeur(bestsol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(bestsol)) :"Tree");
1804#endif
1805 }
1806 }
1807
1808 /* terminate the diving */
1809 if( SCIPinDive(scip) )
1810 {
1812 }
1813 }
1814
1815 TERMINATE:
1816 SCIPdebugMsg(scip, "Termination of Twoopt heuristic\n");
1818 SCIP_CALL( SCIPfreeSol(scip, &worksol) );
1819
1820 return SCIP_OKAY;
1821}
1822
1823/*
1824 * primal heuristic specific interface methods
1825 */
1826
1827/** creates the twoopt primal heuristic and includes it in SCIP */
1829 SCIP* scip /**< SCIP data structure */
1830 )
1831{
1833 SCIP_HEUR* heur;
1834
1835 /* create Twoopt primal heuristic data */
1837
1838 /* include primal heuristic */
1841 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecTwoopt, heurdata) );
1842
1843 assert(heur != NULL);
1844
1845 /* primal heuristic is safe to use in exact solving mode */
1846 SCIPheurMarkExact(heur);
1847
1848 /* set non-NULL pointers to callback methods */
1849 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyTwoopt) );
1850 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeTwoopt) );
1851 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitTwoopt) );
1852 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitTwoopt) );
1853 SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolTwoopt) );
1854 SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolTwoopt) );
1855
1856 /* include boolean flag intopt */
1857 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/twoopt/intopt", " Should Integer-2-Optimization be applied or not?",
1858 &heurdata->intopt, TRUE, DEFAULT_INTOPT, NULL, NULL) );
1859
1860 /* include parameter waitingnodes */
1861 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/twoopt/waitingnodes", "user parameter to determine number of "
1862 "nodes to wait after last best solution before calling heuristic",
1863 &heurdata->waitingnodes, TRUE, DEFAULT_WAITINGNODES, 0, 10000, NULL, NULL));
1864
1865 /* include parameter maxnslaves */
1866 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/twoopt/maxnslaves", "maximum number of slaves for one master variable",
1867 &heurdata->maxnslaves, TRUE, DEFAULT_MAXNSLAVES, -1, 1000000, NULL, NULL) );
1868
1869 /* include parameter matchingrate */
1870 SCIP_CALL( SCIPaddRealParam(scip, "heuristics/twoopt/matchingrate",
1871 "parameter to determine the percentage of rows two variables have to share before they are considered equal",
1872 &heurdata->matchingrate, TRUE, DEFAULT_MATCHINGRATE, 0.0, 1.0, NULL, NULL) );
1873
1874 return SCIP_OKAY;
1875}
static long bound
SCIP_VAR ** b
#define DEFAULT_RANDSEED
#define NULL
Definition def.h:257
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define ABS(x)
Definition def.h:225
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define SCIP_LONGINT_FORMAT
Definition def.h:157
#define SCIP_CALL(x)
Definition def.h:364
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
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
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)
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 SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur,)
Definition scip_heur.c:183
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 SCIPsetHeurInitsol(SCIP *scip, SCIP_HEUR *heur,)
Definition scip_heur.c:231
SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur,)
Definition scip_heur.c:167
SCIP_RETCODE SCIPsetHeurExitsol(SCIP *scip, SCIP_HEUR *heur,)
Definition scip_heur.c:247
void SCIPheurMarkExact(SCIP_HEUR *heur)
Definition heur.c:1457
SCIP_RETCODE SCIPsetHeurExit(SCIP *scip, SCIP_HEUR *heur,)
Definition scip_heur.c:215
SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur,)
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:2986
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition scip_sol.c:882
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition scip_sol.c:2351
SCIP_Longint SCIPsolGetNodenum(SCIP_SOL *sol)
Definition sol.c:4254
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition sol.c:4274
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:1504
SCIP_Bool SCIPsolIsOriginal(SCIP_SOL *sol)
Definition sol.c:4155
int SCIPsolGetIndex(SCIP_SOL *sol)
Definition sol.c:4305
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:4017
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition scip_sol.c:1569
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
void SCIPsolSetHeur(SCIP_SOL *sol, SCIP_HEUR *heur)
Definition sol.c:4319
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:23715
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23418
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23932
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:23485
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23522
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
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)
#define HEUR_TIMING
return SCIP_OKAY
#define HEUR_FREQOFS
#define HEUR_DESC
#define HEUR_DISPCHAR
#define HEUR_MAXDEPTH
#define HEUR_PRIORITY
SCIPfreeSol(scip, &heurdata->sol))
#define HEUR_NAME
#define HEUR_FREQ
#define HEUR_USESSUBSCIP
SCIPfreeRandom(scip, &heurdata->randnumgen)
#define DEFAULT_WAITINGNODES
Definition heur_alns.c:96
SCIP_Bool lperror
SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE))
int nlprows
SCIP_ROW ** lprows
static SCIP_SOL * sol
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIPlinkLPSol(scip, sol))
static SCIP_VAR ** vars
SCIP_Real * activities
static SCIP_Real determineBound(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *master, DIRECTION masterdirection, SCIP_VAR *slave, DIRECTION slavedirection, SCIP_Real *activities, int nrows)
Direction
@ DIRECTION_DOWN
@ DIRECTION_UP
@ DIRECTION_NONE
static void disposeVariable(SCIP_VAR **vars, int *blockend, int varindex)
enum Direction DIRECTION
#define DEFAULT_MATCHINGRATE
Definition heur_twoopt.c:70
static SCIP_Bool checkConstraintMatching(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real matchingrate)
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)
static int varColCompare(SCIP_VAR *var1, SCIP_VAR *var2)
#define DEFAULT_ARRAYSIZE
Definition heur_twoopt.c:73
enum Opttype OPTTYPE
#define DEFAULT_MAXNSLAVES
Definition heur_twoopt.c:72
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)
#define DEFAULT_INTOPT
Definition heur_twoopt.c:68
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)
Opttype
@ OPTTYPE_INTEGER
@ OPTTYPE_BINARY
static SCIP_RETCODE presolveTwoOpt(SCIP *scip, SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
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
#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
#define SCIP_DECL_HEURINITSOL(x)
Definition type_heur.h:132
#define SCIP_DECL_HEURCOPY(x)
Definition type_heur.h:97
struct SCIP_HeurData SCIP_HEURDATA
Definition type_heur.h:77
struct SCIP_Heur SCIP_HEUR
Definition type_heur.h:76
#define SCIP_DECL_HEURINIT(x)
Definition type_heur.h:113
#define SCIP_DECL_HEUREXIT(x)
Definition type_heur.h:121
#define SCIP_DECL_HEURFREE(x)
Definition type_heur.h:105
#define SCIP_DECL_HEUREXITSOL(x)
Definition type_heur.h:143
#define SCIP_DECL_HEUREXEC(x)
Definition type_heur.h:163
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
struct SCIP_Col SCIP_COL
Definition type_lp.h:99
@ SCIP_LPSOLSTAT_OPTIMAL
Definition type_lp.h:44
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:189
struct SCIP_RandNumGen SCIP_RANDNUMGEN
Definition type_misc.h:127
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_FOUNDSOL
Definition type_result.h:56
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARSTATUS_COLUMN
Definition type_var.h:53