Scippy

    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-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file 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/* =========================================== general static functions =========================================== */
    68#ifdef SCIP_DEBUG
    69static
    70void printCutQuad(
    71 SCIP* scip, /**< SCIP data structure */
    72 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    73 SCIP_Real* cutcoefs, /**< non-zero coefficients of cut */
    74 QUAD(SCIP_Real cutrhs), /**< right hand side of the MIR row */
    75 int* cutinds, /**< indices of problem variables for non-zero coefficients */
    76 int cutnnz, /**< number of non-zeros in cut */
    77 SCIP_Bool ignoresol,
    78 SCIP_Bool islocal
    79 )
    80{
    81 SCIP_Real QUAD(activity);
    82 SCIP_VAR** vars;
    83
    84 assert(scip != NULL);
    85 vars = SCIPgetVars(scip);
    86
    87 SCIPdebugMsg(scip, "CUT:");
    88 QUAD_ASSIGN(activity, 0.0);
    89
    90 /**! [SnippetCodeStyleInLoopDeclaration] */
    91 for( int i = 0; i < cutnnz; ++i )
    92 {
    93 SCIP_Real QUAD(coef);
    94
    95 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
    96
    97 if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_BINARY )
    98 SCIPdebugMsgPrint(scip, " %+g<%s>[B]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
    99 else if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_INTEGER )
    100 SCIPdebugMsgPrint(scip, " %+g<%s>[I]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
    101 else
    102 SCIPdebugMsgPrint(scip, " %+g<%s>[C]", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
    103
    104 if( ! ignoresol )
    105 {
    106 SCIPquadprecProdQD(coef, coef, (sol == NULL ? SCIPvarGetLPSol(vars[cutinds[i]]) : SCIPgetSolVal(scip, sol, vars[cutinds[i]])));
    107 }
    108 else
    109 {
    110 if( cutcoefs[i] > 0.0 )
    111 {
    112 SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]])));
    113 }
    114 else
    115 {
    116 SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]])));
    117 }
    118 }
    119
    120 SCIPquadprecSumQQ(activity, activity, coef);
    121 }
    122 /**! [SnippetCodeStyleInLoopDeclaration] */
    123 SCIPdebugMsgPrint(scip, " <= %.6f (activity: %g)\n", QUAD_TO_DBL(cutrhs), QUAD_TO_DBL(activity));
    124}
    125
    126static
    127void printCut(
    128 SCIP* scip, /**< SCIP data structure */
    129 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    130 SCIP_Real* cutcoefs, /**< non-zero coefficients of cut */
    131 SCIP_Real cutrhs, /**< right hand side of the MIR row */
    132 int* cutinds, /**< indices of problem variables for non-zero coefficients */
    133 int cutnnz, /**< number of non-zeros in cut */
    134 SCIP_Bool ignoresol,
    135 SCIP_Bool islocal
    136 )
    137{
    138 SCIP_Real activity;
    139 SCIP_VAR** vars;
    140 int i;
    141
    142 assert(scip != NULL);
    143 vars = SCIPgetVars(scip);
    144
    145 SCIPdebugMsg(scip, "CUT:");
    146 activity = 0.0;
    147 for( i = 0; i < cutnnz; ++i )
    148 {
    149 SCIP_Real coef;
    150
    151 coef = cutcoefs[cutinds[i]];
    152
    153 if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_BINARY )
    154 SCIPdebugMsgPrint(scip, " %+g<%s>[B]", coef, SCIPvarGetName(vars[cutinds[i]]));
    155 else if( SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_INTEGER )
    156 SCIPdebugMsgPrint(scip, " %+g<%s>[I]", coef, SCIPvarGetName(vars[cutinds[i]]));
    157 else
    158 SCIPdebugMsgPrint(scip, " %+g<%s>[C]", coef, SCIPvarGetName(vars[cutinds[i]]));
    159
    160 if( ! ignoresol )
    161 {
    162 coef = coef * (sol == NULL ? SCIPvarGetLPSol(vars[cutinds[i]]) : SCIPgetSolVal(scip, sol, vars[cutinds[i]]));
    163 }
    164 else
    165 {
    166 if( cutcoefs[i] > 0.0 )
    167 {
    168 coef = coef * (islocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]));
    169 }
    170 else
    171 {
    172 coef = coef * (islocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
    173 }
    174 }
    175
    176 activity += coef;
    177 }
    178 SCIPdebugMsgPrint(scip, " <= %.6f (activity: %g)\n", cutrhs, activity);
    179}
    180#endif
    181
    182/** macro to make sure a value is not equal to zero, i.e. NONZERO(x) != 0.0
    183 * will be TRUE for every x including 0.0
    184 *
    185 * To avoid branches it will add 1e-100 with the same sign as x to x which will
    186 * be rounded away for any sane non-zero value but will make sure the value is
    187 * never exactly 0.0.
    188 */
    189#define NONZERO(x) (COPYSIGN(1e-100, (x)) + (x))
    190
    191/** add a scaled row to a dense vector indexed over the problem variables and keep the
    192 * index of non-zeros up-to-date
    193 */
    194static
    196 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
    197 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
    198 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
    199 SCIP_ROW* row, /**< row coefficients to add to variable vector */
    200 SCIP_Real scale /**< scale for adding given row to variable vector */
    201 )
    202{
    203 int i;
    204
    205 assert(inds != NULL);
    206 assert(vals != NULL);
    207 assert(nnz != NULL);
    208 assert(row != NULL);
    209
    210 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    211 for( i = 0 ; i < row->len; ++i )
    212 {
    213 SCIP_Real val;
    214 int probindex;
    215
    216 probindex = row->cols[i]->var_probindex;
    217 val = vals[probindex];
    218
    219 if( val == 0.0 )
    220 inds[(*nnz)++] = probindex;
    221
    222 val += row->vals[i] * scale;
    223
    224 /* the value must not be exactly zero due to sparsity pattern */
    225 val = NONZERO(val);
    226
    227 assert(val != 0.0);
    228 vals[probindex] = val;
    229 }
    230
    231 return SCIP_OKAY;
    232}
    233
    234/** add a scaled row to a dense vector indexed over the problem variables and keep the
    235 * index of non-zeros up-to-date
    236 *
    237 * This is the quad precision version of varVecAddScaledRowCoefs().
    238 */
    239static
    241 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
    242 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
    243 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
    244 SCIP_ROW* row, /**< row coefficients to add to variable vector */
    245 SCIP_Real scale /**< scale for adding given row to variable vector */
    246 )
    247{
    248 int i;
    249
    250 assert(inds != NULL);
    251 assert(vals != NULL);
    252 assert(nnz != NULL);
    253 assert(row != NULL);
    254
    255 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    256 for( i = 0 ; i < row->len; ++i )
    257 {
    258 SCIP_Real QUAD(scaledrowval);
    259 SCIP_Real QUAD(val);
    260 int probindex;
    261
    262 probindex = row->cols[i]->var_probindex;
    263 QUAD_ARRAY_LOAD(val, vals, probindex);
    264
    265 if( QUAD_HI(val) == 0.0 )
    266 inds[(*nnz)++] = probindex;
    267
    268 SCIPquadprecProdDD(scaledrowval, row->vals[i], scale);
    269 SCIPquadprecSumQQ(val, val, scaledrowval);
    270
    271 /* the value must not be exactly zero due to sparsity pattern */
    272 QUAD_HI(val) = NONZERO(QUAD_HI(val));
    273 assert(QUAD_HI(val) != 0.0);
    274
    275 QUAD_ARRAY_STORE(vals, probindex, val);
    276 }
    277
    278 return SCIP_OKAY;
    279}
    280
    281/** add a scaled row to a dense vector indexed over the problem variables and keep the
    282 * index of non-zeros up-to-date
    283 *
    284 * This is the quad precision version of varVecAddScaledRowCoefs() with a quad precision scaling factor.
    285 */
    286static
    288 int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
    289 SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
    290 int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
    291 SCIP_ROW* row, /**< row coefficients to add to variable vector */
    292 QUAD(SCIP_Real scale) /**< scale for adding given row to variable vector */
    293 )
    294{
    295 int i;
    296
    297 assert(inds != NULL);
    298 assert(vals != NULL);
    299 assert(nnz != NULL);
    300 assert(row != NULL);
    301
    302 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    303 for( i = 0 ; i < row->len; ++i )
    304 {
    305 SCIP_Real QUAD(val);
    306 SCIP_Real QUAD(rowval);
    307 int probindex;
    308
    309 probindex = row->cols[i]->var_probindex;
    310 QUAD_ARRAY_LOAD(val, vals, probindex);
    311
    312 if( QUAD_HI(val) == 0.0 )
    313 {
    314 inds[(*nnz)++] = probindex;
    315 SCIPquadprecProdQD(val, scale, row->vals[i]);
    316 }
    317 else
    318 {
    319 SCIPquadprecProdQD(rowval, scale, row->vals[i]);
    320 SCIPquadprecSumQQ(val, val, rowval);
    321 }
    322
    323 /* the value must not be exactly zero due to sparsity pattern */
    324 QUAD_HI(val) = NONZERO(QUAD_HI(val));
    325 assert(QUAD_HI(val) != 0.0);
    326
    327 QUAD_ARRAY_STORE(vals, probindex, val);
    328 }
    329
    330 return SCIP_OKAY;
    331}
    332
    333/** add a scaled row to a dense vector indexed over the problem variables and keep the index of non-zeros up-to-date
    334 *
    335 * In the safe variant, we need to transform all variables (implicitly) to nonnegative variables using their
    336 * upper/lower bounds. When adding \f$\lambda * (c^Tx \le d)\f$ to \f$a^Tx \le b\f$, this results in:
    337 *
    338 * \f{align*}{
    339 * m_i & =a_i+\lambda c_i \\
    340 * U \cap L & = \emptyset \\
    341 * U & = \{ i : x_i \le u_i\} \\
    342 * L & = \{ i : x_i \ge l_i\} \\
    343 * \sum_{i \in U} \overline{m_i}x_i + \sum_{i \in L}\underline{m_i}x_i
    344 * & \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
    345 * \f}
    346 *
    347 * This methods sums up the left hand side, and stores the change of the rhs due to the variable bounds in rhschange.
    348 *
    349 * @note this method is safe for usage in exact solving mode
    350 */
    351static
    353 SCIP* scip, /**< scip data structure */
    354 int* inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
    355 SCIP_Real* vals, /**< array with values of variable vector */
    356 int* nnz, /**< number of non-zeros coefficients of variable vector */
    357 SCIP_ROW* row, /**< row coefficients to add to variable vector */
    358 SCIP_Real scale, /**< scale for adding given row to variable vector */
    359 SCIP_Real* rhschange, /**< change in rhs due to variable conjugation */
    360 SCIP_Bool* success /**< was the addition successful? */
    361 )
    362{
    363 int i;
    364 SCIP_ROUNDMODE previousroundmode;
    365 SCIP_VAR* var;
    366 SCIP_ROWEXACT* rowexact;
    367
    368 assert(SCIPisExact(scip));
    369 assert(inds != NULL);
    370 assert(vals != NULL);
    371 assert(nnz != NULL);
    372 assert(row != NULL);
    373 assert(rhschange != NULL);
    374 assert(success != NULL);
    375 assert(*success);
    376
    377 previousroundmode = SCIPintervalGetRoundingMode();
    379
    380 *rhschange = 0;
    381 rowexact = SCIProwGetRowExact(row);
    382
    383 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    384 for( i = 0 ; i < row->len; ++i )
    385 {
    386 SCIP_Real val;
    387 SCIP_INTERVAL valinterval;
    388 int probindex;
    389
    390 probindex = row->cols[i]->var_probindex;
    391 var = row->cols[i]->var;
    392 val = vals[probindex];
    393
    394 if( val == 0.0 )
    395 {
    396 assert(*nnz < SCIPgetNVars(scip));
    397 inds[(*nnz)++] = probindex;
    398 }
    399
    400 if( val == SCIP_INVALID ) /*lint !e777*/
    401 val = 0.0;
    402
    403 SCIPintervalSetBounds(&valinterval, rowexact->valsinterval[i].inf, rowexact->valsinterval[i].sup);
    404 SCIPintervalMulScalar(SCIPinfinity(scip), &valinterval, valinterval, scale);
    405 SCIPintervalAddScalar(SCIPinfinity(scip), &valinterval, valinterval, val);
    406
    407 if( SCIPisInfinity(scip, REALABS(valinterval.inf)) || SCIPisInfinity(scip, REALABS(valinterval.sup)) )
    408 {
    409 *success = FALSE;
    410 SCIPintervalSetRoundingMode(previousroundmode);
    411 return SCIP_OKAY;
    412 }
    413
    414 if( SCIPvarGetLbGlobal(var) > -SCIPinfinity(scip) && SCIPvarGetLbGlobal(var) >= 0 )
    415 val = valinterval.inf;
    416 else if(SCIPvarGetUbGlobal(var) < SCIPinfinity(scip) && SCIPvarGetUbGlobal(var) <= 0 )
    417 val = valinterval.sup;
    418 else if( SCIPvarGetLbGlobal(var) > -SCIPinfinity(scip) )
    419 {
    420 val = valinterval.inf;
    422 *rhschange += (valinterval.sup - valinterval.inf) * (-SCIPvarGetLbGlobal(var));
    423 }
    424 else if( SCIPvarGetUbGlobal(var) < SCIPinfinity(scip) )
    425 {
    426 val = valinterval.sup;
    428 *rhschange += (valinterval.sup - valinterval.inf) * (SCIPvarGetUbGlobal(var));
    429 }
    430 else
    431 {
    432 *success = FALSE;
    433 SCIPintervalSetRoundingMode(previousroundmode);
    434 return SCIP_OKAY;
    435 }
    436
    437 /* 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
    438 * exactly; this is taken care of in removeZerosSafely */
    439 if( val == 0.0 )
    440 val = SCIP_INVALID;
    441
    442 vals[probindex] = val;
    443 }
    444
    445 SCIPintervalSetRoundingMode(previousroundmode);
    446
    447 return SCIP_OKAY;
    448}
    449
    450/** calculates the cut efficacy for the given solution */
    451static
    453 SCIP* scip, /**< SCIP data structure */
    454 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
    455 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    456 SCIP_Real cutrhs, /**< the right hand side of the cut */
    457 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    458 int cutnnz /**< the number of non-zeros in the cut */
    459 )
    460{
    461 SCIP_VAR** vars;
    462 SCIP_Real norm = 0.0;
    463 SCIP_Real activity = 0.0;
    464 int i;
    465
    466 assert(scip != NULL);
    467 assert(cutcoefs != NULL);
    468 assert(cutinds != NULL);
    469
    470 vars = SCIPgetVars(scip);
    471
    472 switch( scip->set->sepa_efficacynorm )
    473 {
    474 case 'e':
    475 for( i = 0; i < cutnnz; ++i )
    476 {
    477 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    478 norm += SQR(cutcoefs[i]);
    479 }
    480 norm = sqrt(norm);
    481 break;
    482 case 'm':
    483 for( i = 0; i < cutnnz; ++i )
    484 {
    485 SCIP_Real absval;
    486
    487 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    488 absval = REALABS(cutcoefs[i]);
    489 norm = MAX(norm, absval);
    490 }
    491 break;
    492 case 's':
    493 for( i = 0; i < cutnnz; ++i )
    494 {
    495 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    496 norm += REALABS(cutcoefs[i]);
    497 }
    498 break;
    499 case 'd':
    500 for( i = 0; i < cutnnz; ++i )
    501 {
    502 activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    503 if( !SCIPisZero(scip, cutcoefs[i]) )
    504 norm = 1.0;
    505 }
    506 break;
    507 default:
    508 SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", scip->set->sepa_efficacynorm);
    509 assert(FALSE); /*lint !e506*/
    510 }
    511
    512 return (activity - cutrhs) / MAX(1e-6, norm);
    513}
    514
    515/** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter */
    516static
    518 SCIP* scip, /**< SCIP data structure */
    519 SCIP_Real* vals, /**< array of the non-zero coefficients in the vector; this is a quad precision array! */
    520 int* inds, /**< array of the problem indices of variables with a non-zero coefficient in the vector */
    521 int nnz /**< the number of non-zeros in the vector */
    522 )
    523{
    524 SCIP_Real norm = 0.0;
    525 SCIP_Real QUAD(coef);
    526 int i;
    527
    528 assert(scip != NULL);
    529 assert(scip->set != NULL);
    530
    531 switch( scip->set->sepa_efficacynorm )
    532 {
    533 case 'e':
    534 for( i = 0; i < nnz; ++i )
    535 {
    536 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
    537 norm += SQR(QUAD_TO_DBL(coef));
    538 }
    539 norm = sqrt(norm);
    540 break;
    541 case 'm':
    542 for( i = 0; i < nnz; ++i )
    543 {
    544 SCIP_Real absval;
    545 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
    546
    547 absval = REALABS(QUAD_TO_DBL(coef));
    548 norm = MAX(norm, absval);
    549 }
    550 break;
    551 case 's':
    552 for( i = 0; i < nnz; ++i )
    553 {
    554 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
    555 norm += REALABS(QUAD_TO_DBL(coef));
    556 }
    557 break;
    558 case 'd':
    559 for( i = 0; i < nnz; ++i )
    560 {
    561 QUAD_ARRAY_LOAD(coef, vals, inds[i]);
    562 if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
    563 {
    564 norm = 1.0;
    565 break;
    566 }
    567 }
    568 break;
    569 default:
    570 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
    571 assert(FALSE); /*lint !e506*/
    572 }
    573
    574 return norm;
    575}
    576
    577/** calculates the cut efficacy for the given solution; the cut coefs are stored densely */
    578static
    580 SCIP* scip, /**< SCIP data structure */
    581 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
    582 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut; this is a quad precision array! */
    583 SCIP_Real cutrhs, /**< the right hand side of the cut */
    584 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    585 int cutnnz /**< the number of non-zeros in the cut */
    586 )
    587{
    588 SCIP_VAR** vars;
    589 SCIP_Real norm = 0.0;
    590 SCIP_Real activity = 0.0;
    591 SCIP_Real coef;
    592 int i;
    593
    594 assert(scip != NULL);
    595 assert(cutcoefs != NULL);
    596 assert(cutinds != NULL);
    597 assert(scip->set != NULL);
    598
    599 vars = SCIPgetVars(scip);
    600
    601 switch( scip->set->sepa_efficacynorm )
    602 {
    603 case 'e':
    604 for( i = 0; i < cutnnz; ++i )
    605 {
    606 coef = cutcoefs[cutinds[i]];
    607 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    608 norm += SQR(coef);
    609 }
    610 norm = SQR(norm);
    611 break;
    612 case 'm':
    613 for( i = 0; i < cutnnz; ++i )
    614 {
    615 SCIP_Real absval;
    616
    617 coef = cutcoefs[cutinds[i]];
    618 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    619 absval = REALABS(coef);
    620 norm = MAX(norm, absval);
    621 }
    622 break;
    623 case 's':
    624 for( i = 0; i < cutnnz; ++i )
    625 {
    626 coef = cutcoefs[cutinds[i]];
    627 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    628 norm += REALABS(coef);
    629 }
    630 break;
    631 case 'd':
    632 for( i = 0; i < cutnnz; ++i )
    633 {
    634 coef = cutcoefs[cutinds[i]];
    635 activity += coef * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    636 if( !SCIPisZero(scip, coef) )
    637 norm = 1.0;
    638 }
    639 break;
    640 default:
    641 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
    642 assert(FALSE); /*lint !e506*/
    643 }
    644
    645 return (activity - cutrhs) / MAX(1e-6, norm);
    646}
    647
    648/** calculates the cut efficacy for the given solution; the cut coefs are stored densely and in quad precision */
    649static
    651 SCIP* scip, /**< SCIP data structure */
    652 SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
    653 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut; this is a quad precision array! */
    654 SCIP_Real cutrhs, /**< the right hand side of the cut */
    655 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    656 int cutnnz /**< the number of non-zeros in the cut */
    657 )
    658{
    659 SCIP_VAR** vars;
    660 SCIP_Real norm = 0.0;
    661 SCIP_Real activity = 0.0;
    662 SCIP_Real QUAD(coef);
    663 int i;
    664
    665 assert(scip != NULL);
    666 assert(cutcoefs != NULL);
    667 assert(cutinds != NULL);
    668 assert(scip->set != NULL);
    669
    670 vars = SCIPgetVars(scip);
    671
    672 switch( scip->set->sepa_efficacynorm )
    673 {
    674 case 'e':
    675 for( i = 0; i < cutnnz; ++i )
    676 {
    677 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
    678 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    679 norm += SQR(QUAD_TO_DBL(coef));
    680 }
    681 norm = sqrt(norm);
    682 break;
    683 case 'm':
    684 for( i = 0; i < cutnnz; ++i )
    685 {
    686 SCIP_Real absval;
    687
    688 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
    689 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    690 absval = REALABS(QUAD_TO_DBL(coef));
    691 norm = MAX(norm, absval);
    692 }
    693 break;
    694 case 's':
    695 for( i = 0; i < cutnnz; ++i )
    696 {
    697 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
    698 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    699 norm += REALABS(QUAD_TO_DBL(coef));
    700 }
    701 break;
    702 case 'd':
    703 for( i = 0; i < cutnnz; ++i )
    704 {
    705 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
    706 activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
    707 if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
    708 norm = 1.0;
    709 }
    710 break;
    711 default:
    712 SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
    713 assert(FALSE); /*lint !e506*/
    714 }
    715
    716 return (activity - cutrhs) / MAX(1e-6, norm);
    717}
    718
    719/** safely (in the exact solving mode sense) remove all items with |a_i| or |u_i - l_i)| below the given value
    720 *
    721 * Returns TRUE if the cut became redundant.
    722 * If it is a local cut, use local bounds, otherwise, use global bounds.
    723 *
    724 * * @note this method is safe for usage in exact solving mode
    725 */
    726static
    728 SCIP* scip, /**< SCIP data structure */
    729 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
    730 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    731 SCIP_Real* cutrhs, /**< the right hand side of the cut */
    732 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    733 int* cutnnz /**< the number of non-zeros in the cut */
    734 )
    735{
    736 int i;
    737 SCIP_VAR** vars;
    738 SCIP_ROUNDMODE previousroundmode;
    739
    740 assert(SCIPisExact(scip));
    741
    742 previousroundmode = SCIPintervalGetRoundingMode();
    744
    745 vars = SCIPgetVars(scip);
    746
    747 for( i = 0; i < *cutnnz; )
    748 {
    749 SCIP_Real val;
    750 SCIP_Real lb;
    751 SCIP_Real ub;
    752 int v;
    753 SCIP_Bool isfixed;
    754
    755 v = cutinds[i];
    756 val = cutcoefs[v];
    757
    758 if( val == SCIP_INVALID ) /*lint !e777*/
    759 val = 0.0;
    760
    761 /* for now we always use global bounds in exact solving mode (could be improved for local cuts in the future) */
    762 lb = SCIPvarGetLbGlobal(vars[v]);
    763 ub = SCIPvarGetUbGlobal(vars[v]);
    764
    765 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
    766 isfixed = TRUE;
    767 else
    768 isfixed = FALSE;
    769
    770 if( EPSZ(val, minval) || isfixed )
    771 {
    772 /* adjust left and right hand sides with max contribution */
    773 if( val < 0.0 )
    774 {
    775 if( SCIPisInfinity(scip, ub) )
    776 {
    777 SCIPintervalSetRoundingMode(previousroundmode);
    778 return TRUE;
    779 }
    780 else
    781 *cutrhs += (-val) * ub;
    782 }
    783 else
    784 {
    785 if( SCIPisInfinity(scip, -lb) )
    786 {
    787 SCIPintervalSetRoundingMode(previousroundmode);
    788 return TRUE;
    789 }
    790 else
    791 *cutrhs += (-val) * lb;
    792 }
    793
    794 val = 0.0;
    795 cutcoefs[v] = val;
    796
    797 /* remove non-zero entry */
    798 --(*cutnnz);
    799 cutinds[i] = cutinds[*cutnnz];
    800 }
    801 else
    802 ++i;
    803 }
    804
    805 /* relax rhs to 0, if it's very close to 0 */
    806 if( *cutrhs < 0.0 && *cutrhs >= -SCIPepsilon(scip) )
    807 *cutrhs = 0.0;
    808
    809 SCIPintervalSetRoundingMode(previousroundmode);
    810
    811 return FALSE;
    812}
    813
    814/** safely remove all items with |a_i| or |u_i - l_i)| below the given value
    815 *
    816 * Returns TRUE if the cut became redundant.
    817 * If it is a local cut, use local bounds, otherwise, use global bounds.
    818 *
    819 * @note this method is safe for usage in exact solving mode
    820 */
    821static
    823 SCIP* scip, /**< SCIP data structure */
    824 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
    825 SCIP_Bool cutislocal, /**< is the cut local? */
    826 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    827 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
    828 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    829 int* cutnnz /**< the number of non-zeros in the cut */
    830 )
    831{
    832 int i;
    833 SCIP_VAR** vars;
    834
    835 vars = SCIPgetVars(scip);
    836
    837 for( i = 0; i < *cutnnz; )
    838 {
    839 SCIP_Real QUAD(val);
    840 SCIP_Real lb;
    841 SCIP_Real ub;
    842 int v;
    843 SCIP_Bool isfixed;
    844
    845 v = cutinds[i];
    846 QUAD_ARRAY_LOAD(val, cutcoefs, v);
    847
    848 if( cutislocal )
    849 {
    850 lb = SCIPvarGetLbLocal(vars[v]);
    851 ub = SCIPvarGetUbLocal(vars[v]);
    852 }
    853 else
    854 {
    855 lb = SCIPvarGetLbGlobal(vars[v]);
    856 ub = SCIPvarGetUbGlobal(vars[v]);
    857 }
    858
    859 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
    860 isfixed = TRUE;
    861 else
    862 isfixed = FALSE;
    863
    864 if( isfixed || EPSZ(QUAD_TO_DBL(val), minval) )
    865 {
    866 if( REALABS(QUAD_TO_DBL(val)) > QUAD_EPSILON )
    867 {
    868 /* adjust right hand side with max contribution */
    869 if( QUAD_TO_DBL(val) < 0.0 )
    870 {
    871 if( SCIPisInfinity(scip, ub) )
    872 return TRUE;
    873 else
    874 {
    875 SCIPquadprecProdQD(val, val, ub);
    876 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
    877 }
    878 }
    879 else
    880 {
    881 if( SCIPisInfinity(scip, -lb) )
    882 return TRUE;
    883 else
    884 {
    885 SCIPquadprecProdQD(val, val, lb);
    886 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
    887 }
    888 }
    889 }
    890
    891 QUAD_ASSIGN(val, 0.0);
    892 QUAD_ARRAY_STORE(cutcoefs, v, val);
    893
    894 /* remove non-zero entry */
    895 --(*cutnnz);
    896 cutinds[i] = cutinds[*cutnnz];
    897 }
    898 else
    899 ++i;
    900 }
    901
    902 /* relax rhs to 0, if it's very close to 0 */
    903 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    904 QUAD_ASSIGN(*cutrhs, 0.0);
    905
    906 return FALSE;
    907}
    908
    909/** safely remove all items with |a_i| or |u_i - l_i| below the given value
    910 *
    911 * Returns TRUE if the cut became redundant.
    912 * If it is a local cut, use local bounds, otherwise, use global bounds.
    913 */
    914static
    916 SCIP* scip, /**< SCIP data structure */
    917 SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
    918 SCIP_Bool cutislocal, /**< is the cut local? */
    919 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    920 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
    921 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    922 int* cutnnz /**< the number of non-zeros in the cut */
    923 )
    924{
    925 int i;
    926 SCIP_VAR** vars;
    927
    928 vars = SCIPgetVars(scip);
    929
    930 /* loop over non-zeros and remove values below minval; values above QUAD_EPSILON are cancelled with their bound
    931 * to avoid numerical rounding errors
    932 */
    933 for( i = 0; i < *cutnnz; )
    934 {
    935 SCIP_Real val;
    936 SCIP_Real lb;
    937 SCIP_Real ub;
    938 int v;
    939 SCIP_Bool isfixed;
    940 SCIP_Real QUAD(quadprod);
    941
    942 v = cutinds[i];
    943 val = cutcoefs[v];
    944
    945 if( cutislocal )
    946 {
    947 lb = SCIPvarGetLbLocal(vars[v]);
    948 ub = SCIPvarGetUbLocal(vars[v]);
    949 }
    950 else
    951 {
    952 lb = SCIPvarGetLbGlobal(vars[v]);
    953 ub = SCIPvarGetUbGlobal(vars[v]);
    954 }
    955
    956 if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
    957 isfixed = TRUE;
    958 else
    959 isfixed = FALSE;
    960
    961 if( EPSZ(val, minval) || isfixed )
    962 {
    963 if( REALABS(val) > QUAD_EPSILON )
    964 {
    965 /* adjust left and right hand sides with max contribution */
    966 if( val < 0.0 )
    967 {
    968 if( SCIPisInfinity(scip, ub) )
    969 return TRUE;
    970 else
    971 {
    972 SCIPquadprecProdDD(quadprod, -val, ub);
    973 SCIPquadprecSumQQ(*cutrhs, *cutrhs, quadprod);
    974 }
    975 }
    976 else
    977 {
    978 if( SCIPisInfinity(scip, -lb) )
    979 return TRUE;
    980 else
    981 {
    982 SCIPquadprecProdDD(quadprod, -val, lb);
    983 SCIPquadprecSumQQ(*cutrhs, *cutrhs, quadprod);
    984 }
    985 }
    986 }
    987
    988 cutcoefs[v] = 0.0;
    989
    990 /* remove non-zero entry */
    991 --(*cutnnz);
    992 cutinds[i] = cutinds[*cutnnz];
    993 }
    994 else
    995 ++i;
    996 }
    997
    998 /* relax rhs to 0, if it's very close to 0 */
    999 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    1000 QUAD_ASSIGN(*cutrhs, 0.0);
    1001
    1002 return FALSE;
    1003}
    1004
    1005/** compare absolute values of coefficients in quad precision */
    1006static
    1007SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
    1008{
    1009 SCIP_Real abscoef1;
    1010 SCIP_Real abscoef2;
    1011 SCIP_Real QUAD(coef1);
    1012 SCIP_Real QUAD(coef2);
    1013 SCIP_Real* coefs = (SCIP_Real*) dataptr;
    1014
    1015 QUAD_ARRAY_LOAD(coef1, coefs, ind1);
    1016 QUAD_ARRAY_LOAD(coef2, coefs, ind2);
    1017
    1018 abscoef1 = REALABS(QUAD_TO_DBL(coef1));
    1019 abscoef2 = REALABS(QUAD_TO_DBL(coef2));
    1020
    1021 if( abscoef1 < abscoef2 )
    1022 return -1;
    1023 if( abscoef2 < abscoef1 )
    1024 return 1;
    1025
    1026 return 0;
    1027}
    1028
    1029/** compare absolute values of coefficients */
    1030static
    1032{
    1033 SCIP_Real abscoef1;
    1034 SCIP_Real abscoef2;
    1035 SCIP_Real* coefs = (SCIP_Real*) dataptr;
    1036
    1037 abscoef1 = REALABS(coefs[ind1]);
    1038 abscoef2 = REALABS(coefs[ind2]);
    1039
    1040 if( abscoef1 < abscoef2 )
    1041 return -1;
    1042 if( abscoef2 < abscoef1 )
    1043 return 1;
    1044
    1045 return 0;
    1046}
    1047
    1048/** change given coefficient to new given value, adjust right hand side using the variables bound;
    1049 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
    1050 */
    1051static
    1053 SCIP* scip, /**< SCIP data structure */
    1054 SCIP_VAR* var, /**< variable the coefficient belongs to */
    1055 SCIP_Real oldcoeff, /**< old coefficient value */
    1056 SCIP_Real newcoeff, /**< new coefficient value */
    1057 SCIP_Bool cutislocal, /**< is the cut local? */
    1058 QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
    1059 )
    1060{
    1061 SCIP_Real QUAD(delta);
    1062
    1063 SCIPquadprecSumDD(delta, newcoeff, -oldcoeff);
    1064
    1065 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
    1066 {
    1067 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
    1068
    1069 if( SCIPisInfinity(scip, ub) )
    1070 return TRUE;
    1071 else
    1072 {
    1073 SCIPquadprecProdQD(delta, delta, ub);
    1074 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
    1075 }
    1076 }
    1077 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
    1078 {
    1079 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
    1080
    1081 if( SCIPisInfinity(scip, -lb) )
    1082 return TRUE;
    1083 else
    1084 {
    1085 SCIPquadprecProdQD(delta, delta, lb);
    1086 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
    1087 }
    1088 }
    1089
    1090 return FALSE;
    1091}
    1092
    1093/** change given (quad) coefficient to new given value, adjust right hand side using the variables bound;
    1094 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
    1095 */
    1096static
    1098 SCIP* scip, /**< SCIP data structure */
    1099 SCIP_VAR* var, /**< variable the coefficient belongs to */
    1100 QUAD(SCIP_Real oldcoeff), /**< old coefficient value */
    1101 SCIP_Real newcoeff, /**< new coefficient value */
    1102 SCIP_Bool cutislocal, /**< is the cut local? */
    1103 QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
    1104 )
    1105{
    1106 SCIP_Real QUAD(delta);
    1107
    1108 SCIPquadprecSumQD(delta, -oldcoeff, newcoeff);
    1109
    1110 if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
    1111 {
    1112 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
    1113
    1114 if( SCIPisInfinity(scip, ub) )
    1115 return TRUE;
    1116 else
    1117 {
    1118 SCIPquadprecProdQD(delta, delta, ub);
    1119 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
    1120 }
    1121 }
    1122 else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
    1123 {
    1124 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
    1125
    1126 if( SCIPisInfinity(scip, -lb) )
    1127 return TRUE;
    1128 else
    1129 {
    1130 SCIPquadprecProdQD(delta, delta, lb);
    1131 SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
    1132 }
    1133 }
    1134
    1135 return FALSE;
    1136}
    1137
    1138/** change given coefficient to new given value, adjust right hand side using the variables bound;
    1139 * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
    1140 */
    1141static
    1143 SCIP* scip, /**< SCIP data structure */
    1144 SCIP_VAR* var, /**< variable the coefficient belongs to */
    1145 SCIP_Real oldcoeff, /**< old coefficient value */
    1146 SCIP_Real newcoeff, /**< new coefficient value */
    1147 SCIP_Bool cutislocal, /**< is the cut local? */
    1148 SCIP_Real* cutrhs /**< pointer to adjust right hand side of cut */
    1149 )
    1150{
    1151 SCIP_INTERVAL delta;
    1152 SCIP_ROUNDMODE previousroundmode;
    1153
    1154 assert(SCIPisExact(scip));
    1155
    1156 previousroundmode = SCIPintervalGetRoundingMode();
    1158
    1159 SCIPintervalSet(&delta, newcoeff);
    1160 SCIPintervalSubScalar(SCIPinfinity(scip), &delta, delta, oldcoeff);
    1161
    1162 if( SCIPintervalGetSup(delta) > 0 )
    1163 {
    1164 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
    1165
    1166 if( SCIPisInfinity(scip, ub) )
    1167 {
    1168 SCIPintervalSetRoundingMode(previousroundmode);
    1169 return TRUE;
    1170 }
    1171 else
    1172 {
    1173 SCIPintervalMulScalar(SCIPinfinity(scip), &delta, delta, ub);
    1174 *cutrhs += SCIPintervalGetSup(delta);
    1175 }
    1176 }
    1177 else if( SCIPintervalGetInf(delta) < 0 )
    1178 {
    1179 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
    1180
    1181 if( SCIPisInfinity(scip, -lb) )
    1182 {
    1183 SCIPintervalSetRoundingMode(previousroundmode);
    1184 return TRUE;
    1185 }
    1186 else
    1187 {
    1188 SCIPintervalMulScalar(SCIPinfinity(scip), &delta, delta, lb);
    1189 *cutrhs += SCIPintervalGetSup(delta);
    1190 }
    1191 }
    1192 else
    1193 {
    1194 return TRUE;
    1195 }
    1196
    1197 return FALSE;
    1198}
    1199
    1200
    1201/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
    1202 * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse quad precision array;
    1203 *
    1204 * This is the quad precision version of cutTightenCoefs() below.
    1205 */
    1206static
    1208 SCIP* scip, /**< SCIP data structure */
    1209 SCIP_Bool cutislocal, /**< is the cut local? */
    1210 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    1211 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
    1212 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    1213 int* cutnnz, /**< the number of non-zeros in the cut */
    1214 SCIP_Bool* redundant /**< whether the cut was detected to be redundant */
    1215 )
    1216{
    1217 int i;
    1218 int nintegralvars;
    1219 SCIP_Bool isintegral = TRUE;
    1220 SCIP_VAR** vars;
    1221 SCIP_Real QUAD(maxacttmp);
    1222 SCIP_Real maxact;
    1223 SCIP_Real maxabsintval = 0.0;
    1224 SCIP_Real maxabscontval = 0.0;
    1225
    1226 QUAD_ASSIGN(maxacttmp, 0.0);
    1227
    1228 vars = SCIPgetVars(scip);
    1229 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    1230
    1231 assert(redundant != NULL);
    1232 *redundant = FALSE;
    1233
    1234 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
    1235 for( i = 0; i < *cutnnz; ++i )
    1236 {
    1237 SCIP_Real QUAD(val);
    1238
    1239 assert(cutinds[i] >= 0);
    1240 assert(vars[cutinds[i]] != NULL);
    1241
    1242 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1243
    1244 if( QUAD_TO_DBL(val) < 0.0 )
    1245 {
    1246 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    1247
    1248 if( SCIPisInfinity(scip, -lb) )
    1249 return SCIP_OKAY;
    1250
    1251 if( cutinds[i] < nintegralvars )
    1252 maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
    1253 else
    1254 {
    1255 maxabscontval = MAX(maxabscontval, -QUAD_TO_DBL(val));
    1256 isintegral = FALSE;
    1257 }
    1258
    1259 SCIPquadprecProdQD(val, val, lb);
    1260 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
    1261 }
    1262 else
    1263 {
    1264 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    1265
    1266 if( SCIPisInfinity(scip, ub) )
    1267 return SCIP_OKAY;
    1268
    1269 if( cutinds[i] < nintegralvars )
    1270 maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
    1271 else
    1272 {
    1273 maxabscontval = MAX(maxabscontval, QUAD_TO_DBL(val));
    1274 isintegral = FALSE;
    1275 }
    1276
    1277 SCIPquadprecProdQD(val, val, ub);
    1278 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
    1279 }
    1280 }
    1281
    1282 maxact = QUAD_TO_DBL(maxacttmp);
    1283
    1284 /* cut is redundant in activity bounds */
    1285 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
    1286 {
    1287 *redundant = TRUE;
    1288 return SCIP_OKAY;
    1289 }
    1290
    1291 /* cut is only on integral variables, try to scale to integral coefficients */
    1292 if( isintegral )
    1293 {
    1294 SCIP_Real equiscale;
    1295 SCIP_Real intscalar;
    1296 SCIP_Bool success;
    1297 SCIP_Real* intcoeffs;
    1298
    1299 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
    1300
    1301 equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
    1302
    1303 for( i = 0; i < *cutnnz; ++i )
    1304 {
    1305 SCIP_Real QUAD(val);
    1306
    1307 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1308 SCIPquadprecProdQD(val, val, equiscale);
    1309
    1310 intcoeffs[i] = QUAD_TO_DBL(val);
    1311 }
    1312
    1314 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
    1315
    1316 SCIPfreeBufferArray(scip, &intcoeffs);
    1317
    1318 if( success )
    1319 {
    1320 /* if successful, apply the scaling */
    1321 intscalar *= equiscale;
    1322 SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
    1323
    1324 for( i = 0; i < *cutnnz; )
    1325 {
    1326 SCIP_Real QUAD(val);
    1327 SCIP_Real intval;
    1328
    1329 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1330 SCIPquadprecProdQD(val, val, intscalar);
    1331
    1332 intval = SCIPround(scip, QUAD_TO_DBL(val));
    1333
    1334 if( chgQuadCoeffWithBound(scip, vars[cutinds[i]], QUAD(val), intval, cutislocal, QUAD(cutrhs)) )
    1335 {
    1336 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
    1337 *redundant = TRUE;
    1338 return SCIP_OKAY;
    1339 }
    1340
    1341 if( intval != 0.0 )
    1342 {
    1343 QUAD_ASSIGN(val, intval);
    1344 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
    1345 ++i;
    1346 }
    1347 else
    1348 {
    1349 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
    1350 QUAD_ASSIGN(val, 0.0);
    1351 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
    1352 --(*cutnnz);
    1353 cutinds[i] = cutinds[*cutnnz];
    1354 }
    1355 }
    1356
    1357 SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
    1358
    1359 /* recompute the maximal activity after scaling to integral values */
    1360 QUAD_ASSIGN(maxacttmp, 0.0);
    1361 maxabsintval = 0.0;
    1362
    1363 for( i = 0; i < *cutnnz; ++i )
    1364 {
    1365 SCIP_Real QUAD(val);
    1366
    1367 assert(cutinds[i] >= 0);
    1368 assert(vars[cutinds[i]] != NULL);
    1369
    1370 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1371
    1372 if( QUAD_TO_DBL(val) < 0.0 )
    1373 {
    1374 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    1375
    1376 maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
    1377
    1378 SCIPquadprecProdQD(val, val, lb);
    1379
    1380 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
    1381 }
    1382 else
    1383 {
    1384 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    1385
    1386 maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
    1387
    1388 SCIPquadprecProdQD(val, val, ub);
    1389
    1390 SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
    1391 }
    1392 }
    1393
    1394 assert(EPSISINT(QUAD_TO_DBL(maxacttmp), 1e-4));
    1395 SCIPquadprecSumQD(maxacttmp, maxacttmp, 0.5);
    1396 SCIPquadprecFloorQ(maxacttmp, maxacttmp);
    1397 }
    1398 else
    1399 {
    1400 /* otherwise, apply the equilibrium scaling */
    1401 isintegral = FALSE;
    1402
    1403 /* perform the scaling */
    1404 SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
    1405 SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
    1406 maxabsintval *= equiscale;
    1407
    1408 for( i = 0; i < *cutnnz; ++i )
    1409 {
    1410 SCIP_Real QUAD(val);
    1411
    1412 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1413 SCIPquadprecProdQD(val, val, equiscale);
    1414 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
    1415 }
    1416 }
    1417 }
    1418 else
    1419 {
    1420 /* cut has integer and continuous variables, so scale it to equilibrium */
    1421 SCIP_Real scale;
    1422 SCIP_Real maxabsval;
    1423
    1424 maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
    1425 maxabsval = MIN(maxabsval, maxabsintval);
    1426 maxabsval = MAX(maxabsval, maxabscontval);
    1427
    1428 scale = 1.0 / maxabsval; /*lint !e795*/
    1429
    1430 /* perform the scaling */
    1431 SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
    1432 SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
    1433 maxabsintval *= scale;
    1434
    1435 for( i = 0; i < *cutnnz; ++i )
    1436 {
    1437 SCIP_Real QUAD(val);
    1438
    1439 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1440 SCIPquadprecProdQD(val, val, scale);
    1441 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
    1442 }
    1443 }
    1444
    1445 maxact = QUAD_TO_DBL(maxacttmp);
    1446
    1447 /* check again for redundancy after scaling */
    1448 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
    1449 {
    1450 *redundant = TRUE;
    1451 return SCIP_OKAY;
    1452 }
    1453
    1454 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
    1455 if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
    1456 return SCIP_OKAY;
    1457
    1458 /* 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 */
    1459 SCIPsortInt(cutinds, *cutnnz);
    1460 SCIPsortDownInd(cutinds, compareAbsCoefsQuad, (void*) cutcoefs, *cutnnz);
    1461
    1462 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
    1463 for( i = 0; i < *cutnnz; )
    1464 {
    1465 SCIP_Real QUAD(val);
    1466
    1467 if( cutinds[i] >= nintegralvars )
    1468 {
    1469 ++i;
    1470 continue;
    1471 }
    1472
    1473 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1474
    1475 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
    1476
    1477 if( QUAD_TO_DBL(val) < 0.0 && SCIPisLE(scip, maxact + QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
    1478 {
    1479 SCIP_Real QUAD(coef);
    1480 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    1481
    1482 SCIPquadprecSumQQ(coef, *cutrhs, -maxacttmp);
    1483
    1484 if( isintegral )
    1485 {
    1486 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    1487 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    1488 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    1489 }
    1490
    1491 if( QUAD_TO_DBL(coef) > QUAD_TO_DBL(val) )
    1492 {
    1493 SCIP_Real QUAD(delta);
    1494 SCIP_Real QUAD(tmp);
    1495
    1496 SCIPquadprecSumQQ(delta, -val, coef);
    1497 SCIPquadprecProdQD(delta, delta, lb);
    1498
    1499 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    1500 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    1501 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
    1502 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
    1503
    1504 QUAD_ASSIGN_Q(*cutrhs, tmp);
    1505
    1506 assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
    1507
    1508 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
    1509 {
    1510 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    1511 maxact = QUAD_TO_DBL(maxacttmp);
    1512 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    1513 }
    1514 else
    1515 {
    1516 QUAD_ASSIGN(coef, 0.0);
    1517 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    1518 --(*cutnnz);
    1519 cutinds[i] = cutinds[*cutnnz];
    1520 continue;
    1521 }
    1522 }
    1523 }
    1524 else if( QUAD_TO_DBL(val) > 0.0 && SCIPisLE(scip, maxact - QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
    1525 {
    1526 SCIP_Real QUAD(coef);
    1527 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    1528
    1529 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
    1530
    1531 if( isintegral )
    1532 {
    1533 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    1534 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    1535 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    1536 }
    1537
    1538 if( QUAD_TO_DBL(coef) < QUAD_TO_DBL(val) )
    1539 {
    1540 SCIP_Real QUAD(delta);
    1541 SCIP_Real QUAD(tmp);
    1542
    1543 SCIPquadprecSumQQ(delta, -val, coef);
    1544 SCIPquadprecProdQD(delta, delta, ub);
    1545
    1546 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    1547 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    1548 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
    1549 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
    1550
    1551 QUAD_ASSIGN_Q(*cutrhs, tmp);
    1552
    1553 assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
    1554
    1555 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
    1556 {
    1557 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    1558 maxact = QUAD_TO_DBL(maxacttmp);
    1559 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    1560 }
    1561 else
    1562 {
    1563 QUAD_ASSIGN(coef, 0.0);
    1564 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    1565 --(*cutnnz);
    1566 cutinds[i] = cutinds[*cutnnz];
    1567 continue;
    1568 }
    1569 }
    1570 }
    1571 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
    1572 break;
    1573
    1574 ++i;
    1575 }
    1576
    1577 return SCIP_OKAY;
    1578}
    1579
    1580/** multiplies a parameter for a variable in a row safely (using variable bounds and increasing the rhs)
    1581 *
    1582 * @return the scaled value
    1583 */
    1584static
    1586 SCIP* scip, /**< SCIP structure */
    1587 SCIP_Real val, /**< the value that should be scaled */
    1588 SCIP_Real scale, /**< scaling factor */
    1589 SCIP_Bool cutislocal, /**< should local or global bounds be used */
    1590 SCIP_VAR* var, /**< the variable that is relevant */
    1591 SCIP_Real* rhschange, /**< resulting change in rhs of row */
    1592 SCIP_Bool* success /**< was the operation successful? (false if no bounds) */
    1593 )
    1594{
    1595 SCIP_ROUNDMODE previousroundmode;
    1596 SCIP_INTERVAL valinterval;
    1597 SCIP_Real ub;
    1598 SCIP_Real lb;
    1599 SCIP_Real newval = 0.0;
    1600
    1601 assert(SCIPisExact(scip));
    1602
    1603 previousroundmode = SCIPintervalGetRoundingMode();
    1605
    1606 *rhschange = 0;
    1607
    1608 SCIPintervalSet(&valinterval, val);
    1609 SCIPintervalMulScalar(SCIPinfinity(scip), &valinterval, valinterval, scale);
    1610
    1611 lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
    1612 ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
    1613
    1614 *success = TRUE;
    1615
    1616 if( lb > -SCIPinfinity(scip) && lb >= 0 )
    1617 {
    1618 SCIPdebugMessage("Lb positive, no change in rhs needed \n");
    1619 newval = SCIPintervalGetInf(valinterval);
    1620 }
    1621 else if(ub < SCIPinfinity(scip) && ub <= 0 )
    1622 {
    1623 SCIPdebugMessage("Ub negative, no change in rhs needed \n");
    1624 newval = SCIPintervalGetSup(valinterval);
    1625 }
    1626 else if( lb > -SCIPinfinity(scip) )
    1627 {
    1628 newval = SCIPintervalGetInf(valinterval);
    1630 *rhschange = (SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval)) * (-lb);
    1631 SCIPdebugMessage("Using lb %.17g corrected by %.17g. Change to rhs: %.17g \n", SCIPvarGetLbGlobal(var), -SCIPintervalGetSup(valinterval) + SCIPintervalGetInf(valinterval), *rhschange);
    1632 }
    1633 else if( ub < SCIPinfinity(scip) )
    1634 {
    1635 newval = SCIPintervalGetSup(valinterval);
    1637 *rhschange = (SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval)) * (ub);
    1638 SCIPdebugMessage("Using ub %.17g corrected by %.17g. Change to rhs: %.17g \n", SCIPvarGetUbGlobal(var), SCIPintervalGetSup(valinterval) - SCIPintervalGetInf(valinterval), *rhschange);
    1639 }
    1640 else
    1641 {
    1642 *success = FALSE;
    1643 SCIPintervalSetRoundingMode(previousroundmode);
    1644 return newval;
    1645 }
    1646
    1647 SCIPintervalSetRoundingMode(previousroundmode);
    1648
    1649 return newval;
    1650}
    1651
    1652/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
    1653 * see cons_linear.c consdataTightenCoefs() for details;
    1654 *
    1655 * This is the safe version of cutTightenCoefs() below.
    1656 */
    1657static
    1659 SCIP* scip, /**< SCIP data structure */
    1660 SCIP_Bool cutislocal, /**< is the cut local? */
    1661 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    1662 SCIP_Real* cutrhs, /**< the right hand side of the cut */
    1663 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    1664 int* cutnnz, /**< the number of non-zeros in the cut */
    1665 SCIP_Bool* redundant /**< whether the cut was detected to be redundant */
    1666 )
    1667{ /*lint --e{644}*/
    1668 int i;
    1669 int nintegralvars;
    1670 SCIP_Bool isintegral = TRUE;
    1671 SCIP_VAR** vars;
    1672 SCIP_INTERVAL maxact;
    1673 SCIP_INTERVAL tmp;
    1674 SCIP_Real maxabsintval = 0.0;
    1675 SCIP_Real maxabscontval = 0.0;
    1676 SCIP_ROUNDMODE previousroundmode;
    1677 SCIP_MIRINFO* mirinfo = NULL;
    1678
    1679 assert(SCIPisExact(scip));
    1680
    1681 if( SCIPisCertified(scip) )
    1682 {
    1684 assert(mirinfo != NULL);
    1685 }
    1686
    1687 SCIPintervalSet(&maxact, 0.0);
    1688
    1689 vars = SCIPgetVars(scip);
    1690 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    1691
    1692 assert(redundant != NULL);
    1693 *redundant = FALSE;
    1694
    1695 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
    1696 for( i = 0; i < *cutnnz; ++i )
    1697 {
    1698 SCIP_Real val;
    1699
    1700 assert(cutinds[i] >= 0);
    1701 assert(vars[cutinds[i]] != NULL);
    1702
    1703 val = cutcoefs[cutinds[i]];
    1704
    1705 if( val < 0.0 )
    1706 {
    1707 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    1708
    1709 if( SCIPisInfinity(scip, -lb) )
    1710 return SCIP_OKAY;
    1711
    1712 if( cutinds[i] < nintegralvars )
    1713 maxabsintval = MAX(maxabsintval, -val);
    1714 else
    1715 {
    1716 maxabscontval = MAX(maxabscontval, -val);
    1717 isintegral = FALSE;
    1718 }
    1719
    1720 SCIPintervalSet(&tmp, val);
    1721 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, lb);
    1722 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
    1723 }
    1724 else
    1725 {
    1726 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    1727
    1728 if( SCIPisInfinity(scip, ub) )
    1729 return SCIP_OKAY;
    1730
    1731 if( cutinds[i] < nintegralvars )
    1732 maxabsintval = MAX(maxabsintval, val);
    1733 else
    1734 {
    1735 maxabscontval = MAX(maxabscontval, val);
    1736 isintegral = FALSE;
    1737 }
    1738
    1739 SCIPintervalSet(&tmp, val);
    1740 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, ub);
    1741 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
    1742 }
    1743 }
    1744
    1745 /* cut is redundant in activity bounds */
    1746 if( SCIPintervalGetSup(maxact) <= *cutrhs )
    1747 {
    1748 *redundant = TRUE;
    1749 return SCIP_OKAY;
    1750 }
    1751
    1752 previousroundmode = SCIPintervalGetRoundingMode();
    1753
    1754 /* cut is only on integral variables, try to scale to integral coefficients */
    1755 if( isintegral )
    1756 {
    1757 SCIP_Real equiscale;
    1758 SCIP_Real intscalar;
    1759 SCIP_Bool success;
    1760 SCIP_Real* intcoeffs;
    1761 SCIP_Real rhschange;
    1762
    1763 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
    1764
    1765 equiscale = 1.0 / MAX(maxabscontval, maxabsintval);
    1766
    1767 for( i = 0; i < *cutnnz; ++i )
    1768 {
    1769 SCIP_Real val;
    1770
    1771 val = cutcoefs[cutinds[i]];
    1772 val *= equiscale;
    1773
    1774 intcoeffs[i] = val;
    1775 }
    1776
    1778 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
    1779
    1780 SCIPfreeBufferArray(scip, &intcoeffs);
    1781
    1782 if( success )
    1783 {
    1784 /* if successful, apply the scaling */
    1786 intscalar *= equiscale;
    1787
    1788 *cutrhs *= intscalar;
    1789
    1790 if( SCIPisCertified(scip) )
    1791 {
    1792 assert(mirinfo != NULL);
    1793 mirinfo->scale = intscalar;
    1794 }
    1795
    1796 for( i = 0; i < *cutnnz; )
    1797 {
    1798 SCIP_Real val;
    1799 SCIP_Real intval;
    1800
    1801 val = cutcoefs[cutinds[i]];
    1802 val = scaleValSafely(scip, val, intscalar, cutislocal, vars[cutinds[i]], &rhschange, &success);
    1803
    1804 *cutrhs += rhschange;
    1805
    1806 if( !success )
    1807 {
    1808 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
    1809 *redundant = TRUE;
    1810 SCIPintervalSetRoundingMode(previousroundmode);
    1811 return SCIP_OKAY;
    1812 }
    1813 intval = SCIPround(scip, val);
    1814
    1815 if( chgCoeffWithBoundSafely(scip, vars[cutinds[i]], val, intval, cutislocal, cutrhs) )
    1816 {
    1817 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
    1818 SCIPintervalSetRoundingMode(previousroundmode);
    1819 *redundant = TRUE;
    1820 return SCIP_OKAY;
    1821 }
    1822
    1823 if( intval != 0.0 )
    1824 {
    1825 val = intval;
    1826 cutcoefs[cutinds[i]] = val;
    1827 ++i;
    1828 }
    1829 else
    1830 {
    1831 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
    1832 val = 0.0;
    1833 cutcoefs[cutinds[i]] = val;
    1834 --(*cutnnz);
    1835 cutinds[i] = cutinds[*cutnnz];
    1836 }
    1837 }
    1838
    1839 if( SCIPisCertified(scip) )
    1840 {
    1841 assert(mirinfo != NULL);
    1842 mirinfo->unroundedrhs = *cutrhs;
    1843 }
    1844 *cutrhs = floor(*cutrhs); /*lint !e835*/
    1845
    1846 /* recompute the maximal activity after scaling to integral values */
    1847 SCIPintervalSet(&maxact, 0.0);
    1848 maxabsintval = 0.0;
    1849
    1850 for( i = 0; i < *cutnnz; ++i )
    1851 {
    1852 SCIP_Real val;
    1853
    1854 assert(cutinds[i] >= 0);
    1855 assert(vars[cutinds[i]] != NULL);
    1856
    1857 val = cutcoefs[cutinds[i]];
    1858
    1859 if( val < 0.0 )
    1860 {
    1861 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    1862
    1863 maxabsintval = MAX(maxabsintval, -val);
    1864
    1865 SCIPintervalSet(&tmp, val);
    1866 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, lb);
    1867 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
    1868 }
    1869 else
    1870 {
    1871 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    1872
    1873 maxabsintval = MAX(maxabsintval, val);
    1874
    1875 SCIPintervalSet(&tmp, val);
    1876 SCIPintervalMulScalar(SCIPinfinity(scip), &tmp, tmp, ub);
    1877 SCIPintervalAdd(SCIPinfinity(scip), &maxact, maxact, tmp);
    1878 }
    1879 }
    1880
    1881 assert(EPSISINT(SCIPintervalGetSup(maxact), 1e-4));/*lint !e666*/
    1882 /* check again for redundancy */
    1883 if( SCIPisFeasLE(scip, SCIPintervalGetSup(maxact), *cutrhs) )
    1884 {
    1885 *redundant = TRUE;
    1886 SCIPintervalSetRoundingMode(previousroundmode);
    1887 return SCIP_OKAY;
    1888 }
    1889 }
    1890 else
    1891 {
    1892 /* otherwise, apply the equilibrium scaling */
    1893
    1894 /* perform the scaling */
    1895 SCIPintervalMulScalar(SCIPinfinity(scip), &maxact, maxact, equiscale);
    1897
    1898 *cutrhs *= equiscale;
    1899 maxabsintval *= equiscale;
    1900 if( SCIPisCertified(scip) )
    1901 {
    1902 assert(mirinfo != NULL);
    1903 mirinfo->scale = equiscale;
    1904 }
    1905
    1906 for( i = 0; i < *cutnnz; ++i )
    1907 {
    1908 SCIP_Real val;
    1909
    1910 val = cutcoefs[cutinds[i]];
    1911 val = scaleValSafely(scip, val, equiscale, cutislocal, vars[cutinds[i]], &rhschange, &success);
    1912
    1913 if( !success )
    1914 {
    1915 *redundant = TRUE;
    1916 SCIPintervalSetRoundingMode(previousroundmode);
    1917 return SCIP_OKAY;
    1918 }
    1919 cutcoefs[cutinds[i]] = val;
    1920 *cutrhs += rhschange;
    1921 }
    1922 }
    1923 }
    1924 else
    1925 {
    1926 /* cut has integer and continuous variables, so scale it to equilibrium */
    1927 SCIP_Real scale;
    1928 SCIP_Real maxabsval;
    1929 SCIP_Bool success;
    1930 SCIP_Real rhschange;
    1931
    1932 maxabsval = SCIPintervalGetSup(maxact) - *cutrhs;
    1933 maxabsval = MIN(maxabsval, maxabsintval);
    1934 maxabsval = MAX(maxabsval, maxabscontval);
    1935
    1936 scale = 1.0 / maxabsval; /*lint !e795*/
    1937
    1938 /* perform the scaling */
    1939 SCIPintervalSet(&maxact, scale);
    1941 *cutrhs *= scale;
    1942 maxabsintval *= scale;
    1943 if( SCIPisCertified(scip) )
    1944 {
    1945 assert(mirinfo != NULL);
    1946 mirinfo->scale = scale;
    1947 }
    1948
    1949 for( i = 0; i < *cutnnz; ++i )
    1950 {
    1951 SCIP_Real val;
    1952
    1953 val = cutcoefs[cutinds[i]];
    1954 val = scaleValSafely(scip, val, scale, cutislocal, vars[cutinds[i]], &rhschange, &success);
    1955
    1956 *cutrhs += rhschange;
    1957
    1958 if( !success )
    1959 {
    1960 *redundant = TRUE;
    1961 SCIPintervalSetRoundingMode(previousroundmode);
    1962 return SCIP_OKAY;
    1963 }
    1964 cutcoefs[cutinds[i]] = val;
    1965 }
    1966 }
    1967
    1968 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
    1969 if( SCIPisGT(scip, SCIPintervalGetSup(maxact) - maxabsintval, *cutrhs) )
    1970 {
    1971 SCIPintervalSetRoundingMode(previousroundmode);
    1972 return SCIP_OKAY;
    1973 }
    1974
    1975 SCIPsortDownInd(cutinds, compareAbsCoefs, (void*) cutcoefs, *cutnnz);
    1976
    1977#ifdef SCIP_DISABLED_CODE
    1978 /** @todo implement and certify coefficient tightening for cuts in exact solving mode */
    1979 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
    1980 for( i = 0; i < *cutnnz && FALSE; )
    1981 {
    1982 SCIP_Real QUAD(val);
    1983
    1984 if( cutinds[i] >= nintegralvars )
    1985 {
    1986 ++i;
    1987 continue;
    1988 }
    1989
    1990 QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
    1991
    1992 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
    1993
    1994 if( QUAD_TO_DBL(val) < 0.0 && SCIPisLE(scip, maxact + QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
    1995 {
    1996 SCIP_Real QUAD(coef);
    1997 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    1998
    1999 SCIPquadprecSumQQ(coef, *cutrhs, -maxacttmp);
    2000
    2001 if( isintegral )
    2002 {
    2003 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    2004 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    2005 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    2006 }
    2007
    2008 if( QUAD_TO_DBL(coef) > QUAD_TO_DBL(val) )
    2009 {
    2010 SCIP_Real QUAD(delta);
    2011 SCIP_Real QUAD(tmp);
    2012
    2013 SCIPquadprecSumQQ(delta, -val, coef);
    2014 SCIPquadprecProdQD(delta, delta, lb);
    2015
    2016 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    2017 SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2018 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
    2019 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
    2020
    2021 QUAD_ASSIGN_Q(*cutrhs, tmp);
    2022
    2023 assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
    2024
    2025 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
    2026 {
    2027 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2028 maxact = QUAD_TO_DBL(maxacttmp);
    2029 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    2030 }
    2031 else
    2032 {
    2033 QUAD_ASSIGN(coef, 0.0);
    2034 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    2035 --(*cutnnz);
    2036 cutinds[i] = cutinds[*cutnnz];
    2037 continue;
    2038 }
    2039 }
    2040 }
    2041 else if( QUAD_TO_DBL(val) > 0.0 && SCIPisLE(scip, maxact - QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
    2042 {
    2043 SCIP_Real QUAD(coef);
    2044 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2045
    2046 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
    2047
    2048 if( isintegral )
    2049 {
    2050 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    2051 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    2052 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    2053 }
    2054
    2055 if( QUAD_TO_DBL(coef) < QUAD_TO_DBL(val) )
    2056 {
    2057 SCIP_Real QUAD(delta);
    2058 SCIP_Real QUAD(tmp);
    2059
    2060 SCIPquadprecSumQQ(delta, -val, coef);
    2061 SCIPquadprecProdQD(delta, delta, ub);
    2062
    2063 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    2064 SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2065 QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
    2066 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
    2067
    2068 QUAD_ASSIGN_Q(*cutrhs, tmp);
    2069
    2070 assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
    2071
    2072 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
    2073 {
    2074 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2075 maxact = QUAD_TO_DBL(maxacttmp);
    2076 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    2077 }
    2078 else
    2079 {
    2080 QUAD_ASSIGN(coef, 0.0);
    2081 QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
    2082 --(*cutnnz);
    2083 cutinds[i] = cutinds[*cutnnz];
    2084 continue;
    2085 }
    2086 }
    2087 }
    2088 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
    2089 break;
    2090
    2091 ++i;
    2092 }
    2093#endif /*lint --e{438}*/
    2094
    2095 return SCIP_OKAY;
    2096}
    2097
    2098
    2099/** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
    2100 * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse array;
    2101 */
    2102static
    2104 SCIP* scip, /**< SCIP data structure */
    2105 SCIP_Bool cutislocal, /**< is the cut local? */
    2106 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    2107 QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
    2108 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    2109 int* cutnnz, /**< the number of non-zeros in the cut */
    2110 SCIP_Bool* redundant /**< pointer to return whtether the cut was detected to be redundant */
    2111 )
    2112{
    2113 int i;
    2114 int nintegralvars;
    2115 SCIP_Bool isintegral = TRUE;
    2116 SCIP_VAR** vars;
    2117 SCIP_Real QUAD(maxacttmp);
    2118 SCIP_Real maxact;
    2119 SCIP_Real maxabsintval = 0.0;
    2120 SCIP_Real maxabscontval = 0.0;
    2121
    2122 assert(!SCIPisExact(scip));
    2123
    2124 QUAD_ASSIGN(maxacttmp, 0.0);
    2125
    2126 vars = SCIPgetVars(scip);
    2127 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    2128
    2129 assert(redundant != NULL);
    2130 *redundant = FALSE;
    2131
    2132 /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
    2133 for( i = 0; i < *cutnnz; ++i )
    2134 {
    2135 SCIP_Real val;
    2136 SCIP_Real QUAD(quadprod);
    2137
    2138 assert(cutinds[i] >= 0);
    2139 assert(vars[cutinds[i]] != NULL);
    2140
    2141 val = cutcoefs[cutinds[i]];
    2142
    2143 if( val < 0.0 )
    2144 {
    2145 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    2146
    2147 if( SCIPisInfinity(scip, -lb) )
    2148 return SCIP_OKAY;
    2149
    2150 if( cutinds[i] < nintegralvars )
    2151 maxabsintval = MAX(maxabsintval, -val);
    2152 else
    2153 {
    2154 maxabscontval = MAX(maxabscontval, -val);
    2155 isintegral = FALSE;
    2156 }
    2157
    2158 SCIPquadprecProdDD(quadprod, val, lb);
    2159 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2160 }
    2161 else
    2162 {
    2163 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2164
    2165 if( SCIPisInfinity(scip, ub) )
    2166 return SCIP_OKAY;
    2167
    2168 if( cutinds[i] < nintegralvars )
    2169 maxabsintval = MAX(maxabsintval, val);
    2170 else
    2171 {
    2172 maxabscontval = MAX(maxabscontval, val);
    2173 isintegral = FALSE;
    2174 }
    2175
    2176 SCIPquadprecProdDD(quadprod, val, ub);
    2177 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2178 }
    2179 }
    2180
    2181 maxact = QUAD_TO_DBL(maxacttmp);
    2182
    2183 /* cut is redundant in activity bounds */
    2184 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
    2185 {
    2186 *redundant = TRUE;
    2187 return SCIP_OKAY;
    2188 }
    2189
    2190 /* cut is only on integral variables, try to scale to integral coefficients */
    2191 if( isintegral )
    2192 {
    2193 SCIP_Real equiscale;
    2194 SCIP_Real intscalar;
    2195 SCIP_Bool success;
    2196 SCIP_Real* intcoeffs;
    2197
    2198 SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
    2199
    2200 equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
    2201
    2202 for( i = 0; i < *cutnnz; ++i )
    2203 {
    2204 SCIP_Real val;
    2205
    2206 val = equiscale * cutcoefs[cutinds[i]];
    2207
    2208 intcoeffs[i] = val;
    2209 }
    2210
    2212 (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
    2213
    2214 SCIPfreeBufferArray(scip, &intcoeffs);
    2215
    2216 if( success )
    2217 {
    2218 /* if successful, apply the scaling */
    2219 intscalar *= equiscale;
    2220 SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
    2221
    2222 for( i = 0; i < *cutnnz; )
    2223 {
    2224 SCIP_Real val;
    2225 SCIP_Real intval;
    2226
    2227 val = cutcoefs[cutinds[i]];
    2228 val *= intscalar;
    2229
    2230 intval = SCIPround(scip, val);
    2231
    2232 if( chgCoeffWithBound(scip, vars[cutinds[i]], val, intval, cutislocal, QUAD(cutrhs)) )
    2233 {
    2234 /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
    2235 *redundant = TRUE;
    2236 return SCIP_OKAY;
    2237 }
    2238
    2239 if( intval != 0.0 )
    2240 {
    2241 cutcoefs[cutinds[i]] = intval;
    2242 ++i;
    2243 }
    2244 else
    2245 {
    2246 /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
    2247 cutcoefs[cutinds[i]] = 0.0;
    2248 --(*cutnnz);
    2249 cutinds[i] = cutinds[*cutnnz];
    2250 }
    2251 }
    2252
    2253 SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
    2254
    2255 /* recompute the maximal activity after scaling to integral values */
    2256 QUAD_ASSIGN(maxacttmp, 0.0);
    2257 maxabsintval = 0.0;
    2258
    2259 for( i = 0; i < *cutnnz; ++i )
    2260 {
    2261 SCIP_Real val;
    2262 SCIP_Real QUAD(quadprod);
    2263
    2264 assert(cutinds[i] >= 0);
    2265 assert(vars[cutinds[i]] != NULL);
    2266
    2267 val = cutcoefs[cutinds[i]];
    2268
    2269 if( val < 0.0 )
    2270 {
    2271 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    2272
    2273 maxabsintval = MAX(maxabsintval, -val);
    2274
    2275 SCIPquadprecProdDD(quadprod, val, lb);
    2276 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2277 }
    2278 else
    2279 {
    2280 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2281
    2282 maxabsintval = MAX(maxabsintval, val);
    2283
    2284 SCIPquadprecProdDD(quadprod, val, ub);
    2285 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2286 }
    2287 }
    2288
    2289 assert(EPSISINT(QUAD_TO_DBL(maxacttmp), 1e-4));
    2290 SCIPquadprecSumQD(maxacttmp, maxacttmp, 0.5);
    2291 SCIPquadprecFloorQ(maxacttmp, maxacttmp);
    2292 }
    2293 else
    2294 {
    2295 /* otherwise, apply the equilibrium scaling */
    2296 isintegral = FALSE;
    2297
    2298 /* perform the scaling */
    2299 SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
    2300 SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
    2301 maxabsintval *= equiscale;
    2302
    2303 for( i = 0; i < *cutnnz; ++i )
    2304 cutcoefs[cutinds[i]] *= equiscale;
    2305 }
    2306 }
    2307 else
    2308 {
    2309 /* cut has integer and continuous variables, so scale it to equilibrium */
    2310 SCIP_Real scale;
    2311 SCIP_Real maxabsval;
    2312
    2313 maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
    2314 maxabsval = MIN(maxabsval, maxabsintval);
    2315 maxabsval = MAX(maxabsval, maxabscontval);
    2316
    2317 scale = 1.0 / maxabsval; /*lint !e795*/
    2318
    2319 /* perform the scaling */
    2320 SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
    2321 SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
    2322 maxabsintval *= scale;
    2323
    2324 for( i = 0; i < *cutnnz; ++i )
    2325 cutcoefs[cutinds[i]] *= scale;
    2326 }
    2327
    2328 maxact = QUAD_TO_DBL(maxacttmp);
    2329
    2330 /* check again for redundancy after scaling */
    2331 if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
    2332 {
    2333 *redundant = TRUE;
    2334 return SCIP_OKAY;
    2335 }
    2336
    2337 /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
    2338 if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
    2339 return SCIP_OKAY;
    2340
    2341 /* 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 */
    2342 SCIPsortInt(cutinds, *cutnnz);
    2343 SCIPsortDownInd(cutinds, compareAbsCoefs, (void*) cutcoefs, *cutnnz);
    2344
    2345 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
    2346 for( i = 0; i < *cutnnz; )
    2347 {
    2348 SCIP_Real val;
    2349
    2350 if( cutinds[i] >= nintegralvars )
    2351 {
    2352 ++i;
    2353 continue;
    2354 }
    2355
    2356 val = cutcoefs[cutinds[i]];
    2357
    2358 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
    2359
    2360 if( val < 0.0 && SCIPisLE(scip, maxact + val, QUAD_TO_DBL(*cutrhs)) )
    2361 {
    2362 SCIP_Real QUAD(coef);
    2363 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    2364
    2365 SCIPquadprecSumQQ(coef, -maxacttmp, *cutrhs);
    2366
    2367 if( isintegral )
    2368 {
    2369 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    2370 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    2371 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    2372 }
    2373
    2374 if( QUAD_TO_DBL(coef) > val )
    2375 {
    2376 SCIP_Real QUAD(delta);
    2377 SCIP_Real QUAD(tmp);
    2378
    2379 SCIPquadprecSumQD(delta, coef, -val);
    2380 SCIPquadprecProdQD(delta, delta, lb);
    2381
    2382 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    2383 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2384 val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
    2385 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
    2386
    2387 QUAD_ASSIGN_Q(*cutrhs, tmp);
    2388
    2389 assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
    2390
    2391 if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
    2392 {
    2393 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2394 maxact = QUAD_TO_DBL(maxacttmp);
    2395 cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
    2396 }
    2397 else
    2398 {
    2399 cutcoefs[cutinds[i]] = 0.0;
    2400 --(*cutnnz);
    2401 cutinds[i] = cutinds[*cutnnz];
    2402 continue;
    2403 }
    2404 }
    2405 }
    2406 else if( val > 0.0 && SCIPisLE(scip, maxact - val, QUAD_TO_DBL(*cutrhs)) )
    2407 {
    2408 SCIP_Real QUAD(coef);
    2409 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2410
    2411 SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
    2412
    2413 if( isintegral )
    2414 {
    2415 /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
    2416 assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
    2417 QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
    2418 }
    2419
    2420 if( QUAD_TO_DBL(coef) < val )
    2421 {
    2422 SCIP_Real QUAD(delta);
    2423 SCIP_Real QUAD(tmp);
    2424
    2425 SCIPquadprecSumQD(delta, coef, -val);
    2426 SCIPquadprecProdQD(delta, delta, ub);
    2427
    2428 SCIPquadprecSumQQ(tmp, delta, *cutrhs);
    2429 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2430 val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
    2431 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
    2432
    2433 QUAD_ASSIGN_Q(*cutrhs, tmp);
    2434
    2435 assert(! SCIPisNegative(scip, QUAD_TO_DBL(coef)));
    2436
    2437 if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
    2438 {
    2439 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2440 maxact = QUAD_TO_DBL(maxacttmp);
    2441 cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
    2442 }
    2443 else
    2444 {
    2445 cutcoefs[cutinds[i]] = 0.0;
    2446 --(*cutnnz);
    2447 cutinds[i] = cutinds[*cutnnz];
    2448 continue;
    2449 }
    2450 }
    2451 }
    2452 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
    2453 break;
    2454
    2455 ++i;
    2456 }
    2457
    2458 return SCIP_OKAY;
    2459}
    2460
    2461/** perform activity based coefficient tightening on the given cut; returns TRUE if the cut was detected
    2462 * to be redundant due to activity bounds
    2463 *
    2464 * See also cons_linear.c:consdataTightenCoefs().
    2465 */
    2467 SCIP* scip, /**< SCIP data structure */
    2468 SCIP_Bool cutislocal, /**< is the cut local? */
    2469 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    2470 SCIP_Real* cutrhs, /**< the right hand side of the cut */
    2471 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    2472 int* cutnnz, /**< the number of non-zeros in the cut */
    2473 int* nchgcoefs /**< number of changed coefficients */
    2474 )
    2475{
    2476 int i;
    2477 int nintegralvars;
    2478 SCIP_VAR** vars;
    2479 SCIP_Real* absvals;
    2480 SCIP_Real QUAD(maxacttmp);
    2481 SCIP_Real maxact;
    2482 SCIP_Real maxabsval = 0.0;
    2483 SCIP_Bool redundant = FALSE;
    2484
    2485 assert(nchgcoefs != NULL);
    2486
    2487 QUAD_ASSIGN(maxacttmp, 0.0);
    2488
    2489 vars = SCIPgetVars(scip);
    2490 nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    2491 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &absvals, *cutnnz) );
    2492
    2493 assert(nchgcoefs != NULL);
    2494 *nchgcoefs = 0;
    2495
    2496 for( i = 0; i < *cutnnz; ++i )
    2497 {
    2498 SCIP_Real QUAD(quadprod);
    2499
    2500 assert(cutinds[i] >= 0);
    2501 assert(vars[cutinds[i]] != NULL);
    2502
    2503 if( cutcoefs[i] < 0.0 )
    2504 {
    2505 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    2506
    2507 if( SCIPisInfinity(scip, -lb) )
    2508 goto TERMINATE;
    2509
    2510 if( cutinds[i] < nintegralvars )
    2511 {
    2512 maxabsval = MAX(maxabsval, -cutcoefs[i]);
    2513 absvals[i] = -cutcoefs[i];
    2514 }
    2515 else
    2516 absvals[i] = 0.0;
    2517
    2518 SCIPquadprecProdDD(quadprod, lb, cutcoefs[i]);
    2519 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2520 }
    2521 else
    2522 {
    2523 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2524
    2525 if( SCIPisInfinity(scip, ub) )
    2526 goto TERMINATE;
    2527
    2528 if( cutinds[i] < nintegralvars )
    2529 {
    2530 maxabsval = MAX(maxabsval, cutcoefs[i]);
    2531 absvals[i] = cutcoefs[i];
    2532 }
    2533 else
    2534 absvals[i] = 0.0;
    2535
    2536 SCIPquadprecProdDD(quadprod, ub, cutcoefs[i]);
    2537 SCIPquadprecSumQQ(maxacttmp, maxacttmp, quadprod);
    2538 }
    2539 }
    2540
    2541 maxact = QUAD_TO_DBL(maxacttmp);
    2542
    2543 /* cut is redundant in activity bounds */
    2544 if( SCIPisFeasLE(scip, maxact, *cutrhs) )
    2545 {
    2546 redundant = TRUE;
    2547 goto TERMINATE;
    2548 }
    2549
    2550 /* terminate, because coefficient tightening cannot be performed; also excludes the case in which no integral variable is present */
    2551 if( SCIPisGT(scip, maxact - maxabsval, *cutrhs) )
    2552 goto TERMINATE;
    2553
    2554 SCIPsortDownRealRealInt(absvals, cutcoefs, cutinds, *cutnnz);
    2555 SCIPfreeBufferArray(scip, &absvals);
    2556
    2557 /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
    2558 for( i = 0; i < *cutnnz; ++i )
    2559 {
    2560 /* due to sorting, we can exit if we reached a continuous variable: all further integral variables have 0 coefficents anyway */
    2561 if( cutinds[i] >= nintegralvars )
    2562 break;
    2563
    2564 assert(SCIPvarIsIntegral(vars[cutinds[i]]));
    2565
    2566 if( cutcoefs[i] < 0.0 && SCIPisLE(scip, maxact + cutcoefs[i], *cutrhs) )
    2567 {
    2568 SCIP_Real coef = (*cutrhs) - maxact;
    2569 SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
    2570
    2571 coef = SCIPfloor(scip, coef);
    2572
    2573 if( coef > cutcoefs[i] )
    2574 {
    2575 SCIP_Real QUAD(delta);
    2576 SCIP_Real QUAD(tmp);
    2577
    2578 SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
    2579 SCIPquadprecProdQD(delta, delta, lb);
    2580
    2581 SCIPquadprecSumQD(tmp, delta, *cutrhs);
    2582 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2583 cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp), lb,
    2584 cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
    2585
    2586 *cutrhs = QUAD_TO_DBL(tmp);
    2587
    2588 assert(!SCIPisPositive(scip, coef));
    2589
    2590 ++(*nchgcoefs);
    2591
    2592 if( SCIPisNegative(scip, coef) )
    2593 {
    2594 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2595 maxact = QUAD_TO_DBL(maxacttmp);
    2596 cutcoefs[i] = coef;
    2597 }
    2598 else
    2599 {
    2600 --(*cutnnz);
    2601 cutinds[i] = cutinds[*cutnnz];
    2602 cutcoefs[i] = cutcoefs[*cutnnz];
    2603 continue;
    2604 }
    2605 }
    2606 }
    2607 else if( cutcoefs[i] > 0.0 && SCIPisLE(scip, maxact - cutcoefs[i], *cutrhs) )
    2608 {
    2609 SCIP_Real coef = maxact - (*cutrhs);
    2610 SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
    2611
    2612 coef = SCIPceil(scip, coef);
    2613
    2614 if( coef < cutcoefs[i] )
    2615 {
    2616 SCIP_Real QUAD(delta);
    2617 SCIP_Real QUAD(tmp);
    2618
    2619 SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
    2620 SCIPquadprecProdQD(delta, delta, ub);
    2621
    2622 SCIPquadprecSumQD(tmp, delta, *cutrhs);
    2623 SCIPdebugMsg(scip, "tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
    2624 cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp),
    2625 cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
    2626
    2627 *cutrhs = QUAD_TO_DBL(tmp);
    2628
    2629 assert(!SCIPisNegative(scip, coef));
    2630
    2631 ++(*nchgcoefs);
    2632
    2633 if( SCIPisPositive(scip, coef) )
    2634 {
    2635 SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
    2636 maxact = QUAD_TO_DBL(maxacttmp);
    2637 cutcoefs[i] = coef;
    2638 }
    2639 else
    2640 {
    2641 --(*cutnnz);
    2642 cutinds[i] = cutinds[*cutnnz];
    2643 cutcoefs[i] = cutcoefs[*cutnnz];
    2644 continue;
    2645 }
    2646 }
    2647 }
    2648 else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
    2649 break;
    2650 }
    2651
    2652 TERMINATE:
    2653 SCIPfreeBufferArrayNull(scip, &absvals);
    2654
    2655 return redundant;
    2656}
    2657
    2658/* =========================================== aggregation row =========================================== */
    2659
    2660
    2661/** create an empty aggregation row
    2662 *
    2663 * @note By default, this data structure uses quad precision via double-double arithmetic, i.e., it allocates a
    2664 * SCIP_Real array of length two times SCIPgetNVars() for storing the coefficients. In exact solving mode, we
    2665 * cannot use quad precision because we need to control the ronding mode, hence only the first SCIPgetNVars()
    2666 * entries are used.
    2667 */
    2669 SCIP* scip, /**< SCIP data structure */
    2670 SCIP_AGGRROW** aggrrow /**< pointer to return aggregation row */
    2671 )
    2672{
    2673 int nvars;
    2674 assert(scip != NULL);
    2675 assert(aggrrow != NULL);
    2676
    2677 SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
    2678
    2679 nvars = SCIPgetNVars(scip);
    2680
    2681 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)) );
    2682 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->inds, nvars) );
    2683
    2684 BMSclearMemoryArray((*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars));
    2685
    2686 (*aggrrow)->local = FALSE;
    2687 (*aggrrow)->nnz = 0;
    2688 (*aggrrow)->rank = 0;
    2689 QUAD_ASSIGN((*aggrrow)->rhs, 0.0);
    2690 (*aggrrow)->rowsinds = NULL;
    2691 (*aggrrow)->slacksign = NULL;
    2692 (*aggrrow)->rowweights = NULL;
    2693 (*aggrrow)->nrows = 0;
    2694 (*aggrrow)->rowssize = 0;
    2695
    2696 return SCIP_OKAY;
    2697}
    2698
    2699/** free a aggregation row */
    2701 SCIP* scip, /**< SCIP data structure */
    2702 SCIP_AGGRROW** aggrrow /**< pointer to aggregation row that should be freed */
    2703 )
    2704{
    2705 int nvars;
    2706
    2707 assert(scip != NULL);
    2708 assert(aggrrow != NULL);
    2709
    2710 nvars = SCIPgetNVars(scip);
    2711
    2712 SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->inds, nvars);
    2713 SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)); /*lint !e647*/
    2714 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowsinds, (*aggrrow)->rowssize);
    2715 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->slacksign, (*aggrrow)->rowssize);
    2716 SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowweights, (*aggrrow)->rowssize);
    2717 SCIPfreeBlockMemory(scip, aggrrow);
    2718}
    2719
    2720/** output aggregation row to file stream */
    2722 SCIP* scip, /**< SCIP data structure */
    2723 SCIP_AGGRROW* aggrrow, /**< pointer to return aggregation row */
    2724 FILE* file /**< output file (or NULL for standard output) */
    2725 )
    2726{
    2727 SCIP_VAR** vars;
    2728 SCIP_MESSAGEHDLR* messagehdlr;
    2729 int i;
    2730
    2731 assert(scip != NULL);
    2732 assert(aggrrow != NULL);
    2733
    2734 vars = SCIPgetVars(scip);
    2735 assert(vars != NULL);
    2736
    2737 messagehdlr = SCIPgetMessagehdlr(scip);
    2738 assert(messagehdlr);
    2739
    2740 /* print coefficients */
    2741 if( aggrrow->nnz == 0 )
    2742 SCIPmessageFPrintInfo(messagehdlr, file, "0 ");
    2743
    2744 for( i = 0; i < aggrrow->nnz; ++i )
    2745 {
    2746 SCIP_Real QUAD(val);
    2747
    2748 QUAD_ARRAY_LOAD(val, aggrrow->vals, aggrrow->inds[i]);
    2749 assert(SCIPvarGetProbindex(vars[aggrrow->inds[i]]) == aggrrow->inds[i]);
    2750 SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", QUAD_TO_DBL(val), SCIPvarGetName(vars[aggrrow->inds[i]]));
    2751 }
    2752
    2753 /* print right hand side */
    2754 SCIPmessageFPrintInfo(messagehdlr, file, "<= %.15g\n", QUAD_TO_DBL(aggrrow->rhs));
    2755}
    2756
    2757/** copy a aggregation row */
    2759 SCIP* scip, /**< SCIP data structure */
    2760 SCIP_AGGRROW** aggrrow, /**< pointer to return aggregation row */
    2761 SCIP_AGGRROW* source /**< source aggregation row */
    2762 )
    2763{
    2764 int nvars;
    2765
    2766 assert(scip != NULL);
    2767 assert(aggrrow != NULL);
    2768 assert(source != NULL);
    2769
    2770 nvars = SCIPgetNVars(scip);
    2771 SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
    2772
    2773 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->vals, source->vals, QUAD_ARRAY_SIZE(nvars)) );
    2774 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->inds, source->inds, nvars) );
    2775 (*aggrrow)->nnz = source->nnz;
    2776 QUAD_ASSIGN_Q((*aggrrow)->rhs, source->rhs);
    2777
    2778 if( source->nrows > 0 )
    2779 {
    2780 assert(source->rowsinds != NULL);
    2781 assert(source->slacksign != NULL);
    2782 assert(source->rowweights != NULL);
    2783
    2784 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowsinds, source->rowsinds, source->nrows) );
    2785 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->slacksign, source->slacksign, source->nrows) );
    2786 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowweights, source->rowweights, source->nrows) );
    2787 }
    2788 else
    2789 {
    2790 (*aggrrow)->rowsinds = NULL;
    2791 (*aggrrow)->slacksign = NULL;
    2792 (*aggrrow)->rowweights = NULL;
    2793 }
    2794
    2795 (*aggrrow)->nrows = source->nrows;
    2796 (*aggrrow)->rowssize = source->nrows;
    2797 (*aggrrow)->rank = source->rank;
    2798 (*aggrrow)->local = source->local;
    2799
    2800 return SCIP_OKAY;
    2801}
    2802
    2803/** add weighted row to aggregation row */
    2805 SCIP* scip, /**< SCIP data structure */
    2806 SCIP_AGGRROW* aggrrow, /**< aggregation row */
    2807 SCIP_ROW* row, /**< row to add to aggregation row */
    2808 SCIP_Real weight, /**< scale for adding given row to aggregation row */
    2809 int sidetype /**< specify row side type (-1 = lhs, 0 = automatic, 1 = rhs) */
    2810 )
    2811{
    2812 SCIP_Real QUAD(quadprod);
    2813 SCIP_Real sideval;
    2814 SCIP_Bool uselhs;
    2815 int i;
    2816
    2817 assert(row->lppos >= 0);
    2818
    2819 /* update local flag */
    2820 aggrrow->local = aggrrow->local || row->local;
    2821
    2822 /* update rank */
    2823 aggrrow->rank = MAX(row->rank, aggrrow->rank);
    2824
    2825 i = aggrrow->nrows++;
    2826
    2827 if( aggrrow->nrows > aggrrow->rowssize )
    2828 {
    2829 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
    2830 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
    2831 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
    2832 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
    2833 aggrrow->rowssize = newsize;
    2834 }
    2835 aggrrow->rowsinds[i] = SCIProwGetLPPos(row);
    2836 aggrrow->rowweights[i] = weight;
    2837
    2838 if( sidetype == -1 )
    2839 {
    2840 assert( ! SCIPisInfinity(scip, -row->lhs) );
    2841 uselhs = TRUE;
    2842 }
    2843 else if( sidetype == 1 )
    2844 {
    2845 assert( ! SCIPisInfinity(scip, row->rhs) );
    2846 uselhs = FALSE;
    2847 }
    2848 else
    2849 {
    2850 /* Automatically decide, whether we want to use the left or the right hand side of the row in the summation.
    2851 * If possible, use the side that leads to a positive slack value in the summation.
    2852 */
    2853 if( SCIPisInfinity(scip, row->rhs) || (!SCIPisInfinity(scip, -row->lhs) && weight < 0.0) )
    2854 uselhs = TRUE;
    2855 else
    2856 uselhs = FALSE;
    2857 }
    2858
    2859 if( uselhs )
    2860 {
    2861 aggrrow->slacksign[i] = -1;
    2862 sideval = row->lhs - row->constant;
    2863 if( row->integral )
    2864 sideval = SCIPceil(scip, sideval); /* row is integral: round left hand side up */
    2865 }
    2866 else
    2867 {
    2868 aggrrow->slacksign[i] = +1;
    2869 sideval = row->rhs - row->constant;
    2870 if( row->integral )
    2871 sideval = SCIPfloor(scip, sideval); /* row is integral: round right hand side up */
    2872 }
    2873
    2874 SCIPquadprecProdDD(quadprod, weight, sideval);
    2875 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
    2876
    2877 /* add up coefficients */
    2878 SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
    2879
    2880 return SCIP_OKAY;
    2881}
    2882
    2883/** add weighted row to aggregation row
    2884 *
    2885 * @note this method is the variant of SCIPaggrRowAddRow that is safe to use in exact solving mode
    2886 */
    2888 SCIP* scip, /**< SCIP data structure */
    2889 SCIP_AGGRROW* aggrrow, /**< aggregation row */
    2890 SCIP_ROW* row, /**< row to add to aggregation row */
    2891 SCIP_Real weight, /**< scale for adding given row to aggregation row */
    2892 int sidetype, /**< specify row side type (-1 = lhs, 0 = automatic, 1 = rhs) */
    2893 SCIP_Bool* success /**< was the row added successfully */
    2894 )
    2895{
    2896 SCIP_Real sideval;
    2897 SCIP_Real sidevalchg;
    2898 SCIP_Bool uselhs;
    2899 SCIP_ROW* userow;
    2900 SCIP_ROWEXACT* rowexact;
    2901 SCIP_ROUNDMODE previousroundmode;
    2902 int i;
    2903
    2904 assert(SCIPisExact(scip));
    2905 assert(success != NULL);
    2906
    2907 /* update local flag */
    2908 aggrrow->local = aggrrow->local || row->local;
    2909
    2910 /* update rank */
    2911 aggrrow->rank = MAX(row->rank, aggrrow->rank);
    2912
    2913 i = aggrrow->nrows++;
    2914
    2915 if( aggrrow->nrows > aggrrow->rowssize )
    2916 {
    2917 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
    2918 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
    2919 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
    2920 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
    2921 aggrrow->rowssize = newsize;
    2922 }
    2923 aggrrow->rowsinds[i] = SCIProwGetLPPos(row);
    2924 aggrrow->rowweights[i] = weight;
    2925
    2926 if( sidetype == -1 )
    2927 {
    2928 assert(!SCIPisInfinity(scip, -row->lhs));
    2929 uselhs = TRUE;
    2930 }
    2931 else if( sidetype == 1 )
    2932 {
    2933 assert(!SCIPisInfinity(scip, row->rhs));
    2934 uselhs = FALSE;
    2935 }
    2936 else
    2937 {
    2938 /* Automatically decide, whether we want to use the left or the right hand side of the row in the summation.
    2939 * If possible, use the side that leads to a positive slack value in the summation.
    2940 */
    2941 if( SCIPisInfinity(scip, row->rhs) || (!SCIPisInfinity(scip, -row->lhs) && weight < 0.0) )
    2942 uselhs = TRUE;
    2943 else
    2944 uselhs = FALSE;
    2945 }
    2946 rowexact = SCIProwGetRowExact(row);
    2947 if( !SCIProwExactHasFpRelax(rowexact) )
    2948 {
    2949 *success = FALSE;
    2950 return SCIP_OKAY;
    2951 }
    2952 else if( SCIProwExactGetRowRhs(rowexact) != NULL && weight >= 0.0 )
    2953 userow = SCIProwExactGetRowRhs(rowexact);
    2954 else
    2955 userow = row;
    2956
    2957 aggrrow->slacksign[i] = uselhs ? -1 : 1;
    2958
    2959 previousroundmode = SCIPintervalGetRoundingMode();
    2960
    2961 if( uselhs )
    2962 {
    2964 sideval = userow->lhs - userow->constant;
    2965#ifdef SCIP_DISABLED_CODE
    2966 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
    2967 /* row is integral? round left hand side up */
    2968 if( userow->integral )
    2969 sideval = ceil(sideval)
    2970#endif
    2971 }
    2972 else
    2973 {
    2975 sideval = userow->rhs - 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 right hand side down */
    2979 if( userow->integral )
    2980 sideval = floor(sideval);
    2981#endif
    2982 }
    2983
    2985 sidevalchg = QUAD_TO_DBL(aggrrow->rhs);
    2986 sidevalchg += sideval * weight;
    2987 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
    2988
    2989 /* add up coefficients */
    2990 *success = TRUE;
    2991 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, aggrrow->inds, aggrrow->vals, &aggrrow->nnz, userow, weight, &sidevalchg, success) );
    2992
    2993 sidevalchg += QUAD_TO_DBL(aggrrow->rhs);
    2994 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
    2995
    2996 SCIPintervalSetRoundingMode(previousroundmode);
    2997
    2998 return SCIP_OKAY;
    2999}
    3000
    3001/** Removes a given variable @p var from position @p pos the aggregation row and updates the right-hand side according
    3002 * to sign of the coefficient, i.e., rhs -= coef * bound, where bound = lb if coef >= 0 and bound = ub, otherwise.
    3003 *
    3004 * @note: The choice of global or local bounds depend on the validity (global or local) of the aggregation row.
    3005 *
    3006 * @note: The list of non-zero indices will be updated by swapping the last non-zero index to @p pos.
    3007 */
    3009 SCIP* scip, /**< SCIP data structure */
    3010 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3011 SCIP_VAR* var, /**< variable that should be removed */
    3012 int pos, /**< position of the variable in the aggregation row */
    3013 SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
    3014 )
    3015{
    3016 SCIP_Real QUAD(val);
    3017 int v;
    3018
    3019 assert(valid != NULL);
    3020 assert(pos >= 0);
    3021
    3022 v = aggrrow->inds[pos];
    3023 assert(v == SCIPvarGetProbindex(var));
    3024
    3025 QUAD_ARRAY_LOAD(val, aggrrow->vals, v);
    3026
    3027 *valid = TRUE;
    3028
    3029 /* adjust left and right hand sides with max contribution */
    3030 if( QUAD_TO_DBL(val) < 0.0 )
    3031 {
    3032 SCIP_Real ub = aggrrow->local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
    3033
    3034 if( SCIPisInfinity(scip, ub) )
    3035 QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
    3036 else
    3037 {
    3038 SCIPquadprecProdQD(val, val, ub);
    3039 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
    3040 }
    3041 }
    3042 else
    3043 {
    3044 SCIP_Real lb = aggrrow->local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
    3045
    3046 if( SCIPisInfinity(scip, -lb) )
    3047 QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
    3048 else
    3049 {
    3050 SCIPquadprecProdQD(val, val, lb);
    3051 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
    3052 }
    3053 }
    3054
    3055 QUAD_ASSIGN(val, 0.0);
    3056 QUAD_ARRAY_STORE(aggrrow->vals, v, val);
    3057
    3058 /* remove non-zero entry */
    3059 --(aggrrow->nnz);
    3060 aggrrow->inds[pos] = aggrrow->inds[aggrrow->nnz];
    3061
    3062 if( SCIPisInfinity(scip, QUAD_HI(aggrrow->rhs)) )
    3063 *valid = FALSE;
    3064}
    3065
    3066/** add the objective function with right-hand side @p rhs and scaled by @p scale to the aggregation row */
    3068 SCIP* scip, /**< SCIP data structure */
    3069 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3070 SCIP_Real rhs, /**< right-hand side of the artificial row */
    3071 SCIP_Real scale /**< scalar */
    3072 )
    3073{
    3074 SCIP_VAR** vars;
    3075 SCIP_Real QUAD(val);
    3076 int nvars;
    3077
    3078 assert(scip != NULL);
    3079 assert(aggrrow != NULL);
    3080
    3081 vars = SCIPgetVars(scip);
    3082 nvars = SCIPgetNVars(scip);
    3083
    3084 /* add all variables straight forward if the aggregation row is empty */
    3085 if( aggrrow->nnz == 0 )
    3086 {
    3087 int i;
    3088 for( i = 0; i < nvars; ++i )
    3089 {
    3090 assert(SCIPvarGetProbindex(vars[i]) == i);
    3091
    3092 /* skip all variables with zero objective coefficient */
    3093 if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
    3094 continue;
    3095
    3096 QUAD_ASSIGN(val, scale * SCIPvarGetObj(vars[i])); /*lint !e665*/
    3097 QUAD_ARRAY_STORE(aggrrow->vals, i, val);
    3098 aggrrow->inds[aggrrow->nnz++] = i;
    3099 }
    3100
    3101 /* add right-hand side value */
    3102 QUAD_ASSIGN(aggrrow->rhs, scale * rhs); /*lint !e665*/
    3103 }
    3104 else
    3105 {
    3106 int i;
    3107 SCIP_Real QUAD(quadprod);
    3108 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    3109 for( i = 0 ; i < nvars; ++i )
    3110 {
    3111 SCIP_Real varobj;
    3112 assert(SCIPvarGetProbindex(vars[i]) == i);
    3113
    3114 /* skip all variables with zero objective coefficient */
    3115 if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
    3116 continue;
    3117
    3118 QUAD_ARRAY_LOAD(val, aggrrow->vals, i); /* val = aggrrow->vals[i] */
    3119
    3120 if( QUAD_HI(val) == 0.0 )
    3121 aggrrow->inds[aggrrow->nnz++] = i;
    3122
    3123 varobj = SCIPvarGetObj(vars[i]);
    3124 SCIPquadprecProdDD(quadprod, scale, varobj);
    3125 SCIPquadprecSumQQ(val, val, quadprod);
    3126
    3127 /* the value must not be exactly zero due to sparsity pattern */
    3128 QUAD_HI(val) = NONZERO(QUAD_HI(val));
    3129 assert(QUAD_HI(val) != 0.0);
    3130
    3131 QUAD_ARRAY_STORE(aggrrow->vals, i, val);
    3132 }
    3133
    3134 /* add right-hand side value */
    3135 SCIPquadprecProdDD(quadprod, scale, rhs);
    3136 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
    3137 }
    3138
    3139 return SCIP_OKAY;
    3140}
    3141
    3142/** add weighted constraint to the aggregation row */
    3144 SCIP* scip, /**< SCIP data structure */
    3145 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3146 int* inds, /**< variable problem indices in constraint to add to the aggregation row */
    3147 SCIP_Real* vals, /**< values of constraint to add to the aggregation row */
    3148 int len, /**< length of constraint to add to the aggregation row */
    3149 SCIP_Real rhs, /**< right hand side of constraint to add to the aggregation row */
    3150 SCIP_Real weight, /**< (positive) scale for adding given constraint to the aggregation row */
    3151 int rank, /**< rank to use for given constraint */
    3152 SCIP_Bool local /**< is constraint only valid locally */
    3153 )
    3154{
    3155 SCIP_Real QUAD(quadprod);
    3156 int i;
    3157
    3158 assert(weight >= 0.0);
    3159 assert(!SCIPisInfinity(scip, REALABS(weight * rhs)));
    3160
    3161 /* update local flag */
    3162 aggrrow->local = aggrrow->local || local;
    3163
    3164 /* update rank */
    3165 aggrrow->rank = MAX(rank, aggrrow->rank);
    3166
    3167 /* add right hand side value */
    3168 SCIPquadprecProdDD(quadprod, weight, rhs);
    3169 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
    3170
    3171 /* add the non-zeros to the aggregation row and keep non-zero index up to date */
    3172 for( i = 0 ; i < len; ++i )
    3173 {
    3174 SCIP_Real QUAD(val);
    3175 int probindex = inds[i];
    3176
    3177 QUAD_ARRAY_LOAD(val, aggrrow->vals, probindex); /* val = aggrrow->vals[probindex] */
    3178
    3179 if( QUAD_HI(val) == 0.0 )
    3180 aggrrow->inds[aggrrow->nnz++] = probindex;
    3181
    3182 SCIPquadprecProdDD(quadprod, vals[i], weight);
    3183 SCIPquadprecSumQQ(val, val, quadprod);
    3184
    3185 /* the value must not be exactly zero due to sparsity pattern */
    3186 QUAD_HI(val) = NONZERO(QUAD_HI(val));
    3187 assert(QUAD_HI(val) != 0.0);
    3188
    3189 QUAD_ARRAY_STORE(aggrrow->vals, probindex, val);
    3190 }
    3191
    3192 return SCIP_OKAY;
    3193}
    3194
    3195/** version for use in exact solving mode of SCIPaggrRowClear() */
    3197 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    3198 )
    3199{
    3200 int i;
    3201
    3202 /* in exact solving mode, we do not use quad precision, because we need to control the rounding mode; hence, we only
    3203 * use and clear the first SCIPgetNVars() entries
    3204 */
    3205 for( i = 0; i < aggrrow->nnz; ++i )
    3206 {
    3207 aggrrow->vals[aggrrow->inds[i]] = 0.0;
    3208 }
    3209
    3210 aggrrow->nnz = 0;
    3211 aggrrow->nrows = 0;
    3212 aggrrow->rank = 0;
    3213 QUAD_ASSIGN(aggrrow->rhs, 0.0);
    3214 aggrrow->local = FALSE;
    3215}
    3216
    3217/** clear all entries int the aggregation row but don't free memory */
    3219 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    3220 )
    3221{
    3222 int i;
    3223 SCIP_Real QUAD(tmp);
    3224
    3225 QUAD_ASSIGN(tmp, 0.0);
    3226
    3227 for( i = 0; i < aggrrow->nnz; ++i )
    3228 {
    3229 QUAD_ARRAY_STORE(aggrrow->vals, aggrrow->inds[i], tmp);
    3230 }
    3231
    3232 aggrrow->nnz = 0;
    3233 aggrrow->nrows = 0;
    3234 aggrrow->rank = 0;
    3235 QUAD_ASSIGN(aggrrow->rhs, 0.0);
    3236 aggrrow->local = FALSE;
    3237}
    3238
    3239/** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
    3240 *
    3241 * @return the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
    3242 */
    3244 SCIP* scip, /**< SCIP data structure */
    3245 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    3246 )
    3247{
    3248 return calcEfficacyNormQuad(scip, aggrrow->vals, aggrrow->inds, aggrrow->nnz);
    3249}
    3250
    3251/** adds one row to the aggregation row
    3252 *
    3253 * @note this method differs from SCIPaggrRowAddRow() by providing some additional parameters required for
    3254 * SCIPaggrRowSumRows()
    3255 */
    3256static
    3258 SCIP* scip, /**< SCIP data structure */
    3259 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3260 SCIP_ROW* row, /**< the row to add */
    3261 SCIP_Real weight, /**< weight of row to add */
    3262 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
    3263 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
    3264 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
    3265 int maxaggrlen, /**< maximal length of aggregation row */
    3266 SCIP_Bool* rowtoolong /**< is the aggregated row too long */
    3267 )
    3268{
    3269 SCIP_Real QUAD(quadprod);
    3270 SCIP_Real sideval;
    3271 SCIP_Bool uselhs;
    3272 int i;
    3273
    3274 assert( rowtoolong != NULL );
    3275 *rowtoolong = FALSE;
    3276
    3277 if( SCIPisFeasZero(scip, weight) || SCIProwIsModifiable(row) || (SCIProwIsLocal(row) && !allowlocal) )
    3278 {
    3279 return SCIP_OKAY;
    3280 }
    3281
    3282 if( sidetypebasis && !SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
    3283 {
    3285
    3286 if( stat == SCIP_BASESTAT_LOWER )
    3287 {
    3288 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
    3289 uselhs = TRUE;
    3290 }
    3291 else if( stat == SCIP_BASESTAT_UPPER )
    3292 {
    3293 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
    3294 uselhs = FALSE;
    3295 }
    3296 else if( SCIPisInfinity(scip, SCIProwGetRhs(row)) || (weight < 0.0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row))) )
    3297 uselhs = TRUE;
    3298 else
    3299 uselhs = FALSE;
    3300 }
    3301 else if( (weight < 0.0 && !SCIPisInfinity(scip, -row->lhs)) || SCIPisInfinity(scip, row->rhs) )
    3302 uselhs = TRUE;
    3303 else
    3304 uselhs = FALSE;
    3305
    3306 if( uselhs )
    3307 {
    3308 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
    3309
    3310 if( weight > 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
    3311 return SCIP_OKAY;
    3312
    3313 sideval = row->lhs - row->constant;
    3314 /* row is integral? round left hand side up */
    3315 if( row->integral )
    3316 sideval = SCIPceil(scip, sideval);
    3317 }
    3318 else
    3319 {
    3320 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
    3321
    3322 if( weight < 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
    3323 return SCIP_OKAY;
    3324
    3325 sideval = row->rhs - row->constant;
    3326 /* row is integral? round right hand side down */
    3327 if( row->integral )
    3328 sideval = SCIPfloor(scip, sideval);
    3329 }
    3330
    3331 /* add right hand side, update rank and local flag */
    3332 SCIPquadprecProdDD(quadprod, sideval, weight);
    3333 SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, quadprod);
    3334 aggrrow->rank = MAX(aggrrow->rank, row->rank);
    3335 aggrrow->local = aggrrow->local || row->local;
    3336
    3337 /* ensure the array for storing the row information is large enough */
    3338 i = aggrrow->nrows++;
    3339 if( aggrrow->nrows > aggrrow->rowssize )
    3340 {
    3341 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
    3342 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
    3343 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
    3344 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
    3345 aggrrow->rowssize = newsize;
    3346 }
    3347
    3348 /* add information of addditional row */
    3349 aggrrow->rowsinds[i] = row->lppos;
    3350 aggrrow->rowweights[i] = weight;
    3351 aggrrow->slacksign[i] = uselhs ? -1 : 1;
    3352
    3353 /* add up coefficients */
    3354 SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
    3355
    3356 /* check if row is too long now */
    3357 if( aggrrow->nnz > maxaggrlen )
    3358 *rowtoolong = TRUE;
    3359
    3360 return SCIP_OKAY;
    3361}
    3362
    3363/** adds one row to the aggregation row
    3364 *
    3365 * @note this method differs from SCIPaggrRowAddRowSafely() by providing some additional parameters required for
    3366 * SCIPaggrRowSumRows()
    3367 *
    3368 * @note this method is the variant of addOneRow() that is safe to use in exact solving mode
    3369 */
    3370static
    3372 SCIP* scip, /**< SCIP data structure */
    3373 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3374 SCIP_ROW* row, /**< the row to add */
    3375 SCIP_Real weight, /**< weight of row to add */
    3376 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
    3377 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
    3378 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
    3379 int maxaggrlen, /**< maximal length of aggregation row */
    3380 SCIP_Bool* rowtoolong, /**< is the aggregated row too long */
    3381 SCIP_Bool* rowused, /**< was the row really added? */
    3382 SCIP_Bool* success, /**< was the row added successfully? */
    3383 SCIP_Bool* lhsused /**< was the lhs or the rhs of the row used? */
    3384 )
    3385{
    3386 SCIP_Real sideval;
    3387 SCIP_Real sidevalchg;
    3388 SCIP_Bool uselhs;
    3389 SCIP_ROW* userow;
    3390 SCIP_ROWEXACT* rowexact;
    3391 SCIP_ROUNDMODE previousroundmode;
    3392 int i;
    3393
    3394 assert(SCIPisExact(scip));
    3395 assert(rowtoolong != NULL);
    3396 *rowtoolong = FALSE;
    3397 *rowused = FALSE;
    3398
    3399 if( SCIPisFeasZero(scip, weight) || SCIProwIsModifiable(row) || (SCIProwIsLocal(row) && !allowlocal) )
    3400 {
    3401 return SCIP_OKAY;
    3402 }
    3403
    3404 if( sidetypebasis && !SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
    3405 {
    3407
    3408 if( stat == SCIP_BASESTAT_LOWER )
    3409 {
    3410 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
    3411 uselhs = TRUE;
    3412 }
    3413 else if( stat == SCIP_BASESTAT_UPPER )
    3414 {
    3415 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
    3416 uselhs = FALSE;
    3417 }
    3418 else if( SCIPisInfinity(scip, SCIProwGetRhs(row)) || (weight < 0.0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row))) )
    3419 uselhs = TRUE;
    3420 else
    3421 uselhs = FALSE;
    3422 }
    3423 else if( (weight < 0.0 && !SCIPisInfinity(scip, -row->lhs)) || SCIPisInfinity(scip, row->rhs) )
    3424 uselhs = TRUE;
    3425 else
    3426 uselhs = FALSE;
    3427
    3428 rowexact = SCIProwGetRowExact(row);
    3429 if( !SCIProwExactHasFpRelax(rowexact) )
    3430 {
    3431 *success = FALSE;
    3432 return SCIP_OKAY;
    3433 }
    3434 else if( SCIProwExactGetRowRhs(rowexact) != NULL && weight >= 0.0 )
    3435 userow = SCIProwExactGetRowRhs(rowexact);
    3436 else
    3437 userow = row;
    3438
    3439 previousroundmode = SCIPintervalGetRoundingMode();
    3440
    3441 if( uselhs )
    3442 {
    3443 *lhsused = TRUE;
    3444 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
    3445
    3446 if( weight > 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
    3447 return SCIP_OKAY;
    3448
    3450
    3451 sideval = userow->lhs - userow->constant;
    3452#ifdef SCIP_DISABLED_CODE
    3453 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
    3454 /* row is integral? round left hand side up */
    3455 if( userow->integral )
    3456 sideval = ceil(sideval);
    3457#endif
    3458 }
    3459 else
    3460 {
    3461 *lhsused = FALSE;
    3462 assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
    3463
    3464 if( weight < 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
    3465 return SCIP_OKAY;
    3466
    3468
    3469 sideval = userow->rhs - userow->constant;
    3470#ifdef SCIP_DISABLED_CODE
    3471 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in cutsSubstituteMIRSafely() */
    3472 /* row is integral? round right hand side down */
    3473 if( userow->integral )
    3474 sideval = floor(sideval);
    3475#endif
    3476 }
    3477
    3479
    3480 sidevalchg = QUAD_TO_DBL(aggrrow->rhs);
    3481 sidevalchg += sideval * weight;
    3482 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
    3483
    3484 aggrrow->rank = MAX(aggrrow->rank, userow->rank);
    3485 aggrrow->local = aggrrow->local || userow->local;
    3486
    3487 /* ensure the array for storing the row information is large enough */
    3488 i = aggrrow->nrows++;
    3489 *rowused = TRUE;
    3490 if( aggrrow->nrows > aggrrow->rowssize )
    3491 {
    3492 int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
    3493 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
    3494 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
    3495 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
    3496 aggrrow->rowssize = newsize;
    3497 }
    3498
    3499 /* add information of addditional row */
    3500 aggrrow->rowsinds[i] = row->lppos;
    3501 aggrrow->rowweights[i] = weight;
    3502 aggrrow->slacksign[i] = uselhs ? -1 : 1;
    3503
    3504 /* add up coefficients */
    3505 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, aggrrow->inds, aggrrow->vals, &aggrrow->nnz, userow, weight, &sidevalchg, success) );
    3506
    3507 sidevalchg += QUAD_TO_DBL(aggrrow->rhs);
    3508 QUAD_ASSIGN(aggrrow->rhs, sidevalchg);
    3509
    3510 /* check if row is too long now */
    3511 if( aggrrow->nnz > maxaggrlen )
    3512 *rowtoolong = TRUE;
    3513
    3514 SCIPintervalSetRoundingMode(previousroundmode);
    3515
    3516 return SCIP_OKAY;
    3517}
    3518
    3519/** aggregate rows using the given weights; the current content of the aggregation row, \p aggrrow, is overwritten
    3520 *
    3521 * @note this method is safe for usage in exact solving mode
    3522 */
    3524 SCIP* scip, /**< SCIP data structure */
    3525 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3526 SCIP_Real* weights, /**< row weights in row summation */
    3527 int* rowinds, /**< array to store indices of non-zero entries of the weights array, or NULL */
    3528 int nrowinds, /**< number of non-zero entries in weights array, -1 if rowinds is NULL */
    3529 SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
    3530 SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
    3531 int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
    3532 int maxaggrlen, /**< maximal length of aggregation row */
    3533 SCIP_Bool* valid /**< is the aggregation valid */
    3534 )
    3535{
    3536 SCIP_AGGRROW* certificaterow = NULL;
    3537 SCIP_ROW** rows;
    3538 SCIP_ROW** usedrows = NULL;
    3539 SCIP_ROW** negslackrows = NULL;
    3540 SCIP_VAR** vars;
    3541 SCIP_Real* usedweights = NULL;
    3542 SCIP_Real* negslackweights = NULL;
    3543 int nrows;
    3544 int nvars;
    3545 int k;
    3546 int nusedrows;
    3547 int nnegslackrows;
    3548 SCIP_Bool rowtoolong;
    3549 SCIP_Bool rowused, rowusedcert, lhsused;
    3550
    3551 assert( scip != NULL );
    3552 assert( aggrrow != NULL );
    3553 assert( valid != NULL );
    3554
    3555 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    3556 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
    3557
    3558 if( SCIPisExact(scip) )
    3559 SCIPaggrRowClearSafely(aggrrow);
    3560 else
    3561 SCIPaggrRowClear(aggrrow);
    3562 *valid = TRUE;
    3563 lhsused = FALSE;
    3564 nusedrows = 0;
    3565 nnegslackrows = 0;
    3566
    3567 SCIPdebugMessage("Summing up %d rows in aggrrow \n", nrowinds);
    3568
    3569 if( SCIPisCertified(scip) )
    3570 {
    3571 SCIP_CALL( SCIPallocBufferArray(scip, &usedrows, nrows) );
    3572 SCIP_CALL( SCIPallocBufferArray(scip, &usedweights, nrows) );
    3573 SCIP_CALL( SCIPallocBufferArray(scip, &negslackrows, nrows) );
    3574 SCIP_CALL( SCIPallocBufferArray(scip, &negslackweights, nrows) );
    3575 SCIP_CALL( SCIPaggrRowCreate(scip, &certificaterow) );
    3576 }
    3577
    3578 if( rowinds != NULL && nrowinds > -1 )
    3579 {
    3580 for( k = 0; k < nrowinds; ++k )
    3581 {
    3582 if( !SCIPisExact(scip) )
    3583 {
    3584 SCIP_CALL( addOneRow(scip, aggrrow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
    3585
    3586 if( rowtoolong )
    3587 *valid = FALSE;
    3588 }
    3589 else /*lint --e{644}*/
    3590 {
    3591 SCIPdebugMessage("Adding %g times row: ", weights[rowinds[k]]);
    3592 SCIPdebug(SCIPprintRow(scip, rows[rowinds[k]], NULL));
    3593 SCIP_CALL( addOneRowSafely(scip, aggrrow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis, allowlocal,
    3594 negslack, maxaggrlen, &rowtoolong, &rowused, valid, &lhsused) );
    3595
    3596 if( rowtoolong )
    3597 *valid = FALSE;
    3598
    3599 if( !(*valid) )
    3600 break;
    3601
    3602 if( certificaterow != NULL )
    3603 {
    3604 assert(usedrows != NULL);
    3605 assert(usedweights != NULL);
    3606 assert(negslackrows != NULL);
    3607 assert(negslackweights != NULL);
    3608
    3609 SCIP_ROW* row = rows[rowinds[k]];
    3610 SCIP_Bool integral = FALSE;
    3611
    3612 /* just exclude the negative continuous slacks for the certificate rows */
    3613 if( row->integral &&
    3614 ((!lhsused && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant)) ||
    3616 {
    3617 SCIPdebugMessage("row has integral slack\n");
    3618 rowusedcert = FALSE;
    3619 integral = TRUE;
    3620 }
    3621 else
    3622 {
    3623 /* the certificate row may exceed the limit maxaggrlen */
    3624 SCIP_CALL( addOneRowSafely(scip, certificaterow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis,
    3625 allowlocal, 0, nvars, &rowtoolong, &rowusedcert, valid, &lhsused) );
    3626 assert(!rowtoolong);
    3627 }
    3628 if( rowusedcert )
    3629 {
    3630 usedrows[nusedrows] = rows[rowinds[k]];
    3631 usedweights[nusedrows] = weights[rowinds[k]];
    3632 nusedrows++;
    3633 }
    3634 if( rowused && !rowusedcert && !integral )
    3635 {
    3636 SCIPdebugMessage("row has negative continous slack\n");
    3637 assert( (lhsused && weights[rowinds[k]] >= 0) || ((!lhsused) && weights[rowinds[k]] <= 0) || row->integral );
    3638 negslackrows[nnegslackrows] = rows[rowinds[k]];
    3639 negslackweights[nnegslackrows] = -weights[rowinds[k]];
    3640 nnegslackrows++;
    3641 }
    3642 }
    3643 }
    3644
    3645 if( !(*valid) )
    3646 break;
    3647 }
    3648 }
    3649 else
    3650 {
    3651 for( k = 0; k < nrows; ++k )
    3652 {
    3653 if( weights[k] != 0.0 )
    3654 {
    3655 if( !SCIPisExact(scip) )
    3656 {
    3657 SCIP_CALL( addOneRow(scip, aggrrow, rows[k], weights[k], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
    3658
    3659 if( rowtoolong )
    3660 *valid = FALSE;
    3661 }
    3662 else
    3663 {
    3664 SCIPdebugMessage("Adding %g times row: ", weights[k]);
    3665 SCIPdebug(SCIPprintRow(scip, rows[k], NULL));
    3666 SCIP_CALL( addOneRowSafely(scip, aggrrow, rows[k], weights[k], sidetypebasis, allowlocal, negslack,
    3667 maxaggrlen, &rowtoolong, &rowused, valid, &lhsused) );
    3668
    3669 if( rowtoolong )
    3670 *valid = FALSE;
    3671
    3672 if( !(*valid) )
    3673 break;
    3674
    3675 if( certificaterow != NULL )
    3676 {
    3677 assert(usedrows != NULL);
    3678 assert(usedweights != NULL);
    3679 assert(negslackrows != NULL);
    3680 assert(negslackweights != NULL);
    3681
    3682 SCIP_ROW* row = rows[k];
    3683 SCIP_Bool integral = FALSE;
    3684
    3685 /* just exclude the negative continuous slacks for the certificate rows */
    3686 if( row->integral &&
    3687 ((!lhsused && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant)) ||
    3689 {
    3690 rowusedcert = FALSE;
    3691 SCIPdebugMessage("row has integral slack\n");
    3692 integral = TRUE;
    3693 }
    3694 else
    3695 {
    3696 /* the certificate row may exceed the limit maxaggrlen */
    3697 SCIP_CALL( addOneRowSafely(scip, certificaterow, rows[k], weights[k], sidetypebasis, allowlocal, 0,
    3698 nvars, &rowtoolong, &rowusedcert, valid, &lhsused) );
    3699 assert(!rowtoolong);
    3700 }
    3701 if( rowusedcert )
    3702 {
    3703 usedrows[nusedrows] = rows[k];
    3704 usedweights[nusedrows] = weights[k];
    3705 nusedrows++;
    3706 }
    3707 if( rowused && !rowusedcert && !integral )
    3708 {
    3709 SCIPdebugMessage("row has negative continous slack\n");
    3710 assert( (lhsused && weights[k] >= 0) || ((!lhsused) && weights[k] <= 0) || row->integral );
    3711 negslackrows[nnegslackrows] = rows[k];
    3712 negslackweights[nnegslackrows] = -weights[k];
    3713 nnegslackrows++;
    3714 }
    3715 }
    3716 }
    3717
    3718 if( !(*valid) )
    3719 break;
    3720 }
    3721 }
    3722 }
    3723
    3724 if( *valid )
    3725 {
    3726 SCIPaggrRowRemoveZeros(scip, aggrrow, FALSE, valid);
    3727
    3728 if( certificaterow != NULL )
    3729 {
    3730 SCIPaggrRowRemoveZeros(scip, certificaterow, FALSE, valid);
    3731 SCIP_CALL( SCIPaddCertificateAggrInfo(scip, certificaterow, usedrows, usedweights, certificaterow->nrows,
    3732 negslackrows, negslackweights, nnegslackrows) );
    3733 }
    3734 }
    3735
    3736 if( certificaterow != NULL )
    3737 {
    3738 SCIPaggrRowFree(scip, &certificaterow);
    3739 SCIPfreeBufferArray(scip, &negslackweights);
    3740 SCIPfreeBufferArray(scip, &negslackrows);
    3741 SCIPfreeBufferArray(scip, &usedweights);
    3742 SCIPfreeBufferArray(scip, &usedrows);
    3743 }
    3744
    3745 return SCIP_OKAY;
    3746}
    3747
    3748/** checks for cut redundancy and performs activity based coefficient tightening;
    3749 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
    3750 * to remove small coefficients (relative to the maximum absolute coefficient)
    3751 */
    3752static
    3754 SCIP* scip, /**< SCIP data structure */
    3755 SCIP_Bool cutislocal, /**< is the cut a local cut */
    3756 int* cutinds, /**< variable problem indices of non-zeros in cut */
    3757 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
    3758 int* nnz, /**< number non-zeros coefficients of cut */
    3759 SCIP_Real* cutrhs, /**< right hand side of cut */
    3760 SCIP_Bool* success /**< pointer to return whether post-processing was successful or cut is redundant */
    3761 )
    3762{
    3763 int i;
    3764 SCIP_Bool redundant;
    3765 SCIP_Real maxcoef;
    3766 SCIP_Real minallowedcoef;
    3767 SCIP_Real QUAD(rhs);
    3768
    3769 assert(scip != NULL);
    3770 assert(cutinds != NULL);
    3771 assert(cutcoefs != NULL);
    3772 assert(cutrhs != NULL);
    3773 assert(success != NULL);
    3774
    3775 *success = FALSE;
    3776
    3777 QUAD_ASSIGN(rhs, *cutrhs);
    3778
    3779 if( removeZeros(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz) )
    3780 {
    3781 /* right hand side was changed to infinity -> cut is redundant */
    3782 return SCIP_OKAY;
    3783 }
    3784
    3785 if( *nnz == 0 )
    3786 return SCIP_OKAY;
    3787
    3788 SCIP_CALL( cutTightenCoefs(scip, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz, &redundant) );
    3789
    3790 if( redundant )
    3791 {
    3792 /* cut is redundant */
    3793 return SCIP_OKAY;
    3794 }
    3795
    3796 maxcoef = 0.0;
    3797 for( i = 0; i < *nnz; ++i )
    3798 {
    3799 SCIP_Real absval = REALABS(cutcoefs[cutinds[i]]);
    3800 maxcoef = MAX(absval, maxcoef);
    3801 }
    3802
    3803 maxcoef /= scip->set->sepa_maxcoefratio;
    3804 minallowedcoef = SCIPsumepsilon(scip);
    3805 minallowedcoef = MAX(minallowedcoef, maxcoef);
    3806
    3807 *success = ! removeZeros(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz);
    3808 *cutrhs = QUAD_TO_DBL(rhs);
    3809
    3810 return SCIP_OKAY;
    3811}
    3812
    3813
    3814/** checks for cut redundancy and performs activity based coefficient tightening;
    3815 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
    3816 * to remove small coefficients (relative to the maximum absolute coefficient).
    3817 * The cutcoefs must be a quad precision array, i.e. allocated with size
    3818 * QUAD_ARRAY_SIZE(nvars) and accessed with QUAD_ARRAY_LOAD and QUAD_ARRAY_STORE
    3819 * macros.
    3820 */
    3821static
    3823 SCIP* scip, /**< SCIP data structure */
    3824 SCIP_Bool cutislocal, /**< is the cut a local cut */
    3825 int* cutinds, /**< variable problem indices of non-zeros in cut */
    3826 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
    3827 int* nnz, /**< number non-zeros coefficients of cut */
    3828 QUAD(SCIP_Real* cutrhs), /**< right hand side of cut */
    3829 SCIP_Bool* success /**< pointer to return whether the cleanup was successful or if it is useless */
    3830 )
    3831{
    3832 int i;
    3833 SCIP_Bool redundant;
    3834 SCIP_Real maxcoef;
    3835 SCIP_Real minallowedcoef;
    3836
    3837 assert(scip != NULL);
    3838 assert(cutinds != NULL);
    3839 assert(cutcoefs != NULL);
    3840 assert(QUAD_HI(cutrhs) != NULL);
    3841 assert(success != NULL);
    3842
    3843 *success = FALSE;
    3844
    3845 if( removeZerosQuad(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz) )
    3846 {
    3847 /* right hand side was changed to infinity -> cut is redundant */
    3848 return SCIP_OKAY;
    3849 }
    3850
    3851 if( *nnz == 0 )
    3852 return SCIP_OKAY;
    3853
    3854 SCIP_CALL( cutTightenCoefsQuad(scip, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz, &redundant) );
    3855 if( redundant )
    3856 {
    3857 /* cut is redundant */
    3858 return SCIP_OKAY;
    3859 }
    3860
    3861 maxcoef = 0.0;
    3862 for( i = 0; i < *nnz; ++i )
    3863 {
    3864 SCIP_Real abscoef;
    3865 SCIP_Real QUAD(coef);
    3866 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]); /* coef = cutcoefs[cutinds[i]] */
    3867 abscoef = REALABS(QUAD_TO_DBL(coef));
    3868 maxcoef = MAX(abscoef, maxcoef);
    3869 }
    3870
    3871 maxcoef /= scip->set->sepa_maxcoefratio;
    3872 minallowedcoef = SCIPsumepsilon(scip);
    3873 minallowedcoef = MAX(minallowedcoef, maxcoef);
    3874
    3875 *success = ! removeZerosQuad(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz);
    3876
    3877 return SCIP_OKAY;
    3878}
    3879
    3880/** checks for cut redundancy and performs activity based coefficient tightening;
    3881 * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
    3882 * to remove small coefficients (relative to the maximum absolute coefficient).
    3883 * The cutcoefs must be a quad precision array, i.e. allocated with size
    3884 * QUAD_ARRAY_SIZE(nvars) and accessed with QUAD_ARRAY_LOAD and QUAD_ARRAY_STORE
    3885 * macros.
    3886 */
    3887static
    3889 SCIP* scip, /**< SCIP data structure */
    3890 SCIP_Bool cutislocal, /**< is the cut a local cut */
    3891 int* cutinds, /**< variable problem indices of non-zeros in cut */
    3892 SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
    3893 int* nnz, /**< number non-zeros coefficients of cut */
    3894 SCIP_Real* cutrhs, /**< right hand side of cut */
    3895 SCIP_Bool* success /**< pointer to return whether the cleanup was successful or if it is useless */
    3896 )
    3897{
    3898 int i;
    3899 SCIP_Bool redundant;
    3900 SCIP_Real maxcoef;
    3901 SCIP_Real minallowedcoef;
    3902
    3903 assert(SCIPisExact(scip));
    3904
    3905 assert(scip != NULL);
    3906 assert(cutinds != NULL);
    3907 assert(cutcoefs != NULL);
    3908 assert(cutrhs != NULL);
    3909 assert(success != NULL);
    3910
    3911 *success = FALSE;
    3912
    3913 if( removeZerosSafely(scip, SCIPfeastol(scip), cutcoefs, cutrhs, cutinds, nnz) )
    3914 {
    3915 /* right hand side was changed to infinity -> cut is redundant */
    3916 return SCIP_OKAY;
    3917 }
    3918
    3919 if( *nnz == 0 )
    3920 return SCIP_OKAY;
    3921
    3922 SCIP_CALL( cutTightenCoefsSafely(scip, cutislocal, cutcoefs, cutrhs, cutinds, nnz, &redundant) );
    3923 if( redundant )
    3924 {
    3925 /* cut is redundant */
    3926 return SCIP_OKAY;
    3927 }
    3928
    3929 maxcoef = 0.0;
    3930 for( i = 0; i < *nnz; ++i )
    3931 {
    3932 SCIP_Real abscoef;
    3933 SCIP_Real coef;
    3934 coef = cutcoefs[cutinds[i]];
    3935 abscoef = REALABS(coef);
    3936 maxcoef = MAX(abscoef, maxcoef);
    3937 }
    3938
    3939 maxcoef /= scip->set->sepa_maxcoefratio;
    3940 minallowedcoef = SCIPsumepsilon(scip);
    3941 minallowedcoef = MAX(minallowedcoef, maxcoef);
    3942
    3943 *success = ! removeZerosSafely(scip, minallowedcoef, cutcoefs, cutrhs, cutinds, nnz);
    3944
    3945 return SCIP_OKAY;
    3946}
    3947
    3948/** removes almost zero entries from the aggregation row. */
    3950 SCIP* scip, /**< SCIP datastructure */
    3951 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    3952 SCIP_Bool useglbbounds, /**< consider global bound although the cut is local? */
    3953 SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
    3954 )
    3955{
    3956 assert(aggrrow != NULL);
    3957 assert(valid != NULL);
    3958
    3959 if( SCIPisExact(scip) )
    3960 {
    3961 SCIP_Real rhs;
    3962 rhs = QUAD_TO_DBL(aggrrow->rhs);
    3963 *valid = !removeZerosSafely(scip, SCIPsumepsilon(scip), aggrrow->vals, &rhs, aggrrow->inds, &aggrrow->nnz);
    3964 QUAD_ASSIGN(aggrrow->rhs, rhs);
    3965 return;
    3966 }
    3967
    3968 *valid = ! removeZerosQuad(scip, SCIPsumepsilon(scip), useglbbounds ? FALSE : aggrrow->local, aggrrow->vals,
    3969 QUAD(&aggrrow->rhs), aggrrow->inds, &aggrrow->nnz);
    3970}
    3971
    3972/** get number of aggregated rows */
    3974 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    3975 )
    3976{
    3977 assert(aggrrow != NULL);
    3978
    3979 return aggrrow->nrows;
    3980}
    3981
    3982/** get array with lp positions of rows used in aggregation */
    3984 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    3985 )
    3986{
    3987 assert(aggrrow != NULL);
    3988 assert(aggrrow->rowsinds != NULL || aggrrow->nrows == 0);
    3989
    3990 return aggrrow->rowsinds;
    3991}
    3992
    3993/** get array with weights of aggregated rows */
    3995 SCIP_AGGRROW* aggrrow /**< the aggregation row */
    3996 )
    3997{
    3998 assert(aggrrow != NULL);
    3999 assert(aggrrow->rowweights != NULL || aggrrow->nrows == 0);
    4000
    4001 return aggrrow->rowweights;
    4002}
    4003
    4004/** checks whether a given row has been added to the aggregation row */
    4006 SCIP_AGGRROW* aggrrow, /**< the aggregation row */
    4007 SCIP_ROW* row /**< row for which it is checked whether it has been added to the aggregation */
    4008 )
    4009{
    4010 int i;
    4011 int rowind;
    4012
    4013 assert(aggrrow != NULL);
    4014 assert(row != NULL);
    4015
    4016 rowind = SCIProwGetLPPos(row);
    4017
    4018 for( i = 0; i < aggrrow->nrows; ++i )
    4019 {
    4020 if( aggrrow->rowsinds[i] == rowind )
    4021 return TRUE;
    4022 }
    4023
    4024 return FALSE;
    4025}
    4026
    4027/** gets the array of corresponding variable problem indices for each non-zero in the aggregation row */
    4029 SCIP_AGGRROW* aggrrow /**< aggregation row */
    4030 )
    4031{
    4032 assert(aggrrow != NULL);
    4033
    4034 return aggrrow->inds;
    4035}
    4036
    4037/** gets the number of non-zeros in the aggregation row */
    4039 SCIP_AGGRROW* aggrrow /**< aggregation row */
    4040 )
    4041{
    4042 assert(aggrrow != NULL);
    4043
    4044 return aggrrow->nnz;
    4045}
    4046
    4047/** gets the rank of the aggregation row */
    4049 SCIP_AGGRROW* aggrrow /**< aggregation row */
    4050 )
    4051{
    4052 assert(aggrrow != NULL);
    4053
    4054 return aggrrow->rank;
    4055}
    4056
    4057/** checks if the aggregation row is only valid locally */
    4059 SCIP_AGGRROW* aggrrow /**< aggregation row */
    4060 )
    4061{
    4062 assert(aggrrow != NULL);
    4063
    4064 return aggrrow->local;
    4065}
    4066
    4067/** gets the right hand side of the aggregation row */
    4069 SCIP_AGGRROW* aggrrow /**< aggregation row */
    4070 )
    4071{
    4072 assert(aggrrow != NULL);
    4073
    4074 return QUAD_TO_DBL(aggrrow->rhs);
    4075}
    4076
    4077/* =========================================== c-MIR =========================================== */
    4078
    4079#define MAXCMIRSCALE 1e+6 /**< maximal scaling (scale/(1-f0)) allowed in c-MIR calculations */
    4080
    4081/* In order to derive cuts, we partition the variable array up in (not necessarily contiguous) sections.
    4082 * The only requirement we place on these sections is that section i can only have variable bounds variables whose section
    4083 * is strictly greater than i. This way, we can process the variable array in a 'linear' manner. */
    4084
    4085/* @todo maintain a DAG for used varbounds and use topological ordering instead, this would also allow
    4086 * variable bounds on variables of the same section to be used */
    4087
    4088#define NSECTIONS 6
    4089
    4090typedef struct MIR_Data
    4091{
    4092 int totalnnz; /* The total number of nonzeros in all of the sections */
    4093 int* secindices[NSECTIONS]; /* The indices of the variables belonging to the section */
    4094 int secnnz[NSECTIONS]; /* The number of nonzero indices in the section */
    4095
    4096 SCIP_Bool isenfint[NSECTIONS];/**< Does the section have an integrality constraint? */
    4097 SCIP_Bool isimplint[NSECTIONS];/**< Is the section implied integer variables? */
    4098
    4099 /* Settings for cut derivation, per section */
    4100 int usevbds[NSECTIONS]; /**< Should variable bound substitution be done for this section? */
    4101
    4102 /* Problem data that we reuse often */
    4103 SCIP_VAR** vars; /**< pointer to SCIPs variable array */
    4104 int nvars; /**< total number of variables */
    4105 int nbinvars; /**< total number of non-implint binary variables */
    4106 int nintvars; /**< total number of non-implint integer variables */
    4107 int nbinimplvars; /**< total number of implint binary variables */
    4108 int nintimplvars; /**< total number of implint integer variables */
    4109 int ncontimplvars; /**< total number of implint continuous variables */
    4110 int ncontvars; /**< total number of non-implied continuous variables */
    4111
    4112 SCIP_Real* cutcoefs; /**< working cut indices value array */
    4113 SCIP_Real QUAD(cutrhs); /**< the working right hand side of the cut*/
    4114
    4115 int* cutinds; /**< working cut variable problem index array */
    4116 int ncutinds; /**< number of values in the working cut variable problem index array */
    4118
    4119/** Returns the section of a variable.
    4120 *
    4121 * For now, this is equal to the variable type section of the variable in the problem.
    4122 */
    4123static
    4125 MIR_DATA* data, /**< The MIR separation data */
    4126 int probindex /**< Problem index of a variable */
    4127 )
    4128{
    4129 int limit;
    4130
    4131 assert(data != NULL);
    4132
    4133 limit = data->nvars - data->ncontvars;
    4134 if( probindex >= limit )
    4135 return 0;
    4136
    4137 limit -= data->ncontimplvars;
    4138 if( probindex >= limit )
    4139 return 1;
    4140
    4141 limit -= data->nintimplvars;
    4142 if( probindex >= limit )
    4143 return 2;
    4144
    4145 limit -= data->nbinimplvars;
    4146 if( probindex >= limit )
    4147 return 3;
    4148
    4149 limit -= data->nintvars;
    4150 if( probindex >= limit )
    4151 return 4;
    4152
    4153 assert(limit == data->nbinvars);
    4154
    4155 return 5;
    4156}
    4157
    4158/** finds the best lower bound of the variable to use for MIR transformation.
    4159 *
    4160 * Currently, we use a slightly different function for the exact MIR cuts than for the normal MIR cuts due to differences
    4161 * in how the codes can handle variable bound substitution. This function can only be used with the safe MIR code. */
    4162/* @todo make behavior identical to the unsafe MIR cut computation */
    4163static
    4165 SCIP* scip, /**< SCIP data structure */
    4166 SCIP_VAR* var, /**< problem variable */
    4167 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4168 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4169 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4170 SCIP_Real* bestlb, /**< pointer to store best bound value */
    4171 SCIP_Real* simplebound, /**< pointer to store simple bound value */
    4172 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4173 )
    4174{
    4175 assert(bestlb != NULL);
    4176 assert(bestlbtype != NULL);
    4177 assert(usevbds >= 0 && usevbds <= 2);
    4178
    4179 *bestlb = SCIPvarGetLbGlobal(var);
    4180 *bestlbtype = -1;
    4181
    4182 if( allowlocal )
    4183 {
    4184 SCIP_Real loclb;
    4185
    4186 loclb = SCIPvarGetLbLocal(var);
    4187 if( SCIPisGT(scip, loclb, *bestlb) )
    4188 {
    4189 *bestlb = loclb;
    4190 *bestlbtype = -2;
    4191 }
    4192 }
    4193
    4194 *simplebound = *bestlb;
    4195
    4196 if( usevbds && !SCIPvarIsIntegral(var) )
    4197 {
    4198 SCIP_Real bestvlb;
    4199 int bestvlbidx;
    4200
    4201 SCIP_CALL( SCIPgetVarClosestVlb(scip, var, sol, &bestvlb, &bestvlbidx) );
    4202 if( bestvlbidx >= 0 && (bestvlb > *bestlb || (*bestlbtype < 0 && SCIPisGE(scip, bestvlb, *bestlb))) )
    4203 {
    4204 SCIP_VAR** vlbvars;
    4205 SCIP_VAR* vlbvar;
    4206
    4207 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
    4208 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
    4209 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
    4210 */
    4211 vlbvars = SCIPvarGetVlbVars(var);
    4212 assert(vlbvars != NULL);
    4213 vlbvar = vlbvars[bestvlbidx];
    4214 assert(vlbvar != NULL);
    4215 if( ( usevbds == 2 || ( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY
    4216 && !SCIPvarIsImpliedIntegral(vlbvar) ) )
    4217 && SCIPvarGetProbindex(vlbvar) < SCIPvarGetProbindex(var) )
    4218 {
    4219 *bestlb = bestvlb;
    4220 *bestlbtype = bestvlbidx;
    4221 }
    4222 }
    4223 }
    4224
    4225 return SCIP_OKAY;
    4226}
    4227
    4228/** finds the best upper bound of the variable to use for MIR transformation.
    4229 * currently, we use a slightly different function for the exact MIR cuts than for the normal MIR cuts due to differences
    4230 * in how the codes can handle variable bound substitution. This function can only be used with the safe MIR code. */
    4231/* @todo make behavior identical to the unsafe MIR cut computation */
    4232static
    4234 SCIP* scip, /**< SCIP data structure */
    4235 SCIP_VAR* var, /**< problem variable */
    4236 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4237 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4238 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4239 SCIP_Real* bestub, /**< pointer to store best bound value */
    4240 SCIP_Real* simplebound, /**< pointer to store simple bound */
    4241 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4242 )
    4243{
    4244 assert(bestub != NULL);
    4245 assert(bestubtype != NULL);
    4246
    4247 *bestub = SCIPvarGetUbGlobal(var);
    4248 *bestubtype = -1;
    4249
    4250 if( allowlocal )
    4251 {
    4252 SCIP_Real locub;
    4253
    4254 locub = SCIPvarGetUbLocal(var);
    4255 if( SCIPisLT(scip, locub, *bestub) )
    4256 {
    4257 *bestub = locub;
    4258 *bestubtype = -2;
    4259 }
    4260 }
    4261
    4262 *simplebound = *bestub;
    4263
    4264 if( usevbds && !SCIPvarIsIntegral(var) )
    4265 {
    4266 SCIP_Real bestvub;
    4267 int bestvubidx;
    4268
    4269 SCIP_CALL( SCIPgetVarClosestVub(scip, var, sol, &bestvub, &bestvubidx) );
    4270 if( bestvubidx >= 0 && (bestvub < *bestub || (*bestubtype < 0 && SCIPisLE(scip, bestvub, *bestub))) )
    4271 {
    4272 SCIP_VAR** vubvars;
    4273 SCIP_VAR* vubvar;
    4274
    4275 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
    4276 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
    4277 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
    4278 */
    4279 vubvars = SCIPvarGetVubVars(var);
    4280 assert(vubvars != NULL);
    4281 vubvar = vubvars[bestvubidx];
    4282 assert(vubvar != NULL);
    4283 if( ( usevbds == 2 || ( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY
    4284 && !SCIPvarIsImpliedIntegral(vubvar) ) )
    4285 && SCIPvarGetProbindex(vubvar) < SCIPvarGetProbindex(var) )
    4286 {
    4287 *bestub = bestvub;
    4288 *bestubtype = bestvubidx;
    4289 }
    4290 }
    4291 }
    4292
    4293 return SCIP_OKAY;
    4294}
    4295
    4296/** determine the best bounds with respect to the given solution for complementing the given variable */
    4297/* @todo make behavior identical to the unsafe MIR cut computation */
    4298static
    4300 SCIP* scip, /**< SCIP data structure */
    4301 SCIP_VAR* var, /**< variable to determine best bound for */
    4302 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4303 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    4304 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4305 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4306 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    4307 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
    4308 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    4309 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    4310 * NULL for using closest bound for all variables */
    4311 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    4312 * NULL for using closest bound for all variables */
    4313 SCIP_Real* bestlb, /**< pointer to store best lower bound of variable */
    4314 SCIP_Real* bestub, /**< pointer to store best upper bound of variable */
    4315 int* bestlbtype, /**< pointer to store type of the best lower bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4316 int* bestubtype, /**< pointer to store type of best upper bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4317 SCIP_BOUNDTYPE* selectedbound, /**< pointer to store whether the lower bound or the upper bound should be preferred */
    4318 SCIP_Bool* freevariable /**< pointer to store if this is a free variable */
    4319 )
    4320{
    4321 SCIP_Real simplelb;
    4322 SCIP_Real simpleub;
    4323 int v;
    4324
    4325 v = SCIPvarGetProbindex(var);
    4326
    4327 /* check if the user specified a bound to be used */
    4328 if( boundsfortrans != NULL && boundsfortrans[v] > -3 )
    4329 {
    4330 assert(!SCIPvarIsIntegral(var) || boundsfortrans[v] == -2 || boundsfortrans[v] == -1);
    4331 assert(boundtypesfortrans != NULL);
    4332
    4333 /* user has explicitly specified a bound to be used */
    4334 if( boundtypesfortrans[v] == SCIP_BOUNDTYPE_LOWER )
    4335 {
    4336 /* user wants to use lower bound */
    4337 *bestlbtype = boundsfortrans[v];
    4338 if( *bestlbtype == -1 )
    4339 *bestlb = SCIPvarGetLbGlobal(var); /* use global standard lower bound */
    4340 else if( *bestlbtype == -2 )
    4341 *bestlb = SCIPvarGetLbLocal(var); /* use local standard lower bound */
    4342 else
    4343 {
    4344 SCIP_VAR** vlbvars;
    4345 SCIP_Real* vlbcoefs;
    4346 SCIP_Real* vlbconsts;
    4347 int k;
    4348
    4349 assert(!ignoresol);
    4350
    4351 /* use the given variable lower bound */
    4352 vlbvars = SCIPvarGetVlbVars(var);
    4353 vlbcoefs = SCIPvarGetVlbCoefs(var);
    4354 vlbconsts = SCIPvarGetVlbConstants(var);
    4355 k = boundsfortrans[v];
    4356 assert(k >= 0 && k < SCIPvarGetNVlbs(var));
    4357 assert(vlbvars != NULL);
    4358 assert(vlbcoefs != NULL);
    4359 assert(vlbconsts != NULL);
    4360
    4361 *bestlb = vlbcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[k]) : SCIPgetSolVal(scip, sol, vlbvars[k])) + vlbconsts[k];
    4362 }
    4363
    4364 assert(!SCIPisInfinity(scip, - *bestlb));
    4365 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4366
    4367 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
    4368 SCIP_CALL( findBestUbSafely(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestub, &simpleub, bestubtype) );
    4369 }
    4370 else
    4371 {
    4372 assert(boundtypesfortrans[v] == SCIP_BOUNDTYPE_UPPER);
    4373
    4374 /* user wants to use upper bound */
    4375 *bestubtype = boundsfortrans[v];
    4376 if( *bestubtype == -1 )
    4377 *bestub = SCIPvarGetUbGlobal(var); /* use global standard upper bound */
    4378 else if( *bestubtype == -2 )
    4379 *bestub = SCIPvarGetUbLocal(var); /* use local standard upper bound */
    4380 else
    4381 {
    4382 SCIP_VAR** vubvars;
    4383 SCIP_Real* vubcoefs;
    4384 SCIP_Real* vubconsts;
    4385 int k;
    4386
    4387 assert(!ignoresol);
    4388
    4389 /* use the given variable upper bound */
    4390 vubvars = SCIPvarGetVubVars(var);
    4391 vubcoefs = SCIPvarGetVubCoefs(var);
    4392 vubconsts = SCIPvarGetVubConstants(var);
    4393 k = boundsfortrans[v];
    4394 assert(k >= 0 && k < SCIPvarGetNVubs(var));
    4395 assert(vubvars != NULL);
    4396 assert(vubcoefs != NULL);
    4397 assert(vubconsts != NULL);
    4398
    4399 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
    4400 *bestub = vubcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vubvars[k]) : SCIPgetSolVal(scip, sol, vubvars[k])) + vubconsts[k];
    4401 }
    4402
    4403 assert(!SCIPisInfinity(scip, *bestub));
    4404 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4405
    4406 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
    4407 SCIP_CALL( findBestLbSafely(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestlb, &simplelb, bestlbtype) );
    4408 }
    4409 }
    4410 else
    4411 {
    4412 SCIP_Real varsol;
    4413
    4414 /* bound selection should be done automatically */
    4415
    4416 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
    4417 SCIP_CALL( findBestLbSafely(scip, var, sol, usevbds, allowlocal, bestlb, &simplelb, bestlbtype) );
    4418
    4419 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
    4420 SCIP_CALL( findBestUbSafely(scip, var, sol, usevbds, allowlocal, bestub, &simpleub, bestubtype) );
    4421
    4422 /* check, if variable is free variable */
    4423 if( SCIPisInfinity(scip, - *bestlb) && SCIPisInfinity(scip, *bestub) )
    4424 {
    4425 /* we found a free variable in the row with non-zero coefficient
    4426 * -> MIR row can't be transformed in standard form
    4427 */
    4428 *freevariable = TRUE;
    4429 return SCIP_OKAY;
    4430 }
    4431
    4432 if( !ignoresol )
    4433 {
    4434 /* select transformation bound */
    4435 varsol = (sol == NULL ? SCIPvarGetLPSol(var) : SCIPgetSolVal(scip, sol, var));
    4436
    4437 if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
    4438 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4439 else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
    4440 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4441 else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
    4442 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4443 else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
    4444 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4445 else if( *bestlbtype == -1 ) /* prefer global standard bounds */
    4446 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4447 else if( *bestubtype == -1 ) /* prefer global standard bounds */
    4448 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4449 else if( ((*bestlbtype) >= 0 || (*bestubtype) >= 0) && !SCIPisEQ(scip, *bestlb - simplelb, simpleub - *bestub) )
    4450 {
    4451 if( *bestlb - simplelb > simpleub - *bestub )
    4452 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4453 else
    4454 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4455 }
    4456 else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
    4457 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4458 else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
    4459 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4460 else /* no decision yet? just use lower bound */
    4461 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4462 }
    4463 else
    4464 {
    4465 SCIP_Real glbub = SCIPvarGetUbGlobal(var);
    4466 SCIP_Real glblb = SCIPvarGetLbGlobal(var);
    4467 SCIP_Real distlb = REALABS(glblb - *bestlb);
    4468 SCIP_Real distub = REALABS(glbub - *bestub);
    4469
    4470 assert(!SCIPisInfinity(scip, - *bestlb) || !SCIPisInfinity(scip, *bestub));
    4471
    4472 if( SCIPisInfinity(scip, - *bestlb) )
    4473 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4474 else if( !SCIPisNegative(scip, *bestlb) )
    4475 {
    4476 if( SCIPisInfinity(scip, *bestub) )
    4477 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4478 else if( SCIPisZero(scip, glblb) )
    4479 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4480 else if( SCIPisLE(scip, distlb, distub) )
    4481 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4482 else
    4483 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4484 }
    4485 else
    4486 {
    4487 assert(!SCIPisInfinity(scip, - *bestlb));
    4488 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4489 }
    4490 }
    4491 }
    4492
    4493 return SCIP_OKAY; /*lint !e438*/
    4494}
    4495
    4496/** finds the best lower bound of the variable to use for MIR transformation */
    4497static
    4499 SCIP* scip, /**< SCIP data structure */
    4500 SCIP_VAR* var, /**< problem variable */
    4501 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4502 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4503 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4504 SCIP_Real* bestlb, /**< pointer to store best bound value */
    4505 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4506 )
    4507{
    4508 assert(bestlb != NULL);
    4509 assert(bestlbtype != NULL);
    4510 assert(usevbds >= 0 && usevbds <= 2);
    4511
    4512 *bestlb = SCIPvarGetLbGlobal(var);
    4513 *bestlbtype = -1;
    4514
    4515 if( allowlocal )
    4516 {
    4517 SCIP_Real loclb;
    4518
    4519 loclb = SCIPvarGetLbLocal(var);
    4520 if( SCIPisGT(scip, loclb, *bestlb) )
    4521 {
    4522 *bestlb = loclb;
    4523 *bestlbtype = -2;
    4524 }
    4525 }
    4526
    4527 if( usevbds > 0 )
    4528 {
    4529 SCIP_Real bestvlb;
    4530 int bestvlbidx;
    4531
    4532 SCIP_CALL( SCIPgetVarClosestVlb(scip, var, sol, &bestvlb, &bestvlbidx) );
    4533 if( bestvlbidx >= 0 && (bestvlb > *bestlb || (*bestlbtype < 0 && SCIPisGE(scip, bestvlb, *bestlb))) )
    4534 {
    4535 SCIP_VAR** vlbvars;
    4536 SCIP_VAR* vlbvar;
    4537
    4538 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
    4539 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
    4540 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
    4541 */
    4542 vlbvars = SCIPvarGetVlbVars(var);
    4543 assert(vlbvars != NULL);
    4544 vlbvar = vlbvars[bestvlbidx];
    4545 assert(vlbvar != NULL);
    4546 if( ( usevbds == 2 || ( SCIPvarGetType(vlbvar) == SCIP_VARTYPE_BINARY
    4547 && !SCIPvarIsImpliedIntegral(vlbvar) ) ) )
    4548 {
    4549 assert(SCIPvarGetProbindex(vlbvar) < SCIPvarGetProbindex(var));
    4550 *bestlb = bestvlb;
    4551 *bestlbtype = bestvlbidx;
    4552 }
    4553 }
    4554 }
    4555
    4556 return SCIP_OKAY;
    4557}
    4558
    4559/** finds the best upper bound of the variable to use for MIR transformation */
    4560static
    4562 SCIP* scip, /**< SCIP data structure */
    4563 SCIP_VAR* var, /**< problem variable */
    4564 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4565 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4566 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4567 SCIP_Real* bestub, /**< pointer to store best bound value */
    4568 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4569 )
    4570{
    4571 assert(bestub != NULL);
    4572 assert(bestubtype != NULL);
    4573 assert(usevbds >= 0 && usevbds <= 2);
    4574
    4575 *bestub = SCIPvarGetUbGlobal(var);
    4576 *bestubtype = -1;
    4577
    4578 if( allowlocal )
    4579 {
    4580 SCIP_Real locub;
    4581
    4582 locub = SCIPvarGetUbLocal(var);
    4583 if( SCIPisLT(scip, locub, *bestub) )
    4584 {
    4585 *bestub = locub;
    4586 *bestubtype = -2;
    4587 }
    4588 }
    4589
    4590 if( usevbds > 0 )
    4591 {
    4592 SCIP_Real bestvub;
    4593 int bestvubidx;
    4594
    4595 SCIP_CALL( SCIPgetVarClosestVub(scip, var, sol, &bestvub, &bestvubidx) );
    4596 if( bestvubidx >= 0 && (bestvub < *bestub || (*bestubtype < 0 && SCIPisLE(scip, bestvub, *bestub))) )
    4597 {
    4598 SCIP_VAR** vubvars;
    4599 SCIP_VAR* vubvar;
    4600
    4601 /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
    4602 /**@todo this check is not needed for continuous variables; but allowing all but binary variables
    4603 * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
    4604 */
    4605 vubvars = SCIPvarGetVubVars(var);
    4606 assert(vubvars != NULL);
    4607 vubvar = vubvars[bestvubidx];
    4608 assert(vubvar != NULL);
    4609 if( ( usevbds == 2 || ( SCIPvarGetType(vubvar) == SCIP_VARTYPE_BINARY
    4610 && !SCIPvarIsImpliedIntegral(vubvar) ) ) )
    4611 {
    4612 assert( SCIPvarGetProbindex(vubvar) < SCIPvarGetProbindex(var) );
    4613 *bestub = bestvub;
    4614 *bestubtype = bestvubidx;
    4615 }
    4616 }
    4617 }
    4618
    4619 return SCIP_OKAY;
    4620}
    4621
    4622
    4623/** finds the best lower bound of the variable to use for MIR transformation.
    4624 * Differs from findBestLB() in that it allows more variable bound substitutions based on the variable sections. */
    4625static
    4627 SCIP* scip, /**< SCIP data structure */
    4628 SCIP_VAR* var, /**< problem variable */
    4629 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4630 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
    4631 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4632 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4633 SCIP_Real* bestlb, /**< pointer to store best bound value */
    4634 SCIP_Real* simplebound, /**< pointer to store simple bound value */
    4635 int* bestlbtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4636 )
    4637{
    4638 assert(bestlb != NULL);
    4639 assert(bestlbtype != NULL);
    4640 assert(usevbds >= 0 && usevbds <= 2);
    4641
    4642 *bestlb = SCIPvarGetLbGlobal(var);
    4643 *bestlbtype = -1;
    4644
    4645 if( allowlocal )
    4646 {
    4647 SCIP_Real loclb;
    4648
    4649 loclb = SCIPvarGetLbLocal(var);
    4650 if( SCIPisGT(scip, loclb, *bestlb) )
    4651 {
    4652 *bestlb = loclb;
    4653 *bestlbtype = -2;
    4654 }
    4655 }
    4656
    4657 *simplebound = *bestlb;
    4658
    4659 if( usevbds > 0 )
    4660 {
    4661 int nvlbs = SCIPvarGetNVlbs(var);
    4662
    4663 if( nvlbs > 0 )
    4664 {
    4665 SCIP_Real bestvlb = SCIP_REAL_MIN;
    4666 int bestvlbtype = -1;
    4667 int boundedsection = varSection(data, SCIPvarGetProbindex(var));
    4668
    4669 SCIP_VAR** vlbvars;
    4670 SCIP_Real* vlbcoefs;
    4671 SCIP_Real* vlbconsts;
    4672 int i;
    4673
    4674 vlbvars = SCIPvarGetVlbVars(var);
    4675 vlbcoefs = SCIPvarGetVlbCoefs(var);
    4676 vlbconsts = SCIPvarGetVlbConstants(var);
    4677
    4678 /* search best VLB */
    4679 for( i = 0; i < nvlbs; i++ )
    4680 {
    4681 /* For now, we only allow variable bounds from sections that are strictly greater to prevent cyclic usage.*/
    4682 /** @todo: We don't use the caching mechanism of SCIPvarGetClosestVLB() because the cached variable bound
    4683 * may be illegal. Building a local cache here may be worth it. */
    4684 if( SCIPvarIsActive(vlbvars[i]) && boundedsection < varSection(data, SCIPvarGetProbindex(vlbvars[i])) &&
    4685 (usevbds == 2 || SCIPvarIsBinary(vlbvars[i])) )
    4686 {
    4687 SCIP_Real vlbsol;
    4688 SCIP_Real vlbbnd;
    4689
    4690 vlbsol = SCIPgetSolVal(scip, sol, vlbvars[i]);
    4691 vlbbnd = vlbcoefs[i] * vlbsol + vlbconsts[i];
    4692
    4693 if( vlbbnd > bestvlb )
    4694 {
    4695 bestvlb = vlbbnd;
    4696 bestvlbtype = i;
    4697 }
    4698 }
    4699 }
    4700
    4701 if( bestvlbtype >= 0 && SCIPisGE(scip, bestvlb, *bestlb) )
    4702 {
    4703 *bestlb = bestvlb;
    4704 *bestlbtype = bestvlbtype;
    4705 }
    4706 }
    4707 }
    4708
    4709 return SCIP_OKAY;
    4710}
    4711
    4712/** finds the best upper bound of the variable to use for MIR transformation.
    4713 * Differs from findBestUB() in that it allows more variable bound substitutions based on the variable sections. */
    4714static
    4716 SCIP* scip, /**< SCIP data structure */
    4717 SCIP_VAR* var, /**< problem variable */
    4718 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4719 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
    4720 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4721 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4722 SCIP_Real* bestub, /**< pointer to store best bound value */
    4723 SCIP_Real* simplebound, /**< pointer to store simple bound */
    4724 int* bestubtype /**< pointer to store best bound type (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4725 )
    4726{
    4727 assert(bestub != NULL);
    4728 assert(bestubtype != NULL);
    4729 assert(usevbds >= 0 && usevbds <= 2);
    4730
    4731 *bestub = SCIPvarGetUbGlobal(var);
    4732 *bestubtype = -1;
    4733
    4734 if( allowlocal )
    4735 {
    4736 SCIP_Real locub;
    4737
    4738 locub = SCIPvarGetUbLocal(var);
    4739 if( SCIPisLT(scip, locub, *bestub) )
    4740 {
    4741 *bestub = locub;
    4742 *bestubtype = -2;
    4743 }
    4744 }
    4745
    4746 *simplebound = *bestub;
    4747
    4748 if( usevbds > 0 )
    4749 {
    4750 int nvubs = SCIPvarGetNVubs(var);
    4751
    4752 if( nvubs > 0 )
    4753 {
    4754 SCIP_Real bestvub = SCIP_REAL_MAX;
    4755 int bestvubtype = -1;
    4756 int boundedsection = varSection(data, SCIPvarGetProbindex(var));
    4757
    4758 SCIP_VAR** vubvars;
    4759 SCIP_Real* vubcoefs;
    4760 SCIP_Real* vubconsts;
    4761 int i;
    4762
    4763 vubvars = SCIPvarGetVubVars(var);
    4764 vubcoefs = SCIPvarGetVubCoefs(var);
    4765 vubconsts = SCIPvarGetVubConstants(var);
    4766
    4767 /* search best VUB */
    4768 for( i = 0; i < nvubs; i++ )
    4769 {
    4770 /* For now, we only allow variable bounds from sections that are strictly greater to prevent cyclic usage.*/
    4771 /** @todo: We don't use the caching mechanism of SCIPvarGetClosestVLB() because the cached variable bound
    4772 * may be illegal. Building a local cache here may be worth it. */
    4773 if( SCIPvarIsActive(vubvars[i]) && boundedsection < varSection(data, SCIPvarGetProbindex(vubvars[i])) &&
    4774 (usevbds == 2 || SCIPvarIsBinary(vubvars[i])) )
    4775 {
    4776 SCIP_Real vubsol;
    4777 SCIP_Real vubbnd;
    4778
    4779 vubsol = SCIPgetSolVal(scip, sol, vubvars[i]);
    4780 vubbnd = vubcoefs[i] * vubsol + vubconsts[i];
    4781
    4782 if( vubbnd < bestvub )
    4783 {
    4784 bestvub = vubbnd;
    4785 bestvubtype = i;
    4786 }
    4787 }
    4788 }
    4789
    4790 if( bestvubtype >= 0 && SCIPisLE(scip, bestvub, *bestub) )
    4791 {
    4792 *bestub = bestvub;
    4793 *bestubtype = bestvubtype;
    4794 }
    4795 }
    4796 }
    4797
    4798 return SCIP_OKAY;
    4799}
    4800
    4801/** determine the best bounds with respect to the given solution for complementing the given variable */
    4802static
    4804 SCIP* scip, /**< SCIP data structure */
    4805 SCIP_VAR* var, /**< variable to determine best bound for */
    4806 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    4807 MIR_DATA* data, /**< the MIR data that specifies the variable sections */
    4808 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    4809 int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
    4810 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    4811 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    4812 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
    4813 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    4814 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    4815 * NULL for using closest bound for all variables */
    4816 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    4817 * NULL for using closest bound for all variables */
    4818 SCIP_Real* bestlb, /**< pointer to store best lower bound of variable */
    4819 SCIP_Real* bestub, /**< pointer to store best upper bound of variable */
    4820 int* bestlbtype, /**< pointer to store type of best lower bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4821 int* bestubtype, /**< pointer to store type of best upper bound of variable (-2: local bound, -1: global bound, >= 0 variable bound index) */
    4822 SCIP_BOUNDTYPE* selectedbound, /**< pointer to store whether the lower bound or the upper bound should be preferred */
    4823 SCIP_Bool* freevariable /**< pointer to store if this is a free variable */
    4824 )
    4825{
    4826 SCIP_Real simplelb;
    4827 SCIP_Real simpleub;
    4828 int v;
    4829
    4830 assert(usevbds >= 0 && usevbds <= 2);
    4831
    4832 v = SCIPvarGetProbindex(var);
    4833
    4834 /* check if the user specified a bound to be used */
    4835 if( boundsfortrans != NULL && boundsfortrans[v] > -3 )
    4836 {
    4837 assert(!SCIPvarIsIntegral(var) || boundsfortrans[v] == -2 || boundsfortrans[v] == -1);
    4838 assert(boundtypesfortrans != NULL);
    4839
    4840 /* user has explicitly specified a bound to be used */
    4841 if( boundtypesfortrans[v] == SCIP_BOUNDTYPE_LOWER )
    4842 {
    4843 /* user wants to use lower bound */
    4844 *bestlbtype = boundsfortrans[v];
    4845 if( *bestlbtype == -1 )
    4846 *bestlb = SCIPvarGetLbGlobal(var); /* use global standard lower bound */
    4847 else if( *bestlbtype == -2 )
    4848 *bestlb = SCIPvarGetLbLocal(var); /* use local standard lower bound */
    4849 else
    4850 {
    4851 SCIP_Real vlbsol;
    4852 SCIP_VAR** vlbvars;
    4853 SCIP_Real* vlbcoefs;
    4854 SCIP_Real* vlbconsts;
    4855 int k;
    4856
    4857 assert(!ignoresol);
    4858
    4859 /* use the given variable lower bound */
    4860 vlbvars = SCIPvarGetVlbVars(var);
    4861 vlbcoefs = SCIPvarGetVlbCoefs(var);
    4862 vlbconsts = SCIPvarGetVlbConstants(var);
    4863 k = boundsfortrans[v];
    4864 assert(k >= 0 && k < SCIPvarGetNVlbs(var));
    4865 assert(vlbvars != NULL);
    4866 assert(vlbcoefs != NULL);
    4867 assert(vlbconsts != NULL);
    4868
    4869 vlbsol = SCIPgetSolVal(scip, sol, vlbvars[k]);
    4870
    4871 *bestlb = vlbcoefs[k] * vlbsol + vlbconsts[k];
    4872 }
    4873
    4874 assert(!SCIPisInfinity(scip, - *bestlb));
    4875 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4876
    4877 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
    4878 SCIP_CALL( findMIRBestUb(scip, var, sol, data, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestub, &simpleub, bestubtype) );
    4879 }
    4880 else
    4881 {
    4882 assert(boundtypesfortrans[v] == SCIP_BOUNDTYPE_UPPER);
    4883
    4884 /* user wants to use upper bound */
    4885 *bestubtype = boundsfortrans[v];
    4886 if( *bestubtype == -1 )
    4887 *bestub = SCIPvarGetUbGlobal(var); /* use global standard upper bound */
    4888 else if( *bestubtype == -2 )
    4889 *bestub = SCIPvarGetUbLocal(var); /* use local standard upper bound */
    4890 else
    4891 {
    4892 SCIP_Real vubsol;
    4893 SCIP_VAR** vubvars;
    4894 SCIP_Real* vubcoefs;
    4895 SCIP_Real* vubconsts;
    4896 int k;
    4897
    4898 assert(!ignoresol);
    4899
    4900 /* use the given variable upper bound */
    4901 vubvars = SCIPvarGetVubVars(var);
    4902 vubcoefs = SCIPvarGetVubCoefs(var);
    4903 vubconsts = SCIPvarGetVubConstants(var);
    4904 k = boundsfortrans[v];
    4905 assert(k >= 0 && k < SCIPvarGetNVubs(var));
    4906 assert(vubvars != NULL);
    4907 assert(vubcoefs != NULL);
    4908 assert(vubconsts != NULL);
    4909
    4910 vubsol = SCIPgetSolVal(scip, sol, vubvars[k]);
    4911 *bestub = vubcoefs[k] * vubsol + vubconsts[k];
    4912 }
    4913
    4914 assert(!SCIPisInfinity(scip, *bestub));
    4915 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4916
    4917 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
    4918 SCIP_CALL( findMIRBestLb(scip, var, sol, data, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestlb, &simplelb, bestlbtype) );
    4919 }
    4920 }
    4921 else
    4922 {
    4923 SCIP_Real varsol;
    4924
    4925 /* bound selection should be done automatically */
    4926
    4927 /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
    4928 SCIP_CALL( findMIRBestLb(scip, var, sol, data, usevbds, allowlocal, bestlb, &simplelb, bestlbtype) );
    4929
    4930 /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
    4931 SCIP_CALL( findMIRBestUb(scip, var, sol, data, usevbds, allowlocal, bestub, &simpleub, bestubtype) );
    4932
    4933 /* check, if variable is free variable */
    4934 if( SCIPisInfinity(scip, - *bestlb) && SCIPisInfinity(scip, *bestub) )
    4935 {
    4936 /* we found a free variable in the row with non-zero coefficient
    4937 * -> MIR row can't be transformed in standard form
    4938 */
    4939 *freevariable = TRUE;
    4940 return SCIP_OKAY;
    4941 }
    4942
    4943 if( !ignoresol )
    4944 {
    4945 /* select transformation bound */
    4946 varsol = SCIPgetSolVal(scip, sol, var);
    4947
    4948 if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
    4949 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4950 else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
    4951 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4952 else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
    4953 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4954 else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
    4955 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4956 else if( *bestlbtype == -1 ) /* prefer global standard bounds */
    4957 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4958 else if( *bestubtype == -1 ) /* prefer global standard bounds */
    4959 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4960 else if( ((*bestlbtype) >= 0 || (*bestubtype) >= 0) && !SCIPisEQ(scip, *bestlb - simplelb, simpleub - *bestub) )
    4961 {
    4962 if( *bestlb - simplelb > simpleub - *bestub )
    4963 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4964 else
    4965 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4966 }
    4967 else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
    4968 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4969 else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
    4970 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4971 else /* no decision yet? just use lower bound */
    4972 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4973 }
    4974 else
    4975 {
    4976 SCIP_Real glbub = SCIPvarGetUbGlobal(var);
    4977 SCIP_Real glblb = SCIPvarGetLbGlobal(var);
    4978 SCIP_Real distlb = REALABS(glblb - *bestlb);
    4979 SCIP_Real distub = REALABS(glbub - *bestub);
    4980
    4981 assert(!SCIPisInfinity(scip, - *bestlb) || !SCIPisInfinity(scip, *bestub));
    4982
    4983 if( SCIPisInfinity(scip, - *bestlb) )
    4984 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4985 else if( !SCIPisNegative(scip, *bestlb) )
    4986 {
    4987 if( SCIPisInfinity(scip, *bestub) )
    4988 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4989 else if( SCIPisZero(scip, glblb) )
    4990 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4991 else if( SCIPisLE(scip, distlb, distub) )
    4992 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    4993 else
    4994 *selectedbound = SCIP_BOUNDTYPE_UPPER;
    4995 }
    4996 else
    4997 {
    4998 assert(!SCIPisInfinity(scip, - *bestlb));
    4999 *selectedbound = SCIP_BOUNDTYPE_LOWER;
    5000 }
    5001 }
    5002 }
    5003
    5004 return SCIP_OKAY; /*lint !e438*/
    5005}
    5006
    5007/** Performs bound substitution for a MIR cut */
    5008static
    5010 SCIP* scip, /**< SCIP datastructure */
    5011 MIR_DATA* data, /**< the MIR data structure for this cut */
    5012 int varsign, /**< stores the sign of the transformed variable in summation */
    5013 int boundtype, /**< stores the bound used for transformed variable:
    5014 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5015 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
    5016 int probindex, /**< problem index of variable to perform the substitution step for */
    5017 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
    5018 )
    5019{
    5020 SCIP_Real QUAD(coef);
    5021 SCIP_Real QUAD(tmp);
    5022
    5023 assert(!SCIPisInfinity(scip, -varsign * boundval));
    5024
    5025 QUAD_ARRAY_LOAD(coef, data->cutcoefs, probindex);
    5026
    5027 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
    5028 if( boundtype < 0 )
    5029 {
    5030 SCIPquadprecProdQD(tmp, coef, boundval);
    5031 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, -tmp);
    5032 *localbdsused = *localbdsused || ( boundtype == -2 );
    5033 }
    5034 else
    5035 {
    5036 SCIP_VAR** vbdvars;
    5037 SCIP_Real* vbdcoefs;
    5038 SCIP_Real* vbdconsts;
    5039 SCIP_Real QUAD(zcoef);
    5040 int zidx;
    5041 SCIP_VAR* var = SCIPgetVars(scip)[probindex];
    5042
    5043 if( varsign == +1 )
    5044 {
    5045 vbdvars = SCIPvarGetVlbVars(var);
    5046 vbdcoefs = SCIPvarGetVlbCoefs(var);
    5047 vbdconsts = SCIPvarGetVlbConstants(var);
    5048 assert(0 <= boundtype && boundtype < SCIPvarGetNVlbs(var));
    5049 }
    5050 else
    5051 {
    5052 vbdvars = SCIPvarGetVubVars(var);
    5053 vbdcoefs = SCIPvarGetVubCoefs(var);
    5054 vbdconsts = SCIPvarGetVubConstants(var);
    5055 assert(0 <= boundtype && boundtype < SCIPvarGetNVubs(var));
    5056 }
    5057
    5058 assert(vbdvars != NULL);
    5059 assert(vbdcoefs != NULL);
    5060 assert(vbdconsts != NULL);
    5061 assert(SCIPvarIsActive(vbdvars[boundtype]));
    5062
    5063 zidx = SCIPvarGetProbindex(vbdvars[boundtype]);
    5064
    5065 SCIPquadprecProdQD(tmp, coef, vbdconsts[boundtype]);
    5066 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, -tmp);
    5067
    5068 /* check if integral variable already exists in the row */
    5069 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
    5070
    5071 /* If it is new, add it to the indices */
    5072 if( QUAD_HI(zcoef) == 0.0 )
    5073 {
    5074 int section = varSection(data, zidx);
    5075 assert(section > varSection(data, probindex));
    5076
    5077 data->secindices[section][data->secnnz[section]] = zidx;
    5078 ++data->secnnz[section];
    5079 ++data->totalnnz;
    5080 }
    5081
    5082 SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype]);
    5083 SCIPquadprecSumQQ(zcoef, zcoef, tmp);
    5084
    5085 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
    5086 assert(QUAD_HI(zcoef) != 0.0);
    5087
    5088 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
    5089 }
    5090}
    5091
    5092/** performs the bound substitution step with the given variable or simple bounds for the variable with the given problem index
    5093 *
    5094 * @note this method is safe for usage in exact solving mode
    5095 *
    5096 * @todo make behavior identical to the unsafe MIR cut computation
    5097 */
    5098static
    5100 SCIP* scip, /**< SCIP datastructure */
    5101 SCIP_Real* cutcoefs, /**< array of cut coefficients */
    5102 SCIP_Real* cutrhs, /**< pointer to right hand side of the cut */
    5103 int varsign, /**< stores the sign of the transformed variable in summation */
    5104 int boundtype, /**< stores the bound used for transformed variable:
    5105 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5106 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
    5107 int probindex, /**< problem index of variable to perform the substitution step for */
    5108 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
    5109 )
    5110{
    5111 SCIP_Real coef;
    5112 SCIP_ROUNDMODE previousroundmode;
    5113
    5114 assert(!SCIPisInfinity(scip, -varsign * boundval));
    5115 assert(SCIPisExact(scip));
    5116
    5117 previousroundmode = SCIPintervalGetRoundingMode();
    5119
    5120 coef = cutcoefs[probindex];
    5121
    5122 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
    5123 if( boundtype < 0 )
    5124 {
    5125 *cutrhs += coef * (-boundval);
    5126 *localbdsused = *localbdsused || (boundtype == -2);
    5127 }
    5128 else
    5129 {
    5130 /* we don't support vlbs in exact mode yet */
    5131 assert(!SCIPisExact(scip));
    5132 SCIPerrorMessage("variable lower bounds not implemented in exact solving mode yet \n");
    5133 SCIPABORT();
    5134 }
    5135
    5136 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
    5137}
    5138
    5139/** performs the bound substitution step with the simple bound for the variable with the given problem index
    5140 *
    5141 * @note this method is safe for usage in exact solving mode
    5142 *
    5143 * @todo make behavior identical to the unsafe MIR cut computation
    5144 */
    5145static
    5147 SCIP* scip, /**< SCIP datastructure */
    5148 SCIP_Real* cutcoefs, /**< array of cut coefficients */
    5149 SCIP_Real* cutrhs, /**< pointer to right hand side of the cut */
    5150 int boundtype, /**< stores the bound used for transformed variable:
    5151 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5152 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
    5153 int probindex, /**< problem index of variable to perform the substitution step for */
    5154 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
    5155 )
    5156{
    5157 SCIP_Real coef;
    5158 SCIP_ROUNDMODE previousroundmode;
    5159
    5160 assert(!SCIPisInfinity(scip, ABS(boundval)));
    5161 assert(SCIPisExact(scip));
    5162
    5163 previousroundmode = SCIPintervalGetRoundingMode();
    5165
    5166 coef = cutcoefs[probindex];
    5167
    5168 /* must be a standard bound */
    5169 assert( boundtype < 0 );
    5170
    5171 *cutrhs += coef * (-boundval);
    5172
    5173 *localbdsused = *localbdsused || (boundtype == -2);
    5174
    5175 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
    5176}
    5177
    5178/** performs the bound substitution step with the given variable or simple bounds for the variable with the given problem index */
    5179static
    5181 SCIP* scip, /**< SCIP datastructure */
    5182 int* cutinds, /**< index array of nonzeros in the cut */
    5183 SCIP_Real* cutcoefs, /**< array of cut coefficients */
    5184 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
    5185 int* nnz, /**< pointer to number of nonzeros of the cut */
    5186 int varsign, /**< stores the sign of the transformed variable in summation */
    5187 int boundtype, /**< stores the bound used for transformed variable:
    5188 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5189 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
    5190 int probindex, /**< problem index of variable to perform the substitution step for */
    5191 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
    5192 )
    5193{
    5194 SCIP_Real QUAD(coef);
    5195 SCIP_Real QUAD(tmp);
    5196
    5197 assert(!SCIPisInfinity(scip, -varsign * boundval));
    5198 assert(!SCIPisExact(scip));
    5199
    5200 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
    5201
    5202 /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
    5203 if( boundtype < 0 )
    5204 {
    5205 SCIPquadprecProdQD(tmp, coef, boundval);
    5206 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
    5207 *localbdsused = *localbdsused || (boundtype == -2);
    5208 }
    5209 else
    5210 {
    5211 SCIP_VAR** vbdvars;
    5212 SCIP_Real* vbdcoefs;
    5213 SCIP_Real* vbdconsts;
    5214 SCIP_Real QUAD(zcoef);
    5215 int zidx;
    5216 SCIP_VAR* var = SCIPgetVars(scip)[probindex];
    5217
    5218 if( varsign == +1 )
    5219 {
    5220 vbdvars = SCIPvarGetVlbVars(var);
    5221 vbdcoefs = SCIPvarGetVlbCoefs(var);
    5222 vbdconsts = SCIPvarGetVlbConstants(var);
    5223 assert(0 <= boundtype && boundtype < SCIPvarGetNVlbs(var));
    5224 }
    5225 else
    5226 {
    5227 vbdvars = SCIPvarGetVubVars(var);
    5228 vbdcoefs = SCIPvarGetVubCoefs(var);
    5229 vbdconsts = SCIPvarGetVubConstants(var);
    5230 assert(0 <= boundtype && boundtype < SCIPvarGetNVubs(var));
    5231 }
    5232
    5233 assert(vbdvars != NULL);
    5234 assert(vbdcoefs != NULL);
    5235 assert(vbdconsts != NULL);
    5236 assert(SCIPvarIsActive(vbdvars[boundtype]));
    5237
    5238 zidx = SCIPvarGetProbindex(vbdvars[boundtype]);
    5239
    5240 SCIPquadprecProdQD(tmp, coef, vbdconsts[boundtype]);
    5241 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
    5242
    5243 /* check if integral variable already exists in the row */
    5244 QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
    5245
    5246 if( QUAD_HI(zcoef) == 0.0 )
    5247 cutinds[(*nnz)++] = zidx;
    5248
    5249 SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype]);
    5250 SCIPquadprecSumQQ(zcoef, zcoef, tmp);
    5251
    5252 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
    5253 assert(QUAD_HI(zcoef) != 0.0);
    5254
    5255 QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
    5256 }
    5257}
    5258
    5259/** performs the bound substitution step with the simple bound for the variable with the given problem index */
    5260static
    5262 SCIP* scip, /**< SCIP datastructure */
    5263 SCIP_Real* cutcoefs, /**< array of cut coefficients */
    5264 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
    5265 int boundtype, /**< stores the bound used for transformed variable:
    5266 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5267 SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
    5268 int probindex, /**< problem index of variable to perform the substitution step for */
    5269 SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
    5270 )
    5271{
    5272 SCIP_Real QUAD(coef);
    5273 SCIP_Real QUAD(tmp);
    5274
    5275 assert(!SCIPisInfinity(scip, ABS(boundval)));
    5276 assert(!SCIPisExact(scip));
    5277
    5278 QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
    5279
    5280 /* must be a standard bound */
    5281 assert( boundtype < 0 );
    5282
    5283 SCIPquadprecProdQD(tmp, coef, boundval);
    5284 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
    5285 *localbdsused = *localbdsused || (boundtype == -2);
    5286}
    5287
    5288/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
    5289 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
    5290 *
    5291 * Transform variables (lb or ub):
    5292 * \f[
    5293 * \begin{array}{llll}
    5294 * 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},\\
    5295 * 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},
    5296 * \end{array}
    5297 * \f]
    5298 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
    5299 *
    5300 * Transform variables (vlb or vub):
    5301 * \f[
    5302 * \begin{array}{llll}
    5303 * 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.} \\
    5304 * 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.}
    5305 * \end{array}
    5306 * \f]
    5307 * 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:
    5308 * \f[
    5309 * \begin{array}{ll}
    5310 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
    5311 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
    5312 * \end{array}
    5313 * \f]
    5314 *
    5315 * @note this method is safe for usage in exact solving mode
    5316 *
    5317 * @todo make behavior identical to the unsafe MIR cut computation
    5318 */
    5319static
    5321 SCIP* scip, /**< SCIP data structure */
    5322 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    5323 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    5324 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
    5325 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    5326 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    5327 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
    5328 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    5329 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    5330 * NULL for using closest bound for all variables */
    5331 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    5332 * NULL for using closest bound for all variables */
    5333 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    5334 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
    5335 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    5336 int* nnz, /**< number of non-zeros in cut */
    5337 int* varsign, /**< stores the sign of the transformed variable in summation */
    5338 int* boundtype, /**< stores the bound used for transformed variable:
    5339 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5340 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
    5341 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
    5342 )
    5343{ /*lint --e{644}*/
    5344 SCIP_Real* bestlbs;
    5345 SCIP_Real* bestubs;
    5346 int* bestlbtypes;
    5347 int* bestubtypes;
    5348 SCIP_BOUNDTYPE* selectedbounds;
    5349 int i;
    5350 int aggrrowintstart;
    5351 int nvars;
    5352 int firstcontvar;
    5353 SCIP_VAR** vars;
    5354 SCIP_MIRINFO* mirinfo = NULL;
    5355
    5356 SCIP_ROUNDMODE previousroundmode;
    5357
    5358 assert(varsign != NULL);
    5359 assert(boundtype != NULL);
    5360 assert(freevariable != NULL);
    5361 assert(localbdsused != NULL);
    5362 assert(SCIPisExact(scip));
    5363
    5364 if( SCIPisCertified(scip) )
    5366 previousroundmode = SCIPintervalGetRoundingMode();
    5368
    5369 *freevariable = FALSE;
    5370 *localbdsused = FALSE;
    5371
    5372 /* allocate temporary memory to store best bounds and bound types */
    5373 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, 2*(*nnz)) );
    5374 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, 2*(*nnz)) );
    5375 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, 2*(*nnz)) );
    5376 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, 2*(*nnz)) );
    5377 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, 2*(*nnz)) );
    5378
    5379 /* start with continuous variables, because using variable bounds can affect the untransformed integral
    5380 * variables, and these changes have to be incorporated in the transformation of the integral variables
    5381 * (continuous variables have largest problem indices!)
    5382 */
    5383 SCIPsortDownInt(cutinds, *nnz);
    5384
    5385 vars = SCIPgetVars(scip);
    5386 nvars = SCIPgetNVars(scip);
    5387 firstcontvar = nvars - SCIPgetNContVars(scip);
    5388
    5389 /* determine the best bounds for the continuous variables */
    5390 for( i = 0; i < *nnz && cutinds[i] >= firstcontvar; ++i )
    5391 {
    5392 SCIP_CALL( determineBestBoundsSafely(scip, vars[cutinds[i]], sol, boundswitch, usevbds ? 2 : 0, allowlocal, fixintegralrhs,
    5393 ignoresol, boundsfortrans, boundtypesfortrans,
    5394 bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
    5395
    5396 if( *freevariable )
    5397 goto TERMINATE;
    5398 }
    5399
    5400 /* remember start of integer variables in the aggrrow */
    5401 aggrrowintstart = i;
    5402
    5403 /* perform bound substitution for continuous variables */
    5404 for( i = 0; i < aggrrowintstart; ++i )
    5405 {
    5406 int v = cutinds[i];
    5407
    5408 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
    5409 {
    5410 assert(!SCIPisInfinity(scip, -bestlbs[i]));
    5411
    5412 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
    5413 boundtype[i] = bestlbtypes[i];
    5414 varsign[i] = +1;
    5415
    5416 performBoundSubstitutionSafely(scip, cutcoefs, cutrhs, varsign[i], boundtype[i], bestlbs[i], v, localbdsused);
    5417 }
    5418 else
    5419 {
    5420 assert(!SCIPisInfinity(scip, bestubs[i]));
    5421
    5422 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
    5423 boundtype[i] = bestubtypes[i];
    5424 varsign[i] = -1;
    5425
    5426 performBoundSubstitutionSafely(scip, cutcoefs, cutrhs, varsign[i], boundtype[i], bestubs[i], v, localbdsused);
    5427 }
    5428
    5429 if( SCIPisCertified(scip) )
    5430 {
    5431 assert(mirinfo != NULL);
    5432 if( boundtype[i] == -2 )
    5433 {
    5434 mirinfo->localbdused[v] = TRUE;
    5435 mirinfo->nlocalvars++;
    5436 }
    5437 mirinfo->upperused[v] = (varsign[i] == -1);
    5438 }
    5439 }
    5440
    5441 /* remove integral variables that now have a zero coefficient due to variable bound usage of continuous variables
    5442 * and determine the bound to use for the integer variables that are left
    5443 */
    5444 while( i < *nnz )
    5445 {
    5446 int v = cutinds[i];
    5447 assert(cutinds[i] < firstcontvar);
    5448
    5449 /* determine the best bounds for the integral variable, usevbd can be set to 0 here as vbds are only used for continuous variables */
    5450 SCIP_CALL( determineBestBoundsSafely(scip, vars[v], sol, boundswitch, 0, allowlocal, fixintegralrhs,
    5451 ignoresol, boundsfortrans, boundtypesfortrans,
    5452 bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
    5453
    5454 /* increase i */
    5455 ++i;
    5456
    5457 if( *freevariable )
    5458 goto TERMINATE;
    5459 }
    5460
    5461 /* now perform the bound substitution on the remaining integral variables which only uses standard bounds */
    5462 for( i = aggrrowintstart; i < *nnz; ++i )
    5463 {
    5464 int v = cutinds[i];
    5465
    5466 /* perform bound substitution */
    5467 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
    5468 {
    5469 assert(!SCIPisInfinity(scip, - bestlbs[i]));
    5470 assert(bestlbtypes[i] < 0);
    5471
    5472 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
    5473 boundtype[i] = bestlbtypes[i];
    5474 varsign[i] = +1;
    5475
    5476 performBoundSubstitutionSimpleSafely(scip, cutcoefs, cutrhs, boundtype[i], bestlbs[i], v, localbdsused);
    5477 }
    5478 else
    5479 {
    5480 assert(!SCIPisInfinity(scip, bestubs[i]));
    5481 assert(bestubtypes[i] < 0);
    5482
    5483 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
    5484 boundtype[i] = bestubtypes[i];
    5485 varsign[i] = -1;
    5486
    5487 performBoundSubstitutionSimpleSafely(scip, cutcoefs, cutrhs, boundtype[i], bestubs[i], v, localbdsused);
    5488 }
    5489
    5490 if( SCIPisCertified(scip) )
    5491 {
    5492 assert(mirinfo != NULL);
    5493 if( boundtype[i] == -2 )
    5494 {
    5495 mirinfo->localbdused[v] = TRUE;
    5496 mirinfo->nlocalvars++;
    5497 }
    5498 mirinfo->upperused[v] = (varsign[i] == -1);
    5499 }
    5500 }
    5501
    5502 TERMINATE:
    5503 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
    5504
    5505 /*free temporary memory */
    5506 SCIPfreeBufferArray(scip, &selectedbounds);
    5507 SCIPfreeBufferArray(scip, &bestubtypes);
    5508 SCIPfreeBufferArray(scip, &bestlbtypes);
    5509 SCIPfreeBufferArray(scip, &bestubs);
    5510 SCIPfreeBufferArray(scip, &bestlbs);
    5511
    5512 return SCIP_OKAY;
    5513}
    5514
    5515/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
    5516 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
    5517 *
    5518 * Transform variables (lb or ub):
    5519 * \f[
    5520 * \begin{array}{llll}
    5521 * 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},\\
    5522 * 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},
    5523 * \end{array}
    5524 * \f]
    5525 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
    5526 *
    5527 * Transform variables (vlb or vub):
    5528 * \f[
    5529 * \begin{array}{llll}
    5530 * 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.} \\
    5531 * 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.}
    5532 * \end{array}
    5533 * \f]
    5534 * 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:
    5535 * \f[
    5536 * \begin{array}{ll}
    5537 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
    5538 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
    5539 * \end{array}
    5540 * \f]
    5541 */
    5542static
    5544 SCIP* scip, /**< SCIP datastructure */
    5545 MIR_DATA* data, /**< the MIR data structure for this cut */
    5546 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    5547 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    5548 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    5549 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    5550 SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
    5551 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    5552 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    5553 * NULL for using closest bound for all variables */
    5554 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    5555 * NULL for using closest bound for all variables */
    5556 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
    5557 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
    5558 int* varsign, /**< stores the sign of the transformed variable in summation */
    5559 int* boundtype, /**< stores the bound used for transformed variable:
    5560 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    5561 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
    5562 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
    5563 )
    5564{
    5565 SCIP_Real* bestlbs;
    5566 SCIP_Real* bestubs;
    5567 int* bestlbtypes;
    5568 int* bestubtypes;
    5569 SCIP_BOUNDTYPE* selectedbounds;
    5570 SCIP_Real QUAD(coef);
    5571 int totalnnz;
    5572 int s;
    5573 int i;
    5574
    5575 assert(data != NULL);
    5576 assert(varsign != NULL);
    5577 assert(boundtype != NULL);
    5578 assert(freevariable != NULL);
    5579 assert(localbdsused != NULL);
    5580
    5581 totalnnz = data->totalnnz;
    5582
    5583 *freevariable = FALSE;
    5584 *localbdsused = FALSE;
    5585
    5586 int allocsize = MIN(NSECTIONS * totalnnz, data->nvars);
    5587 /* allocate temporary memory to store best bounds and bound types */
    5588 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, allocsize) );
    5589 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, allocsize) );
    5590 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, allocsize) );
    5591 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, allocsize) );
    5592 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, allocsize) );
    5593
    5594 /* transform the cut, one variable section at a time */
    5595 for( s = 0; s < NSECTIONS; ++s )
    5596 {
    5597 int* indices = data->secindices[s];
    5598 int cutindsstart = data->ncutinds;
    5599 int usevbds = data->usevbds[s];
    5600
    5601 i = 0;
    5602 while( i < data->secnnz[s] )
    5603 {
    5604 int cutindex;
    5605 int v = indices[i];
    5606
    5607 /* due to variable bound usage, cancellation may have occurred */
    5608 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
    5609 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
    5610 {
    5611 QUAD_ASSIGN(coef, 0.0);
    5612 QUAD_ARRAY_STORE(data->cutcoefs, v, coef);
    5613 --data->secnnz[s];
    5614 --data->totalnnz;
    5615 indices[i] = indices[data->secnnz[s]];
    5616 /* do not increase the index */
    5617 continue;
    5618 }
    5619
    5620 cutindex = data->ncutinds;
    5621 assert(cutindex < allocsize);
    5622 SCIP_CALL( determineBestBounds(scip, data->vars[v], sol, data, boundswitch, usevbds, allowlocal, fixintegralrhs,
    5623 ignoresol, boundsfortrans, boundtypesfortrans,
    5624 bestlbs + cutindex, bestubs + cutindex, bestlbtypes + cutindex, bestubtypes + cutindex,
    5625 selectedbounds + cutindex, freevariable) );
    5626
    5627 data->cutinds[cutindex] = v;
    5628 ++data->ncutinds;
    5629
    5630 ++i;
    5631
    5632 /* if there is a free variable, we terminate because we cannot derive a MIR cut */
    5633 if( *freevariable )
    5634 {
    5635 int j;
    5636 int k;
    5637
    5638 data->ncutinds = 0;
    5639
    5640 /* if we terminate early, we need to make sure all the zeros in the cut coefficient array are cancelled */
    5641 for( j = 0; j < NSECTIONS; ++j )
    5642 {
    5643 int* indexlist = data->secindices[j];
    5644 for( k = 0; k < data->secnnz[j]; ++k )
    5645 {
    5646 data->cutinds[data->ncutinds] = indexlist[k];
    5647 ++data->ncutinds;
    5648 }
    5649 }
    5650 goto TERMINATE;
    5651 }
    5652 }
    5653
    5654 /* perform bound substitution for added variables */
    5655 for( i = cutindsstart; i < data->ncutinds; ++i )
    5656 {
    5657 SCIP_Real bestbnd;
    5658 int v = data->cutinds[i];
    5659
    5660 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
    5661 {
    5662 assert(!SCIPisInfinity(scip, -bestlbs[i]));
    5663
    5664 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
    5665 boundtype[i] = bestlbtypes[i];
    5666 varsign[i] = +1;
    5667 bestbnd = bestlbs[i];
    5668 }
    5669 else
    5670 {
    5671 assert(!SCIPisInfinity(scip, bestubs[i]));
    5672
    5673 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
    5674 boundtype[i] = bestubtypes[i];
    5675 varsign[i] = -1;
    5676 bestbnd = bestubs[i];
    5677 }
    5678 doMIRBoundSubstitution(scip, data, varsign[i], boundtype[i], bestbnd, v, localbdsused);
    5679 }
    5680 }
    5681
    5682 if( fixintegralrhs )
    5683 {
    5684 SCIP_Real f0;
    5685
    5686 /* check if rhs is fractional */
    5687 f0 = EPSFRAC(QUAD_TO_DBL(data->cutrhs), SCIPsumepsilon(scip));
    5688 if( f0 < minfrac || f0 > maxfrac )
    5689 {
    5690 SCIP_Real bestviolgain;
    5691 SCIP_Real bestnewf0;
    5692 int besti;
    5693
    5694 /* choose complementation of one variable differently such that f0 is in correct range */
    5695 besti = -1;
    5696 bestviolgain = -1e+100;
    5697 bestnewf0 = 1.0;
    5698 for( i = 0; i < data->ncutinds; i++ )
    5699 {
    5700 int v;
    5701
    5702 v = data->cutinds[i];
    5703 assert(0 <= v && v < data->nvars);
    5704
    5705 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
    5706 assert(!EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON));
    5707
    5708 if( boundtype[i] < 0
    5709 && ((varsign[i] == +1 && !SCIPisInfinity(scip, bestubs[i]) && bestubtypes[i] < 0)
    5710 || (varsign[i] == -1 && !SCIPisInfinity(scip, -bestlbs[i]) && bestlbtypes[i] < 0)) )
    5711 {
    5712 SCIP_Real fj;
    5713 SCIP_Real newfj;
    5714 SCIP_Real newrhs;
    5715 SCIP_Real newf0;
    5716 SCIP_Real solval;
    5717 SCIP_Real viol;
    5718 SCIP_Real newviol;
    5719 SCIP_Real violgain;
    5720
    5721 /* currently: a'_j = varsign * a_j -> f'_j = a'_j - floor(a'_j)
    5722 * after complementation: a''_j = -varsign * a_j -> f''_j = a''_j - floor(a''_j) = 1 - f'_j
    5723 * rhs'' = rhs' + varsign * a_j * (lb_j - ub_j)
    5724 * cut violation from f0 and fj: f'_0 - f'_j * x'_j
    5725 * after complementation: f''_0 - f''_j * x''_j
    5726 *
    5727 * for continuous variables, we just set f'_j = f''_j = |a'_j|
    5728 */
    5729 newrhs = QUAD_TO_DBL(data->cutrhs) + varsign[i] * QUAD_TO_DBL(coef) * (bestlbs[i] - bestubs[i]);
    5730 newf0 = EPSFRAC(newrhs, SCIPsumepsilon(scip));
    5731
    5732 if( newf0 < minfrac || newf0 > maxfrac )
    5733 continue;
    5734 if( v >= data->nvars - data->ncontvars )
    5735 {
    5736 fj = REALABS(QUAD_TO_DBL(coef));
    5737 newfj = fj;
    5738 }
    5739 else
    5740 {
    5741 fj = SCIPfrac(scip, varsign[i] * QUAD_TO_DBL(coef));
    5742 newfj = SCIPfrac(scip, -varsign[i] * QUAD_TO_DBL(coef));
    5743 }
    5744
    5745 if( !ignoresol )
    5746 {
    5747 solval = SCIPgetSolVal(scip, sol, data->vars[v]);
    5748 viol = f0 - fj * (varsign[i] == +1 ? solval - bestlbs[i] : bestubs[i] - solval);
    5749 newviol = newf0 - newfj * (varsign[i] == -1 ? solval - bestlbs[i] : bestubs[i] - solval);
    5750 violgain = newviol - viol;
    5751 }
    5752 else
    5753 {
    5754 /* todo: this should be done, this can improve the dualray significantly */
    5755 SCIPerrorMessage("Cannot handle closest bounds with ignoring the LP solution.\n");
    5756 return SCIP_INVALIDCALL;
    5757 }
    5758
    5759 /* prefer larger violations; for equal violations, prefer smaller f0 values since then the possibility that
    5760 * we f_j > f_0 is larger and we may improve some coefficients in rounding
    5761 */
    5762 if( SCIPisGT(scip, violgain, bestviolgain) || (SCIPisGE(scip, violgain, bestviolgain) && newf0 < bestnewf0) )
    5763 {
    5764 besti = i;
    5765 bestviolgain = violgain;
    5766 bestnewf0 = newf0;
    5767 }
    5768 }
    5769 }
    5770
    5771 if( besti >= 0 )
    5772 {
    5773 SCIP_Real QUAD(tmp);
    5774
    5775 assert(besti < data->ncutinds);
    5776 assert(boundtype[besti] < 0);
    5777 assert(!SCIPisInfinity(scip, -bestlbs[besti]));
    5778 assert(!SCIPisInfinity(scip, bestubs[besti]));
    5779
    5780 QUAD_ARRAY_LOAD(coef, data->cutcoefs, data->cutinds[besti]);
    5781 QUAD_SCALE(coef, varsign[besti]);
    5782
    5783 /* switch the complementation of this variable */
    5784 SCIPquadprecSumDD(tmp, bestlbs[besti], - bestubs[besti]);
    5785 SCIPquadprecProdQQ(tmp, tmp, coef);
    5786 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    5787
    5788 if( varsign[besti] == +1 )
    5789 {
    5790 /* switch to upper bound */
    5791 assert(bestubtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
    5792 boundtype[besti] = bestubtypes[besti];
    5793 varsign[besti] = -1;
    5794 }
    5795 else
    5796 {
    5797 /* switch to lower bound */
    5798 assert(bestlbtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
    5799 boundtype[besti] = bestlbtypes[besti];
    5800 varsign[besti] = +1;
    5801 }
    5802 *localbdsused = *localbdsused || (boundtype[besti] == -2);
    5803 }
    5804 }
    5805 }
    5806
    5807 TERMINATE:
    5808
    5809 /*free temporary memory */
    5810 SCIPfreeBufferArray(scip, &selectedbounds);
    5811 SCIPfreeBufferArray(scip, &bestubtypes);
    5812 SCIPfreeBufferArray(scip, &bestlbtypes);
    5813 SCIPfreeBufferArray(scip, &bestubs);
    5814 SCIPfreeBufferArray(scip, &bestlbs);
    5815
    5816 return SCIP_OKAY;
    5817}
    5818
    5819/** 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$
    5820 * \f[
    5821 * \begin{array}{rll}
    5822 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
    5823 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
    5824 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
    5825 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
    5826 * \end{array}
    5827 * \f]
    5828 *
    5829 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
    5830 *
    5831 * (lb or ub):
    5832 * \f[
    5833 * \begin{array}{lllll}
    5834 * 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}, \\
    5835 * 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},
    5836 * \end{array}
    5837 * \f]
    5838 * and move the constant terms
    5839 * \f[
    5840 * \begin{array}{cl}
    5841 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
    5842 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
    5843 * \end{array}
    5844 * \f]
    5845 * to the rhs.
    5846 *
    5847 * (vlb or vub):
    5848 * \f[
    5849 * \begin{array}{lllll}
    5850 * 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)} \\
    5851 * 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)}
    5852 * \end{array}
    5853 * \f]
    5854 * move the constant terms
    5855 * \f[
    5856 * \begin{array}{cl}
    5857 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
    5858 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
    5859 * \end{array}
    5860 * \f]
    5861 * to the rhs, and update the VB variable coefficients:
    5862 * \f[
    5863 * \begin{array}{ll}
    5864 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
    5865 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
    5866 * \end{array}
    5867 * \f]
    5868 *
    5869 * @note this method is safe for usage in exact solving mode
    5870 */
    5871static
    5873 SCIP* scip, /**< SCIP data structure */
    5874 SCIP_Real*RESTRICT cutcoefs, /**< array of coefficients of cut */
    5875 SCIP_Real*RESTRICT cutrhs, /**< pointer to right hand side of cut */
    5876 int*RESTRICT cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    5877 int*RESTRICT nnz, /**< number of non-zeros in cut */
    5878 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
    5879 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
    5880 SCIP_INTERVAL f0 /**< fractional value of rhs */
    5881 )
    5882{
    5883 SCIP_INTERVAL onedivoneminusf0;
    5884 int i;
    5885 int firstcontvar;
    5886 SCIP_VAR** vars;
    5887 int ndelcontvars;
    5888 SCIP_ROUNDMODE previousroundmode;
    5889 SCIP_MIRINFO* mirinfo = NULL;
    5890 SCIP_INTERVAL tmpinterval;
    5891
    5892 assert(cutrhs != NULL);
    5893 assert(cutcoefs != NULL);
    5894 assert(cutinds != NULL);
    5895 assert(nnz != NULL);
    5896 assert(boundtype != NULL);
    5897 assert(varsign != NULL);
    5898 assert(0.0 < SCIPintervalGetInf(f0) && SCIPintervalGetSup(f0) < 1.0);
    5899 assert(SCIPisExact(scip));
    5900
    5901 /* round up at first, since we are dividing and divisor should be as large as possible,
    5902 * then switch to down since we are working on lhs */
    5903 /* 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 */
    5904 if( SCIPisCertified(scip) )
    5906
    5907 previousroundmode = SCIPintervalGetRoundingMode();
    5908 tmpinterval = f0;
    5910 SCIPintervalAddScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, 1.0);
    5911 SCIPintervalSet(&onedivoneminusf0, 1.0);
    5912 SCIPintervalDiv(SCIPinfinity(scip), &onedivoneminusf0, onedivoneminusf0, tmpinterval);
    5914
    5915 /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
    5916 * without destroying the ordering of the aggrrow's non-zeros.
    5917 * (due to sorting in cutsTransformMIR the ordering is continuous before integral)
    5918 */
    5919
    5920 firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    5921 vars = SCIPgetVars(scip);
    5922#ifndef NDEBUG
    5923 /*in debug mode check that all continuous variables of the aggrrow come before the integral variables */
    5924 i = 0;
    5925 while( i < *nnz && cutinds[i] >= firstcontvar )
    5926 ++i;
    5927
    5928 while( i < *nnz )
    5929 {
    5930 assert(cutinds[i] < firstcontvar);
    5931 ++i;
    5932 }
    5933#endif
    5934
    5935 /* round down everything on lhs (excepts for the denominator part above) */
    5937
    5938 for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
    5939 {
    5940 SCIP_VAR* var;
    5941 SCIP_INTERVAL cutaj;
    5942
    5943 int v;
    5944
    5945 v = cutinds[i];
    5946 assert(0 <= v && v < SCIPgetNVars(scip));
    5947
    5948 var = vars[v];
    5949 assert(var != NULL);
    5950 assert(SCIPvarGetProbindex(var) == v);
    5951 assert(varsign[i] == +1 || varsign[i] == -1);
    5952
    5953 /* work on lhs -> round down */
    5955
    5956 /* calculate the coefficient in the retransformed cut */
    5957 {
    5958 SCIP_Real aj;
    5959 SCIP_Real downaj;
    5960 SCIP_Real fj;
    5961
    5962 aj = cutcoefs[v] * varsign[i];
    5963
    5964 downaj = floor(aj);
    5965 fj = aj - downaj;
    5966 assert(fj >= -SCIPepsilon(scip) && fj <= 1.0);
    5967
    5968 if( SCIPisLE(scip, fj, SCIPintervalGetInf(f0)) )
    5969 {
    5970 SCIPintervalSet(&cutaj, downaj);
    5971
    5972 if( SCIPisCertified(scip) && mirinfo != NULL )
    5973 {
    5974 SCIP_RATIONAL* boundval;
    5975
    5976 mirinfo->splitcoefficients[v] = SCIPintervalGetInf(cutaj); /*lint !e644*/
    5977 assert(!SCIPisInfinity(scip, fabs(cutaj.inf)));
    5978 if( mirinfo->upperused[v] )
    5979 {
    5980 mirinfo->splitcoefficients[v] *= -1;
    5981 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
    5982 }
    5983 else
    5984 {
    5985 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
    5986 }
    5987 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
    5988 }
    5989 }
    5990 else
    5991 {
    5992 SCIPintervalSet(&tmpinterval, aj);
    5993 SCIPintervalSubScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, downaj);
    5994 SCIPintervalSub(SCIPinfinity(scip), &tmpinterval, tmpinterval, f0);
    5995 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, onedivoneminusf0);
    5996 SCIPintervalAddScalar(SCIPinfinity(scip), &cutaj, tmpinterval, downaj);
    5997
    5998 if( SCIPisCertified(scip) && mirinfo != NULL )
    5999 {
    6000 SCIP_RATIONAL* boundval;
    6001 mirinfo->splitcoefficients[v] = downaj;
    6002 mirinfo->splitcoefficients[v] += 1.0;
    6003 if( mirinfo->upperused[v] )
    6004 {
    6005 mirinfo->splitcoefficients[v] *= -1;
    6006 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
    6007 }
    6008 else
    6009 {
    6010 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
    6011 }
    6012 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
    6013 }
    6014 }
    6015
    6016 SCIPintervalMulScalar(SCIPinfinity(scip), &cutaj, cutaj, (double) varsign[i]);
    6017 }
    6018
    6019 /* integral var uses standard bound */
    6020 assert(boundtype[i] < 0);
    6021
    6022 if( cutaj.inf != 0.0 || cutaj.sup != 0 )
    6023 {
    6024 /* we have to use the inf of the cutaj-interval both times! */
    6026
    6027 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    6028 if( varsign[i] == +1 )
    6029 {
    6030 /* lower bound was used */
    6031 if( boundtype[i] == -1 )
    6032 {
    6034 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    6036 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6037 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6038 }
    6039 else
    6040 {
    6041 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    6043 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6044 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6045 }
    6046 }
    6047 else
    6048 {
    6049 /* upper bound was used */
    6050 if( boundtype[i] == -1 )
    6051 {
    6053 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    6055 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6056 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6057 }
    6058 else
    6059 {
    6060 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    6062 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6063 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6064 }
    6065 }
    6066 }
    6067
    6068 /* remove zero cut coefficients from cut, only remove exactly 0 in exact solving mode
    6069 * we can only do this here, since the sup might be positive and impact the rhs of the cut */
    6070 if( cutaj.inf == 0.0 )
    6071 {
    6072 cutcoefs[v] = 0.0;
    6073 --*nnz;
    6074 cutinds[i] = cutinds[*nnz];
    6075 continue;
    6076 }
    6077
    6078 cutcoefs[v] = SCIPintervalGetInf(cutaj);
    6079 }
    6080
    6081 /* adapt lhs -> round down */
    6083
    6084 /* now process the continuous variables; postpone deletetion of zeros till all continuous variables have been processed */
    6085 ndelcontvars = 0;
    6086 while( i >= ndelcontvars )
    6087 {
    6088 SCIP_VAR* var;
    6089 SCIP_INTERVAL cutaj;
    6090 SCIP_Real aj;
    6091 int v;
    6092
    6093 v = cutinds[i];
    6094 assert(0 <= v && v < SCIPgetNVars(scip));
    6095
    6096 var = vars[v];
    6097 assert(var != NULL);
    6098 assert(SCIPvarGetProbindex(var) == v);
    6099 assert(varsign[i] == +1 || varsign[i] == -1);
    6100 assert( v >= firstcontvar );
    6101
    6102 /* adapt lhs -> round down */
    6104
    6105 /* calculate the coefficient in the retransformed cut */
    6106 aj = cutcoefs[v];
    6107
    6108 if( aj * varsign[i] >= 0.0 )
    6109 SCIPintervalSet(&cutaj, 0.0);
    6110 else
    6111 {
    6112 SCIPintervalMulScalar(SCIPinfinity(scip), &cutaj, onedivoneminusf0, aj); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
    6113 }
    6114
    6115 /* remove zero cut coefficients from cut; move a continuous var from the beginning
    6116 * to the current position, so that all integral variables stay behind the continuous
    6117 * variables
    6118 */
    6119 if( EPSZ(SCIPintervalGetInf(cutaj), QUAD_EPSILON) && (SCIPintervalGetInf(cutaj) >= 0.0) )
    6120 {
    6121 SCIPintervalSet(&cutaj, 0.0);
    6122 cutcoefs[v] = 0.0;
    6123 cutinds[i] = cutinds[ndelcontvars];
    6124 varsign[i] = varsign[ndelcontvars];
    6125 boundtype[i] = boundtype[ndelcontvars];
    6126 ++ndelcontvars;
    6127 continue;
    6128 }
    6129
    6130 cutcoefs[v] = SCIPintervalGetInf(cutaj);
    6131
    6133
    6134 /* check for variable bound use */
    6135 if( boundtype[i] < 0 )
    6136 {
    6137 /* standard bound */
    6138
    6139 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    6140 if( varsign[i] == +1 )
    6141 {
    6142 /* lower bound was used */
    6143 if( boundtype[i] == -1 )
    6144 {
    6145 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    6147 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6148 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6149 }
    6150 else
    6151 {
    6152 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    6154 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6155 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6156 }
    6157 }
    6158 else
    6159 {
    6160 /* upper bound was used */
    6161 if( boundtype[i] == -1 )
    6162 {
    6163 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    6165 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6166 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6167 }
    6168 else
    6169 {
    6170 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    6172 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, tmpinterval, cutaj);
    6173 *cutrhs += SCIPintervalGetSup(tmpinterval);
    6174 }
    6175 }
    6176 }
    6177 else
    6178 {
    6179 SCIPerrorMessage("varbounds not yet implemented in exact SCIP \n");
    6180 return SCIP_ERROR;
    6181 }
    6182
    6183 /* advance to next variable */
    6184 --i;
    6185 }
    6186
    6187 /* fill the empty position due to deleted continuous variables */
    6188 if( ndelcontvars > 0 )
    6189 {
    6190 assert(ndelcontvars <= *nnz);
    6191 *nnz -= ndelcontvars;
    6192 if( *nnz < ndelcontvars )
    6193 {
    6194 BMScopyMemoryArray(cutinds, cutinds + ndelcontvars, *nnz);
    6195 }
    6196 else
    6197 {
    6198 BMScopyMemoryArray(cutinds, cutinds + *nnz, ndelcontvars);
    6199 }
    6200 }
    6201
    6202 /* reset rounding mode, also set the rhs->data in the mirinfo */
    6203 SCIPintervalSetRoundingMode(previousroundmode);
    6204
    6205 return SCIP_OKAY;
    6206}
    6207
    6208#ifdef SCIP_DISABLED_CODE
    6209/** 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$
    6210 * \f[
    6211 * \begin{array}{rll}
    6212 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
    6213 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
    6214 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
    6215 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
    6216 * \end{array}
    6217 * \f]
    6218 *
    6219 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
    6220 *
    6221 * (lb or ub):
    6222 * \f[
    6223 * \begin{array}{lllll}
    6224 * 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} \\
    6225 * 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}
    6226 * \end{array}
    6227 * \f]
    6228 * and move the constant terms
    6229 * \f[
    6230 * \begin{array}{cl}
    6231 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
    6232 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
    6233 * \end{array}
    6234 * \f]
    6235 * to the rhs.
    6236 *
    6237 * (vlb or vub):
    6238 * \f[
    6239 * \begin{array}{lllll}
    6240 * 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)} \\
    6241 * 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)}
    6242 * \end{array}
    6243 * \f]
    6244 * move the constant terms
    6245 * \f[
    6246 * \begin{array}{cl}
    6247 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
    6248 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
    6249 * \end{array}
    6250 * \f]
    6251 * to the rhs, and update the VB variable coefficients:
    6252 * \f[
    6253 * \begin{array}{ll}
    6254 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
    6255 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
    6256 * \end{array}
    6257 * \f]
    6258 *
    6259 * @note this method is safe for usage in exact solving mode
    6260 */
    6261static
    6262SCIP_RETCODE cutsRoundMIRRational(
    6263 SCIP* scip, /**< SCIP data structure */
    6264 SCIP_Real*RESTRICT cutcoefs, /**< array of coefficients of cut */
    6265 QUAD(SCIP_Real*RESTRICT cutrhs), /**< pointer to right hand side of cut */
    6266 int*RESTRICT cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    6267 int*RESTRICT nnz, /**< number of non-zeros in cut */
    6268 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
    6269 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
    6270 SCIP_RATIONAL* f0 /**< fractional value of rhs */
    6271 )
    6272{
    6273 SCIP_RATIONAL* tmp;
    6274 SCIP_RATIONAL* onedivoneminusf0;
    6275 int i;
    6276 int firstcontvar;
    6277 SCIP_VAR** vars;
    6278 int ndelcontvars;
    6279 SCIP_ROUNDMODE previousroundmode;
    6280 SCIP_MIRINFO* mirinfo;
    6281
    6282 assert(QUAD_HI(cutrhs) != NULL);
    6283 assert(cutcoefs != NULL);
    6284 assert(cutinds != NULL);
    6285 assert(nnz != NULL);
    6286 assert(boundtype != NULL);
    6287 assert(varsign != NULL);
    6288 assert(SCIPrationalIsPositive(f0) && SCIPrationalIsLTReal(f0, 1.0));
    6289 assert(SCIPisExact(scip));
    6290
    6291 SCIP_CALL( SCIPrationalCreateBuffer(SCIPbuffer(scip), &onedivoneminusf0) );
    6293
    6294 /* round up at first, since we are dividing and divisor should be as large as possible,
    6295 * then switch to down since we are working on lhs */
    6296 /* 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 */
    6297 if( SCIPisCertified(scip) )
    6299
    6300 previousroundmode = SCIPintervalGetRoundingMode();
    6301 SCIPrationalSetReal(tmp, 1.0);
    6302 SCIPrationalDiff(tmp, tmp, f0);
    6303 SCIPrationalSetReal(onedivoneminusf0, 1.0);
    6304 SCIPrationalDiv(onedivoneminusf0, onedivoneminusf0, tmp);
    6305
    6306 /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
    6307 * without destroying the ordering of the aggrrow's non-zeros.
    6308 * (due to sorting in cutsTransformMIR the ordering is continuous before integral)
    6309 */
    6310
    6311 firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    6312 vars = SCIPgetVars(scip);
    6313#ifndef NDEBUG
    6314 /*in debug mode check that all continuous variables of the aggrrow come before the integral variables */
    6315 i = 0;
    6316 while( i < *nnz && cutinds[i] >= firstcontvar )
    6317 ++i;
    6318
    6319 while( i < *nnz )
    6320 {
    6321 assert(cutinds[i] < firstcontvar);
    6322 ++i;
    6323 }
    6324#endif
    6325
    6326 for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
    6327 {
    6328 SCIP_VAR* var;
    6329 SCIP_RATIONAL* cutaj;
    6330 SCIP_Real QUAD(cutajquad);
    6331 int v;
    6332
    6333 v = cutinds[i];
    6334 assert(0 <= v && v < SCIPgetNVars(scip));
    6335
    6337
    6338 var = vars[v];
    6339 assert(var != NULL);
    6340 assert(SCIPvarGetProbindex(var) == v);
    6341 assert(varsign[i] == +1 || varsign[i] == -1);
    6342
    6343 /* calculate the coefficient in the retransformed cut */
    6344 {
    6345 SCIP_Real QUAD(aj);
    6346 SCIP_Real downaj;
    6347 SCIP_RATIONAL* fj;
    6348
    6350
    6351 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
    6352 QUAD_SCALE(aj, varsign[i]);
    6353 SCIPrationalSetReal(tmp, aj);
    6354
    6355 downaj = floor(QUAD_TO_DBL(aj));
    6356 SCIPrationalDiffReal(fj, tmp, downaj);
    6357
    6358 if( SCIPrationalIsLE(fj, f0) )
    6359 {
    6360 SCIPrationalSetReal(cutaj, downaj);
    6361
    6362 if( SCIPisCertified(scip) )
    6363 {
    6364 SCIP_RATIONAL* boundval;
    6365
    6366 mirinfo->splitcoefficients[v] = downaj;
    6367 if( mirinfo->upperused[v] )
    6368 {
    6369 mirinfo->splitcoefficients[v] *= -1;
    6370 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
    6371 }
    6372 else
    6373 {
    6374 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
    6375 }
    6376 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
    6377 }
    6378 }
    6379 else
    6380 {
    6382 SCIPrationalDiffReal(tmp, tmp, downaj);
    6383 SCIPrationalDiff(tmp, tmp, f0);
    6384 SCIPrationalMult(tmp, tmp, onedivoneminusf0);
    6385 SCIPrationalAddReal(cutaj, tmp, downaj);
    6386
    6387 if( SCIPisCertified(scip) )
    6388 {
    6389 SCIP_RATIONAL* boundval;
    6390
    6391 mirinfo->splitcoefficients[v] = QUAD_TO_DBL(downaj);
    6392 mirinfo->splitcoefficients[v] += 1.0;
    6393 if( mirinfo->upperused[v] )
    6394 {
    6395 mirinfo->splitcoefficients[v] *= -1;
    6396 boundval = mirinfo->localbdused[v] ? SCIPvarGetUbLocalExact(var) : SCIPvarGetUbGlobalExact(var);
    6397 }
    6398 else
    6399 {
    6400 boundval = mirinfo->localbdused[v] ? SCIPvarGetLbLocalExact(var) : SCIPvarGetLbGlobalExact(var);
    6401 }
    6402 SCIPrationalAddProdReal(mirinfo->rhs, boundval, mirinfo->splitcoefficients[v]);
    6403 }
    6404 }
    6405
    6406 SCIPrationalMultReal(cutaj, cutaj, varsign[i]);
    6407
    6409 }
    6410
    6411 /* remove zero cut coefficients from cut, only remove positive coefficients in exact solving mode */
    6412 if( SCIPrationalIsZero(cutaj) )
    6413 {
    6414 QUAD_ASSIGN(cutajquad, 0.0);
    6415 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
    6416 --*nnz;
    6417 cutinds[i] = cutinds[*nnz];
    6419 continue;
    6420 }
    6421
    6423
    6424 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
    6425
    6426 /* integral var uses standard bound */
    6427 assert(boundtype[i] < 0);
    6428
    6430
    6431 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    6432 if( varsign[i] == +1 )
    6433 {
    6434 /* lower bound was used */
    6435 if( boundtype[i] == -1 )
    6436 {
    6438 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    6439 SCIPrationalMult(tmp, cutaj, SCIPvarGetLbGlobalExact(var));
    6440 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetLbGlobal(var) */
    6441 }
    6442 else
    6443 {
    6444 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    6445 SCIPrationalMult(tmp, cutaj, SCIPvarGetLbLocalExact(var));
    6446 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetLbLocal(var) */
    6447 }
    6448 }
    6449 else
    6450 {
    6451 /* upper bound was used */
    6452 if( boundtype[i] == -1 )
    6453 {
    6455 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    6456 SCIPrationalMult(tmp, cutaj, SCIPvarGetUbGlobalExact(var));
    6457 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetUbGlobal(var) */
    6458 }
    6459 else
    6460 {
    6461 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    6462 SCIPrationalMult(tmp, cutaj, SCIPvarGetUbLocalExact(var));
    6463 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmp, SCIP_R_ROUND_UPWARDS)); /* rhs += cutaj * SCIPvarGetUbLocal(var) */
    6464 }
    6465 }
    6467 }
    6468
    6469 /* now process the continuous variables; postpone deletetion of zeros till all continuous variables have been processed */
    6470 ndelcontvars = 0;
    6471 while( i >= ndelcontvars )
    6472 {
    6473 SCIP_VAR* var;
    6474 SCIP_RATIONAL* cutaj;
    6475 SCIP_RATIONAL* tmprational;
    6476 SCIP_Real QUAD(cutajquad);
    6477 SCIP_Real QUAD(aj);
    6478 int v;
    6479
    6480 /* adapt lhs -> round down */
    6482
    6485
    6486 v = cutinds[i];
    6487 assert(0 <= v && v < SCIPgetNVars(scip));
    6488
    6489 var = vars[v];
    6490 assert(var != NULL);
    6491 assert(SCIPvarGetProbindex(var) == v);
    6492 assert(varsign[i] == +1 || varsign[i] == -1);
    6493 assert( v >= firstcontvar );
    6494
    6495 /* calculate the coefficient in the retransformed cut */
    6496 QUAD_ARRAY_LOAD(aj, cutcoefs, v);
    6497
    6498 if( QUAD_TO_DBL(aj) * varsign[i] >= 0.0 )
    6499 SCIPrationalSetReal(cutaj, 0.0);
    6500 else
    6501 {
    6502 SCIPrationalSetRational(cutaj, onedivoneminusf0);
    6503 SCIPrationalMultReal(cutaj, cutaj, QUAD_TO_DBL(aj)); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
    6504 }
    6505
    6506 /* remove zero cut coefficients from cut; move a continuous var from the beginning
    6507 * to the current position, so that all integral variables stay behind the continuous
    6508 * variables
    6509 */
    6510 if( EPSZ(SCIPrationalGetReal(cutaj), QUAD_EPSILON) && SCIPrationalIsGEReal(cutaj, 0.0) )
    6511 {
    6512 assert(SCIPrationalIsZero(cutaj));
    6513 SCIPrationalSetReal(cutaj, 0.0);
    6514 QUAD_ASSIGN_Q(cutajquad, 0.0);
    6515 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
    6516 cutinds[i] = cutinds[ndelcontvars];
    6517 varsign[i] = varsign[ndelcontvars];
    6518 boundtype[i] = boundtype[ndelcontvars];
    6519 ++ndelcontvars;
    6520
    6521 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
    6523
    6524 continue;
    6525 }
    6526
    6528 QUAD_ARRAY_STORE(cutcoefs, v, cutajquad);
    6529
    6531
    6532 /* check for variable bound use */
    6533 if( boundtype[i] < 0 )
    6534 {
    6535 /* standard bound */
    6536
    6537 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    6538 if( varsign[i] == +1 )
    6539 {
    6540 /* lower bound was used */
    6541 if( boundtype[i] == -1 )
    6542 {
    6544 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    6545 SCIPrationalMult(tmprational, cutaj, SCIPvarGetLbGlobalExact(var));
    6546 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
    6547 }
    6548 else
    6549 {
    6550 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    6551 SCIPrationalMult(tmprational, cutaj, SCIPvarGetLbLocalExact(var));
    6552 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
    6553 }
    6554 }
    6555 else
    6556 {
    6557 /* upper bound was used */
    6558 if( boundtype[i] == -1 )
    6559 {
    6561 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    6562 SCIPrationalMult(tmprational, cutaj, SCIPvarGetUbGlobalExact(var));
    6563 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
    6564 }
    6565 else
    6566 {
    6567 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    6568 SCIPrationalMult(tmprational, cutaj, SCIPvarGetUbLocalExact(var));
    6569 SCIPquadprecSumQD(*cutrhs, *cutrhs, SCIPrationalRoundReal(tmprational, SCIP_R_ROUND_UPWARDS));
    6570 }
    6571 }
    6572
    6573 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
    6575 }
    6576 else
    6577 {
    6578#ifdef SCIP_DISABLED_CODE
    6579 SCIP_VAR** vbz;
    6580 SCIP_Real* vbb;
    6581 SCIP_Real* vbd;
    6582 SCIP_Real QUAD(zcoef);
    6583 int vbidx;
    6584 int zidx;
    6585
    6586 assert(!SCIPisExact(scip));
    6587
    6588 /* variable bound */
    6589 vbidx = boundtype[i];
    6590
    6591 /* change mirrhs and cutaj of integer variable z_j of variable bound */
    6592 if( varsign[i] == +1 )
    6593 {
    6594 /* variable lower bound was used */
    6595 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
    6596 vbz = SCIPvarGetVlbVars(var);
    6597 vbb = SCIPvarGetVlbCoefs(var);
    6598 vbd = SCIPvarGetVlbConstants(var);
    6599 }
    6600 else
    6601 {
    6602 /* variable upper bound was used */
    6603 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
    6604 vbz = SCIPvarGetVubVars(var);
    6605 vbb = SCIPvarGetVubCoefs(var);
    6606 vbd = SCIPvarGetVubConstants(var);
    6607 }
    6608 assert(SCIPvarIsActive(vbz[vbidx]));
    6609 zidx = SCIPvarGetProbindex(vbz[vbidx]);
    6610 assert(0 <= zidx && zidx < firstcontvar);
    6611
    6612 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
    6613 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
    6614
    6615 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
    6616 QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
    6617
    6618 /* update sparsity pattern */
    6619 if( QUAD_HI(zcoef) == 0.0 )
    6620 cutinds[(*nnz)++] = zidx;
    6621
    6622 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
    6623 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
    6624 QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
    6625 assert(QUAD_HI(zcoef) != 0.0);
    6626#endif
    6627 }
    6628
    6629 /* advance to next variable */
    6630 --i;
    6631 }
    6632
    6633 /* fill the empty position due to deleted continuous variables */
    6634 if( ndelcontvars > 0 )
    6635 {
    6636 assert(ndelcontvars <= *nnz);
    6637 *nnz -= ndelcontvars;
    6638 if( *nnz < ndelcontvars )
    6639 {
    6640 BMScopyMemoryArray(cutinds, cutinds + ndelcontvars, *nnz);
    6641 }
    6642 else
    6643 {
    6644 BMScopyMemoryArray(cutinds, cutinds + *nnz, ndelcontvars);
    6645 }
    6646 }
    6647
    6648 /* reset rounding mode, also set the rhs->data in the mirinfo */
    6649 SCIPintervalSetRoundingMode(previousroundmode);
    6650
    6652 SCIPrationalFreeBuffer(SCIPbuffer(scip), &onedivoneminusf0);
    6653
    6654 return SCIP_OKAY;
    6655}
    6656#endif
    6657
    6658
    6659/** 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$
    6660 * \f[
    6661 * \begin{array}{rll}
    6662 * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
    6663 * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
    6664 * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
    6665 * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
    6666 * \end{array}
    6667 * \f]
    6668 *
    6669 * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
    6670 *
    6671 * (lb or ub):
    6672 * \f[
    6673 * \begin{array}{lllll}
    6674 * 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} \\
    6675 * 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}
    6676 * \end{array}
    6677 * \f]
    6678 * and move the constant terms
    6679 * \f[
    6680 * \begin{array}{cl}
    6681 * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
    6682 * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
    6683 * \end{array}
    6684 * \f]
    6685 * to the rhs.
    6686 *
    6687 * (vlb or vub):
    6688 * \f[
    6689 * \begin{array}{lllll}
    6690 * 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)} \\
    6691 * 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)}
    6692 * \end{array}
    6693 * \f]
    6694 * move the constant terms
    6695 * \f[
    6696 * \begin{array}{cl}
    6697 * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
    6698 * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
    6699 * \end{array}
    6700 * \f]
    6701 * to the rhs, and update the VB variable coefficients:
    6702 * \f[
    6703 * \begin{array}{ll}
    6704 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
    6705 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
    6706 * \end{array}
    6707 * \f]
    6708 */
    6709static
    6711 SCIP* scip, /**< SCIP data structure */
    6712 MIR_DATA* data, /**< the MIR data structure for this cut */
    6713 int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
    6714 int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
    6715 QUAD(SCIP_Real f0) /**< fractional value of rhs */
    6716 )
    6717{
    6718 SCIP_Real QUAD(tmp);
    6719 SCIP_Real QUAD(onedivoneminusf0);
    6720 int s;
    6721 int cutindex;
    6722 int i;
    6723
    6724 assert(data != NULL);
    6725 assert(boundtype != NULL);
    6726 assert(varsign != NULL);
    6727 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
    6728
    6729 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
    6730 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
    6731
    6732 /* Loop backwards through the sections, so that the reversing of varbound substitutions does not prematurely effect
    6733 * the coefficients of variables in other sections, because the section index of a variable bound must always be
    6734 * higher than that of the bounded variable. */
    6735 cutindex = data->ncutinds - 1;
    6736 for( s = NSECTIONS - 1; s >= 0; --s )
    6737 {
    6738 int* indices = data->secindices[s];
    6739 int nnz = data->secnnz[s];
    6740
    6741 SCIP_Bool enfintegral = data->isenfint[s];
    6742 SCIP_Bool implintegral = data->isimplint[s];
    6743
    6744 /* iterate backwards over indices in section, so we can easily shrink the section if we find zeros */
    6745 for( i = nnz - 1; i >= 0 ; --i )
    6746 {
    6747 int v;
    6748 int sign;
    6749 int type;
    6750 SCIP_Real QUAD(cutaj);
    6751 SCIP_Real QUAD(aj);
    6752 SCIP_VAR* var;
    6753
    6754 v = indices[i];
    6755 assert(0 <= v && v < data->nvars);
    6756 assert(data->cutinds[cutindex] == v);
    6757
    6758 sign = varsign[cutindex];
    6759 assert(sign == +1 || sign == -1);
    6760 type = boundtype[cutindex];
    6761
    6762 --cutindex;
    6763
    6764 var = data->vars[v];
    6765 assert(var != NULL);
    6766 assert(SCIPvarGetProbindex(var) == v );
    6767
    6768 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
    6769
    6770 if( enfintegral || implintegral )
    6771 {
    6772 /* variable is integral */
    6773 SCIP_Real QUAD(downaj);
    6774 SCIP_Real QUAD(fj);
    6775
    6776 QUAD_SCALE(aj, sign);
    6777
    6778 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
    6779 SCIPquadprecSumQQ(fj, aj, -downaj);
    6780 assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
    6781
    6782 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
    6783 {
    6784 QUAD_ASSIGN_Q(cutaj, downaj); /* a^_j */
    6785 }
    6786 else
    6787 {
    6788 SCIPquadprecSumQQ(tmp, fj, -f0);
    6789 SCIPquadprecProdQQ(tmp, tmp, onedivoneminusf0);
    6790 SCIPquadprecSumQQ(cutaj, tmp, downaj);
    6791 }
    6792 QUAD_SCALE(cutaj, sign);
    6793 }
    6794 else
    6795 {
    6796 /* variable is continuous */
    6798
    6799 if( QUAD_TO_DBL(aj) * sign >= 0.0 )
    6800 QUAD_ASSIGN(cutaj, 0.0);
    6801 else
    6802 SCIPquadprecProdQQ(cutaj, onedivoneminusf0, aj); /* cutaj = aj * onedivoneminusf0 */
    6803 }
    6804
    6805 /* remove coefficient from cut if it becomes zero */
    6806 if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
    6807 {
    6808 QUAD_ASSIGN(cutaj, 0.0);
    6809 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
    6810 --data->totalnnz;
    6811 --data->secnnz[s];
    6812 indices[i] = indices[data->secnnz[s]];
    6813 continue;
    6814 }
    6815
    6816 /* store the updated coefficient */
    6817 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
    6818
    6819 /* undo bound transformations */
    6820 if( type < 0 )
    6821 {
    6822 /* standard bound */
    6823 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    6824 if( sign == +1 )
    6825 {
    6826 /* lower bound was used */
    6827 if( type == -1 )
    6828 {
    6829 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    6830 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
    6831 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    6832 }
    6833 else
    6834 {
    6835 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    6836 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
    6837 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    6838 }
    6839 }
    6840 else
    6841 {
    6842 /* upper bound was used */
    6843 if( type == -1 )
    6844 {
    6845 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    6846 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
    6847 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    6848 }
    6849 else
    6850 {
    6851 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    6852 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
    6853 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    6854 }
    6855 }
    6856 }
    6857 else
    6858 {
    6859 /* variable bound */
    6860 SCIP_VAR** vbz;
    6861 SCIP_Real* vbb;
    6862 SCIP_Real* vbd;
    6863 SCIP_Real QUAD(zcoef);
    6864 int vbidx;
    6865 int zidx;
    6866
    6867 /* variable bound */
    6868 vbidx = type;
    6869
    6870 /* change mirrhs and cutaj of integer variable z_j of variable bound */
    6871 if( sign == +1 )
    6872 {
    6873 /* variable lower bound was used */
    6874 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
    6875 vbz = SCIPvarGetVlbVars(var);
    6876 vbb = SCIPvarGetVlbCoefs(var);
    6877 vbd = SCIPvarGetVlbConstants(var);
    6878 }
    6879 else
    6880 {
    6881 /* variable upper bound was used */
    6882 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
    6883 vbz = SCIPvarGetVubVars(var);
    6884 vbb = SCIPvarGetVubCoefs(var);
    6885 vbd = SCIPvarGetVubConstants(var);
    6886 }
    6887 assert(SCIPvarIsActive(vbz[vbidx]));
    6888 zidx = SCIPvarGetProbindex(vbz[vbidx]);
    6889 assert(varSection(data, zidx) > s);
    6890
    6891 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
    6892 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    6893
    6894 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
    6895 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
    6896
    6897 /* update sparsity pattern */
    6898 if( QUAD_HI(zcoef) == 0.0 )
    6899 {
    6900 int zsection = varSection(data, zidx);
    6901 data->secindices[zsection][data->secnnz[zsection]] = zidx;
    6902 ++data->secnnz[zsection];
    6903 ++data->totalnnz;
    6904 }
    6905
    6906 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
    6907 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
    6908 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
    6909 assert(QUAD_HI(zcoef) != 0.0);
    6910 }
    6911 }
    6912 }
    6913
    6914 /* Finally, store the relevant data in cutinds which is the array used by the other functions */
    6915 data->ncutinds = 0;
    6916 for( s = 0; s < NSECTIONS; ++s )
    6917 {
    6918 int* indices = data->secindices[s];
    6919 int nnz = data->secnnz[s];
    6920 for( i = 0; i < nnz; ++i )
    6921 {
    6922 data->cutinds[data->ncutinds] = indices[i];
    6923 ++data->ncutinds;
    6924 }
    6925 }
    6926 return SCIP_OKAY;
    6927}
    6928
    6929/** substitute aggregated slack variables:
    6930 *
    6931 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    6932 * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r]. \f$
    6933 *
    6934 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    6935 * \f[
    6936 * \begin{array}{rll}
    6937 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r \leq f_0 \\
    6938 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f_0)/(1 - f_0),& \mbox{if}\qquad f_r > f_0 \\
    6939 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r \geq 0 \\
    6940 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f_0), & \mbox{if}\qquad a^\prime_r < 0
    6941 * \end{array}
    6942 * \f]
    6943 *
    6944 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
    6945 *
    6946 * @note this method is safe for usage in exact solving mode
    6947 *
    6948 * @todo certify and use integrality of row in exact solving mode
    6949 *
    6950 * @todo make behavior identical to the unsafe MIR cut computation
    6951 */
    6952static
    6954 SCIP* scip, /**< SCIP data structure */
    6955 SCIP_Real* weights, /**< row weights in row summation */
    6956 int* slacksign, /**< stores the sign of the row's slack variable in summation */
    6957 int* rowinds, /**< sparsity pattern of used rows */
    6958 int nrowinds, /**< number of used rows */
    6959 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
    6960 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    6961 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
    6962 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    6963 int* nnz, /**< number of non-zeros in cut */
    6964 SCIP_INTERVAL f0 /**< fractional value of rhs */
    6965 )
    6966{ /*lint --e{715}*/
    6967 SCIP_ROW** rows;
    6968 SCIP_ROW* userow;
    6969 SCIP_ROWEXACT* rowexact;
    6970 SCIP_INTERVAL onedivoneminusf0, tmpinterval;
    6971 SCIP_ROUNDMODE previousroundmode;
    6972 SCIP_AGGREGATIONINFO* aggrinfo = NULL;
    6973 SCIP_MIRINFO* mirinfo = NULL;
    6974 SCIP_Real mult;
    6975 SCIP_Real splitcoef;
    6976 SCIP_Real slackweight;
    6977 SCIP_Bool slackroundeddown;
    6978 int i;
    6979 int currentnegslackrow;
    6980
    6981 assert(scip != NULL);
    6982 assert(weights != NULL || nrowinds == 0);
    6983 assert(slacksign != NULL || nrowinds == 0);
    6984 assert(rowinds != NULL || nrowinds == 0);
    6985 assert(scale > 0.0);
    6986 assert(cutcoefs != NULL);
    6987 assert(cutrhs != NULL);
    6988 assert(cutinds != NULL);
    6989 assert(nnz != NULL);
    6990 assert(0.0 < SCIPintervalGetInf(f0) && SCIPintervalGetSup(f0) < 1.0);
    6991
    6992 assert(SCIPisExact(scip));
    6993
    6994 /* compute 1/(1-f0) in interval arithmetic */
    6995 previousroundmode = SCIPintervalGetRoundingMode();
    6997 SCIPintervalAddScalar(SCIPinfinity(scip), &tmpinterval, tmpinterval, 1.0);
    6998 SCIPintervalSet(&onedivoneminusf0, 1.0);
    6999 SCIPintervalDiv(SCIPinfinity(scip), &onedivoneminusf0, onedivoneminusf0, tmpinterval);
    7000
    7001 if( SCIPisCertified(scip) )
    7002 {
    7005 }
    7006
    7007 rows = SCIPgetLPRows(scip);
    7008 currentnegslackrow = 0;
    7009 for( i = 0; i < nrowinds; i++ )
    7010 {
    7011 SCIP_ROW* row;
    7012 SCIP_INTERVAL ar;
    7013 SCIP_INTERVAL cutar;
    7014 int r;
    7015 SCIP_Bool integralslack = FALSE;
    7016
    7017 r = rowinds[i]; /*lint !e613*/
    7018 assert(0 <= r && r < SCIPgetNLPRows(scip));
    7019 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
    7020 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
    7021
    7022 row = rows[r];
    7023 assert(row != NULL);
    7024 assert(row->len == 0 || row->cols != NULL);
    7025 assert(row->len == 0 || row->cols_index != NULL);
    7026 assert(row->len == 0 || row->vals != NULL);
    7027
    7028 if( slacksign[i] == 1 )
    7030 else
    7032
    7033 /* get the slack's coefficient a'_r = weights[i] * scale in the aggregated row */
    7034 SCIPintervalSet(&ar, weights[i]);
    7035 SCIPintervalMulScalar(SCIPinfinity(scip), &ar, ar, scale);
    7036 SCIPintervalMulScalar(SCIPinfinity(scip), &ar, ar, (double) slacksign[i]);
    7037
    7038 /* calculate slack variable's coefficient a^_r in the cut */
    7039 if( row->integral &&
    7040 ((slacksign[i] == +1 && SCIPrealIsExactlyIntegral(row->rhs) && SCIPrealIsExactlyIntegral(row->constant))
    7041 || (slacksign[i] == -1 && SCIPrealIsExactlyIntegral(row->lhs) && SCIPrealIsExactlyIntegral(row->constant))) ) /*lint !e613*/
    7042 {
    7043 /* slack variable is always integral:
    7044 * a^_r = a~_r = down(a'_r) , if f_r <= f0
    7045 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    7046 */
    7047 SCIP_Real downar;
    7048 SCIP_INTERVAL fr;
    7049
    7050 SCIPdebugMessage("resubstituting integer slack for row %s\n", row->name);
    7051 downar = floor(ar.inf);
    7052 SCIPintervalSubScalar(SCIPinfinity(scip), &fr, ar, downar);
    7053
    7054 integralslack = TRUE;
    7055
    7056 if( SCIPisLE(scip, fr.inf, f0.inf) )
    7057 {
    7058 SCIPintervalSet(&cutar, downar);
    7059 splitcoef = downar;
    7060 slackweight = weights[i];
    7061 slackroundeddown = TRUE;
    7062 SCIPintervalMul(SCIPinfinity(scip), &fr, fr, onedivoneminusf0);
    7063 SCIPdebugMessage("fractionality %g, f0 %g -> round down to %g\n", fr.inf, f0.inf, splitcoef);
    7064 }
    7065 else
    7066 {
    7067 SCIPintervalSetBounds(&cutar, ar.inf, ar.sup);
    7068 SCIPintervalSubScalar(SCIPinfinity(scip), &cutar, cutar, downar);
    7069 SCIPintervalSub(SCIPinfinity(scip), &cutar, cutar, f0);
    7070 SCIPintervalMul(SCIPinfinity(scip), &cutar, cutar, onedivoneminusf0);
    7071 SCIPintervalAddScalar(SCIPinfinity(scip), &cutar, cutar, downar);
    7072 splitcoef = downar + 1;
    7073 slackweight = weights[i];
    7074 slackroundeddown = FALSE;
    7075 SCIPdebugMessage("fractionality %g, f0 %g -> round up! splitcoef %g sub-coefficient %g", fr.inf, f0.inf, splitcoef, cutar.inf);
    7076 }
    7077 }
    7078 else
    7079 {
    7080 /* slack variable is continuous:
    7081 * a^_r = a~_r = 0 , if a'_r >= 0
    7082 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    7083 */
    7084 if( SCIPintervalGetInf(ar) >= 0.0 )
    7085 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
    7086 else
    7087 {
    7088 SCIPintervalMul(SCIPinfinity(scip), &cutar, onedivoneminusf0, ar); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
    7089 SCIPdebugMessage("resubstituting negative continuous slack for row %s with coef %g\n", row->name, cutar.inf);
    7090 }
    7091 }
    7092
    7093 rowexact = SCIProwGetRowExact(row);
    7094 assert(SCIProwExactHasFpRelax(rowexact));
    7095 if( SCIProwExactGetRowRhs(rowexact) != NULL && slacksign[i] == 1.0 )
    7096 userow = SCIProwExactGetRowRhs(rowexact);
    7097 else
    7098 userow = row;
    7099
    7100 SCIPintervalMulScalar(SCIPinfinity(scip), &cutar, cutar, (double) -slacksign[i]);
    7101
    7102 if( slacksign[i] == -1 )
    7103 mult = cutar.inf;
    7104 else
    7105 mult = cutar.sup;
    7106
    7107 if( SCIPisCertified(scip) && integralslack) /*lint --e{644}*/
    7108 {
    7109 assert(mirinfo != NULL);
    7110 /* save the value for the split disjunction for the integer slack and the continous part (for rounded up we
    7111 * subtract 1-f); multiply by -slacksign (same as above) since slack = side - row
    7112 */
    7113 mirinfo->slackrows[mirinfo->nslacks] = userow;
    7114 SCIP_CALL( SCIPcaptureRow(scip, userow) );
    7115 mirinfo->slackcoefficients[mirinfo->nslacks] = splitcoef * (-slacksign[i]);
    7116 mirinfo->slacksign[mirinfo->nslacks] = slacksign[i];
    7117 assert(SCIPrealIsExactlyIntegral(splitcoef));
    7118 mirinfo->slackweight[mirinfo->nslacks] = slackweight;
    7119 mirinfo->slackscale[mirinfo->nslacks] = scale;
    7120 mirinfo->slackusedcoef[mirinfo->nslacks] = mult;
    7121
    7122 /* save the value that goes into the certificate aggregation row (either downar or ar) */
    7123 mirinfo->slackroundeddown[mirinfo->nslacks] = slackroundeddown;
    7124 if( slackroundeddown )
    7125 mirinfo->nrounddownslacks++;
    7126 mirinfo->nslacks++;
    7127 }
    7128
    7129 /* if the coefficient was reduced to zero, ignore the slack variable */
    7130 if( EPSZ(SCIPintervalGetInf(cutar), QUAD_EPSILON) && (SCIPintervalGetInf(cutar) >= 0.0) )
    7131 continue;
    7132
    7133 /* depending on the slack's sign, we have
    7134 * - sign = 1: s = rhs - a^Tx >= 0
    7135 * - sign = -1: s = lhs - a^Tx <= 0
    7136 */
    7137 {
    7138 SCIP_Bool success = TRUE;
    7139 SCIP_Real sidevalchg;
    7140
    7141 if( SCIPisCertified(scip) && !integralslack )
    7142 {
    7143 assert(aggrinfo != NULL);
    7144 assert(aggrinfo->negslackweights[currentnegslackrow] == -weights[i]); /*lint !e777*/
    7145 aggrinfo->substfactor[currentnegslackrow] = mult;
    7146 currentnegslackrow++;
    7147 }
    7148
    7149 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, cutinds, cutcoefs, nnz, userow, mult, &sidevalchg, &success) );
    7150 assert(success);
    7151
    7152 /* move to rhs -> need to round up */
    7154 *cutrhs += sidevalchg;
    7155 }
    7156
    7157 /* move slack's constant to the right hand side */
    7158 if( slacksign[i] == +1 ) /*lint !e613*/
    7159 {
    7160 SCIP_INTERVAL rowrhs;
    7161
    7163 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
    7164 assert(!SCIPisInfinity(scip, userow->rhs));
    7165 SCIPintervalSet(&rowrhs, userow->rhs);
    7166 SCIPintervalSubScalar(SCIPinfinity(scip), &rowrhs, rowrhs, userow->constant);
    7167#ifdef SCIP_DISABLED_CODE
    7168 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
    7169 if( row->integral )
    7170 {
    7171 /* the right hand side was implicitly rounded down in row aggregation */
    7172 QUAD_ASSIGN(rowrhs, floor(QUAD_TO_DBL(rowrhs)));
    7173 }
    7174#endif
    7175 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, cutar, rowrhs);
    7176 *cutrhs += SCIPintervalGetSup(tmpinterval);
    7177 }
    7178 else
    7179 {
    7180 SCIP_INTERVAL rowlhs;
    7181
    7183 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
    7184 assert(!SCIPisInfinity(scip, -userow->lhs));
    7185 SCIPintervalSet(&rowlhs, userow->lhs);
    7186 SCIPintervalSubScalar(SCIPinfinity(scip), &rowlhs, rowlhs, userow->constant);
    7187#ifdef SCIP_DISABLED_CODE
    7188 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
    7189 if( row->integral )
    7190 {
    7191 /* the left hand side was implicitly rounded up in row aggregation */
    7192 QUAD_ASSIGN(rowlhs, floor(QUAD_TO_DBL(rowlhs)));
    7193 }
    7194#endif
    7195 SCIPintervalMul(SCIPinfinity(scip), &tmpinterval, cutar, rowlhs);
    7196 *cutrhs += SCIPintervalGetSup(tmpinterval);
    7197 }
    7198 }
    7199
    7200 /* relax rhs to zero, if it's very close to 0 */
    7201 if( *cutrhs < 0.0 && *cutrhs >= SCIPepsilon(scip) )
    7202 *cutrhs = 0.0;
    7203
    7204 SCIPintervalSetRoundingMode(previousroundmode);
    7205
    7206 return SCIP_OKAY;
    7207}
    7208
    7209#ifdef SCIP_DISABLED_CODE
    7210/** substitute aggregated slack variables:
    7211 *
    7212 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    7213 * variable only appears in its own row: \f$ a^\prime_r = scale * weight[r] * slacksign[r]. \f$
    7214 *
    7215 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    7216 * \f[
    7217 * \begin{array}{rll}
    7218 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r <= f0 \\
    7219 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f0)/(1 - f0),& \mbox{if}\qquad f_r > f0 \\
    7220 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r >= 0 \\
    7221 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f0), & \mbox{if}\qquad a^\prime_r < 0
    7222 * \end{array}
    7223 * \f]
    7224 *
    7225 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
    7226 *
    7227 * @note this method is safe for usage in exact solving mode
    7228 */
    7229static
    7230SCIP_RETCODE cutsSubstituteMIRRational(
    7231 SCIP* scip, /**< SCIP data structure */
    7232 SCIP_Real* weights, /**< row weights in row summation */
    7233 int* slacksign, /**< stores the sign of the row's slack variable in summation */
    7234 int* rowinds, /**< sparsity pattern of used rows */
    7235 int nrowinds, /**< number of used rows */
    7236 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
    7237 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    7238 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
    7239 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    7240 int* nnz, /**< number of non-zeros in cut */
    7241 SCIP_RATIONAL* f0 /**< fractional value of rhs */
    7242 )
    7243{ /*lint --e{715}*/
    7244 SCIP_ROW** rows;
    7245 SCIP_ROW* userow;
    7246 SCIP_ROWEXACT* rowexact;
    7247 SCIP_RATIONAL* onedivoneminusf0;
    7248 SCIP_RATIONAL* tmprational;
    7249 SCIP_ROUNDMODE previousroundmode;
    7250 SCIP_AGGREGATIONINFO* aggrinfo;
    7251 SCIP_Real mult;
    7252 int i;
    7253 int currentnegslackrow;
    7254 SCIP_RATIONAL* ar;
    7255 SCIP_RATIONAL* cutar;
    7256 int r;
    7257
    7258 assert(scip != NULL);
    7259 assert(weights != NULL || nrowinds == 0);
    7260 assert(slacksign != NULL || nrowinds == 0);
    7261 assert(rowinds != NULL || nrowinds == 0);
    7262 assert(scale > 0.0);
    7263 assert(cutcoefs != NULL);
    7264 assert(QUAD_HI(cutrhs) != NULL);
    7265 assert(cutinds != NULL);
    7266 assert(nnz != NULL);
    7267 assert(SCIPisExact(scip));
    7268
    7270 SCIP_CALL( SCIPrationalCreateBuffer(SCIPbuffer(scip), &onedivoneminusf0) );
    7273
    7274 /* compute 1/(1-f0) in interval arithmetic */
    7275 previousroundmode = SCIPintervalGetRoundingMode();
    7276 SCIPrationalMultReal(onedivoneminusf0, f0, -1);
    7277 SCIPrationalAddReal(onedivoneminusf0, onedivoneminusf0, 1.0);
    7278 SCIPrationalInvert(onedivoneminusf0, onedivoneminusf0);
    7279
    7280 if( SCIPisCertified(scip) )
    7281 {
    7283 }
    7284
    7285 rows = SCIPgetLPRows(scip);
    7286 currentnegslackrow = 0;
    7287 for( i = 0; i < nrowinds; i++ )
    7288 {
    7289 SCIP_ROW* row;
    7290
    7291 r = rowinds[i]; /*lint !e613*/
    7292 assert(0 <= r && r < SCIPgetNLPRows(scip));
    7293 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
    7294 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
    7295
    7296 row = rows[r];
    7297 assert(row != NULL);
    7298 assert(row->len == 0 || row->cols != NULL);
    7299 assert(row->len == 0 || row->cols_index != NULL);
    7300 assert(row->len == 0 || row->vals != NULL);
    7301
    7302 if( slacksign[i] == 1 )
    7304 else
    7306
    7307 /* get the slack's coefficient a'_r = weights[i] * scale in the aggregated row */
    7308 SCIPrationalSetReal(ar, weights[i]);
    7309 SCIPrationalMultReal(ar, ar, scale);
    7310 SCIPrationalMultReal(ar, ar, slacksign[i]);
    7311
    7312 /* calculate slack variable's coefficient a^_r in the cut */
    7313#ifdef SCIP_DISABLED_CODE
    7314 if( row->integral && !SCIPisExact(scip)
    7315 && ((slacksign[i] == +1 && SCIPisFeasIntegral(scip, row->rhs - row->constant))
    7316 || (slacksign[i] == -1 && SCIPisFeasIntegral(scip, row->lhs - row->constant))) ) /*lint !e613*/
    7317 {
    7318 /* slack variable is always integral:
    7319 * a^_r = a~_r = down(a'_r) , if f_r <= f0
    7320 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    7321 */
    7322 if( !SCIPisExact(scip) )
    7323 downar = EPSFLOOR(ar, QUAD_EPSILON);
    7324 else
    7325 downar = floor(ar);
    7326
    7327 SCIPquadprecSumDD(fr, ar, -downar);
    7328 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) && (!SCIPisExact(scip) || QUAD_TO_DBL(fr) <= QUAD_TO_DBL(f0)) )
    7329 {
    7330 QUAD_ASSIGN(cutar, downar);
    7331 }
    7332 else
    7333 {
    7334 SCIPquadprecSumQQ(cutar, fr, -f0);
    7335 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
    7336 SCIPquadprecSumQD(cutar, cutar, downar);
    7337 }
    7338 }
    7339 else
    7340#endif
    7341 {
    7342 /* slack variable is continuous:
    7343 * a^_r = a~_r = 0 , if a'_r >= 0
    7344 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    7345 */
    7346 if( !SCIPrationalIsNegative(ar) )
    7347 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
    7348 else
    7349 {
    7350 SCIPrationalMult(cutar, ar, onedivoneminusf0); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
    7351 }
    7352 }
    7353
    7354 /* if the coefficient was reduced to zero, ignore the slack variable */
    7355 if( SCIPrationalIsZero(cutar) )
    7356 continue;
    7357
    7358 /* depending on the slack's sign, we have
    7359 * sign = 1: s = rhs - a^Tx >= 0
    7360 sign = -1: s = lhs - a^Tx <= 0
    7361 */
    7362
    7363 rowexact = SCIProwGetRowExact(row);
    7364 assert(SCIProwExactHasFpRelax(rowexact));
    7365 if( SCIProwExactGetRowRhs(rowexact) != NULL && slacksign[i] == 1.0 )
    7366 userow = SCIProwExactGetRowRhs(rowexact);
    7367 else
    7368 userow = row;
    7369
    7370 {
    7371 SCIP_Bool success = TRUE;
    7372 SCIP_Real sidevalchg;
    7373
    7374 SCIPrationalMultReal(cutar, cutar, -slacksign[i]);
    7375 if( slacksign[i] == -1 )
    7377 else
    7379
    7380 if( SCIPisCertified(scip) )
    7381 {
    7382 assert(aggrinfo->negslackweights[currentnegslackrow] == -weights[i]);
    7383 aggrinfo->substfactor[currentnegslackrow] = mult;
    7384 currentnegslackrow++;
    7385 }
    7386
    7387 SCIP_CALL( varVecAddScaledRowCoefsSafely(scip, cutinds, cutcoefs, nnz, userow, mult, &sidevalchg, &success) );
    7388 assert(success);
    7389
    7390 /* move to rhs -> need to round up */
    7392 *cutrhs += sidevalchg;
    7393 }
    7394
    7395 /* move slack's constant to the right hand side */
    7396 if( slacksign[i] == +1 ) /*lint !e613*/
    7397 {
    7398 SCIP_INTERVAL valinterval;
    7399 SCIP_INTERVAL cutarinterval;
    7400
    7402 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
    7403 assert(!SCIPisInfinity(scip, userow->rhs));
    7404#ifdef SCIP_DISABLED_CODE
    7405 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
    7406 if( row->integral )
    7407 {
    7408 /* the right hand side was implicitly rounded down in row aggregation */
    7409 QUAD_ASSIGN(rowrhs, floor(QUAD_TO_DBL(rowrhs)));
    7410 }
    7411#endif
    7412 SCIPintervalSet(&valinterval, userow->rhs);
    7413 SCIPintervalSubScalar(SCIPinfinity(scip), &valinterval, valinterval, userow->constant);
    7414 SCIPintervalSetRational(&cutarinterval, cutar);
    7415 SCIPintervalMul(SCIPinfinity(scip), &valinterval, valinterval, cutarinterval);
    7416 SCIPquadprecSumQQ(*cutrhs, *cutrhs, SCIPintervalGetSup(valinterval));
    7417 }
    7418 else
    7419 {
    7420 SCIP_INTERVAL valinterval;
    7421 SCIP_INTERVAL cutarinterval;
    7422
    7424 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
    7425 assert(!SCIPisInfinity(scip, -userow->lhs));
    7426#ifdef SCIP_DISABLED_CODE
    7427 /* this is disabled because we can't certify it yet in exact solving mode; if enabled change also in addOneRowSafely() */
    7428 if( row->integral )
    7429 {
    7430 /* the left hand side was implicitly rounded up in row aggregation */
    7431 QUAD_ASSIGN(rowlhs, floor(QUAD_TO_DBL(rowlhs)));
    7432 }
    7433#endif
    7434 SCIPintervalSet(&valinterval, userow->lhs);
    7435 SCIPintervalSubScalar(SCIPinfinity(scip), &valinterval, valinterval, userow->constant);
    7436 SCIPintervalSetRational(&cutarinterval, cutar);
    7437 SCIPintervalMul(SCIPinfinity(scip), &valinterval, valinterval, cutarinterval);
    7438 SCIPquadprecSumQQ(*cutrhs, *cutrhs, SCIPintervalGetSup(valinterval));
    7439 }
    7440 }
    7441
    7442 /* relax rhs to zero, if it's very close to 0 */
    7443 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    7444 QUAD_ASSIGN(*cutrhs, 0.0);
    7445
    7446 if( SCIPisExact(scip) )
    7447 SCIPintervalSetRoundingMode(previousroundmode);
    7448
    7451
    7452 SCIPrationalFreeBuffer(SCIPbuffer(scip), &onedivoneminusf0);
    7453 SCIPrationalFreeBuffer(SCIPbuffer(scip), &tmprational);
    7454
    7455 return SCIP_OKAY;
    7456}
    7457#endif
    7458
    7459/** substitute aggregated slack variables:
    7460 *
    7461 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    7462 * variable only appears in its own row: \f$ a^\prime_r = scale * weight[r] * slacksign[r]. \f$
    7463 *
    7464 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    7465 * \f[
    7466 * \begin{array}{rll}
    7467 * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r <= f0 \\
    7468 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f0)/(1 - f0),& \mbox{if}\qquad f_r > f0 \\
    7469 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r >= 0 \\
    7470 * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f0), & \mbox{if}\qquad a^\prime_r < 0
    7471 * \end{array}
    7472 * \f]
    7473 *
    7474 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
    7475 */
    7476static
    7478 SCIP* scip, /**< SCIP data structure */
    7479 SCIP_Real* weights, /**< row weights in row summation */
    7480 int* slacksign, /**< stores the sign of the row's slack variable in summation */
    7481 int* rowinds, /**< sparsity pattern of used rows */
    7482 int nrowinds, /**< number of used rows */
    7483 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
    7484 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    7485 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
    7486 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    7487 int* nnz, /**< number of non-zeros in cut */
    7488 QUAD(SCIP_Real f0) /**< fractional value of rhs */
    7489 )
    7490{ /*lint --e{715}*/
    7491 SCIP_ROW** rows;
    7492 SCIP_Real QUAD(onedivoneminusf0);
    7493 int i;
    7494
    7495 assert(scip != NULL);
    7496 assert(weights != NULL || nrowinds == 0);
    7497 assert(slacksign != NULL || nrowinds == 0);
    7498 assert(rowinds != NULL || nrowinds == 0);
    7499 assert(scale > 0.0);
    7500 assert(cutcoefs != NULL);
    7501 assert(QUAD_HI(cutrhs) != NULL);
    7502 assert(cutinds != NULL);
    7503 assert(nnz != NULL);
    7504 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
    7505 assert(!SCIPisExact(scip));
    7506
    7507 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
    7508 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
    7509
    7510 rows = SCIPgetLPRows(scip);
    7511 for( i = 0; i < nrowinds; i++ )
    7512 {
    7513 SCIP_ROW* row;
    7514 SCIP_Real QUAD(ar);
    7515 SCIP_Real QUAD(downar);
    7516 SCIP_Real QUAD(cutar);
    7517 SCIP_Real QUAD(fr);
    7518 SCIP_Real QUAD(tmp);
    7519 SCIP_Real QUAD(myprod);
    7520 int r;
    7521
    7522 r = rowinds[i]; /*lint !e613*/
    7523 assert(0 <= r && r < SCIPgetNLPRows(scip));
    7524 assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
    7525 assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
    7526
    7527 row = rows[r];
    7528 assert(row != NULL);
    7529 assert(row->len == 0 || row->cols != NULL);
    7530 assert(row->len == 0 || row->cols_index != NULL);
    7531 assert(row->len == 0 || row->vals != NULL);
    7532
    7533 /* get the slack's coefficient a'_r in the aggregated row */
    7534 SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
    7535
    7536 /* calculate slack variable's coefficient a^_r in the cut */
    7537 if( row->integral )
    7538 {
    7539 /* slack variable is always integral:
    7540 * a^_r = a~_r = down(a'_r) , if f_r <= f0
    7541 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    7542 */
    7543 SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
    7544 SCIPquadprecSumQQ(fr, ar, -downar);
    7545 assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
    7546
    7547 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
    7548 QUAD_ASSIGN_Q(cutar, downar); /* a^_r */
    7549 else
    7550 {
    7551 SCIPquadprecSumQQ(cutar, fr, -f0);
    7552 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
    7553 SCIPquadprecSumQQ(cutar, cutar, downar);
    7554 }
    7555 }
    7556 else
    7557 {
    7558 /* slack variable is continuous:
    7559 * a^_r = a~_r = 0 , if a'_r >= 0
    7560 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    7561 */
    7562 if( QUAD_TO_DBL(ar) >= 0.0 )
    7563 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
    7564 else
    7565 SCIPquadprecProdQQ(cutar, onedivoneminusf0, ar);
    7566 }
    7567
    7568 /* if the coefficient was reduced to zero, ignore the slack variable */
    7569 if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
    7570 continue;
    7571
    7572 /* depending on the slack's sign, we have
    7573 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
    7574 * substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
    7575 */
    7576 SCIPquadprecProdQD(myprod, cutar, -slacksign[i]);
    7577
    7578 /* add the slack's definition multiplied with a^_j to the cut */
    7579 SCIP_CALL( varVecAddScaledRowCoefsQuadScale(cutinds, cutcoefs, nnz, row, QUAD(myprod)) );
    7580
    7581 /* move slack's constant to the right hand side */
    7582 if( slacksign[i] == +1 ) /*lint !e613*/
    7583 {
    7584 SCIP_Real QUAD(rowrhs);
    7585
    7586 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
    7587 assert(!SCIPisInfinity(scip, row->rhs));
    7588 QUAD_ASSIGN(rowrhs, row->rhs - row->constant);
    7589 if( row->integral )
    7590 {
    7591 /* the right hand side was implicitly rounded down in row aggregation */
    7592 SCIPquadprecEpsFloorQ(rowrhs, rowrhs, SCIPepsilon(scip)); /*lint !e666*/
    7593 }
    7594 SCIPquadprecProdQQ(tmp, myprod, rowrhs);
    7595 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
    7596 }
    7597 else
    7598 {
    7599 SCIP_Real QUAD(rowlhs);
    7600
    7601 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
    7602 assert(!SCIPisInfinity(scip, -row->lhs));
    7603 QUAD_ASSIGN(rowlhs, row->lhs - row->constant);
    7604 if( row->integral )
    7605 {
    7606 /* the left hand side was implicitly rounded up in row aggregation */
    7607 SCIPquadprecEpsCeilQ(rowlhs, rowlhs, SCIPepsilon(scip)); /*lint !e666*/
    7608 }
    7609 SCIPquadprecProdQQ(tmp, myprod, rowlhs);
    7610 SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
    7611 }
    7612 }
    7613
    7614 /* relax rhs to zero, if it's very close to 0 */
    7615 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    7616 QUAD_ASSIGN(*cutrhs, 0.0);
    7617
    7618 return SCIP_OKAY;
    7619}
    7620
    7621/** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
    7622 * these rows cannot participate in an MIR cut.
    7623 *
    7624 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    7625 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    7626 *
    7627 * @pre This method can be called if @p scip is in one of the following stages:
    7628 * - \ref SCIP_STAGE_SOLVING
    7629 *
    7630 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    7631 *
    7632 * @note this method is safe for usage in exact solving mode
    7633 *
    7634 * @todo make behavior identical to the unsafe MIR cut computation
    7635 */
    7636static
    7638 SCIP* scip, /**< SCIP data structure */
    7639 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    7640 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
    7641 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    7642 SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
    7643 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    7644 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    7645 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    7646 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    7647 * NULL for using closest bound for all variables */
    7648 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    7649 * NULL for using closest bound for all variables */
    7650 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
    7651 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
    7652 SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
    7653 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
    7654 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
    7655 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
    7656 int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
    7657 int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
    7658 SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
    7659 int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
    7660 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
    7661 SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
    7662 )
    7663{
    7664 int i;
    7665 int nvars;
    7666 int tmpnnz;
    7667 int* varsign;
    7668 int* boundtype;
    7669 int* tmpinds;
    7670 SCIP_Real* tmpcoefs;
    7671
    7672 SCIP_Real rhs;
    7673 SCIP_Real downrhs;
    7674 SCIP_Bool freevariable;
    7675 SCIP_Bool localbdsused;
    7676 SCIP_Bool tmpislocal;
    7677
    7678 SCIP_ROUNDMODE previousroundmode;
    7679 SCIP_INTERVAL f0interval;
    7680
    7681 assert(aggrrow != NULL);
    7682 assert(SCIPisPositive(scip, scale));
    7683 assert(SCIPisExact(scip));
    7684 assert(success != NULL);
    7685
    7686 SCIPdebugMsg(scip, "calculating MIR cut (scale: %g)\n", scale);
    7687
    7688 *success = FALSE;
    7689 *cutislocal = FALSE;
    7690
    7691 /* allocate temporary memory */
    7692 nvars = SCIPgetNVars(scip);
    7693 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
    7694 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
    7695 SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
    7696 SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, nvars) );
    7697
    7698 /* initialize cut with aggregation */
    7699 tmpnnz = aggrrow->nnz;
    7700 tmpislocal = aggrrow->local;
    7701
    7702 previousroundmode = SCIPintervalGetRoundingMode();
    7704
    7705 if( SCIPisCertified(scip) )
    7706 {
    7708 }
    7709
    7710 rhs = QUAD_TO_DBL(aggrrow->rhs) * scale;
    7711
    7712 if( tmpnnz > 0 )
    7713 {
    7714 BMScopyMemoryArray(tmpinds, aggrrow->inds, tmpnnz);
    7715
    7716 for( i = 0; i < tmpnnz; ++i )
    7717 {
    7718 SCIP_Real coef;
    7719 int k = aggrrow->inds[i];
    7720
    7721 coef = aggrrow->vals[k];
    7722 coef *= scale;
    7723 tmpcoefs[k] = coef;
    7724
    7725 assert(coef != 0.0);
    7726 }
    7727
    7728 SCIPdebugMsg(scip, "Initial row:\n");
    7729 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
    7730
    7731 /* Transform equation a*x == b, lb <= x <= ub into standard form
    7732 * a'*x' == b, 0 <= x' <= ub'.
    7733 *
    7734 * Transform variables (lb or ub):
    7735 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
    7736 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
    7737 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
    7738 *
    7739 * Transform variables (vlb or vub):
    7740 * 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.
    7741 * 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.
    7742 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
    7743 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
    7744 * a_{zu_j} := a_{zu_j} + a_j * bu_j
    7745 */
    7746 SCIP_CALL( cutsTransformMIRSafely(scip, sol, boundswitch, usevbds, allowlocal, fixintegralrhs, FALSE,
    7747 boundsfortrans, boundtypesfortrans, tmpcoefs, &rhs, tmpinds, &tmpnnz, varsign, boundtype, &freevariable, &localbdsused) );
    7748 assert(allowlocal || !localbdsused);
    7749 tmpislocal = tmpislocal || localbdsused;
    7750
    7751 if( freevariable )
    7752 goto TERMINATE;
    7753
    7754 SCIPdebugMsg(scip, "Aggregated and transformed:\n");
    7755 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
    7756 }
    7757
    7758 /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
    7759 * a~*x' <= down(b)
    7760 * integers : a~_j = down(a'_j) , if f_j <= f_0
    7761 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
    7762 * continuous: a~_j = 0 , if a'_j >= 0
    7763 * a~_j = a'_j/(1 - f0) , if a'_j < 0
    7764 *
    7765 * Transform inequality back to a^*x <= rhs:
    7766 *
    7767 * (lb or ub):
    7768 * 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
    7769 * 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
    7770 * and move the constant terms
    7771 * -a~_j * lb_j == -a^_j * lb_j, or
    7772 * a~_j * ub_j == -a^_j * ub_j
    7773 * to the rhs.
    7774 *
    7775 * (vlb or vub):
    7776 * 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)
    7777 * 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)
    7778 * move the constant terms
    7779 * -a~_j * dl_j == -a^_j * dl_j, or
    7780 * a~_j * du_j == -a^_j * du_j
    7781 * to the rhs, and update the VB variable coefficients:
    7782 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
    7783 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
    7784 */
    7785
    7786 downrhs = floor(rhs);
    7787
    7788 if( SCIPisCertified(scip) )
    7789 {
    7791 SCIPrationalSetReal(mirinfo->rhs, downrhs);
    7792 SCIPrationalSetReal(mirinfo->frac, rhs);
    7793 SCIPrationalDiffReal(mirinfo->frac, mirinfo->frac, downrhs);
    7794 }
    7795
    7796 SCIPintervalSet(&f0interval, rhs);
    7797 SCIPintervalSubScalar(SCIPinfinity(scip), &f0interval, f0interval, downrhs);
    7798
    7799 if( f0interval.inf < minfrac || f0interval.sup > maxfrac )
    7800 goto TERMINATE;
    7801
    7802 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
    7803 * If this gives a scalar that is very big, we better do not generate this cut.
    7804 */
    7805 if( REALABS(scale)/(1.0 - f0interval.inf) > MAXCMIRSCALE )
    7806 goto TERMINATE;
    7807
    7808 /* renormalize f0 value */
    7809 rhs = downrhs;
    7810
    7811 if( tmpnnz > 0 )
    7812 {
    7813 SCIP_CALL( cutsRoundMIRSafely(scip, tmpcoefs, &rhs, tmpinds, &tmpnnz, varsign, boundtype, f0interval) ); /*lint !e644*/
    7814
    7815 SCIPdebugMsg(scip, "After MIR rounding:\n");
    7816 SCIPdebug(printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE));
    7817 }
    7818
    7819 /* substitute aggregated slack variables:
    7820 *
    7821 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    7822 * variable only appears in its own row:
    7823 * a'_r = scale * weight[r] * slacksign[r].
    7824 *
    7825 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    7826 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
    7827 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    7828 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
    7829 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    7830 *
    7831 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
    7832 */
    7833
    7834 SCIP_CALL( cutsSubstituteMIRSafely(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
    7835 aggrrow->nrows, scale, tmpcoefs, &rhs, tmpinds, &tmpnnz, f0interval) );
    7836
    7837 SCIPdebugMsg(scip, "After slack substitution:\n");
    7838 SCIPdebug( printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE) );
    7839
    7840 /* we work on rhs -> round up */
    7842
    7843 if( postprocess )
    7844 {
    7845 SCIP_CALL( postprocessCutSafely(scip, tmpislocal, tmpinds, tmpcoefs, &tmpnnz, &rhs, success) );
    7846 }
    7847 else
    7848 {
    7849 *success = !removeZerosSafely(scip, SCIPsumepsilon(scip), tmpcoefs, &rhs, tmpinds, &tmpnnz);
    7850 }
    7851
    7852 SCIPdebugMsg(scip, "After post processing:\n");
    7853 SCIPdebug( printCut(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz, FALSE, FALSE) );
    7854
    7855 if( *success )
    7856 {
    7857 SCIP_Real mirefficacy = calcEfficacyDenseStorage(scip, sol, tmpcoefs, rhs, tmpinds, tmpnnz);
    7858
    7859 if( SCIPisEfficacious(scip, mirefficacy) && (cutefficacy == NULL || mirefficacy > *cutefficacy) )
    7860 {
    7861 BMScopyMemoryArray(cutinds, tmpinds, tmpnnz);
    7862 *cutnnz = tmpnnz;
    7863 *cutrhs = rhs;
    7864 *cutislocal = tmpislocal;
    7865
    7866 /* clean tmpcoefs and go back to double precision */
    7867 for( i = 0; i < *cutnnz; ++i )
    7868 {
    7869 int j = cutinds[i];
    7870
    7871 cutcoefs[i] = tmpcoefs[j];
    7872 tmpcoefs[j] = 0.0;
    7873 }
    7874
    7875 if( cutefficacy != NULL )
    7876 *cutefficacy = mirefficacy;
    7877
    7878 if( cutrank != NULL )
    7879 *cutrank = aggrrow->rank + 1;
    7880 }
    7881 else
    7882 {
    7883 *success = FALSE;
    7884 }
    7885 }
    7886
    7887 TERMINATE:
    7888
    7889 /* reset the rounding mode in exact mode */
    7890 SCIPintervalSetRoundingMode(previousroundmode); /*lint !e644*/
    7891
    7892 if( !(*success) )
    7893 {
    7894 for( i = 0; i < tmpnnz; ++i )
    7895 {
    7896 tmpcoefs[tmpinds[i]] = 0.0;
    7897 }
    7898 }
    7899
    7900 /* free temporary memory */
    7901 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
    7902 SCIPfreeBufferArray(scip, &tmpinds);
    7903 SCIPfreeBufferArray(scip, &boundtype);
    7904 SCIPfreeBufferArray(scip, &varsign);
    7905
    7906 return SCIP_OKAY;
    7907}
    7908
    7909
    7910/** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
    7911 * these rows cannot participate in an MIR cut.
    7912 *
    7913 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    7914 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    7915 *
    7916 * @pre This method can be called if @p scip is in one of the following stages:
    7917 * - \ref SCIP_STAGE_SOLVING
    7918 *
    7919 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    7920 *
    7921 * @note this method is safe for usage in exact solving mode
    7922 */
    7924 SCIP* scip, /**< SCIP data structure */
    7925 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    7926 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
    7927 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    7928 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
    7929 * type substitution is allowed. The indices are: 0: continuous,
    7930 * 1: continuous implint., 2: integer implint, 3: binary implint,
    7931 * 4: integer, 5: binary */
    7932 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    7933 SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
    7934 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    7935 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    7936 * NULL for using closest bound for all variables */
    7937 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    7938 * NULL for using closest bound for all variables */
    7939 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
    7940 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
    7941 SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
    7942 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
    7943 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
    7944 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
    7945 int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
    7946 int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
    7947 SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
    7948 int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
    7949 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
    7950 SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
    7951 )
    7952{
    7953 MIR_DATA* data;
    7954 int* varsign;
    7955 int* boundtype;
    7956 SCIP_Real QUAD(downrhs);
    7957 SCIP_Real QUAD(f0);
    7958 SCIP_Bool freevariable;
    7959 SCIP_Bool localbdsused;
    7960 SCIP_Bool tmpislocal;
    7961
    7962 assert(aggrrow != NULL);
    7963 assert(SCIPisPositive(scip, scale));
    7964 assert(success != NULL);
    7965
    7966 if( SCIPisExact(scip) )
    7967 {
    7968 /* TODO: update exactSCIP cuts to behave identically with respect to implied integrality */
    7969 return calcMIRSafely(scip, sol, postprocess, boundswitch, vartypeusevbds > 0 ? TRUE : FALSE, allowlocal, fixintegralrhs,
    7970 boundsfortrans, boundtypesfortrans, minfrac, maxfrac, scale, aggrrow, cutcoefs, cutrhs,
    7971 cutinds, cutnnz, cutefficacy, cutrank, cutislocal, success);
    7972 }
    7973 SCIPdebugMsg(scip, "calculating MIR cut (scale: %g)\n", scale);
    7974
    7975 *success = FALSE;
    7976
    7977 /* Setup data to track cut and initialize the cut with aggregation */
    7978 int l;
    7979 int nnz;
    7980
    7981 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
    7982
    7983 SCIP_CALL( SCIPallocBuffer(scip, &data) );
    7984
    7985 nnz = aggrrow->nnz;
    7986 data->totalnnz = nnz;
    7987
    7988 /* initialize sections */
    7989 for( l = 0; l < NSECTIONS; ++l )
    7990 {
    7991 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
    7992 data->secnnz[l] = 0;
    7993 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
    7994 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
    7995 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
    7996 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
    7997 /* Use variable bounds for the sections specified by the user */
    7998 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
    7999 }
    8000
    8001 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
    8002 data->vars = SCIPgetVars(scip);
    8003 data->nvars = SCIPgetNVars(scip);
    8004 data->nbinvars = SCIPgetNBinVars(scip);
    8005 data->nintvars = SCIPgetNIntVars(scip);
    8010
    8012 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
    8013
    8014 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, scale);
    8015
    8016 if( nnz > 0 )
    8017 {
    8018 /* Initalize cut with the aggregation */
    8019 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
    8020
    8021 for( l = 0; l < nnz; ++l )
    8022 {
    8023 SCIP_Real QUAD(coef);
    8024 int m = aggrrow->inds[l];
    8025
    8026 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
    8027
    8028 SCIPquadprecProdQD(coef, coef, scale);
    8029
    8030 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
    8031
    8032 assert(QUAD_HI(coef) != 0.0);
    8033 }
    8034
    8035 /* Sort the array by problem index and add the variables to their sections */
    8036 SCIPsortDownInt(data->cutinds, nnz);
    8037 for( l = 0; l < nnz; ++l )
    8038 {
    8039 int section = varSection(data, data->cutinds[l]);
    8040 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
    8041 ++data->secnnz[section];
    8042 }
    8043 }
    8044
    8045 SCIPdebugMsg(scip, "Initial row:\n");
    8046 SCIPdebug( printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, nnz, FALSE, FALSE) );
    8047
    8048 data->ncutinds = 0;
    8049 tmpislocal = aggrrow->local;
    8050
    8051 /* allocate temporary memory */
    8052 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, data->nvars) );
    8053 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, data->nvars) );
    8054
    8055 /* Transform equation a*x == b, lb <= x <= ub into standard form
    8056 * a'*x' == b, 0 <= x' <= ub'.
    8057 *
    8058 * Transform variables (lb or ub):
    8059 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
    8060 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
    8061 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
    8062 *
    8063 * Transform variables (vlb or vub):
    8064 * 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.
    8065 * 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.
    8066 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
    8067 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
    8068 * a_{zu_j} := a_{zu_j} + a_j * bu_j
    8069 */
    8070 if( data->totalnnz > 0 )
    8071 {
    8072 SCIP_CALL( cutsTransformMIR(scip, data, sol, boundswitch, allowlocal, fixintegralrhs, FALSE,
    8073 boundsfortrans, boundtypesfortrans, minfrac, maxfrac,
    8074 varsign, boundtype, &freevariable, &localbdsused) );
    8075 assert(allowlocal || !localbdsused);
    8076 tmpislocal = tmpislocal || localbdsused;
    8077
    8078 if( freevariable )
    8079 goto TERMINATE;
    8080
    8081 SCIPdebugMsg(scip, "Aggregated and transformed:\n");
    8082 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    8083 }
    8084
    8085 /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
    8086 * a~*x' <= down(b)
    8087 * integers : a~_j = down(a'_j) , if f_j <= f_0
    8088 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
    8089 * continuous: a~_j = 0 , if a'_j >= 0
    8090 * a~_j = a'_j/(1 - f0) , if a'_j < 0
    8091 *
    8092 * Transform inequality back to a^*x <= rhs:
    8093 *
    8094 * (lb or ub):
    8095 * 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
    8096 * 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
    8097 * and move the constant terms
    8098 * -a~_j * lb_j == -a^_j * lb_j, or
    8099 * a~_j * ub_j == -a^_j * ub_j
    8100 * to the rhs.
    8101 *
    8102 * (vlb or vub):
    8103 * 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)
    8104 * 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)
    8105 * move the constant terms
    8106 * -a~_j * dl_j == -a^_j * dl_j, or
    8107 * a~_j * du_j == -a^_j * du_j
    8108 * to the rhs, and update the VB variable coefficients:
    8109 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
    8110 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
    8111 */
    8112
    8113 SCIPquadprecEpsFloorQ(downrhs, data->cutrhs, SCIPepsilon(scip)); /*lint !e666*/
    8114 SCIPquadprecSumQQ(f0, data->cutrhs, -downrhs);
    8115 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
    8116
    8117 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
    8118 goto TERMINATE;
    8119
    8120 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
    8121 * If this gives a scalar that is very big, we better do not generate this cut.
    8122 */
    8123 if( REALABS(scale)/(1.0 - QUAD_TO_DBL(f0)) > MAXCMIRSCALE )
    8124 goto TERMINATE;
    8125
    8126 /* renormalize f0 value */
    8127 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
    8128
    8129 QUAD_ASSIGN_Q(data->cutrhs, downrhs);
    8130
    8131 if( data->totalnnz > 0 )
    8132 {
    8133 SCIP_CALL( cutsRoundMIR(scip, data, varsign, boundtype, QUAD(f0)) );
    8134
    8135 SCIPdebugMsg(scip, "After MIR rounding:\n");
    8136 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    8137 }
    8138
    8139 /* substitute aggregated slack variables:
    8140 *
    8141 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    8142 * variable only appears in its own row:
    8143 * a'_r = scale * weight[r] * slacksign[r].
    8144 *
    8145 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    8146 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
    8147 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    8148 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
    8149 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    8150 *
    8151 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
    8152 */
    8153 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
    8154 aggrrow->nrows, scale,
    8155 data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds, QUAD(f0)) );
    8156
    8157 SCIPdebugMsg(scip, "After slack substitution:\n");
    8158 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    8159
    8160 if( postprocess )
    8161 {
    8162 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
    8163 * prevent numerical rounding errors
    8164 */
    8165 SCIP_CALL( postprocessCutQuad(scip, tmpislocal, data->cutinds, data->cutcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
    8166 }
    8167 else
    8168 {
    8169 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), tmpislocal, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds);
    8170 }
    8171
    8172 SCIPdebugMsg(scip, "After post processing:\n");
    8173 SCIPdebug( printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE) );
    8174
    8175 if( *success )
    8176 {
    8177 SCIP_Real mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, data->cutcoefs, QUAD_TO_DBL(data->cutrhs), data->cutinds, data->ncutinds);
    8178
    8179 if( SCIPisEfficacious(scip, mirefficacy) && (cutefficacy == NULL || mirefficacy > *cutefficacy) )
    8180 {
    8181 BMScopyMemoryArray(cutinds, data->cutinds, data->ncutinds);
    8182 *cutnnz = data->ncutinds;
    8183 *cutrhs = QUAD_TO_DBL(data->cutrhs);
    8184 *cutislocal = tmpislocal;
    8185
    8186 /* clean tmpcoefs and go back to double precision */
    8187 for(int i = 0; i < *cutnnz; ++i )
    8188 {
    8189 SCIP_Real QUAD(coef);
    8190 int j = cutinds[i];
    8191
    8192 QUAD_ARRAY_LOAD(coef, data->cutcoefs, j);
    8193
    8194 cutcoefs[i] = QUAD_TO_DBL(coef);
    8195 QUAD_ASSIGN(coef, 0.0);
    8196 QUAD_ARRAY_STORE(data->cutcoefs, j, coef);
    8197 }
    8198
    8199 if( cutefficacy != NULL )
    8200 *cutefficacy = mirefficacy;
    8201
    8202 if( cutrank != NULL )
    8203 *cutrank = aggrrow->rank + 1;
    8204 }
    8205 else
    8206 {
    8207 *success = FALSE;
    8208 }
    8209 }
    8210
    8211 TERMINATE:
    8212 if( !(*success) )
    8213 {
    8214 SCIP_Real QUAD(tmp);
    8215
    8216 QUAD_ASSIGN(tmp, 0.0);
    8217 for(int i = 0; i < data->ncutinds; ++i )
    8218 {
    8219 QUAD_ARRAY_STORE(data->cutcoefs, data->cutinds[i], tmp);
    8220 }
    8221 }
    8222
    8223#ifndef NDEBUG
    8224 for( int i = 0; i < QUAD_ARRAY_SIZE(data->nvars); ++i )
    8225 {
    8226 if(data->cutcoefs[i] != 0.0)
    8227 {
    8228 SCIPdebugMsg(scip, "coefs have not been reset\n");
    8229 SCIPABORT();
    8230 }
    8231 }
    8232#endif
    8233
    8234 SCIPfreeBufferArray(scip, &boundtype);
    8235 SCIPfreeBufferArray(scip, &varsign);
    8236
    8237 if( data->cutinds != NULL )
    8239
    8240 if( data->cutcoefs != NULL )
    8242
    8243 for( int s = NSECTIONS - 1; s >= 0; --s )
    8244 {
    8246 }
    8247
    8248 SCIPfreeBuffer(scip, &data);
    8249
    8250 return SCIP_OKAY;
    8251}
    8252
    8253/** compute the efficacy of the MIR cut for the given values without computing the cut.
    8254 * This is used for the CMIR cut generation heuristic.
    8255 */
    8256static
    8258 SCIP* scip, /**< SCIP datastructure */
    8259 SCIP_Real*RESTRICT coefs, /**< array with coefficients in row */
    8260 SCIP_Real*RESTRICT solvals, /**< solution values of variables in the row */
    8261 SCIP_Real rhs, /**< right hand side of MIR cut */
    8262 SCIP_Real contactivity, /**< aggregated activity of continuous variables in the row */
    8263 SCIP_Real contsqrnorm, /**< squared norm of continuous variables */
    8264 SCIP_Real delta, /**< delta value to compute the violation for */
    8265 int nvars, /**< number of variables in the row, i.e. the size of coefs and solvals arrays */
    8266 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
    8267 SCIP_Real maxfrac /**< maximal fractionality of rhs to produce MIR cut for */
    8268 )
    8269{
    8270 int i;
    8271 SCIP_Real f0pluseps;
    8272 SCIP_Real f0;
    8273 SCIP_Real onedivoneminusf0;
    8274 SCIP_Real scale;
    8275 SCIP_Real downrhs;
    8276 SCIP_Real norm;
    8277 SCIP_Real contscale;
    8278
    8279 scale = 1.0 / delta;
    8280 rhs *= scale;
    8281 downrhs = SCIPfloor(scip, rhs);
    8282 f0 = rhs - downrhs;
    8283
    8284 if( f0 < minfrac || f0 > maxfrac )
    8285 return 0.0;
    8286
    8287 onedivoneminusf0 = 1.0 / (1.0 - f0);
    8288
    8289 contscale = scale * onedivoneminusf0;
    8290
    8291 /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
    8292 * If this gives a scalar that is very big, we better do not generate this cut.
    8293 */
    8294 if( contscale > MAXCMIRSCALE )
    8295 return 0.0;
    8296
    8297 rhs = downrhs;
    8298 rhs -= contscale * contactivity;
    8299 norm = SQR(contscale) * contsqrnorm;
    8300
    8301 assert(!SCIPisFeasZero(scip, f0));
    8302 assert(!SCIPisFeasZero(scip, 1.0 - f0));
    8303
    8304 f0pluseps = f0 + SCIPepsilon(scip);
    8305
    8306 for( i = 0; i < nvars; ++i )
    8307 {
    8308 SCIP_Real floorai = SCIPfloor(scip, scale * coefs[i]);
    8309 SCIP_Real fi = (scale * coefs[i]) - floorai;
    8310
    8311 if( fi > f0pluseps )
    8312 floorai += (fi - f0) * onedivoneminusf0;
    8313
    8314 rhs -= solvals[i] * floorai;
    8315 norm += SQR(floorai);
    8316 }
    8317
    8318 norm = sqrt(norm);
    8319
    8320 return - rhs / MAX(norm, 1e-6);
    8321}
    8322
    8323/** calculates an MIR cut out of an aggregation of LP rows
    8324 *
    8325 * Given the aggregation, it is transformed to a mixed knapsack set via complementation (using bounds or variable bounds)
    8326 * Then, different scalings of the mkset are used to generate a MIR and the best is chosen.
    8327 * One of the steps of the MIR is to round the coefficients of the integer variables down,
    8328 * so one would prefer to have integer coefficients for integer variables which are far away from their bounds in the
    8329 * mkset.
    8330 *
    8331 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    8332 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    8333 *
    8334 * @pre This method can be called if @p scip is in one of the following stages:
    8335 * - \ref SCIP_STAGE_SOLVING
    8336 *
    8337 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    8338 */
    8340 SCIP* scip, /**< SCIP data structure */
    8341 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    8342 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
    8343 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    8344 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
    8345 * type substitution is allowed. The indices are: 0: continuous,
    8346 * 1: continuous implint., 2: integer implint, 3: binary implint,
    8347 * 4: integer, 5: binary */
    8348 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    8349 int maxtestdelta, /**< maximum number of deltas to test */
    8350 int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
    8351 * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
    8352 * NULL for using closest bound for all variables */
    8353 SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
    8354 * NULL for using closest bound for all variables */
    8355 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
    8356 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
    8357 SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
    8358 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
    8359 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
    8360 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
    8361 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
    8362 SCIP_Real* cutefficacy, /**< pointer to store efficacy of best cut; only cuts that are strictly better than the value of
    8363 * this efficacy on input to this function are returned */
    8364 int* cutrank, /**< pointer to return rank of generated cut (or NULL) */
    8365 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
    8366 SCIP_Bool* success /**< pointer to store whether a valid and efficacious cut was returned */
    8367 )
    8368{
    8369 int i;
    8370 int firstcontvar;
    8371 int nvars;
    8372 int intstart;
    8373 int ntmpcoefs;
    8374 int* varsign;
    8375 int* boundtype;
    8376 int* mksetinds;
    8377 SCIP_Real* mksetcoefs;
    8378 SCIP_Real QUAD(mksetrhs);
    8379 int mksetnnz;
    8380 SCIP_Real* bounddist;
    8381 int* bounddistpos;
    8382 int nbounddist;
    8383 SCIP_Real* tmpcoefs;
    8384 SCIP_Real* tmpvalues;
    8385 SCIP_Real* deltacands;
    8386 int ndeltacands;
    8387 SCIP_Real bestdelta;
    8388 SCIP_Real bestefficacy;
    8389 SCIP_Real maxabsmksetcoef;
    8390 SCIP_VAR** vars;
    8391 SCIP_Bool freevariable;
    8392 SCIP_Bool localbdsused;
    8393 SCIP_Real contactivity;
    8394 SCIP_Real contsqrnorm;
    8395 MIR_DATA* data;
    8396
    8397 assert(aggrrow != NULL);
    8398 assert(aggrrow->nrows + aggrrow->nnz >= 1);
    8399 assert(success != NULL);
    8400
    8401 *success = FALSE;
    8402 nvars = SCIPgetNVars(scip);
    8403 firstcontvar = nvars - SCIPgetNContVars(scip) - SCIPgetNContImplVars(scip);
    8404 vars = SCIPgetVars(scip);
    8405
    8406 /* allocate temporary memory */
    8407 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
    8408 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
    8409
    8410 SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, nvars + aggrrow->nrows) );
    8411 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars + aggrrow->nrows) );
    8412 /* The +4 comes from a few rules that create extra delta candidates, see usages of ndeltacands. */
    8413 SCIP_CALL( SCIPallocBufferArray(scip, &deltacands, nvars + 4) );
    8414
    8415 /* we only compute bound distance for integer variables; by variable bound substitution, the number of integer variables
    8416 * can grow significantly. Hence, these allocations are length nvars */
    8417 SCIP_CALL( SCIPallocBufferArray(scip, &bounddist, nvars) );
    8418 SCIP_CALL( SCIPallocBufferArray(scip, &bounddistpos, nvars) );
    8419
    8420 /* initialize mkset with the unscaled aggregation */
    8421 {
    8422 int l;
    8423 int nnz;
    8424
    8425 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
    8426
    8427 SCIP_CALL( SCIPallocBuffer(scip, &data) );
    8428
    8429 nnz = aggrrow->nnz;
    8430 data->totalnnz = nnz;
    8431
    8432 /* initialize sections */
    8433 for( l = 0; l < NSECTIONS; ++l )
    8434 {
    8435 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
    8436 data->secnnz[l] = 0;
    8437 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
    8438 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
    8439 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
    8440 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
    8441 /* Use variable bounds for the sections specified by the user */
    8442 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
    8443 }
    8444
    8445 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
    8446 data->vars = SCIPgetVars(scip);
    8447 data->nvars = SCIPgetNVars(scip);
    8448 data->nbinvars = SCIPgetNBinVars(scip);
    8449 data->nintvars = SCIPgetNIntVars(scip);
    8454
    8456 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
    8457
    8458 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, 1.0);
    8459
    8460 if( nnz > 0 )
    8461 {
    8462 /* Initalize cut with the aggregation */
    8463 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
    8464
    8465 for( l = 0; l < nnz; ++l )
    8466 {
    8467 SCIP_Real QUAD(coef);
    8468 int m = aggrrow->inds[l];
    8469
    8470 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
    8471
    8472 SCIPquadprecProdQD(coef, coef, 1.0);
    8473
    8474 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
    8475
    8476 assert(QUAD_HI(coef) != 0.0);
    8477 }
    8478
    8479 /* Sort the array by problem index and add the variables to their sections */
    8480 SCIPsortDownInt(data->cutinds, nnz);
    8481 for( l = 0; l < nnz; ++l )
    8482 {
    8483 int section = varSection(data, data->cutinds[l]);
    8484 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
    8485 ++data->secnnz[section];
    8486 }
    8487 }
    8488
    8489 data->ncutinds = 0;
    8490 }
    8491 *cutislocal = aggrrow->local;
    8492
    8493 /* Transform equation a*x == b, lb <= x <= ub into standard form
    8494 * a'*x' == b, 0 <= x' <= ub'.
    8495 *
    8496 * Transform variables (lb or ub):
    8497 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
    8498 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
    8499 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
    8500 *
    8501 * Transform variables (vlb or vub):
    8502 * 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.
    8503 * 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.
    8504 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
    8505 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
    8506 * a_{zu_j} := a_{zu_j} + a_j * bu_j
    8507 */
    8508 SCIP_CALL( cutsTransformMIR(scip, data, sol, boundswitch, allowlocal, FALSE, FALSE,
    8509 boundsfortrans, boundtypesfortrans, minfrac, maxfrac, varsign, boundtype, &freevariable, &localbdsused) );
    8510 assert(allowlocal || !localbdsused);
    8511
    8512 /* Use aliases to stay more consistent with the old code. mksetrhs needs to synchronize its values data->cutrhs
    8513 * again before calling SCIProundMIR()! */
    8514 mksetinds = data->cutinds;
    8515 mksetcoefs = data->cutcoefs;
    8516 mksetnnz = data->ncutinds;
    8517 QUAD_ASSIGN_Q(mksetrhs, data->cutrhs);
    8518
    8519 if( freevariable )
    8520 goto TERMINATE;
    8521
    8522 SCIPdebugMsg(scip, "transformed aggrrow row:\n");
    8523 SCIPdebug( printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE) );
    8524
    8525 /* found positions of integral variables that are strictly between their bounds */
    8526 maxabsmksetcoef = -1.0;
    8527 nbounddist = 0;
    8528
    8529 assert(mksetnnz <= nvars);
    8530 for( i = mksetnnz - 1; i >= 0 && mksetinds[i] < firstcontvar; --i )
    8531 {
    8532 SCIP_VAR* var = vars[mksetinds[i]];
    8533 SCIP_Real primsol = SCIPgetSolVal(scip, sol, var);
    8534 SCIP_Real lb = SCIPvarGetLbLocal(var);
    8535 SCIP_Real ub = SCIPvarGetUbLocal(var);
    8536 SCIP_Real QUAD(coef);
    8537
    8538 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
    8539
    8540 if( SCIPisEQ(scip, primsol, lb) || SCIPisEQ(scip, primsol, ub) )
    8541 continue;
    8542
    8543 bounddist[nbounddist] = MIN(ub - primsol, primsol - lb);
    8544 bounddistpos[nbounddist] = i;
    8545 deltacands[nbounddist] = QUAD_TO_DBL(coef);
    8546 ++nbounddist;
    8547 }
    8548 assert(nbounddist <= nvars);
    8549
    8550 /* no fractional variable; so abort here */
    8551 if( nbounddist == 0 )
    8552 goto TERMINATE;
    8553
    8554 intstart = i + 1;
    8555
    8556 /* Check that the continuous and implied integer variables and integer variables are partitioned */
    8557#ifndef NDEBUG
    8558 for( int j = 0; j < intstart; ++j )
    8559 {
    8560 assert(SCIPvarGetType(vars[mksetinds[j]]) == SCIP_VARTYPE_CONTINUOUS);
    8561 }
    8562 for( int j = intstart; j < data->ncutinds; ++j )
    8563 {
    8564 assert(SCIPvarIsIntegral(vars[mksetinds[j]]));
    8565 }
    8566#endif
    8567
    8568 ndeltacands = nbounddist;
    8569 assert(ndeltacands <= nvars);
    8570 SCIPsortDownRealRealInt(bounddist, deltacands, bounddistpos, nbounddist);
    8571
    8572 {
    8573 SCIP_Real intscale;
    8574 SCIP_Bool intscalesuccess;
    8575
    8576 SCIP_CALL( SCIPcalcIntegralScalar(deltacands, nbounddist, -SCIPepsilon(scip), SCIPsumepsilon(scip), (SCIP_Longint)10000, 10000.0, &intscale, &intscalesuccess) );
    8577
    8578 if( intscalesuccess )
    8579 {
    8580 SCIP_Real intf0;
    8581 SCIP_Real intscalerhs;
    8582 SCIP_Real delta;
    8583
    8584 intscalerhs = QUAD_TO_DBL(data->cutrhs) * intscale;
    8585 delta = 1.0 / intscale;
    8586 intf0 = intscalerhs - floor(intscalerhs);
    8587
    8588 if( ! SCIPisFeasIntegral(scip, intf0) )
    8589 {
    8590 if( intf0 < minfrac || intf0 > maxfrac )
    8591 {
    8592 intscale *= SCIPceil(scip, MAX(minfrac, (1.0 - maxfrac)) / MIN(intf0, (1.0 - intf0)));
    8593 intscalerhs = QUAD_TO_DBL(data->cutrhs) * intscale;
    8594 delta = 1.0 / intscale;
    8595 intf0 = intscalerhs - floor(intscalerhs);
    8596 }
    8597
    8598 if( intf0 >= minfrac && intf0 <= maxfrac )
    8599 {
    8600 if( ! SCIPisEQ(scip, delta, 1.0) )
    8601 deltacands[ndeltacands++] = delta;
    8602
    8603 if( intf0 < maxfrac )
    8604 {
    8605 SCIP_Real delta2;
    8606
    8607 delta2 = 1.0 / (intscale * SCIPfloor(scip, maxfrac / intf0));
    8608
    8609 if( ! SCIPisEQ(scip, delta, delta2) && ! SCIPisEQ(scip, delta2, 1.0) )
    8610 deltacands[ndeltacands++] = delta2;
    8611 }
    8612 }
    8613 }
    8614 }
    8615 }
    8616
    8617 for( i = 0; i < nbounddist; ++i )
    8618 {
    8619 SCIP_Real absmksetcoef;
    8620
    8621 absmksetcoef = REALABS(deltacands[i]);
    8622 maxabsmksetcoef = MAX(absmksetcoef, maxabsmksetcoef);
    8623
    8624 deltacands[i] = absmksetcoef;
    8625 }
    8626
    8627 /* also test 1.0 and maxabsmksetcoef + 1.0 as last delta values */
    8628 if( maxabsmksetcoef != -1.0 )
    8629 deltacands[ndeltacands++] = maxabsmksetcoef + 1.0;
    8630
    8631 deltacands[ndeltacands++] = 1.0;
    8632
    8633 maxtestdelta = MIN(ndeltacands, maxtestdelta);
    8634
    8635 /* For each delta
    8636 * Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
    8637 * a~*x' <= down(b)
    8638 * integers : a~_j = down(a'_j) , if f_j <= f_0
    8639 * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
    8640 * continuous: a~_j = 0 , if a'_j >= 0
    8641 * a~_j = a'_j/(1 - f0) , if a'_j < 0
    8642 *
    8643 * Transform inequality back to a^*x <= rhs:
    8644 *
    8645 * (lb or ub):
    8646 * 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
    8647 * 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
    8648 * and move the constant terms
    8649 * -a~_j * lb_j == -a^_j * lb_j, or
    8650 * a~_j * ub_j == -a^_j * ub_j
    8651 * to the rhs.
    8652 *
    8653 * (vlb or vub):
    8654 * 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)
    8655 * 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)
    8656 * move the constant terms
    8657 * -a~_j * dl_j == -a^_j * dl_j, or
    8658 * a~_j * du_j == -a^_j * du_j
    8659 * to the rhs, and update the VB variable coefficients:
    8660 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
    8661 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
    8662 */
    8663
    8664 ntmpcoefs = 0;
    8665 assert(mksetnnz <= nvars);
    8666 for( i = intstart; i < mksetnnz; ++i )
    8667 {
    8668 SCIP_VAR* var;
    8669 SCIP_Real solval;
    8670 SCIP_Real QUAD(coef);
    8671
    8672 var = vars[mksetinds[i]];
    8673
    8674 /* get the soltion value of the continuous variable */
    8675 solval = SCIPgetSolVal(scip, sol, var);
    8676
    8677 /* now compute the solution value in the transform space considering complementation */
    8678 if( boundtype[i] == -1 )
    8679 {
    8680 /* variable was complemented with global (simple) bound */
    8681 if( varsign[i] == -1 )
    8682 solval = SCIPvarGetUbGlobal(var) - solval;
    8683 else
    8684 solval = solval - SCIPvarGetLbGlobal(var);
    8685 }
    8686 else
    8687 {
    8688 assert(boundtype[i] == -2);
    8689
    8690 /* variable was complemented with local (simple) bound */
    8691 if( varsign[i] == -1 )
    8692 solval = SCIPvarGetUbLocal(var) - solval;
    8693 else
    8694 solval = solval - SCIPvarGetLbLocal(var);
    8695 }
    8696
    8697 tmpvalues[ntmpcoefs] = solval;
    8698 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
    8699 tmpcoefs[ntmpcoefs] = varsign[i] * QUAD_TO_DBL(coef);
    8700 ++ntmpcoefs;
    8701 }
    8702
    8703 assert(ntmpcoefs == mksetnnz - intstart);
    8704
    8705 contactivity = 0.0;
    8706 contsqrnorm = 0.0;
    8707 for( i = 0; i < intstart; ++i )
    8708 {
    8709 SCIP_Real solval;
    8710 SCIP_Real QUAD(mksetcoef);
    8711
    8712 QUAD_ARRAY_LOAD(mksetcoef, mksetcoefs, mksetinds[i]);
    8713
    8714 if( varsign[i] * QUAD_TO_DBL(mksetcoef) >= 0.0 )
    8715 continue;
    8716
    8717 /* get the soltion value of the continuous variable */
    8718 solval = SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
    8719
    8720 /* now compute the solution value in the transform space considering complementation */
    8721 switch( boundtype[i] )
    8722 {
    8723 case -1:
    8724 /* variable was complemented with global (simple) bound */
    8725 if( varsign[i] == -1 )
    8726 solval = SCIPvarGetUbGlobal(vars[mksetinds[i]]) - solval;
    8727 else
    8728 solval = solval - SCIPvarGetLbGlobal(vars[mksetinds[i]]);
    8729 break;
    8730 case -2:
    8731 /* variable was complemented with local (simple) bound */
    8732 if( varsign[i] == -1 )
    8733 solval = SCIPvarGetUbLocal(vars[mksetinds[i]]) - solval;
    8734 else
    8735 solval = solval - SCIPvarGetLbLocal(vars[mksetinds[i]]);
    8736 break;
    8737 default:
    8738 /* variable was complemented with a variable bound */
    8739 if( varsign[i] == -1 )
    8740 {
    8741 SCIP_Real coef;
    8742 SCIP_Real constant;
    8743 SCIP_Real vbdsolval;
    8744
    8745 coef = SCIPvarGetVubCoefs(vars[mksetinds[i]])[boundtype[i]];
    8746 constant = SCIPvarGetVubConstants(vars[mksetinds[i]])[boundtype[i]];
    8747 vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVubVars(vars[mksetinds[i]])[boundtype[i]]);
    8748
    8749 solval = (coef * vbdsolval + constant) - solval;
    8750 }
    8751 else
    8752 {
    8753 SCIP_Real coef;
    8754 SCIP_Real constant;
    8755 SCIP_Real vbdsolval;
    8756
    8757 coef = SCIPvarGetVlbCoefs(vars[mksetinds[i]])[boundtype[i]];
    8758 constant = SCIPvarGetVlbConstants(vars[mksetinds[i]])[boundtype[i]];
    8759 vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVlbVars(vars[mksetinds[i]])[boundtype[i]]);
    8760
    8761 solval = solval - (coef * vbdsolval + constant);
    8762 }
    8763 }
    8764
    8765 contactivity += solval * (QUAD_TO_DBL(mksetcoef) * varsign[i]);
    8766 contsqrnorm += QUAD_TO_DBL(mksetcoef) * QUAD_TO_DBL(mksetcoef);
    8767 }
    8768
    8769 {
    8770 SCIP_ROW** rows;
    8771
    8772 rows = SCIPgetLPRows(scip);
    8773 assert(ntmpcoefs <= nvars);
    8774 for( i = 0; i < aggrrow->nrows; ++i )
    8775 {
    8776 SCIP_ROW* row;
    8777 SCIP_Real slackval;
    8778
    8779 row = rows[aggrrow->rowsinds[i]];
    8780
    8781 if( (aggrrow->rowweights[i] * aggrrow->slacksign[i]) >= 0.0 && !row->integral )
    8782 continue;
    8783
    8784 /* compute solution value of slack variable */
    8785 slackval = SCIPgetRowSolActivity(scip, row, sol);
    8786
    8787 if( aggrrow->slacksign[i] == +1 )
    8788 {
    8789 /* right hand side */
    8790 assert(!SCIPisInfinity(scip, row->rhs));
    8791
    8792 slackval = row->rhs - slackval;
    8793 }
    8794 else
    8795 {
    8796 /* left hand side */
    8797 assert(aggrrow->slacksign[i] == -1);
    8798 assert(!SCIPisInfinity(scip, -row->lhs));
    8799
    8800 slackval = slackval - row->lhs;
    8801 }
    8802
    8803 if( row->integral )
    8804 {
    8805 /* if row is integral add variable to tmp arrays */
    8806 tmpvalues[ntmpcoefs] = slackval;
    8807 tmpcoefs[ntmpcoefs] = aggrrow->rowweights[i] * aggrrow->slacksign[i];
    8808 ++ntmpcoefs;
    8809 }
    8810 else
    8811 {
    8812 SCIP_Real slackcoeff = (aggrrow->rowweights[i] * aggrrow->slacksign[i]);
    8813
    8814 /* otherwise add it to continuous activity */
    8815 contactivity += slackval * slackcoeff;
    8816 contsqrnorm += SQR(slackcoeff);
    8817 }
    8818 }
    8819 }
    8820
    8821 /* try all candidates for delta and remember best */
    8822 bestdelta = SCIP_INVALID;
    8823 bestefficacy = -SCIPinfinity(scip);
    8824
    8825 for( i = 0; i < maxtestdelta; ++i )
    8826 {
    8827 int j;
    8828 SCIP_Real efficacy;
    8829
    8830 /* check if we have seen this value of delta before */
    8831 SCIP_Bool deltaseenbefore = FALSE;
    8832 for( j = 0; j < i; ++j )
    8833 {
    8834 if( SCIPisEQ(scip, deltacands[i], deltacands[j]) )
    8835 {
    8836 deltaseenbefore = TRUE;
    8837 break;
    8838 }
    8839 }
    8840
    8841 /* skip this delta value and allow one more delta value if available */
    8842 if( deltaseenbefore )
    8843 {
    8844 maxtestdelta = MIN(maxtestdelta + 1, ndeltacands);
    8845 continue;
    8846 }
    8847
    8848 efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, deltacands[i], ntmpcoefs, minfrac, maxfrac);
    8849
    8850 if( efficacy > bestefficacy )
    8851 {
    8852 bestefficacy = efficacy;
    8853 bestdelta = deltacands[i];
    8854 }
    8855 }
    8856
    8857 /* no delta was found that yielded any cut */
    8858 if( bestdelta == SCIP_INVALID ) /*lint !e777*/
    8859 goto TERMINATE;
    8860
    8861 /* try bestdelta divided by 2, 4 and 8 */
    8862 {
    8863 SCIP_Real basedelta = bestdelta;
    8864 for( i = 2; i <= 8 ; i *= 2 )
    8865 {
    8866 SCIP_Real efficacy;
    8867 SCIP_Real delta;
    8868
    8869 delta = basedelta / i;
    8870
    8871 efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, delta, ntmpcoefs, minfrac, maxfrac);
    8872
    8873 if( efficacy > bestefficacy )
    8874 {
    8875 bestefficacy = efficacy;
    8876 bestdelta = delta;
    8877 }
    8878 }
    8879 }
    8880
    8881 /* try to improve efficacy by switching complementation of integral variables that are not at their bounds
    8882 * in order of non-increasing bound distance
    8883 */
    8884 for( i = 0; i < nbounddist; ++i )
    8885 {
    8886 int k;
    8887 SCIP_Real newefficacy;
    8888 SCIP_Real QUAD(newrhs);
    8889 SCIP_Real QUAD(quadprod);
    8890 SCIP_Real bestlb;
    8891 SCIP_Real bestub;
    8892 SCIP_Real oldsolval;
    8893 int bestlbtype;
    8894 int bestubtype;
    8895
    8896 k = bounddistpos[i];
    8897
    8898 SCIP_CALL( findBestLb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestlb, &bestlbtype) );
    8899
    8900 if( SCIPisInfinity(scip, -bestlb) )
    8901 continue;
    8902
    8903 SCIP_CALL( findBestUb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestub, &bestubtype) );
    8904
    8905 if( SCIPisInfinity(scip, bestub) )
    8906 continue;
    8907
    8908 /* switch the complementation of this variable */
    8909#ifndef NDEBUG
    8910 {
    8911 SCIP_Real QUAD(coef);
    8912 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[k]);
    8913 assert(SCIPisEQ(scip, tmpcoefs[k - intstart], varsign[k] * QUAD_TO_DBL(coef)));
    8914 }
    8915#endif
    8916
    8917 /* compute this: newrhs = mksetrhs + tmpcoefs[k - intstart] * (bestlb - bestub); */
    8918 SCIPquadprecProdDD(quadprod, tmpcoefs[k - intstart], bestlb - bestub);
    8919 SCIPquadprecSumQQ(newrhs, mksetrhs, quadprod);
    8920 tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
    8921
    8922 oldsolval = tmpvalues[k - intstart];
    8923 tmpvalues[k - intstart] = varsign[k] == +1 ? bestub - SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) : SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) - bestlb;
    8924
    8925 /* compute new violation */
    8926 newefficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(newrhs), contactivity, contsqrnorm, bestdelta, ntmpcoefs, minfrac, maxfrac);
    8927
    8928 /* check if violation was increased */
    8929 if( newefficacy > bestefficacy )
    8930 {
    8931 /* keep change of complementation */
    8932 bestefficacy = newefficacy;
    8933 QUAD_ASSIGN_Q(mksetrhs, newrhs);
    8934
    8935 if( varsign[k] == +1 )
    8936 {
    8937 /* switch to upper bound */
    8938 assert(bestubtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
    8939 boundtype[k] = bestubtype;
    8940 varsign[k] = -1;
    8941 }
    8942 else
    8943 {
    8944 /* switch to lower bound */
    8945 assert(bestlbtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
    8946 boundtype[k] = bestlbtype;
    8947 varsign[k] = +1;
    8948 }
    8949
    8950 localbdsused = localbdsused || (boundtype[k] == -2);
    8951 }
    8952 else
    8953 {
    8954 /* undo the change of the complementation */
    8955 tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
    8956 tmpvalues[k - intstart] = oldsolval;
    8957 }
    8958 } /*lint !e438*/
    8959
    8960 if( bestefficacy > 0.0 )
    8961 {
    8962 SCIP_Real mirefficacy;
    8963 SCIP_Real QUAD(downrhs);
    8964 SCIP_Real QUAD(f0);
    8965 SCIP_Real scale;
    8966
    8967 scale = 1.0 / bestdelta;
    8968 SCIPquadprecProdQD(mksetrhs, mksetrhs, scale);
    8969 SCIPquadprecEpsFloorQ(downrhs, mksetrhs, SCIPepsilon(scip)); /*lint !e666*/
    8970 SCIPquadprecSumQQ(f0, mksetrhs, -downrhs);
    8971 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
    8972
    8973 /* renormalize f0 value */
    8974 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
    8975
    8976 /* scale entries by the chosen scale factor */
    8977 for( i = 0; i < mksetnnz; ++i )
    8978 {
    8979 SCIP_Real QUAD(coef);
    8980
    8981 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
    8982 SCIPquadprecProdQD(coef, coef, scale);
    8983 QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], coef);
    8984 }
    8985 SCIPdebugMsg(scip, "applied best scale (=%.13g):\n", scale);
    8986 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
    8987
    8988 QUAD_ASSIGN_Q(mksetrhs, downrhs);
    8989
    8990 QUAD_ASSIGN_Q(data->cutrhs, mksetrhs);
    8991
    8992 SCIP_CALL( cutsRoundMIR(scip, data, varsign, boundtype, QUAD(f0)) );
    8993
    8994 SCIPdebugMsg(scip, "rounded MIR cut:\n");
    8995 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
    8996
    8997 /* substitute aggregated slack variables:
    8998 *
    8999 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    9000 * variable only appears in its own row:
    9001 * a'_r = scale * weight[r] * slacksign[r].
    9002 *
    9003 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    9004 * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
    9005 * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
    9006 * continuous: a^_r = a~_r = 0 , if a'_r >= 0
    9007 * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    9008 *
    9009 * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
    9010 */
    9011 SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
    9012 aggrrow->nrows, scale, mksetcoefs, QUAD(&data->cutrhs), mksetinds, &data->ncutinds, QUAD(f0)) );
    9013
    9014 SCIPdebugMsg(scip, "substituted slacks in MIR cut:\n");
    9015 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
    9016
    9017#ifndef NDEBUG
    9018 {
    9019 SCIP_Real efficacy = -QUAD_TO_DBL(data->cutrhs);
    9020 for( i = 0; i < data->ncutinds; ++i )
    9021 {
    9022 SCIP_Real QUAD(coef);
    9023 QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
    9024 efficacy += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
    9025 }
    9026
    9027 if( !EPSZ(SCIPrelDiff(efficacy, bestefficacy), 1e-4) )
    9028 {
    9029 SCIPdebugMsg(scip, "efficacy of cmir cut is different than expected efficacy: %f != %f\n", efficacy, bestefficacy);
    9030 }
    9031 }
    9032#endif
    9033
    9034 *cutislocal = *cutislocal || localbdsused;
    9035
    9036 /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
    9037 * prevent numerical rounding errors
    9038 */
    9039 if( postprocess )
    9040 {
    9041 SCIP_CALL( postprocessCutQuad(scip, *cutislocal, mksetinds, mksetcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
    9042 }
    9043 else
    9044 {
    9045 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, mksetcoefs, QUAD(&data->cutrhs), mksetinds, &data->ncutinds);
    9046 }
    9047
    9048 SCIPdebugMsg(scip, "post-processed cut (success = %s):\n", *success ? "TRUE" : "FALSE");
    9049 SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(data->cutrhs), mksetinds, data->ncutinds, FALSE, FALSE));
    9050
    9051 if( *success )
    9052 {
    9053 mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, mksetcoefs, QUAD_TO_DBL(data->cutrhs), mksetinds, data->ncutinds);
    9054
    9055 if( SCIPisEfficacious(scip, mirefficacy) && SCIPisGT(scip, mirefficacy, *cutefficacy) )
    9056 {
    9057 BMScopyMemoryArray(cutinds, mksetinds, data->ncutinds);
    9058 for( i = 0; i < data->ncutinds; ++i )
    9059 {
    9060 SCIP_Real QUAD(coef);
    9061 int j = cutinds[i];
    9062
    9063 QUAD_ARRAY_LOAD(coef, mksetcoefs, j);
    9064
    9065 cutcoefs[i] = QUAD_TO_DBL(coef);
    9066 QUAD_ASSIGN(coef, 0.0);
    9067 QUAD_ARRAY_STORE(mksetcoefs, j, coef);
    9068 }
    9069 *cutnnz = data->ncutinds;
    9070 *cutrhs = QUAD_TO_DBL(data->cutrhs);
    9071 *cutefficacy = mirefficacy;
    9072 if( cutrank != NULL )
    9073 *cutrank = aggrrow->rank + 1;
    9074 *cutislocal = *cutislocal || localbdsused;
    9075 }
    9076 else
    9077 *success = FALSE;
    9078 }
    9079 }
    9080
    9081 TERMINATE:
    9082 /* if we aborted early we need to clean the mksetcoefs */
    9083 if( !(*success) )
    9084 {
    9085 SCIP_Real QUAD(tmp);
    9086 QUAD_ASSIGN(tmp, 0.0);
    9087
    9088 for( i = 0; i < data->ncutinds; ++i )
    9089 {
    9090 QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], tmp);
    9091 }
    9092 }
    9093
    9094#ifndef NDEBUG
    9095 for( i = 0; i < QUAD_ARRAY_SIZE(nvars); ++i )
    9096 {
    9097 if(mksetcoefs[i] != 0.0)
    9098 {
    9099 SCIPdebugMsg(scip, "mksetcoefs have not been reset\n");
    9100 SCIPABORT();
    9101 }
    9102 }
    9103#endif
    9104
    9105 if( data->cutinds != NULL )
    9107
    9108 if( data->cutcoefs != NULL )
    9110
    9111 for( int s = NSECTIONS - 1; s >= 0; --s )
    9112 {
    9114 }
    9115
    9116 SCIPfreeBuffer(scip, &data);
    9117 /* free temporary memory */
    9118 SCIPfreeBufferArray(scip, &bounddistpos);
    9119 SCIPfreeBufferArray(scip, &bounddist);
    9120 SCIPfreeBufferArray(scip, &deltacands);
    9121 SCIPfreeBufferArray(scip, &tmpvalues);
    9122 SCIPfreeBufferArray(scip, &tmpcoefs);
    9123 SCIPfreeBufferArray(scip, &boundtype);
    9124 SCIPfreeBufferArray(scip, &varsign);
    9125
    9126 return SCIP_OKAY;
    9127}
    9128
    9129/* =========================================== flow cover =========================================== */
    9130
    9131#define NO_EXACT_KNAPSACK
    9132
    9133#ifndef NO_EXACT_KNAPSACK
    9134#define MAXDNOM 1000LL
    9135#define MINDELTA 1e-03
    9136#define MAXDELTA 1e-09
    9137#define MAXSCALE 1000.0
    9138#define MAXDYNPROGSPACE 1000000
    9139#endif
    9140
    9141#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for snf relaxation */
    9142#define MAXBOUND 1e+10 /**< maximal value of normal bounds used for snf relaxation */
    9143
    9144/** structure that contains all data required to perform the sequence independent lifting
    9145 */
    9146typedef
    9147struct LiftingData
    9148{
    9149 SCIP_Real* M; /**< \f$ M_0 := 0.0 \f$ and \f$ M_i := M_i-1 + m_i \f$ */
    9150 SCIP_Real* m; /**< non-increasing array of variable upper bound coefficients
    9151 * for all variables in \f$ C^{++} \f$ and \f$ L^- \f$,
    9152 * where \f$ C = C^+ \cup C^- \f$ is the flowcover and
    9153 * \f$ C^{++} := \{ j \in C^+ \mid u_j > \lambda \} \f$
    9154 * \f$ L^- := \{ j \in (N^- \setminus C^-) \mid u_j > \lambda \} \f$
    9155 */
    9156 int r; /**< size of array m */
    9157 int t; /**< index of smallest value in m that comes from a variable in \f$ C^{++} \f$ */
    9158 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$ */
    9159 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$ */
    9160 SCIP_Real lambda; /**< excess of the flowcover */
    9161 SCIP_Real mp; /**< smallest variable bound coefficient of variable in \f$ C^{++} (min_{j \in C++} u_j) \f$ */
    9162 SCIP_Real ml; /**< \f$ ml := min(\lambda, \sum_{j \in C^+ \setminus C^{++}} u_j) \f$ */
    9164
    9165/** structure that contains all the data that defines the single-node-flow relaxation of an aggregation row */
    9166typedef
    9167struct SNF_Relaxation
    9168{
    9169 int* transvarcoefs; /**< coefficients of all vars in relaxed set */
    9170 SCIP_Real* transbinvarsolvals; /**< sol val of bin var in vub of all vars in relaxed set */
    9171 SCIP_Real* transcontvarsolvals;/**< sol val of all real vars in relaxed set */
    9172 SCIP_Real* transvarvubcoefs; /**< coefficient in vub of all vars in relaxed set */
    9173 int ntransvars; /**< number of vars in relaxed set */
    9174 SCIP_Real transrhs; /**< rhs in relaxed set */
    9175 int* origbinvars; /**< associated original binary var for all vars in relaxed set */
    9176 int* origcontvars; /**< associated original continuous var for all vars in relaxed set */
    9177 SCIP_Real* aggrcoefsbin; /**< aggregation coefficient of the original binary var used to define the
    9178 * continuous variable in the relaxed set */
    9179 SCIP_Real* aggrcoefscont; /**< aggregation coefficient of the original continuous var used to define the
    9180 * continuous variable in the relaxed set */
    9181 SCIP_Real* aggrconstants; /**< aggregation constant used to define the continuous variable in the relaxed set */
    9183
    9184/** get solution value and index of variable lower bound (with binary variable) which is closest to the current LP
    9185 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
    9186 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
    9187 * given variable
    9188 */
    9189static
    9191 SCIP* scip, /**< SCIP data structure */
    9192 SCIP_VAR* var, /**< given active problem variable */
    9193 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
    9194 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
    9195 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
    9196 * was not used (0) or was not used but is contained in the row (-1) */
    9197 SCIP_Real bestsub, /**< closest simple upper bound of given variable */
    9198 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
    9199 SCIP_Real* closestvlb, /**< pointer to store the LP sol value of the closest variable lower bound */
    9200 int* closestvlbidx /**< pointer to store the index of the closest vlb; -1 if no vlb was found */
    9201 )
    9202{
    9203 int nvlbs;
    9204 int nbinvars;
    9205
    9206 assert(scip != NULL);
    9207 assert(var != NULL);
    9208 assert(bestsub == SCIPvarGetUbGlobal(var) || bestsub == SCIPvarGetUbLocal(var)); /*lint !e777*/
    9209 assert(!SCIPisInfinity(scip, bestsub));
    9210 assert(!EPSZ(rowcoef, QUAD_EPSILON));
    9211 assert(rowcoefs != NULL);
    9212 assert(binvarused != NULL);
    9213 assert(closestvlb != NULL);
    9214 assert(closestvlbidx != NULL);
    9215
    9216 nvlbs = SCIPvarGetNVlbs(var);
    9217 nbinvars = SCIPgetNBinVars(scip);
    9218
    9219 *closestvlbidx = -1;
    9220 *closestvlb = -SCIPinfinity(scip);
    9221 if( nvlbs > 0 )
    9222 {
    9223 SCIP_VAR** vlbvars;
    9224 SCIP_Real* vlbcoefs;
    9225 SCIP_Real* vlbconsts;
    9226 int i;
    9227
    9228 vlbvars = SCIPvarGetVlbVars(var);
    9229 vlbcoefs = SCIPvarGetVlbCoefs(var);
    9230 vlbconsts = SCIPvarGetVlbConstants(var);
    9231
    9232 for( i = 0; i < nvlbs; i++ )
    9233 {
    9234 SCIP_Real rowcoefbinvar;
    9235 SCIP_Real val1;
    9236 SCIP_Real val2;
    9237 SCIP_Real vlbsol;
    9238 SCIP_Real rowcoefsign;
    9239 int probidxbinvar;
    9240
    9241 if( bestsub > vlbconsts[i] )
    9242 continue;
    9243
    9244 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
    9245 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
    9246 */
    9247 if( REALABS(vlbcoefs[i]) > MAXABSVBCOEF )
    9248 continue;
    9249
    9250 /* use only variable lower bounds l~_i * x_i + d_i with x_i binary which are active */
    9251 probidxbinvar = SCIPvarGetProbindex(vlbvars[i]);
    9252
    9253 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
    9254 * ensures that the problem index is between 0 and nbinvars - 1
    9255 */
    9256 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
    9257 continue;
    9258
    9259 assert(SCIPvarIsBinary(vlbvars[i]));
    9260
    9261 /* check if current variable lower bound l~_i * x_i + d_i imposed on y_j meets the following criteria:
    9262 * (let a_j = coefficient of y_j in current row,
    9263 * u_j = closest simple upper bound imposed on y_j,
    9264 * c_i = coefficient of x_i in current row)
    9265 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k yet
    9266 * if a_j > 0:
    9267 * 1. u_j <= d_i
    9268 * 2. a_j ( u_j - d_i ) + c_i <= 0
    9269 * 3. a_j l~_i + c_i <= 0
    9270 * if a_j < 0:
    9271 * 1. u_j <= d_i
    9272 * 2. a_j ( u_j - d_i ) + c_i >= 0
    9273 * 3. a_j l~_i + c_i >= 0
    9274 */
    9275
    9276 /* has already been used in the SNF relaxation */
    9277 if( binvarused[probidxbinvar] == 1 )
    9278 continue;
    9279
    9280 /* get the row coefficient */
    9281 {
    9282 SCIP_Real QUAD(tmp);
    9283 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
    9284 rowcoefbinvar = QUAD_TO_DBL(tmp);
    9285 }
    9286 rowcoefsign = COPYSIGN(1.0, rowcoef);
    9287
    9288 val2 = rowcoefsign * ((rowcoef * vlbcoefs[i]) + rowcoefbinvar);
    9289
    9290 /* variable lower bound does not meet criteria */
    9291 if( val2 > 0.0 || SCIPisInfinity(scip, -val2) )
    9292 continue;
    9293
    9294 val1 = rowcoefsign * ((rowcoef * (bestsub - vlbconsts[i])) + rowcoefbinvar);
    9295
    9296 /* variable lower bound does not meet criteria */
    9297 if( val1 > 0.0 )
    9298 continue;
    9299
    9300 vlbsol = vlbcoefs[i] * SCIPgetSolVal(scip, sol, vlbvars[i]) + vlbconsts[i];
    9301 if( vlbsol > *closestvlb )
    9302 {
    9303 *closestvlb = vlbsol;
    9304 *closestvlbidx = i;
    9305 }
    9306 assert(*closestvlbidx >= 0);
    9307 }
    9308 }
    9309
    9310 return SCIP_OKAY;
    9311}
    9312
    9313/** get LP solution value and index of variable upper bound (with binary variable) which is closest to the current LP
    9314 * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
    9315 * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
    9316 * given variable
    9317 */
    9318static
    9320 SCIP* scip, /**< SCIP data structure */
    9321 SCIP_VAR* var, /**< given active problem variable */
    9322 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
    9323 SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
    9324 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
    9325 * was not used (0) or was not used but is contained in the row (-1)
    9326 */
    9327 SCIP_Real bestslb, /**< closest simple lower bound of given variable */
    9328 SCIP_Real rowcoef, /**< coefficient of given variable in current row */
    9329 SCIP_Real* closestvub, /**< pointer to store the LP sol value of the closest variable upper bound */
    9330 int* closestvubidx /**< pointer to store the index of the closest vub; -1 if no vub was found */
    9331 )
    9332{
    9333 int nvubs;
    9334 int nbinvars;
    9335
    9336 assert(scip != NULL);
    9337 assert(var != NULL);
    9338 assert(bestslb == SCIPvarGetLbGlobal(var) || bestslb == SCIPvarGetLbLocal(var)); /*lint !e777*/
    9339 assert(!SCIPisInfinity(scip, - bestslb));
    9340 assert(!EPSZ(rowcoef, QUAD_EPSILON));
    9341 assert(rowcoefs != NULL);
    9342 assert(binvarused != NULL);
    9343 assert(closestvub != NULL);
    9344 assert(closestvubidx != NULL);
    9345
    9346 nvubs = SCIPvarGetNVubs(var);
    9347 nbinvars = SCIPgetNBinVars(scip);
    9348
    9349 *closestvubidx = -1;
    9350 *closestvub = SCIPinfinity(scip);
    9351 if( nvubs > 0 )
    9352 {
    9353 SCIP_VAR** vubvars;
    9354 SCIP_Real* vubcoefs;
    9355 SCIP_Real* vubconsts;
    9356 int i;
    9357
    9358 vubvars = SCIPvarGetVubVars(var);
    9359 vubcoefs = SCIPvarGetVubCoefs(var);
    9360 vubconsts = SCIPvarGetVubConstants(var);
    9361
    9362 for( i = 0; i < nvubs; i++ )
    9363 {
    9364 SCIP_Real rowcoefbinvar;
    9365 SCIP_Real val1;
    9366 SCIP_Real val2;
    9367 SCIP_Real vubsol;
    9368 SCIP_Real rowcoefsign;
    9369 int probidxbinvar;
    9370
    9371 if( bestslb < vubconsts[i] )
    9372 continue;
    9373
    9374 /* for numerical reasons, ignore variable bounds with large absolute coefficient and
    9375 * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
    9376 */
    9377 if( REALABS(vubcoefs[i]) > MAXABSVBCOEF )
    9378 continue;
    9379
    9380 /* use only variable upper bound u~_i * x_i + d_i with x_i binary and which are active */
    9381 probidxbinvar = SCIPvarGetProbindex(vubvars[i]);
    9382
    9383 /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
    9384 * ensures that the problem index is between 0 and nbinvars - 1
    9385 */
    9386 if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
    9387 continue;
    9388
    9389 assert(SCIPvarIsBinary(vubvars[i]));
    9390
    9391 /* checks if current variable upper bound u~_i * x_i + d_i meets the following criteria
    9392 * (let a_j = coefficient of y_j in current row,
    9393 * l_j = closest simple lower bound imposed on y_j,
    9394 * c_i = coefficient of x_i in current row)
    9395 * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k
    9396 * if a > 0:
    9397 * 1. l_j >= d_i
    9398 * 2. a_j ( l_i - d_i ) + c_i >= 0
    9399 * 3. a_j u~_i + c_i >= 0
    9400 * if a < 0:
    9401 * 1. l_j >= d_i
    9402 * 2. a_j ( l_j - d_i ) + c_i <= 0
    9403 * 3. a_j u~_i + c_i <= 0
    9404 */
    9405
    9406 /* has already been used in the SNF relaxation */
    9407 if( binvarused[probidxbinvar] == 1 )
    9408 continue;
    9409
    9410 /* get the row coefficient */
    9411 {
    9412 SCIP_Real QUAD(tmp);
    9413 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
    9414 rowcoefbinvar = QUAD_TO_DBL(tmp);
    9415 }
    9416 rowcoefsign = COPYSIGN(1.0, rowcoef);
    9417
    9418 val2 = rowcoefsign * ((rowcoef * vubcoefs[i]) + rowcoefbinvar);
    9419
    9420 /* variable upper bound does not meet criteria */
    9421 if( val2 < 0.0 || SCIPisInfinity(scip, val2) )
    9422 continue;
    9423
    9424 val1 = rowcoefsign * ((rowcoef * (bestslb - vubconsts[i])) + rowcoefbinvar);
    9425
    9426 /* variable upper bound does not meet criteria */
    9427 if( val1 < 0.0 )
    9428 continue;
    9429
    9430 vubsol = vubcoefs[i] * SCIPgetSolVal(scip, sol, vubvars[i]) + vubconsts[i];
    9431 if( vubsol < *closestvub )
    9432 {
    9433 *closestvub = vubsol;
    9434 *closestvubidx = i;
    9435 }
    9436 assert(*closestvubidx >= 0);
    9437 }
    9438 }
    9439
    9440 return SCIP_OKAY;
    9441}
    9442
    9443/** determines the bounds to use for constructing the single-node-flow relaxation of a variable in
    9444 * the given row.
    9445 */
    9446static
    9448 SCIP* scip, /**< SCIP data structure */
    9449 SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
    9450 SCIP_VAR** vars, /**< array of problem variables */
    9451 SCIP_Real* rowcoefs, /**< (dense) array of variable coefficients in the row */
    9452 int* rowinds, /**< array with positions of non-zero values in the rowcoefs array */
    9453 int varposinrow, /**< position of variable in the rowinds array for which the bounds should be determined */
    9454 int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
    9455 * was not used (0) or was not used but is contained in the row (-1)
    9456 */
    9457 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    9458 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    9459 SCIP_Real* bestlb, /**< pointer to store best lower bound for transformation */
    9460 SCIP_Real* bestub, /**< pointer to store best upper bound for transformation */
    9461 SCIP_Real* bestslb, /**< pointer to store best simple lower bound for transformation */
    9462 SCIP_Real* bestsub, /**< pointer to store best simple upper bound for transformation */
    9463 int* bestlbtype, /**< pointer to store type of best lower bound (-2: local bound, -1: global bound, >= 0 variable bound index) */
    9464 int* bestubtype, /**< pointer to store type of best upper bound (-2: local bound, -1: global bound, >= 0 variable bound index) */
    9465 int* bestslbtype, /**< pointer to store type of best simple lower bound */
    9466 int* bestsubtype, /**< pointer to store type of best simple upper bound */
    9467 SCIP_BOUNDTYPE* selectedbounds, /**< pointer to store the preferred bound for the transformation */
    9468 SCIP_Bool* freevariable /**< pointer to store if variable is a free variable */
    9469 )
    9470{
    9471 SCIP_VAR* var;
    9472
    9473 SCIP_Real rowcoef;
    9474 SCIP_Real solval;
    9475
    9476 int probidx;
    9477
    9478 bestlb[varposinrow] = -SCIPinfinity(scip);
    9479 bestub[varposinrow] = SCIPinfinity(scip);
    9480 bestlbtype[varposinrow] = -3;
    9481 bestubtype[varposinrow] = -3;
    9482
    9483 probidx = rowinds[varposinrow];
    9484 var = vars[probidx];
    9485 {
    9486 SCIP_Real QUAD(tmp);
    9487 QUAD_ARRAY_LOAD(tmp, rowcoefs, probidx);
    9488 rowcoef = QUAD_TO_DBL(tmp);
    9489 }
    9490
    9491 assert(!EPSZ(rowcoef, QUAD_EPSILON));
    9492
    9493 /* get closest simple lower bound and closest simple upper bound */
    9494 SCIP_CALL( findBestLb(scip, var, sol, 0, allowlocal, &bestslb[varposinrow], &bestslbtype[varposinrow]) );
    9495 SCIP_CALL( findBestUb(scip, var, sol, 0, allowlocal, &bestsub[varposinrow], &bestsubtype[varposinrow]) );
    9496
    9497 /* do not use too large bounds */
    9498 if( bestslb[varposinrow] <= -MAXBOUND )
    9499 bestslb[varposinrow] = -SCIPinfinity(scip);
    9500
    9501 if( bestsub[varposinrow] >= MAXBOUND )
    9502 bestsub[varposinrow] = SCIPinfinity(scip);
    9503
    9504 solval = SCIPgetSolVal(scip, sol, var);
    9505
    9506 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g(%d),%g(%d)]>:\n", varposinrow, rowcoef, SCIPvarGetName(var), probidx,
    9507 solval, bestslb[varposinrow], bestslbtype[varposinrow], bestsub[varposinrow], bestsubtype[varposinrow]);
    9508
    9509 /* mixed integer set cannot be relaxed to 0-1 single node flow set because both simple bounds are -infinity
    9510 * and infinity, respectively
    9511 */
    9512 if( SCIPisInfinity(scip, -bestslb[varposinrow]) && SCIPisInfinity(scip, bestsub[varposinrow]) )
    9513 {
    9514 *freevariable = TRUE;
    9515 return SCIP_OKAY;
    9516 }
    9517
    9518 /* get closest lower bound that can be used to define the real variable y'_j in the 0-1 single node flow
    9519 * relaxation
    9520 */
    9521 if( !SCIPisInfinity(scip, bestsub[varposinrow]) )
    9522 {
    9523 bestlb[varposinrow] = bestslb[varposinrow];
    9524 bestlbtype[varposinrow] = bestslbtype[varposinrow];
    9525
    9527 {
    9528 SCIP_Real bestvlb;
    9529 int bestvlbidx;
    9530
    9531 SCIP_CALL( getClosestVlb(scip, var, sol, rowcoefs, binvarused, bestsub[varposinrow], rowcoef, &bestvlb, &bestvlbidx) );
    9532 if( SCIPisGT(scip, bestvlb, bestlb[varposinrow]) )
    9533 {
    9534 bestlb[varposinrow] = bestvlb;
    9535 bestlbtype[varposinrow] = bestvlbidx;
    9536 }
    9537 }
    9538 }
    9539
    9540 /* get closest upper bound that can be used to define the real variable y'_j in the 0-1 single node flow
    9541 * relaxation
    9542 */
    9543 if( !SCIPisInfinity(scip, -bestslb[varposinrow]) )
    9544 {
    9545 bestub[varposinrow] = bestsub[varposinrow];
    9546 bestubtype[varposinrow] = bestsubtype[varposinrow];
    9547
    9549 {
    9550 SCIP_Real bestvub;
    9551 int bestvubidx;
    9552
    9553 SCIP_CALL( getClosestVub(scip, var, sol, rowcoefs, binvarused, bestslb[varposinrow], rowcoef, &bestvub, &bestvubidx) );
    9554 if( SCIPisLT(scip, bestvub, bestub[varposinrow]) )
    9555 {
    9556 bestub[varposinrow] = bestvub;
    9557 bestubtype[varposinrow] = bestvubidx;
    9558 }
    9559 }
    9560 }
    9561 SCIPdebugMsg(scip, " bestlb=%g(%d), bestub=%g(%d)\n", bestlb[varposinrow], bestlbtype[varposinrow], bestub[varposinrow], bestubtype[varposinrow]);
    9562
    9563 /* mixed integer set cannot be relaxed to 0-1 single node flow set because there are no suitable bounds
    9564 * to define the transformed variable y'_j
    9565 */
    9566 if( SCIPisInfinity(scip, -bestlb[varposinrow]) && SCIPisInfinity(scip, bestub[varposinrow]) )
    9567 {
    9568 *freevariable = TRUE;
    9569 return SCIP_OKAY;
    9570 }
    9571
    9572 *freevariable = FALSE;
    9573
    9574 /* select best upper bound if it is closer to the LP value of y_j and best lower bound otherwise and use this bound
    9575 * to define the real variable y'_j with 0 <= y'_j <= u'_j x_j in the 0-1 single node flow relaxation;
    9576 * prefer variable bounds
    9577 */
    9578 if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) && bestlbtype[varposinrow] >= 0 )
    9579 {
    9580 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
    9581 }
    9582 else if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow])
    9583 && bestubtype[varposinrow] >= 0 )
    9584 {
    9585 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
    9586 }
    9587 else if( SCIPisLE(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) )
    9588 {
    9589 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
    9590 }
    9591 else
    9592 {
    9593 assert(SCIPisGT(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]));
    9594 selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
    9595 }
    9596
    9597 if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_LOWER && bestlbtype[varposinrow] >= 0 )
    9598 {
    9599 int vlbvarprobidx;
    9600 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
    9601
    9602 /* mark binary variable of vlb so that it is not used for other continuous variables
    9603 * by setting it's position in the aggrrow to a negative value
    9604 */
    9605 vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[varposinrow]]);
    9606 binvarused[vlbvarprobidx] = 1;
    9607 }
    9608 else if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_UPPER && bestubtype[varposinrow] >= 0 )
    9609 {
    9610 int vubvarprobidx;
    9611 SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
    9612
    9613 /* mark binary variable of vub 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 vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[varposinrow]]);
    9617 binvarused[vubvarprobidx] = 1;
    9618 }
    9619
    9620 return SCIP_OKAY; /*lint !e438*/
    9621}
    9622
    9623/** construct a 0-1 single node flow relaxation (with some additional simple constraints) of a mixed integer set
    9624 * corresponding to the given aggrrow a * x <= rhs
    9625 */
    9626static
    9628 SCIP* scip, /**< SCIP data structure */
    9629 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    9630 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    9631 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    9632 SCIP_Real* rowcoefs, /**< array of coefficients of row */
    9633 QUAD(SCIP_Real rowrhs), /**< pointer to right hand side of row */
    9634 int* rowinds, /**< array of variables problem indices for non-zero coefficients in row */
    9635 int nnz, /**< number of non-zeros in row */
    9636 SNF_RELAXATION* snf, /**< stores the sign of the transformed variable in summation */
    9637 SCIP_Bool* success, /**< stores whether the transformation was valid */
    9638 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
    9639 )
    9640{
    9641 SCIP_VAR** vars;
    9642 int i;
    9643 int nnonbinvarsrow;
    9644 int8_t* binvarused;
    9645 int nbinvars;
    9646 SCIP_Real QUAD(transrhs);
    9647
    9648 /* arrays to store the selected bound for each non-binary variable in the row */
    9649 SCIP_Real* bestlb;
    9650 SCIP_Real* bestub;
    9651 SCIP_Real* bestslb;
    9652 SCIP_Real* bestsub;
    9653 int* bestlbtype;
    9654 int* bestubtype;
    9655 int* bestslbtype;
    9656 int* bestsubtype;
    9657 SCIP_BOUNDTYPE* selectedbounds;
    9658
    9659 *success = FALSE;
    9660
    9661 SCIPdebugMsg(scip, "--------------------- construction of SNF relaxation ------------------------------------\n");
    9662
    9663 nbinvars = SCIPgetNBinVars(scip);
    9664 vars = SCIPgetVars(scip);
    9665
    9666 SCIP_CALL( SCIPallocBufferArray(scip, &bestlb, nnz) );
    9667 SCIP_CALL( SCIPallocBufferArray(scip, &bestub, nnz) );
    9668 SCIP_CALL( SCIPallocBufferArray(scip, &bestslb, nnz) );
    9669 SCIP_CALL( SCIPallocBufferArray(scip, &bestsub, nnz) );
    9670 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtype, nnz) );
    9671 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtype, nnz) );
    9672 SCIP_CALL( SCIPallocBufferArray(scip, &bestslbtype, nnz) );
    9673 SCIP_CALL( SCIPallocBufferArray(scip, &bestsubtype, nnz) );
    9674 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, nnz) );
    9675
    9676 /* sort descending to have continuous variables first */
    9677 SCIPsortDownInt(rowinds, nnz);
    9678
    9679 /* array to store whether a binary variable is in the row (-1) or has been used (1) due to variable bound usage */
    9680 SCIP_CALL( SCIPallocCleanBufferArray(scip, &binvarused, nbinvars) );
    9681
    9682 for( i = nnz - 1; i >= 0 && rowinds[i] < nbinvars; --i )
    9683 binvarused[rowinds[i]] = -1;
    9684
    9685 nnonbinvarsrow = i + 1;
    9686 /* determine the bounds to use for transforming the non-binary variables */
    9687 for( i = 0; i < nnonbinvarsrow; ++i )
    9688 {
    9689 SCIP_Bool freevariable;
    9690
    9691 assert(rowinds[i] >= nbinvars);
    9692
    9693 SCIP_CALL( determineBoundForSNF(scip, sol, vars, rowcoefs, rowinds, i, binvarused, allowlocal, boundswitch,
    9694 bestlb, bestub, bestslb, bestsub, bestlbtype, bestubtype, bestslbtype, bestsubtype, selectedbounds, &freevariable) );
    9695
    9696 if( freevariable )
    9697 {
    9698 int j;
    9699
    9700 /* clear binvarused at indices of binary variables of row */
    9701 for( j = nnz - 1; j >= nnonbinvarsrow; --j )
    9702 binvarused[rowinds[j]] = 0;
    9703
    9704 /* clear binvarused at indices of selected variable bounds */
    9705 for( j = 0; j < i; ++j )
    9706 {
    9707 if( selectedbounds[j] == SCIP_BOUNDTYPE_LOWER && bestlbtype[j] >= 0 )
    9708 {
    9709 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(vars[rowinds[j]]);
    9710 binvarused[SCIPvarGetProbindex(vlbvars[bestlbtype[j]])] = 0;
    9711 }
    9712 else if( selectedbounds[j] == SCIP_BOUNDTYPE_UPPER && bestubtype[j] >= 0 )
    9713 {
    9714 SCIP_VAR** vubvars = SCIPvarGetVubVars(vars[rowinds[j]]);
    9715 binvarused[SCIPvarGetProbindex(vubvars[bestubtype[j]])] = 0;
    9716 }
    9717 }
    9718
    9719 /* terminate */
    9720 goto TERMINATE;
    9721 }
    9722 }
    9723
    9724 *localbdsused = FALSE;
    9725 QUAD_ASSIGN_Q(transrhs, rowrhs);
    9726 snf->ntransvars = 0;
    9727
    9728 assert(snf->transvarcoefs != NULL); /* for lint */
    9729 assert(snf->transvarvubcoefs != NULL);
    9730 assert(snf->transbinvarsolvals != NULL);
    9731 assert(snf->transcontvarsolvals != NULL);
    9732 assert(snf->aggrconstants != NULL);
    9733 assert(snf->aggrcoefscont != NULL);
    9734 assert(snf->origcontvars != NULL);
    9735 assert(snf->origbinvars != NULL);
    9736 assert(snf->aggrcoefsbin != NULL);
    9737
    9738 /* transform non-binary variables */
    9739 for( i = 0; i < nnonbinvarsrow; ++i )
    9740 {
    9741 SCIP_VAR* var;
    9742 SCIP_Real QUAD(rowcoef);
    9743 SCIP_Real solval;
    9744 int probidx;
    9745
    9746 probidx = rowinds[i];
    9747 var = vars[probidx];
    9748 QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
    9749 assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
    9750 solval = SCIPgetSolVal(scip, sol, var);
    9751
    9752 assert(probidx >= nbinvars);
    9753
    9754 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
    9755 {
    9756 /* use bestlb to define y'_j */
    9757
    9758 assert(!SCIPisInfinity(scip, bestsub[i]));
    9759 assert(!SCIPisInfinity(scip, - bestlb[i]));
    9760 assert(bestsubtype[i] == -1 || bestsubtype[i] == -2);
    9761 assert(bestlbtype[i] > -3 && bestlbtype[i] < SCIPvarGetNVlbs(var));
    9762
    9763 /* store for y_j that bestlb is the bound used to define y'_j and that y'_j is the associated real variable
    9764 * in the relaxed set
    9765 */
    9766 snf->origcontvars[snf->ntransvars] = probidx;
    9767
    9768 if( bestlbtype[i] < 0 )
    9769 {
    9770 SCIP_Real QUAD(val);
    9771 SCIP_Real QUAD(contsolval);
    9772 SCIP_Real QUAD(rowcoeftimesbestsub);
    9773
    9774 /* use simple lower bound in bestlb = l_j <= y_j <= u_j = bestsub to define
    9775 * 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
    9776 * 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,
    9777 * put j into the set
    9778 * N2 if a_j > 0
    9779 * N1 if a_j < 0
    9780 * and update the right hand side of the constraint in the relaxation
    9781 * rhs = rhs - a_j u_j
    9782 */
    9783 SCIPquadprecSumDD(val, bestsub[i], -bestlb[i]);
    9784 SCIPquadprecProdQQ(val, val, rowcoef);
    9785 SCIPquadprecSumDD(contsolval, solval, -bestsub[i]);
    9786 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
    9787
    9788 if( bestlbtype[i] == -2 || bestsubtype[i] == -2 )
    9789 *localbdsused = TRUE;
    9790
    9791 SCIPquadprecProdQD(rowcoeftimesbestsub, rowcoef, bestsub[i]);
    9792
    9793 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
    9794 snf->origbinvars[snf->ntransvars] = -1;
    9795 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
    9796
    9797 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
    9798 {
    9799 snf->transvarcoefs[snf->ntransvars] = - 1;
    9800 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
    9801 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
    9802 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
    9803
    9804 /* aggregation information for y'_j */
    9805 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestsub);
    9806 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
    9807 }
    9808 else
    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 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestsub);
    9820
    9821 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
    9822 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
    9823 snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestsub), QUAD_TO_DBL(rowcoef), bestsub[i], QUAD_TO_DBL(transrhs));
    9824 }
    9825 else
    9826 {
    9827 SCIP_Real QUAD(rowcoefbinary);
    9828 SCIP_Real varsolvalbinary;
    9829 SCIP_Real QUAD(val);
    9830 SCIP_Real QUAD(contsolval);
    9831 SCIP_Real QUAD(rowcoeftimesvlbconst);
    9832 int vlbvarprobidx;
    9833
    9834 SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
    9835 SCIP_Real* vlbconsts = SCIPvarGetVlbConstants(var);
    9836 SCIP_Real* vlbcoefs = SCIPvarGetVlbCoefs(var);
    9837
    9838 /* use variable lower bound in bestlb = l~_j x_j + d_j <= y_j <= u_j = bestsub to define
    9839 * 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
    9840 * 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,
    9841 * where c_j is the coefficient of x_j in the row, put j into the set
    9842 * N2 if a_j > 0
    9843 * N1 if a_j < 0
    9844 * and update the right hand side of the constraint in the relaxation
    9845 * rhs = rhs - a_j d_j
    9846 */
    9847
    9848 vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[i]]);
    9849 assert(binvarused[vlbvarprobidx] == 1);
    9850 assert(vlbvarprobidx < nbinvars);
    9851
    9852 QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vlbvarprobidx);
    9853 varsolvalbinary = SCIPgetSolVal(scip, sol, vlbvars[bestlbtype[i]]);
    9854
    9855 SCIPquadprecProdQD(val, rowcoef, vlbcoefs[bestlbtype[i]]);
    9856 SCIPquadprecSumQQ(val, val, rowcoefbinary);
    9857 {
    9858 SCIP_Real QUAD(tmp);
    9859
    9860 SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
    9861 SCIPquadprecSumDD(contsolval, solval, - vlbconsts[bestlbtype[i]]);
    9862 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
    9863 SCIPquadprecSumQQ(contsolval, contsolval, tmp);
    9864 }
    9865
    9866 SCIPquadprecProdQD(rowcoeftimesvlbconst, rowcoef, vlbconsts[bestlbtype[i]]);
    9867
    9868 /* clear the binvarpos array, since the variable has been processed */
    9869 binvarused[vlbvarprobidx] = 0;
    9870
    9871 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
    9872 snf->origbinvars[snf->ntransvars] = vlbvarprobidx;
    9873
    9874 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
    9875 {
    9876 snf->transvarcoefs[snf->ntransvars] = - 1;
    9877 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
    9878 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
    9879 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
    9880
    9881 /* aggregation information for y'_j */
    9882 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
    9883 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
    9884 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvlbconst);
    9885 }
    9886 else
    9887 {
    9888 snf->transvarcoefs[snf->ntransvars] = 1;
    9889 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
    9890 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
    9891 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
    9892
    9893 /* aggregation information for y'_j */
    9894 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
    9895 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
    9896 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvlbconst);
    9897 }
    9898 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvlbconst);
    9899
    9900 SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
    9901 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
    9902 snf->ntransvars, SCIPvarGetName(vlbvars[bestlbtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvlbconst), QUAD_TO_DBL(rowcoef),
    9903 vlbconsts[bestlbtype[i]], QUAD_TO_DBL(transrhs) );
    9904 }
    9905 }
    9906 else
    9907 {
    9908 /* use bestub to define y'_j */
    9909
    9910 assert(!SCIPisInfinity(scip, bestub[i]));
    9911 assert(!SCIPisInfinity(scip, - bestslb[i]));
    9912 assert(bestslbtype[i] == -1 || bestslbtype[i] == -2);
    9913 assert(bestubtype[i] > -3 && bestubtype[i] < SCIPvarGetNVubs(var));
    9914
    9915 /* store for y_j that y'_j is the associated real variable
    9916 * in the relaxed set
    9917 */
    9918 snf->origcontvars[snf->ntransvars] = probidx;
    9919
    9920 if( bestubtype[i] < 0 )
    9921 {
    9922 SCIP_Real QUAD(val);
    9923 SCIP_Real QUAD(contsolval);
    9924 SCIP_Real QUAD(rowcoeftimesbestslb);
    9925
    9926 /* use simple upper bound in bestslb = l_j <= y_j <= u_j = bestub to define
    9927 * 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
    9928 * 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,
    9929 * put j into the set
    9930 * N1 if a_j > 0
    9931 * N2 if a_j < 0
    9932 * and update the right hand side of the constraint in the relaxation
    9933 * rhs = rhs - a_j l_j
    9934 */
    9935 SCIPquadprecSumDD(val, bestub[i], - bestslb[i]);
    9936 SCIPquadprecProdQQ(val, val, rowcoef);
    9937 SCIPquadprecSumDD(contsolval, solval, - bestslb[i]);
    9938 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
    9939
    9940 if( bestubtype[i] == -2 || bestslbtype[i] == -2 )
    9941 *localbdsused = TRUE;
    9942
    9943 SCIPquadprecProdQD(rowcoeftimesbestslb, rowcoef, bestslb[i]);
    9944
    9945 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
    9946 snf->origbinvars[snf->ntransvars] = -1;
    9947 snf->aggrcoefsbin[snf->ntransvars] = 0.0;
    9948
    9949 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
    9950 {
    9951 snf->transvarcoefs[snf->ntransvars] = 1;
    9952 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
    9953 snf->transbinvarsolvals[snf->ntransvars] = 1.0;
    9954 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
    9955
    9956 /* aggregation information for y'_j */
    9957 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
    9958 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestslb);
    9959 }
    9960 else
    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 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestslb);
    9972
    9973 SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., Y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
    9974 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
    9975 snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestslb), QUAD_TO_DBL(rowcoef), bestslb[i], QUAD_TO_DBL(transrhs));
    9976 }
    9977 else
    9978 {
    9979 SCIP_Real QUAD(rowcoefbinary);
    9980 SCIP_Real varsolvalbinary;
    9981 SCIP_Real QUAD(val);
    9982 SCIP_Real QUAD(contsolval);
    9983 SCIP_Real QUAD(rowcoeftimesvubconst);
    9984 int vubvarprobidx;
    9985
    9986 SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
    9987 SCIP_Real* vubconsts = SCIPvarGetVubConstants(var);
    9988 SCIP_Real* vubcoefs = SCIPvarGetVubCoefs(var);
    9989
    9990 /* use variable upper bound in bestslb = l_j <= y_j <= u~_j x_j + d_j = bestub to define
    9991 * 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
    9992 * 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,
    9993 * where c_j is the coefficient of x_j in the row, put j into the set
    9994 * N1 if a_j > 0
    9995 * N2 if a_j < 0
    9996 * and update the right hand side of the constraint in the relaxation
    9997 * rhs = rhs - a_j d_j
    9998 */
    9999
    10000 vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[i]]);
    10001 assert(binvarused[vubvarprobidx] == 1);
    10002 assert(vubvarprobidx < nbinvars);
    10003
    10004 QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vubvarprobidx);
    10005 varsolvalbinary = SCIPgetSolVal(scip, sol, vubvars[bestubtype[i]]);
    10006
    10007 /* clear the binvarpos array, since the variable has been processed */
    10008 binvarused[vubvarprobidx] = 0;
    10009
    10010 SCIPquadprecProdQD(val, rowcoef, vubcoefs[bestubtype[i]]);
    10011 SCIPquadprecSumQQ(val, val, rowcoefbinary);
    10012 {
    10013 SCIP_Real QUAD(tmp);
    10014 SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
    10015 SCIPquadprecSumDD(contsolval, solval, - vubconsts[bestubtype[i]]);
    10016 SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
    10017 SCIPquadprecSumQQ(contsolval, contsolval, tmp);
    10018 }
    10019
    10020 SCIPquadprecProdQD(rowcoeftimesvubconst, rowcoef, vubconsts[bestubtype[i]]);
    10021 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
    10022 snf->origbinvars[snf->ntransvars] = vubvarprobidx;
    10023
    10024 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
    10025 {
    10026 snf->transvarcoefs[snf->ntransvars] = 1;
    10027 snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
    10028 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
    10029 snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
    10030
    10031 /* aggregation information for y'_j */
    10032 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
    10033 snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
    10034 snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvubconst);
    10035 }
    10036 else
    10037 {
    10038 snf->transvarcoefs[snf->ntransvars] = - 1;
    10039 snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
    10040 snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
    10041 snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
    10042
    10043 /* aggregation information for y'_j */
    10044 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
    10045 snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
    10046 snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvubconst);
    10047 }
    10048 SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvubconst);
    10049
    10050 /* store for x_j that y'_j is the associated real variable in the 0-1 single node flow relaxation */
    10051
    10052 SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
    10053 snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
    10054 snf->ntransvars, SCIPvarGetName(vubvars[bestubtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvubconst), QUAD_TO_DBL(rowcoef),
    10055 vubconsts[bestubtype[i]], QUAD_TO_DBL(transrhs));
    10056 }
    10057 }
    10058
    10059 /* make sure the coefficient is not negative due to small numerical rounding errors */
    10060 assert(snf->transvarvubcoefs[snf->ntransvars] > -QUAD_EPSILON);
    10061 snf->transvarvubcoefs[snf->ntransvars] = MAX(snf->transvarvubcoefs[snf->ntransvars], 0.0);
    10062
    10063 ++snf->ntransvars;
    10064 }
    10065
    10066 snf->transrhs = QUAD_TO_DBL(transrhs);
    10067
    10068 /* transform remaining binary variables of row */
    10069 for( i = nnonbinvarsrow; i < nnz; ++i )
    10070 {
    10071 SCIP_VAR* var;
    10072 SCIP_Real QUAD(rowcoef);
    10073 int probidx;
    10074 SCIP_Real val;
    10075 SCIP_Real contsolval;
    10076 SCIP_Real varsolval;
    10077
    10078 probidx = rowinds[i];
    10079 /* variable should be binary */
    10080 assert(probidx >= 0);
    10081 assert(probidx < nbinvars);
    10082
    10083 /* binary variable was processed together with a non-binary variable */
    10084 if( binvarused[probidx] == 0 )
    10085 continue;
    10086
    10087 /* binary variable was not processed yet, so the binvarused value sould be -1 */
    10088 assert(binvarused[probidx] == -1);
    10089
    10090 /* set binvarused to zero since it has been processed */
    10091 binvarused[probidx] = 0;
    10092
    10093 var = vars[probidx];
    10094 QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
    10095 assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
    10096
    10097 varsolval = SCIPgetSolVal(scip, sol, var);
    10098 SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g, %g]>:\n", i, QUAD_TO_DBL(rowcoef), SCIPvarGetName(var), probidx, varsolval,
    10100
    10101 /* define
    10102 * y'_j = c_j x_j with 0 <= y'_j <= c_j x_j if c_j > 0
    10103 * y'_j = - c_j x_j with 0 <= y'_j <= - c_j x_j if c_j < 0,
    10104 * where c_j is the coefficient of x_j in the row and put j into the set
    10105 * N1 if c_j > 0
    10106 * N2 if c_j < 0.
    10107 */
    10108 val = QUAD_TO_DBL(rowcoef);
    10109 contsolval = QUAD_TO_DBL(rowcoef) * varsolval;
    10110
    10111 /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
    10112 snf->origbinvars[snf->ntransvars] = probidx;
    10113 snf->origcontvars[snf->ntransvars] = -1;
    10114 snf->aggrcoefscont[snf->ntransvars] = 0.0;
    10115 snf->aggrconstants[snf->ntransvars] = 0.0;
    10116
    10117 if( QUAD_TO_DBL(rowcoef) >= 0.0 )
    10118 {
    10119 snf->transvarcoefs[snf->ntransvars] = 1;
    10120 snf->transvarvubcoefs[snf->ntransvars] = val;
    10121 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
    10122 snf->transcontvarsolvals[snf->ntransvars] = contsolval;
    10123
    10124 /* aggregation information for y'_j */
    10125 snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
    10126 }
    10127 else
    10128 {
    10129 snf->transvarcoefs[snf->ntransvars] = - 1;
    10130 snf->transvarvubcoefs[snf->ntransvars] = - val;
    10131 snf->transbinvarsolvals[snf->ntransvars] = varsolval;
    10132 snf->transcontvarsolvals[snf->ntransvars] = - contsolval;
    10133
    10134 /* aggregation information for y'_j */
    10135 snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
    10136 }
    10137
    10138 assert(snf->transvarcoefs[snf->ntransvars] == 1 || snf->transvarcoefs[snf->ntransvars] == - 1 );
    10139 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[snf->ntransvars], 0.0)
    10140 && SCIPisFeasLE(scip, snf->transbinvarsolvals[snf->ntransvars], 1.0));
    10141 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[snf->ntransvars], 0.0)
    10143
    10144 SCIPdebugMsg(scip, " --> ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s))\n", snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars,
    10145 snf->transvarvubcoefs[snf->ntransvars], snf->ntransvars, SCIPvarGetName(var) );
    10146
    10147 /* updates number of variables in transformed problem */
    10148 snf->ntransvars++;
    10149 }
    10150
    10151 /* construction was successful */
    10152 *success = TRUE;
    10153
    10154#ifdef SCIP_DEBUG
    10155 SCIPdebugMsg(scip, "constraint in constructed 0-1 single node flow relaxation: ");
    10156 for( i = 0; i < snf->ntransvars; i++ )
    10157 {
    10158 SCIPdebugMsgPrint(scip, "%s y'_%d ", snf->transvarcoefs[i] == 1 ? "+" : "-", i);
    10159 }
    10160 SCIPdebugMsgPrint(scip, "<= %g\n", snf->transrhs);
    10161#endif
    10162
    10163 TERMINATE:
    10164
    10165 SCIPfreeCleanBufferArray(scip, &binvarused);
    10166 SCIPfreeBufferArray(scip, &selectedbounds);
    10167 SCIPfreeBufferArray(scip, &bestsubtype);
    10168 SCIPfreeBufferArray(scip, &bestslbtype);
    10169 SCIPfreeBufferArray(scip, &bestubtype);
    10170 SCIPfreeBufferArray(scip, &bestlbtype);
    10171 SCIPfreeBufferArray(scip, &bestsub);
    10172 SCIPfreeBufferArray(scip, &bestslb);
    10173 SCIPfreeBufferArray(scip, &bestub);
    10174 SCIPfreeBufferArray(scip, &bestlb);
    10175
    10176 return SCIP_OKAY;
    10177}
    10178
    10179/** allocate buffer arrays for storing the single-node-flow relaxation */
    10180static
    10182 SCIP* scip, /**< SCIP data structure */
    10183 SNF_RELAXATION* snf, /**< pointer to snf relaxation to be destroyed */
    10184 int nvars /**< number of active problem variables */
    10185 )
    10186{
    10196
    10197 return SCIP_OKAY;
    10198}
    10199
    10200/** free buffer arrays for storing the single-node-flow relaxation */
    10201static
    10203 SCIP* scip, /**< SCIP data structure */
    10204 SNF_RELAXATION* snf /**< pointer to snf relaxation to be destroyed */
    10205 )
    10206{
    10216}
    10217
    10218/** solve knapsack problem in maximization form with "<" constraint approximately by greedy; if needed, one can provide
    10219 * arrays to store all selected items and all not selected items
    10220 */
    10221static
    10223 SCIP* scip, /**< SCIP data structure */
    10224 int nitems, /**< number of available items */
    10225 SCIP_Real* weights, /**< item weights */
    10226 SCIP_Real* profits, /**< item profits */
    10227 SCIP_Real capacity, /**< capacity of knapsack */
    10228 int* items, /**< item numbers */
    10229 int* solitems, /**< array to store items in solution, or NULL */
    10230 int* nonsolitems, /**< array to store items not in solution, or NULL */
    10231 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
    10232 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
    10233 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
    10234 )
    10235{
    10236 SCIP_Real* tempsort;
    10237 SCIP_Real solitemsweight;
    10238 SCIP_Real mediancapacity;
    10239 int j;
    10240 int i;
    10241 int criticalitem;
    10242
    10243 assert(weights != NULL);
    10244 assert(profits != NULL);
    10245 assert(SCIPisFeasGE(scip, capacity, 0.0));
    10246 assert(!SCIPisInfinity(scip, capacity));
    10247 assert(items != NULL);
    10248 assert(nitems >= 0);
    10249
    10250 if( solitems != NULL )
    10251 {
    10252 *nsolitems = 0;
    10253 *nnonsolitems = 0;
    10254 }
    10255 if( solval != NULL )
    10256 *solval = 0.0;
    10257
    10258 /* allocate memory for temporary array used for sorting; array should contain profits divided by corresponding weights (p_1 / w_1 ... p_n / w_n )*/
    10259 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
    10260
    10261 /* initialize temporary array */
    10262 for( i = nitems - 1; i >= 0; --i )
    10263 tempsort[i] = profits[i] / weights[i];
    10264
    10265 /* decrease capacity slightly to make it tighter than the original capacity */
    10266 mediancapacity = capacity * (1 - SCIPfeastol(scip));
    10267
    10268 /* rearrange items around */
    10269 SCIPselectWeightedDownRealRealInt(tempsort, profits, items, weights, mediancapacity, nitems, &criticalitem);
    10270
    10271 /* free temporary array */
    10272 SCIPfreeBufferArray(scip, &tempsort);
    10273
    10274 /* select items as long as they fit into the knapsack */
    10275 solitemsweight = 0.0;
    10276 for( j = 0; j < nitems && SCIPisFeasLT(scip, solitemsweight + weights[j], capacity); j++ )
    10277 {
    10278 if( solitems != NULL )
    10279 {
    10280 solitems[*nsolitems] = items[j];
    10281 (*nsolitems)++;
    10282 }
    10283 if( solval != NULL )
    10284 (*solval) += profits[j];
    10285 solitemsweight += weights[j];
    10286 }
    10287
    10288 /* continue to put items into the knapsack if they entirely fit */
    10289 for( ; j < nitems; j++ )
    10290 {
    10291 if( SCIPisFeasLT(scip, solitemsweight + weights[j], capacity) )
    10292 {
    10293 if( solitems != NULL )
    10294 {
    10295 solitems[*nsolitems] = items[j];
    10296 (*nsolitems)++;
    10297 }
    10298 if( solval != NULL )
    10299 (*solval) += profits[j];
    10300 solitemsweight += weights[j];
    10301 }
    10302 else if( solitems != NULL )
    10303 {
    10304 nonsolitems[*nnonsolitems] = items[j];
    10305 (*nnonsolitems)++;
    10306 }
    10307 }
    10308
    10309 return SCIP_OKAY;
    10310}
    10311
    10312
    10313/** build the flow cover which corresponds to the given exact or approximate solution of KP^SNF; given unfinished
    10314 * flow cover contains variables which have been fixed in advance
    10315 */
    10316static
    10318 SCIP* scip, /**< SCIP data structure */
    10319 int* coefs, /**< coefficient of all real variables in N1&N2 */
    10320 SCIP_Real* vubcoefs, /**< coefficient in vub of all real variables in N1&N2 */
    10321 SCIP_Real rhs, /**< right hand side of 0-1 single node flow constraint */
    10322 int* solitems, /**< items in knapsack */
    10323 int* nonsolitems, /**< items not in knapsack */
    10324 int nsolitems, /**< number of items in knapsack */
    10325 int nnonsolitems, /**< number of items not in knapsack */
    10326 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
    10327 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
    10328 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
    10329 QUAD(SCIP_Real* flowcoverweight), /**< pointer to store weight of flow cover */
    10330 SCIP_Real* lambda /**< pointer to store lambda */
    10331 )
    10332{
    10333 int j;
    10334 SCIP_Real QUAD(tmp);
    10335
    10336 assert(scip != NULL);
    10337 assert(coefs != NULL);
    10338 assert(vubcoefs != NULL);
    10339 assert(solitems != NULL);
    10340 assert(nonsolitems != NULL);
    10341 assert(nsolitems >= 0);
    10342 assert(nnonsolitems >= 0);
    10343 assert(nflowcovervars != NULL && *nflowcovervars >= 0);
    10344 assert(nnonflowcovervars != NULL && *nnonflowcovervars >= 0);
    10345 assert(flowcoverstatus != NULL);
    10346 assert(QUAD_HI(flowcoverweight) != NULL);
    10347 assert(lambda != NULL);
    10348
    10349 /* get flowcover status for each item */
    10350 for( j = 0; j < nsolitems; j++ )
    10351 {
    10352 /* j in N1 with z°_j = 1 => j in N1\C1 */
    10353 if( coefs[solitems[j]] == 1 )
    10354 {
    10355 flowcoverstatus[solitems[j]] = -1;
    10356 (*nnonflowcovervars)++;
    10357 }
    10358 /* j in N2 with z_j = 1 => j in C2 */
    10359 else
    10360 {
    10361 assert(coefs[solitems[j]] == -1);
    10362 flowcoverstatus[solitems[j]] = 1;
    10363 (*nflowcovervars)++;
    10364 SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, -vubcoefs[solitems[j]]);
    10365 }
    10366 }
    10367 for( j = 0; j < nnonsolitems; j++ )
    10368 {
    10369 /* j in N1 with z°_j = 0 => j in C1 */
    10370 if( coefs[nonsolitems[j]] == 1 )
    10371 {
    10372 flowcoverstatus[nonsolitems[j]] = 1;
    10373 (*nflowcovervars)++;
    10374 SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, vubcoefs[nonsolitems[j]]);
    10375 }
    10376 /* j in N2 with z_j = 0 => j in N2\C2 */
    10377 else
    10378 {
    10379 assert(coefs[nonsolitems[j]] == -1);
    10380 flowcoverstatus[nonsolitems[j]] = -1;
    10381 (*nnonflowcovervars)++;
    10382 }
    10383 }
    10384
    10385 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
    10386 SCIPquadprecSumQD(tmp, *flowcoverweight, -rhs);
    10387 *lambda = QUAD_TO_DBL(tmp);
    10388}
    10389
    10390#ifndef NO_EXACT_KNAPSACK
    10391
    10392/** checks whether the given scalar scales the given value to an integral number with error in the given bounds */
    10393static
    10395 SCIP_Real val, /**< value that should be scaled to an integral value */
    10396 SCIP_Real scalar, /**< scalar that should be tried */
    10397 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
    10398 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
    10399 )
    10400{
    10401 SCIP_Real sval;
    10402 SCIP_Real downval;
    10403 SCIP_Real upval;
    10404
    10405 assert(mindelta <= 0.0);
    10406 assert(maxdelta >= 0.0);
    10407
    10408 sval = val * scalar;
    10409 downval = floor(sval);
    10410 upval = ceil(sval);
    10411
    10412 return (SCIPrelDiff(sval, downval) <= maxdelta || SCIPrelDiff(sval, upval) >= mindelta);
    10413}
    10414
    10415/** get integral number with error in the bounds which corresponds to given value scaled by a given scalar;
    10416 * should be used in connection with isIntegralScalar()
    10417 */
    10418static
    10419SCIP_Longint getIntegralVal(
    10420 SCIP_Real val, /**< value that should be scaled to an integral value */
    10421 SCIP_Real scalar, /**< scalar that should be tried */
    10422 SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
    10423 SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
    10424 )
    10425{
    10426 SCIP_Real sval;
    10427 SCIP_Real upval;
    10428 SCIP_Longint intval;
    10429
    10430 assert(mindelta <= 0.0);
    10431 assert(maxdelta >= 0.0);
    10432
    10433 sval = val * scalar;
    10434 upval = ceil(sval);
    10435
    10436 if( SCIPrelDiff(sval, upval) >= mindelta )
    10437 intval = (SCIP_Longint) upval;
    10438 else
    10439 intval = (SCIP_Longint) (floor(sval));
    10440
    10441 return intval;
    10442}
    10443
    10444/** get a flow cover (C1, C2) for a given 0-1 single node flow set
    10445 * {(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},
    10446 * 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
    10447 */
    10448static
    10450 SCIP* scip, /**< SCIP data structure */
    10451 SNF_RELAXATION* snf, /**< the single node flow relaxation */
    10452 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
    10453 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
    10454 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
    10455 SCIP_Real* lambda, /**< pointer to store lambda */
    10456 SCIP_Bool* found /**< pointer to store whether a cover was found */
    10457 )
    10458{
    10459 SCIP_Real* transprofitsint;
    10460 SCIP_Real* transprofitsreal;
    10461 SCIP_Real* transweightsreal;
    10462 SCIP_Longint* transweightsint;
    10463 int* items;
    10464 int* itemsint;
    10465 int* nonsolitems;
    10466 int* solitems;
    10467 SCIP_Real QUAD(flowcoverweight);
    10468 SCIP_Real QUAD(flowcoverweightafterfix);
    10469 SCIP_Real n1itemsweight;
    10470 SCIP_Real n2itemsminweight;
    10471 SCIP_Real scalar;
    10472 SCIP_Real transcapacityreal;
    10473#if !defined(NDEBUG) || defined(SCIP_DEBUG)
    10474 SCIP_Bool kpexact;
    10475#endif
    10476 SCIP_Bool scalesuccess;
    10477 SCIP_Bool transweightsrealintegral;
    10478 SCIP_Longint transcapacityint;
    10479 int nflowcovervarsafterfix;
    10480 int nitems;
    10481 int nn1items;
    10482 int nnonflowcovervarsafterfix;
    10483 int nnonsolitems;
    10484 int nsolitems;
    10485 int j;
    10486
    10487 assert(scip != NULL);
    10488 assert(snf->transvarcoefs != NULL);
    10489 assert(snf->transbinvarsolvals != NULL);
    10490 assert(snf->transvarvubcoefs != NULL);
    10491 assert(snf->ntransvars > 0);
    10492 assert(nflowcovervars != NULL);
    10493 assert(nnonflowcovervars != NULL);
    10494 assert(flowcoverstatus != NULL);
    10495 assert(lambda != NULL);
    10496 assert(found != NULL);
    10497
    10498 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
    10499
    10500 /* get data structures */
    10502 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
    10503 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
    10504 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsint, snf->ntransvars) );
    10505 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
    10506 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
    10507 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
    10508 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
    10509
    10510 BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
    10511 *found = FALSE;
    10512 *nflowcovervars = 0;
    10513 *nnonflowcovervars = 0;
    10514
    10515 QUAD_ASSIGN(flowcoverweight, 0.0);
    10516 nflowcovervarsafterfix = 0;
    10517 nnonflowcovervarsafterfix = 0;
    10518 QUAD_ASSIGN(flowcoverweightafterfix, 0.0);
    10519#if !defined(NDEBUG) || defined(SCIP_DEBUG)
    10520 kpexact = FALSE;
    10521#endif
    10522
    10523 /* fix some variables in advance according to the following fixing strategy
    10524 * put j into N1\C1, if j in N1 and x*_j = 0,
    10525 * put j into C1, if j in N1 and x*_j = 1,
    10526 * put j into C2, if j in N2 and x*_j = 1,
    10527 * put j into N2\C2, if j in N2 and x*_j = 0
    10528 * and get the set of the remaining variables
    10529 */
    10530 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
    10531 nitems = 0;
    10532 nn1items = 0;
    10533 n1itemsweight = 0.0;
    10534 n2itemsminweight = SCIP_REAL_MAX;
    10535 for( j = 0; j < snf->ntransvars; j++ )
    10536 {
    10537 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
    10538 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
    10539 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
    10540
    10541 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
    10542 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
    10543 {
    10544 flowcoverstatus[j] = -1;
    10545 (*nnonflowcovervars)++;
    10546 continue;
    10547 }
    10548
    10549 /* x*_j is fractional */
    10551 {
    10552 items[nitems] = j;
    10553 nitems++;
    10554 if( snf->transvarcoefs[j] == 1 )
    10555 {
    10556 n1itemsweight += snf->transvarvubcoefs[j];
    10557 nn1items++;
    10558 }
    10559 else
    10560 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
    10561 }
    10562 /* j is in N1 and x*_j = 0 */
    10563 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
    10564 {
    10565 flowcoverstatus[j] = -1;
    10566 (*nnonflowcovervars)++;
    10567 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
    10568 }
    10569 /* j is in N1 and x*_j = 1 */
    10570 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
    10571 {
    10572 flowcoverstatus[j] = 1;
    10573 (*nflowcovervars)++;
    10574 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
    10575 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
    10576 }
    10577 /* j is in N2 and x*_j = 1 */
    10578 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
    10579 {
    10580 flowcoverstatus[j] = 1;
    10581 (*nflowcovervars)++;
    10582 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
    10583 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
    10584 }
    10585 /* j is in N2 and x*_j = 0 */
    10586 else
    10587 {
    10588 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
    10589 flowcoverstatus[j] = -1;
    10590 (*nnonflowcovervars)++;
    10591 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
    10592 }
    10593 }
    10594 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
    10595 assert(nn1items >= 0);
    10596
    10597 /* to find a flow cover, transform the following knapsack problem
    10598 *
    10599 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
    10600 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
    10601 * z_j in {0,1} for all j in N1 & N2
    10602 *
    10603 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
    10604 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
    10605 *
    10606 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
    10607 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
    10608 * z°_j in {0,1} for all j in N1
    10609 * z_j in {0,1} for all j in N2,
    10610 * and solve it approximately under consideration of the fixing,
    10611 * or
    10612 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
    10613 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
    10614 * and multiplying the constraint by a suitable scalar C
    10615 *
    10616 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
    10617 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
    10618 * z°_j in {0,1} for all j in N1
    10619 * z_j in {0,1} for all j in N2,
    10620 * where
    10621 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
    10622 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
    10623 * and solve it exactly under consideration of the fixing.
    10624 */
    10625 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
    10626
    10627 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
    10628 transweightsrealintegral = TRUE;
    10629 for( j = 0; j < nitems; j++ )
    10630 {
    10631 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
    10632
    10633 if( !isIntegralScalar(transweightsreal[j], 1.0, -MINDELTA, MAXDELTA) )
    10634 transweightsrealintegral = FALSE;
    10635
    10636 if( snf->transvarcoefs[items[j]] == 1 )
    10637 {
    10638 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
    10639 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
    10640 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
    10641 }
    10642 else
    10643 {
    10644 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
    10645 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
    10646 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
    10647 }
    10648 }
    10649 /* get capacity of knapsack constraint in KP^SNF_rat */
    10650 transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight;
    10651 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
    10652 snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
    10653
    10654 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
    10655 * is less than or equal to zero
    10656 */
    10657 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
    10658 {
    10659 assert(!(*found));
    10660 goto TERMINATE;
    10661 }
    10662
    10663 /* KP^SNF_rat has been solved by fixing some variables in advance */
    10664 assert(nitems >= 0);
    10665 if( nitems == 0)
    10666 {
    10667 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
    10668 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
    10669 *lambda = QUAD_TO_DBL(flowcoverweight);
    10670 *found = TRUE;
    10671 goto TERMINATE;
    10672 }
    10673
    10674 /* Use the following strategy
    10675 * solve KP^SNF_int exactly, if a suitable factor C is found and (nitems*capacity) <= MAXDYNPROGSPACE,
    10676 * solve KP^SNF_rat approximately, otherwise
    10677 */
    10678
    10679 /* find a scaling factor C */
    10680 if( transweightsrealintegral )
    10681 {
    10682 /* weights are already integral */
    10683 scalar = 1.0;
    10684 scalesuccess = TRUE;
    10685 }
    10686 else
    10687 {
    10688 scalesuccess = FALSE;
    10689 SCIP_CALL( SCIPcalcIntegralScalar(transweightsreal, nitems, -MINDELTA, MAXDELTA, MAXDNOM, MAXSCALE, &scalar,
    10690 &scalesuccess) );
    10691 }
    10692
    10693 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
    10694 nsolitems = -1;
    10695 nnonsolitems = -1;
    10696
    10697 /* suitable factor C was found*/
    10698 if( scalesuccess )
    10699 {
    10700 SCIP_Real tmp1;
    10701 SCIP_Real tmp2;
    10702
    10703 /* transform KP^SNF to KP^SNF_int */
    10704 for( j = 0; j < nitems; ++j )
    10705 {
    10706 transweightsint[j] = getIntegralVal(transweightsreal[j], scalar, -MINDELTA, MAXDELTA);
    10707 transprofitsint[j] = transprofitsreal[j];
    10708 itemsint[j] = items[j];
    10709 }
    10710 if( isIntegralScalar(transcapacityreal, scalar, -MINDELTA, MAXDELTA) )
    10711 {
    10712 transcapacityint = getIntegralVal(transcapacityreal, scalar, -MINDELTA, MAXDELTA);
    10713 transcapacityint -= 1;
    10714 }
    10715 else
    10716 transcapacityint = (SCIP_Longint) (transcapacityreal * scalar);
    10717 nflowcovervarsafterfix = *nflowcovervars;
    10718 nnonflowcovervarsafterfix = *nnonflowcovervars;
    10719 QUAD_ASSIGN_Q(flowcoverweightafterfix, flowcoverweight);
    10720
    10721 tmp1 = (SCIP_Real) (nitems + 1);
    10722 tmp2 = (SCIP_Real) ((transcapacityint) + 1);
    10723 if( transcapacityint * nitems <= MAXDYNPROGSPACE && tmp1 * tmp2 <= INT_MAX / 8.0)
    10724 {
    10725 SCIP_Bool success;
    10726
    10727 /* solve KP^SNF_int by dynamic programming */
    10728 SCIP_CALL( SCIPsolveKnapsackExactly(scip, nitems, transweightsint, transprofitsint, transcapacityint,
    10729 itemsint, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL, &success) );
    10730
    10731 if( !success )
    10732 {
    10733 /* solve KP^SNF_rat approximately */
    10734 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal,
    10735 transcapacityreal, items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
    10736 }
    10737#if !defined(NDEBUG) || defined(SCIP_DEBUG)
    10738 else
    10739 kpexact = TRUE;
    10740#endif
    10741 }
    10742 else
    10743 {
    10744 /* solve KP^SNF_rat approximately */
    10745 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
    10746 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
    10747 assert(!kpexact);
    10748 }
    10749 }
    10750 else
    10751 {
    10752 /* solve KP^SNF_rat approximately */
    10753 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
    10754 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
    10755 assert(!kpexact);
    10756 }
    10757
    10758 assert(nsolitems != -1);
    10759 assert(nnonsolitems != -1);
    10760
    10761 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
    10762 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
    10763 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
    10764 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
    10765 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
    10766
    10767 /* if the found structure is not a flow cover, because of scaling, solve KP^SNF_rat approximately */
    10768 if( SCIPisFeasLE(scip, *lambda, 0.0) )
    10769 {
    10770 assert(kpexact);
    10771
    10772 /* solve KP^SNF_rat approximately */
    10773 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
    10774 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
    10775#ifdef SCIP_DEBUG /* this time only for SCIP_DEBUG, because only then, the variable is used again */
    10776 kpexact = FALSE;
    10777#endif
    10778
    10779 /* build the flow cover from the solution of KP^SNF_rat and the fixing */
    10780 *nflowcovervars = nflowcovervarsafterfix;
    10781 *nnonflowcovervars = nnonflowcovervarsafterfix;
    10782 QUAD_ASSIGN_Q(flowcoverweight, flowcoverweightafterfix);
    10783
    10784 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
    10785 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
    10786 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
    10787 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
    10788 }
    10789 *found = SCIPisFeasGT(scip, *lambda, 0.0);
    10790
    10791 TERMINATE:
    10792 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
    10793#ifdef SCIP_DEBUG
    10794 if( *found )
    10795 {
    10796 SCIPdebugMsg(scip, "2. %s solution:\n", kpexact ? "exact" : "approximate");
    10797 for( j = 0; j < snf->ntransvars; j++ )
    10798 {
    10799 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
    10800 {
    10801 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
    10802 }
    10803 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
    10804 {
    10805 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
    10806 }
    10807 }
    10808 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
    10809 }
    10810#endif
    10811
    10812 /* free data structures */
    10813 SCIPfreeBufferArray(scip, &nonsolitems);
    10814 SCIPfreeBufferArray(scip, &solitems);
    10815 SCIPfreeBufferArray(scip, &transweightsint);
    10816 SCIPfreeBufferArray(scip, &transweightsreal);
    10817 SCIPfreeBufferArray(scip, &transprofitsint);
    10818 SCIPfreeBufferArray(scip, &transprofitsreal);
    10819 SCIPfreeBufferArray(scip, &itemsint);
    10820 SCIPfreeBufferArray(scip, &items);
    10821
    10822 return SCIP_OKAY;
    10823}
    10824
    10825#else
    10826
    10827/** get a flow cover \f$(C1, C2)\f$ for a given 0-1 single node flow set
    10828 * \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$,
    10829 * i.e., get sets \f$ C1 \subset N1 \f$ and \f$ C2 \subset N2 \f$ with
    10830 * \f$ \sum_{j in C1} u_j - sum_{j in C2} u_j = b + lambda \f$ and \f$ lambda > 0 \f$
    10831 */
    10832static
    10834 SCIP* scip, /**< SCIP data structure */
    10835 SNF_RELAXATION* snf, /**< the 0-1 single node flow relaxation */
    10836 int* nflowcovervars, /**< pointer to store number of variables in flow cover */
    10837 int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
    10838 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
    10839 SCIP_Real* lambda, /**< pointer to store lambda */
    10840 SCIP_Bool* found /**< pointer to store whether a cover was found */
    10841 )
    10842{
    10843 SCIP_Real* transprofitsreal;
    10844 SCIP_Real* transweightsreal;
    10845 SCIP_Longint* transweightsint;
    10846 int* items;
    10847 int* itemsint;
    10848 int* nonsolitems;
    10849 int* solitems;
    10850 SCIP_Real QUAD(flowcoverweight);
    10851 SCIP_Real n1itemsweight;
    10852 SCIP_Real n2itemsminweight;
    10853 SCIP_Real transcapacityreal;
    10854 int nitems;
    10855#ifndef NDEBUG
    10856 int nn1items = 0;
    10857#endif
    10858 int nnonsolitems;
    10859 int nsolitems;
    10860 int j;
    10861
    10862 assert(scip != NULL);
    10863 assert(snf->transvarcoefs != NULL);
    10864 assert(snf->transbinvarsolvals != NULL);
    10865 assert(snf->transvarvubcoefs != NULL);
    10866 assert(snf->ntransvars > 0);
    10867 assert(nflowcovervars != NULL);
    10868 assert(nnonflowcovervars != NULL);
    10869 assert(flowcoverstatus != NULL);
    10870 assert(lambda != NULL);
    10871 assert(found != NULL);
    10872
    10873 SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
    10874
    10875 /* get data structures */
    10877 SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
    10878 SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
    10879 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
    10880 SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
    10881 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
    10882 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
    10883
    10884 BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
    10885 *found = FALSE;
    10886 *nflowcovervars = 0;
    10887 *nnonflowcovervars = 0;
    10888
    10889 QUAD_ASSIGN(flowcoverweight, 0.0);
    10890
    10891 /* fix some variables in advance according to the following fixing strategy
    10892 * put j into N1\C1, if j in N1 and x*_j = 0,
    10893 * put j into C1, if j in N1 and x*_j = 1,
    10894 * put j into C2, if j in N2 and x*_j = 1,
    10895 * put j into N2\C2, if j in N2 and x*_j = 0
    10896 * and get the set of the remaining variables
    10897 */
    10898 SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
    10899 nitems = 0;
    10900 n1itemsweight = 0.0;
    10901 n2itemsminweight = SCIP_REAL_MAX;
    10902 for( j = 0; j < snf->ntransvars; j++ )
    10903 {
    10904 assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
    10905 assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
    10906 assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
    10907
    10908 /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
    10909 if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
    10910 {
    10911 flowcoverstatus[j] = -1;
    10912 (*nnonflowcovervars)++;
    10913 continue;
    10914 }
    10915
    10916 /* x*_j is fractional */
    10918 {
    10919 items[nitems] = j;
    10920 nitems++;
    10921 if( snf->transvarcoefs[j] == 1 )
    10922 {
    10923 n1itemsweight += snf->transvarvubcoefs[j];
    10924#ifndef NDEBUG
    10925 nn1items++;
    10926#endif
    10927 }
    10928 else
    10929 n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
    10930 }
    10931 /* j is in N1 and x*_j = 0 */
    10932 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
    10933 {
    10934 flowcoverstatus[j] = -1;
    10935 (*nnonflowcovervars)++;
    10936 SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
    10937 }
    10938 /* j is in N1 and x*_j = 1 */
    10939 else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
    10940 {
    10941 flowcoverstatus[j] = 1;
    10942 (*nflowcovervars)++;
    10943 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
    10944 SCIPdebugMsg(scip, " <%d>: in C1\n", j);
    10945 }
    10946 /* j is in N2 and x*_j = 1 */
    10947 else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
    10948 {
    10949 flowcoverstatus[j] = 1;
    10950 (*nflowcovervars)++;
    10951 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
    10952 SCIPdebugMsg(scip, " <%d>: in C2\n", j);
    10953 }
    10954 /* j is in N2 and x*_j = 0 */
    10955 else
    10956 {
    10957 assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
    10958 flowcoverstatus[j] = -1;
    10959 (*nnonflowcovervars)++;
    10960 SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
    10961 }
    10962 }
    10963 assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
    10964 assert(nn1items >= 0);
    10965
    10966 /* to find a flow cover, transform the following knapsack problem
    10967 *
    10968 * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
    10969 * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
    10970 * z_j in {0,1} for all j in N1 & N2
    10971 *
    10972 * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
    10973 * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
    10974 *
    10975 * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
    10976 * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
    10977 * z°_j in {0,1} for all j in N1
    10978 * z_j in {0,1} for all j in N2,
    10979 * and solve it approximately under consideration of the fixing,
    10980 * or
    10981 * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
    10982 * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
    10983 * and multiplying the constraint by a suitable scalar C
    10984 *
    10985 * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
    10986 * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
    10987 * z°_j in {0,1} for all j in N1
    10988 * z_j in {0,1} for all j in N2,
    10989 * where
    10990 * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
    10991 * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
    10992 * and solve it exactly under consideration of the fixing.
    10993 */
    10994 SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
    10995
    10996 /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
    10997 for( j = 0; j < nitems; j++ )
    10998 {
    10999 transweightsreal[j] = snf->transvarvubcoefs[items[j]];
    11000
    11001 if( snf->transvarcoefs[items[j]] == 1 )
    11002 {
    11003 transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
    11004 SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
    11005 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
    11006 }
    11007 else
    11008 {
    11009 transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
    11010 SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
    11011 items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
    11012 }
    11013 }
    11014 /* get capacity of knapsack constraint in KP^SNF_rat */
    11015 transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight; /*lint !e644*/
    11016 SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
    11017 snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
    11018
    11019 /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
    11020 * is less than or equal to zero
    11021 */
    11022 if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
    11023 {
    11024 assert(!(*found));
    11025 goto TERMINATE;
    11026 }
    11027
    11028 /* KP^SNF_rat has been solved by fixing some variables in advance */
    11029 assert(nitems >= 0);
    11030 if( nitems == 0 )
    11031 {
    11032 /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
    11033 SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
    11034 *lambda = QUAD_TO_DBL(flowcoverweight);
    11035 *found = TRUE;
    11036 goto TERMINATE;
    11037 }
    11038
    11039 /* Solve the KP^SNF_rat approximately */
    11040
    11041 /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
    11042 nsolitems = -1;
    11043 nnonsolitems = -1;
    11044
    11045 /* suitable factor C was found*/
    11046 /* solve KP^SNF_rat approximately */
    11047 SCIP_CALL( SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
    11048 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL) );
    11049
    11050 assert(nsolitems != -1);
    11051 assert(nnonsolitems != -1);
    11052
    11053 /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
    11054 assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
    11055 buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
    11056 nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
    11057 assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
    11058
    11059 *found = SCIPisFeasGT(scip, *lambda, 0.0);
    11060
    11061 TERMINATE:
    11062 assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
    11063#ifdef SCIP_DEBUG
    11064 if( *found )
    11065 {
    11066 SCIPdebugMsg(scip, "2. approximate solution:\n");
    11067 for( j = 0; j < snf->ntransvars; j++ )
    11068 {
    11069 if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
    11070 {
    11071 SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
    11072 }
    11073 else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
    11074 {
    11075 SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
    11076 }
    11077 }
    11078 SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
    11079 }
    11080#endif
    11081
    11082 /* free data structures */
    11083 SCIPfreeBufferArray(scip, &nonsolitems);
    11084 SCIPfreeBufferArray(scip, &solitems);
    11085 SCIPfreeBufferArray(scip, &transweightsint);
    11086 SCIPfreeBufferArray(scip, &transweightsreal);
    11087 SCIPfreeBufferArray(scip, &transprofitsreal);
    11088 SCIPfreeBufferArray(scip, &itemsint);
    11089 SCIPfreeBufferArray(scip, &items);
    11090
    11091 return SCIP_OKAY;
    11092}
    11093
    11094#endif
    11095
    11096/** evaluate the super-additive lifting function for the lifted simple generalized flowcover inequalities
    11097 * for a given value \f$ x \in \{ u_j \mid j \in C- \} \f$.
    11098 */
    11099static
    11101 SCIP* scip, /**< SCIP data structure */
    11102 LIFTINGDATA* liftingdata, /**< lifting data to use */
    11103 SCIP_Real x /**< value where to evaluate lifting function */
    11104 )
    11105{
    11106 SCIP_Real QUAD(tmp);
    11107 SCIP_Real xpluslambda;
    11108 int i;
    11109
    11110 assert( liftingdata != NULL );
    11111
    11112 xpluslambda = x + liftingdata->lambda;
    11113
    11114 i = 0;
    11115 while( i < liftingdata->r && SCIPisGT(scip, xpluslambda, liftingdata->M[i+1]) )
    11116 ++i;
    11117
    11118 if( i < liftingdata->t )
    11119 {
    11120 if( SCIPisLE(scip, liftingdata->M[i], x) )
    11121 {
    11122 assert(SCIPisLE(scip, xpluslambda, liftingdata->M[i+1]));
    11123 return i * liftingdata->lambda;
    11124 }
    11125
    11126 assert(i > 0 && SCIPisLE(scip, liftingdata->M[i], xpluslambda) && x <= liftingdata->M[i]);
    11127
    11128 /* return x - liftingdata->M[i] + i * liftingdata->lambda */
    11129 SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
    11130 SCIPquadprecSumQD(tmp, tmp, x);
    11131 SCIPquadprecSumQD(tmp, tmp, -liftingdata->M[i]);
    11132 return QUAD_TO_DBL(tmp);
    11133 }
    11134
    11135 if( i < liftingdata->r )
    11136 {
    11137 assert(!SCIPisInfinity(scip, liftingdata->mp));
    11138
    11139 /* p = liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml; */
    11140 SCIPquadprecSumDD(tmp, liftingdata->m[i], -liftingdata->mp);
    11141 SCIPquadprecSumQD(tmp, tmp, -liftingdata->ml);
    11142 SCIPquadprecSumQD(tmp, tmp, liftingdata->lambda);
    11143
    11144 /* p = MAX(0.0, p); */
    11145 if( QUAD_HI(tmp) < 0.0 )
    11146 {
    11147 QUAD_ASSIGN(tmp, 0.0);
    11148 }
    11149
    11150 SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
    11151 SCIPquadprecSumQD(tmp, tmp, liftingdata->ml);
    11152
    11153 if( SCIPisLT(scip, QUAD_TO_DBL(tmp), xpluslambda) )
    11154 return i * liftingdata->lambda;
    11155
    11156 assert(SCIPisFeasLE(scip, liftingdata->M[i], xpluslambda) &&
    11157 SCIPisFeasLE(scip, xpluslambda, liftingdata->M[i] + liftingdata->ml +
    11158 MAX(0.0, liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml)));
    11159
    11160 SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
    11161 SCIPquadprecSumQD(tmp, tmp, x);
    11162 SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[i]);
    11163 return QUAD_TO_DBL(tmp);
    11164 }
    11165
    11166 assert(i == liftingdata->r && SCIPisLE(scip, liftingdata->M[liftingdata->r], xpluslambda));
    11167
    11168 SCIPquadprecProdDD(tmp, liftingdata->r, liftingdata->lambda);
    11169 SCIPquadprecSumQD(tmp, tmp, x);
    11170 SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[liftingdata->r]);
    11171 return QUAD_TO_DBL(tmp);
    11172}
    11173
    11174/** computes
    11175 * \f[
    11176 * (\alpha_j, \beta_j) =
    11177 * \begin{cases}
    11178 * (0, 0) &\quad\text{if} M_i \leq u_j \leq M_{i+1} - \lambda \\
    11179 * (1, M_i - i \lambda) &\quad\text{if} M_i − \lambda < u_j < M_i \\
    11180 * \end{cases}
    11181 * \f]
    11182 */
    11183static
    11185 SCIP* scip, /**< SCIP data structure */
    11186 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
    11187 SCIP_Real vubcoef, /**< vub coefficient to get alpha and beta for */
    11188 int* alpha, /**< get alpha coefficient for lifting */
    11189 SCIP_Real* beta /**< get beta coefficient for lifting */
    11190 )
    11191{
    11192 SCIP_Real vubcoefpluslambda;
    11193 int i;
    11194
    11195 vubcoefpluslambda = vubcoef + liftingdata->lambda;
    11196
    11197 i = 0;
    11198 while( i < liftingdata->r && SCIPisGT(scip, vubcoefpluslambda, liftingdata->M[i+1]) )
    11199 ++i;
    11200
    11201 if( SCIPisLT(scip, vubcoef, liftingdata->M[i]) )
    11202 {
    11203 SCIP_Real QUAD(tmp);
    11204 assert(liftingdata->M[i] < vubcoefpluslambda);
    11205 *alpha = 1;
    11206 SCIPquadprecProdDD(tmp, -i, liftingdata->lambda);
    11207 SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
    11208 *beta = QUAD_TO_DBL(tmp);
    11209 }
    11210 else
    11211 {
    11212 assert(SCIPisSumLE(scip, liftingdata->M[i], vubcoef));
    11213 assert(i == liftingdata->r || SCIPisLE(scip, vubcoefpluslambda, liftingdata->M[i+1]));
    11214 *alpha = 0;
    11215 *beta = 0.0;
    11216 }
    11217}
    11218
    11219/** compute relevant data for performing the sequence independent lifting */
    11220static
    11222 SCIP* scip, /**< SCIP data structure */
    11223 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
    11224 int* transvarflowcoverstatus, /**< pointer to store whether non-binary var is in L2 (2) or not (-1 or 1) */
    11225 SCIP_Real lambda, /**< lambda */
    11226 LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
    11227 SCIP_Bool* valid /**< is the lifting data valid */
    11228 )
    11229{
    11230 int i;
    11231 SCIP_Real QUAD(tmp);
    11232 SCIP_Real QUAD(sumN2mC2LE);
    11233 SCIP_Real QUAD(sumN2mC2GT);
    11234 SCIP_Real QUAD(sumC1LE);
    11235 SCIP_Real QUAD(sumC2);
    11236
    11237#ifndef NDEBUG
    11238 /* for debugging */
    11239 liftingdata->m = NULL;
    11240 liftingdata->M = NULL;
    11241 liftingdata->lambda = SCIP_INVALID;
    11242 liftingdata->t = 0;
    11243 liftingdata->mp = SCIP_INVALID;
    11244#endif
    11245
    11246 SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->m, snf->ntransvars) );
    11247
    11248 liftingdata->r = 0;
    11249 QUAD_ASSIGN(sumN2mC2LE, 0.0);
    11250 QUAD_ASSIGN(sumC1LE, 0.0);
    11251 QUAD_ASSIGN(sumN2mC2GT, 0.0);
    11252 QUAD_ASSIGN(sumC2, 0.0);
    11253
    11254 liftingdata->mp = SCIPinfinity(scip);
    11255
    11256 *valid = FALSE;
    11257
    11258 for( i = 0; i < snf->ntransvars; ++i )
    11259 {
    11260 int s = (snf->transvarcoefs[i] + 1) + (transvarflowcoverstatus[i] + 1)/2;
    11261
    11262 switch(s)
    11263 {
    11264 case 0: /* var is in N2 \ C2 */
    11265 assert(snf->transvarvubcoefs[i] >= 0.0);
    11266 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == -1);
    11267
    11268 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
    11269 {
    11270 SCIPquadprecSumQD(sumN2mC2GT, sumN2mC2GT, snf->transvarvubcoefs[i]);
    11271 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
    11272 }
    11273 else
    11274 {
    11275 SCIPquadprecSumQD(sumN2mC2LE, sumN2mC2LE, snf->transvarvubcoefs[i]);
    11276 }
    11277 break;
    11278 case 1: /* var is in C2 */
    11279 assert(snf->transvarvubcoefs[i] > 0.0);
    11280 assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == 1);
    11281
    11282 SCIPquadprecSumQD(sumC2, sumC2, snf->transvarvubcoefs[i]);
    11283 break;
    11284 case 3: /* var is in C1 */
    11285 assert(snf->transvarcoefs[i] == 1 && transvarflowcoverstatus[i] == 1);
    11286 assert(snf->transvarvubcoefs[i] > 0.0);
    11287
    11288 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
    11289 {
    11290 liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
    11291 liftingdata->mp = MIN(liftingdata->mp, snf->transvarvubcoefs[i]);
    11292 }
    11293 else
    11294 {
    11295 SCIPquadprecSumQD(sumC1LE, sumC1LE, snf->transvarvubcoefs[i]);
    11296 }
    11297 break;
    11298 default:
    11299 assert(s == 2);
    11300 continue;
    11301 }
    11302 }
    11303
    11304 if( SCIPisInfinity(scip, liftingdata->mp) )
    11305 {
    11306 SCIPfreeBufferArray(scip, &liftingdata->m);
    11307 return SCIP_OKAY;
    11308 }
    11309
    11310 SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->M, liftingdata->r + 1) );
    11311
    11312 *valid = TRUE;
    11313
    11314 SCIPquadprecSumQQ(tmp, sumC1LE, sumN2mC2LE);
    11315 liftingdata->ml = MIN(lambda, QUAD_TO_DBL(tmp));
    11316 SCIPquadprecSumQD(tmp, sumC2, snf->transrhs);
    11317 liftingdata->d1 = QUAD_TO_DBL(tmp);
    11318 SCIPquadprecSumQQ(tmp, tmp, sumN2mC2GT);
    11319 SCIPquadprecSumQQ(tmp, tmp, sumN2mC2LE);
    11320 liftingdata->d2 = QUAD_TO_DBL(tmp);
    11321
    11322 SCIPsortDownReal(liftingdata->m, liftingdata->r);
    11323
    11324 /* compute M[i] = sum_{i \in [1,r]} m[i] where m[*] is sorted decreasingly and M[0] = 0 */
    11325 QUAD_ASSIGN(tmp, 0.0);
    11326 for( i = 0; i < liftingdata->r; ++i)
    11327 {
    11328 liftingdata->M[i] = QUAD_TO_DBL(tmp);
    11329 SCIPquadprecSumQD(tmp, tmp, liftingdata->m[i]);
    11330 }
    11331
    11332 liftingdata->M[liftingdata->r] = QUAD_TO_DBL(tmp);
    11333
    11334 SCIP_UNUSED( SCIPsortedvecFindDownReal(liftingdata->m, liftingdata->mp, liftingdata->r, &liftingdata->t) );
    11335 assert(liftingdata->m[liftingdata->t] == liftingdata->mp || SCIPisInfinity(scip, liftingdata->mp)); /*lint !e777*/
    11336
    11337 /* compute t largest index sucht that m_t = mp
    11338 * note that liftingdata->m[t-1] == mp due to zero based indexing of liftingdata->m
    11339 */
    11340 ++liftingdata->t;
    11341 while( liftingdata->t < liftingdata->r && liftingdata->m[liftingdata->t] == liftingdata->mp ) /*lint !e777*/
    11342 ++liftingdata->t;
    11343
    11344 liftingdata->lambda = lambda;
    11345
    11346 return SCIP_OKAY;
    11347}
    11348
    11349/** destroy data used for the sequence independent lifting */
    11350static
    11352 SCIP* scip, /**< SCIP data structure */
    11353 LIFTINGDATA* liftingdata /**< pointer to lifting function struct */
    11354 )
    11355{
    11356 SCIPfreeBufferArray(scip, &liftingdata->M);
    11357 SCIPfreeBufferArray(scip, &liftingdata->m);
    11358}
    11359
    11360/** store the simple lifted flowcover cut defined by the given data in the given arrays
    11361 * the array for storing the cut coefficients must be all zeros
    11362 */
    11363static
    11365 SCIP* scip, /**< SCIP data structure */
    11366 SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
    11367 SCIP_AGGRROW* aggrrow, /**< aggrrow used to construct SNF relaxation */
    11368 int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
    11369 SCIP_Real lambda, /**< lambda */
    11370 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    11371 SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
    11372 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    11373 int* nnz, /**< number of non-zeros in cut */
    11374 SCIP_Bool* success /**< was the cut successfully generated */
    11375 )
    11376{
    11377 SCIP_Real QUAD(rhs);
    11378 LIFTINGDATA liftingdata;
    11379 int i;
    11380
    11381 SCIP_CALL( computeLiftingData(scip, snf, flowcoverstatus, lambda, &liftingdata, success) );
    11382 if( ! *success )
    11383 return SCIP_OKAY;
    11384 assert( liftingdata.m != NULL );
    11385 assert( liftingdata.M != NULL );
    11386 assert( liftingdata.lambda != SCIP_INVALID ); /*lint !e777*/
    11387 assert( liftingdata.r >= 0 );
    11388 assert( liftingdata.t >= 0 );
    11389 assert( liftingdata.mp != SCIP_INVALID ); /*lint !e777*/
    11390
    11391 QUAD_ASSIGN(rhs, liftingdata.d1);
    11392
    11393 *nnz = 0;
    11394
    11395 for( i = 0; i < snf->ntransvars; ++i )
    11396 {
    11397 int s = (snf->transvarcoefs[i] + 1) + (flowcoverstatus[i] + 1)/2;
    11398
    11399 switch(s)
    11400 {
    11401 case 0: /* var is in N2 \ C2 */
    11402 if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
    11403 {
    11404 /* var is in L- */
    11405 if( snf->origbinvars[i] != -1 )
    11406 {
    11407 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
    11408 cutinds[*nnz] = snf->origbinvars[i];
    11409 cutcoefs[snf->origbinvars[i]] = -lambda;
    11410 ++(*nnz);
    11411 }
    11412 else
    11413 {
    11414 SCIPquadprecSumQD(rhs, rhs, lambda);
    11415 }
    11416 }
    11417 else
    11418 {
    11419 /* var is in L-- */
    11420 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
    11421 {
    11422 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
    11423 cutinds[*nnz] = snf->origcontvars[i];
    11424 cutcoefs[snf->origcontvars[i]] = -snf->aggrcoefscont[i];
    11425 ++(*nnz);
    11426 }
    11427
    11428 if( snf->origbinvars[i] != -1 && snf->aggrcoefsbin[i] != 0.0 )
    11429 {
    11430 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
    11431 cutinds[*nnz] = snf->origbinvars[i];
    11432 cutcoefs[snf->origbinvars[i]] = -snf->aggrcoefsbin[i];
    11433 ++(*nnz);
    11434 }
    11435
    11436 SCIPquadprecSumQD(rhs, rhs, snf->aggrconstants[i]);
    11437 }
    11438 break;
    11439 case 1: /* var is in C2 */
    11440 {
    11441 assert(snf->transvarvubcoefs[i] > 0.0);
    11442 assert(snf->transvarcoefs[i] == -1 && flowcoverstatus[i] == 1);
    11443
    11444 if( snf->origbinvars[i] != -1 )
    11445 {
    11446 SCIP_Real liftedbincoef = evaluateLiftingFunction(scip, &liftingdata, snf->transvarvubcoefs[i]);
    11447 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
    11448 if( liftedbincoef != 0.0 )
    11449 {
    11450 cutinds[*nnz] = snf->origbinvars[i];
    11451 cutcoefs[snf->origbinvars[i]] = -liftedbincoef;
    11452 ++(*nnz);
    11453 SCIPquadprecSumQD(rhs, rhs, -liftedbincoef);
    11454 }
    11455 }
    11456 break;
    11457 }
    11458 case 2: /* var is in N1 \ C1 */
    11459 {
    11460 int alpha;
    11461 SCIP_Real beta;
    11462
    11463 assert(snf->transvarcoefs[i] == 1 && flowcoverstatus[i] == -1);
    11464
    11465 getAlphaAndBeta(scip, &liftingdata, snf->transvarvubcoefs[i], &alpha, &beta);
    11466 assert(alpha == 0 || alpha == 1);
    11467
    11468 if( alpha == 1 )
    11469 {
    11470 SCIP_Real QUAD(binvarcoef);
    11471 assert(beta > 0.0);
    11472
    11473 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
    11474 {
    11475 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
    11476 cutinds[*nnz] = snf->origcontvars[i];
    11477 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
    11478 ++(*nnz);
    11479 }
    11480
    11481 SCIPquadprecSumDD(binvarcoef, snf->aggrcoefsbin[i], -beta);
    11482 if( snf->origbinvars[i] != -1 )
    11483 {
    11484 SCIP_Real tmp;
    11485
    11486 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
    11487
    11488 tmp = QUAD_TO_DBL(binvarcoef);
    11489 if( tmp != 0.0 )
    11490 {
    11491 cutinds[*nnz] = snf->origbinvars[i];
    11492 cutcoefs[snf->origbinvars[i]] = tmp;
    11493 ++(*nnz);
    11494 }
    11495 }
    11496 else
    11497 {
    11498 SCIPquadprecSumQQ(rhs, rhs, -binvarcoef);
    11499 }
    11500
    11501 SCIPquadprecSumQD(rhs, rhs, -snf->aggrconstants[i]);
    11502 }
    11503 break;
    11504 }
    11505 case 3: /* var is in C1 */
    11506 {
    11507 SCIP_Real bincoef = snf->aggrcoefsbin[i];
    11508 SCIP_Real constant = snf->aggrconstants[i];
    11509
    11510 if( snf->origbinvars[i] != -1 && SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
    11511 {
    11512 /* var is in C++ */
    11513 SCIP_Real QUAD(tmp);
    11514 SCIP_Real QUAD(tmp2);
    11515
    11516 SCIPquadprecSumDD(tmp, snf->transvarvubcoefs[i], -lambda);
    11517
    11518 SCIPquadprecSumQD(tmp2, tmp, constant);
    11519 constant = QUAD_TO_DBL(tmp2);
    11520
    11521 SCIPquadprecSumQD(tmp2, tmp, -bincoef);
    11522 bincoef = -QUAD_TO_DBL(tmp2);
    11523 }
    11524
    11525 if( snf->origbinvars[i] != -1 && bincoef != 0.0 )
    11526 {
    11527 assert(cutcoefs[snf->origbinvars[i]] == 0.0);
    11528 cutinds[*nnz] = snf->origbinvars[i];
    11529 cutcoefs[snf->origbinvars[i]] = bincoef;
    11530 ++(*nnz);
    11531 }
    11532
    11533 if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
    11534 {
    11535 assert(cutcoefs[snf->origcontvars[i]] == 0.0);
    11536 cutinds[*nnz] = snf->origcontvars[i];
    11537 cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
    11538 ++(*nnz);
    11539 }
    11540
    11541 SCIPquadprecSumQD(rhs, rhs, -constant);
    11542 break;
    11543 }
    11544 default:
    11545 SCIPABORT();
    11546 }
    11547 }
    11548
    11549 destroyLiftingData(scip, &liftingdata);
    11550
    11551 {
    11552 SCIP_ROW** rows = SCIPgetLPRows(scip);
    11553 for( i = 0; i < aggrrow->nrows; ++i )
    11554 {
    11555 SCIP_ROW* row;
    11556 SCIP_Real rowlhs;
    11557 SCIP_Real rowrhs;
    11558 SCIP_Real slackub;
    11559 SCIP_Real slackcoef;
    11560
    11561 slackcoef = aggrrow->rowweights[i] * aggrrow->slacksign[i];
    11562 assert(slackcoef != 0.0);
    11563
    11564 /* positive slack was implicitly handled in flow cover separation */
    11565 if( slackcoef > 0.0 )
    11566 continue;
    11567
    11568 row = rows[aggrrow->rowsinds[i]];
    11569
    11570 /* add the slack's definition multiplied with its coefficient to the cut */
    11571 SCIP_CALL( varVecAddScaledRowCoefs(cutinds, cutcoefs, nnz, row, -aggrrow->rowweights[i]) );
    11572
    11573 /* retrieve sides of row */
    11574 rowlhs = row->lhs - row->constant;
    11575 rowrhs = row->rhs - row->constant;
    11576
    11577 if( row->integral )
    11578 {
    11579 rowrhs = SCIPfloor(scip, rowrhs);
    11580 rowlhs = SCIPceil(scip, rowlhs);
    11581 }
    11582
    11583 slackub = rowrhs - rowlhs;
    11584
    11585 /* move slack's constant to the right hand side, and add lambda to the right hand side if the
    11586 * upper bound of the slack is larger than lambda, since then an artifical binary variable
    11587 * for the slack would get coefficient -lambda
    11588 */
    11589 if( aggrrow->slacksign[i] == +1 )
    11590 {
    11591 SCIP_Real rhsslack;
    11592 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
    11593 assert(!SCIPisInfinity(scip, row->rhs));
    11594
    11595 rhsslack = rowrhs - SCIPgetRowMinActivity(scip, row);
    11596 slackub = -aggrrow->rowweights[i] * MIN(rhsslack, slackub);
    11597
    11598 if( SCIPisGE(scip, slackub, lambda) )
    11599 SCIPquadprecSumQD(rhs, rhs, lambda);
    11600
    11601 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowrhs);
    11602 }
    11603 else
    11604 {
    11605 SCIP_Real lhsslack;
    11606 /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
    11607 assert(!SCIPisInfinity(scip, -row->lhs));
    11608
    11609 lhsslack = SCIPgetRowMaxActivity(scip, row) - rowlhs;
    11610 slackub = aggrrow->rowweights[i] * MIN(lhsslack, slackub);
    11611
    11612 if( SCIPisGE(scip, slackub, lambda) )
    11613 SCIPquadprecSumQD(rhs, rhs, lambda);
    11614
    11615 SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowlhs);
    11616 }
    11617 }
    11618 }
    11619
    11620 *cutrhs = QUAD_TO_DBL(rhs);
    11621
    11622 /* relax rhs to zero, if it's very close to 0 */
    11623 if( *cutrhs < 0.0 && *cutrhs >= -SCIPepsilon(scip) )
    11624 *cutrhs = 0.0;
    11625
    11626 return SCIP_OKAY;
    11627}
    11628
    11629/** calculates a lifted simple generalized flow cover cut out of the weighted sum of LP rows given by an aggregation row; the
    11630 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
    11631 * participate in the cut.
    11632 * For further details we refer to:
    11633 *
    11634 * Gu, Z., Nemhauser, G. L., & Savelsbergh, M. W. (1999). Lifted flow cover inequalities for mixed 0-1 integer programs.
    11635 * Mathematical Programming, 85(3), 439-467.
    11636 *
    11637 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    11638 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    11639 *
    11640 * @pre This method can be called if @p scip is in one of the following stages:
    11641 * - \ref SCIP_STAGE_SOLVING
    11642 *
    11643 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    11644 */
    11646 SCIP* scip, /**< SCIP data structure */
    11647 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    11648 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
    11649 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    11650 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    11651 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
    11652 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
    11653 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
    11654 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
    11655 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
    11656 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
    11657 int* cutrank, /**< pointer to return rank of generated cut */
    11658 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
    11659 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
    11660 )
    11661{
    11662 int i;
    11663 int nvars;
    11664 SCIP_Bool localbdsused;
    11665 SNF_RELAXATION snf;
    11666 SCIP_Real lambda;
    11667 SCIP_Real* tmpcoefs;
    11668 int *transvarflowcoverstatus;
    11669 int nflowcovervars;
    11670 int nnonflowcovervars;
    11671
    11672 nvars = SCIPgetNVars(scip);
    11673
    11674 *success = FALSE;
    11675
    11676 /* get data structures */
    11677 SCIP_CALL( SCIPallocBufferArray(scip, &transvarflowcoverstatus, nvars) );
    11678 SCIP_CALL( allocSNFRelaxation(scip, &snf, nvars) );
    11679
    11680 SCIPdebug( printCutQuad(scip, sol, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, FALSE, aggrrow->local) );
    11681
    11682 SCIP_CALL( constructSNFRelaxation(scip, sol, boundswitch, allowlocal, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, &snf, success, &localbdsused) );
    11683
    11684 if( ! *success )
    11685 {
    11686 goto TERMINATE;
    11687 }
    11688
    11689 *cutislocal = aggrrow->local || localbdsused;
    11690
    11691 /* initialize lambda because gcc issues a stupid warning */
    11692 lambda = 0.0;
    11693 SCIP_CALL( getFlowCover(scip, &snf, &nflowcovervars, &nnonflowcovervars, transvarflowcoverstatus, &lambda, success) );
    11694
    11695 if( ! *success )
    11696 {
    11697 goto TERMINATE;
    11698 }
    11699
    11700 SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, nvars) );
    11701
    11702 SCIP_CALL( generateLiftedFlowCoverCut(scip, &snf, aggrrow, transvarflowcoverstatus, lambda, tmpcoefs, cutrhs, cutinds, cutnnz, success) );
    11703 SCIPdebugMsg(scip, "computed flowcover_%lli_%i:\n", SCIPgetNLPs(scip), SCIPgetNCuts(scip));
    11704
    11705 /* if success is FALSE generateLiftedFlowCoverCut wont have touched the tmpcoefs array so we dont need to clean it then */
    11706 if( *success )
    11707 {
    11708 if( postprocess )
    11709 {
    11710 SCIP_CALL( postprocessCut(scip, *cutislocal, cutinds, tmpcoefs, cutnnz, cutrhs, success) );
    11711 }
    11712 else
    11713 {
    11714 SCIP_Real QUAD(rhs);
    11715
    11716 QUAD_ASSIGN(rhs, *cutrhs);
    11717 *success = ! removeZeros(scip, SCIPsumepsilon(scip), *cutislocal, tmpcoefs, QUAD(&rhs), cutinds, cutnnz);
    11718 *cutrhs = QUAD_TO_DBL(rhs);
    11719 }
    11720
    11721 if( *success )
    11722 {
    11723 /* store cut sparse and calculate efficacy */
    11724 for( i = 0; i < *cutnnz; ++i )
    11725 {
    11726 int j = cutinds[i];
    11727 assert(tmpcoefs[j] != 0.0);
    11728 cutcoefs[i] = tmpcoefs[j];
    11729 tmpcoefs[j] = 0.0;
    11730 }
    11731
    11732 if( cutefficacy != NULL )
    11733 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
    11734
    11735 if( cutrank != NULL )
    11736 *cutrank = aggrrow->rank + 1;
    11737 }
    11738 else
    11739 {
    11740 /* clean buffer array */
    11741 for( i = 0; i < *cutnnz; ++i )
    11742 {
    11743 int j = cutinds[i];
    11744 assert(tmpcoefs[j] != 0.0);
    11745 tmpcoefs[j] = 0.0;
    11746 }
    11747 }
    11748 }
    11749
    11750 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
    11751
    11752 TERMINATE:
    11754 SCIPfreeBufferArray(scip, &transvarflowcoverstatus);
    11755
    11756 return SCIP_OKAY;
    11757}
    11758
    11759/* =========================================== knapsack cover =========================================== */
    11760
    11761/** Relax the row to a possibly fractional knapsack row containing no integer or continuous variables
    11762 * and only having positive coefficients for binary variables. General integer and continuous variables
    11763 * are complemented with variable or simple bounds such that their coefficient becomes positive and then
    11764 * it is relaxed to zero.
    11765 * All remaining binary variables are complemented with simple upper or lower bounds such that their
    11766 * coefficient becomes positive.
    11767 */
    11768static
    11770 SCIP* scip, /**< SCIP data structure */
    11771 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    11772 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    11773 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    11774 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
    11775 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    11776 int* nnz, /**< number of non-zeros in cut */
    11777 int* varsign, /**< stores the sign of the transformed variable in summation */
    11778 int* boundtype, /**< stores the bound used for transformed variable:
    11779 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    11780 SCIP_Bool* localbdsused, /**< pointer to store whether local bounds were used in transformation */
    11781 SCIP_Bool* success /**< stores whether the row could successfully be transformed into a knapsack constraint.
    11782 * Returns FALSE in case a continuous or general integer variable is unbounded in the
    11783 * required direction. */
    11784 )
    11785{
    11786 SCIP_Real* bestbds;
    11787 int i;
    11788 int aggrrowbinstart;
    11789 int firstnonbinvar;
    11790 SCIP_VAR** vars;
    11791
    11792 assert(varsign != NULL);
    11793 assert(boundtype != NULL);
    11794 assert(success != NULL);
    11795 assert(localbdsused != NULL);
    11796
    11797 *success = FALSE;
    11798
    11799 /* allocate temporary memory to store best bounds and bound types */
    11800 SCIP_CALL( SCIPallocBufferArray(scip, &bestbds, 2*(*nnz)) );
    11801
    11802 /* start with continuous variables, because using variable bounds can affect the untransformed binary
    11803 * variables, and these changes have to be incorporated in the transformation of the binary variables
    11804 * (binary variables have the smallest problem indices!)
    11805 */
    11806 SCIPsortDownInt(cutinds, *nnz);
    11807
    11808 vars = SCIPgetVars(scip);
    11809 firstnonbinvar = SCIPgetNBinVars(scip);
    11810
    11811 /* determine best bounds for the continuous and general integer variables such that they will have
    11812 * a positive coefficient in the transformation */
    11813 for( i = 0; i < *nnz && cutinds[i] >= firstnonbinvar; ++i )
    11814 {
    11815 SCIP_Real QUAD(coef);
    11816 int v = cutinds[i];
    11817
    11818 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
    11819
    11820 if( QUAD_TO_DBL(coef) > 0.0 )
    11821 {
    11822 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable
    11823 * so that it will have a positive coefficient */
    11824 SCIP_CALL( findBestLb(scip, vars[v], sol, SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS ? 1 : 0, allowlocal, bestbds + i, boundtype + i) );
    11825
    11826 /* cannot transform into knapsack */
    11827 if( SCIPisInfinity(scip, -bestbds[i]) )
    11828 goto TERMINATE;
    11829
    11830 varsign[i] = +1;
    11831 }
    11832 else if( QUAD_TO_DBL(coef) < 0.0 )
    11833 {
    11834 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable
    11835 * so that it will have a positive coefficient */
    11836 SCIP_CALL( findBestUb(scip, vars[v], sol, SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS ? 1 : 0, allowlocal, bestbds + i, boundtype + i) );
    11837
    11838 /* cannot transform into knapsack */
    11839 if( SCIPisInfinity(scip, bestbds[i]) )
    11840 goto TERMINATE;
    11841
    11842 varsign[i] = -1;
    11843 }
    11844 }
    11845
    11846 /* remember start of integer variables in the aggrrow */
    11847 aggrrowbinstart = i;
    11848
    11849 /* perform bound substitution for continuous variables */
    11850 for( i = 0; i < aggrrowbinstart; ++i )
    11851 {
    11852 SCIP_Real QUAD(coef);
    11853 int v = cutinds[i];
    11854
    11855 performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestbds[i], v, localbdsused);
    11856
    11857 /* relax non-binary coefficient to zero after bound substitution */
    11858 QUAD_ASSIGN(coef, 0.0);
    11859 QUAD_ARRAY_STORE(cutcoefs, v, coef);
    11860 }
    11861
    11862 assert(i == aggrrowbinstart);
    11863
    11864 /* remove non-binary variables because their coefficients have been set to zero after bound substitution */
    11865 if( aggrrowbinstart != 0 )
    11866 {
    11867 *nnz -= aggrrowbinstart;
    11868 BMSmoveMemoryArray(cutinds, cutinds + aggrrowbinstart, *nnz);
    11869 }
    11870 i = 0;
    11871
    11872 /* after doing bound substitution of non-binary vars, some coefficients of binary vars might have changed, so here we
    11873 * remove the ones that became 0 if any; also, we need that all remaining binary vars have positive coefficients,
    11874 * thus we perform bound substitution with simple bounds (i.e. complementing) to achieve this.
    11875 */
    11876 while( i < *nnz )
    11877 {
    11878 SCIP_Real QUAD(coef);
    11879 SCIP_Real bestlb;
    11880 SCIP_Real bestub;
    11881 SCIP_Bool setzero;
    11882 int v = cutinds[i];
    11883
    11884 assert(SCIPvarGetType(vars[v]) == SCIP_VARTYPE_BINARY && !SCIPvarIsImpliedIntegral(vars[v]));
    11885
    11886 assert(v < firstnonbinvar);
    11887 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
    11888
    11889 /* due to variable bound usage for bound substitution of continuous variables cancellation may have occurred */
    11890 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
    11891 {
    11892 /* do not increase i, since last element is copied to the i-th position */
    11893 setzero = TRUE;
    11894 }
    11895 else
    11896 {
    11897 /* perform bound substitution */
    11898 if( QUAD_TO_DBL(coef) < 0.0 )
    11899 {
    11900 SCIP_CALL( findBestUb(scip, vars[v], sol, 0, allowlocal, &bestub, boundtype + i) );
    11901
    11902 if( SCIPisZero(scip, bestub) )
    11903 {
    11904 /* binary variable is fixed to zero */
    11905 setzero = TRUE;
    11906 *localbdsused = *localbdsused || (boundtype[i] == -2);
    11907 }
    11908 else
    11909 {
    11910 varsign[i] = -1;
    11911
    11912 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestub, v, localbdsused);
    11913 QUAD_ARRAY_STORE(cutcoefs, v, -coef);
    11914 setzero = FALSE;
    11915 }
    11916 }
    11917 else
    11918 {
    11919 SCIP_CALL( findBestLb(scip, vars[v], sol, 0, allowlocal, &bestlb, boundtype + i) );
    11920
    11921 if( !SCIPisZero(scip, bestlb) )
    11922 {
    11923 /* binary variable is fixed to one */
    11924 performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestlb, v, localbdsused);
    11925 setzero = TRUE;
    11926 }
    11927 else
    11928 {
    11929 varsign[i] = +1;
    11930 setzero = FALSE;
    11931 }
    11932 }
    11933
    11934 assert(boundtype[i] == -1 || boundtype[i] == -2);
    11935 }
    11936
    11937 /* increase i or remove zero coefficient (i.e. var with 0 coef) by shifting last nonzero to current position */
    11938 if( setzero )
    11939 {
    11940 QUAD_ASSIGN(coef, 0.0);
    11941 QUAD_ARRAY_STORE(cutcoefs, v, coef);
    11942 --(*nnz);
    11943 cutinds[i] = cutinds[*nnz];
    11944 }
    11945 else
    11946 ++i;
    11947 }
    11948
    11949 /* relax rhs to zero if it is close to but slightly below zero */
    11950 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    11951 QUAD_ASSIGN(*cutrhs, 0.0);
    11952
    11953 *success = TRUE;
    11954 TERMINATE:
    11955 /*free temporary memory */
    11956 SCIPfreeBufferArray(scip, &bestbds);
    11957
    11958 return SCIP_OKAY;
    11959}
    11960
    11961/** determines the initial cover for the given (fractional) knapsack row */
    11962static
    11964 SCIP* scip, /**< SCIP datastructure */
    11965 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    11966 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    11967 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    11968 SCIP_Real cutrhs, /**< pointer to the right hand side of the cut */
    11969 int cutnnz, /**< pointer to the number of non-zeros in the cut */
    11970 int* varsign, /**< sign of coefficients for each nonzero in the row be transformation */
    11971 int* coverstatus, /**< array to return the coverstatus for each variable in the knapsack row */
    11972 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
    11973 SCIP_Real* covervals, /**< coefficient value of each variable in the cover */
    11974 int* coversize, /**< pointer to return number of variables in the cover;
    11975 * matches the length of the associated arrays */
    11976 QUAD(SCIP_Real* coverweight) /**< pointer to return the weight of the cover;
    11977 * the weight is the sum of the coefficient values of variables in the cover */
    11978 )
    11979{
    11980 SCIP_VAR** vars;
    11981 int k;
    11982 int j;
    11983 QUAD_ASSIGN(*coverweight, 0);
    11984 *coversize = 0;
    11985 j = cutnnz-1;
    11986 vars = SCIPgetVars(scip);
    11987
    11988 for( k = 0; k < cutnnz; ++k )
    11989 {
    11990 SCIP_Real solval;
    11991 int v = cutinds[k];
    11992 SCIP_Real QUAD(coef);
    11993 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
    11994
    11995 solval = SCIPgetSolVal(scip, sol, vars[v]);
    11996 if( varsign[k] == -1 )
    11997 solval = 1 - solval;
    11998
    11999 if( SCIPisFeasEQ(scip, solval, 1.0) )
    12000 {
    12001 /* every variable with solution value 1 is forced into the cover */
    12002 coverpos[*coversize] = k;
    12003 covervals[*coversize] = QUAD_TO_DBL(coef);
    12004 coverstatus[k] = 1;
    12005 *coversize += 1;
    12006 SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
    12007 }
    12008 else
    12009 {
    12010 coverpos[j] = k;
    12011 covervals[j] = solval * QUAD_TO_DBL(coef);
    12012 coverstatus[k] = 0;
    12013 j -= 1;
    12014 }
    12015 }
    12016
    12017 /* Use these two arrays to sort the variables by decreasing contribution
    12018 * and pick them greedily in the while loop below until they are a cover.
    12019 * Since the cover does not need to be minimal we do not need to remove any of the
    12020 * variables with a high activity contribution even if they are not necessary after
    12021 * picking the last variable.
    12022 */
    12023 SCIPsortDownRealInt(covervals + (*coversize), coverpos + (*coversize), cutnnz - (*coversize));
    12024
    12025 /* overwrite covervals with the coefficients of the variables in the cover
    12026 * as we need to sort decreasingly by those again for the lifting
    12027 */
    12028 while( *coversize < cutnnz &&
    12029 SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) )
    12030 {
    12031 int v;
    12032 SCIP_Real QUAD(coef);
    12033 k = coverpos[*coversize];
    12034 v = cutinds[k];
    12035 coverstatus[k] = 1;
    12036 QUAD_ARRAY_LOAD(coef, cutcoefs, v);
    12037 covervals[*coversize] = QUAD_TO_DBL(coef);
    12038 SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
    12039 *coversize += 1;
    12040 }
    12041
    12042 /* there is no cover */
    12043 if( SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) || *coversize == 0 )
    12044 return FALSE;
    12045
    12046 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(*coverweight), cutrhs);
    12047 assert(*coversize > 0);
    12048
    12049 return TRUE;
    12050}
    12051
    12052/** prepares the data needed to evaluate the lifting function */
    12053static
    12055 SCIP* scip, /**< SCIP datastructure */
    12056 SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
    12057 int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
    12058 QUAD(SCIP_Real cutrhs), /**< pointer to the right hand side of the cut */
    12059 int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
    12060 int coversize, /**< number of variables in the cover */
    12061 QUAD(SCIP_Real coverweight), /**< weight of cover */
    12062 SCIP_Real* covervals, /**< coefficient value of each variable in the cover;
    12063 * on output stores the running sum of S^-(*) values */
    12064 int* coverstatus, /**< coverstatus for each variable in the cover. After calling this function
    12065 * variables in C^- will have the value -1, variables in C^+ the value 1,
    12066 * and all variables outside the cover keep the value 0. */
    12067 QUAD(SCIP_Real* abar), /**< pointer to store the reciprocal value of \bar{a} */
    12068 int* cplussize /**< pointer to store the size of C^+ */
    12069 )
    12070{
    12071 int k;
    12072 SCIP_Real QUAD(tmp);
    12073 SCIP_Real QUAD(sigma);
    12074
    12075 /* Now compute \bar{a}, the unique rational number such that for the cover C it holds that
    12076 * b = \sum_{a_i \in C} \min(\bar{a}, a_i).
    12077 * For that we need to sort by decreasing coefficients of the variables in the cover.
    12078 * After the sorting the covervals array is free to be reused.
    12079 */
    12080 SCIPsortDownRealInt(covervals, coverpos, coversize);
    12081
    12082 /* Now follows Algorithm 1 in the paper to compute \bar{a} */
    12083
    12084 /* set \bar{a} = l_1 */
    12085 QUAD_ARRAY_LOAD(*abar, cutcoefs, cutinds[coverpos[0]]);
    12086 SCIPquadprecSumQQ(sigma, coverweight, -cutrhs);
    12087
    12088 for( k = 1; k < coversize; ++k )
    12089 {
    12090 SCIP_Real QUAD(lkplus1);
    12091 SCIP_Real QUAD(kdelta);
    12092
    12093 /* load next coefficient l_{k+1} in sorted order of cover */
    12094 QUAD_ARRAY_LOAD(lkplus1, cutcoefs, cutinds[coverpos[k]]);
    12095
    12096 /* Let \delta = \bar{a} - l_{k+1} and compute k * \delta */
    12097 SCIPquadprecSumQQ(kdelta, *abar, -lkplus1);
    12098 SCIPquadprecProdQD(kdelta, kdelta, k);
    12099
    12100 /* Set tmp = k * \delta - \sigma to check condition k * \delta < \sigma by tmp < 0 */
    12101 SCIPquadprecSumQQ(tmp, kdelta, -sigma);
    12102 if( QUAD_TO_DBL(tmp) < 0.0 )
    12103 {
    12104 /* Set \bar{a} = l_{k+1} and \sigma = \sigma - k*\delta */
    12105 QUAD_ASSIGN_Q(*abar, lkplus1);
    12106 SCIPquadprecSumQQ(sigma, sigma, -kdelta);
    12107 }
    12108 else
    12109 {
    12110 /* Set \bar{a} = \bar{a} - \sigma / k and \sigma = 0; break; */
    12111 SCIP_Real minusoneoverk = -1.0 / k;
    12112 SCIPquadprecProdQD(sigma, sigma, minusoneoverk);
    12113 SCIPquadprecSumQQ(*abar, *abar, sigma);
    12114 QUAD_ASSIGN(sigma, 0.0);
    12115 break;
    12116 }
    12117 }
    12118
    12119 if( QUAD_TO_DBL(sigma) > 0.0 )
    12120 {
    12121 SCIP_Real oneoverc = 1.0 / coversize;
    12122 SCIPquadprecProdQD(*abar, cutrhs, oneoverc);
    12123 }
    12124
    12125 /* now we partition C into C^+ and C^-, where C^+ are all the elements of C whose weight is strictly larger than
    12126 * \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
    12127 * compute S^-(h) = sum of the h largest a_i^- and store S^-(h+1) in in covervals[h], for k = 0, ..., coversize - 1
    12128 * (S^-(0) = 0 so it doesn't need to be stored; we use S to compute the lifted cut, see below)
    12129 * we remember which elements of C^- in coverstatus, so that element in C^+ have coverstatus 1 and
    12130 * elements in C^- have coverstatus -1 (elements not in C have coverstatus 0)
    12131 */
    12132 QUAD_ASSIGN(tmp, 0.0);
    12133 *cplussize = 0;
    12134 for( k = 0; k < coversize; ++k )
    12135 {
    12136 SCIP_Real QUAD(coef);
    12137 SCIP_Real QUAD(coefminusabar);
    12138
    12139 QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[coverpos[k]]);
    12140 SCIPquadprecSumQQ(coefminusabar, coef, -*abar);
    12141 if( QUAD_TO_DBL(coefminusabar) > 0.0 )
    12142 {
    12143 /* coefficient is in C^+ because it is greater than \bar{a} and contributes only \bar{a} to the sum */
    12144 SCIPquadprecSumQQ(tmp, tmp, *abar);
    12145
    12146 /* rather be on the safe side in numerical corner cases and relax the coefficient to exactly \bar{a}.
    12147 * In that case the coefficient is not treated as in C^+ but as being <= \bar{a} and therefore in C^-.
    12148 */
    12149 if( QUAD_TO_DBL(coefminusabar) > SCIPfeastol(scip) )
    12150 ++(*cplussize);
    12151 else
    12152 coverstatus[coverpos[k]] = -1;
    12153 }
    12154 else
    12155 {
    12156 /* coefficient is in C^- because it is smaller or equal to \bar{a} */
    12157 coverstatus[coverpos[k]] = -1;
    12158 SCIPquadprecSumQQ(tmp, tmp, coef);
    12159 }
    12160 covervals[k] = QUAD_TO_DBL(tmp);
    12161 SCIPdebugMsg(scip, "S^-(%d) = %g\n", k + 1, covervals[k]);
    12162 }
    12163
    12164 /* set abar to its reciprocal for faster computation of the lifting coefficients */
    12165 SCIPquadprecDivDQ(*abar, 1, *abar);
    12166}
    12167
    12168/** evaluate the lifting function based on the given values */
    12169static
    12171 SCIP* scip, /**< SCIP datastructure */
    12172 QUAD(SCIP_Real x), /**< value to evaluate the lifting function at */
    12173 QUAD(SCIP_Real abar), /**< the reciprocal value of \bar{a} */
    12174 SCIP_Real* covervals, /**< the running sum of S^-(*) values */
    12175 int coversize, /**< the size of the cover */
    12176 int cplussize, /**< the size of C^+ */
    12177 SCIP_Real* scale /**< pointer to update the scale to integrality when a fractional value is returned */
    12178 )
    12179{
    12180 SCIP_Real QUAD(tmp);
    12181 SCIP_Real QUAD(hfrac);
    12182 SCIP_Real cutcoef;
    12183 SCIP_Real hreal;
    12184 int h;
    12185
    12186 /* the lifted value is at least the coeficient (a_k) divided by \bar{a} because the largest value
    12187 * contributed to the running sum stored in C is \bar{a}
    12188 * therefore we start the search for the correct h at floor(a_k / \bar{a})
    12189 */
    12190
    12191 SCIPdebugMsg(scip, "coef is %g, coversize is %d\n", QUAD_TO_DBL(x), coversize );
    12192
    12193 SCIPquadprecProdQQ(hfrac, x, abar);
    12194
    12195 /* if the coefficient is below \bar{a}, i.e. a / \bar{a} < 1 then g(a_k) = 0, otherwise g(a_k) > 0 */
    12196 if( QUAD_TO_DBL(hfrac) < 1 )
    12197 return 0.0;
    12198
    12199 /* we perform h = MIN(h, coversize) in floating-point first because on some instances h was seen to exceed the range
    12200 * of int */
    12201 hreal = SCIPfloor(scip, QUAD_TO_DBL(hfrac));
    12202 if( hreal > (SCIP_Real)coversize )
    12203 h = coversize;
    12204 else
    12205 h = (int)hreal;
    12206
    12207 SCIPquadprecSumQD(hfrac, hfrac, -h);
    12208
    12209 assert(h > 0);
    12210 if( h < cplussize && ABS(QUAD_TO_DBL(hfrac)) <= QUAD_EPSILON )
    12211 {
    12212 /* cutcoef can be increased by 0.5 because it is a multiple of \bar{a}
    12213 * (This is the first non-dominated lifting function presented in the paper)
    12214 */
    12215 cutcoef = 0.5;
    12216 *scale = 2.0;
    12217 }
    12218 else
    12219 cutcoef = 0.0;
    12220
    12221 /* decrease by one to make sure rounding errors or coefficients that are larger than the right hand side by themselves
    12222 * did not push h too far */
    12223 h--;
    12224
    12225 /* now increase coefficient to its lifted value based on its size relative to the S^- values.
    12226 * The coefficient a_i is lifted to the unique integer h such that S^-(h) < a_i <= S^-(h+1).
    12227 * (todo: variables that have a coefficient above the right hand side can get an arbitrarily large coefficient but can
    12228 * also be trivially fixed using the base row. Currently they get the coefficient |C| which is 1 above the right hand
    12229 * side in the cover cut so that they can still be trivially fixed by propagating the cover cut.
    12230 * We do not want to apply fixings here though because the LP should stay flushed during separation.
    12231 * Possibly add a parameter to return additional fixings to the caller of the SCIPcalc*() functions in here
    12232 * and the caller can add them as cuts to the sepastore or we add them to the sepastore here?)
    12233 */
    12234 while( h < coversize )
    12235 {
    12236 SCIPquadprecSumQD(tmp, x, -covervals[h]); /* recall: covervals[h] = S^-(h+1) */
    12237 /* compare with standard epsilon tolerance since computation involves abar, which is computed like an activity */
    12238 if( !SCIPisPositive(scip, QUAD_TO_DBL(tmp)) )
    12239 break;
    12240
    12241 ++h;
    12242 }
    12243
    12244 cutcoef += h;
    12245
    12246 SCIPdebugMsg(scip, "x is %g, coversize is %d, h is %d\n", QUAD_TO_DBL(x), coversize, h );
    12247 /* the lifted coefficient is h increased possibly by 0.5 for the case checked above */
    12248 SCIPdebugMsg(scip, "lifted coef %g < %g <= %g to %g\n", h == 0 ? 0 : covervals[h-1], QUAD_TO_DBL(x),
    12249 covervals[h], cutcoef);
    12250
    12251 return cutcoef;
    12252}
    12253
    12254/** calculates a lifted knapsack cover cut out of the weighted sum of LP rows given by an aggregation row; the
    12255 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
    12256 * participate in the cut.
    12257 * For further details we refer to:
    12258 *
    12259 * Letchford, A. N., & Souli, G. (2019). On lifted cover inequalities: A new lifting procedure with unusual properties.
    12260 * Operations Research Letters, 47(2), 83-87.
    12261 *
    12262 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    12263 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    12264 *
    12265 * @pre This method can be called if @p scip is in one of the following stages:
    12266 * - \ref SCIP_STAGE_SOLVING
    12267 *
    12268 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    12269 */
    12271 SCIP* scip, /**< SCIP data structure */
    12272 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    12273 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    12274 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
    12275 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
    12276 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
    12277 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
    12278 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
    12279 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
    12280 int* cutrank, /**< pointer to return rank of generated cut */
    12281 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
    12282 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
    12283 )
    12284{
    12285 int* varsign;
    12286 int* boundtype;
    12287 int* coverstatus;
    12288 int* coverpos;
    12289 int* tmpinds;
    12290 SCIP_Real* tmpcoefs;
    12291 SCIP_Real* covervals;
    12292 SCIP_Real QUAD(rhs);
    12293 SCIP_Real QUAD(coverweight);
    12294 SCIP_Real QUAD(abar);
    12295 SCIP_Bool transformed;
    12296 SCIP_Bool local;
    12297 SCIP_Real efficacy;
    12298 SCIP_Real scale;
    12299 int k;
    12300 int nvars;
    12301 int coversize;
    12302 int cplussize;
    12303 int nnz;
    12304
    12305 assert(scip != NULL);
    12306 assert(aggrrow != NULL);
    12307 assert(cutcoefs != NULL);
    12308 assert(cutrhs != NULL);
    12309 assert(cutinds != NULL);
    12310 assert(cutnnz != NULL);
    12311 assert(cutefficacy != NULL);
    12312 assert(cutislocal != NULL);
    12313 assert(success != NULL);
    12314
    12315 *success = FALSE;
    12316
    12317 if( aggrrow->nnz == 0 )
    12318 return SCIP_OKAY;
    12319
    12320 for( k = 0; k < aggrrow->nrows; ++k )
    12321 {
    12322 /* cannot handle negative slack variables */
    12323 if( aggrrow->rowweights[k] * aggrrow->slacksign[k] < 0 )
    12324 return SCIP_OKAY;
    12325 }
    12326
    12327 /* allocate temporary memory */
    12328 nvars = SCIPgetNVars(scip);
    12329 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
    12330 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
    12331 SCIP_CALL( SCIPallocBufferArray(scip, &coverstatus, nvars) );
    12332 SCIP_CALL( SCIPallocBufferArray(scip, &covervals, nvars) );
    12333 SCIP_CALL( SCIPallocBufferArray(scip, &coverpos, nvars) );
    12334 SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
    12336
    12337 /* initialize cut with aggregation */
    12338 nnz = aggrrow->nnz;
    12339 QUAD_ASSIGN_Q(rhs, aggrrow->rhs);
    12340
    12341 BMScopyMemoryArray(tmpinds, aggrrow->inds, nnz);
    12342
    12343 for( k = 0; k < nnz; ++k )
    12344 {
    12345 SCIP_Real QUAD(coef);
    12346 int j = tmpinds[k];
    12347
    12348 QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
    12349
    12350 QUAD_HI(coef) = NONZERO(QUAD_HI(coef));
    12351 assert(QUAD_HI(coef) != 0.0);
    12352
    12353 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
    12354 }
    12355 SCIPdebugMsg(scip, "Computing lifted knapsack cover for ");
    12356 SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
    12357
    12358 /* Transform aggregated row into a (fractional, i.e. with possibly fractional weights) knapsack constraint.
    12359 * Uses simple or variable lower or upper bounds to relax out continuous and general integers
    12360 * so that only binary variables remain and complements those such that they have a positive coefficient.
    12361 */
    12362 local = aggrrow->local;
    12363 SCIP_CALL( cutsTransformKnapsackCover(scip, sol, allowlocal,
    12364 tmpcoefs, QUAD(&rhs), tmpinds, &nnz, varsign, boundtype, &local, &transformed) );
    12365
    12366 assert(allowlocal || !local);
    12367
    12368 if( !transformed )
    12369 goto TERMINATE;
    12370
    12371 SCIPdebugMsg(scip, "Transformed knapsack relaxation ");
    12372 SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
    12373
    12374 if( !computeInitialKnapsackCover(scip, sol, tmpcoefs, tmpinds, QUAD_TO_DBL(rhs), nnz, varsign, coverstatus,
    12375 coverpos, covervals, &coversize, QUAD(&coverweight)) )
    12376 goto TERMINATE;
    12377
    12378 SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(coverweight), QUAD_TO_DBL(rhs));
    12379 assert(coversize > 0);
    12380
    12381 /* by default do not scale the cut */
    12382 scale = 1.0;
    12383
    12384 if( coversize == 1 )
    12385 {
    12386 SCIP_Real QUAD(tmp);
    12387 /* cover is trivial, return the fixing as cut */
    12388 QUAD_ASSIGN(tmp, 0.0);
    12389 for( k = 0; k < nnz; ++k )
    12390 {
    12391 if( coverstatus[k] == 0 )
    12392 {
    12393 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
    12394 }
    12395 else
    12396 {
    12397 tmpinds[0] = tmpinds[k];
    12398 varsign[0] = varsign[k];
    12399 }
    12400 }
    12401
    12402 nnz = 1;
    12403 if( varsign[0] == -1 )
    12404 {
    12405 QUAD_ASSIGN(rhs, -1.0);
    12406 QUAD_ASSIGN(tmp, -1.0);
    12407 }
    12408 else
    12409 {
    12410 QUAD_ASSIGN(rhs, 0.0);
    12411 QUAD_ASSIGN(tmp, 1.0);
    12412 }
    12413
    12414 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[0], tmp);
    12415 }
    12416 else
    12417 {
    12418 SCIP_Real QUAD(tmp);
    12419
    12420 /* compute lifted cover inequality:
    12421 * sum_{i \in C^-) x_i + sum_{i \in N \ C^-) g(a_i) x_i <= c - 1
    12422 * where g(z) is equal to
    12423 * - 0 if z is 0 (irrelevant as there shouldn't be element with weight 0 in the knapsack)
    12424 * - 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
    12425 * - h if S^-(h) < z <= S^-(h+1) for some h = 0, ..., coversize -1
    12426 * the function S^- is defined above. Note that S^-(0) = 0
    12427 * we store the cut coefficients in tmpcoef
    12428 */
    12429
    12430 SCIPdebugMsg(scip, "call prepareLiftingData: \n");
    12431 /* prepare data required to evaluate lifting function */
    12432 prepareLiftingData(scip, tmpcoefs, tmpinds, QUAD(rhs), coverpos, coversize,
    12433 QUAD(coverweight), covervals, coverstatus, QUAD(&abar), &cplussize);
    12434
    12435 /* compute lifted cover inequality */
    12436 QUAD_ASSIGN(rhs, (coversize - 1));
    12437 for( k = 0; k < nnz; )
    12438 {
    12439 SCIP_Real cutcoef;
    12440 if( coverstatus[k] == -1 )
    12441 { /* variables in C^- get the coefficients 1 */
    12442 cutcoef = 1.0;
    12443 }
    12444 else
    12445 { /* variables is either in C^+ or not in the cover and its coefficient value is computed with the lifing function */
    12446 SCIP_Real QUAD(coef);
    12447
    12448 SCIPdebugMsg(scip, "load QUAD(coef) from tmpcoefs[tmpinds[k] = %d]\n",tmpinds[k]);
    12449 QUAD_ARRAY_LOAD(coef, tmpcoefs, tmpinds[k]);
    12450
    12451 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));
    12452
    12453 SCIPdebugMsg(scip, "call evaluateLiftingFunctionKnapsack:\n");
    12454 cutcoef = evaluateLiftingFunctionKnapsack(scip, QUAD(coef), QUAD(abar), covervals, coversize, cplussize, &scale);
    12455
    12456 /* if the coefficient value is zero then remove the nonzero entry and continue */
    12457 if( cutcoef == 0.0 )
    12458 {
    12459 QUAD_ASSIGN(tmp, 0.0);
    12460 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
    12461 --nnz;
    12462 coverstatus[k] = coverstatus[nnz];
    12463 tmpinds[k] = tmpinds[nnz];
    12464 varsign[k] = varsign[nnz];
    12465 continue;
    12466 }
    12467 }
    12468
    12469 /* directly undo the complementation before storing back the coefficient */
    12470 if( varsign[k] == -1 )
    12471 {
    12472 /* variable was complemented so we have cutcoef * (1-x) = cutcoef - cutcoef * x.Thus we need to adjust the rhs
    12473 * to rhs - cutcoef and flip the sign of cutcoef */
    12474 cutcoef = -cutcoef;
    12475 SCIPquadprecSumQD(rhs, rhs, cutcoef);
    12476 }
    12477
    12478 QUAD_ASSIGN(tmp, cutcoef);
    12479 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
    12480
    12481 ++k;
    12482 }
    12483 }
    12484
    12485 /* calculate the efficacy of the computed cut and store the success flag if the efficacy exceeds the
    12486 * one stored in the cutefficacy variable by the caller
    12487 */
    12488 efficacy = calcEfficacyDenseStorageQuad(scip, sol, tmpcoefs, QUAD_TO_DBL(rhs), tmpinds, nnz);
    12489 *success = SCIPisGT(scip, efficacy, *cutefficacy);
    12490
    12491 SCIPdebugMsg(scip, "FINAL LCI:");
    12492 SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
    12493
    12494 if( *success )
    12495 {
    12496 /* return the cut into the given arrays/pointers */
    12497 *cutislocal = local;
    12498 *cutrhs = scale * QUAD_TO_DBL(rhs);
    12499 *cutnnz = nnz;
    12500
    12501 /* store cut in given array in sparse representation and clean buffer array */
    12502 for( k = 0; k < nnz; ++k )
    12503 {
    12504 SCIP_Real QUAD(coef);
    12505 int j = tmpinds[k];
    12506
    12507 QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
    12508 assert(QUAD_HI(coef) != 0.0);
    12509
    12510 cutcoefs[k] = scale * QUAD_TO_DBL(coef);
    12511 cutinds[k] = j;
    12512 QUAD_ASSIGN(coef, 0.0);
    12513 QUAD_ARRAY_STORE(tmpcoefs, j, coef);
    12514 }
    12515
    12516 assert( cutefficacy != NULL );
    12517 /* calculate efficacy again to make sure it matches the coefficients after they where rounded to double values
    12518 * and after the cleanup and postprocessing step was applied. */
    12519 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, nnz);
    12520
    12521 if( cutrank != NULL )
    12522 *cutrank = aggrrow->rank + 1;
    12523 }
    12524
    12525 TERMINATE:
    12526
    12527 /* if we aborted early the tmpcoefs array needs to be cleaned */
    12528 if( !(*success) )
    12529 {
    12530 SCIP_Real QUAD(tmp);
    12531 QUAD_ASSIGN(tmp, 0.0);
    12532
    12533 for( k = 0; k < nnz; ++k )
    12534 {
    12535 QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
    12536 }
    12537 }
    12538#ifndef NDEBUG
    12539 for( k = 0; k < QUAD_ARRAY_SIZE(nvars); ++k )
    12540 {
    12541 if(tmpcoefs[k] != 0.0)
    12542 {
    12543 SCIPdebugMsg(scip, "tmpcoefs have not been reset\n");
    12544 SCIPABORT();
    12545 }
    12546 }
    12547#endif
    12548
    12549 /* free temporary memory */
    12550 SCIPfreeCleanBufferArray(scip, &tmpcoefs);
    12551 SCIPfreeBufferArray(scip, &tmpinds);
    12552 SCIPfreeBufferArray(scip, &coverpos);
    12553 SCIPfreeBufferArray(scip, &covervals);
    12554 SCIPfreeBufferArray(scip, &coverstatus);
    12555 SCIPfreeBufferArray(scip, &boundtype);
    12556 SCIPfreeBufferArray(scip, &varsign);
    12557
    12558 return SCIP_OKAY;
    12559}
    12560
    12561
    12562/* =========================================== strongcg =========================================== */
    12563
    12564/** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
    12565 * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
    12566 *
    12567 * Differs from cutsTransformMIR for continuous variables for which the lower bound must be used
    12568 * when in case their coefficient is positive and the upper bound in case their coefficient is
    12569 * negative. This forces all continuous variable to have a positive coefficient in the transformed
    12570 * row.
    12571 *
    12572 * Transform variables (lb or ub):
    12573 * \f[
    12574 * \begin{array}{llll}
    12575 * 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}\\
    12576 * 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}
    12577 * \end{array}
    12578 * \f]
    12579 * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
    12580 *
    12581 * Transform variables (vlb or vub):
    12582 * \f[
    12583 * \begin{array}{llll}
    12584 * 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.} \\
    12585 * 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.}
    12586 * \end{array}
    12587 * \f]
    12588 * 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:
    12589 * \f[
    12590 * \begin{array}{ll}
    12591 * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
    12592 * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
    12593 * \end{array}
    12594 * \f]
    12595 */
    12596static
    12598 SCIP* scip, /**< SCIP datastructure */
    12599 MIR_DATA* data, /**< the MIR data structure for this cut */
    12600 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    12601 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    12602 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    12603 int* varsign, /**< stores the sign of the transformed variable in summation */
    12604 int* boundtype, /**< stores the bound used for transformed variable:
    12605 * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
    12606 SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
    12607 SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
    12608 )
    12609{
    12610 SCIP_Real* bestlbs;
    12611 SCIP_Real* bestubs;
    12612 int* bestlbtypes;
    12613 int* bestubtypes;
    12614 SCIP_BOUNDTYPE* selectedbounds;
    12615 int totalnnz;
    12616 int s;
    12617 int i;
    12618
    12619 assert(data != NULL);
    12620 assert(varsign != NULL);
    12621 assert(boundtype != NULL);
    12622 assert(freevariable != NULL);
    12623 assert(localbdsused != NULL);
    12624
    12625 totalnnz = data->totalnnz;
    12626
    12627 *freevariable = FALSE;
    12628 *localbdsused = FALSE;
    12629
    12630 /* allocate temporary memory to store best bounds and bound types */
    12631 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, 2*totalnnz) );
    12632 SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, 2*totalnnz) );
    12633 SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, 2*totalnnz) );
    12634 SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, 2*totalnnz) );
    12635 SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, 2*totalnnz) );
    12636
    12637 /* transform the cut, one variable section at a time */
    12638 for( s = 0; s < NSECTIONS; ++s )
    12639 {
    12640 int* indices = data->secindices[s];
    12641 int cutindsstart = data->ncutinds;
    12642 int usevbds = data->usevbds[s];
    12643
    12644 i = 0;
    12645 /* Iterate over all nonzeros in the section */
    12646 while( i < data->secnnz[s] )
    12647 {
    12648 SCIP_Real QUAD(coef);
    12649 int v = indices[i];
    12650
    12651 /* due to variable bound usage, cancellation may have occurred */
    12652 QUAD_ARRAY_LOAD(coef, data->cutcoefs, v);
    12653 if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
    12654 {
    12655 QUAD_ASSIGN(coef, 0.0);
    12656 QUAD_ARRAY_STORE(data->cutcoefs, v, coef);
    12657 --data->secnnz[s];
    12658 --data->totalnnz;
    12659 indices[i] = indices[data->secnnz[s]];
    12660 /* do not increase the index */
    12661 continue;
    12662 }
    12663
    12664 int cutindex = data->ncutinds;
    12665 /* For continuous variables, we must choose the bound substitution so that they become positive in the cut */
    12666 if( !data->isenfint[s] && !data->isimplint[s] )
    12667 {
    12668 if( QUAD_TO_DBL(coef) > 0.0 )
    12669 {
    12670 SCIP_Real simplelb;
    12671
    12672 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
    12673 SCIP_CALL( findMIRBestLb(scip, data->vars[v], sol, data, usevbds, allowlocal,
    12674 bestlbs + cutindex, &simplelb, bestlbtypes + cutindex) );
    12675
    12676 /* cannot create transformation for strongcg cut */
    12677 if( SCIPisInfinity(scip, -bestlbs[cutindex]) )
    12678 {
    12679 *freevariable = TRUE;
    12680 goto TERMINATE;
    12681 }
    12682
    12683 varsign[cutindex] = +1;
    12684 selectedbounds[cutindex] = SCIP_BOUNDTYPE_LOWER;
    12685 }
    12686 else
    12687 {
    12688 SCIP_Real simpleub;
    12689
    12690 assert(QUAD_TO_DBL(coef) < 0.0);
    12691
    12692 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
    12693 SCIP_CALL( findMIRBestUb(scip, data->vars[v], sol, data, usevbds, allowlocal,
    12694 bestubs + cutindex, &simpleub, bestubtypes + cutindex) );
    12695
    12696 /* cannot create transformation for strongcg cut */
    12697 if( SCIPisInfinity(scip, bestubs[cutindex]) )
    12698 {
    12699 *freevariable = TRUE;
    12700 goto TERMINATE;
    12701 }
    12702
    12703 varsign[cutindex] = -1;
    12704 selectedbounds[cutindex] = SCIP_BOUNDTYPE_UPPER;
    12705 }
    12706 }
    12707 else if( data->isimplint[s] )
    12708 {
    12709 /* For implied integers, we still prefer to choose the bound substitution that makes them positive, but
    12710 * if we cannot manage to do so it is not an error, because we can still treat them as integer variables */
    12711 SCIP_Real simplelb;
    12712 SCIP_Real simpleub;
    12713 SCIP_Bool lowerinf;
    12714 SCIP_Bool upperinf;
    12715 SCIP_Bool positive;
    12716
    12717 /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
    12718 SCIP_CALL( findMIRBestLb(scip, data->vars[v], sol, data, usevbds, allowlocal,
    12719 bestlbs + cutindex, &simplelb, bestlbtypes + cutindex) );
    12720
    12721 /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
    12722 SCIP_CALL( findMIRBestUb(scip, data->vars[v], sol, data, usevbds, allowlocal,
    12723 bestubs + cutindex, &simpleub, bestubtypes + cutindex) );
    12724
    12725 lowerinf = SCIPisInfinity(scip, -bestlbs[cutindex]);
    12726 upperinf = SCIPisInfinity(scip, bestubs[cutindex]);
    12727 positive = QUAD_TO_DBL(coef) > 0.0;
    12728
    12729 if( lowerinf && upperinf )
    12730 {
    12731 /* we found a free variable in the row with non-zero coefficient
    12732 * -> MIR row can't be transformed in standard form
    12733 */
    12734 *freevariable = TRUE;
    12735 goto TERMINATE;
    12736 }
    12737
    12738 /* preferably, choose bound that makes value positive */
    12739 if( (positive && lowerinf) || (!positive && !upperinf) )
    12740 {
    12741 varsign[cutindex] = -1;
    12742 selectedbounds[cutindex] = SCIP_BOUNDTYPE_UPPER;
    12743 }
    12744 else
    12745 {
    12746 varsign[cutindex] = +1;
    12747 selectedbounds[cutindex] = SCIP_BOUNDTYPE_LOWER;
    12748 }
    12749 }
    12750 else
    12751 {
    12752 /* For explicit integers, we have no restrictions. */
    12753 SCIP_CALL( determineBestBounds(scip, data->vars[v], sol, data, boundswitch, usevbds, allowlocal, FALSE, FALSE,
    12754 NULL, NULL, bestlbs + cutindex, bestubs + cutindex,
    12755 bestlbtypes + cutindex, bestubtypes + cutindex, selectedbounds + cutindex, freevariable) );
    12756
    12757 if( *freevariable)
    12758 goto TERMINATE;
    12759 }
    12760
    12761 data->cutinds[cutindex] = v;
    12762 ++data->ncutinds;
    12763
    12764 ++i;
    12765 }
    12766
    12767 /* perform bound substitution for all nonzeros in the section */
    12768 for( i = cutindsstart; i < data->ncutinds; ++i )
    12769 {
    12770 SCIP_Real bestbnd;
    12771 int v = data->cutinds[i];
    12772
    12773 if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
    12774 {
    12775 assert(!SCIPisInfinity(scip, -bestlbs[i]));
    12776
    12777 /* use lower bound as transformation bound: x'_j := x_j - lb_j */
    12778 boundtype[i] = bestlbtypes[i];
    12779 varsign[i] = +1;
    12780 bestbnd = bestlbs[i];
    12781 }
    12782 else
    12783 {
    12784 assert(!SCIPisInfinity(scip, bestubs[i]));
    12785
    12786 /* use upper bound as transformation bound: x'_j := ub_j - x_j */
    12787 boundtype[i] = bestubtypes[i];
    12788 varsign[i] = -1;
    12789 bestbnd = bestubs[i];
    12790 }
    12791
    12792 doMIRBoundSubstitution(scip, data, varsign[i], boundtype[i], bestbnd, v, localbdsused);
    12793 }
    12794 }
    12795
    12796 /* relax rhs to zero if it is close to */
    12797 if( QUAD_TO_DBL(data->cutrhs) < 0.0 && QUAD_TO_DBL(data->cutrhs) >= -SCIPepsilon(scip) )
    12798 QUAD_ASSIGN(data->cutrhs, 0.0);
    12799
    12800 TERMINATE:
    12801
    12802 /* If we terminate early, we need to make sure all the zeros in the cut coefficient array are cancelled */
    12803 if( *freevariable )
    12804 {
    12805 int j;
    12806 int k;
    12807
    12808 data->ncutinds = 0;
    12809 for( j = 0; j < NSECTIONS; ++j )
    12810 {
    12811 int* indexlist = data->secindices[j];
    12812 for( k = 0; k < data->secnnz[j]; ++k )
    12813 {
    12814 data->cutinds[data->ncutinds] = indexlist[k];
    12815 ++data->ncutinds;
    12816 }
    12817 }
    12818 }
    12819
    12820 /*free temporary memory */
    12821 SCIPfreeBufferArray(scip, &selectedbounds);
    12822 SCIPfreeBufferArray(scip, &bestubtypes);
    12823 SCIPfreeBufferArray(scip, &bestlbtypes);
    12824 SCIPfreeBufferArray(scip, &bestubs);
    12825 SCIPfreeBufferArray(scip, &bestlbs);
    12826
    12827 return SCIP_OKAY;
    12828}
    12829
    12830/** Calculate fractionalities \f$ f_0 := b - down(b) \f$, \f$ f_j := a^\prime_j - down(a^\prime_j) \f$,
    12831 * 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
    12832 * 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$
    12833 * and derive strong CG cut \f$ \tilde{a} x^\prime \leq down(b) \f$
    12834 * \f[
    12835 * \begin{array}{rll}
    12836 * integers : & \tilde{a}_j = down(a^\prime_j) &, if \qquad f_j \leq f_0 \\
    12837 * & \tilde{a}_j = down(a^\prime_j) + p_j/(k + 1) &, if \qquad f_j > f_0 \\
    12838 * continuous:& \tilde{a}_j = 0 &, if \qquad a^\prime_j \geq 0 \\
    12839 * & \mbox{no strong CG cut found} &, if \qquad a^\prime_j < 0
    12840 * \end{array}
    12841 * \f]
    12842 *
    12843 * Transform inequality back to \f$ \hat{a}*x <= rhs \f$:
    12844 *
    12845 * (lb or ub):
    12846 * \f[
    12847 * \begin{array}{lllll}
    12848 * 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} \\
    12849 * 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}
    12850 * \end{array}
    12851 * \f]
    12852 * \f[
    12853 * and move the constant terms
    12854 * \begin{array}{rl}
    12855 * -\tilde{a}_j * lb_j == -\hat{a}_j * lb_j, & \mbox{or} \\
    12856 * \tilde{a}_j * ub_j == -\hat{a}_j * ub_j &
    12857 * \end{array}
    12858 * \f]
    12859 * to the rhs.
    12860 *
    12861 * (vlb or vub):
    12862 * \f[
    12863 * \begin{array}{lllll}
    12864 * 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)} \\
    12865 * 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)}
    12866 * \end{array}
    12867 * \f]
    12868 * move the constant terms
    12869 * \f[
    12870 * \begin{array}{rl}
    12871 * -\tilde{a}_j * dl_j == -\hat{a}_j * dl_j,& \mbox{or} \\
    12872 * \tilde{a}_j * du_j == -\hat{a}_j * du_j &
    12873 * \end{array}
    12874 * \f]
    12875 * to the rhs, and update the VB variable coefficients:
    12876 * \f[
    12877 * \begin{array}{ll}
    12878 * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j * bl_j == \hat{a}_{zl_j} - \hat{a}_j * bl_j,& \mbox{or} \\
    12879 * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j * bu_j == \hat{a}_{zu_j} - \hat{a}_j * bu_j &
    12880 * \end{array}
    12881 * \f]
    12882 */
    12883static
    12885 SCIP* scip, /**< SCIP datastructure */
    12886 MIR_DATA* data, /**< the MIR data structure for this cut */
    12887 int* varsign, /**< stores the sign of the transformed variable in summation */
    12888 int* boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub)*/
    12889 QUAD(SCIP_Real f0), /**< fractional value of rhs */
    12890 SCIP_Real k /**< factor to strengthen strongcg cut */
    12891 )
    12892{
    12893 SCIP_Real QUAD(tmp);
    12894 SCIP_Real QUAD(onedivoneminusf0);
    12895 int cutindex;
    12896 int s;
    12897 int i;
    12898
    12899 assert(data != NULL);
    12900 assert(boundtype != NULL);
    12901 assert(varsign != NULL);
    12902 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
    12903
    12904 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
    12905 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
    12906
    12907 /* Loop backwards through the sections, so that the reversing of varbound substitutions does not prematurely effect
    12908 * the coefficients of variables in other sections, because the section index of a variable bound must always be
    12909 * higher than that of the bounded variable. */
    12910 cutindex = data->ncutinds - 1;
    12911 for( s = NSECTIONS - 1; s >= 0; --s )
    12912 {
    12913 int* indices = data->secindices[s];
    12914 int nnz = data->secnnz[s];
    12915 SCIP_Bool enfintegral = data->isenfint[s];
    12916 SCIP_Bool implintegral = data->isimplint[s];
    12917
    12918 /* iterate backwards over indices in section, so we can easily shrink the section if we find zeros */
    12919 for( i = nnz - 1; i >= 0 ; --i )
    12920 {
    12921 SCIP_Real QUAD(cutaj);
    12922 SCIP_Real QUAD(aj);
    12923 SCIP_VAR* var;
    12924 int v = indices[i];
    12925 int sign;
    12926 int type;
    12927
    12928 assert(0 <= v && v < data->nvars);
    12929 assert(data->cutinds[cutindex] == v);
    12930 sign = varsign[cutindex];
    12931 assert(sign == +1 || sign == -1);
    12932 type = boundtype[cutindex];
    12933
    12934 --cutindex;
    12935
    12936 var = data->vars[v];
    12937 assert(var != NULL);
    12938 assert(SCIPvarGetProbindex(var) == v );
    12939
    12940 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
    12941
    12942 if( enfintegral || implintegral )
    12943 {
    12944 /* Variable is integral */
    12945 SCIP_Real QUAD(downaj);
    12946 SCIP_Real QUAD(fj);
    12947
    12948 /* calculate the coefficient in the retransformed cut */
    12949 QUAD_ARRAY_LOAD(aj, data->cutcoefs, v);
    12950 QUAD_SCALE(aj, sign);
    12951 SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
    12952 SCIPquadprecSumQQ(fj, aj, -downaj);
    12953 assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
    12954
    12955 if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
    12956 QUAD_ASSIGN_Q(cutaj, downaj); /* a_j */
    12957 else
    12958 {
    12959 SCIP_Real pj;
    12960
    12961 SCIPquadprecSumQQ(cutaj, fj, -f0);
    12962 SCIPquadprecProdQD(cutaj, cutaj, k);
    12963 SCIPquadprecProdQQ(cutaj, cutaj, onedivoneminusf0);
    12964 pj = SCIPceil(scip, QUAD_TO_DBL(cutaj));
    12965 assert(pj >= 0); /* should be >= 1, but due to rounding bias can be 0 if fj is almost equal to f0 */
    12966 assert(pj <= k);
    12967 SCIPquadprecDivDD(cutaj, pj, k + 1.0);
    12968 SCIPquadprecSumQQ(cutaj, cutaj, downaj);
    12969 }
    12970
    12971 QUAD_SCALE(cutaj, sign);
    12972 }
    12973 else
    12974 {
    12975 /* Variable is continuous; must always be positive in strongcg cut. It will be automatically deleted. */
    12977 assert(QUAD_TO_DBL(aj) * sign >= 0.0);
    12978 QUAD_ASSIGN(cutaj, 0.0);
    12979 }
    12980
    12981 /* remove coefficient from cut if it becomes zero */
    12982 if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
    12983 {
    12984 QUAD_ASSIGN(cutaj, 0.0);
    12985 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
    12986 --data->totalnnz;
    12987 --data->secnnz[s];
    12988 indices[i] = indices[data->secnnz[s]];
    12989 continue;
    12990 }
    12991
    12992 /* store the updated coefficient */
    12993 QUAD_ARRAY_STORE(data->cutcoefs, v, cutaj);
    12994
    12995 /* undo bound transformations. */
    12996 if( type < 0 )
    12997 {
    12998 /* standard bound */
    12999 /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
    13000 if( sign == +1 )
    13001 {
    13002 /* lower bound was used */
    13003 if( type == -1 )
    13004 {
    13005 assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
    13006 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
    13007 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    13008 }
    13009 else
    13010 {
    13011 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
    13012 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
    13013 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    13014 }
    13015 }
    13016 else
    13017 {
    13018 /* upper bound was used */
    13019 if( type == -1 )
    13020 {
    13021 assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
    13022 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
    13023 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    13024 }
    13025 else
    13026 {
    13027 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
    13028 SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
    13029 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    13030 }
    13031 }
    13032 }
    13033 else
    13034 {
    13035 /* variable bound */
    13036 SCIP_VAR** vbz;
    13037 SCIP_Real* vbb;
    13038 SCIP_Real* vbd;
    13039 SCIP_Real QUAD(zcoef);
    13040 int vbidx;
    13041 int zidx;
    13042
    13043 /* variable bound */
    13044 vbidx = type;
    13045
    13046 /* change mirrhs and cutaj of integer variable z_j of variable bound */
    13047 if( sign == +1 )
    13048 {
    13049 /* variable lower bound was used */
    13050 assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
    13051 vbz = SCIPvarGetVlbVars(var);
    13052 vbb = SCIPvarGetVlbCoefs(var);
    13053 vbd = SCIPvarGetVlbConstants(var);
    13054 }
    13055 else
    13056 {
    13057 /* variable upper bound was used */
    13058 assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
    13059 vbz = SCIPvarGetVubVars(var);
    13060 vbb = SCIPvarGetVubCoefs(var);
    13061 vbd = SCIPvarGetVubConstants(var);
    13062 }
    13063 assert(SCIPvarIsActive(vbz[vbidx]));
    13064 zidx = SCIPvarGetProbindex(vbz[vbidx]);
    13065 assert(varSection(data, zidx) > s);
    13066
    13067 SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
    13068 SCIPquadprecSumQQ(data->cutrhs, data->cutrhs, tmp);
    13069
    13070 SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
    13071 QUAD_ARRAY_LOAD(zcoef, data->cutcoefs, zidx);
    13072
    13073 /* update sparsity pattern */
    13074 if( QUAD_HI(zcoef) == 0.0 )
    13075 {
    13076 int zsection = varSection(data, zidx);
    13077 data->secindices[zsection][data->secnnz[zsection]] = zidx;
    13078 ++data->secnnz[zsection];
    13079 ++data->totalnnz;
    13080 }
    13081
    13082 SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
    13083 QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
    13084 QUAD_ARRAY_STORE(data->cutcoefs, zidx, zcoef);
    13085 assert(QUAD_HI(zcoef) != 0.0);
    13086 }
    13087 }
    13088 }
    13089
    13090 /* Finally, store the relevant data in cutinds which is the array used by the other functions */
    13091 data->ncutinds = 0;
    13092 for( s = 0; s < NSECTIONS; ++s )
    13093 {
    13094 int* indices = data->secindices[s];
    13095 int nnz = data->secnnz[s];
    13096 for( i = 0; i < nnz; ++i )
    13097 {
    13098 data->cutinds[data->ncutinds] = indices[i];
    13099 ++data->ncutinds;
    13100 }
    13101 }
    13102
    13103 return SCIP_OKAY;
    13104}
    13105
    13106/** substitute aggregated slack variables:
    13107 *
    13108 * 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
    13109 * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r] \f$.
    13110 *
    13111 * Depending on the slack's type (integral or continuous), its coefficient in the cut calculates as follows:
    13112 * \f[
    13113 * \begin{array}{rll}
    13114 * integers: & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & if \qquad f_r \leq f_0 \\
    13115 * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + p_r/(k + 1), & if \qquad f_r > f_0 \\
    13116 * continuous:& \hat{a}_r = \tilde{a}_r = 0, & if \qquad a^\prime_r \geq 0 \\
    13117 * & \mbox{no strong CG cut found}, & if \qquad a^\prime_r < 0
    13118 * \end{array}
    13119 * \f]
    13120 *
    13121 * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
    13122 */
    13123static
    13125 SCIP* scip, /**< SCIP datastructure */
    13126 SCIP_Real* weights, /**< row weights in row summation */
    13127 int* slacksign, /**< stores the sign of the row's slack variable in summation */
    13128 int* rowinds, /**< sparsity pattern of used rows */
    13129 int nrowinds, /**< number of used rows */
    13130 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
    13131 SCIP_Real* cutcoefs, /**< array of coefficients of cut */
    13132 QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
    13133 int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
    13134 int* nnz, /**< number of non-zeros in cut */
    13135 QUAD(SCIP_Real f0), /**< fractional value of rhs */
    13136 SCIP_Real k /**< factor to strengthen strongcg cut */
    13137 )
    13138{ /*lint --e{715}*/
    13139 SCIP_ROW** rows;
    13140 SCIP_Real QUAD(onedivoneminusf0);
    13141 int i;
    13142
    13143 assert(scip != NULL);
    13144 assert(weights != NULL);
    13145 assert(slacksign != NULL);
    13146 assert(rowinds != NULL);
    13147 assert(SCIPisPositive(scip, scale));
    13148 assert(cutcoefs != NULL);
    13149 assert(QUAD_HI(cutrhs) != NULL);
    13150 assert(cutinds != NULL);
    13151 assert(nnz != NULL);
    13152 assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
    13153
    13154 SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
    13155 SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
    13156
    13157 rows = SCIPgetLPRows(scip);
    13158 for( i = 0; i < nrowinds; i++ )
    13159 {
    13160 SCIP_ROW* row;
    13161 SCIP_Real QUAD(ar);
    13162 SCIP_Real QUAD(downar);
    13163 SCIP_Real QUAD(cutar);
    13164 SCIP_Real QUAD(fr);
    13165 SCIP_Real mul;
    13166 int r;
    13167
    13168 r = rowinds[i];
    13169 assert(0 <= r && r < SCIPgetNLPRows(scip));
    13170 assert(slacksign[i] == -1 || slacksign[i] == +1);
    13171 assert(!SCIPisZero(scip, weights[i]));
    13172
    13173 row = rows[r];
    13174 assert(row != NULL);
    13175 assert(row->len == 0 || row->cols != NULL);
    13176 assert(row->len == 0 || row->cols_index != NULL);
    13177 assert(row->len == 0 || row->vals != NULL);
    13178
    13179 /* get the slack's coefficient a'_r in the aggregated row */
    13180 SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
    13181
    13182 /* calculate slack variable's coefficient a_r in the cut */
    13183 if( row->integral )
    13184 {
    13185 /* slack variable is always integral */
    13186 SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
    13187 SCIPquadprecSumQQ(fr, ar, -downar);
    13188 assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
    13189
    13190 if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
    13191 QUAD_ASSIGN_Q(cutar, downar); /* a_r */
    13192 else
    13193 {
    13194 SCIP_Real pr;
    13195
    13196 SCIPquadprecSumQQ(cutar, fr, -f0);
    13197 SCIPquadprecProdQD(cutar, cutar, k);
    13198 SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
    13199 pr = SCIPceil(scip, QUAD_TO_DBL(cutar));
    13200 assert(pr >= 0); /* should be >= 1, but due to rounding bias can be 0 if fr is almost equal to f0 */
    13201 assert(pr <= k);
    13202 SCIPquadprecDivDD(cutar, pr, k + 1.0);
    13203 SCIPquadprecSumQQ(cutar, cutar, downar);
    13204 }
    13205 }
    13206 else
    13207 {
    13208 /* slack variable is continuous: */
    13209 assert(QUAD_TO_DBL(ar) >= 0.0);
    13210 continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
    13211 }
    13212
    13213 /* if the coefficient was reduced to zero, ignore the slack variable */
    13214 if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
    13215 continue;
    13216
    13217 /* depending on the slack's sign, we have
    13218 * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
    13219 * substitute a_r * s_r by adding a_r times the slack's definition to the cut.
    13220 */
    13221 mul = -slacksign[i] * QUAD_TO_DBL(cutar);
    13222
    13223 /* add the slack's definition multiplied with a_j to the cut */
    13224 SCIP_CALL( varVecAddScaledRowCoefsQuad(cutinds, cutcoefs, nnz, row, mul) );
    13225
    13226 /* move slack's constant to the right hand side */
    13227 if( slacksign[i] == +1 )
    13228 {
    13229 SCIP_Real rhs;
    13230
    13231 /* a*x + c + s == rhs => s == - a*x - c + rhs: move a_r * (rhs - c) to the right hand side */
    13232 assert(!SCIPisInfinity(scip, row->rhs));
    13233 rhs = row->rhs - row->constant;
    13234 if( row->integral )
    13235 {
    13236 /* the right hand side was implicitly rounded down in row aggregation */
    13237 rhs = SCIPfloor(scip, rhs);
    13238 }
    13239
    13240 SCIPquadprecProdQD(cutar, cutar, rhs);
    13241 SCIPquadprecSumQQ(*cutrhs, *cutrhs, -cutar);
    13242 }
    13243 else
    13244 {
    13245 SCIP_Real lhs;
    13246
    13247 /* a*x + c - s == lhs => s == a*x + c - lhs: move a_r * (c - lhs) to the right hand side */
    13248 assert(!SCIPisInfinity(scip, -row->lhs));
    13249 lhs = row->lhs - row->constant;
    13250 if( row->integral )
    13251 {
    13252 /* the left hand side was implicitly rounded up in row aggregation */
    13253 lhs = SCIPceil(scip, lhs);
    13254 }
    13255
    13256 SCIPquadprecProdQD(cutar, cutar, lhs);
    13257 SCIPquadprecSumQQ(*cutrhs, *cutrhs, cutar);
    13258 }
    13259 }
    13260
    13261 /* relax rhs to zero, if it's very close to 0 */
    13262 if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
    13263 QUAD_ASSIGN(*cutrhs, 0.0);
    13264
    13265 return SCIP_OKAY;
    13266}
    13267
    13268
    13269/** calculates a strong CG cut out of the weighted sum of LP rows given by an aggregation row; the
    13270 * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
    13271 * participate in a strongcg cut
    13272 *
    13273 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    13274 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    13275 *
    13276 * @pre This method can be called if @p scip is in one of the following stages:
    13277 * - \ref SCIP_STAGE_SOLVING
    13278 *
    13279 * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
    13280 */
    13282 SCIP* scip, /**< SCIP data structure */
    13283 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    13284 SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
    13285 SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
    13286 int vartypeusevbds, /**< for all variable types with index smaller than this number, variable
    13287 * type substitution is allowed. The indices are: 0: continuous,
    13288 * 1: continuous implint., 2: integer implint, 3: binary implint,
    13289 * 4: integer, 5: binary */
    13290 SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
    13291 SCIP_Real minfrac, /**< minimal fractionality of rhs to produce strong CG cut for */
    13292 SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce strong CG cut for */
    13293 SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
    13294 SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute a strong CG cut for */
    13295 SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
    13296 SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
    13297 int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
    13298 int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
    13299 SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
    13300 int* cutrank, /**< pointer to return rank of generated cut */
    13301 SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
    13302 SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
    13303 )
    13304{
    13305 int i;
    13306 int nvars;
    13307 int* varsign;
    13308 int* boundtype;
    13309 SCIP_Real QUAD(downrhs);
    13310 SCIP_Real QUAD(f0);
    13311 SCIP_Real QUAD(tmp);
    13312 SCIP_Real large;
    13313 SCIP_Real k;
    13314 SCIP_Bool freevariable;
    13315 SCIP_Bool localbdsused;
    13316 MIR_DATA* data;
    13317
    13318 assert(scip != NULL);
    13319 assert(aggrrow != NULL);
    13320 assert(SCIPisPositive(scip, scale));
    13321 assert(cutcoefs != NULL);
    13322 assert(cutrhs != NULL);
    13323 assert(cutinds != NULL);
    13324 assert(success != NULL);
    13325 assert(cutislocal != NULL);
    13326
    13327 SCIPdebugMsg(scip, "calculating strong CG cut (scale: %g)\n", scale);
    13328
    13329 *success = FALSE;
    13330
    13331 /* determine value from which fractionalities are no longer reliable within tolerance */
    13333
    13334 /* terminate if an integral slack fractionality is unreliable or a negative continuous slack variable is present */
    13335 for( i = 0; i < aggrrow->nrows; ++i )
    13336 {
    13337 if( ( scip->lp->rows[aggrrow->rowsinds[i]]->integral && ABS(aggrrow->rowweights[i] * scale) > large )
    13338 || ( !scip->lp->rows[aggrrow->rowsinds[i]]->integral && aggrrow->rowweights[i] * aggrrow->slacksign[i] < 0.0 ) )
    13339 return SCIP_OKAY;
    13340 }
    13341
    13342 /* allocate temporary memory */
    13343 nvars = SCIPgetNVars(scip);
    13344 SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
    13345 SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
    13346
    13347 /* Initialize cut data */
    13348 int l;
    13349 int nnz;
    13350
    13351 assert(vartypeusevbds >= 0 && vartypeusevbds < NSECTIONS);
    13352
    13353 SCIP_CALL( SCIPallocBuffer(scip, &data) );
    13354
    13355 nnz = aggrrow->nnz;
    13356 data->totalnnz = nnz;
    13357
    13358 /* initialize sections */
    13359 for( l = 0; l < NSECTIONS; ++l )
    13360 {
    13361 SCIP_CALL( SCIPallocBufferArray(scip, &data->secindices[l], nnz) );
    13362 data->secnnz[l] = 0;
    13363 /* Cont. | cont impl. | int impl. | bin impl. | int | bin */
    13364 assert(NSECTIONS == 6); /*lint !e506*/ /* If the section definition is changed, the below lines should also be adjusted to match */
    13365 data->isenfint[l] = l >= 2 ? TRUE : FALSE;
    13366 data->isimplint[l] = l >= 1 && l <= 3 ? TRUE : FALSE;
    13367 /* Use variable bounds for the sections specified by the user */
    13368 data->usevbds[l] = l < vartypeusevbds ? 2 : 0;
    13369 }
    13370
    13371 /* Problem data needs to be initialized before cut data as it is used to partition the variables into the sections */
    13372 data->vars = SCIPgetVars(scip);
    13373 data->nvars = SCIPgetNVars(scip);
    13374 data->nbinvars = SCIPgetNBinVars(scip);
    13375 data->nintvars = SCIPgetNIntVars(scip);
    13380
    13382 SCIP_CALL( SCIPallocBufferArray(scip, &data->cutinds, data->nvars) );
    13383
    13384 SCIPquadprecProdQD(data->cutrhs, aggrrow->rhs, scale);
    13385
    13386 if( nnz > 0 )
    13387 {
    13388 /* Initalize cut with the aggregation */
    13389 BMScopyMemoryArray(data->cutinds, aggrrow->inds, nnz);
    13390
    13391 for( l = 0; l < nnz; ++l )
    13392 {
    13393 SCIP_Real QUAD(coef);
    13394 int m = aggrrow->inds[l];
    13395
    13396 QUAD_ARRAY_LOAD(coef, aggrrow->vals, m);
    13397
    13398 SCIPquadprecProdQD(coef, coef, scale);
    13399
    13400 QUAD_ARRAY_STORE(data->cutcoefs, m, coef);
    13401
    13402 assert(QUAD_HI(coef) != 0.0);
    13403 }
    13404
    13405 /* Sort the array by problem index and add the variables to their sections */
    13406 SCIPsortDownInt(data->cutinds, nnz);
    13407 for( l = 0; l < nnz; ++l )
    13408 {
    13409 int section = varSection(data, data->cutinds[l]);
    13410 data->secindices[section][data->secnnz[section]] = data->cutinds[l];
    13411 ++data->secnnz[section];
    13412 }
    13413 }
    13414
    13415 data->ncutinds = 0;
    13416 *cutislocal = aggrrow->local;
    13417
    13418 if( data->totalnnz > 0 )
    13419 {
    13420 int firstcontvar;
    13421
    13422 /* Transform equation a*x == b, lb <= x <= ub into standard form
    13423 * a'*x' == b, 0 <= x' <= ub'.
    13424 *
    13425 * Transform variables (lb or ub):
    13426 * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
    13427 * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
    13428 * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
    13429 *
    13430 * Transform variables (vlb or vub):
    13431 * 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.
    13432 * 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.
    13433 * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
    13434 * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
    13435 * a_{zu_j} := a_{zu_j} + a_j * bu_j
    13436 */
    13437 SCIP_CALL( cutsTransformStrongCG(scip, data, sol, boundswitch, allowlocal, varsign, boundtype, &freevariable, &localbdsused) );
    13438
    13439 if( freevariable )
    13440 goto TERMINATE;
    13441
    13442 assert(allowlocal || !localbdsused);
    13443 *cutislocal = *cutislocal || localbdsused;
    13444
    13445 firstcontvar = nvars - SCIPgetNContVars(scip);
    13446
    13447 /* terminate if an integral coefficient fractionality is unreliable */
    13448 for( i = data->ncutinds - 1; i >= 0 && data->cutinds[i] < firstcontvar; --i )
    13449 {
    13450 SCIP_Real QUAD(coef);
    13451
    13452 QUAD_ARRAY_LOAD(coef, data->cutcoefs, data->cutinds[i]);
    13453
    13454 if( ABS(QUAD_TO_DBL(coef)) > large )
    13455 goto TERMINATE;
    13456 }
    13457
    13458 SCIPdebug(printCutQuad(scip, NULL, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    13459 }
    13460
    13461 /* terminate if the side fractionality is unreliable */
    13462 if( ABS(QUAD_TO_DBL(data->cutrhs)) > large )
    13463 goto TERMINATE;
    13464
    13465 /* Calculate
    13466 * - fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j)
    13467 * - integer k >= 1 with 1/(k + 1) <= f_0 < 1/k
    13468 * (=> k = up(1/f_0) - 1)
    13469 * - 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)
    13470 * (=> p_j = up( (f_j - f_0)/((1 - f_0)/k) ))
    13471 * and derive strong CG cut
    13472 * a~*x' <= (k+1) * down(b)
    13473 * integers : a~_j = down(a'_j) , if f_j <= f_0
    13474 * a~_j = down(a'_j) + p_j/(k + 1) , if f_j > f_0
    13475 * continuous: a~_j = 0 , if a'_j >= 0
    13476 * no strong CG cut found , if a'_j < 0
    13477 *
    13478 * Transform inequality back to a^*x <= rhs:
    13479 *
    13480 * (lb or ub):
    13481 * 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
    13482 * 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
    13483 * and move the constant terms
    13484 * -a~_j * lb_j == -a^_j * lb_j, or
    13485 * a~_j * ub_j == -a^_j * ub_j
    13486 * to the rhs.
    13487 *
    13488 * (vlb or vub):
    13489 * 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)
    13490 * 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)
    13491 * move the constant terms
    13492 * -a~_j * dl_j == -a^_j * dl_j, or
    13493 * a~_j * du_j == -a^_j * du_j
    13494 * to the rhs, and update the VB variable coefficients:
    13495 * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
    13496 * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
    13497 */
    13498 SCIPquadprecEpsFloorQ(downrhs, data->cutrhs, SCIPepsilon(scip)); /*lint !e666*/
    13499 SCIPquadprecSumQQ(f0, data->cutrhs, -downrhs);
    13500 assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
    13501
    13502 if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
    13503 goto TERMINATE;
    13504
    13505 /* renormalize the f0 value */
    13506 SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
    13507
    13508 SCIPquadprecDivDQ(tmp, 1.0, f0);
    13509 SCIPquadprecSumQD(tmp, tmp, -1.0);
    13510 k = SCIPceil(scip, QUAD_TO_DBL(tmp));
    13511 QUAD_ASSIGN_Q(data->cutrhs, downrhs);
    13512
    13513 if( data->totalnnz > 0 )
    13514 {
    13515 SCIP_CALL( cutsRoundStrongCG(scip, data, varsign, boundtype, QUAD(f0), k) );
    13516 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    13517 }
    13518
    13519 /* substitute aggregated slack variables:
    13520 *
    13521 * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
    13522 * variable only appears in its own row:
    13523 * a'_r = scale * weight[r] * slacksign[r].
    13524 *
    13525 * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
    13526 * integers : a_r = a~_r = (k + 1) * down(a'_r) , if f_r <= f0
    13527 * a_r = a~_r = (k + 1) * down(a'_r) + p_r , if f_r > f0
    13528 * continuous: a_r = a~_r = 0 , if a'_r >= 0
    13529 * a_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
    13530 *
    13531 * Substitute a_r * s_r by adding a_r times the slack's definition to the cut.
    13532 */
    13533 SCIP_CALL( cutsSubstituteStrongCG(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
    13534 aggrrow->nrows, scale, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds, QUAD(f0), k) );
    13535 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    13536
    13537 /* remove all nearly-zero coefficients from strong CG row and relax the right hand side correspondingly in order to
    13538 * prevent numerical rounding errors
    13539 */
    13540 if( postprocess )
    13541 {
    13542 SCIP_CALL( postprocessCutQuad(scip, *cutislocal, data->cutinds, data->cutcoefs, &data->ncutinds, QUAD(&data->cutrhs), success) );
    13543 }
    13544 else
    13545 {
    13546 *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, data->cutcoefs, QUAD(&data->cutrhs), data->cutinds, &data->ncutinds);
    13547 }
    13548 SCIPdebug(printCutQuad(scip, sol, data->cutcoefs, QUAD(data->cutrhs), data->cutinds, data->ncutinds, FALSE, FALSE));
    13549
    13550 if( *success )
    13551 {
    13552 *cutrhs = QUAD_TO_DBL(data->cutrhs);
    13553 *cutnnz = data->ncutinds;
    13554
    13555 /* store cut in given array in sparse representation and clean buffer array */
    13556 for( i = 0; i < *cutnnz; ++i )
    13557 {
    13558 SCIP_Real QUAD(coef);
    13559 int j = data->cutinds[i];
    13560
    13561 QUAD_ARRAY_LOAD(coef, data->cutcoefs, j);
    13562 assert(QUAD_HI(coef) != 0.0);
    13563
    13564 cutcoefs[i] = QUAD_TO_DBL(coef);
    13565 cutinds[i] = j;
    13566 QUAD_ASSIGN(coef, 0.0);
    13567 QUAD_ARRAY_STORE(data->cutcoefs, j, coef);
    13568 }
    13569
    13570 if( cutefficacy != NULL )
    13571 *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
    13572
    13573 if( cutrank != NULL )
    13574 *cutrank = aggrrow->rank + 1;
    13575 }
    13576
    13577 TERMINATE:
    13578
    13579 /* if we aborted early the temporary coefficients need to be cleaned */
    13580 if( !(*success) )
    13581 {
    13582 QUAD_ASSIGN(tmp, 0.0);
    13583
    13584 for( i = 0; i < data->ncutinds; ++i )
    13585 {
    13586 QUAD_ARRAY_STORE(data->cutcoefs, data->cutinds[i], tmp);
    13587 }
    13588 }
    13589
    13590 if( data->cutinds != NULL )
    13592
    13593 if( data->cutcoefs != NULL )
    13595
    13596 for( int s = NSECTIONS - 1; s >= 0; --s )
    13597 {
    13599 }
    13600
    13601 SCIPfreeBuffer(scip, &data);
    13602
    13603 /* free temporary memory */
    13604 SCIPfreeBufferArray(scip, &boundtype);
    13605 SCIPfreeBufferArray(scip, &varsign);
    13606
    13607 return SCIP_OKAY;
    13608}
    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:8257
    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:5872
    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:4561
    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:4164
    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:352
    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:5261
    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:12054
    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:3888
    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:11769
    static SCIP_Bool removeZerosSafely(SCIP *scip, SCIP_Real minval, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz)
    Definition: cuts.c:727
    static SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
    Definition: cuts.c:1007
    static SCIP_Real calcEfficacyDenseStorageQuad(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
    Definition: cuts.c:650
    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:822
    static SCIP_RETCODE cutsRoundStrongCG(SCIP *scip, MIR_DATA *data, int *varsign, int *boundtype, QUAD(SCIP_Real f0), SCIP_Real k)
    Definition: cuts.c:12884
    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:4233
    static SCIP_RETCODE cutsRoundMIR(SCIP *scip, MIR_DATA *data, int *RESTRICT varsign, int *RESTRICT boundtype, QUAD(SCIP_Real f0))
    Definition: cuts.c:6710
    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:13124
    static SCIP_RETCODE computeLiftingData(SCIP *scip, SNF_RELAXATION *snf, int *transvarflowcoverstatus, SCIP_Real lambda, LIFTINGDATA *liftingdata, SCIP_Bool *valid)
    Definition: cuts.c:11221
    static void doMIRBoundSubstitution(SCIP *scip, MIR_DATA *data, int varsign, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
    Definition: cuts.c:5009
    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:9190
    static SCIP_RETCODE getFlowCover(SCIP *scip, SNF_RELAXATION *snf, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, SCIP_Real *lambda, SCIP_Bool *found)
    Definition: cuts.c:10833
    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:9319
    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:12170
    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:1052
    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:1097
    #define MAXBOUND
    Definition: cuts.c:9142
    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:1585
    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:4498
    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:5543
    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:9627
    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:3822
    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:7637
    static int varSection(MIR_DATA *data, int probindex)
    Definition: cuts.c:4124
    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:5180
    static void destroyLiftingData(SCIP *scip, LIFTINGDATA *liftingdata)
    Definition: cuts.c:11351
    static void performBoundSubstitutionSimpleSafely(SCIP *scip, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
    Definition: cuts.c:5146
    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:4626
    static SCIP_RETCODE varVecAddScaledRowCoefsQuad(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
    Definition: cuts.c:240
    static SCIP_Real calcEfficacyNormQuad(SCIP *scip, SCIP_Real *vals, int *inds, int nnz)
    Definition: cuts.c:517
    #define NSECTIONS
    Definition: cuts.c:4088
    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:2103
    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:4803
    #define NONZERO(x)
    Definition: cuts.c:189
    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:915
    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:10222
    static SCIP_Real calcEfficacyDenseStorage(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
    Definition: cuts.c:579
    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:9447
    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:3753
    static void destroySNFRelaxation(SCIP *scip, SNF_RELAXATION *snf)
    Definition: cuts.c:10202
    static SCIP_RETCODE allocSNFRelaxation(SCIP *scip, SNF_RELAXATION *snf, int nvars)
    Definition: cuts.c:10181
    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:3371
    static SCIP_Bool chgCoeffWithBoundSafely(SCIP *scip, SCIP_VAR *var, SCIP_Real oldcoeff, SCIP_Real newcoeff, SCIP_Bool cutislocal, SCIP_Real *cutrhs)
    Definition: cuts.c:1142
    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:6953
    static SCIP_Real calcEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
    Definition: cuts.c:452
    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:10317
    #define MAXCMIRSCALE
    Definition: cuts.c:4079
    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:11364
    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:12597
    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:1658
    static void getAlphaAndBeta(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real vubcoef, int *alpha, SCIP_Real *beta)
    Definition: cuts.c:11184
    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:7477
    #define MAXABSVBCOEF
    Definition: cuts.c:9141
    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:3257
    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:4299
    static SCIP_RETCODE varVecAddScaledRowCoefsQuadScale(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, QUAD(SCIP_Real scale))
    Definition: cuts.c:287
    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:5099
    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:5320
    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:1207
    static SCIP_Real evaluateLiftingFunction(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real x)
    Definition: cuts.c:11100
    static SCIP_RETCODE varVecAddScaledRowCoefs(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
    Definition: cuts.c:195
    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:4715
    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:11963
    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:248
    #define COPYSIGN
    Definition: def.h:239
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_UNUSED(x)
    Definition: def.h:409
    #define EPSISINT(x, eps)
    Definition: def.h:195
    #define SCIP_REAL_MAX
    Definition: def.h:158
    #define SCIP_INVALID
    Definition: def.h:178
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_Real
    Definition: def.h:156
    #define ABS(x)
    Definition: def.h:216
    #define EPSFRAC(x, eps)
    Definition: def.h:194
    #define SQR(x)
    Definition: def.h:199
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:334
    #define RESTRICT
    Definition: def.h:260
    #define SCIPABORT()
    Definition: def.h:327
    #define SCIP_REAL_MIN
    Definition: def.h:159
    #define EPSFLOOR(x, eps)
    Definition: def.h:191
    #define REALABS(x)
    Definition: def.h:182
    #define EPSZ(x, eps)
    Definition: def.h:188
    #define SCIP_CALL(x)
    Definition: def.h:355
    SCIP_RETCODE 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:3008
    SCIP_Bool SCIPaggrRowHasRowBeenAdded(SCIP_AGGRROW *aggrrow, SCIP_ROW *row)
    Definition: cuts.c:4005
    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:8339
    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:7923
    int SCIPaggrRowGetRank(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4048
    SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
    Definition: cuts.c:2466
    void SCIPaggrRowClearSafely(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3196
    SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2668
    SCIP_RETCODE SCIPaggrRowAddRowSafely(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype, SCIP_Bool *success)
    Definition: cuts.c:2887
    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:12270
    void SCIPaggrRowClear(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3218
    SCIP_RETCODE SCIPaggrRowCopy(SCIP *scip, SCIP_AGGRROW **aggrrow, SCIP_AGGRROW *source)
    Definition: cuts.c:2758
    SCIP_Bool SCIPaggrRowIsLocal(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4058
    SCIP_Real SCIPaggrRowGetRhs(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4068
    SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
    Definition: scip_cut.c:135
    int SCIPaggrRowGetNRows(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3973
    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:3143
    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:13281
    void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2700
    int * SCIPaggrRowGetInds(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4028
    void SCIPaggrRowPrint(SCIP *scip, SCIP_AGGRROW *aggrrow, FILE *file)
    Definition: cuts.c:2721
    void SCIPaggrRowRemoveZeros(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Bool useglbbounds, SCIP_Bool *valid)
    Definition: cuts.c:3949
    SCIP_Real * SCIPaggrRowGetRowWeights(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3994
    int SCIPaggrRowGetNNz(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4038
    SCIP_RETCODE SCIPaggrRowAddRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype)
    Definition: cuts.c:2804
    int * SCIPaggrRowGetRowInds(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3983
    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:3523
    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:3067
    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:11645
    SCIP_Real SCIPaggrRowCalcEfficacyNorm(SCIP *scip, SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3243
    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:1576
    void SCIPrationalMult(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
    Definition: rational.cpp:1066
    void SCIPrationalInvert(SCIP_RATIONAL *res, SCIP_RATIONAL *op)
    Definition: rational.cpp:1323
    SCIP_Real SCIPrationalGetReal(SCIP_RATIONAL *rational)
    Definition: rational.cpp:2085
    void SCIPrationalDiv(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
    Definition: rational.cpp:1132
    void SCIPrationalSetReal(SCIP_RATIONAL *res, SCIP_Real real)
    Definition: rational.cpp:603
    void SCIPrationalFreeBuffer(BMS_BUFMEM *bufmem, SCIP_RATIONAL **rational)
    Definition: rational.cpp:473
    void SCIPrationalDiff(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_RATIONAL *op2)
    Definition: rational.cpp:983
    SCIP_Bool SCIPrationalIsPositive(SCIP_RATIONAL *rational)
    Definition: rational.cpp:1640
    SCIP_RETCODE SCIPrationalCreateBuffer(BMS_BUFMEM *bufmem, SCIP_RATIONAL **rational)
    Definition: rational.cpp:123
    SCIP_Bool SCIPrationalIsZero(SCIP_RATIONAL *rational)
    Definition: rational.cpp:1624
    void SCIPrationalSetRational(SCIP_RATIONAL *res, SCIP_RATIONAL *src)
    Definition: rational.cpp:569
    SCIP_Bool SCIPrationalIsGEReal(SCIP_RATIONAL *rat, SCIP_Real real)
    Definition: rational.cpp:1606
    SCIP_Bool SCIPrationalIsNegative(SCIP_RATIONAL *rational)
    Definition: rational.cpp:1650
    void SCIPrationalDiffReal(SCIP_RATIONAL *res, SCIP_RATIONAL *rat, SCIP_Real real)
    Definition: rational.cpp:1009
    SCIP_Real SCIPrationalRoundReal(SCIP_RATIONAL *rational, SCIP_ROUNDMODE_RAT roundmode)
    Definition: rational.cpp:2110
    SCIP_Bool SCIPrationalIsEQReal(SCIP_RATIONAL *rat, SCIP_Real real)
    Definition: rational.cpp:1437
    void SCIPrationalMultReal(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_Real op2)
    Definition: rational.cpp:1097
    SCIP_Bool SCIPrationalIsLE(SCIP_RATIONAL *rat1, SCIP_RATIONAL *rat2)
    Definition: rational.cpp:1521
    void SCIPrationalAddReal(SCIP_RATIONAL *res, SCIP_RATIONAL *rat, SCIP_Real real)
    Definition: rational.cpp:961
    void SCIPrationalAddProdReal(SCIP_RATIONAL *res, SCIP_RATIONAL *op1, SCIP_Real op2)
    Definition: rational.cpp:1210
    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:1765
    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:24482
    SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
    Definition: var.c:24504
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23642
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23478
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23498
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23900
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23453
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24142
    SCIP_RETCODE SCIPgetVarClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvub, int *closestvubidx)
    Definition: scip_var.c:8592
    int SCIPvarGetProbindex(SCIP_VAR *var)
    Definition: var.c:23662
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
    Definition: var.c:24514
    int SCIPvarGetNVubs(SCIP_VAR *var)
    Definition: var.c:24524
    SCIP_RATIONAL * SCIPvarGetUbLocalExact(SCIP_VAR *var)
    Definition: var.c:24278
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23490
    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:24664
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24234
    SCIP_RATIONAL * SCIPvarGetLbGlobalExact(SCIP_VAR *var)
    Definition: var.c:24130
    SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
    Definition: var.c:24494
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24120
    SCIP_RATIONAL * SCIPvarGetLbLocalExact(SCIP_VAR *var)
    Definition: var.c:24244
    SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
    Definition: var.c:24556
    SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
    Definition: var.c:24536
    SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
    Definition: var.c:24546
    SCIP_RATIONAL * SCIPvarGetUbGlobalExact(SCIP_VAR *var)
    Definition: var.c:24152
    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 (weighted) 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:9149
    SCIP_Real lambda
    Definition: cuts.c:9160
    int r
    Definition: cuts.c:9156
    int t
    Definition: cuts.c:9157
    SCIP_Real * m
    Definition: cuts.c:9150
    SCIP_Real d2
    Definition: cuts.c:9159
    SCIP_Real mp
    Definition: cuts.c:9161
    SCIP_Real ml
    Definition: cuts.c:9162
    SCIP_Real d1
    Definition: cuts.c:9158
    SCIP_VAR ** vars
    Definition: cuts.c:4103
    int usevbds[NSECTIONS]
    Definition: cuts.c:4100
    SCIP_Real QUAD(cutrhs)
    SCIP_Bool isenfint[NSECTIONS]
    Definition: cuts.c:4096
    int * cutinds
    Definition: cuts.c:4115
    int nvars
    Definition: cuts.c:4104
    int nbinimplvars
    Definition: cuts.c:4107
    int nintvars
    Definition: cuts.c:4106
    SCIP_Bool isimplint[NSECTIONS]
    Definition: cuts.c:4097
    SCIP_Real * cutcoefs
    Definition: cuts.c:4112
    int nintimplvars
    Definition: cuts.c:4108
    int ncutinds
    Definition: cuts.c:4116
    int totalnnz
    Definition: cuts.c:4092
    int ncontvars
    Definition: cuts.c:4110
    int ncontimplvars
    Definition: cuts.c:4109
    int nbinvars
    Definition: cuts.c:4105
    int * secindices[NSECTIONS]
    Definition: cuts.c:4093
    int secnnz[NSECTIONS]
    Definition: cuts.c:4094
    SCIP_Real * vals
    Definition: struct_cuts.h:42
    SCIP_Real * rowweights
    Definition: struct_cuts.h:46
    int * rowsinds
    Definition: struct_cuts.h:44
    SCIP_Bool local
    Definition: struct_cuts.h:52
    int * slacksign
    Definition: struct_cuts.h:45
    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 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:9170
    int * transvarcoefs
    Definition: cuts.c:9169
    SCIP_Real * transcontvarsolvals
    Definition: cuts.c:9171
    SCIP_Real * aggrcoefsbin
    Definition: cuts.c:9177
    int * origcontvars
    Definition: cuts.c:9176
    SCIP_Real transrhs
    Definition: cuts.c:9174
    int * origbinvars
    Definition: cuts.c:9175
    SCIP_Real * aggrconstants
    Definition: cuts.c:9181
    SCIP_Real * aggrcoefscont
    Definition: cuts.c:9179
    int ntransvars
    Definition: cuts.c:9173
    SCIP_Real * transvarvubcoefs
    Definition: cuts.c:9172
    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
    @ 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