SCIP

    Solving Constraint Integer Programs

    prop_obbt.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file prop_obbt.c
    26 * @ingroup DEFPLUGINS_PROP
    27 * @brief optimization-based bound tightening propagator
    28 * @author Stefan Weltge
    29 * @author Benjamin Mueller
    30 */
    31
    32/**@todo if bound tightenings of other propagators are the reason for lpsolstat != SCIP_LPSOLSTAT_OPTIMAL, resolve LP */
    33/**@todo only run more than once in root node if primal bound improved or many cuts were added to the LP */
    34/**@todo filter bounds of a variable already if SCIPisLbBetter()/SCIPisUbBetter() would return FALSE */
    35/**@todo improve warmstarting of LP solving */
    36/**@todo include bound value (finite/infinite) into getScore() function */
    37/**@todo use unbounded ray in filtering */
    38/**@todo do we want to run if the LP is unbounded, maybe for infinite variable bounds? */
    39/**@todo add first filter round in direction of objective function */
    40/**@todo implement conflict resolving callback by calling public method of genvbounds propagator, since the reason are
    41 * exactly the variable bounds with nonnegative reduced costs stored in the right-hand side of the generated
    42 * generalized variable bound (however, this only makes sense if we run locally)
    43 */
    44
    45/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    46
    47#include "scip/cons_indicator.h"
    48#include "scip/cons_linear.h"
    49#include "scip/cons_nonlinear.h"
    52#include "scip/prop_obbt.h"
    53#include "scip/pub_cons.h"
    54#include "scip/pub_lp.h"
    55#include "scip/pub_message.h"
    56#include "scip/pub_misc.h"
    57#include "scip/pub_misc_sort.h"
    58#include "scip/pub_nlp.h"
    59#include "scip/pub_prop.h"
    60#include "scip/pub_tree.h"
    61#include "scip/pub_var.h"
    62#include "scip/scip_cons.h"
    63#include "scip/scip_copy.h"
    64#include "scip/scip_cut.h"
    65#include "scip/scip_general.h"
    66#include "scip/scip_lp.h"
    67#include "scip/scip_mem.h"
    68#include "scip/scip_message.h"
    69#include "scip/scip_nlp.h"
    70#include "scip/scip_numerics.h"
    71#include "scip/scip_param.h"
    72#include "scip/scip_prob.h"
    73#include "scip/scip_probing.h"
    74#include "scip/scip_prop.h"
    77#include "scip/scip_tree.h"
    78#include "scip/scip_var.h"
    79
    80#define PROP_NAME "obbt"
    81#define PROP_DESC "optimization-based bound tightening propagator"
    82#define PROP_TIMING SCIP_PROPTIMING_AFTERLPLOOP
    83#define PROP_PRIORITY -1000000 /**< propagator priority */
    84#define PROP_FREQ 0 /**< propagator frequency */
    85#define PROP_DELAY TRUE /**< should propagation method be delayed, if other propagators
    86 * found reductions? */
    87
    88#define DEFAULT_CREATE_GENVBOUNDS TRUE /**< should obbt try to provide genvbounds if possible? */
    89#define DEFAULT_FILTERING_NORM TRUE /**< should coefficients in filtering be normalized w.r.t. the
    90 * domains sizes? */
    91#define DEFAULT_APPLY_FILTERROUNDS FALSE /**< try to filter bounds in so-called filter rounds by solving
    92 * auxiliary LPs? */
    93#define DEFAULT_APPLY_TRIVIALFITLERING TRUE /**< should obbt try to use the LP solution to filter some bounds? */
    94#define DEFAULT_GENVBDSDURINGFILTER TRUE /**< try to genrate genvbounds during trivial and aggressive filtering? */
    95#define DEFAULT_DUALFEASTOL 1e-9 /**< feasibility tolerance for reduced costs used in obbt; this value
    96 * is used if SCIP's dual feastol is greater */
    97#define DEFAULT_CONDITIONLIMIT -1.0 /**< maximum condition limit used in LP solver (-1.0: no limit) */
    98#define DEFAULT_BOUNDSTREPS 0.001 /**< minimal relative improve for strengthening bounds */
    99#define DEFAULT_FILTERING_MIN 2 /**< minimal number of filtered bounds to apply another filter
    100 * round */
    101#define DEFAULT_ITLIMITFACTOR 10.0 /**< multiple of root node LP iterations used as total LP iteration
    102 * limit for obbt (<= 0: no limit ) */
    103#define DEFAULT_MINITLIMIT 5000L /**< minimum LP iteration limit */
    104#define DEFAULT_ONLYNONCONVEXVARS TRUE /**< only apply obbt on non-convex variables */
    105#define DEFAULT_INDICATORS FALSE /**< apply obbt on variables of indicator constraints? (independent of convexity) */
    106#define DEFAULT_INDICATORTHRESHOLD 1e6 /**< variables of indicator constraints with smaller upper bound are not considered
    107 * and upper bound is tightened only if new bound is smaller */
    108#define DEFAULT_TIGHTINTBOUNDSPROBING TRUE /**< should bounds of integral variables be tightened during
    109 * the probing mode? */
    110#define DEFAULT_TIGHTCONTBOUNDSPROBING FALSE /**< should bounds of continuous variables be tightened during
    111 * the probing mode? */
    112#define DEFAULT_ORDERINGALGO 1 /**< which type of ordering algorithm should we use?
    113 * (0: no, 1: greedy, 2: greedy reverse) */
    114#define OBBT_SCOREBASE 5 /**< base that is used to calculate a bounds score value */
    115#define GENVBOUND_PROP_NAME "genvbounds"
    116
    117#define DEFAULT_SEPARATESOL FALSE /**< should the obbt LP solution be separated? note that that by
    118 * separating solution OBBT will apply all bound tightenings
    119 * immediatly */
    120#define DEFAULT_SEPAMINITER 0 /**< minimum number of iteration spend to separate an obbt LP solution */
    121#define DEFAULT_SEPAMAXITER 10 /**< maximum number of iteration spend to separate an obbt LP solution */
    122#define DEFAULT_GENVBDSDURINGSEPA TRUE /**< try to create genvbounds during separation process? */
    123#define DEFAULT_PROPAGATEFREQ 0 /**< trigger a propagation round after that many bound tightenings
    124 * (0: no propagation) */
    125#define DEFAULT_CREATE_BILININEQS TRUE /**< solve auxiliary LPs in order to find valid inequalities for bilinear terms? */
    126#define DEFAULT_CREATE_LINCONS FALSE /**< create linear constraints from inequalities for bilinear terms? */
    127#define DEFAULT_ITLIMITFAC_BILININEQS 3.0 /**< multiple of OBBT LP limit used as total LP iteration limit for solving bilinear inequality LPs (< 0 for no limit) */
    128#define DEFAULT_MINNONCONVEXITY 1e-1 /**< minimum nonconvexity for choosing a bilinear term */
    129#define DEFAULT_RANDSEED 149 /**< initial random seed */
    130
    131/*
    132 * Data structures
    133 */
    134
    135/** bound data */
    136struct Bound
    137{
    138 SCIP_VAR* var; /**< variable */
    139 SCIP_Real newval; /**< stores a probably tighter value for this bound */
    140 SCIP_BOUNDTYPE boundtype; /**< type of bound */
    141 unsigned int score; /**< score value that is used to group bounds */
    142 unsigned int filtered:1; /**< thrown out during pre-filtering step */
    143 unsigned int found:1; /**< stores whether a probably tighter value for this bound was found */
    144 unsigned int done:1; /**< has this bound been processed already? */
    145 unsigned int nonconvex:1; /**< is this bound affecting a nonconvex term? */
    146 unsigned int indicator:1; /**< is this bound affecting an indicator constraint? */
    147 int index; /**< unique index */
    148};
    149typedef struct Bound BOUND;
    150
    151/* all possible corners of a rectangular domain */
    153{
    158 FILTERED = 15
    160typedef enum Corner CORNER;
    161
    162/** bilinear bound data */
    164{
    165 SCIP_EXPR* expr; /**< product expression */
    166 int filtered; /**< corners that could be thrown out during pre-filtering step */
    167 unsigned int done:1; /**< has this bilinear term been processed already? */
    168 SCIP_Real score; /**< score value that is used to group bilinear term bounds */
    169};
    170typedef struct BilinBound BILINBOUND;
    171
    172/** propagator data */
    173struct SCIP_PropData
    174{
    175 BOUND** bounds; /**< array of interesting bounds */
    176 BILINBOUND** bilinbounds; /**< array of interesting bilinear bounds */
    177 SCIP_ROW* cutoffrow; /**< pointer to current objective cutoff row */
    178 SCIP_PROP* genvboundprop; /**< pointer to genvbound propagator */
    179 SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
    180 SCIP_Longint lastnode; /**< number of last node where obbt was performed */
    181 SCIP_Longint npropagatedomreds; /**< number of domain reductions found during propagation */
    182 SCIP_Longint nprobingiterations; /**< number of LP iterations during the probing mode */
    183 SCIP_Longint nfilterlpiters; /**< number of LP iterations spend for filtering */
    184 SCIP_Longint minitlimit; /**< minimum LP iteration limit */
    185 SCIP_Longint itlimitbilin; /**< total LP iterations limit for solving bilinear inequality LPs */
    186 SCIP_Longint itusedbilin; /**< total LP iterations used for solving bilinear inequality LPs */
    187 SCIP_Real dualfeastol; /**< feasibility tolerance for reduced costs used in obbt; this value is
    188 * used if SCIP's dual feastol is greater */
    189 SCIP_Real conditionlimit; /**< maximum condition limit used in LP solver (-1.0: no limit) */
    190 SCIP_Real boundstreps; /**< minimal relative improve for strengthening bounds */
    191 SCIP_Real itlimitfactor; /**< LP iteration limit for obbt will be this factor times total LP
    192 * iterations in root node */
    193 SCIP_Real itlimitfactorbilin; /**< multiple of OBBT LP limit used as total LP iteration limit for solving bilinear inequality LPs (< 0 for no limit) */
    194 SCIP_Real minnonconvexity; /**< lower bound on minimum absolute value of nonconvex eigenvalues for a bilinear term */
    195 SCIP_Real indicatorthreshold; /**< threshold whether upper bounds of vars of indicator conss are considered or tightened */
    196 SCIP_Bool applyfilterrounds; /**< apply filter rounds? */
    197 SCIP_Bool applytrivialfilter; /**< should obbt try to use the LP solution to filter some bounds? */
    198 SCIP_Bool genvbdsduringfilter;/**< should we try to generate genvbounds during trivial and aggressive
    199 * filtering? */
    200 SCIP_Bool genvbdsduringsepa; /**< try to create genvbounds during separation process? */
    201 SCIP_Bool creategenvbounds; /**< should obbt try to provide genvbounds if possible? */
    202 SCIP_Bool normalize; /**< should coefficients in filtering be normalized w.r.t. the domains
    203 * sizes? */
    204 SCIP_Bool onlynonconvexvars; /**< only apply obbt on non-convex variables */
    205 SCIP_Bool indicators; /**< apply obbt on variables of indicator constraints? (independent of convexity) */
    206 SCIP_Bool tightintboundsprobing; /**< should bounds of integral variables be tightened during
    207 * the probing mode? */
    208 SCIP_Bool tightcontboundsprobing;/**< should bounds of continuous variables be tightened during
    209 * the probing mode? */
    210 SCIP_Bool separatesol; /**< should the obbt LP solution be separated? note that that by
    211 * separating solution OBBT will apply all bound tightenings
    212 * immediatly */
    213 SCIP_Bool createbilinineqs; /**< solve auxiliary LPs in order to find valid inequalities for bilinear terms? */
    214 SCIP_Bool createlincons; /**< create linear constraints from inequalities for bilinear terms? */
    215 int orderingalgo; /**< which type of ordering algorithm should we use?
    216 * (0: no, 1: greedy, 2: greedy reverse) */
    217 int nbounds; /**< length of interesting bounds array */
    218 int nbilinbounds; /**< length of interesting bilinear bounds array */
    219 int bilinboundssize; /**< size of bilinear bounds array */
    220 int boundssize; /**< size of bounds array */
    221 int nminfilter; /**< minimal number of filtered bounds to apply another filter round */
    222 int nfiltered; /**< number of filtered bounds by solving auxiliary variables */
    223 int ntrivialfiltered; /**< number of filtered bounds because the LP value was equal to the bound */
    224 int nsolvedbounds; /**< number of solved bounds during the loop in applyObbt() */
    225 int ngenvboundsprobing; /**< number of non-trivial genvbounds generated and added during obbt */
    226 int ngenvboundsaggrfil; /**< number of non-trivial genvbounds found during aggressive filtering */
    227 int ngenvboundstrivfil; /**< number of non-trivial genvbounds found during trivial filtering */
    228 int lastidx; /**< index to store the last undone and unfiltered bound */
    229 int lastbilinidx; /**< index to store the last undone and unfiltered bilinear bound */
    230 int sepaminiter; /**< minimum number of iteration spend to separate an obbt LP solution */
    231 int sepamaxiter; /**< maximum number of iteration spend to separate an obbt LP solution */
    232 int propagatefreq; /**< trigger a propagation round after that many bound tightenings
    233 * (0: no propagation) */
    234 int propagatecounter; /**< number of bound tightenings since the last propagation round */
    235};
    236
    237
    238/*
    239 * Local methods
    240 */
    241
    242/** solves the LP and handles errors */
    243static
    245 SCIP* scip, /**< SCIP data structure */
    246 int itlimit, /**< maximal number of LP iterations to perform, or -1 for no limit */
    247 SCIP_Bool* error, /**< pointer to store whether an unresolved LP error occurred */
    248 SCIP_Bool* optimal /**< was the LP solved to optimalilty? */
    249 )
    250{
    251 SCIP_LPSOLSTAT lpsolstat;
    252 SCIP_RETCODE retcode;
    253
    254 assert(scip != NULL);
    255 assert(itlimit == -1 || itlimit >= 0);
    256 assert(error != NULL);
    257 assert(optimal != NULL);
    258
    259 *optimal = FALSE;
    260 *error = FALSE;
    261
    262 retcode = SCIPsolveProbingLP(scip, itlimit, error, NULL);
    263
    264 lpsolstat = SCIPgetLPSolstat(scip);
    265
    266 /* an error should not kill the overall solving process */
    267 if( retcode != SCIP_OKAY )
    268 {
    269 SCIPwarningMessage(scip, " error while solving LP in obbt propagator; LP solve terminated with code <%d>\n", retcode);
    270 SCIPwarningMessage(scip, " this does not affect the remaining solution procedure --> continue\n");
    271
    272 *error = TRUE;
    273
    274 return SCIP_OKAY;
    275 }
    276
    277 if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
    278 {
    279 assert(!*error);
    280 *optimal = TRUE;
    281 }
    282#ifdef SCIP_DEBUG
    283 else
    284 {
    285 switch( lpsolstat )
    286 {
    288 SCIPdebugMsg(scip, " reached lp iteration limit\n");
    289 break;
    291 SCIPdebugMsg(scip, " reached time limit while solving lp\n");
    292 break;
    294 SCIPdebugMsg(scip, " lp was unbounded\n");
    295 break;
    297 SCIPdebugMsg(scip, " lp was not solved\n");
    298 break;
    300 SCIPdebugMsg(scip, " an error occurred during solving lp\n");
    301 break;
    304 case SCIP_LPSOLSTAT_OPTIMAL: /* should not appear because it is handled earlier */
    305 default:
    306 SCIPdebugMsg(scip, " received an unexpected solstat during solving lp: %d\n", lpsolstat);
    307 }
    308 }
    309#endif
    310
    311 return SCIP_OKAY;
    312}
    313
    314/** adds the objective cutoff to the LP; must be in probing mode */
    315static
    317 SCIP* scip, /**< SCIP data structure */
    318 SCIP_PROPDATA* propdata /**< data of the obbt propagator */
    319 )
    320{
    321 SCIP_ROW* row;
    322 SCIP_VAR** vars;
    323 char rowname[SCIP_MAXSTRLEN];
    324
    325 int nvars;
    326 int i;
    327
    328 assert(scip != NULL);
    329 assert(SCIPinProbing(scip));
    330 assert(propdata != NULL);
    331 assert(propdata->cutoffrow == NULL);
    332
    334 {
    335 SCIPdebugMsg(scip, "no objective cutoff since there is no cutoff bound\n");
    336 return SCIP_OKAY;
    337 }
    338
    339 SCIPdebugMsg(scip, "create objective cutoff and add it to the LP\n");
    340
    341 /* get variables data */
    342 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    343
    344 /* create objective cutoff row; set local flag to FALSE since primal cutoff is globally valid */
    345 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "obbt_objcutoff");
    348
    349 for( i = 0; i < nvars; i++ )
    350 {
    351 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[i], SCIPvarGetObj(vars[i])) );
    352 }
    354
    355 /* add row to the LP */
    357
    358 propdata->cutoffrow = row;
    359 assert(SCIProwIsInLP(propdata->cutoffrow));
    360
    361 return SCIP_OKAY;
    362}
    363
    364/** determines, whether a variable is already locally fixed */
    365static
    367 SCIP* scip, /**< SCIP data structure */
    368 SCIP_VAR* var /**< variable to check */
    369 )
    370{
    372}
    373
    374/** sets objective to minimize or maximize a single variable */
    375static
    377 SCIP* scip,
    378 SCIP_PROPDATA* propdata,
    379 BOUND* bound,
    380 SCIP_Real coef
    381 )
    382{
    383#ifdef SCIP_DEBUG
    384 SCIP_VAR** vars;
    385 int nvars;
    386 int counter;
    387 int i;
    388#endif
    389
    390 assert( scip != NULL );
    391 assert( propdata != NULL );
    392 assert( bound != NULL );
    393
    394 /* set the objective for bound->var */
    395 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER )
    396 {
    398 }
    399 else
    400 {
    401 SCIP_CALL( SCIPchgVarObjProbing(scip, bound->var, -coef) );
    402 }
    403
    404#ifdef SCIP_DEBUG
    405 vars = SCIPgetVars(scip);
    406 nvars = SCIPgetNVars(scip);
    407 counter = 0;
    408
    409 for( i = 0; i < nvars; ++i )
    410 {
    411 if( SCIPgetVarObjProbing(scip, vars[i]) != 0.0 )
    412 ++counter;
    413 }
    414
    415 assert((counter == 0 && coef == 0.0) || (counter == 1 && coef != 0.0));
    416#endif
    417
    418 return SCIP_OKAY;
    419}
    420
    421/** determines whether variable should be included in the right-hand side of the generalized variable bound */
    422static
    424 SCIP* scip, /**< SCIP data structure */
    425 SCIP_VAR* var /**< variable to check */
    426 )
    427{
    428 SCIP_Real redcost;
    429
    430 assert(scip != NULL);
    431 assert(var != NULL);
    432
    434 return FALSE;
    435
    436 redcost = SCIPgetVarRedcost(scip, var);
    437 assert(redcost != SCIP_INVALID); /*lint !e777 */
    438
    439 if( redcost == SCIP_INVALID ) /*lint !e777 */
    440 return FALSE;
    441
    442 if( redcost < SCIPdualfeastol(scip) && redcost > -SCIPdualfeastol(scip) )
    443 return FALSE;
    444
    445 return TRUE;
    446}
    447
    448/** returns number of LP iterations left (-1: no limit ) */
    449static
    451 SCIP* scip, /**< SCIP data structure */
    452 SCIP_Longint nolditerations, /**< iterations count at the beginning of the corresponding function */
    453 SCIP_Longint itlimit /**< LP iteration limit (-1: no limit) */
    454 )
    455{
    456 SCIP_Longint itsleft;
    457
    458 assert(scip != NULL);
    459 assert(nolditerations >= 0);
    460 assert(itlimit == -1 || itlimit >= 0);
    461
    462 if( itlimit == -1 )
    463 {
    464 SCIPdebugMsg(scip, "iterations left: unlimited\n");
    465 return -1;
    466 }
    467 else
    468 {
    469 itsleft = itlimit - ( SCIPgetNLPIterations(scip) - nolditerations );
    470 itsleft = MAX(itsleft, 0);
    471 itsleft = MIN(itsleft, INT_MAX);
    472
    473 SCIPdebugMsg(scip, "iterations left: %d\n", (int) itsleft);
    474 return (int) itsleft;
    475 }
    476}
    477
    478/** returns the objective coefficient for a variable's bound that will be chosen during filtering */
    479static
    481 SCIP* scip, /**< SCIP data structure */
    482 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
    483 SCIP_VAR* var, /**< variable */
    484 SCIP_BOUNDTYPE boundtype /**< boundtype to be filtered? */
    485 )
    486{
    487 SCIP_Real lb;
    488 SCIP_Real ub;
    489
    490 assert(scip != NULL);
    491 assert(propdata != NULL);
    492 assert(var != NULL);
    493
    494 lb = SCIPvarGetLbLocal(var);
    495 ub = SCIPvarGetUbLocal(var);
    496
    497 /* this function should not be called for fixed variables */
    498 assert(!varIsFixedLocal(scip, var));
    499
    500 /* infinite bounds will not be reached */
    501 if( boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisInfinity(scip, -lb) )
    502 return 0.0;
    503 if( boundtype == SCIP_BOUNDTYPE_UPPER && SCIPisInfinity(scip, ub) )
    504 return 0.0;
    505
    506 if( propdata->normalize )
    507 {
    508 /* if the length of the domain is too large then the coefficient should be set to +/- 1.0 */
    509 if( boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisInfinity(scip, ub) )
    510 return 1.0;
    511 if( boundtype == SCIP_BOUNDTYPE_UPPER && SCIPisInfinity(scip, -lb) )
    512 return -1.0;
    513
    514 /* otherwise the coefficient is +/- 1.0 / ( ub - lb ) */
    515 return boundtype == SCIP_BOUNDTYPE_LOWER ? 1.0 / (ub - lb) : -1.0 / (ub - lb);
    516 }
    517 else
    518 {
    519 return boundtype == SCIP_BOUNDTYPE_LOWER ? 1.0 : -1.0;
    520 }
    521}
    522
    523/** creates a genvbound if the dual LP solution provides such information
    524 *
    525 * Consider the problem
    526 *
    527 * min { +/- x_i : obj * x <= z, lb <= Ax <= ub, l <= x <= u },
    528 *
    529 * where z is the current cutoff bound. Let (mu, nu, gamma, alpha, beta) >= 0 be the optimal solution of the dual of
    530 * problem (P), where the variables correspond to the primal inequalities in the following way:
    531 *
    532 * Ax >= lb <-> mu
    533 * -Ax >= -ub <-> nu
    534 * -obj * x >= -z <-> gamma
    535 * x >= l <-> alpha
    536 * -x >= -u <-> beta
    537 *
    538 * Fixing these multipliers, by weak duality, we obtain the inequality
    539 *
    540 * +/- x_i >= lb*mu - ub*nu - z*gamma + l*alpha - u*beta
    541 *
    542 * that holds for all primal feasible points x with objective value at least z. Setting
    543 *
    544 * c = lb*mu - ub*nu, redcost_k = alpha_k - beta_k
    545 *
    546 * we obtain the inequality
    547 *
    548 * +/- x_i >= sum ( redcost_k * x_k ) + (-gamma) * cutoff_bound + c,
    549 *
    550 * that holds for all primal feasible points with objective value at least cutoff_bound. Therefore, the latter
    551 * inequality can be added as a generalized variable bound.
    552 */
    553static
    555 SCIP* scip, /**< SCIP data structure */
    556 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
    557 BOUND* bound, /**< bound of x_i */
    558 SCIP_Bool* found /**< pointer to store if we have found a non-trivial genvbound */
    559 )
    560{
    561 assert(scip != NULL);
    562 assert(bound != NULL);
    563 assert(propdata != NULL);
    564 assert(propdata->genvboundprop != NULL);
    565 assert(found != NULL);
    566
    567 *found = FALSE;
    568
    569 /* make sure we are in probing mode having an optimal LP solution */
    570 assert(SCIPinProbing(scip));
    571
    573
    574 /* only genvbounds created in the root node are globally valid
    575 *
    576 * note: depth changes to one if we use the probing mode to solve the obbt LPs
    577 */
    578 assert(SCIPgetDepth(scip) == 0 || (SCIPinProbing(scip) && SCIPgetDepth(scip) == 1));
    579
    580 SCIPdebugMsg(scip, " try to create a genvbound for <%s>...\n", SCIPvarGetName(bound->var));
    581
    582 /* a genvbound with a multiplier for x_i would not help us */
    584 {
    585 SCIP_VAR** vars; /* global variables array */
    586 SCIP_VAR** genvboundvars; /* genvbound variables array */
    587
    588 SCIP_VAR* xi; /* variable x_i */
    589
    590 SCIP_Real* genvboundcoefs; /* genvbound coefficients array */
    591
    592 SCIP_Real gamma_dual; /* dual multiplier of objective cutoff */
    593
    594 int k; /* variable for indexing global variables array */
    595 int ncoefs; /* number of nonzero coefficients in genvbound */
    596 int nvars; /* number of global variables */
    597
    598 /* set x_i */
    599 xi = bound->var;
    600
    601 /* get variable data */
    602 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    603
    604 /* count nonzero coefficients in genvbound */
    605 ncoefs = 0;
    606 for( k = 0; k < nvars; k++ )
    607 {
    608 if( includeVarGenVBound(scip, vars[k]) )
    609 {
    610 assert(vars[k] != xi);
    611 ncoefs++;
    612 }
    613 }
    614
    615 /* get dual multiplier for the objective cutoff (set to zero if there is no) */
    616 if( propdata->cutoffrow == NULL )
    617 {
    618 gamma_dual = 0.0;
    619 }
    620 else
    621 {
    623
    624 /* note that the objective cutoff is of the form
    625 * -inf <= obj * x <= cutoff_bound
    626 * but we want the positive dual multiplier!
    627 */
    628 gamma_dual = -SCIProwGetDualsol(propdata->cutoffrow);
    629
    630 /* we need to treat gamma to be exactly 0 if it is below the dual feasibility tolerance, see #2914 */
    631 if( EPSZ(gamma_dual, SCIPdualfeastol(scip)) )
    632 gamma_dual = 0.0;
    633 }
    634
    635 /* we need at least one nonzero coefficient or a nonzero dual multiplier for the objective cutoff */
    636 if( ncoefs > 0 || gamma_dual != 0.0 )
    637 {
    638 SCIP_Bool addgenvbound; /* if everything is fine with the redcosts and the bounds, add the genvbound */
    639 SCIP_Real c; /* helper variable to calculate constant term in genvbound */
    640 int idx; /* variable for indexing genvbound's coefficients array */
    641
    642 /* add the bound if the bool is still TRUE after the loop */
    643 addgenvbound = TRUE;
    644
    645 /* there should be no coefficient for x_i */
    646 assert(SCIPisZero(scip, SCIPgetVarRedcost(scip, xi)));
    647
    648 /* allocate memory for storing the genvbounds right-hand side variables and coefficients */
    649 SCIP_CALL( SCIPallocBufferArray(scip, &(genvboundvars), ncoefs) );
    650 SCIP_CALL( SCIPallocBufferArray(scip, &(genvboundcoefs), ncoefs) );
    651
    652 /* set c = lb*mu - ub*nu - z*gamma + l*alpha - u*beta */
    654
    655 /* subtract ( - z * gamma ) from c */
    656 c += SCIPgetCutoffbound(scip) * gamma_dual;
    657
    658 /* subtract ( l*alpha - u*beta ) from c and set the coefficients of the variables */
    659 idx = 0;
    660 for( k = 0; k < nvars; k++ )
    661 {
    662 SCIP_VAR* xk;
    663
    664 xk = vars[k];
    665
    666 if( includeVarGenVBound(scip, xk) )
    667 {
    668 SCIP_Real redcost;
    669
    670 redcost = SCIPgetVarRedcost(scip, xk);
    671
    672 assert(redcost != SCIP_INVALID); /*lint !e777 */
    673 assert(xk != xi);
    674
    675 /* in this case dont add a genvbound */
    676 if( ( (redcost > SCIPdualfeastol(scip)) && SCIPisInfinity(scip, -SCIPvarGetLbLocal(xk)) ) ||
    677 ( (redcost < -SCIPdualfeastol(scip)) && SCIPisInfinity(scip, SCIPvarGetUbLocal(xk)) ) )
    678 {
    679 addgenvbound = FALSE;
    680 break;
    681 }
    682
    683 /* store coefficients */
    684 assert(idx < ncoefs);
    685 genvboundvars[idx] = xk;
    686 genvboundcoefs[idx] = redcost;
    687 idx++;
    688
    689 /* if redcost > 0, then redcost = alpha_k, otherwise redcost = - beta_k */
    690 assert(redcost <= 0 || !SCIPisInfinity(scip, -SCIPvarGetLbLocal(xk)));
    691 assert(redcost >= 0 || !SCIPisInfinity(scip, SCIPvarGetUbLocal(xk)));
    692 c -= redcost > 0 ? redcost * SCIPvarGetLbLocal(xk) : redcost * SCIPvarGetUbLocal(xk);
    693 }
    694 }
    695
    696 assert(!addgenvbound || idx == ncoefs);
    697
    698 /* add genvbound */
    699 if( addgenvbound && !SCIPisInfinity(scip, -c) )
    700 {
    701#ifndef NDEBUG
    702 /* check whether the activity of the LVB in the optimal solution of the LP is equal to the LP objective value */
    703 SCIP_Real activity = c - gamma_dual * SCIPgetCutoffbound(scip);
    704
    705 for( k = 0; k < ncoefs; ++k )
    706 activity += genvboundcoefs[k] * SCIPvarGetLPSol(genvboundvars[k]);
    707
    708 SCIPdebugMsg(scip, "LVB activity = %g lpobj = %g\n", activity, SCIPgetLPObjval(scip));
    709 assert(EPSZ(SCIPrelDiff(activity, SCIPgetLPObjval(scip)), 18.0 * SCIPdualfeastol(scip)));
    710#endif
    711
    712 SCIPdebugMsg(scip, " adding genvbound\n");
    713 SCIP_CALL( SCIPgenVBoundAdd(scip, propdata->genvboundprop, genvboundvars, xi, genvboundcoefs, ncoefs,
    714 gamma_dual < SCIPdualfeastol(scip) ? 0.0 : -gamma_dual, c, bound->boundtype) );
    715 *found = TRUE;
    716 }
    717
    718 /* free arrays */
    719 SCIPfreeBufferArray(scip, &genvboundcoefs);
    720 SCIPfreeBufferArray(scip, &genvboundvars);
    721 }
    722 else
    723 {
    724 SCIPdebugMsg(scip, " trivial genvbound, skipping\n");
    725 }
    726 }
    727 else
    728 {
    729 SCIPdebugMsg(scip, " found multiplier for <%s>: %g, skipping\n",
    731 }
    732
    733 return SCIP_OKAY;
    734}
    735
    736/** exchange a bound which has been processed and updates the last undone and unfiltered bound index
    737 * NOTE: this method has to be called after filtering or processing a bound
    738 */
    739static
    741 SCIP_PROPDATA* propdata, /**< propagator data */
    742 int i /**< bound that was filtered or processed */
    743 )
    744{
    745 assert(i >= 0 && i < propdata->nbounds);
    746 assert(propdata->lastidx >= 0 && propdata->lastidx < propdata->nbounds);
    747
    748 /* exchange the bounds */
    749 if( propdata->lastidx != i )
    750 {
    751 BOUND* tmp;
    752
    753 tmp = propdata->bounds[i];
    754 propdata->bounds[i] = propdata->bounds[propdata->lastidx];
    755 propdata->bounds[propdata->lastidx] = tmp;
    756 }
    757
    758 propdata->lastidx -= 1;
    759}
    760
    761/** helper function to return a corner of the domain of two variables */
    762static
    764 SCIP_VAR* x, /**< first variable */
    765 SCIP_VAR* y, /**< second variable */
    766 CORNER corner, /**< corner */
    767 SCIP_Real* px, /**< buffer to store point for x */
    768 SCIP_Real* py /**< buffer to store point for y */
    769 )
    770{
    771 assert(x != NULL);
    772 assert(y != NULL);
    773 assert(px != NULL);
    774 assert(py != NULL);
    775
    776 switch( corner )
    777 {
    778 case LEFTBOTTOM:
    779 *px = SCIPvarGetLbGlobal(x);
    780 *py = SCIPvarGetLbGlobal(y);
    781 break;
    782 case RIGHTBOTTOM:
    783 *px = SCIPvarGetUbGlobal(x);
    784 *py = SCIPvarGetLbGlobal(y);
    785 break;
    786 case LEFTTOP:
    787 *px = SCIPvarGetLbGlobal(x);
    788 *py = SCIPvarGetUbGlobal(y);
    789 break;
    790 case RIGHTTOP:
    791 *px = SCIPvarGetUbGlobal(x);
    792 *py = SCIPvarGetUbGlobal(y);
    793 break;
    794 case FILTERED:
    795 SCIPABORT();
    796 }
    797}
    798
    799/** helper function to return the two end points of a diagonal */
    800static
    802 SCIP_VAR* x, /**< first variable */
    803 SCIP_VAR* y, /**< second variable */
    804 CORNER corner, /**< corner */
    805 SCIP_Real* xs, /**< buffer to store start point for x */
    806 SCIP_Real* ys, /**< buffer to store start point for y */
    807 SCIP_Real* xt, /**< buffer to store end point for x */
    808 SCIP_Real* yt /**< buffer to store end point for y */
    809 )
    810{
    811 assert(x != NULL);
    812 assert(y != NULL);
    813 assert(xs != NULL);
    814 assert(ys != NULL);
    815 assert(xt != NULL);
    816 assert(yt != NULL);
    817
    818 /* get end point */
    819 getCorner(x,y, corner, xt, yt);
    820
    821 /* get start point */
    822 switch( corner )
    823 {
    824 case LEFTBOTTOM:
    825 getCorner(x,y, RIGHTTOP, xs, ys);
    826 break;
    827 case RIGHTBOTTOM:
    828 getCorner(x,y, LEFTTOP, xs, ys);
    829 break;
    830 case LEFTTOP:
    831 getCorner(x,y, RIGHTBOTTOM, xs, ys);
    832 break;
    833 case RIGHTTOP:
    834 getCorner(x,y, LEFTBOTTOM, xs, ys);
    835 break;
    836 case FILTERED:
    837 SCIPABORT();
    838 }
    839}
    840
    841/** returns the first variable of a bilinear bound */
    842static
    844 BILINBOUND* bilinbound /**< bilinear bound */
    845 )
    846{
    847 assert(bilinbound->expr != NULL);
    848 assert(SCIPexprGetNChildren(bilinbound->expr) == 2);
    849
    851}
    852
    853/** returns the second variable of a bilinear bound */
    854static
    856 BILINBOUND* bilinbound /**< bilinear bound */
    857 )
    858{
    859 assert(bilinbound->expr != NULL);
    860 assert(SCIPexprGetNChildren(bilinbound->expr) == 2);
    861
    863}
    864
    865/** returns the negative locks of the expression in a bilinear bound */
    866static
    868 BILINBOUND* bilinbound /**< bilinear bound */
    869 )
    870{
    871 assert(bilinbound->expr != NULL);
    872
    873 return SCIPgetExprNLocksNegNonlinear(bilinbound->expr);
    874}
    875
    876/** returns the positive locks of the expression in a bilinear bound */
    877static
    879 BILINBOUND* bilinbound /**< bilinear bound */
    880 )
    881{
    882 assert(bilinbound->expr != NULL);
    883
    884 return SCIPgetExprNLocksPosNonlinear(bilinbound->expr);
    885}
    886
    887/** computes the score of a bilinear term bound */
    888static
    890 SCIP* scip, /**< SCIP data structure */
    891 SCIP_RANDNUMGEN* randnumgen, /**< random number generator */
    892 BILINBOUND* bilinbound /**< bilinear bound */
    893 )
    894{
    895 SCIP_VAR* x = bilinboundGetX(bilinbound);
    896 SCIP_VAR* y = bilinboundGetY(bilinbound);
    901 SCIP_Real score;
    902
    903 assert(scip != NULL);
    904 assert(randnumgen != NULL);
    905 assert(bilinbound != NULL);
    906
    907 /* consider how often a bilinear term is present in the problem */
    908 score = bilinboundGetLocksNeg(bilinbound) + bilinboundGetLocksPos(bilinbound);
    909
    910 /* penalize small variable domains; TODO tune the factor in the logarithm, maybe add a parameter for it */
    911 if( ubx - lbx < 0.5 )
    912 score += log(2.0*(ubx-lbx) + SCIPepsilon(scip));
    913 if( uby - lby < 0.5 )
    914 score += log(2.0*(uby-lby) + SCIPepsilon(scip));
    915
    916 /* consider interiority of variables in the LP solution */
    918 {
    921 SCIP_Real interiorityx = MIN(solx-lbx, ubx-solx) / MAX(ubx-lbx, SCIPepsilon(scip)); /*lint !e666*/
    922 SCIP_Real interiorityy = MIN(soly-lby, uby-soly) / MAX(uby-lby, SCIPepsilon(scip)); /*lint !e666*/
    923
    924 score += interiorityx + interiorityy;
    925 }
    926
    927 /* randomize score */
    928 score *= 1.0 + SCIPrandomGetReal(randnumgen, -SCIPepsilon(scip), SCIPepsilon(scip));
    929
    930 return score;
    931}
    932
    933/** determines whether a variable of an indicator constraint is (still) interesting
    934 *
    935 * A variable is interesting if it is not only part of indicator constraints or if the upper bound is greater than the given threshold.
    936 */
    937static
    939 SCIP* scip, /**< SCIP data structure */
    940 SCIP_VAR* var, /**< variable to check */
    941 int nlcount, /**< number of nonlinear constraints containing the variable
    942 * or number of non-convex terms containing the variable
    943 * (depends on propdata->onlynonconvexvars) */
    944 int nindcount, /**< number of indicator constraints containing the variable
    945 * or 0 (depends on propdata->indicators) */
    946 SCIP_Real threshold /**< variables with smaller upper bound are not interesting */
    947 )
    948{
    949 /* if variable is only part of indicator constraints, consider current upper bound */
    950 if( nlcount == 0 && nindcount > 0 )
    951 {
    952 if( SCIPisLE(scip, SCIPvarGetUbLocal(var), threshold) )
    953 return FALSE;
    954 }
    955
    956 return TRUE;
    957}
    958
    959/** trying to filter some bounds using the existing LP solution */
    960static
    962 SCIP* scip, /**< original SCIP data structure */
    963 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
    964 int* nfiltered, /**< how many bounds were filtered this round? */
    965 BOUND* currbound /**< bound for which OBBT LP was solved (Note: might be NULL) */
    966 )
    967{
    968 int i;
    969
    970 assert(scip != NULL);
    971 assert(propdata != NULL);
    972 assert(nfiltered != NULL);
    973
    974 *nfiltered = 0;
    975
    976 /* only apply filtering if an LP solution is at hand */
    978 {
    979 SCIPdebugMsg(scip, "can't filter using existing lp solution since it was not solved to optimality\n");
    980 return SCIP_OKAY;
    981 }
    982
    983 /* check if a bound is tight */
    984 for( i = propdata->nbounds - 1; i >= 0; --i )
    985 {
    986 BOUND* bound; /* shortcut for current bound */
    987
    988 SCIP_Real solval; /* the variables value in the current solution */
    989 SCIP_Real boundval; /* current local bound for the variable */
    990
    991 bound = propdata->bounds[i];
    992 if( bound->filtered || bound->done )
    993 continue;
    994
    995 boundval = bound->boundtype == SCIP_BOUNDTYPE_UPPER ?
    997 solval = SCIPvarGetLPSol(bound->var);
    998
    999 /* bound is tight; since this holds for all fixed variables, those are filtered here automatically; if the lp solution
    1000 * is infinity, then also the bound is tight */
    1001 if( (bound->boundtype == SCIP_BOUNDTYPE_UPPER &&
    1002 (SCIPisInfinity(scip, solval) || SCIPisFeasGE(scip, solval, boundval)))
    1003 || (bound->boundtype == SCIP_BOUNDTYPE_LOWER &&
    1004 (SCIPisInfinity(scip, -solval) || SCIPisFeasLE(scip, solval, boundval))) )
    1005 {
    1006 SCIP_BASESTAT basestat;
    1007
    1008 /* mark bound as filtered */
    1009 bound->filtered = TRUE;
    1010 SCIPdebugMsg(scip, "trivial filtered var: %s boundval=%e solval=%e\n", SCIPvarGetName(bound->var), boundval, solval);
    1011
    1012 /* get the basis status of the variable */
    1013 basestat = SCIPcolGetBasisStatus(SCIPvarGetCol(bound->var));
    1014
    1015 /* solve corresponding OBBT LP and try to generate a nontrivial genvbound */
    1016 if( propdata->genvbdsduringfilter && currbound != NULL && basestat == SCIP_BASESTAT_BASIC )
    1017 {
    1018#ifndef NDEBUG
    1019 int j;
    1020#endif
    1021 SCIP_Bool optimal;
    1022 SCIP_Bool error;
    1023
    1024 /* set objective coefficient of the bound */
    1025 SCIP_CALL( SCIPchgVarObjProbing(scip, currbound->var, 0.0) );
    1026 SCIP_CALL( setObjProbing(scip, propdata, bound, 1.0) );
    1027
    1028#ifndef NDEBUG
    1029 for( j = 0; j < SCIPgetNVars(scip); ++j )
    1030 {
    1031 SCIP_VAR* var;
    1032
    1033 var = SCIPgetVars(scip)[j];
    1034 assert(var != NULL);
    1035 assert(SCIPisZero(scip, SCIPgetVarObjProbing(scip, var)) || var == bound->var);
    1036 }
    1037#endif
    1038
    1039 /* solve the OBBT LP */
    1040 propdata->nprobingiterations -= SCIPgetNLPIterations(scip);
    1041 SCIP_CALL( solveLP(scip, -1, &error, &optimal) );
    1042 propdata->nprobingiterations += SCIPgetNLPIterations(scip);
    1043 assert(propdata->nprobingiterations >= 0);
    1044
    1045 /* try to generate a genvbound if we have solved the OBBT LP */
    1046 if( optimal && propdata->genvboundprop != NULL
    1047 && (SCIPgetDepth(scip) == 0 || (SCIPinProbing(scip) && SCIPgetDepth(scip) == 1)) )
    1048 {
    1049 SCIP_Bool found;
    1050
    1051 assert(!error);
    1052 SCIP_CALL( createGenVBound(scip, propdata, bound, &found) );
    1053
    1054 if( found )
    1055 {
    1056 propdata->ngenvboundstrivfil += 1;
    1057 SCIPdebugMsg(scip, "found genvbound during trivial filtering\n");
    1058 }
    1059 }
    1060
    1061 /* restore objective function */
    1062 SCIP_CALL( setObjProbing(scip, propdata, bound, 0.0) );
    1063 SCIP_CALL( setObjProbing(scip, propdata, currbound, 1.0) );
    1064 }
    1065
    1066 /* exchange bound i with propdata->bounds[propdata->lastidx] */
    1067 if( propdata->lastidx >= 0 )
    1068 exchangeBounds(propdata, i);
    1069
    1070 /* increase number of filtered variables */
    1071 (*nfiltered)++;
    1072 }
    1073 }
    1074
    1075 /* try to filter bilinear bounds */
    1076 for( i = propdata->lastbilinidx; i < propdata->nbilinbounds; ++i )
    1077 {
    1078 CORNER corners[4] = {LEFTTOP, LEFTBOTTOM, RIGHTTOP, RIGHTBOTTOM};
    1079 BILINBOUND* bilinbound = propdata->bilinbounds[i];
    1080 SCIP_Real solx;
    1081 SCIP_Real soly;
    1082 SCIPdebug(int oldfiltered;)
    1083 int j;
    1084
    1085 /* skip processed and filtered bounds */
    1086 if( bilinbound->done || bilinbound->filtered == FILTERED ) /*lint !e641*/
    1087 continue;
    1088
    1089 SCIPdebug(oldfiltered = bilinbound->filtered;)
    1090 solx = SCIPvarGetLPSol(bilinboundGetX(bilinbound));
    1091 soly = SCIPvarGetLPSol(bilinboundGetY(bilinbound));
    1092
    1093 /* check cases of unbounded solution values */
    1094 if( SCIPisInfinity(scip, solx) )
    1095 bilinbound->filtered = bilinbound->filtered | RIGHTTOP | RIGHTBOTTOM; /*lint !e641*/
    1096 else if( SCIPisInfinity(scip, -solx) )
    1097 bilinbound->filtered = bilinbound->filtered | LEFTTOP | LEFTBOTTOM; /*lint !e641*/
    1098
    1099 if( SCIPisInfinity(scip, soly) )
    1100 bilinbound->filtered = bilinbound->filtered | RIGHTTOP | LEFTTOP; /*lint !e641*/
    1101 else if( SCIPisInfinity(scip, -soly) )
    1102 bilinbound->filtered = bilinbound->filtered | RIGHTBOTTOM | LEFTBOTTOM; /*lint !e641*/
    1103
    1104 /* check all corners */
    1105 for( j = 0; j < 4; ++j )
    1106 {
    1109
    1110 getCorner(bilinboundGetX(bilinbound), bilinboundGetY(bilinbound), corners[j], &xt, &yt);
    1111
    1112 if( (SCIPisInfinity(scip, REALABS(solx)) || SCIPisFeasEQ(scip, xt, solx))
    1113 && (SCIPisInfinity(scip, REALABS(soly)) || SCIPisFeasEQ(scip, yt, soly)) )
    1114 bilinbound->filtered = bilinbound->filtered | corners[j]; /*lint !e641*/
    1115 }
    1116
    1117#ifdef SCIP_DEBUG
    1118 if( oldfiltered != bilinbound->filtered )
    1119 {
    1120 SCIP_VAR* x = bilinboundGetX(bilinbound);
    1121 SCIP_VAR* y = bilinboundGetY(bilinbound);
    1122 SCIPdebugMessage("filtered corners %d for (%s,%s) = (%g,%g) in [%g,%g]x[%g,%g]\n",
    1123 bilinbound->filtered - oldfiltered, SCIPvarGetName(x), SCIPvarGetName(y), solx, soly,
    1125 }
    1126#endif
    1127 }
    1128
    1129 return SCIP_OKAY;
    1130}
    1131
    1132/** enforces one round of filtering */
    1133static
    1135 SCIP* scip, /**< SCIP data structure */
    1136 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
    1137 int itlimit, /**< LP iteration limit (-1: no limit) */
    1138 int* nfiltered, /**< how many bounds were filtered this round */
    1139 SCIP_Real* objcoefs, /**< array to store the nontrivial objective coefficients */
    1140 int* objcoefsinds, /**< array to store bound indices for which their corresponding variables
    1141 * has a nontrivial objective coefficient */
    1142 int nobjcoefs /**< number of nontrivial objective coefficients */
    1143 )
    1144{
    1145 SCIP_VAR** vars; /* array of the problems variables */
    1146 SCIP_Bool error;
    1147 SCIP_Bool optimal;
    1148
    1149 int nvars; /* number of the problems variables */
    1150 int i;
    1151
    1152 assert(scip != NULL);
    1153 assert(SCIPinProbing(scip));
    1154 assert(propdata != NULL);
    1155 assert(itlimit == -1 || itlimit >= 0);
    1156 assert(nfiltered != NULL);
    1157 assert(objcoefs != NULL);
    1158 assert(objcoefsinds != NULL);
    1159 assert(nobjcoefs >= 0);
    1160
    1161 *nfiltered = 0;
    1162
    1163 /* get variable data */
    1164 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    1165
    1166 /* solve LP */
    1167 propdata->nfilterlpiters -= (int) SCIPgetNLPIterations(scip);
    1168 SCIP_CALL( solveLP(scip, itlimit, &error, &optimal) );
    1169 propdata->nfilterlpiters += (int) SCIPgetNLPIterations(scip);
    1170 assert(propdata->nfilterlpiters >= 0);
    1171
    1172 if( !optimal )
    1173 {
    1174 SCIPdebugMsg(scip, "skipping filter round since the LP was not solved to optimality\n");
    1175 return SCIP_OKAY;
    1176 }
    1177
    1178 assert(!error);
    1179
    1180 /* check if a bound is tight */
    1181 for( i = 0; i < propdata->nbounds; i++ )
    1182 {
    1183 BOUND* bound; /* shortcut for current bound */
    1184
    1185 SCIP_Real solval; /* the variables value in the current solution */
    1186 SCIP_Real boundval; /* current local bound for the variable */
    1187
    1188 bound = propdata->bounds[i];
    1189
    1190 /* if bound is filtered it was handled already before */
    1191 if( bound->filtered )
    1192 continue;
    1193
    1194 boundval = bound->boundtype == SCIP_BOUNDTYPE_UPPER ?
    1196 solval = SCIPvarGetLPSol(bound->var);
    1197
    1198 /* bound is tight */
    1199 if( (bound->boundtype == SCIP_BOUNDTYPE_UPPER && SCIPisFeasGE(scip, solval, boundval))
    1200 || (bound->boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisFeasLE(scip, solval, boundval)) )
    1201 {
    1202 SCIP_Real objcoef;
    1203 SCIP_BASESTAT basestat;
    1204
    1205 /* mark bound as filtered */
    1206 bound->filtered = TRUE;
    1207
    1208 /* get the basis status of the variable */
    1209 basestat = SCIPcolGetBasisStatus(SCIPvarGetCol(bound->var));
    1210
    1211 /* increase number of filtered variables */
    1212 (*nfiltered)++;
    1213
    1214 /* solve corresponding OBBT LP and try to generate a nontrivial genvbound */
    1215 if( propdata->genvbdsduringfilter && basestat == SCIP_BASESTAT_BASIC )
    1216 {
    1217 int j;
    1218
    1219 /* set all objective coefficients to zero */
    1220 for( j = 0; j < nobjcoefs; ++j )
    1221 {
    1222 BOUND* filterbound;
    1223
    1224 filterbound = propdata->bounds[ objcoefsinds[j] ];
    1225 assert(filterbound != NULL);
    1226
    1227 SCIP_CALL( SCIPchgVarObjProbing(scip, filterbound->var, 0.0) );
    1228 }
    1229
    1230#ifndef NDEBUG
    1231 for( j = 0; j < nvars; ++j )
    1232 assert(SCIPisZero(scip, SCIPgetVarObjProbing(scip, vars[j])));
    1233#endif
    1234
    1235 /* set objective coefficient of the bound */
    1236 SCIP_CALL( setObjProbing(scip, propdata, bound, 1.0) );
    1237
    1238 /* solve the OBBT LP */
    1239 propdata->nfilterlpiters -= (int) SCIPgetNLPIterations(scip);
    1240 SCIP_CALL( solveLP(scip, -1, &error, &optimal) );
    1241 propdata->nfilterlpiters += (int) SCIPgetNLPIterations(scip);
    1242 assert(propdata->nfilterlpiters >= 0);
    1243
    1244 /* try to generate a genvbound if we have solved the OBBT LP */
    1245 if( optimal && propdata->genvboundprop != NULL
    1246 && (SCIPgetDepth(scip) == 0 || (SCIPinProbing(scip) && SCIPgetDepth(scip) == 1)) )
    1247 {
    1248 SCIP_Bool found;
    1249
    1250 assert(!error);
    1251 SCIP_CALL( createGenVBound(scip, propdata, bound, &found) );
    1252
    1253 if( found )
    1254 {
    1255 propdata->ngenvboundsaggrfil += 1;
    1256 SCIPdebugMsg(scip, "found genvbound during aggressive filtering\n");
    1257 }
    1258 }
    1259
    1260 /* restore objective function */
    1261 for( j = 0; j < nobjcoefs; ++j )
    1262 {
    1263 BOUND* filterbound;
    1264
    1265 filterbound = propdata->bounds[ objcoefsinds[j] ];
    1266 assert(filterbound != NULL);
    1267
    1268 /* NOTE: only restore coefficients of nonfiltered bounds */
    1269 if( !filterbound->filtered )
    1270 {
    1271 assert(!SCIPisZero(scip, objcoefs[j]));
    1272 SCIP_CALL( SCIPchgVarObjProbing(scip, propdata->bounds[ objcoefsinds[j] ]->var, objcoefs[j]) );
    1273 }
    1274 }
    1275 }
    1276
    1277 /* get the corresponding variable's objective coefficient */
    1278 objcoef = SCIPgetVarObjProbing(scip, bound->var);
    1279
    1280 /* change objective coefficient if it was set up for this bound */
    1281 if( (bound->boundtype == SCIP_BOUNDTYPE_UPPER && SCIPisNegative(scip, objcoef))
    1282 || (bound->boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisPositive(scip, objcoef)) )
    1283 {
    1285 }
    1286 }
    1287 }
    1288
    1289 return SCIP_OKAY;
    1290}
    1291
    1292/** filter some bounds that are not improvable by solving auxiliary LPs */
    1293static
    1295 SCIP* scip, /**< SCIP data structure */
    1296 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
    1297 SCIP_Longint itlimit /**< LP iteration limit (-1: no limit) */
    1298 )
    1299{
    1300 SCIP_VAR** vars;
    1301 SCIP_Longint nolditerations;
    1302 SCIP_Real* objcoefs; /* array to store the nontrivial objective coefficients */
    1303 int* objcoefsinds; /* array to store bound indices for which the corresponding variable
    1304 * has a nontrivial objective coefficient */
    1305 int nobjcoefs; /* number of nontrivial objective coefficients */
    1306 int nleftiterations;
    1307 int i;
    1308 int nfiltered;
    1309 int ntotalfiltered;
    1310 int nvars;
    1311
    1312 assert(scip != NULL);
    1313 assert(SCIPinProbing(scip));
    1314 assert(propdata != NULL);
    1315 assert(itlimit == -1 || itlimit >= 0);
    1316
    1317 ntotalfiltered = 0;
    1318 nolditerations = SCIPgetNLPIterations(scip);
    1319 nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
    1320
    1321 /* get variable data */
    1322 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    1323
    1324 SCIPdebugMsg(scip, "start filter rounds\n");
    1325
    1326 SCIP_CALL( SCIPallocBufferArray(scip, &objcoefs, propdata->nbounds) );
    1327 SCIP_CALL( SCIPallocBufferArray(scip, &objcoefsinds, propdata->nbounds) );
    1328 nobjcoefs = 0;
    1329
    1330 /*
    1331 * 1.) Filter bounds of variables that are only part of indicator constraints if they are not interesting any more
    1332 */
    1333 for( i = 0; i < propdata->nbounds; i++ )
    1334 {
    1335 if( !propdata->bounds[i]->filtered && !propdata->bounds[i]->done && propdata->bounds[i]->indicator && !propdata->bounds[i]->nonconvex )
    1336 {
    1337 if( !indicatorVarIsInteresting(scip, vars[i], (int)propdata->bounds[i]->nonconvex, (int)propdata->bounds[i]->indicator, propdata->indicatorthreshold) )
    1338 {
    1339 /* mark bound as filtered */
    1340 propdata->bounds[i]->filtered = TRUE;
    1341
    1342 /* increase number of filtered variables */
    1343 ntotalfiltered++;
    1344 }
    1345 }
    1346 }
    1347
    1348 /*
    1349 * 2.) Try first to filter lower bounds of interesting variables, whose bounds are not already filtered
    1350 */
    1351
    1352 for( i = 0; i < nvars; i++ )
    1353 {
    1354 SCIP_CALL( SCIPchgVarObjProbing(scip, vars[i], 0.0) );
    1355 }
    1356
    1357 for( i = 0; i < propdata->nbounds; i++ )
    1358 {
    1359 if( propdata->bounds[i]->boundtype == SCIP_BOUNDTYPE_LOWER && !propdata->bounds[i]->filtered
    1360 && !propdata->bounds[i]->done )
    1361 {
    1362 SCIP_Real objcoef;
    1363
    1364 objcoef = getFilterCoef(scip, propdata, propdata->bounds[i]->var, SCIP_BOUNDTYPE_LOWER);
    1365
    1366 if( !SCIPisZero(scip, objcoef) )
    1367 {
    1368 SCIP_CALL( SCIPchgVarObjProbing(scip, propdata->bounds[i]->var, objcoef) );
    1369
    1370 /* store nontrivial objective coefficients */
    1371 objcoefs[nobjcoefs] = objcoef;
    1372 objcoefsinds[nobjcoefs] = i;
    1373 ++nobjcoefs;
    1374 }
    1375 }
    1376 }
    1377
    1378 do
    1379 {
    1380 SCIPdebugMsg(scip, "doing a lower bounds round\n");
    1381 SCIP_CALL( filterRound(scip, propdata, nleftiterations, &nfiltered, objcoefs, objcoefsinds, nobjcoefs) );
    1382 ntotalfiltered += nfiltered;
    1383 SCIPdebugMsg(scip, "filtered %d more bounds in lower bounds round\n", nfiltered);
    1384
    1385 /* update iterations left */
    1386 nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
    1387 }
    1388 while( nfiltered >= propdata->nminfilter && ( nleftiterations == -1 || nleftiterations > 0 ) );
    1389
    1390 /*
    1391 * 3.) Now try to filter the remaining upper bounds of interesting variables, whose bounds are not already filtered
    1392 */
    1393
    1394 /* set all objective coefficients to zero */
    1395 for( i = 0; i < nobjcoefs; i++ )
    1396 {
    1397 BOUND* bound;
    1398
    1399 assert(objcoefsinds[i] >= 0 && objcoefsinds[i] < propdata->nbounds);
    1400 bound = propdata->bounds[ objcoefsinds[i] ];
    1401 assert(bound != NULL);
    1403 }
    1404
    1405 /* reset number of nontrivial objective coefficients */
    1406 nobjcoefs = 0;
    1407
    1408#ifndef NDEBUG
    1409 for( i = 0; i < nvars; ++i )
    1410 assert(SCIPisZero(scip, SCIPgetVarObjProbing(scip, vars[i])));
    1411#endif
    1412
    1413 for( i = 0; i < propdata->nbounds; i++ )
    1414 {
    1415 if( propdata->bounds[i]->boundtype == SCIP_BOUNDTYPE_UPPER && !propdata->bounds[i]->filtered )
    1416 {
    1417 SCIP_Real objcoef;
    1418
    1419 objcoef = getFilterCoef(scip, propdata, propdata->bounds[i]->var, SCIP_BOUNDTYPE_UPPER);
    1420
    1421 if( !SCIPisZero(scip, objcoef) )
    1422 {
    1423 SCIP_CALL( SCIPchgVarObjProbing(scip, propdata->bounds[i]->var, objcoef) );
    1424
    1425 /* store nontrivial objective coefficients */
    1426 objcoefs[nobjcoefs] = objcoef;
    1427 objcoefsinds[nobjcoefs] = i;
    1428 ++nobjcoefs;
    1429 }
    1430 }
    1431 }
    1432
    1433 do
    1434 {
    1435 SCIPdebugMsg(scip, "doing an upper bounds round\n");
    1436 SCIP_CALL( filterRound(scip, propdata, nleftiterations, &nfiltered, objcoefs, objcoefsinds, nobjcoefs) );
    1437 SCIPdebugMsg(scip, "filtered %d more bounds in upper bounds round\n", nfiltered);
    1438 ntotalfiltered += nfiltered;
    1439 /* update iterations left */
    1440 nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
    1441 }
    1442 while( nfiltered >= propdata->nminfilter && ( nleftiterations == -1 || nleftiterations > 0 ) );
    1443
    1444 SCIPdebugMsg(scip, "filtered %d this round\n", ntotalfiltered);
    1445 propdata->nfiltered += ntotalfiltered;
    1446
    1447 /* free array */
    1448 SCIPfreeBufferArray(scip, &objcoefsinds);
    1449 SCIPfreeBufferArray(scip, &objcoefs);
    1450
    1451 return SCIP_OKAY;
    1452}
    1453
    1454/** applies possible bound changes that were found */
    1455static
    1457 SCIP* scip, /**< SCIP data structure */
    1458 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
    1459 SCIP_RESULT* result /**< result pointer */
    1460 )
    1461{
    1462#ifdef SCIP_DEBUG
    1463 int ntightened; /* stores the number of successful bound changes */
    1464#endif
    1465 int i;
    1466
    1467 assert(scip != NULL);
    1468 assert(!SCIPinProbing(scip));
    1469 assert(propdata != NULL);
    1470 assert(result != NULL);
    1471 assert(*result == SCIP_DIDNOTFIND);
    1472
    1473 SCIPdebug( ntightened = 0 );
    1474
    1475 for( i = 0; i < propdata->nbounds; i++ )
    1476 {
    1477 BOUND* bound; /* shortcut to the current bound */
    1478 SCIP_Bool infeas; /* stores wether a tightening approach forced an infeasibilty */
    1479 SCIP_Bool tightened; /* stores wether a tightening approach was successful */
    1480
    1481 bound = propdata->bounds[i];
    1482 infeas = FALSE;
    1483
    1484 if( bound->found )
    1485 {
    1486 SCIPdebug( double oldbound = (bound->boundtype == SCIP_BOUNDTYPE_LOWER)
    1487 ? SCIPvarGetLbLocal(bound->var)
    1488 : SCIPvarGetUbLocal(bound->var) );
    1489
    1490 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER )
    1491 {
    1492 SCIP_CALL( SCIPtightenVarLb(scip, bound->var, bound->newval, FALSE, &infeas, &tightened) );
    1493 }
    1494 else
    1495 {
    1496 /* tighten only if new bound is small enough due to numerical reasons */
    1497 if( SCIPisLE(scip, bound->newval, propdata->indicatorthreshold) )
    1498 {
    1499 SCIP_CALL( SCIPtightenVarUb(scip, bound->var, bound->newval, FALSE, &infeas, &tightened) );
    1500 }
    1501 else
    1502 tightened = FALSE;
    1503 }
    1504
    1505 /* handle information about the success */
    1506 if( infeas )
    1507 {
    1508 *result = SCIP_CUTOFF;
    1509 SCIPdebugMsg(scip, "cut off\n");
    1510 break;
    1511 }
    1512
    1513 if( tightened )
    1514 {
    1515 SCIPdebug( SCIPdebugMsg(scip, "tightended: %s old: %e new: %e\n" , SCIPvarGetName(bound->var), oldbound,
    1516 bound->newval) );
    1517
    1518 *result = SCIP_REDUCEDDOM;
    1519 SCIPdebug( ntightened++ );
    1520 }
    1521 }
    1522 }
    1523
    1524 SCIPdebug( SCIPdebugMsg(scip, "tightened bounds: %d\n", ntightened) );
    1525
    1526 return SCIP_OKAY;
    1527}
    1528
    1529/** tries to tighten a bound in probing mode */
    1530static
    1532 SCIP* scip, /**< SCIP data structure */
    1533 BOUND* bound, /**< bound that could be tightened */
    1534 SCIP_Real newval, /**< new bound value */
    1535 SCIP_Bool* tightened /**< was tightening successful? */
    1536 )
    1537{
    1538 SCIP_Real lb;
    1539 SCIP_Real ub;
    1540
    1541 assert(scip != NULL);
    1542 assert(SCIPinProbing(scip));
    1543 assert(bound != NULL);
    1544 assert(tightened != NULL);
    1545
    1546 *tightened = FALSE;
    1547
    1548 /* get old bounds */
    1549 lb = SCIPvarGetLbLocal(bound->var);
    1550 ub = SCIPvarGetUbLocal(bound->var);
    1551
    1552 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER )
    1553 {
    1554 /* round bounds new value if variable is integral */
    1555 if( SCIPvarIsIntegral(bound->var) )
    1556 newval = SCIPceil(scip, newval);
    1557
    1558 /* ensure that we give consistent bounds to the LP solver */
    1559 if( newval > ub )
    1560 newval = ub;
    1561
    1562 /* tighten if really better */
    1563 if( SCIPisLbBetter(scip, newval, lb, ub) )
    1564 {
    1565 SCIP_CALL( SCIPchgVarLbProbing(scip, bound->var, newval) );
    1566 *tightened = TRUE;
    1567 }
    1568 }
    1569 else
    1570 {
    1571 /* round bounds new value if variable is integral */
    1572 if( SCIPvarIsIntegral(bound->var) )
    1573 newval = SCIPfloor(scip, newval);
    1574
    1575 /* ensure that we give consistent bounds to the LP solver */
    1576 if( newval < lb )
    1577 newval = lb;
    1578
    1579 /* tighten if really better */
    1580 if( SCIPisUbBetter(scip, newval, lb, ub) )
    1581 {
    1582 SCIP_CALL( SCIPchgVarUbProbing(scip, bound->var, newval) );
    1583 *tightened = TRUE;
    1584 }
    1585 }
    1586
    1587 return SCIP_OKAY;
    1588}
    1589
    1590/** comparison method for two bounds w.r.t. their scores */
    1591static
    1593{
    1594 BOUND* bound1 = (BOUND*) elem1;
    1595 BOUND* bound2 = (BOUND*) elem2;
    1596
    1597 return bound1->score == bound2->score ? 0 : ( bound1->score > bound2->score ? 1 : -1 );
    1598}
    1599
    1600/** comparison method for two bilinear term bounds w.r.t. their scores */
    1601static
    1602SCIP_DECL_SORTPTRCOMP(compBilinboundsScore)
    1603{
    1604 BILINBOUND* bound1 = (BILINBOUND*) elem1;
    1605 BILINBOUND* bound2 = (BILINBOUND*) elem2;
    1606
    1607 return bound1->score == bound2->score ? 0 : ( bound1->score > bound2->score ? 1 : -1 ); /*lint !e777*/
    1608}
    1609
    1610/** comparison method for two bounds w.r.t. their boundtype */
    1611static
    1612SCIP_DECL_SORTPTRCOMP(compBoundsBoundtype)
    1613{
    1614 int diff;
    1615 BOUND* bound1 = (BOUND*) elem1;
    1616 BOUND* bound2 = (BOUND*) elem2;
    1617
    1618 /* prioritize undone bounds */
    1619 diff = (!bound1->done ? 1 : 0) - (!bound2->done ? 1 : 0);
    1620 if( diff != 0 )
    1621 return diff;
    1622
    1623 /* prioritize unfiltered bounds */
    1624 diff = (!bound1->filtered ? 1 : 0) - (!bound2->filtered ? 1 : 0);
    1625 if( diff != 0 )
    1626 return diff;
    1627
    1628 diff = (bound1->boundtype == SCIP_BOUNDTYPE_LOWER ? 1 : 0) - (bound2->boundtype == SCIP_BOUNDTYPE_LOWER ? 1 : 0);
    1629 if( diff != 0 )
    1630 return diff;
    1631
    1632 return (bound1->score == bound2->score) ? 0 : (bound1->score > bound2->score ? 1 : -1);
    1633}
    1634
    1635/** sort the propdata->bounds array with their distance or their boundtype key */
    1636static
    1638 SCIP* scip, /**< SCIP data structure */
    1639 SCIP_PROPDATA* propdata /**< propagator data */
    1640 )
    1641{
    1642 assert(scip != NULL);
    1643 assert(propdata != NULL);
    1644
    1645 SCIPdebugMsg(scip, "sort bounds\n");
    1646 SCIPsortDownPtr((void**) propdata->bounds, compBoundsBoundtype, propdata->nbounds);
    1647
    1648 return SCIP_OKAY;
    1649}
    1650
    1651/** evaluates a bound for the current LP solution */
    1652static
    1654 SCIP* scip,
    1655 BOUND* bound
    1656 )
    1657{
    1658 assert(scip != NULL);
    1659 assert(bound != NULL);
    1660
    1661 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER )
    1662 return REALABS( SCIPvarGetLPSol(bound->var) - SCIPvarGetLbLocal(bound->var) );
    1663 else
    1664 return REALABS( SCIPvarGetUbLocal(bound->var) - SCIPvarGetLPSol(bound->var) );
    1665}
    1666
    1667/** returns the index of the next undone and unfiltered bound with the smallest distance */
    1668static
    1670 SCIP* scip, /**< SCIP data structure */
    1671 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
    1672 SCIP_Bool convexphase /**< consider only convex variables? */
    1673 )
    1674{
    1675 SCIP_Real bestval;
    1676 int bestidx;
    1677 int k;
    1678
    1679 assert(scip != NULL);
    1680 assert(propdata != NULL);
    1681
    1682 bestidx = -1;
    1683 bestval = SCIPinfinity(scip);
    1684
    1685 for( k = 0; k <= propdata->lastidx; ++k )
    1686 {
    1687 BOUND* tmpbound;
    1688 tmpbound = propdata->bounds[k];
    1689
    1690 assert(tmpbound != NULL);
    1691
    1692 /* variables of indicator constraints are considered as nonconvex */
    1693 if( !tmpbound->filtered && !tmpbound->done && (tmpbound->nonconvex == !convexphase || tmpbound->indicator == !convexphase) )
    1694 {
    1695 SCIP_Real boundval;
    1696
    1697 /* return the next bound which is not done or unfiltered yet */
    1698 if( propdata->orderingalgo == 0 )
    1699 return k;
    1700
    1701 boundval = evalBound(scip, tmpbound);
    1702
    1703 /* negate boundval if we use the reverse greedy algorithm */
    1704 boundval = (propdata->orderingalgo == 2) ? -1.0 * boundval : boundval;
    1705
    1706 if( bestidx == -1 || boundval < bestval )
    1707 {
    1708 bestidx = k;
    1709 bestval = boundval;
    1710 }
    1711 }
    1712 }
    1713
    1714 return bestidx; /*lint !e438*/
    1715}
    1716
    1717/** try to separate the solution of the last OBBT LP in order to learn better variable bounds; we apply additional
    1718 * separation rounds as long as the routine finds better bounds; because of dual degeneracy we apply a minimum number of
    1719 * separation rounds
    1720 */
    1721static
    1723 SCIP* scip, /**< SCIP data structure */
    1724 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
    1725 BOUND* currbound, /**< current bound */
    1726 SCIP_Longint* nleftiterations, /**< number of left iterations (-1 for no limit) */
    1727 SCIP_Bool* success /**< pointer to store if we have found a better bound */
    1728 )
    1729{
    1730 SCIP_Bool inroot;
    1731 int i;
    1732
    1733 assert(nleftiterations != NULL);
    1734 assert(success != NULL);
    1735 assert(SCIPinProbing(scip));
    1736
    1737 *success = FALSE;
    1738
    1739 /* check if we are originally in the root node */
    1740 inroot = SCIPgetDepth(scip) == 1;
    1741
    1742 for( i = 0; i <= propdata->sepamaxiter; ++i )
    1743 {
    1744 SCIPdebug( SCIP_Longint nlpiter; )
    1745 SCIP_Real oldval;
    1746 SCIP_Bool cutoff;
    1747 SCIP_Bool delayed;
    1748 SCIP_Bool error;
    1749 SCIP_Bool optimal;
    1750 SCIP_Bool tightened;
    1751
    1752 oldval = SCIPvarGetLPSol(currbound->var);
    1753
    1754 /* find and store cuts to separate the current LP solution */
    1755 SCIP_CALL( SCIPseparateSol(scip, NULL, inroot, TRUE, FALSE, &delayed, &cutoff) );
    1756 SCIPdebugMsg(scip, "applySeparation() - ncuts = %d\n", SCIPgetNCuts(scip));
    1757
    1758 /* leave if we did not found any cut */
    1759 if( SCIPgetNCuts(scip) == 0 )
    1760 break;
    1761
    1762 /* apply cuts and resolve LP */
    1763 SCIP_CALL( SCIPapplyCutsProbing(scip, &cutoff) );
    1764 assert(SCIPgetNCuts(scip) == 0);
    1765 SCIPdebug( nlpiter = SCIPgetNLPIterations(scip); )
    1766 SCIP_CALL( solveLP(scip, (int) *nleftiterations, &error, &optimal) );
    1767 SCIPdebug( nlpiter = SCIPgetNLPIterations(scip) - nlpiter; )
    1768 SCIPdebug( SCIPdebugMsg(scip, "applySeparation() - optimal=%u error=%u lpiter=%" SCIP_LONGINT_FORMAT "\n", optimal, error, nlpiter); )
    1769 SCIPdebugMsg(scip, "oldval = %e newval = %e\n", oldval, SCIPvarGetLPSol(currbound->var));
    1770
    1771 /* leave if we did not solve the LP to optimality or an error occurred */
    1772 if( error || !optimal )
    1773 break;
    1774
    1775 /* try to generate a genvbound */
    1776 if( inroot && propdata->genvboundprop != NULL && propdata->genvbdsduringsepa )
    1777 {
    1778 SCIP_Bool found;
    1779 SCIP_CALL( createGenVBound(scip, propdata, currbound, &found) );
    1780 propdata->ngenvboundsprobing += found ? 1 : 0;
    1781 }
    1782
    1783 /* try to tight the variable bound */
    1784 tightened = FALSE;
    1785 if( !SCIPisEQ(scip, oldval, SCIPvarGetLPSol(currbound->var)) )
    1786 {
    1787 SCIP_CALL( tightenBoundProbing(scip, currbound, SCIPvarGetLPSol(currbound->var), &tightened) );
    1788 SCIPdebugMsg(scip, "apply separation - tightened=%u oldval=%e newval=%e\n", tightened, oldval,
    1789 SCIPvarGetLPSol(currbound->var));
    1790
    1791 *success |= tightened;
    1792 }
    1793
    1794 /* leave the separation if we did not tighten the bound and proceed at least propdata->sepaminiter iterations */
    1795 if( !tightened && i >= propdata->sepaminiter )
    1796 break;
    1797 }
    1798
    1799 return SCIP_OKAY;
    1800}
    1801
    1802/** finds new variable bounds until no iterations left or all bounds have been checked */
    1803static
    1805 SCIP* scip, /**< SCIP data structure */
    1806 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
    1807 SCIP_Longint* nleftiterations, /**< pointer to store the number of left iterations */
    1808 SCIP_Bool convexphase /**< consider only convex variables? */
    1809 )
    1810{
    1811 SCIP_Longint nolditerations;
    1812 SCIP_Bool iterationsleft;
    1813 BOUND* currbound;
    1814 SCIP_Longint itlimit;
    1815 int nextboundidx;
    1816
    1817 assert(scip != NULL);
    1818 assert(propdata != NULL);
    1819 assert(nleftiterations != NULL);
    1820
    1821 /* update the number of left iterations */
    1822 nolditerations = SCIPgetNLPIterations(scip);
    1823 itlimit = *nleftiterations;
    1824 assert(*nleftiterations == getIterationsLeft(scip, nolditerations, itlimit));
    1825 iterationsleft = (*nleftiterations == -1) || (*nleftiterations > 0);
    1826
    1827 /* To improve the performance we sort the bound in such a way that the undone and
    1828 * unfiltered bounds are at the end of propdata->bounds. We calculate and update
    1829 * the position of the last unfiltered and undone bound in propdata->lastidx
    1830 */
    1831 if( !convexphase )
    1832 {
    1833 /* sort bounds */
    1834 SCIP_CALL( sortBounds(scip, propdata) );
    1835
    1836 /* if the first bound is filtered or done then there is no bound left */
    1837 if( propdata->bounds[0]->done || propdata->bounds[0]->filtered )
    1838 {
    1839 SCIPdebugMsg(scip, "no unprocessed/unfiltered bound left\n");
    1840 return SCIP_OKAY;
    1841 }
    1842
    1843 /* compute the last undone and unfiltered node */
    1844 propdata->lastidx = 0;
    1845 while( propdata->lastidx < propdata->nbounds - 1 && !propdata->bounds[propdata->lastidx]->done &&
    1846 !propdata->bounds[propdata->lastidx]->filtered )
    1847 ++propdata->lastidx;
    1848
    1849 SCIPdebugMsg(scip, "lastidx = %d\n", propdata->lastidx);
    1850 }
    1851
    1852 /* find the first unprocessed bound */
    1853 nextboundidx = nextBound(scip, propdata, convexphase);
    1854
    1855 /* skip if there is no bound left */
    1856 if( nextboundidx == -1 )
    1857 {
    1858 SCIPdebugMsg(scip, "no unprocessed/unfiltered bound left\n");
    1859 return SCIP_OKAY;
    1860 }
    1861
    1862 currbound = propdata->bounds[nextboundidx];
    1863 assert(!currbound->done && !currbound->filtered);
    1864
    1865 /* main loop */
    1866 while( iterationsleft && !SCIPisStopped(scip) )
    1867 {
    1868 SCIP_Bool optimal;
    1869 SCIP_Bool error;
    1870 int nfiltered;
    1871
    1872 assert(currbound != NULL);
    1873 assert(currbound->done == FALSE);
    1874 assert(currbound->filtered == FALSE);
    1875
    1876 /* do not visit currbound more than once */
    1877 currbound->done = TRUE;
    1878 exchangeBounds(propdata, nextboundidx);
    1879
    1880 /* set objective for curr */
    1881 SCIP_CALL( setObjProbing(scip, propdata, currbound, 1.0) );
    1882
    1883 SCIPdebugMsg(scip, "before solving Boundtype: %d , LB: %e , UB: %e\n",
    1884 currbound->boundtype == SCIP_BOUNDTYPE_LOWER, SCIPvarGetLbLocal(currbound->var),
    1885 SCIPvarGetUbLocal(currbound->var) );
    1886 SCIPdebugMsg(scip, "before solving var <%s>, LP value: %f\n",
    1887 SCIPvarGetName(currbound->var), SCIPvarGetLPSol(currbound->var));
    1888
    1889 SCIPdebugMsg(scip, "probing iterations before solve: %lld \n", SCIPgetNLPIterations(scip));
    1890
    1891 propdata->nprobingiterations -= SCIPgetNLPIterations(scip);
    1892
    1893 /* now solve the LP */
    1894 SCIP_CALL( solveLP(scip, (int) *nleftiterations, &error, &optimal) );
    1895
    1896 propdata->nprobingiterations += SCIPgetNLPIterations(scip);
    1897 propdata->nsolvedbounds++;
    1898
    1899 SCIPdebugMsg(scip, "probing iterations after solve: %lld \n", SCIPgetNLPIterations(scip));
    1900 SCIPdebugMsg(scip, "OPT: %u ERROR: %u\n" , optimal, error);
    1901 SCIPdebugMsg(scip, "after solving Boundtype: %d , LB: %e , UB: %e\n",
    1902 currbound->boundtype == SCIP_BOUNDTYPE_LOWER, SCIPvarGetLbLocal(currbound->var),
    1903 SCIPvarGetUbLocal(currbound->var) );
    1904 SCIPdebugMsg(scip, "after solving var <%s>, LP value: %f\n",
    1905 SCIPvarGetName(currbound->var), SCIPvarGetLPSol(currbound->var));
    1906
    1907 /* update nleftiterations */
    1908 *nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
    1909 iterationsleft = (*nleftiterations == -1) || (*nleftiterations > 0);
    1910
    1911 if( error )
    1912 {
    1913 SCIPdebugMsg(scip, "ERROR during LP solving\n");
    1914
    1915 /* set the objective of currbound to zero to null the whole objective; otherwise the objective is wrong when
    1916 * we call findNewBounds() for the convex phase
    1917 */
    1918 SCIP_CALL( SCIPchgVarObjProbing(scip, currbound->var, 0.0) );
    1919
    1920 return SCIP_OKAY;
    1921 }
    1922
    1923 if( optimal )
    1924 {
    1925 SCIP_Bool success;
    1926
    1927 currbound->newval = SCIPvarGetLPSol(currbound->var);
    1928 currbound->found = TRUE;
    1929
    1930 /* in root node we may want to create a genvbound (independent of tightening success) */
    1931 if( (SCIPgetDepth(scip) == 0 || (SCIPinProbing(scip) && SCIPgetDepth(scip) == 1))
    1932 && propdata->genvboundprop != NULL )
    1933 {
    1934 SCIP_Bool found;
    1935
    1936 SCIP_CALL( createGenVBound(scip, propdata, currbound, &found) );
    1937
    1938 if( found )
    1939 propdata->ngenvboundsprobing += 1;
    1940 }
    1941
    1942 /* try to tighten bound in probing mode */
    1943 success = FALSE;
    1944 if( propdata->tightintboundsprobing && SCIPvarIsIntegral(currbound->var) )
    1945 {
    1946 SCIPdebugMsg(scip, "tightening bound %s = %e bounds: [%e, %e]\n", SCIPvarGetName(currbound->var),
    1947 currbound->newval, SCIPvarGetLbLocal(currbound->var), SCIPvarGetUbLocal(currbound->var) );
    1948 SCIP_CALL( tightenBoundProbing(scip, currbound, currbound->newval, &success) );
    1949 SCIPdebugMsg(scip, "tightening bound %s\n", success ? "successful" : "not successful");
    1950 }
    1951 else if( propdata->tightcontboundsprobing && !SCIPvarIsIntegral(currbound->var) )
    1952 {
    1953 SCIPdebugMsg(scip, "tightening bound %s = %e bounds: [%e, %e]\n", SCIPvarGetName(currbound->var),
    1954 currbound->newval, SCIPvarGetLbLocal(currbound->var), SCIPvarGetUbLocal(currbound->var) );
    1955 SCIP_CALL( tightenBoundProbing(scip, currbound, currbound->newval, &success) );
    1956 SCIPdebugMsg(scip, "tightening bound %s\n", success ? "successful" : "not successful");
    1957 }
    1958
    1959 /* separate current OBBT LP solution */
    1960 if( iterationsleft && propdata->separatesol )
    1961 {
    1962 propdata->nprobingiterations -= SCIPgetNLPIterations(scip);
    1963 SCIP_CALL( applySeparation(scip, propdata, currbound, nleftiterations, &success) );
    1964 propdata->nprobingiterations += SCIPgetNLPIterations(scip);
    1965
    1966 /* remember best solution value after solving additional separations LPs */
    1967 if( success )
    1968 {
    1969#ifndef NDEBUG
    1970 SCIP_Real newval = SCIPvarGetLPSol(currbound->var);
    1971
    1972 /* round new bound if the variable is integral */
    1973 if( SCIPvarIsIntegral(currbound->var) )
    1974 newval = currbound->boundtype == SCIP_BOUNDTYPE_LOWER ?
    1975 SCIPceil(scip, newval) : SCIPfloor(scip, newval);
    1976
    1977 assert((currbound->boundtype == SCIP_BOUNDTYPE_LOWER &&
    1978 SCIPisGT(scip, newval, currbound->newval))
    1979 || (currbound->boundtype == SCIP_BOUNDTYPE_UPPER &&
    1980 SCIPisLT(scip, newval, currbound->newval)));
    1981#endif
    1982
    1983 currbound->newval = SCIPvarGetLPSol(currbound->var);
    1984 }
    1985 }
    1986
    1987 /* filter bound candidates by using the current LP solution */
    1988 if( propdata->applytrivialfilter )
    1989 {
    1990 SCIP_CALL( filterExistingLP(scip, propdata, &nfiltered, currbound) );
    1991 SCIPdebugMsg(scip, "filtered %d bounds via inspecting present LP solution\n", nfiltered);
    1992 propdata->ntrivialfiltered += nfiltered;
    1993 }
    1994
    1995 propdata->propagatecounter += success ? 1 : 0;
    1996
    1997 /* propagate if we have found enough bound tightenings */
    1998 if( propdata->propagatefreq != 0 && propdata->propagatecounter >= propdata->propagatefreq )
    1999 {
    2000 SCIP_Longint ndomredsfound;
    2001 SCIP_Bool cutoff;
    2002
    2003 SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, &ndomredsfound) );
    2004 SCIPdebugMsg(scip, "propagation - cutoff %u ndomreds %" SCIP_LONGINT_FORMAT "\n", cutoff, ndomredsfound);
    2005
    2006 propdata->npropagatedomreds += ndomredsfound;
    2007 propdata->propagatecounter = 0;
    2008 }
    2009 }
    2010
    2011 /* set objective to zero */
    2012 SCIP_CALL( setObjProbing(scip, propdata, currbound, 0.0) );
    2013
    2014 /* find the first unprocessed bound */
    2015 nextboundidx = nextBound(scip, propdata, convexphase);
    2016
    2017 /* check if there is no unprocessed and unfiltered node left */
    2018 if( nextboundidx == -1 )
    2019 {
    2020 SCIPdebugMsg(scip, "NO unvisited/unfiltered bound left!\n");
    2021 break;
    2022 }
    2023
    2024 currbound = propdata->bounds[nextboundidx];
    2025 assert(!currbound->done && !currbound->filtered);
    2026 }
    2027
    2028 if( iterationsleft )
    2029 {
    2030 SCIPdebugMsg(scip, "still iterations left: %" SCIP_LONGINT_FORMAT "\n", *nleftiterations);
    2031 }
    2032 else
    2033 {
    2034 SCIPdebugMsg(scip, "no iterations left\n");
    2035 }
    2036
    2037 return SCIP_OKAY;
    2038}
    2039
    2040
    2041/** main function of obbt */
    2042static
    2044 SCIP* scip, /**< SCIP data structure */
    2045 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
    2046 SCIP_Longint itlimit, /**< LP iteration limit (-1: no limit) */
    2047 SCIP_RESULT* result /**< result pointer */
    2048 )
    2049{
    2050 SCIP_VAR** vars;
    2051 SCIP_Real* oldlbs;
    2052 SCIP_Real* oldubs;
    2053 SCIP_Longint lastnpropagatedomreds;
    2054 SCIP_Longint nleftiterations;
    2055 SCIP_Real oldconditionlimit;
    2056 SCIP_Real oldboundstreps;
    2057 SCIP_Real olddualfeastol;
    2058 SCIP_Bool hasconditionlimit;
    2059 SCIP_Bool continuenode;
    2060 SCIP_Bool boundleft;
    2061 int oldpolishing;
    2062 int nfiltered;
    2063 int nvars;
    2064 int i;
    2065
    2066 assert(scip != NULL);
    2067 assert(propdata != NULL);
    2068 assert(itlimit == -1 || itlimit >= 0);
    2069
    2070 SCIPdebugMsg(scip, "apply obbt\n");
    2071
    2072 oldlbs = NULL;
    2073 oldubs = NULL;
    2074 lastnpropagatedomreds = propdata->npropagatedomreds;
    2075 nleftiterations = itlimit;
    2076 continuenode = SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) == propdata->lastnode;
    2077 propdata->lastidx = -1;
    2078 boundleft = FALSE;
    2079 *result = SCIP_DIDNOTFIND;
    2080
    2081 /* store old variable bounds if we use propagation during obbt */
    2082 if( propdata->propagatefreq > 0 )
    2083 {
    2084 SCIP_CALL( SCIPallocBufferArray(scip, &oldlbs, propdata->nbounds) );
    2085 SCIP_CALL( SCIPallocBufferArray(scip, &oldubs, propdata->nbounds) );
    2086 }
    2087
    2088 /* reset bound data structure flags; fixed variables are marked as filtered */
    2089 for( i = 0; i < propdata->nbounds; i++ )
    2090 {
    2091 BOUND* bound = propdata->bounds[i];
    2092 bound->found = FALSE;
    2093
    2094 /* store old variable bounds */
    2095 if( oldlbs != NULL && oldubs != NULL )
    2096 {
    2097 oldlbs[bound->index] = SCIPvarGetLbLocal(bound->var);
    2098 oldubs[bound->index] = SCIPvarGetUbLocal(bound->var);
    2099 }
    2100
    2101 /* reset 'done' and 'filtered' flag in a new B&B node */
    2102 if( !continuenode )
    2103 {
    2104 bound->done = FALSE;
    2105 bound->filtered = FALSE;
    2106 }
    2107
    2108 /* mark fixed variables as filtered */
    2109 bound->filtered |= varIsFixedLocal(scip, bound->var);
    2110
    2111 /* check for an unprocessed bound */
    2112 if( !bound->filtered && !bound->done )
    2113 boundleft = TRUE;
    2114 }
    2115
    2116 /* no bound left to check */
    2117 if( !boundleft )
    2118 goto TERMINATE;
    2119
    2120 /* filter variables via inspecting present LP solution */
    2121 if( propdata->applytrivialfilter && !continuenode )
    2122 {
    2123 SCIP_CALL( filterExistingLP(scip, propdata, &nfiltered, NULL) );
    2124 SCIPdebugMsg(scip, "filtered %d bounds via inspecting present LP solution\n", nfiltered);
    2125 propdata->ntrivialfiltered += nfiltered;
    2126 }
    2127
    2128 /* store old dualfeasibletol */
    2129 olddualfeastol = SCIPdualfeastol(scip);
    2130
    2131 /* start probing */
    2133 SCIPdebugMsg(scip, "start probing\n");
    2134
    2135 /* tighten dual feastol */
    2136 if( propdata->dualfeastol < olddualfeastol )
    2137 {
    2138 SCIP_CALL( SCIPchgDualfeastol(scip, propdata->dualfeastol) );
    2139 }
    2140
    2141 /* tighten condition limit */
    2142 hasconditionlimit = (SCIPgetRealParam(scip, "lp/conditionlimit", &oldconditionlimit) == SCIP_OKAY);
    2143 if( !hasconditionlimit )
    2144 {
    2145 SCIPwarningMessage(scip, "obbt propagator could not set condition limit in LP solver - running without\n");
    2146 }
    2147 else if( propdata->conditionlimit > 0.0 && (oldconditionlimit < 0.0 || propdata->conditionlimit < oldconditionlimit) )
    2148 {
    2149 SCIP_CALL( SCIPsetRealParam(scip, "lp/conditionlimit", propdata->conditionlimit) );
    2150 }
    2151
    2152 /* tighten relative bound improvement limit */
    2153 SCIP_CALL( SCIPgetRealParam(scip, "numerics/boundstreps", &oldboundstreps) );
    2154 if( !SCIPisEQ(scip, oldboundstreps, propdata->boundstreps) )
    2155 {
    2156 SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", propdata->boundstreps) );
    2157 }
    2158
    2159 /* add objective cutoff */
    2160 SCIP_CALL( addObjCutoff(scip, propdata) );
    2161
    2162 /* deactivate LP polishing */
    2163 SCIP_CALL( SCIPgetIntParam(scip, "lp/solutionpolishing", &oldpolishing) );
    2164 SCIP_CALL( SCIPsetIntParam(scip, "lp/solutionpolishing", 0) );
    2165
    2166 /* apply filtering */
    2167 if( propdata->applyfilterrounds )
    2168 {
    2169 SCIP_CALL( filterBounds(scip, propdata, nleftiterations) );
    2170 }
    2171
    2172 /* set objective coefficients to zero */
    2173 vars = SCIPgetVars(scip);
    2174 nvars = SCIPgetNVars(scip);
    2175 for( i = 0; i < nvars; ++i )
    2176 {
    2177 /* note that it is not possible to change the objective of non-column variables during probing; we have to take
    2178 * care of the objective contribution of loose variables in createGenVBound()
    2179 */
    2180 if( SCIPvarGetObj(vars[i]) != 0.0 && SCIPvarGetStatus(vars[i]) == SCIP_VARSTATUS_COLUMN )
    2181 {
    2182 SCIP_CALL( SCIPchgVarObjProbing(scip, vars[i], 0.0) );
    2183 }
    2184 }
    2185
    2186 /* find new bounds for the variables */
    2187 SCIP_CALL( findNewBounds(scip, propdata, &nleftiterations, FALSE) );
    2188
    2189 if( nleftiterations > 0 || itlimit < 0 )
    2190 {
    2191 SCIP_CALL( findNewBounds(scip, propdata, &nleftiterations, TRUE) );
    2192 }
    2193
    2194 /* reset dual feastol and condition limit */
    2195 SCIP_CALL( SCIPchgDualfeastol(scip, olddualfeastol) );
    2196 if( hasconditionlimit )
    2197 {
    2198 SCIP_CALL( SCIPsetRealParam(scip, "lp/conditionlimit", oldconditionlimit) );
    2199 }
    2200
    2201 /* update bound->newval if we have learned additional bound tightenings during SCIPpropagateProbing() */
    2202 if( oldlbs != NULL && oldubs != NULL && propdata->npropagatedomreds - lastnpropagatedomreds > 0 )
    2203 {
    2204 assert(propdata->propagatefreq > 0);
    2205 for( i = 0; i < propdata->nbounds; ++i )
    2206 {
    2207 BOUND* bound = propdata->bounds[i];
    2208
    2209 /* it might be the case that a bound found by the additional propagation is better than the bound found after solving an OBBT
    2210 * LP
    2211 */
    2212 if( bound->found )
    2213 {
    2214 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER )
    2215 bound->newval = MAX(bound->newval, SCIPvarGetLbLocal(bound->var)); /*lint !e666*/
    2216 else
    2217 bound->newval = MIN(bound->newval, SCIPvarGetUbLocal(bound->var)); /*lint !e666*/
    2218 }
    2219 else
    2220 {
    2221 SCIP_Real oldlb;
    2222 SCIP_Real oldub;
    2223
    2224 oldlb = oldlbs[bound->index];
    2225 oldub = oldubs[bound->index];
    2226
    2227 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisLbBetter(scip, SCIPvarGetLbLocal(bound->var), oldlb, oldub) )
    2228 {
    2229 SCIPdebugMsg(scip, "tighter lower bound due to propagation: %d - %e -> %e\n", i, oldlb, SCIPvarGetLbLocal(bound->var));
    2230 bound->newval = SCIPvarGetLbLocal(bound->var);
    2231 bound->found = TRUE;
    2232 }
    2233
    2234 if( bound->boundtype == SCIP_BOUNDTYPE_UPPER && SCIPisUbBetter(scip, SCIPvarGetUbLocal(bound->var), oldlb, oldub) )
    2235 {
    2236 SCIPdebugMsg(scip, "tighter upper bound due to propagation: %d - %e -> %e\n", i, oldub, SCIPvarGetUbLocal(bound->var));
    2237 bound->newval = SCIPvarGetUbLocal(bound->var);
    2238 bound->found = TRUE;
    2239 }
    2240 }
    2241 }
    2242 }
    2243
    2244 /* reset relative bound improvement limit */
    2245 SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", oldboundstreps) );
    2246
    2247 /* reset original LP polishing setting */
    2248 SCIP_CALL( SCIPsetIntParam(scip, "lp/solutionpolishing", oldpolishing) );
    2249
    2250 /* end probing */
    2252 SCIPdebugMsg(scip, "end probing!\n");
    2253
    2254 /* release cutoff row if there is one */
    2255 if( propdata->cutoffrow != NULL )
    2256 {
    2257 assert(!SCIProwIsInLP(propdata->cutoffrow));
    2258 SCIP_CALL( SCIPreleaseRow(scip, &(propdata->cutoffrow)) );
    2259 }
    2260
    2261 /* apply buffered bound changes */
    2262 SCIP_CALL( applyBoundChgs(scip, propdata, result) );
    2263
    2264TERMINATE:
    2265 SCIPfreeBufferArrayNull(scip, &oldubs);
    2266 SCIPfreeBufferArrayNull(scip, &oldlbs);
    2267
    2268 return SCIP_OKAY;
    2269}
    2270
    2271/** computes a valid inequality from the current LP relaxation for a bilinear term xy only involving x and y; the
    2272 * inequality is found by optimizing along the line connecting the points (xs,ys) and (xt,yt) over the currently given
    2273 * linear relaxation of the problem; this optimization problem is an LP
    2274 *
    2275 * max lambda
    2276 * s.t. Ax <= b
    2277 * (x,y) = (xs,ys) + lambda ((xt,yt) - (xs,ys))
    2278 * lambda in [0,1]
    2279 *
    2280 * which is equivalent to
    2281 *
    2282 * max x
    2283 * s.t. (1) Ax <= b
    2284 * (2) (x - xs) / (xt - xs) = (y - ys) / (yt - ys)
    2285 *
    2286 * Let x* be the optimal primal and (mu,theta) be the optimal dual solution of this LP. The KKT conditions imply that
    2287 * the aggregation of the linear constraints mu*Ax <= mu*b can be written as
    2288 *
    2289 * x * (1 - theta) / (xt - xs) + y * theta / (yt - ys) = mu * Ax <= mu * b
    2290 *
    2291 * <=> alpha * x + beta * y <= mu * b = alpha * (x*) + beta * (y*)
    2292 *
    2293 * which is a valid inequality in the (x,y)-space; in order to avoid numerical difficulties when (xs,ys) is too close
    2294 * to (xt,yt), we scale constraint (1) by max{1,|xt-xs|,|yt-ys|} beforehand
    2295 */
    2296static
    2298 SCIP* scip, /**< SCIP data structure */
    2299 SCIP_VAR* x, /**< first variable */
    2300 SCIP_VAR* y, /**< second variable */
    2301 SCIP_Real xs, /**< x-coordinate of the first point */
    2302 SCIP_Real ys, /**< y-coordinate of the first point */
    2303 SCIP_Real xt, /**< x-coordinate of the second point */
    2304 SCIP_Real yt, /**< y-coordinate of the second point */
    2305 SCIP_Real* xcoef, /**< pointer to store the coefficient of x */
    2306 SCIP_Real* ycoef, /**< pointer to store the coefficient of y */
    2307 SCIP_Real* constant, /**< pointer to store the constant */
    2308 SCIP_Longint iterlim, /**< iteration limit (-1: for no limit) */
    2309 int* nnonzduals /**< buffer to store the number of non-zero dual multipliers except for
    2310 * the auxiliary row (NULL if not needed) */
    2311 )
    2312{
    2313 SCIP_ROW* row;
    2314 SCIP_Real signx;
    2315 SCIP_Real scale;
    2316 SCIP_Real side;
    2317 SCIP_Bool lperror;
    2318
    2319 assert(xcoef != NULL);
    2320 assert(ycoef != NULL);
    2321 assert(constant != NULL);
    2322 assert(SCIPinProbing(scip));
    2323
    2324 *xcoef = SCIP_INVALID;
    2325 *ycoef = SCIP_INVALID;
    2326 *constant= SCIP_INVALID;
    2327 if( nnonzduals != NULL )
    2328 *nnonzduals = 0;
    2329
    2330 SCIPdebugMsg(scip, " solve bilinear LP for (%s,%s) from (%g,%g) to (%g,%g)\n", SCIPvarGetName(x), SCIPvarGetName(y), xs,
    2331 ys, xt, yt);
    2332
    2333 /* skip computations if (xs,ys) and (xt,yt) are too close to each other or contain too large values */
    2334 if( SCIPisFeasEQ(scip, xs, xt) || SCIPisFeasEQ(scip, ys, yt)
    2337 {
    2338 SCIPdebugMsg(scip, " -> skip: bounds are too close/large\n");
    2339 return SCIP_OKAY;
    2340 }
    2341
    2342 /* compute scaler for the additional linear constraint */
    2343 scale = MIN(MAX3(1.0, REALABS(xt-xs), REALABS(yt-ys)), 100.0); /*lint !e666*/
    2344
    2345 /* set objective function */
    2346 signx = (xs > xt) ? 1.0 : -1.0;
    2348
    2349 /* create new probing node to remove the added LP row afterwards */
    2351
    2352 /* create row */
    2353 side = scale * (xs/(xt-xs) - ys/(yt-ys));
    2354 SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, "bilinrow", side, side, FALSE, FALSE, TRUE) );
    2355 SCIP_CALL( SCIPaddVarToRow(scip, row, x, scale/(xt-xs)) );
    2356 SCIP_CALL( SCIPaddVarToRow(scip, row, y, -scale/(yt-ys)) );
    2358
    2359 /* solve probing LP */
    2360#ifdef NDEBUG
    2361 {
    2362 SCIP_RETCODE retstat;
    2363 retstat = SCIPsolveProbingLP(scip, iterlim, &lperror, NULL);
    2364 if( retstat != SCIP_OKAY )
    2365 {
    2366 SCIPwarningMessage(scip, "Error while solving LP in quadratic constraint handler; LP solve terminated with" \
    2367 "code <%d>\n", retstat);
    2368 }
    2369 }
    2370#else
    2371 SCIP_CALL( SCIPsolveProbingLP(scip, (int)iterlim, &lperror, NULL) ); /*lint !e712*/
    2372#endif
    2373
    2374 SCIPdebugMsg(scip, " solved probing LP -> lperror=%u lpstat=%d\n", lperror, SCIPgetLPSolstat(scip));
    2375
    2376 /* collect dual and primal solution entries */
    2377 if( !lperror && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
    2378 {
    2379 SCIP_Real xval = SCIPvarGetLPSol(x);
    2380 SCIP_Real yval = SCIPvarGetLPSol(y);
    2381 SCIP_Real mu = -SCIProwGetDualsol(row);
    2382
    2383 SCIPdebugMsg(scip, " primal=(%g,%g) dual=%g\n", xval, yval, mu);
    2384
    2385 /* xcoef x + ycoef y <= constant */
    2386 *xcoef = -signx - (mu * scale) / (xt - xs);
    2387 *ycoef = (mu * scale) / (yt - ys);
    2388 *constant = (*xcoef) * xval + (*ycoef) * yval;
    2389
    2390 /* xcoef x <= -ycoef y + constant */
    2391 *ycoef = -(*ycoef);
    2392
    2393 /* inequality is only useful when both coefficients are different from zero; normalize inequality if possible */
    2394 if( !SCIPisFeasZero(scip, *xcoef) && !SCIPisFeasZero(scip, *ycoef) )
    2395 {
    2396 SCIP_Real val = REALABS(*xcoef);
    2397 int r;
    2398
    2399 *xcoef /= val;
    2400 *ycoef /= val;
    2401 *constant /= val;
    2402
    2403 if( SCIPisZero(scip, *constant) )
    2404 *constant = 0.0;
    2405
    2406 if( nnonzduals != NULL )
    2407 {
    2408 /* count the number of non-zero dual multipliers except for the added row */
    2409 for( r = 0; r < SCIPgetNLPRows(scip); ++r )
    2410 {
    2412 ++(*nnonzduals);
    2413 }
    2414 }
    2415 }
    2416 else
    2417 {
    2418 *xcoef = SCIP_INVALID;
    2419 *ycoef = SCIP_INVALID;
    2420 *constant = SCIP_INVALID;
    2421 }
    2422 }
    2423
    2424 /* release row and backtrack probing node */
    2425 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    2427
    2428 /* reset objective function */
    2430
    2431 return SCIP_OKAY;
    2432}
    2433
    2434/* applies obbt for finding valid inequalities for bilinear terms; function works as follows:
    2435 *
    2436 * 1. start probing mode
    2437 * 2. add objective cutoff (if possible)
    2438 * 3. set objective function to zero
    2439 * 4. set feasibility, optimality, and relative bound improvement tolerances of SCIP
    2440 * 5. main loop
    2441 * 6. restore old tolerances
    2442 *
    2443 */
    2444static
    2446 SCIP* scip, /**< SCIP data structure */
    2447 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
    2448 SCIP_Longint itlimit, /**< LP iteration limit (-1: no limit) */
    2449 SCIP_RESULT* result /**< result pointer */
    2450 )
    2451{
    2452 SCIP_VAR** vars;
    2453 SCIP_Real oldfeastol;
    2454 SCIP_Bool lperror;
    2455 SCIP_Longint nolditerations;
    2456 SCIP_Longint nleftiterations;
    2457 SCIP_CONSHDLR* conshdlr;
    2458 SCIP_NLHDLR* bilinearnlhdlr;
    2459 int nvars;
    2460 int i;
    2461
    2462 assert(scip != NULL);
    2463 assert(propdata != NULL);
    2464 assert(itlimit == -1 || itlimit >= 0);
    2465 assert(result != NULL);
    2466
    2467 if( propdata->nbilinbounds <= 0 || SCIPgetDepth(scip) != 0 || propdata->lastbilinidx >= propdata->nbilinbounds )
    2468 return SCIP_OKAY;
    2469
    2470 SCIPdebugMsg(scip, "call applyObbtBilinear starting from %d\n", propdata->lastbilinidx);
    2471
    2472 /* find nonlinear handler for bilinear terms */
    2473 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
    2474 bilinearnlhdlr = conshdlr != NULL ? SCIPfindNlhdlrNonlinear(conshdlr, "bilinear") : NULL;
    2475
    2476 /* no nonlinear handler available -> skip */
    2477 if( bilinearnlhdlr == NULL )
    2478 return SCIP_OKAY;
    2479
    2480 vars = SCIPgetVars(scip);
    2481 nvars = SCIPgetNVars(scip);
    2482
    2483 nolditerations = SCIPgetNLPIterations(scip);
    2484 nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
    2485 SCIPdebugMsg(scip, "iteration limit: %lld\n", nleftiterations);
    2486
    2487 /* 1. start probing */
    2489
    2490 /* 2. add objective cutoff */
    2491 SCIP_CALL( addObjCutoff(scip, propdata) );
    2492
    2493 /* 3. set objective function to zero */
    2494 for( i = 0; i < nvars; ++i )
    2495 {
    2496 SCIP_CALL( SCIPchgVarObjProbing(scip, vars[i], 0.0) );
    2497 }
    2498
    2499 /* 4. tighten LP feasibility tolerance to be at most feastol/10.0 */
    2500 oldfeastol = SCIPchgRelaxfeastol(scip, SCIPfeastol(scip) / 10.0);
    2501
    2502 /* we need to solve the probing LP before creating new probing nodes in solveBilinearLP() */
    2503 SCIP_CALL( SCIPsolveProbingLP(scip, (int)nleftiterations, &lperror, NULL) );
    2504
    2505 if( lperror )
    2506 goto TERMINATE;
    2507
    2508 /* 5. main loop */
    2509 for( i = propdata->lastbilinidx; i < propdata->nbilinbounds
    2510 && (nleftiterations > 0 || nleftiterations == -1)
    2511 && (propdata->itlimitbilin < 0 || propdata->itlimitbilin > propdata->itusedbilin )
    2512 && !SCIPisStopped(scip); ++i )
    2513 {
    2514 CORNER corners[4] = {LEFTBOTTOM, LEFTTOP, RIGHTTOP, RIGHTBOTTOM};
    2515 BILINBOUND* bilinbound;
    2516 int k;
    2517
    2518 bilinbound = propdata->bilinbounds[i];
    2519 assert(bilinbound != NULL);
    2520
    2521 SCIPdebugMsg(scip, "process %d: %s %s done=%u filtered=%d nunderest=%d noverest=%d\n", i,
    2522 SCIPvarGetName(bilinboundGetX(bilinbound)), SCIPvarGetName(bilinboundGetY(bilinbound)), bilinbound->done,
    2523 bilinbound->filtered, bilinboundGetLocksNeg(bilinbound), bilinboundGetLocksPos(bilinbound));
    2524
    2525 /* we already solved LPs for this bilinear term */
    2526 if( bilinbound->done || bilinbound->filtered == (int)FILTERED )
    2527 continue;
    2528
    2529 /* iterate through all corners
    2530 *
    2531 * 0: (xs,ys)=(ubx,lby) (xt,yt)=(lbx,uby) -> underestimate
    2532 * 1: (xs,ys)=(ubx,uby) (xt,yt)=(lbx,lby) -> overestimate
    2533 * 2: (xs,ys)=(lbx,uby) (xt,yt)=(ubx,lby) -> underestimate
    2534 * 3: (xs,ys)=(lbx,lby) (xt,yt)=(ubx,uby) -> overestimate
    2535 */
    2536 for( k = 0; k < 4; ++k )
    2537 {
    2538 CORNER corner = corners[k];
    2539 SCIP_VAR* x = bilinboundGetX(bilinbound);
    2540 SCIP_VAR* y = bilinboundGetY(bilinbound);
    2541 SCIP_Real xcoef;
    2542 SCIP_Real ycoef;
    2543 SCIP_Real constant;
    2548 int nnonzduals = 0;
    2549
    2550 /* skip corners that lead to an under- or overestimate that is not needed */
    2551 if( ((corner == LEFTTOP || corner == RIGHTBOTTOM) && bilinboundGetLocksPos(bilinbound) == 0)
    2552 || ((corner == LEFTBOTTOM || corner == RIGHTTOP) && bilinboundGetLocksNeg(bilinbound) == 0) )
    2553 continue;
    2554
    2555 /* check whether corner has been filtered already */
    2556 if( (bilinbound->filtered & corner) != 0 ) /*lint !e641*/
    2557 continue;
    2558
    2559 /* get corners (xs,ys) and (xt,yt) */
    2560 getCorners(x, y, corner, &xs, &ys, &xt, &yt);
    2561
    2562 /* skip target corner points with too large values */
    2564 continue;
    2565
    2566 /* compute inequality */
    2567 propdata->itusedbilin -= SCIPgetNLPIterations(scip);
    2568 SCIP_CALL( solveBilinearLP(scip, x, y, xs, ys, xt, yt, &xcoef, &ycoef, &constant, -1L,
    2569 propdata->createlincons ? &nnonzduals : NULL) ); /*lint !e826*/
    2570 propdata->itusedbilin += SCIPgetNLPIterations(scip);
    2571
    2572 /* update number of LP iterations */
    2573 nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
    2574 SCIPdebugMsg(scip, "LP iterations left: %lld\n", nleftiterations);
    2575
    2576 /* add inequality to quadratic constraint handler if it separates (xt,yt) */
    2577 if( !SCIPisHugeValue(scip, xcoef) && !SCIPisFeasZero(scip, xcoef)
    2578 && REALABS(ycoef) < 1e+3 && REALABS(ycoef) > 1e-3 /* TODO add a parameter for this */
    2579 && SCIPisFeasGT(scip, (xcoef*xt - ycoef*yt - constant) / sqrt(SQR(xcoef) + SQR(ycoef) + SQR(constant)), 1e-2) )
    2580 {
    2581 SCIP_Bool success;
    2582
    2583 /* add inequality to the associated product expression */
    2584 SCIP_CALL( SCIPaddIneqBilinear(scip, bilinearnlhdlr, bilinbound->expr, xcoef, ycoef,
    2585 constant, &success) );
    2586
    2587 /* check whether the inequality has been accepted */
    2588 if( success )
    2589 {
    2590 *result = SCIP_REDUCEDDOM;
    2591 SCIPdebugMsg(scip, " found %g x <= %g y + %g with violation %g\n", xcoef, ycoef, constant,
    2592 (xcoef*xt - ycoef*yt - constant) / sqrt(SQR(xcoef) + SQR(ycoef) + SQR(constant)));
    2593
    2594 /* create a linear constraint that is only used for propagation */
    2595 if( propdata->createlincons && nnonzduals > 1 )
    2596 {
    2597 SCIP_CONS* cons;
    2598 char name[SCIP_MAXSTRLEN];
    2599 SCIP_VAR* linvars[2] = {x, y};
    2600 SCIP_Real linvals[2] = {xcoef, -ycoef};
    2601 SCIP_Real rhs = constant;
    2602
    2603 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "bilincons_%s_%s", SCIPvarGetName(x), SCIPvarGetName(y));
    2604 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 2, linvars, linvals, -SCIPinfinity(scip), rhs,
    2606
    2607 SCIP_CALL( SCIPaddCons(scip, cons) );
    2608 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    2609 }
    2610 }
    2611 }
    2612 }
    2613
    2614 /* mark the bound as processed */
    2615 bilinbound->done = TRUE;
    2616 }
    2617
    2618 /* remember last unprocessed bilinear term */
    2619 propdata->lastbilinidx = i;
    2620
    2621 TERMINATE:
    2622 /* end probing */
    2624
    2625 /* release cutoff row if there is one */
    2626 if( propdata->cutoffrow != NULL )
    2627 {
    2628 assert(!SCIProwIsInLP(propdata->cutoffrow));
    2629 SCIP_CALL( SCIPreleaseRow(scip, &(propdata->cutoffrow)) );
    2630 }
    2631
    2632 /* 6. restore old tolerance */
    2633 (void) SCIPchgRelaxfeastol(scip, oldfeastol);
    2634
    2635 return SCIP_OKAY;
    2636}
    2637
    2638/** computes the score of a bound */
    2639static
    2640unsigned int getScore(
    2641 SCIP* scip, /**< SCIP data structure */
    2642 BOUND* bound, /**< pointer of bound */
    2643 int nlcount, /**< number of nonlinear constraints containing the bounds variable */
    2644 int nindcount, /**< number of indicator constraints containing the bounds variable */
    2645 int maxnlcount, /**< maximal number of nonlinear and indicator constraints a variable appears in */
    2646 SCIP_Real smallub /**< variables with upper bound smaller than this value are counted in half iff part of indicator constraints */
    2647 )
    2648{
    2649 SCIP_Real counter;
    2650 unsigned int score; /* score to be computed */
    2651
    2652 assert(scip != NULL);
    2653 assert(bound != NULL);
    2654 assert(nlcount >= 0);
    2655 assert(nindcount >= 0);
    2656 assert(maxnlcount >= nlcount + nindcount);
    2657
    2658 counter = nlcount;
    2659 if( nindcount > 0 )
    2660 {
    2661 /* variables with small upper bound are counted in half
    2662 * since the probability is high that the corresponding indicator constraint is already reformulated as bigM constraint
    2663 */
    2664 if( SCIPvarGetUbLocal(bound->var) <= smallub )
    2665 counter += 0.5 * nindcount;
    2666 else
    2667 counter += nindcount;
    2668 }
    2669
    2670 /* score = ( nlcount * ( BASE - 1 ) / maxnlcount ) * BASE^2 + vartype * BASE + boundtype */
    2671 score = (unsigned int) ( counter > 0 ? (OBBT_SCOREBASE * counter * ( OBBT_SCOREBASE - 1 )) / maxnlcount : 0 ); /*lint !e414*/
    2673 score += 2;
    2674 else
    2675 {
    2676 switch( SCIPvarGetType(bound->var) )
    2677 {
    2679 score += 4;
    2680 break;
    2682 score += 1;
    2683 break;
    2685 score += 3;
    2686 break;
    2687 default:
    2688 SCIPerrorMessage("invalid variable type\n");
    2689 SCIPABORT();
    2690 return 0; /*lint !e527*/
    2691 } /*lint !e788*/
    2692 }
    2693
    2694 score *= OBBT_SCOREBASE;
    2695 if( bound->boundtype == SCIP_BOUNDTYPE_UPPER )
    2696 score += 1;
    2697
    2698 return score;
    2699}
    2700
    2701/** count how often each variable is used in a nonconvex term */
    2702static
    2704 SCIP* scip, /**< SCIP data structure */
    2705 unsigned int* nccounts /**< store the number each variable appears in a
    2706 * non-convex term */
    2707 )
    2708{
    2709 SCIP_CONSHDLR* conshdlr;
    2710 SCIP_HASHMAP* var2expr;
    2711 int nvars;
    2712 int i;
    2713
    2714 assert(scip != NULL);
    2715 assert(nccounts != NULL);
    2716
    2717 nvars = SCIPgetNVars(scip);
    2718
    2719 /* initialize nccounts to zero */
    2720 BMSclearMemoryArray(nccounts, nvars);
    2721
    2722 /* get nonlinear constraint handler */
    2723 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
    2724 if( conshdlr == NULL || SCIPconshdlrGetNConss(conshdlr) == 0 )
    2725 return SCIP_OKAY;
    2726
    2727 var2expr = SCIPgetVarExprHashmapNonlinear(conshdlr);
    2728 assert(var2expr != NULL);
    2729
    2730 for( i = 0; i < SCIPgetNVars(scip); ++i )
    2731 {
    2732 SCIP_VAR* var;
    2733
    2734 var = SCIPgetVars(scip)[i];
    2735 assert(var != NULL);
    2736
    2737 if( SCIPhashmapExists(var2expr, (void*) var) )
    2738 {
    2739 SCIP_EXPR* expr = (SCIP_EXPR*)SCIPhashmapGetImage(var2expr, (void*) var);
    2740 assert(expr != NULL);
    2741 assert(SCIPisExprVar(scip, expr));
    2742
    2744 }
    2745 }
    2746
    2747#ifdef SCIP_DEBUG
    2748 for( i = 0; i < SCIPgetNVars(scip); ++i)
    2749 {
    2750 SCIP_VAR* var = SCIPgetVars(scip)[i];
    2751 assert(var != NULL);
    2752 SCIPdebugMsg(scip, "nccounts[%s] = %u\n", SCIPvarGetName(var), nccounts[SCIPvarGetProbindex(var)]);
    2753 }
    2754#endif
    2755
    2756 return SCIP_OKAY;
    2757}
    2758
    2759/** computes for each variable the number of indicator constraints in which the variable appears */
    2760static
    2762 SCIP* scip, /**< SCIP data structure */
    2763 int* nindcount /**< array that stores in how many indicator conss each variable appears */
    2764 )
    2765{
    2766 SCIP_CONSHDLR* conshdlr;
    2767 SCIP_CONS** indconss;
    2768 int nvars;
    2769 int nindconss;
    2770
    2771 assert(scip != NULL);
    2772 assert(nindcount != NULL);
    2773
    2774 nvars = SCIPgetNVars(scip);
    2775
    2776 /* initialize nindcount to zero */
    2777 BMSclearMemoryArray(nindcount, nvars);
    2778
    2779 /* get indicator constraint handler */
    2780 conshdlr = SCIPfindConshdlr(scip, "indicator");
    2781 if( conshdlr == NULL || SCIPconshdlrGetNConss(conshdlr) == 0 )
    2782 return SCIP_OKAY;
    2783
    2784 nindconss = SCIPconshdlrGetNConss(conshdlr);
    2785 indconss = SCIPconshdlrGetConss(conshdlr);
    2786
    2787 for( int i = 0; i < nindconss; ++i )
    2788 {
    2789 SCIP_VAR** consvars;
    2790 SCIP_VAR* slackvar;
    2791 SCIP_CONS* lincons;
    2792 int nconsvars;
    2793
    2794 lincons = SCIPgetLinearConsIndicator(indconss[i]);
    2795 assert(lincons!=NULL);
    2796
    2797 nconsvars = SCIPgetNVarsLinear(scip, lincons);
    2798 consvars = SCIPgetVarsLinear(scip, lincons);
    2799 assert(consvars != NULL);
    2800 slackvar = SCIPgetSlackVarIndicator(indconss[i]);
    2801
    2802 for( int v = 0; v < nconsvars; ++v )
    2803 {
    2804 /* we should skip the slackvariable */
    2805 if( consvars[v] == slackvar )
    2806 continue;
    2807
    2808 /* consider only active variables */
    2809 if( SCIPvarGetStatus(consvars[v]) == SCIP_VARSTATUS_COLUMN )
    2810 {
    2811 nindcount[SCIPvarGetProbindex(consvars[v])] += 1;
    2812 }
    2813 }
    2814 }
    2815
    2816 return SCIP_OKAY;
    2817}
    2818
    2819/** determines whether a variable is interesting */
    2820static
    2822 SCIP* scip, /**< SCIP data structure */
    2823 SCIP_VAR* var, /**< variable to check */
    2824 int nlcount, /**< number of nonlinear constraints containing the variable
    2825 * or number of non-convex terms containing the variable
    2826 * (depends on propdata->onlynonconvexvars) */
    2827 int nindcount /**< number of indicator constraints containing the variable
    2828 * or 0 (depends on propdata->indicators) */
    2829 )
    2830{
    2831 assert(SCIPgetDepth(scip) == 0);
    2832
    2833 return !SCIPvarIsBinary(var) && SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN && (nlcount > 0 || nindcount > 0)
    2834 && !varIsFixedLocal(scip, var);
    2835}
    2836
    2837/** initializes interesting bounds */
    2838static
    2840 SCIP* scip, /**< SCIP data structure */
    2841 SCIP_PROPDATA* propdata /**< data of the obbt propagator */
    2842 )
    2843{
    2844 SCIP_CONSHDLR* conshdlr;
    2845 SCIP_VAR** vars; /* array of the problems variables */
    2846 int* nlcount; /* array that stores in how many nonlinearities each variable appears */
    2847 int* nindcount; /* array that stores in how many indicator constraints each variable appears */
    2848 unsigned int* nccount; /* array that stores in how many nonconvexities each variable appears */
    2849 SCIP_Real maxcouplingvalue;
    2850 SCIP_Real sepacouplingvalue;
    2851 SCIP_Real smallub;
    2852
    2853 int bdidx; /* bound index inside propdata->bounds */
    2854 int maxnlcount; /* maximal number of nonlinear and indicator constraints a variable appears in */
    2855 int nvars; /* number of the problems variables */
    2856 int i;
    2857
    2858 assert(scip != NULL);
    2859 assert(propdata != NULL);
    2860 assert(SCIPisNLPConstructed(scip) || propdata->indicators);
    2861
    2862 SCIPdebugMsg(scip, "initialize bounds\n");
    2863
    2864 /* get variable data */
    2865 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    2866
    2867 SCIP_CALL( SCIPallocBufferArray(scip, &nlcount, nvars) );
    2868 SCIP_CALL( SCIPallocBufferArray(scip, &nccount, nvars) );
    2869 SCIP_CALL( SCIPallocBufferArray(scip, &nindcount, nvars) );
    2870
    2871 /* count nonlinearities */
    2873 {
    2874 assert(SCIPgetNNLPVars(scip) == nvars);
    2877 }
    2878 else
    2879 {
    2880 /* initialize to zero */
    2881 BMSclearMemoryArray(nlcount, nvars);
    2882 BMSclearMemoryArray(nccount, nvars);
    2883 }
    2884
    2885 /* count indicators */
    2886 if( propdata->indicators )
    2887 {
    2888 SCIP_CALL( getNVarsIndicators(scip, nindcount) );
    2889 }
    2890 else
    2891 {
    2892 /* initialize to zero */
    2893 BMSclearMemoryArray(nindcount, nvars);
    2894 }
    2895
    2896 maxnlcount = 0;
    2897 for( i = 0; i < nvars; i++ )
    2898 {
    2899 if( maxnlcount < (nlcount[i] + nindcount[i]) )
    2900 maxnlcount = nlcount[i] + nindcount[i];
    2901 }
    2902
    2903 /* allocate interesting bounds array */
    2904 propdata->boundssize = 2 * nvars;
    2905 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->bounds), 2 * nvars) );
    2906
    2907 SCIP_CALL( SCIPgetRealParam(scip, "constraints/indicator/maxcouplingvalue", &maxcouplingvalue) );
    2908 SCIP_CALL( SCIPgetRealParam(scip, "constraints/indicator/sepacouplingvalue", &sepacouplingvalue) );
    2909
    2910 smallub = MIN(maxcouplingvalue, sepacouplingvalue);
    2911
    2912 /* get all interesting variables and their bounds */
    2913 bdidx = 0;
    2914 for( i = 0; i < nvars; i++ )
    2915 {
    2916 if( varIsInteresting(scip, vars[i], (propdata->onlynonconvexvars ? (int)nccount[i] : nlcount[i]), (propdata->indicators ? nindcount[i] : 0))
    2917 && indicatorVarIsInteresting(scip, vars[i], (propdata->onlynonconvexvars ? (int)nccount[i] : nlcount[i]), (propdata->indicators ? nindcount[i] : 0), propdata->indicatorthreshold) )
    2918 {
    2919 BOUND** bdaddress;
    2920
    2921 /* create lower bound */
    2922 bdaddress = &(propdata->bounds[bdidx]);
    2923 SCIP_CALL( SCIPallocBlockMemory(scip, bdaddress) );
    2924 propdata->bounds[bdidx]->boundtype = SCIP_BOUNDTYPE_LOWER;
    2925 propdata->bounds[bdidx]->var = vars[i];
    2926 propdata->bounds[bdidx]->found = FALSE;
    2927 propdata->bounds[bdidx]->filtered = FALSE;
    2928 propdata->bounds[bdidx]->newval = 0.0;
    2929 propdata->bounds[bdidx]->score = getScore(scip, propdata->bounds[bdidx], nlcount[i], nindcount[i], maxnlcount, smallub);
    2930 propdata->bounds[bdidx]->done = FALSE;
    2931 propdata->bounds[bdidx]->nonconvex = (nccount[i] > 0);
    2932 propdata->bounds[bdidx]->indicator = (nindcount[i] > 0);
    2933 propdata->bounds[bdidx]->index = bdidx;
    2934 bdidx++;
    2935
    2936 /* create upper bound */
    2937 bdaddress = &(propdata->bounds[bdidx]);
    2938 SCIP_CALL( SCIPallocBlockMemory(scip, bdaddress) );
    2939 propdata->bounds[bdidx]->boundtype = SCIP_BOUNDTYPE_UPPER;
    2940 propdata->bounds[bdidx]->var = vars[i];
    2941 propdata->bounds[bdidx]->found = FALSE;
    2942 propdata->bounds[bdidx]->filtered = FALSE;
    2943 propdata->bounds[bdidx]->newval = 0.0;
    2944 propdata->bounds[bdidx]->score = getScore(scip, propdata->bounds[bdidx], nlcount[i], nindcount[i], maxnlcount, smallub);
    2945 propdata->bounds[bdidx]->done = FALSE;
    2946 propdata->bounds[bdidx]->nonconvex = (nccount[i] > 0);
    2947 propdata->bounds[bdidx]->indicator = (nindcount[i] > 0);
    2948 propdata->bounds[bdidx]->index = bdidx;
    2949 bdidx++;
    2950 }
    2951 }
    2952
    2953 /* set number of interesting bounds */
    2954 propdata->nbounds = bdidx;
    2955
    2956 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
    2957
    2958 /* get all product expressions from nonlinear constraint handler */
    2959 if( propdata->nbounds > 0 && conshdlr != NULL && propdata->createbilinineqs )
    2960 {
    2961 SCIP_NLHDLR* bilinnlhdlr;
    2962 SCIP_EXPR** exprs;
    2963 int nexprs;
    2964
    2965 /* find nonlinear handler for bilinear terms */
    2966 bilinnlhdlr = SCIPfindNlhdlrNonlinear(conshdlr, "bilinear");
    2967 assert(bilinnlhdlr != NULL);
    2968
    2969 /* collect all bilinear product in all nonlinear constraints */
    2970 exprs = SCIPgetExprsBilinear(bilinnlhdlr);
    2971 nexprs = SCIPgetNExprsBilinear(bilinnlhdlr);
    2972
    2973 if( nexprs > 0 )
    2974 {
    2975 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->bilinbounds, nexprs) );
    2976 propdata->bilinboundssize = nexprs;
    2977 propdata->nbilinbounds = 0;
    2978
    2979 /* store candidates as bilinear bounds */
    2980 for( i = 0; i < nexprs; ++i )
    2981 {
    2982 BILINBOUND* bilinbound;
    2983 SCIP_VAR* x;
    2984 SCIP_VAR* y;
    2985
    2986 assert(exprs[i] != NULL);
    2987 assert(SCIPexprGetNChildren(exprs[i]) == 2);
    2988
    2991 assert(x != NULL);
    2992 assert(y != NULL);
    2993 assert(x != y);
    2994
    2995 /* skip almost fixed variables */
    2996 if( !varIsInteresting(scip, x, 1, 0) || !varIsInteresting(scip, y, 1, 0) )
    2997 continue;
    2998
    2999 /* create bilinear bound */
    3000 SCIP_CALL( SCIPallocBlockMemory(scip, &propdata->bilinbounds[propdata->nbilinbounds]) ); /*lint !e866*/
    3001 bilinbound = propdata->bilinbounds[propdata->nbilinbounds];
    3002 BMSclearMemory(bilinbound);
    3003
    3004 /* store and capture expression */
    3005 bilinbound->expr = exprs[i];
    3006 SCIPcaptureExpr(bilinbound->expr);
    3007
    3008 /* compute a descent score */
    3009 bilinbound->score = bilinboundGetScore(scip, propdata->randnumgen, bilinbound);
    3010
    3011 /* increase the number of bilinear bounds */
    3012 ++(propdata->nbilinbounds);
    3013
    3014 SCIPdebugMsg(scip, "added bilinear bound for %s %s\n", SCIPvarGetName(x), SCIPvarGetName(y));
    3015 }
    3016 }
    3017
    3018 /* sort bounds according to decreasing score */
    3019 if( propdata->nbilinbounds > 1 )
    3020 {
    3021 SCIPsortDownPtr((void**) propdata->bilinbounds, compBilinboundsScore, propdata->nbilinbounds);
    3022 }
    3023 }
    3024
    3025 /* free memory for buffering nonlinearities */
    3026 assert(nlcount != NULL);
    3027 assert(nccount != NULL);
    3028 assert(nindcount != NULL);
    3029 SCIPfreeBufferArray(scip, &nindcount);
    3030 SCIPfreeBufferArray(scip, &nccount);
    3031 SCIPfreeBufferArray(scip, &nlcount);
    3032
    3033 /* propdata->bounds array if empty */
    3034 if( propdata->nbounds <= 0 )
    3035 {
    3036 assert(propdata->nbounds == 0);
    3037 assert(propdata->boundssize >= 0 );
    3038 SCIPfreeBlockMemoryArray(scip, &(propdata->bounds), propdata->boundssize);
    3039 }
    3040
    3041 SCIPdebugMsg(scip, "problem has %d/%d interesting bounds\n", propdata->nbounds, 2 * nvars);
    3042
    3043 if( propdata->nbounds > 0 )
    3044 {
    3045 /* sort bounds according to decreasing score; although this initial order will be overruled by the distance
    3046 * criterion later, gives a more well-defined starting situation for OBBT and might help to reduce solver
    3047 * variability
    3048 */
    3049 SCIPsortDownPtr((void**) propdata->bounds, compBoundsScore, propdata->nbounds);
    3050 }
    3051
    3052 return SCIP_OKAY;
    3053}
    3054
    3055/*
    3056 * Callback methods of propagator
    3057 */
    3058
    3059/** copy method for propagator plugins (called when SCIP copies plugins)
    3060 *
    3061 * @note The UG framework assumes that all default plug-ins of SCIP implement a copy callback. We check
    3062 * SCIPgetSubscipDepth() in PROPEXEC to prevent the propagator to run in a sub-SCIP.
    3063 */
    3064static
    3066{ /*lint --e{715}*/
    3067 assert(scip != NULL);
    3068 assert(prop != NULL);
    3069
    3071
    3072 /* call inclusion method of constraint handler */
    3074
    3075 return SCIP_OKAY;
    3076}
    3077
    3078/** solving process initialization method of propagator (called when branch and bound process is about to begin) */
    3079static
    3081{ /*lint --e{715}*/
    3082 SCIP_PROPDATA* propdata;
    3083
    3084 assert(scip != NULL);
    3085 assert(prop != NULL);
    3086
    3088
    3089 /* get propagator data */
    3090 propdata = SCIPpropGetData(prop);
    3091 assert(propdata != NULL);
    3092
    3093 propdata->bounds = NULL;
    3094 propdata->nbounds = -1;
    3095 propdata->boundssize = 0;
    3096 propdata->cutoffrow = NULL;
    3097 propdata->lastnode = -1;
    3098
    3099 /* if genvbounds propagator is not available, we cannot create genvbounds */
    3100 propdata->genvboundprop = propdata->creategenvbounds ? SCIPfindProp(scip, GENVBOUND_PROP_NAME) : NULL;
    3101
    3102 SCIPdebugMsg(scip, "creating genvbounds: %s\n", propdata->genvboundprop != NULL ? "true" : "false");
    3103
    3104 /* create random number generator */
    3105 SCIP_CALL( SCIPcreateRandom(scip, &propdata->randnumgen, DEFAULT_RANDSEED, TRUE) );
    3106
    3107 return SCIP_OKAY;
    3108}
    3109
    3110/** execution method of propagator */
    3111static
    3113{ /*lint --e{715}*/
    3114 SCIP_PROPDATA* propdata;
    3115 SCIP_Longint itlimit;
    3116
    3117 assert(scip != NULL);
    3118 assert(prop != NULL);
    3119
    3121
    3122 *result = SCIP_DIDNOTRUN;
    3123
    3124 /* do not run in: presolving, repropagation, probing mode, if no objective propagation is allowed */
    3126 return SCIP_OKAY;
    3127
    3128 /* do not run propagator in a sub-SCIP */
    3129 if( SCIPgetSubscipDepth(scip) > 0 )
    3130 return SCIP_OKAY;
    3131
    3132 /* get propagator data */
    3133 propdata = SCIPpropGetData(prop);
    3134 assert(propdata != NULL);
    3135
    3136 /* only run for nonlinear problems, i.e., if NLP is constructed
    3137 * or if indicator constraints exists and should be considered
    3138 */
    3140 && (!propdata->indicators || SCIPfindConshdlr(scip, "indicator") == NULL || SCIPconshdlrGetNConss(SCIPfindConshdlr(scip, "indicator")) == 0) )
    3141 {
    3142 SCIPdebugMsg(scip, "NLP not constructed and no indicator constraints available, skipping obbt\n");
    3143 return SCIP_OKAY;
    3144 }
    3145
    3146 /* only run if LP all columns are in the LP, i.e., the LP is a relaxation; e.g., do not run if pricers are active
    3147 * since pricing is not performed in probing mode
    3148 */
    3149 if( !SCIPallColsInLP(scip) )
    3150 {
    3151 SCIPdebugMsg(scip, "not all columns in LP, skipping obbt\n");
    3152 return SCIP_OKAY;
    3153 }
    3154
    3155 /* ensure that bounds are initialized */
    3156 if( propdata->nbounds == -1 )
    3157 {
    3158 /* bounds must be initialized at root node */
    3159 if( SCIPgetDepth(scip) == 0 )
    3160 {
    3161 SCIP_CALL( initBounds(scip, propdata) );
    3162 }
    3163 else
    3164 {
    3165 assert(!SCIPinProbing(scip));
    3166 return SCIP_OKAY;
    3167 }
    3168 }
    3169 assert(propdata->nbounds >= 0);
    3170
    3171 /* do not run if there are no interesting bounds */
    3172 /**@todo disable */
    3173 if( propdata->nbounds <= 0 )
    3174 {
    3175 SCIPdebugMsg(scip, "there are no interesting bounds\n");
    3176 return SCIP_OKAY;
    3177 }
    3178
    3179 /* only run once in a node != root */
    3180 if( SCIPgetDepth(scip) > 0 && SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) == propdata->lastnode )
    3181 {
    3182 return SCIP_OKAY;
    3183 }
    3184
    3185 SCIPdebugMsg(scip, "applying obbt for problem <%s> at depth %d\n", SCIPgetProbName(scip), SCIPgetDepth(scip));
    3186
    3187 /* without an optimal LP solution we don't want to run; this may be because propagators with higher priority have
    3188 * already found reductions or numerical troubles occurred during LP solving
    3189 */
    3191 {
    3192 SCIPdebugMsg(scip, "aborting since no optimal LP solution is at hand\n");
    3193 return SCIP_OKAY;
    3194 }
    3195
    3196 /* compute iteration limit */
    3197 if( propdata->itlimitfactor > 0.0 )
    3198 itlimit = (SCIP_Longint) MAX(propdata->itlimitfactor * SCIPgetNRootLPIterations(scip),
    3199 propdata->minitlimit); /*lint !e666*/
    3200 else
    3201 itlimit = -1;
    3202
    3203 /* apply obbt */
    3204 SCIP_CALL( applyObbt(scip, propdata, itlimit, result) );
    3205 assert(*result != SCIP_DIDNOTRUN);
    3206
    3207 /* compute globally inequalities for bilinear terms */
    3208 if( propdata->createbilinineqs )
    3209 {
    3210 /* set LP iteration limit */
    3211 if( propdata->itlimitbilin == 0L )
    3212 {
    3213 /* no iteration limit if itlimit < 0 or itlimitfactorbilin < 0 */
    3214 propdata->itlimitbilin = (itlimit < 0 || propdata->itlimitfactorbilin < 0)
    3215 ? -1L : (SCIP_Longint)(itlimit * propdata->itlimitfactorbilin);
    3216 }
    3217
    3218 SCIP_CALL( applyObbtBilinear(scip, propdata, itlimit, result) );
    3219 }
    3220
    3221 /* set current node as last node */
    3222 propdata->lastnode = SCIPnodeGetNumber(SCIPgetCurrentNode(scip));
    3223
    3224 return SCIP_OKAY;
    3225}
    3226
    3227/** propagation conflict resolving method of propagator */
    3228static
    3230{ /*lint --e{715}*/
    3231 *result = SCIP_DIDNOTFIND;
    3232
    3233 return SCIP_OKAY;
    3234}
    3235
    3236/** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
    3237static
    3239{ /*lint --e{715}*/
    3240 SCIP_PROPDATA* propdata;
    3241 int i;
    3242
    3243 assert(scip != NULL);
    3244 assert(prop != NULL);
    3245
    3247
    3248 /* get propagator data */
    3249 propdata = SCIPpropGetData(prop);
    3250 assert(propdata != NULL);
    3251
    3252 /* free random number generator */
    3253 SCIPfreeRandom(scip, &propdata->randnumgen);
    3254 propdata->randnumgen = NULL;
    3255
    3256 /* note that because we reset filtered flags to false at each call to obbt, the same bound may be filtered multiple
    3257 * times
    3258 */
    3259 SCIPstatisticMessage("DIVE-LP: %" SCIP_LONGINT_FORMAT " NFILTERED: %d NTRIVIALFILTERED: %d NSOLVED: %d "
    3260 "FILTER-LP: %" SCIP_LONGINT_FORMAT " NGENVB(dive): %d NGENVB(aggr.): %d NGENVB(triv.) %d\n",
    3261 propdata->nprobingiterations, propdata->nfiltered, propdata->ntrivialfiltered, propdata->nsolvedbounds,
    3262 propdata->nfilterlpiters, propdata->ngenvboundsprobing, propdata->ngenvboundsaggrfil, propdata->ngenvboundstrivfil);
    3263
    3264 /* free bilinear bounds */
    3265 if( propdata->bilinboundssize > 0 )
    3266 {
    3267 for( i = propdata->nbilinbounds - 1; i >= 0; --i )
    3268 {
    3269 assert(propdata->bilinbounds[i] != NULL);
    3270 assert(propdata->bilinbounds[i]->expr != NULL);
    3271
    3272 /* release expression */
    3273 SCIP_CALL( SCIPreleaseExpr(scip, &propdata->bilinbounds[i]->expr) );
    3274
    3275 SCIPfreeBlockMemory(scip, &propdata->bilinbounds[i]); /*lint !e866*/
    3276 }
    3277 SCIPfreeBlockMemoryArray(scip, &propdata->bilinbounds, propdata->bilinboundssize);
    3278 propdata->bilinboundssize = 0;
    3279 propdata->nbilinbounds = 0;
    3280 }
    3281
    3282 /* free memory allocated for the bounds */
    3283 if( propdata->nbounds > 0 )
    3284 {
    3285 /* free bounds */
    3286 for( i = propdata->nbounds - 1; i >= 0; i-- )
    3287 {
    3288 SCIPfreeBlockMemory(scip, &(propdata->bounds[i])); /*lint !e866*/
    3289 }
    3290 SCIPfreeBlockMemoryArray(scip, &(propdata->bounds), propdata->boundssize);
    3291 }
    3292
    3293 propdata->nbounds = -1;
    3294 propdata->itlimitbilin = 0;
    3295 propdata->itusedbilin = 0;
    3296
    3297 return SCIP_OKAY;
    3298}
    3299
    3300/** destructor of propagator to free user data (called when SCIP is exiting) */
    3301static
    3303{ /*lint --e{715}*/
    3304 SCIP_PROPDATA* propdata;
    3305
    3307
    3308 /* free propagator data */
    3309 propdata = SCIPpropGetData(prop);
    3310 assert(propdata != NULL);
    3311
    3312 SCIPfreeBlockMemory(scip, &propdata);
    3313
    3314 SCIPpropSetData(prop, NULL);
    3315
    3316 return SCIP_OKAY;
    3317}
    3318
    3319/*
    3320 * propagator specific interface methods
    3321 */
    3322
    3323/** creates the obbt propagator and includes it in SCIP */
    3325 SCIP* scip /**< SCIP data structure */
    3326 )
    3327{
    3328 SCIP_PROPDATA* propdata;
    3329 SCIP_PROP* prop;
    3330
    3331 /* create obbt propagator data */
    3332 SCIP_CALL( SCIPallocBlockMemory(scip, &propdata) );
    3333 BMSclearMemory(propdata);
    3334
    3335 /* initialize statistic variables */
    3336 propdata->nprobingiterations = 0;
    3337 propdata->nfiltered = 0;
    3338 propdata->ntrivialfiltered = 0;
    3339 propdata->nsolvedbounds = 0;
    3340 propdata->ngenvboundsprobing = 0;
    3341 propdata->ngenvboundsaggrfil = 0;
    3342 propdata->ngenvboundstrivfil = 0;
    3343 propdata->nfilterlpiters = 0;
    3344 propdata->lastidx = -1;
    3345 propdata->propagatecounter = 0;
    3346 propdata->npropagatedomreds = 0;
    3347
    3348 /* include propagator */
    3350 propExecObbt, propdata) );
    3351
    3352 SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyObbt) );
    3353 SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeObbt) );
    3354 SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolObbt) );
    3355 SCIP_CALL( SCIPsetPropInitsol(scip, prop, propInitsolObbt) );
    3356 SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropObbt) );
    3357
    3358 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/creategenvbounds",
    3359 "should obbt try to provide genvbounds if possible?",
    3360 &propdata->creategenvbounds, TRUE, DEFAULT_CREATE_GENVBOUNDS, NULL, NULL) );
    3361
    3362 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/normalize",
    3363 "should coefficients in filtering be normalized w.r.t. the domains sizes?",
    3364 &propdata->normalize, TRUE, DEFAULT_FILTERING_NORM, NULL, NULL) );
    3365
    3366 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/applyfilterrounds",
    3367 "try to filter bounds in so-called filter rounds by solving auxiliary LPs?",
    3368 &propdata->applyfilterrounds, TRUE, DEFAULT_APPLY_FILTERROUNDS, NULL, NULL) );
    3369
    3370 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/applytrivialfilter",
    3371 "try to filter bounds with the LP solution after each solve?",
    3372 &propdata->applytrivialfilter, TRUE, DEFAULT_APPLY_TRIVIALFITLERING, NULL, NULL) );
    3373
    3374 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/genvbdsduringfilter",
    3375 "should we try to generate genvbounds during trivial and aggressive filtering?",
    3376 &propdata->genvbdsduringfilter, TRUE, DEFAULT_GENVBDSDURINGFILTER, NULL, NULL) );
    3377
    3378 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/genvbdsduringsepa",
    3379 "try to create genvbounds during separation process?",
    3380 &propdata->genvbdsduringsepa, TRUE, DEFAULT_GENVBDSDURINGSEPA, NULL, NULL) );
    3381
    3382 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/minfilter",
    3383 "minimal number of filtered bounds to apply another filter round",
    3384 &propdata->nminfilter, TRUE, DEFAULT_FILTERING_MIN, 1, INT_MAX, NULL, NULL) );
    3385
    3386 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/itlimitfactor",
    3387 "multiple of root node LP iterations used as total LP iteration limit for obbt (<= 0: no limit )",
    3388 &propdata->itlimitfactor, FALSE, DEFAULT_ITLIMITFACTOR, SCIP_REAL_MIN, SCIP_REAL_MAX, NULL, NULL) );
    3389
    3390 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/itlimitfactorbilin",
    3391 "multiple of OBBT LP limit used as total LP iteration limit for solving bilinear inequality LPs (< 0 for no limit)",
    3392 &propdata->itlimitfactorbilin, FALSE, DEFAULT_ITLIMITFAC_BILININEQS, SCIP_REAL_MIN, SCIP_REAL_MAX, NULL, NULL) );
    3393
    3394 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/minnonconvexity",
    3395 "minimum absolute value of nonconvex eigenvalues for a bilinear term",
    3396 &propdata->minnonconvexity, FALSE, DEFAULT_MINNONCONVEXITY, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    3397
    3398 SCIP_CALL( SCIPaddLongintParam(scip, "propagating/" PROP_NAME "/minitlimit",
    3399 "minimum LP iteration limit",
    3400 &propdata->minitlimit, FALSE, DEFAULT_MINITLIMIT, 0L, SCIP_LONGINT_MAX, NULL, NULL) );
    3401
    3402 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/dualfeastol",
    3403 "feasibility tolerance for reduced costs used in obbt; this value is used if SCIP's dual feastol is greater",
    3404 &propdata->dualfeastol, FALSE, DEFAULT_DUALFEASTOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    3405
    3406 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/conditionlimit",
    3407 "maximum condition limit used in LP solver (-1.0: no limit)",
    3408 &propdata->conditionlimit, FALSE, DEFAULT_CONDITIONLIMIT, -1.0, SCIP_REAL_MAX, NULL, NULL) );
    3409
    3410 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/boundstreps",
    3411 "minimal relative improve for strengthening bounds",
    3412 &propdata->boundstreps, FALSE, DEFAULT_BOUNDSTREPS, 0.0, 1.0, NULL, NULL) );
    3413
    3414 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/indicatorthreshold",
    3415 "threshold whether upper bounds of vars of indicator conss are considered or tightened",
    3416 &propdata->indicatorthreshold, TRUE, DEFAULT_INDICATORTHRESHOLD, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    3417
    3418 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/onlynonconvexvars",
    3419 "only apply obbt on non-convex variables",
    3420 &propdata->onlynonconvexvars, TRUE, DEFAULT_ONLYNONCONVEXVARS, NULL, NULL) );
    3421
    3422 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/indicators",
    3423 "apply obbt on variables of indicator constraints? (independent of convexity)",
    3424 &propdata->indicators, TRUE, DEFAULT_INDICATORS, NULL, NULL) );
    3425
    3426 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/tightintboundsprobing",
    3427 "should integral bounds be tightened during the probing mode?",
    3428 &propdata->tightintboundsprobing, TRUE, DEFAULT_TIGHTINTBOUNDSPROBING, NULL, NULL) );
    3429
    3430 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/tightcontboundsprobing",
    3431 "should continuous bounds be tightened during the probing mode?",
    3432 &propdata->tightcontboundsprobing, TRUE, DEFAULT_TIGHTCONTBOUNDSPROBING, NULL, NULL) );
    3433
    3434 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/createbilinineqs",
    3435 "solve auxiliary LPs in order to find valid inequalities for bilinear terms?",
    3436 &propdata->createbilinineqs, TRUE, DEFAULT_CREATE_BILININEQS, NULL, NULL) );
    3437
    3438 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/createlincons",
    3439 "create linear constraints from inequalities for bilinear terms?",
    3440 &propdata->createlincons, TRUE, DEFAULT_CREATE_LINCONS, NULL, NULL) );
    3441
    3442 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/orderingalgo",
    3443 "select the type of ordering algorithm which should be used (0: no special ordering, 1: greedy, 2: greedy reverse)",
    3444 &propdata->orderingalgo, TRUE, DEFAULT_ORDERINGALGO, 0, 2, NULL, NULL) );
    3445
    3446 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/separatesol",
    3447 "should the obbt LP solution be separated?",
    3448 &propdata->separatesol, TRUE, DEFAULT_SEPARATESOL, NULL, NULL) );
    3449
    3450 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/sepaminiter",
    3451 "minimum number of iteration spend to separate an obbt LP solution",
    3452 &propdata->sepaminiter, TRUE, DEFAULT_SEPAMINITER, 0, INT_MAX, NULL, NULL) );
    3453
    3454 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/sepamaxiter",
    3455 "maximum number of iteration spend to separate an obbt LP solution",
    3456 &propdata->sepamaxiter, TRUE, DEFAULT_SEPAMAXITER, 0, INT_MAX, NULL, NULL) );
    3457
    3458 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/propagatefreq",
    3459 "trigger a propagation round after that many bound tightenings (0: no propagation)",
    3460 &propdata->propagatefreq, TRUE, DEFAULT_PROPAGATEFREQ, 0, INT_MAX, NULL, NULL) );
    3461
    3462 return SCIP_OKAY;
    3463}
    static long bound
    SCIP_VAR ** y
    Definition: circlepacking.c:64
    SCIP_Real * r
    Definition: circlepacking.c:59
    SCIP_VAR ** x
    Definition: circlepacking.c:63
    constraint handler for indicator constraints
    Constraint handler for linear constraints in their most general form, .
    constraint handler for nonlinear constraints specified by algebraic expressions
    #define NULL
    Definition: def.h:257
    #define SCIP_MAXSTRLEN
    Definition: def.h:278
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_REAL_MAX
    Definition: def.h:167
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:100
    #define MIN(x, y)
    Definition: def.h:233
    #define MAX3(x, y, z)
    Definition: def.h:237
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define SQR(x)
    Definition: def.h:208
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define SCIPABORT()
    Definition: def.h:336
    #define SCIP_REAL_MIN
    Definition: def.h:168
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_LONGINT_MAX
    Definition: def.h:151
    #define EPSZ(x, eps)
    Definition: def.h:197
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_VAR ** SCIPgetVarsLinear(SCIP *scip, SCIP_CONS *cons)
    int SCIPgetExprNLocksPosNonlinear(SCIP_EXPR *expr)
    SCIP_HASHMAP * SCIPgetVarExprHashmapNonlinear(SCIP_CONSHDLR *conshdlr)
    int SCIPgetNVarsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
    unsigned int SCIPgetExprNSepaUsesActivityNonlinear(SCIP_EXPR *expr)
    SCIP_VAR * SCIPgetSlackVarIndicator(SCIP_CONS *cons)
    SCIP_CONS * SCIPgetLinearConsIndicator(SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    int SCIPgetExprNLocksNegNonlinear(SCIP_EXPR *expr)
    int SCIPgetSubscipDepth(SCIP *scip)
    Definition: scip_copy.c:2589
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:767
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    const char * SCIPgetProbName(SCIP *scip)
    Definition: scip_prob.c:1242
    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_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3284
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
    Definition: scip_message.c:120
    int SCIPgetNExprsBilinear(SCIP_NLHDLR *nlhdlr)
    SCIP_RETCODE SCIPaddIneqBilinear(SCIP *scip, SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Bool *success)
    SCIP_EXPR ** SCIPgetExprsBilinear(SCIP_NLHDLR *nlhdlr)
    SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
    Definition: misc.c:11162
    SCIP_RETCODE SCIPgenVBoundAdd(SCIP *scip, SCIP_PROP *genvboundprop, SCIP_VAR **vars, SCIP_VAR *var, SCIP_Real *coefs, int ncoefs, SCIP_Real coefcutoffbound, SCIP_Real constant, SCIP_BOUNDTYPE boundtype)
    SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:111
    SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:83
    SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:139
    SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
    Definition: scip_param.c:487
    SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
    Definition: scip_param.c:307
    SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    SCIP_RETCODE SCIPgetIntParam(SCIP *scip, const char *name, int *value)
    Definition: scip_param.c:269
    SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
    Definition: scip_param.c:603
    SCIP_RETCODE SCIPincludePropObbt(SCIP *scip)
    Definition: prop_obbt.c:3324
    SCIP_BASESTAT SCIPcolGetBasisStatus(SCIP_COL *col)
    Definition: lp.c:17414
    int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4782
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4739
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_RETCODE SCIPseparateSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool pretendroot, SCIP_Bool allowlocal, SCIP_Bool onlydelayed, SCIP_Bool *delayed, SCIP_Bool *cutoff)
    Definition: scip_cut.c:710
    int SCIPgetNCuts(SCIP *scip)
    Definition: scip_cut.c:762
    int SCIPexprGetNChildren(SCIP_EXPR *expr)
    Definition: expr.c:3872
    SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
    Definition: scip_expr.c:1443
    SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1457
    SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
    Definition: expr.c:3882
    void SCIPcaptureExpr(SCIP_EXPR *expr)
    Definition: scip_expr.c:1435
    SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
    Definition: scip_lp.c:611
    int SCIPgetNLPRows(SCIP *scip)
    Definition: scip_lp.c:632
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    SCIP_Bool SCIPallColsInLP(SCIP *scip)
    Definition: scip_lp.c:655
    SCIP_Real SCIPgetLPObjval(SCIP *scip)
    Definition: scip_lp.c:253
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    #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 SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPfreeBufferArrayNull(scip, ptr)
    Definition: scip_mem.h:137
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
    Definition: scip_nlp.c:110
    int SCIPgetNNLPVars(SCIP *scip)
    Definition: scip_nlp.c:201
    SCIP_RETCODE SCIPgetNLPVarsNonlinearity(SCIP *scip, int *nlcount)
    Definition: scip_nlp.c:223
    SCIP_NLHDLR * SCIPfindNlhdlrNonlinear(SCIP_CONSHDLR *conshdlr, const char *name)
    SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
    Definition: tree.c:8513
    SCIP_RETCODE SCIPaddRowProbing(SCIP *scip, SCIP_ROW *row)
    Definition: scip_probing.c:913
    SCIP_RETCODE SCIPapplyCutsProbing(SCIP *scip, SCIP_Bool *cutoff)
    Definition: scip_probing.c:953
    SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_probing.c:346
    SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_probing.c:302
    SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
    Definition: scip_probing.c:581
    SCIP_RETCODE SCIPchgVarObjProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
    Definition: scip_probing.c:475
    SCIP_RETCODE SCIPbacktrackProbing(SCIP *scip, int probingdepth)
    Definition: scip_probing.c:226
    SCIP_Bool SCIPinProbing(SCIP *scip)
    Definition: scip_probing.c:98
    SCIP_RETCODE SCIPstartProbing(SCIP *scip)
    Definition: scip_probing.c:120
    SCIP_Real SCIPgetVarObjProbing(SCIP *scip, SCIP_VAR *var)
    Definition: scip_probing.c:389
    SCIP_RETCODE SCIPnewProbingNode(SCIP *scip)
    Definition: scip_probing.c:166
    SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
    Definition: scip_probing.c:825
    SCIP_RETCODE SCIPendProbing(SCIP *scip)
    Definition: scip_probing.c:261
    SCIP_PROP * SCIPfindProp(SCIP *scip, const char *name)
    Definition: scip_prop.c:333
    void SCIPpropSetData(SCIP_PROP *prop, SCIP_PROPDATA *propdata)
    Definition: prop.c:801
    SCIP_RETCODE SCIPsetPropInitsol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPINITSOL((*propinitsol)))
    Definition: scip_prop.c:219
    SCIP_RETCODE SCIPsetPropResprop(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPRESPROP((*propresprop)))
    Definition: scip_prop.c:316
    SCIP_PROPDATA * SCIPpropGetData(SCIP_PROP *prop)
    Definition: prop.c:791
    const char * SCIPpropGetName(SCIP_PROP *prop)
    Definition: prop.c:951
    SCIP_RETCODE SCIPsetPropFree(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPFREE((*propfree)))
    Definition: scip_prop.c:171
    SCIP_RETCODE SCIPsetPropCopy(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPCOPY((*propcopy)))
    Definition: scip_prop.c:155
    SCIP_RETCODE SCIPsetPropExitsol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPEXITSOL((*propexitsol)))
    Definition: scip_prop.c:235
    SCIP_RETCODE SCIPincludePropBasic(SCIP *scip, SCIP_PROP **propptr, const char *name, const char *desc, int priority, int freq, SCIP_Bool delay, SCIP_PROPTIMING timingmask, SCIP_DECL_PROPEXEC((*propexec)), SCIP_PROPDATA *propdata)
    Definition: scip_prop.c:118
    SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1581
    SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1604
    SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_lp.c:1646
    SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1458
    SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
    Definition: lp.c:17917
    SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
    Definition: lp.c:17706
    SCIP_Longint SCIPgetNRootLPIterations(SCIP *scip)
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
    SCIP_Bool SCIPisUbBetter(SCIP *scip, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
    SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Real SCIPchgRelaxfeastol(SCIP *scip, SCIP_Real relaxfeastol)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLbBetter(SCIP *scip, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
    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 SCIPisHugeValue(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_Real SCIPdualfeastol(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_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_RETCODE SCIPchgDualfeastol(SCIP *scip, SCIP_Real dualfeastol)
    SCIP_Bool SCIPinRepropagation(SCIP *scip)
    Definition: scip_tree.c:146
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
    Definition: scip_tree.c:91
    SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6401
    SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
    Definition: var.c:23715
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23510
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23418
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23530
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6651
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23485
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    int SCIPvarGetProbindex(SCIP_VAR *var)
    Definition: var.c:23694
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23522
    SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
    Definition: var.c:24696
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_Real SCIPgetVarRedcost(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:2608
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    SCIP_Bool SCIPallowWeakDualReds(SCIP *scip)
    Definition: scip_var.c:10998
    void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
    SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
    Definition: misc.c:10245
    SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
    void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    #define BMSclearMemory(ptr)
    Definition: memory.h:129
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    bilinear nonlinear handler
    generalized variable bounds propagator
    #define PROP_DESC
    Definition: prop_obbt.c:81
    static SCIP_Real getFilterCoef(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype)
    Definition: prop_obbt.c:480
    static SCIP_DECL_PROPEXEC(propExecObbt)
    Definition: prop_obbt.c:3112
    #define GENVBOUND_PROP_NAME
    Definition: prop_obbt.c:115
    static SCIP_VAR * bilinboundGetY(BILINBOUND *bilinbound)
    Definition: prop_obbt.c:855
    #define DEFAULT_INDICATORS
    Definition: prop_obbt.c:105
    #define DEFAULT_APPLY_FILTERROUNDS
    Definition: prop_obbt.c:91
    #define DEFAULT_BOUNDSTREPS
    Definition: prop_obbt.c:98
    #define DEFAULT_DUALFEASTOL
    Definition: prop_obbt.c:95
    #define PROP_NAME
    Definition: prop_obbt.c:80
    #define DEFAULT_SEPAMINITER
    Definition: prop_obbt.c:120
    static SCIP_RETCODE filterExistingLP(SCIP *scip, SCIP_PROPDATA *propdata, int *nfiltered, BOUND *currbound)
    Definition: prop_obbt.c:961
    #define DEFAULT_FILTERING_MIN
    Definition: prop_obbt.c:99
    #define DEFAULT_MINNONCONVEXITY
    Definition: prop_obbt.c:128
    static SCIP_DECL_PROPRESPROP(propRespropObbt)
    Definition: prop_obbt.c:3229
    #define DEFAULT_INDICATORTHRESHOLD
    Definition: prop_obbt.c:106
    #define DEFAULT_SEPAMAXITER
    Definition: prop_obbt.c:121
    static SCIP_Real bilinboundGetScore(SCIP *scip, SCIP_RANDNUMGEN *randnumgen, BILINBOUND *bilinbound)
    Definition: prop_obbt.c:889
    static SCIP_RETCODE initBounds(SCIP *scip, SCIP_PROPDATA *propdata)
    Definition: prop_obbt.c:2839
    #define DEFAULT_CONDITIONLIMIT
    Definition: prop_obbt.c:97
    static int nextBound(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Bool convexphase)
    Definition: prop_obbt.c:1669
    static SCIP_RETCODE tightenBoundProbing(SCIP *scip, BOUND *bound, SCIP_Real newval, SCIP_Bool *tightened)
    Definition: prop_obbt.c:1531
    static SCIP_Real evalBound(SCIP *scip, BOUND *bound)
    Definition: prop_obbt.c:1653
    #define DEFAULT_TIGHTINTBOUNDSPROBING
    Definition: prop_obbt.c:108
    static SCIP_Bool includeVarGenVBound(SCIP *scip, SCIP_VAR *var)
    Definition: prop_obbt.c:423
    #define DEFAULT_MINITLIMIT
    Definition: prop_obbt.c:103
    #define DEFAULT_ITLIMITFACTOR
    Definition: prop_obbt.c:101
    #define DEFAULT_PROPAGATEFREQ
    Definition: prop_obbt.c:123
    static int bilinboundGetLocksNeg(BILINBOUND *bilinbound)
    Definition: prop_obbt.c:867
    static SCIP_RETCODE filterBounds(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Longint itlimit)
    Definition: prop_obbt.c:1294
    static SCIP_Bool indicatorVarIsInteresting(SCIP *scip, SCIP_VAR *var, int nlcount, int nindcount, SCIP_Real threshold)
    Definition: prop_obbt.c:938
    #define DEFAULT_ORDERINGALGO
    Definition: prop_obbt.c:112
    #define DEFAULT_GENVBDSDURINGSEPA
    Definition: prop_obbt.c:122
    static SCIP_RETCODE addObjCutoff(SCIP *scip, SCIP_PROPDATA *propdata)
    Definition: prop_obbt.c:316
    #define DEFAULT_APPLY_TRIVIALFITLERING
    Definition: prop_obbt.c:93
    #define DEFAULT_SEPARATESOL
    Definition: prop_obbt.c:117
    #define OBBT_SCOREBASE
    Definition: prop_obbt.c:114
    #define PROP_DELAY
    Definition: prop_obbt.c:85
    static SCIP_RETCODE solveLP(SCIP *scip, int itlimit, SCIP_Bool *error, SCIP_Bool *optimal)
    Definition: prop_obbt.c:244
    static SCIP_DECL_PROPFREE(propFreeObbt)
    Definition: prop_obbt.c:3302
    #define DEFAULT_FILTERING_NORM
    Definition: prop_obbt.c:89
    static void getCorners(SCIP_VAR *x, SCIP_VAR *y, CORNER corner, SCIP_Real *xs, SCIP_Real *ys, SCIP_Real *xt, SCIP_Real *yt)
    Definition: prop_obbt.c:801
    static int getIterationsLeft(SCIP *scip, SCIP_Longint nolditerations, SCIP_Longint itlimit)
    Definition: prop_obbt.c:450
    static SCIP_RETCODE filterRound(SCIP *scip, SCIP_PROPDATA *propdata, int itlimit, int *nfiltered, SCIP_Real *objcoefs, int *objcoefsinds, int nobjcoefs)
    Definition: prop_obbt.c:1134
    static SCIP_RETCODE sortBounds(SCIP *scip, SCIP_PROPDATA *propdata)
    Definition: prop_obbt.c:1637
    #define DEFAULT_CREATE_BILININEQS
    Definition: prop_obbt.c:125
    #define DEFAULT_CREATE_LINCONS
    Definition: prop_obbt.c:126
    #define DEFAULT_TIGHTCONTBOUNDSPROBING
    Definition: prop_obbt.c:110
    #define PROP_TIMING
    Definition: prop_obbt.c:82
    static SCIP_VAR * bilinboundGetX(BILINBOUND *bilinbound)
    Definition: prop_obbt.c:843
    Corner
    Definition: prop_obbt.c:153
    @ LEFTTOP
    Definition: prop_obbt.c:157
    @ RIGHTBOTTOM
    Definition: prop_obbt.c:155
    @ FILTERED
    Definition: prop_obbt.c:158
    @ LEFTBOTTOM
    Definition: prop_obbt.c:154
    @ RIGHTTOP
    Definition: prop_obbt.c:156
    static SCIP_DECL_PROPCOPY(propCopyObbt)
    Definition: prop_obbt.c:3065
    #define DEFAULT_CREATE_GENVBOUNDS
    Definition: prop_obbt.c:88
    enum Corner CORNER
    Definition: prop_obbt.c:160
    static SCIP_RETCODE setObjProbing(SCIP *scip, SCIP_PROPDATA *propdata, BOUND *bound, SCIP_Real coef)
    Definition: prop_obbt.c:376
    static unsigned int getScore(SCIP *scip, BOUND *bound, int nlcount, int nindcount, int maxnlcount, SCIP_Real smallub)
    Definition: prop_obbt.c:2640
    #define DEFAULT_ITLIMITFAC_BILININEQS
    Definition: prop_obbt.c:127
    #define DEFAULT_ONLYNONCONVEXVARS
    Definition: prop_obbt.c:104
    #define DEFAULT_RANDSEED
    Definition: prop_obbt.c:129
    static SCIP_RETCODE findNewBounds(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Longint *nleftiterations, SCIP_Bool convexphase)
    Definition: prop_obbt.c:1804
    static SCIP_Bool varIsFixedLocal(SCIP *scip, SCIP_VAR *var)
    Definition: prop_obbt.c:366
    static SCIP_DECL_PROPINITSOL(propInitsolObbt)
    Definition: prop_obbt.c:3080
    static SCIP_RETCODE solveBilinearLP(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, SCIP_Real xs, SCIP_Real ys, SCIP_Real xt, SCIP_Real yt, SCIP_Real *xcoef, SCIP_Real *ycoef, SCIP_Real *constant, SCIP_Longint iterlim, int *nnonzduals)
    Definition: prop_obbt.c:2297
    static SCIP_RETCODE applyObbt(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Longint itlimit, SCIP_RESULT *result)
    Definition: prop_obbt.c:2043
    static SCIP_RETCODE applyObbtBilinear(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Longint itlimit, SCIP_RESULT *result)
    Definition: prop_obbt.c:2445
    static SCIP_DECL_PROPEXITSOL(propExitsolObbt)
    Definition: prop_obbt.c:3238
    #define DEFAULT_GENVBDSDURINGFILTER
    Definition: prop_obbt.c:94
    static SCIP_RETCODE getNVarsIndicators(SCIP *scip, int *nindcount)
    Definition: prop_obbt.c:2761
    static SCIP_RETCODE createGenVBound(SCIP *scip, SCIP_PROPDATA *propdata, BOUND *bound, SCIP_Bool *found)
    Definition: prop_obbt.c:554
    static SCIP_DECL_SORTPTRCOMP(compBoundsScore)
    Definition: prop_obbt.c:1592
    static SCIP_RETCODE applyBoundChgs(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_RESULT *result)
    Definition: prop_obbt.c:1456
    static void getCorner(SCIP_VAR *x, SCIP_VAR *y, CORNER corner, SCIP_Real *px, SCIP_Real *py)
    Definition: prop_obbt.c:763
    static int bilinboundGetLocksPos(BILINBOUND *bilinbound)
    Definition: prop_obbt.c:878
    static SCIP_RETCODE getNLPVarsNonConvexity(SCIP *scip, unsigned int *nccounts)
    Definition: prop_obbt.c:2703
    static SCIP_RETCODE applySeparation(SCIP *scip, SCIP_PROPDATA *propdata, BOUND *currbound, SCIP_Longint *nleftiterations, SCIP_Bool *success)
    Definition: prop_obbt.c:1722
    #define PROP_FREQ
    Definition: prop_obbt.c:84
    #define PROP_PRIORITY
    Definition: prop_obbt.c:83
    static SCIP_Bool varIsInteresting(SCIP *scip, SCIP_VAR *var, int nlcount, int nindcount)
    Definition: prop_obbt.c:2821
    static void exchangeBounds(SCIP_PROPDATA *propdata, int i)
    Definition: prop_obbt.c:740
    optimization-based bound tightening propagator
    public methods for managing constraints
    public methods for LP management
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPstatisticMessage
    Definition: pub_message.h:123
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    #define SCIPdebugMessage
    Definition: pub_message.h:96
    public data structures and miscellaneous methods
    methods for sorting joint arrays of various types
    public methods for NLP management
    public methods for propagators
    public methods for branch and bound tree
    public methods for problem variables
    public methods for constraint handler plugins and constraints
    public methods for problem copies
    public methods for cuts and aggregation rows
    general public methods
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for nonlinear relaxation
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for the probing mode
    public methods for propagator plugins
    public methods for random numbers
    public methods for querying solving statistics
    public methods for the branch-and-bound tree
    public methods for SCIP variables
    SCIP_Real score
    Definition: prop_obbt.c:168
    unsigned int done
    Definition: prop_obbt.c:167
    int filtered
    Definition: prop_obbt.c:166
    SCIP_EXPR * expr
    Definition: prop_obbt.c:165
    unsigned int score
    Definition: prop_obbt.c:141
    unsigned int done
    Definition: prop_obbt.c:144
    unsigned int filtered
    Definition: prop_obbt.c:142
    SCIP_BOUNDTYPE boundtype
    Definition: prop_obbt.c:140
    int index
    Definition: prop_obbt.c:147
    unsigned int found
    Definition: prop_obbt.c:143
    SCIP_Real newval
    Definition: prop_obbt.c:139
    SCIP_VAR * var
    Definition: prop_obbt.c:138
    unsigned int nonconvex
    Definition: prop_obbt.c:145
    unsigned int indicator
    Definition: prop_obbt.c:146
    enum SCIP_LPSolStat SCIP_LPSOLSTAT
    Definition: type_lp.h:52
    @ 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_LPSOLSTAT_ERROR
    Definition: type_lp.h:50
    @ SCIP_LPSOLSTAT_NOTSOLVED
    Definition: type_lp.h:43
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ SCIP_LPSOLSTAT_TIMELIMIT
    Definition: type_lp.h:49
    @ SCIP_LPSOLSTAT_UNBOUNDEDRAY
    Definition: type_lp.h:46
    @ SCIP_LPSOLSTAT_INFEASIBLE
    Definition: type_lp.h:45
    @ SCIP_LPSOLSTAT_OBJLIMIT
    Definition: type_lp.h:47
    @ SCIP_LPSOLSTAT_ITERLIMIT
    Definition: type_lp.h:48
    @ SCIP_BASESTAT_BASIC
    Definition: type_lpi.h:92
    enum SCIP_BaseStat SCIP_BASESTAT
    Definition: type_lpi.h:96
    struct SCIP_PropData SCIP_PROPDATA
    Definition: type_prop.h:52
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_REDUCEDDOM
    Definition: type_result.h:51
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STAGE_SOLVING
    Definition: type_set.h:53
    @ SCIP_VARTYPE_INTEGER
    Definition: type_var.h:65
    @ SCIP_VARTYPE_CONTINUOUS
    Definition: type_var.h:71
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64
    @ SCIP_VARSTATUS_COLUMN
    Definition: type_var.h:53