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