Scippy

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