Scippy

SCIP

Solving Constraint Integer Programs

sepa_zerohalf.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-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /* prints short statistics (callback, preprocessing, adding cuts) */
17 /* // #define SCIP_DEBUG */
18 /* // #define ZEROHALF__PRINT_STATISTICS */ /**< print statistics */
19 
20 /**
21  * @file sepa_zerohalf.c
22  * @brief {0,1/2}-cuts separator
23  * @author Manuel Kutschka
24  * @author Kati Wolter
25  *
26  * {0,1/2}-Chv'atal-Gomory cuts separator. It solves the following separation problem:
27  *
28  *
29  * Given an integer program
30  *
31  * - min { c^T x : Ax <= b, x >= 0, x integer }
32  *
33  * and a fractional solution x* of its LP relaxation.
34  *
35  * Find a weightvector u whose entries u_i are either 0 or 1/2 such that the following inequality is valid for all integral solutions and violated by x*
36  *
37  * - floor(u^T A) x <= floor(u^T b)
38  *
39  * or (if exact methods are used) give a proof that no such inequality exists
40  *
41  *
42  *
43  * References:
44  * - Alberto Caprara, Matteo Fischetti. {0,1/2}-Chvatal-Gomory cuts. Math. Programming, Volume 74, p221--235, 1996.
45  * - Arie M. C. A. Koster, Adrian Zymolka and Manuel Kutschka. \n
46  * Algorithms to separate {0,1/2}-Chvatal-Gomory cuts.
47  * Algorithms - ESA 2007: 15th Annual European Symposium, Eilat, Israel, October 8-10, 2007, \n
48  * Proceedings. Lecture Notes in Computer Science, Volume 4698, p. 693--704, 2007.
49  * - Arie M. C. A. Koster, Adrian Zymolka and Manuel Kutschka. \n
50  * Algorithms to separate {0,1/2}-Chvatal-Gomory cuts (Extended Version). \n
51  * ZIB Report 07-10, Zuse Institute Berlin, 2007. http://www.zib.de/Publications/Reports/ZR-07-10.pdf
52  * - Manuel Kutschka. Algorithmen zur Separierung von {0,1/2}-Schnitten. Diplomarbeit. Technische Universitaet Berlin, 2007.
53  */
54 
55 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
56 
57 #include "string.h"
58 #include "scip/sepa_zerohalf.h"
59 #include "scip/cons_linear.h"
60 #include "scip/scipdefplugins.h"
61 
62 
63 #define SEPA_NAME "zerohalf"
64 #define SEPA_DESC "{0,1/2}-cuts separator"
65 #define SEPA_PRIORITY -6000
66 #define SEPA_FREQ -1
67 #define SEPA_MAXBOUNDDIST 0.0
68 #define SEPA_USESSUBSCIP TRUE
69 #define SEPA_DELAY FALSE
70 
71 #define DEFAULT_MAXROUNDS 5 /**< maximal number of zerohalf separation rounds per node (-1: unlimited) */
72 #define DEFAULT_MAXROUNDSROOT 10 /**< maximal number of zerohalf separation rounds in the root node (-1: unlimited) */
73 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of {0,1/2}-cuts separated per separation round */
74 #define DEFAULT_MAXSEPACUTSROOT 500 /**< maximal number of {0,1/2}-cuts separated per separation round in root node */
75 #define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
76 #define DEFAULT_DECOMPOSEPROBLEM FALSE /**< should problem be decomposed into subproblems (if possible)? */
77 #define DEFAULT_MAXDEPTH -1 /**< separating cuts only if depth <= maxdepth (-1: unlimited) */
78 #define DEFAULT_MINVIOLATION 0.30 /**< minimal violation of a {0,1/2}-cut to be separated */
79 #define DEFAULT_FORCECUTSTOLP FALSE /**< should the cuts be forced to enter the LP? (bypassing SCIPefficacy criteria) */
80 #define DEFAULT_FORCECUTSTOSEPASTORE FALSE /**< should the cuts be forced to enter SCIP's sepastore?
81  * (bypassing SCIPefficicacy criteria, if no other cut is found) */
82 #define DEFAULT_MAXCUTS 100 /**< maximal number of {0,1/2}-cuts determined per separation round
83  * (this includes separated but inefficacious cuts) */
84 #define DEFAULT_MAXCUTSROOT 1000 /**< maximal number of {0,1/2}-cuts determined per separation round
85  * in the root node (this includes separated but inefficacious cuts) */
86 #define DEFAULT_SUBSCIPOBJECTIVE 'v' /**< auxiliary IP objective function type */
87 #define DEFAULT_RELAXCONTVARS FALSE /**< should continuous variables be relaxed by adding variable bounds? */
88 #define DEFAULT_SCALEFRACCOEFFS TRUE /**< should rows be scaled to make fractional coefficients integer? */
89 #define DEFAULT_SUBSCIPSETTINGS "-" /**< optional settings file of the auxiliary IP (-: none) */
90 #define DEFAULT_SUBSCIPSOLLIMIT -1 /**< limits/solutions setting of the auxiliary IP */
91 #define DEFAULT_SUBSCIPUSEALLSOLS TRUE /**< should all (proper) solutions of the auxiliary IP be used to generate
92  * cuts instead of using only the best? */
93 #define DEFAULT_PPDELTA 0.500 /**< value of delta parameter used in preprocessing method 'd' */
94 #define DEFAULT_SUBSCIPOBJPEN 0.001 /**< penalty factor used with objective function 'p' of auxiliary IP */
95 
96 #define DEFAULT_PPMETHODS "CXGXIM" /**< preprocessing methods and ordering */
97 #define DEFAULT_SEPAMETHODS "2g" /**< preprocessing methods and ordering */
98 #define DEFAULT_MAXNCALLS -1LL /**< maximal number of calls (-1: unlimited) */
99 #define DEFAULT_IGNOREPREVIOUSZHCUTS FALSE /**< should zerohalf cuts found in previous callbacks be ignored? */
100 #define DEFAULT_ONLYORIGROWS FALSE /**< should only original LP rows be considered (i.e. ignore previously added LP rows)? */
101 #define DEFAULT_USEZHCUTPOOL TRUE /**< should zerohalf cuts be filtered using a cutpool */
102 #define DEFAULT_DELAYEDCUTS TRUE /**< should cuts be added to the delayed cut pool? */
103 #define DEFAULT_MAXTESTDELTA 10 /**< maximal number of different deltas to try for cmir (-1: unlimited, 0: delta=1) */
104 #define DEFAULT_TRYNEGSCALING TRUE /**< should negative values also be tested in scaling for cmir? */
105 
106 /* cut pool management */
107 #define ORTHOFUNC 'e'
108 #define MINORTHO 0.5
109 
110 /* SCIPcalcMIR parameters */
111 #define NNONZOFFSET 500
112 #define BOUNDSWITCH 0.50
113 #define USEVBDS TRUE
114 #define ALLOWLOCAL TRUE
115 #define FIXINTEGRALRHS TRUE
116 #define BOUNDSFORTRANS NULL
117 #define BOUNDTYPESFORTRANS NULL
118 #define MAXWEIGHTRANGE 10000.00
119 #define MINFRAC 0.05
120 #define MAXFRAC 1.00
121 
122 /* SCIPcalcRowIntegralScalar parameters */
123 #define MAXDNOM 1000
124 #define MAXSCALE 1000.0
125 
126 /* should variable bounds be used for substituting continuous variables */
127 #define USEVARBOUNDS TRUE
128 
129 
130 /* --------------------------------------------------------------------------------------------------------------------
131  * definitions of enums and some related strings
132  * -------------------------------------------------------------------------------------------------------------------- */
133 
134 /** preprocessing methods, usable within the ppmethods parameter */
136  {
147  PPCOLUMNS = 'C',
148  PPROWS = 'R'
149  };
150 #if 0 /* currently not used */
151 typedef enum preprocessingmethods PREPROCESSINGMETHODS;
152 #endif
153 
154 /** separation methods, usable within the sepamethods parameter */
156  {
162  GAUSSHEUR = 'g',
164  };
165 #if 0 /* currently not used */
166 typedef enum sepamethods SEPAMETHODS;
167 #endif
168 
169 /** statistics: "origin" of separated cut */
171  {
173  };
175 
176 
177 
178 /* --------------------------------------------------------------------------------------------------------------------
179  * auxiliary (inline) functions
180  * -------------------------------------------------------------------------------------------------------------------- */
181 
182 #define ISEVEN(scip, value) (SCIPisEQ((scip) , SCIPfloor(scip , (value) / 2) , (value) / 2)) /**< is value even? */
183 #define ISODD(scip, value) (!(ISEVEN((scip), (value)))) /**< is value odd? */
184 #define XOR(bool1, bool2) ((bool1) ^ (bool2))
185 #define DIV(value1, powerof2value) (((unsigned int)(value1)) / ((unsigned int)(powerof2value))) /**< integer division using a power of 2 as divisor */
186 #define MOD(value1, powerof2value) (((unsigned int)(value1)) % ((unsigned int)(powerof2value))) /**< remainder of integer division using a power of 2
187  as divisor */
188 #ifndef BMSmoveMemoryArray
189 /** moves array at source with size num to ptr */
190 #define BMSmoveMemoryArray(ptr, source, num) \
191  { \
192  size_t size__ = (num) * sizeof(*(ptr)); \
193  if( size__ > 0 ) \
194  { \
195  assert((void*)(ptr) != NULL); \
196  assert((void*)(source) != NULL); \
197  memmove((void*)(ptr), (void*)(source), size__); \
198  } \
199  }
200 #endif
201 
202 #ifdef ZEROHALF__PRINT_STATISTICS
203 
204 #define ZEROHALFstatistics(x) x /**< execute if ZEROHALF__PRINT_STATISTICS is defined */
205 #define ZEROHALFstatisticsMessage printf("#### ") ; printf /**< print statistics message */
206 #define ZEROHALFcreateNewTimer(timervar) SCIP_CALL(SCIPcreateClock(scip, &timervar)) /**< create new timer */
207 #define ZEROHALFcreateTimer(timervar) SCIP_CALL(SCIPcreateClock(scip, &timervar)) /**< recreate existing timer */
208 #define ZEROHALFfreeTimer(timervar) SCIP_CALL(SCIPfreeClock(scip, &timervar)) /**< free timer */
209 #define ZEROHALFresetTimer(timervar) SCIP_CALL(SCIPresetClock(scip, timervar)) /**< reset timer */
210 #define ZEROHALFstartTimer(timervar) SCIP_CALL(SCIPstartClock(scip, timervar)) /**< start timer */
211 #define ZEROHALFstopTimer(timervar) SCIP_CALL(SCIPstopClock(scip, timervar)) /**< stop timer */
212 #define ZEROHALFevalTimer(timervar) (SCIPgetClockTime(scip, timervar)) /**< evaluate timer (get time) */
213 
214 #else
215 
216 #if 0 /* currently not used */
217 #define ZEROHALFstatistics(x) /**/ /**< nothing */
218 #define ZEROHALFstatisticsMessage while( FALSE ) printf /**< nothing */
219 #define ZEROHALFcreateNewTimer(timervar) /**/ /**< nothing */
220 #define ZEROHALFcreateTimer(timervar) /**/ /**< nothing */
221 #define ZEROHALFfreeTimer(timervar) /**/ /**< nothing */
222 #define ZEROHALFresetTimer(timervar) /**/ /**< nothing */
223 #define ZEROHALFstartTimer(timervar) /**/ /**< nothing */
224 #define ZEROHALFstopTimer(timervar) /**/ /**< nothing */
225 #define ZEROHALFevalTimer(timervar) (0.0) /**< nothing */
226 #endif
227 
228 #endif
229 
230 
231 /* --------------------------------------------------------------------------------------------------------------------
232  * symbolic constants for statistical analysis
233  * -------------------------------------------------------------------------------------------------------------------- */
234 
235 /* row / columns */
236 #define IRRELEVANT -1 /**< row or column is irrelevant */
237 
238 /* row */
239 #define ZERO_ROW -100 /**< row has no nonzero entries */
240 #define IDENT_TO_ROW_WITH_SMALLER_SLACK -101 /**< row is identical to another row but has a larger slack value */
241 #define SLACK_GREATER_THAN_MAXSLACK -102 /**< row has a slack value > maxslack */
242 #define DEFINES_VIOLATED_ZEROHALF_CUT -103 /**< row defines a violated zerohalf cut */
243 #ifdef WITHDECOMPOSE
244 #define ROW_IN_SUBPROB_WITHOUT_ODD_RHS -104 /**< row is part of a subproblem without rows with odd rhs */
245 #endif
246 #define NONEXISTENT_ROW -105 /**< row does not exist (lhs is -infinity or rhs is infinity) */
247 #define NO_RELEVANT_COLUMNS -106 /**< row does not contain relevant columns */
248 #define SLACK_GREATER_THAN_MSL_MINUS_SODD -107 /**< row has even rhs and the sum of its slack value and the minimum
249  slack value of a odd-rhs-row exceeds maxslack */
250 #define LARGE_COL_EXISTS -108 /**< row contains a column which rounding penalty exceeds maxslack
251  and the sum of this row's slack and the minimum slack of another
252  row with the proper columns exceeds maxslack as well */
253 
254 /* column */
255 #define ZERO_COLUMN -200 /**< column has no nonzero entries */
256 #define IDENT_TO_ANOTHER_COLUMN -201 /**< column is identical to another column */
257 #define ZERO_LP_SOL -202 /**< column corresponds to a variable whose LP solution is zero */
258 #define LP_SOL_EQUALS_EVEN_LB -203 /**< column corresponds to a variable whose LP solution equals its even lb */
259 #define LP_SOL_EQUALS_ODD_LB -204 /**< column corresponds to a variable whose LP solution equals its odd lb */
260 #define LP_SOL_EQUALS_EVEN_UB -205 /**< column corresponds to a variable whose LP solution equals its even ub */
261 #define LP_SOL_EQUALS_ODD_UB -206 /**< column corresponds to a variable whose LP solution equals its odd ub */
262 #define SINGLETON_COLUMN -207 /**< column has only one nonzero entry */
263 #define CONTINUOUS_VARIABLE -208 /**< column corresponds to a non-integer variable */
264 #define SMALL_FRACSOL_HEUR -209 /**< column has been omitted (see preprocessColumnsWithSmallFracsol) */
265 #define ALL_MATRIX_ROWS_DELETED -210 /**< all rows (of the current subproblem) have been deleted */
266 #ifdef WITHDECOMPOSE
267 #define COLUMN_IN_SUBPROB_WITHOUT_ODD_RHS -211 /**< column is part of a subproblem without a row with odd rhs value */
268 #endif
269 
270 
271 /* --------------------------------------------------------------------------------------------------------------------
272  * bit array data structures and functions
273  * -------------------------------------------------------------------------------------------------------------------- */
274 
275 
276 #define BITARRAYBASETYPE unsigned int /**< base type used for the bitarray data structures */
277 #define BITARRAYBITMASKTYPE BITARRAYBASETYPE
278 
279 /** size of BITARRAYBASETYPE */
280 static const unsigned int Zerohalf_bitarraybasetypesize = sizeof(BITARRAYBASETYPE);
281 
282 /** number of bits per BITARRAYBASETYPE */
283 static const unsigned int Zerohalf_bitarraybasetypesize_nbits = sizeof(BITARRAYBASETYPE) << 3;
284 
285 
286 #define BITARRAY BITARRAYBASETYPE*
287 
288 /** get the bit mask where the pos-th bit is set */
289 #define BITMASK(pos) ((unsigned int)(1 << (pos)))
290 
291 /** set the pos-th bit of var */
292 #define BITSET(var, pos) (var) |= BITMASK(pos)
293 
294 /** is the pos-th bit of var set? */
295 #define BITISSET(var, pos) (var & BITMASK(pos))
296 
297 /** set the pos-th bit of bitarray barray */
298 #define BITARRAYBITSET(barray, pos) BITSET(barray[DIV((pos),Zerohalf_bitarraybasetypesize_nbits)], \
299  MOD(pos,Zerohalf_bitarraybasetypesize_nbits))
300 
301 /** is the pos-th bit of bitarray barray set? */
302 #define BITARRAYBITISSET(barray, pos) BITISSET(barray[DIV(pos,Zerohalf_bitarraybasetypesize_nbits)], \
303  MOD(pos,Zerohalf_bitarraybasetypesize_nbits))
304 
305 /** clear bitarray */
306 #define BITARRAYCLEAR(barray, barraysize) BMSclearMemoryArray(barray,barraysize)
307 
308 /** calculates the number of array elements (w.r.t. the bitarray base type) required to create the bitarray */
309 #define GETREQUIREDBITARRAYSIZE(nvalstostore) \
310  ((((unsigned int)(nvalstostore)) % (Zerohalf_bitarraybasetypesize_nbits) == 0) \
311  ? (((unsigned int)(nvalstostore)) / (Zerohalf_bitarraybasetypesize_nbits)) \
312  : ((((unsigned int)(nvalstostore)) / (Zerohalf_bitarraybasetypesize_nbits)) + 1))
313 
314 /** get the corresponding array element of a bitarray position */
315 #define GETBITARRAYINDEX(pos) DIV((pos),Zerohalf_bitarraybasetypesize_nbits)
316 
317 /** get the bitmask to mask all bits except the pos-th bit of an array element */
318 #define GETBITARRAYMASK(pos) BITMASK(MOD((pos),Zerohalf_bitarraybasetypesize_nbits))
319 
320 /** apply operation op for all array elements of bitarray barray1 and barray2 */
321 #define BITARRAYSFOREACH(barray1, barray2, size, op) \
322  { \
323  int idx__; \
324  for( idx__ = 0 ; idx__ < (size) ; ++idx__) \
325  { \
326  barray2[idx__] op barray1[idx__]; \
327  } \
328  }
329 
330 /** barray2 = barray1 XOR barray2 */
331 #define BITARRAYSXOR(barray1, barray2, size) BITARRAYSFOREACH(barray1,barray2,size,^=)
332 
333 /** are barray1 and barray2 equal? */
334 #define BITARRAYSAREEQUAL(barray1, barray2, size) \
335  (memcmp((void*)(barray1), (void*)(barray2), (size_t)((size) * (Zerohalf_bitarraybasetypesize))) == 0)
336 
337 #if 0 /* currently not used */
338 /** clear the pos-th bit of var */
339 #define BITCLEAR(var, pos) (var) &= ~BITMASK(pos)
340 
341 /** flip the pos-th bit of var */
342 #define BITFLIP(var, pos) (var) ^= BITMASK(pos)
343 
344 /** clear the pos-th bit of bitarray barray */
345 #define BITARRAYBITCLEAR(barray, pos) BITCLEAR(barray[DIV((pos),Zerohalf_bitarraybasetypesize_nbits)], \
346  MOD(pos,Zerohalf_bitarraybasetypesize_nbits))
347 
348 /** flip the pos-th bit of bitarray barray */
349 #define BITARRAYBITFLIP(barray, pos) BITFLIP(barray[DIV((pos),Zerohalf_bitarraybasetypesize_nbits)], \
350  MOD(pos,Zerohalf_bitarraybasetypesize_nbits))
351 
352 /** barray2 = barray1 AND barray2 */
353 #define BITARRAYSAND(barray1, barray2, size) BITARRAYSFOREACH(barray1,barray2,size,&=)
354 
355 /** barray2 = barray1 OR barray2 */
356 #define BITARRAYSOR(barray1, barray2, size) BITARRAYSFOREACH(barray1,barray2,size,|=)
357 
358 /** barray2 = NOT barray1 */
359 #define BITARRAYSNOT(barray1, barray2, size) BITARRAYSFOREACH(barray1,barray2,size,= ~)
360 #endif
361 
362 
363 /* --------------------------------------------------------------------------------------------------------------------
364  * data structures
365  * -------------------------------------------------------------------------------------------------------------------- */
366 
367 
368 /** parameters */
369 struct SCIP_SepaData
370 {
371 
372  int maxrounds; /**< maximal number of {0,1/2} separation rounds per node (-1: unlimited) */
373  int maxroundsroot; /**< maximal number of {0,1/2} separation rounds in the root node (-1: unlimited) */
374  int maxsepacuts; /**< maximal number of {0,1/2} cuts separated per separation round */
375  int maxsepacutsroot; /**< maximal number of {0,1/2} cuts separated per separation round in root node */
376  int maxdepth; /**< separating cuts only if depth <= maxdepth (-1: unlimited) */
377  SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
378  SCIP_Bool decomposeproblem; /**< should problem be decomposed into subproblems (if possible)? */
379 
380  SCIP_Real minviolation; /**< minimal violation of a {0,1/2}-cut to be separated */
381  SCIP_Bool forcecutstolp; /**< should the cuts be forced to enter the LP? */
382  SCIP_Bool forcecutstosepastore; /**< should the cuts be forced to enter SCIP's sepastore? */
383  int maxcuts; /**< maximal number of {0,1/2}-cuts determined per separation round
384  (this includes separated but inefficacious cuts) */
385  int maxcutsroot; /**< maximal number of {0,1/2}-cuts determined per separation round
386  in the root node (this includes separated but inefficacious cuts) */
387 
388  char* ppmethods; /**< preprocessing methods */
389  char* sepamethods; /**< separation methods */
390  int nppmethods; /**< length of ppmethods string */
391  int nsepamethods; /**< length of sepamethods string */
392 
393  int subscipsollimit; /**< value of auxiliary IP / subscip "limits/sol" */
394  SCIP_Bool subscipuseallsols; /**< should all known feasible solution of the auxiliary IP be considered? */
395  SCIP_Bool relaxcontvars; /**< should continuous vars be relaxed by adding varbounds? */
396  SCIP_Bool scalefraccoeffs; /**< should fractional coeffs be scaled to become integer? */
397  char* subscipsettings; /**< optional settings file for the auxiliary IP / subscip */
398  char subscipobjective; /**< type of objective function of the auxiliary IP / subscip */
399  SCIP_Real ppdelta; /**< value of delta parameter used in preprocessing method 'd' */
400  SCIP_Real subscipobjpen; /**< penalty factor used with objective function 'p' of auxiliary IP */
401  SCIP_Longint maxncalls; /**< maximal number of callbacks */
402  SCIP_Bool ignoreprevzhcuts; /**< should zerohalf cuts found within previous callbacks considered as well? */
403  SCIP_Bool onlyorigrows; /**< should only original LP rows be considered (i.e. ignore previously added LP rows)? */
404  SCIP_Bool usezhcutpool; /**< should zerohalf cuts be filtered using a cutpool? */
405  SCIP_Bool delayedcuts; /**< should cuts be added to the delayed cut pool? */
406 
407  SCIP_Real maxslack; /**< initial: 1.0 - 2.0 * minviolation */
408  int norigrows; /**< number of original LP rows */
409  int* origrows; /**< set of SCIP_ROW->index of all original LP rows */
410 
411  int maxnnonz; /**< maximal number of nonzeros allowed in a zerohalf cut */
412  int maxtestdelta; /**< maximal number of different deltas to try for cmir (-1: unlimited, 0: delta=1) */
413  SCIP_Bool trynegscaling; /**< should negative values also be tested in scaling for cmir? */
414 
415  /* statistics */
416  int totalncutsfound; /**< total number of separated zerohalf cuts, including inefficious ones */
417  int totalnsepacuts; /**< total number of separated zerohalf cuts */
418  SCIP_CLOCK** pptimers; /**< timers of preprocessing methods */
419  SCIP_CLOCK** sepatimers; /**< timers of separation algorithms */
420  SCIP_CLOCK* dtimer; /**< timer of decomposition method */
421  int* nsepacutsalgo; /**< number zerohalf cuts separated by a specific separation algorithm,
422  * including inefficious cuts */
423  int* nzerohalfcutsalgo; /**< number zerohalf cuts separated by a specific separation algorithm */
424 };
425 
426 
427 /** sub data of the LP or a sub-LP obtained by problem decomposition */
428 struct Zerohalf_SubLPData
429 {
430  int* rrows; /**< relevant rows (indices of elements in rows array of ZEROHALF_LPDATA) */
431  int nrrows; /**< number of relevant rows */
432  SCIP_Real* rrowsrhs; /**< rhs value of relevant rows; could also be lhs value of the orig row */
433  SCIP_Real* rrowsslack; /**< slack value of relevant rows */
434  int* rcols; /**< relevant columns (indices of elements in cols array of ZEROHALF_LPDATA) */
435  int nrcols; /**< number of relevant columns */
436  SCIP_Real* rcolslbslack; /**< slack value of lower bound constraint: x*_j - lb_j */
437  SCIP_Real* rcolsubslack; /**< slack value of upper bound constraint: ub_j - x*_j */
438 };
439 typedef struct Zerohalf_SubLPData ZEROHALF_SUBLPDATA;
440 
441 
442 /** LP data */
443 struct Zerohalf_LPData
444 {
445  SCIP_VAR** vars; /**< LP variables */
446  SCIP_ROW** rows; /**< LP rows */
447  SCIP_COL** cols; /**< LP columns */
448  int nvars; /**< number of LP variables */
449  int nrows; /**< number of LP rows */
450  int ncols; /**< number of LP columns */
451  int nvarbounds; /**< number of variable bounds (-x_j <= -lb_j, x_j <= ub_j) */
452 
453  ZEROHALF_SUBLPDATA** subproblems; /**< decomposed subproblems (subset of the variables, rows and columns above) */
454  int nsubproblems; /**< number of subproblems */
455 
456  SCIP_Real* intscalarsleftrow; /**< array of scalars that would make left half-rows (-a^Tx <= -lhs) rows integral (0.0 if scalar has not been calculated) */
457  SCIP_Real* intscalarsrightrow; /**< array of scalars that would make right half-rows (a^Tx <= rhs) rows integral (0.0 if scalar has not been calculated) */
458 
459  /* row related index sets */
460  int* subproblemsindexofrow; /**< is rows index relevant? value <0: not relevant,
461  value >=0: index of subproblem containing the row */
462  int* rrowsindexofleftrow; /**< maps rows index of lhs <= a^Tx <= rhs to rrows index of -a^Tx <= -lhs */
463  int* rrowsindexofrightrow; /**< maps rows index of lhs <= a^Tx <= rhs to rrows index of a^Tx <= rhs */
464 
465  /* col related index sets */
466  int* subproblemsindexofcol; /**< is cols index relevant? value <0: not relevant
467  * value >=0: index of subproblem containing the column */
468  int* rcolsindexofcol; /**< maps cols index to rcols index */
469 
470  int* bestlbidxofcol; /**< maps cols index of a continuous variable to the index of its
471  * best lower bound (-2: undetermined, -1: lb, >=0: index of vlb)*/
472  int* bestubidxofcol; /**< maps cols index of a continuous variable to the index of its
473  * best upper bound (-2: undetermined, -1: ub, >=0: index of vub)*/
474 
475  /* statistics */
476  int ndelvarbounds; /**< number of deleted variable bounds by basic preprocessing */
477 
478 };
479 typedef struct Zerohalf_LPData ZEROHALF_LPDATA;
480 
481 
482 /** data structure to store data of the auxiliary IP:
483  * (1) minimize violation:
484  * min z := s^T v + x^T y
485  * s.t. (b (mod 2))^T v - 2q = 1 "odd rhs"
486  * (A (mod 2))^T v - y - -2r = 0 "column sum"
487  *
488  * v \\in {0,1}^m
489  * y \\in {0,1}^n
490  * r \\in Z^n_+
491  * q \\in Z_+
492  * (2) minimize (weighted) number of aggregated rows
493  * min z := w^T v
494  * s.t. s^T v + x^T y < 1 "feasibility"
495  * (b (mod 2))^T v - 2q = 1 "odd rhs"
496  * (A (mod 2))^T v - y - -2r = 0 "column sum"
497  *
498  * v \\in {0,1}^m
499  * y \\in {0,1}^n
500  * r \\in Z^n_+
501  * q \\in Z_+
502  *
503  * with w \\in \\Rset^m
504  */
505 struct Zerohalf_AuxIPData
506 {
507  SCIP* subscip; /**< pointer to (sub)SCIP data structure containing the auxiliary IP */
508  int m; /**< number of rows */
509  int n; /**< number of cols */
510 
511  SCIP_VAR** v; /**< decision variable: 1 iff row is selected for generating a violated zerohalf cut */
512  SCIP_VAR** y; /**< auxiliary variable used for calculating the rounding down penalties in the objective */
513  SCIP_VAR** r; /**< auxiliary variable used for modelling mod 2 calculus */
514  SCIP_VAR* q; /**< auxiliary variable used for modelling mod 2 calculus */
515 
516  SCIP_CONS* feasipcons; /**< feasibility constraint */
517  SCIP_CONS* oddrhscons; /**< odd rhs constraint */
518  SCIP_CONS** columnsumcons; /**< column sum constraints */
519 
520  SCIP_Real timelimit; /**< value of "limits/time" of subscip */
521  SCIP_Real memorylimit; /**< value of "limits/memory" of subscip */
522  SCIP_Real objectivelimit; /**< value of objective limit of subscip */
523  int nodelimit; /**< value of "limits/nodes" of subscip */
524 };
525 typedef struct Zerohalf_AuxIPData ZEROHALF_AUXIPDATA;
526 
527 
528 /** data structure to store data (mod 2) densely*/
529 struct Zerohalf_Mod2Data
530 {
531  ZEROHALF_SUBLPDATA* relatedsubproblem; /**< pointer to corresponding subproblem data structure */
532 
533  BITARRAY* rows; /**< dense mod 2 rows */
534  BITARRAY* rowaggregations; /**< Zerohalf_Mod2Data->rows index set, storing the actual row aggregations */
535  SCIP_Bool* rhs; /**< TRUE iff corresponding relatedsubproblem->rrowsrhs is odd */
536 
537  SCIP_Real* slacks; /**< slack value (equal to corresponding relatedsubproblem->rrowsslack value) */
538  SCIP_Real* fracsol; /**< LP solution value of variable of SCIP_COL* */
539 
540  int nrows; /**< number of Zerohalf_Mod2Data->rows */
541  int rowsbitarraysize; /**< size (w.r.t. bitarray base type) of Zerohalf_Mod2Data->rows array */
542  int rowaggregationsbitarraysize; /** size (w.r.t. bitarray base type) of Zerohalf_Mod2Data->rowaggregations array */
543  int nvarbounds; /**< number of variable bounds that are part of Zerohalf_Mod2Data->rows */
544 
545  int* rowsind; /**< index set of subset of Zerohalf_Mod2Data->rows */
546  int* colsind; /**< index set of subset of relatedsubproblem->rcols */
547 
548  int nrowsind; /**< number of rowsind elements */
549  int ncolsind; /**< number of colsind elements */
550 
551  /* statistics */
552  int* rowstatistics; /**< stores if and why a row was removed in preprocessing */
553  int* colstatistics; /**< stores if and why a column was removed in preprocessing */
554 };
555 typedef struct Zerohalf_Mod2Data ZEROHALF_MOD2DATA;
556 
557 
558 /** data structure to store a violated zerohalf cut and related data */
559 struct Zerohalf_CutData
560 {
561  ZEROHALF_SUBLPDATA* relatedsubproblem; /**< pointer to corresponding subproblem data structure */
562  ZEROHALF_MOD2DATA* relatedmod2data; /**< pointer to corresponding mod 2 data structure */
563 
564  SCIP_ROW* cut; /**< pointer to SCIP_ROW storing the cut */
565 
566  SCIP_Bool success; /**< was SCIPcalcMIR successful? */
567  SCIP_Bool isfeasviolated; /**< is zerohalf cut violated w.r.t. the feasibility tolerance? */
568  SCIP_Bool islocal; /**< is zerohalf cut only locally valid? */
569 
570  SCIP_Real activity; /**< activity of the zerohalf cut */
571  SCIP_Real rhs; /**< rhs of the zerohalf cut */
572  SCIP_Real norm; /**< norm of the nonzero elements of the zerohalf cut */
573  SCIP_Real efficacy; /**< efficacy of the zerohalf cut */
574  SCIP_Real violation; /**< violation of the zerohalf cut */
575  int cutrank; /**< rank of cut */
576  int nnonz; /**< number of nonzero coefficients of the zerohalf cut */
577 
578  /* statistics */
579  int nrowsincut; /**< number of LP rows combined into the zerohalf cut */
580  int nrrowsincut; /**< number of preprocessed/aggregated LP rows combined into the zerohalf cut */
581  CUTSEPARATEDBY separatedby; /**< flag to store the method that has separated the zerohalf cut */
582  int addedtolp; /**< was the cut added to SCIP? */
583 
584 };
585 typedef struct Zerohalf_CutData ZEROHALF_CUTDATA;
586 
587 
588 
589 /** auxiliary graph node data structure */
590 struct Zerohalf_AuxGraph_Node;
591 typedef struct Zerohalf_AuxGraph_Node ZEROHALF_AUXGRAPH_NODE;
592 
593 struct Zerohalf_AuxGraph_Node
594 {
595  ZEROHALF_AUXGRAPH_NODE** neighbors; /**< node adjacency list */
596  SCIP_Real* edgeweights; /**< weights of outgoing edges */
597  int* relatedrows; /**< label mapping outgoing edges to mod 2 rows */
598  int nneighbors; /**< number of adjacent nodes */
599  SCIP_Real distance; /**< actual distant from start node (used by Dijkstra)*/
600  ZEROHALF_AUXGRAPH_NODE* previous; /**< previous node in shortest-path-tree (used by Dijkstra) */
601 };
602 
603 
604 /** auxiliary graph data structure */
605 struct Zerohalf_AuxGraph
606 {
607  ZEROHALF_AUXGRAPH_NODE** nodes; /**< list of all original nodes */
608  ZEROHALF_AUXGRAPH_NODE** nodecopies; /**< list of all copies of original nodes */
609  int nnodes; /**< number of original nodes (equals number of copies) */
610 };
611 typedef struct Zerohalf_AuxGraph ZEROHALF_AUXGRAPH;
612 
613 
614 /* --------------------------------------------------------------------------------------------------------------------
615  * local methods: create / free data structure
616  * -------------------------------------------------------------------------------------------------------------------- */
617 
618 
619 /** creates and initializes sub LP data structures */
620 static
622  SCIP* scip, /**< SCIP data structure */
623  ZEROHALF_SUBLPDATA** subproblem /**< pointer to store pointer to created data structure */
624  )
625 {
626  assert(scip != NULL);
627  assert(subproblem != NULL);
628 
629  SCIP_CALL(SCIPallocMemory(scip, subproblem));
630  (*subproblem)->rrows = NULL;
631  (*subproblem)->rrowsrhs = NULL;
632  (*subproblem)->rrowsslack = NULL;
633  (*subproblem)->nrrows = 0;
634 
635  (*subproblem)->rcols = NULL;
636  (*subproblem)->rcolslbslack = NULL;
637  (*subproblem)->rcolsubslack = NULL;
638  (*subproblem)->nrcols = 0;
639 
640  return SCIP_OKAY;
641 }
642 
643 
644 /** frees sub LP data structures */
645 static
647  SCIP* scip, /**< SCIP data structure */
648  ZEROHALF_SUBLPDATA** subproblem /**< pointer to pointer of data structure */
649  )
650 {
651  assert(scip != NULL);
652  assert(subproblem != NULL);
653  assert(*subproblem != NULL);
654 
655  if( (*subproblem)->rrows != NULL )
656  {
657  SCIPfreeMemoryArray(scip, &((*subproblem)->rrows));
658  }
659  if( (*subproblem)->rrowsrhs != NULL )
660  {
661  SCIPfreeMemoryArray(scip, &((*subproblem)->rrowsrhs));
662  }
663  if( (*subproblem)->rrowsslack != NULL )
664  {
665  SCIPfreeMemoryArray(scip, &((*subproblem)->rrowsslack));
666  }
667  if( (*subproblem)->rcols != NULL )
668  {
669  SCIPfreeMemoryArray(scip, &((*subproblem)->rcols));
670  }
671  if( (*subproblem)->rcolslbslack != NULL )
672  {
673  SCIPfreeMemoryArray(scip, &((*subproblem)->rcolslbslack));
674  }
675  if( (*subproblem)->rcolsubslack != NULL )
676  {
677  SCIPfreeMemoryArray(scip, &((*subproblem)->rcolsubslack));
678  }
679  SCIPfreeMemory(scip, subproblem);
680  (*subproblem) = NULL;
681 }
682 
683 
684 /** creates and initializes LP data structures */
685 static
687  SCIP* scip, /**< SCIP data structure */
688  ZEROHALF_LPDATA** lpdata /**< pointer to store pointer to created data structure */
689  )
690 {
691  assert(scip != NULL);
692  assert(lpdata != NULL);
693 
694  SCIP_CALL(SCIPallocMemory(scip, lpdata));
695  (*lpdata)->vars = NULL;
696  (*lpdata)->rows = NULL;
697  (*lpdata)->cols = NULL;
698 
699  (*lpdata)->subproblems = NULL;
700  (*lpdata)->nsubproblems = 0;
701 
702  (*lpdata)->intscalarsleftrow = NULL;
703  (*lpdata)->intscalarsrightrow = NULL;
704 
705  (*lpdata)->subproblemsindexofrow = NULL;
706  (*lpdata)->rrowsindexofleftrow = NULL;
707  (*lpdata)->rrowsindexofrightrow = NULL;
708 
709  (*lpdata)->subproblemsindexofcol = NULL;
710  (*lpdata)->rcolsindexofcol = NULL;
711 
712  (*lpdata)->bestlbidxofcol = NULL;
713  (*lpdata)->bestubidxofcol = NULL;
714 
715  return SCIP_OKAY;
716 }
717 
718 
719 /** frees LP data structures */
720 static
722  SCIP* scip, /**< SCIP data structure */
723  ZEROHALF_LPDATA** lpdata /**< pointer to pointer of data structure */
724  )
725 {
726  int sp;
727 
728  assert(scip != NULL);
729  assert(lpdata != NULL);
730  assert(*lpdata != NULL);
731 
732  /* ! Do not free (*lpdata)->vars, (*lpdata)->rows and (*lpdata)->cols ! */
733  assert(((*lpdata)->nsubproblems == 0 && (*lpdata)->subproblems == NULL)
734  || ((*lpdata)->nsubproblems > 0 && (*lpdata)->subproblems != NULL));
735 
736  if( (*lpdata)->subproblems != NULL )
737  {
738  for( sp = 0 ; sp < (*lpdata)->nsubproblems ; ++sp )
739  if( (*lpdata)->subproblems[sp] != NULL )
740  ZerohalfSubLPDataFree(scip, &((*lpdata)->subproblems[sp]));
741  SCIPfreeMemoryArray(scip, &((*lpdata)->subproblems));
742  }
743 
744  if( (*lpdata)->intscalarsleftrow != NULL )
745  {
746  SCIPfreeMemoryArray(scip, &((*lpdata)->intscalarsleftrow));
747  }
748  if( (*lpdata)->intscalarsrightrow != NULL )
749  {
750  SCIPfreeMemoryArray(scip, &((*lpdata)->intscalarsrightrow));
751  }
752  if( (*lpdata)->subproblemsindexofrow != NULL )
753  {
754  SCIPfreeMemoryArray(scip, &((*lpdata)->subproblemsindexofrow));
755  }
756  if( (*lpdata)->rrowsindexofleftrow != NULL )
757  {
758  SCIPfreeMemoryArray(scip, &((*lpdata)->rrowsindexofleftrow));
759  }
760  if( (*lpdata)->rrowsindexofrightrow != NULL )
761  {
762  SCIPfreeMemoryArray(scip, &((*lpdata)->rrowsindexofrightrow));
763  }
764  if( (*lpdata)->subproblemsindexofcol != NULL )
765  {
766  SCIPfreeMemoryArray(scip, &((*lpdata)->subproblemsindexofcol));
767  }
768  if( (*lpdata)->rcolsindexofcol != NULL )
769  {
770  SCIPfreeMemoryArray(scip, &((*lpdata)->rcolsindexofcol));
771  }
772  if( (*lpdata)->bestlbidxofcol != NULL )
773  {
774  SCIPfreeMemoryArray(scip, &((*lpdata)->bestlbidxofcol));
775  }
776  if( (*lpdata)->bestubidxofcol != NULL )
777  {
778  SCIPfreeMemoryArray(scip, &((*lpdata)->bestubidxofcol));
779  }
780  SCIPfreeMemory(scip, lpdata);
781  (*lpdata) = NULL;
782 
783  return SCIP_OKAY;
784 }
785 
786 
787 /** creates and initializes mod 2 data structures */
788 static
790  SCIP* scip, /**< SCIP data structure */
791  ZEROHALF_MOD2DATA** mod2data /**< pointer to store pointer to created data structure */
792  )
793 {
794  assert(scip != NULL);
795  assert(mod2data != NULL);
796 
797  SCIP_CALL(SCIPallocMemory(scip, mod2data));
798 
799  (*mod2data)->relatedsubproblem = NULL;
800 
801  (*mod2data)->rows = NULL;
802  (*mod2data)->rowaggregations = NULL;
803  (*mod2data)->rhs = NULL;
804 
805  (*mod2data)->slacks = NULL;
806  (*mod2data)->fracsol = NULL;
807 
808  (*mod2data)->rowstatistics = NULL;
809  (*mod2data)->colstatistics = NULL;
810 
811  (*mod2data)->rowsind = NULL;
812  (*mod2data)->colsind = NULL;
813 
814  return SCIP_OKAY;
815 }
816 
817 
818 /** frees data structures */
819 static
821  SCIP* scip, /**< SCIP data structure */
822  ZEROHALF_MOD2DATA** mod2data /**< pointer to pointer of data structure */
823  )
824 {
825  int i;
826 
827  assert(scip != NULL);
828  assert(mod2data != NULL);
829  assert(*mod2data != NULL);
830 
831  if( (*mod2data)->rows != NULL )
832  {
833  for( i = 0 ; i < (*mod2data)->nrows ; ++i)
834  if( (*mod2data)->rows[i] != NULL )
835  {
836  SCIPfreeMemoryArray(scip, &((*mod2data)->rows[i]));
837  }
838  SCIPfreeMemoryArray(scip, &((*mod2data)->rows));
839  }
840 
841  if( (*mod2data)->rowaggregations != NULL )
842  {
843  for( i = 0 ; i < (*mod2data)->nrows ; ++i)
844  if( (*mod2data)->rowaggregations[i] != NULL )
845  {
846  SCIPfreeMemoryArray(scip, &((*mod2data)->rowaggregations[i]));
847  }
848  SCIPfreeMemoryArray(scip, &((*mod2data)->rowaggregations));
849  }
850 
851  if( (*mod2data)->rhs != NULL )
852  {
853  SCIPfreeMemoryArray(scip, &((*mod2data)->rhs));
854  }
855  if( (*mod2data)->slacks != NULL )
856  {
857  SCIPfreeMemoryArray(scip, &((*mod2data)->slacks));
858  }
859  if( (*mod2data)->fracsol != NULL )
860  {
861  SCIPfreeMemoryArray(scip, &((*mod2data)->fracsol));
862  }
863  if( (*mod2data)->rowstatistics != NULL )
864  {
865  SCIPfreeMemoryArray(scip, &((*mod2data)->rowstatistics));
866  }
867  if( (*mod2data)->colstatistics != NULL )
868  {
869  SCIPfreeMemoryArray(scip, &((*mod2data)->colstatistics));
870  }
871  if( (*mod2data)->rowsind != NULL )
872  {
873  SCIPfreeMemoryArray(scip, &((*mod2data)->rowsind));
874  }
875  if( (*mod2data)->colsind != NULL )
876  {
877  SCIPfreeMemoryArray(scip, &((*mod2data)->colsind));
878  }
879  SCIPfreeMemory(scip, mod2data);
880  (*mod2data) = NULL;
881 
882  return SCIP_OKAY;
883 }
884 
885 
886 /** creates and initializes auxiliary IP data structures */
887 static
889  SCIP* scip, /**< SCIP data structure */
890  ZEROHALF_AUXIPDATA** auxipdata /**< pointer to store pointer to created data structure */
891  )
892 {
893  assert(scip != NULL);
894  assert(auxipdata != NULL);
895 
896  SCIP_CALL(SCIPallocMemory(scip, auxipdata));
897 
898  (*auxipdata)->subscip = NULL;
899 
900  (*auxipdata)->v = NULL;
901  (*auxipdata)->y = NULL;
902  (*auxipdata)->r = NULL;
903  (*auxipdata)->q = NULL;
904 
905  (*auxipdata)->feasipcons = NULL;
906  (*auxipdata)->oddrhscons = NULL;
907  (*auxipdata)->columnsumcons = NULL;
908 
909  return SCIP_OKAY;
910 }
911 
912 
913 /** frees auxiliary IP data structures */
914 static
916  SCIP* scip, /**< SCIP data structure */
917  ZEROHALF_AUXIPDATA** auxipdata /**< pointer to pointer of data structure */
918  )
919 {
920  assert(scip != NULL);
921  assert(auxipdata != NULL);
922  assert(*auxipdata != NULL);
923 
924  if( (*auxipdata)->subscip != NULL )
925  {
926  SCIP_CALL( SCIPfree(&((*auxipdata)->subscip)) );
927  }
928 
929  if( (*auxipdata)->v != NULL )
930  {
931  SCIPfreeMemoryArray(scip, &((*auxipdata)->v));
932  }
933  if( (*auxipdata)->y != NULL )
934  {
935  SCIPfreeMemoryArray(scip, &((*auxipdata)->y));
936  }
937  if( (*auxipdata)->r != NULL )
938  {
939  SCIPfreeMemoryArray(scip, &((*auxipdata)->r));
940  }
941  if( (*auxipdata)->columnsumcons != NULL )
942  {
943  SCIPfreeMemoryArray(scip, &((*auxipdata)->columnsumcons));
944  }
945  SCIPfreeMemory(scip, auxipdata);
946  (*auxipdata) = NULL;
947 
948  return SCIP_OKAY;
949 }
950 
951 
952 /** creates and initializes cut data structures */
953 static
955  SCIP* scip, /**< SCIP data structure */
956  ZEROHALF_CUTDATA** cutdata, /**< pointer to pointer of data structure */
957  ZEROHALF_SUBLPDATA* relatedsubproblem, /**< pointer to corresponding subproblem */
958  ZEROHALF_MOD2DATA* relatedmod2data, /**< pointer to corresponding mod 2 data */
959  int nrrowsincut, /**< number of preprocessed / mod 2 rows in cut */
960  int nrowsincut, /**< number of original / LP rows in cut */
961  CUTSEPARATEDBY separatedby /**< flag storing the method that separated this cut */
962  )
963 {
964  assert(scip != NULL);
965  assert(cutdata != NULL);
966  assert(nrrowsincut >= 0);
967  assert(nrowsincut >= 0);
968 
969  SCIP_CALL(SCIPallocMemory(scip, cutdata));
970 
971  (*cutdata)->relatedsubproblem = relatedsubproblem;
972  (*cutdata)->relatedmod2data = relatedmod2data;
973 
974  (*cutdata)->cut = NULL;
975 
976  (*cutdata)->success = FALSE;
977  (*cutdata)->isfeasviolated = FALSE;
978  (*cutdata)->islocal = TRUE;
979 
980  (*cutdata)->activity = 0.0;
981  (*cutdata)->rhs = 0.0;
982  (*cutdata)->norm = 0.0;
983  (*cutdata)->efficacy = 0.0;
984  (*cutdata)->violation = 0.0;
985  (*cutdata)->cutrank = 0;
986  (*cutdata)->nnonz = 0;
987 
988  (*cutdata)->nrrowsincut = nrrowsincut;
989  (*cutdata)->nrowsincut = nrowsincut;
990  (*cutdata)->separatedby = separatedby;
991  (*cutdata)->addedtolp = FALSE;
992 
993  return SCIP_OKAY;
994 }
995 
996 
997 /** frees cut data structures */
998 static
1000  SCIP* scip, /**< SCIP data structure */
1001  ZEROHALF_CUTDATA** cutdata /**< pointer to pointer of data structure */
1002  )
1003 {
1004  assert(scip != NULL);
1005  assert(cutdata != NULL);
1006  assert(*cutdata != NULL);
1007 
1008  if( (*cutdata)->cut != NULL )
1009  {
1010  SCIP_CALL(SCIPreleaseRow(scip, &((*cutdata)->cut)));
1011  }
1012  SCIPfreeMemory(scip, cutdata);
1013  (*cutdata) = NULL;
1014 
1015  return SCIP_OKAY;
1016 }
1017 
1018 
1019 /** creates and initializes auxiliary graph node data structures */
1020 static
1022  SCIP* scip, /**< SCIP data structure */
1023  ZEROHALF_AUXGRAPH_NODE** node /**< pointer to store pointer to created data structure */
1024  )
1025 {
1026  assert(scip != NULL);
1027  assert(node != NULL);
1028 
1029  SCIP_CALL(SCIPallocMemory(scip, node));
1030 
1031  (*node)->neighbors = NULL;
1032  (*node)->edgeweights = NULL;
1033  (*node)->relatedrows = NULL;
1034  (*node)->nneighbors = 0;
1035 
1036  (*node)->distance = -1.0;
1037  (*node)->previous = NULL;
1038 
1039  return SCIP_OKAY;
1040 }
1041 
1042 
1043 /** frees auxiliary graph node data structures */
1044 static
1046  SCIP* scip, /**< SCIP data structure */
1047  ZEROHALF_AUXGRAPH_NODE** node /**< pointer to pointer of data structure */
1048  )
1049 {
1050  assert(scip != NULL);
1051  assert(node != NULL);
1052 
1053  if( (*node)->neighbors != NULL )
1054  {
1055  SCIPfreeMemoryArray(scip, &((*node)->neighbors));
1056  }
1057  if( (*node)->edgeweights != NULL )
1058  {
1059  SCIPfreeMemoryArray(scip, &((*node)->edgeweights));
1060  }
1061  if( (*node)->relatedrows != NULL )
1062  {
1063  SCIPfreeMemoryArray(scip, &((*node)->relatedrows));
1064  }
1065  SCIPfreeMemory(scip, node);
1066  (*node) = NULL;
1067 
1068  return SCIP_OKAY;
1069 }
1070 
1071 
1072 /** creates and initializes auxiliary graph data structures */
1073 static
1075  SCIP* scip, /**< SCIP data structure */
1076  ZEROHALF_AUXGRAPH** auxgraph /**< pointer to store pointer to created data structure */
1077  )
1078 {
1079  assert(scip != NULL);
1080  assert(auxgraph != NULL);
1081 
1082  SCIP_CALL(SCIPallocMemory(scip, auxgraph));
1083 
1084  (*auxgraph)->nodes = NULL;
1085  (*auxgraph)->nodecopies = NULL;
1086 
1087  (*auxgraph)->nnodes = 0;
1088 
1089  return SCIP_OKAY;
1090 }
1091 
1092 
1093 /** frees auxiliary graph data structures */
1094 static
1096  SCIP* scip, /**< SCIP data structure */
1097  ZEROHALF_AUXGRAPH** auxgraph /**< pointer to pointer of data structure */
1098  )
1099 {
1100  int n;
1101 
1102  assert(scip != NULL);
1103  assert(auxgraph != NULL);
1104 
1105  if( (*auxgraph)->nodes != NULL )
1106  {
1107  assert((*auxgraph)->nnodes > 0);
1108  for( n = 0; n < (*auxgraph)->nnodes ; ++n )
1109  if( (*auxgraph)->nodes[n] != NULL )
1110  {
1111  SCIP_CALL(ZerohalfAuxGraphNodeFree(scip, &((*auxgraph)->nodes[n])));
1112  }
1113  SCIPfreeMemoryArray(scip, (&(*auxgraph)->nodes));
1114  }
1115 
1116  if( (*auxgraph)->nodecopies != NULL )
1117  {
1118  assert((*auxgraph)->nnodes > 0);
1119  for( n = 0; n < (*auxgraph)->nnodes ; ++n )
1120  if( (*auxgraph)->nodecopies[n] != NULL )
1121  {
1122  SCIP_CALL(ZerohalfAuxGraphNodeFree(scip, &((*auxgraph)->nodecopies[n])));
1123  }
1124  SCIPfreeMemoryArray(scip, (&(*auxgraph)->nodecopies));
1125  }
1126 
1127  SCIPfreeMemory(scip, auxgraph);
1128  (*auxgraph) = NULL;
1129 
1130  return SCIP_OKAY;
1131 }
1132 
1133 
1134 /* --------------------------------------------------------------------------------------------------------------------
1135  * local methods: debug
1136  * -------------------------------------------------------------------------------------------------------------------- */
1137 
1138 #ifdef SCIP_DEBUG
1139 /** returns a string containing the name of the symbolic constant (given as int value) */
1140 static
1141 char* getconstantname(
1142  char* buffer, /**< string containing the name */
1143  int value /**< symbolic constant given as int value */
1144  )
1145 {
1146  switch( value )
1147  {
1148  case IRRELEVANT:
1149  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "IRRELEVANT"); break;
1150  case ZERO_ROW:
1151  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "ZEROROW"); break;
1153  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "IDENTROW"); break;
1155  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "SLACK>MAXSLACK"); break;
1157  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "ISZHCUT"); break;
1158 #ifdef WITHDECOMPOSE
1159  case ROW_IN_SUBPROB_WITHOUT_ODD_RHS:
1160  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "NOODDRHSROW"); break;
1161 #endif
1162  case NONEXISTENT_ROW:
1163  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "DOESNOTEXIST"); break;
1164  case NO_RELEVANT_COLUMNS:
1165  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "HASNORELEVANTCOLS"); break;
1167  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "SLACK+SODD>MAXSLACK"); break;
1168  case LARGE_COL_EXISTS:
1169  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "SCOL+SODD>MAXSLACK"); break;
1170  case ZERO_COLUMN:
1171  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "ZEROCOLUMN"); break;
1173  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "IDENTCOLUMN"); break;
1174  case ZERO_LP_SOL:
1175  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "PRIMSOL=0"); break;
1176  case LP_SOL_EQUALS_EVEN_LB:
1177  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "PRIMSOL=EVENLB"); break;
1178  case LP_SOL_EQUALS_ODD_LB:
1179  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "PRIMSOL=ODDLB"); break;
1180  case LP_SOL_EQUALS_EVEN_UB:
1181  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "PRIMSOL=EVENUB"); break;
1182  case LP_SOL_EQUALS_ODD_UB:
1183  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "PRIMSOL=ODDUB"); break;
1184  case SINGLETON_COLUMN:
1185  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "SINGLETONCOLUMN"); break;
1186  case CONTINUOUS_VARIABLE:
1187  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "CONTCOLUMN"); break;
1188  case SMALL_FRACSOL_HEUR:
1189  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "SUMFRACSOL<DELTA"); break;
1191  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "NOROWSLEFT"); break;
1192 #ifdef WITHDECOMPOSE
1193  case COLUMN_IN_SUBPROB_WITHOUT_ODD_RHS:
1194  (void) SCIPsnprintf(buffer, SCIP_MAXSTRLEN, "NOODDRHSCOL"); break;
1195 #endif
1196  default:
1197  SCIPerrorMessage("parameter <%s> unknown\n", value);
1198  SCIPABORT();
1199  }
1200 
1201  return buffer;
1202 }
1203 #endif
1204 
1205 
1206 #ifdef ZEROHALF__PRINT_STATISTICS
1207 /** prints the preprocessing statistics of the basic preprocessing applied while
1208  reading the LP data and building basic data structures */
1209 static
1210 SCIP_RETCODE printPreprocessingStatistics(
1211  SCIP* scip, /**< SCIP data structure */
1212  ZEROHALF_LPDATA* lpdata /**< data of current LP relaxation */
1213  )
1214 {
1215  int i;
1216  int nrelevantrows;
1217  int nirrelevantrows;
1218  int nerrors;
1219  int nrelevantcols;
1220  int nirrelevantcols;
1221  int nrows;
1222  int ncols;
1223  int nnonexistingrows;
1224 
1225  assert(lpdata != NULL);
1226 
1227  nrelevantrows = 0;
1228  nirrelevantrows = 0;
1229  nnonexistingrows = 0;
1230  nrelevantcols = 0;
1231  nirrelevantcols = 0;
1232  nerrors = 0;
1233 
1234  for( i = 0 ; i < lpdata->nrows ; ++i)
1235  {
1236  if( lpdata->rrowsindexofleftrow[i] >= 0 )
1237  nrelevantrows++;
1238  else
1239  if( lpdata->rrowsindexofleftrow[i] < -199 )
1240  nerrors++;
1241  else
1242  if( lpdata->rrowsindexofleftrow[i] == NONEXISTENT_ROW )
1243  nnonexistingrows++;
1244  else
1245  nirrelevantrows++;
1246  if( lpdata->rrowsindexofrightrow[i] >= 0 )
1247  nrelevantrows++;
1248  else
1249  if( lpdata->rrowsindexofrightrow[i] < -199 )
1250  nerrors++;
1251  else
1252  if( lpdata->rrowsindexofrightrow[i] == NONEXISTENT_ROW )
1253  nnonexistingrows++;
1254  else
1255  nirrelevantrows++;
1256  }
1257 
1258  for( i = 0 ; i < lpdata->ncols ; ++i)
1259  {
1260  if( lpdata->rcolsindexofcol[i] >= 0 )
1261  nrelevantcols++;
1262  else
1263  if( lpdata->rcolsindexofcol[i] == -1 )
1264  nirrelevantcols++;
1265  else
1266  if( lpdata->rcolsindexofcol[i] > -200 || lpdata->rcolsindexofcol[i] < -299 )
1267  nerrors++;
1268  else
1269  nirrelevantcols++;
1270  }
1271 
1272  nrows = nrelevantrows + nirrelevantrows - nnonexistingrows;
1273  ncols = nrelevantcols + nirrelevantcols;
1274 
1275  ZEROHALFstatisticsMessage("\n");
1276  ZEROHALFstatisticsMessage(" | ----- lp data ----- | --- (reductions) -- | --- problem data -- | -lpdata- | -(red.)- | -probd.- | --------\n");
1277  ZEROHALFstatisticsMessage(" | nrows | ncols | ndelrows | ndelcols | nrrows | nrcols | nvarbnds | ndlvbnds | nvarbnds | \n");
1278  ZEROHALFstatisticsMessage("%15s | %8d | %8d | %8d | %8d | %8d | %8d | %8d | %8d | %8d |\n",
1279  "READING LPDATA", nrows, ncols, nirrelevantrows - nnonexistingrows, nirrelevantcols, nrelevantrows, nrelevantcols,
1280  lpdata->nvarbounds, lpdata->ndelvarbounds, lpdata->nvarbounds - lpdata->ndelvarbounds);
1281 
1282  return SCIP_OKAY;
1283 }
1284 #endif
1285 
1286 
1287 #ifdef SCIP_DEBUG
1288 /** prints the considered subproblem */
1289 static
1290 void debugPrintSubLpData(
1291  SCIP* scip, /**< SCIP data structure */
1292  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
1293  ZEROHALF_SUBLPDATA* sublpdata /**< considered subproblem */
1294  )
1295 {
1296  int i;
1297  int j;
1298 
1299  assert(scip != NULL);
1300  assert(lpdata != NULL);
1301  assert(sublpdata != NULL);
1302 
1303 
1304  SCIPdebugMessage("\n debugPrintSubLpData:\n\n");
1305 
1306  SCIPdebugMessage(" rrows: (nrrows=%d)\n", sublpdata->nrrows);
1307  for( i = 0 ; i < sublpdata->nrrows ; ++i)
1308  {
1309  SCIPdebugMessage(" %6d: rrows: %6d rhs: %6g slack: %6g name: %s\n",
1310  i, sublpdata->rrows[i], sublpdata->rrowsrhs[i], sublpdata->rrowsslack[i],
1311  SCIProwGetName(lpdata->rows[sublpdata->rrows[i]]));
1312  }
1313  SCIPdebugMessage("\n rcols: (nrcols=%d)\n", sublpdata->nrcols);
1314  for( j = 0 ; j < sublpdata->nrcols ; ++j)
1315  {
1316  SCIPdebugMessage(" %6d: rcols: %6d lbslack: %6g ubslack: %6g\n",
1317  i, sublpdata->rcols[i], sublpdata->rcolslbslack[i], sublpdata->rcolsubslack[i]);
1318  }
1319 }
1320 #endif
1321 
1322 
1323 #ifdef SCIP_DEBUG
1324 /** prints mod 2 data structures */
1325 static
1326 void debugPrintMod2Data(
1327  SCIP* scip, /**< SCIP data structure */
1328  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
1329  ZEROHALF_MOD2DATA* mod2data, /**< considered mod 2 data structure */
1330  SCIP_Bool printaggregations /**< should row aggregation bitarrays be printed? */
1331  )
1332 {
1333  int i;
1334  int j;
1335  int k;
1336 
1337  assert(scip != NULL);
1338  assert(lpdata != NULL);
1339  assert(mod2data != NULL);
1340 
1341 
1342  SCIPdebugMessage("\n debugPrintMod2Data:\n\n");
1343 
1344  SCIPdebugMessage(" nrows = %d, nvarbounds = %d, nrcols = %d, nrowsind = %d, ncolsind = %d\n",
1345  mod2data->nrows, mod2data->nvarbounds, mod2data->relatedsubproblem->nrcols,
1346  mod2data->nrowsind, mod2data->ncolsind);
1347  SCIPdebugMessage(" rowsbitarraysize = %d, rowaggregationsbitarraysize = %d\n",
1348  mod2data->rowsbitarraysize, mod2data->rowaggregationsbitarraysize);
1349 
1350 
1351  SCIPdebugMessage("\n fracsol:\n");
1352  for( j = 0 ; j < mod2data->relatedsubproblem->nrcols ; ++j )
1353  {
1354  for( k = 0 ; k < mod2data->ncolsind ; ++k )
1355  if( mod2data->colsind[k] == j )
1356  break;
1357  SCIPdebugMessage(" rcols[%6d]: fracsol: %6g colsind: %6d name: %s\n", j, mod2data->fracsol[j],
1358  k < mod2data->ncolsind ? k : -1,
1359  SCIPvarGetName(SCIPcolGetVar(lpdata->cols[mod2data->relatedsubproblem->rcols[j]])));
1360  }
1361 
1362  SCIPdebugMessage("\n (A mod 2, b mod 2, [#nonz] (slacks), R, name(rrows), left(-)/right(+):\n");
1363  if( mod2data->nrowsind == 0 )
1364  {
1365  SCIPdebugMessage(" empty\n");
1366  }
1367  for( i = 0 ; i < mod2data->nrowsind ; ++i )
1368  {
1369  int nnonz = 0;
1370  SCIPdebugMessage(" ");
1371  for( j = 0 ; j < mod2data->ncolsind; ++j )
1372  if( BITARRAYBITISSET(mod2data->rows[mod2data->rowsind[i]], mod2data->colsind[j]) ) /*lint !e701*/
1373  {
1374  nnonz++;
1375  SCIPdebugPrintf("1");
1376  }
1377  else
1378  {
1379  SCIPdebugPrintf(".");
1380  }
1381  if( mod2data->rhs[mod2data->rowsind[i]] )
1382  {
1383  SCIPdebugPrintf(" 1");
1384  }
1385  else
1386  {
1387  SCIPdebugPrintf(" 0");
1388  }
1389  SCIPdebugPrintf(" [%4d] ", nnonz);
1390  SCIPdebugPrintf("(%6g) ", mod2data->slacks[mod2data->rowsind[i]]);
1391 
1392  if( printaggregations )
1393  {
1394  for( j = 0 ; j < mod2data->relatedsubproblem->nrrows; ++j )
1395  if( BITARRAYBITISSET(mod2data->rowaggregations[mod2data->rowsind[i]], j) ) /*lint !e701*/
1396  {
1397  SCIPdebugPrintf("1");
1398  }
1399  else
1400  {
1401  SCIPdebugPrintf(".");
1402  }
1403  }
1404 
1405  if( mod2data->rowsind[i] < mod2data->nrows - mod2data->nvarbounds )
1406  {
1407  SCIPdebugPrintf(" %s ", SCIProwGetName(lpdata->rows[mod2data->relatedsubproblem->rrows[mod2data->rowsind[i]]]));
1408  if( lpdata->rrowsindexofleftrow[mod2data->relatedsubproblem->rrows[mod2data->rowsind[i]]] == mod2data->rowsind[i] )
1409  {
1410  SCIPdebugPrintf(" -\n");
1411  }
1412  else
1413  {
1414  SCIPdebugPrintf(" +\n");
1415  }
1416  }
1417  else
1418  {
1419  SCIPdebugPrintf(" varbound(rows[%d])\n", mod2data->rowsind[i]);
1420  }
1421  }
1422  SCIPdebugPrintf("\n");
1423 }
1424 #endif
1425 
1426 
1427 #ifdef SCIP_DEBUG
1428 /** prints LP data */
1429 static
1430 SCIP_RETCODE debugPrintLPRowsAndCols(
1431  SCIP* scip, /**< SCIP data structure */
1432  ZEROHALF_LPDATA* lpdata /**< data of current LP relaxation */
1433  )
1434 {
1435  int i;
1436  int j;
1437  char temp[SCIP_MAXSTRLEN];
1438 
1439  assert(scip != NULL);
1440  assert(lpdata != NULL);
1441 
1442  SCIPdebugMessage("\n\nLP rows:\n");
1443  for( i = 0 ; i < lpdata->nrows ; ++i)
1444  {
1445  SCIPdebugMessage("\nrow %d (left): %s[%d,%d] %s:\n", i,
1446  (lpdata->subproblemsindexofrow[i] == IRRELEVANT)
1447  || (lpdata->rrowsindexofleftrow[i] < 0) ? "IRRELEVANT" : "RELEVANT",
1448  lpdata->subproblemsindexofrow[i], lpdata->rrowsindexofleftrow[i],
1449  lpdata->rrowsindexofleftrow[i] < 0 ? getconstantname(temp, lpdata->rrowsindexofleftrow[i]) : "");
1450  SCIPdebugMessage("row %d (right): %s[%d,%d] %s:\n", i,
1451  (lpdata->subproblemsindexofrow[i] == IRRELEVANT)
1452  || (lpdata->rrowsindexofrightrow[i] < 0) ? "IRRELEVANT" : "RELEVANT",
1453  lpdata->subproblemsindexofrow[i], lpdata->rrowsindexofrightrow[i],
1454  lpdata->rrowsindexofrightrow[i] < 0 ? getconstantname(temp, lpdata->rrowsindexofrightrow[i]) : "");
1455  SCIP_CALL( SCIPprintRow(scip, lpdata->rows[i], NULL) );
1456  }
1457 
1458  SCIPdebugMessage("\n\nLP cols:\n");
1459  for( j = 0 ; j < lpdata->ncols ; ++j)
1460  {
1461  SCIPdebugMessage("\ncol %d: %s[%d,%d] %s:\n", j,
1462  (lpdata->subproblemsindexofcol[j] == IRRELEVANT)
1463  || (lpdata->rcolsindexofcol[j] < 0) ? "IRRELEVANT" : "RELEVANT",
1464  lpdata->subproblemsindexofcol[j], lpdata->rcolsindexofcol[j],
1465  lpdata->rcolsindexofcol[j] < 0 ? getconstantname(temp, lpdata->rcolsindexofcol[j]) : "");
1466  SCIPdebugMessage("%s = %f\n",
1467  SCIPvarGetName(SCIPcolGetVar(lpdata->cols[j])),
1468  SCIPcolGetPrimsol(lpdata->cols[j]));
1469  }
1470 
1471  return SCIP_OKAY;
1472 }
1473 #endif
1474 
1475 
1476 /* --------------------------------------------------------------------------------------------------------------------
1477  * local methods: SCIPsortInd comparators
1478  * -------------------------------------------------------------------------------------------------------------------- */
1479 
1480 
1481 /** comparator function for sorting an index array non-decreasingly according to a real array */
1482 static
1483 SCIP_DECL_SORTINDCOMP(compRealNonDecreasing)
1484 {
1485  SCIP_Real* scores;
1486 
1487  scores = (SCIP_Real*) dataptr;
1488 
1489  if( scores[ind1] < scores[ind2] )
1490  return -1;
1491  else if( scores[ind1] > scores[ind2] )
1492  return +1;
1493  else
1494  return 0;
1495 }
1496 
1497 
1498 /** comparator function for sorting an index array non-increasingly according to a real array */
1499 static
1500 SCIP_DECL_SORTINDCOMP(compRealNonIncreasing)
1501 {
1502  SCIP_Real* scores;
1503 
1504  scores = (SCIP_Real*) dataptr;
1505 
1506  if( scores[ind1] < scores[ind2] )
1507  return +1;
1508  else if( scores[ind1] > scores[ind2] )
1509  return -1;
1510  else
1511  return 0;
1512 }
1513 
1514 
1515 /* --------------------------------------------------------------------------------------------------------------------
1516  * local methods: LP data
1517  * -------------------------------------------------------------------------------------------------------------------- */
1518 
1519 
1520 /** searches for relevant columns, i.e., columns that cannot be deleted because of basic preprocessing methods */
1521 static
1523  SCIP* scip, /**< SCIP data structure */
1524  ZEROHALF_LPDATA* lpdata /**< data of current LP relaxation */
1525  )
1526 {
1527  SCIP_VAR* var;
1528  SCIP_COL* col;
1529  SCIP_Real primsol;
1530  SCIP_Real lb;
1531  SCIP_Real ub;
1532  SCIP_Real lbslack;
1533  SCIP_Real ubslack;
1534  ZEROHALF_SUBLPDATA* problem;
1535  int j;
1536 #ifdef ZEROHALF__PRINT_STATISTICS
1537  int tempnvarbnds;
1538 #endif
1539  int nsubproblems;
1540 
1541  assert(scip != NULL);
1542  assert(lpdata != NULL);
1543  assert(lpdata->cols != NULL);
1544  assert(lpdata->ncols > 0);
1545  assert(lpdata->nrows > 0);
1546  assert(lpdata->subproblems == NULL);
1547  assert(lpdata->nsubproblems == 0);
1548  assert(lpdata->subproblemsindexofrow == NULL);
1549  assert(lpdata->rrowsindexofleftrow == NULL);
1550  assert(lpdata->rrowsindexofrightrow == NULL);
1551  assert(lpdata->subproblemsindexofcol == NULL);
1552  assert(lpdata->rcolsindexofcol == NULL);
1553  assert(lpdata->bestlbidxofcol == NULL);
1554  assert(lpdata->bestubidxofcol == NULL);
1555 
1556  nsubproblems = 1;
1557 
1558  /* allocate temporary memory for column data structures */
1559  SCIP_CALL(SCIPallocMemoryArray(scip, &(lpdata->subproblems), nsubproblems)); /* create one "sub"problem */
1560  SCIP_CALL(SCIPallocMemoryArray(scip, &(lpdata->subproblemsindexofcol), lpdata->ncols));
1561  SCIP_CALL(SCIPallocMemoryArray(scip, &(lpdata->rcolsindexofcol), lpdata->ncols));
1562  SCIP_CALL(SCIPallocMemoryArray(scip, &(lpdata->bestlbidxofcol), lpdata->ncols));
1563  SCIP_CALL(SCIPallocMemoryArray(scip, &(lpdata->bestubidxofcol), lpdata->ncols));
1564 
1565  SCIP_CALL(ZerohalfSubLPDataCreate(scip, &problem));
1566  SCIP_CALL(SCIPallocMemoryArray(scip, &(problem->rcols), lpdata->ncols));
1567  SCIP_CALL(SCIPallocMemoryArray(scip, &(problem->rcolslbslack), lpdata->ncols));
1568  SCIP_CALL(SCIPallocMemoryArray(scip, &(problem->rcolsubslack), lpdata->ncols));
1569 
1570  /* initialize data */
1571  BMSclearMemoryArray(lpdata->subproblemsindexofcol, lpdata->ncols);
1572  BMSclearMemoryArray(lpdata->rcolsindexofcol, lpdata->ncols);
1573 
1574  lpdata->nsubproblems = 1;
1575  lpdata->subproblems[0] = problem;
1576  lpdata->nvarbounds = 0;
1577  lpdata->ndelvarbounds = 0;
1578 
1579  /* check all cols */
1580  for( j = 0 ; j < lpdata->ncols ; ++j)
1581  {
1582  /* initialize best lb and best ub (-2: undetermined)*/
1583  lpdata->bestlbidxofcol[j] = -2;
1584  lpdata->bestubidxofcol[j] = -2;
1585 
1586  col = lpdata->cols[j];
1587  var = SCIPcolGetVar(col);
1588 
1589  /* check if vartype is continuous */
1591  {
1592  primsol = SCIPcolGetPrimsol(col);
1593  if( SCIPisFeasZero(scip, primsol) )
1594  primsol = 0.0;
1595 
1596  assert(SCIPisFeasEQ(scip, SCIPgetVarSol(scip, var), primsol));
1597 
1598  lb = SCIPcolGetLb(col);
1599  ub = SCIPcolGetUb(col);
1600  lbslack = primsol - lb;
1601  ubslack = ub - primsol;
1602  if( SCIPisFeasZero(scip, lbslack) )
1603  lbslack = 0.0;
1604  if( SCIPisFeasZero(scip, ubslack) )
1605  ubslack = 0.0;
1606  assert(SCIPisLE(scip, lb, ub));
1607  assert(!SCIPisNegative(scip, lbslack));
1608  assert(!SCIPisNegative(scip, ubslack));
1609 
1610 #ifdef ZEROHALF__PRINT_STATISTICS
1611  tempnvarbnds = 0;
1612  if( !SCIPisInfinity(scip, (-1) * lb) )
1613  tempnvarbnds++;
1614  if( !SCIPisInfinity(scip, ub) )
1615  tempnvarbnds++;
1616  lpdata->nvarbounds += tempnvarbnds;
1617 #endif
1618 
1619  if( SCIPisNegative(scip, lb) )
1620  {
1621  /* column is declared to be irrelevant because its lower bound is negative,
1622  * variable would have to be shifted, complemented or decomposed.
1623  */
1624  /**@todo consider general integers with negative lower bounds and transform to positive representation
1625  * and propagate through corresponding rows. In the current version, redundant inequalities might be
1626  * considered as cut candidates and valid cuts might be missed, but no wrong cuts should be produced
1627  * (due to SCIPcalcMIR) this leads to performance deterioration in the (rare) case of general integers
1628  * with negative bounds.
1629  */
1630  lpdata->subproblemsindexofcol[j] = IRRELEVANT;
1631  lpdata->rcolsindexofcol[j] = IRRELEVANT;
1632  }
1633  else if( !SCIPisZero(scip, primsol) )
1634  {
1635  if( SCIPisZero(scip, lbslack) )
1636  {
1637 #ifdef ZEROHALF__PRINT_STATISTICS
1638  lpdata->ndelvarbounds += tempnvarbnds;
1639 #endif
1640  lpdata->subproblemsindexofcol[j] = IRRELEVANT;
1641  if( ISODD(scip, lb) )
1642  lpdata->rcolsindexofcol[j] = LP_SOL_EQUALS_ODD_LB;
1643  else
1644  lpdata->rcolsindexofcol[j] = LP_SOL_EQUALS_EVEN_LB;
1645  }
1646  else
1647  {
1648  if( SCIPisZero(scip, ubslack) )
1649  {
1650 #ifdef ZEROHALF__PRINT_STATISTICS
1651  lpdata->ndelvarbounds += tempnvarbnds;
1652 #endif
1653  lpdata->subproblemsindexofcol[j] = IRRELEVANT;
1654  if( ISODD(scip, ub) )
1655  lpdata->rcolsindexofcol[j] = LP_SOL_EQUALS_ODD_UB;
1656  else
1657  lpdata->rcolsindexofcol[j] = LP_SOL_EQUALS_EVEN_UB;
1658  }
1659  else
1660  {
1661  /* relevant col was found */
1662  problem->rcols[problem->nrcols] = j;
1663  problem->rcolslbslack[problem->nrcols] = lbslack;
1664  problem->rcolsubslack[problem->nrcols] = ubslack;
1665  lpdata->subproblemsindexofcol[j] = 0;
1666  lpdata->rcolsindexofcol[j] = problem->nrcols;
1667  problem->nrcols++;
1668  }
1669  }
1670  }
1671  else
1672  {
1673 #ifdef ZEROHALF__PRINT_STATISTICS
1674  lpdata->ndelvarbounds += tempnvarbnds;
1675 #endif
1676  lpdata->subproblemsindexofcol[j] = IRRELEVANT;
1677  lpdata->rcolsindexofcol[j] = ZERO_LP_SOL;
1678  }
1679  }
1680  else
1681  {
1682  /* column is irrelevant because vartype is continuous (is handled in getRelevantRows())*/
1683  lpdata->subproblemsindexofcol[j] = IRRELEVANT;
1684  lpdata->rcolsindexofcol[j] = CONTINUOUS_VARIABLE;
1685  }
1686  }
1687 
1688  return SCIP_OKAY;
1689 }
1690 
1691 
1692 /** finds closest lower bound of col and stores it within lpdata;
1693  * the bound can be the lower bound or the best variable lower bound with nonnegative column variable
1694  */
1695 static
1697  SCIP* scip, /**< SCIP data structure */
1698  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
1699  SCIP_COL* col, /**< column to get closest lower bound */
1700  SCIP_Real* bestlbsol, /**< pointer to store value of closest lower bound */
1701  int* bestlbtype, /**< pointer to store type of closest lower bound */
1702  SCIP_VAR** bestzvlb, /**< pointer to store variable z in closest variable lower bound b*z + d */
1703  SCIP_Real* bestbvlb, /**< pointer to store coefficient b in closest variable lower bound b*z + d */
1704  SCIP_Real* bestdvlb /**< pointer to store constant d in closest variable lower bound b*z + d */
1705 
1706  )
1707 {
1708  SCIP_VAR* var;
1709  SCIP_VAR** zvlb;
1710  SCIP_Real* bvlb;
1711  SCIP_Real* dvlb;
1712  int collppos;
1713  int nvlb;
1714  int j;
1715 
1716  assert(lpdata != NULL);
1717  assert(bestlbsol != NULL);
1718  assert(bestlbtype != NULL);
1719  assert(bestzvlb != NULL);
1720  assert(bestbvlb != NULL);
1721  assert(bestdvlb != NULL);
1722 
1723 
1724  collppos = SCIPcolGetLPPos(col);
1725  var = SCIPcolGetVar(col);
1726  *bestlbsol = SCIPcolGetLb(col);
1727  *bestlbtype = lpdata->bestlbidxofcol[collppos];
1728  *bestzvlb = NULL;
1729  *bestbvlb = 0.0;
1730  *bestdvlb = 0.0;
1731 
1732  if( *bestlbtype == -1 )
1733  return;
1734 
1735  if( USEVARBOUNDS ) /*lint !e774 !e506*/
1736  {
1737  nvlb = SCIPvarGetNVlbs(var);
1738  zvlb = SCIPvarGetVlbVars(var);
1739  bvlb = SCIPvarGetVlbCoefs(var);
1740  dvlb = SCIPvarGetVlbConstants(var);
1741 
1742  assert(zvlb != NULL || nvlb == 0);
1743  assert(bvlb != NULL || nvlb == 0);
1744  assert(dvlb != NULL || nvlb == 0);
1745  }
1746 
1747  if( *bestlbtype == -2 )
1748  {
1749  if( USEVARBOUNDS ) /*lint !e774 !e506*/
1750  {
1751 
1752  /* search for lb or vlb with maximal bound value */
1753  for( j = 0; j < nvlb; j++ )
1754  {
1755  assert(zvlb != NULL);
1756  assert(bvlb != NULL);
1757  assert(dvlb != NULL);
1758  assert(SCIPvarGetType(zvlb[j]) != SCIP_VARTYPE_CONTINUOUS);
1759 
1760  /* use only vlb with nonnegative variable z that are column variables and present in the current LP */
1761  if( SCIPvarGetStatus(zvlb[j]) == SCIP_VARSTATUS_COLUMN && SCIPcolIsInLP(SCIPvarGetCol(zvlb[j])) &&
1762  !SCIPisNegative(scip, SCIPcolGetLb(SCIPvarGetCol(zvlb[j]))) )
1763  {
1764  SCIP_Real vlbsol;
1765 
1766  vlbsol = bvlb[j] * SCIPcolGetPrimsol(SCIPvarGetCol(zvlb[j])) + dvlb[j];
1767  if( vlbsol > *bestlbsol )
1768  {
1769  *bestlbsol = vlbsol;
1770  *bestlbtype = j;
1771  }
1772  }
1773  }
1774  }
1775 
1776  /* if no better var bound could be found, set type to the fixed bound (-1) */
1777  if( *bestlbtype == -2 )
1778  *bestlbtype = -1;
1779 
1780  /* store best bound for substitution */
1781  lpdata->bestlbidxofcol[collppos] = *bestlbtype;
1782  }
1783  assert(lpdata->bestlbidxofcol[collppos] > -2);
1784 
1785  if( *bestlbtype >= 0 )
1786  {
1787  assert(USEVARBOUNDS); /*lint !e774 !e506*/
1788  assert(*bestlbtype < nvlb);
1789  assert(zvlb != NULL);
1790  assert(bvlb != NULL);
1791  assert(dvlb != NULL);
1792  *bestzvlb = zvlb[*bestlbtype];
1793  *bestbvlb = bvlb[*bestlbtype];
1794  *bestdvlb = dvlb[*bestlbtype];
1795  }
1796 }
1797 
1798 
1799 /** finds closest upper bound of col and stores it within lpdata;
1800  * the bound can be the upper bound or the best variable upper bound with nonnegative column variable
1801  */
1802 static
1804  SCIP* scip, /**< SCIP data structure */
1805  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
1806  SCIP_COL* col, /**< column to get closest upper bound */
1807  SCIP_Real* bestubsol, /**< pointer to store value of closest upper bound */
1808  int* bestubtype, /**< pointer to store type of closest upper bound */
1809  SCIP_VAR** bestzvub, /**< pointer to store variable z in closest variable upper bound b*z + d */
1810  SCIP_Real* bestbvub, /**< pointer to store coefficient b in closest variable upper bound b*z + d */
1811  SCIP_Real* bestdvub /**< pointer to store constant d in closest variable upper bound b*z + d */
1812 
1813  )
1814 {
1815  SCIP_VAR* var;
1816  SCIP_VAR** zvub;
1817  SCIP_Real* bvub;
1818  SCIP_Real* dvub;
1819  int collppos;
1820  int nvub;
1821  int j;
1822 
1823  assert(lpdata != NULL);
1824  assert(bestubsol != NULL);
1825  assert(bestubtype != NULL);
1826  assert(bestzvub != NULL);
1827  assert(bestbvub != NULL);
1828  assert(bestdvub != NULL);
1829 
1830  collppos = SCIPcolGetLPPos(col);
1831  var = SCIPcolGetVar(col);
1832  *bestubsol = SCIPcolGetUb(col);
1833  *bestubtype = lpdata->bestubidxofcol[collppos];
1834  *bestzvub = NULL;
1835  *bestbvub = 0.0;
1836  *bestdvub = 0.0;
1837 
1838  if( *bestubtype == -1 )
1839  return;
1840 
1841  if( USEVARBOUNDS ) /*lint !e774 !e506*/
1842  {
1843  nvub = SCIPvarGetNVubs(var);
1844  zvub = SCIPvarGetVubVars(var);
1845  bvub = SCIPvarGetVubCoefs(var);
1846  dvub = SCIPvarGetVubConstants(var);
1847 
1848  assert(zvub != NULL || nvub == 0);
1849  assert(bvub != NULL || nvub == 0);
1850  assert(dvub != NULL || nvub == 0);
1851  }
1852 
1853  if( *bestubtype == -2 )
1854  {
1855  if( USEVARBOUNDS ) /*lint !e774 !e506*/
1856  {
1857  /* search for ub or vub with maximal bound value */
1858  for( j = 0; j < nvub; j++ )
1859  {
1860  assert(zvub != NULL);
1861  assert(bvub != NULL);
1862  assert(dvub != NULL);
1863  assert(SCIPvarGetType(zvub[j]) != SCIP_VARTYPE_CONTINUOUS);
1864 
1865  /* use only vub with nonnegative variable z that are column variables and present in the current LP */
1866  if( SCIPvarGetStatus(zvub[j]) == SCIP_VARSTATUS_COLUMN && SCIPcolIsInLP(SCIPvarGetCol(zvub[j])) &&
1867  !SCIPisNegative(scip, SCIPcolGetUb(SCIPvarGetCol(zvub[j]))) )
1868  {
1869  SCIP_Real vubsol;
1870 
1871  vubsol = bvub[j] * SCIPcolGetPrimsol(SCIPvarGetCol(zvub[j])) + dvub[j];
1872  if( vubsol < *bestubsol )
1873  {
1874  *bestubsol = vubsol;
1875  *bestubtype = j;
1876  }
1877  }
1878  }
1879  }
1880  /* if no better var bound could be found, set type to the fixed bound (-1) */
1881  if( *bestubtype == -2 )
1882  *bestubtype = -1;
1883 
1884  /* store best bound for substitution */
1885  lpdata->bestubidxofcol[collppos] = *bestubtype;
1886  }
1887  assert(lpdata->bestubidxofcol[collppos] > -2);
1888 
1889  if( *bestubtype >= 0 )
1890  {
1891  assert(USEVARBOUNDS); /*lint !e774 !e506*/
1892  assert(*bestubtype < nvub);
1893  assert(zvub != NULL);
1894  assert(bvub != NULL);
1895  assert(dvub != NULL);
1896  *bestzvub = zvub[*bestubtype];
1897  *bestbvub = bvub[*bestubtype];
1898  *bestdvub = dvub[*bestubtype];
1899  }
1900 }
1901 
1902 
1903 /** searches for relevant rows, i.e., rows containing relevant columns that cannot be deleted because of basic
1904  * preprocessing methods
1905  */
1906 static
1908  SCIP* scip, /**< SCIP data structure */
1909  SCIP_SEPADATA* sepadata, /**< separator data */
1910  ZEROHALF_LPDATA* lpdata /**< data of current LP relaxation */
1911  )
1912 {
1913  SCIP_COL** colscurrentrow;
1914  SCIP_Real* valscurrentrow;
1915  SCIP_Real* densecoeffscurrentleftrow;
1916  SCIP_Real* densecoeffscurrentrightrow;
1917  SCIP_ROW* row;
1918  SCIP_VAR* var;
1919  SCIP_VAR* bestzvbnd;
1920  SCIP_Real bestbndsol;
1921  SCIP_Real bestbvbnd;
1922  SCIP_Real bestdvbnd;
1923  SCIP_Real intscalarleftrow;
1924  SCIP_Real intscalarrightrow;
1925  SCIP_Real act;
1926  SCIP_Real cst;
1927  SCIP_Real lhs;
1928  SCIP_Real lhsslack;
1929  SCIP_Real maxslack;
1930  SCIP_Real rhs;
1931  SCIP_Real rhsslack;
1932  int bestbndtype;
1933  int nnonzcurrentrow;
1934  int c;
1935  int r;
1936  int k;
1937  SCIP_Bool lhsslackislessequalmaxslack;
1938  SCIP_Bool rhsslackislessequalmaxslack;
1939  SCIP_Bool lhsisinfinity;
1940  SCIP_Bool rhsisinfinity;
1941  SCIP_Bool lhsiseven;
1942  SCIP_Bool rhsiseven;
1943  SCIP_Bool success;
1944  ZEROHALF_SUBLPDATA* problem;
1945 
1946  int collppos;
1947  SCIP_Bool rowisrelevant;
1948 
1949  assert(scip != NULL);
1950  assert(sepadata != NULL);
1951  assert(lpdata != NULL);
1952  assert(lpdata->rows != NULL);
1953  assert(lpdata->nrows > 0);
1954  assert(lpdata->subproblemsindexofcol != NULL);
1955  assert(lpdata->rcolsindexofcol != NULL);
1956  assert(lpdata->subproblems != NULL);
1957  assert(lpdata->nsubproblems > 0);
1958 
1959  assert(lpdata->subproblemsindexofrow == NULL);
1960  assert(lpdata->rrowsindexofleftrow == NULL);
1961  assert(lpdata->rrowsindexofrightrow == NULL);
1962 
1963  k = 0;
1964  problem = lpdata->subproblems[k];
1965 
1966  assert(k >= 0);
1967  assert(k <= lpdata->nsubproblems);
1968  assert(problem != NULL);
1969  assert(problem->rcols != NULL);
1970  assert(problem->nrcols > 0);
1971  assert(problem->rcolslbslack != NULL);
1972  assert(problem->rcolsubslack != NULL);
1973 
1974  assert(problem->rrows == NULL);
1975  assert(problem->rrowsrhs == NULL);
1976  assert(problem->rrowsslack == NULL);
1977 
1978  /* allocate temporary memory for row data structures */
1979  SCIP_CALL(SCIPallocMemoryArray(scip, &(lpdata->subproblemsindexofrow), lpdata->nrows));
1980  SCIP_CALL(SCIPallocMemoryArray(scip, &(lpdata->rrowsindexofleftrow), lpdata->nrows));
1981  SCIP_CALL(SCIPallocMemoryArray(scip, &(lpdata->rrowsindexofrightrow), lpdata->nrows));
1982  SCIP_CALL(SCIPallocMemoryArray(scip, &(problem->rrows), 2 * lpdata->nrows));
1983  SCIP_CALL(SCIPallocMemoryArray(scip, &(problem->rrowsrhs), 2 * lpdata->nrows));
1984  SCIP_CALL(SCIPallocMemoryArray(scip, &(problem->rrowsslack), 2 * lpdata->nrows));
1985 
1986  /* allocate temporary memory */
1987  SCIP_CALL(SCIPallocBufferArray(scip, &densecoeffscurrentleftrow, lpdata->ncols));
1988  SCIP_CALL(SCIPallocBufferArray(scip, &densecoeffscurrentrightrow, lpdata->ncols));
1989 
1990  /* initialize arrays */
1991  BMSclearMemoryArray(lpdata->subproblemsindexofrow, lpdata->nrows);
1992  BMSclearMemoryArray(lpdata->rrowsindexofleftrow, lpdata->nrows);
1993  BMSclearMemoryArray(lpdata->rrowsindexofrightrow, lpdata->nrows);
1994  BMSclearMemoryArray(densecoeffscurrentleftrow, lpdata->ncols);
1995  BMSclearMemoryArray(densecoeffscurrentrightrow, lpdata->ncols);
1996 
1997  maxslack = sepadata->maxslack;
1998  problem->nrrows = 0;
1999  for( r = 0 ; r < lpdata->nrows ; ++r)
2000  {
2001  row = lpdata->rows[r];
2002 
2003  if( sepadata->ignoreprevzhcuts )
2004  {
2005  /* ignore rows whose names start with "zerohalf" */
2006  const char* rowname = SCIProwGetName(row);
2007 
2008  if( strlen(rowname) > 8 )
2009  if(rowname[0] == 'z'
2010  && rowname[1] == 'e'
2011  && rowname[2] == 'r'
2012  && rowname[3] == 'o'
2013  && rowname[4] == 'h'
2014  && rowname[5] == 'a'
2015  && rowname[6] == 'l'
2016  && rowname[7] == 'f' )
2017  {
2018  lpdata->subproblemsindexofrow[r] = IRRELEVANT;
2019  lpdata->rrowsindexofleftrow[r] = NONEXISTENT_ROW;
2020  lpdata->rrowsindexofrightrow[r] = NONEXISTENT_ROW;
2021  continue;
2022  }
2023  }
2024 
2025  /* check if current row is an original LP row (i.e., was not added) if necessary */
2026  if( sepadata->onlyorigrows )
2027  {
2028  int left;
2029  int center;
2030  int right;
2031  int rowindex;
2032 
2033  assert(sepadata->origrows != NULL);
2034  assert(sepadata->norigrows > 0);
2035 
2036  left = 0;
2037  center = 1;
2038  right = sepadata->norigrows - 1;
2039  rowindex = SCIProwGetIndex(row);
2040  while( left <= right && center > -1 )
2041  {
2042  center = left + ((right - left) / 2);
2043  if( sepadata->origrows[center] == rowindex )
2044  center = -1;
2045  if( sepadata->origrows[center] > rowindex )
2046  right = center - 1;
2047  else
2048  left = center + 1;
2049  }
2050  if( center > -1 )
2051  {
2052  lpdata->subproblemsindexofrow[r] = IRRELEVANT;
2053  lpdata->rrowsindexofleftrow[r] = NONEXISTENT_ROW;
2054  lpdata->rrowsindexofrightrow[r] = NONEXISTENT_ROW;
2055  continue;
2056  }
2057  }
2058 
2059  /* get row data */
2060  colscurrentrow = SCIProwGetCols(row);
2061  nnonzcurrentrow = SCIProwGetNLPNonz(row);
2062  valscurrentrow = SCIProwGetVals(row);
2063 
2064  /* clear dense coeffs arrays */
2065  BMSclearMemoryArray(densecoeffscurrentleftrow, lpdata->ncols);
2066  BMSclearMemoryArray(densecoeffscurrentrightrow, lpdata->ncols);
2067 
2068  /* calculate dense coeffs arrays */
2069  for( c = 0; c < nnonzcurrentrow; ++c)
2070  {
2071  collppos = SCIPcolGetLPPos(colscurrentrow[c]);
2072  assert(0 <= collppos && collppos < lpdata->ncols);
2073 
2074  var = SCIPcolGetVar(colscurrentrow[c]);
2075 
2076  /* check if row contains a continuous variable */
2078  {
2079  bestzvbnd = NULL;
2080  bestbndsol = 0.0;
2081  bestbvbnd = 0.0;
2082  bestdvbnd = 0.0;
2083  bestbndtype = -2;
2084 
2085  /* Consider rhs of row and relax continuous variables by substituting for:
2086  * - a_j > 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with column var z >= 0
2087  * - a_j < 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with column var z >= 0
2088  * and
2089  * consider lhs of row and relax continuous variables by substituting for:
2090  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with column var z >= 0
2091  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with column var z >= 0
2092  */
2093 
2094  findClosestLb(scip, lpdata, colscurrentrow[c],
2095  &bestbndsol, &bestbndtype, &bestzvbnd, &bestbvbnd, &bestdvbnd );
2096  assert( bestbndtype > -2 && lpdata->bestlbidxofcol[collppos] == bestbndtype);
2097 
2098  if( bestbndtype > -1 )
2099  {
2100  int zlppos;
2101 
2102  zlppos = SCIPcolGetLPPos(SCIPvarGetCol(bestzvbnd));
2103  assert(0 <= zlppos && zlppos < lpdata->ncols);
2104 
2105  if( valscurrentrow[c] > 0 )
2106  densecoeffscurrentrightrow[zlppos] += valscurrentrow[c] * bestbvbnd;
2107  else
2108  densecoeffscurrentleftrow[zlppos] -= valscurrentrow[c] * bestbvbnd;
2109  }
2110 
2111  findClosestUb(scip, lpdata, colscurrentrow[c],
2112  &bestbndsol, &bestbndtype, &bestzvbnd, &bestbvbnd, &bestdvbnd );
2113  assert(bestbndtype > -2 && lpdata->bestubidxofcol[collppos] == bestbndtype);
2114 
2115  if( bestbndtype > -1 )
2116  {
2117  int zlppos;
2118 
2119  zlppos = SCIPcolGetLPPos(SCIPvarGetCol(bestzvbnd));
2120  assert(0 <= zlppos && zlppos < lpdata->ncols);
2121 
2122  if( valscurrentrow[c] > 0 )
2123  densecoeffscurrentleftrow[zlppos] -= valscurrentrow[c] * bestbvbnd;
2124  else
2125  densecoeffscurrentrightrow[zlppos] += valscurrentrow[c] * bestbvbnd;
2126  }
2127  }
2128  else
2129  {
2130  densecoeffscurrentleftrow[collppos] -= valscurrentrow[c];
2131  densecoeffscurrentrightrow[collppos] += valscurrentrow[c];
2132  }
2133  }
2134 
2135  /* calculate scalar that would make (left|right) row coefficients integral;
2136  * try to avoid unnecessary or expensive scaling calls
2137  */
2138  intscalarleftrow = 1.0;
2139  intscalarrightrow = 1.0;
2140 
2141  if( sepadata->scalefraccoeffs && (!SCIPisIntegral(scip, SCIPgetRowMinCoef(scip, row))
2142  || !SCIPisIntegral(scip, SCIPgetRowMaxCoef(scip, row)) || !SCIPisIntegral(scip, SCIProwGetSumNorm(row))) )
2143  {
2144  SCIP_CALL( SCIPcalcIntegralScalar(densecoeffscurrentleftrow, lpdata->ncols,
2145  -SCIPepsilon(scip), SCIPepsilon(scip), (SCIP_Longint) MAXDNOM, MAXSCALE, &intscalarleftrow, &success) );
2146  if( !success )
2147  {
2148  lpdata->rrowsindexofleftrow[r] = NONEXISTENT_ROW;
2149  }
2150 
2151  SCIP_CALL( SCIPcalcIntegralScalar(densecoeffscurrentrightrow, lpdata->ncols,
2152  -SCIPepsilon(scip), SCIPepsilon(scip), (SCIP_Longint) MAXDNOM, MAXSCALE, &intscalarrightrow, &success) );
2153  if( !success )
2154  {
2155  lpdata->rrowsindexofrightrow[r] = NONEXISTENT_ROW;
2156  }
2157 
2158  if ( lpdata->rrowsindexofleftrow[r] == NONEXISTENT_ROW
2159  && lpdata->rrowsindexofrightrow[r] == NONEXISTENT_ROW )
2160  {
2161  lpdata->subproblemsindexofrow[r] = IRRELEVANT;
2162  continue;
2163  }
2164  }
2165 
2166  lpdata->intscalarsleftrow[r] = intscalarleftrow;
2167  lpdata->intscalarsrightrow[r] = intscalarrightrow;
2168 
2169  /* calculate lhs/rhs & slacks */
2170  act = SCIPgetRowLPActivity(scip, row);
2171  lhs = SCIProwGetLhs(row);
2172  rhs = SCIProwGetRhs(row);
2173  cst = SCIProwGetConstant(row);
2174 
2175  lhsisinfinity = SCIPisInfinity(scip, -lhs);
2176  rhsisinfinity = SCIPisInfinity(scip, rhs);
2177 
2178  lhsslack = SCIPisFeasZero(scip, act - lhs) ? 0.0 : act - lhs;
2179  rhsslack = SCIPisFeasZero(scip, rhs - act) ? 0.0 : rhs - act;
2180 
2181  lhs = (lhs - cst) * intscalarleftrow;
2182  rhs = (rhs - cst) * intscalarrightrow;
2183 
2184  lhsisinfinity = lhsisinfinity || SCIPisInfinity(scip, -lhs);
2185  rhsisinfinity = rhsisinfinity || SCIPisInfinity(scip, rhs);
2186 
2187  lhsslack = lhsslack * intscalarleftrow;
2188  rhsslack = rhsslack * intscalarrightrow;
2189 
2190  /* check if the slack value of the row is small enough */
2191  if( (!lhsisinfinity && SCIPisLE(scip, lhsslack, maxslack))
2192  || (!rhsisinfinity && SCIPisLE(scip, rhsslack, maxslack)) )
2193  {
2194  colscurrentrow = SCIProwGetCols(row);
2195  nnonzcurrentrow = SCIProwGetNLPNonz(row);
2196  valscurrentrow = SCIProwGetVals(row);
2197 
2198  lhsiseven = ISEVEN(scip, lhs);
2199  rhsiseven = ISEVEN(scip, rhs);
2200 
2201  rowisrelevant = FALSE;
2202  for( c = 0 ; c < nnonzcurrentrow ; ++c )
2203  {
2204  collppos = SCIPcolGetLPPos(colscurrentrow[c]);
2205  var = SCIPcolGetVar(colscurrentrow[c]);
2206 
2207  /* check if row contains a column with primsol = odd bound and update lhs/rhs parity */
2208  if( lpdata->rcolsindexofcol[collppos] == LP_SOL_EQUALS_ODD_LB
2209  || lpdata->rcolsindexofcol[collppos] == LP_SOL_EQUALS_ODD_UB )
2210  {
2211  assert(SCIPvarGetType(SCIPcolGetVar(colscurrentrow[c])) != SCIP_VARTYPE_CONTINUOUS);
2212  lhsiseven = !lhsiseven;
2213  rhsiseven = !rhsiseven;
2214  }
2215 
2216  /* check if row contains a continuous variable */
2218  {
2219  if( !rhsisinfinity )
2220  {
2221  if( valscurrentrow[c] * intscalarrightrow > 0 )
2222  {
2223  findClosestLb(scip, lpdata, colscurrentrow[c], &bestbndsol, &bestbndtype, &bestzvbnd, &bestbvbnd, &bestdvbnd );
2224  assert(bestbndtype > -2 && lpdata->bestlbidxofcol[collppos] == bestbndtype);
2225  }
2226  else
2227  {
2228  assert(valscurrentrow[c] * intscalarrightrow < 0);
2229  findClosestUb(scip, lpdata, colscurrentrow[c], &bestbndsol, &bestbndtype, &bestzvbnd, &bestbvbnd, &bestdvbnd );
2230  assert(bestbndtype > -2 && lpdata->bestubidxofcol[collppos] == bestbndtype);
2231  }
2232  assert(bestbndtype == -1 || bestzvbnd != NULL);
2233 
2234  if( SCIPisInfinity(scip, -bestbndsol) || SCIPisInfinity(scip, bestbndsol) )
2235  rhsisinfinity = TRUE;
2236  else
2237  {
2238  /**@todo check whether REALABS is really correct */
2239  if ( bestbndtype == -1 )
2240  rhs -= intscalarrightrow * REALABS(valscurrentrow[c]) * bestbndsol;
2241  else
2242  rhs -= intscalarrightrow * REALABS(valscurrentrow[c]) * bestdvbnd;
2243  rhsslack += intscalarrightrow * REALABS(valscurrentrow[c])
2244  * REALABS(SCIPcolGetPrimsol(colscurrentrow[c]) - bestbndsol);
2245  assert(SCIPisGE(scip, rhsslack, 0.0));
2246  rhsisinfinity = rhsisinfinity || SCIPisInfinity(scip, rhs);
2247  }
2248  }
2249 
2250  if( !lhsisinfinity )
2251  {
2252  if( valscurrentrow[c] * intscalarleftrow < 0 )
2253  {
2254  findClosestLb(scip, lpdata, colscurrentrow[c], &bestbndsol, &bestbndtype, &bestzvbnd, &bestbvbnd, &bestdvbnd );
2255  assert(bestbndtype > -2 && lpdata->bestlbidxofcol[collppos] == bestbndtype);
2256  }
2257  else
2258  {
2259  assert(valscurrentrow[c] * intscalarleftrow > 0);
2260  findClosestUb(scip, lpdata, colscurrentrow[c], &bestbndsol, &bestbndtype, &bestzvbnd, &bestbvbnd, &bestdvbnd );
2261  assert(bestbndtype > -2 && lpdata->bestubidxofcol[collppos] == bestbndtype);
2262  }
2263  assert(bestbndtype == -1 || bestzvbnd != NULL);
2264 
2265  if( SCIPisInfinity(scip, -bestbndsol) || SCIPisInfinity(scip, bestbndsol) )
2266  lhsisinfinity = TRUE;
2267  else
2268  {
2269  /**@todo check whether REALABS is really correct */
2270  if( bestbndtype == -1 )
2271  lhs -= intscalarleftrow * REALABS(valscurrentrow[c]) * bestbndsol;
2272  else
2273  lhs -= intscalarleftrow * REALABS(valscurrentrow[c]) * bestdvbnd;
2274  lhsslack += intscalarleftrow * REALABS(valscurrentrow[c])
2275  * REALABS(SCIPcolGetPrimsol(colscurrentrow[c]) - bestbndsol);
2276  assert(SCIPisGE(scip, lhsslack, 0.0));
2277  lhsisinfinity = lhsisinfinity || SCIPisInfinity(scip, lhs);
2278  }
2279  }
2280 
2281  /* if both lhs and rhs became infinity, then the (relaxed) row is not relevant */
2282  if( lhsisinfinity && rhsisinfinity )
2283  {
2284  rowisrelevant = FALSE;
2285  break;
2286  }
2287 
2288  rowisrelevant = TRUE;
2289  }
2290 
2291  /* check if row contains at least one relevant column (because k == 0 by initialization) */
2292  if( lpdata->subproblemsindexofcol[collppos] == k )
2293  rowisrelevant = TRUE;
2294 
2295  /* check if row contains no relevant columns but an odd lhs or rhs value */
2296  if( c == nnonzcurrentrow - 1 && (!lhsiseven || !rhsiseven) )
2297  rowisrelevant = TRUE;
2298 
2299  }
2300  assert(SCIPisGE(scip, lhsslack, 0.0));
2301  assert(SCIPisGE(scip, rhsslack, 0.0));
2302 
2303 
2304  /* process row if it is relevant */
2305  if( rowisrelevant )
2306  {
2307  /* row is relevant because it contains a relevant column */
2308  problem->rrows[problem->nrrows] = r;
2309 
2310  lhsslackislessequalmaxslack = SCIPisLE(scip, lhsslack, maxslack);
2311  rhsslackislessequalmaxslack = SCIPisLE(scip, rhsslack, maxslack);
2312 
2313  /* note: due to the relaxation of continuous variables with their bounds the coeffs of nonzero variables
2314  * in left row and right row may be different. hence the row with smaller slack cannot be removed without
2315  * checking the coeffs first.
2316  */
2317  if( !lhsisinfinity && lhsslackislessequalmaxslack )
2318  {
2319  /* "-a^T x <= -lhs" */
2320  lpdata->subproblemsindexofrow[r] = k;
2321  lpdata->rrowsindexofleftrow[r] = problem->nrrows;
2322 
2323  problem->rrows[problem->nrrows] = r;
2324  /**@todo check whether lhs is correct, or whether this must be -lhs. do we store the
2325  * -ax <= -lhs constraint or the ax >= lhs constraint? Is this handled correctly above while updating lhs?
2326  */
2327  problem->rrowsrhs[problem->nrrows] = lhs;
2328  problem->rrowsslack[problem->nrrows] = lhsslack;
2329  }
2330  else
2331  {
2332  lpdata->rrowsindexofleftrow[r] = lhsisinfinity ? NONEXISTENT_ROW : SLACK_GREATER_THAN_MAXSLACK;
2333  }
2334  /**@todo check the following: if !lhsinfinity AND !rhsinfinity: then only one of them is stored currently,
2335  * because problem->nrrows++ is only called once. if this is intended, why do we allocate 2 * lpdata->nrows
2336  * entries for rrows?
2337  */
2338  if( !rhsisinfinity && rhsslackislessequalmaxslack )
2339  {
2340  /* "a^T x <= rhs" */
2341  lpdata->subproblemsindexofrow[r] = k;
2342  lpdata->rrowsindexofrightrow[r] = problem->nrrows;
2343 
2344  problem->rrows[problem->nrrows] = r;
2345  problem->rrowsrhs[problem->nrrows] = rhs;
2346  problem->rrowsslack[problem->nrrows] = rhsslack;
2347  }
2348  else
2349  {
2350  lpdata->rrowsindexofrightrow[r] = rhsisinfinity ? NONEXISTENT_ROW : SLACK_GREATER_THAN_MAXSLACK;
2351  }
2352 
2353  /* increase counter only if at least one half row had a sufficiently small slack */
2354  if( lpdata->rrowsindexofleftrow[r] > -1 || lpdata->rrowsindexofrightrow[r] > -1 )
2355  problem->nrrows++;
2356  }
2357  else /* case: !rowisrelevant */
2358  {
2359  /* row does not contain relevant columns */
2360  lpdata->subproblemsindexofrow[r] = IRRELEVANT;
2361  lpdata->rrowsindexofleftrow[r] = lhsisinfinity ? NONEXISTENT_ROW : NO_RELEVANT_COLUMNS;
2362  lpdata->rrowsindexofrightrow[r] = rhsisinfinity ? NONEXISTENT_ROW : NO_RELEVANT_COLUMNS;
2363  }
2364  }
2365  else /* case: lhsslack > maxslack && rhsslack > maxslack */
2366  {
2367  lpdata->subproblemsindexofrow[r] = IRRELEVANT;
2368  lpdata->rrowsindexofleftrow[r] = lhsisinfinity ? NONEXISTENT_ROW : SLACK_GREATER_THAN_MAXSLACK;
2369  lpdata->rrowsindexofrightrow[r] = rhsisinfinity ? NONEXISTENT_ROW : SLACK_GREATER_THAN_MAXSLACK;
2370  }
2371  }
2372 
2373  /* free temporary memory */
2374  SCIPfreeBufferArray(scip, &densecoeffscurrentleftrow);
2375  SCIPfreeBufferArray(scip, &densecoeffscurrentrightrow);
2376 
2377  return SCIP_OKAY;
2378 }
2379 
2380 
2381 
2382 /* check if mod 2 data structure contains at most two nonzero entries per row */
2383 static
2385  ZEROHALF_MOD2DATA* mod2data /**< considered mod 2 data */
2386  )
2387 {
2388  int r;
2389  int c;
2390  int nentries;
2391 
2392  assert(mod2data != NULL);
2393 
2394  if( mod2data->nrowsind == 0 )
2395  return TRUE; /*FALSE;*/
2396 
2397  if( mod2data->ncolsind <= 2 )
2398  return TRUE;
2399 
2400  for( r = 0; r < mod2data->nrowsind ; ++r )
2401  {
2402  nentries = 0;
2403  for( c = 0; c < mod2data->ncolsind ; ++c )
2404  {
2405  if( BITARRAYBITISSET(mod2data->rows[mod2data->rowsind[r]], mod2data->colsind[c]) ) /*lint !e701*/
2406  {
2407  nentries++;
2408  if( nentries > 2 )
2409  return FALSE;
2410  }
2411  }
2412  }
2413 
2414  return TRUE;
2415 }
2416 
2417 
2418 
2419 #ifdef ZEROHALF__PRINT_STATISTICS
2420 /* check if mod 2 data structure contains at most two nonzero entries per column */
2421 static
2422 SCIP_Bool hasMatrixMax2EntriesPerColumn(
2423  ZEROHALF_MOD2DATA* mod2data /**< considered mod 2 data */
2424  )
2425 {
2426  int r;
2427  int c;
2428  int nentries;
2429 
2430  assert(mod2data != NULL);
2431 
2432  if( mod2data->ncolsind == 0 )
2433  return TRUE; /*FALSE;*/
2434 
2435  if( mod2data->nrowsind <= 2 )
2436  return TRUE;
2437 
2438  for( c = 0; c < mod2data->ncolsind ; ++c )
2439  {
2440  nentries = 0;
2441  for( r = 0; r < mod2data->nrowsind ; ++r )
2442  {
2443  if( BITARRAYBITISSET(mod2data->rows[mod2data->rowsind[r]], mod2data->colsind[c]) ) /*lint !e701*/
2444  {
2445  nentries++;
2446  if( nentries > 2 )
2447  return FALSE;
2448  }
2449  }
2450  }
2451 
2452  return TRUE;
2453 }
2454 #endif
2455 
2456 
2457 
2458 /* stores relevant data into bit arrays (mod 2 data structure) */
2459 static
2461  SCIP* scip, /**< SCIP data structure */
2462  SCIP_SEPADATA* sepadata, /**< separator data */
2463  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
2464  int subproblemindex, /**< index of considered subproblem */
2465  ZEROHALF_MOD2DATA* mod2data /**< data (mod 2) */
2466  )
2467 {
2468  ZEROHALF_SUBLPDATA* problem;
2469  SCIP_COL** colscurrentrow;
2470  SCIP_ROW* row;
2471  SCIP_Real* nonzvalscurrentrow;
2472  SCIP_Real maxslack;
2473  SCIP_Real intscalar;
2474  BITARRAY tempcurrentrow;
2475  int* varboundstoadd;
2476  int nnonzcurrentrow;
2477  int rcolsindex;
2478  int c;
2479  int i;
2480  int j;
2481 #ifdef ZEROHALF__PRINT_STATISTICS
2482  int nirrelevantvarbounds;
2483 #endif
2484  SCIP_Bool tempmod2rhs;
2485  SCIP_Bool ignorerow;
2486  SCIP_Bool fliplhsrhs;
2487  SCIP_Bool isrhsrow;
2488  SCIP_Real* densecoeffscurrentrow;
2489 
2490  assert(scip != NULL);
2491  assert(sepadata != NULL);
2492  assert(lpdata != NULL);
2493  assert(lpdata->rows != NULL);
2494  assert(lpdata->nrows > 0);
2495  assert(lpdata->cols != NULL);
2496  assert(lpdata->ncols > 0);
2497  assert(lpdata->subproblems != NULL);
2498  assert(lpdata->nsubproblems > 0);
2499  assert(lpdata->subproblemsindexofrow != NULL);
2500  assert(lpdata->rrowsindexofleftrow != NULL);
2501  assert(lpdata->rrowsindexofrightrow != NULL);
2502  assert(lpdata->subproblemsindexofcol != NULL);
2503  assert(lpdata->rcolsindexofcol != NULL);
2504  assert(0 <= subproblemindex);
2505  assert(subproblemindex <= lpdata->nsubproblems);
2506  problem = lpdata->subproblems[subproblemindex];
2507  assert(problem != NULL);
2508  assert(problem->rrows != NULL);
2509  assert(problem->nrrows > 0);
2510  assert(problem->rrowsrhs != NULL);
2511  assert(problem->rrowsslack != NULL);
2512  assert(problem->rcols != NULL);
2513  assert(problem->nrcols > 0);
2514  assert(problem->rcolslbslack != NULL);
2515  assert(problem->rcolsubslack != NULL);
2516  assert(mod2data != NULL);
2517 
2518  /* identify varbounds to be added to the matrix */
2519  SCIP_CALL(SCIPallocBufferArray(scip, &varboundstoadd, 2 * problem->nrcols)); /* <0: lb, >0: ub */
2520 
2521  maxslack = sepadata->maxslack;
2522 
2523 #ifdef ZEROHALF__PRINT_STATISTICS
2524  nirrelevantvarbounds = 0;
2525 #endif
2526  mod2data->nvarbounds = 0;
2527  for( c = 0 ; c < problem->nrcols ; c++ )
2528  {
2529  SCIP_Bool lbslackisok;
2530  SCIP_Bool ubslackisok;
2531 
2532  lbslackisok = SCIPisLE(scip, problem->rcolslbslack[c], maxslack);
2533  ubslackisok = SCIPisLE(scip, problem->rcolsubslack[c], maxslack);
2534 
2535  if( lbslackisok && ubslackisok )
2536  {
2537  SCIP_Real lb;
2538  SCIP_Real ub;
2539 
2540  lb = SCIPcolGetLb(lpdata->cols[problem->rcols[c]]);
2541  ub = SCIPcolGetUb(lpdata->cols[problem->rcols[c]]);
2542 
2543  if( ISEVEN(scip, lb) != ISEVEN(scip, ub) )
2544  {
2545  varboundstoadd[mod2data->nvarbounds] = (-1) * (c + 1);
2546  mod2data->nvarbounds++;
2547  varboundstoadd[mod2data->nvarbounds] = c + 1;
2548  mod2data->nvarbounds++;
2549  }
2550  else
2551  {
2552  if( SCIPisLE(scip, problem->rcolslbslack[c], problem->rcolsubslack[c]) )
2553  varboundstoadd[mod2data->nvarbounds] = (-1) * (c + 1);
2554  else
2555  varboundstoadd[mod2data->nvarbounds] = c + 1;
2556  mod2data->nvarbounds++;
2557 #ifdef ZEROHALF__PRINT_STATISTICS
2558  nirrelevantvarbounds++;
2559 #endif
2560  }
2561  }
2562  else
2563  {
2564  if( lbslackisok )
2565  {
2566  varboundstoadd[mod2data->nvarbounds] = (-1) * (c + 1);
2567  mod2data->nvarbounds++;
2568  }
2569 #ifdef ZEROHALF__PRINT_STATISTICS
2570  else
2571  nirrelevantvarbounds++;
2572 #endif
2573  if( ubslackisok )
2574  {
2575  varboundstoadd[mod2data->nvarbounds] = c + 1;
2576  mod2data->nvarbounds++;
2577  }
2578 #ifdef ZEROHALF__PRINT_STATISTICS
2579  else
2580  nirrelevantvarbounds++;
2581 #endif
2582  }
2583  }
2584  mod2data->nrows = problem->nrrows + mod2data->nvarbounds;
2585 
2586  /* allocate temporary memory */
2587  SCIP_CALL( SCIPallocMemoryArray(scip, &(mod2data->rows), mod2data->nrows) );
2588  SCIP_CALL( SCIPallocMemoryArray(scip, &(mod2data->rowaggregations), mod2data->nrows) );
2589  SCIP_CALL( SCIPallocMemoryArray(scip, &(mod2data->rhs), mod2data->nrows) );
2590  SCIP_CALL( SCIPallocMemoryArray(scip, &(mod2data->slacks), mod2data->nrows) );
2591  SCIP_CALL( SCIPallocMemoryArray(scip, &(mod2data->fracsol), problem->nrcols) );
2592  SCIP_CALL( SCIPallocMemoryArray(scip, &(mod2data->rowstatistics), mod2data->nrows) );
2593  SCIP_CALL( SCIPallocMemoryArray(scip, &(mod2data->colstatistics), problem->nrcols) );
2594  SCIP_CALL( SCIPallocMemoryArray(scip, &(mod2data->rowsind), mod2data->nrows) );
2595  SCIP_CALL( SCIPallocMemoryArray(scip, &(mod2data->colsind), problem->nrcols) );
2596  SCIP_CALL( SCIPallocBufferArray(scip, &densecoeffscurrentrow, lpdata->ncols) );
2597 
2598  /* initialize temporary memory */
2599  mod2data->relatedsubproblem = problem;
2600  BMSclearMemoryArray(mod2data->rows, mod2data->nrows); /* NULL = 0x0 */
2601  BMSclearMemoryArray(mod2data->rowaggregations, mod2data->nrows); /* NULL = 0x0 */
2602  BMScopyMemoryArray(mod2data->slacks, problem->rrowsslack, problem->nrrows);
2603  for( c = 0 ; c < problem->nrcols ; ++c)
2604  mod2data->fracsol[c] = SCIPcolGetPrimsol(lpdata->cols[problem->rcols[c]]);
2605  for( c = 0 ; c < problem->nrcols ; c++)
2606  mod2data->colsind[c] = c;
2607  mod2data->nrowsind = 0;
2608  mod2data->ncolsind = problem->nrcols;
2609  mod2data->rowsbitarraysize = (int) GETREQUIREDBITARRAYSIZE(problem->nrcols);
2610  mod2data->rowaggregationsbitarraysize = (int) GETREQUIREDBITARRAYSIZE(problem->nrrows);
2611  tempcurrentrow = NULL;
2612 
2613  /* (i) for all relevant rows */
2614  for( i = 0 ; i < problem->nrrows ; ++i )
2615  {
2616  row = lpdata->rows[problem->rrows[i]];
2617  colscurrentrow = SCIProwGetCols(row);
2618  nonzvalscurrentrow = SCIProwGetVals(row);
2619  nnonzcurrentrow = SCIProwGetNLPNonz(row);
2620  assert(nnonzcurrentrow > 0);
2621  tempcurrentrow = NULL;
2622  fliplhsrhs = FALSE;
2623  ignorerow = FALSE;
2624 
2625  /* check if rrows corresponds to a lhs or rhs row in the LP */
2626  if( lpdata->rrowsindexofleftrow[problem->rrows[i]] == i )
2627  isrhsrow = FALSE;
2628  else
2629  {
2630  assert(lpdata->rrowsindexofrightrow[problem->rrows[i]] == i);
2631  isrhsrow = TRUE;
2632  }
2633  intscalar = isrhsrow ? lpdata->intscalarsrightrow[problem->rrows[i]]
2634  : lpdata->intscalarsleftrow[problem->rrows[i]];
2635 
2636  /* clear dense coeffs array */
2637  BMSclearMemoryArray(densecoeffscurrentrow, lpdata->ncols);
2638 
2639  /* compute dense coeffs array of current row (including intscaling and bound substitutions) */
2640  for( j = 0 ; j < nnonzcurrentrow; ++j )
2641  {
2642  if( SCIPvarGetType(SCIPcolGetVar(colscurrentrow[j])) == SCIP_VARTYPE_CONTINUOUS )
2643  {
2644  SCIP_Bool ispositivecoeff;
2645  SCIP_VAR* bestzvbnd;
2646  SCIP_Real bestbndsol;
2647  SCIP_Real bestbvbnd;
2648  SCIP_Real bestdvbnd;
2649  int bestbndtype;
2650 
2651  /* check sign of coefficient */
2652  if( nonzvalscurrentrow[j] * intscalar > 0.0 )
2653  ispositivecoeff = TRUE;
2654  else
2655  ispositivecoeff = FALSE;
2656 
2657  /* get appropriate bound */
2658  if( isrhsrow == ispositivecoeff )
2659  findClosestLb(scip, lpdata, colscurrentrow[j], &bestbndsol, &bestbndtype, &bestzvbnd, &bestbvbnd, &bestdvbnd );
2660  else
2661  findClosestUb(scip, lpdata, colscurrentrow[j], &bestbndsol, &bestbndtype, &bestzvbnd, &bestbvbnd, &bestdvbnd );
2662 
2663  /* check bound type */
2664  assert(bestbndtype > -2);
2665  if( !USEVARBOUNDS ) /*lint !e774 !e506*/
2666  assert(bestbndtype == -1);
2667 
2668  /* normal lb or ub is used; only rhs would have to be adjusted but this has already been done in getRelevantRows */
2669  if( bestbndtype == -1 )
2670  continue;
2671  assert(USEVARBOUNDS && bestbndtype > -1); /*lint !e774 !e506*/
2672 
2673  /* variable bound is used: update coefficient of non-continuous variable z that is used in substitution */
2674  densecoeffscurrentrow[SCIPcolGetLPPos(SCIPvarGetCol(bestzvbnd))] += (nonzvalscurrentrow[j] * intscalar * bestbvbnd);
2675  }
2676  else
2677  {
2678  densecoeffscurrentrow[SCIPcolGetLPPos(colscurrentrow[j])] += (nonzvalscurrentrow[j] * intscalar);
2679  }
2680  }
2681 
2682  for( j = 0 ; j < lpdata->ncols; ++j )
2683  {
2684  assert(SCIPcolGetLPPos(lpdata->cols[j]) == j);
2685 
2686  if( SCIPisZero(scip, densecoeffscurrentrow[j]) )
2687  continue;
2688 
2689  if( intscalar == 1.0 && !SCIPisIntegral(scip, densecoeffscurrentrow[j]) )
2690  {
2691  ignorerow = TRUE;
2692  break;
2693  }
2694  else
2695  assert(sepadata->scalefraccoeffs);
2696 
2697  /* integral coefficient */
2698  /* coefficient is only integral with respect to tolerances; use really integral values */
2699  if( isrhsrow )
2700  densecoeffscurrentrow[j] = SCIPfloor(scip, densecoeffscurrentrow[j]);
2701  else
2702  densecoeffscurrentrow[j] = SCIPceil(scip, densecoeffscurrentrow[j]);
2703 
2704  if( ISODD(scip, densecoeffscurrentrow[j]) )
2705  {
2706  rcolsindex = lpdata->rcolsindexofcol[j];
2707  fliplhsrhs = XOR((int) fliplhsrhs,
2708  (int) (rcolsindex == LP_SOL_EQUALS_ODD_LB || rcolsindex == LP_SOL_EQUALS_ODD_UB));
2709  if( rcolsindex >= 0 ) /* relevant column? */
2710  {
2711  if( tempcurrentrow == NULL )
2712  {
2713  SCIP_CALL( SCIPallocMemoryArray(scip, &tempcurrentrow, mod2data->rowsbitarraysize) );
2714  BITARRAYCLEAR(tempcurrentrow, mod2data->rowsbitarraysize);
2715  }
2716  assert(rcolsindex < problem->nrcols);
2717  BITARRAYBITSET(tempcurrentrow, rcolsindex); /*lint !e701*/
2718  assert(BITARRAYBITISSET(tempcurrentrow, rcolsindex)); /*lint !e701*/
2719  }
2720  }
2721  }
2722 
2723  /* check if current row should be ignored, continuing with the next one */
2724  if( ignorerow )
2725  {
2726  if( tempcurrentrow != NULL )
2727  {
2728  SCIPfreeMemoryArray(scip, &tempcurrentrow);
2729  tempcurrentrow = NULL;
2730  }
2731  continue;
2732  }
2733 
2734  /* consider rhs */
2735  if( XOR((int) ISODD(scip, problem->rrowsrhs[i]), (int) fliplhsrhs) )
2736  tempmod2rhs = TRUE;
2737  else
2738  tempmod2rhs = FALSE;
2739 
2740  if( tempcurrentrow == NULL && tempmod2rhs )
2741  {
2742  SCIP_CALL( SCIPallocMemoryArray(scip, &tempcurrentrow, mod2data->rowsbitarraysize) );
2743  BITARRAYCLEAR(tempcurrentrow, mod2data->rowsbitarraysize);
2744  }
2745  assert(tempcurrentrow != NULL || !tempmod2rhs);
2746 
2747  /* store temporary data in appropriate (mod 2) data structures */
2748  if( tempcurrentrow != NULL )
2749  {
2750  mod2data->rows[i] = tempcurrentrow;
2751  mod2data->rhs[i] = tempmod2rhs;
2752 
2753  assert(mod2data->rowaggregationsbitarraysize > 0);
2754  SCIP_CALL( SCIPallocMemoryArray(scip, &(mod2data->rowaggregations[i]),
2755  mod2data->rowaggregationsbitarraysize) ); /*lint !e866*/
2756  BITARRAYCLEAR(mod2data->rowaggregations[i], mod2data->rowaggregationsbitarraysize); /*lint !e866*/
2757  BITARRAYBITSET(mod2data->rowaggregations[i], i); /*lint !e701*/
2758 
2759  mod2data->rowsind[mod2data->nrowsind] = i;
2760  mod2data->nrowsind++;
2761 
2762  tempcurrentrow = NULL;
2763  }
2764  else
2765  {
2766  /* zero row */
2767  lpdata->subproblemsindexofrow[problem->rrows[i]] = IRRELEVANT;
2768  if( lpdata->rrowsindexofleftrow[problem->rrows[i]] >= 0 )
2769  lpdata->rrowsindexofleftrow[problem->rrows[i]] = ZERO_ROW;
2770  if( lpdata->rrowsindexofrightrow[problem->rrows[i]] >= 0 )
2771  lpdata->rrowsindexofrightrow[problem->rrows[i]] = ZERO_ROW;
2772  }
2773  }
2774 
2775 
2776  /* (ii) for all relevant varbounds */
2777  i = problem->nrrows;
2778  for( j = 0 ; j < mod2data->nvarbounds ; ++j)
2779  {
2780  SCIP_Real bound;
2781 
2782  if( varboundstoadd[j] < 0 )
2783  c = (-1) * varboundstoadd[j] - 1;
2784  else
2785  c = varboundstoadd[j] - 1;
2786 
2787  assert(mod2data->rowsbitarraysize > 0);
2788  SCIP_CALL(SCIPallocMemoryArray(scip, &(mod2data->rows[i]), mod2data->rowsbitarraysize)); /*lint !e866*/
2789  BITARRAYCLEAR(mod2data->rows[i], mod2data->rowsbitarraysize); /*lint !e866*/
2790  BITARRAYBITSET(mod2data->rows[i], c); /*lint !e701*/
2791  assert(BITARRAYBITISSET(mod2data->rows[i], c)); /*lint !e701*/
2792 
2793  SCIP_CALL(SCIPallocMemoryArray(scip, &(mod2data->rowaggregations[i]),
2794  mod2data->rowaggregationsbitarraysize)); /*lint !e866*/
2795  BITARRAYCLEAR(mod2data->rowaggregations[i], mod2data->rowaggregationsbitarraysize); /*lint !e866*/
2796 
2797  if( varboundstoadd[j] < 0 )
2798  {
2799  bound = SCIPcolGetLb(lpdata->cols[problem->rcols[c]]);
2800  mod2data->rhs[i] = ISODD(scip, bound);
2801  mod2data->slacks[i] = problem->rcolslbslack[c];
2802  }
2803  else
2804  {
2805  bound = SCIPcolGetUb(lpdata->cols[problem->rcols[c]]);
2806  mod2data->rhs[i] = ISODD(scip, bound);
2807  mod2data->slacks[i] = problem->rcolsubslack[c];
2808  }
2809  if( SCIPisFeasZero(scip, mod2data->slacks[i]) )
2810  mod2data->slacks[i] = 0.0;
2811 
2812  mod2data->rowsind[mod2data->nrowsind] = i;
2813  mod2data->nrowsind++;
2814  i++;
2815  }
2816 
2817  /* free temporary memory */
2818  SCIPfreeBufferArray(scip, &densecoeffscurrentrow);
2819  SCIPfreeBufferArray(scip, &varboundstoadd);
2820 
2821 #ifdef ZEROHALF__PRINT_STATISTICS
2822  ZEROHALFstatisticsMessage("\n");
2823  ZEROHALFstatisticsMessage(" | ------------------------------- subproblem ------------------------------- | ------------------------------\n");
2824  ZEROHALFstatisticsMessage(" | nrrows | nrcols | nvarbnds | ndlvbnds | max2/row | max2/col | A^T ept | \n");
2825  ZEROHALFstatisticsMessage("%15s | %8d | %8d | %8d | %8d | %8s | %8s | %8s |\n",
2826  "SUBPROBLEMDATA", problem->nrrows, problem->nrcols, mod2data->nvarbounds, nirrelevantvarbounds,
2827  hasMatrixMax2EntriesPerRow(mod2data) ? "yes" : "no", hasMatrixMax2EntriesPerColumn(mod2data) ? "yes" : "no", "n/a");
2828 #endif
2829 
2830  return SCIP_OKAY;
2831 }
2832 
2833 
2834 /* --------------------------------------------------------------------------------------------------------------------
2835  * local methods: cut generation
2836  * -------------------------------------------------------------------------------------------------------------------- */
2837 
2838 
2839 /** stores nonzero elements of dense coefficient vector as sparse vector, and calculates activity and norm */
2840 static
2842  SCIP* scip, /**< SCIP data structure */
2843  int nvars, /**< number of problem variables */
2844  SCIP_VAR** vars, /**< problem variables */
2845  SCIP_Real* cutcoefs, /**< dense coefficient vector */
2846  SCIP_Real* varsolvals, /**< dense variable LP solution vector */
2847  char normtype, /**< type of norm to use for efficacy norm calculation */
2848 
2849  SCIP_VAR** cutvars, /**< array to store variables of sparse cut vector */
2850  SCIP_Real* cutvals, /**< array to store coefficients of sparse cut vector */
2851  int* cutlen, /**< pointer to store number of nonzero entries in cut */
2852  SCIP_Real* cutact, /**< pointer to store activity of cut */
2853  SCIP_Real* cutnorm /**< pointer to store norm of cut vector */
2854  )
2855 {
2856  SCIP_Real val;
2857  SCIP_Real absval;
2858  SCIP_Real cutsqrnorm;
2859  SCIP_Real act;
2860  SCIP_Real norm;
2861  int len;
2862  int v;
2863 
2864  assert(nvars == 0 || cutcoefs != NULL);
2865  assert(nvars == 0 || varsolvals != NULL);
2866  assert(cutvars != NULL);
2867  assert(cutvals != NULL);
2868  assert(cutlen != NULL);
2869  assert(cutact != NULL);
2870  assert(cutnorm != NULL);
2871 
2872  len = 0;
2873  act = 0.0;
2874  norm = 0.0;
2875  switch(normtype)
2876  {
2877  case 'e':
2878  cutsqrnorm = 0.0;
2879  for( v = 0; v < nvars; ++v)
2880  {
2881  val = cutcoefs[v];
2882  if( !SCIPisZero(scip, val) )
2883  {
2884  act += val * varsolvals[v];
2885  cutsqrnorm += SQR(val);
2886  cutvars[len] = vars[v];
2887  cutvals[len] = val;
2888  len++;
2889  }
2890  }
2891  norm = SQRT(cutsqrnorm);
2892  break;
2893  case 'm':
2894  for( v = 0; v < nvars; ++v)
2895  {
2896  val = cutcoefs[v];
2897  if( !SCIPisZero(scip, val) )
2898  {
2899  act += val * varsolvals[v];
2900  absval = REALABS(val);
2901  norm = MAX(norm, absval);
2902  cutvars[len] = vars[v];
2903  cutvals[len] = val;
2904  len++;
2905  }
2906  }
2907  break;
2908  case 's':
2909  for( v = 0; v < nvars; ++v)
2910  {
2911  val = cutcoefs[v];
2912  if( !SCIPisZero(scip, val) )
2913  {
2914  act += val * varsolvals[v];
2915  norm += REALABS(val);
2916  cutvars[len] = vars[v];
2917  cutvals[len] = val;
2918  len++;
2919  }
2920  }
2921  break;
2922  case 'd':
2923  for( v = 0; v < nvars; ++v)
2924  {
2925  val = cutcoefs[v];
2926  if( !SCIPisZero(scip, val) )
2927  {
2928  act += val * varsolvals[v];
2929  norm = 1.0;
2930  cutvars[len] = vars[v];
2931  cutvals[len] = val;
2932  len++;
2933  }
2934  }
2935  break;
2936  default:
2937  SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", normtype);
2938  return SCIP_INVALIDDATA;
2939  }
2940 
2941  *cutlen = len;
2942  *cutact = act;
2943  *cutnorm = norm;
2944 
2945  return SCIP_OKAY;
2946 }
2947 
2948 
2949 
2950 /** adds a separated zerohalf cut to SCIP if it was successfully created and is efficacious */
2951 static
2953  SCIP* scip, /**< SCIP data structure */
2954  SCIP_SEPADATA* sepadata, /**< separator data */
2955  ZEROHALF_CUTDATA* cutdata, /**< separated zerohalf cut */
2956  int* nsepacuts, /**< pointer to store number of separated (efficacious) zerohalf cuts */
2957  SCIP_RESULT* result /**< pointer to store return code */
2958  )
2959 {
2960  assert(scip != NULL);
2961  assert(sepadata != NULL);
2962  assert(cutdata != NULL);
2963  assert(result != NULL);
2964 
2965  /* check if SCIPcalcMIR was not successful */
2966  if( !cutdata->isfeasviolated || !cutdata->success )
2967  return SCIP_OKAY;
2968 
2969  /* check if norm was not calculated correctly */
2970  if( !SCIPisPositive(scip, cutdata->norm) )
2971  {
2972  SCIPerrorMessage("Zerohalf cut norm is NOT positive!\n");
2973  return SCIP_ERROR;
2974  }
2975 
2976  /* check if cut is not efficacious */
2977  if( !sepadata->forcecutstolp && !sepadata->forcecutstosepastore
2978  && !SCIPisEfficacious(scip, cutdata->efficacy) )
2979  {
2980  return SCIP_OKAY;
2981  }
2982 
2983  /* add cut (if no cutpool is used otherwise add it at the end of the separation main method)*/
2984  if( !sepadata->usezhcutpool )
2985  {
2986  SCIP_Bool cutoff;
2987  SCIP_CALL(SCIPaddCut(scip, NULL, cutdata->cut, sepadata->forcecutstolp, &cutoff) );
2988  if ( cutoff )
2989  {
2990  *result = SCIP_CUTOFF;
2991  return SCIP_OKAY;
2992  }
2993  if( !cutdata->islocal )
2994  {
2995  SCIP_CALL(SCIPaddPoolCut(scip, cutdata->cut));
2996  }
2997  }
2998 
2999  cutdata->addedtolp = TRUE;
3000  (*nsepacuts)++;
3001 
3002  *result = SCIP_SEPARATED;
3003 
3004  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, cutdata->cut, NULL) ) );
3005 
3006  return SCIP_OKAY;
3007 }
3008 
3009 
3010 /* --------------------------------------------------------------------------------------------------------------------
3011  * local methods: preprocessing
3012  * -------------------------------------------------------------------------------------------------------------------- */
3013 
3014 
3015 
3016 /** marks a row as "removed" and stores why it has been removed using a flag */
3017 static
3019  ZEROHALF_MOD2DATA* mod2data, /**< considered mod 2 data */
3020  int r, /**< mod2data->rows index of row that shall be removed */
3021  int flag /**< flag (cause of removal) */
3022  )
3023 {
3024  assert(mod2data != NULL);
3025  assert(mod2data->relatedsubproblem != NULL);
3026  assert(mod2data->nrowsind > 0);
3027  assert(r >= 0);
3028  assert(r < mod2data->nrowsind);
3029 
3030  mod2data->rowstatistics[mod2data->rowsind[r]] = flag;
3031 }
3032 
3033 
3034 
3035 /** marks a row as "removed" and stores why it has been removed using a flag. in addition it clears this column's mod 2 data */
3036 static
3038  ZEROHALF_MOD2DATA* mod2data, /**< considered mod 2 data */
3039  int c, /**< mod2data->relatedsubproblem->rcols index of column that shall be removed */
3040  int flag /**< flag (cause of removal) */
3041  )
3042 {
3043  int i;
3044  int rowsbind;
3045  BITARRAYBITMASKTYPE rowsbmask;
3046 
3047  assert(mod2data != NULL);
3048  assert(mod2data->relatedsubproblem != NULL);
3049  assert(mod2data->ncolsind > 0);
3050  assert(c >= 0);
3051  assert(c < mod2data->ncolsind);
3052 
3053 
3054  /* mark col */
3055  mod2data->colstatistics[mod2data->colsind[c]] = flag;
3056 
3057  /* clear col */
3058  rowsbind = (int) GETBITARRAYINDEX(mod2data->colsind[c]);
3059  rowsbmask = ~GETBITARRAYMASK(mod2data->colsind[c]); /*lint !e701*/
3060  for( i = 0 ; i < mod2data->nrowsind ; ++i)
3061  mod2data->rows[mod2data->rowsind[i]][rowsbind] &= rowsbmask;
3062 }
3063 
3064 
3065 
3066 
3067 /** given a subset of mod 2 rows it returns a {0,1/2} weight vector used to
3068  combine the (original) LP rows. Note: original rows a stored as lhs <= a^Tx
3069  <= rhs by SCIP. Positive weights refer to "right half-rows" a^Tx <= rhs and
3070  negative weights to "left half-rows" -a^Tx <= -lhs */
3071 static
3073  SCIP* scip, /**< SCIP data structure */
3074  SCIP_SEPADATA* sepadata, /**< separator data */
3075  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
3076  ZEROHALF_MOD2DATA* mod2data, /**< considered mod 2 data */
3077  BITARRAY rrowsincut, /**< subset of selected mod2data->rows */
3078  SCIP_Real** weights, /**< pointer to store the {-0.5,0,0.5} weights vector */
3079  int* nrowsincut /**< pointer to store the number of combined original LP rows */
3080  )
3081 { /*lint --e{438}*/
3082 
3083  ZEROHALF_SUBLPDATA* problem;
3084  int lppos;
3085  int i;
3086  int nnonz;
3087 
3088  assert(scip != NULL);
3089  assert(lpdata != NULL);
3090  assert(lpdata->nrows > 0);
3091  assert(mod2data != NULL);
3092  assert(mod2data->relatedsubproblem != NULL);
3093  assert(mod2data->nrowsind > 0);
3094  assert(rrowsincut != NULL);
3095  assert(weights != NULL);
3096  assert(*weights == NULL);
3097  assert(nrowsincut != NULL);
3098 
3099 
3100  /* allocate temporary memory */
3101  SCIP_CALL(SCIPallocMemoryArray(scip, weights, lpdata->nrows));
3102 
3103  /* initialize */
3104  BMSclearMemoryArray(*weights, lpdata->nrows);
3105  problem = mod2data->relatedsubproblem;
3106 
3107  /* determine row weights */
3108  *nrowsincut = 0;
3109  nnonz = 0;
3110  for( i = 0 ; i < problem->nrrows ; ++i)
3111  {
3112  lppos = problem->rrows[i];
3113  assert(0 <= lppos && lppos <= lpdata->nrows);
3114  if( BITARRAYBITISSET(rrowsincut, i) ) /*lint !e701*/
3115  {
3116  assert(lpdata->rrowsindexofleftrow[lppos] == i || lpdata->rrowsindexofrightrow[lppos] == i);
3117 
3118  SCIPdebugMessage(" %1s0.5 (int scaling: %16.4f / %16.4f) row[%d] %s\n",
3119  lpdata->rrowsindexofleftrow[lppos] == i ? "-" : "+",
3120  lpdata->intscalarsleftrow[lppos], lpdata->intscalarsrightrow[lppos],
3121  lppos, SCIProwGetName(lpdata->rows[lppos]));
3122 
3123  if( lpdata->rrowsindexofleftrow[lppos] == i )
3124  (*weights)[lppos] = lpdata->intscalarsleftrow[lppos] * (-0.5);
3125  else
3126  (*weights)[lppos] = lpdata->intscalarsrightrow[lppos] * 0.5;
3127 
3128  nnonz += SCIProwGetNLPNonz(lpdata->rows[lppos]);
3129  (*nrowsincut)++;
3130  }
3131  }
3132 
3133  /* check if row aggregation might be too dense */
3134  if( nnonz >= 5 * sepadata->maxnnonz )
3135  {
3136  SCIPfreeMemoryArray(scip, weights);
3137  weights = NULL;/*lint !e438*/
3138  }
3139 
3140  return SCIP_OKAY;
3141 }
3142 
3143 
3144 /** creates a zerohalf cut from a given weightvector */
3145 static
3147  SCIP* scip, /**< SCIP data structure */
3148  SCIP_SEPA* sepa, /**< separator */
3149  SCIP_SEPADATA* sepadata, /**< separator data */
3150  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
3151  SCIP_Real* weights, /**< weightvector */
3152  char normtype, /**< SCIP normtype */
3153  int nzerohalfcuts, /**< number of zerohalf cuts (used for naming the cut) */
3154  SCIP_Real** varsolvals, /**< pointer to array of LP solution values of variables */
3155  ZEROHALF_CUTDATA* cutdata, /**< pointer to data structure used for storing the cut */
3156  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
3157  )
3158 {
3159  SCIP_Real* cutcoefs;
3160  SCIP_VAR** cutvars;
3161  SCIP_Real* cutvals;
3162  char cutname[SCIP_MAXSTRLEN];
3163 
3164  assert(scip != NULL);
3165  assert(lpdata != NULL);
3166  assert(lpdata->nvars > 0);
3167  assert(weights != NULL);
3168  assert(varsolvals != NULL);
3169  assert(cutdata != NULL);
3170  assert(cutdata->relatedsubproblem != NULL);
3171  assert(cutoff != NULL);
3172 
3173  *cutoff = FALSE;
3174 
3175  /* note: cutdata->relatedmod2data can be NULL if cut was determined
3176  * before mod 2 data structures were created */
3177 
3178  /* allocate temporary memory */
3179  SCIP_CALL(SCIPallocBufferArray(scip, &cutcoefs, lpdata->nvars));
3180 
3181  /* calculate MIR */
3182  cutdata->success = FALSE;
3183  if( sepadata->maxtestdelta == 0 )
3184  {
3185  /* generate cut for delta = 1.0 */
3188  weights, NULL, 1.0, NULL, NULL, cutcoefs, &(cutdata->rhs), &(cutdata->activity),
3189  &(cutdata->success), &(cutdata->islocal), &(cutdata->cutrank)) );
3190 
3191  if( sepadata->trynegscaling )
3192  {
3195  weights, NULL, -1.0, NULL, NULL, cutcoefs, &(cutdata->rhs), &(cutdata->activity),
3196  &(cutdata->success), &(cutdata->islocal), &(cutdata->cutrank)) );
3197  }
3198  }
3199  else
3200  {
3201  int ncuts;
3202  SCIP_Real bestdelta;
3203  SCIP_Bool bestdeltavalid;
3204 
3205  ncuts = 0;
3206 
3207  if( *varsolvals == NULL )
3208  {
3209  /* get the solution values for all active variables */
3210  SCIP_CALL(SCIPallocMemoryArray(scip, varsolvals, lpdata->nvars));
3211  SCIP_CALL( SCIPgetSolVals(scip, NULL, lpdata->nvars, lpdata->vars, *varsolvals) );
3212 
3213 #ifndef NDEBUG
3214  /* because later when calling SCIPcutGenerationHeuristicCmir() varsolvals are used, it is needed that the
3215  * corresponding variables have the same order here and there, so we do the same checking and test that all
3216  * variables are ordered by their problem index
3217  */
3218  {
3219  int i;
3220  for(i = lpdata->nvars - 1; i >= 0; --i )
3221  assert(i == SCIPvarGetProbindex(lpdata->vars[i]));
3222  }
3223 #endif
3224  }
3225  assert(*varsolvals != NULL);
3226 
3227  /* find best value of delta */
3228  SCIP_CALL( SCIPcutGenerationHeuristicCmir(scip, sepa, NULL, *varsolvals, sepadata->maxtestdelta, weights, BOUNDSWITCH,
3230  sepadata->trynegscaling, TRUE, "zerohalf", cutoff, &ncuts, &bestdelta, &bestdeltavalid) );
3231  assert(ncuts == 0);
3232 
3233  /* best delta corresponds to an efficient cut */
3234  if( !(*cutoff) && bestdeltavalid )
3235  {
3238  weights, NULL, bestdelta, NULL, NULL, cutcoefs, &(cutdata->rhs), &(cutdata->activity),
3239  &(cutdata->success), &(cutdata->islocal), &(cutdata->cutrank)) );
3240  }
3241  }
3242  assert(ALLOWLOCAL || !cutdata->islocal);
3243 
3244  cutdata->violation = cutdata->activity - cutdata->rhs;
3245 
3246  /* if successful, convert dense cut into sparse row */
3247  if( !(*cutoff) && cutdata->success )
3248  {
3249  cutdata->isfeasviolated = SCIPisFeasGT(scip, cutdata->activity, cutdata->rhs);
3250  SCIPdebugMessage("Cut is %sfeasviolated: (act: %e, rhs: %e, viol: %e)\n",
3251  cutdata->isfeasviolated ? "" : "not ", cutdata->activity, cutdata->rhs, cutdata->violation);
3252 
3253  if( cutdata->isfeasviolated )
3254  {
3255  if( *varsolvals == NULL )
3256  {
3257  /* get the solution values for all active variables */
3258  SCIP_CALL(SCIPallocMemoryArray(scip, varsolvals, lpdata->nvars));
3259  SCIP_CALL( SCIPgetSolVals(scip, NULL, lpdata->nvars, lpdata->vars, *varsolvals) );
3260  }
3261  assert(*varsolvals != NULL);
3262 
3263  /* get temporary memory for storing the cut as sparse row */
3264  SCIP_CALL(SCIPallocBufferArray(scip, &cutvars, lpdata->nvars));
3265  SCIP_CALL(SCIPallocBufferArray(scip, &cutvals, lpdata->nvars));
3266 
3267  /* store the cut as sparse row, calculate activity and norm of cut */
3268  SCIP_CALL(storeCutInArrays(scip, lpdata->nvars, lpdata->vars,
3269  cutcoefs, *varsolvals, normtype, cutvars, cutvals,
3270  &(cutdata->nnonz), &(cutdata->activity), &(cutdata->norm)));
3271 
3272  /* check cut norm and efficacy */
3273  if( SCIPisPositive(scip, cutdata->norm) )
3274  {
3275  cutdata->efficacy = (cutdata->activity - cutdata->rhs) / cutdata->norm;
3276 
3277  if( sepadata->forcecutstolp || sepadata->forcecutstosepastore
3278  || (SCIPisEfficacious(scip, cutdata->efficacy) && cutdata->nnonz < sepadata->maxnnonz) )
3279  {
3280  /* create cut */
3281  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN,"zerohalf%d_%d", SCIPgetNLPs(scip), nzerohalfcuts);
3282  SCIP_CALL(SCIPcreateEmptyRowSepa(scip, &(cutdata->cut), sepa, cutname, -SCIPinfinity(scip), cutdata->rhs,
3283  cutdata->islocal, FALSE, sepadata->dynamiccuts));
3284  SCIP_CALL(SCIPaddVarsToRow(scip, cutdata->cut, cutdata->nnonz, cutvars, cutvals));
3285  /* set cut rank */
3286  SCIProwChgRank(cutdata->cut, cutdata->cutrank);
3287  }
3288  else
3289  cutdata->success = FALSE;
3290  }
3291  else
3292  cutdata->success = FALSE;
3293 
3294  /* free temporary memory */
3295  SCIPfreeBufferArray(scip, &cutvals);
3296  SCIPfreeBufferArray(scip, &cutvars);
3297  }
3298  else
3299  cutdata->success = FALSE;
3300  }
3301 
3302  /* free temporary memory */
3303  SCIPfreeBufferArray(scip, &cutcoefs);
3304 
3305  return SCIP_OKAY;
3306 }
3307 
3308 
3309 /** searches for trivial zerohalf cuts, given as (0,..0) row with rhs=1 and slack <= maxslack */
3310 static
3312  SCIP* scip, /**< SCIP data structure */
3313  SCIP_SEPA* sepa, /**< separator */
3314  SCIP_SEPADATA* sepadata, /**< separator data */
3315  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
3316  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
3317  int firstrowsind, /**< first mod2data->rows index to be considered */
3318  int lastrowsind, /**< last mod2data->rows index to be considered */
3319  char normtype, /**< SCIP normtype */
3320  int maxsepacuts, /**< maximal number of zerohalf cuts separated per separation round */
3321  int maxcuts, /**< maximal number of zerohalf cuts found per separation round (incl. ineff. cuts) */
3322  int* nsepacuts, /**< pointer to store current number of separated zerohalf cuts */
3323  int* nzerohalfcuts, /**< pointer to store current number of found zerohalf cuts */
3324  ZEROHALF_CUTDATA** zerohalfcuts, /**< pointer to store a found zerohalf cut */
3325  SCIP_Real** varsolvals, /**< dense variable LP solution vector */
3326  CUTSEPARATEDBY cutseparatedby, /**< flag */
3327  SCIP_RESULT* result /**< pointer to SCIP result value of separation */
3328  )
3329 {
3330  int r;
3331  int r2;
3332  int nrowsremoved;
3333  SCIP_Real maxslack;
3334  BITARRAY zerorow;
3335  SCIP_Bool* removerow;
3336  SCIP_Real* weights;
3337  int nrowsincut;
3338  SCIP_Bool cutoff = FALSE;
3339 
3340  assert(scip != NULL);
3341  assert(lpdata != NULL);
3342  assert(mod2data != NULL);
3343  assert(mod2data->relatedsubproblem != NULL);
3344  assert(firstrowsind >= 0);
3345  assert(lastrowsind <= mod2data->nrowsind);
3346  assert(nsepacuts != NULL);
3347  assert(nzerohalfcuts != NULL);
3348  assert(zerohalfcuts != NULL);
3349  assert(*nsepacuts <= *nzerohalfcuts);
3350  assert(varsolvals != NULL);
3351  assert(result != NULL);
3352 
3353 
3354  /* check if matrix or colind range is empty */
3355  if( mod2data->nrowsind == 0 || lastrowsind - firstrowsind <= 0 )
3356  return SCIP_OKAY;
3357 
3358 
3359  /* allocate temporary memory */
3360  SCIP_CALL(SCIPallocBufferArray(scip, &removerow, lastrowsind - firstrowsind));
3361  SCIP_CALL(SCIPallocBufferArray(scip, &zerorow, mod2data->rowsbitarraysize));
3362 
3363  /* initialize */
3364  BMSclearMemoryArray(zerorow, mod2data->rowsbitarraysize);
3365  BMSclearMemoryArray(removerow, lastrowsind - firstrowsind);
3366  maxslack = sepadata->maxslack;
3367  nrowsremoved = 0;
3368 
3369 
3370  /* check all rows */
3371  for( r = 0 ; r < lastrowsind - firstrowsind && *nsepacuts < maxsepacuts && *nzerohalfcuts < maxcuts; ++r )
3372  {
3373  if( mod2data->rhs[mod2data->rowsind[firstrowsind + r]] == TRUE )
3374  {
3375  if( SCIPisLE(scip, mod2data->slacks[mod2data->rowsind[firstrowsind + r]], maxslack ))
3376  {
3377  if( BITARRAYSAREEQUAL(mod2data->rows[mod2data->rowsind[firstrowsind + r]],
3378  zerorow, mod2data->rowsbitarraysize) ) /* check if row is (0 ... 0 , 1) */
3379  {
3380  /* a violated zerohalf cut has been found */
3381  weights = NULL;
3382  SCIP_CALL(getZerohalfWeightvectorFromSelectedRowsBitarray(scip, sepadata, lpdata, mod2data,
3383  mod2data->rowaggregations[mod2data->rowsind[firstrowsind + r]], &weights, &nrowsincut));
3384  if( weights == NULL )
3385  {
3386  continue;
3387  }
3388  assert(nrowsincut > 0);
3389 
3390  /* create zerohalf cut */
3391  SCIP_CALL(ZerohalfCutDataCreate(scip, &(zerohalfcuts[*nzerohalfcuts]),
3392  mod2data->relatedsubproblem, mod2data, 1, nrowsincut, cutseparatedby));
3394  lpdata, weights, normtype, *nzerohalfcuts, varsolvals, zerohalfcuts[*nzerohalfcuts], &cutoff));
3395 
3396  if ( cutoff )
3397  *result = SCIP_CUTOFF;
3398  else
3399  {
3400  /* add cut */
3401  SCIP_CALL( addZerohalfCutToLP(scip, sepadata, zerohalfcuts[*nzerohalfcuts], nsepacuts, result) );
3402  (*nzerohalfcuts)++;
3403  }
3404 
3405  /* free temporary memory */
3406  SCIPfreeMemoryArray(scip, &weights);
3407 
3408  if ( cutoff )
3409  break;
3410 
3411  removerow[r] = TRUE;
3412  nrowsremoved++;
3413  }
3414  }
3415  }
3416  }
3417 
3418  /* update mod2data->rowsind if necessary */
3419  if( ! cutoff && nrowsremoved > 0 )
3420  {
3421  r2 = firstrowsind;
3422  for( r = firstrowsind ; r < mod2data->nrowsind && r2 < mod2data->nrowsind; ++r)
3423  {
3424  if( r < lastrowsind - firstrowsind )
3425  while( removerow[r2] && r2 < mod2data->nrowsind )
3426  r2++;
3427  if( r < r2 && r2 < mod2data->nrowsind )
3428  mod2data->rowsind[r] = mod2data->rowsind[r2];
3429  r2++;
3430  }
3431  mod2data->nrowsind -= nrowsremoved;
3432  }
3433 
3434 
3435  /* free temporary memory */
3436  SCIPfreeBufferArray(scip, &zerorow);
3437  SCIPfreeBufferArray(scip, &removerow);
3438 
3439  return SCIP_OKAY;
3440 }
3441 
3442 
3443 /** applies some row reductions */
3444 static
3446  SCIP* scip, /**< SCIP data structure */
3447  SCIP_SEPADATA* sepadata, /**< separator data */
3448  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
3449  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
3450  int firstrowsind, /**< first mod2data->rows index to be considered */
3451  int lastrowsind, /**< last mod2data->rows index to be considered */
3452  SCIP_Bool removezerorows, /**< should zero rows be removed? */
3453  SCIP_Bool removelargeslackrows, /**< should rows with slack > maxslack be removed? */
3454  SCIP_Bool removeidenticalrows /**< should identical rows be removed? */
3455  )
3456 {
3457  int r1;
3458  int r2;
3459  SCIP_Bool* rowisprocessed;
3460  SCIP_Bool* removerow;
3461  int nzerorowsremoved;
3462  int nlargeslackrowsremoved;
3463  int nidenticalrowsremoved;
3464  SCIP_Real maxslack;
3465  BITARRAY zerorow;
3466 
3467  assert(scip != NULL);
3468  assert(lpdata != NULL);
3469  assert(mod2data != NULL);
3470  assert(mod2data->relatedsubproblem != NULL);
3471  assert(firstrowsind >= 0);
3472  assert(lastrowsind <= mod2data->nrowsind);
3473 
3474 
3475  /* check if matrix or colind range is empty */
3476  if( mod2data->nrowsind == 0 || lastrowsind - firstrowsind <= 0 )
3477  return SCIP_OKAY;
3478 
3479  /* allocate temporary memory */
3480  SCIP_CALL(SCIPallocBufferArray(scip, &rowisprocessed, lastrowsind - firstrowsind));
3481  SCIP_CALL(SCIPallocBufferArray(scip, &removerow, lastrowsind - firstrowsind));
3482  zerorow = NULL;
3483  if( removezerorows )
3484  {
3485  SCIP_CALL(SCIPallocBufferArray(scip, &zerorow, mod2data->rowsbitarraysize));
3486  }
3487  /* initialize */
3488  BMSclearMemoryArray(rowisprocessed, lastrowsind - firstrowsind);
3489  BMSclearMemoryArray(removerow, lastrowsind - firstrowsind);
3490  if( removezerorows )
3491  {
3492  BMSclearMemoryArray(zerorow, mod2data->rowsbitarraysize);
3493  }
3494  maxslack = sepadata->maxslack;
3495  nzerorowsremoved = 0;
3496  nlargeslackrowsremoved = 0;
3497  nidenticalrowsremoved = 0;
3498 
3499  /* check all pairs of rows */
3500  for( r1 = 0 ; r1 < lastrowsind - firstrowsind ; ++r1)
3501  if( !rowisprocessed[r1] )
3502  {
3503  rowisprocessed[r1] = TRUE;
3504 
3505  if( removezerorows && !removerow[r1] )
3506  if( mod2data->rhs[mod2data->rowsind[firstrowsind + r1]] == FALSE )
3507  {
3508  assert(zerorow != NULL);
3509  if( BITARRAYSAREEQUAL(mod2data->rows[mod2data->rowsind[firstrowsind + r1]],
3510  zerorow, mod2data->rowsbitarraysize) )
3511  {
3512  markRowAsRemoved(mod2data, firstrowsind + r1, ZERO_ROW);
3513  removerow[r1] = TRUE;
3514  nzerorowsremoved++;
3515  }
3516  }
3517  if( removelargeslackrows && !removerow[r1] )
3518  if( SCIPisGT(scip, mod2data->slacks[mod2data->rowsind[firstrowsind + r1]], maxslack) )
3519  {
3520  markRowAsRemoved(mod2data, firstrowsind + r1, SLACK_GREATER_THAN_MAXSLACK);
3521  removerow[r1] = TRUE;
3522  nlargeslackrowsremoved++;
3523  }
3524 
3525  if( removeidenticalrows && !removerow[r1] )
3526  for( r2 = r1 + 1 ; r2 < lastrowsind - firstrowsind ; ++r2)
3527  if( !rowisprocessed[r2] )
3528  if( mod2data->rhs[mod2data->rowsind[firstrowsind + r1]]
3529  == mod2data->rhs[mod2data->rowsind[firstrowsind + r2]] )
3530  if( BITARRAYSAREEQUAL(mod2data->rows[mod2data->rowsind[firstrowsind + r1]],
3531  mod2data->rows[mod2data->rowsind[firstrowsind + r2]], mod2data->rowsbitarraysize) )
3532  {
3533  if( SCIPisLT(scip, mod2data->slacks[mod2data->rowsind[firstrowsind + r1]],
3534  mod2data->slacks[mod2data->rowsind[firstrowsind + r2]]) )
3535  {
3536  markRowAsRemoved(mod2data, firstrowsind + r2, IDENT_TO_ROW_WITH_SMALLER_SLACK);
3537  removerow[r2] = TRUE;
3538  nidenticalrowsremoved++;
3539  rowisprocessed[r2] = TRUE;
3540  }
3541  else
3542  {
3543  markRowAsRemoved(mod2data, firstrowsind + r1, IDENT_TO_ROW_WITH_SMALLER_SLACK);
3544  removerow[r1] = TRUE;
3545  nidenticalrowsremoved++;
3546  break;
3547  }
3548  }
3549  }
3550 
3551  /* update mod2data->rowsind if necessary */
3552  if( nzerorowsremoved + nlargeslackrowsremoved + nidenticalrowsremoved > 0 )
3553  {
3554  r2 = firstrowsind;
3555  for( r1 = firstrowsind ; r1 < mod2data->nrowsind && r2 < mod2data->nrowsind; ++r1)
3556  {
3557  if( r1 < lastrowsind - firstrowsind )
3558  while( removerow[r2] && r2 < mod2data->nrowsind )
3559  r2++;
3560  if( r1 < r2 && r2 < mod2data->nrowsind )
3561  mod2data->rowsind[r1] = mod2data->rowsind[r2];
3562  r2++;
3563  }
3564  mod2data->nrowsind -= (nzerorowsremoved + nlargeslackrowsremoved + nidenticalrowsremoved);
3565  }
3566 
3567 
3568  /* free temporary memory */
3569  if( removezerorows && zerorow != NULL )
3570  {
3571  SCIPfreeBufferArray(scip, &zerorow);
3572  }
3573  SCIPfreeBufferArray(scip, &removerow);
3574  SCIPfreeBufferArray(scip, &rowisprocessed);
3575 
3576  return SCIP_OKAY;
3577 }
3578 
3579 
3580 /** applies some column reductions */
3581 static
3583  SCIP* scip, /**< SCIP data structure */
3584  SCIP_SEPADATA* sepadata, /**< separator data */
3585  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
3586  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
3587  int firstcolsind, /**< first mod2data->rows index to be considered */
3588  int lastcolsind, /**< last mod2data->rows index to be considered */
3589  SCIP_Bool removezerocols, /**< should zero columns be removed? */
3590  SCIP_Bool removecolsingletons,/**< should column singletons be removed? */
3591  SCIP_Bool checkresultingrows /**< should rows whose slack becomes larger than maxslack be removed? */
3592  )
3593 {
3594  SCIP_Real maxslack;
3595  int maxnnonzentries;
3596  int nzerocolsremoved;
3597  int ncolsingletonsremoved;
3598  int nunprocessedcols;
3599  int nconsideredcols;
3600  int nnonzentries;
3601  SCIP_Bool* removecol;
3602  SCIP_Bool* colisprocessed;
3603  int rowofcolsingleton;
3604  int rowsbind;
3605  BITARRAYBITMASKTYPE rowsbmask;
3606  int r;
3607  int c;
3608  int j;
3609 
3610  assert(scip != NULL);
3611  assert(sepadata != NULL);
3612  assert(lpdata != NULL);
3613  assert(mod2data != NULL);
3614  assert(mod2data->relatedsubproblem != NULL);
3615  assert(firstcolsind >= 0);
3616  assert(lastcolsind <= mod2data->ncolsind);
3617  assert(removezerocols || removecolsingletons);
3618 
3619 
3620  nconsideredcols = lastcolsind - firstcolsind;
3621 
3622  /* check if matrix or colind range is empty */
3623  if( mod2data->ncolsind == 0 || mod2data->nrowsind == 0 || nconsideredcols <= 0 )
3624  return SCIP_OKAY;
3625 
3626 
3627  /* allocate temporary memory */
3628  SCIP_CALL(SCIPallocBufferArray(scip, &colisprocessed, nconsideredcols));
3629  SCIP_CALL(SCIPallocBufferArray(scip, &removecol, nconsideredcols));
3630 
3631  /* initialize */
3632  BMSclearMemoryArray(colisprocessed, nconsideredcols);
3633  BMSclearMemoryArray(removecol, nconsideredcols);
3634  maxslack = sepadata->maxslack;
3635  nunprocessedcols = nconsideredcols;
3636  nzerocolsremoved = 0;
3637  ncolsingletonsremoved = 0;
3638  nnonzentries = 0;
3639  rowofcolsingleton = -1;
3640  if( removecolsingletons )
3641  maxnnonzentries = 1;
3642  else
3643  maxnnonzentries = 0;
3644 
3645  /* check all columns if they contain exactly one nonzero entry */
3646  while(nunprocessedcols > 0)
3647  {
3648  for( c = 0 ; c < nconsideredcols ; ++c )
3649  if( colisprocessed[c] == FALSE )
3650  break;
3651  assert(firstcolsind + c < mod2data->ncolsind);
3652 
3653  nnonzentries = 0;
3654  rowsbind = (int) GETBITARRAYINDEX(mod2data->colsind[firstcolsind + c]);
3655  rowsbmask = GETBITARRAYMASK(mod2data->colsind[firstcolsind + c]); /*lint !e701*/
3656 
3657  for( r = 0 ; r < mod2data->nrowsind ; ++r)
3658  if( mod2data->rows[mod2data->rowsind[r]][rowsbind] & rowsbmask )
3659  {
3660  nnonzentries++;
3661  if( nnonzentries > maxnnonzentries )
3662  break;
3663  rowofcolsingleton = r;
3664  }
3665 
3666  /* check if a zero column has been found */
3667  if( removezerocols )
3668  if( nnonzentries == 0 )
3669  {
3670  /* remove zero columns */
3671  removecol[c] = TRUE;
3672  nzerocolsremoved++;
3673  markColAsRemovedAndClearCol(mod2data, firstcolsind + c, ZERO_COLUMN);
3674  }
3675 
3676  /* check if a column singleton has been found */
3677  if( removecolsingletons && !removecol[c] )
3678  if( nnonzentries == 1 )
3679  {
3680  r = rowofcolsingleton;
3681  removecol[c] = TRUE;
3682 
3683  /* update row slack: slack' = slack + fracsol */
3684  mod2data->slacks[mod2data->rowsind[r]] += mod2data->fracsol[mod2data->colsind[firstcolsind + c]];
3685 
3686  /* if removing col results in a row with slack > maxslack,
3687  * then the row can be removed as well */
3688  if( checkresultingrows && SCIPisGT(scip, mod2data->slacks[mod2data->rowsind[r]], maxslack) )
3689  {
3691  for( j = 0 ; j < nconsideredcols ; ++j)
3692  if( !removecol[j] && colisprocessed[j] )
3693  if( BITARRAYBITISSET(mod2data->rows[mod2data->rowsind[r]],
3694  mod2data->colsind[firstcolsind + j]) ) /*lint !e701*/
3695  {
3696  colisprocessed[j] = FALSE; /* re-consider col */
3697  nunprocessedcols++;
3698  }
3699 
3700  BMSmoveMemoryArray(&((mod2data->rowsind)[r]), &((mod2data->rowsind)[r + 1]),
3701  mod2data->nrowsind - r - 1); /*lint !e866*/
3702 
3703  mod2data->nrowsind--;
3704  }
3705 
3706  /* remove column singleton */
3707  ncolsingletonsremoved++;
3708  markColAsRemovedAndClearCol(mod2data, firstcolsind + c, SINGLETON_COLUMN);
3709  }
3710 
3711  colisprocessed[c] = TRUE;
3712  nunprocessedcols--;
3713 
3714  if( nzerocolsremoved + ncolsingletonsremoved == nconsideredcols || mod2data->nrowsind == 0 )
3715  break;
3716  }
3717 
3718  /* if all rows have been deleted, remove cols as well */
3719  if( mod2data->nrowsind == 0 )
3720  {
3721  for( c = firstcolsind ; c < mod2data->ncolsind; ++c)
3722  if( !removecol[c] )
3723  {
3724  removecol[c] = TRUE;
3725  markColAsRemovedAndClearCol(mod2data, firstcolsind + c, ZERO_COLUMN);
3726  }
3727  nzerocolsremoved = nconsideredcols - ncolsingletonsremoved;
3728  assert(nzerocolsremoved + ncolsingletonsremoved == nconsideredcols);
3729  }
3730 
3731  /* update mod2data->colsind array if necessary*/
3732  if( mod2data->nrowsind == 0 )
3733  mod2data->ncolsind = 0;
3734  else
3735  if( nzerocolsremoved + ncolsingletonsremoved > 0 )
3736  {
3737  j = firstcolsind;
3738  for( c = firstcolsind ; c < mod2data->ncolsind && j < mod2data->ncolsind; ++c)
3739  {
3740  if( c < nconsideredcols )
3741  while( removecol[j] && j < mod2data->ncolsind )
3742  j++;
3743  if( c < j && j < mod2data->ncolsind )
3744  mod2data->colsind[c] = mod2data->colsind[j];
3745  j++;
3746  }
3747  mod2data->ncolsind -= (nzerocolsremoved + ncolsingletonsremoved);
3748  }
3749 
3750  /* free temporary memory */
3751  SCIPfreeBufferArray(scip, &removecol);
3752  SCIPfreeBufferArray(scip, &colisprocessed);
3753 
3754  return SCIP_OKAY;
3755 }
3756 
3757 
3758 /** applies modified Gaussian Elimination reduction */
3759 static
3761  SCIP* scip, /**< SCIP data structure */
3762  SCIP_SEPADATA* sepadata, /**< separator data */
3763  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
3764  ZEROHALF_MOD2DATA* mod2data /**< considered (preprocessed) subproblem mod 2 */
3765  )
3766 {
3767  int nslackzerorows;
3768  int pivotrow;
3769  int pivotcol;
3770  int pivot;
3771  int identsubmatrixsize;
3772  int rowsbind;
3773  BITARRAYBITMASKTYPE rowsbmask;
3774  int r;
3775  int temp;
3776 
3777  assert(scip != NULL);
3778  assert(sepadata != NULL);
3779  assert(lpdata != NULL);
3780  assert(mod2data != NULL);
3781  assert(mod2data->relatedsubproblem != NULL);
3782 
3783  /* check if matrix or colind range is empty */
3784  if( mod2data->ncolsind == 0 || mod2data->nrowsind == 0 )
3785  return SCIP_OKAY;
3786 
3787  /* determine number of slack zero rows */
3788  nslackzerorows = 0;
3789  while( nslackzerorows < mod2data->nrowsind
3790  && SCIPisZero(scip, mod2data->slacks[mod2data->rowsind[nslackzerorows]]) )
3791  nslackzerorows++;
3792  /* check if at least one slack zero row exists */
3793  if( nslackzerorows == 0 )
3794  return SCIP_OKAY;
3795 
3796 
3797  /* sort column indices sets w.r.t. to their primsol values NON-INCREASINGLY */
3798  if( mod2data->ncolsind > 1 )
3799  {
3800  SCIPsortInd( mod2data->colsind , compRealNonIncreasing , (void*) mod2data->fracsol , mod2data->ncolsind );
3801  }
3802 
3803  /* sort row indices sets w.r.t. to their slack values NON-DECREASINGLY */
3804  if( mod2data->nrowsind > 1 )
3805  {
3806  SCIPsortInd( mod2data->rowsind , compRealNonDecreasing , (void*) mod2data->slacks , mod2data->nrowsind );
3807  }
3808 
3809 
3810  identsubmatrixsize = 0;
3811 
3812  /* create maximal identity submatrix */
3813  /* determine pivot col */
3814  for( pivotcol = 0 ; pivotcol < mod2data->ncolsind ; ++pivotcol)
3815  {
3816  if( identsubmatrixsize == mod2data->nrowsind )
3817  break;
3818 
3819  /* determine pivot row */
3820  rowsbind = (int) GETBITARRAYINDEX(mod2data->colsind[pivotcol]);
3821  rowsbmask = GETBITARRAYMASK(mod2data->colsind[pivotcol]); /*lint !e701*/
3822  for( pivotrow = identsubmatrixsize ; pivotrow < nslackzerorows ; ++pivotrow)
3823  if( mod2data->rows[mod2data->rowsind[pivotrow]][rowsbind] & rowsbmask )
3824  break;
3825  if( pivotrow == nslackzerorows )
3826  continue;
3827 
3828  /* Gaussian elimination step */
3829  for( r = 0 ; r < nslackzerorows ; ++r)
3830  {
3831  if( r == pivotrow )
3832  continue;
3833  if( mod2data->rows[mod2data->rowsind[r]][rowsbind] & rowsbmask )
3834  {
3835  /* add pivot row to r-th row */
3836  BITARRAYSXOR(mod2data->rows[mod2data->rowsind[pivotrow]],
3837  mod2data->rows[mod2data->rowsind[r]],mod2data->rowsbitarraysize);
3838  BITARRAYSXOR(mod2data->rowaggregations[mod2data->rowsind[pivotrow]],
3839  mod2data->rowaggregations[mod2data->rowsind[r]],mod2data->rowaggregationsbitarraysize);
3840  mod2data->rhs[mod2data->rowsind[r]] =
3841  XOR(mod2data->rhs[mod2data->rowsind[pivotrow]],mod2data->rhs[mod2data->rowsind[r]]);
3842  /* all rows have slack zero: */
3843  /* // mod2data->slacks[[mod2data->rowsind[r]] += mod2data->slacks[[mod2data->rowsind[pivotrow]]; */
3844  }
3845  }
3846 
3847  /* swap index set positions */
3848  temp = mod2data->rowsind[pivotrow];
3849  mod2data->rowsind[pivotrow] = mod2data->rowsind[identsubmatrixsize];
3850  mod2data->rowsind[identsubmatrixsize] = temp;
3851  temp = mod2data->colsind[pivotcol];
3852  mod2data->colsind[pivotcol] = mod2data->colsind[identsubmatrixsize];
3853  mod2data->colsind[identsubmatrixsize] = temp;
3854 
3855  identsubmatrixsize++;
3856  }
3857 
3858  if( identsubmatrixsize > 0 )
3859  {
3860  /* add rows of identity submatrix properly to rows with positive slack
3861  * to transform each column of the identity submatrix into a column singleton */
3862  for( pivot = 0 ; pivot < identsubmatrixsize ; ++pivot)
3863  {
3864  rowsbind = (int) GETBITARRAYINDEX(mod2data->colsind[pivot]);
3865  rowsbmask = GETBITARRAYMASK(mod2data->colsind[pivot]); /*lint !e701*/
3866  for( r = nslackzerorows ; r < mod2data->nrowsind ; ++r)
3867  if( mod2data->rows[mod2data->rowsind[r]][rowsbind] & rowsbmask )
3868  {
3869  /* add pivot row to r-th row */
3870  BITARRAYSXOR(mod2data->rows[mod2data->rowsind[pivot]],
3871  mod2data->rows[mod2data->rowsind[r]],mod2data->rowsbitarraysize);
3872  BITARRAYSXOR(mod2data->rowaggregations[mod2data->rowsind[pivot]],
3873  mod2data->rowaggregations[mod2data->rowsind[r]],mod2data->rowaggregationsbitarraysize);
3874  mod2data->rhs[mod2data->rowsind[r]] =
3875  XOR(mod2data->rhs[mod2data->rowsind[pivot]],mod2data->rhs[mod2data->rowsind[r]]);
3876  /* all identity submatrix rows have slack zero */
3877  /* // mod2data->slacks[[mod2data->rowsind[r]] += mod2data->slacks[[mod2data->rowsind[pivot]]; */
3878  }
3879  }
3880 
3881  /* remove generated column singletons */
3882  SCIP_CALL(preprocessColumns(scip, sepadata, lpdata, mod2data,
3883  0, /*identsubmatrixsize*/ mod2data->ncolsind, FALSE, TRUE, TRUE));
3884 
3885  /* remove zero rows */
3886  SCIP_CALL(preprocessRows(scip, sepadata, lpdata, mod2data,
3887  0, mod2data->nrowsind, TRUE, FALSE, FALSE));
3888  }
3889 
3890  return SCIP_OKAY;
3891 }
3892 
3893 
3894 /** decomposes the problem into subproblems which can be considered separately */
3895 static
3897  SCIP* scip, /**< SCIP data structure */
3898  SCIP_SEPADATA* sepadata, /**< separator data */
3899  ZEROHALF_LPDATA* lpdata /**< data of current LP relaxation */
3900  )
3901 {
3902 
3903 #ifdef WITHDECOMPOSE
3904  /**@todo this is buggy in different ways.
3905  * 1. it might happen that we ignore a variable of the current row and of all other rows.
3906  * thus at the end, the variable will not occur in any subproblem. BUT, currently we do not update
3907  * lpdata->subproblemsindexofcol[lppos] and lpdata->rcolsindexofcol[lppos] accordingly.
3908  * consequently, it might happen that lpdata->rcolsindexofcol[lppos] > problem->nrcols, with
3909  * with problem being the subproblem still associated to our column. therefore, a corresponding assert
3910  * assert(rcolsindex < problem->nrcols) in storeMod2Data() is violated
3911  * [e.g., for IP/atamtuerk/mik/unbounded/mik.250-1-50.3.mps.gz].
3912  * we could recognize whether a variable is never added to a subproblem and update its data structures,
3913  * but I'm not sure whether this will be correct, i.e., whether it is really ok to ignore some variables here.
3914  * 2. in particular, it seems like that this method has not been adapted to that we can deal with
3915  * continuous variables now. (see the below todo of Manuel)
3916  * 3. in case we end up with only one subproblem, we use the old problem. but in this case we do not update
3917  * the problem data and hence it is not consistent with the lpdata anymore where we might have set some
3918  * rows to be irrelevant.
3919  *
3920  * therefore, we will currently do nothing in here.
3921  */
3922  BITARRAY processedrows;
3923  int nprocessedrows;
3924  int processedrowsbitarraysize;
3925  int unprocessedrowidx;
3926 
3927  BITARRAY processedcols;
3928  int nprocessedcols;
3929  int processedcolsbitarraysize;
3930 
3931  int* queue;
3932  int queuefirst;
3933  int queuelast;
3934 
3935  int i;
3936  int j;
3937  int k;
3938 
3939  SCIP_COL** colsofrow;
3940  SCIP_ROW** rowsofcol;
3941 
3942  SCIP_Real* colvals;
3943  SCIP_Real* rowvals;
3944  int ncolvals;
3945  int nrowvals;
3946  int cidx;
3947  int ridx;
3948  int lppos;
3949 
3950  int rrowsidx;
3951  int rcolsidx;
3952 
3953  SCIP_Bool fliplhsrhs;
3954 
3955  ZEROHALF_SUBLPDATA* problem;
3956  int problemindex;
3957  ZEROHALF_SUBLPDATA* subproblem;
3958 
3959  int* rrowsinsubprob;
3960  int* rcolsinsubprob;
3961  SCIP_Bool* rrowsinsubproboddrhs;
3962  int nrrowsinsubprob;
3963  int nrcolsinsubprob;
3964 
3965  int totalnrrows;
3966  int totalnrcols;
3967 
3968  int nrrowsinitial;
3969  int nrcolsinitial;
3970  int ndelvarbounds;
3971 
3972  int rowindex;
3973  int colindex;
3974 
3975  SCIP_Real maxslack;
3976 
3977  assert(scip != NULL);
3978  assert(sepadata != NULL);
3979  assert(lpdata != NULL);
3980  assert(lpdata->subproblems != NULL);
3981  assert(lpdata->nsubproblems > 0);
3982 
3983  problemindex = 0;
3984 
3985  assert(problemindex >= 0);
3986  assert(problemindex <= lpdata->nsubproblems);
3987 
3988  problem = lpdata->subproblems[problemindex];
3989 
3990  assert(problem != NULL);
3991  assert(problem->rcols != NULL);
3992  assert(problem->nrcols > 0);
3993  assert(problem->rcolslbslack != NULL);
3994  assert(problem->rcolsubslack != NULL);
3995  assert(problem->rrows != NULL);
3996  assert(problem->nrrows > 0);
3997  assert(problem->rrowsrhs != NULL);
3998  assert(problem->rrowsslack != NULL);
3999 
4000  if( sepadata->dtimer == NULL )
4001  {
4002  ZEROHALFcreateTimer((sepadata->dtimer));
4003  }
4004  ZEROHALFstartTimer(sepadata->dtimer);
4005 
4006  processedrowsbitarraysize = (int) GETREQUIREDBITARRAYSIZE(problem->nrrows);
4007  processedcolsbitarraysize = (int) GETREQUIREDBITARRAYSIZE(problem->nrcols);
4008 
4009  SCIPfreeMemoryArray(scip, &(lpdata->subproblems));
4010 
4011  /* allocate temporary memory */
4012  SCIP_CALL(SCIPallocMemoryArray(scip, &(lpdata->subproblems), problem->nrrows));
4013  SCIP_CALL(SCIPallocBufferArray(scip, &processedrows, processedrowsbitarraysize));
4014  SCIP_CALL(SCIPallocBufferArray(scip, &processedcols, processedcolsbitarraysize));
4015  SCIP_CALL(SCIPallocBufferArray(scip, &queue, problem->nrrows));
4016  SCIP_CALL(SCIPallocMemoryArray(scip, &rrowsinsubprob, problem->nrrows));
4017  SCIP_CALL(SCIPallocMemoryArray(scip, &rrowsinsubproboddrhs, problem->nrrows));
4018  SCIP_CALL(SCIPallocMemoryArray(scip, &rcolsinsubprob, problem->nrcols));
4019 
4020  /* initialize temporary memory */
4021  BMSclearMemoryArray(processedrows, processedrowsbitarraysize);
4022  BMSclearMemoryArray(processedcols, processedcolsbitarraysize);
4023  lpdata->nsubproblems = 0;
4024  maxslack = sepadata->maxslack;
4025 
4026  nrrowsinitial = problem->nrrows;
4027  nrcolsinitial = problem->nrcols;
4028  totalnrrows = 0;
4029  totalnrcols = 0;
4030  ndelvarbounds = 0;
4031  nprocessedrows = 0;
4032  nprocessedcols = 0;
4033  k = 0;
4034  unprocessedrowidx = 0;
4035 
4036  while( nprocessedrows < problem->nrrows )
4037  {
4038  ++k;
4039  nrrowsinsubprob = 0;
4040  nrcolsinsubprob = 0;
4041 
4042  for( i = unprocessedrowidx ; i < problem->nrrows ; ++i)
4043  {
4044  if( BITARRAYBITISSET(processedrows, i) ) /*lint !e701*/
4045  unprocessedrowidx++;
4046  else
4047  break;
4048  }
4049  BITARRAYBITSET(processedrows, i); /*lint !e701*/
4050 
4051  queue[0] = i;
4052  queuefirst = 0;
4053  queuelast = 1;
4054 
4055  while( queuelast > queuefirst )
4056  {
4057  assert(queuelast <= problem->nrrows);
4058 
4059  i = queue[queuefirst];
4060  queuefirst++;
4061 
4062  rrowsinsubprob[nrrowsinsubprob] = i;
4063  nrrowsinsubprob++;
4064 
4065  fliplhsrhs = FALSE;
4066 
4067  colsofrow = SCIProwGetCols(lpdata->rows[problem->rrows[i]]);
4068  colvals = SCIProwGetVals(lpdata->rows[problem->rrows[i]]);
4069  ncolvals = SCIProwGetNLPNonz(lpdata->rows[problem->rrows[i]]);
4070 
4071  for( cidx = 0 ; cidx < ncolvals ; ++cidx)
4072  {
4073  lppos = SCIPcolGetLPPos(colsofrow[cidx]);
4074  if( lppos == -1 )
4075  continue;
4076  rcolsidx = lpdata->rcolsindexofcol[lppos];
4077 
4078  if( lpdata->subproblemsindexofcol[lppos] != problemindex || rcolsidx < 0 )
4079  {
4080  if( ISODD(scip, colvals[cidx]) )
4081  fliplhsrhs = XOR(fliplhsrhs,
4082  (lpdata->rcolsindexofcol[lppos] == LP_SOL_EQUALS_ODD_LB
4083  || lpdata->rcolsindexofcol[lppos] == LP_SOL_EQUALS_ODD_UB));
4084 
4085  /**@todo analogue for continuous variables? */
4086 
4087  continue; /* col is not relevant */
4088  }
4089  if( nprocessedcols == problem->nrcols )
4090  continue;
4091 
4092  if( BITARRAYBITISSET(processedcols, rcolsidx) ) /*lint !e701*/
4093  continue;
4094 
4095  if( ISEVEN(scip, colvals[cidx]) )
4096  continue;
4097 
4098  rcolsinsubprob[nrcolsinsubprob] = rcolsidx;
4099  nrcolsinsubprob++;
4100  BITARRAYBITSET(processedcols, rcolsidx); /*lint !e701*/
4101 
4102  rowsofcol = SCIPcolGetRows(colsofrow[cidx]);
4103  rowvals = SCIPcolGetVals(colsofrow[cidx]);
4104  nrowvals = SCIPcolGetNNonz(colsofrow[cidx]);
4105  for( ridx = 0 ; ridx < nrowvals ; ++ridx)
4106  {
4107  lppos = SCIProwGetLPPos(rowsofcol[ridx]);
4108  if( lppos == -1 )
4109  continue;
4110  rrowsidx = lpdata->rrowsindexofleftrow[lppos];
4111  if( lpdata->subproblemsindexofrow[lppos] == problemindex
4112  && rrowsidx >= 0 )
4113  {
4114  if( !BITARRAYBITISSET(processedrows, rrowsidx) ) /*lint !e701*/
4115  if( ISODD(scip, rowvals[ridx]) )
4116  {
4117  queue[queuelast] = rrowsidx;
4118  queuelast++;
4119  BITARRAYBITSET(processedrows, rrowsidx); /*lint !e701*/
4120  }
4121  }
4122  rrowsidx = lpdata->rrowsindexofrightrow[lppos];
4123  if( lpdata->subproblemsindexofrow[lppos] == problemindex
4124  && rrowsidx >= 0 )
4125  {
4126  if( !BITARRAYBITISSET(processedrows, rrowsidx) ) /*lint !e701*/
4127  if( ISODD(scip, rowvals[ridx]) )
4128  {
4129  queue[queuelast] = rrowsidx;
4130  queuelast++;
4131  BITARRAYBITSET(processedrows, rrowsidx); /*lint !e701*/
4132  }
4133  }
4134  }
4135  nprocessedcols++;
4136  }
4137  rrowsinsubproboddrhs[nrrowsinsubprob-1] = XOR(ISODD(scip, problem->rrowsrhs[i]),fliplhsrhs);
4138  nprocessedrows++;
4139  }
4140 
4141  /* a subproblem consisting only of rows with even rhs values can be ignored.
4142  * note: varbounds have to be considered! */
4143  for( i = 0 ; i < nrrowsinsubprob ; ++i)
4144  if( rrowsinsubproboddrhs[i] )
4145  break;
4146  for( j = 0 ; j < nrcolsinsubprob ; ++j)
4147  if( (SCIPisLE(scip, problem->rcolsubslack[rcolsinsubprob[j]], maxslack)
4148  && ISODD(scip, SCIPcolGetUb(lpdata->cols[problem->rcols[rcolsinsubprob[j]]])))
4149  || (SCIPisLE(scip, problem->rcolslbslack[rcolsinsubprob[j]], maxslack)
4150  && ISODD(scip, SCIPcolGetLb(lpdata->cols[problem->rcols[rcolsinsubprob[j]]]))) )
4151  break; /* a relevant odd varbound has been found */
4152  if( i == nrrowsinsubprob && j == nrcolsinsubprob )
4153  {
4154  /* no odd rhs value exists */
4155  for( i = 0 ; i < nrrowsinsubprob ; ++i)
4156  {
4157  lppos = SCIProwGetLPPos(lpdata->rows[problem->rrows[rrowsinsubprob[i]]]);
4158  lpdata->subproblemsindexofrow[lppos] = IRRELEVANT;
4159  if( lpdata->rrowsindexofleftrow[lppos] == rrowsinsubprob[i] )
4160  lpdata->rrowsindexofleftrow[lppos] = ROW_IN_SUBPROB_WITHOUT_ODD_RHS;
4161  if( lpdata->rrowsindexofrightrow[lppos] == rrowsinsubprob[i] )
4162  lpdata->rrowsindexofrightrow[lppos] = ROW_IN_SUBPROB_WITHOUT_ODD_RHS;
4163  }
4164  for( j = 0 ; j < nrcolsinsubprob ; ++j)
4165  {
4166  lppos = SCIPcolGetLPPos(lpdata->cols[problem->rcols[rcolsinsubprob[j]]]);
4167  lpdata->subproblemsindexofcol[lppos] = IRRELEVANT;
4168  lpdata->rcolsindexofcol[lppos] = COLUMN_IN_SUBPROB_WITHOUT_ODD_RHS;
4169 
4170  /* statistics */
4171  if( !SCIPisInfinity(scip, problem->rcolslbslack[rcolsinsubprob[j]]) )
4172  ndelvarbounds++;
4173  if( !SCIPisInfinity(scip, problem->rcolsubslack[rcolsinsubprob[j]]) )
4174  ndelvarbounds++;
4175  }
4176  continue;
4177  }
4178 
4179  /* don't create new "sub"problem if problem can't be decomposed */
4180  if( lpdata->nsubproblems == 0 && nprocessedrows == problem->nrrows )
4181  continue;
4182 
4183  /* create new subproblem */
4184  SCIP_CALL(ZerohalfSubLPDataCreate(scip, &subproblem));
4185  SCIP_CALL(SCIPallocMemoryArray(scip, &(subproblem->rrows), nrrowsinsubprob));
4186  SCIP_CALL(SCIPallocMemoryArray(scip, &(subproblem->rrowsrhs), nrrowsinsubprob));
4187  SCIP_CALL(SCIPallocMemoryArray(scip, &(subproblem->rrowsslack), nrrowsinsubprob));
4188  subproblem->nrrows = nrrowsinsubprob;
4189  SCIP_CALL(SCIPallocMemoryArray(scip, &(subproblem->rcols), nrcolsinsubprob));
4190  SCIP_CALL(SCIPallocMemoryArray(scip, &(subproblem->rcolslbslack), nrcolsinsubprob));
4191  SCIP_CALL(SCIPallocMemoryArray(scip, &(subproblem->rcolsubslack), nrcolsinsubprob));
4192  subproblem->nrcols = nrcolsinsubprob;
4193 
4194  for( i = 0 ; i < nrrowsinsubprob ; ++i)
4195  {
4196  rowindex = problem->rrows[rrowsinsubprob[i]];
4197 
4198  subproblem->rrows[i] = rowindex;
4199  subproblem->rrowsrhs[i] = problem->rrowsrhs[rrowsinsubprob[i]];
4200  subproblem->rrowsslack[i] = problem->rrowsslack[rrowsinsubprob[i]];
4201 
4202  if( lpdata->subproblemsindexofrow[rowindex] != IRRELEVANT )
4203  {
4204  assert(lpdata->rrowsindexofleftrow[rowindex] >= 0
4205  || lpdata->rrowsindexofrightrow[rowindex] >= 0);
4206  lpdata->subproblemsindexofrow[rowindex] = lpdata->nsubproblems;
4207  if( lpdata->rrowsindexofleftrow[rowindex] >= 0 )
4208  lpdata->rrowsindexofleftrow[rowindex] = i;
4209  if( lpdata->rrowsindexofrightrow[rowindex] >= 0 )
4210  lpdata->rrowsindexofrightrow[rowindex] = i;
4211  }
4212  }
4213 
4214  for( i = 0 ; i < nrcolsinsubprob ; ++i)
4215  {
4216  colindex = problem->rcols[rcolsinsubprob[i]];
4217 
4218  subproblem->rcols[i] = colindex;
4219  subproblem->rcolslbslack[i] = problem->rcolslbslack[rcolsinsubprob[i]];
4220  subproblem->rcolsubslack[i] = problem->rcolsubslack[rcolsinsubprob[i]];
4221 
4222  if( lpdata->subproblemsindexofcol[colindex] != IRRELEVANT )
4223  {
4224  assert(lpdata->rcolsindexofcol[colindex] >= 0);
4225  lpdata->subproblemsindexofcol[colindex] = lpdata->nsubproblems;
4226  lpdata->rcolsindexofcol[colindex] = i;
4227  }
4228  }
4229 
4230  lpdata->subproblems[lpdata->nsubproblems] = subproblem;
4231  lpdata->nsubproblems++;
4232 
4233  totalnrrows += subproblem->nrrows;
4234  totalnrcols += subproblem->nrcols;
4235 
4236  SCIPdebugMessage("subproblem %d: %d rrows, %d rcols\n", k, subproblem->nrrows, subproblem->nrcols);
4237  }
4238  if( lpdata->nsubproblems == 0 )
4239  {
4240  /* problem couldn't be decomposed into different subproblems, hence keep the entire problem */
4241  lpdata->subproblems[0] = problem;
4242  lpdata->nsubproblems = 1;
4243  totalnrrows = problem->nrrows;
4244  totalnrcols = problem->nrcols;
4245 
4246  }
4247  else
4248  {
4249  ZerohalfSubLPDataFree(scip, &problem);
4250  }
4251 
4252  /* free temporary memory */
4253  SCIPfreeMemoryArray(scip, &rcolsinsubprob);
4254  SCIPfreeMemoryArray(scip, &rrowsinsubproboddrhs);
4255  SCIPfreeMemoryArray(scip, &rrowsinsubprob);
4256  SCIPfreeBufferArray(scip, &queue);
4257  SCIPfreeBufferArray(scip, &processedcols);
4258  SCIPfreeBufferArray(scip, &processedrows);
4259 
4260 
4261  ZEROHALFstopTimer(sepadata->dtimer);
4262  ZEROHALFstatisticsMessage("\n");
4263  ZEROHALFstatisticsMessage(" | --------------------------------- problem \
4264 -------------------------------- | ----- callback ---- | --total-\n");
4265  ZEROHALFstatisticsMessage(" | nrrows | nrcols | ndlrrows | ndlrcols \
4266 | nsubprob | ndelsubp | ndlvbnds | nsepcuts | ncutsfnd | time\n");
4267  ZEROHALFstatisticsMessage("%15s | %8d | %8d | %8d | %8d | %8d | %8d | %8d | %8d | %8d | %8.4f\n",
4268  "DECOMPOSITION", totalnrrows, totalnrcols, nrrowsinitial - totalnrrows, nrcolsinitial - totalnrcols,
4269  lpdata->nsubproblems, k - lpdata->nsubproblems,
4270  ndelvarbounds,
4271  0, 0, ZEROHALFevalTimer(sepadata->dtimer));
4272 
4273 #else
4274  assert(scip != NULL);
4275  assert(sepadata != NULL);
4276  assert(lpdata != NULL);
4277 #endif
4278 
4279  return SCIP_OKAY;
4280 }
4281 
4282 
4283 /** removes the largest number of columns such that the sum of the corresponding variables is at most delta */
4284 static
4286  SCIP* scip, /**< SCIP data structure */
4287  SCIP_SEPADATA* sepadata, /**< separator data */
4288  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
4289  SCIP_Real delta /**< delta value */
4290  )
4291 {
4292  int ncolsremoved;
4293  int c;
4294  SCIP_Real maxsumfracsols;
4295  SCIP_Real sumfracsols;
4296 
4297 
4298  assert(scip != NULL);
4299  assert(sepadata != NULL);
4300  assert(mod2data != NULL);
4301  assert(delta >= 0.0);
4302  assert(delta <= 1.0);
4303 
4304 
4305  /* check if matrix contains rows or columns */
4306  if( mod2data->ncolsind == 0 || mod2data->nrowsind == 0 )
4307  return SCIP_OKAY;
4308 
4309  /* check if delta is positive */
4310  if( !SCIPisPositive(scip, delta) )
4311  return SCIP_OKAY;
4312 
4313 
4314  ncolsremoved = 0;
4315  sumfracsols = 0.0;
4316  maxsumfracsols = sepadata->maxslack * delta;
4317 
4318  /* sort column indices sets w.r.t. to their primsol values NON-INCREASINGLY */
4319  if( mod2data->ncolsind > 1 )
4320  {
4321  SCIPsortInd( mod2data->colsind , compRealNonIncreasing , (void*) mod2data->fracsol , mod2data->ncolsind );
4322  }
4323 
4324  for( c = mod2data->ncolsind - 1 ; c >= 0 ; --c)
4325  {
4326  if( SCIPisGT(scip, sumfracsols + mod2data->fracsol[mod2data->colsind[c]], maxsumfracsols) )
4327  break;
4328 
4329  sumfracsols += mod2data->fracsol[mod2data->colsind[c]];
4331  ncolsremoved++;
4332  }
4333 
4334  if( ncolsremoved > 0 )
4335  {
4336  mod2data->ncolsind -= ncolsremoved;
4337  sepadata->maxslack -= sumfracsols;
4338  }
4339 
4340  return SCIP_OKAY;
4341 }
4342 
4343 
4344 /** removes some rows that cannot be combined because the resulting slack would be larger than maxslack */
4345 static
4347  SCIP* scip, /**< SCIP data structure */
4348  SCIP_SEPADATA* sepadata, /**< separator data */
4349  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
4350  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
4351  SCIP_Bool removelargeslackrows, /**< should rows with slack + minslack > maxslack be removed? */
4352  SCIP_Bool removelargecolrows /**< should rows with "large valued" columns that cannot be negated be removed? */
4353  )
4354 {
4355  int first;
4356  int last;
4357  int temp;
4358  SCIP_Real minslackoddrhsrows;
4359  SCIP_Real minslackrowwithnonz;
4360  int noddrhsrows;
4361  int nlslrowsremoved;
4362  int nlcolrowsremoved;
4363 #ifndef NDEBUG
4364  int r;
4365 #endif
4366  int c;
4367  SCIP_Bool* removerow;
4368  int i;
4369  int j;
4370  int rowsbind;
4371  BITARRAYBITMASKTYPE rowsbmask;
4372 
4373  assert(scip != NULL);
4374  assert(sepadata != NULL);
4375  assert(lpdata != NULL);
4376  assert(mod2data != NULL);
4377  assert(removelargeslackrows || removelargecolrows);
4378 
4379 
4380  /* check if( A mod 2, b mod 2) is empty */
4381  if( mod2data->nrows == 0 || mod2data->nrowsind == 0 )
4382  return SCIP_OKAY;
4383 
4384 
4385  /* partition rows into odd-rhs-rows and even-rhs-rows */
4386  first = 0;
4387  last = mod2data->nrowsind - 1;
4388  while(first < last)
4389  {
4390  if( !mod2data->rhs[mod2data->rowsind[first]] )
4391  {
4392  temp = mod2data->rowsind[first];
4393  mod2data->rowsind[first] = mod2data->rowsind[last];
4394  mod2data->rowsind[last] = temp;
4395  --last;
4396  }
4397  else
4398  ++first;
4399  }
4400  noddrhsrows = first + (mod2data->rhs[mod2data->rowsind[first]] ? 1 : 0);
4401 
4402 
4403  /* check if odd rows exists */
4404  if( noddrhsrows == 0 )
4405  return SCIP_OKAY;
4406 
4407  /* sort each partition by nondecreasing slacks */
4408  assert(noddrhsrows >= 0);
4409  SCIPsortInd( mod2data->rowsind , compRealNonDecreasing , (void*) mod2data->slacks , noddrhsrows );
4410  if( noddrhsrows < mod2data->nrowsind )
4411  {
4412  SCIPsortInd( mod2data->rowsind + noddrhsrows , compRealNonDecreasing , (void*) mod2data->slacks ,
4413  mod2data->nrowsind - noddrhsrows );
4414  }
4415 
4416  minslackoddrhsrows = mod2data->slacks[mod2data->rowsind[0]];
4417  nlslrowsremoved = 0;
4418  nlcolrowsremoved = 0;
4419 
4420  if( SCIPisFeasZero(scip, minslackoddrhsrows) )
4421  return SCIP_OKAY;
4422 
4423  /* check if a zerohalf cut may be generated */
4424  if( SCIPisGT(scip, minslackoddrhsrows, sepadata->maxslack) )
4425  {
4426  if( removelargeslackrows )
4427  {
4428  for( i = 0 ; i < mod2data->nrowsind ; ++i )
4430  for( i = 0 ; i < mod2data->ncolsind ; ++i )
4432  mod2data->nrowsind = 0;
4433  mod2data->ncolsind = 0;
4434  }
4435  }
4436  else
4437  {
4438  SCIP_CALL(SCIPallocBufferArray(scip, &removerow, mod2data->nrowsind));
4439  BMSclearMemoryArray(removerow, mod2data->nrowsind);
4440 
4441  /* remove all rows with even rhs and slack > maxslack - minslackoddrhsrows */
4442  if( removelargeslackrows )
4443  {
4444  for( i = noddrhsrows ; i < mod2data->nrowsind ; ++i)
4445  if( SCIPisGT(scip, minslackoddrhsrows + mod2data->slacks[mod2data->rowsind[i]], sepadata->maxslack) )
4446  break;
4447  nlslrowsremoved += mod2data->nrowsind - i;
4448  while(i < mod2data->nrowsind)
4449  {
4450 #ifndef NDEBUG
4451  r = mod2data->rowsind[i];
4452 #endif
4453  assert(!mod2data->rhs[r]);
4454  assert(SCIPisGT(scip, minslackoddrhsrows + mod2data->slacks[r], sepadata->maxslack));
4456  removerow[i] = TRUE;
4457  i++;
4458  }
4459  }
4460 
4461  /* consider cols */
4462  if( removelargecolrows )
4463  {
4464  if( mod2data->ncolsind > 0 )
4465  {
4466  /* sort column indices sets w.r.t. to their primsol values NON-INCREASINGLY */
4467  if( mod2data->ncolsind > 1 )
4468  {
4469  SCIPsortInd( mod2data->colsind , compRealNonIncreasing , (void*) mod2data->fracsol , mod2data->ncolsind );
4470  }
4471 
4472  j = 0;
4473  while( j < mod2data->ncolsind && SCIPisGT(scip, mod2data->fracsol[mod2data->colsind[j]] + minslackoddrhsrows, sepadata->maxslack) )
4474  {
4475  c = mod2data->colsind[j];
4476  minslackrowwithnonz = 1.0;
4477  rowsbind = (int) GETBITARRAYINDEX(c);
4478  rowsbmask = GETBITARRAYMASK(c); /*lint !e701*/
4479  for( i = 0 ; i < mod2data->nrowsind ; ++i)
4480  if( !removerow[i] )
4481  if( mod2data->rows[mod2data->rowsind[i]][rowsbind] & rowsbmask )
4482  if( SCIPisLT(scip, mod2data->slacks[mod2data->rowsind[i]], minslackrowwithnonz) )
4483  minslackrowwithnonz = mod2data->slacks[mod2data->rowsind[i]];
4484 
4485  if( minslackrowwithnonz < 1.0 )
4486  {
4487  for( i = 0 ; i < mod2data->nrowsind ; ++i)
4488  if( !removerow[i] )
4489  if( mod2data->rows[mod2data->rowsind[i]][rowsbind] & rowsbmask )
4490  if( SCIPisGT(scip, minslackrowwithnonz + mod2data->slacks[mod2data->rowsind[i]], sepadata->maxslack) )
4491  {
4492  markRowAsRemoved(mod2data, i, LARGE_COL_EXISTS);
4493  removerow[i] = TRUE;
4494  nlcolrowsremoved++;
4495  }
4496  }
4497  j++;
4498  }
4499  }
4500  }
4501 
4502  /* update mod2data->rowsind if necessary */
4503  if( nlslrowsremoved + nlcolrowsremoved > 0 )
4504  {
4505  j = 0;
4506  for( i = 0 ; i < mod2data->nrowsind && j < mod2data->nrowsind; ++i)
4507  {
4508  if( i < mod2data->nrowsind )
4509  while( removerow[j] && j < mod2data->nrowsind )
4510  j++;
4511  if( i < j && j < mod2data->nrowsind )
4512  mod2data->rowsind[i] = mod2data->rowsind[j];
4513  j++;
4514  }
4515  mod2data->nrowsind -= (nlslrowsremoved + nlcolrowsremoved);
4516  }
4517 
4518  /* free temporary memory */
4519  SCIPfreeBufferArray(scip, &removerow);
4520  }
4521 
4522  return SCIP_OKAY;
4523 }
4524 
4525 
4526 /** aggregates identical columns into one column whose (artificial) LP solution is the sum of the aggregated columns */
4527 static
4529  SCIP* scip, /**< SCIP data structure */
4530  ZEROHALF_MOD2DATA* mod2data /**< considered (preprocessed) subproblem mod 2 */
4531  )
4532 {
4533  int c1;
4534  int c2;
4535  int r;
4536  int rowsbind1;
4537  BITARRAYBITMASKTYPE rowsbmask1;
4538  int rowsbind2;
4539  BITARRAYBITMASKTYPE rowsbmask2;
4540  int ncolsremoved;
4541  SCIP_Bool* removecol;
4542 
4543  assert(scip != NULL);
4544  assert(mod2data != NULL);
4545 
4546  /* check if( A mod 2, b mod 2) is empty */
4547  if( mod2data->nrows == 0 || mod2data->nrowsind == 0 || mod2data->ncolsind == 0 )
4548  return SCIP_OKAY;
4549 
4550 
4551  /* allocate and initialize temporary memory */
4552  SCIP_CALL(SCIPallocBufferArray(scip, &removecol, mod2data->ncolsind));
4553  BMSclearMemoryArray(removecol, mod2data->ncolsind);
4554  ncolsremoved = 0;
4555 
4556 
4557  /* check each pair of columns */
4558  for( c1 = 0 ; c1 < mod2data->ncolsind - 1 ; ++c1)
4559  {
4560  rowsbind1 = (int) GETBITARRAYINDEX(mod2data->colsind[c1]);
4561  rowsbmask1 = GETBITARRAYMASK(mod2data->colsind[c1]); /*lint !e701*/
4562  for( c2 = c1 + 1 ; c2 < mod2data->ncolsind ; ++c2)
4563  {
4564  rowsbind2 = (int) GETBITARRAYINDEX(mod2data->colsind[c2]);
4565  rowsbmask2 = GETBITARRAYMASK(mod2data->colsind[c2]); /*lint !e701*/
4566  for( r = 0 ; r < mod2data->nrowsind ; ++r)
4567  if( (mod2data->rows[mod2data->rowsind[r]][rowsbind1] & rowsbmask1)
4568  != (mod2data->rows[mod2data->rowsind[r]][rowsbind2] & rowsbmask2) )
4569  break;
4570  if( r == mod2data->nrowsind )
4571  {
4572  /* a pair of identical columns have been found */
4573 
4574  mod2data->fracsol[mod2data->colsind[c2]] += mod2data->fracsol[mod2data->colsind[c1]];
4575  removecol[c1] = TRUE;
4576  ncolsremoved++;
4578  }
4579  }
4580  }
4581 
4582  /* update mod2data->colsind array if necessary*/
4583  if( ncolsremoved > 0 )
4584  {
4585  c1 = 0;
4586  for( c2 = 0 ; c2 < mod2data->ncolsind && c1 < mod2data->ncolsind; ++c2)
4587  {
4588  if( c2 < mod2data->ncolsind )
4589  while( removecol[c1] && c1 < mod2data->ncolsind )
4590  c1++;
4591  if( c2 < c1 && c1 < mod2data->ncolsind )
4592  mod2data->colsind[c2] = mod2data->colsind[c1];
4593  c1++;
4594  }
4595  mod2data->ncolsind -= ncolsremoved;
4596  }
4597 
4598  /* free temporary memory */
4599  SCIPfreeBufferArray(scip, &removecol);
4600 
4601  return SCIP_OKAY;
4602 }
4603 
4604 
4605 /** preprocess subproblem */
4606 static
4608  SCIP* scip, /**< SCIP data structure */
4609  SCIP_SEPA* sepa, /**< separator */
4610  SCIP_SEPADATA* sepadata, /**< separator data */
4611  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
4612  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
4613  char normtype, /**< type of norm to use for efficacy norm calculation */
4614  int maxsepacuts, /**< maximal number of zerohalf cuts separated per separation round */
4615  int maxcuts, /**< maximal number of zerohalf cuts found per separation round (incl. ineff. cuts) */
4616  int* nsepacuts, /**< pointer to store current number of separated zerohalf cuts */
4617  int* nzerohalfcuts, /**< pointer to store current number of found zerohalf cuts */
4618  ZEROHALF_CUTDATA** zerohalfcuts, /**< array to store found zerohalf cuts */
4619  SCIP_Real** varsolvals, /**< dense variable LP solution vector */
4620  SCIP_RESULT* result /**< pointer to SCIP result value of separation */
4621  )
4622 {
4623  int i;
4624 #ifdef ZEROHALF__PRINT_STATISTICS
4625  int ncolsbeforeppm;
4626  int ncolsinitial;
4627  int nrowsbeforeppm;
4628  int nrowsinitial;
4629  int nsepacutsbeforeppm;
4630  int nsepacutsinitial;
4631  int nzerohalfcutsbeforeppm;
4632  int nzerohalfcutsinitial;
4633  SCIP_CLOCK* timer;
4634  SCIP_CLOCK* pptimer;
4635 #endif
4636  char ppname[SCIP_MAXSTRLEN];
4637 
4638  assert(scip != NULL);
4639  assert(sepadata != NULL);
4640  assert(lpdata != NULL);
4641  assert(mod2data != NULL);
4642  assert(maxsepacuts >= 0);
4643  assert(maxcuts >= 0);
4644  assert(result != NULL);
4645  assert(nsepacuts != NULL);
4646  assert(nzerohalfcuts != NULL);
4647  assert(zerohalfcuts != NULL);
4648  assert(*nsepacuts <= *nzerohalfcuts);
4649 
4650  assert(mod2data->relatedsubproblem != NULL);
4651  assert(mod2data->rows != NULL);
4652  assert(mod2data->rowaggregations != NULL);
4653  assert(mod2data->rhs != NULL);
4654  assert(mod2data->slacks != NULL);
4655  assert(mod2data->fracsol != NULL);
4656  assert(mod2data->nrows > 0);
4657  assert(mod2data->rowsind != NULL);
4658  assert(mod2data->colsind != NULL);
4659 
4660  if( sepadata->nppmethods == -1 )
4661  {
4662  sepadata->nppmethods = (int) strlen(sepadata->ppmethods);
4663  if( sepadata->nppmethods > 0 && sepadata->ppmethods[0] == '-' )
4664  sepadata->nppmethods = 0;
4665  }
4666 
4667  if( sepadata->nppmethods == 0 )
4668  return SCIP_OKAY;
4669 
4670  /* statistics */
4671 #ifdef ZEROHALF__PRINT_STATISTICS
4672  if( sepadata->pptimers == NULL )
4673  {
4674  SCIP_CALL( SCIPallocMemoryArray(scip, &(sepadata->pptimers), sepadata->nppmethods + 1) );
4675  for( i = 0 ; i < sepadata->nppmethods + 1 ; ++i)
4676  {
4677  ZEROHALFcreateTimer((sepadata->pptimers[i]));
4678  }
4679  }
4680  ZEROHALFstartTimer(sepadata->pptimers[sepadata->nppmethods]);
4681 #endif
4682 
4683  if( mod2data->nrowsind == 0 || mod2data->ncolsind == 0 )
4684  return SCIP_OKAY;
4685 
4686 #ifdef ZEROHALF__PRINT_STATISTICS
4687  ncolsinitial = mod2data->ncolsind;
4688  nrowsinitial = mod2data->nrowsind;
4689  nsepacutsinitial = *nsepacuts;
4690  nzerohalfcutsinitial = *nzerohalfcuts;
4691 #endif
4692 
4693 #ifdef ZEROHALF__PRINT_STATISTICS
4694  ZEROHALFstatisticsMessage("\n");
4695  ZEROHALFstatisticsMessage(" | ------------------------------- subproblem\
4696  ------------------------------- | ----- callback ---- | --total-\n");
4697  ZEROHALFstatisticsMessage(" | nrowsind | ncolsind | ndelrows | ndelcols \
4698 | nsepcuts | ncutsfnd | time | nsepcuts | ncutsfnd | time\n");
4699  ZEROHALFstatisticsMessage("%15s | %8d | %8d | %8d | %8d | %8d | %8d | %8.4f | %8d | %8d | %8.4f\n",
4700  "START PREPROCSS", mod2data->nrowsind, mod2data->ncolsind, 0, 0, 0, 0, 0.0,
4701  *nsepacuts, *nzerohalfcuts, ZEROHALFevalTimer(sepadata->pptimers[sepadata->nppmethods]));
4702  ZEROHALFcreateNewTimer(timer);
4703  ZEROHALFstartTimer(timer);
4704 
4705  ZEROHALFcreateNewTimer(pptimer);
4706 #endif
4707 
4708  for( i = 0 ; i < sepadata->nppmethods ; ++i)
4709  {
4710  /* abort if enough cuts have already been found */
4711  if( *nsepacuts >= maxsepacuts || *nzerohalfcuts >= maxcuts )
4712  break;
4713 #ifndef ZEROHALF__PRINT_STATISTICS
4714  /* abort preprocessing if matrix is empty */
4715  if( mod2data->nrowsind == 0 && mod2data->ncolsind == 0 )
4716  break;
4717 #endif
4718 
4719 #ifdef ZEROHALF__PRINT_STATISTICS
4720  /* statistics*/
4721  ZEROHALFstartTimer(pptimer);
4722  ZEROHALFstartTimer(sepadata->pptimers[i]);
4723  ncolsbeforeppm = mod2data->ncolsind;
4724  nrowsbeforeppm = mod2data->nrowsind;
4725  nsepacutsbeforeppm = *nsepacuts;
4726  nzerohalfcutsbeforeppm = *nzerohalfcuts;
4727 #endif
4728 
4729  /* apply preprocessing method */
4730  switch(sepadata->ppmethods[i])
4731  {
4733  SCIP_CALL(preprocessModGaussElim(scip, sepadata, lpdata, mod2data));
4734  strncpy(ppname,"gauss",SCIP_MAXSTRLEN);
4735  break;
4736  case DELETEZEROROWS:
4737  SCIP_CALL(preprocessRows(scip, sepadata, lpdata, mod2data,
4738  0, mod2data->nrowsind, TRUE, FALSE, FALSE));
4739  strncpy(ppname,"zero rows",SCIP_MAXSTRLEN);
4740  break;
4741  case DELETEZEROCOLS:
4742  SCIP_CALL(preprocessColumns(scip, sepadata, lpdata, mod2data,
4743  0, mod2data->ncolsind, TRUE, FALSE, FALSE));
4744  strncpy(ppname,"zero columns",SCIP_MAXSTRLEN);
4745  break;
4746  case DELETECOLSINGLETONS:
4747  SCIP_CALL(preprocessColumns(scip, sepadata, lpdata, mod2data,
4748  0, mod2data->ncolsind, FALSE, TRUE, TRUE));
4749  strncpy(ppname,"col singletons",SCIP_MAXSTRLEN);
4750  break;
4751  case ADDTRIVIALCUTS:
4752  SCIP_CALL(preprocessTrivialZerohalfCuts(scip, sepa, sepadata, lpdata, mod2data,
4753  0, mod2data->nrowsind, normtype, maxsepacuts, maxcuts, nsepacuts,
4754  nzerohalfcuts, zerohalfcuts, varsolvals, PPZEROONEROW, result));
4755  strncpy(ppname,"trivial cuts",SCIP_MAXSTRLEN);
4756  break;
4757  case DELETEIDENTROWS:
4758  SCIP_CALL(preprocessRows(scip, sepadata, lpdata, mod2data,
4759  0, mod2data->nrowsind, FALSE, FALSE, TRUE));
4760  strncpy(ppname,"identical rows",SCIP_MAXSTRLEN);
4761  break;
4762  case MERGEIDENTCOLS:
4763  SCIP_CALL(preprocessIdenticalColums(scip, mod2data));
4764  strncpy(ppname,"identical cols",SCIP_MAXSTRLEN);
4765  break;
4766  case DELETELARGESLACKROWS:
4767  SCIP_CALL(preprocessRows(scip, sepadata, lpdata, mod2data,
4768  0, mod2data->nrowsind, FALSE, TRUE, FALSE));
4769  strncpy(ppname,"sl>maxsl rows",SCIP_MAXSTRLEN);
4770  break;
4771  case PPCOLUMNS:
4772  SCIP_CALL(preprocessColumns(scip, sepadata, lpdata, mod2data,
4773  0, mod2data->ncolsind, TRUE, TRUE, TRUE));
4774  strncpy(ppname,"(pp cols)",SCIP_MAXSTRLEN);
4775  break;
4776  case PPROWS:
4777  SCIP_CALL(preprocessRows(scip, sepadata, lpdata, mod2data,
4778  0, mod2data->nrowsind, TRUE, TRUE, TRUE));
4779  strncpy(ppname,"(pp rows)",SCIP_MAXSTRLEN);
4780  break;
4782  SCIP_CALL(preprocessColumnsWithSmallFracsol(scip, sepadata, mod2data,
4783  sepadata->ppdelta));
4784  strncpy(ppname,"delta heur",SCIP_MAXSTRLEN);
4785  break;
4786  case DELETEROWSWRTMINSLACK:
4787  SCIP_CALL(preprocessConsiderMinSlack(scip, sepadata, lpdata, mod2data, TRUE, TRUE));
4788  strncpy(ppname,"s_odd",SCIP_MAXSTRLEN);
4789  break;
4790  default:
4791  SCIPerrorMessage("invalid preprocessing method '%c'\n", sepadata->ppmethods[i]);
4792  return SCIP_INVALIDDATA;
4793  }
4794 
4795 #ifdef ZEROHALF__PRINT_STATISTICS
4796  /* statistics */
4797  ZEROHALFstopTimer(sepadata->pptimers[i]);
4798  ZEROHALFstopTimer(pptimer);
4799  ZEROHALFstatisticsMessage("%15s | %8d | %8d | %8d | %8d | %8d | %8d | %8.4f | %8d | %8d | %8.4f\n",
4800  ppname, mod2data->nrowsind, mod2data->ncolsind,
4801  nrowsbeforeppm - mod2data->nrowsind, ncolsbeforeppm - mod2data->ncolsind,
4802  *nsepacuts - nsepacutsbeforeppm, *nzerohalfcuts - nzerohalfcutsbeforeppm,
4803  ZEROHALFevalTimer(pptimer), *nsepacuts, *nzerohalfcuts,
4804  ZEROHALFevalTimer(sepadata->pptimers[i]));
4805  ZEROHALFresetTimer(pptimer);
4806 #endif
4807  }
4808 
4809 #ifdef ZEROHALF__PRINT_STATISTICS
4810  /* statistics */
4811  ZEROHALFstopTimer(timer);
4812  ZEROHALFstatisticsMessage("%15s | %8d | %8d | %8d | %8d | %8d | %8d | %8.4f | %8d | %8d | %8.4f\n",
4813  "PREPROCESSED", mod2data->nrowsind, mod2data->ncolsind,
4814  nrowsinitial - mod2data->nrowsind, ncolsinitial - mod2data->ncolsind,
4815  *nsepacuts - nsepacutsinitial, *nzerohalfcuts - nzerohalfcutsinitial,
4816  ZEROHALFevalTimer(timer), *nsepacuts, *nzerohalfcuts,
4817  ZEROHALFevalTimer(sepadata->pptimers[sepadata->nppmethods]));
4818  ZEROHALFstatisticsMessage("\n");
4819  ZEROHALFfreeTimer(timer);
4820  ZEROHALFfreeTimer(pptimer);
4821  ZEROHALFstopTimer(sepadata->pptimers[sepadata->nppmethods]);
4822 
4823  ZEROHALFstatisticsMessage(" | ------------------------------- subproblem ------------------------------- | ------------------------------\n");
4824  ZEROHALFstatisticsMessage(" | | max2/row | max2/col | A^T ept | \n");
4825  ZEROHALFstatisticsMessage("%15s | | %8s | %8s | %8s |\n",
4826  "SUBPROBSTRUCT",
4827  hasMatrixMax2EntriesPerRow(mod2data) ? "yes" : "no", hasMatrixMax2EntriesPerColumn(mod2data) ? "yes" : "no", "n/a");
4828  ZEROHALFstatisticsMessage("\n");
4829 #endif
4830 
4831  return SCIP_OKAY;
4832 }
4833 
4834 
4835 /* --------------------------------------------------------------------------------------------------------------------
4836  * local methods: separating methods
4837  * -------------------------------------------------------------------------------------------------------------------- */
4838 
4839 
4840 /** returns the objective weights for the weighted feasibility AuxIP */
4841 static
4843  BITARRAY rowaggregation, /**< row aggregation bitarray */
4844  int nrrows /**< number of relevant rows */
4845  )
4846 {
4847  int i;
4848  int naggregatedrrows;
4849 
4850  assert(rowaggregation != NULL);
4851  assert(nrrows > 0);
4852 
4853  naggregatedrrows = 0;
4854  for( i = 0 ; i < nrrows ; ++i)
4855  if( BITARRAYBITISSET(rowaggregation, i) ) /*lint !e701*/
4856  naggregatedrrows++;
4857 
4858  return (SCIP_Real) naggregatedrrows;
4859 }
4860 
4861 
4862 /** creates a "subscip" representing the following auxiliary IP (AuxIP):
4863  * min z := s^T v + x^T y
4864  * s.t. (b (mod 2))^T v - 2q = 1
4865  * (A (mod 2))^T v - y - -2r = 0
4866  *
4867  * v \\in {0,1}^nrowsind
4868  * y \\in {0,1}^ncolsind
4869  * r \\in Z^ncolsind_+
4870  * q \\in Z_+
4871  */
4872 #define BRANCHPRIORITY__AVOID_BRANCHING 0
4873 #define BRANCHPRIORITY__PREFER_BRANCHING 0
4874 static
4876  SCIP* scip, /**< SCIP data structure */
4877  SCIP_SEPADATA* sepadata, /**< separator data */
4878  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
4879  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
4880  ZEROHALF_AUXIPDATA* auxipdata, /**< pointer to data structure to store the auxiliary IP data */
4881  SCIP_Bool setnodelimit /**< should a node limit be set? */
4882  )
4883 {
4884  SCIP_VAR** consvars;
4885  SCIP_Real* consvals;
4886  SCIP_Real maxslack;
4887  char consname[SCIP_MAXSTRLEN];
4888  char varname[SCIP_MAXSTRLEN];
4889  int i;
4890  int j;
4891  int maxnconsvars;
4892  int nconsvars;
4893  SCIP_Bool isfeasip;
4894  SCIP_Bool isweighted;
4895  SCIP_Bool ispenalized;
4896  SCIP_Bool settingsfileexists;
4897 
4898  int nrrows;
4899 
4900  int rowsbind;
4901  BITARRAYBITMASKTYPE rowsbmask;
4902 
4903  SCIP_Bool success;
4904 
4905  SCIP_Real feastol;
4906 
4907  assert(scip != NULL);
4908  assert(sepadata != NULL);
4909  assert(lpdata != NULL);
4910  assert(mod2data != NULL);
4911  assert(auxipdata != NULL);
4912 
4913  assert(mod2data->relatedsubproblem != NULL);
4914  assert(mod2data->rows != NULL);
4915  assert(mod2data->rowaggregations != NULL);
4916  assert(mod2data->rhs != NULL);
4917  assert(mod2data->slacks != NULL);
4918  assert(mod2data->fracsol != NULL);
4919  assert(mod2data->rowsind != NULL);
4920  assert(mod2data->colsind != NULL);
4921 
4922  assert(auxipdata->subscip == NULL);
4923  assert(auxipdata->v == NULL);
4924  assert(auxipdata->y == NULL);
4925  assert(auxipdata->r == NULL);
4926  assert(auxipdata->q == NULL);
4927  assert(auxipdata->feasipcons == NULL);
4928  assert(auxipdata->oddrhscons == NULL);
4929  assert(auxipdata->columnsumcons == NULL);
4930 
4931 
4932  auxipdata->m = mod2data->nrowsind;
4933  auxipdata->n = mod2data->ncolsind;
4934 
4935  /* alloc temporary memory for subscipdata elements*/
4936  SCIP_CALL(SCIPallocMemoryArray(scip, &(auxipdata->v), auxipdata->m));
4937  SCIP_CALL(SCIPallocMemoryArray(scip, &(auxipdata->y), auxipdata->n));
4938  SCIP_CALL(SCIPallocMemoryArray(scip, &(auxipdata->r), auxipdata->n));
4939  SCIP_CALL(SCIPallocMemoryArray(scip, &(auxipdata->columnsumcons), auxipdata->n));
4940 
4941  /* initialize allocated data structures */
4942  BMSclearMemoryArray(auxipdata->v, auxipdata->m); /* NULL = 0x0 */
4943  BMSclearMemoryArray(auxipdata->y, auxipdata->n); /* NULL = 0x0 */
4944  BMSclearMemoryArray(auxipdata->r, auxipdata->n); /* NULL = 0x0 */
4945  BMSclearMemoryArray(auxipdata->columnsumcons, auxipdata->n); /* NULL = 0x0 */
4946 
4947  maxslack = sepadata->maxslack;
4948  nrrows = mod2data->relatedsubproblem->nrrows;
4949 
4950  /* determine subscip limits */
4951  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &auxipdata->timelimit) );
4952  if( !SCIPisInfinity(scip, auxipdata->timelimit) )
4953  auxipdata->timelimit -= SCIPgetSolvingTime(scip);
4954 
4955  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
4956  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &auxipdata->memorylimit) );
4957  if( !SCIPisInfinity(scip, auxipdata->memorylimit) )
4958  {
4959  auxipdata->memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
4960  auxipdata->memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
4961  }
4962 
4963  if( setnodelimit == TRUE )
4964  auxipdata->nodelimit = 3000;
4965  else
4966  auxipdata->nodelimit = -1;
4967 
4968  feastol = SCIPfeastol(scip);
4969  auxipdata->objectivelimit = MIN(1.0, maxslack + feastol);
4970 
4971  /* abort if not enough memory available */
4972  if( auxipdata->memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 )
4973  return SCIP_OKAY;
4974 
4975  /* abort if not enough time available */
4976  if( auxipdata->timelimit <= 0.0 )
4977  return SCIP_OKAY;
4978 
4979  /* alloc further temporary memory */
4980  maxnconsvars = auxipdata->m + auxipdata->n + 2;
4981  SCIP_CALL(SCIPallocBufferArray(scip, &consvals, maxnconsvars));
4982  SCIP_CALL(SCIPallocBufferArray(scip, &consvars, maxnconsvars));
4983 
4984  /* create and initialize framework */
4985 
4986  SCIP_CALL( SCIPcreate(&(auxipdata->subscip)) );
4987  success = FALSE;
4988 #ifndef NDEBUG
4989  SCIP_CALL( SCIPcopyPlugins(scip, auxipdata->subscip, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
4990  TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, &success) );
4991 #else
4992  SCIP_CALL( SCIPcopyPlugins(scip, auxipdata->subscip, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE,
4993  TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, &success) );
4994 #endif
4995  SCIPdebugMessage("Copying the plugins was %s successful.\n", success ? "" : "not");
4996 
4997  SCIP_CALL( SCIPcreateProb(auxipdata->subscip, "sepa_zerohalf auxiliary IP (AuxIP)",
4998  NULL, NULL , NULL , NULL , NULL , NULL , NULL) );
4999 
5000  settingsfileexists = TRUE;
5001  if( strlen(sepadata->subscipsettings) == 0 )
5002  settingsfileexists = FALSE;
5003  if( strlen(sepadata->subscipsettings) == 1 && sepadata->subscipsettings[0] == '-' )
5004  settingsfileexists = FALSE;
5005 
5006  if( settingsfileexists )
5007  {
5008  /* read subscip settings file */
5009  SCIP_CALL(SCIPreadParams(auxipdata->subscip, sepadata->subscipsettings));
5010  }
5011  else
5012  {
5013  /* do not abort subscip on CTRL-C */
5014  SCIP_CALL(SCIPsetBoolParam(auxipdata->subscip, "misc/catchctrlc", FALSE));
5015 
5016  /* disable output to console */
5017 #ifdef SCIP_DEBUG
5018  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "display/verblevel", 4));
5019  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "display/freq", 1));
5020 #else
5021  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "display/verblevel", 0));
5022  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "display/freq", 1000));
5023 #endif
5024  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "display/nsols/active", 2));
5025 
5026  /* forbid recursive call of heuristics solving subMIPs */
5027  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/rins/freq", -1));
5028  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/rens/freq", -1));
5029  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/localbranching/freq", -1));
5030  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/crossover/freq", -1));
5031 
5032  /* disable cut separation in subscip */
5033  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "separating/zerohalf/freq", -1));
5034  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "separating/maxrounds", 0)); */
5035  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "separating/maxroundsroot", 0)); */
5036  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "separating/maxcuts", 0)); */
5037  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "separating/maxcutsroot", 0)); */
5038 
5039  /* use pseudo cost branching without strong branching */
5040  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "branching/pscost/priority", INT_MAX/4)); */
5041 
5042  /* disable expensive presolving */
5043  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "presolving/probing/maxrounds", 0)); */
5044  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "constraints/linear/maxpresolpairrounds", 0)); */
5045  /* SCIP_CALL(SCIPsetRealParam(auxipdata->subscip, "constraints/linear/maxaggrnormscale", 0.0)); */
5046 
5047  /* disable conflict analysis */
5048  /* SCIP_CALL(SCIPsetBoolParam(auxipdata->subscip, "conflict/useprop", FALSE)); */
5049  /* SCIP_CALL(SCIPsetBoolParam(auxipdata->subscip, "conflict/useinflp", FALSE)); */
5050  /* SCIP_CALL(SCIPsetBoolParam(auxipdata->subscip, "conflict/useboundlp", FALSE)); */
5051  /* SCIP_CALL(SCIPsetBoolParam(auxipdata->subscip, "conflict/usesb", FALSE)); */
5052  /* SCIP_CALL(SCIPsetBoolParam(auxipdata->subscip, "conflict/usepseudo", FALSE)); */
5053 
5054  SCIP_CALL(SCIPsetBoolParam(auxipdata->subscip, "branching/preferbinary", TRUE));
5055  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/shifting/freq", 3));
5056  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/simplerounding/freq", 1));
5057  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/rounding/freq", 1));
5058  SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/oneopt/freq", 1));
5059 
5060  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/pscostdiving/freq", 1)); */
5061  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/feaspump/freq", 3)); */
5062 
5063  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/coefdiving/freq", -1)); */
5064  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/fracdiving/freq", -1)); */
5065  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/guideddiving/freq", -1)); */
5066  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/linesearchdiving/freq", -1)); */
5067  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/objpscostdiving/freq", -1)); */
5068  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/rootsoldiving/freq", -1)); */
5069  /* SCIP_CALL(SCIPsetIntParam(auxipdata->subscip, "heuristics/veclendiving/freq", -1)); */
5070  }
5071 
5072  /* get type of auxiliary IP objective function */
5073  isfeasip = (sepadata->subscipobjective == 'v' ? FALSE : TRUE);
5074  isweighted = (sepadata->subscipobjective == 'w' ? TRUE : FALSE);
5075  ispenalized = (sepadata->subscipobjective == 'p' ? TRUE : FALSE);
5076 
5077  /* set limits of subscip */
5078  SCIP_CALL( SCIPsetLongintParam(auxipdata->subscip, "limits/nodes", (SCIP_Longint) auxipdata->nodelimit) );
5079  SCIP_CALL( SCIPsetRealParam(auxipdata->subscip, "limits/time", auxipdata->timelimit) );
5080  SCIP_CALL( SCIPsetRealParam(auxipdata->subscip, "limits/memory", auxipdata->memorylimit) );
5081 
5082  if( !isfeasip )
5083  {
5084  SCIP_CALL( SCIPsetObjlimit(auxipdata->subscip, auxipdata->objectivelimit) );
5085  }
5086  SCIP_CALL( SCIPsetIntParam(auxipdata->subscip, "limits/solutions", sepadata->subscipsollimit) );
5087 
5088 
5089  /* create variables and set objective */
5090  /* q */
5091  SCIP_CALL( SCIPcreateVar(auxipdata->subscip, &(auxipdata->q), "q", 0.0, SCIPinfinity(auxipdata->subscip),
5093  SCIP_CALL( SCIPaddVar(auxipdata->subscip, auxipdata->q) );
5094  SCIP_CALL( SCIPchgVarBranchPriority(auxipdata->subscip, auxipdata->q, BRANCHPRIORITY__AVOID_BRANCHING) );
5095  /* r */
5096  for( j = 0 ; j < auxipdata->n ; ++j)
5097  {
5098  (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "r_colsind%d(rcols%d)", j, mod2data->colsind[j]);
5099  SCIP_CALL( SCIPcreateVar(auxipdata->subscip, &(auxipdata->r[j]), varname, 0.0, SCIPinfinity(auxipdata->subscip),
5101  SCIP_CALL( SCIPaddVar(auxipdata->subscip, auxipdata->r[j]) );
5102  SCIP_CALL( SCIPchgVarBranchPriority(auxipdata->subscip, auxipdata->q, BRANCHPRIORITY__AVOID_BRANCHING) );
5103  }
5104  /* v */
5105  for( i = 0 ; i < auxipdata->m ; ++i)
5106  {
5107  SCIP_Real objcoef;
5108  assert(mod2data->rows[mod2data->rowsind[i]] != NULL);
5109 
5110  (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "v_rowsind%d(rrows%d)", i, mod2data->rowsind[i]);
5111  if( isfeasip )
5112  {
5113  if( isweighted )
5114  {
5115  objcoef = calcObjWeight(mod2data->rowaggregations[mod2data->rowsind[i]], nrrows);
5116  }
5117  else if( ispenalized )
5118  {
5119  objcoef = mod2data->slacks[mod2data->rowsind[i]]
5120  + (sepadata->subscipobjpen
5121  * calcObjWeight(mod2data->rowaggregations[mod2data->rowsind[i]], nrrows));
5122  }
5123  else
5124  objcoef = 1.0;
5125  }
5126  else
5127  objcoef = mod2data->slacks[mod2data->rowsind[i]];
5128  assert(!SCIPisFeasNegative(scip, objcoef));
5129  SCIP_CALL( SCIPcreateVar(auxipdata->subscip, &(auxipdata->v[i]), varname, 0.0, 1.0, objcoef,
5131  SCIP_CALL( SCIPaddVar(auxipdata->subscip, auxipdata->v[i]) );
5132  SCIP_CALL(SCIPchgVarBranchPriority(auxipdata->subscip, auxipdata->q, BRANCHPRIORITY__PREFER_BRANCHING));
5133  }
5134  /* y */
5135  for( j = 0 ; j < auxipdata->n ; ++j)
5136  {
5137  SCIP_Real objcoef;
5138  (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "y_%d(%d)", j, mod2data->colsind[j]);
5139  if( isfeasip )
5140  objcoef = 0.0;
5141  else
5142  objcoef = mod2data->fracsol[mod2data->colsind[j]];
5143  SCIP_CALL( SCIPcreateVar(auxipdata->subscip, &(auxipdata->y[j]), varname, 0.0, 1.0, objcoef,
5145  SCIP_CALL( SCIPaddVar(auxipdata->subscip, auxipdata->y[j]) );
5146  }
5147 
5148  /* create constraints */
5149  /* "feasibility constraint" */
5150  if( isfeasip )
5151  {
5152  nconsvars = 0;
5153  for( i = 0 ; i < auxipdata->m ; ++i)
5154  {
5155  consvals[nconsvars] = mod2data->slacks[mod2data->rowsind[i]];
5156  consvars[nconsvars] = auxipdata->v[i];
5157  nconsvars++;
5158  }
5159  for( j = 0 ; j < auxipdata->n ; ++j)
5160  {
5161  consvals[nconsvars] = mod2data->fracsol[mod2data->colsind[j]];
5162  consvars[nconsvars] = auxipdata->y[j];
5163  nconsvars++;
5164  }
5165  SCIP_CALL( SCIPcreateConsLinear(auxipdata->subscip, &(auxipdata->oddrhscons), "feas",
5166  nconsvars, consvars, consvals, 0.0, auxipdata->objectivelimit,
5167  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5168  SCIP_CALL( SCIPaddCons(auxipdata->subscip, auxipdata->oddrhscons) );
5169  }
5170  /* "odd rhs" */
5171  nconsvars = 0;
5172  for( i = 0 ; i < auxipdata->m ; ++i)
5173  if( mod2data->rhs[mod2data->rowsind[i]] == TRUE )
5174  {
5175  consvals[nconsvars] = 1.0;
5176  consvars[nconsvars] = auxipdata->v[i];
5177  nconsvars++;
5178  }
5179  consvals[nconsvars] = -2.0;
5180  consvars[nconsvars] = auxipdata->q;
5181  nconsvars++;
5182  SCIP_CALL( SCIPcreateConsLinear(auxipdata->subscip, &(auxipdata->oddrhscons), "odd_rhs",
5183  nconsvars, consvars, consvals, 1.0, 1.0,
5184  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5185  SCIP_CALL( SCIPaddCons(auxipdata->subscip, auxipdata->oddrhscons) );
5186  /* "column sum" */
5187  for( j = 0 ; j < auxipdata->n ; ++j)
5188  {
5189  nconsvars = 0;
5190 
5191  rowsbind = (int) GETBITARRAYINDEX(mod2data->colsind[j]);
5192  rowsbmask = GETBITARRAYMASK(mod2data->colsind[j]); /*lint !e701*/
5193  for( i = 0 ; i < auxipdata->m ; ++i) {
5194  if( mod2data->rows[mod2data->rowsind[i]][rowsbind] & rowsbmask )
5195  {
5196  consvals[nconsvars] = 1.0;
5197  consvars[nconsvars] = auxipdata->v[i];
5198  nconsvars++;
5199  }
5200  }
5201  consvals[nconsvars] = -1.0;
5202  consvars[nconsvars] = auxipdata->y[j];
5203  nconsvars++;
5204  consvals[nconsvars] = -2.0;
5205  consvars[nconsvars] = auxipdata->r[j];
5206  nconsvars++;
5207 
5208  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "col_%d(%d)_sum", j, mod2data->colsind[j]);
5209  SCIP_CALL( SCIPcreateConsLinear(auxipdata->subscip, &(auxipdata->columnsumcons[j]) , consname, nconsvars, consvars, consvals, 0.0, 0.0,
5210  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5211  SCIP_CALL( SCIPaddCons(auxipdata->subscip, auxipdata->columnsumcons[j]) );
5212  }
5213 
5214  /* free temporary memory */
5215  SCIPfreeBufferArray(scip, &consvars);
5216  SCIPfreeBufferArray(scip, &consvals);
5217 
5218  SCIPdebug( SCIP_CALL( SCIPprintOrigProblem(auxipdata->subscip, NULL, NULL, TRUE) ) );
5219 
5220  return SCIP_OKAY;
5221 }
5222 
5223 
5224 /** solves the auxiliary IP given as subscip */
5225 static
5227  SCIP* scip, /**< SCIP data structure */
5228  SCIP_SEPADATA* sepadata, /**< separator data */
5229  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
5230  ZEROHALF_AUXIPDATA* auxipdata, /**< auxiliary IP data */
5231  SCIP_SOL*** sols, /**< pointer to store array of solutions */
5232  int* nsols /**< pointer to store number of solutions */
5233  )
5234 {
5235  SCIP_RETCODE retcode;
5236  SCIP_STAGE subscipstage;
5237  SCIP_Real maxslack;
5238  int i;
5239  int j;
5240 
5241  assert(sepadata != NULL);
5242  assert(mod2data != NULL);
5243  assert(auxipdata != NULL);
5244  assert(auxipdata->subscip != NULL);
5245  assert(sols != NULL);
5246  assert(*sols == NULL);
5247  assert(*nsols == 0);
5248 
5249  /* solve AuxIP */
5250  retcode = SCIPsolve(auxipdata->subscip);
5251 
5252  /* errors in solving the subproblem should not kill the overall solving process;
5253  * hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */
5254  if ( retcode != SCIP_OKAY )
5255  {
5256 #ifndef NDEBUG
5257  SCIP_CALL( retcode );
5258 #endif
5259  SCIPwarningMessage(scip, "Error while solving subproblem in zerohalf separator; sub-SCIP terminated with code <%d>\n", retcode);
5260  *nsols = 0;
5261  return SCIP_OKAY;
5262  }
5263 
5264  /* print statistic */
5265  SCIPdebug( SCIP_CALL( SCIPprintStatistics(auxipdata->subscip, NULL) ) );
5266 
5267  maxslack = sepadata->maxslack;
5268 
5269  /* check if solving was successful and get solutions */
5270  subscipstage = SCIPgetStage(auxipdata->subscip);
5271  if( subscipstage == SCIP_STAGE_SOLVING || subscipstage == SCIP_STAGE_SOLVED )
5272  *nsols = SCIPgetNSols(auxipdata->subscip);
5273  else
5274  *nsols = 0;
5275  if( *nsols > 0 )
5276  {
5277  *sols = SCIPgetSols(auxipdata->subscip);
5278  /* check if only the best solution should be used */
5279  if( !sepadata->subscipuseallsols )
5280  *nsols = 1;
5281  }
5282 
5283  /* check if proper a proper solution was found */
5284  if( sepadata->subscipobjective == 'v' )
5285  {
5286  for( i = 0 ; i < *nsols ; ++i)
5287  if( SCIPisGT(scip, SCIPgetSolOrigObj(auxipdata->subscip , (*sols)[i]), maxslack) )
5288  break;
5289  *nsols = i;
5290  }
5291  else
5292  {
5293  SCIP_Real z;
5294  SCIP_Real* viols;
5295  SCIP_SOL** propersols;
5296 
5297  SCIP_Bool swapped;
5298  SCIP_Real tempviol;
5299  SCIP_SOL* tempsol;
5300 
5301  int npropersols;
5302 
5303  SCIP_CALL(SCIPallocBufferArray(scip, &viols, *nsols));
5304  SCIP_CALL(SCIPallocMemoryArray(scip, &propersols, *nsols));
5305  npropersols = 0;
5306  for( i = 0 ; i < *nsols ; ++i)
5307  {
5308  z = 0.0;
5309  for( j = 0 ; j < auxipdata->m ; ++j)
5310  z += mod2data->slacks[mod2data->rowsind[j]]
5311  * SCIPgetSolVal(auxipdata->subscip, (*sols)[i], auxipdata->v[j]);
5312  for( j = 0 ; j < auxipdata->n ; ++j)
5313  z += mod2data->fracsol[mod2data->colsind[j]]
5314  * SCIPgetSolVal(auxipdata->subscip, (*sols)[i], auxipdata->y[j]);
5315 
5316  if( SCIPisLE(scip, z, maxslack) )
5317  {
5318  /* proper sol has been found */
5319  propersols[npropersols] = (*sols)[i];
5320  viols[npropersols] = z;
5321  npropersols++;
5322  }
5323  }
5324 
5325 
5326  swapped = TRUE;
5327  for( i = 1 ; i < npropersols && swapped; ++i)
5328  {
5329  swapped = FALSE;
5330  for( j = 0 ; j < npropersols - i ; ++j)
5331  {
5332  if( viols[j] > viols[j+1] )
5333  {
5334  tempviol = viols[j+1];
5335  viols[j+1] = viols[j];
5336  viols[j] = tempviol;
5337  tempsol = propersols[j+1];
5338  propersols[j+1] = propersols[j];
5339  propersols[j] = tempsol;
5340  swapped = TRUE;
5341  }
5342  }
5343  }
5344 
5345  *sols = propersols;
5346  *nsols = npropersols;
5347  SCIPfreeBufferArray(scip, &viols);
5348 
5349  }
5350 
5351  return SCIP_OKAY;
5352 }
5353 
5354 
5355 
5356 
5357 /** determines the weightvector for a single row */
5358 static
5360  SCIP* scip, /**< SCIP data structure */
5361  SCIP_SEPADATA* sepadata, /**< separator data */
5362  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
5363  int rowsindex, /**< lpdata->rows index */
5364  int rrowsindex, /**< "subproblem"->rrows index */
5365  SCIP_Real** weights /**< pointer to store the weight vector */
5366  )
5367 { /*lint --e{438}*/
5368 
5369  assert(scip != NULL);
5370  assert(lpdata != NULL);
5371  assert(lpdata->nrows > 0);
5372  assert(0 <= rowsindex);
5373  assert(rowsindex < lpdata->nrows);
5374  assert(lpdata->rrowsindexofleftrow[rowsindex] == rrowsindex
5375  || lpdata->rrowsindexofrightrow[rowsindex] == rrowsindex);
5376  assert(weights != NULL);
5377  assert(*weights == NULL);
5378 
5379 
5380  /* allocate temporary memory */
5381  SCIP_CALL(SCIPallocMemoryArray(scip, weights, lpdata->nrows));
5382 
5383  /* initialize */
5384  BMSclearMemoryArray(*weights, lpdata->nrows);
5385 
5386  /* determine row weights */
5387  if( lpdata->rrowsindexofleftrow[rowsindex] == rrowsindex )
5388  (*weights)[rowsindex] = lpdata->intscalarsleftrow[rowsindex] * (-0.5);
5389  else
5390  (*weights)[rowsindex] = lpdata->intscalarsrightrow[rowsindex] * 0.5;
5391 
5392  if( SCIProwGetNLPNonz(lpdata->rows[rowsindex]) >= sepadata->maxnnonz )
5393  {
5394  SCIPfreeMemoryArray(scip, weights);
5395  weights = NULL;
5396  }
5397 
5398  return SCIP_OKAY;
5399 }
5400 
5401 
5402 /** gets the subset of rows that should be combined to a violated zerohalf cut */
5403 static
5405  SCIP* scip, /**< SCIP data structure */
5406  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
5407  ZEROHALF_AUXIPDATA* auxipdata, /**< auxiliary IP data */
5408  SCIP_SOL* solution, /**< considered solution */
5409  BITARRAY* rrowsincut, /**< pointer to store the subset of rows as bitarray (length: number of relevant rows) */
5410  int* nrrowsincut /**< number of combined relevant rows */
5411  )
5412 {
5413  int i;
5414 
5415  assert(scip != NULL);
5416  assert(mod2data != NULL);
5417  assert(mod2data->nrowsind > 0);
5418  assert(auxipdata != NULL);
5419  assert(auxipdata->subscip != NULL);
5420  assert(auxipdata->v != NULL);
5421  assert(solution != NULL);
5422  assert(rrowsincut != NULL);
5423  assert(*rrowsincut == NULL);
5424  assert(nrrowsincut != NULL);
5425 
5426 
5427  /* allocate and initialize temporary memory for calculating the symmetric difference */
5428  SCIP_CALL(SCIPallocMemoryArray(scip, rrowsincut, mod2data->rowaggregationsbitarraysize));
5429  BITARRAYCLEAR(*rrowsincut, mod2data->rowaggregationsbitarraysize);
5430 
5431  *nrrowsincut = 0;
5432 
5433  /* calculate symmetric difference of rrowsincut and specific rowaggregations */
5434  for( i = 0 ; i < mod2data->nrowsind ; ++i)
5435  if( auxipdata->v[i] != NULL )
5436  if( !SCIPisZero(scip, SCIPgetSolVal(auxipdata->subscip, solution, auxipdata->v[i])) )
5437  {
5438  BITARRAYSXOR(mod2data->rowaggregations[mod2data->rowsind[i]], (*rrowsincut) ,
5439  mod2data->rowaggregationsbitarraysize);
5440  (*nrrowsincut)++;
5441  }
5442 
5443  return SCIP_OKAY;
5444 }
5445 
5446 
5447 /** separates violated zerohalf cuts by solving an auxiliary IP. (exact method; exponential time) */
5448 static
5450  SCIP* scip, /**< SCIP data structure */
5451  SCIP_SEPA* sepa, /**< separator */
5452  SCIP_SEPADATA* sepadata, /**< separator data */
5453  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
5454  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
5455  char normtype, /**< SCIP normtype */
5456  int maxsepacuts, /**< maximal number of zerohalf cuts separated per separation round */
5457  int maxcuts, /**< maximal number of zerohalf cuts found per separation round (incl. ineff. cuts) */
5458  SCIP_Bool setnodelimit, /**< should a node limit be set for solving the auxiliary IP? */
5459  int* nsepacuts, /**< pointer to store current number of separated zerohalf cuts */
5460  int* nzerohalfcuts, /**< pointer to store current number of found zerohalf cuts */
5461  ZEROHALF_CUTDATA** zerohalfcuts, /**< array to store found zerohalf cuts */
5462  SCIP_Real** varsolvals, /**< dense variable LP solution vector */
5463  SCIP_RESULT* result /**< pointer to SCIP result value of separation */
5464  )
5465 {
5466  ZEROHALF_AUXIPDATA* auxipdata;
5467  SCIP_SOL** sols;
5468  int nsols;
5469  int s;
5470  BITARRAY rrowsincut;
5471  int nrrowsincut;
5472  SCIP_Real* weights;
5473  int nrowsincut;
5474  SCIP_Bool cutoff = FALSE;
5475 
5476  assert(scip != NULL);
5477  assert(sepadata != NULL);
5478  assert(lpdata != NULL);
5479  assert(mod2data != NULL);
5480  assert(maxsepacuts >= 0);
5481  assert(maxcuts >= 0);
5482  assert(nsepacuts != NULL);
5483  assert(nzerohalfcuts != NULL);
5484  assert(zerohalfcuts != NULL);
5485  assert(*nsepacuts <= *nzerohalfcuts);
5486  assert(varsolvals != NULL);
5487  assert(result != NULL);
5488 
5489  assert(mod2data->relatedsubproblem != NULL);
5490  assert(mod2data->rows != NULL);
5491  assert(mod2data->rowaggregations != NULL);
5492  assert(mod2data->rhs != NULL);
5493  assert(mod2data->slacks != NULL);
5494  assert(mod2data->fracsol != NULL);
5495  assert(mod2data->rowsind != NULL);
5496  assert(mod2data->colsind != NULL);
5497 
5498 
5499  /* check if( A mod 2, b mod 2) is empty */
5500  if( mod2data->nrows == 0 || mod2data->nrowsind == 0 )
5501  return SCIP_OKAY;
5502 
5503  /* check if enough cuts have been found */
5504  if( *nsepacuts >= maxsepacuts || *nzerohalfcuts >= maxcuts )
5505  return SCIP_OKAY;
5506 
5507  /* allocate temporary memory for subscip data structure */
5508  SCIP_CALL(ZerohalfAuxIPDataCreate(scip, &auxipdata));
5509 
5510  /* create subscip */
5511  SCIP_CALL(createSubscip(scip, sepadata, lpdata, mod2data, auxipdata, setnodelimit));
5512 
5513  /* abort if subscip was not created */
5514  if( auxipdata->subscip == NULL )
5515  {
5516  SCIP_CALL(ZerohalfAuxIPDataFree(scip, &auxipdata));
5517  return SCIP_OKAY;
5518  }
5519 
5520  /* solve subscip and get solutions yielding a zerohalf cut with violation >= minviolation */
5521  sols = NULL;
5522  nsols = 0;
5523  SCIP_CALL(solveSubscip(scip, sepadata, mod2data, auxipdata, &sols, &nsols));
5524 
5525 
5526  /* process solutions */
5527  for( s = 0; s < nsols ; ++s)
5528  {
5529  /* check if enough cuts have been found */
5530  if( *nsepacuts >= maxsepacuts || *nzerohalfcuts >= maxcuts )
5531  break;
5532 
5533  /* determine rrows of the related subproblem that have to be combined */
5534  rrowsincut = NULL;
5535  SCIP_CALL(getBitarrayOfSelectedRows(scip, mod2data, auxipdata, sols[s],
5536  &rrowsincut, &nrrowsincut));
5537  assert(nrrowsincut > 0);
5538 
5539  /* calculate rows zerohalf weightvector */
5540  weights = NULL;
5542  mod2data, rrowsincut, &weights, &nrowsincut));
5543  if ( weights == NULL )
5544  {
5545  SCIPfreeMemoryArray(scip, &rrowsincut);
5546  continue;
5547  }
5548  assert(nrowsincut > 0);
5549 
5550 
5551 #ifdef SCIP_DEBUG
5552  SCIP_CALL( debugPrintLPRowsAndCols(scip, lpdata) );
5553  SCIPdebugMessage("\n");
5554  debugPrintSubLpData(scip, lpdata, mod2data->relatedsubproblem);
5555  debugPrintMod2Data(scip, lpdata, mod2data, TRUE);
5556  SCIPdebugMessage("\n");
5557  SCIP_CALL( SCIPprintOrigProblem(auxipdata->subscip, NULL, NULL, TRUE) );
5558  SCIPdebugMessage("\n");
5559  SCIP_CALL( SCIPprintBestSol(auxipdata->subscip, NULL , FALSE) );
5560 #endif
5561 
5562  /* create zerohalf cut */
5563  SCIP_CALL(ZerohalfCutDataCreate(scip, &(zerohalfcuts[*nzerohalfcuts]),
5564  mod2data->relatedsubproblem, mod2data, nrrowsincut, nrowsincut, AUXIP));
5566  lpdata, weights, normtype, *nzerohalfcuts, varsolvals, zerohalfcuts[*nzerohalfcuts], &cutoff));
5567 
5568  if ( cutoff )
5569  *result = SCIP_CUTOFF;
5570  else
5571  {
5572  /* add cut */
5573  SCIP_CALL( addZerohalfCutToLP(scip, sepadata, zerohalfcuts[*nzerohalfcuts], nsepacuts, result) );
5574  (*nzerohalfcuts)++;
5575  }
5576 
5577  /* free temporary memory */
5578  SCIPfreeMemoryArray(scip, &weights);
5579  SCIPfreeMemoryArray(scip, &rrowsincut);
5580 
5581  if ( cutoff )
5582  break;
5583  }
5584 
5585  /* free temporary memory */
5586  if( sepadata->subscipobjective != 'v' )
5587  {
5588  SCIPfreeMemoryArray(scip, &sols);
5589  }
5590  SCIP_CALL(ZerohalfAuxIPDataFree(scip, &auxipdata));
5591 
5592  return SCIP_OKAY;
5593 }
5594 
5595 
5596 /** calculates the inner product of mod2data->row and the LP solution */
5597 static
5599  SCIP* scip, /**< SCIP data structure */
5600  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
5601  BITARRAY row, /**< considered mod2data->row */
5602  SCIP_Real maxinnerproduct, /**< calculation is aborted if innerproduct >= maxinnerproduct */
5603  SCIP_Real* innerproduct /**< pointer to store the inner product */
5604  )
5605 {
5606  int c;
5607  int rcolindex;
5608 
5609  assert(scip != NULL);
5610  assert(mod2data != NULL);
5611  assert(row != NULL);
5612  assert(maxinnerproduct >= 0);
5613  assert(innerproduct != NULL);
5614 
5615 
5616  *innerproduct = 0.0;
5617 
5618  /* check if( A mod 2, b mod 2) is empty */
5619  if( mod2data->nrows == 0 || mod2data->nrowsind == 0
5620  || mod2data->ncolsind == 0 )
5621  return SCIP_OKAY;
5622 
5623  /* calculate the inner product of rows[rowsindex] and fracsol */
5624  for( c = 0 ; c < mod2data->ncolsind ; ++c)
5625  {
5626  rcolindex = mod2data->colsind[c];
5627  if( BITARRAYBITISSET(row, rcolindex) ) /*lint !e701*/
5628  *innerproduct += mod2data->fracsol[rcolindex];
5629  if( SCIPisGT(scip, *innerproduct, maxinnerproduct) )
5630  break;
5631  }
5632 
5633  return SCIP_OKAY;
5634 }
5635 
5636 
5637 /** separate violated zerohalf cuts by enumerating possible row combinations. (heuristic; polynomial time) */
5638 static
5640  SCIP* scip, /**< SCIP data structure */
5641  SCIP_SEPA* sepa, /**< separator */
5642  SCIP_SEPADATA* sepadata, /**< separator data */
5643  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
5644  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
5645  char normtype, /**< SCIP normtype */
5646  int maxsepacuts, /**< maximal number of zerohalf cuts separated per separation round */
5647  int maxcuts, /**< maximal number of zerohalf cuts found per separation round (incl. ineff. cuts) */
5648  int* nsepacuts, /**< pointer to store current number of separated zerohalf cuts */
5649  int* nzerohalfcuts, /**< pointer to store current number of found zerohalf cuts */
5650  ZEROHALF_CUTDATA** zerohalfcuts, /**< array to store found zerohalf cuts */
5651  SCIP_Real** varsolvals, /**< dense variable LP solution vector */
5652  SCIP_RESULT* result, /**< pointer to SCIP result value of separation */
5653  int maxncombinedrows /**< maximal number of combined rows; currently only 1 or 2 is supported */
5654  )
5655 {
5656  int first;
5657  int last;
5658  int temp;
5659  SCIP_Real minslackoddrhsrows;
5660  int ncombinedrows;
5661  int noddrhsrows;
5662  int r1;
5663  int r2;
5664  BITARRAY combinedrow;
5665  BITARRAY rrowsincut;
5666  SCIP_Real roundingdownweakening;
5667  SCIP_Real slack1;
5668  SCIP_Real slack2;
5669  int i;
5670  int j;
5671  SCIP_Real* weights;
5672  int nrowsincut;
5673  SCIP_Bool cutoff = FALSE;
5674 
5675  assert(scip != NULL);
5676  assert(sepadata != NULL);
5677  assert(lpdata != NULL);
5678  assert(mod2data != NULL);
5679  assert(maxsepacuts >= 0);
5680  assert(maxcuts >= 0);
5681  assert(nsepacuts != NULL);
5682  assert(nzerohalfcuts != NULL);
5683  assert(zerohalfcuts != NULL);
5684  assert(*nsepacuts <= *nzerohalfcuts);
5685  assert(varsolvals != NULL);
5686  assert(result != NULL);
5687  assert(maxncombinedrows >= 1);
5688 
5689  assert(mod2data->relatedsubproblem != NULL);
5690  assert(mod2data->rows != NULL);
5691  assert(mod2data->rowaggregations != NULL);
5692  assert(mod2data->rhs != NULL);
5693  assert(mod2data->slacks != NULL);
5694  assert(mod2data->fracsol != NULL);
5695  assert(mod2data->rowsind != NULL);
5696  assert(mod2data->colsind != NULL);
5697 
5698 
5699  /* check if( A mod 2, b mod 2) is empty */
5700  if( mod2data->nrows == 0 || mod2data->nrowsind == 0 )
5701  return SCIP_OKAY;
5702 
5703  /* check if enough cuts have been found */
5704  if( *nsepacuts >= maxsepacuts || *nzerohalfcuts >= maxcuts )
5705  return SCIP_OKAY;
5706 
5707 
5708  /* partition rows into odd-rhs-rows and even-rhs-rows */
5709  first = 0;
5710  last = mod2data->nrowsind - 1;
5711  while(first < last)
5712  {
5713  if( !mod2data->rhs[mod2data->rowsind[first]] )
5714  {
5715  temp = mod2data->rowsind[first];
5716  mod2data->rowsind[first] = mod2data->rowsind[last];
5717  mod2data->rowsind[last] = temp;
5718  --last;
5719  }
5720  else
5721  ++first;
5722  }
5723  noddrhsrows = first + (mod2data->rhs[mod2data->rowsind[first]] ? 1 : 0);
5724 
5725  /* check if odd rows exists */
5726  if( noddrhsrows == 0 )
5727  return SCIP_OKAY;
5728 
5729  /* allocate and initialize temporary memory for calculating the symmetric difference */
5730  combinedrow = NULL;
5731  rrowsincut = NULL;
5732  if( maxncombinedrows > 1 )
5733  {
5734  SCIP_CALL(SCIPallocBufferArray(scip, &combinedrow, mod2data->rowsbitarraysize));
5735  SCIP_CALL(SCIPallocBufferArray(scip, &rrowsincut, mod2data->rowaggregationsbitarraysize));
5736  BITARRAYCLEAR(rrowsincut, mod2data->rowaggregationsbitarraysize);
5737  }
5738 
5739  /* sort each partition by nondecreasing slacks */
5740  assert(noddrhsrows >= 0);
5741  SCIPsortInd( mod2data->rowsind , compRealNonDecreasing , (void*) mod2data->slacks , noddrhsrows );
5742 
5743  if( noddrhsrows < mod2data->nrowsind )
5744  {
5745  SCIPsortInd( mod2data->rowsind + noddrhsrows , compRealNonDecreasing , (void*) mod2data->slacks , mod2data->nrowsind - noddrhsrows );
5746  }
5747 
5748  minslackoddrhsrows = mod2data->slacks[mod2data->rowsind[0]];
5749 
5750  if( SCIPisLE(scip, minslackoddrhsrows, sepadata->maxslack) )
5751  {
5752  for( ncombinedrows = 1 ; ncombinedrows <= maxncombinedrows ; ++ncombinedrows )
5753  {
5754  switch( ncombinedrows )
5755  {
5756  case 1:
5757  /* check all rows r1 with rhs(r1) odd */
5758  for( i = 0 ; i < noddrhsrows ; ++i)
5759  {
5760  r1 = mod2data->rowsind[i];
5761  assert(mod2data->rhs[r1]);
5762  if( *nzerohalfcuts == maxcuts || *nsepacuts == maxsepacuts )
5763  break;
5764  slack1 = mod2data->slacks[r1];
5765  if( SCIPisGT(scip, slack1, sepadata->maxslack) )
5766  break; /* because rowsind is sorted */
5767  SCIP_CALL(calcInnerProductOfRowAndFracsol(scip, mod2data, mod2data->rows[r1],
5768  sepadata->maxslack, &roundingdownweakening));
5769  if( SCIPisLE(scip, roundingdownweakening + slack1, sepadata->maxslack) )
5770  {
5771  /* a violated zerohalf cut has been found */
5772 
5773  /* calculate rows zerohalf weightvector */
5774  weights = NULL;
5776  mod2data, mod2data->rowaggregations[r1], &weights, &nrowsincut));
5777  if( weights == NULL )
5778  {
5779  continue;
5780  }
5781  assert(nrowsincut > 0);
5782 
5783  /* create zerohalf cut */
5784  SCIP_CALL(ZerohalfCutDataCreate(scip, &(zerohalfcuts[*nzerohalfcuts]),
5785  mod2data->relatedsubproblem, mod2data, 2, nrowsincut, HEURISTICSENUM));
5787  lpdata, weights, normtype, *nzerohalfcuts, varsolvals, zerohalfcuts[*nzerohalfcuts], &cutoff));
5788 
5789  if ( cutoff )
5790  *result = SCIP_CUTOFF;
5791  else
5792  {
5793  /* add cut */
5794  SCIP_CALL( addZerohalfCutToLP(scip, sepadata, zerohalfcuts[*nzerohalfcuts], nsepacuts, result) );
5795  (*nzerohalfcuts)++;
5796  }
5797 
5798  /* free temporary memory */
5799  SCIPfreeMemoryArray(scip, &weights);
5800  }
5801  }
5802  break;
5803  case 2:
5804  assert(combinedrow != NULL);
5805  assert(rrowsincut != NULL);
5806  if( noddrhsrows == mod2data->nrowsind )
5807  break;
5808  if( mod2data->nrowsind < 2 )
5809  break;
5810 
5811  /* check all pairs (r1,r2) with rhs(r1) odd and rhs(r1) even */
5812  for( i = 0 ; i < noddrhsrows ; ++i)
5813  {
5814  r1 = mod2data->rowsind[i];
5815  assert(mod2data->rhs[r1]);
5816  if( *nzerohalfcuts == maxcuts || *nsepacuts == maxsepacuts )
5817  break;
5818  slack1 = mod2data->slacks[r1];
5819  if( SCIPisGT(scip, slack1, sepadata->maxslack) )
5820  break; /* because rowsind_odd is sorted */
5821 
5822  for( j = noddrhsrows ; j < mod2data->ncolsind ; ++j)
5823  {
5824  r2 = mod2data->rowsind[j];
5825  assert(!mod2data->rhs[r2]);
5826  if( *nzerohalfcuts == maxcuts || *nsepacuts == maxsepacuts )
5827  break;
5828  slack2 = mod2data->slacks[r2];
5829  if( SCIPisGT(scip, slack1 + slack2, sepadata->maxslack) )
5830  break; /* because rowsind_even is sorted */
5831  BMScopyMemoryArray(combinedrow, mod2data->rows[r1], mod2data->rowsbitarraysize);
5832  BITARRAYSXOR(mod2data->rows[r2], combinedrow, mod2data->rowsbitarraysize);
5833  SCIP_CALL(calcInnerProductOfRowAndFracsol(scip, mod2data, combinedrow,
5834  sepadata->maxslack, &roundingdownweakening));
5835  if( SCIPisLE(scip, roundingdownweakening + slack1 + slack2, sepadata->maxslack) )
5836  {
5837  /* a violated zerohalf cut has been found */
5838 
5839  /* determine rrows of the related subproblem that have to be combined */
5840  BMScopyMemoryArray(rrowsincut, mod2data->rowaggregations[r1],
5841  mod2data->rowaggregationsbitarraysize);
5842  BITARRAYSXOR(mod2data->rowaggregations[r2], rrowsincut,
5843  mod2data->rowaggregationsbitarraysize);
5844 
5845  /* calculate rows zerohalf weightvector */
5846  weights = NULL;
5848  mod2data, rrowsincut, &weights, &nrowsincut));
5849  if ( weights == NULL )
5850  {
5851  continue;
5852  }
5853  assert(nrowsincut > 0);
5854 
5855  /* create zerohalf cut */
5856  SCIP_CALL(ZerohalfCutDataCreate(scip, &(zerohalfcuts[*nzerohalfcuts]),
5857  mod2data->relatedsubproblem, mod2data, 2, nrowsincut, HEURISTICSENUM));
5859  lpdata, weights, normtype, *nzerohalfcuts, varsolvals, zerohalfcuts[*nzerohalfcuts], &cutoff));
5860 
5861  if ( cutoff )
5862  *result = SCIP_CUTOFF;
5863  else
5864  {
5865  /* add cut */
5866  SCIP_CALL( addZerohalfCutToLP(scip, sepadata, zerohalfcuts[*nzerohalfcuts], nsepacuts, result) );
5867  (*nzerohalfcuts)++;
5868  }
5869 
5870  /* free temporary memory */
5871  SCIPfreeMemoryArray(scip, &weights);
5872  }
5873  }
5874  }
5875  break;
5876  default:
5877  SCIPerrorMessage("invalid ncombinedrows '%d'\n", ncombinedrows);
5878  return SCIP_INVALIDDATA;
5879  }
5880 
5881  if ( cutoff )
5882  break;
5883  }
5884  }
5885 
5886  /* free temporary memory */
5887  if( rrowsincut != NULL )
5888  {
5889  SCIPfreeBufferArray(scip, &rrowsincut);
5890  }
5891  if( combinedrow != NULL )
5892  {
5893  SCIPfreeBufferArray(scip, &combinedrow);
5894  }
5895  return SCIP_OKAY;
5896 }
5897 
5898 
5899 #if 0
5900 /** prints a node of the auxiliary graph */
5901 static
5902 void debugPrintAuxGraphNode(
5903  ZEROHALF_AUXGRAPH_NODE* node /**< node to be printed */
5904  )
5905 {
5906  int i;
5907 
5908  assert(node != NULL);
5909 
5910  SCIPdebugMessage("\nnode: %p\n", node);
5911  for( i = 0 ; i < node->nneighbors ; ++i)
5912  {
5913  SCIPdebugMessage(" neighbor %4d: %p weight: %6f rrow: %4d\n",
5914  i, node->neighbors[i], node->edgeweights[i], node->relatedrows[i]);
5915  }
5916  SCIPdebugMessage(" nneighbors: %d distance: %6f previous: %p\n",
5917  node->nneighbors, node->distance, node->previous);
5918 }
5919 #endif
5920 
5921 
5922 /** adds an edge (and its "copy" w.r.t. the node copies) to the auxiliary graph */
5923 static
5925  SCIP* scip, /**< SCIP data structure */
5926  ZEROHALF_AUXGRAPH* graph, /**< auxiliary graph */
5927  int node1index, /**< start node of edge */
5928  int node2index, /**< end node of edge */
5929  SCIP_Bool isodd, /**< is the rhs value of the corresponding mod2data->row odd? */
5930  SCIP_Real weight, /**< weight of the edge */
5931  int relatedrow /**< corresponding mod2data->row */
5932  )
5933 {
5934  ZEROHALF_AUXGRAPH_NODE* node1;
5935  ZEROHALF_AUXGRAPH_NODE* node2;
5936  ZEROHALF_AUXGRAPH_NODE* node1copy;
5937  ZEROHALF_AUXGRAPH_NODE* node2copy;
5938  int n1;
5939  int n2;
5940 
5941  int maxnumberofneighbors;
5942 
5943  assert(scip != NULL);
5944  assert(graph != NULL);
5945  assert(node1index >= 0);
5946  assert(node1index < graph->nnodes);
5947  assert(node2index >= 0);
5948  assert(node2index < graph->nnodes);
5949  assert(!SCIPisNegative(scip, weight));
5950 
5951  maxnumberofneighbors = 2 * graph->nnodes - 2;
5952 
5953  if( isodd )
5954  {
5955  node1 = graph->nodes[node1index];
5956  node2 = graph->nodecopies[node2index];
5957  node1copy = graph->nodecopies[node1index];
5958  node2copy = graph->nodes[node2index];
5959  }
5960  else
5961  {
5962  node1 = graph->nodes[node1index];
5963  node2 = graph->nodes[node2index];
5964  node1copy = graph->nodecopies[node1index];
5965  node2copy = graph->nodecopies[node2index];
5966  }
5967 
5968  if( node1->nneighbors == 0 )
5969  {
5970  assert(maxnumberofneighbors > 0);
5971  SCIP_CALL(SCIPallocMemoryArray(scip, &(node1->neighbors), maxnumberofneighbors));
5972  SCIP_CALL(SCIPallocMemoryArray(scip, &(node1->edgeweights), maxnumberofneighbors));
5973  SCIP_CALL(SCIPallocMemoryArray(scip, &(node1->relatedrows), maxnumberofneighbors));
5974 
5975  SCIP_CALL(SCIPallocMemoryArray(scip, &(node1copy->neighbors), maxnumberofneighbors));
5976  SCIP_CALL(SCIPallocMemoryArray(scip, &(node1copy->edgeweights), maxnumberofneighbors));
5977  SCIP_CALL(SCIPallocMemoryArray(scip, &(node1copy->relatedrows), maxnumberofneighbors));
5978  }
5979 
5980  if( node2->nneighbors == 0 )
5981  {
5982  assert(maxnumberofneighbors > 0);
5983  SCIP_CALL(SCIPallocMemoryArray(scip, &(node2->neighbors), maxnumberofneighbors));
5984  SCIP_CALL(SCIPallocMemoryArray(scip, &(node2->edgeweights), maxnumberofneighbors));
5985  SCIP_CALL(SCIPallocMemoryArray(scip, &(node2->relatedrows), maxnumberofneighbors));
5986 
5987  SCIP_CALL(SCIPallocMemoryArray(scip, &(node2copy->neighbors), maxnumberofneighbors));
5988  SCIP_CALL(SCIPallocMemoryArray(scip, &(node2copy->edgeweights), maxnumberofneighbors));
5989  SCIP_CALL(SCIPallocMemoryArray(scip, &(node2copy->relatedrows), maxnumberofneighbors));
5990  }
5991 
5992  n2 = node2->nneighbors;
5993  for( n1 = 0 ; n1 < node1->nneighbors ; ++n1)
5994  if( node1->neighbors[n1] == node2 )
5995  break;
5996  if( n1 < node1->nneighbors)
5997  for( n2 = 0 ; n2 < node2->nneighbors ; ++n2)
5998  if( node2->neighbors[n2] == node1 )
5999  break;
6000  if( n1 < node1->nneighbors )
6001  {
6002  /* if node2 is neighbor of node1, then node1 is neighbor of node2 */
6003  assert(node1->neighbors[n1] == node2);
6004  assert(n2 < node2->nneighbors);
6005  assert(node2->neighbors[n2] == node1);
6006  assert(node1->edgeweights[n1] == node2->edgeweights[n2]); /*lint !e777*/
6007  }
6008 
6009  if( n1 == node1->nneighbors || SCIPisLT(scip, weight, node1->edgeweights[n1]) )
6010  {
6011  node1->neighbors[n1] = node2;
6012  node1->edgeweights[n1] = weight;
6013  node1->relatedrows[n1] = relatedrow;
6014  node1->nneighbors++;
6015 
6016  node2->neighbors[n2] = node1;
6017  node2->edgeweights[n2] = weight;
6018  node2->relatedrows[n2] = relatedrow;
6019  node2->nneighbors++;
6020 
6021  node1copy->neighbors[n1] = node2copy;
6022  node1copy->edgeweights[n1] = weight;
6023  node1copy->relatedrows[n1] = relatedrow;
6024  node1copy->nneighbors++;
6025 
6026  node2copy->neighbors[n2] = node1copy;
6027  node2copy->edgeweights[n2] = weight;
6028  node2copy->relatedrows[n2] = relatedrow;
6029  node2copy->nneighbors++;
6030  }
6031 
6032  return SCIP_OKAY;
6033 }
6034 
6035 
6036 /** Dijkstra's shortest path algorithm. Calculates the shortest path between
6037  sourcenode and targetnode. The calculation is aborted if the shortest path
6038  cannot be shorter than maxdistance */
6039 static
6041  SCIP* scip, /**< SCIP data structure */
6042  ZEROHALF_AUXGRAPH* graph, /**< auxiliary graph */
6043  ZEROHALF_AUXGRAPH_NODE* sourcenode, /**< start node */
6044  ZEROHALF_AUXGRAPH_NODE* targetnode, /**< end node */
6045  SCIP_Real maxdistance /**< calculation will be aborted if a proof is found that no shortest path with
6046  * length less than maxdistance exists */
6047  )
6048 {
6049  ZEROHALF_AUXGRAPH_NODE** unprocessednodes;
6050  int nunprocessednodes;
6051  int u;
6052  int v;
6053  int n;
6054  SCIP_Real mindistance;
6055  SCIP_Real newdistance;
6056  ZEROHALF_AUXGRAPH_NODE* currentnode;
6057 
6058 
6059  assert(scip != NULL);
6060  assert(graph != NULL);
6061  assert(graph->nnodes > 0);
6062  assert(sourcenode != NULL);
6063  assert(targetnode != NULL);
6064  assert(maxdistance > 0.0);
6065  assert(maxdistance <= 1.0);
6066 
6067  /* allocate temporary memory */
6068  SCIP_CALL(SCIPallocBufferArray(scip, &unprocessednodes, 2 * graph->nnodes));
6069 
6070  /* initialize */
6071  nunprocessednodes = 0;
6072  mindistance = 1.0;
6073  for( v = 0; v < graph->nnodes ; ++v)
6074  {
6075  graph->nodes[v]->distance = 1.0;
6076  graph->nodes[v]->previous = NULL;
6077 
6078  graph->nodecopies[v]->distance = 1.0;
6079  graph->nodecopies[v]->previous = NULL;
6080 
6081  unprocessednodes[nunprocessednodes] = graph->nodes[v];
6082  ++nunprocessednodes;
6083  unprocessednodes[nunprocessednodes] = graph->nodecopies[v];
6084  ++nunprocessednodes;
6085  }
6086  sourcenode->distance = 0.0;
6087  sourcenode->previous = NULL;
6088 
6089  assert(nunprocessednodes == 2 * graph->nnodes);
6090  assert(nunprocessednodes > 0);
6091 
6092  /* for all nodes */
6093  while( nunprocessednodes > 0 )
6094  {
6095  /* get unprocessed node with minimum distance from sourcenode */
6096  u = 0;
6097  mindistance = unprocessednodes[0]->distance;
6098  for( v = 1 ; v < nunprocessednodes ; ++v)
6099  if( unprocessednodes[v]->distance < mindistance )
6100  {
6101  u = v;
6102  mindistance = unprocessednodes[v]->distance;
6103  }
6104  /* if mindistance is greater than maxdistance then abort dijkstra */
6105  if( SCIPisGT(scip, mindistance, maxdistance) )
6106  goto exitdijkstra;
6107  /* set minimum distance node as currentnode */
6108  currentnode = unprocessednodes[u];
6109  unprocessednodes[u] = unprocessednodes[nunprocessednodes-1];
6110  nunprocessednodes--;
6111 
6112  /* for all neighbors of currentnode */
6113  for( n = 0 ; n < currentnode->nneighbors ; ++n)
6114  {
6115  newdistance = currentnode->distance + currentnode->edgeweights[n];
6116  /* check if distance via currentnode is less than their actual distance */
6117  if( SCIPisLT(scip, newdistance , currentnode->neighbors[n]->distance) )
6118  {
6119  currentnode->neighbors[n]->distance = newdistance;
6120  currentnode->neighbors[n]->previous = currentnode;
6121  /* if neighbors is targetnode then abort dijkstra */
6122  if( currentnode->neighbors[n] == targetnode )
6123  goto exitdijkstra;
6124  }
6125  }
6126  }
6127 
6128  exitdijkstra:
6129  SCIPfreeBufferArray(scip, &unprocessednodes);
6130  return SCIP_OKAY;
6131 }
6132 
6133 
6134 /** separates violated zerohalf cuts by searching for minweight odd-valued
6135  cycles within an auxiliary graph. (exact method, but only applicable if
6136  each row contains at most two odd entries; polynomial time) */
6137 static
6139  SCIP* scip, /**< SCIP data structure */
6140  SCIP_SEPA* sepa, /**< separator */
6141  SCIP_SEPADATA* sepadata, /**< separator data */
6142  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
6143  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
6144  char normtype, /**< SCIP normtype */
6145  int maxsepacuts, /**< maximal number of zerohalf cuts separated per separation round */
6146  int maxcuts, /**< maximal number of zerohalf cuts found per separation round (incl. ineff. cuts) */
6147  int* nsepacuts, /**< pointer to store current number of separated zerohalf cuts */
6148  int* nzerohalfcuts, /**< pointer to store current number of found zerohalf cuts */
6149  ZEROHALF_CUTDATA** zerohalfcuts, /**< array to store found zerohalf cuts */
6150  SCIP_Real** varsolvals, /**< dense variable LP solution vector */
6151  SCIP_RESULT* result, /**< pointer to SCIP result value of separation */
6152  SCIP_Bool* wrongstructure /**< pointer to store if there is a row with more than two odd entries */
6153  )
6154 {
6155  ZEROHALF_AUXGRAPH* auxgraph;
6156  int rowsindex;
6157  int i;
6158  int j;
6159  int k;
6160  int n;
6161  int q;
6162 
6163  SCIP_Real* weights;
6164  int nrowsincut;
6165  int nrrowsincut;
6166  BITARRAY rrowsincut;
6167  ZEROHALF_AUXGRAPH_NODE* node;
6168  SCIP_Bool cutoff = FALSE;
6169 
6170  assert(scip != NULL);
6171  assert(sepadata != NULL);
6172  assert(lpdata != NULL);
6173  assert(mod2data != NULL);
6174  assert(maxsepacuts >= 0);
6175  assert(maxcuts >= 0);
6176  assert(nsepacuts != NULL);
6177  assert(nzerohalfcuts != NULL);
6178  assert(zerohalfcuts != NULL);
6179  assert(*nsepacuts <= *nzerohalfcuts);
6180  assert(varsolvals != NULL);
6181  assert(result != NULL);
6182  assert(wrongstructure != NULL);
6183 
6184  *wrongstructure = FALSE;
6185 
6186  /* check if( A mod 2, b mod 2) is empty */
6187  if( mod2data->nrows == 0 || mod2data->nrowsind == 0 )
6188  return SCIP_OKAY;
6189 
6190  /* check if enough cuts have been found */
6191  if( *nsepacuts >= maxsepacuts || *nzerohalfcuts >= maxcuts )
6192  return SCIP_OKAY;
6193 
6194  /* check if matrix has proper structure */
6195  if( !hasMatrixMax2EntriesPerRow(mod2data) )
6196  {
6197  *wrongstructure = TRUE;
6198  return SCIP_OKAY;
6199  }
6200 
6201  /* check if only one row exists */
6202  if( mod2data->nrowsind == 1 )
6203  {
6204  SCIP_CALL(separateByEnumerationHeuristics(scip, sepa, sepadata, lpdata, mod2data,
6205  normtype, maxsepacuts, maxcuts, nsepacuts, nzerohalfcuts, zerohalfcuts,
6206  varsolvals, result, 1));
6207  return SCIP_OKAY;
6208  }
6209 
6210 
6211  /* build auxiliary graph */
6212  SCIP_CALL(ZerohalfAuxGraphCreate(scip, &auxgraph));
6213 
6214  /* create nodes */
6215  auxgraph->nnodes = mod2data->ncolsind + 1;
6216  SCIP_CALL(SCIPallocMemoryArray(scip, &(auxgraph->nodes), auxgraph->nnodes));
6217  SCIP_CALL(SCIPallocMemoryArray(scip, &(auxgraph->nodecopies), auxgraph->nnodes));
6218  q = auxgraph->nnodes - 1;
6219 
6220  for( j = 0 ; j < auxgraph->nnodes ; ++j)
6221  {
6222  SCIP_CALL(ZerohalfAuxGraphNodeCreate(scip, &(auxgraph->nodes[j])));
6223  SCIP_CALL(ZerohalfAuxGraphNodeCreate(scip, &(auxgraph->nodecopies[j])));
6224  }
6225  /* create edges */
6226  for( i = 0 ; i < mod2data->nrowsind ; ++i)
6227  {
6228  rowsindex = mod2data->rowsind[i];
6229  for( j = 0 ; j < mod2data->ncolsind; ++j)
6230  if( BITARRAYBITISSET(mod2data->rows[rowsindex], mod2data->colsind[j]) ) /*lint !e701*/
6231  break;
6232  for( k = j+1 ; k < mod2data->ncolsind; ++k)
6233  if( BITARRAYBITISSET(mod2data->rows[rowsindex], mod2data->colsind[k]) ) /*lint !e701*/
6234  break;
6235 
6236  /* check if row i is a zero row */
6237  if( j >= mod2data->ncolsind )
6238  {
6239  if( mod2data->rhs[rowsindex] )
6240  {
6241  if( SCIPisLE(scip, mod2data->slacks[rowsindex], sepadata->maxslack) )
6242  {
6243  /* violated {0,1/2} cut has been found */
6244  weights = NULL;
6245  nrrowsincut = 1;
6246  nrowsincut = 0;
6247  SCIP_CALL(getZerohalfWeightvectorFromSelectedRowsBitarray(scip, sepadata, lpdata, mod2data,
6248  mod2data->rowaggregations[rowsindex], &weights, &nrowsincut));
6249  if( weights == NULL )
6250  {
6251  continue;
6252  }
6253  assert(nrowsincut > 0);
6254 
6255  /* create zerohalf cut */
6256  SCIP_CALL(ZerohalfCutDataCreate(scip, &(zerohalfcuts[*nzerohalfcuts]),
6257  mod2data->relatedsubproblem, mod2data, nrrowsincut, nrowsincut, AUXGRAPH));
6259  lpdata, weights, normtype, *nzerohalfcuts, varsolvals, zerohalfcuts[*nzerohalfcuts], &cutoff));
6260 
6261  if ( cutoff )
6262  *result = SCIP_CUTOFF;
6263  else
6264  {
6265  /* add cut */
6266  SCIP_CALL( addZerohalfCutToLP(scip, sepadata, zerohalfcuts[*nzerohalfcuts], nsepacuts, result) );
6267  (*nzerohalfcuts)++;
6268  }
6269 
6270  /* free temporary memory */
6271  assert( weights != NULL );
6272  SCIPfreeMemoryArray(scip, &weights);
6273  weights = NULL;
6274 
6275  if ( cutoff )
6276  break;
6277  }
6278  }
6279  continue;
6280  }
6281  assert( ! cutoff );
6282 
6283  /* check if row i has only one entry */
6284  if( k >= mod2data->ncolsind )
6285  {
6286  /* add edges (j,q), (j',q') or (j,q'), (j',q) w.r.t. rhs_i mod 2 */
6287  SCIP_CALL(addEdgeToAuxGraph(scip, auxgraph, j, q,
6288  mod2data->rhs[rowsindex], mod2data->slacks[rowsindex], rowsindex));
6289  continue;
6290  }
6291 
6292  /* row i has two entries */
6293  /* add edges (j,k), (j',k') or (j,k'), (j',k) w.r.t. rhs_i mod 2 */
6294  SCIP_CALL(addEdgeToAuxGraph(scip, auxgraph, j, k,
6295  mod2data->rhs[rowsindex], mod2data->slacks[rowsindex], rowsindex));
6296 
6297  }
6298 
6299  if ( ! cutoff )
6300  {
6301  /* create edges (j,q) and (j',q') for all nodes j */
6302  for( n = 0 ; n < auxgraph->nnodes && n != q ; ++n)
6303  {
6304  SCIP_CALL(addEdgeToAuxGraph(scip, auxgraph, n, q,
6305  FALSE, mod2data->fracsol[mod2data->colsind[n]], -1));
6306  }
6307  }
6308  if( cutoff || auxgraph->nnodes == 0 )
6309  {
6310  /* free temporary memory */
6311  SCIP_CALL(ZerohalfAuxGraphFree(scip, &auxgraph));
6312  return SCIP_OKAY;
6313  }
6314 
6315  weights = NULL;
6316 
6317  /* calculate shortest (node_i, nodecopy_i)-paths using the dijkstra algorithm */
6318  for( n = 0 ; n < auxgraph->nnodes && n != q ; ++n)
6319  {
6320  SCIP_CALL(dijkstra(scip, auxgraph,
6321  auxgraph->nodes[n], auxgraph->nodecopies[n], sepadata->maxslack));
6322 
6323  if( SCIPisLE(scip, auxgraph->nodecopies[n]->distance, sepadata->maxslack) )
6324  {
6325  /* a violated {0,1/2} cut has been found */
6326 
6327  /* determine original rows that have to be combined */
6328  SCIP_CALL(SCIPallocBufferArray(scip, &rrowsincut, mod2data->rowaggregationsbitarraysize));
6329  BITARRAYCLEAR(rrowsincut, mod2data->rowaggregationsbitarraysize);
6330 
6331  nrrowsincut = 0;
6332  nrowsincut = 0;
6333  node = auxgraph->nodecopies[n];
6334  while( node->previous != NULL )
6335  {
6336  for( i = 0 ; i < node->nneighbors ; ++i)
6337  if( node->neighbors[i] == node->previous )
6338  break;
6339  assert(i < node->nneighbors);
6340  rowsindex = node->relatedrows[i];
6341  BITARRAYSXOR(mod2data->rowaggregations[rowsindex], rrowsincut ,
6342  mod2data->rowaggregationsbitarraysize);
6343  node = node->previous;
6344  ++nrrowsincut;
6345  }
6346 
6347  /* get {0,1/2}-weight vector */
6348  assert(weights == NULL);
6350  mod2data, rrowsincut, &weights, &nrowsincut));
6351  if( weights == NULL )
6352  {
6353  SCIPfreeBufferArray(scip, &rrowsincut);
6354  continue;
6355  }
6356  assert(nrowsincut > 0);
6357 
6358  /* create zerohalf cut */
6359  SCIP_CALL(ZerohalfCutDataCreate(scip, &(zerohalfcuts[*nzerohalfcuts]),
6360  mod2data->relatedsubproblem, mod2data, nrrowsincut, nrowsincut, AUXGRAPH));
6362  lpdata, weights, normtype, *nzerohalfcuts, varsolvals, zerohalfcuts[*nzerohalfcuts], &cutoff));
6363 
6364  if ( cutoff )
6365  *result = SCIP_CUTOFF;
6366  else
6367  {
6368  /* add cut */
6369  SCIP_CALL( addZerohalfCutToLP(scip, sepadata, zerohalfcuts[*nzerohalfcuts], nsepacuts, result) );
6370  (*nzerohalfcuts)++;
6371  }
6372 
6373  /* free temporary memory */
6374  assert( weights != NULL );
6375  SCIPfreeMemoryArray(scip, &weights);
6376  weights = NULL;
6377 
6378  if( rrowsincut != NULL )
6379  {
6380  SCIPfreeBufferArray(scip, &rrowsincut);
6381  rrowsincut = NULL;
6382  }
6383  }
6384  if ( cutoff )
6385  break;
6386  }
6387 
6388  /* free temporary memory */
6389  SCIP_CALL(ZerohalfAuxGraphFree(scip, &auxgraph));
6390 
6391  return SCIP_OKAY;
6392 }
6393 
6394 
6395 
6396 /** separates violated zerohalf cuts using an extended Gaussian elimination. (heuristic; polynomial time) */
6397 static
6399  SCIP* scip, /**< SCIP data structure */
6400  SCIP_SEPA* sepa, /**< separator */
6401  SCIP_SEPADATA* sepadata, /**< separator data */
6402  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
6403  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
6404  char normtype, /**< SCIP normtype */
6405  int maxsepacuts, /**< maximal number of zerohalf cuts separated per separation round */
6406  int maxcuts, /**< maximal number of zerohalf cuts found per separation round (incl. ineff. cuts) */
6407  int* nsepacuts, /**< pointer to store current number of separated zerohalf cuts */
6408  int* nzerohalfcuts, /**< pointer to store current number of found zerohalf cuts */
6409  ZEROHALF_CUTDATA** zerohalfcuts, /**< array to store found zerohalf cuts */
6410  SCIP_Real** varsolvals, /**< dense variable LP solution vector */
6411  SCIP_RESULT* result /**< pointer to SCIP result value of separation */
6412  )
6413 {
6414  int pivotrow;
6415  int pivotcol;
6416  int identsubmatrixsize;
6417  int rowsbind;
6418  BITARRAYBITMASKTYPE rowsbmask;
6419  int r;
6420  int temp;
6421 
6422  assert(scip != NULL);
6423  assert(sepadata != NULL);
6424  assert(lpdata != NULL);
6425  assert(mod2data != NULL);
6426  assert(maxsepacuts >= 0);
6427  assert(maxcuts >= 0);
6428  assert(nsepacuts != NULL);
6429  assert(nzerohalfcuts != NULL);
6430  assert(zerohalfcuts != NULL);
6431  assert(*nsepacuts <= *nzerohalfcuts);
6432  assert(varsolvals != NULL);
6433  assert(result != NULL);
6434 
6435 
6436  /* check if( A mod 2, b mod 2) is empty */
6437  if( mod2data->nrows == 0 || mod2data->nrowsind == 0 )
6438  return SCIP_OKAY;
6439 
6440  /* check if enough cuts have been found */
6441  if( *nsepacuts >= maxsepacuts || *nzerohalfcuts >= maxcuts )
6442  return SCIP_OKAY;
6443 
6444  if( mod2data->nrowsind == 1 )
6445  {
6446  SCIP_CALL(separateByEnumerationHeuristics(scip, sepa, sepadata, lpdata, mod2data,
6447  normtype, maxsepacuts, maxcuts, nsepacuts, nzerohalfcuts, zerohalfcuts,
6448  varsolvals, result, 1));
6449  return SCIP_OKAY;
6450  }
6451 
6452  identsubmatrixsize = 0;
6453 
6454  /* apply Gaussian elimination mod 2 */
6455 
6456  /* choose pivot col */
6457  for( pivotcol = 0; pivotcol < mod2data->ncolsind; ++pivotcol )
6458  {
6459  if( identsubmatrixsize == mod2data->nrowsind )
6460  break;
6461 
6462  /* sort row indices sets w.r.t. to their slack values NON-DECREASINGLY */
6463  SCIPsortInd(mod2data->rowsind + identsubmatrixsize , compRealNonDecreasing ,
6464  (void*) mod2data->slacks , mod2data->nrowsind - identsubmatrixsize);
6465 
6466  /* break if no unprocessed row with slack <= maxslack is left */
6467  if( SCIPisGT(scip, mod2data->slacks[mod2data->rowsind[identsubmatrixsize]], sepadata->maxslack) )
6468  break;
6469 
6470  /* determine pivot row */
6471  rowsbind = (int) GETBITARRAYINDEX(mod2data->colsind[pivotcol]);
6472  rowsbmask = GETBITARRAYMASK(mod2data->colsind[pivotcol]); /*lint !e701*/
6473  for( pivotrow = identsubmatrixsize ; pivotrow < mod2data->nrowsind ; ++pivotrow)
6474  if( mod2data->rows[mod2data->rowsind[pivotrow]][rowsbind] & rowsbmask )
6475  break;
6476  if( pivotrow == mod2data->nrowsind )
6477  continue;
6478 
6479  /* Gaussian elimination step */
6480  for( r = 0 ; r < mod2data->nrowsind
6481  && SCIPisLE(scip, mod2data->slacks[mod2data->rowsind[r]], sepadata->maxslack) ; ++r)
6482  {
6483  if( r == pivotrow )
6484  continue;
6485  if( mod2data->rows[mod2data->rowsind[r]][rowsbind] & rowsbmask )
6486  {
6487  /* add pivot row to r-th row */
6488  mod2data->slacks[mod2data->rowsind[r]] += mod2data->slacks[mod2data->rowsind[pivotrow]];
6489 
6490 #ifndef SCIP_DEBUG
6491  /* avoid expensive operations on rows with slack > maxslack */
6492  if( SCIPisLE(scip, mod2data->slacks[mod2data->rowsind[r]], sepadata->maxslack) )
6493 #endif
6494  {
6495  BITARRAYSXOR(mod2data->rows[mod2data->rowsind[pivotrow]],
6496  mod2data->rows[mod2data->rowsind[r]],mod2data->rowsbitarraysize);
6497  BITARRAYSXOR(mod2data->rowaggregations[mod2data->rowsind[pivotrow]],
6498  mod2data->rowaggregations[mod2data->rowsind[r]],mod2data->rowaggregationsbitarraysize);
6499  mod2data->rhs[mod2data->rowsind[r]] =
6500  XOR(mod2data->rhs[mod2data->rowsind[pivotrow]],mod2data->rhs[mod2data->rowsind[r]]);
6501  }
6502  }
6503  }
6504 
6505  /* swap index set positions */
6506  temp = mod2data->rowsind[pivotrow];
6507  mod2data->rowsind[pivotrow] = mod2data->rowsind[identsubmatrixsize];
6508  mod2data->rowsind[identsubmatrixsize] = temp;
6509  temp = mod2data->colsind[pivotcol];
6510  mod2data->colsind[pivotcol] = mod2data->colsind[identsubmatrixsize];
6511  mod2data->colsind[identsubmatrixsize] = temp;
6512 
6513  identsubmatrixsize++;
6514  }
6515 
6516  /* remove (generated) column singletons */
6517  SCIP_CALL(preprocessColumns(scip, sepadata, lpdata, mod2data,
6518  0, mod2data->ncolsind, FALSE, TRUE, TRUE));
6519 
6520  /* remove zero rows and rows with slack > maxslack */
6521  SCIP_CALL(preprocessRows(scip, sepadata, lpdata, mod2data,
6522  0, mod2data->nrowsind, TRUE, TRUE, FALSE));
6523 
6524  /* search for zerohalf cuts */
6525  SCIP_CALL(preprocessTrivialZerohalfCuts(scip, sepa, sepadata, lpdata, mod2data,
6526  0, mod2data->nrowsind, normtype, maxsepacuts, maxcuts, nsepacuts,
6527  nzerohalfcuts, zerohalfcuts, varsolvals, HEURISTICSGAUSS, result));
6528 
6529  return SCIP_OKAY;
6530 }
6531 
6532 
6533 /** processes subproblem (i.e. runs separation algorithms)*/
6534 static
6536  SCIP* scip, /**< SCIP data structure */
6537  SCIP_SEPA* sepa, /**< separator */
6538  SCIP_SEPADATA* sepadata, /**< separator data */
6539  ZEROHALF_LPDATA* lpdata, /**< data of current LP relaxation */
6540  ZEROHALF_MOD2DATA* mod2data, /**< considered (preprocessed) subproblem mod 2 */
6541  char normtype, /**< SCIP normtype */
6542  int maxsepacuts, /**< maximal number of zerohalf cuts separated per separation round */
6543  int maxcuts, /**< maximal number of zerohalf cuts found per separation round (incl. ineff. cuts) */
6544  int* nsepacuts, /**< pointer to store current number of separated zerohalf cuts */
6545  int* nzerohalfcuts, /**< pointer to store current number of found zerohalf cuts */
6546  ZEROHALF_CUTDATA** zerohalfcuts, /**< array to store found zerohalf cuts */
6547  SCIP_Real** varsolvals, /**< dense variable LP solution vector */
6548  SCIP_RESULT* result /**< pointer to SCIP result value of separation */
6549  )
6550 {
6551  char sepamethod;
6552  int i;
6553  SCIP_Bool stop;
6554 
6555  char sepaname[SCIP_MAXSTRLEN];
6556 #ifdef ZEROHALF__PRINT_STATISTICS
6557  int nsepacutsbefore;
6558  int nsepacutsinitial;
6559  int nzerohalfcutsbefore;
6560  int nzerohalfcutsinitial;
6561  SCIP_CLOCK* timer;
6562  SCIP_CLOCK* sepatimer;
6563 #endif
6564 
6565  int ncutsfoundbefore;
6566  SCIP_Bool wrongstructure;
6567 
6568  assert(scip != NULL);
6569  assert(sepadata != NULL);
6570  assert(lpdata != NULL);
6571  assert(mod2data != NULL);
6572  assert(maxsepacuts >= 0);
6573  assert(maxcuts >= 0);
6574  assert(result != NULL);
6575  assert(nsepacuts != NULL);
6576  assert(nzerohalfcuts != NULL);
6577  assert(zerohalfcuts != NULL);
6578  assert(*nsepacuts <= *nzerohalfcuts);
6579 
6580  assert(mod2data->relatedsubproblem != NULL);
6581  assert(mod2data->rows != NULL);
6582  assert(mod2data->rowaggregations != NULL);
6583  assert(mod2data->rhs != NULL);
6584  assert(mod2data->slacks != NULL);
6585  assert(mod2data->fracsol != NULL);
6586  assert(mod2data->nrows > 0);
6587  assert(mod2data->rowsind != NULL);
6588  assert(mod2data->colsind != NULL);
6589 
6590  sepadata->nsepamethods = (int) strlen(sepadata->sepamethods);
6591  if( sepadata->nsepamethods > 0 && sepadata->sepamethods[0] == '-' )
6592  sepadata->nsepamethods = 0;
6593 
6594  if( sepadata->nsepamethods == 0 )
6595  return SCIP_OKAY;
6596 
6597 
6598  /* statistics */
6599 #ifdef ZEROHALF__PRINT_STATISTICS
6600  if( sepadata->sepatimers == NULL )
6601  {
6602  SCIP_CALL( SCIPallocMemoryArray(scip, &(sepadata->sepatimers), sepadata->nsepamethods + 1) );
6603  for( i = 0 ; i < sepadata->nsepamethods + 1 ; ++i)
6604  {
6605  ZEROHALFcreateTimer((sepadata->sepatimers[i]));
6606  }
6607  SCIP_CALL( SCIPallocMemoryArray(scip, &(sepadata->nsepacutsalgo), sepadata->nsepamethods + 1) );
6608  SCIP_CALL( SCIPallocMemoryArray(scip, &(sepadata->nzerohalfcutsalgo), sepadata->nsepamethods + 1) );
6609  BMSclearMemoryArray(sepadata->nsepacutsalgo, sepadata->nsepamethods + 1);
6610  BMSclearMemoryArray(sepadata->nzerohalfcutsalgo, sepadata->nsepamethods + 1);
6611  }
6612 
6613  nsepacutsinitial = *nsepacuts;
6614  nzerohalfcutsinitial = *nzerohalfcuts;
6615 
6616  ZEROHALFstatisticsMessage("\n");
6617  ZEROHALFstatisticsMessage(" | -------------------------- subproblem ----\
6618 ---------- | - callback (algo) - | ----- callback ---- | --total-\n");
6619  ZEROHALFstatisticsMessage(" | nrowsind | ncolsind | nsepcuts | ncutsfnd \
6620 | time | nsepcuts | ncutsfnd | nsepcuts | ncutsfnd | time\n");
6621  ZEROHALFstatisticsMessage("%15s | %8d | %8d | %8d | %8d | %8.4f | %8s | %8s | %8d | %8d | %8.4f\n",
6622  "START PROCESSG", mod2data->nrowsind, mod2data->ncolsind,
6623  0, 0, 0.0, " ", " ", *nsepacuts, *nzerohalfcuts, ZEROHALFevalTimer(sepadata->sepatimers[sepadata->nsepamethods]));
6624 #endif
6625 
6626  if( mod2data->nrowsind == 0 || mod2data->ncolsind == 0 )
6627  return SCIP_OKAY;
6628 
6629 #ifdef ZEROHALF__PRINT_STATISTICS
6630  ZEROHALFcreateNewTimer(timer);
6631  ZEROHALFcreateNewTimer(sepatimer);
6632  ZEROHALFstartTimer(sepadata->sepatimers[sepadata->nsepamethods]);
6633  ZEROHALFstartTimer(timer);
6634 #endif
6635 
6636  stop = FALSE;
6637  for( i = 0 ; i < sepadata->nsepamethods && !stop; ++i)
6638  {
6639  /* statistics*/
6640 #ifdef ZEROHALF__PRINT_STATISTICS
6641  ZEROHALFstartTimer(sepatimer);
6642  ZEROHALFstartTimer(sepadata->sepatimers[i]);
6643  nsepacutsbefore = *nsepacuts;
6644  nzerohalfcutsbefore = *nzerohalfcuts;
6645 
6646  /* abort if enough cuts have already been found */
6647  if( *nsepacuts >= maxsepacuts || *nzerohalfcuts >= maxcuts )
6648  break;
6649  /* abort if matrix is empty */
6650  if( mod2data->nrowsind == 0 || mod2data->ncolsind == 0 )
6651  break;
6652 #endif
6653 
6654  /* process */
6655  sepamethod = sepadata->sepamethods[i];
6656 
6657  switch(sepamethod)
6658  {
6659  case STOPIFCUTWASFOUND:
6660  if( *nsepacuts > 0 )
6661  {
6662  stop = TRUE;
6663  }
6664  strncpy(sepaname,"nsepcuts>0 ?",SCIP_MAXSTRLEN);
6665  break;
6666  case SOLVEAUXSCIP:
6667  case SOLVEAUXSCIPEXACT:
6668  ncutsfoundbefore = *nzerohalfcuts;
6669  SCIP_CALL(separateBySolvingAuxIP(scip, sepa, sepadata, lpdata, mod2data, normtype,
6670  maxsepacuts, maxcuts, (sepamethod == SOLVEAUXSCIP),
6671  nsepacuts, nzerohalfcuts, zerohalfcuts, varsolvals, result));/*lint !e641*/
6672  strncpy(sepaname,"auxiliary ip",SCIP_MAXSTRLEN);
6673  if( *nzerohalfcuts == ncutsfoundbefore )
6674  {
6675  /* no violated cut has been found. hence a proof of non-existence is given */
6676  stop = TRUE;
6677  }
6678  break;
6679  case ENUMHEURNMAX1:
6680  SCIP_CALL(separateByEnumerationHeuristics(scip, sepa, sepadata, lpdata, mod2data, normtype, maxsepacuts,
6681  maxcuts, nsepacuts, nzerohalfcuts, zerohalfcuts, varsolvals, result, 1));
6682  strncpy(sepaname,"enum k=1",SCIP_MAXSTRLEN);
6683  break;
6684  case ENUMHEURNMAX2:
6685  SCIP_CALL(separateByEnumerationHeuristics(scip, sepa, sepadata, lpdata, mod2data, normtype, maxsepacuts,
6686  maxcuts, nsepacuts, nzerohalfcuts, zerohalfcuts, varsolvals, result, 2));
6687  strncpy(sepaname,"enum k=1..2",SCIP_MAXSTRLEN);
6688  break;
6689  case GAUSSHEUR:
6690  SCIP_CALL(separateByGaussHeuristics(scip, sepa, sepadata, lpdata, mod2data, normtype, maxsepacuts, maxcuts,
6691  nsepacuts, nzerohalfcuts, zerohalfcuts, varsolvals, result));
6692  strncpy(sepaname,"Gauss heur",SCIP_MAXSTRLEN);
6693  break;
6694  case MAX2ODDENTRIESPERROW:
6695  ncutsfoundbefore = *nzerohalfcuts;
6696  SCIP_CALL(separateByAuxGraph(scip, sepa, sepadata, lpdata, mod2data, normtype, maxsepacuts, maxcuts,
6697  nsepacuts, nzerohalfcuts, zerohalfcuts, varsolvals, result, &wrongstructure));
6698  strncpy(sepaname,"auxgraph",SCIP_MAXSTRLEN);
6699  if( ! wrongstructure )
6700  {
6701  if( *nzerohalfcuts == ncutsfoundbefore )
6702  {
6703  /* no violated cut has been found. hence a proof of non-existence is given */
6704  stop = TRUE;
6705  }
6706  }
6707  break;
6708  default:
6709  SCIPerrorMessage("invalid sepamethod '%c'\n", sepadata->sepamethods[i]);
6710  return SCIP_INVALIDDATA;
6711  }
6712 
6713 #ifdef ZEROHALF__PRINT_STATISTICS
6714  /* statistics */
6715  ZEROHALFstopTimer(sepadata->sepatimers[i]);
6716  ZEROHALFstopTimer(sepatimer);
6717  sepadata->nsepacutsalgo[i] += *nsepacuts - nsepacutsbefore;
6718  sepadata->nzerohalfcutsalgo[i] += *nzerohalfcuts - nzerohalfcutsbefore;
6719  ZEROHALFstatisticsMessage("%15s | %8d | %8d | %8d | %8d | %8.4f | %8d | %8d | %8d | %8d | %8.4f\n",
6720  sepaname, mod2data->nrowsind, mod2data->ncolsind,
6721  *nsepacuts - nsepacutsbefore, *nzerohalfcuts - nzerohalfcutsbefore,
6722  ZEROHALFevalTimer(sepatimer),
6723  sepadata->nsepacutsalgo[i], sepadata->nzerohalfcutsalgo[i],
6724  *nsepacuts, *nzerohalfcuts, ZEROHALFevalTimer(sepadata->sepatimers[i]));
6725  ZEROHALFresetTimer(sepatimer);
6726 #endif
6727  }
6728 
6729 #ifdef ZEROHALF__PRINT_STATISTICS
6730  /* statistics */
6731  ZEROHALFstopTimer(timer);
6732  ZEROHALFstatisticsMessage("%15s | %8d | %8d | %8d | %8d | %8.4f | %8s | %8s | %8d | %8d | %8.4f\n",
6733  "PROCESSED", mod2data->nrowsind, mod2data->ncolsind,
6734  *nsepacuts - nsepacutsinitial , *nzerohalfcuts - nzerohalfcutsinitial,
6735  ZEROHALFevalTimer(timer), " ", " ", *nsepacuts, *nzerohalfcuts,
6736  ZEROHALFevalTimer(sepadata->sepatimers[sepadata->nsepamethods]));
6737  ZEROHALFfreeTimer(timer);
6738  ZEROHALFfreeTimer(sepatimer);
6739  ZEROHALFstopTimer(sepadata->sepatimers[sepadata->nsepamethods]);
6740 #endif
6741 
6742  return SCIP_OKAY;
6743 }
6744 
6745 
6746 #ifdef ZEROHALF__PRINT_STATISTICS
6747 /** prints statistical information about the found zerohalfcuts as table */
6748 static
6749 void printZerohalfCutsStatistics(
6750  SCIP* scip, /**< SCIP data structure */
6751  ZEROHALF_CUTDATA** zerohalfcuts, /**< array of zerohalf cuts */
6752  int nzerohalfcuts, /**< number of zerohalf cuts */
6753  int* zerohalfcutsindices,/**< sorted index set (or NULL) */
6754  SCIP_Real* zerohalfcutsprios, /**< sorted priorities (or NULL) */
6755  SCIP_Real* zerohalfcutsminortho,/**< sorted minimal orthogonalities (or NULL) */
6756  int nsepacuts /**< number of separated zerohalf cuts */
6757  )
6758 {
6759  ZEROHALF_CUTDATA* cut;
6760  int si;
6761  int i;
6762 
6763  assert(scip != NULL);
6764  assert(zerohalfcuts != NULL);
6765  assert(nzerohalfcuts >= 0);
6766 
6767  ZEROHALFstatisticsMessage("\n");
6768  ZEROHALFstatisticsMessage(" NZEROHALFCUTS: %6d\n", nzerohalfcuts);
6769  ZEROHALFstatisticsMessage(" NSEPACUTS: %6d\n", nsepacuts);
6770 
6771  if( nzerohalfcuts == 0 )
6772  return;
6773 
6774  ZEROHALFstatisticsMessage("%15s | index | A | viol | efficacy | ef? \
6775 | minortho | #nonz | norm | #origrows | #preprows | by | priority\n", " ");
6776  for( i = 0 ; i < nzerohalfcuts ; ++i)
6777  {
6778  if( zerohalfcutsindices == NULL )
6779  si = i;
6780  else
6781  si = zerohalfcutsindices[i];
6782  assert(0 <= i);
6783  assert(i < nzerohalfcuts);
6784  cut = zerohalfcuts[si];
6785  ZEROHALFstatisticsMessage("%15s | %6d | %1s | %8f | %8f | %3s | %8f | %8d | %8.2f | %9d | %9d | %2s | %8.6f\n",
6786  "ZEROHALFCUT", si,
6787  cut->addedtolp ? "A" : "-",
6788  cut->violation, cut->efficacy,
6789  SCIPisEfficacious(scip, cut->efficacy) ? "yes" : " no",
6790  zerohalfcutsminortho != NULL ? zerohalfcutsminortho[i] : 0.0,
6791  cut->nnonz, cut->norm, cut->nrowsincut, cut->nrrowsincut,
6792  (cut->separatedby == AUXIP ? "IP" :
6793  (cut->separatedby == DECOMPOSITION ? "DC" :
6794  (cut->separatedby == PPZEROONEROW ? "PP" :
6795  (cut->separatedby == HEURISTICSENUM ? "HE" :
6796  (cut->separatedby == HEURISTICSGAUSS ? "HG" :
6797  (cut->separatedby == AUXGRAPH ? "2R" :
6798  "?"
6799  )))))),
6800  zerohalfcutsprios != NULL ? zerohalfcutsprios[i] : 0.0
6801  );
6802  }
6803 }
6804 #endif
6805 
6806 
6807 
6808 /* --------------------------------------------------------------------------------------------------------------------
6809  * callback methods of separator
6810  * -------------------------------------------------------------------------------------------------------------------- */
6811 
6812 
6813 /** copy method for separator plugins (called when SCIP copies plugins) */
6814 static
6815 SCIP_DECL_SEPACOPY(sepaCopyZerohalf)
6816 { /*lint --e{715}*/
6817  assert(scip != NULL);
6818  assert(sepa != NULL);
6819  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
6820 
6821  /* call inclusion method of constraint handler */
6823 
6824  return SCIP_OKAY;
6825 }
6826 
6827 /** destructor of separator to free user data (called when SCIP is exiting) */
6828 static
6829 SCIP_DECL_SEPAFREE(sepaFreeZerohalf)
6830 {
6831  SCIP_SEPADATA* sepadata;
6832 
6833  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
6834 
6835  /* free separator data */
6836  sepadata = SCIPsepaGetData(sepa);
6837  assert(sepadata != NULL);
6838 
6839  if( sepadata->pptimers != NULL )
6840  {
6841 #ifdef ZEROHALF__PRINT_STATISTICS
6842  int i;
6843 
6844  for( i = 0 ; i < sepadata->nppmethods + 1 ; ++i)
6845  {
6846  ZEROHALFfreeTimer((sepadata->pptimers[i]));
6847  }
6848 #endif
6849  SCIPfreeMemoryArray(scip, &(sepadata->pptimers));
6850  }
6851 
6852  if( sepadata->sepatimers != NULL )
6853  {
6854 #ifdef ZEROHALF__PRINT_STATISTICS
6855  int i;
6856 
6857  for( i = 0 ; i < sepadata->nsepamethods + 1 ; ++i)
6858  {
6859  ZEROHALFfreeTimer((sepadata->sepatimers[i]));
6860  }
6861 #endif
6862  SCIPfreeMemoryArray(scip, &(sepadata->sepatimers));
6863  }
6864 
6865 #ifdef ZEROHALF__PRINT_STATISTICS
6866  if( sepadata->dtimer != NULL )
6867  {
6868  ZEROHALFfreeTimer((sepadata->dtimer));
6869  }
6870 #endif
6871 
6872  if( sepadata->nsepacutsalgo != NULL )
6873  {
6874  SCIPfreeMemoryArray(scip, &(sepadata->nsepacutsalgo));
6875  }
6876  if( sepadata->nzerohalfcutsalgo != NULL )
6877  {
6878  SCIPfreeMemoryArray(scip, &(sepadata->nzerohalfcutsalgo));
6879  }
6880  if( sepadata->origrows != NULL )
6881  {
6882  SCIPfreeMemoryArray(scip, &(sepadata->origrows));
6883  }
6884  SCIPfreeMemory(scip, &sepadata);
6885  SCIPsepaSetData(sepa, NULL);
6886 
6887  return SCIP_OKAY;
6888 }
6889 
6890 
6891 /** LP solution separation method of separator */
6892 static
6893 SCIP_DECL_SEPAEXECLP(sepaExeclpZerohalf)
6894 {
6895  SCIP_SEPADATA* sepadata;
6896  ZEROHALF_LPDATA* lpdata;
6897  ZEROHALF_MOD2DATA* mod2data;
6898  ZEROHALF_CUTDATA** zerohalfcuts;
6899  SCIP_Real* varsolvals;
6900  SCIP_Real* subproblempriorities;
6901  int* sortedsubproblems;
6902  int ncalls;
6903  int depth;
6904  int maxsepacuts;
6905  int maxcuts;
6906  int nsepacuts;
6907  int nzerohalfcuts;
6908  int subproblemindex;
6909  int i;
6910  int j;
6911  char normtype;
6912  SCIP_Longint totalncalls;
6913  SCIP_Real nrcolsfactor;
6914  SCIP_Bool cutoff = FALSE;
6915 
6916  assert(sepa != NULL);
6917  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
6918  assert(scip != NULL);
6919  assert(result != NULL);
6920 
6921  *result = SCIP_DIDNOTRUN;
6922  sepadata = SCIPsepaGetData(sepa);
6923  assert(sepadata != NULL);
6924  depth = SCIPgetDepth(scip);
6925  ncalls = SCIPsepaGetNCallsAtNode(sepa);
6926  totalncalls = SCIPsepaGetNCalls(sepa);
6927 
6928  /* only call separator, if we are not close to terminating */
6929  if( SCIPisStopped(scip) )
6930  return SCIP_OKAY;
6931 
6932  /* only call the {0,1/2}-cut separator a given number of times at all */
6933  if( sepadata->maxncalls > -1 && totalncalls > sepadata->maxncalls - 1 )
6934  return SCIP_OKAY;
6935 
6936  /* only call the {0,1/2}-cut separator a given number of times at each node */
6937  if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
6938  || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
6939  return SCIP_OKAY;
6940 
6941  /* only call separator if depth<=maxdepth or maxdepth unlimited */
6942  if( sepadata->maxdepth > -1 && depth > sepadata->maxdepth )
6943  return SCIP_OKAY;
6944 
6945  /* only call separator, if an optimal LP solution is at hand */
6947  return SCIP_OKAY;
6948 
6949  /* only call separator, if there are fractional variables */
6950  if( SCIPgetNLPBranchCands(scip) == 0 )
6951  return SCIP_OKAY;
6952 
6953  /* allocate temporary memory for LP data structures */
6954  SCIP_CALL(ZerohalfLPDataCreate(scip, &lpdata));
6955 
6956  /* get variables data */
6957  SCIP_CALL(SCIPgetVarsData(scip, &(lpdata->vars), &(lpdata->nvars), NULL, NULL, NULL, NULL));
6958 
6959  /* get LP data */
6960  SCIP_CALL(SCIPgetLPColsData(scip, &(lpdata->cols), &(lpdata->ncols)));
6961  SCIP_CALL(SCIPgetLPRowsData(scip, &(lpdata->rows), &(lpdata->nrows)));
6962  if( lpdata->ncols == 0 || lpdata->nrows == 0 )
6963  {
6964  SCIP_CALL(ZerohalfLPDataFree(scip, &lpdata));
6965  return SCIP_OKAY;
6966  }
6967 
6968  /* store original LP rows indices if necessary */
6969  if( sepadata->onlyorigrows && sepadata->origrows == NULL )
6970  {
6971  SCIP_Bool issorted;
6972  int temp;
6973 
6974  SCIP_CALL( SCIPallocMemoryArray(scip, &(sepadata->origrows), lpdata->nrows) );
6975  for( i = 0 ; i < lpdata->nrows ; ++i )
6976  sepadata->origrows[i] = SCIProwGetIndex(lpdata->rows[i]);
6977  sepadata->norigrows = lpdata->nrows;
6978 
6979  /* bubble sort indices (s.t. binary search can be used to find an index) */
6980  do
6981  {
6982  issorted = TRUE;
6983  for( i = 0 ; i < sepadata->norigrows - 1 ; ++i )
6984  {
6985  if( sepadata->origrows[i] > sepadata->origrows[i+1] )
6986  {
6987  temp = sepadata->origrows[i];
6988  sepadata->origrows[i] = sepadata->origrows[i+1];
6989  sepadata->origrows[i+1] = temp;
6990  issorted = FALSE;
6991  }
6992  }
6993  }
6994  while( !issorted );
6995  }
6996 
6997  /* get the maximal number of cuts allowed in a separation round */
6998  if( depth == 0 )
6999  {
7000  maxcuts = sepadata->maxcutsroot;
7001  maxsepacuts = MIN(maxcuts, sepadata->maxsepacutsroot);
7002  }
7003  else
7004  {
7005  maxcuts = sepadata->maxcuts;
7006  maxsepacuts = MIN(maxcuts, sepadata->maxsepacuts);
7007  }
7008 
7009  /* only call the {0,1/2}-cut separator if at least one cut is allowed in a separation round */
7010  if( maxsepacuts == 0 )
7011  {
7012  SCIP_CALL(ZerohalfLPDataFree(scip, &lpdata));
7013  return SCIP_OKAY;
7014  }
7015 
7016 
7017 #ifdef ZEROHALF__PRINT_STATISTICS
7018  ZEROHALFstatisticsMessage("= SEPA_ZEROHALF ================================================================\
7019 s=============================================\n");
7020 #endif
7021 
7022  /* allocate further temporary memory */
7023  SCIP_CALL(SCIPallocMemoryArray(scip, &(lpdata->intscalarsleftrow), lpdata->nrows));
7024  SCIP_CALL(SCIPallocMemoryArray(scip, &(lpdata->intscalarsrightrow), lpdata->nrows));
7025 
7026  /* initialize */
7027  BMSclearMemoryArray(lpdata->intscalarsleftrow, lpdata->nrows);
7028  BMSclearMemoryArray(lpdata->intscalarsrightrow, lpdata->nrows);
7029 
7030  *result = SCIP_DIDNOTFIND;
7031  sepadata->maxslack = 1.0 - 2.0 * sepadata->minviolation;
7032  nsepacuts = 0;
7033  nzerohalfcuts = 0;
7034  varsolvals = NULL;
7035  SCIP_CALL(SCIPgetCharParam(scip, "separating/efficacynorm", &normtype));
7036 
7037 #ifdef ZEROHALF__PRINT_STATISTICS
7038  if( sepadata->nsepamethods > 0 )
7039  {
7040  assert(sepadata->nsepacutsalgo != NULL);
7041  assert(sepadata->nzerohalfcutsalgo != NULL);
7042  BMSclearMemoryArray(sepadata->nsepacutsalgo, sepadata->nsepamethods + 1);
7043  BMSclearMemoryArray(sepadata->nzerohalfcutsalgo, sepadata->nsepamethods + 1);
7044  }
7045 #endif
7046 
7047  /* determine maximal number of nonzeros allowed in a zerohalf cut */
7048  sepadata->maxnnonz = 0;
7049  for( i = 0 ; i < lpdata->nrows ; i++ )
7050  {
7051  sepadata->maxnnonz += SCIProwGetNLPNonz(lpdata->rows[i]);
7052  }
7053  sepadata->maxnnonz = (int) floor( 10.0 * sepadata->maxnnonz / (double) lpdata->nrows);
7054  sepadata->maxnnonz = (int) floor(MIN(0.1 * lpdata->ncols, sepadata->maxnnonz)) + NNONZOFFSET;
7055 
7056  /* search for relevant columns */
7057  SCIP_CALL(getRelevantColumns(scip, lpdata));
7058  if( lpdata->subproblems[0]->nrcols == 0 )
7059  {
7060  SCIP_CALL(ZerohalfLPDataFree(scip, &lpdata));
7061  return SCIP_OKAY;
7062  }
7063 
7064  /* search for relevant rows */
7065  SCIP_CALL(getRelevantRows(scip, sepadata, lpdata));
7066  if( lpdata->subproblems[0]->nrrows == 0 )
7067  {
7068  SCIP_CALL(ZerohalfLPDataFree(scip, &lpdata));
7069  return SCIP_OKAY;
7070  }
7071 
7072 #ifdef ZEROHALF__PRINT_STATISTICS
7073  SCIP_CALL( printPreprocessingStatistics(scip, lpdata) );
7074 #endif
7075 
7076  /* try to decompose problem into subproblems (and delete obviously redundant subproblems)*/
7077  if( sepadata->decomposeproblem )
7078  {
7079  SCIP_CALL( decomposeProblem(scip, sepadata, lpdata) );
7080  }
7081 
7082  /* sort subproblems */
7083  SCIP_CALL(SCIPallocBufferArray(scip, &sortedsubproblems, lpdata->nsubproblems));
7084  SCIP_CALL(SCIPallocBufferArray(scip, &subproblempriorities, lpdata->nsubproblems));
7085  nrcolsfactor = 1.0 / (2.0 * lpdata->ncols);
7086  for( i = 0 ; i < lpdata->nsubproblems; ++i)
7087  {
7088  sortedsubproblems[i] = i;
7089  subproblempriorities[i] = ((SCIP_Real) lpdata->subproblems[i]->nrrows)
7090  + nrcolsfactor * ((SCIP_Real) lpdata->subproblems[i]->nrcols);
7091  }
7092  SCIPsortRealInt(subproblempriorities, sortedsubproblems, lpdata->nsubproblems);
7093 
7094  /* allocate temporary memory for storing separated zerohalf cuts */
7095  SCIP_CALL(SCIPallocBufferArray(scip, &zerohalfcuts, maxcuts));
7096 
7097  /* process each subproblem */
7098  for( i = 0; i < lpdata->nsubproblems; ++i )
7099  {
7100  /* check if enough cuts have been found */
7101  if( nsepacuts >= maxsepacuts || nzerohalfcuts >= maxcuts )
7102  break;
7103 
7104  subproblemindex = sortedsubproblems[i];
7105  sepadata->maxslack = 1.0 - 2.0 * sepadata->minviolation; /* ignore previous changes */
7106 
7107  /* if the subproblem consists of a single row a^Tx <= b such that a = 0 and b mod 2 = 1,
7108  * then a violated zerohalf cut can be generated by multiplying this row with 0.5 and rounding down.
7109  */
7110  if( lpdata->subproblems[subproblemindex]->nrrows == 1 && lpdata->subproblems[subproblemindex]->nrcols == 0 )
7111  {
7112  SCIP_Real* weights;
7113 
7114 #ifdef SCIP_DEBUG
7115  SCIP_CALL( debugPrintLPRowsAndCols(scip, lpdata) );
7116  SCIPdebugMessage("\n");
7117  debugPrintSubLpData(scip, lpdata, lpdata->subproblems[subproblemindex]);
7118  SCIPdebugMessage("\n");
7119 #endif
7120  /* create weightvector */
7121  weights = NULL;
7122  SCIP_CALL( getZerohalfWeightvectorForSingleRow(scip, sepadata, lpdata, lpdata->subproblems[subproblemindex]->rrows[0],
7123  0, &weights) );
7124  if( weights == NULL )
7125  continue;
7126 
7127  /* create zerohalf cut */
7128  SCIP_CALL( ZerohalfCutDataCreate(scip, &(zerohalfcuts[nzerohalfcuts]),
7129  lpdata->subproblems[subproblemindex], NULL, 1, 1, DECOMPOSITION) );
7131  lpdata, weights, normtype, nzerohalfcuts, &varsolvals, zerohalfcuts[nzerohalfcuts], &cutoff) );
7132 
7133  if ( cutoff )
7134  *result = SCIP_CUTOFF;
7135  else
7136  {
7137  /* add cut to LP */
7138  SCIP_CALL( addZerohalfCutToLP(scip, sepadata, zerohalfcuts[nzerohalfcuts], &nsepacuts, result) );
7139  nzerohalfcuts++;
7140  }
7141 
7142  /* free weightsvector memory */
7143  SCIPfreeMemoryArray(scip, &weights);
7144 
7145  if ( cutoff )
7146  break;
7147 
7148  if( lpdata->rrowsindexofleftrow[lpdata->subproblems[subproblemindex]->rrows[0]] >= 0 )
7149  lpdata->rrowsindexofleftrow[lpdata->subproblems[subproblemindex]->rrows[0]] =
7151  else
7152  if( lpdata->rrowsindexofrightrow[lpdata->subproblems[subproblemindex]->rrows[0]] >= 0 )
7153  lpdata->rrowsindexofrightrow[lpdata->subproblems[subproblemindex]->rrows[0]] =
7155 
7156  continue;
7157  }
7158  assert( ! cutoff );
7159 
7160  /* check if enough cuts have been found */
7161  if( nsepacuts >= maxsepacuts || nzerohalfcuts >= maxcuts )
7162  break;
7163 
7164  /* allocate temporary memory for data (mod 2) structures */
7165  SCIP_CALL( ZerohalfMod2DataCreate(scip, &mod2data) );
7166 
7167  /* store data (mod 2) */
7168  SCIP_CALL( storeMod2Data(scip, sepadata, lpdata, subproblemindex, mod2data) );
7169 
7170  /* preprocess subproblem: reduce problem size and/or separate 'easy' zerohalf cuts */
7171  SCIP_CALL( preprocess(scip, sepa, sepadata, lpdata, mod2data, normtype, maxsepacuts, maxcuts,
7172  &nsepacuts, &nzerohalfcuts, zerohalfcuts, &varsolvals, result) );
7173 
7174  if( nsepacuts < maxsepacuts || nzerohalfcuts < maxcuts )
7175  {
7176  /* process subproblem: separate violated zerohalf cuts */
7177  SCIP_CALL( process(scip, sepa, sepadata, lpdata, mod2data, normtype, maxsepacuts, maxcuts,
7178  &nsepacuts, &nzerohalfcuts, zerohalfcuts, &varsolvals, result) );
7179  }
7180 
7181  /* free temporary memory */
7182  SCIP_CALL( ZerohalfMod2DataFree(scip, &mod2data) );
7183 
7184  /* update pointer of zerohalfcuts that has become invalid */
7185  for( j = 0 ; j < nzerohalfcuts ; ++j)
7186  zerohalfcuts[j]->relatedmod2data = NULL;
7187  }
7188 
7189 #ifdef ZEROHALF__PRINT_STATISTICS
7190  if( !sepadata->usezhcutpool )
7191  printZerohalfCutsStatistics(scip, zerohalfcuts, nzerohalfcuts, NULL, NULL, NULL, nsepacuts);
7192 #endif
7193 
7194  if( ! cutoff && sepadata->usezhcutpool )
7195  {
7196  ZEROHALF_CUTDATA* cutdatai;
7197  ZEROHALF_CUTDATA* cutdataj;
7198  SCIP_Real* zerohalfcutpriorities;
7199  SCIP_Real* zerohalfcutminortho;
7200  int* sortedzerohalfcuts;
7201  SCIP_Real violationbucketsize;
7202  SCIP_Bool hasminorthogonality;
7203  int si;
7204  int sj;
7205  int nignoredcuts;
7206 
7207  /* allocate temporary memory */
7208  SCIP_CALL(SCIPallocBufferArray(scip, &sortedzerohalfcuts, nzerohalfcuts));
7209  SCIP_CALL(SCIPallocBufferArray(scip, &zerohalfcutpriorities, nzerohalfcuts));
7210  SCIP_CALL(SCIPallocBufferArray(scip, &zerohalfcutminortho, nzerohalfcuts));
7211 
7212  /* initialize */
7213  violationbucketsize = 10.0;
7214  nignoredcuts = 0;
7215 
7216 #if 1 /* old cutpool version */
7217  /* sort zerohalf cutpool w.r.t. the violation (primary) and the density (secondary) */
7218  for( i = 0 ; i < nzerohalfcuts; ++i)
7219  {
7220  sortedzerohalfcuts[i] = i;
7221  zerohalfcutpriorities[i] = SCIPfloor(scip, violationbucketsize * (zerohalfcuts[i])->violation)
7222  + (1.0 - (SCIP_Real) (zerohalfcuts[i])->nnonz / (SCIP_Real) lpdata->ncols);
7223  }
7224  SCIPsortDownRealInt(zerohalfcutpriorities, sortedzerohalfcuts, nzerohalfcuts);
7225 
7226  /* check orthogonality */
7227  for( si = 0; si < nzerohalfcuts; ++si )
7228  {
7229  cutdatai = zerohalfcuts[sortedzerohalfcuts[si]];
7230  if( cutdatai->cut == NULL || !cutdatai->addedtolp )
7231  continue;
7232  hasminorthogonality = TRUE;
7233  for( sj = 0; hasminorthogonality && sj < si; ++sj )
7234  {
7235  cutdataj = zerohalfcuts[sortedzerohalfcuts[sj]];
7236  if( cutdataj->cut != NULL && cutdataj->addedtolp )
7237  if( SCIPisLT(scip, SCIProwGetOrthogonality(cutdatai->cut , cutdataj->cut, ORTHOFUNC),
7238  MINORTHO) )
7239  hasminorthogonality = FALSE;
7240  }
7241 
7242  /* add cut to LP */
7243  if( hasminorthogonality && cutdatai->addedtolp )
7244  {
7245  /* use delayed cutpool for globally valid cuts */
7246  if( sepadata->delayedcuts && !cutdatai->islocal )
7247  {
7248  SCIP_CALL( SCIPaddDelayedPoolCut(scip, cutdatai->cut) );
7249  }
7250  else
7251  {
7252  SCIP_CALL(SCIPaddCut(scip, NULL, cutdatai->cut, sepadata->forcecutstolp, &cutoff) );
7253  if ( cutoff )
7254  {
7255  *result = SCIP_CUTOFF;
7256  break;
7257  }
7258  if( !cutdatai->islocal )
7259  {
7260  SCIP_CALL(SCIPaddPoolCut(scip, cutdatai->cut));
7261  }
7262  cutdatai->addedtolp = TRUE;
7263  }
7264  }
7265  else
7266  {
7267  cutdatai->addedtolp = FALSE;
7268  nignoredcuts++;
7269  }
7270  }
7271  nsepacuts -= nignoredcuts;
7272 
7273 #ifdef ZEROHALF__PRINT_STATISTICS
7274  printZerohalfCutsStatistics(scip, zerohalfcuts, nzerohalfcuts, sortedzerohalfcuts,
7275  zerohalfcutpriorities, NULL, nsepacuts);
7276 #endif
7277 #else /* new cutpool version: does not seem to be better */
7278  {
7279  int ncutpool;
7280  int ncutpoolold;
7281 
7282  ncutpool = 0;
7283 
7284  /* calculate score for all zerohalfcuts in cutpool */
7285  for( i = 0 ; i < nzerohalfcuts; ++i )
7286  {
7287  cutdatai = zerohalfcuts[i];
7288 
7289  if( cutdatai->cut == NULL || !cutdatai->addedtolp )
7290  continue;
7291 
7292  sortedzerohalfcuts[ncutpool] = i;
7293  zerohalfcutminortho[ncutpool] = 1.0;
7294  zerohalfcutpriorities[ncutpool] = SCIPfloor(scip, violationbucketsize * cutdatai->efficacy)
7295  + (1.0 - (SCIP_Real) cutdatai->nnonz / (SCIP_Real) lpdata->ncols)
7296  + SCIPfloor(scip, violationbucketsize * zerohalfcutminortho[ncutpool]);
7297 
7298  ncutpool++;
7299  }
7300  ncutpoolold = ncutpool;
7301 
7302  /* cut selection loop */
7303  while( ncutpool > 0 )
7304  {
7305  SCIP_Real bestscore;
7306  SCIP_Real priotmp;
7307  SCIP_Real minorthotmp;
7308  SCIP_Bool cutoff;
7309  int bestpos;
7310  int sortidxtmp;
7311 
7312  assert(cutdatai->addedtolp);
7313 
7314  bestscore = SCIP_REAL_MIN;
7315  bestpos = -1;
7316 
7317  /* find cut with best (highest) score */
7318  for( i = 0; i < ncutpool; i++ )
7319  {
7320  /* check if cut is current best cut */
7321  if( zerohalfcutpriorities[i] > bestscore )
7322  {
7323  bestscore = zerohalfcutpriorities[i];
7324  bestpos = i;
7325  }
7326  }
7327 
7328  cutdatai = zerohalfcuts[sortedzerohalfcuts[bestpos]];
7329 
7330  /* add best cut to LP */
7331  SCIP_CALL(SCIPaddCut(scip, NULL, cutdatai->cut, sepadata->forcecutstolp), &cutoff);
7332  if ( cutoff )
7333  {
7334  *result = SCIP_CUTOFF;
7335  break;
7336  }
7337  if( !cutdatai->islocal )
7338  {
7339  SCIP_CALL(SCIPaddPoolCut(scip, cutdatai->cut));
7340  }
7341 
7342  priotmp = zerohalfcutpriorities[bestpos];
7343  minorthotmp = zerohalfcutminortho[bestpos];
7344  sortidxtmp = sortedzerohalfcuts[bestpos];
7345 
7346  /* delete best cut from cutpool */
7347  zerohalfcutpriorities[bestpos] = zerohalfcutpriorities[ncutpool-1];
7348  zerohalfcutminortho[bestpos] = zerohalfcutminortho[ncutpool-1];
7349  sortedzerohalfcuts[bestpos] = sortedzerohalfcuts[ncutpool-1];
7350  ncutpool--;
7351 
7352  /* save data for statistic output */
7353  zerohalfcutpriorities[ncutpool] = priotmp;
7354  zerohalfcutminortho[ncutpool] = minorthotmp;
7355  sortedzerohalfcuts[ncutpool] = sortidxtmp;
7356 
7357  /* update orthogonalities of remaining cuts in cutpool */
7358  j = 0;
7359  while( j < ncutpool )
7360  {
7361  SCIP_Real thisortho;
7362 
7363  cutdataj = zerohalfcuts[sortedzerohalfcuts[j]];
7364  thisortho = SCIProwGetOrthogonality(cutdatai->cut , cutdataj->cut, ORTHOFUNC);
7365 
7366  if( thisortho < MINORTHO )
7367  {
7368  priotmp = zerohalfcutpriorities[j];
7369  minorthotmp = zerohalfcutminortho[j];
7370  sortidxtmp = sortedzerohalfcuts[j];
7371 
7372  /* delete cut from cutpool */
7373  zerohalfcutpriorities[j] = zerohalfcutpriorities[ncutpool-1];
7374  zerohalfcutminortho[j] = zerohalfcutminortho[ncutpool-1];
7375  sortedzerohalfcuts[j] = sortedzerohalfcuts[ncutpool-1];
7376  cutdataj->addedtolp = FALSE;
7377  ncutpool--;
7378  nignoredcuts++;
7379 
7380  /* save data for statistic output */
7381  zerohalfcutpriorities[ncutpool] = priotmp;
7382  zerohalfcutminortho[ncutpool] = minorthotmp;
7383  sortedzerohalfcuts[ncutpool] = sortidxtmp;
7384  }
7385  else
7386  {
7387  /* update score */
7388  if( thisortho < zerohalfcutminortho[j] )
7389  {
7390  zerohalfcutminortho[j] = thisortho;
7391  zerohalfcutpriorities[j] = SCIPfloor(scip, violationbucketsize * cutdataj->efficacy)
7392  + (1.0 - (SCIP_Real) cutdataj->nnonz / (SCIP_Real) lpdata->ncols)
7393  + SCIPfloor(scip, violationbucketsize * zerohalfcutminortho[j]);
7394  }
7395  j++;
7396  }
7397  }
7398  }
7399  nsepacuts -= nignoredcuts;
7400 
7401 #ifdef ZEROHALF__PRINT_STATISTICS
7402  printZerohalfCutsStatistics(scip, zerohalfcuts, ncutpoolold, sortedzerohalfcuts,
7403  zerohalfcutpriorities, zerohalfcutminortho, nsepacuts);
7404 #endif
7405  }
7406 #endif
7407 
7408  /* free temporary memory */
7409  SCIPfreeBufferArray(scip, &zerohalfcutminortho);
7410  SCIPfreeBufferArray(scip, &zerohalfcutpriorities);
7411  SCIPfreeBufferArray(scip, &sortedzerohalfcuts);
7412  }
7413 
7414  sepadata->totalncutsfound += nzerohalfcuts;
7415  sepadata->totalnsepacuts += nsepacuts;
7416 
7417  /* free temporary memory */
7418  if( varsolvals != NULL )
7419  {
7420  SCIPfreeMemoryArray(scip, &varsolvals);
7421  }
7422 
7423  for( i = 0 ; i < nzerohalfcuts ; ++i)
7424  {
7425  SCIP_CALL( ZerohalfCutDataFree(scip, &(zerohalfcuts[i])) );
7426  }
7427  SCIPfreeBufferArray(scip, &zerohalfcuts);
7428  SCIPfreeBufferArray(scip, &subproblempriorities);
7429  SCIPfreeBufferArray(scip, &sortedsubproblems);
7430  SCIP_CALL( ZerohalfLPDataFree(scip, &lpdata) );
7431 
7432  return SCIP_OKAY;
7433 }
7434 
7435 
7436 /* --------------------------------------------------------------------------------------------------------------------
7437  * separator specific interface methods
7438  * -------------------------------------------------------------------------------------------------------------------- */
7439 
7440 /** creates the zerohalf separator and includes it in SCIP */
7442  SCIP* scip /**< SCIP data structure */
7443  )
7444 {
7445  SCIP_SEPADATA* sepadata;
7446  SCIP_SEPA* sepa;
7447 
7448  /* description of the preprocessing methods parameter */
7449  char preprocessingmethodsdescription[SCIP_MAXSTRLEN];
7450  /* description of the sepamethods parameter */
7451  char sepamethodsdescription[SCIP_MAXSTRLEN];
7452  /* description of the subscip parameter */
7453  char subscipobjectivedescription[SCIP_MAXSTRLEN];
7454  int ncharsprinted;
7455 
7456  ncharsprinted = SCIPmemccpy(preprocessingmethodsdescription,
7457  "preprocessing methods and ordering:\n"
7458  " # 'd' columns with small LP solution,\n"
7459  " # 'G' modified Gaussian elimination,\n"
7460  " # 'i' identical columns,\n"
7461  " # 'I' identical rows,\n"
7462  " # 'L' large slack rows,\n"
7463  " # 'M' large slack rows (minslack),\n"
7464  " # 's' column singletons,\n", '\0', SCIP_MAXSTRLEN - 1);
7465 
7466  assert(ncharsprinted > 0 && ncharsprinted < SCIP_MAXSTRLEN);
7467 
7468  ncharsprinted += SCIPmemccpy(&(preprocessingmethodsdescription[ncharsprinted - 1]),
7469  " # 'X' add trivial zerohalf cuts,\n"
7470  " # 'z' zero columns,\n"
7471  " # 'Z' zero rows,\n"
7472  " # 'C' fast {'z','s'},\n"
7473  " # 'R' fast {'Z','L','I'}\n"
7474  " #\n"
7475  " # '-' no preprocessing\n"
7476  " #", '\0', (unsigned int) (SCIP_MAXSTRLEN - ncharsprinted - 1));
7477 
7478  assert(ncharsprinted > 0 && ncharsprinted < SCIP_MAXSTRLEN);
7479 
7480  ncharsprinted = SCIPmemccpy(sepamethodsdescription,
7481  "separating methods and ordering:\n"
7482  " # '!' stop further processing if a cut was found,\n"
7483  " # '2' exact polynomial time algorithm (only if matrix has max 2 odd entries per row),\n"
7484  " # 'e' enumeration heuristics (k=1: try all preprocessed rows),\n"
7485  " # 'E' enumeration heuristics (k=2: try all combinations of up to two preprocessed rows),\n"
7486  " # 'g' Extended Gaussian elimination heuristics,\n", '\0', SCIP_MAXSTRLEN - 1);
7487 
7488  assert(ncharsprinted > 0 && ncharsprinted < SCIP_MAXSTRLEN);
7489 
7490  ncharsprinted += SCIPmemccpy(&(sepamethodsdescription[ncharsprinted - 1]),
7491  " # 's' auxiliary IP heuristics (i.e. number of solved nodes is limited)\n"
7492  " # 'S' auxiliary IP exact (i.e. unlimited number of nodes)\n"
7493  " #\n"
7494  " # '-' no processing\n"
7495  " #", '\0', (unsigned int) (SCIP_MAXSTRLEN - ncharsprinted - 1));
7496 
7497  assert(ncharsprinted > 0 && ncharsprinted < SCIP_MAXSTRLEN);
7498 
7499  ncharsprinted = SCIPmemccpy(subscipobjectivedescription,
7500  "auxiliary IP objective:\n"
7501  " # 'v' maximize cut violation,\n"
7502  " # 'u' minimize number of aggregated rows in cut,\n"
7503  " # 'w' minimize number of aggregated rows in cut\n"
7504  " # weighted by the number of rows in the aggregation,\n", '\0', SCIP_MAXSTRLEN - 1);
7505 
7506  assert(ncharsprinted > 0 && ncharsprinted < SCIP_MAXSTRLEN);
7507 
7508  ncharsprinted += SCIPmemccpy(&(subscipobjectivedescription[ncharsprinted - 1]),
7509  " # 'p' maximize cut violation and penalize a high number\n"
7510  " # of aggregated rows in the cut weighted by the number\n"
7511  " # of rows in the aggregation and the penalty factor p\n"
7512  " #", '\0', (unsigned int) (SCIP_MAXSTRLEN - ncharsprinted - 1));
7513 
7514  assert(ncharsprinted > 0 && ncharsprinted < SCIP_MAXSTRLEN);
7515 
7516  /* create zerohalf separator data */
7517  SCIP_CALL(SCIPallocMemory(scip, &sepadata));
7518 
7519  /* initialize statistics */
7520  sepadata->totalncutsfound = 0;
7521  sepadata->totalnsepacuts = 0;
7522  sepadata->pptimers = NULL;
7523  sepadata->dtimer = NULL;
7524  sepadata->sepatimers = NULL;
7525  sepadata->nsepacutsalgo = NULL;
7526  sepadata->nzerohalfcutsalgo = NULL;
7527 
7528  sepadata->ppmethods = NULL;
7529  sepadata->sepamethods = NULL;
7530  sepadata->nppmethods = -1;
7531  sepadata->nsepamethods = -1;
7532  sepadata->subscipsettings = NULL;
7533 
7534  sepadata->norigrows = 0;
7535  sepadata->origrows = NULL;
7536 
7537  /* include separator */
7540  sepaExeclpZerohalf, NULL,
7541  sepadata) );
7542 
7543  assert(sepa != NULL);
7544 
7545  /* set non-NULL pointers to callback methods */
7546  SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyZerohalf) );
7547  SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeZerohalf) );
7548 
7549  /* add zerohalf separator parameters */
7551  "separating/zerohalf/maxrounds",
7552  "maximal number of zerohalf separation rounds per node (-1: unlimited)",
7553  &(sepadata->maxrounds), FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL));
7555  "separating/zerohalf/maxroundsroot",
7556  "maximal number of zerohalf separation rounds in the root node (-1: unlimited)",
7557  &(sepadata->maxroundsroot), FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL));
7559  "separating/zerohalf/maxsepacuts",
7560  "maximal number of {0,1/2}-cuts separated per separation round",
7561  &(sepadata->maxsepacuts), FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL));
7563  "separating/zerohalf/maxsepacutsroot",
7564  "maximal number of {0,1/2}-cuts separated per separation round in the root node",
7565  &(sepadata->maxsepacutsroot), FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL));
7567  "separating/zerohalf/dynamiccuts",
7568  "should generated cuts be removed from the LP if they are no longer tight?",
7569  &(sepadata->dynamiccuts), FALSE, DEFAULT_DYNAMICCUTS, NULL, NULL));
7570 
7571 
7573  "separating/zerohalf/maxcutsfound",
7574  "maximal number of {0,1/2}-cuts determined per separation round\n\
7575  # (this includes separated but inefficacious cuts)",
7576  &(sepadata->maxcuts), TRUE, DEFAULT_MAXCUTS, 0, 1000000, NULL, NULL));
7578  "separating/zerohalf/maxcutsfoundroot",
7579  "maximal number of {0,1/2}-cuts determined per separation round in the root node\n\
7580  # (this includes separated but inefficacious cuts)",
7581  &(sepadata->maxcutsroot), TRUE, DEFAULT_MAXCUTSROOT, 0, 1000000, NULL, NULL));
7582 
7583 
7585  "separating/zerohalf/maxdepth",
7586  "separating cuts only if depth <= maxdepth (-1: unlimited)",
7587  &(sepadata->maxdepth), TRUE, DEFAULT_MAXDEPTH, -1, INT_MAX, NULL, NULL));
7589  "separating/zerohalf/maxncalls",
7590  "maximal number of calls (-1: unlimited)",
7591  &(sepadata->maxncalls), TRUE, DEFAULT_MAXNCALLS, -1LL, SCIP_LONGINT_MAX, NULL, NULL));
7593  "separating/zerohalf/relaxcontvars",
7594  "should continuous variables be relaxed by adding variable bounds?",
7595  &(sepadata->relaxcontvars), TRUE, DEFAULT_RELAXCONTVARS, NULL, NULL)); /**@todo support this */
7597  "separating/zerohalf/scalefraccoeffs",
7598  "should rows be scaled to make fractional coefficients integer?",
7599  &(sepadata->scalefraccoeffs), TRUE, DEFAULT_SCALEFRACCOEFFS, NULL, NULL));
7601  "separating/zerohalf/ignoreprevzhcuts",
7602  "should zerohalf cuts found in previous callbacks ignored?",
7603  &(sepadata->ignoreprevzhcuts), TRUE, DEFAULT_IGNOREPREVIOUSZHCUTS, NULL, NULL));
7605  "separating/zerohalf/onlyorigrows",
7606  "should only original LP rows be considered (i.e. ignore previously added LP rows)?",
7607  &(sepadata->onlyorigrows), TRUE, DEFAULT_ONLYORIGROWS, NULL, NULL));
7608 
7610  "separating/zerohalf/usezhcutpool",
7611  "should zerohalf cuts be filtered using a cutpool?",
7612  &(sepadata->usezhcutpool), TRUE, DEFAULT_USEZHCUTPOOL, NULL, NULL));
7614  "separating/zerohalf/delayedcuts",
7615  "should cuts be added to the delayed cut pool?",
7616  &sepadata->delayedcuts, TRUE, DEFAULT_DELAYEDCUTS, NULL, NULL) );
7617  SCIP_CALL( SCIPaddIntParam(scip,
7618  "separating/zerohalf/maxtestdelta",
7619  "maximal number of different deltas to try for cmir (-1: unlimited, 0: delta=1)",
7620  &sepadata->maxtestdelta, TRUE, DEFAULT_MAXTESTDELTA, -1, INT_MAX, NULL, NULL) );
7622  "separating/zerohalf/trynegscaling",
7623  "should negative values also be tested in scaling for cmir?",
7624  &sepadata->trynegscaling, TRUE, DEFAULT_TRYNEGSCALING, NULL, NULL) );
7625 
7626 
7628  "separating/zerohalf/preprocessing/decomposeproblem",
7629  "should problem be decomposed into subproblems (if possible) before applying preprocessing?",
7630  &(sepadata->decomposeproblem), FALSE, DEFAULT_DECOMPOSEPROBLEM, NULL, NULL));
7632  "separating/zerohalf/preprocessing/delta",
7633  "value of delta parameter used in preprocessing method 'd'",
7634  &(sepadata->ppdelta), FALSE, DEFAULT_PPDELTA, 0.0, 1.0, NULL, NULL));
7636  "separating/zerohalf/preprocessing/ppmethods",
7637  preprocessingmethodsdescription,
7638  &(sepadata->ppmethods), FALSE, DEFAULT_PPMETHODS, NULL, NULL));
7639 
7640 
7641 
7643  "separating/zerohalf/separating/forcecutstolp",
7644  "should the cuts be forced to enter the LP?",
7645  &(sepadata->forcecutstolp), FALSE, DEFAULT_FORCECUTSTOLP, NULL, NULL));
7647  "separating/zerohalf/separating/forcecutstosepastore",
7648  "should the cuts be forced to enter SCIP's sepastore?",
7649  &(sepadata->forcecutstosepastore), FALSE, DEFAULT_FORCECUTSTOSEPASTORE, NULL, NULL));
7651  "separating/zerohalf/separating/minviolation",
7652  "minimal violation of a {0,1/2}-cut to be separated",
7653  &(sepadata->minviolation), FALSE, DEFAULT_MINVIOLATION, 0.001, 0.5, NULL, NULL));
7655  "separating/zerohalf/separating/sepamethods",
7656  sepamethodsdescription,
7657  &(sepadata->sepamethods), FALSE, DEFAULT_SEPAMETHODS, NULL, NULL));
7658 
7659 
7660 
7662  "separating/zerohalf/separating/auxip/settingsfile",
7663  "optional settings file of the auxiliary IP (-: none)",
7664  &(sepadata->subscipsettings), FALSE, DEFAULT_SUBSCIPSETTINGS, NULL, NULL));
7666  "separating/zerohalf/separating/auxip/sollimit",
7667  "limits/solutions setting of the auxiliary IP",
7668  &(sepadata->subscipsollimit), FALSE, DEFAULT_SUBSCIPSOLLIMIT, -1, INT_MAX, NULL, NULL));
7670  "separating/zerohalf/separating/auxip/penaltyfactor",
7671  "penalty factor used with objective function 'p' of auxiliary IP",
7672  &(sepadata->subscipobjpen), FALSE, DEFAULT_SUBSCIPOBJPEN, 0.0, 1.0, NULL, NULL));
7674  "separating/zerohalf/separating/auxip/useallsols",
7675  "should all (proper) solutions of the auxiliary IP be used to generate cuts instead of using only the best?",
7676  &(sepadata->subscipuseallsols), FALSE, DEFAULT_SUBSCIPUSEALLSOLS, NULL, NULL));
7678  "separating/zerohalf/separating/auxip/objective",
7679  subscipobjectivedescription,
7680  &(sepadata->subscipobjective), FALSE, DEFAULT_SUBSCIPOBJECTIVE, "uvwp", NULL, NULL));
7681 
7682  return SCIP_OKAY;
7683 }
7684 
7685