SCIP

    Solving Constraint Integer Programs

    nlhdlr_perspective.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file nlhdlr_perspective.c
    26 * @ingroup DEFPLUGINS_NLHDLR
    27 * @brief perspective nonlinear handler
    28 * @author Ksenia Bestuzheva
    29 */
    30
    32#include "scip/cons_nonlinear.h"
    33#include "scip/scip_sol.h"
    35#include "scip/nlhdlr.h"
    36
    37/* fundamental nonlinear handler properties */
    38#define NLHDLR_NAME "perspective"
    39#define NLHDLR_DESC "perspective handler for expressions"
    40#define NLHDLR_DETECTPRIORITY -20 /**< detect last so that to make use of what other handlers detected */
    41#define NLHDLR_ENFOPRIORITY 125 /**< enforce first because perspective cuts are always stronger */
    42
    43#define DEFAULT_MAXPROPROUNDS 1 /**< maximal number of propagation rounds in probing */
    44#define DEFAULT_MINDOMREDUCTION 0.1 /**< minimal relative reduction in a variable's domain for applying probing */
    45#define DEFAULT_MINVIOLPROBING 1e-05 /**< minimal violation w.r.t. auxiliary variables for applying probing */
    46#define DEFAULT_PROBINGONLYINSEPA TRUE /**< whether to do probing only in separation loop */
    47#define DEFAULT_PROBINGFREQ 1 /**< probing frequency (-1 - no probing, 0 - root node only) */
    48#define DEFAULT_CONVEXONLY FALSE /**< whether perspective cuts are added only for convex expressions */
    49#define DEFAULT_TIGHTENBOUNDS TRUE /**< whether variable semicontinuity is used to tighten variable bounds */
    50#define DEFAULT_ADJREFPOINT TRUE /**< whether to adjust the reference point if indicator is not 1 */
    51
    52/*
    53 * Data structures
    54 */
    55
    56/** data structure to store information of a semicontinuous variable
    57 *
    58 * For a variable x (not stored in the struct), this stores the data of nbnds implications
    59 * bvars[i] = 0 -> x = vals[i]
    60 * bvars[i] = 1 -> lbs[i] <= x <= ubs[i]
    61 * where bvars[i] are binary variables.
    62 */
    63struct SCVarData
    64{
    65 SCIP_Real* vals0; /**< values of the variable when the corresponding bvars[i] = 0 */
    66 SCIP_Real* lbs1; /**< global lower bounds of the variable when the corresponding bvars[i] = 1 */
    67 SCIP_Real* ubs1; /**< global upper bounds of the variable when the corresponding bvars[i] = 1 */
    68 SCIP_VAR** bvars; /**< the binary variables on which the variable domain depends */
    69 int nbnds; /**< number of suitable on/off bounds the var has */
    70 int bndssize; /**< size of the arrays */
    71};
    72typedef struct SCVarData SCVARDATA;
    73
    74/** nonlinear handler expression data
    75 *
    76 * For an expression expr (not stored in the struct), this stores the data of nindicators implications
    77 * indicators[i] = 0 -> expr = exprvals[0]
    78 * where indicators[i] is an indicator (binary) variable, corresponding to some bvars entry in SCVarData.
    79 *
    80 * Also stores the variables the expression depends on.
    81 */
    82struct SCIP_NlhdlrExprData
    83{
    84 SCIP_Real* exprvals0; /**< 'off' values of the expression for each indicator variable */
    85 SCIP_VAR** vars; /**< expression variables (both original and auxiliary) */
    86 int nvars; /**< total number of variables in the expression */
    87 int varssize; /**< size of the vars array */
    88 SCIP_VAR** indicators; /**< all indicator variables for the expression */
    89 int nindicators; /**< number of indicator variables */
    90};
    91
    92/** nonlinear handler data */
    93struct SCIP_NlhdlrData
    94{
    95 SCIP_HASHMAP* scvars; /**< maps semicontinuous variables to their on/off bounds (SCVarData) */
    96
    97 /* parameters */
    98 int maxproprounds; /**< maximal number of propagation rounds in probing */
    99 SCIP_Real mindomreduction; /**< minimal relative reduction in a variable's domain for applying probing */
    100 SCIP_Real minviolprobing; /**< minimal violation w.r.t. auxiliary variables for applying probing */
    101 SCIP_Bool probingonlyinsepa; /**< whether to do probing only in separation loop */
    102 int probingfreq; /**< if and when to do probing */
    103 SCIP_Bool convexonly; /**< whether perspective cuts are added only for convex expressions */
    104 SCIP_Bool tightenbounds; /**< whether variable semicontinuity is used to tighten variable bounds */
    105 SCIP_Bool adjrefpoint; /**< whether to adjust the reference point if indicator is not 1 */
    106};
    107
    108/*
    109 * Local methods
    110 */
    111
    112/*
    113 * Helper methods for working with nlhdlrExprData
    114 */
    115
    116/** frees nlhdlrexprdata structure */
    117static
    119 SCIP* scip, /**< SCIP data structure */
    120 SCIP_NLHDLREXPRDATA* nlhdlrexprdata /**< nlhdlr expression data */
    121 )
    122{
    123 int v;
    124
    125 if( nlhdlrexprdata->nindicators != 0 )
    126 {
    127 assert(nlhdlrexprdata->indicators != NULL);
    128 for( v = nlhdlrexprdata->nindicators - 1; v >= 0; --v )
    129 {
    130 SCIP_CALL( SCIPreleaseVar(scip, &(nlhdlrexprdata->indicators[v])) );
    131 }
    132 SCIPfreeBlockMemoryArray(scip, &(nlhdlrexprdata->indicators), nlhdlrexprdata->nindicators);
    133 SCIPfreeBlockMemoryArrayNull(scip, &(nlhdlrexprdata->exprvals0), nlhdlrexprdata->nindicators);
    134 }
    135
    136 for( v = nlhdlrexprdata->nvars - 1; v >= 0; --v )
    137 {
    138 SCIP_CALL( SCIPreleaseVar(scip, &(nlhdlrexprdata->vars[v])) );
    139 }
    140 SCIPfreeBlockMemoryArrayNull(scip, &nlhdlrexprdata->vars, nlhdlrexprdata->varssize);
    141
    142 return SCIP_OKAY;
    143}
    144
    145/* remove an indicator from nlhdlr expression data */
    146static
    148 SCIP* scip, /**< SCIP data structure */
    149 SCIP_NLHDLREXPRDATA* nlexprdata, /**< nlhdlr expression data */
    150 int pos /**< position of the indicator */
    151 )
    152{
    153 int i;
    154
    155 assert(pos >= 0 && pos < nlexprdata->nindicators);
    156
    157 SCIP_CALL( SCIPreleaseVar(scip, &nlexprdata->indicators[pos]) );
    158 for( i = pos; i < nlexprdata->nindicators - 1; ++i )
    159 {
    160 nlexprdata->indicators[i] = nlexprdata->indicators[i+1];
    161 }
    162
    163 --nlexprdata->nindicators;
    164
    165 return SCIP_OKAY;
    166}
    167
    168/** adds an auxiliary variable to the vars array in nlhdlrexprdata */
    169static
    171 SCIP* scip, /**< SCIP data structure */
    172 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
    173 SCIP_HASHMAP* auxvarmap, /**< hashmap linking auxvars to positions in nlhdlrexprdata->vars */
    174 SCIP_VAR* auxvar /**< variable to be added */
    175 )
    176{
    177 int pos;
    178 int newsize;
    179
    180 assert(nlhdlrexprdata != NULL);
    181 assert(auxvar != NULL);
    182
    183 pos = SCIPhashmapGetImageInt(auxvarmap, (void*) auxvar);
    184
    185 if( pos != INT_MAX )
    186 return SCIP_OKAY;
    187
    188 /* ensure size */
    189 if( nlhdlrexprdata->nvars + 1 > nlhdlrexprdata->varssize )
    190 {
    191 newsize = SCIPcalcMemGrowSize(scip, nlhdlrexprdata->nvars + 1);
    192 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &nlhdlrexprdata->vars, nlhdlrexprdata->varssize, newsize) );
    193 nlhdlrexprdata->varssize = newsize;
    194 }
    195 assert(nlhdlrexprdata->nvars + 1 <= nlhdlrexprdata->varssize);
    196
    197 nlhdlrexprdata->vars[nlhdlrexprdata->nvars] = auxvar;
    198 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
    199 SCIP_CALL( SCIPhashmapSetImageInt(auxvarmap, (void*) auxvar, nlhdlrexprdata->nvars) );
    200 ++(nlhdlrexprdata->nvars);
    201
    202 return SCIP_OKAY;
    203}
    204
    205/*
    206 * Semicontinuous variable methods
    207 */
    208
    209/** adds an indicator to the data of a semicontinuous variable */
    210static
    212 SCIP* scip, /**< SCIP data structure */
    213 SCVARDATA* scvdata, /**< semicontinuous variable data */
    214 SCIP_VAR* indicator, /**< indicator to be added */
    215 SCIP_Real val0, /**< value of the variable when indicator == 0 */
    216 SCIP_Real lb1, /**< lower bound of the variable when indicator == 1 */
    217 SCIP_Real ub1 /**< upper bound of the variable when indicator == 1 */
    218 )
    219{
    220 int newsize;
    221 int i;
    222 SCIP_Bool found;
    223 int pos;
    224
    225 assert(scvdata != NULL);
    226 assert(indicator != NULL);
    227
    228 /* find the position where to insert */
    229 if( scvdata->bvars == NULL )
    230 {
    231 assert(scvdata->nbnds == 0 && scvdata->bndssize == 0);
    232 found = FALSE;
    233 pos = 0;
    234 }
    235 else
    236 {
    237 found = SCIPsortedvecFindPtr((void**)scvdata->bvars, SCIPvarComp, (void*)indicator, scvdata->nbnds, &pos);
    238 }
    239
    240 if( found )
    241 return SCIP_OKAY;
    242
    243 /* ensure sizes */
    244 if( scvdata->nbnds + 1 > scvdata->bndssize )
    245 {
    246 newsize = SCIPcalcMemGrowSize(scip, scvdata->nbnds + 1);
    247 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->bvars, scvdata->bndssize, newsize) );
    248 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->vals0, scvdata->bndssize, newsize) );
    249 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->lbs1, scvdata->bndssize, newsize) );
    250 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &scvdata->ubs1, scvdata->bndssize, newsize) );
    251 scvdata->bndssize = newsize;
    252 }
    253 assert(scvdata->nbnds + 1 <= scvdata->bndssize);
    254 assert(scvdata->bvars != NULL);
    255
    256 /* move entries if needed */
    257 for( i = scvdata->nbnds; i > pos; --i )
    258 {
    259 /* coverity[var_deref_op] */
    260 scvdata->bvars[i] = scvdata->bvars[i-1];
    261 scvdata->vals0[i] = scvdata->vals0[i-1];
    262 scvdata->lbs1[i] = scvdata->lbs1[i-1];
    263 scvdata->ubs1[i] = scvdata->ubs1[i-1];
    264 }
    265
    266 scvdata->bvars[pos] = indicator;
    267 scvdata->vals0[pos] = val0;
    268 scvdata->lbs1[pos] = lb1;
    269 scvdata->ubs1[pos] = ub1;
    270 ++scvdata->nbnds;
    271
    272 return SCIP_OKAY;
    273}
    274
    275/** find scvardata of var and position of indicator in it
    276 *
    277 * If indicator is not there, returns NULL.
    278 */
    279static
    281 SCIP_HASHMAP* scvars, /**< hashmap linking variables to scvardata */
    282 SCIP_VAR* var, /**< variable */
    283 SCIP_VAR* indicator, /**< indicator variable */
    284 int* pos /**< pointer to store the position of indicator */
    285 )
    286{
    287 SCIP_Bool exists;
    288 SCVARDATA* scvdata;
    289
    290 assert(var != NULL);
    291 assert(scvars != NULL);
    292 assert(indicator != NULL);
    293
    294 scvdata = (SCVARDATA*) SCIPhashmapGetImage(scvars, (void*)var);
    295 if( scvdata != NULL )
    296 {
    297 /* look for the indicator variable */
    298 exists = SCIPsortedvecFindPtr((void**)scvdata->bvars, SCIPvarComp, (void*)indicator, scvdata->nbnds, pos);
    299 if( !exists )
    300 return NULL;
    301
    302 return scvdata;
    303 }
    304
    305 return NULL;
    306}
    307
    308/** checks if a variable is semicontinuous and, if needed, updates the scvars hashmap
    309 *
    310 * A variable \f$x\f$ is semicontinuous if its bounds depend on at least one binary variable called the indicator,
    311 * and indicator = 0 &rArr; \f$x = x^0\f$ for some real constant \f$x^0\f$.
    312 */
    313static
    315 SCIP* scip, /**< SCIP data structure */
    316 SCIP_VAR* var, /**< the variable to check */
    317 SCIP_HASHMAP* scvars, /**< semicontinuous variable information */
    318 SCIP_Bool* result /**< buffer to store whether var is semicontinuous */
    319 )
    320{
    321 SCIP_Real lb0;
    322 SCIP_Real ub0;
    323 SCIP_Real lb1;
    324 SCIP_Real ub1;
    325 SCIP_Real glb;
    326 SCIP_Real gub;
    327 SCIP_Bool exists;
    328 int c;
    329 int pos;
    330 SCIP_VAR** vlbvars;
    331 SCIP_VAR** vubvars;
    332 SCIP_Real* vlbcoefs;
    333 SCIP_Real* vubcoefs;
    334 SCIP_Real* vlbconstants;
    335 SCIP_Real* vubconstants;
    336 int nvlbs;
    337 int nvubs;
    338 SCVARDATA* scvdata;
    339 SCIP_VAR* bvar;
    340
    341 assert(scip != NULL);
    342 assert(var != NULL);
    343 assert(scvars != NULL);
    344 assert(result != NULL);
    345
    346 scvdata = (SCVARDATA*) SCIPhashmapGetImage(scvars, (void*)var);
    347 if( scvdata != NULL )
    348 {
    349 *result = TRUE;
    350 return SCIP_OKAY;
    351 }
    352
    353 vlbvars = SCIPvarGetVlbVars(var);
    354 vubvars = SCIPvarGetVubVars(var);
    355 vlbcoefs = SCIPvarGetVlbCoefs(var);
    356 vubcoefs = SCIPvarGetVubCoefs(var);
    357 vlbconstants = SCIPvarGetVlbConstants(var);
    358 vubconstants = SCIPvarGetVubConstants(var);
    359 nvlbs = SCIPvarGetNVlbs(var);
    360 nvubs = SCIPvarGetNVubs(var);
    361 glb = SCIPvarGetLbGlobal(var);
    362 gub = SCIPvarGetUbGlobal(var);
    363
    364 *result = FALSE;
    365
    366 /* Scan through lower bounds; for each binary vlbvar save the corresponding lb0 and lb1.
    367 * Then check if there is an upper bound with this vlbvar and save ub0 and ub1.
    368 * If the found bounds imply that the var value is fixed to some val0 when vlbvar = 0,
    369 * save vlbvar and val0 to scvdata.
    370 */
    371 for( c = 0; c < nvlbs; ++c )
    372 {
    373 if( SCIPvarGetType(vlbvars[c]) != SCIP_VARTYPE_BINARY || SCIPvarIsImpliedIntegral(vlbvars[c]) )
    374 continue;
    375
    376 SCIPdebugMsg(scip, "var <%s>[%f, %f] lower bound: %f <%s> %+f", SCIPvarGetName(var), glb, gub, vlbcoefs[c], SCIPvarGetName(vlbvars[c]), vlbconstants[c]);
    377
    378 bvar = vlbvars[c];
    379
    380 lb0 = MAX(vlbconstants[c], glb);
    381 lb1 = MAX(vlbconstants[c] + vlbcoefs[c], glb);
    382
    383 /* look for bvar in vubvars */
    384 if( vubvars != NULL )
    385 exists = SCIPsortedvecFindPtr((void**)vubvars, SCIPvarComp, bvar, nvubs, &pos);
    386 else
    387 exists = FALSE;
    388 if( exists )
    389 { /*lint --e{644}*/
    390 SCIPdebugMsgPrint(scip, ", upper bound: %f <%s> %+f", vubcoefs[pos], SCIPvarGetName(vubvars[pos]), vubconstants[pos]); /*lint !e613*/
    391
    392 /* save the upper bounds */
    393 ub0 = MIN(vubconstants[pos], gub);
    394 ub1 = MIN(vubconstants[pos] + vubcoefs[pos], gub);
    395 }
    396 else
    397 {
    398 /* if there is no upper bound with vubvar = bvar, use global var bounds */
    399 ub0 = gub;
    400 ub1 = gub;
    401 }
    402
    403 /* the 'off' domain of a semicontinuous var should reduce to a single point and be different from the 'on' domain */
    404 SCIPdebugMsgPrint(scip, " -> <%s> in [%f, %f] (off), [%f, %f] (on)\n", SCIPvarGetName(var), lb0, ub0, lb1, ub1);
    405 if( SCIPisEQ(scip, lb0, ub0) && (!SCIPisEQ(scip, lb0, lb1) || !SCIPisEQ(scip, ub0, ub1)) )
    406 {
    407 if( scvdata == NULL )
    408 {
    410 }
    411
    412 SCIP_CALL( addSCVarIndicator(scip, scvdata, bvar, lb0, lb1, ub1) );
    413 }
    414 }
    415
    416 /* look for vubvars that have not been processed yet */
    417 assert(vubvars != NULL || nvubs == 0);
    418 for( c = 0; c < nvubs; ++c )
    419 {
    420 /* coverity[var_deref_op] */
    421 if( SCIPvarGetType(vubvars[c]) != SCIP_VARTYPE_BINARY || SCIPvarIsImpliedIntegral(vubvars[c]) ) /*lint !e613*/
    422 continue;
    423
    424 bvar = vubvars[c]; /*lint !e613*/
    425
    426 /* skip vars that are in vlbvars */
    427 if( vlbvars != NULL && SCIPsortedvecFindPtr((void**)vlbvars, SCIPvarComp, bvar, nvlbs, &pos) )
    428 continue;
    429
    430 SCIPdebugMsg(scip, "var <%s>[%f, %f] upper bound: %f <%s> %+f",
    431 SCIPvarGetName(var), glb, gub, vubcoefs[c], SCIPvarGetName(vubvars[c]), vubconstants[c]); /*lint !e613*/
    432
    433 lb0 = glb;
    434 lb1 = glb;
    435 ub0 = MIN(vubconstants[c], gub);
    436 ub1 = MIN(vubconstants[c] + vubcoefs[c], gub);
    437
    438 /* the 'off' domain of a semicontinuous var should reduce to a single point and be different from the 'on' domain */
    439 SCIPdebugMsgPrint(scip, " -> <%s> in [%f, %f] (off), [%f, %f] (on)\n", SCIPvarGetName(var), lb0, ub0, lb1, ub1);
    440 if( SCIPisEQ(scip, lb0, ub0) && (!SCIPisEQ(scip, lb0, lb1) || !SCIPisEQ(scip, ub0, ub1)) )
    441 {
    442 if( scvdata == NULL )
    443 {
    445 }
    446
    447 SCIP_CALL( addSCVarIndicator(scip, scvdata, bvar, lb0, lb1, ub1) );
    448 }
    449 }
    450
    451 if( scvdata != NULL )
    452 {
    453#ifdef SCIP_DEBUG
    454 SCIPdebugMsg(scip, "var <%s> has global bounds [%f, %f] and the following on/off bounds:\n", SCIPvarGetName(var), glb, gub);
    455 for( c = 0; c < scvdata->nbnds; ++c )
    456 {
    457 SCIPdebugMsg(scip, " c = %d, bvar <%s>: val0 = %f\n", c, SCIPvarGetName(scvdata->bvars[c]), scvdata->vals0[c]);
    458 }
    459#endif
    460 SCIP_CALL( SCIPhashmapInsert(scvars, var, scvdata) );
    461 *result = TRUE;
    462 }
    463
    464 return SCIP_OKAY;
    465}
    466
    467/*
    468 * Semicontinuous expression methods
    469 */
    470
    471/* checks if an expression is semicontinuous
    472 *
    473 * An expression is semicontinuous if all of its nonlinear variables are semicontinuous
    474 * and share at least one common indicator variable
    475 */
    476static
    478 SCIP* scip, /**< SCIP data structure */
    479 SCIP_NLHDLRDATA* nlhdlrdata, /**< nonlinear handler data */
    480 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
    481 SCIP_EXPR* expr, /**< expression */
    482 SCIP_Bool* res /**< buffer to store whether the expression is semicontinuous */
    483 )
    484{
    485 int v;
    486 SCIP_Bool var_is_sc;
    487 SCVARDATA* scvdata;
    488 SCIP_VAR* var;
    489 int nindicators;
    490 int nbnds0;
    491 int c;
    492 SCIP_VAR** indicators;
    493 SCIP_Bool* nonlinear;
    494
    495 *res = FALSE;
    496
    497 /* constant expression is not semicontinuous; variable expressions are of no interest here */
    498 if( nlhdlrexprdata->nvars == 0 )
    499 return SCIP_OKAY;
    500
    501 indicators = NULL;
    502 nindicators = 0;
    503 nbnds0 = 0;
    504
    505 if( SCIPisExprSum(scip, expr) )
    506 {
    507 SCIP_EXPRITER* it;
    508 SCIP_EXPR* child;
    509 SCIP_EXPR* curexpr;
    510 int pos;
    511 SCIP_Bool issc;
    512
    513 /* sums are treated separately because if there are variables that are non-semicontinuous but
    514 * appear only linearly, we still want to apply perspective to expr
    515 */
    516
    517 SCIP_CALL( SCIPallocClearBufferArray(scip, &nonlinear, nlhdlrexprdata->nvars) );
    519
    520 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
    521 {
    522 child = SCIPexprGetChildren(expr)[c];
    523
    524 if( SCIPisExprVar(scip, child) )
    525 {
    526 var = SCIPgetVarExprVar(child);
    527
    528 /* save information on semicontinuity of child */
    529 SCIP_CALL( varIsSemicontinuous(scip, var, nlhdlrdata->scvars, &var_is_sc) );
    530
    531 /* since child is a variable, go on regardless of the value of var_is_sc */
    532 continue;
    533 }
    534
    535 issc = TRUE;
    536
    538 curexpr = SCIPexpriterGetCurrent(it);
    539
    540 /* all nonlinear terms of a sum should be semicontinuous in original variables */
    541 while( !SCIPexpriterIsEnd(it) )
    542 {
    543 assert(curexpr != NULL);
    544
    545 if( SCIPisExprVar(scip, curexpr) )
    546 {
    547 var = SCIPgetVarExprVar(curexpr);
    548
    549 if( !SCIPvarIsRelaxationOnly(var) )
    550 {
    551 SCIP_CALL( varIsSemicontinuous(scip, var, nlhdlrdata->scvars, &var_is_sc) );
    552
    553 /* mark the variable as nonlinear */
    554 (void) SCIPsortedvecFindPtr((void**) nlhdlrexprdata->vars, SCIPvarComp, (void*) var, nlhdlrexprdata->nvars,
    555 &pos);
    556 assert(0 <= pos && pos < nlhdlrexprdata->nvars);
    557 nonlinear[pos] = TRUE;
    558
    559 if( !var_is_sc )
    560 {
    561 /* non-semicontinuous child which is (due to a previous check) not a var ->
    562 * expr is non-semicontinuous
    563 */
    564 issc = FALSE;
    565 break;
    566 }
    567 }
    568 }
    569 curexpr = SCIPexpriterGetNext(it);
    570 }
    571
    572 if( !issc )
    573 {
    574 SCIPfreeExpriter(&it);
    575 goto TERMINATE;
    576 }
    577 }
    578 SCIPfreeExpriter(&it);
    579 }
    580 else
    581 {
    582 /* non-sum expression */
    583 nonlinear = NULL;
    584
    585 /* all variables of a non-sum on/off expression should be semicontinuous */
    586 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
    587 {
    588 SCIP_CALL( varIsSemicontinuous(scip, nlhdlrexprdata->vars[v], nlhdlrdata->scvars, &var_is_sc) );
    589 if( !var_is_sc )
    590 return SCIP_OKAY;
    591 }
    592 }
    593
    594 /* look for common binary variables for all variables of the expression */
    595
    596 SCIPdebugMsg(scip, "Array intersection for var <%s>\n", SCIPvarGetName(nlhdlrexprdata->vars[0]));
    597 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
    598 {
    599 SCIPdebugMsg(scip, "%s; \n", SCIPvarGetName(nlhdlrexprdata->vars[v]));
    600
    601 if( nonlinear != NULL && !nonlinear[v] )
    602 continue;
    603
    604 scvdata = (SCVARDATA*)SCIPhashmapGetImage(nlhdlrdata->scvars, (void*) nlhdlrexprdata->vars[v]);
    605
    606 /* we should have exited earlier if there is a nonlinear non-semicontinuous variable */
    607 assert(scvdata != NULL);
    608
    609 if( indicators == NULL )
    610 {
    611 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &indicators, scvdata->bvars, scvdata->nbnds) );
    612 nbnds0 = scvdata->nbnds;
    613 nindicators = nbnds0;
    614 }
    615 else
    616 {
    617 SCIPcomputeArraysIntersectionPtr((void**)indicators, nindicators, (void**)scvdata->bvars, scvdata->nbnds,
    618 SCIPvarComp, (void**)indicators, &nindicators);
    619 }
    620
    621 /* if we have found out that the intersection is empty, expr is not semicontinuous */
    622 if( indicators != NULL && nindicators == 0 )
    623 {
    624 SCIPfreeBlockMemoryArray(scip, &indicators, nbnds0);
    625 goto TERMINATE;
    626 }
    627 }
    628
    629 /* this can happen if all children are linear vars and none are semicontinuous */
    630 if( indicators == NULL )
    631 {
    632 goto TERMINATE;
    633 }
    634 assert(nindicators > 0 && nindicators <= nbnds0);
    635
    636 if( nindicators < nbnds0 )
    637 {
    638 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &indicators, nbnds0, nindicators) );
    639 }
    640
    641 for( v = 0; v < nindicators; ++v )
    642 {
    643 SCIP_CALL( SCIPcaptureVar(scip, indicators[v]) );
    644 }
    645 nlhdlrexprdata->indicators = indicators;
    646 nlhdlrexprdata->nindicators = nindicators;
    647 *res = TRUE;
    648
    649 TERMINATE:
    650 SCIPfreeBufferArrayNull(scip, &nonlinear);
    651
    652 return SCIP_OKAY;
    653}
    654
    655/** computes the 'off' value of the expression and the 'off' values of
    656 * semicontinuous auxiliary variables for each indicator variable
    657 */
    658static
    660 SCIP* scip, /**< SCIP data structure */
    661 SCIP_NLHDLRDATA* nlhdlrdata, /**< nonlinear handler data */
    662 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
    663 SCIP_EXPR* expr /**< expression */
    664 )
    665{
    666 SCIP_EXPRITER* it;
    667 SCIP_SOL* sol;
    668 int i;
    669 int v;
    670 int norigvars;
    671 SCIP_Real* origvals0;
    672 SCIP_VAR** origvars;
    673 SCVARDATA* scvdata;
    674 SCIP_VAR* auxvar;
    675 SCIP_EXPR* curexpr;
    676 SCIP_HASHMAP* auxvarmap;
    677 SCIP_Bool hasnonsc;
    678 int pos;
    679
    680 assert(expr != NULL);
    681
    682 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(nlhdlrexprdata->exprvals0), nlhdlrexprdata->nindicators) );
    683 SCIP_CALL( SCIPcreateSol(scip, &sol, NULL) );
    684 SCIP_CALL( SCIPallocBufferArray(scip, &origvals0, nlhdlrexprdata->nvars) );
    685 SCIP_CALL( SCIPhashmapCreate(&auxvarmap, SCIPblkmem(scip), 10) );
    687 SCIP_CALL( SCIPduplicateBufferArray(scip, &origvars, nlhdlrexprdata->vars, nlhdlrexprdata->nvars) );
    688 norigvars = nlhdlrexprdata->nvars;
    689
    690 for( i = nlhdlrexprdata->nindicators - 1; i >= 0; --i )
    691 {
    692 hasnonsc = FALSE;
    693
    694 /* set sol to the off value of all expr vars for this indicator */
    695 for( v = 0; v < norigvars; ++v )
    696 {
    697 /* set vals0[v] = 0 if var is non-sc with respect to indicators[i] - then it will not
    698 * contribute to exprvals0[i] since any non-sc var must be linear
    699 */
    700 scvdata = getSCVarDataInd(nlhdlrdata->scvars, origvars[v], nlhdlrexprdata->indicators[i], &pos);
    701 if( scvdata == NULL )
    702 {
    703 origvals0[v] = 0.0;
    704 hasnonsc = TRUE;
    705 }
    706 else
    707 {
    708 origvals0[v] = scvdata->vals0[pos];
    709 }
    710 }
    711 SCIP_CALL( SCIPsetSolVals(scip, sol, norigvars, origvars, origvals0) );
    712 SCIP_CALL( SCIPevalExpr(scip, expr, sol, 0L) );
    713
    714 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID ) /*lint !e777*/
    715 {
    716 SCIPdebugMsg(scip, "expression evaluation failed for %p, removing indicator %s\n",
    717 (void*)expr, SCIPvarGetName(nlhdlrexprdata->indicators[i]));
    718 /* TODO should we fix the indicator variable to 1? */
    719 /* since the loop is backwards, this only modifies the already processed part of nlhdlrexprdata->indicators */
    720 SCIP_CALL( removeIndicator(scip, nlhdlrexprdata, i) );
    721 continue;
    722 }
    723
    724 nlhdlrexprdata->exprvals0[i] = SCIPexprGetEvalValue(expr);
    725
    726 /* iterate through the expression and create scvdata for aux vars */
    728 curexpr = SCIPexpriterGetCurrent(it);
    729
    730 while( !SCIPexpriterIsEnd(it) )
    731 {
    732 auxvar = SCIPgetExprAuxVarNonlinear(curexpr);
    733
    734 if( auxvar != NULL )
    735 {
    736 SCIP_Bool issc = TRUE;
    737#ifndef NDEBUG
    738 SCIP_EXPR** childvarexprs;
    739 int nchildvarexprs;
    740 SCIP_VAR* var;
    741#endif
    742
    743 if( hasnonsc )
    744 {
    745 /* expr is a sum with non-semicontinuous linear terms. Therefore, curexpr might be
    746 * non-semicontinuous. In that case the auxvar is also non-semicontinuous, so
    747 * we will skip on/off bounds computation.
    748 */
    749 if( SCIPisExprVar(scip, curexpr) )
    750 {
    751 /* easy case: curexpr is a variable, can check semicontinuity immediately */
    752 scvdata = getSCVarDataInd(nlhdlrdata->scvars, SCIPgetVarExprVar(curexpr),
    753 nlhdlrexprdata->indicators[i], &pos);
    754 issc = scvdata != NULL;
    755 }
    756 else if( SCIPisExprSum(scip, curexpr) && curexpr == expr )
    757 {
    758 /* if expr itself is a sum, this is an exception since a sum with nonlinear terms is
    759 * allowed to have both semicontinuous and non-semicontinuous variables; we skip it here
    760 * and then analyse it term by term
    761 */
    762 issc = FALSE;
    763 }
    764
    765#ifndef NDEBUG
    766 if( !SCIPisExprVar(scip, curexpr) && (!SCIPisExprSum(scip, curexpr) || curexpr != expr) )
    767 {
    768 /* curexpr is a non-variable expression and does not fit the sum special case,
    769 * so it belongs to the non-linear part of expr.
    770 * Since the non-linear part of expr must be semicontinuous with respect to
    771 * nlhdlrexprdata->indicators[i], curexpr must be semicontinuous
    772 */
    773
    774 SCIP_CALL( SCIPallocBufferArray(scip, &childvarexprs, norigvars) );
    775 SCIP_CALL( SCIPgetExprVarExprs(scip, curexpr, childvarexprs, &nchildvarexprs) );
    776
    777 /* all nonlinear variables of a sum on/off term should be semicontinuous */
    778 for( v = 0; v < nchildvarexprs; ++v )
    779 {
    780 var = SCIPgetVarExprVar(childvarexprs[v]);
    781 scvdata = getSCVarDataInd(nlhdlrdata->scvars, var, nlhdlrexprdata->indicators[i], &pos);
    782 assert(scvdata != NULL);
    783
    784 SCIP_CALL( SCIPreleaseExpr(scip, &childvarexprs[v]) );
    785 }
    786
    787 SCIPfreeBufferArray(scip, &childvarexprs);
    788 }
    789#endif
    790 }
    791
    792 if( issc )
    793 {
    794 /* we know that all vars are semicontinuous with respect to exprdata->indicators; it remains to:
    795 * - get or create the scvardata structure for auxvar
    796 * - if had to create scvardata, add it to scvars hashmap
    797 * - add the indicator and the off value (= curexpr's off value) to scvardata
    798 */
    799 scvdata = (SCVARDATA*) SCIPhashmapGetImage(nlhdlrdata->scvars, (void*)auxvar);
    800 if( scvdata == NULL )
    801 {
    803 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &scvdata->bvars, nlhdlrexprdata->nindicators) );
    804 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &scvdata->vals0, nlhdlrexprdata->nindicators) );
    805 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &scvdata->lbs1, nlhdlrexprdata->nindicators) );
    806 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &scvdata->ubs1, nlhdlrexprdata->nindicators) );
    807 scvdata->bndssize = nlhdlrexprdata->nindicators;
    808 SCIP_CALL( SCIPhashmapInsert(nlhdlrdata->scvars, auxvar, scvdata) );
    809 }
    810
    811 SCIP_CALL( addSCVarIndicator(scip, scvdata, nlhdlrexprdata->indicators[i],
    812 SCIPexprGetEvalValue(curexpr), SCIPvarGetLbGlobal(auxvar), SCIPvarGetUbGlobal(auxvar)) );
    813 }
    814
    815 SCIP_CALL( addAuxVar(scip, nlhdlrexprdata, auxvarmap, auxvar) );
    816 }
    817
    818 curexpr = SCIPexpriterGetNext(it);
    819 }
    820 }
    821
    822 SCIPfreeExpriter(&it);
    823 SCIPhashmapFree(&auxvarmap);
    824 SCIPfreeBufferArray(scip, &origvars);
    825 SCIPfreeBufferArray(scip, &origvals0);
    826 SCIP_CALL( SCIPfreeSol(scip, &sol) );
    827
    828 return SCIP_OKAY;
    829}
    830
    831/*
    832 * Probing and bound tightening methods
    833 */
    834
    835/** go into probing and set some variable bounds */
    836static
    838 SCIP* scip, /**< SCIP data structure */
    839 SCIP_NLHDLRDATA* nlhdlrdata, /**< nonlinear handler data */
    840 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
    841 SCIP_VAR* indicator, /**< indicator variable */
    842 SCIP_VAR** probingvars, /**< array of vars whose bounds we will change in probing */
    843 SCIP_INTERVAL* probingdoms, /**< array of intervals to which bounds of probingvars will be changed in probing */
    844 int nprobingvars, /**< number of probing vars */
    845 SCIP_SOL* sol, /**< solution to be separated */
    846 SCIP_SOL** solcopy, /**< buffer for a copy of sol before going into probing; if *solcopy == sol, then copy is created */
    847 SCIP_Bool* cutoff_probing /**< pointer to store whether indicator == 1 is infeasible */
    848 )
    849{
    850 int v;
    851 SCIP_Real newlb;
    852 SCIP_Real newub;
    853 SCIP_Bool propagate;
    854
    855 propagate = SCIPgetDepth(scip) == 0;
    856
    857 /* if a copy of sol has not been created yet, then create one now and copy the relevant var values from sol,
    858 * because sol can change after SCIPstartProbing, e.g., when linked to the LP solution
    859 */
    860 if( *solcopy == sol )
    861 {
    862 SCIP_CALL( SCIPcreateSol(scip, solcopy, NULL) );
    863 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
    864 {
    865 SCIP_CALL( SCIPsetSolVal(scip, *solcopy, nlhdlrexprdata->vars[v], SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[v])) );
    866 }
    867 for( v = 0; v < nlhdlrexprdata->nindicators; ++v )
    868 {
    869 SCIP_CALL( SCIPsetSolVal(scip, *solcopy, nlhdlrexprdata->indicators[v], SCIPgetSolVal(scip, sol, nlhdlrexprdata->indicators[v])) );
    870 }
    871 }
    872
    873 /* go into probing */
    875
    876 /* create a probing node */
    878
    879 /* set indicator to 1 */
    880 SCIP_CALL( SCIPchgVarLbProbing(scip, indicator, 1.0) );
    881
    882 /* apply stored bounds */
    883 for( v = 0; v < nprobingvars; ++v )
    884 {
    885 newlb = SCIPintervalGetInf(probingdoms[v]);
    886 newub = SCIPintervalGetSup(probingdoms[v]);
    887
    888 if( SCIPisGT(scip, newlb, SCIPvarGetLbLocal(probingvars[v])) || (newlb >= 0.0 && SCIPvarGetLbLocal(probingvars[v]) < 0.0) )
    889 {
    890 SCIP_CALL( SCIPchgVarLbProbing(scip, probingvars[v], newlb) );
    891 }
    892 if( SCIPisLT(scip, newub, SCIPvarGetUbLocal(probingvars[v])) || (newub <= 0.0 && SCIPvarGetUbLocal(probingvars[v]) > 0.0) )
    893 {
    894 SCIP_CALL( SCIPchgVarUbProbing(scip, probingvars[v], newub) );
    895 }
    896 }
    897
    898 if( propagate )
    899 {
    900 SCIP_Longint ndomreds;
    901
    902 SCIP_CALL( SCIPpropagateProbing(scip, nlhdlrdata->maxproprounds, cutoff_probing, &ndomreds) );
    903 }
    904
    905 return SCIP_OKAY;
    906}
    907
    908/** analyse on/off bounds on a variable
    909 *
    910 * analyses for
    911 * 1. tightening bounds in probing for indicator = 1,
    912 * 2. fixing indicator / detecting cutoff if one or both states are infeasible,
    913 * 3. tightening local bounds if indicator is fixed.
    914 *
    915 * `probinglb` and `probingub` are only set if `doprobing` is TRUE.
    916 * They are either set to bounds that should be used in probing or to `SCIP_INVALID` if bounds on
    917 * `var` shouldn't be changed in probing.
    918 */
    919static
    921 SCIP* scip, /**< SCIP data structure */
    922 SCIP_NLHDLRDATA* nlhdlrdata, /**< nonlinear handler data */
    923 SCIP_VAR* var, /**< variable */
    924 SCIP_VAR* indicator, /**< indicator variable */
    925 SCIP_Bool indvalue, /**< indicator value for which the bounds are applied */
    926 SCIP_Bool* infeas, /**< pointer to store whether infeasibility has been detected */
    927 SCIP_Real* probinglb, /**< pointer to store the lower bound to be applied in probing */
    928 SCIP_Real* probingub, /**< pointer to store the upper bound to be applied in probing */
    929 SCIP_Bool doprobing, /**< whether we currently consider to go into probing */
    930 SCIP_Bool* reduceddom /**< pointer to store whether any variables were fixed */
    931 )
    932{
    933 SCVARDATA* scvdata;
    934 int pos;
    935 SCIP_Real sclb;
    936 SCIP_Real scub;
    937 SCIP_Real loclb;
    938 SCIP_Real locub;
    939 SCIP_Bool bndchgsuccess;
    940
    941 assert(var != NULL);
    942 assert(indicator != NULL);
    943 assert(infeas != NULL);
    944 assert(reduceddom != NULL);
    945
    946 /* shouldn't be called if indicator is fixed to !indvalue */
    947 assert((indvalue && SCIPvarGetUbLocal(indicator) > 0.5) || (!indvalue && SCIPvarGetLbLocal(indicator) < 0.5));
    948
    949 *infeas = FALSE;
    950 *reduceddom = FALSE;
    951 scvdata = getSCVarDataInd(nlhdlrdata->scvars, var, indicator, &pos);
    952 if( doprobing )
    953 {
    954 assert(probinglb != NULL);
    955 assert(probingub != NULL);
    956
    957 *probinglb = SCIP_INVALID;
    958 *probingub = SCIP_INVALID;
    959 }
    960
    961 /* nothing to do for non-semicontinuous variables */
    962 if( scvdata == NULL )
    963 {
    964 return SCIP_OKAY;
    965 }
    966
    967 sclb = indvalue ? scvdata->lbs1[pos] : scvdata->vals0[pos];
    968 scub = indvalue ? scvdata->ubs1[pos] : scvdata->vals0[pos];
    969 loclb = SCIPvarGetLbLocal(var);
    970 locub = SCIPvarGetUbLocal(var);
    971
    972 /* nothing to do for fixed variables */
    973 if( SCIPisEQ(scip, loclb, locub) )
    974 return SCIP_OKAY;
    975
    976 /* use a non-redundant lower bound */
    977 if( SCIPisGT(scip, sclb, SCIPvarGetLbLocal(var)) || (sclb >= 0.0 && loclb < 0.0) )
    978 {
    979 /* first check for infeasibility */
    980 if( SCIPisFeasGT(scip, sclb, SCIPvarGetUbLocal(var)) )
    981 {
    982 SCIP_CALL( SCIPfixVar(scip, indicator, indvalue ? 0.0 : 1.0, infeas, &bndchgsuccess) );
    983 *reduceddom += bndchgsuccess;
    984 if( *infeas )
    985 {
    986 return SCIP_OKAY;
    987 }
    988 }
    989 else if( nlhdlrdata->tightenbounds &&
    990 (SCIPvarGetUbLocal(indicator) <= 0.5 || SCIPvarGetLbLocal(indicator) >= 0.5) )
    991 {
    992 /* indicator is fixed; due to a previous check, here it can only be fixed to indvalue;
    993 * therefore, sclb is valid for the current node
    994 */
    995
    996 if( indvalue == 0 )
    997 {
    998 assert(sclb == scub); /*lint !e777*/
    999 SCIP_CALL( SCIPfixVar(scip, var, sclb, infeas, &bndchgsuccess) );
    1000 }
    1001 else
    1002 {
    1003 SCIP_CALL( SCIPtightenVarLb(scip, var, sclb, FALSE, infeas, &bndchgsuccess) );
    1004 }
    1005 *reduceddom += bndchgsuccess;
    1006 if( *infeas )
    1007 {
    1008 return SCIP_OKAY;
    1009 }
    1010 }
    1011 }
    1012
    1013 /* use a non-redundant upper bound */
    1014 if( SCIPisLT(scip, scub, SCIPvarGetUbLocal(var)) || (scub <= 0.0 && locub > 0.0) )
    1015 {
    1016 /* first check for infeasibility */
    1017 if( SCIPisFeasLT(scip, scub, SCIPvarGetLbLocal(var)) )
    1018 {
    1019 SCIP_CALL( SCIPfixVar(scip, indicator, indvalue ? 0.0 : 1.0, infeas, &bndchgsuccess) );
    1020 *reduceddom += bndchgsuccess;
    1021 if( *infeas )
    1022 {
    1023 return SCIP_OKAY;
    1024 }
    1025 }
    1026 else if( nlhdlrdata->tightenbounds &&
    1027 (SCIPvarGetUbLocal(indicator) <= 0.5 || SCIPvarGetLbLocal(indicator) >= 0.5) )
    1028 {
    1029 /* indicator is fixed; due to a previous check, here it can only be fixed to indvalue;
    1030 * therefore, scub is valid for the current node
    1031 */
    1032
    1033 if( indvalue == 0 )
    1034 {
    1035 assert(sclb == scub); /*lint !e777*/
    1036 SCIP_CALL( SCIPfixVar(scip, var, scub, infeas, &bndchgsuccess) );
    1037 }
    1038 else
    1039 {
    1040 SCIP_CALL( SCIPtightenVarUb(scip, var, scub, FALSE, infeas, &bndchgsuccess) );
    1041 }
    1042 *reduceddom += bndchgsuccess;
    1043 if( *infeas )
    1044 {
    1045 return SCIP_OKAY;
    1046 }
    1047 }
    1048 }
    1049
    1050 /* If a bound change has been found and indvalue == TRUE, try to use the new bounds.
    1051 * This is only done for indvalue == TRUE since this is where enfo asks other nlhdlrs to estimate,
    1052 * and at indicator == FALSE we already only have a single point
    1053 */
    1054 if( doprobing && indvalue && (((scub - sclb) / (locub - loclb)) <= 1.0 - nlhdlrdata->mindomreduction ||
    1055 (sclb >= 0.0 && loclb < 0.0) || (scub <= 0.0 && locub > 0.0)) )
    1056 {
    1057 *probinglb = sclb;
    1058 *probingub = scub;
    1059 }
    1060
    1061 SCIPdebugMsg(scip, "%s in [%g, %g] instead of [%g, %g] (vals0 = %g)\n", SCIPvarGetName(var), sclb, scub,
    1062 SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), scvdata->vals0[pos]);
    1063
    1064 return SCIP_OKAY;
    1065}
    1066
    1067/** looks for bound tightenings to be applied either in the current node or in probing
    1068 *
    1069 * Loops through both possible values of indicator and calls analyseVarOnoffBounds().
    1070 * Might update the `*doprobing` flag by setting it to `FALSE` if:
    1071 * - indicator is fixed or
    1072 * - analyseVarOnoffBounds() hasn't found a sufficient improvement at indicator==1.
    1073 *
    1074 * If `*doprobing==TRUE`, stores bounds suggested by analyseVarOnoffBounds() in order to apply them in probing together
    1075 * with the fixing `indicator=1`.
    1076 */
    1077static
    1079 SCIP* scip, /**< SCIP data structure */
    1080 SCIP_NLHDLRDATA* nlhdlrdata, /**< nonlinear handler data */
    1081 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
    1082 SCIP_VAR* indicator, /**< indicator variable */
    1083 SCIP_VAR*** probingvars, /**< array to store variables whose bounds will be changed in probing */
    1084 SCIP_INTERVAL** probingdoms, /**< array to store bounds to be applied in probing */
    1085 int* nprobingvars, /**< pointer to store number of vars whose bounds will be changed in probing */
    1086 SCIP_Bool* doprobing, /**< pointer to the flag telling whether we want to do probing */
    1087 SCIP_RESULT* result /**< pointer to store the result */
    1088 )
    1089{
    1090 int v;
    1091 SCIP_VAR* var;
    1092 SCIP_Bool infeas;
    1093 int b;
    1094 SCIP_Real probinglb = SCIP_INVALID;
    1095 SCIP_Real probingub = SCIP_INVALID;
    1096 SCIP_Bool changed;
    1097 SCIP_Bool reduceddom;
    1098
    1099 assert(indicator != NULL);
    1100 assert(nprobingvars != NULL);
    1101 assert(doprobing != NULL);
    1102 assert(result != NULL);
    1103
    1104 changed = FALSE;
    1105
    1106 /* no probing if indicator already fixed */
    1107 if( SCIPvarGetUbLocal(indicator) <= 0.5 || SCIPvarGetLbLocal(indicator) >= 0.5 )
    1108 {
    1109 *doprobing = FALSE;
    1110 }
    1111
    1112 /* consider each possible value of indicator */
    1113 for( b = 0; b < 2; ++b )
    1114 {
    1115 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
    1116 {
    1117 /* nothing left to do if indicator is already fixed to !indvalue
    1118 * (checked in the inner loop since analyseVarOnoff bounds might fix the indicator)
    1119 */
    1120 if( (b == 1 && SCIPvarGetUbLocal(indicator) <= 0.5) || (b == 0 && SCIPvarGetLbLocal(indicator) >= 0.5) )
    1121 {
    1122 *doprobing = FALSE;
    1123 break;
    1124 }
    1125
    1126 var = nlhdlrexprdata->vars[v];
    1127
    1128 SCIP_CALL( analyseVarOnoffBounds(scip, nlhdlrdata, var, indicator, b == 1, &infeas, &probinglb,
    1129 &probingub, *doprobing, &reduceddom) );
    1130
    1131 if( infeas )
    1132 {
    1133 *result = SCIP_CUTOFF;
    1134 *doprobing = FALSE;
    1135 return SCIP_OKAY;
    1136 }
    1137 else if( reduceddom )
    1138 {
    1139 *result = SCIP_REDUCEDDOM;
    1140 }
    1141
    1142 if( !(*doprobing) )
    1143 continue;
    1144
    1145 /* if bounds to be applied in probing have been found, store them */
    1146 if( probinglb != SCIP_INVALID ) /*lint !e777*/
    1147 {
    1148 assert(probingub != SCIP_INVALID); /*lint !e777*/
    1149
    1150 SCIP_CALL( SCIPreallocBufferArray(scip, probingvars, *nprobingvars + 1) );
    1151 SCIP_CALL( SCIPreallocBufferArray(scip, probingdoms, *nprobingvars + 1) );
    1152 (*probingvars)[*nprobingvars] = var;
    1153 (*probingdoms)[*nprobingvars].inf = probinglb;
    1154 (*probingdoms)[*nprobingvars].sup = probingub;
    1155 ++*nprobingvars;
    1156
    1157 changed = TRUE;
    1158 }
    1159 }
    1160 }
    1161
    1162 if( !changed )
    1163 {
    1164 *doprobing = FALSE;
    1165 }
    1166
    1167 return SCIP_OKAY;
    1168}
    1169
    1170/** saves local bounds on all expression variables, including auxiliary variables, obtained from propagating
    1171 * indicator == 1 to the corresponding SCVARDATA (should only be used in the root node)
    1172 */
    1173static
    1175 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
    1176 SCIP_HASHMAP* scvars, /**< hashmap with semicontinuous variables */
    1177 SCIP_VAR* indicator /**< indicator variable */
    1178 )
    1179{
    1180 int v;
    1181 SCIP_VAR* var;
    1182 SCVARDATA* scvdata;
    1183 int pos;
    1184 SCIP_Real lb;
    1185 SCIP_Real ub;
    1186
    1187 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
    1188 {
    1189 var = nlhdlrexprdata->vars[v];
    1190 lb = SCIPvarGetLbLocal(var);
    1191 ub = SCIPvarGetUbLocal(var);
    1192 scvdata = getSCVarDataInd(scvars, var, indicator, &pos);
    1193
    1194 if( scvdata != NULL )
    1195 {
    1196 scvdata->lbs1[pos] = MAX(scvdata->lbs1[pos], lb);
    1197 scvdata->ubs1[pos] = MIN(scvdata->ubs1[pos], ub);
    1198 }
    1199 }
    1200
    1201 return SCIP_OKAY;
    1202}
    1203
    1204/*
    1205 * Callback methods of nonlinear handler
    1206 */
    1207
    1208/** nonlinear handler copy callback */
    1209static
    1210SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrPerspective)
    1211{ /*lint --e{715}*/
    1212 assert(targetscip != NULL);
    1213 assert(sourcenlhdlr != NULL);
    1214
    1216
    1218
    1219 return SCIP_OKAY;
    1220}
    1221
    1222
    1223/** callback to free data of handler */
    1224static
    1225SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrdataPerspective)
    1226{ /*lint --e{715}*/
    1227 SCIPfreeBlockMemory(scip, nlhdlrdata);
    1228
    1229 return SCIP_OKAY;
    1230}
    1231
    1232
    1233/** callback to free expression specific data */
    1234static
    1235SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataPerspective)
    1236{ /*lint --e{715}*/
    1237 SCIP_CALL( freeNlhdlrExprData(scip, *nlhdlrexprdata) );
    1238 SCIPfreeBlockMemory(scip, nlhdlrexprdata);
    1239
    1240 return SCIP_OKAY;
    1241}
    1242
    1243/** callback to be called in deinitialization */
    1244static
    1245SCIP_DECL_NLHDLREXIT(nlhdlrExitPerspective)
    1246{ /*lint --e{715}*/
    1247 SCIP_HASHMAPENTRY* entry;
    1248 SCVARDATA* data;
    1249 int c;
    1250 SCIP_NLHDLRDATA* nlhdlrdata;
    1251
    1252 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    1253 assert(nlhdlrdata != NULL);
    1254
    1255 if( nlhdlrdata->scvars != NULL )
    1256 {
    1257 for( c = 0; c < SCIPhashmapGetNEntries(nlhdlrdata->scvars); ++c )
    1258 {
    1259 entry = SCIPhashmapGetEntry(nlhdlrdata->scvars, c);
    1260 if( entry != NULL )
    1261 {
    1262 data = (SCVARDATA*) SCIPhashmapEntryGetImage(entry);
    1267 SCIPfreeBlockMemory(scip, &data);
    1268 }
    1269 }
    1270 SCIPhashmapFree(&nlhdlrdata->scvars);
    1271 assert(nlhdlrdata->scvars == NULL);
    1272 }
    1273
    1274 return SCIP_OKAY;
    1275}
    1276
    1277/** callback to detect structure in expression tree
    1278 *
    1279 * We are looking for expressions g(x), where x is a vector of semicontinuous variables that all share at least one
    1280 * indicator variable.
    1281 */
    1282static
    1283SCIP_DECL_NLHDLRDETECT(nlhdlrDetectPerspective)
    1284{ /*lint --e{715}*/
    1285 SCIP_NLHDLRDATA* nlhdlrdata;
    1286 SCIP_EXPR** varexprs;
    1287 SCIP_Bool success = FALSE;
    1288 int i;
    1289 SCIP_Bool hassepabelow = FALSE;
    1290 SCIP_Bool hassepaabove = FALSE;
    1291 SCIP_Bool hasnondefault = FALSE;
    1292
    1293 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    1294
    1295 assert(scip != NULL);
    1296 assert(nlhdlr != NULL);
    1297 assert(expr != NULL);
    1298 assert(participating != NULL);
    1299 assert(enforcing != NULL);
    1300 assert(nlhdlrexprdata != NULL);
    1301 assert(nlhdlrdata != NULL);
    1302
    1303 /* do not run if we will have no auxvar to add a cut for */
    1304 if( SCIPgetExprNAuxvarUsesNonlinear(expr) == 0 )
    1305 return SCIP_OKAY;
    1306
    1307 if( SCIPgetNBinVars(scip) == 0 )
    1308 {
    1309 SCIPdebugMsg(scip, "problem has no binary variables, not running perspective detection\n");
    1310 return SCIP_OKAY;
    1311 }
    1312
    1313 for( i = 0; i < SCIPgetExprNEnfosNonlinear(expr); ++i )
    1314 {
    1315 SCIP_NLHDLR* nlhdlr2;
    1316 SCIP_NLHDLR_METHOD nlhdlr2participates;
    1317 SCIP_Bool sepabelowusesactivity;
    1318 SCIP_Bool sepaaboveusesactivity;
    1319 SCIPgetExprEnfoDataNonlinear(expr, i, &nlhdlr2, NULL, &nlhdlr2participates, &sepabelowusesactivity, &sepaaboveusesactivity, NULL);
    1320
    1321 if( (nlhdlr2participates & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
    1322 continue;
    1323
    1324 if( !SCIPnlhdlrHasEstimate(nlhdlr2) )
    1325 continue;
    1326
    1327 if( strcmp(SCIPnlhdlrGetName(nlhdlr2), "default") != 0 )
    1328 hasnondefault = TRUE;
    1329
    1330 /* If we are supposed to run only on convex expressions, than check whether there is a nlhdlr
    1331 * that participates in separation without using activity for it. Otherwise, check for
    1332 * participation regardless of activity usage.
    1333 */
    1334 if( (nlhdlr2participates & SCIP_NLHDLR_METHOD_SEPABELOW) && (!nlhdlrdata->convexonly || !sepabelowusesactivity) )
    1335 hassepabelow = TRUE;
    1336
    1337 if( (nlhdlr2participates & SCIP_NLHDLR_METHOD_SEPAABOVE) && (!nlhdlrdata->convexonly || !sepaaboveusesactivity) )
    1338 hassepaabove = TRUE;
    1339 }
    1340
    1341 /* If a sum expression is handled only by default nlhdlr, then all the children will have auxiliary vars.
    1342 * Since the sum will then be linear in auxiliary variables, perspective can't improve anything for it
    1343 */
    1344 if( SCIPisExprSum(scip, expr) && !hasnondefault )
    1345 {
    1346 SCIPdebugMsg(scip, "sum expr only has default exprhdlr, not running perspective detection\n");
    1347 return SCIP_OKAY;
    1348 }
    1349
    1350 /* If no other nlhdlr separates, neither does perspective (if convexonly, only separation
    1351 * without using activity counts)
    1352 */
    1353 if( !hassepabelow && !hassepaabove )
    1354 {
    1355 SCIPdebugMsg(scip, "no nlhdlr separates without using activity, not running perspective detection\n");
    1356 return SCIP_OKAY;
    1357 }
    1358
    1359#ifdef SCIP_DEBUG
    1360 SCIPdebugMsg(scip, "Called perspective detect, expr = %p: ", (void*)expr);
    1361 SCIPprintExpr(scip, expr, NULL);
    1362 SCIPdebugMsgPrint(scip, "\n");
    1363#endif
    1364
    1365 /* allocate memory */
    1366 SCIP_CALL( SCIPallocClearBlockMemory(scip, nlhdlrexprdata) );
    1367 if( nlhdlrdata->scvars == NULL )
    1368 {
    1369 SCIP_CALL( SCIPhashmapCreate(&(nlhdlrdata->scvars), SCIPblkmem(scip), SCIPgetNVars(scip)) );
    1370 }
    1371
    1372 /* save varexprs to nlhdlrexprdata */
    1373 SCIP_CALL( SCIPgetExprNVars(scip, expr, &(*nlhdlrexprdata)->nvars) );
    1374 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlhdlrexprdata)->vars, (*nlhdlrexprdata)->nvars) );
    1375 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, (*nlhdlrexprdata)->nvars) );
    1376 (*nlhdlrexprdata)->varssize = (*nlhdlrexprdata)->nvars;
    1377 SCIP_CALL( SCIPgetExprVarExprs(scip, expr, varexprs, &(*nlhdlrexprdata)->nvars) );
    1378 for( i = 0; i < (*nlhdlrexprdata)->nvars; ++i )
    1379 {
    1380 (*nlhdlrexprdata)->vars[i] = SCIPgetVarExprVar(varexprs[i]);
    1381 SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[i]) );
    1382 SCIP_CALL( SCIPcaptureVar(scip, (*nlhdlrexprdata)->vars[i]) );
    1383 }
    1384 SCIPsortPtr((void**) (*nlhdlrexprdata)->vars, SCIPvarComp, (*nlhdlrexprdata)->nvars);
    1385 SCIPfreeBufferArray(scip, &varexprs);
    1386
    1387 /* check if expr is semicontinuous and save indicator variables */
    1388 SCIP_CALL( exprIsSemicontinuous(scip, nlhdlrdata, *nlhdlrexprdata, expr, &success) );
    1389
    1390 if( success )
    1391 {
    1392 assert(*nlhdlrexprdata != NULL);
    1393 assert((*nlhdlrexprdata)->nindicators > 0);
    1394
    1395 if( hassepaabove )
    1396 *participating |= SCIP_NLHDLR_METHOD_SEPAABOVE;
    1397 if( hassepabelow )
    1398 *participating |= SCIP_NLHDLR_METHOD_SEPABELOW;
    1399
    1400#ifdef SCIP_DEBUG
    1401 SCIPinfoMessage(scip, NULL, "detected an on/off expr: ");
    1402 SCIPprintExpr(scip, expr, NULL);
    1403 SCIPinfoMessage(scip, NULL, "\n");
    1404#endif
    1405 }
    1406 else
    1407 {
    1408 assert(*nlhdlrexprdata != NULL);
    1409 SCIP_CALL( nlhdlrFreeExprDataPerspective(scip, nlhdlr, expr, nlhdlrexprdata) );
    1410 }
    1411
    1412 return SCIP_OKAY;
    1413}
    1414
    1415
    1416/** auxiliary evaluation callback of nonlinear handler */
    1417static
    1418SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxPerspective)
    1419{ /*lint --e{715}*/
    1420 int e;
    1421 SCIP_Real maxdiff;
    1422 SCIP_Real auxvarvalue;
    1423 SCIP_Real enfoauxval;
    1424
    1425 assert(scip != NULL);
    1426 assert(expr != NULL);
    1427 assert(auxvalue != NULL);
    1428
    1429 auxvarvalue = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr));
    1430 maxdiff = 0.0;
    1431 *auxvalue = auxvarvalue;
    1432
    1433 /* use the auxvalue from one of the other nlhdlrs that estimates for this expr: take the one that is farthest
    1434 * from the current value of auxvar
    1435 */
    1436 for( e = 0; e < SCIPgetExprNEnfosNonlinear(expr); ++e )
    1437 {
    1438 SCIP_NLHDLR* nlhdlr2;
    1439 SCIP_NLHDLREXPRDATA* nlhdlr2exprdata;
    1440 SCIP_NLHDLR_METHOD nlhdlr2participation;
    1441
    1442 SCIPgetExprEnfoDataNonlinear(expr, e, &nlhdlr2, &nlhdlr2exprdata, &nlhdlr2participation, NULL, NULL, NULL);
    1443
    1444 /* skip nlhdlr that do not participate or do not provide estimate */
    1445 if( (nlhdlr2participation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 || !SCIPnlhdlrHasEstimate(nlhdlr2) )
    1446 continue;
    1447
    1448 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr2, expr, nlhdlr2exprdata, &enfoauxval, sol) );
    1449
    1450 SCIPsetExprEnfoAuxValueNonlinear(expr, e, enfoauxval);
    1451
    1452 if( REALABS(enfoauxval - auxvarvalue) > maxdiff && enfoauxval != SCIP_INVALID ) /*lint !e777*/
    1453 {
    1454 maxdiff = REALABS(enfoauxval - auxvarvalue);
    1455 *auxvalue = enfoauxval;
    1456 }
    1457 }
    1458
    1459 return SCIP_OKAY;
    1460}
    1461
    1462/** separation initialization method of a nonlinear handler */
    1463static
    1464SCIP_DECL_NLHDLRINITSEPA(nlhdlrInitSepaPerspective)
    1465{ /*lint --e{715}*/
    1466 int sindicators;
    1467
    1468 sindicators = nlhdlrexprdata->nindicators;
    1469
    1470 /* compute 'off' values of expr and subexprs (and thus auxvars too) */
    1471 SCIP_CALL( computeOffValues(scip, SCIPnlhdlrGetData(nlhdlr), nlhdlrexprdata, expr) );
    1472
    1473 /* some indicator variables might have been removed if evaluation failed, check how many remain */
    1474 if( nlhdlrexprdata->nindicators == 0 )
    1475 {
    1476 SCIPfreeBlockMemoryArray(scip, &nlhdlrexprdata->indicators, sindicators);
    1477 SCIPfreeBlockMemoryArray(scip, &nlhdlrexprdata->exprvals0, sindicators);
    1478 }
    1479 else if( nlhdlrexprdata->nindicators < sindicators )
    1480 {
    1481 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &nlhdlrexprdata->indicators, sindicators, nlhdlrexprdata->nindicators) );
    1482 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &nlhdlrexprdata->exprvals0, sindicators, nlhdlrexprdata->nindicators) );
    1483 }
    1484
    1485 return SCIP_OKAY;
    1486}
    1487
    1488/** nonlinear handler enforcement callback
    1489 *
    1490 * "Perspectivies" cuts produced by other nonlinear handlers.
    1491 *
    1492 * Suppose that we want to separate \f$x\f$ from the set \f$\{ x : g(x) \leq 0\}\f$.
    1493 * If \f$g(x) = g^0\f$ if indicator \f$z = 0\f$, and a cut is given by \f$\sum_i a_ix_i + c \leq \text{aux}\f$, where \f$x_i = x_i^0\f$ if \f$z = 0\f$ for all \f$i\f$,
    1494 * then the "perspectivied" cut is \f[\sum_i a_ix_i + c + (1 - z)\,(g^0 - c - \sum_i a_ix_i^0) \leq \text{aux}.\f]
    1495 * This ensures that at \f$z = 1\f$, the new cut is equivalent to the given cut, and at \f$z = 0\f$ it reduces to \f$g^0 \leq \text{aux}\f$.
    1496 */
    1497static
    1498SCIP_DECL_NLHDLRENFO(nlhdlrEnfoPerspective)
    1499{ /*lint --e{715}*/
    1500 SCIP_ROWPREP* rowprep;
    1501 SCIP_VAR* auxvar;
    1502 int i;
    1503 int j;
    1504 SCIP_NLHDLRDATA* nlhdlrdata;
    1505 SCIP_Real cst0;
    1506 SCIP_VAR* indicator;
    1507 SCIP_PTRARRAY* rowpreps2;
    1508 SCIP_PTRARRAY* rowpreps;
    1509 int nrowpreps;
    1510 SCIP_SOL* solcopy;
    1511 SCIP_Bool doprobing;
    1512 SCIP_BOOLARRAY* addedbranchscores2;
    1513 SCIP_Bool stop;
    1514 int nenfos;
    1515 int* enfoposs;
    1516 SCIP_SOL* soladj;
    1517 int pos;
    1518 SCVARDATA* scvdata;
    1519
    1520 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    1521
    1522#ifdef SCIP_DEBUG
    1523 SCIPinfoMessage(scip, NULL, "enforcement method of perspective nonlinear handler called for expr %p: ", (void*)expr);
    1524 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
    1525 SCIPinfoMessage(scip, NULL, " at\n");
    1526 for( i = 0; i < nlhdlrexprdata->nvars; ++i )
    1527 {
    1528 SCIPinfoMessage(scip, NULL, "%s = %g\n", SCIPvarGetName(nlhdlrexprdata->vars[i]),
    1529 SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[i]));
    1530 }
    1533#endif
    1534
    1535 assert(scip != NULL);
    1536 assert(expr != NULL);
    1537 assert(conshdlr != NULL);
    1538 assert(nlhdlrexprdata != NULL);
    1539 assert(nlhdlrdata != NULL);
    1540
    1541 if( nlhdlrexprdata->nindicators == 0 )
    1542 {
    1543 /* we might have removed all indicators in initsepa */
    1544 *result = SCIP_DIDNOTRUN;
    1545 return SCIP_OKAY;
    1546 }
    1547
    1548 if( branchcandonly )
    1549 {
    1550 /* let the regular calls to the nlhdlrs after perspective register branching candidates */
    1551 *result = SCIP_DIDNOTRUN;
    1552 return SCIP_OKAY;
    1553 }
    1554
    1555 auxvar = SCIPgetExprAuxVarNonlinear(expr);
    1556 assert(auxvar != NULL);
    1557
    1558 /* detect should have picked only those expressions for which at least one other nlhdlr can enforce */
    1559 assert(SCIPgetExprNEnfosNonlinear(expr) > 1);
    1560
    1562
    1563 doprobing = FALSE;
    1564 nenfos = 0;
    1565 soladj = NULL;
    1566
    1567 /* find suitable nlhdlrs and check if there is enough violation to do probing */
    1568 for( j = 0; j < SCIPgetExprNEnfosNonlinear(expr); ++j )
    1569 {
    1570 SCIP_NLHDLR* nlhdlr2;
    1571 SCIP_NLHDLREXPRDATA* nlhdlr2exprdata;
    1572 SCIP_NLHDLR_METHOD nlhdlr2participate;
    1573 SCIP_Real nlhdlr2auxvalue;
    1574 SCIP_Real violation;
    1575 SCIP_Bool violbelow;
    1576 SCIP_Bool violabove;
    1577 SCIP_Bool sepausesactivity = FALSE;
    1578
    1579 SCIPgetExprEnfoDataNonlinear(expr, j, &nlhdlr2, &nlhdlr2exprdata, &nlhdlr2participate, !overestimate ? &sepausesactivity : NULL, overestimate ? &sepausesactivity: NULL, &nlhdlr2auxvalue); /*lint !e826*/
    1580
    1581 if( nlhdlr2 == nlhdlr )
    1582 continue;
    1583
    1584 /* if nlhdlr2 cannot estimate, then cannot use it */
    1585 if( !SCIPnlhdlrHasEstimate(nlhdlr2) )
    1586 continue;
    1587
    1588 /* if nlhdlr2 does not participate in the separation on the desired side (overestimate), then skip it */
    1589 if( (nlhdlr2participate & (overestimate ? SCIP_NLHDLR_METHOD_SEPAABOVE : SCIP_NLHDLR_METHOD_SEPABELOW)) == 0 )
    1590 continue;
    1591
    1592 /* if only working on convex-looking expressions, then skip nlhdlr if it uses activity for estimates */
    1593 if( nlhdlrdata->convexonly && sepausesactivity )
    1594 continue;
    1595
    1596 /* evalaux should have called evalaux of nlhdlr2 by now
    1597 * check whether handling the violation for nlhdlr2 requires under- or overestimation and this fits to
    1598 * overestimate flag
    1599 */
    1600 SCIP_CALL( SCIPgetExprAbsAuxViolationNonlinear(scip, expr, nlhdlr2auxvalue, sol, &violation, &violbelow,
    1601 &violabove) );
    1602 assert(violation >= 0.0);
    1603
    1604 if( (overestimate && !violabove) || (!overestimate && !violbelow) )
    1605 continue;
    1606
    1607 /* if violation is small, cuts would likely be weak - skip perspectification */
    1608 if( !allowweakcuts && violation < SCIPfeastol(scip) )
    1609 continue;
    1610
    1611 enfoposs[nenfos] = j;
    1612 ++nenfos;
    1613
    1614 /* enable probing if tightening the domain could be useful for nlhdlr and violation is above threshold */
    1615 if( sepausesactivity && violation >= nlhdlrdata->minviolprobing )
    1616 doprobing = TRUE;
    1617 }
    1618
    1619 if( nenfos == 0 )
    1620 {
    1621 *result = SCIP_DIDNOTRUN;
    1622 SCIPfreeBufferArray(scip, &enfoposs);
    1623 return SCIP_OKAY;
    1624 }
    1625
    1626 /* check probing frequency against depth in b&b tree */
    1627 if( nlhdlrdata->probingfreq == -1 || (nlhdlrdata->probingfreq == 0 && SCIPgetDepth(scip) != 0) ||
    1628 (nlhdlrdata->probingfreq > 0 && SCIPgetDepth(scip) % nlhdlrdata->probingfreq != 0) )
    1629 doprobing = FALSE;
    1630
    1631 /* if addbranchscores is TRUE, then we can assume to be in enforcement and not in separation */
    1632 if( nlhdlrdata->probingonlyinsepa && addbranchscores )
    1633 doprobing = FALSE;
    1634
    1635 /* disable probing if already being in probing or if in a subscip */
    1637 doprobing = FALSE;
    1638
    1639 nrowpreps = 0;
    1640 *result = SCIP_DIDNOTFIND;
    1641 solcopy = sol;
    1642 stop = FALSE;
    1643
    1644 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps2) );
    1645 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
    1646 SCIP_CALL( SCIPcreateBoolarray(scip, &addedbranchscores2) );
    1647
    1648 /* build cuts for every indicator variable */
    1649 for( i = 0; i < nlhdlrexprdata->nindicators && !stop; ++i )
    1650 {
    1651 int v;
    1652 int minidx;
    1653 int maxidx;
    1654 int r;
    1655 SCIP_VAR** probingvars;
    1656 SCIP_INTERVAL* probingdoms;
    1657 int nprobingvars;
    1658 SCIP_Bool doprobingind;
    1659 SCIP_Real indval;
    1660 SCIP_Real solval;
    1661 SCIP_Bool adjrefpoint;
    1662
    1663 indicator = nlhdlrexprdata->indicators[i];
    1664 probingvars = NULL;
    1665 probingdoms = NULL;
    1666 nprobingvars = 0;
    1667 doprobingind = doprobing;
    1668 solval = SCIPgetSolVal(scip, solcopy, indicator);
    1669 adjrefpoint = nlhdlrdata->adjrefpoint && !SCIPisFeasEQ(scip, solval, 1.0);
    1670
    1671 SCIP_CALL( analyseOnoffBounds(scip, nlhdlrdata, nlhdlrexprdata, indicator, &probingvars, &probingdoms,
    1672 &nprobingvars, &doprobingind, result) );
    1673
    1674 /* don't add perspective cuts for fixed indicators since there is no use for perspectivy */
    1675 if( SCIPvarGetLbLocal(indicator) >= 0.5 )
    1676 {
    1677 assert(!doprobingind);
    1678 continue;
    1679 }
    1680
    1681 if( SCIPvarGetUbLocal(indicator) <= 0.5 )
    1682 { /* this case is stronger as it implies that everything is fixed; therefore we are now happy */
    1683 assert(!doprobingind);
    1684 SCIPfreeBufferArrayNull(scip, &probingvars);
    1685 SCIPfreeBufferArrayNull(scip, &probingdoms);
    1686 goto TERMINATE;
    1687 }
    1688
    1689 if( doprobingind )
    1690 {
    1691 SCIP_Bool propagate;
    1692 SCIP_Bool cutoff_probing = FALSE;
    1693 SCIP_Bool cutoff;
    1694 SCIP_Bool fixed;
    1695
    1696#ifndef NDEBUG
    1697 SCIP_Real* solvals;
    1698 SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nlhdlrexprdata->nvars) );
    1699 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
    1700 {
    1701 solvals[v] = SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[v]);
    1702 }
    1703#endif
    1704
    1705 propagate = SCIPgetDepth(scip) == 0;
    1706
    1707 SCIP_CALL( startProbing(scip, nlhdlrdata, nlhdlrexprdata, indicator, probingvars, probingdoms, nprobingvars,
    1708 sol, &solcopy, &cutoff_probing) );
    1709
    1710#ifndef NDEBUG
    1711 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
    1712 {
    1713 assert(solvals[v] == SCIPgetSolVal(scip, solcopy, nlhdlrexprdata->vars[v])); /*lint !e777*/
    1714 }
    1715 SCIPfreeBufferArray(scip, &solvals);
    1716#endif
    1717
    1718 SCIPfreeBufferArrayNull(scip, &probingvars);
    1719 SCIPfreeBufferArrayNull(scip, &probingdoms);
    1720
    1721 if( propagate )
    1722 { /* we are in the root node and startProbing did propagation */
    1723 /* probing propagation might have detected infeasibility */
    1724 if( cutoff_probing )
    1725 {
    1726 /* indicator == 1 is infeasible -> set indicator to 0 */
    1727
    1729
    1730 SCIP_CALL( SCIPfixVar(scip, indicator, 0.0, &cutoff, &fixed) );
    1731
    1732 if( cutoff )
    1733 {
    1734 *result = SCIP_CUTOFF;
    1735 goto TERMINATE;
    1736 }
    1737
    1738 continue;
    1739 }
    1740
    1741 /* probing propagation in the root node can provide better on/off bounds */
    1742 SCIP_CALL( tightenOnBounds(nlhdlrexprdata, nlhdlrdata->scvars, indicator) );
    1743 }
    1744 }
    1745
    1746 if( adjrefpoint )
    1747 {
    1748 /* make sure that when we adjust the point, we don't divide by something too close to 0.0 */
    1749 indval = MAX(solval, 0.1);
    1750
    1751 /* create an adjusted point x^adj = (x* - x0) / z* + x0 */
    1752 SCIP_CALL( SCIPcreateSol(scip, &soladj, NULL) );
    1753 for( v = 0; v < nlhdlrexprdata->nvars; ++v )
    1754 {
    1755 if( SCIPvarGetStatus(nlhdlrexprdata->vars[v]) == SCIP_VARSTATUS_FIXED )
    1756 continue;
    1757
    1758 scvdata = getSCVarDataInd(nlhdlrdata->scvars, nlhdlrexprdata->vars[v], indicator, &pos);
    1759
    1760 /* a non-semicontinuous variable must be linear in expr; skip it */
    1761 if( scvdata == NULL )
    1762 continue;
    1763
    1764 SCIP_CALL( SCIPsetSolVal(scip, soladj, nlhdlrexprdata->vars[v],
    1765 (SCIPgetSolVal(scip, solcopy, nlhdlrexprdata->vars[v]) - scvdata->vals0[pos]) / indval
    1766 + scvdata->vals0[pos]) );
    1767 }
    1768 for( v = 0; v < nlhdlrexprdata->nindicators; ++v )
    1769 {
    1770 if( SCIPvarGetStatus(nlhdlrexprdata->indicators[v]) == SCIP_VARSTATUS_FIXED )
    1771 continue;
    1772
    1773 SCIP_CALL( SCIPsetSolVal(scip, soladj, nlhdlrexprdata->indicators[v],
    1774 SCIPgetSolVal(scip, solcopy, nlhdlrexprdata->indicators[v])) );
    1775 }
    1776 if( SCIPvarGetStatus(auxvar) != SCIP_VARSTATUS_FIXED )
    1777 {
    1778 SCIP_CALL( SCIPsetSolVal(scip, soladj, auxvar, SCIPgetSolVal(scip, solcopy, auxvar)) );
    1779 }
    1780 }
    1781
    1782 /* use cuts from every suitable nlhdlr */
    1783 for( j = 0; j < nenfos; ++j )
    1784 {
    1785 SCIP_Bool addedbranchscores2j;
    1786 SCIP_NLHDLR* nlhdlr2;
    1787 SCIP_NLHDLREXPRDATA* nlhdlr2exprdata;
    1788 SCIP_Real nlhdlr2auxvalue;
    1789 SCIP_Bool success2;
    1790
    1791 SCIPgetExprEnfoDataNonlinear(expr, enfoposs[j], &nlhdlr2, &nlhdlr2exprdata, NULL, NULL, NULL, &nlhdlr2auxvalue);
    1792 assert(SCIPnlhdlrHasEstimate(nlhdlr2) && nlhdlr2 != nlhdlr);
    1793
    1794 SCIPdebugMsg(scip, "asking nonlinear handler %s to %sestimate\n", SCIPnlhdlrGetName(nlhdlr2), overestimate ? "over" : "under");
    1795
    1796 /* ask the nonlinear handler for an estimator */
    1797 if( adjrefpoint )
    1798 {
    1799 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr2, expr, nlhdlr2exprdata, &nlhdlr2auxvalue, soladj) );
    1800
    1801 /* coverity[copy_paste_error] */
    1802 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr2, expr,
    1803 nlhdlr2exprdata, soladj,
    1804 nlhdlr2auxvalue, overestimate, SCIPgetSolVal(scip, solcopy, auxvar),
    1805 FALSE, rowpreps2, &success2, &addedbranchscores2j) );
    1806 }
    1807 else
    1808 {
    1809 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr2, expr,
    1810 nlhdlr2exprdata, solcopy,
    1811 nlhdlr2auxvalue, overestimate, SCIPgetSolVal(scip, solcopy, auxvar),
    1812 FALSE, rowpreps2, &success2, &addedbranchscores2j) );
    1813 }
    1814
    1815 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps2);
    1816 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps2);
    1817
    1818 assert((success2 && minidx <= maxidx) || (!success2 && minidx > maxidx));
    1819
    1820 /* perspectivy all cuts from nlhdlr2 and add them to rowpreps */
    1821 for( r = minidx; r <= maxidx; ++r )
    1822 {
    1823 SCIP_Real maxcoef;
    1824 SCIP_Real* rowprepcoefs;
    1825 SCIP_VAR** rowprepvars;
    1826
    1827 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps2, r);
    1828 assert(rowprep != NULL);
    1829
    1830#ifdef SCIP_DEBUG
    1831 SCIPinfoMessage(scip, NULL, "rowprep for expr ");
    1832 SCIPprintExpr(scip, expr, NULL);
    1833 SCIPinfoMessage(scip, NULL, "rowprep before perspectivy is: \n");
    1834 SCIPprintRowprep(scip, rowprep, NULL);
    1835#endif
    1836
    1837 /* given a rowprep: sum aixi + sum biyi + c, where xi are semicontinuous variables and yi are
    1838 * non-semicontinuous variables (which appear in expr linearly, which detect must have ensured),
    1839 * perspectivy the semicontinuous part by adding (1-z)(g0 - c - sum aix0i) (the constant is
    1840 * treated as belonging to the semicontinuous part)
    1841 */
    1842
    1843 /* we want cst0 = g0 - c - sum aix0i; first add g0 - c */
    1844 cst0 = nlhdlrexprdata->exprvals0[i] + SCIProwprepGetSide(rowprep);
    1845
    1846 maxcoef = 0.0;
    1847 rowprepcoefs = SCIProwprepGetCoefs(rowprep);
    1848 rowprepvars = SCIProwprepGetVars(rowprep);
    1849
    1850 for( v = 0; v < SCIProwprepGetNVars(rowprep); ++v )
    1851 {
    1852 if( REALABS( rowprepcoefs[v]) > maxcoef )
    1853 {
    1854 maxcoef = REALABS(rowprepcoefs[v]);
    1855 }
    1856
    1857 scvdata = getSCVarDataInd(nlhdlrdata->scvars, rowprepvars[v], indicator, &pos);
    1858
    1859 /* a non-semicontinuous variable must be linear in expr; skip it */
    1860 if( scvdata == NULL )
    1861 continue;
    1862
    1863 cst0 -= rowprepcoefs[v] * scvdata->vals0[pos];
    1864 }
    1865
    1866 /* only perspectivy when the absolute value of cst0 is not too small
    1867 * TODO on ex1252a there was cst0=0 - ok to still use the cut?
    1868 */
    1869 if( cst0 == 0.0 || maxcoef / REALABS(cst0) <= 10.0 / SCIPfeastol(scip) )
    1870 {
    1871 /* update the rowprep by adding cst0 - cst0*z */
    1872 SCIProwprepAddConstant(rowprep, cst0);
    1873 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, indicator, -cst0) );
    1874 }
    1875 else
    1876 {
    1877 SCIPfreeRowprep(scip, &rowprep);
    1878 continue;
    1879 }
    1880
    1881 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
    1882
    1883 SCIPdebugMsg(scip, "rowprep after perspectivy is: \n");
    1884#ifdef SCIP_DEBUG
    1885 SCIPprintRowprep(scip, rowprep, NULL);
    1886#endif
    1887
    1888 SCIP_CALL( SCIPsetPtrarrayVal(scip, rowpreps, nrowpreps, rowprep) );
    1889 SCIP_CALL( SCIPsetBoolarrayVal(scip, addedbranchscores2, nrowpreps, addedbranchscores2j) );
    1890 ++nrowpreps;
    1891 }
    1892
    1893 SCIP_CALL( SCIPclearPtrarray(scip, rowpreps2) );
    1894 }
    1895
    1896 if( adjrefpoint )
    1897 {
    1898 SCIP_CALL( SCIPfreeSol(scip, &soladj) );
    1899 }
    1900
    1901 if( doprobingind )
    1902 {
    1904 }
    1905
    1906 /* add all cuts found for indicator i */
    1907 for( r = SCIPgetPtrarrayMinIdx(scip, rowpreps); r <= SCIPgetPtrarrayMaxIdx(scip, rowpreps) && !stop; ++r )
    1908 {
    1909 SCIP_RESULT resultr;
    1910
    1911#ifdef SCIP_DEBUG
    1912 SCIPprintRowprep(scip, rowprep, NULL);
    1913#endif
    1914 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
    1915 resultr = SCIP_DIDNOTFIND;
    1916
    1917 (void) strcat(SCIProwprepGetName(rowprep), "_persp_indicator_");
    1918 (void) strcat(SCIProwprepGetName(rowprep), SCIPvarGetName(indicator));
    1919
    1920 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar, auxvalue,
    1921 allowweakcuts, SCIPgetBoolarrayVal(scip, addedbranchscores2, r), FALSE, solcopy, &resultr) );
    1922
    1923 if( resultr == SCIP_SEPARATED )
    1924 *result = SCIP_SEPARATED;
    1925 else if( resultr == SCIP_CUTOFF )
    1926 {
    1927 *result = SCIP_CUTOFF;
    1928 stop = TRUE;
    1929 }
    1930 else if( resultr == SCIP_BRANCHED )
    1931 {
    1932 if( *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
    1933 *result = SCIP_BRANCHED;
    1934 }
    1935 else if( resultr != SCIP_DIDNOTFIND )
    1936 {
    1937 SCIPerrorMessage("estimate called by perspective nonlinear handler returned invalid result <%d>\n", resultr);
    1938 return SCIP_INVALIDRESULT;
    1939 }
    1940 }
    1941
    1942 /* free all rowpreps for indicator i */
    1943 for( r = SCIPgetPtrarrayMinIdx(scip, rowpreps); r <= SCIPgetPtrarrayMaxIdx(scip, rowpreps); ++r )
    1944 {
    1945 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
    1946 SCIPfreeRowprep(scip, &rowprep);
    1947 }
    1948
    1949 SCIP_CALL( SCIPclearPtrarray(scip, rowpreps) );
    1950 }
    1951
    1952TERMINATE:
    1953 SCIP_CALL( SCIPfreeBoolarray(scip, &addedbranchscores2) );
    1954 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
    1955 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps2) );
    1956 if( solcopy != sol )
    1957 {
    1958 SCIP_CALL( SCIPfreeSol(scip, &solcopy) );
    1959 }
    1960 SCIPfreeBufferArray(scip, &enfoposs);
    1961
    1962 return SCIP_OKAY;
    1963}
    1964
    1965
    1966/*
    1967 * nonlinear handler specific interface methods
    1968 */
    1969
    1970/** includes perspective nonlinear handler in nonlinear constraint handler */
    1972 SCIP* scip /**< SCIP data structure */
    1973 )
    1974{
    1975 SCIP_NLHDLRDATA* nlhdlrdata;
    1976 SCIP_NLHDLR* nlhdlr;
    1977
    1978 assert(scip != NULL);
    1979
    1980 /* create nonlinear handler data */
    1981 SCIP_CALL( SCIPallocBlockMemory(scip, &nlhdlrdata) );
    1982 BMSclearMemory(nlhdlrdata);
    1983
    1985 NLHDLR_ENFOPRIORITY, nlhdlrDetectPerspective, nlhdlrEvalauxPerspective, nlhdlrdata) );
    1986 assert(nlhdlr != NULL);
    1987
    1988 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/maxproprounds",
    1989 "maximal number of propagation rounds in probing",
    1990 &nlhdlrdata->maxproprounds, FALSE, DEFAULT_MAXPROPROUNDS, -1, INT_MAX, NULL, NULL) );
    1991
    1992 SCIP_CALL( SCIPaddRealParam(scip, "nlhdlr/" NLHDLR_NAME "/mindomreduction",
    1993 "minimal relative reduction in a variable's domain for applying probing",
    1994 &nlhdlrdata->mindomreduction, FALSE, DEFAULT_MINDOMREDUCTION, 0.0, 1.0, NULL, NULL) );
    1995
    1996 SCIP_CALL( SCIPaddRealParam(scip, "nlhdlr/" NLHDLR_NAME "/minviolprobing",
    1997 "minimal violation w.r.t. auxiliary variables for applying probing",
    1998 &nlhdlrdata->minviolprobing, FALSE, DEFAULT_MINVIOLPROBING, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    1999
    2000 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/probingonlyinsepa",
    2001 "whether to do probing only in separation",
    2002 &nlhdlrdata->probingonlyinsepa, FALSE, DEFAULT_PROBINGONLYINSEPA, NULL, NULL) );
    2003
    2004 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/probingfreq",
    2005 "probing frequency (-1 - no probing, 0 - root node only)",
    2006 &nlhdlrdata->probingfreq, FALSE, DEFAULT_PROBINGFREQ, -1, INT_MAX, NULL, NULL) );
    2007
    2008 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/convexonly",
    2009 "whether perspective cuts are added only for convex expressions",
    2010 &nlhdlrdata->convexonly, FALSE, DEFAULT_CONVEXONLY, NULL, NULL) );
    2011
    2012 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/tightenbounds",
    2013 "whether variable semicontinuity is used to tighten variable bounds",
    2014 &nlhdlrdata->tightenbounds, FALSE, DEFAULT_TIGHTENBOUNDS, NULL, NULL) );
    2015
    2016 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/adjrefpoint",
    2017 "whether to adjust the reference point",
    2018 &nlhdlrdata->adjrefpoint, FALSE, DEFAULT_ADJREFPOINT, NULL, NULL) );
    2019
    2020 SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrPerspective);
    2021 SCIPnlhdlrSetFreeHdlrData(nlhdlr, nlhdlrFreehdlrdataPerspective);
    2022 SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrFreeExprDataPerspective);
    2023 SCIPnlhdlrSetInitExit(nlhdlr, NULL, nlhdlrExitPerspective);
    2024 SCIPnlhdlrSetSepa(nlhdlr, nlhdlrInitSepaPerspective, nlhdlrEnfoPerspective, NULL, NULL);
    2025
    2026 return SCIP_OKAY;
    2027}
    SCIP_VAR ** b
    Definition: circlepacking.c:65
    SCIP_Real * r
    Definition: circlepacking.c:59
    constraint handler for nonlinear constraints specified by algebraic expressions
    #define NULL
    Definition: def.h:257
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_REAL_MAX
    Definition: def.h:167
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:100
    #define MIN(x, y)
    Definition: def.h:233
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    void SCIPcomputeArraysIntersectionPtr(void **array1, int narray1, void **array2, int narray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void **intersectarray, int *nintersectarray)
    Definition: misc.c:10583
    unsigned int SCIPgetExprNAuxvarUsesNonlinear(SCIP_EXPR *expr)
    void SCIPgetExprEnfoDataNonlinear(SCIP_EXPR *expr, int idx, SCIP_NLHDLR **nlhdlr, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_NLHDLR_METHOD *nlhdlrparticipation, SCIP_Bool *sepabelowusesactivity, SCIP_Bool *sepaaboveusesactivity, SCIP_Real *auxvalue)
    void SCIPsetExprEnfoAuxValueNonlinear(SCIP_EXPR *expr, int idx, SCIP_Real auxvalue)
    SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
    SCIP_RETCODE SCIPprocessRowprepNonlinear(SCIP *scip, SCIP_NLHDLR *nlhdlr, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_ROWPREP *rowprep, SCIP_Bool overestimate, SCIP_VAR *auxvar, SCIP_Real auxvalue, SCIP_Bool allowweakcuts, SCIP_Bool branchscoresuccess, SCIP_Bool inenforcement, SCIP_SOL *sol, SCIP_RESULT *result)
    int SCIPgetExprNEnfosNonlinear(SCIP_EXPR *expr)
    SCIP_RETCODE SCIPgetExprAbsAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
    int SCIPgetSubscipDepth(SCIP *scip)
    Definition: scip_copy.c:2589
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    int SCIPgetNBinVars(SCIP *scip)
    Definition: scip_prob.c:2293
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    void * SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY *entry)
    Definition: misc.c:3613
    int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3304
    void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3284
    SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
    Definition: misc.c:3143
    int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
    Definition: misc.c:3584
    SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
    Definition: misc.c:3592
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3400
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    #define SCIPdebugMsgPrint
    Definition: scip_message.h:79
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPincludeNlhdlrPerspective(SCIP *scip)
    SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:83
    SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:139
    SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    int SCIPgetPtrarrayMinIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
    SCIP_Bool SCIPgetBoolarrayVal(SCIP *scip, SCIP_BOOLARRAY *boolarray, int idx)
    SCIP_RETCODE SCIPclearPtrarray(SCIP *scip, SCIP_PTRARRAY *ptrarray)
    void * SCIPgetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx)
    SCIP_RETCODE SCIPfreePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
    SCIP_RETCODE SCIPfreeBoolarray(SCIP *scip, SCIP_BOOLARRAY **boolarray)
    int SCIPgetPtrarrayMaxIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
    SCIP_RETCODE SCIPsetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx, void *val)
    SCIP_RETCODE SCIPcreateBoolarray(SCIP *scip, SCIP_BOOLARRAY **boolarray)
    SCIP_RETCODE SCIPsetBoolarrayVal(SCIP *scip, SCIP_BOOLARRAY *boolarray, int idx, SCIP_Bool val)
    SCIP_RETCODE SCIPcreatePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
    SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
    Definition: scip_expr.c:1661
    int SCIPexprGetNChildren(SCIP_EXPR *expr)
    Definition: expr.c:3872
    SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
    Definition: expriter.c:969
    SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1479
    SCIP_RETCODE SCIPgetExprNVars(SCIP *scip, SCIP_EXPR *expr, int *nvars)
    Definition: scip_expr.c:2083
    SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
    Definition: scip_expr.c:1443
    SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
    Definition: expriter.c:683
    SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1457
    SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
    Definition: scip_expr.c:2362
    SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
    Definition: scip_expr.c:1512
    SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
    Definition: expr.c:3946
    SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
    Definition: expriter.c:858
    SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
    Definition: expr.c:3882
    SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
    Definition: expr_var.c:423
    void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
    Definition: scip_expr.c:2376
    SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
    Definition: expriter.c:501
    SCIP_RETCODE SCIPgetExprVarExprs(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **varexprs, int *nvarexprs)
    Definition: scip_expr.c:2121
    SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
    SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    #define SCIPallocClearBlockMemory(scip, ptr)
    Definition: scip_mem.h:91
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPreallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:128
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPduplicateBufferArray(scip, ptr, source, num)
    Definition: scip_mem.h:132
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
    Definition: scip_mem.h:99
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
    Definition: scip_mem.h:111
    #define SCIPfreeBufferArrayNull(scip, ptr)
    Definition: scip_mem.h:137
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    #define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
    Definition: scip_mem.h:105
    void SCIPnlhdlrSetCopyHdlr(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRCOPYHDLR((*copy)))
    Definition: nlhdlr.c:77
    void SCIPnlhdlrSetFreeExprData(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRFREEEXPRDATA((*freeexprdata)))
    Definition: nlhdlr.c:99
    SCIP_NLHDLRDATA * SCIPnlhdlrGetData(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:217
    void SCIPnlhdlrSetFreeHdlrData(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRFREEHDLRDATA((*freehdlrdata)))
    Definition: nlhdlr.c:88
    void SCIPnlhdlrSetSepa(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINITSEPA((*initsepa)), SCIP_DECL_NLHDLRENFO((*enfo)), SCIP_DECL_NLHDLRESTIMATE((*estimate)), SCIP_DECL_NLHDLREXITSEPA((*exitsepa)))
    Definition: nlhdlr.c:137
    void SCIPnlhdlrSetInitExit(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINIT((*init)), SCIP_DECL_NLHDLREXIT((*exit_)))
    Definition: nlhdlr.c:111
    const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:167
    SCIP_Bool SCIPnlhdlrHasEstimate(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:277
    SCIP_RETCODE SCIPincludeNlhdlrNonlinear(SCIP *scip, SCIP_NLHDLR **nlhdlr, const char *name, const char *desc, int detectpriority, int enfopriority, SCIP_DECL_NLHDLRDETECT((*detect)), SCIP_DECL_NLHDLREVALAUX((*evalaux)), SCIP_NLHDLRDATA *nlhdlrdata)
    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_Bool SCIPinProbing(SCIP *scip)
    Definition: scip_probing.c:98
    SCIP_RETCODE SCIPstartProbing(SCIP *scip)
    Definition: scip_probing.c:120
    SCIP_RETCODE SCIPnewProbingNode(SCIP *scip)
    Definition: scip_probing.c:166
    SCIP_RETCODE SCIPendProbing(SCIP *scip)
    Definition: scip_probing.c:261
    SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:514
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1250
    SCIP_RETCODE SCIPsetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
    Definition: scip_sol.c:1660
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1569
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    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
    int SCIPvarGetNVlbs(SCIP_VAR *var)
    Definition: var.c:24514
    SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
    Definition: var.c:24536
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23418
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23530
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6651
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23485
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
    Definition: var.c:24546
    int SCIPvarGetNVubs(SCIP_VAR *var)
    Definition: var.c:24556
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_Bool SCIPvarIsRelaxationOnly(SCIP_VAR *var)
    Definition: var.c:23632
    SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
    Definition: var.c:24526
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
    Definition: scip_var.c:10318
    SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
    Definition: var.c:24588
    SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
    Definition: var.c:24568
    SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
    Definition: var.c:24578
    SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:1853
    SCIP_VAR ** SCIProwprepGetVars(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:639
    SCIP_Real SCIProwprepGetSide(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:659
    SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:649
    char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:689
    void SCIProwprepAddConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
    Definition: misc_rowprep.c:760
    SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
    Definition: misc_rowprep.c:913
    int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:629
    void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
    Definition: misc_rowprep.c:583
    void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
    Definition: misc_rowprep.c:801
    SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
    void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
    #define BMSclearMemory(ptr)
    Definition: memory.h:129
    private functions of nonlinear handlers of nonlinear constraints
    static SCIP_RETCODE varIsSemicontinuous(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *scvars, SCIP_Bool *result)
    static SCIP_DECL_NLHDLRENFO(nlhdlrEnfoPerspective)
    #define NLHDLR_DETECTPRIORITY
    static SCIP_DECL_NLHDLRINITSEPA(nlhdlrInitSepaPerspective)
    static SCIP_RETCODE tightenOnBounds(SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_HASHMAP *scvars, SCIP_VAR *indicator)
    #define DEFAULT_MINVIOLPROBING
    #define NLHDLR_ENFOPRIORITY
    static SCIP_RETCODE freeNlhdlrExprData(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata)
    static SCIP_RETCODE startProbing(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *indicator, SCIP_VAR **probingvars, SCIP_INTERVAL *probingdoms, int nprobingvars, SCIP_SOL *sol, SCIP_SOL **solcopy, SCIP_Bool *cutoff_probing)
    static SCIP_RETCODE removeIndicator(SCIP *scip, SCIP_NLHDLREXPRDATA *nlexprdata, int pos)
    static SCIP_RETCODE exprIsSemicontinuous(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_EXPR *expr, SCIP_Bool *res)
    static SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxPerspective)
    #define DEFAULT_TIGHTENBOUNDS
    #define DEFAULT_ADJREFPOINT
    static SCIP_RETCODE analyseVarOnoffBounds(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_VAR *var, SCIP_VAR *indicator, SCIP_Bool indvalue, SCIP_Bool *infeas, SCIP_Real *probinglb, SCIP_Real *probingub, SCIP_Bool doprobing, SCIP_Bool *reduceddom)
    #define NLHDLR_DESC
    static SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrPerspective)
    #define DEFAULT_MINDOMREDUCTION
    #define DEFAULT_PROBINGFREQ
    static SCIP_RETCODE addAuxVar(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_HASHMAP *auxvarmap, SCIP_VAR *auxvar)
    static SCIP_DECL_NLHDLRDETECT(nlhdlrDetectPerspective)
    #define NLHDLR_NAME
    #define DEFAULT_PROBINGONLYINSEPA
    #define DEFAULT_CONVEXONLY
    static SCIP_RETCODE analyseOnoffBounds(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *indicator, SCIP_VAR ***probingvars, SCIP_INTERVAL **probingdoms, int *nprobingvars, SCIP_Bool *doprobing, SCIP_RESULT *result)
    static SCIP_RETCODE addSCVarIndicator(SCIP *scip, SCVARDATA *scvdata, SCIP_VAR *indicator, SCIP_Real val0, SCIP_Real lb1, SCIP_Real ub1)
    static SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrdataPerspective)
    static SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataPerspective)
    static SCIP_RETCODE computeOffValues(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_EXPR *expr)
    #define DEFAULT_MAXPROPROUNDS
    static SCIP_DECL_NLHDLREXIT(nlhdlrExitPerspective)
    static SCVARDATA * getSCVarDataInd(SCIP_HASHMAP *scvars, SCIP_VAR *var, SCIP_VAR *indicator, int *pos)
    perspective nonlinear handler
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    preparation of a linear inequality to become a SCIP_ROW
    public methods for solutions
    SCIP_Real * vals0
    SCIP_VAR ** bvars
    SCIP_Real * ubs1
    SCIP_Real * lbs1
    @ SCIP_EXPRITER_DFS
    Definition: type_expr.h:718
    #define SCIP_NLHDLR_METHOD_SEPAABOVE
    Definition: type_nlhdlr.h:52
    struct SCIP_NlhdlrData SCIP_NLHDLRDATA
    Definition: type_nlhdlr.h:452
    #define SCIP_NLHDLR_METHOD_SEPABOTH
    Definition: type_nlhdlr.h:53
    unsigned int SCIP_NLHDLR_METHOD
    Definition: type_nlhdlr.h:57
    struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
    Definition: type_nlhdlr.h:453
    #define SCIP_NLHDLR_METHOD_SEPABELOW
    Definition: type_nlhdlr.h:51
    @ 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
    @ SCIP_BRANCHED
    Definition: type_result.h:54
    @ SCIP_SEPARATED
    Definition: type_result.h:49
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_INVALIDRESULT
    Definition: type_retcode.h:53
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64
    @ SCIP_VARSTATUS_FIXED
    Definition: type_var.h:54