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-2018 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file sepa_zerohalf.c
17  * @brief {0,1/2}-cuts separator
18  * @author Robert Lion Gottwald
19  * @author Manuel Kutschka
20  * @author Kati Wolter
21  *
22  * {0,1/2}-Chvátal-Gomory cuts separator. It solves the following separation problem:
23  * Consider an integer program
24  * \f[
25  * \min \{ c^T x : Ax \leq b, x \geq 0, x \mbox{ integer} \}
26  * \f]
27  * and a fractional solution \f$x^*\f$ of its LP relaxation. Find a weightvector \f$u\f$ whose entries \f$u_i\f$ are either 0 or
28  * \f$\frac{1}{2}\f$ such that the following inequality is valid for all integral solutions and violated by \f$x^*\f$:
29  * \f[
30  * \lfloor(u^T A) x \rfloor \leq \lfloor u^T b\rfloor
31  * \f]
32  *
33  * References:
34  * - Alberto Caprara, Matteo Fischetti. {0,1/2}-Chvatal-Gomory cuts. Math. Programming, Volume 74, p221--235, 1996.
35  * - Arie M. C. A. Koster, Adrian Zymolka and Manuel Kutschka. \n
36  * Algorithms to separate {0,1/2}-Chvatal-Gomory cuts.
37  * Algorithms - ESA 2007: 15th Annual European Symposium, Eilat, Israel, October 8-10, 2007, \n
38  * Proceedings. Lecture Notes in Computer Science, Volume 4698, p. 693--704, 2007.
39  * - Arie M. C. A. Koster, Adrian Zymolka and Manuel Kutschka. \n
40  * Algorithms to separate {0,1/2}-Chvatal-Gomory cuts (Extended Version). \n
41  * ZIB Report 07-10, Zuse Institute Berlin, 2007. http://www.zib.de/Publications/Reports/ZR-07-10.pdf
42  * - Manuel Kutschka. Algorithmen zur Separierung von {0,1/2}-Schnitten. Diplomarbeit. Technische Universitaet Berlin, 2007.
43  */
44 
45 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
46 
47 #include "string.h"
48 #include "scip/sepa_zerohalf.h"
49 #include "scip/cons_linear.h"
50 #include "scip/scipdefplugins.h"
51 #include "scip/struct_lp.h"
52 
53 #define SEPA_NAME "zerohalf"
54 #define SEPA_DESC "{0,1/2}-cuts separator"
55 #define SEPA_PRIORITY -6000
56 #define SEPA_FREQ 10
57 #define SEPA_MAXBOUNDDIST 1.0
58 #define SEPA_USESSUBSCIP FALSE
59 #define SEPA_DELAY FALSE
60 
61 #define DEFAULT_MAXROUNDS 5 /**< maximal number of zerohalf separation rounds per node (-1: unlimited) */
62 #define DEFAULT_MAXROUNDSROOT 20 /**< maximal number of zerohalf separation rounds in the root node (-1: unlimited) */
63 #define DEFAULT_MAXSEPACUTS 20 /**< maximal number of zerohalf cuts separated per separation round */
64 #define DEFAULT_MAXSEPACUTSROOT 100 /**< maximal number of zerohalf cuts separated per separation round in root node */
65 #define DEFAULT_MAXCUTCANDS 2000 /**< maximal number of zerohalf cuts considered per separation round */
66 #define DEFAULT_MAXSLACK 0.0 /**< maximal slack of rows to be used in aggregation */
67 #define DEFAULT_MAXSLACKROOT 0.0 /**< maximal slack of rows to be used in aggregation in the root node */
68 #define DEFAULT_GOODSCORE 0.9 /**< threshold for score of cut relative to best score to be considered good,
69  * so that less strict filtering is applied */
70 #define DEFAULT_BADSCORE 0.5 /**< threshold for score of cut relative to best score to be discarded */
71 #define DEFAULT_MINVIOL 0.1 /**< minimal violation to generate zerohalfcut for */
72 #define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
73 #define DEFAULT_MAXROWDENSITY 0.05 /**< maximal density of row to be used in aggregation */
74 #define DEFAULT_DENSITYOFFSET 100 /**< additional number of variables allowed in row on top of density */
75 
76 /* SCIPcalcRowIntegralScalar parameters */
77 #define MAXDNOM 1000LL
78 #define MAXSCALE 1000.0
79 
80 /* other defines */
81 #define MAXREDUCTIONROUNDS 100 /**< maximum number of rounds to perform reductions on the mod 2 system */
82 #define BOUNDSWITCH 0.5 /**< threshold for bound switching */
83 #define MAXAGGRLEN(nvars) ((int)(0.1*(nvars)+1000))
84 
85 typedef struct Mod2Col MOD2_COL;
86 typedef struct Mod2Row MOD2_ROW;
87 typedef struct Mod2Matrix MOD2_MATRIX;
88 typedef struct TransIntRow TRANSINTROW;
89 typedef struct RowIndex ROWINDEX;
90 
91 /** enum for different types of row indices in ROWINDEX structure */
92 
93 #define ROWIND_TYPE unsigned int
94 #define ORIG_RHS 0u
95 #define ORIG_LHS 1u
96 #define TRANSROW 2u
97 
98 /* macro to get a unique index from the rowindex */
99 #define UNIQUE_INDEX(rowind) (3*(rowind).index + (rowind).type)
101 struct RowIndex
102 {
103  unsigned int type:2; /**< type of row index; 0 means lp row using the right hand side,
104  * 1 means lp row using the left hand side, and 2 means a
105  * transformed integral row */
106  unsigned int index:30; /**< lp position of original row, or index of transformed integral row */
107 };
108 
109 /** structure containing a transformed integral row obtained by relaxing an lp row */
110 struct TransIntRow
111 {
112  SCIP_Real slack; /**< slack of row after transformation */
113  SCIP_Real rhs; /**< right hand side value of integral row after transformation */
114  SCIP_Real* vals; /**< values of row */
115  int* varinds; /**< problem variable indices of row */
116  int size; /**< alloc size of row */
117  int len; /**< length of row */
118  int rank; /**< rank of row */
119  SCIP_Bool local; /**< is row local? */
120 };
121 
122 /** structure representing a row in the mod 2 system */
123 struct Mod2Row
124 {
125  ROWINDEX* rowinds; /**< index set of rows associated with the mod 2 row */
126  MOD2_COL** nonzcols; /**< sorted array of non-zero mod 2 columns in this mod 2 row */
127  SCIP_Real slack; /**< slack of mod 2 row */
128  SCIP_Real maxsolval; /**< maximum solution value of columns in mod 2 row */
129  int index; /**< unique index of mod 2 row */
130  int pos; /**< position of mod 2 row in mod 2 matrix rows array */
131  int rhs; /**< rhs of row */
132  int nrowinds; /**< number of elements in rowinds */
133  int rowindssize; /**< size of rowinds array */
134  int nnonzcols; /**< number of columns in nonzcols */
135  int nonzcolssize; /**< size of nonzcols array */
136 };
137 
138 /** structure representing a column in the mod 2 system */
139 struct Mod2Col
140 {
141  SCIP_HASHSET* nonzrows; /**< the set of rows that contain this column */
142  SCIP_Real solval; /**< solution value of the column */
143  int pos; /**< position of column in matrix */
144  int index; /**< index of SCIP column associated to this column */
145 };
146 
147 /** matrix representing the modulo 2 system */
148 struct Mod2Matrix
149 {
150  MOD2_COL** cols; /**< columns of the matrix */
151  MOD2_ROW** rows; /**< rows of the matrix */
152  TRANSINTROW* transintrows; /**< transformed integral rows obtained from non-integral lp rows */
153  int ntransintrows; /**< number of transformed integral rows obtained from non-integral lp rows */
154  int nzeroslackrows; /**< number of rows with zero slack */
155  int nrows; /**< number of rows of the matrix; number of elements in rows */
156  int ncols; /**< number of cols of the matrix; number of elements in cols */
157  int rowssize; /**< length of rows array */
158  int colssize; /**< length of cols array */
159 };
160 
161 /** data of separator */
162 struct SCIP_SepaData
163 {
164  SCIP_AGGRROW* aggrrow; /**< aggregation row used for generating cuts */
165  SCIP_ROW** cuts; /**< generated in the current call */
166  SCIP_Real* cutscores; /**< score for each cut genereted in the current call */
167  SCIP_Real minviol; /**< minimal violation to generate zerohalfcut for */
168  SCIP_Real maxslack; /**< maximal slack of rows to be used in aggregation */
169  SCIP_Real maxslackroot; /**< maximal slack of rows to be used in aggregation in the root node */
170  SCIP_Real maxrowdensity; /**< maximal density of row to be used in aggregation */
171  SCIP_Real goodscore; /**< threshold for score of cut relative to best score to be considered good,
172  * so that less strict filtering is applied */
173  SCIP_Real badscore; /**< threshold for score of cut relative to best score to be discarded */
174  SCIP_Bool infeasible; /**< infeasibility was detected after adding a zerohalf cut */
175  SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
176  int maxrounds; /**< maximal number of cmir separation rounds per node (-1: unlimited) */
177  int maxroundsroot; /**< maximal number of cmir separation rounds in the root node (-1: unlimited) */
178  int maxsepacuts; /**< maximal number of cmir cuts separated per separation round */
179  int maxsepacutsroot; /**< maximal number of cmir cuts separated per separation round in root node */
180  int maxcutcands; /**< maximal number of zerohalf cuts considered per separation round */
181  int densityoffset; /**< additional number of variables allowed in row on top of density */
182  int cutssize; /**< size of cuts and cutscores arrays */
183  int ncuts; /**< number of cuts generated in the current call */
184  int nreductions; /**< number of reductions to the mod 2 system found so far */
185 };
186 
187 
188 #define COLINFO_GET_MOD2COL(x) ((MOD2_COL*) (((uintptr_t)(x)) & ~((uintptr_t)1)))
189 #define COLINFO_GET_RHSOFFSET(x) ((int) (((uintptr_t)(x)) & ((uintptr_t)1)))
190 #define COLINFO_CREATE(mod2col, rhsoffset) ((void*) (((uintptr_t)(mod2col)) | ((uintptr_t)(rhsoffset))))
192 
193 #ifndef NDEBUG
194 static
195 void checkRow(MOD2_ROW* row)
196 {
197  int i;
198  SCIP_Real maxsolval = 0.0;
199 
200  for( i = 0; i < row->nnonzcols; ++i )
201  {
202  assert(row->nonzcols[i]->solval > 0.0);
203  maxsolval = MAX(maxsolval, row->nonzcols[i]->solval);
204 
205  if( i + 1 < row->nnonzcols )
206  assert(row->nonzcols[i]->index < row->nonzcols[i+1]->index);
207  }
208 
209  assert(row->maxsolval == maxsolval); /*lint !e777*/
210 }
211 #else
212 #define checkRow(x)
213 #endif
214 
215 /** compare to mod 2 columns by there index */
216 static
217 SCIP_DECL_SORTPTRCOMP(compareColIndex)
218 {
219  MOD2_COL* col1;
220  MOD2_COL* col2;
221 
222  col1 = (MOD2_COL*) elem1;
223  col2 = (MOD2_COL*) elem2;
224 
225  if( col1->index < col2->index )
226  return -1;
227  if( col2->index < col1->index )
228  return 1;
229 
230  return 0;
231 }
232 
233 /** comparison function for slack of mod 2 rows */
234 static
235 SCIP_DECL_SORTPTRCOMP(compareRowSlack)
236 {
237  MOD2_ROW* row1;
238  MOD2_ROW* row2;
239  SCIP_Bool slack1iszero;
240  SCIP_Bool slack2iszero;
241 
242  row1 = (MOD2_ROW*) elem1;
243  row2 = (MOD2_ROW*) elem2;
244 
245  slack1iszero = EPSZ(row1->slack, SCIP_DEFAULT_EPSILON);
246  slack2iszero = EPSZ(row2->slack, SCIP_DEFAULT_EPSILON);
247 
248  /* zero slack comes first */
249  if( slack1iszero && !slack2iszero )
250  return -1;
251  if( slack2iszero && !slack1iszero )
252  return 1;
253  if( !slack1iszero && !slack2iszero )
254  return 0;
255 
256  /* prefer rows that contain columns with large solution value */
257  if( row1->maxsolval > row2->maxsolval )
258  return -1;
259  if( row2->maxsolval > row1->maxsolval )
260  return 1;
261 
262  /* rows with less non-zeros come first rows */
263  if( row1->nnonzcols < row2->nnonzcols )
264  return -1;
265  if( row2->nnonzcols < row1->nnonzcols )
266  return 1;
267 
268  return 0;
269 }
270 
271 /** take integral real value modulo 2 */
272 static
273 int mod2(
274  SCIP* scip, /**< scip data structure */
275  SCIP_Real val /**< value to take mod 2 */
276 )
277 {
278  assert(SCIPisFeasIntegral(scip, val));
279  val *= 0.5;
280  return (REALABS(SCIPround(scip, val) - val) > 0.1) ? 1 : 0;
281 }
282 
283 /** returns the integral value for the given scaling parameters, see SCIPcalcIntegralScalar() */
284 static
285 void getIntegralScalar(
286  SCIP_Real val, /**< value that should be scaled to an integral value */
287  SCIP_Real scalar, /**< scalar that should be tried */
288  SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
289  SCIP_Real maxdelta, /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
290  SCIP_Real* sval, /**< pointer to store the scaled value */
291  SCIP_Real* intval /**< pointer to store the scaled integral value */
292  )
293 {
294  SCIP_Real upviol;
295  SCIP_Real downviol;
296  SCIP_Real downval;
297  SCIP_Real upval;
298 
299  assert(mindelta <= 0.0);
300  assert(maxdelta >= 0.0);
301 
302  *sval = val * scalar;
303  downval = floor(*sval);
304  upval = ceil(*sval);
305 
306  downviol = SCIPrelDiff(*sval, downval) - maxdelta;
307  upviol = mindelta - SCIPrelDiff(*sval, upval);
308 
309  if( downviol < upviol )
310  *intval = downval;
311  else
312  *intval = upval;
313 }
314 
315 /** Tries to transform a non-integral row into an integral row that can be used in zerohalf separation */
316 static
318  SCIP* scip, /**< scip data structure */
319  SCIP_Bool allowlocal, /**< should local cuts be allowed */
320  SCIP_Real maxslack, /**< maximum slack allowed for transformed row */
321  int sign, /**< +1 or -1 scale to select the side of the row */
322  SCIP_Bool local, /**< is the row only valid locally? */
323  int rank, /**< rank of row */
324  int rowlen, /**< length of row */
325  SCIP_Real* rowvals, /**< coefficients of columns in row */
326  SCIP_COL** rowcols, /**< columns of row */
327  SCIP_Real rhs, /**< right hand side of row */
328  int* intvarpos, /**< clean buffer array of size SCIPgetNVars that will be clean when the function returns */
329  TRANSINTROW* introw, /**< pointer to return transformed row */
330  SCIP_Bool* success /**< pointer to return whether the transformation succeeded */
331  )
332 {
333  int i;
334  int transrowlen;
335  SCIP_Real transrowrhs;
336  int* transrowvars;
337  SCIP_Real* transrowvals;
338 
339  assert(scip != NULL);
340  assert(sign == +1 || sign == -1);
341  assert(rowvals != NULL || rowlen == 0);
342  assert(rowcols != NULL || rowlen == 0);
343  assert(intvarpos != NULL);
344  assert(introw != NULL);
345  assert(success != NULL);
346 
347  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &transrowvars, rowlen) );
348  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &transrowvals, rowlen) );
349  transrowlen = 0;
350  transrowrhs = rhs;
351 
352  /* first add all integral variables to the transformed row and remember their positions in the row */
353  for( i = 0; i < rowlen; ++i )
354  {
355  if( !SCIPcolIsIntegral(rowcols[i]) ) /*lint !e613*/
356  continue;
357 
358  transrowvars[transrowlen] = rowcols[i]->var_probindex; /*lint !e613*/
359  transrowvals[transrowlen] = sign * rowvals[i]; /*lint !e613*/
360  intvarpos[rowcols[i]->var_probindex] = ++transrowlen; /*lint !e613*/
361  }
362 
363  /* now loop over the non-integral columns of the row and project them out using simple or variable bounds */
364  *success = TRUE;
365 
366  for( i = 0; i < rowlen; ++i )
367  {
368  int closestvbdind;
369  SCIP_Real closestbound;
370  SCIP_VAR* vbdvar;
371  SCIP_Real vbdcoef;
372  SCIP_Real vbdconst;
373  SCIP_VAR* colvar;
374  SCIP_Real val;
375  SCIP_Real closestvbd;
376  SCIP_Bool localbound;
377 
378  if( SCIPcolIsIntegral(rowcols[i]) ) /*lint !e613*/
379  continue;
380 
381  localbound = FALSE;
382 
383  colvar = SCIPcolGetVar(rowcols[i]); /*lint !e613*/
384 
385  val = sign * rowvals[i]; /*lint !e613*/
386 
387  /* if the value is positive we need to use a lower bound constraint */
388  if( val > 0.0 )
389  {
390  /* retrieve simple variable bound */
391  closestbound = SCIPvarGetLbGlobal(colvar);
392  if( allowlocal && SCIPisSumGT(scip, SCIPvarGetLbLocal(colvar), closestbound) )
393  {
394  /* only use local bound if it is better thatn the global bound */
395  closestbound = SCIPvarGetLbLocal(colvar);
396  localbound = TRUE;
397  }
398 
399  /* retrieve closest variable bound */
400  SCIP_CALL( SCIPgetVarClosestVlb(scip, colvar, NULL, &closestvbd, &closestvbdind) );
401 
402  /* if a suitable variable bound exists which is at least as good as a local simple bound
403  * or better than a global simple bound we use it
404  */
405  if( closestvbdind >= 0 && (SCIPisGT(scip, closestvbd, closestbound) || (localbound && SCIPisSumEQ(scip, closestvbd, closestbound))) )
406  {
407  vbdcoef = SCIPvarGetVlbCoefs(colvar)[closestvbdind];
408  vbdvar = SCIPvarGetVlbVars(colvar)[closestvbdind];
409  vbdconst = SCIPvarGetVlbConstants(colvar)[closestvbdind];
410  closestbound = closestvbd;
411  }
412  else
413  {
414  closestvbdind = -1;
415  }
416  }
417  else
418  {
419  /* retrieve simple variable bound */
420  closestbound = SCIPvarGetUbGlobal(colvar);
421  if( allowlocal && SCIPisSumLT(scip, SCIPvarGetUbLocal(colvar), closestbound) )
422  {
423  closestbound = SCIPvarGetUbLocal(colvar);
424  localbound = TRUE;
425  }
426 
427  /* retrieve closest variable bound */
428  SCIP_CALL( SCIPgetVarClosestVub(scip, colvar, NULL, &closestvbd, &closestvbdind) );
429 
430  /* if a suitable variable bound exists which is at least as good as a local simple bound
431  * or better than a global simple bound we use it
432  */
433  if( closestvbdind >= 0 && (SCIPisLT(scip, closestvbd, closestbound) || (localbound && SCIPisSumEQ(scip, closestvbd, closestbound))) )
434  {
435  vbdcoef = SCIPvarGetVubCoefs(colvar)[closestvbdind];
436  vbdvar = SCIPvarGetVubVars(colvar)[closestvbdind];
437  vbdconst = SCIPvarGetVubConstants(colvar)[closestvbdind];
438  closestbound = closestvbd;
439  }
440  else
441  {
442  closestvbdind = -1;
443  }
444  }
445 
446  if( closestvbdind >= 0 )
447  {
448  SCIP_Real coef;
449  int pos;
450 
451  coef = val * vbdcoef; /*lint !e644*/
452  transrowrhs -= val * vbdconst; /*lint !e644*/
453 
454  pos = intvarpos[SCIPvarGetProbindex(vbdvar)] - 1; /*lint !e644*/
455  if( pos >= 0 )
456  {
457  transrowvals[pos] += coef;
458  }
459  else
460  {
461  transrowvars[transrowlen] = SCIPvarGetProbindex(vbdvar);
462  transrowvals[transrowlen] = coef;
463  intvarpos[SCIPvarGetProbindex(vbdvar)] = ++transrowlen;
464  }
465  }
466  else if( !SCIPisInfinity(scip, REALABS(closestbound)) )
467  {
468  local = local || localbound;
469  transrowrhs -= val * closestbound;
470  }
471  else
472  {
473  *success = FALSE;
474  break;
475  }
476  }
477 
478  for( i = 0; i < transrowlen;)
479  {
480  intvarpos[transrowvars[i]] = 0;
481  if( SCIPisZero(scip, transrowvals[i]) )
482  {
483  --transrowlen;
484  transrowvals[i] = transrowvals[transrowlen];
485  transrowvars[i] = transrowvars[transrowlen];
486  }
487  else
488  ++i;
489  }
490 
491  if( transrowlen <= 1 )
492  *success = FALSE;
493 
494  if( *success )
495  {
496  SCIP_Real mindelta;
497  SCIP_Real maxdelta;
498  SCIP_Real intscalar;
499  int nchgcoefs;
500 
501  SCIP_VAR** vars = SCIPgetVars(scip);
502 
503  *success = !SCIPcutsTightenCoefficients(scip, local, transrowvals, &transrowrhs, transrowvars, &transrowlen, &nchgcoefs);
504 
505  mindelta = -SCIPepsilon(scip);
506  maxdelta = SCIPsumepsilon(scip);
507 
508  if( *success )
509  {
510  SCIP_CALL( SCIPcalcIntegralScalar(transrowvals, transrowlen, mindelta, maxdelta, MAXDNOM, MAXSCALE, &intscalar, success) );
511  }
512 
513  if( *success )
514  {
515  SCIP_Real floorrhs;
516  SCIP_Real slack;
517 
518  transrowrhs *= intscalar; /*lint !e644*/
519 
520  /* slack is initialized to zero since the transrowrhs can still change due to bound usage in the loop below;
521  * the floored right hand side is then added afterwards
522  */
523  slack = 0.0;
524  for( i = 0; i < transrowlen; ++i )
525  {
526  SCIP_Real solval = SCIPgetVarSol(scip, vars[transrowvars[i]]);
527  SCIP_Real intval;
528  SCIP_Real newval;
529 
530  getIntegralScalar(transrowvals[i], intscalar, mindelta, maxdelta, &newval, &intval);
531 
532  if( !SCIPisEQ(scip, intval, newval) )
533  {
534  if( intval < newval )
535  {
536  SCIP_Real lb = local ? SCIPvarGetLbLocal(vars[transrowvars[i]]) : SCIPvarGetLbGlobal(vars[transrowvars[i]]);
537 
538  if( SCIPisInfinity(scip, -lb) )
539  {
540  *success = FALSE;
541  break;
542  }
543 
544  transrowrhs += (intval - newval) * lb;
545  }
546  else
547  {
548  SCIP_Real ub = local ? SCIPvarGetUbLocal(vars[transrowvars[i]]) : SCIPvarGetUbGlobal(vars[transrowvars[i]]);
549 
550  if( SCIPisInfinity(scip, ub) )
551  {
552  *success = FALSE;
553  break;
554  }
555 
556  transrowrhs += (intval - newval) * ub;
557  }
558  }
559 
560  slack -= solval * intval;
561  transrowvals[i] = intval;
562  }
563 
564  if( *success )
565  {
566  floorrhs = SCIPfeasFloor(scip, transrowrhs);
567  slack += floorrhs;
568 
569  if( slack <= maxslack )
570  {
571  introw->rhs = floorrhs;
572  introw->slack = slack;
573  introw->vals = transrowvals;
574  introw->varinds = transrowvars;
575  introw->len = transrowlen;
576  introw->size = rowlen;
577  introw->local = local;
578  introw->rank = rank;
579 
580  if( !SCIPisEQ(scip, floorrhs, transrowrhs) )
581  introw->rank += 1;
582  }
583  else
584  {
585  *success = FALSE;
586  }
587  }
588  }
589  }
590 
591  if( !(*success) )
592  {
593  SCIPfreeBlockMemoryArray(scip, &transrowvals, rowlen);
594  SCIPfreeBlockMemoryArray(scip, &transrowvars, rowlen);
595  }
596 
597  return SCIP_OKAY;
598 }
599 
600 
601 /** Tries to transform non-integral rows into an integral form by using simple and variable bounds */
602 static
604  SCIP* scip, /**< scip data structure */
605  SCIP_SEPADATA* sepadata, /**< zerohalf separator data */
606  MOD2_MATRIX* mod2matrix, /**< mod2 matrix structure */
607  SCIP_Bool allowlocal, /**< should local cuts be allowed */
608  SCIP_Real maxslack /**< maximum slack allowed for mod 2 rows */
609  )
610 {
611  SCIP_ROW** rows;
612  int nrows;
613  int* intvarpos;
614  int i;
615  int maxnonzeros;
616  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
617  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &mod2matrix->transintrows, 2*nrows) );
618  mod2matrix->ntransintrows = 0;
619 
620  SCIP_CALL( SCIPallocCleanBufferArray(scip, &intvarpos, SCIPgetNVars(scip)) );
621 
622  maxnonzeros = (int)(SCIPgetNLPCols(scip) * sepadata->maxrowdensity) + sepadata->densityoffset;
623 
624  for( i = 0; i < nrows; ++i )
625  {
626  int rowlen;
627  SCIP_Real activity;
628  SCIP_Real lhs;
629  SCIP_Real rhs;
630  SCIP_Real lhsslack;
631  SCIP_Real rhsslack;
632  SCIP_Real* rowvals;
633  SCIP_COL** rowcols;
634 
635  /* skip integral rows and rows not suitable for generating cuts */
636  if( SCIProwIsModifiable(rows[i]) || SCIProwIsIntegral(rows[i]) || (SCIProwIsLocal(rows[i]) && !allowlocal) || SCIProwGetNNonz(rows[i]) > maxnonzeros )
637  continue;
638 
639  lhs = SCIProwGetLhs(rows[i]) - SCIProwGetConstant(rows[i]);
640  rhs = SCIProwGetRhs(rows[i]) - SCIProwGetConstant(rows[i]);
641  activity = SCIPgetRowLPActivity(scip, rows[i]) - SCIProwGetConstant(rows[i]);
642 
643  /* compute lhsslack: activity - lhs */
644  if( SCIPisInfinity(scip, -SCIProwGetLhs(rows[i])) )
645  lhsslack = SCIPinfinity(scip);
646  else
647  {
648  lhsslack = activity - lhs;
649  }
650 
651  /* compute rhsslack: rhs - activity */
652  if( SCIPisInfinity(scip, SCIProwGetRhs(rows[i])) )
653  rhsslack = SCIPinfinity(scip);
654  else
655  rhsslack = rhs - activity;
656 
657  if( rhsslack > maxslack && lhsslack > maxslack )
658  continue;
659 
660  rowlen = SCIProwGetNLPNonz(rows[i]);
661  rowvals = SCIProwGetVals(rows[i]);
662  rowcols = SCIProwGetCols(rows[i]);
663 
664  if( rhsslack <= maxslack )
665  {
666  SCIP_Bool success;
667  TRANSINTROW* introw = &mod2matrix->transintrows[mod2matrix->ntransintrows];
668  SCIP_CALL( transformNonIntegralRow(scip, allowlocal, maxslack, 1, SCIProwIsLocal(rows[i]), SCIProwGetRank(rows[i]), \
669  rowlen, rowvals, rowcols, rhs, intvarpos, introw, &success) );
670 
671  assert(success == 1 || success == 0);
672  mod2matrix->ntransintrows += (int)success;
673  }
674 
675  if( lhsslack <= maxslack )
676  {
677  SCIP_Bool success;
678  TRANSINTROW* introw = &mod2matrix->transintrows[mod2matrix->ntransintrows];
679  SCIP_CALL( transformNonIntegralRow(scip, allowlocal, maxslack, -1, SCIProwIsLocal(rows[i]), SCIProwGetRank(rows[i]), \
680  rowlen, rowvals, rowcols, -lhs, intvarpos, introw, &success) );
681 
682  assert(success == 1 || success == 0);
683  mod2matrix->ntransintrows += (int)success;
684  }
685  }
686 
687  SCIPfreeCleanBufferArray(scip, &intvarpos);
688 
689  return SCIP_OKAY;
690 }
691 
692 
693 /** adds new column to the mod 2 matrix */
694 static
696  SCIP* scip, /**< SCIP datastructure */
697  MOD2_MATRIX* mod2matrix, /**< mod 2 matrix */
698  SCIP_HASHMAP* origvar2col, /**< hash map for mapping of problem variables to mod 2 columns */
699  SCIP_VAR* origvar, /**< problem variable to create mod 2 column for */
700  SCIP_Real solval, /**< solution value of problem variable */
701  int rhsoffset /**< offset in right hand side due complementation (mod 2) */
702  )
703 {
704  MOD2_COL* col;
705 
706  /* allocate memory */
707  SCIP_CALL( SCIPallocBlockMemory(scip, &col) );
708 
709  /* initialize fields */
710  col->pos = mod2matrix->ncols++;
711  col->index = SCIPvarGetProbindex(origvar);
712  col->solval = solval;
713  SCIP_CALL( SCIPhashsetCreate(&col->nonzrows, SCIPblkmem(scip), 1) );
714 
715  /* add column to mod 2 matrix */
716  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &mod2matrix->cols, &mod2matrix->colssize, mod2matrix->ncols) );
717  mod2matrix->cols[col->pos] = col;
718 
719  /* create mapping of problem variable to mod 2 column with its right hand side offset */
720  SCIP_CALL( SCIPhashmapInsert(origvar2col, (void*) origvar, COLINFO_CREATE(col, rhsoffset)) );
721 
722  return SCIP_OKAY;
723 }
724 
725 /** links row to mod 2 column */
726 static
728  BMS_BLKMEM* blkmem, /**< block memory shell */
729  MOD2_COL* col, /**< mod 2 column */
730  MOD2_ROW* row /**< mod 2 row */
731  )
732 {
733  SCIP_CALL( SCIPhashsetInsert(col->nonzrows, blkmem, (void*)row) );
734 
735  assert(SCIPhashsetExists(col->nonzrows, (void*)row));
736 
737  row->maxsolval = MAX(col->solval, row->maxsolval);
738 
739  return SCIP_OKAY;
740 }
741 
742 /** unlinks row from mod 2 column */
743 static
745  MOD2_COL* col, /**< mod 2 column */
746  MOD2_ROW* row /**< mod 2 row */
747  )
748 {
749  SCIP_CALL( SCIPhashsetRemove(col->nonzrows, (void*)row) );
750 
751  assert(!SCIPhashsetExists(col->nonzrows, (void*)row));
752 #ifndef NDEBUG
753  {
754  int nslots = SCIPhashsetGetNSlots(col->nonzrows);
755  MOD2_ROW** rows = (MOD2_ROW**) SCIPhashsetGetSlots(col->nonzrows);
756  int i;
757 
758  for( i = 0; i < nslots; ++i )
759  {
760  assert(rows[i] != row);
761  }
762  }
763 #endif
764 
765  return SCIP_OKAY;
766 }
767 
768 /** unlinks row from mod 2 column */
769 static
770 void mod2rowUnlinkCol(
771  MOD2_ROW* row /**< mod 2 row */,
772  MOD2_COL* col /**< mod 2 column */
773  )
774 {
775  int i;
776 
777  assert(row->nnonzcols == 0 || row->nonzcols != NULL);
778 
779  SCIP_UNUSED( SCIPsortedvecFindPtr((void**) row->nonzcols, compareColIndex, col, row->nnonzcols, &i) );
780  assert(row->nonzcols[i] == col);
781 
782  --row->nnonzcols;
783  BMSmoveMemoryArray(row->nonzcols + i, row->nonzcols + i + 1, row->nnonzcols - i); /*lint !e866*/
784 
785  if( col->solval >= row->maxsolval )
786  {
787  row->maxsolval = 0.0;
788  for( i = 0; i < row->nnonzcols; ++i )
789  {
790  row->maxsolval = MAX(row->nonzcols[i]->solval, row->maxsolval);
791  }
792  }
793 }
794 
795 /** adds a SCIP_ROW to the mod 2 matrix */
796 static
798  SCIP* scip, /**< scip data structure */
799  BMS_BLKMEM* blkmem, /**< block memory shell */
800  MOD2_MATRIX* mod2matrix, /**< modulo 2 matrix */
801  SCIP_HASHMAP* origcol2col, /**< hashmap to retrieve the mod 2 column from a SCIP_COL */
802  SCIP_ROW* origrow, /**< original SCIP row */
803  SCIP_Real slack, /**< slack of row */
804  ROWIND_TYPE side, /**< side of row that is used for mod 2 row, must be ORIG_RHS or ORIG_LHS */
805  int rhsmod2 /**< modulo 2 value of the row's right hand side */
806  )
807 {
808  SCIP_Real* rowvals;
809  SCIP_COL** rowcols;
810  int rowlen;
811  int i;
812  MOD2_ROW* row;
813 
814  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &row) );
815 
816  row->index = mod2matrix->nrows++;
817  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &mod2matrix->rows, &mod2matrix->rowssize, mod2matrix->nrows) );
818  mod2matrix->rows[row->index] = row;
819 
820  row->slack = MAX(0.0, slack);
821  row->maxsolval = 0.0;
822  row->rhs = rhsmod2;
823  row->nrowinds = 1;
824  row->rowinds = NULL;
825  row->rowindssize = 0;
826 
827  if( SCIPisZero(scip, row->slack) )
828  ++mod2matrix->nzeroslackrows;
829 
830  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &row->rowinds, &row->rowindssize, row->nrowinds) );
831  row->rowinds[0].type = side;
832  row->rowinds[0].index = (unsigned int)SCIProwGetLPPos(origrow);
833 
834  row->nnonzcols = 0;
835  row->nonzcolssize = 0;
836  row->nonzcols = NULL;
837 
838  rowlen = SCIProwGetNNonz(origrow);
839  rowvals = SCIProwGetVals(origrow);
840  rowcols = SCIProwGetCols(origrow);
841 
842  for( i = 0; i < rowlen; ++i )
843  {
844  if( mod2(scip, rowvals[i]) == 1 )
845  {
846  void* colinfo;
847  MOD2_COL* col;
848  int rhsoffset;
849 
850  colinfo = SCIPhashmapGetImage(origcol2col, (void*)SCIPcolGetVar(rowcols[i]));
851 
852  /* extract the righthand side offset from the colinfo and update the righthand side */
853  rhsoffset = COLINFO_GET_RHSOFFSET(colinfo);
854  row->rhs = (row->rhs + rhsoffset) % 2;
855 
856  /* extract the column pointer from the colinfo */
857  col = COLINFO_GET_MOD2COL(colinfo);
858 
859  if( col != NULL )
860  {
861  int k;
862 
863  k = row->nnonzcols++;
864 
866  row->nonzcols[k] = col;
867 
868  SCIP_CALL( mod2colLinkRow(blkmem, col, row) );
869  }
870  }
871  }
872 
873  SCIPsortPtr((void**)row->nonzcols, compareColIndex, row->nnonzcols);
874 
875  checkRow(row);
876 
877  return SCIP_OKAY;
878 }
879 
880 /** adds a transformed integral row to the mod 2 matrix */
881 static
883  SCIP* scip, /**< scip data structure */
884  MOD2_MATRIX* mod2matrix, /**< modulo 2 matrix */
885  SCIP_HASHMAP* origcol2col, /**< hashmap to retrieve the mod 2 column from a SCIP_COL */
886  int transrowind /**< index to transformed int row */
887  )
888 {
889  int i;
890  SCIP_VAR** vars;
891  BMS_BLKMEM* blkmem;
892  MOD2_ROW* row;
893  TRANSINTROW* introw;
894 
895  SCIP_CALL( SCIPallocBlockMemory(scip, &row) );
896 
897  vars = SCIPgetVars(scip);
898  introw = &mod2matrix->transintrows[transrowind];
899 
900  blkmem = SCIPblkmem(scip);
901  row->index = mod2matrix->nrows++;
902  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &mod2matrix->rows, &mod2matrix->rowssize, mod2matrix->nrows) );
903  mod2matrix->rows[row->index] = row;
904 
905  row->slack = MAX(0.0, introw->slack);
906  row->rhs = mod2(scip, introw->rhs);
907  row->nrowinds = 1;
908  row->rowinds = NULL;
909  row->rowindssize = 0;
910  row->maxsolval = 0.0;
911 
912  if( SCIPisZero(scip, row->slack) )
913  ++mod2matrix->nzeroslackrows;
914 
915  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &row->rowinds, &row->rowindssize, row->nrowinds) );
916  row->rowinds[0].type = TRANSROW;
917  row->rowinds[0].index = (unsigned int)transrowind;
918 
919  row->nnonzcols = 0;
920  row->nonzcolssize = 0;
921  row->nonzcols = NULL;
922 
923  for( i = 0; i < introw->len; ++i )
924  {
925  if( mod2(scip, introw->vals[i]) == 1 )
926  {
927  void* colinfo;
928  MOD2_COL* col;
929  int rhsoffset;
930 
931  colinfo = SCIPhashmapGetImage(origcol2col, (void*)vars[introw->varinds[i]]);
932 
933  /* extract the righthand side offset from the colinfo and update the righthand side */
934  rhsoffset = COLINFO_GET_RHSOFFSET(colinfo);
935  row->rhs = (row->rhs + rhsoffset) % 2;
936 
937  /* extract the column pointer from the colinfo */
938  col = COLINFO_GET_MOD2COL(colinfo);
939 
940  if( col != NULL )
941  {
942  int k;
943 
944  k = row->nnonzcols++;
945 
947  row->nonzcols[k] = col;
948 
949  SCIP_CALL( mod2colLinkRow(blkmem, col, row) );
950  }
951  }
952  }
953 
954  SCIPsortPtr((void**)row->nonzcols, compareColIndex, row->nnonzcols);
955 
956  checkRow(row);
957 
958  return SCIP_OKAY;
959 }
960 
961 /** free all resources held by the mod 2 matrix */
962 static
963 void destroyMod2Matrix(
964  SCIP* scip, /**< scip data structure */
965  MOD2_MATRIX* mod2matrix /**< pointer to mod2 matrix structure */
966  )
967 {
968  int i;
969 
970  for( i = 0; i < mod2matrix->ncols; ++i )
971  {
972  SCIPhashsetFree(&mod2matrix->cols[i]->nonzrows, SCIPblkmem(scip));
973  SCIPfreeBlockMemory(scip, &mod2matrix->cols[i]); /*lint !e866*/
974  }
975 
976  for( i = 0; i < mod2matrix->nrows; ++i )
977  {
978  SCIPfreeBlockMemoryArrayNull(scip, &mod2matrix->rows[i]->nonzcols, mod2matrix->rows[i]->nonzcolssize);
979  SCIPfreeBlockMemoryArrayNull(scip, &mod2matrix->rows[i]->rowinds, mod2matrix->rows[i]->rowindssize);
980  SCIPfreeBlockMemory(scip, &mod2matrix->rows[i]); /*lint !e866*/
981  }
982 
983  for( i = 0; i < mod2matrix->ntransintrows; ++i )
984  {
985  SCIPfreeBlockMemoryArray(scip, &mod2matrix->transintrows[i].vals, mod2matrix->transintrows[i].size);
986  SCIPfreeBlockMemoryArray(scip, &mod2matrix->transintrows[i].varinds, mod2matrix->transintrows[i].size);
987  }
988 
989  SCIPfreeBlockMemoryArray(scip, &mod2matrix->transintrows, 2*SCIPgetNLPRows(scip)); /*lint !e647*/
990 
991  SCIPfreeBlockMemoryArrayNull(scip, &mod2matrix->rows, mod2matrix->rowssize);
992  SCIPfreeBlockMemoryArrayNull(scip, &mod2matrix->cols, mod2matrix->colssize);
993 }
994 
995 /** build the modulo 2 matrix from all integral rows in the LP, and non-integral rows
996  * if the transformation to an integral row succeeds
997  */
998 static
1000  SCIP* scip, /**< scip data structure */
1001  SCIP_SEPADATA* sepadata, /**< zerohalf separator data */
1002  BMS_BLKMEM* blkmem, /**< block memory shell */
1003  MOD2_MATRIX* mod2matrix, /**< mod 2 matrix */
1004  SCIP_Bool allowlocal, /**< should local cuts be allowed */
1005  SCIP_Real maxslack /**< maximum slack allowed for mod 2 rows */
1006  )
1007 {
1008  SCIP_VAR** vars;
1009  SCIP_ROW** rows;
1010  SCIP_COL** cols;
1011  SCIP_HASHMAP* origcol2col;
1012  int ncols;
1013  int nrows;
1014  int nintvars;
1015  int maxnonzeros;
1016  int i;
1017  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
1018  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
1019 
1020  nintvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
1021  vars = SCIPgetVars(scip);
1022 
1023  /* initialize fields */
1024  mod2matrix->cols = NULL;
1025  mod2matrix->colssize = 0;
1026  mod2matrix->ncols = 0;
1027  mod2matrix->rows = NULL;
1028  mod2matrix->rowssize = 0;
1029  mod2matrix->nrows = 0;
1030  mod2matrix->nzeroslackrows = 0;
1031 
1032  SCIP_CALL( SCIPhashmapCreate(&origcol2col, SCIPblkmem(scip), 1) );
1033 
1034  /* add all integral vars if they are not at their bound */
1035  for( i = 0; i < nintvars; ++i )
1036  {
1037  SCIP_Real lb;
1038  SCIP_Real ub;
1039  SCIP_Real lbsol;
1040  SCIP_Real ubsol;
1041  SCIP_Real primsol;
1042  SCIP_Bool useub;
1043 
1044  primsol = SCIPgetVarSol(scip, vars[i]);
1045 
1046  lb = allowlocal ? SCIPvarGetLbLocal(vars[i]) : SCIPvarGetLbGlobal(vars[i]);
1047  lbsol = MAX(0.0, primsol - lb);
1048  if( SCIPisZero(scip, lbsol) )
1049  {
1050  SCIP_CALL( SCIPhashmapInsert(origcol2col, (void*) vars[i], COLINFO_CREATE(NULL, mod2(scip, lb))) );
1051  continue;
1052  }
1053 
1054  ub = allowlocal ? SCIPvarGetUbLocal(vars[i]) : SCIPvarGetUbGlobal(vars[i]);
1055  ubsol = MAX(0.0, ub - primsol);
1056  if( SCIPisZero(scip, ubsol) )
1057  {
1058  SCIP_CALL( SCIPhashmapInsert(origcol2col, (void*) vars[i], COLINFO_CREATE(NULL, mod2(scip, ub))) );
1059  continue;
1060  }
1061 
1062  if( SCIPisInfinity(scip, ub) ) /* if there is no ub, use lb */
1063  useub = FALSE;
1064  else if( SCIPisInfinity(scip, -lb) ) /* if there is no lb, use ub */
1065  useub = TRUE;
1066  else if( SCIPisLT(scip, primsol, (1.0 - BOUNDSWITCH) * lb + BOUNDSWITCH * ub) )
1067  useub = FALSE;
1068  else
1069  useub = TRUE;
1070 
1071  if( useub )
1072  {
1073  assert(ubsol > 0.0);
1074  SCIP_CALL( mod2MatrixAddCol(scip, mod2matrix, origcol2col, vars[i], ubsol, mod2(scip, ub)) );
1075  }
1076  else
1077  {
1078  assert(lbsol > 0.0);
1079  SCIP_CALL( mod2MatrixAddCol(scip, mod2matrix, origcol2col, vars[i], lbsol, mod2(scip, lb)) );
1080  }
1081  }
1082 
1083  maxnonzeros = (int)(SCIPgetNLPCols(scip) * sepadata->maxrowdensity) + sepadata->densityoffset;
1084 
1085  /* add all integral rows using the created columns */
1086  for( i = 0; i < nrows; ++i )
1087  {
1088  SCIP_Real lhs;
1089  SCIP_Real rhs;
1090  SCIP_Real activity;
1091  SCIP_Real lhsslack;
1092  SCIP_Real rhsslack;
1093  int lhsmod2;
1094  int rhsmod2;
1095 
1096  /* skip non-integral rows and rows not suitable for generating cuts */
1097  if( SCIProwIsModifiable(rows[i]) || !SCIProwIsIntegral(rows[i]) || (SCIProwIsLocal(rows[i]) && !allowlocal) || SCIProwGetNNonz(rows[i]) > maxnonzeros )
1098  continue;
1099 
1100  lhsmod2 = 0;
1101  rhsmod2 = 0;
1102  activity = SCIPgetRowLPActivity(scip, rows[i]) - SCIProwGetConstant(rows[i]);
1103 
1104  /* since row is integral we can ceil/floor the lhs/rhs after subtracting the constant */
1105  lhs = SCIPfeasCeil(scip, SCIProwGetLhs(rows[i]) - SCIProwGetConstant(rows[i]));
1106  rhs = SCIPfeasFloor(scip, SCIProwGetRhs(rows[i]) - SCIProwGetConstant(rows[i]));
1107 
1108  /* compute lhsslack: activity - lhs */
1109  if( SCIPisInfinity(scip, -SCIProwGetLhs(rows[i])) )
1110  lhsslack = SCIPinfinity(scip);
1111  else
1112  {
1113  lhsslack = activity - lhs;
1114  lhsmod2 = mod2(scip, lhs);
1115  }
1116 
1117  /* compute rhsslack: rhs - activity */
1118  if( SCIPisInfinity(scip, SCIProwGetRhs(rows[i])) )
1119  rhsslack = SCIPinfinity(scip);
1120  else
1121  {
1122  rhsslack = rhs - activity;
1123  rhsmod2 = mod2(scip, rhs);
1124  }
1125 
1126  if( rhsslack <= maxslack && lhsslack <= maxslack )
1127  {
1128  if( lhsmod2 == rhsmod2 )
1129  {
1130  /* maxslack < 1 implies rhs - lhs = rhsslack + lhsslack < 2. Therefore lhs = rhs (mod2) can only hold if they
1131  * are equal
1132  */
1133  assert(SCIPisEQ(scip, lhs, rhs));
1134 
1135  /* use rhs */
1136  SCIP_CALL( mod2MatrixAddOrigRow(scip, blkmem, mod2matrix, origcol2col, rows[i], rhsslack, ORIG_RHS, rhsmod2) );
1137  }
1138  else
1139  {
1140  /* use both */
1141  SCIP_CALL( mod2MatrixAddOrigRow(scip, blkmem, mod2matrix, origcol2col, rows[i], lhsslack, ORIG_LHS, lhsmod2) );
1142  SCIP_CALL( mod2MatrixAddOrigRow(scip, blkmem, mod2matrix, origcol2col, rows[i], rhsslack, ORIG_RHS, rhsmod2) );
1143  }
1144  }
1145  else if( rhsslack <= maxslack )
1146  {
1147  /* use rhs */
1148  SCIP_CALL( mod2MatrixAddOrigRow(scip, blkmem, mod2matrix, origcol2col, rows[i], rhsslack, ORIG_RHS, rhsmod2) );
1149  }
1150  else if( lhsslack <= maxslack )
1151  {
1152  /* use lhs */
1153  SCIP_CALL( mod2MatrixAddOrigRow(scip, blkmem, mod2matrix, origcol2col, rows[i], lhsslack, ORIG_LHS, lhsmod2) );
1154  }
1155  }
1156 
1157  /* transform non-integral rows */
1158  SCIP_CALL( mod2MatrixTransformContRows(scip, sepadata, mod2matrix, allowlocal, maxslack) );
1159 
1160  /* add all transformed integral rows using the created columns */
1161  for( i = 0; i < mod2matrix->ntransintrows; ++i )
1162  {
1163  SCIP_CALL( mod2MatrixAddTransRow(scip, mod2matrix, origcol2col, i) );
1164  }
1165 
1166  SCIPhashmapFree(&origcol2col);
1167 
1168  return SCIP_OKAY;
1169 }
1170 
1171 /* compare two mod 2 columns for equality */
1172 static
1173 SCIP_DECL_HASHKEYEQ(columnsEqual)
1174 { /*lint --e{715}*/
1175  MOD2_COL* col1;
1176  MOD2_COL* col2;
1177  int nslotscol1;
1178  MOD2_ROW** col1rows;
1179  int i;
1180 
1181  col1 = (MOD2_COL*) key1;
1182  col2 = (MOD2_COL*) key2;
1183 
1185  return FALSE;
1186 
1187  nslotscol1 = SCIPhashsetGetNSlots(col1->nonzrows);
1188  col1rows = (MOD2_ROW**) SCIPhashsetGetSlots(col1->nonzrows);
1189  for( i = 0; i < nslotscol1; ++i )
1190  {
1191  if( col1rows[i] != NULL && !SCIPhashsetExists(col2->nonzrows, (void*)col1rows[i]) )
1192  return FALSE;
1193  }
1194 
1195  return TRUE;
1196 }
1197 
1198 /* compute a signature of the rows in a mod 2 matrix as hash value */
1199 static
1200 SCIP_DECL_HASHKEYVAL(columnGetSignature)
1201 { /*lint --e{715}*/
1202  MOD2_COL* col;
1203  MOD2_ROW** rows;
1204  uint64_t signature;
1205  int i;
1206  int nslots;
1207 
1208  col = (MOD2_COL*) key;
1209 
1210  nslots = SCIPhashsetGetNSlots(col->nonzrows);
1211  rows = (MOD2_ROW**) SCIPhashsetGetSlots(col->nonzrows);
1212 
1213  signature = 0;
1214  for( i = 0; i < nslots; ++i )
1215  {
1216  if( rows[i] != NULL )
1217  signature |= SCIPhashSignature64(rows[i]->index);
1218  }
1219 
1220  return signature;
1221 }
1222 
1223 /* compare two mod 2 rows for equality */
1224 static
1225 SCIP_DECL_HASHKEYEQ(rowsEqual)
1226 { /*lint --e{715}*/
1227  MOD2_ROW* row1;
1228  MOD2_ROW* row2;
1229  int i;
1230 
1231  row1 = (MOD2_ROW*) key1;
1232  row2 = (MOD2_ROW*) key2;
1233 
1234  assert(row1 != NULL);
1235  assert(row2 != NULL);
1236  assert(row1->nnonzcols == 0 || row1->nonzcols != NULL);
1237  assert(row2->nnonzcols == 0 || row2->nonzcols != NULL);
1238 
1239  if( row1->nnonzcols != row2->nnonzcols || row1->rhs != row2->rhs )
1240  return FALSE;
1241 
1242  for( i = 0; i < row1->nnonzcols; ++i )
1243  {
1244  if( row1->nonzcols[i] != row2->nonzcols[i] )
1245  return FALSE;
1246  }
1247 
1248  return TRUE;
1249 }
1250 
1251 /* compute a signature of a mod 2 row as hash value */
1252 static
1253 SCIP_DECL_HASHKEYVAL(rowGetSignature)
1254 { /*lint --e{715}*/
1255  MOD2_ROW* row;
1256  int i;
1257  uint64_t signature;
1258 
1259  row = (MOD2_ROW*) key;
1260  assert(row->nnonzcols == 0 || row->nonzcols != NULL);
1261 
1262  signature = row->rhs; /*lint !e732*/
1263 
1264  for( i = 0; i < row->nnonzcols; ++i )
1265  signature |= SCIPhashSignature64(row->nonzcols[i]->index);
1266 
1267  return signature;
1268 }
1269 
1270 /** removes a row from the mod 2 matrix */
1271 static
1273  SCIP* scip, /**< scip data structure */
1274  MOD2_MATRIX* mod2matrix, /**< the mod 2 matrix */
1275  MOD2_ROW* row /**< mod 2 row */
1276  )
1277 {
1278  int i;
1279  int position = row->pos;
1280 
1281  checkRow(row);
1282 
1283  /* update counter for zero slack rows */
1284  if( SCIPisZero(scip, row->slack) )
1285  --mod2matrix->nzeroslackrows;
1286 
1287  /* remove the row from the array */
1288  --mod2matrix->nrows;
1289  mod2matrix->rows[position] = mod2matrix->rows[mod2matrix->nrows];
1290  mod2matrix->rows[position]->pos = position;
1291 
1292  /* unlink columns from row */
1293  for( i = 0; i < row->nnonzcols; ++i )
1294  {
1295  SCIP_CALL( mod2colUnlinkRow(row->nonzcols[i], row) );
1296  }
1297 
1298  /* free row */
1300  SCIPfreeBlockMemoryArray(scip, &row->rowinds, row->rowindssize);
1301  SCIPfreeBlockMemory(scip, &row);
1302 
1303  return SCIP_OKAY;
1304 }
1305 
1306 /** removes a column from the mod 2 matrix */
1307 static
1308 void mod2matrixRemoveCol(
1309  SCIP* scip, /**< scip data structure */
1310  MOD2_MATRIX* mod2matrix, /**< the mod 2 matrix */
1311  MOD2_COL* col /**< a column in the mod 2 matrix */
1312  )
1313 {
1314  int i;
1315  int nslots;
1316  MOD2_ROW** rows;
1317  int position;
1318 
1319  assert(col != NULL);
1320 
1321  /* cppcheck-suppress nullPointer */
1322  position = col->pos;
1323 
1324  /* remove column from arrays */
1325  --mod2matrix->ncols;
1326  mod2matrix->cols[position] = mod2matrix->cols[mod2matrix->ncols];
1327  mod2matrix->cols[position]->pos = position;
1328 
1329  /* cppcheck-suppress nullPointer */
1330  nslots = SCIPhashsetGetNSlots(col->nonzrows);
1331  /* cppcheck-suppress nullPointer */
1332  rows = (MOD2_ROW**) SCIPhashsetGetSlots(col->nonzrows);
1333 
1334  /* adjust rows of column */
1335  for( i = 0; i < nslots; ++i )
1336  {
1337  if( rows[i] != NULL )
1338  mod2rowUnlinkCol(rows[i], col);
1339  }
1340 
1341  /* free column */
1342  SCIPhashsetFree(&col->nonzrows, SCIPblkmem(scip));
1343  SCIPfreeBlockMemory(scip, &col);
1344 }
1345 
1346 /* remove columns that are (Prop3 iii) zero (Prop3 iv) identify indentical columns (Prop3 v) unit vector columns */
1347 static
1349  SCIP* scip, /**< scip data structure */
1350  MOD2_MATRIX* mod2matrix, /**< mod 2 matrix */
1351  SCIP_SEPADATA* sepadata /**< zerohalf separator data */
1352  )
1353 {
1354  int i;
1355  SCIP_HASHTABLE* columntable;
1356 
1357  SCIP_CALL( SCIPhashtableCreate(&columntable, SCIPblkmem(scip), mod2matrix->ncols,
1358  SCIPhashGetKeyStandard, columnsEqual, columnGetSignature, NULL) );
1359 
1360  for( i = 0; i < mod2matrix->ncols; )
1361  {
1362  MOD2_COL* col = mod2matrix->cols[i];
1363  int nnonzrows = SCIPhashsetGetNElements(col->nonzrows);
1364  if( nnonzrows == 0 )
1365  { /* Prop3 iii */
1366  mod2matrixRemoveCol(scip, mod2matrix, col);
1367  }
1368  else if( nnonzrows == 1 )
1369  { /* Prop3 v */
1370  MOD2_ROW* row;
1371 
1372  {
1373  int j = 0;
1374  MOD2_ROW** rows;
1375  rows = (MOD2_ROW**) SCIPhashsetGetSlots(col->nonzrows);
1376  while( rows[j] == NULL )
1377  ++j;
1378 
1379  row = rows[j];
1380  }
1381 
1382  checkRow(row);
1383 
1384  /* column is unit vector, so add its solution value to the rows slack and remove it */
1385  if( SCIPisZero(scip, row->slack) )
1386  --mod2matrix->nzeroslackrows;
1387 
1388  row->slack += col->solval;
1389  assert(!SCIPisZero(scip, row->slack));
1390 
1391  mod2matrixRemoveCol(scip, mod2matrix, col);
1392  ++sepadata->nreductions;
1393 
1394  checkRow(row);
1395  }
1396  else
1397  {
1398  MOD2_COL* identicalcol;
1399  identicalcol = (MOD2_COL*)SCIPhashtableRetrieve(columntable, col);
1400  if( identicalcol != NULL )
1401  {
1402  assert(identicalcol != col);
1403 
1404  /* column is identical to other column so add its solution value to the other one and then remove and free it */
1405  identicalcol->solval += col->solval;
1406 
1407  /* also adjust the solval of the removed column so that the maxsolval of each row is properly updated */
1408  col->solval = identicalcol->solval;
1409 
1410  mod2matrixRemoveCol(scip, mod2matrix, col);
1411  }
1412  else
1413  {
1414  SCIP_CALL( SCIPhashtableInsert(columntable, (void*)col) );
1415  ++i;
1416  }
1417  }
1418  }
1419 
1420  SCIPhashtableFree(&columntable);
1421 
1422  return SCIP_OKAY;
1423 }
1424 
1425 #define NONZERO(x) (COPYSIGN(1e-100, (x)) + (x))
1427 /** add original row to aggregation with weight 0.5 */
1428 static
1429 void addOrigRow(
1430  SCIP* scip, /**< SCIP datastructure */
1431  SCIP_Real* tmpcoefs, /**< array to add coefficients to */
1432  SCIP_Real* cutrhs, /**< pointer to add right hand side */
1433  int* nonzeroinds, /**< array of non-zeros in the aggregation */
1434  int* nnz, /**< pointer to update number of non-zeros */
1435  int* cutrank, /**< pointer to update cut rank */
1436  SCIP_Bool* cutislocal, /**< pointer to update local flag */
1437  SCIP_ROW* row, /**< row to add */
1438  int sign /**< sign for weight, i.e. +1 to use right hand side or -1 to use left hand side */
1439  )
1440 {
1441  int i;
1442  SCIP_Real weight = 0.5 * sign;
1443 
1444  for( i = 0; i < row->len; ++i )
1445  {
1446  int probindex = row->cols[i]->var_probindex;
1447  SCIP_Real val = tmpcoefs[probindex];
1448 
1449  if( val == 0.0 )
1450  {
1451  nonzeroinds[(*nnz)++] = probindex;
1452  }
1453 
1454  val += weight * row->vals[i];
1455  tmpcoefs[probindex] = NONZERO(val);
1456  }
1457 
1458  if( sign == +1 )
1459  {
1460  *cutrhs += weight * SCIPfeasFloor(scip, row->rhs - row->constant);
1461  }
1462  else
1463  {
1464  assert(sign == -1);
1465  *cutrhs += weight * SCIPfeasCeil(scip, row->lhs - row->constant);
1466  }
1467 
1468  *cutrank = MAX(*cutrank, row->rank);
1469  *cutislocal = *cutislocal || row->local;
1470 }
1471 
1472 /** add transformed integral row to aggregation with weight 0.5 */
1473 static
1474 void addTransRow(
1475  SCIP_Real* tmpcoefs, /**< array to add coefficients to */
1476  SCIP_Real* cutrhs, /**< pointer to add right hand side */
1477  int* nonzeroinds, /**< array of non-zeros in the aggregation */
1478  int* nnz, /**< pointer to update number of non-zeros */
1479  int* cutrank, /**< pointer to update cut rank */
1480  SCIP_Bool* cutislocal, /**< pointer to update local flag */
1481  TRANSINTROW* introw /**< transformed integral row to add to the aggregation */
1482  )
1483 {
1484  int i;
1485 
1486  for( i = 0; i < introw->len; ++i )
1487  {
1488  int probindex = introw->varinds[i];
1489  SCIP_Real val = tmpcoefs[probindex];
1490 
1491  if( val == 0.0 )
1492  {
1493  nonzeroinds[(*nnz)++] = probindex;
1494  }
1495 
1496  val += 0.5 * introw->vals[i];
1497  tmpcoefs[probindex] = NONZERO(val);
1498  }
1499 
1500  *cutrhs += 0.5 * introw->rhs;
1501 
1502  *cutrank = MAX(*cutrank, introw->rank);
1503  *cutislocal = *cutislocal || introw->local;
1504 }
1505 
1506 /* calculates the cuts efficacy of cut */
1507 static
1509  SCIP* scip, /**< SCIP data structure */
1510  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
1511  SCIP_Real cutrhs, /**< the right hand side of the cut */
1512  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
1513  int cutnnz /**< the number of non-zeros in the cut */
1514  )
1515 {
1516  SCIP_VAR** vars;
1517  SCIP_Real norm;
1518  SCIP_Real activity;
1519  int i;
1520 
1521  assert(scip != NULL);
1522  assert(cutcoefs != NULL);
1523  assert(cutinds != NULL);
1524 
1525  norm = SCIPgetVectorEfficacyNorm(scip, cutcoefs, cutnnz);
1526  vars = SCIPgetVars(scip);
1527 
1528  activity = 0.0;
1529  for( i = 0; i < cutnnz; ++i )
1530  activity += cutcoefs[i] * SCIPgetVarSol(scip, vars[cutinds[i]]);
1531 
1532  return (activity - cutrhs) / MAX(1e-6, norm);
1533 }
1534 
1535 /** computes maximal violation that can be achieved for zerohalf cuts where this row particiaptes */
1536 static
1538  MOD2_ROW* row /**< mod 2 row */
1539  )
1540 {
1541  SCIP_Real viol;
1542 
1543  viol = 1.0 - row->slack;
1544  viol *= 0.5;
1545 
1546  return viol;
1547 }
1548 
1549 /** computes violation of zerohalf cut generated from given mod 2 row */
1550 static
1552  MOD2_ROW* row /**< mod 2 row */
1553  )
1554 {
1555  int i;
1556  SCIP_Real viol;
1557 
1558  viol = 1.0 - row->slack;
1559 
1560  for( i = 0; i < row->nnonzcols; ++i )
1561  {
1562  viol -= row->nonzcols[i]->solval;
1563  }
1564 
1565  viol *= 0.5;
1566 
1567  return viol;
1568 }
1569 
1570 /** generate a zerohalf cut from a given mod 2 row, i.e., try if aggregations of rows of the
1571  * mod2 matrix give violated cuts
1572  */
1573 static
1575  SCIP* scip, /**< scip data structure */
1576  MOD2_MATRIX* mod2matrix, /**< mod 2 matrix */
1577  SCIP_SEPA* sepa, /**< zerohalf separator */
1578  SCIP_SEPADATA* sepadata, /**< zerohalf separator data */
1579  SCIP_Bool allowlocal, /**< should local cuts be allowed */
1580  MOD2_ROW* row /**< mod 2 row */
1581  )
1582 {
1583  SCIP_Bool cutislocal;
1584  int i;
1585  int cutnnz;
1586  int cutrank;
1587  int nvars;
1588  int maxaggrlen;
1589  int nchgcoefs;
1590  int* cutinds;
1591  SCIP_ROW** rows;
1592  SCIP_VAR** vars;
1593  SCIP_Real* tmpcoefs;
1594  SCIP_Real* cutcoefs;
1595  SCIP_Real cutrhs;
1596  SCIP_Real cutefficacy;
1597 
1598  if( computeViolation(row) < sepadata->minviol )
1599  return SCIP_OKAY;
1600 
1601  rows = SCIPgetLPRows(scip);
1602  nvars = SCIPgetNVars(scip);
1603  vars = SCIPgetVars(scip);
1604 
1605  maxaggrlen = MAXAGGRLEN(SCIPgetNLPCols(scip));
1606 
1607  /* right hand side must be odd, otherwise no cut can be generated */
1608  assert(row->rhs == 1);
1609 
1610  /* perform the summation of the rows defined by the mod 2 row*/
1611  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, nvars) );
1612  SCIP_CALL( SCIPallocBufferArray(scip, &cutinds, nvars) );
1613  SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nvars) );
1614 
1615  /* the right hand side of the zerohalf cut will be rounded down by 0.5
1616  * thus we can instead subtract 0.5 directly
1617  */
1618  cutrhs = -0.5;
1619  cutnnz = 0;
1620  cutrank = 0;
1621  cutislocal = FALSE;
1622 
1623  /* compute the aggregation of the rows with weight 0.5 */
1624  for( i = 0; i < row->nrowinds; ++i )
1625  {
1626  switch( row->rowinds[i].type )
1627  {
1628  case ORIG_RHS:
1629  addOrigRow(scip, tmpcoefs, &cutrhs, cutinds, &cutnnz, &cutrank, &cutislocal, rows[row->rowinds[i].index], 1);
1630  break;
1631  case ORIG_LHS:
1632  addOrigRow(scip, tmpcoefs, &cutrhs, cutinds, &cutnnz, &cutrank, &cutislocal, rows[row->rowinds[i].index], -1);
1633  break;
1634  case TRANSROW: {
1635  TRANSINTROW* introw = &mod2matrix->transintrows[row->rowinds[i].index];
1636  SCIPdebugMsg(scip, "using transformed row %i of length %i with slack %f and rhs %f for cut\n", row->rowinds[i].index, introw->len, introw->slack, introw->rhs);
1637  addTransRow(tmpcoefs, &cutrhs, cutinds, &cutnnz, &cutrank, &cutislocal, introw);
1638  break;
1639  }
1640  default:
1641  SCIPABORT();
1642  }
1643  }
1644 
1645  /* abort if aggregation is too long */
1646  if( cutnnz > maxaggrlen )
1647  {
1648  /* clean buffer array must be set to zero before jumping to the terminate label */
1649  for( i = 0; i < cutnnz; ++i )
1650  {
1651  int k = cutinds[i];
1652  tmpcoefs[k] = 0.0;
1653  }
1654  goto TERMINATE;
1655  }
1656 
1657  /* compute the cut coefficients and update right handside due to complementation if necessary */
1658  for( i = 0; i < cutnnz; )
1659  {
1660  int k = cutinds[i];
1661  SCIP_Real coef = tmpcoefs[k];
1662  SCIP_Real floorcoef = SCIPfeasFloor(scip, coef);
1663  tmpcoefs[k] = 0.0;
1664 
1665  /* only check complementation if the coefficient was rounded down */
1666  if( REALABS(coef - floorcoef) > 0.1 )
1667  {
1668  SCIP_Real lb;
1669  SCIP_Real ub;
1670  SCIP_Bool loclb;
1671  SCIP_Bool locub;
1672  SCIP_Real primsol;
1673  SCIP_Bool useub;
1674 
1675  /* complement with closest bound */
1676  primsol = SCIPgetVarSol(scip, vars[k]);
1677  lb = SCIPvarGetLbGlobal(vars[k]);
1678  ub = SCIPvarGetUbGlobal(vars[k]);
1679  loclb = FALSE;
1680  locub = FALSE;
1681 
1682  /* use local bounds if better */
1683  if( allowlocal )
1684  {
1685  if( SCIPisGT(scip, SCIPvarGetLbLocal(vars[k]), lb) )
1686  {
1687  loclb = TRUE;
1688  lb = SCIPvarGetLbLocal(vars[k]);
1689  }
1690 
1691  if( SCIPisLT(scip, SCIPvarGetUbLocal(vars[k]), ub) )
1692  {
1693  locub = TRUE;
1694  ub = SCIPvarGetUbLocal(vars[k]);
1695  }
1696  }
1697 
1698  if( SCIPisInfinity(scip, ub) ) /* if there is no ub, use lb */
1699  useub = FALSE;
1700  else if( SCIPisInfinity(scip, -lb) ) /* if there is no lb, use ub */
1701  useub = TRUE;
1702  else if( SCIPisLT(scip, primsol, (1.0 - BOUNDSWITCH) * lb + BOUNDSWITCH * ub) )
1703  useub = FALSE;
1704  else
1705  useub = TRUE;
1706 
1707  if( useub )
1708  {
1709  /* set local flag if local bound was used */
1710  if( locub )
1711  cutislocal = TRUE;
1712 
1713  /* upper bound was used so floor was the wrong direction to round, coefficient must be ceiled instead */
1714  floorcoef += 1.0;
1715 
1716  assert(SCIPisFeasEQ(scip, floorcoef - coef, 0.5));
1717 
1718  /* add delta of complementing then rounding by 0.5 and complementing back to the right hand side */
1719  cutrhs += 0.5 * ub;
1720  }
1721  else
1722  {
1723  /* set local flag if local bound was used */
1724  if( loclb )
1725  cutislocal = TRUE;
1726 
1727  assert(SCIPisFeasEQ(scip, coef - floorcoef, 0.5));
1728 
1729  /* add delta of complementing then rounding by 0.5 and complementing back to the right hand side */
1730  cutrhs -= 0.5 * lb;
1731  }
1732  }
1733 
1734  /* make coefficient exactly integral */
1735  assert(SCIPisFeasIntegral(scip, floorcoef));
1736  floorcoef = SCIPfeasRound(scip, floorcoef);
1737 
1738  /* if coefficient is zero remove entry, otherwise set to floorcoef */
1739  if( floorcoef == 0.0 )
1740  {
1741  --cutnnz;
1742  cutinds[i] = cutinds[cutnnz];
1743  }
1744  else
1745  {
1746  cutcoefs[i] = floorcoef;
1747  ++i;
1748  }
1749  }
1750 
1751  /* make right hand side exactly integral */
1752  assert(SCIPisFeasIntegral(scip, cutrhs));
1753  cutrhs = SCIPfeasRound(scip, cutrhs);
1754 
1755  if( ! SCIPcutsTightenCoefficients(scip, cutislocal, cutcoefs, &cutrhs, cutinds, &cutnnz, &nchgcoefs) )
1756  {
1757  /* calculate efficacy */
1758  cutefficacy = calcEfficacy(scip, cutcoefs, cutrhs, cutinds, cutnnz);
1759 
1760  if( SCIPisEfficacious(scip, cutefficacy) )
1761  {
1762  SCIP_ROW* cut;
1763  char cutname[SCIP_MAXSTRLEN];
1764  int v;
1765 
1766  /* increase rank by 1 */
1767  cutrank += 1;
1768 
1769  assert(allowlocal || !cutislocal);
1770 
1771  /* create the cut */
1772  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "zerohalf%d_x%d", SCIPgetNLPs(scip), row->index);
1773 
1774  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE, sepadata->dynamiccuts) );
1775 
1776  SCIProwChgRank(cut, cutrank);
1777 
1778  /* cache the row extension and only flush them if the cut gets added */
1779  SCIP_CALL( SCIPcacheRowExtensions(scip, cut) );
1780 
1781  /* collect all non-zero coefficients */
1782  for( v = 0; v < cutnnz; ++v )
1783  {
1784  SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[cutinds[v]], cutcoefs[v]) );
1785  }
1786 
1787  /* flush all changes before adding the cut */
1788  SCIP_CALL( SCIPflushRowExtensions(scip, cut) );
1789 
1790  if( SCIPisCutNew(scip, cut) )
1791  {
1792  int pos = sepadata->ncuts++;
1793 
1794  if( sepadata->ncuts > sepadata->cutssize )
1795  {
1796  int newsize = SCIPcalcMemGrowSize(scip, sepadata->ncuts);
1797  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &sepadata->cuts, sepadata->cutssize, newsize) );
1798  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &sepadata->cutscores, sepadata->cutssize, newsize) );
1799  sepadata->cutssize = newsize;
1800  }
1801 
1802  sepadata->cuts[pos] = cut;
1803  sepadata->cutscores[pos] = cutefficacy + 1e-4 * (1 - SCIProwIsLocal(cut));
1804  }
1805  else
1806  {
1807  /* release the row */
1808  SCIP_CALL( SCIPreleaseRow(scip, &cut) );
1809  }
1810  }
1811  }
1812 
1813  TERMINATE:
1814  SCIPfreeBufferArray(scip, &cutinds);
1815  SCIPfreeBufferArray(scip, &cutcoefs);
1816  SCIPfreeCleanBufferArray(scip, &tmpcoefs);
1817 
1818  return SCIP_OKAY;
1819 }
1820 
1821 
1822 /** remove rows that are (a) zero (b) identical to other rows (keep the one with smallest slack) (c) have slack greater
1823  * than 1 (d) for zero rows with 1 as rhs and slack less than 1, we can directly generate a cut and remove the row (Lemma 4)
1824  */
1825 static
1827  SCIP* scip, /**< scip data structure */
1828  MOD2_MATRIX* mod2matrix, /**< the mod 2 matrix */
1829  SCIP_SEPA* sepa, /**< the zerohalf separator */
1830  SCIP_SEPADATA* sepadata, /**< data of the zerohalf separator */
1831  SCIP_Bool allowlocal /**< should local cuts be allowed */
1832  )
1833 {
1834  int i;
1835  SCIP_HASHTABLE* rowtable;
1836 
1837  SCIP_CALL( SCIPhashtableCreate(&rowtable, SCIPblkmem(scip), mod2matrix->nrows,
1838  SCIPhashGetKeyStandard, rowsEqual, rowGetSignature, NULL) );
1839 
1840  for( i = 0; i < mod2matrix->nrows; )
1841  {
1842  MOD2_ROW* row = mod2matrix->rows[i];
1843  row->pos = i;
1844 
1845  checkRow(row);
1846 
1847  assert(row->nnonzcols == 0 || row->nonzcols != NULL);
1848 
1849  if( (row->nnonzcols == 0 && row->rhs == 0) || computeMaxViolation(row) < sepadata->minviol )
1850  { /* (a) and (c) */
1851  sepadata->nreductions += row->nnonzcols;
1852  SCIP_CALL( mod2matrixRemoveRow(scip, mod2matrix, row) );
1853  }
1854  else if( row->nnonzcols > 0 )
1855  { /* (b) */
1856  MOD2_ROW* identicalrow;
1857  identicalrow = (MOD2_ROW*)SCIPhashtableRetrieve(rowtable, (void*)row);
1858  if( identicalrow != NULL )
1859  {
1860  assert(identicalrow != row);
1861  assert(identicalrow->nnonzcols == 0 || identicalrow->nonzcols != NULL);
1862 
1863  checkRow(identicalrow);
1864 
1865  /* row is identical to other row; only keep the one with smaller slack */
1866  if( identicalrow->slack <= row->slack )
1867  {
1868  SCIP_CALL( mod2matrixRemoveRow(scip, mod2matrix, row) );
1869  }
1870  else
1871  {
1872  assert(SCIPhashtableExists(rowtable, (void*)identicalrow));
1873 
1874  SCIP_CALL( SCIPhashtableRemove(rowtable, (void*)identicalrow) );
1875  assert(!SCIPhashtableExists(rowtable, (void*)identicalrow));
1876 
1877  SCIP_CALL( SCIPhashtableInsert(rowtable, (void*)row) );
1878 
1879  SCIPswapPointers((void**) &mod2matrix->rows[row->pos], (void**) &mod2matrix->rows[identicalrow->pos]);
1880  SCIPswapInts(&row->pos, &identicalrow->pos);
1881 
1882  assert(mod2matrix->rows[row->pos] == row && mod2matrix->rows[identicalrow->pos] == identicalrow);
1883  assert(identicalrow->pos == i);
1884  assert(row->pos < i);
1885 
1886  SCIP_CALL( mod2matrixRemoveRow(scip, mod2matrix, identicalrow) );
1887  }
1888  }
1889  else
1890  {
1891  SCIP_CALL( SCIPhashtableInsert(rowtable, (void*)row) );
1892  ++i;
1893  }
1894  }
1895  else
1896  {
1897  /* (d) */
1898  assert(row->nnonzcols == 0 && row->rhs == 1 && SCIPisLT(scip, row->slack, 1.0));
1899 
1900  SCIP_CALL( generateZerohalfCut(scip, mod2matrix, sepa, sepadata, allowlocal, row) );
1901 
1902  if( sepadata->infeasible )
1903  goto TERMINATE;
1904 
1905  SCIP_CALL( mod2matrixRemoveRow(scip, mod2matrix, row) );
1906  ++i;
1907  }
1908  }
1909 TERMINATE:
1910  SCIPhashtableFree(&rowtable);
1911 
1912  return SCIP_OKAY;
1913 }
1914 
1915 /** add a mod2 row to another one */
1916 static
1918  SCIP* scip, /**< scip data structure */
1919  BMS_BLKMEM* blkmem, /**< block memory shell */
1920  MOD2_MATRIX* mod2matrix, /**< mod 2 matrix */
1921  MOD2_ROW* row, /**< mod 2 row */
1922  MOD2_ROW* rowtoadd /**< mod 2 row that is added to the other mod 2 row */
1923  )
1924 {
1925  SCIP_Shortbool* contained;
1926  int i;
1927  int j;
1928  int k;
1929  int nnewentries;
1930  int nlprows;
1931  MOD2_COL** newnonzcols;
1932  SCIP_Real newslack;
1933 
1934  checkRow(row);
1935  checkRow(rowtoadd);
1936 
1937  assert(row->nnonzcols == 0 || row->nonzcols != NULL);
1938  assert(rowtoadd->nnonzcols == 0 || rowtoadd->nonzcols != NULL);
1939 
1940  nlprows = SCIPgetNLPRows(scip);
1941  row->rhs ^= rowtoadd->rhs;
1942 
1943  newslack = row->slack + rowtoadd->slack;
1944  blkmem = SCIPblkmem(scip);
1945 
1946  if( SCIPisZero(scip, row->slack) && !SCIPisZero(scip, newslack) )
1947  --mod2matrix->nzeroslackrows;
1948 
1949  row->slack = newslack;
1950 
1951  {
1952  /* the maximum index return by the UNIQUE_INDEX macro is 3 times
1953  * the maximum index value in the ROWINDEX struct. The index value could
1954  * be the lp position of an original row or the index of a transformed row.
1955  * Hence we need to allocate 3 times the maximum of these two possible
1956  * index types.
1957  */
1958  int allocsize = 3 * MAX(nlprows, mod2matrix->ntransintrows);
1959  SCIP_CALL( SCIPallocCleanBufferArray(scip, &contained, allocsize) );
1960  }
1961 
1962  /* remember entries that are in the row to add */
1963  for( i = 0; i < rowtoadd->nrowinds; ++i )
1964  {
1965  contained[UNIQUE_INDEX(rowtoadd->rowinds[i])] = 1;
1966  }
1967 
1968  /* remove the entries that are in both rows from the row (1 + 1 = 0 (mod 2)) */
1969  nnewentries = rowtoadd->nrowinds;
1970  for( i = 0; i < row->nrowinds; )
1971  {
1972  if( contained[UNIQUE_INDEX(row->rowinds[i])] )
1973  {
1974  --nnewentries;
1975  contained[UNIQUE_INDEX(row->rowinds[i])] = 0;
1976  --row->nrowinds;
1977  row->rowinds[i] = row->rowinds[row->nrowinds];
1978  }
1979  else
1980  {
1981  ++i;
1982  }
1983  }
1984 
1985  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &row->rowinds, &row->rowindssize, row->nrowinds + nnewentries) );
1986 
1987  /* add remaining entries of row to add */
1988  for ( i = 0; i < rowtoadd->nrowinds; ++i )
1989  {
1990  if( contained[UNIQUE_INDEX(rowtoadd->rowinds[i])] )
1991  {
1992  contained[UNIQUE_INDEX(rowtoadd->rowinds[i])] = 0;
1993  row->rowinds[row->nrowinds++] = rowtoadd->rowinds[i];
1994  }
1995  }
1996 
1997  SCIPfreeCleanBufferArray(scip, &contained);
1998 
1999  SCIP_CALL( SCIPallocBufferArray(scip, &newnonzcols, row->nnonzcols + rowtoadd->nnonzcols) );
2000 
2001  i = 0;
2002  j = 0;
2003  k = 0;
2004  row->maxsolval = 0.0;
2005 
2006  /* since columns are sorted we can merge them */
2007  while( i < row->nnonzcols && j < rowtoadd->nnonzcols )
2008  {
2009  if( row->nonzcols[i] == rowtoadd->nonzcols[j] )
2010  {
2011  SCIP_CALL( mod2colUnlinkRow(row->nonzcols[i], row) );
2012  ++i;
2013  ++j;
2014  }
2015  else if( row->nonzcols[i]->index < rowtoadd->nonzcols[j]->index )
2016  {
2017  row->maxsolval = MAX(row->maxsolval, row->nonzcols[i]->solval);
2018  newnonzcols[k++] = row->nonzcols[i++];
2019  }
2020  else
2021  {
2022  SCIP_CALL( mod2colLinkRow(blkmem, rowtoadd->nonzcols[j], row) );
2023  newnonzcols[k++] = rowtoadd->nonzcols[j++];
2024  }
2025  }
2026 
2027  while( i < row->nnonzcols )
2028  {
2029  row->maxsolval = MAX(row->maxsolval, row->nonzcols[i]->solval);
2030  newnonzcols[k++] = row->nonzcols[i++];
2031  }
2032 
2033  while( j < rowtoadd->nnonzcols )
2034  {
2035  SCIP_CALL( mod2colLinkRow(blkmem, rowtoadd->nonzcols[j], row) );
2036  newnonzcols[k++] = rowtoadd->nonzcols[j++];
2037  }
2038 
2039  row->nnonzcols = k;
2041  BMScopyMemoryArray(row->nonzcols, newnonzcols, row->nnonzcols);
2042 
2043  SCIPfreeBufferArray(scip, &newnonzcols);
2044 
2045  assert(row->nnonzcols == 0 || row->nonzcols != NULL);
2046  checkRow(row);
2047  checkRow(rowtoadd);
2048 
2049  return SCIP_OKAY;
2050 }
2051 
2052 /* --------------------------------------------------------------------------------------------------------------------
2053  * callback methods of separator
2054  * -------------------------------------------------------------------------------------------------------------------- */
2055 
2056 /** copy method for separator plugins (called when SCIP copies plugins) */
2057 static
2058 SCIP_DECL_SEPACOPY(sepaCopyZerohalf)
2059 { /*lint --e{715}*/
2060  assert(scip != NULL);
2061  assert(sepa != NULL);
2062  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
2063 
2064  /* call inclusion method of constraint handler */
2066 
2067  return SCIP_OKAY;
2068 }
2069 
2070 /** destructor of separator to free user data (called when SCIP is exiting) */
2071 static
2072 SCIP_DECL_SEPAFREE(sepaFreeZerohalf)
2074  SCIP_SEPADATA* sepadata;
2075 
2076  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
2077 
2078  /* free separator data */
2079  sepadata = SCIPsepaGetData(sepa);
2080  assert(sepadata != NULL);
2081 
2082  SCIPfreeBlockMemory(scip, &sepadata);
2083  SCIPsepaSetData(sepa, NULL);
2084 
2085  return SCIP_OKAY;
2086 }
2087 
2088 /** LP solution separation method of separator */
2089 static
2090 SCIP_DECL_SEPAEXECLP(sepaExeclpZerohalf)
2092  int i;
2093  int k;
2094  int maxsepacuts;
2095  SCIP_Real maxslack;
2096  SCIP_SEPADATA* sepadata;
2097  MOD2_MATRIX mod2matrix;
2098  MOD2_ROW** nonzrows;
2099 
2100  assert(result != NULL);
2101  assert(sepa != NULL);
2102  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
2103 
2104  *result = SCIP_DIDNOTRUN;
2105 
2106  /* only call separator, if we are not close to terminating */
2107  if( SCIPisStopped(scip) )
2108  return SCIP_OKAY;
2109 
2110  /* only call separator, if an optimal LP solution is at hand */
2112  return SCIP_OKAY;
2113 
2114  /* only call separator, if there are fractional variables */
2115  if( SCIPgetNLPBranchCands(scip) == 0 )
2116  return SCIP_OKAY;
2117 
2118  sepadata = SCIPsepaGetData(sepa);
2119  assert(sepadata != NULL);
2120 
2121  {
2122  int depth = SCIPgetDepth(scip);
2123  int ncalls = SCIPsepaGetNCallsAtNode(sepa);
2124 
2125  /* only call the cmir cut separator a given number of times at each node */
2126  if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
2127  || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
2128  return SCIP_OKAY;
2129 
2130  maxsepacuts = depth == 0 ? sepadata->maxsepacutsroot : sepadata->maxsepacuts;
2131  maxslack = depth == 0 ? sepadata->maxslackroot : sepadata->maxslack;
2132  maxslack += 2 * SCIPfeastol(scip);
2133  }
2134 
2135  *result = SCIP_DIDNOTFIND;
2136 
2137  SCIP_CALL( SCIPaggrRowCreate(scip, &sepadata->aggrrow) );
2138  sepadata->ncuts = 0;
2139  sepadata->cutssize = 0;
2140  sepadata->cutscores = NULL;
2141  sepadata->cuts = NULL;
2142  sepadata->infeasible = FALSE;
2143 
2144  SCIP_CALL( buildMod2Matrix(scip, sepadata, SCIPblkmem(scip), &mod2matrix, allowlocal, maxslack) );
2145 
2146  SCIPdebugMsg(scip, "built mod2 matrix (%i rows, %i cols)\n", mod2matrix.nrows, mod2matrix.ncols);
2147 
2148  SCIP_CALL( SCIPallocBufferArray(scip, &nonzrows, mod2matrix.nrows) );
2149 
2150  for( k = 0; k < MAXREDUCTIONROUNDS; ++k )
2151  {
2152  int ncancel;
2153 
2154  sepadata->nreductions = 0;
2155 
2156  assert(mod2matrix.nzeroslackrows <= mod2matrix.nrows);
2157  SCIP_CALL( mod2matrixPreprocessRows(scip, &mod2matrix, sepa, sepadata, allowlocal) );
2158  assert(mod2matrix.nzeroslackrows <= mod2matrix.nrows);
2159 
2160  SCIPdebugMsg(scip, "preprocessed rows (%i rows, %i cols, %i cuts) \n", mod2matrix.nrows, mod2matrix.ncols,
2161  sepadata->ncuts);
2162 
2163  if( mod2matrix.nrows == 0 )
2164  break;
2165 
2166  if( sepadata->ncuts >= sepadata->maxcutcands )
2167  {
2168  SCIPdebugMsg(scip, "enough cuts, stopping (%i rows, %i cols)\n", mod2matrix.nrows, mod2matrix.ncols);
2169  break;
2170  }
2171 
2172  SCIP_CALL( mod2matrixPreprocessColumns(scip, &mod2matrix, sepadata) );
2173 
2174  SCIPdebugMsg(scip, "preprocessed columns (%i rows, %i cols)\n", mod2matrix.nrows, mod2matrix.ncols);
2175 
2176  ncancel = mod2matrix.nrows;
2177  if( ncancel > 100 )
2178  {
2179  ncancel = 100;
2180  SCIPselectPtr((void**) mod2matrix.rows, compareRowSlack, ncancel, mod2matrix.nrows);
2181  }
2182 
2183  SCIPsortPtr((void**) mod2matrix.rows, compareRowSlack, ncancel);
2184 
2185  if( mod2matrix.ncols == 0 )
2186  break;
2187 
2188  assert(mod2matrix.nzeroslackrows <= mod2matrix.nrows);
2189 
2190  /* apply Prop5 */
2191  for( i = 0; i < ncancel; ++i )
2192  {
2193  int j;
2194  MOD2_COL* col = NULL;
2195  MOD2_ROW* row = mod2matrix.rows[i];
2196 
2197  if( SCIPisPositive(scip, row->slack) || row->nnonzcols == 0 )
2198  continue;
2199 
2200  SCIPdebugMsg(scip, "processing row %i/%i (%i/%i cuts)\n", i, mod2matrix.nrows, sepadata->ncuts, sepadata->maxcutcands);
2201 
2202  for( j = 0; j < row->nnonzcols; ++j )
2203  {
2204  if( row->nonzcols[j]->solval == row->maxsolval ) /*lint !e777*/
2205  {
2206  col = row->nonzcols[j];
2207  break;
2208  }
2209  }
2210 
2211  assert( col != NULL );
2212 
2213  {
2214  int nslots;
2215  int nnonzrows;
2216  MOD2_ROW** rows;
2217 
2218  ++sepadata->nreductions;
2219 
2220  nnonzrows = 0;
2221  /* cppcheck-suppress nullPointer */
2222  nslots = SCIPhashsetGetNSlots(col->nonzrows);
2223  /* cppcheck-suppress nullPointer */
2224  rows = (MOD2_ROW**) SCIPhashsetGetSlots(col->nonzrows);
2225 
2226  for( j = 0; j < nslots; ++j )
2227  {
2228  if( rows[j] != NULL && rows[j] != row )
2229  nonzrows[nnonzrows++] = rows[j];
2230  }
2231 
2232  for( j = 0; j < nnonzrows; ++j )
2233  {
2234  SCIP_CALL( mod2rowAddRow(scip, SCIPblkmem(scip), &mod2matrix, nonzrows[j], row) );
2235  }
2236 
2237  /* cppcheck-suppress nullPointer */
2238  row->slack = col->solval;
2239  --mod2matrix.nzeroslackrows;
2240 
2241  mod2matrixRemoveCol(scip, &mod2matrix, col);
2242  }
2243  }
2244 
2245  SCIPdebugMsg(scip, "applied proposition five (%i rows, %i cols)\n", mod2matrix.nrows, mod2matrix.ncols);
2246 
2247  if( sepadata->nreductions == 0 )
2248  {
2249  SCIPdebugMsg(scip, "no change, stopping (%i rows, %i cols)\n", mod2matrix.nrows, mod2matrix.ncols);
2250  break;
2251  }
2252  }
2253 
2254  for( i = 0; i < mod2matrix.nrows && sepadata->ncuts < sepadata->maxcutcands; ++i )
2255  {
2256  MOD2_ROW* row = mod2matrix.rows[i];
2257 
2258  if( computeMaxViolation(row) < sepadata->minviol )
2259  break;
2260 
2261  if( row->rhs == 0 )
2262  continue;
2263 
2264  SCIP_CALL( generateZerohalfCut(scip, &mod2matrix, sepa, sepadata, allowlocal, row) );
2265  }
2266 
2267  SCIPdebugMsg(scip, "total number of cuts found: %i\n", sepadata->ncuts);
2268 
2269  /* If cuts where found we apply a filtering procedure using the scores and the orthogonalities,
2270  * similar to the sepastore. We only add the cuts that make it through this process and discard
2271  * the rest.
2272  */
2273  if( sepadata->ncuts > 0 )
2274  {
2275  SCIP_Real goodscore;
2276  SCIP_Real badscore;
2277  int naccepted;
2278 
2279  SCIPsortDownRealPtr(sepadata->cutscores, (void**)sepadata->cuts, sepadata->ncuts);
2280 
2281  goodscore = sepadata->goodscore * sepadata->cutscores[0];
2282  badscore = sepadata->badscore * sepadata->cutscores[0];
2283  naccepted = 0;
2284 
2285  for( i = 0; i < sepadata->ncuts; ++i )
2286  {
2287  int j;
2288  int newncuts;
2289 
2290  if( sepadata->cuts[i] == NULL )
2291  continue;
2292 
2293  /* just release remaining cuts if the maximum number has been accepted or score is too bad */
2294  if( naccepted == maxsepacuts || sepadata->cutscores[i] < badscore )
2295  {
2296  SCIP_CALL( SCIPreleaseRow(scip, &sepadata->cuts[i]) );
2297  continue;
2298  }
2299 
2300  /* add global cuts to the pool and local cuts to the sepastore */
2301  if( SCIProwIsLocal(sepadata->cuts[i]) )
2302  {
2303  SCIP_CALL( SCIPaddRow(scip, sepadata->cuts[i], FALSE, &sepadata->infeasible) );
2304  }
2305  else
2306  {
2307  SCIP_CALL( SCIPaddPoolCut(scip, sepadata->cuts[i]) );
2308  }
2309 
2310  /* increase counters and initialize newncuts variable to truncate the
2311  * the loop if cuts at the end of the array have been removed already
2312  */
2313  newncuts = i;
2314  ++naccepted;
2315 
2316  for( j = i + 1; j < sepadata->ncuts; ++j )
2317  {
2318  SCIP_Real ortho;
2319 
2320  if( sepadata->cuts[j] == NULL )
2321  continue;
2322 
2323  /* compute orthogonality */
2324  ortho = SCIProwGetOrthogonality(sepadata->cuts[j], sepadata->cuts[i], 'e');
2325 
2326  /* if the orthogonality is below 0.5 we always discard the other cut and if it
2327  * is above 0.9 we always keep it. If the orthogonality is between these values we
2328  * only keep global cuts of relatively high quality.
2329  */
2330  if( ortho < 0.5 ||
2331  (ortho < 0.9 && (SCIProwIsLocal(sepadata->cuts[j]) || sepadata->cutscores[j] < goodscore)) )
2332  {
2333  SCIP_CALL( SCIPreleaseRow(scip, &sepadata->cuts[j]) );
2334  }
2335  else
2336  {
2337  newncuts = j + 1;
2338  }
2339  }
2340 
2341  /* release current cut */
2342  SCIP_CALL( SCIPreleaseRow(scip, &sepadata->cuts[i]) );
2343 
2344  /* remember new number of cuts so that we do not iterate over NULL values
2345  * at the end of the array over and over again
2346  */
2347  sepadata->ncuts = newncuts;
2348  }
2349 
2350  SCIPfreeBlockMemoryArray(scip, &sepadata->cuts, sepadata->cutssize);
2351  SCIPfreeBlockMemoryArray(scip, &sepadata->cutscores, sepadata->cutssize);
2352 
2353  if( sepadata->infeasible )
2354  *result = SCIP_CUTOFF;
2355  else
2356  *result = SCIP_SEPARATED;
2357  }
2358 
2359  SCIPfreeBufferArray(scip, &nonzrows);
2360  SCIPaggrRowFree(scip, &sepadata->aggrrow);
2361 
2362  destroyMod2Matrix(scip, &mod2matrix);
2363 
2364  return SCIP_OKAY;
2365 }
2366 
2367 /** creates the zerohalf separator and includes it in SCIP */
2369  SCIP* scip /**< SCIP data structure */
2370  )
2371 {
2372  SCIP_SEPADATA* sepadata;
2373  SCIP_SEPA* sepa;
2374 
2375  /* create zerohalf separator data */
2376  SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
2377 
2378  /* include separator */
2380  SEPA_USESSUBSCIP, SEPA_DELAY, sepaExeclpZerohalf, NULL, sepadata) );
2381 
2382  assert(sepa != NULL);
2383 
2384  /* set non-NULL pointers to callback methods */
2385  SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyZerohalf) );
2386  SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeZerohalf) );
2387 
2388  /* add zerohalf separator parameters */
2389  SCIP_CALL( SCIPaddIntParam(scip,
2390  "separating/" SEPA_NAME "/maxrounds",
2391  "maximal number of cmir separation rounds per node (-1: unlimited)",
2392  &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
2393  SCIP_CALL( SCIPaddIntParam(scip,
2394  "separating/" SEPA_NAME "/maxroundsroot",
2395  "maximal number of cmir separation rounds in the root node (-1: unlimited)",
2396  &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
2397  SCIP_CALL( SCIPaddIntParam(scip,
2398  "separating/" SEPA_NAME "/maxsepacuts",
2399  "maximal number of cmir cuts separated per separation round",
2400  &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
2401  SCIP_CALL( SCIPaddIntParam(scip,
2402  "separating/" SEPA_NAME "/maxsepacutsroot",
2403  "maximal number of cmir cuts separated per separation round in the root node",
2404  &sepadata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
2405  SCIP_CALL( SCIPaddIntParam(scip,
2406  "separating/" SEPA_NAME "/maxcutcands",
2407  "maximal number of zerohalf cuts considered per separation round",
2408  &sepadata->maxcutcands, FALSE, DEFAULT_MAXCUTCANDS, 0, INT_MAX, NULL, NULL) );
2410  "separating/" SEPA_NAME "/maxslack",
2411  "maximal slack of rows to be used in aggregation",
2412  &sepadata->maxslack, TRUE, DEFAULT_MAXSLACK, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2414  "separating/" SEPA_NAME "/maxslackroot",
2415  "maximal slack of rows to be used in aggregation in the root node",
2416  &sepadata->maxslackroot, TRUE, DEFAULT_MAXSLACKROOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2418  "separating/" SEPA_NAME "/goodscore",
2419  "threshold for score of cut relative to best score to be considered good, so that less strict filtering is applied",
2420  &sepadata->goodscore, TRUE, DEFAULT_GOODSCORE, 0.0, 1.0, NULL, NULL) );
2422  "separating/" SEPA_NAME "/badscore",
2423  "threshold for score of cut relative to best score to be discarded",
2424  &sepadata->badscore, TRUE, DEFAULT_BADSCORE, 0.0, 1.0, NULL, NULL) );
2426  "separating/" SEPA_NAME "/minviol",
2427  "minimal violation to generate zerohalfcut for",
2428  &sepadata->minviol, TRUE, DEFAULT_MINVIOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2430  "separating/" SEPA_NAME "/dynamiccuts",
2431  "should generated cuts be removed from the LP if they are no longer tight?",
2432  &sepadata->dynamiccuts, FALSE, DEFAULT_DYNAMICCUTS, NULL, NULL) );
2434  "separating/" SEPA_NAME "/maxrowdensity",
2435  "maximal density of row to be used in aggregation",
2436  &sepadata->maxrowdensity, TRUE, DEFAULT_MAXROWDENSITY, 0.0, 1.0, NULL, NULL) );
2437  SCIP_CALL( SCIPaddIntParam(scip,
2438  "separating/" SEPA_NAME "/densityoffset",
2439  "additional number of variables allowed in row on top of density",
2440  &sepadata->densityoffset, TRUE, DEFAULT_DENSITYOFFSET, 0, INT_MAX, NULL, NULL) );
2441 
2442  return SCIP_OKAY;
2443 }
#define BOUNDSWITCH
Definition: sepa_zerohalf.c:83
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22604
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip.c:29675
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:22593
void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1570
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17490
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:46443
#define COLINFO_CREATE(mod2col, rhsoffset)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22587
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30613
#define DEFAULT_MAXSLACK
Definition: sepa_zerohalf.c:66
#define DEFAULT_MAXSLACKROOT
Definition: sepa_zerohalf.c:67
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47298
SCIP_Real * vals
static SCIP_RETCODE mod2matrixPreprocessRows(SCIP *scip, MOD2_MATRIX *mod2matrix, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_Bool allowlocal)
SCIP_RETCODE SCIPhashsetRemove(SCIP_HASHSET *hashset, void *element)
Definition: misc.c:3439
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2265
static void mod2matrixRemoveCol(SCIP *scip, MOD2_MATRIX *mod2matrix, MOD2_COL *col)
int SCIPhashsetGetNElements(SCIP_HASHSET *hashset)
Definition: misc.c:3573
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30636
void ** SCIPhashsetGetSlots(SCIP_HASHSET *hashset)
Definition: misc.c:3589
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17276
#define SCIP_MAXSTRLEN
Definition: def.h:259
static SCIP_DECL_HASHKEYVAL(columnGetSignature)
#define ORIG_LHS
Definition: sepa_zerohalf.c:96
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:46813
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:30668
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16405
#define COLINFO_GET_RHSOFFSET(x)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:47088
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17332
int rowindssize
MOD2_ROW ** rows
void SCIPsortDownRealPtr(SCIP_Real *realarray, void **ptrarray, int len)
int rank
Definition: struct_lp.h:239
SCIP_Real SCIPfeasRound(SCIP *scip, SCIP_Real val)
Definition: scip.c:47447
static SCIP_RETCODE mod2colUnlinkRow(MOD2_COL *col, MOD2_ROW *row)
MOD2_COL ** nonzcols
static SCIP_RETCODE mod2matrixRemoveRow(SCIP *scip, MOD2_MATRIX *mod2matrix, MOD2_ROW *row)
SCIP_RETCODE SCIPincludeSepaZerohalf(SCIP *scip)
int SCIProwGetNLPNonz(SCIP_ROW *row)
Definition: lp.c:16419
#define DEFAULT_GOODSCORE
Definition: sepa_zerohalf.c:68
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:9639
static SCIP_RETCODE mod2rowAddRow(SCIP *scip, BMS_BLKMEM *blkmem, MOD2_MATRIX *mod2matrix, MOD2_ROW *row, MOD2_ROW *rowtoadd)
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16484
#define FALSE
Definition: def.h:64
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2793
#define TRANSROW
Definition: sepa_zerohalf.c:97
SCIP_Bool SCIPcolIsIntegral(SCIP_COL *col)
Definition: lp.c:16274
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10289
static SCIP_Real calcEfficacy(SCIP *scip, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
static void mod2rowUnlinkCol(MOD2_ROW *row, MOD2_COL *col)
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:47028
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10011
#define TRUE
Definition: def.h:63
SCIP_RETCODE SCIPhashsetCreate(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem, int size)
Definition: misc.c:3340
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:646
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
#define ROWIND_TYPE
Definition: sepa_zerohalf.c:94
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:16969
SCIP_Bool SCIPhashsetExists(SCIP_HASHSET *hashset, void *element)
Definition: misc.c:3398
#define SCIP_UNUSED(x)
Definition: def.h:404
SCIP_Real SCIPgetVectorEfficacyNorm(SCIP *scip, SCIP_Real *vals, int nvals)
Definition: scip.c:34560
#define MAXAGGRLEN(nvars)
Definition: sepa_zerohalf.c:84
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:22602
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17480
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2931
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46963
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:22632
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:22585
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip.c:37034
SCIP_RETCODE SCIPgetLPColsData(SCIP *scip, SCIP_COL ***cols, int *ncols)
Definition: scip.c:29562
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
Definition: scip.c:7427
#define SCIPdebugMsg
Definition: scip.h:455
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4265
int SCIPhashsetGetNSlots(SCIP_HASHSET *hashset)
Definition: misc.c:3581
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:11992
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:46415
SCIP_RETCODE SCIPgetVarClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvlb, int *closestvlbidx)
Definition: scip.c:23923
#define DEFAULT_MAXROUNDSROOT
Definition: sepa_zerohalf.c:62
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
Definition: scip.c:47435
SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
Definition: sepa.c:557
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2014
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:47423
#define SCIP_DEFAULT_EPSILON
Definition: def.h:155
#define UNIQUE_INDEX(rowind)
SCIP_Real * vals
Definition: struct_lp.h:220
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition: scip.h:22638
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17286
SCIP_Real maxsolval
#define MAXREDUCTIONROUNDS
Definition: sepa_zerohalf.c:82
static SCIP_DECL_SEPAEXECLP(sepaExeclpZerohalf)
#define SEPA_FREQ
Definition: sepa_zerohalf.c:56
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46976
SCIP_COL ** cols
Definition: struct_lp.h:218
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:16593
TRANSINTROW * transintrows
void SCIPhashsetFree(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem)
Definition: misc.c:3371
#define BMSmoveMemoryArray(ptr, source, num)
Definition: memory.h:120
int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
Definition: sepa.c:773
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip.c:34546
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:46731
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
SCIP_Real lhs
Definition: struct_lp.h:195
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17542
SCIPInterval sign(const SCIPInterval &x)
#define SEPA_NAME
Definition: sepa_zerohalf.c:53
SCIP_Bool local
SCIP_Bool SCIProwIsIntegral(SCIP_ROW *row)
Definition: lp.c:16583
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2826
void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
Definition: sepa.c:567
#define SCIP_Shortbool
Definition: def.h:69
#define SEPA_USESSUBSCIP
Definition: sepa_zerohalf.c:58
#define REALABS(x)
Definition: def.h:173
#define ORIG_RHS
Definition: sepa_zerohalf.c:95
int SCIPgetNLPRows(SCIP *scip)
Definition: scip.c:29696
SCIP_Bool SCIPisSumEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47197
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_HASHSET * nonzrows
#define SCIP_CALL(x)
Definition: def.h:350
#define MAXDNOM
Definition: sepa_zerohalf.c:78
#define SCIPensureBlockMemoryArray(scip, ptr, arraysizeptr, minsize)
Definition: scip.h:22601
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17500
#define SCIPhashSignature64(a)
Definition: pub_misc.h:472
#define DEFAULT_MAXSEPACUTS
Definition: sepa_zerohalf.c:63
SCIP_RETCODE SCIPgetVarClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvub, int *closestvubidx)
Definition: scip.c:23946
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2395
#define DEFAULT_MAXROWDENSITY
Definition: sepa_zerohalf.c:74
#define SEPA_DELAY
Definition: sepa_zerohalf.c:59
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16494
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17532
SCIP_Real SCIPgetRowLPActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30960
static SCIP_DECL_HASHKEYEQ(columnsEqual)
void SCIPselectPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int k, int len)
#define DEFAULT_MAXCUTCANDS
Definition: sepa_zerohalf.c:65
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:34661
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:16603
MOD2_COL ** cols
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:16430
int var_probindex
Definition: struct_lp.h:169
SCIP_RETCODE SCIPincludeSepaBasic(SCIP *scip, SCIP_SEPA **sepa, const char *name, const char *desc, int priority, int freq, SCIP_Real maxbounddist, SCIP_Bool usessubscip, SCIP_Bool delay, SCIP_DECL_SEPAEXECLP((*sepaexeclp)), SCIP_DECL_SEPAEXECSOL((*sepaexecsol)), SCIP_SEPADATA *sepadata)
Definition: scip.c:7385
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:22620
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:16440
SCIP_Bool SCIPisSumGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47236
static SCIP_Real computeMaxViolation(MOD2_ROW *row)
static void addOrigRow(SCIP *scip, SCIP_Real *tmpcoefs, SCIP_Real *cutrhs, int *nonzeroinds, int *nnz, int *cutrank, SCIP_Bool *cutislocal, SCIP_ROW *row, int sign)
static int mod2(SCIP *scip, SCIP_Real val)
SCIP_Real solval
#define SCIP_Bool
Definition: def.h:61
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:29293
SCIP_Real rhs
SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
Definition: cuts.c:1337
static SCIP_RETCODE mod2MatrixAddTransRow(SCIP *scip, MOD2_MATRIX *mod2matrix, SCIP_HASHMAP *origcol2col, int transrowind)
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:43045
static void destroyMod2Matrix(SCIP *scip, MOD2_MATRIX *mod2matrix)
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:34772
#define NONZERO(x)
SCIP_Real slack
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:30431
static void addTransRow(SCIP_Real *tmpcoefs, SCIP_Real *cutrhs, int *nonzeroinds, int *nnz, int *cutrank, SCIP_Bool *cutislocal, TRANSINTROW *introw)
SCIP_Real slack
static SCIP_RETCODE mod2MatrixAddCol(SCIP *scip, MOD2_MATRIX *mod2matrix, SCIP_HASHMAP *origvar2col, SCIP_VAR *origvar, SCIP_Real solval, int rhsoffset)
static SCIP_DECL_SORTPTRCOMP(compareColIndex)
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:116
Constraint handler for linear constraints in their most general form, .
static void getIntegralScalar(SCIP_Real val, SCIP_Real scalar, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Real *sval, SCIP_Real *intval)
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2326
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:47039
#define DEFAULT_DENSITYOFFSET
Definition: sepa_zerohalf.c:75
SCIP_Bool SCIPisCutNew(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:34754
int SCIProwGetRank(SCIP_ROW *row)
Definition: lp.c:16573
{0,1/2}-cuts separator
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2064
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:11812
#define SCIP_REAL_MAX
Definition: def.h:150
static SCIP_RETCODE mod2MatrixAddOrigRow(SCIP *scip, BMS_BLKMEM *blkmem, MOD2_MATRIX *mod2matrix, SCIP_HASHMAP *origcol2col, SCIP_ROW *origrow, SCIP_Real slack, ROWIND_TYPE side, int rhsmod2)
SCIP_Real rhs
Definition: struct_lp.h:196
SCIP_Real constant
Definition: struct_lp.h:194
unsigned int type
int nzeroslackrows
SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
Definition: lp.c:16450
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:30540
#define DEFAULT_MINVIOL
Definition: sepa_zerohalf.c:72
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAFREE((*sepafree)))
Definition: scip.c:7443
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47002
#define DEFAULT_DYNAMICCUTS
Definition: sepa_zerohalf.c:73
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16254
unsigned int index
#define COLINFO_GET_MOD2COL(x)
void SCIProwChgRank(SCIP_ROW *row, int rank)
Definition: lp.c:16706
#define DEFAULT_BADSCORE
Definition: sepa_zerohalf.c:71
#define SEPA_PRIORITY
Definition: sepa_zerohalf.c:55
static SCIP_RETCODE buildMod2Matrix(SCIP *scip, SCIP_SEPADATA *sepadata, BMS_BLKMEM *blkmem, MOD2_MATRIX *mod2matrix, SCIP_Bool allowlocal, SCIP_Real maxslack)
static void checkRow(MOD2_ROW *row)
data structures for LP management
static SCIP_RETCODE mod2MatrixTransformContRows(SCIP *scip, SCIP_SEPADATA *sepadata, MOD2_MATRIX *mod2matrix, SCIP_Bool allowlocal, SCIP_Real maxslack)
SCIP_RETCODE SCIPhashsetInsert(SCIP_HASHSET *hashset, BMS_BLKMEM *blkmem, void *element)
Definition: misc.c:3381
#define SEPA_MAXBOUNDDIST
Definition: sepa_zerohalf.c:57
static SCIP_RETCODE transformNonIntegralRow(SCIP *scip, SCIP_Bool allowlocal, SCIP_Real maxslack, int sign, SCIP_Bool local, int rank, int rowlen, SCIP_Real *rowvals, SCIP_COL **rowcols, SCIP_Real rhs, int *intvarpos, TRANSINTROW *introw, SCIP_Bool *success)
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:11767
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:16673
static SCIP_Real computeViolation(MOD2_ROW *row)
#define SCIP_Real
Definition: def.h:149
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition: scip.h:22642
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1145
#define DEFAULT_MAXROUNDS
Definition: sepa_zerohalf.c:61
int nrowinds
SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1538
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17522
SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
Definition: misc.c:8881
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2377
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:47076
SCIP_Real SCIPgetVarSol(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:19832
#define SEPA_DESC
Definition: sepa_zerohalf.c:54
int SCIPgetNLPCols(SCIP *scip)
Definition: scip.c:29618
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17342
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:22605
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:47399
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:433
SCIP_Real SCIPsumepsilon(SCIP *scip)
Definition: scip.c:46429
int nnonzcols
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2874
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47210
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip.c:29640
ROWINDEX * rowinds
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:9613
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:419
static SCIP_RETCODE mod2matrixPreprocessColumns(SCIP *scip, MOD2_MATRIX *mod2matrix, SCIP_SEPADATA *sepadata)
#define SCIP_ALLOC(x)
Definition: def.h:361
SCIP_Longint SCIPgetNLPs(SCIP *scip)
Definition: scip.c:42314
#define SCIPABORT()
Definition: def.h:322
static SCIP_RETCODE generateZerohalfCut(SCIP *scip, MOD2_MATRIX *mod2matrix, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_Bool allowlocal, MOD2_ROW *row)
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
Definition: scip.c:47173
#define MAXSCALE
Definition: sepa_zerohalf.c:79
int nonzcolssize
default SCIP plugins
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4321
unsigned int local
Definition: struct_lp.h:249
#define EPSZ(x, eps)
Definition: def.h:179
static SCIP_RETCODE mod2colLinkRow(BMS_BLKMEM *blkmem, MOD2_COL *col, MOD2_ROW *row)
static SCIP_DECL_SEPAFREE(sepaFreeZerohalf)
struct SCIP_SepaData SCIP_SEPADATA
Definition: type_sepa.h:38
int len
Definition: struct_lp.h:226
SCIP_Real SCIProwGetOrthogonality(SCIP_ROW *row1, SCIP_ROW *row2, char orthofunc)
Definition: lp.c:7594
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4239
#define DEFAULT_MAXSEPACUTSROOT
Definition: sepa_zerohalf.c:64
static SCIP_DECL_SEPACOPY(sepaCopyZerohalf)