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