SCIP

    Solving Constraint Integer Programs

    cuts.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 cuts.c
    26 * @ingroup OTHER_CFILES
    27 * @brief methods for aggregation of rows
    28 * @author Jakob Witzig
    29 * @author Leona Gottwald
    30 * @author Marc Pfetsch
    31 */
    32
    33/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    35#include "scip/cuts.h"
    36#include "scip/certificate.h"
    37#include "scip/dbldblarith.h"
    38#include "scip/intervalarith.h"
    39#include "scip/lp.h"
    40#include "scip/misc.h"
    41#include "scip/pub_lp.h"
    42#include "scip/pub_lpexact.h"
    43#include "scip/pub_message.h"
    44#include "scip/pub_misc.h"
    46#include "scip/pub_misc_sort.h"
    47#include "scip/pub_var.h"
    49#include "scip/scip_cut.h"
    50#include "scip/scip_exact.h"
    51#include "scip/scip_lp.h"
    52#include "scip/scip_mem.h"
    53#include "scip/scip_message.h"
    54#include "scip/scip_numerics.h"
    55#include "scip/scip_prob.h"
    56#include "scip/scip_sol.h"
    58#include "scip/scip_var.h"
    59#include "scip/struct_lp.h"
    60#include "scip/struct_lpexact.h"
    61#include "scip/struct_scip.h"
    62#include "scip/struct_set.h"
    65#include "scip/rational.h"
    66
    67/*
    68 * Default values for cut generation parameters
    69 */
    70#define DEFAULT_CUTGEN_POSTPROCESS TRUE /**< default for applying post-processing */
    71#define DEFAULT_CUTGEN_BOUNDSWITCH 0.5 /**< default fraction of domain for bound switching */
    72#define DEFAULT_CUTGEN_ALLOWLOCAL TRUE /**< default for allowing local cuts */
    73#define DEFAULT_CUTGEN_VARTYPEUSEVBDS 2 /**< default variable types for varbound substitution */
    74#define DEFAULT_CUTGEN_MINFRAC 0.05 /**< default minimal fractionality of rhs */
    75#define DEFAULT_CUTGEN_MAXFRAC 0.999 /**< default maximal fractionality of rhs */
    76#define DEFAULT_CUTGEN_MAXTESTDELTA (-1) /**< default maximum number of deltas to test (-1 = unlimited) */
    77
    78/* =========================================== general static functions =========================================== */
    79#ifdef SCIP_DEBUG
    80static
    81void printCutQuad(
    82 SCIP* scip, /**< SCIP data structure */
    83 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    84 SCIP_Real* cutcoefs, /**< non-zero coefficients of cut */
    85 QUAD(SCIP_Real cutrhs), /**< right hand side of the MIR row */
    86 int* cutinds, /**< indices of problem variables for non-zero coefficients */
    87 int cutnnz, /**< number of non-zeros in cut */
    88 SCIP_Bool ignoresol,
    89 SCIP_Bool islocal
    90 )
    91{
    92 SCIP_Real QUAD(activity);
    93 SCIP_VAR** vars;
    94
    95 assert(scip != NULL);
    96 vars = SCIPgetVars(scip);
    97
    98 SCIPdebugMsg(scip, "CUT:");
    99 QUAD_ASSIGN(activity, 0.0);
    100
    101 /**! [SnippetCodeStyleInLoopDeclaration] */
    102 for( int i = 0; i < cutnnz; ++i )
    103 {
    104 SCIP_Real QUAD(coef);
    105
    106 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
    107
    108 if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_BINARY )
    109 SCIPdebugMsgPrint(scip, " %+g<%s>[B]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
    110 else if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_INTEGER )
    111 SCIPdebugMsgPrint(scip, " %+g<%s>[I]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
    112 else
    113 SCIPdebugMsgPrint(scip, " %+g<%s>[C]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
    114
    115 if( ! ignoresol )
    116 {
    117 SCIPquadprecProdQD(coef, coef, (sol == NULL ? SCIPvarGetLPSol(vars[cutinds[i]]) : SCIPgetSolVal(scip, sol, vars[cutinds[i]])));
    118 }
    119 else
    120 {
    121 if( cutcoefs[i] > 0.0 )
    122 {
    123 SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]])));
    124 }
    125 else
    126 {
    127 SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]])));
    128 }
    129 }
    130
    131 SCIPquadprecSumQQ(activity, activity, coef);
    132 }
    133 /**! [SnippetCodeStyleInLoopDeclaration] */
    134 SCIPdebugMsgPrint(scip, " <= %.6f (activity: %g)\n", QUAD_TO_DBL(cutrhs), QUAD_TO_DBL(activity));
    135}
    136
    137static
    138void printCut(
    139 SCIP* scip, /**< SCIP data structure */
    140 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    141 SCIP_Real* cutcoefs, /**< non-zero coefficients of cut */
    142 SCIP_Real cutrhs, /**< right hand side of the MIR row */
    143 int* cutinds, /**< indices of problem variables for non-zero coefficients */
    144 int cutnnz, /**< number of non-zeros in cut */
    145 SCIP_Bool ignoresol,
    146 SCIP_Bool islocal
    147 )
    148{
    149 SCIP_Real activity;
    150 SCIP_VAR** vars;
    151 int i;
    152
    153 assert(scip != NULL);
    154 vars = SCIPgetVars(scip);
    155
    156 SCIPdebugMsg(scip, "CUT:");
    157 activity = 0.0;
    158 for( i = 0; i < cutnnz; ++i )
    159 {
    160 SCIP_Real coef;
    161
    162 coef = cutcoefs[cutinds[i]];
    163
    164 if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_BINARY )
    165 SCIPdebugMsgPrint(scip, " %+g<%s>[B]", coef, SCIPvarGetName(vars[cutinds[i]]));
    166 else if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_INTEGER )
    167 SCIPdebugMsgPrint(scip, " %+g<%s>[I]", coef, SCIPvarGetName(vars[cutinds[i]]));
    168 else
    169 SCIPdebugMsgPrint(scip, " %+g<%s>[C]", coef, SCIPvarGetName(vars[cutinds[i]]));
    170
    171 if( ! ignoresol )
    172 {
    173 coef = coef * (sol == NULL ? SCIPvarGetLPSol(vars[cutinds[i]]) : SCIPgetSolVal(scip, sol, vars[cutinds[i]]));
    174 }
    175 else
    176 {
    177 if( cutcoefs[i] > 0.0 )
    178 {
    179 coef = coef * (islocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]));
    180 }
    181 else
    182 {
    183 coef = coef * (islocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
    184 }
    185 }
    186
    187 activity += coef;
    188 }
    189 SCIPdebugMsgPrint(scip, " <= %.6f (activity: %g)\n", cutrhs, activity);
    190}
    191#endif
    192
    193/** macro to make sure a value is not equal to zero, i.e. NONZERO(x) != 0.0
    194 * will be TRUE for every x including 0.0
    195 *
    196 * To avoid branches it will add 1e-100 with the same sign as x to x which will
    197 * be rounded away for any sane non-zero value but will make sure the value is
    198 * never exactly 0.0.
    199 */
    200#define NONZERO(x) (COPYSIGN(1e-100, (x)) + (x))
    201
    202/** add a scaled row to a dense vector indexed over the problem variables and keep the
    203 * index of non-zeros up-to-date
    204 */
    205static
    207 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
    208 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
    209 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
    210 SCIP_ROW* row, /**< row coefficients to add to variable vector */
    211 SCIP_Real scale /**< scale for adding given row to variable vector */
    212 )
    213{
    214 int i;
    215
    216 assert(inds != NULL);
    217 assert(vals != NULL);
    218 assert(nnz != NULL);
    219 assert(row != NULL);
    220
    221 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    222 for( i = 0 ; i < row->len; ++i )
    223 {
    224 SCIP_Real val;
    225 int probindex;
    226
    227 probindex = row->cols[i]->var_probindex;
    228 val = vals[probindex];
    229
    230 if( val == 0.0 )
    231 inds[(*nnz)++] = probindex;
    232
    233 val += row->vals[i] * scale;
    234
    235 /* the value must not be exactly zero due to sparsity pattern */
    236 val = NONZERO(val);
    237
    238 assert(val != 0.0);
    239 vals[probindex] = val;
    240 }
    241
    242 return SCIP_OKAY;
    243}
    244
    245/** add a scaled row to a dense vector indexed over the problem variables and keep the
    246 * index of non-zeros up-to-date
    247 *
    248 * This is the quad precision version of varVecAddScaledRowCoefs().
    249 */
    250static
    252 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
    253 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
    254 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
    255 SCIP_ROW* row, /**< row coefficients to add to variable vector */
    256 SCIP_Real scale /**< scale for adding given row to variable vector */
    257 )
    258{
    259 int i;
    260
    261 assert(inds != NULL);
    262 assert(vals != NULL);
    263 assert(nnz != NULL);
    264 assert(row != NULL);
    265
    266 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    267 for( i = 0 ; i < row->len; ++i )
    268 {
    269 SCIP_Real QUAD(scaledrowval);
    270 SCIP_Real QUAD(val);
    271 int probindex;
    272
    273 probindex = row->cols[i]->var_probindex;
    274 QUAD_ARRAY_LOAD(val, vals, probindex);
    275
    276 if( QUAD_HI(val) == 0.0 )
    277 inds[(*nnz)++] = probindex;
    278
    279 SCIPquadprecProdDD(scaledrowval, row->vals[i], scale);
    280 SCIPquadprecSumQQ(val, val, scaledrowval);
    281
    282 /* the value must not be exactly zero due to sparsity pattern */
    283 QUAD_HI(val) = NONZERO(QUAD_HI(val));
    284 assert(QUAD_HI(val) != 0.0);
    285
    286 QUAD_ARRAY_STORE(vals, probindex, val);
    287 }
    288
    289 return SCIP_OKAY;
    290}
    291
    292/** add a scaled row to a dense vector indexed over the problem variables and keep the
    293 * index of non-zeros up-to-date
    294 *
    295 * This is the quad precision version of varVecAddScaledRowCoefs() with a quad precision scaling factor.
    296 */
    297static
    299 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
    300 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
    301 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
    302 SCIP_ROW* row, /**< row coefficients to add to variable vector */
    303 QUAD(SCIP_Real scale) /**< scale for adding given row to variable vector */
    304 )
    305{
    306 int i;
    307
    308 assert(inds != NULL);
    309 assert(vals != NULL);
    310 assert(nnz != NULL);
    311 assert(row != NULL);
    312
    313 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    314 for( i = 0 ; i < row->len; ++i )
    315 {
    316 SCIP_Real QUAD(val);
    317 SCIP_Real QUAD(rowval);
    318 int probindex;
    319
    320 probindex = row->cols[i]->var_probindex;
    321 QUAD_ARRAY_LOAD(val, vals, probindex);
    322
    323 if( QUAD_HI(val) == 0.0 )
    324 {
    325 inds[(*nnz)++] = probindex;
    326 SCIPquadprecProdQD(val, scale, row->vals[i]);
    327 }
    328 else
    329 {
    330 SCIPquadprecProdQD(rowval, scale, row->vals[i]);
    331 SCIPquadprecSumQQ(val, val, rowval);
    332 }
    333
    334 /* the value must not be exactly zero due to sparsity pattern */
    335 QUAD_HI(val) = NONZERO(QUAD_HI(val));
    336 assert(QUAD_HI(val) != 0.0);
    337
    338 QUAD_ARRAY_STORE(vals, probindex, val);
    339 }
    340
    341 return SCIP_OKAY;
    342}
    343
    344/** add a scaled row to a dense vector indexed over the problem variables and keep the index of non-zeros up-to-date
    345 *
    346 * In the safe variant, we need to transform all variables (implicitly) to nonnegative variables using their
    347 * upper/lower bounds. When adding \f$\lambda * (c^Tx \le d)\f$ to \f$a^Tx \le b\f$, this results in:
    348 *
    349 * \f{align*}{
    350 * m_i & =a_i+\lambda c_i \\
    351 * U \cap L & = \emptyset \\
    352 * U & = \{ i : x_i \le u_i\} \\
    353 * L & = \{ i : x_i \ge l_i\} \\
    354 * \sum_{i \in U} \overline{m_i}x_i + \sum_{i \in L}\underline{m_i}x_i
    355 * & \le b+ \lambda d + \sum_{i \in U, u_i > 0}(\overline{m_i}-\underline{m_i})u_i + \sum_{i \in L, l_i < 0}(\underline{m_i}-\overline{m_i})l_i
    356 * \f}
    357 *
    358 * This methods sums up the left hand side, and stores the change of the rhs due to the variable bounds in rhschange.
    359 *
    360 * @note this method is safe for usage in exact solving mode
    361 */
    362static
    364 SCIP* scip, /**< scip data structure */
    365 int* inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
    366 SCIP_Real* vals, /**< array with values of variable vector */
    367 int* nnz, /**< number of non-zeros coefficients of variable vector */
    368 SCIP_ROW* row, /**< row coefficients to add to variable vector */
    369 SCIP_Real scale, /**< scale for adding given row to variable vector */
    370 SCIP_Real* rhschange, /**< change in rhs due to variable conjugation */
    371 SCIP_Bool* success /**< was the addition successful? */
    372 )
    373{
    374 int i;
    375 SCIP_ROUNDMODE previousroundmode;
    376 SCIP_VAR* var;
    377 SCIP_ROWEXACT* rowexact;
    378
    379 assert(SCIPisExact(scip));
    380 assert(inds != NULL);
    381 assert(vals != NULL);
    382 assert(nnz != NULL);
    383 assert(row != NULL);
    384 assert(rhschange != NULL);
    385 assert(success != NULL);
    386 assert(*success);
    387
    388 previousroundmode = SCIPintervalGetRoundingMode();
    390
    391 *rhschange = 0;
    392 rowexact = SCIProwGetRowExact(row);
    393
    394 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    395 for( i = 0 ; i < row->len; ++i )
    396 {
    397 SCIP_Real val;
    398 SCIP_INTERVAL valinterval;
    399 int probindex;
    400
    401 probindex = row->cols[i]->var_probindex;
    402 var = row->cols[i]->var;
    403 val = vals[probindex];
    404
    405 if( val == 0.0 )
    406 {
    407 assert(*nnz < SCIPgetNVars(scip));
    408 inds[(*nnz)++] = probindex;
    409 }
    410
    411 if( val == SCIP_INVALID ) /*lint !e777*/
    412 val = 0.0;
    413
    414 SCIPintervalSetBounds(&valinterval, rowexact->valsinterval[i].inf, rowexact->valsinterval[i].sup);
    415 SCIPintervalMulScalar(SCIPinfinity(scip), &valinterval, valinterval, scale);
    416 SCIPintervalAddScalar(SCIPinfinity(scip), &valinterval, valinterval, val);
    417
    418 if( SCIPisInfinity(scip, REALABS(valinterval.inf)) || SCIPisInfinity(scip, REALABS(valinterval.sup)) )
    419 {
    420 *success = FALSE;
    421 SCIPintervalSetRoundingMode(previousroundmode);
    422 return SCIP_OKAY;
    423 }
    424
    425 if( SCIPvarGetLbGlobal(var) > -SCIPinfinity(scip) && SCIPvarGetLbGlobal(var) >= 0 )
    426 val = valinterval.inf;
    427 else if(SCIPvarGetUbGlobal(var) < SCIPinfinity(scip) && SCIPvarGetUbGlobal(var) <= 0 )
    428 val = valinterval.sup;
    429 else if( SCIPvarGetLbGlobal(var) > -SCIPinfinity(scip) )
    430 {
    431 val = valinterval.inf;
    433 *rhschange += (valinterval.sup - valinterval.inf) * (-SCIPvarGetLbGlobal(var));
    434 }
    435 else if( SCIPvarGetUbGlobal(var) < SCIPinfinity(scip) )
    436 {
    437 val = valinterval.sup;
    439 *rhschange += (valinterval.sup - valinterval.inf) * (SCIPvarGetUbGlobal(var));
    440 }
    441 else
    442 {
    443 *success = FALSE;
    444 SCIPintervalSetRoundingMode(previousroundmode);
    445 return SCIP_OKAY;
    446 }
    447
    448 /* we can't set the value to 0 or the sparsity pattern does not work. We can't perturb it slightly because we are solving
    449 * exactly; this is taken care of in removeZerosSafely */
    450 if( val == 0.0 )
    451 val = SCIP_INVALID;
    452
    453 vals[probindex] = val;
    454 }
    455
    456 SCIPintervalSetRoundingMode(previousroundmode);
    457
    458 return SCIP_OKAY;
    459}
    460
    461/** calculates the cut efficacy for the given solution */
    462static
    464 SCIP* scip, /**< SCIP data structure */
    465 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
    466 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    467 SCIP_Real cutrhs, /**< the right hand side of the cut */
    468 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    469 int cutnnz /**< the number of non-zeros in the cut */
    470 )
    471{
    472 SCIP_VAR** vars;
    473 SCIP_Real norm = 0.0;
    474 SCIP_Real activity = 0.0;
    475 int i;
    476
    477 assert(scip != NULL);
    478 assert(cutcoefs != NULL);
    479 assert(cutinds != NULL);
    480
    481 vars = SCIPgetVars(scip);
    482
    483 switch( scip->set->sepa_efficacynorm )
    484 {
    485 case 'e':
    486 for( i = 0; i < cutnnz; ++i )
    487 {
    488 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    489 norm += SQR(cutcoefs[i]);
    490 }
    491 norm = sqrt(norm);
    492 break;
    493 case 'm':
    494 for( i = 0; i < cutnnz; ++i )
    495 {
    496 SCIP_Real absval;
    497
    498 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    499 absval = REALABS(cutcoefs[i]);
    500 norm = MAX(norm, absval);
    501 }
    502 break;
    503 case 's':
    504 for( i = 0; i < cutnnz; ++i )
    505 {
    506 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    507 norm += REALABS(cutcoefs[i]);
    508 }
    509 break;
    510 case 'd':
    511 for( i = 0; i < cutnnz; ++i )
    512 {
    513 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    514 if( !SCIPisZero(scip, cutcoefs[i]) )
    515 norm = 1.0;
    516 }
    517 break;
    518 default:
    519 SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", scip->set->sepa_efficacynorm);
    520 assert(FALSE); /*lint !e506*/
    521 }
    522
    523 return (activity - cutrhs) / MAX(1e-6, norm);
    524}
    525
    526/** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter */
    527static
    529 SCIP* scip, /**< SCIP data structure */
    530 SCIP_Real* vals, /**< array of the non-zero coefficients in the vector; this is a quad precision array! */
    531 int* inds, /**< array of the problem indices of variables with a non-zero coefficient in the vector */
    532 int nnz /**< the number of non-zeros in the vector */
    533 )
    534{
    535 SCIP_Real norm = 0.0;
    536 SCIP_Real QUAD(coef);
    537 int i;
    538
    539 assert(scip != NULL);
    540 assert(scip->set != NULL);
    541
    542 switch( scip->set->sepa_efficacynorm )
    543 {
    544 case 'e':
    545 for( i = 0; i < nnz; ++i )
    546 {
    547 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
    548 norm += SQR(QUAD_TO_DBL(coef));
    549 }
    550 norm = sqrt(norm);
    551 break;
    552 case 'm':
    553 for( i = 0; i < nnz; ++i )
    554 {
    555 SCIP_Real absval;
    556 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
    557
    558 absval = REALABS(QUAD_TO_DBL(coef));
    559 norm = MAX(norm, absval);
    560 }
    561 break;
    562 case 's':
    563 for( i = 0; i < nnz; ++i )
    564 {
    565 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
    566 norm += REALABS(QUAD_TO_DBL(coef));
    567 }
    568 break;
    569 case 'd':
    570 for( i = 0; i < nnz; ++i )
    571 {
    572 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
    573 if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
    574 {
    575 norm = 1.0;
    576 break;
    577 }
    578 }
    579 break;
    580 default:
    581 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
    582 assert(FALSE); /*lint !e506*/
    583 }
    584
    585 return norm;
    586}
    587
    588/** calculates the cut efficacy for the given solution; the cut coefs are stored densely */
    589static
    591 SCIP* scip, /**< SCIP data structure */
    592 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
    593 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut; this is a quad precision array! */
    594 SCIP_Real cutrhs, /**< the right hand side of the cut */
    595 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    596 int cutnnz /**< the number of non-zeros in the cut */
    597 )
    598{
    599 SCIP_VAR** vars;
    600 SCIP_Real norm = 0.0;
    601 SCIP_Real activity = 0.0;
    602 SCIP_Real coef;
    603 int i;
    604
    605 assert(scip != NULL);
    606 assert(cutcoefs != NULL);
    607 assert(cutinds != NULL);
    608 assert(scip->set != NULL);
    609
    610 vars = SCIPgetVars(scip);
    611
    612 switch( scip->set->sepa_efficacynorm )
    613 {
    614 case 'e':
    615 for( i = 0; i < cutnnz; ++i )
    616 {
    617 coef = cutcoefs[cutinds[i]];
    618 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    619 norm += SQR(coef);
    620 }
    621 norm = sqrt(norm);
    622 break;
    623 case 'm':
    624 for( i = 0; i < cutnnz; ++i )
    625 {
    626 SCIP_Real absval;
    627
    628 coef = cutcoefs[cutinds[i]];
    629 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    630 absval = REALABS(coef);
    631 norm = MAX(norm, absval);
    632 }
    633 break;
    634 case 's':
    635 for( i = 0; i < cutnnz; ++i )
    636 {
    637 coef = cutcoefs[cutinds[i]];
    638 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    639 norm += REALABS(coef);
    640 }
    641 break;
    642 case 'd':
    643 for( i = 0; i < cutnnz; ++i )
    644 {
    645 coef = cutcoefs[cutinds[i]];
    646 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    647 if( !SCIPisZero(scip, coef) )
    648 norm = 1.0;
    649 }
    650 break;
    651 default:
    652 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
    653 assert(FALSE); /*lint !e506*/
    654 }
    655
    656 return (activity - cutrhs) / MAX(1e-6, norm);
    657}
    658
    659/** calculates the cut efficacy for the given solution; the cut coefs are stored densely and in quad precision */
    660static
    662 SCIP* scip, /**< SCIP data structure */
    663 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
    664 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut; this is a quad precision array! */
    665 SCIP_Real cutrhs, /**< the right hand side of the cut */
    666 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    667 int cutnnz /**< the number of non-zeros in the cut */
    668 )
    669{
    670 SCIP_VAR** vars;
    671 SCIP_Real norm = 0.0;
    672 SCIP_Real activity = 0.0;
    673 SCIP_Real QUAD(coef);
    674 int i;
    675
    676 assert(scip != NULL);
    677 assert(cutcoefs != NULL);
    678 assert(cutinds != NULL);
    679 assert(scip->set != NULL);
    680
    681 vars = SCIPgetVars(scip);
    682
    683 switch( scip->set->sepa_efficacynorm )
    684 {
    685 case 'e':
    686 for( i = 0; i < cutnnz; ++i )
    687 {
    688 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
    689 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    690 norm += SQR(QUAD_TO_DBL(coef));
    691 }
    692 norm = sqrt(norm);
    693 break;
    694 case 'm':
    695 for( i = 0; i < cutnnz; ++i )
    696 {
    697 SCIP_Real absval;
    698
    699 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
    700 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    701 absval = REALABS(QUAD_TO_DBL(coef));
    702 norm = MAX(norm, absval);
    703 }
    704 break;
    705 case 's':
    706 for( i = 0; i < cutnnz; ++i )
    707 {
    708 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
    709 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    710 norm += REALABS(QUAD_TO_DBL(coef));
    711 }
    712 break;
    713 case 'd':
    714 for( i = 0; i < cutnnz; ++i )
    715 {
    716 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
    717 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    718 if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
    719 norm = 1.0;
    720 }
    721 break;
    722 default:
    723 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
    724 assert(FALSE); /*lint !e506*/
    725 }
    726
    727 return (activity - cutrhs) / MAX(1e-6, norm);
    728}
    729
    730/** safely (in the exact solving mode sense) remove all items with |a_i| or |u_i - l_i)| below the given value
    731 *
    732 * Returns TRUE if the cut became redundant.
    733 * If it is a local cut, use local bounds, otherwise, use global bounds.
    734 *
    735 * * @note this method is safe for usage in exact solving mode
    736 */
    737static
    739 SCIP* scip, /**< SCIP data structure */
    740 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
    741 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    742 SCIP_Real* cutrhs, /**< the right hand side of the cut */
    743 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    744 int* cutnnz /**< the number of non-zeros in the cut */
    745 )
    746{
    747 int i;
    748 SCIP_VAR** vars;
    749 SCIP_ROUNDMODE previousroundmode;
    750
    751 assert(SCIPisExact(scip));
    752
    753 previousroundmode = SCIPintervalGetRoundingMode();
    755
    756 vars = SCIPgetVars(scip);
    757
    758 for( i = 0; i < *cutnnz; )
    759 {
    760 SCIP_Real val;
    761 SCIP_Real lb;
    762 SCIP_Real ub;
    763 int v;
    764 SCIP_Bool isfixed;
    765
    766 v = cutinds[i];
    767 val = cutcoefs[v];
    768
    769 if( val == SCIP_INVALID ) /*lint !e777*/
    770 val = 0.0;
    771
    772 /* for now we always use global bounds in exact solving mode (could be improved for local cuts in the future) */
    773 lb = SCIPvarGetLbGlobal(vars[v]);
    774 ub = SCIPvarGetUbGlobal(vars[v]);
    775
    776 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
    777 isfixed = TRUE;
    778 else
    779 isfixed = FALSE;
    780
    781 if( EPSZ(val, minval) || isfixed )
    782 {
    783 /* adjust left and right hand sides with max contribution */
    784 if( val < 0.0 )
    785 {
    786 if( SCIPisInfinity(scip, ub) )
    787 {
    788 SCIPintervalSetRoundingMode(previousroundmode);
    789 return TRUE;
    790 }
    791 else
    792 *cutrhs += (-val) * ub;
    793 }
    794 else
    795 {
    796 if( SCIPisInfinity(scip, -lb) )
    797 {
    798 SCIPintervalSetRoundingMode(previousroundmode);
    799 return TRUE;
    800 }
    801 else
    802 *cutrhs += (-val) * lb;
    803 }
    804
    805 val = 0.0;
    806 cutcoefs[v] = val;
    807
    808 /* remove non-zero entry */
    809 --(*cutnnz);
    810 cutinds[i] = cutinds[*cutnnz];
    811 }
    812 else
    813 ++i;
    814 }
    815
    816 /* relax rhs to 0, if it's very close to 0 */
    817 if( *cutrhs < 0.0 && *cutrhs >= -SCIPepsilon(scip) )
    818 *cutrhs = 0.0;
    819
    820 SCIPintervalSetRoundingMode(previousroundmode);
    821
    822 return FALSE;
    823}
    824
    825/** safely remove all items with |a_i| or |u_i - l_i)| below the given value
    826 *
    827 * Returns TRUE if the cut became redundant.
    828 * If it is a local cut, use local bounds, otherwise, use global bounds.
    829 *
    830 * @note this method is safe for usage in exact solving mode
    831 */
    832static
    834 SCIP* scip, /**< SCIP data structure */
    835 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
    836 SCIP_Bool cutislocal, /**< is the cut local? */
    837 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    838 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
    839 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    840 int* cutnnz /**< the number of non-zeros in the cut */
    841 )
    842{
    843 int i;
    844 SCIP_VAR** vars;
    845
    846 vars = SCIPgetVars(scip);
    847
    848 for( i = 0; i < *cutnnz; )
    849 {
    850 SCIP_Real QUAD(val);
    851 SCIP_Real lb;
    852 SCIP_Real ub;
    853 int v;
    854 SCIP_Bool isfixed;
    855
    856 v = cutinds[i];
    857 QUAD_ARRAY_LOAD(val, cutcoefs, v);
    858
    859 if( cutislocal )
    860 {
    861 lb = SCIPvarGetLbLocal(vars[v]);
    862 ub = SCIPvarGetUbLocal(vars[v]);
    863 }
    864 else
    865 {
    866 lb = SCIPvarGetLbGlobal(vars[v]);
    867 ub = SCIPvarGetUbGlobal(vars[v]);
    868 }
    869
    870 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
    871 isfixed = TRUE;
    872 else
    873 isfixed = FALSE;
    874
    875 if( isfixed || EPSZ(QUAD_TO_DBL(val), minval) )
    876 {
    877 if( REALABS(QUAD_TO_DBL(val)) > QUAD_EPSILON )
    878 {
    879 /* adjust right hand side with max contribution */
    880 if( QUAD_TO_DBL(val) < 0.0 )
    881 {
    882 if( SCIPisInfinity(scip, ub) )
    883 return TRUE;
    884 else
    885 {
    886 SCIPquadprecProdQD(val, val, ub);
    887 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
    888 }
    889 }
    890 else
    891 {
    892 if( SCIPisInfinity(scip, -lb) )
    893 return TRUE;
    894 else
    895 {
    896 SCIPquadprecProdQD(val, val, lb);
    897 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
    898 }
    899 }
    900 }
    901
    902 QUAD_ASSIGN(val, 0.0);
    903 QUAD_ARRAY_STORE(cutcoefs, v, val);
    904
    905 /* remove non-zero entry */
    906 --(*cutnnz);
    907 cutinds[i] = cutinds[*cutnnz];
    908 }
    909 else
    910 ++i;
    911 }
    912
    913 /* relax rhs to 0, if it's very close to 0 */
    914 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    915 QUAD_ASSIGN(*cutrhs, 0.0);
    916
    917 return FALSE;
    918}
    919
    920/** safely remove all items with |a_i| or |u_i - l_i| below the given value
    921 *
    922 * Returns TRUE if the cut became redundant.
    923 * If it is a local cut, use local bounds, otherwise, use global bounds.
    924 */
    925static
    927 SCIP* scip, /**< SCIP data structure */
    928 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
    929 SCIP_Bool cutislocal, /**< is the cut local? */
    930 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    931 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
    932 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    933 int* cutnnz /**< the number of non-zeros in the cut */
    934 )
    935{
    936 int i;
    937 SCIP_VAR** vars;
    938
    939 vars = SCIPgetVars(scip);
    940
    941 /* loop over non-zeros and remove values below minval; values above QUAD_EPSILON are cancelled with their bound
    942 * to avoid numerical rounding errors
    943 */
    944 for( i = 0; i < *cutnnz; )
    945 {
    946 SCIP_Real val;
    947 SCIP_Real lb;
    948 SCIP_Real ub;
    949 int v;
    950 SCIP_Bool isfixed;
    951 SCIP_Real QUAD(quadprod);
    952
    953 v = cutinds[i];
    954 val = cutcoefs[v];
    955
    956 if( cutislocal )
    957 {
    958 lb = SCIPvarGetLbLocal(vars[v]);
    959 ub = SCIPvarGetUbLocal(vars[v]);
    960 }
    961 else
    962 {
    963 lb = SCIPvarGetLbGlobal(vars[v]);
    964 ub = SCIPvarGetUbGlobal(vars[v]);
    965 }
    966
    967 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
    968 isfixed = TRUE;
    969 else
    970 isfixed = FALSE;
    971
    972 if( EPSZ(val, minval) || isfixed )
    973 {
    974 if( REALABS(val) > QUAD_EPSILON )
    975 {
    976 /* adjust left and right hand sides with max contribution */
    977 if( val < 0.0 )
    978 {
    979 if( SCIPisInfinity(scip, ub) )
    980 return TRUE;
    981 else
    982 {
    983 SCIPquadprecProdDD(quadprod, -val, ub);
    984 SCIPquadprecSumQQ(*cutrhs, *cutrhs, quadprod);
    985 }
    986 }
    987 else
    988 {
    989 if( SCIPisInfinity(scip, -lb) )
    990 return TRUE;
    991 else
    992 {
    993 SCIPquadprecProdDD(quadprod, -val, lb);
    994 SCIPquadprecSumQQ(*cutrhs, *cutrhs, quadprod);
    995 }
    996 }
    997 }
    998
    999 cutcoefs[v] = 0.0;
    1000
    1001 /* remove non-zero entry */
    1002 --(*cutnnz);
    1003 cutinds[i] = cutinds[*cutnnz];
    1004 }
    1005 else
    1006 ++i;
    1007 }
    1008
    1009 /* relax rhs to 0, if it's very close to 0 */
    1010 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    1011 QUAD_ASSIGN(*cutrhs, 0.0);
    1012
    1013 return FALSE;
    1014}
    1015
    1016/** compare absolute values of coefficients in quad precision */
    1017static
    1018SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
    1019{
    1020 SCIP_Real abscoef1;
    1021 SCIP_Real abscoef2;
    1022 SCIP_Real QUAD(coef1);
    1023 SCIP_Real QUAD(coef2);
    1024 SCIP_Real* coefs = (SCIP_Real*) dataptr;
    1025
    1026 QUAD_ARRAY_LOAD(coef1, coefs, ind1);
    1027 QUAD_ARRAY_LOAD(coef2, coefs, ind2);
    1028
    1029 abscoef1 = REALABS(QUAD_TO_DBL(coef1));
    1030 abscoef2 = REALABS(QUAD_TO_DBL(coef2));
    1031
    1032 if( abscoef1 < abscoef2 )
    1033 return -1;
    1034 if( abscoef2 < abscoef1 )
    1035 return 1;
    1036
    1037 return 0;
    1038}
    1039
    1040/** compare absolute values of coefficients */
    1041static
    1043{
    1044 SCIP_Real abscoef1;
    1045 SCIP_Real abscoef2;
    1046 SCIP_Real* coefs = (SCIP_Real*) dataptr;
    1047
    1048 abscoef1 = REALABS(coefs[ind1]);
    1049 abscoef2 = REALABS(coefs[ind2]);
    1050
    1051 if( abscoef1 < abscoef2 )
    1052 return -1;
    1053 if( abscoef2 < abscoef1 )
    1054 return 1;
    1055
    1056 return 0;
    1057}
    1058
    1059/** change given coefficient to new given value, adjust right hand side using the variables bound;
    1060 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
    1061 */
    1062static
    1064 SCIP* scip, /**< SCIP data structure */
    1065 SCIP_VAR* var, /**< variable the coefficient belongs to */
    1066 SCIP_Real oldcoeff, /**< old coefficient value */
    1067 SCIP_Real newcoeff, /**< new coefficient value */
    1068 SCIP_Bool cutislocal, /**< is the cut local? */
    1069 QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
    1070 )
    1071{
    1072 SCIP_Real QUAD(delta);
    1073
    1074 SCIPquadprecSumDD(delta, newcoeff, -oldcoeff);
    1075
    1076 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
    1077 {
    1078 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
    1079
    1080 if( SCIPisInfinity(scip, ub) )
    1081 return TRUE;
    1082 else
    1083 {
    1084 SCIPquadprecProdQD(delta, delta, ub);
    1085 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
    1086 }
    1087 }
    1088 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
    1089 {
    1090 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
    1091
    1092 if( SCIPisInfinity(scip, -lb) )
    1093 return TRUE;
    1094 else
    1095 {
    1096 SCIPquadprecProdQD(delta, delta, lb);
    1097 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
    1098 }
    1099 }
    1100
    1101 return FALSE;
    1102}
    1103
    1104/** change given (quad) coefficient to new given value, adjust right hand side using the variables bound;
    1105 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
    1106 */
    1107static
    1109 SCIP* scip, /**< SCIP data structure */
    1110 SCIP_VAR* var, /**< variable the coefficient belongs to */
    1111 QUAD(SCIP_Real oldcoeff), /**< old coefficient value */
    1112 SCIP_Real newcoeff, /**< new coefficient value */
    1113 SCIP_Bool cutislocal, /**< is the cut local? */
    1114 QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
    1115 )
    1116{
    1117 SCIP_Real QUAD(delta);
    1118
    1119 SCIPquadprecSumQD(delta, -oldcoeff, newcoeff);
    1120
    1121 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
    1122 {
    1123 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
    1124
    1125 if( SCIPisInfinity(scip, ub) )
    1126 return TRUE;
    1127 else
    1128 {
    1129 SCIPquadprecProdQD(delta, delta, ub);
    1130 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
    1131 }
    1132 }
    1133 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
    1134 {
    1135 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
    1136
    1137 if( SCIPisInfinity(scip, -lb) )
    1138 return TRUE;
    1139 else
    1140 {
    1141 SCIPquadprecProdQD(delta, delta, lb);
    1142 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
    1143 }
    1144 }
    1145
    1146 return FALSE;
    1147}
    1148
    1149/** change given coefficient to new given value, adjust right hand side using the variables bound;
    1150 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
    1151 */
    1152static
    1154 SCIP* scip, /**< SCIP data structure */
    1155 SCIP_VAR* var, /**< variable the coefficient belongs to */
    1156 SCIP_Real oldcoeff, /**< old coefficient value */
    1157 SCIP_Real newcoeff, /**< new coefficient value */
    1158 SCIP_Bool cutislocal, /**< is the cut local? */
    1159 SCIP_Real* cutrhs /**< pointer to adjust right hand side of cut */
    1160 )
    1161{
    1162 SCIP_INTERVAL delta;
    1163 SCIP_ROUNDMODE previousroundmode;
    1164
    1165 assert(SCIPisExact(scip));
    1166
    1167 previousroundmode = SCIPintervalGetRoundingMode();
    1169
    1170 SCIPintervalSet(&delta, newcoeff);
    1171 SCIPintervalSubScalar(SCIPinfinity(scip), &delta, delta, oldcoeff);
    1172
    1173 if( SCIPintervalGetSup(delta) > 0 )
    1174 {
    1175 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
    1176
    1177 if( SCIPisInfinity(scip, ub) )
    1178 {
    1179 SCIPintervalSetRoundingMode(previousroundmode);
    1180 return TRUE;
    1181 }
    1182 else
    1183 {
    1184 SCIPintervalMulScalar(SCIPinfinity(scip), &delta, delta, ub);
    1185 *cutrhs += SCIPintervalGetSup(delta);
    1186 }
    1187 }
    1188 else if( SCIPintervalGetInf(delta) < 0 )
    1189 {
    1190 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
    1191
    1192 if( SCIPisInfinity(scip, -lb) )
    1193 {
    1194 SCIPintervalSetRoundingMode(previousroundmode);
    1195 return TRUE;
    1196 }
    1197 else
    1198 {
    1199 SCIPintervalMulScalar(SCIPinfinity(scip), &delta, delta, lb);
    1200 *cutrhs += SCIPintervalGetSup(delta);
    1201 }
    1202 }
    1203 else
    1204 {
    1205 return TRUE;
    1206 }
    1207
    1208 return FALSE;
    1209}
    1210
    1211
    1212/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
    1213 * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse quad precision array;
    1214 *
    1215 * This is the quad precision version of cutTightenCoefs() below.
    1216 */
    1217static
    1219 SCIP* scip, /**< SCIP data structure */
    1220 SCIP_Bool cutislocal, /**< is the cut local? */
    1221 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    1222 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
    1223 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    1224 int* cutnnz, /**< the number of non-zeros in the cut */
    1225 SCIP_Bool* redundant /**< whether the cut was detected to be redundant */
    1226 )
    1227{
    1228 int i;
    1229 int nintegralvars;
    1230 SCIP_Bool isintegral = TRUE;
    1231 SCIP_VAR** vars;
    1232 SCIP_Real QUAD(maxacttmp);
    1233 SCIP_Real maxact;
    1234 SCIP_Real maxabsintval = 0.0;
    1235 SCIP_Real maxabscontval = 0.0;
    1236
    1237 QUAD_ASSIGN(maxacttmp, 0.0);
    1238
    1239 vars = SCIPgetVars(scip);
    1240 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    1241
    1242 assert(redundant != NULL);
    1243 *redundant = FALSE;
    1244
    1245 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
    1246 for( i = 0; i < *cutnnz; ++i )
    1247 {
    1248 SCIP_Real QUAD(val);
    1249
    1250 assert(cutinds[i] >= 0);
    1251 assert(vars[cutinds[i]] != NULL);
    1252
    1253 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1254
    1255 if( QUAD_TO_DBL(val) < 0.0 )
    1256 {
    1257 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    1258
    1259 if( SCIPisInfinity(scip, -lb) )
    1260 return SCIP_OKAY;
    1261
    1262 if( cutinds[i] < nintegralvars )
    1263 maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
    1264 else
    1265 {
    1266 maxabscontval = MAX(maxabscontval, -QUAD_TO_DBL(val));
    1267 isintegral = FALSE;
    1268 }
    1269
    1270 SCIPquadprecProdQD(val, val, lb);
    1271 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
    1272 }
    1273 else
    1274 {
    1275 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    1276
    1277 if( SCIPisInfinity(scip, ub) )
    1278 return SCIP_OKAY;
    1279
    1280 if( cutinds[i] < nintegralvars )
    1281 maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
    1282 else
    1283 {
    1284 maxabscontval = MAX(maxabscontval, QUAD_TO_DBL(val));
    1285 isintegral = FALSE;
    1286 }
    1287
    1288 SCIPquadprecProdQD(val, val, ub);
    1289 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
    1290 }
    1291 }
    1292
    1293 maxact = QUAD_TO_DBL(maxacttmp);
    1294
    1295 /* cut is redundant in activity bounds */
    1296 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
    1297 {
    1298 *redundant = TRUE;
    1299 return SCIP_OKAY;
    1300 }
    1301
    1302 /* cut is only on integral variables, try to scale to integral coefficients */
    1303 if( isintegral )
    1304 {
    1305 SCIP_Real equiscale;
    1306 SCIP_Real intscalar;
    1307 SCIP_Bool success;
    1308 SCIP_Real* intcoeffs;
    1309
    1310 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
    1311
    1312 equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
    1313
    1314 for( i = 0; i < *cutnnz; ++i )
    1315 {
    1316 SCIP_Real QUAD(val);
    1317
    1318 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1319 SCIPquadprecProdQD(val, val, equiscale);
    1320
    1321 intcoeffs[i] = QUAD_TO_DBL(val);
    1322 }
    1323
    1325 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
    1326
    1327 SCIPfreeBufferArray(scip, &intcoeffs);
    1328
    1329 if( success )
    1330 {
    1331 /* if successful, apply the scaling */
    1332 intscalar *= equiscale;
    1333 SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
    1334
    1335 for( i = 0; i < *cutnnz; )
    1336 {
    1337 SCIP_Real QUAD(val);
    1338 SCIP_Real intval;
    1339
    1340 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1341 SCIPquadprecProdQD(val, val, intscalar);
    1342
    1343 intval = SCIPround(scip, QUAD_TO_DBL(val));
    1344
    1345 if( chgQuadCoeffWithBound(scip, vars[cutinds[i]], QUAD(val), intval, cutislocal, QUAD(cutrhs)) )
    1346 {
    1347 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
    1348 *redundant = TRUE;
    1349 return SCIP_OKAY;
    1350 }
    1351
    1352 if( intval != 0.0 )
    1353 {
    1354 QUAD_ASSIGN(val, intval);
    1355 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
    1356 ++i;
    1357 }
    1358 else
    1359 {
    1360 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
    1361 QUAD_ASSIGN(val, 0.0);
    1362 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
    1363 --(*cutnnz);
    1364 cutinds[i] = cutinds[*cutnnz];
    1365 }
    1366 }
    1367
    1368 SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
    1369
    1370 /* recompute the maximal activity after scaling to integral values */
    1371 QUAD_ASSIGN(maxacttmp, 0.0);
    1372 maxabsintval = 0.0;
    1373
    1374 for( i = 0; i < *cutnnz; ++i )
    1375 {
    1376 SCIP_Real QUAD(val);
    1377
    1378 assert(cutinds[i] >= 0);
    1379 assert(vars[cutinds[i]] != NULL);
    1380
    1381 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1382
    1383 if( QUAD_TO_DBL(val) < 0.0 )
    1384 {
    1385 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    1386
    1387 maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
    1388
    1389 SCIPquadprecProdQD(val, val, lb);
    1390
    1391 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
    1392 }
    1393 else
    1394 {
    1395 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    1396
    1397 maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
    1398
    1399 SCIPquadprecProdQD(val, val, ub);
    1400
    1401 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
    1402 }
    1403 }
    1404
    1405 assert(EPSISINT(QUAD_TO_DBL(maxacttmp), 1e-4));
    1406 SCIPquadprecSumQD(maxacttmp, maxacttmp, 0.5);
    1407 SCIPquadprecFloorQ(maxacttmp, maxacttmp);
    1408 }
    1409 else
    1410 {
    1411 /* otherwise, apply the equilibrium scaling */
    1412 isintegral = FALSE;
    1413
    1414 /* perform the scaling */
    1415 SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
    1416 SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
    1417 maxabsintval *= equiscale;
    1418
    1419 for( i = 0; i < *cutnnz; ++i )
    1420 {
    1421 SCIP_Real QUAD(val);
    1422
    1423 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1424 SCIPquadprecProdQD(val, val, equiscale);
    1425 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
    1426 }
    1427 }
    1428 }
    1429 else
    1430 {
    1431 /* cut has integer and continuous variables, so scale it to equilibrium */
    1432 SCIP_Real scale;
    1433 SCIP_Real maxabsval;
    1434
    1435 maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
    1436 maxabsval = MIN(maxabsval, maxabsintval);
    1437 maxabsval = MAX(maxabsval, maxabscontval);
    1438
    1439 scale = 1.0 / maxabsval; /*lint !e795*/
    1440
    1441 /* perform the scaling */
    1442 SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
    1443 SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
    1444 maxabsintval *= scale;
    1445
    1446 for( i = 0; i < *cutnnz; ++i )
    1447 {
    1448 SCIP_Real QUAD(val);
    1449
    1450 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1451 SCIPquadprecProdQD(val, val, scale);
    1452 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
    1453 }
    1454 }
    1455
    1456 maxact = QUAD_TO_DBL(maxacttmp);
    1457
    1458 /* check again for redundancy after scaling */
    1459 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
    1460 {
    1461 *redundant = TRUE;
    1462 return SCIP_OKAY;
    1463 }
    1464
    1465 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
    1466 if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
    1467 return SCIP_OKAY;
    1468
    1469 /* first sort indices, so that in the following sort, the order for coefficients with same absolute value does not depend on how cutinds was initially ordered */
    1470 SCIPsortInt(cutinds, *cutnnz);
    1471 SCIPsortDownInd(cutinds, compareAbsCoefsQuad, (void*) cutcoefs, *cutnnz);
    1472
    1473 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
    1474 for( i = 0; i < *cutnnz; )
    1475 {
    1476 SCIP_Real QUAD(val);
    1477
    1478 if( cutinds[i] >= nintegralvars )
    1479 {
    1480 ++i;
    1481 continue;
    1482 }
    1483
    1484 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1485
    1486 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
    1487
    1488 if( QUAD_TO_DBL(val) < 0.0 && SCIPisLE(scip, maxact + QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
    1489 {
    1490 SCIP_Real QUAD(coef);
    1491 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    1492
    1493 SCIPquadprecSumQQ(coef, *cutrhs, -maxacttmp);
    1494
    1495 if( isintegral )
    1496 {
    1497 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    1498 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    1499 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    1500 }
    1501
    1502 if( QUAD_TO_DBL(coef) > QUAD_TO_DBL(val) )
    1503 {
    1504 SCIP_Real QUAD(delta);
    1505 SCIP_Real QUAD(tmp);
    1506
    1507 SCIPquadprecSumQQ(delta, -val, coef);
    1508 SCIPquadprecProdQD(delta, delta, lb);
    1509
    1510 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    1511 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    1512 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
    1513 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
    1514
    1515 QUAD_ASSIGN_Q(*cutrhs, tmp);
    1516
    1517 assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
    1518
    1519 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
    1520 {
    1521 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    1522 maxact = QUAD_TO_DBL(maxacttmp);
    1523 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    1524 }
    1525 else
    1526 {
    1527 QUAD_ASSIGN(coef, 0.0);
    1528 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    1529 --(*cutnnz);
    1530 cutinds[i] = cutinds[*cutnnz];
    1531 continue;
    1532 }
    1533 }
    1534 }
    1535 else if( QUAD_TO_DBL(val) > 0.0 && SCIPisLE(scip, maxact - QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
    1536 {
    1537 SCIP_Real QUAD(coef);
    1538 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    1539
    1540 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
    1541
    1542 if( isintegral )
    1543 {
    1544 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    1545 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    1546 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    1547 }
    1548
    1549 if( QUAD_TO_DBL(coef) < QUAD_TO_DBL(val) )
    1550 {
    1551 SCIP_Real QUAD(delta);
    1552 SCIP_Real QUAD(tmp);
    1553
    1554 SCIPquadprecSumQQ(delta, -val, coef);
    1555 SCIPquadprecProdQD(delta, delta, ub);
    1556
    1557 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    1558 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    1559 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
    1560 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
    1561
    1562 QUAD_ASSIGN_Q(*cutrhs, tmp);
    1563
    1564 assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
    1565
    1566 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
    1567 {
    1568 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    1569 maxact = QUAD_TO_DBL(maxacttmp);
    1570 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    1571 }
    1572 else
    1573 {
    1574 QUAD_ASSIGN(coef, 0.0);
    1575 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    1576 --(*cutnnz);
    1577 cutinds[i] = cutinds[*cutnnz];
    1578 continue;
    1579 }
    1580 }
    1581 }
    1582 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
    1583 break;
    1584
    1585 ++i;
    1586 }
    1587
    1588 return SCIP_OKAY;
    1589}
    1590
    1591/** multiplies a parameter for a variable in a row safely (using variable bounds and increasing the rhs)
    1592 *
    1593 * @return the scaled value
    1594 */
    1595static
    1597 SCIP* scip, /**< SCIP structure */
    1598 SCIP_Real val, /**< the value that should be scaled */
    1599 SCIP_Real scale, /**< scaling factor */
    1600 SCIP_Bool cutislocal, /**< should local or global bounds be used */
    1601 SCIP_VAR* var, /**< the variable that is relevant */
    1602 SCIP_Real* rhschange, /**< resulting change in rhs of row */
    1603 SCIP_Bool* success /**< was the operation successful? (false if no bounds) */
    1604 )
    1605{
    1606 SCIP_ROUNDMODE previousroundmode;
    1607 SCIP_INTERVAL valinterval;
    1608 SCIP_Real ub;
    1609 SCIP_Real lb;
    1610 SCIP_Real newval = 0.0;
    1611
    1612 assert(SCIPisExact(scip));
    1613
    1614 previousroundmode = SCIPintervalGetRoundingMode();
    1616
    1617 *rhschange = 0;
    1618
    1619 SCIPintervalSet(&valinterval, val);
    1620 SCIPintervalMulScalar(SCIPinfinity(scip), &valinterval, valinterval, scale);
    1621
    1622 lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
    1623 ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
    1624
    1625 *success = TRUE;
    1626
    1627 if( lb > -SCIPinfinity(scip) && lb >= 0 )
    1628 {
    1629 SCIPdebugMessage("Lb positive, no change in rhs needed \n");
    1630 newval = SCIPintervalGetInf(valinterval);
    1631 }
    1632 else if(ub < SCIPinfinity(scip) && ub <= 0 )
    1633 {
    1634 SCIPdebugMessage("Ub negative, no change in rhs needed \n");
    1635 newval = SCIPintervalGetSup(valinterval);
    1636 }
    1637 else if( lb > -SCIPinfinity(scip) )
    1638 {
    1639 newval = SCIPintervalGetInf(valinterval);
    1641 *rhschange = (SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval)) * (-lb);
    1642 SCIPdebugMessage("Using lb %.17g corrected by %.17g. Change to rhs: %.17g \n", SCIPvarGetLbGlobal(var), -SCIPintervalGetSup(valinterval) + SCIPintervalGetInf(valinterval), *rhschange);
    1643 }
    1644 else if( ub < SCIPinfinity(scip) )
    1645 {
    1646 newval = SCIPintervalGetSup(valinterval);
    1648 *rhschange = (SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval)) * (ub);
    1649 SCIPdebugMessage("Using ub %.17g corrected by %.17g. Change to rhs: %.17g \n", SCIPvarGetUbGlobal(var), SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval), *rhschange);
    1650 }
    1651 else
    1652 {
    1653 *success = FALSE;
    1654 SCIPintervalSetRoundingMode(previousroundmode);
    1655 return newval;
    1656 }
    1657
    1658 SCIPintervalSetRoundingMode(previousroundmode);
    1659
    1660 return newval;
    1661}
    1662
    1663/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
    1664 * see cons_linear.c consdataTightenCoefs() for details;
    1665 *
    1666 * This is the safe version of cutTightenCoefs() below.
    1667 */
    1668static
    1670 SCIP* scip, /**< SCIP data structure */
    1671 SCIP_Bool cutislocal, /**< is the cut local? */
    1672 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    1673 SCIP_Real* cutrhs, /**< the right hand side of the cut */
    1674 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    1675 int* cutnnz, /**< the number of non-zeros in the cut */
    1676 SCIP_Bool* redundant /**< whether the cut was detected to be redundant */
    1677 )
    1678{ /*lint --e{644}*/
    1679 int i;
    1680 int nintegralvars;
    1681 SCIP_Bool isintegral = TRUE;
    1682 SCIP_VAR** vars;
    1683 SCIP_INTERVAL maxact;
    1684 SCIP_INTERVAL tmp;
    1685 SCIP_Real maxabsintval = 0.0;
    1686 SCIP_Real maxabscontval = 0.0;
    1687 SCIP_ROUNDMODE previousroundmode;
    1688 SCIP_MIRINFO* mirinfo = NULL;
    1689
    1690 assert(SCIPisExact(scip));
    1691
    1692 if( SCIPisCertified(scip) )
    1693 {
    1695 assert(mirinfo != NULL);
    1696 }
    1697
    1698 SCIPintervalSet(&maxact, 0.0);
    1699
    1700 vars = SCIPgetVars(scip);
    1701 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    1702
    1703 assert(redundant != NULL);
    1704 *redundant = FALSE;
    1705
    1706 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
    1707 for( i = 0; i < *cutnnz; ++i )
    1708 {
    1709 SCIP_Real val;
    1710
    1711 assert(cutinds[i] >= 0);
    1712 assert(vars[cutinds[i]] != NULL);
    1713
    1714 val = cutcoefs[cutinds[i]];
    1715
    1716 if( val < 0.0 )
    1717 {
    1718 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    1719
    1720 if( SCIPisInfinity(scip, -lb) )
    1721 return SCIP_OKAY;
    1722
    1723 if( cutinds[i] < nintegralvars )
    1724 maxabsintval = MAX(maxabsintval, -val);
    1725 else
    1726 {
    1727 maxabscontval = MAX(maxabscontval, -val);
    1728 isintegral = FALSE;
    1729 }
    1730
    1731 SCIPintervalSet(&tmp, val);
    1732 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, lb);
    1733 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
    1734 }
    1735 else
    1736 {
    1737 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    1738
    1739 if( SCIPisInfinity(scip, ub) )
    1740 return SCIP_OKAY;
    1741
    1742 if( cutinds[i] < nintegralvars )
    1743 maxabsintval = MAX(maxabsintval, val);
    1744 else
    1745 {
    1746 maxabscontval = MAX(maxabscontval, val);
    1747 isintegral = FALSE;
    1748 }
    1749
    1750 SCIPintervalSet(&tmp, val);
    1751 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, ub);
    1752 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
    1753 }
    1754 }
    1755
    1756 /* cut is redundant in activity bounds */
    1757 if( SCIPintervalGetSup(maxact) <= *cutrhs )
    1758 {
    1759 *redundant = TRUE;
    1760 return SCIP_OKAY;
    1761 }
    1762
    1763 previousroundmode = SCIPintervalGetRoundingMode();
    1764
    1765 /* cut is only on integral variables, try to scale to integral coefficients */
    1766 if( isintegral )
    1767 {
    1768 SCIP_Real equiscale;
    1769 SCIP_Real intscalar;
    1770 SCIP_Bool success;
    1771 SCIP_Real* intcoeffs;
    1772 SCIP_Real rhschange;
    1773
    1774 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
    1775
    1776 equiscale = 1.0 / MAX(maxabscontval, maxabsintval);
    1777
    1778 for( i = 0; i < *cutnnz; ++i )
    1779 {
    1780 SCIP_Real val;
    1781
    1782 val = cutcoefs[cutinds[i]];
    1783 val *= equiscale;
    1784
    1785 intcoeffs[i] = val;
    1786 }
    1787
    1789 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
    1790
    1791 SCIPfreeBufferArray(scip, &intcoeffs);
    1792
    1793 if( success )
    1794 {
    1795 /* if successful, apply the scaling */
    1797 intscalar *= equiscale;
    1798
    1799 *cutrhs *= intscalar;
    1800
    1801 if( SCIPisCertified(scip) )
    1802 {
    1803 assert(mirinfo != NULL);
    1804 mirinfo->scale = intscalar;
    1805 }
    1806
    1807 for( i = 0; i < *cutnnz; )
    1808 {
    1809 SCIP_Real val;
    1810 SCIP_Real intval;
    1811
    1812 val = cutcoefs[cutinds[i]];
    1813 val = scaleValSafely(scip, val, intscalar, cutislocal, vars[cutinds[i]], &rhschange, &success);
    1814
    1815 *cutrhs += rhschange;
    1816
    1817 if( !success )
    1818 {
    1819 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
    1820 *redundant = TRUE;
    1821 SCIPintervalSetRoundingMode(previousroundmode);
    1822 return SCIP_OKAY;
    1823 }
    1824 intval = SCIPround(scip, val);
    1825
    1826 if( chgCoeffWithBoundSafely(scip, vars[cutinds[i]], val, intval, cutislocal, cutrhs) )
    1827 {
    1828 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
    1829 SCIPintervalSetRoundingMode(previousroundmode);
    1830 *redundant = TRUE;
    1831 return SCIP_OKAY;
    1832 }
    1833
    1834 if( intval != 0.0 )
    1835 {
    1836 val = intval;
    1837 cutcoefs[cutinds[i]] = val;
    1838 ++i;
    1839 }
    1840 else
    1841 {
    1842 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
    1843 val = 0.0;
    1844 cutcoefs[cutinds[i]] = val;
    1845 --(*cutnnz);
    1846 cutinds[i] = cutinds[*cutnnz];
    1847 }
    1848 }
    1849
    1850 if( SCIPisCertified(scip) )
    1851 {
    1852 assert(mirinfo != NULL);
    1853 mirinfo->unroundedrhs = *cutrhs;
    1854 }
    1855 *cutrhs = floor(*cutrhs); /*lint !e835*/
    1856
    1857 /* recompute the maximal activity after scaling to integral values */
    1858 SCIPintervalSet(&maxact, 0.0);
    1859 maxabsintval = 0.0;
    1860
    1861 for( i = 0; i < *cutnnz; ++i )
    1862 {
    1863 SCIP_Real val;
    1864
    1865 assert(cutinds[i] >= 0);
    1866 assert(vars[cutinds[i]] != NULL);
    1867
    1868 val = cutcoefs[cutinds[i]];
    1869
    1870 if( val < 0.0 )
    1871 {
    1872 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    1873
    1874 maxabsintval = MAX(maxabsintval, -val);
    1875
    1876 SCIPintervalSet(&tmp, val);
    1877 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, lb);
    1878 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
    1879 }
    1880 else
    1881 {
    1882 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    1883
    1884 maxabsintval = MAX(maxabsintval, val);
    1885
    1886 SCIPintervalSet(&tmp, val);
    1887 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, ub);
    1888 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
    1889 }
    1890 }
    1891
    1892 assert(EPSISINT(SCIPintervalGetSup(maxact), 1e-4));/*lint !e666*/
    1893 /* check again for redundancy */
    1894 if( SCIPisFeasLE(scip, SCIPintervalGetSup(maxact), *cutrhs) )
    1895 {
    1896 *redundant = TRUE;
    1897 SCIPintervalSetRoundingMode(previousroundmode);
    1898 return SCIP_OKAY;
    1899 }
    1900 }
    1901 else
    1902 {
    1903 /* otherwise, apply the equilibrium scaling */
    1904
    1905 /* perform the scaling */
    1906 SCIPintervalMulScalar(SCIPinfinity(scip), &maxact, maxact, equiscale);
    1908
    1909 *cutrhs *= equiscale;
    1910 maxabsintval *= equiscale;
    1911 if( SCIPisCertified(scip) )
    1912 {
    1913 assert(mirinfo != NULL);
    1914 mirinfo->scale = equiscale;
    1915 }
    1916
    1917 for( i = 0; i < *cutnnz; ++i )
    1918 {
    1919 SCIP_Real val;
    1920
    1921 val = cutcoefs[cutinds[i]];
    1922 val = scaleValSafely(scip, val, equiscale, cutislocal, vars[cutinds[i]], &rhschange, &success);
    1923
    1924 if( !success )
    1925 {
    1926 *redundant = TRUE;
    1927 SCIPintervalSetRoundingMode(previousroundmode);
    1928 return SCIP_OKAY;
    1929 }
    1930 cutcoefs[cutinds[i]] = val;
    1931 *cutrhs += rhschange;
    1932 }
    1933 }
    1934 }
    1935 else
    1936 {
    1937 /* cut has integer and continuous variables, so scale it to equilibrium */
    1938 SCIP_Real scale;
    1939 SCIP_Real maxabsval;
    1940 SCIP_Bool success;
    1941 SCIP_Real rhschange;
    1942
    1943 maxabsval = SCIPintervalGetSup(maxact) - *cutrhs;
    1944 maxabsval = MIN(maxabsval, maxabsintval);
    1945 maxabsval = MAX(maxabsval, maxabscontval);
    1946
    1947 scale = 1.0 / maxabsval; /*lint !e795*/
    1948
    1949 /* perform the scaling */
    1950 SCIPintervalSet(&maxact, scale);
    1952 *cutrhs *= scale;
    1953 maxabsintval *= scale;
    1954 if( SCIPisCertified(scip) )
    1955 {
    1956 assert(mirinfo != NULL);
    1957 mirinfo->scale = scale;
    1958 }
    1959
    1960 for( i = 0; i < *cutnnz; ++i )
    1961 {
    1962 SCIP_Real val;
    1963
    1964 val = cutcoefs[cutinds[i]];
    1965 val = scaleValSafely(scip, val, scale, cutislocal, vars[cutinds[i]], &rhschange, &success);
    1966
    1967 *cutrhs += rhschange;
    1968
    1969 if( !success )
    1970 {
    1971 *redundant = TRUE;
    1972 SCIPintervalSetRoundingMode(previousroundmode);
    1973 return SCIP_OKAY;
    1974 }
    1975 cutcoefs[cutinds[i]] = val;
    1976 }
    1977 }
    1978
    1979 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
    1980 if( SCIPisGT(scip, SCIPintervalGetSup(maxact) - maxabsintval, *cutrhs) )
    1981 {
    1982 SCIPintervalSetRoundingMode(previousroundmode);
    1983 return SCIP_OKAY;
    1984 }
    1985
    1986 SCIPsortDownInd(cutinds, compareAbsCoefs, (void*) cutcoefs, *cutnnz);
    1987
    1988#ifdef SCIP_DISABLED_CODE
    1989 /** @todo implement and certify coefficient tightening for cuts in exact solving mode */
    1990 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
    1991 for( i = 0; i < *cutnnz && FALSE; )
    1992 {
    1993 SCIP_Real QUAD(val);
    1994
    1995 if( cutinds[i] >= nintegralvars )
    1996 {
    1997 ++i;
    1998 continue;
    1999 }
    2000
    2001 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    2002
    2003 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
    2004
    2005 if( QUAD_TO_DBL(val) < 0.0 && SCIPisLE(scip, maxact + QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
    2006 {
    2007 SCIP_Real QUAD(coef);
    2008 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    2009
    2010 SCIPquadprecSumQQ(coef, *cutrhs, -maxacttmp);
    2011
    2012 if( isintegral )
    2013 {
    2014 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    2015 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    2016 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    2017 }
    2018
    2019 if( QUAD_TO_DBL(coef) > QUAD_TO_DBL(val) )
    2020 {
    2021 SCIP_Real QUAD(delta);
    2022 SCIP_Real QUAD(tmp);
    2023
    2024 SCIPquadprecSumQQ(delta, -val, coef);
    2025 SCIPquadprecProdQD(delta, delta, lb);
    2026
    2027 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    2028 SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2029 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
    2030 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
    2031
    2032 QUAD_ASSIGN_Q(*cutrhs, tmp);
    2033
    2034 assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
    2035
    2036 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
    2037 {
    2038 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2039 maxact = QUAD_TO_DBL(maxacttmp);
    2040 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    2041 }
    2042 else
    2043 {
    2044 QUAD_ASSIGN(coef, 0.0);
    2045 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    2046 --(*cutnnz);
    2047 cutinds[i] = cutinds[*cutnnz];
    2048 continue;
    2049 }
    2050 }
    2051 }
    2052 else if( QUAD_TO_DBL(val) > 0.0 && SCIPisLE(scip, maxact - QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
    2053 {
    2054 SCIP_Real QUAD(coef);
    2055 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2056
    2057 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
    2058
    2059 if( isintegral )
    2060 {
    2061 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    2062 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    2063 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    2064 }
    2065
    2066 if( QUAD_TO_DBL(coef) < QUAD_TO_DBL(val) )
    2067 {
    2068 SCIP_Real QUAD(delta);
    2069 SCIP_Real QUAD(tmp);
    2070
    2071 SCIPquadprecSumQQ(delta, -val, coef);
    2072 SCIPquadprecProdQD(delta, delta, ub);
    2073
    2074 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    2075 SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2076 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
    2077 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
    2078
    2079 QUAD_ASSIGN_Q(*cutrhs, tmp);
    2080
    2081 assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
    2082
    2083 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
    2084 {
    2085 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2086 maxact = QUAD_TO_DBL(maxacttmp);
    2087 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    2088 }
    2089 else
    2090 {
    2091 QUAD_ASSIGN(coef, 0.0);
    2092 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    2093 --(*cutnnz);
    2094 cutinds[i] = cutinds[*cutnnz];
    2095 continue;
    2096 }
    2097 }
    2098 }
    2099 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
    2100 break;
    2101
    2102 ++i;
    2103 }
    2104#endif /*lint --e{438}*/
    2105
    2106 return SCIP_OKAY;
    2107}
    2108
    2109
    2110/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
    2111 * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse array;
    2112 */
    2113static
    2115 SCIP* scip, /**< SCIP data structure */
    2116 SCIP_Bool cutislocal, /**< is the cut local? */
    2117 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    2118 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
    2119 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    2120 int* cutnnz, /**< the number of non-zeros in the cut */
    2121 SCIP_Bool* redundant /**< pointer to return whtether the cut was detected to be redundant */
    2122 )
    2123{
    2124 int i;
    2125 int nintegralvars;
    2126 SCIP_Bool isintegral = TRUE;
    2127 SCIP_VAR** vars;
    2128 SCIP_Real QUAD(maxacttmp);
    2129 SCIP_Real maxact;
    2130 SCIP_Real maxabsintval = 0.0;
    2131 SCIP_Real maxabscontval = 0.0;
    2132
    2133 assert(!SCIPisExact(scip));
    2134
    2135 QUAD_ASSIGN(maxacttmp, 0.0);
    2136
    2137 vars = SCIPgetVars(scip);
    2138 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    2139
    2140 assert(redundant != NULL);
    2141 *redundant = FALSE;
    2142
    2143 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
    2144 for( i = 0; i < *cutnnz; ++i )
    2145 {
    2146 SCIP_Real val;
    2147 SCIP_Real QUAD(quadprod);
    2148
    2149 assert(cutinds[i] >= 0);
    2150 assert(vars[cutinds[i]] != NULL);
    2151
    2152 val = cutcoefs[cutinds[i]];
    2153
    2154 if( val < 0.0 )
    2155 {
    2156 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    2157
    2158 if( SCIPisInfinity(scip, -lb) )
    2159 return SCIP_OKAY;
    2160
    2161 if( cutinds[i] < nintegralvars )
    2162 maxabsintval = MAX(maxabsintval, -val);
    2163 else
    2164 {
    2165 maxabscontval = MAX(maxabscontval, -val);
    2166 isintegral = FALSE;
    2167 }
    2168
    2169 SCIPquadprecProdDD(quadprod, val, lb);
    2170 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2171 }
    2172 else
    2173 {
    2174 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2175
    2176 if( SCIPisInfinity(scip, ub) )
    2177 return SCIP_OKAY;
    2178
    2179 if( cutinds[i] < nintegralvars )
    2180 maxabsintval = MAX(maxabsintval, val);
    2181 else
    2182 {
    2183 maxabscontval = MAX(maxabscontval, val);
    2184 isintegral = FALSE;
    2185 }
    2186
    2187 SCIPquadprecProdDD(quadprod, val, ub);
    2188 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2189 }
    2190 }
    2191
    2192 maxact = QUAD_TO_DBL(maxacttmp);
    2193
    2194 /* cut is redundant in activity bounds */
    2195 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
    2196 {
    2197 *redundant = TRUE;
    2198 return SCIP_OKAY;
    2199 }
    2200
    2201 /* cut is only on integral variables, try to scale to integral coefficients */
    2202 if( isintegral )
    2203 {
    2204 SCIP_Real equiscale;
    2205 SCIP_Real intscalar;
    2206 SCIP_Bool success;
    2207 SCIP_Real* intcoeffs;
    2208
    2209 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
    2210
    2211 equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
    2212
    2213 for( i = 0; i < *cutnnz; ++i )
    2214 {
    2215 SCIP_Real val;
    2216
    2217 val = equiscale * cutcoefs[cutinds[i]];
    2218
    2219 intcoeffs[i] = val;
    2220 }
    2221
    2223 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
    2224
    2225 SCIPfreeBufferArray(scip, &intcoeffs);
    2226
    2227 if( success )
    2228 {
    2229 /* if successful, apply the scaling */
    2230 intscalar *= equiscale;
    2231 SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
    2232
    2233 for( i = 0; i < *cutnnz; )
    2234 {
    2235 SCIP_Real val;
    2236 SCIP_Real intval;
    2237
    2238 val = cutcoefs[cutinds[i]];
    2239 val *= intscalar;
    2240
    2241 intval = SCIPround(scip, val);
    2242
    2243 if( chgCoeffWithBound(scip, vars[cutinds[i]], val, intval, cutislocal, QUAD(cutrhs)) )
    2244 {
    2245 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
    2246 *redundant = TRUE;
    2247 return SCIP_OKAY;
    2248 }
    2249
    2250 if( intval != 0.0 )
    2251 {
    2252 cutcoefs[cutinds[i]] = intval;
    2253 ++i;
    2254 }
    2255 else
    2256 {
    2257 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
    2258 cutcoefs[cutinds[i]] = 0.0;
    2259 --(*cutnnz);
    2260 cutinds[i] = cutinds[*cutnnz];
    2261 }
    2262 }
    2263
    2264 SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
    2265
    2266 /* recompute the maximal activity after scaling to integral values */
    2267 QUAD_ASSIGN(maxacttmp, 0.0);
    2268 maxabsintval = 0.0;
    2269
    2270 for( i = 0; i < *cutnnz; ++i )
    2271 {
    2272 SCIP_Real val;
    2273 SCIP_Real QUAD(quadprod);
    2274
    2275 assert(cutinds[i] >= 0);
    2276 assert(vars[cutinds[i]] != NULL);
    2277
    2278 val = cutcoefs[cutinds[i]];
    2279
    2280 if( val < 0.0 )
    2281 {
    2282 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    2283
    2284 maxabsintval = MAX(maxabsintval, -val);
    2285
    2286 SCIPquadprecProdDD(quadprod, val, lb);
    2287 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2288 }
    2289 else
    2290 {
    2291 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2292
    2293 maxabsintval = MAX(maxabsintval, val);
    2294
    2295 SCIPquadprecProdDD(quadprod, val, ub);
    2296 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2297 }
    2298 }
    2299
    2300 assert(EPSISINT(QUAD_TO_DBL(maxacttmp), 1e-4));
    2301 SCIPquadprecSumQD(maxacttmp, maxacttmp, 0.5);
    2302 SCIPquadprecFloorQ(maxacttmp, maxacttmp);
    2303 }
    2304 else
    2305 {
    2306 /* otherwise, apply the equilibrium scaling */
    2307 isintegral = FALSE;
    2308
    2309 /* perform the scaling */
    2310 SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
    2311 SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
    2312 maxabsintval *= equiscale;
    2313
    2314 for( i = 0; i < *cutnnz; ++i )
    2315 cutcoefs[cutinds[i]] *= equiscale;
    2316 }
    2317 }
    2318 else
    2319 {
    2320 /* cut has integer and continuous variables, so scale it to equilibrium */
    2321 SCIP_Real scale;
    2322 SCIP_Real maxabsval;
    2323
    2324 maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
    2325 maxabsval = MIN(maxabsval, maxabsintval);
    2326 maxabsval = MAX(maxabsval, maxabscontval);
    2327
    2328 scale = 1.0 / maxabsval; /*lint !e795*/
    2329
    2330 /* perform the scaling */
    2331 SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
    2332 SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
    2333 maxabsintval *= scale;
    2334
    2335 for( i = 0; i < *cutnnz; ++i )
    2336 cutcoefs[cutinds[i]] *= scale;
    2337 }
    2338
    2339 maxact = QUAD_TO_DBL(maxacttmp);
    2340
    2341 /* check again for redundancy after scaling */
    2342 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
    2343 {
    2344 *redundant = TRUE;
    2345 return SCIP_OKAY;
    2346 }
    2347
    2348 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
    2349 if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
    2350 return SCIP_OKAY;
    2351
    2352 /* first sort indices, so that in the following sort, the order for coefficients with same absolute value does not depend on how cutinds was initially ordered */
    2353 SCIPsortInt(cutinds, *cutnnz);
    2354 SCIPsortDownInd(cutinds, compareAbsCoefs, (void*) cutcoefs, *cutnnz);
    2355
    2356 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
    2357 for( i = 0; i < *cutnnz; )
    2358 {
    2359 SCIP_Real val;
    2360
    2361 if( cutinds[i] >= nintegralvars )
    2362 {
    2363 ++i;
    2364 continue;
    2365 }
    2366
    2367 val = cutcoefs[cutinds[i]];
    2368
    2369 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
    2370
    2371 if( val < 0.0 && SCIPisLE(scip, maxact + val, QUAD_TO_DBL(*cutrhs)) )
    2372 {
    2373 SCIP_Real QUAD(coef);
    2374 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    2375
    2376 SCIPquadprecSumQQ(coef, -maxacttmp, *cutrhs);
    2377
    2378 if( isintegral )
    2379 {
    2380 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    2381 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    2382 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    2383 }
    2384
    2385 if( QUAD_TO_DBL(coef) > val )
    2386 {
    2387 SCIP_Real QUAD(delta);
    2388 SCIP_Real QUAD(tmp);
    2389
    2390 SCIPquadprecSumQD(delta, coef, -val);
    2391 SCIPquadprecProdQD(delta, delta, lb);
    2392
    2393 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    2394 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2395 val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
    2396 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
    2397
    2398 QUAD_ASSIGN_Q(*cutrhs, tmp);
    2399
    2400 assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
    2401
    2402 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
    2403 {
    2404 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2405 maxact = QUAD_TO_DBL(maxacttmp);
    2406 cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
    2407 }
    2408 else
    2409 {
    2410 cutcoefs[cutinds[i]] = 0.0;
    2411 --(*cutnnz);
    2412 cutinds[i] = cutinds[*cutnnz];
    2413 continue;
    2414 }
    2415 }
    2416 }
    2417 else if( val > 0.0 && SCIPisLE(scip, maxact - val, QUAD_TO_DBL(*cutrhs)) )
    2418 {
    2419 SCIP_Real QUAD(coef);
    2420 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2421
    2422 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
    2423
    2424 if( isintegral )
    2425 {
    2426 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    2427 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    2428 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    2429 }
    2430
    2431 if( QUAD_TO_DBL(coef) < val )
    2432 {
    2433 SCIP_Real QUAD(delta);
    2434 SCIP_Real QUAD(tmp);
    2435
    2436 SCIPquadprecSumQD(delta, coef, -val);
    2437 SCIPquadprecProdQD(delta, delta, ub);
    2438
    2439 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    2440 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2441 val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
    2442 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
    2443
    2444 QUAD_ASSIGN_Q(*cutrhs, tmp);
    2445
    2446 assert(! SCIPisNegative(scip, QUAD_TO_DBL(coef)));
    2447
    2448 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
    2449 {
    2450 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2451 maxact = QUAD_TO_DBL(maxacttmp);
    2452 cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
    2453 }
    2454 else
    2455 {
    2456 cutcoefs[cutinds[i]] = 0.0;
    2457 --(*cutnnz);
    2458 cutinds[i] = cutinds[*cutnnz];
    2459 continue;
    2460 }
    2461 }
    2462 }
    2463 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
    2464 break;
    2465
    2466 ++i;
    2467 }
    2468
    2469 return SCIP_OKAY;
    2470}
    2471
    2472/** perform activity based coefficient tightening on the given cut; returns TRUE if the cut was detected
    2473 * to be redundant due to activity bounds
    2474 *
    2475 * See also cons_linear.c:consdataTightenCoefs().
    2476 */
    2478 SCIP* scip, /**< SCIP data structure */
    2479 SCIP_Bool cutislocal, /**< is the cut local? */
    2480 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    2481 SCIP_Real* cutrhs, /**< the right hand side of the cut */
    2482 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    2483 int* cutnnz, /**< the number of non-zeros in the cut */
    2484 int* nchgcoefs /**< number of changed coefficients */
    2485 )
    2486{
    2487 int i;
    2488 int nintegralvars;
    2489 SCIP_VAR** vars;
    2490 SCIP_Real* absvals;
    2491 SCIP_Real QUAD(maxacttmp);
    2492 SCIP_Real maxact;
    2493 SCIP_Real maxabsval = 0.0;
    2494 SCIP_Bool redundant = FALSE;
    2495
    2496 assert(nchgcoefs != NULL);
    2497
    2498 QUAD_ASSIGN(maxacttmp, 0.0);
    2499
    2500 vars = SCIPgetVars(scip);
    2501 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    2502 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &absvals, *cutnnz) );
    2503
    2504 assert(nchgcoefs != NULL);
    2505 *nchgcoefs = 0;
    2506
    2507 for( i = 0; i < *cutnnz; ++i )
    2508 {
    2509 SCIP_Real QUAD(quadprod);
    2510
    2511 assert(cutinds[i] >= 0);
    2512 assert(vars[cutinds[i]] != NULL);
    2513
    2514 if( cutcoefs[i] < 0.0 )
    2515 {
    2516 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    2517
    2518 if( SCIPisInfinity(scip, -lb) )
    2519 goto TERMINATE;
    2520
    2521 if( cutinds[i] < nintegralvars )
    2522 {
    2523 maxabsval = MAX(maxabsval, -cutcoefs[i]);
    2524 absvals[i] = -cutcoefs[i];
    2525 }
    2526 else
    2527 absvals[i] = 0.0;
    2528
    2529 SCIPquadprecProdDD(quadprod, lb, cutcoefs[i]);
    2530 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2531 }
    2532 else
    2533 {
    2534 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2535
    2536 if( SCIPisInfinity(scip, ub) )
    2537 goto TERMINATE;
    2538
    2539 if( cutinds[i] < nintegralvars )
    2540 {
    2541 maxabsval = MAX(maxabsval, cutcoefs[i]);
    2542 absvals[i] = cutcoefs[i];
    2543 }
    2544 else
    2545 absvals[i] = 0.0;
    2546
    2547 SCIPquadprecProdDD(quadprod, ub, cutcoefs[i]);
    2548 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2549 }
    2550 }
    2551
    2552 maxact = QUAD_TO_DBL(maxacttmp);
    2553
    2554 /* cut is redundant in activity bounds */
    2555 if( SCIPisFeasLE(scip, maxact, *cutrhs) )
    2556 {
    2557 redundant = TRUE;
    2558 goto TERMINATE;
    2559 }
    2560
    2561 /* terminate, because coefficient tightening cannot be performed; also excludes the case in which no integral variable is present */
    2562 if( SCIPisGT(scip, maxact - maxabsval, *cutrhs) )
    2563 goto TERMINATE;
    2564
    2565 SCIPsortDownRealRealInt(absvals, cutcoefs, cutinds, *cutnnz);
    2566 SCIPfreeBufferArray(scip, &absvals);
    2567
    2568 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
    2569 for( i = 0; i < *cutnnz; ++i )
    2570 {
    2571 /* due to sorting, we can exit if we reached a continuous variable: all further integral variables have 0 coefficents anyway */
    2572 if( cutinds[i] >= nintegralvars )
    2573 break;
    2574
    2575 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
    2576
    2577 if( cutcoefs[i] < 0.0 && SCIPisLE(scip, maxact + cutcoefs[i], *cutrhs) )
    2578 {
    2579 SCIP_Real coef = (*cutrhs) - maxact;
    2580 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    2581
    2582 coef = SCIPfloor(scip, coef);
    2583
    2584 if( coef > cutcoefs[i] )
    2585 {
    2586 SCIP_Real QUAD(delta);
    2587 SCIP_Real QUAD(tmp);
    2588
    2589 SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
    2590 SCIPquadprecProdQD(delta, delta, lb);
    2591
    2592 SCIPquadprecSumQD(tmp, delta, *cutrhs);
    2593 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2594 cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp), lb,
    2595 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
    2596
    2597 *cutrhs = QUAD_TO_DBL(tmp);
    2598
    2599 assert(!SCIPisPositive(scip, coef));
    2600
    2601 ++(*nchgcoefs);
    2602
    2603 if( SCIPisNegative(scip, coef) )
    2604 {
    2605 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2606 maxact = QUAD_TO_DBL(maxacttmp);
    2607 cutcoefs[i] = coef;
    2608 }
    2609 else
    2610 {
    2611 --(*cutnnz);
    2612 cutinds[i] = cutinds[*cutnnz];
    2613 cutcoefs[i] = cutcoefs[*cutnnz];
    2614 continue;
    2615 }
    2616 }
    2617 }
    2618 else if( cutcoefs[i] > 0.0 && SCIPisLE(scip, maxact - cutcoefs[i], *cutrhs) )
    2619 {
    2620 SCIP_Real coef = maxact - (*cutrhs);
    2621 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2622
    2623 coef = SCIPceil(scip, coef);
    2624
    2625 if( coef < cutcoefs[i] )
    2626 {
    2627 SCIP_Real QUAD(delta);
    2628 SCIP_Real QUAD(tmp);
    2629
    2630 SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
    2631 SCIPquadprecProdQD(delta, delta, ub);
    2632
    2633 SCIPquadprecSumQD(tmp, delta, *cutrhs);
    2634 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2635 cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp),
    2636 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
    2637
    2638 *cutrhs = QUAD_TO_DBL(tmp);
    2639
    2640 assert(!SCIPisNegative(scip, coef));
    2641
    2642 ++(*nchgcoefs);
    2643
    2644 if( SCIPisPositive(scip, coef) )
    2645 {
    2646 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2647 maxact = QUAD_TO_DBL(maxacttmp);
    2648 cutcoefs[i] = coef;
    2649 }
    2650 else
    2651 {
    2652 --(*cutnnz);
    2653 cutinds[i] = cutinds[*cutnnz];
    2654 cutcoefs[i] = cutcoefs[*cutnnz];
    2655 continue;
    2656 }
    2657 }
    2658 }
    2659 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
    2660 break;
    2661 }
    2662
    2663 TERMINATE:
    2664 SCIPfreeBufferArrayNull(scip, &absvals);
    2665
    2666 return redundant;
    2667}
    2668
    2669/* =========================================== aggregation row =========================================== */
    2670
    2671
    2672/** create an empty aggregation row
    2673 *
    2674 * @note By default, this data structure uses quad precision via double-double arithmetic, i.e., it allocates a
    2675 * SCIP_Real array of length two times SCIPgetNVars() for storing the coefficients. In exact solving mode, we
    2676 * cannot use quad precision because we need to control the ronding mode, hence only the first SCIPgetNVars()
    2677 * entries are used.
    2678 */
    2680 SCIP* scip, /**< SCIP data structure */
    2681 SCIP_AGGRROW** aggrrow /**< pointer to return aggregation row */
    2682 )
    2683{
    2684 int nvars;
    2685 assert(scip != NULL);
    2686 assert(aggrrow != NULL);
    2687
    2688 SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
    2689
    2690 nvars = SCIPgetNVars(scip);
    2691
    2692 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)) );
    2693 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->inds, nvars) );
    2694
    2695 BMSclearMemoryArray((*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars));
    2696
    2697 (*aggrrow)->local = FALSE;
    2698 (*aggrrow)->nnz = 0;
    2699 (*aggrrow)->rank = 0;
    2700 QUAD_ASSIGN((*aggrrow)->rhs, 0.0);
    2701 (*aggrrow)->rowsinds = NULL;
    2702 (*aggrrow)->slacksign = NULL;
    2703 (*aggrrow)->rowweights = NULL;
    2704 (*aggrrow)->nrows = 0;
    2705 (*aggrrow)->rowssize = 0;
    2706
    2707 return SCIP_OKAY;
    2708}
    2709
    2710/** free a aggregation row */
    2712 SCIP* scip, /**< SCIP data structure */
    2713 SCIP_AGGRROW** aggrrow /**< pointer to aggregation row that should be freed */
    2714 )
    2715{
    2716 int nvars;
    2717
    2718 assert(scip != NULL);
    2719 assert(aggrrow != NULL);
    2720
    2721 nvars = SCIPgetNVars(scip);
    2722
    2723 SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->inds, nvars);
    2724 SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)); /*lint !e647*/
    2725 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowsinds, (*aggrrow)->rowssize);
    2726 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->slacksign, (*aggrrow)->rowssize);
    2727 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowweights, (*aggrrow)->rowssize);
    2728 SCIPfreeBlockMemory(scip, aggrrow);
    2729}
    2730
    2731/** output aggregation row to file stream */
    2733 SCIP* scip, /**< SCIP data structure */
    2734 SCIP_AGGRROW* aggrrow, /**< pointer to return aggregation row */
    2735 FILE* file /**< output file (or NULL for standard output) */
    2736 )
    2737{
    2738 SCIP_VAR** vars;
    2739 SCIP_MESSAGEHDLR* messagehdlr;
    2740 int i;
    2741
    2742 assert(scip != NULL);
    2743 assert(aggrrow != NULL);
    2744
    2745 vars = SCIPgetVars(scip);
    2746 assert(vars != NULL);
    2747
    2748 messagehdlr = SCIPgetMessagehdlr(scip);
    2749 assert(messagehdlr);
    2750
    2751 /* print coefficients */
    2752 if( aggrrow->nnz == 0 )
    2753 SCIPmessageFPrintInfo(messagehdlr, file, "0 ");
    2754
    2755 for( i = 0; i < aggrrow->nnz; ++i )
    2756 {
    2757 SCIP_Real QUAD(val);
    2758
    2759 QUAD_ARRAY_LOAD(val, aggrrow->vals, aggrrow->inds[i]);
    2760 assert(SCIPvarGetProbindex(vars[aggrrow->inds[i]]) == aggrrow->inds[i]);
    2761 SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", QUAD_TO_DBL(val), SCIPvarGetName(vars[aggrrow->inds[i]]));
    2762 }
    2763
    2764 /* print right hand side */
    2765 SCIPmessageFPrintInfo(messagehdlr, file, "<= %.15g\n", QUAD_TO_DBL(aggrrow->rhs));
    2766}
    2767
    2768/** copy a aggregation row */
    2770 SCIP* scip, /**< SCIP data structure */
    2771 SCIP_AGGRROW** aggrrow, /**< pointer to return aggregation row */
    2772 SCIP_AGGRROW* source /**< source aggregation row */
    2773 )
    2774{
    2775 int nvars;
    2776
    2777 assert(scip != NULL);
    2778 assert(aggrrow != NULL);
    2779 assert(source != NULL);
    2780
    2781 nvars = SCIPgetNVars(scip);
    2782 SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
    2783
    2784 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->vals, source->vals, QUAD_ARRAY_SIZE(nvars)) );
    2785 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->inds, source->inds, nvars) );
    2786 (*aggrrow)->nnz = source->nnz;
    2787 QUAD_ASSIGN_Q((*aggrrow)->rhs, source->rhs);
    2788
    2789 if( source->nrows > 0 )
    2790 {
    2791 assert(source->rowsinds != NULL);
    2792 assert(source->slacksign != NULL);
    2793 assert(source->rowweights != NULL);
    2794
    2795 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowsinds, source->rowsinds, source->nrows) );
    2796 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->slacksign, source->slacksign, source->nrows) );
    2797 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowweights, source->rowweights, source->nrows) );
    2798 }
    2799 else
    2800 {
    2801 (*aggrrow)->rowsinds = NULL;
    2802 (*aggrrow)->slacksign = NULL;
    2803 (*aggrrow)->rowweights = NULL;
    2804 }
    2805
    2806 (*aggrrow)->nrows = source->nrows;
    2807 (*aggrrow)->rowssize = source->nrows;
    2808 (*aggrrow)->rank = source->rank;
    2809 (*aggrrow)->local = source->local;
    2810
    2811 return SCIP_OKAY;
    2812}
    2813
    2814/** add weighted row to aggregation row */
    2816 SCIP* scip, /**< SCIP data structure */
    2817 SCIP_AGGRROW* aggrrow, /**< aggregation row */
    2818 SCIP_ROW* row, /**< row to add to aggregation row */
    2819 SCIP_Real weight, /**< scale for adding given row to aggregation row */
    2820 int sidetype /**< specify row side type (-1 = lhs, 0 = automatic, 1 = rhs) */
    2821 )
    2822{
    2823 SCIP_Real QUAD(quadprod);
    2824 SCIP_Real sideval;
    2825 SCIP_Bool uselhs;
    2826 int i;
    2827
    2828 assert(row->lppos >= 0);
    2829
    2830 /* update local flag */
    2831 aggrrow->local = aggrrow->local || row->local;
    2832
    2833 /* update rank */
    2834 aggrrow->rank = MAX(row->rank, aggrrow->rank);
    2835
    2836 i = aggrrow->nrows++;
    2837
    2838 if( aggrrow->nrows > aggrrow->rowssize )
    2839 {
    2840 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
    2841 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
    2842 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
    2843 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
    2844 aggrrow->rowssize = newsize;
    2845 }
    2846 aggrrow->rowsinds[i] = SCIProwGetLPPos(row);
    2847 aggrrow->rowweights[i] = weight;
    2848
    2849 if( sidetype == -1 )
    2850 {
    2851 assert( ! SCIPisInfinity(scip, -row->lhs) );
    2852 uselhs = TRUE;
    2853 }
    2854 else if( sidetype == 1 )
    2855 {
    2856 assert( ! SCIPisInfinity(scip, row->rhs) );
    2857 uselhs = FALSE;
    2858 }
    2859 else
    2860 {
    2861 /* Automatically decide, whether we want to use the left or the right hand side of the row in the summation.
    2862 * If possible, use the side that leads to a positive slack value in the summation.
    2863 */
    2864 if( SCIPisInfinity(scip, row->rhs) || (!SCIPisInfinity(scip, -row->lhs) && weight < 0.0) )
    2865 uselhs = TRUE;
    2866 else
    2867 uselhs = FALSE;
    2868 }
    2869
    2870 if( uselhs )
    2871 {
    2872 aggrrow->slacksign[i] = -1;
    2873 sideval = row->lhs - row->constant;
    2874 if( row->integral )
    2875 sideval = SCIPceil(scip, sideval); /* row is integral: round left hand side up */
    2876 }
    2877 else
    2878 {
    2879 aggrrow->slacksign[i] = +1;
    2880 sideval = row->rhs - row->constant;
    2881 if( row->integral )
    2882 sideval = SCIPfloor(scip, sideval); /* row is integral: round right hand side up */
    2883 }
    2884
    2885 SCIPquadprecProdDD(quadprod, weight, sideval);
    2886 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
    2887
    2888 /* add up coefficients */
    2889 SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
    2890
    2891 return SCIP_OKAY;
    2892}
    2893
    2894/** add weighted row to aggregation row
    2895 *
    2896 * @note this method is the variant of SCIPaggrRowAddRow that is safe to use in exact solving mode
    2897 */
    2899 SCIP* scip, /**< SCIP data structure */
    2900 SCIP_AGGRROW* aggrrow, /**< aggregation row */
    2901 SCIP_ROW* row, /**< row to add to aggregation row */
    2902 SCIP_Real weight, /**< scale for adding given row to aggregation row */
    2903 int sidetype, /**< specify row side type (-1 = lhs, 0 = automatic, 1 = rhs) */
    2904 SCIP_Bool* success /**< was the row added successfully */
    2905 )
    2906{
    2907 SCIP_Real sideval;
    2908 SCIP_Real sidevalchg;
    2909 SCIP_Bool uselhs;
    2910 SCIP_ROW* userow;
    2911 SCIP_ROWEXACT* rowexact;
    2912 SCIP_ROUNDMODE previousroundmode;
    2913 int i;
    2914
    2915 assert(SCIPisExact(scip));
    2916 assert(success != NULL);
    2917
    2918 /* update local flag */
    2919 aggrrow->local = aggrrow->local || row->local;
    2920
    2921 /* update rank */
    2922 aggrrow->rank = MAX(row->rank, aggrrow->rank);
    2923
    2924 i = aggrrow->nrows++;
    2925
    2926 if( aggrrow->nrows > aggrrow->rowssize )
    2927 {
    2928 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
    2929 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
    2930 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
    2931 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
    2932 aggrrow->rowssize = newsize;
    2933 }
    2934 aggrrow->rowsinds[i] = SCIProwGetLPPos(row);
    2935 aggrrow->rowweights[i] = weight;
    2936
    2937 if( sidetype == -1 )
    2938 {
    2939 assert(!SCIPisInfinity(scip, -row->lhs));
    2940 uselhs = TRUE;
    2941 }
    2942 else if( sidetype == 1 )
    2943 {
    2944 assert(!SCIPisInfinity(scip, row->rhs));
    2945 uselhs = FALSE;
    2946 }
    2947 else
    2948 {
    2949 /* Automatically decide, whether we want to use the left or the right hand side of the row in the summation.
    2950 * If possible, use the side that leads to a positive slack value in the summation.
    2951 */
    2952 if( SCIPisInfinity(scip, row->rhs) || (!SCIPisInfinity(scip, -row->lhs) && weight < 0.0) )
    2953 uselhs = TRUE;
    2954 else
    2955 uselhs = FALSE;
    2956 }
    2957 rowexact = SCIProwGetRowExact(row);
    2958 if( !SCIProwExactHasFpRelax(rowexact) )
    2959 {
    2960 *success = FALSE;
    2961 return SCIP_OKAY;
    2962 }
    2963 else if( SCIProwExactGetRowRhs(rowexact) != NULL && weight >= 0.0 )
    2964 userow = SCIProwExactGetRowRhs(rowexact);
    2965 else
    2966 userow = row;
    2967
    2968 aggrrow->slacksign[i] = uselhs ? -1 : 1;
    2969
    2970 previousroundmode = SCIPintervalGetRoundingMode();
    2971
    2972 if( uselhs )
    2973 {
    2975 sideval = userow->lhs - userow->constant;
    2976#ifdef SCIP_DISABLED_CODE
    2977 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
    2978 /* row is integral? round left hand side up */
    2979 if( userow->integral )
    2980 sideval = ceil(sideval)
    2981#endif
    2982 }
    2983 else
    2984 {
    2986 sideval = userow->rhs - userow->constant;
    2987#ifdef SCIP_DISABLED_CODE
    2988 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
    2989 /* row is integral? round right hand side down */
    2990 if( userow->integral )
    2991 sideval = floor(sideval);
    2992#endif
    2993 }
    2994
    2996 sidevalchg = QUAD_TO_DBL(aggrrow->rhs);
    2997 sidevalchg += sideval * weight;
    2998 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
    2999
    3000 /* add up coefficients */
    3001 *success = TRUE;
    3002 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, aggrrow->inds, aggrrow->vals, &aggrrow->nnz, userow, weight, &sidevalchg, success) );
    3003
    3004 sidevalchg += QUAD_TO_DBL(aggrrow->rhs);
    3005 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
    3006
    3007 SCIPintervalSetRoundingMode(previousroundmode);
    3008
    3009 return SCIP_OKAY;
    3010}
    3011
    3012/** Removes a given variable @p var from position @p pos the aggregation row and updates the right-hand side according
    3013 * to sign of the coefficient, i.e., rhs -= coef * bound, where bound = lb if coef >= 0 and bound = ub, otherwise.
    3014 *
    3015 * @note: The choice of global or local bounds depend on the validity (global or local) of the aggregation row.
    3016 *
    3017 * @note: The list of non-zero indices will be updated by swapping the last non-zero index to @p pos.
    3018 */
    3020 SCIP* scip, /**< SCIP data structure */
    3021 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3022 SCIP_VAR* var, /**< variable that should be removed */
    3023 int pos, /**< position of the variable in the aggregation row */
    3024 SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
    3025 )
    3026{
    3027 SCIP_Real QUAD(val);
    3028 int v;
    3029
    3030 assert(valid != NULL);
    3031 assert(pos >= 0);
    3032
    3033 v = aggrrow->inds[pos];
    3034 assert(v == SCIPvarGetProbindex(var));
    3035
    3036 QUAD_ARRAY_LOAD(val, aggrrow->vals, v);
    3037
    3038 *valid = TRUE;
    3039
    3040 /* adjust left and right hand sides with max contribution */
    3041 if( QUAD_TO_DBL(val) < 0.0 )
    3042 {
    3043 SCIP_Real ub = aggrrow->local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
    3044
    3045 if( SCIPisInfinity(scip, ub) )
    3046 QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
    3047 else
    3048 {
    3049 SCIPquadprecProdQD(val, val, ub);
    3050 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
    3051 }
    3052 }
    3053 else
    3054 {
    3055 SCIP_Real lb = aggrrow->local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
    3056
    3057 if( SCIPisInfinity(scip, -lb) )
    3058 QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
    3059 else
    3060 {
    3061 SCIPquadprecProdQD(val, val, lb);
    3062 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
    3063 }
    3064 }
    3065
    3066 QUAD_ASSIGN(val, 0.0);
    3067 QUAD_ARRAY_STORE(aggrrow->vals, v, val);
    3068
    3069 /* remove non-zero entry */
    3070 --(aggrrow->nnz);
    3071 aggrrow->inds[pos] = aggrrow->inds[aggrrow->nnz];
    3072
    3073 if( SCIPisInfinity(scip, QUAD_HI(aggrrow->rhs)) )
    3074 *valid = FALSE;
    3075}
    3076
    3077/** add the objective function with right-hand side @p rhs and scaled by @p scale to the aggregation row */
    3079 SCIP* scip, /**< SCIP data structure */
    3080 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3081 SCIP_Real rhs, /**< right-hand side of the artificial row */
    3082 SCIP_Real scale /**< scalar */
    3083 )
    3084{
    3085 SCIP_VAR** vars;
    3086 SCIP_Real QUAD(val);
    3087 int nvars;
    3088
    3089 assert(scip != NULL);
    3090 assert(aggrrow != NULL);
    3091
    3092 vars = SCIPgetVars(scip);
    3093 nvars = SCIPgetNVars(scip);
    3094
    3095 /* add all variables straight forward if the aggregation row is empty */
    3096 if( aggrrow->nnz == 0 )
    3097 {
    3098 int i;
    3099 for( i = 0; i < nvars; ++i )
    3100 {
    3101 assert(SCIPvarGetProbindex(vars[i]) == i);
    3102
    3103 /* skip all variables with zero objective coefficient */
    3104 if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
    3105 continue;
    3106
    3107 QUAD_ASSIGN(val, scale * SCIPvarGetObj(vars[i])); /*lint !e665*/
    3108 QUAD_ARRAY_STORE(aggrrow->vals, i, val);
    3109 aggrrow->inds[aggrrow->nnz++] = i;
    3110 }
    3111
    3112 /* add right-hand side value */
    3113 QUAD_ASSIGN(aggrrow->rhs, scale * rhs); /*lint !e665*/
    3114 }
    3115 else
    3116 {
    3117 int i;
    3118 SCIP_Real QUAD(quadprod);
    3119 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    3120 for( i = 0 ; i < nvars; ++i )
    3121 {
    3122 SCIP_Real varobj;
    3123 assert(SCIPvarGetProbindex(vars[i]) == i);
    3124
    3125 /* skip all variables with zero objective coefficient */
    3126 if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
    3127 continue;
    3128
    3129 QUAD_ARRAY_LOAD(val, aggrrow->vals, i); /* val = aggrrow->vals[i] */
    3130
    3131 if( QUAD_HI(val) == 0.0 )
    3132 aggrrow->inds[aggrrow->nnz++] = i;
    3133
    3134 varobj = SCIPvarGetObj(vars[i]);
    3135 SCIPquadprecProdDD(quadprod, scale, varobj);
    3136 SCIPquadprecSumQQ(val, val, quadprod);
    3137
    3138 /* the value must not be exactly zero due to sparsity pattern */
    3139 QUAD_HI(val) = NONZERO(QUAD_HI(val));
    3140 assert(QUAD_HI(val) != 0.0);
    3141
    3142 QUAD_ARRAY_STORE(aggrrow->vals, i, val);
    3143 }
    3144
    3145 /* add right-hand side value */
    3146 SCIPquadprecProdDD(quadprod, scale, rhs);
    3147 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
    3148 }
    3149
    3150 return SCIP_OKAY;
    3151}
    3152
    3153/** add weighted constraint to the aggregation row */
    3155 SCIP* scip, /**< SCIP data structure */
    3156 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3157 int* inds, /**< variable problem indices in constraint to add to the aggregation row */
    3158 SCIP_Real* vals, /**< values of constraint to add to the aggregation row */
    3159 int len, /**< length of constraint to add to the aggregation row */
    3160 SCIP_Real rhs, /**< right hand side of constraint to add to the aggregation row */
    3161 SCIP_Real weight, /**< (positive) scale for adding given constraint to the aggregation row */
    3162 int rank, /**< rank to use for given constraint */
    3163 SCIP_Bool local /**< is constraint only valid locally */
    3164 )
    3165{
    3166 SCIP_Real QUAD(quadprod);
    3167 int i;
    3168
    3169 assert(weight >= 0.0);
    3170 assert(!SCIPisInfinity(scip, REALABS(weight * rhs)));
    3171
    3172 /* update local flag */
    3173 aggrrow->local = aggrrow->local || local;
    3174
    3175 /* update rank */
    3176 aggrrow->rank = MAX(rank, aggrrow->rank);
    3177
    3178 /* add right hand side value */
    3179 SCIPquadprecProdDD(quadprod, weight, rhs);
    3180 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
    3181
    3182 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    3183 for( i = 0 ; i < len; ++i )
    3184 {
    3185 SCIP_Real QUAD(val);
    3186 int probindex = inds[i];
    3187
    3188 QUAD_ARRAY_LOAD(val, aggrrow->vals, probindex); /* val = aggrrow->vals[probindex] */
    3189
    3190 if( QUAD_HI(val) == 0.0 )
    3191 aggrrow->inds[aggrrow->nnz++] = probindex;
    3192
    3193 SCIPquadprecProdDD(quadprod, vals[i], weight);
    3194 SCIPquadprecSumQQ(val, val, quadprod);
    3195
    3196 /* the value must not be exactly zero due to sparsity pattern */
    3197 QUAD_HI(val) = NONZERO(QUAD_HI(val));
    3198 assert(QUAD_HI(val) != 0.0);
    3199
    3200 QUAD_ARRAY_STORE(aggrrow->vals, probindex, val);
    3201 }
    3202
    3203 return SCIP_OKAY;
    3204}
    3205
    3206/** version for use in exact solving mode of SCIPaggrRowClear() */
    3208 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    3209 )
    3210{
    3211 int i;
    3212
    3213 /* in exact solving mode, we do not use quad precision, because we need to control the rounding mode; hence, we only
    3214 * use and clear the first SCIPgetNVars() entries
    3215 */
    3216 for( i = 0; i < aggrrow->nnz; ++i )
    3217 {
    3218 aggrrow->vals[aggrrow->inds[i]] = 0.0;
    3219 }
    3220
    3221 aggrrow->nnz = 0;
    3222 aggrrow->nrows = 0;
    3223 aggrrow->rank = 0;
    3224 QUAD_ASSIGN(aggrrow->rhs, 0.0);
    3225 aggrrow->local = FALSE;
    3226}
    3227
    3228/** clear all entries int the aggregation row but don't free memory */
    3230 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    3231 )
    3232{
    3233 int i;
    3234 SCIP_Real QUAD(tmp);
    3235
    3236 QUAD_ASSIGN(tmp, 0.0);
    3237
    3238 for( i = 0; i < aggrrow->nnz; ++i )
    3239 {
    3240 QUAD_ARRAY_STORE(aggrrow->vals, aggrrow->inds[i], tmp);
    3241 }
    3242
    3243 aggrrow->nnz = 0;
    3244 aggrrow->nrows = 0;
    3245 aggrrow->rank = 0;
    3246 QUAD_ASSIGN(aggrrow->rhs, 0.0);
    3247 aggrrow->local = FALSE;
    3248}
    3249
    3250/** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
    3251 *
    3252 * @return the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
    3253 */
    3255 SCIP* scip, /**< SCIP data structure */
    3256 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    3257 )
    3258{
    3259 return calcEfficacyNormQuad(scip, aggrrow->vals, aggrrow->inds, aggrrow->nnz);
    3260}
    3261
    3262/** adds one row to the aggregation row
    3263 *
    3264 * @note this method differs from SCIPaggrRowAddRow() by providing some additional parameters required for
    3265 * SCIPaggrRowSumRows()
    3266 */
    3267static
    3269 SCIP* scip, /**< SCIP data structure */
    3270 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3271 SCIP_ROW* row, /**< the row to add */
    3272 SCIP_Real weight, /**< weight of row to add */
    3273 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
    3274 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
    3275 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
    3276 int maxaggrlen, /**< maximal length of aggregation row */
    3277 SCIP_Bool* rowtoolong /**< is the aggregated row too long */
    3278 )
    3279{
    3280 SCIP_Real QUAD(quadprod);
    3281 SCIP_Real sideval;
    3282 SCIP_Bool uselhs;
    3283 int i;
    3284
    3285 assert( rowtoolong != NULL );
    3286 *rowtoolong = FALSE;
    3287
    3288 if( SCIPisFeasZero(scip, weight) || SCIProwIsModifiable(row) || (SCIProwIsLocal(row) && !allowlocal) )
    3289 {
    3290 return SCIP_OKAY;
    3291 }
    3292
    3293 if( sidetypebasis && !SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
    3294 {
    3296
    3297 if( stat == SCIP_BASESTAT_LOWER )
    3298 {
    3299 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
    3300 uselhs = TRUE;
    3301 }
    3302 else if( stat == SCIP_BASESTAT_UPPER )
    3303 {
    3304 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
    3305 uselhs = FALSE;
    3306 }
    3307 else if( SCIPisInfinity(scip, SCIProwGetRhs(row)) || (weight < 0.0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row))) )
    3308 uselhs = TRUE;
    3309 else
    3310 uselhs = FALSE;
    3311 }
    3312 else if( (weight < 0.0 && !SCIPisInfinity(scip, -row->lhs)) || SCIPisInfinity(scip, row->rhs) )
    3313 uselhs = TRUE;
    3314 else
    3315 uselhs = FALSE;
    3316
    3317 if( uselhs )
    3318 {
    3319 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
    3320
    3321 if( weight > 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
    3322 return SCIP_OKAY;
    3323
    3324 sideval = row->lhs - row->constant;
    3325 /* row is integral? round left hand side up */
    3326 if( row->integral )
    3327 sideval = SCIPceil(scip, sideval);
    3328 }
    3329 else
    3330 {
    3331 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
    3332
    3333 if( weight < 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
    3334 return SCIP_OKAY;
    3335
    3336 sideval = row->rhs - row->constant;
    3337 /* row is integral? round right hand side down */
    3338 if( row->integral )
    3339 sideval = SCIPfloor(scip, sideval);
    3340 }
    3341
    3342 /* add right hand side, update rank and local flag */
    3343 SCIPquadprecProdDD(quadprod, sideval, weight);
    3344 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
    3345 aggrrow->rank = MAX(aggrrow->rank, row->rank);
    3346 aggrrow->local = aggrrow->local || row->local;
    3347
    3348 /* ensure the array for storing the row information is large enough */
    3349 i = aggrrow->nrows++;
    3350 if( aggrrow->nrows > aggrrow->rowssize )
    3351 {
    3352 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
    3353 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
    3354 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
    3355 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
    3356 aggrrow->rowssize = newsize;
    3357 }
    3358
    3359 /* add information of addditional row */
    3360 aggrrow->rowsinds[i] = row->lppos;
    3361 aggrrow->rowweights[i] = weight;
    3362 aggrrow->slacksign[i] = uselhs ? -1 : 1;
    3363
    3364 /* add up coefficients */
    3365 SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
    3366
    3367 /* check if row is too long now */
    3368 if( aggrrow->nnz > maxaggrlen )
    3369 *rowtoolong = TRUE;
    3370
    3371 return SCIP_OKAY;
    3372}
    3373
    3374/** adds one row to the aggregation row
    3375 *
    3376 * @note this method differs from SCIPaggrRowAddRowSafely() by providing some additional parameters required for
    3377 * SCIPaggrRowSumRows()
    3378 *
    3379 * @note this method is the variant of addOneRow() that is safe to use in exact solving mode
    3380 */
    3381static
    3383 SCIP* scip, /**< SCIP data structure */
    3384 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3385 SCIP_ROW* row, /**< the row to add */
    3386 SCIP_Real weight, /**< weight of row to add */
    3387 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
    3388 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
    3389 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
    3390 int maxaggrlen, /**< maximal length of aggregation row */
    3391 SCIP_Bool* rowtoolong, /**< is the aggregated row too long */
    3392 SCIP_Bool* rowused, /**< was the row really added? */
    3393 SCIP_Bool* success, /**< was the row added successfully? */
    3394 SCIP_Bool* lhsused /**< was the lhs or the rhs of the row used? */
    3395 )
    3396{
    3397 SCIP_Real sideval;
    3398 SCIP_Real sidevalchg;
    3399 SCIP_Bool uselhs;
    3400 SCIP_ROW* userow;
    3401 SCIP_ROWEXACT* rowexact;
    3402 SCIP_ROUNDMODE previousroundmode;
    3403 int i;
    3404
    3405 assert(SCIPisExact(scip));
    3406 assert(rowtoolong != NULL);
    3407 *rowtoolong = FALSE;
    3408 *rowused = FALSE;
    3409
    3410 if( SCIPisFeasZero(scip, weight) || SCIProwIsModifiable(row) || (SCIProwIsLocal(row) && !allowlocal) )
    3411 {
    3412 return SCIP_OKAY;
    3413 }
    3414
    3415 if( sidetypebasis && !SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
    3416 {
    3418
    3419 if( stat == SCIP_BASESTAT_LOWER )
    3420 {
    3421 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
    3422 uselhs = TRUE;
    3423 }
    3424 else if( stat == SCIP_BASESTAT_UPPER )
    3425 {
    3426 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
    3427 uselhs = FALSE;
    3428 }
    3429 else if( SCIPisInfinity(scip, SCIProwGetRhs(row)) || (weight < 0.0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row))) )
    3430 uselhs = TRUE;
    3431 else
    3432 uselhs = FALSE;
    3433 }
    3434 else if( (weight < 0.0 && !SCIPisInfinity(scip, -row->lhs)) || SCIPisInfinity(scip, row->rhs) )
    3435 uselhs = TRUE;
    3436 else
    3437 uselhs = FALSE;
    3438
    3439 rowexact = SCIProwGetRowExact(row);
    3440 if( !SCIProwExactHasFpRelax(rowexact) )
    3441 {
    3442 *success = FALSE;
    3443 return SCIP_OKAY;
    3444 }
    3445 else if( SCIProwExactGetRowRhs(rowexact) != NULL && weight >= 0.0 )
    3446 userow = SCIProwExactGetRowRhs(rowexact);
    3447 else
    3448 userow = row;
    3449
    3450 previousroundmode = SCIPintervalGetRoundingMode();
    3451
    3452 if( uselhs )
    3453 {
    3454 *lhsused = TRUE;
    3455 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
    3456
    3457 if( weight > 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
    3458 return SCIP_OKAY;
    3459
    3461
    3462 sideval = userow->lhs - userow->constant;
    3463#ifdef SCIP_DISABLED_CODE
    3464 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
    3465 /* row is integral? round left hand side up */
    3466 if( userow->integral )
    3467 sideval = ceil(sideval);
    3468#endif
    3469 }
    3470 else
    3471 {
    3472 *lhsused = FALSE;
    3473 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
    3474
    3475 if( weight < 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
    3476 return SCIP_OKAY;
    3477
    3479
    3480 sideval = userow->rhs - userow->constant;
    3481#ifdef SCIP_DISABLED_CODE
    3482 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
    3483 /* row is integral? round right hand side down */
    3484 if( userow->integral )
    3485 sideval = floor(sideval);
    3486#endif
    3487 }
    3488
    3490
    3491 sidevalchg = QUAD_TO_DBL(aggrrow->rhs);
    3492 sidevalchg += sideval * weight;
    3493 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
    3494
    3495 aggrrow->rank = MAX(aggrrow->rank, userow->rank);
    3496 aggrrow->local = aggrrow->local || userow->local;
    3497
    3498 /* ensure the array for storing the row information is large enough */
    3499 i = aggrrow->nrows++;
    3500 *rowused = TRUE;
    3501 if( aggrrow->nrows > aggrrow->rowssize )
    3502 {
    3503 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
    3504 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
    3505 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
    3506 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
    3507 aggrrow->rowssize = newsize;
    3508 }
    3509
    3510 /* add information of addditional row */
    3511 aggrrow->rowsinds[i] = row->lppos;
    3512 aggrrow->rowweights[i] = weight;
    3513 aggrrow->slacksign[i] = uselhs ? -1 : 1;
    3514
    3515 /* add up coefficients */
    3516 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, aggrrow->inds, aggrrow->vals, &aggrrow->nnz, userow, weight, &sidevalchg, success) );
    3517
    3518 sidevalchg += QUAD_TO_DBL(aggrrow->rhs);
    3519 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
    3520
    3521 /* check if row is too long now */
    3522 if( aggrrow->nnz > maxaggrlen )
    3523 *rowtoolong = TRUE;
    3524
    3525 SCIPintervalSetRoundingMode(previousroundmode);
    3526
    3527 return SCIP_OKAY;
    3528}
    3529
    3530/** aggregate rows using the given weights; the current content of the aggregation row, \p aggrrow, is overwritten
    3531 *
    3532 * @note this method is safe for usage in exact solving mode
    3533 */
    3535 SCIP* scip, /**< SCIP data structure */
    3536 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3537 SCIP_Real* weights, /**< row weights in row summation */
    3538 int* rowinds, /**< array to store indices of non-zero entries of the weights array, or NULL */
    3539 int nrowinds, /**< number of non-zero entries in weights array, -1 if rowinds is NULL */
    3540 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
    3541 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
    3542 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
    3543 int maxaggrlen, /**< maximal length of aggregation row */
    3544 SCIP_Bool* valid /**< is the aggregation valid */
    3545 )
    3546{
    3547 SCIP_AGGRROW* certificaterow = NULL;
    3548 SCIP_ROW** rows;
    3549 SCIP_ROW** usedrows = NULL;
    3550 SCIP_ROW** negslackrows = NULL;
    3551 SCIP_VAR** vars;
    3552 SCIP_Real* usedweights = NULL;
    3553 SCIP_Real* negslackweights = NULL;
    3554 int nrows;
    3555 int nvars;
    3556 int k;
    3557 int nusedrows;
    3558 int nnegslackrows;
    3559 SCIP_Bool rowtoolong;
    3560 SCIP_Bool rowused, rowusedcert, lhsused;
    3561
    3562 assert( scip != NULL );
    3563 assert( aggrrow != NULL );
    3564 assert( valid != NULL );
    3565
    3566 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    3567 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
    3568
    3569 if( SCIPisExact(scip) )
    3570 SCIPaggrRowClearSafely(aggrrow);
    3571 else
    3572 SCIPaggrRowClear(aggrrow);
    3573 *valid = TRUE;
    3574 lhsused = FALSE;
    3575 nusedrows = 0;
    3576 nnegslackrows = 0;
    3577
    3578 SCIPdebugMessage("Summing up %d rows in aggrrow \n", nrowinds);
    3579
    3580 if( SCIPisCertified(scip) )
    3581 {
    3582 SCIP_CALL( SCIPallocBufferArray(scip, &usedrows, nrows) );
    3583 SCIP_CALL( SCIPallocBufferArray(scip, &usedweights, nrows) );
    3584 SCIP_CALL( SCIPallocBufferArray(scip, &negslackrows, nrows) );
    3585 SCIP_CALL( SCIPallocBufferArray(scip, &negslackweights, nrows) );
    3586 SCIP_CALL( SCIPaggrRowCreate(scip, &certificaterow) );
    3587 }
    3588
    3589 if( rowinds != NULL && nrowinds > -1 )
    3590 {
    3591 for( k = 0; k < nrowinds; ++k )
    3592 {
    3593 if( !SCIPisExact(scip) )
    3594 {
    3595 SCIP_CALL( addOneRow(scip, aggrrow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
    3596
    3597 if( rowtoolong )
    3598 *valid = FALSE;
    3599 }
    3600 else /*lint --e{644}*/
    3601 {
    3602 SCIPdebugMessage("Adding %g times row: ", weights[rowinds[k]]);
    3603 SCIPdebug(SCIPprintRow(scip, rows[rowinds[k]], NULL));
    3604 SCIP_CALL( addOneRowSafely(scip, aggrrow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis, allowlocal,
    3605 negslack, maxaggrlen, &rowtoolong, &rowused, valid, &lhsused) );
    3606
    3607 if( rowtoolong )
    3608 *valid = FALSE;
    3609
    3610 if( !(*valid) )
    3611 break;
    3612
    3613 if( certificaterow != NULL )
    3614 {
    3615 assert(usedrows != NULL);
    3616 assert(usedweights != NULL);
    3617 assert(negslackrows != NULL);
    3618 assert(negslackweights != NULL);
    3619
    3620 SCIP_ROW* row = rows[rowinds[k]];
    3621 SCIP_Bool integral = FALSE;
    3622
    3623 /* just exclude the negative continuous slacks for the certificate rows */
    3624 if( row->integral &&
    3625 ((!lhsused && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant)) ||
    3627 {
    3628 SCIPdebugMessage("row has integral slack\n");
    3629 rowusedcert = FALSE;
    3630 integral = TRUE;
    3631 }
    3632 else
    3633 {
    3634 /* the certificate row may exceed the limit maxaggrlen */
    3635 SCIP_CALL( addOneRowSafely(scip, certificaterow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis,
    3636 allowlocal, 0, nvars, &rowtoolong, &rowusedcert, valid, &lhsused) );
    3637 assert(!rowtoolong);
    3638 }
    3639 if( rowusedcert )
    3640 {
    3641 usedrows[nusedrows] = rows[rowinds[k]];
    3642 usedweights[nusedrows] = weights[rowinds[k]];
    3643 nusedrows++;
    3644 }
    3645 if( rowused && !rowusedcert && !integral )
    3646 {
    3647 SCIPdebugMessage("row has negative continous slack\n");
    3648 assert( (lhsused && weights[rowinds[k]] >= 0) || ((!lhsused) && weights[rowinds[k]] <= 0) || row->integral );
    3649 negslackrows[nnegslackrows] = rows[rowinds[k]];
    3650 negslackweights[nnegslackrows] = -weights[rowinds[k]];
    3651 nnegslackrows++;
    3652 }
    3653 }
    3654 }
    3655
    3656 if( !(*valid) )
    3657 break;
    3658 }
    3659 }
    3660 else
    3661 {
    3662 for( k = 0; k < nrows; ++k )
    3663 {
    3664 if( weights[k] != 0.0 )
    3665 {
    3666 if( !SCIPisExact(scip) )
    3667 {
    3668 SCIP_CALL( addOneRow(scip, aggrrow, rows[k], weights[k], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
    3669
    3670 if( rowtoolong )
    3671 *valid = FALSE;
    3672 }
    3673 else
    3674 {
    3675 SCIPdebugMessage("Adding %g times row: ", weights[k]);
    3676 SCIPdebug(SCIPprintRow(scip, rows[k], NULL));
    3677 SCIP_CALL( addOneRowSafely(scip, aggrrow, rows[k], weights[k], sidetypebasis, allowlocal, negslack,
    3678 maxaggrlen, &rowtoolong, &rowused, valid, &lhsused) );
    3679
    3680 if( rowtoolong )
    3681 *valid = FALSE;
    3682
    3683 if( !(*valid) )
    3684 break;
    3685
    3686 if( certificaterow != NULL )
    3687 {
    3688 assert(usedrows != NULL);
    3689 assert(usedweights != NULL);
    3690 assert(negslackrows != NULL);
    3691 assert(negslackweights != NULL);
    3692
    3693 SCIP_ROW* row = rows[k];
    3694 SCIP_Bool integral = FALSE;
    3695
    3696 /* just exclude the negative continuous slacks for the certificate rows */
    3697 if( row->integral &&
    3698 ((!lhsused && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant)) ||
    3700 {
    3701 rowusedcert = FALSE;
    3702 SCIPdebugMessage("row has integral slack\n");
    3703 integral = TRUE;
    3704 }
    3705 else
    3706 {
    3707 /* the certificate row may exceed the limit maxaggrlen */
    3708 SCIP_CALL( addOneRowSafely(scip, certificaterow, rows[k], weights[k], sidetypebasis, allowlocal, 0,
    3709 nvars, &rowtoolong, &rowusedcert, valid, &lhsused) );
    3710 assert(!rowtoolong);
    3711 }
    3712 if( rowusedcert )
    3713 {
    3714 usedrows[nusedrows] = rows[k];
    3715 usedweights[nusedrows] = weights[k];
    3716 nusedrows++;
    3717 }
    3718 if( rowused && !rowusedcert && !integral )
    3719 {
    3720 SCIPdebugMessage("row has negative continous slack\n");
    3721 assert( (lhsused && weights[k] >= 0) || ((!lhsused) && weights[k] <= 0) || row->integral );
    3722 negslackrows[nnegslackrows] = rows[k];
    3723 negslackweights[nnegslackrows] = -weights[k];
    3724 nnegslackrows++;
    3725 }
    3726 }
    3727 }
    3728
    3729 if( !(*valid) )
    3730 break;
    3731 }
    3732 }
    3733 }
    3734
    3735 if( *valid )
    3736 {
    3737 SCIPaggrRowRemoveZeros(scip, aggrrow, FALSE, valid);
    3738
    3739 if( certificaterow != NULL )
    3740 {
    3741 SCIPaggrRowRemoveZeros(scip, certificaterow, FALSE, valid);
    3742 SCIP_CALL( SCIPaddCertificateAggrInfo(scip, certificaterow, usedrows, usedweights, certificaterow->nrows,
    3743 negslackrows, negslackweights, nnegslackrows) );
    3744 }
    3745 }
    3746
    3747 if( certificaterow != NULL )
    3748 {
    3749 SCIPaggrRowFree(scip, &certificaterow);
    3750 SCIPfreeBufferArray(scip, &negslackweights);
    3751 SCIPfreeBufferArray(scip, &negslackrows);
    3752 SCIPfreeBufferArray(scip, &usedweights);
    3753 SCIPfreeBufferArray(scip, &usedrows);
    3754 }
    3755
    3756 return SCIP_OKAY;
    3757}
    3758
    3759/** checks for cut redundancy and performs activity based coefficient tightening;
    3760 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
    3761 * to remove small coefficients (relative to the maximum absolute coefficient)
    3762 */
    3763static
    3765 SCIP* scip, /**< SCIP data structure */
    3766 SCIP_Bool cutislocal, /**< is the cut a local cut */
    3767 int* cutinds, /**< variable problem indices of non-zeros in cut */
    3768 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
    3769 int* nnz, /**< number non-zeros coefficients of cut */
    3770 SCIP_Real* cutrhs, /**< right hand side of cut */
    3771 SCIP_Bool* success /**< pointer to return whether post-processing was successful or cut is redundant */
    3772 )
    3773{
    3774 int i;
    3775 SCIP_Bool redundant;
    3776 SCIP_Real maxcoef;
    3777 SCIP_Real minallowedcoef;
    3778 SCIP_Real QUAD(rhs);
    3779
    3780 assert(scip != NULL);
    3781 assert(cutinds != NULL);
    3782 assert(cutcoefs != NULL);
    3783 assert(cutrhs != NULL);
    3784 assert(success != NULL);
    3785
    3786 *success = FALSE;
    3787
    3788 QUAD_ASSIGN(rhs, *cutrhs);
    3789
    3790 if( removeZeros(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz) )
    3791 {
    3792 /* right hand side was changed to infinity -> cut is redundant */
    3793 return SCIP_OKAY;
    3794 }
    3795
    3796 if( *nnz == 0 )
    3797 return SCIP_OKAY;
    3798
    3799 SCIP_CALL( cutTightenCoefs(scip, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz, &redundant) );
    3800
    3801 if( redundant )
    3802 {
    3803 /* cut is redundant */
    3804 return SCIP_OKAY;
    3805 }
    3806
    3807 maxcoef = 0.0;
    3808 for( i = 0; i < *nnz; ++i )
    3809 {
    3810 SCIP_Real absval = REALABS(cutcoefs[cutinds[i]]);
    3811 maxcoef = MAX(absval, maxcoef);
    3812 }
    3813
    3814 maxcoef /= scip->set->sepa_maxcoefratio;
    3815 minallowedcoef = SCIPsumepsilon(scip);
    3816 minallowedcoef = MAX(minallowedcoef, maxcoef);
    3817
    3818 *success = ! removeZeros(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz);
    3819 *cutrhs = QUAD_TO_DBL(rhs);
    3820
    3821 return SCIP_OKAY;
    3822}
    3823
    3824
    3825/** checks for cut redundancy and performs activity based coefficient tightening;
    3826 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
    3827 * to remove small coefficients (relative to the maximum absolute coefficient).
    3828 * The cutcoefs must be a quad precision array, i.e. allocated with size
    3829 * QUAD_ARRAY_SIZE(nvars) and accessed with QUAD_ARRAY_LOAD and QUAD_ARRAY_STORE
    3830 * macros.
    3831 */
    3832static
    3834 SCIP* scip, /**< SCIP data structure */
    3835 SCIP_Bool cutislocal, /**< is the cut a local cut */
    3836 int* cutinds, /**< variable problem indices of non-zeros in cut */
    3837 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
    3838 int* nnz, /**< number non-zeros coefficients of cut */
    3839 QUAD(SCIP_Real* cutrhs), /**< right hand side of cut */
    3840 SCIP_Bool* success /**< pointer to return whether the cleanup was successful or if it is useless */
    3841 )
    3842{
    3843 int i;
    3844 SCIP_Bool redundant;
    3845 SCIP_Real maxcoef;
    3846 SCIP_Real minallowedcoef;
    3847
    3848 assert(scip != NULL);
    3849 assert(cutinds != NULL);
    3850 assert(cutcoefs != NULL);
    3851 assert(QUAD_HI(cutrhs) != NULL);
    3852 assert(success != NULL);
    3853
    3854 *success = FALSE;
    3855
    3856 if( removeZerosQuad(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz) )
    3857 {
    3858 /* right hand side was changed to infinity -> cut is redundant */
    3859 return SCIP_OKAY;
    3860 }
    3861
    3862 if( *nnz == 0 )
    3863 return SCIP_OKAY;
    3864
    3865 SCIP_CALL( cutTightenCoefsQuad(scip, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz, &redundant) );
    3866 if( redundant )
    3867 {
    3868 /* cut is redundant */
    3869 return SCIP_OKAY;
    3870 }
    3871
    3872 maxcoef = 0.0;
    3873 for( i = 0; i < *nnz; ++i )
    3874 {
    3875 SCIP_Real abscoef;
    3876 SCIP_Real QUAD(coef);
    3877 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]); /* coef = cutcoefs[cutinds[i]] */
    3878 abscoef = REALABS(QUAD_TO_DBL(coef));
    3879 maxcoef = MAX(abscoef, maxcoef);
    3880 }
    3881
    3882 maxcoef /= scip->set->sepa_maxcoefratio;
    3883 minallowedcoef = SCIPsumepsilon(scip);
    3884 minallowedcoef = MAX(minallowedcoef, maxcoef);
    3885
    3886 *success = ! removeZerosQuad(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz);
    3887
    3888 return SCIP_OKAY;
    3889}
    3890
    3891/** checks for cut redundancy and performs activity based coefficient tightening;
    3892 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
    3893 * to remove small coefficients (relative to the maximum absolute coefficient).
    3894 * The cutcoefs must be a quad precision array, i.e. allocated with size
    3895 * QUAD_ARRAY_SIZE(nvars) and accessed with QUAD_ARRAY_LOAD and QUAD_ARRAY_STORE
    3896 * macros.
    3897 */
    3898static
    3900 SCIP* scip, /**< SCIP data structure */
    3901 SCIP_Bool cutislocal, /**< is the cut a local cut */
    3902 int* cutinds, /**< variable problem indices of non-zeros in cut */
    3903 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
    3904 int* nnz, /**< number non-zeros coefficients of cut */
    3905 SCIP_Real* cutrhs, /**< right hand side of cut */
    3906 SCIP_Bool* success /**< pointer to return whether the cleanup was successful or if it is useless */
    3907 )
    3908{
    3909 int i;
    3910 SCIP_Bool redundant;
    3911 SCIP_Real maxcoef;
    3912 SCIP_Real minallowedcoef;
    3913
    3914 assert(SCIPisExact(scip));
    3915
    3916 assert(scip != NULL);
    3917 assert(cutinds != NULL);
    3918 assert(cutcoefs != NULL);
    3919 assert(cutrhs != NULL);
    3920 assert(success != NULL);
    3921
    3922 *success = FALSE;
    3923
    3924 if( removeZerosSafely(scip, SCIPfeastol(scip), cutcoefs, cutrhs, cutinds, nnz) )
    3925 {
    3926 /* right hand side was changed to infinity -> cut is redundant */
    3927 return SCIP_OKAY;
    3928 }
    3929
    3930 if( *nnz == 0 )
    3931 return SCIP_OKAY;
    3932
    3933 SCIP_CALL( cutTightenCoefsSafely(scip, cutislocal, cutcoefs, cutrhs, cutinds, nnz, &redundant) );
    3934 if( redundant )
    3935 {
    3936 /* cut is redundant */
    3937 return SCIP_OKAY;
    3938 }
    3939
    3940 maxcoef = 0.0;
    3941 for( i = 0; i < *nnz; ++i )
    3942 {
    3943 SCIP_Real abscoef;
    3944 SCIP_Real coef;
    3945 coef = cutcoefs[cutinds[i]];
    3946 abscoef = REALABS(coef);
    3947 maxcoef = MAX(abscoef, maxcoef);
    3948 }
    3949
    3950 maxcoef /= scip->set->sepa_maxcoefratio;
    3951 minallowedcoef = SCIPsumepsilon(scip);
    3952 minallowedcoef = MAX(minallowedcoef, maxcoef);
    3953
    3954 *success = ! removeZerosSafely(scip, minallowedcoef, cutcoefs, cutrhs, cutinds, nnz);
    3955
    3956 return SCIP_OKAY;
    3957}
    3958
    3959/** removes almost zero entries from the aggregation row. */
    3961 SCIP* scip, /**< SCIP datastructure */
    3962 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3963 SCIP_Bool useglbbounds, /**< consider global bound although the cut is local? */
    3964 SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
    3965 )
    3966{
    3967 assert(aggrrow != NULL);
    3968 assert(valid != NULL);
    3969
    3970 if( SCIPisExact(scip) )
    3971 {
    3972 SCIP_Real rhs;
    3973 rhs = QUAD_TO_DBL(aggrrow->rhs);
    3974 *valid = !removeZerosSafely(scip, SCIPsumepsilon(scip), aggrrow->vals, &rhs, aggrrow->inds, &aggrrow->nnz);
    3975 QUAD_ASSIGN(aggrrow->rhs, rhs);
    3976 return;
    3977 }
    3978
    3979 *valid = ! removeZerosQuad(scip, SCIPsumepsilon(scip), useglbbounds ? FALSE : aggrrow->local, aggrrow->vals,
    3980 QUAD(&aggrrow->rhs), aggrrow->inds, &aggrrow->nnz);
    3981}
    3982
    3983/** get number of aggregated rows */
    3985 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    3986 )
    3987{
    3988 assert(aggrrow != NULL);
    3989
    3990 return aggrrow->nrows;
    3991}
    3992
    3993/** get array with lp positions of rows used in aggregation */
    3995 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    3996 )
    3997{
    3998 assert(aggrrow != NULL);
    3999 assert(aggrrow->rowsinds != NULL || aggrrow->nrows == 0);
    4000
    4001 return aggrrow->rowsinds;
    4002}
    4003
    4004/** get array with weights of aggregated rows */
    4006 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    4007 )
    4008{
    4009 assert(aggrrow != NULL);
    4010 assert(aggrrow->rowweights != NULL || aggrrow->nrows == 0);
    4011
    4012 return aggrrow->rowweights;
    4013}
    4014
    4015/** checks whether a given row has been added to the aggregation row */
    4017 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    4018 SCIP_ROW* row /**< row for which it is checked whether it has been added to the aggregation */
    4019 )
    4020{
    4021 int i;
    4022 int rowind;
    4023
    4024 assert(aggrrow != NULL);
    4025 assert(row != NULL);
    4026
    4027 rowind = SCIProwGetLPPos(row);
    4028
    4029 for( i = 0; i < aggrrow->nrows; ++i )
    4030 {
    4031 if( aggrrow->rowsinds[i] == rowind )
    4032 return TRUE;
    4033 }
    4034
    4035 return FALSE;
    4036}
    4037
    4038/** gets the array of corresponding variable problem indices for each non-zero in the aggregation row */
    4040 SCIP_AGGRROW* aggrrow /**< aggregation row */
    4041 )
    4042{
    4043 assert(aggrrow != NULL);
    4044
    4045 return aggrrow->inds;
    4046}
    4047
    4048/** gets the number of non-zeros in the aggregation row */
    4050 SCIP_AGGRROW* aggrrow /**< aggregation row */
    4051 )
    4052{
    4053 assert(aggrrow != NULL);
    4054
    4055 return aggrrow->nnz;
    4056}
    4057
    4058/** gets the rank of the aggregation row */
    4060 SCIP_AGGRROW* aggrrow /**< aggregation row */
    4061 )
    4062{
    4063 assert(aggrrow != NULL);
    4064
    4065 return aggrrow->rank;
    4066}
    4067
    4068/** checks if the aggregation row is only valid locally */
    4070 SCIP_AGGRROW* aggrrow /**< aggregation row */
    4071 )
    4072{
    4073 assert(aggrrow != NULL);
    4074
    4075 return aggrrow->local;
    4076}
    4077
    4078/** gets the right hand side of the aggregation row */
    4080 SCIP_AGGRROW* aggrrow /**< aggregation row */
    4081 )
    4082{
    4083 assert(aggrrow != NULL);
    4084
    4085 return QUAD_TO_DBL(aggrrow->rhs);
    4086}
    4087
    4088/* =========================================== c-MIR =========================================== */
    4089
    4090#define MAXCMIRSCALE 1e+6 /**< maximal scaling (scale/(1-f0)) allowed in c-MIR calculations */
    4091
    4092/* In order to derive cuts, we partition the variable array up in (not necessarily contiguous) sections.
    4093 * The only requirement we place on these sections is that section i can only have variable bounds variables whose section
    4094 * is strictly greater than i. This way, we can process the variable array in a 'linear' manner. */
    4095
    4096/* @todo maintain a DAG for used varbounds and use topological ordering instead, this would also allow
    4097 * variable bounds on variables of the same section to be used */
    4098
    4099#define NSECTIONS 6
    4100
    4101typedef struct MIR_Data
    4102{
    4103 int totalnnz; /* The total number of nonzeros in all of the sections */
    4104 int* secindices[NSECTIONS]; /* The indices of the variables belonging to the section */
    4105 int secnnz[NSECTIONS]; /* The number of nonzero indices in the section */
    4106
    4107 SCIP_Bool isenfint[NSECTIONS];/**< Does the section have an integrality constraint? */
    4108 SCIP_Bool isimplint[NSECTIONS];/**< Is the section implied integer variables? */
    4109
    4110 /* Settings for cut derivation, per section */
    4111 int usevbds[NSECTIONS]; /**< Should variable bound substitution be done for this section? */
    4112
    4113 /* Problem data that we reuse often */
    4114 SCIP_VAR** vars; /**< pointer to SCIPs variable array */
    4115 int nvars; /**< total number of variables */
    4116 int nbinvars; /**< total number of non-implint binary variables */
    4117 int nintvars; /**< total number of non-implint integer variables */
    4118 int nbinimplvars; /**< total number of implint binary variables */
    4119 int nintimplvars; /**< total number of implint integer variables */
    4120 int ncontimplvars; /**< total number of implint continuous variables */
    4121 int ncontvars; /**< total number of non-implied continuous variables */
    4122
    4123 SCIP_Real* cutcoefs; /**< working cut indices value array */
    4124 SCIP_Real QUAD(cutrhs); /**< the working right hand side of the cut*/
    4125
    4126 int* cutinds; /**< working cut variable problem index array */
    4127 int ncutinds; /**< number of values in the working cut variable problem index array */
    4129
    4130/** Returns the section of a variable.
    4131 *
    4132 * For now, this is equal to the variable type section of the variable in the problem.
    4133 */
    4134static
    4136 MIR_DATA* data, /**< The MIR separation data */
    4137 int probindex /**< Problem index of a variable */
    4138 )
    4139{
    4140 int limit;
    4141
    4142 assert(data != NULL);
    4143
    4144 limit = data->nvars - data->ncontvars;
    4145 if( probindex >= limit )
    4146 return 0;
    4147
    4148 limit -= data->ncontimplvars;
    4149 if( probindex >= limit )
    4150 return 1;
    4151
    4152 limit -= data->nintimplvars;
    4153 if( probindex >= limit )
    4154 return 2;
    4155
    4156 limit -= data->nbinimplvars;
    4157 if( probindex >= limit )
    4158 return 3;
    4159
    4160 limit -= data->nintvars;
    4161 if( probindex >= limit )
    4162 return 4;
    4163
    4164 assert(limit == data->nbinvars);
    4165
    4166 return 5;
    4167}
    4168
    4169/** finds the best lower bound of the variable to use for MIR transformation.
    4170 *
    4171 * Currently, we use a slightly different function for the exact MIR cuts than for the normal MIR cuts due to differences
    4172 * in how the codes can handle variable bound substitution. This function can only be used with the safe MIR code. */
    4173/* @todo make behavior identical to the unsafe MIR cut computation */
    4174static
    4176 SCIP* scip, /**< SCIP data structure */
    4177 SCIP_VAR* var, /**< problem variable */
    4178 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4179 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4180 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4181 SCIP_Real* bestlb, /**< pointer to store best bound value */
    4182 SCIP_Real* simplebound, /**< pointer to store simple bound value */
    4183 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4184 )
    4185{
    4186 assert(bestlb != NULL);
    4187 assert(bestlbtype != NULL);
    4188 assert(usevbds >= 0 && usevbds <= 2);
    4189
    4190 *bestlb = SCIPvarGetLbGlobal(var);
    4191 *bestlbtype = -1;
    4192
    4193 if( allowlocal )
    4194 {
    4195 SCIP_Real loclb;
    4196
    4197 loclb = SCIPvarGetLbLocal(var);
    4198 if( SCIPisGT(scip, loclb, *bestlb) )
    4199 {
    4200 *bestlb = loclb;
    4201 *bestlbtype = -2;
    4202 }
    4203 }
    4204
    4205 *simplebound = *bestlb;
    4206
    4207 if( usevbds && !SCIPvarIsIntegral(var) )
    4208 {
    4209 SCIP_Real bestvlb;
    4210 int bestvlbidx;
    4211
    4212 SCIP_CALL( SCIPgetVarClosestVlb(scip, var, sol, &bestvlb, &bestvlbidx) );
    4213 if( bestvlbidx >= 0 && (bestvlb > *bestlb || (*bestlbtype < 0 && SCIPisGE(scip, bestvlb, *bestlb))) )
    4214 {
    4215 SCIP_VAR** vlbvars;
    4216 SCIP_VAR* vlbvar;
    4217
    4218 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
    4219 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
    4220 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
    4221 */
    4222 vlbvars = SCIPvarGetVlbVars(var);
    4223 assert(vlbvars != NULL);
    4224 vlbvar = vlbvars[bestvlbidx];
    4225 assert(vlbvar != NULL);
    4226 if( ( usevbds == 2 || ( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY
    4227 && !SCIPvarIsImpliedIntegral(vlbvar) ) )
    4228 && SCIPvarGetProbindex(vlbvar) < SCIPvarGetProbindex(var) )
    4229 {
    4230 *bestlb = bestvlb;
    4231 *bestlbtype = bestvlbidx;
    4232 }
    4233 }
    4234 }
    4235
    4236 return SCIP_OKAY;
    4237}
    4238
    4239/** finds the best upper bound of the variable to use for MIR transformation.
    4240 * currently, we use a slightly different function for the exact MIR cuts than for the normal MIR cuts due to differences
    4241 * in how the codes can handle variable bound substitution. This function can only be used with the safe MIR code. */
    4242/* @todo make behavior identical to the unsafe MIR cut computation */
    4243static
    4245 SCIP* scip, /**< SCIP data structure */
    4246 SCIP_VAR* var, /**< problem variable */
    4247 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4248 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4249 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4250 SCIP_Real* bestub, /**< pointer to store best bound value */
    4251 SCIP_Real* simplebound, /**< pointer to store simple bound */
    4252 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4253 )
    4254{
    4255 assert(bestub != NULL);
    4256 assert(bestubtype != NULL);
    4257
    4258 *bestub = SCIPvarGetUbGlobal(var);
    4259 *bestubtype = -1;
    4260
    4261 if( allowlocal )
    4262 {
    4263 SCIP_Real locub;
    4264
    4265 locub = SCIPvarGetUbLocal(var);
    4266 if( SCIPisLT(scip, locub, *bestub) )
    4267 {
    4268 *bestub = locub;
    4269 *bestubtype = -2;
    4270 }
    4271 }
    4272
    4273 *simplebound = *bestub;
    4274
    4275 if( usevbds && !SCIPvarIsIntegral(var) )
    4276 {
    4277 SCIP_Real bestvub;
    4278 int bestvubidx;
    4279
    4280 SCIP_CALL( SCIPgetVarClosestVub(scip, var, sol, &bestvub, &bestvubidx) );
    4281 if( bestvubidx >= 0 && (bestvub < *bestub || (*bestubtype < 0 && SCIPisLE(scip, bestvub, *bestub))) )
    4282 {
    4283 SCIP_VAR** vubvars;
    4284 SCIP_VAR* vubvar;
    4285
    4286 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
    4287 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
    4288 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
    4289 */
    4290 vubvars = SCIPvarGetVubVars(var);
    4291 assert(vubvars != NULL);
    4292 vubvar = vubvars[bestvubidx];
    4293 assert(vubvar != NULL);
    4294 if( ( usevbds == 2 || ( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY
    4295 && !SCIPvarIsImpliedIntegral(vubvar) ) )
    4296 && SCIPvarGetProbindex(vubvar) < SCIPvarGetProbindex(var) )
    4297 {
    4298 *bestub = bestvub;
    4299 *bestubtype = bestvubidx;
    4300 }
    4301 }
    4302 }
    4303
    4304 return SCIP_OKAY;
    4305}
    4306
    4307/** determine the best bounds with respect to the given solution for complementing the given variable */
    4308/* @todo make behavior identical to the unsafe MIR cut computation */
    4309static
    4311 SCIP* scip, /**< SCIP data structure */
    4312 SCIP_VAR* var, /**< variable to determine best bound for */
    4313 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4314 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    4315 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4316 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4317 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    4318 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
    4319 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    4320 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    4321 * NULL for using closest bound for all variables */
    4322 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    4323 * NULL for using closest bound for all variables */
    4324 SCIP_Real* bestlb, /**< pointer to store best lower bound of variable */
    4325 SCIP_Real* bestub, /**< pointer to store best upper bound of variable */
    4326 int* bestlbtype, /**< pointer to store type of the best lower bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4327 int* bestubtype, /**< pointer to store type of best upper bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4328 SCIP_BOUNDTYPE* selectedbound, /**< pointer to store whether the lower bound or the upper bound should be preferred */
    4329 SCIP_Bool* freevariable /**< pointer to store if this is a free variable */
    4330 )
    4331{
    4332 SCIP_Real simplelb;
    4333 SCIP_Real simpleub;
    4334 int v;
    4335
    4336 v = SCIPvarGetProbindex(var);
    4337
    4338 /* check if the user specified a bound to be used */
    4339 if( boundsfortrans != NULL && boundsfortrans[v] > -3 )
    4340 {
    4341 assert(!SCIPvarIsIntegral(var) || boundsfortrans[v] == -2 || boundsfortrans[v] == -1);
    4342 assert(boundtypesfortrans != NULL);
    4343
    4344 /* user has explicitly specified a bound to be used */
    4345 if( boundtypesfortrans[v] == SCIP_BOUNDTYPE_LOWER )
    4346 {
    4347 /* user wants to use lower bound */
    4348 *bestlbtype = boundsfortrans[v];
    4349 if( *bestlbtype == -1 )
    4350 *bestlb = SCIPvarGetLbGlobal(var); /* use global standard lower bound */
    4351 else if( *bestlbtype == -2 )
    4352 *bestlb = SCIPvarGetLbLocal(var); /* use local standard lower bound */
    4353 else
    4354 {
    4355 SCIP_VAR** vlbvars;
    4356 SCIP_Real* vlbcoefs;
    4357 SCIP_Real* vlbconsts;
    4358 int k;
    4359
    4360 assert(!ignoresol);
    4361
    4362 /* use the given variable lower bound */
    4363 vlbvars = SCIPvarGetVlbVars(var);
    4364 vlbcoefs = SCIPvarGetVlbCoefs(var);
    4365 vlbconsts = SCIPvarGetVlbConstants(var);
    4366 k = boundsfortrans[v];
    4367 assert(k >= 0 && k < SCIPvarGetNVlbs(var));
    4368 assert(vlbvars != NULL);
    4369 assert(vlbcoefs != NULL);
    4370 assert(vlbconsts != NULL);
    4371
    4372 *bestlb = vlbcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[k]) : SCIPgetSolVal(scip, sol, vlbvars[k])) + vlbconsts[k];
    4373 }
    4374
    4375 assert(!SCIPisInfinity(scip, - *bestlb));
    4376 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4377
    4378 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
    4379 SCIP_CALL( findBestUbSafely(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestub, &simpleub, bestubtype) );
    4380 }
    4381 else
    4382 {
    4383 assert(boundtypesfortrans[v] == SCIP_BOUNDTYPE_UPPER);
    4384
    4385 /* user wants to use upper bound */
    4386 *bestubtype = boundsfortrans[v];
    4387 if( *bestubtype == -1 )
    4388 *bestub = SCIPvarGetUbGlobal(var); /* use global standard upper bound */
    4389 else if( *bestubtype == -2 )
    4390 *bestub = SCIPvarGetUbLocal(var); /* use local standard upper bound */
    4391 else
    4392 {
    4393 SCIP_VAR** vubvars;
    4394 SCIP_Real* vubcoefs;
    4395 SCIP_Real* vubconsts;
    4396 int k;
    4397
    4398 assert(!ignoresol);
    4399
    4400 /* use the given variable upper bound */
    4401 vubvars = SCIPvarGetVubVars(var);
    4402 vubcoefs = SCIPvarGetVubCoefs(var);
    4403 vubconsts = SCIPvarGetVubConstants(var);
    4404 k = boundsfortrans[v];
    4405 assert(k >= 0 && k < SCIPvarGetNVubs(var));
    4406 assert(vubvars != NULL);
    4407 assert(vubcoefs != NULL);
    4408 assert(vubconsts != NULL);
    4409
    4410 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
    4411 *bestub = vubcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vubvars[k]) : SCIPgetSolVal(scip, sol, vubvars[k])) + vubconsts[k];
    4412 }
    4413
    4414 assert(!SCIPisInfinity(scip, *bestub));
    4415 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4416
    4417 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
    4418 SCIP_CALL( findBestLbSafely(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestlb, &simplelb, bestlbtype) );
    4419 }
    4420 }
    4421 else
    4422 {
    4423 SCIP_Real varsol;
    4424
    4425 /* bound selection should be done automatically */
    4426
    4427 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
    4428 SCIP_CALL( findBestLbSafely(scip, var, sol, usevbds, allowlocal, bestlb, &simplelb, bestlbtype) );
    4429
    4430 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
    4431 SCIP_CALL( findBestUbSafely(scip, var, sol, usevbds, allowlocal, bestub, &simpleub, bestubtype) );
    4432
    4433 /* check, if variable is free variable */
    4434 if( SCIPisInfinity(scip, - *bestlb) && SCIPisInfinity(scip, *bestub) )
    4435 {
    4436 /* we found a free variable in the row with non-zero coefficient
    4437 * -> MIR row can't be transformed in standard form
    4438 */
    4439 *freevariable = TRUE;
    4440 return SCIP_OKAY;
    4441 }
    4442
    4443 if( !ignoresol )
    4444 {
    4445 /* select transformation bound */
    4446 varsol = (sol == NULL ? SCIPvarGetLPSol(var) : SCIPgetSolVal(scip, sol, var));
    4447
    4448 if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
    4449 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4450 else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
    4451 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4452 else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
    4453 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4454 else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
    4455 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4456 else if( *bestlbtype == -1 ) /* prefer global standard bounds */
    4457 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4458 else if( *bestubtype == -1 ) /* prefer global standard bounds */
    4459 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4460 else if( ((*bestlbtype) >= 0 || (*bestubtype) >= 0) && !SCIPisEQ(scip, *bestlb - simplelb, simpleub - *bestub) )
    4461 {
    4462 if( *bestlb - simplelb > simpleub - *bestub )
    4463 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4464 else
    4465 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4466 }
    4467 else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
    4468 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4469 else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
    4470 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4471 else /* no decision yet? just use lower bound */
    4472 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4473 }
    4474 else
    4475 {
    4476 SCIP_Real glbub = SCIPvarGetUbGlobal(var);
    4477 SCIP_Real glblb = SCIPvarGetLbGlobal(var);
    4478 SCIP_Real distlb = REALABS(glblb - *bestlb);
    4479 SCIP_Real distub = REALABS(glbub - *bestub);
    4480
    4481 assert(!SCIPisInfinity(scip, - *bestlb) || !SCIPisInfinity(scip, *bestub));
    4482
    4483 if( SCIPisInfinity(scip, - *bestlb) )
    4484 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4485 else if( !SCIPisNegative(scip, *bestlb) )
    4486 {
    4487 if( SCIPisInfinity(scip, *bestub) )
    4488 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4489 else if( SCIPisZero(scip, glblb) )
    4490 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4491 else if( SCIPisLE(scip, distlb, distub) )
    4492 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4493 else
    4494 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4495 }
    4496 else
    4497 {
    4498 assert(!SCIPisInfinity(scip, - *bestlb));
    4499 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4500 }
    4501 }
    4502 }
    4503
    4504 return SCIP_OKAY; /*lint !e438*/
    4505}
    4506
    4507/** finds the best lower bound of the variable to use for MIR transformation */
    4508static
    4510 SCIP* scip, /**< SCIP data structure */
    4511 SCIP_VAR* var, /**< problem variable */
    4512 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4513 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4514 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4515 SCIP_Real* bestlb, /**< pointer to store best bound value */
    4516 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4517 )
    4518{
    4519 assert(bestlb != NULL);
    4520 assert(bestlbtype != NULL);
    4521 assert(usevbds >= 0 && usevbds <= 2);
    4522
    4523 *bestlb = SCIPvarGetLbGlobal(var);
    4524 *bestlbtype = -1;
    4525
    4526 if( allowlocal )
    4527 {
    4528 SCIP_Real loclb;
    4529
    4530 loclb = SCIPvarGetLbLocal(var);
    4531 if( SCIPisGT(scip, loclb, *bestlb) )
    4532 {
    4533 *bestlb = loclb;
    4534 *bestlbtype = -2;
    4535 }
    4536 }
    4537
    4538 if( usevbds > 0 )
    4539 {
    4540 SCIP_Real bestvlb;
    4541 int bestvlbidx;
    4542
    4543 SCIP_CALL( SCIPgetVarClosestVlb(scip, var, sol, &bestvlb, &bestvlbidx) );
    4544 if( bestvlbidx >= 0 && (bestvlb > *bestlb || (*bestlbtype < 0 && SCIPisGE(scip, bestvlb, *bestlb))) )
    4545 {
    4546 SCIP_VAR** vlbvars;
    4547 SCIP_VAR* vlbvar;
    4548
    4549 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
    4550 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
    4551 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
    4552 */
    4553 vlbvars = SCIPvarGetVlbVars(var);
    4554 assert(vlbvars != NULL);
    4555 vlbvar = vlbvars[bestvlbidx];
    4556 assert(vlbvar != NULL);
    4557 if( ( usevbds == 2 || ( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY
    4558 && !SCIPvarIsImpliedIntegral(vlbvar) ) ) )
    4559 {
    4560 assert(SCIPvarGetProbindex(vlbvar) < SCIPvarGetProbindex(var));
    4561 *bestlb = bestvlb;
    4562 *bestlbtype = bestvlbidx;
    4563 }
    4564 }
    4565 }
    4566
    4567 return SCIP_OKAY;
    4568}
    4569
    4570/** finds the best upper bound of the variable to use for MIR transformation */
    4571static
    4573 SCIP* scip, /**< SCIP data structure */
    4574 SCIP_VAR* var, /**< problem variable */
    4575 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4576 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4577 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4578 SCIP_Real* bestub, /**< pointer to store best bound value */
    4579 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4580 )
    4581{
    4582 assert(bestub != NULL);
    4583 assert(bestubtype != NULL);
    4584 assert(usevbds >= 0 && usevbds <= 2);
    4585
    4586 *bestub = SCIPvarGetUbGlobal(var);
    4587 *bestubtype = -1;
    4588
    4589 if( allowlocal )
    4590 {
    4591 SCIP_Real locub;
    4592
    4593 locub = SCIPvarGetUbLocal(var);
    4594 if( SCIPisLT(scip, locub, *bestub) )
    4595 {
    4596 *bestub = locub;
    4597 *bestubtype = -2;
    4598 }
    4599 }
    4600
    4601 if( usevbds > 0 )
    4602 {
    4603 SCIP_Real bestvub;
    4604 int bestvubidx;
    4605
    4606 SCIP_CALL( SCIPgetVarClosestVub(scip, var, sol, &bestvub, &bestvubidx) );
    4607 if( bestvubidx >= 0 && (bestvub < *bestub || (*bestubtype < 0 && SCIPisLE(scip, bestvub, *bestub))) )
    4608 {
    4609 SCIP_VAR** vubvars;
    4610 SCIP_VAR* vubvar;
    4611
    4612 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
    4613 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
    4614 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
    4615 */
    4616 vubvars = SCIPvarGetVubVars(var);
    4617 assert(vubvars != NULL);
    4618 vubvar = vubvars[bestvubidx];
    4619 assert(vubvar != NULL);
    4620 if( ( usevbds == 2 || ( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY
    4621 && !SCIPvarIsImpliedIntegral(vubvar) ) ) )
    4622 {
    4623 assert( SCIPvarGetProbindex(vubvar) < SCIPvarGetProbindex(var) );
    4624 *bestub = bestvub;
    4625 *bestubtype = bestvubidx;
    4626 }
    4627 }
    4628 }
    4629
    4630 return SCIP_OKAY;
    4631}
    4632
    4633
    4634/** finds the best lower bound of the variable to use for MIR transformation.
    4635 * Differs from findBestLB() in that it allows more variable bound substitutions based on the variable sections. */
    4636static
    4638 SCIP* scip, /**< SCIP data structure */
    4639 SCIP_VAR* var, /**< problem variable */
    4640 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4641 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
    4642 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4643 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4644 SCIP_Real* bestlb, /**< pointer to store best bound value */
    4645 SCIP_Real* simplebound, /**< pointer to store simple bound value */
    4646 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4647 )
    4648{
    4649 assert(bestlb != NULL);
    4650 assert(bestlbtype != NULL);
    4651 assert(usevbds >= 0 && usevbds <= 2);
    4652
    4653 *bestlb = SCIPvarGetLbGlobal(var);
    4654 *bestlbtype = -1;
    4655
    4656 if( allowlocal )
    4657 {
    4658 SCIP_Real loclb;
    4659
    4660 loclb = SCIPvarGetLbLocal(var);
    4661 if( SCIPisGT(scip, loclb, *bestlb) )
    4662 {
    4663 *bestlb = loclb;
    4664 *bestlbtype = -2;
    4665 }
    4666 }
    4667
    4668 *simplebound = *bestlb;
    4669
    4670 if( usevbds > 0 )
    4671 {
    4672 int nvlbs = SCIPvarGetNVlbs(var);
    4673
    4674 if( nvlbs > 0 )
    4675 {
    4676 SCIP_Real bestvlb = SCIP_REAL_MIN;
    4677 int bestvlbtype = -1;
    4678 int boundedsection = varSection(data, SCIPvarGetProbindex(var));
    4679
    4680 SCIP_VAR** vlbvars;
    4681 SCIP_Real* vlbcoefs;
    4682 SCIP_Real* vlbconsts;
    4683 int i;
    4684
    4685 vlbvars = SCIPvarGetVlbVars(var);
    4686 vlbcoefs = SCIPvarGetVlbCoefs(var);
    4687 vlbconsts = SCIPvarGetVlbConstants(var);
    4688
    4689 /* search best VLB */
    4690 for( i = 0; i < nvlbs; i++ )
    4691 {
    4692 /* For now, we only allow variable bounds from sections that are strictly greater to prevent cyclic usage.*/
    4693 /** @todo: We don't use the caching mechanism of SCIPvarGetClosestVLB() because the cached variable bound
    4694 * may be illegal. Building a local cache here may be worth it. */
    4695 if( SCIPvarIsActive(vlbvars[i]) && boundedsection < varSection(data, SCIPvarGetProbindex(vlbvars[i])) &&
    4696 (usevbds == 2 || SCIPvarIsBinary(vlbvars[i])) )
    4697 {
    4698 SCIP_Real vlbsol;
    4699 SCIP_Real vlbbnd;
    4700
    4701 vlbsol = SCIPgetSolVal(scip, sol, vlbvars[i]);
    4702 vlbbnd = vlbcoefs[i] * vlbsol + vlbconsts[i];
    4703
    4704 if( vlbbnd > bestvlb )
    4705 {
    4706 bestvlb = vlbbnd;
    4707 bestvlbtype = i;
    4708 }
    4709 }
    4710 }
    4711
    4712 if( bestvlbtype >= 0 && SCIPisGE(scip, bestvlb, *bestlb) )
    4713 {
    4714 *bestlb = bestvlb;
    4715 *bestlbtype = bestvlbtype;
    4716 }
    4717 }
    4718 }
    4719
    4720 return SCIP_OKAY;
    4721}
    4722
    4723/** finds the best upper bound of the variable to use for MIR transformation.
    4724 * Differs from findBestUB() in that it allows more variable bound substitutions based on the variable sections. */
    4725static
    4727 SCIP* scip, /**< SCIP data structure */
    4728 SCIP_VAR* var, /**< problem variable */
    4729 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4730 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
    4731 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4732 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4733 SCIP_Real* bestub, /**< pointer to store best bound value */
    4734 SCIP_Real* simplebound, /**< pointer to store simple bound */
    4735 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4736 )
    4737{
    4738 assert(bestub != NULL);
    4739 assert(bestubtype != NULL);
    4740 assert(usevbds >= 0 && usevbds <= 2);
    4741
    4742 *bestub = SCIPvarGetUbGlobal(var);
    4743 *bestubtype = -1;
    4744
    4745 if( allowlocal )
    4746 {
    4747 SCIP_Real locub;
    4748
    4749 locub = SCIPvarGetUbLocal(var);
    4750 if( SCIPisLT(scip, locub, *bestub) )
    4751 {
    4752 *bestub = locub;
    4753 *bestubtype = -2;
    4754 }
    4755 }
    4756
    4757 *simplebound = *bestub;
    4758
    4759 if( usevbds > 0 )
    4760 {
    4761 int nvubs = SCIPvarGetNVubs(var);
    4762
    4763 if( nvubs > 0 )
    4764 {
    4765 SCIP_Real bestvub = SCIP_REAL_MAX;
    4766 int bestvubtype = -1;
    4767 int boundedsection = varSection(data, SCIPvarGetProbindex(var));
    4768
    4769 SCIP_VAR** vubvars;
    4770 SCIP_Real* vubcoefs;
    4771 SCIP_Real* vubconsts;
    4772 int i;
    4773
    4774 vubvars = SCIPvarGetVubVars(var);
    4775 vubcoefs = SCIPvarGetVubCoefs(var);
    4776 vubconsts = SCIPvarGetVubConstants(var);
    4777
    4778 /* search best VUB */
    4779 for( i = 0; i < nvubs; i++ )
    4780 {
    4781 /* For now, we only allow variable bounds from sections that are strictly greater to prevent cyclic usage.*/
    4782 /** @todo: We don't use the caching mechanism of SCIPvarGetClosestVLB() because the cached variable bound
    4783 * may be illegal. Building a local cache here may be worth it. */
    4784 if( SCIPvarIsActive(vubvars[i]) && boundedsection < varSection(data, SCIPvarGetProbindex(vubvars[i])) &&
    4785 (usevbds == 2 || SCIPvarIsBinary(vubvars[i])) )
    4786 {
    4787 SCIP_Real vubsol;
    4788 SCIP_Real vubbnd;
    4789
    4790 vubsol = SCIPgetSolVal(scip, sol, vubvars[i]);
    4791 vubbnd = vubcoefs[i] * vubsol + vubconsts[i];
    4792
    4793 if( vubbnd < bestvub )
    4794 {
    4795 bestvub = vubbnd;
    4796 bestvubtype = i;
    4797 }
    4798 }
    4799 }
    4800
    4801 if( bestvubtype >= 0 && SCIPisLE(scip, bestvub, *bestub) )
    4802 {
    4803 *bestub = bestvub;
    4804 *bestubtype = bestvubtype;
    4805 }
    4806 }
    4807 }
    4808
    4809 return SCIP_OKAY;
    4810}
    4811
    4812/** determine the best bounds with respect to the given solution for complementing the given variable */
    4813static
    4815 SCIP* scip, /**< SCIP data structure */
    4816 SCIP_VAR* var, /**< variable to determine best bound for */
    4817 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4818 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
    4819 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    4820 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4821 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4822 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    4823 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
    4824 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    4825 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    4826 * NULL for using closest bound for all variables */
    4827 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    4828 * NULL for using closest bound for all variables */
    4829 SCIP_Real* bestlb, /**< pointer to store best lower bound of variable */
    4830 SCIP_Real* bestub, /**< pointer to store best upper bound of variable */
    4831 int* bestlbtype, /**< pointer to store type of best lower bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4832 int* bestubtype, /**< pointer to store type of best upper bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4833 SCIP_BOUNDTYPE* selectedbound, /**< pointer to store whether the lower bound or the upper bound should be preferred */
    4834 SCIP_Bool* freevariable /**< pointer to store if this is a free variable */
    4835 )
    4836{
    4837 SCIP_Real simplelb;
    4838 SCIP_Real simpleub;
    4839 int v;
    4840
    4841 assert(usevbds >= 0 && usevbds <= 2);
    4842
    4843 v = SCIPvarGetProbindex(var);
    4844
    4845 /* check if the user specified a bound to be used */
    4846 if( boundsfortrans != NULL && boundsfortrans[v] > -3 )
    4847 {
    4848 assert(!SCIPvarIsIntegral(var) || boundsfortrans[v] == -2 || boundsfortrans[v] == -1);
    4849 assert(boundtypesfortrans != NULL);
    4850
    4851 /* user has explicitly specified a bound to be used */
    4852 if( boundtypesfortrans[v] == SCIP_BOUNDTYPE_LOWER )
    4853 {
    4854 /* user wants to use lower bound */
    4855 *bestlbtype = boundsfortrans[v];
    4856 if( *bestlbtype == -1 )
    4857 *bestlb = SCIPvarGetLbGlobal(var); /* use global standard lower bound */
    4858 else if( *bestlbtype == -2 )
    4859 *bestlb = SCIPvarGetLbLocal(var); /* use local standard lower bound */
    4860 else
    4861 {
    4862 SCIP_Real vlbsol;
    4863 SCIP_VAR** vlbvars;
    4864 SCIP_Real* vlbcoefs;
    4865 SCIP_Real* vlbconsts;
    4866 int k;
    4867
    4868 assert(!ignoresol);
    4869
    4870 /* use the given variable lower bound */
    4871 vlbvars = SCIPvarGetVlbVars(var);
    4872 vlbcoefs = SCIPvarGetVlbCoefs(var);
    4873 vlbconsts = SCIPvarGetVlbConstants(var);
    4874 k = boundsfortrans[v];
    4875 assert(k >= 0 && k < SCIPvarGetNVlbs(var));
    4876 assert(vlbvars != NULL);
    4877 assert(vlbcoefs != NULL);
    4878 assert(vlbconsts != NULL);
    4879
    4880 vlbsol = SCIPgetSolVal(scip, sol, vlbvars[k]);
    4881
    4882 *bestlb = vlbcoefs[k] * vlbsol + vlbconsts[k];
    4883 }
    4884
    4885 assert(!SCIPisInfinity(scip, - *bestlb));
    4886 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4887
    4888 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
    4889 SCIP_CALL( findMIRBestUb(scip, var, sol, data, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestub, &simpleub, bestubtype) );
    4890 }
    4891 else
    4892 {
    4893 assert(boundtypesfortrans[v] == SCIP_BOUNDTYPE_UPPER);
    4894
    4895 /* user wants to use upper bound */
    4896 *bestubtype = boundsfortrans[v];
    4897 if( *bestubtype == -1 )
    4898 *bestub = SCIPvarGetUbGlobal(var); /* use global standard upper bound */
    4899 else if( *bestubtype == -2 )
    4900 *bestub = SCIPvarGetUbLocal(var); /* use local standard upper bound */
    4901 else
    4902 {
    4903 SCIP_Real vubsol;
    4904 SCIP_VAR** vubvars;
    4905 SCIP_Real* vubcoefs;
    4906 SCIP_Real* vubconsts;
    4907 int k;
    4908
    4909 assert(!ignoresol);
    4910
    4911 /* use the given variable upper bound */
    4912 vubvars = SCIPvarGetVubVars(var);
    4913 vubcoefs = SCIPvarGetVubCoefs(var);
    4914 vubconsts = SCIPvarGetVubConstants(var);
    4915 k = boundsfortrans[v];
    4916 assert(k >= 0 && k < SCIPvarGetNVubs(var));
    4917 assert(vubvars != NULL);
    4918 assert(vubcoefs != NULL);
    4919 assert(vubconsts != NULL);
    4920
    4921 vubsol = SCIPgetSolVal(scip, sol, vubvars[k]);
    4922 *bestub = vubcoefs[k] * vubsol + vubconsts[k];
    4923 }
    4924
    4925 assert(!SCIPisInfinity(scip, *bestub));
    4926 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4927
    4928 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
    4929 SCIP_CALL( findMIRBestLb(scip, var, sol, data, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestlb, &simplelb, bestlbtype) );
    4930 }
    4931 }
    4932 else
    4933 {
    4934 SCIP_Real varsol;
    4935
    4936 /* bound selection should be done automatically */
    4937
    4938 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
    4939 SCIP_CALL( findMIRBestLb(scip, var, sol, data, usevbds, allowlocal, bestlb, &simplelb, bestlbtype) );
    4940
    4941 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
    4942 SCIP_CALL( findMIRBestUb(scip, var, sol, data, usevbds, allowlocal, bestub, &simpleub, bestubtype) );
    4943
    4944 /* check, if variable is free variable */
    4945 if( SCIPisInfinity(scip, - *bestlb) && SCIPisInfinity(scip, *bestub) )
    4946 {
    4947 /* we found a free variable in the row with non-zero coefficient
    4948 * -> MIR row can't be transformed in standard form
    4949 */
    4950 *freevariable = TRUE;
    4951 return SCIP_OKAY;
    4952 }
    4953
    4954 if( !ignoresol )
    4955 {
    4956 /* select transformation bound */
    4957 varsol = SCIPgetSolVal(scip, sol, var);
    4958
    4959 if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
    4960 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4961 else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
    4962 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4963 else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
    4964 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4965 else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
    4966 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4967 else if( *bestlbtype == -1 ) /* prefer global standard bounds */
    4968 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4969 else if( *bestubtype == -1 ) /* prefer global standard bounds */
    4970 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4971 else if( ((*bestlbtype) >= 0 || (*bestubtype) >= 0) && !SCIPisEQ(scip, *bestlb - simplelb, simpleub - *bestub) )
    4972 {
    4973 if( *bestlb - simplelb > simpleub - *bestub )
    4974 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4975 else
    4976 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4977 }
    4978 else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
    4979 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4980 else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
    4981 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4982 else /* no decision yet? just use lower bound */
    4983 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4984 }
    4985 else
    4986 {
    4987 SCIP_Real glbub = SCIPvarGetUbGlobal(var);
    4988 SCIP_Real glblb = SCIPvarGetLbGlobal(var);
    4989 SCIP_Real distlb = REALABS(glblb - *bestlb);
    4990 SCIP_Real distub = REALABS(glbub - *bestub);
    4991
    4992 assert(!SCIPisInfinity(scip, - *bestlb) || !SCIPisInfinity(scip, *bestub));
    4993
    4994 if( SCIPisInfinity(scip, - *bestlb) )
    4995 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4996 else if( !SCIPisNegative(scip, *bestlb) )
    4997 {
    4998 if( SCIPisInfinity(scip, *bestub) )
    4999 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    5000 else if( SCIPisZero(scip, glblb) )
    5001 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    5002 else if( SCIPisLE(scip, distlb, distub) )
    5003 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    5004 else
    5005 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    5006 }
    5007 else
    5008 {
    5009 assert(!SCIPisInfinity(scip, - *bestlb));
    5010 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    5011 }
    5012 }
    5013 }
    5014
    5015 return SCIP_OKAY; /*lint !e438*/
    5016}
    5017
    5018/** Performs bound substitution for a MIR cut */
    5019static
    5021 SCIP* scip, /**< SCIP datastructure */
    5022 MIR_DATA* data, /**< the MIR data structure for this cut */
    5023 int varsign, /**< stores the sign of the transformed variable in summation */
    5024 int boundtype, /**< stores the bound used for transformed variable:
    5025 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5026 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
    5027 int probindex, /**< problem index of variable to perform the substitution step for */
    5028 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
    5029 )
    5030{
    5031 SCIP_Real QUAD(coef);
    5032 SCIP_Real QUAD(tmp);
    5033
    5034 assert(!SCIPisInfinity(scip, -varsign * boundval));
    5035
    5036 QUAD_ARRAY_LOAD(coef, data->cutcoefs, probindex);
    5037
    5038 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
    5039 if( boundtype < 0 )
    5040 {
    5041 SCIPquadprecProdQD(tmp, coef, boundval);
    5042 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, -tmp);
    5043 *localbdsused = *localbdsused || ( boundtype == -2 );
    5044 }
    5045 else
    5046 {
    5047 SCIP_VAR** vbdvars;
    5048 SCIP_Real* vbdcoefs;
    5049 SCIP_Real* vbdconsts;
    5050 SCIP_Real QUAD(zcoef);
    5051 int zidx;
    5052 SCIP_VAR* var = SCIPgetVars(scip)[probindex];
    5053
    5054 if( varsign == +1 )
    5055 {
    5056 vbdvars = SCIPvarGetVlbVars(var);
    5057 vbdcoefs = SCIPvarGetVlbCoefs(var);
    5058 vbdconsts = SCIPvarGetVlbConstants(var);
    5059 assert(0 <= boundtype && boundtype < SCIPvarGetNVlbs(var));
    5060 }
    5061 else
    5062 {
    5063 vbdvars = SCIPvarGetVubVars(var);
    5064 vbdcoefs = SCIPvarGetVubCoefs(var);
    5065 vbdconsts = SCIPvarGetVubConstants(var);
    5066 assert(0 <= boundtype && boundtype < SCIPvarGetNVubs(var));
    5067 }
    5068
    5069 assert(vbdvars != NULL);
    5070 assert(vbdcoefs != NULL);
    5071 assert(vbdconsts != NULL);
    5072 assert(SCIPvarIsActive(vbdvars[boundtype]));
    5073
    5074 zidx = SCIPvarGetProbindex(vbdvars[boundtype]);
    5075
    5076 SCIPquadprecProdQD(tmp, coef, vbdconsts[boundtype]);
    5077 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, -tmp);
    5078
    5079 /* check if integral variable already exists in the row */
    5080 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
    5081
    5082 /* If it is new, add it to the indices */
    5083 if( QUAD_HI(zcoef) == 0.0 )
    5084 {
    5085 int section = varSection(data, zidx);
    5086 assert(section > varSection(data, probindex));
    5087
    5088 data->secindices[section][data->secnnz[section]] = zidx;
    5089 ++data->secnnz[section];
    5090 ++data->totalnnz;
    5091 }
    5092
    5093 SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype]);
    5094 SCIPquadprecSumQQ(zcoef, zcoef, tmp);
    5095
    5096 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
    5097 assert(QUAD_HI(zcoef) != 0.0);
    5098
    5099 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
    5100 }
    5101}
    5102
    5103/** performs the bound substitution step with the given variable or simple bounds for the variable with the given problem index
    5104 *
    5105 * @note this method is safe for usage in exact solving mode
    5106 *
    5107 * @todo make behavior identical to the unsafe MIR cut computation
    5108 */
    5109static
    5111 SCIP* scip, /**< SCIP datastructure */
    5112 SCIP_Real* cutcoefs, /**< array of cut coefficients */
    5113 SCIP_Real* cutrhs, /**< pointer to right hand side of the cut */
    5114 int varsign, /**< stores the sign of the transformed variable in summation */
    5115 int boundtype, /**< stores the bound used for transformed variable:
    5116 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5117 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
    5118 int probindex, /**< problem index of variable to perform the substitution step for */
    5119 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
    5120 )
    5121{
    5122 SCIP_Real coef;
    5123 SCIP_ROUNDMODE previousroundmode;
    5124
    5125 assert(!SCIPisInfinity(scip, -varsign * boundval));
    5126 assert(SCIPisExact(scip));
    5127
    5128 previousroundmode = SCIPintervalGetRoundingMode();
    5130
    5131 coef = cutcoefs[probindex];
    5132
    5133 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
    5134 if( boundtype < 0 )
    5135 {
    5136 *cutrhs += coef * (-boundval);
    5137 *localbdsused = *localbdsused || (boundtype == -2);
    5138 }
    5139 else
    5140 {
    5141 /* we don't support vlbs in exact mode yet */
    5142 assert(!SCIPisExact(scip));
    5143 SCIPerrorMessage("variable lower bounds not implemented in exact solving mode yet \n");
    5144 SCIPABORT();
    5145 }
    5146
    5147 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
    5148}
    5149
    5150/** performs the bound substitution step with the simple bound for the variable with the given problem index
    5151 *
    5152 * @note this method is safe for usage in exact solving mode
    5153 *
    5154 * @todo make behavior identical to the unsafe MIR cut computation
    5155 */
    5156static
    5158 SCIP* scip, /**< SCIP datastructure */
    5159 SCIP_Real* cutcoefs, /**< array of cut coefficients */
    5160 SCIP_Real* cutrhs, /**< pointer to right hand side of the cut */
    5161 int boundtype, /**< stores the bound used for transformed variable:
    5162 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5163 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
    5164 int probindex, /**< problem index of variable to perform the substitution step for */
    5165 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
    5166 )
    5167{
    5168 SCIP_Real coef;
    5169 SCIP_ROUNDMODE previousroundmode;
    5170
    5171 assert(!SCIPisInfinity(scip, ABS(boundval)));
    5172 assert(SCIPisExact(scip));
    5173
    5174 previousroundmode = SCIPintervalGetRoundingMode();
    5176
    5177 coef = cutcoefs[probindex];
    5178
    5179 /* must be a standard bound */
    5180 assert( boundtype < 0 );
    5181
    5182 *cutrhs += coef * (-boundval);
    5183
    5184 *localbdsused = *localbdsused || (boundtype == -2);
    5185
    5186 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
    5187}
    5188
    5189/** performs the bound substitution step with the given variable or simple bounds for the variable with the given problem index */
    5190static
    5192 SCIP* scip, /**< SCIP datastructure */
    5193 int* cutinds, /**< index array of nonzeros in the cut */
    5194 SCIP_Real* cutcoefs, /**< array of cut coefficients */
    5195 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
    5196 int* nnz, /**< pointer to number of nonzeros of the cut */
    5197 int varsign, /**< stores the sign of the transformed variable in summation */
    5198 int boundtype, /**< stores the bound used for transformed variable:
    5199 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5200 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
    5201 int probindex, /**< problem index of variable to perform the substitution step for */
    5202 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
    5203 )
    5204{
    5205 SCIP_Real QUAD(coef);
    5206 SCIP_Real QUAD(tmp);
    5207
    5208 assert(!SCIPisInfinity(scip, -varsign * boundval));
    5209 assert(!SCIPisExact(scip));
    5210
    5211 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
    5212
    5213 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
    5214 if( boundtype < 0 )
    5215 {
    5216 SCIPquadprecProdQD(tmp, coef, boundval);
    5217 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
    5218 *localbdsused = *localbdsused || (boundtype == -2);
    5219 }
    5220 else
    5221 {
    5222 SCIP_VAR** vbdvars;
    5223 SCIP_Real* vbdcoefs;
    5224 SCIP_Real* vbdconsts;
    5225 SCIP_Real QUAD(zcoef);
    5226 int zidx;
    5227 SCIP_VAR* var = SCIPgetVars(scip)[probindex];
    5228
    5229 if( varsign == +1 )
    5230 {
    5231 vbdvars = SCIPvarGetVlbVars(var);
    5232 vbdcoefs = SCIPvarGetVlbCoefs(var);
    5233 vbdconsts = SCIPvarGetVlbConstants(var);
    5234 assert(0 <= boundtype && boundtype < SCIPvarGetNVlbs(var));
    5235 }
    5236 else
    5237 {
    5238 vbdvars = SCIPvarGetVubVars(var);
    5239 vbdcoefs = SCIPvarGetVubCoefs(var);
    5240 vbdconsts = SCIPvarGetVubConstants(var);
    5241 assert(0 <= boundtype && boundtype < SCIPvarGetNVubs(var));
    5242 }
    5243
    5244 assert(vbdvars != NULL);
    5245 assert(vbdcoefs != NULL);
    5246 assert(vbdconsts != NULL);
    5247 assert(SCIPvarIsActive(vbdvars[boundtype]));
    5248
    5249 zidx = SCIPvarGetProbindex(vbdvars[boundtype]);
    5250
    5251 SCIPquadprecProdQD(tmp, coef, vbdconsts[boundtype]);
    5252 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
    5253
    5254 /* check if integral variable already exists in the row */
    5255 QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
    5256
    5257 if( QUAD_HI(zcoef) == 0.0 )
    5258 cutinds[(*nnz)++] = zidx;
    5259
    5260 SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype]);
    5261 SCIPquadprecSumQQ(zcoef, zcoef, tmp);
    5262
    5263 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
    5264 assert(QUAD_HI(zcoef) != 0.0);
    5265
    5266 QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
    5267 }
    5268}
    5269
    5270/** performs the bound substitution step with the simple bound for the variable with the given problem index */
    5271static
    5273 SCIP* scip, /**< SCIP datastructure */
    5274 SCIP_Real* cutcoefs, /**< array of cut coefficients */
    5275 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
    5276 int boundtype, /**< stores the bound used for transformed variable:
    5277 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5278 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
    5279 int probindex, /**< problem index of variable to perform the substitution step for */
    5280 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
    5281 )
    5282{
    5283 SCIP_Real QUAD(coef);
    5284 SCIP_Real QUAD(tmp);
    5285
    5286 assert(!SCIPisInfinity(scip, ABS(boundval)));
    5287 assert(!SCIPisExact(scip));
    5288
    5289 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
    5290
    5291 /* must be a standard bound */
    5292 assert( boundtype < 0 );
    5293
    5294 SCIPquadprecProdQD(tmp, coef, boundval);
    5295 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
    5296 *localbdsused = *localbdsused || (boundtype == -2);
    5297}
    5298
    5299/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
    5300 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
    5301 *
    5302 * Transform variables (lb or ub):
    5303 * \f[
    5304 * \begin{array}{llll}
    5305 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \mbox{if lb is used in transformation},\\
    5306 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if ub is used in transformation},
    5307 * \end{array}
    5308 * \f]
    5309 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
    5310 *
    5311 * Transform variables (vlb or vub):
    5312 * \f[
    5313 * \begin{array}{llll}
    5314 * x^\prime_j := x_j - (bl_j\, zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \mbox{if vlb is used in transf.} \\
    5315 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if vub is used in transf.}
    5316 * \end{array}
    5317 * \f]
    5318 * move the constant terms \f$ a_j\, dl_j \f$ or \f$ a_j\, du_j \f$ to the rhs, and update the coefficient of the VLB variable:
    5319 * \f[
    5320 * \begin{array}{ll}
    5321 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
    5322 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
    5323 * \end{array}
    5324 * \f]
    5325 *
    5326 * @note this method is safe for usage in exact solving mode
    5327 *
    5328 * @todo make behavior identical to the unsafe MIR cut computation
    5329 */
    5330static
    5332 SCIP* scip, /**< SCIP data structure */
    5333 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    5334 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    5335 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
    5336 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    5337 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    5338 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
    5339 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    5340 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    5341 * NULL for using closest bound for all variables */
    5342 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    5343 * NULL for using closest bound for all variables */
    5344 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    5345 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
    5346 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    5347 int* nnz, /**< number of non-zeros in cut */
    5348 int* varsign, /**< stores the sign of the transformed variable in summation */
    5349 int* boundtype, /**< stores the bound used for transformed variable:
    5350 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5351 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
    5352 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
    5353 )
    5354{ /*lint --e{644}*/
    5355 SCIP_Real* bestlbs;
    5356 SCIP_Real* bestubs;
    5357 int* bestlbtypes;
    5358 int* bestubtypes;
    5359 SCIP_BOUNDTYPE* selectedbounds;
    5360 int i;
    5361 int aggrrowintstart;
    5362 int nvars;
    5363 int firstcontvar;
    5364 SCIP_VAR** vars;
    5365 SCIP_MIRINFO* mirinfo = NULL;
    5366
    5367 SCIP_ROUNDMODE previousroundmode;
    5368
    5369 assert(varsign != NULL);
    5370 assert(boundtype != NULL);
    5371 assert(freevariable != NULL);
    5372 assert(localbdsused != NULL);
    5373 assert(SCIPisExact(scip));
    5374
    5375 if( SCIPisCertified(scip) )
    5377 previousroundmode = SCIPintervalGetRoundingMode();
    5379
    5380 *freevariable = FALSE;
    5381 *localbdsused = FALSE;
    5382
    5383 /* allocate temporary memory to store best bounds and bound types */
    5384 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, 2*(*nnz)) );
    5385 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, 2*(*nnz)) );
    5386 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, 2*(*nnz)) );
    5387 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, 2*(*nnz)) );
    5388 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, 2*(*nnz)) );
    5389
    5390 /* start with continuous variables, because using variable bounds can affect the untransformed integral
    5391 * variables, and these changes have to be incorporated in the transformation of the integral variables
    5392 * (continuous variables have largest problem indices!)
    5393 */
    5394 SCIPsortDownInt(cutinds, *nnz);
    5395
    5396 vars = SCIPgetVars(scip);
    5397 nvars = SCIPgetNVars(scip);
    5398 firstcontvar = nvars - SCIPgetNContVars(scip);
    5399
    5400 /* determine the best bounds for the continuous variables */
    5401 for( i = 0; i < *nnz && cutinds[i] >= firstcontvar; ++i )
    5402 {
    5403 SCIP_CALL( determineBestBoundsSafely(scip, vars[cutinds[i]], sol, boundswitch, usevbds ? 2 : 0, allowlocal, fixintegralrhs,
    5404 ignoresol, boundsfortrans, boundtypesfortrans,
    5405 bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
    5406
    5407 if( *freevariable )
    5408 goto TERMINATE;
    5409 }
    5410
    5411 /* remember start of integer variables in the aggrrow */
    5412 aggrrowintstart = i;
    5413
    5414 /* perform bound substitution for continuous variables */
    5415 for( i = 0; i < aggrrowintstart; ++i )
    5416 {
    5417 int v = cutinds[i];
    5418
    5419 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
    5420 {
    5421 assert(!SCIPisInfinity(scip, -bestlbs[i]));
    5422
    5423 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
    5424 boundtype[i] = bestlbtypes[i];
    5425 varsign[i] = +1;
    5426
    5427 performBoundSubstitutionSafely(scip, cutcoefs, cutrhs, varsign[i], boundtype[i], bestlbs[i], v, localbdsused);
    5428 }
    5429 else
    5430 {
    5431 assert(!SCIPisInfinity(scip, bestubs[i]));
    5432
    5433 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
    5434 boundtype[i] = bestubtypes[i];
    5435 varsign[i] = -1;
    5436
    5437 performBoundSubstitutionSafely(scip, cutcoefs, cutrhs, varsign[i], boundtype[i], bestubs[i], v, localbdsused);
    5438 }
    5439
    5440 if( SCIPisCertified(scip) )
    5441 {
    5442 assert(mirinfo != NULL);
    5443 if( boundtype[i] == -2 )
    5444 {
    5445 mirinfo->localbdused[v] = TRUE;
    5446 mirinfo->nlocalvars++;
    5447 }
    5448 mirinfo->upperused[v] = (varsign[i] == -1);
    5449 }
    5450 }
    5451
    5452 /* remove integral variables that now have a zero coefficient due to variable bound usage of continuous variables
    5453 * and determine the bound to use for the integer variables that are left
    5454 */
    5455 while( i < *nnz )
    5456 {
    5457 int v = cutinds[i];
    5458 assert(cutinds[i] < firstcontvar);
    5459
    5460 /* determine the best bounds for the integral variable, usevbd can be set to 0 here as vbds are only used for continuous variables */
    5461 SCIP_CALL( determineBestBoundsSafely(scip, vars[v], sol, boundswitch, 0, allowlocal, fixintegralrhs,
    5462 ignoresol, boundsfortrans, boundtypesfortrans,
    5463 bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
    5464
    5465 /* increase i */
    5466 ++i;
    5467
    5468 if( *freevariable )
    5469 goto TERMINATE;
    5470 }
    5471
    5472 /* now perform the bound substitution on the remaining integral variables which only uses standard bounds */
    5473 for( i = aggrrowintstart; i < *nnz; ++i )
    5474 {
    5475 int v = cutinds[i];
    5476
    5477 /* perform bound substitution */
    5478 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
    5479 {
    5480 assert(!SCIPisInfinity(scip, - bestlbs[i]));
    5481 assert(bestlbtypes[i] < 0);
    5482
    5483 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
    5484 boundtype[i] = bestlbtypes[i];
    5485 varsign[i] = +1;
    5486
    5487 performBoundSubstitutionSimpleSafely(scip, cutcoefs, cutrhs, boundtype[i], bestlbs[i], v, localbdsused);
    5488 }
    5489 else
    5490 {
    5491 assert(!SCIPisInfinity(scip, bestubs[i]));
    5492 assert(bestubtypes[i] < 0);
    5493
    5494 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
    5495 boundtype[i] = bestubtypes[i];
    5496 varsign[i] = -1;
    5497
    5498 performBoundSubstitutionSimpleSafely(scip, cutcoefs, cutrhs, boundtype[i], bestubs[i], v, localbdsused);
    5499 }
    5500
    5501 if( SCIPisCertified(scip) )
    5502 {
    5503 assert(mirinfo != NULL);
    5504 if( boundtype[i] == -2 )
    5505 {
    5506 mirinfo->localbdused[v] = TRUE;
    5507 mirinfo->nlocalvars++;
    5508 }
    5509 mirinfo->upperused[v] = (varsign[i] == -1);
    5510 }
    5511 }
    5512
    5513 TERMINATE:
    5514 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
    5515
    5516 /*free temporary memory */
    5517 SCIPfreeBufferArray(scip, &selectedbounds);
    5518 SCIPfreeBufferArray(scip, &bestubtypes);
    5519 SCIPfreeBufferArray(scip, &bestlbtypes);
    5520 SCIPfreeBufferArray(scip, &bestubs);
    5521 SCIPfreeBufferArray(scip, &bestlbs);
    5522
    5523 return SCIP_OKAY;
    5524}
    5525
    5526/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
    5527 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
    5528 *
    5529 * Transform variables (lb or ub):
    5530 * \f[
    5531 * \begin{array}{llll}
    5532 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \mbox{if lb is used in transformation},\\
    5533 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if ub is used in transformation},
    5534 * \end{array}
    5535 * \f]
    5536 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
    5537 *
    5538 * Transform variables (vlb or vub):
    5539 * \f[
    5540 * \begin{array}{llll}
    5541 * x^\prime_j := x_j - (bl_j\, zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \mbox{if vlb is used in transf.} \\
    5542 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if vub is used in transf.}
    5543 * \end{array}
    5544 * \f]
    5545 * move the constant terms \f$ a_j\, dl_j \f$ or \f$ a_j\, du_j \f$ to the rhs, and update the coefficient of the VLB variable:
    5546 * \f[
    5547 * \begin{array}{ll}
    5548 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
    5549 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
    5550 * \end{array}
    5551 * \f]
    5552 */
    5553static
    5555 SCIP* scip, /**< SCIP datastructure */
    5556 MIR_DATA* data, /**< the MIR data structure for this cut */
    5557 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    5558 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    5559 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    5560 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    5561 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
    5562 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    5563 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    5564 * NULL for using closest bound for all variables */
    5565 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    5566 * NULL for using closest bound for all variables */
    5567 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
    5568 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
    5569 int* varsign, /**< stores the sign of the transformed variable in summation */
    5570 int* boundtype, /**< stores the bound used for transformed variable:
    5571 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5572 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
    5573 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
    5574 )
    5575{
    5576 SCIP_Real* bestlbs;
    5577 SCIP_Real* bestubs;
    5578 int* bestlbtypes;
    5579 int* bestubtypes;
    5580 SCIP_BOUNDTYPE* selectedbounds;
    5581 SCIP_Real QUAD(coef);
    5582 int totalnnz;
    5583 int s;
    5584 int i;
    5585
    5586 assert(data != NULL);
    5587 assert(varsign != NULL);
    5588 assert(boundtype != NULL);
    5589 assert(freevariable != NULL);
    5590 assert(localbdsused != NULL);
    5591
    5592 totalnnz = data->totalnnz;
    5593
    5594 *freevariable = FALSE;
    5595 *localbdsused = FALSE;
    5596
    5597 int allocsize = MIN(NSECTIONS * totalnnz, data->nvars);
    5598 /* allocate temporary memory to store best bounds and bound types */
    5599 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, allocsize) );
    5600 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, allocsize) );
    5601 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, allocsize) );
    5602 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, allocsize) );
    5603 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, allocsize) );
    5604
    5605 /* transform the cut, one variable section at a time */
    5606 for( s = 0; s < NSECTIONS; ++s )
    5607 {
    5608 int* indices = data->secindices[s];
    5609 int cutindsstart = data->ncutinds;
    5610 int usevbds = data->usevbds[s];
    5611
    5612 i = 0;
    5613 while( i < data->secnnz[s] )
    5614 {
    5615 int cutindex;
    5616 int v = indices[i];
    5617
    5618 /* due to variable bound usage, cancellation may have occurred */
    5619 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
    5620 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
    5621 {
    5622 QUAD_ASSIGN(coef, 0.0);
    5623 QUAD_ARRAY_STORE(data->cutcoefs, v, coef);
    5624 --data->secnnz[s];
    5625 --data->totalnnz;
    5626 indices[i] = indices[data->secnnz[s]];
    5627 /* do not increase the index */
    5628 continue;
    5629 }
    5630
    5631 cutindex = data->ncutinds;
    5632 assert(cutindex < allocsize);
    5633 SCIP_CALL( determineBestBounds(scip, data->vars[v], sol, data, boundswitch, usevbds, allowlocal, fixintegralrhs,
    5634 ignoresol, boundsfortrans, boundtypesfortrans,
    5635 bestlbs + cutindex, bestubs + cutindex, bestlbtypes + cutindex, bestubtypes + cutindex,
    5636 selectedbounds + cutindex, freevariable) );
    5637
    5638 data->cutinds[cutindex] = v;
    5639 ++data->ncutinds;
    5640
    5641 ++i;
    5642
    5643 /* if there is a free variable, we terminate because we cannot derive a MIR cut */
    5644 if( *freevariable )
    5645 {
    5646 int j;
    5647 int k;
    5648
    5649 data->ncutinds = 0;
    5650
    5651 /* if we terminate early, we need to make sure all the zeros in the cut coefficient array are cancelled */
    5652 for( j = 0; j < NSECTIONS; ++j )
    5653 {
    5654 int* indexlist = data->secindices[j];
    5655 for( k = 0; k < data->secnnz[j]; ++k )
    5656 {
    5657 data->cutinds[data->ncutinds] = indexlist[k];
    5658 ++data->ncutinds;
    5659 }
    5660 }
    5661 goto TERMINATE;
    5662 }
    5663 }
    5664
    5665 /* perform bound substitution for added variables */
    5666 for( i = cutindsstart; i < data->ncutinds; ++i )
    5667 {
    5668 SCIP_Real bestbnd;
    5669 int v = data->cutinds[i];
    5670
    5671 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
    5672 {
    5673 assert(!SCIPisInfinity(scip, -bestlbs[i]));
    5674
    5675 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
    5676 boundtype[i] = bestlbtypes[i];
    5677 varsign[i] = +1;
    5678 bestbnd = bestlbs[i];
    5679 }
    5680 else
    5681 {
    5682 assert(!SCIPisInfinity(scip, bestubs[i]));
    5683
    5684 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
    5685 boundtype[i] = bestubtypes[i];
    5686 varsign[i] = -1;
    5687 bestbnd = bestubs[i];
    5688 }
    5689 doMIRBoundSubstitution(scip, data, varsign[i], boundtype[i], bestbnd, v, localbdsused);
    5690 }
    5691 }
    5692
    5693 if( fixintegralrhs )
    5694 {
    5695 SCIP_Real f0;
    5696
    5697 /* check if rhs is fractional */
    5698 f0 = EPSFRAC(QUAD_TO_DBL(data->cutrhs), SCIPsumepsilon(scip));
    5699 if( f0 < minfrac || f0 > maxfrac )
    5700 {
    5701 SCIP_Real bestviolgain;
    5702 SCIP_Real bestnewf0;
    5703 int besti;
    5704
    5705 /* choose complementation of one variable differently such that f0 is in correct range */
    5706 besti = -1;
    5707 bestviolgain = -1e+100;
    5708 bestnewf0 = 1.0;
    5709 for( i = 0; i < data->ncutinds; i++ )
    5710 {
    5711 int v;
    5712
    5713 v = data->cutinds[i];
    5714 assert(0 <= v && v < data->nvars);
    5715
    5716 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
    5717 assert(!EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON));
    5718
    5719 if( boundtype[i] < 0
    5720 && ((varsign[i] == +1 && !SCIPisInfinity(scip, bestubs[i]) && bestubtypes[i] < 0)
    5721 || (varsign[i] == -1 && !SCIPisInfinity(scip, -bestlbs[i]) && bestlbtypes[i] < 0)) )
    5722 {
    5723 SCIP_Real fj;
    5724 SCIP_Real newfj;
    5725 SCIP_Real newrhs;
    5726 SCIP_Real newf0;
    5727 SCIP_Real solval;
    5728 SCIP_Real viol;
    5729 SCIP_Real newviol;
    5730 SCIP_Real violgain;
    5731
    5732 /* currently: a'_j = varsign * a_j -> f'_j = a'_j - floor(a'_j)
    5733 * after complementation: a''_j = -varsign * a_j -> f''_j = a''_j - floor(a''_j) = 1 - f'_j
    5734 * rhs'' = rhs' + varsign * a_j * (lb_j - ub_j)
    5735 * cut violation from f0 and fj: f'_0 - f'_j * x'_j
    5736 * after complementation: f''_0 - f''_j * x''_j
    5737 *
    5738 * for continuous variables, we just set f'_j = f''_j = |a'_j|
    5739 */
    5740 newrhs = QUAD_TO_DBL(data->cutrhs) + varsign[i] * QUAD_TO_DBL(coef) * (bestlbs[i] - bestubs[i]);
    5741 newf0 = EPSFRAC(newrhs, SCIPsumepsilon(scip));
    5742
    5743 if( newf0 < minfrac || newf0 > maxfrac )
    5744 continue;
    5745 if( v >= data->nvars - data->ncontvars )
    5746 {
    5747 fj = REALABS(QUAD_TO_DBL(coef));
    5748 newfj = fj;
    5749 }
    5750 else
    5751 {
    5752 fj = SCIPfrac(scip, varsign[i] * QUAD_TO_DBL(coef));
    5753 newfj = SCIPfrac(scip, -varsign[i] * QUAD_TO_DBL(coef));
    5754 }
    5755
    5756 if( !ignoresol )
    5757 {
    5758 solval = SCIPgetSolVal(scip, sol, data->vars[v]);
    5759 viol = f0 - fj * (varsign[i] == +1 ? solval - bestlbs[i] : bestubs[i] - solval);
    5760 newviol = newf0 - newfj * (varsign[i] == -1 ? solval - bestlbs[i] : bestubs[i] - solval);
    5761 violgain = newviol - viol;
    5762 }
    5763 else
    5764 {
    5765 /* todo: this should be done, this can improve the dualray significantly */
    5766 SCIPerrorMessage("Cannot handle closest bounds with ignoring the LP solution.\n");
    5767 return SCIP_INVALIDCALL;
    5768 }
    5769
    5770 /* prefer larger violations; for equal violations, prefer smaller f0 values since then the possibility that
    5771 * we f_j > f_0 is larger and we may improve some coefficients in rounding
    5772 */
    5773 if( SCIPisGT(scip, violgain, bestviolgain) || (SCIPisGE(scip, violgain, bestviolgain) && newf0 < bestnewf0) )
    5774 {
    5775 besti = i;
    5776 bestviolgain = violgain;
    5777 bestnewf0 = newf0;
    5778 }
    5779 }
    5780 }
    5781
    5782 if( besti >= 0 )
    5783 {
    5784 SCIP_Real QUAD(tmp);
    5785
    5786 assert(besti < data->ncutinds);
    5787 assert(boundtype[besti] < 0);
    5788 assert(!SCIPisInfinity(scip, -bestlbs[besti]));
    5789 assert(!SCIPisInfinity(scip, bestubs[besti]));
    5790
    5791 QUAD_ARRAY_LOAD(coef, data->cutcoefs, data->cutinds[besti]);
    5792 QUAD_SCALE(coef, varsign[besti]);
    5793
    5794 /* switch the complementation of this variable */
    5795 SCIPquadprecSumDD(tmp, bestlbs[besti], - bestubs[besti]);
    5796 SCIPquadprecProdQQ(tmp, tmp, coef);
    5797 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    5798
    5799 if( varsign[besti] == +1 )
    5800 {
    5801 /* switch to upper bound */
    5802 assert(bestubtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
    5803 boundtype[besti] = bestubtypes[besti];
    5804 varsign[besti] = -1;
    5805 }
    5806 else
    5807 {
    5808 /* switch to lower bound */
    5809 assert(bestlbtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
    5810 boundtype[besti] = bestlbtypes[besti];
    5811 varsign[besti] = +1;
    5812 }
    5813 *localbdsused = *localbdsused || (boundtype[besti] == -2);
    5814 }
    5815 }
    5816 }
    5817
    5818 TERMINATE:
    5819
    5820 /*free temporary memory */
    5821 SCIPfreeBufferArray(scip, &selectedbounds);
    5822 SCIPfreeBufferArray(scip, &bestubtypes);
    5823 SCIPfreeBufferArray(scip, &bestlbtypes);
    5824 SCIPfreeBufferArray(scip, &bestubs);
    5825 SCIPfreeBufferArray(scip, &bestlbs);
    5826
    5827 return SCIP_OKAY;
    5828}
    5829
    5830/** Calculate fractionalities \f$ f_0 := b - down(b), f_j := a^\prime_j - down(a^\prime_j) \f$, and derive MIR cut \f$ \tilde{a} \cdot x' \leq down(b) \f$
    5831 * \f[
    5832 * \begin{array}{rll}
    5833 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
    5834 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
    5835 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
    5836 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
    5837 * \end{array}
    5838 * \f]
    5839 *
    5840 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
    5841 *
    5842 * (lb or ub):
    5843 * \f[
    5844 * \begin{array}{lllll}
    5845 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{if lb was used in transformation}, \\
    5846 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{if ub was used in transformation},
    5847 * \end{array}
    5848 * \f]
    5849 * and move the constant terms
    5850 * \f[
    5851 * \begin{array}{cl}
    5852 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
    5853 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
    5854 * \end{array}
    5855 * \f]
    5856 * to the rhs.
    5857 *
    5858 * (vlb or vub):
    5859 * \f[
    5860 * \begin{array}{lllll}
    5861 * x^\prime_j := x_j - (bl_j \cdot zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{(vlb)} \\
    5862 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{(vub)}
    5863 * \end{array}
    5864 * \f]
    5865 * move the constant terms
    5866 * \f[
    5867 * \begin{array}{cl}
    5868 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
    5869 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
    5870 * \end{array}
    5871 * \f]
    5872 * to the rhs, and update the VB variable coefficients:
    5873 * \f[
    5874 * \begin{array}{ll}
    5875 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
    5876 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
    5877 * \end{array}
    5878 * \f]
    5879 *
    5880 * @note this method is safe for usage in exact solving mode
    5881 */
    5882static
    5884 SCIP* scip, /**< SCIP data structure */
    5885 SCIP_Real*RESTRICT cutcoefs, /**< array of coefficients of cut */
    5886 SCIP_Real*RESTRICT cutrhs, /**< pointer to right hand side of cut */
    5887 int*RESTRICT cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    5888 int*RESTRICT nnz, /**< number of non-zeros in cut */
    5889 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
    5890 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
    5891 SCIP_INTERVAL f0 /**< fractional value of rhs */
    5892 )
    5893{
    5894 SCIP_INTERVAL onedivoneminusf0;
    5895 int i;
    5896 int firstcontvar;
    5897 SCIP_VAR** vars;
    5898 int ndelcontvars;
    5899 SCIP_ROUNDMODE previousroundmode;
    5900 SCIP_MIRINFO* mirinfo = NULL;
    5901 SCIP_INTERVAL tmpinterval;
    5902
    5903 assert(cutrhs != NULL);
    5904 assert(cutcoefs != NULL);
    5905 assert(cutinds != NULL);
    5906 assert(nnz != NULL);
    5907 assert(boundtype != NULL);
    5908 assert(varsign != NULL);
    5909 assert(0.0 < SCIPintervalGetInf(f0) && SCIPintervalGetSup(f0) < 1.0);
    5910 assert(SCIPisExact(scip));
    5911
    5912 /* round up at first, since we are dividing and divisor should be as large as possible,
    5913 * then switch to down since we are working on lhs */
    5914 /* we need to careate the split-data for certification here, since part of the f_j > f_0 variables goes into the continuous part of the split */
    5915 if( SCIPisCertified(scip) )
    5917
    5918 previousroundmode = SCIPintervalGetRoundingMode();
    5919 tmpinterval = f0;
    5921 SCIPintervalAddScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, 1.0);
    5922 SCIPintervalSet(&onedivoneminusf0, 1.0);
    5923 SCIPintervalDiv(SCIPinfinity(scip), &onedivoneminusf0, onedivoneminusf0, tmpinterval);
    5925
    5926 /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
    5927 * without destroying the ordering of the aggrrow's non-zeros.
    5928 * (due to sorting in cutsTransformMIR the ordering is continuous before integral)
    5929 */
    5930
    5931 firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    5932 vars = SCIPgetVars(scip);
    5933#ifndef NDEBUG
    5934 /*in debug mode check that all continuous variables of the aggrrow come before the integral variables */
    5935 i = 0;
    5936 while( i < *nnz && cutinds[i] >= firstcontvar )
    5937 ++i;
    5938
    5939 while( i < *nnz )
    5940 {
    5941 assert(cutinds[i] < firstcontvar);
    5942 ++i;
    5943 }
    5944#endif
    5945
    5946 /* round down everything on lhs (excepts for the denominator part above) */
    5948
    5949 for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
    5950 {
    5951 SCIP_VAR* var;
    5952 SCIP_INTERVAL cutaj;
    5953
    5954 int v;
    5955
    5956 v = cutinds[i];
    5957 assert(0 <= v && v < SCIPgetNVars(scip));
    5958
    5959 var = vars[v];
    5960 assert(var != NULL);
    5961 assert(SCIPvarGetProbindex(var) == v);
    5962 assert(varsign[i] == +1 || varsign[i] == -1);
    5963
    5964 /* work on lhs -> round down */
    5966
    5967 /* calculate the coefficient in the retransformed cut */
    5968 {
    5969 SCIP_Real aj;
    5970 SCIP_Real downaj;
    5971 SCIP_Real fj;
    5972
    5973 aj = cutcoefs[v] * varsign[i];
    5974
    5975 downaj = floor(aj);
    5976 fj = aj - downaj;
    5977 assert(fj >= -SCIPepsilon(scip) && fj <= 1.0);
    5978
    5979 if( SCIPisLE(scip, fj, SCIPintervalGetInf(f0)) )
    5980 {
    5981 SCIPintervalSet(&cutaj, downaj);
    5982
    5983 if( SCIPisCertified(scip) && mirinfo != NULL )
    5984 {
    5985 SCIP_RATIONAL* boundval;
    5986
    5987 mirinfo->splitcoefficients[v] = SCIPintervalGetInf(cutaj); /*lint !e644*/
    5988 assert(!SCIPisInfinity(scip, fabs(cutaj.inf)));
    5989 if( mirinfo->upperused[v] )
    5990 {
    5991 mirinfo->splitcoefficients[v] *= -1;
    5992 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
    5993 }
    5994 else
    5995 {
    5996 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
    5997 }
    5998 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
    5999 }
    6000 }
    6001 else
    6002 {
    6003 SCIPintervalSet(&tmpinterval, aj);
    6004 SCIPintervalSubScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, downaj);
    6005 SCIPintervalSub(SCIPinfinity(scip), &tmpinterval, tmpinterval, f0);
    6006 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, onedivoneminusf0);
    6007 SCIPintervalAddScalar(SCIPinfinity(scip), &cutaj, tmpinterval, downaj);
    6008
    6009 if( SCIPisCertified(scip) && mirinfo != NULL )
    6010 {
    6011 SCIP_RATIONAL* boundval;
    6012 mirinfo->splitcoefficients[v] = downaj;
    6013 mirinfo->splitcoefficients[v] += 1.0;
    6014 if( mirinfo->upperused[v] )
    6015 {
    6016 mirinfo->splitcoefficients[v] *= -1;
    6017 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
    6018 }
    6019 else
    6020 {
    6021 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
    6022 }
    6023 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
    6024 }
    6025 }
    6026
    6027 SCIPintervalMulScalar(SCIPinfinity(scip), &cutaj, cutaj, (double) varsign[i]);
    6028 }
    6029
    6030 /* integral var uses standard bound */
    6031 assert(boundtype[i] < 0);
    6032
    6033 if( cutaj.inf != 0.0 || cutaj.sup != 0 )
    6034 {
    6035 /* we have to use the inf of the cutaj-interval both times! */
    6037
    6038 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    6039 if( varsign[i] == +1 )
    6040 {
    6041 /* lower bound was used */
    6042 if( boundtype[i] == -1 )
    6043 {
    6045 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    6047 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6048 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6049 }
    6050 else
    6051 {
    6052 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    6054 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6055 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6056 }
    6057 }
    6058 else
    6059 {
    6060 /* upper bound was used */
    6061 if( boundtype[i] == -1 )
    6062 {
    6064 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    6066 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6067 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6068 }
    6069 else
    6070 {
    6071 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    6073 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6074 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6075 }
    6076 }
    6077 }
    6078
    6079 /* remove zero cut coefficients from cut, only remove exactly 0 in exact solving mode
    6080 * we can only do this here, since the sup might be positive and impact the rhs of the cut */
    6081 if( cutaj.inf == 0.0 )
    6082 {
    6083 cutcoefs[v] = 0.0;
    6084 --*nnz;
    6085 cutinds[i] = cutinds[*nnz];
    6086 continue;
    6087 }
    6088
    6089 cutcoefs[v] = SCIPintervalGetInf(cutaj);
    6090 }
    6091
    6092 /* adapt lhs -> round down */
    6094
    6095 /* now process the continuous variables; postpone deletetion of zeros till all continuous variables have been processed */
    6096 ndelcontvars = 0;
    6097 while( i >= ndelcontvars )
    6098 {
    6099 SCIP_VAR* var;
    6100 SCIP_INTERVAL cutaj;
    6101 SCIP_Real aj;
    6102 int v;
    6103
    6104 v = cutinds[i];
    6105 assert(0 <= v && v < SCIPgetNVars(scip));
    6106
    6107 var = vars[v];
    6108 assert(var != NULL);
    6109 assert(SCIPvarGetProbindex(var) == v);
    6110 assert(varsign[i] == +1 || varsign[i] == -1);
    6111 assert( v >= firstcontvar );
    6112
    6113 /* adapt lhs -> round down */
    6115
    6116 /* calculate the coefficient in the retransformed cut */
    6117 aj = cutcoefs[v];
    6118
    6119 if( aj * varsign[i] >= 0.0 )
    6120 SCIPintervalSet(&cutaj, 0.0);
    6121 else
    6122 {
    6123 SCIPintervalMulScalar(SCIPinfinity(scip), &cutaj, onedivoneminusf0, aj); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
    6124 }
    6125
    6126 /* remove zero cut coefficients from cut; move a continuous var from the beginning
    6127 * to the current position, so that all integral variables stay behind the continuous
    6128 * variables
    6129 */
    6130 if( EPSZ(SCIPintervalGetInf(cutaj), QUAD_EPSILON) && (SCIPintervalGetInf(cutaj) >= 0.0) )
    6131 {
    6132 SCIPintervalSet(&cutaj, 0.0);
    6133 cutcoefs[v] = 0.0;
    6134 cutinds[i] = cutinds[ndelcontvars];
    6135 varsign[i] = varsign[ndelcontvars];
    6136 boundtype[i] = boundtype[ndelcontvars];
    6137 ++ndelcontvars;
    6138 continue;
    6139 }
    6140
    6141 cutcoefs[v] = SCIPintervalGetInf(cutaj);
    6142
    6144
    6145 /* check for variable bound use */
    6146 if( boundtype[i] < 0 )
    6147 {
    6148 /* standard bound */
    6149
    6150 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    6151 if( varsign[i] == +1 )
    6152 {
    6153 /* lower bound was used */
    6154 if( boundtype[i] == -1 )
    6155 {
    6156 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    6158 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6159 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6160 }
    6161 else
    6162 {
    6163 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    6165 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6166 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6167 }
    6168 }
    6169 else
    6170 {
    6171 /* upper bound was used */
    6172 if( boundtype[i] == -1 )
    6173 {
    6174 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    6176 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6177 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6178 }
    6179 else
    6180 {
    6181 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    6183 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6184 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6185 }
    6186 }
    6187 }
    6188 else
    6189 {
    6190 SCIPerrorMessage("varbounds not yet implemented in exact SCIP \n");
    6191 return SCIP_ERROR;
    6192 }
    6193
    6194 /* advance to next variable */
    6195 --i;
    6196 }
    6197
    6198 /* fill the empty position due to deleted continuous variables */
    6199 if( ndelcontvars > 0 )
    6200 {
    6201 assert(ndelcontvars <= *nnz);
    6202 *nnz -= ndelcontvars;
    6203 if( *nnz < ndelcontvars )
    6204 {
    6205 BMScopyMemoryArray(cutinds, cutinds + ndelcontvars, *nnz);
    6206 }
    6207 else
    6208 {
    6209 BMScopyMemoryArray(cutinds, cutinds + *nnz, ndelcontvars);
    6210 }
    6211 }
    6212
    6213 /* reset rounding mode, also set the rhs->data in the mirinfo */
    6214 SCIPintervalSetRoundingMode(previousroundmode);
    6215
    6216 return SCIP_OKAY;
    6217}
    6218
    6219#ifdef SCIP_DISABLED_CODE
    6220/** Calculate fractionalities \f$ f_0 := b - down(b), f_j := a^\prime_j - down(a^\prime_j) \f$, and derive MIR cut \f$ \tilde{a} \cdot x' \leq down(b) \f$
    6221 * \f[
    6222 * \begin{array}{rll}
    6223 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
    6224 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
    6225 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
    6226 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
    6227 * \end{array}
    6228 * \f]
    6229 *
    6230 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
    6231 *
    6232 * (lb or ub):
    6233 * \f[
    6234 * \begin{array}{lllll}
    6235 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{if lb was used in transformation} \\
    6236 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{if ub was used in transformation}
    6237 * \end{array}
    6238 * \f]
    6239 * and move the constant terms
    6240 * \f[
    6241 * \begin{array}{cl}
    6242 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
    6243 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
    6244 * \end{array}
    6245 * \f]
    6246 * to the rhs.
    6247 *
    6248 * (vlb or vub):
    6249 * \f[
    6250 * \begin{array}{lllll}
    6251 * x^\prime_j := x_j - (bl_j \cdot zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{(vlb)} \\
    6252 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{(vub)}
    6253 * \end{array}
    6254 * \f]
    6255 * move the constant terms
    6256 * \f[
    6257 * \begin{array}{cl}
    6258 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
    6259 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
    6260 * \end{array}
    6261 * \f]
    6262 * to the rhs, and update the VB variable coefficients:
    6263 * \f[
    6264 * \begin{array}{ll}
    6265 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
    6266 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
    6267 * \end{array}
    6268 * \f]
    6269 *
    6270 * @note this method is safe for usage in exact solving mode
    6271 */
    6272static
    6273SCIP_RETCODE cutsRoundMIRRational(
    6274 SCIP* scip, /**< SCIP data structure */
    6275 SCIP_Real*RESTRICT cutcoefs, /**< array of coefficients of cut */
    6276 QUAD(SCIP_Real*RESTRICT cutrhs), /**< pointer to right hand side of cut */
    6277 int*RESTRICT cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    6278 int*RESTRICT nnz, /**< number of non-zeros in cut */
    6279 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
    6280 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
    6281 SCIP_RATIONAL* f0 /**< fractional value of rhs */
    6282 )
    6283{
    6284 SCIP_RATIONAL* tmp;
    6285 SCIP_RATIONAL* onedivoneminusf0;
    6286 int i;
    6287 int firstcontvar;
    6288 SCIP_VAR** vars;
    6289 int ndelcontvars;
    6290 SCIP_ROUNDMODE previousroundmode;
    6291 SCIP_MIRINFO* mirinfo;
    6292
    6293 assert(QUAD_HI(cutrhs) != NULL);
    6294 assert(cutcoefs != NULL);
    6295 assert(cutinds != NULL);
    6296 assert(nnz != NULL);
    6297 assert(boundtype != NULL);
    6298 assert(varsign != NULL);
    6299 assert(SCIPrationalIsPositive(f0) && SCIPrationalIsLTReal(f0, 1.0));
    6300 assert(SCIPisExact(scip));
    6301
    6302 SCIP_CALL( SCIPrationalCreateBuffer(SCIPbuffer(scip), &onedivoneminusf0) );
    6304
    6305 /* round up at first, since we are dividing and divisor should be as large as possible,
    6306 * then switch to down since we are working on lhs */
    6307 /* we need to careate the split-data for certification here, since part of the f_j > f_0 variables goes into the continuous part of the split */
    6308 if( SCIPisCertified(scip) )
    6310
    6311 previousroundmode = SCIPintervalGetRoundingMode();
    6312 SCIPrationalSetReal(tmp, 1.0);
    6313 SCIPrationalDiff(tmp, tmp, f0);
    6314 SCIPrationalSetReal(onedivoneminusf0, 1.0);
    6315 SCIPrationalDiv(onedivoneminusf0, onedivoneminusf0, tmp);
    6316
    6317 /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
    6318 * without destroying the ordering of the aggrrow's non-zeros.
    6319 * (due to sorting in cutsTransformMIR the ordering is continuous before integral)
    6320 */
    6321
    6322 firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    6323 vars = SCIPgetVars(scip);
    6324#ifndef NDEBUG
    6325 /*in debug mode check that all continuous variables of the aggrrow come before the integral variables */
    6326 i = 0;
    6327 while( i < *nnz && cutinds[i] >= firstcontvar )
    6328 ++i;
    6329
    6330 while( i < *nnz )
    6331 {
    6332 assert(cutinds[i] < firstcontvar);
    6333 ++i;
    6334 }
    6335#endif
    6336
    6337 for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
    6338 {
    6339 SCIP_VAR* var;
    6340 SCIP_RATIONAL* cutaj;
    6341 SCIP_Real QUAD(cutajquad);
    6342 int v;
    6343
    6344 v = cutinds[i];
    6345 assert(0 <= v && v < SCIPgetNVars(scip));
    6346
    6348
    6349 var = vars[v];
    6350 assert(var != NULL);
    6351 assert(SCIPvarGetProbindex(var) == v);
    6352 assert(varsign[i] == +1 || varsign[i] == -1);
    6353
    6354 /* calculate the coefficient in the retransformed cut */
    6355 {
    6356 SCIP_Real QUAD(aj);
    6357 SCIP_Real downaj;
    6358 SCIP_RATIONAL* fj;
    6359
    6361
    6362 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
    6363 QUAD_SCALE(aj, varsign[i]);
    6364 SCIPrationalSetReal(tmp, aj);
    6365
    6366 downaj = floor(QUAD_TO_DBL(aj));
    6367 SCIPrationalDiffReal(fj, tmp, downaj);
    6368
    6369 if( SCIPrationalIsLE(fj, f0) )
    6370 {
    6371 SCIPrationalSetReal(cutaj, downaj);
    6372
    6373 if( SCIPisCertified(scip) )
    6374 {
    6375 SCIP_RATIONAL* boundval;
    6376
    6377 mirinfo->splitcoefficients[v] = downaj;
    6378 if( mirinfo->upperused[v] )
    6379 {
    6380 mirinfo->splitcoefficients[v] *= -1;
    6381 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
    6382 }
    6383 else
    6384 {
    6385 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
    6386 }
    6387 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
    6388 }
    6389 }
    6390 else
    6391 {
    6393 SCIPrationalDiffReal(tmp, tmp, downaj);
    6394 SCIPrationalDiff(tmp, tmp, f0);
    6395 SCIPrationalMult(tmp, tmp, onedivoneminusf0);
    6396 SCIPrationalAddReal(cutaj, tmp, downaj);
    6397
    6398 if( SCIPisCertified(scip) )
    6399 {
    6400 SCIP_RATIONAL* boundval;
    6401
    6402 mirinfo->splitcoefficients[v] = QUAD_TO_DBL(downaj);
    6403 mirinfo->splitcoefficients[v] += 1.0;
    6404 if( mirinfo->upperused[v] )
    6405 {
    6406 mirinfo->splitcoefficients[v] *= -1;
    6407 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
    6408 }
    6409 else
    6410 {
    6411 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
    6412 }
    6413 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
    6414 }
    6415 }
    6416
    6417 SCIPrationalMultReal(cutaj, cutaj, varsign[i]);
    6418
    6420 }
    6421
    6422 /* remove zero cut coefficients from cut, only remove positive coefficients in exact solving mode */
    6423 if( SCIPrationalIsZero(cutaj) )
    6424 {
    6425 QUAD_ASSIGN(cutajquad, 0.0);
    6426 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
    6427 --*nnz;
    6428 cutinds[i] = cutinds[*nnz];
    6430 continue;
    6431 }
    6432
    6434
    6435 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
    6436
    6437 /* integral var uses standard bound */
    6438 assert(boundtype[i] < 0);
    6439
    6441
    6442 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    6443 if( varsign[i] == +1 )
    6444 {
    6445 /* lower bound was used */
    6446 if( boundtype[i] == -1 )
    6447 {
    6449 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    6450 SCIPrationalMult(tmp, cutaj, SCIPvarGetLbGlobalExact(var));
    6451 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetLbGlobal(var) */
    6452 }
    6453 else
    6454 {
    6455 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    6456 SCIPrationalMult(tmp, cutaj, SCIPvarGetLbLocalExact(var));
    6457 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetLbLocal(var) */
    6458 }
    6459 }
    6460 else
    6461 {
    6462 /* upper bound was used */
    6463 if( boundtype[i] == -1 )
    6464 {
    6466 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    6467 SCIPrationalMult(tmp, cutaj, SCIPvarGetUbGlobalExact(var));
    6468 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetUbGlobal(var) */
    6469 }
    6470 else
    6471 {
    6472 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    6473 SCIPrationalMult(tmp, cutaj, SCIPvarGetUbLocalExact(var));
    6474 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetUbLocal(var) */
    6475 }
    6476 }
    6478 }
    6479
    6480 /* now process the continuous variables; postpone deletetion of zeros till all continuous variables have been processed */
    6481 ndelcontvars = 0;
    6482 while( i >= ndelcontvars )
    6483 {
    6484 SCIP_VAR* var;
    6485 SCIP_RATIONAL* cutaj;
    6486 SCIP_RATIONAL* tmprational;
    6487 SCIP_Real QUAD(cutajquad);
    6488 SCIP_Real QUAD(aj);
    6489 int v;
    6490
    6491 /* adapt lhs -> round down */
    6493
    6496
    6497 v = cutinds[i];
    6498 assert(0 <= v && v < SCIPgetNVars(scip));
    6499
    6500 var = vars[v];
    6501 assert(var != NULL);
    6502 assert(SCIPvarGetProbindex(var) == v);
    6503 assert(varsign[i] == +1 || varsign[i] == -1);
    6504 assert( v >= firstcontvar );
    6505
    6506 /* calculate the coefficient in the retransformed cut */
    6507 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
    6508
    6509 if( QUAD_TO_DBL(aj) * varsign[i] >= 0.0 )
    6510 SCIPrationalSetReal(cutaj, 0.0);
    6511 else
    6512 {
    6513 SCIPrationalSetRational(cutaj, onedivoneminusf0);
    6514 SCIPrationalMultReal(cutaj, cutaj, QUAD_TO_DBL(aj)); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
    6515 }
    6516
    6517 /* remove zero cut coefficients from cut; move a continuous var from the beginning
    6518 * to the current position, so that all integral variables stay behind the continuous
    6519 * variables
    6520 */
    6521 if( EPSZ(SCIPrationalGetReal(cutaj), QUAD_EPSILON) && SCIPrationalIsGEReal(cutaj, 0.0) )
    6522 {
    6523 assert(SCIPrationalIsZero(cutaj));
    6524 SCIPrationalSetReal(cutaj, 0.0);
    6525 QUAD_ASSIGN_Q(cutajquad, 0.0);
    6526 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
    6527 cutinds[i] = cutinds[ndelcontvars];
    6528 varsign[i] = varsign[ndelcontvars];
    6529 boundtype[i] = boundtype[ndelcontvars];
    6530 ++ndelcontvars;
    6531
    6532 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
    6534
    6535 continue;
    6536 }
    6537
    6539 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
    6540
    6542
    6543 /* check for variable bound use */
    6544 if( boundtype[i] < 0 )
    6545 {
    6546 /* standard bound */
    6547
    6548 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    6549 if( varsign[i] == +1 )
    6550 {
    6551 /* lower bound was used */
    6552 if( boundtype[i] == -1 )
    6553 {
    6555 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    6556 SCIPrationalMult(tmprational, cutaj, SCIPvarGetLbGlobalExact(var));
    6557 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
    6558 }
    6559 else
    6560 {
    6561 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    6562 SCIPrationalMult(tmprational, cutaj, SCIPvarGetLbLocalExact(var));
    6563 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
    6564 }
    6565 }
    6566 else
    6567 {
    6568 /* upper bound was used */
    6569 if( boundtype[i] == -1 )
    6570 {
    6572 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    6573 SCIPrationalMult(tmprational, cutaj, SCIPvarGetUbGlobalExact(var));
    6574 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
    6575 }
    6576 else
    6577 {
    6578 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    6579 SCIPrationalMult(tmprational, cutaj, SCIPvarGetUbLocalExact(var));
    6580 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
    6581 }
    6582 }
    6583
    6584 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
    6586 }
    6587 else
    6588 {
    6589#ifdef SCIP_DISABLED_CODE
    6590 SCIP_VAR** vbz;
    6591 SCIP_Real* vbb;
    6592 SCIP_Real* vbd;
    6593 SCIP_Real QUAD(zcoef);
    6594 int vbidx;
    6595 int zidx;
    6596
    6597 assert(!SCIPisExact(scip));
    6598
    6599 /* variable bound */
    6600 vbidx = boundtype[i];
    6601
    6602 /* change mirrhs and cutaj of integer variable z_j of variable bound */
    6603 if( varsign[i] == +1 )
    6604 {
    6605 /* variable lower bound was used */
    6606 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
    6607 vbz = SCIPvarGetVlbVars(var);
    6608 vbb = SCIPvarGetVlbCoefs(var);
    6609 vbd = SCIPvarGetVlbConstants(var);
    6610 }
    6611 else
    6612 {
    6613 /* variable upper bound was used */
    6614 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
    6615 vbz = SCIPvarGetVubVars(var);
    6616 vbb = SCIPvarGetVubCoefs(var);
    6617 vbd = SCIPvarGetVubConstants(var);
    6618 }
    6619 assert(SCIPvarIsActive(vbz[vbidx]));
    6620 zidx = SCIPvarGetProbindex(vbz[vbidx]);
    6621 assert(0 <= zidx && zidx < firstcontvar);
    6622
    6623 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
    6624 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
    6625
    6626 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
    6627 QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
    6628
    6629 /* update sparsity pattern */
    6630 if( QUAD_HI(zcoef) == 0.0 )
    6631 cutinds[(*nnz)++] = zidx;
    6632
    6633 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
    6634 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
    6635 QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
    6636 assert(QUAD_HI(zcoef) != 0.0);
    6637#endif
    6638 }
    6639
    6640 /* advance to next variable */
    6641 --i;
    6642 }
    6643
    6644 /* fill the empty position due to deleted continuous variables */
    6645 if( ndelcontvars > 0 )
    6646 {
    6647 assert(ndelcontvars <= *nnz);
    6648 *nnz -= ndelcontvars;
    6649 if( *nnz < ndelcontvars )
    6650 {
    6651 BMScopyMemoryArray(cutinds, cutinds + ndelcontvars, *nnz);
    6652 }
    6653 else
    6654 {
    6655 BMScopyMemoryArray(cutinds, cutinds + *nnz, ndelcontvars);
    6656 }
    6657 }
    6658
    6659 /* reset rounding mode, also set the rhs->data in the mirinfo */
    6660 SCIPintervalSetRoundingMode(previousroundmode);
    6661
    6663 SCIPrationalFreeBuffer(SCIPbuffer(scip), &onedivoneminusf0);
    6664
    6665 return SCIP_OKAY;
    6666}
    6667#endif
    6668
    6669
    6670/** Calculate fractionalities \f$ f_0 := b - down(b), f_j := a^\prime_j - down(a^\prime_j) \f$, and derive MIR cut \f$ \tilde{a} \cdot x' \leq down(b) \f$
    6671 * \f[
    6672 * \begin{array}{rll}
    6673 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
    6674 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
    6675 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
    6676 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
    6677 * \end{array}
    6678 * \f]
    6679 *
    6680 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
    6681 *
    6682 * (lb or ub):
    6683 * \f[
    6684 * \begin{array}{lllll}
    6685 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{if lb was used in transformation} \\
    6686 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{if ub was used in transformation}
    6687 * \end{array}
    6688 * \f]
    6689 * and move the constant terms
    6690 * \f[
    6691 * \begin{array}{cl}
    6692 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
    6693 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
    6694 * \end{array}
    6695 * \f]
    6696 * to the rhs.
    6697 *
    6698 * (vlb or vub):
    6699 * \f[
    6700 * \begin{array}{lllll}
    6701 * x^\prime_j := x_j - (bl_j \cdot zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{(vlb)} \\
    6702 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{(vub)}
    6703 * \end{array}
    6704 * \f]
    6705 * move the constant terms
    6706 * \f[
    6707 * \begin{array}{cl}
    6708 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
    6709 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
    6710 * \end{array}
    6711 * \f]
    6712 * to the rhs, and update the VB variable coefficients:
    6713 * \f[
    6714 * \begin{array}{ll}
    6715 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
    6716 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
    6717 * \end{array}
    6718 * \f]
    6719 */
    6720static
    6722 SCIP* scip, /**< SCIP data structure */
    6723 MIR_DATA* data, /**< the MIR data structure for this cut */
    6724 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
    6725 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
    6726 QUAD(SCIP_Real f0) /**< fractional value of rhs */
    6727 )
    6728{
    6729 SCIP_Real QUAD(tmp);
    6730 SCIP_Real QUAD(onedivoneminusf0);
    6731 int s;
    6732 int cutindex;
    6733 int i;
    6734
    6735 assert(data != NULL);
    6736 assert(boundtype != NULL);
    6737 assert(varsign != NULL);
    6738 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
    6739
    6740 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
    6741 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
    6742
    6743 /* Loop backwards through the sections, so that the reversing of varbound substitutions does not prematurely effect
    6744 * the coefficients of variables in other sections, because the section index of a variable bound must always be
    6745 * higher than that of the bounded variable. */
    6746 cutindex = data->ncutinds - 1;
    6747 for( s = NSECTIONS - 1; s >= 0; --s )
    6748 {
    6749 int* indices = data->secindices[s];
    6750 int nnz = data->secnnz[s];
    6751
    6752 SCIP_Bool enfintegral = data->isenfint[s];
    6753 SCIP_Bool implintegral = data->isimplint[s];
    6754
    6755 /* iterate backwards over indices in section, so we can easily shrink the section if we find zeros */
    6756 for( i = nnz - 1; i >= 0 ; --i )
    6757 {
    6758 int v;
    6759 int sign;
    6760 int type;
    6761 SCIP_Real QUAD(cutaj);
    6762 SCIP_Real QUAD(aj);
    6763 SCIP_VAR* var;
    6764
    6765 v = indices[i];
    6766 assert(0 <= v && v < data->nvars);
    6767 assert(data->cutinds[cutindex] == v);
    6768
    6769 sign = varsign[cutindex];
    6770 assert(sign == +1 || sign == -1);
    6771 type = boundtype[cutindex];
    6772
    6773 --cutindex;
    6774
    6775 var = data->vars[v];
    6776 assert(var != NULL);
    6777 assert(SCIPvarGetProbindex(var) == v );
    6778
    6779 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
    6780
    6781 if( enfintegral || implintegral )
    6782 {
    6783 /* variable is integral */
    6784 SCIP_Real QUAD(downaj);
    6785 SCIP_Real QUAD(fj);
    6786
    6787 QUAD_SCALE(aj, sign);
    6788
    6789 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
    6790 SCIPquadprecSumQQ(fj, aj, -downaj);
    6791 assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
    6792
    6793 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
    6794 {
    6795 QUAD_ASSIGN_Q(cutaj, downaj); /* a^_j */
    6796 }
    6797 else
    6798 {
    6799 SCIPquadprecSumQQ(tmp, fj, -f0);
    6800 SCIPquadprecProdQQ(tmp, tmp, onedivoneminusf0);
    6801 SCIPquadprecSumQQ(cutaj, tmp, downaj);
    6802 }
    6803 QUAD_SCALE(cutaj, sign);
    6804 }
    6805 else
    6806 {
    6807 /* variable is continuous */
    6809
    6810 if( QUAD_TO_DBL(aj) * sign >= 0.0 )
    6811 QUAD_ASSIGN(cutaj, 0.0);
    6812 else
    6813 SCIPquadprecProdQQ(cutaj, onedivoneminusf0, aj); /* cutaj = aj * onedivoneminusf0 */
    6814 }
    6815
    6816 /* remove coefficient from cut if it becomes zero */
    6817 if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
    6818 {
    6819 QUAD_ASSIGN(cutaj, 0.0);
    6820 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
    6821 --data->totalnnz;
    6822 --data->secnnz[s];
    6823 indices[i] = indices[data->secnnz[s]];
    6824 continue;
    6825 }
    6826
    6827 /* store the updated coefficient */
    6828 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
    6829
    6830 /* undo bound transformations */
    6831 if( type < 0 )
    6832 {
    6833 /* standard bound */
    6834 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    6835 if( sign == +1 )
    6836 {
    6837 /* lower bound was used */
    6838 if( type == -1 )
    6839 {
    6840 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    6841 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
    6842 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    6843 }
    6844 else
    6845 {
    6846 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    6847 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
    6848 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    6849 }
    6850 }
    6851 else
    6852 {
    6853 /* upper bound was used */
    6854 if( type == -1 )
    6855 {
    6856 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    6857 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
    6858 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    6859 }
    6860 else
    6861 {
    6862 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    6863 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
    6864 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    6865 }
    6866 }
    6867 }
    6868 else
    6869 {
    6870 /* variable bound */
    6871 SCIP_VAR** vbz;
    6872 SCIP_Real* vbb;
    6873 SCIP_Real* vbd;
    6874 SCIP_Real QUAD(zcoef);
    6875 int vbidx;
    6876 int zidx;
    6877
    6878 /* variable bound */
    6879 vbidx = type;
    6880
    6881 /* change mirrhs and cutaj of integer variable z_j of variable bound */
    6882 if( sign == +1 )
    6883 {
    6884 /* variable lower bound was used */
    6885 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
    6886 vbz = SCIPvarGetVlbVars(var);
    6887 vbb = SCIPvarGetVlbCoefs(var);
    6888 vbd = SCIPvarGetVlbConstants(var);
    6889 }
    6890 else
    6891 {
    6892 /* variable upper bound was used */
    6893 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
    6894 vbz = SCIPvarGetVubVars(var);
    6895 vbb = SCIPvarGetVubCoefs(var);
    6896 vbd = SCIPvarGetVubConstants(var);
    6897 }
    6898 assert(SCIPvarIsActive(vbz[vbidx]));
    6899 zidx = SCIPvarGetProbindex(vbz[vbidx]);
    6900 assert(varSection(data, zidx) > s);
    6901
    6902 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
    6903 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    6904
    6905 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
    6906 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
    6907
    6908 /* update sparsity pattern */
    6909 if( QUAD_HI(zcoef) == 0.0 )
    6910 {
    6911 int zsection = varSection(data, zidx);
    6912 data->secindices[zsection][data->secnnz[zsection]] = zidx;
    6913 ++data->secnnz[zsection];
    6914 ++data->totalnnz;
    6915 }
    6916
    6917 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
    6918 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
    6919 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
    6920 assert(QUAD_HI(zcoef) != 0.0);
    6921 }
    6922 }
    6923 }
    6924
    6925 /* Finally, store the relevant data in cutinds which is the array used by the other functions */
    6926 data->ncutinds = 0;
    6927 for( s = 0; s < NSECTIONS; ++s )
    6928 {
    6929 int* indices = data->secindices[s];
    6930 int nnz = data->secnnz[s];
    6931 for( i = 0; i < nnz; ++i )
    6932 {
    6933 data->cutinds[data->ncutinds] = indices[i];
    6934 ++data->ncutinds;
    6935 }
    6936 }
    6937 return SCIP_OKAY;
    6938}
    6939
    6940/** substitute aggregated slack variables:
    6941 *
    6942 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    6943 * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r]. \f$
    6944 *
    6945 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    6946 * \f[
    6947 * \begin{array}{rll}
    6948 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r \leq f_0 \\
    6949 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f_0)/(1 - f_0),& \mbox{if}\qquad f_r > f_0 \\
    6950 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r \geq 0 \\
    6951 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f_0), & \mbox{if}\qquad a^\prime_r < 0
    6952 * \end{array}
    6953 * \f]
    6954 *
    6955 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
    6956 *
    6957 * @note this method is safe for usage in exact solving mode
    6958 *
    6959 * @todo certify and use integrality of row in exact solving mode
    6960 *
    6961 * @todo make behavior identical to the unsafe MIR cut computation
    6962 */
    6963static
    6965 SCIP* scip, /**< SCIP data structure */
    6966 SCIP_Real* weights, /**< row weights in row summation */
    6967 int* slacksign, /**< stores the sign of the row's slack variable in summation */
    6968 int* rowinds, /**< sparsity pattern of used rows */
    6969 int nrowinds, /**< number of used rows */
    6970 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
    6971 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    6972 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
    6973 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    6974 int* nnz, /**< number of non-zeros in cut */
    6975 SCIP_INTERVAL f0 /**< fractional value of rhs */
    6976 )
    6977{ /*lint --e{715}*/
    6978 SCIP_ROW** rows;
    6979 SCIP_ROW* userow;
    6980 SCIP_ROWEXACT* rowexact;
    6981 SCIP_INTERVAL onedivoneminusf0, tmpinterval;
    6982 SCIP_ROUNDMODE previousroundmode;
    6983 SCIP_AGGREGATIONINFO* aggrinfo = NULL;
    6984 SCIP_MIRINFO* mirinfo = NULL;
    6985 SCIP_Real mult;
    6986 SCIP_Real splitcoef;
    6987 SCIP_Real slackweight;
    6988 SCIP_Bool slackroundeddown;
    6989 int i;
    6990 int currentnegslackrow;
    6991
    6992 assert(scip != NULL);
    6993 assert(weights != NULL || nrowinds == 0);
    6994 assert(slacksign != NULL || nrowinds == 0);
    6995 assert(rowinds != NULL || nrowinds == 0);
    6996 assert(scale > 0.0);
    6997 assert(cutcoefs != NULL);
    6998 assert(cutrhs != NULL);
    6999 assert(cutinds != NULL);
    7000 assert(nnz != NULL);
    7001 assert(0.0 < SCIPintervalGetInf(f0) && SCIPintervalGetSup(f0) < 1.0);
    7002
    7003 assert(SCIPisExact(scip));
    7004
    7005 /* compute 1/(1-f0) in interval arithmetic */
    7006 previousroundmode = SCIPintervalGetRoundingMode();
    7008 SCIPintervalAddScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, 1.0);
    7009 SCIPintervalSet(&onedivoneminusf0, 1.0);
    7010 SCIPintervalDiv(SCIPinfinity(scip), &onedivoneminusf0, onedivoneminusf0, tmpinterval);
    7011
    7012 if( SCIPisCertified(scip) )
    7013 {
    7016 }
    7017
    7018 rows = SCIPgetLPRows(scip);
    7019 currentnegslackrow = 0;
    7020 for( i = 0; i < nrowinds; i++ )
    7021 {
    7022 SCIP_ROW* row;
    7023 SCIP_INTERVAL ar;
    7024 SCIP_INTERVAL cutar;
    7025 int r;
    7026 SCIP_Bool integralslack = FALSE;
    7027
    7028 r = rowinds[i]; /*lint !e613*/
    7029 assert(0 <= r && r < SCIPgetNLPRows(scip));
    7030 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
    7031 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
    7032
    7033 row = rows[r];
    7034 assert(row != NULL);
    7035 assert(row->len == 0 || row->cols != NULL);
    7036 assert(row->len == 0 || row->cols_index != NULL);
    7037 assert(row->len == 0 || row->vals != NULL);
    7038
    7039 if( slacksign[i] == 1 )
    7041 else
    7043
    7044 /* get the slack's coefficient a'_r = weights[i] * scale in the aggregated row */
    7045 SCIPintervalSet(&ar, weights[i]);
    7046 SCIPintervalMulScalar(SCIPinfinity(scip), &ar, ar, scale);
    7047 SCIPintervalMulScalar(SCIPinfinity(scip), &ar, ar, (double) slacksign[i]);
    7048
    7049 /* calculate slack variable's coefficient a^_r in the cut */
    7050 if( row->integral &&
    7051 ((slacksign[i] == +1 && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant))
    7052 || (slacksign[i] == -1 && SCIPrealIsExactlyIntegral(row->lhs) && SCIPrealIsExactlyIntegral(row->constant))) ) /*lint !e613*/
    7053 {
    7054 /* slack variable is always integral:
    7055 * a^_r = a~_r = down(a'_r) , if f_r <= f0
    7056 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    7057 */
    7058 SCIP_Real downar;
    7059 SCIP_INTERVAL fr;
    7060
    7061 SCIPdebugMessage("resubstituting integer slack for row %s\n", row->name);
    7062 downar = floor(ar.inf);
    7063 SCIPintervalSubScalar(SCIPinfinity(scip), &fr, ar, downar);
    7064
    7065 integralslack = TRUE;
    7066
    7067 if( SCIPisLE(scip, fr.inf, f0.inf) )
    7068 {
    7069 SCIPintervalSet(&cutar, downar);
    7070 splitcoef = downar;
    7071 slackweight = weights[i];
    7072 slackroundeddown = TRUE;
    7073 SCIPintervalMul(SCIPinfinity(scip), &fr, fr, onedivoneminusf0);
    7074 SCIPdebugMessage("fractionality %g, f0 %g -> round down to %g\n", fr.inf, f0.inf, splitcoef);
    7075 }
    7076 else
    7077 {
    7078 SCIPintervalSetBounds(&cutar, ar.inf, ar.sup);
    7079 SCIPintervalSubScalar(SCIPinfinity(scip), &cutar, cutar, downar);
    7080 SCIPintervalSub(SCIPinfinity(scip), &cutar, cutar, f0);
    7081 SCIPintervalMul(SCIPinfinity(scip), &cutar, cutar, onedivoneminusf0);
    7082 SCIPintervalAddScalar(SCIPinfinity(scip), &cutar, cutar, downar);
    7083 splitcoef = downar + 1;
    7084 slackweight = weights[i];
    7085 slackroundeddown = FALSE;
    7086 SCIPdebugMessage("fractionality %g, f0 %g -> round up! splitcoef %g sub-coefficient %g", fr.inf, f0.inf, splitcoef, cutar.inf);
    7087 }
    7088 }
    7089 else
    7090 {
    7091 /* slack variable is continuous:
    7092 * a^_r = a~_r = 0 , if a'_r >= 0
    7093 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    7094 */
    7095 if( SCIPintervalGetInf(ar) >= 0.0 )
    7096 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
    7097 else
    7098 {
    7099 SCIPintervalMul(SCIPinfinity(scip), &cutar, onedivoneminusf0, ar); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
    7100 SCIPdebugMessage("resubstituting negative continuous slack for row %s with coef %g\n", row->name, cutar.inf);
    7101 }
    7102 }
    7103
    7104 rowexact = SCIProwGetRowExact(row);
    7105 assert(SCIProwExactHasFpRelax(rowexact));
    7106 if( SCIProwExactGetRowRhs(rowexact) != NULL && slacksign[i] == 1.0 )
    7107 userow = SCIProwExactGetRowRhs(rowexact);
    7108 else
    7109 userow = row;
    7110
    7111 SCIPintervalMulScalar(SCIPinfinity(scip), &cutar, cutar, (double) -slacksign[i]);
    7112
    7113 if( slacksign[i] == -1 )
    7114 mult = cutar.inf;
    7115 else
    7116 mult = cutar.sup;
    7117
    7118 if( SCIPisCertified(scip) && integralslack) /*lint --e{644}*/
    7119 {
    7120 assert(mirinfo != NULL);
    7121 /* save the value for the split disjunction for the integer slack and the continous part (for rounded up we
    7122 * subtract 1-f); multiply by -slacksign (same as above) since slack = side - row
    7123 */
    7124 mirinfo->slackrows[mirinfo->nslacks] = userow;
    7125 SCIP_CALL( SCIPcaptureRow(scip, userow) );
    7126 mirinfo->slackcoefficients[mirinfo->nslacks] = splitcoef * (-slacksign[i]);
    7127 mirinfo->slacksign[mirinfo->nslacks] = slacksign[i];
    7128 assert(SCIPrealIsExactlyIntegral(splitcoef));
    7129 mirinfo->slackweight[mirinfo->nslacks] = slackweight;
    7130 mirinfo->slackscale[mirinfo->nslacks] = scale;
    7131 mirinfo->slackusedcoef[mirinfo->nslacks] = mult;
    7132
    7133 /* save the value that goes into the certificate aggregation row (either downar or ar) */
    7134 mirinfo->slackroundeddown[mirinfo->nslacks] = slackroundeddown;
    7135 if( slackroundeddown )
    7136 mirinfo->nrounddownslacks++;
    7137 mirinfo->nslacks++;
    7138 }
    7139
    7140 /* if the coefficient was reduced to zero, ignore the slack variable */
    7141 if( EPSZ(SCIPintervalGetInf(cutar), QUAD_EPSILON) && (SCIPintervalGetInf(cutar) >= 0.0) )
    7142 continue;
    7143
    7144 /* depending on the slack's sign, we have
    7145 * - sign = 1: s = rhs - a^Tx >= 0
    7146 * - sign = -1: s = lhs - a^Tx <= 0
    7147 */
    7148 {
    7149 SCIP_Bool success = TRUE;
    7150 SCIP_Real sidevalchg;
    7151
    7152 if( SCIPisCertified(scip) && !integralslack )
    7153 {
    7154 assert(aggrinfo != NULL);
    7155 assert(aggrinfo->negslackweights[currentnegslackrow] == -weights[i]); /*lint !e777*/
    7156 aggrinfo->substfactor[currentnegslackrow] = mult;
    7157 currentnegslackrow++;
    7158 }
    7159
    7160 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, cutinds, cutcoefs, nnz, userow, mult, &sidevalchg, &success) );
    7161 assert(success);
    7162
    7163 /* move to rhs -> need to round up */
    7165 *cutrhs += sidevalchg;
    7166 }
    7167
    7168 /* move slack's constant to the right hand side */
    7169 if( slacksign[i] == +1 ) /*lint !e613*/
    7170 {
    7171 SCIP_INTERVAL rowrhs;
    7172
    7174 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
    7175 assert(!SCIPisInfinity(scip, userow->rhs));
    7176 SCIPintervalSet(&rowrhs, userow->rhs);
    7177 SCIPintervalSubScalar(SCIPinfinity(scip), &rowrhs, rowrhs, userow->constant);
    7178#ifdef SCIP_DISABLED_CODE
    7179 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
    7180 if( row->integral )
    7181 {
    7182 /* the right hand side was implicitly rounded down in row aggregation */
    7183 QUAD_ASSIGN(rowrhs, floor(QUAD_TO_DBL(rowrhs)));
    7184 }
    7185#endif
    7186 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, cutar, rowrhs);
    7187 *cutrhs += SCIPintervalGetSup(tmpinterval);
    7188 }
    7189 else
    7190 {
    7191 SCIP_INTERVAL rowlhs;
    7192
    7194 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
    7195 assert(!SCIPisInfinity(scip, -userow->lhs));
    7196 SCIPintervalSet(&rowlhs, userow->lhs);
    7197 SCIPintervalSubScalar(SCIPinfinity(scip), &rowlhs, rowlhs, userow->constant);
    7198#ifdef SCIP_DISABLED_CODE
    7199 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
    7200 if( row->integral )
    7201 {
    7202 /* the left hand side was implicitly rounded up in row aggregation */
    7203 QUAD_ASSIGN(rowlhs, floor(QUAD_TO_DBL(rowlhs)));
    7204 }
    7205#endif
    7206 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, cutar, rowlhs);
    7207 *cutrhs += SCIPintervalGetSup(tmpinterval);
    7208 }
    7209 }
    7210
    7211 /* relax rhs to zero, if it's very close to 0 */
    7212 if( *cutrhs < 0.0 && *cutrhs >= SCIPepsilon(scip) )
    7213 *cutrhs = 0.0;
    7214
    7215 SCIPintervalSetRoundingMode(previousroundmode);
    7216
    7217 return SCIP_OKAY;
    7218}
    7219
    7220#ifdef SCIP_DISABLED_CODE
    7221/** substitute aggregated slack variables:
    7222 *
    7223 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    7224 * variable only appears in its own row: \f$ a^\prime_r = scale * weight[r] * slacksign[r]. \f$
    7225 *
    7226 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    7227 * \f[
    7228 * \begin{array}{rll}
    7229 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r <= f0 \\
    7230 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f0)/(1 - f0),& \mbox{if}\qquad f_r > f0 \\
    7231 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r >= 0 \\
    7232 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f0), & \mbox{if}\qquad a^\prime_r < 0
    7233 * \end{array}
    7234 * \f]
    7235 *
    7236 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
    7237 *
    7238 * @note this method is safe for usage in exact solving mode
    7239 */
    7240static
    7241SCIP_RETCODE cutsSubstituteMIRRational(
    7242 SCIP* scip, /**< SCIP data structure */
    7243 SCIP_Real* weights, /**< row weights in row summation */
    7244 int* slacksign, /**< stores the sign of the row's slack variable in summation */
    7245 int* rowinds, /**< sparsity pattern of used rows */
    7246 int nrowinds, /**< number of used rows */
    7247 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
    7248 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    7249 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
    7250 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    7251 int* nnz, /**< number of non-zeros in cut */
    7252 SCIP_RATIONAL* f0 /**< fractional value of rhs */
    7253 )
    7254{ /*lint --e{715}*/
    7255 SCIP_ROW** rows;
    7256 SCIP_ROW* userow;
    7257 SCIP_ROWEXACT* rowexact;
    7258 SCIP_RATIONAL* onedivoneminusf0;
    7259 SCIP_RATIONAL* tmprational;
    7260 SCIP_ROUNDMODE previousroundmode;
    7261 SCIP_AGGREGATIONINFO* aggrinfo;
    7262 SCIP_Real mult;
    7263 int i;
    7264 int currentnegslackrow;
    7265 SCIP_RATIONAL* ar;
    7266 SCIP_RATIONAL* cutar;
    7267 int r;
    7268
    7269 assert(scip != NULL);
    7270 assert(weights != NULL || nrowinds == 0);
    7271 assert(slacksign != NULL || nrowinds == 0);
    7272 assert(rowinds != NULL || nrowinds == 0);
    7273 assert(scale > 0.0);
    7274 assert(cutcoefs != NULL);
    7275 assert(QUAD_HI(cutrhs) != NULL);
    7276 assert(cutinds != NULL);
    7277 assert(nnz != NULL);
    7278 assert(SCIPisExact(scip));
    7279
    7281 SCIP_CALL( SCIPrationalCreateBuffer(SCIPbuffer(scip), &onedivoneminusf0) );
    7284
    7285 /* compute 1/(1-f0) in interval arithmetic */
    7286 previousroundmode = SCIPintervalGetRoundingMode();
    7287 SCIPrationalMultReal(onedivoneminusf0, f0, -1);
    7288 SCIPrationalAddReal(onedivoneminusf0, onedivoneminusf0, 1.0);
    7289 SCIPrationalInvert(onedivoneminusf0, onedivoneminusf0);
    7290
    7291 if( SCIPisCertified(scip) )
    7292 {
    7294 }
    7295
    7296 rows = SCIPgetLPRows(scip);
    7297 currentnegslackrow = 0;
    7298 for( i = 0; i < nrowinds; i++ )
    7299 {
    7300 SCIP_ROW* row;
    7301
    7302 r = rowinds[i]; /*lint !e613*/
    7303 assert(0 <= r && r < SCIPgetNLPRows(scip));
    7304 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
    7305 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
    7306
    7307 row = rows[r];
    7308 assert(row != NULL);
    7309 assert(row->len == 0 || row->cols != NULL);
    7310 assert(row->len == 0 || row->cols_index != NULL);
    7311 assert(row->len == 0 || row->vals != NULL);
    7312
    7313 if( slacksign[i] == 1 )
    7315 else
    7317
    7318 /* get the slack's coefficient a'_r = weights[i] * scale in the aggregated row */
    7319 SCIPrationalSetReal(ar, weights[i]);
    7320 SCIPrationalMultReal(ar, ar, scale);
    7321 SCIPrationalMultReal(ar, ar, slacksign[i]);
    7322
    7323 /* calculate slack variable's coefficient a^_r in the cut */
    7324#ifdef SCIP_DISABLED_CODE
    7325 if( row->integral && !SCIPisExact(scip)
    7326 && ((slacksign[i] == +1 && SCIPisFeasIntegral(scip, row->rhs - row->constant))
    7327 || (slacksign[i] == -1 && SCIPisFeasIntegral(scip, row->lhs - row->constant))) ) /*lint !e613*/
    7328 {
    7329 /* slack variable is always integral:
    7330 * a^_r = a~_r = down(a'_r) , if f_r <= f0
    7331 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    7332 */
    7333 if( !SCIPisExact(scip) )
    7334 downar = EPSFLOOR(ar, QUAD_EPSILON);
    7335 else
    7336 downar = floor(ar);
    7337
    7338 SCIPquadprecSumDD(fr, ar, -downar);
    7339 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) && (!SCIPisExact(scip) || QUAD_TO_DBL(fr) <= QUAD_TO_DBL(f0)) )
    7340 {
    7341 QUAD_ASSIGN(cutar, downar);
    7342 }
    7343 else
    7344 {
    7345 SCIPquadprecSumQQ(cutar, fr, -f0);
    7346 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
    7347 SCIPquadprecSumQD(cutar, cutar, downar);
    7348 }
    7349 }
    7350 else
    7351#endif
    7352 {
    7353 /* slack variable is continuous:
    7354 * a^_r = a~_r = 0 , if a'_r >= 0
    7355 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    7356 */
    7357 if( !SCIPrationalIsNegative(ar) )
    7358 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
    7359 else
    7360 {
    7361 SCIPrationalMult(cutar, ar, onedivoneminusf0); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
    7362 }
    7363 }
    7364
    7365 /* if the coefficient was reduced to zero, ignore the slack variable */
    7366 if( SCIPrationalIsZero(cutar) )
    7367 continue;
    7368
    7369 /* depending on the slack's sign, we have
    7370 * sign = 1: s = rhs - a^Tx >= 0
    7371 sign = -1: s = lhs - a^Tx <= 0
    7372 */
    7373
    7374 rowexact = SCIProwGetRowExact(row);
    7375 assert(SCIProwExactHasFpRelax(rowexact));
    7376 if( SCIProwExactGetRowRhs(rowexact) != NULL && slacksign[i] == 1.0 )
    7377 userow = SCIProwExactGetRowRhs(rowexact);
    7378 else
    7379 userow = row;
    7380
    7381 {
    7382 SCIP_Bool success = TRUE;
    7383 SCIP_Real sidevalchg;
    7384
    7385 SCIPrationalMultReal(cutar, cutar, -slacksign[i]);
    7386 if( slacksign[i] == -1 )
    7388 else
    7390
    7391 if( SCIPisCertified(scip) )
    7392 {
    7393 assert(aggrinfo->negslackweights[currentnegslackrow] == -weights[i]);
    7394 aggrinfo->substfactor[currentnegslackrow] = mult;
    7395 currentnegslackrow++;
    7396 }
    7397
    7398 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, cutinds, cutcoefs, nnz, userow, mult, &sidevalchg, &success) );
    7399 assert(success);
    7400
    7401 /* move to rhs -> need to round up */
    7403 *cutrhs += sidevalchg;
    7404 }
    7405
    7406 /* move slack's constant to the right hand side */
    7407 if( slacksign[i] == +1 ) /*lint !e613*/
    7408 {
    7409 SCIP_INTERVAL valinterval;
    7410 SCIP_INTERVAL cutarinterval;
    7411
    7413 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
    7414 assert(!SCIPisInfinity(scip, userow->rhs));
    7415#ifdef SCIP_DISABLED_CODE
    7416 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
    7417 if( row->integral )
    7418 {
    7419 /* the right hand side was implicitly rounded down in row aggregation */
    7420 QUAD_ASSIGN(rowrhs, floor(QUAD_TO_DBL(rowrhs)));
    7421 }
    7422#endif
    7423 SCIPintervalSet(&valinterval, userow->rhs);
    7424 SCIPintervalSubScalar(SCIPinfinity(scip), &valinterval, valinterval, userow->constant);
    7425 SCIPintervalSetRational(&cutarinterval, cutar);
    7426 SCIPintervalMul(SCIPinfinity(scip), &valinterval, valinterval, cutarinterval);
    7427 SCIPquadprecSumQQ(*cutrhs, *cutrhs, SCIPintervalGetSup(valinterval));
    7428 }
    7429 else
    7430 {
    7431 SCIP_INTERVAL valinterval;
    7432 SCIP_INTERVAL cutarinterval;
    7433
    7435 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
    7436 assert(!SCIPisInfinity(scip, -userow->lhs));
    7437#ifdef SCIP_DISABLED_CODE
    7438 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
    7439 if( row->integral )
    7440 {
    7441 /* the left hand side was implicitly rounded up in row aggregation */
    7442 QUAD_ASSIGN(rowlhs, floor(QUAD_TO_DBL(rowlhs)));
    7443 }
    7444#endif
    7445 SCIPintervalSet(&valinterval, userow->lhs);
    7446 SCIPintervalSubScalar(SCIPinfinity(scip), &valinterval, valinterval, userow->constant);
    7447 SCIPintervalSetRational(&cutarinterval, cutar);
    7448 SCIPintervalMul(SCIPinfinity(scip), &valinterval, valinterval, cutarinterval);
    7449 SCIPquadprecSumQQ(*cutrhs, *cutrhs, SCIPintervalGetSup(valinterval));
    7450 }
    7451 }
    7452
    7453 /* relax rhs to zero, if it's very close to 0 */
    7454 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    7455 QUAD_ASSIGN(*cutrhs, 0.0);
    7456
    7457 if( SCIPisExact(scip) )
    7458 SCIPintervalSetRoundingMode(previousroundmode);
    7459
    7462
    7463 SCIPrationalFreeBuffer(SCIPbuffer(scip), &onedivoneminusf0);
    7464 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
    7465
    7466 return SCIP_OKAY;
    7467}
    7468#endif
    7469
    7470/** substitute aggregated slack variables:
    7471 *
    7472 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    7473 * variable only appears in its own row: \f$ a^\prime_r = scale * weight[r] * slacksign[r]. \f$
    7474 *
    7475 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    7476 * \f[
    7477 * \begin{array}{rll}
    7478 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r <= f0 \\
    7479 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f0)/(1 - f0),& \mbox{if}\qquad f_r > f0 \\
    7480 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r >= 0 \\
    7481 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f0), & \mbox{if}\qquad a^\prime_r < 0
    7482 * \end{array}
    7483 * \f]
    7484 *
    7485 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
    7486 */
    7487static
    7489 SCIP* scip, /**< SCIP data structure */
    7490 SCIP_Real* weights, /**< row weights in row summation */
    7491 int* slacksign, /**< stores the sign of the row's slack variable in summation */
    7492 int* rowinds, /**< sparsity pattern of used rows */
    7493 int nrowinds, /**< number of used rows */
    7494 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
    7495 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    7496 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
    7497 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    7498 int* nnz, /**< number of non-zeros in cut */
    7499 QUAD(SCIP_Real f0) /**< fractional value of rhs */
    7500 )
    7501{ /*lint --e{715}*/
    7502 SCIP_ROW** rows;
    7503 SCIP_Real QUAD(onedivoneminusf0);
    7504 int i;
    7505
    7506 assert(scip != NULL);
    7507 assert(weights != NULL || nrowinds == 0);
    7508 assert(slacksign != NULL || nrowinds == 0);
    7509 assert(rowinds != NULL || nrowinds == 0);
    7510 assert(scale > 0.0);
    7511 assert(cutcoefs != NULL);
    7512 assert(QUAD_HI(cutrhs) != NULL);
    7513 assert(cutinds != NULL);
    7514 assert(nnz != NULL);
    7515 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
    7516 assert(!SCIPisExact(scip));
    7517
    7518 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
    7519 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
    7520
    7521 rows = SCIPgetLPRows(scip);
    7522 for( i = 0; i < nrowinds; i++ )
    7523 {
    7524 SCIP_ROW* row;
    7525 SCIP_Real QUAD(ar);
    7526 SCIP_Real QUAD(downar);
    7527 SCIP_Real QUAD(cutar);
    7528 SCIP_Real QUAD(fr);
    7529 SCIP_Real QUAD(tmp);
    7530 SCIP_Real QUAD(myprod);
    7531 int r;
    7532
    7533 r = rowinds[i]; /*lint !e613*/
    7534 assert(0 <= r && r < SCIPgetNLPRows(scip));
    7535 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
    7536 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
    7537
    7538 row = rows[r];
    7539 assert(row != NULL);
    7540 assert(row->len == 0 || row->cols != NULL);
    7541 assert(row->len == 0 || row->cols_index != NULL);
    7542 assert(row->len == 0 || row->vals != NULL);
    7543
    7544 /* get the slack's coefficient a'_r in the aggregated row */
    7545 SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
    7546
    7547 /* calculate slack variable's coefficient a^_r in the cut */
    7548 if( row->integral )
    7549 {
    7550 /* slack variable is always integral:
    7551 * a^_r = a~_r = down(a'_r) , if f_r <= f0
    7552 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    7553 */
    7554 SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
    7555 SCIPquadprecSumQQ(fr, ar, -downar);
    7556 assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
    7557
    7558 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
    7559 QUAD_ASSIGN_Q(cutar, downar); /* a^_r */
    7560 else
    7561 {
    7562 SCIPquadprecSumQQ(cutar, fr, -f0);
    7563 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
    7564 SCIPquadprecSumQQ(cutar, cutar, downar);
    7565 }
    7566 }
    7567 else
    7568 {
    7569 /* slack variable is continuous:
    7570 * a^_r = a~_r = 0 , if a'_r >= 0
    7571 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    7572 */
    7573 if( QUAD_TO_DBL(ar) >= 0.0 )
    7574 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
    7575 else
    7576 SCIPquadprecProdQQ(cutar, onedivoneminusf0, ar);
    7577 }
    7578
    7579 /* if the coefficient was reduced to zero, ignore the slack variable */
    7580 if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
    7581 continue;
    7582
    7583 /* depending on the slack's sign, we have
    7584 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
    7585 * substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
    7586 */
    7587 SCIPquadprecProdQD(myprod, cutar, -slacksign[i]);
    7588
    7589 /* add the slack's definition multiplied with a^_j to the cut */
    7590 SCIP_CALL( varVecAddScaledRowCoefsQuadScale(cutinds, cutcoefs, nnz, row, QUAD(myprod)) );
    7591
    7592 /* move slack's constant to the right hand side */
    7593 if( slacksign[i] == +1 ) /*lint !e613*/
    7594 {
    7595 SCIP_Real QUAD(rowrhs);
    7596
    7597 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
    7598 assert(!SCIPisInfinity(scip, row->rhs));
    7599 QUAD_ASSIGN(rowrhs, row->rhs - row->constant);
    7600 if( row->integral )
    7601 {
    7602 /* the right hand side was implicitly rounded down in row aggregation */
    7603 SCIPquadprecEpsFloorQ(rowrhs, rowrhs, SCIPepsilon(scip)); /*lint !e666*/
    7604 }
    7605 SCIPquadprecProdQQ(tmp, myprod, rowrhs);
    7606 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
    7607 }
    7608 else
    7609 {
    7610 SCIP_Real QUAD(rowlhs);
    7611
    7612 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
    7613 assert(!SCIPisInfinity(scip, -row->lhs));
    7614 QUAD_ASSIGN(rowlhs, row->lhs - row->constant);
    7615 if( row->integral )
    7616 {
    7617 /* the left hand side was implicitly rounded up in row aggregation */
    7618 SCIPquadprecEpsCeilQ(rowlhs, rowlhs, SCIPepsilon(scip)); /*lint !e666*/
    7619 }
    7620 SCIPquadprecProdQQ(tmp, myprod, rowlhs);
    7621 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
    7622 }
    7623 }
    7624
    7625 /* relax rhs to zero, if it's very close to 0 */
    7626 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    7627 QUAD_ASSIGN(*cutrhs, 0.0);
    7628
    7629 return SCIP_OKAY;
    7630}
    7631
    7632/** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
    7633 * these rows cannot participate in an MIR cut.
    7634 *
    7635 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    7636 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    7637 *
    7638 * @pre This method can be called if @p scip is in one of the following stages:
    7639 * - \ref SCIP_STAGE_SOLVING
    7640 *
    7641 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    7642 *
    7643 * @note this method is safe for usage in exact solving mode
    7644 *
    7645 * @todo make behavior identical to the unsafe MIR cut computation
    7646 */
    7647static
    7649 SCIP* scip, /**< SCIP data structure */
    7650 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    7651 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
    7652 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    7653 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
    7654 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    7655 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    7656 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    7657 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    7658 * NULL for using closest bound for all variables */
    7659 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    7660 * NULL for using closest bound for all variables */
    7661 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
    7662 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
    7663 SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
    7664 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
    7665 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
    7666 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
    7667 int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
    7668 int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
    7669 SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
    7670 int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
    7671 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
    7672 SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
    7673 )
    7674{
    7675 int i;
    7676 int nvars;
    7677 int tmpnnz;
    7678 int* varsign;
    7679 int* boundtype;
    7680 int* tmpinds;
    7681 SCIP_Real* tmpcoefs;
    7682
    7683 SCIP_Real rhs;
    7684 SCIP_Real downrhs;
    7685 SCIP_Bool freevariable;
    7686 SCIP_Bool localbdsused;
    7687 SCIP_Bool tmpislocal;
    7688
    7689 SCIP_ROUNDMODE previousroundmode;
    7690 SCIP_INTERVAL f0interval;
    7691
    7692 assert(aggrrow != NULL);
    7693 assert(SCIPisPositive(scip, scale));
    7694 assert(SCIPisExact(scip));
    7695 assert(success != NULL);
    7696
    7697 SCIPdebugMsg(scip, "calculating MIR cut (scale: %g)\n", scale);
    7698
    7699 *success = FALSE;
    7700 *cutislocal = FALSE;
    7701
    7702 /* allocate temporary memory */
    7703 nvars = SCIPgetNVars(scip);
    7704 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
    7705 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
    7706 SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
    7707 SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, nvars) );
    7708
    7709 /* initialize cut with aggregation */
    7710 tmpnnz = aggrrow->nnz;
    7711 tmpislocal = aggrrow->local;
    7712
    7713 previousroundmode = SCIPintervalGetRoundingMode();
    7715
    7716 if( SCIPisCertified(scip) )
    7717 {
    7719 }
    7720
    7721 rhs = QUAD_TO_DBL(aggrrow->rhs) * scale;
    7722
    7723 if( tmpnnz > 0 )
    7724 {
    7725 BMScopyMemoryArray(tmpinds, aggrrow->inds, tmpnnz);
    7726
    7727 for( i = 0; i < tmpnnz; ++i )
    7728 {
    7729 SCIP_Real coef;
    7730 int k = aggrrow->inds[i];
    7731
    7732 coef = aggrrow->vals[k];
    7733 coef *= scale;
    7734 tmpcoefs[k] = coef;
    7735
    7736 assert(coef != 0.0);
    7737 }
    7738
    7739 SCIPdebugMsg(scip, "Initial row:\n");
    7740 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
    7741
    7742 /* Transform equation a*x == b, lb <= x <= ub into standard form
    7743 * a'*x' == b, 0 <= x' <= ub'.
    7744 *
    7745 * Transform variables (lb or ub):
    7746 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
    7747 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
    7748 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
    7749 *
    7750 * Transform variables (vlb or vub):
    7751 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
    7752 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
    7753 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
    7754 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
    7755 * a_{zu_j} := a_{zu_j} + a_j * bu_j
    7756 */
    7757 SCIP_CALL( cutsTransformMIRSafely(scip, sol, boundswitch, usevbds, allowlocal, fixintegralrhs, FALSE,
    7758 boundsfortrans, boundtypesfortrans, tmpcoefs, &rhs, tmpinds, &tmpnnz, varsign, boundtype, &freevariable, &localbdsused) );
    7759 assert(allowlocal || !localbdsused);
    7760 tmpislocal = tmpislocal || localbdsused;
    7761
    7762 if( freevariable )
    7763 goto TERMINATE;
    7764
    7765 SCIPdebugMsg(scip, "Aggregated and transformed:\n");
    7766 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
    7767 }
    7768
    7769 /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
    7770 * a~*x' <= down(b)
    7771 * integers : a~_j = down(a'_j) , if f_j <= f_0
    7772 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
    7773 * continuous: a~_j = 0 , if a'_j >= 0
    7774 * a~_j = a'_j/(1 - f0) , if a'_j < 0
    7775 *
    7776 * Transform inequality back to a^*x <= rhs:
    7777 *
    7778 * (lb or ub):
    7779 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
    7780 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
    7781 * and move the constant terms
    7782 * -a~_j * lb_j == -a^_j * lb_j, or
    7783 * a~_j * ub_j == -a^_j * ub_j
    7784 * to the rhs.
    7785 *
    7786 * (vlb or vub):
    7787 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
    7788 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
    7789 * move the constant terms
    7790 * -a~_j * dl_j == -a^_j * dl_j, or
    7791 * a~_j * du_j == -a^_j * du_j
    7792 * to the rhs, and update the VB variable coefficients:
    7793 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
    7794 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
    7795 */
    7796
    7797 downrhs = floor(rhs);
    7798
    7799 if( SCIPisCertified(scip) )
    7800 {
    7802 SCIPrationalSetReal(mirinfo->rhs, downrhs);
    7803 SCIPrationalSetReal(mirinfo->frac, rhs);
    7804 SCIPrationalDiffReal(mirinfo->frac, mirinfo->frac, downrhs);
    7805 }
    7806
    7807 SCIPintervalSet(&f0interval, rhs);
    7808 SCIPintervalSubScalar(SCIPinfinity(scip), &f0interval, f0interval, downrhs);
    7809
    7810 if( f0interval.inf < minfrac || f0interval.sup > maxfrac )
    7811 goto TERMINATE;
    7812
    7813 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
    7814 * If this gives a scalar that is very big, we better do not generate this cut.
    7815 */
    7816 if( REALABS(scale)/(1.0 - f0interval.inf) > MAXCMIRSCALE )
    7817 goto TERMINATE;
    7818
    7819 /* renormalize f0 value */
    7820 rhs = downrhs;
    7821
    7822 if( tmpnnz > 0 )
    7823 {
    7824 SCIP_CALL( cutsRoundMIRSafely(scip, tmpcoefs, &rhs, tmpinds, &tmpnnz, varsign, boundtype, f0interval) ); /*lint !e644*/
    7825
    7826 SCIPdebugMsg(scip, "After MIR rounding:\n");
    7827 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
    7828 }
    7829
    7830 /* substitute aggregated slack variables:
    7831 *
    7832 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    7833 * variable only appears in its own row:
    7834 * a'_r = scale * weight[r] * slacksign[r].
    7835 *
    7836 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    7837 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
    7838 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    7839 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
    7840 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    7841 *
    7842 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
    7843 */
    7844
    7845 SCIP_CALL( cutsSubstituteMIRSafely(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
    7846 aggrrow->nrows, scale, tmpcoefs, &rhs, tmpinds, &tmpnnz, f0interval) );
    7847
    7848 SCIPdebugMsg(scip, "After slack substitution:\n");
    7849 SCIPdebug( printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE) );
    7850
    7851 /* we work on rhs -> round up */
    7853
    7854 if( postprocess )
    7855 {
    7856 SCIP_CALL( postprocessCutSafely(scip, tmpislocal, tmpinds, tmpcoefs, &tmpnnz, &rhs, success) );
    7857 }
    7858 else
    7859 {
    7860 *success = !removeZerosSafely(scip, SCIPsumepsilon(scip), tmpcoefs, &rhs, tmpinds, &tmpnnz);
    7861 }
    7862
    7863 SCIPdebugMsg(scip, "After post processing:\n");
    7864 SCIPdebug( printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE) );
    7865
    7866 if( *success )
    7867 {
    7868 SCIP_Real mirefficacy = calcEfficacyDenseStorage(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz);
    7869
    7870 if( SCIPisEfficacious(scip, mirefficacy) && (cutefficacy == NULL || mirefficacy > *cutefficacy) )
    7871 {
    7872 BMScopyMemoryArray(cutinds, tmpinds, tmpnnz);
    7873 *cutnnz = tmpnnz;
    7874 *cutrhs = rhs;
    7875 *cutislocal = tmpislocal;
    7876
    7877 /* clean tmpcoefs and go back to double precision */
    7878 for( i = 0; i < *cutnnz; ++i )
    7879 {
    7880 int j = cutinds[i];
    7881
    7882 cutcoefs[i] = tmpcoefs[j];
    7883 tmpcoefs[j] = 0.0;
    7884 }
    7885
    7886 if( cutefficacy != NULL )
    7887 *cutefficacy = mirefficacy;
    7888
    7889 if( cutrank != NULL )
    7890 *cutrank = aggrrow->rank + 1;
    7891 }
    7892 else
    7893 {
    7894 *success = FALSE;
    7895 }
    7896 }
    7897
    7898 TERMINATE:
    7899
    7900 /* reset the rounding mode in exact mode */
    7901 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
    7902
    7903 if( !(*success) )
    7904 {
    7905 for( i = 0; i < tmpnnz; ++i )
    7906 {
    7907 tmpcoefs[tmpinds[i]] = 0.0;
    7908 }
    7909 }
    7910
    7911 /* free temporary memory */
    7912 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
    7913 SCIPfreeBufferArray(scip, &tmpinds);
    7914 SCIPfreeBufferArray(scip, &boundtype);
    7915 SCIPfreeBufferArray(scip, &varsign);
    7916
    7917 return SCIP_OKAY;
    7918}
    7919
    7920
    7921/** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
    7922 * these rows cannot participate in an MIR cut.
    7923 *
    7924 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    7925 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    7926 *
    7927 * @pre This method can be called if @p scip is in one of the following stages:
    7928 * - \ref SCIP_STAGE_SOLVING
    7929 *
    7930 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    7931 *
    7932 * @note this method is safe for usage in exact solving mode
    7933 */
    7935 SCIP* scip, /**< SCIP data structure */
    7936 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    7937 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
    7938 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    7939 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
    7940 * type substitution is allowed. The indices are: 0: continuous,
    7941 * 1: continuous implint., 2: integer implint, 3: binary implint,
    7942 * 4: integer, 5: binary */
    7943 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    7944 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    7945 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    7946 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    7947 * NULL for using closest bound for all variables */
    7948 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    7949 * NULL for using closest bound for all variables */
    7950 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
    7951 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
    7952 SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
    7953 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
    7954 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
    7955 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
    7956 int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
    7957 int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
    7958 SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
    7959 int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
    7960 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
    7961 SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
    7962 )
    7963{
    7964 MIR_DATA* data;
    7965 int* varsign;
    7966 int* boundtype;
    7967 SCIP_Real QUAD(downrhs);
    7968 SCIP_Real QUAD(f0);
    7969 SCIP_Bool freevariable;
    7970 SCIP_Bool localbdsused;
    7971 SCIP_Bool tmpislocal;
    7972
    7973 assert(aggrrow != NULL);
    7974 assert(SCIPisPositive(scip, scale));
    7975 assert(success != NULL);
    7976
    7977 if( SCIPisExact(scip) )
    7978 {
    7979 /* TODO: update exactSCIP cuts to behave identically with respect to implied integrality */
    7980 return calcMIRSafely(scip, sol, postprocess, boundswitch, vartypeusevbds > 0 ? TRUE : FALSE, allowlocal, fixintegralrhs,
    7981 boundsfortrans, boundtypesfortrans, minfrac, maxfrac, scale, aggrrow, cutcoefs, cutrhs,
    7982 cutinds, cutnnz, cutefficacy, cutrank, cutislocal, success);
    7983 }
    7984 SCIPdebugMsg(scip, "calculating MIR cut (scale: %g)\n", scale);
    7985
    7986 *success = FALSE;
    7987
    7988 /* Setup data to track cut and initialize the cut with aggregation */
    7989 int l;
    7990 int nnz;
    7991
    7992 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
    7993
    7994 SCIP_CALL( SCIPallocBuffer(scip, &data) );
    7995
    7996 nnz = aggrrow->nnz;
    7997 data->totalnnz = nnz;
    7998
    7999 /* initialize sections */
    8000 for( l = 0; l < NSECTIONS; ++l )
    8001 {
    8002 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
    8003 data->secnnz[l] = 0;
    8004 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
    8005 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
    8006 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
    8007 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
    8008 /* Use variable bounds for the sections specified by the user */
    8009 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
    8010 }
    8011
    8012 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
    8013 data->vars = SCIPgetVars(scip);
    8014 data->nvars = SCIPgetNVars(scip);
    8015 data->nbinvars = SCIPgetNBinVars(scip);
    8016 data->nintvars = SCIPgetNIntVars(scip);
    8021
    8023 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
    8024
    8025 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, scale);
    8026
    8027 if( nnz > 0 )
    8028 {
    8029 /* Initalize cut with the aggregation */
    8030 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
    8031
    8032 for( l = 0; l < nnz; ++l )
    8033 {
    8034 SCIP_Real QUAD(coef);
    8035 int m = aggrrow->inds[l];
    8036
    8037 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
    8038
    8039 SCIPquadprecProdQD(coef, coef, scale);
    8040
    8041 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
    8042
    8043 assert(QUAD_HI(coef) != 0.0);
    8044 }
    8045
    8046 /* Sort the array by problem index and add the variables to their sections */
    8047 SCIPsortDownInt(data->cutinds, nnz);
    8048 for( l = 0; l < nnz; ++l )
    8049 {
    8050 int section = varSection(data, data->cutinds[l]);
    8051 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
    8052 ++data->secnnz[section];
    8053 }
    8054 }
    8055
    8056 SCIPdebugMsg(scip, "Initial row:\n");
    8057 SCIPdebug( printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, nnz, FALSE, FALSE) );
    8058
    8059 data->ncutinds = 0;
    8060 tmpislocal = aggrrow->local;
    8061
    8062 /* allocate temporary memory */
    8063 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, data->nvars) );
    8064 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, data->nvars) );
    8065
    8066 /* Transform equation a*x == b, lb <= x <= ub into standard form
    8067 * a'*x' == b, 0 <= x' <= ub'.
    8068 *
    8069 * Transform variables (lb or ub):
    8070 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
    8071 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
    8072 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
    8073 *
    8074 * Transform variables (vlb or vub):
    8075 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
    8076 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
    8077 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
    8078 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
    8079 * a_{zu_j} := a_{zu_j} + a_j * bu_j
    8080 */
    8081 if( data->totalnnz > 0 )
    8082 {
    8083 SCIP_CALL( cutsTransformMIR(scip, data, sol, boundswitch, allowlocal, fixintegralrhs, FALSE,
    8084 boundsfortrans, boundtypesfortrans, minfrac, maxfrac,
    8085 varsign, boundtype, &freevariable, &localbdsused) );
    8086 assert(allowlocal || !localbdsused);
    8087 tmpislocal = tmpislocal || localbdsused;
    8088
    8089 if( freevariable )
    8090 goto TERMINATE;
    8091
    8092 SCIPdebugMsg(scip, "Aggregated and transformed:\n");
    8093 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    8094 }
    8095
    8096 /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
    8097 * a~*x' <= down(b)
    8098 * integers : a~_j = down(a'_j) , if f_j <= f_0
    8099 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
    8100 * continuous: a~_j = 0 , if a'_j >= 0
    8101 * a~_j = a'_j/(1 - f0) , if a'_j < 0
    8102 *
    8103 * Transform inequality back to a^*x <= rhs:
    8104 *
    8105 * (lb or ub):
    8106 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
    8107 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
    8108 * and move the constant terms
    8109 * -a~_j * lb_j == -a^_j * lb_j, or
    8110 * a~_j * ub_j == -a^_j * ub_j
    8111 * to the rhs.
    8112 *
    8113 * (vlb or vub):
    8114 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
    8115 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
    8116 * move the constant terms
    8117 * -a~_j * dl_j == -a^_j * dl_j, or
    8118 * a~_j * du_j == -a^_j * du_j
    8119 * to the rhs, and update the VB variable coefficients:
    8120 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
    8121 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
    8122 */
    8123
    8124 SCIPquadprecEpsFloorQ(downrhs, data->cutrhs, SCIPepsilon(scip)); /*lint !e666*/
    8125 SCIPquadprecSumQQ(f0, data->cutrhs, -downrhs);
    8126 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
    8127
    8128 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
    8129 goto TERMINATE;
    8130
    8131 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
    8132 * If this gives a scalar that is very big, we better do not generate this cut.
    8133 */
    8134 if( REALABS(scale)/(1.0 - QUAD_TO_DBL(f0)) > MAXCMIRSCALE )
    8135 goto TERMINATE;
    8136
    8137 /* renormalize f0 value */
    8138 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
    8139
    8140 QUAD_ASSIGN_Q(data->cutrhs, downrhs);
    8141
    8142 if( data->totalnnz > 0 )
    8143 {
    8144 SCIP_CALL( cutsRoundMIR(scip, data, varsign, boundtype, QUAD(f0)) );
    8145
    8146 SCIPdebugMsg(scip, "After MIR rounding:\n");
    8147 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    8148 }
    8149
    8150 /* substitute aggregated slack variables:
    8151 *
    8152 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    8153 * variable only appears in its own row:
    8154 * a'_r = scale * weight[r] * slacksign[r].
    8155 *
    8156 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    8157 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
    8158 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    8159 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
    8160 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    8161 *
    8162 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
    8163 */
    8164 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
    8165 aggrrow->nrows, scale,
    8166 data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds, QUAD(f0)) );
    8167
    8168 SCIPdebugMsg(scip, "After slack substitution:\n");
    8169 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    8170
    8171 if( postprocess )
    8172 {
    8173 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
    8174 * prevent numerical rounding errors
    8175 */
    8176 SCIP_CALL( postprocessCutQuad(scip, tmpislocal, data->cutinds, data->cutcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
    8177 }
    8178 else
    8179 {
    8180 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), tmpislocal, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds);
    8181 }
    8182
    8183 SCIPdebugMsg(scip, "After post processing:\n");
    8184 SCIPdebug( printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE) );
    8185
    8186 if( *success )
    8187 {
    8188 SCIP_Real mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, data->cutcoefs, QUAD_TO_DBL(data->cutrhs), data->cutinds, data->ncutinds);
    8189
    8190 if( SCIPisEfficacious(scip, mirefficacy) && (cutefficacy == NULL || mirefficacy > *cutefficacy) )
    8191 {
    8192 BMScopyMemoryArray(cutinds, data->cutinds, data->ncutinds);
    8193 *cutnnz = data->ncutinds;
    8194 *cutrhs = QUAD_TO_DBL(data->cutrhs);
    8195 *cutislocal = tmpislocal;
    8196
    8197 /* clean tmpcoefs and go back to double precision */
    8198 for(int i = 0; i < *cutnnz; ++i )
    8199 {
    8200 SCIP_Real QUAD(coef);
    8201 int j = cutinds[i];
    8202
    8203 QUAD_ARRAY_LOAD(coef, data->cutcoefs, j);
    8204
    8205 cutcoefs[i] = QUAD_TO_DBL(coef);
    8206 QUAD_ASSIGN(coef, 0.0);
    8207 QUAD_ARRAY_STORE(data->cutcoefs, j, coef);
    8208 }
    8209
    8210 if( cutefficacy != NULL )
    8211 *cutefficacy = mirefficacy;
    8212
    8213 if( cutrank != NULL )
    8214 *cutrank = aggrrow->rank + 1;
    8215 }
    8216 else
    8217 {
    8218 *success = FALSE;
    8219 }
    8220 }
    8221
    8222 TERMINATE:
    8223 if( !(*success) )
    8224 {
    8225 SCIP_Real QUAD(tmp);
    8226
    8227 QUAD_ASSIGN(tmp, 0.0);
    8228 for(int i = 0; i < data->ncutinds; ++i )
    8229 {
    8230 QUAD_ARRAY_STORE(data->cutcoefs, data->cutinds[i], tmp);
    8231 }
    8232 }
    8233
    8234#ifndef NDEBUG
    8235 for( int i = 0; i < QUAD_ARRAY_SIZE(data->nvars); ++i )
    8236 {
    8237 if(data->cutcoefs[i] != 0.0)
    8238 {
    8239 SCIPdebugMsg(scip, "coefs have not been reset\n");
    8240 SCIPABORT();
    8241 }
    8242 }
    8243#endif
    8244
    8245 SCIPfreeBufferArray(scip, &boundtype);
    8246 SCIPfreeBufferArray(scip, &varsign);
    8247
    8248 if( data->cutinds != NULL )
    8250
    8251 if( data->cutcoefs != NULL )
    8253
    8254 for( int s = NSECTIONS - 1; s >= 0; --s )
    8255 {
    8257 }
    8258
    8259 SCIPfreeBuffer(scip, &data);
    8260
    8261 return SCIP_OKAY;
    8262}
    8263
    8264/** compute the efficacy of the MIR cut for the given values without computing the cut.
    8265 * This is used for the CMIR cut generation heuristic.
    8266 */
    8267static
    8269 SCIP* scip, /**< SCIP datastructure */
    8270 SCIP_Real*RESTRICT coefs, /**< array with coefficients in row */
    8271 SCIP_Real*RESTRICT solvals, /**< solution values of variables in the row */
    8272 SCIP_Real rhs, /**< right hand side of MIR cut */
    8273 SCIP_Real contactivity, /**< aggregated activity of continuous variables in the row */
    8274 SCIP_Real contsqrnorm, /**< squared norm of continuous variables */
    8275 SCIP_Real delta, /**< delta value to compute the violation for */
    8276 int nvars, /**< number of variables in the row, i.e. the size of coefs and solvals arrays */
    8277 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
    8278 SCIP_Real maxfrac /**< maximal fractionality of rhs to produce MIR cut for */
    8279 )
    8280{
    8281 int i;
    8282 SCIP_Real f0pluseps;
    8283 SCIP_Real f0;
    8284 SCIP_Real onedivoneminusf0;
    8285 SCIP_Real scale;
    8286 SCIP_Real downrhs;
    8287 SCIP_Real norm;
    8288 SCIP_Real contscale;
    8289
    8290 scale = 1.0 / delta;
    8291 rhs *= scale;
    8292 downrhs = SCIPfloor(scip, rhs);
    8293 f0 = rhs - downrhs;
    8294
    8295 if( f0 < minfrac || f0 > maxfrac )
    8296 return 0.0;
    8297
    8298 onedivoneminusf0 = 1.0 / (1.0 - f0);
    8299
    8300 contscale = scale * onedivoneminusf0;
    8301
    8302 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
    8303 * If this gives a scalar that is very big, we better do not generate this cut.
    8304 */
    8305 if( contscale > MAXCMIRSCALE )
    8306 return 0.0;
    8307
    8308 rhs = downrhs;
    8309 rhs -= contscale * contactivity;
    8310 norm = SQR(contscale) * contsqrnorm;
    8311
    8312 assert(!SCIPisFeasZero(scip, f0));
    8313 assert(!SCIPisFeasZero(scip, 1.0 - f0));
    8314
    8315 f0pluseps = f0 + SCIPepsilon(scip);
    8316
    8317 for( i = 0; i < nvars; ++i )
    8318 {
    8319 SCIP_Real floorai = SCIPfloor(scip, scale * coefs[i]);
    8320 SCIP_Real fi = (scale * coefs[i]) - floorai;
    8321
    8322 if( fi > f0pluseps )
    8323 floorai += (fi - f0) * onedivoneminusf0;
    8324
    8325 rhs -= solvals[i] * floorai;
    8326 norm += SQR(floorai);
    8327 }
    8328
    8329 norm = sqrt(norm);
    8330
    8331 return - rhs / MAX(norm, 1e-6);
    8332}
    8333
    8334/** calculates an MIR cut out of an aggregation of LP rows
    8335 *
    8336 * Given the aggregation, it is transformed to a mixed knapsack set via complementation (using bounds or variable bounds)
    8337 * Then, different scalings of the mkset are used to generate a MIR and the best is chosen.
    8338 * One of the steps of the MIR is to round the coefficients of the integer variables down,
    8339 * so one would prefer to have integer coefficients for integer variables which are far away from their bounds in the
    8340 * mkset.
    8341 *
    8342 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    8343 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    8344 *
    8345 * @pre This method can be called if @p scip is in one of the following stages:
    8346 * - \ref SCIP_STAGE_SOLVING
    8347 *
    8348 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    8349 */
    8351 SCIP* scip, /**< SCIP data structure */
    8352 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    8353 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
    8354 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    8355 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
    8356 * type substitution is allowed. The indices are: 0: continuous,
    8357 * 1: continuous implint., 2: integer implint, 3: binary implint,
    8358 * 4: integer, 5: binary */
    8359 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    8360 int maxtestdelta, /**< maximum number of deltas to test */
    8361 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    8362 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    8363 * NULL for using closest bound for all variables */
    8364 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    8365 * NULL for using closest bound for all variables */
    8366 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
    8367 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
    8368 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
    8369 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
    8370 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
    8371 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
    8372 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
    8373 SCIP_Real* cutefficacy, /**< pointer to store efficacy of best cut; only cuts that are strictly better than the value of
    8374 * this efficacy on input to this function are returned */
    8375 int* cutrank, /**< pointer to return rank of generated cut (or NULL) */
    8376 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
    8377 SCIP_Bool* success /**< pointer to store whether a valid and efficacious cut was returned */
    8378 )
    8379{
    8380 int i;
    8381 int firstcontvar;
    8382 int nvars;
    8383 int intstart;
    8384 int ntmpcoefs;
    8385 int* varsign;
    8386 int* boundtype;
    8387 int* mksetinds;
    8388 SCIP_Real* mksetcoefs;
    8389 SCIP_Real QUAD(mksetrhs);
    8390 int mksetnnz;
    8391 SCIP_Real* bounddist;
    8392 int* bounddistpos;
    8393 int nbounddist;
    8394 SCIP_Real* tmpcoefs;
    8395 SCIP_Real* tmpvalues;
    8396 SCIP_Real* deltacands;
    8397 int ndeltacands;
    8398 SCIP_Real bestdelta;
    8399 SCIP_Real bestefficacy;
    8400 SCIP_Real maxabsmksetcoef;
    8401 SCIP_VAR** vars;
    8402 SCIP_Bool freevariable;
    8403 SCIP_Bool localbdsused;
    8404 SCIP_Real contactivity;
    8405 SCIP_Real contsqrnorm;
    8406 MIR_DATA* data;
    8407
    8408 assert(aggrrow != NULL);
    8409 assert(aggrrow->nrows + aggrrow->nnz >= 1);
    8410 assert(success != NULL);
    8411
    8412 *success = FALSE;
    8413 nvars = SCIPgetNVars(scip);
    8414 firstcontvar = nvars - SCIPgetNContVars(scip) - SCIPgetNContImplVars(scip);
    8415 vars = SCIPgetVars(scip);
    8416
    8417 /* allocate temporary memory */
    8418 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
    8419 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
    8420
    8421 SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, nvars + aggrrow->nrows) );
    8422 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars + aggrrow->nrows) );
    8423 /* The +4 comes from a few rules that create extra delta candidates, see usages of ndeltacands. */
    8424 SCIP_CALL( SCIPallocBufferArray(scip, &deltacands, nvars + 4) );
    8425
    8426 /* we only compute bound distance for integer variables; by variable bound substitution, the number of integer variables
    8427 * can grow significantly. Hence, these allocations are length nvars */
    8428 SCIP_CALL( SCIPallocBufferArray(scip, &bounddist, nvars) );
    8429 SCIP_CALL( SCIPallocBufferArray(scip, &bounddistpos, nvars) );
    8430
    8431 /* initialize mkset with the unscaled aggregation */
    8432 {
    8433 int l;
    8434 int nnz;
    8435
    8436 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
    8437
    8438 SCIP_CALL( SCIPallocBuffer(scip, &data) );
    8439
    8440 nnz = aggrrow->nnz;
    8441 data->totalnnz = nnz;
    8442
    8443 /* initialize sections */
    8444 for( l = 0; l < NSECTIONS; ++l )
    8445 {
    8446 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
    8447 data->secnnz[l] = 0;
    8448 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
    8449 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
    8450 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
    8451 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
    8452 /* Use variable bounds for the sections specified by the user */
    8453 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
    8454 }
    8455
    8456 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
    8457 data->vars = SCIPgetVars(scip);
    8458 data->nvars = SCIPgetNVars(scip);
    8459 data->nbinvars = SCIPgetNBinVars(scip);
    8460 data->nintvars = SCIPgetNIntVars(scip);
    8465
    8467 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
    8468
    8469 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, 1.0);
    8470
    8471 if( nnz > 0 )
    8472 {
    8473 /* Initalize cut with the aggregation */
    8474 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
    8475
    8476 for( l = 0; l < nnz; ++l )
    8477 {
    8478 SCIP_Real QUAD(coef);
    8479 int m = aggrrow->inds[l];
    8480
    8481 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
    8482
    8483 SCIPquadprecProdQD(coef, coef, 1.0);
    8484
    8485 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
    8486
    8487 assert(QUAD_HI(coef) != 0.0);
    8488 }
    8489
    8490 /* Sort the array by problem index and add the variables to their sections */
    8491 SCIPsortDownInt(data->cutinds, nnz);
    8492 for( l = 0; l < nnz; ++l )
    8493 {
    8494 int section = varSection(data, data->cutinds[l]);
    8495 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
    8496 ++data->secnnz[section];
    8497 }
    8498 }
    8499
    8500 data->ncutinds = 0;
    8501 }
    8502 *cutislocal = aggrrow->local;
    8503
    8504 /* Transform equation a*x == b, lb <= x <= ub into standard form
    8505 * a'*x' == b, 0 <= x' <= ub'.
    8506 *
    8507 * Transform variables (lb or ub):
    8508 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
    8509 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
    8510 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
    8511 *
    8512 * Transform variables (vlb or vub):
    8513 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
    8514 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
    8515 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
    8516 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
    8517 * a_{zu_j} := a_{zu_j} + a_j * bu_j
    8518 */
    8519 SCIP_CALL( cutsTransformMIR(scip, data, sol, boundswitch, allowlocal, FALSE, FALSE,
    8520 boundsfortrans, boundtypesfortrans, minfrac, maxfrac, varsign, boundtype, &freevariable, &localbdsused) );
    8521 assert(allowlocal || !localbdsused);
    8522
    8523 /* Use aliases to stay more consistent with the old code. mksetrhs needs to synchronize its values data->cutrhs
    8524 * again before calling SCIProundMIR()! */
    8525 mksetinds = data->cutinds;
    8526 mksetcoefs = data->cutcoefs;
    8527 mksetnnz = data->ncutinds;
    8528 QUAD_ASSIGN_Q(mksetrhs, data->cutrhs);
    8529
    8530 if( freevariable )
    8531 goto TERMINATE;
    8532
    8533 SCIPdebugMsg(scip, "transformed aggrrow row:\n");
    8534 SCIPdebug( printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE) );
    8535
    8536 /* found positions of integral variables that are strictly between their bounds */
    8537 maxabsmksetcoef = -1.0;
    8538 nbounddist = 0;
    8539
    8540 assert(mksetnnz <= nvars);
    8541 for( i = mksetnnz - 1; i >= 0 && mksetinds[i] < firstcontvar; --i )
    8542 {
    8543 SCIP_VAR* var = vars[mksetinds[i]];
    8544 SCIP_Real primsol = SCIPgetSolVal(scip, sol, var);
    8545 SCIP_Real lb = SCIPvarGetLbLocal(var);
    8546 SCIP_Real ub = SCIPvarGetUbLocal(var);
    8547 SCIP_Real QUAD(coef);
    8548
    8549 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
    8550
    8551 if( SCIPisEQ(scip, primsol, lb) || SCIPisEQ(scip, primsol, ub) )
    8552 continue;
    8553
    8554 bounddist[nbounddist] = MIN(ub - primsol, primsol - lb);
    8555 bounddistpos[nbounddist] = i;
    8556 deltacands[nbounddist] = QUAD_TO_DBL(coef);
    8557 ++nbounddist;
    8558 }
    8559 assert(nbounddist <= nvars);
    8560
    8561 /* no fractional variable; so abort here */
    8562 if( nbounddist == 0 )
    8563 goto TERMINATE;
    8564
    8565 intstart = i + 1;
    8566
    8567 /* Check that the continuous and implied integer variables and integer variables are partitioned */
    8568#ifndef NDEBUG
    8569 for( int j = 0; j < intstart; ++j )
    8570 {
    8571 assert(SCIPvarGetType(vars[mksetinds[j]]) == SCIP_VARTYPE_CONTINUOUS);
    8572 }
    8573 for( int j = intstart; j < data->ncutinds; ++j )
    8574 {
    8575 assert(SCIPvarIsIntegral(vars[mksetinds[j]]));
    8576 }
    8577#endif
    8578
    8579 ndeltacands = nbounddist;
    8580 assert(ndeltacands <= nvars);
    8581 SCIPsortDownRealRealInt(bounddist, deltacands, bounddistpos, nbounddist);
    8582
    8583 {
    8584 SCIP_Real intscale;
    8585 SCIP_Bool intscalesuccess;
    8586
    8587 SCIP_CALL( SCIPcalcIntegralScalar(deltacands, nbounddist, -SCIPepsilon(scip), SCIPsumepsilon(scip), (SCIP_Longint)10000, 10000.0, &intscale, &intscalesuccess) );
    8588
    8589 if( intscalesuccess )
    8590 {
    8591 SCIP_Real intf0;
    8592 SCIP_Real intscalerhs;
    8593 SCIP_Real delta;
    8594
    8595 intscalerhs = QUAD_TO_DBL(data->cutrhs) * intscale;
    8596 delta = 1.0 / intscale;
    8597 intf0 = intscalerhs - floor(intscalerhs);
    8598
    8599 if( ! SCIPisFeasIntegral(scip, intf0) )
    8600 {
    8601 if( intf0 < minfrac || intf0 > maxfrac )
    8602 {
    8603 intscale *= SCIPceil(scip, MAX(minfrac, (1.0 - maxfrac)) / MIN(intf0, (1.0 - intf0)));
    8604 intscalerhs = QUAD_TO_DBL(data->cutrhs) * intscale;
    8605 delta = 1.0 / intscale;
    8606 intf0 = intscalerhs - floor(intscalerhs);
    8607 }
    8608
    8609 if( intf0 >= minfrac && intf0 <= maxfrac )
    8610 {
    8611 if( ! SCIPisEQ(scip, delta, 1.0) )
    8612 deltacands[ndeltacands++] = delta;
    8613
    8614 if( intf0 < maxfrac )
    8615 {
    8616 SCIP_Real delta2;
    8617
    8618 delta2 = 1.0 / (intscale * SCIPfloor(scip, maxfrac / intf0));
    8619
    8620 if( ! SCIPisEQ(scip, delta, delta2) && ! SCIPisEQ(scip, delta2, 1.0) )
    8621 deltacands[ndeltacands++] = delta2;
    8622 }
    8623 }
    8624 }
    8625 }
    8626 }
    8627
    8628 for( i = 0; i < nbounddist; ++i )
    8629 {
    8630 SCIP_Real absmksetcoef;
    8631
    8632 absmksetcoef = REALABS(deltacands[i]);
    8633 maxabsmksetcoef = MAX(absmksetcoef, maxabsmksetcoef);
    8634
    8635 deltacands[i] = absmksetcoef;
    8636 }
    8637
    8638 /* also test 1.0 and maxabsmksetcoef + 1.0 as last delta values */
    8639 if( maxabsmksetcoef != -1.0 )
    8640 deltacands[ndeltacands++] = maxabsmksetcoef + 1.0;
    8641
    8642 deltacands[ndeltacands++] = 1.0;
    8643
    8644 maxtestdelta = MIN(ndeltacands, maxtestdelta);
    8645
    8646 /* For each delta
    8647 * Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
    8648 * a~*x' <= down(b)
    8649 * integers : a~_j = down(a'_j) , if f_j <= f_0
    8650 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
    8651 * continuous: a~_j = 0 , if a'_j >= 0
    8652 * a~_j = a'_j/(1 - f0) , if a'_j < 0
    8653 *
    8654 * Transform inequality back to a^*x <= rhs:
    8655 *
    8656 * (lb or ub):
    8657 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
    8658 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
    8659 * and move the constant terms
    8660 * -a~_j * lb_j == -a^_j * lb_j, or
    8661 * a~_j * ub_j == -a^_j * ub_j
    8662 * to the rhs.
    8663 *
    8664 * (vlb or vub):
    8665 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
    8666 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
    8667 * move the constant terms
    8668 * -a~_j * dl_j == -a^_j * dl_j, or
    8669 * a~_j * du_j == -a^_j * du_j
    8670 * to the rhs, and update the VB variable coefficients:
    8671 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
    8672 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
    8673 */
    8674
    8675 ntmpcoefs = 0;
    8676 assert(mksetnnz <= nvars);
    8677 for( i = intstart; i < mksetnnz; ++i )
    8678 {
    8679 SCIP_VAR* var;
    8680 SCIP_Real solval;
    8681 SCIP_Real QUAD(coef);
    8682
    8683 var = vars[mksetinds[i]];
    8684
    8685 /* get the soltion value of the continuous variable */
    8686 solval = SCIPgetSolVal(scip, sol, var);
    8687
    8688 /* now compute the solution value in the transform space considering complementation */
    8689 if( boundtype[i] == -1 )
    8690 {
    8691 /* variable was complemented with global (simple) bound */
    8692 if( varsign[i] == -1 )
    8693 solval = SCIPvarGetUbGlobal(var) - solval;
    8694 else
    8695 solval = solval - SCIPvarGetLbGlobal(var);
    8696 }
    8697 else
    8698 {
    8699 assert(boundtype[i] == -2);
    8700
    8701 /* variable was complemented with local (simple) bound */
    8702 if( varsign[i] == -1 )
    8703 solval = SCIPvarGetUbLocal(var) - solval;
    8704 else
    8705 solval = solval - SCIPvarGetLbLocal(var);
    8706 }
    8707
    8708 tmpvalues[ntmpcoefs] = solval;
    8709 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
    8710 tmpcoefs[ntmpcoefs] = varsign[i] * QUAD_TO_DBL(coef);
    8711 ++ntmpcoefs;
    8712 }
    8713
    8714 assert(ntmpcoefs == mksetnnz - intstart);
    8715
    8716 contactivity = 0.0;
    8717 contsqrnorm = 0.0;
    8718 for( i = 0; i < intstart; ++i )
    8719 {
    8720 SCIP_Real solval;
    8721 SCIP_Real QUAD(mksetcoef);
    8722
    8723 QUAD_ARRAY_LOAD(mksetcoef, mksetcoefs, mksetinds[i]);
    8724
    8725 if( varsign[i] * QUAD_TO_DBL(mksetcoef) >= 0.0 )
    8726 continue;
    8727
    8728 /* get the soltion value of the continuous variable */
    8729 solval = SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
    8730
    8731 /* now compute the solution value in the transform space considering complementation */
    8732 switch( boundtype[i] )
    8733 {
    8734 case -1:
    8735 /* variable was complemented with global (simple) bound */
    8736 if( varsign[i] == -1 )
    8737 solval = SCIPvarGetUbGlobal(vars[mksetinds[i]]) - solval;
    8738 else
    8739 solval = solval - SCIPvarGetLbGlobal(vars[mksetinds[i]]);
    8740 break;
    8741 case -2:
    8742 /* variable was complemented with local (simple) bound */
    8743 if( varsign[i] == -1 )
    8744 solval = SCIPvarGetUbLocal(vars[mksetinds[i]]) - solval;
    8745 else
    8746 solval = solval - SCIPvarGetLbLocal(vars[mksetinds[i]]);
    8747 break;
    8748 default:
    8749 /* variable was complemented with a variable bound */
    8750 if( varsign[i] == -1 )
    8751 {
    8752 SCIP_Real coef;
    8753 SCIP_Real constant;
    8754 SCIP_Real vbdsolval;
    8755
    8756 coef = SCIPvarGetVubCoefs(vars[mksetinds[i]])[boundtype[i]];
    8757 constant = SCIPvarGetVubConstants(vars[mksetinds[i]])[boundtype[i]];
    8758 vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVubVars(vars[mksetinds[i]])[boundtype[i]]);
    8759
    8760 solval = (coef * vbdsolval + constant) - solval;
    8761 }
    8762 else
    8763 {
    8764 SCIP_Real coef;
    8765 SCIP_Real constant;
    8766 SCIP_Real vbdsolval;
    8767
    8768 coef = SCIPvarGetVlbCoefs(vars[mksetinds[i]])[boundtype[i]];
    8769 constant = SCIPvarGetVlbConstants(vars[mksetinds[i]])[boundtype[i]];
    8770 vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVlbVars(vars[mksetinds[i]])[boundtype[i]]);
    8771
    8772 solval = solval - (coef * vbdsolval + constant);
    8773 }
    8774 }
    8775
    8776 contactivity += solval * (QUAD_TO_DBL(mksetcoef) * varsign[i]);
    8777 contsqrnorm += QUAD_TO_DBL(mksetcoef) * QUAD_TO_DBL(mksetcoef);
    8778 }
    8779
    8780 {
    8781 SCIP_ROW** rows;
    8782
    8783 rows = SCIPgetLPRows(scip);
    8784 assert(ntmpcoefs <= nvars);
    8785 for( i = 0; i < aggrrow->nrows; ++i )
    8786 {
    8787 SCIP_ROW* row;
    8788 SCIP_Real slackval;
    8789
    8790 row = rows[aggrrow->rowsinds[i]];
    8791
    8792 if( (aggrrow->rowweights[i] * aggrrow->slacksign[i]) >= 0.0 && !row->integral )
    8793 continue;
    8794
    8795 /* compute solution value of slack variable */
    8796 slackval = SCIPgetRowSolActivity(scip, row, sol);
    8797
    8798 if( aggrrow->slacksign[i] == +1 )
    8799 {
    8800 /* right hand side */
    8801 assert(!SCIPisInfinity(scip, row->rhs));
    8802
    8803 slackval = row->rhs - slackval;
    8804 }
    8805 else
    8806 {
    8807 /* left hand side */
    8808 assert(aggrrow->slacksign[i] == -1);
    8809 assert(!SCIPisInfinity(scip, -row->lhs));
    8810
    8811 slackval = slackval - row->lhs;
    8812 }
    8813
    8814 if( row->integral )
    8815 {
    8816 /* if row is integral add variable to tmp arrays */
    8817 tmpvalues[ntmpcoefs] = slackval;
    8818 tmpcoefs[ntmpcoefs] = aggrrow->rowweights[i] * aggrrow->slacksign[i];
    8819 ++ntmpcoefs;
    8820 }
    8821 else
    8822 {
    8823 SCIP_Real slackcoeff = (aggrrow->rowweights[i] * aggrrow->slacksign[i]);
    8824
    8825 /* otherwise add it to continuous activity */
    8826 contactivity += slackval * slackcoeff;
    8827 contsqrnorm += SQR(slackcoeff);
    8828 }
    8829 }
    8830 }
    8831
    8832 /* try all candidates for delta and remember best */
    8833 bestdelta = SCIP_INVALID;
    8834 bestefficacy = -SCIPinfinity(scip);
    8835
    8836 for( i = 0; i < maxtestdelta; ++i )
    8837 {
    8838 int j;
    8839 SCIP_Real efficacy;
    8840
    8841 /* check if we have seen this value of delta before */
    8842 SCIP_Bool deltaseenbefore = FALSE;
    8843 for( j = 0; j < i; ++j )
    8844 {
    8845 if( SCIPisEQ(scip, deltacands[i], deltacands[j]) )
    8846 {
    8847 deltaseenbefore = TRUE;
    8848 break;
    8849 }
    8850 }
    8851
    8852 /* skip this delta value and allow one more delta value if available */
    8853 if( deltaseenbefore )
    8854 {
    8855 maxtestdelta = MIN(maxtestdelta + 1, ndeltacands);
    8856 continue;
    8857 }
    8858
    8859 efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, deltacands[i], ntmpcoefs, minfrac, maxfrac);
    8860
    8861 if( efficacy > bestefficacy )
    8862 {
    8863 bestefficacy = efficacy;
    8864 bestdelta = deltacands[i];
    8865 }
    8866 }
    8867
    8868 /* no delta was found that yielded any cut */
    8869 if( bestdelta == SCIP_INVALID ) /*lint !e777*/
    8870 goto TERMINATE;
    8871
    8872 /* try bestdelta divided by 2, 4 and 8 */
    8873 {
    8874 SCIP_Real basedelta = bestdelta;
    8875 for( i = 2; i <= 8 ; i *= 2 )
    8876 {
    8877 SCIP_Real efficacy;
    8878 SCIP_Real delta;
    8879
    8880 delta = basedelta / i;
    8881
    8882 efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, delta, ntmpcoefs, minfrac, maxfrac);
    8883
    8884 if( efficacy > bestefficacy )
    8885 {
    8886 bestefficacy = efficacy;
    8887 bestdelta = delta;
    8888 }
    8889 }
    8890 }
    8891
    8892 /* try to improve efficacy by switching complementation of integral variables that are not at their bounds
    8893 * in order of non-increasing bound distance
    8894 */
    8895 for( i = 0; i < nbounddist; ++i )
    8896 {
    8897 int k;
    8898 SCIP_Real newefficacy;
    8899 SCIP_Real QUAD(newrhs);
    8900 SCIP_Real QUAD(quadprod);
    8901 SCIP_Real bestlb;
    8902 SCIP_Real bestub;
    8903 SCIP_Real oldsolval;
    8904 int bestlbtype;
    8905 int bestubtype;
    8906
    8907 k = bounddistpos[i];
    8908
    8909 SCIP_CALL( findBestLb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestlb, &bestlbtype) );
    8910
    8911 if( SCIPisInfinity(scip, -bestlb) )
    8912 continue;
    8913
    8914 SCIP_CALL( findBestUb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestub, &bestubtype) );
    8915
    8916 if( SCIPisInfinity(scip, bestub) )
    8917 continue;
    8918
    8919 /* switch the complementation of this variable */
    8920#ifndef NDEBUG
    8921 {
    8922 SCIP_Real QUAD(coef);
    8923 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[k]);
    8924 assert(SCIPisEQ(scip, tmpcoefs[k - intstart], varsign[k] * QUAD_TO_DBL(coef)));
    8925 }
    8926#endif
    8927
    8928 /* compute this: newrhs = mksetrhs + tmpcoefs[k - intstart] * (bestlb - bestub); */
    8929 SCIPquadprecProdDD(quadprod, tmpcoefs[k - intstart], bestlb - bestub);
    8930 SCIPquadprecSumQQ(newrhs, mksetrhs, quadprod);
    8931 tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
    8932
    8933 oldsolval = tmpvalues[k - intstart];
    8934 tmpvalues[k - intstart] = varsign[k] == +1 ? bestub - SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) : SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) - bestlb;
    8935
    8936 /* compute new violation */
    8937 newefficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(newrhs), contactivity, contsqrnorm, bestdelta, ntmpcoefs, minfrac, maxfrac);
    8938
    8939 /* check if violation was increased */
    8940 if( newefficacy > bestefficacy )
    8941 {
    8942 /* keep change of complementation */
    8943 bestefficacy = newefficacy;
    8944 QUAD_ASSIGN_Q(mksetrhs, newrhs);
    8945
    8946 if( varsign[k] == +1 )
    8947 {
    8948 /* switch to upper bound */
    8949 assert(bestubtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
    8950 boundtype[k] = bestubtype;
    8951 varsign[k] = -1;
    8952 }
    8953 else
    8954 {
    8955 /* switch to lower bound */
    8956 assert(bestlbtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
    8957 boundtype[k] = bestlbtype;
    8958 varsign[k] = +1;
    8959 }
    8960
    8961 localbdsused = localbdsused || (boundtype[k] == -2);
    8962 }
    8963 else
    8964 {
    8965 /* undo the change of the complementation */
    8966 tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
    8967 tmpvalues[k - intstart] = oldsolval;
    8968 }
    8969 } /*lint !e438*/
    8970
    8971 if( bestefficacy > 0.0 )
    8972 {
    8973 SCIP_Real mirefficacy;
    8974 SCIP_Real QUAD(downrhs);
    8975 SCIP_Real QUAD(f0);
    8976 SCIP_Real scale;
    8977
    8978 scale = 1.0 / bestdelta;
    8979 SCIPquadprecProdQD(mksetrhs, mksetrhs, scale);
    8980 SCIPquadprecEpsFloorQ(downrhs, mksetrhs, SCIPepsilon(scip)); /*lint !e666*/
    8981 SCIPquadprecSumQQ(f0, mksetrhs, -downrhs);
    8982 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
    8983
    8984 /* renormalize f0 value */
    8985 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
    8986
    8987 /* scale entries by the chosen scale factor */
    8988 for( i = 0; i < mksetnnz; ++i )
    8989 {
    8990 SCIP_Real QUAD(coef);
    8991
    8992 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
    8993 SCIPquadprecProdQD(coef, coef, scale);
    8994 QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], coef);
    8995 }
    8996 SCIPdebugMsg(scip, "applied best scale (=%.13g):\n", scale);
    8997 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
    8998
    8999 QUAD_ASSIGN_Q(mksetrhs, downrhs);
    9000
    9001 QUAD_ASSIGN_Q(data->cutrhs, mksetrhs);
    9002
    9003 SCIP_CALL( cutsRoundMIR(scip, data, varsign, boundtype, QUAD(f0)) );
    9004
    9005 SCIPdebugMsg(scip, "rounded MIR cut:\n");
    9006 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
    9007
    9008 /* substitute aggregated slack variables:
    9009 *
    9010 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    9011 * variable only appears in its own row:
    9012 * a'_r = scale * weight[r] * slacksign[r].
    9013 *
    9014 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    9015 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
    9016 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    9017 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
    9018 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    9019 *
    9020 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
    9021 */
    9022 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
    9023 aggrrow->nrows, scale, mksetcoefs, QUAD(&data->cutrhs), mksetinds, &data->ncutinds, QUAD(f0)) );
    9024
    9025 SCIPdebugMsg(scip, "substituted slacks in MIR cut:\n");
    9026 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
    9027
    9028#ifndef NDEBUG
    9029 {
    9030 SCIP_Real efficacy = -QUAD_TO_DBL(data->cutrhs);
    9031 for( i = 0; i < data->ncutinds; ++i )
    9032 {
    9033 SCIP_Real QUAD(coef);
    9034 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
    9035 efficacy += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
    9036 }
    9037
    9038 if( !EPSZ(SCIPrelDiff(efficacy, bestefficacy), 1e-4) )
    9039 {
    9040 SCIPdebugMsg(scip, "efficacy of cmir cut is different than expected efficacy: %f != %f\n", efficacy, bestefficacy);
    9041 }
    9042 }
    9043#endif
    9044
    9045 *cutislocal = *cutislocal || localbdsused;
    9046
    9047 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
    9048 * prevent numerical rounding errors
    9049 */
    9050 if( postprocess )
    9051 {
    9052 SCIP_CALL( postprocessCutQuad(scip, *cutislocal, mksetinds, mksetcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
    9053 }
    9054 else
    9055 {
    9056 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, mksetcoefs, QUAD(&data->cutrhs), mksetinds, &data->ncutinds);
    9057 }
    9058
    9059 SCIPdebugMsg(scip, "post-processed cut (success = %s):\n", *success ? "TRUE" : "FALSE");
    9060 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
    9061
    9062 if( *success )
    9063 {
    9064 mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, mksetcoefs, QUAD_TO_DBL(data->cutrhs), mksetinds, data->ncutinds);
    9065
    9066 if( SCIPisEfficacious(scip, mirefficacy) && SCIPisGT(scip, mirefficacy, *cutefficacy) )
    9067 {
    9068 BMScopyMemoryArray(cutinds, mksetinds, data->ncutinds);
    9069 for( i = 0; i < data->ncutinds; ++i )
    9070 {
    9071 SCIP_Real QUAD(coef);
    9072 int j = cutinds[i];
    9073
    9074 QUAD_ARRAY_LOAD(coef, mksetcoefs, j);
    9075
    9076 cutcoefs[i] = QUAD_TO_DBL(coef);
    9077 QUAD_ASSIGN(coef, 0.0);
    9078 QUAD_ARRAY_STORE(mksetcoefs, j, coef);
    9079 }
    9080 *cutnnz = data->ncutinds;
    9081 *cutrhs = QUAD_TO_DBL(data->cutrhs);
    9082 *cutefficacy = mirefficacy;
    9083 if( cutrank != NULL )
    9084 *cutrank = aggrrow->rank + 1;
    9085 *cutislocal = *cutislocal || localbdsused;
    9086 }
    9087 else
    9088 *success = FALSE;
    9089 }
    9090 }
    9091
    9092 TERMINATE:
    9093 /* if we aborted early we need to clean the mksetcoefs */
    9094 if( !(*success) )
    9095 {
    9096 SCIP_Real QUAD(tmp);
    9097 QUAD_ASSIGN(tmp, 0.0);
    9098
    9099 for( i = 0; i < data->ncutinds; ++i )
    9100 {
    9101 QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], tmp);
    9102 }
    9103 }
    9104
    9105#ifndef NDEBUG
    9106 for( i = 0; i < QUAD_ARRAY_SIZE(nvars); ++i )
    9107 {
    9108 if(mksetcoefs[i] != 0.0)
    9109 {
    9110 SCIPdebugMsg(scip, "mksetcoefs have not been reset\n");
    9111 SCIPABORT();
    9112 }
    9113 }
    9114#endif
    9115
    9116 if( data->cutinds != NULL )
    9118
    9119 if( data->cutcoefs != NULL )
    9121
    9122 for( int s = NSECTIONS - 1; s >= 0; --s )
    9123 {
    9125 }
    9126
    9127 SCIPfreeBuffer(scip, &data);
    9128 /* free temporary memory */
    9129 SCIPfreeBufferArray(scip, &bounddistpos);
    9130 SCIPfreeBufferArray(scip, &bounddist);
    9131 SCIPfreeBufferArray(scip, &deltacands);
    9132 SCIPfreeBufferArray(scip, &tmpvalues);
    9133 SCIPfreeBufferArray(scip, &tmpcoefs);
    9134 SCIPfreeBufferArray(scip, &boundtype);
    9135 SCIPfreeBufferArray(scip, &varsign);
    9136
    9137 return SCIP_OKAY;
    9138}
    9139
    9140/* =========================================== flow cover =========================================== */
    9141
    9142#define NO_EXACT_KNAPSACK
    9143
    9144#ifndef NO_EXACT_KNAPSACK
    9145#define MAXDNOM 1000LL
    9146#define MINDELTA 1e-03
    9147#define MAXDELTA 1e-09
    9148#define MAXSCALE 1000.0
    9149#define MAXDYNPROGSPACE 1000000
    9150#endif
    9151
    9152#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for snf relaxation */
    9153#define MAXBOUND 1e+10 /**< maximal value of normal bounds used for snf relaxation */
    9154
    9155/** structure that contains all data required to perform the sequence independent lifting
    9156 */
    9157typedef
    9158struct LiftingData
    9159{
    9160 SCIP_Real* M; /**< \f$ M_0 := 0.0 \f$ and \f$ M_i := M_i-1 + m_i \f$ */
    9161 SCIP_Real* m; /**< non-increasing array of variable upper bound coefficients
    9162 * for all variables in \f$ C^{++} \f$ and \f$ L^- \f$,
    9163 * where \f$ C = C^+ \cup C^- \f$ is the flowcover and
    9164 * \f$ C^{++} := \{ j \in C^+ \mid u_j > \lambda \} \f$
    9165 * \f$ L^- := \{ j \in (N^- \setminus C^-) \mid u_j > \lambda \} \f$
    9166 */
    9167 int r; /**< size of array m */
    9168 int t; /**< index of smallest value in m that comes from a variable in \f$ C^{++} \f$ */
    9169 SCIP_Real d1; /**< right hand side of single-node-flow set plus the sum of all \f$ u_j \f$ for \f$ j \in C^- \f$ */
    9170 SCIP_Real d2; /**< right hand side of single-node-flow set plus the sum of all \f$ u_j \f$ for \f$ j \in N^- \f$ */
    9171 SCIP_Real lambda; /**< excess of the flowcover */
    9172 SCIP_Real mp; /**< smallest variable bound coefficient of variable in \f$ C^{++} (min_{j \in C++} u_j) \f$ */
    9173 SCIP_Real ml; /**< \f$ ml := min(\lambda, \sum_{j \in C^+ \setminus C^{++}} u_j) \f$ */
    9175
    9176/** structure that contains all the data that defines the single-node-flow relaxation of an aggregation row */
    9177typedef
    9178struct SNF_Relaxation
    9179{
    9180 int* transvarcoefs; /**< coefficients of all vars in relaxed set */
    9181 SCIP_Real* transbinvarsolvals; /**< sol val of bin var in vub of all vars in relaxed set */
    9182 SCIP_Real* transcontvarsolvals;/**< sol val of all real vars in relaxed set */
    9183 SCIP_Real* transvarvubcoefs; /**< coefficient in vub of all vars in relaxed set */
    9184 int ntransvars; /**< number of vars in relaxed set */
    9185 SCIP_Real transrhs; /**< rhs in relaxed set */
    9186 int* origbinvars; /**< associated original binary var for all vars in relaxed set */
    9187 int* origcontvars; /**< associated original continuous var for all vars in relaxed set */
    9188 SCIP_Real* aggrcoefsbin; /**< aggregation coefficient of the original binary var used to define the
    9189 * continuous variable in the relaxed set */
    9190 SCIP_Real* aggrcoefscont; /**< aggregation coefficient of the original continuous var used to define the
    9191 * continuous variable in the relaxed set */
    9192 SCIP_Real* aggrconstants; /**< aggregation constant used to define the continuous variable in the relaxed set */
    9194
    9195/** get solution value and index of variable lower bound (with binary variable) which is closest to the current LP
    9196 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
    9197 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
    9198 * given variable
    9199 */
    9200static
    9202 SCIP* scip, /**< SCIP data structure */
    9203 SCIP_VAR* var, /**< given active problem variable */
    9204 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
    9205 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
    9206 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
    9207 * was not used (0) or was not used but is contained in the row (-1) */
    9208 SCIP_Real bestsub, /**< closest simple upper bound of given variable */
    9209 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
    9210 SCIP_Real* closestvlb, /**< pointer to store the LP sol value of the closest variable lower bound */
    9211 int* closestvlbidx /**< pointer to store the index of the closest vlb; -1 if no vlb was found */
    9212 )
    9213{
    9214 int nvlbs;
    9215 int nbinvars;
    9216
    9217 assert(scip != NULL);
    9218 assert(var != NULL);
    9219 assert(bestsub == SCIPvarGetUbGlobal(var) || bestsub == SCIPvarGetUbLocal(var)); /*lint !e777*/
    9220 assert(!SCIPisInfinity(scip, bestsub));
    9221 assert(!EPSZ(rowcoef, QUAD_EPSILON));
    9222 assert(rowcoefs != NULL);
    9223 assert(binvarused != NULL);
    9224 assert(closestvlb != NULL);
    9225 assert(closestvlbidx != NULL);
    9226
    9227 nvlbs = SCIPvarGetNVlbs(var);
    9228 nbinvars = SCIPgetNBinVars(scip);
    9229
    9230 *closestvlbidx = -1;
    9231 *closestvlb = -SCIPinfinity(scip);
    9232 if( nvlbs > 0 )
    9233 {
    9234 SCIP_VAR** vlbvars;
    9235 SCIP_Real* vlbcoefs;
    9236 SCIP_Real* vlbconsts;
    9237 int i;
    9238
    9239 vlbvars = SCIPvarGetVlbVars(var);
    9240 vlbcoefs = SCIPvarGetVlbCoefs(var);
    9241 vlbconsts = SCIPvarGetVlbConstants(var);
    9242
    9243 for( i = 0; i < nvlbs; i++ )
    9244 {
    9245 SCIP_Real rowcoefbinvar;
    9246 SCIP_Real val1;
    9247 SCIP_Real val2;
    9248 SCIP_Real vlbsol;
    9249 SCIP_Real rowcoefsign;
    9250 int probidxbinvar;
    9251
    9252 if( bestsub > vlbconsts[i] )
    9253 continue;
    9254
    9255 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
    9256 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
    9257 */
    9258 if( REALABS(vlbcoefs[i]) > MAXABSVBCOEF )
    9259 continue;
    9260
    9261 /* use only variable lower bounds l~_i * x_i + d_i with x_i binary which are active */
    9262 probidxbinvar = SCIPvarGetProbindex(vlbvars[i]);
    9263
    9264 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
    9265 * ensures that the problem index is between 0 and nbinvars - 1
    9266 */
    9267 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
    9268 continue;
    9269
    9270 assert(SCIPvarIsBinary(vlbvars[i]));
    9271
    9272 /* check if current variable lower bound l~_i * x_i + d_i imposed on y_j meets the following criteria:
    9273 * (let a_j = coefficient of y_j in current row,
    9274 * u_j = closest simple upper bound imposed on y_j,
    9275 * c_i = coefficient of x_i in current row)
    9276 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k yet
    9277 * if a_j > 0:
    9278 * 1. u_j <= d_i
    9279 * 2. a_j ( u_j - d_i ) + c_i <= 0
    9280 * 3. a_j l~_i + c_i <= 0
    9281 * if a_j < 0:
    9282 * 1. u_j <= d_i
    9283 * 2. a_j ( u_j - d_i ) + c_i >= 0
    9284 * 3. a_j l~_i + c_i >= 0
    9285 */
    9286
    9287 /* has already been used in the SNF relaxation */
    9288 if( binvarused[probidxbinvar] == 1 )
    9289 continue;
    9290
    9291 /* get the row coefficient */
    9292 {
    9293 SCIP_Real QUAD(tmp);
    9294 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
    9295 rowcoefbinvar = QUAD_TO_DBL(tmp);
    9296 }
    9297 rowcoefsign = COPYSIGN(1.0, rowcoef);
    9298
    9299 val2 = rowcoefsign * ((rowcoef * vlbcoefs[i]) + rowcoefbinvar);
    9300
    9301 /* variable lower bound does not meet criteria */
    9302 if( val2 > 0.0 || SCIPisInfinity(scip, -val2) )
    9303 continue;
    9304
    9305 val1 = rowcoefsign * ((rowcoef * (bestsub - vlbconsts[i])) + rowcoefbinvar);
    9306
    9307 /* variable lower bound does not meet criteria */
    9308 if( val1 > 0.0 )
    9309 continue;
    9310
    9311 vlbsol = vlbcoefs[i] * SCIPgetSolVal(scip, sol, vlbvars[i]) + vlbconsts[i];
    9312 if( vlbsol > *closestvlb )
    9313 {
    9314 *closestvlb = vlbsol;
    9315 *closestvlbidx = i;
    9316 }
    9317 assert(*closestvlbidx >= 0);
    9318 }
    9319 }
    9320
    9321 return SCIP_OKAY;
    9322}
    9323
    9324/** get LP solution value and index of variable upper bound (with binary variable) which is closest to the current LP
    9325 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
    9326 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
    9327 * given variable
    9328 */
    9329static
    9331 SCIP* scip, /**< SCIP data structure */
    9332 SCIP_VAR* var, /**< given active problem variable */
    9333 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
    9334 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
    9335 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
    9336 * was not used (0) or was not used but is contained in the row (-1)
    9337 */
    9338 SCIP_Real bestslb, /**< closest simple lower bound of given variable */
    9339 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
    9340 SCIP_Real* closestvub, /**< pointer to store the LP sol value of the closest variable upper bound */
    9341 int* closestvubidx /**< pointer to store the index of the closest vub; -1 if no vub was found */
    9342 )
    9343{
    9344 int nvubs;
    9345 int nbinvars;
    9346
    9347 assert(scip != NULL);
    9348 assert(var != NULL);
    9349 assert(bestslb == SCIPvarGetLbGlobal(var) || bestslb == SCIPvarGetLbLocal(var)); /*lint !e777*/
    9350 assert(!SCIPisInfinity(scip, - bestslb));
    9351 assert(!EPSZ(rowcoef, QUAD_EPSILON));
    9352 assert(rowcoefs != NULL);
    9353 assert(binvarused != NULL);
    9354 assert(closestvub != NULL);
    9355 assert(closestvubidx != NULL);
    9356
    9357 nvubs = SCIPvarGetNVubs(var);
    9358 nbinvars = SCIPgetNBinVars(scip);
    9359
    9360 *closestvubidx = -1;
    9361 *closestvub = SCIPinfinity(scip);
    9362 if( nvubs > 0 )
    9363 {
    9364 SCIP_VAR** vubvars;
    9365 SCIP_Real* vubcoefs;
    9366 SCIP_Real* vubconsts;
    9367 int i;
    9368
    9369 vubvars = SCIPvarGetVubVars(var);
    9370 vubcoefs = SCIPvarGetVubCoefs(var);
    9371 vubconsts = SCIPvarGetVubConstants(var);
    9372
    9373 for( i = 0; i < nvubs; i++ )
    9374 {
    9375 SCIP_Real rowcoefbinvar;
    9376 SCIP_Real val1;
    9377 SCIP_Real val2;
    9378 SCIP_Real vubsol;
    9379 SCIP_Real rowcoefsign;
    9380 int probidxbinvar;
    9381
    9382 if( bestslb < vubconsts[i] )
    9383 continue;
    9384
    9385 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
    9386 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
    9387 */
    9388 if( REALABS(vubcoefs[i]) > MAXABSVBCOEF )
    9389 continue;
    9390
    9391 /* use only variable upper bound u~_i * x_i + d_i with x_i binary and which are active */
    9392 probidxbinvar = SCIPvarGetProbindex(vubvars[i]);
    9393
    9394 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
    9395 * ensures that the problem index is between 0 and nbinvars - 1
    9396 */
    9397 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
    9398 continue;
    9399
    9400 assert(SCIPvarIsBinary(vubvars[i]));
    9401
    9402 /* checks if current variable upper bound u~_i * x_i + d_i meets the following criteria
    9403 * (let a_j = coefficient of y_j in current row,
    9404 * l_j = closest simple lower bound imposed on y_j,
    9405 * c_i = coefficient of x_i in current row)
    9406 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k
    9407 * if a > 0:
    9408 * 1. l_j >= d_i
    9409 * 2. a_j ( l_i - d_i ) + c_i >= 0
    9410 * 3. a_j u~_i + c_i >= 0
    9411 * if a < 0:
    9412 * 1. l_j >= d_i
    9413 * 2. a_j ( l_j - d_i ) + c_i <= 0
    9414 * 3. a_j u~_i + c_i <= 0
    9415 */
    9416
    9417 /* has already been used in the SNF relaxation */
    9418 if( binvarused[probidxbinvar] == 1 )
    9419 continue;
    9420
    9421 /* get the row coefficient */
    9422 {
    9423 SCIP_Real QUAD(tmp);
    9424 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
    9425 rowcoefbinvar = QUAD_TO_DBL(tmp);
    9426 }
    9427 rowcoefsign = COPYSIGN(1.0, rowcoef);
    9428
    9429 val2 = rowcoefsign * ((rowcoef * vubcoefs[i]) + rowcoefbinvar);
    9430
    9431 /* variable upper bound does not meet criteria */
    9432 if( val2 < 0.0 || SCIPisInfinity(scip, val2) )
    9433 continue;
    9434
    9435 val1 = rowcoefsign * ((rowcoef * (bestslb - vubconsts[i])) + rowcoefbinvar);
    9436
    9437 /* variable upper bound does not meet criteria */
    9438 if( val1 < 0.0 )
    9439 continue;
    9440
    9441 vubsol = vubcoefs[i] * SCIPgetSolVal(scip, sol, vubvars[i]) + vubconsts[i];
    9442 if( vubsol < *closestvub )
    9443 {
    9444 *closestvub = vubsol;
    9445 *closestvubidx = i;
    9446 }
    9447 assert(*closestvubidx >= 0);
    9448 }
    9449 }
    9450
    9451 return SCIP_OKAY;
    9452}
    9453
    9454/** determines the bounds to use for constructing the single-node-flow relaxation of a variable in
    9455 * the given row.
    9456 */
    9457static
    9459 SCIP* scip, /**< SCIP data structure */
    9460 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
    9461 SCIP_VAR** vars, /**< array of problem variables */
    9462 SCIP_Real* rowcoefs, /**< (dense) array of variable coefficients in the row */
    9463 int* rowinds, /**< array with positions of non-zero values in the rowcoefs array */
    9464 int varposinrow, /**< position of variable in the rowinds array for which the bounds should be determined */
    9465 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
    9466 * was not used (0) or was not used but is contained in the row (-1)
    9467 */
    9468 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    9469 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    9470 SCIP_Real* bestlb, /**< pointer to store best lower bound for transformation */
    9471 SCIP_Real* bestub, /**< pointer to store best upper bound for transformation */
    9472 SCIP_Real* bestslb, /**< pointer to store best simple lower bound for transformation */
    9473 SCIP_Real* bestsub, /**< pointer to store best simple upper bound for transformation */
    9474 int* bestlbtype, /**< pointer to store type of best lower bound (-2: local bound, -1: global bound, >= 0 variable bound index) */
    9475 int* bestubtype, /**< pointer to store type of best upper bound (-2: local bound, -1: global bound, >= 0 variable bound index) */
    9476 int* bestslbtype, /**< pointer to store type of best simple lower bound */
    9477 int* bestsubtype, /**< pointer to store type of best simple upper bound */
    9478 SCIP_BOUNDTYPE* selectedbounds, /**< pointer to store the preferred bound for the transformation */
    9479 SCIP_Bool* freevariable /**< pointer to store if variable is a free variable */
    9480 )
    9481{
    9482 SCIP_VAR* var;
    9483
    9484 SCIP_Real rowcoef;
    9485 SCIP_Real solval;
    9486
    9487 int probidx;
    9488
    9489 bestlb[varposinrow] = -SCIPinfinity(scip);
    9490 bestub[varposinrow] = SCIPinfinity(scip);
    9491 bestlbtype[varposinrow] = -3;
    9492 bestubtype[varposinrow] = -3;
    9493
    9494 probidx = rowinds[varposinrow];
    9495 var = vars[probidx];
    9496 {
    9497 SCIP_Real QUAD(tmp);
    9498 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidx);
    9499 rowcoef = QUAD_TO_DBL(tmp);
    9500 }
    9501
    9502 assert(!EPSZ(rowcoef, QUAD_EPSILON));
    9503
    9504 /* get closest simple lower bound and closest simple upper bound */
    9505 SCIP_CALL( findBestLb(scip, var, sol, 0, allowlocal, &bestslb[varposinrow], &bestslbtype[varposinrow]) );
    9506 SCIP_CALL( findBestUb(scip, var, sol, 0, allowlocal, &bestsub[varposinrow], &bestsubtype[varposinrow]) );
    9507
    9508 /* do not use too large bounds */
    9509 if( bestslb[varposinrow] <= -MAXBOUND )
    9510 bestslb[varposinrow] = -SCIPinfinity(scip);
    9511
    9512 if( bestsub[varposinrow] >= MAXBOUND )
    9513 bestsub[varposinrow] = SCIPinfinity(scip);
    9514
    9515 solval = SCIPgetSolVal(scip, sol, var);
    9516
    9517 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g(%d),%g(%d)]>:\n", varposinrow, rowcoef, SCIPvarGetName(var), probidx,
    9518 solval, bestslb[varposinrow], bestslbtype[varposinrow], bestsub[varposinrow], bestsubtype[varposinrow]);
    9519
    9520 /* mixed integer set cannot be relaxed to 0-1 single node flow set because both simple bounds are -infinity
    9521 * and infinity, respectively
    9522 */
    9523 if( SCIPisInfinity(scip, -bestslb[varposinrow]) && SCIPisInfinity(scip, bestsub[varposinrow]) )
    9524 {
    9525 *freevariable = TRUE;
    9526 return SCIP_OKAY;
    9527 }
    9528
    9529 /* get closest lower bound that can be used to define the real variable y'_j in the 0-1 single node flow
    9530 * relaxation
    9531 */
    9532 if( !SCIPisInfinity(scip, bestsub[varposinrow]) )
    9533 {
    9534 bestlb[varposinrow] = bestslb[varposinrow];
    9535 bestlbtype[varposinrow] = bestslbtype[varposinrow];
    9536
    9538 {
    9539 SCIP_Real bestvlb;
    9540 int bestvlbidx;
    9541
    9542 SCIP_CALL( getClosestVlb(scip, var, sol, rowcoefs, binvarused, bestsub[varposinrow], rowcoef, &bestvlb, &bestvlbidx) );
    9543 if( SCIPisGT(scip, bestvlb, bestlb[varposinrow]) )
    9544 {
    9545 bestlb[varposinrow] = bestvlb;
    9546 bestlbtype[varposinrow] = bestvlbidx;
    9547 }
    9548 }
    9549 }
    9550
    9551 /* get closest upper bound that can be used to define the real variable y'_j in the 0-1 single node flow
    9552 * relaxation
    9553 */
    9554 if( !SCIPisInfinity(scip, -bestslb[varposinrow]) )
    9555 {
    9556 bestub[varposinrow] = bestsub[varposinrow];
    9557 bestubtype[varposinrow] = bestsubtype[varposinrow];
    9558
    9560 {
    9561 SCIP_Real bestvub;
    9562 int bestvubidx;
    9563
    9564 SCIP_CALL( getClosestVub(scip, var, sol, rowcoefs, binvarused, bestslb[varposinrow], rowcoef, &bestvub, &bestvubidx) );
    9565 if( SCIPisLT(scip, bestvub, bestub[varposinrow]) )
    9566 {
    9567 bestub[varposinrow] = bestvub;
    9568 bestubtype[varposinrow] = bestvubidx;
    9569 }
    9570 }
    9571 }
    9572 SCIPdebugMsg(scip, " bestlb=%g(%d), bestub=%g(%d)\n", bestlb[varposinrow], bestlbtype[varposinrow], bestub[varposinrow], bestubtype[varposinrow]);
    9573
    9574 /* mixed integer set cannot be relaxed to 0-1 single node flow set because there are no suitable bounds
    9575 * to define the transformed variable y'_j
    9576 */
    9577 if( SCIPisInfinity(scip, -bestlb[varposinrow]) && SCIPisInfinity(scip, bestub[varposinrow]) )
    9578 {
    9579 *freevariable = TRUE;
    9580 return SCIP_OKAY;
    9581 }
    9582
    9583 *freevariable = FALSE;
    9584
    9585 /* select best upper bound if it is closer to the LP value of y_j and best lower bound otherwise and use this bound
    9586 * to define the real variable y'_j with 0 <= y'_j <= u'_j x_j in the 0-1 single node flow relaxation;
    9587 * prefer variable bounds
    9588 */
    9589 if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) && bestlbtype[varposinrow] >= 0 )
    9590 {
    9591 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
    9592 }
    9593 else if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow])
    9594 && bestubtype[varposinrow] >= 0 )
    9595 {
    9596 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
    9597 }
    9598 else if( SCIPisLE(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) )
    9599 {
    9600 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
    9601 }
    9602 else
    9603 {
    9604 assert(SCIPisGT(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]));
    9605 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
    9606 }
    9607
    9608 if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_LOWER && bestlbtype[varposinrow] >= 0 )
    9609 {
    9610 int vlbvarprobidx;
    9611 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
    9612
    9613 /* mark binary variable of vlb so that it is not used for other continuous variables
    9614 * by setting it's position in the aggrrow to a negative value
    9615 */
    9616 vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[varposinrow]]);
    9617 binvarused[vlbvarprobidx] = 1;
    9618 }
    9619 else if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_UPPER && bestubtype[varposinrow] >= 0 )
    9620 {
    9621 int vubvarprobidx;
    9622 SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
    9623
    9624 /* mark binary variable of vub so that it is not used for other continuous variables
    9625 * by setting it's position in the aggrrow to a negative value
    9626 */
    9627 vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[varposinrow]]);
    9628 binvarused[vubvarprobidx] = 1;
    9629 }
    9630
    9631 return SCIP_OKAY; /*lint !e438*/
    9632}
    9633
    9634/** construct a 0-1 single node flow relaxation (with some additional simple constraints) of a mixed integer set
    9635 * corresponding to the given aggrrow a * x <= rhs
    9636 */
    9637static
    9639 SCIP* scip, /**< SCIP data structure */
    9640 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    9641 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    9642 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    9643 SCIP_Real* rowcoefs, /**< array of coefficients of row */
    9644 QUAD(SCIP_Real rowrhs), /**< pointer to right hand side of row */
    9645 int* rowinds, /**< array of variables problem indices for non-zero coefficients in row */
    9646 int nnz, /**< number of non-zeros in row */
    9647 SNF_RELAXATION* snf, /**< stores the sign of the transformed variable in summation */
    9648 SCIP_Bool* success, /**< stores whether the transformation was valid */
    9649 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
    9650 )
    9651{
    9652 SCIP_VAR** vars;
    9653 int i;
    9654 int nnonbinvarsrow;
    9655 int8_t* binvarused;
    9656 int nbinvars;
    9657 SCIP_Real QUAD(transrhs);
    9658
    9659 /* arrays to store the selected bound for each non-binary variable in the row */
    9660 SCIP_Real* bestlb;
    9661 SCIP_Real* bestub;
    9662 SCIP_Real* bestslb;
    9663 SCIP_Real* bestsub;
    9664 int* bestlbtype;
    9665 int* bestubtype;
    9666 int* bestslbtype;
    9667 int* bestsubtype;
    9668 SCIP_BOUNDTYPE* selectedbounds;
    9669
    9670 *success = FALSE;
    9671
    9672 SCIPdebugMsg(scip, "--------------------- construction of SNF relaxation ------------------------------------\n");
    9673
    9674 nbinvars = SCIPgetNBinVars(scip);
    9675 vars = SCIPgetVars(scip);
    9676
    9677 SCIP_CALL( SCIPallocBufferArray(scip, &bestlb, nnz) );
    9678 SCIP_CALL( SCIPallocBufferArray(scip, &bestub, nnz) );
    9679 SCIP_CALL( SCIPallocBufferArray(scip, &bestslb, nnz) );
    9680 SCIP_CALL( SCIPallocBufferArray(scip, &bestsub, nnz) );
    9681 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtype, nnz) );
    9682 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtype, nnz) );
    9683 SCIP_CALL( SCIPallocBufferArray(scip, &bestslbtype, nnz) );
    9684 SCIP_CALL( SCIPallocBufferArray(scip, &bestsubtype, nnz) );
    9685 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, nnz) );
    9686
    9687 /* sort descending to have continuous variables first */
    9688 SCIPsortDownInt(rowinds, nnz);
    9689
    9690 /* array to store whether a binary variable is in the row (-1) or has been used (1) due to variable bound usage */
    9691 SCIP_CALL( SCIPallocCleanBufferArray(scip, &binvarused, nbinvars) );
    9692
    9693 for( i = nnz - 1; i >= 0 && rowinds[i] < nbinvars; --i )
    9694 binvarused[rowinds[i]] = -1;
    9695
    9696 nnonbinvarsrow = i + 1;
    9697 /* determine the bounds to use for transforming the non-binary variables */
    9698 for( i = 0; i < nnonbinvarsrow; ++i )
    9699 {
    9700 SCIP_Bool freevariable;
    9701
    9702 assert(rowinds[i] >= nbinvars);
    9703
    9704 SCIP_CALL( determineBoundForSNF(scip, sol, vars, rowcoefs, rowinds, i, binvarused, allowlocal, boundswitch,
    9705 bestlb, bestub, bestslb, bestsub, bestlbtype, bestubtype, bestslbtype, bestsubtype, selectedbounds, &freevariable) );
    9706
    9707 if( freevariable )
    9708 {
    9709 int j;
    9710
    9711 /* clear binvarused at indices of binary variables of row */
    9712 for( j = nnz - 1; j >= nnonbinvarsrow; --j )
    9713 binvarused[rowinds[j]] = 0;
    9714
    9715 /* clear binvarused at indices of selected variable bounds */
    9716 for( j = 0; j < i; ++j )
    9717 {
    9718 if( selectedbounds[j] == SCIP_BOUNDTYPE_LOWER && bestlbtype[j] >= 0 )
    9719 {
    9720 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(vars[rowinds[j]]);
    9721 binvarused[SCIPvarGetProbindex(vlbvars[bestlbtype[j]])] = 0;
    9722 }
    9723 else if( selectedbounds[j] == SCIP_BOUNDTYPE_UPPER && bestubtype[j] >= 0 )
    9724 {
    9725 SCIP_VAR** vubvars = SCIPvarGetVubVars(vars[rowinds[j]]);
    9726 binvarused[SCIPvarGetProbindex(vubvars[bestubtype[j]])] = 0;
    9727 }
    9728 }
    9729
    9730 /* terminate */
    9731 goto TERMINATE;
    9732 }
    9733 }
    9734
    9735 *localbdsused = FALSE;
    9736 QUAD_ASSIGN_Q(transrhs, rowrhs);
    9737 snf->ntransvars = 0;
    9738
    9739 assert(snf->transvarcoefs != NULL); /* for lint */
    9740 assert(snf->transvarvubcoefs != NULL);
    9741 assert(snf->transbinvarsolvals != NULL);
    9742 assert(snf->transcontvarsolvals != NULL);
    9743 assert(snf->aggrconstants != NULL);
    9744 assert(snf->aggrcoefscont != NULL);
    9745 assert(snf->origcontvars != NULL);
    9746 assert(snf->origbinvars != NULL);
    9747 assert(snf->aggrcoefsbin != NULL);
    9748
    9749 /* transform non-binary variables */
    9750 for( i = 0; i < nnonbinvarsrow; ++i )
    9751 {
    9752 SCIP_VAR* var;
    9753 SCIP_Real QUAD(rowcoef);
    9754 SCIP_Real solval;
    9755 int probidx;
    9756
    9757 probidx = rowinds[i];
    9758 var = vars[probidx];
    9759 QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
    9760 assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
    9761 solval = SCIPgetSolVal(scip, sol, var);
    9762
    9763 assert(probidx >= nbinvars);
    9764
    9765 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
    9766 {
    9767 /* use bestlb to define y'_j */
    9768
    9769 assert(!SCIPisInfinity(scip, bestsub[i]));
    9770 assert(!SCIPisInfinity(scip, - bestlb[i]));
    9771 assert(bestsubtype[i] == -1 || bestsubtype[i] == -2);
    9772 assert(bestlbtype[i] > -3 && bestlbtype[i] < SCIPvarGetNVlbs(var));
    9773
    9774 /* store for y_j that bestlb is the bound used to define y'_j and that y'_j is the associated real variable
    9775 * in the relaxed set
    9776 */
    9777 snf->origcontvars[snf->ntransvars] = probidx;
    9778
    9779 if( bestlbtype[i] < 0 )
    9780 {
    9781 SCIP_Real QUAD(val);
    9782 SCIP_Real QUAD(contsolval);
    9783 SCIP_Real QUAD(rowcoeftimesbestsub);
    9784
    9785 /* use simple lower bound in bestlb = l_j <= y_j <= u_j = bestsub to define
    9786 * y'_j = - a_j ( y_j - u_j ) with 0 <= y'_j <= a_j ( u_j - l_j ) x_j and x_j = 1 if a_j > 0
    9787 * y'_j = a_j ( y_j - u_j ) with 0 <= y'_j <= - a_j ( u_j - l_j ) x_j and x_j = 1 if a_j < 0,
    9788 * put j into the set
    9789 * N2 if a_j > 0
    9790 * N1 if a_j < 0
    9791 * and update the right hand side of the constraint in the relaxation
    9792 * rhs = rhs - a_j u_j
    9793 */
    9794 SCIPquadprecSumDD(val, bestsub[i], -bestlb[i]);
    9795 SCIPquadprecProdQQ(val, val, rowcoef);
    9796 SCIPquadprecSumDD(contsolval, solval, -bestsub[i]);
    9797 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
    9798
    9799 if( bestlbtype[i] == -2 || bestsubtype[i] == -2 )
    9800 *localbdsused = TRUE;
    9801
    9802 SCIPquadprecProdQD(rowcoeftimesbestsub, rowcoef, bestsub[i]);
    9803
    9804 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
    9805 snf->origbinvars[snf->ntransvars] = -1;
    9806 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
    9807
    9808 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
    9809 {
    9810 snf->transvarcoefs[snf->ntransvars] = - 1;
    9811 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
    9812 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
    9813 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
    9814
    9815 /* aggregation information for y'_j */
    9816 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestsub);
    9817 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
    9818 }
    9819 else
    9820 {
    9821 snf->transvarcoefs[snf->ntransvars] = 1;
    9822 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
    9823 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
    9824 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
    9825
    9826 /* aggregation information for y'_j */
    9827 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestsub);
    9828 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
    9829 }
    9830 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestsub);
    9831
    9832 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
    9833 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
    9834 snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestsub), QUAD_TO_DBL(rowcoef), bestsub[i], QUAD_TO_DBL(transrhs));
    9835 }
    9836 else
    9837 {
    9838 SCIP_Real QUAD(rowcoefbinary);
    9839 SCIP_Real varsolvalbinary;
    9840 SCIP_Real QUAD(val);
    9841 SCIP_Real QUAD(contsolval);
    9842 SCIP_Real QUAD(rowcoeftimesvlbconst);
    9843 int vlbvarprobidx;
    9844
    9845 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
    9846 SCIP_Real* vlbconsts = SCIPvarGetVlbConstants(var);
    9847 SCIP_Real* vlbcoefs = SCIPvarGetVlbCoefs(var);
    9848
    9849 /* use variable lower bound in bestlb = l~_j x_j + d_j <= y_j <= u_j = bestsub to define
    9850 * y'_j = - ( a_j ( y_j - d_j ) + c_j x_j ) with 0 <= y'_j <= - ( a_j l~_j + c_j ) x_j if a_j > 0
    9851 * y'_j = a_j ( y_j - d_j ) + c_j x_j with 0 <= y'_j <= ( a_j l~_j + c_j ) x_j if a_j < 0,
    9852 * where c_j is the coefficient of x_j in the row, put j into the set
    9853 * N2 if a_j > 0
    9854 * N1 if a_j < 0
    9855 * and update the right hand side of the constraint in the relaxation
    9856 * rhs = rhs - a_j d_j
    9857 */
    9858
    9859 vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[i]]);
    9860 assert(binvarused[vlbvarprobidx] == 1);
    9861 assert(vlbvarprobidx < nbinvars);
    9862
    9863 QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vlbvarprobidx);
    9864 varsolvalbinary = SCIPgetSolVal(scip, sol, vlbvars[bestlbtype[i]]);
    9865
    9866 SCIPquadprecProdQD(val, rowcoef, vlbcoefs[bestlbtype[i]]);
    9867 SCIPquadprecSumQQ(val, val, rowcoefbinary);
    9868 {
    9869 SCIP_Real QUAD(tmp);
    9870
    9871 SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
    9872 SCIPquadprecSumDD(contsolval, solval, - vlbconsts[bestlbtype[i]]);
    9873 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
    9874 SCIPquadprecSumQQ(contsolval, contsolval, tmp);
    9875 }
    9876
    9877 SCIPquadprecProdQD(rowcoeftimesvlbconst, rowcoef, vlbconsts[bestlbtype[i]]);
    9878
    9879 /* clear the binvarpos array, since the variable has been processed */
    9880 binvarused[vlbvarprobidx] = 0;
    9881
    9882 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
    9883 snf->origbinvars[snf->ntransvars] = vlbvarprobidx;
    9884
    9885 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
    9886 {
    9887 snf->transvarcoefs[snf->ntransvars] = - 1;
    9888 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
    9889 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
    9890 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
    9891
    9892 /* aggregation information for y'_j */
    9893 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
    9894 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
    9895 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvlbconst);
    9896 }
    9897 else
    9898 {
    9899 snf->transvarcoefs[snf->ntransvars] = 1;
    9900 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
    9901 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
    9902 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
    9903
    9904 /* aggregation information for y'_j */
    9905 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
    9906 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
    9907 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvlbconst);
    9908 }
    9909 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvlbconst);
    9910
    9911 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
    9912 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
    9913 snf->ntransvars, SCIPvarGetName(vlbvars[bestlbtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvlbconst), QUAD_TO_DBL(rowcoef),
    9914 vlbconsts[bestlbtype[i]], QUAD_TO_DBL(transrhs) );
    9915 }
    9916 }
    9917 else
    9918 {
    9919 /* use bestub to define y'_j */
    9920
    9921 assert(!SCIPisInfinity(scip, bestub[i]));
    9922 assert(!SCIPisInfinity(scip, - bestslb[i]));
    9923 assert(bestslbtype[i] == -1 || bestslbtype[i] == -2);
    9924 assert(bestubtype[i] > -3 && bestubtype[i] < SCIPvarGetNVubs(var));
    9925
    9926 /* store for y_j that y'_j is the associated real variable
    9927 * in the relaxed set
    9928 */
    9929 snf->origcontvars[snf->ntransvars] = probidx;
    9930
    9931 if( bestubtype[i] < 0 )
    9932 {
    9933 SCIP_Real QUAD(val);
    9934 SCIP_Real QUAD(contsolval);
    9935 SCIP_Real QUAD(rowcoeftimesbestslb);
    9936
    9937 /* use simple upper bound in bestslb = l_j <= y_j <= u_j = bestub to define
    9938 * y'_j = a_j ( y_j - l_j ) with 0 <= y'_j <= a_j ( u_j - l_j ) x_j and x_j = 1 if a_j > 0
    9939 * y'_j = - a_j ( y_j - l_j ) with 0 <= y'_j <= - a_j ( u_j - l_j ) x_j and x_j = 1 if a_j < 0,
    9940 * put j into the set
    9941 * N1 if a_j > 0
    9942 * N2 if a_j < 0
    9943 * and update the right hand side of the constraint in the relaxation
    9944 * rhs = rhs - a_j l_j
    9945 */
    9946 SCIPquadprecSumDD(val, bestub[i], - bestslb[i]);
    9947 SCIPquadprecProdQQ(val, val, rowcoef);
    9948 SCIPquadprecSumDD(contsolval, solval, - bestslb[i]);
    9949 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
    9950
    9951 if( bestubtype[i] == -2 || bestslbtype[i] == -2 )
    9952 *localbdsused = TRUE;
    9953
    9954 SCIPquadprecProdQD(rowcoeftimesbestslb, rowcoef, bestslb[i]);
    9955
    9956 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
    9957 snf->origbinvars[snf->ntransvars] = -1;
    9958 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
    9959
    9960 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
    9961 {
    9962 snf->transvarcoefs[snf->ntransvars] = 1;
    9963 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
    9964 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
    9965 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
    9966
    9967 /* aggregation information for y'_j */
    9968 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
    9969 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestslb);
    9970 }
    9971 else
    9972 {
    9973 snf->transvarcoefs[snf->ntransvars] = - 1;
    9974 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
    9975 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
    9976 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
    9977
    9978 /* aggregation information for y'_j */
    9979 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
    9980 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestslb);
    9981 }
    9982 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestslb);
    9983
    9984 SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., Y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
    9985 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
    9986 snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestslb), QUAD_TO_DBL(rowcoef), bestslb[i], QUAD_TO_DBL(transrhs));
    9987 }
    9988 else
    9989 {
    9990 SCIP_Real QUAD(rowcoefbinary);
    9991 SCIP_Real varsolvalbinary;
    9992 SCIP_Real QUAD(val);
    9993 SCIP_Real QUAD(contsolval);
    9994 SCIP_Real QUAD(rowcoeftimesvubconst);
    9995 int vubvarprobidx;
    9996
    9997 SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
    9998 SCIP_Real* vubconsts = SCIPvarGetVubConstants(var);
    9999 SCIP_Real* vubcoefs = SCIPvarGetVubCoefs(var);
    10000
    10001 /* use variable upper bound in bestslb = l_j <= y_j <= u~_j x_j + d_j = bestub to define
    10002 * y'_j = a_j ( y_j - d_j ) + c_j x_j with 0 <= y'_j <= ( a_j u~_j + c_j ) x_j if a_j > 0
    10003 * y'_j = - ( a_j ( y_j - d_j ) + c_j x_j ) with 0 <= y'_j <= - ( a_j u~_j + c_j ) x_j if a_j < 0,
    10004 * where c_j is the coefficient of x_j in the row, put j into the set
    10005 * N1 if a_j > 0
    10006 * N2 if a_j < 0
    10007 * and update the right hand side of the constraint in the relaxation
    10008 * rhs = rhs - a_j d_j
    10009 */
    10010
    10011 vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[i]]);
    10012 assert(binvarused[vubvarprobidx] == 1);
    10013 assert(vubvarprobidx < nbinvars);
    10014
    10015 QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vubvarprobidx);
    10016 varsolvalbinary = SCIPgetSolVal(scip, sol, vubvars[bestubtype[i]]);
    10017
    10018 /* clear the binvarpos array, since the variable has been processed */
    10019 binvarused[vubvarprobidx] = 0;
    10020
    10021 SCIPquadprecProdQD(val, rowcoef, vubcoefs[bestubtype[i]]);
    10022 SCIPquadprecSumQQ(val, val, rowcoefbinary);
    10023 {
    10024 SCIP_Real QUAD(tmp);
    10025 SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
    10026 SCIPquadprecSumDD(contsolval, solval, - vubconsts[bestubtype[i]]);
    10027 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
    10028 SCIPquadprecSumQQ(contsolval, contsolval, tmp);
    10029 }
    10030
    10031 SCIPquadprecProdQD(rowcoeftimesvubconst, rowcoef, vubconsts[bestubtype[i]]);
    10032 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
    10033 snf->origbinvars[snf->ntransvars] = vubvarprobidx;
    10034
    10035 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
    10036 {
    10037 snf->transvarcoefs[snf->ntransvars] = 1;
    10038 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
    10039 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
    10040 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
    10041
    10042 /* aggregation information for y'_j */
    10043 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
    10044 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
    10045 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvubconst);
    10046 }
    10047 else
    10048 {
    10049 snf->transvarcoefs[snf->ntransvars] = - 1;
    10050 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
    10051 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
    10052 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
    10053
    10054 /* aggregation information for y'_j */
    10055 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
    10056 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
    10057 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvubconst);
    10058 }
    10059 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvubconst);
    10060
    10061 /* store for x_j that y'_j is the associated real variable in the 0-1 single node flow relaxation */
    10062
    10063 SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
    10064 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
    10065 snf->ntransvars, SCIPvarGetName(vubvars[bestubtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvubconst), QUAD_TO_DBL(rowcoef),
    10066 vubconsts[bestubtype[i]], QUAD_TO_DBL(transrhs));
    10067 }
    10068 }
    10069
    10070 /* make sure the coefficient is not negative due to small numerical rounding errors */
    10071 assert(snf->transvarvubcoefs[snf->ntransvars] > -QUAD_EPSILON);
    10072 snf->transvarvubcoefs[snf->ntransvars] = MAX(snf->transvarvubcoefs[snf->ntransvars], 0.0);
    10073
    10074 ++snf->ntransvars;
    10075 }
    10076
    10077 snf->transrhs = QUAD_TO_DBL(transrhs);
    10078
    10079 /* transform remaining binary variables of row */
    10080 for( i = nnonbinvarsrow; i < nnz; ++i )
    10081 {
    10082 SCIP_VAR* var;
    10083 SCIP_Real QUAD(rowcoef);
    10084 int probidx;
    10085 SCIP_Real val;
    10086 SCIP_Real contsolval;
    10087 SCIP_Real varsolval;
    10088
    10089 probidx = rowinds[i];
    10090 /* variable should be binary */
    10091 assert(probidx >= 0);
    10092 assert(probidx < nbinvars);
    10093
    10094 /* binary variable was processed together with a non-binary variable */
    10095 if( binvarused[probidx] == 0 )
    10096 continue;
    10097
    10098 /* binary variable was not processed yet, so the binvarused value sould be -1 */
    10099 assert(binvarused[probidx] == -1);
    10100
    10101 /* set binvarused to zero since it has been processed */
    10102 binvarused[probidx] = 0;
    10103
    10104 var = vars[probidx];
    10105 QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
    10106 assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
    10107
    10108 varsolval = SCIPgetSolVal(scip, sol, var);
    10109 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g, %g]>:\n", i, QUAD_TO_DBL(rowcoef), SCIPvarGetName(var), probidx, varsolval,
    10111
    10112 /* define
    10113 * y'_j = c_j x_j with 0 <= y'_j <= c_j x_j if c_j > 0
    10114 * y'_j = - c_j x_j with 0 <= y'_j <= - c_j x_j if c_j < 0,
    10115 * where c_j is the coefficient of x_j in the row and put j into the set
    10116 * N1 if c_j > 0
    10117 * N2 if c_j < 0.
    10118 */
    10119 val = QUAD_TO_DBL(rowcoef);
    10120 contsolval = QUAD_TO_DBL(rowcoef) * varsolval;
    10121
    10122 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
    10123 snf->origbinvars[snf->ntransvars] = probidx;
    10124 snf->origcontvars[snf->ntransvars] = -1;
    10125 snf->aggrcoefscont[snf->ntransvars] = 0.0;
    10126 snf->aggrconstants[snf->ntransvars] = 0.0;
    10127
    10128 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
    10129 {
    10130 snf->transvarcoefs[snf->ntransvars] = 1;
    10131 snf->transvarvubcoefs[snf->ntransvars] = val;
    10132 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
    10133 snf->transcontvarsolvals[snf->ntransvars] = contsolval;
    10134
    10135 /* aggregation information for y'_j */
    10136 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
    10137 }
    10138 else
    10139 {
    10140 snf->transvarcoefs[snf->ntransvars] = - 1;
    10141 snf->transvarvubcoefs[snf->ntransvars] = - val;
    10142 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
    10143 snf->transcontvarsolvals[snf->ntransvars] = - contsolval;
    10144
    10145 /* aggregation information for y'_j */
    10146 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
    10147 }
    10148
    10149 assert(snf->transvarcoefs[snf->ntransvars] == 1 || snf->transvarcoefs[snf->ntransvars] == - 1 );
    10150 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[snf->ntransvars], 0.0)
    10151 && SCIPisFeasLE(scip, snf->transbinvarsolvals[snf->ntransvars], 1.0));
    10152 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[snf->ntransvars], 0.0)
    10154
    10155 SCIPdebugMsg(scip, " --> ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s))\n", snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars,
    10156 snf->transvarvubcoefs[snf->ntransvars], snf->ntransvars, SCIPvarGetName(var) );
    10157
    10158 /* updates number of variables in transformed problem */
    10159 snf->ntransvars++;
    10160 }
    10161
    10162 /* construction was successful */
    10163 *success = TRUE;
    10164
    10165#ifdef SCIP_DEBUG
    10166 SCIPdebugMsg(scip, "constraint in constructed 0-1 single node flow relaxation: ");
    10167 for( i = 0; i < snf->ntransvars; i++ )
    10168 {
    10169 SCIPdebugMsgPrint(scip, "%s y'_%d ", snf->transvarcoefs[i] == 1 ? "+" : "-", i);
    10170 }
    10171 SCIPdebugMsgPrint(scip, "<= %g\n", snf->transrhs);
    10172#endif
    10173
    10174 TERMINATE:
    10175
    10176 SCIPfreeCleanBufferArray(scip, &binvarused);
    10177 SCIPfreeBufferArray(scip, &selectedbounds);
    10178 SCIPfreeBufferArray(scip, &bestsubtype);
    10179 SCIPfreeBufferArray(scip, &bestslbtype);
    10180 SCIPfreeBufferArray(scip, &bestubtype);
    10181 SCIPfreeBufferArray(scip, &bestlbtype);
    10182 SCIPfreeBufferArray(scip, &bestsub);
    10183 SCIPfreeBufferArray(scip, &bestslb);
    10184 SCIPfreeBufferArray(scip, &bestub);
    10185 SCIPfreeBufferArray(scip, &bestlb);
    10186
    10187 return SCIP_OKAY;
    10188}
    10189
    10190/** allocate buffer arrays for storing the single-node-flow relaxation */
    10191static
    10193 SCIP* scip, /**< SCIP data structure */
    10194 SNF_RELAXATION* snf, /**< pointer to snf relaxation to be destroyed */
    10195 int nvars /**< number of active problem variables */
    10196 )
    10197{
    10207
    10208 return SCIP_OKAY;
    10209}
    10210
    10211/** free buffer arrays for storing the single-node-flow relaxation */
    10212static
    10214 SCIP* scip, /**< SCIP data structure */
    10215 SNF_RELAXATION* snf /**< pointer to snf relaxation to be destroyed */
    10216 )
    10217{
    10227}
    10228
    10229/** solve knapsack problem in maximization form with "<" constraint approximately by greedy; if needed, one can provide
    10230 * arrays to store all selected items and all not selected items
    10231 */
    10232static
    10234 SCIP* scip, /**< SCIP data structure */
    10235 int nitems, /**< number of available items */
    10236 SCIP_Real* weights, /**< item weights */
    10237 SCIP_Real* profits, /**< item profits */
    10238 SCIP_Real capacity, /**< capacity of knapsack */
    10239 int* items, /**< item numbers */
    10240 int* solitems, /**< array to store items in solution, or NULL */
    10241 int* nonsolitems, /**< array to store items not in solution, or NULL */
    10242 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
    10243 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
    10244 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
    10245 )
    10246{
    10247 SCIP_Real* tempsort;
    10248 SCIP_Real solitemsweight;
    10249 SCIP_Real mediancapacity;
    10250 int j;
    10251 int i;
    10252 int criticalitem;
    10253
    10254 assert(weights != NULL);
    10255 assert(profits != NULL);
    10256 assert(SCIPisFeasGE(scip, capacity, 0.0));
    10257 assert(!SCIPisInfinity(scip, capacity));
    10258 assert(items != NULL);
    10259 assert(nitems >= 0);
    10260
    10261 if( solitems != NULL )
    10262 {
    10263 *nsolitems = 0;
    10264 *nnonsolitems = 0;
    10265 }
    10266 if( solval != NULL )
    10267 *solval = 0.0;
    10268
    10269 /* allocate memory for temporary array used for sorting; array should contain profits divided by corresponding weights (p_1 / w_1 ... p_n / w_n )*/
    10270 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
    10271
    10272 /* initialize temporary array */
    10273 for( i = nitems - 1; i >= 0; --i )
    10274 tempsort[i] = profits[i] / weights[i];
    10275
    10276 /* decrease capacity slightly to make it tighter than the original capacity */
    10277 mediancapacity = capacity * (1 - SCIPfeastol(scip));
    10278
    10279 /* rearrange items around */
    10280 SCIPselectWeightedDownRealRealInt(tempsort, profits, items, weights, mediancapacity, nitems, &criticalitem);
    10281
    10282 /* free temporary array */
    10283 SCIPfreeBufferArray(scip, &tempsort);
    10284
    10285 /* select items as long as they fit into the knapsack */
    10286 solitemsweight = 0.0;
    10287 for( j = 0; j < nitems && SCIPisFeasLT(scip, solitemsweight + weights[j], capacity); j++ )
    10288 {
    10289 if( solitems != NULL )
    10290 {
    10291 solitems[*nsolitems] = items[j];
    10292 (*nsolitems)++;
    10293 }
    10294 if( solval != NULL )
    10295 (*solval) += profits[j];
    10296 solitemsweight += weights[j];
    10297 }
    10298
    10299 /* continue to put items into the knapsack if they entirely fit */
    10300 for( ; j < nitems; j++ )
    10301 {
    10302 if( SCIPisFeasLT(scip, solitemsweight + weights[j], capacity) )
    10303 {
    10304 if( solitems != NULL )
    10305 {
    10306 solitems[*nsolitems] = items[j];
    10307 (*nsolitems)++;
    10308 }
    10309 if( solval != NULL )
    10310 (*solval) += profits[j];
    10311 solitemsweight += weights[j];
    10312 }
    10313 else if( solitems != NULL )
    10314 {
    10315 nonsolitems[*nnonsolitems] = items[j];
    10316 (*nnonsolitems)++;
    10317 }
    10318 }
    10319
    10320 return SCIP_OKAY;
    10321}
    10322
    10323
    10324/** build the flow cover which corresponds to the given exact or approximate solution of KP^SNF; given unfinished
    10325 * flow cover contains variables which have been fixed in advance
    10326 */
    10327static
    10329 SCIP* scip, /**< SCIP data structure */
    10330 int* coefs, /**< coefficient of all real variables in N1&N2 */
    10331 SCIP_Real* vubcoefs, /**< coefficient in vub of all real variables in N1&N2 */
    10332 SCIP_Real rhs, /**< right hand side of 0-1 single node flow constraint */
    10333 int* solitems, /**< items in knapsack */
    10334 int* nonsolitems, /**< items not in knapsack */
    10335 int nsolitems, /**< number of items in knapsack */
    10336 int nnonsolitems, /**< number of items not in knapsack */
    10337 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
    10338 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
    10339 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
    10340 QUAD(SCIP_Real* flowcoverweight), /**< pointer to store weight of flow cover */
    10341 SCIP_Real* lambda /**< pointer to store lambda */
    10342 )
    10343{
    10344 int j;
    10345 SCIP_Real QUAD(tmp);
    10346
    10347 assert(scip != NULL);
    10348 assert(coefs != NULL);
    10349 assert(vubcoefs != NULL);
    10350 assert(solitems != NULL);
    10351 assert(nonsolitems != NULL);
    10352 assert(nsolitems >= 0);
    10353 assert(nnonsolitems >= 0);
    10354 assert(nflowcovervars != NULL && *nflowcovervars >= 0);
    10355 assert(nnonflowcovervars != NULL && *nnonflowcovervars >= 0);
    10356 assert(flowcoverstatus != NULL);
    10357 assert(QUAD_HI(flowcoverweight) != NULL);
    10358 assert(lambda != NULL);
    10359
    10360 /* get flowcover status for each item */
    10361 for( j = 0; j < nsolitems; j++ )
    10362 {
    10363 /* j in N1 with z°_j = 1 => j in N1\C1 */
    10364 if( coefs[solitems[j]] == 1 )
    10365 {
    10366 flowcoverstatus[solitems[j]] = -1;
    10367 (*nnonflowcovervars)++;
    10368 }
    10369 /* j in N2 with z_j = 1 => j in C2 */
    10370 else
    10371 {
    10372 assert(coefs[solitems[j]] == -1);
    10373 flowcoverstatus[solitems[j]] = 1;
    10374 (*nflowcovervars)++;
    10375 SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, -vubcoefs[solitems[j]]);
    10376 }
    10377 }
    10378 for( j = 0; j < nnonsolitems; j++ )
    10379 {
    10380 /* j in N1 with z°_j = 0 => j in C1 */
    10381 if( coefs[nonsolitems[j]] == 1 )
    10382 {
    10383 flowcoverstatus[nonsolitems[j]] = 1;
    10384 (*nflowcovervars)++;
    10385 SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, vubcoefs[nonsolitems[j]]);
    10386 }
    10387 /* j in N2 with z_j = 0 => j in N2\C2 */
    10388 else
    10389 {
    10390 assert(coefs[nonsolitems[j]] == -1);
    10391 flowcoverstatus[nonsolitems[j]] = -1;
    10392 (*nnonflowcovervars)++;
    10393 }
    10394 }
    10395
    10396 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
    10397 SCIPquadprecSumQD(tmp, *flowcoverweight, -rhs);
    10398 *lambda = QUAD_TO_DBL(tmp);
    10399}
    10400
    10401#ifndef NO_EXACT_KNAPSACK
    10402
    10403/** checks whether the given scalar scales the given value to an integral number with error in the given bounds */
    10404static
    10406 SCIP_Real val, /**< value that should be scaled to an integral value */
    10407 SCIP_Real scalar, /**< scalar that should be tried */
    10408 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
    10409 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
    10410 )
    10411{
    10412 SCIP_Real sval;
    10413 SCIP_Real downval;
    10414 SCIP_Real upval;
    10415
    10416 assert(mindelta <= 0.0);
    10417 assert(maxdelta >= 0.0);
    10418
    10419 sval = val * scalar;
    10420 downval = floor(sval);
    10421 upval = ceil(sval);
    10422
    10423 return (SCIPrelDiff(sval, downval) <= maxdelta || SCIPrelDiff(sval, upval) >= mindelta);
    10424}
    10425
    10426/** get integral number with error in the bounds which corresponds to given value scaled by a given scalar;
    10427 * should be used in connection with isIntegralScalar()
    10428 */
    10429static
    10430SCIP_Longint getIntegralVal(
    10431 SCIP_Real val, /**< value that should be scaled to an integral value */
    10432 SCIP_Real scalar, /**< scalar that should be tried */
    10433 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
    10434 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
    10435 )
    10436{
    10437 SCIP_Real sval;
    10438 SCIP_Real upval;
    10439 SCIP_Longint intval;
    10440
    10441 assert(mindelta <= 0.0);
    10442 assert(maxdelta >= 0.0);
    10443
    10444 sval = val * scalar;
    10445 upval = ceil(sval);
    10446
    10447 if( SCIPrelDiff(sval, upval) >= mindelta )
    10448 intval = (SCIP_Longint) upval;
    10449 else
    10450 intval = (SCIP_Longint) (floor(sval));
    10451
    10452 return intval;
    10453}
    10454
    10455/** get a flow cover (C1, C2) for a given 0-1 single node flow set
    10456 * {(x,y) in {0,1}^n x R^n : sum_{j in N1} y_j - sum_{j in N2} y_j <= b, 0 <= y_j <= u_j x_j},
    10457 * i.e., get sets C1 subset N1 and C2 subset N2 with sum_{j in C1} u_j - sum_{j in C2} u_j = b + lambda and lambda > 0
    10458 */
    10459static
    10461 SCIP* scip, /**< SCIP data structure */
    10462 SNF_RELAXATION* snf, /**< the single node flow relaxation */
    10463 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
    10464 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
    10465 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
    10466 SCIP_Real* lambda, /**< pointer to store lambda */
    10467 SCIP_Bool* found /**< pointer to store whether a cover was found */
    10468 )
    10469{
    10470 SCIP_Real* transprofitsint;
    10471 SCIP_Real* transprofitsreal;
    10472 SCIP_Real* transweightsreal;
    10473 SCIP_Longint* transweightsint;
    10474 int* items;
    10475 int* itemsint;
    10476 int* nonsolitems;
    10477 int* solitems;
    10478 SCIP_Real QUAD(flowcoverweight);
    10479 SCIP_Real QUAD(flowcoverweightafterfix);
    10480 SCIP_Real n1itemsweight;
    10481 SCIP_Real n2itemsminweight;
    10482 SCIP_Real scalar;
    10483 SCIP_Real transcapacityreal;
    10484#if !defined(NDEBUG) || defined(SCIP_DEBUG)
    10485 SCIP_Bool kpexact;
    10486#endif
    10487 SCIP_Bool scalesuccess;
    10488 SCIP_Bool transweightsrealintegral;
    10489 SCIP_Longint transcapacityint;
    10490 int nflowcovervarsafterfix;
    10491 int nitems;
    10492 int nn1items;
    10493 int nnonflowcovervarsafterfix;
    10494 int nnonsolitems;
    10495 int nsolitems;
    10496 int j;
    10497
    10498 assert(scip != NULL);
    10499 assert(snf->transvarcoefs != NULL);
    10500 assert(snf->transbinvarsolvals != NULL);
    10501 assert(snf->transvarvubcoefs != NULL);
    10502 assert(snf->ntransvars > 0);
    10503 assert(nflowcovervars != NULL);
    10504 assert(nnonflowcovervars != NULL);
    10505 assert(flowcoverstatus != NULL);
    10506 assert(lambda != NULL);
    10507 assert(found != NULL);
    10508
    10509 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
    10510
    10511 /* get data structures */
    10513 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
    10514 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
    10515 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsint, snf->ntransvars) );
    10516 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
    10517 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
    10518 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
    10519 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
    10520
    10521 BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
    10522 *found = FALSE;
    10523 *nflowcovervars = 0;
    10524 *nnonflowcovervars = 0;
    10525
    10526 QUAD_ASSIGN(flowcoverweight, 0.0);
    10527 nflowcovervarsafterfix = 0;
    10528 nnonflowcovervarsafterfix = 0;
    10529 QUAD_ASSIGN(flowcoverweightafterfix, 0.0);
    10530#if !defined(NDEBUG) || defined(SCIP_DEBUG)
    10531 kpexact = FALSE;
    10532#endif
    10533
    10534 /* fix some variables in advance according to the following fixing strategy
    10535 * put j into N1\C1, if j in N1 and x*_j = 0,
    10536 * put j into C1, if j in N1 and x*_j = 1,
    10537 * put j into C2, if j in N2 and x*_j = 1,
    10538 * put j into N2\C2, if j in N2 and x*_j = 0
    10539 * and get the set of the remaining variables
    10540 */
    10541 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
    10542 nitems = 0;
    10543 nn1items = 0;
    10544 n1itemsweight = 0.0;
    10545 n2itemsminweight = SCIP_REAL_MAX;
    10546 for( j = 0; j < snf->ntransvars; j++ )
    10547 {
    10548 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
    10549 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
    10550 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
    10551
    10552 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
    10553 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
    10554 {
    10555 flowcoverstatus[j] = -1;
    10556 (*nnonflowcovervars)++;
    10557 continue;
    10558 }
    10559
    10560 /* x*_j is fractional */
    10562 {
    10563 items[nitems] = j;
    10564 nitems++;
    10565 if( snf->transvarcoefs[j] == 1 )
    10566 {
    10567 n1itemsweight += snf->transvarvubcoefs[j];
    10568 nn1items++;
    10569 }
    10570 else
    10571 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
    10572 }
    10573 /* j is in N1 and x*_j = 0 */
    10574 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
    10575 {
    10576 flowcoverstatus[j] = -1;
    10577 (*nnonflowcovervars)++;
    10578 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
    10579 }
    10580 /* j is in N1 and x*_j = 1 */
    10581 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
    10582 {
    10583 flowcoverstatus[j] = 1;
    10584 (*nflowcovervars)++;
    10585 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
    10586 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
    10587 }
    10588 /* j is in N2 and x*_j = 1 */
    10589 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
    10590 {
    10591 flowcoverstatus[j] = 1;
    10592 (*nflowcovervars)++;
    10593 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
    10594 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
    10595 }
    10596 /* j is in N2 and x*_j = 0 */
    10597 else
    10598 {
    10599 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
    10600 flowcoverstatus[j] = -1;
    10601 (*nnonflowcovervars)++;
    10602 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
    10603 }
    10604 }
    10605 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
    10606 assert(nn1items >= 0);
    10607
    10608 /* to find a flow cover, transform the following knapsack problem
    10609 *
    10610 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
    10611 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
    10612 * z_j in {0,1} for all j in N1 & N2
    10613 *
    10614 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
    10615 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
    10616 *
    10617 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
    10618 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
    10619 * z°_j in {0,1} for all j in N1
    10620 * z_j in {0,1} for all j in N2,
    10621 * and solve it approximately under consideration of the fixing,
    10622 * or
    10623 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
    10624 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
    10625 * and multiplying the constraint by a suitable scalar C
    10626 *
    10627 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
    10628 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
    10629 * z°_j in {0,1} for all j in N1
    10630 * z_j in {0,1} for all j in N2,
    10631 * where
    10632 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
    10633 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
    10634 * and solve it exactly under consideration of the fixing.
    10635 */
    10636 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
    10637
    10638 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
    10639 transweightsrealintegral = TRUE;
    10640 for( j = 0; j < nitems; j++ )
    10641 {
    10642 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
    10643
    10644 if( !isIntegralScalar(transweightsreal[j], 1.0, -MINDELTA, MAXDELTA) )
    10645 transweightsrealintegral = FALSE;
    10646
    10647 if( snf->transvarcoefs[items[j]] == 1 )
    10648 {
    10649 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
    10650 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
    10651 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
    10652 }
    10653 else
    10654 {
    10655 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
    10656 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
    10657 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
    10658 }
    10659 }
    10660 /* get capacity of knapsack constraint in KP^SNF_rat */
    10661 transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight;
    10662 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
    10663 snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
    10664
    10665 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
    10666 * is less than or equal to zero
    10667 */
    10668 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
    10669 {
    10670 assert(!(*found));
    10671 goto TERMINATE;
    10672 }
    10673
    10674 /* KP^SNF_rat has been solved by fixing some variables in advance */
    10675 assert(nitems >= 0);
    10676 if( nitems == 0)
    10677 {
    10678 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
    10679 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
    10680 *lambda = QUAD_TO_DBL(flowcoverweight);
    10681 *found = TRUE;
    10682 goto TERMINATE;
    10683 }
    10684
    10685 /* Use the following strategy
    10686 * solve KP^SNF_int exactly, if a suitable factor C is found and (nitems*capacity) <= MAXDYNPROGSPACE,
    10687 * solve KP^SNF_rat approximately, otherwise
    10688 */
    10689
    10690 /* find a scaling factor C */
    10691 if( transweightsrealintegral )
    10692 {
    10693 /* weights are already integral */
    10694 scalar = 1.0;
    10695 scalesuccess = TRUE;
    10696 }
    10697 else
    10698 {
    10699 scalesuccess = FALSE;
    10700 SCIP_CALL( SCIPcalcIntegralScalar(transweightsreal, nitems, -MINDELTA, MAXDELTA, MAXDNOM, MAXSCALE, &scalar,
    10701 &scalesuccess) );
    10702 }
    10703
    10704 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
    10705 nsolitems = -1;
    10706 nnonsolitems = -1;
    10707
    10708 /* suitable factor C was found*/
    10709 if( scalesuccess )
    10710 {
    10711 SCIP_Real tmp1;
    10712 SCIP_Real tmp2;
    10713
    10714 /* transform KP^SNF to KP^SNF_int */
    10715 for( j = 0; j < nitems; ++j )
    10716 {
    10717 transweightsint[j] = getIntegralVal(transweightsreal[j], scalar, -MINDELTA, MAXDELTA);
    10718 transprofitsint[j] = transprofitsreal[j];
    10719 itemsint[j] = items[j];
    10720 }
    10721 if( isIntegralScalar(transcapacityreal, scalar, -MINDELTA, MAXDELTA) )
    10722 {
    10723 transcapacityint = getIntegralVal(transcapacityreal, scalar, -MINDELTA, MAXDELTA);
    10724 transcapacityint -= 1;
    10725 }
    10726 else
    10727 transcapacityint = (SCIP_Longint) (transcapacityreal * scalar);
    10728 nflowcovervarsafterfix = *nflowcovervars;
    10729 nnonflowcovervarsafterfix = *nnonflowcovervars;
    10730 QUAD_ASSIGN_Q(flowcoverweightafterfix, flowcoverweight);
    10731
    10732 tmp1 = (SCIP_Real) (nitems + 1);
    10733 tmp2 = (SCIP_Real) ((transcapacityint) + 1);
    10734 if( transcapacityint * nitems <= MAXDYNPROGSPACE && tmp1 * tmp2 <= INT_MAX / 8.0)
    10735 {
    10736 SCIP_Bool success;
    10737
    10738 /* solve KP^SNF_int by dynamic programming */
    10739 SCIP_CALL( SCIPsolveKnapsackExactly(scip, nitems, transweightsint, transprofitsint, transcapacityint,
    10740 itemsint, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL, &success) );
    10741
    10742 if( !success )
    10743 {
    10744 /* solve KP^SNF_rat approximately */
    10745 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal,
    10746 transcapacityreal, items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
    10747 }
    10748#if !defined(NDEBUG) || defined(SCIP_DEBUG)
    10749 else
    10750 kpexact = TRUE;
    10751#endif
    10752 }
    10753 else
    10754 {
    10755 /* solve KP^SNF_rat approximately */
    10756 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
    10757 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
    10758 assert(!kpexact);
    10759 }
    10760 }
    10761 else
    10762 {
    10763 /* solve KP^SNF_rat approximately */
    10764 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
    10765 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
    10766 assert(!kpexact);
    10767 }
    10768
    10769 assert(nsolitems != -1);
    10770 assert(nnonsolitems != -1);
    10771
    10772 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
    10773 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
    10774 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
    10775 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
    10776 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
    10777
    10778 /* if the found structure is not a flow cover, because of scaling, solve KP^SNF_rat approximately */
    10779 if( SCIPisFeasLE(scip, *lambda, 0.0) )
    10780 {
    10781 assert(kpexact);
    10782
    10783 /* solve KP^SNF_rat approximately */
    10784 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
    10785 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
    10786#ifdef SCIP_DEBUG /* this time only for SCIP_DEBUG, because only then, the variable is used again */
    10787 kpexact = FALSE;
    10788#endif
    10789
    10790 /* build the flow cover from the solution of KP^SNF_rat and the fixing */
    10791 *nflowcovervars = nflowcovervarsafterfix;
    10792 *nnonflowcovervars = nnonflowcovervarsafterfix;
    10793 QUAD_ASSIGN_Q(flowcoverweight, flowcoverweightafterfix);
    10794
    10795 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
    10796 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
    10797 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
    10798 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
    10799 }
    10800 *found = SCIPisFeasGT(scip, *lambda, 0.0);
    10801
    10802 TERMINATE:
    10803 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
    10804#ifdef SCIP_DEBUG
    10805 if( *found )
    10806 {
    10807 SCIPdebugMsg(scip, "2. %s solution:\n", kpexact ? "exact" : "approximate");
    10808 for( j = 0; j < snf->ntransvars; j++ )
    10809 {
    10810 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
    10811 {
    10812 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
    10813 }
    10814 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
    10815 {
    10816 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
    10817 }
    10818 }
    10819 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
    10820 }
    10821#endif
    10822
    10823 /* free data structures */
    10824 SCIPfreeBufferArray(scip, &nonsolitems);
    10825 SCIPfreeBufferArray(scip, &solitems);
    10826 SCIPfreeBufferArray(scip, &transweightsint);
    10827 SCIPfreeBufferArray(scip, &transweightsreal);
    10828 SCIPfreeBufferArray(scip, &transprofitsint);
    10829 SCIPfreeBufferArray(scip, &transprofitsreal);
    10830 SCIPfreeBufferArray(scip, &itemsint);
    10831 SCIPfreeBufferArray(scip, &items);
    10832
    10833 return SCIP_OKAY;
    10834}
    10835
    10836#else
    10837
    10838/** get a flow cover \f$(C1, C2)\f$ for a given 0-1 single node flow set
    10839 * \f${(x,y) in {0,1}^n x R^n : sum_{j in N1} y_j - sum_{j in N2} y_j <= b, 0 <= y_j <= u_j x_j}\f$,
    10840 * i.e., get sets \f$ C1 \subset N1 \f$ and \f$ C2 \subset N2 \f$ with
    10841 * \f$ \sum_{j in C1} u_j - sum_{j in C2} u_j = b + lambda \f$ and \f$ lambda > 0 \f$
    10842 */
    10843static
    10845 SCIP* scip, /**< SCIP data structure */
    10846 SNF_RELAXATION* snf, /**< the 0-1 single node flow relaxation */
    10847 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
    10848 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
    10849 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
    10850 SCIP_Real* lambda, /**< pointer to store lambda */
    10851 SCIP_Bool* found /**< pointer to store whether a cover was found */
    10852 )
    10853{
    10854 SCIP_Real* transprofitsreal;
    10855 SCIP_Real* transweightsreal;
    10856 SCIP_Longint* transweightsint;
    10857 int* items;
    10858 int* itemsint;
    10859 int* nonsolitems;
    10860 int* solitems;
    10861 SCIP_Real QUAD(flowcoverweight);
    10862 SCIP_Real n1itemsweight;
    10863 SCIP_Real n2itemsminweight;
    10864 SCIP_Real transcapacityreal;
    10865 int nitems;
    10866#ifndef NDEBUG
    10867 int nn1items = 0;
    10868#endif
    10869 int nnonsolitems;
    10870 int nsolitems;
    10871 int j;
    10872
    10873 assert(scip != NULL);
    10874 assert(snf->transvarcoefs != NULL);
    10875 assert(snf->transbinvarsolvals != NULL);
    10876 assert(snf->transvarvubcoefs != NULL);
    10877 assert(snf->ntransvars > 0);
    10878 assert(nflowcovervars != NULL);
    10879 assert(nnonflowcovervars != NULL);
    10880 assert(flowcoverstatus != NULL);
    10881 assert(lambda != NULL);
    10882 assert(found != NULL);
    10883
    10884 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
    10885
    10886 /* get data structures */
    10888 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
    10889 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
    10890 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
    10891 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
    10892 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
    10893 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
    10894
    10895 BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
    10896 *found = FALSE;
    10897 *nflowcovervars = 0;
    10898 *nnonflowcovervars = 0;
    10899
    10900 QUAD_ASSIGN(flowcoverweight, 0.0);
    10901
    10902 /* fix some variables in advance according to the following fixing strategy
    10903 * put j into N1\C1, if j in N1 and x*_j = 0,
    10904 * put j into C1, if j in N1 and x*_j = 1,
    10905 * put j into C2, if j in N2 and x*_j = 1,
    10906 * put j into N2\C2, if j in N2 and x*_j = 0
    10907 * and get the set of the remaining variables
    10908 */
    10909 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
    10910 nitems = 0;
    10911 n1itemsweight = 0.0;
    10912 n2itemsminweight = SCIP_REAL_MAX;
    10913 for( j = 0; j < snf->ntransvars; j++ )
    10914 {
    10915 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
    10916 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
    10917 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
    10918
    10919 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
    10920 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
    10921 {
    10922 flowcoverstatus[j] = -1;
    10923 (*nnonflowcovervars)++;
    10924 continue;
    10925 }
    10926
    10927 /* x*_j is fractional */
    10929 {
    10930 items[nitems] = j;
    10931 nitems++;
    10932 if( snf->transvarcoefs[j] == 1 )
    10933 {
    10934 n1itemsweight += snf->transvarvubcoefs[j];
    10935#ifndef NDEBUG
    10936 nn1items++;
    10937#endif
    10938 }
    10939 else
    10940 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
    10941 }
    10942 /* j is in N1 and x*_j = 0 */
    10943 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
    10944 {
    10945 flowcoverstatus[j] = -1;
    10946 (*nnonflowcovervars)++;
    10947 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
    10948 }
    10949 /* j is in N1 and x*_j = 1 */
    10950 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
    10951 {
    10952 flowcoverstatus[j] = 1;
    10953 (*nflowcovervars)++;
    10954 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
    10955 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
    10956 }
    10957 /* j is in N2 and x*_j = 1 */
    10958 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
    10959 {
    10960 flowcoverstatus[j] = 1;
    10961 (*nflowcovervars)++;
    10962 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
    10963 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
    10964 }
    10965 /* j is in N2 and x*_j = 0 */
    10966 else
    10967 {
    10968 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
    10969 flowcoverstatus[j] = -1;
    10970 (*nnonflowcovervars)++;
    10971 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
    10972 }
    10973 }
    10974 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
    10975 assert(nn1items >= 0);
    10976
    10977 /* to find a flow cover, transform the following knapsack problem
    10978 *
    10979 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
    10980 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
    10981 * z_j in {0,1} for all j in N1 & N2
    10982 *
    10983 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
    10984 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
    10985 *
    10986 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
    10987 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
    10988 * z°_j in {0,1} for all j in N1
    10989 * z_j in {0,1} for all j in N2,
    10990 * and solve it approximately under consideration of the fixing,
    10991 * or
    10992 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
    10993 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
    10994 * and multiplying the constraint by a suitable scalar C
    10995 *
    10996 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
    10997 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
    10998 * z°_j in {0,1} for all j in N1
    10999 * z_j in {0,1} for all j in N2,
    11000 * where
    11001 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
    11002 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
    11003 * and solve it exactly under consideration of the fixing.
    11004 */
    11005 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
    11006
    11007 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
    11008 for( j = 0; j < nitems; j++ )
    11009 {
    11010 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
    11011
    11012 if( snf->transvarcoefs[items[j]] == 1 )
    11013 {
    11014 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
    11015 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
    11016 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
    11017 }
    11018 else
    11019 {
    11020 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
    11021 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
    11022 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
    11023 }
    11024 }
    11025 /* get capacity of knapsack constraint in KP^SNF_rat */
    11026 transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight; /*lint !e644*/
    11027 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
    11028 snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
    11029
    11030 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
    11031 * is less than or equal to zero
    11032 */
    11033 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
    11034 {
    11035 assert(!(*found));
    11036 goto TERMINATE;
    11037 }
    11038
    11039 /* KP^SNF_rat has been solved by fixing some variables in advance */
    11040 assert(nitems >= 0);
    11041 if( nitems == 0 )
    11042 {
    11043 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
    11044 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
    11045 *lambda = QUAD_TO_DBL(flowcoverweight);
    11046 *found = TRUE;
    11047 goto TERMINATE;
    11048 }
    11049
    11050 /* Solve the KP^SNF_rat approximately */
    11051
    11052 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
    11053 nsolitems = -1;
    11054 nnonsolitems = -1;
    11055
    11056 /* suitable factor C was found*/
    11057 /* solve KP^SNF_rat approximately */
    11058 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
    11059 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
    11060
    11061 assert(nsolitems != -1);
    11062 assert(nnonsolitems != -1);
    11063
    11064 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
    11065 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
    11066 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
    11067 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
    11068 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
    11069
    11070 *found = SCIPisFeasGT(scip, *lambda, 0.0);
    11071
    11072 TERMINATE:
    11073 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
    11074#ifdef SCIP_DEBUG
    11075 if( *found )
    11076 {
    11077 SCIPdebugMsg(scip, "2. approximate solution:\n");
    11078 for( j = 0; j < snf->ntransvars; j++ )
    11079 {
    11080 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
    11081 {
    11082 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
    11083 }
    11084 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
    11085 {
    11086 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
    11087 }
    11088 }
    11089 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
    11090 }
    11091#endif
    11092
    11093 /* free data structures */
    11094 SCIPfreeBufferArray(scip, &nonsolitems);
    11095 SCIPfreeBufferArray(scip, &solitems);
    11096 SCIPfreeBufferArray(scip, &transweightsint);
    11097 SCIPfreeBufferArray(scip, &transweightsreal);
    11098 SCIPfreeBufferArray(scip, &transprofitsreal);
    11099 SCIPfreeBufferArray(scip, &itemsint);
    11100 SCIPfreeBufferArray(scip, &items);
    11101
    11102 return SCIP_OKAY;
    11103}
    11104
    11105#endif
    11106
    11107/** evaluate the super-additive lifting function for the lifted simple generalized flowcover inequalities
    11108 * for a given value \f$ x \in \{ u_j \mid j \in C- \} \f$.
    11109 */
    11110static
    11112 SCIP* scip, /**< SCIP data structure */
    11113 LIFTINGDATA* liftingdata, /**< lifting data to use */
    11114 SCIP_Real x /**< value where to evaluate lifting function */
    11115 )
    11116{
    11117 SCIP_Real QUAD(tmp);
    11118 SCIP_Real xpluslambda;
    11119 int i;
    11120
    11121 assert( liftingdata != NULL );
    11122
    11123 xpluslambda = x + liftingdata->lambda;
    11124
    11125 i = 0;
    11126 while( i < liftingdata->r && SCIPisGT(scip, xpluslambda, liftingdata->M[i+1]) )
    11127 ++i;
    11128
    11129 if( i < liftingdata->t )
    11130 {
    11131 if( SCIPisLE(scip, liftingdata->M[i], x) )
    11132 {
    11133 assert(SCIPisLE(scip, xpluslambda, liftingdata->M[i+1]));
    11134 return i * liftingdata->lambda;
    11135 }
    11136
    11137 assert(i > 0 && SCIPisLE(scip, liftingdata->M[i], xpluslambda) && x <= liftingdata->M[i]);
    11138
    11139 /* return x - liftingdata->M[i] + i * liftingdata->lambda */
    11140 SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
    11141 SCIPquadprecSumQD(tmp, tmp, x);
    11142 SCIPquadprecSumQD(tmp, tmp, -liftingdata->M[i]);
    11143 return QUAD_TO_DBL(tmp);
    11144 }
    11145
    11146 if( i < liftingdata->r )
    11147 {
    11148 assert(!SCIPisInfinity(scip, liftingdata->mp));
    11149
    11150 /* p = liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml; */
    11151 SCIPquadprecSumDD(tmp, liftingdata->m[i], -liftingdata->mp);
    11152 SCIPquadprecSumQD(tmp, tmp, -liftingdata->ml);
    11153 SCIPquadprecSumQD(tmp, tmp, liftingdata->lambda);
    11154
    11155 /* p = MAX(0.0, p); */
    11156 if( QUAD_HI(tmp) < 0.0 )
    11157 {
    11158 QUAD_ASSIGN(tmp, 0.0);
    11159 }
    11160
    11161 SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
    11162 SCIPquadprecSumQD(tmp, tmp, liftingdata->ml);
    11163
    11164 if( SCIPisLT(scip, QUAD_TO_DBL(tmp), xpluslambda) )
    11165 return i * liftingdata->lambda;
    11166
    11167 assert(SCIPisFeasLE(scip, liftingdata->M[i], xpluslambda) &&
    11168 SCIPisFeasLE(scip, xpluslambda, liftingdata->M[i] + liftingdata->ml +
    11169 MAX(0.0, liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml)));
    11170
    11171 SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
    11172 SCIPquadprecSumQD(tmp, tmp, x);
    11173 SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[i]);
    11174 return QUAD_TO_DBL(tmp);
    11175 }
    11176
    11177 assert(i == liftingdata->r && SCIPisLE(scip, liftingdata->M[liftingdata->r], xpluslambda));
    11178
    11179 SCIPquadprecProdDD(tmp, liftingdata->r, liftingdata->lambda);
    11180 SCIPquadprecSumQD(tmp, tmp, x);
    11181 SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[liftingdata->r]);
    11182 return QUAD_TO_DBL(tmp);
    11183}
    11184
    11185/** computes
    11186 * \f[
    11187 * (\alpha_j, \beta_j) =
    11188 * \begin{cases}
    11189 * (0, 0) &\quad\text{if} M_i \leq u_j \leq M_{i+1} - \lambda \\
    11190 * (1, M_i - i \lambda) &\quad\text{if} M_i − \lambda < u_j < M_i \\
    11191 * \end{cases}
    11192 * \f]
    11193 */
    11194static
    11196 SCIP* scip, /**< SCIP data structure */
    11197 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
    11198 SCIP_Real vubcoef, /**< vub coefficient to get alpha and beta for */
    11199 int* alpha, /**< get alpha coefficient for lifting */
    11200 SCIP_Real* beta /**< get beta coefficient for lifting */
    11201 )
    11202{
    11203 SCIP_Real vubcoefpluslambda;
    11204 int i;
    11205
    11206 vubcoefpluslambda = vubcoef + liftingdata->lambda;
    11207
    11208 i = 0;
    11209 while( i < liftingdata->r && SCIPisGT(scip, vubcoefpluslambda, liftingdata->M[i+1]) )
    11210 ++i;
    11211
    11212 if( SCIPisLT(scip, vubcoef, liftingdata->M[i]) )
    11213 {
    11214 SCIP_Real QUAD(tmp);
    11215 assert(liftingdata->M[i] < vubcoefpluslambda);
    11216 *alpha = 1;
    11217 SCIPquadprecProdDD(tmp, -i, liftingdata->lambda);
    11218 SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
    11219 *beta = QUAD_TO_DBL(tmp);
    11220 }
    11221 else
    11222 {
    11223 assert(SCIPisSumLE(scip, liftingdata->M[i], vubcoef));
    11224 assert(i == liftingdata->r || SCIPisLE(scip, vubcoefpluslambda, liftingdata->M[i+1]));
    11225 *alpha = 0;
    11226 *beta = 0.0;
    11227 }
    11228}
    11229
    11230/** compute relevant data for performing the sequence independent lifting */
    11231static
    11233 SCIP* scip, /**< SCIP data structure */
    11234 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
    11235 int* transvarflowcoverstatus, /**< pointer to store whether non-binary var is in L2 (2) or not (-1 or 1) */
    11236 SCIP_Real lambda, /**< lambda */
    11237 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
    11238 SCIP_Bool* valid /**< is the lifting data valid */
    11239 )
    11240{
    11241 int i;
    11242 SCIP_Real QUAD(tmp);
    11243 SCIP_Real QUAD(sumN2mC2LE);
    11244 SCIP_Real QUAD(sumN2mC2GT);
    11245 SCIP_Real QUAD(sumC1LE);
    11246 SCIP_Real QUAD(sumC2);
    11247
    11248#ifndef NDEBUG
    11249 /* for debugging */
    11250 liftingdata->m = NULL;
    11251 liftingdata->M = NULL;
    11252 liftingdata->lambda = SCIP_INVALID;
    11253 liftingdata->t = 0;
    11254 liftingdata->mp = SCIP_INVALID;
    11255#endif
    11256
    11257 SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->m, snf->ntransvars) );
    11258
    11259 liftingdata->r = 0;
    11260 QUAD_ASSIGN(sumN2mC2LE, 0.0);
    11261 QUAD_ASSIGN(sumC1LE, 0.0);
    11262 QUAD_ASSIGN(sumN2mC2GT, 0.0);
    11263 QUAD_ASSIGN(sumC2, 0.0);
    11264
    11265 liftingdata->mp = SCIPinfinity(scip);
    11266
    11267 *valid = FALSE;
    11268
    11269 for( i = 0; i < snf->ntransvars; ++i )
    11270 {
    11271 int s = (snf->transvarcoefs[i] + 1) + (transvarflowcoverstatus[i] + 1)/2;
    11272
    11273 switch(s)
    11274 {
    11275 case 0: /* var is in N2 \ C2 */
    11276 assert(snf->transvarvubcoefs[i] >= 0.0);
    11277 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == -1);
    11278
    11279 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
    11280 {
    11281 SCIPquadprecSumQD(sumN2mC2GT, sumN2mC2GT, snf->transvarvubcoefs[i]);
    11282 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
    11283 }
    11284 else
    11285 {
    11286 SCIPquadprecSumQD(sumN2mC2LE, sumN2mC2LE, snf->transvarvubcoefs[i]);
    11287 }
    11288 break;
    11289 case 1: /* var is in C2 */
    11290 assert(snf->transvarvubcoefs[i] > 0.0);
    11291 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == 1);
    11292
    11293 SCIPquadprecSumQD(sumC2, sumC2, snf->transvarvubcoefs[i]);
    11294 break;
    11295 case 3: /* var is in C1 */
    11296 assert(snf->transvarcoefs[i] == 1 && transvarflowcoverstatus[i] == 1);
    11297 assert(snf->transvarvubcoefs[i] > 0.0);
    11298
    11299 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
    11300 {
    11301 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
    11302 liftingdata->mp = MIN(liftingdata->mp, snf->transvarvubcoefs[i]);
    11303 }
    11304 else
    11305 {
    11306 SCIPquadprecSumQD(sumC1LE, sumC1LE, snf->transvarvubcoefs[i]);
    11307 }
    11308 break;
    11309 default:
    11310 assert(s == 2);
    11311 continue;
    11312 }
    11313 }
    11314
    11315 if( SCIPisInfinity(scip, liftingdata->mp) )
    11316 {
    11317 SCIPfreeBufferArray(scip, &liftingdata->m);
    11318 return SCIP_OKAY;
    11319 }
    11320
    11321 SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->M, liftingdata->r + 1) );
    11322
    11323 *valid = TRUE;
    11324
    11325 SCIPquadprecSumQQ(tmp, sumC1LE, sumN2mC2LE);
    11326 liftingdata->ml = MIN(lambda, QUAD_TO_DBL(tmp));
    11327 SCIPquadprecSumQD(tmp, sumC2, snf->transrhs);
    11328 liftingdata->d1 = QUAD_TO_DBL(tmp);
    11329 SCIPquadprecSumQQ(tmp, tmp, sumN2mC2GT);
    11330 SCIPquadprecSumQQ(tmp, tmp, sumN2mC2LE);
    11331 liftingdata->d2 = QUAD_TO_DBL(tmp);
    11332
    11333 SCIPsortDownReal(liftingdata->m, liftingdata->r);
    11334
    11335 /* compute M[i] = sum_{i \in [1,r]} m[i] where m[*] is sorted decreasingly and M[0] = 0 */
    11336 QUAD_ASSIGN(tmp, 0.0);
    11337 for( i = 0; i < liftingdata->r; ++i)
    11338 {
    11339 liftingdata->M[i] = QUAD_TO_DBL(tmp);
    11340 SCIPquadprecSumQD(tmp, tmp, liftingdata->m[i]);
    11341 }
    11342
    11343 liftingdata->M[liftingdata->r] = QUAD_TO_DBL(tmp);
    11344
    11345 SCIP_UNUSED( SCIPsortedvecFindDownReal(liftingdata->m, liftingdata->mp, liftingdata->r, &liftingdata->t) );
    11346 assert(liftingdata->m[liftingdata->t] == liftingdata->mp || SCIPisInfinity(scip, liftingdata->mp)); /*lint !e777*/
    11347
    11348 /* compute t largest index sucht that m_t = mp
    11349 * note that liftingdata->m[t-1] == mp due to zero based indexing of liftingdata->m
    11350 */
    11351 ++liftingdata->t;
    11352 while( liftingdata->t < liftingdata->r && liftingdata->m[liftingdata->t] == liftingdata->mp ) /*lint !e777*/
    11353 ++liftingdata->t;
    11354
    11355 liftingdata->lambda = lambda;
    11356
    11357 return SCIP_OKAY;
    11358}
    11359
    11360/** destroy data used for the sequence independent lifting */
    11361static
    11363 SCIP* scip, /**< SCIP data structure */
    11364 LIFTINGDATA* liftingdata /**< pointer to lifting function struct */
    11365 )
    11366{
    11367 SCIPfreeBufferArray(scip, &liftingdata->M);
    11368 SCIPfreeBufferArray(scip, &liftingdata->m);
    11369}
    11370
    11371/** store the simple lifted flowcover cut defined by the given data in the given arrays
    11372 * the array for storing the cut coefficients must be all zeros
    11373 */
    11374static
    11376 SCIP* scip, /**< SCIP data structure */
    11377 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
    11378 SCIP_AGGRROW* aggrrow, /**< aggrrow used to construct SNF relaxation */
    11379 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
    11380 SCIP_Real lambda, /**< lambda */
    11381 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    11382 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
    11383 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    11384 int* nnz, /**< number of non-zeros in cut */
    11385 SCIP_Bool* success /**< was the cut successfully generated */
    11386 )
    11387{
    11388 SCIP_Real QUAD(rhs);
    11389 LIFTINGDATA liftingdata;
    11390 int i;
    11391
    11392 SCIP_CALL( computeLiftingData(scip, snf, flowcoverstatus, lambda, &liftingdata, success) );
    11393 if( ! *success )
    11394 return SCIP_OKAY;
    11395 assert( liftingdata.m != NULL );
    11396 assert( liftingdata.M != NULL );
    11397 assert( liftingdata.lambda != SCIP_INVALID ); /*lint !e777*/
    11398 assert( liftingdata.r >= 0 );
    11399 assert( liftingdata.t >= 0 );
    11400 assert( liftingdata.mp != SCIP_INVALID ); /*lint !e777*/
    11401
    11402 QUAD_ASSIGN(rhs, liftingdata.d1);
    11403
    11404 *nnz = 0;
    11405
    11406 for( i = 0; i < snf->ntransvars; ++i )
    11407 {
    11408 int s = (snf->transvarcoefs[i] + 1) + (flowcoverstatus[i] + 1)/2;
    11409
    11410 switch(s)
    11411 {
    11412 case 0: /* var is in N2 \ C2 */
    11413 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
    11414 {
    11415 /* var is in L- */
    11416 if( snf->origbinvars[i] != -1 )
    11417 {
    11418 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
    11419 cutinds[*nnz] = snf->origbinvars[i];
    11420 cutcoefs[snf->origbinvars[i]] = -lambda;
    11421 ++(*nnz);
    11422 }
    11423 else
    11424 {
    11425 SCIPquadprecSumQD(rhs, rhs, lambda);
    11426 }
    11427 }
    11428 else
    11429 {
    11430 /* var is in L-- */
    11431 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
    11432 {
    11433 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
    11434 cutinds[*nnz] = snf->origcontvars[i];
    11435 cutcoefs[snf->origcontvars[i]] = -snf->aggrcoefscont[i];
    11436 ++(*nnz);
    11437 }
    11438
    11439 if( snf->origbinvars[i] != -1 && snf->aggrcoefsbin[i] != 0.0 )
    11440 {
    11441 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
    11442 cutinds[*nnz] = snf->origbinvars[i];
    11443 cutcoefs[snf->origbinvars[i]] = -snf->aggrcoefsbin[i];
    11444 ++(*nnz);
    11445 }
    11446
    11447 SCIPquadprecSumQD(rhs, rhs, snf->aggrconstants[i]);
    11448 }
    11449 break;
    11450 case 1: /* var is in C2 */
    11451 {
    11452 assert(snf->transvarvubcoefs[i] > 0.0);
    11453 assert(snf->transvarcoefs[i] == -1 && flowcoverstatus[i] == 1);
    11454
    11455 if( snf->origbinvars[i] != -1 )
    11456 {
    11457 SCIP_Real liftedbincoef = evaluateLiftingFunction(scip, &liftingdata, snf->transvarvubcoefs[i]);
    11458 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
    11459 if( liftedbincoef != 0.0 )
    11460 {
    11461 cutinds[*nnz] = snf->origbinvars[i];
    11462 cutcoefs[snf->origbinvars[i]] = -liftedbincoef;
    11463 ++(*nnz);
    11464 SCIPquadprecSumQD(rhs, rhs, -liftedbincoef);
    11465 }
    11466 }
    11467 break;
    11468 }
    11469 case 2: /* var is in N1 \ C1 */
    11470 {
    11471 int alpha;
    11472 SCIP_Real beta;
    11473
    11474 assert(snf->transvarcoefs[i] == 1 && flowcoverstatus[i] == -1);
    11475
    11476 getAlphaAndBeta(scip, &liftingdata, snf->transvarvubcoefs[i], &alpha, &beta);
    11477 assert(alpha == 0 || alpha == 1);
    11478
    11479 if( alpha == 1 )
    11480 {
    11481 SCIP_Real QUAD(binvarcoef);
    11482 assert(beta > 0.0);
    11483
    11484 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
    11485 {
    11486 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
    11487 cutinds[*nnz] = snf->origcontvars[i];
    11488 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
    11489 ++(*nnz);
    11490 }
    11491
    11492 SCIPquadprecSumDD(binvarcoef, snf->aggrcoefsbin[i], -beta);
    11493 if( snf->origbinvars[i] != -1 )
    11494 {
    11495 SCIP_Real tmp;
    11496
    11497 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
    11498
    11499 tmp = QUAD_TO_DBL(binvarcoef);
    11500 if( tmp != 0.0 )
    11501 {
    11502 cutinds[*nnz] = snf->origbinvars[i];
    11503 cutcoefs[snf->origbinvars[i]] = tmp;
    11504 ++(*nnz);
    11505 }
    11506 }
    11507 else
    11508 {
    11509 SCIPquadprecSumQQ(rhs, rhs, -binvarcoef);
    11510 }
    11511
    11512 SCIPquadprecSumQD(rhs, rhs, -snf->aggrconstants[i]);
    11513 }
    11514 break;
    11515 }
    11516 case 3: /* var is in C1 */
    11517 {
    11518 SCIP_Real bincoef = snf->aggrcoefsbin[i];
    11519 SCIP_Real constant = snf->aggrconstants[i];
    11520
    11521 if( snf->origbinvars[i] != -1 && SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
    11522 {
    11523 /* var is in C++ */
    11524 SCIP_Real QUAD(tmp);
    11525 SCIP_Real QUAD(tmp2);
    11526
    11527 SCIPquadprecSumDD(tmp, snf->transvarvubcoefs[i], -lambda);
    11528
    11529 SCIPquadprecSumQD(tmp2, tmp, constant);
    11530 constant = QUAD_TO_DBL(tmp2);
    11531
    11532 SCIPquadprecSumQD(tmp2, tmp, -bincoef);
    11533 bincoef = -QUAD_TO_DBL(tmp2);
    11534 }
    11535
    11536 if( snf->origbinvars[i] != -1 && bincoef != 0.0 )
    11537 {
    11538 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
    11539 cutinds[*nnz] = snf->origbinvars[i];
    11540 cutcoefs[snf->origbinvars[i]] = bincoef;
    11541 ++(*nnz);
    11542 }
    11543
    11544 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
    11545 {
    11546 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
    11547 cutinds[*nnz] = snf->origcontvars[i];
    11548 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
    11549 ++(*nnz);
    11550 }
    11551
    11552 SCIPquadprecSumQD(rhs, rhs, -constant);
    11553 break;
    11554 }
    11555 default:
    11556 SCIPABORT();
    11557 }
    11558 }
    11559
    11560 destroyLiftingData(scip, &liftingdata);
    11561
    11562 {
    11563 SCIP_ROW** rows = SCIPgetLPRows(scip);
    11564 for( i = 0; i < aggrrow->nrows; ++i )
    11565 {
    11566 SCIP_ROW* row;
    11567 SCIP_Real rowlhs;
    11568 SCIP_Real rowrhs;
    11569 SCIP_Real slackub;
    11570 SCIP_Real slackcoef;
    11571
    11572 slackcoef = aggrrow->rowweights[i] * aggrrow->slacksign[i];
    11573 assert(slackcoef != 0.0);
    11574
    11575 /* positive slack was implicitly handled in flow cover separation */
    11576 if( slackcoef > 0.0 )
    11577 continue;
    11578
    11579 row = rows[aggrrow->rowsinds[i]];
    11580
    11581 /* add the slack's definition multiplied with its coefficient to the cut */
    11582 SCIP_CALL( varVecAddScaledRowCoefs(cutinds, cutcoefs, nnz, row, -aggrrow->rowweights[i]) );
    11583
    11584 /* retrieve sides of row */
    11585 rowlhs = row->lhs - row->constant;
    11586 rowrhs = row->rhs - row->constant;
    11587
    11588 if( row->integral )
    11589 {
    11590 rowrhs = SCIPfloor(scip, rowrhs);
    11591 rowlhs = SCIPceil(scip, rowlhs);
    11592 }
    11593
    11594 slackub = rowrhs - rowlhs;
    11595
    11596 /* move slack's constant to the right hand side, and add lambda to the right hand side if the
    11597 * upper bound of the slack is larger than lambda, since then an artifical binary variable
    11598 * for the slack would get coefficient -lambda
    11599 */
    11600 if( aggrrow->slacksign[i] == +1 )
    11601 {
    11602 SCIP_Real rhsslack;
    11603 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
    11604 assert(!SCIPisInfinity(scip, row->rhs));
    11605
    11606 rhsslack = rowrhs - SCIPgetRowMinActivity(scip, row);
    11607 slackub = -aggrrow->rowweights[i] * MIN(rhsslack, slackub);
    11608
    11609 if( SCIPisGE(scip, slackub, lambda) )
    11610 SCIPquadprecSumQD(rhs, rhs, lambda);
    11611
    11612 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowrhs);
    11613 }
    11614 else
    11615 {
    11616 SCIP_Real lhsslack;
    11617 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
    11618 assert(!SCIPisInfinity(scip, -row->lhs));
    11619
    11620 lhsslack = SCIPgetRowMaxActivity(scip, row) - rowlhs;
    11621 slackub = aggrrow->rowweights[i] * MIN(lhsslack, slackub);
    11622
    11623 if( SCIPisGE(scip, slackub, lambda) )
    11624 SCIPquadprecSumQD(rhs, rhs, lambda);
    11625
    11626 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowlhs);
    11627 }
    11628 }
    11629 }
    11630
    11631 *cutrhs = QUAD_TO_DBL(rhs);
    11632
    11633 /* relax rhs to zero, if it's very close to 0 */
    11634 if( *cutrhs < 0.0 && *cutrhs >= -SCIPepsilon(scip) )
    11635 *cutrhs = 0.0;
    11636
    11637 return SCIP_OKAY;
    11638}
    11639
    11640/** calculates a lifted simple generalized flow cover cut out of the weighted sum of LP rows given by an aggregation row; the
    11641 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
    11642 * participate in the cut.
    11643 * For further details we refer to:
    11644 *
    11645 * Gu, Z., Nemhauser, G. L., & Savelsbergh, M. W. (1999). Lifted flow cover inequalities for mixed 0-1 integer programs.
    11646 * Mathematical Programming, 85(3), 439-467.
    11647 *
    11648 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    11649 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    11650 *
    11651 * @pre This method can be called if @p scip is in one of the following stages:
    11652 * - \ref SCIP_STAGE_SOLVING
    11653 *
    11654 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    11655 */
    11657 SCIP* scip, /**< SCIP data structure */
    11658 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    11659 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
    11660 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    11661 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    11662 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
    11663 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
    11664 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
    11665 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
    11666 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
    11667 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
    11668 int* cutrank, /**< pointer to return rank of generated cut */
    11669 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
    11670 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
    11671 )
    11672{
    11673 SNF_RELAXATION snf;
    11674 SCIP_Bool localbdsused;
    11675 SCIP_Real lambda;
    11676 SCIP_Real* tmpcoefs;
    11677 SCIP_Real tmprhs = 0.0;
    11678 SCIP_Bool tmpislocal;
    11679 int* tmpinds;
    11680 int tmpnnz;
    11681 int* transvarflowcoverstatus;
    11682 int nvars;
    11683 int nflowcovervars;
    11684 int nnonflowcovervars;
    11685 int i;
    11686
    11687 nvars = SCIPgetNVars(scip);
    11688
    11689 *success = FALSE;
    11690
    11691 /* get data structures */
    11692 SCIP_CALL( SCIPallocBufferArray(scip, &transvarflowcoverstatus, nvars) );
    11693 SCIP_CALL( allocSNFRelaxation(scip, &snf, nvars) );
    11694
    11695 SCIPdebug( printCutQuad(scip, sol, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, FALSE, aggrrow->local) );
    11696
    11697 SCIP_CALL( constructSNFRelaxation(scip, sol, boundswitch, allowlocal, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, &snf, success, &localbdsused) );
    11698
    11699 if( ! *success )
    11700 {
    11701 goto TERMINATE;
    11702 }
    11703
    11704 tmpislocal = aggrrow->local || localbdsused;
    11705
    11706 /* initialize lambda because gcc issues a stupid warning */
    11707 lambda = 0.0;
    11708 SCIP_CALL( getFlowCover(scip, &snf, &nflowcovervars, &nnonflowcovervars, transvarflowcoverstatus, &lambda, success) );
    11709
    11710 if( ! *success )
    11711 {
    11712 goto TERMINATE;
    11713 }
    11714
    11715 SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, nvars) );
    11716 SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
    11717
    11718 SCIP_CALL( generateLiftedFlowCoverCut(scip, &snf, aggrrow, transvarflowcoverstatus, lambda, tmpcoefs, &tmprhs, tmpinds, &tmpnnz, success) );
    11719 SCIPdebugMsg(scip, "computed flowcover_%lli_%i:\n", SCIPgetNLPs(scip), SCIPgetNCuts(scip));
    11720
    11721 /* if success is FALSE generateLiftedFlowCoverCut wont have touched the tmpcoefs array so we dont need to clean it then */
    11722 if( *success )
    11723 {
    11724 if( postprocess )
    11725 {
    11726 SCIP_CALL( postprocessCut(scip, tmpislocal, tmpinds, tmpcoefs, &tmpnnz, &tmprhs, success) );
    11727 }
    11728 else
    11729 {
    11730 SCIP_Real QUAD(rhs);
    11731
    11732 QUAD_ASSIGN(rhs, tmprhs);
    11733 *success = ! removeZeros(scip, SCIPsumepsilon(scip), tmpislocal, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz);
    11734 tmprhs = QUAD_TO_DBL(rhs);
    11735 }
    11736
    11737 if( *success )
    11738 {
    11739 /* only return cut if it improves upon the input efficacy threshold */
    11740 if( cutefficacy != NULL )
    11741 {
    11742 /* calculate efficacy from dense storage */
    11743 SCIP_Real efficacy = calcEfficacyDenseStorage(scip, sol, tmpcoefs, tmprhs, tmpinds, tmpnnz);
    11744
    11745 if( SCIPisLT(scip, *cutefficacy, efficacy) )
    11746 *cutefficacy = efficacy;
    11747 else
    11748 *success = FALSE;
    11749 }
    11750
    11751 /* copy cut data to output if successful */
    11752 if( *success )
    11753 {
    11754 if( cutrank != NULL )
    11755 *cutrank = aggrrow->rank + 1;
    11756 if( cutislocal != NULL )
    11757 *cutislocal = tmpislocal;
    11758
    11759 for( i = 0; i < tmpnnz; ++i )
    11760 {
    11761 int j = tmpinds[i];
    11762
    11763 cutinds[i] = j;
    11764 cutcoefs[i] = tmpcoefs[j];
    11765 }
    11766
    11767 *cutnnz = tmpnnz;
    11768 *cutrhs = tmprhs;
    11769 }
    11770 }
    11771
    11772 /* clean buffer array */
    11773 for( i = 0; i < tmpnnz; ++i )
    11774 {
    11775 int j = tmpinds[i];
    11776 assert(tmpcoefs[j] != 0.0);
    11777 tmpcoefs[j] = 0.0;
    11778 }
    11779 }
    11780
    11781 SCIPfreeBufferArray(scip, &tmpinds);
    11782 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
    11783
    11784 TERMINATE:
    11786 SCIPfreeBufferArray(scip, &transvarflowcoverstatus);
    11787
    11788 return SCIP_OKAY;
    11789}
    11790
    11791/* =========================================== knapsack cover =========================================== */
    11792
    11793/** Relax the row to a possibly fractional knapsack row containing no integer or continuous variables
    11794 * and only having positive coefficients for binary variables. General integer and continuous variables
    11795 * are complemented with variable or simple bounds such that their coefficient becomes positive and then
    11796 * it is relaxed to zero.
    11797 * All remaining binary variables are complemented with simple upper or lower bounds such that their
    11798 * coefficient becomes positive.
    11799 */
    11800static
    11802 SCIP* scip, /**< SCIP data structure */
    11803 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    11804 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    11805 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    11806 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
    11807 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    11808 int* nnz, /**< number of non-zeros in cut */
    11809 int* varsign, /**< stores the sign of the transformed variable in summation */
    11810 int* boundtype, /**< stores the bound used for transformed variable:
    11811 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    11812 SCIP_Bool* localbdsused, /**< pointer to store whether local bounds were used in transformation */
    11813 SCIP_Bool* success /**< stores whether the row could successfully be transformed into a knapsack constraint.
    11814 * Returns FALSE in case a continuous or general integer variable is unbounded in the
    11815 * required direction. */
    11816 )
    11817{
    11818 SCIP_Real* bestbds;
    11819 int i;
    11820 int aggrrowbinstart;
    11821 int firstnonbinvar;
    11822 SCIP_VAR** vars;
    11823
    11824 assert(varsign != NULL);
    11825 assert(boundtype != NULL);
    11826 assert(success != NULL);
    11827 assert(localbdsused != NULL);
    11828
    11829 *success = FALSE;
    11830
    11831 /* allocate temporary memory to store best bounds and bound types */
    11832 SCIP_CALL( SCIPallocBufferArray(scip, &bestbds, 2*(*nnz)) );
    11833
    11834 /* start with continuous variables, because using variable bounds can affect the untransformed binary
    11835 * variables, and these changes have to be incorporated in the transformation of the binary variables
    11836 * (binary variables have the smallest problem indices!)
    11837 */
    11838 SCIPsortDownInt(cutinds, *nnz);
    11839
    11840 vars = SCIPgetVars(scip);
    11841 firstnonbinvar = SCIPgetNBinVars(scip);
    11842
    11843 /* determine best bounds for the continuous and general integer variables such that they will have
    11844 * a positive coefficient in the transformation */
    11845 for( i = 0; i < *nnz && cutinds[i] >= firstnonbinvar; ++i )
    11846 {
    11847 SCIP_Real QUAD(coef);
    11848 int v = cutinds[i];
    11849
    11850 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
    11851
    11852 if( QUAD_TO_DBL(coef) > 0.0 )
    11853 {
    11854 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable
    11855 * so that it will have a positive coefficient */
    11856 SCIP_CALL( findBestLb(scip, vars[v], sol, SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS ? 1 : 0, allowlocal, bestbds + i, boundtype + i) );
    11857
    11858 /* cannot transform into knapsack */
    11859 if( SCIPisInfinity(scip, -bestbds[i]) )
    11860 goto TERMINATE;
    11861
    11862 varsign[i] = +1;
    11863 }
    11864 else if( QUAD_TO_DBL(coef) < 0.0 )
    11865 {
    11866 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable
    11867 * so that it will have a positive coefficient */
    11868 SCIP_CALL( findBestUb(scip, vars[v], sol, SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS ? 1 : 0, allowlocal, bestbds + i, boundtype + i) );
    11869
    11870 /* cannot transform into knapsack */
    11871 if( SCIPisInfinity(scip, bestbds[i]) )
    11872 goto TERMINATE;
    11873
    11874 varsign[i] = -1;
    11875 }
    11876 }
    11877
    11878 /* remember start of integer variables in the aggrrow */
    11879 aggrrowbinstart = i;
    11880
    11881 /* perform bound substitution for continuous variables */
    11882 for( i = 0; i < aggrrowbinstart; ++i )
    11883 {
    11884 SCIP_Real QUAD(coef);
    11885 int v = cutinds[i];
    11886
    11887 performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestbds[i], v, localbdsused);
    11888
    11889 /* relax non-binary coefficient to zero after bound substitution */
    11890 QUAD_ASSIGN(coef, 0.0);
    11891 QUAD_ARRAY_STORE(cutcoefs, v, coef);
    11892 }
    11893
    11894 assert(i == aggrrowbinstart);
    11895
    11896 /* remove non-binary variables because their coefficients have been set to zero after bound substitution */
    11897 if( aggrrowbinstart != 0 )
    11898 {
    11899 *nnz -= aggrrowbinstart;
    11900 BMSmoveMemoryArray(cutinds, cutinds + aggrrowbinstart, *nnz);
    11901 }
    11902 i = 0;
    11903
    11904 /* after doing bound substitution of non-binary vars, some coefficients of binary vars might have changed, so here we
    11905 * remove the ones that became 0 if any; also, we need that all remaining binary vars have positive coefficients,
    11906 * thus we perform bound substitution with simple bounds (i.e. complementing) to achieve this.
    11907 */
    11908 while( i < *nnz )
    11909 {
    11910 SCIP_Real QUAD(coef);
    11911 SCIP_Real bestlb;
    11912 SCIP_Real bestub;
    11913 SCIP_Bool setzero;
    11914 int v = cutinds[i];
    11915
    11916 assert(SCIPvarGetType(vars[v]) == SCIP_VARTYPE_BINARY && !SCIPvarIsImpliedIntegral(vars[v]));
    11917
    11918 assert(v < firstnonbinvar);
    11919 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
    11920
    11921 /* due to variable bound usage for bound substitution of continuous variables cancellation may have occurred */
    11922 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
    11923 {
    11924 /* do not increase i, since last element is copied to the i-th position */
    11925 setzero = TRUE;
    11926 }
    11927 else
    11928 {
    11929 /* perform bound substitution */
    11930 if( QUAD_TO_DBL(coef) < 0.0 )
    11931 {
    11932 SCIP_CALL( findBestUb(scip, vars[v], sol, 0, allowlocal, &bestub, boundtype + i) );
    11933
    11934 if( SCIPisZero(scip, bestub) )
    11935 {
    11936 /* binary variable is fixed to zero */
    11937 setzero = TRUE;
    11938 *localbdsused = *localbdsused || (boundtype[i] == -2);
    11939 }
    11940 else
    11941 {
    11942 varsign[i] = -1;
    11943
    11944 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestub, v, localbdsused);
    11945 QUAD_ARRAY_STORE(cutcoefs, v, -coef);
    11946 setzero = FALSE;
    11947 }
    11948 }
    11949 else
    11950 {
    11951 SCIP_CALL( findBestLb(scip, vars[v], sol, 0, allowlocal, &bestlb, boundtype + i) );
    11952
    11953 if( !SCIPisZero(scip, bestlb) )
    11954 {
    11955 /* binary variable is fixed to one */
    11956 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestlb, v, localbdsused);
    11957 setzero = TRUE;
    11958 }
    11959 else
    11960 {
    11961 varsign[i] = +1;
    11962 setzero = FALSE;
    11963 }
    11964 }
    11965
    11966 assert(boundtype[i] == -1 || boundtype[i] == -2);
    11967 }
    11968
    11969 /* increase i or remove zero coefficient (i.e. var with 0 coef) by shifting last nonzero to current position */
    11970 if( setzero )
    11971 {
    11972 QUAD_ASSIGN(coef, 0.0);
    11973 QUAD_ARRAY_STORE(cutcoefs, v, coef);
    11974 --(*nnz);
    11975 cutinds[i] = cutinds[*nnz];
    11976 }
    11977 else
    11978 ++i;
    11979 }
    11980
    11981 /* relax rhs to zero if it is close to but slightly below zero */
    11982 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    11983 QUAD_ASSIGN(*cutrhs, 0.0);
    11984
    11985 *success = TRUE;
    11986 TERMINATE:
    11987 /*free temporary memory */
    11988 SCIPfreeBufferArray(scip, &bestbds);
    11989
    11990 return SCIP_OKAY;
    11991}
    11992
    11993/** determines the initial cover for the given (fractional) knapsack row */
    11994static
    11996 SCIP* scip, /**< SCIP datastructure */
    11997 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    11998 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    11999 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    12000 SCIP_Real cutrhs, /**< pointer to the right hand side of the cut */
    12001 int cutnnz, /**< pointer to the number of non-zeros in the cut */
    12002 int* varsign, /**< sign of coefficients for each nonzero in the row be transformation */
    12003 int* coverstatus, /**< array to return the coverstatus for each variable in the knapsack row */
    12004 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
    12005 SCIP_Real* covervals, /**< coefficient value of each variable in the cover */
    12006 int* coversize, /**< pointer to return number of variables in the cover;
    12007 * matches the length of the associated arrays */
    12008 QUAD(SCIP_Real* coverweight) /**< pointer to return the weight of the cover;
    12009 * the weight is the sum of the coefficient values of variables in the cover */
    12010 )
    12011{
    12012 SCIP_VAR** vars;
    12013 int k;
    12014 int j;
    12015 QUAD_ASSIGN(*coverweight, 0);
    12016 *coversize = 0;
    12017 j = cutnnz-1;
    12018 vars = SCIPgetVars(scip);
    12019
    12020 for( k = 0; k < cutnnz; ++k )
    12021 {
    12022 SCIP_Real solval;
    12023 int v = cutinds[k];
    12024 SCIP_Real QUAD(coef);
    12025 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
    12026
    12027 solval = SCIPgetSolVal(scip, sol, vars[v]);
    12028 if( varsign[k] == -1 )
    12029 solval = 1 - solval;
    12030
    12031 if( SCIPisFeasEQ(scip, solval, 1.0) )
    12032 {
    12033 /* every variable with solution value 1 is forced into the cover */
    12034 coverpos[*coversize] = k;
    12035 covervals[*coversize] = QUAD_TO_DBL(coef);
    12036 coverstatus[k] = 1;
    12037 *coversize += 1;
    12038 SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
    12039 }
    12040 else
    12041 {
    12042 coverpos[j] = k;
    12043 covervals[j] = solval * QUAD_TO_DBL(coef);
    12044 coverstatus[k] = 0;
    12045 j -= 1;
    12046 }
    12047 }
    12048
    12049 /* Use these two arrays to sort the variables by decreasing contribution
    12050 * and pick them greedily in the while loop below until they are a cover.
    12051 * Since the cover does not need to be minimal we do not need to remove any of the
    12052 * variables with a high activity contribution even if they are not necessary after
    12053 * picking the last variable.
    12054 */
    12055 SCIPsortDownRealInt(covervals + (*coversize), coverpos + (*coversize), cutnnz - (*coversize));
    12056
    12057 /* overwrite covervals with the coefficients of the variables in the cover
    12058 * as we need to sort decreasingly by those again for the lifting
    12059 */
    12060 while( *coversize < cutnnz &&
    12061 SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) )
    12062 {
    12063 int v;
    12064 SCIP_Real QUAD(coef);
    12065 k = coverpos[*coversize];
    12066 v = cutinds[k];
    12067 coverstatus[k] = 1;
    12068 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
    12069 covervals[*coversize] = QUAD_TO_DBL(coef);
    12070 SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
    12071 *coversize += 1;
    12072 }
    12073
    12074 /* there is no cover */
    12075 if( SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) || *coversize == 0 )
    12076 return FALSE;
    12077
    12078 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(*coverweight), cutrhs);
    12079 assert(*coversize > 0);
    12080
    12081 return TRUE;
    12082}
    12083
    12084/** prepares the data needed to evaluate the lifting function */
    12085static
    12087 SCIP* scip, /**< SCIP datastructure */
    12088 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    12089 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    12090 QUAD(SCIP_Real cutrhs), /**< pointer to the right hand side of the cut */
    12091 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
    12092 int coversize, /**< number of variables in the cover */
    12093 QUAD(SCIP_Real coverweight), /**< weight of cover */
    12094 SCIP_Real* covervals, /**< coefficient value of each variable in the cover;
    12095 * on output stores the running sum of S^-(*) values */
    12096 int* coverstatus, /**< coverstatus for each variable in the cover. After calling this function
    12097 * variables in C^- will have the value -1, variables in C^+ the value 1,
    12098 * and all variables outside the cover keep the value 0. */
    12099 QUAD(SCIP_Real* abar), /**< pointer to store the reciprocal value of \bar{a} */
    12100 int* cplussize /**< pointer to store the size of C^+ */
    12101 )
    12102{
    12103 int k;
    12104 SCIP_Real QUAD(tmp);
    12105 SCIP_Real QUAD(sigma);
    12106
    12107 /* Now compute \bar{a}, the unique rational number such that for the cover C it holds that
    12108 * b = \sum_{a_i \in C} \min(\bar{a}, a_i).
    12109 * For that we need to sort by decreasing coefficients of the variables in the cover.
    12110 * After the sorting the covervals array is free to be reused.
    12111 */
    12112 SCIPsortDownRealInt(covervals, coverpos, coversize);
    12113
    12114 /* Now follows Algorithm 1 in the paper to compute \bar{a} */
    12115
    12116 /* set \bar{a} = l_1 */
    12117 QUAD_ARRAY_LOAD(*abar, cutcoefs, cutinds[coverpos[0]]);
    12118 SCIPquadprecSumQQ(sigma, coverweight, -cutrhs);
    12119
    12120 for( k = 1; k < coversize; ++k )
    12121 {
    12122 SCIP_Real QUAD(lkplus1);
    12123 SCIP_Real QUAD(kdelta);
    12124
    12125 /* load next coefficient l_{k+1} in sorted order of cover */
    12126 QUAD_ARRAY_LOAD(lkplus1, cutcoefs, cutinds[coverpos[k]]);
    12127
    12128 /* Let \delta = \bar{a} - l_{k+1} and compute k * \delta */
    12129 SCIPquadprecSumQQ(kdelta, *abar, -lkplus1);
    12130 SCIPquadprecProdQD(kdelta, kdelta, k);
    12131
    12132 /* Set tmp = k * \delta - \sigma to check condition k * \delta < \sigma by tmp < 0 */
    12133 SCIPquadprecSumQQ(tmp, kdelta, -sigma);
    12134 if( QUAD_TO_DBL(tmp) < 0.0 )
    12135 {
    12136 /* Set \bar{a} = l_{k+1} and \sigma = \sigma - k*\delta */
    12137 QUAD_ASSIGN_Q(*abar, lkplus1);
    12138 SCIPquadprecSumQQ(sigma, sigma, -kdelta);
    12139 }
    12140 else
    12141 {
    12142 /* Set \bar{a} = \bar{a} - \sigma / k and \sigma = 0; break; */
    12143 SCIP_Real minusoneoverk = -1.0 / k;
    12144 SCIPquadprecProdQD(sigma, sigma, minusoneoverk);
    12145 SCIPquadprecSumQQ(*abar, *abar, sigma);
    12146 QUAD_ASSIGN(sigma, 0.0);
    12147 break;
    12148 }
    12149 }
    12150
    12151 if( QUAD_TO_DBL(sigma) > 0.0 )
    12152 {
    12153 SCIP_Real oneoverc = 1.0 / coversize;
    12154 SCIPquadprecProdQD(*abar, cutrhs, oneoverc);
    12155 }
    12156
    12157 /* now we partition C into C^+ and C^-, where C^+ are all the elements of C whose weight is strictly larger than
    12158 * \bar{a} and C^- the rest. If a_i are the weights of the elements in C, let a_i^- = min(a_i, \bar{a}) We also
    12159 * compute S^-(h) = sum of the h largest a_i^- and store S^-(h+1) in in covervals[h], for k = 0, ..., coversize - 1
    12160 * (S^-(0) = 0 so it doesn't need to be stored; we use S to compute the lifted cut, see below)
    12161 * we remember which elements of C^- in coverstatus, so that element in C^+ have coverstatus 1 and
    12162 * elements in C^- have coverstatus -1 (elements not in C have coverstatus 0)
    12163 */
    12164 QUAD_ASSIGN(tmp, 0.0);
    12165 *cplussize = 0;
    12166 for( k = 0; k < coversize; ++k )
    12167 {
    12168 SCIP_Real QUAD(coef);
    12169 SCIP_Real QUAD(coefminusabar);
    12170
    12171 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[coverpos[k]]);
    12172 SCIPquadprecSumQQ(coefminusabar, coef, -*abar);
    12173 if( QUAD_TO_DBL(coefminusabar) > 0.0 )
    12174 {
    12175 /* coefficient is in C^+ because it is greater than \bar{a} and contributes only \bar{a} to the sum */
    12176 SCIPquadprecSumQQ(tmp, tmp, *abar);
    12177
    12178 /* rather be on the safe side in numerical corner cases and relax the coefficient to exactly \bar{a}.
    12179 * In that case the coefficient is not treated as in C^+ but as being <= \bar{a} and therefore in C^-.
    12180 */
    12181 if( QUAD_TO_DBL(coefminusabar) > SCIPfeastol(scip) )
    12182 ++(*cplussize);
    12183 else
    12184 coverstatus[coverpos[k]] = -1;
    12185 }
    12186 else
    12187 {
    12188 /* coefficient is in C^- because it is smaller or equal to \bar{a} */
    12189 coverstatus[coverpos[k]] = -1;
    12190 SCIPquadprecSumQQ(tmp, tmp, coef);
    12191 }
    12192 covervals[k] = QUAD_TO_DBL(tmp);
    12193 SCIPdebugMsg(scip, "S^-(%d) = %g\n", k + 1, covervals[k]);
    12194 }
    12195
    12196 /* set abar to its reciprocal for faster computation of the lifting coefficients */
    12197 SCIPquadprecDivDQ(*abar, 1, *abar);
    12198}
    12199
    12200/** evaluate the lifting function based on the given values */
    12201static
    12203 SCIP* scip, /**< SCIP datastructure */
    12204 QUAD(SCIP_Real x), /**< value to evaluate the lifting function at */
    12205 QUAD(SCIP_Real abar), /**< the reciprocal value of \bar{a} */
    12206 SCIP_Real* covervals, /**< the running sum of S^-(*) values */
    12207 int coversize, /**< the size of the cover */
    12208 int cplussize, /**< the size of C^+ */
    12209 SCIP_Real* scale /**< pointer to update the scale to integrality when a fractional value is returned */
    12210 )
    12211{
    12212 SCIP_Real QUAD(tmp);
    12213 SCIP_Real QUAD(hfrac);
    12214 SCIP_Real cutcoef;
    12215 SCIP_Real hreal;
    12216 int h;
    12217
    12218 /* the lifted value is at least the coeficient (a_k) divided by \bar{a} because the largest value
    12219 * contributed to the running sum stored in C is \bar{a}
    12220 * therefore we start the search for the correct h at floor(a_k / \bar{a})
    12221 */
    12222
    12223 SCIPdebugMsg(scip, "coef is %g, coversize is %d\n", QUAD_TO_DBL(x), coversize );
    12224
    12225 SCIPquadprecProdQQ(hfrac, x, abar);
    12226
    12227 /* if the coefficient is below \bar{a}, i.e. a / \bar{a} < 1 then g(a_k) = 0, otherwise g(a_k) > 0 */
    12228 if( QUAD_TO_DBL(hfrac) < 1 )
    12229 return 0.0;
    12230
    12231 /* we perform h = MIN(h, coversize) in floating-point first because on some instances h was seen to exceed the range
    12232 * of int */
    12233 hreal = SCIPfloor(scip, QUAD_TO_DBL(hfrac));
    12234 if( hreal > (SCIP_Real)coversize )
    12235 h = coversize;
    12236 else
    12237 h = (int)hreal;
    12238
    12239 SCIPquadprecSumQD(hfrac, hfrac, -h);
    12240
    12241 assert(h > 0);
    12242 if( h < cplussize && ABS(QUAD_TO_DBL(hfrac)) <= QUAD_EPSILON )
    12243 {
    12244 /* cutcoef can be increased by 0.5 because it is a multiple of \bar{a}
    12245 * (This is the first non-dominated lifting function presented in the paper)
    12246 */
    12247 cutcoef = 0.5;
    12248 *scale = 2.0;
    12249 }
    12250 else
    12251 cutcoef = 0.0;
    12252
    12253 /* decrease by one to make sure rounding errors or coefficients that are larger than the right hand side by themselves
    12254 * did not push h too far */
    12255 h--;
    12256
    12257 /* now increase coefficient to its lifted value based on its size relative to the S^- values.
    12258 * The coefficient a_i is lifted to the unique integer h such that S^-(h) < a_i <= S^-(h+1).
    12259 * (todo: variables that have a coefficient above the right hand side can get an arbitrarily large coefficient but can
    12260 * also be trivially fixed using the base row. Currently they get the coefficient |C| which is 1 above the right hand
    12261 * side in the cover cut so that they can still be trivially fixed by propagating the cover cut.
    12262 * We do not want to apply fixings here though because the LP should stay flushed during separation.
    12263 * Possibly add a parameter to return additional fixings to the caller of the SCIPcalc*() functions in here
    12264 * and the caller can add them as cuts to the sepastore or we add them to the sepastore here?)
    12265 */
    12266 while( h < coversize )
    12267 {
    12268 SCIPquadprecSumQD(tmp, x, -covervals[h]); /* recall: covervals[h] = S^-(h+1) */
    12269 /* compare with standard epsilon tolerance since computation involves abar, which is computed like an activity */
    12270 if( !SCIPisPositive(scip, QUAD_TO_DBL(tmp)) )
    12271 break;
    12272
    12273 ++h;
    12274 }
    12275
    12276 cutcoef += h;
    12277
    12278 SCIPdebugMsg(scip, "x is %g, coversize is %d, h is %d\n", QUAD_TO_DBL(x), coversize, h );
    12279 /* the lifted coefficient is h increased possibly by 0.5 for the case checked above */
    12280 SCIPdebugMsg(scip, "lifted coef %g < %g <= %g to %g\n", h == 0 ? 0 : covervals[h-1], QUAD_TO_DBL(x),
    12281 covervals[h], cutcoef);
    12282
    12283 return cutcoef;
    12284}
    12285
    12286/** calculates a lifted knapsack cover cut out of the weighted sum of LP rows given by an aggregation row; the
    12287 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
    12288 * participate in the cut.
    12289 * For further details we refer to:
    12290 *
    12291 * Letchford, A. N., & Souli, G. (2019). On lifted cover inequalities: A new lifting procedure with unusual properties.
    12292 * Operations Research Letters, 47(2), 83-87.
    12293 *
    12294 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    12295 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    12296 *
    12297 * @pre This method can be called if @p scip is in one of the following stages:
    12298 * - \ref SCIP_STAGE_SOLVING
    12299 *
    12300 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    12301 */
    12303 SCIP* scip, /**< SCIP data structure */
    12304 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    12305 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    12306 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
    12307 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
    12308 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
    12309 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
    12310 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
    12311 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
    12312 int* cutrank, /**< pointer to return rank of generated cut */
    12313 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
    12314 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
    12315 )
    12316{
    12317 int* varsign;
    12318 int* boundtype;
    12319 int* coverstatus;
    12320 int* coverpos;
    12321 int* tmpinds;
    12322 SCIP_Real* tmpcoefs;
    12323 SCIP_Real* covervals;
    12324 SCIP_Real QUAD(rhs);
    12325 SCIP_Real QUAD(coverweight);
    12326 SCIP_Real QUAD(abar);
    12327 SCIP_Bool transformed;
    12328 SCIP_Bool local;
    12329 SCIP_Real efficacy;
    12330 SCIP_Real scale;
    12331 int k;
    12332 int nvars;
    12333 int coversize;
    12334 int cplussize;
    12335 int nnz;
    12336
    12337 assert(scip != NULL);
    12338 assert(aggrrow != NULL);
    12339 assert(cutcoefs != NULL);
    12340 assert(cutrhs != NULL);
    12341 assert(cutinds != NULL);
    12342 assert(cutnnz != NULL);
    12343 assert(cutefficacy != NULL);
    12344 assert(cutislocal != NULL);
    12345 assert(success != NULL);
    12346
    12347 *success = FALSE;
    12348
    12349 if( aggrrow->nnz == 0 )
    12350 return SCIP_OKAY;
    12351
    12352 for( k = 0; k < aggrrow->nrows; ++k )
    12353 {
    12354 /* cannot handle negative slack variables */
    12355 if( aggrrow->rowweights[k] * aggrrow->slacksign[k] < 0 )
    12356 return SCIP_OKAY;
    12357 }
    12358
    12359 /* allocate temporary memory */
    12360 nvars = SCIPgetNVars(scip);
    12361 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
    12362 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
    12363 SCIP_CALL( SCIPallocBufferArray(scip, &coverstatus, nvars) );
    12364 SCIP_CALL( SCIPallocBufferArray(scip, &covervals, nvars) );
    12365 SCIP_CALL( SCIPallocBufferArray(scip, &coverpos, nvars) );
    12366 SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
    12368
    12369 /* initialize cut with aggregation */
    12370 nnz = aggrrow->nnz;
    12371 QUAD_ASSIGN_Q(rhs, aggrrow->rhs);
    12372
    12373 BMScopyMemoryArray(tmpinds, aggrrow->inds, nnz);
    12374
    12375 for( k = 0; k < nnz; ++k )
    12376 {
    12377 SCIP_Real QUAD(coef);
    12378 int j = tmpinds[k];
    12379
    12380 QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
    12381
    12382 QUAD_HI(coef) = NONZERO(QUAD_HI(coef));
    12383 assert(QUAD_HI(coef) != 0.0);
    12384
    12385 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
    12386 }
    12387 SCIPdebugMsg(scip, "Computing lifted knapsack cover for ");
    12388 SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
    12389
    12390 /* Transform aggregated row into a (fractional, i.e. with possibly fractional weights) knapsack constraint.
    12391 * Uses simple or variable lower or upper bounds to relax out continuous and general integers
    12392 * so that only binary variables remain and complements those such that they have a positive coefficient.
    12393 */
    12394 local = aggrrow->local;
    12395 SCIP_CALL( cutsTransformKnapsackCover(scip, sol, allowlocal,
    12396 tmpcoefs, QUAD(&rhs), tmpinds, &nnz, varsign, boundtype, &local, &transformed) );
    12397
    12398 assert(allowlocal || !local);
    12399
    12400 if( !transformed )
    12401 goto TERMINATE;
    12402
    12403 SCIPdebugMsg(scip, "Transformed knapsack relaxation ");
    12404 SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
    12405
    12406 if( !computeInitialKnapsackCover(scip, sol, tmpcoefs, tmpinds, QUAD_TO_DBL(rhs), nnz, varsign, coverstatus,
    12407 coverpos, covervals, &coversize, QUAD(&coverweight)) )
    12408 goto TERMINATE;
    12409
    12410 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(coverweight), QUAD_TO_DBL(rhs));
    12411 assert(coversize > 0);
    12412
    12413 /* by default do not scale the cut */
    12414 scale = 1.0;
    12415
    12416 if( coversize == 1 )
    12417 {
    12418 SCIP_Real QUAD(tmp);
    12419 /* cover is trivial, return the fixing as cut */
    12420 QUAD_ASSIGN(tmp, 0.0);
    12421 for( k = 0; k < nnz; ++k )
    12422 {
    12423 if( coverstatus[k] == 0 )
    12424 {
    12425 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
    12426 }
    12427 else
    12428 {
    12429 tmpinds[0] = tmpinds[k];
    12430 varsign[0] = varsign[k];
    12431 }
    12432 }
    12433
    12434 nnz = 1;
    12435 if( varsign[0] == -1 )
    12436 {
    12437 QUAD_ASSIGN(rhs, -1.0);
    12438 QUAD_ASSIGN(tmp, -1.0);
    12439 }
    12440 else
    12441 {
    12442 QUAD_ASSIGN(rhs, 0.0);
    12443 QUAD_ASSIGN(tmp, 1.0);
    12444 }
    12445
    12446 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[0], tmp);
    12447 }
    12448 else
    12449 {
    12450 SCIP_Real QUAD(tmp);
    12451
    12452 /* compute lifted cover inequality:
    12453 * sum_{i \in C^-) x_i + sum_{i \in N \ C^-) g(a_i) x_i <= c - 1
    12454 * where g(z) is equal to
    12455 * - 0 if z is 0 (irrelevant as there shouldn't be element with weight 0 in the knapsack)
    12456 * - h + 1/2 if z = k * \bar{a} for some integer k \in [1, |C^+| - 1] and S^-(h) < z <= S^-(h+1) for some h = 0, ..., coversize -1
    12457 * - h if S^-(h) < z <= S^-(h+1) for some h = 0, ..., coversize -1
    12458 * the function S^- is defined above. Note that S^-(0) = 0
    12459 * we store the cut coefficients in tmpcoef
    12460 */
    12461
    12462 SCIPdebugMsg(scip, "call prepareLiftingData: \n");
    12463 /* prepare data required to evaluate lifting function */
    12464 prepareLiftingData(scip, tmpcoefs, tmpinds, QUAD(rhs), coverpos, coversize,
    12465 QUAD(coverweight), covervals, coverstatus, QUAD(&abar), &cplussize);
    12466
    12467 /* compute lifted cover inequality */
    12468 QUAD_ASSIGN(rhs, (coversize - 1));
    12469 for( k = 0; k < nnz; )
    12470 {
    12471 SCIP_Real cutcoef;
    12472 if( coverstatus[k] == -1 )
    12473 { /* variables in C^- get the coefficients 1 */
    12474 cutcoef = 1.0;
    12475 }
    12476 else
    12477 { /* variables is either in C^+ or not in the cover and its coefficient value is computed with the lifing function */
    12478 SCIP_Real QUAD(coef);
    12479
    12480 SCIPdebugMsg(scip, "load QUAD(coef) from tmpcoefs[tmpinds[k] = %d]\n",tmpinds[k]);
    12481 QUAD_ARRAY_LOAD(coef, tmpcoefs, tmpinds[k]);
    12482
    12483 SCIPdebugMsg(scip, "coef is QUAD_HI=%g, QUAD_LO=%g, QUAD_TO_DBL = %g\n",QUAD_HI(coef), QUAD_LO(coef), QUAD_TO_DBL(coef));
    12484
    12485 SCIPdebugMsg(scip, "call evaluateLiftingFunctionKnapsack:\n");
    12486 cutcoef = evaluateLiftingFunctionKnapsack(scip, QUAD(coef), QUAD(abar), covervals, coversize, cplussize, &scale);
    12487
    12488 /* if the coefficient value is zero then remove the nonzero entry and continue */
    12489 if( cutcoef == 0.0 )
    12490 {
    12491 QUAD_ASSIGN(tmp, 0.0);
    12492 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
    12493 --nnz;
    12494 coverstatus[k] = coverstatus[nnz];
    12495 tmpinds[k] = tmpinds[nnz];
    12496 varsign[k] = varsign[nnz];
    12497 continue;
    12498 }
    12499 }
    12500
    12501 /* directly undo the complementation before storing back the coefficient */
    12502 if( varsign[k] == -1 )
    12503 {
    12504 /* variable was complemented so we have cutcoef * (1-x) = cutcoef - cutcoef * x.Thus we need to adjust the rhs
    12505 * to rhs - cutcoef and flip the sign of cutcoef */
    12506 cutcoef = -cutcoef;
    12507 SCIPquadprecSumQD(rhs, rhs, cutcoef);
    12508 }
    12509
    12510 QUAD_ASSIGN(tmp, cutcoef);
    12511 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
    12512
    12513 ++k;
    12514 }
    12515 }
    12516
    12517 /* calculate the efficacy of the computed cut and store the success flag if the efficacy exceeds the
    12518 * one stored in the cutefficacy variable by the caller
    12519 */
    12520 efficacy = calcEfficacyDenseStorageQuad(scip, sol, tmpcoefs, QUAD_TO_DBL(rhs), tmpinds, nnz);
    12521 *success = SCIPisGT(scip, efficacy, *cutefficacy);
    12522
    12523 SCIPdebugMsg(scip, "FINAL LCI:");
    12524 SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
    12525
    12526 if( *success )
    12527 {
    12528 /* return the cut into the given arrays/pointers */
    12529 *cutislocal = local;
    12530 *cutrhs = scale * QUAD_TO_DBL(rhs);
    12531 *cutnnz = nnz;
    12532
    12533 /* store cut in given array in sparse representation and clean buffer array */
    12534 for( k = 0; k < nnz; ++k )
    12535 {
    12536 SCIP_Real QUAD(coef);
    12537 int j = tmpinds[k];
    12538
    12539 QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
    12540 assert(QUAD_HI(coef) != 0.0);
    12541
    12542 cutcoefs[k] = scale * QUAD_TO_DBL(coef);
    12543 cutinds[k] = j;
    12544 QUAD_ASSIGN(coef, 0.0);
    12545 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
    12546 }
    12547
    12548 assert( cutefficacy != NULL );
    12549 /* calculate efficacy again to make sure it matches the coefficients after they where rounded to double values
    12550 * and after the cleanup and postprocessing step was applied. */
    12551 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, nnz);
    12552
    12553 if( cutrank != NULL )
    12554 *cutrank = aggrrow->rank + 1;
    12555 }
    12556
    12557 TERMINATE:
    12558
    12559 /* if we aborted early the tmpcoefs array needs to be cleaned */
    12560 if( !(*success) )
    12561 {
    12562 SCIP_Real QUAD(tmp);
    12563 QUAD_ASSIGN(tmp, 0.0);
    12564
    12565 for( k = 0; k < nnz; ++k )
    12566 {
    12567 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
    12568 }
    12569 }
    12570#ifndef NDEBUG
    12571 for( k = 0; k < QUAD_ARRAY_SIZE(nvars); ++k )
    12572 {
    12573 if(tmpcoefs[k] != 0.0)
    12574 {
    12575 SCIPdebugMsg(scip, "tmpcoefs have not been reset\n");
    12576 SCIPABORT();
    12577 }
    12578 }
    12579#endif
    12580
    12581 /* free temporary memory */
    12582 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
    12583 SCIPfreeBufferArray(scip, &tmpinds);
    12584 SCIPfreeBufferArray(scip, &coverpos);
    12585 SCIPfreeBufferArray(scip, &covervals);
    12586 SCIPfreeBufferArray(scip, &coverstatus);
    12587 SCIPfreeBufferArray(scip, &boundtype);
    12588 SCIPfreeBufferArray(scip, &varsign);
    12589
    12590 return SCIP_OKAY;
    12591}
    12592
    12593
    12594/* =========================================== strongcg =========================================== */
    12595
    12596/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
    12597 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
    12598 *
    12599 * Differs from cutsTransformMIR for continuous variables for which the lower bound must be used
    12600 * when in case their coefficient is positive and the upper bound in case their coefficient is
    12601 * negative. This forces all continuous variable to have a positive coefficient in the transformed
    12602 * row.
    12603 *
    12604 * Transform variables (lb or ub):
    12605 * \f[
    12606 * \begin{array}{llll}
    12607 * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \mbox{if lb is used in transformation}\\
    12608 * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if ub is used in transformation}
    12609 * \end{array}
    12610 * \f]
    12611 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
    12612 *
    12613 * Transform variables (vlb or vub):
    12614 * \f[
    12615 * \begin{array}{llll}
    12616 * x^\prime_j := x_j - (bl_j\, zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \mbox{if vlb is used in transf.} \\
    12617 * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if vub is used in transf.}
    12618 * \end{array}
    12619 * \f]
    12620 * move the constant terms \f$ a_j\, dl_j \f$ or \f$ a_j\, du_j \f$ to the rhs, and update the coefficient of the VLB variable:
    12621 * \f[
    12622 * \begin{array}{ll}
    12623 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
    12624 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
    12625 * \end{array}
    12626 * \f]
    12627 */
    12628static
    12630 SCIP* scip, /**< SCIP datastructure */
    12631 MIR_DATA* data, /**< the MIR data structure for this cut */
    12632 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    12633 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    12634 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    12635 int* varsign, /**< stores the sign of the transformed variable in summation */
    12636 int* boundtype, /**< stores the bound used for transformed variable:
    12637 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    12638 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
    12639 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
    12640 )
    12641{
    12642 SCIP_Real* bestlbs;
    12643 SCIP_Real* bestubs;
    12644 int* bestlbtypes;
    12645 int* bestubtypes;
    12646 SCIP_BOUNDTYPE* selectedbounds;
    12647 int totalnnz;
    12648 int s;
    12649 int i;
    12650
    12651 assert(data != NULL);
    12652 assert(varsign != NULL);
    12653 assert(boundtype != NULL);
    12654 assert(freevariable != NULL);
    12655 assert(localbdsused != NULL);
    12656
    12657 totalnnz = data->totalnnz;
    12658
    12659 *freevariable = FALSE;
    12660 *localbdsused = FALSE;
    12661
    12662 /* allocate temporary memory to store best bounds and bound types */
    12663 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, 2*totalnnz) );
    12664 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, 2*totalnnz) );
    12665 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, 2*totalnnz) );
    12666 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, 2*totalnnz) );
    12667 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, 2*totalnnz) );
    12668
    12669 /* transform the cut, one variable section at a time */
    12670 for( s = 0; s < NSECTIONS; ++s )
    12671 {
    12672 int* indices = data->secindices[s];
    12673 int cutindsstart = data->ncutinds;
    12674 int usevbds = data->usevbds[s];
    12675
    12676 i = 0;
    12677 /* Iterate over all nonzeros in the section */
    12678 while( i < data->secnnz[s] )
    12679 {
    12680 SCIP_Real QUAD(coef);
    12681 int v = indices[i];
    12682
    12683 /* due to variable bound usage, cancellation may have occurred */
    12684 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
    12685 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
    12686 {
    12687 QUAD_ASSIGN(coef, 0.0);
    12688 QUAD_ARRAY_STORE(data->cutcoefs, v, coef);
    12689 --data->secnnz[s];
    12690 --data->totalnnz;
    12691 indices[i] = indices[data->secnnz[s]];
    12692 /* do not increase the index */
    12693 continue;
    12694 }
    12695
    12696 int cutindex = data->ncutinds;
    12697 /* For continuous variables, we must choose the bound substitution so that they become positive in the cut */
    12698 if( !data->isenfint[s] && !data->isimplint[s] )
    12699 {
    12700 if( QUAD_TO_DBL(coef) > 0.0 )
    12701 {
    12702 SCIP_Real simplelb;
    12703
    12704 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
    12705 SCIP_CALL( findMIRBestLb(scip, data->vars[v], sol, data, usevbds, allowlocal,
    12706 bestlbs + cutindex, &simplelb, bestlbtypes + cutindex) );
    12707
    12708 /* cannot create transformation for strongcg cut */
    12709 if( SCIPisInfinity(scip, -bestlbs[cutindex]) )
    12710 {
    12711 *freevariable = TRUE;
    12712 goto TERMINATE;
    12713 }
    12714
    12715 varsign[cutindex] = +1;
    12716 selectedbounds[cutindex] = SCIP_BOUNDTYPE_LOWER;
    12717 }
    12718 else
    12719 {
    12720 SCIP_Real simpleub;
    12721
    12722 assert(QUAD_TO_DBL(coef) < 0.0);
    12723
    12724 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
    12725 SCIP_CALL( findMIRBestUb(scip, data->vars[v], sol, data, usevbds, allowlocal,
    12726 bestubs + cutindex, &simpleub, bestubtypes + cutindex) );
    12727
    12728 /* cannot create transformation for strongcg cut */
    12729 if( SCIPisInfinity(scip, bestubs[cutindex]) )
    12730 {
    12731 *freevariable = TRUE;
    12732 goto TERMINATE;
    12733 }
    12734
    12735 varsign[cutindex] = -1;
    12736 selectedbounds[cutindex] = SCIP_BOUNDTYPE_UPPER;
    12737 }
    12738 }
    12739 else if( data->isimplint[s] )
    12740 {
    12741 /* For implied integers, we still prefer to choose the bound substitution that makes them positive, but
    12742 * if we cannot manage to do so it is not an error, because we can still treat them as integer variables */
    12743 SCIP_Real simplelb;
    12744 SCIP_Real simpleub;
    12745 SCIP_Bool lowerinf;
    12746 SCIP_Bool upperinf;
    12747 SCIP_Bool positive;
    12748
    12749 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
    12750 SCIP_CALL( findMIRBestLb(scip, data->vars[v], sol, data, usevbds, allowlocal,
    12751 bestlbs + cutindex, &simplelb, bestlbtypes + cutindex) );
    12752
    12753 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
    12754 SCIP_CALL( findMIRBestUb(scip, data->vars[v], sol, data, usevbds, allowlocal,
    12755 bestubs + cutindex, &simpleub, bestubtypes + cutindex) );
    12756
    12757 lowerinf = SCIPisInfinity(scip, -bestlbs[cutindex]);
    12758 upperinf = SCIPisInfinity(scip, bestubs[cutindex]);
    12759 positive = QUAD_TO_DBL(coef) > 0.0;
    12760
    12761 if( lowerinf && upperinf )
    12762 {
    12763 /* we found a free variable in the row with non-zero coefficient
    12764 * -> MIR row can't be transformed in standard form
    12765 */
    12766 *freevariable = TRUE;
    12767 goto TERMINATE;
    12768 }
    12769
    12770 /* preferably, choose bound that makes value positive */
    12771 if( (positive && lowerinf) || (!positive && !upperinf) )
    12772 {
    12773 varsign[cutindex] = -1;
    12774 selectedbounds[cutindex] = SCIP_BOUNDTYPE_UPPER;
    12775 }
    12776 else
    12777 {
    12778 varsign[cutindex] = +1;
    12779 selectedbounds[cutindex] = SCIP_BOUNDTYPE_LOWER;
    12780 }
    12781 }
    12782 else
    12783 {
    12784 /* For explicit integers, we have no restrictions. */
    12785 SCIP_CALL( determineBestBounds(scip, data->vars[v], sol, data, boundswitch, usevbds, allowlocal, FALSE, FALSE,
    12786 NULL, NULL, bestlbs + cutindex, bestubs + cutindex,
    12787 bestlbtypes + cutindex, bestubtypes + cutindex, selectedbounds + cutindex, freevariable) );
    12788
    12789 if( *freevariable)
    12790 goto TERMINATE;
    12791 }
    12792
    12793 data->cutinds[cutindex] = v;
    12794 ++data->ncutinds;
    12795
    12796 ++i;
    12797 }
    12798
    12799 /* perform bound substitution for all nonzeros in the section */
    12800 for( i = cutindsstart; i < data->ncutinds; ++i )
    12801 {
    12802 SCIP_Real bestbnd;
    12803 int v = data->cutinds[i];
    12804
    12805 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
    12806 {
    12807 assert(!SCIPisInfinity(scip, -bestlbs[i]));
    12808
    12809 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
    12810 boundtype[i] = bestlbtypes[i];
    12811 varsign[i] = +1;
    12812 bestbnd = bestlbs[i];
    12813 }
    12814 else
    12815 {
    12816 assert(!SCIPisInfinity(scip, bestubs[i]));
    12817
    12818 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
    12819 boundtype[i] = bestubtypes[i];
    12820 varsign[i] = -1;
    12821 bestbnd = bestubs[i];
    12822 }
    12823
    12824 doMIRBoundSubstitution(scip, data, varsign[i], boundtype[i], bestbnd, v, localbdsused);
    12825 }
    12826 }
    12827
    12828 /* relax rhs to zero if it is close to */
    12829 if( QUAD_TO_DBL(data->cutrhs) < 0.0 && QUAD_TO_DBL(data->cutrhs) >= -SCIPepsilon(scip) )
    12830 QUAD_ASSIGN(data->cutrhs, 0.0);
    12831
    12832 TERMINATE:
    12833
    12834 /* If we terminate early, we need to make sure all the zeros in the cut coefficient array are cancelled */
    12835 if( *freevariable )
    12836 {
    12837 int j;
    12838 int k;
    12839
    12840 data->ncutinds = 0;
    12841 for( j = 0; j < NSECTIONS; ++j )
    12842 {
    12843 int* indexlist = data->secindices[j];
    12844 for( k = 0; k < data->secnnz[j]; ++k )
    12845 {
    12846 data->cutinds[data->ncutinds] = indexlist[k];
    12847 ++data->ncutinds;
    12848 }
    12849 }
    12850 }
    12851
    12852 /*free temporary memory */
    12853 SCIPfreeBufferArray(scip, &selectedbounds);
    12854 SCIPfreeBufferArray(scip, &bestubtypes);
    12855 SCIPfreeBufferArray(scip, &bestlbtypes);
    12856 SCIPfreeBufferArray(scip, &bestubs);
    12857 SCIPfreeBufferArray(scip, &bestlbs);
    12858
    12859 return SCIP_OKAY;
    12860}
    12861
    12862/** Calculate fractionalities \f$ f_0 := b - down(b) \f$, \f$ f_j := a^\prime_j - down(a^\prime_j) \f$,
    12863 * integer \f$ k \geq 1 \f$ with \f$ 1/(k + 1) \leq f_0 < 1/k \f$ \f$ (\Rightarrow k = up(1/f_0) - 1) \f$ and
    12864 * integer \f$ 1 \leq p_j \leq k \f$ with \f$ f_0 + ((p_j - 1) \cdot (1 - f_0)/k) < f_j \leq f_0 + (p_j (1 - f_0)/k)\f$ \f$ (\Rightarrow p_j = up( k\,(f_j - f_0)/(1 - f_0) )) \f$
    12865 * and derive strong CG cut \f$ \tilde{a} x^\prime \leq down(b) \f$
    12866 * \f[
    12867 * \begin{array}{rll}
    12868 * integers : & \tilde{a}_j = down(a^\prime_j) &, if \qquad f_j \leq f_0 \\
    12869 * & \tilde{a}_j = down(a^\prime_j) + p_j/(k + 1) &, if \qquad f_j > f_0 \\
    12870 * continuous:& \tilde{a}_j = 0 &, if \qquad a^\prime_j \geq 0 \\
    12871 * & \mbox{no strong CG cut found} &, if \qquad a^\prime_j < 0
    12872 * \end{array}
    12873 * \f]
    12874 *
    12875 * Transform inequality back to \f$ \hat{a}*x <= rhs \f$:
    12876 *
    12877 * (lb or ub):
    12878 * \f[
    12879 * \begin{array}{lllll}
    12880 * x^\prime_j := x_j - lb_j,& x_j == x^\prime_j + lb_j,& a^\prime_j == a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{if lb was used in transformation} \\
    12881 * x^\prime_j := ub_j - x_j,& x_j == ub_j - x^\prime_j,& a^\prime_j == -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{if ub was used in transformation}
    12882 * \end{array}
    12883 * \f]
    12884 * \f[
    12885 * and move the constant terms
    12886 * \begin{array}{rl}
    12887 * -\tilde{a}_j * lb_j == -\hat{a}_j * lb_j, & \mbox{or} \\
    12888 * \tilde{a}_j * ub_j == -\hat{a}_j * ub_j &
    12889 * \end{array}
    12890 * \f]
    12891 * to the rhs.
    12892 *
    12893 * (vlb or vub):
    12894 * \f[
    12895 * \begin{array}{lllll}
    12896 * x^\prime_j := x_j - (bl_j * zl_j + dl_j),& x_j == x^\prime_j + (bl_j * zl_j + dl_j),& a^\prime_j == a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{(vlb)} \\
    12897 * x^\prime_j := (bu_j * zu_j + du_j) - x_j,& x_j == (bu_j * zu_j + du_j) - x^\prime_j,& a^\prime_j == -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{(vub)}
    12898 * \end{array}
    12899 * \f]
    12900 * move the constant terms
    12901 * \f[
    12902 * \begin{array}{rl}
    12903 * -\tilde{a}_j * dl_j == -\hat{a}_j * dl_j,& \mbox{or} \\
    12904 * \tilde{a}_j * du_j == -\hat{a}_j * du_j &
    12905 * \end{array}
    12906 * \f]
    12907 * to the rhs, and update the VB variable coefficients:
    12908 * \f[
    12909 * \begin{array}{ll}
    12910 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j * bl_j == \hat{a}_{zl_j} - \hat{a}_j * bl_j,& \mbox{or} \\
    12911 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j * bu_j == \hat{a}_{zu_j} - \hat{a}_j * bu_j &
    12912 * \end{array}
    12913 * \f]
    12914 */
    12915static
    12917 SCIP* scip, /**< SCIP datastructure */
    12918 MIR_DATA* data, /**< the MIR data structure for this cut */
    12919 int* varsign, /**< stores the sign of the transformed variable in summation */
    12920 int* boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub)*/
    12921 QUAD(SCIP_Real f0), /**< fractional value of rhs */
    12922 SCIP_Real k /**< factor to strengthen strongcg cut */
    12923 )
    12924{
    12925 SCIP_Real QUAD(tmp);
    12926 SCIP_Real QUAD(onedivoneminusf0);
    12927 int cutindex;
    12928 int s;
    12929 int i;
    12930
    12931 assert(data != NULL);
    12932 assert(boundtype != NULL);
    12933 assert(varsign != NULL);
    12934 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
    12935
    12936 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
    12937 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
    12938
    12939 /* Loop backwards through the sections, so that the reversing of varbound substitutions does not prematurely effect
    12940 * the coefficients of variables in other sections, because the section index of a variable bound must always be
    12941 * higher than that of the bounded variable. */
    12942 cutindex = data->ncutinds - 1;
    12943 for( s = NSECTIONS - 1; s >= 0; --s )
    12944 {
    12945 int* indices = data->secindices[s];
    12946 int nnz = data->secnnz[s];
    12947 SCIP_Bool enfintegral = data->isenfint[s];
    12948 SCIP_Bool implintegral = data->isimplint[s];
    12949
    12950 /* iterate backwards over indices in section, so we can easily shrink the section if we find zeros */
    12951 for( i = nnz - 1; i >= 0 ; --i )
    12952 {
    12953 SCIP_Real QUAD(cutaj);
    12954 SCIP_Real QUAD(aj);
    12955 SCIP_VAR* var;
    12956 int v = indices[i];
    12957 int sign;
    12958 int type;
    12959
    12960 assert(0 <= v && v < data->nvars);
    12961 assert(data->cutinds[cutindex] == v);
    12962 sign = varsign[cutindex];
    12963 assert(sign == +1 || sign == -1);
    12964 type = boundtype[cutindex];
    12965
    12966 --cutindex;
    12967
    12968 var = data->vars[v];
    12969 assert(var != NULL);
    12970 assert(SCIPvarGetProbindex(var) == v );
    12971
    12972 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
    12973
    12974 if( enfintegral || implintegral )
    12975 {
    12976 /* Variable is integral */
    12977 SCIP_Real QUAD(downaj);
    12978 SCIP_Real QUAD(fj);
    12979
    12980 /* calculate the coefficient in the retransformed cut */
    12981 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
    12982 QUAD_SCALE(aj, sign);
    12983 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
    12984 SCIPquadprecSumQQ(fj, aj, -downaj);
    12985 assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
    12986
    12987 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
    12988 QUAD_ASSIGN_Q(cutaj, downaj); /* a_j */
    12989 else
    12990 {
    12991 SCIP_Real pj;
    12992
    12993 SCIPquadprecSumQQ(cutaj, fj, -f0);
    12994 SCIPquadprecProdQD(cutaj, cutaj, k);
    12995 SCIPquadprecProdQQ(cutaj, cutaj, onedivoneminusf0);
    12996 pj = SCIPceil(scip, QUAD_TO_DBL(cutaj));
    12997 assert(pj >= 0); /* should be >= 1, but due to rounding bias can be 0 if fj is almost equal to f0 */
    12998 assert(pj <= k);
    12999 SCIPquadprecDivDD(cutaj, pj, k + 1.0);
    13000 SCIPquadprecSumQQ(cutaj, cutaj, downaj);
    13001 }
    13002
    13003 QUAD_SCALE(cutaj, sign);
    13004 }
    13005 else
    13006 {
    13007 /* Variable is continuous; must always be positive in strongcg cut. It will be automatically deleted. */
    13009 assert(QUAD_TO_DBL(aj) * sign >= 0.0);
    13010 QUAD_ASSIGN(cutaj, 0.0);
    13011 }
    13012
    13013 /* remove coefficient from cut if it becomes zero */
    13014 if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
    13015 {
    13016 QUAD_ASSIGN(cutaj, 0.0);
    13017 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
    13018 --data->totalnnz;
    13019 --data->secnnz[s];
    13020 indices[i] = indices[data->secnnz[s]];
    13021 continue;
    13022 }
    13023
    13024 /* store the updated coefficient */
    13025 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
    13026
    13027 /* undo bound transformations. */
    13028 if( type < 0 )
    13029 {
    13030 /* standard bound */
    13031 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    13032 if( sign == +1 )
    13033 {
    13034 /* lower bound was used */
    13035 if( type == -1 )
    13036 {
    13037 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    13038 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
    13039 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    13040 }
    13041 else
    13042 {
    13043 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    13044 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
    13045 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    13046 }
    13047 }
    13048 else
    13049 {
    13050 /* upper bound was used */
    13051 if( type == -1 )
    13052 {
    13053 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    13054 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
    13055 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    13056 }
    13057 else
    13058 {
    13059 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    13060 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
    13061 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    13062 }
    13063 }
    13064 }
    13065 else
    13066 {
    13067 /* variable bound */
    13068 SCIP_VAR** vbz;
    13069 SCIP_Real* vbb;
    13070 SCIP_Real* vbd;
    13071 SCIP_Real QUAD(zcoef);
    13072 int vbidx;
    13073 int zidx;
    13074
    13075 /* variable bound */
    13076 vbidx = type;
    13077
    13078 /* change mirrhs and cutaj of integer variable z_j of variable bound */
    13079 if( sign == +1 )
    13080 {
    13081 /* variable lower bound was used */
    13082 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
    13083 vbz = SCIPvarGetVlbVars(var);
    13084 vbb = SCIPvarGetVlbCoefs(var);
    13085 vbd = SCIPvarGetVlbConstants(var);
    13086 }
    13087 else
    13088 {
    13089 /* variable upper bound was used */
    13090 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
    13091 vbz = SCIPvarGetVubVars(var);
    13092 vbb = SCIPvarGetVubCoefs(var);
    13093 vbd = SCIPvarGetVubConstants(var);
    13094 }
    13095 assert(SCIPvarIsActive(vbz[vbidx]));
    13096 zidx = SCIPvarGetProbindex(vbz[vbidx]);
    13097 assert(varSection(data, zidx) > s);
    13098
    13099 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
    13100 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    13101
    13102 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
    13103 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
    13104
    13105 /* update sparsity pattern */
    13106 if( QUAD_HI(zcoef) == 0.0 )
    13107 {
    13108 int zsection = varSection(data, zidx);
    13109 data->secindices[zsection][data->secnnz[zsection]] = zidx;
    13110 ++data->secnnz[zsection];
    13111 ++data->totalnnz;
    13112 }
    13113
    13114 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
    13115 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
    13116 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
    13117 assert(QUAD_HI(zcoef) != 0.0);
    13118 }
    13119 }
    13120 }
    13121
    13122 /* Finally, store the relevant data in cutinds which is the array used by the other functions */
    13123 data->ncutinds = 0;
    13124 for( s = 0; s < NSECTIONS; ++s )
    13125 {
    13126 int* indices = data->secindices[s];
    13127 int nnz = data->secnnz[s];
    13128 for( i = 0; i < nnz; ++i )
    13129 {
    13130 data->cutinds[data->ncutinds] = indices[i];
    13131 ++data->ncutinds;
    13132 }
    13133 }
    13134
    13135 return SCIP_OKAY;
    13136}
    13137
    13138/** substitute aggregated slack variables:
    13139 *
    13140 * The coefficient of the slack variable \f$s_r\f$ is equal to the row's weight times the slack's sign, because the slack
    13141 * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r] \f$.
    13142 *
    13143 * Depending on the slack's type (integral or continuous), its coefficient in the cut calculates as follows:
    13144 * \f[
    13145 * \begin{array}{rll}
    13146 * integers: & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & if \qquad f_r \leq f_0 \\
    13147 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + p_r/(k + 1), & if \qquad f_r > f_0 \\
    13148 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & if \qquad a^\prime_r \geq 0 \\
    13149 * & \mbox{no strong CG cut found}, & if \qquad a^\prime_r < 0
    13150 * \end{array}
    13151 * \f]
    13152 *
    13153 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
    13154 */
    13155static
    13157 SCIP* scip, /**< SCIP datastructure */
    13158 SCIP_Real* weights, /**< row weights in row summation */
    13159 int* slacksign, /**< stores the sign of the row's slack variable in summation */
    13160 int* rowinds, /**< sparsity pattern of used rows */
    13161 int nrowinds, /**< number of used rows */
    13162 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
    13163 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    13164 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
    13165 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    13166 int* nnz, /**< number of non-zeros in cut */
    13167 QUAD(SCIP_Real f0), /**< fractional value of rhs */
    13168 SCIP_Real k /**< factor to strengthen strongcg cut */
    13169 )
    13170{ /*lint --e{715}*/
    13171 SCIP_ROW** rows;
    13172 SCIP_Real QUAD(onedivoneminusf0);
    13173 int i;
    13174
    13175 assert(scip != NULL);
    13176 assert(weights != NULL);
    13177 assert(slacksign != NULL);
    13178 assert(rowinds != NULL);
    13179 assert(SCIPisPositive(scip, scale));
    13180 assert(cutcoefs != NULL);
    13181 assert(QUAD_HI(cutrhs) != NULL);
    13182 assert(cutinds != NULL);
    13183 assert(nnz != NULL);
    13184 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
    13185
    13186 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
    13187 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
    13188
    13189 rows = SCIPgetLPRows(scip);
    13190 for( i = 0; i < nrowinds; i++ )
    13191 {
    13192 SCIP_ROW* row;
    13193 SCIP_Real QUAD(ar);
    13194 SCIP_Real QUAD(downar);
    13195 SCIP_Real QUAD(cutar);
    13196 SCIP_Real QUAD(fr);
    13197 SCIP_Real mul;
    13198 int r;
    13199
    13200 r = rowinds[i];
    13201 assert(0 <= r && r < SCIPgetNLPRows(scip));
    13202 assert(slacksign[i] == -1 || slacksign[i] == +1);
    13203 assert(!SCIPisZero(scip, weights[i]));
    13204
    13205 row = rows[r];
    13206 assert(row != NULL);
    13207 assert(row->len == 0 || row->cols != NULL);
    13208 assert(row->len == 0 || row->cols_index != NULL);
    13209 assert(row->len == 0 || row->vals != NULL);
    13210
    13211 /* get the slack's coefficient a'_r in the aggregated row */
    13212 SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
    13213
    13214 /* calculate slack variable's coefficient a_r in the cut */
    13215 if( row->integral )
    13216 {
    13217 /* slack variable is always integral */
    13218 SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
    13219 SCIPquadprecSumQQ(fr, ar, -downar);
    13220 assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
    13221
    13222 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
    13223 QUAD_ASSIGN_Q(cutar, downar); /* a_r */
    13224 else
    13225 {
    13226 SCIP_Real pr;
    13227
    13228 SCIPquadprecSumQQ(cutar, fr, -f0);
    13229 SCIPquadprecProdQD(cutar, cutar, k);
    13230 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
    13231 pr = SCIPceil(scip, QUAD_TO_DBL(cutar));
    13232 assert(pr >= 0); /* should be >= 1, but due to rounding bias can be 0 if fr is almost equal to f0 */
    13233 assert(pr <= k);
    13234 SCIPquadprecDivDD(cutar, pr, k + 1.0);
    13235 SCIPquadprecSumQQ(cutar, cutar, downar);
    13236 }
    13237 }
    13238 else
    13239 {
    13240 /* slack variable is continuous: */
    13241 assert(QUAD_TO_DBL(ar) >= 0.0);
    13242 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
    13243 }
    13244
    13245 /* if the coefficient was reduced to zero, ignore the slack variable */
    13246 if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
    13247 continue;
    13248
    13249 /* depending on the slack's sign, we have
    13250 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
    13251 * substitute a_r * s_r by adding a_r times the slack's definition to the cut.
    13252 */
    13253 mul = -slacksign[i] * QUAD_TO_DBL(cutar);
    13254
    13255 /* add the slack's definition multiplied with a_j to the cut */
    13256 SCIP_CALL( varVecAddScaledRowCoefsQuad(cutinds, cutcoefs, nnz, row, mul) );
    13257
    13258 /* move slack's constant to the right hand side */
    13259 if( slacksign[i] == +1 )
    13260 {
    13261 SCIP_Real rhs;
    13262
    13263 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a_r * (rhs - c) to the right hand side */
    13264 assert(!SCIPisInfinity(scip, row->rhs));
    13265 rhs = row->rhs - row->constant;
    13266 if( row->integral )
    13267 {
    13268 /* the right hand side was implicitly rounded down in row aggregation */
    13269 rhs = SCIPfloor(scip, rhs);
    13270 }
    13271
    13272 SCIPquadprecProdQD(cutar, cutar, rhs);
    13273 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -cutar);
    13274 }
    13275 else
    13276 {
    13277 SCIP_Real lhs;
    13278
    13279 /* a*x + c - s == lhs => s == a*x + c - lhs: move a_r * (c - lhs) to the right hand side */
    13280 assert(!SCIPisInfinity(scip, -row->lhs));
    13281 lhs = row->lhs - row->constant;
    13282 if( row->integral )
    13283 {
    13284 /* the left hand side was implicitly rounded up in row aggregation */
    13285 lhs = SCIPceil(scip, lhs);
    13286 }
    13287
    13288 SCIPquadprecProdQD(cutar, cutar, lhs);
    13289 SCIPquadprecSumQQ(*cutrhs, *cutrhs, cutar);
    13290 }
    13291 }
    13292
    13293 /* relax rhs to zero, if it's very close to 0 */
    13294 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    13295 QUAD_ASSIGN(*cutrhs, 0.0);
    13296
    13297 return SCIP_OKAY;
    13298}
    13299
    13300
    13301/** calculates a strong CG cut out of the weighted sum of LP rows given by an aggregation row; the
    13302 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
    13303 * participate in a strongcg cut
    13304 *
    13305 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    13306 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    13307 *
    13308 * @pre This method can be called if @p scip is in one of the following stages:
    13309 * - \ref SCIP_STAGE_SOLVING
    13310 *
    13311 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    13312 */
    13314 SCIP* scip, /**< SCIP data structure */
    13315 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    13316 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
    13317 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    13318 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
    13319 * type substitution is allowed. The indices are: 0: continuous,
    13320 * 1: continuous implint., 2: integer implint, 3: binary implint,
    13321 * 4: integer, 5: binary */
    13322 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    13323 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce strong CG cut for */
    13324 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce strong CG cut for */
    13325 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
    13326 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute a strong CG cut for */
    13327 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
    13328 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
    13329 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
    13330 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
    13331 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
    13332 int* cutrank, /**< pointer to return rank of generated cut */
    13333 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
    13334 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
    13335 )
    13336{
    13337 int i;
    13338 int nvars;
    13339 int* varsign;
    13340 int* boundtype;
    13341 SCIP_Real QUAD(downrhs);
    13342 SCIP_Real QUAD(f0);
    13343 SCIP_Real QUAD(tmp);
    13344 SCIP_Real large;
    13345 SCIP_Real k;
    13346 SCIP_Bool freevariable;
    13347 SCIP_Bool localbdsused;
    13348 MIR_DATA* data;
    13349
    13350 assert(scip != NULL);
    13351 assert(aggrrow != NULL);
    13352 assert(SCIPisPositive(scip, scale));
    13353 assert(cutcoefs != NULL);
    13354 assert(cutrhs != NULL);
    13355 assert(cutinds != NULL);
    13356 assert(success != NULL);
    13357 assert(cutislocal != NULL);
    13358
    13359 SCIPdebugMsg(scip, "calculating strong CG cut (scale: %g)\n", scale);
    13360
    13361 *success = FALSE;
    13362
    13363 /* determine value from which fractionalities are no longer reliable within tolerance */
    13365
    13366 /* terminate if an integral slack fractionality is unreliable or a negative continuous slack variable is present */
    13367 for( i = 0; i < aggrrow->nrows; ++i )
    13368 {
    13369 if( ( scip->lp->rows[aggrrow->rowsinds[i]]->integral && ABS(aggrrow->rowweights[i] * scale) > large )
    13370 || ( !scip->lp->rows[aggrrow->rowsinds[i]]->integral && aggrrow->rowweights[i] * aggrrow->slacksign[i] < 0.0 ) )
    13371 return SCIP_OKAY;
    13372 }
    13373
    13374 /* allocate temporary memory */
    13375 nvars = SCIPgetNVars(scip);
    13376 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
    13377 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
    13378
    13379 /* Initialize cut data */
    13380 int l;
    13381 int nnz;
    13382
    13383 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
    13384
    13385 SCIP_CALL( SCIPallocBuffer(scip, &data) );
    13386
    13387 nnz = aggrrow->nnz;
    13388 data->totalnnz = nnz;
    13389
    13390 /* initialize sections */
    13391 for( l = 0; l < NSECTIONS; ++l )
    13392 {
    13393 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
    13394 data->secnnz[l] = 0;
    13395 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
    13396 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
    13397 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
    13398 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
    13399 /* Use variable bounds for the sections specified by the user */
    13400 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
    13401 }
    13402
    13403 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
    13404 data->vars = SCIPgetVars(scip);
    13405 data->nvars = SCIPgetNVars(scip);
    13406 data->nbinvars = SCIPgetNBinVars(scip);
    13407 data->nintvars = SCIPgetNIntVars(scip);
    13412
    13414 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
    13415
    13416 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, scale);
    13417
    13418 if( nnz > 0 )
    13419 {
    13420 /* Initalize cut with the aggregation */
    13421 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
    13422
    13423 for( l = 0; l < nnz; ++l )
    13424 {
    13425 SCIP_Real QUAD(coef);
    13426 int m = aggrrow->inds[l];
    13427
    13428 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
    13429
    13430 SCIPquadprecProdQD(coef, coef, scale);
    13431
    13432 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
    13433
    13434 assert(QUAD_HI(coef) != 0.0);
    13435 }
    13436
    13437 /* Sort the array by problem index and add the variables to their sections */
    13438 SCIPsortDownInt(data->cutinds, nnz);
    13439 for( l = 0; l < nnz; ++l )
    13440 {
    13441 int section = varSection(data, data->cutinds[l]);
    13442 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
    13443 ++data->secnnz[section];
    13444 }
    13445 }
    13446
    13447 data->ncutinds = 0;
    13448 *cutislocal = aggrrow->local;
    13449
    13450 if( data->totalnnz > 0 )
    13451 {
    13452 int firstcontvar;
    13453
    13454 /* Transform equation a*x == b, lb <= x <= ub into standard form
    13455 * a'*x' == b, 0 <= x' <= ub'.
    13456 *
    13457 * Transform variables (lb or ub):
    13458 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
    13459 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
    13460 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
    13461 *
    13462 * Transform variables (vlb or vub):
    13463 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
    13464 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
    13465 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
    13466 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
    13467 * a_{zu_j} := a_{zu_j} + a_j * bu_j
    13468 */
    13469 SCIP_CALL( cutsTransformStrongCG(scip, data, sol, boundswitch, allowlocal, varsign, boundtype, &freevariable, &localbdsused) );
    13470
    13471 if( freevariable )
    13472 goto TERMINATE;
    13473
    13474 assert(allowlocal || !localbdsused);
    13475 *cutislocal = *cutislocal || localbdsused;
    13476
    13477 firstcontvar = nvars - SCIPgetNContVars(scip);
    13478
    13479 /* terminate if an integral coefficient fractionality is unreliable */
    13480 for( i = data->ncutinds - 1; i >= 0 && data->cutinds[i] < firstcontvar; --i )
    13481 {
    13482 SCIP_Real QUAD(coef);
    13483
    13484 QUAD_ARRAY_LOAD(coef, data->cutcoefs, data->cutinds[i]);
    13485
    13486 if( ABS(QUAD_TO_DBL(coef)) > large )
    13487 goto TERMINATE;
    13488 }
    13489
    13490 SCIPdebug(printCutQuad(scip, NULL, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    13491 }
    13492
    13493 /* terminate if the side fractionality is unreliable */
    13494 if( ABS(QUAD_TO_DBL(data->cutrhs)) > large )
    13495 goto TERMINATE;
    13496
    13497 /* Calculate
    13498 * - fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j)
    13499 * - integer k >= 1 with 1/(k + 1) <= f_0 < 1/k
    13500 * (=> k = up(1/f_0) - 1)
    13501 * - integer 1 <= p_j <= k with f_0 + ((p_j - 1) * (1 - f_0)/k) < f_j <= f_0 + (p_j * (1 - f_0)/k)
    13502 * (=> p_j = up( (f_j - f_0)/((1 - f_0)/k) ))
    13503 * and derive strong CG cut
    13504 * a~*x' <= (k+1) * down(b)
    13505 * integers : a~_j = down(a'_j) , if f_j <= f_0
    13506 * a~_j = down(a'_j) + p_j/(k + 1) , if f_j > f_0
    13507 * continuous: a~_j = 0 , if a'_j >= 0
    13508 * no strong CG cut found , if a'_j < 0
    13509 *
    13510 * Transform inequality back to a^*x <= rhs:
    13511 *
    13512 * (lb or ub):
    13513 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
    13514 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
    13515 * and move the constant terms
    13516 * -a~_j * lb_j == -a^_j * lb_j, or
    13517 * a~_j * ub_j == -a^_j * ub_j
    13518 * to the rhs.
    13519 *
    13520 * (vlb or vub):
    13521 * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
    13522 * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
    13523 * move the constant terms
    13524 * -a~_j * dl_j == -a^_j * dl_j, or
    13525 * a~_j * du_j == -a^_j * du_j
    13526 * to the rhs, and update the VB variable coefficients:
    13527 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
    13528 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
    13529 */
    13530 SCIPquadprecEpsFloorQ(downrhs, data->cutrhs, SCIPepsilon(scip)); /*lint !e666*/
    13531 SCIPquadprecSumQQ(f0, data->cutrhs, -downrhs);
    13532 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
    13533
    13534 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
    13535 goto TERMINATE;
    13536
    13537 /* renormalize the f0 value */
    13538 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
    13539
    13540 SCIPquadprecDivDQ(tmp, 1.0, f0);
    13541 SCIPquadprecSumQD(tmp, tmp, -1.0);
    13542 k = SCIPceil(scip, QUAD_TO_DBL(tmp));
    13543 QUAD_ASSIGN_Q(data->cutrhs, downrhs);
    13544
    13545 if( data->totalnnz > 0 )
    13546 {
    13547 SCIP_CALL( cutsRoundStrongCG(scip, data, varsign, boundtype, QUAD(f0), k) );
    13548 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    13549 }
    13550
    13551 /* substitute aggregated slack variables:
    13552 *
    13553 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    13554 * variable only appears in its own row:
    13555 * a'_r = scale * weight[r] * slacksign[r].
    13556 *
    13557 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    13558 * integers : a_r = a~_r = (k + 1) * down(a'_r) , if f_r <= f0
    13559 * a_r = a~_r = (k + 1) * down(a'_r) + p_r , if f_r > f0
    13560 * continuous: a_r = a~_r = 0 , if a'_r >= 0
    13561 * a_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    13562 *
    13563 * Substitute a_r * s_r by adding a_r times the slack's definition to the cut.
    13564 */
    13565 SCIP_CALL( cutsSubstituteStrongCG(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
    13566 aggrrow->nrows, scale, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds, QUAD(f0), k) );
    13567 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    13568
    13569 /* remove all nearly-zero coefficients from strong CG row and relax the right hand side correspondingly in order to
    13570 * prevent numerical rounding errors
    13571 */
    13572 if( postprocess )
    13573 {
    13574 SCIP_CALL( postprocessCutQuad(scip, *cutislocal, data->cutinds, data->cutcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
    13575 }
    13576 else
    13577 {
    13578 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds);
    13579 }
    13580 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    13581
    13582 if( *success )
    13583 {
    13584 *cutrhs = QUAD_TO_DBL(data->cutrhs);
    13585 *cutnnz = data->ncutinds;
    13586
    13587 /* store cut in given array in sparse representation and clean buffer array */
    13588 for( i = 0; i < *cutnnz; ++i )
    13589 {
    13590 SCIP_Real QUAD(coef);
    13591 int j = data->cutinds[i];
    13592
    13593 QUAD_ARRAY_LOAD(coef, data->cutcoefs, j);
    13594 assert(QUAD_HI(coef) != 0.0);
    13595
    13596 cutcoefs[i] = QUAD_TO_DBL(coef);
    13597 cutinds[i] = j;
    13598 QUAD_ASSIGN(coef, 0.0);
    13599 QUAD_ARRAY_STORE(data->cutcoefs, j, coef);
    13600 }
    13601
    13602 if( cutefficacy != NULL )
    13603 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
    13604
    13605 if( cutrank != NULL )
    13606 *cutrank = aggrrow->rank + 1;
    13607 }
    13608
    13609 TERMINATE:
    13610
    13611 /* if we aborted early the temporary coefficients need to be cleaned */
    13612 if( !(*success) )
    13613 {
    13614 QUAD_ASSIGN(tmp, 0.0);
    13615
    13616 for( i = 0; i < data->ncutinds; ++i )
    13617 {
    13618 QUAD_ARRAY_STORE(data->cutcoefs, data->cutinds[i], tmp);
    13619 }
    13620 }
    13621
    13622 if( data->cutinds != NULL )
    13624
    13625 if( data->cutcoefs != NULL )
    13627
    13628 for( int s = NSECTIONS - 1; s >= 0; --s )
    13629 {
    13631 }
    13632
    13633 SCIPfreeBuffer(scip, &data);
    13634
    13635 /* free temporary memory */
    13636 SCIPfreeBufferArray(scip, &boundtype);
    13637 SCIPfreeBufferArray(scip, &varsign);
    13638
    13639 return SCIP_OKAY;
    13640}
    13641
    13642/** initializes cut generation parameters with default values */
    13644 SCIP_CUTGENPARAMS* params /**< pointer to parameters to initialize */
    13645 )
    13646{
    13647 assert(params != NULL);
    13648
    13654 params->boundsfortrans = NULL;
    13655 params->boundtypesfortrans = NULL;
    13658}
    13659
    13660/** creates a cut generation result structure and allocates arrays for cut coefficients and indices
    13661 *
    13662 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    13663 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    13664 */
    13666 SCIP* scip, /**< SCIP data structure */
    13667 SCIP_CUTGENRESULT** result /**< pointer to store the created result structure */
    13668 )
    13669{
    13670 int nvars;
    13671
    13672 assert(scip != NULL);
    13673 assert(result != NULL);
    13674
    13675 nvars = SCIPgetNVars(scip);
    13676
    13677 SCIP_CALL( SCIPallocBuffer(scip, result) );
    13678 SCIP_CALL( SCIPallocBufferArray(scip, &(*result)->cutcoefs, nvars) );
    13679 SCIP_CALL( SCIPallocBufferArray(scip, &(*result)->cutinds, nvars) );
    13680
    13681 return SCIP_OKAY;
    13682}
    13683
    13684/** frees a cut generation result structure created by SCIPcreateCutGenResult() */
    13686 SCIP* scip, /**< SCIP data structure */
    13687 SCIP_CUTGENRESULT** result /**< pointer to the result structure to free */
    13688 )
    13689{
    13690 assert(scip != NULL);
    13691 assert(result != NULL);
    13692 assert(*result != NULL);
    13693
    13694 SCIPfreeBufferArray(scip, &(*result)->cutinds);
    13695 SCIPfreeBufferArray(scip, &(*result)->cutcoefs);
    13696 SCIPfreeBuffer(scip, result);
    13697}
    13698
    13699/** tries multiple cut generation methods on an aggregation row and returns the best cut by efficacy
    13700 *
    13701 * This function attempts to generate cuts using the specified methods.
    13702 * Each method only returns a cut if it improves upon the previous best efficacy.
    13703 * See type_cuts.h for available SCIP_CUTGENMETHOD_* flags.
    13704 *
    13705 * Use SCIPinitCutGenParams() to initialize parameters with default values.
    13706 * Use SCIPcreateCutGenResult() to create the result structure, or manually set result->cutcoefs and result->cutinds
    13707 * to point to arrays of size at least SCIPgetNVars(scip).
    13708 * Use SCIPfreeCutGenResult() to free the result structure when done.
    13709 *
    13710 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    13711 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    13712 *
    13713 * @pre This method can be called if @p scip is in one of the following stages:
    13714 * - \ref SCIP_STAGE_SOLVING
    13715 */
    13717 SCIP* scip, /**< SCIP data structure */
    13718 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    13719 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute cuts for */
    13720 SCIP_CUTGENMETHOD methods, /**< bit field indicating which methods to try (SCIP_CUTGENMETHOD_*) */
    13721 SCIP_CUTGENPARAMS* params, /**< cut generation parameters */
    13722 SCIP_CUTGENRESULT* result /**< pointer to result structure (cutcoefs and cutinds pre-allocated) */
    13723 )
    13724{
    13725 SCIP_Real cutrhs;
    13726 SCIP_Real efficacy;
    13727 SCIP_Bool cutislocal;
    13728 SCIP_Bool success;
    13729 int cutnnz;
    13730 int cutrank;
    13731
    13732 assert(scip != NULL);
    13733 assert(aggrrow != NULL);
    13734 assert(aggrrow->nnz >= 0);
    13735 assert(methods != SCIP_CUTGENMETHOD_NONE);
    13736 assert(params != NULL);
    13737 assert(result != NULL);
    13738 assert(result->cutcoefs != NULL);
    13739 assert(result->cutinds != NULL);
    13740
    13741 /* initialize result */
    13743 result->cutefficacy = -SCIPinfinity(scip);
    13744 result->cutrhs = 0.0;
    13745 result->cutnnz = 0;
    13746 result->cutrank = 0;
    13747 result->cutislocal = FALSE;
    13748 result->success = FALSE;
    13749
    13750 /* bail out early if the aggregation row is empty */
    13751 if( aggrrow->nnz == 0 )
    13752 return SCIP_OKAY;
    13753
    13754 /* Each cut generation method writes to local variables and only succeeds if the generated cut has efficacy strictly
    13755 * better than the input efficacy. We copy results only on success.
    13756 */
    13757
    13758 /* try FlowCover */
    13759 if( methods & SCIP_CUTGENMETHOD_FLOWCOVER )
    13760 {
    13761 efficacy = result->cutefficacy;
    13762 SCIP_CALL( SCIPcalcFlowCover(scip, sol, params->postprocess, params->boundswitch, params->allowlocal, aggrrow,
    13763 result->cutcoefs, &cutrhs, result->cutinds, &cutnnz, &efficacy, &cutrank, &cutislocal, &success) );
    13764
    13765 if( success )
    13766 {
    13768 result->cutefficacy = efficacy;
    13769 result->cutrhs = cutrhs;
    13770 result->cutnnz = cutnnz;
    13771 result->cutrank = cutrank;
    13772 result->cutislocal = cutislocal;
    13773 result->success = TRUE;
    13774 }
    13775 }
    13776
    13777 /* try KnapsackCover */
    13778 if( methods & SCIP_CUTGENMETHOD_KNAPSACKCOVER )
    13779 {
    13780 efficacy = result->cutefficacy;
    13781 SCIP_CALL( SCIPcalcKnapsackCover(scip, sol, params->allowlocal, aggrrow,
    13782 result->cutcoefs, &cutrhs, result->cutinds, &cutnnz, &efficacy, &cutrank, &cutislocal, &success) );
    13783
    13784 if( success )
    13785 {
    13787 result->cutefficacy = efficacy;
    13788 result->cutrhs = cutrhs;
    13789 result->cutnnz = cutnnz;
    13790 result->cutrank = cutrank;
    13791 result->cutislocal = cutislocal;
    13792 result->success = TRUE;
    13793 }
    13794 }
    13795
    13796 /* try CMIR */
    13797 if( methods & SCIP_CUTGENMETHOD_CMIR )
    13798 {
    13799 efficacy = result->cutefficacy;
    13801 params->vartypeusevbds, params->allowlocal, params->maxtestdelta, params->boundsfortrans,
    13802 params->boundtypesfortrans, params->minfrac, params->maxfrac, aggrrow,
    13803 result->cutcoefs, &cutrhs, result->cutinds, &cutnnz, &efficacy, &cutrank, &cutislocal, &success) );
    13804
    13805 if( success )
    13806 {
    13808 result->cutefficacy = efficacy;
    13809 result->cutrhs = cutrhs;
    13810 result->cutnnz = cutnnz;
    13811 result->cutrank = cutrank;
    13812 result->cutislocal = cutislocal;
    13813 result->success = TRUE;
    13814 }
    13815 }
    13816
    13817 return SCIP_OKAY;
    13818}
    SCIP_CERTIFICATE * SCIPgetCertificate(SCIP *scip)
    methods for certificate output
    SCIP_VAR * h
    Definition: circlepacking.c:68
    SCIP_Real * r
    Definition: circlepacking.c:59
    SCIP_VAR ** x
    Definition: circlepacking.c:63
    #define MAXDNOM
    Definition: cons_linear.c:166
    static SCIP_Real computeMIREfficacy(SCIP *scip, SCIP_Real *RESTRICT coefs, SCIP_Real *RESTRICT solvals, SCIP_Real rhs, SCIP_Real contactivity, SCIP_Real contsqrnorm, SCIP_Real delta, int nvars, SCIP_Real minfrac, SCIP_Real maxfrac)
    Definition: cuts.c:8268
    static SCIP_RETCODE cutsRoundMIRSafely(SCIP *scip, SCIP_Real *RESTRICT cutcoefs, SCIP_Real *RESTRICT cutrhs, int *RESTRICT cutinds, int *RESTRICT nnz, int *RESTRICT varsign, int *RESTRICT boundtype, SCIP_INTERVAL f0)
    Definition: cuts.c:5883
    struct MIR_Data MIR_DATA
    static SCIP_RETCODE findBestUb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestub, int *bestubtype)
    Definition: cuts.c:4572
    static SCIP_RETCODE findBestLbSafely(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestlb, SCIP_Real *simplebound, int *bestlbtype)
    Definition: cuts.c:4175
    static SCIP_RETCODE varVecAddScaledRowCoefsSafely(SCIP *scip, int *inds, SCIP_Real *vals, int *nnz, SCIP_ROW *row, SCIP_Real scale, SCIP_Real *rhschange, SCIP_Bool *success)
    Definition: cuts.c:363
    static void performBoundSubstitutionSimple(SCIP *scip, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
    Definition: cuts.c:5272
    static void prepareLiftingData(SCIP *scip, SCIP_Real *cutcoefs, int *cutinds, QUAD(SCIP_Real cutrhs), int *coverpos, int coversize, QUAD(SCIP_Real coverweight), SCIP_Real *covervals, int *coverstatus, QUAD(SCIP_Real *abar), int *cplussize)
    Definition: cuts.c:12086
    static SCIP_RETCODE postprocessCutSafely(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, SCIP_Real *cutrhs, SCIP_Bool *success)
    Definition: cuts.c:3899
    static SCIP_RETCODE cutsTransformKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool allowlocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *localbdsused, SCIP_Bool *success)
    Definition: cuts.c:11801
    static SCIP_Bool removeZerosSafely(SCIP *scip, SCIP_Real minval, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz)
    Definition: cuts.c:738
    static SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
    Definition: cuts.c:1018
    static SCIP_Real calcEfficacyDenseStorageQuad(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
    Definition: cuts.c:661
    #define DEFAULT_CUTGEN_VARTYPEUSEVBDS
    Definition: cuts.c:73
    static SCIP_Bool removeZerosQuad(SCIP *scip, SCIP_Real minval, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz)
    Definition: cuts.c:833
    static SCIP_RETCODE cutsRoundStrongCG(SCIP *scip, MIR_DATA *data, int *varsign, int *boundtype, QUAD(SCIP_Real f0), SCIP_Real k)
    Definition: cuts.c:12916
    static SCIP_RETCODE findBestUbSafely(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestub, SCIP_Real *simplebound, int *bestubtype)
    Definition: cuts.c:4244
    static SCIP_RETCODE cutsRoundMIR(SCIP *scip, MIR_DATA *data, int *RESTRICT varsign, int *RESTRICT boundtype, QUAD(SCIP_Real f0))
    Definition: cuts.c:6721
    static SCIP_RETCODE cutsSubstituteStrongCG(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, QUAD(SCIP_Real f0), SCIP_Real k)
    Definition: cuts.c:13156
    static SCIP_RETCODE computeLiftingData(SCIP *scip, SNF_RELAXATION *snf, int *transvarflowcoverstatus, SCIP_Real lambda, LIFTINGDATA *liftingdata, SCIP_Bool *valid)
    Definition: cuts.c:11232
    static void doMIRBoundSubstitution(SCIP *scip, MIR_DATA *data, int varsign, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
    Definition: cuts.c:5020
    static SCIP_RETCODE getClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *rowcoefs, int8_t *binvarused, SCIP_Real bestsub, SCIP_Real rowcoef, SCIP_Real *closestvlb, int *closestvlbidx)
    Definition: cuts.c:9201
    static SCIP_RETCODE getFlowCover(SCIP *scip, SNF_RELAXATION *snf, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, SCIP_Real *lambda, SCIP_Bool *found)
    Definition: cuts.c:10844
    static SCIP_RETCODE getClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *rowcoefs, int8_t *binvarused, SCIP_Real bestslb, SCIP_Real rowcoef, SCIP_Real *closestvub, int *closestvubidx)
    Definition: cuts.c:9330
    static SCIP_Real evaluateLiftingFunctionKnapsack(SCIP *scip, QUAD(SCIP_Real x), QUAD(SCIP_Real abar), SCIP_Real *covervals, int coversize, int cplussize, SCIP_Real *scale)
    Definition: cuts.c:12202
    static SCIP_Bool chgCoeffWithBound(SCIP *scip, SCIP_VAR *var, SCIP_Real oldcoeff, SCIP_Real newcoeff, SCIP_Bool cutislocal, QUAD(SCIP_Real *cutrhs))
    Definition: cuts.c:1063
    static SCIP_Bool chgQuadCoeffWithBound(SCIP *scip, SCIP_VAR *var, QUAD(SCIP_Real oldcoeff), SCIP_Real newcoeff, SCIP_Bool cutislocal, QUAD(SCIP_Real *cutrhs))
    Definition: cuts.c:1108
    #define MAXBOUND
    Definition: cuts.c:9153
    static SCIP_Real scaleValSafely(SCIP *scip, SCIP_Real val, SCIP_Real scale, SCIP_Bool cutislocal, SCIP_VAR *var, SCIP_Real *rhschange, SCIP_Bool *success)
    Definition: cuts.c:1596
    static SCIP_RETCODE findBestLb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestlb, int *bestlbtype)
    Definition: cuts.c:4509
    static SCIP_RETCODE cutsTransformMIR(SCIP *scip, MIR_DATA *data, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
    Definition: cuts.c:5554
    static SCIP_RETCODE constructSNFRelaxation(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_Real *rowcoefs, QUAD(SCIP_Real rowrhs), int *rowinds, int nnz, SNF_RELAXATION *snf, SCIP_Bool *success, SCIP_Bool *localbdsused)
    Definition: cuts.c:9638
    static SCIP_RETCODE postprocessCutQuad(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, QUAD(SCIP_Real *cutrhs), SCIP_Bool *success)
    Definition: cuts.c:3833
    #define DEFAULT_CUTGEN_MAXFRAC
    Definition: cuts.c:75
    static SCIP_RETCODE calcMIRSafely(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
    Definition: cuts.c:7648
    static int varSection(MIR_DATA *data, int probindex)
    Definition: cuts.c:4135
    static void performBoundSubstitution(SCIP *scip, int *cutinds, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *nnz, int varsign, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
    Definition: cuts.c:5191
    static void destroyLiftingData(SCIP *scip, LIFTINGDATA *liftingdata)
    Definition: cuts.c:11362
    static void performBoundSubstitutionSimpleSafely(SCIP *scip, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
    Definition: cuts.c:5157
    static SCIP_RETCODE findMIRBestLb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, MIR_DATA *data, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestlb, SCIP_Real *simplebound, int *bestlbtype)
    Definition: cuts.c:4637
    static SCIP_RETCODE varVecAddScaledRowCoefsQuad(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
    Definition: cuts.c:251
    static SCIP_Real calcEfficacyNormQuad(SCIP *scip, SCIP_Real *vals, int *inds, int nnz)
    Definition: cuts.c:528
    #define NSECTIONS
    Definition: cuts.c:4099
    static SCIP_RETCODE cutTightenCoefs(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz, SCIP_Bool *redundant)
    Definition: cuts.c:2114
    static SCIP_RETCODE determineBestBounds(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, MIR_DATA *data, SCIP_Real boundswitch, int usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real *bestlb, SCIP_Real *bestub, int *bestlbtype, int *bestubtype, SCIP_BOUNDTYPE *selectedbound, SCIP_Bool *freevariable)
    Definition: cuts.c:4814
    #define DEFAULT_CUTGEN_BOUNDSWITCH
    Definition: cuts.c:71
    #define NONZERO(x)
    Definition: cuts.c:200
    static SCIP_Bool removeZeros(SCIP *scip, SCIP_Real minval, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz)
    Definition: cuts.c:926
    #define DEFAULT_CUTGEN_MAXTESTDELTA
    Definition: cuts.c:76
    struct LiftingData LIFTINGDATA
    static SCIP_RETCODE SCIPsolveKnapsackApproximatelyLT(SCIP *scip, int nitems, SCIP_Real *weights, SCIP_Real *profits, SCIP_Real capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
    Definition: cuts.c:10233
    static SCIP_Real calcEfficacyDenseStorage(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
    Definition: cuts.c:590
    static SCIP_RETCODE determineBoundForSNF(SCIP *scip, SCIP_SOL *sol, SCIP_VAR **vars, SCIP_Real *rowcoefs, int *rowinds, int varposinrow, int8_t *binvarused, SCIP_Bool allowlocal, SCIP_Real boundswitch, SCIP_Real *bestlb, SCIP_Real *bestub, SCIP_Real *bestslb, SCIP_Real *bestsub, int *bestlbtype, int *bestubtype, int *bestslbtype, int *bestsubtype, SCIP_BOUNDTYPE *selectedbounds, SCIP_Bool *freevariable)
    Definition: cuts.c:9458
    static SCIP_RETCODE postprocessCut(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, SCIP_Real *cutrhs, SCIP_Bool *success)
    Definition: cuts.c:3764
    static void destroySNFRelaxation(SCIP *scip, SNF_RELAXATION *snf)
    Definition: cuts.c:10213
    static SCIP_RETCODE allocSNFRelaxation(SCIP *scip, SNF_RELAXATION *snf, int nvars)
    Definition: cuts.c:10192
    static SCIP_RETCODE addOneRowSafely(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *rowtoolong, SCIP_Bool *rowused, SCIP_Bool *success, SCIP_Bool *lhsused)
    Definition: cuts.c:3382
    #define DEFAULT_CUTGEN_MINFRAC
    Definition: cuts.c:74
    static SCIP_Bool chgCoeffWithBoundSafely(SCIP *scip, SCIP_VAR *var, SCIP_Real oldcoeff, SCIP_Real newcoeff, SCIP_Bool cutislocal, SCIP_Real *cutrhs)
    Definition: cuts.c:1153
    static SCIP_RETCODE cutsSubstituteMIRSafely(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *nnz, SCIP_INTERVAL f0)
    Definition: cuts.c:6964
    static SCIP_Real calcEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
    Definition: cuts.c:463
    static void buildFlowCover(SCIP *scip, int *coefs, SCIP_Real *vubcoefs, SCIP_Real rhs, int *solitems, int *nonsolitems, int nsolitems, int nnonsolitems, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, QUAD(SCIP_Real *flowcoverweight), SCIP_Real *lambda)
    Definition: cuts.c:10328
    #define DEFAULT_CUTGEN_ALLOWLOCAL
    Definition: cuts.c:72
    #define MAXCMIRSCALE
    Definition: cuts.c:4090
    static SCIP_RETCODE generateLiftedFlowCoverCut(SCIP *scip, SNF_RELAXATION *snf, SCIP_AGGRROW *aggrrow, int *flowcoverstatus, SCIP_Real lambda, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *nnz, SCIP_Bool *success)
    Definition: cuts.c:11375
    static SCIP_RETCODE cutsTransformStrongCG(SCIP *scip, MIR_DATA *data, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool allowlocal, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
    Definition: cuts.c:12629
    static SCIP_RETCODE cutTightenCoefsSafely(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Bool *redundant)
    Definition: cuts.c:1669
    static void getAlphaAndBeta(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real vubcoef, int *alpha, SCIP_Real *beta)
    Definition: cuts.c:11195
    static SCIP_RETCODE cutsSubstituteMIR(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, QUAD(SCIP_Real f0))
    Definition: cuts.c:7488
    #define MAXABSVBCOEF
    Definition: cuts.c:9152
    static SCIP_RETCODE addOneRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *rowtoolong)
    Definition: cuts.c:3268
    static SCIP_RETCODE determineBestBoundsSafely(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real boundswitch, int usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real *bestlb, SCIP_Real *bestub, int *bestlbtype, int *bestubtype, SCIP_BOUNDTYPE *selectedbound, SCIP_Bool *freevariable)
    Definition: cuts.c:4310
    static SCIP_RETCODE varVecAddScaledRowCoefsQuadScale(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, QUAD(SCIP_Real scale))
    Definition: cuts.c:298
    static void performBoundSubstitutionSafely(SCIP *scip, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int varsign, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
    Definition: cuts.c:5110
    static SCIP_RETCODE cutsTransformMIRSafely(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
    Definition: cuts.c:5331
    struct SNF_Relaxation SNF_RELAXATION
    static SCIP_RETCODE cutTightenCoefsQuad(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz, SCIP_Bool *redundant)
    Definition: cuts.c:1218
    static SCIP_Real evaluateLiftingFunction(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real x)
    Definition: cuts.c:11111
    static SCIP_RETCODE varVecAddScaledRowCoefs(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
    Definition: cuts.c:206
    #define DEFAULT_CUTGEN_POSTPROCESS
    Definition: cuts.c:70
    static SCIP_RETCODE findMIRBestUb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, MIR_DATA *data, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestub, SCIP_Real *simplebound, int *bestubtype)
    Definition: cuts.c:4726
    static SCIP_Bool computeInitialKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, int *cutinds, SCIP_Real cutrhs, int cutnnz, int *varsign, int *coverstatus, int *coverpos, SCIP_Real *covervals, int *coversize, QUAD(SCIP_Real *coverweight))
    Definition: cuts.c:11995
    methods for the aggregation rows
    defines macros for basic operations in double-double arithmetic giving roughly twice the precision of...
    #define QUAD_LO(x)
    Definition: dbldblarith.h:46
    #define QUAD_EPSILON
    Definition: dbldblarith.h:42
    #define QUAD_ARRAY_STORE(a, idx, x)
    Definition: dbldblarith.h:55
    #define SCIPquadprecProdDD(r, a, b)
    Definition: dbldblarith.h:58
    #define SCIPquadprecProdQD(r, a, b)
    Definition: dbldblarith.h:63
    #define QUAD_SCALE(x, a)
    Definition: dbldblarith.h:50
    #define SCIPquadprecProdQQ(r, a, b)
    Definition: dbldblarith.h:66
    #define SCIPquadprecSumQD(r, a, b)
    Definition: dbldblarith.h:62
    #define QUAD_ARRAY_SIZE(size)
    Definition: dbldblarith.h:53
    #define SCIPquadprecEpsFloorQ(r, a, eps)
    Definition: dbldblarith.h:75
    #define QUAD_ASSIGN(a, constant)
    Definition: dbldblarith.h:51
    #define SCIPquadprecFloorQ(r, a)
    Definition: dbldblarith.h:73
    #define QUAD(x)
    Definition: dbldblarith.h:47
    #define SCIPquadprecEpsCeilQ(r, a, eps)
    Definition: dbldblarith.h:76
    #define SCIPquadprecSumDD(r, a, b)
    Definition: dbldblarith.h:60
    #define SCIPquadprecSumQQ(r, a, b)
    Definition: dbldblarith.h:67
    #define SCIPquadprecDivDQ(r, a, b)
    Definition: dbldblarith.h:64
    #define QUAD_HI(x)
    Definition: dbldblarith.h:45
    #define QUAD_ASSIGN_Q(a, b)
    Definition: dbldblarith.h:52
    #define QUAD_ARRAY_LOAD(r, a, idx)
    Definition: dbldblarith.h:54
    #define SCIPquadprecDivDD(r, a, b)
    Definition: dbldblarith.h:61
    #define QUAD_TO_DBL(x)
    Definition: dbldblarith.h:49
    #define NULL
    Definition: def.h:257
    #define COPYSIGN
    Definition: def.h:248
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_UNUSED(x)
    Definition: def.h:418
    #define EPSISINT(x, eps)
    Definition: def.h:204
    #define SCIP_REAL_MAX
    Definition: def.h:167
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:100
    #define MIN(x, y)
    Definition: def.h:233
    #define SCIP_Real
    Definition: def.h:165
    #define ABS(x)
    Definition: def.h:225
    #define EPSFRAC(x, eps)
    Definition: def.h:203
    #define SQR(x)
    Definition: def.h:208
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:343
    #define RESTRICT
    Definition: def.h:269
    #define SCIPABORT()
    Definition: def.h:336
    #define SCIP_REAL_MIN
    Definition: def.h:168
    #define EPSFLOOR(x, eps)
    Definition: def.h:200
    #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 SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
    int SCIPgetNIntVars(SCIP *scip)
    Definition: scip_prob.c:2340
    int SCIPgetNContVars(SCIP *scip)
    Definition: scip_prob.c:2569
    int SCIPgetNBinImplVars(SCIP *scip)
    Definition: scip_prob.c:2432
    SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
    Definition: scip_prob.c:2115
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    int SCIPgetNIntImplVars(SCIP *scip)
    Definition: scip_prob.c:2477
    int SCIPgetNContImplVars(SCIP *scip)
    Definition: scip_prob.c:2522
    int SCIPgetNBinVars(SCIP *scip)
    Definition: scip_prob.c:2293
    #define SCIPdebugMsgPrint
    Definition: scip_message.h:79
    SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
    Definition: scip_message.c:88
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_Bool SCIPrealIsExactlyIntegral(SCIP_Real val)
    Definition: misc.c:9604
    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 SCIPaddCertificateMirInfo(SCIP *scip)
    SCIP_Bool SCIPisCertified(SCIP *scip)
    SCIP_RETCODE SCIPaddCertificateAggrInfo(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW **aggrrows, SCIP_Real *weights, int naggrrows, SCIP_ROW **negslackrows, SCIP_Real *negslackweights, int nnegslackrows)
    void SCIPaggrRowCancelVarWithBound(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_VAR *var, int pos, SCIP_Bool *valid)
    Definition: cuts.c:3019
    SCIP_Bool SCIPaggrRowHasRowBeenAdded(SCIP_AGGRROW *aggrrow, SCIP_ROW *row)
    Definition: cuts.c:4016
    SCIP_RETCODE SCIPcutGenerationHeuristicCMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, int vartypeusevbds, SCIP_Bool allowlocal, int maxtestdelta, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
    Definition: cuts.c:8350
    SCIP_RETCODE SCIPcalcMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, int vartypeusevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
    Definition: cuts.c:7934
    int SCIPaggrRowGetRank(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4059
    SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
    Definition: cuts.c:2477
    void SCIPaggrRowClearSafely(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3207
    SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2679
    SCIP_RETCODE SCIPaggrRowAddRowSafely(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype, SCIP_Bool *success)
    Definition: cuts.c:2898
    SCIP_RETCODE SCIPcalcKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
    Definition: cuts.c:12302
    SCIP_RETCODE SCIPcreateCutGenResult(SCIP *scip, SCIP_CUTGENRESULT **result)
    Definition: cuts.c:13665
    void SCIPaggrRowClear(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3229
    SCIP_RETCODE SCIPaggrRowCopy(SCIP *scip, SCIP_AGGRROW **aggrrow, SCIP_AGGRROW *source)
    Definition: cuts.c:2769
    SCIP_Bool SCIPaggrRowIsLocal(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4069
    SCIP_Real SCIPaggrRowGetRhs(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4079
    SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
    Definition: scip_cut.c:135
    int SCIPaggrRowGetNRows(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3984
    SCIP_RETCODE SCIPaggrRowAddCustomCons(SCIP *scip, SCIP_AGGRROW *aggrrow, int *inds, SCIP_Real *vals, int len, SCIP_Real rhs, SCIP_Real weight, int rank, SCIP_Bool local)
    Definition: cuts.c:3154
    SCIP_RETCODE SCIPcalcStrongCG(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, int vartypeusevbds, SCIP_Bool allowlocal, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
    Definition: cuts.c:13313
    void SCIPfreeCutGenResult(SCIP *scip, SCIP_CUTGENRESULT **result)
    Definition: cuts.c:13685
    void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2711
    void SCIPinitCutGenParams(SCIP_CUTGENPARAMS *params)
    Definition: cuts.c:13643
    SCIP_RETCODE SCIPcalcBestCut(SCIP *scip, SCIP_SOL *sol, SCIP_AGGRROW *aggrrow, SCIP_CUTGENMETHOD methods, SCIP_CUTGENPARAMS *params, SCIP_CUTGENRESULT *result)
    Definition: cuts.c:13716
    int * SCIPaggrRowGetInds(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4039
    void SCIPaggrRowPrint(SCIP *scip, SCIP_AGGRROW *aggrrow, FILE *file)
    Definition: cuts.c:2732
    void SCIPaggrRowRemoveZeros(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Bool useglbbounds, SCIP_Bool *valid)
    Definition: cuts.c:3960
    SCIP_Real * SCIPaggrRowGetRowWeights(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4005
    int SCIPaggrRowGetNNz(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4049
    SCIP_RETCODE SCIPaggrRowAddRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype)
    Definition: cuts.c:2815
    int * SCIPaggrRowGetRowInds(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3994
    SCIP_RETCODE SCIPaggrRowSumRows(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real *weights, int *rowinds, int nrowinds, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *valid)
    Definition: cuts.c:3534
    int SCIPgetNCuts(SCIP *scip)
    Definition: scip_cut.c:762
    SCIP_RETCODE SCIPaggrRowAddObjectiveFunction(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real rhs, SCIP_Real scale)
    Definition: cuts.c:3078
    SCIP_RETCODE SCIPcalcFlowCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
    Definition: cuts.c:11656
    SCIP_Real SCIPaggrRowCalcEfficacyNorm(SCIP *scip, SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3254
    SCIP_Bool SCIPisExact(SCIP *scip)
    Definition: scip_exact.c:193
    void SCIPintervalSetRoundingModeUpwards(void)
    void SCIPintervalSetRoundingModeDownwards(void)
    SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
    void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
    SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
    void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
    void SCIPintervalSubScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
    int SCIP_ROUNDMODE
    Definition: intervalarith.h:65
    void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
    void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
    void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
    void SCIPintervalMul(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
    void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
    void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
    SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
    void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
    void SCIPintervalSetRational(SCIP_INTERVAL *resultant, SCIP_RATIONAL *value)
    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
    #define SCIPfreeCleanBufferArray(scip, ptr)
    Definition: scip_mem.h:146
    #define SCIPfreeBuffer(scip, ptr)
    Definition: scip_mem.h:134
    #define SCIPallocCleanBufferArray(scip, ptr, num)
    Definition: scip_mem.h:142
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    BMS_BUFMEM * SCIPbuffer(SCIP *scip)
    Definition: scip_mem.c:72
    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 SCIPallocBuffer(scip, ptr)
    Definition: scip_mem.h:122
    #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 SCIPfreeBufferArrayNull(scip, ptr)
    Definition: scip_mem.h:137
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    #define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
    Definition: scip_mem.h:105
    SCIP_Bool SCIPrationalIsLTReal(SCIP_RATIONAL *rat, SCIP_Real real)
    Definition: rational.cpp:1577
    void SCIPrationalMult(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
    Definition: rational.cpp:1067
    void SCIPrationalInvert(SCIP_RATIONAL *res, SCIP_RATIONAL *op)
    Definition: rational.cpp:1324
    SCIP_Real SCIPrationalGetReal(SCIP_RATIONAL *rational)
    Definition: rational.cpp:2084
    void SCIPrationalDiv(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
    Definition: rational.cpp:1133
    void SCIPrationalSetReal(SCIP_RATIONAL *res, SCIP_Real real)
    Definition: rational.cpp:604
    void SCIPrationalFreeBuffer(BMS_BUFMEM *bufmem, SCIP_RATIONAL **rational)
    Definition: rational.cpp:474
    void SCIPrationalDiff(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
    Definition: rational.cpp:984
    SCIP_Bool SCIPrationalIsPositive(SCIP_RATIONAL *rational)
    Definition: rational.cpp:1641
    SCIP_RETCODE SCIPrationalCreateBuffer(BMS_BUFMEM *bufmem, SCIP_RATIONAL **rational)
    Definition: rational.cpp:124
    SCIP_Bool SCIPrationalIsZero(SCIP_RATIONAL *rational)
    Definition: rational.cpp:1625
    void SCIPrationalSetRational(SCIP_RATIONAL *res, SCIP_RATIONAL *src)
    Definition: rational.cpp:570
    SCIP_Bool SCIPrationalIsGEReal(SCIP_RATIONAL *rat, SCIP_Real real)
    Definition: rational.cpp:1607
    SCIP_Bool SCIPrationalIsNegative(SCIP_RATIONAL *rational)
    Definition: rational.cpp:1651
    void SCIPrationalDiffReal(SCIP_RATIONAL *res, SCIP_RATIONAL *rat, SCIP_Real real)
    Definition: rational.cpp:1010
    SCIP_Real SCIPrationalRoundReal(SCIP_RATIONAL *rational, SCIP_ROUNDMODE_RAT roundmode)
    Definition: rational.cpp:2109
    SCIP_Bool SCIPrationalIsEQReal(SCIP_RATIONAL *rat, SCIP_Real real)
    Definition: rational.cpp:1438
    void SCIPrationalMultReal(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_Real op2)
    Definition: rational.cpp:1098
    SCIP_Bool SCIPrationalIsLE(SCIP_RATIONAL *rat1, SCIP_RATIONAL *rat2)
    Definition: rational.cpp:1522
    void SCIPrationalAddReal(SCIP_RATIONAL *res, SCIP_RATIONAL *rat, SCIP_Real real)
    Definition: rational.cpp:962
    void SCIPrationalAddProdReal(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_Real op2)
    Definition: rational.cpp:1211
    SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
    Definition: lp.c:17686
    SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
    Definition: lp.c:17805
    SCIP_Real SCIPgetRowMinActivity(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1903
    SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
    Definition: lp.c:17696
    SCIP_Real SCIPgetRowMaxActivity(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1920
    int SCIProwGetLPPos(SCIP_ROW *row)
    Definition: lp.c:17895
    SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
    Definition: lp.c:17795
    SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
    Definition: scip_lp.c:2176
    SCIP_RETCODE SCIPcaptureRow(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1486
    SCIP_ROWEXACT * SCIProwGetRowExact(SCIP_ROW *row)
    Definition: lp.c:17959
    SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
    Definition: lp.c:17734
    SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
    Definition: scip_lp.c:2108
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    SCIP_Longint SCIPgetNLPs(SCIP *scip)
    SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_Real SCIPfrac(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPgetHugeValue(SCIP *scip)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasGT(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 SCIPisSumLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPvarGetNVlbs(SCIP_VAR *var)
    Definition: var.c:24514
    SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
    Definition: var.c:24536
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23674
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23510
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23530
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23485
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    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
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
    Definition: var.c:24546
    int SCIPvarGetNVubs(SCIP_VAR *var)
    Definition: var.c:24556
    SCIP_RATIONAL * SCIPvarGetUbLocalExact(SCIP_VAR *var)
    Definition: var.c:24310
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23522
    SCIP_RETCODE SCIPgetVarClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvlb, int *closestvlbidx)
    Definition: scip_var.c:8569
    SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
    Definition: var.c:24696
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_RATIONAL * SCIPvarGetLbGlobalExact(SCIP_VAR *var)
    Definition: var.c:24162
    SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
    Definition: var.c:24526
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    SCIP_RATIONAL * SCIPvarGetLbLocalExact(SCIP_VAR *var)
    Definition: var.c:24276
    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
    SCIP_RATIONAL * SCIPvarGetUbGlobalExact(SCIP_VAR *var)
    Definition: var.c:24184
    void SCIPselectWeightedDownRealRealInt(SCIP_Real *realarray1, SCIP_Real *realarray2, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
    void SCIPsortDownRealRealInt(SCIP_Real *realarray1, SCIP_Real *realarray2, int *intarray, int len)
    SCIP_Bool SCIPsortedvecFindDownReal(SCIP_Real *realarray, SCIP_Real val, int len, int *pos)
    void SCIPsortDownReal(SCIP_Real *realarray, int len)
    void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
    void SCIPsortDownInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
    void SCIPsortDownInt(int *intarray, int len)
    void SCIPsortInt(int *intarray, int len)
    interval arithmetics for provable bounds
    static SCIP_Bool isIntegralScalar(SCIP_Real val, SCIP_Real scalar, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Real *intval)
    Definition: lp.c:5099
    internal methods for LP management
    SCIP_Bool SCIProwExactHasFpRelax(SCIP_ROWEXACT *row)
    Definition: lpexact.c:5089
    SCIP_ROW * SCIProwExactGetRowRhs(SCIP_ROWEXACT *row)
    Definition: lpexact.c:5079
    memory allocation routines
    #define BMScopyMemoryArray(ptr, source, num)
    Definition: memory.h:134
    #define BMSmoveMemoryArray(ptr, source, num)
    Definition: memory.h:138
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
    Definition: message.c:618
    internal miscellaneous methods
    #define MAXSCALE
    #define MAXDELTA
    #define MINDELTA
    public methods for LP management
    public methods for LP management
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    #define SCIPdebugMessage
    Definition: pub_message.h:96
    #define SCIPdebugPrintf
    Definition: pub_message.h:99
    public data structures and miscellaneous methods
    methods for selecting k-medians
    methods for sorting joint arrays of various types
    public methods for problem variables
    wrapper for rational number arithmetic
    public methods for certified solving
    public methods for cuts and aggregation rows
    public methods for exact solving
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for numerical tolerances
    public methods for global and local (sub)problems
    public methods for solutions
    public methods for querying solving statistics
    public methods for SCIP variables
    SCIP_Real * M
    Definition: cuts.c:9160
    SCIP_Real lambda
    Definition: cuts.c:9171
    int r
    Definition: cuts.c:9167
    int t
    Definition: cuts.c:9168
    SCIP_Real * m
    Definition: cuts.c:9161
    SCIP_Real d2
    Definition: cuts.c:9170
    SCIP_Real mp
    Definition: cuts.c:9172
    SCIP_Real ml
    Definition: cuts.c:9173
    SCIP_Real d1
    Definition: cuts.c:9169
    SCIP_VAR ** vars
    Definition: cuts.c:4114
    int usevbds[NSECTIONS]
    Definition: cuts.c:4111
    SCIP_Real QUAD(cutrhs)
    SCIP_Bool isenfint[NSECTIONS]
    Definition: cuts.c:4107
    int * cutinds
    Definition: cuts.c:4126
    int nvars
    Definition: cuts.c:4115
    int nbinimplvars
    Definition: cuts.c:4118
    int nintvars
    Definition: cuts.c:4117
    SCIP_Bool isimplint[NSECTIONS]
    Definition: cuts.c:4108
    SCIP_Real * cutcoefs
    Definition: cuts.c:4123
    int nintimplvars
    Definition: cuts.c:4119
    int ncutinds
    Definition: cuts.c:4127
    int totalnnz
    Definition: cuts.c:4103
    int ncontvars
    Definition: cuts.c:4121
    int ncontimplvars
    Definition: cuts.c:4120
    int nbinvars
    Definition: cuts.c:4116
    int * secindices[NSECTIONS]
    Definition: cuts.c:4104
    int secnnz[NSECTIONS]
    Definition: cuts.c:4105
    SCIP_Real * vals
    Definition: struct_cuts.h:44
    SCIP_Real * rowweights
    Definition: struct_cuts.h:48
    int * rowsinds
    Definition: struct_cuts.h:46
    SCIP_Bool local
    Definition: struct_cuts.h:54
    int * slacksign
    Definition: struct_cuts.h:47
    SCIP_Longint nmirinfos
    SCIP_MIRINFO ** mirinfo
    SCIP_Longint naggrinfos
    SCIP_AGGREGATIONINFO ** aggrinfo
    SCIP_VAR * var
    Definition: struct_lp.h:162
    int var_probindex
    Definition: struct_lp.h:180
    SCIP_Real boundswitch
    Definition: struct_cuts.h:61
    SCIP_Bool postprocess
    Definition: struct_cuts.h:68
    SCIP_Real minfrac
    Definition: struct_cuts.h:62
    SCIP_BOUNDTYPE * boundtypesfortrans
    Definition: struct_cuts.h:67
    SCIP_Real maxfrac
    Definition: struct_cuts.h:63
    SCIP_Bool allowlocal
    Definition: struct_cuts.h:69
    SCIP_Bool cutislocal
    Definition: struct_cuts.h:82
    SCIP_Real cutrhs
    Definition: struct_cuts.h:79
    SCIP_Real cutefficacy
    Definition: struct_cuts.h:78
    SCIP_CUTGENMETHOD winningmethod
    Definition: struct_cuts.h:77
    SCIP_Bool success
    Definition: struct_cuts.h:83
    SCIP_Real * cutcoefs
    Definition: struct_cuts.h:75
    SCIP_Real sup
    Definition: intervalarith.h:57
    SCIP_Real inf
    Definition: intervalarith.h:56
    SCIP_Real * slackscale
    SCIP_Real * slackcoefficients
    SCIP_RATIONAL * frac
    SCIP_ROW ** slackrows
    SCIP_Real * slackweight
    SCIP_Bool * upperused
    SCIP_Real * splitcoefficients
    SCIP_RATIONAL * rhs
    SCIP_Real * slackusedcoef
    SCIP_Real unroundedrhs
    SCIP_Bool * localbdused
    SCIP_Bool * slackroundeddown
    SCIP_INTERVAL * valsinterval
    int rank
    Definition: struct_lp.h:253
    SCIP_Real rhs
    Definition: struct_lp.h:208
    int lppos
    Definition: struct_lp.h:243
    char * name
    Definition: struct_lp.h:229
    SCIP_Real * vals
    Definition: struct_lp.h:232
    unsigned int local
    Definition: struct_lp.h:264
    SCIP_Real lhs
    Definition: struct_lp.h:207
    SCIP_COL ** cols
    Definition: struct_lp.h:230
    unsigned int integral
    Definition: struct_lp.h:263
    SCIP_Real constant
    Definition: struct_lp.h:206
    int * cols_index
    Definition: struct_lp.h:231
    int len
    Definition: struct_lp.h:239
    SCIP_Real * transbinvarsolvals
    Definition: cuts.c:9181
    int * transvarcoefs
    Definition: cuts.c:9180
    SCIP_Real * transcontvarsolvals
    Definition: cuts.c:9182
    SCIP_Real * aggrcoefsbin
    Definition: cuts.c:9188
    int * origcontvars
    Definition: cuts.c:9187
    SCIP_Real transrhs
    Definition: cuts.c:9185
    int * origbinvars
    Definition: cuts.c:9186
    SCIP_Real * aggrconstants
    Definition: cuts.c:9192
    SCIP_Real * aggrcoefscont
    Definition: cuts.c:9190
    int ntransvars
    Definition: cuts.c:9184
    SCIP_Real * transvarvubcoefs
    Definition: cuts.c:9183
    data structures for certificate output
    data structures for LP management
    data structures for exact LP management
    SCIP main data structure.
    datastructures for global SCIP settings
    type definitions for certificate output
    #define SCIP_CUTGENMETHOD_KNAPSACKCOVER
    Definition: type_cuts.h:44
    #define SCIP_CUTGENMETHOD_NONE
    Definition: type_cuts.h:42
    #define SCIP_CUTGENMETHOD_CMIR
    Definition: type_cuts.h:45
    uint32_t SCIP_CUTGENMETHOD
    Definition: type_cuts.h:39
    #define SCIP_CUTGENMETHOD_FLOWCOVER
    Definition: type_cuts.h:43
    @ SCIP_BOUNDTYPE_UPPER
    Definition: type_lp.h:58
    @ SCIP_BOUNDTYPE_LOWER
    Definition: type_lp.h:57
    enum SCIP_BoundType SCIP_BOUNDTYPE
    Definition: type_lp.h:60
    @ SCIP_BASESTAT_UPPER
    Definition: type_lpi.h:93
    @ SCIP_BASESTAT_LOWER
    Definition: type_lpi.h:91
    enum SCIP_BaseStat SCIP_BASESTAT
    Definition: type_lpi.h:96
    @ SCIP_R_ROUND_UPWARDS
    Definition: type_rational.h:58
    @ SCIP_R_ROUND_DOWNWARDS
    Definition: type_rational.h:57
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    @ SCIP_ERROR
    Definition: type_retcode.h:43
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_VARTYPE_INTEGER
    Definition: type_var.h:65
    @ SCIP_VARTYPE_CONTINUOUS
    Definition: type_var.h:71
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64